1 /*
2 * $RCSfile: gkrellmlaunch.c,v $
3 * Revision: $Revision: 1.12 $
4 * Date: $Date: 2002/09/26 13:53:08 $
5 *
6 * Copyright (C) 2001 Lee Webb
7 *
8 * Author: Lee Webb leewebb@users.sourceforge.net
9 * Latest versions: http://gkrellmlaunch.sourceforge.net
10 *
11 * Contributions:
12 * Bill Wilson http://bill.nalens.com/ GTK2 port
13 * Etan Reisner GTK2 port
14 *
15 * This program is free software which I release under the GNU General Public
16 * License. You may redistribute and/or modify this program under the terms
17 * of that license as published by the Free Software Foundation; either
18 * version 2 of the License, or (at your option) any later version.
19 *
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
24 *
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
28 *
29 * Requires GKrellM 2 or better
30 *
31 * gcc -fPIC `pkg-config gtk+-2.0 --cflags` `pkg-config gtk+-2.0 --libs` -c gkrellmlaunch.c
32 * gcc -shared -Wl -o gkrellmlaunch.so gkrellmlaunch.o
33 * gkrellm -p gkrellmlaunch.so
34 */
35
36 #include <gkrellm2/gkrellm.h>
37
38 /*
39 * Make sure we have a compatible version of GKrellM
40 * (Version 2+ is required due to the use of GTK2)
41 */
42 #if !defined(GKRELLM_VERSION_MAJOR) || GKRELLM_VERSION_MAJOR < 2
43 #error This plugin requires GKrellM version >= 2
44 #endif
45
46 #define CONFIG_NAME "GKrellMLaunch"
47
48 #define PLUGIN_PLACEMENT (MON_UPTIME | MON_INSERT_AFTER)
49
50 #define PLUGIN_CONFIG_KEYWORD "gkrellmlaunch"
51
52 #define STYLE_NAME "GKrellMLaunch"
53
54 static gchar *GKrellMLaunchInfo[] =
55 {
56 "<b>Usage\n\n",
57 "Label: ",
58 "This is the text that will appear on the button for the command.\n\n",
59 "Command: ",
60 "This is the binary name to run (e.g., mozilla).\n",
61 "Visible: ",
62 "Check box to allow buttons to be hidden if not used.\n\n",
63 "Use the \"Add\" button to create a new button.\n",
64 "Use the \"Replace\" button to update changes made for currently selected ",
65 "list entry.\n",
66 "Use the \"Delete\" button to delete the selected entry.\n",
67 "Use the /\\ & \\/ buttons to move selected entry up & down in position.\n",
68 };
69
70 static gchar GKrellMLaunchAbout[] =
71 "GKrellMLaunch Version 0.5 (GKrellm2)\n"\
72 "GKrellM plugin to give one-click access to frequently used programs.\n\n"\
73 "Copyright (c) 2001-2002 by Lee Webb\n"\
74 "Release Date: 26/09/2002\n"\
75 "leewebb@users.sourceforge.net\n"\
76 "http://gkrellmlaunch.sourceforge.net\n\n"\
77 "Released under the GNU Public License.\n";
78
79 static GkrellmMonitor *monitor;
80
81 typedef struct
82 {
83 gint visible;
84 gchar *cmd;
85 gchar *label;
86
87 /* Each launcher has its own Panel & Decal */
88 GkrellmPanel *panel;
89 GkrellmDecal *decal;
90 } GLauncher;
91
92 /*
93 * We need a list to hold our series of GLaunchers.
94 */
95 static GList *launcherList;
96
97 /*
98 * Unlike the array version of GKrellMLaunch, where buttons were always
99 * kept in memory, regardless if they were used or not (due to the
100 * limitations of fixed size arrays), the new list implementation zaps the
101 * entire list & recreates it when apply_plugin_config is reached. Although
102 * not necessarily a major problem, the graphical effect of GKrellM
103 * deleting and (re)adding the Panels/Decals is not pretty. So we're going
104 * to use a varible to keep track of modifications to the list & only zap
105 * the list should something change.
106 */
107 static gboolean listModified;
108
109 static gint style_id;
110
111 /*
112 * Create Config tab widgets.
113 */
114 static GtkWidget *cmdEntry;
115 static GtkWidget *cmdEntryLabel;
116 static GtkWidget *toggleButton;
117 static GtkWidget *launcherVbox;
118 /*
119 * Listbox widget for the config tab.
120 */
121 static GtkWidget *launcherCList;
122
123 /*
124 * Keep track of selected item in the Config listbox.
125 */
126 static gint selectedRow;
127
128 /*
129 * Handle decal button presses
130 */
buttonPress(GkrellmDecalbutton * button)131 static void buttonPress (GkrellmDecalbutton *button)
132 {
133 gchar *cmdRun = "";
134 gint i;
135 gint selected;
136 GLauncher *launcher;
137 GList *list;
138
139 /*
140 * Perform the appropriate action acccording to the button pressed.
141 * Note: we append the '&' for the user to ensure background execution.
142 *
143 * Bill has informed me that using system() can be iffy:
144 * "Whenever a program execs a child, the child inherits all open
145 * file descriptors and this could cause a problem because of plugins like
146 * Volume which have the audio device open. So, for example, a user can
147 * launch a program, then later after quitting gkrellm, can try to unload
148 * a sound module. But this will fail if the child program launched from
149 * gkrellm is still running because it has the audio device opened."
150 *
151 * Thus, use gkrellm_system() (a wrapper around system() that closes all
152 * open files before doing the system()).
153 * Unfortunately, such safety comes at a price: this call requires GKrellM
154 * version 1.2.2.
155 */
156
157 selected = (GPOINTER_TO_INT (button->data));
158 /*
159 * Allocate space for cmd.
160 * Note: We're adding 2 (not 1) to the length.
161 * One for the '&' and one for the null.
162 * No point having a variable just to hold a '&'.
163 */
164
165 /*
166 * Move to selected button in the list
167 */
168 for (i = 0, list = launcherList; i < selected; i += 1, list = list->next);
169
170 launcher = (GLauncher *) list->data;
171
172 /*
173 * g_spawn_command_line_async() replaces gkrellm_system as a built in GTK2
174 * call. Runs the specified command in the background so no need to append
175 * '&' ourselves.
176 */
177 cmdRun = g_strdup (launcher->cmd);
178 g_spawn_command_line_async (cmdRun, NULL);
179
180 /*
181 * Cleanup as g_strdup doesn't automatically free()
182 */
183 g_free (cmdRun);
184
185 }
186
panel_expose_event(GtkWidget * widget,GdkEventExpose * ev)187 static gint panel_expose_event (GtkWidget *widget, GdkEventExpose *ev)
188 {
189 GLauncher *launcher;
190 GList *list;
191
192 /*
193 * O.K. This isn't particularly efficient, but in the interests of
194 * maintainability, I'm going to keep this in.
195 */
196 for (list = launcherList; list; list = list->next)
197 {
198 launcher = (GLauncher *) list->data;
199 if (widget == launcher->panel->drawing_area)
200 {
201 gdk_draw_pixmap (widget->window,
202 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
203 launcher->panel->pixmap, ev->area.x, ev->area.y,
204 ev->area.x, ev->area.y, ev->area.width, ev->area.height);
205 }
206 }
207
208 return FALSE;
209 }
210
211 /*
212 * Func called by create_plugin() & apply_config() to show/hide panels
213 * at startup according to related config item.
214 */
setVisibility()215 static void setVisibility ()
216 {
217 GLauncher *launcher;
218 GList *list;
219
220 for (list = launcherList ; list ; list = list->next)
221 {
222 launcher = (GLauncher *) list->data;
223 if (launcher->visible == 0)
224 {
225 gkrellm_panel_hide (launcher->panel);
226 }
227 else
228 {
229 gkrellm_panel_show (launcher->panel);
230 }
231 }
232 }
233
update_plugin()234 static void update_plugin ()
235 {
236 GLauncher *launcher;
237 GList *list;
238
239 for (list = launcherList; list; list = list->next)
240 {
241 launcher = (GLauncher *) list->data;
242 gkrellm_draw_panel_layers (launcher->panel);
243 }
244 }
245
246 /*
247 * Configuration
248 */
save_plugin_config(FILE * f)249 static void save_plugin_config (FILE *f)
250 {
251 GLauncher *launcher;
252 GList *list;
253 gchar *ptr;
254
255 for (list = launcherList; list; list = list->next)
256 {
257 launcher = (GLauncher *) list->data;
258
259 /*
260 * Since labels may have spaces, we need to convert those to
261 * underscores: else sscanf won't work properly on load.
262 */
263 for (ptr = launcher->label; *ptr; ptr++)
264 {
265 if (*ptr == ' ')
266 {
267 *ptr = '_';
268 }
269 }
270 fprintf (f, "%s visible=%d label=%s cmd=%s\n",
271 PLUGIN_CONFIG_KEYWORD, launcher->visible,
272 launcher->label, launcher->cmd);
273 }
274 }
275
apply_plugin_config()276 static void apply_plugin_config ()
277 {
278 gchar *string;
279 gint i;
280 gint row;
281 GLauncher *launcher;
282 GList *list;
283 GList *newList;
284 GkrellmStyle *style;
285 GkrellmTextstyle *ts;
286 GkrellmTextstyle *ts_alt;
287
288 if (listModified)
289 {
290 /*
291 * Create a new list with the applied settings
292 * Trash the old list.
293 */
294 newList = NULL;
295
296 /*
297 * Read each row of the listbox & create a new launcher.
298 * Append each launcher to the new list.
299 */
300 for (row = 0; row < (GTK_CLIST (launcherCList)->rows); row += 1)
301 {
302 launcher = g_new0 (GLauncher, 1);
303 newList = g_list_append (newList, launcher);
304
305 gtk_clist_set_row_data (GTK_CLIST (launcherCList), row, launcher);
306
307 /*
308 * Fill the visible option.
309 */
310 gtk_clist_get_text (GTK_CLIST (launcherCList), row, 0, &string);
311 launcher->visible = (strcmp (string, "No") ? 1 : 0);
312
313 /*
314 * Fill the label option.
315 */
316 gtk_clist_get_text (GTK_CLIST (launcherCList), row, 1, &string);
317 gkrellm_dup_string (&launcher->label, string);
318
319 /*
320 * Fill the command option.
321 */
322 gtk_clist_get_text (GTK_CLIST (launcherCList), row, 2, &string);
323 gkrellm_dup_string (&launcher->cmd, string);
324
325 }
326
327 /*
328 * Wipe out the old list.
329 */
330 while (launcherList)
331 {
332 launcher = (GLauncher *) launcherList->data;
333 gkrellm_panel_destroy (launcher->panel);
334 launcherList = g_list_remove (launcherList, launcher);
335 }
336
337 /*
338 * And then update to the new list.
339 */
340 launcherList = newList;
341
342 /*
343 * Since we've destroyed the old list & the panels/decals with it,
344 * we have to recreate those associated panels/decals.
345 */
346
347 /*
348 * First make sure we have the styles set up.
349 */
350 style = gkrellm_meter_style (style_id);
351 ts = gkrellm_meter_textstyle (style_id);
352 ts_alt = gkrellm_meter_alt_textstyle (style_id);
353
354 for (i = 0, list = launcherList; list; i += 1, list = list->next)
355 {
356 launcher = (GLauncher *) list->data;
357 launcher->panel = gkrellm_panel_new0();
358 launcher->decal = gkrellm_create_decal_text (launcher->panel,
359 launcher->label, ts_alt, style, -1, -1, -1);
360
361 /*
362 * Configure the panel to the created decal, and create it.
363 */
364 gkrellm_panel_configure (launcher->panel, NULL, style);
365 gkrellm_panel_create (launcherVbox, monitor, launcher->panel);
366
367 /*
368 * Panel's been created so convert the decal into a button.
369 */
370 gkrellm_draw_decal_text (launcher->panel, launcher->decal,
371 launcher->label, 1);
372
373 gkrellm_put_decal_in_meter_button (launcher->panel, launcher->decal,
374 buttonPress,
375 GINT_TO_POINTER (i), NULL);
376 /*
377 * Connect our panel to the expose event to allow it to be drawn in
378 * update_plugin().
379 */
380 gtk_signal_connect (GTK_OBJECT (launcher->panel->drawing_area),
381 "expose_event", (GtkSignalFunc) panel_expose_event,
382 NULL);
383
384 }
385 setVisibility ();
386
387 /*
388 * Reset the modification state.
389 */
390 listModified = FALSE;
391 }
392 }
393
load_plugin_config(gchar * arg)394 static void load_plugin_config (gchar *arg)
395 {
396 gchar cmd[255];
397 gchar label[25];
398 gchar visible[2];
399 gchar *ptr;
400 gint n;
401 GLauncher *launcher;
402 GList *list;
403
404 n = sscanf (arg, "visible=%s label=%s cmd=%[^\n]", visible, label, cmd);
405
406 if (n == 3)
407 {
408 launcher = g_new0 (GLauncher, 1);
409 launcher->cmd = g_strdup (cmd);
410
411 /*
412 * Spaces in labels will have been converted to underscores in
413 * save_plugin_config(). Convert them back to spaces.
414 */
415 for (ptr = label; *ptr; ptr++)
416 {
417 if (*ptr == '_')
418 {
419 *ptr = ' ';
420 }
421 }
422 launcher->label = g_strdup (label);
423 launcher->visible = atoi (visible);
424 launcherList = g_list_append (launcherList, launcher);
425 }
426
427 for (list = launcherList; list; list = list->next)
428 {
429 launcher = (GLauncher *) list->data;
430 }
431 }
432
cbMoveUp(GtkWidget * widget,gpointer drawer)433 static void cbMoveUp (GtkWidget *widget, gpointer drawer)
434 {
435 gint row;
436 GtkWidget *clist;
437
438 clist = launcherCList;
439 row = selectedRow;
440
441 /*
442 * Only attempt a move if we're not on the first row.
443 */
444 if (row > 0)
445 {
446 /*
447 * Move the selected row up one position.
448 * Note that we have to reselect it afterwards.
449 */
450 gtk_clist_row_move (GTK_CLIST (clist), row, row - 1);
451 gtk_clist_select_row (GTK_CLIST (clist), row - 1, -1);
452
453 selectedRow = row - 1;
454 listModified = TRUE;
455 }
456 }
457
cbMoveDown(GtkWidget * widget,gpointer drawer)458 static void cbMoveDown (GtkWidget *widget, gpointer drawer)
459 {
460 gint row;
461 GtkWidget *clist;
462
463 clist = launcherCList;
464 row = selectedRow;
465
466 /*
467 * Only attempt a row if we're not on the last row.
468 * Note that we have to reselect it afterwards.
469 */
470 if ((row >= 0) && (row < (GTK_CLIST (clist)->rows - 1)))
471 {
472 gtk_clist_row_move (GTK_CLIST (clist), row, row + 1);
473 gtk_clist_select_row (GTK_CLIST (clist), row + 1, -1);
474
475 selectedRow = row + 1;
476 listModified = TRUE;
477 }
478 }
479
cListSelected(GtkWidget * clist,gint row,gint column,GdkEventButton * bevent,gpointer data)480 static void cListSelected (GtkWidget *clist, gint row, gint column,
481 GdkEventButton *bevent, gpointer data)
482 {
483 gchar *string;
484
485 /*
486 * Fill the entry widgets & check box accoring to the selected row's text
487 */
488 gtk_clist_get_text (GTK_CLIST (launcherCList), row, 0, &string);
489 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggleButton),
490 strcmp (string, "No") ? TRUE : FALSE);
491
492 gtk_clist_get_text (GTK_CLIST (launcherCList), row, 1, &string);
493 gtk_entry_set_text (GTK_ENTRY (cmdEntryLabel), string);
494
495 gtk_clist_get_text (GTK_CLIST (launcherCList), row, 2, &string);
496 gtk_entry_set_text (GTK_ENTRY (cmdEntry), string);
497
498 selectedRow = row;
499 }
500
cListUnSelected(GtkWidget * clist,gint row,gint column,GdkEventButton * bevent,gpointer data)501 static void cListUnSelected (GtkWidget *clist, gint row, gint column,
502 GdkEventButton *bevent, gpointer data)
503 {
504 /*
505 * Reset the entry widgets & check box
506 */
507 gtk_entry_set_text (GTK_ENTRY (cmdEntryLabel), "");
508 gtk_entry_set_text (GTK_ENTRY (cmdEntry), "");
509 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggleButton), 0);
510
511 selectedRow = -1;
512 }
513
cbAdd(GtkWidget * widget,gpointer data)514 static void cbAdd (GtkWidget *widget, gpointer data)
515 {
516 gchar *buffer[3];
517
518 buffer[0] = (gtk_toggle_button_get_active
519 (GTK_TOGGLE_BUTTON (toggleButton)) == TRUE ? "0" : "1");
520 buffer[1] = gkrellm_gtk_entry_get_text (&cmdEntryLabel);
521 buffer[2] = gkrellm_gtk_entry_get_text (&cmdEntry);
522
523 /*
524 * If either of the Label or Command entries are empty, forget it.
525 */
526 if ((!strlen (buffer[1])) || (!strlen (buffer[2])))
527 {
528 return;
529 }
530
531 buffer[0] = gtk_toggle_button_get_active
532 (GTK_TOGGLE_BUTTON (toggleButton)) == TRUE ? "Yes" : "No";
533 gtk_clist_append (GTK_CLIST (launcherCList), buffer);
534 listModified = TRUE;
535
536 /*
537 * Reset the entry widgets & check box
538 */
539 gtk_entry_set_text (GTK_ENTRY (cmdEntryLabel), "");
540 gtk_entry_set_text (GTK_ENTRY (cmdEntry), "");
541 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggleButton), 0);
542 }
543
cbReplace(GtkWidget * widget,gpointer data)544 static void cbReplace (GtkWidget *widget, gpointer data)
545 {
546 gchar *buffer[3];
547
548 buffer[0] = (gtk_toggle_button_get_active
549 (GTK_TOGGLE_BUTTON (toggleButton)) == TRUE ? "0" : "1");
550 buffer[1] = gkrellm_gtk_entry_get_text (&cmdEntryLabel);
551 buffer[2] = gkrellm_gtk_entry_get_text (&cmdEntry);
552
553 /*
554 * If either of the Label or Command entries are empty, forget it.
555 */
556 if ((!strlen (buffer[1])) || (!strlen (buffer[2])))
557 {
558 return;
559 }
560
561 /*
562 * If a row is selected, we're modifying an existing entry,
563 */
564 if (selectedRow >= 0)
565 {
566 gtk_clist_set_text (GTK_CLIST (launcherCList),
567 selectedRow, 1, buffer[1]);
568 gtk_clist_set_text (GTK_CLIST (launcherCList),
569 selectedRow, 2, buffer[2]);
570 gtk_clist_set_text (GTK_CLIST (launcherCList),
571 selectedRow, 0,
572 gtk_toggle_button_get_active
573 (GTK_TOGGLE_BUTTON (toggleButton))
574 == TRUE ? "Yes" : "No");
575 gtk_clist_unselect_row (GTK_CLIST (launcherCList), selectedRow, 0);
576 selectedRow = -1;
577 listModified = TRUE;
578 }
579
580 /*
581 * Reset the entry widgets & check box
582 */
583 gtk_entry_set_text (GTK_ENTRY (cmdEntryLabel), "");
584 gtk_entry_set_text (GTK_ENTRY (cmdEntry), "");
585 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggleButton), 0);
586
587 gtk_clist_unselect_row (GTK_CLIST (launcherCList), selectedRow, 0);
588 }
589
cbDelete(GtkWidget * widget,gpointer data)590 static void cbDelete (GtkWidget *widget, gpointer data)
591 {
592 /*
593 * Reset the entry widgets & check box
594 */
595 gtk_entry_set_text (GTK_ENTRY (cmdEntryLabel), "");
596 gtk_entry_set_text (GTK_ENTRY (cmdEntry), "");
597 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggleButton), 0);
598
599 if (selectedRow >= 0)
600 {
601 gtk_clist_remove (GTK_CLIST (launcherCList), selectedRow);
602 selectedRow = -1;
603 listModified = TRUE;
604 }
605 }
606
607 /*
608 * Create a Config tab with:
609 * 1. Checkbox to make panel visible/hidden
610 * 2. Text entry widget for command to run
611 * 3. Text entry widget for button label
612 * 4. Listbox to show items
613 * 5. Info tab
614 */
create_plugin_tab(GtkWidget * tab_vbox)615 static void create_plugin_tab (GtkWidget *tab_vbox)
616 {
617 gchar *titles[3] = {"Visible", "Label", "Command"};
618 gchar *buffer[3];
619 gchar visible[5];
620 gint i = 0;
621 GLauncher *launcher;
622 GList *list;
623 GtkWidget *tabs;
624 GtkWidget *vbox;
625 GtkWidget *hbox;
626 GtkWidget *scrolled;
627 GtkWidget *text;
628 GtkWidget *label;
629 GtkWidget *button;
630 GtkWidget *aboutLabel;
631 GtkWidget *aboutText;
632
633 /*
634 * Make a couple of tabs. One for Config and one for info.
635 */
636 tabs = gtk_notebook_new ();
637 gtk_notebook_set_tab_pos (GTK_NOTEBOOK (tabs), GTK_POS_TOP);
638 gtk_box_pack_start (GTK_BOX (tab_vbox), tabs, TRUE, TRUE, 0);
639
640 /*
641 * Setup tab: give it some scroll bars to keep the config
642 * window size compact.
643 */
644 vbox = gkrellm_gtk_notebook_page (tabs, "Setup");
645 vbox = gkrellm_gtk_scrolled_vbox (vbox, NULL,
646 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
647
648 /*
649 * Dynamically create the options on the Config tab according to MAX_BUTTONS.
650 */
651
652 /*
653 * Create text boxes to put Labels and Commands in
654 */
655
656 label = gtk_label_new ("Label: ");
657 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
658 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
659 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
660
661 cmdEntryLabel = gtk_entry_new_with_max_length (255) ;
662 gtk_entry_set_text (GTK_ENTRY (cmdEntryLabel), "") ;
663 gtk_entry_set_editable (GTK_ENTRY (cmdEntryLabel), TRUE);
664 gtk_box_pack_start (GTK_BOX (vbox), cmdEntryLabel, FALSE, FALSE, 0) ;
665
666 label = gtk_label_new ("Command:");
667 gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, i);
668 gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
669 gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
670
671 cmdEntry = gtk_entry_new_with_max_length (255) ;
672 gtk_entry_set_text (GTK_ENTRY (cmdEntry), "") ;
673 gtk_entry_set_editable (GTK_ENTRY (cmdEntry), TRUE) ;
674 gtk_box_pack_start (GTK_BOX (vbox), cmdEntry, FALSE, FALSE, 0) ;
675
676 toggleButton = gtk_check_button_new_with_label ("Visible?");
677 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggleButton), 0);
678 gtk_box_pack_start (GTK_BOX (vbox), toggleButton, FALSE, TRUE, 0);
679
680 /*
681 * Add buttons into their own box
682 * => Add Replace Delete /\ \/
683 */
684 hbox = gtk_hbox_new (FALSE, 0);
685 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
686
687 /*
688 * Add "Add", "Replace" & "Delete" buttons
689 */
690 button = gtk_button_new_with_label ("Add");
691 gtk_signal_connect (GTK_OBJECT (button), "clicked",
692 (GtkSignalFunc) cbAdd, NULL);
693
694 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
695
696 button = gtk_button_new_with_label ("Replace");
697 gtk_signal_connect (GTK_OBJECT (button), "clicked",
698 (GtkSignalFunc) cbReplace, NULL);
699 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
700
701 button = gtk_button_new_with_label ("Delete");
702 gtk_signal_connect (GTK_OBJECT (button), "clicked",
703 (GtkSignalFunc) cbDelete, NULL);
704 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
705
706 /*
707 * Add reposition buttons
708 */
709 button = gtk_button_new_with_label ("/\\");
710 gtk_signal_connect (GTK_OBJECT (button), "clicked",
711 (GtkSignalFunc) cbMoveUp, NULL);
712
713 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
714 button = gtk_button_new_with_label ("\\/");
715 gtk_signal_connect (GTK_OBJECT (button), "clicked",
716 (GtkSignalFunc) cbMoveDown, NULL);
717 gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
718
719 /*
720 * Create listbox to hold each item
721 */
722 scrolled = gtk_scrolled_window_new (NULL, NULL);
723 gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
724 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
725 gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
726
727 /*
728 * Create the CList with 3 titles:
729 * Label, Command, Visible
730 */
731 launcherCList = gtk_clist_new_with_titles (3, titles);
732 gtk_clist_set_shadow_type (GTK_CLIST (launcherCList), GTK_SHADOW_OUT);
733
734 /*
735 * Set the column widths
736 */
737 /* Label */
738 gtk_clist_set_column_width (GTK_CLIST (launcherCList), 0, 30);
739 /* Command */
740 gtk_clist_set_column_width (GTK_CLIST (launcherCList), 1, 100);
741 /* Visible */
742 gtk_clist_set_column_width (GTK_CLIST (launcherCList), 2, 200);
743
744 gtk_clist_set_column_justification (GTK_CLIST (launcherCList),
745 0, GTK_JUSTIFY_LEFT);
746 gtk_clist_set_column_justification (GTK_CLIST (launcherCList),
747 1, GTK_JUSTIFY_LEFT);
748 gtk_clist_set_column_justification (GTK_CLIST (launcherCList),
749 2, GTK_JUSTIFY_LEFT);
750
751 /*
752 * Add signals for selecting a row in the CList.
753 */
754 gtk_signal_connect (GTK_OBJECT (launcherCList), "select_row",
755 (GtkSignalFunc) cListSelected, NULL);
756
757 /*
758 * Add signal for deselecting a row in the CList.
759 * If not, delselecting & attempting to create a new entry will overwrite
760 * the previuosly selected row.
761 */
762 gtk_signal_connect (GTK_OBJECT (launcherCList), "unselect_row",
763 (GtkSignalFunc) cListUnSelected, NULL);
764
765 /*
766 * Add the CList to the scrolling window
767 */
768 gtk_container_add (GTK_CONTAINER (scrolled), launcherCList);
769
770 /*
771 * Fill the CList with our commands etc.
772 */
773 for (i = 0, list = launcherList; list; i += 1, list = list->next)
774 {
775 launcher = (GLauncher *) list->data;
776 sprintf (visible, "%s", (launcher->visible == 1 ? "Yes" : "No"));
777 buffer[0] = visible;
778 buffer[1] = launcher->label;
779 buffer[2] = launcher->cmd;
780 gtk_clist_append (GTK_CLIST (launcherCList), buffer);
781 gtk_clist_set_row_data (GTK_CLIST (launcherCList), i, launcher);
782 }
783
784 /*
785 * Info tab
786 */
787 vbox = gkrellm_gtk_notebook_page (tabs, "Info");
788 text = gkrellm_gtk_scrolled_text_view (vbox, NULL, GTK_POLICY_AUTOMATIC,
789 GTK_POLICY_AUTOMATIC);
790 gkrellm_gtk_text_view_append_strings (text, GKrellMLaunchInfo,
791 (sizeof (GKrellMLaunchInfo)
792 / sizeof (gchar *)));
793
794 /*
795 * About tab
796 */
797 aboutText = gtk_label_new (GKrellMLaunchAbout);
798 aboutLabel = gtk_label_new ("About");
799 gtk_notebook_append_page (GTK_NOTEBOOK (tabs), aboutText, aboutLabel);
800
801 }
802
create_plugin(GtkWidget * vbox,gint first_create)803 static void create_plugin (GtkWidget *vbox, gint first_create)
804 {
805 gint i;
806 GLauncher *launcher;
807 GList *list;
808 GkrellmStyle *style;
809 GkrellmTextstyle *ts;
810 GkrellmTextstyle *ts_alt;
811
812 launcherVbox = vbox;
813
814 if (first_create)
815 {
816 for (list = launcherList; list; list = list->next)
817 {
818 launcher = (GLauncher *) list->data;
819 launcher->panel = gkrellm_panel_new0();
820 }
821 }
822
823 style = gkrellm_meter_style (style_id);
824
825 /*
826 * Each GkrellmStyle has two text styles. The theme designer has picked the
827 * colors and font sizes, presumably based on knowledge of what you draw
828 * on your panel. You just do the drawing. You probably could assume
829 * the ts font is larger than the ts_alt font, but again you can be
830 * overridden by the theme designer.
831 */
832 ts = gkrellm_meter_textstyle (style_id);
833 ts_alt = gkrellm_meter_alt_textstyle (style_id);
834
835 /*
836 * Create a text decal that will be converted to a button.
837 * Make it the entire width of the panel.
838 */
839 for (i = 0, list = launcherList; list; i += 1, list = list->next)
840 {
841 launcher = (GLauncher *) list->data;
842 launcher->decal = gkrellm_create_decal_text (launcher->panel,
843 launcher->label, ts_alt, style, -1, -1, -1);
844 /*
845 * Configure the panel to created decal, and create it.
846 */
847 gkrellm_panel_configure (launcher->panel, NULL, style);
848 gkrellm_panel_create (vbox, monitor, launcher->panel);
849
850 /*
851 * After the panel is created, the decal can be converted into a button.
852 * First draw the initial text into the text decal button and then
853 * put the text decal into a meter button.
854 */
855 gkrellm_draw_decal_text (launcher->panel, launcher->decal,
856 launcher->label,1);
857 gkrellm_put_decal_in_meter_button (launcher->panel, launcher->decal,
858 buttonPress,
859 GINT_TO_POINTER (i), NULL);
860 }
861
862 /*
863 * Note: all of the above gkrellm_draw_decal_XXX() calls will not
864 * appear on the panel until a gkrellm_draw_panel_layers() call is
865 * made. This will be done in update_plugin(), otherwise we would
866 * make the call here and anytime the decals are changed.
867 */
868
869 if (first_create)
870 {
871 for (list = launcherList; list; list = list->next)
872 {
873 launcher = (GLauncher *) list->data;
874 gtk_signal_connect (GTK_OBJECT (launcher->panel->drawing_area),
875 "expose_event", (GtkSignalFunc) panel_expose_event, NULL);
876 }
877 /*
878 * Setup the initial visible status of each panel
879 * according to the config item read in.
880 */
881 setVisibility ();
882 }
883 }
884
885
886 /*
887 * The monitor structure tells GKrellM how to call the plugin routines.
888 */
889 static GkrellmMonitor plugin_mon =
890 {
891 CONFIG_NAME, /* Name, for config tab. */
892 0, /* Id, 0 if a plugin */
893 create_plugin, /* The create function */
894 update_plugin, /* The update function */
895 create_plugin_tab, /* The config tab create function */
896 apply_plugin_config, /* Apply the config function */
897 save_plugin_config, /* Save user config */
898 load_plugin_config, /* Load user config */
899 PLUGIN_CONFIG_KEYWORD, /* config keyword */
900
901 NULL, /* Undefined 2 */
902 NULL, /* Undefined 1 */
903 NULL, /* private */
904
905 PLUGIN_PLACEMENT, /* Insert plugin before this monitor */
906
907 NULL, /* Handle if a plugin, filled in by GKrellM */
908 NULL /* path if a plugin, filled in by GKrellM */
909 };
910
911 /*
912 * All GKrellM plugins must have one global routine named gkrellm_init_plugin()
913 * which returns a pointer to a filled in monitor structure.
914 */
gkrellm_init_plugin()915 GkrellmMonitor* gkrellm_init_plugin ()
916 {
917 /*
918 * Don't want any row in the Config tab initially selected.
919 */
920 selectedRow = -1;
921 listModified = FALSE;
922
923 style_id = gkrellm_add_meter_style (&plugin_mon, STYLE_NAME);
924 monitor = &plugin_mon;
925 return &plugin_mon;
926 }
927