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