4 * The BlackBerry-specific windows message processing methods.
6 * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved.
7 * Written by Pawel W. Olszta, <olszta@sourceforge.net>
8 * Copied for Platform code by Evan Felix <karcaw at gmail.com>
9 * Copyright (C) 2012 Sylvain Beucler
10 * Copyright (C) 2013 Vincent Simonetti
12 * Permission is hereby granted, free of charge, to any person obtaining a
13 * copy of this software and associated documentation files (the "Software"),
14 * to deal in the Software without restriction, including without limitation
15 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 * and/or sell copies of the Software, and to permit persons to whom the
17 * Software is furnished to do so, subject to the following conditions:
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
26 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 #include <GL/freeglut.h>
31 #include "fg_internal.h"
32 #include "egl/fg_window_egl.h"
41 #define LOGI(...) ((void)slogf(1337, _SLOG_INFO, __VA_ARGS__))
43 #define LOGW(...) ((void)slogf(1337, _SLOG_WARNING, __VA_ARGS__))
44 #ifndef SLOG2_FA_SIGNED
45 #define SLOG2_FA_SIGNED(x) (x)
50 #define LOGI(...) ((void)slog2fa(NULL, 1337, SLOG2_INFO, __VA_ARGS__, SLOG2_FA_END))
52 #define LOGW(...) ((void)slog2fa(NULL, 1337, SLOG2_WARNING, __VA_ARGS__, SLOG2_FA_END))
54 #include <sys/keycodes.h>
55 #include <input/screen_helpers.h>
57 #include <bps/event.h>
58 #include <bps/screen.h>
59 #include <bps/navigator.h>
60 #include <bps/virtualkeyboard.h>
62 extern void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify);
63 extern void fghOnPositionNotify(SFG_Window *window, int x, int y, GLboolean forceNotify);
64 extern void fgPlatformFullScreenToggle( SFG_Window *win );
65 extern void fgPlatformPositionWindow( SFG_Window *window, int x, int y );
66 extern void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height );
67 extern void fgPlatformPushWindow( SFG_Window *window );
68 extern void fgPlatformPopWindow( SFG_Window *window );
69 extern void fgPlatformHideWindow( SFG_Window *window );
70 extern void fgPlatformIconifyWindow( SFG_Window *window );
71 extern void fgPlatformShowWindow( SFG_Window *window );
72 extern void fgPlatformMainLoopPostWork ( void );
73 extern void fgPlatformRotateWindow( SFG_Window *window, int rotation );
74 extern void fgPlatformFlushCommands ( void );
76 static struct touchscreen touchscreen;
78 #define ESCAPE_BUTTON_KEY 0x001B
80 unsigned int key_special(int qnxKeycode)
108 return GLUT_KEY_PAGE_UP;
109 case KEYCODE_PG_DOWN:
110 return GLUT_KEY_PAGE_DOWN;
112 return GLUT_KEY_HOME;
116 return GLUT_KEY_INSERT;
118 //case KEYCODE_KP_UP:
121 //case KEYCODE_KP_DOWN:
122 return GLUT_KEY_DOWN;
124 //case KEYCODE_KP_LEFT:
125 return GLUT_KEY_LEFT;
127 //case KEYCODE_KP_RIGHT:
128 return GLUT_KEY_RIGHT;
129 case KEYCODE_NUM_LOCK:
130 return GLUT_KEY_NUM_LOCK;
131 case KEYCODE_LEFT_ALT:
132 return GLUT_KEY_ALT_L;
133 case KEYCODE_RIGHT_ALT:
134 return GLUT_KEY_ALT_R;
135 case KEYCODE_LEFT_SHIFT:
136 return GLUT_KEY_SHIFT_L;
137 case KEYCODE_RIGHT_SHIFT:
138 return GLUT_KEY_SHIFT_R;
139 case KEYCODE_LEFT_CTRL:
140 return GLUT_KEY_CTRL_L;
141 case KEYCODE_RIGHT_CTRL:
142 return GLUT_KEY_CTRL_R;
147 unsigned char key_ascii(int qnxKeycode)
149 if (qnxKeycode >= KEYCODE_PC_KEYS && qnxKeycode <= UNICODE_PRIVATE_USE_AREA_LAST) {
150 switch (qnxKeycode) {
151 case KEYCODE_BACKSPACE:
155 case KEYCODE_KP_ENTER:
159 return ESCAPE_BUTTON_KEY;
166 fg_time_t fgPlatformSystemTime ( void )
168 #ifdef CLOCK_MONOTONIC
170 clock_gettime(CLOCK_MONOTONIC, &now);
171 return now.tv_nsec/1000000 + now.tv_sec*1000;
172 #elif defined(HAVE_GETTIMEOFDAY)
174 gettimeofday( &now, NULL );
175 return now.tv_usec/1000 + now.tv_sec*1000;
180 * Does the magic required to relinquish the CPU until something interesting
183 void fgPlatformSleepForEvents( fg_time_t msec )
185 if(fgStructure.CurrentWindow && fgDisplay.pDisplay.event == NULL &&
186 bps_get_event(&fgDisplay.pDisplay.event, (int)msec) != BPS_SUCCESS) {
187 LOGW("BPS couldn't get event");
191 void handle_left_mouse(int x, int y, int height, int eventType, SFG_Window* window)
193 bool handled = false;
194 /* Virtual arrows PAD */
195 /* Don't interfere with existing mouse move event */
196 if (!touchscreen.in_mmotion) {
197 struct vpad_state prev_vpad = touchscreen.vpad;
198 touchscreen.vpad.left = touchscreen.vpad.right = touchscreen.vpad.up = touchscreen.vpad.down = false;
200 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH || eventType == SCREEN_EVENT_MTOUCH_MOVE) {
201 if ((x > 0 && x < 100) && (y > (height - 100) && y < height))
203 touchscreen.vpad.left = true;
205 if ((x > 200 && x < 300) && (y > (height - 100) && y < height))
207 touchscreen.vpad.right = true;
209 if ((x > 100 && x < 200) && (y > (height - 100) && y < height))
211 touchscreen.vpad.down = true;
213 if ((x > 100 && x < 200) && (y > (height - 200) && y < (height - 100)))
215 touchscreen.vpad.up = true;
219 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH &&
220 (touchscreen.vpad.left || touchscreen.vpad.right || touchscreen.vpad.down || touchscreen.vpad.up)) {
221 touchscreen.vpad.on = true;
223 if (eventType == SCREEN_EVENT_MTOUCH_RELEASE) {
224 touchscreen.vpad.on = false;
227 if (prev_vpad.left != touchscreen.vpad.left
228 || prev_vpad.right != touchscreen.vpad.right
229 || prev_vpad.up != touchscreen.vpad.up
230 || prev_vpad.down != touchscreen.vpad.down
231 || prev_vpad.on != touchscreen.vpad.on) {
232 if (FETCH_WCB(*window, Special)) {
233 if (prev_vpad.left == false && touchscreen.vpad.left == true) {
234 INVOKE_WCB(*window, Special, (GLUT_KEY_LEFT, x, y));
236 else if (prev_vpad.right == false && touchscreen.vpad.right == true) {
237 INVOKE_WCB(*window, Special, (GLUT_KEY_RIGHT, x, y));
239 else if (prev_vpad.up == false && touchscreen.vpad.up == true) {
240 INVOKE_WCB(*window, Special, (GLUT_KEY_UP, x, y));
242 else if (prev_vpad.down == false && touchscreen.vpad.down == true) {
243 INVOKE_WCB(*window, Special, (GLUT_KEY_DOWN, x, y));
246 if (FETCH_WCB(*window, SpecialUp)) {
247 if (prev_vpad.left == true && touchscreen.vpad.left == false) {
248 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_LEFT, x, y));
250 if (prev_vpad.right == true && touchscreen.vpad.right == false) {
251 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_RIGHT, x, y));
253 if (prev_vpad.up == true && touchscreen.vpad.up == false) {
254 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_UP, x, y));
256 if (prev_vpad.down == true && touchscreen.vpad.down == false) {
257 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_DOWN, x, y));
264 /* Normal mouse events */
265 if (!handled && !touchscreen.vpad.on) {
266 window->State.MouseX = x;
267 window->State.MouseY = y;
269 if(eventType == SCREEN_EVENT_MTOUCH_MOVE) {
270 INVOKE_WCB(*window, Motion, (x, y));
271 } else if(FETCH_WCB(*window, Mouse)) {
272 touchscreen.in_mmotion = eventType == SCREEN_EVENT_MTOUCH_TOUCH;
273 int glutTouchType = eventType == SCREEN_EVENT_MTOUCH_TOUCH ? GLUT_DOWN : GLUT_UP;
274 INVOKE_WCB(*window, Mouse, (GLUT_LEFT_BUTTON, glutTouchType, x, y));
280 * Determine a GLUT modifier mask based on BlackBerry modifier info.
282 int fgPlatformGetModifiers (int mod)
284 return (((mod & KEYMOD_SHIFT) ? GLUT_ACTIVE_SHIFT : 0) |
285 ((mod & KEYMOD_CTRL) ? GLUT_ACTIVE_CTRL : 0) |
286 ((mod & KEYMOD_ALT) ? GLUT_ACTIVE_ALT : 0));
289 void fgPlatformHandleKeyboardHeight(SFG_Window* window, int height)
293 int nScreenHeight = -1;
295 screenHeight = glutGet(GLUT_WINDOW_HEIGHT); //Using this takes rotation into account
297 nScreenHeight = screenHeight;
299 else if(!screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_POSITION, size)) {
300 /* Calculate the new screen size */ //XXX Make sure to use display size instead of screen size
301 nScreenHeight = ((size[1] + screenHeight) - height) - size[1];
304 if(nScreenHeight != -1) {
305 /* If nScreenHeight is less then zero then window is covered. If nScreenHeight == height, then no change in size. Else, change in size */
307 int screenWidth = glutGet(GLUT_WINDOW_WIDTH);
308 if(nScreenHeight < 0) {
309 LOGI("fgPlatformHandleKeyboardHeight: Covered window state");
310 window->State.Visible = GL_FALSE;
311 window->State.pWState.windowCovered = GL_TRUE;
312 INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_COVERED));
313 fghOnReshapeNotify(window, screenWidth, 0, GL_FALSE);
315 if(window->State.pWState.windowCovered == GL_TRUE) {
316 LOGI("fgPlatformHandleKeyboardHeight: Resetting window state");
318 /* Reset window status if it was previously covered */
319 switch(window->State.pWState.windowState) {
320 case NAVIGATOR_WINDOW_FULLSCREEN:
321 window->State.Visible = GL_TRUE;
322 INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED));
324 case NAVIGATOR_WINDOW_THUMBNAIL:
325 window->State.Visible = GL_TRUE;
326 INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
328 case NAVIGATOR_WINDOW_INVISIBLE:
329 window->State.Visible = GL_FALSE;
330 INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN));
333 window->State.pWState.windowCovered = GL_FALSE;
335 fghOnReshapeNotify(window, screenWidth, nScreenHeight, GL_FALSE);
340 void fgPlatformProcessSingleEvent ( void )
342 if(fgStructure.CurrentWindow == NULL) {
343 //XXX Is this right? Would this just cause a whole lot of busy looping while we wait for events?
344 LOGW("fgPlatformProcessSingleEvent: Missing current window. Skipping event processing");
348 if(fgDisplay.pDisplay.event == NULL)
355 SFG_Window* window = fgStructure.CurrentWindow;
356 /* Get the keyboard height before doing anything since we otherwise don't get it until it changes */
357 if(window->State.pWState.keyboardHeight == 0) {
358 virtualkeyboard_get_height(&window->State.pWState.keyboardHeight);
360 domain = bps_event_get_domain(fgDisplay.pDisplay.event);
361 if (domain == screen_get_domain()) {
364 screen_event_t screenEvent = screen_event_get_event(fgDisplay.pDisplay.event);
365 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_TYPE, &eventType);
368 //Mostly from fg_main_android
369 case SCREEN_EVENT_MTOUCH_TOUCH:
370 case SCREEN_EVENT_MTOUCH_RELEASE:
371 case SCREEN_EVENT_MTOUCH_MOVE:
373 mtouch_event_t touchEvent;
374 screen_get_mtouch_event(screenEvent, &touchEvent, 0);
376 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
381 LOGI("fgPlatformProcessSingleEvent: SCREEN_EVENT_MTOUCH_*: Type: 0x%X, X: %d, Y: %d, Contact Id: %d, Mod: 0x%X", SLOG2_FA_SIGNED(eventType), SLOG2_FA_SIGNED(touchEvent.x), SLOG2_FA_SIGNED(touchEvent.y), SLOG2_FA_SIGNED(touchEvent.contact_id), SLOG2_FA_SIGNED(mod));
383 /* Remember the current modifiers state so user can query it from their callback */
384 fgState.Modifiers = fgPlatformGetModifiers(mod);
386 if(touchEvent.contact_id == 0) {
388 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
389 handle_left_mouse(touchEvent.x, touchEvent.y, size[1], eventType, window);
392 //Now handle mutlitouch (adapted from fg_main_windows)
393 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH) {
394 INVOKE_WCB( *window, MultiEntry, ( touchEvent.contact_id, GLUT_ENTERED ) );
395 INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_DOWN ) );
396 } else if (eventType == SCREEN_EVENT_MTOUCH_MOVE) {
397 INVOKE_WCB( *window, MultiMotion, ( touchEvent.contact_id, touchEvent.x, touchEvent.y ) );
398 //XXX No motion is performed without contact, thus MultiPassive is never used
399 } else if (eventType == SCREEN_EVENT_MTOUCH_RELEASE) {
400 INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_UP ) );
401 INVOKE_WCB( *window, MultiEntry, ( touchEvent.contact_id, GLUT_LEFT ) );
404 fgState.Modifiers = INVALID_MODIFIERS;
408 case SCREEN_EVENT_POINTER:
410 //Based off/part taken from GamePlay3d PlatformBlackBerry
411 static int mouse_pressed = 0;
415 // A move event will be fired unless a button state changed.
417 bool left_move = false;
418 // This is a mouse move event, it is applicable to a device with a usb mouse or simulator.
419 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_BUTTONS, &buttons);
420 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_SOURCE_POSITION, position);
422 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_MOUSE_WHEEL, &wheel);
423 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
428 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
430 LOGI("fgPlatformProcessSingleEvent: SCREEN_EVENT_POINTER: Buttons: 0x%X, X: %d, Y: %d, Wheel: %d, Mod: 0x%X", SLOG2_FA_SIGNED(buttons), SLOG2_FA_SIGNED(position[0]), SLOG2_FA_SIGNED(position[1]), SLOG2_FA_SIGNED(wheel), SLOG2_FA_SIGNED(mod));
432 //XXX Is multitouch be handled in a good way?
434 /* Remember the current modifiers state so user can query it from their callback */
435 fgState.Modifiers = fgPlatformGetModifiers(mod);
437 // Handle left mouse. Interpret as touch if the left mouse event is not consumed.
438 if (buttons & SCREEN_LEFT_MOUSE_BUTTON) {
439 if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
443 mouse_pressed |= SCREEN_LEFT_MOUSE_BUTTON;
444 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_TOUCH, window);
446 } else if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
448 mouse_pressed &= ~SCREEN_LEFT_MOUSE_BUTTON;
449 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_RELEASE, window);
452 // Handle right mouse.
453 if (buttons & SCREEN_RIGHT_MOUSE_BUTTON) {
454 if ((mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) == 0) {
456 mouse_pressed |= SCREEN_RIGHT_MOUSE_BUTTON;
457 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_DOWN, position[0], position[1]));
459 } else if (mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) {
461 mouse_pressed &= ~SCREEN_RIGHT_MOUSE_BUTTON;
462 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_UP, position[0], position[1]));
465 // Handle middle mouse.
466 if (buttons & SCREEN_MIDDLE_MOUSE_BUTTON) {
467 if ((mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) == 0) {
469 mouse_pressed |= SCREEN_MIDDLE_MOUSE_BUTTON;
470 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_DOWN, position[0], position[1]));
472 } else if (mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) {
474 mouse_pressed &= ~SCREEN_MIDDLE_MOUSE_BUTTON;
475 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_UP, position[0], position[1]));
478 // Fire a move event if none of the buttons changed.
479 if (left_move || move) {
480 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_MOVE, window);
484 /* Very slightly modified from fg_main_mswin.
485 * Because we don't want MouseWheel to be called every. single. time.
486 * That the action occurs, we mimic the Windows version with "wheel deltas"
487 * XXX Do we even want this?
488 * XXX If we want this, it's possible to get horizontal scroll as well.
489 * XXX -Vertical scroll=wheel 0, horizontal=wheel 1? */
490 fgState.MouseWheelTicks -= wheel;
491 if (abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
493 int wheel_number = 0;
494 int direction = (fgState.MouseWheelTicks > 0) ? -1 : 1;
496 if (!FETCH_WCB(*window, MouseWheel) && !FETCH_WCB(*window, Mouse))
499 //XXX fgSetWindow(window);
501 while(abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
503 if (FETCH_WCB(*window, MouseWheel))
504 INVOKE_WCB(*window, MouseWheel, (wheel_number, direction, window->State.MouseX, window->State.MouseY));
505 else /* No mouse wheel, call the mouse button callback twice */
508 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
509 * " " one +1 to 5, -1 to 6, ...
511 * XXX The below assumes that you have no more than 3 mouse
512 * XXX buttons. Sorry.
514 int button = wheel_number * 2 + 3;
517 INVOKE_WCB(*window, Mouse, (button, GLUT_DOWN, window->State.MouseX, window->State.MouseY));
518 INVOKE_WCB(*window, Mouse, (button, GLUT_UP, window->State.MouseX, window->State.MouseY));
521 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
526 fgState.Modifiers = INVALID_MODIFIERS;
530 //Based off fg_main_android
531 case SCREEN_EVENT_KEYBOARD:
535 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_FLAGS, &flags);
536 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_SYM, &value);
537 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
539 LOGI("fgPlatformProcessSingleEvent: SCREEN_EVENT_KEYBOARD. Flags: 0x%X, Sym: 0x%X, Mod: 0x%X", SLOG2_FA_SIGNED(flags), SLOG2_FA_SIGNED(value), SLOG2_FA_SIGNED(mod));
541 /* Suppress key repeats if desired. Based off fg_main_mswin */
542 if ((flags & KEY_REPEAT) == 0 || (fgState.KeyRepeat == GLUT_KEY_REPEAT_OFF && fgStructure.CurrentWindow->State.IgnoreKeyRepeat == GL_TRUE)) {
543 unsigned int keypress = 0;
544 unsigned char ascii = 0;
546 /* Remember the current modifiers state so user can query it from their callback */
547 fgState.Modifiers = fgPlatformGetModifiers(mod);
550 if ((keypress = key_special(value))) {
551 if(flags & KEY_DOWN) {
552 INVOKE_WCB(*window, Special, (keypress, window->State.MouseX, window->State.MouseY));
554 INVOKE_WCB(*window, SpecialUp, (keypress, window->State.MouseX, window->State.MouseY));
556 } else if((flags & KEY_SYM_VALID) && (ascii = key_ascii(value))) {
557 if(flags & KEY_DOWN) {
558 INVOKE_WCB(*window, Keyboard, (ascii, window->State.MouseX, window->State.MouseY));
560 INVOKE_WCB(*window, KeyboardUp, (ascii, window->State.MouseX, window->State.MouseY));
563 LOGW("fgPlatformProcessSingleEvent: SCREEN_EVENT_KEYBOARD. Unhandled key event");
566 fgState.Modifiers = INVALID_MODIFIERS;
571 case SCREEN_EVENT_PROPERTY:
572 case SCREEN_EVENT_IDLE:
576 LOGW("fgPlatformProcessSingleEvent: unknown screen event: 0x%X", SLOG2_FA_SIGNED(eventType));
579 } else if (domain == navigator_get_domain()) {
580 unsigned int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
583 case NAVIGATOR_WINDOW_STATE:
585 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE");
587 /* Covered only happens due to keyboard. When the app is minimized, the keyboard is closed.
588 When the keyboard is open, and the app is fullscreened, the keyboard is also closed.
589 If a window is covered and the app is minimized, the state will be set and the keyboard event
590 will adjust the screen size and change window status. */
591 navigator_window_state_t state = navigator_event_get_window_state(fgDisplay.pDisplay.event);
592 if(window->State.pWState.windowCovered == GL_FALSE)
596 case NAVIGATOR_WINDOW_FULLSCREEN:
597 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_FULLSCREEN");
598 window->State.Visible = GL_TRUE;
599 INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED));
601 case NAVIGATOR_WINDOW_THUMBNAIL:
602 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_THUMBNAIL");
603 window->State.Visible = GL_TRUE;
604 INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
606 case NAVIGATOR_WINDOW_INVISIBLE:
607 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_INVISIBLE");
608 window->State.Visible = GL_FALSE;
609 INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN));
612 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
616 window->State.pWState.windowState = state;
622 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_EXIT");
624 fgPlatformMainLoopPostWork();
626 /* User closed the application for good, let's kill the window */
627 SFG_Window* window = fgStructure.CurrentWindow;
628 if (window != NULL) {
629 fgDestroyWindow(window);
631 LOGW("NAVIGATOR_EXIT: No current window");
634 //XXX Should this be a bit more "forceful" so that it doesn't continue to loop through events?
638 case NAVIGATOR_SWIPE_DOWN:
639 /* XXX Open app menu */
642 /* Orientation is a bunch of handshakes.
643 - First the app get's asked if it wants to rotate (NAVIGATOR_ORIENTATION_CHECK)
644 - If the app wants to rotate, then it will be told what size it will be after rotate (NAVIGATOR_ORIENTATION_SIZE).
645 - Once the OS confirms that it's ready to rotate, it tells the app to handle rotation (NAVIGATOR_ORIENTATION).
646 - Once rotation is complete, the OS tells the app it's done (NAVIGATOR_ORIENTATION_DONE) */
647 case NAVIGATOR_ORIENTATION_CHECK:
648 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_CHECK");
651 window->State.pWState.newWidth = 0;
652 window->State.pWState.newHeight = 0;
655 /* On rotation, the keyboard is closed. This prevents two resize calls */
656 window->State.pWState.keyboardOpen = GL_FALSE;
659 /* Notify that we want to rotate */
660 navigator_orientation_check_response(fgDisplay.pDisplay.event, true);
663 case NAVIGATOR_ORIENTATION:
664 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION");
666 /* NAVIGATOR_ORIENTATION occurs before NAVIGATOR_KEYBOARD_POSITION */
668 /* Rotate and resize the window */
669 fgPlatformRotateWindow(window, navigator_event_get_orientation_angle(fgDisplay.pDisplay.event));
670 fgPlatformFlushCommands();
672 /* PlayBook doesn't indicate what the new size will be, so we need to retrieve it from the window itself */
673 window->State.pWState.newWidth = glutGet(GLUT_WINDOW_WIDTH);
674 window->State.pWState.newHeight = glutGet(GLUT_WINDOW_HEIGHT);
675 fghOnReshapeNotify(window, window->State.pWState.newWidth, window->State.pWState.newHeight, GL_FALSE);
677 if(window->State.pWState.keyboardOpen == GL_FALSE) {
678 /* On rotation, if the keyboard is open, it will get the keyboard resize events anyway. Otherwise, handle the resize. */
679 fghOnReshapeNotify(window, window->State.pWState.newWidth, window->State.pWState.newHeight, GL_FALSE);
684 window->State.pWState.newWidth = 0;
685 window->State.pWState.newHeight = 0;
688 navigator_done_orientation(fgDisplay.pDisplay.event);
692 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_BACK");
693 INVOKE_WCB(*window, Keyboard, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
694 INVOKE_WCB(*window, KeyboardUp, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
697 case NAVIGATOR_WINDOW_ACTIVE:
698 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_ACTIVE");
699 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_RESUME));
702 case NAVIGATOR_WINDOW_INACTIVE:
703 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_INACTIVE");
704 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_PAUSE));
707 case NAVIGATOR_ORIENTATION_DONE:
708 case NAVIGATOR_ORIENTATION_RESULT:
709 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_DONE/NAVIGATOR_ORIENTATION_RESULT");
713 case NAVIGATOR_KEYBOARD_STATE:
714 case NAVIGATOR_KEYBOARD_POSITION:
715 /* See virtual keyboard handling for info on why this is not used. */
718 case NAVIGATOR_DEVICE_LOCK_STATE:
721 case NAVIGATOR_WINDOW_COVER:
722 case NAVIGATOR_WINDOW_COVER_ENTER:
723 case NAVIGATOR_WINDOW_COVER_EXIT:
724 /* BlackBerry specific. Let app status and window status take care of everything */
727 case NAVIGATOR_APP_STATE:
728 /* Can do the same as NAVIGATOR_WINDOW_ACTIVE/NAVIGATOR_WINDOW_INACTIVE but
729 seems like it doesn't work when the app comes to the foreground. Might be a bug */
732 case NAVIGATOR_ORIENTATION_SIZE:
733 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_SIZE");
735 /* Get new window size */
736 window->State.pWState.newWidth = navigator_event_get_orientation_size_width(fgDisplay.pDisplay.event);
737 window->State.pWState.newHeight = navigator_event_get_orientation_size_height(fgDisplay.pDisplay.event);
741 case 0: //Doesn't exist in header, but shows up when keyboard shows and resizes
742 case NAVIGATOR_OTHER:
746 LOGW("fgPlatformProcessSingleEvent: unknown navigator event: 0x%X", SLOG2_FA_SIGNED(eventType));
751 * BlackBerry 10 navigator provides keyboard events, but they conflict with how we handle keyboard events.
752 * Causing multiple reshape messages and can leave window state incorrectly setup.
754 else if(domain == virtualkeyboard_get_domain()) {
755 unsigned int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
757 case VIRTUALKEYBOARD_EVENT_VISIBLE:
758 LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_VISIBLE");
759 if(window->State.pWState.keyboardOpen != GL_TRUE) {
760 window->State.pWState.keyboardOpen = GL_TRUE;
761 fgPlatformHandleKeyboardHeight(window, window->State.pWState.keyboardHeight);
765 case VIRTUALKEYBOARD_EVENT_HIDDEN:
766 LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_HIDDEN");
767 if(window->State.pWState.keyboardOpen != GL_FALSE) {
768 window->State.pWState.keyboardOpen = GL_FALSE;
769 fgPlatformHandleKeyboardHeight(window, 0);
773 case VIRTUALKEYBOARD_EVENT_INFO:
774 LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_INFO");
775 window->State.pWState.keyboardHeight = virtualkeyboard_event_get_height(fgDisplay.pDisplay.event);
776 if(window->State.pWState.keyboardOpen == GL_TRUE) {
777 fgPlatformHandleKeyboardHeight(window, window->State.pWState.keyboardHeight);
782 LOGW("fgPlatformProcessSingleEvent: unknown virtualkeyboard event: 0x%X", eventType);
786 } while(bps_get_event(&fgDisplay.pDisplay.event, 1) == BPS_SUCCESS && fgDisplay.pDisplay.event != NULL);
788 /* Reset event to reduce chances of triggering something */
789 fgDisplay.pDisplay.event = NULL;
792 void fgPlatformMainLoopPreliminaryWork ( void )
794 LOGI("fgPlatformMainLoopPreliminaryWork");
796 /* Request navigator events */
797 navigator_request_events(NAVIGATOR_EXTENDED_DATA);
800 navigator_rotation_lock(false);
802 /* Request keyboard events */
803 virtualkeyboard_request_events(0);
805 /* Request window events */
806 screen_request_events(fgDisplay.pDisplay.screenContext);
809 void fgPlatformMainLoopPostWork ( void )
811 LOGI("fgPlatformMainLoopPostWork");
813 /* Stop all events */
814 screen_stop_events(fgDisplay.pDisplay.screenContext);
817 navigator_stop_events(0);
821 /* deal with work list items */
822 void fgPlatformInitWork(SFG_Window* window)
824 LOGI("fgPlatformInitWork");
826 /* Position callback, always at 0,0 */
827 fghOnPositionNotify(window, 0, 0, GL_TRUE);
829 /* Get window size */
831 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
832 fghOnReshapeNotify(window, size[0], size[1], GL_FALSE);
834 /* Size gets notified on window creation with size detection in mainloop above
835 * XXX CHECK: does this messages happen too early like on windows,
836 * so client code cannot have registered a callback yet and the message
837 * is thus never received by client?
841 void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask)
843 if (workMask & GLUT_FULL_SCREEN_WORK)
844 fgPlatformFullScreenToggle( window );
845 if (workMask & GLUT_POSITION_WORK)
846 fgPlatformPositionWindow( window, window->State.DesiredXpos, window->State.DesiredYpos );
847 if (workMask & GLUT_SIZE_WORK)
848 fgPlatformReshapeWindow ( window, window->State.DesiredWidth, window->State.DesiredHeight );
849 if (workMask & GLUT_ZORDER_WORK)
851 if (window->State.DesiredZOrder < 0)
852 fgPlatformPushWindow( window );
854 fgPlatformPopWindow( window );
858 void fgPlatformVisibilityWork(SFG_Window* window)
860 /* Visibility status of window should get updated in the window message handlers
861 * For now, none of these functions called below do anything, so don't worry
864 SFG_Window *win = window;
865 switch (window->State.DesiredVisibility)
867 case DesireHiddenState:
868 fgPlatformHideWindow( window );
870 case DesireIconicState:
871 /* Call on top-level window */
874 fgPlatformIconifyWindow( win );
876 case DesireNormalState:
877 fgPlatformShowWindow( window );