2 * Copyright © 2009-10 Sam Thursfield
4 * SPDX-License-Identifier: LGPL-2.1-or-later
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 * Author: Sam Thursfield <ssssam@gmail.com>
22 /* GRegistrySettingsBackend implementation notes:
24 * - All settings are stored under the registry path given at construction
25 * time. Permissions and system-wide defaults are not implemented and will
26 * probably always be out of scope of the Windows port of GLib.
28 * - The registry type system is limited. Most GVariant types are stored as
29 * literals via g_variant_print/parse(). Strings are stored without the
30 * quotes that GVariant requires. Integer types are stored as native
31 * REG_DWORD or REG_QWORD. The REG_MULTI_SZ (string array) type could be
32 * used to avoid flattening container types.
34 * - Notifications are handled; the change event is watched for in a separate
35 * thread (Windows does not provide a callback API) which sends them with
36 * g_idle_add to the GLib main loop. The threading is done using Windows
37 * API functions, so there is no dependence on GThread.
39 * - Windows doesn't tell us which value has changed. This means we have to
40 * maintain a cache of every stored value so we can play spot the
41 * difference. This should not be a performance issue because if you are
42 * storing thousands of values in GSettings, you are probably using it
45 * - The cache stores the value as a registry type. Because many variants are
46 * stored as string representations, values which have changed equality but
47 * not equivalence may trigger spurious change notifications. GSettings
48 * users must already deal with this possibility and converting all data to
49 * GVariant values would be more effort.
51 * - Because we have to cache every registry value locally, reads are done
52 * from the cache rather than directly from the registry. Writes update
53 * both. This means that the backend will not work if the watch thread is
54 * not running. A GSettings object always subscribes to changes so we can
55 * be sure that the watch thread will be running, but if for some reason
56 * the backend is being used directly you should bear that in mind.
58 * - The registry is totally user-editable, so we are very forgiving about
59 * errors in the data we get.
61 * - The registry uses backslashes as path separators. GSettings keys only
62 * allow [A-Za-z\-] so no escaping is needed. No attempt is made to solve
63 * clashes between keys differing only in case.
65 * - RegCreateKeyW is used - We should always make the UTF-8 -> UTF-16
66 * conversion ourselves to avoid problems when the system language changes.
68 * - The Windows registry has the following limitations: a key may not exceed
69 * 255 characters, an entry's value may not exceed 16,383 characters, and
70 * all the values of a key may not exceed 65,535 characters.
73 * * in GSettings, a 'key' is eg. /desktop/gnome/background/primary-color
74 * * in the registry, the 'key' is path, which contains some 'values'.
75 * * in this file, any GSettings key is a 'key', while a registry key is
76 * termed a 'path', which contains 'values'.
78 * - My set of tests for this backend are currently at:
79 * http://gitorious.org/gsettings-gtk/gsettings-test.git
81 * - There is an undocumented function in ntdll.dll which might be more
82 * than RegNotifyChangeKeyValue(), NtNotifyChangeKey:
83 * http://source.winehq.org/source/dlls/ntdll/reg.c#L618
84 * http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Key/NtNotifyChangeKey.html
86 * - If updating the cache ever becomes a performance issue it may make sense
87 * to use a red-black tree, but I don't currently think it's worth the time
92 #include "gregistrysettingsbackend.h"
93 #include "gsettingsbackend.h"
94 #include "gsettingsbackendinternal.h"
95 #include "giomodule-priv.h"
103 /* GSettings' limit */
104 #define MAX_KEY_NAME_LENGTH 128
106 /* Testing (on Windows XP SP3) shows that WaitForMultipleObjects fails with
107 * "The parameter is incorrect" after 64 watches. We need one for the
108 * message_sent cond, which is allowed for in the way the watches_remaining
111 #define MAX_WATCHES 64
113 /* A watch on one registry path and its subkeys */
122 /* Simple message passing for the watch thread. Not enough traffic to
128 WATCH_THREAD_ADD_WATCH,
129 WATCH_THREAD_REMOVE_WATCH,
131 } WatchThreadMessageType;
135 WatchThreadMessageType type;
137 } WatchThreadMessage;
141 GSettingsBackend *owner;
144 /* Details of the things we are watching. */
145 int watches_remaining;
146 GPtrArray *events, *handles, *prefixes, *cache_nodes;
148 /* Communication with the main thread. Only one message is stored at a time,
149 * to make sure that messages are acknowledged before being overwritten we
150 * create two events - one is signalled when a new message is set, the
151 * other is signalled by the thread when it has processed the message.
153 WatchThreadMessage message;
154 CRITICAL_SECTION *message_lock;
155 HANDLE message_sent_event, message_received_event;
158 #define G_TYPE_REGISTRY_SETTINGS_BACKEND (g_registry_settings_backend_get_type ())
159 #define G_REGISTRY_SETTINGS_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
160 G_TYPE_REGISTRY_SETTINGS_BACKEND, GRegistrySettingsBackend))
161 #define G_IS_REGISTRY_SETTINGS_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
162 G_TYPE_REGISTRY_SETTINGS_BACKEND))
165 PROP_REGISTRY_KEY = 1,
166 } GRegistrySettingsBackendProperty;
168 typedef GSettingsBackendClass GRegistrySettingsBackendClass;
171 GSettingsBackend parent_instance;
175 gunichar2 *base_pathw;
177 /* A stored copy of the whole tree being watched. When we receive a change notification
178 * we have to check against this to see what has changed ... every time ...*/
179 CRITICAL_SECTION *cache_lock;
182 WatchThreadState *watch;
183 } GRegistrySettingsBackend;
185 G_DEFINE_TYPE_WITH_CODE (GRegistrySettingsBackend,
186 g_registry_settings_backend,
187 G_TYPE_SETTINGS_BACKEND,
188 _g_io_modules_ensure_extension_points_registered ();
189 g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
190 g_define_type_id, "registry", 90))
192 /**********************************************************************************
194 **********************************************************************************/
198 trace (const char *format,
202 va_list va; va_start (va, format);
203 vprintf (format, va);
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. */
213 static void G_GNUC_PRINTF (2, 3)
214 g_message_win32_error (DWORD result_code,
221 gchar *win32_message;
223 g_return_if_fail (result_code != 0);
225 va_start (va, format);
226 message = g_strdup_vprintf (format, va);
227 win32_error = g_win32_error_message (result_code);
228 win32_message = g_strdup_printf ("%s: %s", message, win32_error);
230 g_free (win32_error);
232 if (result_code == ERROR_KEY_DELETED)
233 trace ("(%s)", win32_message);
235 g_message ("%s", win32_message);
237 g_free (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++)
280 g_variant_get_as_dword (GVariant *variant)
282 switch (g_variant_get_type_string (variant)[0])
285 return g_variant_get_boolean (variant);
287 return g_variant_get_byte (variant);
289 return g_variant_get_int16 (variant);
291 return g_variant_get_uint16 (variant);
293 return g_variant_get_int32 (variant);
295 return g_variant_get_uint32 (variant);
297 g_warn_if_reached ();
303 g_variant_get_as_qword (GVariant *variant)
305 switch (g_variant_get_type_string (variant)[0])
308 return g_variant_get_int64 (variant);
310 return g_variant_get_uint64 (variant);
312 g_warn_if_reached ();
318 handle_read_error (LONG result,
319 const gchar *path_name,
320 const gchar *value_name)
322 /* file not found means key value not set, this isn't an error for us. */
323 if (result != ERROR_FILE_NOT_FOUND)
324 g_message_win32_error (result, "Unable to query value %s/%s",
325 path_name, value_name);
333 static const HandleNamePair predefined_key_names[] = {
334 { HKEY_CLASSES_ROOT, "HKEY_CLASSES_ROOT" },
335 { HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG" },
336 { HKEY_CURRENT_USER, "HKEY_CURRENT_USER" },
337 { HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE" },
338 { HKEY_USERS, "HKEY_USERS" }
342 predefined_key_to_string (HKEY key)
344 for (gsize i = 0; i < G_N_ELEMENTS (predefined_key_names); i++)
346 if (predefined_key_names[i].handle == key)
347 return predefined_key_names[i].name;
350 g_warning ("gregistrysettingsbackend: unexpected root key (%p)", key);
355 split_registry_path (const gchar *full_path,
358 g_assert (full_path != NULL);
360 for (gsize i = 0; i < G_N_ELEMENTS (predefined_key_names); i++)
362 const gchar *root_name = predefined_key_names[i].name;
364 if (g_str_has_prefix (full_path, root_name))
366 const gchar *rest = full_path + strlen (root_name);
370 if (root_key != NULL)
371 *root_key = predefined_key_names[i].handle;
381 /***************************************************************************
382 * Cache of registry values
383 ***************************************************************************/
385 /* Generic container for registry values */
390 gint dword; /* FIXME: could inline QWORD on 64-bit systems too */
396 registry_value_dump (RegistryValue value)
398 if (value.type == REG_DWORD)
399 return g_strdup_printf ("%d", value.dword);
400 else if (value.type == REG_QWORD)
401 return g_strdup_printf ("%"G_GINT64_FORMAT, value.ptr == NULL ? 0: *(DWORDLONG *)value.ptr);
402 else if (value.type == REG_SZ)
403 return g_strdup_printf ("%s", (char *)value.ptr);
404 else if (value.type == REG_NONE)
405 return g_strdup_printf ("<empty>");
407 return g_strdup_printf ("<invalid>");
411 registry_value_free (RegistryValue value)
413 if (value.type == REG_SZ || value.type == REG_QWORD)
416 value.type = REG_NONE;
420 /* The registry cache is stored as a tree, for easy traversal. Right now we
421 * don't sort it in a clever way. Each node corresponds to a path element
422 * ('key' in registry terms) or a value.
424 * Each subscription uses the same cache. Because GSettings can subscribe to
425 * the tree at any node any number of times, we need to reference count the
430 /* Component of path that this node represents */
433 /* If a watch is subscribed at this point (subscription_count > 0) we can
434 * block its next notification. This is useful because if two watches cover
435 * the same path, both will trigger when it changes. It also allows changes
436 * done by the application to be ignored by the watch thread.
438 gint32 block_count : 8;
440 /* Number of times g_settings_subscribe has been called for this location
441 * (I guess you can't subscribe more than 16383 times) */
442 gint32 subscription_count : 14;
444 gint32 ref_count : 9;
451 registry_cache_add_item (GNode *parent,
456 RegistryCacheItem *item;
459 g_return_val_if_fail (name != NULL, NULL);
460 g_return_val_if_fail (parent != NULL, NULL);
462 item = g_slice_new (RegistryCacheItem);
464 /* Ref count should be the number of watch points above this node */
465 item->ref_count = ref_count;
467 item->name = g_strdup (name);
469 item->subscription_count = 0;
470 item->block_count = 0;
471 item->readable = FALSE;
473 trace ("\tregistry cache: adding %s to %s\n",
474 name, ((RegistryCacheItem *)parent->data)->name);
476 cache_node = g_node_new (item);
477 g_node_append (parent, cache_node);
482 /* The reference counting of cache tree nodes works like this: when a node is
483 * subscribed to (GSettings wants us to watch that path and everything below
484 * it) the reference count of that node and everything below is increased, as
485 * well as each parent up to the root.
489 _ref_down (GNode *node)
491 RegistryCacheItem *item = node->data;
493 g_node_children_foreach (node, G_TRAVERSE_ALL,
494 (GNodeForeachFunc)_ref_down, NULL);
499 registry_cache_ref_tree (GNode *tree)
501 RegistryCacheItem *item = tree->data;
502 GNode *node = tree->parent;
504 g_return_if_fail (tree != NULL);
508 g_node_children_foreach (tree, G_TRAVERSE_ALL,
509 (GNodeForeachFunc)_ref_down, NULL);
511 for (node = tree->parent; node; node = node->parent)
519 registry_cache_item_free (RegistryCacheItem *item)
521 trace ("\t -- Free node %s\n", item->name);
524 registry_value_free (item->value);
525 g_slice_free (RegistryCacheItem, item);
528 /* Unreferencing has to be done bottom-up */
530 _unref_node (GNode *node)
532 RegistryCacheItem *item = node->data;
536 g_warn_if_fail (item->ref_count >= 0);
538 if (item->ref_count == 0)
540 registry_cache_item_free (item);
541 g_node_destroy (node);
546 _unref_down (GNode *node)
548 g_node_children_foreach (node, G_TRAVERSE_ALL,
549 (GNodeForeachFunc)_unref_down, NULL);
554 registry_cache_unref_tree (GNode *tree)
556 GNode *parent = tree->parent, *next_parent;
562 next_parent = parent->parent;
563 _unref_node (parent);
564 parent = next_parent;
570 registry_cache_dump (GNode *cache_node,
573 RegistryCacheItem *item = cache_node->data;
575 int depth = GPOINTER_TO_INT(data),
579 g_return_if_fail (cache_node != NULL);
581 for (i=0; i<depth; i++)
584 g_print ("*root*\n");
586 g_print ("'%s' [%i] @ %x = %s\n", item->name, item->ref_count, (guint)cache_node,
587 registry_value_dump (item->value));
588 g_node_children_foreach (cache_node, G_TRAVERSE_ALL, registry_cache_dump,
589 GINT_TO_POINTER (new_depth));
597 } RegistryCacheSearch;
600 registry_cache_find_compare (GNode *node,
603 RegistryCacheSearch *search = data;
604 RegistryCacheItem *item = node->data;
606 if (item == NULL) /* root node */
609 g_return_val_if_fail (search->name != NULL, FALSE);
610 g_return_val_if_fail (item->name != NULL, FALSE);
612 if (strcmp (search->name, item->name) == 0)
614 search->result = node;
622 registry_cache_find_immediate_child (GNode *node,
625 RegistryCacheSearch search;
627 search.result = NULL;
630 g_node_traverse (node, G_POST_ORDER, G_TRAVERSE_ALL, 2,
631 registry_cache_find_compare, &search);
633 return search.result;
637 registry_cache_get_node_for_key_recursive (GNode *node,
639 gboolean create_if_not_found,
640 gint n_parent_watches)
642 RegistryCacheItem *item;
643 gchar *component = key_name;
644 gchar *c = strchr (component, '/');
650 /* We count up how many watch points we travel through finding this node,
651 * because a new node should have as many references as there are watches at
652 * points above it in the tree.
655 if (item->subscription_count > 0)
658 child = registry_cache_find_immediate_child (node, component);
659 if (child == NULL && create_if_not_found)
661 RegistryValue null_value = { REG_NONE, {0} };
663 child = registry_cache_add_item (node, component,
664 null_value, n_parent_watches);
666 trace ("\tget node for key recursive: new %x = %s.\n", node, component);
669 /* We are done if there are no more path components. Allow for a trailing /. */
670 if (child == NULL || c == NULL || *(c + 1) == 0)
673 trace ("get node for key recursive: next: %s.\n", c + 1);
675 return registry_cache_get_node_for_key_recursive (child, c + 1,
680 /* Look up a GSettings key in the cache. */
682 registry_cache_get_node_for_key (GNode *root,
683 const gchar *key_name,
684 gboolean create_if_not_found)
687 GNode *result = NULL;
688 gchar *component, *c;
690 g_return_val_if_fail (key_name != NULL, NULL);
692 if (key_name[0] == '/')
695 /* Ignore preceding / */
696 component = g_strdup (key_name);
697 c = strchr (component, '/');
708 child = registry_cache_find_immediate_child (root, component);
709 if (child == NULL && create_if_not_found)
711 RegistryValue null_value = { REG_NONE, {0} };
713 /* Reference count is set to 0, tree should be referenced by the caller */
714 child = registry_cache_add_item (root, component,
717 trace ("get_node_for_key: New node for component '%s'\n", component);
722 else if (child != NULL)
723 result = registry_cache_get_node_for_key_recursive (child, c + 1,
724 create_if_not_found, 0);
731 /* Check the cache node against the registry key it represents. Return TRUE if
732 * they differ, and update the cache with the new value.
735 registry_cache_update_node (GNode *cache_node,
736 RegistryValue registry_value)
738 RegistryCacheItem *cache_item;
740 g_return_val_if_fail (cache_node != NULL, FALSE);
741 g_return_val_if_fail (cache_node->data != NULL, FALSE);
743 cache_item = cache_node->data;
745 if (registry_value.type != cache_item->value.type)
747 /* The type has changed. Update cache item and register it as changed.
748 * Either the schema has changed and this is entirely legitimate, or
749 * whenever the app reads the key it will get the default value due to
752 cache_item->value = registry_value;
756 switch (registry_value.type)
760 if (cache_item->value.dword == registry_value.dword)
764 cache_item->value.dword = registry_value.dword;
770 g_return_val_if_fail (registry_value.ptr != NULL &&
771 cache_item->value.ptr != NULL, FALSE);
773 if (memcmp (registry_value.ptr, cache_item->value.ptr, 8)==0)
775 g_free (registry_value.ptr);
780 g_free (cache_item->value.ptr);
781 cache_item->value.ptr = registry_value.ptr;
787 /* Value should not exist if it is NULL, an empty string is "" */
788 g_return_val_if_fail (cache_item->value.ptr != NULL, FALSE);
789 g_return_val_if_fail (registry_value.ptr != NULL, FALSE);
791 if (strcmp (registry_value.ptr, cache_item->value.ptr) == 0)
793 g_free (registry_value.ptr);
798 g_free (cache_item->value.ptr);
799 cache_item->value.ptr = registry_value.ptr;
804 g_warning ("gregistrysettingsbackend: registry_cache_update_node: Unhandled value type");
809 /* Blocking notifications is a useful optimisation. When a change is made
810 * through GSettings we update the cache manually, but a notification is
811 * triggered as well. This function is also used for nested notifications,
812 * eg. if /test and /test/foo are watched, and /test/foo/value is changed then
813 * we will get notified both for /test/foo and /test and it is helpful to block
817 registry_cache_block_notification (GNode *node)
819 RegistryCacheItem *item = node->data;
821 g_return_if_fail (node != NULL);
823 if (item->subscription_count > 0)
826 if (node->parent != NULL)
827 registry_cache_block_notification (node->parent);
830 static void registry_cache_destroy_tree (GNode *node,
831 WatchThreadState *self);
833 /***************************************************************************
834 * Reading and writing
835 ***************************************************************************/
838 registry_read (HKEY hpath,
839 const gchar *path_name,
840 const gchar *value_name,
841 RegistryValue *p_value)
844 DWORD value_data_size;
846 gunichar2 *value_namew;
848 g_return_val_if_fail (p_value != NULL, FALSE);
850 p_value->type = REG_NONE;
853 value_namew = g_utf8_to_utf16 (value_name, -1, NULL, NULL, NULL);
855 result = RegQueryValueExW (hpath, value_namew, 0, &p_value->type, NULL, &value_data_size);
856 if (result != ERROR_SUCCESS)
858 handle_read_error (result, path_name, value_name);
859 g_free (value_namew);
863 if (p_value->type == REG_SZ && value_data_size == 0)
865 p_value->ptr = g_strdup ("");
866 g_free (value_namew);
870 if (p_value->type == REG_DWORD)
871 /* REG_DWORD is inlined */
872 buffer = (void *)&p_value->dword;
874 buffer = p_value->ptr = g_malloc (value_data_size);
876 result = RegQueryValueExW (hpath, value_namew, 0, NULL, (LPBYTE)buffer, &value_data_size);
877 g_free (value_namew);
879 if (result != ERROR_SUCCESS)
881 handle_read_error (result, path_name, value_name);
883 if (p_value->type != REG_DWORD)
889 if (p_value->type == REG_SZ)
891 gchar *valueu8 = g_utf16_to_utf8 (p_value->ptr, -1, NULL, NULL, NULL);
892 g_free (p_value->ptr);
893 p_value->ptr = valueu8;
900 g_registry_settings_backend_read (GSettingsBackend *backend,
901 const gchar *key_name,
902 const GVariantType *expected_type,
903 gboolean default_value)
905 GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
907 RegistryValue registry_value;
908 GVariant *gsettings_value = NULL;
909 gchar *gsettings_type;
911 g_return_val_if_fail (expected_type != NULL, NULL);
916 /* Simply read from the cache, which is updated from the registry by the
917 * watch thread as soon as changes can propagate. Any changes not yet in the
918 * cache will have the 'changed' signal emitted after this function returns.
920 EnterCriticalSection (self->cache_lock);
921 cache_node = registry_cache_get_node_for_key (self->cache_root, key_name, FALSE);
922 LeaveCriticalSection (self->cache_lock);
924 trace ("Reading key %s, cache node %x\n", key_name, cache_node);
926 /* Maybe it's not set, we can return to default */
927 if (cache_node == NULL)
930 trace ("\t- cached value %s\n", registry_value_dump (((RegistryCacheItem *)cache_node->data)->value));
932 registry_value = ((RegistryCacheItem *)cache_node->data)->value;
934 gsettings_type = g_variant_type_dup_string (expected_type);
936 /* The registry is user-editable, so we need to be fault-tolerant here. */
937 switch (gsettings_type[0])
945 if (registry_value.type == REG_DWORD)
946 gsettings_value = g_variant_new (gsettings_type, registry_value.dword);
951 if (registry_value.type == REG_QWORD)
953 DWORDLONG qword_value = *(DWORDLONG *)registry_value.ptr;
954 gsettings_value = g_variant_new (gsettings_type, qword_value);
959 if (registry_value.type == REG_SZ)
961 if (gsettings_type[0] == 's')
962 gsettings_value = g_variant_new_string ((char *)registry_value.ptr);
965 GError *error = NULL;
967 gsettings_value = g_variant_parse (expected_type, registry_value.ptr,
971 g_message ("gregistrysettingsbackend: error parsing key %s: %s",
972 key_name, error->message);
978 g_free (gsettings_type);
980 return gsettings_value;
986 GRegistrySettingsBackend *self;
991 g_registry_settings_backend_write_one (const char *key_name,
995 GRegistrySettingsBackend *self;
996 RegistryWrite *action;
1001 gunichar2 *path_namew;
1002 gchar *value_name = NULL;
1003 gunichar2 *value_namew;
1004 DWORD value_data_size;
1006 gunichar2 *value_dataw;
1010 const gchar *type_string;
1012 type_string = g_variant_get_type_string (variant);
1014 self = G_REGISTRY_SETTINGS_BACKEND (action->self);
1015 hroot = action->hroot;
1017 value.type = REG_NONE;
1020 switch (type_string[0])
1028 value.type = REG_DWORD;
1029 value.dword = g_variant_get_as_dword (variant);
1030 value_data_size = 4;
1031 value_data = &value.dword;
1036 value.type = REG_QWORD;
1037 value.ptr = g_malloc (8);
1038 *(DWORDLONG *)value.ptr = g_variant_get_as_qword (variant);
1039 value_data_size = 8;
1040 value_data = value.ptr;
1044 value.type = REG_SZ;
1045 if (type_string[0] == 's')
1048 value.ptr = g_strdup (g_variant_get_string (variant, &length));
1049 value_data_size = length + 1;
1050 value_data = value.ptr;
1054 GString *value_string;
1055 value_string = g_variant_print_string (variant, NULL, FALSE);
1056 value_data_size = value_string->len + 1;
1057 value.ptr = value_data = g_string_free (value_string, FALSE);
1062 /* First update the cache, because the value may not have changed and we can
1065 * If 'value' has changed then its memory will not be freed by update_node(),
1066 * because it will be stored in the node.
1068 EnterCriticalSection (self->cache_lock);
1069 node = registry_cache_get_node_for_key (self->cache_root, key_name, TRUE);
1070 changed = registry_cache_update_node (node, value);
1071 LeaveCriticalSection (self->cache_lock);
1076 /* Block the next notification to any watch points above this location,
1077 * because they will each get triggered on a change that is already updated
1080 registry_cache_block_notification (node);
1082 path_name = parse_key (key_name, NULL, &value_name);
1084 trace ("Set key: %s / %s\n", path_name, value_name);
1086 path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
1088 /* Store the value in the registry */
1089 result = RegCreateKeyExW (hroot, path_namew, 0, NULL, 0, KEY_WRITE, NULL, &hpath, NULL);
1090 if (result != ERROR_SUCCESS)
1092 g_message_win32_error (result, "gregistrysettingsbackend: opening key %s failed",
1094 registry_value_free (value);
1095 g_free (path_namew);
1100 g_free (path_namew);
1102 value_namew = g_utf8_to_utf16 (value_name, -1, NULL, NULL, NULL);
1106 switch (type_string[0])
1118 value_dataw = g_utf8_to_utf16 (value_data, -1, NULL, NULL, NULL);
1119 value_data = value_dataw;
1120 value_data_size = (DWORD)((wcslen (value_data) + 1) * sizeof (gunichar2));
1124 result = RegSetValueExW (hpath, value_namew, 0, value.type, value_data, value_data_size);
1126 if (result != ERROR_SUCCESS)
1127 g_message_win32_error (result, "gregistrysettingsbackend: setting value %s\\%s\\%s\\%s failed.\n",
1128 predefined_key_to_string (self->base_key),
1129 self->base_path, path_name, value_name);
1131 /* If the write fails then it will seem like the value has changed until the
1132 * next execution (because we wrote to the cache first). There's no reason
1133 * for it to fail unless something is weirdly broken, however.
1136 RegCloseKey (hpath);
1138 g_free (value_namew);
1139 g_free (value_dataw);
1144 /* The dconf write policy is to do the write while making out it succeeded,
1145 * and then backtrack if it didn't. The registry functions are synchronous so
1146 * we can't do that. */
1149 g_registry_settings_backend_write (GSettingsBackend *backend,
1150 const gchar *key_name,
1152 gpointer origin_tag)
1154 GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
1157 RegistryWrite action;
1159 result = RegCreateKeyExW (self->base_key, self->base_pathw, 0, NULL, 0,
1160 KEY_WRITE, NULL, &hroot, NULL);
1161 if (result != ERROR_SUCCESS)
1163 trace ("Error opening/creating key %s\\%s.\n",
1164 predefined_key_to_string (self->base_key),
1170 action.hroot = hroot;
1171 g_registry_settings_backend_write_one (key_name, value, &action);
1172 g_settings_backend_changed (backend, key_name, origin_tag);
1174 RegCloseKey (hroot);
1180 g_registry_settings_backend_write_tree (GSettingsBackend *backend,
1182 gpointer origin_tag)
1184 GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
1187 RegistryWrite action;
1189 result = RegCreateKeyExW (self->base_key, self->base_pathw, 0, NULL, 0,
1190 KEY_WRITE, NULL, &hroot, NULL);
1191 if (result != ERROR_SUCCESS)
1193 trace ("Error opening/creating key %s\\%s.\n",
1194 predefined_key_to_string (self->base_key),
1200 action.hroot = hroot;
1201 g_tree_foreach (values, (GTraverseFunc)g_registry_settings_backend_write_one,
1204 g_settings_backend_changed_tree (backend, values, origin_tag);
1205 RegCloseKey (hroot);
1211 g_registry_settings_backend_reset (GSettingsBackend *backend,
1212 const gchar *key_name,
1213 gpointer origin_tag)
1215 GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
1217 gunichar2 *path_namew;
1218 gchar *value_name = NULL;
1219 gunichar2 *value_namew;
1224 /* Remove from cache */
1225 EnterCriticalSection (self->cache_lock);
1226 cache_node = registry_cache_get_node_for_key (self->cache_root, key_name, FALSE);
1228 registry_cache_destroy_tree (cache_node, self->watch);
1229 LeaveCriticalSection (self->cache_lock);
1231 /* Remove from the registry */
1232 path_name = parse_key (key_name, self->base_path, &value_name);
1233 path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
1235 result = RegOpenKeyExW (self->base_key, path_namew, 0, KEY_SET_VALUE, &hpath);
1236 g_free (path_namew);
1238 if (result != ERROR_SUCCESS)
1240 g_message_win32_error (result, "Registry: resetting key '%s\\%s'",
1241 predefined_key_to_string (self->base_key),
1247 value_namew = g_utf8_to_utf16 (value_name, -1, NULL, NULL, NULL);
1249 result = RegDeleteValueW (hpath, value_namew);
1250 g_free (value_namew);
1251 RegCloseKey (hpath);
1253 if (result != ERROR_SUCCESS)
1255 g_message_win32_error (result, "Registry: resetting key '%s\\%s'",
1256 predefined_key_to_string (self->base_key),
1264 g_settings_backend_changed (backend, key_name, origin_tag);
1268 g_registry_settings_backend_get_writable (GSettingsBackend *backend,
1269 const gchar *key_name)
1271 GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
1273 gunichar2 *path_namew;
1274 gchar *value_name = NULL;
1278 path_name = parse_key (key_name, self->base_path, &value_name);
1279 path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
1281 /* Note: we create the key if it wasn't created yet, but it is not much
1282 * of a problem since at the end of the day we have to create it anyway
1283 * to read or to write from it
1285 result = RegCreateKeyExW (self->base_key, path_namew, 0, NULL, 0,
1286 KEY_WRITE, NULL, &hpath, NULL);
1287 g_free (path_namew);
1289 if (result != ERROR_SUCCESS)
1291 trace ("Error opening/creating key to check writability: %s\\%s.\n",
1292 predefined_key_to_string (self->base_key),
1300 RegCloseKey (hpath);
1305 /********************************************************************************
1306 * Spot-the-difference engine
1307 ********************************************************************************/
1310 _free_watch (WatchThreadState *self,
1315 registry_cache_item_reset_readable (GNode *node,
1318 RegistryCacheItem *item = node->data;
1319 item->readable = FALSE;
1322 /* Delete a node and any children, for when it has been deleted from the registry */
1324 registry_cache_destroy_tree (GNode *node,
1325 WatchThreadState *self)
1327 RegistryCacheItem *item = node->data;
1329 g_node_children_foreach (node, G_TRAVERSE_ALL,
1330 (GNodeForeachFunc)registry_cache_destroy_tree, self);
1332 if (item->subscription_count > 0)
1336 /* There must be some watches active if this node is a watch point */
1337 g_warn_if_fail (self->cache_nodes->len > 1);
1339 /* This is a watch point that has been deleted. Let's free the watch! */
1340 for (i = 1; i < self->cache_nodes->len; i++)
1342 if (g_ptr_array_index (self->cache_nodes, i) == node)
1346 if (i >= self->cache_nodes->len)
1347 g_warning ("watch thread: a watch point was deleted, but unable to "
1348 "find '%s' in the list of %i watch nodes\n", item->name,
1349 self->cache_nodes->len - 1);
1352 _free_watch (self, i, node);
1353 g_atomic_int_inc (&self->watches_remaining);
1356 registry_cache_item_free (node->data);
1357 g_node_destroy (node);
1360 /* One of these is sent down the pipe when something happens in the registry. */
1363 GRegistrySettingsBackend *self;
1364 gchar *prefix; /* prefix is a gsettings path, all items are subkeys of this. */
1365 GPtrArray *items; /* each item is a subkey below prefix that has changed. */
1370 RegistryEvent *event;
1371 gchar *current_key_name;
1375 mark_all_subkeys_as_changed (GNode *node,
1378 RegistryCacheItem *item = node->data;
1379 DeletedItemData *item_data = data;
1381 if (item_data->current_key_name == NULL)
1382 item_data->current_key_name = g_strdup (item->name);
1387 name = g_build_path ("/", item_data->current_key_name, item->name, NULL);
1388 g_free (item_data->current_key_name);
1389 item_data->current_key_name = name;
1392 /* Iterate until we find an item that is a value */
1393 if (item->value.type == REG_NONE)
1394 g_node_children_foreach (node, G_TRAVERSE_ALL,
1395 mark_all_subkeys_as_changed, data);
1397 g_ptr_array_add (item_data->event->items, item_data->current_key_name);
1401 registry_cache_remove_deleted (GNode *node,
1404 RegistryCacheItem *item = node->data;
1405 RegistryEvent *event = data;
1407 if (!item->readable)
1409 DeletedItemData item_data;
1411 item_data.event = event;
1412 item_data.current_key_name = NULL;
1414 mark_all_subkeys_as_changed (node, &item_data);
1415 registry_cache_destroy_tree (node, event->self->watch);
1419 /* Update cache from registry, and optionally report on the changes.
1421 * This function is sometimes called from the watch thread, with no locking. It
1422 * does call g_registry_settings_backend functions, but this is okay because they only
1423 * access self->base which is constant.
1425 * When looking at this code bear in mind the terminology: in the registry, keys
1426 * are containers that contain values, and other keys. Keys have a 'default'
1427 * value which we always ignore.
1429 * n_parent_watches: a counter used to set the reference count of any new nodes
1430 * that are created - they should have as many references as
1431 * there are notifications that are watching them.
1434 registry_cache_update (GRegistrySettingsBackend *self,
1436 const gchar *prefix,
1437 const gchar *partial_key_name,
1440 RegistryEvent *event)
1442 gunichar2 bufferw[MAX_KEY_NAME_LENGTH + 1];
1447 RegistryCacheItem *item;
1449 item = cache_node->data;
1451 if (item->subscription_count > 0)
1454 /* prefix is the level that all changes occur below; partial_key_name should
1455 * be NULL on the first call to this function */
1456 key_name = g_build_path ("/", prefix, partial_key_name, NULL);
1458 trace ("registry cache update: %s. Node %x has %i children\n", key_name,
1459 cache_node, g_node_n_children (cache_node));
1461 /* Start by zeroing 'readable' flag. When the registry traversal is done, any unreadable nodes
1462 * must have been deleted from the registry.
1464 g_node_children_foreach (cache_node, G_TRAVERSE_ALL,
1465 registry_cache_item_reset_readable, NULL);
1467 /* Recurse into each subpath at the current level, if any */
1471 DWORD bufferw_size = MAX_KEY_NAME_LENGTH + 1;
1474 result = RegEnumKeyExW (hpath, i++, bufferw, &bufferw_size, NULL, NULL, NULL, NULL);
1475 if (result != ERROR_SUCCESS)
1478 result = RegOpenKeyExW (hpath, bufferw, 0, KEY_READ, &hsubpath);
1479 if (result == ERROR_SUCCESS)
1482 RegistryCacheItem *child_item;
1483 gchar *new_partial_key_name;
1485 buffer = g_utf16_to_utf8 (bufferw, -1, NULL, NULL, NULL);
1489 subkey_node = registry_cache_find_immediate_child (cache_node, buffer);
1490 if (subkey_node == NULL)
1492 RegistryValue null_value = {REG_NONE, {0}};
1493 subkey_node = registry_cache_add_item (cache_node, buffer,
1494 null_value, n_watches);
1497 new_partial_key_name = g_build_path ("/", partial_key_name, buffer, NULL);
1498 registry_cache_update (self, hsubpath, prefix, new_partial_key_name,
1499 subkey_node, n_watches, event);
1500 g_free (new_partial_key_name);
1502 child_item = subkey_node->data;
1503 child_item->readable = TRUE;
1506 RegCloseKey (hsubpath);
1510 if (result != ERROR_NO_MORE_ITEMS)
1511 g_message_win32_error (result, "gregistrysettingsbackend: error enumerating subkeys for cache.");
1513 /* Enumerate each value at 'path' and check if it has changed */
1517 DWORD bufferw_size = MAX_KEY_NAME_LENGTH + 1;
1518 GNode *cache_child_node;
1519 RegistryCacheItem *child_item;
1520 RegistryValue value;
1521 gboolean changed = FALSE;
1523 result = RegEnumValueW (hpath, i++, bufferw, &bufferw_size, NULL, NULL, NULL, NULL);
1524 if (result != ERROR_SUCCESS)
1527 buffer = g_utf16_to_utf8 (bufferw, -1, NULL, NULL, NULL);
1529 if (buffer == NULL || buffer[0] == 0)
1531 /* This is the key's 'default' value, for which we have no use. */
1536 cache_child_node = registry_cache_find_immediate_child (cache_node, buffer);
1538 if (!registry_read (hpath, key_name, buffer, &value))
1544 trace ("\tgot value %s for %s, node %x\n",
1545 registry_value_dump (value), buffer, cache_child_node);
1547 if (cache_child_node == NULL)
1549 /* This is a new value */
1550 cache_child_node = registry_cache_add_item (cache_node, buffer, value,
1556 /* For efficiency, instead of converting every value back to a GVariant to
1557 * compare it, we compare them as registry values (integers, or string
1558 * representations of the variant). The spurious change notifications that may
1559 * result should not be a big issue.
1561 * Note that 'value' is swallowed or freed.
1563 changed = registry_cache_update_node (cache_child_node, value);
1566 child_item = cache_child_node->data;
1567 child_item->readable = TRUE;
1568 if (changed && event != NULL)
1572 if (partial_key_name == NULL)
1573 item_path = g_strdup (buffer);
1575 item_path = g_build_path ("/", partial_key_name, buffer, NULL);
1577 g_ptr_array_add (event->items, item_path);
1583 if (result != ERROR_NO_MORE_ITEMS)
1584 g_message_win32_error (result, "gregistrysettingsbackend: error enumerating values for cache");
1586 /* Any nodes now left unreadable must have been deleted, remove them from cache */
1587 g_node_children_foreach (cache_node, G_TRAVERSE_ALL,
1588 registry_cache_remove_deleted, event);
1590 trace ("registry cache update complete.\n");
1595 /***********************************************************************************
1596 * Thread to watch for registry change events
1597 ***********************************************************************************/
1599 /* Called by watch thread. Apply for notifications on a registry key and its subkeys. */
1601 registry_watch_key (HKEY hpath,
1604 return RegNotifyChangeKeyValue (hpath, TRUE,
1605 REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
1609 /* This handler runs in the main thread to emit the changed signals */
1611 watch_handler (RegistryEvent *event)
1613 trace ("Watch handler: got event in %s, items %i.\n", event->prefix, event->items->len);
1615 /* GSettings requires us to NULL-terminate the array. */
1616 g_ptr_array_add (event->items, NULL);
1617 g_settings_backend_keys_changed (G_SETTINGS_BACKEND (event->self), event->prefix,
1618 (gchar const **)event->items->pdata, NULL);
1620 g_ptr_array_free (event->items, TRUE);
1621 g_free (event->prefix);
1622 g_object_unref (event->self);
1623 g_slice_free (RegistryEvent, event);
1625 return G_SOURCE_REMOVE;
1629 _free_watch (WatchThreadState *self,
1637 g_return_if_fail (index > 0 && index < self->events->len);
1639 cond = g_ptr_array_index (self->events, index);
1640 hpath = g_ptr_array_index (self->handles, index);
1641 prefix = g_ptr_array_index (self->prefixes, index);
1643 trace ("Freeing watch %i [%s]\n", index, prefix);
1645 /* These can be NULL if the watch was already dead, this can happen when eg.
1646 * a key is deleted but GSettings is still subscribed to it - the watch is
1647 * kept alive so that the unsubscribe function works properly, but does not
1651 RegCloseKey (hpath);
1653 if (cache_node != NULL)
1655 //registry_cache_dump (G_REGISTRY_SETTINGS_BACKEND (self->owner)->cache_root, NULL);
1656 registry_cache_unref_tree (cache_node);
1662 /* As long as we remove from each array at the same time, it doesn't matter that
1663 * their orders get messed up - they all get messed up the same.
1665 g_ptr_array_remove_index_fast (self->handles, index);
1666 g_ptr_array_remove_index_fast (self->events, index);
1667 g_ptr_array_remove_index_fast (self->prefixes, index);
1668 g_ptr_array_remove_index_fast (self->cache_nodes, index);
1672 watch_thread_handle_message (WatchThreadState *self)
1674 switch (self->message.type)
1676 case WATCH_THREAD_NONE:
1677 trace ("watch thread: you woke me up for nothin', man!");
1680 case WATCH_THREAD_ADD_WATCH:
1682 RegistryWatch *watch = &self->message.watch;
1685 result = registry_watch_key (watch->hpath, watch->event);
1687 if (result == ERROR_SUCCESS)
1689 g_ptr_array_add (self->events, watch->event);
1690 g_ptr_array_add (self->handles, watch->hpath);
1691 g_ptr_array_add (self->prefixes, watch->prefix);
1692 g_ptr_array_add (self->cache_nodes, watch->cache_node);
1694 trace ("watch thread: new watch on %s, %i total\n", watch->prefix,
1699 g_message_win32_error (result, "watch thread: could not watch %s", watch->prefix);
1701 CloseHandle (watch->event);
1702 RegCloseKey (watch->hpath);
1703 g_free (watch->prefix);
1704 registry_cache_unref_tree (watch->cache_node);
1709 case WATCH_THREAD_REMOVE_WATCH:
1712 RegistryCacheItem *cache_item;
1715 for (i = 1; i < self->prefixes->len; i++)
1717 if (strcmp (g_ptr_array_index (self->prefixes, i),
1718 self->message.watch.prefix) == 0)
1722 if (i >= self->prefixes->len)
1724 /* Don't make a fuss if the prefix is not being watched because
1725 * maybe the path was deleted so we removed the watch.
1727 trace ("unsubscribe: prefix %s is not being watched [%i things are]!\n",
1728 self->message.watch.prefix, self->prefixes->len);
1729 g_free (self->message.watch.prefix);
1733 cache_node = g_ptr_array_index (self->cache_nodes, i);
1735 trace ("watch thread: unsubscribe: freeing node %p, prefix %s, index %i\n",
1736 cache_node, self->message.watch.prefix, i);
1738 if (cache_node != NULL)
1740 cache_item = cache_node->data;
1742 /* There may be more than one GSettings object subscribed to this
1743 * path, only free the watch when the last one unsubscribes.
1745 cache_item->subscription_count--;
1746 if (cache_item->subscription_count > 0)
1750 _free_watch (self, i, cache_node);
1751 g_free (self->message.watch.prefix);
1753 g_atomic_int_inc (&self->watches_remaining);
1757 case WATCH_THREAD_STOP:
1761 /* Free any remaining cache and watch handles */
1762 for (i = 1; i < self->events->len; i++)
1763 _free_watch (self, i, g_ptr_array_index (self->cache_nodes, i));
1765 SetEvent (self->message_received_event);
1770 self->message.type = WATCH_THREAD_NONE;
1771 SetEvent (self->message_received_event);
1774 /* Thread which watches for win32 registry events */
1776 watch_thread_function (LPVOID parameter)
1778 WatchThreadState *self = (WatchThreadState *)parameter;
1781 self->events = g_ptr_array_new ();
1782 self->handles = g_ptr_array_new ();
1783 self->prefixes = g_ptr_array_new ();
1784 self->cache_nodes = g_ptr_array_new ();
1785 g_ptr_array_add (self->events, self->message_sent_event);
1786 g_ptr_array_add (self->handles, NULL);
1787 g_ptr_array_add (self->prefixes, NULL);
1788 g_ptr_array_add (self->cache_nodes, NULL);
1792 trace ("watch thread: going to sleep; %i events watched.\n", self->events->len);
1793 result = WaitForMultipleObjects (self->events->len, self->events->pdata, FALSE, INFINITE);
1795 if (result == WAIT_OBJECT_0)
1797 /* A message to you. The sender (main thread) will block until we signal the received
1798 * event, so there should be no danger of it sending another before we receive the
1801 watch_thread_handle_message (self);
1803 else if (result > WAIT_OBJECT_0 && result <= WAIT_OBJECT_0 + self->events->len)
1809 RegistryCacheItem *cache_item;
1810 RegistryEvent *event;
1813 /* One of our notifications has triggered. All we know is which one, and which key
1814 * this is for. We do most of the processing here, because we may as well. If the
1815 * registry changes further while we are processing it doesn't matter - we will then
1816 * receive another change notification from the OS anyway.
1818 notify_index = result - WAIT_OBJECT_0;
1819 hpath = g_ptr_array_index (self->handles, notify_index);
1820 cond = g_ptr_array_index (self->events, notify_index);
1821 prefix = g_ptr_array_index (self->prefixes, notify_index);
1822 cache_node = g_ptr_array_index (self->cache_nodes, notify_index);
1824 trace ("Watch thread: notify received on prefix %i: %s.\n", notify_index, prefix);
1826 if (cache_node == NULL)
1828 /* This path has been deleted */
1829 trace ("Notify received on a path that was deleted\n");
1833 /* Firstly we need to reapply for the notification, because (what a
1834 * sensible API) we won't receive any more. MSDN is pretty
1835 * inconsistent on this matter:
1836 * http://msdn.microsoft.com/en-us/library/ms724892%28VS.85%29.aspx
1837 * http://support.microsoft.com/kb/236570
1838 * But my tests (on Windows XP SP3) show that we need to reapply
1841 result = registry_watch_key (hpath, cond);
1843 if (result != ERROR_SUCCESS)
1845 /* Watch failed, most likely because the key has just been
1846 * deleted. Free the watch and unref the cache nodes.
1848 if (result != ERROR_KEY_DELETED)
1849 g_message_win32_error (result, "watch thread: failed to watch %s", prefix);
1851 _free_watch (self, notify_index, cache_node);
1852 g_atomic_int_inc (&self->watches_remaining);
1856 /* The notification may have been blocked because we just changed
1857 * some data ourselves.
1859 cache_item = cache_node->data;
1860 if (cache_item->block_count)
1862 cache_item->block_count--;
1863 trace ("Watch thread: notify blocked at %s\n", prefix);
1867 /* Now we update our stored cache from registry data, and find which keys have
1868 * actually changed. If more changes happen while we are processing, we will get
1869 * another event because we have reapplied for change notifications already.
1871 * Working here rather than in the main thread is preferable because the UI is less
1872 * likely to block (only when changing notification subscriptions).
1874 event = g_slice_new (RegistryEvent);
1875 event->self = G_REGISTRY_SETTINGS_BACKEND (g_object_ref (self->owner));
1876 event->prefix = g_strdup (prefix);
1877 event->items = g_ptr_array_new_with_free_func (g_free);
1879 EnterCriticalSection (G_REGISTRY_SETTINGS_BACKEND (self->owner)->cache_lock);
1880 registry_cache_update (G_REGISTRY_SETTINGS_BACKEND (self->owner), hpath,
1881 prefix, NULL, cache_node, 0, event);
1882 LeaveCriticalSection (G_REGISTRY_SETTINGS_BACKEND (self->owner)->cache_lock);
1884 if (event->items->len > 0)
1885 g_idle_add ((GSourceFunc) watch_handler, event);
1888 g_object_unref (event->self);
1889 g_free (event->prefix);
1890 g_ptr_array_free (event->items, TRUE);
1891 g_slice_free (RegistryEvent, event);
1896 /* God knows what has happened */
1897 g_message_win32_error (GetLastError(), "watch thread: WaitForMultipleObjects error");
1905 watch_start (GRegistrySettingsBackend *self)
1907 WatchThreadState *watch;
1909 g_return_val_if_fail (self->watch == NULL, FALSE);
1911 watch = g_slice_new (WatchThreadState);
1912 watch->owner = G_SETTINGS_BACKEND (self);
1914 watch->watches_remaining = MAX_WATCHES;
1916 watch->message_lock = g_slice_new (CRITICAL_SECTION);
1917 InitializeCriticalSection (watch->message_lock);
1918 watch->message_sent_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1919 watch->message_received_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1920 if (watch->message_sent_event == NULL || watch->message_received_event == NULL)
1922 g_message_win32_error (GetLastError (), "gregistrysettingsbackend: Failed to create sync objects.");
1926 /* Use a small stack to make the thread more lightweight. */
1927 watch->thread = CreateThread (NULL, 1024, watch_thread_function, watch, 0, NULL);
1928 if (watch->thread == NULL)
1930 g_message_win32_error (GetLastError (), "gregistrysettingsbackend: Failed to create notify watch thread.");
1934 self->watch = watch;
1939 DeleteCriticalSection (watch->message_lock);
1940 g_slice_free (CRITICAL_SECTION, watch->message_lock);
1941 if (watch->message_sent_event != NULL)
1942 CloseHandle (watch->message_sent_event);
1943 if (watch->message_received_event != NULL)
1944 CloseHandle (watch->message_received_event);
1945 g_slice_free (WatchThreadState, watch);
1950 /* This function assumes you hold the message lock! */
1952 watch_stop_unlocked (GRegistrySettingsBackend *self)
1954 WatchThreadState *watch = self->watch;
1957 g_return_if_fail (watch != NULL);
1959 watch->message.type = WATCH_THREAD_STOP;
1960 SetEvent (watch->message_sent_event);
1962 /* This is signalled as soon as the message is received. We must not return
1963 * while the watch thread is still firing off callbacks. Freeing all of the
1964 * memory is done in the watch thread after this is signalled.
1966 result = WaitForSingleObject (watch->message_received_event, INFINITE);
1967 if (result != WAIT_OBJECT_0)
1969 g_warning ("gregistrysettingsbackend: unable to stop watch thread.");
1973 LeaveCriticalSection (watch->message_lock);
1974 DeleteCriticalSection (watch->message_lock);
1975 g_slice_free (CRITICAL_SECTION, watch->message_lock);
1976 CloseHandle (watch->message_sent_event);
1977 CloseHandle (watch->message_received_event);
1978 CloseHandle (watch->thread);
1979 g_slice_free (WatchThreadState, watch);
1981 trace ("\nwatch thread: %x: all data freed.\n", self);
1986 watch_add_notify (GRegistrySettingsBackend *self,
1989 gchar *gsettings_prefix)
1991 WatchThreadState *watch = self->watch;
1993 RegistryCacheItem *cache_item;
1998 g_return_val_if_fail (watch != NULL, FALSE);
2000 trace ("watch_add_notify: prefix %s.\n", gsettings_prefix);
2002 /* Duplicate tree into the cache in the main thread, before we add the notify: if we do it in the
2003 * thread we can miss changes while we are caching.
2005 EnterCriticalSection (self->cache_lock);
2006 cache_node = registry_cache_get_node_for_key (self->cache_root, gsettings_prefix, TRUE);
2008 if (cache_node == NULL || cache_node->data == NULL)
2010 LeaveCriticalSection (self->cache_lock);
2011 g_warn_if_reached ();
2015 cache_item = cache_node->data;
2017 cache_item->subscription_count++;
2018 if (cache_item->subscription_count > 1)
2020 trace ("watch_add_notify: prefix %s already watched, %i subscribers.\n",
2021 gsettings_prefix, cache_item->subscription_count);
2022 LeaveCriticalSection (self->cache_lock);
2026 registry_cache_ref_tree (cache_node);
2027 registry_cache_update (self, hpath, gsettings_prefix, NULL, cache_node, 0, NULL);
2028 //registry_cache_dump (self->cache_root, NULL);
2029 LeaveCriticalSection (self->cache_lock);
2031 EnterCriticalSection (watch->message_lock);
2032 watch->message.type = WATCH_THREAD_ADD_WATCH;
2033 watch->message.watch.event = event;
2034 watch->message.watch.hpath = hpath;
2035 watch->message.watch.prefix = gsettings_prefix;
2036 watch->message.watch.cache_node = cache_node;
2038 SetEvent (watch->message_sent_event);
2040 /* Wait for the received event in return, to avoid sending another message before the first
2041 * one was received. If it takes > 200ms there is a possible race but the worst outcome is
2042 * a notification is ignored.
2047 WaitForSingleObject (watch->message_received_event, 200);
2049 if (result != WAIT_OBJECT_0)
2050 trace ("watch thread is slow to respond - notification may not be added.");
2053 LeaveCriticalSection (watch->message_lock);
2059 watch_remove_notify (GRegistrySettingsBackend *self,
2060 const gchar *key_name)
2062 WatchThreadState *watch = self->watch;
2065 if (self->watch == NULL)
2066 /* Here we assume that the unsubscribe message is for somewhere that was
2067 * deleted, and so it has already been removed and the watch thread has
2072 EnterCriticalSection (watch->message_lock);
2073 watch->message.type = WATCH_THREAD_REMOVE_WATCH;
2074 watch->message.watch.prefix = g_strdup (key_name);
2076 SetEvent (watch->message_sent_event);
2078 /* Wait for the received event in return, to avoid sending another message before the first
2081 result = WaitForSingleObject (watch->message_received_event, INFINITE);
2083 if (result != ERROR_SUCCESS)
2084 g_warning ("unsubscribe from %s: message not acknowledged", key_name);
2086 if (g_atomic_int_get (&watch->watches_remaining) >= MAX_WATCHES)
2087 /* Stop it before any new ones can get added and confuse things */
2088 watch_stop_unlocked (self);
2090 LeaveCriticalSection (watch->message_lock);
2093 /* dconf semantics are: if the key ends in /, watch the keys underneath it - if not, watch that
2094 * key. Our job is easier because keys and values are separate.
2097 g_registry_settings_backend_subscribe (GSettingsBackend *backend,
2098 const char *key_name)
2100 GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
2102 gunichar2 *path_namew;
2103 gchar *value_name = NULL;
2108 if (self->watch == NULL && !watch_start (self))
2111 if (g_atomic_int_dec_and_test (&self->watch->watches_remaining))
2113 g_atomic_int_inc (&self->watch->watches_remaining);
2114 g_warning ("subscribe() failed: only %i different paths may be watched.", MAX_WATCHES);
2118 path_name = parse_key (key_name, self->base_path, &value_name);
2120 /* Must check for this, otherwise strange crashes occur because the cache
2121 * node that is being watched gets freed. All path names to subscribe must
2124 if (value_name != NULL && *value_name != 0)
2125 g_warning ("subscribe() failed: path must end in a /, got %s", key_name);
2127 trace ("Subscribing to %s [registry %s / %s] - watch %x\n", key_name, path_name, value_name, self->watch);
2129 path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
2132 /* Give the caller the benefit of the doubt if the key doesn't exist and create it. The caller
2133 * is almost certainly a new g_settings with this path as base path. */
2134 result = RegCreateKeyExW (self->base_key, path_namew, 0, NULL, 0, KEY_READ, NULL, &hpath,
2136 g_free (path_namew);
2138 if (result != ERROR_SUCCESS)
2140 g_message_win32_error (result, "gregistrysettingsbackend: Unable to subscribe to key %s.", key_name);
2141 g_atomic_int_inc (&self->watch->watches_remaining);
2145 event = CreateEvent (NULL, FALSE, FALSE, NULL);
2148 g_message_win32_error (result, "gregistrysettingsbackend: CreateEvent failed.");
2149 g_atomic_int_inc (&self->watch->watches_remaining);
2150 RegCloseKey (hpath);
2154 /* The actual watch is added by the thread, which has to re-subscribe each time it
2155 * receives a change. */
2156 if (!watch_add_notify (self, event, hpath, g_strdup (key_name)))
2158 g_atomic_int_inc (&self->watch->watches_remaining);
2159 RegCloseKey (hpath);
2160 CloseHandle (event);
2165 g_registry_settings_backend_unsubscribe (GSettingsBackend *backend,
2166 const char *key_name)
2168 trace ("unsubscribe: %s.\n", key_name);
2170 watch_remove_notify (G_REGISTRY_SETTINGS_BACKEND (backend), key_name);
2173 /********************************************************************************
2174 * Object management junk
2175 ********************************************************************************/
2178 g_registry_settings_backend_finalize (GObject *object)
2180 GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
2181 RegistryCacheItem *item;
2183 item = self->cache_root->data;
2184 g_warn_if_fail (item->ref_count == 1);
2186 registry_cache_item_free (item);
2187 g_node_destroy (self->cache_root);
2189 if (self->watch != NULL)
2191 EnterCriticalSection (self->watch->message_lock);
2192 watch_stop_unlocked (self);
2195 DeleteCriticalSection (self->cache_lock);
2196 g_slice_free (CRITICAL_SECTION, self->cache_lock);
2198 g_free (self->base_path);
2199 g_free (self->base_pathw);
2203 g_registry_settings_backend_constructed (GObject *object)
2205 GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
2207 if (self->base_key == NULL || self->base_path == NULL || self->base_pathw == NULL)
2209 self->base_key = HKEY_CURRENT_USER;
2210 self->base_path = g_strdup ("Software\\GSettings");
2211 self->base_pathw = g_utf8_to_utf16 (self->base_path, -1, NULL, NULL, NULL);
2216 g_registry_settings_backend_get_property (GObject *object,
2221 GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
2223 switch ((GRegistrySettingsBackendProperty) prop_id)
2225 case PROP_REGISTRY_KEY:
2226 g_value_take_string (value,
2227 g_strdup_printf ("%s\\%s",
2228 predefined_key_to_string (self->base_key),
2233 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2239 g_registry_settings_backend_set_property (GObject *object,
2241 const GValue *value,
2244 GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
2245 const gchar *reg_path;
2247 switch ((GRegistrySettingsBackendProperty) prop_id)
2249 case PROP_REGISTRY_KEY:
2250 /* Construct only. */
2251 g_assert (self->base_key == NULL);
2252 g_assert (self->base_path == NULL);
2253 g_assert (self->base_pathw == NULL);
2255 reg_path = g_value_get_string (value);
2256 if (reg_path != NULL)
2259 const gchar *base_path = split_registry_path (reg_path, &base_key);
2261 if (base_path != NULL)
2263 gunichar2 *base_pathw = g_utf8_to_utf16 (base_path, -1, NULL, NULL, NULL);
2265 if (base_pathw != NULL)
2267 self->base_key = g_steal_pointer (&base_key);
2268 self->base_path = g_strdup (base_path);
2269 self->base_pathw = g_steal_pointer (&base_pathw);
2272 g_warning ("gregistrysettingsbackend: invalid base registry path '%s'", reg_path);
2275 g_warning ("gregistrysettingsbackend: base registry path '%s' does not start with a valid root key", reg_path);
2280 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
2286 g_registry_settings_backend_class_init (GRegistrySettingsBackendClass *class)
2288 GSettingsBackendClass *backend_class = G_SETTINGS_BACKEND_CLASS (class);
2289 GObjectClass *object_class = G_OBJECT_CLASS (class);
2291 object_class->finalize = g_registry_settings_backend_finalize;
2292 object_class->constructed = g_registry_settings_backend_constructed;
2293 object_class->get_property = g_registry_settings_backend_get_property;
2294 object_class->set_property = g_registry_settings_backend_set_property;
2296 backend_class->read = g_registry_settings_backend_read;
2297 backend_class->write = g_registry_settings_backend_write;
2298 backend_class->write_tree = g_registry_settings_backend_write_tree;
2299 backend_class->reset = g_registry_settings_backend_reset;
2300 backend_class->get_writable = g_registry_settings_backend_get_writable;
2301 backend_class->subscribe = g_registry_settings_backend_subscribe;
2302 backend_class->unsubscribe = g_registry_settings_backend_unsubscribe;
2305 * GRegistrySettingsBackend:registry-key:
2307 * The location where settings are stored in the registry. Must
2308 * start with one of the following:
2309 * - `HKEY_CLASSES_ROOT`
2310 * - `HKEY_CURRENT_CONFIG`
2311 * - `HKEY_CURRENT_USER`
2312 * - `HKEY_LOCAL_MACHINE`
2315 * Defaults to `HKEY_CURRENT_USER\Software\GSettings`.
2319 g_object_class_install_property (object_class,
2321 g_param_spec_string ("registry-key",
2323 "HKEY_CURRENT_USER\\Software\\GSettings",
2324 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
2325 G_PARAM_STATIC_STRINGS));
2329 g_registry_settings_backend_init (GRegistrySettingsBackend *self)
2331 RegistryCacheItem *item;
2333 item = g_slice_new (RegistryCacheItem);
2334 item->value.type = REG_NONE;
2335 item->value.ptr = NULL;
2336 item->name = g_strdup ("<root>");
2337 item->ref_count = 1;
2338 self->cache_root = g_node_new (item);
2340 self->cache_lock = g_slice_new (CRITICAL_SECTION);
2341 InitializeCriticalSection (self->cache_lock);
2347 * g_registry_settings_backend_new:
2348 * @registry_key: (nullable): the path to the registry key where
2349 * settings are stored, or %NULL.
2351 * If @registry_key is %NULL then the default path
2352 * `HKEY_CURRENT_USER\Software\GSettings` is used.
2354 * Returns: (transfer full): a registry-backed #GSettingsBackend
2359 g_registry_settings_backend_new (const gchar *registry_key)
2361 g_return_val_if_fail (registry_key == NULL || split_registry_path (registry_key, NULL), NULL);
2363 return G_SETTINGS_BACKEND (g_object_new (G_TYPE_REGISTRY_SETTINGS_BACKEND,
2364 "registry-key", registry_key,