1 /*
2 * fg_main_blackberry.c
3 *
4 * The BlackBerry-specific windows message processing methods.
5 *
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
11 *
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:
18 *
19 * The above copyright notice and this permission notice shall be included
20 * in all copies or substantial portions of the Software.
21 *
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.
28 */
29
30 #include <GL/freeglut.h>
31 #include "fg_internal.h"
32 #include "egl/fg_window_egl.h"
33
34 #ifdef NDEBUG
35 #define LOGI(...)
36 #endif
37
38 #ifdef __PLAYBOOK__
39 #include <sys/slog.h>
40 #ifndef LOGI
41 #define LOGI(...) ((void)slogf(1337, _SLOG_INFO, __VA_ARGS__))
42 #endif
43 #define LOGW(...) ((void)slogf(1337, _SLOG_WARNING, __VA_ARGS__))
44 #ifndef SLOG2_FA_SIGNED
45 #define SLOG2_FA_SIGNED(x) (x)
46 #endif
47 #else
48 #include <slog2.h>
49 #ifndef LOGI
50 #define LOGI(...) ((void)slog2fa(NULL, 1337, SLOG2_INFO, __VA_ARGS__, SLOG2_FA_END))
51 #endif
52 #define LOGW(...) ((void)slog2fa(NULL, 1337, SLOG2_WARNING, __VA_ARGS__, SLOG2_FA_END))
53 #endif
54 #include <sys/keycodes.h>
55 #include <input/screen_helpers.h>
56 #include <bps/bps.h>
57 #include <bps/event.h>
58 #include <bps/screen.h>
59 #include <bps/navigator.h>
60 #include <bps/virtualkeyboard.h>
61
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 );
75
76 static struct touchscreen touchscreen;
77
78 #define ESCAPE_BUTTON_KEY 0x001B
79
key_special(int qnxKeycode)80 unsigned int key_special(int qnxKeycode)
81 {
82 switch(qnxKeycode) {
83 case KEYCODE_F1:
84 return GLUT_KEY_F1;
85 case KEYCODE_F2:
86 return GLUT_KEY_F2;
87 case KEYCODE_F3:
88 return GLUT_KEY_F3;
89 case KEYCODE_F4:
90 return GLUT_KEY_F4;
91 case KEYCODE_F5:
92 return GLUT_KEY_F5;
93 case KEYCODE_F6:
94 return GLUT_KEY_F6;
95 case KEYCODE_F7:
96 return GLUT_KEY_F7;
97 case KEYCODE_F8:
98 return GLUT_KEY_F8;
99 case KEYCODE_F9:
100 return GLUT_KEY_F9;
101 case KEYCODE_F10:
102 return GLUT_KEY_F10;
103 case KEYCODE_F11:
104 return GLUT_KEY_F11;
105 case KEYCODE_F12:
106 return GLUT_KEY_F12;
107 case KEYCODE_PG_UP:
108 return GLUT_KEY_PAGE_UP;
109 case KEYCODE_PG_DOWN:
110 return GLUT_KEY_PAGE_DOWN;
111 case KEYCODE_HOME:
112 return GLUT_KEY_HOME;
113 case KEYCODE_END:
114 return GLUT_KEY_END;
115 case KEYCODE_INSERT:
116 return GLUT_KEY_INSERT;
117 case KEYCODE_UP:
118 //case KEYCODE_KP_UP:
119 return GLUT_KEY_UP;
120 case KEYCODE_DOWN:
121 //case KEYCODE_KP_DOWN:
122 return GLUT_KEY_DOWN;
123 case KEYCODE_LEFT:
124 //case KEYCODE_KP_LEFT:
125 return GLUT_KEY_LEFT;
126 case KEYCODE_RIGHT:
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;
143 }
144 return 0;
145 }
146
key_ascii(int qnxKeycode)147 unsigned char key_ascii(int qnxKeycode)
148 {
149 if (qnxKeycode >= KEYCODE_PC_KEYS && qnxKeycode <= UNICODE_PRIVATE_USE_AREA_LAST) {
150 switch (qnxKeycode) {
151 case KEYCODE_BACKSPACE:
152 return 0x0008;
153 case KEYCODE_TAB:
154 return 0x0009;
155 case KEYCODE_KP_ENTER:
156 case KEYCODE_RETURN:
157 return 0x000A;
158 case KEYCODE_ESCAPE:
159 return ESCAPE_BUTTON_KEY;
160 }
161 }
162 return qnxKeycode;
163 }
164
165 //From fg_main_x11
fgPlatformSystemTime(void)166 fg_time_t fgPlatformSystemTime ( void )
167 {
168 #ifdef CLOCK_MONOTONIC
169 struct timespec now;
170 clock_gettime(CLOCK_MONOTONIC, &now);
171 return now.tv_nsec/1000000 + now.tv_sec*1000;
172 #elif defined(HAVE_GETTIMEOFDAY)
173 struct timeval now;
174 gettimeofday( &now, NULL );
175 return now.tv_usec/1000 + now.tv_sec*1000;
176 #endif
177 }
178
179 /*
180 * Does the magic required to relinquish the CPU until something interesting
181 * happens.
182 */
fgPlatformSleepForEvents(fg_time_t msec)183 void fgPlatformSleepForEvents( fg_time_t msec )
184 {
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");
188 }
189 }
190
handle_left_mouse(int x,int y,int height,int eventType,SFG_Window * window)191 void handle_left_mouse(int x, int y, int height, int eventType, SFG_Window* window)
192 {
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;
199
200 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH || eventType == SCREEN_EVENT_MTOUCH_MOVE) {
201 if ((x > 0 && x < 100) && (y > (height - 100) && y < height))
202 {
203 touchscreen.vpad.left = true;
204 }
205 if ((x > 200 && x < 300) && (y > (height - 100) && y < height))
206 {
207 touchscreen.vpad.right = true;
208 }
209 if ((x > 100 && x < 200) && (y > (height - 100) && y < height))
210 {
211 touchscreen.vpad.down = true;
212 }
213 if ((x > 100 && x < 200) && (y > (height - 200) && y < (height - 100)))
214 {
215 touchscreen.vpad.up = true;
216 }
217 }
218
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;
222 }
223 if (eventType == SCREEN_EVENT_MTOUCH_RELEASE) {
224 touchscreen.vpad.on = false;
225 }
226
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));
235 }
236 else if (prev_vpad.right == false && touchscreen.vpad.right == true) {
237 INVOKE_WCB(*window, Special, (GLUT_KEY_RIGHT, x, y));
238 }
239 else if (prev_vpad.up == false && touchscreen.vpad.up == true) {
240 INVOKE_WCB(*window, Special, (GLUT_KEY_UP, x, y));
241 }
242 else if (prev_vpad.down == false && touchscreen.vpad.down == true) {
243 INVOKE_WCB(*window, Special, (GLUT_KEY_DOWN, x, y));
244 }
245 }
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));
249 }
250 if (prev_vpad.right == true && touchscreen.vpad.right == false) {
251 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_RIGHT, x, y));
252 }
253 if (prev_vpad.up == true && touchscreen.vpad.up == false) {
254 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_UP, x, y));
255 }
256 if (prev_vpad.down == true && touchscreen.vpad.down == false) {
257 INVOKE_WCB(*window, SpecialUp, (GLUT_KEY_DOWN, x, y));
258 }
259 }
260 handled = true;
261 }
262 }
263
264 /* Normal mouse events */
265 if (!handled && !touchscreen.vpad.on) {
266 window->State.MouseX = x;
267 window->State.MouseY = y;
268
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));
275 }
276 }
277 }
278
279 /*
280 * Determine a GLUT modifier mask based on BlackBerry modifier info.
281 */
fgPlatformGetModifiers(int mod)282 int fgPlatformGetModifiers (int mod)
283 {
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));
287 }
288
fgPlatformHandleKeyboardHeight(SFG_Window * window,int height)289 void fgPlatformHandleKeyboardHeight(SFG_Window* window, int height)
290 {
291 int size[2];
292 int screenHeight;
293 int nScreenHeight = -1;
294
295 screenHeight = glutGet(GLUT_WINDOW_HEIGHT); //Using this takes rotation into account
296 if(height == 0) {
297 nScreenHeight = screenHeight;
298 }
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];
302 }
303
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 */
306
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);
314 } else {
315 if(window->State.pWState.windowCovered == GL_TRUE) {
316 LOGI("fgPlatformHandleKeyboardHeight: Resetting window state");
317
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));
323 break;
324 case NAVIGATOR_WINDOW_THUMBNAIL:
325 window->State.Visible = GL_TRUE;
326 INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
327 break;
328 case NAVIGATOR_WINDOW_INVISIBLE:
329 window->State.Visible = GL_FALSE;
330 INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN));
331 break;
332 }
333 window->State.pWState.windowCovered = GL_FALSE;
334 }
335 fghOnReshapeNotify(window, screenWidth, nScreenHeight, GL_FALSE);
336 }
337 }
338 }
339
fgPlatformProcessSingleEvent(void)340 void fgPlatformProcessSingleEvent ( void )
341 {
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");
345 return;
346 }
347
348 if(fgDisplay.pDisplay.event == NULL)
349 /* Nothing to do */
350 return;
351
352 int domain;
353 do
354 {
355 SFG_Window* window = fgStructure.CurrentWindow;
356 /* Get the keyboard height before doing anything since we otherwise don't get it until it changes */
357 if(window->State.pWState.keyboardHeight == 0) {
358 virtualkeyboard_get_height(&window->State.pWState.keyboardHeight);
359 }
360 domain = bps_event_get_domain(fgDisplay.pDisplay.event);
361 if (domain == screen_get_domain()) {
362 int eventType;
363 int mod;
364 screen_event_t screenEvent = screen_event_get_event(fgDisplay.pDisplay.event);
365 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_TYPE, &eventType);
366 switch (eventType) {
367
368 //Mostly from fg_main_android
369 case SCREEN_EVENT_MTOUCH_TOUCH:
370 case SCREEN_EVENT_MTOUCH_RELEASE:
371 case SCREEN_EVENT_MTOUCH_MOVE:
372 {
373 mtouch_event_t touchEvent;
374 screen_get_mtouch_event(screenEvent, &touchEvent, 0);
375 #ifndef __PLAYBOOK__
376 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
377 #else
378 mod = 0;
379 #endif
380
381 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));
382
383 /* Remember the current modifiers state so user can query it from their callback */
384 fgState.Modifiers = fgPlatformGetModifiers(mod);
385
386 if(touchEvent.contact_id == 0) {
387 int size[2];
388 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
389 handle_left_mouse(touchEvent.x, touchEvent.y, size[1], eventType, window);
390 }
391
392 //Now handle mutlitouch (adapted from fg_main_windows)
393 if (eventType == SCREEN_EVENT_MTOUCH_TOUCH) {
394 INVOKE_WCB( *window, MultiEntry, ( touchEvent.contact_id, GLUT_ENTERED ) );
395 INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_DOWN ) );
396 } else if (eventType == SCREEN_EVENT_MTOUCH_MOVE) {
397 INVOKE_WCB( *window, MultiMotion, ( touchEvent.contact_id, touchEvent.x, touchEvent.y ) );
398 //XXX No motion is performed without contact, thus MultiPassive is never used
399 } else if (eventType == SCREEN_EVENT_MTOUCH_RELEASE) {
400 INVOKE_WCB( *window, MultiButton, ( touchEvent.contact_id, touchEvent.x, touchEvent.y, 0, GLUT_UP ) );
401 INVOKE_WCB( *window, MultiEntry, ( touchEvent.contact_id, GLUT_LEFT ) );
402 }
403
404 fgState.Modifiers = INVALID_MODIFIERS;
405 break;
406 }
407
408 case SCREEN_EVENT_POINTER:
409 {
410 //Based off/part taken from GamePlay3d PlatformBlackBerry
411 static int mouse_pressed = 0;
412 int buttons;
413 int position[2];
414 int wheel;
415 // A move event will be fired unless a button state changed.
416 bool move = true;
417 bool left_move = false;
418 // This is a mouse move event, it is applicable to a device with a usb mouse or simulator.
419 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_BUTTONS, &buttons);
420 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_SOURCE_POSITION, position);
421 #ifndef __PLAYBOOK__
422 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_MOUSE_WHEEL, &wheel);
423 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
424 #else
425 wheel = mod = 0;
426 #endif
427 int size[2];
428 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
429
430 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));
431
432 //XXX Is multitouch be handled in a good way?
433
434 /* Remember the current modifiers state so user can query it from their callback */
435 fgState.Modifiers = fgPlatformGetModifiers(mod);
436
437 // Handle left mouse. Interpret as touch if the left mouse event is not consumed.
438 if (buttons & SCREEN_LEFT_MOUSE_BUTTON) {
439 if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
440 left_move = true;
441 } else {
442 move = false;
443 mouse_pressed |= SCREEN_LEFT_MOUSE_BUTTON;
444 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_TOUCH, window);
445 }
446 } else if (mouse_pressed & SCREEN_LEFT_MOUSE_BUTTON) {
447 move = false;
448 mouse_pressed &= ~SCREEN_LEFT_MOUSE_BUTTON;
449 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_RELEASE, window);
450 }
451
452 // Handle right mouse.
453 if (buttons & SCREEN_RIGHT_MOUSE_BUTTON) {
454 if ((mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) == 0) {
455 move = false;
456 mouse_pressed |= SCREEN_RIGHT_MOUSE_BUTTON;
457 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_DOWN, position[0], position[1]));
458 }
459 } else if (mouse_pressed & SCREEN_RIGHT_MOUSE_BUTTON) {
460 move = false;
461 mouse_pressed &= ~SCREEN_RIGHT_MOUSE_BUTTON;
462 INVOKE_WCB(*window, Mouse, (GLUT_RIGHT_BUTTON, GLUT_UP, position[0], position[1]));
463 }
464
465 // Handle middle mouse.
466 if (buttons & SCREEN_MIDDLE_MOUSE_BUTTON) {
467 if ((mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) == 0) {
468 move = false;
469 mouse_pressed |= SCREEN_MIDDLE_MOUSE_BUTTON;
470 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_DOWN, position[0], position[1]));
471 }
472 } else if (mouse_pressed & SCREEN_MIDDLE_MOUSE_BUTTON) {
473 move = false;
474 mouse_pressed &= ~SCREEN_MIDDLE_MOUSE_BUTTON;
475 INVOKE_WCB(*window, Mouse, (GLUT_MIDDLE_BUTTON, GLUT_UP, position[0], position[1]));
476 }
477
478 // Fire a move event if none of the buttons changed.
479 if (left_move || move) {
480 handle_left_mouse(position[0], position[1], size[1], SCREEN_EVENT_MTOUCH_MOVE, window);
481 }
482
483 if (wheel) {
484 /* Very slightly modified from fg_main_mswin.
485 * Because we don't want MouseWheel to be called every. single. time.
486 * That the action occurs, we mimic the Windows version with "wheel deltas"
487 * XXX Do we even want this?
488 * XXX If we want this, it's possible to get horizontal scroll as well.
489 * XXX -Vertical scroll=wheel 0, horizontal=wheel 1? */
490 fgState.MouseWheelTicks -= wheel;
491 if (abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
492 {
493 int wheel_number = 0;
494 int direction = (fgState.MouseWheelTicks > 0) ? -1 : 1;
495
496 if (!FETCH_WCB(*window, MouseWheel) && !FETCH_WCB(*window, Mouse))
497 break;
498
499 //XXX fgSetWindow(window);
500
501 while(abs(fgState.MouseWheelTicks) >= WHEEL_DELTA)
502 {
503 if (FETCH_WCB(*window, MouseWheel))
504 INVOKE_WCB(*window, MouseWheel, (wheel_number, direction, window->State.MouseX, window->State.MouseY));
505 else /* No mouse wheel, call the mouse button callback twice */
506 {
507 /*
508 * Map wheel zero to button 3 and 4; +1 to 3, -1 to 4
509 * " " one +1 to 5, -1 to 6, ...
510 *
511 * XXX The below assumes that you have no more than 3 mouse
512 * XXX buttons. Sorry.
513 */
514 int button = wheel_number * 2 + 3;
515 if (direction < 0)
516 ++button;
517 INVOKE_WCB(*window, Mouse, (button, GLUT_DOWN, window->State.MouseX, window->State.MouseY));
518 INVOKE_WCB(*window, Mouse, (button, GLUT_UP, window->State.MouseX, window->State.MouseY));
519 }
520
521 fgState.MouseWheelTicks -= WHEEL_DELTA * direction;
522 }
523 }
524 }
525
526 fgState.Modifiers = INVALID_MODIFIERS;
527 break;
528 }
529
530 //Based off fg_main_android
531 case SCREEN_EVENT_KEYBOARD:
532 {
533 int flags;
534 int value;
535 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_FLAGS, &flags);
536 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_SYM, &value);
537 screen_get_event_property_iv(screenEvent, SCREEN_PROPERTY_KEY_MODIFIERS, &mod);
538
539 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));
540
541 /* Suppress key repeats if desired. Based off fg_main_mswin */
542 if ((flags & KEY_REPEAT) == 0 || (fgState.KeyRepeat == GLUT_KEY_REPEAT_OFF && fgStructure.CurrentWindow->State.IgnoreKeyRepeat == GL_TRUE)) {
543 unsigned int keypress = 0;
544 unsigned char ascii = 0;
545
546 /* Remember the current modifiers state so user can query it from their callback */
547 fgState.Modifiers = fgPlatformGetModifiers(mod);
548
549 /* Process keys */
550 if ((keypress = key_special(value))) {
551 if(flags & KEY_DOWN) {
552 INVOKE_WCB(*window, Special, (keypress, window->State.MouseX, window->State.MouseY));
553 } else {
554 INVOKE_WCB(*window, SpecialUp, (keypress, window->State.MouseX, window->State.MouseY));
555 }
556 } else if((flags & KEY_SYM_VALID) && (ascii = key_ascii(value))) {
557 if(flags & KEY_DOWN) {
558 INVOKE_WCB(*window, Keyboard, (ascii, window->State.MouseX, window->State.MouseY));
559 } else {
560 INVOKE_WCB(*window, KeyboardUp, (ascii, window->State.MouseX, window->State.MouseY));
561 }
562 } else {
563 LOGW("fgPlatformProcessSingleEvent: SCREEN_EVENT_KEYBOARD. Unhandled key event");
564 }
565
566 fgState.Modifiers = INVALID_MODIFIERS;
567 }
568 break;
569 }
570
571 case SCREEN_EVENT_PROPERTY:
572 case SCREEN_EVENT_IDLE:
573 break;
574
575 default:
576 LOGW("fgPlatformProcessSingleEvent: unknown screen event: 0x%X", SLOG2_FA_SIGNED(eventType));
577 break;
578 }
579 } else if (domain == navigator_get_domain()) {
580 unsigned int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
581 switch (eventType) {
582
583 case NAVIGATOR_WINDOW_STATE:
584 {
585 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE");
586
587 /* Covered only happens due to keyboard. When the app is minimized, the keyboard is closed.
588 When the keyboard is open, and the app is fullscreened, the keyboard is also closed.
589 If a window is covered and the app is minimized, the state will be set and the keyboard event
590 will adjust the screen size and change window status. */
591 navigator_window_state_t state = navigator_event_get_window_state(fgDisplay.pDisplay.event);
592 if(window->State.pWState.windowCovered == GL_FALSE)
593 {
594 switch (state)
595 {
596 case NAVIGATOR_WINDOW_FULLSCREEN:
597 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_FULLSCREEN");
598 window->State.Visible = GL_TRUE;
599 INVOKE_WCB(*window, WindowStatus, (GLUT_FULLY_RETAINED));
600 break;
601 case NAVIGATOR_WINDOW_THUMBNAIL:
602 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_THUMBNAIL");
603 window->State.Visible = GL_TRUE;
604 INVOKE_WCB(*window, WindowStatus, (GLUT_PARTIALLY_RETAINED));
605 break;
606 case NAVIGATOR_WINDOW_INVISIBLE:
607 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE-NAVIGATOR_WINDOW_INVISIBLE");
608 window->State.Visible = GL_FALSE;
609 INVOKE_WCB(*window, WindowStatus, (GLUT_HIDDEN));
610 break;
611 default:
612 LOGW("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_STATE unknown: 0x%X", SLOG2_FA_SIGNED(state));
613 break;
614 }
615 }
616 window->State.pWState.windowState = state;
617 break;
618 }
619
620 case NAVIGATOR_EXIT:
621 {
622 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_EXIT");
623
624 fgPlatformMainLoopPostWork();
625
626 /* User closed the application for good, let's kill the window */
627 SFG_Window* window = fgStructure.CurrentWindow;
628 if (window != NULL) {
629 fgDestroyWindow(window);
630 } else {
631 LOGW("NAVIGATOR_EXIT: No current window");
632 }
633
634 //XXX Should this be a bit more "forceful" so that it doesn't continue to loop through events?
635 break;
636 }
637
638 case NAVIGATOR_SWIPE_DOWN:
639 /* XXX Open app menu */
640 break;
641
642 /* Orientation is a bunch of handshakes.
643 - First the app get's asked if it wants to rotate (NAVIGATOR_ORIENTATION_CHECK)
644 - If the app wants to rotate, then it will be told what size it will be after rotate (NAVIGATOR_ORIENTATION_SIZE).
645 - Once the OS confirms that it's ready to rotate, it tells the app to handle rotation (NAVIGATOR_ORIENTATION).
646 - Once rotation is complete, the OS tells the app it's done (NAVIGATOR_ORIENTATION_DONE) */
647 case NAVIGATOR_ORIENTATION_CHECK:
648 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_CHECK");
649
650 /* Reset sizes */
651 window->State.pWState.newWidth = 0;
652 window->State.pWState.newHeight = 0;
653
654 #ifdef __PLAYBOOK__
655 /* On rotation, the keyboard is closed. This prevents two resize calls */
656 window->State.pWState.keyboardOpen = GL_FALSE;
657 #endif
658
659 /* Notify that we want to rotate */
660 navigator_orientation_check_response(fgDisplay.pDisplay.event, true);
661 break;
662
663 case NAVIGATOR_ORIENTATION:
664 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION");
665
666 /* NAVIGATOR_ORIENTATION occurs before NAVIGATOR_KEYBOARD_POSITION */
667
668 /* Rotate and resize the window */
669 fgPlatformRotateWindow(window, navigator_event_get_orientation_angle(fgDisplay.pDisplay.event));
670 fgPlatformFlushCommands();
671 #ifdef __PLAYBOOK__
672 /* PlayBook doesn't indicate what the new size will be, so we need to retrieve it from the window itself */
673 window->State.pWState.newWidth = glutGet(GLUT_WINDOW_WIDTH);
674 window->State.pWState.newHeight = glutGet(GLUT_WINDOW_HEIGHT);
675 fghOnReshapeNotify(window, window->State.pWState.newWidth, window->State.pWState.newHeight, GL_FALSE);
676 #else
677 if(window->State.pWState.keyboardOpen == GL_FALSE) {
678 /* On rotation, if the keyboard is open, it will get the keyboard resize events anyway. Otherwise, handle the resize. */
679 fghOnReshapeNotify(window, window->State.pWState.newWidth, window->State.pWState.newHeight, GL_FALSE);
680 }
681 #endif
682
683 /* Reset sizes */
684 window->State.pWState.newWidth = 0;
685 window->State.pWState.newHeight = 0;
686
687 /* Done rotating */
688 navigator_done_orientation(fgDisplay.pDisplay.event);
689 break;
690
691 case NAVIGATOR_BACK:
692 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_BACK");
693 INVOKE_WCB(*window, Keyboard, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
694 INVOKE_WCB(*window, KeyboardUp, (ESCAPE_BUTTON_KEY, window->State.MouseX, window->State.MouseY));
695 break;
696
697 case NAVIGATOR_WINDOW_ACTIVE:
698 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_ACTIVE");
699 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_RESUME));
700 break;
701
702 case NAVIGATOR_WINDOW_INACTIVE:
703 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_WINDOW_INACTIVE");
704 INVOKE_WCB(*window, AppStatus, (GLUT_APPSTATUS_PAUSE));
705 break;
706
707 case NAVIGATOR_ORIENTATION_DONE:
708 case NAVIGATOR_ORIENTATION_RESULT:
709 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_DONE/NAVIGATOR_ORIENTATION_RESULT");
710 break;
711
712 #ifndef __PLAYBOOK__
713 case NAVIGATOR_KEYBOARD_STATE:
714 case NAVIGATOR_KEYBOARD_POSITION:
715 /* See virtual keyboard handling for info on why this is not used. */
716 break;
717
718 case NAVIGATOR_DEVICE_LOCK_STATE:
719 break;
720
721 case NAVIGATOR_WINDOW_COVER:
722 case NAVIGATOR_WINDOW_COVER_ENTER:
723 case NAVIGATOR_WINDOW_COVER_EXIT:
724 /* BlackBerry specific. Let app status and window status take care of everything */
725 break;
726
727 case NAVIGATOR_APP_STATE:
728 /* Can do the same as NAVIGATOR_WINDOW_ACTIVE/NAVIGATOR_WINDOW_INACTIVE but
729 seems like it doesn't work when the app comes to the foreground. Might be a bug */
730 break;
731
732 case NAVIGATOR_ORIENTATION_SIZE:
733 LOGI("fgPlatformProcessSingleEvent: NAVIGATOR_ORIENTATION_SIZE");
734
735 /* Get new window size */
736 window->State.pWState.newWidth = navigator_event_get_orientation_size_width(fgDisplay.pDisplay.event);
737 window->State.pWState.newHeight = navigator_event_get_orientation_size_height(fgDisplay.pDisplay.event);
738 break;
739 #endif
740
741 case 0: //Doesn't exist in header, but shows up when keyboard shows and resizes
742 case NAVIGATOR_OTHER:
743 break;
744
745 default:
746 LOGW("fgPlatformProcessSingleEvent: unknown navigator event: 0x%X", SLOG2_FA_SIGNED(eventType));
747 break;
748 }
749 }
750 /*
751 * BlackBerry 10 navigator provides keyboard events, but they conflict with how we handle keyboard events.
752 * Causing multiple reshape messages and can leave window state incorrectly setup.
753 */
754 else if(domain == virtualkeyboard_get_domain()) {
755 unsigned int eventType = bps_event_get_code(fgDisplay.pDisplay.event);
756 switch (eventType) {
757 case VIRTUALKEYBOARD_EVENT_VISIBLE:
758 LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_VISIBLE");
759 if(window->State.pWState.keyboardOpen != GL_TRUE) {
760 window->State.pWState.keyboardOpen = GL_TRUE;
761 fgPlatformHandleKeyboardHeight(window, window->State.pWState.keyboardHeight);
762 }
763 break;
764
765 case VIRTUALKEYBOARD_EVENT_HIDDEN:
766 LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_HIDDEN");
767 if(window->State.pWState.keyboardOpen != GL_FALSE) {
768 window->State.pWState.keyboardOpen = GL_FALSE;
769 fgPlatformHandleKeyboardHeight(window, 0);
770 }
771 break;
772
773 case VIRTUALKEYBOARD_EVENT_INFO:
774 LOGI("fgPlatformProcessSingleEvent: VIRTUALKEYBOARD_EVENT_INFO");
775 window->State.pWState.keyboardHeight = virtualkeyboard_event_get_height(fgDisplay.pDisplay.event);
776 if(window->State.pWState.keyboardOpen == GL_TRUE) {
777 fgPlatformHandleKeyboardHeight(window, window->State.pWState.keyboardHeight);
778 }
779 break;
780
781 default:
782 LOGW("fgPlatformProcessSingleEvent: unknown virtualkeyboard event: 0x%X", eventType);
783 break;
784 }
785 }
786 } while(bps_get_event(&fgDisplay.pDisplay.event, 1) == BPS_SUCCESS && fgDisplay.pDisplay.event != NULL);
787
788 /* Reset event to reduce chances of triggering something */
789 fgDisplay.pDisplay.event = NULL;
790 }
791
fgPlatformMainLoopPreliminaryWork(void)792 void fgPlatformMainLoopPreliminaryWork ( void )
793 {
794 LOGI("fgPlatformMainLoopPreliminaryWork");
795
796 /* Request navigator events */
797 navigator_request_events(NAVIGATOR_EXTENDED_DATA);
798
799 /* Allow rotation */
800 navigator_rotation_lock(false);
801
802 /* Request keyboard events */
803 virtualkeyboard_request_events(0);
804
805 /* Request window events */
806 screen_request_events(fgDisplay.pDisplay.screenContext);
807 }
808
fgPlatformMainLoopPostWork(void)809 void fgPlatformMainLoopPostWork ( void )
810 {
811 LOGI("fgPlatformMainLoopPostWork");
812
813 /* Stop all events */
814 screen_stop_events(fgDisplay.pDisplay.screenContext);
815
816 #ifndef __PLAYBOOK__
817 navigator_stop_events(0);
818 #endif
819 }
820
821 /* deal with work list items */
fgPlatformInitWork(SFG_Window * window)822 void fgPlatformInitWork(SFG_Window* window)
823 {
824 LOGI("fgPlatformInitWork");
825
826 /* Position callback, always at 0,0 */
827 fghOnPositionNotify(window, 0, 0, GL_TRUE);
828
829 /* Get window size */
830 int size[2];
831 screen_get_window_property_iv(window->Window.Handle, SCREEN_PROPERTY_BUFFER_SIZE, size);
832 fghOnReshapeNotify(window, size[0], size[1], GL_FALSE);
833
834 /* Size gets notified on window creation with size detection in mainloop above
835 * XXX CHECK: does this messages happen too early like on windows,
836 * so client code cannot have registered a callback yet and the message
837 * is thus never received by client?
838 */
839 }
840
fgPlatformPosResZordWork(SFG_Window * window,unsigned int workMask)841 void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask)
842 {
843 if (workMask & GLUT_FULL_SCREEN_WORK)
844 fgPlatformFullScreenToggle( window );
845 if (workMask & GLUT_POSITION_WORK)
846 fgPlatformPositionWindow( window, window->State.DesiredXpos, window->State.DesiredYpos );
847 if (workMask & GLUT_SIZE_WORK)
848 fgPlatformReshapeWindow ( window, window->State.DesiredWidth, window->State.DesiredHeight );
849 if (workMask & GLUT_ZORDER_WORK)
850 {
851 if (window->State.DesiredZOrder < 0)
852 fgPlatformPushWindow( window );
853 else
854 fgPlatformPopWindow( window );
855 }
856 }
857
fgPlatformVisibilityWork(SFG_Window * window)858 void fgPlatformVisibilityWork(SFG_Window* window)
859 {
860 /* Visibility status of window should get updated in the window message handlers
861 * For now, none of these functions called below do anything, so don't worry
862 * about it
863 */
864 SFG_Window *win = window;
865 switch (window->State.DesiredVisibility)
866 {
867 case DesireHiddenState:
868 fgPlatformHideWindow( window );
869 break;
870 case DesireIconicState:
871 /* Call on top-level window */
872 while (win->Parent)
873 win = win->Parent;
874 fgPlatformIconifyWindow( win );
875 break;
876 case DesireNormalState:
877 fgPlatformShowWindow( window );
878 break;
879 }
880 }
881