a95ee04248e9b9011a7724803f5b4eb807465c9f
[lxde/lxappearance.git] / src / main-dlg.c
1 #ifdef HAVE_CONFIG_H
2 # include <config.h>
3 #endif
4
5 #include <gtk/gtk.h>
6 #include <gdk/gdkx.h>
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12
13 /* for kill & waitpid */
14 #include <sys/types.h>
15 #include <signal.h>
16 #include <sys/wait.h>
17
18 #include "main-dlg.h"
19 #include "main-dlg-ui.h"
20 #include "glade-support.h"
21
22 #define GET_WIDGET( name ) name = lookup_widget( dlg, #name )
23
24 #define INIT_LIST(name, prop) \
25 GET_WIDGET( name##_view ); \
26 name##_list = init_tree_view( name##_view, G_CALLBACK(on_list_sel_changed), prop ); \
27 load_##name##s( name##_list, name##_name );
28
29 #define enable_apply() gtk_dialog_set_response_sensitive( main_dlg, GTK_RESPONSE_APPLY, TRUE )
30 #define disable_apply() gtk_dialog_set_response_sensitive( main_dlg, GTK_RESPONSE_APPLY, FALSE )
31
32 extern gboolean under_lxde; /* wether lxde-xsettings daemon is active */
33
34 extern GtkWidget* main_dlg; /* defined in main.c */
35
36 static GtkTreeView* gtk_theme_view = NULL;
37 static GtkListStore* gtk_theme_list = NULL;
38
39 static GtkTreeView* icon_theme_view = NULL;
40 static GtkListStore* icon_theme_list = NULL;
41
42 static char* gtk_theme_name = NULL;
43 static char* icon_theme_name = NULL;
44 static char* font_name = NULL;
45 static GtkToolbarStyle tb_style = GTK_TOOLBAR_BOTH;
46
47 extern char tmp_rc_file[];
48 static char* rc_file = NULL;
49
50 /*
51 static GtkTreeView* font_view = NULL;
52 static GtkListStore* font_list = NULL;
53 */
54 static GtkWidget* demo_box = NULL;
55 static GtkWidget* demo_socket = NULL;
56 static GPid demo_pid = 0;
57
58 static void reload_demo_process()
59 {
60 char* argv[5];
61 char wid[16];
62
63 if( demo_pid > 0 ) /* kill old demo */
64 {
65 int stat;
66 kill( demo_pid, SIGTERM );
67 waitpid( demo_pid, &stat, 0 );
68 demo_pid = 0;
69 }
70
71 g_snprintf( wid, 16, "%ld", gtk_socket_get_id(demo_socket) );
72
73 argv[0] = g_get_prgname();
74 argv[1] = "demo";
75 argv[2] = wid;
76 argv[3] = tmp_rc_file;
77 argv[4] = NULL;
78 g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, &demo_pid, NULL );
79
80 /* reloading demo means the current selected theme is changed */
81 enable_apply();
82 }
83
84 static void write_rc_file( const char* path )
85 {
86 FILE* f;
87 static char* tb_styles[] = {
88 "GTK_TOOLBAR_ICONS",
89 "GTK_TOOLBAR_TEXT",
90 "GTK_TOOLBAR_BOTH",
91 "GTK_TOOLBAR_BOTH_HORIZ"
92 };
93
94 if( f = fopen( path, "w" ) )
95 {
96 fputs( "# DO NOT EDIT! This file will be overwritten by LXAppearance.\n"
97 "# Any customization should be done in ~/.gtkrc-2.0.mine\n\n", f );
98
99 fprintf( f, "gtk-theme-name=\"%s\"\n", gtk_theme_name );
100 fprintf( f, "gtk-icon-theme-name=\"%s\"\n", icon_theme_name );
101 fprintf( f, "gtk-font-name=\"%s\"\n", font_name );
102 fprintf( f, "gtk-toolbar-style=%d\n", tb_style );
103
104 fprintf( f, "include \"%s/.gtkrc-2.0.mine\"\n", g_get_home_dir() );
105
106 fclose( f );
107 }
108 }
109
110 static void create_lxde_config_dir()
111 {
112 char* dir = g_build_filename( g_get_user_config_dir(), "lxde", NULL );
113 #if GTK_CHECK_VERSION( 2, 8, 0 )
114 g_mkdir_with_parents( dir, 0755 );
115 #else
116 /* FIXME: implement mkdir -p for gtk+ < 2.8 */
117 #endif
118 g_free( dir );
119 }
120
121 static void write_lxde_config()
122 {
123 FILE* f;
124 char* file, *data;
125 gsize len;
126 GKeyFile* kf = g_key_file_new();
127 gboolean ret;
128
129 file = g_build_filename( g_get_user_config_dir(), "lxde/config", NULL );
130 ret = g_key_file_load_from_file( kf, file, G_KEY_FILE_KEEP_COMMENTS, NULL );
131
132 if( ! ret )
133 {
134 const char** dir, **dirs = g_get_system_data_dirs();
135 create_lxde_config_dir();
136 /* load system-wide config file */
137 for( dir = dirs; *dir; ++dir )
138 {
139 char* path = g_build_filename( *dir, "lxde/config", NULL );
140 ret = g_key_file_load_from_file( kf, path, 0, NULL );
141 g_free( path );
142 if( ret )
143 break;
144 }
145 }
146
147 g_key_file_set_string( kf, "GTK", "sNet/ThemeName", gtk_theme_name );
148 g_key_file_set_string( kf, "GTK", "sNet/IconThemeName", icon_theme_name );
149 g_key_file_set_string( kf, "GTK", "sGtk/FontName", font_name );
150 g_key_file_set_integer( kf, "GTK", "iGtk/ToolbarStyle", tb_style );
151
152 data = g_key_file_to_data( kf, &len, NULL );
153 g_key_file_free( kf );
154
155 if( f = fopen( file, "w" ) )
156 {
157 fwrite( data, sizeof(char), len, f );
158 fclose( f );
159 }
160 g_free( data );
161 }
162
163 static void reload_theme()
164 {
165
166 gtk_rc_reparse_all();
167 }
168
169 static void on_list_sel_changed( GtkTreeSelection* sel, const char* prop )
170 {
171 GtkTreeIter it;
172 GtkTreeModel* model;
173 if( gtk_tree_selection_get_selected( sel, &model, &it ) )
174 {
175 char* name;
176 gtk_tree_model_get( model, &it, 0, &name, -1 );
177
178 if( model == gtk_theme_list ) /* gtk+ theme */
179 {
180 if( name && gtk_theme_name && 0 == strcmp( name, gtk_theme_name ) )
181 goto out;
182 g_free( gtk_theme_name );
183 gtk_theme_name = name;
184
185 if( under_lxde )
186 g_object_set( gtk_settings_get_default(), "gtk-theme-name", name, NULL );
187 }
188 else if( model == icon_theme_list ) /* icon theme */
189 {
190 if( name && icon_theme_name && 0 == strcmp( name, icon_theme_name ) )
191 goto out;
192 g_free( icon_theme_name );
193 icon_theme_name = name;
194
195 if( under_lxde )
196 g_object_set( gtk_settings_get_default(), "gtk-icon-theme-name", name, NULL );
197 }
198
199 if( under_lxde )
200 {
201 enable_apply();
202 }
203 else
204 {
205 write_rc_file( tmp_rc_file );
206 //gtk_rc_reparse_all_for_settings(gtk_settings_get_default(), TRUE);
207 reload_demo_process();
208 }
209
210 return;
211 out:
212 g_free( name );
213 }
214 }
215
216 static GtkListStore* init_tree_view( GtkTreeView* view, GCallback on_sel_changed, const char* prop )
217 {
218 GtkTreeViewColumn* col;
219 GtkListStore* list;
220 GtkTreeSelection* sel;
221 col = gtk_tree_view_column_new_with_attributes( NULL, gtk_cell_renderer_text_new(), "text", 0, NULL );
222 gtk_tree_view_append_column( view, col );
223 sel = gtk_tree_view_get_selection(view);
224 g_signal_connect( sel, "changed", on_sel_changed, prop );
225
226 list = gtk_list_store_new( 1, G_TYPE_STRING );
227 gtk_tree_view_set_model( view, (GtkTreeModel*)list );
228 g_object_unref( list );
229 return list;
230 }
231
232 static void load_themes_from_dir( GtkListStore* list,
233 const char* dir_path,
234 const char* lookup,
235 GtkTreeSelection* sel,
236 const char* init_sel )
237 {
238 GDir* dir;
239 if( dir = g_dir_open( dir_path, 0, NULL ) )
240 {
241 char* name;
242 while( name = g_dir_read_name( dir ) )
243 {
244 char* file = g_build_filename( dir_path, name, lookup, NULL );
245 if( g_file_test( file, G_FILE_TEST_EXISTS ) )
246 {
247 GtkTreeIter it;
248 gtk_list_store_append( list, &it );
249 gtk_list_store_set( list, &it, 0, name, -1 );
250 if( 0 == strcmp( name, init_sel ) )
251 {
252 GtkTreeView* view;
253 GtkTreePath* tp;
254 gtk_tree_selection_select_iter( sel, &it );
255 view = gtk_tree_selection_get_tree_view( sel );
256 tp = gtk_tree_model_get_path( (GtkTreeModel*)list, &it );
257 gtk_tree_view_scroll_to_cell( view, tp, NULL, FALSE, 0, 0 );
258 gtk_tree_path_free( tp );
259 }
260 }
261 g_free( file );
262 }
263 g_dir_close( dir );
264 }
265 }
266
267 static void load_from_data_dirs( GtkListStore* list,
268 const char* relative_path,
269 const char* lookup,
270 GtkTreeSelection* sel,
271 const char* init_sel )
272 {
273 const char* const *dirs = g_get_system_data_dirs();
274 const char* const *dir;
275 char* dir_path;
276 for( dir = dirs; *dir; ++dir )
277 {
278 dir_path = g_build_filename( *dir, relative_path, NULL );
279 load_themes_from_dir( list, dir_path, lookup, sel, init_sel );
280 g_free( dir_path );
281 }
282 dir_path = g_build_filename( g_get_user_data_dir(), relative_path, NULL );
283 load_themes_from_dir( list, dir_path, lookup, sel, init_sel );
284 g_free( dir_path );
285 }
286
287 static void load_gtk_themes( GtkListStore* list, const char* cur_sel )
288 {
289 char* path;
290 GtkTreeSelection* sel = gtk_tree_view_get_selection( gtk_theme_view );
291 load_from_data_dirs( list, "themes", "gtk-2.0", sel, cur_sel );
292 path = g_build_filename( g_get_home_dir(), ".themes", NULL );
293 load_themes_from_dir( list, path, "gtk-2.0", sel, cur_sel );
294 g_free( path );
295 }
296
297 static void load_icon_themes( GtkListStore* list, const char* cur_sel )
298 {
299 char* path;
300 GtkTreeSelection* sel = gtk_tree_view_get_selection( icon_theme_view );
301 load_from_data_dirs( list, "icons", "index.theme", sel, cur_sel );
302 path = g_build_filename( g_get_home_dir(), ".icons", NULL );
303 load_themes_from_dir( list, path, "index.theme", sel, cur_sel );
304 g_free( path );
305 }
306
307 /*
308 static void load_fonts( GtkListStore* list )
309 {
310
311 }
312 */
313
314 gboolean center_win( GtkWindow* dlg )
315 {
316 gtk_widget_show( dlg );
317 return FALSE;
318 }
319
320 static void on_demo_loaded( GtkSocket* socket, GtkWidget* dlg )
321 {
322 /* sleep for 0.8 sec for loading of the demo window */
323 /* FIXME: we need a better way to do this, such as IPC */
324 g_timeout_add_full( G_PRIORITY_LOW, 800, (GSourceFunc)center_win, dlg, NULL );
325 g_signal_handlers_disconnect_by_func( socket, on_demo_loaded, dlg );
326 }
327
328 void main_dlg_init( GtkWidget* dlg )
329 {
330 char* files[] = { tmp_rc_file, NULL };
331 char** def_files = gtk_rc_get_default_files();
332 char** file;
333
334 /* no lxde-settings daemon, use gtkrc-2.0 */
335 if( ! under_lxde )
336 {
337 for( file = def_files; *file; ++file )
338 {
339 if( 0 == access( *file, W_OK ) )
340 rc_file = *file;
341 }
342 if( rc_file )
343 rc_file = g_strdup( rc_file );
344 else
345 rc_file = g_build_filename( g_get_home_dir(), ".gtkrc-2.0", NULL );
346 }
347
348 g_object_get( gtk_settings_get_default(),
349 "gtk-theme-name", &gtk_theme_name,
350 "gtk-icon-theme-name", &icon_theme_name,
351 "gtk-font-name", &font_name,
352 "gtk-toolbar-style", &tb_style,
353 NULL );
354
355 if( ! gtk_theme_name )
356 gtk_theme_name = g_strdup( "Raleigh" );
357 if( ! icon_theme_name )
358 gtk_theme_name = g_strdup( "hicolor" );
359 if( ! font_name )
360 font_name = g_strdup( "Sans 10" );
361
362 /* no lxde-settings daemon, use gtkrc-2.0 */
363 if( ! under_lxde )
364 write_rc_file( tmp_rc_file );
365
366 INIT_LIST( gtk_theme, "gtk-theme-name" )
367 INIT_LIST( icon_theme, "gtk-icon-theme-name" )
368 gtk_font_button_set_font_name( (GtkFontButton*)lookup_widget(dlg, "font"), font_name );
369
370 gtk_combo_box_set_active( (GtkComboBox*)lookup_widget(dlg, "tb_style"), tb_style < 4 ? tb_style : 3 );
371
372 GET_WIDGET( demo_box );
373 gtk_widget_show( demo_box );
374
375 if( under_lxde )
376 {
377 /* XSettings daemon of LXDE is running, gtkrc is useless.
378 * We should set properties of GtkSettings object on the fly.
379 * This will cause problems with some themes, but we have no choice.
380 */
381 show_demo( (GdkNativeWindow)demo_box );
382 gtk_widget_show_all( dlg );
383 }
384 else
385 {
386 /* no lxde-settings daemon, use gtkrc-2.0 and load preview in another process */
387 demo_socket = gtk_socket_new();
388 g_signal_connect( demo_socket, "plug-added", G_CALLBACK(on_demo_loaded), dlg );
389 g_signal_connect( demo_socket, "plug-removed", G_CALLBACK(gtk_true), NULL );
390 gtk_widget_show( demo_socket );
391 gtk_container_add( (GtkContainer*)demo_box, demo_socket );
392
393 gtk_widget_realize( dlg );
394 reload_demo_process();
395 }
396
397 disable_apply();
398 }
399
400 static void reload_all_programs( gboolean icon_only )
401 {
402 GdkEventClient event;
403 event.type = GDK_CLIENT_EVENT;
404 event.send_event = TRUE;
405 event.window = NULL;
406
407 if( under_lxde )
408 {
409 event.message_type = gdk_atom_intern("LXDE_SETTINGS", FALSE);
410 event.data.b[0] = 0; /* LXS_RELOAD */
411 }
412 else
413 {
414 if( icon_only )
415 event.message_type = gdk_atom_intern("_GTK_LOAD_ICONTHEMES", FALSE);
416 else
417 event.message_type = gdk_atom_intern("_GTK_READ_RCFILES", FALSE);
418 }
419 event.data_format = 8;
420 gdk_event_send_clientmessage_toall((GdkEvent *)&event);
421 }
422
423 void
424 on_apply_clicked (GtkButton *button,
425 gpointer user_data)
426 {
427 if( under_lxde )
428 write_lxde_config();
429 else
430 write_rc_file( rc_file );
431
432 reload_all_programs( FALSE );
433 disable_apply();
434 }
435
436
437 void
438 on_font_changed (GtkFontButton *fontbutton,
439 gpointer user_data)
440 {
441 const char* name = gtk_font_button_get_font_name(fontbutton);
442 if( name && font_name && 0 == strcmp( name, font_name ) )
443 return;
444 g_free( font_name );
445 font_name = g_strdup( name );
446
447 if( under_lxde )
448 {
449 g_object_set( gtk_settings_get_default(), "gtk-font-name", font_name, NULL );
450
451 enable_apply();
452 }
453 else
454 {
455 write_rc_file( tmp_rc_file );
456 reload_demo_process();
457 }
458 }
459
460 void
461 on_install_theme_clicked (GtkButton *button,
462 gpointer user_data)
463 {
464 GtkFileFilter* filter = gtk_file_filter_new();
465 GtkWidget* fc = gtk_file_chooser_dialog_new( _("Select an icon theme"), NULL,
466 GTK_FILE_CHOOSER_ACTION_OPEN,
467 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
468 GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL );
469
470 gtk_file_filter_add_pattern( filter, "*.tar.gz" );
471 gtk_file_filter_add_pattern( filter, "*.tar.bz2" );
472 gtk_file_filter_set_name( filter, _("*.tar.gz, *.tar.bz2 (Icon Theme)") );
473
474 gtk_file_chooser_add_filter( fc, filter );
475 gtk_file_chooser_set_filter( (GtkFileChooser*)fc, filter );
476
477 if( gtk_dialog_run( (GtkDialog*)fc ) == GTK_RESPONSE_OK )
478 {
479 char* file = gtk_file_chooser_get_filename( fc );
480 char* argv[]={
481 PACKAGE_DATA_DIR"/lxappearance/install-icon-theme.sh",
482 file, NULL };
483 int status = 0;
484 char* stdo = NULL;
485 if( g_spawn_sync( NULL, argv, NULL, 0, NULL, NULL, &stdo, NULL, &status, NULL ) && 0 == status )
486 {
487 char* sep = stdo ? strchr( stdo, '\n' ) : NULL;
488 if( sep )
489 *sep = '\0';
490
491 /* reload all icon themes */
492 gtk_list_store_clear( icon_theme_list );
493 load_icon_themes( icon_theme_list, stdo ? stdo : "" );
494 }
495 g_free( file );
496 }
497
498 gtk_widget_destroy( fc );
499 }
500
501
502 void
503 on_remove_theme_clicked (GtkButton *button,
504 gpointer user_data)
505 {
506
507 }
508
509
510 void
511 on_tb_style_changed (GtkComboBox *combobox,
512 gpointer user_data)
513 {
514 int sel = gtk_combo_box_get_active( combobox );
515 if( sel == tb_style || sel < 0 )
516 return;
517 tb_style = sel;
518
519 if( under_lxde )
520 {
521 g_object_set( gtk_settings_get_default(), "gtk-toolbar-style", tb_style, NULL );
522 enable_apply();
523 }
524 else
525 {
526 write_rc_file( tmp_rc_file );
527 reload_demo_process();
528 }
529 }
530