mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
Merge branch 'registry-settings-root-key' into 'main'
gregistrysettingsbackend: Allow a different root key path See merge request GNOME/glib!3306
This commit is contained in:
commit
da35056247
@ -110,3 +110,13 @@ G_WIN32_REGISTRY_KEY_GET_CLASS
|
||||
G_TYPE_WIN32_REGISTRY_SUBKEY_ITER
|
||||
G_TYPE_WIN32_REGISTRY_VALUE_ITER
|
||||
</SECTION>
|
||||
|
||||
<SECTION>
|
||||
<FILE>gregistrysettingsbackend</FILE>
|
||||
<TITLE>GRegistrySettingsBackend</TITLE>
|
||||
GRegistrySettingsBackend
|
||||
g_registry_settings_backend_new
|
||||
|
||||
<SUBSECTION Private>
|
||||
g_registry_settings_backend_get_type
|
||||
</SECTION>
|
||||
|
@ -1355,7 +1355,7 @@ _g_io_modules_ensure_loaded (void)
|
||||
#ifdef G_OS_WIN32
|
||||
g_type_ensure (_g_win32_volume_monitor_get_type ());
|
||||
g_type_ensure (g_win32_file_monitor_get_type ());
|
||||
g_type_ensure (g_registry_backend_get_type ());
|
||||
g_type_ensure (g_registry_settings_backend_get_type ());
|
||||
#endif
|
||||
#ifdef HAVE_COCOA
|
||||
g_type_ensure (g_nextstep_settings_backend_get_type ());
|
||||
|
@ -19,13 +19,11 @@
|
||||
* Author: Sam Thursfield <ssssam@gmail.com>
|
||||
*/
|
||||
|
||||
/* GRegistryBackend implementation notes:
|
||||
/* GRegistrySettingsBackend implementation notes:
|
||||
*
|
||||
* - All settings are stored under the path:
|
||||
* HKEY_CURRENT_USER\Software\GSettings\
|
||||
* This means all settings are per-user. Permissions and system-wide
|
||||
* defaults are not implemented and will probably always be out of scope of
|
||||
* the Windows port of GLib.
|
||||
* - All settings are stored under the registry path given at construction
|
||||
* time. Permissions and system-wide defaults are not implemented and will
|
||||
* probably always be out of scope of the Windows port of GLib.
|
||||
*
|
||||
* - The registry type system is limited. Most GVariant types are stored as
|
||||
* literals via g_variant_print/parse(). Strings are stored without the
|
||||
@ -93,8 +91,11 @@
|
||||
|
||||
#include "gregistrysettingsbackend.h"
|
||||
#include "gsettingsbackend.h"
|
||||
#include "gsettingsbackendinternal.h"
|
||||
#include "giomodule-priv.h"
|
||||
|
||||
#include <glibintl.h>
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
//#define TRACE
|
||||
@ -154,17 +155,22 @@ typedef struct
|
||||
HANDLE message_sent_event, message_received_event;
|
||||
} WatchThreadState;
|
||||
|
||||
#define G_TYPE_REGISTRY_BACKEND (g_registry_backend_get_type ())
|
||||
#define G_REGISTRY_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
|
||||
G_TYPE_REGISTRY_BACKEND, GRegistryBackend))
|
||||
#define G_IS_REGISTRY_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
|
||||
G_TYPE_REGISTRY_BACKEND))
|
||||
#define G_TYPE_REGISTRY_SETTINGS_BACKEND (g_registry_settings_backend_get_type ())
|
||||
#define G_REGISTRY_SETTINGS_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
|
||||
G_TYPE_REGISTRY_SETTINGS_BACKEND, GRegistrySettingsBackend))
|
||||
#define G_IS_REGISTRY_SETTINGS_BACKEND(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
|
||||
G_TYPE_REGISTRY_SETTINGS_BACKEND))
|
||||
|
||||
typedef GSettingsBackendClass GRegistryBackendClass;
|
||||
typedef enum {
|
||||
PROP_REGISTRY_KEY = 1,
|
||||
} GRegistrySettingsBackendProperty;
|
||||
|
||||
typedef GSettingsBackendClass GRegistrySettingsBackendClass;
|
||||
|
||||
typedef struct {
|
||||
GSettingsBackend parent_instance;
|
||||
|
||||
HKEY base_key;
|
||||
gchar *base_path;
|
||||
gunichar2 *base_pathw;
|
||||
|
||||
@ -174,10 +180,10 @@ typedef struct {
|
||||
GNode *cache_root;
|
||||
|
||||
WatchThreadState *watch;
|
||||
} GRegistryBackend;
|
||||
} GRegistrySettingsBackend;
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GRegistryBackend,
|
||||
g_registry_backend,
|
||||
G_DEFINE_TYPE_WITH_CODE (GRegistrySettingsBackend,
|
||||
g_registry_settings_backend,
|
||||
G_TYPE_SETTINGS_BACKEND,
|
||||
_g_io_modules_ensure_extension_points_registered ();
|
||||
g_io_extension_point_implement (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
|
||||
@ -231,8 +237,8 @@ g_message_win32_error (DWORD result_code,
|
||||
g_free (win32_message);
|
||||
}
|
||||
|
||||
/* Make gsettings key into a registry path & value pair.
|
||||
*
|
||||
/* Make gsettings key into a registry path & value pair.
|
||||
*
|
||||
* Note that the return value *only* needs freeing - registry_value_name
|
||||
* is a pointer to further inside the same block of memory.
|
||||
*/
|
||||
@ -319,6 +325,59 @@ handle_read_error (LONG result,
|
||||
path_name, value_name);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
HKEY handle;
|
||||
const char *name;
|
||||
} HandleNamePair;
|
||||
|
||||
static const HandleNamePair predefined_key_names[] = {
|
||||
{ HKEY_CLASSES_ROOT, "HKEY_CLASSES_ROOT" },
|
||||
{ HKEY_CURRENT_CONFIG, "HKEY_CURRENT_CONFIG" },
|
||||
{ HKEY_CURRENT_USER, "HKEY_CURRENT_USER" },
|
||||
{ HKEY_LOCAL_MACHINE, "HKEY_LOCAL_MACHINE" },
|
||||
{ HKEY_USERS, "HKEY_USERS" }
|
||||
};
|
||||
|
||||
static const gchar*
|
||||
predefined_key_to_string (HKEY key)
|
||||
{
|
||||
for (gsize i = 0; i < G_N_ELEMENTS (predefined_key_names); i++)
|
||||
{
|
||||
if (predefined_key_names[i].handle == key)
|
||||
return predefined_key_names[i].name;
|
||||
}
|
||||
|
||||
g_warning ("gregistrysettingsbackend: unexpected root key (%p)", key);
|
||||
return "";
|
||||
}
|
||||
|
||||
static const gchar*
|
||||
split_registry_path (const gchar *full_path,
|
||||
HKEY *root_key)
|
||||
{
|
||||
g_assert (full_path != NULL);
|
||||
|
||||
for (gsize i = 0; i < G_N_ELEMENTS (predefined_key_names); i++)
|
||||
{
|
||||
const gchar *root_name = predefined_key_names[i].name;
|
||||
|
||||
if (g_str_has_prefix (full_path, root_name))
|
||||
{
|
||||
const gchar *rest = full_path + strlen (root_name);
|
||||
|
||||
if (*rest == '\\')
|
||||
{
|
||||
if (root_key != NULL)
|
||||
*root_key = predefined_key_names[i].handle;
|
||||
|
||||
return ++rest;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
* Cache of registry values
|
||||
***************************************************************************/
|
||||
@ -381,7 +440,7 @@ typedef struct
|
||||
/* Number of times g_settings_subscribe has been called for this location
|
||||
* (I guess you can't subscribe more than 16383 times) */
|
||||
gint32 subscription_count : 14;
|
||||
|
||||
|
||||
gint32 ref_count : 9;
|
||||
|
||||
gint32 readable : 1;
|
||||
@ -693,7 +752,7 @@ registry_cache_update_node (GNode *cache_node,
|
||||
cache_item->value = registry_value;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
switch (registry_value.type)
|
||||
{
|
||||
case REG_DWORD:
|
||||
@ -742,7 +801,7 @@ registry_cache_update_node (GNode *cache_node,
|
||||
}
|
||||
}
|
||||
default:
|
||||
g_warning ("gregistrybackend: registry_cache_update_node: Unhandled value type");
|
||||
g_warning ("gregistrysettingsbackend: registry_cache_update_node: Unhandled value type");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
@ -838,12 +897,12 @@ registry_read (HKEY hpath,
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
g_registry_backend_read (GSettingsBackend *backend,
|
||||
const gchar *key_name,
|
||||
const GVariantType *expected_type,
|
||||
gboolean default_value)
|
||||
g_registry_settings_backend_read (GSettingsBackend *backend,
|
||||
const gchar *key_name,
|
||||
const GVariantType *expected_type,
|
||||
gboolean default_value)
|
||||
{
|
||||
GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
|
||||
GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
|
||||
GNode *cache_node;
|
||||
RegistryValue registry_value;
|
||||
GVariant *gsettings_value = NULL;
|
||||
@ -924,16 +983,16 @@ g_registry_backend_read (GSettingsBackend *backend,
|
||||
|
||||
typedef struct
|
||||
{
|
||||
GRegistryBackend *self;
|
||||
GRegistrySettingsBackend *self;
|
||||
HKEY hroot;
|
||||
} RegistryWrite;
|
||||
|
||||
static gboolean
|
||||
g_registry_backend_write_one (const char *key_name,
|
||||
GVariant *variant,
|
||||
gpointer user_data)
|
||||
g_registry_settings_backend_write_one (const char *key_name,
|
||||
GVariant *variant,
|
||||
gpointer user_data)
|
||||
{
|
||||
GRegistryBackend *self;
|
||||
GRegistrySettingsBackend *self;
|
||||
RegistryWrite *action;
|
||||
RegistryValue value;
|
||||
HKEY hroot;
|
||||
@ -952,7 +1011,7 @@ g_registry_backend_write_one (const char *key_name,
|
||||
|
||||
type_string = g_variant_get_type_string (variant);
|
||||
action = user_data;
|
||||
self = G_REGISTRY_BACKEND (action->self);
|
||||
self = G_REGISTRY_SETTINGS_BACKEND (action->self);
|
||||
hroot = action->hroot;
|
||||
|
||||
value.type = REG_NONE;
|
||||
@ -1002,7 +1061,7 @@ g_registry_backend_write_one (const char *key_name,
|
||||
|
||||
/* First update the cache, because the value may not have changed and we can
|
||||
* save a write.
|
||||
*
|
||||
*
|
||||
* If 'value' has changed then its memory will not be freed by update_node(),
|
||||
* because it will be stored in the node.
|
||||
*/
|
||||
@ -1030,7 +1089,7 @@ g_registry_backend_write_one (const char *key_name,
|
||||
result = RegCreateKeyExW (hroot, path_namew, 0, NULL, 0, KEY_WRITE, NULL, &hpath, NULL);
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
g_message_win32_error (result, "gregistrybackend: opening key %s failed",
|
||||
g_message_win32_error (result, "gregistrysettingsbackend: opening key %s failed",
|
||||
path_name + 1);
|
||||
registry_value_free (value);
|
||||
g_free (path_namew);
|
||||
@ -1065,7 +1124,8 @@ g_registry_backend_write_one (const char *key_name,
|
||||
result = RegSetValueExW (hpath, value_namew, 0, value.type, value_data, value_data_size);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
g_message_win32_error (result, "gregistrybackend: setting value %s\\%s\\%s failed.\n",
|
||||
g_message_win32_error (result, "gregistrysettingsbackend: setting value %s\\%s\\%s\\%s failed.\n",
|
||||
predefined_key_to_string (self->base_key),
|
||||
self->base_path, path_name, value_name);
|
||||
|
||||
/* If the write fails then it will seem like the value has changed until the
|
||||
@ -1081,32 +1141,34 @@ g_registry_backend_write_one (const char *key_name,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* The dconf write policy is to do the write while making out it succeeded,
|
||||
/* The dconf write policy is to do the write while making out it succeeded,
|
||||
* and then backtrack if it didn't. The registry functions are synchronous so
|
||||
* we can't do that. */
|
||||
|
||||
static gboolean
|
||||
g_registry_backend_write (GSettingsBackend *backend,
|
||||
const gchar *key_name,
|
||||
GVariant *value,
|
||||
gpointer origin_tag)
|
||||
g_registry_settings_backend_write (GSettingsBackend *backend,
|
||||
const gchar *key_name,
|
||||
GVariant *value,
|
||||
gpointer origin_tag)
|
||||
{
|
||||
GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
|
||||
GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
|
||||
LONG result;
|
||||
HKEY hroot;
|
||||
RegistryWrite action;
|
||||
|
||||
result = RegCreateKeyExW (HKEY_CURRENT_USER, self->base_pathw, 0, NULL, 0,
|
||||
result = RegCreateKeyExW (self->base_key, self->base_pathw, 0, NULL, 0,
|
||||
KEY_WRITE, NULL, &hroot, NULL);
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
trace ("Error opening/creating key %s.\n", self->base_path);
|
||||
trace ("Error opening/creating key %s\\%s.\n",
|
||||
predefined_key_to_string (self->base_key),
|
||||
self->base_path);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
action.self = self;
|
||||
action.hroot = hroot;
|
||||
g_registry_backend_write_one (key_name, value, &action);
|
||||
g_registry_settings_backend_write_one (key_name, value, &action);
|
||||
g_settings_backend_changed (backend, key_name, origin_tag);
|
||||
|
||||
RegCloseKey (hroot);
|
||||
@ -1115,26 +1177,28 @@ g_registry_backend_write (GSettingsBackend *backend,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
g_registry_backend_write_tree (GSettingsBackend *backend,
|
||||
GTree *values,
|
||||
gpointer origin_tag)
|
||||
g_registry_settings_backend_write_tree (GSettingsBackend *backend,
|
||||
GTree *values,
|
||||
gpointer origin_tag)
|
||||
{
|
||||
GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
|
||||
GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
|
||||
LONG result;
|
||||
HKEY hroot;
|
||||
RegistryWrite action;
|
||||
|
||||
result = RegCreateKeyExW (HKEY_CURRENT_USER, self->base_pathw, 0, NULL, 0,
|
||||
result = RegCreateKeyExW (self->base_key, self->base_pathw, 0, NULL, 0,
|
||||
KEY_WRITE, NULL, &hroot, NULL);
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
trace ("Error opening/creating key %s.\n", self->base_path);
|
||||
trace ("Error opening/creating key %s\\%s.\n",
|
||||
predefined_key_to_string (self->base_key),
|
||||
self->base_path);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
action.self = self;
|
||||
action.hroot = hroot;
|
||||
g_tree_foreach (values, (GTraverseFunc)g_registry_backend_write_one,
|
||||
g_tree_foreach (values, (GTraverseFunc)g_registry_settings_backend_write_one,
|
||||
&action);
|
||||
|
||||
g_settings_backend_changed_tree (backend, values, origin_tag);
|
||||
@ -1144,11 +1208,11 @@ g_registry_backend_write_tree (GSettingsBackend *backend,
|
||||
}
|
||||
|
||||
static void
|
||||
g_registry_backend_reset (GSettingsBackend *backend,
|
||||
const gchar *key_name,
|
||||
gpointer origin_tag)
|
||||
g_registry_settings_backend_reset (GSettingsBackend *backend,
|
||||
const gchar *key_name,
|
||||
gpointer origin_tag)
|
||||
{
|
||||
GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
|
||||
GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
|
||||
gchar *path_name;
|
||||
gunichar2 *path_namew;
|
||||
gchar *value_name = NULL;
|
||||
@ -1168,12 +1232,14 @@ g_registry_backend_reset (GSettingsBackend *backend,
|
||||
path_name = parse_key (key_name, self->base_path, &value_name);
|
||||
path_namew = g_utf8_to_utf16 (path_name, -1, NULL, NULL, NULL);
|
||||
|
||||
result = RegOpenKeyExW (HKEY_CURRENT_USER, path_namew, 0, KEY_SET_VALUE, &hpath);
|
||||
result = RegOpenKeyExW (self->base_key, path_namew, 0, KEY_SET_VALUE, &hpath);
|
||||
g_free (path_namew);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
g_message_win32_error (result, "Registry: resetting key '%s'", path_name);
|
||||
g_message_win32_error (result, "Registry: resetting key '%s\\%s'",
|
||||
predefined_key_to_string (self->base_key),
|
||||
path_name);
|
||||
g_free (path_name);
|
||||
return;
|
||||
}
|
||||
@ -1186,7 +1252,9 @@ g_registry_backend_reset (GSettingsBackend *backend,
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
g_message_win32_error (result, "Registry: resetting key '%s'", path_name);
|
||||
g_message_win32_error (result, "Registry: resetting key '%s\\%s'",
|
||||
predefined_key_to_string (self->base_key),
|
||||
path_name);
|
||||
g_free (path_name);
|
||||
return;
|
||||
}
|
||||
@ -1197,10 +1265,10 @@ g_registry_backend_reset (GSettingsBackend *backend,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
g_registry_backend_get_writable (GSettingsBackend *backend,
|
||||
const gchar *key_name)
|
||||
g_registry_settings_backend_get_writable (GSettingsBackend *backend,
|
||||
const gchar *key_name)
|
||||
{
|
||||
GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
|
||||
GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
|
||||
gchar *path_name;
|
||||
gunichar2 *path_namew;
|
||||
gchar *value_name = NULL;
|
||||
@ -1214,13 +1282,14 @@ g_registry_backend_get_writable (GSettingsBackend *backend,
|
||||
* of a problem since at the end of the day we have to create it anyway
|
||||
* to read or to write from it
|
||||
*/
|
||||
result = RegCreateKeyExW (HKEY_CURRENT_USER, path_namew, 0, NULL, 0,
|
||||
result = RegCreateKeyExW (self->base_key, path_namew, 0, NULL, 0,
|
||||
KEY_WRITE, NULL, &hpath, NULL);
|
||||
g_free (path_namew);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
trace ("Error opening/creating key to check writability: %s.\n",
|
||||
trace ("Error opening/creating key to check writability: %s\\%s.\n",
|
||||
predefined_key_to_string (self->base_key),
|
||||
path_name);
|
||||
g_free (path_name);
|
||||
|
||||
@ -1291,7 +1360,7 @@ registry_cache_destroy_tree (GNode *node,
|
||||
/* One of these is sent down the pipe when something happens in the registry. */
|
||||
typedef struct
|
||||
{
|
||||
GRegistryBackend *self;
|
||||
GRegistrySettingsBackend *self;
|
||||
gchar *prefix; /* prefix is a gsettings path, all items are subkeys of this. */
|
||||
GPtrArray *items; /* each item is a subkey below prefix that has changed. */
|
||||
} RegistryEvent;
|
||||
@ -1348,9 +1417,9 @@ registry_cache_remove_deleted (GNode *node,
|
||||
}
|
||||
|
||||
/* Update cache from registry, and optionally report on the changes.
|
||||
*
|
||||
*
|
||||
* This function is sometimes called from the watch thread, with no locking. It
|
||||
* does call g_registry_backend functions, but this is okay because they only
|
||||
* does call g_registry_settings_backend functions, but this is okay because they only
|
||||
* access self->base which is constant.
|
||||
*
|
||||
* When looking at this code bear in mind the terminology: in the registry, keys
|
||||
@ -1362,13 +1431,13 @@ registry_cache_remove_deleted (GNode *node,
|
||||
* there are notifications that are watching them.
|
||||
*/
|
||||
static void
|
||||
registry_cache_update (GRegistryBackend *self,
|
||||
HKEY hpath,
|
||||
const gchar *prefix,
|
||||
const gchar *partial_key_name,
|
||||
GNode *cache_node,
|
||||
int n_watches,
|
||||
RegistryEvent *event)
|
||||
registry_cache_update (GRegistrySettingsBackend *self,
|
||||
HKEY hpath,
|
||||
const gchar *prefix,
|
||||
const gchar *partial_key_name,
|
||||
GNode *cache_node,
|
||||
int n_watches,
|
||||
RegistryEvent *event)
|
||||
{
|
||||
gunichar2 bufferw[MAX_KEY_NAME_LENGTH + 1];
|
||||
gchar *buffer;
|
||||
@ -1439,7 +1508,7 @@ registry_cache_update (GRegistryBackend *self,
|
||||
}
|
||||
|
||||
if (result != ERROR_NO_MORE_ITEMS)
|
||||
g_message_win32_error (result, "gregistrybackend: error enumerating subkeys for cache.");
|
||||
g_message_win32_error (result, "gregistrysettingsbackend: error enumerating subkeys for cache.");
|
||||
|
||||
/* Enumerate each value at 'path' and check if it has changed */
|
||||
i = 0;
|
||||
@ -1512,7 +1581,7 @@ registry_cache_update (GRegistryBackend *self,
|
||||
}
|
||||
|
||||
if (result != ERROR_NO_MORE_ITEMS)
|
||||
g_message_win32_error (result, "gregistrybackend: error enumerating values for cache");
|
||||
g_message_win32_error (result, "gregistrysettingsbackend: error enumerating values for cache");
|
||||
|
||||
/* Any nodes now left unreadable must have been deleted, remove them from cache */
|
||||
g_node_children_foreach (cache_node, G_TRAVERSE_ALL,
|
||||
@ -1572,7 +1641,7 @@ _free_watch (WatchThreadState *self,
|
||||
prefix = g_ptr_array_index (self->prefixes, index);
|
||||
|
||||
trace ("Freeing watch %i [%s]\n", index, prefix);
|
||||
|
||||
|
||||
/* These can be NULL if the watch was already dead, this can happen when eg.
|
||||
* a key is deleted but GSettings is still subscribed to it - the watch is
|
||||
* kept alive so that the unsubscribe function works properly, but does not
|
||||
@ -1583,7 +1652,7 @@ _free_watch (WatchThreadState *self,
|
||||
|
||||
if (cache_node != NULL)
|
||||
{
|
||||
//registry_cache_dump (G_REGISTRY_BACKEND (self->owner)->cache_root, NULL);
|
||||
//registry_cache_dump (G_REGISTRY_SETTINGS_BACKEND (self->owner)->cache_root, NULL);
|
||||
registry_cache_unref_tree (cache_node);
|
||||
}
|
||||
|
||||
@ -1803,14 +1872,14 @@ watch_thread_function (LPVOID parameter)
|
||||
* likely to block (only when changing notification subscriptions).
|
||||
*/
|
||||
event = g_slice_new (RegistryEvent);
|
||||
event->self = G_REGISTRY_BACKEND (g_object_ref (self->owner));
|
||||
event->self = G_REGISTRY_SETTINGS_BACKEND (g_object_ref (self->owner));
|
||||
event->prefix = g_strdup (prefix);
|
||||
event->items = g_ptr_array_new_with_free_func (g_free);
|
||||
|
||||
EnterCriticalSection (G_REGISTRY_BACKEND (self->owner)->cache_lock);
|
||||
registry_cache_update (G_REGISTRY_BACKEND (self->owner), hpath,
|
||||
EnterCriticalSection (G_REGISTRY_SETTINGS_BACKEND (self->owner)->cache_lock);
|
||||
registry_cache_update (G_REGISTRY_SETTINGS_BACKEND (self->owner), hpath,
|
||||
prefix, NULL, cache_node, 0, event);
|
||||
LeaveCriticalSection (G_REGISTRY_BACKEND (self->owner)->cache_lock);
|
||||
LeaveCriticalSection (G_REGISTRY_SETTINGS_BACKEND (self->owner)->cache_lock);
|
||||
|
||||
if (event->items->len > 0)
|
||||
g_idle_add ((GSourceFunc) watch_handler, event);
|
||||
@ -1833,7 +1902,7 @@ watch_thread_function (LPVOID parameter)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
watch_start (GRegistryBackend *self)
|
||||
watch_start (GRegistrySettingsBackend *self)
|
||||
{
|
||||
WatchThreadState *watch;
|
||||
|
||||
@ -1850,7 +1919,7 @@ watch_start (GRegistryBackend *self)
|
||||
watch->message_received_event = CreateEvent (NULL, FALSE, FALSE, NULL);
|
||||
if (watch->message_sent_event == NULL || watch->message_received_event == NULL)
|
||||
{
|
||||
g_message_win32_error (GetLastError (), "gregistrybackend: Failed to create sync objects.");
|
||||
g_message_win32_error (GetLastError (), "gregistrysettingsbackend: Failed to create sync objects.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -1858,7 +1927,7 @@ watch_start (GRegistryBackend *self)
|
||||
watch->thread = CreateThread (NULL, 1024, watch_thread_function, watch, 0, NULL);
|
||||
if (watch->thread == NULL)
|
||||
{
|
||||
g_message_win32_error (GetLastError (), "gregistrybackend: Failed to create notify watch thread.");
|
||||
g_message_win32_error (GetLastError (), "gregistrysettingsbackend: Failed to create notify watch thread.");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
@ -1880,7 +1949,7 @@ fail:
|
||||
|
||||
/* This function assumes you hold the message lock! */
|
||||
static void
|
||||
watch_stop_unlocked (GRegistryBackend *self)
|
||||
watch_stop_unlocked (GRegistrySettingsBackend *self)
|
||||
{
|
||||
WatchThreadState *watch = self->watch;
|
||||
DWORD result;
|
||||
@ -1897,7 +1966,7 @@ watch_stop_unlocked (GRegistryBackend *self)
|
||||
result = WaitForSingleObject (watch->message_received_event, INFINITE);
|
||||
if (result != WAIT_OBJECT_0)
|
||||
{
|
||||
g_warning ("gregistrybackend: unable to stop watch thread.");
|
||||
g_warning ("gregistrysettingsbackend: unable to stop watch thread.");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1914,10 +1983,10 @@ watch_stop_unlocked (GRegistryBackend *self)
|
||||
}
|
||||
|
||||
static gboolean
|
||||
watch_add_notify (GRegistryBackend *self,
|
||||
HANDLE event,
|
||||
HKEY hpath,
|
||||
gchar *gsettings_prefix)
|
||||
watch_add_notify (GRegistrySettingsBackend *self,
|
||||
HANDLE event,
|
||||
HKEY hpath,
|
||||
gchar *gsettings_prefix)
|
||||
{
|
||||
WatchThreadState *watch = self->watch;
|
||||
GNode *cache_node;
|
||||
@ -1942,7 +2011,7 @@ watch_add_notify (GRegistryBackend *self,
|
||||
g_warn_if_reached ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
cache_item = cache_node->data;
|
||||
|
||||
cache_item->subscription_count++;
|
||||
@ -1987,8 +2056,8 @@ watch_add_notify (GRegistryBackend *self,
|
||||
}
|
||||
|
||||
static void
|
||||
watch_remove_notify (GRegistryBackend *self,
|
||||
const gchar *key_name)
|
||||
watch_remove_notify (GRegistrySettingsBackend *self,
|
||||
const gchar *key_name)
|
||||
{
|
||||
WatchThreadState *watch = self->watch;
|
||||
LONG result;
|
||||
@ -2025,10 +2094,10 @@ watch_remove_notify (GRegistryBackend *self,
|
||||
* key. Our job is easier because keys and values are separate.
|
||||
*/
|
||||
static void
|
||||
g_registry_backend_subscribe (GSettingsBackend *backend,
|
||||
const char *key_name)
|
||||
g_registry_settings_backend_subscribe (GSettingsBackend *backend,
|
||||
const char *key_name)
|
||||
{
|
||||
GRegistryBackend *self = G_REGISTRY_BACKEND (backend);
|
||||
GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (backend);
|
||||
gchar *path_name;
|
||||
gunichar2 *path_namew;
|
||||
gchar *value_name = NULL;
|
||||
@ -2062,13 +2131,13 @@ g_registry_backend_subscribe (GSettingsBackend *backend,
|
||||
|
||||
/* Give the caller the benefit of the doubt if the key doesn't exist and create it. The caller
|
||||
* is almost certainly a new g_settings with this path as base path. */
|
||||
result = RegCreateKeyExW (HKEY_CURRENT_USER, path_namew, 0, NULL, 0, KEY_READ, NULL, &hpath,
|
||||
result = RegCreateKeyExW (self->base_key, path_namew, 0, NULL, 0, KEY_READ, NULL, &hpath,
|
||||
NULL);
|
||||
g_free (path_namew);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
{
|
||||
g_message_win32_error (result, "gregistrybackend: Unable to subscribe to key %s.", key_name);
|
||||
g_message_win32_error (result, "gregistrysettingsbackend: Unable to subscribe to key %s.", key_name);
|
||||
g_atomic_int_inc (&self->watch->watches_remaining);
|
||||
return;
|
||||
}
|
||||
@ -2076,7 +2145,7 @@ g_registry_backend_subscribe (GSettingsBackend *backend,
|
||||
event = CreateEvent (NULL, FALSE, FALSE, NULL);
|
||||
if (event == NULL)
|
||||
{
|
||||
g_message_win32_error (result, "gregistrybackend: CreateEvent failed.");
|
||||
g_message_win32_error (result, "gregistrysettingsbackend: CreateEvent failed.");
|
||||
g_atomic_int_inc (&self->watch->watches_remaining);
|
||||
RegCloseKey (hpath);
|
||||
return;
|
||||
@ -2093,12 +2162,12 @@ g_registry_backend_subscribe (GSettingsBackend *backend,
|
||||
}
|
||||
|
||||
static void
|
||||
g_registry_backend_unsubscribe (GSettingsBackend *backend,
|
||||
const char *key_name)
|
||||
g_registry_settings_backend_unsubscribe (GSettingsBackend *backend,
|
||||
const char *key_name)
|
||||
{
|
||||
trace ("unsubscribe: %s.\n", key_name);
|
||||
|
||||
watch_remove_notify (G_REGISTRY_BACKEND (backend), key_name);
|
||||
watch_remove_notify (G_REGISTRY_SETTINGS_BACKEND (backend), key_name);
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
@ -2106,9 +2175,9 @@ g_registry_backend_unsubscribe (GSettingsBackend *backend,
|
||||
********************************************************************************/
|
||||
|
||||
static void
|
||||
g_registry_backend_finalize (GObject *object)
|
||||
g_registry_settings_backend_finalize (GObject *object)
|
||||
{
|
||||
GRegistryBackend *self = G_REGISTRY_BACKEND (object);
|
||||
GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
|
||||
RegistryCacheItem *item;
|
||||
|
||||
item = self->cache_root->data;
|
||||
@ -2131,30 +2200,137 @@ g_registry_backend_finalize (GObject *object)
|
||||
}
|
||||
|
||||
static void
|
||||
g_registry_backend_class_init (GRegistryBackendClass *class)
|
||||
g_registry_settings_backend_constructed (GObject *object)
|
||||
{
|
||||
GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
|
||||
|
||||
if (self->base_key == NULL || self->base_path == NULL || self->base_pathw == NULL)
|
||||
{
|
||||
self->base_key = HKEY_CURRENT_USER;
|
||||
self->base_path = g_strdup ("Software\\GSettings");
|
||||
self->base_pathw = g_utf8_to_utf16 (self->base_path, -1, NULL, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_registry_settings_backend_get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
|
||||
|
||||
switch ((GRegistrySettingsBackendProperty) prop_id)
|
||||
{
|
||||
case PROP_REGISTRY_KEY:
|
||||
g_value_take_string (value,
|
||||
g_strdup_printf ("%s\\%s",
|
||||
predefined_key_to_string (self->base_key),
|
||||
self->base_path));
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_registry_settings_backend_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
GRegistrySettingsBackend *self = G_REGISTRY_SETTINGS_BACKEND (object);
|
||||
const gchar *reg_path;
|
||||
|
||||
switch ((GRegistrySettingsBackendProperty) prop_id)
|
||||
{
|
||||
case PROP_REGISTRY_KEY:
|
||||
/* Construct only. */
|
||||
g_assert (self->base_key == NULL);
|
||||
g_assert (self->base_path == NULL);
|
||||
g_assert (self->base_pathw == NULL);
|
||||
|
||||
reg_path = g_value_get_string (value);
|
||||
if (reg_path != NULL)
|
||||
{
|
||||
HKEY base_key;
|
||||
const gchar *base_path = split_registry_path (reg_path, &base_key);
|
||||
|
||||
if (base_path != NULL)
|
||||
{
|
||||
gunichar2 *base_pathw = g_utf8_to_utf16 (base_path, -1, NULL, NULL, NULL);
|
||||
|
||||
if (base_pathw != NULL)
|
||||
{
|
||||
self->base_key = g_steal_pointer (&base_key);
|
||||
self->base_path = g_strdup (base_path);
|
||||
self->base_pathw = g_steal_pointer (&base_pathw);
|
||||
}
|
||||
else
|
||||
g_warning ("gregistrysettingsbackend: invalid base registry path '%s'", reg_path);
|
||||
}
|
||||
else
|
||||
g_warning ("gregistrysettingsbackend: base registry path '%s' does not start with a valid root key", reg_path);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
g_registry_settings_backend_class_init (GRegistrySettingsBackendClass *class)
|
||||
{
|
||||
GSettingsBackendClass *backend_class = G_SETTINGS_BACKEND_CLASS (class);
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
object_class->finalize = g_registry_backend_finalize;
|
||||
object_class->finalize = g_registry_settings_backend_finalize;
|
||||
object_class->constructed = g_registry_settings_backend_constructed;
|
||||
object_class->get_property = g_registry_settings_backend_get_property;
|
||||
object_class->set_property = g_registry_settings_backend_set_property;
|
||||
|
||||
backend_class->read = g_registry_backend_read;
|
||||
backend_class->write = g_registry_backend_write;
|
||||
backend_class->write_tree = g_registry_backend_write_tree;
|
||||
backend_class->reset = g_registry_backend_reset;
|
||||
backend_class->get_writable = g_registry_backend_get_writable;
|
||||
backend_class->subscribe = g_registry_backend_subscribe;
|
||||
backend_class->unsubscribe = g_registry_backend_unsubscribe;
|
||||
backend_class->read = g_registry_settings_backend_read;
|
||||
backend_class->write = g_registry_settings_backend_write;
|
||||
backend_class->write_tree = g_registry_settings_backend_write_tree;
|
||||
backend_class->reset = g_registry_settings_backend_reset;
|
||||
backend_class->get_writable = g_registry_settings_backend_get_writable;
|
||||
backend_class->subscribe = g_registry_settings_backend_subscribe;
|
||||
backend_class->unsubscribe = g_registry_settings_backend_unsubscribe;
|
||||
|
||||
/**
|
||||
* GRegistrySettingsBackend:registry-key:
|
||||
*
|
||||
* The location where settings are stored in the registry. Must
|
||||
* start with one of the following:
|
||||
* - `HKEY_CLASSES_ROOT`
|
||||
* - `HKEY_CURRENT_CONFIG`
|
||||
* - `HKEY_CURRENT_USER`
|
||||
* - `HKEY_LOCAL_MACHINE`
|
||||
* - `HKEY_USERS`
|
||||
*
|
||||
* Defaults to `HKEY_CURRENT_USER\Software\GSettings`.
|
||||
*
|
||||
* Since: 2.78
|
||||
*/
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_REGISTRY_KEY,
|
||||
g_param_spec_string ("registry-key",
|
||||
P_("Root registry key"),
|
||||
P_("The path to the registry key where settings are stored"),
|
||||
"HKEY_CURRENT_USER\\Software\\GSettings",
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
}
|
||||
|
||||
static void
|
||||
g_registry_backend_init (GRegistryBackend *self)
|
||||
g_registry_settings_backend_init (GRegistrySettingsBackend *self)
|
||||
{
|
||||
RegistryCacheItem *item;
|
||||
|
||||
self->base_path = g_strdup_printf ("Software\\GSettings");
|
||||
self->base_pathw = g_utf8_to_utf16 (self->base_path, -1, NULL, NULL, NULL);
|
||||
|
||||
item = g_slice_new (RegistryCacheItem);
|
||||
item->value.type = REG_NONE;
|
||||
item->value.ptr = NULL;
|
||||
@ -2167,3 +2343,25 @@ g_registry_backend_init (GRegistryBackend *self)
|
||||
|
||||
self->watch = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* g_registry_settings_backend_new:
|
||||
* @registry_key: (nullable): the path to the registry key where
|
||||
* settings are stored, or %NULL.
|
||||
*
|
||||
* If @registry_key is %NULL then the default path
|
||||
* `HKEY_CURRENT_USER\Software\GSettings` is used.
|
||||
*
|
||||
* Returns: (transfer full): a registry-backed #GSettingsBackend
|
||||
*
|
||||
* Since: 2.78
|
||||
**/
|
||||
GSettingsBackend *
|
||||
g_registry_settings_backend_new (const gchar *registry_key)
|
||||
{
|
||||
g_return_val_if_fail (registry_key == NULL || split_registry_path (registry_key, NULL), NULL);
|
||||
|
||||
return G_SETTINGS_BACKEND (g_object_new (G_TYPE_REGISTRY_SETTINGS_BACKEND,
|
||||
"registry-key", registry_key,
|
||||
NULL));
|
||||
}
|
||||
|
@ -24,7 +24,9 @@
|
||||
|
||||
#include <glib-object.h>
|
||||
|
||||
GType g_registry_backend_get_type (void);
|
||||
#include <gio/gsettingsbackend.h>
|
||||
|
||||
GIO_AVAILABLE_IN_2_78
|
||||
GSettingsBackend * g_registry_settings_backend_new (const gchar *registry_key);
|
||||
|
||||
#endif /* __G_REGISTRY_SETTINGS_BACKEND_H__ */
|
||||
|
@ -95,4 +95,8 @@ GType g_keyfile_settings_backend_get_type (void);
|
||||
GType g_nextstep_settings_backend_get_type (void);
|
||||
#endif
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
GType g_registry_settings_backend_get_type (void);
|
||||
#endif
|
||||
|
||||
#endif /* __G_SETTINGS_BACKEND_INTERNAL_H__ */
|
||||
|
@ -276,10 +276,6 @@ settings_sources = files(
|
||||
'gsettings.c',
|
||||
)
|
||||
|
||||
if host_system == 'windows'
|
||||
settings_sources += files('gregistrysettingsbackend.c')
|
||||
endif
|
||||
|
||||
application_headers = files(
|
||||
'gapplication.h',
|
||||
'gapplicationcommandline.h',
|
||||
@ -444,6 +440,7 @@ else
|
||||
|
||||
win32_sources += files(
|
||||
'gmemorymonitorwin32.c',
|
||||
'gregistrysettingsbackend.c',
|
||||
'gwin32registrykey.c',
|
||||
'gwin32mount.c',
|
||||
'gwin32volumemonitor.c',
|
||||
@ -467,6 +464,7 @@ else
|
||||
win32_sources += [gio_win_res]
|
||||
|
||||
gio_win32_include_headers = files(
|
||||
'gregistrysettingsbackend.h',
|
||||
'gwin32inputstream.h',
|
||||
'gwin32outputstream.h',
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user