1 /*
2 * lxde-settings.c - XSettings daemon of LXDE
3 *
4 * Copyright 2008 PCMan <pcman.tw@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program 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
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1301, USA.
20 */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <glib.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <sys/types.h>
30 #include <sys/wait.h>
31 #include <sys/stat.h>
32 #include <unistd.h>
33 #include <string.h>
34 #include <locale.h>
35
36 #include "xevent.h"
37 #include "xsettings-manager.h"
38 #include "xutils.h"
39
40 #include <X11/XKBlib.h>
41
42 static XSettingsManager **managers = NULL;
43
44 /* FORWARDS */
45 gboolean settings_daemon_start(GKeyFile* kf);
46 void settings_manager_selection_clear( XEvent* evt );
47 void settings_daemon_reload(GKeyFile* kf);
48 /* End FORWARDS */
49
terminate_cb(void * data)50 static void terminate_cb (void *data)
51 {
52 gboolean *terminated = data;
53
54 if (*terminated)
55 return;
56
57 *terminated = TRUE;
58 exit( 0 );
59 // gtk_main_quit ();
60 }
61
merge_xrdb(const char * content,int len)62 static void merge_xrdb(const char* content, int len)
63 {
64 gchar* argv[] = { "xrdb", "-merge", "-", NULL };
65 GPid pid;
66 int stdi, status, w;
67 if( g_spawn_async_with_pipes(NULL, argv, NULL, G_SPAWN_SEARCH_PATH,
68 NULL, NULL, &pid, &stdi, NULL, NULL, NULL ) )
69 {
70 if (len < 0)
71 {
72 w = write( stdi, content, strlen(content));
73 }
74 else
75 {
76 w = write( stdi, content, len);
77 }
78 close(stdi);
79 waitpid( pid, &status, 0 );
80 }
81 }
82
83
84 /* This function is taken from Gnome's control-center 2.6.0.3 (gnome-settings-mouse.c) and was modified*/
85 #define DEFAULT_PTR_MAP_SIZE 128
set_left_handed_mouse(gboolean mouse_left_handed)86 static void set_left_handed_mouse( gboolean mouse_left_handed )
87 {
88 unsigned char *buttons;
89 gint n_buttons, i;
90 gint idx_1 = 0, idx_3 = 1;
91
92 buttons = g_alloca (DEFAULT_PTR_MAP_SIZE);
93 n_buttons = XGetPointerMapping (dpy, buttons, DEFAULT_PTR_MAP_SIZE);
94 if (n_buttons > DEFAULT_PTR_MAP_SIZE)
95 {
96 buttons = g_alloca (n_buttons);
97 n_buttons = XGetPointerMapping (dpy, buttons, n_buttons);
98 }
99
100 for (i = 0; i < n_buttons; i++)
101 {
102 if (buttons[i] == 1)
103 idx_1 = i;
104 else if (buttons[i] == ((n_buttons < 3) ? 2 : 3))
105 idx_3 = i;
106 }
107
108 if ((mouse_left_handed && idx_1 < idx_3) ||
109 (!mouse_left_handed && idx_1 > idx_3))
110 {
111 buttons[idx_1] = ((n_buttons < 3) ? 2 : 3);
112 buttons[idx_3] = 1;
113 XSetPointerMapping (dpy, buttons, n_buttons);
114 }
115 }
116
configure_input(GKeyFile * kf)117 static void configure_input(GKeyFile* kf)
118 {
119 XKeyboardControl values;
120
121 /* Mouse settings */
122 int accel_factor, accel_threshold, delay, interval;
123 gboolean left_handed, beep;
124
125 accel_factor = g_key_file_get_integer(kf, "Mouse", "AccFactor", NULL);
126 accel_threshold = g_key_file_get_integer(kf, "Mouse", "AccThreshold", NULL);
127 if( accel_factor || accel_threshold )
128 {
129 XChangePointerControl(dpy, accel_factor != 0, accel_threshold != 0,
130 accel_factor, 10, accel_threshold);
131 }
132
133 left_handed = g_key_file_get_integer(kf, "Mouse", "LeftHanded", NULL);
134 set_left_handed_mouse(left_handed);
135
136 /* Keyboard settings */
137 if(XkbGetAutoRepeatRate(dpy, XkbUseCoreKbd, (unsigned int*) &delay, (unsigned int*) &interval))
138 {
139 int val;
140 val = g_key_file_get_integer(kf, "Keyboard", "Delay", NULL);
141 if(val > 0)
142 delay = val;
143 val = g_key_file_get_integer(kf, "Keyboard", "Interval", NULL);
144 if(val > 0)
145 interval = val;
146 if( val > 0 )
147 {
148 XkbSetAutoRepeatRate(dpy, XkbUseCoreKbd, delay, interval);
149 }
150 }
151
152 beep = g_key_file_get_integer(kf, "Keyboard", "Beep", NULL);
153 values.bell_percent = beep ? -1 : 0;
154 XChangeKeyboardControl(dpy, KBBellPercent, &values);
155 }
156
load_settings(GKeyFile * kf)157 static void load_settings( GKeyFile* kf )
158 {
159 GString* buf;
160 char* str;
161 int val;
162
163 int i;
164 const char group[] = "GTK";
165 char** keys, **key;
166
167 /* Mouse cursor (does this work?) */
168 str = g_key_file_get_string( kf, group, "sGtk/CursorThemeName", NULL);
169 val = g_key_file_get_integer(kf, group, "iGtk/CursorThemeSize", NULL);
170 if(str || val > 0)
171 {
172 buf = g_string_sized_new(100);
173 if(str)
174 {
175 if(*str)
176 g_string_append_printf(buf, "Xcursor.theme:%s\n", str);
177 g_free(str);
178 }
179 g_string_append(buf, "Xcursor.theme_core:true\n");
180 if(val > 0)
181 g_string_append_printf(buf, "Xcursor.size:%d\n", val);
182 merge_xrdb( buf->str, buf->len );
183 g_string_free(buf, TRUE);
184 }
185
186 /* Load mouse and keyboard settings */
187 configure_input(kf);
188
189 /* Load GTK+ settings */
190 if ( (keys = g_key_file_get_keys( kf, group, NULL, NULL )) == NULL )
191 return;
192
193 for( key = keys; *key; ++key )
194 {
195 const char* name = *key + 1;
196
197 switch( **key )
198 {
199 case 's': /* string */
200 {
201 str = g_key_file_get_string( kf, group, *key, NULL );
202 if( str )
203 {
204 for( i = 0; managers[i]; ++i )
205 xsettings_manager_set_string( managers [i], name, str );
206 g_free( str );
207 }
208 else
209 {
210 for( i = 0; managers[i]; ++i )
211 xsettings_manager_delete_setting( managers[i], name );
212 }
213 break;
214 }
215 case 'i': /* integer */
216 {
217 val = g_key_file_get_integer( kf, group, *key, NULL );
218 for( i = 0; managers[i]; ++i )
219 xsettings_manager_set_int( managers [i], name, val );
220 break;
221 }
222 case 'c': /* color */
223 {
224 gsize len = 0;
225 int* vals = g_key_file_get_integer_list( kf, group, *key, &len, NULL );
226 if( vals && len >= 3 )
227 {
228 XSettingsColor color;
229 color.red = (gushort)vals[0];
230 color.green = (gushort)vals[1];
231 color.blue = (gushort)vals[2];
232 color.alpha = (gushort)( len >3 ? vals[3] : 65535 );
233 for( i = 0; managers[i]; ++i )
234 xsettings_manager_set_color( managers [i], name, &color );
235 }
236 else
237 {
238 for( i = 0; managers[i]; ++i )
239 xsettings_manager_delete_setting( managers[i], name );
240 }
241 g_free( vals );
242 break;
243 }
244 }
245 }
246
247 for( i = 0; managers[i]; ++i )
248 xsettings_manager_notify( managers [i] );
249 }
250
create_xsettings_managers()251 static gboolean create_xsettings_managers()
252 {
253 int n_screens = ScreenCount(dpy);
254 int i;
255 gboolean terminated = FALSE;
256
257 if (xsettings_manager_check_running( dpy, n_screens) )
258 {
259 g_error ("You can only run one xsettings manager at a time; exiting\n");
260 return FALSE;
261 }
262
263 managers = g_new (XSettingsManager *, n_screens + 1);
264 for( i = 0; i < n_screens; ++i )
265 {
266 Screen *screen;
267 screen = ScreenOfDisplay( dpy, i );
268 managers [i] = xsettings_manager_new ( dpy, i, terminate_cb, &terminated);
269 if(!managers [i])
270 {
271 g_error("Could not create xsettings manager for screen %d!\n", i);
272 return FALSE;
273 }
274 XSelectInput( dpy, RootWindow(dpy, i), SubstructureNotifyMask | PropertyChangeMask );
275 }
276 managers [i] = NULL;
277
278 return TRUE;
279 }
280
settings_daemon_start(GKeyFile * kf)281 gboolean settings_daemon_start(GKeyFile* kf)
282 {
283 /* initialize X-related stuff and connect to X Display */
284 if( G_UNLIKELY(! xevent_init() ) )
285 return FALSE;
286
287 if( ! create_xsettings_managers() )
288 return FALSE;
289
290 load_settings(kf);
291
292 /* sync with X11 to prevent some racing conditions:
293 * For example: if gtk+ applications are started before
294 * XSETTINGS properties are properly set on root window,
295 * they cannot correctly use settings from Xsettings daemon. */
296 XSync(dpy, FALSE);
297
298 return TRUE;
299 }
300
settings_manager_selection_clear(XEvent * evt)301 void settings_manager_selection_clear( XEvent* evt )
302 {
303 XSettingsManager**mgr;
304 for( mgr = managers; *mgr; ++mgr )
305 {
306 if( xsettings_manager_get_window( *mgr ) == evt->xany.window )
307 xsettings_manager_process_event( *mgr, evt );
308 }
309 }
310
settings_daemon_reload(GKeyFile * kf)311 void settings_daemon_reload(GKeyFile* kf)
312 {
313 if(kf)
314 {
315 load_settings(kf);
316 }
317 }
318