GIcon: add g_icon_[de]serialize()
[glib.git] / gio / gregistrysettingsbackend.c
blob1b4c119859fee5744854b9e614c833f458736ec8
1 /*
2 * Copyright © 2009-10 Sam Thursfield
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Author: Sam Thursfield <ssssam@gmail.com>
22 /* GRegistryBackend implementation notes:
24 * - All settings are stored under the path:
25 * HKEY_CURRENT_USER\Software\GSettings\
26 * This means all settings are per-user. Permissions and system-wide
27 * defaults are not implemented and will probably always be out of scope of
28 * the Windows port of GLib.
30 * - The registry type system is limited. Most GVariant types are stored as
31 * literals via g_variant_print/parse(). Strings are stored without the
32 * quotes that GVariant requires. Integer types are stored as native
33 * REG_DWORD or REG_QWORD. The REG_MULTI_SZ (string array) type could be
34 * used to avoid flattening container types.
36 * - Notifications are handled; the change event is watched for in a separate
37 * thread (Windows does not provide a callback API) which sends them with
38 * g_idle_add to the GLib main loop. The threading is done using Windows
39 * API functions, so there is no dependence on GThread.
41 * - Windows doesn't tell us which value has changed. This means we have to
42 * maintain a cache of every stored value so we can play spot the
43 * difference. This should not be a performance issue because if you are
44 * storing thousands of values in GSettings, you are probably using it
45 * wrong.
47 * - The cache stores the value as a registry type. Because many variants are
48 * stored as string representations, values which have changed equality but
49 * not equivalence may trigger spurious change notifications. GSettings
50 * users must already deal with this possibility and converting all data to
51 * GVariant values would be more effort.
53 * - Because we have to cache every registry value locally, reads are done
54 * from the cache rather than directly from the registry. Writes update
55 * both. This means that the backend will not work if the watch thread is
56 * not running. A GSettings object always subscribes to changes so we can
57 * be sure that the watch thread will be running, but if for some reason
58 * the backend is being used directly you should bear that in mind.
60 * - The registry is totally user-editable, so we are very forgiving about
61 * errors in the data we get.
63 * - The registry uses backslashes as path separators. GSettings keys only
64 * allow [A-Za-z\-] so no escaping is needed. No attempt is made to solve
65 * clashes between keys differing only in case.
67 * - RegCreateKeyA is used - Windows can also handle UTF16LE strings.
68 * GSettings doesn't pay any attention to encoding, so by using ANSI we
69 * hopefully avoid passing any invalid Unicode.
71 * - The Windows registry has the following limitations: a key may not exceed
72 * 255 characters, an entry's value may not exceed 16,383 characters, and
73 * all the values of a key may not exceed 65,535 characters.
75 * - Terminology:
76 * * in GSettings, a 'key' is eg. /desktop/gnome/background/primary-color
77 * * in the registry, the 'key' is path, which contains some 'values'.
78 * * in this file, any GSettings key is a 'key', while a registry key is
79 * termed a 'path', which contains 'values'.
81 * - My set of tests for this backend are currently at:
82 * http://gitorious.org/gsettings-gtk/gsettings-test.git
84 * - There is an undocumented function in ntdll.dll which might be more
85 * than RegNotifyChangeKeyValue(), NtNotifyChangeKey:
86 * http://source.winehq.org/source/dlls/ntdll/reg.c#L618
87 * http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Key/NtNotifyChangeKey.html
89 * - If updating the cache ever becomes a performance issue it may make sense
90 * to use a red-black tree, but I don't currently think it's worth the time
93 #include "config.h"
95 #include "gregistrysettingsbackend.h"
96 #include "gsimplepermission.h"
97 #include "gsettingsbackend.h"
98 #include "giomodule.h"
100 #include <windows.h>
102 //#define TRACE
104 /* GSettings' limit */
105 #define MAX_KEY_NAME_LENGTH 32
107 /* Testing (on Windows XP SP3) shows that WaitForMultipleObjects fails with
108 * "The parameter is incorrect" after 64 watches. We need one for the
109 * message_sent cond, which is allowed for in the way the watches_remaining
110 * variable is used.
112 #define MAX_WATCHES 64
114 /* A watch on one registry path and its subkeys */
115 typedef struct
117 HANDLE event;
118 HKEY hpath;
119 char *prefix;
120 GNode *cache_node;
121 } RegistryWatch;
124 /* Simple message passing for the watch thread. Not enough traffic to
125 * justify a queue.
127 typedef enum
129 WATCH_THREAD_NONE,
130 WATCH_THREAD_ADD_WATCH,
131 WATCH_THREAD_REMOVE_WATCH,
132 WATCH_THREAD_STOP
133 } WatchThreadMessageType;
135 typedef struct
137 WatchThreadMessageType type;
138 RegistryWatch watch;
139 } WatchThreadMessage;
142 typedef struct
144 GSettingsBackend *owner;
145 HANDLE *thread;
147 /* Details of the things we are watching. */
148 int watches_remaining;
149 GPtrArray *events, *handles, *prefixes, *cache_nodes;
151 /* Communication with the main thread. Only one message is stored at a time,
152 * to make sure that messages are acknowledged before being overwritten we
153 * create two events - one is signalled when a new message is set, the
154 * other is signalled by the thread when it has processed the message.
156 WatchThreadMessage message;
157 CRITICAL_SECTION *message_lock;
158 HANDLE message_sent_event, message_received_event;
159 } WatchThreadState;
162 #define G_TYPE_REGISTRY_BACKEND (g_registry_backend_get_type ())
163 #define G_REGISTRY_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
164 G_TYPE_REGISTRY_BACKEND, GRegistryBackend))
165 #define G_IS_REGISTRY_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
166 G_TYPE_REGISTRY_BACKEND))
169 typedef GSettingsBackendClass GRegistryBackendClass;
171 typedef struct {
172 GSettingsBackend parent_instance;
174 char *base_path;
176 /* A stored copy of the whole tree being watched. When we receive a change notification
177 * we have to check against this to see what has changed ... every time ...*/
178 CRITICAL_SECTION *cache_lock;
179 GNode *cache_root;
181 WatchThreadState *watch;
182 } GRegistryBackend;
184 G_DEFINE_TYPE_WITH_CODE (GRegistryBackend,
185 g_registry_backend,
186 G_TYPE_SETTINGS_BACKEND,
187 g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
188 g_define_type_id, "registry", 90))
191 /**********************************************************************************
192 * Utility functions
193 **********************************************************************************/
195 #include <stdio.h>
196 static void
197 trace (const char *format, ...)
199 #ifdef TRACE
200 va_list va; va_start (va, format);
201 vprintf (format, va); fflush (stdout);
202 va_end (va);
203 #endif
206 /* g_message including a windows error message. It is not useful to have an
207 * equivalent function for g_warning because none of the registry errors can
208 * result from programmer error (Microsoft programmers don't count), instead
209 * they will mostly occur from people messing with the registry by hand. */
210 static void
211 g_message_win32_error (DWORD result_code,
212 const gchar *format,
213 ...)
215 va_list va;
216 gint pos;
217 gchar win32_message[1024];
219 if (result_code == 0)
220 result_code = GetLastError ();
222 va_start (va, format);
223 pos = g_vsnprintf (win32_message, 512, format, va);
225 win32_message[pos++] = ':'; win32_message[pos++] = ' ';
227 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, result_code, 0, (LPTSTR)(win32_message+pos),
228 1023 - pos, NULL);
230 if (result_code == ERROR_KEY_DELETED)
231 trace ("(%s)", win32_message);
232 else
233 g_message (win32_message);
237 /* Make gsettings key into a registry path & value pair.
239 * Note that the return value *only* needs freeing - registry_value_name
240 * is a pointer to further inside the same block of memory.
242 static gchar *
243 parse_key (const gchar *key_name,
244 const gchar *registry_prefix,
245 gchar **value_name)
247 gchar *path_name, *c;
249 /* All key paths are treated as absolute; gsettings doesn't seem to enforce a
250 * preceding /.
252 if (key_name[0] == '/')
253 key_name ++;
255 if (registry_prefix == NULL)
256 path_name = g_strdup (key_name);
257 else
258 path_name = g_strjoin ("/", registry_prefix, key_name, NULL);
260 /* Prefix is expected to be in registry format (\ separators) so don't escape that. */
261 for (c=path_name+(registry_prefix?strlen(registry_prefix):0); *c!=0; c++)
262 if (*c == '/')
264 *c = '\\';
265 (*value_name) = c;
268 **value_name = 0; (*value_name)++;
269 return path_name;
273 static DWORD
274 g_variant_get_as_dword (GVariant *variant)
276 switch (g_variant_get_type_string (variant)[0])
278 case 'b': return g_variant_get_boolean (variant);
279 case 'y': return g_variant_get_byte (variant);
280 case 'n': return g_variant_get_int16 (variant);
281 case 'q': return g_variant_get_uint16 (variant);
282 case 'i': return g_variant_get_int32 (variant);
283 case 'u': return g_variant_get_uint32 (variant);
284 default: g_warn_if_reached ();
286 return 0;
289 static DWORDLONG
290 g_variant_get_as_qword (GVariant *variant)
292 switch (g_variant_get_type_string (variant)[0])
294 case 'x': return g_variant_get_int64 (variant);
295 case 't': return g_variant_get_uint64 (variant);
296 default: g_warn_if_reached ();
298 return 0;
302 static void
303 handle_read_error (LONG result,
304 const gchar *path_name,
305 const gchar *value_name)
307 /* file not found means key value not set, this isn't an error for us. */
308 if (result != ERROR_FILE_NOT_FOUND)
309 g_message_win32_error (result, "Unable to query value %s/%s: %s.\n",
310 path_name, value_name);
313 /***************************************************************************
314 * Cache of registry values
315 ***************************************************************************/
317 /* Generic container for registry values */
318 typedef struct {
319 DWORD type;
321 union {
322 gint dword; /* FIXME: could inline QWORD on 64-bit systems too */
323 void *ptr;
325 } RegistryValue;
327 static char *
328 registry_value_dump (RegistryValue value)
330 if (value.type == REG_DWORD)
331 return g_strdup_printf ("%i", value.dword);
332 else if (value.type == REG_QWORD)
333 return g_strdup_printf ("%I64i", value.ptr==NULL? 0: *(DWORDLONG *)value.ptr);
334 else if (value.type == REG_SZ)
335 return g_strdup_printf ("%s", (char *)value.ptr);
336 else if (value.type == REG_NONE)
337 return g_strdup_printf ("<empty>");
338 else
339 return g_strdup_printf ("<invalid>");
342 static void
343 registry_value_free (RegistryValue value)
345 if (value.type == REG_SZ || value.type == REG_QWORD)
346 g_free (value.ptr);
347 value.type = REG_NONE;
348 value.ptr = NULL;
352 /* The registry cache is stored as a tree, for easy traversal. Right now we
353 * don't sort it in a clever way. Each node corresponds to a path element
354 * ('key' in registry terms) or a value.
356 * Each subscription uses the same cache. Because GSettings can subscribe to
357 * the tree at any node any number of times, we need to reference count the
358 * nodes.
360 typedef struct
362 /* Component of path that this node represents */
363 gchar *name;
365 /* If a watch is subscribed at this point (subscription_count > 0) we can
366 * block its next notification. This is useful because if two watches cover
367 * the same path, both will trigger when it changes. It also allows changes
368 * done by the application to be ignored by the watch thread.
370 gint32 block_count : 8;
372 /* Number of times g_settings_subscribe has been called for this location
373 * (I guess you can't subscribe more than 16383 times) */
374 gint32 subscription_count : 14;
376 gint32 ref_count : 9;
378 gint32 touched : 1;
379 RegistryValue value;
380 } RegistryCacheItem;
384 static GNode *
385 registry_cache_add_item (GNode *parent,
386 gchar *name,
387 RegistryValue value,
388 gint ref_count)
390 RegistryCacheItem *item = g_slice_new (RegistryCacheItem);
391 GNode *cache_node;
393 g_return_val_if_fail (name != NULL, NULL);
394 g_return_val_if_fail (parent != NULL, NULL);
396 /* Ref count should be the number of watch points above this node */
397 item->ref_count = ref_count;
399 item->name = g_strdup (name);
400 item->value = value;
401 item->subscription_count = 0;
402 item->block_count = 0;
403 item->touched = FALSE;
404 trace ("\treg cache: adding %s to %s\n", name, ((RegistryCacheItem *)parent->data)->name);
406 cache_node = g_node_new (item);
407 g_node_append (parent, cache_node);
408 return cache_node;
411 /* The reference counting of cache tree nodes works like this: when a node is
412 * subscribed to (GSettings wants us to watch that path and everything below
413 * it) the reference count of that node and everything below is increased, as
414 * well as each parent up to the root.
418 static void
419 _ref_down (GNode *node)
421 RegistryCacheItem *item = node->data;
422 g_node_children_foreach (node, G_TRAVERSE_ALL,
423 (GNodeForeachFunc)_ref_down, NULL);
424 item->ref_count ++;
426 static void
427 registry_cache_ref_tree (GNode *tree)
429 RegistryCacheItem *item = tree->data;
430 GNode *node = tree->parent;
432 g_return_if_fail (tree != NULL);
434 item->ref_count ++;
436 g_node_children_foreach (tree, G_TRAVERSE_ALL,
437 (GNodeForeachFunc)_ref_down, NULL);
439 for (node=tree->parent; node; node=node->parent)
441 item = node->data;
442 item->ref_count ++;
446 static void
447 _free_cache_item (RegistryCacheItem *item)
449 trace ("\t -- Free node %s\n", item->name);
450 g_free (item->name);
451 registry_value_free (item->value);
452 g_slice_free (RegistryCacheItem, item);
455 /* Unreferencing has to be done bottom-up */
456 static void
457 _unref_node (GNode *node)
459 RegistryCacheItem *item = node->data;
461 item->ref_count --;
463 g_warn_if_fail (item->ref_count >= 0);
465 if (item->ref_count == 0)
467 _free_cache_item (item);
468 g_node_destroy (node);
472 static void
473 _unref_down (GNode *node)
475 g_node_children_foreach (node, G_TRAVERSE_ALL,
476 (GNodeForeachFunc)_unref_down, NULL);
477 _unref_node (node);
480 static void
481 registry_cache_unref_tree (GNode *tree)
483 GNode *parent = tree->parent, *next_parent;
485 _unref_down (tree);
487 while (parent)
489 next_parent = parent->parent;
490 _unref_node (parent);
491 parent = next_parent;
495 #if 0
496 static void
497 registry_cache_dump (GNode *cache_node,
498 gpointer data)
500 RegistryCacheItem *item = cache_node->data;
502 int depth = GPOINTER_TO_INT(data),
503 new_depth = depth+1,
506 g_return_if_fail (cache_node != NULL);
508 for (i=0; i<depth; i++)
509 g_print (" ");
510 if (item == NULL)
511 g_print ("*root*\n");
512 else
513 g_print ("'%s' [%i] @ %x = %s\n", item->name, item->ref_count, (guint)cache_node,
514 registry_value_dump (item->value));
515 g_node_children_foreach (cache_node, G_TRAVERSE_ALL, registry_cache_dump,
516 GINT_TO_POINTER (new_depth));
518 #endif
520 typedef struct
522 gchar *name;
523 GNode *result;
524 } RegistryCacheSearch;
526 static gboolean
527 registry_cache_find_compare (GNode *node,
528 gpointer data)
530 RegistryCacheSearch *search = data;
531 RegistryCacheItem *item = node->data;
533 if (item == NULL) /* root node */
534 return FALSE;
536 g_return_val_if_fail (search->name != NULL, FALSE);
537 g_return_val_if_fail (item->name != NULL, FALSE);
539 if (strcmp (search->name, item->name) == 0)
541 search->result = node;
542 return TRUE;
544 return FALSE;
547 static GNode *
548 registry_cache_find_immediate_child (GNode *node,
549 gchar *name)
551 RegistryCacheSearch search;
552 search.result = NULL;
553 search.name = name;
554 g_node_traverse (node, G_POST_ORDER, G_TRAVERSE_ALL, 2,
555 registry_cache_find_compare, &search);
556 return search.result;
560 static GNode *
561 registry_cache_get_node_for_key_recursive (GNode *node,
562 gchar *key_name,
563 gboolean create_if_not_found,
564 gint n_parent_watches)
566 RegistryCacheItem *item;
567 gchar *component = key_name,
568 *c = strchr (component, '/');
569 GNode *child;
571 if (c != NULL)
572 *c = 0;
574 /* We count up how many watch points we travel through finding this node,
575 * because a new node should have as many references as there are watches at
576 * points above it in the tree.
578 item = node->data;
579 if (item->subscription_count > 0)
580 n_parent_watches ++;
582 child = registry_cache_find_immediate_child (node, component);
583 if (child == NULL && create_if_not_found)
585 item = g_slice_new (RegistryCacheItem);
586 item->name = g_strdup (component);
587 item->value.type = REG_NONE;
588 item->value.ptr = NULL;
589 item->ref_count = n_parent_watches;
590 child = g_node_new (item);
591 g_node_append (node, child);
592 trace ("\tget node for key recursive: new %x = %s.\n", node, item->name);
595 /* We are done if there are no more path components. Allow for a trailing /. */
596 if (child==NULL || c == NULL || *(c+1)==0)
597 return child;
598 else
600 trace ("get node for key recursive: next: %s.\n", c+1);
601 return registry_cache_get_node_for_key_recursive
602 (child, c+1, create_if_not_found, n_parent_watches);
606 /* Look up a GSettings key in the cache. */
607 static GNode *
608 registry_cache_get_node_for_key (GNode *root,
609 const gchar *key_name,
610 gboolean create_if_not_found)
612 GNode *child = NULL,
613 *result = NULL;
614 gchar *component, *c;
616 g_return_val_if_fail (key_name != NULL, NULL);
618 if (key_name[0] == '/')
619 key_name ++;
621 /* Ignore preceding / */
622 component = g_strdup (key_name);
623 c = strchr (component, '/');
624 if (c != NULL)
625 *c = 0;
627 child = registry_cache_find_immediate_child (root, component);
628 if (child == NULL && create_if_not_found)
630 /* Reference count is set to 0, tree should be referenced by the caller */
631 RegistryCacheItem *item = g_slice_new (RegistryCacheItem);
632 item->value.type = REG_NONE;
633 item->value.ptr = NULL;
634 item->name = g_strdup (component);
635 item->ref_count = 0;
636 trace ("get_node_for_key: New node for component '%s'\n", item->name);
637 child = g_node_new (item);
638 g_node_append (root, child);
641 if (c == NULL)
642 result = root;
643 else if (*(c+1)==0)
644 result = child;
645 else if (child != NULL)
646 result = registry_cache_get_node_for_key_recursive (child, c+1, create_if_not_found, 0);
648 g_free (component);
650 return result;
653 /* Check the cache node against the registry key it represents. Return TRUE if
654 * they differ, and update the cache with the new value.
656 static gboolean
657 registry_cache_update_node (GNode *cache_node,
658 RegistryValue registry_value)
660 RegistryCacheItem *cache_item = cache_node->data;
662 g_return_val_if_fail (cache_node != NULL, FALSE);
663 g_return_val_if_fail (cache_item != NULL, FALSE);
665 if (registry_value.type != cache_item->value.type)
667 /* The type has changed. Update cache item and register it as changed.
668 * Either the schema has changed and this is entirely legitimate, or
669 * whenever the app reads the key it will get the default value due to
670 * the type mismatch.
672 cache_item->value = registry_value;
673 return TRUE;
676 switch (registry_value.type)
678 case REG_DWORD:
680 if (cache_item->value.dword == registry_value.dword)
681 return FALSE;
682 else
684 cache_item->value.dword = registry_value.dword;
685 return TRUE;
688 case REG_QWORD:
690 g_return_val_if_fail (registry_value.ptr != NULL &&
691 cache_item->value.ptr != NULL, FALSE);
693 if (memcmp (registry_value.ptr, cache_item->value.ptr, 8)==0)
695 g_free (registry_value.ptr);
696 return FALSE;
698 else
700 g_free (cache_item->value.ptr);
701 cache_item->value.ptr = registry_value.ptr;
702 return TRUE;
705 case REG_SZ:
707 /* Value should not exist if it is NULL, an empty string is "" */
708 g_return_val_if_fail (cache_item->value.ptr != NULL, FALSE);
709 g_return_val_if_fail (registry_value.ptr != NULL, FALSE);
711 if (strcmp (registry_value.ptr, cache_item->value.ptr) == 0)
713 g_free (registry_value.ptr);
714 return FALSE;
716 else
718 g_free (cache_item->value.ptr);
719 cache_item->value.ptr = registry_value.ptr;
720 return TRUE;
723 default:
724 g_warning ("gregistrybackend: registry_cache_update_node: Unhandled value type :(");
725 return FALSE;
729 /* Blocking notifications is a useful optimisation. When a change is made
730 * through GSettings we update the cache manually, but a notifcation is
731 * triggered as well. This function is also used for nested notifications,
732 * eg. if /test and /test/foo are watched, and /test/foo/value is changed then
733 * we will get notified both for /test/foo and /test and it is helpful to block
734 * the second.
736 static void
737 registry_cache_block_notification (GNode *node)
739 RegistryCacheItem *item = node->data;
741 g_return_if_fail (node != NULL);
743 if (item->subscription_count > 0)
744 item->block_count ++;
746 if (node->parent != NULL)
747 registry_cache_block_notification (node->parent);
750 static void
751 registry_cache_destroy_tree (GNode *node,
752 WatchThreadState *self);
754 /***************************************************************************
755 * Reading and writing
756 ***************************************************************************/
758 static gboolean
759 registry_read (HKEY hpath,
760 const gchar *path_name,
761 const gchar *value_name,
762 RegistryValue *p_value)
764 LONG result;
765 DWORD value_data_size;
766 gpointer *buffer;
768 g_return_val_if_fail (p_value != NULL, FALSE);
770 p_value->type = REG_NONE;
771 p_value->ptr = NULL;
773 result = RegQueryValueExA (hpath, value_name, 0, &p_value->type, NULL, &value_data_size);
774 if (result != ERROR_SUCCESS)
776 handle_read_error (result, path_name, value_name);
777 return FALSE;
780 if (p_value->type == REG_SZ && value_data_size == 0)
782 p_value->ptr = g_strdup ("");
783 return TRUE;
786 if (p_value->type == REG_DWORD)
787 /* REG_DWORD is inlined */
788 buffer = (void *)&p_value->dword;
789 else
790 buffer = p_value->ptr = g_malloc (value_data_size);
792 result = RegQueryValueExA (hpath, value_name, 0, NULL, (LPBYTE)buffer, &value_data_size);
793 if (result != ERROR_SUCCESS)
795 handle_read_error (result, path_name, value_name);
796 return FALSE;
799 return TRUE;
803 static GVariant *
804 g_registry_backend_read (GSettingsBackend *backend,
805 const gchar *key_name,
806 const GVariantType *expected_type,
807 gboolean default_value)
809 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
811 GNode *cache_node;
812 RegistryValue registry_value;
813 GVariant *gsettings_value = NULL;
814 gchar *gsettings_type;
816 g_return_val_if_fail (expected_type != NULL, NULL);
818 if (default_value)
819 return NULL;
821 /* Simply read from the cache, which is updated from the registry by the
822 * watch thread as soon as changes can propagate. Any changes not yet in the
823 * cache will have the 'changed' signal emitted after this function returns.
825 EnterCriticalSection (self->cache_lock);
826 cache_node = registry_cache_get_node_for_key (self->cache_root, key_name, FALSE);
827 LeaveCriticalSection (self->cache_lock);
829 trace ("Reading key %s, cache node %x\n", key_name, cache_node);
831 /* Maybe it's not set, we can return to default */
832 if (cache_node == NULL)
833 return NULL;
835 trace ("\t- cached value %s\n", registry_value_dump (((RegistryCacheItem *)cache_node->data)->value));
837 registry_value = ((RegistryCacheItem *)cache_node->data)->value;
839 gsettings_type = g_variant_type_dup_string (expected_type);
841 /* The registry is user-editable, so we need to be fault-tolerant here. */
842 switch (gsettings_type[0])
844 case 'b': case 'y': case 'n': case 'q': case 'i': case 'u':
845 if (registry_value.type == REG_DWORD)
846 gsettings_value = g_variant_new (gsettings_type, registry_value.dword);
847 break;
849 case 't': case 'x':
850 if (registry_value.type == REG_QWORD)
852 DWORDLONG qword_value = *(DWORDLONG *)registry_value.ptr;
853 gsettings_value = g_variant_new (gsettings_type, qword_value);
855 break;
857 default:
858 if (registry_value.type == REG_SZ)
860 if (gsettings_type[0]=='s')
861 gsettings_value = g_variant_new_string ((char *)registry_value.ptr);
862 else
864 GError *error = NULL;
865 gsettings_value = g_variant_parse (expected_type, registry_value.ptr, NULL, NULL, &error);
867 if (error != NULL)
868 g_message ("gregistrysettingsbackend: error parsing key %s: %s\n",
869 key_name, error->message);
872 break;
875 g_free (gsettings_type);
877 return gsettings_value;
881 typedef struct
883 GRegistryBackend *self;
884 HKEY hroot;
885 } RegistryWrite;
887 static gboolean
888 g_registry_backend_write_one (const char *key_name,
889 GVariant *variant,
890 gpointer user_data)
892 GRegistryBackend *self;
893 RegistryWrite *action;
894 RegistryValue value;
896 HKEY hroot, hpath;
897 gchar *path_name, *value_name = NULL;
898 DWORD value_data_size;
899 LPVOID value_data;
900 LONG result;
902 GNode *node;
903 gboolean changed;
905 const gchar *type_string = g_variant_get_type_string (variant);
907 action = user_data;
908 self = G_REGISTRY_BACKEND (action->self);
909 hroot = action->hroot;
911 value.type = REG_NONE;
912 value.ptr = NULL;
914 switch (type_string[0])
916 case 'b': case 'y': case 'n': case 'q': case 'i': case 'u':
917 value.type = REG_DWORD;
918 value.dword = g_variant_get_as_dword (variant);
919 value_data_size = 4;
920 value_data = &value.dword;
921 break;
923 case 'x': case 't':
924 value.type = REG_QWORD;
925 value.ptr = g_malloc (8);
926 *(DWORDLONG *)value.ptr = g_variant_get_as_qword (variant);
927 value_data_size = 8;
928 value_data = value.ptr;
929 break;
931 default:
932 value.type = REG_SZ;
933 if (type_string[0]=='s')
935 gsize length;
936 value.ptr = g_strdup (g_variant_get_string (variant, &length));
937 value_data_size = length + 1;
938 value_data = value.ptr;
940 else
942 GString *value_string;
943 value_string = g_variant_print_string (variant, NULL, FALSE);
944 value_data_size = value_string->len+1;
945 value.ptr = value_data = g_string_free (value_string, FALSE);
947 break;
950 /* First update the cache, because the value may not have changed and we can
951 * save a write.
953 * If 'value' has changed then its memory will not be freed by update_node(),
954 * because it will be stored in the node.
956 EnterCriticalSection (self->cache_lock);
957 node = registry_cache_get_node_for_key (self->cache_root, key_name, TRUE);
958 changed = registry_cache_update_node (node, value);
959 LeaveCriticalSection (self->cache_lock);
961 if (!changed)
962 return FALSE;
964 /* Block the next notification to any watch points above this location,
965 * because they will each get triggered on a change that is already updated
966 * in the cache.
968 registry_cache_block_notification (node);
970 path_name = parse_key (key_name, NULL, &value_name);
972 trace ("Set key: %s / %s\n", path_name, value_name);
974 /* Store the value in the registry */
975 result = RegCreateKeyExA (hroot, path_name, 0, NULL, 0, KEY_WRITE, NULL, &hpath, NULL);
976 if (result != ERROR_SUCCESS)
978 g_message_win32_error (result, "gregistrybackend: opening key %s failed", path_name+1);
979 registry_value_free (value);
980 g_free (path_name);
981 return FALSE;
984 result = RegSetValueExA (hpath, value_name, 0, value.type, value_data, value_data_size);
985 if (result != ERROR_SUCCESS)
986 g_message_win32_error (result, "gregistrybackend: setting value %s\\%s\\%s failed.\n",
987 self->base_path, path_name, value_name);
989 /* If the write fails then it will seem like the value has changed until the
990 * next execution (because we wrote to the cache first). There's no reason
991 * for it to fail unless something is weirdly broken, however.
994 RegCloseKey (hpath);
995 g_free (path_name);
997 return FALSE;
1000 /* The dconf write policy is to do the write while making out it succeeded,
1001 * and then backtrack if it didn't. The registry functions are synchronous so
1002 * we can't do that. */
1004 static gboolean
1005 g_registry_backend_write (GSettingsBackend *backend,
1006 const gchar *key_name,
1007 GVariant *value,
1008 gpointer origin_tag)
1010 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
1011 LONG result;
1012 HKEY hroot;
1013 RegistryWrite action;
1015 result = RegCreateKeyExA (HKEY_CURRENT_USER, self->base_path, 0, NULL, 0,
1016 KEY_WRITE, NULL, &hroot, NULL);
1017 if (result != ERROR_SUCCESS) {
1018 trace ("Error opening/creating key %s.\n", self->base_path);
1019 return FALSE;
1022 action.self = self;
1023 action.hroot = hroot;
1024 g_registry_backend_write_one (key_name, value, &action);
1025 g_settings_backend_changed (backend, key_name, origin_tag);
1027 RegCloseKey (hroot);
1029 return TRUE;
1032 static gboolean
1033 g_registry_backend_write_tree (GSettingsBackend *backend,
1034 GTree *values,
1035 gpointer origin_tag)
1037 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
1038 LONG result;
1039 HKEY hroot;
1040 RegistryWrite action;
1042 result = RegCreateKeyExA (HKEY_CURRENT_USER, self->base_path, 0, NULL, 0,
1043 KEY_WRITE, NULL, &hroot, NULL);
1044 if (result != ERROR_SUCCESS) {
1045 trace ("Error opening/creating key %s.\n", self->base_path);
1046 return FALSE;
1049 action.self = self;
1050 action.hroot = hroot;
1051 g_tree_foreach (values, (GTraverseFunc)g_registry_backend_write_one,
1052 &action);
1054 g_settings_backend_changed_tree (backend, values, origin_tag);
1055 RegCloseKey (hroot);
1057 return TRUE;
1060 static void
1061 g_registry_backend_reset (GSettingsBackend *backend,
1062 const gchar *key_name,
1063 gpointer origin_tag)
1065 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
1066 gchar *path_name, *value_name = NULL;
1067 GNode *cache_node;
1068 LONG result;
1069 HKEY hpath;
1071 /* Remove from cache */
1072 EnterCriticalSection (self->cache_lock);
1073 cache_node = registry_cache_get_node_for_key (self->cache_root, key_name, FALSE);
1074 if (cache_node)
1075 registry_cache_destroy_tree (cache_node, self->watch);
1076 LeaveCriticalSection (self->cache_lock);
1078 /* Remove from the registry */
1079 path_name = parse_key (key_name, self->base_path, &value_name);
1081 result = RegOpenKeyExA (HKEY_CURRENT_USER, path_name, 0, KEY_SET_VALUE, &hpath);
1082 if (result != ERROR_SUCCESS)
1084 g_message_win32_error (result, "Registry: resetting key '%s'", path_name);
1085 g_free (path_name);
1086 return;
1089 result = RegDeleteValueA (hpath, value_name);
1090 RegCloseKey (hpath);
1092 if (result != ERROR_SUCCESS)
1094 g_message_win32_error (result, "Registry: resetting key '%s'", path_name);
1095 g_free (path_name);
1096 return;
1099 g_free (path_name);
1102 g_settings_backend_changed (backend, key_name, origin_tag);
1105 /* Not implemented and probably beyond the scope of this backend */
1106 static gboolean
1107 g_registry_backend_get_writable (GSettingsBackend *backend,
1108 const gchar *key_name)
1110 return TRUE;
1113 static GPermission *
1114 g_registry_backend_get_permission (GSettingsBackend *backend,
1115 const gchar *key_name)
1117 return g_simple_permission_new (TRUE);
1121 /********************************************************************************
1122 * Spot-the-difference engine
1123 ********************************************************************************/
1125 static void
1126 _free_watch (WatchThreadState *self,
1127 gint index,
1128 GNode *cache_node);
1130 static void
1131 registry_cache_item_reset_touched (GNode *node,
1132 gpointer data)
1134 RegistryCacheItem *item = node->data;
1135 item->touched = FALSE;
1138 /* Delete a node and any children, for when it has been deleted from the registry */
1139 static void
1140 registry_cache_destroy_tree (GNode *node,
1141 WatchThreadState *self)
1143 RegistryCacheItem *item = node->data;
1145 g_node_children_foreach (node, G_TRAVERSE_ALL,
1146 (GNodeForeachFunc)registry_cache_destroy_tree, self);
1148 if (item->subscription_count > 0)
1150 gint i;
1151 /* There must be some watches active if this node is a watch point */
1152 g_warn_if_fail (self->cache_nodes->len > 1);
1154 /* This is a watch point that has been deleted. Let's free the watch! */
1155 for (i=1; i<self->cache_nodes->len; i++)
1156 if (g_ptr_array_index (self->cache_nodes, i) == node)
1157 break;
1158 if (i >= self->cache_nodes->len)
1159 g_warning ("watch thread: a watch point was deleted, but unable to "
1160 "find '%s' in the list of %i watch nodes\n", item->name,
1161 self->cache_nodes->len-1);
1162 else
1164 _free_watch (self, i, node);
1165 g_atomic_int_inc (&self->watches_remaining);
1168 _free_cache_item (node->data);
1169 g_node_destroy (node);
1172 static void
1173 registry_cache_remove_deleted (GNode *node,
1174 gpointer data)
1176 RegistryCacheItem *item = node->data;
1178 if (!item->touched)
1179 registry_cache_destroy_tree (node, data);
1182 /* Update cache from registry, and optionally report on the changes.
1184 * This function is sometimes called from the watch thread, with no locking. It
1185 * does call g_registry_backend functions, but this is okay because they only
1186 * access self->base which is constant.
1188 * When looking at this code bear in mind the terminology: in the registry, keys
1189 * are containers that contain values, and other keys. Keys have a 'default'
1190 * value which we always ignore.
1192 * n_parent_watches: a counter used to set the reference count of any new nodes
1193 * that are created - they should have as many references as
1194 * there are notifications that are watching them.
1196 static void
1197 registry_cache_update (GRegistryBackend *self,
1198 HKEY hpath,
1199 const gchar *prefix,
1200 const gchar *partial_key_name,
1201 GNode *cache_node,
1202 int n_watches,
1203 GPtrArray *changes)
1205 gchar buffer[MAX_KEY_NAME_LENGTH + 1];
1206 gchar *key_name;
1207 gint i;
1208 LONG result;
1210 RegistryCacheItem *item = cache_node->data;
1212 if (item->subscription_count > 0)
1213 n_watches ++;
1215 /* prefix is the level that all changes occur below; partial_key_name should
1216 * be NULL on the first call to this function */
1217 key_name = g_build_path ("/", prefix, partial_key_name, NULL);
1219 trace ("registry cache update: %s. Node %x has %i children\n", key_name,
1220 cache_node, g_node_n_children (cache_node));
1222 /* Start by zeroing 'touched' flag. When the registry traversal is done, any untouched nodes
1223 * must have been deleted from the registry.
1225 g_node_children_foreach (cache_node, G_TRAVERSE_ALL,
1226 registry_cache_item_reset_touched, NULL);
1228 /* Recurse into each subpath at the current level, if any */
1229 i = 0;
1230 while (1)
1232 DWORD buffer_size = MAX_KEY_NAME_LENGTH;
1233 HKEY hsubpath;
1235 result = RegEnumKeyEx (hpath, i++, buffer, &buffer_size, NULL, NULL, NULL, NULL);
1236 if (result != ERROR_SUCCESS)
1237 break;
1239 result = RegOpenKeyEx (hpath, buffer, 0, KEY_READ, &hsubpath);
1240 if (result == ERROR_SUCCESS)
1242 GNode *subkey_node;
1243 RegistryCacheItem *child_item;
1245 subkey_node = registry_cache_find_immediate_child (cache_node, buffer);
1246 if (subkey_node == NULL)
1248 RegistryValue null_value = {REG_NONE, {0}};
1249 subkey_node = registry_cache_add_item (cache_node, buffer,
1250 null_value, n_watches);
1254 registry_cache_update (self, hsubpath, prefix, buffer, subkey_node,
1255 n_watches, changes);
1256 child_item = subkey_node->data;
1257 child_item->touched = TRUE;
1259 RegCloseKey (hsubpath);
1262 if (result != ERROR_NO_MORE_ITEMS)
1263 g_message_win32_error (result, "gregistrybackend: error enumerating subkeys for cache.");
1265 /* Enumerate each value at 'path' and check if it has changed */
1266 i = 0;
1267 while (1)
1269 DWORD buffer_size = MAX_KEY_NAME_LENGTH;
1270 GNode *cache_child_node;
1271 RegistryCacheItem *child_item;
1272 RegistryValue value;
1273 gboolean changed = FALSE;
1275 result = RegEnumValue (hpath, i++, buffer, &buffer_size, NULL, NULL, NULL, NULL);
1276 if (result != ERROR_SUCCESS)
1277 break;
1279 if (buffer[0]==0)
1280 /* This is the key's 'default' value, for which we have no use. */
1281 continue;
1283 cache_child_node = registry_cache_find_immediate_child (cache_node, buffer);
1285 if (!registry_read (hpath, key_name, buffer, &value))
1286 continue;
1288 trace ("\tgot value %s for %s, node %x\n", registry_value_dump (value), buffer, cache_child_node);
1290 if (cache_child_node == NULL)
1292 /* This is a new value */
1293 cache_child_node = registry_cache_add_item (cache_node, buffer, value,
1294 n_watches);
1295 changed = TRUE;
1297 else
1299 /* For efficiency, instead of converting every value back to a GVariant to
1300 * compare it, we compare them as registry values (integers, or string
1301 * representations of the variant). The spurious change notifications that may
1302 * result should not be a big issue.
1304 * Note that 'value' is swallowed or freed.
1306 changed = registry_cache_update_node (cache_child_node, value);
1309 child_item = cache_child_node->data;
1310 child_item->touched = TRUE;
1311 if (changed == TRUE && changes != NULL)
1313 gchar *item;
1314 if (partial_key_name == NULL)
1315 item = g_strdup (buffer);
1316 else
1317 item = g_build_path ("/", partial_key_name, buffer, NULL);
1318 g_ptr_array_add (changes, item);
1322 if (result != ERROR_NO_MORE_ITEMS)
1323 g_message_win32_error (result, "gregistrybackend: error enumerating values for cache");
1325 /* Any nodes now left untouched must have been deleted, remove them from cache */
1326 g_node_children_foreach (cache_node, G_TRAVERSE_ALL,
1327 registry_cache_remove_deleted, self->watch);
1329 trace ("registry cache update complete.\n");
1330 g_free (key_name);
1335 /***********************************************************************************
1336 * Thread to watch for registry change events
1337 ***********************************************************************************/
1339 /* Called by watch thread. Apply for notifications on a registry key and its subkeys. */
1340 static DWORD
1341 registry_watch_key (HKEY hpath, HANDLE event)
1343 return RegNotifyChangeKeyValue (hpath, TRUE,
1344 REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
1345 event, TRUE);
1349 /* One of these is sent down the pipe when something happens in the registry. */
1350 typedef struct
1352 GRegistryBackend *self;
1353 gchar *prefix; /* prefix is a gsettings path, all items are subkeys of this. */
1354 GPtrArray *items; /* each item is a subkey below prefix that has changed. */
1355 } RegistryEvent;
1357 /* This handler runs in the main thread to emit the changed signals */
1358 static gboolean
1359 watch_handler (RegistryEvent *event)
1361 gint i;
1362 trace ("Watch handler: got event in %s, items %i.\n", event->prefix, event->items->len);
1364 /* GSettings requires us to NULL-terminate the array. */
1365 g_ptr_array_add (event->items, NULL);
1366 g_settings_backend_keys_changed (G_SETTINGS_BACKEND (event->self), event->prefix,
1367 (gchar const **)event->items->pdata, NULL);
1369 for (i=0; i<event->items->len; i++)
1370 g_free (g_ptr_array_index (event->items, i));
1371 g_ptr_array_free (event->items, TRUE);
1373 g_free (event->prefix);
1374 g_object_unref (event->self);
1376 g_slice_free (RegistryEvent, event);
1377 return G_SOURCE_REMOVE;
1381 static void
1382 _free_watch (WatchThreadState *self,
1383 gint index,
1384 GNode *cache_node)
1386 HKEY hpath;
1387 HANDLE cond;
1388 gchar *prefix;
1390 g_return_if_fail (index > 0 && index < self->events->len);
1392 cond = g_ptr_array_index (self->events, index);
1393 hpath = g_ptr_array_index (self->handles, index);
1394 prefix = g_ptr_array_index (self->prefixes, index);
1396 trace ("Freeing watch %i [%s]\n", index, prefix);
1398 /* These can be NULL if the watch was already dead, this can happen when eg.
1399 * a key is deleted but GSettings is still subscribed to it - the watch is
1400 * kept alive so that the unsubscribe function works properly, but does not
1401 * do anything.
1403 if (hpath != NULL)
1404 RegCloseKey (hpath);
1406 if (cache_node != NULL)
1408 //registry_cache_dump (G_REGISTRY_BACKEND (self->owner)->cache_root, NULL);
1409 registry_cache_unref_tree (cache_node);
1412 CloseHandle (cond);
1413 g_free (prefix);
1415 /* As long as we remove from each array at the same time, it doesn't matter that
1416 * their orders get messed up - they all get messed up the same.
1418 g_ptr_array_remove_index_fast (self->handles, index);
1419 g_ptr_array_remove_index_fast (self->events, index);
1420 g_ptr_array_remove_index_fast (self->prefixes, index);
1421 g_ptr_array_remove_index_fast (self->cache_nodes, index);
1424 static void
1425 watch_thread_handle_message (WatchThreadState *self)
1427 switch (self->message.type)
1429 case WATCH_THREAD_NONE:
1430 trace ("watch thread: you woke me up for nothin', man!");
1431 break;
1433 case WATCH_THREAD_ADD_WATCH:
1435 RegistryWatch *watch = &self->message.watch;
1436 LONG result;
1437 result = registry_watch_key (watch->hpath, watch->event);
1438 if (result == ERROR_SUCCESS)
1440 g_ptr_array_add (self->events, watch->event);
1441 g_ptr_array_add (self->handles, watch->hpath);
1442 g_ptr_array_add (self->prefixes, watch->prefix);
1443 g_ptr_array_add (self->cache_nodes, watch->cache_node);
1444 trace ("watch thread: new watch on %s, %i total\n", watch->prefix,
1445 self->events->len);
1447 else
1449 g_message_win32_error (result, "watch thread: could not watch %s", watch->prefix);
1450 CloseHandle (watch->event);
1451 RegCloseKey (watch->hpath);
1452 g_free (watch->prefix);
1453 registry_cache_unref_tree (watch->cache_node);
1455 break;
1458 case WATCH_THREAD_REMOVE_WATCH:
1460 GNode *cache_node;
1461 RegistryCacheItem *cache_item;
1462 gint i;
1464 for (i=1; i<self->prefixes->len; i++)
1465 if (strcmp (g_ptr_array_index (self->prefixes, i),
1466 self->message.watch.prefix) == 0)
1467 break;
1469 if (i >= self->prefixes->len)
1471 /* Don't make a fuss if the prefix is not being watched because
1472 * maybe the path was deleted so we removed the watch.
1474 trace ("unsubscribe: prefix %s is not being watched [%i things are]!\n",
1475 self->message.watch.prefix, self->prefixes->len);
1476 g_free (self->message.watch.prefix);
1477 break;
1480 cache_node = g_ptr_array_index (self->cache_nodes, i);
1482 trace ("watch thread: unsubscribe: freeing node %x, prefix %s, index %i\n",
1483 (guint)cache_node, self->message.watch.prefix, i);
1484 if (cache_node != NULL)
1486 cache_item = cache_node->data;
1488 /* There may be more than one GSettings object subscribed to this
1489 * path, only free the watch when the last one unsubscribes.
1491 cache_item->subscription_count --;
1492 if (cache_item->subscription_count > 0)
1493 break;
1496 _free_watch (self, i, cache_node);
1497 g_free (self->message.watch.prefix);
1499 g_atomic_int_inc (&self->watches_remaining);
1500 break;
1503 case WATCH_THREAD_STOP:
1505 gint i;
1507 /* Free any remaining cache and watch handles */
1508 for (i=1; i<self->events->len; i++)
1509 _free_watch (self, i, g_ptr_array_index (self->cache_nodes, i));
1511 SetEvent (self->message_received_event);
1512 ExitThread (0);
1516 self->message.type = WATCH_THREAD_NONE;
1517 SetEvent (self->message_received_event);
1521 /* Thread which watches for win32 registry events */
1522 static DWORD WINAPI
1523 watch_thread_function (LPVOID parameter)
1525 WatchThreadState *self = (WatchThreadState *)parameter;
1526 DWORD result;
1528 self->events = g_ptr_array_new ();
1529 self->handles = g_ptr_array_new ();
1530 self->prefixes = g_ptr_array_new ();
1531 self->cache_nodes = g_ptr_array_new ();
1532 g_ptr_array_add (self->events, self->message_sent_event);
1533 g_ptr_array_add (self->handles, NULL);
1534 g_ptr_array_add (self->prefixes, NULL);
1535 g_ptr_array_add (self->cache_nodes, NULL);
1537 while (1)
1539 trace ("watch thread: going to sleep; %i events watched.\n", self->events->len);
1540 result = WaitForMultipleObjects (self->events->len, self->events->pdata, FALSE, INFINITE);
1542 if (result == WAIT_OBJECT_0)
1544 /* A message to you. The sender (main thread) will block until we signal the received
1545 * event, so there should be no danger of it sending another before we receive the
1546 * first.
1548 watch_thread_handle_message (self);
1550 else if (result > WAIT_OBJECT_0 && result <= WAIT_OBJECT_0 + self->events->len)
1552 HKEY hpath;
1553 HANDLE cond;
1554 gchar *prefix;
1555 GNode *cache_node;
1556 RegistryCacheItem *cache_item;
1557 RegistryEvent *event;
1559 /* One of our notifications has triggered. All we know is which one, and which key
1560 * this is for. We do most of the processing here, because we may as well. If the
1561 * registry changes further while we are processing it doesn't matter - we will then
1562 * receive another change notification from the OS anyway.
1564 gint notify_index = result - WAIT_OBJECT_0;
1565 hpath = g_ptr_array_index (self->handles, notify_index);
1566 cond = g_ptr_array_index (self->events, notify_index);
1567 prefix = g_ptr_array_index (self->prefixes, notify_index);
1568 cache_node = g_ptr_array_index (self->cache_nodes, notify_index);
1570 trace ("Watch thread: notify received on prefix %i: %s.\n", notify_index, prefix);
1572 if (cache_node == NULL)
1574 /* This path has been deleted */
1575 trace ("Notify received on a path that was deleted :(\n");
1576 continue;
1579 /* Firstly we need to reapply for the notification, because (what a
1580 * sensible API) we won't receive any more. MSDN is pretty
1581 * inconsistent on this matter:
1582 * http://msdn.microsoft.com/en-us/library/ms724892%28VS.85%29.aspx
1583 * http://support.microsoft.com/kb/236570
1584 * But my tests (on Windows XP SP3) show that we need to reapply
1585 * each time.
1587 result = registry_watch_key (hpath, cond);
1589 if (result != ERROR_SUCCESS)
1591 /* Watch failed, most likely because the key has just been
1592 * deleted. Free the watch and unref the cache nodes.
1594 if (result != ERROR_KEY_DELETED)
1595 g_message_win32_error (result, "watch thread: failed to watch %s", prefix);
1596 _free_watch (self, notify_index, cache_node);
1597 g_atomic_int_inc (&self->watches_remaining);
1598 continue;
1601 /* The notification may have been blocked because we just changed
1602 * some data ourselves.
1604 cache_item = cache_node->data;
1605 if (cache_item->block_count)
1607 cache_item->block_count --;
1608 trace ("Watch thread: notify blocked at %s\n", prefix);
1609 continue;
1612 /* Now we update our stored cache from registry data, and find which keys have
1613 * actually changed. If more changes happen while we are processing, we will get
1614 * another event because we have reapplied for change notifications already.
1616 * Working here rather than in the main thread is preferable because the UI is less
1617 * likely to block (only when changing notification subscriptions).
1619 event = g_slice_new (RegistryEvent);
1621 event->self = G_REGISTRY_BACKEND (self->owner);
1622 g_object_ref (self->owner);
1624 event->items = g_ptr_array_new ();
1626 EnterCriticalSection (G_REGISTRY_BACKEND (self->owner)->cache_lock);
1627 registry_cache_update (G_REGISTRY_BACKEND (self->owner), hpath,
1628 prefix, NULL, cache_node, 0, event->items);
1629 LeaveCriticalSection (G_REGISTRY_BACKEND (self->owner)->cache_lock);
1631 if (event->items->len > 0)
1633 event->prefix = g_strdup (prefix);
1634 g_idle_add ((GSourceFunc) watch_handler, event);
1636 else
1638 g_ptr_array_free (event->items, TRUE);
1639 g_slice_free (RegistryEvent, event);
1642 else
1644 /* God knows what has happened */
1645 g_message_win32_error (GetLastError(), "watch thread: WaitForMultipleObjects error");
1649 return -1;
1652 static gboolean
1653 watch_start (GRegistryBackend *self)
1655 WatchThreadState *watch;
1657 g_return_val_if_fail (self->watch == NULL, FALSE);
1659 self->cache_lock = g_slice_new (CRITICAL_SECTION);
1660 InitializeCriticalSection (self->cache_lock);
1662 watch = g_slice_new (WatchThreadState);
1663 watch->owner = G_SETTINGS_BACKEND (self);
1665 watch->watches_remaining = MAX_WATCHES;
1667 watch->message_lock = g_slice_new (CRITICAL_SECTION);
1668 InitializeCriticalSection (watch->message_lock);
1669 watch->message_sent_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1670 watch->message_received_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1671 if (watch->message_sent_event == NULL || watch->message_received_event == NULL)
1673 g_message_win32_error (0, "gregistrybackend: Failed to create sync objects.");
1674 goto fail_1;
1677 /* Use a small stack to make the thread more lightweight. */
1678 watch->thread = CreateThread (NULL, 1024, watch_thread_function, watch, 0, NULL);
1679 if (watch->thread == NULL)
1681 g_message_win32_error (0, "gregistrybackend: Failed to create notify watch thread.");
1682 goto fail_2;
1685 self->watch = watch;
1687 return TRUE;
1689 fail_2:
1690 DeleteCriticalSection (self->cache_lock);
1691 g_slice_free (CRITICAL_SECTION, self->cache_lock);
1692 DeleteCriticalSection (watch->message_lock);
1693 g_slice_free (CRITICAL_SECTION, watch->message_lock);
1694 CloseHandle (watch->message_sent_event);
1695 CloseHandle (watch->message_received_event);
1696 fail_1:
1697 g_slice_free (WatchThreadState, watch);
1698 return FALSE;
1701 /* This function assumes you hold the message lock! */
1702 static void
1703 watch_stop_unlocked (GRegistryBackend *self)
1705 WatchThreadState *watch = self->watch;
1706 DWORD result;
1707 g_return_if_fail (watch != NULL);
1709 watch->message.type = WATCH_THREAD_STOP;
1710 SetEvent (watch->message_sent_event);
1712 /* This is signalled as soon as the message is received. We must not return
1713 * while the watch thread is still firing off callbacks. Freeing all of the
1714 * memory is done in the watch thread after this is signalled.
1716 result = WaitForSingleObject (watch->message_received_event, INFINITE);
1717 if (result != WAIT_OBJECT_0)
1719 g_warning ("gregistrybackend: unable to stop watch thread.");
1720 return;
1723 LeaveCriticalSection (watch->message_lock);
1724 DeleteCriticalSection (watch->message_lock);
1725 DeleteCriticalSection (self->cache_lock);
1726 g_slice_free (CRITICAL_SECTION, watch->message_lock);
1727 g_slice_free (CRITICAL_SECTION, self->cache_lock);
1728 CloseHandle (watch->message_sent_event);
1729 CloseHandle (watch->message_received_event);
1730 CloseHandle (watch->thread);
1731 g_slice_free (WatchThreadState, watch);
1733 trace ("\nwatch thread: %x: all data freed.\n", self);
1734 self->watch = NULL;
1737 static gboolean
1738 watch_add_notify (GRegistryBackend *self,
1739 HANDLE event,
1740 HKEY hpath,
1741 gchar *gsettings_prefix)
1743 WatchThreadState *watch = self->watch;
1744 GNode *cache_node;
1745 RegistryCacheItem *cache_item;
1746 #ifdef TRACE
1747 DWORD result;
1748 #endif
1750 g_return_val_if_fail (watch != NULL, FALSE);
1751 trace ("watch_add_notify: prefix %s.\n", gsettings_prefix);
1753 /* Duplicate tree into the cache in the main thread, before we add the notify: if we do it in the
1754 * thread we can miss changes while we are caching.
1756 EnterCriticalSection (self->cache_lock);
1757 cache_node = registry_cache_get_node_for_key (self->cache_root, gsettings_prefix, TRUE);
1759 g_return_val_if_fail (cache_node != NULL, FALSE);
1760 g_return_val_if_fail (cache_node->data != NULL, FALSE);
1762 cache_item = cache_node->data;
1764 cache_item->subscription_count ++;
1765 if (cache_item->subscription_count > 1)
1767 trace ("watch_add_notify: prefix %s already watched, %i subscribers.\n",
1768 gsettings_prefix, cache_item->subscription_count);
1769 return FALSE;
1772 registry_cache_ref_tree (cache_node);
1773 registry_cache_update (self, hpath, gsettings_prefix, NULL, cache_node, 0, NULL);
1774 //registry_cache_dump (self->cache_root, NULL);
1775 LeaveCriticalSection (self->cache_lock);
1777 EnterCriticalSection (watch->message_lock);
1778 watch->message.type = WATCH_THREAD_ADD_WATCH;
1779 watch->message.watch.event = event;
1780 watch->message.watch.hpath = hpath;
1781 watch->message.watch.prefix = gsettings_prefix;
1782 watch->message.watch.cache_node = cache_node;
1784 SetEvent (watch->message_sent_event);
1786 /* Wait for the received event in return, to avoid sending another message before the first
1787 * one was received. If it takes > 200ms there is a possible race but the worst outcome is
1788 * a notification is ignored.
1790 #ifdef TRACE
1791 result =
1792 #endif
1793 WaitForSingleObject (watch->message_received_event, 200);
1794 #ifdef TRACE
1795 if (result != WAIT_OBJECT_0)
1796 trace ("watch thread is slow to respond - notification may not be added.");
1797 #endif
1799 LeaveCriticalSection (watch->message_lock);
1801 return TRUE;
1805 static void
1806 watch_remove_notify (GRegistryBackend *self,
1807 const gchar *key_name)
1809 WatchThreadState *watch = self->watch;
1810 LONG result;
1812 if (self->watch == NULL)
1813 /* Here we assume that the unsubscribe message is for somewhere that was
1814 * deleted, and so it has already been removed and the watch thread has
1815 * stopped.
1817 return;
1819 EnterCriticalSection (watch->message_lock);
1820 watch->message.type = WATCH_THREAD_REMOVE_WATCH;
1821 watch->message.watch.prefix = g_strdup (key_name);
1823 SetEvent (watch->message_sent_event);
1825 /* Wait for the received event in return, to avoid sending another message before the first
1826 * one was received.
1828 result = WaitForSingleObject (watch->message_received_event, INFINITE);
1830 if (result != ERROR_SUCCESS)
1831 g_warning ("unsubscribe from %s: message not acknowledged\n", key_name);
1833 if (g_atomic_int_get (&watch->watches_remaining) >= MAX_WATCHES)
1834 /* Stop it before any new ones can get added and confuse things */
1835 watch_stop_unlocked (self);
1836 else
1837 LeaveCriticalSection (watch->message_lock);
1840 /* dconf semantics are: if the key ends in /, watch the keys underneath it - if not, watch that
1841 * key. Our job is easier because keys and values are separate.
1843 static void
1844 g_registry_backend_subscribe (GSettingsBackend *backend,
1845 const char *key_name)
1847 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
1848 gchar *path_name, *value_name = NULL;
1849 HKEY hpath;
1850 HANDLE event;
1851 LONG result;
1853 if (self->watch == NULL)
1854 if (!watch_start (self))
1855 return;
1857 if (g_atomic_int_dec_and_test (&self->watch->watches_remaining))
1859 g_atomic_int_inc (&self->watch->watches_remaining);
1860 g_warning ("subscribe() failed: only %i different paths may be watched.\n", MAX_WATCHES);
1861 return;
1864 path_name = parse_key (key_name, self->base_path, &value_name);
1866 /* Must check for this, otherwise strange crashes occur because the cache
1867 * node that is being watched gets freed. All path names to subscribe must
1868 * end in a slash!
1870 if (value_name != NULL && *value_name != 0)
1871 g_warning ("subscribe() failed: path must end in a /, got %s\n", key_name);
1873 trace ("Subscribing to %s [registry %s / %s] - watch %x\n", key_name, path_name, value_name, self->watch);
1876 /* Give the caller the benefit of the doubt if the key doesn't exist and create it. The caller
1877 * is almost certainly a new g_settings with this path as base path. */
1878 result = RegCreateKeyExA (HKEY_CURRENT_USER, path_name, 0, NULL, 0, KEY_READ, NULL, &hpath,
1879 NULL);
1880 g_free (path_name);
1882 if (result != ERROR_SUCCESS)
1884 g_message_win32_error (result, "gregistrybackend: Unable to subscribe to key %s.", key_name);
1885 g_atomic_int_inc (&self->watch->watches_remaining);
1886 return;
1889 event = CreateEvent (NULL, FALSE, FALSE, NULL);
1890 if (event == NULL)
1892 g_message_win32_error (result, "gregistrybackend: CreateEvent failed.\n");
1893 g_atomic_int_inc (&self->watch->watches_remaining);
1894 RegCloseKey (hpath);
1895 return;
1898 /* The actual watch is added by the thread, which has to re-subscribe each time it
1899 * receives a change. */
1900 if (!watch_add_notify (self, event, hpath, g_strdup (key_name)))
1901 g_atomic_int_inc (&self->watch->watches_remaining);
1904 static void
1905 g_registry_backend_unsubscribe (GSettingsBackend *backend,
1906 const char *key_name)
1908 trace ("unsubscribe: %s.\n", key_name);
1910 watch_remove_notify (G_REGISTRY_BACKEND (backend), key_name);
1914 /********************************************************************************
1915 * Object management junk
1916 ********************************************************************************/
1918 static void
1919 g_registry_backend_finalize (GObject *object)
1921 GRegistryBackend *self = G_REGISTRY_BACKEND (object);
1922 RegistryCacheItem *item;
1924 item = self->cache_root->data;
1925 g_warn_if_fail (item->ref_count == 1);
1927 _free_cache_item (item);
1928 g_node_destroy (self->cache_root);
1930 if (self->watch != NULL)
1932 EnterCriticalSection (self->watch->message_lock);
1933 watch_stop_unlocked (self);
1936 g_free (self->base_path);
1939 static void
1940 g_registry_backend_class_init (GRegistryBackendClass *class)
1942 GSettingsBackendClass *backend_class = G_SETTINGS_BACKEND_CLASS (class);
1943 GObjectClass *object_class = G_OBJECT_CLASS (class);
1945 object_class->finalize = g_registry_backend_finalize;
1947 backend_class->read = g_registry_backend_read;
1948 backend_class->write = g_registry_backend_write;
1949 backend_class->write_tree = g_registry_backend_write_tree;
1950 backend_class->reset = g_registry_backend_reset;
1951 backend_class->get_writable = g_registry_backend_get_writable;
1952 backend_class->get_permission = g_registry_backend_get_permission;
1953 backend_class->subscribe = g_registry_backend_subscribe;
1954 backend_class->unsubscribe = g_registry_backend_unsubscribe;
1957 static void
1958 g_registry_backend_init (GRegistryBackend *self)
1960 RegistryCacheItem *item;
1961 self->base_path = g_strdup_printf ("Software\\GSettings");
1963 item = g_slice_new (RegistryCacheItem);
1964 item->value.type = REG_NONE;
1965 item->value.ptr = NULL;
1966 item->name = g_strdup ("<root>");
1967 item->ref_count = 1;
1968 self->cache_root = g_node_new (item);
1970 self->watch = NULL;