Releasing debian version 0.6.3-1.
[debian/lxappearance.git] / src / lxappearance.c
1 /*
2 * lxappearance.c
3 *
4 * Copyright 2010 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 "lxappearance.h"
27
28 #include <gtk/gtk.h>
29 #include <glib/gi18n.h>
30 #include <glib/gstdio.h>
31
32 #include <X11/X.h>
33 #include <X11/Xatom.h>
34 #include <X11/Xlib.h>
35 #include <gdk/gdkx.h>
36 #include <string.h>
37
38 #if ENABLE_DBUS
39 #include <dbus/dbus.h>
40 #endif
41
42 #include "widget-theme.h"
43 #include "color-scheme.h"
44 #include "icon-theme.h"
45 #include "cursor-theme.h"
46 #include "font.h"
47 #include "other.h"
48 #include "plugin.h"
49
50 LXAppearance app = {0};
51
52 Atom lxsession_atom = 0;
53 static const char* lxsession_name = NULL;
54
55 /* Dbus functions Copy from lxsession-logout
56 TODO Create a library fro this ?
57 */
58
59 static gboolean check_lxde_dbus()
60 {
61 #if ENABLE_DBUS
62 DBusError error;
63 dbus_error_init(&error);
64 DBusConnection * connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
65 if (connection == NULL)
66 {
67 g_warning(G_STRLOC ": Failed to connect to the session message bus: %s", error.message);
68 dbus_error_free(&error);
69 return FALSE;
70 }
71
72 dbus_bool_t ret = dbus_bus_name_has_owner(connection,"org.lxde.SessionManager",NULL);
73
74 if (ret == TRUE)
75 {
76 return TRUE;
77 }
78 else
79 {
80 return FALSE;
81 }
82 #else
83 return FALSE;
84 #endif
85 }
86
87 static void check_lxsession()
88 {
89 lxsession_atom = XInternAtom( GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), "_LXSESSION", True );
90 if( lxsession_atom != None )
91 {
92 XGrabServer( GDK_DISPLAY_XDISPLAY(gdk_display_get_default()) );
93 if( XGetSelectionOwner( GDK_DISPLAY_XDISPLAY(gdk_display_get_default()), lxsession_atom ) )
94 {
95 app.use_lxsession = TRUE;
96 lxsession_name = g_getenv("DESKTOP_SESSION");
97 }
98 XUngrabServer( GDK_DISPLAY_XDISPLAY(gdk_display_get_default()) );
99 }
100
101 /* Check Lxsession also with dbus */
102 if (check_lxde_dbus())
103 {
104 app.use_lxsession = TRUE;
105 lxsession_name = g_getenv("DESKTOP_SESSION");
106 }
107
108 }
109
110 static GOptionEntry option_entries[] =
111 {
112 { NULL }
113 };
114
115 static gboolean verify_cursor_theme(GKeyFile *kf, const char *cursor_theme,
116 const char *test)
117 {
118 char *fpath;
119 gboolean ret;
120
121 /* get the inherited theme name. */
122 fpath = g_build_filename(g_get_home_dir(), ".icons", cursor_theme,
123 "index.theme", NULL);
124 ret = g_key_file_load_from_file(kf, fpath, 0, NULL);
125 g_free(fpath);
126
127 if (!ret)
128 {
129 fpath = g_build_filename("icons", cursor_theme, "index.theme", NULL);
130 ret = g_key_file_load_from_data_dirs(kf, fpath, NULL, 0, NULL);
131 g_free(fpath);
132 }
133
134 if (ret)
135 {
136 fpath = g_key_file_get_string(kf, "Icon Theme", "Inherits", NULL);
137 if (fpath == NULL) /* end of chain, success */
138 return TRUE;
139 if (strcmp(fpath, test) == 0) /* recursion */
140 ret = FALSE;
141 else if (!verify_cursor_theme(kf, fpath, test)) /* recursion */
142 ret = FALSE;
143 else /* check recursion against this one too */
144 ret = verify_cursor_theme(kf, fpath, cursor_theme);
145 g_free(fpath);
146 }
147 return ret;
148 }
149
150 static void save_cursor_theme_name()
151 {
152 char* dir_path;
153 GKeyFile* kf;
154
155 if (app.cursor_theme == NULL || strcmp(app.cursor_theme, "default") == 0)
156 return;
157
158 dir_path = g_build_filename(g_get_home_dir(), ".icons/default", NULL);
159 kf = g_key_file_new();
160 /* test if cursor theme isn't recursed and don't use it otherwise */
161 if (!verify_cursor_theme(kf, app.cursor_theme, "default"))
162 {
163 g_free(app.cursor_theme);
164 app.cursor_theme = NULL; /* FIXME: replace with "default"? */
165 /* FIXME: show an error message */
166 }
167 /* SF bug #614: ~/.icons/default may be symlink so remove symlink */
168 else if (g_file_test(dir_path, G_FILE_TEST_IS_SYMLINK) &&
169 g_unlink(dir_path) != 0)
170 {
171 /* FIXME: show an error message */
172 }
173 else if (0 == g_mkdir_with_parents(dir_path, 0700))
174 {
175 char* index_theme = g_build_filename(dir_path, "index.theme", NULL);
176 char* content = g_strdup_printf(
177 "# This file is written by LXAppearance. Do not edit.\n"
178 "[Icon Theme]\n"
179 "Name=Default\n"
180 "Comment=Default Cursor Theme\n"
181 "Inherits=%s\n", app.cursor_theme);
182 g_file_set_contents(index_theme, content, -1, NULL);
183 g_free(content);
184 g_free(index_theme);
185 }
186 g_key_file_free(kf);
187 g_free(dir_path);
188
189 /*
190 dir_path = g_build_filename(g_get_home_dir(), ".Xdefaults", NULL);
191 Xcursor.theme: name
192 Xcursor.size: [size]
193 g_file_set_contents(dir_path, "", -1, NULL);
194 g_free(dir_path);
195 */
196 }
197
198 static void reload_all_programs()
199 {
200 #if GTK_CHECK_VERSION(3, 0, 0)
201
202 /* TODO Port this to something else than gdk_event_send_clientmessage_toall */
203
204 #else
205 GdkEventClient event;
206 event.type = GDK_CLIENT_EVENT;
207 event.send_event = TRUE;
208 event.window = NULL;
209
210 if( app.use_lxsession )
211 {
212 event.message_type = gdk_atom_intern_static_string("_LXSESSION");
213 event.data.b[0] = 0; /* LXS_RELOAD */
214 }
215 else
216 {
217 /* if( icon_only )
218 event.message_type = gdk_atom_intern("_GTK_LOAD_ICONTHEMES", FALSE);
219 */
220 event.message_type = gdk_atom_intern("_GTK_READ_RCFILES", FALSE);
221 }
222 event.data_format = 8;
223 gdk_event_send_clientmessage_toall((GdkEvent *)&event);
224 #endif
225 }
226
227 static void lxappearance_save_gtkrc()
228 {
229 static const char* tb_styles[]={
230 "GTK_TOOLBAR_ICONS",
231 "GTK_TOOLBAR_TEXT",
232 "GTK_TOOLBAR_BOTH",
233 "GTK_TOOLBAR_BOTH_HORIZ"
234 };
235 static const char* tb_icon_sizes[]={
236 "GTK_ICON_SIZE_INVALID",
237 "GTK_ICON_SIZE_MENU",
238 "GTK_ICON_SIZE_SMALL_TOOLBAR",
239 "GTK_ICON_SIZE_LARGE_TOOLBAR",
240 "GTK_ICON_SIZE_BUTTON",
241 "GTK_ICON_SIZE_DND",
242 "GTK_ICON_SIZE_DIALOG"
243 };
244
245 char **gtkrc_files = gtk_rc_get_default_files();
246 char *file_path = NULL;
247 GString* content = g_string_sized_new(512);
248
249 /* check for availability of path via GTK2_RC_FILES */
250 while (gtkrc_files && gtkrc_files[0])
251 {
252 g_debug("checking gtkrc path %s",gtkrc_files[0]);
253 if (g_str_has_prefix(gtkrc_files[0], g_get_home_dir()))
254 break;
255 else
256 gtkrc_files++;
257 }
258 /* if none found then use hardcoded one */
259 if (gtkrc_files == NULL || gtkrc_files[0] == NULL)
260 {
261 g_debug("none found, use hardcoded %s/.gtkrc-2.0",g_get_home_dir());
262 file_path = g_build_filename(g_get_home_dir(), ".gtkrc-2.0", NULL);
263 }
264 g_string_append(content,
265 "# DO NOT EDIT! This file will be overwritten by LXAppearance.\n"
266 "# Any customization should be done in ~/.gtkrc-2.0.mine instead.\n\n");
267
268 /* include ~/.gtkrc-2.0.mine first to be able to apply changes done
269 by LXAppearance if the same settings exist in that file */
270 g_string_append_printf(content,
271 "include \"%s/.gtkrc-2.0.mine\"\n",
272 g_get_home_dir());
273
274 if(app.widget_theme)
275 g_string_append_printf(content,
276 "gtk-theme-name=\"%s\"\n", app.widget_theme);
277 if(app.icon_theme)
278 g_string_append_printf(content,
279 "gtk-icon-theme-name=\"%s\"\n", app.icon_theme);
280 if(app.default_font)
281 g_string_append_printf(content,
282 "gtk-font-name=\"%s\"\n", app.default_font);
283 if(app.cursor_theme)
284 g_string_append_printf(content,
285 "gtk-cursor-theme-name=\"%s\"\n", app.cursor_theme);
286 save_cursor_theme_name();
287
288 g_string_append_printf(content,
289 "gtk-cursor-theme-size=%d\n"
290 "gtk-toolbar-style=%s\n"
291 "gtk-toolbar-icon-size=%s\n"
292 "gtk-button-images=%d\n"
293 "gtk-menu-images=%d\n"
294 #if GTK_CHECK_VERSION(2, 14, 0)
295 "gtk-enable-event-sounds=%d\n"
296 "gtk-enable-input-feedback-sounds=%d\n"
297 #endif
298 "gtk-xft-antialias=%d\n"
299 "gtk-xft-hinting=%d\n"
300
301 , app.cursor_theme_size,
302 tb_styles[app.toolbar_style],
303 tb_icon_sizes[app.toolbar_icon_size],
304 app.button_images ? 1 : 0,
305 app.menu_images ? 1 : 0,
306 #if GTK_CHECK_VERSION(2, 14, 0)
307 app.enable_event_sound ? 1 : 0,
308 app.enable_input_feedback ? 1 : 0,
309 #endif
310 app.enable_antialising ? 1 : 0,
311 app.enable_hinting ? 1 : 0
312 );
313
314 if(app.hinting_style)
315 g_string_append_printf(content,
316 "gtk-xft-hintstyle=\"%s\"\n", app.hinting_style);
317
318 if(app.font_rgba)
319 g_string_append_printf(content,
320 "gtk-xft-rgba=\"%s\"\n", app.font_rgba);
321
322 if(app.modules && app.modules[0])
323 g_string_append_printf(content, "gtk-modules=\"%s\"\n", app.modules);
324
325 #if 0
326 /* unfortunately we cannot set colors without XSETTINGS daemon,
327 themes will override any custom settings in .gtkrc-2.0 file */
328 /* FIXME: we should support other xsettings daemons too */
329 if(app.color_scheme)
330 {
331 char* escaped = g_strescape(app.color_scheme, NULL);
332 g_string_append_printf(content,
333 "gtk-color-scheme=\"%s\"\n",
334 escaped);
335 g_free(escaped);
336 }
337 #endif
338
339 if (file_path)
340 g_file_set_contents(file_path, content->str, content->len, NULL);
341 else
342 g_file_set_contents(gtkrc_files[0], content->str, content->len, NULL);
343
344 /* Save also in GTK3 folder
345 Content shold be different from the gtk2 one
346 */
347 GKeyFile *content_gtk3 = g_key_file_new();
348 char* file_path_gtk3 = g_build_filename(g_get_user_config_dir(), "gtk-3.0", NULL);
349 char* file_path_settings = g_build_filename(file_path_gtk3, "settings.ini", NULL);
350
351 if (!g_file_test(file_path_gtk3, G_FILE_TEST_IS_DIR))
352 {
353 g_mkdir_with_parents(file_path_gtk3, 0755);
354 }
355
356 g_key_file_load_from_file(content_gtk3, file_path_settings, /* ignoring errors */
357 G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS, NULL);
358
359 if(app.widget_theme)
360 g_key_file_set_string(content_gtk3, "Settings",
361 "gtk-theme-name", app.widget_theme);
362 if(app.icon_theme)
363 g_key_file_set_string(content_gtk3, "Settings",
364 "gtk-icon-theme-name", app.icon_theme);
365 if(app.default_font)
366 g_key_file_set_string(content_gtk3, "Settings",
367 "gtk-font-name", app.default_font);
368 if(app.cursor_theme)
369 g_key_file_set_string(content_gtk3, "Settings",
370 "gtk-cursor-theme-name", app.cursor_theme);
371 save_cursor_theme_name();
372
373 g_key_file_set_integer(content_gtk3, "Settings",
374 "gtk-cursor-theme-size", app.cursor_theme_size);
375 g_key_file_set_string(content_gtk3, "Settings",
376 "gtk-toolbar-style", tb_styles[app.toolbar_style]);
377 g_key_file_set_string(content_gtk3, "Settings",
378 "gtk-toolbar-icon-size", tb_icon_sizes[app.toolbar_icon_size]);
379 g_key_file_set_integer(content_gtk3, "Settings",
380 "gtk-button-images", app.button_images ? 1 : 0);
381 g_key_file_set_integer(content_gtk3, "Settings",
382 "gtk-menu-images", app.menu_images ? 1 : 0);
383 #if GTK_CHECK_VERSION(2, 14, 0)
384 g_key_file_set_integer(content_gtk3, "Settings",
385 "gtk-enable-event-sounds", app.enable_event_sound ? 1 : 0);
386 g_key_file_set_integer(content_gtk3, "Settings",
387 "gtk-enable-input-feedback-sounds", app.enable_input_feedback ? 1 : 0);
388 #endif
389 g_key_file_set_integer(content_gtk3, "Settings",
390 "gtk-xft-antialias", app.enable_antialising ? 1 : 0);
391 g_key_file_set_integer(content_gtk3, "Settings",
392 "gtk-xft-hinting", app.enable_hinting ? 1 : 0);
393
394 if(app.hinting_style)
395 g_key_file_set_string(content_gtk3, "Settings",
396 "gtk-xft-hintstyle", app.hinting_style);
397
398 if(app.font_rgba)
399 g_key_file_set_string(content_gtk3, "Settings",
400 "gtk-xft-rgba", app.font_rgba);
401
402 if(app.modules && app.modules[0])
403 g_key_file_set_string(content_gtk3, "Settings", "gtk-modules", app.modules);
404 else
405 g_key_file_remove_key(content_gtk3, "Settings", "gtk-modules", NULL);
406
407 #if 0
408 /* unfortunately we cannot set colors without XSETTINGS daemon,
409 themes will override any custom settings in .gtkrc-2.0 file */
410 /* FIXME: we should support other xsettings daemons too */
411 if(app.color_scheme)
412 {
413 char* escaped = g_strescape(app.color_scheme, NULL);
414 g_string_append_printf(content_gtk3,
415 "gtk-color-scheme=%s\n",
416 escaped);
417 g_free(escaped);
418 }
419 #endif
420
421 #if GLIB_CHECK_VERSION(2, 40, 0)
422 g_key_file_save_to_file(content_gtk3, file_path_settings, NULL);
423 #else
424 char *contents;
425 gsize s;
426
427 contents = g_key_file_to_data(content_gtk3, &s, NULL);
428 if (contents)
429 g_file_set_contents(file_path_settings, contents, s, NULL);
430 g_free(contents);
431 #endif
432
433 g_free(file_path_gtk3);
434 g_free(file_path_settings);
435 g_string_free(content, TRUE);
436 g_key_file_free(content_gtk3);
437 g_free(file_path);
438 }
439
440 static void lxappearance_save_lxsession()
441 {
442 char* rel_path = g_strconcat("lxsession/", lxsession_name, "/desktop.conf", NULL);
443 char* user_config_file = g_build_filename(g_get_user_config_dir(), rel_path, NULL);
444 char* buf;
445 gsize len;
446 GKeyFile* kf = g_key_file_new();
447
448 if(!g_key_file_load_from_file(kf, user_config_file, G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS, NULL))
449 {
450 /* the user config file doesn't exist, create its parent dir */
451 len = strlen(user_config_file) - strlen("/desktop.conf");
452 user_config_file[len] = '\0';
453 g_debug("user_config_file = %s", user_config_file);
454 g_mkdir_with_parents(user_config_file, 0700);
455 user_config_file[len] = '/';
456
457 g_key_file_load_from_dirs(kf, rel_path, (const char**)g_get_system_config_dirs(), NULL,
458 G_KEY_FILE_KEEP_COMMENTS|G_KEY_FILE_KEEP_TRANSLATIONS, NULL);
459 }
460
461 g_free(rel_path);
462
463 g_key_file_set_string( kf, "GTK", "sNet/ThemeName", app.widget_theme );
464 g_key_file_set_string( kf, "GTK", "sGtk/FontName", app.default_font );
465
466 g_key_file_set_string( kf, "GTK", "sGtk/ColorScheme", app.color_scheme ? app.color_scheme : "" );
467
468 g_key_file_set_string( kf, "GTK", "sNet/IconThemeName", app.icon_theme );
469
470 g_key_file_set_string( kf, "GTK", "sGtk/CursorThemeName", app.cursor_theme );
471 g_key_file_set_integer( kf, "GTK", "iGtk/CursorThemeSize", app.cursor_theme_size );
472 save_cursor_theme_name();
473
474 g_key_file_set_integer( kf, "GTK", "iGtk/ToolbarStyle", app.toolbar_style );
475 g_key_file_set_integer( kf, "GTK", "iGtk/ToolbarIconSize", app.toolbar_icon_size );
476
477 g_key_file_set_integer( kf, "GTK", "iGtk/ToolbarStyle", app.toolbar_style );
478 g_key_file_set_integer( kf, "GTK", "iGtk/ToolbarIconSize", app.toolbar_icon_size );
479
480 g_key_file_set_integer( kf, "GTK", "iGtk/ButtonImages", app.button_images );
481 g_key_file_set_integer( kf, "GTK", "iGtk/MenuImages", app.menu_images );
482
483 #if GTK_CHECK_VERSION(2, 14, 0)
484 /* "Net/SoundThemeName\0" "gtk-sound-theme-name\0" */
485 g_key_file_set_integer( kf, "GTK", "iNet/EnableEventSounds", app.enable_event_sound);
486 g_key_file_set_integer( kf, "GTK", "iNet/EnableInputFeedbackSounds", app.enable_input_feedback);
487 #endif
488 g_key_file_set_integer( kf, "GTK", "iXft/Antialias", app.enable_antialising);
489 g_key_file_set_integer( kf, "GTK", "iXft/Hinting", app.enable_hinting);
490 g_key_file_set_string( kf, "GTK", "sXft/HintStyle", app.hinting_style);
491 g_key_file_set_string( kf, "GTK", "sXft/RGBA", app.font_rgba);
492
493 buf = g_key_file_to_data( kf, &len, NULL );
494 g_key_file_free(kf);
495
496 g_file_set_contents(user_config_file, buf, len, NULL);
497 g_free(buf);
498 g_free(user_config_file);
499 }
500
501 static void on_dlg_response(GtkDialog* dlg, int res, gpointer user_data)
502 {
503 switch(res)
504 {
505 case GTK_RESPONSE_APPLY:
506
507 if(app.use_lxsession)
508 lxappearance_save_lxsession();
509 lxappearance_save_gtkrc();
510
511 reload_all_programs();
512
513 app.changed = FALSE;
514 gtk_dialog_set_response_sensitive(GTK_DIALOG(app.dlg), GTK_RESPONSE_APPLY, FALSE);
515 break;
516 case 1: /* about dialog */
517 {
518 GtkBuilder* b = gtk_builder_new();
519 if(gtk_builder_add_from_file(b, PACKAGE_UI_DIR "/about.ui", NULL))
520 {
521 GtkWidget* dlg = GTK_WIDGET(gtk_builder_get_object(b, "dlg"));
522 gtk_dialog_run(GTK_DIALOG(dlg));
523 gtk_widget_destroy(dlg);
524 }
525 g_object_unref(b);
526 }
527 break;
528 default:
529 gtk_main_quit();
530 }
531 }
532
533 static void settings_init()
534 {
535 GtkSettings* settings = gtk_settings_get_default();
536 g_object_get(settings,
537 "gtk-theme-name", &app.widget_theme,
538 "gtk-font-name", &app.default_font,
539 "gtk-icon-theme-name", &app.icon_theme,
540 "gtk-cursor-theme-name", &app.cursor_theme,
541 "gtk-cursor-theme-size", &app.cursor_theme_size,
542 "gtk-toolbar-style", &app.toolbar_style,
543 "gtk-toolbar-icon-size", &app.toolbar_icon_size,
544 "gtk-button-images", &app.button_images,
545 "gtk-menu-images", &app.menu_images,
546 #if GTK_CHECK_VERSION(2, 14, 0)
547 "gtk-enable-event-sounds", &app.enable_event_sound,
548 "gtk-enable-input-feedback-sounds", &app.enable_input_feedback,
549 #endif
550 "gtk-xft-antialias", &app.enable_antialising,
551 "gtk-xft-hinting", &app.enable_hinting,
552 "gtk-xft-hintstyle", &app.hinting_style,
553 "gtk-xft-rgba", &app.font_rgba,
554 "gtk-modules", &app.modules,
555 NULL);
556 /* try to figure out cursor theme used. */
557 if(!app.cursor_theme || g_strcmp0(app.cursor_theme, "default") == 0)
558 {
559 /* get the real theme name from default. */
560 GKeyFile* kf = g_key_file_new();
561 char* fpath = g_build_filename(g_get_home_dir(), ".icons/default/index.theme", NULL);
562 gboolean ret = g_key_file_load_from_file(kf, fpath, 0, NULL);
563 g_free(fpath);
564
565 if(!ret)
566 ret = g_key_file_load_from_data_dirs(kf, "icons/default/index.theme", NULL, 0, NULL);
567
568 if(ret)
569 {
570 g_free(app.cursor_theme);
571 app.cursor_theme = g_key_file_get_string(kf, "Icon Theme", "Inherits", NULL);
572 g_debug("cursor theme name: %s", app.cursor_theme);
573 }
574 g_key_file_free(kf);
575 }
576
577 app.color_scheme_hash = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
578 /* try to load custom color scheme if available */
579 if(app.use_lxsession)
580 {
581 char* rel_path = g_strconcat("lxsession/", lxsession_name, "/desktop.conf", NULL);
582 char* user_config_file = g_build_filename(g_get_user_config_dir(), rel_path, NULL);
583 GKeyFile* kf = g_key_file_new();
584 if(g_key_file_load_from_file(kf, user_config_file, 0, NULL))
585 app.color_scheme = g_key_file_get_string(kf, "GTK", "sGtk/ColorScheme", NULL);
586 else if(g_key_file_load_from_dirs(kf, rel_path, (const char**)g_get_system_config_dirs(), NULL, 0, NULL))
587 app.color_scheme = g_key_file_get_string(kf, "GTK", "sGtk/ColorScheme", NULL);
588 g_key_file_free(kf);
589 g_free(rel_path);
590 g_free(user_config_file);
591
592 if(app.color_scheme)
593 {
594 if(*app.color_scheme)
595 color_scheme_str_to_hash(app.color_scheme_hash, app.color_scheme);
596 else
597 {
598 g_free(app.color_scheme);
599 app.color_scheme = NULL;
600 }
601 }
602 }
603 #if 0
604 /* unfortunately we cannot set colors without XSETTINGS daemon,
605 themes will override any custom settings in .gtkrc-2.0 file */
606 /* FIXME: we should support other xsettings daemons too */
607 else
608 {
609 char* gtkrc_file = g_build_filename(g_get_home_dir(), ".gtkrc-2.0", NULL);
610 gtkrc_file_get_color_scheme(gtkrc_file, app.color_scheme_hash);
611 g_free(gtkrc_file);
612 if(g_hash_table_size(app.color_scheme_hash) > 0)
613 app.color_scheme = color_scheme_hash_to_str(app.color_scheme_hash);
614 }
615 #endif
616 }
617
618 int main(int argc, char** argv)
619 {
620 GError* err = NULL;
621 GtkBuilder* b;
622
623 /* gettext support */
624 #ifdef ENABLE_NLS
625 bindtextdomain ( GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR );
626 bind_textdomain_codeset ( GETTEXT_PACKAGE, "UTF-8" );
627 textdomain ( GETTEXT_PACKAGE );
628 #endif
629
630 #if !GLIB_CHECK_VERSION(2, 32, 0)
631 g_thread_init(NULL);
632 #endif
633 /* initialize GTK+ and parse the command line arguments */
634 if( G_UNLIKELY( ! gtk_init_with_args( &argc, &argv, "", option_entries, GETTEXT_PACKAGE, &err ) ) )
635 {
636 g_print( "Error: %s\n", err->message );
637 return 1;
638 }
639
640 app.abi_version = LXAPPEARANCE_ABI_VERSION;
641
642 /* check if we're under LXSession */
643 check_lxsession();
644
645 /* create GUI here */
646 b = gtk_builder_new();
647 if(!gtk_builder_add_from_file(b, PACKAGE_UI_DIR "/lxappearance.ui", NULL))
648 return 1;
649
650 /* NOTE: GUI must be created prior to loading settings from GtkSettings object.
651 * Some properties of GtkSettings class are installed by some other gtk classes.
652 * For example, "gtk-menu-images" property is actually installed by initialization
653 * of GtkImageMenuItem class. If we load the GUI first, then when the menu items
654 * are created, this property gets correctly registered. So later it can be read. */
655
656 /* load config values */
657 settings_init();
658
659 app.dlg = GTK_WIDGET(gtk_builder_get_object(b, "dlg"));
660
661 widget_theme_init(b);
662 color_scheme_init(b);
663 icon_theme_init(b);
664 cursor_theme_init(b);
665 font_init(b);
666 other_init(b);
667 /* the page for window manager plugins */
668 app.wm_page = GTK_WIDGET(gtk_builder_get_object(b, "wm_page"));
669
670 plugins_init(b);
671
672 g_signal_connect(app.dlg, "response", G_CALLBACK(on_dlg_response), NULL);
673
674 gtk_window_present(GTK_WINDOW(app.dlg));
675 g_object_unref(b);
676
677 gtk_main();
678
679 plugins_finalize();
680
681 return 0;
682 }
683
684 void lxappearance_changed()
685 {
686 if(!app.changed)
687 {
688 app.changed = TRUE;
689 gtk_dialog_set_response_sensitive(GTK_DIALOG(app.dlg), GTK_RESPONSE_APPLY, TRUE);
690 }
691 }
692
693 void on_check_button_toggled(GtkToggleButton* btn, gpointer user_data)
694 {
695 gboolean* val = (gboolean*)user_data;
696 gboolean new_val = gtk_toggle_button_get_active(btn);
697 if(new_val != *val)
698 {
699 *val = new_val;
700 lxappearance_changed();
701 }
702 }