Blender V4.3
GHOST_SystemSDL.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cassert>
10#include <stdexcept>
11
12#include "GHOST_ContextSDL.hh"
13#include "GHOST_SystemSDL.hh"
14#include "GHOST_WindowSDL.hh"
15
17
18#include "GHOST_EventButton.hh"
19#include "GHOST_EventCursor.hh"
20#include "GHOST_EventKey.hh"
21#include "GHOST_EventWheel.hh"
22
24{
25 if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) {
26 throw std::runtime_error(SDL_GetError());
27 }
28
29 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
30 SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
31 SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
32 SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);
33 SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8);
34}
35
37{
38 SDL_Quit();
39}
40
41GHOST_IWindow *GHOST_SystemSDL::createWindow(const char *title,
42 int32_t left,
43 int32_t top,
44 uint32_t width,
45 uint32_t height,
47 GHOST_GPUSettings gpuSettings,
48 const bool exclusive,
49 const bool /*is_dialog*/,
50 const GHOST_IWindow *parentWindow)
51{
52 GHOST_WindowSDL *window = nullptr;
53
54 window = new GHOST_WindowSDL(this,
55 title,
56 left,
57 top,
58 width,
59 height,
60 state,
61 gpuSettings.context_type,
62 ((gpuSettings.flags & GHOST_gpuStereoVisual) != 0),
63 exclusive,
64 parentWindow);
65
66 if (window) {
68 SDL_Window *sdl_win = window->getSDLWindow();
69 SDL_DisplayMode mode;
70
71 static_cast<GHOST_DisplayManagerSDL *>(m_displayManager)->getCurrentDisplayModeSDL(mode);
72
73 SDL_SetWindowDisplayMode(sdl_win, &mode);
74 SDL_ShowWindow(sdl_win);
75 SDL_SetWindowFullscreen(sdl_win, SDL_TRUE);
76 }
77
78 if (window->getValid()) {
81 }
82 else {
83 delete window;
84 window = nullptr;
85 }
86 }
87 return window;
88}
89
90GHOST_TSuccess GHOST_SystemSDL::init()
91{
93
94 if (success) {
96
97 if (m_displayManager) {
98 return GHOST_kSuccess;
99 }
100 }
101
102 return GHOST_kFailure;
103}
104
110{
111 SDL_DisplayMode mode;
112 const int display_index = 0; /* NOTE: always 0 display. */
113 if (SDL_GetDesktopDisplayMode(display_index, &mode) < 0) {
114 return;
115 }
116 width = mode.w;
117 height = mode.h;
118}
119
121{
122 SDL_DisplayMode mode;
123 const int display_index = 0; /* NOTE: always 0 display. */
124 if (SDL_GetCurrentDisplayMode(display_index, &mode) < 0) {
125 return;
126 }
127 width = mode.w;
128 height = mode.h;
129}
130
132{
133 return SDL_GetNumVideoDisplays();
134}
135
137{
138 switch (gpuSettings.context_type) {
139#ifdef WITH_OPENGL_BACKEND
140 case GHOST_kDrawingContextTypeOpenGL: {
141 for (int minor = 6; minor >= 3; --minor) {
142 GHOST_Context *context = new GHOST_ContextSDL(
143 false,
144 nullptr,
145 0, /* Profile bit. */
146 4,
147 minor,
150
151 if (context->initializeDrawingContext()) {
152 return context;
153 }
154 delete context;
155 }
156 return nullptr;
157 }
158#endif
159
160 default:
161 /* Unsupported backend. */
162 return nullptr;
163 }
164}
165
167{
168 delete context;
169
170 return GHOST_kSuccess;
171}
172
174{
175 SDL_Keymod mod = SDL_GetModState();
176
177 keys.set(GHOST_kModifierKeyLeftShift, (mod & KMOD_LSHIFT) != 0);
178 keys.set(GHOST_kModifierKeyRightShift, (mod & KMOD_RSHIFT) != 0);
179 keys.set(GHOST_kModifierKeyLeftControl, (mod & KMOD_LCTRL) != 0);
180 keys.set(GHOST_kModifierKeyRightControl, (mod & KMOD_RCTRL) != 0);
181 keys.set(GHOST_kModifierKeyLeftAlt, (mod & KMOD_LALT) != 0);
182 keys.set(GHOST_kModifierKeyRightAlt, (mod & KMOD_RALT) != 0);
183 keys.set(GHOST_kModifierKeyLeftOS, (mod & KMOD_LGUI) != 0);
184 keys.set(GHOST_kModifierKeyRightOS, (mod & KMOD_RGUI) != 0);
185
186 return GHOST_kSuccess;
187}
188
189#define GXMAP(k, x, y) \
190 case x: \
191 k = y; \
192 break
193
194static GHOST_TKey convertSDLKey(SDL_Scancode key)
195{
196 GHOST_TKey type;
197
198 if ((key >= SDL_SCANCODE_A) && (key <= SDL_SCANCODE_Z)) {
199 type = GHOST_TKey(key - SDL_SCANCODE_A + int(GHOST_kKeyA));
200 }
201 else if ((key >= SDL_SCANCODE_1) && (key <= SDL_SCANCODE_0)) {
202 type = (key == SDL_SCANCODE_0) ? GHOST_kKey0 :
203 GHOST_TKey(key - SDL_SCANCODE_1 + int(GHOST_kKey1));
204 }
205 else if ((key >= SDL_SCANCODE_F1) && (key <= SDL_SCANCODE_F12)) {
206 type = GHOST_TKey(key - SDL_SCANCODE_F1 + int(GHOST_kKeyF1));
207 }
208 else if ((key >= SDL_SCANCODE_F13) && (key <= SDL_SCANCODE_F24)) {
209 type = GHOST_TKey(key - SDL_SCANCODE_F13 + int(GHOST_kKeyF13));
210 }
211 else {
212 switch (key) {
213 GXMAP(type, SDL_SCANCODE_BACKSPACE, GHOST_kKeyBackSpace);
214 GXMAP(type, SDL_SCANCODE_TAB, GHOST_kKeyTab);
215 GXMAP(type, SDL_SCANCODE_RETURN, GHOST_kKeyEnter);
216 GXMAP(type, SDL_SCANCODE_ESCAPE, GHOST_kKeyEsc);
217 GXMAP(type, SDL_SCANCODE_SPACE, GHOST_kKeySpace);
218
219 GXMAP(type, SDL_SCANCODE_SEMICOLON, GHOST_kKeySemicolon);
220 GXMAP(type, SDL_SCANCODE_PERIOD, GHOST_kKeyPeriod);
221 GXMAP(type, SDL_SCANCODE_COMMA, GHOST_kKeyComma);
222 GXMAP(type, SDL_SCANCODE_APOSTROPHE, GHOST_kKeyQuote);
223 GXMAP(type, SDL_SCANCODE_GRAVE, GHOST_kKeyAccentGrave);
224 GXMAP(type, SDL_SCANCODE_MINUS, GHOST_kKeyMinus);
225 GXMAP(type, SDL_SCANCODE_EQUALS, GHOST_kKeyEqual);
226
227 GXMAP(type, SDL_SCANCODE_SLASH, GHOST_kKeySlash);
228 GXMAP(type, SDL_SCANCODE_BACKSLASH, GHOST_kKeyBackslash);
229 GXMAP(type, SDL_SCANCODE_KP_EQUALS, GHOST_kKeyEqual);
230 GXMAP(type, SDL_SCANCODE_LEFTBRACKET, GHOST_kKeyLeftBracket);
231 GXMAP(type, SDL_SCANCODE_RIGHTBRACKET, GHOST_kKeyRightBracket);
232 GXMAP(type, SDL_SCANCODE_PAUSE, GHOST_kKeyPause);
233
234 GXMAP(type, SDL_SCANCODE_LSHIFT, GHOST_kKeyLeftShift);
235 GXMAP(type, SDL_SCANCODE_RSHIFT, GHOST_kKeyRightShift);
236 GXMAP(type, SDL_SCANCODE_LCTRL, GHOST_kKeyLeftControl);
237 GXMAP(type, SDL_SCANCODE_RCTRL, GHOST_kKeyRightControl);
238 GXMAP(type, SDL_SCANCODE_LALT, GHOST_kKeyLeftAlt);
239 GXMAP(type, SDL_SCANCODE_RALT, GHOST_kKeyRightAlt);
240 GXMAP(type, SDL_SCANCODE_LGUI, GHOST_kKeyLeftOS);
241 GXMAP(type, SDL_SCANCODE_RGUI, GHOST_kKeyRightOS);
242 GXMAP(type, SDL_SCANCODE_APPLICATION, GHOST_kKeyApp);
243
244 GXMAP(type, SDL_SCANCODE_INSERT, GHOST_kKeyInsert);
245 GXMAP(type, SDL_SCANCODE_DELETE, GHOST_kKeyDelete);
246 GXMAP(type, SDL_SCANCODE_HOME, GHOST_kKeyHome);
247 GXMAP(type, SDL_SCANCODE_END, GHOST_kKeyEnd);
248 GXMAP(type, SDL_SCANCODE_PAGEUP, GHOST_kKeyUpPage);
249 GXMAP(type, SDL_SCANCODE_PAGEDOWN, GHOST_kKeyDownPage);
250
251 GXMAP(type, SDL_SCANCODE_LEFT, GHOST_kKeyLeftArrow);
252 GXMAP(type, SDL_SCANCODE_RIGHT, GHOST_kKeyRightArrow);
253 GXMAP(type, SDL_SCANCODE_UP, GHOST_kKeyUpArrow);
254 GXMAP(type, SDL_SCANCODE_DOWN, GHOST_kKeyDownArrow);
255
256 GXMAP(type, SDL_SCANCODE_CAPSLOCK, GHOST_kKeyCapsLock);
257 GXMAP(type, SDL_SCANCODE_SCROLLLOCK, GHOST_kKeyScrollLock);
258 GXMAP(type, SDL_SCANCODE_NUMLOCKCLEAR, GHOST_kKeyNumLock);
259 GXMAP(type, SDL_SCANCODE_PRINTSCREEN, GHOST_kKeyPrintScreen);
260
261 /* keypad events */
262
263 /* NOTE: SDL defines a bunch of key-pad identifiers that aren't supported by GHOST,
264 * such as #SDL_SCANCODE_KP_PERCENT, #SDL_SCANCODE_KP_XOR. */
265 GXMAP(type, SDL_SCANCODE_KP_0, GHOST_kKeyNumpad0);
266 GXMAP(type, SDL_SCANCODE_KP_1, GHOST_kKeyNumpad1);
267 GXMAP(type, SDL_SCANCODE_KP_2, GHOST_kKeyNumpad2);
268 GXMAP(type, SDL_SCANCODE_KP_3, GHOST_kKeyNumpad3);
269 GXMAP(type, SDL_SCANCODE_KP_4, GHOST_kKeyNumpad4);
270 GXMAP(type, SDL_SCANCODE_KP_5, GHOST_kKeyNumpad5);
271 GXMAP(type, SDL_SCANCODE_KP_6, GHOST_kKeyNumpad6);
272 GXMAP(type, SDL_SCANCODE_KP_7, GHOST_kKeyNumpad7);
273 GXMAP(type, SDL_SCANCODE_KP_8, GHOST_kKeyNumpad8);
274 GXMAP(type, SDL_SCANCODE_KP_9, GHOST_kKeyNumpad9);
275 GXMAP(type, SDL_SCANCODE_KP_PERIOD, GHOST_kKeyNumpadPeriod);
276
277 GXMAP(type, SDL_SCANCODE_KP_ENTER, GHOST_kKeyNumpadEnter);
278 GXMAP(type, SDL_SCANCODE_KP_PLUS, GHOST_kKeyNumpadPlus);
279 GXMAP(type, SDL_SCANCODE_KP_MINUS, GHOST_kKeyNumpadMinus);
280 GXMAP(type, SDL_SCANCODE_KP_MULTIPLY, GHOST_kKeyNumpadAsterisk);
281 GXMAP(type, SDL_SCANCODE_KP_DIVIDE, GHOST_kKeyNumpadSlash);
282
283 /* Media keys in some keyboards and laptops with XFree86/XORG. */
284 GXMAP(type, SDL_SCANCODE_AUDIOPLAY, GHOST_kKeyMediaPlay);
285 GXMAP(type, SDL_SCANCODE_AUDIOSTOP, GHOST_kKeyMediaStop);
286 GXMAP(type, SDL_SCANCODE_AUDIOPREV, GHOST_kKeyMediaFirst);
287 // GXMAP(type, XF86XK_AudioRewind, GHOST_kKeyMediaFirst);
288 GXMAP(type, SDL_SCANCODE_AUDIONEXT, GHOST_kKeyMediaLast);
289
290 /* International Keys. */
291
292 /* This key has multiple purposes,
293 * however the only GHOST key that uses the scan-code is GrLess. */
294 GXMAP(type, SDL_SCANCODE_NONUSBACKSLASH, GHOST_kKeyGrLess);
295
296 default:
297 printf("Unknown\n");
298 type = GHOST_kKeyUnknown;
299 break;
300 }
301 }
302
303 return type;
304}
305#undef GXMAP
306
307static char convert_keyboard_event_to_ascii(const SDL_KeyboardEvent &sdl_sub_evt)
308{
309 SDL_Keycode sym = sdl_sub_evt.keysym.sym;
310 if (sym > 127) {
311 switch (sym) {
312 case SDLK_KP_DIVIDE:
313 sym = '/';
314 break;
315 case SDLK_KP_MULTIPLY:
316 sym = '*';
317 break;
318 case SDLK_KP_MINUS:
319 sym = '-';
320 break;
321 case SDLK_KP_PLUS:
322 sym = '+';
323 break;
324 case SDLK_KP_1:
325 sym = '1';
326 break;
327 case SDLK_KP_2:
328 sym = '2';
329 break;
330 case SDLK_KP_3:
331 sym = '3';
332 break;
333 case SDLK_KP_4:
334 sym = '4';
335 break;
336 case SDLK_KP_5:
337 sym = '5';
338 break;
339 case SDLK_KP_6:
340 sym = '6';
341 break;
342 case SDLK_KP_7:
343 sym = '7';
344 break;
345 case SDLK_KP_8:
346 sym = '8';
347 break;
348 case SDLK_KP_9:
349 sym = '9';
350 break;
351 case SDLK_KP_0:
352 sym = '0';
353 break;
354 case SDLK_KP_PERIOD:
355 sym = '.';
356 break;
357 default:
358 sym = 0;
359 break;
360 }
361 }
362 else {
363 if (sdl_sub_evt.keysym.mod & (KMOD_LSHIFT | KMOD_RSHIFT)) {
364 /* Weak US keyboard assumptions. */
365 if (sym >= 'a' && sym <= ('a' + 32)) {
366 sym -= 32;
367 }
368 else {
369 switch (sym) {
370 case '`':
371 sym = '~';
372 break;
373 case '1':
374 sym = '!';
375 break;
376 case '2':
377 sym = '@';
378 break;
379 case '3':
380 sym = '#';
381 break;
382 case '4':
383 sym = '$';
384 break;
385 case '5':
386 sym = '%';
387 break;
388 case '6':
389 sym = '^';
390 break;
391 case '7':
392 sym = '&';
393 break;
394 case '8':
395 sym = '*';
396 break;
397 case '9':
398 sym = '(';
399 break;
400 case '0':
401 sym = ')';
402 break;
403 case '-':
404 sym = '_';
405 break;
406 case '=':
407 sym = '+';
408 break;
409 case '[':
410 sym = '{';
411 break;
412 case ']':
413 sym = '}';
414 break;
415 case '\\':
416 sym = '|';
417 break;
418 case ';':
419 sym = ':';
420 break;
421 case '\'':
422 sym = '"';
423 break;
424 case ',':
425 sym = '<';
426 break;
427 case '.':
428 sym = '>';
429 break;
430 case '/':
431 sym = '?';
432 break;
433 default:
434 break;
435 }
436 }
437 }
438 }
439 return char(sym);
440}
441
446static SDL_Window *SDL_GetWindowFromID_fallback(Uint32 id)
447{
448 SDL_Window *sdl_win = SDL_GetWindowFromID(id);
449 if (sdl_win == nullptr) {
450 sdl_win = SDL_GL_GetCurrentWindow();
451 }
452 return sdl_win;
453}
454
455void GHOST_SystemSDL::processEvent(SDL_Event *sdl_event)
456{
457 GHOST_Event *g_event = nullptr;
458
459 switch (sdl_event->type) {
460 case SDL_WINDOWEVENT: {
461 const SDL_WindowEvent &sdl_sub_evt = sdl_event->window;
462 const uint64_t event_ms = sdl_sub_evt.timestamp;
463 GHOST_WindowSDL *window = findGhostWindow(
464 SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
465 /* Can be nullptr on close window. */
466#if 0
467 assert(window != nullptr);
468#endif
469
470 switch (sdl_sub_evt.event) {
471 case SDL_WINDOWEVENT_EXPOSED:
472 g_event = new GHOST_Event(event_ms, GHOST_kEventWindowUpdate, window);
473 break;
474 case SDL_WINDOWEVENT_RESIZED:
475 g_event = new GHOST_Event(event_ms, GHOST_kEventWindowSize, window);
476 break;
477 case SDL_WINDOWEVENT_MOVED:
478 g_event = new GHOST_Event(event_ms, GHOST_kEventWindowMove, window);
479 break;
480 case SDL_WINDOWEVENT_FOCUS_GAINED:
481 g_event = new GHOST_Event(event_ms, GHOST_kEventWindowActivate, window);
482 break;
483 case SDL_WINDOWEVENT_FOCUS_LOST:
484 g_event = new GHOST_Event(event_ms, GHOST_kEventWindowDeactivate, window);
485 break;
486 case SDL_WINDOWEVENT_CLOSE:
487 g_event = new GHOST_Event(event_ms, GHOST_kEventWindowClose, window);
488 break;
489 }
490
491 break;
492 }
493
494 case SDL_QUIT: {
495 const SDL_QuitEvent &sdl_sub_evt = sdl_event->quit;
496 const uint64_t event_ms = sdl_sub_evt.timestamp;
498 g_event = new GHOST_Event(event_ms, GHOST_kEventQuitRequest, window);
499 break;
500 }
501
502 case SDL_MOUSEMOTION: {
503 const SDL_MouseMotionEvent &sdl_sub_evt = sdl_event->motion;
504 const uint64_t event_ms = sdl_sub_evt.timestamp;
505 SDL_Window *sdl_win = SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID);
506 GHOST_WindowSDL *window = findGhostWindow(sdl_win);
507 assert(window != nullptr);
508
509 int x_win, y_win;
510 SDL_GetWindowPosition(sdl_win, &x_win, &y_win);
511
512 int32_t x_root = sdl_sub_evt.x + x_win;
513 int32_t y_root = sdl_sub_evt.y + y_win;
514
515#if 0
516 if (window->getCursorGrabMode() != GHOST_kGrabDisable &&
518 int32_t x_new = x_root;
519 int32_t y_new = y_root;
520 int32_t x_accum, y_accum;
522
523 /* fallback to window bounds */
525 window->getClientBounds(bounds);
526
527 /* Could also clamp to screen bounds wrap with a window outside the view will
528 * fail at the moment. Use offset of 8 in case the window is at screen bounds. */
529 bounds.wrapPoint(x_new, y_new, 8, window->getCursorGrabAxis());
530 window->getCursorGrabAccum(x_accum, y_accum);
531
532 /* Can't use #setCursorPosition because the mouse may have no focus! */
533 if (x_new != x_root || y_new != y_root) {
534 if (1 /* `xme.time > m_last_warp` */ ) {
535 /* when wrapping we don't need to add an event because the
536 * #setCursorPosition call will cause a new event after */
537 SDL_WarpMouseInWindow(sdl_win, x_new - x_win, y_new - y_win); /* wrap */
538 window->setCursorGrabAccum(x_accum + (x_root - x_new), y_accum + (y_root - y_new));
539 // m_last_warp = lastEventTime(xme.time);
540 }
541 else {
542 // setCursorPosition(x_new, y_new); /* wrap but don't accumulate */
543 SDL_WarpMouseInWindow(sdl_win, x_new - x_win, y_new - y_win);
544 }
545
546 g_event = new GHOST_EventCursor(event_ms,
548 window,
549 x_new,
550 y_new,
552 }
553 else {
554 g_event = new GHOST_EventCursor(event_ms,
556 window,
557 x_root + x_accum,
558 y_root + y_accum,
560 }
561 }
562 else
563#endif
564 {
565 g_event = new GHOST_EventCursor(
566 event_ms, GHOST_kEventCursorMove, window, x_root, y_root, GHOST_TABLET_DATA_NONE);
567 }
568 break;
569 }
570 case SDL_MOUSEBUTTONUP:
571 case SDL_MOUSEBUTTONDOWN: {
572 const SDL_MouseButtonEvent &sdl_sub_evt = sdl_event->button;
573 const uint64_t event_ms = sdl_sub_evt.timestamp;
575 GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventButtonDown :
577
578 GHOST_WindowSDL *window = findGhostWindow(
579 SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
580 assert(window != nullptr);
581
582 /* process rest of normal mouse buttons */
583 if (sdl_sub_evt.button == SDL_BUTTON_LEFT) {
584 gbmask = GHOST_kButtonMaskLeft;
585 }
586 else if (sdl_sub_evt.button == SDL_BUTTON_MIDDLE) {
588 }
589 else if (sdl_sub_evt.button == SDL_BUTTON_RIGHT) {
590 gbmask = GHOST_kButtonMaskRight;
591 /* these buttons are untested! */
592 }
593 else if (sdl_sub_evt.button == SDL_BUTTON_X1) {
595 }
596 else if (sdl_sub_evt.button == SDL_BUTTON_X2) {
598 }
599 else {
600 break;
601 }
602
603 g_event = new GHOST_EventButton(event_ms, type, window, gbmask, GHOST_TABLET_DATA_NONE);
604 break;
605 }
606 case SDL_MOUSEWHEEL: {
607 const SDL_MouseWheelEvent &sdl_sub_evt = sdl_event->wheel;
608 const uint64_t event_ms = sdl_sub_evt.timestamp;
609 GHOST_WindowSDL *window = findGhostWindow(
610 SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
611 assert(window != nullptr);
612 g_event = new GHOST_EventWheel(event_ms, window, sdl_sub_evt.y);
613 break;
614 }
615 case SDL_KEYDOWN:
616 case SDL_KEYUP: {
617 const SDL_KeyboardEvent &sdl_sub_evt = sdl_event->key;
618 const uint64_t event_ms = sdl_sub_evt.timestamp;
619 GHOST_TEventType type = (sdl_sub_evt.state == SDL_PRESSED) ? GHOST_kEventKeyDown :
621 const bool is_repeat = sdl_sub_evt.repeat != 0;
622
623 GHOST_WindowSDL *window = findGhostWindow(
624 SDL_GetWindowFromID_fallback(sdl_sub_evt.windowID));
625 assert(window != nullptr);
626
627 GHOST_TKey gkey = convertSDLKey(sdl_sub_evt.keysym.scancode);
628 /* NOTE: the `sdl_sub_evt.keysym.sym` is truncated,
629 * for unicode support ghost has to be modified. */
630
631 /* TODO(@ideasman42): support full unicode, SDL supports this but it needs to be
632 * explicitly enabled via #SDL_StartTextInput which GHOST would have to wrap. */
633 char utf8_buf[sizeof(GHOST_TEventKeyData::utf8_buf)] = {'\0'};
634 if (type == GHOST_kEventKeyDown) {
635 utf8_buf[0] = convert_keyboard_event_to_ascii(sdl_sub_evt);
636 }
637
638 g_event = new GHOST_EventKey(event_ms, type, window, gkey, is_repeat, utf8_buf);
639 break;
640 }
641 }
642
643 if (g_event) {
644 pushEvent(g_event);
645 }
646}
647
649{
650 int x_win, y_win;
651 SDL_Window *win = SDL_GetMouseFocus();
652 SDL_GetWindowPosition(win, &x_win, &y_win);
653
654 int xi, yi;
655 SDL_GetMouseState(&xi, &yi);
656 x = xi + x_win;
657 y = yi + x_win;
658
659 return GHOST_kSuccess;
660}
661
663{
664 int x_win, y_win;
665 SDL_Window *win = SDL_GetMouseFocus();
666 SDL_GetWindowPosition(win, &x_win, &y_win);
667
668 SDL_WarpMouseInWindow(win, x - x_win, y - y_win);
669 return GHOST_kSuccess;
670}
671
672bool GHOST_SystemSDL::generateWindowExposeEvents()
673{
674 std::vector<GHOST_WindowSDL *>::iterator w_start = m_dirty_windows.begin();
675 std::vector<GHOST_WindowSDL *>::const_iterator w_end = m_dirty_windows.end();
676 bool anyProcessed = false;
677
678 for (; w_start != w_end; ++w_start) {
679 /* The caller doesn't have a time-stamp. */
680 const uint64_t event_ms = getMilliSeconds();
681 GHOST_Event *g_event = new GHOST_Event(event_ms, GHOST_kEventWindowUpdate, *w_start);
682
683 (*w_start)->validate();
684
685 if (g_event) {
686 // printf("Expose events pushed\n");
687 pushEvent(g_event);
688 anyProcessed = true;
689 }
690 }
691
692 m_dirty_windows.clear();
693 return anyProcessed;
694}
695
696bool GHOST_SystemSDL::processEvents(bool waitForEvent)
697{
698 /* Get all the current events - translate them into
699 * ghost events and call base class #pushEvent() method. */
700
701 bool anyProcessed = false;
702
703 do {
705
706 if (waitForEvent && m_dirty_windows.empty() && !SDL_HasEvents(SDL_FIRSTEVENT, SDL_LASTEVENT)) {
707 uint64_t next = timerMgr->nextFireTime();
708
709 if (next == GHOST_kFireTimeNever) {
710 SDL_WaitEventTimeout(nullptr, -1);
711 // SleepTillEvent(m_display, -1);
712 }
713 else {
714 int64_t maxSleep = next - getMilliSeconds();
715
716 if (maxSleep >= 0) {
717 SDL_WaitEventTimeout(nullptr, next - getMilliSeconds());
718 // SleepTillEvent(m_display, next - getMilliSeconds()); /* X11. */
719 }
720 }
721 }
722
723 if (timerMgr->fireTimers(getMilliSeconds())) {
724 anyProcessed = true;
725 }
726
727 SDL_Event sdl_event;
728 while (SDL_PollEvent(&sdl_event)) {
729 processEvent(&sdl_event);
730 anyProcessed = true;
731 }
732
733 if (generateWindowExposeEvents()) {
734 anyProcessed = true;
735 }
736 } while (waitForEvent && !anyProcessed);
737
738 return anyProcessed;
739}
740
741GHOST_WindowSDL *GHOST_SystemSDL::findGhostWindow(SDL_Window *sdl_win)
742{
743 if (sdl_win == nullptr) {
744 return nullptr;
745 }
746 /* It is not entirely safe to do this as the back-pointer may point
747 * to a window that has recently been removed.
748 * We should always check the window manager's list of windows
749 * and only process events on these windows. */
750
751 const std::vector<GHOST_IWindow *> &win_vec = m_windowManager->getWindows();
752
753 std::vector<GHOST_IWindow *>::const_iterator win_it = win_vec.begin();
754 std::vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end();
755
756 for (; win_it != win_end; ++win_it) {
757 GHOST_WindowSDL *window = static_cast<GHOST_WindowSDL *>(*win_it);
758 if (window->getSDLWindow() == sdl_win) {
759 return window;
760 }
761 }
762 return nullptr;
763}
764
766{
767 GHOST_ASSERT((bad_wind != nullptr), "addDirtyWindow() nullptr ptr trapped (window)");
768
769 m_dirty_windows.push_back(bad_wind);
770}
771
773{
774 Uint8 state = SDL_GetMouseState(nullptr, nullptr);
775 buttons.set(GHOST_kButtonMaskLeft, (state & SDL_BUTTON_LMASK) != 0);
776 buttons.set(GHOST_kButtonMaskMiddle, (state & SDL_BUTTON_MMASK) != 0);
777 buttons.set(GHOST_kButtonMaskRight, (state & SDL_BUTTON_RMASK) != 0);
778
779 return GHOST_kSuccess;
780}
781
783{
786 ~(
787 /* This SDL back-end has not yet implemented primary clipboard. */
789 /* This SDL back-end has not yet implemented color sampling the desktop. */
791 /* This SDL back-end has not yet implemented image copy/paste. */
793 /* No support yet for IME input methods. */
795}
796
797char *GHOST_SystemSDL::getClipboard(bool /*selection*/) const
798{
799 return (char *)SDL_GetClipboardText();
800}
801
802void GHOST_SystemSDL::putClipboard(const char *buffer, bool /*selection*/) const
803{
804 SDL_SetClipboardText(buffer);
805}
806
808{
809 return SDL_GetTicks64();
810}
#define GHOST_OPENGL_SDL_RESET_NOTIFICATION_STRATEGY
#define GHOST_OPENGL_SDL_CONTEXT_FLAGS
#define GHOST_ASSERT(x, info)
static char convert_keyboard_event_to_ascii(const SDL_KeyboardEvent &sdl_sub_evt)
static GHOST_TKey convertSDLKey(SDL_Scancode key)
#define GXMAP(k, x, y)
static SDL_Window * SDL_GetWindowFromID_fallback(Uint32 id)
#define pushEvent
GHOST_TWindowState
@ GHOST_kWindowStateFullScreen
GHOST_TEventType
@ GHOST_kEventWindowClose
@ GHOST_kEventWindowMove
@ GHOST_kEventWindowSize
@ GHOST_kEventCursorMove
@ GHOST_kEventButtonUp
@ GHOST_kEventWindowActivate
@ GHOST_kEventWindowUpdate
@ GHOST_kEventWindowDeactivate
@ GHOST_kEventButtonDown
@ GHOST_kEventKeyDown
@ GHOST_kEventKeyUp
@ GHOST_kEventQuitRequest
static const GHOST_TabletData GHOST_TABLET_DATA_NONE
GHOST_TCapabilityFlag
Definition GHOST_Types.h:96
@ GHOST_kCapabilityInputIME
@ GHOST_kCapabilityClipboardImages
@ GHOST_kCapabilityPrimaryClipboard
@ GHOST_kCapabilityDesktopSample
#define GHOST_CAPABILITY_FLAG_ALL
GHOST_TKey
@ GHOST_kKeyLeftOS
@ GHOST_kKeyInsert
@ GHOST_kKeySemicolon
@ GHOST_kKeyMediaPlay
@ GHOST_kKeyQuote
@ GHOST_kKeyNumpad3
@ GHOST_kKeyAccentGrave
@ GHOST_kKeyNumpad1
@ GHOST_kKeyLeftAlt
@ GHOST_kKeyRightShift
@ GHOST_kKeyNumLock
@ GHOST_kKeyEnter
@ GHOST_kKeyNumpadSlash
@ GHOST_kKeyRightArrow
@ GHOST_kKeyF13
@ GHOST_kKeyNumpad4
@ GHOST_kKeyPause
@ GHOST_kKeyCapsLock
@ GHOST_kKeyApp
@ GHOST_kKeyMinus
@ GHOST_kKeyMediaStop
@ GHOST_kKeyBackSpace
@ GHOST_kKey0
@ GHOST_kKeyDownPage
@ GHOST_kKeyGrLess
@ GHOST_kKeyDownArrow
@ GHOST_kKeyRightOS
@ GHOST_kKeyNumpadPeriod
@ GHOST_kKeyF1
@ GHOST_kKeyNumpadAsterisk
@ GHOST_kKeyPrintScreen
@ GHOST_kKeyLeftControl
@ GHOST_kKeyLeftBracket
@ GHOST_kKey1
@ GHOST_kKeyTab
@ GHOST_kKeyComma
@ GHOST_kKeyRightBracket
@ GHOST_kKeyBackslash
@ GHOST_kKeyNumpad2
@ GHOST_kKeyRightAlt
@ GHOST_kKeyPeriod
@ GHOST_kKeyNumpadPlus
@ GHOST_kKeyUpPage
@ GHOST_kKeyNumpad5
@ GHOST_kKeyLeftArrow
@ GHOST_kKeyEqual
@ GHOST_kKeyHome
@ GHOST_kKeyNumpad6
@ GHOST_kKeyNumpad8
@ GHOST_kKeyNumpad9
@ GHOST_kKeyEnd
@ GHOST_kKeyUpArrow
@ GHOST_kKeyDelete
@ GHOST_kKeyNumpad0
@ GHOST_kKeyA
@ GHOST_kKeyMediaFirst
@ GHOST_kKeyNumpad7
@ GHOST_kKeyRightControl
@ GHOST_kKeyEsc
@ GHOST_kKeyUnknown
@ GHOST_kKeyScrollLock
@ GHOST_kKeySlash
@ GHOST_kKeyNumpadEnter
@ GHOST_kKeyNumpadMinus
@ GHOST_kKeyLeftShift
@ GHOST_kKeyMediaLast
@ GHOST_kKeySpace
@ GHOST_kModifierKeyRightControl
@ GHOST_kModifierKeyLeftControl
@ GHOST_kModifierKeyRightAlt
@ GHOST_kModifierKeyRightShift
@ GHOST_kModifierKeyLeftAlt
@ GHOST_kModifierKeyLeftShift
@ GHOST_kModifierKeyLeftOS
@ GHOST_kModifierKeyRightOS
GHOST_TSuccess
Definition GHOST_Types.h:87
@ GHOST_kFailure
Definition GHOST_Types.h:87
@ GHOST_kSuccess
Definition GHOST_Types.h:87
@ GHOST_kFireTimeNever
@ GHOST_gpuStereoVisual
Definition GHOST_Types.h:76
@ GHOST_kGrabDisable
@ GHOST_kGrabNormal
GHOST_TButton
@ GHOST_kButtonMaskRight
@ GHOST_kButtonMaskButton4
@ GHOST_kButtonMaskLeft
@ GHOST_kButtonMaskButton5
@ GHOST_kButtonMaskMiddle
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
GHOST_IContext * createOffscreenContext(GHOST_GPUSettings gpuSettings) override
GHOST_TSuccess getCursorPosition(int32_t &x, int32_t &y) const override
GHOST_TSuccess setCursorPosition(int32_t x, int32_t y) override
char * getClipboard(bool selection) const override
void getMainDisplayDimensions(uint32_t &width, uint32_t &height) const override
GHOST_TCapabilityFlag getCapabilities() const override
void addDirtyWindow(GHOST_WindowSDL *bad_wind)
void getAllDisplayDimensions(uint32_t &width, uint32_t &height) const override
uint8_t getNumDisplays() const override
GHOST_TSuccess disposeContext(GHOST_IContext *context) override
void putClipboard(const char *buffer, bool selection) const override
GHOST_TSuccess getButtons(GHOST_Buttons &buttons) const override
GHOST_TSuccess getModifierKeys(GHOST_ModifierKeys &keys) const override
uint64_t getMilliSeconds() const override
bool processEvents(bool waitForEvent) override
virtual GHOST_TSuccess init()
GHOST_TimerManager * getTimerManager() const
GHOST_WindowManager * m_windowManager
GHOST_DisplayManager * m_displayManager
bool fireTimers(uint64_t time)
GHOST_TSuccess addWindow(GHOST_IWindow *window)
const std::vector< GHOST_IWindow * > & getWindows() const
GHOST_IWindow * getActiveWindow() const
SDL_Window * getSDLWindow()
void getClientBounds(GHOST_Rect &bounds) const override
bool getValid() const override
GHOST_TSuccess getCursorGrabBounds(GHOST_Rect &bounds) const override
void setCursorGrabAccum(int32_t x, int32_t y)
GHOST_TAxisFlag getCursorGrabAxis() const
GHOST_TGrabCursorMode getCursorGrabMode() const
void getCursorGrabAccum(int32_t &x, int32_t &y) const
#define printf
static ulong * next
static ulong state[N]
unsigned int uint32_t
Definition stdint.h:80
__int64 int64_t
Definition stdint.h:89
signed int int32_t
Definition stdint.h:77
unsigned char uint8_t
Definition stdint.h:78
unsigned __int64 uint64_t
Definition stdint.h:90
void set(GHOST_TButton mask, bool down)
GHOST_TDrawingContextType context_type
void set(GHOST_TModifierKey mask, bool down)
ccl_device_inline int mod(int x, int m)
Definition util/math.h:520