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;
357 /* Get the keyboard height before doing anything since we otherwise don't get it until it changes */
358 if(window->State.pWState.keyboardHeight == 0) {
359 virtualkeyboard_get_height(&window->State.pWState.keyboardHeight);
362 domain = bps_event_get_domain(fgDisplay.pDisplay.event);
363 if (domain == screen_get_domain()) {
366 screen_event_t screenEvent = screen_event_get_event(fgDisplay.pDisplay.event);
367 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_TYPE, &eventType);
370 //Mostly from fg_main_android
371 case SCREEN_EVENT_MTOUCH_TOUCH:
372 case SCREEN_EVENT_MTOUCH_RELEASE:
373 case SCREEN_EVENT_MTOUCH_MOVE:
375 mtouch_event_t touchEvent;
376 screen_get_mtouch_event(screenEvent, &touchEvent, 0);
378 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
383 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));
385 /* Remember the current modifiers state so user can query it from their callback */
386 fgState.Modifiers = fgPlatformGetModifiers(mod);
388 if(touchEvent.contact_id == 0) {
390 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
391 handle_left_mouse(touchEvent.x, touchEvent.y, size[1], eventType, window);
394 //Now handle mutlitouch (adapted from fg_main_windows)
395 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH) {
396 INVOKE_WCB( *window, MultiEntry, ( touchEvent.contact_id, GLUT_ENTERED ) );
397 INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_DOWN ) );
398 } else if (eventType == SCREEN_EVENT_MTOUCH_MOVE) {
399 INVOKE_WCB( *window, MultiMotion, ( touchEvent.contact_id, touchEvent.x, touchEvent.y ) );
400 //XXX No motion is performed without contact, thus MultiPassive is never used
401 } else if (eventType == SCREEN_EVENT_MTOUCH_RELEASE) {
402 INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_UP ) );
403 INVOKE_WCB( *window, MultiEntry, ( touchEvent.contact_id, GLUT_LEFT ) );
406 fgState.Modifiers = INVALID_MODIFIERS;
410 case SCREEN_EVENT_POINTER:
412 //Based off/part taken from GamePlay3d PlatformBlackBerry
413 static int mouse_pressed = 0;
417 // A move event will be fired unless a button state changed.
419 bool left_move = false;
420 // This is a mouse move event, it is applicable to a device with a usb mouse or simulator.
421 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_BUTTONS, &buttons);
422 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_SOURCE_POSITION, position);
424 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_MOUSE_WHEEL, &wheel);
425 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
430 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
432 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));
434 //XXX Is multitouch be handled in a good way?
436 /* Remember the current modifiers state so user can query it from their callback */
437 fgState.Modifiers = fgPlatformGetModifiers(mod);
439 // Handle left mouse. Interpret as touch if the left mouse event is not consumed.
440 if (buttons & SCREEN_LEFT_MOUSE_BUTTON) {
441 if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
445 mouse_pressed |= SCREEN_LEFT_MOUSE_BUTTON;
446 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_TOUCH, window);
448 } else if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
450 mouse_pressed &= ~SCREEN_LEFT_MOUSE_BUTTON;
451 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_RELEASE, window);
454 // Handle right mouse.
455 if (buttons & SCREEN_RIGHT_MOUSE_BUTTON) {
456 if ((mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) == 0) {
458 mouse_pressed |= SCREEN_RIGHT_MOUSE_BUTTON;
459 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_DOWN, position[0], position[1]));
461 } else if (mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) {
463 mouse_pressed &= ~SCREEN_RIGHT_MOUSE_BUTTON;
464 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_UP, position[0], position[1]));
467 // Handle middle mouse.
468 if (buttons & SCREEN_MIDDLE_MOUSE_BUTTON) {
469 if ((mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) == 0) {
471 mouse_pressed |= SCREEN_MIDDLE_MOUSE_BUTTON;
472 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_DOWN, position[0], position[1]));
474 } else if (mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) {
476 mouse_pressed &= ~SCREEN_MIDDLE_MOUSE_BUTTON;
477 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_UP, position[0], position[1]));
480 // Fire a move event if none of the buttons changed.
481 if (left_move || move) {
482 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_MOVE, window);
486 /* Very slightly modified from fg_main_mswin.
487 * Because we don't want MouseWheel to be called every. single. time.
488 * That the action occurs, we mimic the Windows version with "wheel deltas"
489 * XXX Do we even want this?
490 * XXX If we want this, it's possible to get horizontal scroll as well.
491 * XXX -Vertical scroll=wheel 0, horizontal=wheel 1? */
492 fgState.MouseWheelTicks -= wheel;
493 if (abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
495 int wheel_number = 0;
496 int direction = (fgState.MouseWheelTicks > 0) ? -1 : 1;
498 if (!FETCH_WCB(*window, MouseWheel) && !FETCH_WCB(*window, Mouse))
501 //XXX fgSetWindow(window);
503 while(abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
505 if (FETCH_WCB(*window, MouseWheel))
506 INVOKE_WCB(*window, MouseWheel, (wheel_number, direction, window->State.MouseX, window->State.MouseY));
507 else /* No mouse wheel, call the mouse button callback twice */
510 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
511 * " " one +1 to 5, -1 to 6, ...
513 * XXX The below assumes that you have no more than 3 mouse
514 * XXX buttons. Sorry.
516 int button = wheel_number * 2 + 3;
519 INVOKE_WCB(*window, Mouse, (button, GLUT_DOWN, window->State.MouseX, window->State.MouseY));
520 INVOKE_WCB(*window, Mouse, (button, GLUT_UP, window->State.MouseX, window->State.MouseY));
523 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
528 fgState.Modifiers = INVALID_MODIFIERS;
532 //Based off fg_main_android
533 case SCREEN_EVENT_KEYBOARD:
537 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_FLAGS, &flags);
538 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_SYM, &value);
539 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
541 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));
543 /* Suppress key repeats if desired. Based off fg_main_mswin */
544 if ((flags & KEY_REPEAT) == 0 || (fgState.KeyRepeat == GLUT_KEY_REPEAT_OFF && fgStructure.CurrentWindow->State.IgnoreKeyRepeat == GL_TRUE)) {
545 unsigned int keypress = 0;
546 unsigned char ascii = 0;
548 /* Remember the current modifiers state so user can query it from their callback */
549 fgState.Modifiers = fgPlatformGetModifiers(mod);
552 if ((keypress = key_special(value))) {
553 if(flags & KEY_DOWN) {
554 INVOKE_WCB(*window, Special, (keypress, window->State.MouseX, window->State.MouseY));
556 INVOKE_WCB(*window, SpecialUp, (keypress, window->State.MouseX, window->State.MouseY));
558 } else if((flags & KEY_SYM_VALID) && (ascii = key_ascii(value))) {
559 if(flags & KEY_DOWN) {
560 INVOKE_WCB(*window, Keyboard, (ascii, window->State.MouseX, window->State.MouseY));
562 INVOKE_WCB(*window, KeyboardUp, (ascii, window->State.MouseX, window->State.MouseY));
565 LOGW("fgPlatformProcessSingleEvent: SCREEN_EVENT_KEYBOARD. Unhandled key event");
568 fgState.Modifiers = INVALID_MODIFIERS;
573 case SCREEN_EVENT_PROPERTY:
574 case SCREEN_EVENT_IDLE:
578 LOGW("fgPlatformProcessSingleEvent: unknown screen event: 0x%X", SLOG2_FA_SIGNED(eventType));
581 } else if (domain == navigator_get_domain()) {
582 unsigned int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
585 case NAVIGATOR_WINDOW_STATE:
587 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE");
589 /* Covered only happens due to keyboard. When the app is minimized, the keyboard is closed.
590 When the keyboard is open, and the app is fullscreened, the keyboard is also closed.
591 If a window is covered and the app is minimized, the state will be set and the keyboard event
592 will adjust the screen size and change window status. */
593 navigator_window_state_t state = navigator_event_get_window_state(fgDisplay.pDisplay.event);
594 if(window->State.pWState.windowCovered == GL_FALSE)
598 case NAVIGATOR_WINDOW_FULLSCREEN:
599 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_FULLSCREEN");
600 window->State.Visible = GL_TRUE;
601 INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED));
603 case NAVIGATOR_WINDOW_THUMBNAIL:
604 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_THUMBNAIL");
605 window->State.Visible = GL_TRUE;
606 INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
608 case NAVIGATOR_WINDOW_INVISIBLE:
609 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_INVISIBLE");
610 window->State.Visible = GL_FALSE;
611 INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN));
614 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
618 window->State.pWState.windowState = state;
624 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_EXIT");
626 fgPlatformMainLoopPostWork();
628 /* User closed the application for good, let's kill the window */
629 SFG_Window* window = fgStructure.CurrentWindow;
630 if (window != NULL) {
631 fgDestroyWindow(window);
633 LOGW("NAVIGATOR_EXIT: No current window");
636 //XXX Should this be a bit more "forceful" so that it doesn't continue to loop through events?
640 case NAVIGATOR_SWIPE_DOWN:
641 /* XXX Open app menu */
644 /* Orientation is a bunch of handshakes.
645 - First the app get's asked if it wants to rotate (NAVIGATOR_ORIENTATION_CHECK)
646 - If the app wants to rotate, then it will be told what size it will be after rotate (NAVIGATOR_ORIENTATION_SIZE).
647 - Once the OS confirms that it's ready to rotate, it tells the app to handle rotation (NAVIGATOR_ORIENTATION).
648 - Once rotation is complete, the OS tells the app it's done (NAVIGATOR_ORIENTATION_DONE) */
649 case NAVIGATOR_ORIENTATION_CHECK:
650 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_CHECK");
653 window->State.pWState.newWidth = 0;
654 window->State.pWState.newHeight = 0;
657 /* On rotation, the keyboard is closed. This prevents two resize calls */
658 window->State.pWState.keyboardOpen = GL_FALSE;
661 /* Notify that we want to rotate */
662 navigator_orientation_check_response(fgDisplay.pDisplay.event, true);
665 case NAVIGATOR_ORIENTATION:
666 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION");
668 /* NAVIGATOR_ORIENTATION occurs before NAVIGATOR_KEYBOARD_POSITION */
670 /* Rotate and resize the window */
671 fgPlatformRotateWindow(window, navigator_event_get_orientation_angle(fgDisplay.pDisplay.event));
672 fgPlatformFlushCommands();
674 /* PlayBook doesn't indicate what the new size will be, so we need to retrieve it from the window itself */
675 window->State.pWState.newWidth = glutGet(GLUT_WINDOW_WIDTH);
676 window->State.pWState.newHeight = glutGet(GLUT_WINDOW_HEIGHT);
678 fghOnReshapeNotify(window, window->State.pWState.newWidth, window->State.pWState.newHeight, GL_FALSE);
681 window->State.pWState.newWidth = 0;
682 window->State.pWState.newHeight = 0;
685 navigator_done_orientation(fgDisplay.pDisplay.event);
689 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_BACK");
690 INVOKE_WCB(*window, Keyboard, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
691 INVOKE_WCB(*window, KeyboardUp, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
694 case NAVIGATOR_WINDOW_ACTIVE:
695 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_ACTIVE");
696 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_RESUME));
699 case NAVIGATOR_WINDOW_INACTIVE:
700 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_INACTIVE");
701 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_PAUSE));
704 case NAVIGATOR_ORIENTATION_DONE:
705 case NAVIGATOR_ORIENTATION_RESULT:
706 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_DONE/NAVIGATOR_ORIENTATION_RESULT");
710 case NAVIGATOR_KEYBOARD_STATE:
712 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE");
714 navigator_keyboard_state_t state = navigator_event_get_keyboard_state(fgDisplay.pDisplay.event);
717 case NAVIGATOR_KEYBOARD_CLOSED:
718 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE-NAVIGATOR_KEYBOARD_CLOSED");
719 /* NAVIGATOR_KEYBOARD_POSITION only occurs on open, so on keyboard close we need to reset the keyboard height */
720 fgPlatformHandleKeyboardHeight(window, 0);
722 case NAVIGATOR_KEYBOARD_OPENING:
723 case NAVIGATOR_KEYBOARD_OPENED:
724 case NAVIGATOR_KEYBOARD_CLOSING:
726 case NAVIGATOR_KEYBOARD_UNRECOGNIZED:
727 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE-NAVIGATOR_KEYBOARD_UNRECOGNIZED");
730 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
736 case NAVIGATOR_KEYBOARD_POSITION:
738 /* Occurs only when keyboard has opened or resizes */
739 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_POSITION");
741 int keyboardOffset = navigator_event_get_keyboard_position(fgDisplay.pDisplay.event);
742 if(keyboardOffset == BPS_FAILURE) {
743 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_POSITION: getting keyboard offset failed");
745 /* keyboardOffset is the offset from the top of the screen to the top of the keyboard, AKA the size of the uncovered screen
746 We want the height of the keyboard. So instead of determining the orientation, getting the right display size, and subtracting;
747 we just get the keyboard height which may be slower but easier to understand and work with */
748 virtualkeyboard_get_height(&keyboardOffset);
749 fgPlatformHandleKeyboardHeight(window, keyboardOffset);
754 case NAVIGATOR_DEVICE_LOCK_STATE:
757 case NAVIGATOR_WINDOW_COVER:
758 case NAVIGATOR_WINDOW_COVER_ENTER:
759 case NAVIGATOR_WINDOW_COVER_EXIT:
760 /* BlackBerry specific. Let app status and window status take care of everything */
763 case NAVIGATOR_APP_STATE:
764 /* Can do the same as NAVIGATOR_WINDOW_ACTIVE/NAVIGATOR_WINDOW_INACTIVE but
765 seems like it doesn't work when the app comes to the foreground. Might be a bug */
768 case NAVIGATOR_ORIENTATION_SIZE:
769 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_SIZE");
771 /* Get new window size */
772 window->State.pWState.newWidth = navigator_event_get_orientation_size_width(fgDisplay.pDisplay.event);
773 window->State.pWState.newHeight = navigator_event_get_orientation_size_height(fgDisplay.pDisplay.event);
777 case 0: //Doesn't exist in header, but shows up when keyboard shows and resizes
781 LOGW("fgPlatformProcessSingleEvent: unknown navigator event: 0x%X", SLOG2_FA_SIGNED(eventType));
786 /* While this could be used for non-PlayBook, BlackBerry 10 will still get navigator events, so use those. They are a bit more exact. */
787 else if(domain == virtualkeyboard_get_domain()) {
788 unsigned int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
790 case VIRTUALKEYBOARD_EVENT_VISIBLE:
791 LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_VISIBLE");
792 if(window->State.pWState.keyboardOpen != GL_TRUE) {
793 window->State.pWState.keyboardOpen = GL_TRUE;
794 fgPlatformHandleKeyboardHeight(window, window->State.pWState.keyboardHeight);
798 case VIRTUALKEYBOARD_EVENT_HIDDEN:
799 LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_HIDDEN");
800 if(window->State.pWState.keyboardOpen != GL_FALSE) {
801 window->State.pWState.keyboardOpen = GL_FALSE;
802 fgPlatformHandleKeyboardHeight(window, 0);
806 case VIRTUALKEYBOARD_EVENT_INFO:
807 LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_INFO");
808 window->State.pWState.keyboardHeight = virtualkeyboard_event_get_height(fgDisplay.pDisplay.event);
809 if(window->State.pWState.keyboardOpen == GL_TRUE) {
810 fgPlatformHandleKeyboardHeight(window, window->State.pWState.keyboardHeight);
815 LOGW("fgPlatformProcessSingleEvent: unknown virtualkeyboard event: 0x%X", eventType);
820 } while(bps_get_event(&fgDisplay.pDisplay.event, 1) == BPS_SUCCESS && fgDisplay.pDisplay.event != NULL);
822 /* Reset event to reduce chances of triggering something */
823 fgDisplay.pDisplay.event = NULL;
826 void fgPlatformMainLoopPreliminaryWork ( void )
828 LOGI("fgPlatformMainLoopPreliminaryWork");
830 /* Request navigator events */
831 navigator_request_events(0);
834 navigator_rotation_lock(false);
837 /* Request keyboard events */
838 virtualkeyboard_request_events(0);
841 /* Request window events */
842 screen_request_events(fgDisplay.pDisplay.screenContext);
845 void fgPlatformMainLoopPostWork ( void )
847 LOGI("fgPlatformMainLoopPostWork");
849 /* Stop all events */
850 screen_stop_events(fgDisplay.pDisplay.screenContext);
853 navigator_stop_events(0);
857 /* deal with work list items */
858 void fgPlatformInitWork(SFG_Window* window)
860 LOGI("fgPlatformInitWork");
862 /* Position callback, always at 0,0 */
863 fghOnPositionNotify(window, 0, 0, GL_TRUE);
865 /* Get window size */
867 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
868 fghOnReshapeNotify(window, size[0], size[1], GL_FALSE);
870 /* Size gets notified on window creation with size detection in mainloop above
871 * XXX CHECK: does this messages happen too early like on windows,
872 * so client code cannot have registered a callback yet and the message
873 * is thus never received by client?
877 void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask)
879 if (workMask & GLUT_FULL_SCREEN_WORK)
880 fgPlatformFullScreenToggle( window );
881 if (workMask & GLUT_POSITION_WORK)
882 fgPlatformPositionWindow( window, window->State.DesiredXpos, window->State.DesiredYpos );
883 if (workMask & GLUT_SIZE_WORK)
884 fgPlatformReshapeWindow ( window, window->State.DesiredWidth, window->State.DesiredHeight );
885 if (workMask & GLUT_ZORDER_WORK)
887 if (window->State.DesiredZOrder < 0)
888 fgPlatformPushWindow( window );
890 fgPlatformPopWindow( window );
894 void fgPlatformVisibilityWork(SFG_Window* window)
896 /* Visibility status of window should get updated in the window message handlers
897 * For now, none of these functions called below do anything, so don't worry
900 SFG_Window *win = window;
901 switch (window->State.DesiredVisibility)
903 case DesireHiddenState:
904 fgPlatformHideWindow( window );
906 case DesireIconicState:
907 /* Call on top-level window */
910 fgPlatformIconifyWindow( win );
912 case DesireNormalState:
913 fgPlatformShowWindow( window );