2 * Copyright © 2001 Red Hat, Inc.
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Red Hat not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. Red Hat makes no representations about the
11 * suitability of this software for any purpose. It is provided "as is"
12 * without express or implied warranty.
14 * RED HAT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL RED HAT
16 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
18 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
19 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
21 * Author: Owen Taylor, Red Hat, Inc.
29 #include <X11/Xmd.h> /* For CARD16 */
31 #include "xsettings-client.h"
36 struct _XSettingsClient
40 XSettingsNotifyFunc notify
;
41 XSettingsWatchFunc watch
;
44 Window manager_window
;
45 XSettingsList
*settings
;
49 void xsettings_notify_cb (const char *name
, XSettingsAction action
, XSettingsSetting
*setting
, void *data
)
51 //printf("xsettings_notify_cb\n");
52 if ((action
== XSETTINGS_ACTION_NEW
|| action
== XSETTINGS_ACTION_CHANGED
) && name
!= NULL
&& setting
!= NULL
) {
53 if (!strcmp(name
, "Net/IconThemeName") && setting
->type
== XSETTINGS_TYPE_STRING
) {
54 if (icon_theme_name
) {
55 if (strcmp(icon_theme_name
, setting
->data
.v_string
) == 0)
57 g_free(icon_theme_name
);
59 icon_theme_name
= strdup(setting
->data
.v_string
);
62 for (i
= 0 ; i
< nb_panel
; i
++) {
63 Launcher
*launcher
= &panel1
[i
].launcher
;
64 cleanup_launcher_theme(launcher
);
65 launcher_load_themes(launcher
);
66 launcher_load_icons(launcher
);
67 launcher
->area
.resize
= 1;
74 static void notify_changes (XSettingsClient
*client
, XSettingsList
*old_list
)
76 XSettingsList
*old_iter
= old_list
;
77 XSettingsList
*new_iter
= client
->settings
;
82 while (old_iter
|| new_iter
) {
85 if (old_iter
&& new_iter
)
86 cmp
= strcmp (old_iter
->setting
->name
, new_iter
->setting
->name
);
93 client
->notify (old_iter
->setting
->name
, XSETTINGS_ACTION_DELETED
, NULL
, client
->cb_data
);
96 if (!xsettings_setting_equal (old_iter
->setting
, new_iter
->setting
))
97 client
->notify (old_iter
->setting
->name
, XSETTINGS_ACTION_CHANGED
, new_iter
->setting
, client
->cb_data
);
100 client
->notify (new_iter
->setting
->name
, XSETTINGS_ACTION_NEW
, new_iter
->setting
, client
->cb_data
);
104 old_iter
= old_iter
->next
;
106 new_iter
= new_iter
->next
;
111 static int ignore_errors (Display
*display
, XErrorEvent
*event
)
116 static char local_byte_order
= '\0';
118 #define BYTES_LEFT(buffer) ((buffer)->data + (buffer)->len - (buffer)->pos)
120 static XSettingsResult
fetch_card16 (XSettingsBuffer
*buffer
, CARD16
*result
)
124 if (BYTES_LEFT (buffer
) < 2)
125 return XSETTINGS_ACCESS
;
127 x
= *(CARD16
*)buffer
->pos
;
130 if (buffer
->byte_order
== local_byte_order
)
133 *result
= (x
<< 8) | (x
>> 8);
135 return XSETTINGS_SUCCESS
;
139 static XSettingsResult
fetch_ushort (XSettingsBuffer
*buffer
, unsigned short *result
)
144 r
= fetch_card16 (buffer
, &x
);
145 if (r
== XSETTINGS_SUCCESS
)
152 static XSettingsResult
fetch_card32 (XSettingsBuffer
*buffer
, CARD32
*result
)
156 if (BYTES_LEFT (buffer
) < 4)
157 return XSETTINGS_ACCESS
;
159 x
= *(CARD32
*)buffer
->pos
;
162 if (buffer
->byte_order
== local_byte_order
)
165 *result
= (x
<< 24) | ((x
& 0xff00) << 8) | ((x
& 0xff0000) >> 8) | (x
>> 24);
167 return XSETTINGS_SUCCESS
;
170 static XSettingsResult
fetch_card8 (XSettingsBuffer
*buffer
, CARD8
*result
)
172 if (BYTES_LEFT (buffer
) < 1)
173 return XSETTINGS_ACCESS
;
175 *result
= *(CARD8
*)buffer
->pos
;
178 return XSETTINGS_SUCCESS
;
181 #define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1)))
183 static XSettingsList
*parse_settings (unsigned char *data
, size_t len
)
185 XSettingsBuffer buffer
;
186 XSettingsResult result
= XSETTINGS_SUCCESS
;
187 XSettingsList
*settings
= NULL
;
191 XSettingsSetting
*setting
= NULL
;
193 local_byte_order
= xsettings_byte_order ();
195 buffer
.pos
= buffer
.data
= data
;
198 result
= fetch_card8 (&buffer
, (CARD8
*)&buffer
.byte_order
);
199 if (buffer
.byte_order
!= MSBFirst
&& buffer
.byte_order
!= LSBFirst
) {
200 fprintf (stderr
, "Invalid byte order %x in XSETTINGS property\n", buffer
.byte_order
);
201 result
= XSETTINGS_FAILED
;
207 result
= fetch_card32 (&buffer
, &serial
);
208 if (result
!= XSETTINGS_SUCCESS
)
211 result
= fetch_card32 (&buffer
, &n_entries
);
212 if (result
!= XSETTINGS_SUCCESS
)
215 for (i
= 0; i
< n_entries
; i
++) {
221 result
= fetch_card8 (&buffer
, &type
);
222 if (result
!= XSETTINGS_SUCCESS
)
227 result
= fetch_card16 (&buffer
, &name_len
);
228 if (result
!= XSETTINGS_SUCCESS
)
231 pad_len
= XSETTINGS_PAD(name_len
, 4);
232 if (BYTES_LEFT (&buffer
) < pad_len
) {
233 result
= XSETTINGS_ACCESS
;
237 setting
= malloc (sizeof *setting
);
239 result
= XSETTINGS_NO_MEM
;
242 setting
->type
= XSETTINGS_TYPE_INT
; /* No allocated memory */
244 setting
->name
= malloc (name_len
+ 1);
245 if (!setting
->name
) {
246 result
= XSETTINGS_NO_MEM
;
250 memcpy (setting
->name
, buffer
.pos
, name_len
);
251 setting
->name
[name_len
] = '\0';
252 buffer
.pos
+= pad_len
;
254 result
= fetch_card32 (&buffer
, &v_int
);
255 if (result
!= XSETTINGS_SUCCESS
)
257 setting
->last_change_serial
= v_int
;
260 case XSETTINGS_TYPE_INT
:
261 result
= fetch_card32 (&buffer
, &v_int
);
262 if (result
!= XSETTINGS_SUCCESS
)
264 setting
->data
.v_int
= (INT32
)v_int
;
266 case XSETTINGS_TYPE_STRING
:
267 result
= fetch_card32 (&buffer
, &v_int
);
268 if (result
!= XSETTINGS_SUCCESS
)
271 pad_len
= XSETTINGS_PAD (v_int
, 4);
272 if (v_int
+ 1 == 0 || /* Guard against wrap-around */
273 BYTES_LEFT (&buffer
) < pad_len
) {
274 result
= XSETTINGS_ACCESS
;
278 setting
->data
.v_string
= malloc (v_int
+ 1);
279 if (!setting
->data
.v_string
) {
280 result
= XSETTINGS_NO_MEM
;
284 memcpy (setting
->data
.v_string
, buffer
.pos
, v_int
);
285 setting
->data
.v_string
[v_int
] = '\0';
286 buffer
.pos
+= pad_len
;
288 case XSETTINGS_TYPE_COLOR
:
289 result
= fetch_ushort (&buffer
, &setting
->data
.v_color
.red
);
290 if (result
!= XSETTINGS_SUCCESS
)
292 result
= fetch_ushort (&buffer
, &setting
->data
.v_color
.green
);
293 if (result
!= XSETTINGS_SUCCESS
)
295 result
= fetch_ushort (&buffer
, &setting
->data
.v_color
.blue
);
296 if (result
!= XSETTINGS_SUCCESS
)
298 result
= fetch_ushort (&buffer
, &setting
->data
.v_color
.alpha
);
299 if (result
!= XSETTINGS_SUCCESS
)
303 /* Quietly ignore unknown types */
307 setting
->type
= type
;
309 result
= xsettings_list_insert (&settings
, setting
);
310 if (result
!= XSETTINGS_SUCCESS
)
318 if (result
!= XSETTINGS_SUCCESS
) {
320 case XSETTINGS_NO_MEM
:
321 fprintf(stderr
, "Out of memory reading XSETTINGS property\n");
323 case XSETTINGS_ACCESS
:
324 fprintf(stderr
, "Invalid XSETTINGS property (read off end)\n");
326 case XSETTINGS_DUPLICATE_ENTRY
:
327 fprintf (stderr
, "Duplicate XSETTINGS entry for '%s'\n", setting
->name
);
328 case XSETTINGS_FAILED
:
329 case XSETTINGS_SUCCESS
:
330 case XSETTINGS_NO_ENTRY
:
335 xsettings_setting_free (setting
);
337 xsettings_list_free (settings
);
345 static void read_settings (XSettingsClient
*client
)
349 unsigned long n_items
;
350 unsigned long bytes_after
;
354 int (*old_handler
) (Display
*, XErrorEvent
*);
356 XSettingsList
*old_list
= client
->settings
;
357 client
->settings
= NULL
;
359 old_handler
= XSetErrorHandler (ignore_errors
);
360 result
= XGetWindowProperty (client
->display
, client
->manager_window
, server
.atom
._XSETTINGS_SETTINGS
, 0, LONG_MAX
, False
, server
.atom
._XSETTINGS_SETTINGS
, &type
, &format
, &n_items
, &bytes_after
, &data
);
361 XSetErrorHandler (old_handler
);
363 if (result
== Success
&& type
== server
.atom
._XSETTINGS_SETTINGS
) {
365 fprintf (stderr
, "Invalid format for XSETTINGS property %d", format
);
368 client
->settings
= parse_settings (data
, n_items
);
372 notify_changes (client
, old_list
);
373 xsettings_list_free (old_list
);
377 static void check_manager_window (XSettingsClient
*client
)
379 if (client
->manager_window
&& client
->watch
)
380 client
->watch (client
->manager_window
, False
, 0, client
->cb_data
);
382 XGrabServer (client
->display
);
384 client
->manager_window
= XGetSelectionOwner (server
.dsp
, server
.atom
._XSETTINGS_SCREEN
);
385 if (client
->manager_window
)
386 XSelectInput (server
.dsp
, client
->manager_window
, PropertyChangeMask
| StructureNotifyMask
);
388 XUngrabServer (client
->display
);
389 XFlush (client
->display
);
391 if (client
->manager_window
&& client
->watch
)
392 client
->watch (client
->manager_window
, True
, PropertyChangeMask
| StructureNotifyMask
, client
->cb_data
);
394 read_settings (client
);
398 XSettingsClient
*xsettings_client_new (Display
*display
, int screen
, XSettingsNotifyFunc notify
, XSettingsWatchFunc watch
, void *cb_data
)
400 XSettingsClient
*client
;
402 client
= malloc (sizeof *client
);
406 client
->display
= display
;
407 client
->screen
= screen
;
408 client
->notify
= notify
;
409 client
->watch
= watch
;
410 client
->cb_data
= cb_data
;
412 client
->manager_window
= None
;
413 client
->settings
= NULL
;
416 client
->watch (RootWindow (display
, screen
), True
, StructureNotifyMask
, client
->cb_data
);
418 check_manager_window (client
);
420 if (client
->manager_window
== None
) {
421 printf("NO XSETTINGS manager, tint2 use config 'launcher_icon_theme'.\n");
430 void xsettings_client_destroy (XSettingsClient
*client
)
433 client
->watch (RootWindow (client
->display
, client
->screen
), False
, 0, client
->cb_data
);
434 if (client
->manager_window
&& client
->watch
)
435 client
->watch (client
->manager_window
, False
, 0, client
->cb_data
);
437 xsettings_list_free (client
->settings
);
442 XSettingsResult
xsettings_client_get_setting (XSettingsClient
*client
, const char *name
, XSettingsSetting
**setting
)
444 XSettingsSetting
*search
= xsettings_list_lookup (client
->settings
, name
);
446 *setting
= xsettings_setting_copy (search
);
447 return *setting
? XSETTINGS_SUCCESS
: XSETTINGS_NO_MEM
;
450 return XSETTINGS_NO_ENTRY
;
454 Bool
xsettings_client_process_event (XSettingsClient
*client
, XEvent
*xev
)
456 /* The checks here will not unlikely cause us to reread
457 * the properties from the manager window a number of
458 * times when the manager changes from A->B. But manager changes
459 * are going to be pretty rare.
461 if (xev
->xany
.window
== RootWindow (server
.dsp
, server
.screen
)) {
462 if (xev
->xany
.type
== ClientMessage
&& xev
->xclient
.message_type
== server
.atom
.MANAGER
) {
463 check_manager_window (client
);
467 else if (xev
->xany
.window
== client
->manager_window
) {
468 if (xev
->xany
.type
== DestroyNotify
) {
469 check_manager_window (client
);
472 else if (xev
->xany
.type
== PropertyNotify
) {
473 read_settings (client
);