gkrellmlaunch.c 27 KB

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