2 * Copyright © 2009-10 Sam Thursfield
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the licence, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Author: Sam Thursfield <ssssam@gmail.com>
22 /* GRegistryBackend implementation notes:
24 * - All settings are stored under the path:
25 * HKEY_CURRENT_USER\Software\GSettings\
26 * This means all settings are per-user. Permissions and system-wide
27 * defaults are not implemented and will probably always be out of scope of
28 * the Windows port of GLib.
30 * - The registry type system is limited. Most GVariant types are stored as
31 * literals via g_variant_print/parse(). Strings are stored without the
32 * quotes that GVariant requires. Integer types are stored as native
33 * REG_DWORD or REG_QWORD. The REG_MULTI_SZ (string array) type could be
34 * used to avoid flattening container types.
36 * - Notifications are handled; the change event is watched for in a separate
37 * thread (Windows does not provide a callback API) which sends them with
38 * g_idle_add to the GLib main loop. The threading is done using Windows
39 * API functions, so there is no dependence on GThread.
41 * - Windows doesn't tell us which value has changed. This means we have to
42 * maintain a cache of every stored value so we can play spot the
43 * difference. This should not be a performance issue because if you are
44 * storing thousands of values in GSettings, you are probably using it
47 * - The cache stores the value as a registry type. Because many variants are
48 * stored as string representations, values which have changed equality but
49 * not equivalence may trigger spurious change notifications. GSettings
50 * users must already deal with this possibility and converting all data to
51 * GVariant values would be more effort.
53 * - Because we have to cache every registry value locally, reads are done
54 * from the cache rather than directly from the registry. Writes update
55 * both. This means that the backend will not work if the watch thread is
56 * not running. A GSettings object always subscribes to changes so we can
57 * be sure that the watch thread will be running, but if for some reason
58 * the backend is being used directly you should bear that in mind.
60 * - The registry is totally user-editable, so we are very forgiving about
61 * errors in the data we get.
63 * - The registry uses backslashes as path separators. GSettings keys only
64 * allow [A-Za-z\-] so no escaping is needed. No attempt is made to solve
65 * clashes between keys differing only in case.
67 * - RegCreateKeyA is used - Windows can also handle UTF16LE strings.
68 * GSettings doesn't pay any attention to encoding, so by using ANSI we
69 * hopefully avoid passing any invalid Unicode.
71 * - The Windows registry has the following limitations: a key may not exceed
72 * 255 characters, an entry's value may not exceed 16,383 characters, and
73 * all the values of a key may not exceed 65,535 characters.
76 * * in GSettings, a 'key' is eg. /desktop/gnome/background/primary-color
77 * * in the registry, the 'key' is path, which contains some 'values'.
78 * * in this file, any GSettings key is a 'key', while a registry key is
79 * termed a 'path', which contains 'values'.
81 * - My set of tests for this backend are currently at:
82 * http://gitorious.org/gsettings-gtk/gsettings-test.git
84 * - There is an undocumented function in ntdll.dll which might be more
85 * than RegNotifyChangeKeyValue(), NtNotifyChangeKey:
86 * http://source.winehq.org/source/dlls/ntdll/reg.c#L618
87 * http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/NT%20Objects/Key/NtNotifyChangeKey.html
89 * - If updating the cache ever becomes a performance issue it may make sense
90 * to use a red-black tree, but I don't currently think it's worth the time
95 #include "gregistrysettingsbackend.h"
96 #include "gsimplepermission.h"
97 #include "gsettingsbackend.h"
98 #include "giomodule.h"
101 #define _WIN32_WINNT 0x0500
102 #define WIN32_LEAN_AND_MEAN
107 /* GSettings' limit */
108 #define MAX_KEY_NAME_LENGTH 32
110 /* Testing (on Windows XP SP3) shows that WaitForMultipleObjects fails with
111 * "The parameter is incorrect" after 64 watches. We need one for the
112 * message_sent cond, which is allowed for in the way the watches_remaining
115 #define MAX_WATCHES 64
117 /* A watch on one registry path and its subkeys */
127 /* Simple message passing for the watch thread. Not enough traffic to
133 WATCH_THREAD_ADD_WATCH
,
134 WATCH_THREAD_REMOVE_WATCH
,
136 } WatchThreadMessageType
;
140 WatchThreadMessageType type
;
142 } WatchThreadMessage
;
147 GSettingsBackend
*owner
;
150 /* Details of the things we are watching. */
151 int watches_remaining
;
152 GPtrArray
*events
, *handles
, *prefixes
, *cache_nodes
;
154 /* Communication with the main thread. Only one message is stored at a time,
155 * to make sure that messages are acknowledged before being overwritten we
156 * create two events - one is signalled when a new message is set, the
157 * other is signalled by the thread when it has processed the message.
159 WatchThreadMessage message
;
160 CRITICAL_SECTION
*message_lock
;
161 HANDLE message_sent_event
, message_received_event
;
165 #define G_TYPE_REGISTRY_BACKEND (g_registry_backend_get_type ())
166 #define G_REGISTRY_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
167 G_TYPE_REGISTRY_BACKEND, GRegistryBackend))
168 #define G_IS_REGISTRY_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
169 G_TYPE_REGISTRY_BACKEND))
172 typedef GSettingsBackendClass GRegistryBackendClass
;
175 GSettingsBackend parent_instance
;
179 /* A stored copy of the whole tree being watched. When we receive a change notification
180 * we have to check against this to see what has changed ... every time ...*/
181 CRITICAL_SECTION
*cache_lock
;
184 WatchThreadState
*watch
;
187 G_DEFINE_TYPE_WITH_CODE (GRegistryBackend
,
189 G_TYPE_SETTINGS_BACKEND
,
190 g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME
,
191 g_define_type_id
, "registry", 90))
194 /**********************************************************************************
196 **********************************************************************************/
200 trace (const char *format
, ...)
203 va_list va
; va_start (va
, format
);
204 vprintf (format
, va
); fflush (stdout
);
209 /* g_message including a windows error message. It is not useful to have an
210 * equivalent function for g_warning because none of the registry errors can
211 * result from programmer error (Microsoft programmers don't count), instead
212 * they will mostly occur from people messing with the registry by hand. */
214 g_message_win32_error (DWORD result_code
,
220 gchar win32_message
[1024];
222 if (result_code
== 0)
223 result_code
= GetLastError ();
225 va_start (va
, format
);
226 pos
= g_vsnprintf (win32_message
, 512, format
, va
);
228 win32_message
[pos
++] = ':'; win32_message
[pos
++] = ' ';
230 FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM
, NULL
, result_code
, 0, (LPTSTR
)(win32_message
+pos
),
233 if (result_code
== ERROR_KEY_DELETED
)
234 trace ("(%s)", win32_message
);
236 g_message (win32_message
);
240 /* Make gsettings key into a registry path & value pair.
242 * Note that the return value *only* needs freeing - registry_value_name
243 * is a pointer to further inside the same block of memory.
246 parse_key (const gchar
*key_name
,
247 const gchar
*registry_prefix
,
250 gchar
*path_name
, *c
;
252 /* All key paths are treated as absolute; gsettings doesn't seem to enforce a
255 if (key_name
[0] == '/')
258 if (registry_prefix
== NULL
)
259 path_name
= g_strdup (key_name
);
261 path_name
= g_strjoin ("/", registry_prefix
, key_name
, NULL
);
263 /* Prefix is expected to be in registry format (\ separators) so don't escape that. */
264 for (c
=path_name
+(registry_prefix
?strlen(registry_prefix
):0); *c
!=0; c
++)
271 **value_name
= 0; (*value_name
)++;
277 g_variant_get_as_dword (GVariant
*variant
)
279 switch (g_variant_get_type_string (variant
)[0])
281 case 'b': return g_variant_get_boolean (variant
);
282 case 'y': return g_variant_get_byte (variant
);
283 case 'n': return g_variant_get_int16 (variant
);
284 case 'q': return g_variant_get_uint16 (variant
);
285 case 'i': return g_variant_get_int32 (variant
);
286 case 'u': return g_variant_get_uint32 (variant
);
287 default: g_warn_if_reached ();
293 g_variant_get_as_qword (GVariant
*variant
)
295 switch (g_variant_get_type_string (variant
)[0])
297 case 'x': return g_variant_get_int64 (variant
);
298 case 't': return g_variant_get_uint64 (variant
);
299 default: g_warn_if_reached ();
306 handle_read_error (LONG result
,
307 const gchar
*path_name
,
308 const gchar
*value_name
)
310 /* file not found means key value not set, this isn't an error for us. */
311 if (result
!= ERROR_FILE_NOT_FOUND
)
312 g_message_win32_error (result
, "Unable to query value %s/%s: %s.\n",
313 path_name
, value_name
);
316 /***************************************************************************
317 * Cache of registry values
318 ***************************************************************************/
320 /* Generic container for registry values */
325 gint dword
; /* FIXME: could inline QWORD on 64-bit systems too */
331 registry_value_dump (RegistryValue value
)
333 if (value
.type
== REG_DWORD
)
334 return g_strdup_printf ("%i", value
.dword
);
335 else if (value
.type
== REG_QWORD
)
336 return g_strdup_printf ("%I64i", value
.ptr
==NULL
? 0: *(DWORDLONG
*)value
.ptr
);
337 else if (value
.type
== REG_SZ
)
338 return g_strdup_printf ("%s", (char *)value
.ptr
);
339 else if (value
.type
== REG_NONE
)
340 return g_strdup_printf ("<empty>");
342 return g_strdup_printf ("<invalid>");
346 registry_value_free (RegistryValue value
)
348 if (value
.type
== REG_SZ
|| value
.type
== REG_QWORD
)
350 value
.type
= REG_NONE
;
355 /* The registry cache is stored as a tree, for easy traversal. Right now we
356 * don't sort it in a clever way. Each node corresponds to a path element
357 * ('key' in registry terms) or a value.
359 * Each subscription uses the same cache. Because GSettings can subscribe to
360 * the tree at any node any number of times, we need to reference count the
365 /* Component of path that this node represents */
368 /* If a watch is subscribed at this point (subscription_count > 0) we can
369 * block its next notification. This is useful because if two watches cover
370 * the same path, both will trigger when it changes. It also allows changes
371 * done by the application to be ignored by the watch thread.
373 gint32 block_count
: 8;
375 /* Number of times g_settings_subscribe has been called for this location
376 * (I guess you can't subscribe more than 16383 times) */
377 gint32 subscription_count
: 14;
379 gint32 ref_count
: 9;
388 registry_cache_add_item (GNode
*parent
,
393 RegistryCacheItem
*item
= g_slice_new (RegistryCacheItem
);
396 g_return_val_if_fail (name
!= NULL
, NULL
);
397 g_return_val_if_fail (parent
!= NULL
, NULL
);
399 /* Ref count should be the number of watch points above this node */
400 item
->ref_count
= ref_count
;
402 item
->name
= g_strdup (name
);
404 item
->subscription_count
= 0;
405 item
->block_count
= 0;
406 item
->touched
= FALSE
;
407 trace ("\treg cache: adding %s to %s\n", name
, ((RegistryCacheItem
*)parent
->data
)->name
);
409 cache_node
= g_node_new (item
);
410 g_node_append (parent
, cache_node
);
414 /* The reference counting of cache tree nodes works like this: when a node is
415 * subscribed to (GSettings wants us to watch that path and everything below
416 * it) the reference count of that node and everything below is increased, as
417 * well as each parent up to the root.
422 _ref_down (GNode
*node
)
424 RegistryCacheItem
*item
= node
->data
;
425 g_node_children_foreach (node
, G_TRAVERSE_ALL
,
426 (GNodeForeachFunc
)_ref_down
, NULL
);
430 registry_cache_ref_tree (GNode
*tree
)
432 RegistryCacheItem
*item
= tree
->data
;
433 GNode
*node
= tree
->parent
;
435 g_return_if_fail (tree
!= NULL
);
439 g_node_children_foreach (tree
, G_TRAVERSE_ALL
,
440 (GNodeForeachFunc
)_ref_down
, NULL
);
442 for (node
=tree
->parent
; node
; node
=node
->parent
)
450 _free_cache_item (RegistryCacheItem
*item
)
452 trace ("\t -- Free node %s\n", item
->name
);
454 registry_value_free (item
->value
);
455 g_slice_free (RegistryCacheItem
, item
);
458 /* Unreferencing has to be done bottom-up */
460 _unref_node (GNode
*node
)
462 RegistryCacheItem
*item
= node
->data
;
466 g_warn_if_fail (item
->ref_count
>= 0);
468 if (item
->ref_count
== 0)
470 _free_cache_item (item
);
471 g_node_destroy (node
);
476 _unref_down (GNode
*node
)
478 g_node_children_foreach (node
, G_TRAVERSE_ALL
,
479 (GNodeForeachFunc
)_unref_down
, NULL
);
484 registry_cache_unref_tree (GNode
*tree
)
486 GNode
*parent
= tree
->parent
, *next_parent
;
492 next_parent
= parent
->parent
;
493 _unref_node (parent
);
494 parent
= next_parent
;
500 registry_cache_dump (GNode
*cache_node
,
503 RegistryCacheItem
*item
= cache_node
->data
;
505 int depth
= GPOINTER_TO_INT(data
),
509 g_return_if_fail (cache_node
!= NULL
);
511 for (i
=0; i
<depth
; i
++)
514 g_print ("*root*\n");
516 g_print ("'%s' [%i] @ %x = %s\n", item
->name
, item
->ref_count
, (guint
)cache_node
,
517 registry_value_dump (item
->value
));
518 g_node_children_foreach (cache_node
, G_TRAVERSE_ALL
, registry_cache_dump
,
519 GINT_TO_POINTER (new_depth
));
527 } RegistryCacheSearch
;
530 registry_cache_find_compare (GNode
*node
,
533 RegistryCacheSearch
*search
= data
;
534 RegistryCacheItem
*item
= node
->data
;
536 if (item
== NULL
) /* root node */
539 g_return_val_if_fail (search
->name
!= NULL
, FALSE
);
540 g_return_val_if_fail (item
->name
!= NULL
, FALSE
);
542 if (strcmp (search
->name
, item
->name
) == 0)
544 search
->result
= node
;
551 registry_cache_find_immediate_child (GNode
*node
,
554 RegistryCacheSearch search
;
555 search
.result
= NULL
;
557 g_node_traverse (node
, G_POST_ORDER
, G_TRAVERSE_ALL
, 2,
558 registry_cache_find_compare
, &search
);
559 return search
.result
;
564 registry_cache_get_node_for_key_recursive (GNode
*node
,
566 gboolean create_if_not_found
,
567 gint n_parent_watches
)
569 RegistryCacheItem
*item
;
570 gchar
*component
= key_name
,
571 *c
= strchr (component
, '/');
577 /* We count up how many watch points we travel through finding this node,
578 * because a new node should have as many references as there are watches at
579 * points above it in the tree.
582 if (item
->subscription_count
> 0)
585 child
= registry_cache_find_immediate_child (node
, component
);
586 if (child
== NULL
&& create_if_not_found
)
588 item
= g_slice_new (RegistryCacheItem
);
589 item
->name
= g_strdup (component
);
590 item
->value
.type
= REG_NONE
;
591 item
->value
.ptr
= NULL
;
592 item
->ref_count
= n_parent_watches
;
593 child
= g_node_new (item
);
594 g_node_append (node
, child
);
595 trace ("\tget node for key recursive: new %x = %s.\n", node
, item
->name
);
598 /* We are done if there are no more path components. Allow for a trailing /. */
599 if (child
==NULL
|| c
== NULL
|| *(c
+1)==0)
603 trace ("get node for key recursive: next: %s.\n", c
+1);
604 return registry_cache_get_node_for_key_recursive
605 (child
, c
+1, create_if_not_found
, n_parent_watches
);
609 /* Look up a GSettings key in the cache. */
611 registry_cache_get_node_for_key (GNode
*root
,
612 const gchar
*key_name
,
613 gboolean create_if_not_found
)
617 gchar
*component
, *c
;
619 g_return_val_if_fail (key_name
!= NULL
, NULL
);
621 if (key_name
[0] == '/')
624 /* Ignore preceding / */
625 component
= g_strdup (key_name
);
626 c
= strchr (component
, '/');
630 child
= registry_cache_find_immediate_child (root
, component
);
631 if (child
== NULL
&& create_if_not_found
)
633 /* Reference count is set to 0, tree should be referenced by the caller */
634 RegistryCacheItem
*item
= g_slice_new (RegistryCacheItem
);
635 item
->value
.type
= REG_NONE
;
636 item
->value
.ptr
= NULL
;
637 item
->name
= g_strdup (component
);
639 trace ("get_node_for_key: New node for component '%s'\n", item
->name
);
640 child
= g_node_new (item
);
641 g_node_append (root
, child
);
648 else if (child
!= NULL
)
649 result
= registry_cache_get_node_for_key_recursive (child
, c
+1, create_if_not_found
, 0);
656 /* Check the cache node against the registry key it represents. Return TRUE if
657 * they differ, and update the cache with the new value.
660 registry_cache_update_node (GNode
*cache_node
,
661 RegistryValue registry_value
)
663 RegistryCacheItem
*cache_item
= cache_node
->data
;
665 g_return_val_if_fail (cache_node
!= NULL
, FALSE
);
666 g_return_val_if_fail (cache_item
!= NULL
, FALSE
);
668 if (registry_value
.type
!= cache_item
->value
.type
)
670 /* The type has changed. Update cache item and register it as changed.
671 * Either the schema has changed and this is entirely legitimate, or
672 * whenever the app reads the key it will get the default value due to
675 cache_item
->value
= registry_value
;
679 switch (registry_value
.type
)
683 if (cache_item
->value
.dword
== registry_value
.dword
)
687 cache_item
->value
.dword
= registry_value
.dword
;
693 g_return_val_if_fail (registry_value
.ptr
!= NULL
&&
694 cache_item
->value
.ptr
!= NULL
, FALSE
);
696 if (memcmp (registry_value
.ptr
, cache_item
->value
.ptr
, 8)==0)
698 g_free (registry_value
.ptr
);
703 g_free (cache_item
->value
.ptr
);
704 cache_item
->value
.ptr
= registry_value
.ptr
;
710 /* Value should not exist if it is NULL, an empty string is "" */
711 g_return_val_if_fail (cache_item
->value
.ptr
!= NULL
, FALSE
);
712 g_return_val_if_fail (registry_value
.ptr
!= NULL
, FALSE
);
714 if (strcmp (registry_value
.ptr
, cache_item
->value
.ptr
) == 0)
716 g_free (registry_value
.ptr
);
721 g_free (cache_item
->value
.ptr
);
722 cache_item
->value
.ptr
= registry_value
.ptr
;
727 g_warning ("gregistrybackend: registry_cache_update_node: Unhandled value type :(");
732 /* Blocking notifications is a useful optimisation. When a change is made
733 * through GSettings we update the cache manually, but a notifcation is
734 * triggered as well. This function is also used for nested notifications,
735 * eg. if /test and /test/foo are watched, and /test/foo/value is changed then
736 * we will get notified both for /test/foo and /test and it is helpful to block
740 registry_cache_block_notification (GNode
*node
)
742 RegistryCacheItem
*item
= node
->data
;
744 g_return_if_fail (node
!= NULL
);
746 if (item
->subscription_count
> 0)
747 item
->block_count
++;
749 if (node
->parent
!= NULL
)
750 registry_cache_block_notification (node
->parent
);
754 registry_cache_destroy_tree (GNode
*node
,
755 WatchThreadState
*self
);
757 /***************************************************************************
758 * Reading and writing
759 ***************************************************************************/
762 registry_read (HKEY hpath
,
763 const gchar
*path_name
,
764 const gchar
*value_name
,
765 RegistryValue
*p_value
)
768 DWORD value_data_size
;
771 g_return_val_if_fail (p_value
!= NULL
, FALSE
);
773 p_value
->type
= REG_NONE
;
776 result
= RegQueryValueExA (hpath
, value_name
, 0, &p_value
->type
, NULL
, &value_data_size
);
777 if (result
!= ERROR_SUCCESS
)
779 handle_read_error (result
, path_name
, value_name
);
783 if (p_value
->type
== REG_SZ
&& value_data_size
== 0)
785 p_value
->ptr
= g_strdup ("");
789 if (p_value
->type
== REG_DWORD
)
790 /* REG_DWORD is inlined */
791 buffer
= (void *)&p_value
->dword
;
793 buffer
= p_value
->ptr
= g_malloc (value_data_size
);
795 result
= RegQueryValueExA (hpath
, value_name
, 0, NULL
, (LPBYTE
)buffer
, &value_data_size
);
796 if (result
!= ERROR_SUCCESS
)
798 handle_read_error (result
, path_name
, value_name
);
807 g_registry_backend_read (GSettingsBackend
*backend
,
808 const gchar
*key_name
,
809 const GVariantType
*expected_type
,
810 gboolean default_value
)
812 GRegistryBackend
*self
= G_REGISTRY_BACKEND (backend
);
815 RegistryValue registry_value
;
816 GVariant
*gsettings_value
= NULL
;
817 gchar
*gsettings_type
;
819 g_return_val_if_fail (expected_type
!= NULL
, NULL
);
824 /* Simply read from the cache, which is updated from the registry by the
825 * watch thread as soon as changes can propagate. Any changes not yet in the
826 * cache will have the 'changed' signal emitted after this function returns.
828 EnterCriticalSection (self
->cache_lock
);
829 cache_node
= registry_cache_get_node_for_key (self
->cache_root
, key_name
, FALSE
);
830 LeaveCriticalSection (self
->cache_lock
);
832 trace ("Reading key %s, cache node %x\n", key_name
, cache_node
);
834 /* Maybe it's not set, we can return to default */
835 if (cache_node
== NULL
)
838 trace ("\t- cached value %s\n", registry_value_dump (((RegistryCacheItem
*)cache_node
->data
)->value
));
840 registry_value
= ((RegistryCacheItem
*)cache_node
->data
)->value
;
842 gsettings_type
= g_variant_type_dup_string (expected_type
);
844 /* The registry is user-editable, so we need to be fault-tolerant here. */
845 switch (gsettings_type
[0])
847 case 'b': case 'y': case 'n': case 'q': case 'i': case 'u':
848 if (registry_value
.type
== REG_DWORD
)
849 gsettings_value
= g_variant_new (gsettings_type
, registry_value
.dword
);
853 if (registry_value
.type
== REG_QWORD
)
855 DWORDLONG qword_value
= *(DWORDLONG
*)registry_value
.ptr
;
856 gsettings_value
= g_variant_new (gsettings_type
, qword_value
);
861 if (registry_value
.type
== REG_SZ
)
863 if (gsettings_type
[0]=='s')
864 gsettings_value
= g_variant_new_string ((char *)registry_value
.ptr
);
867 GError
*error
= NULL
;
868 gsettings_value
= g_variant_parse (expected_type
, registry_value
.ptr
, NULL
, NULL
, &error
);
871 g_message ("gregistrysettingsbackend: error parsing key %s: %s\n",
872 key_name
, error
->message
);
878 g_free (gsettings_type
);
880 return gsettings_value
;
886 GRegistryBackend
*self
;
891 g_registry_backend_write_one (const char *key_name
,
895 GRegistryBackend
*self
;
896 RegistryWrite
*action
;
900 gchar
*path_name
, *value_name
= NULL
;
901 DWORD value_data_size
;
908 const gchar
*type_string
= g_variant_get_type_string (variant
);
911 self
= G_REGISTRY_BACKEND (action
->self
);
912 hroot
= action
->hroot
;
914 value
.type
= REG_NONE
;
917 switch (type_string
[0])
919 case 'b': case 'y': case 'n': case 'q': case 'i': case 'u':
920 value
.type
= REG_DWORD
;
921 value
.dword
= g_variant_get_as_dword (variant
);
923 value_data
= &value
.dword
;
927 value
.type
= REG_QWORD
;
928 value
.ptr
= g_malloc (8);
929 *(DWORDLONG
*)value
.ptr
= g_variant_get_as_qword (variant
);
931 value_data
= value
.ptr
;
936 if (type_string
[0]=='s')
939 value
.ptr
= g_strdup (g_variant_get_string (variant
, &length
));
940 value_data_size
= length
+ 1;
941 value_data
= value
.ptr
;
945 GString
*value_string
;
946 value_string
= g_variant_print_string (variant
, NULL
, FALSE
);
947 value_data_size
= value_string
->len
+1;
948 value
.ptr
= value_data
= g_string_free (value_string
, FALSE
);
953 /* First update the cache, because the value may not have changed and we can
956 * If 'value' has changed then its memory will not be freed by update_node(),
957 * because it will be stored in the node.
959 EnterCriticalSection (self
->cache_lock
);
960 node
= registry_cache_get_node_for_key (self
->cache_root
, key_name
, TRUE
);
961 changed
= registry_cache_update_node (node
, value
);
962 LeaveCriticalSection (self
->cache_lock
);
967 /* Block the next notification to any watch points above this location,
968 * because they will each get triggered on a change that is already updated
971 registry_cache_block_notification (node
);
973 path_name
= parse_key (key_name
, NULL
, &value_name
);
975 trace ("Set key: %s / %s\n", path_name
, value_name
);
977 /* Store the value in the registry */
978 result
= RegCreateKeyExA (hroot
, path_name
, 0, NULL
, 0, KEY_WRITE
, NULL
, &hpath
, NULL
);
979 if (result
!= ERROR_SUCCESS
)
981 g_message_win32_error (result
, "gregistrybackend: opening key %s failed", path_name
+1);
982 registry_value_free (value
);
987 result
= RegSetValueExA (hpath
, value_name
, 0, value
.type
, value_data
, value_data_size
);
988 if (result
!= ERROR_SUCCESS
)
989 g_message_win32_error (result
, "gregistrybackend: setting value %s\\%s\\%s failed.\n",
990 self
->base_path
, path_name
, value_name
);
992 /* If the write fails then it will seem like the value has changed until the
993 * next execution (because we wrote to the cache first). There's no reason
994 * for it to fail unless something is weirdly broken, however.
1003 /* The dconf write policy is to do the write while making out it succeeded,
1004 * and then backtrack if it didn't. The registry functions are synchronous so
1005 * we can't do that. */
1008 g_registry_backend_write (GSettingsBackend
*backend
,
1009 const gchar
*key_name
,
1011 gpointer origin_tag
)
1013 GRegistryBackend
*self
= G_REGISTRY_BACKEND (backend
);
1016 RegistryWrite action
;
1018 result
= RegCreateKeyExA (HKEY_CURRENT_USER
, self
->base_path
, 0, NULL
, 0,
1019 KEY_WRITE
, NULL
, &hroot
, NULL
);
1020 if (result
!= ERROR_SUCCESS
) {
1021 trace ("Error opening/creating key %s.\n", self
->base_path
);
1026 action
.hroot
= hroot
;
1027 g_registry_backend_write_one (key_name
, value
, &action
);
1028 g_settings_backend_changed (backend
, key_name
, origin_tag
);
1030 RegCloseKey (hroot
);
1036 g_registry_backend_write_tree (GSettingsBackend
*backend
,
1038 gpointer origin_tag
)
1040 GRegistryBackend
*self
= G_REGISTRY_BACKEND (backend
);
1043 RegistryWrite action
;
1045 result
= RegCreateKeyExA (HKEY_CURRENT_USER
, self
->base_path
, 0, NULL
, 0,
1046 KEY_WRITE
, NULL
, &hroot
, NULL
);
1047 if (result
!= ERROR_SUCCESS
) {
1048 trace ("Error opening/creating key %s.\n", self
->base_path
);
1053 action
.hroot
= hroot
;
1054 g_tree_foreach (values
, (GTraverseFunc
)g_registry_backend_write_one
,
1057 g_settings_backend_changed_tree (backend
, values
, origin_tag
);
1058 RegCloseKey (hroot
);
1064 g_registry_backend_reset (GSettingsBackend
*backend
,
1065 const gchar
*key_name
,
1066 gpointer origin_tag
)
1068 GRegistryBackend
*self
= G_REGISTRY_BACKEND (backend
);
1069 gchar
*path_name
, *value_name
= NULL
;
1074 /* Remove from cache */
1075 EnterCriticalSection (self
->cache_lock
);
1076 cache_node
= registry_cache_get_node_for_key (self
->cache_root
, key_name
, FALSE
);
1078 registry_cache_destroy_tree (cache_node
, self
->watch
);
1079 LeaveCriticalSection (self
->cache_lock
);
1081 /* Remove from the registry */
1082 path_name
= parse_key (key_name
, self
->base_path
, &value_name
);
1084 result
= RegOpenKeyExA (HKEY_CURRENT_USER
, path_name
, 0, KEY_SET_VALUE
, &hpath
);
1085 if (result
!= ERROR_SUCCESS
)
1087 g_message_win32_error (result
, "Registry: resetting key '%s'", path_name
);
1092 result
= RegDeleteValueA (hpath
, value_name
);
1093 RegCloseKey (hpath
);
1095 if (result
!= ERROR_SUCCESS
)
1097 g_message_win32_error (result
, "Registry: resetting key '%s'", path_name
);
1105 g_settings_backend_changed (backend
, key_name
, origin_tag
);
1108 /* Not implemented and probably beyond the scope of this backend */
1110 g_registry_backend_get_writable (GSettingsBackend
*backend
,
1111 const gchar
*key_name
)
1116 static GPermission
*
1117 g_registry_backend_get_permission (GSettingsBackend
*backend
,
1118 const gchar
*key_name
)
1120 return g_simple_permission_new (TRUE
);
1124 /********************************************************************************
1125 * Spot-the-difference engine
1126 ********************************************************************************/
1129 _free_watch (WatchThreadState
*self
,
1134 registry_cache_item_reset_touched (GNode
*node
,
1137 RegistryCacheItem
*item
= node
->data
;
1138 item
->touched
= FALSE
;
1141 /* Delete a node and any children, for when it has been deleted from the registry */
1143 registry_cache_destroy_tree (GNode
*node
,
1144 WatchThreadState
*self
)
1146 RegistryCacheItem
*item
= node
->data
;
1148 g_node_children_foreach (node
, G_TRAVERSE_ALL
,
1149 (GNodeForeachFunc
)registry_cache_destroy_tree
, self
);
1151 if (item
->subscription_count
> 0)
1154 /* There must be some watches active if this node is a watch point */
1155 g_warn_if_fail (self
->cache_nodes
->len
> 1);
1157 /* This is a watch point that has been deleted. Let's free the watch! */
1158 for (i
=1; i
<self
->cache_nodes
->len
; i
++)
1159 if (g_ptr_array_index (self
->cache_nodes
, i
) == node
)
1161 if (i
>= self
->cache_nodes
->len
)
1162 g_warning ("watch thread: a watch point was deleted, but unable to "
1163 "find '%s' in the list of %i watch nodes\n", item
->name
,
1164 self
->cache_nodes
->len
-1);
1167 _free_watch (self
, i
, node
);
1168 g_atomic_int_inc (&self
->watches_remaining
);
1171 _free_cache_item (node
->data
);
1172 g_node_destroy (node
);
1176 registry_cache_remove_deleted (GNode
*node
,
1179 RegistryCacheItem
*item
= node
->data
;
1182 registry_cache_destroy_tree (node
, data
);
1185 /* Update cache from registry, and optionally report on the changes.
1187 * This function is sometimes called from the watch thread, with no locking. It
1188 * does call g_registry_backend functions, but this is okay because they only
1189 * access self->base which is constant.
1191 * When looking at this code bear in mind the terminology: in the registry, keys
1192 * are containers that contain values, and other keys. Keys have a 'default'
1193 * value which we always ignore.
1195 * n_parent_watches: a counter used to set the reference count of any new nodes
1196 * that are created - they should have as many references as
1197 * there are notifications that are watching them.
1200 registry_cache_update (GRegistryBackend
*self
,
1202 const gchar
*prefix
,
1203 const gchar
*partial_key_name
,
1208 gchar buffer
[MAX_KEY_NAME_LENGTH
+ 1];
1213 RegistryCacheItem
*item
= cache_node
->data
;
1215 if (item
->subscription_count
> 0)
1218 /* prefix is the level that all changes occur below; partial_key_name should
1219 * be NULL on the first call to this function */
1220 key_name
= g_build_path ("/", prefix
, partial_key_name
, NULL
);
1222 trace ("registry cache update: %s. Node %x has %i children\n", key_name
,
1223 cache_node
, g_node_n_children (cache_node
));
1225 /* Start by zeroing 'touched' flag. When the registry traversal is done, any untouched nodes
1226 * must have been deleted from the registry.
1228 g_node_children_foreach (cache_node
, G_TRAVERSE_ALL
,
1229 registry_cache_item_reset_touched
, NULL
);
1231 /* Recurse into each subpath at the current level, if any */
1235 DWORD buffer_size
= MAX_KEY_NAME_LENGTH
;
1238 result
= RegEnumKeyEx (hpath
, i
++, buffer
, &buffer_size
, NULL
, NULL
, NULL
, NULL
);
1239 if (result
!= ERROR_SUCCESS
)
1242 result
= RegOpenKeyEx (hpath
, buffer
, 0, KEY_READ
, &hsubpath
);
1243 if (result
== ERROR_SUCCESS
)
1246 RegistryCacheItem
*child_item
;
1248 subkey_node
= registry_cache_find_immediate_child (cache_node
, buffer
);
1249 if (subkey_node
== NULL
)
1251 RegistryValue null_value
= {REG_NONE
, {0}};
1252 subkey_node
= registry_cache_add_item (cache_node
, buffer
,
1253 null_value
, n_watches
);
1257 registry_cache_update (self
, hsubpath
, prefix
, buffer
, subkey_node
,
1258 n_watches
, changes
);
1259 child_item
= subkey_node
->data
;
1260 child_item
->touched
= TRUE
;
1262 RegCloseKey (hsubpath
);
1265 if (result
!= ERROR_NO_MORE_ITEMS
)
1266 g_message_win32_error (result
, "gregistrybackend: error enumerating subkeys for cache.");
1268 /* Enumerate each value at 'path' and check if it has changed */
1272 DWORD buffer_size
= MAX_KEY_NAME_LENGTH
;
1273 GNode
*cache_child_node
;
1274 RegistryCacheItem
*child_item
;
1275 RegistryValue value
;
1276 gboolean changed
= FALSE
;
1278 result
= RegEnumValue (hpath
, i
++, buffer
, &buffer_size
, NULL
, NULL
, NULL
, NULL
);
1279 if (result
!= ERROR_SUCCESS
)
1283 /* This is the key's 'default' value, for which we have no use. */
1286 cache_child_node
= registry_cache_find_immediate_child (cache_node
, buffer
);
1288 if (!registry_read (hpath
, key_name
, buffer
, &value
))
1291 trace ("\tgot value %s for %s, node %x\n", registry_value_dump (value
), buffer
, cache_child_node
);
1293 if (cache_child_node
== NULL
)
1295 /* This is a new value */
1296 cache_child_node
= registry_cache_add_item (cache_node
, buffer
, value
,
1302 /* For efficiency, instead of converting every value back to a GVariant to
1303 * compare it, we compare them as registry values (integers, or string
1304 * representations of the variant). The spurious change notifications that may
1305 * result should not be a big issue.
1307 * Note that 'value' is swallowed or freed.
1309 changed
= registry_cache_update_node (cache_child_node
, value
);
1312 child_item
= cache_child_node
->data
;
1313 child_item
->touched
= TRUE
;
1314 if (changed
== TRUE
&& changes
!= NULL
)
1317 if (partial_key_name
== NULL
)
1318 item
= g_strdup (buffer
);
1320 item
= g_build_path ("/", partial_key_name
, buffer
, NULL
);
1321 g_ptr_array_add (changes
, item
);
1325 if (result
!= ERROR_NO_MORE_ITEMS
)
1326 g_message_win32_error (result
, "gregistrybackend: error enumerating values for cache");
1328 /* Any nodes now left untouched must have been deleted, remove them from cache */
1329 g_node_children_foreach (cache_node
, G_TRAVERSE_ALL
,
1330 registry_cache_remove_deleted
, self
->watch
);
1332 trace ("registry cache update complete.\n");
1338 /***********************************************************************************
1339 * Thread to watch for registry change events
1340 ***********************************************************************************/
1342 /* Called by watch thread. Apply for notifications on a registry key and its subkeys. */
1344 registry_watch_key (HKEY hpath
, HANDLE event
)
1346 return RegNotifyChangeKeyValue (hpath
, TRUE
,
1347 REG_NOTIFY_CHANGE_NAME
| REG_NOTIFY_CHANGE_LAST_SET
,
1352 /* One of these is sent down the pipe when something happens in the registry. */
1355 GRegistryBackend
*self
;
1356 gchar
*prefix
; /* prefix is a gsettings path, all items are subkeys of this. */
1357 GPtrArray
*items
; /* each item is a subkey below prefix that has changed. */
1360 /* This handler runs in the main thread to emit the changed signals */
1362 watch_handler (RegistryEvent
*event
)
1365 trace ("Watch handler: got event in %s, items %i.\n", event
->prefix
, event
->items
->len
);
1367 /* GSettings requires us to NULL-terminate the array. */
1368 g_ptr_array_add (event
->items
, NULL
);
1369 g_settings_backend_keys_changed (G_SETTINGS_BACKEND (event
->self
), event
->prefix
,
1370 (gchar
const **)event
->items
->pdata
, NULL
);
1372 for (i
=0; i
<event
->items
->len
; i
++)
1373 g_free (g_ptr_array_index (event
->items
, i
));
1374 g_ptr_array_free (event
->items
, TRUE
);
1376 g_free (event
->prefix
);
1377 g_object_unref (event
->self
);
1379 g_slice_free (RegistryEvent
, event
);
1380 return G_SOURCE_REMOVE
;
1385 _free_watch (WatchThreadState
*self
,
1393 g_return_if_fail (index
> 0 && index
< self
->events
->len
);
1395 cond
= g_ptr_array_index (self
->events
, index
);
1396 hpath
= g_ptr_array_index (self
->handles
, index
);
1397 prefix
= g_ptr_array_index (self
->prefixes
, index
);
1399 trace ("Freeing watch %i [%s]\n", index
, prefix
);
1401 /* These can be NULL if the watch was already dead, this can happen when eg.
1402 * a key is deleted but GSettings is still subscribed to it - the watch is
1403 * kept alive so that the unsubscribe function works properly, but does not
1407 RegCloseKey (hpath
);
1409 if (cache_node
!= NULL
)
1411 //registry_cache_dump (G_REGISTRY_BACKEND (self->owner)->cache_root, NULL);
1412 registry_cache_unref_tree (cache_node
);
1418 /* As long as we remove from each array at the same time, it doesn't matter that
1419 * their orders get messed up - they all get messed up the same.
1421 g_ptr_array_remove_index_fast (self
->handles
, index
);
1422 g_ptr_array_remove_index_fast (self
->events
, index
);
1423 g_ptr_array_remove_index_fast (self
->prefixes
, index
);
1424 g_ptr_array_remove_index_fast (self
->cache_nodes
, index
);
1428 watch_thread_handle_message (WatchThreadState
*self
)
1430 switch (self
->message
.type
)
1432 case WATCH_THREAD_NONE
:
1433 trace ("watch thread: you woke me up for nothin', man!");
1436 case WATCH_THREAD_ADD_WATCH
:
1438 RegistryWatch
*watch
= &self
->message
.watch
;
1440 result
= registry_watch_key (watch
->hpath
, watch
->event
);
1441 if (result
== ERROR_SUCCESS
)
1443 g_ptr_array_add (self
->events
, watch
->event
);
1444 g_ptr_array_add (self
->handles
, watch
->hpath
);
1445 g_ptr_array_add (self
->prefixes
, watch
->prefix
);
1446 g_ptr_array_add (self
->cache_nodes
, watch
->cache_node
);
1447 trace ("watch thread: new watch on %s, %i total\n", watch
->prefix
,
1452 g_message_win32_error (result
, "watch thread: could not watch %s", watch
->prefix
);
1453 CloseHandle (watch
->event
);
1454 RegCloseKey (watch
->hpath
);
1455 g_free (watch
->prefix
);
1456 registry_cache_unref_tree (watch
->cache_node
);
1461 case WATCH_THREAD_REMOVE_WATCH
:
1464 RegistryCacheItem
*cache_item
;
1467 for (i
=1; i
<self
->prefixes
->len
; i
++)
1468 if (strcmp (g_ptr_array_index (self
->prefixes
, i
),
1469 self
->message
.watch
.prefix
) == 0)
1472 if (i
>= self
->prefixes
->len
)
1474 /* Don't make a fuss if the prefix is not being watched because
1475 * maybe the path was deleted so we removed the watch.
1477 trace ("unsubscribe: prefix %s is not being watched [%i things are]!\n",
1478 self
->message
.watch
.prefix
, self
->prefixes
->len
);
1479 g_free (self
->message
.watch
.prefix
);
1483 cache_node
= g_ptr_array_index (self
->cache_nodes
, i
);
1485 trace ("watch thread: unsubscribe: freeing node %x, prefix %s, index %i\n",
1486 (guint
)cache_node
, self
->message
.watch
.prefix
, i
);
1487 if (cache_node
!= NULL
)
1489 cache_item
= cache_node
->data
;
1491 /* There may be more than one GSettings object subscribed to this
1492 * path, only free the watch when the last one unsubscribes.
1494 cache_item
->subscription_count
--;
1495 if (cache_item
->subscription_count
> 0)
1499 _free_watch (self
, i
, cache_node
);
1500 g_free (self
->message
.watch
.prefix
);
1502 g_atomic_int_inc (&self
->watches_remaining
);
1506 case WATCH_THREAD_STOP
:
1510 /* Free any remaining cache and watch handles */
1511 for (i
=1; i
<self
->events
->len
; i
++)
1512 _free_watch (self
, i
, g_ptr_array_index (self
->cache_nodes
, i
));
1514 SetEvent (self
->message_received_event
);
1519 self
->message
.type
= WATCH_THREAD_NONE
;
1520 SetEvent (self
->message_received_event
);
1524 /* Thread which watches for win32 registry events */
1526 watch_thread_function (LPVOID parameter
)
1528 WatchThreadState
*self
= (WatchThreadState
*)parameter
;
1531 self
->events
= g_ptr_array_new ();
1532 self
->handles
= g_ptr_array_new ();
1533 self
->prefixes
= g_ptr_array_new ();
1534 self
->cache_nodes
= g_ptr_array_new ();
1535 g_ptr_array_add (self
->events
, self
->message_sent_event
);
1536 g_ptr_array_add (self
->handles
, NULL
);
1537 g_ptr_array_add (self
->prefixes
, NULL
);
1538 g_ptr_array_add (self
->cache_nodes
, NULL
);
1542 trace ("watch thread: going to sleep; %i events watched.\n", self
->events
->len
);
1543 result
= WaitForMultipleObjects (self
->events
->len
, self
->events
->pdata
, FALSE
, INFINITE
);
1545 if (result
== WAIT_OBJECT_0
)
1547 /* A message to you. The sender (main thread) will block until we signal the received
1548 * event, so there should be no danger of it sending another before we receive the
1551 watch_thread_handle_message (self
);
1553 else if (result
> WAIT_OBJECT_0
&& result
<= WAIT_OBJECT_0
+ self
->events
->len
)
1559 RegistryCacheItem
*cache_item
;
1560 RegistryEvent
*event
;
1562 /* One of our notifications has triggered. All we know is which one, and which key
1563 * this is for. We do most of the processing here, because we may as well. If the
1564 * registry changes further while we are processing it doesn't matter - we will then
1565 * receive another change notification from the OS anyway.
1567 gint notify_index
= result
- WAIT_OBJECT_0
;
1568 hpath
= g_ptr_array_index (self
->handles
, notify_index
);
1569 cond
= g_ptr_array_index (self
->events
, notify_index
);
1570 prefix
= g_ptr_array_index (self
->prefixes
, notify_index
);
1571 cache_node
= g_ptr_array_index (self
->cache_nodes
, notify_index
);
1573 trace ("Watch thread: notify received on prefix %i: %s.\n", notify_index
, prefix
);
1575 if (cache_node
== NULL
)
1577 /* This path has been deleted */
1578 trace ("Notify received on a path that was deleted :(\n");
1582 /* Firstly we need to reapply for the notification, because (what a
1583 * sensible API) we won't receive any more. MSDN is pretty
1584 * inconsistent on this matter:
1585 * http://msdn.microsoft.com/en-us/library/ms724892%28VS.85%29.aspx
1586 * http://support.microsoft.com/kb/236570
1587 * But my tests (on Windows XP SP3) show that we need to reapply
1590 result
= registry_watch_key (hpath
, cond
);
1592 if (result
!= ERROR_SUCCESS
)
1594 /* Watch failed, most likely because the key has just been
1595 * deleted. Free the watch and unref the cache nodes.
1597 if (result
!= ERROR_KEY_DELETED
)
1598 g_message_win32_error (result
, "watch thread: failed to watch %s", prefix
);
1599 _free_watch (self
, notify_index
, cache_node
);
1600 g_atomic_int_inc (&self
->watches_remaining
);
1604 /* The notification may have been blocked because we just changed
1605 * some data ourselves.
1607 cache_item
= cache_node
->data
;
1608 if (cache_item
->block_count
)
1610 cache_item
->block_count
--;
1611 trace ("Watch thread: notify blocked at %s\n", prefix
);
1615 /* Now we update our stored cache from registry data, and find which keys have
1616 * actually changed. If more changes happen while we are processing, we will get
1617 * another event because we have reapplied for change notifications already.
1619 * Working here rather than in the main thread is preferable because the UI is less
1620 * likely to block (only when changing notification subscriptions).
1622 event
= g_slice_new (RegistryEvent
);
1624 event
->self
= G_REGISTRY_BACKEND (self
->owner
);
1625 g_object_ref (self
->owner
);
1627 event
->items
= g_ptr_array_new ();
1629 EnterCriticalSection (G_REGISTRY_BACKEND (self
->owner
)->cache_lock
);
1630 registry_cache_update (G_REGISTRY_BACKEND (self
->owner
), hpath
,
1631 prefix
, NULL
, cache_node
, 0, event
->items
);
1632 LeaveCriticalSection (G_REGISTRY_BACKEND (self
->owner
)->cache_lock
);
1634 if (event
->items
->len
> 0)
1636 event
->prefix
= g_strdup (prefix
);
1637 g_idle_add ((GSourceFunc
) watch_handler
, event
);
1641 g_ptr_array_free (event
->items
, TRUE
);
1642 g_slice_free (RegistryEvent
, event
);
1647 /* God knows what has happened */
1648 g_message_win32_error (GetLastError(), "watch thread: WaitForMultipleObjects error");
1656 watch_start (GRegistryBackend
*self
)
1658 WatchThreadState
*watch
;
1660 g_return_val_if_fail (self
->watch
== NULL
, FALSE
);
1662 self
->cache_lock
= g_slice_new (CRITICAL_SECTION
);
1663 InitializeCriticalSection (self
->cache_lock
);
1665 watch
= g_slice_new (WatchThreadState
);
1666 watch
->owner
= G_SETTINGS_BACKEND (self
);
1668 watch
->watches_remaining
= MAX_WATCHES
;
1670 watch
->message_lock
= g_slice_new (CRITICAL_SECTION
);
1671 InitializeCriticalSection (watch
->message_lock
);
1672 watch
->message_sent_event
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
1673 watch
->message_received_event
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
1674 if (watch
->message_sent_event
== NULL
|| watch
->message_received_event
== NULL
)
1676 g_message_win32_error (0, "gregistrybackend: Failed to create sync objects.");
1680 /* Use a small stack to make the thread more lightweight. */
1681 watch
->thread
= CreateThread (NULL
, 1024, watch_thread_function
, watch
, 0, NULL
);
1682 if (watch
->thread
== NULL
)
1684 g_message_win32_error (0, "gregistrybackend: Failed to create notify watch thread.");
1688 self
->watch
= watch
;
1693 DeleteCriticalSection (self
->cache_lock
);
1694 g_slice_free (CRITICAL_SECTION
, self
->cache_lock
);
1695 DeleteCriticalSection (watch
->message_lock
);
1696 g_slice_free (CRITICAL_SECTION
, watch
->message_lock
);
1697 CloseHandle (watch
->message_sent_event
);
1698 CloseHandle (watch
->message_received_event
);
1700 g_slice_free (WatchThreadState
, watch
);
1704 /* This function assumes you hold the message lock! */
1706 watch_stop_unlocked (GRegistryBackend
*self
)
1708 WatchThreadState
*watch
= self
->watch
;
1710 g_return_if_fail (watch
!= NULL
);
1712 watch
->message
.type
= WATCH_THREAD_STOP
;
1713 SetEvent (watch
->message_sent_event
);
1715 /* This is signalled as soon as the message is received. We must not return
1716 * while the watch thread is still firing off callbacks. Freeing all of the
1717 * memory is done in the watch thread after this is signalled.
1719 result
= WaitForSingleObject (watch
->message_received_event
, INFINITE
);
1720 if (result
!= WAIT_OBJECT_0
)
1722 g_warning ("gregistrybackend: unable to stop watch thread.");
1726 LeaveCriticalSection (watch
->message_lock
);
1727 DeleteCriticalSection (watch
->message_lock
);
1728 DeleteCriticalSection (self
->cache_lock
);
1729 g_slice_free (CRITICAL_SECTION
, watch
->message_lock
);
1730 g_slice_free (CRITICAL_SECTION
, self
->cache_lock
);
1731 CloseHandle (watch
->message_sent_event
);
1732 CloseHandle (watch
->message_received_event
);
1733 CloseHandle (watch
->thread
);
1734 g_slice_free (WatchThreadState
, watch
);
1736 trace ("\nwatch thread: %x: all data freed.\n", self
);
1741 watch_add_notify (GRegistryBackend
*self
,
1744 gchar
*gsettings_prefix
)
1746 WatchThreadState
*watch
= self
->watch
;
1748 RegistryCacheItem
*cache_item
;
1751 g_return_val_if_fail (watch
!= NULL
, FALSE
);
1752 trace ("watch_add_notify: prefix %s.\n", gsettings_prefix
);
1754 /* Duplicate tree into the cache in the main thread, before we add the notify: if we do it in the
1755 * thread we can miss changes while we are caching.
1757 EnterCriticalSection (self
->cache_lock
);
1758 cache_node
= registry_cache_get_node_for_key (self
->cache_root
, gsettings_prefix
, TRUE
);
1760 g_return_val_if_fail (cache_node
!= NULL
, FALSE
);
1761 g_return_val_if_fail (cache_node
->data
!= NULL
, FALSE
);
1763 cache_item
= cache_node
->data
;
1765 cache_item
->subscription_count
++;
1766 if (cache_item
->subscription_count
> 1)
1768 trace ("watch_add_notify: prefix %s already watched, %i subscribers.\n",
1769 gsettings_prefix
, cache_item
->subscription_count
);
1773 registry_cache_ref_tree (cache_node
);
1774 registry_cache_update (self
, hpath
, gsettings_prefix
, NULL
, cache_node
, 0, NULL
);
1775 //registry_cache_dump (self->cache_root, NULL);
1776 LeaveCriticalSection (self
->cache_lock
);
1778 EnterCriticalSection (watch
->message_lock
);
1779 watch
->message
.type
= WATCH_THREAD_ADD_WATCH
;
1780 watch
->message
.watch
.event
= event
;
1781 watch
->message
.watch
.hpath
= hpath
;
1782 watch
->message
.watch
.prefix
= gsettings_prefix
;
1783 watch
->message
.watch
.cache_node
= cache_node
;
1785 SetEvent (watch
->message_sent_event
);
1787 /* Wait for the received event in return, to avoid sending another message before the first
1788 * one was received. If it takes > 200ms there is a possible race but the worst outcome is
1789 * a notification is ignored.
1791 result
= WaitForSingleObject (watch
->message_received_event
, 200);
1793 if (result
!= WAIT_OBJECT_0
)
1794 trace ("watch thread is slow to respond - notification may not be added.");
1796 LeaveCriticalSection (watch
->message_lock
);
1803 watch_remove_notify (GRegistryBackend
*self
,
1804 const gchar
*key_name
)
1806 WatchThreadState
*watch
= self
->watch
;
1809 if (self
->watch
== NULL
)
1810 /* Here we assume that the unsubscribe message is for somewhere that was
1811 * deleted, and so it has already been removed and the watch thread has
1816 EnterCriticalSection (watch
->message_lock
);
1817 watch
->message
.type
= WATCH_THREAD_REMOVE_WATCH
;
1818 watch
->message
.watch
.prefix
= g_strdup (key_name
);
1820 SetEvent (watch
->message_sent_event
);
1822 /* Wait for the received event in return, to avoid sending another message before the first
1825 result
= WaitForSingleObject (watch
->message_received_event
, INFINITE
);
1827 if (result
!= ERROR_SUCCESS
)
1828 g_warning ("unsubscribe from %s: message not acknowledged\n", key_name
);
1830 if (g_atomic_int_get (&watch
->watches_remaining
) >= MAX_WATCHES
)
1831 /* Stop it before any new ones can get added and confuse things */
1832 watch_stop_unlocked (self
);
1834 LeaveCriticalSection (watch
->message_lock
);
1837 /* dconf semantics are: if the key ends in /, watch the keys underneath it - if not, watch that
1838 * key. Our job is easier because keys and values are separate.
1841 g_registry_backend_subscribe (GSettingsBackend
*backend
,
1842 const char *key_name
)
1844 GRegistryBackend
*self
= G_REGISTRY_BACKEND (backend
);
1845 gchar
*path_name
, *value_name
= NULL
;
1850 if (self
->watch
== NULL
)
1851 if (!watch_start (self
))
1854 if (g_atomic_int_dec_and_test (&self
->watch
->watches_remaining
))
1856 g_atomic_int_inc (&self
->watch
->watches_remaining
);
1857 g_warning ("subscribe() failed: only %i different paths may be watched.\n", MAX_WATCHES
);
1861 path_name
= parse_key (key_name
, self
->base_path
, &value_name
);
1863 /* Must check for this, otherwise strange crashes occur because the cache
1864 * node that is being watched gets freed. All path names to subscribe must
1867 if (value_name
!= NULL
&& *value_name
!= 0)
1868 g_warning ("subscribe() failed: path must end in a /, got %s\n", key_name
);
1870 trace ("Subscribing to %s [registry %s / %s] - watch %x\n", key_name
, path_name
, value_name
, self
->watch
);
1873 /* Give the caller the benefit of the doubt if the key doesn't exist and create it. The caller
1874 * is almost certainly a new g_settings with this path as base path. */
1875 result
= RegCreateKeyExA (HKEY_CURRENT_USER
, path_name
, 0, NULL
, 0, KEY_READ
, NULL
, &hpath
,
1879 if (result
!= ERROR_SUCCESS
)
1881 g_message_win32_error (result
, "gregistrybackend: Unable to subscribe to key %s.", key_name
);
1882 g_atomic_int_inc (&self
->watch
->watches_remaining
);
1886 event
= CreateEvent (NULL
, FALSE
, FALSE
, NULL
);
1889 g_message_win32_error (result
, "gregistrybackend: CreateEvent failed.\n");
1890 g_atomic_int_inc (&self
->watch
->watches_remaining
);
1891 RegCloseKey (hpath
);
1895 /* The actual watch is added by the thread, which has to re-subscribe each time it
1896 * receives a change. */
1897 if (!watch_add_notify (self
, event
, hpath
, g_strdup (key_name
)))
1898 g_atomic_int_inc (&self
->watch
->watches_remaining
);
1902 g_registry_backend_unsubscribe (GSettingsBackend
*backend
,
1903 const char *key_name
)
1905 trace ("unsubscribe: %s.\n", key_name
);
1907 watch_remove_notify (G_REGISTRY_BACKEND (backend
), key_name
);
1911 /********************************************************************************
1912 * Object management junk
1913 ********************************************************************************/
1916 g_registry_backend_new (void) {
1917 return g_object_new (G_TYPE_REGISTRY_BACKEND
, NULL
);
1921 g_registry_backend_finalize (GObject
*object
)
1923 GRegistryBackend
*self
= G_REGISTRY_BACKEND (object
);
1924 RegistryCacheItem
*item
;
1926 item
= self
->cache_root
->data
;
1927 g_warn_if_fail (item
->ref_count
== 1);
1929 _free_cache_item (item
);
1930 g_node_destroy (self
->cache_root
);
1932 if (self
->watch
!= NULL
)
1934 EnterCriticalSection (self
->watch
->message_lock
);
1935 watch_stop_unlocked (self
);
1938 g_free (self
->base_path
);
1942 g_registry_backend_class_init (GRegistryBackendClass
*class)
1944 GSettingsBackendClass
*backend_class
= G_SETTINGS_BACKEND_CLASS (class);
1945 GObjectClass
*object_class
= G_OBJECT_CLASS (class);
1947 object_class
->finalize
= g_registry_backend_finalize
;
1949 backend_class
->read
= g_registry_backend_read
;
1950 backend_class
->write
= g_registry_backend_write
;
1951 backend_class
->write_tree
= g_registry_backend_write_tree
;
1952 backend_class
->reset
= g_registry_backend_reset
;
1953 backend_class
->get_writable
= g_registry_backend_get_writable
;
1954 backend_class
->get_permission
= g_registry_backend_get_permission
;
1955 backend_class
->subscribe
= g_registry_backend_subscribe
;
1956 backend_class
->unsubscribe
= g_registry_backend_unsubscribe
;
1960 g_registry_backend_init (GRegistryBackend
*self
)
1962 RegistryCacheItem
*item
;
1963 self
->base_path
= g_strdup_printf ("Software\\GSettings");
1965 item
= g_slice_new (RegistryCacheItem
);
1966 item
->value
.type
= REG_NONE
;
1967 item
->value
.ptr
= NULL
;
1968 item
->name
= g_strdup ("<root>");
1969 item
->ref_count
= 1;
1970 self
->cache_root
= g_node_new (item
);