1 /* GdkGLExt - OpenGL Extension to GDK
2  * Copyright (C) 2002-2004  Naofumi Yasufuku
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif /* HAVE_CONFIG_H */
22 
23 #include <string.h>
24 
25 #include "gdkglx.h"
26 #include "gdkglprivate-x11.h"
27 #include "gdkgloverlay-x11.h"
28 #include "gdkglconfig-x11.h"
29 
30 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
31 #include <gdk/gdkscreen.h>
32 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
33 
34 #ifdef HAVE_LIBXMU
35 
36 #include <X11/Xatom.h>  /* for XA_RGB_DEFAULT_MAP atom */
37 
38 #ifdef HAVE_XMU_STDCMAP_H
39 #include <Xmu/StdCmap.h>  /* for XmuLookupStandardColormap */
40 #else
41 #include <X11/Xmu/StdCmap.h>  /* for XmuLookupStandardColormap */
42 #endif
43 
44 #endif /* HAVE_LIBXMU */
45 
46 static void gdk_gl_config_impl_x11_class_init (GdkGLConfigImplX11Class *klass);
47 static void gdk_gl_config_impl_x11_finalize   (GObject                 *object);
48 
49 static gpointer parent_class = NULL;
50 
51 GType
gdk_gl_config_impl_x11_get_type(void)52 gdk_gl_config_impl_x11_get_type (void)
53 {
54   static GType type = 0;
55 
56   if (!type)
57     {
58       static const GTypeInfo type_info = {
59         sizeof (GdkGLConfigImplX11Class),
60         (GBaseInitFunc) NULL,
61         (GBaseFinalizeFunc) NULL,
62         (GClassInitFunc) gdk_gl_config_impl_x11_class_init,
63         (GClassFinalizeFunc) NULL,
64         NULL,                   /* class_data */
65         sizeof (GdkGLConfigImplX11),
66         0,                      /* n_preallocs */
67         (GInstanceInitFunc) NULL
68       };
69 
70       type = g_type_register_static (GDK_TYPE_GL_CONFIG,
71                                      "GdkGLConfigImplX11",
72                                      &type_info, 0);
73     }
74 
75   return type;
76 }
77 
78 static void
gdk_gl_config_impl_x11_class_init(GdkGLConfigImplX11Class * klass)79 gdk_gl_config_impl_x11_class_init (GdkGLConfigImplX11Class *klass)
80 {
81   GObjectClass *object_class = G_OBJECT_CLASS (klass);
82 
83   GDK_GL_NOTE_FUNC_PRIVATE ();
84 
85   parent_class = g_type_class_peek_parent (klass);
86 
87   object_class->finalize = gdk_gl_config_impl_x11_finalize;
88 }
89 
90 static void
gdk_gl_config_impl_x11_finalize(GObject * object)91 gdk_gl_config_impl_x11_finalize (GObject *object)
92 {
93   GdkGLConfigImplX11 *impl = GDK_GL_CONFIG_IMPL_X11 (object);
94 
95   GDK_GL_NOTE_FUNC_PRIVATE ();
96 
97   XFree (impl->xvinfo);
98 
99   g_object_unref (G_OBJECT (impl->colormap));
100 
101   G_OBJECT_CLASS (parent_class)->finalize (object);
102 }
103 
104 /*
105  * Get standard RGB colormap
106  */
107 
108 #ifdef HAVE_GDK_X11_COLORMAP_FOREIGN_NEW
109 
110 static GdkColormap *
gdk_gl_config_get_std_rgb_colormap(GdkScreen * screen,XVisualInfo * xvinfo,gboolean is_mesa_glx)111 gdk_gl_config_get_std_rgb_colormap (GdkScreen   *screen,
112                                     XVisualInfo *xvinfo,
113                                     gboolean     is_mesa_glx)
114 {
115   GdkDisplay *display;
116   Display *xdisplay;
117   int screen_num;
118   Window xroot_window;
119   Status status;
120   Colormap xcolormap = None;
121   XStandardColormap *standard_cmaps;
122   int i, num_cmaps;
123   GdkVisual *visual;
124 
125   GDK_GL_NOTE_FUNC_PRIVATE ();
126 
127   display = gdk_screen_get_display (screen);
128   xdisplay = GDK_DISPLAY_XDISPLAY (display);
129   screen_num = xvinfo->screen;
130   xroot_window = RootWindow (xdisplay, screen_num);
131 
132   /*
133    * (ripped from GLUT)
134    * Hewlett-Packard supports a feature called "HP Color Recovery".
135    * Mesa has code to use HP Color Recovery.  For Mesa to use this feature,
136    * the atom _HP_RGB_SMOOTH_MAP_LIST must be defined on the root window AND
137    * the colormap obtainable by XGetRGBColormaps for that atom must be set on
138    * the window.  If that colormap is not set, the output will look stripy.
139    */
140 
141   if (is_mesa_glx &&
142       xvinfo->visual->class == TrueColor &&
143       xvinfo->depth == 8)
144     {
145       Atom xa_hp_cr_maps;
146 
147       GDK_GL_NOTE (MISC,
148         g_message (" -- Try to find a standard RGB colormap with HP Color Recovery"));
149 
150       xa_hp_cr_maps = gdk_x11_get_xatom_by_name_for_display (display,
151                                                              "_HP_RGB_SMOOTH_MAP_LIST");
152 
153       status = XGetRGBColormaps (xdisplay, xroot_window,
154                                  &standard_cmaps, &num_cmaps,
155                                  xa_hp_cr_maps);
156       if (status)
157         {
158           for (i = 0; i < num_cmaps; i++)
159             {
160               if (standard_cmaps[i].visualid == xvinfo->visualid)
161                 {
162                   xcolormap = standard_cmaps[i].colormap;
163                   break;
164                 }
165             }
166 
167           XFree (standard_cmaps);
168 
169           if (xcolormap != None)
170             {
171               GDK_GL_NOTE (MISC,
172                 g_message (" -- Colormap: standard RGB with HP Color Recovery"));
173 
174               visual = gdk_x11_screen_lookup_visual (screen, xvinfo->visualid);
175               return gdk_x11_colormap_foreign_new (visual, xcolormap);
176             }
177         }
178     }
179 
180 #if defined(HAVE_LIBXMU) && !defined(_DISABLE_STANDARD_RGB_CMAP)
181 
182   /*
183    * (ripped from GLUT)
184    * Solaris 2.4 and 2.5 have a bug in their XmuLookupStandardColormap
185    * implementations.  Please compile your Solaris 2.4 or 2.5 version of
186    * GtkGLExt with -D_DISABLE_STANDARD_RGB_CMAP to work around this bug.
187    * The symptom of the bug is that programs will get a BadMatch error
188    * from XCreateWindow when creating a window because Solaris 2.4 and 2.5
189    * create a corrupted RGB_DEFAULT_MAP property.  Note that this workaround
190    * prevents colormap sharing between applications, perhaps leading
191    * unnecessary colormap installations or colormap flashing.  Sun fixed
192    * this bug in Solaris 2.6.
193    */
194 
195   if (!_gdk_gl_config_no_standard_colormap)
196     {
197       GDK_GL_NOTE (MISC,
198         g_message (" -- Try to find a standard RGB colormap"));
199 
200       status = XmuLookupStandardColormap (xdisplay, screen_num,
201                                           xvinfo->visualid, xvinfo->depth,
202                                           XA_RGB_DEFAULT_MAP,
203                                           False, True);
204       if (status)
205         {
206           status = XGetRGBColormaps (xdisplay, xroot_window,
207                                      &standard_cmaps, &num_cmaps,
208                                      XA_RGB_DEFAULT_MAP);
209           if (status)
210             {
211               for (i = 0; i < num_cmaps; i++)
212                 {
213                   if (standard_cmaps[i].visualid == xvinfo->visualid)
214                     {
215                       xcolormap = standard_cmaps[i].colormap;
216                       break;
217                     }
218                 }
219 
220               XFree (standard_cmaps);
221 
222               if (xcolormap != None)
223                 {
224                   GDK_GL_NOTE (MISC, g_message (" -- Colormap: standard RGB"));
225 
226                   visual = gdk_x11_screen_lookup_visual (screen, xvinfo->visualid);
227                   return gdk_x11_colormap_foreign_new (visual, xcolormap);
228                 }
229             }
230         }
231     }
232 
233 #endif /* defined(HAVE_LIBXMU) && !defined(_DISABLE_STANDARD_RGB_CMAP) */
234 
235   return NULL;
236 }
237 
238 #endif /* HAVE_GDK_X11_COLORMAP_FOREIGN_NEW */
239 
240 /*
241  * Setup colormap.
242  */
243 
244 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
245 
246 static GdkColormap *
gdk_gl_config_setup_colormap(GdkScreen * screen,XVisualInfo * xvinfo,gboolean is_rgba,gboolean is_mesa_glx)247 gdk_gl_config_setup_colormap (GdkScreen   *screen,
248                               XVisualInfo *xvinfo,
249                               gboolean     is_rgba,
250                               gboolean     is_mesa_glx)
251 {
252   GdkColormap *colormap;
253   GdkVisual *visual;
254   GdkGLOverlayInfo overlay_info;
255   gboolean overlay_supported;
256 
257   GDK_GL_NOTE_FUNC_PRIVATE ();
258 
259   if (is_rgba)
260     {
261       /*
262        * For RGBA mode.
263        */
264 
265       /* Try default colormap. */
266 
267       colormap = gdk_screen_get_default_colormap (screen);
268       visual = gdk_colormap_get_visual (colormap);
269       if (GDK_VISUAL_XVISUAL (visual)->visualid == xvinfo->visualid)
270         {
271           GDK_GL_NOTE (MISC, g_message (" -- Colormap: screen default"));
272           g_object_ref (G_OBJECT (colormap));
273           return colormap;
274         }
275 
276       /* Try standard RGB colormap. */
277 
278 #ifdef HAVE_GDK_X11_COLORMAP_FOREIGN_NEW
279       colormap = gdk_gl_config_get_std_rgb_colormap (screen, xvinfo, is_mesa_glx);
280       if (colormap)
281         return colormap;
282 #endif /* HAVE_GDK_X11_COLORMAP_FOREIGN_NEW */
283 
284       /* New colormap. */
285 
286       GDK_GL_NOTE (MISC, g_message (" -- Colormap: new"));
287       visual = gdk_x11_screen_lookup_visual (screen, xvinfo->visualid);
288       colormap = gdk_colormap_new (visual, FALSE);
289       return colormap;
290 
291     }
292   else
293     {
294       /*
295        * For color index mode.
296        */
297 
298       visual = gdk_x11_screen_lookup_visual (screen, xvinfo->visualid);
299 
300       overlay_supported = _gdk_x11_gl_overlay_get_info (visual, &overlay_info);
301       if (overlay_supported &&
302           overlay_info.transparent_type == GDK_GL_OVERLAY_TRANSPARENT_PIXEL &&
303           overlay_info.value < (guint32) xvinfo->visual->map_entries)
304         {
305 
306           /*
307            * On machines where zero (or some other value in the range
308            * of 0 through map_entries-1), BadAlloc may be generated
309            * when an AllocAll overlay colormap is allocated since the
310            * transparent pixel precludes all the cells in the colormap
311            * being allocated (the transparent pixel is pre-allocated).
312            * So in this case, use XAllocColorCells to allocate
313            * map_entries-1 pixels (that is, all but the transparent pixel).
314            */
315 
316           GDK_GL_NOTE (MISC, g_message (" -- Colormap: new"));
317           colormap = gdk_colormap_new (visual, FALSE);
318         }
319       else
320         {
321 
322           /*
323            * If there is no transparent pixel or if the transparent
324            * pixel is outside the range of valid colormap cells (HP
325            * can implement their overlays this smart way since their
326            * transparent pixel is 255), we can AllocAll the colormap.
327            * See note above.
328            */
329 
330           GDK_GL_NOTE (MISC, g_message (" -- Colormap: new allocated writable"));
331           colormap = gdk_colormap_new (visual, TRUE);
332         }
333 
334       return colormap;
335 
336     }
337 
338   /* not reached */
339   return NULL;
340 }
341 
342 #else  /* GDKGLEXT_MULTIHEAD_SUPPORT */
343 
344 static GdkColormap *
gdk_gl_config_setup_colormap(GdkScreen * screen,XVisualInfo * xvinfo,gboolean is_rgba,gboolean is_mesa_glx)345 gdk_gl_config_setup_colormap (GdkScreen   *screen,
346                               XVisualInfo *xvinfo,
347                               gboolean     is_rgba,
348                               gboolean     is_mesa_glx)
349 {
350   GdkColormap *colormap;
351   GdkVisual *visual;
352   GdkGLOverlayInfo overlay_info;
353   gboolean overlay_supported;
354 
355   GDK_GL_NOTE_FUNC_PRIVATE ();
356 
357   if (is_rgba)
358     {
359       /*
360        * For RGBA mode.
361        */
362 
363       /* Try default colormap. */
364 
365       colormap = gdk_colormap_get_system ();
366       visual = gdk_colormap_get_visual (colormap);
367       if (GDK_VISUAL_XVISUAL (visual)->visualid == xvinfo->visualid)
368         {
369           GDK_GL_NOTE (MISC, g_message (" -- Colormap: system default"));
370 
371           g_object_ref (G_OBJECT (colormap));
372           return colormap;
373         }
374 
375       /* New colormap. */
376 
377       GDK_GL_NOTE (MISC, g_message (" -- Colormap: new"));
378 
379       visual = gdkx_visual_get (xvinfo->visualid);
380       colormap = gdk_colormap_new (visual, FALSE);
381       return colormap;
382 
383     }
384   else
385     {
386       /*
387        * For color index mode.
388        */
389 
390       visual = gdkx_visual_get (xvinfo->visualid);
391 
392       overlay_supported = _gdk_x11_gl_overlay_get_info (visual, &overlay_info);
393       if (overlay_supported &&
394           overlay_info.transparent_type == GDK_GL_OVERLAY_TRANSPARENT_PIXEL &&
395           overlay_info.value < xvinfo->visual->map_entries)
396         {
397 
398           /*
399            * On machines where zero (or some other value in the range
400            * of 0 through map_entries-1), BadAlloc may be generated
401            * when an AllocAll overlay colormap is allocated since the
402            * transparent pixel precludes all the cells in the colormap
403            * being allocated (the transparent pixel is pre-allocated).
404            * So in this case, use XAllocColorCells to allocate
405            * map_entries-1 pixels (that is, all but the transparent pixel).
406            */
407 
408           GDK_GL_NOTE (MISC, g_message (" -- Colormap: new"));
409           colormap = gdk_colormap_new (visual, FALSE);
410         }
411       else
412         {
413 
414           /*
415            * If there is no transparent pixel or if the transparent
416            * pixel is outside the range of valid colormap cells (HP
417            * can implement their overlays this smart way since their
418            * transparent pixel is 255), we can AllocAll the colormap.
419            * See note above.
420            */
421 
422           GDK_GL_NOTE (MISC, g_message (" -- Colormap: new allocated writable"));
423           colormap = gdk_colormap_new (visual, TRUE);
424         }
425 
426       return colormap;
427 
428     }
429 
430   /* not reached */
431   return NULL;
432 }
433 
434 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
435 
436 static void
gdk_gl_config_init_attrib(GdkGLConfig * glconfig)437 gdk_gl_config_init_attrib (GdkGLConfig *glconfig)
438 {
439   GdkGLConfigImplX11 *impl;
440   int value;
441 
442   impl = GDK_GL_CONFIG_IMPL_X11 (glconfig);
443 
444 #define _GET_CONFIG(__attrib) \
445   glXGetConfig (impl->xdisplay, impl->xvinfo, __attrib, &value)
446 
447   /* RGBA mode? */
448   _GET_CONFIG (GLX_RGBA);
449   glconfig->is_rgba = value ? TRUE : FALSE;
450 
451   /* Layer plane. */
452   _GET_CONFIG (GLX_LEVEL);
453   glconfig->layer_plane = value;
454 
455   /* Double buffering is supported? */
456   _GET_CONFIG (GLX_DOUBLEBUFFER);
457   glconfig->is_double_buffered = value ? TRUE : FALSE;
458 
459   /* Stereo is supported? */
460   _GET_CONFIG (GLX_STEREO);
461   glconfig->is_stereo = value ? TRUE : FALSE;
462 
463   /* Number of aux buffers */
464   _GET_CONFIG (GLX_AUX_BUFFERS);
465   glconfig->n_aux_buffers = value;
466 
467   /* Has alpha bits? */
468   _GET_CONFIG (GLX_ALPHA_SIZE);
469   glconfig->has_alpha = value ? TRUE : FALSE;
470 
471   /* Has depth buffer? */
472   _GET_CONFIG (GLX_DEPTH_SIZE);
473   glconfig->has_depth_buffer = value ? TRUE : FALSE;
474 
475   /* Has stencil buffer? */
476   _GET_CONFIG (GLX_STENCIL_SIZE);
477   glconfig->has_stencil_buffer = value ? TRUE : FALSE;
478 
479   /* Has accumulation buffer? */
480   _GET_CONFIG (GLX_ACCUM_RED_SIZE);
481   glconfig->has_accum_buffer = value ? TRUE : FALSE;
482 
483   /* Number of multisample buffers (not supported yet) */
484   glconfig->n_sample_buffers = 0;
485 
486 #undef _GET_CONFIG
487 }
488 
489 static GdkGLConfig *
gdk_gl_config_new_common(GdkScreen * screen,const int * attrib_list)490 gdk_gl_config_new_common (GdkScreen *screen,
491                           const int *attrib_list)
492 {
493   GdkGLConfig *glconfig;
494   GdkGLConfigImplX11 *impl;
495 
496   Display *xdisplay;
497   int screen_num;
498   XVisualInfo *xvinfo;
499   int is_rgba;
500 
501   GDK_GL_NOTE_FUNC_PRIVATE ();
502 
503 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
504   xdisplay = GDK_SCREEN_XDISPLAY (screen);
505   screen_num = GDK_SCREEN_XNUMBER (screen);
506 #else  /* GDKGLEXT_MULTIHEAD_SUPPORT */
507   xdisplay = gdk_x11_get_default_xdisplay ();
508   screen_num = gdk_x11_get_default_screen ();
509 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
510 
511   GDK_GL_NOTE (MISC, _gdk_x11_gl_print_glx_info (xdisplay, screen_num));
512 
513   /*
514    * Find an OpenGL-capable visual.
515    */
516 
517   GDK_GL_NOTE_FUNC_IMPL ("glXChooseVisual");
518 
519   xvinfo = glXChooseVisual (xdisplay, screen_num, (int *) attrib_list);
520   if (xvinfo == NULL)
521     return NULL;
522 
523   GDK_GL_NOTE (MISC,
524     g_message (" -- glXChooseVisual: screen number = %d", xvinfo->screen));
525   GDK_GL_NOTE (MISC,
526     g_message (" -- glXChooseVisual: visual id = 0x%lx", xvinfo->visualid));
527 
528   /*
529    * Instantiate the GdkGLConfigImplX11 object.
530    */
531 
532   glconfig = g_object_new (GDK_TYPE_GL_CONFIG_IMPL_X11, NULL);
533   impl = GDK_GL_CONFIG_IMPL_X11 (glconfig);
534 
535   impl->xdisplay = xdisplay;
536   impl->screen_num = screen_num;
537   impl->xvinfo = xvinfo;
538 
539   impl->screen = screen;
540 
541   /* Using Mesa? */
542   if (strstr (glXQueryServerString (xdisplay, screen_num, GLX_VERSION), "Mesa"))
543     impl->is_mesa_glx = TRUE;
544   else
545     impl->is_mesa_glx = FALSE;
546 
547   /*
548    * Get an appropriate colormap.
549    */
550 
551   /* RGBA mode? */
552   glXGetConfig (xdisplay, xvinfo, GLX_RGBA, &is_rgba);
553 
554   impl->colormap = gdk_gl_config_setup_colormap (impl->screen,
555                                                  impl->xvinfo,
556                                                  is_rgba,
557                                                  impl->is_mesa_glx);
558 
559   GDK_GL_NOTE (MISC,
560     g_message (" -- Colormap: visual id = 0x%lx",
561                GDK_VISUAL_XVISUAL (impl->colormap->visual)->visualid));
562 
563   /*
564    * Init configuration attributes.
565    */
566 
567   gdk_gl_config_init_attrib (glconfig);
568 
569   return glconfig;
570 }
571 
572 /**
573  * gdk_gl_config_new:
574  * @attrib_list: a list of attribute/value pairs. The last attribute must
575  *               be GDK_GL_ATTRIB_LIST_NONE.
576  *
577  * Returns an OpenGL frame buffer configuration that match the specified
578  * attributes.
579  *
580  * attrib_list is a int array that contains the attribute/value pairs.
581  * Available attributes are:
582  * GDK_GL_USE_GL, GDK_GL_BUFFER_SIZE, GDK_GL_LEVEL, GDK_GL_RGBA,
583  * GDK_GL_DOUBLEBUFFER, GDK_GL_STEREO, GDK_GL_AUX_BUFFERS,
584  * GDK_GL_RED_SIZE, GDK_GL_GREEN_SIZE, GDK_GL_BLUE_SIZE, GDK_GL_ALPHA_SIZE,
585  * GDK_GL_DEPTH_SIZE, GDK_GL_STENCIL_SIZE, GDK_GL_ACCUM_RED_SIZE,
586  * GDK_GL_ACCUM_GREEN_SIZE, GDK_GL_ACCUM_BLUE_SIZE, GDK_GL_ACCUM_ALPHA_SIZE.
587  *
588  * Return value: the new #GdkGLConfig.
589  **/
590 GdkGLConfig *
gdk_gl_config_new(const int * attrib_list)591 gdk_gl_config_new (const int *attrib_list)
592 {
593   GdkScreen *screen;
594 
595   GDK_GL_NOTE_FUNC ();
596 
597   g_return_val_if_fail (attrib_list != NULL, NULL);
598 
599 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
600   screen = gdk_screen_get_default ();
601 #else  /* GDKGLEXT_MULTIHEAD_SUPPORT */
602   screen = NULL;
603 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
604 
605   return gdk_gl_config_new_common (screen, attrib_list);
606 }
607 
608 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
609 
610 /**
611  * gdk_gl_config_new_for_screen:
612  * @screen: target screen.
613  * @attrib_list: a list of attribute/value pairs. The last attribute must
614  *               be GDK_GL_ATTRIB_LIST_NONE.
615  *
616  * Returns an OpenGL frame buffer configuration that match the specified
617  * attributes.
618  *
619  * Return value: the new #GdkGLConfig.
620  **/
621 GdkGLConfig *
gdk_gl_config_new_for_screen(GdkScreen * screen,const int * attrib_list)622 gdk_gl_config_new_for_screen (GdkScreen *screen,
623                               const int *attrib_list)
624 {
625   GDK_GL_NOTE_FUNC ();
626 
627   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
628   g_return_val_if_fail (attrib_list != NULL, NULL);
629 
630   return gdk_gl_config_new_common (screen, attrib_list);
631 }
632 
633 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
634 
635 /*
636  * XVisualInfo returned by this function should be freed by XFree ().
637  */
638 static XVisualInfo *
gdk_x11_gl_get_xvinfo(Display * xdisplay,int screen_num,VisualID xvisualid)639 gdk_x11_gl_get_xvinfo (Display  *xdisplay,
640                        int       screen_num,
641                        VisualID  xvisualid)
642 {
643   XVisualInfo xvinfo_template;
644   XVisualInfo *xvinfo_list;
645   int nitems_return;
646 
647   GDK_GL_NOTE_FUNC_PRIVATE ();
648 
649   xvinfo_template.visualid = xvisualid;
650   xvinfo_template.screen = screen_num;
651 
652   xvinfo_list = XGetVisualInfo (xdisplay,
653                                 VisualIDMask | VisualScreenMask,
654                                 &xvinfo_template,
655                                 &nitems_return);
656 
657   /* Returned XVisualInfo needs to be unique */
658   g_assert (xvinfo_list != NULL && nitems_return == 1);
659 
660   return xvinfo_list;
661 }
662 
663 static GdkGLConfig *
gdk_x11_gl_config_new_from_visualid_common(GdkScreen * screen,VisualID xvisualid)664 gdk_x11_gl_config_new_from_visualid_common (GdkScreen *screen,
665                                             VisualID   xvisualid)
666 {
667   GdkGLConfig *glconfig;
668   GdkGLConfigImplX11 *impl;
669 
670   Display *xdisplay;
671   int screen_num;
672   XVisualInfo *xvinfo;
673   int is_rgba;
674 
675   GDK_GL_NOTE_FUNC_PRIVATE ();
676 
677 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
678   xdisplay = GDK_SCREEN_XDISPLAY (screen);
679   screen_num = GDK_SCREEN_XNUMBER (screen);
680 #else  /* GDKGLEXT_MULTIHEAD_SUPPORT */
681   xdisplay = gdk_x11_get_default_xdisplay ();
682   screen_num = gdk_x11_get_default_screen ();
683 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
684 
685   GDK_GL_NOTE (MISC,
686                g_message (" -- GLX_VENDOR     : %s",
687                           glXGetClientString (xdisplay, GLX_VENDOR)));
688   GDK_GL_NOTE (MISC,
689                g_message (" -- GLX_VERSION    : %s",
690                           glXGetClientString (xdisplay, GLX_VERSION)));
691   GDK_GL_NOTE (MISC,
692                g_message (" -- GLX_EXTENSIONS : %s",
693                           glXGetClientString (xdisplay, GLX_EXTENSIONS)));
694 
695   /*
696    * Get XVisualInfo.
697    */
698 
699   xvinfo = gdk_x11_gl_get_xvinfo (xdisplay, screen_num, xvisualid);
700   if (xvinfo == NULL)
701     return NULL;
702 
703   GDK_GL_NOTE (MISC,
704     g_message (" -- gdk_x11_gl_get_xvinfo: screen number = %d", xvinfo->screen));
705   GDK_GL_NOTE (MISC,
706     g_message (" -- gdk_x11_gl_get_xvinfo: visual id = 0x%lx", xvinfo->visualid));
707 
708   /*
709    * Instantiate the GdkGLConfigImplX11 object.
710    */
711 
712   glconfig = g_object_new (GDK_TYPE_GL_CONFIG_IMPL_X11, NULL);
713   impl = GDK_GL_CONFIG_IMPL_X11 (glconfig);
714 
715   impl->xdisplay = xdisplay;
716   impl->screen_num = screen_num;
717   impl->xvinfo = xvinfo;
718 
719   impl->screen = screen;
720 
721   /* Using Mesa? */
722   if (strstr (glXQueryServerString (xdisplay, screen_num, GLX_VERSION), "Mesa"))
723     impl->is_mesa_glx = TRUE;
724   else
725     impl->is_mesa_glx = FALSE;
726 
727   /*
728    * Get an appropriate colormap.
729    */
730 
731   /* RGBA mode? */
732   glXGetConfig (xdisplay, xvinfo, GLX_RGBA, &is_rgba);
733 
734   impl->colormap = gdk_gl_config_setup_colormap (impl->screen,
735                                                  impl->xvinfo,
736                                                  is_rgba,
737                                                  impl->is_mesa_glx);
738 
739   GDK_GL_NOTE (MISC,
740     g_message (" -- Colormap: visual id = 0x%lx",
741                GDK_VISUAL_XVISUAL (impl->colormap->visual)->visualid));
742 
743   /*
744    * Init configuration attributes.
745    */
746 
747   gdk_gl_config_init_attrib (glconfig);
748 
749   return glconfig;
750 }
751 
752 /**
753  * gdk_x11_gl_config_new_from_visualid:
754  * @xvisualid: visual ID.
755  *
756  * Creates #GdkGLConfig from given visual ID that specifies the OpenGL-capable
757  * visual.
758  *
759  * Return value: the new #GdkGLConfig.
760  **/
761 GdkGLConfig *
gdk_x11_gl_config_new_from_visualid(VisualID xvisualid)762 gdk_x11_gl_config_new_from_visualid (VisualID xvisualid)
763 {
764   GdkScreen *screen;
765 
766   GDK_GL_NOTE_FUNC ();
767 
768 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
769   screen = gdk_screen_get_default ();
770 #else  /* GDKGLEXT_MULTIHEAD_SUPPORT */
771   screen = NULL;
772 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
773 
774   return gdk_x11_gl_config_new_from_visualid_common (screen, xvisualid);
775 }
776 
777 #ifdef GDKGLEXT_MULTIHEAD_SUPPORT
778 
779 /**
780  * gdk_x11_gl_config_new_from_visualid_for_screen:
781  * @screen: target screen.
782  * @xvisualid: visual ID.
783  *
784  * Creates #GdkGLConfig from given visual ID that specifies the OpenGL-capable
785  * visual.
786  *
787  * Return value: the new #GdkGLConfig.
788  **/
789 GdkGLConfig *
gdk_x11_gl_config_new_from_visualid_for_screen(GdkScreen * screen,VisualID xvisualid)790 gdk_x11_gl_config_new_from_visualid_for_screen (GdkScreen *screen,
791                                                 VisualID   xvisualid)
792 {
793   GDK_GL_NOTE_FUNC ();
794 
795   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
796 
797   return gdk_x11_gl_config_new_from_visualid_common (screen, xvisualid);
798 }
799 
800 #endif /* GDKGLEXT_MULTIHEAD_SUPPORT */
801 
802 /**
803  * gdk_gl_config_get_screen:
804  * @glconfig: a #GdkGLConfig.
805  *
806  * Gets #GdkScreen.
807  *
808  * Return value: the #GdkScreen.
809  **/
810 GdkScreen *
gdk_gl_config_get_screen(GdkGLConfig * glconfig)811 gdk_gl_config_get_screen (GdkGLConfig *glconfig)
812 {
813   g_return_val_if_fail (GDK_IS_GL_CONFIG_IMPL_X11 (glconfig), NULL);
814 
815   return GDK_GL_CONFIG_IMPL_X11 (glconfig)->screen;
816 }
817 
818 /**
819  * gdk_gl_config_get_attrib:
820  * @glconfig: a #GdkGLConfig.
821  * @attribute: the attribute to be returned.
822  * @value: returns the requested value.
823  *
824  * Gets information about a OpenGL frame buffer configuration.
825  *
826  * Return value: TRUE if it succeeded, FALSE otherwise.
827  **/
828 gboolean
gdk_gl_config_get_attrib(GdkGLConfig * glconfig,int attribute,int * value)829 gdk_gl_config_get_attrib (GdkGLConfig *glconfig,
830                           int          attribute,
831                           int         *value)
832 {
833   GdkGLConfigImplX11 *impl;
834   int ret;
835 
836   g_return_val_if_fail (GDK_IS_GL_CONFIG_IMPL_X11 (glconfig), FALSE);
837 
838   impl = GDK_GL_CONFIG_IMPL_X11 (glconfig);
839 
840   ret = glXGetConfig (impl->xdisplay, impl->xvinfo, attribute, value);
841 
842   return (ret == Success);
843 }
844 
845 /**
846  * gdk_gl_config_get_colormap:
847  * @glconfig: a #GdkGLConfig.
848  *
849  * Gets the #GdkColormap that is appropriate for the OpenGL frame buffer
850  * configuration.
851  *
852  * Return value: the appropriate #GdkColormap.
853  **/
854 GdkColormap *
gdk_gl_config_get_colormap(GdkGLConfig * glconfig)855 gdk_gl_config_get_colormap (GdkGLConfig *glconfig)
856 {
857   g_return_val_if_fail (GDK_IS_GL_CONFIG_IMPL_X11 (glconfig), NULL);
858 
859   return GDK_GL_CONFIG_IMPL_X11 (glconfig)->colormap;
860 }
861 
862 /**
863  * gdk_gl_config_get_visual:
864  * @glconfig: a #GdkGLConfig.
865  *
866  * Gets the #GdkVisual that is appropriate for the OpenGL frame buffer
867  * configuration.
868  *
869  * Return value: the appropriate #GdkVisual.
870  **/
871 GdkVisual *
gdk_gl_config_get_visual(GdkGLConfig * glconfig)872 gdk_gl_config_get_visual (GdkGLConfig *glconfig)
873 {
874   g_return_val_if_fail (GDK_IS_GL_CONFIG_IMPL_X11 (glconfig), NULL);
875 
876   return gdk_colormap_get_visual (GDK_GL_CONFIG_IMPL_X11 (glconfig)->colormap);
877 }
878 
879 /**
880  * gdk_gl_config_get_depth:
881  * @glconfig: a #GdkGLConfig.
882  *
883  * Gets the color depth of the OpenGL-capable visual.
884  *
885  * Return value: number of bits per pixel
886  **/
887 gint
gdk_gl_config_get_depth(GdkGLConfig * glconfig)888 gdk_gl_config_get_depth (GdkGLConfig *glconfig)
889 {
890   g_return_val_if_fail (GDK_IS_GL_CONFIG_IMPL_X11 (glconfig), 0);
891 
892   return GDK_GL_CONFIG_IMPL_X11 (glconfig)->xvinfo->depth;
893 }
894 
895 /**
896  * gdk_x11_gl_config_get_xdisplay:
897  * @glconfig: a #GdkGLConfig.
898  *
899  * Gets X Display.
900  *
901  * Return value: pointer to the Display.
902  **/
903 Display *
gdk_x11_gl_config_get_xdisplay(GdkGLConfig * glconfig)904 gdk_x11_gl_config_get_xdisplay (GdkGLConfig *glconfig)
905 {
906   g_return_val_if_fail (GDK_IS_GL_CONFIG_IMPL_X11 (glconfig), NULL);
907 
908   return GDK_GL_CONFIG_IMPL_X11 (glconfig)->xdisplay;
909 }
910 
911 /**
912  * gdk_x11_gl_config_get_screen_number:
913  * @glconfig: a #GdkGLConfig.
914  *
915  * Gets X screen number.
916  *
917  * Return value: the screen number.
918  **/
919 int
gdk_x11_gl_config_get_screen_number(GdkGLConfig * glconfig)920 gdk_x11_gl_config_get_screen_number (GdkGLConfig *glconfig)
921 {
922   g_return_val_if_fail (GDK_IS_GL_CONFIG_IMPL_X11 (glconfig), 0);
923 
924   return GDK_GL_CONFIG_IMPL_X11 (glconfig)->screen_num;
925 }
926 
927 /**
928  * gdk_x11_gl_config_get_xvinfo:
929  * @glconfig: a #GdkGLConfig.
930  *
931  * Gets XVisualInfo data.
932  *
933  * Return value: pointer to the XVisualInfo data.
934  **/
935 XVisualInfo *
gdk_x11_gl_config_get_xvinfo(GdkGLConfig * glconfig)936 gdk_x11_gl_config_get_xvinfo (GdkGLConfig *glconfig)
937 {
938   g_return_val_if_fail (GDK_IS_GL_CONFIG_IMPL_X11 (glconfig), NULL);
939 
940   return GDK_GL_CONFIG_IMPL_X11 (glconfig)->xvinfo;
941 }
942 
943 /**
944  * gdk_x11_gl_config_is_mesa_glx:
945  * @glconfig: a #GdkGLConfig.
946  *
947  * Returns whether the server's GLX entension is Mesa.
948  *
949  * Return value: TRUE if Mesa GLX, FALSE otherwise.
950  **/
951 gboolean
gdk_x11_gl_config_is_mesa_glx(GdkGLConfig * glconfig)952 gdk_x11_gl_config_is_mesa_glx (GdkGLConfig *glconfig)
953 {
954   g_return_val_if_fail (GDK_IS_GL_CONFIG_IMPL_X11 (glconfig), FALSE);
955 
956   return GDK_GL_CONFIG_IMPL_X11 (glconfig)->is_mesa_glx;
957 }
958