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 printf("XSETTINGS_ACTION %s\n", setting
->data
.v_string
);
55 if (icon_theme_name
) {
56 if (strcmp(icon_theme_name
, setting
->data
.v_string
) == 0)
58 g_free(icon_theme_name
);
60 icon_theme_name
= strdup(setting
->data
.v_string
);
65 for (i=0 ; i < nb_panel ; i++) {
67 init_launcher_panel(p);
70 MBTrayApp *mb = (MBTrayApp *)data;
71 mb->theme_name = strdup(setting->data.v_string);
73 mb->theme_cb(mb, mb->theme_name);
80 static void notify_changes (XSettingsClient
*client
, XSettingsList
*old_list
)
82 XSettingsList
*old_iter
= old_list
;
83 XSettingsList
*new_iter
= client
->settings
;
88 while (old_iter
|| new_iter
) {
91 if (old_iter
&& new_iter
)
92 cmp
= strcmp (old_iter
->setting
->name
, new_iter
->setting
->name
);
99 client
->notify (old_iter
->setting
->name
, XSETTINGS_ACTION_DELETED
, NULL
, client
->cb_data
);
102 if (!xsettings_setting_equal (old_iter
->setting
, new_iter
->setting
))
103 client
->notify (old_iter
->setting
->name
, XSETTINGS_ACTION_CHANGED
, new_iter
->setting
, client
->cb_data
);
106 client
->notify (new_iter
->setting
->name
, XSETTINGS_ACTION_NEW
, new_iter
->setting
, client
->cb_data
);
110 old_iter
= old_iter
->next
;
112 new_iter
= new_iter
->next
;
117 static int ignore_errors (Display
*display
, XErrorEvent
*event
)
122 static char local_byte_order
= '\0';
124 #define BYTES_LEFT(buffer) ((buffer)->data + (buffer)->len - (buffer)->pos)
126 static XSettingsResult
fetch_card16 (XSettingsBuffer
*buffer
, CARD16
*result
)
130 if (BYTES_LEFT (buffer
) < 2)
131 return XSETTINGS_ACCESS
;
133 x
= *(CARD16
*)buffer
->pos
;
136 if (buffer
->byte_order
== local_byte_order
)
139 *result
= (x
<< 8) | (x
>> 8);
141 return XSETTINGS_SUCCESS
;
145 static XSettingsResult
fetch_ushort (XSettingsBuffer
*buffer
, unsigned short *result
)
150 r
= fetch_card16 (buffer
, &x
);
151 if (r
== XSETTINGS_SUCCESS
)
158 static XSettingsResult
fetch_card32 (XSettingsBuffer
*buffer
, CARD32
*result
)
162 if (BYTES_LEFT (buffer
) < 4)
163 return XSETTINGS_ACCESS
;
165 x
= *(CARD32
*)buffer
->pos
;
168 if (buffer
->byte_order
== local_byte_order
)
171 *result
= (x
<< 24) | ((x
& 0xff00) << 8) | ((x
& 0xff0000) >> 8) | (x
>> 24);
173 return XSETTINGS_SUCCESS
;
176 static XSettingsResult
fetch_card8 (XSettingsBuffer
*buffer
, CARD8
*result
)
178 if (BYTES_LEFT (buffer
) < 1)
179 return XSETTINGS_ACCESS
;
181 *result
= *(CARD8
*)buffer
->pos
;
184 return XSETTINGS_SUCCESS
;
187 #define XSETTINGS_PAD(n,m) ((n + m - 1) & (~(m-1)))
189 static XSettingsList
*parse_settings (unsigned char *data
, size_t len
)
191 XSettingsBuffer buffer
;
192 XSettingsResult result
= XSETTINGS_SUCCESS
;
193 XSettingsList
*settings
= NULL
;
197 XSettingsSetting
*setting
= NULL
;
199 local_byte_order
= xsettings_byte_order ();
201 buffer
.pos
= buffer
.data
= data
;
204 result
= fetch_card8 (&buffer
, (CARD8
*)&buffer
.byte_order
);
205 if (buffer
.byte_order
!= MSBFirst
&& buffer
.byte_order
!= LSBFirst
) {
206 fprintf (stderr
, "Invalid byte order %x in XSETTINGS property\n", buffer
.byte_order
);
207 result
= XSETTINGS_FAILED
;
213 result
= fetch_card32 (&buffer
, &serial
);
214 if (result
!= XSETTINGS_SUCCESS
)
217 result
= fetch_card32 (&buffer
, &n_entries
);
218 if (result
!= XSETTINGS_SUCCESS
)
221 for (i
= 0; i
< n_entries
; i
++) {
227 result
= fetch_card8 (&buffer
, &type
);
228 if (result
!= XSETTINGS_SUCCESS
)
233 result
= fetch_card16 (&buffer
, &name_len
);
234 if (result
!= XSETTINGS_SUCCESS
)
237 pad_len
= XSETTINGS_PAD(name_len
, 4);
238 if (BYTES_LEFT (&buffer
) < pad_len
) {
239 result
= XSETTINGS_ACCESS
;
243 setting
= malloc (sizeof *setting
);
245 result
= XSETTINGS_NO_MEM
;
248 setting
->type
= XSETTINGS_TYPE_INT
; /* No allocated memory */
250 setting
->name
= malloc (name_len
+ 1);
251 if (!setting
->name
) {
252 result
= XSETTINGS_NO_MEM
;
256 memcpy (setting
->name
, buffer
.pos
, name_len
);
257 setting
->name
[name_len
] = '\0';
258 buffer
.pos
+= pad_len
;
260 result
= fetch_card32 (&buffer
, &v_int
);
261 if (result
!= XSETTINGS_SUCCESS
)
263 setting
->last_change_serial
= v_int
;
266 case XSETTINGS_TYPE_INT
:
267 result
= fetch_card32 (&buffer
, &v_int
);
268 if (result
!= XSETTINGS_SUCCESS
)
270 setting
->data
.v_int
= (INT32
)v_int
;
272 case XSETTINGS_TYPE_STRING
:
273 result
= fetch_card32 (&buffer
, &v_int
);
274 if (result
!= XSETTINGS_SUCCESS
)
277 pad_len
= XSETTINGS_PAD (v_int
, 4);
278 if (v_int
+ 1 == 0 || /* Guard against wrap-around */
279 BYTES_LEFT (&buffer
) < pad_len
) {
280 result
= XSETTINGS_ACCESS
;
284 setting
->data
.v_string
= malloc (v_int
+ 1);
285 if (!setting
->data
.v_string
) {
286 result
= XSETTINGS_NO_MEM
;
290 memcpy (setting
->data
.v_string
, buffer
.pos
, v_int
);
291 setting
->data
.v_string
[v_int
] = '\0';
292 buffer
.pos
+= pad_len
;
294 case XSETTINGS_TYPE_COLOR
:
295 result
= fetch_ushort (&buffer
, &setting
->data
.v_color
.red
);
296 if (result
!= XSETTINGS_SUCCESS
)
298 result
= fetch_ushort (&buffer
, &setting
->data
.v_color
.green
);
299 if (result
!= XSETTINGS_SUCCESS
)
301 result
= fetch_ushort (&buffer
, &setting
->data
.v_color
.blue
);
302 if (result
!= XSETTINGS_SUCCESS
)
304 result
= fetch_ushort (&buffer
, &setting
->data
.v_color
.alpha
);
305 if (result
!= XSETTINGS_SUCCESS
)
309 /* Quietly ignore unknown types */
313 setting
->type
= type
;
315 result
= xsettings_list_insert (&settings
, setting
);
316 if (result
!= XSETTINGS_SUCCESS
)
324 if (result
!= XSETTINGS_SUCCESS
) {
326 case XSETTINGS_NO_MEM
:
327 fprintf(stderr
, "Out of memory reading XSETTINGS property\n");
329 case XSETTINGS_ACCESS
:
330 fprintf(stderr
, "Invalid XSETTINGS property (read off end)\n");
332 case XSETTINGS_DUPLICATE_ENTRY
:
333 fprintf (stderr
, "Duplicate XSETTINGS entry for '%s'\n", setting
->name
);
334 case XSETTINGS_FAILED
:
335 case XSETTINGS_SUCCESS
:
336 case XSETTINGS_NO_ENTRY
:
341 xsettings_setting_free (setting
);
343 xsettings_list_free (settings
);
351 static void read_settings (XSettingsClient
*client
)
355 unsigned long n_items
;
356 unsigned long bytes_after
;
360 int (*old_handler
) (Display
*, XErrorEvent
*);
362 XSettingsList
*old_list
= client
->settings
;
363 client
->settings
= NULL
;
364 printf("read_settings 1\n");
366 old_handler
= XSetErrorHandler (ignore_errors
);
367 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
);
368 XSetErrorHandler (old_handler
);
370 if (result
== Success
&& type
== server
.atom
._XSETTINGS_SETTINGS
) {
372 fprintf (stderr
, "Invalid format for XSETTINGS property %d", format
);
375 client
->settings
= parse_settings (data
, n_items
);
379 notify_changes (client
, old_list
);
380 xsettings_list_free (old_list
);
384 static void check_manager_window (XSettingsClient
*client
)
386 if (client
->manager_window
&& client
->watch
)
387 client
->watch (client
->manager_window
, False
, 0, client
->cb_data
);
389 XGrabServer (client
->display
);
391 client
->manager_window
= XGetSelectionOwner (server
.dsp
, server
.atom
._XSETTINGS_SCREEN
);
392 if (client
->manager_window
)
393 XSelectInput (server
.dsp
, client
->manager_window
, PropertyChangeMask
| StructureNotifyMask
);
395 XUngrabServer (client
->display
);
396 XFlush (client
->display
);
398 if (client
->manager_window
&& client
->watch
)
399 client
->watch (client
->manager_window
, True
, PropertyChangeMask
| StructureNotifyMask
, client
->cb_data
);
401 read_settings (client
);
405 XSettingsClient
*xsettings_client_new (Display
*display
, int screen
, XSettingsNotifyFunc notify
, XSettingsWatchFunc watch
, void *cb_data
)
407 XSettingsClient
*client
;
409 client
= malloc (sizeof *client
);
413 client
->display
= display
;
414 client
->screen
= screen
;
415 client
->notify
= notify
;
416 client
->watch
= watch
;
417 client
->cb_data
= cb_data
;
419 client
->manager_window
= None
;
420 client
->settings
= NULL
;
422 XGrabServer (server
.dsp
);
423 client
->manager_window
= XGetSelectionOwner (server
.dsp
, server
.atom
._XSETTINGS_SCREEN
);
424 if (client
->manager_window
!= None
)
425 XSelectInput (server
.dsp
, client
->manager_window
, PropertyChangeMask
| StructureNotifyMask
);
426 XUngrabServer (client
->display
);
427 XFlush (client
->display
);
429 if (client
->manager_window
== None
) {
430 printf("NO XSETTINGS manager, tint2 use config 'launcher_icon_theme'.\n");
436 client
->watch (RootWindow (display
, screen
), True
, StructureNotifyMask
, client
->cb_data
);
438 check_manager_window (client
);
444 void xsettings_client_destroy (XSettingsClient
*client
)
447 client
->watch (RootWindow (client
->display
, client
->screen
), False
, 0, client
->cb_data
);
448 if (client
->manager_window
&& client
->watch
)
449 client
->watch (client
->manager_window
, False
, 0, client
->cb_data
);
451 xsettings_list_free (client
->settings
);
456 XSettingsResult
xsettings_client_get_setting (XSettingsClient
*client
, const char *name
, XSettingsSetting
**setting
)
458 XSettingsSetting
*search
= xsettings_list_lookup (client
->settings
, name
);
460 *setting
= xsettings_setting_copy (search
);
461 return *setting
? XSETTINGS_SUCCESS
: XSETTINGS_NO_MEM
;
464 return XSETTINGS_NO_ENTRY
;
468 Bool
xsettings_client_process_event (XSettingsClient
*client
, XEvent
*xev
)
470 /* The checks here will not unlikely cause us to reread
471 * the properties from the manager window a number of
472 * times when the manager changes from A->B. But manager changes
473 * are going to be pretty rare.
475 if (xev
->xany
.window
== RootWindow (server
.dsp
, server
.screen
)) {
476 if (xev
->xany
.type
== ClientMessage
&& xev
->xclient
.message_type
== server
.atom
.MANAGER
) {
477 check_manager_window (client
);
481 else if (xev
->xany
.window
== client
->manager_window
) {
482 if (xev
->xany
.type
== DestroyNotify
) {
483 check_manager_window (client
);
486 else if (xev
->xany
.type
== PropertyNotify
) {
487 read_settings (client
);