~ctf/unity-settings-daemon/bug1389099_mic_volume_icons

« back to all changes in this revision

Viewing changes to plugins/xsettings/xsettings-manager.c

  • Committer: Package Import Robot
  • Author(s): Robert Ancell
  • Date: 2014-02-07 11:44:36 UTC
  • Revision ID: package-import@ubuntu.com-20140207114436-7t5u3yvwc4ul7w3e
Tags: upstream-14.04.0
ImportĀ upstreamĀ versionĀ 14.04.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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 <glib.h>
 
28
#include <X11/Xmd.h>            /* For CARD16 */
 
29
 
 
30
#include "xsettings-manager.h"
 
31
 
 
32
#define XSETTINGS_VARIANT_TYPE_COLOR  (G_VARIANT_TYPE ("(qqqq)"))
 
33
 
 
34
struct _XSettingsManager
 
35
{
 
36
  Display *display;
 
37
  int screen;
 
38
 
 
39
  Window window;
 
40
  Atom manager_atom;
 
41
  Atom selection_atom;
 
42
  Atom xsettings_atom;
 
43
 
 
44
  XSettingsTerminateFunc terminate;
 
45
  void *cb_data;
 
46
 
 
47
  GHashTable *settings;
 
48
  unsigned long serial;
 
49
 
 
50
  GVariant *overrides;
 
51
};
 
52
 
 
53
typedef struct 
 
54
{
 
55
  Window window;
 
56
  Atom timestamp_prop_atom;
 
57
} TimeStampInfo;
 
58
 
 
59
static Bool
 
60
timestamp_predicate (Display *display,
 
61
                     XEvent  *xevent,
 
62
                     XPointer arg)
 
63
{
 
64
  TimeStampInfo *info = (TimeStampInfo *)arg;
 
65
 
 
66
  if (xevent->type == PropertyNotify &&
 
67
      xevent->xproperty.window == info->window &&
 
68
      xevent->xproperty.atom == info->timestamp_prop_atom)
 
69
    return True;
 
70
 
 
71
  return False;
 
72
}
 
73
 
 
74
/**
 
75
 * get_server_time:
 
76
 * @display: display from which to get the time
 
77
 * @window: a #Window, used for communication with the server.
 
78
 *          The window must have PropertyChangeMask in its
 
79
 *          events mask or a hang will result.
 
80
 * 
 
81
 * Routine to get the current X server time stamp. 
 
82
 * 
 
83
 * Return value: the time stamp.
 
84
 **/
 
85
static Time
 
86
get_server_time (Display *display,
 
87
                 Window   window)
 
88
{
 
89
  unsigned char c = 'a';
 
90
  XEvent xevent;
 
91
  TimeStampInfo info;
 
92
 
 
93
  info.timestamp_prop_atom = XInternAtom  (display, "_TIMESTAMP_PROP", False);
 
94
  info.window = window;
 
95
 
 
96
  XChangeProperty (display, window,
 
97
                   info.timestamp_prop_atom, info.timestamp_prop_atom,
 
98
                   8, PropModeReplace, &c, 1);
 
99
 
 
100
  XIfEvent (display, &xevent,
 
101
            timestamp_predicate, (XPointer)&info);
 
102
 
 
103
  return xevent.xproperty.time;
 
104
}
 
105
 
 
106
Bool
 
107
xsettings_manager_check_running (Display *display,
 
108
                                 int      screen)
 
109
{
 
110
  char buffer[256];
 
111
  Atom selection_atom;
 
112
  
 
113
  sprintf(buffer, "_XSETTINGS_S%d", screen);
 
114
  selection_atom = XInternAtom (display, buffer, False);
 
115
 
 
116
  if (XGetSelectionOwner (display, selection_atom))
 
117
    return True;
 
118
  else
 
119
    return False;
 
120
}
 
121
 
 
122
XSettingsManager *
 
123
xsettings_manager_new (Display                *display,
 
124
                       int                     screen,
 
125
                       XSettingsTerminateFunc  terminate,
 
126
                       void                   *cb_data)
 
127
{
 
128
  XSettingsManager *manager;
 
129
  Time timestamp;
 
130
  XClientMessageEvent xev;
 
131
 
 
132
  char buffer[256];
 
133
 
 
134
  manager = g_slice_new (XSettingsManager);
 
135
 
 
136
  manager->display = display;
 
137
  manager->screen = screen;
 
138
 
 
139
  sprintf(buffer, "_XSETTINGS_S%d", screen);
 
140
  manager->selection_atom = XInternAtom (display, buffer, False);
 
141
  manager->xsettings_atom = XInternAtom (display, "_XSETTINGS_SETTINGS", False);
 
142
  manager->manager_atom = XInternAtom (display, "MANAGER", False);
 
143
 
 
144
  manager->terminate = terminate;
 
145
  manager->cb_data = cb_data;
 
146
 
 
147
  manager->settings = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, (GDestroyNotify) xsettings_setting_free);
 
148
  manager->serial = 0;
 
149
  manager->overrides = NULL;
 
150
 
 
151
  manager->window = XCreateSimpleWindow (display,
 
152
                                         RootWindow (display, screen),
 
153
                                         0, 0, 10, 10, 0,
 
154
                                         WhitePixel (display, screen),
 
155
                                         WhitePixel (display, screen));
 
156
 
 
157
  XSelectInput (display, manager->window, PropertyChangeMask);
 
158
  timestamp = get_server_time (display, manager->window);
 
159
 
 
160
  XSetSelectionOwner (display, manager->selection_atom,
 
161
                      manager->window, timestamp);
 
162
 
 
163
  /* Check to see if we managed to claim the selection. If not,
 
164
   * we treat it as if we got it then immediately lost it
 
165
   */
 
166
 
 
167
  if (XGetSelectionOwner (display, manager->selection_atom) ==
 
168
      manager->window)
 
169
    {
 
170
      xev.type = ClientMessage;
 
171
      xev.window = RootWindow (display, screen);
 
172
      xev.message_type = manager->manager_atom;
 
173
      xev.format = 32;
 
174
      xev.data.l[0] = timestamp;
 
175
      xev.data.l[1] = manager->selection_atom;
 
176
      xev.data.l[2] = manager->window;
 
177
      xev.data.l[3] = 0;        /* manager specific data */
 
178
      xev.data.l[4] = 0;        /* manager specific data */
 
179
      
 
180
      XSendEvent (display, RootWindow (display, screen),
 
181
                  False, StructureNotifyMask, (XEvent *)&xev);
 
182
    }
 
183
  else
 
184
    {
 
185
      manager->terminate (manager->cb_data);
 
186
    }
 
187
  
 
188
  return manager;
 
189
}
 
190
 
 
191
void
 
192
xsettings_manager_destroy (XSettingsManager *manager)
 
193
{
 
194
  XDestroyWindow (manager->display, manager->window);
 
195
 
 
196
  g_hash_table_unref (manager->settings);
 
197
 
 
198
  g_slice_free (XSettingsManager, manager);
 
199
}
 
200
 
 
201
static void
 
202
xsettings_manager_set_setting (XSettingsManager *manager,
 
203
                               const gchar      *name,
 
204
                               gint              tier,
 
205
                               GVariant         *value)
 
206
{
 
207
  XSettingsSetting *setting;
 
208
 
 
209
  setting = g_hash_table_lookup (manager->settings, name);
 
210
 
 
211
  if (setting == NULL)
 
212
    {
 
213
      setting = xsettings_setting_new (name);
 
214
      setting->last_change_serial = manager->serial;
 
215
      g_hash_table_insert (manager->settings, setting->name, setting);
 
216
    }
 
217
 
 
218
  xsettings_setting_set (setting, tier, value, manager->serial);
 
219
 
 
220
  if (xsettings_setting_get (setting) == NULL)
 
221
    g_hash_table_remove (manager->settings, name);
 
222
}
 
223
 
 
224
void
 
225
xsettings_manager_set_int (XSettingsManager *manager,
 
226
                           const char       *name,
 
227
                           int               value)
 
228
{
 
229
  xsettings_manager_set_setting (manager, name, 0, g_variant_new_int32 (value));
 
230
}
 
231
 
 
232
void
 
233
xsettings_manager_set_string (XSettingsManager *manager,
 
234
                              const char       *name,
 
235
                              const char       *value)
 
236
{
 
237
  xsettings_manager_set_setting (manager, name, 0, g_variant_new_string (value));
 
238
}
 
239
 
 
240
void
 
241
xsettings_manager_set_color (XSettingsManager *manager,
 
242
                             const char       *name,
 
243
                             XSettingsColor   *value)
 
244
{
 
245
  GVariant *tmp;
 
246
 
 
247
  tmp = g_variant_new ("(qqqq)", value->red, value->green, value->blue, value->alpha);
 
248
  g_assert (g_variant_is_of_type (tmp, XSETTINGS_VARIANT_TYPE_COLOR)); /* paranoia... */
 
249
  xsettings_manager_set_setting (manager, name, 0, tmp);
 
250
}
 
251
 
 
252
void
 
253
xsettings_manager_delete_setting (XSettingsManager *manager,
 
254
                                  const char       *name)
 
255
{
 
256
  xsettings_manager_set_setting (manager, name, 0, NULL);
 
257
}
 
258
 
 
259
static gchar
 
260
xsettings_get_typecode (GVariant *value)
 
261
{
 
262
  switch (g_variant_classify (value))
 
263
    {
 
264
    case G_VARIANT_CLASS_INT32:
 
265
      return XSETTINGS_TYPE_INT;
 
266
    case G_VARIANT_CLASS_STRING:
 
267
      return XSETTINGS_TYPE_STRING;
 
268
    case G_VARIANT_CLASS_TUPLE:
 
269
      return XSETTINGS_TYPE_COLOR;
 
270
    default:
 
271
      g_assert_not_reached ();
 
272
    }
 
273
}
 
274
 
 
275
static void
 
276
align_string (GString *string,
 
277
              gint     alignment)
 
278
{
 
279
  /* Adds nul-bytes to the string until its length is an even multiple
 
280
   * of the specified alignment requirement.
 
281
   */
 
282
  while ((string->len % alignment) != 0)
 
283
    g_string_append_c (string, '\0');
 
284
}
 
285
 
 
286
static void
 
287
setting_store (XSettingsSetting *setting,
 
288
               GString          *buffer)
 
289
{
 
290
  XSettingsType type;
 
291
  GVariant *value;
 
292
  guint16 len16;
 
293
 
 
294
  value = xsettings_setting_get (setting);
 
295
 
 
296
  type = xsettings_get_typecode (value);
 
297
 
 
298
  g_string_append_c (buffer, type);
 
299
  g_string_append_c (buffer, 0);
 
300
 
 
301
  len16 = strlen (setting->name);
 
302
  g_string_append_len (buffer, (gchar *) &len16, 2);
 
303
  g_string_append (buffer, setting->name);
 
304
  align_string (buffer, 4);
 
305
 
 
306
  g_string_append_len (buffer, (gchar *) &setting->last_change_serial, 4);
 
307
 
 
308
  if (type == XSETTINGS_TYPE_STRING)
 
309
    {
 
310
      const gchar *string;
 
311
      gsize stringlen;
 
312
      guint32 len32;
 
313
 
 
314
      string = g_variant_get_string (value, &stringlen);
 
315
      len32 = stringlen;
 
316
      g_string_append_len (buffer, (gchar *) &len32, 4);
 
317
      g_string_append (buffer, string);
 
318
      align_string (buffer, 4);
 
319
    }
 
320
  else
 
321
    /* GVariant format is the same as XSETTINGS format for the non-string types */
 
322
    g_string_append_len (buffer, g_variant_get_data (value), g_variant_get_size (value));
 
323
}
 
324
 
 
325
void
 
326
xsettings_manager_notify (XSettingsManager *manager)
 
327
{
 
328
  GString *buffer;
 
329
  GHashTableIter iter;
 
330
  int n_settings;
 
331
  gpointer value;
 
332
 
 
333
  n_settings = g_hash_table_size (manager->settings);
 
334
 
 
335
  buffer = g_string_new (NULL);
 
336
  g_string_append_c (buffer, xsettings_byte_order ());
 
337
  g_string_append_c (buffer, '\0');
 
338
  g_string_append_c (buffer, '\0');
 
339
  g_string_append_c (buffer, '\0');
 
340
 
 
341
  g_string_append_len (buffer, (gchar *) &manager->serial, 4);
 
342
  g_string_append_len (buffer, (gchar *) &n_settings, 4);
 
343
 
 
344
  g_hash_table_iter_init (&iter, manager->settings);
 
345
  while (g_hash_table_iter_next (&iter, NULL, &value))
 
346
    setting_store (value, buffer);
 
347
 
 
348
  XChangeProperty (manager->display, manager->window,
 
349
                   manager->xsettings_atom, manager->xsettings_atom,
 
350
                   8, PropModeReplace, (guchar *) buffer->str, buffer->len);
 
351
 
 
352
  g_string_free (buffer, TRUE);
 
353
  manager->serial++;
 
354
}
 
355
 
 
356
void
 
357
xsettings_manager_set_overrides (XSettingsManager *manager,
 
358
                                 GVariant         *overrides)
 
359
{
 
360
  GVariantIter iter;
 
361
  const gchar *key;
 
362
  GVariant *value;
 
363
 
 
364
  g_return_if_fail (overrides != NULL && g_variant_is_of_type (overrides, G_VARIANT_TYPE_VARDICT));
 
365
 
 
366
  if (manager->overrides)
 
367
    {
 
368
      /* unset the existing overrides */
 
369
 
 
370
      g_variant_iter_init (&iter, manager->overrides);
 
371
      while (g_variant_iter_next (&iter, "{&sv}", &key, NULL))
 
372
        /* only unset it at this point if it's not in the new list */
 
373
        if (!g_variant_lookup (overrides, key, "*", NULL))
 
374
          xsettings_manager_set_setting (manager, key, 1, NULL);
 
375
      g_variant_unref (manager->overrides);
 
376
    }
 
377
 
 
378
  /* save this so we can do the unsets next time */
 
379
  manager->overrides = g_variant_ref_sink (overrides);
 
380
 
 
381
  /* set the new values */
 
382
  g_variant_iter_init (&iter, overrides);
 
383
  while (g_variant_iter_loop (&iter, "{&sv}", &key, &value))
 
384
    {
 
385
      /* only accept recognised types... */
 
386
      if (!g_variant_is_of_type (value, G_VARIANT_TYPE_STRING) &&
 
387
          !g_variant_is_of_type (value, G_VARIANT_TYPE_INT32) &&
 
388
          !g_variant_is_of_type (value, XSETTINGS_VARIANT_TYPE_COLOR))
 
389
        continue;
 
390
 
 
391
      xsettings_manager_set_setting (manager, key, 1, value);
 
392
    }
 
393
}