(root)/
glib-2.79.0/
gio/
gregistrysettingsbackend.c
       1  /*
       2   * Copyright © 2009-10 Sam Thursfield
       3   *
       4   * SPDX-License-Identifier: LGPL-2.1-or-later
       5   *
       6   * This library is free software; you can redistribute it and/or
       7   * modify it under the terms of the GNU Lesser General Public
       8   * License as published by the Free Software Foundation; either
       9   * version 2.1 of the License, or (at your option) any later version.
      10   *
      11   * This library is distributed in the hope that it will be useful,
      12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      14   * Lesser General Public License for more details.
      15   *
      16   * You should have received a copy of the GNU Lesser General Public
      17   * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      18   *
      19   * Author: Sam Thursfield <ssssam@gmail.com>
      20   */
      21  
      22  /* GRegistrySettingsBackend implementation notes:
      23   *
      24   *   - All settings are stored under the registry path given at construction
      25   *     time. Permissions and system-wide defaults are not implemented and will
      26   *     probably always be out of scope of the Windows port of GLib.
      27   *
      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.
      33   *
      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.
      38   *
      39   *   - Windows doesn't tell us which value has changed. This means we have to
      40   *     maintain a cache of every stored value so we can play spot the
      41   *     difference. This should not be a performance issue because if you are
      42   *     storing thousands of values in GSettings, you are probably using it
      43   *     wrong.
      44   *
      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.
      50   *
      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.
      57   *
      58   *   - The registry is totally user-editable, so we are very forgiving about
      59   *     errors in the data we get.
      60   *
      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.
      64   *
      65   *   - RegCreateKeyW is used - We should always make the UTF-8 -> UTF-16
      66   *     conversion ourselves to avoid problems when the system language changes.
      67   *
      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.
      71   *
      72   *   - Terminology:
      73   *     * in GSettings, a 'key' is eg. /desktop/gnome/background/primary-color
      74   *     * in the registry, the 'key' is path, which contains some 'values'.
      75   *     * in this file, any GSettings key is a 'key', while a registry key is
      76   *       termed a 'path', which contains 'values'.
      77   *
      78   *   - My set of tests for this backend are currently at:
      79   *       http://gitorious.org/gsettings-gtk/gsettings-test.git
      80   *
      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
      85   *
      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
      88   */
      89  
      90  #include "config.h"
      91  
      92  #include "gregistrysettingsbackend.h"
      93  #include "gsettingsbackend.h"
      94  #include "gsettingsbackendinternal.h"
      95  #include "giomodule-priv.h"
      96  
      97  #include <glibintl.h>
      98  
      99  #include <windows.h>
     100  
     101  //#define TRACE
     102  
     103  /* GSettings' limit */
     104  #define MAX_KEY_NAME_LENGTH   128
     105  
     106  /* Testing (on Windows XP SP3) shows that WaitForMultipleObjects fails with
     107   * "The parameter is incorrect" after 64 watches. We need one for the
     108   * message_sent cond, which is allowed for in the way the watches_remaining
     109   * variable is used.
     110   */
     111  #define MAX_WATCHES   64
     112  
     113  /* A watch on one registry path and its subkeys */
     114  typedef struct
     115  {
     116    HANDLE event;
     117    HKEY hpath;
     118    char *prefix;
     119    GNode *cache_node;
     120  } RegistryWatch;
     121  
     122  /* Simple message passing for the watch thread. Not enough traffic to
     123   * justify a queue.
     124   */
     125  typedef enum
     126  {
     127    WATCH_THREAD_NONE,
     128    WATCH_THREAD_ADD_WATCH,
     129    WATCH_THREAD_REMOVE_WATCH,
     130    WATCH_THREAD_STOP
     131  } WatchThreadMessageType;
     132  
     133  typedef struct
     134  {
     135    WatchThreadMessageType type;
     136    RegistryWatch watch;
     137  } WatchThreadMessage;
     138  
     139  typedef struct
     140  {
     141    GSettingsBackend *owner;
     142    HANDLE *thread;
     143  
     144    /* Details of the things we are watching. */
     145    int watches_remaining;
     146    GPtrArray *events, *handles, *prefixes, *cache_nodes;
     147  
     148    /* Communication with the main thread. Only one message is stored at a time,
     149     * to make sure that messages are acknowledged before being overwritten we
     150     * create two events - one is signalled when a new message is set, the
     151     * other is signalled by the thread when it has processed the message.
     152     */
     153    WatchThreadMessage message;
     154    CRITICAL_SECTION *message_lock;
     155    HANDLE message_sent_event, message_received_event;
     156  } WatchThreadState;
     157  
     158  #define G_TYPE_REGISTRY_SETTINGS_BACKEND      (g_registry_settings_backend_get_type ())
     159  #define G_REGISTRY_SETTINGS_BACKEND(inst)     (G_TYPE_CHECK_INSTANCE_CAST ((inst),         \
     160                                                 G_TYPE_REGISTRY_SETTINGS_BACKEND, GRegistrySettingsBackend))
     161  #define G_IS_REGISTRY_SETTINGS_BACKEND(inst)  (G_TYPE_CHECK_INSTANCE_TYPE ((inst),         \
     162                                                 G_TYPE_REGISTRY_SETTINGS_BACKEND))
     163  
     164  typedef enum {
     165    PROP_REGISTRY_KEY = 1,
     166  } GRegistrySettingsBackendProperty;
     167  
     168  typedef GSettingsBackendClass GRegistrySettingsBackendClass;
     169  
     170  typedef struct {
     171    GSettingsBackend parent_instance;
     172  
     173    HKEY base_key;
     174    gchar *base_path;
     175    gunichar2 *base_pathw;
     176  
     177    /* A stored copy of the whole tree being watched. When we receive a change notification
     178     * we have to check against this to see what has changed ... every time ...*/
     179    CRITICAL_SECTION *cache_lock;
     180    GNode *cache_root;
     181  
     182    WatchThreadState *watch;
     183  } GRegistrySettingsBackend;
     184  
     185  G_DEFINE_TYPE_WITH_CODE (GRegistrySettingsBackend,
     186                           g_registry_settings_backend,
     187                           G_TYPE_SETTINGS_BACKEND,
     188                           _g_io_modules_ensure_extension_points_registered ();
     189                           g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
     190                                                           g_define_type_id, "registry", 90))
     191  
     192  /**********************************************************************************
     193   * Utility functions
     194   **********************************************************************************/
     195  
     196  #include <stdio.h>
     197  static void
     198  trace (const char *format,
     199         ...)
     200  {
     201  #ifdef TRACE
     202    va_list va; va_start (va, format);
     203    vprintf (format, va);
     204    fflush (stdout);
     205    va_end (va);
     206  #endif
     207  }
     208  
     209  /* g_message including a windows error message. It is not useful to have an
     210   * equivalent function for g_warning because none of the registry errors can
     211   * result from programmer error (Microsoft programmers don't count), instead
     212   * they will mostly occur from people messing with the registry by hand. */
     213  static void G_GNUC_PRINTF (2, 3)
     214  g_message_win32_error (DWORD        result_code,
     215                         const gchar *format,
     216                        ...)
     217  {
     218    va_list va;
     219    gchar *message;
     220    gchar *win32_error;
     221    gchar *win32_message;
     222  
     223    g_return_if_fail (result_code != 0);
     224  
     225    va_start (va, format);
     226    message = g_strdup_vprintf (format, va);
     227    win32_error = g_win32_error_message (result_code);
     228    win32_message = g_strdup_printf ("%s: %s", message, win32_error);
     229    g_free (message);
     230    g_free (win32_error);
     231  
     232    if (result_code == ERROR_KEY_DELETED)
     233      trace ("(%s)", win32_message);
     234    else
     235      g_message ("%s", win32_message);
     236  
     237    g_free (win32_message);
     238  }
     239  
     240  /* Make gsettings key into a registry path & value pair.
     241   *
     242   * Note that the return value *only* needs freeing - registry_value_name
     243   * is a pointer to further inside the same block of memory.
     244   */
     245  static gchar *
     246  parse_key (const gchar  *key_name,
     247             const gchar  *registry_prefix,
     248             gchar       **value_name)
     249  {
     250    gchar *path_name, *c;
     251  
     252    /* All key paths are treated as absolute; gsettings doesn't seem to enforce a
     253     * preceding /.
     254     */
     255    if (key_name[0] == '/')
     256      key_name++;
     257  
     258    if (registry_prefix == NULL)
     259      path_name = g_strdup (key_name);
     260    else
     261      path_name = g_strjoin ("/", registry_prefix, key_name, NULL);
     262  
     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++)
     265      {
     266        if (*c == '/')
     267          {
     268            *c = '\\';
     269            *value_name = c;
     270          }
     271      }
     272  
     273    **value_name = 0;
     274    (*value_name)++;
     275  
     276    return path_name;
     277  }
     278  
     279  static DWORD
     280  g_variant_get_as_dword (GVariant *variant)
     281  {
     282    switch (g_variant_get_type_string (variant)[0])
     283      {
     284      case 'b':
     285        return g_variant_get_boolean (variant);
     286      case 'y':
     287        return g_variant_get_byte (variant);
     288      case 'n':
     289        return g_variant_get_int16 (variant);
     290      case 'q':
     291        return g_variant_get_uint16 (variant);
     292      case 'i':
     293        return g_variant_get_int32 (variant);
     294      case 'u':
     295        return g_variant_get_uint32 (variant);
     296      default:
     297        g_warn_if_reached ();
     298      }
     299    return 0;
     300  }
     301  
     302  static DWORDLONG
     303  g_variant_get_as_qword (GVariant *variant)
     304  {
     305    switch (g_variant_get_type_string (variant)[0])
     306      {
     307      case 'x':
     308        return g_variant_get_int64 (variant);
     309      case 't':
     310        return g_variant_get_uint64 (variant);
     311      default:
     312        g_warn_if_reached ();
     313      }
     314    return 0;
     315  }
     316  
     317  static void
     318  handle_read_error (LONG         result,
     319                     const gchar *path_name,
     320                     const gchar *value_name)
     321  {
     322    /* file not found means key value not set, this isn't an error for us. */
     323    if (result != ERROR_FILE_NOT_FOUND)
     324      g_message_win32_error (result, "Unable to query value %s/%s",
     325                             path_name, value_name);
     326  }
     327  
     328  typedef struct {
     329    HKEY handle;
     330    const char *name;
     331  } HandleNamePair;
     332  
     333  static const HandleNamePair predefined_key_names[] = {
     334    { HKEY_CLASSES_ROOT, "HKEY_CLASSES_ROOT" },
     335    { HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG" },
     336    { HKEY_CURRENT_USER, "HKEY_CURRENT_USER" },
     337    { HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE" },
     338    { HKEY_USERS, "HKEY_USERS" }
     339  };
     340  
     341  static const gchar*
     342  predefined_key_to_string (HKEY key)
     343  {
     344    for (gsize i = 0; i < G_N_ELEMENTS (predefined_key_names); i++)
     345      {
     346        if (predefined_key_names[i].handle == key)
     347          return predefined_key_names[i].name;
     348      }
     349  
     350    g_warning ("gregistrysettingsbackend: unexpected root key (%p)", key);
     351    return "";
     352  }
     353  
     354  static const gchar*
     355  split_registry_path (const gchar *full_path,
     356                       HKEY        *root_key)
     357  {
     358    g_assert (full_path != NULL);
     359  
     360    for (gsize i = 0; i < G_N_ELEMENTS (predefined_key_names); i++)
     361      {
     362        const gchar *root_name = predefined_key_names[i].name;
     363  
     364        if (g_str_has_prefix (full_path, root_name))
     365          {
     366            const gchar *rest = full_path + strlen (root_name);
     367  
     368            if (*rest == '\\')
     369              {
     370                if (root_key != NULL)
     371                  *root_key = predefined_key_names[i].handle;
     372  
     373                return ++rest;
     374              }
     375          }
     376      }
     377  
     378    return NULL;
     379  }
     380  
     381  /***************************************************************************
     382   * Cache of registry values
     383   ***************************************************************************/
     384  
     385  /* Generic container for registry values */
     386  typedef struct {
     387    DWORD type;
     388  
     389    union {
     390      gint  dword;  /* FIXME: could inline QWORD on 64-bit systems too */
     391      void *ptr;
     392    };
     393  } RegistryValue;
     394  
     395  static char *
     396  registry_value_dump (RegistryValue value)
     397  {
     398    if (value.type == REG_DWORD)
     399      return g_strdup_printf ("%d", value.dword);
     400    else if (value.type == REG_QWORD)
     401      return g_strdup_printf ("%"G_GINT64_FORMAT, value.ptr == NULL ? 0: *(DWORDLONG *)value.ptr);
     402    else if (value.type == REG_SZ)
     403      return g_strdup_printf ("%s", (char *)value.ptr);
     404    else if (value.type == REG_NONE)
     405      return g_strdup_printf ("<empty>");
     406    else
     407      return g_strdup_printf ("<invalid>");
     408  }
     409  
     410  static void
     411  registry_value_free (RegistryValue value)
     412  {
     413    if (value.type == REG_SZ || value.type == REG_QWORD)
     414      g_free (value.ptr);
     415  
     416    value.type = REG_NONE;
     417    value.ptr = NULL;
     418  }
     419  
     420  /* The registry cache is stored as a tree, for easy traversal. Right now we
     421   * don't sort it in a clever way. Each node corresponds to a path element
     422   * ('key' in registry terms) or a value.
     423   *
     424   * Each subscription uses the same cache. Because GSettings can subscribe to
     425   * the tree at any node any number of times, we need to reference count the
     426   * nodes.
     427   */
     428  typedef struct
     429  {
     430    /* Component of path that this node represents */
     431    gchar *name;
     432  
     433    /* If a watch is subscribed at this point (subscription_count > 0) we can
     434     * block its next notification. This is useful because if two watches cover
     435     * the same path, both will trigger when it changes. It also allows changes
     436     * done by the application to be ignored by the watch thread.
     437     */
     438    gint32 block_count : 8;
     439  
     440    /* Number of times g_settings_subscribe has been called for this location
     441     * (I guess you can't subscribe more than 16383 times) */
     442    gint32 subscription_count : 14;
     443  
     444    gint32 ref_count : 9;
     445  
     446    guint32 readable : 1;
     447    RegistryValue value;
     448  } RegistryCacheItem;
     449  
     450  static GNode *
     451  registry_cache_add_item (GNode         *parent,
     452                           gchar         *name,
     453                           RegistryValue  value,
     454                           gint           ref_count)
     455  {
     456    RegistryCacheItem *item;
     457    GNode *cache_node;
     458  
     459    g_return_val_if_fail (name != NULL, NULL);
     460    g_return_val_if_fail (parent != NULL, NULL);
     461  
     462    item = g_slice_new (RegistryCacheItem);
     463  
     464    /* Ref count should be the number of watch points above this node */
     465    item->ref_count = ref_count;
     466  
     467    item->name = g_strdup (name);
     468    item->value = value;
     469    item->subscription_count = 0;
     470    item->block_count = 0;
     471    item->readable = FALSE;
     472  
     473    trace ("\tregistry cache: adding %s to %s\n",
     474           name, ((RegistryCacheItem *)parent->data)->name);
     475  
     476    cache_node = g_node_new (item);
     477    g_node_append (parent, cache_node);
     478  
     479    return cache_node;
     480  }
     481  
     482  /* The reference counting of cache tree nodes works like this: when a node is
     483   * subscribed to (GSettings wants us to watch that path and everything below
     484   * it) the reference count of that node and everything below is increased, as
     485   * well as each parent up to the root.
     486   */
     487  
     488  static void
     489  _ref_down (GNode *node)
     490  {
     491    RegistryCacheItem *item = node->data;
     492  
     493    g_node_children_foreach (node, G_TRAVERSE_ALL,
     494                             (GNodeForeachFunc)_ref_down, NULL);
     495    item->ref_count++;
     496  }
     497  
     498  static void
     499  registry_cache_ref_tree (GNode *tree)
     500  {
     501    RegistryCacheItem *item = tree->data;
     502    GNode *node = tree->parent;
     503  
     504    g_return_if_fail (tree != NULL);
     505  
     506    item->ref_count++;
     507  
     508    g_node_children_foreach (tree, G_TRAVERSE_ALL,
     509                             (GNodeForeachFunc)_ref_down, NULL);
     510  
     511    for (node = tree->parent; node; node = node->parent)
     512      {
     513        item = node->data;
     514        item->ref_count++;
     515      }
     516  }
     517  
     518  static void
     519  registry_cache_item_free (RegistryCacheItem *item)
     520  {
     521    trace ("\t -- Free node %s\n", item->name);
     522  
     523    g_free (item->name);
     524    registry_value_free (item->value);
     525    g_slice_free (RegistryCacheItem, item);
     526  }
     527  
     528  /* Unreferencing has to be done bottom-up */
     529  static void
     530  _unref_node (GNode *node)
     531  {
     532    RegistryCacheItem *item = node->data;
     533  
     534    item->ref_count--;
     535  
     536    g_warn_if_fail (item->ref_count >= 0);
     537  
     538    if (item->ref_count == 0)
     539      {
     540        registry_cache_item_free (item);
     541        g_node_destroy (node);
     542      }
     543  }
     544  
     545  static void
     546  _unref_down (GNode *node)
     547  {
     548    g_node_children_foreach (node, G_TRAVERSE_ALL,
     549                             (GNodeForeachFunc)_unref_down, NULL);
     550    _unref_node (node);
     551  }
     552  
     553  static void
     554  registry_cache_unref_tree (GNode *tree)
     555  {
     556    GNode *parent = tree->parent, *next_parent;
     557  
     558    _unref_down (tree);
     559  
     560    while (parent)
     561      {
     562        next_parent = parent->parent;
     563        _unref_node (parent);
     564        parent = next_parent;
     565      }
     566  }
     567  
     568  #if 0
     569  static void
     570  registry_cache_dump (GNode    *cache_node,
     571                       gpointer  data)
     572  {
     573    RegistryCacheItem *item = cache_node->data;
     574  
     575    int depth     = GPOINTER_TO_INT(data),
     576        new_depth = depth+1,
     577        i;
     578  
     579    g_return_if_fail (cache_node != NULL);
     580  
     581    for (i=0; i<depth; i++)
     582      g_print ("  ");
     583    if (item == NULL)
     584      g_print ("*root*\n");
     585    else
     586      g_print ("'%s'  [%i] @ %x = %s\n", item->name, item->ref_count, (guint)cache_node,
     587               registry_value_dump (item->value));
     588    g_node_children_foreach (cache_node, G_TRAVERSE_ALL, registry_cache_dump,
     589                             GINT_TO_POINTER (new_depth));
     590  }
     591  #endif
     592  
     593  typedef struct
     594  {
     595    gchar *name;
     596    GNode *result;
     597  } RegistryCacheSearch;
     598  
     599  static gboolean
     600  registry_cache_find_compare (GNode    *node,
     601                               gpointer  data)
     602  {
     603    RegistryCacheSearch *search = data;
     604    RegistryCacheItem *item = node->data;
     605  
     606    if (item == NULL)  /* root node */
     607      return FALSE;
     608  
     609    g_return_val_if_fail (search->name != NULL, FALSE);
     610    g_return_val_if_fail (item->name != NULL, FALSE);
     611  
     612    if (strcmp (search->name, item->name) == 0)
     613      {
     614        search->result = node;
     615        return TRUE;
     616      }
     617  
     618    return FALSE;
     619  }
     620  
     621  static GNode *
     622  registry_cache_find_immediate_child (GNode *node,
     623                                       gchar *name)
     624  {
     625    RegistryCacheSearch search;
     626  
     627    search.result = NULL;
     628    search.name = name;
     629  
     630    g_node_traverse (node, G_POST_ORDER, G_TRAVERSE_ALL, 2,
     631                     registry_cache_find_compare, &search);
     632  
     633    return search.result;
     634  }
     635  
     636  static GNode *
     637  registry_cache_get_node_for_key_recursive (GNode    *node,
     638                                             gchar    *key_name,
     639                                             gboolean  create_if_not_found,
     640                                             gint      n_parent_watches)
     641  {
     642    RegistryCacheItem *item;
     643    gchar *component = key_name;
     644    gchar *c = strchr (component, '/');
     645    GNode *child;
     646  
     647    if (c != NULL)
     648      *c = 0;
     649  
     650    /* We count up how many watch points we travel through finding this node,
     651     * because a new node should have as many references as there are watches at
     652     * points above it in the tree.
     653     */
     654    item = node->data;
     655    if (item->subscription_count > 0)
     656      n_parent_watches++;
     657  
     658    child = registry_cache_find_immediate_child (node, component);
     659    if (child == NULL && create_if_not_found)
     660      {
     661        RegistryValue null_value = { REG_NONE, {0} };
     662  
     663        child = registry_cache_add_item (node, component,
     664                                         null_value, n_parent_watches);
     665  
     666        trace ("\tget node for key recursive: new %x = %s.\n", node, component);
     667      }
     668  
     669    /* We are done if there are no more path components. Allow for a trailing /. */
     670    if (child == NULL || c == NULL || *(c + 1) == 0)
     671      return child;
     672  
     673    trace ("get node for key recursive: next: %s.\n", c + 1);
     674  
     675    return registry_cache_get_node_for_key_recursive (child, c + 1,
     676                                                      create_if_not_found,
     677                                                      n_parent_watches);
     678  }
     679  
     680  /* Look up a GSettings key in the cache. */
     681  static GNode *
     682  registry_cache_get_node_for_key (GNode       *root,
     683                                   const gchar *key_name,
     684                                   gboolean     create_if_not_found)
     685  {
     686    GNode *child = NULL;
     687    GNode *result = NULL;
     688    gchar *component, *c;
     689  
     690    g_return_val_if_fail (key_name != NULL, NULL);
     691  
     692    if (key_name[0] == '/')
     693      key_name++;
     694  
     695    /* Ignore preceding / */
     696    component = g_strdup (key_name);
     697    c = strchr (component, '/');
     698  
     699    if (c == NULL)
     700      {
     701        g_free (component);
     702        return root;
     703      }
     704  
     705    if (c != NULL)
     706      *c = 0;
     707  
     708    child = registry_cache_find_immediate_child (root, component);
     709    if (child == NULL && create_if_not_found)
     710      {
     711        RegistryValue null_value = { REG_NONE, {0} };
     712  
     713        /* Reference count is set to 0, tree should be referenced by the caller */
     714        child = registry_cache_add_item (root, component,
     715                                         null_value, 0);
     716  
     717        trace ("get_node_for_key: New node for component '%s'\n", component);
     718      }
     719  
     720    if (*(c + 1) == 0)
     721      result = child;
     722    else if (child != NULL)
     723      result = registry_cache_get_node_for_key_recursive (child, c + 1,
     724                                                          create_if_not_found, 0);
     725  
     726    g_free (component);
     727  
     728    return result;
     729  }
     730  
     731  /* Check the cache node against the registry key it represents. Return TRUE if
     732   * they differ, and update the cache with the new value.
     733   */
     734  static gboolean
     735  registry_cache_update_node (GNode        *cache_node,
     736                              RegistryValue registry_value)
     737  {
     738    RegistryCacheItem *cache_item;
     739  
     740    g_return_val_if_fail (cache_node != NULL, FALSE);
     741    g_return_val_if_fail (cache_node->data != NULL, FALSE);
     742  
     743    cache_item = cache_node->data;
     744  
     745    if (registry_value.type != cache_item->value.type)
     746      {
     747        /* The type has changed. Update cache item and register it as changed.
     748         * Either the schema has changed and this is entirely legitimate, or
     749         * whenever the app reads the key it will get the default value due to
     750         * the type mismatch.
     751         */
     752        cache_item->value = registry_value;
     753        return TRUE;
     754      }
     755  
     756    switch (registry_value.type)
     757      {
     758      case REG_DWORD:
     759        {
     760          if (cache_item->value.dword == registry_value.dword)
     761            return FALSE;
     762          else
     763            {
     764              cache_item->value.dword = registry_value.dword;
     765              return TRUE;
     766            }
     767        }
     768      case REG_QWORD:
     769        {
     770          g_return_val_if_fail (registry_value.ptr != NULL &&
     771                                cache_item->value.ptr != NULL, FALSE);
     772  
     773          if (memcmp (registry_value.ptr, cache_item->value.ptr, 8)==0)
     774            {
     775              g_free (registry_value.ptr);
     776              return FALSE;
     777            }
     778          else
     779            {
     780              g_free (cache_item->value.ptr);
     781              cache_item->value.ptr = registry_value.ptr;
     782              return TRUE;
     783            }
     784        }
     785      case REG_SZ:
     786        {
     787          /* Value should not exist if it is NULL, an empty string is "" */
     788          g_return_val_if_fail (cache_item->value.ptr != NULL, FALSE);
     789          g_return_val_if_fail (registry_value.ptr != NULL, FALSE);
     790  
     791          if (strcmp (registry_value.ptr, cache_item->value.ptr) == 0)
     792            {
     793              g_free (registry_value.ptr);
     794              return FALSE;
     795            }
     796          else
     797            {
     798              g_free (cache_item->value.ptr);
     799              cache_item->value.ptr = registry_value.ptr;
     800              return TRUE;
     801            }
     802        }
     803      default:
     804        g_warning ("gregistrysettingsbackend: registry_cache_update_node: Unhandled value type");
     805        return FALSE;
     806      }
     807  }
     808  
     809  /* Blocking notifications is a useful optimisation. When a change is made
     810   * through GSettings we update the cache manually, but a notification is
     811   * triggered as well. This function is also used for nested notifications,
     812   * eg. if /test and /test/foo are watched, and /test/foo/value is changed then
     813   * we will get notified both for /test/foo and /test and it is helpful to block
     814   * the second.
     815   */
     816  static void
     817  registry_cache_block_notification (GNode *node)
     818  {
     819    RegistryCacheItem *item = node->data;
     820  
     821    g_return_if_fail (node != NULL);
     822  
     823    if (item->subscription_count > 0)
     824      item->block_count++;
     825  
     826    if (node->parent != NULL)
     827      registry_cache_block_notification (node->parent);
     828  }
     829  
     830  static void registry_cache_destroy_tree (GNode            *node,
     831                                           WatchThreadState *self);
     832  
     833  /***************************************************************************
     834   * Reading and writing
     835   ***************************************************************************/
     836  
     837  static gboolean
     838  registry_read (HKEY           hpath,
     839                 const gchar   *path_name,
     840                 const gchar   *value_name,
     841                 RegistryValue *p_value)
     842  {
     843    LONG result;
     844    DWORD value_data_size;
     845    gpointer *buffer;
     846    gunichar2 *value_namew;
     847  
     848    g_return_val_if_fail (p_value != NULL, FALSE);
     849  
     850    p_value->type = REG_NONE;
     851    p_value->ptr = NULL;
     852  
     853    value_namew = g_utf8_to_utf16 (value_name, -1, NULL, NULL, NULL);
     854  
     855    result = RegQueryValueExW (hpath, value_namew, 0, &p_value->type, NULL, &value_data_size);
     856    if (result != ERROR_SUCCESS)
     857      {
     858        handle_read_error (result, path_name, value_name);
     859        g_free (value_namew);
     860        return FALSE;
     861      }
     862  
     863    if (p_value->type == REG_SZ && value_data_size == 0)
     864      {
     865        p_value->ptr = g_strdup ("");
     866        g_free (value_namew);
     867        return TRUE;
     868      }
     869  
     870    if (p_value->type == REG_DWORD)
     871      /* REG_DWORD is inlined */
     872      buffer = (void *)&p_value->dword;
     873    else
     874      buffer = p_value->ptr = g_malloc (value_data_size);
     875  
     876    result = RegQueryValueExW (hpath, value_namew, 0, NULL, (LPBYTE)buffer, &value_data_size);
     877    g_free (value_namew);
     878  
     879    if (result != ERROR_SUCCESS)
     880      {
     881        handle_read_error (result, path_name, value_name);
     882  
     883        if (p_value->type != REG_DWORD)
     884          g_free (buffer);
     885  
     886        return FALSE;
     887      }
     888  
     889    if (p_value->type == REG_SZ)
     890      {
     891        gchar *valueu8 = g_utf16_to_utf8 (p_value->ptr, -1, NULL, NULL, NULL);
     892        g_free (p_value->ptr);
     893        p_value->ptr = valueu8;
     894      }
     895  
     896    return TRUE;
     897  }
     898  
     899  static GVariant *
     900  g_registry_settings_backend_read (GSettingsBackend   *backend,
     901                                    const gchar        *key_name,
     902                                    const GVariantType *expected_type,
     903                                    gboolean            default_value)
     904  {
     905    GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
     906    GNode *cache_node;
     907    RegistryValue registry_value;
     908    GVariant *gsettings_value = NULL;
     909    gchar *gsettings_type;
     910  
     911    g_return_val_if_fail (expected_type != NULL, NULL);
     912  
     913    if (default_value)
     914      return NULL;
     915  
     916    /* Simply read from the cache, which is updated from the registry by the
     917     * watch thread as soon as changes can propagate. Any changes not yet in the
     918     * cache will have the 'changed' signal emitted after this function returns.
     919     */
     920    EnterCriticalSection (self->cache_lock);
     921    cache_node = registry_cache_get_node_for_key (self->cache_root, key_name, FALSE);
     922    LeaveCriticalSection (self->cache_lock);
     923  
     924    trace ("Reading key %s, cache node %x\n", key_name, cache_node);
     925  
     926    /* Maybe it's not set, we can return to default */
     927    if (cache_node == NULL)
     928      return NULL;
     929  
     930    trace ("\t- cached value %s\n", registry_value_dump (((RegistryCacheItem *)cache_node->data)->value));
     931  
     932    registry_value = ((RegistryCacheItem *)cache_node->data)->value;
     933  
     934    gsettings_type = g_variant_type_dup_string (expected_type);
     935  
     936    /* The registry is user-editable, so we need to be fault-tolerant here. */
     937    switch (gsettings_type[0])
     938      {
     939      case 'b':
     940      case 'y':
     941      case 'n':
     942      case 'q':
     943      case 'i':
     944      case 'u':
     945        if (registry_value.type == REG_DWORD)
     946          gsettings_value = g_variant_new (gsettings_type, registry_value.dword);
     947        break;
     948  
     949      case 't':
     950      case 'x':
     951        if (registry_value.type == REG_QWORD)
     952          {
     953            DWORDLONG qword_value = *(DWORDLONG *)registry_value.ptr;
     954            gsettings_value = g_variant_new (gsettings_type, qword_value);
     955          }
     956        break;
     957  
     958      default:
     959        if (registry_value.type == REG_SZ)
     960          {
     961            if (gsettings_type[0] == 's')
     962              gsettings_value = g_variant_new_string ((char *)registry_value.ptr);
     963            else
     964              {
     965                GError *error = NULL;
     966  
     967                gsettings_value = g_variant_parse (expected_type, registry_value.ptr,
     968                                                   NULL, NULL, &error);
     969  
     970                if (error != NULL)
     971                  g_message ("gregistrysettingsbackend: error parsing key %s: %s",
     972                             key_name, error->message);
     973              }
     974          }
     975          break;
     976      }
     977  
     978    g_free (gsettings_type);
     979  
     980    return gsettings_value;
     981  }
     982  
     983  
     984  typedef struct
     985  {
     986    GRegistrySettingsBackend *self;
     987    HKEY hroot;
     988  } RegistryWrite;
     989  
     990  static gboolean
     991  g_registry_settings_backend_write_one (const char *key_name,
     992                                         GVariant   *variant,
     993                                         gpointer    user_data)
     994  {
     995    GRegistrySettingsBackend *self;
     996    RegistryWrite *action;
     997    RegistryValue value;
     998    HKEY hroot;
     999    HKEY hpath;
    1000    gchar *path_name;
    1001    gunichar2 *path_namew;
    1002    gchar *value_name = NULL;
    1003    gunichar2 *value_namew;
    1004    DWORD value_data_size;
    1005    LPVOID value_data;
    1006    gunichar2 *value_dataw;
    1007    LONG result;
    1008    GNode *node;
    1009    gboolean changed;
    1010    const gchar *type_string;
    1011  
    1012    type_string = g_variant_get_type_string (variant);
    1013    action = user_data;
    1014    self = G_REGISTRY_SETTINGS_BACKEND (action->self);
    1015    hroot = action->hroot;
    1016  
    1017    value.type = REG_NONE;
    1018    value.ptr = NULL;
    1019  
    1020    switch (type_string[0])
    1021      {
    1022      case 'b':
    1023      case 'y':
    1024      case 'n':
    1025      case 'q':
    1026      case 'i':
    1027      case 'u':
    1028        value.type = REG_DWORD;
    1029        value.dword = g_variant_get_as_dword (variant);
    1030        value_data_size = 4;
    1031        value_data = &value.dword;
    1032        break;
    1033  
    1034      case 'x':
    1035      case 't':
    1036        value.type = REG_QWORD;
    1037        value.ptr = g_malloc (8);
    1038        *(DWORDLONG *)value.ptr = g_variant_get_as_qword (variant);
    1039        value_data_size = 8;
    1040        value_data = value.ptr;
    1041        break;
    1042  
    1043      default:
    1044        value.type = REG_SZ;
    1045        if (type_string[0] == 's')
    1046          {
    1047            gsize length;
    1048            value.ptr = g_strdup (g_variant_get_string (variant, &length));
    1049            value_data_size = length + 1;
    1050            value_data = value.ptr;
    1051          }
    1052        else
    1053          {
    1054            GString *value_string;
    1055            value_string = g_variant_print_string (variant, NULL, FALSE);
    1056            value_data_size = value_string->len + 1;
    1057            value.ptr = value_data = g_string_free (value_string, FALSE);
    1058          }
    1059        break;
    1060      }
    1061  
    1062    /* First update the cache, because the value may not have changed and we can
    1063     * save a write.
    1064     *
    1065     * If 'value' has changed then its memory will not be freed by update_node(),
    1066     * because it will be stored in the node.
    1067     */
    1068    EnterCriticalSection (self->cache_lock);
    1069    node = registry_cache_get_node_for_key (self->cache_root, key_name, TRUE);
    1070    changed = registry_cache_update_node (node, value);
    1071    LeaveCriticalSection (self->cache_lock);
    1072  
    1073    if (!changed)
    1074      return FALSE;
    1075  
    1076    /* Block the next notification to any watch points above this location,
    1077     * because they will each get triggered on a change that is already updated
    1078     * in the cache.
    1079     */
    1080    registry_cache_block_notification (node);
    1081  
    1082    path_name = parse_key (key_name, NULL, &value_name);
    1083  
    1084    trace ("Set key: %s / %s\n", path_name, value_name);
    1085  
    1086    path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
    1087  
    1088    /* Store the value in the registry */
    1089    result = RegCreateKeyExW (hroot, path_namew, 0, NULL, 0, KEY_WRITE, NULL, &hpath, NULL);
    1090    if (result != ERROR_SUCCESS)
    1091      {
    1092        g_message_win32_error (result, "gregistrysettingsbackend: opening key %s failed",
    1093                               path_name + 1);
    1094        registry_value_free (value);
    1095        g_free (path_namew);
    1096        g_free (path_name);
    1097        return FALSE;
    1098      }
    1099  
    1100    g_free (path_namew);
    1101  
    1102    value_namew = g_utf8_to_utf16 (value_name, -1, NULL, NULL, NULL);
    1103  
    1104    value_dataw = NULL;
    1105  
    1106    switch (type_string[0])
    1107      {
    1108      case 'b':
    1109      case 'y':
    1110      case 'n':
    1111      case 'q':
    1112      case 'i':
    1113      case 'u':
    1114      case 'x':
    1115      case 't':
    1116        break;
    1117      default:
    1118        value_dataw = g_utf8_to_utf16 (value_data, -1, NULL, NULL, NULL);
    1119        value_data = value_dataw;
    1120        value_data_size = (DWORD)((wcslen (value_data) + 1) * sizeof (gunichar2));
    1121        break;
    1122      }
    1123  
    1124    result = RegSetValueExW (hpath, value_namew, 0, value.type, value_data, value_data_size);
    1125  
    1126    if (result != ERROR_SUCCESS)
    1127      g_message_win32_error (result, "gregistrysettingsbackend: setting value %s\\%s\\%s\\%s failed.\n",
    1128                             predefined_key_to_string (self->base_key),
    1129                             self->base_path, path_name, value_name);
    1130  
    1131    /* If the write fails then it will seem like the value has changed until the
    1132     * next execution (because we wrote to the cache first). There's no reason
    1133     * for it to fail unless something is weirdly broken, however.
    1134     */
    1135  
    1136    RegCloseKey (hpath);
    1137    g_free (path_name);
    1138    g_free (value_namew);
    1139    g_free (value_dataw);
    1140  
    1141    return FALSE;
    1142  }
    1143  
    1144  /* The dconf write policy is to do the write while making out it succeeded,
    1145   * and then backtrack if it didn't. The registry functions are synchronous so
    1146   * we can't do that. */
    1147  
    1148  static gboolean
    1149  g_registry_settings_backend_write (GSettingsBackend *backend,
    1150                                     const gchar      *key_name,
    1151                                     GVariant         *value,
    1152                                     gpointer          origin_tag)
    1153  {
    1154    GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
    1155    LONG result;
    1156    HKEY hroot;
    1157    RegistryWrite action;
    1158  
    1159    result = RegCreateKeyExW (self->base_key, self->base_pathw, 0, NULL, 0,
    1160                              KEY_WRITE, NULL, &hroot, NULL);
    1161    if (result != ERROR_SUCCESS)
    1162      {
    1163        trace ("Error opening/creating key %s\\%s.\n",
    1164               predefined_key_to_string (self->base_key),
    1165               self->base_path);
    1166        return FALSE;
    1167      }
    1168  
    1169    action.self = self;
    1170    action.hroot = hroot;
    1171    g_registry_settings_backend_write_one (key_name, value, &action);
    1172    g_settings_backend_changed (backend, key_name, origin_tag);
    1173  
    1174    RegCloseKey (hroot);
    1175  
    1176    return TRUE;
    1177  }
    1178  
    1179  static gboolean
    1180  g_registry_settings_backend_write_tree (GSettingsBackend *backend,
    1181                                          GTree            *values,
    1182                                          gpointer          origin_tag)
    1183  {
    1184    GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
    1185    LONG result;
    1186    HKEY hroot;
    1187    RegistryWrite action;
    1188  
    1189    result = RegCreateKeyExW (self->base_key, self->base_pathw, 0, NULL, 0,
    1190                              KEY_WRITE, NULL, &hroot, NULL);
    1191    if (result != ERROR_SUCCESS)
    1192      {
    1193        trace ("Error opening/creating key %s\\%s.\n",
    1194               predefined_key_to_string (self->base_key),
    1195               self->base_path);
    1196        return FALSE;
    1197      }
    1198  
    1199    action.self =  self;
    1200    action.hroot = hroot;
    1201    g_tree_foreach (values, (GTraverseFunc)g_registry_settings_backend_write_one,
    1202                    &action);
    1203  
    1204    g_settings_backend_changed_tree (backend, values, origin_tag);
    1205    RegCloseKey (hroot);
    1206  
    1207    return TRUE;
    1208  }
    1209  
    1210  static void
    1211  g_registry_settings_backend_reset (GSettingsBackend *backend,
    1212                                     const gchar      *key_name,
    1213                                     gpointer          origin_tag)
    1214  {
    1215    GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
    1216    gchar *path_name;
    1217    gunichar2 *path_namew;
    1218    gchar *value_name = NULL;
    1219    gunichar2 *value_namew;
    1220    GNode *cache_node;
    1221    LONG result;
    1222    HKEY hpath;
    1223  
    1224    /* Remove from cache */
    1225    EnterCriticalSection (self->cache_lock);
    1226    cache_node = registry_cache_get_node_for_key (self->cache_root, key_name, FALSE);
    1227    if (cache_node)
    1228      registry_cache_destroy_tree (cache_node, self->watch);
    1229    LeaveCriticalSection (self->cache_lock);
    1230  
    1231    /* Remove from the registry */
    1232    path_name = parse_key (key_name, self->base_path, &value_name);
    1233    path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
    1234  
    1235    result = RegOpenKeyExW (self->base_key, path_namew, 0, KEY_SET_VALUE, &hpath);
    1236    g_free (path_namew);
    1237  
    1238    if (result != ERROR_SUCCESS)
    1239      {
    1240        g_message_win32_error (result, "Registry: resetting key '%s\\%s'",
    1241                               predefined_key_to_string (self->base_key),
    1242                               path_name);
    1243        g_free (path_name);
    1244        return;
    1245      }
    1246  
    1247    value_namew = g_utf8_to_utf16 (value_name, -1, NULL, NULL, NULL);
    1248  
    1249    result = RegDeleteValueW (hpath, value_namew);
    1250    g_free (value_namew);
    1251    RegCloseKey (hpath);
    1252  
    1253    if (result != ERROR_SUCCESS)
    1254      {
    1255        g_message_win32_error (result, "Registry: resetting key '%s\\%s'",
    1256                               predefined_key_to_string (self->base_key),
    1257                               path_name);
    1258        g_free (path_name);
    1259        return;
    1260      }
    1261  
    1262    g_free (path_name);
    1263  
    1264    g_settings_backend_changed (backend, key_name, origin_tag);
    1265  }
    1266  
    1267  static gboolean
    1268  g_registry_settings_backend_get_writable (GSettingsBackend *backend,
    1269                                            const gchar      *key_name)
    1270  {
    1271    GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
    1272    gchar *path_name;
    1273    gunichar2 *path_namew;
    1274    gchar *value_name = NULL;
    1275    HKEY hpath;
    1276    LONG result;
    1277  
    1278    path_name = parse_key (key_name, self->base_path, &value_name);
    1279    path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
    1280  
    1281    /* Note: we create the key if it wasn't created yet, but it is not much
    1282     * of a problem since at the end of the day we have to create it anyway
    1283     * to read or to write from it
    1284     */
    1285    result = RegCreateKeyExW (self->base_key, path_namew, 0, NULL, 0,
    1286                              KEY_WRITE, NULL, &hpath, NULL);
    1287    g_free (path_namew);
    1288  
    1289    if (result != ERROR_SUCCESS)
    1290      {
    1291        trace ("Error opening/creating key to check writability: %s\\%s.\n",
    1292               predefined_key_to_string (self->base_key),
    1293               path_name);
    1294        g_free (path_name);
    1295  
    1296        return FALSE;
    1297      }
    1298  
    1299    g_free (path_name);
    1300    RegCloseKey (hpath);
    1301  
    1302    return TRUE;
    1303  }
    1304  
    1305  /********************************************************************************
    1306   * Spot-the-difference engine
    1307   ********************************************************************************/
    1308  
    1309  static void
    1310  _free_watch (WatchThreadState *self,
    1311               guint             index,
    1312               GNode            *cache_node);
    1313  
    1314  static void
    1315  registry_cache_item_reset_readable (GNode    *node,
    1316                                      gpointer  data)
    1317  {
    1318    RegistryCacheItem *item = node->data;
    1319    item->readable = FALSE;
    1320  }
    1321  
    1322  /* Delete a node and any children, for when it has been deleted from the registry */
    1323  static void
    1324  registry_cache_destroy_tree (GNode            *node,
    1325                               WatchThreadState *self)
    1326  {
    1327    RegistryCacheItem *item = node->data;
    1328  
    1329    g_node_children_foreach (node, G_TRAVERSE_ALL,
    1330                             (GNodeForeachFunc)registry_cache_destroy_tree, self);
    1331  
    1332    if (item->subscription_count > 0)
    1333      {
    1334        guint i;
    1335  
    1336        /* There must be some watches active if this node is a watch point */
    1337        g_warn_if_fail (self->cache_nodes->len > 1);
    1338  
    1339        /* This is a watch point that has been deleted. Let's free the watch! */
    1340        for (i = 1; i < self->cache_nodes->len; i++)
    1341          {
    1342            if (g_ptr_array_index (self->cache_nodes, i) == node)
    1343              break;
    1344          }
    1345  
    1346        if (i >= self->cache_nodes->len)
    1347          g_warning ("watch thread: a watch point was deleted, but unable to "
    1348                     "find '%s' in the list of %i watch nodes\n", item->name,
    1349                     self->cache_nodes->len - 1);
    1350        else
    1351          {
    1352            _free_watch (self, i, node);
    1353            g_atomic_int_inc (&self->watches_remaining);
    1354          }
    1355      }
    1356    registry_cache_item_free (node->data);
    1357    g_node_destroy (node);
    1358  }
    1359  
    1360  /* One of these is sent down the pipe when something happens in the registry. */
    1361  typedef struct
    1362  {
    1363    GRegistrySettingsBackend *self;
    1364    gchar *prefix;          /* prefix is a gsettings path, all items are subkeys of this. */
    1365    GPtrArray *items;       /* each item is a subkey below prefix that has changed. */
    1366  } RegistryEvent;
    1367  
    1368  typedef struct
    1369  {
    1370    RegistryEvent *event;
    1371    gchar *current_key_name;
    1372  } DeletedItemData;
    1373  
    1374  static void
    1375  mark_all_subkeys_as_changed (GNode    *node,
    1376                               gpointer  data)
    1377  {
    1378    RegistryCacheItem *item = node->data;
    1379    DeletedItemData *item_data = data;
    1380  
    1381    if (item_data->current_key_name == NULL)
    1382      item_data->current_key_name = g_strdup (item->name);
    1383    else
    1384      {
    1385        gchar *name;
    1386  
    1387        name = g_build_path ("/", item_data->current_key_name, item->name, NULL);
    1388        g_free (item_data->current_key_name);
    1389        item_data->current_key_name = name;
    1390      }
    1391  
    1392    /* Iterate until we find an item that is a value */
    1393    if (item->value.type == REG_NONE)
    1394      g_node_children_foreach (node, G_TRAVERSE_ALL,
    1395                               mark_all_subkeys_as_changed, data);
    1396    else
    1397      g_ptr_array_add (item_data->event->items, item_data->current_key_name);
    1398  }
    1399  
    1400  static void
    1401  registry_cache_remove_deleted (GNode    *node,
    1402                                 gpointer  data)
    1403  {
    1404    RegistryCacheItem *item = node->data;
    1405    RegistryEvent *event = data;
    1406  
    1407    if (!item->readable)
    1408      {
    1409        DeletedItemData item_data;
    1410  
    1411        item_data.event = event;
    1412        item_data.current_key_name = NULL;
    1413  
    1414        mark_all_subkeys_as_changed (node, &item_data);
    1415        registry_cache_destroy_tree (node, event->self->watch);
    1416      }
    1417  }
    1418  
    1419  /* Update cache from registry, and optionally report on the changes.
    1420   *
    1421   * This function is sometimes called from the watch thread, with no locking. It
    1422   * does call g_registry_settings_backend functions, but this is okay because they only
    1423   * access self->base which is constant.
    1424   *
    1425   * When looking at this code bear in mind the terminology: in the registry, keys
    1426   * are containers that contain values, and other keys. Keys have a 'default'
    1427   * value which we always ignore.
    1428   *
    1429   * n_parent_watches: a counter used to set the reference count of any new nodes
    1430   *                   that are created - they should have as many references as
    1431   *                   there are notifications that are watching them.
    1432   */
    1433  static void
    1434  registry_cache_update (GRegistrySettingsBackend *self,
    1435                         HKEY                      hpath,
    1436                         const gchar              *prefix,
    1437                         const gchar              *partial_key_name,
    1438                         GNode                    *cache_node,
    1439                         int                       n_watches,
    1440                         RegistryEvent            *event)
    1441  {
    1442    gunichar2 bufferw[MAX_KEY_NAME_LENGTH + 1];
    1443    gchar *buffer;
    1444    gchar *key_name;
    1445    gint i;
    1446    LONG result;
    1447    RegistryCacheItem *item;
    1448  
    1449    item = cache_node->data;
    1450  
    1451    if (item->subscription_count > 0)
    1452      n_watches++;
    1453  
    1454    /* prefix is the level that all changes occur below; partial_key_name should
    1455     * be NULL on the first call to this function */
    1456    key_name = g_build_path ("/", prefix, partial_key_name, NULL);
    1457  
    1458    trace ("registry cache update: %s. Node %x has %i children\n", key_name,
    1459           cache_node, g_node_n_children (cache_node));
    1460  
    1461    /* Start by zeroing 'readable' flag. When the registry traversal is done, any unreadable nodes
    1462     * must have been deleted from the registry.
    1463     */
    1464    g_node_children_foreach (cache_node, G_TRAVERSE_ALL,
    1465                             registry_cache_item_reset_readable, NULL);
    1466  
    1467    /* Recurse into each subpath at the current level, if any */
    1468    i = 0;
    1469    while (1)
    1470      {
    1471        DWORD bufferw_size = MAX_KEY_NAME_LENGTH + 1;
    1472        HKEY  hsubpath;
    1473  
    1474        result = RegEnumKeyExW (hpath, i++, bufferw, &bufferw_size, NULL, NULL, NULL, NULL);
    1475        if (result != ERROR_SUCCESS)
    1476          break;
    1477  
    1478        result = RegOpenKeyExW (hpath, bufferw, 0, KEY_READ, &hsubpath);
    1479        if (result == ERROR_SUCCESS)
    1480          {
    1481            GNode *subkey_node;
    1482            RegistryCacheItem *child_item;
    1483            gchar *new_partial_key_name;
    1484  
    1485            buffer = g_utf16_to_utf8 (bufferw, -1, NULL, NULL, NULL);
    1486            if (buffer == NULL)
    1487              continue;
    1488  
    1489            subkey_node = registry_cache_find_immediate_child (cache_node, buffer);
    1490            if (subkey_node == NULL)
    1491              {
    1492                RegistryValue null_value = {REG_NONE, {0}};
    1493                subkey_node = registry_cache_add_item (cache_node, buffer,
    1494                                                       null_value, n_watches);
    1495              }
    1496  
    1497            new_partial_key_name = g_build_path ("/", partial_key_name, buffer, NULL);
    1498            registry_cache_update (self, hsubpath, prefix, new_partial_key_name,
    1499                                   subkey_node, n_watches, event);
    1500            g_free (new_partial_key_name);
    1501  
    1502            child_item = subkey_node->data;
    1503            child_item->readable = TRUE;
    1504  
    1505            g_free (buffer);
    1506            RegCloseKey (hsubpath);
    1507          }
    1508      }
    1509  
    1510    if (result != ERROR_NO_MORE_ITEMS)
    1511      g_message_win32_error (result, "gregistrysettingsbackend: error enumerating subkeys for cache.");
    1512  
    1513    /* Enumerate each value at 'path' and check if it has changed */
    1514    i = 0;
    1515    while (1)
    1516      {
    1517        DWORD bufferw_size = MAX_KEY_NAME_LENGTH + 1;
    1518        GNode *cache_child_node;
    1519        RegistryCacheItem *child_item;
    1520        RegistryValue value;
    1521        gboolean changed = FALSE;
    1522  
    1523        result = RegEnumValueW (hpath, i++, bufferw, &bufferw_size, NULL, NULL, NULL, NULL);
    1524        if (result != ERROR_SUCCESS)
    1525          break;
    1526  
    1527        buffer = g_utf16_to_utf8 (bufferw, -1, NULL, NULL, NULL);
    1528  
    1529        if (buffer == NULL || buffer[0] == 0)
    1530          {
    1531            /* This is the key's 'default' value, for which we have no use. */
    1532            g_free (buffer);
    1533            continue;
    1534          }
    1535  
    1536        cache_child_node = registry_cache_find_immediate_child (cache_node, buffer);
    1537  
    1538        if (!registry_read (hpath, key_name, buffer, &value))
    1539          {
    1540            g_free (buffer);
    1541            continue;
    1542          }
    1543  
    1544        trace ("\tgot value %s for %s, node %x\n",
    1545               registry_value_dump (value), buffer, cache_child_node);
    1546  
    1547        if (cache_child_node == NULL)
    1548          {
    1549            /* This is a new value */
    1550            cache_child_node = registry_cache_add_item (cache_node, buffer, value,
    1551                                                        n_watches);
    1552            changed = TRUE;
    1553          }
    1554        else
    1555          {
    1556           /* For efficiency, instead of converting every value back to a GVariant to
    1557            * compare it, we compare them as registry values (integers, or string
    1558            * representations of the variant). The spurious change notifications that may
    1559            * result should not be a big issue.
    1560            *
    1561            * Note that 'value' is swallowed or freed.
    1562            */
    1563            changed = registry_cache_update_node (cache_child_node, value);
    1564          }
    1565  
    1566        child_item = cache_child_node->data;
    1567        child_item->readable = TRUE;
    1568        if (changed && event != NULL)
    1569          {
    1570            gchar *item_path;
    1571  
    1572            if (partial_key_name == NULL)
    1573              item_path = g_strdup (buffer);
    1574            else
    1575              item_path = g_build_path ("/", partial_key_name, buffer, NULL);
    1576  
    1577            g_ptr_array_add (event->items, item_path);
    1578          }
    1579  
    1580        g_free (buffer);
    1581      }
    1582  
    1583    if (result != ERROR_NO_MORE_ITEMS)
    1584      g_message_win32_error (result, "gregistrysettingsbackend: error enumerating values for cache");
    1585  
    1586    /* Any nodes now left unreadable must have been deleted, remove them from cache */
    1587    g_node_children_foreach (cache_node, G_TRAVERSE_ALL,
    1588                             registry_cache_remove_deleted, event);
    1589  
    1590    trace ("registry cache update complete.\n");
    1591  
    1592    g_free (key_name);
    1593  }
    1594  
    1595  /***********************************************************************************
    1596   * Thread to watch for registry change events
    1597   ***********************************************************************************/
    1598  
    1599  /* Called by watch thread. Apply for notifications on a registry key and its subkeys. */
    1600  static DWORD
    1601  registry_watch_key (HKEY   hpath,
    1602                      HANDLE event)
    1603  {
    1604    return RegNotifyChangeKeyValue (hpath, TRUE,
    1605                                    REG_NOTIFY_CHANGE_NAME | REG_NOTIFY_CHANGE_LAST_SET,
    1606                                    event, TRUE);
    1607  }
    1608  
    1609  /* This handler runs in the main thread to emit the changed signals */
    1610  static gboolean
    1611  watch_handler (RegistryEvent *event)
    1612  {
    1613    trace ("Watch handler: got event in %s, items %i.\n", event->prefix, event->items->len);
    1614  
    1615    /* GSettings requires us to NULL-terminate the array. */
    1616    g_ptr_array_add (event->items, NULL);
    1617    g_settings_backend_keys_changed (G_SETTINGS_BACKEND (event->self), event->prefix,
    1618                                     (gchar const **)event->items->pdata, NULL);
    1619  
    1620    g_ptr_array_free (event->items, TRUE);
    1621    g_free (event->prefix);
    1622    g_object_unref (event->self);
    1623    g_slice_free (RegistryEvent, event);
    1624  
    1625    return G_SOURCE_REMOVE;
    1626  }
    1627  
    1628  static void
    1629  _free_watch (WatchThreadState *self,
    1630               guint             index,
    1631               GNode            *cache_node)
    1632  {
    1633    HKEY hpath;
    1634    HANDLE cond;
    1635    gchar *prefix;
    1636  
    1637    g_return_if_fail (index > 0 && index < self->events->len);
    1638  
    1639    cond = g_ptr_array_index (self->events, index);
    1640    hpath = g_ptr_array_index (self->handles, index);
    1641    prefix = g_ptr_array_index (self->prefixes, index);
    1642  
    1643    trace ("Freeing watch %i [%s]\n", index, prefix);
    1644  
    1645    /* These can be NULL if the watch was already dead, this can happen when eg.
    1646     * a key is deleted but GSettings is still subscribed to it - the watch is
    1647     * kept alive so that the unsubscribe function works properly, but does not
    1648     * do anything.
    1649     */
    1650    if (hpath != NULL)
    1651      RegCloseKey (hpath);
    1652  
    1653    if (cache_node != NULL)
    1654      {
    1655        //registry_cache_dump (G_REGISTRY_SETTINGS_BACKEND (self->owner)->cache_root, NULL);
    1656        registry_cache_unref_tree (cache_node);
    1657      }
    1658  
    1659    CloseHandle (cond);
    1660    g_free (prefix);
    1661  
    1662    /* As long as we remove from each array at the same time, it doesn't matter that
    1663     * their orders get messed up - they all get messed up the same.
    1664     */
    1665    g_ptr_array_remove_index_fast (self->handles, index);
    1666    g_ptr_array_remove_index_fast (self->events, index);
    1667    g_ptr_array_remove_index_fast (self->prefixes, index);
    1668    g_ptr_array_remove_index_fast (self->cache_nodes, index);
    1669  }
    1670  
    1671  static void
    1672  watch_thread_handle_message (WatchThreadState *self)
    1673  {
    1674    switch (self->message.type)
    1675      {
    1676      case WATCH_THREAD_NONE:
    1677        trace ("watch thread: you woke me up for nothin', man!");
    1678        break;
    1679  
    1680      case WATCH_THREAD_ADD_WATCH:
    1681        {
    1682          RegistryWatch *watch = &self->message.watch;
    1683          LONG result;
    1684  
    1685          result = registry_watch_key (watch->hpath, watch->event);
    1686  
    1687          if (result == ERROR_SUCCESS)
    1688            {
    1689              g_ptr_array_add (self->events, watch->event);
    1690              g_ptr_array_add (self->handles, watch->hpath);
    1691              g_ptr_array_add (self->prefixes, watch->prefix);
    1692              g_ptr_array_add (self->cache_nodes, watch->cache_node);
    1693  
    1694              trace ("watch thread: new watch on %s, %i total\n", watch->prefix,
    1695                     self->events->len);
    1696            }
    1697          else
    1698            {
    1699              g_message_win32_error (result, "watch thread: could not watch %s", watch->prefix);
    1700  
    1701              CloseHandle (watch->event);
    1702              RegCloseKey (watch->hpath);
    1703              g_free (watch->prefix);
    1704              registry_cache_unref_tree (watch->cache_node);
    1705            }
    1706          break;
    1707        }
    1708  
    1709      case WATCH_THREAD_REMOVE_WATCH:
    1710        {
    1711          GNode *cache_node;
    1712          RegistryCacheItem *cache_item;
    1713          guint i;
    1714  
    1715          for (i = 1; i < self->prefixes->len; i++)
    1716            {
    1717              if (strcmp (g_ptr_array_index (self->prefixes, i),
    1718                          self->message.watch.prefix) == 0)
    1719                break;
    1720            }
    1721  
    1722          if (i >= self->prefixes->len)
    1723            {
    1724              /* Don't make a fuss if the prefix is not being watched because
    1725               * maybe the path was deleted so we removed the watch.
    1726               */
    1727              trace ("unsubscribe: prefix %s is not being watched [%i things are]!\n",
    1728                     self->message.watch.prefix, self->prefixes->len);
    1729              g_free (self->message.watch.prefix);
    1730              break;
    1731            }
    1732  
    1733          cache_node = g_ptr_array_index (self->cache_nodes, i);
    1734  
    1735          trace ("watch thread: unsubscribe: freeing node %p, prefix %s, index %i\n",
    1736                 cache_node, self->message.watch.prefix, i);
    1737  
    1738          if (cache_node != NULL)
    1739            {
    1740              cache_item = cache_node->data;
    1741  
    1742              /* There may be more than one GSettings object subscribed to this
    1743               * path, only free the watch when the last one unsubscribes.
    1744               */
    1745              cache_item->subscription_count--;
    1746              if (cache_item->subscription_count > 0)
    1747                break;
    1748            }
    1749  
    1750          _free_watch (self, i, cache_node);
    1751          g_free (self->message.watch.prefix);
    1752  
    1753          g_atomic_int_inc (&self->watches_remaining);
    1754          break;
    1755        }
    1756  
    1757      case WATCH_THREAD_STOP:
    1758        {
    1759          guint i;
    1760  
    1761          /* Free any remaining cache and watch handles */
    1762          for (i = 1; i < self->events->len; i++)
    1763            _free_watch (self, i, g_ptr_array_index (self->cache_nodes, i));
    1764  
    1765          SetEvent (self->message_received_event);
    1766          ExitThread (0);
    1767        }
    1768      }
    1769  
    1770    self->message.type = WATCH_THREAD_NONE;
    1771    SetEvent (self->message_received_event);
    1772  }
    1773  
    1774  /* Thread which watches for win32 registry events */
    1775  static DWORD WINAPI
    1776  watch_thread_function (LPVOID parameter)
    1777  {
    1778    WatchThreadState *self = (WatchThreadState *)parameter;
    1779    DWORD result;
    1780  
    1781    self->events = g_ptr_array_new ();
    1782    self->handles = g_ptr_array_new ();
    1783    self->prefixes = g_ptr_array_new ();
    1784    self->cache_nodes = g_ptr_array_new ();
    1785    g_ptr_array_add (self->events, self->message_sent_event);
    1786    g_ptr_array_add (self->handles, NULL);
    1787    g_ptr_array_add (self->prefixes, NULL);
    1788    g_ptr_array_add (self->cache_nodes, NULL);
    1789  
    1790    while (1)
    1791      {
    1792        trace ("watch thread: going to sleep; %i events watched.\n", self->events->len);
    1793        result = WaitForMultipleObjects (self->events->len, self->events->pdata, FALSE, INFINITE);
    1794  
    1795        if (result == WAIT_OBJECT_0)
    1796          {
    1797            /* A message to you. The sender (main thread) will block until we signal the received
    1798             * event, so there should be no danger of it sending another before we receive the
    1799             * first.
    1800             */
    1801            watch_thread_handle_message (self);
    1802          }
    1803        else if (result > WAIT_OBJECT_0 && result <= WAIT_OBJECT_0 + self->events->len)
    1804          {
    1805            HKEY hpath;
    1806            HANDLE cond;
    1807            gchar *prefix;
    1808            GNode *cache_node;
    1809            RegistryCacheItem *cache_item;
    1810            RegistryEvent *event;
    1811            gint notify_index;
    1812  
    1813            /* One of our notifications has triggered. All we know is which one, and which key
    1814             * this is for. We do most of the processing here, because we may as well. If the
    1815             * registry changes further while we are processing it doesn't matter - we will then
    1816             * receive another change notification from the OS anyway.
    1817             */
    1818            notify_index = result - WAIT_OBJECT_0;
    1819            hpath = g_ptr_array_index (self->handles, notify_index);
    1820            cond = g_ptr_array_index (self->events, notify_index);
    1821            prefix = g_ptr_array_index (self->prefixes, notify_index);
    1822            cache_node = g_ptr_array_index (self->cache_nodes, notify_index);
    1823  
    1824            trace ("Watch thread: notify received on prefix %i: %s.\n", notify_index, prefix);
    1825  
    1826            if (cache_node == NULL)
    1827              {
    1828                /* This path has been deleted */
    1829                trace ("Notify received on a path that was deleted\n");
    1830                continue;
    1831              }
    1832  
    1833            /* Firstly we need to reapply for the notification, because (what a
    1834             * sensible API) we won't receive any more. MSDN is pretty
    1835             * inconsistent on this matter:
    1836             *   http://msdn.microsoft.com/en-us/library/ms724892%28VS.85%29.aspx
    1837             *   http://support.microsoft.com/kb/236570
    1838             * But my tests (on Windows XP SP3) show that we need to reapply
    1839             * each time.
    1840             */
    1841            result = registry_watch_key (hpath, cond);
    1842  
    1843            if (result != ERROR_SUCCESS)
    1844              {
    1845                /* Watch failed, most likely because the key has just been
    1846                 * deleted. Free the watch and unref the cache nodes.
    1847                 */
    1848               if (result != ERROR_KEY_DELETED)
    1849                 g_message_win32_error (result, "watch thread: failed to watch %s", prefix);
    1850  
    1851               _free_watch (self, notify_index, cache_node);
    1852               g_atomic_int_inc (&self->watches_remaining);
    1853               continue;
    1854              }
    1855  
    1856            /* The notification may have been blocked because we just changed
    1857             * some data ourselves.
    1858             */
    1859            cache_item = cache_node->data;
    1860            if (cache_item->block_count)
    1861              {
    1862                cache_item->block_count--;
    1863                trace ("Watch thread: notify blocked at %s\n", prefix);
    1864                continue;
    1865              }
    1866  
    1867            /* Now we update our stored cache from registry data, and find which keys have
    1868             * actually changed. If more changes happen while we are processing, we will get
    1869             * another event because we have reapplied for change notifications already.
    1870             *
    1871             * Working here rather than in the main thread is preferable because the UI is less
    1872             * likely to block (only when changing notification subscriptions).
    1873             */
    1874            event = g_slice_new (RegistryEvent);
    1875            event->self = G_REGISTRY_SETTINGS_BACKEND (g_object_ref (self->owner));
    1876            event->prefix = g_strdup (prefix);
    1877            event->items = g_ptr_array_new_with_free_func (g_free);
    1878  
    1879            EnterCriticalSection (G_REGISTRY_SETTINGS_BACKEND (self->owner)->cache_lock);
    1880            registry_cache_update (G_REGISTRY_SETTINGS_BACKEND (self->owner), hpath,
    1881                                   prefix, NULL, cache_node, 0, event);
    1882            LeaveCriticalSection (G_REGISTRY_SETTINGS_BACKEND (self->owner)->cache_lock);
    1883  
    1884            if (event->items->len > 0)
    1885              g_idle_add ((GSourceFunc) watch_handler, event);
    1886            else
    1887              {
    1888                g_object_unref (event->self);
    1889                g_free (event->prefix);
    1890                g_ptr_array_free (event->items, TRUE);
    1891                g_slice_free (RegistryEvent, event);
    1892              }
    1893          }
    1894        else
    1895          {
    1896            /* God knows what has happened */
    1897            g_message_win32_error (GetLastError(), "watch thread: WaitForMultipleObjects error");
    1898          }
    1899      }
    1900  
    1901    return -1;
    1902  }
    1903  
    1904  static gboolean
    1905  watch_start (GRegistrySettingsBackend *self)
    1906  {
    1907    WatchThreadState *watch;
    1908  
    1909    g_return_val_if_fail (self->watch == NULL, FALSE);
    1910  
    1911    watch = g_slice_new (WatchThreadState);
    1912    watch->owner = G_SETTINGS_BACKEND (self);
    1913  
    1914    watch->watches_remaining = MAX_WATCHES;
    1915  
    1916    watch->message_lock = g_slice_new (CRITICAL_SECTION);
    1917    InitializeCriticalSection (watch->message_lock);
    1918    watch->message_sent_event = CreateEvent (NULL, FALSE, FALSE, NULL);
    1919    watch->message_received_event = CreateEvent (NULL, FALSE, FALSE, NULL);
    1920    if (watch->message_sent_event == NULL || watch->message_received_event == NULL)
    1921      {
    1922        g_message_win32_error (GetLastError (), "gregistrysettingsbackend: Failed to create sync objects.");
    1923        goto fail;
    1924      }
    1925  
    1926    /* Use a small stack to make the thread more lightweight. */
    1927    watch->thread = CreateThread (NULL, 1024, watch_thread_function, watch, 0, NULL);
    1928    if (watch->thread == NULL)
    1929      {
    1930        g_message_win32_error (GetLastError (), "gregistrysettingsbackend: Failed to create notify watch thread.");
    1931        goto fail;
    1932      }
    1933  
    1934    self->watch = watch;
    1935  
    1936    return TRUE;
    1937  
    1938  fail:
    1939    DeleteCriticalSection (watch->message_lock);
    1940    g_slice_free (CRITICAL_SECTION, watch->message_lock);
    1941    if (watch->message_sent_event != NULL)
    1942      CloseHandle (watch->message_sent_event);
    1943    if (watch->message_received_event != NULL)
    1944      CloseHandle (watch->message_received_event);
    1945    g_slice_free (WatchThreadState, watch);
    1946  
    1947    return FALSE;
    1948  }
    1949  
    1950  /* This function assumes you hold the message lock! */
    1951  static void
    1952  watch_stop_unlocked (GRegistrySettingsBackend *self)
    1953  {
    1954    WatchThreadState *watch = self->watch;
    1955    DWORD result;
    1956  
    1957    g_return_if_fail (watch != NULL);
    1958  
    1959    watch->message.type = WATCH_THREAD_STOP;
    1960    SetEvent (watch->message_sent_event);
    1961  
    1962    /* This is signalled as soon as the message is received. We must not return
    1963     * while the watch thread is still firing off callbacks. Freeing all of the
    1964     * memory is done in the watch thread after this is signalled.
    1965     */
    1966    result = WaitForSingleObject (watch->message_received_event, INFINITE);
    1967    if (result != WAIT_OBJECT_0)
    1968      {
    1969        g_warning ("gregistrysettingsbackend: unable to stop watch thread.");
    1970        return;
    1971      }
    1972  
    1973    LeaveCriticalSection (watch->message_lock);
    1974    DeleteCriticalSection (watch->message_lock);
    1975    g_slice_free (CRITICAL_SECTION, watch->message_lock);
    1976    CloseHandle (watch->message_sent_event);
    1977    CloseHandle (watch->message_received_event);
    1978    CloseHandle (watch->thread);
    1979    g_slice_free (WatchThreadState, watch);
    1980  
    1981    trace ("\nwatch thread: %x: all data freed.\n", self);
    1982    self->watch = NULL;
    1983  }
    1984  
    1985  static gboolean
    1986  watch_add_notify (GRegistrySettingsBackend *self,
    1987                    HANDLE                    event,
    1988                    HKEY                      hpath,
    1989                    gchar                    *gsettings_prefix)
    1990  {
    1991    WatchThreadState *watch = self->watch;
    1992    GNode *cache_node;
    1993    RegistryCacheItem *cache_item;
    1994  #ifdef TRACE
    1995    DWORD result;
    1996  #endif
    1997  
    1998    g_return_val_if_fail (watch != NULL, FALSE);
    1999  
    2000    trace ("watch_add_notify: prefix %s.\n", gsettings_prefix);
    2001  
    2002    /* Duplicate tree into the cache in the main thread, before we add the notify: if we do it in the
    2003     * thread we can miss changes while we are caching.
    2004     */
    2005    EnterCriticalSection (self->cache_lock);
    2006    cache_node = registry_cache_get_node_for_key (self->cache_root, gsettings_prefix, TRUE);
    2007  
    2008    if (cache_node == NULL || cache_node->data == NULL)
    2009      {
    2010        LeaveCriticalSection (self->cache_lock);
    2011        g_warn_if_reached ();
    2012        return FALSE;
    2013      }
    2014  
    2015    cache_item = cache_node->data;
    2016  
    2017    cache_item->subscription_count++;
    2018    if (cache_item->subscription_count > 1)
    2019      {
    2020        trace ("watch_add_notify: prefix %s already watched, %i subscribers.\n",
    2021               gsettings_prefix, cache_item->subscription_count);
    2022        LeaveCriticalSection (self->cache_lock);
    2023        return FALSE;
    2024      }
    2025  
    2026    registry_cache_ref_tree (cache_node);
    2027    registry_cache_update (self, hpath, gsettings_prefix, NULL, cache_node, 0, NULL);
    2028    //registry_cache_dump (self->cache_root, NULL);
    2029    LeaveCriticalSection (self->cache_lock);
    2030  
    2031    EnterCriticalSection (watch->message_lock);
    2032    watch->message.type = WATCH_THREAD_ADD_WATCH;
    2033    watch->message.watch.event = event;
    2034    watch->message.watch.hpath = hpath;
    2035    watch->message.watch.prefix = gsettings_prefix;
    2036    watch->message.watch.cache_node = cache_node;
    2037  
    2038    SetEvent (watch->message_sent_event);
    2039  
    2040    /* Wait for the received event in return, to avoid sending another message before the first
    2041     * one was received. If it takes > 200ms there is a possible race but the worst outcome is
    2042     * a notification is ignored.
    2043     */
    2044  #ifdef TRACE
    2045    result =
    2046  #endif
    2047      WaitForSingleObject (watch->message_received_event, 200);
    2048  #ifdef TRACE
    2049    if (result != WAIT_OBJECT_0)
    2050      trace ("watch thread is slow to respond - notification may not be added.");
    2051  #endif
    2052  
    2053    LeaveCriticalSection (watch->message_lock);
    2054  
    2055    return TRUE;
    2056  }
    2057  
    2058  static void
    2059  watch_remove_notify (GRegistrySettingsBackend *self,
    2060                       const gchar              *key_name)
    2061  {
    2062    WatchThreadState *watch = self->watch;
    2063    LONG result;
    2064  
    2065    if (self->watch == NULL)
    2066      /* Here we assume that the unsubscribe message is for somewhere that was
    2067       * deleted, and so it has already been removed and the watch thread has
    2068       * stopped.
    2069       */
    2070      return;
    2071  
    2072    EnterCriticalSection (watch->message_lock);
    2073    watch->message.type = WATCH_THREAD_REMOVE_WATCH;
    2074    watch->message.watch.prefix = g_strdup (key_name);
    2075  
    2076    SetEvent (watch->message_sent_event);
    2077  
    2078    /* Wait for the received event in return, to avoid sending another message before the first
    2079     * one was received.
    2080     */
    2081    result = WaitForSingleObject (watch->message_received_event, INFINITE);
    2082  
    2083    if (result != ERROR_SUCCESS)
    2084      g_warning ("unsubscribe from %s: message not acknowledged", key_name);
    2085  
    2086    if (g_atomic_int_get (&watch->watches_remaining) >= MAX_WATCHES)
    2087      /* Stop it before any new ones can get added and confuse things */
    2088      watch_stop_unlocked (self);
    2089    else
    2090      LeaveCriticalSection (watch->message_lock);
    2091  }
    2092  
    2093  /* dconf semantics are: if the key ends in /, watch the keys underneath it - if not, watch that
    2094   * key. Our job is easier because keys and values are separate.
    2095   */
    2096  static void
    2097  g_registry_settings_backend_subscribe (GSettingsBackend *backend,
    2098                                         const char       *key_name)
    2099  {
    2100    GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
    2101    gchar *path_name;
    2102    gunichar2 *path_namew;
    2103    gchar *value_name = NULL;
    2104    HKEY hpath;
    2105    HANDLE event;
    2106    LONG result;
    2107  
    2108    if (self->watch == NULL && !watch_start (self))
    2109      return;
    2110  
    2111    if (g_atomic_int_dec_and_test (&self->watch->watches_remaining))
    2112      {
    2113        g_atomic_int_inc (&self->watch->watches_remaining);
    2114        g_warning ("subscribe() failed: only %i different paths may be watched.", MAX_WATCHES);
    2115        return;
    2116      }
    2117  
    2118    path_name = parse_key (key_name, self->base_path, &value_name);
    2119  
    2120    /* Must check for this, otherwise strange crashes occur because the cache
    2121     * node that is being watched gets freed. All path names to subscribe must
    2122     * end in a slash!
    2123     */
    2124    if (value_name != NULL && *value_name != 0)
    2125      g_warning ("subscribe() failed: path must end in a /, got %s", key_name);
    2126  
    2127    trace ("Subscribing to %s [registry %s / %s] - watch %x\n", key_name, path_name, value_name, self->watch);
    2128  
    2129    path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
    2130    g_free (path_name);
    2131  
    2132    /* Give the caller the benefit of the doubt if the key doesn't exist and create it. The caller
    2133     * is almost certainly a new g_settings with this path as base path. */
    2134    result = RegCreateKeyExW (self->base_key, path_namew, 0, NULL, 0, KEY_READ, NULL, &hpath,
    2135                              NULL);
    2136    g_free (path_namew);
    2137  
    2138    if (result != ERROR_SUCCESS)
    2139      {
    2140        g_message_win32_error (result, "gregistrysettingsbackend: Unable to subscribe to key %s.", key_name);
    2141        g_atomic_int_inc (&self->watch->watches_remaining);
    2142        return;
    2143      }
    2144  
    2145    event = CreateEvent (NULL, FALSE, FALSE, NULL);
    2146    if (event == NULL)
    2147      {
    2148        g_message_win32_error (result, "gregistrysettingsbackend: CreateEvent failed.");
    2149        g_atomic_int_inc (&self->watch->watches_remaining);
    2150        RegCloseKey (hpath);
    2151        return;
    2152      }
    2153  
    2154    /* The actual watch is added by the thread, which has to re-subscribe each time it
    2155     * receives a change. */
    2156    if (!watch_add_notify (self, event, hpath, g_strdup (key_name)))
    2157      {
    2158        g_atomic_int_inc (&self->watch->watches_remaining);
    2159        RegCloseKey (hpath);
    2160        CloseHandle (event);
    2161      }
    2162  }
    2163  
    2164  static void
    2165  g_registry_settings_backend_unsubscribe (GSettingsBackend *backend,
    2166                                           const char       *key_name)
    2167  {
    2168    trace ("unsubscribe: %s.\n", key_name);
    2169  
    2170    watch_remove_notify (G_REGISTRY_SETTINGS_BACKEND (backend), key_name);
    2171  }
    2172  
    2173  /********************************************************************************
    2174   * Object management junk
    2175   ********************************************************************************/
    2176  
    2177  static void
    2178  g_registry_settings_backend_finalize (GObject *object)
    2179  {
    2180    GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
    2181    RegistryCacheItem *item;
    2182  
    2183    item = self->cache_root->data;
    2184    g_warn_if_fail (item->ref_count == 1);
    2185  
    2186    registry_cache_item_free (item);
    2187    g_node_destroy (self->cache_root);
    2188  
    2189    if (self->watch != NULL)
    2190      {
    2191        EnterCriticalSection (self->watch->message_lock);
    2192        watch_stop_unlocked (self);
    2193      }
    2194  
    2195    DeleteCriticalSection (self->cache_lock);
    2196    g_slice_free (CRITICAL_SECTION, self->cache_lock);
    2197  
    2198    g_free (self->base_path);
    2199    g_free (self->base_pathw);
    2200  }
    2201  
    2202  static void
    2203  g_registry_settings_backend_constructed (GObject *object)
    2204  {
    2205    GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
    2206  
    2207    if (self->base_key == NULL || self->base_path == NULL || self->base_pathw == NULL)
    2208      {
    2209        self->base_key = HKEY_CURRENT_USER;
    2210        self->base_path = g_strdup ("Software\\GSettings");
    2211        self->base_pathw = g_utf8_to_utf16 (self->base_path, -1, NULL, NULL, NULL);
    2212      }
    2213  }
    2214  
    2215  static void
    2216  g_registry_settings_backend_get_property (GObject    *object,
    2217                                            guint       prop_id,
    2218                                            GValue     *value,
    2219                                            GParamSpec *pspec)
    2220  {
    2221    GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
    2222  
    2223    switch ((GRegistrySettingsBackendProperty) prop_id)
    2224      {
    2225      case PROP_REGISTRY_KEY:
    2226        g_value_take_string (value,
    2227                             g_strdup_printf ("%s\\%s",
    2228                                              predefined_key_to_string (self->base_key),
    2229                                              self->base_path));
    2230        break;
    2231  
    2232      default:
    2233        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    2234        break;
    2235      }
    2236  }
    2237  
    2238  static void
    2239  g_registry_settings_backend_set_property (GObject      *object,
    2240                                            guint         prop_id,
    2241                                            const GValue *value,
    2242                                            GParamSpec   *pspec)
    2243  {
    2244    GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
    2245    const gchar *reg_path;
    2246  
    2247    switch ((GRegistrySettingsBackendProperty) prop_id)
    2248      {
    2249      case PROP_REGISTRY_KEY:
    2250        /* Construct only. */
    2251        g_assert (self->base_key == NULL);
    2252        g_assert (self->base_path == NULL);
    2253        g_assert (self->base_pathw == NULL);
    2254  
    2255        reg_path = g_value_get_string (value);
    2256        if (reg_path != NULL)
    2257          {
    2258            HKEY base_key;
    2259            const gchar *base_path = split_registry_path (reg_path, &base_key);
    2260  
    2261            if (base_path != NULL)
    2262              {
    2263                gunichar2 *base_pathw = g_utf8_to_utf16 (base_path, -1, NULL, NULL, NULL);
    2264  
    2265                if (base_pathw != NULL)
    2266                  {
    2267                    self->base_key = g_steal_pointer (&base_key);
    2268                    self->base_path = g_strdup (base_path);
    2269                    self->base_pathw = g_steal_pointer (&base_pathw);
    2270                  }
    2271                else
    2272                  g_warning ("gregistrysettingsbackend: invalid base registry path '%s'", reg_path);
    2273              }
    2274            else
    2275              g_warning ("gregistrysettingsbackend: base registry path '%s' does not start with a valid root key", reg_path);
    2276          }
    2277        break;
    2278  
    2279      default:
    2280        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
    2281        break;
    2282      }
    2283  }
    2284  
    2285  static void
    2286  g_registry_settings_backend_class_init (GRegistrySettingsBackendClass *class)
    2287  {
    2288    GSettingsBackendClass *backend_class = G_SETTINGS_BACKEND_CLASS (class);
    2289    GObjectClass *object_class = G_OBJECT_CLASS (class);
    2290  
    2291    object_class->finalize = g_registry_settings_backend_finalize;
    2292    object_class->constructed = g_registry_settings_backend_constructed;
    2293    object_class->get_property = g_registry_settings_backend_get_property;
    2294    object_class->set_property = g_registry_settings_backend_set_property;
    2295  
    2296    backend_class->read = g_registry_settings_backend_read;
    2297    backend_class->write = g_registry_settings_backend_write;
    2298    backend_class->write_tree = g_registry_settings_backend_write_tree;
    2299    backend_class->reset = g_registry_settings_backend_reset;
    2300    backend_class->get_writable = g_registry_settings_backend_get_writable;
    2301    backend_class->subscribe = g_registry_settings_backend_subscribe;
    2302    backend_class->unsubscribe = g_registry_settings_backend_unsubscribe;
    2303  
    2304    /**
    2305     * GRegistrySettingsBackend:registry-key:
    2306     *
    2307     * The location where settings are stored in the registry. Must
    2308     * start with one of the following:
    2309     * - `HKEY_CLASSES_ROOT`
    2310     * - `HKEY_CURRENT_CONFIG`
    2311     * - `HKEY_CURRENT_USER`
    2312     * - `HKEY_LOCAL_MACHINE`
    2313     * - `HKEY_USERS`
    2314     *
    2315     * Defaults to `HKEY_CURRENT_USER\Software\GSettings`.
    2316     *
    2317     * Since: 2.78
    2318     */
    2319    g_object_class_install_property (object_class,
    2320                                     PROP_REGISTRY_KEY,
    2321                                     g_param_spec_string ("registry-key",
    2322                                                          NULL, NULL,
    2323                                                          "HKEY_CURRENT_USER\\Software\\GSettings",
    2324                                                          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
    2325                                                          G_PARAM_STATIC_STRINGS));
    2326  }
    2327  
    2328  static void
    2329  g_registry_settings_backend_init (GRegistrySettingsBackend *self)
    2330  {
    2331    RegistryCacheItem *item;
    2332  
    2333    item = g_slice_new (RegistryCacheItem);
    2334    item->value.type = REG_NONE;
    2335    item->value.ptr = NULL;
    2336    item->name = g_strdup ("<root>");
    2337    item->ref_count = 1;
    2338    self->cache_root = g_node_new (item);
    2339  
    2340    self->cache_lock = g_slice_new (CRITICAL_SECTION);
    2341    InitializeCriticalSection (self->cache_lock);
    2342  
    2343    self->watch = NULL;
    2344  }
    2345  
    2346  /**
    2347   * g_registry_settings_backend_new:
    2348   * @registry_key: (nullable): the path to the registry key where
    2349   *                settings are stored, or %NULL.
    2350   *
    2351   * If @registry_key is %NULL then the default path
    2352   * `HKEY_CURRENT_USER\Software\GSettings` is used.
    2353   *
    2354   * Returns: (transfer full): a registry-backed #GSettingsBackend
    2355   *
    2356   * Since: 2.78
    2357   **/
    2358  GSettingsBackend *
    2359  g_registry_settings_backend_new (const gchar *registry_key)
    2360  {
    2361    g_return_val_if_fail (registry_key == NULL || split_registry_path (registry_key, NULL), NULL);
    2362  
    2363    return G_SETTINGS_BACKEND (g_object_new (G_TYPE_REGISTRY_SETTINGS_BACKEND,
    2364                                             "registry-key", registry_key,
    2365                                             NULL));
    2366  }