/* GKrellM (C) 1999-2000 Bill Wilson | | Author: Bill Wilson bill@gkrellm.net | Latest versions might be found at: http://gkrellm.net | | 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. | | To get a copy of the GNU General Puplic License, write to the | Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* File Monitor plugin for GKrellM | | Copyright (C) 2000 Anatoly Asviyan | | Author: Anatoly Asviyan | | Version: for gkrellm version 0.10.4 and up | | See README for details */ #include #include #include #include "fm_led.xpm" static char *plugin_info[] = { "File Monitor plugin for GKrellM\n" "Copyright (C) 2001 Anatoly Asviyan\n" "aanatoly@linuxmail.org\n" "Released under GPL\n" "\n" "This plugin monitors a file and displays its contens in gkrellm. File can have\n" "multiple rows of the form 'name : value : [flag]'. If flag non-empty then\n" "for WARNING value - the orange led will light up and for ALERT value - red.\n" "For example\n" " CPU:50.8:ALERT\n" " SBr:33.4:WARNING\n" " Fan1:4560:\n" "or\n" " Temp:31 C:\n" " Hum:49 %:\n" "\n" "Plugin can monitor multiple files and for each file, you can specify\n" "the following:\n", "Label", " - label of gkrellm panel\n", "File to monitor", " - as is :) - file to monitor. It would be checked every 5 sec\n", "Update program", " - the program to update a monitored file.\n", "Warning command", " - any shell command to run whenever warning flag is set.\n", "Alert command", " - any shell command to run whenever alert flag is set.\n" "\n" "I'm using it to monitor my HW state from via686a sensor chip. For this purpose\n" "I wrote sensors.tcl script that periodicaly run 'sensors' utility, processes\n" "its output and writes results to ~/.sensors in the above format. \n" "sensors.tcl has its own documentation at the beginning of file.\n" "Here is sensor's configuration\n" "label \n" "file <~/.sensors>\n" "Update command \n" "Warning command \n" "Alert command \n" "\n", "CREDITS\n", "Plugin is based on Bill Willson (bill@gkrellm.net) demo programs\n" "and on fileread plugin by Henry Palonen (h@yty.net)\n" "\n" }; #define FM_CONFIG_NAME "FMonitor" /* Name in the configuration window */ #define FM_STYLE_NAME "fmonitor" /* Theme subdirectory name and gkrellmrc */ #define LEN 1024 #define MAXFILENUM 10 #define MAXPARAMNUM 10 #define MAXARGNUM 20 //#define HORIZONTALLY_CENTERED_LED enum { FM_LABEL, FM_FILE, FM_UPDATE, FM_WARN, FM_ALERT, FM_ENTRY_NUM }; typedef struct { gchar *text[FM_ENTRY_NUM]; gint pid; //pid of update command } fm_data; typedef struct { Panel *panel; Decal *label; Decal *led[MAXPARAMNUM]; Decal *name[MAXPARAMNUM]; Decal *value[MAXPARAMNUM]; int fn[MAXPARAMNUM]; int rownum, y; } fm_gui; static fm_data fmc[MAXFILENUM]; static fm_gui fmg[MAXFILENUM]; static int fmnum = 0, cnum = 0, selrow = -1; extern struct tm current_tm; //static Panel *panel; //static Decal *label_text; static gint style_id; static gboolean force_update; static GdkPixmap *ledp, *ledm; static GtkWidget *fm_vbox; static GtkWidget *entry[FM_ENTRY_NUM]; static GtkWidget *config_list; static GtkWidget *btn_enter, *btn_del; static char *config_name[FM_ENTRY_NUM] = { "label", "file", "update", "warn", "alert" }; #define MY_FREE(x) if(x) {g_free(x);(x)=NULL;} static void destroy_fm_panels(); static void create_fm_panels(int first_create); static void run_update_cmds(); static gint panel_expose_event(GtkWidget *widget, GdkEventExpose *ev) { int i; for (i = 0; i < fmnum; i++) { if (widget == fmg[i].panel->drawing_area) gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], fmg[i].panel->pixmap, ev->area.x, ev->area.y, ev->area.x, ev->area.y, ev->area.width, ev->area.height); } return FALSE; } /* Shamelessly ripped from the Gtk docs. */ void fr_message(gchar *message) { GtkWidget *dialog, *label, *okay_button; dialog = gtk_dialog_new(); label = gtk_label_new (message); okay_button = gtk_button_new_with_label("OK"); gtk_signal_connect_object (GTK_OBJECT (okay_button), "clicked", GTK_SIGNAL_FUNC (gtk_widget_destroy), GTK_OBJECT(dialog)); gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->action_area), okay_button); gtk_container_add (GTK_CONTAINER (GTK_DIALOG(dialog)->vbox), label); gtk_widget_show_all (dialog); } static void destroy_decal(Panel *p, Decal *d) { p->decal = g_list_remove(p->decal, d); gkrellm_destroy_decal(d); } static void update_plugin() { Style *style; TextStyle *ts, *ts_alt; int x, h, r, i, rownum, ph, drawing_leds, changed = 0; int alert = 0, warning = 0; char s[LEN]; FILE *fp; /* animation of alert and warning led */ if (!GK.ten_second_tick && !force_update) { for (i = 0; i < fmnum; i++) { drawing_leds = FALSE; for (r = 0; r < fmg[i].rownum; ++r) { if (fmg[i].fn[r] < 2) { x = ((GK.timer_ticks % 10) < 2) ? 2 : fmg[i].fn[r]; gkrellm_draw_decal_pixmap(fmg[i].panel, fmg[i].led[r],x); drawing_leds = TRUE; } } if (drawing_leds) gkrellm_draw_layers(fmg[i].panel); } return; } /* time to check monitored file(s) */ force_update = FALSE; style = gkrellm_meter_style(style_id); ts = gkrellm_meter_textstyle(style_id); ts_alt = gkrellm_meter_alt_textstyle(style_id); for (i = 0; i < fmnum; i++) { ph = fmg[i].panel->h; rownum = 0; fp = fopen(fmc[i].text[FM_FILE], "r"); if (fp) { /* read at most MAXPARAMNUM valid rows from file */ while (fgets(s, LEN, fp) && (rownum < MAXPARAMNUM)) { char *sname, *svalue, *sled; sname = strtok(s, ":"); if (!sname || *sname == '\0') continue; svalue = strtok(NULL, ":"); if (!svalue || *svalue == '\0') continue; sled = strtok(NULL, " \n\t"); rownum++; /* create decals for new row */ if (rownum > fmg[i].rownum) { changed = 1; r = rownum - 1; fmg[i].y += 1; #ifdef HORIZONTALLY_CENTERED_LED /* Create led first so it will be behind name and value */ /* name at left margin, value at right margin, led center */ fmg[i].led[r] = gkrellm_create_decal_pixmap(fmg[i].panel, ledp, ledm, 3, style, 0, fmg[i].y); fmg[i].led[r]->x = (gkrellm_chart_width() - fmg[i].led[r]->w) / 2; fmg[i].name[r] = gkrellm_create_decal_text(fmg[i].panel, "VCOR2", ts_alt, style, -1, fmg[i].y, 0); fmg[i].value[r] = gkrellm_create_decal_text(fmg[i].panel, "5555", ts_alt, style, 0, fmg[i].y, 0); fmg[i].value[r]->x = gkrellm_chart_width() - fmg[i].value[r]->w - style->margin; #else fmg[i].led[r] = gkrellm_create_decal_pixmap(fmg[i].panel, ledp, ledm, 3, style, -1, fmg[i].y); x = style->margin + 5; fmg[i].name[r] = gkrellm_create_decal_text(fmg[i].panel, "VCOR2", ts_alt, style, x, fmg[i].y, 0); // fmg[i].value[r] = gkrellm_create_decal_text(fmg[i].panel, // "5555", ts_alt, style, x+fmg[i].name[r]->w, fmg[i].y, 0); /* Bill: Do you think value decal should be at right margin ? */ /* Anatoly: Yes I do, I added it to TODO list */ fmg[i].value[r] = gkrellm_create_decal_text(fmg[i].panel, "5555", ts_alt, style, 0, fmg[i].y, 0); fmg[i].value[r]->x = gkrellm_chart_width() - fmg[i].value[r]->w - style->margin; #endif h = fmg[i].name[r]->h; if (fmg[i].value[r]->h > h) h = fmg[i].value[r]->h; if (fmg[i].led[r]->h < h) /* vertically center led */ fmg[i].led[r]->y += (h - fmg[i].led[r]->h) / 2; fmg[i].y += h; fmg[i].rownum++; } if (!sled || !(*sled)) { fmg[i].fn[rownum-1] = 2; } else if (!strcmp(sled, "WARNING")) { fmg[i].fn[rownum-1] = 1; warning = 1; } else { fmg[i].fn[rownum-1] = 0; alert = 1; } gkrellm_draw_decal_pixmap(fmg[i].panel, fmg[i].led[rownum-1], fmg[i].fn[rownum-1]); fprintf(stderr, "update led pixmap\n"); gkrellm_draw_decal_text(fmg[i].panel, fmg[i].name[rownum-1], sname, -1); gkrellm_draw_decal_text(fmg[i].panel, fmg[i].value[rownum-1], svalue, -1); } fclose(fp); } /* destroys unused decals */ while (fmg[i].rownum > rownum) { changed = 1; h = fmg[i].name[fmg[i].rownum-1]->h; if (fmg[i].value[fmg[i].rownum-1]->h > h) h = fmg[i].value[fmg[i].rownum-1]->h; fmg[i].y -= h; destroy_decal(fmg[i].panel, fmg[i].led[fmg[i].rownum-1]); destroy_decal(fmg[i].panel, fmg[i].name[fmg[i].rownum-1]); destroy_decal(fmg[i].panel, fmg[i].value[fmg[i].rownum-1]); fmg[i].rownum--; } //gkrellm_monitor_height_adjust(fmg[i].panel->h - ph); if (changed) { gkrellm_configure_panel(fmg[i].panel, NULL, style); gkrellm_create_panel(fm_vbox, fmg[i].panel, gkrellm_bg_meter_image(style_id)); gkrellm_monitor_height_adjust(fmg[i].panel->h - ph); gkrellm_pack_side_frames(); if (fmc[i].text[FM_LABEL]) { gkrellm_draw_decal_text(fmg[i].panel, fmg[i].label, fmc[i].text[FM_LABEL], -1); } } if (warning) system(fmc[i].text[FM_WARN]); if (alert) system(fmc[i].text[FM_ALERT]); gkrellm_draw_layers(fmg[i].panel); } return; } /* creates "Sensors" monitor panel. the panel consists of label, * and led/name/value pair for each row found in rc_file */ static void create_plugin(GtkWidget *vbox, gint first_create) { fm_vbox = vbox; create_fm_panels(first_create); force_update = TRUE; } static void destroy_fm_panels() { int i; for (i = 0; i < fmnum; i++) { if (fmg[i].panel) { gkrellm_monitor_height_adjust(-fmg[i].panel->h); gkrellm_destroy_decal_list(fmg[i].panel); gkrellm_destroy_krell_list(fmg[i].panel); gkrellm_destroy_panel(fmg[i].panel); g_free(fmg[i].panel); fmg[i].panel = NULL; fmg[i].rownum = 0; } } } static void create_fm_panels(int first_create) { Style *style; TextStyle *ts, *ts_alt; int i; GdkImlibImage *led = NULL; style = gkrellm_meter_style(style_id); ts = gkrellm_meter_textstyle(style_id); ts_alt = gkrellm_meter_alt_textstyle(style_id); /* gkrellm_load_image will kill red_led and orange_led if not NULL */ gkrellm_load_image("fm_led", fm_led_xpm, &led, FM_STYLE_NAME); gkrellm_render_to_pixmap(led, &ledp, &ledm, 0, 0); for (i = 0; i < fmnum; i++) { //int y; if (first_create) fmg[i].panel = gkrellm_panel_new0(); else { gkrellm_destroy_krell_list(fmg[i].panel); gkrellm_destroy_decal_list(fmg[i].panel); fmg[i].rownum = 0; } fmg[i].panel->textstyle = ts; /* would be used for a panel label */ fmg[i].y = 0; if (fmc[i].text[FM_LABEL]) { fmg[i].label = gkrellm_create_decal_text(fmg[i].panel, fmc[i].text[FM_LABEL], ts, style, -1, -1, -1); fmg[i].y = fmg[i].label->y + fmg[i].label->h; } else /* If no label, start remaining decals at top margin */ gkrellm_get_top_bottom_margins(style, &fmg[i].y, NULL); gkrellm_configure_panel(fmg[i].panel, NULL, style); //panel->label->h_panel += 2; /* Some bottom margin */ gkrellm_create_panel(fm_vbox, fmg[i].panel, gkrellm_bg_meter_image(style_id)); gkrellm_monitor_height_adjust(fmg[i].panel->h); if (fmc[i].text[FM_LABEL]) { gkrellm_draw_decal_text(fmg[i].panel, fmg[i].label, fmc[i].text[FM_LABEL], 1); } if (first_create) gtk_signal_connect(GTK_OBJECT (fmg[i].panel->drawing_area), "expose_event", (GtkSignalFunc) panel_expose_event, NULL); gkrellm_draw_layers(fmg[i].panel); } if (first_create) run_update_cmds(); } static void item_sel(GtkWidget *clist, gint row, gint column, GdkEventButton *event, gpointer data ) { gchar *tmp; int i; selrow = row; for (i = 0; i < FM_ENTRY_NUM; i++) { if (gtk_clist_get_text(GTK_CLIST(config_list), row, i, &tmp)) { gtk_entry_set_text(GTK_ENTRY(entry[i]), tmp); } else { fprintf(stderr, "Strange: can't read %d-th col data " "of %d selected row\n", i, row); } } gtk_widget_set_sensitive(btn_del, TRUE); return; } static void item_unsel(GtkWidget *clist, gint row, gint column, GdkEventButton *event, gpointer data ) { int i; selrow = -1; for (i = 0; i < FM_ENTRY_NUM; i++) { gtk_entry_set_text(GTK_ENTRY(entry[i]), ""); } gtk_widget_set_sensitive(btn_del, FALSE); return; } static void on_add_click(GtkButton *button, gpointer *data) { char str[80]; int i; fm_data c; if (!*gtk_entry_get_text(GTK_ENTRY(entry[FM_FILE]))) { sprintf(str, "You must specify file to monitor.\n"); fr_message(str); return; } if (selrow >= 0) { /* we're editing existing entry */ gtk_clist_freeze( GTK_CLIST(config_list) ); for (i = 0; i < FM_ENTRY_NUM; i++) { gtk_clist_set_text(GTK_CLIST(config_list), selrow, i, gtk_entry_get_text(GTK_ENTRY(entry[i]))); } gtk_clist_thaw( GTK_CLIST(config_list) ); } else { /* we're adding new row */ if (cnum == MAXFILENUM) { sprintf(str, "Maximum (%d) files has reached.\nSorry.\n", MAXFILENUM); fr_message(str); return; } cnum++; for (i = 0; i < FM_ENTRY_NUM; i++) { c.text[i] = gtk_entry_get_text(GTK_ENTRY(entry[i])); } gtk_clist_append (GTK_CLIST(config_list), c.text); } return; } static void on_del_click(GtkButton *button, gpointer *data) { if (selrow == -1) return; gtk_clist_remove(GTK_CLIST(config_list), selrow); cnum--; } static void create_config_tab(GtkWidget *tab_vbox) { GtkWidget *vbox; GtkWidget *tabs; GtkWidget *text; GtkWidget *scrolled; GtkWidget *btn_hbox; gchar *titles[]={"Lable","File", "Update Command", "Warning Command", "Alert Command" }; GtkWidget *edit_table, *scrolled_window; GtkWidget *llabel, *lfile, *lupdate, *lwarn, *lalert; gint i; //item_t *item; 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); /* Preferences Tab */ vbox = gkrellm_create_tab(tabs, "Preferences"); // Edit table edit_table = gtk_table_new(3, 5, FALSE); llabel = gtk_label_new("Label:"); gtk_misc_set_alignment (GTK_MISC (llabel), 1, 1); gtk_table_attach(GTK_TABLE(edit_table), llabel, 0, 1, 0, 1, GTK_FILL, 0, 1, 1); entry[FM_LABEL] = gtk_entry_new_with_max_length(9); gtk_table_attach(GTK_TABLE(edit_table), entry[FM_LABEL], 1, 2, 0, 1, 0, 0, 1 , 1); llabel = gtk_label_new(" "); gtk_misc_set_alignment (GTK_MISC (llabel), 1, 1); gtk_table_attach(GTK_TABLE(edit_table), llabel, 2, 3, 0, 1, GTK_FILL|GTK_EXPAND, 0, 1, 1); lfile = gtk_label_new("File to monitor:"); gtk_misc_set_alignment (GTK_MISC (lfile), 1, 1); gtk_table_attach(GTK_TABLE(edit_table), lfile, 0, 1, 1, 2, GTK_FILL, 0, 1, 1); entry[FM_FILE] = gtk_entry_new_with_max_length(255); gtk_table_attach(GTK_TABLE(edit_table), entry[FM_FILE], 1, 3, 1, 2, GTK_FILL|GTK_EXPAND, 0, 1, 1); lupdate = gtk_label_new("Update Command:"); gtk_misc_set_alignment (GTK_MISC (lupdate), 1, 1); gtk_table_attach(GTK_TABLE(edit_table), lupdate, 0, 1, 2, 3, GTK_FILL, 0, 1, 1); entry[FM_UPDATE] = gtk_entry_new_with_max_length(255); gtk_table_attach(GTK_TABLE(edit_table), entry[FM_UPDATE], 1, 3, 2, 3, GTK_FILL, 0, 1, 1); lwarn = gtk_label_new("Warning Command:"); gtk_misc_set_alignment (GTK_MISC (lwarn), 1, 1); gtk_table_attach(GTK_TABLE(edit_table), lwarn, 0, 1, 3, 4, GTK_FILL, 0, 1, 1 ); entry[FM_WARN] = gtk_entry_new_with_max_length(255); gtk_table_attach(GTK_TABLE(edit_table), entry[FM_WARN], 1, 3, 3, 4, GTK_FILL, 0, 1, 1); lalert = gtk_label_new("Alert Command:"); gtk_misc_set_alignment (GTK_MISC (lalert), 1, 1); gtk_table_attach(GTK_TABLE(edit_table), lalert, 0, 1, 4, 5, GTK_FILL, 0, 1, 1); entry[FM_ALERT] = gtk_entry_new_with_max_length(255); gtk_table_attach(GTK_TABLE(edit_table), entry[FM_ALERT], 1, 3, 4, 5, GTK_FILL, 0, 1, 1); // Buttons to accept/reject config. data in the edit box btn_hbox = gtk_hbox_new(FALSE, 5); btn_enter=gtk_button_new_with_label("Enter"); gtk_signal_connect(GTK_OBJECT(btn_enter), "clicked", GTK_SIGNAL_FUNC(on_add_click),NULL); btn_del=gtk_button_new_with_label("Delete"); gtk_widget_set_sensitive(btn_del, FALSE); gtk_signal_connect(GTK_OBJECT(btn_del), "clicked", GTK_SIGNAL_FUNC(on_del_click),NULL); gtk_box_pack_start(GTK_BOX(btn_hbox), btn_enter, TRUE, FALSE, 2); gtk_box_pack_start(GTK_BOX(btn_hbox), btn_del, TRUE, FALSE, 2); // List with saved configurations scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), GTK_POLICY_ALWAYS, GTK_POLICY_ALWAYS); config_list = gtk_clist_new_with_titles(5,titles); gtk_container_add(GTK_CONTAINER(scrolled_window), config_list); gtk_signal_connect(GTK_OBJECT(config_list), "select-row", GTK_SIGNAL_FUNC(item_sel), NULL); gtk_signal_connect(GTK_OBJECT(config_list), "unselect-row", GTK_SIGNAL_FUNC(item_unsel), NULL); gtk_clist_set_selection_mode(GTK_CLIST(config_list), GTK_SELECTION_SINGLE); for (i=0; i<5; i++) { int width; switch (i) { case 0: width=70;break; case 1: width=80;break; default: width=150;break; } gtk_clist_set_column_width(GTK_CLIST(config_list), i, width); } for (i = 0; i < fmnum; i++) gtk_clist_append(GTK_CLIST(config_list), fmc[i].text); cnum = fmnum; //gtk_clist_columns_autosize(GTK_CLIST(config_list)); gtk_box_pack_start(GTK_BOX(vbox), edit_table, FALSE, FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox), btn_hbox, FALSE, FALSE, 2); gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 2); /* Info Tab */ vbox = gkrellm_create_tab(tabs, "Info"); 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); text = gtk_text_new(NULL, NULL); for (i = 0; i < sizeof(plugin_info)/sizeof(gchar *); ++i) gkrellm_add_info_text_string(text, plugin_info[i]); gtk_text_set_editable(GTK_TEXT(text), FALSE); gtk_container_add(GTK_CONTAINER(scrolled), text); } static void save_config(FILE *f) { int i, j; for (i = 0; i < fmnum; i++) { for (j = 0; j < FM_ENTRY_NUM; j++) { fprintf(f, "FMonitor %s:%d:%s\n", config_name[j], i, fmc[i].text[j] ? fmc[i].text[j] : ""); } } } static void load_config( gchar* arg ) { char *tmp, *tmp2, *name, *value; int rowno, i; tmp = g_strdup(arg); name = strtok(tmp, ":"); if (!name) return; tmp2 = strtok(NULL, ":"); if (!tmp2) return; rowno = atoi(tmp2); if (rowno < MAXFILENUM) { value = strtok(NULL, "\n"); for (i = 0; i < FM_ENTRY_NUM; i++) { if (!strcmp(name, config_name[i])) { if (value) fmc[rowno].text[i] = g_strdup(value); else fmc[rowno].text[i] = g_strdup(""); } } if (rowno+1 > fmnum) fmnum = rowno+1; } g_free(tmp); } static void del_fmc_entries() { int i, no; for (no = 0; no < fmnum; no++) { for (i = 0; i < FM_ENTRY_NUM; i++) { MY_FREE(fmc[no].text[i]); } } } static void run_update_cmds() { int i, pid, ac; char *arg[MAXARGNUM], *cmd; //fprintf(stderr, "run_update_cmds\n"); for (i = 0; i < fmnum; i++) { cmd = g_strdup(fmc[i].text[FM_UPDATE]); ac = 0; arg[ac] = strtok(cmd, " \n\t"); while ((ac < MAXARGNUM-1) && arg[ac]) arg[++ac] = strtok(NULL, " \n\t"); if (arg[0] && *(arg[0])) { pid = fork(); if (pid) { //papa fmc[i].pid = pid; g_free(cmd); } else { //son execvp(arg[0], arg); fprintf(stderr, "Can't execvp <%s>\n", fmc[i].text[FM_UPDATE]); _exit(1); } } } } static void kill_update_cmds() { int i; //fprintf(stderr, "kill_update_cmds\n"); for (i = 0; i < fmnum; i++) { if (fmc[i].pid) { //fprintf(stderr, "\tkilling %d\n", fmc[i].pid); kill(fmc[i].pid, SIGKILL); } } } static void apply_config() { char *tmp; int i; selrow = -1; //fprintf(stderr, "apply_config\n"); item_unsel(GTK_WIDGET(config_list), 0, 0, NULL, NULL); del_fmc_entries(); kill_update_cmds(); destroy_fm_panels(); fmnum = 0; while (gtk_clist_get_text(GTK_CLIST(config_list), fmnum, 0, &tmp)) { for (i = 0; i < FM_ENTRY_NUM; i++) { if (gtk_clist_get_text(GTK_CLIST(config_list), fmnum, i, &tmp)) fmc[fmnum].text[i] = g_strdup(tmp); } fmnum++; if (fmnum == MAXFILENUM) break; } create_fm_panels(1); force_update = TRUE; } void my_wait(int signo) { waitpid(-1, NULL, WNOHANG | WUNTRACED); } /* The monitor structure tells GKrellM how to call the plugin routines. */ static Monitor plugin_mon = { FM_CONFIG_NAME, /* Name, for config tab. */ 0, /* Id, 0 if a plugin */ create_plugin, /* The create function */ update_plugin, /* The update function */ create_config_tab, /* The config tab create function */ apply_config, /* Apply the config function */ save_config, /* Save user config */ load_config, /* Load user config */ FM_CONFIG_NAME, /* config keyword */ NULL, /* Undefined 2 */ NULL, /* Undefined 1 */ NULL, /* private */ MON_MAIL, /* 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 init_plugin() | which returns a pointer to a filled in monitor structure. */ Monitor * init_plugin() { style_id = gkrellm_add_meter_style(&plugin_mon, FM_STYLE_NAME); atexit(kill_update_cmds); signal(SIGCHLD, my_wait); return &plugin_mon; }