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"
39 #define LOGI(...) ((void)slogf(1337, _SLOG_INFO, __VA_ARGS__))
41 #define LOGW(...) ((void)slogf(1337, _SLOG_WARNING, __VA_ARGS__))
42 #ifndef SLOG2_FA_SIGNED
43 #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 domain = bps_event_get_domain(fgDisplay.pDisplay.event);
357 if (domain == screen_get_domain()) {
360 screen_event_t screenEvent = screen_event_get_event(fgDisplay.pDisplay.event);
361 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_TYPE, &eventType);
364 //Mostly from fg_main_android
365 case SCREEN_EVENT_MTOUCH_TOUCH:
366 case SCREEN_EVENT_MTOUCH_RELEASE:
367 case SCREEN_EVENT_MTOUCH_MOVE:
369 mtouch_event_t touchEvent;
370 screen_get_mtouch_event(screenEvent, &touchEvent, 0);
372 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
377 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));
379 /* Remember the current modifiers state so user can query it from their callback */
380 fgState.Modifiers = fgPlatformGetModifiers(mod);
382 if(touchEvent.contact_id == 0) {
384 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
385 handle_left_mouse(touchEvent.x, touchEvent.y, size[1], eventType, window);
388 //Now handle mutlitouch (adapted from fg_main_windows)
389 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH) {
390 INVOKE_WCB( *window, MultiEntry, ( touchEvent.contact_id, GLUT_ENTERED ) );
391 INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_DOWN ) );
392 } else if (eventType == SCREEN_EVENT_MTOUCH_MOVE) {
393 INVOKE_WCB( *window, MultiMotion, ( touchEvent.contact_id, touchEvent.x, touchEvent.y ) );
394 //XXX No motion is performed without contact, thus MultiPassive is never used
395 } else if (eventType == SCREEN_EVENT_MTOUCH_RELEASE) {
396 INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_UP ) );
397 INVOKE_WCB( *window, MultiEntry, ( touchEvent.contact_id, GLUT_LEFT ) );
400 fgState.Modifiers = INVALID_MODIFIERS;
404 case SCREEN_EVENT_POINTER:
406 //Based off/part taken from GamePlay3d PlatformBlackBerry
407 static int mouse_pressed = 0;
411 // A move event will be fired unless a button state changed.
413 bool left_move = false;
414 // This is a mouse move event, it is applicable to a device with a usb mouse or simulator.
415 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_BUTTONS, &buttons);
416 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_SOURCE_POSITION, position);
418 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_MOUSE_WHEEL, &wheel);
419 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
424 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
426 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));
428 //XXX Is multitouch be handled in a good way?
430 /* Remember the current modifiers state so user can query it from their callback */
431 fgState.Modifiers = fgPlatformGetModifiers(mod);
433 // Handle left mouse. Interpret as touch if the left mouse event is not consumed.
434 if (buttons & SCREEN_LEFT_MOUSE_BUTTON) {
435 if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
439 mouse_pressed |= SCREEN_LEFT_MOUSE_BUTTON;
440 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_TOUCH, window);
442 } else if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
444 mouse_pressed &= ~SCREEN_LEFT_MOUSE_BUTTON;
445 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_RELEASE, window);
448 // Handle right mouse.
449 if (buttons & SCREEN_RIGHT_MOUSE_BUTTON) {
450 if ((mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) == 0) {
452 mouse_pressed |= SCREEN_RIGHT_MOUSE_BUTTON;
453 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_DOWN, position[0], position[1]));
455 } else if (mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) {
457 mouse_pressed &= ~SCREEN_RIGHT_MOUSE_BUTTON;
458 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_UP, position[0], position[1]));
461 // Handle middle mouse.
462 if (buttons & SCREEN_MIDDLE_MOUSE_BUTTON) {
463 if ((mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) == 0) {
465 mouse_pressed |= SCREEN_MIDDLE_MOUSE_BUTTON;
466 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_DOWN, position[0], position[1]));
468 } else if (mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) {
470 mouse_pressed &= ~SCREEN_MIDDLE_MOUSE_BUTTON;
471 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_UP, position[0], position[1]));
474 // Fire a move event if none of the buttons changed.
475 if (left_move || move) {
476 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_MOVE, window);
480 /* Very slightly modified from fg_main_mswin.
481 * Because we don't want MouseWheel to be called every. single. time.
482 * That the action occurs, we mimic the Windows version with "wheel deltas"
483 * XXX Do we even want this?
484 * XXX If we want this, it's possible to get horizontal scroll as well.
485 * XXX -Vertical scroll=wheel 0, horizontal=wheel 1? */
486 fgState.MouseWheelTicks -= wheel;
487 if (abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
489 int wheel_number = 0;
490 int direction = (fgState.MouseWheelTicks > 0) ? -1 : 1;
492 if (!FETCH_WCB(*window, MouseWheel) && !FETCH_WCB(*window, Mouse))
495 //XXX fgSetWindow(window);
497 while(abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
499 if (FETCH_WCB(*window, MouseWheel))
500 INVOKE_WCB(*window, MouseWheel, (wheel_number, direction, window->State.MouseX, window->State.MouseY));
501 else /* No mouse wheel, call the mouse button callback twice */
504 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
505 * " " one +1 to 5, -1 to 6, ...
507 * XXX The below assumes that you have no more than 3 mouse
508 * XXX buttons. Sorry.
510 int button = wheel_number * 2 + 3;
513 INVOKE_WCB(*window, Mouse, (button, GLUT_DOWN, window->State.MouseX, window->State.MouseY));
514 INVOKE_WCB(*window, Mouse, (button, GLUT_UP, window->State.MouseX, window->State.MouseY));
517 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
522 fgState.Modifiers = INVALID_MODIFIERS;
526 //Based off fg_main_android
527 case SCREEN_EVENT_KEYBOARD:
531 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_FLAGS, &flags);
532 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_SYM, &value);
533 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
535 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));
537 /* Suppress key repeats if desired. Based off fg_main_mswin */
538 if ((flags & KEY_REPEAT) == 0 || (fgState.KeyRepeat == GLUT_KEY_REPEAT_OFF && fgStructure.CurrentWindow->State.IgnoreKeyRepeat == GL_TRUE)) {
539 unsigned int keypress = 0;
540 unsigned char ascii = 0;
542 /* Remember the current modifiers state so user can query it from their callback */
543 fgState.Modifiers = fgPlatformGetModifiers(mod);
546 if ((keypress = key_special(value))) {
547 if(flags & KEY_DOWN) {
548 INVOKE_WCB(*window, Special, (keypress, window->State.MouseX, window->State.MouseY));
550 INVOKE_WCB(*window, SpecialUp, (keypress, window->State.MouseX, window->State.MouseY));
552 } else if((flags & KEY_SYM_VALID) && (ascii = key_ascii(value))) {
553 if(flags & KEY_DOWN) {
554 INVOKE_WCB(*window, Keyboard, (ascii, window->State.MouseX, window->State.MouseY));
556 INVOKE_WCB(*window, KeyboardUp, (ascii, window->State.MouseX, window->State.MouseY));
559 LOGW("fgPlatformProcessSingleEvent: SCREEN_EVENT_KEYBOARD. Unhandled key event");
562 fgState.Modifiers = INVALID_MODIFIERS;
567 case SCREEN_EVENT_PROPERTY:
568 case SCREEN_EVENT_IDLE:
572 LOGW("fgPlatformProcessSingleEvent: unknown screen event: 0x%X", SLOG2_FA_SIGNED(eventType));
575 } else if (domain == navigator_get_domain()) {
576 unsigned int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
579 case NAVIGATOR_WINDOW_STATE:
581 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE");
583 /* Covered only happens due to keyboard. When the app is minimized, the keyboard is closed.
584 When the keyboard is open, and the app is fullscreened, the keyboard is also closed.
585 If a window is covered and the app is minimized, the state will be set and the keyboard event
586 will adjust the screen size and change window status. */
587 navigator_window_state_t state = navigator_event_get_window_state(fgDisplay.pDisplay.event);
588 if(window->State.pWState.windowCovered == GL_FALSE)
592 case NAVIGATOR_WINDOW_FULLSCREEN:
593 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_FULLSCREEN");
594 window->State.Visible = GL_TRUE;
595 INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED));
597 case NAVIGATOR_WINDOW_THUMBNAIL:
598 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_THUMBNAIL");
599 window->State.Visible = GL_TRUE;
600 INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
602 case NAVIGATOR_WINDOW_INVISIBLE:
603 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_INVISIBLE");
604 window->State.Visible = GL_FALSE;
605 INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN));
608 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
612 window->State.pWState.windowState = state;
618 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_EXIT");
620 fgPlatformMainLoopPostWork();
622 /* User closed the application for good, let's kill the window */
623 SFG_Window* window = fgStructure.CurrentWindow;
624 if (window != NULL) {
625 fgDestroyWindow(window);
627 LOGW("NAVIGATOR_EXIT: No current window");
632 case NAVIGATOR_SWIPE_DOWN:
633 /* XXX Open app menu */
636 /* Orientation is a bunch of handshakes.
637 - First the app get's asked if it wants to rotate (NAVIGATOR_ORIENTATION_CHECK)
638 - If the app wants to rotate, then it will be told what size it will be after rotate (NAVIGATOR_ORIENTATION_SIZE).
639 - Once the OS confirms that it's ready to rotate, it tells the app to handle rotation (NAVIGATOR_ORIENTATION).
640 - Once rotation is complete, the OS tells the app it's done (NAVIGATOR_ORIENTATION_DONE) */
641 case NAVIGATOR_ORIENTATION_CHECK:
642 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_CHECK");
645 window->State.pWState.newWidth = 0;
646 window->State.pWState.newHeight = 0;
648 /* Notify that we want to rotate */
649 navigator_orientation_check_response(fgDisplay.pDisplay.event, true);
652 case NAVIGATOR_ORIENTATION:
653 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION");
655 /* NAVIGATOR_ORIENTATION occurs before NAVIGATOR_KEYBOARD_POSITION */
657 /* Rotate and resize the window */
658 fgPlatformRotateWindow(window, navigator_event_get_orientation_angle(fgDisplay.pDisplay.event));
659 fgPlatformFlushCommands();
661 /* PlayBook doesn't indicate what the new size will be, so we need to retrieve it from the window itself */
662 window->State.pWState.newWidth = glutGet(GLUT_WINDOW_WIDTH);
663 window->State.pWState.newHeight = glutGet(GLUT_WINDOW_HEIGHT);
665 fghOnReshapeNotify(window, window->State.pWState.newWidth, window->State.pWState.newHeight, GL_FALSE);
668 window->State.pWState.newWidth = 0;
669 window->State.pWState.newHeight = 0;
672 navigator_done_orientation(fgDisplay.pDisplay.event);
676 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_BACK");
677 INVOKE_WCB(*window, Keyboard, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
678 INVOKE_WCB(*window, KeyboardUp, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
681 case NAVIGATOR_WINDOW_ACTIVE:
682 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_ACTIVE");
683 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_RESUME));
686 case NAVIGATOR_WINDOW_INACTIVE:
687 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_INACTIVE");
688 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_PAUSE));
691 case NAVIGATOR_ORIENTATION_DONE:
692 case NAVIGATOR_ORIENTATION_RESULT:
693 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_DONE/NAVIGATOR_ORIENTATION_RESULT");
697 case NAVIGATOR_KEYBOARD_STATE:
699 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE");
701 navigator_keyboard_state_t state = navigator_event_get_keyboard_state(fgDisplay.pDisplay.event);
704 case NAVIGATOR_KEYBOARD_CLOSED:
705 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE-NAVIGATOR_KEYBOARD_CLOSED");
706 /* NAVIGATOR_KEYBOARD_POSITION only occurs on open, so on keyboard close we need to reset the keyboard height */
707 fgPlatformHandleKeyboardHeight(window, 0);
709 case NAVIGATOR_KEYBOARD_OPENING:
710 case NAVIGATOR_KEYBOARD_OPENED:
711 case NAVIGATOR_KEYBOARD_CLOSING:
713 case NAVIGATOR_KEYBOARD_UNRECOGNIZED:
714 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE-NAVIGATOR_KEYBOARD_UNRECOGNIZED");
717 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
723 case NAVIGATOR_KEYBOARD_POSITION:
725 /* Occurs only when keyboard has opened or resizes */
726 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_POSITION");
728 int keyboardOffset = navigator_event_get_keyboard_position(fgDisplay.pDisplay.event);
729 if(keyboardOffset == BPS_FAILURE) {
730 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_POSITION: getting keyboard offset failed");
732 /* keyboardOffset is the offset from the top of the screen to the top of the keyboard, AKA the size of the uncovered screen
733 We want the height of the keyboard. So instead of determining the orientation, getting the right display size, and subtracting;
734 we just get the keyboard height which may be slower but easier to understand and work with */
735 virtualkeyboard_get_height(&keyboardOffset);
736 fgPlatformHandleKeyboardHeight(window, keyboardOffset);
741 case NAVIGATOR_DEVICE_LOCK_STATE:
744 case NAVIGATOR_WINDOW_COVER:
745 case NAVIGATOR_WINDOW_COVER_ENTER:
746 case NAVIGATOR_WINDOW_COVER_EXIT:
747 /* BlackBerry specific. Let app status and window status take care of everything */
750 case NAVIGATOR_APP_STATE:
751 /* Can do the same as NAVIGATOR_WINDOW_ACTIVE/NAVIGATOR_WINDOW_INACTIVE but
752 seems like it doesn't work when the app comes to the foreground. Might be a bug */
755 case NAVIGATOR_ORIENTATION_SIZE:
756 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_SIZE");
758 /* Get new window size */
759 window->State.pWState.newWidth = navigator_event_get_orientation_size_width(fgDisplay.pDisplay.event);
760 window->State.pWState.newHeight = navigator_event_get_orientation_size_height(fgDisplay.pDisplay.event);
764 case 0: //Doesn't exist in header, but shows up when keyboard shows and resizes
768 LOGW("fgPlatformProcessSingleEvent: unknown navigator event: 0x%X", SLOG2_FA_SIGNED(eventType));
773 else if(domain == virtualkeyboard_get_domain()) {
774 unsigned int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
776 case VIRTUALKEYBOARD_EVENT_VISIBLE:
779 case VIRTUALKEYBOARD_EVENT_HIDDEN:
780 LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_HIDDEN");
781 fgPlatformHandleKeyboardHeight(window, 0);
784 case VIRTUALKEYBOARD_EVENT_INFO:
785 LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_INFO");
786 fgPlatformHandleKeyboardHeight(window, virtualkeyboard_event_get_height(fgDisplay.pDisplay.event));
790 LOGW("fgPlatformProcessSingleEvent: unknown virtualkeyboard event: 0x%X", eventType);
795 } while(bps_get_event(&fgDisplay.pDisplay.event, 1) == BPS_SUCCESS && fgDisplay.pDisplay.event != NULL);
797 /* Reset event to reduce chances of triggering something */
798 fgDisplay.pDisplay.event = NULL;
801 void fgPlatformMainLoopPreliminaryWork ( void )
803 LOGI("fgPlatformMainLoopPreliminaryWork");
805 /* Request navigator events */
806 navigator_request_events(0);
809 navigator_rotation_lock(false);
812 /* Request keyboard events */
813 virtualkeyboard_request_events(0);
816 /* Request window events */
817 screen_request_events(fgDisplay.pDisplay.screenContext);
820 void fgPlatformMainLoopPostWork ( void )
822 LOGI("fgPlatformMainLoopPostWork");
824 /* Stop all events */
825 screen_stop_events(fgDisplay.pDisplay.screenContext);
828 navigator_stop_events(0);
832 /* deal with work list items */
833 void fgPlatformInitWork(SFG_Window* window)
835 LOGI("fgPlatformInitWork");
837 /* Position callback, always at 0,0 */
838 fghOnPositionNotify(window, 0, 0, GL_TRUE);
840 /* Get window size */
842 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
843 fghOnReshapeNotify(window, size[0], size[1], GL_FALSE);
845 /* Size gets notified on window creation with size detection in mainloop above
846 * XXX CHECK: does this messages happen too early like on windows,
847 * so client code cannot have registered a callback yet and the message
848 * is thus never received by client?
852 void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask)
854 if (workMask & GLUT_FULL_SCREEN_WORK)
855 fgPlatformFullScreenToggle( window );
856 if (workMask & GLUT_POSITION_WORK)
857 fgPlatformPositionWindow( window, window->State.DesiredXpos, window->State.DesiredYpos );
858 if (workMask & GLUT_SIZE_WORK)
859 fgPlatformReshapeWindow ( window, window->State.DesiredWidth, window->State.DesiredHeight );
860 if (workMask & GLUT_ZORDER_WORK)
862 if (window->State.DesiredZOrder < 0)
863 fgPlatformPushWindow( window );
865 fgPlatformPopWindow( window );
869 void fgPlatformVisibilityWork(SFG_Window* window)
871 /* Visibility status of window should get updated in the window message handlers
872 * For now, none of these functions called below do anything, so don't worry
875 SFG_Window *win = window;
876 switch (window->State.DesiredVisibility)
878 case DesireHiddenState:
879 fgPlatformHideWindow( window );
881 case DesireIconicState:
882 /* Call on top-level window */
885 fgPlatformIconifyWindow( win );
887 case DesireNormalState:
888 fgPlatformShowWindow( window );