Move new lxsession with built-in settings daemon to trunk.
[lxde/lxsession.git] / lxsession / xsettings-manager.c
1 /*
2 * Copyright © 2001 Red Hat, Inc.
3 *
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.
13 *
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.
20 *
21 * Author: Owen Taylor, Red Hat, Inc.
22 */
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include <X11/Xmd.h> /* For CARD16 */
28
29 #include "xsettings-manager.h"
30
31 struct _XSettingsManager
32 {
33 Display *display;
34 int screen;
35
36 Window window;
37 Atom manager_atom;
38 Atom selection_atom;
39 Atom xsettings_atom;
40
41 XSettingsTerminateFunc terminate;
42 void *cb_data;
43
44 XSettingsList *settings;
45 unsigned long serial;
46 };
47
48 static XSettingsList *settings;
49
50 typedef struct
51 {
52 Window window;
53 Atom timestamp_prop_atom;
54 } TimeStampInfo;
55
56 static Bool
57 timestamp_predicate (Display *display,
58 XEvent *xevent,
59 XPointer arg)
60 {
61 TimeStampInfo *info = (TimeStampInfo *)arg;
62
63 if (xevent->type == PropertyNotify &&
64 xevent->xproperty.window == info->window &&
65 xevent->xproperty.atom == info->timestamp_prop_atom)
66 return True;
67
68 return False;
69 }
70
71 /**
72 * get_server_time:
73 * @display: display from which to get the time
74 * @window: a #Window, used for communication with the server.
75 * The window must have PropertyChangeMask in its
76 * events mask or a hang will result.
77 *
78 * Routine to get the current X server time stamp.
79 *
80 * Return value: the time stamp.
81 **/
82 static Time
83 get_server_time (Display *display,
84 Window window)
85 {
86 unsigned char c = 'a';
87 XEvent xevent;
88 TimeStampInfo info;
89
90 info.timestamp_prop_atom = XInternAtom (display, "_TIMESTAMP_PROP", False);
91 info.window = window;
92
93 XChangeProperty (display, window,
94 info.timestamp_prop_atom, info.timestamp_prop_atom,
95 8, PropModeReplace, &c, 1);
96
97 XIfEvent (display, &xevent,
98 timestamp_predicate, (XPointer)&info);
99
100 return xevent.xproperty.time;
101 }
102
103 Bool
104 xsettings_manager_check_running (Display *display,
105 int screen)
106 {
107 char buffer[256];
108 Atom selection_atom;
109
110 sprintf(buffer, "_XSETTINGS_S%d", screen);
111 selection_atom = XInternAtom (display, buffer, False);
112
113 if (XGetSelectionOwner (display, selection_atom))
114 return True;
115 else
116 return False;
117 }
118
119 XSettingsManager *
120 xsettings_manager_new (Display *display,
121 int screen,
122 XSettingsTerminateFunc terminate,
123 void *cb_data)
124 {
125 XSettingsManager *manager;
126 Time timestamp;
127 XClientMessageEvent xev;
128
129 char buffer[256];
130
131 manager = malloc (sizeof *manager);
132 if (!manager)
133 return NULL;
134
135 manager->display = display;
136 manager->screen = screen;
137
138 sprintf(buffer, "_XSETTINGS_S%d", screen);
139 manager->selection_atom = XInternAtom (display, buffer, False);
140 manager->xsettings_atom = XInternAtom (display, "_XSETTINGS_SETTINGS", False);
141 manager->manager_atom = XInternAtom (display, "MANAGER", False);
142
143 manager->terminate = terminate;
144 manager->cb_data = cb_data;
145
146 manager->settings = NULL;
147 manager->serial = 0;
148
149 manager->window = XCreateSimpleWindow (display,
150 RootWindow (display, screen),
151 0, 0, 10, 10, 0,
152 WhitePixel (display, screen),
153 WhitePixel (display, screen));
154
155 XSelectInput (display, manager->window, PropertyChangeMask);
156 timestamp = get_server_time (display, manager->window);
157
158 XSetSelectionOwner (display, manager->selection_atom,
159 manager->window, timestamp);
160
161 /* Check to see if we managed to claim the selection. If not,
162 * we treat it as if we got it then immediately lost it
163 */
164
165 if (XGetSelectionOwner (display, manager->selection_atom) ==
166 manager->window)
167 {
168 xev.type = ClientMessage;
169 xev.window = RootWindow (display, screen);
170 xev.message_type = manager->manager_atom;
171 xev.format = 32;
172 xev.data.l[0] = timestamp;
173 xev.data.l[1] = manager->selection_atom;
174 xev.data.l[2] = manager->window;
175 xev.data.l[3] = 0; /* manager specific data */
176 xev.data.l[4] = 0; /* manager specific data */
177
178 XSendEvent (display, RootWindow (display, screen),
179 False, StructureNotifyMask, (XEvent *)&xev);
180 }
181 else
182 {
183 manager->terminate (manager->cb_data);
184 }
185
186 return manager;
187 }
188
189 void
190 xsettings_manager_destroy (XSettingsManager *manager)
191 {
192 XDestroyWindow (manager->display, manager->window);
193
194 xsettings_list_free (manager->settings);
195 free (manager);
196 }
197
198 Window
199 xsettings_manager_get_window (XSettingsManager *manager)
200 {
201 return manager->window;
202 }
203
204 Bool
205 xsettings_manager_process_event (XSettingsManager *manager,
206 XEvent *xev)
207 {
208 if (xev->xany.window == manager->window &&
209 xev->xany.type == SelectionClear &&
210 xev->xselectionclear.selection == manager->selection_atom)
211 {
212 manager->terminate (manager->cb_data);
213 return True;
214 }
215
216 return False;
217 }
218
219 XSettingsResult
220 xsettings_manager_delete_setting (XSettingsManager *manager,
221 const char *name)
222 {
223 return xsettings_list_delete (&settings, name);
224 }
225
226 XSettingsResult
227 xsettings_manager_set_setting (XSettingsManager *manager,
228 XSettingsSetting *setting)
229 {
230 XSettingsSetting *old_setting = xsettings_list_lookup (settings, setting->name);
231 XSettingsSetting *new_setting;
232 XSettingsResult result;
233
234 if (old_setting)
235 {
236 if (xsettings_setting_equal (old_setting, setting))
237 return XSETTINGS_SUCCESS;
238
239 xsettings_list_delete (&settings, setting->name);
240 }
241
242 new_setting = xsettings_setting_copy (setting);
243 if (!new_setting)
244 return XSETTINGS_NO_MEM;
245
246 new_setting->last_change_serial = manager->serial;
247
248 result = xsettings_list_insert (&settings, new_setting);
249
250 if (result != XSETTINGS_SUCCESS)
251 xsettings_setting_free (new_setting);
252
253 return result;
254 }
255
256 XSettingsResult
257 xsettings_manager_set_int (XSettingsManager *manager,
258 const char *name,
259 int value)
260 {
261 XSettingsSetting setting;
262
263 setting.name = (char *)name;
264 setting.type = XSETTINGS_TYPE_INT;
265 setting.data.v_int = value;
266
267 return xsettings_manager_set_setting (manager, &setting);
268 }
269
270 XSettingsResult
271 xsettings_manager_set_string (XSettingsManager *manager,
272 const char *name,
273 const char *value)
274 {
275 XSettingsSetting setting;
276
277 setting.name = (char *)name;
278 setting.type = XSETTINGS_TYPE_STRING;
279 setting.data.v_string = (char *)value;
280
281 return xsettings_manager_set_setting (manager, &setting);
282 }
283
284 XSettingsResult
285 xsettings_manager_set_color (XSettingsManager *manager,
286 const char *name,
287 XSettingsColor *value)
288 {
289 XSettingsSetting setting;
290
291 setting.name = (char *)name;
292 setting.type = XSETTINGS_TYPE_COLOR;
293 setting.data.v_color = *value;
294
295 return xsettings_manager_set_setting (manager, &setting);
296 }
297
298 static size_t
299 setting_length (XSettingsSetting *setting)
300 {
301 size_t length = 8; /* type + pad + name-len + last-change-serial */
302 length += XSETTINGS_PAD (strlen (setting->name), 4);
303
304 switch (setting->type)
305 {
306 case XSETTINGS_TYPE_INT:
307 length += 4;
308 break;
309 case XSETTINGS_TYPE_STRING:
310 length += 4 + XSETTINGS_PAD (strlen (setting->data.v_string), 4);
311 break;
312 case XSETTINGS_TYPE_COLOR:
313 length += 8;
314 break;
315 }
316
317 return length;
318 }
319
320 static void
321 setting_store (XSettingsSetting *setting,
322 XSettingsBuffer *buffer)
323 {
324 size_t string_len;
325 size_t length;
326
327 *(buffer->pos++) = setting->type;
328 *(buffer->pos++) = 0;
329
330 string_len = strlen (setting->name);
331 *(CARD16 *)(buffer->pos) = string_len;
332 buffer->pos += 2;
333
334 length = XSETTINGS_PAD (string_len, 4);
335 memcpy (buffer->pos, setting->name, string_len);
336 length -= string_len;
337 buffer->pos += string_len;
338
339 while (length > 0)
340 {
341 *(buffer->pos++) = 0;
342 length--;
343 }
344
345 *(CARD32 *)(buffer->pos) = setting->last_change_serial;
346 buffer->pos += 4;
347
348 switch (setting->type)
349 {
350 case XSETTINGS_TYPE_INT:
351 *(CARD32 *)(buffer->pos) = setting->data.v_int;
352 buffer->pos += 4;
353 break;
354 case XSETTINGS_TYPE_STRING:
355 string_len = strlen (setting->data.v_string);
356 *(CARD32 *)(buffer->pos) = string_len;
357 buffer->pos += 4;
358
359 length = XSETTINGS_PAD (string_len, 4);
360 memcpy (buffer->pos, setting->data.v_string, string_len);
361 length -= string_len;
362 buffer->pos += string_len;
363
364 while (length > 0)
365 {
366 *(buffer->pos++) = 0;
367 length--;
368 }
369 break;
370 case XSETTINGS_TYPE_COLOR:
371 *(CARD16 *)(buffer->pos) = setting->data.v_color.red;
372 *(CARD16 *)(buffer->pos + 2) = setting->data.v_color.green;
373 *(CARD16 *)(buffer->pos + 4) = setting->data.v_color.blue;
374 *(CARD16 *)(buffer->pos + 6) = setting->data.v_color.alpha;
375 buffer->pos += 8;
376 break;
377 }
378 }
379
380 XSettingsResult
381 xsettings_manager_notify (XSettingsManager *manager)
382 {
383 XSettingsBuffer buffer;
384 XSettingsList *iter;
385 int n_settings = 0;
386
387 buffer.len = 12; /* byte-order + pad + SERIAL + N_SETTINGS */
388
389 iter = settings;
390 while (iter)
391 {
392 buffer.len += setting_length (iter->setting);
393 n_settings++;
394 iter = iter->next;
395 }
396
397 buffer.data = buffer.pos = malloc (buffer.len);
398 if (!buffer.data)
399 return XSETTINGS_NO_MEM;
400
401 *buffer.pos = xsettings_byte_order ();
402
403 buffer.pos += 4;
404 *(CARD32 *)buffer.pos = manager->serial++;
405 buffer.pos += 4;
406 *(CARD32 *)buffer.pos = n_settings;
407 buffer.pos += 4;
408
409 iter = settings;
410 while (iter)
411 {
412 setting_store (iter->setting, &buffer);
413 iter = iter->next;
414 }
415
416 XChangeProperty (manager->display, manager->window,
417 manager->xsettings_atom, manager->xsettings_atom,
418 8, PropModeReplace, buffer.data, buffer.len);
419
420 free (buffer.data);
421
422 return XSETTINGS_SUCCESS;
423 }
424