1 /*
2 * (SLIK) SimpLIstic sKin functions
3 * (C) 2005 John Ellis
4 *
5 * Author: 5ohn Ellis
6 *
7 * This software is released under the GNU General Public License (GNU GPL).
8 * Please read the included file COPYING for more information.
9 * This software comes with no warranty of any kind, use at your own risk!
10 */
11
12 #include "ui2_includes.h"
13 #include "ui2_typedefs.h"
14 #include "ui2_main.h"
15
16 #include "ui2_button.h"
17 #include "ui2_decal.h"
18 #include "ui2_display.h"
19 #include "ui2_parse.h"
20 #include "ui2_skin.h"
21 #include "ui2_util.h"
22 #include "ui2_widget.h"
23 #include "ui_fileops.h"
24 #include "ui_misc.h"
25 #include "ui_utildlg.h"
26
27 #include "ui2_logo.h"
28
29 /* these two includes are _only_ used in ui_iconify() */
30 #include <gdk/gdkx.h>
31 #include <X11/Xlib.h>
32
33
34 /*
35 *-------------
36 * yes, these are globals
37 *-------------
38 */
39
40 gint slik_smart_placement = TRUE;
41 gint slik_remember_position = FALSE;
42
43 gint slik_focus_enable = TRUE;
44
45 gint slik_double_size = FALSE;
46
47 gint slik_scale = FALSE;
48 gfloat slik_scale_value = 1.0;
49 gint slik_allow_shapes = TRUE;
50
51 gint slik_colorshift_r = 128;
52 gint slik_colorshift_g = 128;
53 gint slik_colorshift_b = 128;
54 gint slik_colorshift_a = 128;
55 gint slik_colorshift_on = FALSE;
56
57 gint slik_transparency_force = FALSE;
58 gint slik_transparency_force_a = 192;
59
60 gint debug_mode = FALSE;
61 gint debug_skin = FALSE;
62
63 /* list of all windows created with ui_new() */
64 static GList *slik_ui_list = NULL;
65
66
67 /*
68 *-------------
69 * misc
70 *-------------
71 */
72
window_set_icon(GtkWidget * window,const char ** icon,const gchar * file,GdkPixbuf * pixbuf)73 void window_set_icon(GtkWidget *window, const char **icon, const gchar *file, GdkPixbuf *pixbuf)
74 {
75 GdkPixbuf *pb;
76
77 if (icon)
78 {
79 pb = gdk_pixbuf_new_from_xpm_data(icon);
80 }
81 else if (file)
82 {
83 pb = util_pixbuf_new_from_file(file);
84 }
85 else
86 {
87 pb = pixbuf;
88 if (pb)
89 {
90 gdk_pixbuf_ref(pb);
91 }
92 else
93 {
94 pb = ui_slik_logo();
95 }
96 }
97
98 if (!pb) return;
99 gtk_window_set_icon(GTK_WINDOW(window), pb);
100 gdk_pixbuf_unref(pb);
101 }
102
ui_set_icon(UIData * ui,const char ** icon,const gchar * file,GdkPixbuf * pixbuf)103 void ui_set_icon(UIData *ui, const char **icon, const gchar *file, GdkPixbuf *pixbuf)
104 {
105 if (!ui || !ui->window) return;
106
107 window_set_icon(ui->window, icon, file, pixbuf);
108 }
109
ui_iconify(UIData * ui)110 void ui_iconify(UIData *ui)
111 {
112 Window xwindow;
113
114 if (!ui || !ui->window->window) return;
115
116 xwindow = GDK_WINDOW_XWINDOW(ui->window->window);
117 XIconifyWindow (GDK_DISPLAY (), xwindow, DefaultScreen (GDK_DISPLAY ()));
118 }
119
ui_mode_unique(UIData * ui,const gchar * mode_key)120 static gint ui_mode_unique(UIData *ui, const gchar *mode_key)
121 {
122 GList *work;
123
124 if (!mode_key) return FALSE;
125
126 if (ui->parent) ui = ui->parent;
127
128 if (strcmp(mode_key, "skindata") == 0) return FALSE;
129 if (ui->skin_mode_key && strcmp(ui->skin_mode_key, mode_key) == 0) return FALSE;
130 if (ui->key && strcmp(ui->key, mode_key) == 0) return FALSE;
131
132 work = ui->children;
133 while (work)
134 {
135 UIData *child;
136
137 child = work->data;
138 work = work->next;
139
140 if (child->key && strcmp(child->key, mode_key) == 0) return FALSE;
141 }
142
143 return TRUE;
144 }
145
146 /*
147 *-------------
148 * these are the reserved widgets for window resizing and skin mode toggles.
149 *-------------
150 */
151
ui_skin_toggle_click_cb(ButtonData * button,const gchar * key,gpointer data)152 static void ui_skin_toggle_click_cb(ButtonData *button, const gchar *key, gpointer data)
153 {
154 UIData *ui = data;
155 const gchar *mode_key;
156
157 /* luckily, the editor disables this button, no need to handle ui->edit */
158
159 mode_key = ui_widget_get_data_by_widget(ui, button);
160
161 if (debug_mode) printf("Setting skin mode key = \"%s\"\n", mode_key);
162
163 ui_skin_mode_set(ui, mode_key);
164 }
165
ui_skin_expand_status_cb(ButtonData * button,const gchar * key,gpointer data)166 static gint ui_skin_expand_status_cb(ButtonData *button, const gchar *key, gpointer data)
167 {
168 UIData *ui = data;
169 SkinData *skin;
170
171 skin = ui->skin;
172
173 return (skin->width != skin->width_def || skin->height != skin->height_def);
174 }
175
ui_skin_expand_click_cb(ButtonData * button,const gchar * key,gpointer data)176 static void ui_skin_expand_click_cb(ButtonData *button, const gchar *key, gpointer data)
177 {
178 UIData *ui = data;
179 const gchar *text;
180 gint w, h;
181
182 text = ui_widget_get_data_by_widget(ui, button);
183
184 /* we must support the editor */
185 if (!text && ui->edit && skin_widget_get_by_widget(ui->skin, button) == NULL)
186 {
187 text = ui_widget_get_data_by_widget(ui->edit, button);
188 ui = ui->edit;
189 }
190
191 if (debug_mode) printf("Skin expand data = \"%s\"\n", text);
192
193 if (text && sscanf(text, "%i %i", &w, &h) == 2)
194 {
195 SkinData *skin = ui->skin;
196 gint state;
197
198 if (skin->width == skin->width_def && skin->height == skin->height_def)
199 {
200 util_size(&w);
201 util_size(&h);
202
203 /* do the expand (can be negative too) */
204 skin_resize(ui, skin->width + w, skin->height + h);
205 state = TRUE;
206 }
207 else
208 {
209 /* assume expanded, snap back to default */
210 skin_resize(ui, skin->width_def, skin->height_def);
211 state = FALSE;
212 }
213 button_state_set("skin_expand", ui, state);
214 }
215 }
216
ui_spawn_child(UIData * parent,const gchar * key,const gchar * title,const gchar * mode_key)217 UIData *ui_spawn_child(UIData *parent, const gchar *key, const gchar *title, const gchar *mode_key)
218 {
219 UIData *child;
220 SkinData *skin;
221
222 if (!key) return NULL;
223
224 if (parent->parent) parent = parent->parent;
225
226 if (debug_mode) printf("ui2_main.c: opening skin \"%s\"for addition as \"%s\"\n", (mode_key) ? mode_key : "default", key);
227
228 if (parent->skin_path)
229 {
230 gchar *datafile;
231
232 datafile = g_strconcat(parent->skin_path, "/", (mode_key) ? mode_key : "skindata", NULL);
233 skin = skin_parse(parent->skin_path, datafile, FALSE);
234 g_free(datafile);
235 }
236 else
237 {
238 if (parent->skin_func)
239 {
240 skin = parent->skin_func(parent, mode_key, parent->skin_data);
241 }
242 else
243 {
244 skin = NULL;
245 }
246 }
247
248 if (!skin)
249 {
250 printf("ui2_main.c: failed to open skin \"%s\"for spawned window\n", mode_key);
251 return NULL;
252 }
253
254 child = ui_new(parent->class, key, parent->decorations, parent->class);
255 ui_title_set(child, title);
256 child->allow_move = parent->allow_move;
257
258 /* copy a few things from parent, it is up to the application to determine if
259 * the UI in the callback(s) is the parent.
260 */
261 child->click_func = parent->click_func;
262 child->click_data = parent->click_data;
263
264 child->skin_func = parent->skin_func;
265 child->skin_data = parent->skin_data;
266
267 child->back_func = parent->back_func;
268 child->back_data = parent->back_data;
269
270 child->new_window_func = parent->new_window_func;
271 child->new_window_data = parent->new_window_data;
272
273 child->new_skin_func = parent->new_skin_func;
274 child->new_skin_data = parent->new_skin_data;
275
276 ui_group_set_child(parent, child);
277
278 ui_skin_set(child, skin, parent->skin_path, mode_key);
279
280 if (parent->new_window_func)
281 {
282 parent->new_window_func(child, child->key, parent->new_window_data);
283 }
284
285 return child;
286 }
287
ui_skin_open_click_cb(ButtonData * button,const gchar * key,gpointer data)288 static void ui_skin_open_click_cb(ButtonData *button, const gchar *key, gpointer data)
289 {
290 UIData *ui = data;
291 UIData *child;
292 const gchar *mode_key;
293
294 mode_key = ui_widget_get_data_by_widget(ui, button);
295
296 if (!mode_key || strlen(mode_key) == 0)
297 {
298 printf("ui2_main.c: skin_open requires valid mode key\n");
299 return;
300 }
301
302 if (!ui_mode_unique(ui, mode_key)) return;
303
304 if (debug_mode) printf("ui2_main.c: opening skin \"%s\"for addition\n", mode_key);
305
306 child = ui_spawn_child(ui, mode_key, NULL, mode_key);
307 if (child)
308 {
309 gtk_widget_show(child->window);
310 }
311 }
312
ui_skin_close_click_cb(ButtonData * button,const gchar * key,gpointer data)313 static void ui_skin_close_click_cb(ButtonData *button, const gchar *key, gpointer data)
314 {
315 UIData *ui = data;
316
317 if (!ui->parent) return;
318
319 if (debug_mode) printf("ui2_main.c: closing skin \"%s\"\n", ui->skin_mode_key);
320
321 ui_close(ui);
322 }
323
ui_skin_iconify_click_cb(ButtonData * button,const gchar * key,gpointer data)324 static void ui_skin_iconify_click_cb(ButtonData *button, const gchar *key, gpointer data)
325 {
326 UIData *ui = data;
327
328 if (ui->allow_move) ui_iconify(ui);
329 }
330
ui_skin_sticky_update_cb(WidgetData * wd,gpointer data,UIData * ui)331 static void ui_skin_sticky_update_cb(WidgetData *wd, gpointer data, UIData *ui)
332 {
333 ui_widget_draw(ui, wd, TRUE, FALSE);
334 }
335
ui_skin_sticky_update(UIData * ui)336 static void ui_skin_sticky_update(UIData *ui)
337 {
338 ui_widget_for_each_key_one(ui, "skin_sticky", button_type_id(),
339 ui_skin_sticky_update_cb, NULL);
340 }
341
ui_skin_sticky_status_cb(ButtonData * button,const gchar * key,gpointer data)342 static gint ui_skin_sticky_status_cb(ButtonData *button, const gchar *key, gpointer data)
343 {
344 UIData *ui = data;
345
346 return ui->sticky;
347 }
348
ui_skin_sticky_click_cb(ButtonData * button,const gchar * key,gpointer data)349 static void ui_skin_sticky_click_cb(ButtonData *button, const gchar *key, gpointer data)
350 {
351 UIData *ui = data;
352
353 if (!ui->window) return;
354
355 if (debug_mode) printf("setting sticky state to %d\n", !ui->sticky);
356
357 if (ui->sticky)
358 {
359 gtk_window_unstick(GTK_WINDOW(ui->window));
360 ui->sticky = FALSE;
361 }
362 else
363 {
364 gtk_window_stick(GTK_WINDOW(ui->window));
365 ui->sticky = TRUE;
366 }
367
368 ui_skin_sticky_update(ui);
369 }
370
ui_window_state_cb(GtkWidget * widget,GdkEventWindowState * event,gpointer data)371 static gboolean ui_window_state_cb(GtkWidget *widget, GdkEventWindowState *event, gpointer data)
372 {
373 UIData *ui = data;
374
375 if (event->changed_mask & GDK_WINDOW_STATE_STICKY)
376 {
377 ui->sticky = (event->new_window_state & GDK_WINDOW_STATE_STICKY);
378 ui_skin_sticky_update(ui);
379
380 if (debug_mode) printf("sticky changed: %d\n", ui->sticky);
381 }
382
383 return FALSE;
384 }
385
ui_add_reserved(UIData * ui)386 static void ui_add_reserved(UIData *ui)
387 {
388 /* ensure decals can be recognized */
389 decal_type_init();
390
391 if (!ui_registered_key_exists(ui, "skin_toggle", button_type_id()))
392 {
393 button_register_key("skin_toggle", ui,
394 NULL, NULL,
395 ui_skin_toggle_click_cb, ui,
396 NULL, NULL,
397 NULL, NULL);
398 }
399 if (!ui_registered_key_exists(ui, "skin_size", button_type_id()))
400 {
401 /* this is really a dummy register, but it makes the key show in the editor */
402 button_register_key("skin_size", ui,
403 NULL, NULL,
404 NULL, NULL,
405 NULL, NULL,
406 NULL, NULL);
407 }
408 if (!ui_registered_key_exists(ui, "skin_expand", button_type_id()))
409 {
410 button_register_key("skin_expand", ui,
411 ui_skin_expand_status_cb, ui,
412 ui_skin_expand_click_cb, ui,
413 NULL, NULL,
414 NULL, NULL);
415 }
416
417 if (!ui_registered_key_exists(ui, "skin_open", button_type_id()))
418 {
419 button_register_key("skin_open", ui,
420 NULL, NULL,
421 ui_skin_open_click_cb, ui,
422 NULL, NULL,
423 NULL, NULL);
424 }
425 if (!ui_registered_key_exists(ui, "skin_close", button_type_id()))
426 {
427 button_register_key("skin_close", ui,
428 NULL, NULL,
429 ui_skin_close_click_cb, ui,
430 NULL, NULL,
431 NULL, NULL);
432 }
433 if (!ui_registered_key_exists(ui, "skin_iconify", button_type_id()))
434 {
435 button_register_key("skin_iconify", ui,
436 NULL, NULL,
437 ui_skin_iconify_click_cb, ui,
438 NULL, NULL,
439 NULL, NULL);
440 }
441 if (!ui_registered_key_exists(ui, "skin_sticky", button_type_id()))
442 {
443 button_register_key("skin_sticky", ui,
444 ui_skin_sticky_status_cb, ui,
445 ui_skin_sticky_click_cb, ui,
446 NULL, NULL,
447 NULL, NULL);
448 }
449 }
450
451 /*
452 *-------------
453 * ui
454 *-------------
455 */
456
ui_free(UIData * ui)457 void ui_free(UIData *ui)
458 {
459 if (!ui) return;
460
461 if (!ui->destroyed)
462 {
463 printf("warning: free called for ui \"%s\" not marked as destroyed\n", ui->key);
464 }
465
466 /* close children */
467 while (ui->children)
468 {
469 UIData *child = ui->children->data;
470 ui_close(child);
471 }
472
473 /* if child, break from parent */
474 ui_group_unset_child(ui);
475
476 slik_ui_list = g_list_remove(slik_ui_list, ui);
477
478 if (ui->root_win_idle != -1) g_source_remove(ui->root_win_idle);
479 ui_register_free_all(ui);
480 skin_free(ui->skin);
481 g_free(ui->skin_path);
482 g_free(ui->skin_mode_key);
483 g_free(ui->class);
484 g_free(ui->key);
485 g_free(ui);
486 }
487
ui_hide_cb(GtkWidget * widget,gpointer data)488 static void ui_hide_cb(GtkWidget *widget, gpointer data)
489 {
490 UIData *ui = data;
491 gint x, y, w, h;
492
493 if (ui_geometry_get(ui, &x, &y, &w, &h))
494 {
495 if (debug_mode) printf("hidden \"%s\"\n", ui->key);
496 ui_state_set(filename_from_path(ui->skin_path), ui->skin_mode_key, x, y, w, h);
497 }
498 }
499
ui_destroy_cb(GtkWidget * widget,gpointer data)500 static void ui_destroy_cb(GtkWidget *widget, gpointer data)
501 {
502 UIData *ui = data;
503
504 if (debug_mode) printf("UI destroyed \"%s\"\n", ui->key);
505
506 ui->destroyed = TRUE;
507 ui_free(ui);
508 }
509
ui_real_new(const gchar * class,const gchar * key,gint decorations,const gchar * title,GtkWindowType type)510 static UIData *ui_real_new(const gchar *class, const gchar *key,
511 gint decorations, const gchar *title, GtkWindowType type)
512 {
513 UIData *ui;
514
515 ui = g_new0(UIData, 1);
516
517 ui->decorations = decorations;
518 ui->root_win_idle = -1;
519 ui->edit = NULL;
520 ui->skin = NULL;
521 ui->class = g_strdup((class) ? class : "SLIK");
522 ui->key = g_strdup(key);
523 ui->allow_move = TRUE;
524 ui->focus_enable = FALSE;
525 ui->tooltips_enable = FALSE;
526
527 ui->parent = NULL;
528 ui->children = NULL;
529
530 ui->window = gtk_window_new(type);
531 gtk_window_set_resizable(GTK_WINDOW(ui->window), FALSE);
532 gtk_container_set_border_width(GTK_CONTAINER(ui->window), 0);
533 gtk_window_set_wmclass(GTK_WINDOW(ui->window), ui->key, ui->class);
534 gtk_window_set_title(GTK_WINDOW(ui->window), title);
535
536 g_signal_connect(G_OBJECT(ui->window), "hide",
537 G_CALLBACK(ui_hide_cb), ui);
538 g_signal_connect(G_OBJECT(ui->window), "destroy",
539 G_CALLBACK(ui_destroy_cb), ui);
540 g_signal_connect(G_OBJECT(ui->window), "window_state_event",
541 G_CALLBACK(ui_window_state_cb), ui);
542
543 ui->display = gtk_drawing_area_new();
544 ui_display_events_init(ui);
545 gtk_container_add(GTK_CONTAINER(ui->window), ui->display);
546 gtk_widget_show(ui->display);
547
548 if (GTK_WIDGET_CAN_FOCUS(ui->display)) gtk_widget_grab_focus(ui->display);
549
550 if (type != GTK_WINDOW_POPUP && !ui->decorations)
551 {
552 gtk_window_set_decorated(GTK_WINDOW(ui->window), 0);
553 }
554
555 /* add the default reserved keys */
556 ui_add_reserved(ui);
557
558 slik_ui_list = g_list_append(slik_ui_list, ui);
559
560 return ui;
561 }
562
ui_new(const gchar * class,const gchar * subclass,gint decorations,const gchar * title)563 UIData *ui_new(const gchar *class, const gchar *subclass, gint decorations, const gchar *title)
564 {
565 return ui_real_new(class, subclass, decorations, title, GTK_WINDOW_TOPLEVEL);
566 }
567
ui_new_dialog(const gchar * class,const gchar * subclass,gint decorations,const gchar * title)568 UIData *ui_new_dialog(const gchar *class, const gchar *subclass, gint decorations, const gchar *title)
569 {
570 UIData *ui;
571
572 ui = ui_real_new(class, subclass, decorations, title, GTK_WINDOW_TOPLEVEL);
573 gtk_window_set_type_hint(GTK_WINDOW(ui->window), GDK_WINDOW_TYPE_HINT_DIALOG);
574
575 return ui;
576 }
577
ui_new_into_container(const gchar * class,const gchar * key,GtkWidget * widget)578 UIData *ui_new_into_container(const gchar *class, const gchar *key, GtkWidget *widget)
579 {
580 UIData *ui;
581
582 ui = g_new0(UIData, 1);
583
584 ui->decorations = FALSE;
585 ui->root_win_idle = -1;
586 ui->edit = NULL;
587 ui->skin = NULL;
588 ui->class = g_strdup((class) ? class : "SLIK");
589 ui->key = g_strdup(key);
590 ui->allow_move = FALSE;
591 ui->focus_enable = FALSE;
592 ui->tooltips_enable = FALSE;
593
594 ui->parent = NULL;
595 ui->children = NULL;
596
597 ui->window = NULL;
598
599 ui->display = gtk_drawing_area_new();
600 g_signal_connect(G_OBJECT(ui->display), "destroy",
601 G_CALLBACK(ui_destroy_cb), ui);
602
603 ui_display_events_init(ui);
604 if (widget)
605 {
606 gtk_container_add(GTK_CONTAINER(widget), ui->display);
607 }
608
609 gtk_widget_show(ui->display);
610
611 /* add the default reserved keys */
612 ui_add_reserved(ui);
613
614 slik_ui_list = g_list_append(slik_ui_list, ui);
615
616 return ui;
617 }
618
ui_close_cb(gpointer data)619 static gint ui_close_cb(gpointer data)
620 {
621 UIData *ui = data;
622
623 if (ui->window)
624 {
625 gtk_widget_destroy(ui->window);
626 }
627 else
628 {
629 gtk_widget_destroy(ui->display);
630 }
631
632 return FALSE;
633 }
634
ui_close(UIData * ui)635 void ui_close(UIData *ui)
636 {
637 if (!ui || ui->destroyed) return;
638
639 /* This may be called in the middle of a widget event (like a button press handler),
640 * and bad things may happen if the ui vanishes from under the handler, so hide the window
641 * then clean up in an idle function.
642 */
643
644 ui->destroyed = TRUE;
645 if (ui->window && GTK_WIDGET_VISIBLE(ui->window)) gtk_widget_hide(ui->window);
646
647 /* close children.
648 * this may be duplicating effort in ui free,
649 * but has the benefit immediately hiding the windows.
650 */
651 while (ui->children)
652 {
653 UIData *child = ui->children->data;
654 ui_close(child);
655 }
656
657 /* if a child, break from parent */
658 ui_group_unset_child(ui);
659
660 g_idle_add(ui_close_cb, ui);
661 }
662
ui_set_mouse_callback(UIData * ui,void (* func)(UIData * ui,gint button,guint32 time,gpointer data),gpointer data)663 void ui_set_mouse_callback(UIData *ui, void (*func)(UIData *ui, gint button, guint32 time, gpointer data), gpointer data)
664 {
665 ui->click_func = func;
666 ui->click_data = data;
667 }
668
ui_set_skin_callback(UIData * ui,SkinData * (* func)(UIData * ui,const gchar * key,gpointer data),gpointer data)669 void ui_set_skin_callback(UIData *ui, SkinData *(*func)(UIData *ui, const gchar *key, gpointer data), gpointer data)
670 {
671 ui->skin_func = func;
672 ui->skin_data = data;
673 }
674
ui_set_back_callback(UIData * ui,gint (* func)(UIData * ui,GdkPixbuf * pixbuf,gpointer data),gpointer data)675 void ui_set_back_callback(UIData *ui, gint (*func)(UIData *ui, GdkPixbuf *pixbuf, gpointer data), gpointer data)
676 {
677 ui->back_func = func;
678 ui->back_data = data;
679 }
680
ui_set_new_window_callback(UIData * ui,void (* func)(UIData * ui,const gchar * key,gpointer data),gpointer data)681 void ui_set_new_window_callback(UIData *ui, void (*func)(UIData *ui, const gchar *key, gpointer data), gpointer data)
682 {
683 ui->new_window_func = func;
684 ui->new_window_data = data;
685 }
686
ui_set_new_skin_callback(UIData * ui,void (* func)(UIData * ui,SkinData * skin,gint initialized,gpointer data),gpointer data)687 void ui_set_new_skin_callback(UIData *ui, void (*func)(UIData *ui, SkinData *skin, gint initialized, gpointer data),
688 gpointer data)
689 {
690 ui->new_skin_func = func;
691 ui->new_skin_data = data;
692 }
693
694
695 /*
696 *-------------
697 * app side keys
698 *-------------
699 */
700
ui_register_key(UIData * ui,const gchar * key,WidgetType type,gpointer callbacks,guint length)701 RegisterData *ui_register_key(UIData *ui, const gchar *key, WidgetType type, gpointer callbacks, guint length)
702 {
703 RegisterData *rd;
704
705 rd = g_new0(RegisterData, 1);
706 rd->type = type;
707 rd->key = g_strdup(key);
708 rd->tooltip = NULL;
709 rd->callbacks = callbacks;
710 rd->callbacks_l = length;
711 rd->private = FALSE;
712 rd->private_widget = NULL;
713
714 ui->register_list = g_list_prepend(ui->register_list, rd);
715
716 return rd;
717 }
718
ui_register_key_private(UIData * ui,const gchar * key,WidgetType type,gpointer callbacks,guint length,gpointer widget)719 RegisterData *ui_register_key_private(UIData *ui, const gchar *key, WidgetType type,
720 gpointer callbacks, guint length, gpointer widget)
721 {
722 RegisterData *rd;
723
724 rd = ui_register_key(ui, key, type, callbacks, length);
725 rd->private = TRUE;
726 rd->private_widget = widget;
727 return rd;
728 }
729
ui_register_free(RegisterData * rd)730 static void ui_register_free(RegisterData *rd)
731 {
732 g_free(rd->callbacks);
733 g_free(rd->key);
734 g_free(rd->tooltip);
735 g_free(rd);
736 }
737
ui_register_free_all(UIData * ui)738 void ui_register_free_all(UIData *ui)
739 {
740 while(ui->register_list)
741 {
742 RegisterData *rd = ui->register_list->data;
743 ui->register_list = g_list_remove(ui->register_list, rd);
744 ui_register_free(rd);
745 }
746 }
747
ui_register_free_private(UIData * ui)748 void ui_register_free_private(UIData *ui)
749 {
750 GList *work = ui->register_list;
751
752 while(work)
753 {
754 RegisterData *rd = work->data;
755 work = work->next;
756
757 if (rd->private)
758 {
759 ui->register_list = g_list_remove(ui->register_list, rd);
760 ui_register_free(rd);
761 }
762 }
763 }
764
765 /* this will remove all keys with private_widget that match the widget,
766 * needed only when removing a widget
767 */
ui_unregister_key_private_for_widget(UIData * ui,gpointer widget)768 void ui_unregister_key_private_for_widget(UIData *ui, gpointer widget)
769 {
770 GList *work;
771
772 if (!widget) return;
773
774 work = ui->register_list;
775 while (work)
776 {
777 RegisterData *rd = work->data;
778 work = work->next;
779
780 if (rd->private && rd->private_widget == widget)
781 {
782 ui->register_list = g_list_remove(ui->register_list, rd);
783 ui_register_free(rd);
784 }
785 }
786 }
787
ui_registered_by_key(UIData * ui,const gchar * key,WidgetType type)788 static RegisterData *ui_registered_by_key(UIData *ui, const gchar *key, WidgetType type)
789 {
790 GList *work;
791
792 work = ui->register_list;
793 while (work)
794 {
795 RegisterData *rd = work->data;
796 if (rd->type == type && strcmp(rd->key, key) == 0) return rd;
797 work = work->next;
798 }
799 return NULL;
800 }
801
ui_get_registered_callbacks(UIData * ui,const gchar * key,WidgetType type)802 gpointer ui_get_registered_callbacks(UIData *ui, const gchar *key, WidgetType type)
803 {
804 RegisterData *rd;
805
806 rd = ui_registered_by_key(ui, key, type);
807 if (rd) return rd->callbacks;
808
809 if (ui->parent)
810 {
811 return ui_get_registered_callbacks(ui->parent, key, type);
812 }
813
814 return NULL;
815 }
816
ui_registered_key_exists(UIData * ui,const gchar * key,WidgetType type)817 gint ui_registered_key_exists(UIData *ui, const gchar *key, WidgetType type)
818 {
819 return (ui_registered_by_key(ui, key, type) != NULL);
820 }
821
ui_widget_exists(UIData * ui,const gchar * key,WidgetType type)822 gint ui_widget_exists(UIData *ui, const gchar *key, WidgetType type)
823 {
824 if (!ui->skin) return FALSE;
825
826 return (skin_widget_get_by_key(ui->skin, key, type) != NULL);
827 }
828
ui_registered_key_is_private(UIData * ui,const gchar * key,WidgetType type)829 gint ui_registered_key_is_private(UIData *ui, const gchar *key, WidgetType type)
830 {
831 GList *work;
832
833 /* walk the loop ourselves, for speed only strcmp if private and type match */
834
835 work = ui->register_list;
836 while (work)
837 {
838 RegisterData *rd = work->data;
839 if (rd->private && rd->type == type && strcmp(rd->key, key) == 0) return TRUE;
840 work = work->next;
841 }
842 return FALSE;
843 }
844
ui_tooltip_set(UIData * ui,const gchar * key,WidgetType type,const gchar * message)845 void ui_tooltip_set(UIData *ui, const gchar *key, WidgetType type, const gchar *message)
846 {
847 RegisterData *rd;
848
849 rd = ui_registered_by_key(ui, key, type);
850 if (!rd) return;
851
852 g_free(rd->tooltip);
853 rd->tooltip = g_strdup(message);
854 }
855
ui_tooltip_get(UIData * ui,const gchar * key,WidgetType type)856 const gchar *ui_tooltip_get(UIData *ui, const gchar *key, WidgetType type)
857 {
858 RegisterData *rd;
859
860 rd = ui_registered_by_key(ui, key, type);
861 if (rd) return rd->tooltip;
862
863 if (ui->parent)
864 {
865 return ui_tooltip_get(ui->parent, key, type);
866 }
867
868 return NULL;
869 }
870
871
ui_debug_print_register_list(UIData * ui)872 static void ui_debug_print_register_list(UIData *ui)
873 {
874 GList *work;
875
876 printf("-------------------------\n");
877 printf("UI registered keys (%3d):\n", g_list_length(ui->register_list));
878 printf("-[key]------------------------[type]-----\n");
879
880 work = ui->register_list;
881 while (work)
882 {
883 RegisterData *rd = work->data;
884 work = work->next;
885
886 printf("%-30s %-10s %s\n", rd->key, ui_widget_type_to_text(rd->type), rd->private ? "(widget)" : "");
887 }
888 }
889
ui_debug_print_registered_keys(UIData * ui)890 void ui_debug_print_registered_keys(UIData *ui)
891 {
892 if (!ui) return;
893
894 if (ui->parent)
895 {
896 printf("=========================\n");
897 printf("UI is \"%s\" is a child of \"%s\"\n", ui->key, ui->parent->key);
898 printf("printing out keys starting at the parent\n");
899 printf("-------------------------\n");
900 ui_debug_print_registered_keys(ui->parent);
901 return;
902 }
903
904 printf("=========================\n");
905 printf("UI is \"%s\"\n", ui->key);
906 printf("-------------------------\n");
907 printf(" skin: \"%s\"\n", ui->skin_path);
908 printf("mode key: \"%s\"\n", ui->skin_mode_key);
909
910 ui_debug_print_register_list(ui);
911
912 if (ui->children)
913 {
914 GList *work;
915
916 printf("-------------------------\n");
917 printf("children: %d\n", g_list_length(ui->children));
918
919 work = ui->children;
920 while (work)
921 {
922 UIData *child;
923
924 child = work->data;
925 work = work->next;
926
927 printf("=========================\n");
928 printf(" child: \"%s\"\n", child->key);
929 printf("mode key: \"%s\"\n", child->skin_mode_key);
930
931 ui_debug_print_register_list(child);
932 }
933 }
934
935 printf("=========================\n");
936 }
937
ui_debug_print_all_keys(UIData * ui)938 void ui_debug_print_all_keys(UIData *ui)
939 {
940 GList *work;
941
942 ui_debug_print_registered_keys(ui);
943
944 if (ui->parent) ui = ui->parent;
945
946 skin_debug_print_registered_keys(ui->skin);
947
948 work = ui->children;
949 while (work)
950 {
951 UIData *child;
952
953 child = work->data;
954 work = work->next;
955
956 printf("=========================\n");
957 printf("child: \"%s\"\n", child->key);
958 printf("-------------------------\n");
959
960 skin_debug_print_registered_keys(child->skin);
961 }
962
963 printf("=========================\n");
964 }
965
966 /*
967 *-------------
968 * ui_misc
969 *-------------
970 */
971
ui_update(UIData * ui)972 void ui_update(UIData *ui)
973 {
974 GList *work;
975
976 if (!ui) return;
977
978 ui_display_draw_all(ui, TRUE, FALSE);
979
980 work = ui->children;
981 while (work)
982 {
983 UIData *child = work->data;
984 work = work->next;
985
986 ui_display_draw_all(child, TRUE, FALSE);
987 }
988 }
989
ui_geometry_get(UIData * ui,gint * x,gint * y,gint * w,gint * h)990 gint ui_geometry_get(UIData *ui, gint *x, gint *y, gint *w, gint *h)
991 {
992 gint rx, ry, rw, rh;
993
994 if (!ui || !ui->skin ||
995 !ui->window || !ui->window->window ||
996 !GTK_WIDGET_REALIZED(ui->window)) return FALSE;
997
998 gdk_window_get_position(ui->window->window, &rx, &ry);
999 gtk_window_get_size(GTK_WINDOW(ui->window), &rw, &rh);
1000
1001 if (x) *x = rx;
1002 if (y) *y = ry;
1003 if (w) *w = rw;
1004 if (h) *h = rh;
1005
1006 ui_state_set(filename_from_path(ui->skin_path), ui->skin_mode_key, rx, ry, rw, rh);
1007
1008 return TRUE;
1009 }
1010
ui_title_set(UIData * ui,const gchar * text)1011 void ui_title_set(UIData *ui, const gchar *text)
1012 {
1013 gtk_window_set_title(GTK_WINDOW(ui->window), text);
1014 }
1015
ui_moveable_set(UIData * ui,gint moveable)1016 void ui_moveable_set(UIData *ui, gint moveable)
1017 {
1018 ui->allow_move = moveable;
1019 }
1020
ui_focus_set(UIData * ui,gint enable)1021 void ui_focus_set(UIData *ui, gint enable)
1022 {
1023 ui->focus_enable = enable;
1024 }
1025
ui_tooltips_enable(UIData * ui,gint enable)1026 void ui_tooltips_enable(UIData *ui, gint enable)
1027 {
1028 ui->tooltips_enable = enable;
1029 }
1030
ui_skin_set(UIData * ui,SkinData * skin,const gchar * path,const gchar * mode_key)1031 void ui_skin_set(UIData *ui, SkinData *skin, const gchar *path, const gchar *mode_key)
1032 {
1033 gchar *tmp;
1034
1035 if (!skin) return;
1036
1037 /* handle children, closing any that were opened
1038 * with the skin_open button, these are identified by
1039 * having the same key and skin_mode_key.
1040 */
1041 if (( (path == NULL) != (ui->skin_path == NULL) ) ||
1042 (path && strcmp(path, ui->skin_path) != 0) )
1043 {
1044 GList *work;
1045
1046 work = ui->children;
1047 while (work)
1048 {
1049 UIData *child;
1050
1051 child = work->data;
1052 work = work->next;
1053
1054 if (child->key && child->skin_mode_key &&
1055 strcmp(child->key, child->skin_mode_key) == 0)
1056 {
1057 ui_close(child);
1058 }
1059 }
1060 }
1061
1062 /* save current state of old skin */
1063 ui_geometry_get(ui, NULL, NULL, NULL, NULL);
1064
1065 /* remove old internal widget signals */
1066 ui_register_free_private(ui);
1067
1068 /* notify app of new skin */
1069 if (ui->new_skin_func)
1070 {
1071 ui->new_skin_func(ui, skin, FALSE, ui->new_skin_data);
1072 }
1073
1074 skin_free(ui->skin);
1075 ui->skin = skin;
1076 skin->ui = ui;
1077
1078 ui->active_widget = NULL;
1079 ui->focus_widget = NULL;
1080
1081 /* use tmp, may be src = dest */
1082
1083 tmp = g_strdup(path);
1084 g_free(ui->skin_path);
1085 ui->skin_path = tmp;
1086
1087 tmp = g_strdup(mode_key);
1088 g_free(ui->skin_mode_key);
1089 ui->skin_mode_key = tmp;
1090
1091 /* set up new internal widget signals */
1092 skin_widgets_init(skin, ui);
1093
1094 /* notify app new skin is about to be drawn */
1095 if (ui->new_skin_func)
1096 {
1097 ui->new_skin_func(ui, skin, TRUE, ui->new_skin_data);
1098 }
1099
1100 /* restore skin states */
1101 if (slik_remember_position)
1102 {
1103 gint x;
1104 gint y;
1105 gint w;
1106 gint h;
1107
1108 if (ui_state_get(filename_from_path(ui->skin_path), ui->skin_mode_key, &x, &y, &w, &h))
1109 {
1110 /* if not visible, this is the first skin, set position */
1111 if (ui->window && !GTK_WIDGET_VISIBLE(ui->window) && ui->allow_move)
1112 {
1113 /* ensure that window is at least visible */
1114 if (x < 0 - skin->width) x = 0;
1115 if (x > gdk_screen_width()) x = gdk_screen_width() - skin->width;
1116 if (y < 0 - skin->height) y = 0;
1117 if (y > gdk_screen_height()) y = gdk_screen_height() - skin->height;
1118
1119 if (debug_mode) printf("setting window position %d, %d\n", x, y);
1120
1121 gtk_window_move(GTK_WINDOW(ui->window), x, y);
1122 }
1123
1124 /* only do this if the skin is actually sizeable in some way */
1125 if ((skin->sizeable && ui_widget_exists(ui, "skin_size", button_type_id())) ||
1126 ui_widget_exists(ui, "skin_expand", button_type_id()) )
1127 {
1128 w = CLAMP(w, skin->width_min, skin->width_max);
1129 h = CLAMP(h, skin->height_min, skin->height_max);
1130 skin_resize(ui, w, h);
1131 }
1132 }
1133 }
1134
1135 ui_display_sync_all(ui);
1136 }
1137
ui_skin_load_default(UIData * ui,const gchar * key)1138 SkinData *ui_skin_load_default(UIData *ui, const gchar *key)
1139 {
1140 SkinData *skin = NULL;
1141
1142 if (ui->skin_func)
1143 {
1144 skin = ui->skin_func(ui, key, ui->skin_data);
1145 }
1146 if (!skin)
1147 {
1148 /* well, return something! */
1149 skin = skin_new();
1150
1151 skin->real_overlay = ui_slik_logo();
1152 skin->width = gdk_pixbuf_get_width(skin->real_overlay);
1153 skin->height = gdk_pixbuf_get_height(skin->real_overlay);
1154
1155 /* add some widgets (a text message maybe? ) */
1156
1157 skin->width_def = skin->width_min = skin->width_max = skin->width;
1158 skin->height_def = skin->height_min = skin->height_max = skin->height;
1159 }
1160
1161 return skin;
1162 }
1163
ui_skin_load(UIData * ui,const gchar * path,const gchar * mode_key)1164 gint ui_skin_load(UIData *ui, const gchar *path, const gchar *mode_key)
1165 {
1166 SkinData *skin;
1167 gint success = FALSE;
1168 gchar *cpath;
1169 gchar *ckey;
1170
1171 if (!mode_key) mode_key = "skindata";
1172
1173 /* copy, since loading a new skin may free the source ? */
1174 cpath = g_strdup(path);
1175 ckey = g_strdup(mode_key);
1176
1177 if (cpath)
1178 {
1179 if (!isdir(cpath) && isfile(cpath))
1180 {
1181 gchar *dirbuf = remove_level_from_path(path);
1182
1183 g_free(ckey);
1184 ckey = g_strdup(filename_from_path(path));
1185
1186 skin = skin_parse(dirbuf, cpath, FALSE);
1187
1188 g_free(cpath);
1189 cpath = dirbuf;
1190 }
1191 else
1192 {
1193 gchar *datafile;
1194
1195 datafile = g_strconcat(cpath, "/", ckey, NULL);
1196 skin = skin_parse(cpath, datafile, FALSE);
1197 g_free(datafile);
1198 }
1199
1200 }
1201 else
1202 {
1203 skin = ui_skin_load_default(ui, ckey);
1204 }
1205
1206 if (skin)
1207 {
1208 ui_skin_set(ui, skin, cpath, ckey);
1209 success = TRUE;
1210 }
1211
1212 g_free(cpath);
1213 g_free(ckey);
1214
1215 return success;
1216 }
1217
ui_skin_mode_set(UIData * ui,const gchar * mode_key)1218 gint ui_skin_mode_set(UIData *ui, const gchar *mode_key)
1219 {
1220 gint success;
1221 gint ox, oy, ow, oh;
1222
1223 if (ui->window)
1224 {
1225 gdk_window_get_position(ui->window->window, &ox, &oy);
1226 }
1227 else
1228 {
1229 ox = oy = 0;
1230 }
1231 ow = ui->skin->width;
1232 oh = ui->skin->height;
1233
1234 success = ui_skin_load(ui, ui->skin_path, mode_key);
1235
1236 if (slik_smart_placement && success && ui->window)
1237 {
1238 gint x, y;
1239 gint move = FALSE;
1240
1241 x = y = 0;
1242
1243 if (oy + (oh / 2) > gdk_screen_height() / 2)
1244 {
1245 move = TRUE;
1246 if (oh > ui->skin->height)
1247 {
1248 x = ox;
1249 y = oy + oh - ui->skin->height;
1250 if (y > gdk_screen_height() - ui->skin->height)
1251 {
1252 y = gdk_screen_height() - ui->skin->height;
1253 }
1254 }
1255 else
1256 {
1257 x = ox;
1258 y = oy + oh - ui->skin->height;
1259 }
1260 }
1261 else if (oy < 0)
1262 {
1263 move = TRUE;
1264 x = ox;
1265 y = 0;
1266 }
1267 if (move) gdk_window_move(ui->window->window, x, y);
1268 }
1269
1270 return success;
1271 }
1272
ui_set_underlay(UIData * ui,GdkPixbuf * pb)1273 void ui_set_underlay(UIData *ui, GdkPixbuf *pb)
1274 {
1275 if (!ui || !ui->skin) return;
1276
1277 skin_set_underlay(ui->skin, ui, pb);
1278 ui_display_sync(ui, FALSE);
1279 }
1280
ui_sync_states(void)1281 void ui_sync_states(void)
1282 {
1283 GList *work;
1284
1285 work = slik_ui_list;
1286 while (work)
1287 {
1288 UIData *ui = work->data;
1289 gint x, y, w, h;
1290
1291 if (ui_geometry_get(ui, &x, &y, &w, &h))
1292 {
1293 ui_state_set(filename_from_path(ui->skin_path), ui->skin_mode_key, x, y, w, h);
1294 }
1295
1296 work = work->next;
1297 }
1298 }
1299
1300 /*
1301 *-------------
1302 * ui_misc text based utils
1303 *-------------
1304 */
1305
ui_find_by_key(const gchar * key)1306 UIData *ui_find_by_key(const gchar *key)
1307 {
1308 GList *work;
1309
1310 if (!key) return NULL;
1311
1312 work = slik_ui_list;
1313 while(work)
1314 {
1315 UIData *ui = work->data;
1316
1317 if (ui->key && strcmp(ui->key, key) == 0) return ui;
1318
1319 work = work->next;
1320 }
1321 return NULL;
1322 }
1323
1324 /*
1325 *-------------
1326 * grouping (children) support
1327 *-------------
1328 */
1329
ui_group_set_child(UIData * parent,UIData * child)1330 void ui_group_set_child(UIData *parent, UIData *child)
1331 {
1332 if (!parent || !child) return;
1333
1334 if (child->parent) return;
1335
1336 /* children are linear,
1337 * that is one parent and the rest are children of that parent (no complex trees!)
1338 */
1339 if (parent->parent) parent = parent->parent;
1340
1341 child->parent = parent;
1342 parent->children = g_list_append(parent->children, child);
1343
1344 if (debug_mode) printf("setting %s as a child of %s\n", child->skin_mode_key, parent->skin_mode_key);
1345 }
1346
ui_group_unset_child(UIData * child)1347 void ui_group_unset_child(UIData *child)
1348 {
1349 UIData *parent;
1350
1351 if (!child || !child->parent) return;
1352
1353 parent = child->parent;
1354 parent->children = g_list_remove(parent->children, child);
1355 child->parent = NULL;
1356
1357 if (debug_mode) printf("removed %s as a child of %s\n", child->skin_mode_key, parent->skin_mode_key);
1358 }
1359
ui_group_get_parent(UIData * ui)1360 UIData *ui_group_get_parent(UIData *ui)
1361 {
1362 if (!ui) return NULL;
1363
1364 return ui->parent;
1365 }
1366
ui_group_get_child(UIData * ui,const gchar * key)1367 UIData *ui_group_get_child(UIData *ui, const gchar *key)
1368 {
1369 GList *work;
1370
1371 if (!ui || !key) return NULL;
1372
1373 work = ui->children;
1374 while (work)
1375 {
1376 UIData *child = work->data;
1377 work = work->next;
1378
1379 if (child->key && strcmp(child->key, key) == 0) return child;
1380 }
1381
1382 return NULL;
1383 }
1384
1385 /*
1386 *-------------
1387 * SLIK credits / about / logo
1388 *-------------
1389 */
1390
ui_slik_logo(void)1391 GdkPixbuf *ui_slik_logo(void)
1392 {
1393 return gdk_pixbuf_new_from_inline(-1, icon_slik_logo, FALSE, NULL);
1394 }
1395
1396 static GenericDialog *slik_about = NULL;
1397
ui_slik_about_destroy_cb(GtkWidget * widget,gpointer data)1398 static void ui_slik_about_destroy_cb(GtkWidget *widget, gpointer data)
1399 {
1400 slik_about = NULL;
1401 }
1402
slik_about_toggle_cb(GtkWidget * button,gpointer data)1403 static void slik_about_toggle_cb(GtkWidget *button, gpointer data)
1404 {
1405 gint *val = data;
1406 *val = GTK_TOGGLE_BUTTON(button)->active;
1407
1408 if (val == &debug_mode)
1409 {
1410 printf("Debug set: %d\n", debug_mode);
1411 }
1412 else if (val == &debug_skin)
1413 {
1414 printf("Skin coordinates set: %d\n", debug_skin);
1415 }
1416 }
1417
ui_slik_about(void)1418 static void ui_slik_about(void)
1419 {
1420 GtkWidget *hbox;
1421 GtkWidget *label;
1422 GtkWidget *button;
1423 GtkWidget *image;
1424 GdkPixbuf *pixbuf;
1425 gchar *buf;
1426
1427 if (slik_about)
1428 {
1429 gtk_window_present(GTK_WINDOW(slik_about->dialog));
1430 return;
1431 }
1432
1433 slik_about = generic_dialog_new(_("About - SLIK"),
1434 "SLIK", "about",
1435 NULL, TRUE, NULL, NULL);
1436 g_signal_connect(G_OBJECT(slik_about->dialog), "destroy",
1437 G_CALLBACK(ui_slik_about_destroy_cb), NULL);
1438 generic_dialog_add_button(slik_about, GTK_STOCK_CLOSE, NULL, NULL, TRUE);
1439
1440 pixbuf = ui_slik_logo();
1441 image = gtk_image_new_from_pixbuf(pixbuf);
1442 gdk_pixbuf_unref(pixbuf);
1443
1444 gtk_box_pack_start(GTK_BOX(slik_about->vbox), image, FALSE, FALSE, 0);
1445 gtk_widget_show(image);
1446
1447 buf = g_strdup_printf(_("SLIK\nSimpLIstic sKin interface\n%s\nCopyright (c) %s John Ellis\nwebsite: %s\nemail: %s\n\nReleased under the GNU General Public License"),
1448 SLIK_VERSION,
1449 "2005",
1450 "gqmpeg.sourceforge.net",
1451 "gqview@users.sourceforge.net");
1452 label = pref_label_new(slik_about->vbox, buf);
1453 g_free(buf);
1454 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER);
1455
1456 hbox = pref_box_new(slik_about->vbox, FALSE, GTK_ORIENTATION_HORIZONTAL, 0);
1457
1458 button = gtk_toggle_button_new();
1459 gtk_widget_set_size_request(button, 8, 8);
1460 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), debug_mode);
1461 g_signal_connect(G_OBJECT(button), "toggled",
1462 G_CALLBACK(slik_about_toggle_cb), &debug_mode);
1463 gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, FALSE, 4);
1464 gtk_widget_show(button);
1465
1466 button = gtk_toggle_button_new();
1467 gtk_widget_set_size_request(button, 8, 8);
1468 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), debug_skin);
1469 g_signal_connect(G_OBJECT(button), "toggled",
1470 G_CALLBACK(slik_about_toggle_cb), &debug_skin);
1471 gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 4);
1472 gtk_widget_show(button);
1473
1474 window_set_icon(slik_about->dialog, NULL, NULL, NULL);
1475
1476 gtk_widget_show(slik_about->dialog);
1477 }
1478
ui_slik_credit(void)1479 GtkWidget *ui_slik_credit(void)
1480 {
1481 GtkWidget *frame;
1482 GtkWidget *hbox;
1483 GtkWidget *label;
1484 GtkWidget *image;
1485 GdkPixbuf *pb;
1486 gchar *buf;
1487
1488 frame = gtk_button_new();
1489 gtk_button_set_relief(GTK_BUTTON(frame), GTK_RELIEF_NONE);
1490 gtk_container_set_border_width(GTK_CONTAINER(frame), 10);
1491 g_signal_connect(G_OBJECT(frame), "clicked",
1492 G_CALLBACK(ui_slik_about), NULL);
1493
1494 hbox = gtk_hbox_new(FALSE, 5);
1495 gtk_container_add(GTK_CONTAINER(frame), hbox);
1496 gtk_widget_show(hbox);
1497
1498 pb = ui_slik_logo();
1499 image = gtk_image_new_from_pixbuf(pb);
1500 gdk_pixbuf_unref(pb);
1501
1502 gtk_box_pack_start(GTK_BOX(hbox), image, FALSE, FALSE, 0);
1503 gtk_widget_show(image);
1504
1505 buf = g_strdup_printf(_("utilizes SLIK %s\nSimpLIstic sKin interface"), SLIK_VERSION);
1506 label = gtk_label_new(buf);
1507 g_free(buf);
1508 gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
1509
1510 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
1511 gtk_widget_show(label);
1512
1513 return frame;
1514 }
1515
1516
1517