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