1/* GDK - The GIMP Drawing Kit
2 * Copyright (C) 2000 Red Hat, Inc.
3 * 2005 Imendio AB
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19#include "config.h"
20
21#include "gdkproperty.h"
22
23#include "gdkprivate.h"
24
25/**
26 * SECTION:properties
27 * @Short_description: Functions to manipulate properties on windows
28 * @Title: Properties and Atoms
29 *
30 * Each window under X can have any number of associated
31 * “properties” attached to it.
32 * Properties are arbitrary chunks of data identified by
33 * “atom”s. (An “atom”
34 * is a numeric index into a string table on the X server. They are used
35 * to transfer strings efficiently between clients without
36 * having to transfer the entire string.) A property
37 * has an associated type, which is also identified
38 * using an atom.
39 *
40 * A property has an associated “format”,
41 * an integer describing how many bits are in each unit
42 * of data inside the property. It must be 8, 16, or 32.
43 * When data is transferred between the server and client,
44 * if they are of different endianesses it will be byteswapped
45 * as necessary according to the format of the property.
46 * Note that on the client side, properties of format 32
47 * will be stored with one unit per long,
48 * even if a long integer has more than 32 bits on the platform.
49 * (This decision was apparently made for Xlib to maintain
50 * compatibility with programs that assumed longs were 32
51 * bits, at the expense of programs that knew better.)
52 *
53 * The functions in this section are used to add, remove
54 * and change properties on windows, to convert atoms
55 * to and from strings and to manipulate some types of
56 * data commonly stored in X window properties.
57 */
58
59static GHashTable *names_to_atoms;
60static GPtrArray *atoms_to_names;
61
62static const gchar xatoms_string[] =
63 /* These are all the standard predefined X atoms */
64 "NONE\0"
65 "PRIMARY\0"
66 "SECONDARY\0"
67 "ARC\0"
68 "ATOM\0"
69 "BITMAP\0"
70 "CARDINAL\0"
71 "COLORMAP\0"
72 "CURSOR\0"
73 "CUT_BUFFER0\0"
74 "CUT_BUFFER1\0"
75 "CUT_BUFFER2\0"
76 "CUT_BUFFER3\0"
77 "CUT_BUFFER4\0"
78 "CUT_BUFFER5\0"
79 "CUT_BUFFER6\0"
80 "CUT_BUFFER7\0"
81 "DRAWABLE\0"
82 "FONT\0"
83 "INTEGER\0"
84 "PIXMAP\0"
85 "POINT\0"
86 "RECTANGLE\0"
87 "RESOURCE_MANAGER\0"
88 "RGB_COLOR_MAP\0"
89 "RGB_BEST_MAP\0"
90 "RGB_BLUE_MAP\0"
91 "RGB_DEFAULT_MAP\0"
92 "RGB_GRAY_MAP\0"
93 "RGB_GREEN_MAP\0"
94 "RGB_RED_MAP\0"
95 "STRING\0"
96 "VISUALID\0"
97 "WINDOW\0"
98 "WM_COMMAND\0"
99 "WM_HINTS\0"
100 "WM_CLIENT_MACHINE\0"
101 "WM_ICON_NAME\0"
102 "WM_ICON_SIZE\0"
103 "WM_NAME\0"
104 "WM_NORMAL_HINTS\0"
105 "WM_SIZE_HINTS\0"
106 "WM_ZOOM_HINTS\0"
107 "MIN_SPACE\0"
108 "NORM_SPACE\0"
109 "MAX_SPACE\0"
110 "END_SPACE\0"
111 "SUPERSCRIPT_X\0"
112 "SUPERSCRIPT_Y\0"
113 "SUBSCRIPT_X\0"
114 "SUBSCRIPT_Y\0"
115 "UNDERLINE_POSITION\0"
116 "UNDERLINE_THICKNESS\0"
117 "STRIKEOUT_ASCENT\0"
118 "STRIKEOUT_DESCENT\0"
119 "ITALIC_ANGLE\0"
120 "X_HEIGHT\0"
121 "QUAD_WIDTH\0"
122 "WEIGHT\0"
123 "POINT_SIZE\0"
124 "RESOLUTION\0"
125 "COPYRIGHT\0"
126 "NOTICE\0"
127 "FONT_NAME\0"
128 "FAMILY_NAME\0"
129 "FULL_NAME\0"
130 "CAP_HEIGHT\0"
131 "WM_CLASS\0"
132 "WM_TRANSIENT_FOR\0"
133 "CLIPBOARD\0" /* = 69 */;
134
135static const gint xatoms_offset[] = {
136 0, 5, 13, 23, 27, 32, 39, 48, 57, 64, 76, 88,
137 100, 112, 124, 136, 148, 160, 169, 174, 182, 189, 195, 205,
138 222, 236, 249, 262, 278, 291, 305, 317, 324, 333, 340, 351,
139 360, 378, 391, 404, 412, 428, 442, 456, 466, 477, 487, 497,
140 511, 525, 537, 549, 568, 588, 605, 623, 636, 645, 656, 663,
141 674, 685, 695, 702, 712, 724, 734, 745, 754, 771
142};
143
144static void
145ensure_atom_tables (void)
146{
147 int i;
148
149 if (names_to_atoms)
150 return;
151
152 names_to_atoms = g_hash_table_new (g_str_hash, g_str_equal);
153 atoms_to_names = g_ptr_array_sized_new (G_N_ELEMENTS (xatoms_offset));
154
155 for (i = 0; i < G_N_ELEMENTS (xatoms_offset); i++)
156 {
157 g_hash_table_insert(names_to_atoms, (gchar *)xatoms_string + xatoms_offset[i], GINT_TO_POINTER (i));
158 g_ptr_array_add(atoms_to_names, (gchar *)xatoms_string + xatoms_offset[i]);
159 }
160}
161
162static GdkAtom
163intern_atom_internal (const gchar *atom_name,
164 gboolean allocate)
165{
166 gpointer result;
167 gchar *name;
168
169 ensure_atom_tables ();
170
171 if (g_hash_table_lookup_extended (names_to_atoms, atom_name, NULL, &result))
172 return result;
173
174 result = GINT_TO_POINTER (atoms_to_names->len);
175 name = allocate ? g_strdup (atom_name) : (gchar *)atom_name;
176 g_hash_table_insert (names_to_atoms, name, result);
177 g_ptr_array_add (atoms_to_names, name);
178
179 return result;
180}
181
182/**
183 * gdk_atom_intern:
184 * @atom_name: a string.
185 * @only_if_exists: if %TRUE, GDK is allowed to not create a new atom, but
186 * just return %GDK_NONE if the requested atom doesn’t already
187 * exists. Currently, the flag is ignored, since checking the
188 * existance of an atom is as expensive as creating it.
189 *
190 * Finds or creates an atom corresponding to a given string.
191 *
192 * Returns: (transfer none): the atom corresponding to @atom_name.
193 */
194GdkAtom
195gdk_atom_intern (const gchar *atom_name,
196 gboolean only_if_exists)
197{
198 g_return_val_if_fail (atom_name != NULL, GDK_NONE);
199
200 return intern_atom_internal (atom_name, TRUE);
201}
202
203/**
204 * gdk_atom_intern_static_string:
205 * @atom_name: a static string
206 *
207 * Finds or creates an atom corresponding to a given string.
208 *
209 * Note that this function is identical to gdk_atom_intern() except
210 * that if a new #GdkAtom is created the string itself is used rather
211 * than a copy. This saves memory, but can only be used if the string
212 * will always exist. It can be used with statically
213 * allocated strings in the main program, but not with statically
214 * allocated memory in dynamically loaded modules, if you expect to
215 * ever unload the module again (e.g. do not use this function in
216 * GTK+ theme engines).
217 *
218 * Returns: (transfer none): the atom corresponding to @atom_name
219 *
220 * Since: 2.10
221 */
222GdkAtom
223gdk_atom_intern_static_string (const gchar *atom_name)
224{
225 g_return_val_if_fail (atom_name != NULL, GDK_NONE);
226
227 return intern_atom_internal (atom_name, FALSE);
228}
229
230/**
231 * gdk_atom_name:
232 * @atom: a #GdkAtom.
233 *
234 * Determines the string corresponding to an atom.
235 *
236 * Returns: a newly-allocated string containing the string
237 * corresponding to @atom. When you are done with the
238 * return value, you should free it using g_free().
239 */
240gchar *
241gdk_atom_name (GdkAtom atom)
242{
243 return g_strdup (_gdk_atom_name_const (atom));
244}
245
246const gchar *
247_gdk_atom_name_const (GdkAtom atom)
248{
249 ensure_atom_tables ();
250
251 if (GPOINTER_TO_INT (atom) >= atoms_to_names->len)
252 return NULL;
253
254 return g_ptr_array_index (atoms_to_names, GPOINTER_TO_INT (atom));
255}
256