1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4
5 #if defined(__MSW__)
6 # include <windows.h>
7 #else
8 # include <X11/X.h>
9 # include <X11/Xlib.h>
10 # include <X11/Xutil.h>
11 # include <X11/keysym.h>
12 # include <X11/Xproto.h>
13 # include <X11/Xatom.h>
14 # include <X11/cursorfont.h>
15 # include <X11/extensions/shape.h>
16 # ifdef HAVE_XF86_VIDMODE
17 # include <X11/extensions/xf86vmode.h>
18 # ifndef XF86VIDMODE_H
19 # define XF86VIDMODE_H
20 # endif
21 # ifndef XF86VIDMODE_EVENTS
22 # define XF86VIDMODE_EVENTS
23 # endif
24 # endif /* HAVE_XF86_VIDMODE */
25 # ifdef HAVE_LIBXPM
26 # include <X11/xpm.h>
27 # ifndef XPM_H
28 # define XPM_H
29 # endif
30 # ifndef XpmDefaultColorCloseness
31 # define XpmDefaultColorCloseness 40000
32 # endif
33 # endif /* HAVE_LIBXPM */
34 #endif
35
36 #include <GL/gl.h>
37 #include <GL/glu.h>
38
39 #include "gw.h"
40 #include "stategl.h"
41
42 #include "gwdata/default.fnt"
43
44
45 #ifdef X_H
46 static int GWXErrorHandler(Display *xdpy, XErrorEvent *xerrorevent);
47 int GWGetCharacterFromKeyCode(gw_display_struct *dpy, KeyCode keycode);
48 Window GWGetParent(gw_display_struct *dpy, Window w);
49
50 /*
51 static void GWGrabPointerCursor(
52 gw_display_struct *display, Window w, Boolean confine,
53 Cursor cursor
54 );
55 */
56
57 static void GWGrabPointer(
58 gw_display_struct *display, Window w, Boolean confine
59 );
60 static void GWUngrabPointer(gw_display_struct *display);
61
62 void GWSetWindowIconFile(
63 gw_display_struct *display, int ctx_num,
64 const char *icon_path, const char *icon_name
65 );
66 Window GWCreateWindow(
67 gw_display_struct *display,
68 Window parent,
69 int x, int y,
70 int width, int height,
71 const char *title
72 );
73 #endif /* X_H */
74
75 #ifdef X_H
76 /* GW init/management/shutdown */
77 gw_display_struct *GWInit(int argc, char **argv);
78 void GWManage(gw_display_struct *display);
79 void GWShutdown(gw_display_struct *display);
80 #endif /* X_H */
81
82 #ifdef X_H
83 /* GW sync */
84 void GWFlush(gw_display_struct *display);
85 void GWSync(gw_display_struct *display);
86 int GWEventsPending(gw_display_struct *display);
87 #endif
88
89 /* GW dialog message and response */
90 void GWOutputMessage(
91 gw_display_struct *display,
92 int type,
93 const char *subject,
94 const char *message,
95 const char *help_details
96 );
97 int GWConfirmation(
98 gw_display_struct *display,
99 int type,
100 const char *subject,
101 const char *message,
102 const char *help_details,
103 int default_response
104 );
105 int GWConfirmationSimple(
106 gw_display_struct *display, const char *message
107 );
108
109 /* GW callback setting */
110 void GWSetDrawCB(
111 gw_display_struct *display,
112 void (*func)(int, void *),
113 void *data
114 );
115 void GWSetResizeCB(
116 gw_display_struct *display,
117 void (*func)(int, void *, int, int, int, int),
118 void *data
119 );
120 void GWSetKeyboardCB(
121 gw_display_struct *display,
122 void (*func)(void *, int, Boolean, unsigned long),
123 void *data
124 );
125 void GWSetPointerCB(
126 gw_display_struct *display,
127 void (*func)(int, void *, int, int, gw_event_type, int, unsigned long),
128 void *data
129 );
130 void GWSetVisibilityCB(
131 gw_display_struct *display,
132 void (*func)(int, void *, gw_visibility),
133 void *data
134 );
135 void GWSetSaveYourselfCB(
136 gw_display_struct *display,
137 void (*func)(int, void *),
138 void *data
139 );
140 void GWSetCloseCB(
141 gw_display_struct *display,
142 void (*func)(int, void *, void *),
143 void *data
144 );
145 void GWSetTimeoutCB(
146 gw_display_struct *display,
147 void (*func)(void *),
148 void *data
149 );
150
151 /* GW context */
152 #ifdef X_H
153 int GWContextNew(
154 gw_display_struct *display,
155 int x, int y, int width, int height,
156 const char *title,
157 const char *icon_path, const char *icon_name,
158 Bool no_windows
159 );
160 void GWContextDelete(
161 gw_display_struct *display, int ctx_num
162 );
163 int GWContextCurrent(gw_display_struct *display);
164 int GWContextGet(
165 gw_display_struct *display, int ctx_num,
166 void **window_id_rtn, void **gl_context_rtn,
167 int *x_rtn, int *y_rtn, int *width_rtn, int *height_rtn
168 );
169 int GWContextSet(gw_display_struct *display, int ctx_num);
170 void GWContextPosition(
171 gw_display_struct *display, int x, int y
172 );
173 void GWContextSize(
174 gw_display_struct *display, int width, int height
175 );
176 Boolean GWContextIsFullScreen(gw_display_struct *display);
177 int GWContextFullScreen(gw_display_struct *display, Boolean state);
178 #endif /* X_H */
179
180 /* Frame buffer */
181 #ifdef X_H
182 void GWPostRedraw(gw_display_struct *display);
183 void GWSwapBuffer(gw_display_struct *display);
184 #endif /* X_H */
185
186 /* Set up gl projection matrix for 2d drawing */
187 void GWOrtho2D(gw_display_struct *display);
188 void GWOrtho2DCoord(
189 gw_display_struct *display,
190 float left, float right, float top, float bottom
191 );
192
193 /* Keyboard */
194 #ifdef X_H
195 void GWKeyboardAutoRepeat(gw_display_struct *display, Boolean b);
196 #endif /* X_H */
197
198 /* Video modes */
199 #ifdef X_H
200 gw_vidmode_struct *GWVidModesGet(
201 gw_display_struct *display, int *n
202 );
203 #endif /* X_H */
204 void GWVidModesFree(gw_vidmode_struct *vidmode, int n);
205
206 /* Accelerator keys */
207 gw_accelerator_struct *GWAcceleratorNew(
208 int key, int modifier
209 );
210 void GWAcceleratorDelete(gw_accelerator_struct *a);
211 int GWAcceleratorListAdd(
212 gw_accelerator_struct ***a, int *total,
213 int key, int modifier
214 );
215 void GWAcceleratorListDelete(
216 gw_accelerator_struct ***a, int *total
217 );
218 Boolean GWAcceleratorListCheck(
219 gw_accelerator_struct **a, int total,
220 int key, int modifier
221 );
222
223 /* GW pointer cursor */
224 #ifdef X_H
225 void *GWCursorNew(
226 gw_display_struct *display,
227 int width, int height, /* In pixels */
228 int hot_x, int hot_y, /* In pixels */
229 int bpl, /* Bytes per line, 0 for autocalc */
230 const void *data /* RGBA data (4 bytes per pixel) */
231 );
232 void GWCursorSet(gw_display_struct *display, void *cursor_ptr);
233 void GWCursorDelete(gw_display_struct *display, void *cursor_ptr);
234 void GWSetPointerCursor(
235 gw_display_struct *display, gw_pointer_cursor cursor
236 );
237 void GWShowCursor(gw_display_struct *display);
238 void GWHideCursor(gw_display_struct *display);
239 Boolean GWIsCursorShown(gw_display_struct *display);
240 void GWSetInputBusy(gw_display_struct *display);
241 void GWSetInputReady(gw_display_struct *display);
242 #endif /* X_H */
243
244 /* GW font IO */
245 void GWSetFont(gw_display_struct *display, GWFont *font);
246 int GWGetFontSize(
247 GWFont *font,
248 int *width, int *height,
249 int *character_spacing, int *line_spacing
250 );
251
252 /* GW string drawing */
253 void GWDrawString(
254 gw_display_struct *display,
255 int x, int y,
256 const char *string
257 );
258 void GWDrawCharacter(
259 gw_display_struct *display,
260 int x, int y,
261 char c
262 );
263
264 /* GW image IO */
265 int GWImageLoadHeaderFromData(
266 gw_display_struct *display,
267 int *width, int *height, int *bpl, int *bpp,
268 const void *data
269 );
270 u_int8_t *GWImageLoadFromDataRGB(
271 gw_display_struct *display,
272 int *width, int *height, int *bpl,
273 const void *data
274 );
275 const u_int8_t *GWImageLoadFromDataSharedRGB(
276 gw_display_struct *display,
277 int *width, int *height, int *bpl,
278 const void *data
279 );
280 u_int8_t *GWImageLoadFromDataRGBA(
281 gw_display_struct *display,
282 int *width, int *height, int *bpl,
283 const void *data
284 );
285 const u_int8_t *GWImageLoadFromDataSharedRGBA(
286 gw_display_struct *display,
287 int *width, int *height, int *bpl,
288 const void *data
289 );
290
291 static void GWImageDrawFromDataNexus(
292 gw_display_struct *display, const u_int8_t *img_data,
293 int x, int y, int width, int height,
294 int img_width, int img_height,
295 GLenum img_format
296 );
297 void GWImageDrawFromDataRGB(
298 gw_display_struct *display, const void *data,
299 int x, int y, int width, int height
300 );
301 void GWImageDrawFromDataRGBA(
302 gw_display_struct *display, const void *data,
303 int x, int y, int width, int height
304 );
305
306
307
308
309 #define ATOI(s) (((s) != NULL) ? atoi(s) : 0)
310 #define ATOL(s) (((s) != NULL) ? atol(s) : 0)
311 #define ATOF(s) (((s) != NULL) ? (float)atof(s) : 0.0f)
312 #define STRDUP(s) (((s) != NULL) ? strdup(s) : NULL)
313
314 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
315 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
316 #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h)))
317 #define STRLEN(s) (((s) != NULL) ? ((int)strlen(s)) : 0)
318 #define STRISEMPTY(s) (((s) != NULL) ? ((s) == '\0') : True)
319
320 #define RADTODEG(r) ((r) * 180 / PI)
321 #define DEGTORAD(d) ((d) * PI / 180)
322
323 #define FREE_PIXMAP(p) \
324 { if(*(p) != None) { XFreePixmap(dpy, *(p)); *(p) = None; } }
325 #define FREE_BITMAP(p) FREE_PIXMAP(p)
326 #define DESTROY_WINDOW(p) \
327 { if(*(p) != None) { XDestroyWindow(dpy, *(p)); *(p) = None; } }
328 #define DELETE_FONT(p) \
329 { GWXFontDelete(display, *(p)); *(p) = NULL; }
330
331 #define DESTROY_TOPLEVEL_WINDOW(p) \
332 { if(*(p) != None) { \
333 /* Get WM hints and destroy icon Window, Pixmap, and \
334 * mask. \
335 */ \
336 XWMHints *wm_hints = XGetWMHints(dpy, *(p)); \
337 if(wm_hints != NULL) { \
338 if(wm_hints->flags & IconWindowHint) \
339 DESTROY_WINDOW(&wm_hints->icon_window); \
340 if(wm_hints->flags & IconPixmapHint) \
341 FREE_PIXMAP(&wm_hints->icon_pixmap); \
342 if(wm_hints->flags & IconMaskHint) \
343 FREE_BITMAP(&wm_hints->icon_mask); \
344 XFree(wm_hints); \
345 } \
346 /* Destroy toplevel Window */ \
347 DESTROY_WINDOW(p); \
348 } }
349
350 #define XCOLOR_SET_RGB_COEFF(p,r,g,b) \
351 { if((p) != NULL) { \
352 (p)->flags = DoRed | DoGreen | DoBlue; \
353 (p)->red = (float)(r) * (unsigned short)-1; \
354 (p)->green = (float)(g) * (unsigned short)-1; \
355 (p)->blue = (float)(b) * (unsigned short)-1; \
356 (p)->pad = 0; \
357 } }
358 #define XCOLOR_SET_GREY_COEFF(p,g) \
359 { if((p) != NULL) { \
360 (p)->flags = DoRed | DoGreen | DoBlue; \
361 (p)->red = (float)(g) * (unsigned short)-1; \
362 (p)->green = (p)->red; \
363 (p)->blue = (p)->red; \
364 (p)->pad = 0; \
365 } }
366
367
368
369 /* Graphics wrapped debugging flag */
370 static Boolean gw_debug = False;
371 /* String prefixed to all GW debugging messages */
372 #define GW_DEBUG_PREFIX "GW Debug: "
373
374
375 #ifdef X_H
376 /*
377 * Modified by GWXErrorHandler() to indicate error or none.
378 *
379 * This will be set to a non-zero value when GWXErrorHandler()
380 * is called, GWXErrorHandler() is called whenever the X server
381 * generates an error.
382 *
383 * If xerrval is not 0 then xerrmsg will contain a string
384 * describing the X error.
385 */
386 static int xerrval;
387 static char xerrmsg[256];
388 #endif /* X_H */
389
390
391 #ifdef X_H
392 /*
393 * Visual attributes list (for picking Visuals), last member must
394 * be None to mark end of array.
395 */
396 static int attributeListSglRGB[] = {
397 GLX_RGBA, /* Use only TrueColor or DirectColor */
398 GLX_RED_SIZE, 1, /* Get deepest buffer with >= 1 red bit */
399 GLX_GREEN_SIZE, 1,
400 GLX_BLUE_SIZE, 1,
401 GLX_DEPTH_SIZE, 1, /* Z buffer depth, not bit depth */
402 GLX_STENCIL_SIZE, 1,
403 None
404 };
405
406 static int attributeListSglRGBA[] = {
407 GLX_RGBA, /* Use only TrueColor or DirectColor */
408 GLX_RED_SIZE, 1, /* Get deepest buffer with >= 1 red bit */
409 GLX_GREEN_SIZE, 1,
410 GLX_BLUE_SIZE, 1,
411 GLX_ALPHA_SIZE, 1,
412 GLX_DEPTH_SIZE, 1,
413 GLX_STENCIL_SIZE, 1,
414 None
415 };
416
417 static int attributeListDblRGB[] = {
418 GLX_RGBA, /* Use only TrueColor or DirectColor */
419 GLX_DOUBLEBUFFER, /* Double buffer */
420 GLX_RED_SIZE, 1,
421 GLX_GREEN_SIZE, 1,
422 GLX_BLUE_SIZE, 1,
423 GLX_DEPTH_SIZE, 1,
424 GLX_STENCIL_SIZE, 1,
425 None
426 };
427
428 static int attributeListDblRGBA[] = {
429 GLX_RGBA, /* Use only TrueColor or DirectColor */
430 GLX_DOUBLEBUFFER, /* Double buffer */
431 GLX_RED_SIZE, 1,
432 GLX_GREEN_SIZE, 1,
433 GLX_BLUE_SIZE, 1,
434 GLX_ALPHA_SIZE, 1,
435 GLX_DEPTH_SIZE, 1,
436 GLX_STENCIL_SIZE, 1,
437 None
438 };
439 #endif /* X_H */
440
441
442 /*
443 * Keysym name to character value table, even numbers are pointers
444 * to strings while odd numbers are pointers who's value is a
445 * character value.
446 */
447 static char *keytable[] = {
448 "Alt_L", (char *)GWKeyAlt,
449 "Alt_R", (char *)GWKeyAlt,
450 "Control_L", (char *)GWKeyCtrl,
451 "Control_R", (char *)GWKeyCtrl,
452 "Shift_L", (char *)GWKeyShift,
453 "Shift_R", (char *)GWKeyShift,
454
455 "BackSpace", (char *)GWKeyBackSpace,
456 "Tab", (char *)'\t',
457 "ISO_Left_Tab", (char *)'\t',
458 "Linefeed", (char *)'\f',
459 "Clear", (char *)'\0',
460 "Return", (char *)'\n',
461 "Pause", (char *)GWKeyPause,
462 "Scroll_Lock", (char *)GWKeyScrollLock,
463 "Sys_Req", (char *)GWKeySysReq,
464 "Escape", (char *)0x1b,
465 "Delete", (char *)GWKeyDelete,
466
467 "Home", (char *)GWKeyHome,
468 "Left", (char *)GWKeyLeft,
469 "Up", (char *)GWKeyUp,
470 "Right", (char *)GWKeyRight,
471 "Down", (char *)GWKeyDown,
472 "Prior", (char *)GWKeyPageUp, /* ??? */
473 "Page_Up", (char *)GWKeyPageUp,
474 "Next", (char *)GWKeyPageDown, /* ??? */
475 "Page_Down", (char *)GWKeyPageDown,
476 "End", (char *)GWKeyEnd,
477 "Begin", (char *)GWKeyHome, /* ??? */
478
479 "KP_0", (char *)'0',
480 "KP_1", (char *)'1',
481 "KP_2", (char *)'2',
482 "KP_3", (char *)'3',
483 "KP_4", (char *)'4',
484 "KP_5", (char *)'5',
485 "KP_6", (char *)'6',
486 "KP_7", (char *)'7',
487 "KP_8", (char *)'8',
488 "KP_9", (char *)'9',
489
490 "KP_Space", (char *)' ',
491 "KP_Tab", (char *)'\t',
492 "KP_Enter", (char *)'\n',
493 "KP_F1", (char *)GWKeyF1,
494 "KP_F2", (char *)GWKeyF2,
495 "KP_F3", (char *)GWKeyF3,
496 "KP_F4", (char *)GWKeyF4,
497 "KP_Home", (char *)GWKeyHome,
498 "KP_Left", (char *)GWKeyLeft,
499 "KP_Up", (char *)GWKeyUp,
500 "KP_Right", (char *)GWKeyRight,
501 "KP_Down", (char *)GWKeyDown,
502 "KP_Prior", (char *)GWKeyPageUp,
503 "KP_Page_Up", (char *)GWKeyPageUp,
504 "KP_Next", (char *)GWKeyPageDown,
505 "KP_Page_Down", (char *)GWKeyPageDown,
506 "KP_End", (char *)GWKeyEnd,
507 "KP_Begin", (char *)GWKeyHome,
508 "KP_Insert", (char *)GWKeyInsert,
509 "KP_Delete", (char *)GWKeyDelete,
510 "KP_Equal", (char *)'=',
511 "KP_Multiply", (char *)'*',
512 "KP_Add", (char *)'+',
513 "KP_Separator", (char *)'\0',
514 "KP_Subtract", (char *)'-',
515 "KP_Decimal", (char *)'.',
516 "KP_Divide", (char *)'/',
517
518 "F1", (char *)GWKeyF1,
519 "F2", (char *)GWKeyF2,
520 "F3", (char *)GWKeyF3,
521 "F4", (char *)GWKeyF4,
522 "F5", (char *)GWKeyF5,
523 "F6", (char *)GWKeyF6,
524 "F7", (char *)GWKeyF7,
525 "F8", (char *)GWKeyF8,
526 "F9", (char *)GWKeyF9,
527 "F10", (char *)GWKeyF10,
528 "F11", (char *)GWKeyF11,
529 "F12", (char *)GWKeyF12,
530 "F13", (char *)GWKeyF13,
531 "F14", (char *)GWKeyF14,
532 "F15", (char *)GWKeyF15,
533 "F16", (char *)GWKeyF16,
534 "F17", (char *)GWKeyF17,
535 "F18", (char *)GWKeyF18,
536 "F19", (char *)GWKeyF19,
537 "F20", (char *)GWKeyF20,
538
539 "space", (char *)' ',
540 "exclam", (char *)'!',
541 "quotedbl", (char *)'"',
542 "numbersign", (char *)'#',
543 "dollar", (char *)'$',
544 "percent", (char *)'%',
545 "ampersand", (char *)'&',
546 "apostrophe", (char *)'\'',
547 "quoteright", (char *)'"',
548 "parenleft", (char *)'(',
549 "parenright", (char *)')',
550 "asterisk", (char *)'*',
551 "plus", (char *)'+',
552 "comma", (char *)',',
553 "minus", (char *)'-',
554 "period", (char *)'.',
555 "slash", (char *)'/',
556
557 "0", (char *)'0',
558 "1", (char *)'1',
559 "2", (char *)'2',
560 "3", (char *)'3',
561 "4", (char *)'4',
562 "5", (char *)'5',
563 "6", (char *)'6',
564 "7", (char *)'7',
565 "8", (char *)'8',
566 "9", (char *)'9',
567
568 "colon", (char *)':',
569 "semicolon", (char *)';',
570 "less", (char *)'\0',
571 "equal", (char *)'=',
572 "greater", (char *)'>',
573 "question", (char *)'?',
574 "at", (char *)'@',
575
576 "A", (char *)'A',
577 "B", (char *)'B',
578 "C", (char *)'C',
579 "D", (char *)'D',
580 "E", (char *)'E',
581 "F", (char *)'F',
582 "G", (char *)'G',
583 "H", (char *)'H',
584 "I", (char *)'I',
585 "J", (char *)'J',
586 "K", (char *)'K',
587 "L", (char *)'L',
588 "M", (char *)'M',
589 "N", (char *)'N',
590 "O", (char *)'O',
591 "P", (char *)'P',
592 "Q", (char *)'Q',
593 "R", (char *)'R',
594 "S", (char *)'S',
595 "T", (char *)'T',
596 "U", (char *)'U',
597 "V", (char *)'V',
598 "W", (char *)'W',
599 "X", (char *)'X',
600 "Y", (char *)'Y',
601 "Z", (char *)'Z',
602
603 "bracketleft", (char *)'[',
604 "backslash", (char *)'\\',
605 "bracketright", (char *)']',
606 "asciicircum", (char *)'^',
607 "underscore", (char *)'_',
608 "grave", (char *)'\0',
609 "quoteleft", (char *)'"',
610
611 "a", (char *)'a',
612 "b", (char *)'b',
613 "c", (char *)'c',
614 "d", (char *)'d',
615 "e", (char *)'e',
616 "f", (char *)'f',
617 "g", (char *)'g',
618 "h", (char *)'h',
619 "i", (char *)'i',
620 "j", (char *)'j',
621 "k", (char *)'k',
622 "l", (char *)'l',
623 "m", (char *)'m',
624 "n", (char *)'n',
625 "o", (char *)'o',
626 "p", (char *)'p',
627 "q", (char *)'q',
628 "r", (char *)'r',
629 "s", (char *)'s',
630 "t", (char *)'t',
631 "u", (char *)'u',
632 "v", (char *)'v',
633 "w", (char *)'w',
634 "x", (char *)'x',
635 "y", (char *)'y',
636 "z", (char *)'z',
637
638 "braceleft", (char *)'{',
639 "bar", (char *)'|',
640 "braceright", (char *)'}',
641 "asciitilde", (char *)'~'
642
643 };
644
645
646 #ifdef X_H
647 /*
648 * X error handler:
649 */
GWXErrorHandler(Display * dpy,XErrorEvent * ev)650 static int GWXErrorHandler(Display *dpy, XErrorEvent *ev)
651 {
652 const char *error_code_name;
653
654
655 if((dpy == NULL) || (ev == NULL))
656 return(0);
657
658 /* Reset global xerror value */
659 xerrval = 0;
660 *xerrmsg = '\0';
661
662 /* ******************************************************* */
663 /* Ignore these error codes */
664
665 /* Success */
666 if(ev->error_code == Success)
667 return(0);
668
669 /* Calls to XGetImage() often return error when the error is
670 * non-critical, we need to ignore that here.
671 */
672 if(ev->request_code == X_GetImage)
673 return(0);
674
675 /* ******************************************************** */
676 /* If this point is reached, it means we got a definate
677 * (serious) error from the X server.
678 */
679
680 /* Set global xerrval to -1, indicating a serious error */
681 xerrval = -1;
682
683 switch(ev->error_code)
684 {
685 case Success:
686 error_code_name = "Success";
687 break;
688 case BadRequest:
689 error_code_name = "BadRequest";
690 break;
691 case BadValue:
692 error_code_name = "BadValue";
693 break;
694 case BadWindow:
695 error_code_name = "BadWindow";
696 break;
697 case BadPixmap:
698 error_code_name = "BadPixmap";
699 break;
700 case BadAtom:
701 error_code_name = "BadAtom";
702 break;
703 case BadCursor:
704 error_code_name = "BadCursor";
705 break;
706 case BadFont:
707 error_code_name = "BadFont";
708 break;
709 case BadMatch:
710 error_code_name = "BadMatch";
711 break;
712 case BadDrawable:
713 error_code_name = "BadDrawable";
714 break;
715 case BadAccess:
716 error_code_name = "BadAccess";
717 break;
718 case BadAlloc:
719 error_code_name = "BadAlloc";
720 break;
721 case BadColor:
722 error_code_name = "BadColor";
723 break;
724 case BadGC:
725 error_code_name = "BadGC";
726 break;
727 case BadIDChoice:
728 error_code_name = "BadIDChoice";
729 break;
730 case BadName:
731 error_code_name = "BadName";
732 break;
733 case BadLength:
734 error_code_name = "BadLength";
735 break;
736 case BadImplementation:
737 error_code_name = "BadImplementation";
738 break;
739 default:
740 error_code_name = "Unknown";
741 break;
742 }
743
744 /* Set X error message */
745 sprintf(
746 xerrmsg,
747 "X Server error #%ld: type: %s major_op_code: %i minor_op_code: %i",
748 ev->serial,
749 error_code_name,
750 ev->request_code,
751 ev->minor_code
752 );
753
754 /* Print this error to stderr */
755 fprintf(stderr, "%s\n", xerrmsg);
756
757 return(0);
758 }
759 #endif /* X_H */
760
761 #ifdef X_H
762 /*
763 * Returns the character or key value for the given keycode
764 * looked up on the keytable.
765 */
GWGetCharacterFromKeyCode(gw_display_struct * dpy,KeyCode keycode)766 int GWGetCharacterFromKeyCode(gw_display_struct *dpy, KeyCode keycode)
767 {
768 int i;
769 const int total = sizeof(keytable) / sizeof(char *);
770 KeySym keysym;
771 const char *cstrptr;
772
773 if(dpy == NULL)
774 return((int)'\0');
775
776 if(dpy->display == NULL)
777 return((int)'\0');
778
779 xerrval = 0;
780 keysym = XKeycodeToKeysym(
781 dpy->display,
782 keycode,
783 /* (int)((dpy->shift_key_state) ? 1 : 0) */
784 0
785 );
786 if(xerrval)
787 return((int)'\0');
788
789 xerrval = 0;
790 if((keysym != XK_Shift_R) && (keysym != XK_Shift_L) &&
791 dpy->shift_key_state
792 )
793 {
794 keysym = XKeycodeToKeysym(
795 dpy->display,
796 keycode,
797 1
798 );
799 if(xerrval)
800 return((int)'\0');
801 }
802
803 xerrval = 0;
804 cstrptr = XKeysymToString(keysym);
805 if(xerrval || (cstrptr == NULL))
806 return((int)'\0');
807
808 for(i = 0; i < total; i += 2)
809 {
810 if(!strcmp(keytable[i], cstrptr))
811 return((int)(keytable[i + 1]));
812 }
813
814 return('\0');
815 }
816 #endif /* X_H */
817
818 #ifdef X_H
819 /*
820 * Returns the Window's parent;
821 *
822 * Can return None if w is the root window or an error occured.
823 */
GWGetParent(gw_display_struct * dpy,Window w)824 Window GWGetParent(gw_display_struct *dpy, Window w)
825 {
826 Window root, parent, *children = NULL;
827 unsigned int total_children = 0;
828
829 if((w == None) || (w == dpy->root))
830 return(None);
831
832 xerrval = 0;
833 if(XQueryTree(
834 dpy->display, w, &root, &parent, &children, &total_children
835 ))
836 XFree(children);
837 else
838 parent = None;
839 if(xerrval && gw_debug)
840 printf(GW_DEBUG_PREFIX
841 "XQueryTree(): Unable to get parent or children for Window 0x%.8x.\n",
842 (u_int32_t)w
843 );
844
845 return(parent);
846 }
847 #endif /* X_H */
848
849 #ifdef X_H
850 /*
851 * Grabs pointer.
852 * This function is not used. Commenting it out.
853 * - Jesse
854 static void GWGrabPointerCursor(
855 gw_display_struct *display, Window w, Boolean confine,
856 Cursor cursor
857 )
858 {
859 Display *dpy;
860
861 if(w == None)
862 GWUngrabPointer(display);
863
864 if(display == NULL)
865 return;
866
867 dpy = display->display;
868 if(dpy == NULL)
869 return;
870
871 GWUngrabPointer(display);
872
873 xerrval = 0;
874 if(XGrabPointer(
875 dpy, w, True,
876 ButtonPressMask | ButtonReleaseMask |
877 PointerMotionMask,
878 GrabModeAsync, GrabModeAsync,
879 confine ? w : None, cursor, CurrentTime
880 ) == GrabSuccess)
881 display->grab_window = w;
882 else
883 display->grab_window = None;
884 if(xerrval && gw_debug)
885 printf(GW_DEBUG_PREFIX
886 "XGrabPointer(): Error grabbing pointer for Window 0x%.8x.\n",
887 (u_int32_t)w
888 );
889 }
890 */
891
892 #endif /* X_H */
893
894 #ifdef X_H
895 /*
896 * Grabs pointer.
897 */
GWGrabPointer(gw_display_struct * display,Window w,Boolean confine)898 static void GWGrabPointer(
899 gw_display_struct *display, Window w, Boolean confine
900 )
901 {
902 Display *dpy;
903
904 if(w == None)
905 GWUngrabPointer(display);
906
907 if(display == NULL)
908 return;
909
910 dpy = display->display;
911 if(dpy == NULL)
912 return;
913
914 // Ungrab pointer first as needed
915 GWUngrabPointer(display);
916
917 // Grab pointer
918 xerrval = 0;
919 if(XGrabPointer(
920 dpy, w, True,
921 ButtonPressMask | ButtonReleaseMask |
922 PointerMotionMask,
923 GrabModeAsync, GrabModeAsync,
924 confine ? w : None, None, CurrentTime
925 ) == GrabSuccess)
926 display->grab_window = w;
927 else
928 display->grab_window = None;
929 if(xerrval && gw_debug)
930 printf(GW_DEBUG_PREFIX
931 "XGrabPointer(): Error grabbing pointer for Window 0x%.8x.\n",
932 (u_int32_t)w
933 );
934 }
935 #endif /* X_H */
936
937 #ifdef X_H
938 /*
939 * Ungrabs pointer.
940 */
GWUngrabPointer(gw_display_struct * display)941 static void GWUngrabPointer(gw_display_struct *display)
942 {
943 if(display == NULL)
944 return;
945
946 if(display->grab_window != None)
947 {
948 xerrval = 0;
949 XUngrabPointer(display->display, CurrentTime);
950 if(xerrval && gw_debug)
951 printf(GW_DEBUG_PREFIX
952 "XUngrabPointer(): Error ungrabbing pointer for Window 0x%.8x.\n",
953 (u_int32_t)display->grab_window
954 );
955 display->grab_window = None;
956 }
957 }
958 #endif /* X_H */
959
960
961 #ifdef X_H
962 /*
963 * Sets the WM icon for the given toplevel Window in display.
964 *
965 * The path to the icon data icon_path needs to be an xpm file.
966 *
967 * The icon_name will be set as the icon's icon name which appears
968 * next to the icon (or however the WM has it displayed).
969 */
GWSetWindowIconFile(gw_display_struct * display,int ctx_num,const char * icon_path,const char * icon_name)970 void GWSetWindowIconFile(
971 gw_display_struct *display, int ctx_num,
972 const char *icon_path, const char *icon_name
973 )
974 {
975 #ifdef XPM_H
976 int depth;
977 Display *dpy = (display != NULL) ? display->display : NULL;
978 char *tmp_filename;
979 Window w, root, icon_w = None;
980 Pixmap icon_pm, icon_mask;
981 int xpm_status;
982 XpmAttributes xpm_attr;
983 XWMHints *wm_hints;
984 if((dpy == NULL) || STRISEMPTY(icon_path))
985 return;
986
987 if((ctx_num < 0) || (ctx_num >= display->total_gl_contexts))
988 return;
989
990 w = display->toplevel[ctx_num];
991 root = display->root;
992 depth = display->depth;
993 if((w == None) || (root == None) || (depth < 1))
994 return;
995
996 /* Set up XPM attributes for XPM loading */
997 xpm_attr.valuemask = XpmSize | XpmCloseness | XpmDepth;
998 xpm_attr.closeness = XpmDefaultColorCloseness;
999 xpm_attr.depth = depth;
1000 xpm_attr.width = 0; /* Reset size returns */
1001 xpm_attr.height = 0;
1002 tmp_filename = STRDUP(icon_path);
1003 xpm_status = XpmReadFileToPixmap(
1004 dpy, root, tmp_filename,
1005 &icon_pm, &icon_mask,
1006 &xpm_attr
1007 );
1008 free(tmp_filename);
1009 if(xpm_status == XpmSuccess)
1010 {
1011 int count;
1012 int width = xpm_attr.width;
1013 int height = xpm_attr.height;
1014 Pixel black_pix = display->black_pix;
1015 Pixel white_pix = display->white_pix;
1016 XIconSize *icon_sizes;
1017
1018 /* Check if the loaded icon has is a valid size by
1019 * confirming the size with the X server
1020 */
1021 xerrval = 0;
1022 if(XGetIconSizes(dpy, w, &icon_sizes, &count))
1023 {
1024 int i;
1025
1026 /* Iterate through X server's prefered icon sizees */
1027 for(i = 0; i < count; i++)
1028 {
1029 /* Icon size falls in bounds with this X server
1030 * prefered size?
1031 */
1032 if((width >= icon_sizes[i].min_width) &&
1033 (width <= icon_sizes[i].max_width) &&
1034 (height >= icon_sizes[i].min_height) &&
1035 (height <= icon_sizes[i].max_height)
1036 )
1037 break;
1038 }
1039 XFree(icon_sizes);
1040
1041 /* Did not get valid icon size bounds? */
1042 if(i >= count)
1043 {
1044 fprintf(
1045 stderr,
1046 "GWSetWindowIconFile(): Invalid icon size %ix%i.\n",
1047 width, height
1048 );
1049 /* Delete icon pixmap and mask before returning */
1050 FREE_PIXMAP(&icon_pm);
1051 FREE_BITMAP(&icon_mask);
1052 return;
1053 }
1054 }
1055 if(xerrval && gw_debug)
1056 printf(GW_DEBUG_PREFIX
1057 "XGetIconSizes(): Error obtaining preffered icon sizes for Window 0x%.8x.\n",
1058 (u_int32_t)w
1059 );
1060
1061
1062 /* Create icon window */
1063 xerrval = 0;
1064 icon_w = XCreateSimpleWindow(
1065 dpy, root,
1066 0, 0, /* Coordinates */
1067 width, height, /* Size */
1068 0, /* Border width */
1069 white_pix, /* Border color */
1070 black_pix /* Background color */
1071 );
1072 if(xerrval || (icon_w == None))
1073 {
1074 /* Error creating icon window */
1075
1076 if(gw_debug)
1077 printf(GW_DEBUG_PREFIX
1078 "XCreateSimpleWindow(): Error creating a Window for the icon.\n"
1079 );
1080
1081 /* Delete icon pixmap and mask before returning */
1082 FREE_PIXMAP(&icon_pm);
1083 FREE_BITMAP(&icon_mask);
1084 return;
1085 }
1086 /* If the icon mask is available then mask the newly
1087 * created Window to the shape of the icon mask
1088 */
1089 if(icon_mask != None)
1090 {
1091 xerrval = 0;
1092 XShapeCombineMask(
1093 dpy, icon_w,
1094 ShapeBounding,
1095 0, 0,
1096 icon_mask,
1097 ShapeSet
1098 );
1099 if(xerrval && gw_debug)
1100 printf(GW_DEBUG_PREFIX
1101 "XShapeCombineMask(): Error setting the shape of the icon window 0x%.8x.\n",
1102 (u_int32_t)icon_w
1103 );
1104 }
1105 }
1106 else
1107 {
1108 /* Unable to load the XPM file */
1109 fprintf(stderr, "%s: Unable to load.\n", icon_path);
1110 return;
1111 }
1112
1113 /* Set the Window Manager Hints */
1114 wm_hints = XAllocWMHints();
1115 if(wm_hints != NULL)
1116 {
1117 wm_hints->flags = InputHint | StateHint |
1118 IconPixmapHint | IconWindowHint |
1119 IconMaskHint;
1120 wm_hints->input = True;
1121 wm_hints->initial_state = NormalState;
1122 wm_hints->icon_pixmap = icon_pm;
1123 wm_hints->icon_mask = icon_mask;
1124 wm_hints->icon_window = icon_w;
1125
1126 xerrval = 0;
1127 XSetWMHints(dpy, w, wm_hints);
1128 if(xerrval && gw_debug)
1129 printf(GW_DEBUG_PREFIX
1130 "XSetWMHints(): Error setting icon w=0x%.8x p=0x%.8x m=0x%.8x for window 0x%.8x.\n",
1131 (u_int32_t)icon_w, (u_int32_t)icon_pm,
1132 (u_int32_t)icon_mask, (u_int32_t)w
1133 );
1134
1135 XFree(wm_hints);
1136 }
1137
1138 /* Set the Window Manager Icon Name */
1139 if(icon_name != NULL)
1140 {
1141 XTextProperty *t = (XTextProperty *)malloc(
1142 sizeof(XTextProperty)
1143 );
1144 t->value = (unsigned char *)icon_name;
1145 t->encoding = XA_STRING;
1146 t->format = 8;
1147 t->nitems = STRLEN(icon_name);
1148
1149 xerrval = 0;
1150 XSetWMIconName(dpy, w, t);
1151 if(xerrval && gw_debug)
1152 printf(GW_DEBUG_PREFIX
1153 "XSetWMIconName(): Error setting name of icon window 0x%.8x for window 0x%.8x.\n",
1154 (u_int32_t)icon_w, (u_int32_t)w
1155 );
1156
1157 free(t);
1158 }
1159
1160 #endif /* XPM_H */
1161 }
1162 #endif /* X_H */
1163
1164
1165 #ifdef X_H
1166 /*
1167 * Creates a new Window.
1168 */
GWCreateWindow(gw_display_struct * display,Window parent,int x,int y,int width,int height,const char * title)1169 Window GWCreateWindow(
1170 gw_display_struct *display,
1171 Window parent,
1172 int x, int y,
1173 int width, int height,
1174 const char *title
1175 )
1176 {
1177 Bool is_toplevel;
1178 unsigned long wa_flags;
1179 XVisualInfo *vi;
1180 Window w = None;
1181 XSetWindowAttributes wa;
1182 Display *dpy;
1183
1184 if((display == NULL) || (width <= 0) || (height <= 0))
1185 return(w);
1186
1187 dpy = display->display;
1188 vi = display->visual_info;
1189
1190 if((dpy == NULL) || (vi == NULL))
1191 return(w);
1192
1193 /* If the specified parent is None, then use the use root
1194 * Window (the desktop) as the parent
1195 */
1196 if(parent == None)
1197 {
1198 parent = display->root;
1199
1200 /* Root window not available? */
1201 if(parent == None)
1202 {
1203 if(gw_debug)
1204 printf(GW_DEBUG_PREFIX
1205 "GWCreateWindow(): Root window not available as parent to create the window.\n"
1206 );
1207 return(w);
1208 }
1209 }
1210
1211 /* Are we going to create a toplevel Window? */
1212 is_toplevel = (parent == display->root) ? True : False;
1213
1214 /* Set values for the new Window */
1215 wa_flags = CWBackPixmap | CWBorderPixel |
1216 CWBitGravity | CWWinGravity |
1217 CWBackingStore | CWOverrideRedirect |
1218 CWSaveUnder | CWEventMask |
1219 CWColormap | CWCursor;
1220 wa.background_pixmap = None;
1221 wa.border_pixel = display->black_pix;
1222 wa.bit_gravity = ForgetGravity;
1223 wa.win_gravity = CenterGravity;
1224 wa.backing_store = NotUseful;
1225 wa.save_under = False;
1226 wa.event_mask = StructureNotifyMask | ExposureMask |
1227 KeyPressMask | KeyReleaseMask |
1228 ButtonPressMask | ButtonReleaseMask |
1229 PointerMotionMask | VisibilityChangeMask;
1230 wa.override_redirect = False;
1231 wa.colormap = display->colormap;
1232 wa.cursor = None;
1233
1234 /* Create the new Window */
1235 if(gw_debug)
1236 printf(GW_DEBUG_PREFIX
1237 "Creating X window parented to 0x%.8x of geometry %ix%i%s%i%s%i at Depth %i bits\n",
1238 (unsigned int)parent,
1239 width, height,
1240 (x < 0) ? "" : "+", x,
1241 (y < 0) ? "" : "+", y,
1242 display->depth
1243 );
1244 xerrval = 0;
1245 w = XCreateWindow(
1246 dpy,
1247 parent,
1248 x, y,
1249 width, height,
1250 0,
1251 display->depth,
1252 InputOutput,
1253 vi->visual,
1254 wa_flags,
1255 &wa
1256 );
1257 if(xerrval || (w == None))
1258 {
1259 if(gw_debug)
1260 printf(GW_DEBUG_PREFIX
1261 "XCreateWindow(): Error creating Window.\n"
1262 );
1263 return(w);
1264 }
1265 else
1266 {
1267 if(gw_debug)
1268 printf(GW_DEBUG_PREFIX
1269 "Created Window 0x%.8x.\n",
1270 (unsigned int)w
1271 );
1272 }
1273
1274 /* Set additional values if the Window is a toplevel Window */
1275 if(is_toplevel)
1276 {
1277 const int natoms = 6;
1278 Atom *a = (Atom *)malloc(natoms * sizeof(Atom));
1279 XSizeHints *sz_hints = XAllocSizeHints();;
1280
1281 /* Set Size Hints */
1282 if(sz_hints != NULL)
1283 {
1284 sz_hints->flags = USPosition | PSize |
1285 PMinSize | PBaseSize;
1286 sz_hints->x = x;
1287 sz_hints->y = y;
1288 sz_hints->width = width;
1289 sz_hints->height = height;
1290 sz_hints->min_width = GW_MIN_TOPLEVEL_WIDTH;
1291 sz_hints->min_width = GW_MIN_TOPLEVEL_HEIGHT;
1292 sz_hints->base_width = 0;
1293 sz_hints->base_height = 0;
1294
1295 xerrval = 0;
1296 XSetWMNormalHints(dpy, w, sz_hints);
1297 if(xerrval && gw_debug)
1298 printf(GW_DEBUG_PREFIX
1299 "XSetWMNormalHints(): Error setting WM size hints for window 0x%.8x.\n",
1300 (u_int32_t)w
1301 );
1302 }
1303
1304 /* Set Title */
1305 if(!STRISEMPTY(title))
1306 {
1307 xerrval = 0;
1308 XStoreName(dpy, w, title);
1309 if(xerrval && gw_debug)
1310 printf(GW_DEBUG_PREFIX
1311 "XStoreName(): Error setting the title for window 0x%.8x.\n",
1312 (u_int32_t)w
1313 );
1314 }
1315
1316 /* Set Atoms */
1317 a[0] = display->atom_wm_close_window;
1318 a[1] = display->atom_wm_delete_window;
1319 a[2] = display->atom_wm_ping;
1320 a[3] = display->atom_wm_save_yourself;
1321 a[4] = display->atom_wm_take_focus;
1322 a[5] = display->atom_wm_workarea;
1323 xerrval = 0;
1324 XSetWMProtocols(
1325 dpy, /* Display */
1326 w, /* Window */
1327 a, /* Atoms */
1328 natoms /* Number of Atoms */
1329 );
1330 if(xerrval && gw_debug)
1331 printf(GW_DEBUG_PREFIX
1332 "XSetWMProtocols(): Cannot set atoms for window 0x%.8x.\n",
1333 (u_int32_t)w
1334 );
1335
1336
1337 XFree(sz_hints);
1338 free(a);
1339 }
1340
1341 return(w);
1342 }
1343 #endif /* X_H */
1344
1345
1346 #ifdef X_H
1347 /*
1348 * Initializes the graphics wrapper.
1349 */
GWInit(int argc,char ** argv)1350 gw_display_struct *GWInit(int argc, char **argv)
1351 {
1352 Boolean direct_rendering = True;
1353 Boolean fullscreen = False;
1354 float aspect_offset = 0.0f;
1355 Boolean no_windows = False;
1356 int i, status;
1357 int major_version, minor_version;
1358 #ifdef XF86VIDMODE_H
1359 int vm_event_base, vm_error_base;
1360 #endif /* XF86VIDMODE_H */
1361 const char *arg;
1362 XVisualInfo *vi;
1363 int x = 0, y = 0, off_screen_margin = 10;
1364 int width = 320, height = 240;
1365 gw_display_struct *display = NULL;
1366 const char *display_address = NULL;
1367 const char *background_color = NULL;
1368 const char *foreground_color = NULL;
1369 const char *font_name =
1370 "-adobe-helvetica-medium-r-normal-*-12-*-*-*-p-*-iso8859-1";
1371 const char *title = "Untitled";
1372 const char *icon_path = NULL;
1373 const char *icon_name = NULL;
1374 const char *pointer_color = NULL;
1375 Bool allow_key_repeat = True;
1376
1377 /* Parse arguments */
1378 for(i = 0; i < argc; i++)
1379 {
1380 arg = argv[i];
1381 if(arg == NULL)
1382 continue;
1383
1384 /* Print GW debug messages to stdout? */
1385 if(!strcasecmp(arg, "--gw_debug") ||
1386 !strcasecmp(arg, "-gw_debug")
1387 )
1388 {
1389 gw_debug = True;
1390 }
1391 /* Software rendering? */
1392 else if(!strcasecmp(arg, "--software_rendering") ||
1393 !strcasecmp(arg, "-software_rendering") ||
1394 !strcasecmp(arg, "--software-rendering") ||
1395 !strcasecmp(arg, "-software-rendering") ||
1396 !strcasecmp(arg, "--software") ||
1397 !strcasecmp(arg, "-software")
1398 )
1399 {
1400 direct_rendering = False;
1401 }
1402 /* Hardware rendering? */
1403 else if(!strcasecmp(arg, "--hardware_rendering") ||
1404 !strcasecmp(arg, "-hardware_rendering") ||
1405 !strcasecmp(arg, "--hardware-rendering") ||
1406 !strcasecmp(arg, "-hardware-rendering") ||
1407 !strcasecmp(arg, "--hardware") ||
1408 !strcasecmp(arg, "-hardware") ||
1409 !strcasecmp(arg, "--direct_rendering") ||
1410 !strcasecmp(arg, "-direct_rendering") ||
1411 !strcasecmp(arg, "--direct-rendering") ||
1412 !strcasecmp(arg, "-direct-rendering")
1413 )
1414 {
1415 direct_rendering = True;
1416 }
1417 /* Display address (address to X server)? */
1418 else if(!strcasecmp(arg, "--display") ||
1419 !strcasecmp(arg, "-display") ||
1420 !strcasecmp(arg, "--dpy") ||
1421 !strcasecmp(arg, "-dpy")
1422 )
1423 {
1424 i++;
1425 arg = (i < argc) ? argv[i] : NULL;
1426 if(arg != NULL)
1427 {
1428 display_address = arg;
1429 }
1430 else
1431 {
1432 fprintf(
1433 stderr,
1434 "%s: Requires argument.\n",
1435 argv[i - 1]
1436 );
1437 }
1438 }
1439 /* Background color? */
1440 else if(!strcasecmp(arg, "--background") ||
1441 !strcasecmp(arg, "-background") ||
1442 !strcasecmp(arg, "--bg") ||
1443 !strcasecmp(arg, "-bg")
1444 )
1445 {
1446 i++;
1447 arg = (i < argc) ? argv[i] : NULL;
1448 if(arg != NULL)
1449 {
1450 background_color = arg;
1451 }
1452 else
1453 {
1454 fprintf(
1455 stderr,
1456 "%s: Requires argument.\n",
1457 argv[i - 1]
1458 );
1459 }
1460 }
1461 /* Foreground color? */
1462 else if(!strcasecmp(arg, "--foreground") ||
1463 !strcasecmp(arg, "-foreground") ||
1464 !strcasecmp(arg, "--fg") ||
1465 !strcasecmp(arg, "-fg")
1466 )
1467 {
1468 i++;
1469 arg = (i < argc) ? argv[i] : NULL;
1470 if(arg != NULL)
1471 {
1472 foreground_color = arg;
1473 }
1474 else
1475 {
1476 fprintf(
1477 stderr,
1478 "%s: Requires argument.\n",
1479 argv[i - 1]
1480 );
1481 }
1482 }
1483 /* Font name? */
1484 else if(!strcasecmp(arg, "--font") ||
1485 !strcasecmp(arg, "-font") ||
1486 !strcasecmp(arg, "--fn") ||
1487 !strcasecmp(arg, "-fn")
1488 )
1489 {
1490 i++;
1491 arg = (i < argc) ? argv[i] : NULL;
1492 if(arg != NULL)
1493 {
1494 font_name = arg;
1495 }
1496 else
1497 {
1498 fprintf(
1499 stderr,
1500 "%s: Requires argument.\n",
1501 argv[i - 1]
1502 );
1503 }
1504 }
1505 /* Title of toplevel window? */
1506 else if(!strcasecmp(arg, "--title") ||
1507 !strcasecmp(arg, "-title")
1508 )
1509 {
1510 i++;
1511 arg = (i < argc) ? argv[i] : NULL;
1512 if(arg != NULL)
1513 {
1514 title = arg;
1515 }
1516 else
1517 {
1518 fprintf(
1519 stderr,
1520 "%s: Requires argument.\n",
1521 argv[i - 1]
1522 );
1523 }
1524 }
1525 /* Toplevel window's WM icon? */
1526 else if(!strcasecmp(arg, "--icon_path") ||
1527 !strcasecmp(arg, "-icon_path") ||
1528 !strcasecmp(arg, "--icon_file") ||
1529 !strcasecmp(arg, "-icon_file") ||
1530 !strcasecmp(arg, "--icon") ||
1531 !strcasecmp(arg, "-icon")
1532 )
1533 {
1534 i++;
1535 arg = (i < argc) ? argv[i] : NULL;
1536 if(arg != NULL)
1537 {
1538 icon_path = arg;
1539 }
1540 else
1541 {
1542 fprintf(
1543 stderr,
1544 "%s: Requires argument.\n",
1545 argv[i - 1]
1546 );
1547 }
1548 }
1549 /* Toplevel window's WM icon name? */
1550 else if(!strcasecmp(arg, "--icon_name") ||
1551 !strcasecmp(arg, "-icon_name")
1552 )
1553 {
1554 i++;
1555 arg = (i < argc) ? argv[i] : NULL;
1556 if(arg != NULL)
1557 {
1558 icon_name = arg;
1559 }
1560 else
1561 {
1562 fprintf(
1563 stderr,
1564 "%s: Requires argument.\n",
1565 argv[i - 1]
1566 );
1567 }
1568 }
1569 /* Full screen mode? */
1570 else if(!strcasecmp(arg, "--fullscreen") ||
1571 !strcasecmp(arg, "-fullscreen") ||
1572 !strcasecmp(arg, "--full_screen") ||
1573 !strcasecmp(arg, "-full_screen")
1574 )
1575 {
1576 fullscreen = True;
1577 }
1578 else if ( (!strcasecmp(arg, "--window")) ||
1579 (!strcasecmp(arg, "-window") )
1580 )
1581 {
1582 fullscreen = False;
1583 }
1584 else if ( (!strcasecmp(arg, "--no-autorepeat")) ||
1585 (!strcasecmp(arg, "--no-keyrepeat") )
1586 )
1587 {
1588 allow_key_repeat = False;
1589 }
1590 /* Position and size of toplevel window? */
1591 else if(!strcasecmp(arg, "--geometry") ||
1592 !strcasecmp(arg, "-geometry")
1593 )
1594 {
1595 i++;
1596 arg = (i < argc) ? argv[i] : NULL;
1597 if(arg != NULL)
1598 {
1599 int start_x = 0, start_y = 0;
1600 unsigned int start_width = 320, start_height = 240;
1601
1602 XParseGeometry(
1603 arg,
1604 &start_x, &start_y,
1605 &start_width, &start_height
1606 );
1607
1608 x = start_x;
1609 y = start_y;
1610 width = MAX((int)start_width, off_screen_margin);
1611 height = MAX((int)start_height, off_screen_margin);
1612 }
1613 else
1614 {
1615 fprintf(
1616 stderr,
1617 "%s: Requires argument.\n",
1618 argv[i - 1]
1619 );
1620 }
1621 }
1622 /* Pointer color? */
1623 else if(!strcasecmp(arg, "--pointer_color") ||
1624 !strcasecmp(arg, "-pointer_color") ||
1625 !strcasecmp(arg, "--pointer-color") ||
1626 !strcasecmp(arg, "-pointer-color") ||
1627 !strcasecmp(arg, "--ms") ||
1628 !strcasecmp(arg, "-ms")
1629 )
1630 {
1631 i++;
1632 arg = (i < argc) ? argv[i] : NULL;
1633 if(arg != NULL)
1634 {
1635 pointer_color = arg;
1636 }
1637 else
1638 {
1639 fprintf(
1640 stderr,
1641 "%s: Requires argument.\n",
1642 argv[i - 1]
1643 );
1644 }
1645 }
1646 /* Aspect offset? */
1647 else if(!strcasecmp(arg, "--aspect_offset") ||
1648 !strcasecmp(arg, "-aspect_offset") ||
1649 !strcasecmp(arg, "--aspect-offset") ||
1650 !strcasecmp(arg, "-aspect-offset") ||
1651 !strcasecmp(arg, "--aspectoffset") ||
1652 !strcasecmp(arg, "-aspectoffset")
1653 )
1654 {
1655 i++;
1656 arg = (i < argc) ? argv[i] : NULL;
1657 if(arg != NULL)
1658 {
1659 aspect_offset = ATOF(arg);
1660 }
1661 else
1662 {
1663 fprintf(
1664 stderr,
1665 "%s: Requires argument.\n",
1666 argv[i - 1]
1667 );
1668 }
1669 }
1670 /* No window, this is a special argument to specify that
1671 * no windows (or dialogs) are to be created.
1672 */
1673 else if(!strcasecmp(arg, "--no_windows") ||
1674 !strcasecmp(arg, "-no_windows") ||
1675 !strcasecmp(arg, "--nowindows") ||
1676 !strcasecmp(arg, "-nowindows")
1677 )
1678 {
1679 no_windows = True;
1680 }
1681 }
1682
1683 /* Is GW debugging enabled? */
1684 if(gw_debug)
1685 printf(GW_DEBUG_PREFIX
1686 "Debugging enabled, messages will be sent to stdout.\n"
1687 );
1688
1689
1690 /* Allocate a new graphics wrapper display structure */
1691 display = (gw_display_struct *)calloc(
1692 1, sizeof(gw_display_struct)
1693 );
1694 if(display == NULL)
1695 return(display);
1696
1697 /* Reset values */
1698 display->grab_window = None;
1699 display->cursor_shown = True;
1700 display->last_button_press = 0;
1701 display->button_press_count = 0;
1702 display->fullscreen = False;
1703 display->fullscreen_context_num = -1;
1704 display->allow_autorepeat = allow_key_repeat;
1705 memset(&display->vidmode_last_gui_geometry, 0x00, sizeof(XRectangle));
1706
1707
1708 /* Open connection to display */
1709 status = -1;
1710 while(True)
1711 {
1712 /* First try connecting using the given display address
1713 * (which may be NULL).
1714 */
1715 display->display = XOpenDisplay(display_address);
1716 if(display->display != NULL)
1717 {
1718 status = 0; /* Success */
1719 if(gw_debug)
1720 printf(GW_DEBUG_PREFIX
1721 "Connected to X server display: %s\n",
1722 display_address
1723 );
1724 break;
1725 }
1726
1727 /* Check if host address was unspecified */
1728 if(display_address == NULL)
1729 {
1730 /* Try using the value from the DISPLAY environment
1731 * variable (if any).
1732 */
1733 display_address = getenv("DISPLAY");
1734 if(display_address != NULL)
1735 display->display = XOpenDisplay(display_address);
1736 if(display->display != NULL)
1737 {
1738 status = 0; /* Success */
1739 if(gw_debug)
1740 printf(GW_DEBUG_PREFIX
1741 "Connected to X server display (environment variable \"DISPLAY\"): %s\n",
1742 display_address
1743 );
1744 break;
1745 }
1746
1747 #if 0
1748 /* All else fails try explicitly using localhost */
1749 display_address = "127.0.0.1:0.0";
1750 if(display_address != NULL)
1751 display->display = XOpenDisplay(display_address);
1752 if(display->display != NULL)
1753 {
1754 status = 0; /* Success */
1755 if(gw_debug)
1756 printf(GW_DEBUG_PREFIX
1757 "Connected to X server display (default local): %s\n",
1758 display_address
1759 );
1760 break;
1761 }
1762 #endif
1763 }
1764
1765 /* Failed */
1766 break;
1767 }
1768 /* Connect failed? */
1769 if(status)
1770 {
1771 if(gw_debug)
1772 printf(GW_DEBUG_PREFIX
1773 "Connection to X server failed, see stderr output for details.\n"
1774 );
1775
1776 /* Print reason for failed connect */
1777 fprintf(stderr, "Cannot connect to X server: ");
1778 if(getenv("DISPLAY") == NULL)
1779 fprintf(stderr, "`DISPLAY' environment variable not set.");
1780 else
1781 fprintf(stderr, "%s", XDisplayName(NULL));
1782 fprintf(stderr, "\n");
1783
1784 /* Print verbose help */
1785 fprintf(stderr,
1786 "\nCheck to make sure that your X server is running and that your\n\
1787 enviroment variable `DISPLAY' is set properly.\n"
1788 );
1789
1790 free(display);
1791 return(NULL);
1792 }
1793
1794 /* Set X server error handler */
1795 XSetErrorHandler(GWXErrorHandler);
1796
1797
1798 /* Check version numbers of the glX extension */
1799 if(glXQueryVersion(display->display, &major_version, &minor_version))
1800 {
1801 if(gw_debug)
1802 printf(GW_DEBUG_PREFIX
1803 "glX version: major=%i minor=%i\n",
1804 major_version, minor_version
1805 );
1806 /* Store glX version */
1807 display->glx_version_major = major_version;
1808 display->glx_version_minor = minor_version;
1809 }
1810 else
1811 {
1812 /* Could not get glX version, implying glX not available */
1813
1814 if(gw_debug)
1815 printf(GW_DEBUG_PREFIX
1816 "glXQueryVersion(): Failed, implying glX is not available.\n"
1817 );
1818
1819 fprintf(stderr,
1820 "Warning: Unable to find glX, this is used for X and OpenGL communications.\n"
1821 );
1822 }
1823
1824 /* Get Visual */
1825 vi = NULL;
1826 display->alpha_channel_bits = 0;
1827 display->has_double_buffer = False;
1828 for(i = 0; i < 4; i++)
1829 {
1830 switch(i)
1831 {
1832 case 0: /* First try double buffer RGBA */
1833 vi = glXChooseVisual(
1834 display->display,
1835 DefaultScreen(display->display),
1836 attributeListDblRGBA
1837 );
1838 if(vi == NULL)
1839 {
1840 if(gw_debug)
1841 printf(GW_DEBUG_PREFIX
1842 "glXChooseVisual(): RGBA double buffer X Visual not available.\n"
1843 );
1844 }
1845 break;
1846
1847 case 1: /* Second try single buffer RGBA */
1848 vi = glXChooseVisual(
1849 display->display,
1850 DefaultScreen(display->display),
1851 attributeListSglRGBA
1852 );
1853 if(vi == NULL)
1854 {
1855 if(gw_debug)
1856 printf(GW_DEBUG_PREFIX
1857 "glXChooseVisual(): RGBA single buffer X Visual not available.\n"
1858 );
1859 }
1860 break;
1861
1862 case 2: /* Third try double buffer RGB */
1863 vi = glXChooseVisual(
1864 display->display,
1865 DefaultScreen(display->display),
1866 attributeListDblRGB
1867 );
1868 if(vi == NULL)
1869 {
1870 if(gw_debug)
1871 printf(GW_DEBUG_PREFIX
1872 "glXChooseVisual(): RGB double buffer X Visual not available.\n"
1873 );
1874 }
1875 break;
1876
1877 case 3: /* Fourth try single buffer RGB */
1878 vi = glXChooseVisual(
1879 display->display,
1880 DefaultScreen(display->display),
1881 attributeListSglRGB
1882 );
1883 if(vi == NULL)
1884 {
1885 if(gw_debug)
1886 printf(GW_DEBUG_PREFIX
1887 "glXChooseVisual(): RGB single buffer X Visual not available.\n"
1888 );
1889 }
1890 break;
1891 }
1892 if(vi != NULL)
1893 break;
1894 }
1895 /* Record the matched XVisualInfo from above (even if NULL) */
1896 display->visual_info = vi;
1897
1898 /* Get values from matched Visual */
1899 if(vi != NULL)
1900 {
1901 int vi_val;
1902
1903 if(!glXGetConfig(
1904 display->display, vi,
1905 GLX_DOUBLEBUFFER, &vi_val
1906 ))
1907 display->has_double_buffer = (vi_val ? True : False);
1908
1909 if(!glXGetConfig(
1910 display->display, vi,
1911 GLX_ALPHA_SIZE, &vi_val
1912 ))
1913 display->alpha_channel_bits = vi_val;
1914 }
1915
1916 /* Failed to find a useable Visual? */
1917 if(vi == NULL)
1918 {
1919 fprintf(
1920 stderr,
1921 "Unable to find a suitable X Visual.\n\
1922 \n\
1923 Please verify that you have an X Visual suitable for OpenGL rendering\n\
1924 by running \"xdpyinfo\". Also note that defining multiple Visuals\n\
1925 may confuse the selection of a proper Visual (in which case try defining\n\
1926 only one Visual).\n\
1927 \n\
1928 Your hardware may have a Visual that is not compatible with this program.\n"
1929 );
1930 GWShutdown(display);
1931 return(NULL);
1932 }
1933
1934
1935 /* Begin query for X extensions */
1936
1937 /* XShape */
1938 if(XShapeQueryVersion(
1939 display->display, &major_version, &minor_version
1940 ))
1941 {
1942 if(gw_debug)
1943 printf(GW_DEBUG_PREFIX
1944 "Shape extension version: major=%i minor=%i\n",
1945 major_version, minor_version
1946 );
1947 }
1948 else
1949 {
1950 if(gw_debug)
1951 printf(GW_DEBUG_PREFIX
1952 "XShapeQueryVersion(): Shape extension not available.\n"
1953 );
1954 }
1955
1956 /* Screen Saver */
1957 /* TODO
1958 Status XScreenSaverQueryVersion(
1959 Display *dpy,
1960 int *major,
1961 int *minor
1962 );
1963 */
1964
1965 #ifdef XF86VIDMODE_H
1966 /* XF86 VidMode */
1967 if(XF86VidModeQueryExtension(
1968 display->display, &vm_event_base, &vm_error_base
1969 ))
1970 {
1971 if(XF86VidModeQueryVersion(
1972 display->display, &major_version, &minor_version
1973 ))
1974 {
1975 if(gw_debug)
1976 printf(GW_DEBUG_PREFIX
1977 "XF86VidMode extension version: major=%i minor=%i\n",
1978 major_version, minor_version
1979 );
1980 }
1981 if(gw_debug)
1982 {
1983 Display *dpy = display->display;
1984 int scr = DefaultScreen(dpy);
1985 XF86VidModeModeInfo **mode_line;
1986 int total_mode_lines;
1987 int vp_x = 0, vp_y = 0;
1988
1989 /* Get current viewport position */
1990 XF86VidModeGetViewPort(dpy, scr, &vp_x, &vp_y);
1991
1992 if(XF86VidModeGetAllModeLines(
1993 dpy, scr,
1994 &total_mode_lines, &mode_line
1995 ))
1996 {
1997 /* First mode is the current mode */
1998 XF86VidModeModeInfo *m = (total_mode_lines > 0) ?
1999 mode_line[0] : NULL;
2000 if(m != NULL)
2001 printf(
2002 "\tCurrent Video Mode: %ix%i Viewport: %i %i\n",
2003 m->hdisplay, m->vdisplay,
2004 vp_x, vp_y
2005 );
2006
2007 /* Print info for subsequent modes */
2008 for(i = 1; i < total_mode_lines; i++)
2009 {
2010 m = mode_line[i];
2011 if(m == NULL)
2012 continue;
2013
2014 printf(
2015 "\tVideo Mode #%i: %ix%i\n",
2016 i, m->hdisplay, m->vdisplay
2017 );
2018 }
2019
2020 /* Deallocate memory on each mode info structure */
2021 for(i = 0; i < total_mode_lines; i++)
2022 {
2023 m = mode_line[i];
2024 if(m == NULL)
2025 continue;
2026
2027 /* If private is not NULL then it needs to be
2028 * deallocated. Currently this only occures for
2029 * the S3 servers.
2030 */
2031 if((m->privsize > 0) && (m->private != NULL))
2032 {
2033 XFree(m->private);
2034 m->private = NULL;
2035 m->privsize = 0;
2036 }
2037
2038 /* Do not free each structure */
2039 /* XFree(m); */
2040 }
2041 XFree(mode_line);
2042 }
2043 }
2044 display->has_vidmode_ext = True;
2045 display->vidmode_ext_event_offset = vm_event_base;
2046 }
2047 else
2048 {
2049 /* XF86 VidMode not available */
2050 if(gw_debug)
2051 printf(GW_DEBUG_PREFIX
2052 "XF86VidModeQueryExtension(): XF86 VidMode extension not available.\n"
2053 );
2054 display->has_vidmode_ext = False;
2055 display->vidmode_ext_event_offset = 0;
2056 }
2057 #else
2058 display->has_vidmode_ext = False;
2059 display->vidmode_ext_event_offset = 0;
2060 #endif /* XF86VIDMODE_H */
2061
2062
2063 /* Get other default values */
2064 display->aspect_offset = aspect_offset;
2065 display->direct_rendering = direct_rendering;
2066 display->visual = DefaultVisual(display->display, vi->screen);
2067 display->white_pix = WhitePixel(display->display, vi->screen);
2068 display->black_pix = BlackPixel(display->display, vi->screen);
2069 display->depth = vi->depth;
2070 if(gw_debug)
2071 printf(GW_DEBUG_PREFIX
2072 "Using X Depth %i bits.\n", display->depth
2073 );
2074
2075 display->gc = DefaultGC(display->display, vi->screen);
2076 display->current_font = NULL;
2077 #if 0
2078 /* We do not use X fonts to draw strings, so do not set any of this
2079 *
2080 * The default xfont name will be coppied to the display structure
2081 * further below
2082 */
2083 = XLoadFont(display->display, font_name);
2084 XSetFont(display->display, display->gc, font);
2085 #endif
2086
2087 XSetForeground(display->display, display->gc, display->black_pix);
2088 display->current_font = default_fnt;
2089 display->atom_wm_motif_all_clients = XInternAtom(
2090 display->display,
2091 "_MOTIF_WM_ALL_CLIENTS",
2092 False
2093 );
2094 display->atom_wm_motif_hints = XInternAtom(
2095 display->display,
2096 "_MOTIF_WM_HINTS",
2097 False
2098 );
2099 display->atom_wm_motif_info = XInternAtom(
2100 display->display,
2101 "_MOTIF_WM_INFO",
2102 False
2103 );
2104 display->atom_wm_motif_menu = XInternAtom(
2105 display->display,
2106 "_MOTIF_WM_MENU",
2107 False
2108 );
2109 display->atom_wm_motif_messages = XInternAtom(
2110 display->display,
2111 "_MOTIF_WM_MESSAGES",
2112 False
2113 );
2114 display->atom_wm_motif_offset = XInternAtom(
2115 display->display,
2116 "_MOTIF_WM_OFFSET",
2117 False
2118 );
2119 display->atom_wm_motif_query = XInternAtom(
2120 display->display,
2121 "_MOTIF_WM_QUERY",
2122 False
2123 );
2124 display->atom_wm_close_window = XInternAtom(
2125 display->display,
2126 "_NET_CLOSE_WINDOW",
2127 False
2128 );
2129 display->atom_wm_delete_window = XInternAtom(
2130 display->display,
2131 "WM_DELETE_WINDOW",
2132 False
2133 );
2134 display->atom_wm_ping = XInternAtom(
2135 display->display,
2136 "_NET_WM_PING",
2137 False
2138 );
2139 display->atom_wm_save_yourself = XInternAtom(
2140 display->display,
2141 "WM_SAVE_YOURSELF",
2142 False
2143 );
2144 display->atom_wm_state = XInternAtom(
2145 display->display,
2146 "WM_STATE",
2147 False
2148 );
2149 display->atom_wm_take_focus = XInternAtom(
2150 display->display,
2151 "WM_TAKE_FOCUS",
2152 False
2153 );
2154 display->atom_wm_workarea = XInternAtom(
2155 display->display,
2156 "_NET_WORKAREA",
2157 False
2158 );
2159
2160
2161 /* Get root window and its geometry */
2162 display->root = RootWindow(display->display, vi->screen);
2163 display->root_width = DisplayWidth(display->display, vi->screen);
2164 display->root_height = DisplayHeight(display->display, vi->screen);
2165 if(display->root == None)
2166 {
2167 if(gw_debug)
2168 printf(GW_DEBUG_PREFIX
2169 "Cannot find root window (the desktop).\n"
2170 );
2171 }
2172
2173
2174 /* Create X Colormap */
2175 xerrval = 0;
2176 display->colormap = XCreateColormap(
2177 display->display,
2178 display->root,
2179 vi->visual, AllocNone
2180 );
2181 if(xerrval || (display->colormap == None))
2182 {
2183 if(gw_debug)
2184 printf(GW_DEBUG_PREFIX
2185 "XCreateColormap(): Cannot create X colormap.\n"
2186 );
2187 }
2188
2189
2190 /* Sanitize the geometry for creation of the first toplevel
2191 * window to fall within the root window's size
2192 */
2193 if((x + width) < off_screen_margin)
2194 x = off_screen_margin - width;
2195 if((y + height) < off_screen_margin)
2196 y = off_screen_margin - height;
2197
2198 if(x > (display->root_width - off_screen_margin))
2199 x = display->root_width - off_screen_margin;
2200 if(y > (display->root_height - off_screen_margin))
2201 y = display->root_height - off_screen_margin;
2202
2203
2204 /* Create first GL context and toplevel Window */
2205 display->gl_context_num = -1;
2206 display->total_gl_contexts = 0;
2207 display->glx_context = NULL;
2208 display->toplevel = NULL;
2209 display->toplevel_geometry = NULL;
2210 display->draw_count = NULL;
2211 i = GWContextNew(
2212 display, x, y, width, height,
2213 title, icon_path, icon_name, no_windows
2214 );
2215 GWContextSet(display, i);
2216
2217
2218 /* At this point we have the glX context created and set to our
2219 * main toplevel window, now we can get the GL version
2220 */
2221 arg = (const char *)glGetString(GL_VERSION);
2222 if(arg != NULL)
2223 {
2224 char *gl_vs_ptr;
2225 char *gl_vs = STRDUP(arg);
2226 if(gl_vs != NULL)
2227 {
2228 /* Deliminate at space which separates version and vendor
2229 * name.
2230 */
2231 gl_vs_ptr = strchr(gl_vs, ' ');
2232 if(gl_vs_ptr != NULL)
2233 *gl_vs_ptr = '\0';
2234
2235 gl_vs_ptr = gl_vs;
2236 if(gl_vs_ptr != NULL)
2237 {
2238 display->gl_version_major = ATOI(gl_vs_ptr);
2239 gl_vs_ptr = strchr(gl_vs_ptr, '.');
2240 if(gl_vs_ptr != NULL)
2241 gl_vs_ptr++;
2242 }
2243 if(gl_vs_ptr != NULL)
2244 {
2245 display->gl_version_minor = ATOI(gl_vs_ptr);
2246 gl_vs_ptr = strchr(gl_vs_ptr, '.');
2247 if(gl_vs_ptr != NULL)
2248 gl_vs_ptr++;
2249 }
2250
2251 free(gl_vs);
2252 }
2253
2254 if(gw_debug)
2255 printf(GW_DEBUG_PREFIX
2256 "OpenGL implementation version: major=%i minor=%i\n",
2257 display->gl_version_major, display->gl_version_minor
2258 );
2259 }
2260 else
2261 {
2262 if(gw_debug)
2263 printf(GW_DEBUG_PREFIX
2264 "glGetString(GL_VERSION): Returned NULL, cannot get OpenGL implementation version.\n"
2265 );
2266 fprintf(stderr, "Cannot obtain OpenGL implementation version.\n");
2267 }
2268
2269 /* Font name specified? */
2270 if(font_name != NULL)
2271 {
2272 /* Load font to see if it exists */
2273 XFontStruct *xfont = XLoadQueryFont(
2274 display->display, font_name
2275 );
2276 if(xfont == NULL)
2277 {
2278 /* Fall back to something safe */
2279 font_name =
2280 "-*-clean-*-*-*-*-*-*-*-*-*-*-*-*";
2281 }
2282 else
2283 {
2284 /* Do not keep the loaded X font */
2285 XFreeFont(display->display, xfont);
2286 }
2287
2288 /* Record font name */
2289 display->def_xfont_name = STRDUP(font_name);
2290 }
2291
2292 /* Get maximum texture lengths, in pixels */
2293 if(True)
2294 {
2295 GLint v[1];
2296 glGetIntegerv(GL_MAX_TEXTURE_SIZE, v);
2297 display->texture_1d_max = display->texture_2d_max =
2298 display->texture_3d_max = v[0];
2299 }
2300
2301 /* Turn on keyboard autorepeat */
2302 GWKeyboardAutoRepeat(display, True);
2303
2304 /* Reset GL states */
2305 StateGLResetAll(&display->state_gl);
2306
2307 /* Set pixel storage format (for rastering bitmaps) */
2308 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
2309 glPixelStorei(GL_PACK_ALIGNMENT, 1);
2310
2311 /* Set other GL defaults that we want. Some of these might
2312 * default to on but we want them off to improve performance
2313 */
2314 StateGLDisable(&display->state_gl, GL_DITHER);
2315
2316
2317 /* Load cursors */
2318 if(True)
2319 {
2320 Display *dpy = display->display;
2321 Cursor cur;
2322 /* XColor c_fg, c_bg; */
2323 int width = 8, height = 8;
2324 u_int8_t *data = (u_int8_t *)calloc(
2325 width * height, 4 * sizeof(u_int8_t)
2326 );
2327
2328 #define CREATE_FONT_CURSOR(i) \
2329 { \
2330 xerrval = 0; \
2331 cur = XCreateFontCursor(dpy, i); \
2332 /* if((cur != None) && !xerrval) { \
2333 xerrval = 0; \
2334 XRecolorCursor(dpy, cur, &c_fg, &c_bg); \
2335 } */ \
2336 }
2337 /*
2338 XCOLOR_SET_RGB_COEFF(&c_fg, 1.0, 1.0, 1.0);
2339 XCOLOR_SET_RGB_COEFF(&c_bg, 0.0, 0.0, 0.0);
2340 */
2341 cur = None; /* Standard cursor is None */
2342 display->cursor_standard = cur;
2343
2344 /*
2345 XCOLOR_SET_RGB_COEFF(&c_fg, 0.0, 0.0, 0.0);
2346 XCOLOR_SET_RGB_COEFF(&c_bg, 1.0, 1.0, 1.0);
2347 */
2348 CREATE_FONT_CURSOR(XC_watch);
2349 display->cursor_busy = cur;
2350
2351 CREATE_FONT_CURSOR(XC_xterm);
2352 display->cursor_text = cur;
2353
2354 CREATE_FONT_CURSOR(XC_fleur);
2355 display->cursor_translate = cur;
2356
2357 CREATE_FONT_CURSOR(XC_sizing);
2358 display->cursor_zoom = cur;
2359
2360 display->cursor_invisible = (Cursor)GWCursorNew(
2361 display, width, height, width / 2, height / 2,
2362 0, data
2363 );
2364
2365 free(data);
2366 #undef CREATE_FONT_CURSOR
2367 }
2368
2369 /* Initialize dialogs */
2370 if(!no_windows)
2371 {
2372 GWXDialogCreate(
2373 display, &display->mesg_dialog,
2374 GWX_DIALOG_TYPE_MESG
2375 );
2376 GWXDialogCreate(
2377 display, &display->conf_dialog,
2378 GWX_DIALOG_TYPE_CONF_CANCEL
2379 );
2380 }
2381
2382 /* Go to full screen mode on start up? */
2383 if(fullscreen)
2384 {
2385 GWContextFullScreen(display, True);
2386 }
2387
2388 if(gw_debug)
2389 printf(GW_DEBUG_PREFIX
2390 "Initialization done.\n"
2391 );
2392
2393 return(display);
2394 }
2395 #endif /* X_H */
2396
2397 #ifdef X_H
2398 /*
2399 * Graphics wrapper management function, called once per loop.
2400 */
GWManage(gw_display_struct * display)2401 void GWManage(gw_display_struct *display)
2402 {
2403 XEvent event;
2404 XClientMessageEvent *cm;
2405 Window w;
2406 int i, key, events_handled;
2407
2408 if(display == NULL)
2409 return;
2410
2411 if(display->display != NULL)
2412 {
2413 Display *dpy = display->display;
2414
2415 /* Fetch events while there are events pending */
2416 while(
2417 XPending(dpy)
2418 /* XEventsQueued(dpy, QueuedAlready) > 0 */
2419 /* XEventsQueued(dpy, QueuedAfterFlush) > 0 */
2420 )
2421 {
2422 /* Get next event */
2423 xerrval = 0;
2424 XNextEvent(dpy, &event);
2425 if(xerrval)
2426 break;
2427
2428 /* Get window for this event */
2429 w = event.xany.window;
2430
2431 events_handled = 0;
2432
2433 /* Handle event by type */
2434 switch(event.type)
2435 {
2436 case Expose:
2437 for(i = 0; i < display->total_gl_contexts; i++)
2438 {
2439 if((display->toplevel[i] == w) &&
2440 (display->func_draw != NULL)
2441 )
2442 {
2443 display->func_draw(
2444 i, display->func_draw_data
2445 );
2446 events_handled++;
2447 break;
2448 }
2449 }
2450 break;
2451
2452 case ConfigureNotify:
2453 if(gw_debug)
2454 printf(GW_DEBUG_PREFIX
2455 "Got XEvent ConfigureNotify: window=0x%.8x x=%i y=%i width=%i height=%i\n",
2456 (u_int32_t)w,
2457 event.xconfigure.x,
2458 event.xconfigure.y,
2459 (int)event.xconfigure.width,
2460 (int)event.xconfigure.height
2461 );
2462 for(i = 0; i < display->total_gl_contexts; i++)
2463 {
2464 if(display->toplevel[i] == w)
2465 {
2466 XRectangle *rect = &display->toplevel_geometry[i];
2467 rect->x = event.xconfigure.x;
2468 rect->y = event.xconfigure.y;
2469 rect->width = event.xconfigure.width;
2470 rect->height = event.xconfigure.height;
2471 #ifdef XF86VIDMODE_H
2472 /* Move viewport if in full screen mode */
2473 if(display->fullscreen &&
2474 (display->fullscreen_context_num == i)
2475 )
2476 {
2477 int scr = DefaultScreen(dpy);
2478 XF86VidModeSetViewPort(
2479 dpy, scr, rect->x, rect->y
2480 );
2481 }
2482 #endif /* XF86VIDMODE_H */
2483 /* Call resize callback */
2484 if(display->func_resize != NULL)
2485 display->func_resize(
2486 i, display->func_resize_data,
2487 event.xconfigure.x,
2488 event.xconfigure.y,
2489 (int)event.xconfigure.width,
2490 (int)event.xconfigure.height
2491 );
2492 events_handled++;
2493 break;
2494 }
2495 }
2496 break;
2497
2498 case KeyPress:
2499 if(gw_debug)
2500 printf(GW_DEBUG_PREFIX
2501 "Got XEvent KeyPress: window=0x%.8x keycode=0x%.8x\n",
2502 (u_int32_t)w,
2503 (u_int32_t)event.xkey.keycode
2504 );
2505 key = GWGetCharacterFromKeyCode(
2506 display,
2507 event.xkey.keycode
2508 );
2509 /* First handle key globally (independent of window) */
2510 switch(key)
2511 {
2512 case GWKeyAlt:
2513 display->alt_key_state = True;
2514 break;
2515 case GWKeyCtrl:
2516 display->ctrl_key_state = True;
2517 break;
2518 case GWKeyShift:
2519 display->shift_key_state = True;
2520 break;
2521 }
2522 /* Now see which window belongs to this key event */
2523 for(i = 0; i < display->total_gl_contexts; i++)
2524 {
2525 if((display->toplevel[i] == w) &&
2526 (display->func_keyboard != NULL)
2527 )
2528 {
2529 display->func_keyboard(
2530 display->func_keyboard_data,
2531 key,
2532 True,
2533 event.xkey.time
2534 );
2535 events_handled++;
2536 break;
2537 }
2538 }
2539 #if 0
2540 /* This does not work well with dialogs mapped */
2541 /* Key event not matched to any window? Then send it "globally" */
2542 if(events_handled <= 0)
2543 {
2544 if(display->func_keyboard != NULL)
2545 {
2546 display->func_keyboard(
2547 display->func_keyboard_data,
2548 key,
2549 True,
2550 event.xkey.time
2551 );
2552 events_handled++;
2553 }
2554 }
2555 #endif
2556 break;
2557
2558 case KeyRelease:
2559 if(gw_debug)
2560 printf(GW_DEBUG_PREFIX
2561 "Got XEvent KeyRelease: window=0x%.8x keycode=0x%.8x\n",
2562 (u_int32_t)w,
2563 (u_int32_t)event.xkey.keycode
2564 );
2565 key = GWGetCharacterFromKeyCode(
2566 display,
2567 event.xkey.keycode
2568 );
2569 /* First handle key globally (independent of window) */
2570 switch(key)
2571 {
2572 case GWKeyAlt:
2573 display->alt_key_state = False;
2574 break;
2575 case GWKeyCtrl:
2576 display->ctrl_key_state = False;
2577 break;
2578 case GWKeyShift:
2579 display->shift_key_state = False;
2580 break;
2581 }
2582 /* Now see which window belongs to this key event */
2583 for(i = 0; i < display->total_gl_contexts; i++)
2584 {
2585 if((display->toplevel[i] == w) &&
2586 (display->func_keyboard != NULL)
2587 )
2588 {
2589 display->func_keyboard(
2590 display->func_keyboard_data,
2591 key,
2592 False,
2593 event.xkey.time
2594 );
2595 events_handled++;
2596 break;
2597 }
2598 }
2599 #if 0
2600 /* This does not work well with dialogs mapped */
2601 /* Key event not matched to any window? Then send it "globally" */
2602 if(events_handled <= 0)
2603 {
2604 if(display->func_keyboard != NULL)
2605 {
2606 display->func_keyboard(
2607 display->func_keyboard_data,
2608 key,
2609 False,
2610 event.xkey.time
2611 );
2612 events_handled++;
2613 }
2614 }
2615 #endif
2616 break;
2617
2618 case ButtonPress:
2619 if(gw_debug)
2620 printf(GW_DEBUG_PREFIX
2621 "Got XEvent ButtonPress: window=0x%.8x button=%i x=%i y=%i\n",
2622 (u_int32_t)w,
2623 event.xbutton.button,
2624 event.xbutton.x,
2625 event.xbutton.y
2626 );
2627 for(i = 0; i < display->total_gl_contexts; i++)
2628 {
2629 if((display->toplevel[i] == w) &&
2630 (display->func_pointer != NULL)
2631 )
2632 {
2633 int btn_num = 0,
2634 button_press_count = display->button_press_count;
2635 unsigned long ev_last_time = display->last_button_press,
2636 ev_time = event.xbutton.time;
2637 switch(event.xbutton.button)
2638 {
2639 case Button1:
2640 btn_num = 1;
2641 break;
2642 case Button2:
2643 btn_num = 2;
2644 break;
2645 case Button3:
2646 btn_num = 3;
2647 break;
2648 case Button4:
2649 btn_num = 4;
2650 break;
2651 case Button5:
2652 btn_num = 5;
2653 break;
2654 }
2655 display->func_pointer(
2656 i, display->func_pointer_data,
2657 event.xbutton.x,
2658 event.xbutton.y,
2659 GWEventTypeButtonPress,
2660 btn_num,
2661 ev_time
2662 );
2663
2664 /* Check double click */
2665 if((button_press_count == 0) &&
2666 (ev_last_time > 0) &&
2667 (ev_last_time <= ev_time) &&
2668 ((ev_time - ev_last_time) <= GW_2BUTTON_PRESS_INTERVAL)
2669 )
2670 {
2671 display->func_pointer(
2672 i, display->func_pointer_data,
2673 event.xbutton.x,
2674 event.xbutton.y,
2675 GWEventType2ButtonPress,
2676 btn_num,
2677 ev_time
2678 );
2679 display->button_press_count++;
2680 }
2681 /* Check triple click */
2682 else if((button_press_count == 1) &&
2683 (ev_last_time > 0) &&
2684 (ev_last_time <= ev_time) &&
2685 ((ev_time - ev_last_time) <= GW_3BUTTON_PRESS_INTERVAL)
2686 )
2687 {
2688 display->func_pointer(
2689 i, display->func_pointer_data,
2690 event.xbutton.x,
2691 event.xbutton.y,
2692 GWEventType3ButtonPress,
2693 btn_num,
2694 ev_time
2695 );
2696 display->button_press_count++;
2697 }
2698 else
2699 {
2700 display->button_press_count = 0;
2701 display->last_button_press = ev_time;
2702 }
2703
2704 events_handled++;
2705 break;
2706 }
2707 }
2708 break;
2709
2710 case ButtonRelease:
2711 if(gw_debug)
2712 printf(GW_DEBUG_PREFIX
2713 "Got XEvent ButtonRelease: window=0x%.8x button=%i x=%i y=%i\n",
2714 (u_int32_t)w,
2715 event.xbutton.button,
2716 event.xbutton.x,
2717 event.xbutton.y
2718 );
2719 for(i = 0; i < display->total_gl_contexts; i++)
2720 {
2721 if((display->toplevel[i] == w) &&
2722 (display->func_pointer != NULL)
2723 )
2724 {
2725 int btn_num = 0;
2726 switch(event.xbutton.button)
2727 {
2728 case Button1:
2729 btn_num = 1;
2730 break;
2731 case Button2:
2732 btn_num = 2;
2733 break;
2734 case Button3:
2735 btn_num = 3;
2736 break;
2737 case Button4:
2738 btn_num = 4;
2739 break;
2740 case Button5:
2741 btn_num = 5;
2742 break;
2743 }
2744 display->func_pointer(
2745 i, display->func_pointer_data,
2746 event.xbutton.x,
2747 event.xbutton.y,
2748 GWEventTypeButtonRelease,
2749 btn_num,
2750 event.xbutton.time
2751 );
2752 events_handled++;
2753 break;
2754 }
2755 }
2756 break;
2757
2758 case MotionNotify:
2759 for(i = 0; i < display->total_gl_contexts; i++)
2760 {
2761 if((display->toplevel[i] == w) &&
2762 (display->func_pointer != NULL)
2763 )
2764 {
2765 display->func_pointer(
2766 i, display->func_pointer_data,
2767 event.xmotion.x,
2768 event.xmotion.y,
2769 GWEventTypePointerMotion,
2770 0,
2771 event.xmotion.time
2772 );
2773 events_handled++;
2774 break;
2775 }
2776 }
2777 break;
2778
2779 case VisibilityNotify:
2780 if(gw_debug)
2781 printf(GW_DEBUG_PREFIX
2782 "Got XEvent VisibilityNotify: window=0x%.8x state=%i\n",
2783 (u_int32_t)w,
2784 event.xvisibility.state
2785 );
2786 for(i = 0; i < display->total_gl_contexts; i++)
2787 {
2788 if((display->toplevel[i] == w) &&
2789 (display->func_visibility != NULL)
2790 )
2791 {
2792 switch(event.xvisibility.state)
2793 {
2794 case VisibilityFullyObscured:
2795 display->func_visibility(
2796 i, display->func_visibility_data,
2797 GWVisibilityFullyObscured
2798 );
2799 break;
2800 case VisibilityPartiallyObscured:
2801 display->func_visibility(
2802 i, display->func_visibility_data,
2803 GWVisibilityPartiallyObscured
2804 );
2805 break;
2806 default:
2807 display->func_visibility(
2808 i, display->func_visibility_data,
2809 GWVisibilityUnobscured
2810 );
2811 break;
2812 }
2813 events_handled++;
2814 break;
2815 }
2816 }
2817 break;
2818
2819 case ClientMessage:
2820 cm = &event.xclient;
2821
2822 if(gw_debug && (cm->format == 32))
2823 {
2824 char *atom_name = XGetAtomName(
2825 display->display,
2826 cm->message_type
2827 );
2828 printf(GW_DEBUG_PREFIX
2829 "Got XEvent ClientMessage: window=0x%.8x message_type=0x%.8x atom_name=\"%s\"\n",
2830 (u_int32_t)cm->window,
2831 (u_int32_t)cm->message_type,
2832 atom_name
2833 );
2834 XFree(atom_name);
2835 }
2836
2837 /* Note, NEWER client messages have member
2838 * message_type set to the atom to determine the
2839 * type of message, while OLDER client messages use
2840 * member data.l[0] to determine message type and
2841 * message_type is always set to WM_PROTOCOLS
2842 */
2843
2844 /* WM close (from WM_DELETE_WINDOW) */
2845 if((cm->format == 32) &&
2846 (cm->data.l[0] == display->atom_wm_delete_window)
2847 )
2848 {
2849 for(i = 0; i < display->total_gl_contexts; i++)
2850 {
2851 if(display->toplevel[i] == cm->window)
2852 {
2853 glXWaitGL();
2854 glXWaitX();
2855 // glFinish();
2856 // XSync(display->display, False);
2857
2858 /* Call close callback */
2859 if(display->func_close != NULL)
2860 display->func_close(
2861 i, display->func_close_data,
2862 (void *)w
2863 );
2864
2865 events_handled++;
2866 break;
2867 }
2868 }
2869 }
2870 /* WM close (from _NET_CLOSE_WINDOW) */
2871 else if((cm->format == 32) &&
2872 (cm->message_type == display->atom_wm_close_window)
2873 )
2874 {
2875 for(i = 0; i < display->total_gl_contexts; i++)
2876 {
2877 if(display->toplevel[i] == cm->window)
2878 {
2879 glXWaitGL();
2880 glXWaitX();
2881 // glFinish();
2882 // XSync(display->display, False);
2883
2884 /* Call close callback */
2885 if(display->func_close != NULL)
2886 display->func_close(
2887 i, display->func_close_data,
2888 (void *)w
2889 );
2890
2891 events_handled++;
2892 break;
2893 }
2894 }
2895 }
2896 /* WM ping */
2897 else if((cm->format == 32) &&
2898 (cm->data.l[0] == display->atom_wm_ping)
2899 )
2900 {
2901 /*
2902 const long timestamp = cm->data.l[1];
2903 */
2904 for(i = 0; i < display->total_gl_contexts; i++)
2905 {
2906 if(display->toplevel[i] == cm->window)
2907 {
2908 /* Respond to ping */
2909 event.xany.window = display->root;
2910 event.xclient.window = display->root;
2911 XSendEvent(
2912 display->display,
2913 display->root,
2914 False,
2915 SubstructureNotifyMask | SubstructureRedirectMask,
2916 &event
2917 );
2918
2919 events_handled++;
2920 break;
2921 }
2922 }
2923 }
2924 /* Save yourself */
2925 else if((cm->format == 32) &&
2926 (cm->data.l[0] == display->atom_wm_save_yourself)
2927 )
2928 {
2929 for(i = 0; i < display->total_gl_contexts; i++)
2930 {
2931 if(display->toplevel[i] == cm->window)
2932 {
2933 glXWaitGL();
2934 glXWaitX();
2935 // glFinish();
2936 // XSync(display->display, False);
2937
2938 /* Call save yourself callback */
2939 if(display->func_save_yourself != NULL)
2940 display->func_save_yourself(
2941 i, display->func_save_yourself_data
2942 );
2943
2944 events_handled++;
2945 break;
2946 }
2947 }
2948 }
2949 /* Take focus */
2950 else if((cm->format == 32) &&
2951 (cm->data.l[0] == display->atom_wm_take_focus)
2952 )
2953 {
2954 for(i = 0; i < display->total_gl_contexts; i++)
2955 {
2956 if(display->toplevel[i] == cm->window)
2957 {
2958 #if 0
2959 /* Don't need to rebind the GL context */
2960 glXWaitX();
2961 glXMakeCurrent(
2962 display->display,
2963 display->toplevel[i],
2964 display->glx_context[i]
2965 );
2966 glXWaitGL();
2967 #endif
2968 events_handled++;
2969 break;
2970 }
2971 }
2972 }
2973 /* Work area (viewport, from _NET_WORKAREA) */
2974 else if((cm->format == 32) &&
2975 (cm->message_type == display->atom_wm_workarea)
2976 )
2977 {
2978 for(i = 0; i < display->total_gl_contexts; i++)
2979 {
2980 if(display->toplevel[i] == cm->window)
2981 {
2982 display->viewport_x = (int)cm->data.l[0];
2983 display->viewport_y = (int)cm->data.l[1];
2984 display->viewport_width = (int)cm->data.l[2];
2985 display->viewport_height = (int)cm->data.l[3];
2986
2987 events_handled++;
2988 break;
2989 }
2990 }
2991 }
2992 break;
2993
2994 default:
2995 /* Some extension type event */
2996 #ifdef XF86VIDMODE_H
2997 /* XF86 VidMode change? */
2998 if(display->has_vidmode_ext)
2999 {
3000 #ifdef XF86VidModeNotify
3001 if(event.type == (display->vidmode_ext_event_offset +
3002 XF86VidModeNotify)
3003 )
3004 {
3005 if(gw_debug)
3006 printf(
3007 GW_DEBUG_PREFIX
3008 "Got event %i XF86VidModeNotify\n",
3009 event.type
3010 );
3011 }
3012 #endif /* XF86VidModeNotify */
3013 #ifdef XF86VidModeModeChange
3014 if(event.type == (display->vidmode_ext_event_offset +
3015 XF86VidModeModeChange)
3016 )
3017 {
3018
3019 if(gw_debug)
3020 printf(
3021 GW_DEBUG_PREFIX
3022 "Got event %i XF86VidModeModeChange\n",
3023 event.type
3024 );
3025 }
3026 #endif /* XF86VidModeModeChange */
3027 }
3028 #endif /* XF86VIDMODE_H */
3029 break;
3030 }
3031
3032 /* Hand event message off to dialog management functions */
3033 GWXDialogManage(
3034 display, &display->mesg_dialog, &event
3035 );
3036 GWXDialogManage(
3037 display, &display->conf_dialog, &event
3038 );
3039
3040 }
3041 }
3042
3043 /* Any pending posted draws for the current context? */
3044 if(display->gl_context_num > -1)
3045 {
3046 int ctx_num = display->gl_context_num;
3047 if((ctx_num >= 0) && (ctx_num < display->total_gl_contexts))
3048 {
3049 if(display->draw_count[ctx_num] > 0)
3050 {
3051 /* Posted draws are pending, call draw function
3052 * and reset draw count.
3053 */
3054 if(display->func_draw != NULL)
3055 display->func_draw(
3056 ctx_num, display->func_draw_data
3057 );
3058 display->draw_count[ctx_num] = 0;
3059 }
3060 }
3061 }
3062
3063 /* Always call the timeout function once per call */
3064 if(display->func_timeout != NULL)
3065 display->func_timeout(display->func_timeout_data);
3066 }
3067 #endif /* X_H */
3068
3069 #ifdef X_H
3070 /*
3071 * Graphics wrapper shutdown.
3072 */
GWShutdown(gw_display_struct * display)3073 void GWShutdown(gw_display_struct *display)
3074 {
3075 Display *dpy;
3076
3077 if(display == NULL)
3078 return;
3079
3080 if(gw_debug)
3081 printf(GW_DEBUG_PREFIX
3082 "Beginning shutdown...\n"
3083 );
3084
3085 /* Turn the keyboard auto repeat back on to avoid
3086 messing with the operating system.
3087 - Jesse
3088 */
3089 XAutoRepeatOn(display->display);
3090
3091 /* If was in full screen mode then switch back to GUI mode
3092 * first before shutdown
3093 */
3094 if(display->fullscreen)
3095 {
3096 if(display->fullscreen_context_num != display->gl_context_num)
3097 GWContextSet(display, display->fullscreen_context_num);
3098 GWContextFullScreen(display, False);
3099 }
3100
3101 /* Get pointer to X display structure */
3102 dpy = display->display;
3103 if(dpy != NULL)
3104 {
3105 int i;
3106 Cursor *cursor;
3107
3108
3109 /* Destroy dialog widgets and resources */
3110 GWXDialogDestroy(
3111 display, &display->mesg_dialog
3112 );
3113 GWXDialogDestroy(
3114 display, &display->conf_dialog
3115 );
3116
3117
3118 /* Destroy all gl contexts and toplevel Windows, current
3119 * gl context will be disabled first as needed.
3120 */
3121 for(i = display->total_gl_contexts - 1; i >= 0; i--)
3122 GWContextDelete(display, i);
3123
3124 /* Deallocate pointer arrays for all gl contexts and
3125 * toplevel Windows.
3126 */
3127 free(display->glx_context);
3128 display->glx_context = NULL;
3129 free(display->toplevel);
3130 display->toplevel = NULL;
3131 free(display->toplevel_geometry);
3132 display->toplevel_geometry = NULL;
3133 free(display->draw_count);
3134 display->draw_count = NULL;
3135 display->total_gl_contexts = 0;
3136 display->gl_context_num = -1;
3137
3138 /* Ungrab pointer once more just in case */
3139 GWUngrabPointer(display);
3140
3141 /* Destroy cursors */
3142 #define DO_DESTROY_CURSOR \
3143 { if(cursor != NULL) { \
3144 if(*cursor != None) { \
3145 xerrval = 0; \
3146 XFreeCursor(dpy, *cursor); \
3147 if(xerrval && gw_debug) \
3148 printf(GW_DEBUG_PREFIX \
3149 "XFreeCursor(): Error destroying Cursor 0x%.8x.\n", \
3150 (u_int32_t)(*cursor) \
3151 ); \
3152 *cursor = None; \
3153 } } }
3154 cursor = &display->cursor_standard;
3155 DO_DESTROY_CURSOR
3156 cursor = &display->cursor_busy;
3157 DO_DESTROY_CURSOR
3158 cursor = &display->cursor_text;
3159 DO_DESTROY_CURSOR
3160 cursor = &display->cursor_translate;
3161 DO_DESTROY_CURSOR
3162 cursor = &display->cursor_zoom;
3163 DO_DESTROY_CURSOR
3164 cursor = &display->cursor_invisible;
3165 DO_DESTROY_CURSOR
3166 #undef DO_DESTROY_CURSOR
3167
3168 /* Turn on keyboard autorepeat */
3169 /* We do this above.
3170 - Jesse
3171 GWKeyboardAutoRepeat(display, True); */
3172
3173 if(gw_debug)
3174 printf(GW_DEBUG_PREFIX
3175 "Closing X display...\n"
3176 );
3177
3178 /* Free Colormap */
3179 if(display->colormap != None)
3180 {
3181 XFreeColormap(dpy, display->colormap);
3182 display->colormap = None;
3183 }
3184
3185 /* Destroy XVisualInfo structure */
3186 if(display->visual_info != NULL)
3187 {
3188 XFree(display->visual_info);
3189 display->visual_info = NULL;
3190 }
3191
3192 /* Close connection to X server */
3193 XCloseDisplay(dpy);
3194 display->display = dpy = NULL;
3195 }
3196
3197 /* Deallocate other display structure resources */
3198 free(display->def_xfont_name);
3199
3200 /* Deallocate graphics wrapper display structure itself */
3201 free(display);
3202
3203 if(gw_debug)
3204 printf(GW_DEBUG_PREFIX
3205 "Shutdown done.\n"
3206 );
3207 }
3208 #endif /* X_H */
3209
3210
3211 #ifdef X_H
3212 /*
3213 * Flushes output.
3214 */
GWFlush(gw_display_struct * display)3215 void GWFlush(gw_display_struct *display)
3216 {
3217 if(display == NULL)
3218 return;
3219
3220 XFlush(display->display);
3221 glXWaitGL();
3222 // glFinish();
3223 }
3224 #endif /* X_H */
3225
3226 #ifdef X_H
3227 /*
3228 * Sync output.
3229 */
GWSync(gw_display_struct * display)3230 void GWSync(gw_display_struct *display)
3231 {
3232 if(display == NULL)
3233 return;
3234
3235 XSync(display->display, False);
3236 glXWaitGL();
3237 // glFinish();
3238 }
3239 #endif /* X_H */
3240
3241 #ifdef X_H
3242 /*
3243 * Returns the number of events pending.
3244 */
GWEventsPending(gw_display_struct * display)3245 int GWEventsPending(gw_display_struct *display)
3246 {
3247 return((display != NULL) ? XPending(display->display) : 0);
3248 }
3249 #endif /* X_H */
3250
3251
3252 #ifdef X_H
3253 /*
3254 * Output message.
3255 */
GWOutputMessage(gw_display_struct * display,int type,const char * subject,const char * message,const char * help_details)3256 void GWOutputMessage(
3257 gw_display_struct *display,
3258 int type, /* One of GWOutputMessageType* */
3259 const char *subject,
3260 const char *message,
3261 const char *help_details
3262 )
3263 {
3264 gwx_dialog_struct *dialog;
3265 gwx_button_struct *btn;
3266
3267 if(display == NULL)
3268 return;
3269
3270 dialog = &display->mesg_dialog;
3271
3272 switch(type)
3273 {
3274 case GWOutputMessageTypeWarning:
3275 GWXDialogLoadIcon(
3276 display, dialog,
3277 GWX_ICON_WARNING
3278 );
3279 break;
3280
3281 case GWOutputMessageTypeError:
3282 GWXDialogLoadIcon(
3283 display, dialog,
3284 GWX_ICON_ERROR
3285 );
3286 break;
3287
3288 case GWOutputMessageTypeQuestion:
3289 GWXDialogLoadIcon(
3290 display, dialog,
3291 GWX_ICON_QUESTION
3292 );
3293 break;
3294
3295 default:
3296 GWXDialogLoadIcon(
3297 display, dialog,
3298 GWX_ICON_INFO
3299 );
3300 break;
3301 }
3302
3303 /* Set dialog message */
3304 GWXDialogSetMesg(
3305 display, dialog,
3306 subject, message, help_details
3307 );
3308
3309 /* Set OK button as the default button */
3310 btn = &dialog->ok_btn;
3311 GWXWidgetGrabDefault(display, GWX_WIDGET(btn));
3312 GWXWidgetFocus(display, GWX_WIDGET(btn));
3313
3314 /* Map and draw dialog */
3315 GWXDialogMap(display, dialog);
3316 }
3317 #endif /* X_H */
3318
3319 #ifdef X_H
3320 /*
3321 * Blocks client execution until confirmation is returned.
3322 * Returns one of GWConfirmation*.
3323 *
3324 * If this function is called while already blocking then
3325 * GWConfirmationNotAvailable will be returned immediatly.
3326 */
GWConfirmation(gw_display_struct * display,int type,const char * subject,const char * message,const char * help_details,int default_response)3327 int GWConfirmation(
3328 gw_display_struct *display,
3329 int type, /* One of GWOutputMessageType* */
3330 const char *subject,
3331 const char *message,
3332 const char *help_details,
3333 int default_response /* One of GWConfirmation* */
3334 )
3335 {
3336 static Boolean reenterant = False;
3337 int status;
3338 gwx_dialog_struct *dialog;
3339 gwx_button_struct *btn;
3340
3341
3342 if(reenterant)
3343 return(GWConfirmationNotAvailable);
3344 else
3345 reenterant = True;
3346
3347 /* Is display valid? */
3348 if(display == NULL)
3349 {
3350 /* No display, so return with GWConfirmationNotAvailable */
3351 reenterant = False;
3352 return(GWConfirmationNotAvailable);
3353 }
3354 else
3355 {
3356 /* Get pointer to dialog */
3357 dialog = &display->conf_dialog;
3358 }
3359
3360 /* Load icon */
3361 switch(type)
3362 {
3363 case GWOutputMessageTypeWarning:
3364 GWXDialogLoadIcon(
3365 display, dialog,
3366 GWX_ICON_WARNING
3367 );
3368 break;
3369
3370 case GWOutputMessageTypeError:
3371 GWXDialogLoadIcon(
3372 display, dialog,
3373 GWX_ICON_ERROR
3374 );
3375 break;
3376
3377 case GWOutputMessageTypeQuestion:
3378 GWXDialogLoadIcon(
3379 display, dialog,
3380 GWX_ICON_QUESTION
3381 );
3382 break;
3383
3384 default:
3385 GWXDialogLoadIcon(
3386 display, dialog,
3387 GWX_ICON_INFO
3388 );
3389 break;
3390 }
3391
3392 /* Set message */
3393 GWXDialogSetMesg(
3394 display, dialog,
3395 subject, message, help_details
3396 );
3397
3398 /* Set default button in accordance with the confirmation */
3399 btn = &dialog->yes_btn;
3400 GWXWidgetUngrabDefault(display, GWX_WIDGET(btn));
3401 GWXWidgetUnfocus(display, GWX_WIDGET(btn));
3402 btn = &dialog->no_btn;
3403 GWXWidgetUngrabDefault(display, GWX_WIDGET(btn));
3404 GWXWidgetUnfocus(display, GWX_WIDGET(btn));
3405 btn = &dialog->cancel_btn;
3406 GWXWidgetUngrabDefault(display, GWX_WIDGET(btn));
3407 GWXWidgetUnfocus(display, GWX_WIDGET(btn));
3408 switch(default_response)
3409 {
3410 case GWConfirmationNo:
3411 btn = &dialog->no_btn;
3412 break;
3413 case GWConfirmationYes:
3414 btn = &dialog->yes_btn;
3415 break;
3416 case GWConfirmationCancel:
3417 btn = &dialog->no_btn;
3418 break;
3419 }
3420 GWXWidgetGrabDefault(display, GWX_WIDGET(btn));
3421 GWXWidgetFocus(display, GWX_WIDGET(btn));
3422
3423 GWXDialogMap(display, dialog);
3424
3425 /* Block until confirmation is recieved */
3426 status = GWXDoBlockUntilConf(display);
3427
3428 /* Unmap confirmation dialog */
3429 GWXWidgetUnmap(display, GWX_WIDGET(dialog));
3430
3431 reenterant = False;
3432 return(status);
3433 }
3434 #endif /* X_H */
3435
3436 #ifdef X_H
3437 /*
3438 * Block client execution until confirmation is returned.
3439 * Returns one of GWConfirmation*.
3440 */
GWConfirmationSimple(gw_display_struct * display,const char * message)3441 int GWConfirmationSimple(
3442 gw_display_struct *display, const char *message
3443 )
3444 {
3445 return(GWConfirmation(
3446 display,
3447 GWOutputMessageTypeQuestion,
3448 "Confirmation",
3449 message,
3450 NULL,
3451 GWConfirmationYes
3452 ));
3453 }
3454 #endif /* X_H */
3455
3456 #ifdef X_H
3457 /*
3458 * Sets redraw (expose) callback function:
3459 */
GWSetDrawCB(gw_display_struct * display,void (* func)(int,void *),void * data)3460 void GWSetDrawCB(
3461 gw_display_struct *display,
3462 void (*func)(int, void *),
3463 void *data
3464 )
3465 {
3466 if(display == NULL)
3467 return;
3468
3469 display->func_draw = func;
3470 display->func_draw_data = data;
3471 }
3472
3473 /*
3474 * Sets resize (configure notify) callback function:
3475 */
GWSetResizeCB(gw_display_struct * display,void (* func)(int,void *,int,int,int,int),void * data)3476 void GWSetResizeCB(
3477 gw_display_struct *display,
3478 void (*func)(int, void *, int, int, int, int),
3479 void *data
3480 )
3481 {
3482 if(display == NULL)
3483 return;
3484
3485 display->func_resize = func;
3486 display->func_resize_data = data;
3487 }
3488
3489 /*
3490 * Sets keyboard event callback function:
3491 */
GWSetKeyboardCB(gw_display_struct * display,void (* func)(void *,int,Boolean,unsigned long),void * data)3492 void GWSetKeyboardCB(
3493 gw_display_struct *display,
3494 void (*func)(void *, int, Boolean, unsigned long),
3495 void *data
3496 )
3497 {
3498 if(display == NULL)
3499 return;
3500
3501 display->func_keyboard = func;
3502 display->func_keyboard_data = data;
3503 }
3504
3505 /*
3506 * Sets visibility notify callback function:
3507 */
GWSetVisibilityCB(gw_display_struct * display,void (* func)(int,void *,gw_visibility),void * data)3508 void GWSetVisibilityCB(
3509 gw_display_struct *display,
3510 void (*func)(int, void *, gw_visibility),
3511 void *data
3512 )
3513 {
3514 if(display == NULL)
3515 return;
3516
3517 display->func_visibility = func;
3518 display->func_visibility_data = data;
3519 }
3520
3521 /*
3522 * Sets pointer event callback function:
3523 */
GWSetPointerCB(gw_display_struct * display,void (* func)(int,void *,int,int,gw_event_type,int,unsigned long),void * data)3524 void GWSetPointerCB(
3525 gw_display_struct *display,
3526 void (*func)(int, void *, int, int, gw_event_type, int, unsigned long),
3527 void *data
3528 )
3529 {
3530 if(display == NULL)
3531 return;
3532
3533 display->func_pointer = func;
3534 display->func_pointer_data = data;
3535 }
3536
3537 /*
3538 * Sets save yourself callback function:
3539 */
GWSetSaveYourselfCB(gw_display_struct * display,void (* func)(int,void *),void * data)3540 void GWSetSaveYourselfCB(
3541 gw_display_struct *display,
3542 void (*func)(int, void *),
3543 void *data
3544 )
3545 {
3546 if(display == NULL)
3547 return;
3548
3549 display->func_save_yourself = func;
3550 display->func_save_yourself_data = data;
3551 }
3552
3553 /*
3554 * Sets window close (delete event) callback function:
3555 */
GWSetCloseCB(gw_display_struct * display,void (* func)(int,void *,void *),void * data)3556 void GWSetCloseCB(
3557 gw_display_struct *display,
3558 void (*func)(int, void *, void *),
3559 void *data
3560 )
3561 {
3562 if(display == NULL)
3563 return;
3564
3565 display->func_close = func;
3566 display->func_close_data = data;
3567 }
3568
3569 /*
3570 * Sets timeout (idle) callback function:
3571 */
GWSetTimeoutCB(gw_display_struct * display,void (* func)(void *),void * data)3572 void GWSetTimeoutCB(
3573 gw_display_struct *display,
3574 void (*func)(void *),
3575 void *data
3576 )
3577 {
3578 if(display == NULL)
3579 return;
3580
3581 display->func_timeout = func;
3582 display->func_timeout_data = data;
3583 }
3584 #endif /* X_H */
3585
3586
3587 #ifdef X_H
3588 /*
3589 * Creates a new GL context and window, returning the context
3590 * number or -1 on error.
3591 */
GWContextNew(gw_display_struct * display,int x,int y,int width,int height,const char * title,const char * icon_path,const char * icon_name,Bool no_windows)3592 int GWContextNew(
3593 gw_display_struct *display,
3594 int x, int y, int width, int height,
3595 const char *title,
3596 const char *icon_path, const char *icon_name,
3597 Bool no_windows
3598 )
3599 {
3600 Display *dpy;
3601 Window w;
3602 GLXContext glx_context;
3603 XRectangle *rect;
3604 int ctx_num;
3605
3606
3607 if(display == NULL)
3608 return(-1);
3609
3610 dpy = display->display;
3611 if(dpy == NULL)
3612 return(-1);
3613
3614 /* Search for an available GL context index number */
3615 for(ctx_num = 0; ctx_num < display->total_gl_contexts; ctx_num++)
3616 {
3617 w = display->toplevel[ctx_num];
3618 glx_context = display->glx_context[ctx_num];
3619
3620 /* Is this GL context index available? */
3621 if((w == None) && (glx_context == NULL))
3622 break;
3623 }
3624 /* No available GL contexts? */
3625 if(ctx_num >= display->total_gl_contexts)
3626 {
3627 /* Allocate a new gl context */
3628
3629 ctx_num = MAX(display->total_gl_contexts, 0);
3630 display->total_gl_contexts = ctx_num + 1;
3631
3632 display->glx_context = (GLXContext *)realloc(
3633 display->glx_context,
3634 display->total_gl_contexts * sizeof(GLXContext)
3635 );
3636 display->toplevel = (Window *)realloc(
3637 display->toplevel,
3638 display->total_gl_contexts * sizeof(Window)
3639 );
3640 display->toplevel_geometry = (XRectangle *)realloc(
3641 display->toplevel_geometry,
3642 display->total_gl_contexts * sizeof(XRectangle)
3643 );
3644 display->draw_count = (int *)realloc(
3645 display->draw_count,
3646 display->total_gl_contexts * sizeof(int)
3647 );
3648 if((display->glx_context == NULL) || (display->toplevel == NULL) ||
3649 (display->toplevel_geometry == NULL) || (display->draw_count == NULL)
3650 )
3651 {
3652 display->gl_context_num = -1;
3653 display->total_gl_contexts = 0;
3654 return(-1);
3655 }
3656 }
3657
3658 /* At this point we have an available GL context specified by
3659 * ctx_num
3660 */
3661
3662 /* Create GL rendering context */
3663 display->glx_context[ctx_num] = glx_context = glXCreateContext(
3664 dpy,
3665 display->visual_info, /* Visual info */
3666 NULL, /* Share list (none) */
3667 (display->direct_rendering) ? GL_TRUE : GL_FALSE /* Direct rendering? */
3668 );
3669 if(glx_context == NULL)
3670 {
3671 if(gw_debug)
3672 printf(GW_DEBUG_PREFIX
3673 "glXCreateContext(): Cannot create glX %s rendering context.\n",
3674 (display->direct_rendering) ? "hardware" : "software"
3675 );
3676
3677 fprintf(
3678 stderr,
3679 "Error creating glX %s rendering context.\n",
3680 (display->direct_rendering) ? "hardware" : "software"
3681 );
3682 if(display->direct_rendering)
3683 fprintf(
3684 stderr,
3685 "Try software rendering instead (add argument \"--software\")?\n"
3686 );
3687 }
3688 else
3689 {
3690 glXWaitGL(); /* Wait for GL context to be created */
3691 // glFinish();
3692 if(gw_debug)
3693 printf(GW_DEBUG_PREFIX
3694 "glXCreateContext(): Created glX %s rendering context.\n",
3695 (display->direct_rendering) ? "hardware" : "software"
3696 );
3697 }
3698
3699 /* Create first toplevel window and buffer */
3700 if(!no_windows)
3701 {
3702 /* Set initial geometry of new Window before creation */
3703 rect = &display->toplevel_geometry[ctx_num];
3704 rect->x = x;
3705 rect->y = y;
3706 rect->width = (unsigned int)width;
3707 rect->height = (unsigned int)height;
3708
3709 /* Create first toplevel Window */
3710 display->toplevel[ctx_num] = w = GWCreateWindow(
3711 display,
3712 display->root,
3713 x, y,
3714 width, height,
3715 title
3716 );
3717 if(w == None)
3718 {
3719 /* Error creating Window */
3720 fprintf(
3721 stderr,
3722 "Error creating toplevel window for GL context %i.\n",
3723 ctx_num
3724 );
3725 return(-1);
3726 }
3727 else
3728 {
3729 XTextProperty *t;
3730 XClassHint *class_hint;
3731
3732 /* Set the Window's WM Name */
3733 t = (XTextProperty *)malloc(sizeof(XTextProperty));
3734 if(t != NULL)
3735 {
3736 if(!STRISEMPTY(title))
3737 {
3738 t->value = (unsigned char *)title;
3739 t->encoding = XA_STRING;
3740 t->format = 8;
3741 t->nitems = STRLEN(title);
3742 xerrval = 0;
3743 XSetWMName(dpy, w, t);
3744 if(xerrval && gw_debug)
3745 printf(GW_DEBUG_PREFIX
3746 "GWContextNew(): Error setting the WM name for window 0x%.8x.\n",
3747 (u_int32_t)w
3748 );
3749 }
3750 free(t);
3751 }
3752
3753 /* Set the Window's WM Class Hint */
3754 class_hint = XAllocClassHint();
3755 if(class_hint != NULL)
3756 {
3757 if(!STRISEMPTY(title))
3758 {
3759 class_hint->res_name = "toplevel";
3760 class_hint->res_class = (char *)title;
3761 xerrval = 0;
3762 XSetClassHint(dpy, w, class_hint);
3763 if(xerrval && gw_debug)
3764 printf(GW_DEBUG_PREFIX
3765 "GWContextNew(): Error setting the WM class for window 0x%.8x.\n",
3766 (u_int32_t)w
3767 );
3768 }
3769 XFree(class_hint);
3770 }
3771
3772 /* Set the Window's WM Icon */
3773 GWSetWindowIconFile(
3774 display, ctx_num, icon_path, icon_name
3775 );
3776
3777 /* Map the Window */
3778 xerrval = 0;
3779 XMapRaised(dpy, w);
3780 if(xerrval && gw_debug)
3781 printf(GW_DEBUG_PREFIX
3782 "XMapRaised(): Error maping and raising Window 0x%.8x.\n",
3783 (u_int32_t)w
3784 );
3785
3786 /* Need to move window after mapping it, because the WM
3787 * often places it at the wrong sport despite giving
3788 * proper hints as to the creation position
3789 */
3790 xerrval = 0;
3791 XMoveWindow(dpy, w, x, y);
3792 if(xerrval && gw_debug)
3793 printf(GW_DEBUG_PREFIX
3794 "XMoveWindow(): Error moving Window 0x%.8x.\n",
3795 (u_int32_t)w
3796 );
3797
3798 glXWaitX(); /* Wait for X window creation commands to finish */
3799 // XSync(display->display, False);
3800 }
3801 display->draw_count[ctx_num] = 0;
3802 }
3803 else
3804 {
3805 rect = &display->toplevel_geometry[ctx_num];
3806 memset(rect, 0x00, sizeof(XRectangle));
3807 display->toplevel[ctx_num] = None;
3808 display->draw_count[ctx_num] = 0;
3809 }
3810 if(gw_debug)
3811 printf(GW_DEBUG_PREFIX
3812 "Created gl context number %i.\n",
3813 ctx_num
3814 );
3815
3816 return(ctx_num);
3817 }
3818 #endif /* X_H */
3819
3820 #ifdef X_H
3821 /*
3822 * Destroys the gl context and window given by the context number
3823 * ctx_num. If the specified gl context is the current gl context
3824 * then the current gl context will be no longer valid.
3825 */
GWContextDelete(gw_display_struct * display,int ctx_num)3826 void GWContextDelete(
3827 gw_display_struct *display, int ctx_num
3828 )
3829 {
3830 Display *dpy;
3831 Window w;
3832 GLXContext glx_context;
3833 XRectangle *rect;
3834
3835
3836 if(display == NULL)
3837 return;
3838
3839 dpy = display->display;
3840 if(dpy == NULL)
3841 return;
3842
3843 if((ctx_num < 0) || (ctx_num >= display->total_gl_contexts))
3844 return;
3845
3846 if(gw_debug)
3847 printf(GW_DEBUG_PREFIX
3848 "Destroying gl context number %i...\n",
3849 ctx_num
3850 );
3851
3852 /* Is the given gl context the current gl context? */
3853 if(ctx_num == display->gl_context_num)
3854 {
3855 display->gl_context_num = -1;
3856
3857 if(gw_debug)
3858 printf(GW_DEBUG_PREFIX
3859 "Disabling current gl context because it is about to be destroyed...\n"
3860 );
3861
3862 glXWaitX();
3863 // XSync(display->display, False);
3864 glXMakeCurrent(dpy, None, NULL);
3865 glXWaitGL();
3866 // glFinish();
3867 }
3868
3869 /* Begin destroying the Window */
3870 w = display->toplevel[ctx_num];
3871 if(w != None)
3872 {
3873 XWMHints *wm_hints;
3874
3875 /* If this context's window is grabbing the pointer then
3876 * ungrab the pointer before destroying the window.
3877 */
3878 if(display->grab_window == w)
3879 GWUngrabPointer(display);
3880
3881 /* Get WM hints of window */
3882 xerrval = 0;
3883 wm_hints = XGetWMHints(dpy, w);
3884 if(!xerrval && (wm_hints != NULL))
3885 {
3886 /* Deallocate resources of window specified in the WM
3887 * hints structure.
3888 */
3889 if(wm_hints->flags & IconWindowHint)
3890 if(wm_hints->icon_window != None)
3891 DESTROY_WINDOW(&wm_hints->icon_window);
3892 if(wm_hints->flags & IconPixmapHint)
3893 if(wm_hints->icon_pixmap != None)
3894 FREE_PIXMAP(&wm_hints->icon_pixmap);
3895 if(wm_hints->flags & IconMaskHint)
3896 if(wm_hints->icon_mask != None)
3897 FREE_BITMAP(&wm_hints->icon_mask);
3898
3899 /* Deallocate recieved WM hints structure */
3900 XFree(wm_hints);
3901 }
3902
3903 /* Destroy the toplevel Window */
3904 xerrval = 0;
3905 DESTROY_WINDOW(&w);
3906 if(xerrval && gw_debug)
3907 printf(GW_DEBUG_PREFIX
3908 "XDestroyWindow(): Error destroying window 0x%.8x.\n",
3909 (u_int32_t)display->toplevel[ctx_num]
3910 );
3911 else if(gw_debug)
3912 printf(GW_DEBUG_PREFIX
3913 "Destroyed window 0x%.8x.\n",
3914 (u_int32_t)display->toplevel[ctx_num]
3915 );
3916 display->toplevel[ctx_num] = None;
3917
3918 glXWaitX(); /* Wait for X window destroy commands to finish */
3919 // XSync(display->display, False);
3920 }
3921
3922 /* Begin destroying the gl context */
3923 glx_context = display->glx_context[ctx_num];
3924 if(glx_context != NULL)
3925 {
3926 /* Destroy gl context */
3927 glXDestroyContext(dpy, glx_context);
3928 if(gw_debug)
3929 printf(GW_DEBUG_PREFIX
3930 "Destroyed glX context 0x%.8x.\n",
3931 (u_int32_t)glx_context
3932 );
3933 display->glx_context[ctx_num] = glx_context = NULL;
3934
3935 // glXWaitGL(); /* Wait for GL context destroy commands to finish */
3936 }
3937
3938 /* Clear the toplevel rectangle */
3939 rect = &display->toplevel_geometry[ctx_num];
3940 memset(rect, 0x00, sizeof(XRectangle));
3941
3942 /* Reset draw count */
3943 display->draw_count[ctx_num] = 0;
3944
3945 if(gw_debug)
3946 printf(GW_DEBUG_PREFIX
3947 "Destroyed gl context number %i.\n",
3948 ctx_num
3949 );
3950 }
3951 #endif /* X_H */
3952
3953 #ifdef X_H
3954 /*
3955 * Returns the current GL context number or -1 on error.
3956 */
GWContextCurrent(gw_display_struct * display)3957 int GWContextCurrent(gw_display_struct *display)
3958 {
3959 return((display != NULL) ?
3960 MIN(display->gl_context_num, display->total_gl_contexts - 1) : -1
3961 );
3962 }
3963 #endif /* X_H */
3964
3965 #ifdef X_H
3966 /*
3967 * Gets the opaque handle of the Window and the GL rendering
3968 * context of the specified GL context.
3969 *
3970 * Returns non-zero on error.
3971 */
GWContextGet(gw_display_struct * display,int ctx_num,void ** window_id_rtn,void ** gl_context_rtn,int * x_rtn,int * y_rtn,int * width_rtn,int * height_rtn)3972 int GWContextGet(
3973 gw_display_struct *display, int ctx_num,
3974 void **window_id_rtn, void **gl_context_rtn,
3975 int *x_rtn, int *y_rtn, int *width_rtn, int *height_rtn
3976 )
3977 {
3978 Display *dpy = (display != NULL) ? display->display : NULL;
3979 Window w;
3980 GLXContext glx_context;
3981 const XRectangle *rect;
3982
3983
3984 if(window_id_rtn != NULL)
3985 *window_id_rtn = NULL;
3986 if(gl_context_rtn != NULL)
3987 *gl_context_rtn = NULL;
3988 if(x_rtn != NULL)
3989 *x_rtn = 0;
3990 if(y_rtn != NULL)
3991 *y_rtn = 0;
3992 if(width_rtn != NULL)
3993 *width_rtn = 0;
3994 if(height_rtn != NULL)
3995 *height_rtn = 0;
3996
3997 if(dpy == NULL)
3998 return(-1);
3999
4000 if((ctx_num < 0) || (ctx_num >= display->total_gl_contexts))
4001 return(-1);
4002
4003 w = display->toplevel[ctx_num];
4004 glx_context = display->glx_context[ctx_num];
4005 rect = &display->toplevel_geometry[ctx_num];
4006
4007 if((w == None) || (glx_context == NULL))
4008 return(-1);
4009
4010
4011 if(window_id_rtn != NULL)
4012 *window_id_rtn = (void *)w;
4013 if(gl_context_rtn != NULL)
4014 *gl_context_rtn = (void *)glx_context;
4015
4016 if(x_rtn != NULL)
4017 *x_rtn = (int)rect->x;
4018 if(y_rtn != NULL)
4019 *y_rtn = (int)rect->y;
4020 if(width_rtn != NULL)
4021 *width_rtn = (int)rect->width;
4022 if(height_rtn != NULL)
4023 *height_rtn = (int)rect->height;
4024
4025 return(0);
4026 }
4027 #endif /* X_H */
4028
4029 #ifdef X_H
4030 /*
4031 * Puts the GL rendering context specified by ctx_num as the
4032 * current rendering GL context.
4033 *
4034 * Returns non-zero on error.
4035 */
GWContextSet(gw_display_struct * display,int ctx_num)4036 int GWContextSet(gw_display_struct *display, int ctx_num)
4037 {
4038 Display *dpy;
4039 Window w;
4040 GLXContext glx_context;
4041
4042
4043 if(display == NULL)
4044 return(-1);
4045
4046 dpy = display->display;
4047 if(dpy == NULL)
4048 return(-1);
4049
4050 if((ctx_num < 0) || (ctx_num >= display->total_gl_contexts))
4051 return(-1);
4052
4053 /* Specified gl context already the current gl context? */
4054 if(ctx_num == display->gl_context_num)
4055 return(0);
4056
4057
4058 /* Get Window and gl context of the specified context */
4059 w = display->toplevel[ctx_num];
4060 glx_context = display->glx_context[ctx_num];
4061
4062 if((w == None) || (glx_context == NULL))
4063 return(-1);
4064
4065 glXWaitX(); /* Wait for X commands to finish */
4066 // XSync(display->display, False);
4067
4068 /* Make selected GL context current */
4069 if(glXMakeCurrent(dpy, (GLXDrawable)w, glx_context))
4070 {
4071 display->gl_context_num = ctx_num;
4072 glXWaitGL(); /* Wait for GL context switch commands to finish */
4073 // glFinish();
4074 return(0);
4075 }
4076 else
4077 {
4078 return(-1);
4079 }
4080 }
4081 #endif /* X_H */
4082
4083 #ifdef X_H
4084 /*
4085 * Sets the position of the current GL rendering context.
4086 */
GWContextPosition(gw_display_struct * display,int x,int y)4087 void GWContextPosition(
4088 gw_display_struct *display, int x, int y
4089 )
4090 {
4091 Display *dpy = (display != NULL) ? display->display : NULL;
4092 int ctx_num;
4093 Window w;
4094 XRectangle *rect;
4095 if(dpy == NULL)
4096 return;
4097
4098 ctx_num = display->gl_context_num;
4099 if((ctx_num >= 0) && (ctx_num < display->total_gl_contexts))
4100 {
4101 w = display->toplevel[ctx_num];
4102 rect = &display->toplevel_geometry[ctx_num];
4103 }
4104 else
4105 {
4106 w = None;
4107 rect = NULL;
4108 }
4109 if(w == None)
4110 return;
4111
4112 if((x != rect->x) || (y != rect->y))
4113 {
4114 glXWaitGL();
4115 // glFinish();
4116
4117 xerrval = 0;
4118 XMoveWindow(dpy, w, x, y);
4119 if(xerrval && gw_debug)
4120 printf(GW_DEBUG_PREFIX
4121 "XMoveWindow(): Error moving Window 0x%.8x.\n",
4122 (u_int32_t)w
4123 );
4124
4125 // glXWaitX();
4126 XSync(display->display, False);
4127
4128 /* Need to update position immediately */
4129 rect->x = x;
4130 rect->y = y;
4131 }
4132 }
4133 #endif /* X_H */
4134
4135 #ifdef X_H
4136 /*
4137 * Sets the size of the current GL rendering context.
4138 *
4139 * If currently in full screen then the calling function needs
4140 * to call GWContextFullScreen(display, True) after calling this
4141 * function so that the full screen is adjusted to the new size.
4142 */
GWContextSize(gw_display_struct * display,int width,int height)4143 void GWContextSize(
4144 gw_display_struct *display, int width, int height
4145 )
4146 {
4147 Display *dpy = (display != NULL) ? display->display : NULL;
4148 int ctx_num;
4149 Window w;
4150 XRectangle *rect;
4151 if(dpy == NULL)
4152 return;
4153
4154 ctx_num = display->gl_context_num;
4155 if((ctx_num >= 0) && (ctx_num < display->total_gl_contexts))
4156 {
4157 w = display->toplevel[ctx_num];
4158 rect = &display->toplevel_geometry[ctx_num];
4159 }
4160 else
4161 {
4162 w = None;
4163 rect = NULL;
4164 }
4165 if(w == None)
4166 return;
4167
4168 if((((int)rect->width != width) || ((int)rect->height != height)) &&
4169 ((width >= GW_MIN_TOPLEVEL_WIDTH) && (height >= GW_MIN_TOPLEVEL_HEIGHT))
4170 )
4171 {
4172 int new_width = (int)MAX(
4173 ((width > 0) ? width : rect->width),
4174 GW_MIN_TOPLEVEL_WIDTH
4175 ),
4176 new_height = (int)MAX(
4177 ((height > 0) ? height : rect->height),
4178 GW_MIN_TOPLEVEL_HEIGHT
4179 );
4180
4181 glXWaitGL();
4182 // glFinish();
4183 xerrval = 0;
4184 XResizeWindow(dpy, w, new_width, new_height);
4185 glXWaitX();
4186 // XSync(display->display, False);
4187
4188 if(xerrval && gw_debug)
4189 printf(GW_DEBUG_PREFIX
4190 "XResizeWindow(): Error resizing Window 0x%.8x.\n",
4191 (u_int32_t)w
4192 );
4193
4194 /* Need to update size immediately */
4195 rect->width = new_width;
4196 rect->height = new_height;
4197 }
4198 }
4199 #endif /* X_H */
4200
4201 #ifdef X_H
4202 /*
4203 * Returns True if the current context is currently full screen.
4204 */
GWContextIsFullScreen(gw_display_struct * display)4205 Boolean GWContextIsFullScreen(gw_display_struct *display)
4206 {
4207 return((display != NULL) ? display->fullscreen : False);
4208 }
4209 #endif /* X_H */
4210
4211 #ifdef X_H
4212 /*
4213 * Sets the current context into full screen if state is True
4214 * or returns to GUI mode if state is False.
4215 *
4216 * The full screen size depends on the current size of the GL
4217 * context so GWContextSize() should be called prior to going
4218 * to full screen.
4219 *
4220 * For X the size of the toplevel window must match the size of
4221 * a vidmode defined by the X server or else -2 is returned.
4222 *
4223 * Returns:
4224 *
4225 * 0 Success
4226 * -1 General error
4227 * -2 Unable to find valid mode
4228 * -3 System error
4229 * -5 This function is not supported
4230 */
GWContextFullScreen(gw_display_struct * display,Boolean state)4231 int GWContextFullScreen(gw_display_struct *display, Boolean state)
4232 {
4233 #ifdef XF86VIDMODE_H
4234 Display *dpy;
4235 int ctx_num;
4236 int scr;
4237 Window w;
4238 XRectangle *rect, *last_vidmode_gui_rect;
4239
4240
4241 if(display == NULL)
4242 return(-1);
4243
4244 if(!display->has_vidmode_ext)
4245 return(-5);
4246
4247 dpy = display->display;
4248 if(dpy == NULL)
4249 return(-1);
4250
4251 ctx_num = display->gl_context_num;
4252 if((ctx_num < 0) || (ctx_num >= display->total_gl_contexts))
4253 return(-1);
4254
4255 scr = DefaultScreen(dpy);
4256 w = display->toplevel[ctx_num];
4257 rect = &display->toplevel_geometry[ctx_num];
4258 last_vidmode_gui_rect = &display->vidmode_last_gui_geometry;
4259 if(w == None)
4260 return(-3);
4261
4262 /* Go to full screen mode? */
4263 if(state)
4264 {
4265 Boolean switched_modes = False;
4266 XF86VidModeModeLine mode_line;
4267 XF86VidModeModeInfo **mode_line_info, *m;
4268 int i, n, dotclock;
4269 int vidmode_last_x = 0,
4270 vidmode_last_y = 0;
4271 unsigned int vidmode_last_width = 0,
4272 vidmode_last_height = 0;
4273
4274 /* Get current video mode geometry values */
4275 XF86VidModeGetViewPort(
4276 dpy, scr, &vidmode_last_x, &vidmode_last_y
4277 );
4278 if(XF86VidModeGetModeLine(
4279 dpy, scr, &dotclock, &mode_line
4280 ))
4281 {
4282 vidmode_last_width = (unsigned int)mode_line.hdisplay;
4283 vidmode_last_height = (unsigned int)mode_line.vdisplay;
4284 }
4285
4286 /* Search for suitable video mode that matches the current
4287 * toplevel window size
4288 */
4289 if(XF86VidModeGetAllModeLines(
4290 dpy, scr, &n, &mode_line_info
4291 ))
4292 {
4293 for(i = 0; i < n; i++)
4294 {
4295 m = mode_line_info[i];
4296 if(m == NULL)
4297 continue;
4298
4299 /* This mode suitable? */
4300 if(!switched_modes &&
4301 (m->hdisplay == rect->width) &&
4302 (m->vdisplay == rect->height)
4303 )
4304 {
4305 /* Record last position of toplevel window in
4306 * GUI mode
4307 */
4308 if(!display->fullscreen)
4309 {
4310 display->vidmode_last_gui_wx = rect->x;
4311 display->vidmode_last_gui_wy = rect->y;
4312 }
4313
4314 /* Begin switching to new vidmode */
4315
4316 /* Raise window above other windows */
4317 xerrval = 0;
4318 XMapRaised(dpy, w);
4319 if(xerrval && gw_debug)
4320 printf(GW_DEBUG_PREFIX
4321 "XMapRaised(): Error mapping and raising Window 0x%.8x.\n",
4322 (u_int32_t)w
4323 );
4324
4325 /* Move window to the center of the desktop */
4326 rect->x = (int)(display->root_width - rect->width) / 2;
4327 rect->y = (int)(display->root_height - rect->height) / 2;
4328 xerrval = 0;
4329 XMoveWindow(dpy, w, rect->x, rect->y);
4330 if(xerrval && gw_debug)
4331 printf(GW_DEBUG_PREFIX
4332 "XMoveWindow(): Error moving Window 0x%.8x.\n",
4333 (u_int32_t)w
4334 );
4335
4336 /* Move pointer to the center of the window */
4337 xerrval = 0;
4338 XWarpPointer(
4339 dpy, None, w,
4340 0, 0, 0, 0,
4341 (int)rect->width / 2,
4342 (int)rect->height / 2
4343 );
4344 if(xerrval && gw_debug)
4345 printf(GW_DEBUG_PREFIX
4346 "XWarpPointer(): Error moving pointer.\n"
4347 );
4348
4349 /* Grab the pointer so that it is confined to
4350 * the window's area
4351 */
4352 GWGrabPointer(display, w, True);
4353
4354 /* Switch vidmode */
4355 if(XF86VidModeSwitchToMode(dpy, scr, m))
4356 switched_modes = True;
4357
4358 #if 0
4359 /* Move the virtual screen when the ConfigureNotify event is received */
4360 XF86VidModeSetViewPort(
4361 dpy, scr, rect->x, rect->y
4362 );
4363 #endif
4364
4365 if(!switched_modes && gw_debug)
4366 printf(GW_DEBUG_PREFIX
4367 "Unable to switch to video mode %ix%i for full screen mode.\n",
4368 m->hdisplay, m->vdisplay
4369 );
4370 }
4371
4372 /* If private is not NULL then it needs to be
4373 * deleted
4374 *
4375 * Currently, this is only needed for the S3 servers
4376 */
4377 if((m->privsize > 0) && (m->private != NULL))
4378 {
4379 XFree(m->private);
4380 m->private = NULL;
4381 m->privsize = 0;
4382 }
4383
4384 /* Do not delete each structure */
4385 /* XFree(m); */
4386 }
4387 XFree(mode_line_info);
4388 }
4389
4390 /* Successfully switched modes? */
4391 if(switched_modes)
4392 {
4393 /* Record previous GUI values */
4394 if(!display->fullscreen)
4395 {
4396 last_vidmode_gui_rect->x = vidmode_last_x;
4397 last_vidmode_gui_rect->y = vidmode_last_y;
4398 last_vidmode_gui_rect->width = vidmode_last_width;
4399 last_vidmode_gui_rect->height = vidmode_last_height;
4400 }
4401 display->fullscreen = True;
4402 display->fullscreen_context_num = ctx_num;
4403 return(0);
4404 }
4405 else
4406 {
4407 return(-2);
4408 }
4409 }
4410 else
4411 {
4412 /* Go to GUI mode */
4413 Boolean switched_modes = False;
4414 XF86VidModeModeInfo **mode_line_info, *m;
4415 int i, n;
4416
4417 /* If this context's window is grabbing the pointer then
4418 * ungrab the pointer before switching video modes.
4419 */
4420 if(display->grab_window == w)
4421 GWUngrabPointer(display);
4422
4423 /* Search for suitable video mode that matches the previous
4424 * GUI geometry.
4425 */
4426 if(XF86VidModeGetAllModeLines(
4427 dpy, scr, &n, &mode_line_info
4428 ))
4429 {
4430 for(i = 0; i < n; i++)
4431 {
4432 m = mode_line_info[i];
4433 if(m == NULL)
4434 continue;
4435
4436 /* This mode suitable? */
4437 if(!switched_modes &&
4438 (m->hdisplay == last_vidmode_gui_rect->width) &&
4439 (m->vdisplay == last_vidmode_gui_rect->height)
4440 )
4441 {
4442 /* Switch vidmode */
4443 if(XF86VidModeSwitchToMode(dpy, scr, m))
4444 switched_modes = True;
4445
4446 if(switched_modes)
4447 {
4448 /* Move virtual screen to the last recorded
4449 * position it was in GUI mode
4450 */
4451 XF86VidModeSetViewPort(
4452 dpy, scr,
4453 last_vidmode_gui_rect->x,
4454 last_vidmode_gui_rect->y
4455 );
4456 /* Move window to the last recorded
4457 * position it was in the GUI mode
4458 */
4459 if((rect->x != display->vidmode_last_gui_wx) ||
4460 (rect->y != display->vidmode_last_gui_wy)
4461 )
4462 {
4463 rect->x = display->vidmode_last_gui_wx;
4464 rect->y = display->vidmode_last_gui_wy;
4465 xerrval = 0;
4466 XMoveWindow(
4467 dpy, w, rect->x, rect->y
4468 );
4469 if(xerrval && gw_debug)
4470 printf(GW_DEBUG_PREFIX
4471 "XMoveWindow(): Error moving Window 0x%.8x.\n",
4472 (u_int32_t)w
4473 );
4474 }
4475
4476 /* Move pointer to center of window */
4477 xerrval = 0;
4478 XWarpPointer(
4479 dpy, None, w,
4480 0, 0, 0, 0,
4481 (int)rect->width / 2,
4482 (int)rect->height / 2
4483 );
4484 if(xerrval && gw_debug)
4485 printf(GW_DEBUG_PREFIX
4486 "XWarpPointer(): Error moving pointer.\n"
4487 );
4488 }
4489
4490 if(!switched_modes && gw_debug)
4491 printf(GW_DEBUG_PREFIX
4492 "Unable to switch to video mode %ix%i to restore GUI mode.\n",
4493 m->hdisplay, m->vdisplay
4494 );
4495 }
4496
4497 /* If private is not NULL then it needs to be
4498 * deallocated. Currently this only occures for
4499 * the S3 servers.
4500 */
4501 if((m->privsize > 0) && (m->private != NULL))
4502 {
4503 XFree(m->private);
4504 m->private = NULL;
4505 m->privsize = 0;
4506 }
4507
4508 /* Do not free each structure */
4509 /* XFree(m); */
4510 }
4511 XFree(mode_line_info);
4512 }
4513
4514 /* Successfully switched modes? */
4515 if(switched_modes)
4516 {
4517 /* Mark that we are no longer in full screen mode */
4518 display->fullscreen = False;
4519 display->fullscreen_context_num = -1;
4520 return(0);
4521 }
4522 else
4523 {
4524 return(-2);
4525 }
4526 }
4527 #endif
4528 return(-5);
4529 }
4530 #endif /* X_H */
4531
4532
4533 #ifdef X_H
4534 /*
4535 * Sends a (synthetic) redraw event for the current context.
4536 */
GWPostRedraw(gw_display_struct * display)4537 void GWPostRedraw(gw_display_struct *display)
4538 {
4539 int ctx_num = GWContextCurrent(display);
4540 if(ctx_num < 0)
4541 return;
4542
4543 #if 0
4544 /* This makes drawing async and some progrmas want to redraw
4545 * immediately which causes problems
4546 */
4547 /* Increment queued draw count */
4548 display->draw_count[ctx_num] = MAX(
4549 display->draw_count[ctx_num] + 1, 0
4550 );
4551 #else
4552 /* Call draw callback to draw */
4553 if(display->func_draw != NULL)
4554 display->func_draw(
4555 ctx_num, display->func_draw_data
4556 );
4557 #endif
4558 }
4559 #endif /* X_H */
4560
4561 #ifdef X_H
4562 /*
4563 * Swaps buffers (if using double buffers), all GL operations are
4564 * gauranteed to be completed after this call.
4565 */
GWSwapBuffer(gw_display_struct * display)4566 void GWSwapBuffer(gw_display_struct *display)
4567 {
4568 int ctx_num;
4569 Display *dpy;
4570 GLXDrawable gl_drawable;
4571
4572 if(display == NULL)
4573 return;
4574
4575 dpy = display->display;
4576 if(dpy == NULL)
4577 return;
4578
4579 ctx_num = display->gl_context_num;
4580 if((ctx_num >= 0) && (ctx_num < display->total_gl_contexts))
4581 gl_drawable = (GLXDrawable)display->toplevel[ctx_num];
4582 else
4583 gl_drawable = None;
4584 if(gl_drawable == None)
4585 return;
4586
4587 /* If using double buffers then we need to swap buffers, this
4588 * will flush all GL commands. If we are using single buffer
4589 * then do not swap buf still wait for GL commands to be
4590 * executed since this call should have all GL commands flushed.
4591 */
4592 if(display->has_double_buffer)
4593 glXSwapBuffers(dpy, gl_drawable);
4594 else
4595 glXWaitGL();
4596 // glFinish();
4597
4598 /* Reset draw count since we've just drawn */
4599 display->draw_count[ctx_num] = 0;
4600 }
4601 #endif /* X_H */
4602
4603 #ifdef X_H
4604 /*
4605 * Turns keyboard auto repeat on/off.
4606 */
GWKeyboardAutoRepeat(gw_display_struct * display,Boolean b)4607 void GWKeyboardAutoRepeat(gw_display_struct *display, Boolean b)
4608 {
4609 if(display == NULL)
4610 return;
4611 if(display->display == NULL)
4612 return;
4613
4614 xerrval = 0;
4615 // XAutoRepeatOff(display->display);
4616 /*
4617 Getting rid of this as it causes all sorts of trouble
4618 on Ubuntu. The key does not stop repeating for some reason.
4619 Will turn it back on at the end of the game to avoid
4620 messing with the operating system.
4621 - Jesse <jessefrgsmith@yahoo.ca>
4622
4623 Update: Leaving it off causes problems for people who
4624 use other apps while SAR is running. Will turn ON
4625 auto-repeat UNLESS --no-repeat flag is set.
4626 -- Jesse
4627 */
4628 if (display->allow_autorepeat)
4629 {
4630 if(b)
4631 {
4632 XAutoRepeatOn(display->display);
4633 }
4634 else
4635 {
4636 XAutoRepeatOff(display->display);
4637 }
4638 }
4639 else // auto repeat is forbidden so...
4640 XAutoRepeatOff(display->display);
4641
4642
4643 if(xerrval && gw_debug)
4644 printf(GW_DEBUG_PREFIX
4645 "Cannot switch keyboard auto repeat.\n"
4646 );
4647 }
4648 #endif /* X_H */
4649
4650
4651 #ifdef X_H
4652 /*
4653 * Returns a list of video modes, the number of video modes
4654 * will be set to the storage pointer to by n.
4655 *
4656 * Can return NULL on error or information not available.
4657 *
4658 * The calling function needs to free() the returned pointer.
4659 */
GWVidModesGet(gw_display_struct * display,int * n)4660 gw_vidmode_struct *GWVidModesGet(
4661 gw_display_struct *display, int *n
4662 )
4663 {
4664 #ifdef XF86VIDMODE_H
4665 Display *dpy;
4666 Boolean is_dup;
4667 int i, j, k, t = 0, scr;
4668 XF86VidModeModeInfo **mode_line_info, *m;
4669 gw_vidmode_struct *vm = NULL, *vm_ptr;
4670
4671 if(n != NULL)
4672 *n = t;
4673
4674 if(display == NULL)
4675 return(vm);
4676
4677 dpy = display->display;
4678 if(dpy == NULL)
4679 return(vm);
4680
4681 scr = DefaultScreen(dpy);
4682
4683 if(XF86VidModeGetAllModeLines(
4684 dpy, scr, &t, &mode_line_info
4685 ))
4686 {
4687 for(i = 0, j = 0; i < t; i++)
4688 {
4689 m = mode_line_info[i];
4690 if(m == NULL)
4691 continue;
4692
4693 /* Check for duplicate video mode */
4694 for(is_dup = False, k = 0; k < j; k++)
4695 {
4696 vm_ptr = &vm[k];
4697 if((vm_ptr->width == m->hdisplay) &&
4698 (vm_ptr->height == m->vdisplay) &&
4699 (vm_ptr->vwidth == m->htotal) &&
4700 (vm_ptr->vheight == m->vtotal)
4701 )
4702 {
4703 is_dup = True;
4704 break;
4705 }
4706 }
4707 if(!is_dup)
4708 {
4709 /* Allocate a new video mode */
4710 vm = (gw_vidmode_struct *)realloc(
4711 vm, (j + 1) * sizeof(gw_vidmode_struct)
4712 );
4713 if(vm != NULL)
4714 {
4715 vm_ptr = &vm[j];
4716 vm_ptr->width = m->hdisplay;
4717 vm_ptr->height = m->vdisplay;
4718 vm_ptr->vwidth = m->htotal;
4719 vm_ptr->vheight = m->vtotal;
4720 j++;
4721 }
4722 }
4723
4724 /* If private is not NULL then it needs to be
4725 * deallocated. Currently this only occures for
4726 * the S3 servers.
4727 */
4728 if((m->privsize > 0) && (m->private != NULL))
4729 {
4730 XFree(m->private);
4731 m->private = NULL;
4732 m->privsize = 0;
4733 }
4734
4735 /* Do not free each structure */
4736 /* XFree(m); */
4737 }
4738 XFree(mode_line_info);
4739 }
4740 if(n != NULL)
4741 *n = t;
4742 return(vm);
4743 #else
4744 if(n != NULL)
4745 *n = 0;
4746 return(NULL);
4747 #endif
4748 }
4749 #endif /* X_H */
4750
4751 /*
4752 * Deletes a list of video modes obtained from GWVidModesGet().
4753 */
GWVidModesFree(gw_vidmode_struct * vidmode,int n)4754 void GWVidModesFree(gw_vidmode_struct *vidmode, int n)
4755 {
4756 if(vidmode == NULL)
4757 return;
4758
4759 free(vidmode);
4760 }
4761
4762 /*
4763 * Creates a new accelerator structure, can return NULL on error.
4764 */
GWAcceleratorNew(int key,int modifier)4765 gw_accelerator_struct *GWAcceleratorNew(
4766 int key, int modifier
4767 )
4768 {
4769 gw_accelerator_struct *a = (gw_accelerator_struct *)calloc(
4770 1, sizeof(gw_accelerator_struct)
4771 );
4772 if(a == NULL)
4773 return(NULL);
4774
4775 a->key = key;
4776 a->modifier = modifier;
4777
4778 return(a);
4779 }
4780
4781 /*
4782 * Deallocates the given accelerator structure.
4783 */
GWAcceleratorDelete(gw_accelerator_struct * a)4784 void GWAcceleratorDelete(gw_accelerator_struct *a)
4785 {
4786 if(a == NULL)
4787 return;
4788
4789 free(a);
4790 }
4791
4792 /*
4793 * Appends a new accelerator structure to the list. Returns the
4794 * index to the new accelerator structure or -1 on error.
4795 */
GWAcceleratorListAdd(gw_accelerator_struct *** a,int * total,int key,int modifier)4796 int GWAcceleratorListAdd(
4797 gw_accelerator_struct ***a, int *total,
4798 int key, int modifier
4799 )
4800 {
4801 int n;
4802 gw_accelerator_struct *akey;
4803
4804
4805 if((a == NULL) || (total == NULL))
4806 return(-1);
4807
4808 if(*total < 0)
4809 *total = 0;
4810
4811 n = *total;
4812 *total = n + 1;
4813 *a = (gw_accelerator_struct **)realloc(
4814 *a,
4815 (*total) * sizeof(gw_accelerator_struct *)
4816 );
4817 if(*a == NULL)
4818 {
4819 *total = 0;
4820 return(-1);
4821 }
4822
4823 (*a)[n] = akey = GWAcceleratorNew(key, modifier);
4824 if(akey == NULL)
4825 return(-1);
4826 else
4827 return(n);
4828 }
4829
4830 /*
4831 * Deallocates the list of accelerators.
4832 */
GWAcceleratorListDelete(gw_accelerator_struct *** a,int * total)4833 void GWAcceleratorListDelete(
4834 gw_accelerator_struct ***a, int *total
4835 )
4836 {
4837 int i;
4838
4839 if((a == NULL) || (total == NULL))
4840 return;
4841
4842 for(i = 0; i < *total; i++)
4843 GWAcceleratorDelete((*a)[i]);
4844
4845 free(*a);
4846 *a = NULL;
4847 *total = 0;
4848 }
4849
4850 /*
4851 * Returns True if the given key and modifier match one of the
4852 * accelerators in the given list.
4853 */
GWAcceleratorListCheck(gw_accelerator_struct ** a,int total,int key,int modifier)4854 Boolean GWAcceleratorListCheck(
4855 gw_accelerator_struct **a, int total,
4856 int key, int modifier
4857 )
4858 {
4859 int i;
4860 gw_accelerator_struct *a_ptr;
4861
4862 if((a == NULL) || (total <= 0))
4863 return(False);
4864
4865 /* Iterate through all accelerator keys in the list */
4866 for(i = 0; i < total; i++)
4867 {
4868 a_ptr = a[i];
4869 if(a_ptr == NULL)
4870 continue;
4871
4872 /* Does the given accelerator key and modifier key match
4873 * this accelerator key and modifier key?
4874 */
4875 if((a_ptr->key == key) &&
4876 (a_ptr->modifier == modifier)
4877 )
4878 return(True);
4879 }
4880
4881 return(False);
4882 }
4883
4884
4885
4886 #ifdef X_H
4887 /*
4888 * Creates a new pointer cursor from the given RGBA data.
4889 *
4890 * In X all alpha values less than 0x80 is considered transparent
4891 * and values above that are solid.
4892 */
GWCursorNew(gw_display_struct * display,int width,int height,int hot_x,int hot_y,int bpl,const void * data)4893 void *GWCursorNew(
4894 gw_display_struct *display,
4895 int width, int height, /* In pixels */
4896 int hot_x, int hot_y, /* In pixels */
4897 int bpl, /* Bytes per line, 0 for autocalc */
4898 const void *data /* RGBA data (4 bytes per pixel) */
4899 )
4900 {
4901 Display *dpy = (display != NULL) ? display->display : NULL;
4902 const u_int8_t *v, *ptr8 = (const u_int8_t *)data;
4903 int x, y, ctx_num;
4904 unsigned int best_width, best_height;
4905 Drawable d;
4906 Pixmap pixmap, mask;
4907 Pixel black_pix, white_pix;
4908 GC gc;
4909 XGCValues gcv;
4910 Cursor c;
4911 XColor fg_c, bg_c;
4912 if((dpy == NULL) || (ptr8 == NULL))
4913 return(NULL);
4914
4915 if((width <= 0) || (height <= 0))
4916 return(NULL);
4917
4918 if(bpl <= 0)
4919 bpl = width * 4 * sizeof(u_int8_t);
4920
4921 black_pix = display->black_pix;
4922 white_pix = display->white_pix;
4923
4924 ctx_num = display->gl_context_num;
4925 if((ctx_num >= 0) && (ctx_num < display->total_gl_contexts))
4926 d = (Drawable)display->toplevel[ctx_num];
4927 else
4928 d = None;
4929 if(d == None)
4930 return(NULL);
4931
4932 /* Query cursor size */
4933 xerrval = 0;
4934 if(XQueryBestCursor(
4935 dpy, d, width, height, &best_width, &best_height
4936 ))
4937 {
4938 if(width > best_width)
4939 {
4940 fprintf(
4941 stderr,
4942 "GWCursorNew(): Cursor width %i is too big,\
4943 reducing to recommend width %i.\n",
4944 width, best_width
4945 );
4946 width = best_width;
4947 }
4948 if(height > best_height)
4949 {
4950 fprintf(
4951 stderr,
4952 "GWCursorNew(): Cursor height %i is too big,\
4953 reducing to recommend height %i.\n",
4954 height, best_height
4955 );
4956 height = best_height;
4957 }
4958 }
4959 if(xerrval && gw_debug)
4960 printf(GW_DEBUG_PREFIX
4961 "XQueryBestCursor(): Unable to obtain best cursor size for\
4962 Window 0x%.8x.\n",
4963 (u_int32_t)d
4964 );
4965
4966 /* Set up foreground and background RGB colors for the
4967 * cursor.
4968 */
4969 XCOLOR_SET_RGB_COEFF(&fg_c, 1.0, 1.0, 1.0);
4970 fg_c.pixel = white_pix;
4971 XCOLOR_SET_RGB_COEFF(&bg_c, 0.0, 0.0, 0.0);
4972 bg_c.pixel = black_pix;
4973
4974 /* Create pixmap and mask that will be used to create the
4975 * cursor. Both the pixmap and mask must have a depth of 1
4976 * bit per pixel.
4977 */
4978 xerrval = 0;
4979 pixmap = XCreatePixmap(dpy, d, width, height, 1);
4980 if((pixmap == None) || xerrval)
4981 {
4982 if(gw_debug)
4983 printf(GW_DEBUG_PREFIX
4984 "XCreatePixmap(): Unable to create Pixmap of size %ix%i\
4985 and %i bits per pixel.\n",
4986 width, height, 1
4987 );
4988 return(NULL);
4989 }
4990 xerrval = 0;
4991 mask = XCreatePixmap(dpy, d, width, height, 1);
4992 if((mask == None) || xerrval)
4993 {
4994 if(gw_debug)
4995 printf(GW_DEBUG_PREFIX
4996 "XCreatePixmap(): Unable to create Pixmap of size %ix%i\
4997 and %i bits per pixel.\n",
4998 width, height, 1
4999 );
5000 FREE_PIXMAP(&pixmap);
5001 return(NULL);
5002 }
5003
5004 /* Create GC for the pixmap and mask */
5005 gcv.function = GXcopy;
5006 gcv.plane_mask = AllPlanes;
5007 gcv.foreground = white_pix;
5008 gcv.background = black_pix;
5009 xerrval = 0;
5010 gc = XCreateGC(
5011 dpy, pixmap,
5012 GCFunction | GCPlaneMask |
5013 GCForeground | GCBackground,
5014 &gcv
5015 );
5016 if((gc == None) || xerrval)
5017 {
5018 if(gw_debug)
5019 printf(GW_DEBUG_PREFIX
5020 "XCreateGC(): Unable to create GC for Pixmap 0x%.8x.\n",
5021 (u_int32_t)pixmap
5022 );
5023 FREE_PIXMAP(&pixmap);
5024 FREE_BITMAP(&mask);
5025 return(NULL);
5026 }
5027
5028 /* Copy the given data to the pixmap and mask, we will draw the
5029 * pixmap and mask with GC functions GXset and GXclear since
5030 * everything is in black and white.
5031 */
5032 for(y = 0; y < height; y++)
5033 {
5034 for(x = 0; x < width; x++)
5035 {
5036 /* Get current RGBA pixel value */
5037 v = &ptr8[(y * bpl) + (x * 4)];
5038
5039 /* Check alpha value and draw mask pixel */
5040 XSetFunction(
5041 dpy, gc,
5042 (v[3] >= 0x80) ? GXset : GXclear
5043 );
5044 XDrawPoint(dpy, mask, gc, x, y);
5045
5046 /* Check RGB value and draw pixmap pixel */
5047 XSetFunction(
5048 dpy, gc,
5049 (((v[0] + v[1] + v[2]) / 3) >= 0x80) ?
5050 GXset : GXclear
5051 );
5052 XDrawPoint(dpy, pixmap, gc, x, y);
5053 }
5054 }
5055
5056 /* Create cursor */
5057 xerrval = 0;
5058 c = XCreatePixmapCursor(
5059 dpy, pixmap, mask,
5060 &fg_c, &bg_c,
5061 hot_x, hot_y
5062 );
5063 if((c == None) || xerrval)
5064 {
5065 if(gw_debug)
5066 printf(GW_DEBUG_PREFIX
5067 "XCreatePixmapCursor(): Unable to create Cursor of size %ix%i from\
5068 Pixmap 0x%.8x and mask 0x%.8x.\n",
5069 width, height,
5070 (u_int32_t)pixmap,
5071 (u_int32_t)mask
5072 );
5073 }
5074
5075 /* Delete pixmap, mask and the GC since they are no longer
5076 * needed after the creation of the cursor.
5077 */
5078 FREE_PIXMAP(&pixmap);
5079 FREE_BITMAP(&mask);
5080 XFreeGC(dpy, gc);
5081
5082 return((c != None) ? (void *)c : NULL);
5083 }
5084 #endif /* X_H */
5085
5086 #ifdef X_H
5087 /*
5088 * Sets the pointer cursor for the current toplevel window in
5089 * context.
5090 *
5091 * The pointer cursor must be one that has been returned by
5092 * GWCursorNew().
5093 */
GWCursorSet(gw_display_struct * display,void * cursor_ptr)5094 void GWCursorSet(gw_display_struct *display, void *cursor_ptr)
5095 {
5096 Display *dpy = (display != NULL) ? display->display : NULL;
5097 Cursor c = (Cursor)((cursor_ptr != NULL) ? cursor_ptr : None);
5098 int ctx_num;
5099 Window w;
5100 if(dpy == NULL)
5101 return;
5102
5103 ctx_num = display->gl_context_num;
5104 if((ctx_num >= 0) && (ctx_num < display->total_gl_contexts))
5105 w = display->toplevel[ctx_num];
5106 else
5107 w = None;
5108 if(w == None)
5109 return;
5110
5111 if(c == None)
5112 {
5113 xerrval = 0;
5114 XUndefineCursor(dpy, w);
5115 if(xerrval && gw_debug)
5116 printf(GW_DEBUG_PREFIX
5117 "XUndefineCursor(): Unable to set default Cursor for Window 0x%.8x.\n",
5118 (u_int32_t)w
5119 );
5120 }
5121 else
5122 {
5123 xerrval = 0;
5124 XDefineCursor(dpy, w, c);
5125 if(xerrval && gw_debug)
5126 printf(GW_DEBUG_PREFIX
5127 "XDefineCursor(): Unable to set Cursor 0x%.8x for Window 0x%.8x.\n",
5128 (u_int32_t)c, (u_int32_t)w
5129 );
5130 }
5131 XFlush(dpy);
5132 }
5133 #endif /* X_H */
5134
5135 #ifdef X_H
5136 /*
5137 * Deletes a pointer cursor created by GWCursorNew().
5138 */
GWCursorDelete(gw_display_struct * display,void * cursor_ptr)5139 void GWCursorDelete(gw_display_struct *display, void *cursor_ptr)
5140 {
5141 Display *dpy = (display != NULL) ? display->display : NULL;
5142 Cursor c = (Cursor)((cursor_ptr != NULL) ? cursor_ptr : None);
5143 if((dpy == NULL) || (c == None))
5144 return;
5145
5146 XFreeCursor(dpy, c);
5147 }
5148 #endif /* X_H */
5149
5150 #ifdef X_H
5151 /*
5152 * Sets the pointer cursor for the current toplevel window in
5153 * context.
5154 */
GWSetPointerCursor(gw_display_struct * display,gw_pointer_cursor cursor)5155 void GWSetPointerCursor(
5156 gw_display_struct *display, gw_pointer_cursor cursor
5157 )
5158 {
5159 Display *dpy = (display != NULL) ? display->display : NULL;
5160 int ctx_num;
5161 Cursor c = None;
5162 Window w;
5163 if(dpy == NULL)
5164 return;
5165
5166 ctx_num = display->gl_context_num;
5167 if((ctx_num < 0) || (ctx_num >= display->total_gl_contexts))
5168 return;
5169
5170 w = display->toplevel[ctx_num];
5171 if(w == None)
5172 return;
5173
5174 switch(cursor)
5175 {
5176 case GWPointerCursorStandard:
5177 c = display->cursor_standard;
5178 break;
5179 case GWPointerCursorBusy:
5180 c = display->cursor_busy;
5181 break;
5182 case GWPointerCursorText:
5183 c = display->cursor_text;
5184 break;
5185 case GWPointerCursorTranslate:
5186 c = display->cursor_translate;
5187 break;
5188 case GWPointerCursorZoom:
5189 c = display->cursor_zoom;
5190 break;
5191 case GWPointerCursorInvisible:
5192 c = display->cursor_invisible;
5193 break;
5194 }
5195
5196 if(c == None)
5197 {
5198 xerrval = 0;
5199 XUndefineCursor(dpy, w);
5200 if(xerrval && gw_debug)
5201 printf(GW_DEBUG_PREFIX
5202 "XUndefineCursor(): Unable to set default Cursor for Window 0x%.8x.\n",
5203 (u_int32_t)w
5204 );
5205 }
5206 else
5207 {
5208 xerrval = 0;
5209 XDefineCursor(dpy, w, c);
5210 if(xerrval && gw_debug)
5211 printf(GW_DEBUG_PREFIX
5212 "XDefineCursor(): Unable to set Cursor 0x%.8x for Window 0x%.8x.\n",
5213 (u_int32_t)c, (u_int32_t)w
5214 );
5215 }
5216 XFlush(dpy);
5217 }
5218 #endif /* X_H */
5219
5220 #ifdef X_H
5221 /*
5222 * Shows the pointer cursor.
5223 */
GWShowCursor(gw_display_struct * display)5224 void GWShowCursor(gw_display_struct *display)
5225 {
5226 if(display == NULL)
5227 return;
5228
5229 if(display->cursor_shown)
5230 return;
5231
5232 GWSetPointerCursor(display, GWPointerCursorStandard);
5233 display->cursor_shown = True;
5234 }
5235 #endif /* X_H */
5236
5237 #ifdef X_H
5238 /*
5239 * Hides the pointer cursor.
5240 */
GWHideCursor(gw_display_struct * display)5241 void GWHideCursor(gw_display_struct *display)
5242 {
5243 if(display == NULL)
5244 return;
5245
5246 if(!display->cursor_shown)
5247 return;
5248
5249 GWSetPointerCursor(display, GWPointerCursorInvisible);
5250 display->cursor_shown = False;
5251 }
5252 #endif /* X_H */
5253
5254 #ifdef X_H
5255 /*
5256 * Returns True if the cursor is shown.
5257 */
GWIsCursorShown(gw_display_struct * display)5258 Boolean GWIsCursorShown(gw_display_struct *display)
5259 {
5260 return((display != NULL) ? display->cursor_shown : False);
5261 }
5262 #endif /* X_H */
5263
5264 #ifdef X_H
5265 /*
5266 * Sets pointer cursor as busy and ignores input.
5267 */
GWSetInputBusy(gw_display_struct * display)5268 void GWSetInputBusy(gw_display_struct *display)
5269 {
5270 if(!GWIsCursorShown(display))
5271 return;
5272
5273 GWSetPointerCursor(display, GWPointerCursorBusy);
5274 }
5275 #endif /* X_H */
5276
5277 #ifdef X_H
5278 /*
5279 * Sets pointer cursor as ready and resumes allowing input.
5280 */
GWSetInputReady(gw_display_struct * display)5281 void GWSetInputReady(gw_display_struct *display)
5282 {
5283 if(!GWIsCursorShown(display))
5284 return;
5285
5286 GWSetPointerCursor(display, GWPointerCursorStandard);
5287 }
5288 #endif /* X_H */
5289
5290
5291 #ifdef X_H
5292 /*
5293 * Set up gl projection matrix for 2d drawing.
5294 */
GWOrtho2D(gw_display_struct * display)5295 void GWOrtho2D(gw_display_struct *display)
5296 {
5297 int ctx_num;
5298 const XRectangle *rect;
5299
5300
5301 if(display == NULL)
5302 return;
5303
5304 /* Get current gl context */
5305 ctx_num = display->gl_context_num;
5306 if((ctx_num < 0) || (ctx_num >= display->total_gl_contexts))
5307 return;
5308
5309 /* Get size of current gl context */
5310 rect = &display->toplevel_geometry[ctx_num];
5311
5312 /* Set up gl projection matrix for 2d drawing */
5313 glMatrixMode(GL_PROJECTION);
5314 glLoadIdentity();
5315 gluOrtho2D(
5316 0, /* Left, right coordinate values */
5317 MAX(rect->width - 1, 1),
5318 0, /* Top, bottom coordinate values */
5319 MAX(rect->height - 1, 1)
5320 );
5321 glMatrixMode(GL_MODELVIEW);
5322 glLoadIdentity();
5323 }
5324 #endif /* X_H */
5325
5326 #ifdef X_H
5327 /*
5328 * Set up gl projection matrix for 2d drawing with specific
5329 * coordinates.
5330 */
GWOrtho2DCoord(gw_display_struct * display,float left,float right,float top,float bottom)5331 void GWOrtho2DCoord(
5332 gw_display_struct *display,
5333 float left, float right, float top, float bottom
5334 )
5335 {
5336 if(display == NULL)
5337 return;
5338
5339 if((left == right) || (top == bottom))
5340 return;
5341
5342 /* Set up gl projection matrix for 2d drawing */
5343 glMatrixMode(GL_PROJECTION);
5344 glLoadIdentity();
5345 gluOrtho2D(
5346 left, right,
5347 bottom, top
5348 );
5349 glMatrixMode(GL_MODELVIEW);
5350 glLoadIdentity();
5351 }
5352 #endif /* X_H */
5353
5354 /*
5355 * Sets font to the foreground of the graphics context.
5356 */
GWSetFont(gw_display_struct * display,GWFont * font)5357 void GWSetFont(gw_display_struct *display, GWFont *font)
5358 {
5359 if(display == NULL)
5360 return;
5361
5362 display->current_font = font;
5363 }
5364
5365 /*
5366 * Gets font sizes.
5367 *
5368 * If an input is NULL, then its value will not be set.
5369 *
5370 * Returns 0 on success or non-zero on error.
5371 */
GWGetFontSize(GWFont * font,int * width,int * height,int * character_spacing,int * line_spacing)5372 int GWGetFontSize(
5373 GWFont *font,
5374 int *width, int *height,
5375 int *character_spacing, int *line_spacing
5376 )
5377 {
5378 if(font == NULL)
5379 return(-1);
5380
5381 /* Format, header is first 32 bytes:
5382 *
5383 * Address Desc
5384 * 0 Width of each font
5385 * 1 Height of each font
5386 * 2 Character width spacing
5387 * 3 Line spacing
5388 * 4 Bytes per line
5389 */
5390
5391 if(width != NULL)
5392 *width = (int)((u_int8_t)font[0]);
5393
5394 if(height != NULL)
5395 *height = (int)((u_int8_t)font[1]);
5396
5397 if(character_spacing != NULL)
5398 *character_spacing = (int)((u_int8_t)font[2]);
5399
5400 if(line_spacing != NULL)
5401 *line_spacing = (int)((u_int8_t)font[3]);
5402
5403 return(0);
5404 }
5405
5406 /*
5407 * Draws string.
5408 *
5409 * GWOrtho2D() must be called to transform orientations before
5410 * using this function.
5411 */
5412 #ifdef USE_OLD_GWDRAWSTRING
GWDrawString(gw_display_struct * display,int x,int y,const char * string)5413 void GWDrawString(
5414 gw_display_struct *display,
5415 int x, int y,
5416 const char *string
5417 )
5418 {
5419 u_int8_t *font_header, *font_data;
5420
5421 int font_width, font_height; /* In pixels */
5422 int width_spacing, line_spacing; /* In pixels */
5423 int bytes_per_line; /* Bytes per line (per width) */
5424 int bytes_per_char_len; /* Bytes per character */
5425
5426 int win_height;
5427
5428
5429 if((display == NULL) || (string == NULL))
5430 return;
5431
5432 win_height = display->height;
5433
5434 /* Get pointer to font header data */
5435 font_header = display->current_font;
5436 if(font_header == NULL)
5437 return;
5438
5439 /* Seek past header and get pointer to start of font data */
5440 font_data = font_header + 32;
5441
5442 /* Format, header is first 32 bytes:
5443 *
5444 * Address Desc
5445 * 0 Width of each font
5446 * 1 Height of each font
5447 * 2 Character width spacing
5448 * 3 Line spacing
5449 * 4 Bytes per line
5450 */
5451
5452 font_width = font_header[0];
5453 font_height = font_header[1];
5454 width_spacing = font_header[2];
5455 line_spacing = font_header[3];
5456 bytes_per_line = font_header[4];
5457
5458 /* Calculate bytes per character */
5459 bytes_per_char_len = bytes_per_line * font_height;
5460
5461 /* Convert y position */
5462 y = win_height - y - font_height;
5463
5464 while(*string != '\0')
5465 {
5466 glRasterPos2i(x, y);
5467 glBitmap(
5468 font_width, font_height,
5469 0.0, 0.0,
5470 width_spacing, 0.0,
5471 &font_data[
5472 bytes_per_char_len * (char)(*string)
5473 ]
5474 );
5475
5476 x += width_spacing;
5477 string++;
5478 }
5479 }
5480 #else /* USE_OLD_GWDRAWSTRING */
GWDrawString(gw_display_struct * display,int x,int y,const char * string)5481 void GWDrawString(
5482 gw_display_struct *display,
5483 int x, int y,
5484 const char *string
5485 )
5486 {
5487 u_int8_t *font_header, *font_data;
5488 int width, height;
5489 int font_width, font_height; /* In pixels */
5490 int width_spacing, line_spacing; /* In pixels */
5491 int bytes_per_line; /* Bytes per line (per width) */
5492 int bytes_per_char; /* Bytes per character */
5493 int char_offset; /* Current char's offset in the font data */
5494
5495 int chars_hidden = 0; /* # of chars entirely outside viewport */
5496 float xorig = 0.0f;
5497 float yorig = 0.0f;
5498
5499
5500 if((display == NULL) || (string == NULL))
5501 return;
5502
5503 GWContextGet(
5504 display, display->gl_context_num,
5505 NULL, NULL,
5506 NULL, NULL,
5507 &width, &height
5508 );
5509
5510 /* Get pointer to font header data */
5511 font_header = display->current_font;
5512 if(font_header == NULL)
5513 return;
5514
5515 /* Seek past header and get pointer to start of font data */
5516 font_data = font_header + 32;
5517
5518 /* Format, header is first 32 bytes:
5519 *
5520 * Address Desc
5521 * 0 Width of each font
5522 * 1 Height of each font
5523 * 2 Character width spacing
5524 * 3 Line spacing
5525 * 4 Bytes per line
5526 */
5527
5528 font_width = font_header[0];
5529 font_height = font_header[1];
5530 width_spacing = font_header[2];
5531 line_spacing = font_header[3];
5532 bytes_per_line = font_header[4];
5533
5534 /* Flip y values */
5535 y = height - line_spacing - y + 1;
5536
5537 /* Calculate bytes per character */
5538 bytes_per_char = bytes_per_line * font_height;
5539
5540 /* Adjust string index in case x < 0 */
5541 if(x < 0)
5542 {
5543 chars_hidden = (-x) / width_spacing;
5544 xorig = (float)((-x) - (chars_hidden * width_spacing));
5545
5546 if(chars_hidden >= STRLEN(string))
5547 return;
5548
5549 x = 0;
5550 string += chars_hidden;
5551 }
5552 if(y < 0)
5553 {
5554 if(y < -line_spacing)
5555 return;
5556
5557 yorig = (float)-y;
5558 y = 0;
5559 }
5560
5561 glRasterPos2i(x, y);
5562 for(; *string; string++)
5563 {
5564 char_offset = bytes_per_char * (*string);
5565
5566 glBitmap(
5567 font_width, font_height,
5568 (GLfloat)xorig, (GLfloat)yorig,
5569 (GLfloat)width_spacing, 0.0,
5570 font_data + char_offset
5571 );
5572 }
5573 }
5574 #endif /* USE_OLD_GWDRAWSTRING */
5575
5576 /*
5577 * Same as GWDrawString() except that it draws just the specified
5578 * character.
5579 */
GWDrawCharacter(gw_display_struct * display,int x,int y,char c)5580 void GWDrawCharacter(
5581 gw_display_struct *display,
5582 int x, int y,
5583 char c
5584 )
5585 {
5586 u_int8_t *font_header, *font_data;
5587 int width, height;
5588 int font_width, font_height; /* In pixels */
5589 int width_spacing, line_spacing; /* In pixels */
5590 int bytes_per_line; /* Bytes per line (per width) */
5591 int bytes_per_char_len; /* Bytes per character */
5592
5593
5594 if((display == NULL) || (c == '\0'))
5595 return;
5596
5597 GWContextGet(
5598 display, display->gl_context_num,
5599 NULL, NULL,
5600 NULL, NULL,
5601 &width, &height
5602 );
5603
5604 /* Get pointer to font header data */
5605 font_header = display->current_font;
5606 if(font_header == NULL)
5607 return;
5608
5609 /* Seek past header and get pointer to start of font data */
5610 font_data = font_header + 32;
5611
5612 /* Format, header is first 32 bytes:
5613 *
5614 * Address Desc
5615 * 0 Width of each font
5616 * 1 Height of each font
5617 * 2 Character width spacing
5618 * 3 Line spacing
5619 * 4 Bytes per line
5620 */
5621
5622 font_width = font_header[0];
5623 font_height = font_header[1];
5624 width_spacing = font_header[2];
5625 line_spacing = font_header[3];
5626 bytes_per_line = font_header[4];
5627
5628 /* Calculate bytes per character */
5629 bytes_per_char_len = bytes_per_line * font_height;
5630
5631 /* Convert y position */
5632 y = height - y - font_height;
5633
5634 glRasterPos2i(x, y);
5635 glBitmap(
5636 font_width, font_height,
5637 0.0, 0.0,
5638 (GLfloat)width_spacing, 0.0,
5639 &font_data[
5640 bytes_per_char_len * c
5641 ]
5642 );
5643 }
5644
5645
5646 /*
5647 * Reads the header from the given image data.
5648 *
5649 * Returns non-zero on error.
5650 */
GWImageLoadHeaderFromData(gw_display_struct * display,int * width,int * height,int * bpl,int * bpp,const void * data)5651 int GWImageLoadHeaderFromData(
5652 gw_display_struct *display,
5653 int *width, int *height, int *bpl, int *bpp,
5654 const void *data
5655 )
5656 {
5657 const u_int8_t *src8;
5658
5659 if((display == NULL) || (data == NULL))
5660 {
5661 if(width != NULL) *width = 0;
5662 if(height != NULL) *height = 0;
5663 if(bpl != NULL) *bpl = 0;
5664 if(bpp != NULL) *bpp = 0;
5665 return(-1);
5666 }
5667
5668 /* First 32 bytes are header, format:
5669 *
5670 * <width32> <height32> <bpl32> <bpp32>
5671 */
5672 src8 = (const u_int8_t *)data + (0 * sizeof(u_int8_t));
5673
5674 if(width != NULL)
5675 *width = *(u_int32_t *)src8;
5676 src8 += sizeof(u_int32_t);
5677
5678 if(height != NULL)
5679 *height = *(u_int32_t *)src8;
5680 src8 += sizeof(u_int32_t);
5681
5682 if(bpl != NULL)
5683 *bpl = *(u_int32_t *)src8;
5684 src8 += sizeof(u_int32_t);
5685
5686 if(bpp != NULL)
5687 *bpp = *(u_int32_t *)src8;
5688
5689 return(0);
5690 }
5691
5692 /*
5693 * Loads image RGB (3 bytes per pixel) image data.
5694 */
GWImageLoadFromDataRGB(gw_display_struct * display,int * width,int * height,int * bpl,const void * data)5695 u_int8_t *GWImageLoadFromDataRGB(
5696 gw_display_struct *display,
5697 int *width, int *height, int *bpl,
5698 const void *data
5699 )
5700 {
5701 int w, h, lbpl, tar8_len;
5702 const u_int8_t *src8;
5703 u_int8_t *tar8;
5704
5705
5706 /* Get image data */
5707 src8 = GWImageLoadFromDataSharedRGB(
5708 display, &w, &h, &lbpl, data
5709 );
5710 if(src8 == NULL)
5711 {
5712 if(width != NULL) *width = 0;
5713 if(height != NULL) *height = 0;
5714 if(bpl != NULL) *bpl = 0;
5715 return(NULL);
5716 }
5717
5718 /* Image size too small? */
5719 if((w <= 0) || (h <= 0) || (lbpl <= 0))
5720 {
5721 if(width != NULL) *width = 0;
5722 if(height != NULL) *height = 0;
5723 if(bpl != NULL) *bpl = 0;
5724 return(NULL);
5725 }
5726
5727 /* Update returns */
5728 if(width != NULL) *width = w;
5729 if(height != NULL) *height = h;
5730 if(bpl != NULL) *bpl = lbpl;
5731
5732 /* Calculate size of image data in bytes */
5733 tar8_len = h * lbpl;
5734
5735 /* Allocate target image data */
5736 tar8 = (u_int8_t *)malloc(tar8_len);
5737 if(tar8 == NULL)
5738 return(NULL);
5739
5740 /* Copy source image data to target image data */
5741 memcpy(tar8, src8, tar8_len);
5742
5743 return(tar8);
5744 }
5745
5746 /*
5747 * Loads image RGB (3 bytes per pixel) image data.
5748 *
5749 * The returned pointer must not be deallocated since it points to
5750 * a position within the given data.
5751 */
GWImageLoadFromDataSharedRGB(gw_display_struct * display,int * width,int * height,int * bpl,const void * data)5752 const u_int8_t *GWImageLoadFromDataSharedRGB(
5753 gw_display_struct *display,
5754 int *width, int *height, int *bpl,
5755 const void *data
5756 )
5757 {
5758 int w, h, lbpl, lbpp;
5759
5760 /* Read header */
5761 if(GWImageLoadHeaderFromData(
5762 display, &w, &h, &lbpl, &lbpp, data
5763 ))
5764 {
5765 if(width != NULL) *width = 0;
5766 if(height != NULL) *height = 0;
5767 if(bpl != NULL) *bpl = 0;
5768 return(NULL);
5769 }
5770
5771 /* Bytes per pixel does not match? */
5772 if(lbpp != 3)
5773 {
5774 fprintf(
5775 stderr,
5776 "GWImageLoadFromDataSharedRGB(): Warning: Bytes per pixel %i is not 3.\n",
5777 lbpp
5778 );
5779 if(width != NULL) *width = 0;
5780 if(height != NULL) *height = 0;
5781 if(bpl != NULL) *bpl = 0;
5782 return(NULL);
5783 }
5784
5785 /* Need to calculate bytes per line? */
5786 if(lbpl <= 0)
5787 lbpl = w * lbpp;
5788
5789 /* Update returns */
5790 if(width != NULL) *width = w;
5791 if(height != NULL) *height = h;
5792 if(bpl != NULL) *bpl = lbpl;
5793
5794 /* Return image data */
5795 return((const u_int8_t *)data + (32 * sizeof(u_int8_t)));
5796 }
5797
5798 /*
5799 * Loads image RGBA (4 bytes per pixel) image data.
5800 */
GWImageLoadFromDataRGBA(gw_display_struct * display,int * width,int * height,int * bpl,const void * data)5801 u_int8_t *GWImageLoadFromDataRGBA(
5802 gw_display_struct *display,
5803 int *width, int *height, int *bpl,
5804 const void *data
5805 )
5806 {
5807 int w, h, lbpl, tar8_len;
5808 const u_int8_t *src8;
5809 u_int8_t *tar8;
5810
5811
5812 /* Get image data */
5813 src8 = GWImageLoadFromDataSharedRGBA(
5814 display, &w, &h, &lbpl, data
5815 );
5816 if(src8 == NULL)
5817 {
5818 if(width != NULL) *width = 0;
5819 if(height != NULL) *height = 0;
5820 if(bpl != NULL) *bpl = 0;
5821 return(NULL);
5822 }
5823
5824 /* Image size too small? */
5825 if((w <= 0) || (h <= 0) || (lbpl <= 0))
5826 {
5827 if(width != NULL) *width = 0;
5828 if(height != NULL) *height = 0;
5829 if(bpl != NULL) *bpl = 0;
5830 return(NULL);
5831 }
5832
5833 /* Update returns */
5834 if(width != NULL) *width = w;
5835 if(height != NULL) *height = h;
5836 if(bpl != NULL) *bpl = lbpl;
5837
5838 /* Calculate size of image data in bytes */
5839 tar8_len = h * lbpl;
5840
5841 /* Allocate target image data */
5842 tar8 = (u_int8_t *)malloc(tar8_len);
5843 if(tar8 == NULL)
5844 return(NULL);
5845
5846 /* Copy source image data to target image data */
5847 memcpy(tar8, src8, tar8_len);
5848
5849 return(tar8);
5850 }
5851
5852 /*
5853 * Loads image RGBA (4 bytes per pixel) image data.
5854 *
5855 * The returned pointer must not be deallocated since it points to
5856 * a position within the given data.
5857 */
GWImageLoadFromDataSharedRGBA(gw_display_struct * display,int * width,int * height,int * bpl,const void * data)5858 const u_int8_t *GWImageLoadFromDataSharedRGBA(
5859 gw_display_struct *display,
5860 int *width, int *height, int *bpl,
5861 const void *data
5862 )
5863 {
5864 int w, h, lbpl, lbpp;
5865
5866 /* Read header */
5867 if(GWImageLoadHeaderFromData(
5868 display, &w, &h, &lbpl, &lbpp, data
5869 ))
5870 {
5871 if(width != NULL) *width = 0;
5872 if(height != NULL) *height = 0;
5873 if(bpl != NULL) *bpl = 0;
5874 return(NULL);
5875 }
5876
5877 /* Bytes per pixel does not match? */
5878 if(lbpp != 4)
5879 {
5880 fprintf(
5881 stderr,
5882 "GWImageLoadFromDataSharedRGBA(): Warning: Bytes per pixel %i is not 4.\n",
5883 lbpp
5884 );
5885 if(width != NULL) *width = 0;
5886 if(height != NULL) *height = 0;
5887 if(bpl != NULL) *bpl = 0;
5888 return(NULL);
5889 }
5890
5891 /* Need to calculate bytes per line? */
5892 if(lbpl <= 0)
5893 lbpl = w * lbpp;
5894
5895 /* Update returns */
5896 if(width != NULL) *width = w;
5897 if(height != NULL) *height = h;
5898 if(bpl != NULL) *bpl = lbpl;
5899
5900 /* Return image data */
5901 return((const u_int8_t *)data + (32 * sizeof(u_int8_t)));
5902 }
5903
5904
5905 /*
5906 * Called by GWImageDrawFromData*() to draw the image.
5907 *
5908 * img_format may be GL_RGB or GL_RGBA.
5909 */
GWImageDrawFromDataNexus(gw_display_struct * display,const u_int8_t * img_data,int x,int y,int width,int height,int img_width,int img_height,GLenum img_format)5910 static void GWImageDrawFromDataNexus(
5911 gw_display_struct *display, const u_int8_t *img_data,
5912 int x, int y, int width, int height,
5913 int img_width, int img_height,
5914 GLenum img_format
5915 )
5916 {
5917 StateGLBoolean alpha_test;
5918 GLint x2, y2;
5919 GLfloat x_zoom_factor, y_zoom_factor;
5920 int win_width, win_height;
5921
5922 GWContextGet(
5923 display, GWContextCurrent(display),
5924 NULL, NULL,
5925 NULL, NULL,
5926 &win_width, &win_height
5927 );
5928
5929 /* If no requested image size set, then use actual image size */
5930 if(width < 1)
5931 width = img_width;
5932 if(height < 1)
5933 height = img_height;
5934
5935 /* Calculate GL converted coordinate positions */
5936 x2 = (GLint)MAX(x, 0);
5937 y2 = (GLint)MAX((win_height - y - 1), 0);
5938
5939 /* Calculate zoom factor based on the requested image size
5940 * and the actual image data size.
5941 */
5942 x_zoom_factor = (GLfloat)width / (GLfloat)img_width;
5943 y_zoom_factor = -(GLfloat)height / (GLfloat)img_height;
5944
5945 /* Set image drawing coordinates */
5946 glRasterPos2i(
5947 CLIP(x2, 0, win_width - 1),
5948 CLIP(y2, 0, win_height - 1)
5949 );
5950
5951 /* Set zoom factor of image */
5952 glPixelZoom(x_zoom_factor, y_zoom_factor);
5953
5954 /* Enable GL alpha testing if the image data has an alpha
5955 * channel.
5956 */
5957 alpha_test = display->state_gl.alpha_test;
5958 if(img_format == GL_RGBA)
5959 {
5960 StateGLEnable(&display->state_gl, GL_ALPHA_TEST);
5961 StateGLAlphaFunc(&display->state_gl, GL_GREATER, 0.5f);
5962 }
5963
5964 /* Draw the image */
5965 glDrawPixels(
5966 img_width, img_height,
5967 img_format, GL_UNSIGNED_BYTE,
5968 (const GLvoid *)img_data
5969 );
5970
5971 /* Restore GL states */
5972 if(!alpha_test)
5973 StateGLDisable(&display->state_gl, GL_ALPHA_TEST);
5974
5975 /* Restore zoom */
5976 glPixelZoom(1.0f, 1.0f);
5977 }
5978
5979
5980 /*
5981 * Draws the image specified by data, which must be in RGB format.
5982 */
GWImageDrawFromDataRGB(gw_display_struct * display,const void * data,int x,int y,int width,int height)5983 void GWImageDrawFromDataRGB(
5984 gw_display_struct *display, const void *data,
5985 int x, int y, int width, int height
5986 )
5987 {
5988 int img_width, img_height, bpl;
5989 const u_int8_t *img_data = GWImageLoadFromDataSharedRGB(
5990 display, &img_width, &img_height, &bpl,
5991 data
5992 );
5993 if(img_data == NULL)
5994 return;
5995
5996 GWImageDrawFromDataNexus(
5997 display, img_data,
5998 x, y, width, height,
5999 img_width, img_height,
6000 GL_RGB
6001 );
6002 }
6003
6004 /*
6005 * Draws the image specified by data, which must be in RGBA format.
6006 */
GWImageDrawFromDataRGBA(gw_display_struct * display,const void * data,int x,int y,int width,int height)6007 void GWImageDrawFromDataRGBA(
6008 gw_display_struct *display, const void *data,
6009 int x, int y, int width, int height
6010 )
6011 {
6012 int img_width, img_height, bpl;
6013 const u_int8_t *img_data = GWImageLoadFromDataSharedRGBA(
6014 display, &img_width, &img_height, &bpl,
6015 data
6016 );
6017 if(img_data == NULL)
6018 return;
6019
6020 GWImageDrawFromDataNexus(
6021 display, img_data,
6022 x, y, width, height,
6023 img_width, img_height,
6024 GL_RGBA
6025 );
6026 }
6027
6028