1 /*
2 * Copyright © 2006 Novell, Inc.
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 *
18 */
19
20 ////////////////////////////////////////////////////
21 //themer stuff
22 #include <engine.h>
23 #include <signal.h>
24 typedef enum _EngineCol
25 {
26 ENGINE_COL_DLNAME,
27 ENGINE_COL_NAME,
28 ENGINE_COL_VER,
29 ENGINE_COL_LAST_COMPAT,
30 ENGINE_COL_MARKUP,
31 ENGINE_COL_ICON,
32 ENGINE_COL_COUNT
33 } EngineCol;
34 typedef struct _EngineData
35 {
36 const gchar * canname;
37 gchar * dlname;
38 GtkWidget * vbox;
39 EngineMetaInfo meta;
40 } EngineData;
41 typedef struct _FindEngine
42 {
43 const gchar * canname;
44 gboolean found;
45 gint i;
46 EngineData * d;
47 } FindEngine;
48 GSList * SettingList = NULL;
49 GSList * EngineList = NULL;
50 GtkWidget * EngineCombo;
51 GtkListStore * EngineModel;
52 GtkWidget * EngineContainer;
53 //GtkWidget * PreviewImage[BX_COUNT];
54 //GtkWidget * ButtonImage[BX_COUNT];
55 gboolean apply=FALSE;
56 gboolean changed=FALSE;
57 GKeyFile * global_theme_file;
58 GKeyFile * global_settings_file;
59 #ifdef USE_DBUS
60 DBusConnection *dbcon;
61 #endif
62 gchar * active_engine = NULL;
63
display_part(const gchar * p)64 static gchar* display_part(const gchar *p)
65 {
66 gchar *name = g_strdup(p);
67 gchar *tmp;
68
69 if ((tmp = g_strrstr(name,":"))) {
70 *tmp++ = 0;
71 tmp = g_strdup(tmp);
72 g_free(name);
73 name = tmp;
74 }
75
76 if ((tmp = g_strrstr(name,"."))) {
77 *tmp = 0;
78 }
79
80 return name;
81 }
82
get_setting_list()83 GSList * get_setting_list()
84 {
85 return SettingList;
86 }
scaler_new(gdouble low,gdouble high,gdouble prec)87 GtkWidget * scaler_new(gdouble low, gdouble high, gdouble prec)
88 {
89 GtkWidget * w;
90 w = gtk_hscale_new_with_range(low,high,prec);
91 gtk_scale_set_value_pos(GTK_SCALE(w),GTK_POS_RIGHT);
92 gtk_range_set_update_policy(GTK_RANGE(w),GTK_UPDATE_DISCONTINUOUS);
93 gtk_widget_set_size_request(w,100,-1);
94 return w;
95 }
add_color_alpha_value(gchar * caption,gchar * basekey,gchar * sect,gboolean active)96 void add_color_alpha_value(gchar * caption, gchar * basekey, gchar * sect, gboolean active)
97 {
98 GtkWidget * w;
99 gchar * colorkey;
100 gchar * alphakey;
101 colorkey = g_strdup_printf(active?"active_%s":"inactive_%s",basekey);
102 alphakey = g_strdup_printf(active?"active_%s_alpha":"inactive_%s_alpha",
103 basekey);
104
105 w = gtk_label_new(caption);
106 table_append(w,FALSE);
107
108 w = gtk_color_button_new();
109 table_append(w,FALSE);
110 register_setting(w,ST_COLOR,sect,colorkey);
111
112 w = scaler_new(0.0,1.0,0.01);
113 table_append(w,TRUE);
114 register_setting(w,ST_FLOAT,sect,alphakey);
115 //we don't g_free because they are registered with register_setting
116 }
make_labels(gchar * header)117 void make_labels(gchar * header)
118 {
119 table_append(gtk_label_new(header),FALSE);
120 table_append(gtk_label_new("Color"),FALSE);
121 table_append(gtk_label_new("Opacity"),FALSE);
122 }
build_frame(GtkWidget * vbox,gchar * title,gboolean is_hbox)123 GtkWidget * build_frame(GtkWidget * vbox, gchar * title, gboolean is_hbox)
124 {
125 GtkWidget * frame;
126 GtkWidget * box;
127 frame = gtk_frame_new(title);
128 gtk_box_pack_startC(vbox,frame,TRUE,TRUE,0);
129 box = is_hbox?gtk_hbox_new(FALSE,2):gtk_vbox_new(FALSE, 2);
130 gtk_container_set_border_widthC(box,8);
131 gtk_container_addC(frame,box);
132 return box;
133 }
register_img_file_setting(GtkWidget * widget,gchar * section,gchar * key,GtkImage * image)134 SettingItem * register_img_file_setting(GtkWidget * widget, gchar * section, gchar * key, GtkImage * image)
135 {
136 SettingItem * item = register_setting(widget,ST_IMG_FILE,section,key);
137 gtk_file_chooser_button_set_width_chars(GTK_FILE_CHOOSER_BUTTON(widget),0);
138 item->image = image;
139 item->preview = GTK_IMAGE(gtk_image_new());
140 gtk_file_chooser_set_preview_widget(GTK_FILE_CHOOSER(widget),GTK_WIDGET(item->preview));
141 g_signal_connect(widget,"update-preview",G_CALLBACK(update_preview_cb),
142 item->preview);
143 return item;
144 }
register_setting(GtkWidget * widget,SettingType type,gchar * section,gchar * key)145 SettingItem * register_setting(GtkWidget * widget, SettingType type, gchar * section, gchar * key)
146 {
147 SettingItem * item;
148 item = malloc(sizeof(SettingItem));
149 item->type = type;
150 item->key = g_strdup(key);
151 item->section = g_strdup(section);
152 item->widget = widget;
153 item->fvalue = g_strdup("");
154 SettingList = g_slist_append(SettingList,item);
155 switch(item->type)
156 {
157 case ST_BOOL:
158 case ST_SFILE_BOOL:
159 g_signal_connect(widget,"toggled",
160 G_CALLBACK(cb_apply_setting),
161 item);
162 break;
163 case ST_INT:
164 case ST_SFILE_INT:
165 g_signal_connect(widget,"value-changed",
166 G_CALLBACK(cb_apply_setting),
167 item);
168 break;
169 case ST_FLOAT:
170 g_signal_connect(widget,"value-changed",
171 G_CALLBACK(cb_apply_setting),
172 item);
173 break;
174 case ST_COLOR:
175 g_signal_connect(widget,"color-set",
176 G_CALLBACK(cb_apply_setting),
177 item);
178 break;
179 case ST_FONT:
180 g_signal_connect(widget,"font-set",
181 G_CALLBACK(cb_apply_setting),
182 item);
183 break;
184 case ST_IMG_FILE:
185 g_signal_connect(widget,"selection-changed",
186 G_CALLBACK(cb_apply_setting),
187 item);
188 break;
189 case ST_STRING_COMBO:
190 g_signal_connect(gtk_bin_get_child(GTK_BIN(widget)),"changed",
191 G_CALLBACK(cb_apply_setting),
192 item);
193 break;
194 case ST_SFILE_INT_COMBO:
195 g_signal_connect(widget,"changed",
196 G_CALLBACK(cb_apply_setting),
197 item);
198 break;
199 case ST_ENGINE_COMBO:
200 g_signal_connect(widget,"changed",
201 G_CALLBACK(cb_apply_setting),
202 item);
203 default:
204 break;
205 //unconnected types
206 }
207 return item;
208 }
209
210 static gint current_table_width;
211 static GtkTable * current_table;
212 static gint current_table_col;
213 static gint current_table_row;
214
table_new(gint width,gboolean same,gboolean labels)215 void table_new(gint width, gboolean same, gboolean labels)
216 {
217 //WARNING - clobbers all the current_table_ vars.
218 current_table = GTK_TABLE(gtk_table_new(width,1,same));
219 gtk_table_set_row_spacings(current_table,8);
220 gtk_table_set_col_spacings(current_table,8);
221 current_table_col = labels?1:0;
222 current_table_row = 0;
223 current_table_width = width;
224 }
table_append(GtkWidget * child,gboolean stretch)225 void table_append(GtkWidget * child,gboolean stretch)
226 {
227 gtk_table_attach(current_table,child,current_table_col,current_table_col+1,
228 current_table_row,current_table_row+1,
229 (stretch?GTK_EXPAND:GTK_SHRINK)|GTK_FILL,
230 (stretch?GTK_EXPAND:GTK_SHRINK)|GTK_FILL,
231 0,0);
232 current_table_col++;
233 if (current_table_col == current_table_width)
234 {
235 current_table_col=0;
236 current_table_row++;
237 // gtk_table_resize(current_table,current_table_width,current_table_row+1);
238 }
239 }
table_append_separator()240 void table_append_separator()
241 {
242 current_table_col=0;
243 current_table_row++;
244 // gtk_table_resize(current_table,current_table_width,current_table_row+1);
245 gtk_table_attach_defaults(current_table,
246 gtk_hseparator_new(),
247 0,current_table_width,
248 current_table_row,
249 current_table_row+1);
250 current_table_row++;
251 // gtk_table_resize(current_table,current_table_width,current_table_row+1);
252 }
get_current_table()253 GtkTable * get_current_table()
254 {
255 return current_table;
256 }
send_reload_signal()257 void send_reload_signal()
258 {
259 #ifdef USE_DBUS
260 DBusMessage *message;
261 message = dbus_message_new_signal("/","org.metascape.emerald.dbus.Signal","Reload");
262 dbus_connection_send(dbcon,message,NULL);
263 dbus_message_unref(message);
264 #else
265 Atom wmAtom = 0;
266 Display *dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
267
268 char buffer[128];
269 char *part = display_part(getenv("DISPLAY"));
270
271 sprintf(buffer, "_COMPIZ_DM_S%s", part);
272 free(part);
273
274 if (dpy)
275 wmAtom = XInternAtom(dpy,buffer,0);
276
277 if (wmAtom) {
278 XEvent clientEvent;
279 Status missed;
280 Window w = XGetSelectionOwner(dpy,wmAtom);
281 Atom ReloadIt = XInternAtom(dpy, "emerald-sigusr1", 0);
282 clientEvent.xclient.type = ClientMessage;
283 clientEvent.xclient.window = w;
284 clientEvent.xclient.message_type = ReloadIt;
285 clientEvent.xclient.format = 32;
286 clientEvent.xclient.display = dpy;
287 clientEvent.xclient.data.l[0] = 0;
288 clientEvent.xclient.data.l[1] = 0;
289 clientEvent.xclient.data.l[2] = 0;
290 clientEvent.xclient.data.l[3] = 0;
291 clientEvent.xclient.data.l[4] = 0;
292 missed = XSendEvent(dpy,w,
293 False,
294 NoEventMask,
295 &clientEvent);
296 XSync (dpy, False);
297 } else {
298 /* The old way */
299 gchar * args[]=
300 {"killall","-u",(gchar *)g_get_user_name(),"-SIGUSR1","emerald",NULL};
301 gchar * ret=NULL;
302 if (!g_spawn_sync(NULL,args,NULL,G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_SEARCH_PATH,
303 NULL,NULL,&ret,NULL,NULL,NULL) || !ret)
304 g_warning("Couldn't find running emerald, no reload signal sent.");
305 }
306 #endif
307 }
apply_settings()308 void apply_settings()
309 {
310 gchar * file = g_strjoin("/",g_get_home_dir(),".emerald/theme/theme.ini",NULL);
311 gchar * path = g_strjoin("/",g_get_home_dir(),".emerald/theme/",NULL);
312 gchar * at;
313 g_slist_foreach(SettingList,(GFunc) write_setting,global_theme_file);
314 g_key_file_set_string(global_theme_file,"theme","version",VERSION);
315 g_mkdir_with_parents(path,00755);
316 at = g_key_file_to_data(global_theme_file,NULL,NULL);
317 if (at)
318 {
319 g_file_set_contents(file,at,-1,NULL);
320 g_free(at);
321 }
322 g_free(file);
323 g_free(path);
324 send_reload_signal();
325 }
cb_apply_setting(GtkWidget * w,gpointer p)326 void cb_apply_setting(GtkWidget * w, gpointer p)
327 {
328 SettingItem * item = p;
329 if (item->type == ST_IMG_FILE)
330 {
331 gchar * s;
332 if (!(s=gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(item->widget))))
333 return; // for now just ignore setting it to an invalid name
334 if (!strcmp(s,item->fvalue))
335 {
336 g_free(s);
337 return;
338 }
339 g_free(item->fvalue);
340 item->fvalue=s;
341 check_file(item,s);
342 }
343 write_setting(p,(gpointer) global_theme_file);
344 if (apply)
345 apply_settings();
346 else
347 {
348 changed=TRUE;
349 }
350 }
351 #ifdef USE_DBUS
setup_dbus()352 void setup_dbus()
353 {
354 dbcon = dbus_bus_get (DBUS_BUS_SESSION,NULL);
355 dbus_connection_setup_with_g_main(dbcon,NULL);
356 }
357 #endif
write_setting(SettingItem * item,gpointer p)358 void write_setting(SettingItem * item, gpointer p)
359 {
360 GKeyFile * f = (GKeyFile *) p;
361 switch(item->type)
362 {
363 case ST_BOOL:
364 g_key_file_set_boolean(f,item->section,item->key,get_bool(item));
365 break;
366 case ST_INT:
367 g_key_file_set_integer(f,item->section,item->key,get_int(item));
368 break;
369 case ST_FLOAT:
370 g_key_file_set_string(f,item->section,item->key,get_float_str(item));
371 break;
372 case ST_COLOR:
373 g_key_file_set_string(f,item->section,item->key,get_color(item));
374 break;
375 case ST_FONT:
376 g_key_file_set_string(f,item->section,item->key,get_font(item));
377 break;
378 case ST_META_STRING:
379 g_key_file_set_string(f,item->section,item->key,get_string(item));
380 break;
381 case ST_STRING_COMBO:
382 g_key_file_set_string(f,item->section,item->key,get_string_combo(item));
383 break;
384 case ST_IMG_FILE:
385 //g_key_file_set_string(f,item->section,item->key,get_img_file(item));
386 {
387 gchar * s = g_strdup_printf("%s/.emerald/theme/%s.%s.png",g_get_home_dir(),item->section,item->key);
388 GdkPixbuf * pbuf = gtk_image_get_pixbuf(item->image);
389 if (pbuf)
390 {
391 gdk_pixbuf_savev(pbuf,s,"png",NULL,NULL,NULL);
392 }
393 else
394 {
395 g_unlink(s); // to really clear out a clear'd image
396 }
397 g_free(s);
398 }
399 break;
400 case ST_ENGINE_COMBO:
401 {
402 EngineMetaInfo emi;
403 const gchar * active_engine = get_engine_combo(item);
404 if (get_engine_meta_info(active_engine,&emi))
405 g_key_file_set_string(f,"engine_version",active_engine,emi.version);
406 g_key_file_set_string(f,item->section,item->key,active_engine);
407 do_engine(active_engine);
408 }
409 break;
410 case ST_SFILE_INT:
411 if (f==global_theme_file)
412 {
413 g_key_file_set_integer(global_settings_file,item->section,
414 item->key,get_int(item));
415 write_setting_file();
416 }
417 break;
418 case ST_SFILE_BOOL:
419 if (f==global_theme_file)
420 {
421 g_key_file_set_boolean(global_settings_file,item->section,
422 item->key,get_bool(item));
423 write_setting_file();
424 }
425 break;
426 case ST_SFILE_INT_COMBO:
427 if (f==global_theme_file)
428 {
429 g_key_file_set_integer(global_settings_file,item->section,
430 item->key,get_sf_int_combo(item));
431 write_setting_file();
432 }
433 break;
434 default:
435 break;
436 //unhandled types
437 }
438 }
write_setting_file()439 void write_setting_file()
440 {
441 gchar * file = g_strjoin("/",g_get_home_dir(),".emerald/settings.ini",NULL);
442 gchar * path = g_strjoin("/",g_get_home_dir(),".emerald/",NULL);
443 gchar * at;
444 g_mkdir_with_parents(path,00755);
445 at = g_key_file_to_data(global_settings_file,NULL,NULL);
446 if (at)
447 {
448 g_file_set_contents(file,at,-1,NULL);
449 g_free(at);
450 }
451 g_free(file);
452 g_free(path);
453 }
454
455 gchar * globalStr = NULL;
456 gchar globalFloatStr[G_ASCII_DTOSTR_BUF_SIZE+1];
457
get_bool(SettingItem * item)458 gboolean get_bool(SettingItem * item)
459 {
460 return gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(item->widget));
461 }
get_float(SettingItem * item)462 gdouble get_float(SettingItem * item)
463 {
464 if(!strcmp(G_OBJECT_TYPE_NAME(item->widget),"GtkSpinButton")) {
465 return gtk_spin_button_get_value((GtkSpinButton *)item->widget);
466 }
467 else {
468 return gtk_range_get_value(GTK_RANGE(item->widget));
469 }
470 }
get_int(SettingItem * item)471 gint get_int(SettingItem * item)
472 {
473 return get_float(item);
474 }
get_float_str(SettingItem * item)475 const gchar * get_float_str(SettingItem * item)
476 {
477 g_ascii_dtostr(globalFloatStr,G_ASCII_DTOSTR_BUF_SIZE,
478 get_float(item));
479 return globalFloatStr;
480 }
get_color(SettingItem * item)481 const gchar * get_color(SettingItem * item)
482 {
483 GdkColor c;
484 if (globalStr)
485 g_free(globalStr);
486 gtk_color_button_get_color(GTK_COLOR_BUTTON(item->widget),&c);
487 globalStr = g_strdup_printf("#%02x%02x%02x",c.red>>8,c.green>>8,c.blue>>8);
488 return globalStr;
489 }
get_font(SettingItem * item)490 const gchar * get_font(SettingItem * item)
491 {
492 return gtk_font_button_get_font_name(GTK_FONT_BUTTON(item->widget));
493 }
get_string(SettingItem * item)494 const gchar * get_string(SettingItem * item)
495 {
496 return gtk_entry_get_text(GTK_ENTRY(item->widget));
497 }
check_file(SettingItem * item,gchar * f)498 void check_file(SettingItem * item,gchar * f)
499 {
500 GdkPixbuf * p;
501 p = gdk_pixbuf_new_from_file(f,NULL);
502 if(p)
503 {
504 gtk_image_set_from_pixbuf(item->image,p);
505 gtk_image_set_from_pixbuf(item->preview,p);
506 }
507 else
508 {
509 gtk_image_clear(item->image);
510 gtk_image_clear(item->preview);
511 }
512 if(p)
513 g_object_unref(p);
514 }
get_img_file(SettingItem * item)515 const gchar * get_img_file(SettingItem * item)
516 {
517 return item->fvalue;
518 }
get_string_combo(SettingItem * item)519 const gchar * get_string_combo(SettingItem * item)
520 {
521 const gchar * s;
522 s= gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(item->widget))));
523 if (strlen(s))
524 return s;
525 s="IT::HNXC:Default Layout (Blank Entry)";
526 return s;
527 }
show_engine_named(EngineData * d,gpointer p)528 void show_engine_named(EngineData * d, gpointer p)
529 {
530 gchar * nam = p;
531 if (!strcmp(nam,d->canname))
532 {
533 gtk_container_add(GTK_CONTAINER(EngineContainer),d->vbox);
534 gtk_widget_show_all(EngineContainer);
535 }
536 }
do_engine(const gchar * nam)537 void do_engine(const gchar * nam)
538 {
539 GtkWidget * w;
540 if (active_engine && !strcmp(active_engine,nam))
541 return;
542 if (active_engine)
543 g_free(active_engine);
544 active_engine = g_strdup(nam);
545 if ((w=gtk_bin_get_child(GTK_BIN(EngineContainer))))
546 gtk_container_remove(GTK_CONTAINER(EngineContainer),w);
547 g_slist_foreach(EngineList,(GFunc) show_engine_named, (gpointer) nam);
548
549 }
search_engine(EngineData * d,gpointer p)550 void search_engine(EngineData * d, gpointer p)
551 {
552 FindEngine * fe = p;
553 if (!fe->found)
554 {
555 if (!strcmp(d->canname,fe->canname))
556 {
557 fe->d = d;
558 fe->found=TRUE;
559 }
560 else
561 fe->i++;
562 }
563 }
get_engine_meta_info(const gchar * engine,EngineMetaInfo * inf)564 gboolean get_engine_meta_info(const gchar * engine, EngineMetaInfo * inf)
565 {
566 FindEngine fe;
567 fe.canname = engine;
568 fe.found = FALSE;
569 fe.i=0;
570 fe.d=NULL;
571 g_slist_foreach(EngineList,(GFunc) search_engine, &fe);
572 if (fe.found)
573 memcpy(inf,&(fe.d->meta),sizeof(EngineMetaInfo));
574 return fe.found;
575 }
set_engine_combo(SettingItem * item,gchar * val)576 void set_engine_combo(SettingItem * item, gchar * val)
577 {
578 FindEngine fe;
579 fe.canname = val;
580 fe.found=FALSE;
581 fe.i = 0;
582 g_slist_foreach(EngineList,(GFunc) search_engine,&fe);
583 if (fe.found)
584 {
585 gtk_combo_box_set_active(GTK_COMBO_BOX(item->widget),fe.i);
586 }
587 else
588 {
589 fe.canname = "legacy";
590 fe.found=FALSE;
591 fe.i=0;
592 g_slist_foreach(EngineList,(GFunc) search_engine,&fe);
593 if (fe.found)
594 gtk_combo_box_set_active(GTK_COMBO_BOX(item->widget),fe.i);
595 }
596 do_engine(fe.canname);
597 }
get_engine_combo(SettingItem * item)598 const gchar * get_engine_combo(SettingItem * item)
599 {
600 static gchar * s = NULL;
601 GtkTreeIter i;
602 if(s) g_free(s);
603 //s = gtk_combo_box_get_active_text(GTK_COMBO_BOX(item->widget));
604 if (gtk_combo_box_get_active_iter(GTK_COMBO_BOX(item->widget),&i))
605 {
606 gtk_tree_model_get(GTK_TREE_MODEL(EngineModel),&i,ENGINE_COL_NAME,&s,-1);
607 if (!strlen(s))
608 {
609 g_free(s);
610 s=g_strdup("legacy");
611 }
612 }
613 return s;
614 }
get_sf_int_combo(SettingItem * item)615 gint get_sf_int_combo(SettingItem * item)
616 {
617 return gtk_combo_box_get_active(GTK_COMBO_BOX(item->widget));
618 }
update_preview(GtkFileChooser * fc,gchar * filename,GtkImage * img)619 void update_preview(GtkFileChooser * fc, gchar * filename, GtkImage * img)
620 {
621 GdkPixbuf * pixbuf;
622 gboolean have_preview;
623 pixbuf = gdk_pixbuf_new_from_file(filename,NULL);
624 have_preview = (pixbuf != NULL);
625 gtk_image_set_from_pixbuf(GTK_IMAGE(img),pixbuf);
626 if (pixbuf)
627 g_object_unref(pixbuf);
628 gtk_file_chooser_set_preview_widget_active(fc,have_preview);
629 }
update_preview_cb(GtkFileChooser * file_chooser,gpointer data)630 void update_preview_cb(GtkFileChooser * file_chooser, gpointer data)
631 {
632 gchar * filename;
633 filename = gtk_file_chooser_get_preview_filename(file_chooser);
634 update_preview(file_chooser,filename,GTK_IMAGE(data));
635 g_free(filename);
636 }
set_img_file(SettingItem * item,gchar * f)637 void set_img_file(SettingItem * item,gchar * f)
638 {
639 g_free(item->fvalue);
640 item->fvalue = g_strdup(f);
641 gtk_file_chooser_select_filename(GTK_FILE_CHOOSER(item->widget),f);
642 check_file(item,f);
643 }
set_bool(SettingItem * item,gboolean b)644 void set_bool(SettingItem * item, gboolean b)
645 {
646 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(item->widget),b);
647 }
set_float(SettingItem * item,gdouble f)648 void set_float(SettingItem * item, gdouble f)
649 {
650 if(!strcmp(G_OBJECT_TYPE_NAME(item->widget),"GtkSpinButton")) {
651 gtk_spin_button_set_value((GtkSpinButton *)item->widget, f);
652 }
653 else {
654 gtk_range_set_value(GTK_RANGE(item->widget),f);
655 }
656 }
set_int(SettingItem * item,gint i)657 void set_int(SettingItem * item, gint i)
658 {
659 set_float(item,i);
660 }
set_float_str(SettingItem * item,gchar * s)661 void set_float_str(SettingItem * item, gchar * s)
662 {
663 set_float(item,g_ascii_strtod(s,NULL));
664 }
set_color(SettingItem * item,gchar * s)665 void set_color(SettingItem * item, gchar * s)
666 {
667 GdkColor c;
668 gdk_color_parse(s,&c);
669 gtk_color_button_set_color(GTK_COLOR_BUTTON(item->widget),&c);
670 }
set_font(SettingItem * item,gchar * f)671 void set_font(SettingItem * item, gchar * f)
672 {
673 gtk_font_button_set_font_name(GTK_FONT_BUTTON(item->widget),f);
674 }
set_string(SettingItem * item,gchar * s)675 void set_string(SettingItem * item, gchar * s)
676 {
677 gtk_entry_set_text(GTK_ENTRY(item->widget),s);
678 }
set_string_combo(SettingItem * item,gchar * s)679 void set_string_combo(SettingItem * item, gchar * s)
680 {
681 gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(item->widget))),s);
682 }
set_sf_int_combo(SettingItem * item,gint i)683 void set_sf_int_combo(SettingItem * item, gint i)
684 {
685 gtk_combo_box_set_active(GTK_COMBO_BOX(item->widget),i);
686 }
read_setting(SettingItem * item,gpointer * p)687 void read_setting(SettingItem * item, gpointer * p)
688 {
689 GKeyFile * f = (GKeyFile *) p;
690 GError * e = NULL;
691 gboolean b;
692 gint i;
693 gchar * s;
694 switch(item->type)
695 {
696 case ST_BOOL:
697 b = g_key_file_get_boolean(f,item->section,item->key,&e);
698 if (!e)
699 set_bool(item,b);
700 break;
701 case ST_INT:
702 i = g_key_file_get_integer(f,item->section,item->key,&e);
703 if (!e)
704 set_int(item,i);
705 break;
706 case ST_FLOAT:
707 s = g_key_file_get_string(f,item->section,item->key,&e);
708 if (!e && s)
709 {
710 set_float_str(item,s);
711 g_free(s);
712 }
713 break;
714 case ST_COLOR:
715 s = g_key_file_get_string(f,item->section,item->key,&e);
716 if (!e && s)
717 {
718 set_color(item,s);
719 g_free(s);
720 }
721 break;
722 case ST_FONT:
723 s = g_key_file_get_string(f,item->section,item->key,&e);
724 if (!e && s)
725 {
726 set_font(item,s);
727 g_free(s);
728 }
729 break;
730 case ST_META_STRING:
731 s = g_key_file_get_string(f,item->section,item->key,&e);
732 if (!e && s)
733 {
734 set_string(item,s);
735 g_free(s);
736 }
737 break;
738 case ST_STRING_COMBO:
739 s = g_key_file_get_string(f,item->section,item->key,&e);
740 if (!e && s)
741 {
742 set_string_combo(item,s);
743 g_free(s);
744 }
745 break;
746 case ST_IMG_FILE:
747 /*s = g_key_file_get_string(f,item->section,item->key,&e);
748 if (!e && s)
749 {
750 set_img_file(item,s);
751 g_free(s);
752 }*/
753 s = g_strdup_printf("%s/.emerald/theme/%s.%s.png",g_get_home_dir(),item->section,item->key);
754 set_img_file(item,s);
755 g_free(s);
756 break;
757 case ST_ENGINE_COMBO:
758 s = g_key_file_get_string(f,item->section,item->key,&e);
759 if (!e && s)
760 {
761 set_engine_combo(item,s);
762 g_free(s);
763 }
764 break;
765 case ST_SFILE_INT:
766 if (f==global_theme_file)
767 {
768 i = g_key_file_get_integer(global_settings_file,
769 item->section,item->key,&e);
770 if (!e)
771 set_int(item,i);
772 }
773 break;
774 case ST_SFILE_BOOL:
775 if (f==global_theme_file)
776 {
777 b = g_key_file_get_boolean(global_settings_file,
778 item->section,item->key,&e);
779 if (!e)
780 set_bool(item,b);
781 }
782 break;
783 case ST_SFILE_INT_COMBO:
784 if (f==global_theme_file)
785 {
786 i = g_key_file_get_integer(global_settings_file,
787 item->section,item->key,&e);
788 if (!e)
789 set_sf_int_combo(item,i);
790 }
791 break;
792 default:
793 break;
794 //unhandled types
795 }
796 }
init_settings()797 void init_settings()
798 {
799 gchar * file = g_strjoin("/",g_get_home_dir(),".emerald/theme/theme.ini",NULL);
800 g_key_file_load_from_file(global_theme_file,file,G_KEY_FILE_KEEP_COMMENTS,NULL);
801 g_free(file);
802 file = g_strjoin("/",g_get_home_dir(),".emerald/settings.ini",NULL);
803 g_key_file_load_from_file(global_settings_file,file,G_KEY_FILE_KEEP_COMMENTS,NULL);
804 g_free(file);
805 g_slist_foreach(SettingList,(GFunc) read_setting,global_theme_file);
806 }
807
set_changed(gboolean schanged)808 void set_changed(gboolean schanged)
809 {
810 changed=schanged;
811 }
set_apply(gboolean sapply)812 void set_apply(gboolean sapply)
813 {
814 apply=sapply;
815 }
cb_clear_file(GtkWidget * button,gpointer p)816 void cb_clear_file(GtkWidget * button, gpointer p)
817 {
818 SettingItem * item = p;
819 check_file(item,"");
820 item->fvalue="";
821 gtk_file_chooser_unselect_all(GTK_FILE_CHOOSER(item->widget));
822 write_setting(p,global_theme_file);
823 if (apply) apply_settings();
824 }
init_key_files()825 void init_key_files()
826 {
827 global_theme_file = g_key_file_new();
828 global_settings_file = g_key_file_new();
829 }
layout_engine_list(GtkWidget * vbox)830 void layout_engine_list(GtkWidget * vbox)
831 {
832 GtkWidget * hbox;
833 EngineCombo = gtk_combo_box_new();
834 hbox = gtk_hbox_new(FALSE,2);
835 gtk_box_pack_startC(vbox,hbox,FALSE,FALSE,0);
836 gtk_box_pack_startC(hbox,gtk_label_new(_("Select\nEngine")),FALSE,FALSE,0);
837 gtk_box_pack_startC(hbox,EngineCombo,FALSE,FALSE,0);
838 gtk_box_pack_startC(vbox,gtk_hseparator_new(),FALSE,FALSE,0);
839 EngineContainer = gtk_alignment_new(0,0,1,1); // really only needed for the bin-ness
840 gtk_box_pack_startC(vbox,EngineContainer,TRUE,TRUE,0);
841 }
canonize_name(gchar * dlname)842 static gchar * canonize_name(gchar * dlname)
843 {
844 gchar * end;
845 gchar * begin = g_strrstr(dlname,"/lib");
846 if (!begin)
847 return g_strdup("");
848 begin+=4;
849 begin = g_strdup(begin);
850 end = g_strrstr(begin,".so");
851 end[0]='\0';
852 return begin;
853 }
engine_comp(EngineData * d,gpointer p)854 static void engine_comp(EngineData * d,gpointer p)
855 {
856 FindEngine * e = p;
857 if (!strcmp(e->canname, d->canname))
858 e->found=TRUE;
859 }
engine_is_unique(gchar * canname)860 static gboolean engine_is_unique (gchar * canname)
861 {
862 FindEngine e;
863 e.canname=canname;
864 e.found=FALSE;
865 g_slist_foreach(EngineList,(GFunc)engine_comp,&e);
866 return !e.found;
867 }
append_engine(gchar * dlname)868 static void append_engine(gchar * dlname)
869 {
870 gchar * can;
871 gchar * err;
872 (void) dlerror();
873 void * hand = dlopen(dlname,RTLD_NOW);
874 err = dlerror();
875 if (!hand || err)
876 {
877 g_warning("%s", err);
878 if (hand)
879 dlclose(hand);
880 return;
881 }
882 can = canonize_name(dlname);
883 if (engine_is_unique(can))
884 {
885 layout_settings_proc lay;
886 lay = dlsym(hand,"layout_engine_settings");
887 if ((err=dlerror()))
888 g_warning("%s", err);
889 if (lay)
890 {
891 get_meta_info_proc meta;
892 EngineData * d = malloc(sizeof(EngineData));
893 GtkTreeIter i;
894 const gchar * format =
895 "<b>%s</b> (%s)\n"
896 "<i><small>%s</small></i>";
897 meta = dlsym(hand,"get_meta_info");
898 if ((err=dlerror()))
899 g_warning("%s", err);
900 d->meta.description=g_strdup("No Description");
901 d->meta.version=g_strdup("0.0");
902 d->meta.last_compat=g_strdup("0.0");
903 d->meta.icon=gtk_widget_render_icon(EngineCombo,GTK_STOCK_MISSING_IMAGE,
904 GTK_ICON_SIZE_LARGE_TOOLBAR,"themeengine");
905 if (meta)
906 meta(&(d->meta));
907 else
908 g_warning("Engine %s has no meta info, please update it, using defaults.",dlname);
909
910 d->dlname = dlname;
911 d->canname = can;
912 d->vbox = gtk_vbox_new(FALSE,2);
913 g_object_ref(d->vbox);
914 lay(d->vbox);
915 EngineList = g_slist_append(EngineList,d);
916 gtk_list_store_append(EngineModel,&i);
917
918 gtk_list_store_set(EngineModel,&i,ENGINE_COL_DLNAME,d->dlname,ENGINE_COL_NAME,d->canname,
919 ENGINE_COL_VER,d->meta.version,ENGINE_COL_LAST_COMPAT,d->meta.last_compat,
920 ENGINE_COL_ICON,d->meta.icon,ENGINE_COL_MARKUP,
921 g_markup_printf_escaped(format,d->canname,d->meta.version,d->meta.description),
922 -1);
923 //gtk_combo_box_prepend_text(GTK_COMBO_BOX(EngineCombo),d->canname);
924 }
925 }
926 dlclose(hand);
927 }
engine_scan_dir(gchar * dir)928 static void engine_scan_dir(gchar * dir)
929 {
930 GDir * d;
931 d = g_dir_open(dir,0,NULL);
932 if (d)
933 {
934 gchar * n;
935 GPatternSpec * ps;
936 ps = g_pattern_spec_new("lib*.so");
937 while ((n = (gchar *) g_dir_read_name(d)))
938 {
939 if (g_pattern_match_string(ps,n))
940 {
941 gchar * dln = g_strjoin("/",dir,n,NULL);
942 append_engine(dln);
943 }
944 }
945 g_pattern_spec_free(ps);
946 g_dir_close(d);
947 }
948 }
init_engine_list()949 void init_engine_list()
950 {
951 //presumes the container & combo are created
952 //presumes the combo is NOT registered
953 GtkCellRenderer * r;
954
955 EngineModel = gtk_list_store_new(ENGINE_COL_COUNT,G_TYPE_STRING,
956 G_TYPE_STRING,G_TYPE_STRING,G_TYPE_STRING,G_TYPE_STRING,GDK_TYPE_PIXBUF);
957 gchar * local_engine_dir = g_strjoin("/",g_get_home_dir(),".emerald/engines",NULL);
958 gtk_combo_box_set_model(GTK_COMBO_BOX(EngineCombo),GTK_TREE_MODEL(EngineModel));
959 r = gtk_cell_renderer_pixbuf_new();
960 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(EngineCombo),r,FALSE);
961 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(EngineCombo),r,"pixbuf",ENGINE_COL_ICON);
962 r = gtk_cell_renderer_text_new();
963 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(EngineCombo),r,TRUE);
964 gtk_cell_layout_add_attribute(GTK_CELL_LAYOUT(EngineCombo),r,"markup",ENGINE_COL_MARKUP);
965 engine_scan_dir(local_engine_dir);
966 g_free(local_engine_dir);
967 engine_scan_dir(ENGINE_DIR);
968
969 register_setting(EngineCombo,ST_ENGINE_COMBO,"engine","engine");
970 }
build_notebook_page(gchar * title,GtkWidget * notebook)971 GtkWidget * build_notebook_page(gchar * title, GtkWidget * notebook)
972 {
973 GtkWidget * vbox;
974 vbox = gtk_vbox_new(FALSE,2);
975 gtk_container_set_border_widthC(vbox,8);
976 gtk_notebook_append_page(GTK_NOTEBOOK(notebook),vbox,
977 gtk_label_new(title));
978 return vbox;
979 }
980
981