1 /*******************************************************************************
2 * pxgsettings - A helper binary to query gsettings
3 * Copyright (C) 2006 Nathaniel McCallum <nathaniel@natemccallum.com>
4 * Copyright (C) 2011 Dominique Leuenberger <dominique@leuenberger.net>
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, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 ******************************************************************************/
20
21 #include <cstdio>
22 #include <unistd.h>
23 #include <signal.h>
24 #include <stdexcept>
25
26 #include <glib.h>
27 #include <glib-object.h>
28 #include <gio/gio.h>
29
30 using namespace std;
31
32 static GMainLoop* loop = NULL;
33
print_value(GVariant * value,const char * suffix)34 static int print_value(GVariant *value, const char *suffix) {
35
36 if (!value) return 0;
37 if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
38 return printf("%s%s", g_variant_get_string(value, NULL), suffix);
39 }
40 else if(g_variant_is_of_type(value, G_VARIANT_TYPE_INT32)) {
41 return printf("%d%s", g_variant_get_int32(value), suffix);
42 }
43 else if(g_variant_is_of_type(value, G_VARIANT_TYPE_BOOLEAN)) {
44 gboolean result;
45 result = g_variant_get_boolean(value);
46 return printf("%s%s", result ? "true" : "false", suffix);
47 }
48 else if(g_variant_is_of_type(value, G_VARIANT_TYPE_ARRAY)) {
49 int count;
50 const gchar** items;
51 items = g_variant_get_strv(value, NULL);
52 for (count=0; items[count]; count++) {
53 printf("%s%s", count < 1 ? "" : ",", items[count]);
54 }
55 printf("%s", suffix);
56 return count;
57 }
58 else {
59 throw exception();
60 }
61
62 return 0;
63 }
64
on_value_change(GSettings * settings,const gchar * key,gpointer user_data)65 static void on_value_change(GSettings *settings, const gchar *key, gpointer user_data) {
66 printf("%s/%s\t", (gchar *)user_data, key);
67 print_value(g_settings_get_value(settings, key), "\n");
68 }
69
on_sig(int)70 static void on_sig(int /*signal*/) {
71 g_main_loop_quit(loop);
72 }
73
err(GIOChannel *,GIOCondition,gpointer)74 static gboolean err(GIOChannel* /*source*/, GIOCondition /*condition*/, gpointer /*data*/) {
75 g_main_loop_quit(loop);
76 return false;
77 }
78
in(GIOChannel * source,GIOCondition condition,gpointer data)79 static gboolean in(GIOChannel *source, GIOCondition condition, gpointer data) {
80 gchar *key, *val;
81 GIOStatus st = g_io_channel_read_line(source, &key, NULL, NULL, NULL);
82
83 // Remove the trailing '\n'
84 for (int i=0 ; key && key[i] ; i++)
85 if (key[i] == '\n')
86 key[i] = '\0';
87
88 // If we were successful
89 if (key && st == G_IO_STATUS_NORMAL) {
90 if (!g_strrstr(key, "\t"))
91 goto exit;
92
93 val = g_strrstr(key, "\t") + 1;
94 *(val-1) = '\0';
95
96 g_free(key);
97 return true;
98 }
99 else if (key && st == G_IO_STATUS_AGAIN) {
100 g_free(key);
101 return in(source, condition, data);
102 }
103
104 exit:
105 g_free(key);
106 return err(source, condition, data);
107 }
108
main(int argc,char ** argv)109 int main(int argc, char **argv) {
110 if (argc < 2) return 1;
111
112 // Register sighup handler
113 if (signal(SIGHUP, on_sig) == SIG_ERR || signal(SIGPIPE, on_sig) == SIG_ERR || signal(SIGABRT, on_sig) == SIG_ERR) {
114 fprintf(stderr, "Unable to trap signals!");
115 return 2;
116 }
117
118 // Switch stdout to line buffering
119 if (setvbuf(stdout, NULL, _IOLBF, 0)) {
120 fprintf(stderr, "Unable to switch stdout to line buffering!");
121 return 3;
122 }
123
124 // Switch stdin to line buffering
125 if (setvbuf(stdin, NULL, _IOLBF, 0)) {
126 fprintf(stderr, "Unable to switch stdin to line buffering!");
127 return 4;
128 }
129
130 // Init
131 #if !GLIB_CHECK_VERSION(2,36,0)
132 g_type_init();
133 #endif
134
135 // Get the main loop
136 loop = g_main_loop_new(NULL, false);
137
138 // Setup our GIO Channels
139 GIOChannel* inchan = g_io_channel_unix_new(fileno(stdin));
140 GIOChannel* outchan = g_io_channel_unix_new(fileno(stdout));
141 g_io_add_watch(inchan, G_IO_IN, in, NULL);
142 g_io_add_watch(inchan, G_IO_PRI, in, NULL);
143 g_io_add_watch(inchan, G_IO_ERR, err, NULL);
144 g_io_add_watch(inchan, G_IO_HUP, err, NULL);
145 g_io_add_watch(outchan, G_IO_ERR, err, NULL);
146 g_io_add_watch(outchan, G_IO_HUP, err, NULL);
147
148 // Get GSettings obkecy
149 GSettings* settings;
150
151 for (int i=1; i<argc; i++) {
152 settings = g_settings_new(argv[i]);
153 #if GLIB_CHECK_VERSION(2,46,0)
154 GSettingsSchema *schema;
155 g_object_get (settings, "settings-schema", &schema, NULL);
156 gchar** keys = g_settings_schema_list_keys(schema);
157 g_settings_schema_unref(schema);
158 #else
159 gchar** keys = g_settings_list_keys(settings);
160 #endif
161 g_signal_connect(settings, "changed", G_CALLBACK (on_value_change), argv[i]);
162 for (int j=0; keys[j]; on_value_change(settings, keys[j++],argv[i] ));
163 g_strfreev(keys);
164 }
165
166 // A blank line indicates the end of the initial values
167 printf("\n");
168
169 g_main_loop_run(loop);
170
171 // Cleanup
172 g_object_unref(settings);
173 g_io_channel_shutdown(inchan, FALSE, NULL);
174 g_io_channel_shutdown(outchan, FALSE, NULL);
175 g_io_channel_unref(inchan);
176 g_io_channel_unref(outchan);
177 g_main_loop_unref(loop);
178 }
179