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
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.
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
95 #include "gregistrysettingsbackend.h"
96 #include "gsimplepermission.h"
97 #include "gsettingsbackend.h"
98 #include "giomodule.h"
101 #define _WIN32_WINNT 0x0500
102 #define WIN32_LEAN_AND_MEAN
107 /* GSettings' limit */
108 #define MAX_KEY_NAME_LENGTH 32
110 /* Testing (on Windows XP SP3) shows that WaitForMultipleObjects fails with
111 * "The parameter is incorrect" after 64 watches. We need one for the
112 * message_sent cond, which is allowed for in the way the watches_remaining
115 #define MAX_WATCHES 64
117 /* A watch on one registry path and its subkeys */
127 /* Simple message passing for the watch thread. Not enough traffic to
133 WATCH_THREAD_ADD_WATCH,
134 WATCH_THREAD_REMOVE_WATCH,
136 } WatchThreadMessageType;
140 WatchThreadMessageType type;
142 } WatchThreadMessage;
147 GSettingsBackend *owner;
150 /* Details of the things we are watching. */
151 int watches_remaining;
152 GPtrArray *events, *handles, *prefixes, *cache_nodes;
154 /* Communication with the main thread. Only one message is stored at a time,
155 * to make sure that messages are acknowledged before being overwritten we
156 * create two events - one is signalled when a new message is set, the
157 * other is signalled by the thread when it has processed the message.
159 WatchThreadMessage message;
160 CRITICAL_SECTION *message_lock;
161 HANDLE message_sent_event, message_received_event;
165 #define G_TYPE_REGISTRY_BACKEND (g_registry_backend_get_type ())
166 #define G_REGISTRY_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
167 G_TYPE_REGISTRY_BACKEND, GRegistryBackend))
168 #define G_IS_REGISTRY_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
169 G_TYPE_REGISTRY_BACKEND))
172 typedef GSettingsBackendClass GRegistryBackendClass;
175 GSettingsBackend parent_instance;
179 /* A stored copy of the whole tree being watched. When we receive a change notification
180 * we have to check against this to see what has changed ... every time ...*/
181 CRITICAL_SECTION *cache_lock;
184 WatchThreadState *watch;
187 G_DEFINE_TYPE_WITH_CODE (GRegistryBackend,
189 G_TYPE_SETTINGS_BACKEND,
190 g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
191 g_define_type_id, "registry", 90))
194 /**********************************************************************************
196 **********************************************************************************/
200 trace (const char *format, ...)
203 va_list va; va_start (va, format);
204 vprintf (format, va); fflush (stdout);
209 /* g_message including a windows error message. It is not useful to have an
210 * equivalent function for g_warning because none of the registry errors can
211 * result from programmer error (Microsoft programmers don't count), instead
212 * they will mostly occur from people messing with the registry by hand. */
214 g_message_win32_error (DWORD result_code,
220 gchar win32_message[1024];
222 if (result_code == 0)
223 result_code = GetLastError ();
225 va_start (va, format);
226 pos = g_vsnprintf (win32_message, 512, format, va);
228 win32_message[pos++] = ':'; win32_message[pos++] = ' ';
230 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM, NULL, result_code, 0, (LPTSTR)(win32_message+pos),
233 if (result_code == ERROR_KEY_DELETED)
234 trace ("(%s)", win32_message);
236 g_message (win32_message);
240 /* Make gsettings key into a registry path & value pair.
242 * Note that the return value *only* needs freeing - registry_value_name
243 * is a pointer to further inside the same block of memory.
246 parse_key (const gchar *key_name,
247 const gchar *registry_prefix,
250 gchar *path_name, *c;
252 /* All key paths are treated as absolute; gsettings doesn't seem to enforce a
255 if (key_name[0] == '/')
258 if (registry_prefix == NULL)
259 path_name = g_strdup (key_name);
261 path_name = g_strjoin ("/", registry_prefix, key_name, NULL);
263 /* Prefix is expected to be in registry format (\ separators) so don't escape that. */
264 for (c=path_name+(registry_prefix?strlen(registry_prefix):0); *c!=0; c++)
271 **value_name = 0; (*value_name)++;
277 g_variant_get_as_dword (GVariant *variant)
279 switch (g_variant_get_type_string (variant)[0])
281 case 'b': return g_variant_get_boolean (variant);
282 case 'y': return g_variant_get_byte (variant);
283 case 'n': return g_variant_get_int16 (variant);
284 case 'q': return g_variant_get_uint16 (variant);
285 case 'i': return g_variant_get_int32 (variant);
286 case 'u': return g_variant_get_uint32 (variant);
287 default: g_warn_if_reached ();
293 g_variant_get_as_qword (GVariant *variant)
295 switch (g_variant_get_type_string (variant)[0])
297 case 'x': return g_variant_get_int64 (variant);
298 case 't': return g_variant_get_uint64 (variant);
299 default: g_warn_if_reached ();
306 handle_read_error (LONG result,
307 const gchar *path_name,
308 const gchar *value_name)
310 /* file not found means key value not set, this isn't an error for us. */
311 if (result != ERROR_FILE_NOT_FOUND)
312 g_message_win32_error (result, "Unable to query value %s/%s: %s.\n",
313 path_name, value_name);
316 /***************************************************************************
317 * Cache of registry values
318 ***************************************************************************/
320 /* Generic container for registry values */
325 gint dword; /* FIXME: could inline QWORD on 64-bit systems too */
331 registry_value_dump (RegistryValue value)
333 if (value.type == REG_DWORD)
334 return g_strdup_printf ("%i", value.dword);
335 else if (value.type == REG_QWORD)
336 return g_strdup_printf ("%I64i", value.ptr==NULL? 0: *(DWORDLONG *)value.ptr);
337 else if (value.type == REG_SZ)
338 return g_strdup_printf ("%s", (char *)value.ptr);
339 else if (value.type == REG_NONE)
340 return g_strdup_printf ("<empty>");
342 return g_strdup_printf ("<invalid>");
346 registry_value_free (RegistryValue value)
348 if (value.type == REG_SZ || value.type == REG_QWORD)
350 value.type = REG_NONE;
355 /* The registry cache is stored as a tree, for easy traversal. Right now we
356 * don't sort it in a clever way. Each node corresponds to a path element
357 * ('key' in registry terms) or a value.
359 * Each subscription uses the same cache. Because GSettings can subscribe to
360 * the tree at any node any number of times, we need to reference count the
365 /* Component of path that this node represents */
368 /* If a watch is subscribed at this point (subscription_count > 0) we can
369 * block its next notification. This is useful because if two watches cover
370 * the same path, both will trigger when it changes. It also allows changes
371 * done by the application to be ignored by the watch thread.
373 gint32 block_count : 8;
375 /* Number of times g_settings_subscribe has been called for this location
376 * (I guess you can't subscribe more than 16383 times) */
377 gint32 subscription_count : 14;
379 gint32 ref_count : 9;
388 registry_cache_add_item (GNode *parent,
393 RegistryCacheItem *item = g_slice_new (RegistryCacheItem);
396 g_return_val_if_fail (name != NULL, NULL);
397 g_return_val_if_fail (parent != NULL, NULL);
399 /* Ref count should be the number of watch points above this node */
400 item->ref_count = ref_count;
402 item->name = g_strdup (name);
404 item->subscription_count = 0;
405 item->block_count = 0;
406 item->touched = FALSE;
407 trace ("\treg cache: adding %s to %s\n", name, ((RegistryCacheItem *)parent->data)->name);
409 cache_node = g_node_new (item);
410 g_node_append (parent, cache_node);
414 /* The reference counting of cache tree nodes works like this: when a node is
415 * subscribed to (GSettings wants us to watch that path and everything below
416 * it) the reference count of that node and everything below is increased, as
417 * well as each parent up to the root.
422 _ref_down (GNode *node)
424 RegistryCacheItem *item = node->data;
425 g_node_children_foreach (node, G_TRAVERSE_ALL,
426 (GNodeForeachFunc)_ref_down, NULL);
430 registry_cache_ref_tree (GNode *tree)
432 RegistryCacheItem *item = tree->data;
433 GNode *node = tree->parent;
435 g_return_if_fail (tree != NULL);
439 g_node_children_foreach (tree, G_TRAVERSE_ALL,
440 (GNodeForeachFunc)_ref_down, NULL);
442 for (node=tree->parent; node; node=node->parent)
450 _free_cache_item (RegistryCacheItem *item)
452 trace ("\t -- Free node %s\n", item->name);
454 registry_value_free (item->value);
455 g_slice_free (RegistryCacheItem, item);
458 /* Unreferencing has to be done bottom-up */
460 _unref_node (GNode *node)
462 RegistryCacheItem *item = node->data;
466 g_warn_if_fail (item->ref_count >= 0);
468 if (item->ref_count == 0)
470 _free_cache_item (item);
471 g_node_destroy (node);
476 _unref_down (GNode *node)
478 g_node_children_foreach (node, G_TRAVERSE_ALL,
479 (GNodeForeachFunc)_unref_down, NULL);
484 registry_cache_unref_tree (GNode *tree)
486 GNode *parent = tree->parent, *next_parent;
492 next_parent = parent->parent;
493 _unref_node (parent);
494 parent = next_parent;
500 registry_cache_dump (GNode *cache_node,
503 RegistryCacheItem *item = cache_node->data;
505 int depth = GPOINTER_TO_INT(data),
509 g_return_if_fail (cache_node != NULL);
511 for (i=0; i<depth; i++)
514 g_print ("*root*\n");
516 g_print ("'%s' [%i] @ %x = %s\n", item->name, item->ref_count, (guint)cache_node,
517 registry_value_dump (item->value));
518 g_node_children_foreach (cache_node, G_TRAVERSE_ALL, registry_cache_dump,
519 GINT_TO_POINTER (new_depth));
527 } RegistryCacheSearch;
530 registry_cache_find_compare (GNode *node,
533 RegistryCacheSearch *search = data;
534 RegistryCacheItem *item = node->data;
536 if (item == NULL) /* root node */
539 g_return_val_if_fail (search->name != NULL, FALSE);
540 g_return_val_if_fail (item->name != NULL, FALSE);
542 if (strcmp (search->name, item->name) == 0)
544 search->result = node;
551 registry_cache_find_immediate_child (GNode *node,
554 RegistryCacheSearch search;
555 search.result = NULL;
557 g_node_traverse (node, G_POST_ORDER, G_TRAVERSE_ALL, 2,
558 registry_cache_find_compare, &search);
559 return search.result;
564 registry_cache_get_node_for_key_recursive (GNode *node,
566 gboolean create_if_not_found,
567 gint n_parent_watches)
569 RegistryCacheItem *item;
570 gchar *component = key_name,
571 *c = strchr (component, '/');
576 /* We count up how many watch points we travel through finding this node,
577 * because a new node should have as many references as there are watches at
578 * points above it in the tree.
581 if (item->subscription_count > 0)
584 GNode *child = registry_cache_find_immediate_child (node, component);
585 if (child == NULL && create_if_not_found)
587 item = g_slice_new (RegistryCacheItem);
588 item->name = g_strdup (component);
589 item->value.type = REG_NONE;
590 item->value.ptr = NULL;
591 item->ref_count = n_parent_watches;
592 child = g_node_new (item);
593 g_node_append (node, child);
594 trace ("\tget node for key recursive: new %x = %s.\n", node, item->name);
597 /* We are done if there are no more path components. Allow for a trailing /. */
598 if (child==NULL || c == NULL || *(c+1)==0)
602 trace ("get node for key recursive: next: %s.\n", c+1);
603 return registry_cache_get_node_for_key_recursive
604 (child, c+1, create_if_not_found, n_parent_watches);
608 /* Look up a GSettings key in the cache. */
610 registry_cache_get_node_for_key (GNode *root,
611 const gchar *key_name,
612 gboolean create_if_not_found)
616 gchar *component, *c;
618 g_return_val_if_fail (key_name != NULL, NULL);
620 if (key_name[0] == '/')
623 /* Ignore preceeding / */
624 component = g_strdup (key_name);
625 c = strchr (component, '/');
629 child = registry_cache_find_immediate_child (root, component);
630 if (child == NULL && create_if_not_found)
632 /* Reference count is set to 0, tree should be referenced by the caller */
633 RegistryCacheItem *item = g_slice_new (RegistryCacheItem);
634 item->value.type = REG_NONE;
635 item->value.ptr = NULL;
636 item->name = g_strdup (component);
638 trace ("get_node_for_key: New node for component '%s'\n", item->name);
639 child = g_node_new (item);
640 g_node_append (root, child);
647 else if (child != NULL)
648 result = registry_cache_get_node_for_key_recursive (child, c+1, create_if_not_found, 0);
655 /* Check the cache node against the registry key it represents. Return TRUE if
656 * they differ, and update the cache with the new value.
659 registry_cache_update_node (GNode *cache_node,
660 RegistryValue registry_value)
662 RegistryCacheItem *cache_item = cache_node->data;
664 g_return_val_if_fail (cache_node != NULL, FALSE);
665 g_return_val_if_fail (cache_item != NULL, FALSE);
667 if (registry_value.type != cache_item->value.type)
669 /* The type has changed. Update cache item and register it as changed.
670 * Either the schema has changed and this is entirely legitimate, or
671 * whenever the app reads the key it will get the default value due to
674 cache_item->value = registry_value;
678 switch (registry_value.type)
682 if (cache_item->value.dword == registry_value.dword)
686 cache_item->value.dword = registry_value.dword;
692 g_return_val_if_fail (registry_value.ptr != NULL &&
693 cache_item->value.ptr != NULL, FALSE);
695 if (memcmp (registry_value.ptr, cache_item->value.ptr, 8)==0)
697 g_free (registry_value.ptr);
702 g_free (cache_item->value.ptr);
703 cache_item->value.ptr = registry_value.ptr;
709 /* Value should not exist if it is NULL, an empty string is "" */
710 g_return_val_if_fail (cache_item->value.ptr != NULL, FALSE);
711 g_return_val_if_fail (registry_value.ptr != NULL, FALSE);
713 if (strcmp (registry_value.ptr, cache_item->value.ptr) == 0)
715 g_free (registry_value.ptr);
720 g_free (cache_item->value.ptr);
721 cache_item->value.ptr = registry_value.ptr;
726 g_warning ("gregistrybackend: registry_cache_update_node: Unhandled value type :(");
731 /* Blocking notifications is a useful optimisation. When a change is made
732 * through GSettings we update the cache manually, but a notifcation is
733 * triggered as well. This function is also used for nested notifications,
734 * eg. if /test and /test/foo are watched, and /test/foo/value is changed then
735 * we will get notified both for /test/foo and /test and it is helpful to block
739 registry_cache_block_notification (GNode *node)
741 RegistryCacheItem *item = node->data;
743 g_return_if_fail (node != NULL);
745 if (item->subscription_count > 0)
746 item->block_count ++;
748 if (node->parent != NULL)
749 registry_cache_block_notification (node->parent);
753 registry_cache_destroy_tree (GNode *node,
754 WatchThreadState *self);
756 /***************************************************************************
757 * Reading and writing
758 ***************************************************************************/
761 registry_read (HKEY hpath,
762 const gchar *path_name,
763 const gchar *value_name,
764 RegistryValue *p_value)
767 DWORD value_data_size;
770 g_return_val_if_fail (p_value != NULL, FALSE);
772 p_value->type = REG_NONE;
775 result = RegQueryValueExA (hpath, value_name, 0, &p_value->type, NULL, &value_data_size);
776 if (result != ERROR_SUCCESS)
778 handle_read_error (result, path_name, value_name);
782 if (p_value->type == REG_SZ && value_data_size == 0)
784 p_value->ptr = g_strdup ("");
788 if (p_value->type == REG_DWORD)
789 /* REG_DWORD is inlined */
790 buffer = (void *)&p_value->dword;
792 buffer = p_value->ptr = g_malloc (value_data_size);
794 result = RegQueryValueExA (hpath, value_name, 0, NULL, (LPBYTE)buffer, &value_data_size);
795 if (result != ERROR_SUCCESS)
797 handle_read_error (result, path_name, value_name);
806 g_registry_backend_read (GSettingsBackend *backend,
807 const gchar *key_name,
808 const GVariantType *expected_type,
809 gboolean default_value)
811 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
814 RegistryValue registry_value;
815 GVariant *gsettings_value = NULL;
816 gchar *gsettings_type;
818 g_return_val_if_fail (expected_type != NULL, NULL);
823 /* Simply read from the cache, which is updated from the registry by the
824 * watch thread as soon as changes can propagate. Any changes not yet in the
825 * cache will have the 'changed' signal emitted after this function returns.
827 EnterCriticalSection (self->cache_lock);
828 cache_node = registry_cache_get_node_for_key (self->cache_root, key_name, FALSE);
829 LeaveCriticalSection (self->cache_lock);
831 trace ("Reading key %s, cache node %x\n", key_name, cache_node);
833 /* Maybe it's not set, we can return to default */
834 if (cache_node == NULL)
837 trace ("\t- cached value %s\n", registry_value_dump (((RegistryCacheItem *)cache_node->data)->value));
839 registry_value = ((RegistryCacheItem *)cache_node->data)->value;
841 gsettings_type = g_variant_type_dup_string (expected_type);
843 /* The registry is user-editable, so we need to be fault-tolerant here. */
844 switch (gsettings_type[0])
846 case 'b': case 'y': case 'n': case 'q': case 'i': case 'u':
847 if (registry_value.type == REG_DWORD)
848 gsettings_value = g_variant_new (gsettings_type, registry_value.dword);
852 if (registry_value.type == REG_QWORD)
854 DWORDLONG qword_value = *(DWORDLONG *)registry_value.ptr;
855 gsettings_value = g_variant_new (gsettings_type, qword_value);
860 if (registry_value.type == REG_SZ)
862 if (gsettings_type[0]=='s')
863 gsettings_value = g_variant_new_string ((char *)registry_value.ptr);
866 GError *error = NULL;
867 gsettings_value = g_variant_parse (expected_type, registry_value.ptr, NULL, NULL, &error);
870 g_message ("gregistrysettingsbackend: error parsing key %s: %s\n",
871 key_name, error->message);
877 g_free (gsettings_type);
879 return gsettings_value;
885 GRegistryBackend *self;
890 g_registry_backend_write_one (const char *key_name,
894 GRegistryBackend *self;
895 RegistryWrite *action;
899 gchar *path_name, *value_name = NULL;
900 DWORD value_data_size;
908 self = G_REGISTRY_BACKEND (action->self);
909 hroot = action->hroot;
911 value.type = REG_NONE;
914 const gchar *type_string = g_variant_get_type_string (variant);
915 switch (type_string[0])
917 case 'b': case 'y': case 'n': case 'q': case 'i': case 'u':
918 value.type = REG_DWORD;
919 value.dword = g_variant_get_as_dword (variant);
921 value_data = &value.dword;
925 value.type = REG_QWORD;
926 value.ptr = g_malloc (8);
927 *(DWORDLONG *)value.ptr = g_variant_get_as_qword (variant);
929 value_data = value.ptr;
934 if (type_string[0]=='s')
937 value.ptr = g_strdup (g_variant_get_string (variant, &length));
938 value_data_size = length + 1;
939 value_data = value.ptr;
943 GString *value_string;
944 value_string = g_variant_print_string (variant, NULL, FALSE);
945 value_data_size = value_string->len+1;
946 value.ptr = value_data = g_string_free (value_string, FALSE);
951 /* First update the cache, because the value may not have changed and we can
954 * If 'value' has changed then its memory will not be freed by update_node(),
955 * because it will be stored in the node.
957 EnterCriticalSection (self->cache_lock);
958 node = registry_cache_get_node_for_key (self->cache_root, key_name, TRUE);
959 changed = registry_cache_update_node (node, value);
960 LeaveCriticalSection (self->cache_lock);
965 /* Block the next notification to any watch points above this location,
966 * because they will each get triggered on a change that is already updated
969 registry_cache_block_notification (node);
971 path_name = parse_key (key_name, NULL, &value_name);
973 trace ("Set key: %s / %s\n", path_name, value_name);
975 /* Store the value in the registry */
976 result = RegCreateKeyExA (hroot, path_name, 0, NULL, 0, KEY_WRITE, NULL, &hpath, NULL);
977 if (result != ERROR_SUCCESS)
979 g_message_win32_error (result, "gregistrybackend: opening key %s failed", path_name+1);
980 registry_value_free (value);
985 result = RegSetValueExA (hpath, value_name, 0, value.type, value_data, value_data_size);
986 if (result != ERROR_SUCCESS)
987 g_message_win32_error (result, "gregistrybackend: setting value %s\%s\\%s failed.\n",
988 self->base_path, path_name, value_name);
990 /* If the write fails then it will seem like the value has changed until the
991 * next execution (because we wrote to the cache first). There's no reason
992 * for it to fail unless something is weirdly broken, however.
1001 /* The dconf write policy is to do the write while making out it succeeded,
1002 * and then backtrack if it didn't. The registry functions are synchronous so
1003 * we can't do that. */
1006 g_registry_backend_write (GSettingsBackend *backend,
1007 const gchar *key_name,
1009 gpointer origin_tag)
1011 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
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);
1022 RegistryWrite action = { self, hroot };
1023 g_registry_backend_write_one (key_name, value, &action);
1024 g_settings_backend_changed (backend, key_name, origin_tag);
1026 RegCloseKey (hroot);
1032 g_registry_backend_write_tree (GSettingsBackend *backend,
1034 gpointer origin_tag)
1036 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
1040 result = RegCreateKeyExA (HKEY_CURRENT_USER, self->base_path, 0, NULL, 0,
1041 KEY_WRITE, NULL, &hroot, NULL);
1042 if (result != ERROR_SUCCESS) {
1043 trace ("Error opening/creating key %s.\n", self->base_path);
1047 RegistryWrite action = { self, hroot };
1048 g_tree_foreach (values, (GTraverseFunc)g_registry_backend_write_one,
1051 g_settings_backend_changed_tree (backend, values, origin_tag);
1052 RegCloseKey (hroot);
1058 g_registry_backend_reset (GSettingsBackend *backend,
1059 const gchar *key_name,
1060 gpointer origin_tag)
1062 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
1063 gchar *path_name, *value_name = NULL;
1068 /* Remove from cache */
1069 EnterCriticalSection (self->cache_lock);
1070 cache_node = registry_cache_get_node_for_key (self->cache_root, key_name, FALSE);
1072 registry_cache_destroy_tree (cache_node, self->watch);
1073 LeaveCriticalSection (self->cache_lock);
1075 /* Remove from the registry */
1076 path_name = parse_key (key_name, self->base_path, &value_name);
1078 result = RegOpenKeyExA (HKEY_CURRENT_USER, path_name, 0, KEY_SET_VALUE, &hpath);
1079 if (result != ERROR_SUCCESS)
1081 g_message_win32_error (result, "Registry: resetting key '%s'", path_name);
1086 result = RegDeleteValueA (hpath, value_name);
1087 RegCloseKey (hpath);
1089 if (result != ERROR_SUCCESS)
1091 g_message_win32_error (result, "Registry: resetting key '%s'", path_name);
1099 g_settings_backend_changed (backend, key_name, origin_tag);
1102 /* Not implemented and probably beyond the scope of this backend */
1104 g_registry_backend_get_writable (GSettingsBackend *backend,
1105 const gchar *key_name)
1110 static GPermission *
1111 g_registry_backend_get_permission (GSettingsBackend *backend,
1112 const gchar *key_name)
1114 return g_simple_permission_new (TRUE);
1118 /********************************************************************************
1119 * Spot-the-difference engine
1120 ********************************************************************************/
1123 _free_watch (WatchThreadState *self,
1128 registry_cache_item_reset_touched (GNode *node,
1131 RegistryCacheItem *item = node->data;
1132 item->touched = FALSE;
1135 /* Delete a node and any children, for when it has been deleted from the registry */
1137 registry_cache_destroy_tree (GNode *node,
1138 WatchThreadState *self)
1140 RegistryCacheItem *item = node->data;
1142 g_node_children_foreach (node, G_TRAVERSE_ALL,
1143 (GNodeForeachFunc)registry_cache_destroy_tree, self);
1145 if (item->subscription_count > 0)
1147 /* There must be some watches active if this node is a watch point */
1148 g_warn_if_fail (self->cache_nodes->len > 1);
1150 /* This is a watch point that has been deleted. Let's free the watch! */
1152 for (i=1; i<self->cache_nodes->len; i++)
1153 if (g_ptr_array_index (self->cache_nodes, i) == node)
1155 if (i >= self->cache_nodes->len)
1156 g_warning ("watch thread: a watch point was deleted, but unable to "
1157 "find '%s' in the list of %i watch nodes\n", item->name,
1158 self->cache_nodes->len-1);
1161 _free_watch (self, i, node);
1162 g_atomic_int_inc (&self->watches_remaining);
1165 _free_cache_item (node->data);
1166 g_node_destroy (node);
1170 registry_cache_remove_deleted (GNode *node,
1173 RegistryCacheItem *item = node->data;
1176 registry_cache_destroy_tree (node, data);
1179 /* Update cache from registry, and optionally report on the changes.
1181 * This function is sometimes called from the watch thread, with no locking. It
1182 * does call g_registry_backend functions, but this is okay because they only
1183 * access self->base which is constant.
1185 * When looking at this code bear in mind the terminology: in the registry, keys
1186 * are containers that contain values, and other keys. Keys have a 'default'
1187 * value which we always ignore.
1189 * n_parent_watches: a counter used to set the reference count of any new nodes
1190 * that are created - they should have as many references as
1191 * there are notifications that are watching them.
1194 registry_cache_update (GRegistryBackend *self,
1196 const gchar *prefix,
1197 const gchar *partial_key_name,
1202 gchar buffer[MAX_KEY_NAME_LENGTH + 1];
1207 RegistryCacheItem *item = cache_node->data;
1209 if (item->subscription_count > 0)
1212 /* prefix is the level that all changes occur below; partial_key_name should
1213 * be NULL on the first call to this function */
1214 key_name = g_build_path ("/", prefix, partial_key_name, NULL);
1216 trace ("registry cache update: %s. Node %x has %i children\n", key_name,
1217 cache_node, g_node_n_children (cache_node));
1219 /* Start by zeroing 'touched' flag. When the registry traversal is done, any untouched nodes
1220 * must have been deleted from the registry.
1222 g_node_children_foreach (cache_node, G_TRAVERSE_ALL,
1223 registry_cache_item_reset_touched, NULL);
1225 /* Recurse into each subpath at the current level, if any */
1229 DWORD buffer_size = MAX_KEY_NAME_LENGTH;
1232 result = RegEnumKeyEx (hpath, i++, buffer, &buffer_size, NULL, NULL, NULL, NULL);
1233 if (result != ERROR_SUCCESS)
1236 result = RegOpenKeyEx (hpath, buffer, 0, KEY_READ, &hsubpath);
1237 if (result == ERROR_SUCCESS)
1240 RegistryCacheItem *child_item;
1242 subkey_node = registry_cache_find_immediate_child (cache_node, buffer);
1243 if (subkey_node == NULL)
1245 RegistryValue null_value = {REG_NONE, {0}};
1246 subkey_node = registry_cache_add_item (cache_node, buffer,
1247 null_value, n_watches);
1251 registry_cache_update (self, hsubpath, prefix, buffer, subkey_node,
1252 n_watches, changes);
1253 child_item = subkey_node->data;
1254 child_item->touched = TRUE;
1256 RegCloseKey (hsubpath);
1259 if (result != ERROR_NO_MORE_ITEMS)
1260 g_message_win32_error (result, "gregistrybackend: error enumerating subkeys for cache.");
1262 /* Enumerate each value at 'path' and check if it has changed */
1266 DWORD buffer_size = MAX_KEY_NAME_LENGTH;
1267 GNode *cache_child_node;
1268 RegistryCacheItem *child_item;
1269 RegistryValue value;
1270 gboolean changed = FALSE;
1272 result = RegEnumValue (hpath, i++, buffer, &buffer_size, NULL, NULL, NULL, NULL);
1273 if (result != ERROR_SUCCESS)
1277 /* This is the key's 'default' value, for which we have no use. */
1280 cache_child_node = registry_cache_find_immediate_child (cache_node, buffer);
1282 if (!registry_read (hpath, key_name, buffer, &value))
1285 trace ("\tgot value %s for %s, node %x\n", registry_value_dump (value), buffer, cache_child_node);
1287 if (cache_child_node == NULL)
1289 /* This is a new value */
1290 cache_child_node = registry_cache_add_item (cache_node, buffer, value,
1296 /* For efficiency, instead of converting every value back to a GVariant to
1297 * compare it, we compare them as registry values (integers, or string
1298 * representations of the variant). The spurious change notifications that may
1299 * result should not be a big issue.
1301 * Note that 'value' is swallowed or freed.
1303 changed = registry_cache_update_node (cache_child_node, value);
1306 child_item = cache_child_node->data;
1307 child_item->touched = TRUE;
1308 if (changed == TRUE && changes != NULL)
1311 if (partial_key_name == NULL)
1312 item = g_strdup (buffer);
1314 item = g_build_path ("/", partial_key_name, buffer, NULL);
1315 g_ptr_array_add (changes, item);
1319 if (result != ERROR_NO_MORE_ITEMS)
1320 g_message_win32_error (result, "gregistrybackend: error enumerating values for cache");
1322 /* Any nodes now left untouched must have been deleted, remove them from cache */
1323 g_node_children_foreach (cache_node, G_TRAVERSE_ALL,
1324 registry_cache_remove_deleted, self->watch);
1326 trace ("registry cache update complete.\n");
1332 /***********************************************************************************
1333 * Thread to watch for registry change events
1334 ***********************************************************************************/
1336 /* Called by watch thread. Apply for notifications on a registry key and its subkeys. */
1338 registry_watch_key (HKEY hpath, HANDLE event)
1340 return RegNotifyChangeKeyValue (hpath, TRUE,
1341 REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
1346 /* One of these is sent down the pipe when something happens in the registry. */
1349 GRegistryBackend *self;
1350 gchar *prefix; /* prefix is a gsettings path, all items are subkeys of this. */
1351 GPtrArray *items; /* each item is a subkey below prefix that has changed. */
1354 /* This handler runs in the main thread to emit the changed signals */
1356 watch_handler (RegistryEvent *event)
1359 trace ("Watch handler: got event in %s, items %i.\n", event->prefix, event->items->len);
1361 /* GSettings requires us to NULL-terminate the array. */
1362 g_ptr_array_add (event->items, NULL);
1363 g_settings_backend_keys_changed (G_SETTINGS_BACKEND (event->self), event->prefix,
1364 (gchar const **)event->items->pdata, NULL);
1366 for (i=0; i<event->items->len; i++)
1367 g_free (g_ptr_array_index (event->items, i));
1368 g_ptr_array_free (event->items, TRUE);
1370 g_free (event->prefix);
1371 g_object_unref (event->self);
1373 g_slice_free (RegistryEvent, event);
1379 _free_watch (WatchThreadState *self,
1387 g_return_if_fail (index > 0 && index < self->events->len);
1389 cond = g_ptr_array_index (self->events, index);
1390 hpath = g_ptr_array_index (self->handles, index);
1391 prefix = g_ptr_array_index (self->prefixes, index);
1393 trace ("Freeing watch %i [%s]\n", index, prefix);
1395 /* These can be NULL if the watch was already dead, this can happen when eg.
1396 * a key is deleted but GSettings is still subscribed to it - the watch is
1397 * kept alive so that the unsubscribe function works properly, but does not
1401 RegCloseKey (hpath);
1403 if (cache_node != NULL)
1405 //registry_cache_dump (G_REGISTRY_BACKEND (self->owner)->cache_root, NULL);
1406 registry_cache_unref_tree (cache_node);
1412 /* As long as we remove from each array at the same time, it doesn't matter that
1413 * their orders get messed up - they all get messed up the same.
1415 g_ptr_array_remove_index_fast (self->handles, index);
1416 g_ptr_array_remove_index_fast (self->events, index);
1417 g_ptr_array_remove_index_fast (self->prefixes, index);
1418 g_ptr_array_remove_index_fast (self->cache_nodes, index);
1422 watch_thread_handle_message (WatchThreadState *self)
1424 switch (self->message.type)
1426 case WATCH_THREAD_NONE:
1427 trace ("watch thread: you woke me up for nothin', man!");
1430 case WATCH_THREAD_ADD_WATCH:
1432 RegistryWatch *watch = &self->message.watch;
1434 result = registry_watch_key (watch->hpath, watch->event);
1435 if (result == ERROR_SUCCESS)
1437 g_ptr_array_add (self->events, watch->event);
1438 g_ptr_array_add (self->handles, watch->hpath);
1439 g_ptr_array_add (self->prefixes, watch->prefix);
1440 g_ptr_array_add (self->cache_nodes, watch->cache_node);
1441 trace ("watch thread: new watch on %s, %i total\n", watch->prefix,
1446 g_message_win32_error (result, "watch thread: could not watch %s", watch->prefix);
1447 CloseHandle (watch->event);
1448 RegCloseKey (watch->hpath);
1449 g_free (watch->prefix);
1450 registry_cache_unref_tree (watch->cache_node);
1455 case WATCH_THREAD_REMOVE_WATCH:
1458 RegistryCacheItem *cache_item;
1461 for (i=1; i<self->prefixes->len; i++)
1462 if (strcmp (g_ptr_array_index (self->prefixes, i),
1463 self->message.watch.prefix) == 0)
1466 if (i >= self->prefixes->len)
1468 /* Don't make a fuss if the prefix is not being watched because
1469 * maybe the path was deleted so we removed the watch.
1471 trace ("unsubscribe: prefix %s is not being watched [%i things are]!\n",
1472 self->message.watch.prefix, self->prefixes->len);
1473 g_free (self->message.watch.prefix);
1477 cache_node = g_ptr_array_index (self->cache_nodes, i);
1479 trace ("watch thread: unsubscribe: freeing node %x, prefix %s, index %i\n",
1480 (guint)cache_node, self->message.watch.prefix, i);
1481 if (cache_node != NULL)
1483 cache_item = cache_node->data;
1485 /* There may be more than one GSettings object subscribed to this
1486 * path, only free the watch when the last one unsubscribes.
1488 cache_item->subscription_count --;
1489 if (cache_item->subscription_count > 0)
1493 _free_watch (self, i, cache_node);
1494 g_free (self->message.watch.prefix);
1496 g_atomic_int_inc (&self->watches_remaining);
1500 case WATCH_THREAD_STOP:
1504 /* Free any remaining cache and watch handles */
1505 for (i=1; i<self->events->len; i++)
1506 _free_watch (self, i, g_ptr_array_index (self->cache_nodes, i));
1508 SetEvent (self->message_received_event);
1513 self->message.type = WATCH_THREAD_NONE;
1514 SetEvent (self->message_received_event);
1518 /* Thread which watches for win32 registry events */
1520 watch_thread_function (LPVOID parameter)
1522 WatchThreadState *self = (WatchThreadState *)parameter;
1525 self->events = g_ptr_array_new ();
1526 self->handles = g_ptr_array_new ();
1527 self->prefixes = g_ptr_array_new ();
1528 self->cache_nodes = g_ptr_array_new ();
1529 g_ptr_array_add (self->events, self->message_sent_event);
1530 g_ptr_array_add (self->handles, NULL);
1531 g_ptr_array_add (self->prefixes, NULL);
1532 g_ptr_array_add (self->cache_nodes, NULL);
1536 trace ("watch thread: going to sleep; %i events watched.\n", self->events->len);
1537 result = WaitForMultipleObjects (self->events->len, self->events->pdata, FALSE, INFINITE);
1539 if (result == WAIT_OBJECT_0)
1541 /* A message to you. The sender (main thread) will block until we signal the received
1542 * event, so there should be no danger of it sending another before we receive the
1545 watch_thread_handle_message (self);
1547 else if (result > WAIT_OBJECT_0 && result <= WAIT_OBJECT_0 + self->events->len)
1553 RegistryCacheItem *cache_item;
1554 RegistryEvent *event;
1556 /* One of our notifications has triggered. All we know is which one, and which key
1557 * this is for. We do most of the processing here, because we may as well. If the
1558 * registry changes further while we are processing it doesn't matter - we will then
1559 * receive another change notification from the OS anyway.
1561 gint notify_index = result - WAIT_OBJECT_0;
1562 hpath = g_ptr_array_index (self->handles, notify_index);
1563 cond = g_ptr_array_index (self->events, notify_index);
1564 prefix = g_ptr_array_index (self->prefixes, notify_index);
1565 cache_node = g_ptr_array_index (self->cache_nodes, notify_index);
1567 trace ("Watch thread: notify received on prefix %i: %s.\n", notify_index, prefix);
1569 if (cache_node == NULL)
1571 /* This path has been deleted */
1572 trace ("Notify received on a path that was deleted :(\n");
1576 /* Firstly we need to reapply for the notification, because (what a
1577 * sensible API) we won't receive any more. MSDN is pretty
1578 * inconsistent on this matter:
1579 * http://msdn.microsoft.com/en-us/library/ms724892%28VS.85%29.aspx
1580 * http://support.microsoft.com/kb/236570
1581 * But my tests (on Windows XP SP3) show that we need to reapply
1584 result = registry_watch_key (hpath, cond);
1586 if (result != ERROR_SUCCESS)
1588 /* Watch failed, most likely because the key has just been
1589 * deleted. Free the watch and unref the cache nodes.
1591 if (result != ERROR_KEY_DELETED)
1592 g_message_win32_error (result, "watch thread: failed to watch %s", prefix);
1593 _free_watch (self, notify_index, cache_node);
1594 g_atomic_int_inc (&self->watches_remaining);
1598 /* The notification may have been blocked because we just changed
1599 * some data ourselves.
1601 cache_item = cache_node->data;
1602 if (cache_item->block_count)
1604 cache_item->block_count --;
1605 trace ("Watch thread: notify blocked at %s\n", prefix);
1609 /* Now we update our stored cache from registry data, and find which keys have
1610 * actually changed. If more changes happen while we are processing, we will get
1611 * another event because we have reapplied for change notifications already.
1613 * Working here rather than in the main thread is preferable because the UI is less
1614 * likely to block (only when changing notification subscriptions).
1616 event = g_slice_new (RegistryEvent);
1618 event->self = G_REGISTRY_BACKEND (self->owner);
1619 g_object_ref (self->owner);
1621 event->items = g_ptr_array_new ();
1623 EnterCriticalSection (G_REGISTRY_BACKEND (self->owner)->cache_lock);
1624 registry_cache_update (G_REGISTRY_BACKEND (self->owner), hpath,
1625 prefix, NULL, cache_node, 0, event->items);
1626 LeaveCriticalSection (G_REGISTRY_BACKEND (self->owner)->cache_lock);
1628 if (event->items->len > 0)
1630 event->prefix = g_strdup (prefix);
1631 g_idle_add ((GSourceFunc) watch_handler, event);
1635 g_ptr_array_free (event->items, TRUE);
1636 g_slice_free (RegistryEvent, event);
1641 /* God knows what has happened */
1642 g_message_win32_error (GetLastError(), "watch thread: WaitForMultipleObjects error");
1650 watch_start (GRegistryBackend *self)
1652 WatchThreadState *watch;
1654 g_return_val_if_fail (self->watch == NULL, FALSE);
1656 self->cache_lock = g_slice_new (CRITICAL_SECTION);
1657 InitializeCriticalSection (self->cache_lock);
1659 watch = g_slice_new (WatchThreadState);
1660 watch->owner = G_SETTINGS_BACKEND (self);
1662 watch->watches_remaining = MAX_WATCHES;
1664 watch->message_lock = g_slice_new (CRITICAL_SECTION);
1665 InitializeCriticalSection (watch->message_lock);
1666 watch->message_sent_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1667 watch->message_received_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1668 if (watch->message_sent_event == NULL || watch->message_received_event == NULL)
1670 g_message_win32_error (0, "gregistrybackend: Failed to create sync objects.");
1674 /* Use a small stack to make the thread more lightweight. */
1675 watch->thread = CreateThread (NULL, 1024, watch_thread_function, watch, 0, NULL);
1676 if (watch->thread == NULL)
1678 g_message_win32_error (0, "gregistrybackend: Failed to create notify watch thread.");
1682 self->watch = watch;
1687 DeleteCriticalSection (self->cache_lock);
1688 g_slice_free (CRITICAL_SECTION, self->cache_lock);
1689 DeleteCriticalSection (watch->message_lock);
1690 g_slice_free (CRITICAL_SECTION, watch->message_lock);
1691 CloseHandle (watch->message_sent_event);
1692 CloseHandle (watch->message_received_event);
1694 g_slice_free (WatchThreadState, watch);
1698 /* This function assumes you hold the message lock! */
1700 watch_stop_unlocked (GRegistryBackend *self)
1702 WatchThreadState *watch = self->watch;
1704 g_return_if_fail (watch != NULL);
1706 watch->message.type = WATCH_THREAD_STOP;
1707 SetEvent (watch->message_sent_event);
1709 /* This is signalled as soon as the message is received. We must not return
1710 * while the watch thread is still firing off callbacks. Freeing all of the
1711 * memory is done in the watch thread after this is signalled.
1713 result = WaitForSingleObject (watch->message_received_event, INFINITE);
1714 if (result != WAIT_OBJECT_0)
1716 g_warning ("gregistrybackend: unable to stop watch thread.");
1720 LeaveCriticalSection (watch->message_lock);
1721 DeleteCriticalSection (watch->message_lock);
1722 DeleteCriticalSection (self->cache_lock);
1723 g_slice_free (CRITICAL_SECTION, watch->message_lock);
1724 g_slice_free (CRITICAL_SECTION, self->cache_lock);
1725 CloseHandle (watch->message_sent_event);
1726 CloseHandle (watch->message_received_event);
1727 CloseHandle (watch->thread);
1728 g_slice_free (WatchThreadState, watch);
1730 trace ("\nwatch thread: %x: all data freed.\n", self);
1735 watch_add_notify (GRegistryBackend *self,
1738 gchar *gsettings_prefix)
1740 WatchThreadState *watch = self->watch;
1742 RegistryCacheItem *cache_item;
1745 g_return_val_if_fail (watch != NULL, FALSE);
1746 trace ("watch_add_notify: prefix %s.\n", gsettings_prefix);
1748 /* Duplicate tree into the cache in the main thread, before we add the notify: if we do it in the
1749 * thread we can miss changes while we are caching.
1751 EnterCriticalSection (self->cache_lock);
1752 cache_node = registry_cache_get_node_for_key (self->cache_root, gsettings_prefix, TRUE);
1754 g_return_val_if_fail (cache_node != NULL, FALSE);
1755 g_return_val_if_fail (cache_node->data != NULL, FALSE);
1757 cache_item = cache_node->data;
1759 cache_item->subscription_count ++;
1760 if (cache_item->subscription_count > 1)
1762 trace ("watch_add_notify: prefix %s already watched, %i subscribers.\n",
1763 gsettings_prefix, cache_item->subscription_count);
1767 registry_cache_ref_tree (cache_node);
1768 registry_cache_update (self, hpath, gsettings_prefix, NULL, cache_node, 0, NULL);
1769 //registry_cache_dump (self->cache_root, NULL);
1770 LeaveCriticalSection (self->cache_lock);
1772 EnterCriticalSection (watch->message_lock);
1773 watch->message.type = WATCH_THREAD_ADD_WATCH;
1774 watch->message.watch.event = event;
1775 watch->message.watch.hpath = hpath;
1776 watch->message.watch.prefix = gsettings_prefix;
1777 watch->message.watch.cache_node = cache_node;
1779 SetEvent (watch->message_sent_event);
1781 /* Wait for the received event in return, to avoid sending another message before the first
1782 * one was received. If it takes > 200ms there is a possible race but the worst outcome is
1783 * a notification is ignored.
1785 result = WaitForSingleObject (watch->message_received_event, 200);
1787 if (result != WAIT_OBJECT_0)
1788 trace ("watch thread is slow to respond - notification may not be added.");
1790 LeaveCriticalSection (watch->message_lock);
1797 watch_remove_notify (GRegistryBackend *self,
1798 const gchar *key_name)
1800 WatchThreadState *watch = self->watch;
1803 if (self->watch == NULL)
1804 /* Here we assume that the unsubscribe message is for somewhere that was
1805 * deleted, and so it has already been removed and the watch thread has
1810 EnterCriticalSection (watch->message_lock);
1811 watch->message.type = WATCH_THREAD_REMOVE_WATCH;
1812 watch->message.watch.prefix = g_strdup (key_name);
1814 SetEvent (watch->message_sent_event);
1816 /* Wait for the received event in return, to avoid sending another message before the first
1819 result = WaitForSingleObject (watch->message_received_event, INFINITE);
1821 if (result != ERROR_SUCCESS)
1822 g_warning ("unsubscribe from %s: message not acknowledged\n", key_name);
1824 if (g_atomic_int_get (&watch->watches_remaining) >= MAX_WATCHES)
1825 /* Stop it before any new ones can get added and confuse things */
1826 watch_stop_unlocked (self);
1828 LeaveCriticalSection (watch->message_lock);
1831 /* dconf semantics are: if the key ends in /, watch the keys underneath it - if not, watch that
1832 * key. Our job is easier because keys and values are separate.
1835 g_registry_backend_subscribe (GSettingsBackend *backend,
1836 const char *key_name)
1838 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
1839 gchar *path_name, *value_name = NULL;
1844 if (self->watch == NULL)
1845 if (!watch_start (self))
1848 if (g_atomic_int_dec_and_test (&self->watch->watches_remaining))
1850 g_atomic_int_inc (&self->watch->watches_remaining);
1851 g_warning ("subscribe() failed: only %i different paths may be watched.\n", MAX_WATCHES);
1855 path_name = parse_key (key_name, self->base_path, &value_name);
1857 /* Must check for this, otherwise strange crashes occur because the cache
1858 * node that is being watched gets freed. All path names to subscribe must
1861 if (value_name != NULL && *value_name != 0)
1862 g_warning ("subscribe() failed: path must end in a /, got %s\n", key_name);
1864 trace ("Subscribing to %s [registry %s / %s] - watch %x\n", key_name, path_name, value_name, self->watch);
1867 /* Give the caller the benefit of the doubt if the key doesn't exist and create it. The caller
1868 * is almost certainly a new g_settings with this path as base path. */
1869 result = RegCreateKeyExA (HKEY_CURRENT_USER, path_name, 0, NULL, 0, KEY_READ, NULL, &hpath,
1873 if (result != ERROR_SUCCESS)
1875 g_message_win32_error (result, "gregistrybackend: Unable to subscribe to key %s.", key_name);
1876 g_atomic_int_inc (&self->watch->watches_remaining);
1880 event = CreateEvent (NULL, FALSE, FALSE, NULL);
1883 g_message_win32_error (result, "gregistrybackend: CreateEvent failed.\n");
1884 g_atomic_int_inc (&self->watch->watches_remaining);
1885 RegCloseKey (hpath);
1889 /* The actual watch is added by the thread, which has to re-subscribe each time it
1890 * receives a change. */
1891 if (!watch_add_notify (self, event, hpath, g_strdup (key_name)))
1892 g_atomic_int_inc (&self->watch->watches_remaining);
1896 g_registry_backend_unsubscribe (GSettingsBackend *backend,
1897 const char *key_name)
1899 trace ("unsubscribe: %s.\n", key_name);
1901 watch_remove_notify (G_REGISTRY_BACKEND (backend), key_name);
1905 /********************************************************************************
1906 * Object management junk
1907 ********************************************************************************/
1910 g_registry_backend_new (void) {
1911 return g_object_new (G_TYPE_REGISTRY_BACKEND, NULL);
1915 g_registry_backend_finalize (GObject *object)
1917 GRegistryBackend *self = G_REGISTRY_BACKEND (object);
1918 RegistryCacheItem *item;
1920 item = self->cache_root->data;
1921 g_warn_if_fail (item->ref_count == 1);
1923 _free_cache_item (item);
1924 g_node_destroy (self->cache_root);
1926 if (self->watch != NULL)
1928 EnterCriticalSection (self->watch->message_lock);
1929 watch_stop_unlocked (self);
1932 g_free (self->base_path);
1936 g_registry_backend_class_init (GRegistryBackendClass *class)
1938 GSettingsBackendClass *backend_class = G_SETTINGS_BACKEND_CLASS (class);
1939 GObjectClass *object_class = G_OBJECT_CLASS (class);
1941 object_class->finalize = g_registry_backend_finalize;
1943 backend_class->read = g_registry_backend_read;
1944 backend_class->write = g_registry_backend_write;
1945 backend_class->write_tree = g_registry_backend_write_tree;
1946 backend_class->reset = g_registry_backend_reset;
1947 backend_class->get_writable = g_registry_backend_get_writable;
1948 backend_class->get_permission = g_registry_backend_get_permission;
1949 backend_class->subscribe = g_registry_backend_subscribe;
1950 backend_class->unsubscribe = g_registry_backend_unsubscribe;
1954 g_registry_backend_init (GRegistryBackend *self)
1956 self->base_path = g_strdup_printf ("Software\\GSettings");
1958 RegistryCacheItem *item = g_slice_new (RegistryCacheItem);
1959 item->value.type = REG_NONE;
1960 item->value.ptr = NULL;
1961 item->name = g_strdup ("<root>");
1962 item->ref_count = 1;
1963 self->cache_root = g_node_new (item);