|
|
@@ -0,0 +1,926 @@
|
|
|
+/*
|
|
|
+ * $RCSfile: gkrellmlaunch.c,v $
|
|
|
+ * Revision: $Revision: 1.12 $
|
|
|
+ * Date: $Date: 2002/09/26 13:53:08 $
|
|
|
+ *
|
|
|
+ * Copyright (C) 2001 Lee Webb
|
|
|
+ *
|
|
|
+ * Author: Lee Webb leewebb@users.sourceforge.net
|
|
|
+ * Latest versions: http://gkrellmlaunch.sourceforge.net
|
|
|
+ *
|
|
|
+ * Contributions:
|
|
|
+ * Bill Wilson http://bill.nalens.com/ GTK2 port
|
|
|
+ * Etan Reisner GTK2 port
|
|
|
+ *
|
|
|
+ * This program is free software which I release under the GNU General Public
|
|
|
+ * License. You may redistribute and/or modify this program under the terms
|
|
|
+ * of that license as published by the Free Software Foundation; either
|
|
|
+ * version 2 of the License, or (at your option) any later version.
|
|
|
+ *
|
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
+ * GNU General Public License for more details.
|
|
|
+ *
|
|
|
+ * You should have received a copy of the GNU General Public License
|
|
|
+ * along with this program; if not, write to the Free Software
|
|
|
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
|
+ *
|
|
|
+ * Requires GKrellM 2 or better
|
|
|
+ *
|
|
|
+ * gcc -fPIC `pkg-config gtk+-2.0 --cflags` `pkg-config gtk+-2.0 --libs` -c gkrellmlaunch.c
|
|
|
+ * gcc -shared -Wl -o gkrellmlaunch.so gkrellmlaunch.o
|
|
|
+ * gkrellm -p gkrellmlaunch.so
|
|
|
+ */
|
|
|
+
|
|
|
+#include <gkrellm2/gkrellm.h>
|
|
|
+
|
|
|
+/*
|
|
|
+ * Make sure we have a compatible version of GKrellM
|
|
|
+ * (Version 2+ is required due to the use of GTK2)
|
|
|
+ */
|
|
|
+#if !defined(GKRELLM_VERSION_MAJOR) || GKRELLM_VERSION_MAJOR < 2
|
|
|
+#error This plugin requires GKrellM version >= 2
|
|
|
+#endif
|
|
|
+
|
|
|
+#define CONFIG_NAME "GKrellMLaunch"
|
|
|
+
|
|
|
+#define PLUGIN_PLACEMENT (MON_UPTIME | MON_INSERT_AFTER)
|
|
|
+
|
|
|
+#define PLUGIN_CONFIG_KEYWORD "gkrellmlaunch"
|
|
|
+
|
|
|
+#define STYLE_NAME "GKrellMLaunch"
|
|
|
+
|
|
|
+static gchar *GKrellMLaunchInfo[] =
|
|
|
+{
|
|
|
+ "<b>Usage\n\n",
|
|
|
+ "Label: ",
|
|
|
+ "This is the text that will appear on the button for the command.\n\n",
|
|
|
+ "Command: ",
|
|
|
+ "This is the binary name to run (e.g., mozilla).\n",
|
|
|
+ "Visible: ",
|
|
|
+ "Check box to allow buttons to be hidden if not used.\n\n",
|
|
|
+ "Use the \"Add\" button to create a new button.\n",
|
|
|
+ "Use the \"Replace\" button to update changes made for currently selected ",
|
|
|
+ "list entry.\n",
|
|
|
+ "Use the \"Delete\" button to delete the selected entry.\n",
|
|
|
+ "Use the /\\ & \\/ buttons to move selected entry up & down in position.\n",
|
|
|
+};
|
|
|
+
|
|
|
+static gchar GKrellMLaunchAbout[] =
|
|
|
+ "GKrellMLaunch Version 0.5 (GKrellm2)\n"\
|
|
|
+ "GKrellM plugin to give one-click access to frequently used programs.\n\n"\
|
|
|
+ "Copyright (c) 2001-2002 by Lee Webb\n"\
|
|
|
+ "Release Date: 26/09/2002\n"\
|
|
|
+ "leewebb@users.sourceforge.net\n"\
|
|
|
+ "http://gkrellmlaunch.sourceforge.net\n\n"\
|
|
|
+ "Released under the GNU Public License.\n";
|
|
|
+
|
|
|
+static GkrellmMonitor *monitor;
|
|
|
+
|
|
|
+typedef struct
|
|
|
+{
|
|
|
+ gint visible;
|
|
|
+ gchar *cmd;
|
|
|
+ gchar *label;
|
|
|
+
|
|
|
+ /* Each launcher has its own Panel & Decal */
|
|
|
+ GkrellmPanel *panel;
|
|
|
+ GkrellmDecal *decal;
|
|
|
+} GLauncher;
|
|
|
+
|
|
|
+/*
|
|
|
+ * We need a list to hold our series of GLaunchers.
|
|
|
+ */
|
|
|
+static GList *launcherList;
|
|
|
+
|
|
|
+/*
|
|
|
+ * Unlike the array version of GKrellMLaunch, where buttons were always
|
|
|
+ * kept in memory, regardless if they were used or not (due to the
|
|
|
+ * limitations of fixed size arrays), the new list implementation zaps the
|
|
|
+ * entire list & recreates it when apply_plugin_config is reached. Although
|
|
|
+ * not necessarily a major problem, the graphical effect of GKrellM
|
|
|
+ * deleting and (re)adding the Panels/Decals is not pretty. So we're going
|
|
|
+ * to use a varible to keep track of modifications to the list & only zap
|
|
|
+ * the list should something change.
|
|
|
+ */
|
|
|
+static gboolean listModified;
|
|
|
+
|
|
|
+static gint style_id;
|
|
|
+
|
|
|
+/*
|
|
|
+ * Create Config tab widgets.
|
|
|
+ */
|
|
|
+static GtkWidget *cmdEntry;
|
|
|
+static GtkWidget *cmdEntryLabel;
|
|
|
+static GtkWidget *toggleButton;
|
|
|
+static GtkWidget *launcherVbox;
|
|
|
+/*
|
|
|
+ * Listbox widget for the config tab.
|
|
|
+ */
|
|
|
+static GtkWidget *launcherCList;
|
|
|
+
|
|
|
+/*
|
|
|
+ * Keep track of selected item in the Config listbox.
|
|
|
+ */
|
|
|
+static gint selectedRow;
|
|
|
+
|
|
|
+/*
|
|
|
+ * Handle decal button presses
|
|
|
+ */
|
|
|
+static void buttonPress (GkrellmDecalbutton *button)
|
|
|
+{
|
|
|
+ gchar *cmdRun = "";
|
|
|
+ gint i;
|
|
|
+ gint selected;
|
|
|
+ GLauncher *launcher;
|
|
|
+ GList *list;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Perform the appropriate action acccording to the button pressed.
|
|
|
+ * Note: we append the '&' for the user to ensure background execution.
|
|
|
+ *
|
|
|
+ * Bill has informed me that using system() can be iffy:
|
|
|
+ * "Whenever a program execs a child, the child inherits all open
|
|
|
+ * file descriptors and this could cause a problem because of plugins like
|
|
|
+ * Volume which have the audio device open. So, for example, a user can
|
|
|
+ * launch a program, then later after quitting gkrellm, can try to unload
|
|
|
+ * a sound module. But this will fail if the child program launched from
|
|
|
+ * gkrellm is still running because it has the audio device opened."
|
|
|
+ *
|
|
|
+ * Thus, use gkrellm_system() (a wrapper around system() that closes all
|
|
|
+ * open files before doing the system()).
|
|
|
+ * Unfortunately, such safety comes at a price: this call requires GKrellM
|
|
|
+ * version 1.2.2.
|
|
|
+ */
|
|
|
+
|
|
|
+ selected = (GPOINTER_TO_INT (button->data));
|
|
|
+ /*
|
|
|
+ * Allocate space for cmd.
|
|
|
+ * Note: We're adding 2 (not 1) to the length.
|
|
|
+ * One for the '&' and one for the null.
|
|
|
+ * No point having a variable just to hold a '&'.
|
|
|
+ */
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Move to selected button in the list
|
|
|
+ */
|
|
|
+ for (i = 0, list = launcherList; i < selected; i += 1, list = list->next);
|
|
|
+
|
|
|
+ launcher = (GLauncher *) list->data;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * g_spawn_command_line_async() replaces gkrellm_system as a built in GTK2
|
|
|
+ * call. Runs the specified command in the background so no need to append
|
|
|
+ * '&' ourselves.
|
|
|
+ */
|
|
|
+ cmdRun = g_strdup (launcher->cmd);
|
|
|
+ g_spawn_command_line_async (cmdRun, NULL);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Cleanup as g_strdup doesn't automatically free()
|
|
|
+ */
|
|
|
+ g_free (cmdRun);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static gint panel_expose_event (GtkWidget *widget, GdkEventExpose *ev)
|
|
|
+{
|
|
|
+ GLauncher *launcher;
|
|
|
+ GList *list;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * O.K. This isn't particularly efficient, but in the interests of
|
|
|
+ * maintainability, I'm going to keep this in.
|
|
|
+ */
|
|
|
+ for (list = launcherList; list; list = list->next)
|
|
|
+ {
|
|
|
+ launcher = (GLauncher *) list->data;
|
|
|
+ if (widget == launcher->panel->drawing_area)
|
|
|
+ {
|
|
|
+ gdk_draw_pixmap (widget->window,
|
|
|
+ widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
|
|
|
+ launcher->panel->pixmap, ev->area.x, ev->area.y,
|
|
|
+ ev->area.x, ev->area.y, ev->area.width, ev->area.height);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return FALSE;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Func called by create_plugin() & apply_config() to show/hide panels
|
|
|
+ * at startup according to related config item.
|
|
|
+ */
|
|
|
+static void setVisibility ()
|
|
|
+{
|
|
|
+ GLauncher *launcher;
|
|
|
+ GList *list;
|
|
|
+
|
|
|
+ for (list = launcherList ; list ; list = list->next)
|
|
|
+ {
|
|
|
+ launcher = (GLauncher *) list->data;
|
|
|
+ if (launcher->visible == 0)
|
|
|
+ {
|
|
|
+ gkrellm_panel_hide (launcher->panel);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ gkrellm_panel_show (launcher->panel);
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void update_plugin ()
|
|
|
+{
|
|
|
+ GLauncher *launcher;
|
|
|
+ GList *list;
|
|
|
+
|
|
|
+ for (list = launcherList; list; list = list->next)
|
|
|
+ {
|
|
|
+ launcher = (GLauncher *) list->data;
|
|
|
+ gkrellm_draw_panel_layers (launcher->panel);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Configuration
|
|
|
+ */
|
|
|
+static void save_plugin_config (FILE *f)
|
|
|
+{
|
|
|
+ GLauncher *launcher;
|
|
|
+ GList *list;
|
|
|
+ gchar *ptr;
|
|
|
+
|
|
|
+ for (list = launcherList; list; list = list->next)
|
|
|
+ {
|
|
|
+ launcher = (GLauncher *) list->data;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Since labels may have spaces, we need to convert those to
|
|
|
+ * underscores: else sscanf won't work properly on load.
|
|
|
+ */
|
|
|
+ for (ptr = launcher->label; *ptr; ptr++)
|
|
|
+ {
|
|
|
+ if (*ptr == ' ')
|
|
|
+ {
|
|
|
+ *ptr = '_';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fprintf (f, "%s visible=%d label=%s cmd=%s\n",
|
|
|
+ PLUGIN_CONFIG_KEYWORD, launcher->visible,
|
|
|
+ launcher->label, launcher->cmd);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void apply_plugin_config ()
|
|
|
+{
|
|
|
+ gchar *string;
|
|
|
+ gint i;
|
|
|
+ gint row;
|
|
|
+ GLauncher *launcher;
|
|
|
+ GList *list;
|
|
|
+ GList *newList;
|
|
|
+ GkrellmStyle *style;
|
|
|
+ GkrellmTextstyle *ts;
|
|
|
+ GkrellmTextstyle *ts_alt;
|
|
|
+
|
|
|
+ if (listModified)
|
|
|
+ {
|
|
|
+ /*
|
|
|
+ * Create a new list with the applied settings
|
|
|
+ * Trash the old list.
|
|
|
+ */
|
|
|
+ newList = NULL;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Read each row of the listbox & create a new launcher.
|
|
|
+ * Append each launcher to the new list.
|
|
|
+ */
|
|
|
+ for (row = 0; row < (GTK_CLIST (launcherCList)->rows); row += 1)
|
|
|
+ {
|
|
|
+ launcher = g_new0 (GLauncher, 1);
|
|
|
+ newList = g_list_append (newList, launcher);
|
|
|
+
|
|
|
+ gtk_clist_set_row_data (GTK_CLIST (launcherCList), row, launcher);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Fill the visible option.
|
|
|
+ */
|
|
|
+ gtk_clist_get_text (GTK_CLIST (launcherCList), row, 0, &string);
|
|
|
+ launcher->visible = (strcmp (string, "No") ? 1 : 0);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Fill the label option.
|
|
|
+ */
|
|
|
+ gtk_clist_get_text (GTK_CLIST (launcherCList), row, 1, &string);
|
|
|
+ gkrellm_dup_string (&launcher->label, string);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Fill the command option.
|
|
|
+ */
|
|
|
+ gtk_clist_get_text (GTK_CLIST (launcherCList), row, 2, &string);
|
|
|
+ gkrellm_dup_string (&launcher->cmd, string);
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Wipe out the old list.
|
|
|
+ */
|
|
|
+ while (launcherList)
|
|
|
+ {
|
|
|
+ launcher = (GLauncher *) launcherList->data;
|
|
|
+ gkrellm_panel_destroy (launcher->panel);
|
|
|
+ launcherList = g_list_remove (launcherList, launcher);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * And then update to the new list.
|
|
|
+ */
|
|
|
+ launcherList = newList;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Since we've destroyed the old list & the panels/decals with it,
|
|
|
+ * we have to recreate those associated panels/decals.
|
|
|
+ */
|
|
|
+
|
|
|
+ /*
|
|
|
+ * First make sure we have the styles set up.
|
|
|
+ */
|
|
|
+ style = gkrellm_meter_style (style_id);
|
|
|
+ ts = gkrellm_meter_textstyle (style_id);
|
|
|
+ ts_alt = gkrellm_meter_alt_textstyle (style_id);
|
|
|
+
|
|
|
+ for (i = 0, list = launcherList; list; i += 1, list = list->next)
|
|
|
+ {
|
|
|
+ launcher = (GLauncher *) list->data;
|
|
|
+ launcher->panel = gkrellm_panel_new0();
|
|
|
+ launcher->decal = gkrellm_create_decal_text (launcher->panel,
|
|
|
+ launcher->label, ts_alt, style, -1, -1, -1);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Configure the panel to the created decal, and create it.
|
|
|
+ */
|
|
|
+ gkrellm_panel_configure (launcher->panel, NULL, style);
|
|
|
+ gkrellm_panel_create (launcherVbox, monitor, launcher->panel);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Panel's been created so convert the decal into a button.
|
|
|
+ */
|
|
|
+ gkrellm_draw_decal_text (launcher->panel, launcher->decal,
|
|
|
+ launcher->label, 1);
|
|
|
+
|
|
|
+ gkrellm_put_decal_in_meter_button (launcher->panel, launcher->decal,
|
|
|
+ buttonPress,
|
|
|
+ GINT_TO_POINTER (i), NULL);
|
|
|
+ /*
|
|
|
+ * Connect our panel to the expose event to allow it to be drawn in
|
|
|
+ * update_plugin().
|
|
|
+ */
|
|
|
+ gtk_signal_connect (GTK_OBJECT (launcher->panel->drawing_area),
|
|
|
+ "expose_event", (GtkSignalFunc) panel_expose_event,
|
|
|
+ NULL);
|
|
|
+
|
|
|
+ }
|
|
|
+ setVisibility ();
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Reset the modification state.
|
|
|
+ */
|
|
|
+ listModified = FALSE;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void load_plugin_config (gchar *arg)
|
|
|
+{
|
|
|
+ gchar cmd[255];
|
|
|
+ gchar label[25];
|
|
|
+ gchar visible[2];
|
|
|
+ gchar *ptr;
|
|
|
+ gint n;
|
|
|
+ GLauncher *launcher;
|
|
|
+ GList *list;
|
|
|
+
|
|
|
+ n = sscanf (arg, "visible=%s label=%s cmd=%[^\n]", visible, label, cmd);
|
|
|
+
|
|
|
+ if (n == 3)
|
|
|
+ {
|
|
|
+ launcher = g_new0 (GLauncher, 1);
|
|
|
+ launcher->cmd = g_strdup (cmd);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Spaces in labels will have been converted to underscores in
|
|
|
+ * save_plugin_config(). Convert them back to spaces.
|
|
|
+ */
|
|
|
+ for (ptr = label; *ptr; ptr++)
|
|
|
+ {
|
|
|
+ if (*ptr == '_')
|
|
|
+ {
|
|
|
+ *ptr = ' ';
|
|
|
+ }
|
|
|
+ }
|
|
|
+ launcher->label = g_strdup (label);
|
|
|
+ launcher->visible = atoi (visible);
|
|
|
+ launcherList = g_list_append (launcherList, launcher);
|
|
|
+ }
|
|
|
+
|
|
|
+ for (list = launcherList; list; list = list->next)
|
|
|
+ {
|
|
|
+ launcher = (GLauncher *) list->data;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void cbMoveUp (GtkWidget *widget, gpointer drawer)
|
|
|
+{
|
|
|
+ gint row;
|
|
|
+ GtkWidget *clist;
|
|
|
+
|
|
|
+ clist = launcherCList;
|
|
|
+ row = selectedRow;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Only attempt a move if we're not on the first row.
|
|
|
+ */
|
|
|
+ if (row > 0)
|
|
|
+ {
|
|
|
+ /*
|
|
|
+ * Move the selected row up one position.
|
|
|
+ * Note that we have to reselect it afterwards.
|
|
|
+ */
|
|
|
+ gtk_clist_row_move (GTK_CLIST (clist), row, row - 1);
|
|
|
+ gtk_clist_select_row (GTK_CLIST (clist), row - 1, -1);
|
|
|
+
|
|
|
+ selectedRow = row - 1;
|
|
|
+ listModified = TRUE;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void cbMoveDown (GtkWidget *widget, gpointer drawer)
|
|
|
+{
|
|
|
+ gint row;
|
|
|
+ GtkWidget *clist;
|
|
|
+
|
|
|
+ clist = launcherCList;
|
|
|
+ row = selectedRow;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Only attempt a row if we're not on the last row.
|
|
|
+ * Note that we have to reselect it afterwards.
|
|
|
+ */
|
|
|
+ if ((row >= 0) && (row < (GTK_CLIST (clist)->rows - 1)))
|
|
|
+ {
|
|
|
+ gtk_clist_row_move (GTK_CLIST (clist), row, row + 1);
|
|
|
+ gtk_clist_select_row (GTK_CLIST (clist), row + 1, -1);
|
|
|
+
|
|
|
+ selectedRow = row + 1;
|
|
|
+ listModified = TRUE;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static void cListSelected (GtkWidget *clist, gint row, gint column,
|
|
|
+ GdkEventButton *bevent, gpointer data)
|
|
|
+{
|
|
|
+ gchar *string;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Fill the entry widgets & check box accoring to the selected row's text
|
|
|
+ */
|
|
|
+ gtk_clist_get_text (GTK_CLIST (launcherCList), row, 0, &string);
|
|
|
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggleButton),
|
|
|
+ strcmp (string, "No") ? TRUE : FALSE);
|
|
|
+
|
|
|
+ gtk_clist_get_text (GTK_CLIST (launcherCList), row, 1, &string);
|
|
|
+ gtk_entry_set_text (GTK_ENTRY (cmdEntryLabel), string);
|
|
|
+
|
|
|
+ gtk_clist_get_text (GTK_CLIST (launcherCList), row, 2, &string);
|
|
|
+ gtk_entry_set_text (GTK_ENTRY (cmdEntry), string);
|
|
|
+
|
|
|
+ selectedRow = row;
|
|
|
+}
|
|
|
+
|
|
|
+static void cListUnSelected (GtkWidget *clist, gint row, gint column,
|
|
|
+ GdkEventButton *bevent, gpointer data)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * Reset the entry widgets & check box
|
|
|
+ */
|
|
|
+ gtk_entry_set_text (GTK_ENTRY (cmdEntryLabel), "");
|
|
|
+ gtk_entry_set_text (GTK_ENTRY (cmdEntry), "");
|
|
|
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggleButton), 0);
|
|
|
+
|
|
|
+ selectedRow = -1;
|
|
|
+}
|
|
|
+
|
|
|
+static void cbAdd (GtkWidget *widget, gpointer data)
|
|
|
+{
|
|
|
+ gchar *buffer[3];
|
|
|
+
|
|
|
+ buffer[0] = (gtk_toggle_button_get_active
|
|
|
+ (GTK_TOGGLE_BUTTON (toggleButton)) == TRUE ? "0" : "1");
|
|
|
+ buffer[1] = gkrellm_gtk_entry_get_text (&cmdEntryLabel);
|
|
|
+ buffer[2] = gkrellm_gtk_entry_get_text (&cmdEntry);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If either of the Label or Command entries are empty, forget it.
|
|
|
+ */
|
|
|
+ if ((!strlen (buffer[1])) || (!strlen (buffer[2])))
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ buffer[0] = gtk_toggle_button_get_active
|
|
|
+ (GTK_TOGGLE_BUTTON (toggleButton)) == TRUE ? "Yes" : "No";
|
|
|
+ gtk_clist_append (GTK_CLIST (launcherCList), buffer);
|
|
|
+ listModified = TRUE;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Reset the entry widgets & check box
|
|
|
+ */
|
|
|
+ gtk_entry_set_text (GTK_ENTRY (cmdEntryLabel), "");
|
|
|
+ gtk_entry_set_text (GTK_ENTRY (cmdEntry), "");
|
|
|
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggleButton), 0);
|
|
|
+}
|
|
|
+
|
|
|
+static void cbReplace (GtkWidget *widget, gpointer data)
|
|
|
+{
|
|
|
+ gchar *buffer[3];
|
|
|
+
|
|
|
+ buffer[0] = (gtk_toggle_button_get_active
|
|
|
+ (GTK_TOGGLE_BUTTON (toggleButton)) == TRUE ? "0" : "1");
|
|
|
+ buffer[1] = gkrellm_gtk_entry_get_text (&cmdEntryLabel);
|
|
|
+ buffer[2] = gkrellm_gtk_entry_get_text (&cmdEntry);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If either of the Label or Command entries are empty, forget it.
|
|
|
+ */
|
|
|
+ if ((!strlen (buffer[1])) || (!strlen (buffer[2])))
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If a row is selected, we're modifying an existing entry,
|
|
|
+ */
|
|
|
+ if (selectedRow >= 0)
|
|
|
+ {
|
|
|
+ gtk_clist_set_text (GTK_CLIST (launcherCList),
|
|
|
+ selectedRow, 1, buffer[1]);
|
|
|
+ gtk_clist_set_text (GTK_CLIST (launcherCList),
|
|
|
+ selectedRow, 2, buffer[2]);
|
|
|
+ gtk_clist_set_text (GTK_CLIST (launcherCList),
|
|
|
+ selectedRow, 0,
|
|
|
+ gtk_toggle_button_get_active
|
|
|
+ (GTK_TOGGLE_BUTTON (toggleButton))
|
|
|
+ == TRUE ? "Yes" : "No");
|
|
|
+ gtk_clist_unselect_row (GTK_CLIST (launcherCList), selectedRow, 0);
|
|
|
+ selectedRow = -1;
|
|
|
+ listModified = TRUE;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Reset the entry widgets & check box
|
|
|
+ */
|
|
|
+ gtk_entry_set_text (GTK_ENTRY (cmdEntryLabel), "");
|
|
|
+ gtk_entry_set_text (GTK_ENTRY (cmdEntry), "");
|
|
|
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggleButton), 0);
|
|
|
+
|
|
|
+ gtk_clist_unselect_row (GTK_CLIST (launcherCList), selectedRow, 0);
|
|
|
+}
|
|
|
+
|
|
|
+static void cbDelete (GtkWidget *widget, gpointer data)
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * Reset the entry widgets & check box
|
|
|
+ */
|
|
|
+ gtk_entry_set_text (GTK_ENTRY (cmdEntryLabel), "");
|
|
|
+ gtk_entry_set_text (GTK_ENTRY (cmdEntry), "");
|
|
|
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggleButton), 0);
|
|
|
+
|
|
|
+ if (selectedRow >= 0)
|
|
|
+ {
|
|
|
+ gtk_clist_remove (GTK_CLIST (launcherCList), selectedRow);
|
|
|
+ selectedRow = -1;
|
|
|
+ listModified = TRUE;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Create a Config tab with:
|
|
|
+ * 1. Checkbox to make panel visible/hidden
|
|
|
+ * 2. Text entry widget for command to run
|
|
|
+ * 3. Text entry widget for button label
|
|
|
+ * 4. Listbox to show items
|
|
|
+ * 5. Info tab
|
|
|
+ */
|
|
|
+static void create_plugin_tab (GtkWidget *tab_vbox)
|
|
|
+{
|
|
|
+ gchar *titles[3] = {"Visible", "Label", "Command"};
|
|
|
+ gchar *buffer[3];
|
|
|
+ gchar visible[5];
|
|
|
+ gint i = 0;
|
|
|
+ GLauncher *launcher;
|
|
|
+ GList *list;
|
|
|
+ GtkWidget *tabs;
|
|
|
+ GtkWidget *vbox;
|
|
|
+ GtkWidget *hbox;
|
|
|
+ GtkWidget *scrolled;
|
|
|
+ GtkWidget *text;
|
|
|
+ GtkWidget *label;
|
|
|
+ GtkWidget *button;
|
|
|
+ GtkWidget *aboutLabel;
|
|
|
+ GtkWidget *aboutText;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Make a couple of tabs. One for Config and one for info.
|
|
|
+ */
|
|
|
+ tabs = gtk_notebook_new ();
|
|
|
+ gtk_notebook_set_tab_pos (GTK_NOTEBOOK (tabs), GTK_POS_TOP);
|
|
|
+ gtk_box_pack_start (GTK_BOX (tab_vbox), tabs, TRUE, TRUE, 0);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Setup tab: give it some scroll bars to keep the config
|
|
|
+ * window size compact.
|
|
|
+ */
|
|
|
+ vbox = gkrellm_gtk_notebook_page (tabs, "Setup");
|
|
|
+ vbox = gkrellm_gtk_scrolled_vbox (vbox, NULL,
|
|
|
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Dynamically create the options on the Config tab according to MAX_BUTTONS.
|
|
|
+ */
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Create text boxes to put Labels and Commands in
|
|
|
+ */
|
|
|
+
|
|
|
+ label = gtk_label_new ("Label: ");
|
|
|
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
|
|
|
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
|
|
|
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
|
|
|
+
|
|
|
+ cmdEntryLabel = gtk_entry_new_with_max_length (255) ;
|
|
|
+ gtk_entry_set_text (GTK_ENTRY (cmdEntryLabel), "") ;
|
|
|
+ gtk_entry_set_editable (GTK_ENTRY (cmdEntryLabel), TRUE);
|
|
|
+ gtk_box_pack_start (GTK_BOX (vbox), cmdEntryLabel, FALSE, FALSE, 0) ;
|
|
|
+
|
|
|
+ label = gtk_label_new ("Command:");
|
|
|
+ gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, i);
|
|
|
+ gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
|
|
|
+ gtk_misc_set_alignment (GTK_MISC (label), 0, 0);
|
|
|
+
|
|
|
+ cmdEntry = gtk_entry_new_with_max_length (255) ;
|
|
|
+ gtk_entry_set_text (GTK_ENTRY (cmdEntry), "") ;
|
|
|
+ gtk_entry_set_editable (GTK_ENTRY (cmdEntry), TRUE) ;
|
|
|
+ gtk_box_pack_start (GTK_BOX (vbox), cmdEntry, FALSE, FALSE, 0) ;
|
|
|
+
|
|
|
+ toggleButton = gtk_check_button_new_with_label ("Visible?");
|
|
|
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (toggleButton), 0);
|
|
|
+ gtk_box_pack_start (GTK_BOX (vbox), toggleButton, FALSE, TRUE, 0);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Add buttons into their own box
|
|
|
+ * => Add Replace Delete /\ \/
|
|
|
+ */
|
|
|
+ hbox = gtk_hbox_new (FALSE, 0);
|
|
|
+ gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Add "Add", "Replace" & "Delete" buttons
|
|
|
+ */
|
|
|
+ button = gtk_button_new_with_label ("Add");
|
|
|
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
|
+ (GtkSignalFunc) cbAdd, NULL);
|
|
|
+
|
|
|
+ gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
|
|
|
+
|
|
|
+ button = gtk_button_new_with_label ("Replace");
|
|
|
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
|
+ (GtkSignalFunc) cbReplace, NULL);
|
|
|
+ gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
|
|
|
+
|
|
|
+ button = gtk_button_new_with_label ("Delete");
|
|
|
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
|
+ (GtkSignalFunc) cbDelete, NULL);
|
|
|
+ gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Add reposition buttons
|
|
|
+ */
|
|
|
+ button = gtk_button_new_with_label ("/\\");
|
|
|
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
|
+ (GtkSignalFunc) cbMoveUp, NULL);
|
|
|
+
|
|
|
+ gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
|
|
|
+ button = gtk_button_new_with_label ("\\/");
|
|
|
+ gtk_signal_connect (GTK_OBJECT (button), "clicked",
|
|
|
+ (GtkSignalFunc) cbMoveDown, NULL);
|
|
|
+ gtk_box_pack_start (GTK_BOX (hbox), button, TRUE, TRUE, 0);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Create listbox to hold each item
|
|
|
+ */
|
|
|
+ scrolled = gtk_scrolled_window_new (NULL, NULL);
|
|
|
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled),
|
|
|
+ GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
|
+ gtk_box_pack_start (GTK_BOX (vbox), scrolled, TRUE, TRUE, 0);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Create the CList with 3 titles:
|
|
|
+ * Label, Command, Visible
|
|
|
+ */
|
|
|
+ launcherCList = gtk_clist_new_with_titles (3, titles);
|
|
|
+ gtk_clist_set_shadow_type (GTK_CLIST (launcherCList), GTK_SHADOW_OUT);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Set the column widths
|
|
|
+ */
|
|
|
+ /* Label */
|
|
|
+ gtk_clist_set_column_width (GTK_CLIST (launcherCList), 0, 30);
|
|
|
+ /* Command */
|
|
|
+ gtk_clist_set_column_width (GTK_CLIST (launcherCList), 1, 100);
|
|
|
+ /* Visible */
|
|
|
+ gtk_clist_set_column_width (GTK_CLIST (launcherCList), 2, 200);
|
|
|
+
|
|
|
+ gtk_clist_set_column_justification (GTK_CLIST (launcherCList),
|
|
|
+ 0, GTK_JUSTIFY_LEFT);
|
|
|
+ gtk_clist_set_column_justification (GTK_CLIST (launcherCList),
|
|
|
+ 1, GTK_JUSTIFY_LEFT);
|
|
|
+ gtk_clist_set_column_justification (GTK_CLIST (launcherCList),
|
|
|
+ 2, GTK_JUSTIFY_LEFT);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Add signals for selecting a row in the CList.
|
|
|
+ */
|
|
|
+ gtk_signal_connect (GTK_OBJECT (launcherCList), "select_row",
|
|
|
+ (GtkSignalFunc) cListSelected, NULL);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Add signal for deselecting a row in the CList.
|
|
|
+ * If not, delselecting & attempting to create a new entry will overwrite
|
|
|
+ * the previuosly selected row.
|
|
|
+ */
|
|
|
+ gtk_signal_connect (GTK_OBJECT (launcherCList), "unselect_row",
|
|
|
+ (GtkSignalFunc) cListUnSelected, NULL);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Add the CList to the scrolling window
|
|
|
+ */
|
|
|
+ gtk_container_add (GTK_CONTAINER (scrolled), launcherCList);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Fill the CList with our commands etc.
|
|
|
+ */
|
|
|
+ for (i = 0, list = launcherList; list; i += 1, list = list->next)
|
|
|
+ {
|
|
|
+ launcher = (GLauncher *) list->data;
|
|
|
+ sprintf (visible, "%s", (launcher->visible == 1 ? "Yes" : "No"));
|
|
|
+ buffer[0] = visible;
|
|
|
+ buffer[1] = launcher->label;
|
|
|
+ buffer[2] = launcher->cmd;
|
|
|
+ gtk_clist_append (GTK_CLIST (launcherCList), buffer);
|
|
|
+ gtk_clist_set_row_data (GTK_CLIST (launcherCList), i, launcher);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Info tab
|
|
|
+ */
|
|
|
+ vbox = gkrellm_gtk_notebook_page (tabs, "Info");
|
|
|
+ text = gkrellm_gtk_scrolled_text_view (vbox, NULL, GTK_POLICY_AUTOMATIC,
|
|
|
+ GTK_POLICY_AUTOMATIC);
|
|
|
+ gkrellm_gtk_text_view_append_strings (text, GKrellMLaunchInfo,
|
|
|
+ (sizeof (GKrellMLaunchInfo)
|
|
|
+ / sizeof (gchar *)));
|
|
|
+
|
|
|
+ /*
|
|
|
+ * About tab
|
|
|
+ */
|
|
|
+ aboutText = gtk_label_new (GKrellMLaunchAbout);
|
|
|
+ aboutLabel = gtk_label_new ("About");
|
|
|
+ gtk_notebook_append_page (GTK_NOTEBOOK (tabs), aboutText, aboutLabel);
|
|
|
+
|
|
|
+}
|
|
|
+
|
|
|
+static void create_plugin (GtkWidget *vbox, gint first_create)
|
|
|
+{
|
|
|
+ gint i;
|
|
|
+ GLauncher *launcher;
|
|
|
+ GList *list;
|
|
|
+ GkrellmStyle *style;
|
|
|
+ GkrellmTextstyle *ts;
|
|
|
+ GkrellmTextstyle *ts_alt;
|
|
|
+
|
|
|
+ launcherVbox = vbox;
|
|
|
+
|
|
|
+ if (first_create)
|
|
|
+ {
|
|
|
+ for (list = launcherList; list; list = list->next)
|
|
|
+ {
|
|
|
+ launcher = (GLauncher *) list->data;
|
|
|
+ launcher->panel = gkrellm_panel_new0();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ style = gkrellm_meter_style (style_id);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Each GkrellmStyle has two text styles. The theme designer has picked the
|
|
|
+ * colors and font sizes, presumably based on knowledge of what you draw
|
|
|
+ * on your panel. You just do the drawing. You probably could assume
|
|
|
+ * the ts font is larger than the ts_alt font, but again you can be
|
|
|
+ * overridden by the theme designer.
|
|
|
+ */
|
|
|
+ ts = gkrellm_meter_textstyle (style_id);
|
|
|
+ ts_alt = gkrellm_meter_alt_textstyle (style_id);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Create a text decal that will be converted to a button.
|
|
|
+ * Make it the entire width of the panel.
|
|
|
+ */
|
|
|
+ for (i = 0, list = launcherList; list; i += 1, list = list->next)
|
|
|
+ {
|
|
|
+ launcher = (GLauncher *) list->data;
|
|
|
+ launcher->decal = gkrellm_create_decal_text (launcher->panel,
|
|
|
+ launcher->label, ts_alt, style, -1, -1, -1);
|
|
|
+ /*
|
|
|
+ * Configure the panel to created decal, and create it.
|
|
|
+ */
|
|
|
+ gkrellm_panel_configure (launcher->panel, NULL, style);
|
|
|
+ gkrellm_panel_create (vbox, monitor, launcher->panel);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * After the panel is created, the decal can be converted into a button.
|
|
|
+ * First draw the initial text into the text decal button and then
|
|
|
+ * put the text decal into a meter button.
|
|
|
+ */
|
|
|
+ gkrellm_draw_decal_text (launcher->panel, launcher->decal,
|
|
|
+ launcher->label,1);
|
|
|
+ gkrellm_put_decal_in_meter_button (launcher->panel, launcher->decal,
|
|
|
+ buttonPress,
|
|
|
+ GINT_TO_POINTER (i), NULL);
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Note: all of the above gkrellm_draw_decal_XXX() calls will not
|
|
|
+ * appear on the panel until a gkrellm_draw_panel_layers() call is
|
|
|
+ * made. This will be done in update_plugin(), otherwise we would
|
|
|
+ * make the call here and anytime the decals are changed.
|
|
|
+ */
|
|
|
+
|
|
|
+ if (first_create)
|
|
|
+ {
|
|
|
+ for (list = launcherList; list; list = list->next)
|
|
|
+ {
|
|
|
+ launcher = (GLauncher *) list->data;
|
|
|
+ gtk_signal_connect (GTK_OBJECT (launcher->panel->drawing_area),
|
|
|
+ "expose_event", (GtkSignalFunc) panel_expose_event, NULL);
|
|
|
+ }
|
|
|
+ /*
|
|
|
+ * Setup the initial visible status of each panel
|
|
|
+ * according to the config item read in.
|
|
|
+ */
|
|
|
+ setVisibility ();
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+/*
|
|
|
+ * The monitor structure tells GKrellM how to call the plugin routines.
|
|
|
+ */
|
|
|
+static GkrellmMonitor plugin_mon =
|
|
|
+{
|
|
|
+ CONFIG_NAME, /* Name, for config tab. */
|
|
|
+ 0, /* Id, 0 if a plugin */
|
|
|
+ create_plugin, /* The create function */
|
|
|
+ update_plugin, /* The update function */
|
|
|
+ create_plugin_tab, /* The config tab create function */
|
|
|
+ apply_plugin_config, /* Apply the config function */
|
|
|
+ save_plugin_config, /* Save user config */
|
|
|
+ load_plugin_config, /* Load user config */
|
|
|
+ PLUGIN_CONFIG_KEYWORD, /* config keyword */
|
|
|
+
|
|
|
+ NULL, /* Undefined 2 */
|
|
|
+ NULL, /* Undefined 1 */
|
|
|
+ NULL, /* private */
|
|
|
+
|
|
|
+ PLUGIN_PLACEMENT, /* Insert plugin before this monitor */
|
|
|
+
|
|
|
+ NULL, /* Handle if a plugin, filled in by GKrellM */
|
|
|
+ NULL /* path if a plugin, filled in by GKrellM */
|
|
|
+};
|
|
|
+
|
|
|
+/*
|
|
|
+ * All GKrellM plugins must have one global routine named gkrellm_init_plugin()
|
|
|
+ * which returns a pointer to a filled in monitor structure.
|
|
|
+ */
|
|
|
+GkrellmMonitor* gkrellm_init_plugin ()
|
|
|
+{
|
|
|
+ /*
|
|
|
+ * Don't want any row in the Config tab initially selected.
|
|
|
+ */
|
|
|
+ selectedRow = -1;
|
|
|
+ listModified = FALSE;
|
|
|
+
|
|
|
+ style_id = gkrellm_add_meter_style (&plugin_mon, STYLE_NAME);
|
|
|
+ monitor = &plugin_mon;
|
|
|
+ return &plugin_mon;
|
|
|
+}
|