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"
35 #define LOGI(...) ((void)slog2fa(NULL, 1337, SLOG2_INFO, __VA_ARGS__, SLOG2_FA_END))
36 #define LOGW(...) ((void)slog2fa(NULL, 1337, SLOG2_WARNING, __VA_ARGS__, SLOG2_FA_END))
37 #include <sys/keycodes.h>
38 #include <input/screen_helpers.h>
40 #include <bps/event.h>
41 #include <bps/screen.h>
42 #include <bps/navigator.h>
43 #include <bps/virtualkeyboard.h>
45 extern void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify);
46 extern void fghOnPositionNotify(SFG_Window *window, int x, int y, GLboolean forceNotify);
47 extern void fgPlatformFullScreenToggle( SFG_Window *win );
48 extern void fgPlatformPositionWindow( SFG_Window *window, int x, int y );
49 extern void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height );
50 extern void fgPlatformPushWindow( SFG_Window *window );
51 extern void fgPlatformPopWindow( SFG_Window *window );
52 extern void fgPlatformHideWindow( SFG_Window *window );
53 extern void fgPlatformIconifyWindow( SFG_Window *window );
54 extern void fgPlatformShowWindow( SFG_Window *window );
55 extern void fgPlatformMainLoopPostWork ( void );
56 extern void fgPlatformRotateWindow( SFG_Window *window, int rotation );
57 extern void fgPlatformFlushCommands ( void );
59 static struct touchscreen touchscreen;
61 #define ESCAPE_BUTTON_KEY 0x001B
63 unsigned int key_special(int qnxKeycode)
91 return GLUT_KEY_PAGE_UP;
93 return GLUT_KEY_PAGE_DOWN;
99 return GLUT_KEY_INSERT;
101 //case KEYCODE_KP_UP:
104 //case KEYCODE_KP_DOWN:
105 return GLUT_KEY_DOWN;
107 //case KEYCODE_KP_LEFT:
108 return GLUT_KEY_LEFT;
110 //case KEYCODE_KP_RIGHT:
111 return GLUT_KEY_RIGHT;
112 case KEYCODE_NUM_LOCK:
113 return GLUT_KEY_NUM_LOCK;
114 case KEYCODE_LEFT_ALT:
115 return GLUT_KEY_ALT_L;
116 case KEYCODE_RIGHT_ALT:
117 return GLUT_KEY_ALT_R;
118 case KEYCODE_LEFT_SHIFT:
119 return GLUT_KEY_SHIFT_L;
120 case KEYCODE_RIGHT_SHIFT:
121 return GLUT_KEY_SHIFT_R;
122 case KEYCODE_LEFT_CTRL:
123 return GLUT_KEY_CTRL_L;
124 case KEYCODE_RIGHT_CTRL:
125 return GLUT_KEY_CTRL_R;
130 unsigned char key_ascii(int qnxKeycode)
132 if (qnxKeycode >= KEYCODE_PC_KEYS && qnxKeycode <= UNICODE_PRIVATE_USE_AREA_LAST) {
133 switch (qnxKeycode) {
134 case KEYCODE_BACKSPACE:
138 case KEYCODE_KP_ENTER:
142 return ESCAPE_BUTTON_KEY;
149 fg_time_t fgPlatformSystemTime ( void )
151 #ifdef CLOCK_MONOTONIC
153 clock_gettime(CLOCK_MONOTONIC, &now);
154 return now.tv_nsec/1000000 + now.tv_sec*1000;
155 #elif defined(HAVE_GETTIMEOFDAY)
157 gettimeofday( &now, NULL );
158 return now.tv_usec/1000 + now.tv_sec*1000;
163 * Does the magic required to relinquish the CPU until something interesting
166 void fgPlatformSleepForEvents( fg_time_t msec )
168 if(fgStructure.CurrentWindow && fgDisplay.pDisplay.event == NULL && bps_get_event(&fgDisplay.pDisplay.event, (int)msec) != BPS_SUCCESS) {
169 LOGW("BPS couldn't get event");
173 void handle_left_mouse(int x, int y, int height, int eventType, SFG_Window* window)
175 bool handled = false;
176 /* Virtual arrows PAD */
177 /* Don't interfere with existing mouse move event */
178 if (!touchscreen.in_mmotion) {
179 struct vpad_state prev_vpad = touchscreen.vpad;
180 touchscreen.vpad.left = touchscreen.vpad.right = touchscreen.vpad.up = touchscreen.vpad.down = false;
182 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH || eventType == SCREEN_EVENT_MTOUCH_MOVE) {
183 if ((x > 0 && x < 100) && (y > (height - 100) && y < height))
185 touchscreen.vpad.left = true;
187 if ((x > 200 && x < 300) && (y > (height - 100) && y < height))
189 touchscreen.vpad.right = true;
191 if ((x > 100 && x < 200) && (y > (height - 100) && y < height))
193 touchscreen.vpad.down = true;
195 if ((x > 100 && x < 200) && (y > (height - 200) && y < (height - 100)))
197 touchscreen.vpad.up = true;
201 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH &&
202 (touchscreen.vpad.left || touchscreen.vpad.right || touchscreen.vpad.down || touchscreen.vpad.up)) {
203 touchscreen.vpad.on = true;
205 if (eventType == SCREEN_EVENT_MTOUCH_RELEASE) {
206 touchscreen.vpad.on = false;
209 if (prev_vpad.left != touchscreen.vpad.left
210 || prev_vpad.right != touchscreen.vpad.right
211 || prev_vpad.up != touchscreen.vpad.up
212 || prev_vpad.down != touchscreen.vpad.down
213 || prev_vpad.on != touchscreen.vpad.on) {
214 if (FETCH_WCB(*window, Special)) {
215 if (prev_vpad.left == false && touchscreen.vpad.left == true) {
216 INVOKE_WCB(*window, Special, (GLUT_KEY_LEFT, x, y));
218 else if (prev_vpad.right == false && touchscreen.vpad.right == true) {
219 INVOKE_WCB(*window, Special, (GLUT_KEY_RIGHT, x, y));
221 else if (prev_vpad.up == false && touchscreen.vpad.up == true) {
222 INVOKE_WCB(*window, Special, (GLUT_KEY_UP, x, y));
224 else if (prev_vpad.down == false && touchscreen.vpad.down == true) {
225 INVOKE_WCB(*window, Special, (GLUT_KEY_DOWN, x, y));
228 if (FETCH_WCB(*window, SpecialUp)) {
229 if (prev_vpad.left == true && touchscreen.vpad.left == false) {
230 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_LEFT, x, y));
232 if (prev_vpad.right == true && touchscreen.vpad.right == false) {
233 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_RIGHT, x, y));
235 if (prev_vpad.up == true && touchscreen.vpad.up == false) {
236 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_UP, x, y));
238 if (prev_vpad.down == true && touchscreen.vpad.down == false) {
239 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_DOWN, x, y));
246 /* Normal mouse events */
247 if (!handled && !touchscreen.vpad.on) {
248 window->State.MouseX = x;
249 window->State.MouseY = y;
251 if(eventType == SCREEN_EVENT_MTOUCH_MOVE) {
252 INVOKE_WCB(*window, Motion, (x, y));
253 } else if(FETCH_WCB(*window, Mouse)) {
254 touchscreen.in_mmotion = eventType == SCREEN_EVENT_MTOUCH_TOUCH;
255 int glutTouchType = eventType == SCREEN_EVENT_MTOUCH_TOUCH ? GLUT_DOWN : GLUT_UP;
256 INVOKE_WCB(*window, Mouse, (GLUT_LEFT_BUTTON, glutTouchType, x, y));
262 * Determine a GLUT modifier mask based on BlackBerry modifier info.
264 int fgPlatformGetModifiers (int mod)
266 return (((mod & KEYMOD_SHIFT) ? GLUT_ACTIVE_SHIFT : 0) |
267 ((mod & KEYMOD_CTRL) ? GLUT_ACTIVE_CTRL : 0) |
268 ((mod & KEYMOD_ALT) ? GLUT_ACTIVE_ALT : 0));
271 void fgPlatformHandleKeyboardHeight(SFG_Window* window, int height)
275 int nScreenHeight = -1;
277 screenHeight = glutGet(GLUT_WINDOW_HEIGHT); //Using this takes rotation into account
279 nScreenHeight = screenHeight;
281 else if(!screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_POSITION, size)) {
282 /* Calculate the new screen size */ //XXX Make sure to use display size instead of screen size
283 nScreenHeight = ((size[1] + screenHeight) - height) - size[1];
286 if(nScreenHeight != -1) {
287 /* If nScreenHeight is less then zero then window is covered. If nScreenHeight == height, then no change in size. Else, change in size */
289 int screenWidth = glutGet(GLUT_WINDOW_WIDTH);
290 if(nScreenHeight < 0) {
291 LOGI("fgPlatformHandleKeyboardHeight: Covered window state");
292 window->State.Visible = GL_FALSE;
293 window->State.pWState.windowCovered = GL_TRUE;
294 INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_COVERED));
295 fghOnReshapeNotify(window, screenWidth, 0, GL_FALSE);
297 if(window->State.pWState.windowCovered == GL_TRUE) {
298 LOGI("fgPlatformHandleKeyboardHeight: Resetting window state");
300 /* Reset window status if it was previously covered */
301 switch(window->State.pWState.windowState) {
302 case NAVIGATOR_WINDOW_FULLSCREEN:
303 window->State.Visible = GL_TRUE;
304 INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED));
306 case NAVIGATOR_WINDOW_THUMBNAIL:
307 window->State.Visible = GL_TRUE;
308 INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
310 case NAVIGATOR_WINDOW_INVISIBLE:
311 window->State.Visible = GL_FALSE;
312 INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN));
315 window->State.pWState.windowCovered = GL_FALSE;
317 fghOnReshapeNotify(window, screenWidth, nScreenHeight, GL_FALSE);
322 void fgPlatformProcessSingleEvent ( void )
324 if(fgStructure.CurrentWindow == NULL) {
325 //XXX Is this right? Would this just cause a whole lot of busy looping while we wait for events?
326 LOGW("fgPlatformProcessSingleEvent: Missing current window. Skipping event processing");
330 if(fgDisplay.pDisplay.event == NULL)
337 SFG_Window* window = fgStructure.CurrentWindow;
338 domain = bps_event_get_domain(fgDisplay.pDisplay.event);
339 if (domain == screen_get_domain()) {
342 screen_event_t screenEvent = screen_event_get_event(fgDisplay.pDisplay.event);
343 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_TYPE, &eventType);
346 //Mostly from fg_main_android
347 case SCREEN_EVENT_MTOUCH_TOUCH:
348 case SCREEN_EVENT_MTOUCH_RELEASE:
349 case SCREEN_EVENT_MTOUCH_MOVE:
351 mtouch_event_t touchEvent;
352 screen_get_mtouch_event(screenEvent, &touchEvent, 0);
353 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
355 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));
357 /* Remember the current modifiers state so user can query it from their callback */
358 fgState.Modifiers = fgPlatformGetModifiers(mod);
360 if(touchEvent.contact_id == 0) {
362 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
363 handle_left_mouse(touchEvent.x, touchEvent.y, size[1], eventType, window);
366 //Now handle mutlitouch (adapted from fg_main_windows)
367 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH) {
368 INVOKE_WCB( *window, MultiEntry, ( touchEvent.contact_id, GLUT_ENTERED ) );
369 INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_DOWN ) );
370 } else if (eventType == SCREEN_EVENT_MTOUCH_MOVE) {
371 INVOKE_WCB( *window, MultiMotion, ( touchEvent.contact_id, touchEvent.x, touchEvent.y ) );
372 //XXX No motion is performed without contact, thus MultiPassive is never used
373 } else if (eventType == SCREEN_EVENT_MTOUCH_RELEASE) {
374 INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_UP ) );
375 INVOKE_WCB( *window, MultiEntry, ( touchEvent.contact_id, GLUT_LEFT ) );
378 fgState.Modifiers = INVALID_MODIFIERS;
382 case SCREEN_EVENT_POINTER:
384 //Based off/part taken from GamePlay3d PlatformBlackBerry
385 static int mouse_pressed = 0;
389 // A move event will be fired unless a button state changed.
391 bool left_move = false;
392 // This is a mouse move event, it is applicable to a device with a usb mouse or simulator.
393 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_BUTTONS, &buttons);
394 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_SOURCE_POSITION, position);
395 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_MOUSE_WHEEL, &wheel);
396 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
398 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
400 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));
402 //XXX Is multitouch be handled in a good way?
404 /* Remember the current modifiers state so user can query it from their callback */
405 fgState.Modifiers = fgPlatformGetModifiers(mod);
407 // Handle left mouse. Interpret as touch if the left mouse event is not consumed.
408 if (buttons & SCREEN_LEFT_MOUSE_BUTTON) {
409 if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
413 mouse_pressed |= SCREEN_LEFT_MOUSE_BUTTON;
414 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_TOUCH, window);
416 } else if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
418 mouse_pressed &= ~SCREEN_LEFT_MOUSE_BUTTON;
419 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_RELEASE, window);
422 // Handle right mouse.
423 if (buttons & SCREEN_RIGHT_MOUSE_BUTTON) {
424 if ((mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) == 0) {
426 mouse_pressed |= SCREEN_RIGHT_MOUSE_BUTTON;
427 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_DOWN, position[0], position[1]));
429 } else if (mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) {
431 mouse_pressed &= ~SCREEN_RIGHT_MOUSE_BUTTON;
432 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_UP, position[0], position[1]));
435 // Handle middle mouse.
436 if (buttons & SCREEN_MIDDLE_MOUSE_BUTTON) {
437 if ((mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) == 0) {
439 mouse_pressed |= SCREEN_MIDDLE_MOUSE_BUTTON;
440 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_DOWN, position[0], position[1]));
442 } else if (mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) {
444 mouse_pressed &= ~SCREEN_MIDDLE_MOUSE_BUTTON;
445 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_UP, position[0], position[1]));
448 // Fire a move event if none of the buttons changed.
449 if (left_move || move) {
450 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_MOVE, window);
454 /* Very slightly modified from fg_main_mswin.
455 * Because we don't want MouseWheel to be called every. single. time.
456 * That the action occurs, we mimic the Windows version with "wheel deltas"
457 * XXX Do we even want this?
458 * XXX If we want this, it's possible to get horizontal scroll as well.
459 * XXX -Vertical scroll=wheel 0, horizontal=wheel 1? */
460 fgState.MouseWheelTicks -= wheel;
461 if (abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
463 int wheel_number = 0;
464 int direction = (fgState.MouseWheelTicks > 0) ? -1 : 1;
466 if (!FETCH_WCB(*window, MouseWheel) && !FETCH_WCB(*window, Mouse))
469 //XXX fgSetWindow(window);
471 while(abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
473 if (FETCH_WCB(*window, MouseWheel))
474 INVOKE_WCB(*window, MouseWheel, (wheel_number, direction, window->State.MouseX, window->State.MouseY));
475 else /* No mouse wheel, call the mouse button callback twice */
478 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
479 * " " one +1 to 5, -1 to 6, ...
481 * XXX The below assumes that you have no more than 3 mouse
482 * XXX buttons. Sorry.
484 int button = wheel_number * 2 + 3;
487 INVOKE_WCB(*window, Mouse, (button, GLUT_DOWN, window->State.MouseX, window->State.MouseY));
488 INVOKE_WCB(*window, Mouse, (button, GLUT_UP, window->State.MouseX, window->State.MouseY));
491 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
496 fgState.Modifiers = INVALID_MODIFIERS;
500 //Based off fg_main_android
501 case SCREEN_EVENT_KEYBOARD:
505 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_FLAGS, &flags);
506 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_SYM, &value);
507 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
509 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));
511 /* Suppress key repeats if desired. Based off fg_main_mswin */
512 if ((flags & KEY_REPEAT) == 0 || (fgState.KeyRepeat == GLUT_KEY_REPEAT_OFF && fgStructure.CurrentWindow->State.IgnoreKeyRepeat == GL_TRUE)) {
513 unsigned int keypress = 0;
514 unsigned char ascii = 0;
516 /* Remember the current modifiers state so user can query it from their callback */
517 fgState.Modifiers = fgPlatformGetModifiers(mod);
520 if ((keypress = key_special(value))) {
521 if(flags & KEY_DOWN) {
522 INVOKE_WCB(*window, Special, (keypress, window->State.MouseX, window->State.MouseY));
524 INVOKE_WCB(*window, SpecialUp, (keypress, window->State.MouseX, window->State.MouseY));
526 } else if((flags & KEY_SYM_VALID) && (ascii = key_ascii(value))) {
527 if(flags & KEY_DOWN) {
528 INVOKE_WCB(*window, Keyboard, (ascii, window->State.MouseX, window->State.MouseY));
530 INVOKE_WCB(*window, KeyboardUp, (ascii, window->State.MouseX, window->State.MouseY));
533 LOGW("fgPlatformProcessSingleEvent: SCREEN_EVENT_KEYBOARD. Unhandled key event");
536 fgState.Modifiers = INVALID_MODIFIERS;
541 case SCREEN_EVENT_PROPERTY:
542 case SCREEN_EVENT_IDLE:
546 LOGW("fgPlatformProcessSingleEvent: unknown screen event: 0x%X", SLOG2_FA_SIGNED(eventType));
549 } else if (domain == navigator_get_domain()) {
550 int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
553 case NAVIGATOR_WINDOW_STATE:
555 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE");
557 /* Covered only happens due to keyboard. When the app is minimized, the keyboard is closed.
558 When the keyboard is open, and the app is fullscreened, the keyboard is also closed.
559 If a window is covered and the app is minimized, the state will be set and the keyboard event
560 will adjust the screen size and change window status. */
561 navigator_window_state_t state = navigator_event_get_window_state(fgDisplay.pDisplay.event);
562 if(window->State.pWState.windowCovered == GL_FALSE)
566 case NAVIGATOR_WINDOW_FULLSCREEN:
567 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_FULLSCREEN");
568 window->State.Visible = GL_TRUE;
569 INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED));
571 case NAVIGATOR_WINDOW_THUMBNAIL:
572 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_THUMBNAIL");
573 window->State.Visible = GL_TRUE;
574 INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
576 case NAVIGATOR_WINDOW_INVISIBLE:
577 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_INVISIBLE");
578 window->State.Visible = GL_FALSE;
579 INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN));
582 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
586 window->State.pWState.windowState = state;
592 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_EXIT");
594 fgPlatformMainLoopPostWork();
596 /* User closed the application for good, let's kill the window */
597 SFG_Window* window = fgStructure.CurrentWindow;
598 if (window != NULL) {
599 fgDestroyWindow(window);
601 LOGW("NAVIGATOR_EXIT: No current window");
606 case NAVIGATOR_SWIPE_DOWN:
607 /* XXX Open app menu */
610 /* Orientation is a bunch of handshakes.
611 - First the app get's asked if it wants to rotate (NAVIGATOR_ORIENTATION_CHECK)
612 - If the app wants to rotate, then it will be told what size it will be after rotate (NAVIGATOR_ORIENTATION_SIZE).
613 - Once the OS confirms that it's ready to rotate, it tells the app to handle rotation (NAVIGATOR_ORIENTATION).
614 - Once rotation is complete, the OS tells the app it's done (NAVIGATOR_ORIENTATION_DONE) */
615 case NAVIGATOR_ORIENTATION_CHECK:
616 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_CHECK");
619 window->State.pWState.newWidth = 0;
620 window->State.pWState.newHeight = 0;
622 /* Notify that we want to rotate */
623 navigator_orientation_check_response(fgDisplay.pDisplay.event, true);
626 case NAVIGATOR_ORIENTATION:
627 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION");
629 /* NAVIGATOR_ORIENTATION occurs before NAVIGATOR_KEYBOARD_POSITION */
631 /* Rotate and resize the window */
632 fgPlatformRotateWindow(window, navigator_event_get_orientation_angle(fgDisplay.pDisplay.event));
633 fgPlatformFlushCommands();
634 fghOnReshapeNotify(window, window->State.pWState.newWidth, window->State.pWState.newHeight, GL_FALSE);
637 window->State.pWState.newWidth = 0;
638 window->State.pWState.newHeight = 0;
641 navigator_done_orientation(fgDisplay.pDisplay.event);
645 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_BACK");
646 INVOKE_WCB(*window, Keyboard, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
647 INVOKE_WCB(*window, KeyboardUp, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
650 case NAVIGATOR_WINDOW_ACTIVE:
651 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_ACTIVE");
652 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_RESUME));
655 case NAVIGATOR_WINDOW_INACTIVE:
656 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_INACTIVE");
657 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_PAUSE));
660 case NAVIGATOR_ORIENTATION_DONE:
661 case NAVIGATOR_ORIENTATION_RESULT:
662 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_DONE/NAVIGATOR_ORIENTATION_RESULT");
665 case NAVIGATOR_KEYBOARD_STATE:
667 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE");
669 navigator_keyboard_state_t state = navigator_event_get_keyboard_state(fgDisplay.pDisplay.event);
672 case NAVIGATOR_KEYBOARD_CLOSED:
673 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE-NAVIGATOR_KEYBOARD_CLOSED");
674 /* NAVIGATOR_KEYBOARD_POSITION only occurs on open, so on keyboard close we need to reset the keyboard height */
675 fgPlatformHandleKeyboardHeight(window, 0);
677 case NAVIGATOR_KEYBOARD_OPENING:
678 case NAVIGATOR_KEYBOARD_OPENED:
679 case NAVIGATOR_KEYBOARD_CLOSING:
681 case NAVIGATOR_KEYBOARD_UNRECOGNIZED:
682 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE-NAVIGATOR_KEYBOARD_UNRECOGNIZED");
685 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
691 case NAVIGATOR_KEYBOARD_POSITION:
693 /* Occurs only when keyboard has opened or resizes */
694 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_POSITION");
696 int keyboardOffset = navigator_event_get_keyboard_position(fgDisplay.pDisplay.event);
697 if(keyboardOffset == BPS_FAILURE) {
698 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_POSITION: getting keyboard offset failed");
700 /* keyboardOffset is the offset from the top of the screen to the top of the keyboard, AKA the size of the uncovered screen
701 We want the height of the keyboard. So instead of determining the orientation, getting the right display size, and subtracting;
702 we just get the keyboard height which may be slower but easier to understand and work with */
703 virtualkeyboard_get_height(&keyboardOffset);
704 fgPlatformHandleKeyboardHeight(window, keyboardOffset);
709 case NAVIGATOR_DEVICE_LOCK_STATE:
712 case NAVIGATOR_WINDOW_COVER:
713 case NAVIGATOR_WINDOW_COVER_ENTER:
714 case NAVIGATOR_WINDOW_COVER_EXIT:
715 /* BlackBerry specific. Let app status and window status take care of everything */
718 case NAVIGATOR_APP_STATE:
719 /* Can do the same as NAVIGATOR_WINDOW_ACTIVE/NAVIGATOR_WINDOW_INACTIVE but
720 seems like it doesn't work when the app comes to the foreground. Might be a bug */
723 case NAVIGATOR_ORIENTATION_SIZE:
724 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_SIZE");
726 /* Get new window size */
727 window->State.pWState.newWidth = navigator_event_get_orientation_size_width(fgDisplay.pDisplay.event);
728 window->State.pWState.newHeight = navigator_event_get_orientation_size_height(fgDisplay.pDisplay.event);
731 case 0: //Doesn't exist in header, but shows up when keyboard shows and resizes
735 LOGW("fgPlatformProcessSingleEvent: unknown navigator event: 0x%X", SLOG2_FA_SIGNED(eventType));
739 } while(bps_get_event(&fgDisplay.pDisplay.event, 1) == BPS_SUCCESS && fgDisplay.pDisplay.event != NULL);
741 /* Reset event to reduce chances of triggering something */
742 fgDisplay.pDisplay.event = NULL;
745 void fgPlatformMainLoopPreliminaryWork ( void )
747 LOGI("fgPlatformMainLoopPreliminaryWork");
749 /* Request navigator events */
750 navigator_request_events(0);
753 navigator_rotation_lock(false);
755 /* Request window events */
756 screen_request_events(fgDisplay.pDisplay.screenContext);
759 void fgPlatformMainLoopPostWork ( void )
761 LOGI("fgPlatformMainLoopPostWork");
763 /* Stop all events */
764 screen_stop_events(fgDisplay.pDisplay.screenContext);
766 navigator_stop_events(0);
769 /* deal with work list items */
770 void fgPlatformInitWork(SFG_Window* window)
772 LOGI("fgPlatformInitWork");
774 /* Position callback, always at 0,0 */
775 fghOnPositionNotify(window, 0, 0, GL_TRUE);
777 /* Get window size */
779 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
780 fghOnReshapeNotify(window, size[0], size[1], GL_FALSE);
782 /* Size gets notified on window creation with size detection in mainloop above
783 * XXX CHECK: does this messages happen too early like on windows,
784 * so client code cannot have registered a callback yet and the message
785 * is thus never received by client?
789 void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask)
791 if (workMask & GLUT_FULL_SCREEN_WORK)
792 fgPlatformFullScreenToggle( window );
793 if (workMask & GLUT_POSITION_WORK)
794 fgPlatformPositionWindow( window, window->State.DesiredXpos, window->State.DesiredYpos );
795 if (workMask & GLUT_SIZE_WORK)
796 fgPlatformReshapeWindow ( window, window->State.DesiredWidth, window->State.DesiredHeight );
797 if (workMask & GLUT_ZORDER_WORK)
799 if (window->State.DesiredZOrder < 0)
800 fgPlatformPushWindow( window );
802 fgPlatformPopWindow( window );
806 void fgPlatformVisibilityWork(SFG_Window* window)
808 /* Visibility status of window should get updated in the window message handlers
809 * For now, none of these functions called below do anything, so don't worry
812 SFG_Window *win = window;
813 switch (window->State.DesiredVisibility)
815 case DesireHiddenState:
816 fgPlatformHideWindow( window );
818 case DesireIconicState:
819 /* Call on top-level window */
822 fgPlatformIconifyWindow( win );
824 case DesireNormalState:
825 fgPlatformShowWindow( window );