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"
38 #define LOGI(...) ((void)slog2fa(NULL, 1337, SLOG2_INFO, __VA_ARGS__, SLOG2_FA_END))
40 #define LOGW(...) ((void)slog2fa(NULL, 1337, SLOG2_WARNING, __VA_ARGS__, SLOG2_FA_END))
41 #include <sys/keycodes.h>
42 #include <input/screen_helpers.h>
44 #include <bps/event.h>
45 #include <bps/screen.h>
46 #include <bps/navigator.h>
47 #include <bps/virtualkeyboard.h>
49 extern void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify);
50 extern void fghOnPositionNotify(SFG_Window *window, int x, int y, GLboolean forceNotify);
51 extern void fgPlatformFullScreenToggle( SFG_Window *win );
52 extern void fgPlatformPositionWindow( SFG_Window *window, int x, int y );
53 extern void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height );
54 extern void fgPlatformPushWindow( SFG_Window *window );
55 extern void fgPlatformPopWindow( SFG_Window *window );
56 extern void fgPlatformHideWindow( SFG_Window *window );
57 extern void fgPlatformIconifyWindow( SFG_Window *window );
58 extern void fgPlatformShowWindow( SFG_Window *window );
59 extern void fgPlatformMainLoopPostWork ( void );
60 extern void fgPlatformRotateWindow( SFG_Window *window, int rotation );
61 extern void fgPlatformFlushCommands ( void );
63 static struct touchscreen touchscreen;
65 #define ESCAPE_BUTTON_KEY 0x001B
67 unsigned int key_special(int qnxKeycode)
95 return GLUT_KEY_PAGE_UP;
97 return GLUT_KEY_PAGE_DOWN;
103 return GLUT_KEY_INSERT;
105 //case KEYCODE_KP_UP:
108 //case KEYCODE_KP_DOWN:
109 return GLUT_KEY_DOWN;
111 //case KEYCODE_KP_LEFT:
112 return GLUT_KEY_LEFT;
114 //case KEYCODE_KP_RIGHT:
115 return GLUT_KEY_RIGHT;
116 case KEYCODE_NUM_LOCK:
117 return GLUT_KEY_NUM_LOCK;
118 case KEYCODE_LEFT_ALT:
119 return GLUT_KEY_ALT_L;
120 case KEYCODE_RIGHT_ALT:
121 return GLUT_KEY_ALT_R;
122 case KEYCODE_LEFT_SHIFT:
123 return GLUT_KEY_SHIFT_L;
124 case KEYCODE_RIGHT_SHIFT:
125 return GLUT_KEY_SHIFT_R;
126 case KEYCODE_LEFT_CTRL:
127 return GLUT_KEY_CTRL_L;
128 case KEYCODE_RIGHT_CTRL:
129 return GLUT_KEY_CTRL_R;
134 unsigned char key_ascii(int qnxKeycode)
136 if (qnxKeycode >= KEYCODE_PC_KEYS && qnxKeycode <= UNICODE_PRIVATE_USE_AREA_LAST) {
137 switch (qnxKeycode) {
138 case KEYCODE_BACKSPACE:
142 case KEYCODE_KP_ENTER:
146 return ESCAPE_BUTTON_KEY;
153 fg_time_t fgPlatformSystemTime ( void )
155 #ifdef CLOCK_MONOTONIC
157 clock_gettime(CLOCK_MONOTONIC, &now);
158 return now.tv_nsec/1000000 + now.tv_sec*1000;
159 #elif defined(HAVE_GETTIMEOFDAY)
161 gettimeofday( &now, NULL );
162 return now.tv_usec/1000 + now.tv_sec*1000;
167 * Does the magic required to relinquish the CPU until something interesting
170 void fgPlatformSleepForEvents( fg_time_t msec )
172 if(fgStructure.CurrentWindow && fgDisplay.pDisplay.event == NULL &&
173 bps_get_event(&fgDisplay.pDisplay.event, (int)msec) != BPS_SUCCESS) {
174 LOGW("BPS couldn't get event");
178 void handle_left_mouse(int x, int y, int height, int eventType, SFG_Window* window)
180 bool handled = false;
181 /* Virtual arrows PAD */
182 /* Don't interfere with existing mouse move event */
183 if (!touchscreen.in_mmotion) {
184 struct vpad_state prev_vpad = touchscreen.vpad;
185 touchscreen.vpad.left = touchscreen.vpad.right = touchscreen.vpad.up = touchscreen.vpad.down = false;
187 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH || eventType == SCREEN_EVENT_MTOUCH_MOVE) {
188 if ((x > 0 && x < 100) && (y > (height - 100) && y < height))
190 touchscreen.vpad.left = true;
192 if ((x > 200 && x < 300) && (y > (height - 100) && y < height))
194 touchscreen.vpad.right = true;
196 if ((x > 100 && x < 200) && (y > (height - 100) && y < height))
198 touchscreen.vpad.down = true;
200 if ((x > 100 && x < 200) && (y > (height - 200) && y < (height - 100)))
202 touchscreen.vpad.up = true;
206 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH &&
207 (touchscreen.vpad.left || touchscreen.vpad.right || touchscreen.vpad.down || touchscreen.vpad.up)) {
208 touchscreen.vpad.on = true;
210 if (eventType == SCREEN_EVENT_MTOUCH_RELEASE) {
211 touchscreen.vpad.on = false;
214 if (prev_vpad.left != touchscreen.vpad.left
215 || prev_vpad.right != touchscreen.vpad.right
216 || prev_vpad.up != touchscreen.vpad.up
217 || prev_vpad.down != touchscreen.vpad.down
218 || prev_vpad.on != touchscreen.vpad.on) {
219 if (FETCH_WCB(*window, Special)) {
220 if (prev_vpad.left == false && touchscreen.vpad.left == true) {
221 INVOKE_WCB(*window, Special, (GLUT_KEY_LEFT, x, y));
223 else if (prev_vpad.right == false && touchscreen.vpad.right == true) {
224 INVOKE_WCB(*window, Special, (GLUT_KEY_RIGHT, x, y));
226 else if (prev_vpad.up == false && touchscreen.vpad.up == true) {
227 INVOKE_WCB(*window, Special, (GLUT_KEY_UP, x, y));
229 else if (prev_vpad.down == false && touchscreen.vpad.down == true) {
230 INVOKE_WCB(*window, Special, (GLUT_KEY_DOWN, x, y));
233 if (FETCH_WCB(*window, SpecialUp)) {
234 if (prev_vpad.left == true && touchscreen.vpad.left == false) {
235 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_LEFT, x, y));
237 if (prev_vpad.right == true && touchscreen.vpad.right == false) {
238 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_RIGHT, x, y));
240 if (prev_vpad.up == true && touchscreen.vpad.up == false) {
241 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_UP, x, y));
243 if (prev_vpad.down == true && touchscreen.vpad.down == false) {
244 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_DOWN, x, y));
251 /* Normal mouse events */
252 if (!handled && !touchscreen.vpad.on) {
253 window->State.MouseX = x;
254 window->State.MouseY = y;
256 if(eventType == SCREEN_EVENT_MTOUCH_MOVE) {
257 INVOKE_WCB(*window, Motion, (x, y));
258 } else if(FETCH_WCB(*window, Mouse)) {
259 touchscreen.in_mmotion = eventType == SCREEN_EVENT_MTOUCH_TOUCH;
260 int glutTouchType = eventType == SCREEN_EVENT_MTOUCH_TOUCH ? GLUT_DOWN : GLUT_UP;
261 INVOKE_WCB(*window, Mouse, (GLUT_LEFT_BUTTON, glutTouchType, x, y));
267 * Determine a GLUT modifier mask based on BlackBerry modifier info.
269 int fgPlatformGetModifiers (int mod)
271 return (((mod & KEYMOD_SHIFT) ? GLUT_ACTIVE_SHIFT : 0) |
272 ((mod & KEYMOD_CTRL) ? GLUT_ACTIVE_CTRL : 0) |
273 ((mod & KEYMOD_ALT) ? GLUT_ACTIVE_ALT : 0));
276 void fgPlatformHandleKeyboardHeight(SFG_Window* window, int height)
280 int nScreenHeight = -1;
282 screenHeight = glutGet(GLUT_WINDOW_HEIGHT); //Using this takes rotation into account
284 nScreenHeight = screenHeight;
286 else if(!screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_POSITION, size)) {
287 /* Calculate the new screen size */ //XXX Make sure to use display size instead of screen size
288 nScreenHeight = ((size[1] + screenHeight) - height) - size[1];
291 if(nScreenHeight != -1) {
292 /* If nScreenHeight is less then zero then window is covered. If nScreenHeight == height, then no change in size. Else, change in size */
294 int screenWidth = glutGet(GLUT_WINDOW_WIDTH);
295 if(nScreenHeight < 0) {
296 LOGI("fgPlatformHandleKeyboardHeight: Covered window state");
297 window->State.Visible = GL_FALSE;
298 window->State.pWState.windowCovered = GL_TRUE;
299 INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_COVERED));
300 fghOnReshapeNotify(window, screenWidth, 0, GL_FALSE);
302 if(window->State.pWState.windowCovered == GL_TRUE) {
303 LOGI("fgPlatformHandleKeyboardHeight: Resetting window state");
305 /* Reset window status if it was previously covered */
306 switch(window->State.pWState.windowState) {
307 case NAVIGATOR_WINDOW_FULLSCREEN:
308 window->State.Visible = GL_TRUE;
309 INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED));
311 case NAVIGATOR_WINDOW_THUMBNAIL:
312 window->State.Visible = GL_TRUE;
313 INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
315 case NAVIGATOR_WINDOW_INVISIBLE:
316 window->State.Visible = GL_FALSE;
317 INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN));
320 window->State.pWState.windowCovered = GL_FALSE;
322 fghOnReshapeNotify(window, screenWidth, nScreenHeight, GL_FALSE);
327 void fgPlatformProcessSingleEvent ( void )
329 if(fgStructure.CurrentWindow == NULL) {
330 //XXX Is this right? Would this just cause a whole lot of busy looping while we wait for events?
331 LOGW("fgPlatformProcessSingleEvent: Missing current window. Skipping event processing");
335 if(fgDisplay.pDisplay.event == NULL)
342 SFG_Window* window = fgStructure.CurrentWindow;
343 domain = bps_event_get_domain(fgDisplay.pDisplay.event);
344 if (domain == screen_get_domain()) {
347 screen_event_t screenEvent = screen_event_get_event(fgDisplay.pDisplay.event);
348 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_TYPE, &eventType);
351 //Mostly from fg_main_android
352 case SCREEN_EVENT_MTOUCH_TOUCH:
353 case SCREEN_EVENT_MTOUCH_RELEASE:
354 case SCREEN_EVENT_MTOUCH_MOVE:
356 mtouch_event_t touchEvent;
357 screen_get_mtouch_event(screenEvent, &touchEvent, 0);
358 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
360 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));
362 /* Remember the current modifiers state so user can query it from their callback */
363 fgState.Modifiers = fgPlatformGetModifiers(mod);
365 if(touchEvent.contact_id == 0) {
367 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
368 handle_left_mouse(touchEvent.x, touchEvent.y, size[1], eventType, window);
371 //Now handle mutlitouch (adapted from fg_main_windows)
372 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH) {
373 INVOKE_WCB( *window, MultiEntry, ( touchEvent.contact_id, GLUT_ENTERED ) );
374 INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_DOWN ) );
375 } else if (eventType == SCREEN_EVENT_MTOUCH_MOVE) {
376 INVOKE_WCB( *window, MultiMotion, ( touchEvent.contact_id, touchEvent.x, touchEvent.y ) );
377 //XXX No motion is performed without contact, thus MultiPassive is never used
378 } else if (eventType == SCREEN_EVENT_MTOUCH_RELEASE) {
379 INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_UP ) );
380 INVOKE_WCB( *window, MultiEntry, ( touchEvent.contact_id, GLUT_LEFT ) );
383 fgState.Modifiers = INVALID_MODIFIERS;
387 case SCREEN_EVENT_POINTER:
389 //Based off/part taken from GamePlay3d PlatformBlackBerry
390 static int mouse_pressed = 0;
394 // A move event will be fired unless a button state changed.
396 bool left_move = false;
397 // This is a mouse move event, it is applicable to a device with a usb mouse or simulator.
398 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_BUTTONS, &buttons);
399 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_SOURCE_POSITION, position);
400 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_MOUSE_WHEEL, &wheel);
401 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
403 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
405 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));
407 //XXX Is multitouch be handled in a good way?
409 /* Remember the current modifiers state so user can query it from their callback */
410 fgState.Modifiers = fgPlatformGetModifiers(mod);
412 // Handle left mouse. Interpret as touch if the left mouse event is not consumed.
413 if (buttons & SCREEN_LEFT_MOUSE_BUTTON) {
414 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_TOUCH, window);
421 } else if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
423 mouse_pressed &= ~SCREEN_LEFT_MOUSE_BUTTON;
424 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_RELEASE, window);
427 // Handle right mouse.
428 if (buttons & SCREEN_RIGHT_MOUSE_BUTTON) {
429 if ((mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) == 0) {
431 mouse_pressed |= SCREEN_RIGHT_MOUSE_BUTTON;
432 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_DOWN, position[0], position[1]));
434 } else if (mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) {
436 mouse_pressed &= ~SCREEN_RIGHT_MOUSE_BUTTON;
437 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_UP, position[0], position[1]));
440 // Handle middle mouse.
441 if (buttons & SCREEN_MIDDLE_MOUSE_BUTTON) {
442 if ((mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) == 0) {
444 mouse_pressed |= SCREEN_MIDDLE_MOUSE_BUTTON;
445 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_DOWN, position[0], position[1]));
447 } else if (mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) {
449 mouse_pressed &= ~SCREEN_MIDDLE_MOUSE_BUTTON;
450 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_UP, position[0], position[1]));
453 // Fire a move event if none of the buttons changed.
454 if (left_move || move) {
455 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_MOVE, window);
459 /* Very slightly modified from fg_main_mswin.
460 * Because we don't want MouseWheel to be called every. single. time.
461 * That the action occurs, we mimic the Windows version with "wheel deltas"
462 * XXX Do we even want this?
463 * XXX If we want this, it's possible to get horizontal scroll as well.
464 * XXX -Vertical scroll=wheel 0, horizontal=wheel 1? */
465 fgState.MouseWheelTicks -= wheel;
466 if (abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
468 int wheel_number = 0;
469 int direction = (fgState.MouseWheelTicks > 0) ? -1 : 1;
471 if (!FETCH_WCB(*window, MouseWheel) && !FETCH_WCB(*window, Mouse))
474 //XXX fgSetWindow(window);
476 while(abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
478 if (FETCH_WCB(*window, MouseWheel))
479 INVOKE_WCB(*window, MouseWheel, (wheel_number, direction, window->State.MouseX, window->State.MouseY));
480 else /* No mouse wheel, call the mouse button callback twice */
483 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
484 * " " one +1 to 5, -1 to 6, ...
486 * XXX The below assumes that you have no more than 3 mouse
487 * XXX buttons. Sorry.
489 int button = wheel_number * 2 + 3;
492 INVOKE_WCB(*window, Mouse, (button, GLUT_DOWN, window->State.MouseX, window->State.MouseY));
493 INVOKE_WCB(*window, Mouse, (button, GLUT_UP, window->State.MouseX, window->State.MouseY));
496 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
501 fgState.Modifiers = INVALID_MODIFIERS;
505 //Based off fg_main_android
506 case SCREEN_EVENT_KEYBOARD:
510 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_FLAGS, &flags);
511 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_SYM, &value);
512 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
514 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));
516 /* Suppress key repeats if desired. Based off fg_main_mswin */
517 if ((flags & KEY_REPEAT) == 0 || (fgState.KeyRepeat == GLUT_KEY_REPEAT_OFF && fgStructure.CurrentWindow->State.IgnoreKeyRepeat == GL_TRUE)) {
518 unsigned int keypress = 0;
519 unsigned char ascii = 0;
521 /* Remember the current modifiers state so user can query it from their callback */
522 fgState.Modifiers = fgPlatformGetModifiers(mod);
525 if ((keypress = key_special(value))) {
526 if(flags & KEY_DOWN) {
527 INVOKE_WCB(*window, Special, (keypress, window->State.MouseX, window->State.MouseY));
529 INVOKE_WCB(*window, SpecialUp, (keypress, window->State.MouseX, window->State.MouseY));
531 } else if((flags & KEY_SYM_VALID) && (ascii = key_ascii(value))) {
532 if(flags & KEY_DOWN) {
533 INVOKE_WCB(*window, Keyboard, (ascii, window->State.MouseX, window->State.MouseY));
535 INVOKE_WCB(*window, KeyboardUp, (ascii, window->State.MouseX, window->State.MouseY));
538 LOGW("fgPlatformProcessSingleEvent: SCREEN_EVENT_KEYBOARD. Unhandled key event");
541 fgState.Modifiers = INVALID_MODIFIERS;
546 case SCREEN_EVENT_PROPERTY:
547 case SCREEN_EVENT_IDLE:
551 LOGW("fgPlatformProcessSingleEvent: unknown screen event: 0x%X", SLOG2_FA_SIGNED(eventType));
554 } else if (domain == navigator_get_domain()) {
555 int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
558 case NAVIGATOR_WINDOW_STATE:
560 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE");
562 /* Covered only happens due to keyboard. When the app is minimized, the keyboard is closed.
563 When the keyboard is open, and the app is fullscreened, the keyboard is also closed.
564 If a window is covered and the app is minimized, the state will be set and the keyboard event
565 will adjust the screen size and change window status. */
566 navigator_window_state_t state = navigator_event_get_window_state(fgDisplay.pDisplay.event);
567 if(window->State.pWState.windowCovered == GL_FALSE)
571 case NAVIGATOR_WINDOW_FULLSCREEN:
572 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_FULLSCREEN");
573 window->State.Visible = GL_TRUE;
574 INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED));
576 case NAVIGATOR_WINDOW_THUMBNAIL:
577 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_THUMBNAIL");
578 window->State.Visible = GL_TRUE;
579 INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
581 case NAVIGATOR_WINDOW_INVISIBLE:
582 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_INVISIBLE");
583 window->State.Visible = GL_FALSE;
584 INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN));
587 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
591 window->State.pWState.windowState = state;
597 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_EXIT");
599 fgPlatformMainLoopPostWork();
601 /* User closed the application for good, let's kill the window */
602 SFG_Window* window = fgStructure.CurrentWindow;
603 if (window != NULL) {
604 fgDestroyWindow(window);
606 LOGW("NAVIGATOR_EXIT: No current window");
611 case NAVIGATOR_SWIPE_DOWN:
612 /* XXX Open app menu */
615 /* Orientation is a bunch of handshakes.
616 - First the app get's asked if it wants to rotate (NAVIGATOR_ORIENTATION_CHECK)
617 - If the app wants to rotate, then it will be told what size it will be after rotate (NAVIGATOR_ORIENTATION_SIZE).
618 - Once the OS confirms that it's ready to rotate, it tells the app to handle rotation (NAVIGATOR_ORIENTATION).
619 - Once rotation is complete, the OS tells the app it's done (NAVIGATOR_ORIENTATION_DONE) */
620 case NAVIGATOR_ORIENTATION_CHECK:
621 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_CHECK");
624 window->State.pWState.newWidth = 0;
625 window->State.pWState.newHeight = 0;
627 /* Notify that we want to rotate */
628 navigator_orientation_check_response(fgDisplay.pDisplay.event, true);
631 case NAVIGATOR_ORIENTATION:
632 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION");
634 /* NAVIGATOR_ORIENTATION occurs before NAVIGATOR_KEYBOARD_POSITION */
636 /* Rotate and resize the window */
637 fgPlatformRotateWindow(window, navigator_event_get_orientation_angle(fgDisplay.pDisplay.event));
638 fgPlatformFlushCommands();
639 fghOnReshapeNotify(window, window->State.pWState.newWidth, window->State.pWState.newHeight, GL_FALSE);
642 window->State.pWState.newWidth = 0;
643 window->State.pWState.newHeight = 0;
646 navigator_done_orientation(fgDisplay.pDisplay.event);
650 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_BACK");
651 INVOKE_WCB(*window, Keyboard, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
652 INVOKE_WCB(*window, KeyboardUp, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
655 case NAVIGATOR_WINDOW_ACTIVE:
656 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_ACTIVE");
657 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_RESUME));
660 case NAVIGATOR_WINDOW_INACTIVE:
661 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_INACTIVE");
662 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_PAUSE));
665 case NAVIGATOR_ORIENTATION_DONE:
666 case NAVIGATOR_ORIENTATION_RESULT:
667 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_DONE/NAVIGATOR_ORIENTATION_RESULT");
670 case NAVIGATOR_KEYBOARD_STATE:
672 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE");
674 navigator_keyboard_state_t state = navigator_event_get_keyboard_state(fgDisplay.pDisplay.event);
677 case NAVIGATOR_KEYBOARD_CLOSED:
678 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE-NAVIGATOR_KEYBOARD_CLOSED");
679 /* NAVIGATOR_KEYBOARD_POSITION only occurs on open, so on keyboard close we need to reset the keyboard height */
680 fgPlatformHandleKeyboardHeight(window, 0);
682 case NAVIGATOR_KEYBOARD_OPENING:
683 case NAVIGATOR_KEYBOARD_OPENED:
684 case NAVIGATOR_KEYBOARD_CLOSING:
686 case NAVIGATOR_KEYBOARD_UNRECOGNIZED:
687 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE-NAVIGATOR_KEYBOARD_UNRECOGNIZED");
690 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
696 case NAVIGATOR_KEYBOARD_POSITION:
698 /* Occurs only when keyboard has opened or resizes */
699 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_POSITION");
701 int keyboardOffset = navigator_event_get_keyboard_position(fgDisplay.pDisplay.event);
702 if(keyboardOffset == BPS_FAILURE) {
703 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_KEYBOARD_POSITION: getting keyboard offset failed");
705 /* keyboardOffset is the offset from the top of the screen to the top of the keyboard, AKA the size of the uncovered screen
706 We want the height of the keyboard. So instead of determining the orientation, getting the right display size, and subtracting;
707 we just get the keyboard height which may be slower but easier to understand and work with */
708 virtualkeyboard_get_height(&keyboardOffset);
709 fgPlatformHandleKeyboardHeight(window, keyboardOffset);
714 case NAVIGATOR_DEVICE_LOCK_STATE:
717 case NAVIGATOR_WINDOW_COVER:
718 case NAVIGATOR_WINDOW_COVER_ENTER:
719 case NAVIGATOR_WINDOW_COVER_EXIT:
720 /* BlackBerry specific. Let app status and window status take care of everything */
723 case NAVIGATOR_APP_STATE:
724 /* Can do the same as NAVIGATOR_WINDOW_ACTIVE/NAVIGATOR_WINDOW_INACTIVE but
725 seems like it doesn't work when the app comes to the foreground. Might be a bug */
728 case NAVIGATOR_ORIENTATION_SIZE:
729 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_SIZE");
731 /* Get new window size */
732 window->State.pWState.newWidth = navigator_event_get_orientation_size_width(fgDisplay.pDisplay.event);
733 window->State.pWState.newHeight = navigator_event_get_orientation_size_height(fgDisplay.pDisplay.event);
736 case 0: //Doesn't exist in header, but shows up when keyboard shows and resizes
740 LOGW("fgPlatformProcessSingleEvent: unknown navigator event: 0x%X", SLOG2_FA_SIGNED(eventType));
744 } while(bps_get_event(&fgDisplay.pDisplay.event, 1) == BPS_SUCCESS && fgDisplay.pDisplay.event != NULL);
746 /* Reset event to reduce chances of triggering something */
747 fgDisplay.pDisplay.event = NULL;
750 void fgPlatformMainLoopPreliminaryWork ( void )
752 LOGI("fgPlatformMainLoopPreliminaryWork");
754 /* Request navigator events */
755 navigator_request_events(0);
758 navigator_rotation_lock(false);
760 /* Request window events */
761 screen_request_events(fgDisplay.pDisplay.screenContext);
764 void fgPlatformMainLoopPostWork ( void )
766 LOGI("fgPlatformMainLoopPostWork");
768 /* Stop all events */
769 screen_stop_events(fgDisplay.pDisplay.screenContext);
771 navigator_stop_events(0);
774 /* deal with work list items */
775 void fgPlatformInitWork(SFG_Window* window)
777 LOGI("fgPlatformInitWork");
779 /* Position callback, always at 0,0 */
780 fghOnPositionNotify(window, 0, 0, GL_TRUE);
782 /* Get window size */
784 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
785 fghOnReshapeNotify(window, size[0], size[1], GL_FALSE);
787 /* Size gets notified on window creation with size detection in mainloop above
788 * XXX CHECK: does this messages happen too early like on windows,
789 * so client code cannot have registered a callback yet and the message
790 * is thus never received by client?
794 void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask)
796 if (workMask & GLUT_FULL_SCREEN_WORK)
797 fgPlatformFullScreenToggle( window );
798 if (workMask & GLUT_POSITION_WORK)
799 fgPlatformPositionWindow( window, window->State.DesiredXpos, window->State.DesiredYpos );
800 if (workMask & GLUT_SIZE_WORK)
801 fgPlatformReshapeWindow ( window, window->State.DesiredWidth, window->State.DesiredHeight );
802 if (workMask & GLUT_ZORDER_WORK)
804 if (window->State.DesiredZOrder < 0)
805 fgPlatformPushWindow( window );
807 fgPlatformPopWindow( window );
811 void fgPlatformVisibilityWork(SFG_Window* window)
813 /* Visibility status of window should get updated in the window message handlers
814 * For now, none of these functions called below do anything, so don't worry
817 SFG_Window *win = window;
818 switch (window->State.DesiredVisibility)
820 case DesireHiddenState:
821 fgPlatformHideWindow( window );
823 case DesireIconicState:
824 /* Call on top-level window */
827 fgPlatformIconifyWindow( win );
829 case DesireNormalState:
830 fgPlatformShowWindow( window );