#include "fg_internal.h"
#include "egl/fg_window_egl.h"
+#ifdef NDEBUG
+#define LOGI(...)
+#endif
+
+#ifdef __PLAYBOOK__
+#include <sys/slog.h>
+#ifndef LOGI
+#define LOGI(...) ((void)slogf(1337, _SLOG_INFO, __VA_ARGS__))
+#endif
+#define LOGW(...) ((void)slogf(1337, _SLOG_WARNING, __VA_ARGS__))
+#ifndef SLOG2_FA_SIGNED
+#define SLOG2_FA_SIGNED(x) (x)
+#endif
+#else
#include <slog2.h>
+#ifndef LOGI
#define LOGI(...) ((void)slog2fa(NULL, 1337, SLOG2_INFO, __VA_ARGS__, SLOG2_FA_END))
+#endif
#define LOGW(...) ((void)slog2fa(NULL, 1337, SLOG2_WARNING, __VA_ARGS__, SLOG2_FA_END))
+#endif
#include <sys/keycodes.h>
#include <input/screen_helpers.h>
#include <bps/bps.h>
#include <bps/event.h>
#include <bps/screen.h>
#include <bps/navigator.h>
+#include <bps/virtualkeyboard.h>
extern void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify);
extern void fghOnPositionNotify(SFG_Window *window, int x, int y, GLboolean forceNotify);
extern void fgPlatformShowWindow( SFG_Window *window );
extern void fgPlatformMainLoopPostWork ( void );
extern void fgPlatformRotateWindow( SFG_Window *window, int rotation );
+extern void fgPlatformFlushCommands ( void );
static struct touchscreen touchscreen;
+#define ESCAPE_BUTTON_KEY 0x001B
+
unsigned int key_special(int qnxKeycode)
{
switch(qnxKeycode) {
case KEYCODE_RETURN:
return 0x000A;
case KEYCODE_ESCAPE:
- return 0x001B;
+ return ESCAPE_BUTTON_KEY;
}
}
return qnxKeycode;
*/
void fgPlatformSleepForEvents( fg_time_t msec )
{
- //XXX: Is this right? Is there a more direct way to access the context?
- if(fgStructure.CurrentWindow && fgDisplay.pDisplay.event == NULL && bps_get_event(&fgDisplay.pDisplay.event, (int)msec) != BPS_SUCCESS) {
+ if(fgStructure.CurrentWindow && fgDisplay.pDisplay.event == NULL &&
+ bps_get_event(&fgDisplay.pDisplay.event, (int)msec) != BPS_SUCCESS) {
LOGW("BPS couldn't get event");
}
}
((mod & KEYMOD_ALT) ? GLUT_ACTIVE_ALT : 0));
}
+void fgPlatformHandleKeyboardHeight(SFG_Window* window, int height)
+{
+ int size[2];
+ int screenHeight;
+ int nScreenHeight = -1;
+
+ screenHeight = glutGet(GLUT_WINDOW_HEIGHT); //Using this takes rotation into account
+ if(height == 0) {
+ nScreenHeight = screenHeight;
+ }
+ else if(!screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_POSITION, size)) {
+ /* Calculate the new screen size */ //XXX Make sure to use display size instead of screen size
+ nScreenHeight = ((size[1] + screenHeight) - height) - size[1];
+ }
+
+ if(nScreenHeight != -1) {
+ /* If nScreenHeight is less then zero then window is covered. If nScreenHeight == height, then no change in size. Else, change in size */
+
+ int screenWidth = glutGet(GLUT_WINDOW_WIDTH);
+ if(nScreenHeight < 0) {
+ LOGI("fgPlatformHandleKeyboardHeight: Covered window state");
+ window->State.Visible = GL_FALSE;
+ window->State.pWState.windowCovered = GL_TRUE;
+ INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_COVERED));
+ fghOnReshapeNotify(window, screenWidth, 0, GL_FALSE);
+ } else {
+ if(window->State.pWState.windowCovered == GL_TRUE) {
+ LOGI("fgPlatformHandleKeyboardHeight: Resetting window state");
+
+ /* Reset window status if it was previously covered */
+ switch(window->State.pWState.windowState) {
+ case NAVIGATOR_WINDOW_FULLSCREEN:
+ window->State.Visible = GL_TRUE;
+ INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED));
+ break;
+ case NAVIGATOR_WINDOW_THUMBNAIL:
+ window->State.Visible = GL_TRUE;
+ INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
+ break;
+ case NAVIGATOR_WINDOW_INVISIBLE:
+ window->State.Visible = GL_FALSE;
+ INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN));
+ break;
+ }
+ window->State.pWState.windowCovered = GL_FALSE;
+ }
+ fghOnReshapeNotify(window, screenWidth, nScreenHeight, GL_FALSE);
+ }
+ }
+}
+
void fgPlatformProcessSingleEvent ( void )
{
if(fgStructure.CurrentWindow == NULL) {
do
{
SFG_Window* window = fgStructure.CurrentWindow;
+ /* Get the keyboard height before doing anything since we otherwise don't get it until it changes */
+ if(window->State.pWState.keyboardHeight == 0) {
+ virtualkeyboard_get_height(&window->State.pWState.keyboardHeight);
+ }
domain = bps_event_get_domain(fgDisplay.pDisplay.event);
if (domain == screen_get_domain()) {
int eventType;
{
mtouch_event_t touchEvent;
screen_get_mtouch_event(screenEvent, &touchEvent, 0);
+#ifndef __PLAYBOOK__
screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
+#else
+ mod = 0;
+#endif
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));
// This is a mouse move event, it is applicable to a device with a usb mouse or simulator.
screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_BUTTONS, &buttons);
screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_SOURCE_POSITION, position);
+#ifndef __PLAYBOOK__
screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_MOUSE_WHEEL, &wheel);
screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
+#else
+ wheel = mod = 0;
+#endif
int size[2];
screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
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));
- //XXX Should multitouch be handled?
+ //XXX Is multitouch be handled in a good way?
/* Remember the current modifiers state so user can query it from their callback */
fgState.Modifiers = fgPlatformGetModifiers(mod);
break;
}
} else if (domain == navigator_get_domain()) {
- int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
+ unsigned int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
switch (eventType) {
case NAVIGATOR_WINDOW_STATE:
{
LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE");
+
+ /* Covered only happens due to keyboard. When the app is minimized, the keyboard is closed.
+ When the keyboard is open, and the app is fullscreened, the keyboard is also closed.
+ If a window is covered and the app is minimized, the state will be set and the keyboard event
+ will adjust the screen size and change window status. */
navigator_window_state_t state = navigator_event_get_window_state(fgDisplay.pDisplay.event);
- switch (state)
+ if(window->State.pWState.windowCovered == GL_FALSE)
{
- case NAVIGATOR_WINDOW_FULLSCREEN:
- LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_FULLSCREEN");
- window->State.Visible = GL_TRUE;
- INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED));
- break;
- case NAVIGATOR_WINDOW_THUMBNAIL:
- LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_THUMBNAIL");
- window->State.Visible = GL_TRUE;
- INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
- break;
- case NAVIGATOR_WINDOW_INVISIBLE:
- LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_INVISIBLE");
- window->State.Visible = GL_FALSE;
- INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN)); //XXX Should this be GLUT_FULLY_COVERED?
- break;
- default:
- LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
- break;
+ switch (state)
+ {
+ case NAVIGATOR_WINDOW_FULLSCREEN:
+ LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_FULLSCREEN");
+ window->State.Visible = GL_TRUE;
+ INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED));
+ break;
+ case NAVIGATOR_WINDOW_THUMBNAIL:
+ LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_THUMBNAIL");
+ window->State.Visible = GL_TRUE;
+ INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
+ break;
+ case NAVIGATOR_WINDOW_INVISIBLE:
+ LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_INVISIBLE");
+ window->State.Visible = GL_FALSE;
+ INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN));
+ break;
+ default:
+ LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
+ break;
+ }
}
+ window->State.pWState.windowState = state;
break;
}
} else {
LOGW("NAVIGATOR_EXIT: No current window");
}
+
+ //XXX Should this be a bit more "forceful" so that it doesn't continue to loop through events?
break;
}
window->State.pWState.newWidth = 0;
window->State.pWState.newHeight = 0;
+#ifdef __PLAYBOOK__
+ /* On rotation, the keyboard is closed. This prevents two resize calls */
+ window->State.pWState.keyboardOpen = GL_FALSE;
+#endif
+
/* Notify that we want to rotate */
navigator_orientation_check_response(fgDisplay.pDisplay.event, true);
break;
case NAVIGATOR_ORIENTATION:
LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION");
+ /* NAVIGATOR_ORIENTATION occurs before NAVIGATOR_KEYBOARD_POSITION */
+
/* Rotate and resize the window */
fgPlatformRotateWindow(window, navigator_event_get_orientation_angle(fgDisplay.pDisplay.event));
+ fgPlatformFlushCommands();
+#ifdef __PLAYBOOK__
+ /* PlayBook doesn't indicate what the new size will be, so we need to retrieve it from the window itself */
+ window->State.pWState.newWidth = glutGet(GLUT_WINDOW_WIDTH);
+ window->State.pWState.newHeight = glutGet(GLUT_WINDOW_HEIGHT);
fghOnReshapeNotify(window, window->State.pWState.newWidth, window->State.pWState.newHeight, GL_FALSE);
+#else
+ if(window->State.pWState.keyboardOpen == GL_FALSE) {
+ /* On rotation, if the keyboard is open, it will get the keyboard resize events anyway. Otherwise, handle the resize. */
+ fghOnReshapeNotify(window, window->State.pWState.newWidth, window->State.pWState.newHeight, GL_FALSE);
+ }
+#endif
/* Reset sizes */
window->State.pWState.newWidth = 0;
break;
case NAVIGATOR_BACK:
- /* XXX Should this be a Special/SpecialUp event? */
+ LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_BACK");
+ INVOKE_WCB(*window, Keyboard, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
+ INVOKE_WCB(*window, KeyboardUp, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
break;
case NAVIGATOR_WINDOW_ACTIVE:
case NAVIGATOR_ORIENTATION_DONE:
case NAVIGATOR_ORIENTATION_RESULT:
- LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_DONE\NAVIGATOR_ORIENTATION_RESULT");
+ LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_DONE/NAVIGATOR_ORIENTATION_RESULT");
break;
+#ifndef __PLAYBOOK__
case NAVIGATOR_KEYBOARD_STATE:
- /* XXX Should something be done with this? */
- break;
-
case NAVIGATOR_KEYBOARD_POSITION:
- /* TODO Invoke resize with the modified screen size (((y + height) - keyboardPos) - y).
- * If result is less then zero then window is covered. If == height, then no change in size. Else, change in size */
+ /* See virtual keyboard handling for info on why this is not used. */
break;
case NAVIGATOR_DEVICE_LOCK_STATE:
case NAVIGATOR_APP_STATE:
/* Can do the same as NAVIGATOR_WINDOW_ACTIVE/NAVIGATOR_WINDOW_INACTIVE but
- seems less likely to work when the app comes to the foreground. Might be a bug */
+ seems like it doesn't work when the app comes to the foreground. Might be a bug */
break;
case NAVIGATOR_ORIENTATION_SIZE:
window->State.pWState.newWidth = navigator_event_get_orientation_size_width(fgDisplay.pDisplay.event);
window->State.pWState.newHeight = navigator_event_get_orientation_size_height(fgDisplay.pDisplay.event);
break;
+#endif
case 0: //Doesn't exist in header, but shows up when keyboard shows and resizes
+ case NAVIGATOR_OTHER:
break;
default:
break;
}
}
+ /*
+ * BlackBerry 10 navigator provides keyboard events, but they conflict with how we handle keyboard events.
+ * Causing multiple reshape messages and can leave window state incorrectly setup.
+ */
+ else if(domain == virtualkeyboard_get_domain()) {
+ unsigned int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
+ switch (eventType) {
+ case VIRTUALKEYBOARD_EVENT_VISIBLE:
+ LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_VISIBLE");
+ if(window->State.pWState.keyboardOpen != GL_TRUE) {
+ window->State.pWState.keyboardOpen = GL_TRUE;
+ fgPlatformHandleKeyboardHeight(window, window->State.pWState.keyboardHeight);
+ }
+ break;
+
+ case VIRTUALKEYBOARD_EVENT_HIDDEN:
+ LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_HIDDEN");
+ if(window->State.pWState.keyboardOpen != GL_FALSE) {
+ window->State.pWState.keyboardOpen = GL_FALSE;
+ fgPlatformHandleKeyboardHeight(window, 0);
+ }
+ break;
+
+ case VIRTUALKEYBOARD_EVENT_INFO:
+ LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_INFO");
+ window->State.pWState.keyboardHeight = virtualkeyboard_event_get_height(fgDisplay.pDisplay.event);
+ if(window->State.pWState.keyboardOpen == GL_TRUE) {
+ fgPlatformHandleKeyboardHeight(window, window->State.pWState.keyboardHeight);
+ }
+ break;
+
+ default:
+ LOGW("fgPlatformProcessSingleEvent: unknown virtualkeyboard event: 0x%X", eventType);
+ break;
+ }
+ }
} while(bps_get_event(&fgDisplay.pDisplay.event, 1) == BPS_SUCCESS && fgDisplay.pDisplay.event != NULL);
/* Reset event to reduce chances of triggering something */
LOGI("fgPlatformMainLoopPreliminaryWork");
/* Request navigator events */
- navigator_request_events(0);
+ navigator_request_events(NAVIGATOR_EXTENDED_DATA);
/* Allow rotation */
navigator_rotation_lock(false);
+ /* Request keyboard events */
+ virtualkeyboard_request_events(0);
+
/* Request window events */
screen_request_events(fgDisplay.pDisplay.screenContext);
}
/* Stop all events */
screen_stop_events(fgDisplay.pDisplay.screenContext);
+#ifndef __PLAYBOOK__
navigator_stop_events(0);
+#endif
}
/* deal with work list items */