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, see <http://www.gnu.org/licenses/>.
16  */
17 
18 /*
19  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
20  * file for a list of people on the GTK+ Team.  See the ChangeLog
21  * files for a list of changes.  These files are distributed with
22  * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
23  */
24 
25 #include "config.h"
26 
27 #include "gdkinternals.h"
28 #include "gdkprivate-x11.h"
29 #include "gdkdisplay-x11.h"
30 #include "gdkscreen-x11.h"
31 
32 #include <X11/Xlib.h>
33 #include <X11/Xatom.h>
34 #include <string.h>
35 
36 static void
insert_atom_pair(GdkDisplay * display,const char * string,Atom xatom)37 insert_atom_pair (GdkDisplay *display,
38                   const char *string,
39 		  Atom        xatom)
40 {
41   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
42   char *s;
43 
44   if (!display_x11->atom_from_string)
45     {
46       display_x11->atom_from_string = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
47       display_x11->atom_to_string = g_hash_table_new (NULL, NULL);
48     }
49 
50   s = g_strdup (string);
51   g_hash_table_insert (display_x11->atom_from_string, s, GUINT_TO_POINTER (xatom));
52   g_hash_table_insert (display_x11->atom_to_string, GUINT_TO_POINTER (xatom), s);
53 }
54 
55 static Atom
lookup_cached_xatom(GdkDisplay * display,const char * string)56 lookup_cached_xatom (GdkDisplay *display,
57 		     const char *string)
58 {
59   GdkX11Display *display_x11 = GDK_X11_DISPLAY (display);
60 
61   if (display_x11->atom_from_string)
62     return GPOINTER_TO_UINT (g_hash_table_lookup (display_x11->atom_from_string, string));
63 
64   return None;
65 }
66 
67 /**
68  * gdk_x11_get_xatom_by_name_for_display:
69  * @display: (type GdkX11Display): a `GdkDisplay`
70  * @atom_name: a string
71  *
72  * Returns the X atom for a `GdkDisplay` corresponding to @atom_name.
73  * This function caches the result, so if called repeatedly it is much
74  * faster than XInternAtom(), which is a round trip to the server each time.
75  *
76  * Returns: a X atom for a `GdkDisplay`
77  **/
78 Atom
gdk_x11_get_xatom_by_name_for_display(GdkDisplay * display,const char * atom_name)79 gdk_x11_get_xatom_by_name_for_display (GdkDisplay  *display,
80 				       const char *atom_name)
81 {
82   Atom xatom = None;
83 
84   g_return_val_if_fail (GDK_IS_DISPLAY (display), None);
85 
86   if (atom_name == NULL)
87     return None;
88 
89   if (gdk_display_is_closed (display))
90     return None;
91 
92   xatom = lookup_cached_xatom (display, atom_name);
93 
94   if (!xatom)
95     {
96       xatom = XInternAtom (GDK_DISPLAY_XDISPLAY (display), atom_name, FALSE);
97       insert_atom_pair (display, atom_name, xatom);
98     }
99 
100   return xatom;
101 }
102 
103 void
_gdk_x11_precache_atoms(GdkDisplay * display,const char * const * atom_names,int n_atoms)104 _gdk_x11_precache_atoms (GdkDisplay          *display,
105 			 const char * const *atom_names,
106 			 int                  n_atoms)
107 {
108   Atom *xatoms;
109   const char **xatom_names;
110   int n_xatoms;
111   int i;
112 
113   xatoms = g_new (Atom, n_atoms);
114   xatom_names = g_new (const char *, n_atoms);
115 
116   n_xatoms = 0;
117   for (i = 0; i < n_atoms; i++)
118     {
119       if (lookup_cached_xatom (display, atom_names[i]) == None)
120 	{
121 	  xatom_names[n_xatoms] = atom_names[i];
122 	  n_xatoms++;
123 	}
124     }
125 
126   if (n_xatoms)
127     XInternAtoms (GDK_DISPLAY_XDISPLAY (display),
128                   (char **) xatom_names, n_xatoms, False, xatoms);
129 
130   for (i = 0; i < n_xatoms; i++)
131     insert_atom_pair (display, xatom_names[i], xatoms[i]);
132 
133   g_free (xatoms);
134   g_free (xatom_names);
135 }
136 
137 /**
138  * gdk_x11_get_xatom_name_for_display:
139  * @display: (type GdkX11Display): the `GdkDisplay` where @xatom is defined
140  * @xatom: an X atom
141  *
142  * Returns the name of an X atom for its display. This
143  * function is meant mainly for debugging, so for convenience, unlike
144  * XAtomName() and the result doesn’t need to
145  * be freed.
146  *
147  * Returns: name of the X atom; this string is owned by GDK,
148  *   so it shouldn’t be modified or freed.
149  **/
150 const char *
gdk_x11_get_xatom_name_for_display(GdkDisplay * display,Atom xatom)151 gdk_x11_get_xatom_name_for_display (GdkDisplay *display,
152 				    Atom        xatom)
153 
154 {
155   GdkX11Display *display_x11;
156   const char *string;
157 
158   g_return_val_if_fail (GDK_IS_DISPLAY (display), NULL);
159 
160   if (xatom == None)
161     return NULL;
162 
163   if (gdk_display_is_closed (display))
164     return NULL;
165 
166   display_x11 = GDK_X11_DISPLAY (display);
167 
168   if (display_x11->atom_to_string)
169     string = g_hash_table_lookup (display_x11->atom_to_string,
170 				  GUINT_TO_POINTER (xatom));
171   else
172     string = NULL;
173 
174   if (!string)
175     {
176       /* If this atom doesn't exist, we'll die with an X error unless
177        * we take precautions
178        */
179       char *name;
180       gdk_x11_display_error_trap_push (display);
181       name = XGetAtomName (GDK_DISPLAY_XDISPLAY (display), xatom);
182       if (gdk_x11_display_error_trap_pop (display))
183 	{
184 	  g_warning (G_STRLOC " invalid X atom: %ld", xatom);
185 	}
186       else
187 	{
188 	  insert_atom_pair (display, name, xatom);
189 	  XFree (name);
190           string = g_hash_table_lookup (display_x11->atom_to_string,
191                                         GUINT_TO_POINTER (xatom));
192 	}
193     }
194 
195   return string;
196 }
197 
198 Atom
_gdk_x11_get_xatom_for_display_printf(GdkDisplay * display,const char * format,...)199 _gdk_x11_get_xatom_for_display_printf (GdkDisplay    *display,
200                                        const char    *format,
201                                        ...)
202 {
203   va_list args;
204   char *atom_name;
205   Atom atom;
206 
207   va_start (args, format);
208   atom_name = g_strdup_vprintf (format, args);
209   va_end (args);
210 
211   atom = gdk_x11_get_xatom_by_name_for_display (display, atom_name);
212 
213   g_free (atom_name);
214 
215   return atom;
216 }
217 
218