Add some more cases to the app-id unit tests
[glib.git] / gio / gregistrysettingsbackend.c
blobe35f48e7de1720b4302e45fd29fdb27fcbe80b6f
1 /*
2 * Copyright © 2009-10 Sam Thursfield
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 * Author: Sam Thursfield <ssssam@gmail.com>
20 /* GRegistryBackend implementation notes:
22 * - All settings are stored under the path:
23 * HKEY_CURRENT_USER\Software\GSettings\
24 * This means all settings are per-user. Permissions and system-wide
25 * defaults are not implemented and will probably always be out of scope of
26 * 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
43 * wrong.
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.
72 * - Terminology:
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
90 #include "config.h"
92 #include "gregistrysettingsbackend.h"
93 #include "gsettingsbackend.h"
94 #include "giomodule.h"
96 #include <windows.h>
98 //#define TRACE
100 /* GSettings' limit */
101 #define MAX_KEY_NAME_LENGTH 32
103 /* Testing (on Windows XP SP3) shows that WaitForMultipleObjects fails with
104 * "The parameter is incorrect" after 64 watches. We need one for the
105 * message_sent cond, which is allowed for in the way the watches_remaining
106 * variable is used.
108 #define MAX_WATCHES 64
110 /* A watch on one registry path and its subkeys */
111 typedef struct
113 HANDLE event;
114 HKEY hpath;
115 char *prefix;
116 GNode *cache_node;
117 } RegistryWatch;
119 /* Simple message passing for the watch thread. Not enough traffic to
120 * justify a queue.
122 typedef enum
124 WATCH_THREAD_NONE,
125 WATCH_THREAD_ADD_WATCH,
126 WATCH_THREAD_REMOVE_WATCH,
127 WATCH_THREAD_STOP
128 } WatchThreadMessageType;
130 typedef struct
132 WatchThreadMessageType type;
133 RegistryWatch watch;
134 } WatchThreadMessage;
136 typedef struct
138 GSettingsBackend *owner;
139 HANDLE *thread;
141 /* Details of the things we are watching. */
142 int watches_remaining;
143 GPtrArray *events, *handles, *prefixes, *cache_nodes;
145 /* Communication with the main thread. Only one message is stored at a time,
146 * to make sure that messages are acknowledged before being overwritten we
147 * create two events - one is signalled when a new message is set, the
148 * other is signalled by the thread when it has processed the message.
150 WatchThreadMessage message;
151 CRITICAL_SECTION *message_lock;
152 HANDLE message_sent_event, message_received_event;
153 } WatchThreadState;
155 #define G_TYPE_REGISTRY_BACKEND (g_registry_backend_get_type ())
156 #define G_REGISTRY_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
157 G_TYPE_REGISTRY_BACKEND, GRegistryBackend))
158 #define G_IS_REGISTRY_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
159 G_TYPE_REGISTRY_BACKEND))
161 typedef GSettingsBackendClass GRegistryBackendClass;
163 typedef struct {
164 GSettingsBackend parent_instance;
166 gchar *base_path;
167 gunichar2 *base_pathw;
169 /* A stored copy of the whole tree being watched. When we receive a change notification
170 * we have to check against this to see what has changed ... every time ...*/
171 CRITICAL_SECTION *cache_lock;
172 GNode *cache_root;
174 WatchThreadState *watch;
175 } GRegistryBackend;
177 G_DEFINE_TYPE_WITH_CODE (GRegistryBackend,
178 g_registry_backend,
179 G_TYPE_SETTINGS_BACKEND,
180 g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
181 g_define_type_id, "registry", 90))
183 /**********************************************************************************
184 * Utility functions
185 **********************************************************************************/
187 #include <stdio.h>
188 static void
189 trace (const char *format,
190 ...)
192 #ifdef TRACE
193 va_list va; va_start (va, format);
194 vprintf (format, va);
195 fflush (stdout);
196 va_end (va);
197 #endif
200 /* g_message including a windows error message. It is not useful to have an
201 * equivalent function for g_warning because none of the registry errors can
202 * result from programmer error (Microsoft programmers don't count), instead
203 * they will mostly occur from people messing with the registry by hand. */
204 static void
205 g_message_win32_error (DWORD result_code,
206 const gchar *format,
207 ...)
209 va_list va;
210 gchar *message;
211 gchar *win32_error;
212 gchar *win32_message;
214 g_return_if_fail (result_code != 0);
216 va_start (va, format);
217 message = g_strdup_vprintf (format, va);
218 win32_error = g_win32_error_message (result_code);
219 win32_message = g_strdup_printf ("%s: %s", message, win32_error);
220 g_free (message);
221 g_free (win32_error);
223 if (result_code == ERROR_KEY_DELETED)
224 trace ("(%s)", win32_message);
225 else
226 g_message ("%s", win32_message);
228 g_free (win32_message);
231 /* Make gsettings key into a registry path & value pair.
233 * Note that the return value *only* needs freeing - registry_value_name
234 * is a pointer to further inside the same block of memory.
236 static gchar *
237 parse_key (const gchar *key_name,
238 const gchar *registry_prefix,
239 gchar **value_name)
241 gchar *path_name, *c;
243 /* All key paths are treated as absolute; gsettings doesn't seem to enforce a
244 * preceding /.
246 if (key_name[0] == '/')
247 key_name++;
249 if (registry_prefix == NULL)
250 path_name = g_strdup (key_name);
251 else
252 path_name = g_strjoin ("/", registry_prefix, key_name, NULL);
254 /* Prefix is expected to be in registry format (\ separators) so don't escape that. */
255 for (c = path_name + (registry_prefix ? strlen (registry_prefix) : 0); *c != 0; c++)
257 if (*c == '/')
259 *c = '\\';
260 *value_name = c;
264 **value_name = 0;
265 (*value_name)++;
267 return path_name;
270 static DWORD
271 g_variant_get_as_dword (GVariant *variant)
273 switch (g_variant_get_type_string (variant)[0])
275 case 'b':
276 return g_variant_get_boolean (variant);
277 case 'y':
278 return g_variant_get_byte (variant);
279 case 'n':
280 return g_variant_get_int16 (variant);
281 case 'q':
282 return g_variant_get_uint16 (variant);
283 case 'i':
284 return g_variant_get_int32 (variant);
285 case 'u':
286 return g_variant_get_uint32 (variant);
287 default:
288 g_warn_if_reached ();
290 return 0;
293 static DWORDLONG
294 g_variant_get_as_qword (GVariant *variant)
296 switch (g_variant_get_type_string (variant)[0])
298 case 'x':
299 return g_variant_get_int64 (variant);
300 case 't':
301 return g_variant_get_uint64 (variant);
302 default:
303 g_warn_if_reached ();
305 return 0;
308 static void
309 handle_read_error (LONG result,
310 const gchar *path_name,
311 const gchar *value_name)
313 /* file not found means key value not set, this isn't an error for us. */
314 if (result != ERROR_FILE_NOT_FOUND)
315 g_message_win32_error (result, "Unable to query value %s/%s: %s.\n",
316 path_name, value_name);
319 /***************************************************************************
320 * Cache of registry values
321 ***************************************************************************/
323 /* Generic container for registry values */
324 typedef struct {
325 DWORD type;
327 union {
328 gint dword; /* FIXME: could inline QWORD on 64-bit systems too */
329 void *ptr;
331 } RegistryValue;
333 static char *
334 registry_value_dump (RegistryValue value)
336 if (value.type == REG_DWORD)
337 return g_strdup_printf ("%d", value.dword);
338 else if (value.type == REG_QWORD)
339 return g_strdup_printf ("%"G_GINT64_FORMAT, value.ptr == NULL ? 0: *(DWORDLONG *)value.ptr);
340 else if (value.type == REG_SZ)
341 return g_strdup_printf ("%s", (char *)value.ptr);
342 else if (value.type == REG_NONE)
343 return g_strdup_printf ("<empty>");
344 else
345 return g_strdup_printf ("<invalid>");
348 static void
349 registry_value_free (RegistryValue value)
351 if (value.type == REG_SZ || value.type == REG_QWORD)
352 g_free (value.ptr);
354 value.type = REG_NONE;
355 value.ptr = NULL;
358 /* The registry cache is stored as a tree, for easy traversal. Right now we
359 * don't sort it in a clever way. Each node corresponds to a path element
360 * ('key' in registry terms) or a value.
362 * Each subscription uses the same cache. Because GSettings can subscribe to
363 * the tree at any node any number of times, we need to reference count the
364 * nodes.
366 typedef struct
368 /* Component of path that this node represents */
369 gchar *name;
371 /* If a watch is subscribed at this point (subscription_count > 0) we can
372 * block its next notification. This is useful because if two watches cover
373 * the same path, both will trigger when it changes. It also allows changes
374 * done by the application to be ignored by the watch thread.
376 gint32 block_count : 8;
378 /* Number of times g_settings_subscribe has been called for this location
379 * (I guess you can't subscribe more than 16383 times) */
380 gint32 subscription_count : 14;
382 gint32 ref_count : 9;
384 gint32 readable : 1;
385 RegistryValue value;
386 } RegistryCacheItem;
388 static GNode *
389 registry_cache_add_item (GNode *parent,
390 gchar *name,
391 RegistryValue value,
392 gint ref_count)
394 RegistryCacheItem *item;
395 GNode *cache_node;
397 g_return_val_if_fail (name != NULL, NULL);
398 g_return_val_if_fail (parent != NULL, NULL);
400 item = g_slice_new (RegistryCacheItem);
402 /* Ref count should be the number of watch points above this node */
403 item->ref_count = ref_count;
405 item->name = g_strdup (name);
406 item->value = value;
407 item->subscription_count = 0;
408 item->block_count = 0;
409 item->readable = FALSE;
411 trace ("\treg cache: adding %s to %s\n",
412 name, ((RegistryCacheItem *)parent->data)->name);
414 cache_node = g_node_new (item);
415 g_node_append (parent, cache_node);
417 return cache_node;
420 /* The reference counting of cache tree nodes works like this: when a node is
421 * subscribed to (GSettings wants us to watch that path and everything below
422 * it) the reference count of that node and everything below is increased, as
423 * well as each parent up to the root.
426 static void
427 _ref_down (GNode *node)
429 RegistryCacheItem *item = node->data;
431 g_node_children_foreach (node, G_TRAVERSE_ALL,
432 (GNodeForeachFunc)_ref_down, NULL);
433 item->ref_count++;
436 static void
437 registry_cache_ref_tree (GNode *tree)
439 RegistryCacheItem *item = tree->data;
440 GNode *node = tree->parent;
442 g_return_if_fail (tree != NULL);
444 item->ref_count++;
446 g_node_children_foreach (tree, G_TRAVERSE_ALL,
447 (GNodeForeachFunc)_ref_down, NULL);
449 for (node = tree->parent; node; node = node->parent)
451 item = node->data;
452 item->ref_count++;
456 static void
457 registry_cache_item_free (RegistryCacheItem *item)
459 trace ("\t -- Free node %s\n", item->name);
461 g_free (item->name);
462 registry_value_free (item->value);
463 g_slice_free (RegistryCacheItem, item);
466 /* Unreferencing has to be done bottom-up */
467 static void
468 _unref_node (GNode *node)
470 RegistryCacheItem *item = node->data;
472 item->ref_count--;
474 g_warn_if_fail (item->ref_count >= 0);
476 if (item->ref_count == 0)
478 registry_cache_item_free (item);
479 g_node_destroy (node);
483 static void
484 _unref_down (GNode *node)
486 g_node_children_foreach (node, G_TRAVERSE_ALL,
487 (GNodeForeachFunc)_unref_down, NULL);
488 _unref_node (node);
491 static void
492 registry_cache_unref_tree (GNode *tree)
494 GNode *parent = tree->parent, *next_parent;
496 _unref_down (tree);
498 while (parent)
500 next_parent = parent->parent;
501 _unref_node (parent);
502 parent = next_parent;
506 #if 0
507 static void
508 registry_cache_dump (GNode *cache_node,
509 gpointer data)
511 RegistryCacheItem *item = cache_node->data;
513 int depth = GPOINTER_TO_INT(data),
514 new_depth = depth+1,
517 g_return_if_fail (cache_node != NULL);
519 for (i=0; i<depth; i++)
520 g_print (" ");
521 if (item == NULL)
522 g_print ("*root*\n");
523 else
524 g_print ("'%s' [%i] @ %x = %s\n", item->name, item->ref_count, (guint)cache_node,
525 registry_value_dump (item->value));
526 g_node_children_foreach (cache_node, G_TRAVERSE_ALL, registry_cache_dump,
527 GINT_TO_POINTER (new_depth));
529 #endif
531 typedef struct
533 gchar *name;
534 GNode *result;
535 } RegistryCacheSearch;
537 static gboolean
538 registry_cache_find_compare (GNode *node,
539 gpointer data)
541 RegistryCacheSearch *search = data;
542 RegistryCacheItem *item = node->data;
544 if (item == NULL) /* root node */
545 return FALSE;
547 g_return_val_if_fail (search->name != NULL, FALSE);
548 g_return_val_if_fail (item->name != NULL, FALSE);
550 if (strcmp (search->name, item->name) == 0)
552 search->result = node;
553 return TRUE;
556 return FALSE;
559 static GNode *
560 registry_cache_find_immediate_child (GNode *node,
561 gchar *name)
563 RegistryCacheSearch search;
565 search.result = NULL;
566 search.name = name;
568 g_node_traverse (node, G_POST_ORDER, G_TRAVERSE_ALL, 2,
569 registry_cache_find_compare, &search);
571 return search.result;
574 static GNode *
575 registry_cache_get_node_for_key_recursive (GNode *node,
576 gchar *key_name,
577 gboolean create_if_not_found,
578 gint n_parent_watches)
580 RegistryCacheItem *item;
581 gchar *component = key_name;
582 gchar *c = strchr (component, '/');
583 GNode *child;
585 if (c != NULL)
586 *c = 0;
588 /* We count up how many watch points we travel through finding this node,
589 * because a new node should have as many references as there are watches at
590 * points above it in the tree.
592 item = node->data;
593 if (item->subscription_count > 0)
594 n_parent_watches++;
596 child = registry_cache_find_immediate_child (node, component);
597 if (child == NULL && create_if_not_found)
599 RegistryValue null_value = { REG_NONE, {0} };
601 child = registry_cache_add_item (node, component,
602 null_value, n_parent_watches);
604 trace ("\tget node for key recursive: new %x = %s.\n", node, component);
607 /* We are done if there are no more path components. Allow for a trailing /. */
608 if (child == NULL || c == NULL || *(c + 1) == 0)
609 return child;
611 trace ("get node for key recursive: next: %s.\n", c + 1);
613 return registry_cache_get_node_for_key_recursive (child, c + 1,
614 create_if_not_found,
615 n_parent_watches);
618 /* Look up a GSettings key in the cache. */
619 static GNode *
620 registry_cache_get_node_for_key (GNode *root,
621 const gchar *key_name,
622 gboolean create_if_not_found)
624 GNode *child = NULL;
625 GNode *result = NULL;
626 gchar *component, *c;
628 g_return_val_if_fail (key_name != NULL, NULL);
630 if (key_name[0] == '/')
631 key_name++;
633 /* Ignore preceding / */
634 component = g_strdup (key_name);
635 c = strchr (component, '/');
637 if (c == NULL)
639 g_free (component);
640 return root;
643 if (c != NULL)
644 *c = 0;
646 child = registry_cache_find_immediate_child (root, component);
647 if (child == NULL && create_if_not_found)
649 RegistryValue null_value = { REG_NONE, {0} };
651 /* Reference count is set to 0, tree should be referenced by the caller */
652 child = registry_cache_add_item (root, component,
653 null_value, 0);
655 trace ("get_node_for_key: New node for component '%s'\n", component);
658 if (*(c + 1) == 0)
659 result = child;
660 else if (child != NULL)
661 result = registry_cache_get_node_for_key_recursive (child, c + 1,
662 create_if_not_found, 0);
664 g_free (component);
666 return result;
669 /* Check the cache node against the registry key it represents. Return TRUE if
670 * they differ, and update the cache with the new value.
672 static gboolean
673 registry_cache_update_node (GNode *cache_node,
674 RegistryValue registry_value)
676 RegistryCacheItem *cache_item;
678 g_return_val_if_fail (cache_node != NULL, FALSE);
679 g_return_val_if_fail (cache_node->data != NULL, FALSE);
681 cache_item = cache_node->data;
683 if (registry_value.type != cache_item->value.type)
685 /* The type has changed. Update cache item and register it as changed.
686 * Either the schema has changed and this is entirely legitimate, or
687 * whenever the app reads the key it will get the default value due to
688 * the type mismatch.
690 cache_item->value = registry_value;
691 return TRUE;
694 switch (registry_value.type)
696 case REG_DWORD:
698 if (cache_item->value.dword == registry_value.dword)
699 return FALSE;
700 else
702 cache_item->value.dword = registry_value.dword;
703 return TRUE;
706 case REG_QWORD:
708 g_return_val_if_fail (registry_value.ptr != NULL &&
709 cache_item->value.ptr != NULL, FALSE);
711 if (memcmp (registry_value.ptr, cache_item->value.ptr, 8)==0)
713 g_free (registry_value.ptr);
714 return FALSE;
716 else
718 g_free (cache_item->value.ptr);
719 cache_item->value.ptr = registry_value.ptr;
720 return TRUE;
723 case REG_SZ:
725 /* Value should not exist if it is NULL, an empty string is "" */
726 g_return_val_if_fail (cache_item->value.ptr != NULL, FALSE);
727 g_return_val_if_fail (registry_value.ptr != NULL, FALSE);
729 if (strcmp (registry_value.ptr, cache_item->value.ptr) == 0)
731 g_free (registry_value.ptr);
732 return FALSE;
734 else
736 g_free (cache_item->value.ptr);
737 cache_item->value.ptr = registry_value.ptr;
738 return TRUE;
741 default:
742 g_warning ("gregistrybackend: registry_cache_update_node: Unhandled value type");
743 return FALSE;
747 /* Blocking notifications is a useful optimisation. When a change is made
748 * through GSettings we update the cache manually, but a notifcation is
749 * triggered as well. This function is also used for nested notifications,
750 * eg. if /test and /test/foo are watched, and /test/foo/value is changed then
751 * we will get notified both for /test/foo and /test and it is helpful to block
752 * the second.
754 static void
755 registry_cache_block_notification (GNode *node)
757 RegistryCacheItem *item = node->data;
759 g_return_if_fail (node != NULL);
761 if (item->subscription_count > 0)
762 item->block_count++;
764 if (node->parent != NULL)
765 registry_cache_block_notification (node->parent);
768 static void registry_cache_destroy_tree (GNode *node,
769 WatchThreadState *self);
771 /***************************************************************************
772 * Reading and writing
773 ***************************************************************************/
775 static gboolean
776 registry_read (HKEY hpath,
777 const gchar *path_name,
778 const gchar *value_name,
779 RegistryValue *p_value)
781 LONG result;
782 DWORD value_data_size;
783 gpointer *buffer;
784 gunichar2 *value_namew;
786 g_return_val_if_fail (p_value != NULL, FALSE);
788 p_value->type = REG_NONE;
789 p_value->ptr = NULL;
791 value_namew = g_utf8_to_utf16 (value_name, -1, NULL, NULL, NULL);
793 result = RegQueryValueExW (hpath, value_namew, 0, &p_value->type, NULL, &value_data_size);
794 if (result != ERROR_SUCCESS)
796 handle_read_error (result, path_name, value_name);
797 g_free (value_namew);
798 return FALSE;
801 if (p_value->type == REG_SZ && value_data_size == 0)
803 p_value->ptr = g_strdup ("");
804 g_free (value_namew);
805 return TRUE;
808 if (p_value->type == REG_DWORD)
809 /* REG_DWORD is inlined */
810 buffer = (void *)&p_value->dword;
811 else
812 buffer = p_value->ptr = g_malloc (value_data_size);
814 result = RegQueryValueExW (hpath, value_namew, 0, NULL, (LPBYTE)buffer, &value_data_size);
815 g_free (value_namew);
817 if (result != ERROR_SUCCESS)
819 handle_read_error (result, path_name, value_name);
821 if (p_value->type != REG_DWORD)
822 g_free (buffer);
824 return FALSE;
827 if (p_value->type == REG_SZ)
829 gchar *valueu8 = g_utf16_to_utf8 (p_value->ptr, -1, NULL, NULL, NULL);
830 g_free (p_value->ptr);
831 p_value->ptr = valueu8;
834 return TRUE;
837 static GVariant *
838 g_registry_backend_read (GSettingsBackend *backend,
839 const gchar *key_name,
840 const GVariantType *expected_type,
841 gboolean default_value)
843 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
844 GNode *cache_node;
845 RegistryValue registry_value;
846 GVariant *gsettings_value = NULL;
847 gchar *gsettings_type;
849 g_return_val_if_fail (expected_type != NULL, NULL);
851 if (default_value)
852 return NULL;
854 /* Simply read from the cache, which is updated from the registry by the
855 * watch thread as soon as changes can propagate. Any changes not yet in the
856 * cache will have the 'changed' signal emitted after this function returns.
858 EnterCriticalSection (self->cache_lock);
859 cache_node = registry_cache_get_node_for_key (self->cache_root, key_name, FALSE);
860 LeaveCriticalSection (self->cache_lock);
862 trace ("Reading key %s, cache node %x\n", key_name, cache_node);
864 /* Maybe it's not set, we can return to default */
865 if (cache_node == NULL)
866 return NULL;
868 trace ("\t- cached value %s\n", registry_value_dump (((RegistryCacheItem *)cache_node->data)->value));
870 registry_value = ((RegistryCacheItem *)cache_node->data)->value;
872 gsettings_type = g_variant_type_dup_string (expected_type);
874 /* The registry is user-editable, so we need to be fault-tolerant here. */
875 switch (gsettings_type[0])
877 case 'b':
878 case 'y':
879 case 'n':
880 case 'q':
881 case 'i':
882 case 'u':
883 if (registry_value.type == REG_DWORD)
884 gsettings_value = g_variant_new (gsettings_type, registry_value.dword);
885 break;
887 case 't':
888 case 'x':
889 if (registry_value.type == REG_QWORD)
891 DWORDLONG qword_value = *(DWORDLONG *)registry_value.ptr;
892 gsettings_value = g_variant_new (gsettings_type, qword_value);
894 break;
896 default:
897 if (registry_value.type == REG_SZ)
899 if (gsettings_type[0] == 's')
900 gsettings_value = g_variant_new_string ((char *)registry_value.ptr);
901 else
903 GError *error = NULL;
905 gsettings_value = g_variant_parse (expected_type, registry_value.ptr,
906 NULL, NULL, &error);
908 if (error != NULL)
909 g_message ("gregistrysettingsbackend: error parsing key %s: %s",
910 key_name, error->message);
913 break;
916 g_free (gsettings_type);
918 return gsettings_value;
922 typedef struct
924 GRegistryBackend *self;
925 HKEY hroot;
926 } RegistryWrite;
928 static gboolean
929 g_registry_backend_write_one (const char *key_name,
930 GVariant *variant,
931 gpointer user_data)
933 GRegistryBackend *self;
934 RegistryWrite *action;
935 RegistryValue value;
936 HKEY hroot;
937 HKEY hpath;
938 gchar *path_name;
939 gunichar2 *path_namew;
940 gchar *value_name = NULL;
941 gunichar2 *value_namew;
942 DWORD value_data_size;
943 LPVOID value_data;
944 gunichar2 *value_dataw;
945 LONG result;
946 GNode *node;
947 gboolean changed;
948 const gchar *type_string;
950 type_string = g_variant_get_type_string (variant);
951 action = user_data;
952 self = G_REGISTRY_BACKEND (action->self);
953 hroot = action->hroot;
955 value.type = REG_NONE;
956 value.ptr = NULL;
958 switch (type_string[0])
960 case 'b':
961 case 'y':
962 case 'n':
963 case 'q':
964 case 'i':
965 case 'u':
966 value.type = REG_DWORD;
967 value.dword = g_variant_get_as_dword (variant);
968 value_data_size = 4;
969 value_data = &value.dword;
970 break;
972 case 'x':
973 case 't':
974 value.type = REG_QWORD;
975 value.ptr = g_malloc (8);
976 *(DWORDLONG *)value.ptr = g_variant_get_as_qword (variant);
977 value_data_size = 8;
978 value_data = value.ptr;
979 break;
981 default:
982 value.type = REG_SZ;
983 if (type_string[0] == 's')
985 gsize length;
986 value.ptr = g_strdup (g_variant_get_string (variant, &length));
987 value_data_size = length + 1;
988 value_data = value.ptr;
990 else
992 GString *value_string;
993 value_string = g_variant_print_string (variant, NULL, FALSE);
994 value_data_size = value_string->len + 1;
995 value.ptr = value_data = g_string_free (value_string, FALSE);
997 break;
1000 /* First update the cache, because the value may not have changed and we can
1001 * save a write.
1003 * If 'value' has changed then its memory will not be freed by update_node(),
1004 * because it will be stored in the node.
1006 EnterCriticalSection (self->cache_lock);
1007 node = registry_cache_get_node_for_key (self->cache_root, key_name, TRUE);
1008 changed = registry_cache_update_node (node, value);
1009 LeaveCriticalSection (self->cache_lock);
1011 if (!changed)
1012 return FALSE;
1014 /* Block the next notification to any watch points above this location,
1015 * because they will each get triggered on a change that is already updated
1016 * in the cache.
1018 registry_cache_block_notification (node);
1020 path_name = parse_key (key_name, NULL, &value_name);
1022 trace ("Set key: %s / %s\n", path_name, value_name);
1024 path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
1026 /* Store the value in the registry */
1027 result = RegCreateKeyExW (hroot, path_namew, 0, NULL, 0, KEY_WRITE, NULL, &hpath, NULL);
1028 if (result != ERROR_SUCCESS)
1030 g_message_win32_error (result, "gregistrybackend: opening key %s failed",
1031 path_name + 1);
1032 registry_value_free (value);
1033 g_free (path_namew);
1034 g_free (path_name);
1035 return FALSE;
1038 g_free (path_namew);
1040 value_namew = g_utf8_to_utf16 (value_name, -1, NULL, NULL, NULL);
1042 value_dataw = NULL;
1044 switch (type_string[0])
1046 case 'b':
1047 case 'y':
1048 case 'n':
1049 case 'q':
1050 case 'i':
1051 case 'u':
1052 case 'x':
1053 case 't':
1054 break;
1055 default:
1056 value_dataw = g_utf8_to_utf16 (value_data, -1, NULL, NULL, NULL);
1057 value_data = value_dataw;
1058 value_data_size = (DWORD)((wcslen (value_data) + 1) * sizeof (gunichar2));
1059 break;
1062 result = RegSetValueExW (hpath, value_namew, 0, value.type, value_data, value_data_size);
1064 if (result != ERROR_SUCCESS)
1065 g_message_win32_error (result, "gregistrybackend: setting value %s\\%s\\%s failed.\n",
1066 self->base_path, path_name, value_name);
1068 /* If the write fails then it will seem like the value has changed until the
1069 * next execution (because we wrote to the cache first). There's no reason
1070 * for it to fail unless something is weirdly broken, however.
1073 RegCloseKey (hpath);
1074 g_free (path_name);
1075 g_free (value_namew);
1076 g_free (value_dataw);
1078 return FALSE;
1081 /* The dconf write policy is to do the write while making out it succeeded,
1082 * and then backtrack if it didn't. The registry functions are synchronous so
1083 * we can't do that. */
1085 static gboolean
1086 g_registry_backend_write (GSettingsBackend *backend,
1087 const gchar *key_name,
1088 GVariant *value,
1089 gpointer origin_tag)
1091 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
1092 LONG result;
1093 HKEY hroot;
1094 RegistryWrite action;
1096 result = RegCreateKeyExW (HKEY_CURRENT_USER, self->base_pathw, 0, NULL, 0,
1097 KEY_WRITE, NULL, &hroot, NULL);
1098 if (result != ERROR_SUCCESS)
1100 trace ("Error opening/creating key %s.\n", self->base_path);
1101 return FALSE;
1104 action.self = self;
1105 action.hroot = hroot;
1106 g_registry_backend_write_one (key_name, value, &action);
1107 g_settings_backend_changed (backend, key_name, origin_tag);
1109 RegCloseKey (hroot);
1111 return TRUE;
1114 static gboolean
1115 g_registry_backend_write_tree (GSettingsBackend *backend,
1116 GTree *values,
1117 gpointer origin_tag)
1119 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
1120 LONG result;
1121 HKEY hroot;
1122 RegistryWrite action;
1124 result = RegCreateKeyExW (HKEY_CURRENT_USER, self->base_pathw, 0, NULL, 0,
1125 KEY_WRITE, NULL, &hroot, NULL);
1126 if (result != ERROR_SUCCESS)
1128 trace ("Error opening/creating key %s.\n", self->base_path);
1129 return FALSE;
1132 action.self = self;
1133 action.hroot = hroot;
1134 g_tree_foreach (values, (GTraverseFunc)g_registry_backend_write_one,
1135 &action);
1137 g_settings_backend_changed_tree (backend, values, origin_tag);
1138 RegCloseKey (hroot);
1140 return TRUE;
1143 static void
1144 g_registry_backend_reset (GSettingsBackend *backend,
1145 const gchar *key_name,
1146 gpointer origin_tag)
1148 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
1149 gchar *path_name;
1150 gunichar2 *path_namew;
1151 gchar *value_name = NULL;
1152 gunichar2 *value_namew;
1153 GNode *cache_node;
1154 LONG result;
1155 HKEY hpath;
1157 /* Remove from cache */
1158 EnterCriticalSection (self->cache_lock);
1159 cache_node = registry_cache_get_node_for_key (self->cache_root, key_name, FALSE);
1160 if (cache_node)
1161 registry_cache_destroy_tree (cache_node, self->watch);
1162 LeaveCriticalSection (self->cache_lock);
1164 /* Remove from the registry */
1165 path_name = parse_key (key_name, self->base_path, &value_name);
1166 path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
1168 result = RegOpenKeyExW (HKEY_CURRENT_USER, path_namew, 0, KEY_SET_VALUE, &hpath);
1169 g_free (path_namew);
1171 if (result != ERROR_SUCCESS)
1173 g_message_win32_error (result, "Registry: resetting key '%s'", path_name);
1174 g_free (path_name);
1175 return;
1178 value_namew = g_utf8_to_utf16 (value_name, -1, NULL, NULL, NULL);
1180 result = RegDeleteValueW (hpath, value_namew);
1181 g_free (value_namew);
1182 RegCloseKey (hpath);
1184 if (result != ERROR_SUCCESS)
1186 g_message_win32_error (result, "Registry: resetting key '%s'", path_name);
1187 g_free (path_name);
1188 return;
1191 g_free (path_name);
1193 g_settings_backend_changed (backend, key_name, origin_tag);
1196 static gboolean
1197 g_registry_backend_get_writable (GSettingsBackend *backend,
1198 const gchar *key_name)
1200 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
1201 gchar *path_name;
1202 gunichar2 *path_namew;
1203 gchar *value_name;
1204 HKEY hpath;
1205 LONG result;
1207 path_name = parse_key (key_name, self->base_path, &value_name);
1208 path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
1210 /* Note: we create the key if it wasn't created yet, but it is not much
1211 * of a problem since at the end of the day we have to create it anyway
1212 * to read or to write from it
1214 result = RegCreateKeyExW (HKEY_CURRENT_USER, path_namew, 0, NULL, 0,
1215 KEY_WRITE, NULL, &hpath, NULL);
1216 g_free (path_namew);
1218 if (result != ERROR_SUCCESS)
1220 trace ("Error opening/creating key to check writability: %s.\n",
1221 path_name);
1222 g_free (path_name);
1224 return FALSE;
1227 g_free (path_name);
1228 RegCloseKey (hpath);
1230 return TRUE;
1233 /********************************************************************************
1234 * Spot-the-difference engine
1235 ********************************************************************************/
1237 static void
1238 _free_watch (WatchThreadState *self,
1239 guint index,
1240 GNode *cache_node);
1242 static void
1243 registry_cache_item_reset_readable (GNode *node,
1244 gpointer data)
1246 RegistryCacheItem *item = node->data;
1247 item->readable = FALSE;
1250 /* Delete a node and any children, for when it has been deleted from the registry */
1251 static void
1252 registry_cache_destroy_tree (GNode *node,
1253 WatchThreadState *self)
1255 RegistryCacheItem *item = node->data;
1257 g_node_children_foreach (node, G_TRAVERSE_ALL,
1258 (GNodeForeachFunc)registry_cache_destroy_tree, self);
1260 if (item->subscription_count > 0)
1262 guint i;
1264 /* There must be some watches active if this node is a watch point */
1265 g_warn_if_fail (self->cache_nodes->len > 1);
1267 /* This is a watch point that has been deleted. Let's free the watch! */
1268 for (i = 1; i < self->cache_nodes->len; i++)
1270 if (g_ptr_array_index (self->cache_nodes, i) == node)
1271 break;
1274 if (i >= self->cache_nodes->len)
1275 g_warning ("watch thread: a watch point was deleted, but unable to "
1276 "find '%s' in the list of %i watch nodes\n", item->name,
1277 self->cache_nodes->len - 1);
1278 else
1280 _free_watch (self, i, node);
1281 g_atomic_int_inc (&self->watches_remaining);
1284 registry_cache_item_free (node->data);
1285 g_node_destroy (node);
1288 /* One of these is sent down the pipe when something happens in the registry. */
1289 typedef struct
1291 GRegistryBackend *self;
1292 gchar *prefix; /* prefix is a gsettings path, all items are subkeys of this. */
1293 GPtrArray *items; /* each item is a subkey below prefix that has changed. */
1294 } RegistryEvent;
1296 typedef struct
1298 RegistryEvent *event;
1299 gchar *current_key_name;
1300 } DeletedItemData;
1302 static void
1303 mark_all_subkeys_as_changed (GNode *node,
1304 gpointer data)
1306 RegistryCacheItem *item = node->data;
1307 DeletedItemData *item_data = data;
1309 if (item_data->current_key_name == NULL)
1310 item_data->current_key_name = g_strdup (item->name);
1311 else
1313 gchar *name;
1315 name = g_build_path ("/", item_data->current_key_name, item->name, NULL);
1316 g_free (item_data->current_key_name);
1317 item_data->current_key_name = name;
1320 /* Iterate until we find an item that is a value */
1321 if (item->value.type == REG_NONE)
1322 g_node_children_foreach (node, G_TRAVERSE_ALL,
1323 mark_all_subkeys_as_changed, data);
1324 else
1325 g_ptr_array_add (item_data->event->items, item_data->current_key_name);
1328 static void
1329 registry_cache_remove_deleted (GNode *node,
1330 gpointer data)
1332 RegistryCacheItem *item = node->data;
1333 RegistryEvent *event = data;
1335 if (!item->readable)
1337 DeletedItemData item_data;
1339 item_data.event = event;
1340 item_data.current_key_name = NULL;
1342 mark_all_subkeys_as_changed (node, &item_data);
1343 registry_cache_destroy_tree (node, event->self->watch);
1347 /* Update cache from registry, and optionally report on the changes.
1349 * This function is sometimes called from the watch thread, with no locking. It
1350 * does call g_registry_backend functions, but this is okay because they only
1351 * access self->base which is constant.
1353 * When looking at this code bear in mind the terminology: in the registry, keys
1354 * are containers that contain values, and other keys. Keys have a 'default'
1355 * value which we always ignore.
1357 * n_parent_watches: a counter used to set the reference count of any new nodes
1358 * that are created - they should have as many references as
1359 * there are notifications that are watching them.
1361 static void
1362 registry_cache_update (GRegistryBackend *self,
1363 HKEY hpath,
1364 const gchar *prefix,
1365 const gchar *partial_key_name,
1366 GNode *cache_node,
1367 int n_watches,
1368 RegistryEvent *event)
1370 gunichar2 bufferw[MAX_KEY_NAME_LENGTH + 1];
1371 gchar *buffer;
1372 gchar *key_name;
1373 gint i;
1374 LONG result;
1375 RegistryCacheItem *item;
1377 item = cache_node->data;
1379 if (item->subscription_count > 0)
1380 n_watches++;
1382 /* prefix is the level that all changes occur below; partial_key_name should
1383 * be NULL on the first call to this function */
1384 key_name = g_build_path ("/", prefix, partial_key_name, NULL);
1386 trace ("registry cache update: %s. Node %x has %i children\n", key_name,
1387 cache_node, g_node_n_children (cache_node));
1389 /* Start by zeroing 'readable' flag. When the registry traversal is done, any unreadable nodes
1390 * must have been deleted from the registry.
1392 g_node_children_foreach (cache_node, G_TRAVERSE_ALL,
1393 registry_cache_item_reset_readable, NULL);
1395 /* Recurse into each subpath at the current level, if any */
1396 i = 0;
1397 while (1)
1399 DWORD bufferw_size = MAX_KEY_NAME_LENGTH + 1;
1400 HKEY hsubpath;
1402 result = RegEnumKeyExW (hpath, i++, bufferw, &bufferw_size, NULL, NULL, NULL, NULL);
1403 if (result != ERROR_SUCCESS)
1404 break;
1406 result = RegOpenKeyExW (hpath, bufferw, 0, KEY_READ, &hsubpath);
1407 if (result == ERROR_SUCCESS)
1409 GNode *subkey_node;
1410 RegistryCacheItem *child_item;
1411 gchar *new_partial_key_name;
1413 buffer = g_utf16_to_utf8 (bufferw, -1, NULL, NULL, NULL);
1414 if (buffer == NULL)
1415 continue;
1417 subkey_node = registry_cache_find_immediate_child (cache_node, buffer);
1418 if (subkey_node == NULL)
1420 RegistryValue null_value = {REG_NONE, {0}};
1421 subkey_node = registry_cache_add_item (cache_node, buffer,
1422 null_value, n_watches);
1425 new_partial_key_name = g_build_path ("/", partial_key_name, buffer, NULL);
1426 registry_cache_update (self, hsubpath, prefix, new_partial_key_name,
1427 subkey_node, n_watches, event);
1428 g_free (new_partial_key_name);
1430 child_item = subkey_node->data;
1431 child_item->readable = TRUE;
1433 g_free (buffer);
1434 RegCloseKey (hsubpath);
1438 if (result != ERROR_NO_MORE_ITEMS)
1439 g_message_win32_error (result, "gregistrybackend: error enumerating subkeys for cache.");
1441 /* Enumerate each value at 'path' and check if it has changed */
1442 i = 0;
1443 while (1)
1445 DWORD bufferw_size = MAX_KEY_NAME_LENGTH + 1;
1446 GNode *cache_child_node;
1447 RegistryCacheItem *child_item;
1448 RegistryValue value;
1449 gboolean changed = FALSE;
1451 result = RegEnumValueW (hpath, i++, bufferw, &bufferw_size, NULL, NULL, NULL, NULL);
1452 if (result != ERROR_SUCCESS)
1453 break;
1455 buffer = g_utf16_to_utf8 (bufferw, -1, NULL, NULL, NULL);
1457 if (buffer == NULL || buffer[0] == 0)
1459 /* This is the key's 'default' value, for which we have no use. */
1460 g_free (buffer);
1461 continue;
1464 cache_child_node = registry_cache_find_immediate_child (cache_node, buffer);
1466 if (!registry_read (hpath, key_name, buffer, &value))
1468 g_free (buffer);
1469 continue;
1472 trace ("\tgot value %s for %s, node %x\n",
1473 registry_value_dump (value), buffer, cache_child_node);
1475 if (cache_child_node == NULL)
1477 /* This is a new value */
1478 cache_child_node = registry_cache_add_item (cache_node, buffer, value,
1479 n_watches);
1480 changed = TRUE;
1482 else
1484 /* For efficiency, instead of converting every value back to a GVariant to
1485 * compare it, we compare them as registry values (integers, or string
1486 * representations of the variant). The spurious change notifications that may
1487 * result should not be a big issue.
1489 * Note that 'value' is swallowed or freed.
1491 changed = registry_cache_update_node (cache_child_node, value);
1494 child_item = cache_child_node->data;
1495 child_item->readable = TRUE;
1496 if (changed && event != NULL)
1498 gchar *item;
1500 if (partial_key_name == NULL)
1501 item = g_strdup (buffer);
1502 else
1503 item = g_build_path ("/", partial_key_name, buffer, NULL);
1505 g_ptr_array_add (event->items, item);
1508 g_free (buffer);
1511 if (result != ERROR_NO_MORE_ITEMS)
1512 g_message_win32_error (result, "gregistrybackend: error enumerating values for cache");
1514 /* Any nodes now left unreadable must have been deleted, remove them from cache */
1515 g_node_children_foreach (cache_node, G_TRAVERSE_ALL,
1516 registry_cache_remove_deleted, event);
1518 trace ("registry cache update complete.\n");
1520 g_free (key_name);
1523 /***********************************************************************************
1524 * Thread to watch for registry change events
1525 ***********************************************************************************/
1527 /* Called by watch thread. Apply for notifications on a registry key and its subkeys. */
1528 static DWORD
1529 registry_watch_key (HKEY hpath,
1530 HANDLE event)
1532 return RegNotifyChangeKeyValue (hpath, TRUE,
1533 REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
1534 event, TRUE);
1537 /* This handler runs in the main thread to emit the changed signals */
1538 static gboolean
1539 watch_handler (RegistryEvent *event)
1541 trace ("Watch handler: got event in %s, items %i.\n", event->prefix, event->items->len);
1543 /* GSettings requires us to NULL-terminate the array. */
1544 g_ptr_array_add (event->items, NULL);
1545 g_settings_backend_keys_changed (G_SETTINGS_BACKEND (event->self), event->prefix,
1546 (gchar const **)event->items->pdata, NULL);
1548 g_ptr_array_free (event->items, TRUE);
1549 g_free (event->prefix);
1550 g_object_unref (event->self);
1551 g_slice_free (RegistryEvent, event);
1553 return G_SOURCE_REMOVE;
1556 static void
1557 _free_watch (WatchThreadState *self,
1558 guint index,
1559 GNode *cache_node)
1561 HKEY hpath;
1562 HANDLE cond;
1563 gchar *prefix;
1565 g_return_if_fail (index > 0 && index < self->events->len);
1567 cond = g_ptr_array_index (self->events, index);
1568 hpath = g_ptr_array_index (self->handles, index);
1569 prefix = g_ptr_array_index (self->prefixes, index);
1571 trace ("Freeing watch %i [%s]\n", index, prefix);
1573 /* These can be NULL if the watch was already dead, this can happen when eg.
1574 * a key is deleted but GSettings is still subscribed to it - the watch is
1575 * kept alive so that the unsubscribe function works properly, but does not
1576 * do anything.
1578 if (hpath != NULL)
1579 RegCloseKey (hpath);
1581 if (cache_node != NULL)
1583 //registry_cache_dump (G_REGISTRY_BACKEND (self->owner)->cache_root, NULL);
1584 registry_cache_unref_tree (cache_node);
1587 CloseHandle (cond);
1588 g_free (prefix);
1590 /* As long as we remove from each array at the same time, it doesn't matter that
1591 * their orders get messed up - they all get messed up the same.
1593 g_ptr_array_remove_index_fast (self->handles, index);
1594 g_ptr_array_remove_index_fast (self->events, index);
1595 g_ptr_array_remove_index_fast (self->prefixes, index);
1596 g_ptr_array_remove_index_fast (self->cache_nodes, index);
1599 static void
1600 watch_thread_handle_message (WatchThreadState *self)
1602 switch (self->message.type)
1604 case WATCH_THREAD_NONE:
1605 trace ("watch thread: you woke me up for nothin', man!");
1606 break;
1608 case WATCH_THREAD_ADD_WATCH:
1610 RegistryWatch *watch = &self->message.watch;
1611 LONG result;
1613 result = registry_watch_key (watch->hpath, watch->event);
1615 if (result == ERROR_SUCCESS)
1617 g_ptr_array_add (self->events, watch->event);
1618 g_ptr_array_add (self->handles, watch->hpath);
1619 g_ptr_array_add (self->prefixes, watch->prefix);
1620 g_ptr_array_add (self->cache_nodes, watch->cache_node);
1622 trace ("watch thread: new watch on %s, %i total\n", watch->prefix,
1623 self->events->len);
1625 else
1627 g_message_win32_error (result, "watch thread: could not watch %s", watch->prefix);
1629 CloseHandle (watch->event);
1630 RegCloseKey (watch->hpath);
1631 g_free (watch->prefix);
1632 registry_cache_unref_tree (watch->cache_node);
1634 break;
1637 case WATCH_THREAD_REMOVE_WATCH:
1639 GNode *cache_node;
1640 RegistryCacheItem *cache_item;
1641 guint i;
1643 for (i = 1; i < self->prefixes->len; i++)
1645 if (strcmp (g_ptr_array_index (self->prefixes, i),
1646 self->message.watch.prefix) == 0)
1647 break;
1650 if (i >= self->prefixes->len)
1652 /* Don't make a fuss if the prefix is not being watched because
1653 * maybe the path was deleted so we removed the watch.
1655 trace ("unsubscribe: prefix %s is not being watched [%i things are]!\n",
1656 self->message.watch.prefix, self->prefixes->len);
1657 g_free (self->message.watch.prefix);
1658 break;
1661 cache_node = g_ptr_array_index (self->cache_nodes, i);
1663 trace ("watch thread: unsubscribe: freeing node %p, prefix %s, index %i\n",
1664 cache_node, self->message.watch.prefix, i);
1666 if (cache_node != NULL)
1668 cache_item = cache_node->data;
1670 /* There may be more than one GSettings object subscribed to this
1671 * path, only free the watch when the last one unsubscribes.
1673 cache_item->subscription_count--;
1674 if (cache_item->subscription_count > 0)
1675 break;
1678 _free_watch (self, i, cache_node);
1679 g_free (self->message.watch.prefix);
1681 g_atomic_int_inc (&self->watches_remaining);
1682 break;
1685 case WATCH_THREAD_STOP:
1687 guint i;
1689 /* Free any remaining cache and watch handles */
1690 for (i = 1; i < self->events->len; i++)
1691 _free_watch (self, i, g_ptr_array_index (self->cache_nodes, i));
1693 SetEvent (self->message_received_event);
1694 ExitThread (0);
1698 self->message.type = WATCH_THREAD_NONE;
1699 SetEvent (self->message_received_event);
1702 /* Thread which watches for win32 registry events */
1703 static DWORD WINAPI
1704 watch_thread_function (LPVOID parameter)
1706 WatchThreadState *self = (WatchThreadState *)parameter;
1707 DWORD result;
1709 self->events = g_ptr_array_new ();
1710 self->handles = g_ptr_array_new ();
1711 self->prefixes = g_ptr_array_new ();
1712 self->cache_nodes = g_ptr_array_new ();
1713 g_ptr_array_add (self->events, self->message_sent_event);
1714 g_ptr_array_add (self->handles, NULL);
1715 g_ptr_array_add (self->prefixes, NULL);
1716 g_ptr_array_add (self->cache_nodes, NULL);
1718 while (1)
1720 trace ("watch thread: going to sleep; %i events watched.\n", self->events->len);
1721 result = WaitForMultipleObjects (self->events->len, self->events->pdata, FALSE, INFINITE);
1723 if (result == WAIT_OBJECT_0)
1725 /* A message to you. The sender (main thread) will block until we signal the received
1726 * event, so there should be no danger of it sending another before we receive the
1727 * first.
1729 watch_thread_handle_message (self);
1731 else if (result > WAIT_OBJECT_0 && result <= WAIT_OBJECT_0 + self->events->len)
1733 HKEY hpath;
1734 HANDLE cond;
1735 gchar *prefix;
1736 GNode *cache_node;
1737 RegistryCacheItem *cache_item;
1738 RegistryEvent *event;
1739 gint notify_index;
1741 /* One of our notifications has triggered. All we know is which one, and which key
1742 * this is for. We do most of the processing here, because we may as well. If the
1743 * registry changes further while we are processing it doesn't matter - we will then
1744 * receive another change notification from the OS anyway.
1746 notify_index = result - WAIT_OBJECT_0;
1747 hpath = g_ptr_array_index (self->handles, notify_index);
1748 cond = g_ptr_array_index (self->events, notify_index);
1749 prefix = g_ptr_array_index (self->prefixes, notify_index);
1750 cache_node = g_ptr_array_index (self->cache_nodes, notify_index);
1752 trace ("Watch thread: notify received on prefix %i: %s.\n", notify_index, prefix);
1754 if (cache_node == NULL)
1756 /* This path has been deleted */
1757 trace ("Notify received on a path that was deleted\n");
1758 continue;
1761 /* Firstly we need to reapply for the notification, because (what a
1762 * sensible API) we won't receive any more. MSDN is pretty
1763 * inconsistent on this matter:
1764 * http://msdn.microsoft.com/en-us/library/ms724892%28VS.85%29.aspx
1765 * http://support.microsoft.com/kb/236570
1766 * But my tests (on Windows XP SP3) show that we need to reapply
1767 * each time.
1769 result = registry_watch_key (hpath, cond);
1771 if (result != ERROR_SUCCESS)
1773 /* Watch failed, most likely because the key has just been
1774 * deleted. Free the watch and unref the cache nodes.
1776 if (result != ERROR_KEY_DELETED)
1777 g_message_win32_error (result, "watch thread: failed to watch %s", prefix);
1779 _free_watch (self, notify_index, cache_node);
1780 g_atomic_int_inc (&self->watches_remaining);
1781 continue;
1784 /* The notification may have been blocked because we just changed
1785 * some data ourselves.
1787 cache_item = cache_node->data;
1788 if (cache_item->block_count)
1790 cache_item->block_count--;
1791 trace ("Watch thread: notify blocked at %s\n", prefix);
1792 continue;
1795 /* Now we update our stored cache from registry data, and find which keys have
1796 * actually changed. If more changes happen while we are processing, we will get
1797 * another event because we have reapplied for change notifications already.
1799 * Working here rather than in the main thread is preferable because the UI is less
1800 * likely to block (only when changing notification subscriptions).
1802 event = g_slice_new (RegistryEvent);
1803 event->self = g_object_ref (self->owner);
1804 event->prefix = g_strdup (prefix);
1805 event->items = g_ptr_array_new_with_free_func (g_free);
1807 EnterCriticalSection (G_REGISTRY_BACKEND (self->owner)->cache_lock);
1808 registry_cache_update (G_REGISTRY_BACKEND (self->owner), hpath,
1809 prefix, NULL, cache_node, 0, event);
1810 LeaveCriticalSection (G_REGISTRY_BACKEND (self->owner)->cache_lock);
1812 if (event->items->len > 0)
1813 g_idle_add ((GSourceFunc) watch_handler, event);
1814 else
1816 g_object_unref (event->self);
1817 g_free (event->prefix);
1818 g_ptr_array_free (event->items, TRUE);
1819 g_slice_free (RegistryEvent, event);
1822 else
1824 /* God knows what has happened */
1825 g_message_win32_error (GetLastError(), "watch thread: WaitForMultipleObjects error");
1829 return -1;
1832 static gboolean
1833 watch_start (GRegistryBackend *self)
1835 WatchThreadState *watch;
1837 g_return_val_if_fail (self->watch == NULL, FALSE);
1839 watch = g_slice_new (WatchThreadState);
1840 watch->owner = G_SETTINGS_BACKEND (self);
1842 watch->watches_remaining = MAX_WATCHES;
1844 watch->message_lock = g_slice_new (CRITICAL_SECTION);
1845 InitializeCriticalSection (watch->message_lock);
1846 watch->message_sent_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1847 watch->message_received_event = CreateEvent (NULL, FALSE, FALSE, NULL);
1848 if (watch->message_sent_event == NULL || watch->message_received_event == NULL)
1850 g_message_win32_error (GetLastError (), "gregistrybackend: Failed to create sync objects.");
1851 goto fail;
1854 /* Use a small stack to make the thread more lightweight. */
1855 watch->thread = CreateThread (NULL, 1024, watch_thread_function, watch, 0, NULL);
1856 if (watch->thread == NULL)
1858 g_message_win32_error (GetLastError (), "gregistrybackend: Failed to create notify watch thread.");
1859 goto fail;
1862 self->watch = watch;
1864 return TRUE;
1866 fail:
1867 DeleteCriticalSection (watch->message_lock);
1868 g_slice_free (CRITICAL_SECTION, watch->message_lock);
1869 if (watch->message_sent_event != NULL)
1870 CloseHandle (watch->message_sent_event);
1871 if (watch->message_received_event != NULL)
1872 CloseHandle (watch->message_received_event);
1873 g_slice_free (WatchThreadState, watch);
1875 return FALSE;
1878 /* This function assumes you hold the message lock! */
1879 static void
1880 watch_stop_unlocked (GRegistryBackend *self)
1882 WatchThreadState *watch = self->watch;
1883 DWORD result;
1885 g_return_if_fail (watch != NULL);
1887 watch->message.type = WATCH_THREAD_STOP;
1888 SetEvent (watch->message_sent_event);
1890 /* This is signalled as soon as the message is received. We must not return
1891 * while the watch thread is still firing off callbacks. Freeing all of the
1892 * memory is done in the watch thread after this is signalled.
1894 result = WaitForSingleObject (watch->message_received_event, INFINITE);
1895 if (result != WAIT_OBJECT_0)
1897 g_warning ("gregistrybackend: unable to stop watch thread.");
1898 return;
1901 LeaveCriticalSection (watch->message_lock);
1902 DeleteCriticalSection (watch->message_lock);
1903 g_slice_free (CRITICAL_SECTION, watch->message_lock);
1904 CloseHandle (watch->message_sent_event);
1905 CloseHandle (watch->message_received_event);
1906 CloseHandle (watch->thread);
1907 g_slice_free (WatchThreadState, watch);
1909 trace ("\nwatch thread: %x: all data freed.\n", self);
1910 self->watch = NULL;
1913 static gboolean
1914 watch_add_notify (GRegistryBackend *self,
1915 HANDLE event,
1916 HKEY hpath,
1917 gchar *gsettings_prefix)
1919 WatchThreadState *watch = self->watch;
1920 GNode *cache_node;
1921 RegistryCacheItem *cache_item;
1922 #ifdef TRACE
1923 DWORD result;
1924 #endif
1926 g_return_val_if_fail (watch != NULL, FALSE);
1928 trace ("watch_add_notify: prefix %s.\n", gsettings_prefix);
1930 /* Duplicate tree into the cache in the main thread, before we add the notify: if we do it in the
1931 * thread we can miss changes while we are caching.
1933 EnterCriticalSection (self->cache_lock);
1934 cache_node = registry_cache_get_node_for_key (self->cache_root, gsettings_prefix, TRUE);
1936 if (cache_node == NULL || cache_node->data == NULL)
1938 LeaveCriticalSection (self->cache_lock);
1939 g_warn_if_reached ();
1940 return FALSE;
1943 cache_item = cache_node->data;
1945 cache_item->subscription_count++;
1946 if (cache_item->subscription_count > 1)
1948 trace ("watch_add_notify: prefix %s already watched, %i subscribers.\n",
1949 gsettings_prefix, cache_item->subscription_count);
1950 LeaveCriticalSection (self->cache_lock);
1951 return FALSE;
1954 registry_cache_ref_tree (cache_node);
1955 registry_cache_update (self, hpath, gsettings_prefix, NULL, cache_node, 0, NULL);
1956 //registry_cache_dump (self->cache_root, NULL);
1957 LeaveCriticalSection (self->cache_lock);
1959 EnterCriticalSection (watch->message_lock);
1960 watch->message.type = WATCH_THREAD_ADD_WATCH;
1961 watch->message.watch.event = event;
1962 watch->message.watch.hpath = hpath;
1963 watch->message.watch.prefix = gsettings_prefix;
1964 watch->message.watch.cache_node = cache_node;
1966 SetEvent (watch->message_sent_event);
1968 /* Wait for the received event in return, to avoid sending another message before the first
1969 * one was received. If it takes > 200ms there is a possible race but the worst outcome is
1970 * a notification is ignored.
1972 #ifdef TRACE
1973 result =
1974 #endif
1975 WaitForSingleObject (watch->message_received_event, 200);
1976 #ifdef TRACE
1977 if (result != WAIT_OBJECT_0)
1978 trace ("watch thread is slow to respond - notification may not be added.");
1979 #endif
1981 LeaveCriticalSection (watch->message_lock);
1983 return TRUE;
1986 static void
1987 watch_remove_notify (GRegistryBackend *self,
1988 const gchar *key_name)
1990 WatchThreadState *watch = self->watch;
1991 LONG result;
1993 if (self->watch == NULL)
1994 /* Here we assume that the unsubscribe message is for somewhere that was
1995 * deleted, and so it has already been removed and the watch thread has
1996 * stopped.
1998 return;
2000 EnterCriticalSection (watch->message_lock);
2001 watch->message.type = WATCH_THREAD_REMOVE_WATCH;
2002 watch->message.watch.prefix = g_strdup (key_name);
2004 SetEvent (watch->message_sent_event);
2006 /* Wait for the received event in return, to avoid sending another message before the first
2007 * one was received.
2009 result = WaitForSingleObject (watch->message_received_event, INFINITE);
2011 if (result != ERROR_SUCCESS)
2012 g_warning ("unsubscribe from %s: message not acknowledged", key_name);
2014 if (g_atomic_int_get (&watch->watches_remaining) >= MAX_WATCHES)
2015 /* Stop it before any new ones can get added and confuse things */
2016 watch_stop_unlocked (self);
2017 else
2018 LeaveCriticalSection (watch->message_lock);
2021 /* dconf semantics are: if the key ends in /, watch the keys underneath it - if not, watch that
2022 * key. Our job is easier because keys and values are separate.
2024 static void
2025 g_registry_backend_subscribe (GSettingsBackend *backend,
2026 const char *key_name)
2028 GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
2029 gchar *path_name;
2030 gunichar2 *path_namew;
2031 gchar *value_name = NULL;
2032 HKEY hpath;
2033 HANDLE event;
2034 LONG result;
2036 if (self->watch == NULL && !watch_start (self))
2037 return;
2039 if (g_atomic_int_dec_and_test (&self->watch->watches_remaining))
2041 g_atomic_int_inc (&self->watch->watches_remaining);
2042 g_warning ("subscribe() failed: only %i different paths may be watched.", MAX_WATCHES);
2043 return;
2046 path_name = parse_key (key_name, self->base_path, &value_name);
2048 /* Must check for this, otherwise strange crashes occur because the cache
2049 * node that is being watched gets freed. All path names to subscribe must
2050 * end in a slash!
2052 if (value_name != NULL && *value_name != 0)
2053 g_warning ("subscribe() failed: path must end in a /, got %s", key_name);
2055 trace ("Subscribing to %s [registry %s / %s] - watch %x\n", key_name, path_name, value_name, self->watch);
2057 path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
2058 g_free (path_name);
2060 /* Give the caller the benefit of the doubt if the key doesn't exist and create it. The caller
2061 * is almost certainly a new g_settings with this path as base path. */
2062 result = RegCreateKeyExW (HKEY_CURRENT_USER, path_namew, 0, NULL, 0, KEY_READ, NULL, &hpath,
2063 NULL);
2064 g_free (path_namew);
2066 if (result != ERROR_SUCCESS)
2068 g_message_win32_error (result, "gregistrybackend: Unable to subscribe to key %s.", key_name);
2069 g_atomic_int_inc (&self->watch->watches_remaining);
2070 return;
2073 event = CreateEvent (NULL, FALSE, FALSE, NULL);
2074 if (event == NULL)
2076 g_message_win32_error (result, "gregistrybackend: CreateEvent failed.");
2077 g_atomic_int_inc (&self->watch->watches_remaining);
2078 RegCloseKey (hpath);
2079 return;
2082 /* The actual watch is added by the thread, which has to re-subscribe each time it
2083 * receives a change. */
2084 if (!watch_add_notify (self, event, hpath, g_strdup (key_name)))
2086 g_atomic_int_inc (&self->watch->watches_remaining);
2087 RegCloseKey (hpath);
2088 CloseHandle (event);
2092 static void
2093 g_registry_backend_unsubscribe (GSettingsBackend *backend,
2094 const char *key_name)
2096 trace ("unsubscribe: %s.\n", key_name);
2098 watch_remove_notify (G_REGISTRY_BACKEND (backend), key_name);
2101 /********************************************************************************
2102 * Object management junk
2103 ********************************************************************************/
2105 static void
2106 g_registry_backend_finalize (GObject *object)
2108 GRegistryBackend *self = G_REGISTRY_BACKEND (object);
2109 RegistryCacheItem *item;
2111 item = self->cache_root->data;
2112 g_warn_if_fail (item->ref_count == 1);
2114 registry_cache_item_free (item);
2115 g_node_destroy (self->cache_root);
2117 if (self->watch != NULL)
2119 EnterCriticalSection (self->watch->message_lock);
2120 watch_stop_unlocked (self);
2123 DeleteCriticalSection (self->cache_lock);
2124 g_slice_free (CRITICAL_SECTION, self->cache_lock);
2126 g_free (self->base_path);
2127 g_free (self->base_pathw);
2130 static void
2131 g_registry_backend_class_init (GRegistryBackendClass *class)
2133 GSettingsBackendClass *backend_class = G_SETTINGS_BACKEND_CLASS (class);
2134 GObjectClass *object_class = G_OBJECT_CLASS (class);
2136 object_class->finalize = g_registry_backend_finalize;
2138 backend_class->read = g_registry_backend_read;
2139 backend_class->write = g_registry_backend_write;
2140 backend_class->write_tree = g_registry_backend_write_tree;
2141 backend_class->reset = g_registry_backend_reset;
2142 backend_class->get_writable = g_registry_backend_get_writable;
2143 backend_class->subscribe = g_registry_backend_subscribe;
2144 backend_class->unsubscribe = g_registry_backend_unsubscribe;
2147 static void
2148 g_registry_backend_init (GRegistryBackend *self)
2150 RegistryCacheItem *item;
2152 self->base_path = g_strdup_printf ("Software\\GSettings");
2153 self->base_pathw = g_utf8_to_utf16 (self->base_path, -1, NULL, NULL, NULL);
2155 item = g_slice_new (RegistryCacheItem);
2156 item->value.type = REG_NONE;
2157 item->value.ptr = NULL;
2158 item->name = g_strdup ("<root>");
2159 item->ref_count = 1;
2160 self->cache_root = g_node_new (item);
2162 self->cache_lock = g_slice_new (CRITICAL_SECTION);
2163 InitializeCriticalSection (self->cache_lock);
2165 self->watch = NULL;