1 /* GKrellM-trayicons
2
3 Author, current maintainer:
4
5 Tomas Styblo <tripie@cpan.org>
6
7 Copyright (C) 2003
8
9 This program is free software which I release under the GNU General Public
10 License. You may redistribute and/or modify this program under the terms
11 of that license as published by the Free Software Foundation; either
12 version 2 of the License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 To get a copy of the GNU General Puplic License, write to the
20 Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include <gkrellm2/gkrellm.h>
24 #include <utime.h>
25 #include <dirent.h>
26 #include <errno.h>
27 #include <math.h>
28
29 #define xstr(s) str(s)
30 #define str(s) #s
31 #define MY_BUFLEN 1024
32
33 typedef struct
34 {
35 gchar *activation_file;
36 gchar *icon_active_file;
37 gchar *icon_inactive_file;
38 gchar *left_click_active_command;
39 gchar *left_click_inactive_command;
40 gboolean blink;
41 gboolean popup;
42 gboolean activated;
43 gboolean icon_state;
44 time_t activation_file_mtime;
45 gint x;
46 gint y;
47 GkrellmDecalbutton *but;
48 /*
49 GString *buf;
50 */
51 } item_t;
52
53 enum
54 {
55 ACTIVATION_FILE_COLUMN,
56 ICON_ACTIVE_PIXBUF_COLUMN,
57 ICON_ACTIVE_FILE_COLUMN,
58 ICON_INACTIVE_PIXBUF_COLUMN,
59 ICON_INACTIVE_FILE_COLUMN,
60 LEFT_CLICK_ACTIVE_COMMAND_COLUMN,
61 LEFT_CLICK_INACTIVE_COMMAND_COLUMN,
62 BLINK_COLUMN,
63 POPUP_COLUMN,
64 N_COLUMNS
65 };
66
67 #ifndef VERSION
68 #error "VERSION is not defined."
69 #endif
70
71 #define NOTICE_SEPARATOR "\n- - - - - - - - - - - -\n"
72 #define TREE_SIZE_PADDING 300
73 #define TREE_SIZE_MAX 600
74 #define TREE_HEIGHT 150
75
76 static GkrellmMonitor *monitor;
77 static GArray *trayicons;
78 static GkrellmPanel *panel;
79 static gint icon_size = 16; /* the default */
80 static gint icon_padding = 4; /* the default */
81 static gint popup_timeout = 5; /* the default */
82 static GtkWidget *trayicons_vbox;
83 static GtkWidget *win_bubble;
84 static GdkColor popup_fg_color = { 0, 0xFFFF, 0xFFFF, 0xFFFF };
85 static GdkColor popup_bg_color = { 0, 0xFFFF, 0x0000, 0x0000 };
86 static GtkWidget *active_popup = NULL;
87 static gint active_popup_icon;
88 static gint active_timeout = 0;
89 static gchar *active_popup_str = NULL;
90
91 void setup_trayicons(gint first_create);
92 static GdkPixbuf *get_pixbuf(const gchar *filename, gint size);
93 static void draw_icon(gint i, gboolean state);
94 static void deactivate_icon(gint icon);
95
destroy_bubble()96 static void destroy_bubble() {
97 if (active_popup) {
98 gtk_widget_destroy(active_popup);
99 active_popup = NULL;
100 g_free(active_popup_str);
101 active_popup_str = NULL;
102 }
103 if (active_timeout) {
104 gtk_timeout_remove(active_timeout);
105 }
106 }
107
bubble_timeout(gpointer data)108 static gint bubble_timeout(gpointer data)
109 {
110 destroy_bubble();
111 return 0; /* cancel the timeout */
112 }
113
bubble_button_press(GtkWidget * widget,GdkEventButton * event,gpointer data)114 static gboolean bubble_button_press(GtkWidget *widget,
115 GdkEventButton *event, gpointer data)
116 {
117 destroy_bubble();
118 deactivate_icon(active_popup_icon);
119 return TRUE;
120 }
121
bubble_paint_window(gchar * str)122 static gint bubble_paint_window(gchar *str)
123 {
124 gtk_paint_flat_box(win_bubble->style, win_bubble->window,
125 GTK_STATE_NORMAL, GTK_SHADOW_OUT,
126 NULL, GTK_WIDGET(win_bubble), "tooltip",
127 0, 0, -1, -1);
128
129 return FALSE;
130 }
131
create_bubble(gchar * str,gint icon)132 static void create_bubble(gchar *str, gint icon)
133 {
134 GtkWidget *label;
135 GtkRequisition requisition;
136 GtkWidget *widget;
137 GtkStyle *style;
138 gint x, y, w, h, scr_w, scr_h;
139 GdkScreen *screen;
140
141 if (active_popup) {
142 gchar *oldstr = g_strdup(active_popup_str);
143 destroy_bubble();
144 active_popup_str = g_strconcat(oldstr, NOTICE_SEPARATOR, str, NULL);
145 g_free(oldstr);
146 }
147 else {
148 active_popup_str = g_strdup(str);
149 }
150
151 win_bubble = gtk_window_new(GTK_WINDOW_POPUP);
152 active_popup = win_bubble;
153 active_popup_icon = icon;
154 gtk_widget_set_app_paintable(win_bubble, TRUE);
155 gtk_window_set_resizable(GTK_WINDOW(win_bubble), FALSE);
156 gtk_widget_set_name(win_bubble, "gkrellm-trayicons-buuble");
157 gtk_container_set_border_width(GTK_CONTAINER(win_bubble), 4);
158
159 g_signal_connect_swapped(win_bubble, "expose_event",
160 G_CALLBACK(bubble_paint_window), NULL);
161
162 label = gtk_label_new(NULL);
163 gtk_widget_set_events (win_bubble, GDK_BUTTON_PRESS_MASK);
164 g_signal_connect(GTK_OBJECT(win_bubble), "button-press-event",
165 G_CALLBACK(bubble_button_press), NULL);
166 gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
167 gtk_misc_set_alignment(GTK_MISC(label), 0.5, 0.5);
168 gtk_widget_modify_fg(label, GTK_STATE_NORMAL, &popup_fg_color);
169 gtk_widget_modify_bg(win_bubble, GTK_STATE_NORMAL, &popup_bg_color);
170 gtk_widget_show(label);
171 gtk_container_add(GTK_CONTAINER(win_bubble), label);
172 g_signal_connect (win_bubble, "destroy",
173 G_CALLBACK(gtk_widget_destroyed),
174 &win_bubble);
175
176 gtk_widget_ensure_style(win_bubble);
177 style = win_bubble->style;
178
179 screen = gtk_widget_get_screen(win_bubble);
180 scr_w = gdk_screen_get_width(screen);
181 scr_h = gdk_screen_get_height(screen);
182
183 gtk_label_set_text(GTK_LABEL(label), active_popup_str);
184
185 gtk_widget_size_request(win_bubble, &requisition);
186 w = requisition.width;
187 h = requisition.height;
188
189 /*
190 gdk_window_get_pointer(gdk_screen_get_root_window (screen),
191 &x, &y, NULL);
192 */
193
194 widget = panel->drawing_area;
195
196 gdk_window_get_origin (widget->window, &x, &y);
197 if (GTK_WIDGET_NO_WINDOW (widget))
198 {
199 x += widget->allocation.x;
200 y += widget->allocation.y;
201 }
202
203 x -= (w / 2 + 4);
204 if ((x + w) > scr_w)
205 x -= (x + w) - scr_w;
206 else if (x < 0)
207 x = 0;
208
209 y -= (h + 6);
210 if ((y + h) > scr_h)
211 y -= (y + w) - scr_h;
212 else if (y < 0)
213 y = 0;
214
215 /* printf("w=%d, h=%d, x=%d, y=%d\n", w, h, x, y); */
216
217 gtk_window_move(GTK_WINDOW(win_bubble), x, y);
218 gtk_widget_show(win_bubble);
219
220 if (popup_timeout > 0) {
221 active_timeout = gtk_timeout_add(popup_timeout * 1000, bubble_timeout, NULL);
222 }
223 }
224
append_file_to_buf(const gchar * filename,GString * gs)225 void append_file_to_buf(const gchar *filename, GString *gs)
226 {
227 FILE *fh;
228 char buf[1024];
229 size_t num;
230
231 if (! (fh = fopen(filename, "r"))) {
232 fprintf(stderr, "gkrellm-trayicons: cannot read activation file: %s (%s)",
233 filename, strerror(errno));
234 gkrellm_message_dialog("Error", "Cannot read activation file.");
235 return;
236 }
237
238 while ((num = fread(buf, sizeof(char), sizeof(buf), fh)) > 0) {
239 if (ferror(fh))
240 break;
241 g_string_append_len(gs, buf, num);
242 }
243
244 if (ferror(fh)) {
245 fprintf(stderr, "gkrellm-trayicons: cannot read activation file: %s (%s)",
246 filename, strerror(errno));
247 gkrellm_message_dialog("Error", "Cannot read activation file.");
248 }
249 if (fclose(fh) == EOF) {
250 fprintf(stderr, "gkrellm-trayicons: cannot close activation file: %s (%s)",
251 filename, strerror(errno));
252 gkrellm_message_dialog("Error", "Cannot close activation file.");
253 }
254
255 if (gs->str[gs->len - 1] == '\n') {
256 g_string_truncate(gs, gs->len - 1);
257 }
258 }
259
update_trayicons_real()260 static void update_trayicons_real()
261 {
262 gint i;
263 struct stat st;
264
265 for (i = 0; i < trayicons->len; i++) {
266 gchar *acfile = g_array_index(trayicons,item_t, i).activation_file;
267 GString *new = g_string_new("");
268
269 /* check icons that should blink */
270 if (g_array_index(trayicons,item_t, i).activated &&
271 g_array_index(trayicons,item_t, i).blink) {
272 draw_icon(i, !g_array_index(trayicons,item_t, i).icon_state);
273 }
274
275 /* check new activations */
276 if (stat(acfile, &st) == -1) {
277 // gkrellm_message_dialog("Error", "Cannot stat activation file.");
278 continue;
279 }
280
281 if (S_ISDIR(st.st_mode)) {
282 DIR *d;
283 struct dirent *de;
284 gboolean first = TRUE;
285
286 if (chdir(acfile) == -1) {
287 fprintf(stderr,
288 "gkrellm-trayicons: cannot chdir to the activation directory: %s (%s)",
289 acfile, strerror(errno));
290 }
291
292 if (! (d = opendir(acfile))) {
293 fprintf(stderr, "gkrellm-trayicons: cannot open activation directory: %s (%s)", acfile, strerror(errno));
294 gkrellm_message_dialog("Error", "Cannot open activation directory.");
295 continue;
296 }
297
298 while ((de = readdir(d))) {
299 if (strcmp(de->d_name, ".") != 0 && strcmp(de->d_name, "..") != 0) {
300 if (! first) {
301 g_string_append(new, NOTICE_SEPARATOR);
302 }
303 first = FALSE;
304 append_file_to_buf(de->d_name, new);
305 if (unlink(de->d_name) == -1) {
306 fprintf(stderr, "gkrellm-trayicons: cannot unlink activation file: %s (%s)", de->d_name, strerror(errno));
307 gkrellm_message_dialog("Error", "Cannot unlink activation file.");
308 }
309 }
310 }
311
312 if (closedir(d) == -1) {
313 fprintf(stderr,
314 "gkrellm-trayicons: cannot close activation directory: %s (%s)",
315 acfile, strerror(errno));
316 gkrellm_message_dialog("Error", "Cannot close activation directory.");
317 continue;
318 }
319
320 if (first) {
321 /* no file was read */
322 continue;
323 }
324 else {
325 /* activate icon */
326 draw_icon(i, TRUE);
327 g_array_index(trayicons,item_t, i).activated = TRUE;
328
329 if (g_array_index(trayicons,item_t, i).popup) {
330 create_bubble(new->str, i);
331 }
332 }
333 }
334 else {
335 if (g_array_index(trayicons,item_t, i).activation_file_mtime != 0 &&
336 st.st_mtime != g_array_index(trayicons,item_t, i).activation_file_mtime) {
337 append_file_to_buf(acfile, new);
338 /* activate icon */
339 draw_icon(i, TRUE);
340 g_array_index(trayicons,item_t, i).activated = TRUE;
341
342 if (g_array_index(trayicons,item_t, i).popup) {
343 create_bubble(new->str, i);
344 }
345 }
346 g_array_index(trayicons,item_t, i).activation_file_mtime = st.st_mtime;
347 }
348 g_string_free(new, TRUE);
349 }
350 gkrellm_draw_panel_layers(panel);
351 }
352
update_trayicons()353 static void update_trayicons()
354 {
355 if (GK.second_tick) {
356 update_trayicons_real();
357 }
358 }
359
panel_expose_event(GtkWidget * widget,GdkEventExpose * ev,GkrellmPanel * p)360 static gint panel_expose_event(GtkWidget *widget, GdkEventExpose *ev, GkrellmPanel *p)
361 {
362 gdk_draw_pixmap(widget->window,
363 widget->style->fg_gc[GTK_WIDGET_STATE (widget)], p->pixmap,
364 ev->area.x, ev->area.y, ev->area.x, ev->area.y,
365 ev->area.width, ev->area.height);
366 return TRUE;
367 }
368
deactivate_icon(gint icon)369 static void deactivate_icon(gint icon)
370 {
371 g_array_index(trayicons, item_t, icon).activated = FALSE;
372 draw_icon(icon, FALSE);
373 gkrellm_draw_panel_layers(panel);
374 /*
375 if (g_array_index(trayicons, item_t, icon).buf) {
376 g_string_free(g_array_index(trayicons, item_t, icon).buf, TRUE);
377 g_array_index(trayicons, item_t, icon).buf = NULL;
378 }
379 */
380 }
381
cb_panel_button(GtkWidget * widget,GdkEventButton * ev,gpointer data)382 static gboolean cb_panel_button(GtkWidget *widget, GdkEventButton *ev,
383 gpointer data)
384 {
385 if (ev->button == 2)
386 {
387 gkrellm_open_config_window(monitor);
388 return TRUE;
389 }
390
391 return FALSE;
392 }
393
cb_icon_click_left(GkrellmDecalbutton * button,gpointer data)394 static void cb_icon_click_left(GkrellmDecalbutton *button, gpointer data)
395 {
396 gint icon = GPOINTER_TO_INT(data);
397 gchar *cmd;
398
399 /* printf("left button on icon %d was pressed\n", GPOINTER_TO_INT(data)); */
400 if (g_array_index(trayicons, item_t, icon).activated) {
401 cmd = g_array_index(trayicons, item_t, icon).left_click_active_command;
402 }
403 else {
404 cmd = g_array_index(trayicons, item_t, icon).left_click_inactive_command;
405 }
406
407 if (cmd) {
408 /* fprintf(stderr, "running command: %s\n", cmd); */
409 g_spawn_command_line_async(cmd, NULL);
410 }
411
412 deactivate_icon(icon);
413 if (active_popup) {
414 destroy_bubble();
415 }
416 }
417
cb_icon_click_right(GkrellmDecalbutton * button,gpointer data)418 static void cb_icon_click_right(GkrellmDecalbutton *button, gpointer data)
419 {
420 gint icon = GPOINTER_TO_INT(data);
421 /* printf("right button on icon %d was pressed\n", icon); */
422 if (active_popup) {
423 destroy_bubble();
424 }
425 else {
426 /*
427 if (g_array_index(trayicons, item_t, icon).buf) {
428 create_bubble(g_array_index(trayicons, item_t, icon).buf->str, icon);
429 }
430 */
431 }
432 deactivate_icon(icon);
433 }
434
draw_icon(gint i,gboolean state)435 static void draw_icon(gint i, gboolean state)
436 {
437 GkrellmPiximage *pix_prim;
438 GkrellmPiximage *pix_sec;
439 gchar *filename_prim;
440 gchar *filename_sec;
441
442 if (state) {
443 filename_prim = g_array_index(trayicons, item_t, i).icon_active_file;
444 filename_sec = g_array_index(trayicons, item_t, i).icon_inactive_file;
445 }
446 else {
447 filename_prim = g_array_index(trayicons, item_t, i).icon_inactive_file;
448 filename_sec = g_array_index(trayicons, item_t, i).icon_active_file;
449 }
450
451 if (g_array_index(trayicons, item_t, i).but) {
452 gkrellm_destroy_button(g_array_index(trayicons, item_t, i).but);
453 }
454
455 if ((pix_prim = gkrellm_piximage_new_from_file(filename_prim)) &&
456 (pix_sec = gkrellm_piximage_new_from_file(filename_sec))) {
457 /*
458 GkrellmDecalbutton *but = gkrellm_make_scaled_button(panel,
459 pix_prim, cb_icon_click_left, GINT_TO_POINTER(i),
460 FALSE, FALSE,
461 0, 0, 1,
462 g_array_index(trayicons, item_t, i).x,
463 g_array_index(trayicons, item_t, i).y,
464 icon_size, icon_size);
465 */
466 GkrellmDecalbutton *but = gkrellm_make_overlay_button(panel,
467 cb_icon_click_left, GINT_TO_POINTER(i),
468 g_array_index(trayicons, item_t, i).x,
469 g_array_index(trayicons, item_t, i).y,
470 icon_size, icon_size,
471 pix_prim,
472 pix_sec);
473 but->type = 0; /* disable auto hide */
474
475 gkrellm_destroy_piximage(pix_prim);
476 gkrellm_destroy_piximage(pix_sec);
477
478 if (but) {
479 g_array_index(trayicons, item_t, i).icon_state = state;
480 g_array_index(trayicons, item_t, i).but = but;
481 gkrellm_decal_button_right_connect(but, cb_icon_click_right, GINT_TO_POINTER(i));
482 gkrellm_show_button(but);
483 }
484 else {
485 gkrellm_message_dialog("Error", "Cannot create button.");
486 }
487 }
488 else {
489 gkrellm_message_dialog("Error", "Cannot load icon.");
490 }
491 }
492
setup_trayicons(gint first_create)493 void setup_trayicons(gint first_create)
494 {
495 GkrellmStyle *trayicons_style;
496 gint i;
497 GkrellmMargin *margin;
498 gint x, y;
499 GdkPixmap *bg_scaled = NULL;
500 GkrellmDecal *decal_bg = NULL;
501 GkrellmPiximage *bg = NULL;
502
503 if (panel) {
504 gkrellm_destroy_decal_list(panel);
505 for (i = 0; i < trayicons->len; i++) {
506 g_array_index(trayicons, item_t, i).but = NULL;
507 }
508 gkrellm_panel_destroy(panel);
509 }
510 panel = gkrellm_panel_new0();
511
512 trayicons_style = gkrellm_meter_style(DEFAULT_STYLE_ID);
513 margin = gkrellm_get_style_margins(trayicons_style);
514
515 /*
516 fprintf(stderr, "num icons: %d\n", trayicons->len);
517 fprintf(stderr, "chart width: %d\n", gkrellm_chart_width());
518 fprintf(stderr, "margin left: %d\n", margin->left);
519 fprintf(stderr, "margin right: %d\n", margin->right);
520 */
521
522 /* calculate height so we can create the background first */
523 x = margin->left;
524 y = margin->top;
525 for (i = 0; i < trayicons->len; i++) {
526 if (x + icon_size + margin->right > gkrellm_chart_width()) {
527 x = margin->left;
528 y += icon_size;
529 y += icon_padding;
530 }
531 x += icon_size;
532 x += icon_padding;
533 }
534
535 /* create the background */
536 if ((bg = gkrellm_bg_meter_piximage(DEFAULT_STYLE_ID))) {
537 gkrellm_scale_piximage_to_pixmap(bg, &bg_scaled, NULL,
538 gkrellm_chart_width(), y + icon_size + margin->bottom);
539 }
540
541 if (bg_scaled) {
542 decal_bg = gkrellm_create_decal_pixmap(panel, bg_scaled, NULL, 0, NULL, 0, 0);
543 gkrellm_draw_decal_pixmap(panel, decal_bg, 0);
544 }
545
546 /* position and draw all the icons */
547 x = margin->left;
548 y = margin->top;
549 for (i = 0; i < trayicons->len; i++) {
550 if (x + icon_size + margin->right > gkrellm_chart_width()) {
551 x = margin->left;
552 y += icon_size;
553 y += icon_padding;
554 }
555 /* fprintf(stderr, "%d, %d, %d\n", i, x, y); */
556 g_array_index(trayicons, item_t, i).x = x;
557 g_array_index(trayicons, item_t, i).y = y;
558 draw_icon(i, FALSE);
559 x += icon_size;
560 x += icon_padding;
561 }
562
563 /* configure and create the panel */
564 gkrellm_panel_configure(panel, NULL, trayicons_style);
565 if (trayicons->len > 0) {
566 gkrellm_panel_configure_set_height(panel, y + icon_size + margin->bottom);
567 }
568 else {
569 gkrellm_panel_configure_set_height(panel, 1);
570 gkrellm_panel_hide(panel);
571 }
572 gkrellm_panel_create(trayicons_vbox, monitor, panel);
573 gkrellm_draw_panel_layers(panel);
574
575 g_signal_connect(G_OBJECT(panel->drawing_area), "expose_event",
576 G_CALLBACK(panel_expose_event), panel);
577 g_signal_connect(G_OBJECT(panel->drawing_area), "button_press_event",
578 G_CALLBACK(cb_panel_button), NULL);
579 }
580
create_trayicons(GtkWidget * vbox,gint first_create)581 void create_trayicons(GtkWidget *vbox, gint first_create)
582 {
583 trayicons_vbox = vbox;
584 setup_trayicons(first_create);
585 update_trayicons_real();
586 }
587
588 /*
589 * Configuration page
590 */
591
592 static GtkWidget *activation_file_entry;
593 static GtkWidget *icon_active_file_entry;
594 static GtkWidget *icon_inactive_file_entry;
595 static GtkWidget *left_click_active_command_entry;
596 static GtkWidget *left_click_inactive_command_entry;
597 static GtkListStore *store_trayicons;
598 static GtkWidget *tree_trayicons;
599 static gint trayicons_item=0;
600 static GtkTreePath *path_selected = NULL;
601 static GtkWidget *btn_modify;
602 static GtkWidget *popup_fg_draw;
603 static GtkWidget *popup_bg_draw;
604
error_msg(gchar * message)605 void error_msg(gchar *message)
606 {
607 gkrellm_config_message_dialog("Error", message);
608 }
609
610 /*
611 static void
612 destroy_item(gpointer data)
613 {
614 g_free(((item_t *)data)->activation_file);
615 g_free(((item_t *)data)->icon_active_file);
616 g_free(((item_t *)data)->icon_inactive_file);
617 g_free(((item_t *)data)->left_click_active_command);
618 g_free(((item_t *)data)->left_click_inactive_command);
619 g_free(data);
620 }
621 */
622
on_clear_click(GtkButton * button,gpointer * data)623 static void on_clear_click(GtkButton *button, gpointer *data)
624 {
625 gtk_entry_set_text(GTK_ENTRY(activation_file_entry), "");
626 gtk_entry_set_text(GTK_ENTRY(icon_active_file_entry), "");
627 gtk_entry_set_text(GTK_ENTRY(icon_inactive_file_entry), "");
628 gtk_entry_set_text(GTK_ENTRY(left_click_active_command_entry), "");
629 gtk_entry_set_text(GTK_ENTRY(left_click_inactive_command_entry), "");
630 }
631
632
on_add_click(GtkButton * button,gpointer * data)633 static void on_add_click(GtkButton *button, gpointer *data)
634 {
635 struct stat st;
636 GtkTreeIter iter;
637 const gchar *activation_file = gtk_entry_get_text(GTK_ENTRY(activation_file_entry));
638 const gchar *icon_active_file = gtk_entry_get_text(GTK_ENTRY(icon_active_file_entry));
639 const gchar *icon_inactive_file = gtk_entry_get_text(GTK_ENTRY(icon_inactive_file_entry));
640 const gchar *left_click_active_command = gtk_entry_get_text(GTK_ENTRY(left_click_active_command_entry));
641 const gchar *left_click_inactive_command = gtk_entry_get_text(GTK_ENTRY(left_click_inactive_command_entry));
642
643 if (!activation_file[0])
644 {
645 error_msg("Please enter activation file path.");
646 return;
647 }
648
649 if (!icon_active_file[0]) {
650 error_msg("Please enter active icon path.");
651 return;
652 }
653
654 if (!icon_inactive_file[0]) {
655 error_msg("Please enter inactive icon path.");
656 return;
657 }
658
659 if (stat(activation_file, &st) == -1) {
660 error_msg("Activation file/dir doesn't exist.");
661 return;
662 }
663
664 if (stat(icon_active_file, &st) == -1) {
665 error_msg("Active icon file doesn't exist.");
666 return;
667 }
668
669 if (stat(icon_inactive_file, &st) == -1) {
670 error_msg("Inactive icon file doesn't exist.");
671 return;
672 }
673
674 if (GPOINTER_TO_INT(data) == 1) {
675 if (path_selected && gtk_tree_model_get_iter(GTK_TREE_MODEL(store_trayicons), &iter, path_selected)) {
676 gtk_list_store_set(store_trayicons, &iter,
677 ACTIVATION_FILE_COLUMN, activation_file,
678 ICON_ACTIVE_FILE_COLUMN, icon_active_file,
679 ICON_INACTIVE_FILE_COLUMN, icon_inactive_file,
680 LEFT_CLICK_ACTIVE_COMMAND_COLUMN, left_click_active_command,
681 LEFT_CLICK_INACTIVE_COMMAND_COLUMN, left_click_inactive_command,
682 ICON_ACTIVE_PIXBUF_COLUMN, get_pixbuf(icon_active_file, 16),
683 ICON_INACTIVE_PIXBUF_COLUMN, get_pixbuf(icon_inactive_file, 16),
684 -1);
685 }
686 }
687 else {
688 gtk_list_store_append(store_trayicons, &iter);
689 gtk_list_store_set(store_trayicons, &iter,
690 ACTIVATION_FILE_COLUMN, activation_file,
691 ICON_ACTIVE_FILE_COLUMN, icon_active_file,
692 ICON_INACTIVE_FILE_COLUMN, icon_inactive_file,
693 LEFT_CLICK_ACTIVE_COMMAND_COLUMN, left_click_active_command,
694 LEFT_CLICK_INACTIVE_COMMAND_COLUMN, left_click_inactive_command,
695 ICON_ACTIVE_PIXBUF_COLUMN, get_pixbuf(icon_active_file, 16),
696 ICON_INACTIVE_PIXBUF_COLUMN, get_pixbuf(icon_inactive_file, 16),
697 -1);
698 }
699
700 return;
701 }
702
on_del_click(GtkButton * button,gpointer * data)703 static void on_del_click(GtkButton *button, gpointer *data)
704 {
705 GtkTreeSelection *sel;
706 GtkListStore *store;
707 GtkTreeIter iter;
708
709 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_trayicons));
710 if (gtk_tree_selection_get_selected(sel, (GtkTreeModel **)&store, &iter)) {
711 gtk_list_store_remove(store, &iter);
712 }
713 }
714
on_up_click(GtkButton * button,gpointer * data)715 static void on_up_click(GtkButton *button, gpointer *data)
716 {
717 GtkTreeSelection *sel;
718 GtkListStore *store;
719 GtkTreeIter iter;
720
721 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_trayicons));
722 if (gtk_tree_selection_get_selected(sel, (GtkTreeModel **)&store, &iter)) {
723 gchar *path_str;
724 gint path_num;
725
726 path_str = gtk_tree_model_get_string_from_iter(GTK_TREE_MODEL(store), &iter);
727 path_num = atoi(path_str);
728
729 if (path_num - 2 >= -1) {
730 gchar npath[256];
731 GtkTreeIter iter2;
732 GtkTreePath *path;
733
734 if (path_num - 2 == -1) {
735 gtk_list_store_move_after(store, &iter, NULL);
736 }
737 else {
738 snprintf(npath, sizeof(npath), "%d", path_num - 2);
739 path = gtk_tree_path_new_from_string(npath);
740 gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter2, path);
741 gtk_list_store_move_after(store, &iter, &iter2);
742 }
743 }
744
745 g_free(path_str);
746 }
747 }
748
on_down_click(GtkButton * button,gpointer * data)749 static void on_down_click(GtkButton *button, gpointer *data)
750 {
751 GtkTreeSelection *sel;
752 GtkListStore *store;
753 GtkTreeIter iter;
754
755 sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_trayicons));
756 if (gtk_tree_selection_get_selected(sel, (GtkTreeModel **)&store, &iter)) {
757 GtkTreeIter iter2;
758 memcpy(&iter2, &iter, sizeof(iter));
759 if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter2)) {
760 gtk_list_store_move_after(store, &iter, &iter2);
761 }
762 }
763 }
764
on_colorsel_click(GtkButton * button,gpointer * data)765 static void on_colorsel_click(GtkButton *button, gpointer *data)
766 {
767 gint response;
768 GtkColorSelection *cs;
769 GtkWidget *colorseldlg;
770 gboolean fg = (GPOINTER_TO_INT(data) == 1 ? TRUE : FALSE);
771
772 /* Create color selection dialog */
773 colorseldlg = gtk_color_selection_dialog_new(fg ? "Select foreground color" : "Select background color");
774
775 /* Get the ColorSelection widget */
776 cs = GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(colorseldlg)->colorsel);
777
778 gtk_color_selection_set_previous_color(cs, fg ? &popup_fg_color : &popup_bg_color);
779 gtk_color_selection_set_current_color(cs, fg ? &popup_fg_color : &popup_bg_color);
780 gtk_color_selection_set_has_palette(cs, TRUE);
781
782 /* Show the dialog */
783 response = gtk_dialog_run(GTK_DIALOG(colorseldlg));
784
785 if (response == GTK_RESPONSE_OK) {
786 gtk_color_selection_get_current_color(cs, fg ? &popup_fg_color : &popup_bg_color);
787 gtk_widget_modify_bg(fg ? popup_fg_draw : popup_bg_draw,
788 GTK_STATE_NORMAL, fg ? &popup_fg_color : &popup_bg_color);
789 }
790
791 gtk_widget_destroy (colorseldlg);
792 }
793
cursor_changed(GtkTreeView * tree,gpointer data)794 static void cursor_changed(GtkTreeView *tree, gpointer data)
795 {
796 GtkTreeIter iter;
797 GtkTreePath *path;
798 gchar *activation_file;
799 gchar *icon_active_file;
800 gchar *icon_inactive_file;
801 gchar *left_click_active_command;
802 gchar *left_click_inactive_command;
803
804 gtk_tree_view_get_cursor(tree, &path, NULL);
805 if (path == NULL) {
806 return;
807 }
808
809 if (path_selected) gtk_tree_path_free(path_selected);
810 path_selected = gtk_tree_path_copy(path);
811 g_object_set(G_OBJECT(btn_modify), "sensitive", TRUE, NULL);
812
813 if (gtk_tree_model_get_iter(GTK_TREE_MODEL(store_trayicons), &iter, path)) {
814 gtk_tree_model_get(GTK_TREE_MODEL(store_trayicons), &iter,
815 ACTIVATION_FILE_COLUMN, &activation_file,
816 ICON_ACTIVE_FILE_COLUMN, &icon_active_file,
817 ICON_INACTIVE_FILE_COLUMN, &icon_inactive_file,
818 LEFT_CLICK_ACTIVE_COMMAND_COLUMN, &left_click_active_command,
819 LEFT_CLICK_INACTIVE_COMMAND_COLUMN, &left_click_inactive_command,
820 -1);
821
822 gtk_entry_set_text(GTK_ENTRY(activation_file_entry), activation_file);
823 gtk_entry_set_text(GTK_ENTRY(icon_active_file_entry), icon_active_file);
824 gtk_entry_set_text(GTK_ENTRY(icon_inactive_file_entry), icon_inactive_file);
825 gtk_entry_set_text(GTK_ENTRY(left_click_active_command_entry), left_click_active_command ?
826 left_click_active_command : "");
827 gtk_entry_set_text(GTK_ENTRY(left_click_inactive_command_entry),
828 left_click_inactive_command ? left_click_inactive_command : "");
829 }
830 }
831
832
row_toggled(GtkCellRendererText * renderer,gchar * row,gpointer data)833 static void row_toggled(GtkCellRendererText *renderer,
834 gchar *row, gpointer data)
835 {
836 GtkTreeIter iter;
837
838 if (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store_trayicons), &iter,
839 NULL, atoi(row))) {
840 gtk_list_store_set(store_trayicons, &iter, GPOINTER_TO_INT(data),
841 !gtk_cell_renderer_toggle_get_active(GTK_CELL_RENDERER_TOGGLE(renderer)), -1);
842 }
843 }
844
cb_icon_size(GtkMenuItem * item,gpointer data)845 static void cb_icon_size(GtkMenuItem *item, gpointer data)
846 {
847 icon_size = GPOINTER_TO_INT(data);
848 }
849
cb_icon_padding(GtkMenuItem * item,gpointer data)850 static void cb_icon_padding(GtkMenuItem *item, gpointer data)
851 {
852 icon_padding = GPOINTER_TO_INT(data);
853 }
854
cb_popup_timeout(GtkMenuItem * item,gpointer data)855 static void cb_popup_timeout(GtkMenuItem *item, gpointer data)
856 {
857 popup_timeout = GPOINTER_TO_INT(data);
858 }
859
860 static GtkWidget *picker;
861
store_filename(GtkButton * but,gpointer user_data)862 static void store_filename(GtkButton *but, gpointer user_data)
863 {
864 const gchar *selected_filename;
865
866 selected_filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (picker));
867 gtk_entry_set_text(GTK_ENTRY(user_data), selected_filename);
868 }
869
config_filepicker(GtkButton * button,gpointer * data)870 static void config_filepicker(GtkButton *button, gpointer *data)
871 {
872 picker = gtk_file_selection_new("Select file");
873 g_signal_connect(GTK_OBJECT(GTK_FILE_SELECTION(picker)->ok_button),
874 "clicked", G_CALLBACK(store_filename), data);
875
876 /* Ensure that the dialog box is destroyed when the user clicks a button. */
877 g_signal_connect_swapped (GTK_OBJECT (GTK_FILE_SELECTION (picker)->ok_button),
878 "clicked",
879 G_CALLBACK (gtk_widget_destroy),
880 (gpointer) picker);
881
882 g_signal_connect_swapped (GTK_OBJECT (GTK_FILE_SELECTION (picker)->cancel_button),
883 "clicked",
884 G_CALLBACK (gtk_widget_destroy),
885 (gpointer) picker);
886
887 gtk_widget_show(picker);
888 }
889
890 /* Create a new hbox with an image and a label packed into it
891 * and return the box. */
button_box(const gchar * label_text,const gchar * stock_id)892 GtkWidget *button_box(const gchar *label_text, const gchar *stock_id)
893 {
894 GtkWidget *box;
895 GtkWidget *label;
896 GtkWidget *image;
897 GtkWidget *button;
898
899 /* Create box for image and label */
900 box = gtk_hbox_new(FALSE, 0);
901 gtk_container_set_border_width(GTK_CONTAINER (box), 2);
902
903 /* Now on to the image stuff */
904 image = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_SMALL_TOOLBAR);
905
906 /* Create a label for the button */
907 label = gtk_label_new(label_text);
908
909 /* Pack the image and label into the box */
910 gtk_box_pack_start(GTK_BOX (box), image, FALSE, FALSE, 3);
911 gtk_box_pack_start(GTK_BOX (box), label, FALSE, FALSE, 3);
912
913 gtk_widget_show(image);
914 gtk_widget_show(label);
915 gtk_widget_show (box);
916
917 button = gtk_button_new();
918 gtk_container_add(GTK_CONTAINER(button), box);
919 gtk_widget_show(button);
920
921 return button;
922 }
923
create_trayicons_tab(GtkWidget * tab_vbox)924 static void create_trayicons_tab(GtkWidget *tab_vbox)
925 {
926 GtkWidget *vbox;
927 GtkWidget *tabs;
928 GtkWidget *btn_hbox;
929 GtkWidget *table;
930 GtkWidget *table_set;
931 gint i;
932
933 tabs = gtk_notebook_new();
934 gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs), GTK_POS_TOP);
935 gtk_box_pack_start(GTK_BOX(tab_vbox), tabs, TRUE, TRUE, 0);
936
937 /* File location tab */
938
939 vbox = gkrellm_gtk_notebook_page(tabs, "Icons");
940 btn_hbox = gtk_hbox_new(FALSE, 5);
941
942 /* buttons */
943 {
944 GtkWidget *btn_add;
945 GtkWidget *btn_del;
946 GtkWidget *btn_clear;
947 GtkWidget *btn_up;
948 GtkWidget *btn_down;
949
950 btn_add = button_box("Add", GTK_STOCK_ADD);
951 gtk_signal_connect(GTK_OBJECT(btn_add), "clicked",
952 GTK_SIGNAL_FUNC(on_add_click), GINT_TO_POINTER(0));
953
954 btn_del = button_box("Remove", GTK_STOCK_REMOVE);
955 gtk_signal_connect(GTK_OBJECT(btn_del), "clicked",
956 GTK_SIGNAL_FUNC(on_del_click), NULL);
957
958 btn_modify = button_box("Modify selected", GTK_STOCK_APPLY);
959 gtk_signal_connect(GTK_OBJECT(btn_modify), "clicked",
960 GTK_SIGNAL_FUNC(on_add_click), GINT_TO_POINTER(1));
961 g_object_set(G_OBJECT(btn_modify), "sensitive", FALSE, NULL);
962
963 btn_clear = button_box("Clear", GTK_STOCK_CLEAR);
964 gtk_signal_connect(GTK_OBJECT(btn_clear), "clicked",
965 GTK_SIGNAL_FUNC(on_clear_click), NULL);
966
967 btn_up = button_box("Up", GTK_STOCK_GO_UP);
968 gtk_signal_connect(GTK_OBJECT(btn_up), "clicked",
969 GTK_SIGNAL_FUNC(on_up_click), NULL);
970
971 btn_down = button_box("Down", GTK_STOCK_GO_DOWN);
972 gtk_signal_connect(GTK_OBJECT(btn_down), "clicked",
973 GTK_SIGNAL_FUNC(on_down_click), NULL);
974
975 gtk_box_pack_start(GTK_BOX(btn_hbox), btn_add, TRUE, TRUE, 2);
976 gtk_box_pack_start(GTK_BOX(btn_hbox), btn_del, TRUE, TRUE, 2);
977 gtk_box_pack_start(GTK_BOX(btn_hbox), btn_modify, TRUE, TRUE, 2);
978 gtk_box_pack_start(GTK_BOX(btn_hbox), btn_up, TRUE, TRUE, 2);
979 gtk_box_pack_start(GTK_BOX(btn_hbox), btn_down, TRUE, TRUE, 2);
980 gtk_box_pack_start(GTK_BOX(btn_hbox), btn_clear, TRUE, TRUE, 2);
981 }
982
983 store_trayicons = gtk_list_store_new(N_COLUMNS, G_TYPE_STRING,
984 GDK_TYPE_PIXBUF, G_TYPE_STRING,
985 GDK_TYPE_PIXBUF, G_TYPE_STRING,
986 G_TYPE_STRING, G_TYPE_STRING,
987 G_TYPE_BOOLEAN, G_TYPE_BOOLEAN);
988
989 for (i = 0; i < trayicons->len; i++)
990 {
991 GtkTreeIter iter;
992 gtk_list_store_append(store_trayicons, &iter);
993 gtk_list_store_set(store_trayicons, &iter,
994 ACTIVATION_FILE_COLUMN, g_strdup(g_array_index(trayicons,item_t,i).activation_file),
995 ICON_ACTIVE_PIXBUF_COLUMN, get_pixbuf(g_array_index(trayicons,item_t,i).icon_active_file, 16),
996 ICON_ACTIVE_FILE_COLUMN, g_strdup(g_array_index(trayicons,item_t,i).icon_active_file),
997 ICON_INACTIVE_PIXBUF_COLUMN, get_pixbuf(g_array_index(trayicons,item_t,i).icon_inactive_file, 16),
998 ICON_INACTIVE_FILE_COLUMN, g_strdup(g_array_index(trayicons,item_t,i).icon_inactive_file),
999 LEFT_CLICK_ACTIVE_COMMAND_COLUMN, g_strdup(g_array_index(trayicons,item_t,i).left_click_active_command),
1000 LEFT_CLICK_INACTIVE_COMMAND_COLUMN, g_strdup(g_array_index(trayicons,item_t,i).left_click_inactive_command),
1001 BLINK_COLUMN, g_array_index(trayicons,item_t,i).blink,
1002 POPUP_COLUMN, g_array_index(trayicons,item_t,i).popup,
1003 -1
1004 );
1005 }
1006 trayicons_item=0;
1007
1008 table = gtk_table_new(4, 3, FALSE);
1009
1010 /* activation file */
1011 {
1012 GtkWidget *activation_file_picker_but;
1013 GtkWidget *activation_file_lbl;
1014 GtkWidget *activation_file_align;
1015 GtkWidget *warning_lbl;
1016
1017 activation_file_entry = gtk_entry_new_with_max_length(255);
1018 activation_file_picker_but = button_box("Pick file", GTK_STOCK_OPEN);
1019 g_signal_connect(G_OBJECT(activation_file_picker_but), "clicked",
1020 G_CALLBACK(config_filepicker), activation_file_entry);
1021 activation_file_align = gtk_alignment_new(0, 0.5, 0, 0);
1022 activation_file_lbl=gtk_label_new("Activation file/dir path:");
1023 gtk_container_add(GTK_CONTAINER(activation_file_align), activation_file_lbl);
1024 gtk_table_attach(GTK_TABLE(table), activation_file_align, 0, 1, 0, 1, GTK_FILL, 0, 5, 5);
1025 gtk_table_attach(GTK_TABLE(table), activation_file_entry, 1, 2, 0, 1, GTK_FILL | GTK_EXPAND, 0, 5, 5);
1026 gtk_table_attach(GTK_TABLE(table), activation_file_picker_but, 2, 3, 0, 1, GTK_FILL, 0, 5, 5);
1027
1028 /* warning */
1029 warning_lbl=gtk_label_new("WARNING: All files in the specified directory are *deleted*.");
1030 gtk_table_attach(GTK_TABLE(table), warning_lbl, 1, 2, 1, 2, GTK_FILL | GTK_EXPAND, 0, 5, 5);
1031 }
1032
1033 /* icon active */
1034 {
1035 GtkWidget *icon_active_file_picker_but;
1036 GtkWidget *icon_active_file_align;
1037 GtkWidget *icon_active_file_lbl;
1038
1039 icon_active_file_entry = gtk_entry_new_with_max_length(255);
1040 icon_active_file_picker_but = button_box("Pick file", GTK_STOCK_OPEN);
1041 g_signal_connect(G_OBJECT(icon_active_file_picker_but), "clicked",
1042 G_CALLBACK(config_filepicker), icon_active_file_entry);
1043 icon_active_file_align = gtk_alignment_new(0, 0.5, 0, 0);
1044 icon_active_file_lbl=gtk_label_new("Active icon file path:");
1045 gtk_container_add(GTK_CONTAINER(icon_active_file_align), icon_active_file_lbl);
1046 gtk_table_attach(GTK_TABLE(table), icon_active_file_align, 0, 1, 2, 3, GTK_FILL, 0, 5, 5);
1047 gtk_table_attach(GTK_TABLE(table), icon_active_file_entry, 1, 2, 2, 3, GTK_FILL | GTK_EXPAND, 0, 5, 5);
1048 gtk_table_attach(GTK_TABLE(table), icon_active_file_picker_but, 2, 3, 2, 3, GTK_FILL, 0, 5, 5);
1049 }
1050
1051 /* icon inactive */
1052 {
1053 GtkWidget *icon_inactive_file_picker_but;
1054 GtkWidget *icon_inactive_file_align;
1055 GtkWidget *icon_inactive_file_lbl;
1056
1057 icon_inactive_file_entry = gtk_entry_new_with_max_length(255);
1058 icon_inactive_file_picker_but = button_box("Pick file", GTK_STOCK_OPEN);
1059 g_signal_connect(G_OBJECT(icon_inactive_file_picker_but), "clicked",
1060 G_CALLBACK(config_filepicker), icon_inactive_file_entry);
1061 icon_inactive_file_align = gtk_alignment_new(0, 0.5, 0, 0);
1062 icon_inactive_file_lbl=gtk_label_new("Inactive icon file path:");
1063 gtk_container_add(GTK_CONTAINER(icon_inactive_file_align), icon_inactive_file_lbl);
1064 gtk_table_attach(GTK_TABLE(table), icon_inactive_file_align, 0, 1, 3, 4, GTK_FILL, 0, 5, 5);
1065 gtk_table_attach(GTK_TABLE(table), icon_inactive_file_entry, 1, 2, 3, 4, GTK_FILL | GTK_EXPAND, 0, 5, 5);
1066 gtk_table_attach(GTK_TABLE(table), icon_inactive_file_picker_but, 2, 3, 3, 4, GTK_FILL, 0, 5, 5);
1067 }
1068
1069 /* left click active command */
1070 {
1071 GtkWidget *left_click_active_command_align;
1072 GtkWidget *left_click_active_command_lbl;
1073
1074 left_click_active_command_align = gtk_alignment_new(0, 0.5, 0, 0);
1075 left_click_active_command_lbl=gtk_label_new("Active command:");
1076 gtk_container_add(GTK_CONTAINER(left_click_active_command_align), left_click_active_command_lbl);
1077 left_click_active_command_entry = gtk_entry_new_with_max_length(255);
1078 gtk_table_attach(GTK_TABLE(table), left_click_active_command_align, 0, 1, 4, 5, GTK_FILL, 0, 5, 5);
1079 gtk_table_attach(GTK_TABLE(table), left_click_active_command_entry, 1, 2, 4, 5, GTK_FILL | GTK_EXPAND, 0, 5, 5);
1080 }
1081
1082 /* left click inactive command */
1083 {
1084 GtkWidget *left_click_inactive_command_align;
1085 GtkWidget *left_click_inactive_command_lbl;
1086
1087 left_click_inactive_command_align = gtk_alignment_new(0, 0.5, 0, 0);
1088 left_click_inactive_command_lbl=gtk_label_new("Inactive command:");
1089 gtk_container_add(GTK_CONTAINER(left_click_inactive_command_align), left_click_inactive_command_lbl);
1090 left_click_inactive_command_entry = gtk_entry_new_with_max_length(255);
1091 gtk_table_attach(GTK_TABLE(table), left_click_inactive_command_align, 0, 1, 5, 6, GTK_FILL, 0, 5, 5);
1092 gtk_table_attach(GTK_TABLE(table), left_click_inactive_command_entry, 1, 2, 5, 6, GTK_FILL | GTK_EXPAND, 0, 5, 5);
1093 }
1094
1095 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 2);
1096 gtk_box_pack_start(GTK_BOX(vbox), btn_hbox, FALSE, FALSE, 2);
1097
1098 /* tree view and its columns */
1099 {
1100 GtkTreeSelection *select;
1101 GtkCellRenderer *renderer;
1102 GtkTreeViewColumn *column;
1103 GdkScreen *screen;
1104 GtkWidget *scrolled_window;
1105 gint tree_width;
1106
1107 tree_trayicons = gtk_tree_view_new_with_model (GTK_TREE_MODEL(store_trayicons));
1108 select = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_trayicons));
1109 gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);
1110
1111 screen = gtk_widget_get_screen(tree_trayicons);
1112 tree_width = gdk_screen_get_width(screen) - TREE_SIZE_PADDING;
1113 if (tree_width > TREE_SIZE_MAX) tree_width = TREE_SIZE_MAX;
1114
1115 /* column pixbuf - icon active */
1116 renderer = gtk_cell_renderer_pixbuf_new();
1117 column = gtk_tree_view_column_new_with_attributes ("Active icon", renderer,
1118 "pixbuf", ICON_ACTIVE_PIXBUF_COLUMN, NULL);
1119 g_object_set(G_OBJECT(column), "resizable", FALSE, NULL);
1120 gtk_tree_view_append_column (GTK_TREE_VIEW(tree_trayicons), column);
1121
1122 /* column pixbuf - icon inactive */
1123 renderer = gtk_cell_renderer_pixbuf_new();
1124 column = gtk_tree_view_column_new_with_attributes ("Inactive icon", renderer,
1125 "pixbuf", ICON_INACTIVE_PIXBUF_COLUMN, NULL);
1126 g_object_set(G_OBJECT(column), "resizable", FALSE, NULL);
1127 gtk_tree_view_append_column (GTK_TREE_VIEW(tree_trayicons), column);
1128
1129 /* column blink */
1130 renderer = gtk_cell_renderer_toggle_new();
1131 g_object_set(G_OBJECT(renderer), "activatable", TRUE, NULL);
1132 g_signal_connect(G_OBJECT(renderer), "toggled",
1133 G_CALLBACK(row_toggled), GINT_TO_POINTER(BLINK_COLUMN));
1134 column = gtk_tree_view_column_new_with_attributes ("Blink", renderer,
1135 "active", BLINK_COLUMN,
1136 NULL);
1137 g_object_set(G_OBJECT(column), "resizable", FALSE, NULL);
1138 gtk_tree_view_append_column (GTK_TREE_VIEW(tree_trayicons), column);
1139
1140 /* column popup */
1141 renderer = gtk_cell_renderer_toggle_new();
1142 g_object_set(G_OBJECT(renderer), "activatable", TRUE, NULL);
1143 g_signal_connect(G_OBJECT(renderer), "toggled",
1144 G_CALLBACK(row_toggled), GINT_TO_POINTER(POPUP_COLUMN));
1145 column = gtk_tree_view_column_new_with_attributes ("Popup", renderer,
1146 "active", POPUP_COLUMN,
1147 NULL);
1148 g_object_set(G_OBJECT(column), "resizable", FALSE, NULL);
1149 gtk_tree_view_append_column (GTK_TREE_VIEW(tree_trayicons), column);
1150
1151 /* column activation file */
1152 renderer = gtk_cell_renderer_text_new();
1153 g_object_set(G_OBJECT(renderer), "editable", FALSE, NULL);
1154 column = gtk_tree_view_column_new_with_attributes ("Activation file/dir", renderer,
1155 "text", ACTIVATION_FILE_COLUMN, NULL);
1156 g_object_set(G_OBJECT(column), "resizable", TRUE, NULL);
1157 gtk_tree_view_column_set_max_width(column, 300);
1158 gtk_tree_view_append_column (GTK_TREE_VIEW(tree_trayicons), column);
1159
1160 /* tree view settings */
1161 g_object_set(G_OBJECT(tree_trayicons), "headers-visible", TRUE, NULL);
1162 gtk_widget_set_size_request(tree_trayicons, tree_width, TREE_HEIGHT);
1163
1164 gtk_tree_view_columns_autosize(GTK_TREE_VIEW(tree_trayicons));
1165 scrolled_window = gtk_scrolled_window_new(NULL, NULL);
1166 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1167 gtk_container_add(GTK_CONTAINER(scrolled_window), tree_trayicons);
1168 gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 12);
1169 g_signal_connect(G_OBJECT(tree_trayicons), "cursor-changed",
1170 G_CALLBACK(cursor_changed), NULL);
1171 }
1172
1173 /****************/
1174 /* Settings tab */
1175 /****************/
1176 vbox = gkrellm_gtk_notebook_page(tabs, "Settings");
1177 table_set = gtk_table_new(5, 2, FALSE);
1178
1179 /* icon size */
1180 {
1181 GtkWidget *icon_size_lbl;
1182 GtkWidget *icon_size_align;
1183 GtkWidget *icon_size_align_optmenu;
1184 GtkWidget *icon_size_menu;
1185 GtkWidget *icon_size_optmenu;
1186 gint select_icon_size = 0;
1187 static const struct ConfigIconSize {
1188 gchar *title;
1189 gint size;
1190 } config_icon_size[] = {
1191 { "16 x 16", 16 },
1192 { "20 x 20", 20 },
1193 { "24 x 24", 24 },
1194 { "32 x 32", 32 },
1195 { "48 x 48", 48 },
1196 { "64 x 64", 64 },
1197 };
1198
1199 icon_size_lbl = gtk_label_new("Size at which icons will be displayed:");
1200 icon_size_align = gtk_alignment_new(1, 0, 0, 0);
1201 gtk_container_add(GTK_CONTAINER(icon_size_align), icon_size_lbl);
1202 gtk_table_attach(GTK_TABLE(table_set), icon_size_align, 0, 1, 0, 1, GTK_FILL, 0, 5, 5);
1203
1204 icon_size_menu = gtk_menu_new();
1205 for (i = 0; i < sizeof(config_icon_size) / sizeof(struct ConfigIconSize); i++) {
1206 GtkWidget *item;
1207 item = gtk_menu_item_new_with_label(config_icon_size[i].title);
1208 g_signal_connect(G_OBJECT(item), "select", G_CALLBACK(cb_icon_size),
1209 GINT_TO_POINTER(config_icon_size[i].size));
1210 gtk_menu_shell_append(GTK_MENU_SHELL(icon_size_menu), item);
1211 if (config_icon_size[i].size == icon_size) {
1212 select_icon_size = i;
1213 }
1214 }
1215
1216 icon_size_optmenu = gtk_option_menu_new();
1217 gtk_option_menu_set_menu(GTK_OPTION_MENU(icon_size_optmenu), icon_size_menu);
1218 gtk_option_menu_set_history(GTK_OPTION_MENU(icon_size_optmenu), select_icon_size);
1219 icon_size_align_optmenu = gtk_alignment_new(0, 0, 0, 0);
1220 gtk_container_add(GTK_CONTAINER(icon_size_align_optmenu), icon_size_optmenu);
1221 gtk_table_attach(GTK_TABLE(table_set), icon_size_align_optmenu, 1, 2, 0, 1, GTK_FILL, 0, 5, 5);
1222 }
1223
1224 /* icon padding */
1225 {
1226 GtkWidget *icon_padding_lbl;
1227 GtkWidget *icon_padding_align;
1228 GtkWidget *icon_padding_align_optmenu;
1229 GtkWidget *icon_padding_menu;
1230 GtkWidget *icon_padding_optmenu;
1231 gint select_icon_padding = 0;
1232
1233 icon_padding_lbl = gtk_label_new("Padding between icons:");
1234 icon_padding_align = gtk_alignment_new(1, 0, 0, 0);
1235 gtk_container_add(GTK_CONTAINER(icon_padding_align), icon_padding_lbl);
1236 gtk_table_attach(GTK_TABLE(table_set), icon_padding_align, 0, 1, 1, 2, GTK_FILL, 0, 5, 5);
1237
1238 icon_padding_menu = gtk_menu_new();
1239 for (i = 1; i <= 16; i++) {
1240 GtkWidget *item;
1241 gchar label[128];
1242 snprintf(label, sizeof(label), "%d", i);
1243 item = gtk_menu_item_new_with_label(label);
1244 g_signal_connect(G_OBJECT(item), "select", G_CALLBACK(cb_icon_padding),
1245 GINT_TO_POINTER(i));
1246 gtk_menu_shell_append(GTK_MENU_SHELL(icon_padding_menu), item);
1247 if (i == icon_padding) {
1248 select_icon_padding = i - 1;
1249 }
1250 }
1251
1252 icon_padding_optmenu = gtk_option_menu_new();
1253 gtk_option_menu_set_menu(GTK_OPTION_MENU(icon_padding_optmenu), icon_padding_menu);
1254 gtk_option_menu_set_history(GTK_OPTION_MENU(icon_padding_optmenu), select_icon_padding);
1255 icon_padding_align_optmenu = gtk_alignment_new(0, 0, 0, 0);
1256 gtk_container_add(GTK_CONTAINER(icon_padding_align_optmenu), icon_padding_optmenu);
1257 gtk_table_attach(GTK_TABLE(table_set), icon_padding_align_optmenu, 1, 2, 1, 2, GTK_FILL, 0, 5, 5);
1258 }
1259
1260 /* popup timeout */
1261 {
1262 GtkWidget *popup_timeout_lbl;
1263 GtkWidget *popup_timeout_align;
1264 GtkWidget *popup_timeout_align_optmenu;
1265 GtkWidget *popup_timeout_menu;
1266 GtkWidget *popup_timeout_optmenu;
1267 gint select_popup_timeout = 0;
1268 static const gint config_popup_timeout[] = {
1269 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
1270 12, 14, 16, 18, 20, 25, 30, 40, 50, 60,
1271 -1 /* end */
1272 };
1273
1274 popup_timeout_lbl = gtk_label_new("Popup timeout:");
1275 popup_timeout_align = gtk_alignment_new(1, 0, 0, 0);
1276 gtk_container_add(GTK_CONTAINER(popup_timeout_align), popup_timeout_lbl);
1277 gtk_table_attach(GTK_TABLE(table_set), popup_timeout_align, 0, 1, 2, 3, GTK_FILL, 0, 5, 5);
1278
1279 popup_timeout_menu = gtk_menu_new();
1280 i = 0;
1281 while (config_popup_timeout[i] != -1) {
1282 GtkWidget *item;
1283 gchar label[128];
1284 gint timeout = config_popup_timeout[i];
1285
1286 snprintf(label, sizeof(label), "%d", timeout);
1287 item = gtk_menu_item_new_with_label(label);
1288 g_signal_connect(G_OBJECT(item), "select", G_CALLBACK(cb_popup_timeout),
1289 GINT_TO_POINTER(timeout));
1290 gtk_menu_shell_append(GTK_MENU_SHELL(popup_timeout_menu), item);
1291 if (timeout == popup_timeout) {
1292 select_popup_timeout = i;
1293 }
1294 i++;
1295 }
1296
1297 popup_timeout_optmenu = gtk_option_menu_new();
1298 gtk_option_menu_set_menu(GTK_OPTION_MENU(popup_timeout_optmenu), popup_timeout_menu);
1299 gtk_option_menu_set_history(GTK_OPTION_MENU(popup_timeout_optmenu), select_popup_timeout);
1300 popup_timeout_align_optmenu = gtk_alignment_new(0, 0, 0, 0);
1301 gtk_container_add(GTK_CONTAINER(popup_timeout_align_optmenu), popup_timeout_optmenu);
1302 gtk_table_attach(GTK_TABLE(table_set), popup_timeout_align_optmenu, 1, 2, 2, 3, GTK_FILL, 0, 5, 5);
1303 }
1304
1305 /* popup foreground color */
1306 {
1307 GtkWidget *popup_fg_lbl;
1308 GtkWidget *popup_fg_align;
1309 GtkWidget *popup_fg_button;
1310
1311 popup_fg_lbl = gtk_label_new("Popup foreground color:");
1312 popup_fg_align = gtk_alignment_new(1, 0, 0, 0);
1313 gtk_container_add(GTK_CONTAINER(popup_fg_align), popup_fg_lbl);
1314 gtk_table_attach(GTK_TABLE(table_set), popup_fg_align, 0, 1, 3, 4, GTK_FILL, 0, 5, 5);
1315
1316 popup_fg_draw = gtk_drawing_area_new();
1317 gtk_widget_modify_bg(popup_fg_draw, GTK_STATE_NORMAL, &popup_fg_color);
1318 gtk_widget_set_size_request(GTK_WIDGET(popup_fg_draw), 40, 15);
1319
1320 popup_fg_button = gtk_button_new();
1321 gtk_container_add(GTK_CONTAINER(popup_fg_button), popup_fg_draw);
1322 gtk_signal_connect(GTK_OBJECT(popup_fg_button), "clicked",
1323 GTK_SIGNAL_FUNC(on_colorsel_click), GINT_TO_POINTER(1));
1324
1325 gtk_table_attach(GTK_TABLE(table_set), popup_fg_button, 1, 2, 3, 4, GTK_FILL, 0, 5, 5);
1326 }
1327
1328 /* popup background color */
1329 {
1330 GtkWidget *popup_bg_lbl;
1331 GtkWidget *popup_bg_align;
1332 GtkWidget *popup_bg_button;
1333
1334 popup_bg_lbl = gtk_label_new("Popup background color:");
1335 popup_bg_align = gtk_alignment_new(1, 0, 0, 0);
1336 gtk_container_add(GTK_CONTAINER(popup_bg_align), popup_bg_lbl);
1337 gtk_table_attach(GTK_TABLE(table_set), popup_bg_align, 0, 1, 4, 5, GTK_FILL, 0, 5, 5);
1338
1339 popup_bg_draw = gtk_drawing_area_new();
1340 gtk_widget_modify_bg(popup_bg_draw, GTK_STATE_NORMAL, &popup_bg_color);
1341 gtk_widget_set_size_request(GTK_WIDGET(popup_bg_draw), 40, 15);
1342
1343 popup_bg_button = gtk_button_new();
1344 gtk_container_add(GTK_CONTAINER(popup_bg_button), popup_bg_draw);
1345 gtk_signal_connect(GTK_OBJECT(popup_bg_button), "clicked",
1346 GTK_SIGNAL_FUNC(on_colorsel_click), GINT_TO_POINTER(0));
1347
1348 gtk_table_attach(GTK_TABLE(table_set), popup_bg_button, 1, 2, 4, 5, GTK_FILL, 0, 5, 5);
1349 }
1350
1351 gtk_box_pack_start(GTK_BOX(vbox), table_set, FALSE, FALSE, 2);
1352
1353 /************/
1354 /* Info tab */
1355 /************/
1356 {
1357 GtkWidget *info_text_w;
1358 static const gchar *trayicons_info_text[] = {
1359 "<b>Trayicons plugin " VERSION "\n",
1360 "\n",
1361 "<b>Usage:\n",
1362 "left click - deactivate the icon and run the command\n"
1363 "right click - deactivate the icon\n"
1364 "middle click - open the configuration dialog\n"
1365 "\n",
1366 "<b>Homepage: ",
1367 "http://sweb.cz/tripie/gkrellm/trayicons/\n",
1368 "<b>Author: ",
1369 "Tomas Styblo <tripie@cpan.org>\n"
1370 "\n"
1371 "Copyright (C) 2003\n"
1372 "Distributed under the ",
1373 "<b>GNU General Public License (GPL)\n"
1374 };
1375
1376 vbox = gkrellm_gtk_notebook_page(tabs, "Info");
1377 info_text_w = gkrellm_gtk_scrolled_text_view(vbox, NULL,
1378 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1379 gkrellm_gtk_text_view_append_strings(info_text_w, (char **)trayicons_info_text,
1380 sizeof(trayicons_info_text) / sizeof(gchar *));
1381 }
1382 }
1383
get_pixbuf(const gchar * filename,gint size)1384 static GdkPixbuf *get_pixbuf(const gchar *filename, gint size)
1385 {
1386 GdkPixbuf *px = NULL;
1387
1388 if (! (px = gdk_pixbuf_new_from_file(filename, NULL))) {
1389 return NULL;
1390 }
1391
1392 return gdk_pixbuf_scale_simple(px, size, size, GDK_INTERP_BILINEAR);
1393 }
1394
save_trayicons_config(FILE * f)1395 static void save_trayicons_config(FILE *f)
1396 {
1397 gint i;
1398
1399 /*
1400 printf("Saving config...\n");
1401 */
1402
1403 fprintf(f, "trayicons icon_size %i\n", icon_size);
1404 fprintf(f, "trayicons icon_padding %i\n", icon_padding);
1405 fprintf(f, "trayicons popup_timeout %i\n", popup_timeout);
1406 fprintf(f, "trayicons popup_fg_color #%04X%04X%04X\n",
1407 popup_fg_color.red, popup_fg_color.green, popup_fg_color.blue);
1408 fprintf(f, "trayicons popup_bg_color #%04X%04X%04X\n",
1409 popup_bg_color.red, popup_bg_color.green, popup_bg_color.blue);
1410 for (i = 0; i < trayicons->len; i++)
1411 {
1412 fprintf(f,"trayicons activation_file%i %s\n",i,g_array_index(trayicons,item_t,i).activation_file);
1413 fprintf(f,"trayicons icon_active_file%i %s\n",i,g_array_index(trayicons,item_t,i).icon_active_file);
1414 fprintf(f,"trayicons icon_inactive_file%i %s\n",i,g_array_index(trayicons,item_t,i).icon_inactive_file);
1415 if (g_array_index(trayicons,item_t,i).left_click_active_command) {
1416 fprintf(f,"trayicons left_click_active_command%i %s\n",i,g_array_index(trayicons,item_t,i).left_click_active_command);
1417 }
1418 if (g_array_index(trayicons,item_t,i).left_click_inactive_command) {
1419 fprintf(f,"trayicons left_click_inactive_command%i %s\n",i,g_array_index(trayicons,item_t,i).left_click_inactive_command);
1420 }
1421 fprintf(f,"trayicons blink%i %d\n",i,g_array_index(trayicons,item_t,i).blink);
1422
1423 /* popup must be the last - see load_trayicons_config() */
1424 fprintf(f,"trayicons popup%i %d\n",i,g_array_index(trayicons,item_t,i).popup);
1425 }
1426 }
1427
1428 static item_t c;
1429
load_trayicons_config(gchar * arg)1430 static void load_trayicons_config(gchar *arg)
1431 {
1432 gchar buf[MY_BUFLEN+1];
1433 gint i;
1434 gboolean boolean;
1435
1436 /*
1437 printf("trayicons_config=<%s>\n", arg);
1438 */
1439
1440 if (sscanf(arg, "icon_size %i",&i) == 1) {
1441 icon_size = i;
1442 }
1443 else if (sscanf(arg, "icon_padding %i",&i) == 1) {
1444 icon_padding = i;
1445 }
1446 else if (sscanf(arg, "popup_timeout %i",&i) == 1) {
1447 popup_timeout = i;
1448 }
1449 else if (sscanf(arg, "popup_fg_color %" xstr(MY_BUFLEN) "s", buf) == 1) {
1450 if (!gdk_color_parse(buf, &popup_fg_color)) {
1451 fprintf(stderr, "gkrellm-trayicons: cannot parse color: %s\n", buf);
1452 }
1453 }
1454 else if (sscanf(arg, "popup_bg_color %" xstr(MY_BUFLEN) "s", buf) == 1) {
1455 if (!gdk_color_parse(buf, &popup_bg_color)) {
1456 fprintf(stderr, "gkrellm-trayicons: cannot parse color: %s\n", buf);
1457 }
1458 }
1459 else if (sscanf(arg, "activation_file%i %" xstr(MY_BUFLEN) "s", &i, buf) == 2) {
1460 c.activation_file = g_strdup(buf);
1461 }
1462 else if (sscanf(arg, "icon_active_file%i %" xstr(MY_BUFLEN) "s", &i, buf) == 2) {
1463 c.icon_active_file = g_strdup(buf);
1464 }
1465 else if (sscanf(arg, "icon_inactive_file%i %" xstr(MY_BUFLEN) "s", &i, buf) == 2) {
1466 c.icon_inactive_file = g_strdup(buf);
1467 }
1468 else if (strncmp(arg, "left_click_active_command", strlen("left_click_active_command")) == 0) {
1469 char *p;
1470 if ((p = strchr(arg, ' '))) {
1471 c.left_click_active_command = g_strdup(p+1);
1472 }
1473 }
1474 else if (strncmp(arg, "left_click_inactive_command", strlen("left_click_inactive_command")) == 0) {
1475 char *p;
1476 if ((p = strchr(arg, ' '))) {
1477 c.left_click_inactive_command = g_strdup(p+1);
1478 }
1479 }
1480 else if (sscanf(arg, "blink%i %i",&i,&boolean) == 2) {
1481 c.blink = boolean;
1482 }
1483 else if (sscanf(arg, "popup%i %i",&i,&boolean) == 2) {
1484 c.popup = boolean;
1485 /* finish the item */
1486 g_array_append_val(trayicons, c);
1487 memset(&c, 0, sizeof(c));
1488 }
1489 }
1490
apply_trayicons_config()1491 static void apply_trayicons_config()
1492 {
1493 gint i;
1494 GtkTreeIter iter;
1495
1496 /*
1497 printf("Applying config...\n");
1498 */
1499
1500 for (i = 0; i < trayicons->len; i++)
1501 {
1502 g_free(g_array_index(trayicons, item_t, i).activation_file);
1503 g_free(g_array_index(trayicons, item_t, i).icon_active_file);
1504 g_free(g_array_index(trayicons, item_t, i).icon_inactive_file);
1505 g_free(g_array_index(trayicons, item_t, i).left_click_active_command);
1506 g_free(g_array_index(trayicons, item_t, i).left_click_inactive_command);
1507 gkrellm_destroy_button(g_array_index(trayicons, item_t, i).but);
1508 /*
1509 if (g_array_index(trayicons, item_t, i).buf) {
1510 g_string_free(g_array_index(trayicons, item_t, i).buf, TRUE);
1511 }
1512 */
1513 }
1514
1515 g_array_free(trayicons, TRUE);
1516 trayicons=g_array_new(FALSE, TRUE, sizeof(item_t));
1517 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store_trayicons), &iter)) {
1518 do {
1519 item_t item;
1520 memset(&item, 0, sizeof(item));
1521 gtk_tree_model_get(GTK_TREE_MODEL(store_trayicons), &iter,
1522 ACTIVATION_FILE_COLUMN, &item.activation_file,
1523 ICON_ACTIVE_FILE_COLUMN, &item.icon_active_file,
1524 ICON_INACTIVE_FILE_COLUMN, &item.icon_inactive_file,
1525 LEFT_CLICK_ACTIVE_COMMAND_COLUMN, &item.left_click_active_command,
1526 LEFT_CLICK_INACTIVE_COMMAND_COLUMN, &item.left_click_inactive_command,
1527 BLINK_COLUMN, &item.blink,
1528 POPUP_COLUMN, &item.popup,
1529 -1);
1530
1531 if (item.left_click_active_command != NULL &&
1532 strlen(item.left_click_active_command) == 0) {
1533 item.left_click_active_command = NULL;
1534 }
1535 if (item.left_click_inactive_command != NULL &&
1536 strlen(item.left_click_inactive_command) == 0) {
1537 item.left_click_inactive_command = NULL;
1538 }
1539 g_array_append_val(trayicons, item);
1540 } while (gtk_tree_model_iter_next(GTK_TREE_MODEL(store_trayicons), &iter));
1541 }
1542
1543 setup_trayicons(0);
1544 update_trayicons_real();
1545 }
1546
1547
1548 static GkrellmMonitor plugin_mon =
1549 {
1550 "Trayicons", /* Name, for config tab. */
1551 0, /* Id, 0 if a plugin */
1552 create_trayicons, /* The create function */
1553 update_trayicons, /* The update function */
1554 create_trayicons_tab, /* The config tab create function */
1555 apply_trayicons_config, /* Apply the config function */
1556 save_trayicons_config, /* Save user config */
1557 load_trayicons_config, /* Load user config */
1558 "trayicons", /* config keyword */
1559 NULL, /* Undefined 2 */
1560 NULL, /* Undefined 1 */
1561 NULL, /* Undefined 0 */
1562 MON_APM, /* Insert plugin before this monitor */
1563 NULL, /* Handle if a plugin, filled in by GKrellM */
1564 NULL /* path if a plugin, filled in by GKrellM */
1565 };
1566
gkrellm_init_plugin()1567 GkrellmMonitor * gkrellm_init_plugin()
1568 {
1569 trayicons=g_array_new(FALSE,TRUE,sizeof(item_t));
1570 monitor = &plugin_mon;
1571 return &plugin_mon;
1572 }
1573