AllegroGL 0.4.4

- Main Page
- Related Pages
- Modules
- Files

- File List
- Globals

x.c
1 /* This code is (C) AllegroGL contributors, and double licensed under
2 * the GPL and zlib licenses. See gpl.txt or zlib.txt for details.
3 */
4 /*----------------------------------------------------------------
5 * x.c -- Allegro-GLX interfacing
6 *----------------------------------------------------------------
7 * This is the interface module for use under X.
8 */
9 #include <string.h>
10 #include <stdio.h>
11
12 #include <allegro.h>
13 #include <xalleg.h>
14
15 #include <allegro/platform/aintunix.h>
16
17 #include "alleggl.h"
18 #include "allglint.h"
19 #include "glvtable.h"
20
21
22 #ifndef XLOCK
23 #define OLD_ALLEGRO
24 #define XLOCK() DISABLE()
25 #undef XUNLOCK
26 #define XUNLOCK() ENABLE()
27 #endif
28
29 #define PREFIX_I "agl-x INFO: "
30 #define PREFIX_E "agl-x ERROR: "
31
32
33 #ifdef ALLEGRO_XWINDOWS_WITH_XPM
34 #include <X11/xpm.h>
35 extern void *allegro_icon;
36 #endif
37
38
39 static BITMAP *allegro_gl_x_windowed_init(int w, int h, int vw, int vh,
40 int color_depth);
41 static void allegro_gl_x_exit(BITMAP *bmp);
42 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
43 static GFX_MODE_LIST* allegro_gl_x_fetch_mode_list(void);
44 #endif
45 static void allegro_gl_x_vsync(void);
46 static void allegro_gl_x_hide_mouse(void);
47
48 static BITMAP *allegro_gl_screen = NULL;
49
50 /* TODO: Revamp the whole window handling under X11 in Allegro and
51 * AllegroGL. We really shouldn't have to duplicate code or hack on
52 * Allegro internals in AllegroGL - the *only* difference for the AllegroGL
53 * window should be the GLX visual (e.g. cursor, icon, VidModeExtension and
54 * so on should never have been touched in this file).
55 */
56 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
57 static Window backup_allegro_window = None;
58 static Colormap backup_allegro_colormap = None;
59 #endif
60
61
62 static BITMAP *allegro_gl_x_fullscreen_init(int w, int h, int vw, int vh,
63 int color_depth);
64
65 GFX_DRIVER gfx_allegro_gl_fullscreen =
66 {
67 GFX_OPENGL_FULLSCREEN,
68 empty_string,
69 empty_string,
70 "AllegroGL Fullscreen (X)",
71 allegro_gl_x_fullscreen_init,
72 allegro_gl_x_exit,
73 NULL,
74 allegro_gl_x_vsync,
75 NULL,
76 NULL, NULL, NULL,
77 allegro_gl_create_video_bitmap,
78 allegro_gl_destroy_video_bitmap,
79 NULL, NULL, /* No show/request video bitmaps */
80 NULL, NULL,
81 allegro_gl_set_mouse_sprite,
82 allegro_gl_show_mouse,
83 allegro_gl_x_hide_mouse,
84 allegro_gl_move_mouse,
85 allegro_gl_drawing_mode,
86 NULL, NULL,
87 allegro_gl_set_blender_mode,
88 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
89 allegro_gl_x_fetch_mode_list,
90 #else
91 NULL,
92 #endif
93 0, 0,
94 0,
95 0, 0,
96 0,
97 0,
98 FALSE /* Windowed mode */
99 };
100
101
102
103 GFX_DRIVER gfx_allegro_gl_windowed =
104 {
105 GFX_OPENGL_WINDOWED,
106 empty_string,
107 empty_string,
108 "AllegroGL Windowed (X)",
109 allegro_gl_x_windowed_init,
110 allegro_gl_x_exit,
111 NULL,
112 allegro_gl_x_vsync,
113 NULL,
114 NULL, NULL, NULL,
115 allegro_gl_create_video_bitmap,
116 allegro_gl_destroy_video_bitmap,
117 NULL, NULL, /* No show/request video bitmaps */
118 NULL, NULL,
119 allegro_gl_set_mouse_sprite,
120 allegro_gl_show_mouse,
121 allegro_gl_x_hide_mouse,
122 allegro_gl_move_mouse,
123 allegro_gl_drawing_mode,
124 NULL, NULL,
125 allegro_gl_set_blender_mode,
126 NULL, /* No fetch_mode_list */
127 0, 0,
128 0,
129 0, 0,
130 0,
131 0,
132 TRUE /* Windowed mode */
133 };
134
135
136
137 static struct allegro_gl_driver allegro_gl_x;
138
139 static XVisualInfo *allegro_gl_x_windowed_choose_visual (void);
140 static int allegro_gl_x_create_window (int fullscreen);
141 static BITMAP *allegro_gl_x_windowed_create_screen (GFX_DRIVER *drv, int w, int h, int depth);
142
143 static int decode_visual (XVisualInfo *v, struct allegro_gl_display_info *i);
144 struct {
145 int fullscreen;
146 GLXContext ctx;
147 int major, minor; /* Major and minor GLX version */
148 int error_base, event_base;
149 int use_glx_window;
150 GLXWindow window;
151 } _glxwin;
152
153 static void (*old_window_redrawer)(int, int, int, int);
154 extern void (*_xwin_window_redrawer)(int, int, int, int);
155 static int (*old_x_error_handler)(Display*, XErrorEvent*);
156
157
158
159 /* allegro_gl_redraw_window :
160 * Redraws the window when an Expose event is processed
161 * Important note : no GL commands should be processed in this function
162 * since it may be called by a thread which is different from the main thread.
163 * In order to be able to process GL commands, we should create another context
164 * and make it current to the other thread. IMHO it would be overkill.
165 */
166 static void allegro_gl_redraw_window(int x, int y, int w, int h)
167 {
168 /* Does nothing */
169 return;
170 }
171
172
173
174 #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
175 /* _xwin_hide_x_mouse:
176 * Create invisible X cursor
177 */
178 static void _xwin_hide_x_mouse(void)
179 {
180 unsigned long gcmask;
181 XGCValues gcvalues;
182 Pixmap pixmap;
183
184 XUndefineCursor(_xwin.display, _xwin.window);
185
186 if (_xwin.cursor != None) {
187 XFreeCursor(_xwin.display, _xwin.cursor);
188 _xwin.cursor = None;
189 }
190
191 if (_xwin.xcursor_image != None) {
192 XcursorImageDestroy(_xwin.xcursor_image);
193 _xwin.xcursor_image = None;
194 }
195
196 pixmap = XCreatePixmap(_xwin.display, _xwin.window, 1, 1, 1);
197 if (pixmap != None) {
198 GC temp_gc;
199 XColor color;
200
201 gcmask = GCFunction | GCForeground | GCBackground;
202 gcvalues.function = GXcopy;
203 gcvalues.foreground = 0;
204 gcvalues.background = 0;
205 temp_gc = XCreateGC(_xwin.display, pixmap, gcmask, &gcvalues);
206 XDrawPoint(_xwin.display, pixmap, temp_gc, 0, 0);
207 XFreeGC(_xwin.display, temp_gc);
208 color.pixel = 0;
209 color.red = color.green = color.blue = 0;
210 color.flags = DoRed | DoGreen | DoBlue;
211 _xwin.cursor = XCreatePixmapCursor(_xwin.display, pixmap, pixmap, &color, &color, 0, 0);
212 XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
213 XFreePixmap(_xwin.display, pixmap);
214 }
215 else {
216 _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape);
217 XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
218 }
219 }
220 #endif
221
222
223
224 /* hide_mouse:
225 * Hide the custom X cursor (if supported)
226 */
227 static void hide_mouse(void)
228 {
229 #ifdef ALLEGRO_XWINDOWS_WITH_XCURSOR
230 if (_xwin.support_argb_cursor) {
231 XLOCK();
232 _xwin_hide_x_mouse();
233 XUNLOCK();
234 }
235 #endif
236 return;
237 }
238
239
240
241 /* If Allegro's X11 mouse driver enabled hw cursors, we shouldn't use
242 * allegro_gl_hide_mouse();
243 */
244 static void allegro_gl_x_hide_mouse(void)
245 {
246 if (_xwin.hw_cursor_ok) {
247 hide_mouse();
248 }
249 else {
250 allegro_gl_hide_mouse();
251 }
252 }
253
254
255
256 /* allegro_gl_x_windowed_init:
257 * Creates screen bitmap.
258 */
259 static BITMAP *allegro_gl_x_create_screen(int w, int h, int vw, int vh,
260 int depth, int fullscreen)
261 {
262 int _keyboard_was_installed = FALSE;
263 int _mouse_was_installed = FALSE;
264 int create_window_ret;
265
266 /* test if Allegro have pthread support enabled */
267 if (!_unix_bg_man->multi_threaded) {
268 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
269 get_config_text("Fatal Error : pthread support is not enabled"));
270 return NULL;
271 }
272
273 if (keyboard_driver) {
274 _keyboard_was_installed = TRUE;
275 remove_keyboard();
276 TRACE(PREFIX_I "x_create_screen: Removing Keyboard...\n");
277 }
278
279 if (mouse_driver) {
280 _mouse_was_installed = TRUE;
281 remove_mouse();
282 TRACE(PREFIX_I "x_create_screen: Removing Mouse...\n");
283 }
284
285 XLOCK();
286
287 if (!glXQueryExtension(_xwin.display, &_glxwin.error_base,
288 &_glxwin.event_base)) {
289
290 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
291 get_config_text("GLX Extension not supported by display"));
292 XUNLOCK();
293 goto failure;
294 }
295
296 sscanf(glXQueryServerString(_xwin.display, _xwin.screen, GLX_VERSION),
297 "%i.%i", &_glxwin.major, &_glxwin.minor);
298
299 if ((w == 0) && (h == 0)) {
300 w = 640;
301 h = 480;
302 }
303
304 if ((vw > w) || (vh > h)) {
305 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
306 get_config_text ("OpenGL drivers do not support virtual screens"));
307 XUNLOCK();
308 goto failure;
309 }
310
311 allegro_gl_display_info.w = w;
312 allegro_gl_display_info.h = h;
313
314 old_window_redrawer = _xwin_window_redrawer;
315 _xwin_window_redrawer = allegro_gl_redraw_window;
316 _glxwin.fullscreen = FALSE;
317 _glxwin.use_glx_window = FALSE;
318
319 create_window_ret = allegro_gl_x_create_window(fullscreen);
320 if (create_window_ret) {
321 if (fullscreen && create_window_ret == -2) {
322 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
323 get_config_text ("Unable to switch in GLX fullscreen"));
324 }
325 else if (create_window_ret == -2) {
326 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
327 get_config_text ("Unable to create GLX window"));
328 }
329 XUNLOCK();
330 allegro_gl_x_exit(NULL);
331 goto failure;
332 }
333
334 /* If pixel format is Allegro compatible, set up Allegro correctly. */
335 set_color_depth(allegro_gl_display_info.colour_depth);
336
337 /* XXX <rohannessian> X can run on Big-Endian systems. We need to
338 * make a check for that and pass TRUE to
339 * __allegro_gl_set_allegro_image_format() in that case.
340 */
341 __allegro_gl_set_allegro_image_format(FALSE);
342
343 if (fullscreen) {
344 allegro_gl_screen =
345 allegro_gl_x_windowed_create_screen (&gfx_allegro_gl_fullscreen,
346 allegro_gl_display_info.w, allegro_gl_display_info.h,
347 _color_depth);
348 }
349 else {
350 allegro_gl_screen =
351 allegro_gl_x_windowed_create_screen (&gfx_allegro_gl_windowed,
352 allegro_gl_display_info.w, allegro_gl_display_info.h,
353 _color_depth);
354 }
355
356 if (!allegro_gl_screen) {
357 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
358 get_config_text ("Error creating screen bitmap"));
359 XUNLOCK();
360 allegro_gl_x_exit(NULL);
361 goto failure;
362 }
363
364 __allegro_gl_valid_context = TRUE;
365 __allegro_gl_driver = &allegro_gl_x;
366
367 /* Print out OpenGL version info */
368 TRACE(PREFIX_I "OpenGL Version: %s\n", (AL_CONST char*)glGetString(GL_VERSION));
369 TRACE(PREFIX_I "OpenGL Vendor: %s\n", (AL_CONST char*)glGetString(GL_VENDOR));
370 TRACE(PREFIX_I "OpenGL Renderer: %s\n", (AL_CONST char*)glGetString(GL_RENDERER));
371
372 /* Detect if the GL driver is based on Mesa */
373 allegro_gl_info.is_mesa_driver = FALSE;
374 if (strstr((AL_CONST char*)glGetString(GL_VERSION),"Mesa")) {
375 AGL_LOG(1, "OpenGL driver based on Mesa\n");
376 allegro_gl_info.is_mesa_driver = TRUE;
377 }
378
379 /* Print out GLX version info */
380 TRACE(PREFIX_I "GLX Version: %d.%d\n", _glxwin.major, _glxwin.minor);
381
382 #ifdef LOGLEVEL
383 if (glXIsDirect(_xwin.display, _glxwin.ctx)) {
384 AGL_LOG(1, "GLX Direct Rendering is enabled\n");
385 }
386 else {
387 AGL_LOG(1, "GLX Direct Rendering is disabled\n");
388 }
389 #endif
390
391 /* Prints out GLX extensions info */
392 AGL_LOG(1, "glX Extensions:\n");
393 #ifdef LOGLEVEL
394 __allegro_gl_print_extensions(
395 (AL_CONST char*)glXQueryExtensionsString(_xwin.display, _xwin.screen));
396 #endif
397 /* Prints out OpenGL extensions info and activates needed extensions */
398 __allegro_gl_manage_extensions();
399
400 /* Update screen vtable in order to use AGL's */
401 __allegro_gl__glvtable_update_vtable (&allegro_gl_screen->vtable);
402 memcpy(&_screen_vtable, allegro_gl_screen->vtable, sizeof(GFX_VTABLE));
403 allegro_gl_screen->vtable = &_screen_vtable;
404
405 XUNLOCK();
406
407 if (_keyboard_was_installed) {
408 TRACE(PREFIX_I "x_create_screen: Installing Keyboard...\n");
409 install_keyboard();
410 }
411
412 if (_mouse_was_installed) {
413 TRACE(PREFIX_I "x_create_screen: Installing Mouse...\n");
414 install_mouse();
415 }
416 gfx_capabilities |= GFX_HW_CURSOR;
417
418 return allegro_gl_screen;
419
420 failure:
421 if (_keyboard_was_installed) {
422 install_keyboard();
423 }
424
425 if (_mouse_was_installed) {
426 install_mouse();
427 }
428
429 return NULL;
430 }
431
432
433
434 /* allegro_gl_x_windowed_init:
435 * Creates screen bitmap for windowed driver.
436 */
437 static BITMAP *allegro_gl_x_windowed_init(int w, int h, int vw, int vh,
438 int depth)
439 {
440 return allegro_gl_x_create_screen(w, h, vw, vh, depth, FALSE);
441 }
442
443
444
445 /* allegro_gl_x_fullscreen_init:
446 * Creates screen bitmap for fullscreen driver.
447 */
448 static BITMAP *allegro_gl_x_fullscreen_init(int w, int h, int vw, int vh,
449 int depth)
450 {
451 return allegro_gl_x_create_screen(w, h, vw, vh, depth, TRUE);
452 }
453
454
455
456 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
457 /* free_modelines:
458 * Free mode lines.
459 */
460 static void free_modelines(XF86VidModeModeInfo **modesinfo, int num_modes)
461 {
462 int i;
463
464 for (i = 0; i < num_modes; i++)
465 if (modesinfo[i]->privsize > 0)
466 XFree(modesinfo[i]->private);
467 XFree(modesinfo);
468 }
469 #endif
470
471
472
473 /* allegro_gl_x_exit:
474 * Shuts down the driver (shared between windowed and full-screen)
475 */
476 static void allegro_gl_x_exit(BITMAP *bmp)
477 {
478 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
479 XSetWindowAttributes setattr;
480 #endif
481
482 XLOCK();
483 /* We politely wait for OpenGL to finish its current operations before
484 shutting down the driver */
485 glXWaitGL();
486
487 __allegro_gl_unmanage_extensions();
488
489 if (_glxwin.ctx) {
490 if (!allegro_gl_info.is_ati_r200_chip) {
491 /* The DRI drivers for ATI cards with R200 chip
492 * seem to be broken since they crash at this point.
493 * As a workaround AGL does not release the GLX context
494 * here. This should not hurt since the GLX specs don't
495 * require the context to be released before the program
496 * ends or before another context is made current to the
497 * thread.
498 */
499 if (!glXMakeCurrent(_xwin.display, None, NULL)) {
500 ustrzcpy (allegro_error, ALLEGRO_ERROR_SIZE,
501 get_config_text ("Could not release drawing context.\n"));
502 }
503 }
504
505 glXDestroyContext(_xwin.display, _glxwin.ctx);
506 _glxwin.ctx = NULL;
507 }
508
509 if (_xwin.mouse_grabbed) {
510 XUngrabPointer(_xwin.display, CurrentTime);
511 _xwin.mouse_grabbed = 0;
512 }
513
514 if (_xwin.keyboard_grabbed) {
515 XUngrabKeyboard(_xwin.display, CurrentTime);
516 _xwin.keyboard_grabbed = 0;
517 }
518
519 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
520 if (_glxwin.fullscreen) {
521 if (_xwin.mode_switched) {
522 XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, False);
523 XF86VidModeSwitchToMode(_xwin.display, _xwin.screen,
524 _xwin.modesinfo[0]);
525 XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0);
526 _xwin.mode_switched = 0;
527 }
528 if (_xwin.override_redirected) {
529 setattr.override_redirect = False;
530 XChangeWindowAttributes(_xwin.display, _xwin.window,
531 CWOverrideRedirect, &setattr);
532 _xwin.override_redirected = 0;
533 }
534
535 /* Free modelines. */
536 free_modelines(_xwin.modesinfo, _xwin.num_modes);
537 _xwin.num_modes = 0;
538 _xwin.modesinfo = NULL;
539 }
540 #endif
541
542 /* Note: Allegro will destroy screen (== allegro_gl_screen),
543 * so don't destroy it here.
544 */
545 //destroy_bitmap(allegro_gl_screen);
546 ASSERT(allegro_gl_screen == screen);
547 allegro_gl_screen = NULL;
548
549 /* Unmap the window in order not to see the cursor when quitting.
550 The window *must not* be destroyed and _xwin.visual must be left
551 to its current value otherwise the program will crash when exiting */
552 if (_xwin.window != None)
553 XUnmapWindow(_xwin.display, _xwin.window);
554
555 if (_glxwin.use_glx_window) {
556 glXDestroyWindow(_xwin.display, _glxwin.window);
557 _glxwin.window = 0;
558 _glxwin.use_glx_window = FALSE;
559 }
560
561 __allegro_gl_valid_context = FALSE;
562
563 _xwin_window_redrawer = old_window_redrawer;
564 XSetErrorHandler(old_x_error_handler);
565
566
567 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
568 /* Hack: Allegro 4.2.1 uses a persistent window, we need to restore it. */
569 if (backup_allegro_window != None) {
570 if (_xwin.colormap != None) {
571 XUninstallColormap(_xwin.display, _xwin.colormap);
572 XFreeColormap(_xwin.display, _xwin.colormap);
573 }
574 _xwin.colormap = backup_allegro_colormap;
575
576 if (_xwin.window != None)
577 XDestroyWindow(_xwin.display, _xwin.window);
578 _xwin.window = backup_allegro_window;
579 backup_allegro_window = None;
580 XMapWindow(_xwin.display, _xwin.window);
581 }
582 #endif
583
584 XUNLOCK();
585 }
586
587
588
589 /* get_shift:
590 * Returns the shift value for a given mask.
591 */
592 static int get_shift (int mask)
593 {
594 int i = 0, j = 1;
595 if (!mask) return -1;
596 while (!(j & mask)) {
597 i++;
598 j <<= 1;
599 }
600 return i;
601 }
602
603
604
605 static int decode_fbconfig (GLXFBConfig fbc, struct allegro_gl_display_info *i) {
606 int render_type, visual_type, buffer_size, sbuffers, samples;
607 int drawable_type, renderable;
608 XVisualInfo *v;
609
610 TRACE(PREFIX_I "decode_fbconfig: Decoding:\n");
611 i->rmethod = 2;
612
613 if (glXGetFBConfigAttrib (_xwin.display, fbc, GLX_RENDER_TYPE,
614 &render_type)
615 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_X_RENDERABLE,
616 &renderable)
617 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_DRAWABLE_TYPE,
618 &drawable_type)
619 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_X_VISUAL_TYPE,
620 &visual_type)
621 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_BUFFER_SIZE,
622 &buffer_size)
623 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_DEPTH_SIZE,
624 &i->depth_size)
625 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_STEREO,
626 &i->stereo)
627 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_RED_SIZE,
628 &i->pixel_size.rgba.r)
629 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_GREEN_SIZE,
630 &i->pixel_size.rgba.g)
631 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_BLUE_SIZE,
632 &i->pixel_size.rgba.b)
633 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ALPHA_SIZE,
634 &i->pixel_size.rgba.a)
635 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_DOUBLEBUFFER,
636 &i->doublebuffered)
637 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_AUX_BUFFERS,
638 &i->aux_buffers)
639 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_STENCIL_SIZE,
640 &i->stencil_size)
641 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_RED_SIZE,
642 &i->accum_size.rgba.r)
643 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_GREEN_SIZE,
644 &i->accum_size.rgba.g)
645 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_BLUE_SIZE,
646 &i->accum_size.rgba.b)
647 || glXGetFBConfigAttrib (_xwin.display, fbc, GLX_ACCUM_ALPHA_SIZE,
648 &i->accum_size.rgba.a)) {
649 TRACE(PREFIX_I "decode_fbconfig: Incomplete glX mode ...\n");
650 return -1;
651 }
652
653 if (!(render_type & GLX_RGBA_BIT) && !(render_type & GLX_RGBA_FLOAT_BIT)) {
654 TRACE(PREFIX_I "decode_fbconfig: Not RGBA mode\n");
655 return -1;
656 }
657
658 if (!(drawable_type & GLX_WINDOW_BIT)) {
659 TRACE(PREFIX_I "decode_fbconfig: Cannot render to a window.\n");
660 return -1;
661 }
662
663 if (renderable == False) {
664 TRACE(PREFIX_I "decode_fbconfig: GLX windows not supported.\n");
665 return -1;
666 }
667
668 if (visual_type != GLX_TRUE_COLOR && visual_type != GLX_DIRECT_COLOR) {
669 TRACE(PREFIX_I "decode_fbconfig: visual type other than TrueColor and "
670 "DirectColor.\n");
671 return -1;
672 }
673
674 /* Floating-point depth is not supported as glx extension (yet). */
675 i->float_depth = 0;
676
677 i->float_color = (render_type & GLX_RGBA_FLOAT_BIT);
678
679 v = glXGetVisualFromFBConfig(_xwin.display, fbc);
680 if (!v) {
681 TRACE(PREFIX_I "decode_fbconfig: Cannot get associated visual for the "
682 "FBConfig.\n");
683 return -1;
684 }
685 i->r_shift = get_shift (v->red_mask);
686 i->g_shift = get_shift (v->green_mask);
687 i->b_shift = get_shift (v->blue_mask);
688 i->a_shift = 0;
689
690 /* If we are going to need to setup a palette we need bit shifts */
691 if ((visual_type == GLX_DIRECT_COLOR)
692 && ((i->r_shift == -1) || (i->g_shift == -1) || (i->b_shift == -1))
693 && (i->pixel_size.rgba.r + i->pixel_size.rgba.g + i->pixel_size.rgba.b
694 <= 12)) {
695 /* XXX <rohannessian> Report something here? */
696 XFree(v);
697 return -1;
698 }
699
700 i->colour_depth = 0;
701
702 if (i->pixel_size.rgba.r == 3
703 && i->pixel_size.rgba.g == 3
704 && i->pixel_size.rgba.b == 2) {
705 i->colour_depth = 8;
706 }
707
708 if (i->pixel_size.rgba.r == 5
709 && i->pixel_size.rgba.b == 5) {
710 if (i->pixel_size.rgba.g == 5) {
711 i->colour_depth = 15;
712 }
713 if (i->pixel_size.rgba.g == 6) {
714 i->colour_depth = 16;
715 }
716 }
717
718 if (i->pixel_size.rgba.r == 8
719 && i->pixel_size.rgba.g == 8
720 && i->pixel_size.rgba.b == 8) {
721 if (i->pixel_size.rgba.a == 0) {
722 i->colour_depth = 24;
723 }
724 if (i->pixel_size.rgba.a == 8) {
725 i->colour_depth = 32;
726 /* small hack that tries to guess alpha shifting */
727 i->a_shift = 48 - i->r_shift - i->g_shift - i->b_shift;
728 }
729 }
730
731 i->allegro_format = (i->colour_depth != 0)
732 && (i->g_shift == i->pixel_size.rgba.b)
733 && (i->r_shift * i->b_shift == 0)
734 && (i->r_shift + i->b_shift
735 == i->pixel_size.rgba.b + i->pixel_size.rgba.g);
736
737 if (glXGetConfig(_xwin.display, v, GLX_SAMPLE_BUFFERS, &sbuffers)) {
738 /* Multisample extension is not supported */
739 i->sample_buffers = 0;
740 }
741 else {
742 i->sample_buffers = sbuffers;
743 }
744 if (glXGetConfig(_xwin.display, v, GLX_SAMPLES, &samples)) {
745 /* Multisample extension is not supported */
746 i->samples = 0;
747 }
748 else {
749 i->samples = samples;
750 }
751
752 XFree(v);
753
754 TRACE(PREFIX_I "Color Depth: %i\n", buffer_size);
755 TRACE(PREFIX_I "RGBA Type: %s point\n", i->float_color ? "floating" : "fixed");
756 TRACE(PREFIX_I "RGBA: %i.%i.%i.%i\n", i->pixel_size.rgba.r, i->pixel_size.rgba.g,
757 i->pixel_size.rgba.b, i->pixel_size.rgba.a);
758 TRACE(PREFIX_I "Accum: %i.%i.%i.%i\n", i->accum_size.rgba.r, i->accum_size.rgba.g,
759 i->accum_size.rgba.b, i->accum_size.rgba.a);
760 TRACE(PREFIX_I "DblBuf: %i Zbuf: %i Stereo: %i Aux: %i Stencil: %i\n",
761 i->doublebuffered, i->depth_size, i->stereo,
762 i->aux_buffers, i->stencil_size);
763 TRACE(PREFIX_I "Shift: %i.%i.%i.%i\n", i->r_shift, i->g_shift, i->b_shift,
764 i->a_shift);
765 TRACE(PREFIX_I "Sample Buffers: %i Samples: %i\n", i->sample_buffers, i->samples);
766 TRACE(PREFIX_I "Decoded bpp: %i\n", i->colour_depth);
767
768 return 0;
769 }
770
771
772
773 int allegro_gl_x_windowed_choose_fbconfig (GLXFBConfig *ret_fbconfig) {
774 int num_fbconfigs, i;
775 GLXFBConfig *fbconfig;
776 struct allegro_gl_display_info dinfo;
777
778 fbconfig = glXGetFBConfigs (_xwin.display, _xwin.screen, &num_fbconfigs);
779 if (!fbconfig || !num_fbconfigs)
780 return FALSE;
781
782 TRACE(PREFIX_I "x_windowed_choose_fbconfig: %i formats.\n", num_fbconfigs);
783 __allegro_gl_reset_scorer();
784
785 for (i = 0; i < num_fbconfigs; i++) {
786 TRACE(PREFIX_I "x_windowed_choose_fbconfig: Mode %i\n", i);
787 if (decode_fbconfig (*(fbconfig + i), &dinfo) != -1) {
788 __allegro_gl_score_config (i, &dinfo);
789 }
790 }
791
792 i = __allegro_gl_best_config();
793 TRACE(PREFIX_I "x_windowed_choose_fbconfig: Best FBConfig is: %i\n", i);
794
795 if (i < 0) {
796 XFree(fbconfig);
797 return FALSE;
798 }
799
800 *ret_fbconfig = *(fbconfig + i);
801 XFree(fbconfig);
802
803 return TRUE;
804 }
805
806
807
808 /* windowed_choose_visual:
809 * Chooses a visual to use.
810 */
811 static XVisualInfo *allegro_gl_x_windowed_choose_visual (void)
812 {
813 int num_visuals, i;
814 XVisualInfo *vinfo;
815 struct allegro_gl_display_info dinfo;
816 static XVisualInfo ret_vinfo;
817
818 vinfo = XGetVisualInfo (_xwin.display, 0, NULL, &num_visuals);
819 if (!vinfo) return NULL;
820
821 TRACE(PREFIX_I "x_windowed_choose_visual: %i formats.\n", num_visuals);
822 __allegro_gl_reset_scorer();
823
824 for (i = 0; i < num_visuals; i++) {
825 TRACE(PREFIX_I "x_windowed_choose_visual: Mode %i\n", i);
826 if (decode_visual (vinfo + i, &dinfo) != -1) {
827 __allegro_gl_score_config (i, &dinfo);
828 }
829 }
830
831 i = __allegro_gl_best_config();
832 TRACE(PREFIX_I "x_windowed_choose_visual: Best config is: %i\n", i);
833
834 if (i < 0) return NULL;
835
836 memcpy (&ret_vinfo, vinfo+i, sizeof ret_vinfo);
837 XFree (vinfo);
838
839 return &ret_vinfo;
840 }
841
842
843
844 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
845 /* get_xf86_modes:
846 * Test if the XF86VidMode extension is available and get the gfx modes
847 * that can be queried.
848 */
849 static int get_xf86_modes(XF86VidModeModeInfo ***modesinfo, int *num_modes)
850 {
851 int vid_event_base, vid_error_base;
852 int vid_major_version, vid_minor_version;
853
854 /* Test for presence of VidMode extension. */
855 if (!XF86VidModeQueryExtension(_xwin.display, &vid_event_base,
856 &vid_error_base)
857 || !XF86VidModeQueryVersion(_xwin.display, &vid_major_version,
858 &vid_minor_version)) {
859
860 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
861 get_config_text("VidMode extension is not supported"));
862 return -1;
863 }
864
865 if (!XF86VidModeGetAllModeLines(_xwin.display, _xwin.screen, num_modes,
866 modesinfo)) {
867 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
868 get_config_text("Can not Get ModeLines"));
869 return -1;
870 }
871
872 return 0;
873 }
874 #endif
875
876
877 static int allegro_gl_x_error_handler(Display *display, XErrorEvent *err_event)
878 {
879 char buffer[256];
880
881 XGetErrorText(display, err_event->error_code, buffer, 256);
882 TRACE(PREFIX_E "%s\n", buffer);
883 return 0;
884 }
885
886
887 /* create_window:
888 * Based on Michael's `_xwin[_private]_create_window' and the xdemos
889 * from the Mesa distribution (I don't remember which one).
890 */
891 static int allegro_gl_x_create_window (int fullscreen)
892 {
893 Window root;
894 XVisualInfo *visinfo;
895 XSetWindowAttributes setattr;
896 unsigned long valuemask = CWBackPixel | CWBorderPixel | CWColormap
897 | CWEventMask;
898 XSizeHints *hints;
899 GLXFBConfig fbconfig;
900 int use_fbconfig;
901
902 if (_xwin.display == 0) {
903 return -2;
904 }
905
906 old_x_error_handler = XSetErrorHandler(allegro_gl_x_error_handler);
907
908 /* Fill in missing color depth info */
909 __allegro_gl_fill_in_info();
910
911 use_fbconfig = (_glxwin.major > 1 || (_glxwin.major == 1 && _glxwin.minor >= 3));
912
913 if (use_fbconfig) {
914 TRACE(PREFIX_I "x_create_window: using FBConfig routines\n");
915
916 if (!allegro_gl_x_windowed_choose_fbconfig(&fbconfig)) {
917 TRACE(PREFIX_I "x_create_window: Failed using FBConfig, switching "
918 "back to VisualInfo routines\n");
919 use_fbconfig = FALSE;
920 goto old_choose_visual;
921 }
922
923 /* Query back FBConfig components */
924 if (decode_fbconfig(fbconfig, &allegro_gl_display_info)) {
925 TRACE(PREFIX_E "x_create_window: Cannot decode FBConfig, switching "
926 "back to VisualInfo routines\n");
927 use_fbconfig = FALSE;
928 goto old_choose_visual;
929 }
930
931 visinfo = glXGetVisualFromFBConfig(_xwin.display, fbconfig);
932 if (!visinfo) {
933 TRACE(PREFIX_I "x_create_window: Failed to convert FBConfig to "
934 "visual, switching back to VisualInfo routines\n");
935 use_fbconfig = FALSE;
936 goto old_choose_visual;
937 }
938 }
939 else {
940 old_choose_visual:
941 TRACE(PREFIX_I "x_create_window: using VisualInfo routines\n");
942
943 /* Find best visual */
944 visinfo = allegro_gl_x_windowed_choose_visual();
945 if (!visinfo) {
946 TRACE(PREFIX_E "x_create_window: Can not get visual.\n");
947 XSetErrorHandler(old_x_error_handler);
948 return -2;
949 }
950
951 /* Query back visual components */
952 if (decode_visual (visinfo, &allegro_gl_display_info)) {
953 TRACE(PREFIX_E "x_create_window: Can not decode visual.\n");
954 XSetErrorHandler(old_x_error_handler);
955 return -2;
956 }
957 }
958
959 /* Log some information about it */
960 switch (visinfo->class) {
961 case TrueColor:
962 AGL_LOG (1, "x.c: visual class: TrueColor\n");
963 break;
964 case DirectColor:
965 AGL_LOG (1, "x.c: visual class: DirectColor\n");
966 break;
967 default:
968 AGL_LOG (1, "x.c: visual class: invalid(!)\n");
969 }
970
971
972 /* Begin window creation. */
973
974 #if GET_ALLEGRO_VERSION() >= MAKE_VER(4, 2, 1)
975 /* Hack: For Allegro 4.2.1, we need to keep the existing window. */
976 if (backup_allegro_window == None) {
977 backup_allegro_window = _xwin.window;
978 backup_allegro_colormap = _xwin.colormap;
979 _xwin.colormap = None;
980 XUnmapWindow(_xwin.display, _xwin.window);
981 }
982 else
983 #endif
984 XDestroyWindow (_xwin.display, _xwin.window);
985
986 _xwin.window = None;
987
988 root = RootWindow (_xwin.display, _xwin.screen);
989
990 /* Recreate window. */
991 setattr.background_pixel = XBlackPixel (_xwin.display, _xwin.screen);
992 setattr.border_pixel = XBlackPixel (_xwin.display, _xwin.screen);
993 setattr.colormap = XCreateColormap (_xwin.display, root, visinfo->visual, AllocNone);
994 setattr.event_mask =
995 ( KeyPressMask | KeyReleaseMask
996 | EnterWindowMask | LeaveWindowMask
997 | FocusChangeMask | ExposureMask
998 | ButtonPressMask | ButtonReleaseMask | PointerMotionMask
999 /*| MappingNotifyMask (SubstructureRedirectMask?)*/
1000 );
1001
1002 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
1003 if (fullscreen) {
1004 int i;
1005 int bestmode = 0;
1006 _xwin.num_modes = 0;
1007 _xwin.modesinfo = NULL;
1008 _glxwin.fullscreen = TRUE;
1009
1010 if (get_xf86_modes(&_xwin.modesinfo, &_xwin.num_modes)) {
1011 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1012 get_config_text("x_create_window: Can't get"
1013 "XF86VidMode info.\n"));
1014 XSetErrorHandler(old_x_error_handler);
1015 return -2;
1016 }
1017
1018 /* look for mode with requested resolution */
1019 for (i = 0; i < _xwin.num_modes; i++)
1020 {
1021 if ((_xwin.modesinfo[i]->hdisplay == allegro_gl_display_info.w)
1022 && (_xwin.modesinfo[i]->vdisplay == allegro_gl_display_info.h))
1023 bestmode = i;
1024 }
1025
1026 setattr.override_redirect = True;
1027 if (!XF86VidModeSwitchToMode(_xwin.display, _xwin.screen,
1028 _xwin.modesinfo[bestmode])) {
1029
1030 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1031 get_config_text("Can not set XF86VidMode mode"));
1032 XSetErrorHandler(old_x_error_handler);
1033 return -1;
1034 }
1035
1036 XF86VidModeSetViewPort(_xwin.display, _xwin.screen, 0, 0);
1037
1038 /* Lock Mode switching */
1039 XF86VidModeLockModeSwitch(_xwin.display, _xwin.screen, True);
1040 _xwin.mode_switched = 1;
1041
1042 allegro_gl_display_info.x = 0;
1043 allegro_gl_display_info.y = 0;
1044 allegro_gl_display_info.w = _xwin.modesinfo[bestmode]->hdisplay;
1045 allegro_gl_display_info.h = _xwin.modesinfo[bestmode]->vdisplay;
1046
1047 valuemask |= CWOverrideRedirect;
1048 _xwin.override_redirected = 1;
1049 }
1050
1051 _xwin.window = XCreateWindow (
1052 _xwin.display, root,
1053 allegro_gl_display_info.x, allegro_gl_display_info.y,
1054 allegro_gl_display_info.w, allegro_gl_display_info.h, 0,
1055 visinfo->depth,
1056 InputOutput,
1057 visinfo->visual,
1058 valuemask, &setattr
1059 );
1060
1061 #else //ALLEGROGL_HAVE_XF86VIDMODE
1062 if (fullscreen) {
1063 /* Without Xf86VidMode extension we support only fullscreen modes which
1064 * match current resolution. */
1065 int fs_width = DisplayWidth(_xwin.display, _xwin.screen);
1066 int fs_height = DisplayHeight(_xwin.display, _xwin.screen);
1067
1068 if (fs_width != allegro_gl_display_info.w
1069 || fs_height != allegro_gl_display_info.h) {
1070 TRACE(PREFIX_E "Only desktop resolution fullscreen available.");
1071 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1072 get_config_text("Compiled without Xf86VidMode extension support.\n"
1073 "Only desktop resolution fullscreen available."));
1074 XSetErrorHandler(old_x_error_handler);
1075 return -1;
1076 }
1077
1078 _glxwin.fullscreen = TRUE;
1079
1080 /* Create the fullscreen window. */
1081 _xwin.window = XCreateWindow(_xwin.display, root,
1082 allegro_gl_display_info.x, allegro_gl_display_info.y,
1083 fs_width, fs_height, 0,
1084 visinfo->depth,
1085 InputOutput,
1086 visinfo->visual,
1087 valuemask, &setattr);
1088
1089 /* Map the fullscreen window. */
1090 XMapRaised(_xwin.display, _xwin.window);
1091
1092 /* Make sure we got to the top of the window stack. */
1093 XRaiseWindow(_xwin.display, _xwin.fs_window);
1094 }
1095 else {
1096 _xwin.window = XCreateWindow (
1097 _xwin.display, root,
1098 allegro_gl_display_info.x, allegro_gl_display_info.y,
1099 allegro_gl_display_info.w, allegro_gl_display_info.h, 0,
1100 visinfo->depth,
1101 InputOutput,
1102 visinfo->visual,
1103 valuemask, &setattr
1104 );
1105 }
1106 #endif //ALLEGROGL_HAVE_XF86VIDMODE
1107
1108 /* Set size and position hints for Window Manager :
1109 * prevents the window to be resized
1110 */
1111 hints = XAllocSizeHints();
1112 if (hints) {
1113 /* This code chunk comes from Allegro's src/x/xwin.c */
1114 hints->flags = PMinSize | PMaxSize | PBaseSize;
1115 hints->min_width = hints->max_width = hints->base_width
1116 = allegro_gl_display_info.w;
1117 hints->min_height = hints->max_height = hints->base_height
1118 = allegro_gl_display_info.h;
1119
1120 XSetWMNormalHints(_xwin.display, _xwin.window, hints);
1121 XFree(hints);
1122 }
1123
1124
1125 /* Set WM_DELETE_WINDOW atom in WM_PROTOCOLS property
1126 * (to get window_delete requests).
1127 */
1128 {
1129 Atom wm_delete_window = XInternAtom(_xwin.display, "WM_DELETE_WINDOW", False);
1130 XSetWMProtocols(_xwin.display, _xwin.window, &wm_delete_window, 1);
1131 }
1132
1133 /* Finish off the GLX setup */
1134 if (use_fbconfig)
1135 _glxwin.ctx = glXCreateNewContext (_xwin.display, fbconfig, GLX_RGBA_TYPE, NULL, True);
1136 else
1137 _glxwin.ctx = glXCreateContext (_xwin.display, visinfo, NULL, True);
1138
1139 if (use_fbconfig) {
1140 _glxwin.window = glXCreateWindow(_xwin.display, fbconfig, _xwin.window, 0);
1141 if (!_glxwin.window) {
1142 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1143 get_config_text("Cannot create GLX window."));
1144 XSetErrorHandler(old_x_error_handler);
1145 return -1;
1146 }
1147 _glxwin.use_glx_window = TRUE;
1148 }
1149
1150 if (!_glxwin.ctx) {
1151 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1152 get_config_text("Can not create GLX context."));
1153 XSetErrorHandler(old_x_error_handler);
1154 return -1;
1155 }
1156 else {
1157 Bool ret;
1158
1159 if (use_fbconfig)
1160 ret = glXMakeContextCurrent(_xwin.display, _glxwin.window, _glxwin.window, _glxwin.ctx);
1161 else
1162 ret = glXMakeCurrent (_xwin.display, _xwin.window, _glxwin.ctx);
1163
1164 if (!ret) {
1165 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1166 get_config_text("Cannot make GLX context current."));
1167 XSetErrorHandler(old_x_error_handler);
1168 return -1;
1169 }
1170 }
1171
1172 /* Finish off the Allegro setup */
1173
1174 /* Get associated visual and window depth (bits per pixel), and
1175 * store window size */
1176 {
1177 XWindowAttributes getattr;
1178 XGetWindowAttributes(_xwin.display, _xwin.window, &getattr);
1179 _xwin.visual = getattr.visual;
1180 _xwin.window_depth = getattr.depth;
1181 _xwin.window_width = allegro_gl_display_info.w;
1182 _xwin.window_height = allegro_gl_display_info.h;
1183 _xwin.screen_depth = getattr.depth;
1184 _xwin.screen_width = allegro_gl_display_info.w;
1185 _xwin.screen_height = allegro_gl_display_info.h;
1186 }
1187
1188 /* Destroy the current colormap (if any) */
1189 if (_xwin.colormap != None) {
1190 XUninstallColormap(_xwin.display, _xwin.colormap);
1191 XFreeColormap(_xwin.display, _xwin.colormap);
1192 }
1193
1194 /* Create and install colormap. */
1195 if (_xwin.visual->class == DirectColor) {
1196 _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window,
1197 _xwin.visual, AllocAll);
1198 }
1199 else { /* must be TrueColor */
1200 _xwin.colormap = XCreateColormap(_xwin.display, _xwin.window,
1201 _xwin.visual, AllocNone);
1202 }
1203 XSetWindowColormap(_xwin.display, _xwin.window, _xwin.colormap);
1204 XInstallColormap(_xwin.display, _xwin.colormap);
1205
1206 /* Setup a palette if needed */
1207 if (_xwin.visual->class == DirectColor) {
1208 XColor color;
1209 int rsize, gsize, bsize;
1210 int rmax, gmax, bmax;
1211 int rshift, gshift, bshift;
1212 int r, g, b;
1213
1214 AGL_LOG (1, "x.c: Using DirectColor visual, setting palette...\n");
1215
1216 rsize = 1 << allegro_gl_display_info.pixel_size.rgba.r;
1217 gsize = 1 << allegro_gl_display_info.pixel_size.rgba.g;
1218 bsize = 1 << allegro_gl_display_info.pixel_size.rgba.b;
1219
1220 rshift = allegro_gl_display_info.r_shift;
1221 bshift = allegro_gl_display_info.b_shift;
1222 gshift = allegro_gl_display_info.g_shift;
1223
1224 rmax = rsize - 1;
1225 gmax = gsize - 1;
1226 bmax = bsize - 1;
1227
1228 color.flags = DoRed | DoGreen | DoBlue;
1229 for (r = 0; r < rsize; r++) {
1230 for (g = 0; g < gsize; g++) {
1231 for (b = 0; b < bsize; b++) {
1232 color.pixel = (r << rshift) | (g << gshift) | (b << bshift);
1233 color.red = ((rmax <= 0) ? 0 : ((r * 65535L) / rmax));
1234 color.green = ((gmax <= 0) ? 0 : ((g * 65535L) / gmax));
1235 color.blue = ((bmax <= 0) ? 0 : ((b * 65535L) / bmax));
1236 XStoreColor(_xwin.display, _xwin.colormap, &color);
1237 }
1238 }
1239 }
1240 }
1241
1242 /* Configure the window a bit */
1243 {
1244 XClassHint hint;
1245 XWMHints wm_hints;
1246
1247 /* Set title. */
1248 XStoreName(_xwin.display, _xwin.window, _xwin.window_title);
1249
1250 /* Set hints. */
1251 hint.res_name = _xwin.application_name;
1252 hint.res_class = _xwin.application_class;
1253 XSetClassHint(_xwin.display, _xwin.window, &hint);
1254
1255 wm_hints.flags = InputHint | StateHint;
1256 wm_hints.input = True;
1257 wm_hints.initial_state = NormalState;
1258
1259 #ifdef ALLEGRO_XWINDOWS_WITH_XPM
1260 if (allegro_icon) {
1261 wm_hints.flags |= IconPixmapHint | IconMaskHint | WindowGroupHint;
1262 XpmCreatePixmapFromData(_xwin.display, _xwin.window, allegro_icon,&wm_hints.icon_pixmap, &wm_hints.icon_mask, NULL);
1263 }
1264 #endif
1265
1266 XSetWMHints(_xwin.display, _xwin.window, &wm_hints);
1267 }
1268
1269 /* Map window. */
1270 XMapWindow(_xwin.display, _xwin.window);
1271
1272
1273 if (fullscreen) {
1274 AL_CONST char *fc = NULL;
1275 char tmp1[64], tmp2[128];
1276 int c = 0;
1277 int h = allegro_gl_display_info.h;
1278 int w = allegro_gl_display_info.w;
1279
1280 /* This chunk is disabled by default because of problems on KDE
1281 desktops. */
1282 fc = get_config_string(uconvert_ascii("graphics", tmp1),
1283 uconvert_ascii("force_centering", tmp2), NULL);
1284 if ((fc) && ((c = ugetc(fc)) != 0) && ((c == 'y') || (c == 'Y')
1285 || (c == '1'))) {
1286 /* Hack: make the window fully visible and center cursor. */
1287 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0, 0, 0);
1288 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
1289 w - 1, 0);
1290 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
1291 0, h - 1);
1292 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
1293 w - 1, h - 1);
1294 }
1295 XWarpPointer(_xwin.display, None, _xwin.window, 0, 0, 0, 0,
1296 w / 2, h / 2);
1297 XSync(_xwin.display, False);
1298
1299 /* Grab keyboard and mouse. */
1300 if (XGrabKeyboard(_xwin.display, _xwin.window, False, GrabModeAsync,
1301 GrabModeAsync, CurrentTime) != GrabSuccess) {
1302 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1303 get_config_text("Can not grab keyboard"));
1304 XSetErrorHandler(old_x_error_handler);
1305 return -1;
1306 }
1307 _xwin.keyboard_grabbed = 1;
1308
1309 if (XGrabPointer(_xwin.display, _xwin.window, False,
1310 PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1311 GrabModeAsync, GrabModeAsync, _xwin.window, None, CurrentTime)
1312 != GrabSuccess) {
1313
1314 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1315 get_config_text("Can not grab mouse"));
1316 XSetErrorHandler(old_x_error_handler);
1317 return -1;
1318 }
1319 _xwin.mouse_grabbed = 1;
1320 }
1321
1322
1323 /* Destroy current cursor (if any) */
1324 if (_xwin.cursor != None) {
1325 XUndefineCursor(_xwin.display, _xwin.window);
1326 XFreeCursor(_xwin.display, _xwin.cursor);
1327 }
1328
1329 {
1330 /* Create invisible X cursor. */
1331 Pixmap pixmap = XCreatePixmap(_xwin.display, _xwin.window, 1, 1, 1);
1332 if (pixmap != None) {
1333 GC temp_gc;
1334 XColor color;
1335 XGCValues gcvalues;
1336
1337 int gcmask = GCFunction | GCForeground | GCBackground;
1338 gcvalues.function = GXcopy;
1339 gcvalues.foreground = 0;
1340 gcvalues.background = 0;
1341 temp_gc = XCreateGC(_xwin.display, pixmap, gcmask, &gcvalues);
1342 XDrawPoint(_xwin.display, pixmap, temp_gc, 0, 0);
1343 XFreeGC(_xwin.display, temp_gc);
1344 color.pixel = 0;
1345 color.red = color.green = color.blue = 0;
1346 color.flags = DoRed | DoGreen | DoBlue;
1347 _xwin.cursor = XCreatePixmapCursor(_xwin.display, pixmap, pixmap,
1348 &color, &color, 0, 0);
1349 XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
1350 XFreePixmap(_xwin.display, pixmap);
1351 }
1352 else {
1353 _xwin.cursor = XCreateFontCursor(_xwin.display, _xwin.cursor_shape);
1354 XDefineCursor(_xwin.display, _xwin.window, _xwin.cursor);
1355 }
1356 }
1357
1358 /* Wait for the first exposure event. See comment in Allegro's
1359 * xwin.c about why no blocking X11 function is used.
1360 */
1361 while (1) {
1362 XEvent e;
1363 if (XCheckTypedEvent(_xwin.display, Expose, &e)) {
1364 if (e.xexpose.count == 0) break;
1365 }
1366 rest(1);
1367 }
1368
1369 return 0;
1370 }
1371
1372
1373
1374 static BITMAP *allegro_gl_x_windowed_create_screen (GFX_DRIVER *drv, int w, int h, int depth)
1375 {
1376 BITMAP *bmp;
1377 int is_linear = drv->linear;
1378
1379 drv->linear = 1;
1380 bmp = _make_bitmap (w, h, 0, drv, depth, 0);
1381 bmp->id = BMP_ID_VIDEO | BMP_ID_MASK;
1382 drv->linear = is_linear;
1383
1384 if (bmp == 0) {
1385 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1386 get_config_text("Not enough memory"));
1387 return NULL;
1388 }
1389
1390 drv->w = w;
1391 drv->h = h;
1392
1393 return bmp;
1394 }
1395
1396
1397
1398 /* decode_visual:
1399 * Used to read back the information in the visual. 0 = ok.
1400 */
1401 static int decode_visual (XVisualInfo *v, struct allegro_gl_display_info *i)
1402 {
1403 int rgba, buffer_size, use_gl, sbuffers, samples;
1404
1405 TRACE(PREFIX_I "decode_visual: Decoding:\n");
1406 i->rmethod = 2;
1407
1408 /* We can only support TrueColor and DirectColor visuals --
1409 * we only support RGBA mode */
1410 if (v->class != TrueColor && v->class != DirectColor)
1411 return -1;
1412
1413 if (glXGetConfig (_xwin.display, v, GLX_RGBA, &rgba)
1414 || glXGetConfig (_xwin.display, v, GLX_USE_GL, &use_gl)
1415 || glXGetConfig (_xwin.display, v, GLX_BUFFER_SIZE, &buffer_size)
1416 || glXGetConfig (_xwin.display, v, GLX_RED_SIZE, &i->pixel_size.rgba.r)
1417 || glXGetConfig (_xwin.display, v, GLX_GREEN_SIZE, &i->pixel_size.rgba.g)
1418 || glXGetConfig (_xwin.display, v, GLX_BLUE_SIZE, &i->pixel_size.rgba.b)
1419 || glXGetConfig (_xwin.display, v, GLX_ALPHA_SIZE, &i->pixel_size.rgba.a)
1420 || glXGetConfig (_xwin.display, v, GLX_DOUBLEBUFFER, &i->doublebuffered)
1421 || glXGetConfig (_xwin.display, v, GLX_STEREO, &i->stereo)
1422 || glXGetConfig (_xwin.display, v, GLX_AUX_BUFFERS, &i->aux_buffers)
1423 || glXGetConfig (_xwin.display, v, GLX_DEPTH_SIZE, &i->depth_size)
1424 || glXGetConfig (_xwin.display, v, GLX_STENCIL_SIZE, &i->stencil_size)
1425 || glXGetConfig (_xwin.display, v, GLX_ACCUM_RED_SIZE,
1426 &i->accum_size.rgba.r)
1427 || glXGetConfig (_xwin.display, v, GLX_ACCUM_GREEN_SIZE,
1428 &i->accum_size.rgba.g)
1429 || glXGetConfig (_xwin.display, v, GLX_ACCUM_BLUE_SIZE,
1430 &i->accum_size.rgba.b)
1431 || glXGetConfig (_xwin.display, v, GLX_ACCUM_ALPHA_SIZE,
1432 &i->accum_size.rgba.a)) {
1433 TRACE(PREFIX_I "x_create_window: Incomplete glX mode ...\n");
1434 return -1;
1435 }
1436
1437 if (!rgba) {
1438 TRACE(PREFIX_I "x_create_window: Not RGBA mode\n");
1439 return -1;
1440 }
1441
1442 if (!use_gl) {
1443 ustrzcpy (allegro_gl_error, AGL_ERROR_SIZE,
1444 get_config_text("OpenGL Unsupported"));
1445 return -1;
1446 }
1447
1448 i->r_shift = get_shift (v->red_mask);
1449 i->g_shift = get_shift (v->green_mask);
1450 i->b_shift = get_shift (v->blue_mask);
1451 i->a_shift = 0;
1452
1453 /* If we are going to need to setup a palette we need bit shifts */
1454 if ((v->class == DirectColor)
1455 && ((i->r_shift == -1) || (i->g_shift == -1) || (i->b_shift == -1))
1456 && (i->pixel_size.rgba.r + i->pixel_size.rgba.g + i->pixel_size.rgba.b
1457 <= 12)) {
1458 /* XXX <rohannessian> Report something here? */
1459 return -1;
1460 }
1461
1462 i->float_color = 0;
1463 i->float_depth = 0;
1464
1465 i->colour_depth = 0;
1466
1467 if (i->pixel_size.rgba.r == 3
1468 && i->pixel_size.rgba.g == 3
1469 && i->pixel_size.rgba.b == 2) {
1470 i->colour_depth = 8;
1471 }
1472
1473 if (i->pixel_size.rgba.r == 5
1474 && i->pixel_size.rgba.b == 5) {
1475 if (i->pixel_size.rgba.g == 5) {
1476 i->colour_depth = 15;
1477 }
1478 if (i->pixel_size.rgba.g == 6) {
1479 i->colour_depth = 16;
1480 }
1481 }
1482
1483 if (i->pixel_size.rgba.r == 8
1484 && i->pixel_size.rgba.g == 8
1485 && i->pixel_size.rgba.b == 8) {
1486 if (i->pixel_size.rgba.a == 0) {
1487 i->colour_depth = 24;
1488 }
1489 if (i->pixel_size.rgba.a == 8) {
1490 i->colour_depth = 32;
1491 /* small hack that tries to guess alpha shifting */
1492 i->a_shift = 48 - i->r_shift - i->g_shift - i->b_shift;
1493 }
1494 }
1495
1496 i->allegro_format = (i->colour_depth != 0)
1497 && (i->g_shift == i->pixel_size.rgba.b)
1498 && (i->r_shift * i->b_shift == 0)
1499 && (i->r_shift + i->b_shift
1500 == i->pixel_size.rgba.b + i->pixel_size.rgba.g);
1501
1502 if (glXGetConfig(_xwin.display, v, GLX_SAMPLE_BUFFERS, &sbuffers)
1503 == GLX_BAD_ATTRIBUTE) {
1504 /* Multisample extension is not supported */
1505 i->sample_buffers = 0;
1506 }
1507 else {
1508 i->sample_buffers = sbuffers;
1509 }
1510 if (glXGetConfig(_xwin.display, v, GLX_SAMPLES, &samples)
1511 == GLX_BAD_ATTRIBUTE) {
1512 /* Multisample extension is not supported */
1513 i->samples = 0;
1514 }
1515 else {
1516 i->samples = samples;
1517 }
1518
1519
1520 TRACE(PREFIX_I "Color Depth: %i\n", buffer_size);
1521 TRACE(PREFIX_I "RGBA: %i.%i.%i.%i\n", i->pixel_size.rgba.r, i->pixel_size.rgba.g,
1522 i->pixel_size.rgba.b, i->pixel_size.rgba.a);
1523 TRACE(PREFIX_I "Accum: %i.%i.%i.%i\n", i->accum_size.rgba.r, i->accum_size.rgba.g,
1524 i->accum_size.rgba.b, i->accum_size.rgba.a);
1525 TRACE(PREFIX_I "DblBuf: %i Zbuf: %i Stereo: %i Aux: %i Stencil: %i\n",
1526 i->doublebuffered, i->depth_size, i->stereo,
1527 i->aux_buffers, i->stencil_size);
1528 TRACE(PREFIX_I "Shift: %i.%i.%i.%i\n", i->r_shift, i->g_shift, i->b_shift,
1529 i->a_shift);
1530 TRACE(PREFIX_I "Sample Buffers: %i Samples: %i\n", i->sample_buffers, i->samples);
1531 TRACE(PREFIX_I "Decoded bpp: %i\n", i->colour_depth);
1532
1533 return 0;
1534 }
1535
1536
1537
1538 #ifdef ALLEGROGL_HAVE_XF86VIDMODE
1539 /* allegro_gl_x_fetch_mode_list:
1540 * Generates a list of valid video modes (made after
1541 * _xvidmode_private_fetch_mode_list of Allegro)
1542 */
1543 static GFX_MODE_LIST* allegro_gl_x_fetch_mode_list(void)
1544 {
1545 int num_modes = 0;
1546 XF86VidModeModeInfo **modesinfo = NULL;
1547 GFX_MODE_LIST *mode_list;
1548 int i;
1549
1550 XLOCK();
1551
1552 if (get_xf86_modes(&modesinfo, &num_modes)) {
1553 XUNLOCK();
1554 return NULL;
1555 }
1556
1557 /* Allocate space for mode list. */
1558 mode_list = malloc(sizeof(GFX_MODE_LIST));
1559 if (!mode_list) {
1560 free_modelines(modesinfo, num_modes);
1561 XUNLOCK();
1562 return NULL;
1563 }
1564
1565 mode_list->mode = malloc(sizeof(GFX_MODE) * (num_modes + 1));
1566 if (!mode_list->mode) {
1567 free(mode_list);
1568 free_modelines(modesinfo, num_modes);
1569 XUNLOCK();
1570 return NULL;
1571 }
1572
1573 /* Fill in mode list. */
1574 for (i = 0; i < num_modes; i++) {
1575 mode_list->mode[i].width = modesinfo[i]->hdisplay;
1576 mode_list->mode[i].height = modesinfo[i]->vdisplay;
1577 /* Since XF86VidMode can not change the color depth of
1578 * the screen, there is no need to define modes for other
1579 * color depth than the desktop's.
1580 */
1581 mode_list->mode[i].bpp = desktop_color_depth();
1582 }
1583
1584 mode_list->mode[num_modes].width = 0;
1585 mode_list->mode[num_modes].height = 0;
1586 mode_list->mode[num_modes].bpp = 0;
1587 mode_list->num_modes = num_modes;
1588
1589 free_modelines(modesinfo, num_modes);
1590
1591 XUNLOCK();
1592 return mode_list;
1593 }
1594 #endif
1595
1596
1597
1598 /* allegro_gl_x_vsync:
1599 * Wait for a vertical retrace. GLX_SGI_video_sync is needed.
1600 */
1601 static void allegro_gl_x_vsync(void)
1602 {
1603 XLOCK();
1604 if (allegro_gl_extensions_GLX.SGI_video_sync) {
1605 unsigned int count;
1606
1607 glXGetVideoSyncSGI(&count);
1608 glXWaitVideoSyncSGI(2, (count+1) & 1, &count);
1609 }
1610 XUNLOCK();
1611 }
1612
1613
1614
1615 /******************************/
1616 /* AllegroGL driver functions */
1617 /******************************/
1618
1619 /* flip:
1620 * Does a page flip / double buffer copy / whatever it really is.
1621 */
1622 static void flip (void)
1623 {
1624 XLOCK();
1625 if (_glxwin.use_glx_window)
1626 glXSwapBuffers (_xwin.display, _glxwin.window);
1627 else
1628 glXSwapBuffers (_xwin.display, _xwin.window);
1629 XUNLOCK();
1630 }
1631
1632
1633
1634 /* gl_on, gl_off:
1635 * Switches to/from GL mode.
1636 */
1637 static void gl_on (void)
1638 {
1639 #ifdef OLD_ALLEGRO
1640 DISABLE();
1641 #endif
1642 }
1643
1644
1645
1646 static void gl_off (void)
1647 {
1648 #ifdef OLD_ALLEGRO
1649 ENABLE();
1650 _xwin_handle_input();
1651 #endif
1652 }
1653
1654
1655
1656 /*****************/
1657 /* Driver struct */
1658 /*****************/
1659
1660 static struct allegro_gl_driver allegro_gl_x = {
1661 flip,
1662 gl_on,
1663 gl_off,
1664 NULL
1665 };
1666
GFX_OPENGL_FULLSCREEN
#define GFX_OPENGL_FULLSCREEN
Fullscreen OpenGL graphics driver for Allegro.
Definition: alleggl.h:435
GFX_OPENGL_WINDOWED
#define GFX_OPENGL_WINDOWED
Windowed OpenGL graphics driver for Allegro.
Definition: alleggl.h:433
allegro_gl_destroy_video_bitmap
void allegro_gl_destroy_video_bitmap(BITMAP *bmp)
destroy_video_bitmap() overload.
Definition: videovtb.c:308
alleggl.h
Main header file for AllegroGL.
allegro_gl_screen
BITMAP * allegro_gl_screen
Direct-mode GL `screen&#39; bitmap.
Definition: alleggl.c:62
allegro_gl_create_video_bitmap
BITMAP * allegro_gl_create_video_bitmap(int w, int h)
create_video_bitmap() overload.
Definition: videovtb.c:344