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