]> Pileus Git - ~andy/gtk/blob - gdk/x11/gdkvisual-x11.c
b3fef17731ea55f62be05e38bc3bd7e861cc9b0c
[~andy/gtk] / gdk / x11 / gdkvisual-x11.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
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 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
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.  See the ChangeLog
23  * files for a list of changes.  These files are distributed with
24  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
25  */
26
27 #include "config.h"
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30
31 #include "gdkx.h"
32 #include "gdkvisual.h"
33 #include "gdkprivate-x11.h"
34 #include "gdkscreen-x11.h"
35 #include "gdkinternals.h"
36
37 struct _GdkVisualPrivate
38 {
39   Visual *xvisual;
40   GdkScreen *screen;
41   Colormap colormap;
42 };
43
44 struct _GdkVisualClass
45 {
46   GObjectClass parent_class;
47 };
48
49 static void     gdk_visual_add            (GdkVisual *visual);
50 static void     gdk_visual_decompose_mask (gulong     mask,
51                                            gint      *shift,
52                                            gint      *prec);
53 static guint    gdk_visual_hash           (Visual    *key);
54 static gboolean gdk_visual_equal          (Visual    *a,
55                                            Visual    *b);
56
57
58 #ifdef G_ENABLE_DEBUG
59
60 static const gchar *const visual_names[] =
61 {
62   "static gray",
63   "grayscale",
64   "static color",
65   "pseudo color",
66   "true color",
67   "direct color",
68 };
69
70 #endif /* G_ENABLE_DEBUG */
71
72 G_DEFINE_TYPE (GdkVisual, gdk_visual, G_TYPE_OBJECT)
73
74 static void
75 gdk_visual_finalize (GObject *object)
76 {
77   GdkVisualPrivate *priv = (GdkVisualPrivate *) object;
78
79   if (priv->colormap != None)
80     XFreeColormap (GDK_SCREEN_XDISPLAY (priv->screen),
81                    priv->colormap);
82
83   G_OBJECT_CLASS (gdk_visual_parent_class)->finalize (object);
84 }
85
86 static void
87 gdk_visual_class_init (GdkVisualClass *visual_class)
88 {
89   GObjectClass *object_class = G_OBJECT_CLASS (visual_class);
90
91   g_type_class_add_private (object_class, sizeof (GdkVisualPrivate));
92
93   object_class->finalize = gdk_visual_finalize;
94 }
95
96 static void
97 gdk_visual_init (GdkVisual *visual)
98 {
99   visual->priv = G_TYPE_INSTANCE_GET_PRIVATE (visual,
100                                               GDK_TYPE_VISUAL,
101                                               GdkVisualPrivate);
102
103   visual->priv->colormap = None;
104 }
105
106 void
107 _gdk_visual_init (GdkScreen *screen)
108 {
109   static const gint possible_depths[8] = { 32, 30, 24, 16, 15, 8, 4, 1 };
110   static const GdkVisualType possible_types[6] =
111     {
112       GDK_VISUAL_DIRECT_COLOR,
113       GDK_VISUAL_TRUE_COLOR,
114       GDK_VISUAL_PSEUDO_COLOR,
115       GDK_VISUAL_STATIC_COLOR,
116       GDK_VISUAL_GRAYSCALE,
117       GDK_VISUAL_STATIC_GRAY
118     };
119
120   GdkScreenX11 *screen_x11;
121   XVisualInfo *visual_list;
122   XVisualInfo visual_template;
123   GdkVisual *temp_visual;
124   Visual *default_xvisual;
125   GdkVisual **visuals;
126   int nxvisuals;
127   int nvisuals;
128   int i, j;
129   
130   g_return_if_fail (GDK_IS_SCREEN (screen));
131   screen_x11 = GDK_SCREEN_X11 (screen);
132
133   nxvisuals = 0;
134   visual_template.screen = screen_x11->screen_num;
135   visual_list = XGetVisualInfo (screen_x11->xdisplay, VisualScreenMask, &visual_template, &nxvisuals);
136   
137   visuals = g_new (GdkVisual *, nxvisuals);
138   for (i = 0; i < nxvisuals; i++)
139     visuals[i] = g_object_new (GDK_TYPE_VISUAL, NULL);
140
141   default_xvisual = DefaultVisual (screen_x11->xdisplay, screen_x11->screen_num);
142
143   nvisuals = 0;
144   for (i = 0; i < nxvisuals; i++)
145     {
146       visuals[nvisuals]->priv->screen = screen;
147       
148       if (visual_list[i].depth >= 1)
149         {
150 #ifdef __cplusplus
151           switch (visual_list[i].c_class)
152 #else /* __cplusplus */
153           switch (visual_list[i].class)
154 #endif /* __cplusplus */
155             {
156             case StaticGray:
157               visuals[nvisuals]->type = GDK_VISUAL_STATIC_GRAY;
158               break;
159             case GrayScale:
160               visuals[nvisuals]->type = GDK_VISUAL_GRAYSCALE;
161               break;
162             case StaticColor:
163               visuals[nvisuals]->type = GDK_VISUAL_STATIC_COLOR;
164               break;
165             case PseudoColor:
166               visuals[nvisuals]->type = GDK_VISUAL_PSEUDO_COLOR;
167               break;
168             case TrueColor:
169               visuals[nvisuals]->type = GDK_VISUAL_TRUE_COLOR;
170               break;
171             case DirectColor:
172               visuals[nvisuals]->type = GDK_VISUAL_DIRECT_COLOR;
173               break;
174             }
175
176           visuals[nvisuals]->depth = visual_list[i].depth;
177           visuals[nvisuals]->byte_order =
178             (ImageByteOrder(screen_x11->xdisplay) == LSBFirst) ?
179             GDK_LSB_FIRST : GDK_MSB_FIRST;
180           visuals[nvisuals]->red_mask = visual_list[i].red_mask;
181           visuals[nvisuals]->green_mask = visual_list[i].green_mask;
182           visuals[nvisuals]->blue_mask = visual_list[i].blue_mask;
183           visuals[nvisuals]->colormap_size = visual_list[i].colormap_size;
184           visuals[nvisuals]->bits_per_rgb = visual_list[i].bits_per_rgb;
185           visuals[nvisuals]->priv->xvisual = visual_list[i].visual;
186
187           if ((visuals[nvisuals]->type == GDK_VISUAL_TRUE_COLOR) ||
188               (visuals[nvisuals]->type == GDK_VISUAL_DIRECT_COLOR))
189             {
190               gdk_visual_decompose_mask (visuals[nvisuals]->red_mask,
191                                          &visuals[nvisuals]->red_shift,
192                                          &visuals[nvisuals]->red_prec);
193
194               gdk_visual_decompose_mask (visuals[nvisuals]->green_mask,
195                                          &visuals[nvisuals]->green_shift,
196                                          &visuals[nvisuals]->green_prec);
197
198               gdk_visual_decompose_mask (visuals[nvisuals]->blue_mask,
199                                          &visuals[nvisuals]->blue_shift,
200                                          &visuals[nvisuals]->blue_prec);
201             }
202           else
203             {
204               visuals[nvisuals]->red_mask = 0;
205               visuals[nvisuals]->red_shift = 0;
206               visuals[nvisuals]->red_prec = 0;
207
208               visuals[nvisuals]->green_mask = 0;
209               visuals[nvisuals]->green_shift = 0;
210               visuals[nvisuals]->green_prec = 0;
211
212               visuals[nvisuals]->blue_mask = 0;
213               visuals[nvisuals]->blue_shift = 0;
214               visuals[nvisuals]->blue_prec = 0;
215             }
216           
217           nvisuals += 1;
218         }
219     }
220
221   if (visual_list)
222     XFree (visual_list);
223
224   for (i = 0; i < nvisuals; i++)
225     {
226       for (j = i+1; j < nvisuals; j++)
227         {
228           if (visuals[j]->depth >= visuals[i]->depth)
229             {
230               if ((visuals[j]->depth == 8) && (visuals[i]->depth == 8))
231                 {
232                   if (visuals[j]->type == GDK_VISUAL_PSEUDO_COLOR)
233                     {
234                       temp_visual = visuals[j];
235                       visuals[j] = visuals[i];
236                       visuals[i] = temp_visual;
237                     }
238                   else if ((visuals[i]->type != GDK_VISUAL_PSEUDO_COLOR) &&
239                            visuals[j]->type > visuals[i]->type)
240                     {
241                       temp_visual = visuals[j];
242                       visuals[j] = visuals[i];
243                       visuals[i] = temp_visual;
244                     }
245                 }
246               else if ((visuals[j]->depth > visuals[i]->depth) ||
247                        ((visuals[j]->depth == visuals[i]->depth) &&
248                         (visuals[j]->type > visuals[i]->type)))
249                 {
250                   temp_visual = visuals[j];
251                   visuals[j] = visuals[i];
252                   visuals[i] = temp_visual;
253                 }
254             }
255         }
256     }
257
258   for (i = 0; i < nvisuals; i++)
259     {
260       if (default_xvisual->visualid == visuals[i]->priv->xvisual->visualid)
261          {
262            screen_x11->system_visual = visuals[i];
263            visuals[i]->priv->colormap = DefaultColormap (screen_x11->xdisplay,
264                                                          screen_x11->screen_num);
265          }
266
267       /* For now, we only support 8888 ARGB for the "rgba visual".
268        * Additional formats (like ABGR) could be added later if they
269        * turn up.
270        */
271       if (visuals[i]->depth == 32 &&
272           (visuals[i]->red_mask   == 0xff0000 &&
273            visuals[i]->green_mask == 0x00ff00 &&
274            visuals[i]->blue_mask  == 0x0000ff))
275         {
276           screen_x11->rgba_visual = GDK_VISUAL (visuals[i]);
277         }
278     }
279
280 #ifdef G_ENABLE_DEBUG 
281   if (_gdk_debug_flags & GDK_DEBUG_MISC)
282     {
283       static const gchar *const visual_names[] =
284       {
285         "static gray",
286         "grayscale",
287         "static color",
288         "pseudo color",
289         "true color",
290         "direct color",
291       };
292
293       for (i = 0; i < nvisuals; i++)
294         g_message ("visual: %s: %d",
295                    visual_names[visuals[i]->type],
296                    visuals[i]->depth);
297     }
298 #endif /* G_ENABLE_DEBUG */
299
300   screen_x11->navailable_depths = 0;
301   for (i = 0; i < G_N_ELEMENTS (possible_depths); i++)
302     {
303       for (j = 0; j < nvisuals; j++)
304         {
305           if (visuals[j]->depth == possible_depths[i])
306             {
307               screen_x11->available_depths[screen_x11->navailable_depths++] = visuals[j]->depth;
308               break;
309             }
310         }
311     }
312
313   if (screen_x11->navailable_depths == 0)
314     g_error ("unable to find a usable depth");
315
316   screen_x11->navailable_types = 0;
317   for (i = 0; i < G_N_ELEMENTS (possible_types); i++)
318     {
319       for (j = 0; j < nvisuals; j++)
320         {
321           if (visuals[j]->type == possible_types[i])
322             {
323               screen_x11->available_types[screen_x11->navailable_types++] = visuals[j]->type;
324               break;
325             }
326         }
327     }
328
329   for (i = 0; i < nvisuals; i++)
330     gdk_visual_add ((GdkVisual*) visuals[i]);
331
332   if (screen_x11->navailable_types == 0)
333     g_error ("unable to find a usable visual type");
334
335   screen_x11->visuals = visuals;
336   screen_x11->nvisuals = nvisuals;
337 }
338
339 /**
340  * gdk_visual_get_best_depth:
341  * 
342  * Get the best available depth for the default GDK screen.  "Best"
343  * means "largest," i.e. 32 preferred over 24 preferred over 8 bits
344  * per pixel.
345  * 
346  * Return value: best available depth
347  **/
348 gint
349 gdk_visual_get_best_depth (void)
350 {
351   GdkScreen *screen = gdk_screen_get_default();
352   
353   return GDK_SCREEN_X11 (screen)->available_depths[0];
354 }
355
356 /**
357  * gdk_visual_get_best_type:
358  * 
359  * Return the best available visual type for the default GDK screen.
360  * 
361  * Return value: best visual type
362  **/
363 GdkVisualType
364 gdk_visual_get_best_type (void)
365 {
366   GdkScreen *screen = gdk_screen_get_default();
367   
368   return GDK_SCREEN_X11 (screen)->available_types[0];
369 }
370
371 /**
372  * gdk_screen_get_system_visual:
373  * @screen: a #GdkScreen.
374  * 
375  * Get the system's default visual for @screen.
376  * This is the visual for the root window of the display.
377  * The return value should not be freed.
378  * 
379  * Return value: (transfer none): the system visual
380  *
381  * Since: 2.2
382  **/
383 GdkVisual *
384 gdk_screen_get_system_visual (GdkScreen * screen)
385 {
386   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
387
388   return ((GdkVisual *) GDK_SCREEN_X11 (screen)->system_visual);
389 }
390
391 /**
392  * gdk_visual_get_best:
393  *
394  * Get the visual with the most available colors for the default
395  * GDK screen. The return value should not be freed.
396  * 
397  * Return value: (transfer none): best visual
398  **/
399 GdkVisual*
400 gdk_visual_get_best (void)
401 {
402   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (gdk_screen_get_default());
403
404   return (GdkVisual *)screen_x11->visuals[0];
405 }
406
407 /**
408  * gdk_visual_get_best_with_depth:
409  * @depth: a bit depth
410  * 
411  * Get the best visual with depth @depth for the default GDK screen.
412  * Color visuals and visuals with mutable colormaps are preferred
413  * over grayscale or fixed-colormap visuals. The return value should not
414  * be freed. %NULL may be returned if no visual supports @depth.
415  * 
416  * Return value: (transfer none): best visual for the given depth
417  **/
418 GdkVisual*
419 gdk_visual_get_best_with_depth (gint depth)
420 {
421   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (gdk_screen_get_default ());
422   GdkVisual *return_val;
423   int i;
424   
425   return_val = NULL;
426   for (i = 0; i < screen_x11->nvisuals; i++)
427     if (depth == screen_x11->visuals[i]->depth)
428       {
429         return_val = (GdkVisual *) screen_x11->visuals[i];
430         break;
431       }
432
433   return return_val;
434 }
435
436 /**
437  * gdk_visual_get_best_with_type:
438  * @visual_type: a visual type
439  *
440  * Get the best visual of the given @visual_type for the default GDK screen.
441  * Visuals with higher color depths are considered better. The return value
442  * should not be freed. %NULL may be returned if no visual has type
443  * @visual_type.
444  * 
445  * Return value: (transfer none): best visual of the given type
446  **/
447 GdkVisual*
448 gdk_visual_get_best_with_type (GdkVisualType visual_type)
449 {
450   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (gdk_screen_get_default ());
451   GdkVisual *return_val;
452   int i;
453
454   return_val = NULL;
455   for (i = 0; i < screen_x11->nvisuals; i++)
456     if (visual_type == screen_x11->visuals[i]->type)
457       {
458         return_val = (GdkVisual *) screen_x11->visuals[i];
459         break;
460       }
461
462   return return_val;
463 }
464
465 /**
466  * gdk_visual_get_best_with_both:
467  * @depth: a bit depth
468  * @visual_type: a visual type
469  *
470  * Combines gdk_visual_get_best_with_depth() and gdk_visual_get_best_with_type().
471  * 
472  * Return value: (transfer none): best visual with both @depth and
473  *     @visual_type, or %NULL if none
474  **/
475 GdkVisual*
476 gdk_visual_get_best_with_both (gint          depth,
477                                GdkVisualType visual_type)
478 {
479   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (gdk_screen_get_default ());
480   GdkVisual *return_val;
481   int i;
482
483   return_val = NULL;
484   for (i = 0; i < screen_x11->nvisuals; i++)
485     if ((depth == screen_x11->visuals[i]->depth) &&
486         (visual_type == screen_x11->visuals[i]->type))
487       {
488         return_val = (GdkVisual *) screen_x11->visuals[i];
489         break;
490       }
491
492   return return_val;
493 }
494
495 /**
496  * gdk_query_depths:
497  * @depths: (out) (array): return location for available depths
498  * @count: (out): return location for number of available depths
499  *
500  * This function returns the available bit depths for the default
501  * screen. It's equivalent to listing the visuals
502  * (gdk_list_visuals()) and then looking at the depth field in each
503  * visual, removing duplicates.
504  * 
505  * The array returned by this function should not be freed.
506  * 
507  **/
508 void
509 gdk_query_depths  (gint **depths,
510                    gint  *count)
511 {
512   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (gdk_screen_get_default ());
513   
514   *count = screen_x11->navailable_depths;
515   *depths = screen_x11->available_depths;
516 }
517
518 /**
519  * gdk_query_visual_types:
520  * @visual_types: return location for the available visual types
521  * @count: return location for the number of available visual types
522  *
523  * This function returns the available visual types for the default
524  * screen. It's equivalent to listing the visuals
525  * (gdk_list_visuals()) and then looking at the type field in each
526  * visual, removing duplicates.
527  * 
528  * The array returned by this function should not be freed.
529  **/
530 void
531 gdk_query_visual_types (GdkVisualType **visual_types,
532                         gint           *count)
533 {
534   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (gdk_screen_get_default ());
535   
536   *count = screen_x11->navailable_types;
537   *visual_types = screen_x11->available_types;
538 }
539
540 /**
541  * gdk_screen_list_visuals:
542  * @screen: the relevant #GdkScreen.
543  *  
544  * Lists the available visuals for the specified @screen.
545  * A visual describes a hardware image data format.
546  * For example, a visual might support 24-bit color, or 8-bit color,
547  * and might expect pixels to be in a certain format.
548  *
549  * Call g_list_free() on the return value when you're finished with it.
550  * 
551  * Return value: (transfer container) (element-type GdkVisual):
552  *     a list of visuals; the list must be freed, but not its contents
553  *
554  * Since: 2.2
555  **/
556 GList *
557 gdk_screen_list_visuals (GdkScreen *screen)
558 {
559   GList *list;
560   GdkScreenX11 *screen_x11;
561   guint i;
562
563   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
564   screen_x11 = GDK_SCREEN_X11 (screen);
565   
566   list = NULL;
567
568   for (i = 0; i < screen_x11->nvisuals; ++i)
569     list = g_list_append (list, screen_x11->visuals[i]);
570
571   return list;
572 }
573
574 /**
575  * gdk_x11_screen_lookup_visual:
576  * @screen: a #GdkScreen.
577  * @xvisualid: an X Visual ID.
578  *
579  * Looks up the #GdkVisual for a particular screen and X Visual ID.
580  *
581  * Returns: the #GdkVisual (owned by the screen object), or %NULL
582  *   if the visual ID wasn't found.
583  *
584  * Since: 2.2
585  */
586 GdkVisual *
587 gdk_x11_screen_lookup_visual (GdkScreen *screen,
588                               VisualID   xvisualid)
589 {
590   int i;
591   GdkScreenX11 *screen_x11;
592   g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
593   screen_x11 = GDK_SCREEN_X11 (screen);
594
595   for (i = 0; i < screen_x11->nvisuals; i++)
596     if (xvisualid == screen_x11->visuals[i]->priv->xvisual->visualid)
597       return (GdkVisual *)  screen_x11->visuals[i];
598
599   return NULL;
600 }
601
602 /**
603  * gdkx_visual_get:
604  * @xvisualid: a X visual id.
605  * 
606  * Returns a #GdkVisual corresponding to a X visual. 
607  * 
608  * Return value: the #GdkVisual.
609  **/
610 GdkVisual*
611 gdkx_visual_get (VisualID xvisualid)
612 {
613   return gdk_x11_screen_lookup_visual (gdk_screen_get_default (), xvisualid);
614 }
615
616 static void
617 gdk_visual_add (GdkVisual *visual)
618 {
619   GdkScreenX11 *screen_x11 = GDK_SCREEN_X11 (visual->priv->screen);
620   
621   if (!screen_x11->visual_hash)
622     screen_x11->visual_hash = g_hash_table_new ((GHashFunc) gdk_visual_hash,
623                                                 (GEqualFunc) gdk_visual_equal);
624
625   g_hash_table_insert (screen_x11->visual_hash, visual->priv->xvisual, visual);
626 }
627
628 static void
629 gdk_visual_decompose_mask (gulong  mask,
630                            gint   *shift,
631                            gint   *prec)
632 {
633   *shift = 0;
634   *prec = 0;
635
636   if (mask == 0)
637     {
638       g_warning ("Mask is 0 in visual. Server bug ?");
639       return;
640     }
641
642   while (!(mask & 0x1))
643     {
644       (*shift)++;
645       mask >>= 1;
646     }
647
648   while (mask & 0x1)
649     {
650       (*prec)++;
651       mask >>= 1;
652     }
653 }
654
655 static guint
656 gdk_visual_hash (Visual *key)
657 {
658   return key->visualid;
659 }
660
661 static gboolean
662 gdk_visual_equal (Visual *a,
663                   Visual *b)
664 {
665   return (a->visualid == b->visualid);
666 }
667
668 /**
669  * _gdk_visual_get_x11_colormap:
670  * @visual: the visual to get the colormap from
671  *
672  * Gets the colormap to use
673  *
674  * Returns: the X Colormap to use for new windows using @visual
675  **/
676 Colormap
677 _gdk_visual_get_x11_colormap (GdkVisual *visual)
678 {
679   GdkVisualPrivate *priv;
680
681   g_return_val_if_fail (GDK_IS_VISUAL (visual), None);
682
683   priv = visual->priv;
684
685   if (priv->colormap == None)
686     {
687       priv->colormap = XCreateColormap (GDK_SCREEN_XDISPLAY (priv->screen),
688                                         GDK_SCREEN_XROOTWIN (priv->screen),
689                                         GDK_VISUAL_XVISUAL (visual),
690                                         AllocNone);
691     }
692
693   return priv->colormap;
694 }
695
696 /**
697  * gdk_x11_visual_get_xvisual:
698  * @visual: a #GdkVisual.
699  * 
700  * Returns the X visual belonging to a #GdkVisual.
701  * 
702  * Return value: an Xlib <type>Visual*</type>.
703  **/
704 Visual *
705 gdk_x11_visual_get_xvisual (GdkVisual *visual)
706 {
707   g_return_val_if_fail (visual != NULL, NULL);
708
709   return visual->priv->xvisual;
710 }
711
712 /**
713  * gdk_visual_get_screen:
714  * @visual: a #GdkVisual
715  * 
716  * Gets the screen to which this visual belongs
717  * 
718  * Return value: (transfer none): the screen to which this visual belongs.
719  *
720  * Since: 2.2
721  **/
722 GdkScreen *
723 gdk_visual_get_screen (GdkVisual *visual)
724 {
725   g_return_val_if_fail (GDK_IS_VISUAL (visual), NULL);
726
727   return visual->priv->screen;
728 }