comparison mupdf-source/thirdparty/freeglut/src/x11/fg_main_x11.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 /*
2 * fg_main_x11.c
3 *
4 * The X11-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 * Creation date: Thur Feb 2 2012
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
25 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
26 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
27 */
28
29 #include <GL/freeglut.h>
30 #include "../fg_internal.h"
31 #include <errno.h>
32 #include <limits.h>
33 #include <stdarg.h>
34 #include <sys/select.h>
35
36 /*
37 * Try to get the maximum value allowed for ints, falling back to the minimum
38 * guaranteed by ISO C99 if there is no suitable header.
39 */
40 #ifdef HAVE_LIMITS_H
41 # include <limits.h>
42 #endif
43 #ifndef INT_MAX
44 # define INT_MAX 32767
45 #endif
46
47 #ifndef MIN
48 # define MIN(a,b) (((a)<(b)) ? (a) : (b))
49 #endif
50
51 extern void fghOnReshapeNotify(SFG_Window *window, int width, int height, GLboolean forceNotify);
52 extern void fghOnPositionNotify(SFG_Window *window, int x, int y, GLboolean forceNotify);
53 extern void fgPlatformFullScreenToggle( SFG_Window *win );
54 extern void fgPlatformPositionWindow( SFG_Window *window, int x, int y );
55 extern void fgPlatformReshapeWindow ( SFG_Window *window, int width, int height );
56 extern void fgPlatformPushWindow( SFG_Window *window );
57 extern void fgPlatformPopWindow( SFG_Window *window );
58 extern void fgPlatformHideWindow( SFG_Window *window );
59 extern void fgPlatformIconifyWindow( SFG_Window *window );
60 extern void fgPlatformShowWindow( SFG_Window *window );
61
62 /* used in the event handling code to match and discard stale mouse motion events */
63 static Bool match_motion(Display *dpy, XEvent *xev, XPointer arg);
64
65 /*
66 * TODO BEFORE THE STABLE RELEASE:
67 *
68 * There are some issues concerning window redrawing under X11, and maybe
69 * some events are not handled.
70 *
71 * Need to investigate why the X11 version breaks out with an error when
72 * closing a window (using the window manager, not glutDestroyWindow)...
73 */
74
75
76
77 fg_time_t fgPlatformSystemTime ( void )
78 {
79 #ifdef CLOCK_MONOTONIC
80 struct timespec now;
81 clock_gettime(CLOCK_MONOTONIC, &now);
82 return now.tv_nsec/1000000 + now.tv_sec*1000;
83 #elif defined(HAVE_GETTIMEOFDAY)
84 struct timeval now;
85 gettimeofday( &now, NULL );
86 return now.tv_usec/1000 + now.tv_sec*1000;
87 #endif
88 }
89
90 /*
91 * Does the magic required to relinquish the CPU until something interesting
92 * happens.
93 */
94
95 void fgPlatformSleepForEvents( fg_time_t msec )
96 {
97 /*
98 * Possibly due to aggressive use of XFlush() and friends,
99 * it is possible to have our socket drained but still have
100 * unprocessed events. (Or, this may just be normal with
101 * X, anyway?) We do non-trivial processing of X events
102 * after the event-reading loop, in any case, so we
103 * need to allow that we may have an empty socket but non-
104 * empty event queue.
105 */
106 if( ! XPending( fgDisplay.pDisplay.Display ) )
107 {
108 fd_set fdset;
109 int err;
110 int socket;
111 struct timeval wait;
112
113 socket = ConnectionNumber( fgDisplay.pDisplay.Display );
114 FD_ZERO( &fdset );
115 FD_SET( socket, &fdset );
116 wait.tv_sec = msec / 1000;
117 wait.tv_usec = (msec % 1000) * 1000;
118 err = select( socket+1, &fdset, NULL, NULL, &wait );
119
120 if( ( -1 == err ) && ( errno != EINTR ) )
121 fgWarning ( "freeglut select() error: %d", errno );
122 }
123 }
124
125
126 /*
127 * Returns GLUT modifier mask for the state field of an X11 event.
128 */
129 int fgPlatformGetModifiers( int state )
130 {
131 int ret = 0;
132
133 if( state & ( ShiftMask | LockMask ) )
134 ret |= GLUT_ACTIVE_SHIFT;
135 if( state & ControlMask )
136 ret |= GLUT_ACTIVE_CTRL;
137 if( state & Mod1Mask )
138 ret |= GLUT_ACTIVE_ALT;
139
140 return ret;
141 }
142
143 static const char* fghTypeToString( int type )
144 {
145 switch( type ) {
146 case KeyPress: return "KeyPress";
147 case KeyRelease: return "KeyRelease";
148 case ButtonPress: return "ButtonPress";
149 case ButtonRelease: return "ButtonRelease";
150 case MotionNotify: return "MotionNotify";
151 case EnterNotify: return "EnterNotify";
152 case LeaveNotify: return "LeaveNotify";
153 case FocusIn: return "FocusIn";
154 case FocusOut: return "FocusOut";
155 case KeymapNotify: return "KeymapNotify";
156 case Expose: return "Expose";
157 case GraphicsExpose: return "GraphicsExpose";
158 case NoExpose: return "NoExpose";
159 case VisibilityNotify: return "VisibilityNotify";
160 case CreateNotify: return "CreateNotify";
161 case DestroyNotify: return "DestroyNotify";
162 case UnmapNotify: return "UnmapNotify";
163 case MapNotify: return "MapNotify";
164 case MapRequest: return "MapRequest";
165 case ReparentNotify: return "ReparentNotify";
166 case ConfigureNotify: return "ConfigureNotify";
167 case ConfigureRequest: return "ConfigureRequest";
168 case GravityNotify: return "GravityNotify";
169 case ResizeRequest: return "ResizeRequest";
170 case CirculateNotify: return "CirculateNotify";
171 case CirculateRequest: return "CirculateRequest";
172 case PropertyNotify: return "PropertyNotify";
173 case SelectionClear: return "SelectionClear";
174 case SelectionRequest: return "SelectionRequest";
175 case SelectionNotify: return "SelectionNotify";
176 case ColormapNotify: return "ColormapNotify";
177 case ClientMessage: return "ClientMessage";
178 case MappingNotify: return "MappingNotify";
179 default: return "UNKNOWN";
180 }
181 }
182
183 static const char* fghBoolToString( Bool b )
184 {
185 return b == False ? "False" : "True";
186 }
187
188 static const char* fghNotifyHintToString( char is_hint )
189 {
190 switch( is_hint ) {
191 case NotifyNormal: return "NotifyNormal";
192 case NotifyHint: return "NotifyHint";
193 default: return "UNKNOWN";
194 }
195 }
196
197 static const char* fghNotifyModeToString( int mode )
198 {
199 switch( mode ) {
200 case NotifyNormal: return "NotifyNormal";
201 case NotifyGrab: return "NotifyGrab";
202 case NotifyUngrab: return "NotifyUngrab";
203 case NotifyWhileGrabbed: return "NotifyWhileGrabbed";
204 default: return "UNKNOWN";
205 }
206 }
207
208 static const char* fghNotifyDetailToString( int detail )
209 {
210 switch( detail ) {
211 case NotifyAncestor: return "NotifyAncestor";
212 case NotifyVirtual: return "NotifyVirtual";
213 case NotifyInferior: return "NotifyInferior";
214 case NotifyNonlinear: return "NotifyNonlinear";
215 case NotifyNonlinearVirtual: return "NotifyNonlinearVirtual";
216 case NotifyPointer: return "NotifyPointer";
217 case NotifyPointerRoot: return "NotifyPointerRoot";
218 case NotifyDetailNone: return "NotifyDetailNone";
219 default: return "UNKNOWN";
220 }
221 }
222
223 static const char* fghVisibilityToString( int state ) {
224 switch( state ) {
225 case VisibilityUnobscured: return "VisibilityUnobscured";
226 case VisibilityPartiallyObscured: return "VisibilityPartiallyObscured";
227 case VisibilityFullyObscured: return "VisibilityFullyObscured";
228 default: return "UNKNOWN";
229 }
230 }
231
232 static const char* fghConfigureDetailToString( int detail )
233 {
234 switch( detail ) {
235 case Above: return "Above";
236 case Below: return "Below";
237 case TopIf: return "TopIf";
238 case BottomIf: return "BottomIf";
239 case Opposite: return "Opposite";
240 default: return "UNKNOWN";
241 }
242 }
243
244 static const char* fghPlaceToString( int place )
245 {
246 switch( place ) {
247 case PlaceOnTop: return "PlaceOnTop";
248 case PlaceOnBottom: return "PlaceOnBottom";
249 default: return "UNKNOWN";
250 }
251 }
252
253 static const char* fghMappingRequestToString( int request )
254 {
255 switch( request ) {
256 case MappingModifier: return "MappingModifier";
257 case MappingKeyboard: return "MappingKeyboard";
258 case MappingPointer: return "MappingPointer";
259 default: return "UNKNOWN";
260 }
261 }
262
263 static const char* fghPropertyStateToString( int state )
264 {
265 switch( state ) {
266 case PropertyNewValue: return "PropertyNewValue";
267 case PropertyDelete: return "PropertyDelete";
268 default: return "UNKNOWN";
269 }
270 }
271
272 static const char* fghColormapStateToString( int state )
273 {
274 switch( state ) {
275 case ColormapUninstalled: return "ColormapUninstalled";
276 case ColormapInstalled: return "ColormapInstalled";
277 default: return "UNKNOWN";
278 }
279 }
280
281 __fg_unused static void fghPrintEvent( XEvent *event )
282 {
283 switch( event->type ) {
284
285 case KeyPress:
286 case KeyRelease: {
287 XKeyEvent *e = &event->xkey;
288 fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, "
289 "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, "
290 "keycode=%u, same_screen=%s", fghTypeToString( e->type ),
291 e->window, e->root, e->subwindow, (unsigned long)e->time,
292 e->x, e->y, e->x_root, e->y_root, e->state, e->keycode,
293 fghBoolToString( e->same_screen ) );
294 break;
295 }
296
297 case ButtonPress:
298 case ButtonRelease: {
299 XButtonEvent *e = &event->xbutton;
300 fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, "
301 "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, "
302 "button=%u, same_screen=%d", fghTypeToString( e->type ),
303 e->window, e->root, e->subwindow, (unsigned long)e->time,
304 e->x, e->y, e->x_root, e->y_root, e->state, e->button,
305 fghBoolToString( e->same_screen ) );
306 break;
307 }
308
309 case MotionNotify: {
310 XMotionEvent *e = &event->xmotion;
311 fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, "
312 "(x,y)=(%d,%d), (x_root,y_root)=(%d,%d), state=0x%x, "
313 "is_hint=%s, same_screen=%d", fghTypeToString( e->type ),
314 e->window, e->root, e->subwindow, (unsigned long)e->time,
315 e->x, e->y, e->x_root, e->y_root, e->state,
316 fghNotifyHintToString( e->is_hint ),
317 fghBoolToString( e->same_screen ) );
318 break;
319 }
320
321 case EnterNotify:
322 case LeaveNotify: {
323 XCrossingEvent *e = &event->xcrossing;
324 fgWarning( "%s: window=0x%x, root=0x%x, subwindow=0x%x, time=%lu, "
325 "(x,y)=(%d,%d), mode=%s, detail=%s, same_screen=%d, "
326 "focus=%d, state=0x%x", fghTypeToString( e->type ),
327 e->window, e->root, e->subwindow, (unsigned long)e->time,
328 e->x, e->y, fghNotifyModeToString( e->mode ),
329 fghNotifyDetailToString( e->detail ), (int)e->same_screen,
330 (int)e->focus, e->state );
331 break;
332 }
333
334 case FocusIn:
335 case FocusOut: {
336 XFocusChangeEvent *e = &event->xfocus;
337 fgWarning( "%s: window=0x%x, mode=%s, detail=%s",
338 fghTypeToString( e->type ), e->window,
339 fghNotifyModeToString( e->mode ),
340 fghNotifyDetailToString( e->detail ) );
341 break;
342 }
343
344 case KeymapNotify: {
345 XKeymapEvent *e = &event->xkeymap;
346 char buf[32 * 2 + 1];
347 int i;
348 for ( i = 0; i < 32; i++ ) {
349 snprintf( &buf[ i * 2 ], sizeof( buf ) - i * 2,
350 "%02x", e->key_vector[ i ] );
351 }
352 buf[ i ] = '\0';
353 fgWarning( "%s: window=0x%x, %s", fghTypeToString( e->type ), e->window,
354 buf );
355 break;
356 }
357
358 case Expose: {
359 XExposeEvent *e = &event->xexpose;
360 fgWarning( "%s: window=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), "
361 "count=%d", fghTypeToString( e->type ), e->window, e->x,
362 e->y, e->width, e->height, e->count );
363 break;
364 }
365
366 case GraphicsExpose: {
367 XGraphicsExposeEvent *e = &event->xgraphicsexpose;
368 fgWarning( "%s: drawable=0x%x, (x,y)=(%d,%d), (width,height)=(%d,%d), "
369 "count=%d, (major_code,minor_code)=(%d,%d)",
370 fghTypeToString( e->type ), e->drawable, e->x, e->y,
371 e->width, e->height, e->count, e->major_code,
372 e->minor_code );
373 break;
374 }
375
376 case NoExpose: {
377 XNoExposeEvent *e = &event->xnoexpose;
378 fgWarning( "%s: drawable=0x%x, (major_code,minor_code)=(%d,%d)",
379 fghTypeToString( e->type ), e->drawable, e->major_code,
380 e->minor_code );
381 break;
382 }
383
384 case VisibilityNotify: {
385 XVisibilityEvent *e = &event->xvisibility;
386 fgWarning( "%s: window=0x%x, state=%s", fghTypeToString( e->type ),
387 e->window, fghVisibilityToString( e->state) );
388 break;
389 }
390
391 case CreateNotify: {
392 XCreateWindowEvent *e = &event->xcreatewindow;
393 fgWarning( "%s: (x,y)=(%d,%d), (width,height)=(%d,%d), border_width=%d, "
394 "window=0x%x, override_redirect=%s",
395 fghTypeToString( e->type ), e->x, e->y, e->width, e->height,
396 e->border_width, e->window,
397 fghBoolToString( e->override_redirect ) );
398 break;
399 }
400
401 case DestroyNotify: {
402 XDestroyWindowEvent *e = &event->xdestroywindow;
403 fgWarning( "%s: event=0x%x, window=0x%x",
404 fghTypeToString( e->type ), e->event, e->window );
405 break;
406 }
407
408 case UnmapNotify: {
409 XUnmapEvent *e = &event->xunmap;
410 fgWarning( "%s: event=0x%x, window=0x%x, from_configure=%s",
411 fghTypeToString( e->type ), e->event, e->window,
412 fghBoolToString( e->from_configure ) );
413 break;
414 }
415
416 case MapNotify: {
417 XMapEvent *e = &event->xmap;
418 fgWarning( "%s: event=0x%x, window=0x%x, override_redirect=%s",
419 fghTypeToString( e->type ), e->event, e->window,
420 fghBoolToString( e->override_redirect ) );
421 break;
422 }
423
424 case MapRequest: {
425 XMapRequestEvent *e = &event->xmaprequest;
426 fgWarning( "%s: parent=0x%x, window=0x%x",
427 fghTypeToString( event->type ), e->parent, e->window );
428 break;
429 }
430
431 case ReparentNotify: {
432 XReparentEvent *e = &event->xreparent;
433 fgWarning( "%s: event=0x%x, window=0x%x, parent=0x%x, (x,y)=(%d,%d), "
434 "override_redirect=%s", fghTypeToString( e->type ),
435 e->event, e->window, e->parent, e->x, e->y,
436 fghBoolToString( e->override_redirect ) );
437 break;
438 }
439
440 case ConfigureNotify: {
441 XConfigureEvent *e = &event->xconfigure;
442 fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d), "
443 "(width,height)=(%d,%d), border_width=%d, above=0x%x, "
444 "override_redirect=%s", fghTypeToString( e->type ), e->event,
445 e->window, e->x, e->y, e->width, e->height, e->border_width,
446 e->above, fghBoolToString( e->override_redirect ) );
447 break;
448 }
449
450 case ConfigureRequest: {
451 XConfigureRequestEvent *e = &event->xconfigurerequest;
452 fgWarning( "%s: parent=0x%x, window=0x%x, (x,y)=(%d,%d), "
453 "(width,height)=(%d,%d), border_width=%d, above=0x%x, "
454 "detail=%s, value_mask=%lx", fghTypeToString( e->type ),
455 e->parent, e->window, e->x, e->y, e->width, e->height,
456 e->border_width, e->above,
457 fghConfigureDetailToString( e->detail ), e->value_mask );
458 break;
459 }
460
461 case GravityNotify: {
462 XGravityEvent *e = &event->xgravity;
463 fgWarning( "%s: event=0x%x, window=0x%x, (x,y)=(%d,%d)",
464 fghTypeToString( e->type ), e->event, e->window, e->x, e->y );
465 break;
466 }
467
468 case ResizeRequest: {
469 XResizeRequestEvent *e = &event->xresizerequest;
470 fgWarning( "%s: window=0x%x, (width,height)=(%d,%d)",
471 fghTypeToString( e->type ), e->window, e->width, e->height );
472 break;
473 }
474
475 case CirculateNotify: {
476 XCirculateEvent *e = &event->xcirculate;
477 fgWarning( "%s: event=0x%x, window=0x%x, place=%s",
478 fghTypeToString( e->type ), e->event, e->window,
479 fghPlaceToString( e->place ) );
480 break;
481 }
482
483 case CirculateRequest: {
484 XCirculateRequestEvent *e = &event->xcirculaterequest;
485 fgWarning( "%s: parent=0x%x, window=0x%x, place=%s",
486 fghTypeToString( e->type ), e->parent, e->window,
487 fghPlaceToString( e->place ) );
488 break;
489 }
490
491 case PropertyNotify: {
492 XPropertyEvent *e = &event->xproperty;
493 fgWarning( "%s: window=0x%x, atom=%lu, time=%lu, state=%s",
494 fghTypeToString( e->type ), e->window,
495 (unsigned long)e->atom, (unsigned long)e->time,
496 fghPropertyStateToString( e->state ) );
497 break;
498 }
499
500 case SelectionClear: {
501 XSelectionClearEvent *e = &event->xselectionclear;
502 fgWarning( "%s: window=0x%x, selection=%lu, time=%lu",
503 fghTypeToString( e->type ), e->window,
504 (unsigned long)e->selection, (unsigned long)e->time );
505 break;
506 }
507
508 case SelectionRequest: {
509 XSelectionRequestEvent *e = &event->xselectionrequest;
510 fgWarning( "%s: owner=0x%x, requestor=0x%x, selection=0x%x, "
511 "target=0x%x, property=%lu, time=%lu",
512 fghTypeToString( e->type ), e->owner, e->requestor,
513 (unsigned long)e->selection, (unsigned long)e->target,
514 (unsigned long)e->property, (unsigned long)e->time );
515 break;
516 }
517
518 case SelectionNotify: {
519 XSelectionEvent *e = &event->xselection;
520 fgWarning( "%s: requestor=0x%x, selection=0x%x, target=0x%x, "
521 "property=%lu, time=%lu", fghTypeToString( e->type ),
522 e->requestor, (unsigned long)e->selection,
523 (unsigned long)e->target, (unsigned long)e->property,
524 (unsigned long)e->time );
525 break;
526 }
527
528 case ColormapNotify: {
529 XColormapEvent *e = &event->xcolormap;
530 fgWarning( "%s: window=0x%x, colormap=%lu, new=%s, state=%s",
531 fghTypeToString( e->type ), e->window,
532 (unsigned long)e->colormap, fghBoolToString( e->new ),
533 fghColormapStateToString( e->state ) );
534 break;
535 }
536
537 case ClientMessage: {
538 XClientMessageEvent *e = &event->xclient;
539 char buf[ 61 ];
540 char* p = buf;
541 char* end = buf + sizeof( buf );
542 int i;
543 switch( e->format ) {
544 case 8:
545 for ( i = 0; i < 20; i++, p += 3 ) {
546 snprintf( p, end - p, " %02x", e->data.b[ i ] );
547 }
548 break;
549 case 16:
550 for ( i = 0; i < 10; i++, p += 5 ) {
551 snprintf( p, end - p, " %04x", e->data.s[ i ] );
552 }
553 break;
554 case 32:
555 for ( i = 0; i < 5; i++, p += 9 ) {
556 snprintf( p, end - p, " %08lx", e->data.l[ i ] );
557 }
558 break;
559 }
560 *p = '\0';
561 fgWarning( "%s: window=0x%x, message_type=%lu, format=%d, data=(%s )",
562 fghTypeToString( e->type ), e->window,
563 (unsigned long)e->message_type, e->format, buf );
564 break;
565 }
566
567 case MappingNotify: {
568 XMappingEvent *e = &event->xmapping;
569 fgWarning( "%s: window=0x%x, request=%s, first_keycode=%d, count=%d",
570 fghTypeToString( e->type ), e->window,
571 fghMappingRequestToString( e->request ), e->first_keycode,
572 e->count );
573 break;
574 }
575
576 default: {
577 fgWarning( "%s", fghTypeToString( event->type ) );
578 break;
579 }
580 }
581 }
582
583 /* UTF-8 decoding routine */
584 enum
585 {
586 Runeerror = 0xFFFD, /* decoding error in UTF */
587
588 Bit1 = 7,
589 Bitx = 6,
590 Bit2 = 5,
591 Bit3 = 4,
592 Bit4 = 3,
593 Bit5 = 2,
594
595 T1 = ((1<<(Bit1+1))-1) ^ 0xFF, /* 0000 0000 */
596 Tx = ((1<<(Bitx+1))-1) ^ 0xFF, /* 1000 0000 */
597 T2 = ((1<<(Bit2+1))-1) ^ 0xFF, /* 1100 0000 */
598 T3 = ((1<<(Bit3+1))-1) ^ 0xFF, /* 1110 0000 */
599 T4 = ((1<<(Bit4+1))-1) ^ 0xFF, /* 1111 0000 */
600 T5 = ((1<<(Bit5+1))-1) ^ 0xFF, /* 1111 1000 */
601
602 Rune1 = (1<<(Bit1+0*Bitx))-1, /* 0000 0000 0111 1111 */
603 Rune2 = (1<<(Bit2+1*Bitx))-1, /* 0000 0111 1111 1111 */
604 Rune3 = (1<<(Bit3+2*Bitx))-1, /* 1111 1111 1111 1111 */
605 Rune4 = (1<<(Bit4+3*Bitx))-1, /* 0001 1111 1111 1111 1111 1111 */
606
607 Maskx = (1<<Bitx)-1, /* 0011 1111 */
608 Testx = Maskx ^ 0xFF, /* 1100 0000 */
609
610 Bad = Runeerror,
611 };
612
613 static int chartorune(int *rune, const char *str)
614 {
615 int c, c1, c2, c3;
616 int l;
617
618 /*
619 * one character sequence
620 * 00000-0007F => T1
621 */
622 c = *(const unsigned char*)str;
623 if(c < Tx) {
624 *rune = c;
625 return 1;
626 }
627
628 /*
629 * two character sequence
630 * 0080-07FF => T2 Tx
631 */
632 c1 = *(const unsigned char*)(str+1) ^ Tx;
633 if(c1 & Testx)
634 goto bad;
635 if(c < T3) {
636 if(c < T2)
637 goto bad;
638 l = ((c << Bitx) | c1) & Rune2;
639 if(l <= Rune1)
640 goto bad;
641 *rune = l;
642 return 2;
643 }
644
645 /*
646 * three character sequence
647 * 0800-FFFF => T3 Tx Tx
648 */
649 c2 = *(const unsigned char*)(str+2) ^ Tx;
650 if(c2 & Testx)
651 goto bad;
652 if(c < T4) {
653 l = ((((c << Bitx) | c1) << Bitx) | c2) & Rune3;
654 if(l <= Rune2)
655 goto bad;
656 *rune = l;
657 return 3;
658 }
659
660 /*
661 * four character sequence (21-bit value)
662 * 10000-1FFFFF => T4 Tx Tx Tx
663 */
664 c3 = *(const unsigned char*)(str+3) ^ Tx;
665 if (c3 & Testx)
666 goto bad;
667 if (c < T5) {
668 l = ((((((c << Bitx) | c1) << Bitx) | c2) << Bitx) | c3) & Rune4;
669 if (l <= Rune3)
670 goto bad;
671 *rune = l;
672 return 4;
673 }
674 /*
675 * Support for 5-byte or longer UTF-8 would go here, but
676 * since we don't have that, we'll just fall through to bad.
677 */
678
679 /*
680 * bad decoding
681 */
682 bad:
683 *rune = Bad;
684 return 1;
685 }
686
687 extern char *fgClipboardBuffer[3];
688
689 static Atom fghGetAtom(const char *name)
690 {
691 return XInternAtom(fgDisplay.pDisplay.Display, name, False);
692 }
693
694 static void fgHandleSelectionNotify(XEvent *event)
695 {
696 Display *dpy = fgDisplay.pDisplay.Display;
697 Atom actual_type;
698 int actual_format;
699 unsigned long item_count;
700 unsigned long bytes_after;
701 unsigned char *prop;
702
703 if (event->xselection.property == None)
704 {
705 fgWarning("Couldn't convert selection to UTF-8 string.");
706 return;
707 }
708
709 XGetWindowProperty(dpy, event->xselection.requestor, event->xselection.property,
710 0, LONG_MAX, True, AnyPropertyType,
711 &actual_type, &actual_format, &item_count, &bytes_after, &prop);
712
713 if (actual_type == fghGetAtom("UTF8_STRING"))
714 {
715 if (event->xselection.selection == fghGetAtom("CLIPBOARD"))
716 {
717 free(fgClipboardBuffer[GLUT_CLIPBOARD]);
718 fgClipboardBuffer[GLUT_CLIPBOARD] = strdup((char*)prop);
719 }
720 if (event->xselection.selection == XA_PRIMARY)
721 {
722 free(fgClipboardBuffer[GLUT_PRIMARY]);
723 fgClipboardBuffer[GLUT_PRIMARY] = strdup((char*)prop);
724 }
725 if (event->xselection.selection == XA_SECONDARY)
726 {
727 free(fgClipboardBuffer[GLUT_SECONDARY]);
728 fgClipboardBuffer[GLUT_SECONDARY] = strdup((char*)prop);
729 }
730 }
731
732 XFree(prop);
733 }
734
735 static void fgHandleSelectionClear(XEvent *event)
736 {
737 if (event->xselectionclear.selection == fghGetAtom("CLIPBOARD"))
738 {
739 free(fgClipboardBuffer[GLUT_CLIPBOARD]);
740 fgClipboardBuffer[GLUT_CLIPBOARD] = NULL;
741 }
742 else if (event->xselectionclear.selection == XA_PRIMARY)
743 {
744 free(fgClipboardBuffer[GLUT_PRIMARY]);
745 fgClipboardBuffer[GLUT_PRIMARY] = NULL;
746 }
747 else if (event->xselectionclear.selection == XA_SECONDARY)
748 {
749 free(fgClipboardBuffer[GLUT_SECONDARY]);
750 fgClipboardBuffer[GLUT_SECONDARY] = NULL;
751 }
752 }
753
754 static void fgHandleSelectionRequest(XEvent *event)
755 {
756 Display *dpy = fgDisplay.pDisplay.Display;
757 Window requestor = event->xselectionrequest.requestor;
758 Atom selection = event->xselectionrequest.selection;
759 Atom target = event->xselectionrequest.target;
760 Atom property = event->xselectionrequest.property;
761 Atom time = event->xselectionrequest.time;
762 XEvent response;
763 char *text;
764
765 if (property == None)
766 property = target;
767
768 response.xselection.type = SelectionNotify;
769 response.xselection.send_event = True;
770 response.xselection.display = dpy;
771 response.xselection.requestor = requestor;
772 response.xselection.selection = selection;
773 response.xselection.target = target;
774 response.xselection.property = property;
775 response.xselection.time = time;
776
777 if (selection == fghGetAtom("CLIPBOARD"))
778 text = fgClipboardBuffer[GLUT_CLIPBOARD];
779 else if (selection == XA_PRIMARY)
780 text = fgClipboardBuffer[GLUT_PRIMARY];
781 else if (selection == XA_SECONDARY)
782 text = fgClipboardBuffer[GLUT_SECONDARY];
783 else
784 return;
785 if (!text)
786 return;
787
788 if (target == fghGetAtom("TARGETS"))
789 {
790 Atom list[4] = {
791 fghGetAtom("TARGETS"),
792 fghGetAtom("TIMESTAMP"),
793 XA_STRING,
794 fghGetAtom("UTF8_STRING")
795 };
796 XChangeProperty(dpy, requestor, property, target,
797 32, PropModeReplace, (unsigned char *)list, sizeof(list)/sizeof(Atom));
798 }
799 else if (target == XA_STRING || target == fghGetAtom("UTF8_STRING"))
800 {
801 XChangeProperty(dpy, requestor, property, target,
802 8, PropModeReplace, (unsigned char *)text, strlen(text));
803 }
804
805 XSendEvent(dpy, requestor, False, 0, &response);
806 }
807
808 void fgPlatformSetClipboard(int selection, const char *text)
809 {
810 Display *dpy = fgDisplay.pDisplay.Display;
811 Window window = fgStructure.CurrentWindow->Window.Handle;
812 Atom xselection;
813 if (selection == GLUT_CLIPBOARD)
814 xselection = fghGetAtom("CLIPBOARD");
815 else if (selection == GLUT_PRIMARY)
816 xselection = XA_PRIMARY;
817 else if (selection == GLUT_SECONDARY)
818 xselection = XA_SECONDARY;
819 else
820 return;
821
822 free(fgClipboardBuffer[selection]);
823 fgClipboardBuffer[selection] = strdup(text);
824
825 XSetSelectionOwner(dpy, xselection, window, CurrentTime);
826 }
827
828 static Bool isSelectionNotify(Display *dpi, XEvent *event, XPointer arg)
829 {
830 return (event->type == SelectionNotify);
831 }
832
833 const char *fgPlatformGetClipboard(int selection)
834 {
835 Display *dpy = fgDisplay.pDisplay.Display;
836 Window window = fgStructure.CurrentWindow->Window.Handle;
837 Atom xselection;
838 Window owner;
839 XEvent event;
840
841 if (selection == GLUT_CLIPBOARD)
842 xselection = fghGetAtom("CLIPBOARD");
843 else if (selection == GLUT_PRIMARY)
844 xselection = XA_PRIMARY;
845 else if (selection == GLUT_SECONDARY)
846 xselection = XA_SECONDARY;
847 else
848 return NULL;
849
850 owner = XGetSelectionOwner(dpy, xselection);
851 if (!owner)
852 return NULL;
853 if (owner != window)
854 {
855 XConvertSelection(dpy, xselection, fghGetAtom("UTF8_STRING"), xselection, window, CurrentTime);
856 XIfEvent(dpy, &event, isSelectionNotify, NULL);
857 fgHandleSelectionNotify(&event);
858 }
859
860 return fgClipboardBuffer[selection];
861 }
862
863 void fgPlatformProcessSingleEvent ( void )
864 {
865 SFG_Window* window;
866 XEvent event;
867
868 /* This code was repeated constantly, so here it goes into a definition: */
869 #define GETWINDOW(a) \
870 window = fgWindowByHandle( event.a.window ); \
871 if( window == NULL ) \
872 break;
873
874 #define GETMOUSE(a) \
875 window->State.MouseX = event.a.x; \
876 window->State.MouseY = event.a.y;
877
878 FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutMainLoopEvent" );
879
880 while( XPending( fgDisplay.pDisplay.Display ) )
881 {
882 XNextEvent( fgDisplay.pDisplay.Display, &event );
883 #if _DEBUG
884 fghPrintEvent( &event );
885 #endif
886 if (XFilterEvent(&event, None))
887 continue;
888
889 switch( event.type )
890 {
891 case ClientMessage:
892 if (fgStructure.CurrentWindow)
893 if(fgIsSpaceballXEvent(&event)) {
894 fgSpaceballHandleXEvent(&event);
895 break;
896 }
897 /* Destroy the window when the WM_DELETE_WINDOW message arrives */
898 if( (Atom) event.xclient.data.l[ 0 ] == fgDisplay.pDisplay.DeleteWindow )
899 {
900 GETWINDOW( xclient );
901
902 fgDestroyWindow ( window );
903
904 if( fgState.ActionOnWindowClose == GLUT_ACTION_EXIT )
905 {
906 fgDeinitialize( );
907 exit( 0 );
908 }
909 else if( fgState.ActionOnWindowClose == GLUT_ACTION_GLUTMAINLOOP_RETURNS )
910 fgState.ExecState = GLUT_EXEC_STATE_STOP;
911
912 return;
913 }
914 break;
915
916 case SelectionClear:
917 fgHandleSelectionClear(&event);
918 break;
919 case SelectionRequest:
920 fgHandleSelectionRequest(&event);
921 break;
922 case SelectionNotify:
923 fgHandleSelectionNotify(&event);
924 break;
925
926 /*
927 * CreateNotify causes a configure-event so that sub-windows are
928 * handled compatibly with GLUT. Otherwise, your sub-windows
929 * (in freeglut only) will not get an initial reshape event,
930 * which can break things.
931 *
932 * GLUT presumably does this because it generally tries to treat
933 * sub-windows the same as windows.
934 */
935 case CreateNotify:
936 case ConfigureNotify:
937 {
938 int width, height, x, y;
939 if( event.type == CreateNotify ) {
940 GETWINDOW( xcreatewindow );
941 width = event.xcreatewindow.width;
942 height = event.xcreatewindow.height;
943 x = event.xcreatewindow.x;
944 y = event.xcreatewindow.y;
945 } else {
946 GETWINDOW( xconfigure );
947 width = event.xconfigure.width;
948 height = event.xconfigure.height;
949 x = event.xconfigure.x;
950 y = event.xconfigure.y;
951 }
952
953 /* Update state and call callback, if there was a change */
954 fghOnPositionNotify(window, x, y, GL_FALSE);
955 /* Update state and call callback, if there was a change */
956 fghOnReshapeNotify(window, width, height, GL_FALSE);
957 }
958 break;
959
960 case DestroyNotify:
961 /*
962 * This is sent to confirm the XDestroyWindow call.
963 *
964 * XXX WHY is this commented out? Should we re-enable it?
965 */
966 /* fgAddToWindowDestroyList ( window ); */
967 break;
968
969 case Expose:
970 /*
971 * We are too dumb to process partial exposes...
972 *
973 * XXX Well, we could do it. However, it seems to only
974 * XXX be potentially useful for single-buffered (since
975 * XXX double-buffered does not respect viewport when we
976 * XXX do a buffer-swap).
977 *
978 */
979 if( event.xexpose.count == 0 )
980 {
981 GETWINDOW( xexpose );
982 window->State.WorkMask |= GLUT_DISPLAY_WORK;
983 }
984 break;
985
986 case MapNotify:
987 break;
988
989 case UnmapNotify:
990 /* We get this when iconifying a window. */
991 GETWINDOW( xunmap );
992 INVOKE_WCB( *window, WindowStatus, ( GLUT_HIDDEN ) );
993 window->State.Visible = GL_FALSE;
994 break;
995
996 case MappingNotify:
997 /*
998 * Have the client's keyboard knowledge updated (xlib.ps,
999 * page 206, says that's a good thing to do)
1000 */
1001 XRefreshKeyboardMapping( (XMappingEvent *) &event );
1002 break;
1003
1004 case VisibilityNotify:
1005 {
1006 /*
1007 * Sending this event, the X server can notify us that the window
1008 * has just acquired one of the three possible visibility states:
1009 * VisibilityUnobscured, VisibilityPartiallyObscured or
1010 * VisibilityFullyObscured. Note that we DO NOT receive a
1011 * VisibilityNotify event when iconifying a window, we only get an
1012 * UnmapNotify then.
1013 */
1014 GETWINDOW( xvisibility );
1015 switch( event.xvisibility.state )
1016 {
1017 case VisibilityUnobscured:
1018 INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_RETAINED ) );
1019 window->State.Visible = GL_TRUE;
1020 break;
1021
1022 case VisibilityPartiallyObscured:
1023 INVOKE_WCB( *window, WindowStatus,
1024 ( GLUT_PARTIALLY_RETAINED ) );
1025 window->State.Visible = GL_TRUE;
1026 break;
1027
1028 case VisibilityFullyObscured:
1029 INVOKE_WCB( *window, WindowStatus, ( GLUT_FULLY_COVERED ) );
1030 window->State.Visible = GL_FALSE;
1031 break;
1032
1033 default:
1034 fgWarning( "Unknown X visibility state: %d",
1035 event.xvisibility.state );
1036 break;
1037 }
1038 }
1039 break;
1040
1041 case EnterNotify:
1042 case LeaveNotify:
1043 GETWINDOW( xcrossing );
1044 GETMOUSE( xcrossing );
1045 if( ( event.type == LeaveNotify ) && window->IsMenu &&
1046 window->ActiveMenu && window->ActiveMenu->IsActive )
1047 fgUpdateMenuHighlight( window->ActiveMenu );
1048
1049 INVOKE_WCB( *window, Entry, ( ( EnterNotify == event.type ) ?
1050 GLUT_ENTERED :
1051 GLUT_LEFT ) );
1052 break;
1053
1054 case MotionNotify:
1055 {
1056 /* if GLUT_SKIP_STALE_MOTION_EVENTS is true, then discard all but
1057 * the last motion event from the queue
1058 */
1059 if(fgState.SkipStaleMotion) {
1060 while(XCheckIfEvent(fgDisplay.pDisplay.Display, &event, match_motion, 0));
1061 }
1062
1063 GETWINDOW( xmotion );
1064 GETMOUSE( xmotion );
1065
1066 if( window->ActiveMenu )
1067 {
1068 if( window == window->ActiveMenu->ParentWindow )
1069 {
1070 window->ActiveMenu->Window->State.MouseX =
1071 event.xmotion.x_root - window->ActiveMenu->X;
1072 window->ActiveMenu->Window->State.MouseY =
1073 event.xmotion.y_root - window->ActiveMenu->Y;
1074 }
1075
1076 fgUpdateMenuHighlight( window->ActiveMenu );
1077
1078 break;
1079 }
1080
1081 /*
1082 * XXX For more than 5 buttons, just check {event.xmotion.state},
1083 * XXX rather than a host of bit-masks? Or maybe we need to
1084 * XXX track ButtonPress/ButtonRelease events in our own
1085 * XXX bit-mask?
1086 */
1087 fgState.Modifiers = fgPlatformGetModifiers( event.xmotion.state );
1088 if ( event.xmotion.state & ( Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask ) ) {
1089 INVOKE_WCB( *window, Motion, ( event.xmotion.x,
1090 event.xmotion.y ) );
1091 } else {
1092 INVOKE_WCB( *window, Passive, ( event.xmotion.x,
1093 event.xmotion.y ) );
1094 }
1095 fgState.Modifiers = INVALID_MODIFIERS;
1096 }
1097 break;
1098
1099 case ButtonRelease:
1100 case ButtonPress:
1101 {
1102 GLboolean pressed = GL_TRUE;
1103 int button;
1104
1105 if( event.type == ButtonRelease )
1106 pressed = GL_FALSE ;
1107
1108 /*
1109 * A mouse button has been pressed or released. Traditionally,
1110 * break if the window was found within the freeglut structures.
1111 */
1112 GETWINDOW( xbutton );
1113 GETMOUSE( xbutton );
1114
1115 /*
1116 * An X button (at least in XFree86) is numbered from 1.
1117 * A GLUT button is numbered from 0.
1118 * Old GLUT passed through buttons other than just the first
1119 * three, though it only gave symbolic names and official
1120 * support to the first three.
1121 */
1122 button = event.xbutton.button - 1;
1123
1124 /*
1125 * Do not execute the application's mouse callback if a menu
1126 * is hooked to this button. In that case an appropriate
1127 * private call should be generated.
1128 */
1129 if( fgCheckActiveMenu( window, button, pressed,
1130 event.xbutton.x, event.xbutton.y ) )
1131 break;
1132
1133 /*
1134 * Check if there is a mouse or mouse wheel callback hooked to the
1135 * window
1136 */
1137 if( ! FETCH_WCB( *window, Mouse ) &&
1138 ! FETCH_WCB( *window, MouseWheel ) )
1139 break;
1140
1141 fgState.Modifiers = fgPlatformGetModifiers( event.xbutton.state );
1142
1143 /* Finally execute the mouse or mouse wheel callback */
1144 if( ( button < glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS ) ) || ( ! FETCH_WCB( *window, MouseWheel ) ) )
1145 INVOKE_WCB( *window, Mouse, ( button,
1146 pressed ? GLUT_DOWN : GLUT_UP,
1147 event.xbutton.x,
1148 event.xbutton.y )
1149 );
1150 else
1151 {
1152 /*
1153 * Map 4 and 5 to wheel zero; EVEN to +1, ODD to -1
1154 * " 6 and 7 " " one; ...
1155 *
1156 * XXX This *should* be behind some variables/macros,
1157 * XXX since the order and numbering isn't certain
1158 * XXX See XFree86 configuration docs (even back in the
1159 * XXX 3.x days, and especially with 4.x).
1160 *
1161 * XXX Note that {button} has already been decremented
1162 * XXX in mapping from X button numbering to GLUT.
1163 *
1164 * XXX Should add support for partial wheel turns as Windows does -- 5/27/11
1165 */
1166 int wheel_number = (button - glutDeviceGet ( GLUT_NUM_MOUSE_BUTTONS )) / 2;
1167 int direction = -1;
1168 if( button % 2 )
1169 direction = 1;
1170
1171 if( pressed )
1172 INVOKE_WCB( *window, MouseWheel, ( wheel_number,
1173 direction,
1174 event.xbutton.x,
1175 event.xbutton.y )
1176 );
1177 }
1178 fgState.Modifiers = INVALID_MODIFIERS;
1179 }
1180 break;
1181
1182 case KeyRelease:
1183 case KeyPress:
1184 {
1185 FGCBKeyboardExt keyboard_ext_cb;
1186 FGCBKeyboard keyboard_cb, keyboard_low_cb;
1187 FGCBSpecial special_cb;
1188 int did_keyboard_cb = 0;
1189
1190 GETWINDOW( xkey );
1191 GETMOUSE( xkey );
1192
1193 /* Detect auto repeated keys, if configured globally or per-window */
1194
1195 if ( fgState.KeyRepeat==GLUT_KEY_REPEAT_OFF || window->State.IgnoreKeyRepeat==GL_TRUE )
1196 {
1197 if (event.type==KeyRelease)
1198 {
1199 /*
1200 * Look at X11 keystate to detect repeat mode.
1201 * While X11 says the key is actually held down, we'll ignore KeyRelease/KeyPress pairs.
1202 */
1203
1204 char keys[32];
1205 XQueryKeymap( fgDisplay.pDisplay.Display, keys ); /* Look at X11 keystate to detect repeat mode */
1206
1207 if ( event.xkey.keycode<256 ) /* XQueryKeymap is limited to 256 keycodes */
1208 {
1209 if ( keys[event.xkey.keycode>>3] & (1<<(event.xkey.keycode%8)) )
1210 window->State.pWState.KeyRepeating = GL_TRUE;
1211 else
1212 window->State.pWState.KeyRepeating = GL_FALSE;
1213 }
1214 }
1215 }
1216 else
1217 window->State.pWState.KeyRepeating = GL_FALSE;
1218
1219 /* Cease processing this event if it is auto repeated */
1220
1221 if (window->State.pWState.KeyRepeating)
1222 {
1223 if (event.type == KeyPress) window->State.pWState.KeyRepeating = GL_FALSE;
1224 break;
1225 }
1226
1227 if( event.type == KeyPress )
1228 {
1229 keyboard_ext_cb = (FGCBKeyboardExt)( FETCH_WCB( *window, KeyboardExt ));
1230 keyboard_low_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardDown ));
1231 keyboard_cb = (FGCBKeyboard)( FETCH_WCB( *window, Keyboard ));
1232 special_cb = (FGCBSpecial) ( FETCH_WCB( *window, Special ));
1233 }
1234 else
1235 {
1236 keyboard_ext_cb = NULL;
1237 keyboard_low_cb = (FGCBKeyboard)( FETCH_WCB( *window, KeyboardUp ));
1238 keyboard_cb = NULL;
1239 special_cb = (FGCBSpecial) ( FETCH_WCB( *window, SpecialUp ));
1240 }
1241
1242 /* Is there a character keyboard callback hooked for this window? */
1243 if (keyboard_ext_cb || keyboard_cb)
1244 {
1245 static XComposeStatus composeStatus = { 0 }; /* keep state across invocations */
1246 XIC ic = window->Window.pContext.IC;
1247 Status status;
1248 char buf[32], *utf8 = buf;
1249 KeySym keySym;
1250 int i, c, len;
1251
1252 /* Check for the Unicode text associated with the event: */
1253 if (ic)
1254 {
1255 len = Xutf8LookupString(ic, &event.xkey, buf, sizeof buf, &keySym, &status);
1256 if (status == XBufferOverflow)
1257 {
1258 utf8 = malloc(len);
1259 len = Xutf8LookupString(ic, &event.xkey, utf8, len, &keySym, &status);
1260 }
1261 }
1262 else
1263 {
1264 len = XLookupString(&event.xkey, buf, sizeof buf, &keySym, &composeStatus);
1265 }
1266
1267 if (len > 0)
1268 {
1269 fgSetWindow(window);
1270 fgState.Modifiers = fgPlatformGetModifiers(event.xkey.state);
1271
1272 i = 0;
1273 while (i < len)
1274 {
1275 i += chartorune(&c, utf8 + i);
1276
1277 /* ...for the Unicode translateable keypresses... */
1278 if (keyboard_ext_cb)
1279 keyboard_ext_cb(c, event.xkey.x, event.xkey.y);
1280
1281 /* ...for the Latin-1 translateable keypresses... */
1282 if (keyboard_cb)
1283 if (c < 256)
1284 keyboard_cb(c, event.xkey.x, event.xkey.y);
1285 }
1286
1287 fgState.Modifiers = INVALID_MODIFIERS;
1288
1289 did_keyboard_cb = 1;
1290 }
1291
1292 if (utf8 != buf)
1293 free(utf8);
1294 }
1295
1296 /* Is there a low-level keyboard callback hooked for this window? */
1297 if (keyboard_low_cb || special_cb)
1298 {
1299 int special = -1;
1300 int ascii = 0;
1301
1302 KeySym keySym = XLookupKeysym(&event.xkey, 0);
1303
1304 /* ...for low-level keys, which need to be
1305 * translated to GLUT_KEY_Xs or ASCII values...
1306 */
1307 switch( keySym )
1308 {
1309 case XK_F1: special = GLUT_KEY_F1; break;
1310 case XK_F2: special = GLUT_KEY_F2; break;
1311 case XK_F3: special = GLUT_KEY_F3; break;
1312 case XK_F4: special = GLUT_KEY_F4; break;
1313 case XK_F5: special = GLUT_KEY_F5; break;
1314 case XK_F6: special = GLUT_KEY_F6; break;
1315 case XK_F7: special = GLUT_KEY_F7; break;
1316 case XK_F8: special = GLUT_KEY_F8; break;
1317 case XK_F9: special = GLUT_KEY_F9; break;
1318 case XK_F10: special = GLUT_KEY_F10; break;
1319 case XK_F11: special = GLUT_KEY_F11; break;
1320 case XK_F12: special = GLUT_KEY_F12; break;
1321
1322 case XK_KP_Left:
1323 case XK_Left: special = GLUT_KEY_LEFT; break;
1324 case XK_KP_Right:
1325 case XK_Right: special = GLUT_KEY_RIGHT; break;
1326 case XK_KP_Up:
1327 case XK_Up: special = GLUT_KEY_UP; break;
1328 case XK_KP_Down:
1329 case XK_Down: special = GLUT_KEY_DOWN; break;
1330
1331 case XK_KP_Prior:
1332 case XK_Prior: special = GLUT_KEY_PAGE_UP; break;
1333 case XK_KP_Next:
1334 case XK_Next: special = GLUT_KEY_PAGE_DOWN; break;
1335 case XK_KP_Home:
1336 case XK_Home: special = GLUT_KEY_HOME; break;
1337 case XK_KP_End:
1338 case XK_End: special = GLUT_KEY_END; break;
1339 case XK_KP_Insert:
1340 case XK_Insert: special = GLUT_KEY_INSERT; break;
1341
1342 case XK_Num_Lock : special = GLUT_KEY_NUM_LOCK; break;
1343 case XK_KP_Begin : special = GLUT_KEY_BEGIN; break;
1344 case XK_KP_Delete: special = GLUT_KEY_DELETE; break;
1345
1346 case XK_Shift_L: special = GLUT_KEY_SHIFT_L; break;
1347 case XK_Shift_R: special = GLUT_KEY_SHIFT_R; break;
1348 case XK_Control_L: special = GLUT_KEY_CTRL_L; break;
1349 case XK_Control_R: special = GLUT_KEY_CTRL_R; break;
1350 case XK_Alt_L: special = GLUT_KEY_ALT_L; break;
1351 case XK_Alt_R: special = GLUT_KEY_ALT_R; break;
1352 default:
1353 if( keySym >= XK_space && keySym <= XK_ydiaeresis )
1354 ascii = keySym;
1355 break;
1356 }
1357
1358 /*
1359 * Execute the callback (if one has been specified),
1360 * given that the special code seems to be valid...
1361 * But only if we haven't already sent translated text for it,
1362 * such as numeric keypad keys with numlock on.
1363 */
1364 if( special_cb && (special != -1) && !did_keyboard_cb )
1365 {
1366 fgSetWindow( window );
1367 fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state );
1368 special_cb( special, event.xkey.x, event.xkey.y );
1369 fgState.Modifiers = INVALID_MODIFIERS;
1370 }
1371 else if( keyboard_low_cb && (ascii >= 32 && ascii < 256) )
1372 {
1373 fgSetWindow( window );
1374 fgState.Modifiers = fgPlatformGetModifiers( event.xkey.state );
1375 keyboard_low_cb( ascii, event.xkey.x, event.xkey.y );
1376 fgState.Modifiers = INVALID_MODIFIERS;
1377 }
1378 }
1379 }
1380 break;
1381
1382 case ReparentNotify:
1383 break; /* XXX Should disable this event */
1384
1385 /* Not handled */
1386 case GravityNotify:
1387 break;
1388
1389 default:
1390 /* enter handling of Extension Events here */
1391 #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H
1392 fgHandleExtensionEvents( &event );
1393 #endif
1394 break;
1395 }
1396 }
1397 }
1398
1399
1400 static Bool match_motion(Display *dpy, XEvent *xev, XPointer arg)
1401 {
1402 return xev->type == MotionNotify;
1403 }
1404
1405 void fgPlatformMainLoopPreliminaryWork ( void )
1406 {
1407 }
1408
1409
1410 /* deal with work list items */
1411 void fgPlatformInitWork(SFG_Window* window)
1412 {
1413 /* Notify windowStatus/visibility, position and size get notified on window creation with message handlers above
1414 * XXX CHECK: do the messages happen too early like on windows, so client code cannot have registered
1415 * a callback yet and the message is thus never received by client?
1416 * -> this is a no-op
1417 */
1418 return;
1419 }
1420
1421 void fgPlatformPosResZordWork(SFG_Window* window, unsigned int workMask)
1422 {
1423 if (workMask & GLUT_FULL_SCREEN_WORK)
1424 fgPlatformFullScreenToggle( window );
1425 if (workMask & GLUT_POSITION_WORK)
1426 fgPlatformPositionWindow( window, window->State.DesiredXpos, window->State.DesiredYpos );
1427 if (workMask & GLUT_SIZE_WORK)
1428 fgPlatformReshapeWindow ( window, window->State.DesiredWidth, window->State.DesiredHeight );
1429 if (workMask & GLUT_ZORDER_WORK)
1430 {
1431 if (window->State.DesiredZOrder < 0)
1432 fgPlatformPushWindow( window );
1433 else
1434 fgPlatformPopWindow( window );
1435 }
1436 }
1437
1438 void fgPlatformVisibilityWork(SFG_Window* window)
1439 {
1440 /* Visibility status of window gets updated in the window message handlers above
1441 * XXX: is this really the case? check
1442 */
1443 SFG_Window *win = window;
1444 switch (window->State.DesiredVisibility)
1445 {
1446 case DesireHiddenState:
1447 fgPlatformHideWindow( window );
1448 break;
1449 case DesireIconicState:
1450 /* Call on top-level window */
1451 while (win->Parent)
1452 win = win->Parent;
1453 fgPlatformIconifyWindow( win );
1454 break;
1455 case DesireNormalState:
1456 fgPlatformShowWindow( window );
1457 break;
1458 }
1459 }
1460