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
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 "giomodule.h"
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
108 #define MAX_WATCHES 64
110 /* A watch on one registry path and its subkeys */
119 /* Simple message passing for the watch thread. Not enough traffic to
125 WATCH_THREAD_ADD_WATCH
,
126 WATCH_THREAD_REMOVE_WATCH
,
128 } WatchThreadMessageType
;
132 WatchThreadMessageType type
;
134 } WatchThreadMessage
;
138 GSettingsBackend
*owner
;
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
;
155 G_DECLARE_FINAL_TYPE (GRegistryBackend
, g_registry_backend
, G
, REGISTRY_BACKEND
, GSettingsBackend
)
157 struct _GRegistryBackend
{
158 GSettingsBackend parent_instance
;
161 gunichar2
*base_pathw
;
163 /* A stored copy of the whole tree being watched. When we receive a change notification
164 * we have to check against this to see what has changed ... every time ...*/
165 CRITICAL_SECTION
*cache_lock
;
168 WatchThreadState
*watch
;
171 G_DEFINE_TYPE_WITH_CODE (GRegistryBackend
,
173 G_TYPE_SETTINGS_BACKEND
,
174 g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME
,
175 g_define_type_id
, "registry", 90))
177 /**********************************************************************************
179 **********************************************************************************/
183 trace (const char *format
,
187 va_list va
; va_start (va
, format
);
188 vprintf (format
, va
);
194 /* g_message including a windows error message. It is not useful to have an
195 * equivalent function for g_warning because none of the registry errors can
196 * result from programmer error (Microsoft programmers don't count), instead
197 * they will mostly occur from people messing with the registry by hand. */
199 g_message_win32_error (DWORD result_code
,
206 gchar
*win32_message
;
208 g_return_if_fail (result_code
!= 0);
210 va_start (va
, format
);
211 message
= g_strdup_vprintf (format
, va
);
212 win32_error
= g_win32_error_message (result_code
);
213 win32_message
= g_strdup_printf ("%s: %s", message
, win32_error
);
215 g_free (win32_error
);
217 if (result_code
== ERROR_KEY_DELETED
)
218 trace ("(%s)", win32_message
);
220 g_message ("%s", win32_message
);
222 g_free (win32_message
);
225 /* Make gsettings key into a registry path & value pair.
227 * Note that the return value *only* needs freeing - registry_value_name
228 * is a pointer to further inside the same block of memory.
231 parse_key (const gchar
*key_name
,
232 const gchar
*registry_prefix
,
235 gchar
*path_name
, *c
;
237 /* All key paths are treated as absolute; gsettings doesn't seem to enforce a
240 if (key_name
[0] == '/')
243 if (registry_prefix
== NULL
)
244 path_name
= g_strdup (key_name
);
246 path_name
= g_strjoin ("/", registry_prefix
, key_name
, NULL
);
248 /* Prefix is expected to be in registry format (\ separators) so don't escape that. */
249 for (c
= path_name
+ (registry_prefix
? strlen (registry_prefix
) : 0); *c
!= 0; c
++)
265 g_variant_get_as_dword (GVariant
*variant
)
267 switch (g_variant_get_type_string (variant
)[0])
270 return g_variant_get_boolean (variant
);
272 return g_variant_get_byte (variant
);
274 return g_variant_get_int16 (variant
);
276 return g_variant_get_uint16 (variant
);
278 return g_variant_get_int32 (variant
);
280 return g_variant_get_uint32 (variant
);
282 g_warn_if_reached ();
288 g_variant_get_as_qword (GVariant
*variant
)
290 switch (g_variant_get_type_string (variant
)[0])
293 return g_variant_get_int64 (variant
);
295 return g_variant_get_uint64 (variant
);
297 g_warn_if_reached ();
303 handle_read_error (LONG result
,
304 const gchar
*path_name
,
305 const gchar
*value_name
)
307 /* file not found means key value not set, this isn't an error for us. */
308 if (result
!= ERROR_FILE_NOT_FOUND
)
309 g_message_win32_error (result
, "Unable to query value %s/%s: %s.\n",
310 path_name
, value_name
);
313 /***************************************************************************
314 * Cache of registry values
315 ***************************************************************************/
317 /* Generic container for registry values */
322 gint dword
; /* FIXME: could inline QWORD on 64-bit systems too */
328 registry_value_dump (RegistryValue value
)
330 if (value
.type
== REG_DWORD
)
331 return g_strdup_printf ("%d", value
.dword
);
332 else if (value
.type
== REG_QWORD
)
333 return g_strdup_printf ("%"G_GINT64_FORMAT
, value
.ptr
== NULL
? 0: *(DWORDLONG
*)value
.ptr
);
334 else if (value
.type
== REG_SZ
)
335 return g_strdup_printf ("%s", (char *)value
.ptr
);
336 else if (value
.type
== REG_NONE
)
337 return g_strdup_printf ("<empty>");
339 return g_strdup_printf ("<invalid>");
343 registry_value_free (RegistryValue value
)
345 if (value
.type
== REG_SZ
|| value
.type
== REG_QWORD
)
348 value
.type
= REG_NONE
;
352 /* The registry cache is stored as a tree, for easy traversal. Right now we
353 * don't sort it in a clever way. Each node corresponds to a path element
354 * ('key' in registry terms) or a value.
356 * Each subscription uses the same cache. Because GSettings can subscribe to
357 * the tree at any node any number of times, we need to reference count the
362 /* Component of path that this node represents */
365 /* If a watch is subscribed at this point (subscription_count > 0) we can
366 * block its next notification. This is useful because if two watches cover
367 * the same path, both will trigger when it changes. It also allows changes
368 * done by the application to be ignored by the watch thread.
370 gint32 block_count
: 8;
372 /* Number of times g_settings_subscribe has been called for this location
373 * (I guess you can't subscribe more than 16383 times) */
374 gint32 subscription_count
: 14;
376 gint32 ref_count
: 9;
383 registry_cache_add_item (GNode
*parent
,
388 RegistryCacheItem
*item
;
391 g_return_val_if_fail (name
!= NULL
, NULL
);
392 g_return_val_if_fail (parent
!= NULL
, NULL
);
394 item
= g_slice_new (RegistryCacheItem
);
396 /* Ref count should be the number of watch points above this node */
397 item
->ref_count
= ref_count
;
399 item
->name
= g_strdup (name
);
401 item
->subscription_count
= 0;
402 item
->block_count
= 0;
403 item
->readable
= FALSE
;
405 trace ("\treg cache: adding %s to %s\n",
406 name
, ((RegistryCacheItem
*)parent
->data
)->name
);
408 cache_node
= g_node_new (item
);
409 g_node_append (parent
, cache_node
);
414 /* The reference counting of cache tree nodes works like this: when a node is
415 * subscribed to (GSettings wants us to watch that path and everything below
416 * it) the reference count of that node and everything below is increased, as
417 * well as each parent up to the root.
421 _ref_down (GNode
*node
)
423 RegistryCacheItem
*item
= node
->data
;
425 g_node_children_foreach (node
, G_TRAVERSE_ALL
,
426 (GNodeForeachFunc
)_ref_down
, NULL
);
431 registry_cache_ref_tree (GNode
*tree
)
433 RegistryCacheItem
*item
= tree
->data
;
434 GNode
*node
= tree
->parent
;
436 g_return_if_fail (tree
!= NULL
);
440 g_node_children_foreach (tree
, G_TRAVERSE_ALL
,
441 (GNodeForeachFunc
)_ref_down
, NULL
);
443 for (node
= tree
->parent
; node
; node
= node
->parent
)
451 registry_cache_item_free (RegistryCacheItem
*item
)
453 trace ("\t -- Free node %s\n", item
->name
);
456 registry_value_free (item
->value
);
457 g_slice_free (RegistryCacheItem
, item
);
460 /* Unreferencing has to be done bottom-up */
462 _unref_node (GNode
*node
)
464 RegistryCacheItem
*item
= node
->data
;
468 g_warn_if_fail (item
->ref_count
>= 0);
470 if (item
->ref_count
== 0)
472 registry_cache_item_free (item
);
473 g_node_destroy (node
);
478 _unref_down (GNode
*node
)
480 g_node_children_foreach (node
, G_TRAVERSE_ALL
,
481 (GNodeForeachFunc
)_unref_down
, NULL
);
486 registry_cache_unref_tree (GNode
*tree
)
488 GNode
*parent
= tree
->parent
, *next_parent
;
494 next_parent
= parent
->parent
;
495 _unref_node (parent
);
496 parent
= next_parent
;
502 registry_cache_dump (GNode
*cache_node
,
505 RegistryCacheItem
*item
= cache_node
->data
;
507 int depth
= GPOINTER_TO_INT(data
),
511 g_return_if_fail (cache_node
!= NULL
);
513 for (i
=0; i
<depth
; i
++)
516 g_print ("*root*\n");
518 g_print ("'%s' [%i] @ %x = %s\n", item
->name
, item
->ref_count
, (guint
)cache_node
,
519 registry_value_dump (item
->value
));
520 g_node_children_foreach (cache_node
, G_TRAVERSE_ALL
, registry_cache_dump
,
521 GINT_TO_POINTER (new_depth
));
529 } RegistryCacheSearch
;
532 registry_cache_find_compare (GNode
*node
,
535 RegistryCacheSearch
*search
= data
;
536 RegistryCacheItem
*item
= node
->data
;
538 if (item
== NULL
) /* root node */
541 g_return_val_if_fail (search
->name
!= NULL
, FALSE
);
542 g_return_val_if_fail (item
->name
!= NULL
, FALSE
);
544 if (strcmp (search
->name
, item
->name
) == 0)
546 search
->result
= node
;
554 registry_cache_find_immediate_child (GNode
*node
,
557 RegistryCacheSearch search
;
559 search
.result
= NULL
;
562 g_node_traverse (node
, G_POST_ORDER
, G_TRAVERSE_ALL
, 2,
563 registry_cache_find_compare
, &search
);
565 return search
.result
;
569 registry_cache_get_node_for_key_recursive (GNode
*node
,
571 gboolean create_if_not_found
,
572 gint n_parent_watches
)
574 RegistryCacheItem
*item
;
575 gchar
*component
= key_name
;
576 gchar
*c
= strchr (component
, '/');
582 /* We count up how many watch points we travel through finding this node,
583 * because a new node should have as many references as there are watches at
584 * points above it in the tree.
587 if (item
->subscription_count
> 0)
590 child
= registry_cache_find_immediate_child (node
, component
);
591 if (child
== NULL
&& create_if_not_found
)
593 RegistryValue null_value
= { REG_NONE
, {0} };
595 child
= registry_cache_add_item (node
, component
,
596 null_value
, n_parent_watches
);
598 trace ("\tget node for key recursive: new %x = %s.\n", node
, component
);
601 /* We are done if there are no more path components. Allow for a trailing /. */
602 if (child
== NULL
|| c
== NULL
|| *(c
+ 1) == 0)
605 trace ("get node for key recursive: next: %s.\n", c
+ 1);
607 return registry_cache_get_node_for_key_recursive (child
, c
+ 1,
612 /* Look up a GSettings key in the cache. */
614 registry_cache_get_node_for_key (GNode
*root
,
615 const gchar
*key_name
,
616 gboolean create_if_not_found
)
619 GNode
*result
= NULL
;
620 gchar
*component
, *c
;
622 g_return_val_if_fail (key_name
!= NULL
, NULL
);
624 if (key_name
[0] == '/')
627 /* Ignore preceding / */
628 component
= g_strdup (key_name
);
629 c
= strchr (component
, '/');
640 child
= registry_cache_find_immediate_child (root
, component
);
641 if (child
== NULL
&& create_if_not_found
)
643 RegistryValue null_value
= { REG_NONE
, {0} };
645 /* Reference count is set to 0, tree should be referenced by the caller */
646 child
= registry_cache_add_item (root
, component
,
649 trace ("get_node_for_key: New node for component '%s'\n", component
);
654 else if (child
!= NULL
)
655 result
= registry_cache_get_node_for_key_recursive (child
, c
+ 1,
656 create_if_not_found
, 0);
663 /* Check the cache node against the registry key it represents. Return TRUE if
664 * they differ, and update the cache with the new value.
667 registry_cache_update_node (GNode
*cache_node
,
668 RegistryValue registry_value
)
670 RegistryCacheItem
*cache_item
;
672 g_return_val_if_fail (cache_node
!= NULL
, FALSE
);
673 g_return_val_if_fail (cache_node
->data
!= NULL
, FALSE
);
675 cache_item
= cache_node
->data
;
677 if (registry_value
.type
!= cache_item
->value
.type
)
679 /* The type has changed. Update cache item and register it as changed.
680 * Either the schema has changed and this is entirely legitimate, or
681 * whenever the app reads the key it will get the default value due to
684 cache_item
->value
= registry_value
;
688 switch (registry_value
.type
)
692 if (cache_item
->value
.dword
== registry_value
.dword
)
696 cache_item
->value
.dword
= registry_value
.dword
;
702 g_return_val_if_fail (registry_value
.ptr
!= NULL
&&
703 cache_item
->value
.ptr
!= NULL
, FALSE
);
705 if (memcmp (registry_value
.ptr
, cache_item
->value
.ptr
, 8)==0)
707 g_free (registry_value
.ptr
);
712 g_free (cache_item
->value
.ptr
);
713 cache_item
->value
.ptr
= registry_value
.ptr
;
719 /* Value should not exist if it is NULL, an empty string is "" */
720 g_return_val_if_fail (cache_item
->value
.ptr
!= NULL
, FALSE
);
721 g_return_val_if_fail (registry_value
.ptr
!= NULL
, FALSE
);
723 if (strcmp (registry_value
.ptr
, cache_item
->value
.ptr
) == 0)
725 g_free (registry_value
.ptr
);
730 g_free (cache_item
->value
.ptr
);
731 cache_item
->value
.ptr
= registry_value
.ptr
;
736 g_warning ("gregistrybackend: registry_cache_update_node: Unhandled value type");
741 /* Blocking notifications is a useful optimisation. When a change is made
742 * through GSettings we update the cache manually, but a notifcation is
743 * triggered as well. This function is also used for nested notifications,
744 * eg. if /test and /test/foo are watched, and /test/foo/value is changed then
745 * we will get notified both for /test/foo and /test and it is helpful to block
749 registry_cache_block_notification (GNode
*node
)
751 RegistryCacheItem
*item
= node
->data
;
753 g_return_if_fail (node
!= NULL
);
755 if (item
->subscription_count
> 0)
758 if (node
->parent
!= NULL
)
759 registry_cache_block_notification (node
->parent
);
762 static void registry_cache_destroy_tree (GNode
*node
,
763 WatchThreadState
*self
);
765 /***************************************************************************
766 * Reading and writing
767 ***************************************************************************/
770 registry_read (HKEY hpath
,
771 const gchar
*path_name
,
772 const gchar
*value_name
,
773 RegistryValue
*p_value
)
776 DWORD value_data_size
;
778 gunichar2
*value_namew
;
780 g_return_val_if_fail (p_value
!= NULL
, FALSE
);
782 p_value
->type
= REG_NONE
;
785 value_namew
= g_utf8_to_utf16 (value_name
, -1, NULL
, NULL
, NULL
);
787 result
= RegQueryValueExW (hpath
, value_namew
, 0, &p_value
->type
, NULL
, &value_data_size
);
788 if (result
!= ERROR_SUCCESS
)
790 handle_read_error (result
, path_name
, value_name
);
791 g_free (value_namew
);
795 if (p_value
->type
== REG_SZ
&& value_data_size
== 0)
797 p_value
->ptr
= g_strdup ("");
798 g_free (value_namew
);
802 if (p_value
->type
== REG_DWORD
)
803 /* REG_DWORD is inlined */
804 buffer
= (void *)&p_value
->dword
;
806 buffer
= p_value
->ptr
= g_malloc (value_data_size
);
808 result
= RegQueryValueExW (hpath
, value_namew
, 0, NULL
, (LPBYTE
)buffer
, &value_data_size
);
809 g_free (value_namew
);
811 if (result
!= ERROR_SUCCESS
)
813 handle_read_error (result
, path_name
, value_name
);
815 if (p_value
->type
!= REG_DWORD
)
821 if (p_value
->type
== REG_SZ
)
823 gchar
*valueu8
= g_utf16_to_utf8 (p_value
->ptr
, -1, NULL
, NULL
, NULL
);
824 g_free (p_value
->ptr
);
825 p_value
->ptr
= valueu8
;
832 g_registry_backend_read (GSettingsBackend
*backend
,
833 const gchar
*key_name
,
834 const GVariantType
*expected_type
,
835 gboolean default_value
)
837 GRegistryBackend
*self
= G_REGISTRY_BACKEND (backend
);
839 RegistryValue registry_value
;
840 GVariant
*gsettings_value
= NULL
;
841 gchar
*gsettings_type
;
843 g_return_val_if_fail (expected_type
!= NULL
, NULL
);
848 /* Simply read from the cache, which is updated from the registry by the
849 * watch thread as soon as changes can propagate. Any changes not yet in the
850 * cache will have the 'changed' signal emitted after this function returns.
852 EnterCriticalSection (self
->cache_lock
);
853 cache_node
= registry_cache_get_node_for_key (self
->cache_root
, key_name
, FALSE
);
854 LeaveCriticalSection (self
->cache_lock
);
856 trace ("Reading key %s, cache node %x\n", key_name
, cache_node
);
858 /* Maybe it's not set, we can return to default */
859 if (cache_node
== NULL
)
862 trace ("\t- cached value %s\n", registry_value_dump (((RegistryCacheItem
*)cache_node
->data
)->value
));
864 registry_value
= ((RegistryCacheItem
*)cache_node
->data
)->value
;
866 gsettings_type
= g_variant_type_dup_string (expected_type
);
868 /* The registry is user-editable, so we need to be fault-tolerant here. */
869 switch (gsettings_type
[0])
877 if (registry_value
.type
== REG_DWORD
)
878 gsettings_value
= g_variant_new (gsettings_type
, registry_value
.dword
);
883 if (registry_value
.type
== REG_QWORD
)
885 DWORDLONG qword_value
= *(DWORDLONG
*)registry_value
.ptr
;
886 gsettings_value
= g_variant_new (gsettings_type
, qword_value
);
891 if (registry_value
.type
== REG_SZ
)
893 if (gsettings_type
[0] == 's')
894 gsettings_value
= g_variant_new_string ((char *)registry_value
.ptr
);
897 GError
*error
= NULL
;
899 gsettings_value
= g_variant_parse (expected_type
, registry_value
.ptr
,
903 g_message ("gregistrysettingsbackend: error parsing key %s: %s",
904 key_name
, error
->message
);
910 g_free (gsettings_type
);
912 return gsettings_value
;
918 GRegistryBackend
*self
;
923 g_registry_backend_write_one (const char *key_name
,
927 GRegistryBackend
*self
;
928 RegistryWrite
*action
;
933 gunichar2
*path_namew
;
934 gchar
*value_name
= NULL
;
935 gunichar2
*value_namew
;
936 DWORD value_data_size
;
938 gunichar2
*value_dataw
;
942 const gchar
*type_string
;
944 type_string
= g_variant_get_type_string (variant
);
946 self
= G_REGISTRY_BACKEND (action
->self
);
947 hroot
= action
->hroot
;
949 value
.type
= REG_NONE
;
952 switch (type_string
[0])
960 value
.type
= REG_DWORD
;
961 value
.dword
= g_variant_get_as_dword (variant
);
963 value_data
= &value
.dword
;
968 value
.type
= REG_QWORD
;
969 value
.ptr
= g_malloc (8);
970 *(DWORDLONG
*)value
.ptr
= g_variant_get_as_qword (variant
);
972 value_data
= value
.ptr
;
977 if (type_string
[0] == 's')
980 value
.ptr
= g_strdup (g_variant_get_string (variant
, &length
));
981 value_data_size
= length
+ 1;
982 value_data
= value
.ptr
;
986 GString
*value_string
;
987 value_string
= g_variant_print_string (variant
, NULL
, FALSE
);
988 value_data_size
= value_string
->len
+ 1;
989 value
.ptr
= value_data
= g_string_free (value_string
, FALSE
);
994 /* First update the cache, because the value may not have changed and we can
997 * If 'value' has changed then its memory will not be freed by update_node(),
998 * because it will be stored in the node.
1000 EnterCriticalSection (self
->cache_lock
);
1001 node
= registry_cache_get_node_for_key (self
->cache_root
, key_name
, TRUE
);
1002 changed
= registry_cache_update_node (node
, value
);
1003 LeaveCriticalSection (self
->cache_lock
);
1008 /* Block the next notification to any watch points above this location,
1009 * because they will each get triggered on a change that is already updated
1012 registry_cache_block_notification (node
);
1014 path_name
= parse_key (key_name
, NULL
, &value_name
);
1016 trace ("Set key: %s / %s\n", path_name
, value_name
);
1018 path_namew
= g_utf8_to_utf16 (path_name
, -1, NULL
, NULL
, NULL
);
1020 /* Store the value in the registry */
1021 result
= RegCreateKeyExW (hroot
, path_namew
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hpath
, NULL
);
1022 if (result
!= ERROR_SUCCESS
)
1024 g_message_win32_error (result
, "gregistrybackend: opening key %s failed",
1026 registry_value_free (value
);
1027 g_free (path_namew
);
1032 g_free (path_namew
);
1034 value_namew
= g_utf8_to_utf16 (value_name
, -1, NULL
, NULL
, NULL
);
1038 switch (type_string
[0])
1050 value_dataw
= g_utf8_to_utf16 (value_data
, -1, NULL
, NULL
, NULL
);
1051 value_data
= value_dataw
;
1052 value_data_size
= (DWORD
)((wcslen (value_data
) + 1) * sizeof (gunichar2
));
1056 result
= RegSetValueExW (hpath
, value_namew
, 0, value
.type
, value_data
, value_data_size
);
1058 if (result
!= ERROR_SUCCESS
)
1059 g_message_win32_error (result
, "gregistrybackend: setting value %s\\%s\\%s failed.\n",
1060 self
->base_path
, path_name
, value_name
);
1062 /* If the write fails then it will seem like the value has changed until the
1063 * next execution (because we wrote to the cache first). There's no reason
1064 * for it to fail unless something is weirdly broken, however.
1067 RegCloseKey (hpath
);
1069 g_free (value_namew
);
1070 g_free (value_dataw
);
1075 /* The dconf write policy is to do the write while making out it succeeded,
1076 * and then backtrack if it didn't. The registry functions are synchronous so
1077 * we can't do that. */
1080 g_registry_backend_write (GSettingsBackend
*backend
,
1081 const gchar
*key_name
,
1083 gpointer origin_tag
)
1085 GRegistryBackend
*self
= G_REGISTRY_BACKEND (backend
);
1088 RegistryWrite action
;
1090 result
= RegCreateKeyExW (HKEY_CURRENT_USER
, self
->base_pathw
, 0, NULL
, 0,
1091 KEY_WRITE
, NULL
, &hroot
, NULL
);
1092 if (result
!= ERROR_SUCCESS
)
1094 trace ("Error opening/creating key %s.\n", self
->base_path
);
1099 action
.hroot
= hroot
;
1100 g_registry_backend_write_one (key_name
, value
, &action
);
1101 g_settings_backend_changed (backend
, key_name
, origin_tag
);
1103 RegCloseKey (hroot
);
1109 g_registry_backend_write_tree (GSettingsBackend
*backend
,
1111 gpointer origin_tag
)
1113 GRegistryBackend
*self
= G_REGISTRY_BACKEND (backend
);
1116 RegistryWrite action
;
1118 result
= RegCreateKeyExW (HKEY_CURRENT_USER
, self
->base_pathw
, 0, NULL
, 0,
1119 KEY_WRITE
, NULL
, &hroot
, NULL
);
1120 if (result
!= ERROR_SUCCESS
)
1122 trace ("Error opening/creating key %s.\n", self
->base_path
);
1127 action
.hroot
= hroot
;
1128 g_tree_foreach (values
, (GTraverseFunc
)g_registry_backend_write_one
,
1131 g_settings_backend_changed_tree (backend
, values
, origin_tag
);
1132 RegCloseKey (hroot
);
1138 g_registry_backend_reset (GSettingsBackend
*backend
,
1139 const gchar
*key_name
,
1140 gpointer origin_tag
)
1142 GRegistryBackend
*self
= G_REGISTRY_BACKEND (backend
);
1144 gunichar2
*path_namew
;
1145 gchar
*value_name
= NULL
;
1146 gunichar2
*value_namew
;
1151 /* Remove from cache */
1152 EnterCriticalSection (self
->cache_lock
);
1153 cache_node
= registry_cache_get_node_for_key (self
->cache_root
, key_name
, FALSE
);
1155 registry_cache_destroy_tree (cache_node
, self
->watch
);
1156 LeaveCriticalSection (self
->cache_lock
);
1158 /* Remove from the registry */
1159 path_name
= parse_key (key_name
, self
->base_path
, &value_name
);
1160 path_namew
= g_utf8_to_utf16 (path_name
, -1, NULL
, NULL
, NULL
);
1162 result
= RegOpenKeyExW (HKEY_CURRENT_USER
, path_namew
, 0, KEY_SET_VALUE
, &hpath
);
1163 g_free (path_namew
);
1165 if (result
!= ERROR_SUCCESS
)
1167 g_message_win32_error (result
, "Registry: resetting key '%s'", path_name
);
1172 value_namew
= g_utf8_to_utf16 (value_name
, -1, NULL
, NULL
, NULL
);
1174 result
= RegDeleteValueW (hpath
, value_namew
);
1175 g_free (value_namew
);
1176 RegCloseKey (hpath
);
1178 if (result
!= ERROR_SUCCESS
)
1180 g_message_win32_error (result
, "Registry: resetting key '%s'", path_name
);
1187 g_settings_backend_changed (backend
, key_name
, origin_tag
);
1191 g_registry_backend_get_writable (GSettingsBackend
*backend
,
1192 const gchar
*key_name
)
1194 GRegistryBackend
*self
= G_REGISTRY_BACKEND (backend
);
1196 gunichar2
*path_namew
;
1201 path_name
= parse_key (key_name
, self
->base_path
, &value_name
);
1202 path_namew
= g_utf8_to_utf16 (path_name
, -1, NULL
, NULL
, NULL
);
1204 /* Note: we create the key if it wasn't created yet, but it is not much
1205 * of a problem since at the end of the day we have to create it anyway
1206 * to read or to write from it
1208 result
= RegCreateKeyExW (HKEY_CURRENT_USER
, path_namew
, 0, NULL
, 0,
1209 KEY_WRITE
, NULL
, &hpath
, NULL
);
1210 g_free (path_namew
);
1212 if (result
!= ERROR_SUCCESS
)
1214 trace ("Error opening/creating key to check writability: %s.\n",
1222 RegCloseKey (hpath
);
1227 /********************************************************************************
1228 * Spot-the-difference engine
1229 ********************************************************************************/
1232 _free_watch (WatchThreadState
*self
,
1237 registry_cache_item_reset_readable (GNode
*node
,
1240 RegistryCacheItem
*item
= node
->data
;
1241 item
->readable
= FALSE
;
1244 /* Delete a node and any children, for when it has been deleted from the registry */
1246 registry_cache_destroy_tree (GNode
*node
,
1247 WatchThreadState
*self
)
1249 RegistryCacheItem
*item
= node
->data
;
1251 g_node_children_foreach (node
, G_TRAVERSE_ALL
,
1252 (GNodeForeachFunc
)registry_cache_destroy_tree
, self
);
1254 if (item
->subscription_count
> 0)
1258 /* There must be some watches active if this node is a watch point */
1259 g_warn_if_fail (self
->cache_nodes
->len
> 1);
1261 /* This is a watch point that has been deleted. Let's free the watch! */
1262 for (i
= 1; i
< self
->cache_nodes
->len
; i
++)
1264 if (g_ptr_array_index (self
->cache_nodes
, i
) == node
)
1268 if (i
>= self
->cache_nodes
->len
)
1269 g_warning ("watch thread: a watch point was deleted, but unable to "
1270 "find '%s' in the list of %i watch nodes\n", item
->name
,
1271 self
->cache_nodes
->len
- 1);
1274 _free_watch (self
, i
, node
);
1275 g_atomic_int_inc (&self
->watches_remaining
);
1278 registry_cache_item_free (node
->data
);
1279 g_node_destroy (node
);
1282 /* One of these is sent down the pipe when something happens in the registry. */
1285 GRegistryBackend
*self
;
1286 gchar
*prefix
; /* prefix is a gsettings path, all items are subkeys of this. */
1287 GPtrArray
*items
; /* each item is a subkey below prefix that has changed. */
1292 RegistryEvent
*event
;
1293 gchar
*current_key_name
;
1297 mark_all_subkeys_as_changed (GNode
*node
,
1300 RegistryCacheItem
*item
= node
->data
;
1301 DeletedItemData
*item_data
= data
;
1303 if (item_data
->current_key_name
== NULL
)
1304 item_data
->current_key_name
= g_strdup (item
->name
);
1309 name
= g_build_path ("/", item_data
->current_key_name
, item
->name
, NULL
);
1310 g_free (item_data
->current_key_name
);
1311 item_data
->current_key_name
= name
;
1314 /* Iterate until we find an item that is a value */
1315 if (item
->value
.type
== REG_NONE
)
1316 g_node_children_foreach (node
, G_TRAVERSE_ALL
,
1317 mark_all_subkeys_as_changed
, data
);
1319 g_ptr_array_add (item_data
->event
->items
, item_data
->current_key_name
);
1323 registry_cache_remove_deleted (GNode
*node
,
1326 RegistryCacheItem
*item
= node
->data
;
1327 RegistryEvent
*event
= data
;
1329 if (!item
->readable
)
1331 DeletedItemData item_data
;
1333 item_data
.event
= event
;
1334 item_data
.current_key_name
= NULL
;
1336 mark_all_subkeys_as_changed (node
, &item_data
);
1337 registry_cache_destroy_tree (node
, event
->self
->watch
);
1341 /* Update cache from registry, and optionally report on the changes.
1343 * This function is sometimes called from the watch thread, with no locking. It
1344 * does call g_registry_backend functions, but this is okay because they only
1345 * access self->base which is constant.
1347 * When looking at this code bear in mind the terminology: in the registry, keys
1348 * are containers that contain values, and other keys. Keys have a 'default'
1349 * value which we always ignore.
1351 * n_parent_watches: a counter used to set the reference count of any new nodes
1352 * that are created - they should have as many references as
1353 * there are notifications that are watching them.
1356 registry_cache_update (GRegistryBackend
*self
,
1358 const gchar
*prefix
,
1359 const gchar
*partial_key_name
,
1362 RegistryEvent
*event
)
1364 gunichar2 bufferw
[MAX_KEY_NAME_LENGTH
+ 1];
1369 RegistryCacheItem
*item
;
1371 item
= cache_node
->data
;
1373 if (item
->subscription_count
> 0)
1376 /* prefix is the level that all changes occur below; partial_key_name should
1377 * be NULL on the first call to this function */
1378 key_name
= g_build_path ("/", prefix
, partial_key_name
, NULL
);
1380 trace ("registry cache update: %s. Node %x has %i children\n", key_name
,
1381 cache_node
, g_node_n_children (cache_node
));
1383 /* Start by zeroing 'readable' flag. When the registry traversal is done, any unreadable nodes
1384 * must have been deleted from the registry.
1386 g_node_children_foreach (cache_node
, G_TRAVERSE_ALL
,
1387 registry_cache_item_reset_readable
, NULL
);
1389 /* Recurse into each subpath at the current level, if any */
1393 DWORD bufferw_size
= MAX_KEY_NAME_LENGTH
+ 1;
1396 result
= RegEnumKeyExW (hpath
, i
++, bufferw
, &bufferw_size
, NULL
, NULL
, NULL
, NULL
);
1397 if (result
!= ERROR_SUCCESS
)
1400 result
= RegOpenKeyExW (hpath
, bufferw
, 0, KEY_READ
, &hsubpath
);
1401 if (result
== ERROR_SUCCESS
)
1404 RegistryCacheItem
*child_item
;
1405 gchar
*new_partial_key_name
;
1407 buffer
= g_utf16_to_utf8 (bufferw
, -1, NULL
, NULL
, NULL
);
1411 subkey_node
= registry_cache_find_immediate_child (cache_node
, buffer
);
1412 if (subkey_node
== NULL
)
1414 RegistryValue null_value
= {REG_NONE
, {0}};
1415 subkey_node
= registry_cache_add_item (cache_node
, buffer
,
1416 null_value
, n_watches
);
1419 new_partial_key_name
= g_build_path ("/", partial_key_name
, buffer
, NULL
);
1420 registry_cache_update (self
, hsubpath
, prefix
, new_partial_key_name
,
1421 subkey_node
, n_watches
, event
);
1422 g_free (new_partial_key_name
);
1424 child_item
= subkey_node
->data
;
1425 child_item
->readable
= TRUE
;
1428 RegCloseKey (hsubpath
);
1432 if (result
!= ERROR_NO_MORE_ITEMS
)
1433 g_message_win32_error (result
, "gregistrybackend: error enumerating subkeys for cache.");
1435 /* Enumerate each value at 'path' and check if it has changed */
1439 DWORD bufferw_size
= MAX_KEY_NAME_LENGTH
+ 1;
1440 GNode
*cache_child_node
;
1441 RegistryCacheItem
*child_item
;
1442 RegistryValue value
;
1443 gboolean changed
= FALSE
;
1445 result
= RegEnumValueW (hpath
, i
++, bufferw
, &bufferw_size
, NULL
, NULL
, NULL
, NULL
);
1446 if (result
!= ERROR_SUCCESS
)
1449 buffer
= g_utf16_to_utf8 (bufferw
, -1, NULL
, NULL
, NULL
);
1451 if (buffer
== NULL
|| buffer
[0] == 0)
1453 /* This is the key's 'default' value, for which we have no use. */
1458 cache_child_node
= registry_cache_find_immediate_child (cache_node
, buffer
);
1460 if (!registry_read (hpath
, key_name
, buffer
, &value
))
1466 trace ("\tgot value %s for %s, node %x\n",
1467 registry_value_dump (value
), buffer
, cache_child_node
);
1469 if (cache_child_node
== NULL
)
1471 /* This is a new value */
1472 cache_child_node
= registry_cache_add_item (cache_node
, buffer
, value
,
1478 /* For efficiency, instead of converting every value back to a GVariant to
1479 * compare it, we compare them as registry values (integers, or string
1480 * representations of the variant). The spurious change notifications that may
1481 * result should not be a big issue.
1483 * Note that 'value' is swallowed or freed.
1485 changed
= registry_cache_update_node (cache_child_node
, value
);
1488 child_item
= cache_child_node
->data
;
1489 child_item
->readable
= TRUE
;
1490 if (changed
&& event
!= NULL
)
1494 if (partial_key_name
== NULL
)
1495 item
= g_strdup (buffer
);
1497 item
= g_build_path ("/", partial_key_name
, buffer
, NULL
);
1499 g_ptr_array_add (event
->items
, item
);
1505 if (result
!= ERROR_NO_MORE_ITEMS
)
1506 g_message_win32_error (result
, "gregistrybackend: error enumerating values for cache");
1508 /* Any nodes now left unreadable must have been deleted, remove them from cache */
1509 g_node_children_foreach (cache_node
, G_TRAVERSE_ALL
,
1510 registry_cache_remove_deleted
, event
);
1512 trace ("registry cache update complete.\n");
1517 /***********************************************************************************
1518 * Thread to watch for registry change events
1519 ***********************************************************************************/
1521 /* Called by watch thread. Apply for notifications on a registry key and its subkeys. */
1523 registry_watch_key (HKEY hpath
,
1526 return RegNotifyChangeKeyValue (hpath
, TRUE
,
1527 REG_NOTIFY_CHANGE_NAME
| REG_NOTIFY_CHANGE_LAST_SET
,
1531 /* This handler runs in the main thread to emit the changed signals */
1533 watch_handler (RegistryEvent
*event
)
1537 trace ("Watch handler: got event in %s, items %i.\n", event
->prefix
, event
->items
->len
);
1539 /* GSettings requires us to NULL-terminate the array. */
1540 g_ptr_array_add (event
->items
, NULL
);
1541 g_settings_backend_keys_changed (G_SETTINGS_BACKEND (event
->self
), event
->prefix
,
1542 (gchar
const **)event
->items
->pdata
, NULL
);
1544 g_ptr_array_free (event
->items
, TRUE
);
1545 g_free (event
->prefix
);
1546 g_object_unref (event
->self
);
1547 g_slice_free (RegistryEvent
, event
);
1549 return G_SOURCE_REMOVE
;
1553 _free_watch (WatchThreadState
*self
,
1561 g_return_if_fail (index
> 0 && index
< self
->events
->len
);
1563 cond
= g_ptr_array_index (self
->events
, index
);
1564 hpath
= g_ptr_array_index (self
->handles
, index
);
1565 prefix
= g_ptr_array_index (self
->prefixes
, index
);
1567 trace ("Freeing watch %i [%s]\n", index
, prefix
);
1569 /* These can be NULL if the watch was already dead, this can happen when eg.
1570 * a key is deleted but GSettings is still subscribed to it - the watch is
1571 * kept alive so that the unsubscribe function works properly, but does not
1575 RegCloseKey (hpath
);
1577 if (cache_node
!= NULL
)
1579 //registry_cache_dump (G_REGISTRY_BACKEND (self->owner)->cache_root, NULL);
1580 registry_cache_unref_tree (cache_node
);
1586 /* As long as we remove from each array at the same time, it doesn't matter that
1587 * their orders get messed up - they all get messed up the same.
1589 g_ptr_array_remove_index_fast (self
->handles
, index
);
1590 g_ptr_array_remove_index_fast (self
->events
, index
);
1591 g_ptr_array_remove_index_fast (self
->prefixes
, index
);
1592 g_ptr_array_remove_index_fast (self
->cache_nodes
, index
);
1596 watch_thread_handle_message (WatchThreadState
*self
)
1598 switch (self
->message
.type
)
1600 case WATCH_THREAD_NONE
:
1601 trace ("watch thread: you woke me up for nothin', man!");
1604 case WATCH_THREAD_ADD_WATCH
:
1606 RegistryWatch
*watch
= &self
->message
.watch
;
1609 result
= registry_watch_key (watch
->hpath
, watch
->event
);
1611 if (result
== ERROR_SUCCESS
)
1613 g_ptr_array_add (self
->events
, watch
->event
);
1614 g_ptr_array_add (self
->handles
, watch
->hpath
);
1615 g_ptr_array_add (self
->prefixes
, watch
->prefix
);
1616 g_ptr_array_add (self
->cache_nodes
, watch
->cache_node
);
1618 trace ("watch thread: new watch on %s, %i total\n", watch
->prefix
,
1623 g_message_win32_error (result
, "watch thread: could not watch %s", watch
->prefix
);
1625 CloseHandle (watch
->event
);
1626 RegCloseKey (watch
->hpath
);
1627 g_free (watch
->prefix
);
1628 registry_cache_unref_tree (watch
->cache_node
);
1633 case WATCH_THREAD_REMOVE_WATCH
:
1636 RegistryCacheItem
*cache_item
;
1639 for (i
= 1; i
< self
->prefixes
->len
; i
++)
1641 if (strcmp (g_ptr_array_index (self
->prefixes
, i
),
1642 self
->message
.watch
.prefix
) == 0)
1646 if (i
>= self
->prefixes
->len
)
1648 /* Don't make a fuss if the prefix is not being watched because
1649 * maybe the path was deleted so we removed the watch.
1651 trace ("unsubscribe: prefix %s is not being watched [%i things are]!\n",
1652 self
->message
.watch
.prefix
, self
->prefixes
->len
);
1653 g_free (self
->message
.watch
.prefix
);
1657 cache_node
= g_ptr_array_index (self
->cache_nodes
, i
);
1659 trace ("watch thread: unsubscribe: freeing node %p, prefix %s, index %i\n",
1660 cache_node
, self
->message
.watch
.prefix
, i
);
1662 if (cache_node
!= NULL
)
1664 cache_item
= cache_node
->data
;
1666 /* There may be more than one GSettings object subscribed to this
1667 * path, only free the watch when the last one unsubscribes.
1669 cache_item
->subscription_count
--;
1670 if (cache_item
->subscription_count
> 0)
1674 _free_watch (self
, i
, cache_node
);
1675 g_free (self
->message
.watch
.prefix
);
1677 g_atomic_int_inc (&self
->watches_remaining
);
1681 case WATCH_THREAD_STOP
:
1685 /* Free any remaining cache and watch handles */
1686 for (i
= 1; i
< self
->events
->len
; i
++)
1687 _free_watch (self
, i
, g_ptr_array_index (self
->cache_nodes
, i
));
1689 SetEvent (self
->message_received_event
);
1694 self
->message
.type
= WATCH_THREAD_NONE
;
1695 SetEvent (self
->message_received_event
);
1698 /* Thread which watches for win32 registry events */
1700 watch_thread_function (LPVOID parameter
)
1702 WatchThreadState
*self
= (WatchThreadState
*)parameter
;
1705 self
->events
= g_ptr_array_new ();
1706 self
->handles
= g_ptr_array_new ();
1707 self
->prefixes
= g_ptr_array_new ();
1708 self
->cache_nodes
= g_ptr_array_new ();
1709 g_ptr_array_add (self
->events
, self
->message_sent_event
);
1710 g_ptr_array_add (self
->handles
, NULL
);
1711 g_ptr_array_add (self
->prefixes
, NULL
);
1712 g_ptr_array_add (self
->cache_nodes
, NULL
);
1716 trace ("watch thread: going to sleep; %i events watched.\n", self
->events
->len
);
1717 result
= WaitForMultipleObjects (self
->events
->len
, self
->events
->pdata
, FALSE
, INFINITE
);
1719 if (result
== WAIT_OBJECT_0
)
1721 /* A message to you. The sender (main thread) will block until we signal the received
1722 * event, so there should be no danger of it sending another before we receive the
1725 watch_thread_handle_message (self
);
1727 else if (result
> WAIT_OBJECT_0
&& result
<= WAIT_OBJECT_0
+ self
->events
->len
)
1733 RegistryCacheItem
*cache_item
;
1734 RegistryEvent
*event
;
1737 /* One of our notifications has triggered. All we know is which one, and which key
1738 * this is for. We do most of the processing here, because we may as well. If the
1739 * registry changes further while we are processing it doesn't matter - we will then
1740 * receive another change notification from the OS anyway.
1742 notify_index
= result
- WAIT_OBJECT_0
;
1743 hpath
= g_ptr_array_index (self
->handles
, notify_index
);
1744 cond
= g_ptr_array_index (self
->events
, notify_index
);
1745 prefix
= g_ptr_array_index (self
->prefixes
, notify_index
);
1746 cache_node
= g_ptr_array_index (self
->cache_nodes
, notify_index
);
1748 trace ("Watch thread: notify received on prefix %i: %s.\n", notify_index
, prefix
);
1750 if (cache_node
== NULL
)
1752 /* This path has been deleted */
1753 trace ("Notify received on a path that was deleted\n");
1757 /* Firstly we need to reapply for the notification, because (what a
1758 * sensible API) we won't receive any more. MSDN is pretty
1759 * inconsistent on this matter:
1760 * http://msdn.microsoft.com/en-us/library/ms724892%28VS.85%29.aspx
1761 * http://support.microsoft.com/kb/236570
1762 * But my tests (on Windows XP SP3) show that we need to reapply
1765 result
= registry_watch_key (hpath
, cond
);
1767 if (result
!= ERROR_SUCCESS
)
1769 /* Watch failed, most likely because the key has just been
1770 * deleted. Free the watch and unref the cache nodes.
1772 if (result
!= ERROR_KEY_DELETED
)
1773 g_message_win32_error (result
, "watch thread: failed to watch %s", prefix
);
1775 _free_watch (self
, notify_index
, cache_node
);
1776 g_atomic_int_inc (&self
->watches_remaining
);
1780 /* The notification may have been blocked because we just changed
1781 * some data ourselves.
1783 cache_item
= cache_node
->data
;
1784 if (cache_item
->block_count
)
1786 cache_item
->block_count
--;
1787 trace ("Watch thread: notify blocked at %s\n", prefix
);
1791 /* Now we update our stored cache from registry data, and find which keys have
1792 * actually changed. If more changes happen while we are processing, we will get
1793 * another event because we have reapplied for change notifications already.
1795 * Working here rather than in the main thread is preferable because the UI is less
1796 * likely to block (only when changing notification subscriptions).
1798 event
= g_slice_new (RegistryEvent
);
1799 event
->self
= g_object_ref (self
->owner
);
1800 event
->prefix
= g_strdup (prefix
);
1801 event
->items
= g_ptr_array_new_with_free_func (g_free
);
1803 EnterCriticalSection (G_REGISTRY_BACKEND (self
->owner
)->cache_lock
);
1804 registry_cache_update (G_REGISTRY_BACKEND (self
->owner
), hpath
,
1805 prefix
, NULL
, cache_node
, 0, event
);
1806 LeaveCriticalSection (G_REGISTRY_BACKEND (self
->owner
)->cache_lock
);
1808 if (event
->items
->len
> 0)
1809 g_idle_add ((GSourceFunc
) watch_handler
, event
);
1812 g_object_unref (event
->self
);
1813 g_free (event
->prefix
);
1814 g_ptr_array_free (event
->items
, TRUE
);
1815 g_slice_free (RegistryEvent
, event
);
1820 /* God knows what has happened */
1821 g_message_win32_error (GetLastError(), "watch thread: WaitForMultipleObjects error");
1829 watch_start (GRegistryBackend
*self
)
1831 WatchThreadState
*watch
;
1833 g_return_val_if_fail (self
->watch
== NULL
, FALSE
);
1835 watch
= g_slice_new (WatchThreadState
);
1836 watch
->owner
= G_SETTINGS_BACKEND (self
);
1838 watch
->watches_remaining
= MAX_WATCHES
;
1840 watch
->message_lock
= g_slice_new (CRITICAL_SECTION
);
1841 InitializeCriticalSection (watch
->message_lock
);
1842 watch
->message_sent_event
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
1843 watch
->message_received_event
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
1844 if (watch
->message_sent_event
== NULL
|| watch
->message_received_event
== NULL
)
1846 g_message_win32_error (GetLastError (), "gregistrybackend: Failed to create sync objects.");
1850 /* Use a small stack to make the thread more lightweight. */
1851 watch
->thread
= CreateThread (NULL
, 1024, watch_thread_function
, watch
, 0, NULL
);
1852 if (watch
->thread
== NULL
)
1854 g_message_win32_error (GetLastError (), "gregistrybackend: Failed to create notify watch thread.");
1858 self
->watch
= watch
;
1863 DeleteCriticalSection (watch
->message_lock
);
1864 g_slice_free (CRITICAL_SECTION
, watch
->message_lock
);
1865 if (watch
->message_sent_event
!= NULL
)
1866 CloseHandle (watch
->message_sent_event
);
1867 if (watch
->message_received_event
!= NULL
)
1868 CloseHandle (watch
->message_received_event
);
1869 g_slice_free (WatchThreadState
, watch
);
1874 /* This function assumes you hold the message lock! */
1876 watch_stop_unlocked (GRegistryBackend
*self
)
1878 WatchThreadState
*watch
= self
->watch
;
1881 g_return_if_fail (watch
!= NULL
);
1883 watch
->message
.type
= WATCH_THREAD_STOP
;
1884 SetEvent (watch
->message_sent_event
);
1886 /* This is signalled as soon as the message is received. We must not return
1887 * while the watch thread is still firing off callbacks. Freeing all of the
1888 * memory is done in the watch thread after this is signalled.
1890 result
= WaitForSingleObject (watch
->message_received_event
, INFINITE
);
1891 if (result
!= WAIT_OBJECT_0
)
1893 g_warning ("gregistrybackend: unable to stop watch thread.");
1897 LeaveCriticalSection (watch
->message_lock
);
1898 DeleteCriticalSection (watch
->message_lock
);
1899 g_slice_free (CRITICAL_SECTION
, watch
->message_lock
);
1900 CloseHandle (watch
->message_sent_event
);
1901 CloseHandle (watch
->message_received_event
);
1902 CloseHandle (watch
->thread
);
1903 g_slice_free (WatchThreadState
, watch
);
1905 trace ("\nwatch thread: %x: all data freed.\n", self
);
1910 watch_add_notify (GRegistryBackend
*self
,
1913 gchar
*gsettings_prefix
)
1915 WatchThreadState
*watch
= self
->watch
;
1917 RegistryCacheItem
*cache_item
;
1922 g_return_val_if_fail (watch
!= NULL
, FALSE
);
1924 trace ("watch_add_notify: prefix %s.\n", gsettings_prefix
);
1926 /* Duplicate tree into the cache in the main thread, before we add the notify: if we do it in the
1927 * thread we can miss changes while we are caching.
1929 EnterCriticalSection (self
->cache_lock
);
1930 cache_node
= registry_cache_get_node_for_key (self
->cache_root
, gsettings_prefix
, TRUE
);
1932 if (cache_node
== NULL
|| cache_node
->data
== NULL
)
1934 LeaveCriticalSection (self
->cache_lock
);
1935 g_warn_if_reached ();
1939 cache_item
= cache_node
->data
;
1941 cache_item
->subscription_count
++;
1942 if (cache_item
->subscription_count
> 1)
1944 trace ("watch_add_notify: prefix %s already watched, %i subscribers.\n",
1945 gsettings_prefix
, cache_item
->subscription_count
);
1946 LeaveCriticalSection (self
->cache_lock
);
1950 registry_cache_ref_tree (cache_node
);
1951 registry_cache_update (self
, hpath
, gsettings_prefix
, NULL
, cache_node
, 0, NULL
);
1952 //registry_cache_dump (self->cache_root, NULL);
1953 LeaveCriticalSection (self
->cache_lock
);
1955 EnterCriticalSection (watch
->message_lock
);
1956 watch
->message
.type
= WATCH_THREAD_ADD_WATCH
;
1957 watch
->message
.watch
.event
= event
;
1958 watch
->message
.watch
.hpath
= hpath
;
1959 watch
->message
.watch
.prefix
= gsettings_prefix
;
1960 watch
->message
.watch
.cache_node
= cache_node
;
1962 SetEvent (watch
->message_sent_event
);
1964 /* Wait for the received event in return, to avoid sending another message before the first
1965 * one was received. If it takes > 200ms there is a possible race but the worst outcome is
1966 * a notification is ignored.
1971 WaitForSingleObject (watch
->message_received_event
, 200);
1973 if (result
!= WAIT_OBJECT_0
)
1974 trace ("watch thread is slow to respond - notification may not be added.");
1977 LeaveCriticalSection (watch
->message_lock
);
1983 watch_remove_notify (GRegistryBackend
*self
,
1984 const gchar
*key_name
)
1986 WatchThreadState
*watch
= self
->watch
;
1989 if (self
->watch
== NULL
)
1990 /* Here we assume that the unsubscribe message is for somewhere that was
1991 * deleted, and so it has already been removed and the watch thread has
1996 EnterCriticalSection (watch
->message_lock
);
1997 watch
->message
.type
= WATCH_THREAD_REMOVE_WATCH
;
1998 watch
->message
.watch
.prefix
= g_strdup (key_name
);
2000 SetEvent (watch
->message_sent_event
);
2002 /* Wait for the received event in return, to avoid sending another message before the first
2005 result
= WaitForSingleObject (watch
->message_received_event
, INFINITE
);
2007 if (result
!= ERROR_SUCCESS
)
2008 g_warning ("unsubscribe from %s: message not acknowledged", key_name
);
2010 if (g_atomic_int_get (&watch
->watches_remaining
) >= MAX_WATCHES
)
2011 /* Stop it before any new ones can get added and confuse things */
2012 watch_stop_unlocked (self
);
2014 LeaveCriticalSection (watch
->message_lock
);
2017 /* dconf semantics are: if the key ends in /, watch the keys underneath it - if not, watch that
2018 * key. Our job is easier because keys and values are separate.
2021 g_registry_backend_subscribe (GSettingsBackend
*backend
,
2022 const char *key_name
)
2024 GRegistryBackend
*self
= G_REGISTRY_BACKEND (backend
);
2026 gunichar2
*path_namew
;
2027 gchar
*value_name
= NULL
;
2032 if (self
->watch
== NULL
&& !watch_start (self
))
2035 if (g_atomic_int_dec_and_test (&self
->watch
->watches_remaining
))
2037 g_atomic_int_inc (&self
->watch
->watches_remaining
);
2038 g_warning ("subscribe() failed: only %i different paths may be watched.", MAX_WATCHES
);
2042 path_name
= parse_key (key_name
, self
->base_path
, &value_name
);
2044 /* Must check for this, otherwise strange crashes occur because the cache
2045 * node that is being watched gets freed. All path names to subscribe must
2048 if (value_name
!= NULL
&& *value_name
!= 0)
2049 g_warning ("subscribe() failed: path must end in a /, got %s", key_name
);
2051 trace ("Subscribing to %s [registry %s / %s] - watch %x\n", key_name
, path_name
, value_name
, self
->watch
);
2053 path_namew
= g_utf8_to_utf16 (path_name
, -1, NULL
, NULL
, NULL
);
2056 /* Give the caller the benefit of the doubt if the key doesn't exist and create it. The caller
2057 * is almost certainly a new g_settings with this path as base path. */
2058 result
= RegCreateKeyExW (HKEY_CURRENT_USER
, path_namew
, 0, NULL
, 0, KEY_READ
, NULL
, &hpath
,
2060 g_free (path_namew
);
2062 if (result
!= ERROR_SUCCESS
)
2064 g_message_win32_error (result
, "gregistrybackend: Unable to subscribe to key %s.", key_name
);
2065 g_atomic_int_inc (&self
->watch
->watches_remaining
);
2069 event
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
2072 g_message_win32_error (result
, "gregistrybackend: CreateEvent failed.");
2073 g_atomic_int_inc (&self
->watch
->watches_remaining
);
2074 RegCloseKey (hpath
);
2078 /* The actual watch is added by the thread, which has to re-subscribe each time it
2079 * receives a change. */
2080 if (!watch_add_notify (self
, event
, hpath
, g_strdup (key_name
)))
2082 g_atomic_int_inc (&self
->watch
->watches_remaining
);
2083 RegCloseKey (hpath
);
2084 CloseHandle (event
);
2089 g_registry_backend_unsubscribe (GSettingsBackend
*backend
,
2090 const char *key_name
)
2092 trace ("unsubscribe: %s.\n", key_name
);
2094 watch_remove_notify (G_REGISTRY_BACKEND (backend
), key_name
);
2097 /********************************************************************************
2098 * Object management junk
2099 ********************************************************************************/
2102 g_registry_backend_finalize (GObject
*object
)
2104 GRegistryBackend
*self
= G_REGISTRY_BACKEND (object
);
2105 RegistryCacheItem
*item
;
2107 item
= self
->cache_root
->data
;
2108 g_warn_if_fail (item
->ref_count
== 1);
2110 registry_cache_item_free (item
);
2111 g_node_destroy (self
->cache_root
);
2113 if (self
->watch
!= NULL
)
2115 EnterCriticalSection (self
->watch
->message_lock
);
2116 watch_stop_unlocked (self
);
2119 DeleteCriticalSection (self
->cache_lock
);
2120 g_slice_free (CRITICAL_SECTION
, self
->cache_lock
);
2122 g_free (self
->base_path
);
2123 g_free (self
->base_pathw
);
2127 g_registry_backend_class_init (GRegistryBackendClass
*class)
2129 GSettingsBackendClass
*backend_class
= G_SETTINGS_BACKEND_CLASS (class);
2130 GObjectClass
*object_class
= G_OBJECT_CLASS (class);
2132 object_class
->finalize
= g_registry_backend_finalize
;
2134 backend_class
->read
= g_registry_backend_read
;
2135 backend_class
->write
= g_registry_backend_write
;
2136 backend_class
->write_tree
= g_registry_backend_write_tree
;
2137 backend_class
->reset
= g_registry_backend_reset
;
2138 backend_class
->get_writable
= g_registry_backend_get_writable
;
2139 backend_class
->subscribe
= g_registry_backend_subscribe
;
2140 backend_class
->unsubscribe
= g_registry_backend_unsubscribe
;
2144 g_registry_backend_init (GRegistryBackend
*self
)
2146 RegistryCacheItem
*item
;
2148 self
->base_path
= g_strdup_printf ("Software\\GSettings");
2149 self
->base_pathw
= g_utf8_to_utf16 (self
->base_path
, -1, NULL
, NULL
, NULL
);
2151 item
= g_slice_new (RegistryCacheItem
);
2152 item
->value
.type
= REG_NONE
;
2153 item
->value
.ptr
= NULL
;
2154 item
->name
= g_strdup ("<root>");
2155 item
->ref_count
= 1;
2156 self
->cache_root
= g_node_new (item
);
2158 self
->cache_lock
= g_slice_new (CRITICAL_SECTION
);
2159 InitializeCriticalSection (self
->cache_lock
);