/* GKrellM | Copyright (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. */ /* Seti@home plugin for GKrellM | | Copyright (C) 2000 Henry Palonen | | Author: Henry Palonen h yty dot net | | Version: for gkrellm version 0.10.4 and up */ /* Simple seti@home client monitor. See www.setiathome.com for details about | seti@home effort. Basicaly we are trying to find extraterrestial | intelligence ;) | | You can start & stop seti@home client by pressing left-mouse button over | seti-monitor. | | Plugin is based to Bill Wilson's great work, GKrellM & meminfo.c & template.c files. | | Latest versions might be found from http://www.yty.net/h/gkrellm */ /* If this file is compiled as a shared object file and installed in | in your ~/.gkrellm/plugins directory, then it will be loaded when | gkrellm starts up. | | gcc -fPIC `gtk-config --cflags` `imlib-config --cflags-gdk` -c seti.c | gcc -shared -Wl -o seti.so seti.o | cp seti.so ~/.gkrellm/plugins */ /* | Starting code, finally ;) */ #include #include #include #define PIPE_SIZE 4 static Panel *seti; static gchar *seti_file_path; static gint seti_pipe[PIPE_SIZE]; typedef struct { gchar *command; FILE *pipe; gint timeout; gint messages; gint new; gint seen; } Setiproc; static Decal *seti_label_decal; static Decal *seti_icon_decal; static Setiproc seti_user_agent; static gint seti_prog_state; static Decal *seti_decal; static gchar *seti_label; static gint seti_label_is_data,x_seti; static Krell *seti_krell; static gint seti_first_create=1; /* * Updating krell */ static void update_seti() { FILE *f; gchar buf[160]; gdouble lprogress; gchar hjuu[10]; gfloat daa; Krell *krell; krell = KRELL(seti); /* It's enough to update once every ten seconds. It's actually too | often. Should be minute or so. But then there should be a call which | updates krell with "force" at startup so seti@home status is readable | right away. I worst case there would be one minute delay. Now delay is 10 secs max. | | UPDATE since 0.10.0: | Now there is "seti_first_create" which launces drawing of monitor right | from the start. | */ if (GK.ten_second_tick || seti_first_create) { /* This was the first time to draw */ seti_first_create = 0; /* File format is something with | | prog=0.2355233 | | line on it. */ if ((f = fopen(seti_file_path, "r")) != NULL) { while ((fgets(buf, sizeof(buf), f)) != NULL) { if (strncmp(buf, "prog", 4) == 0) { sscanf(buf,"prog=%lg", &lprogress); if (GK.debug) printf("setiprogress %g \n", lprogress); lprogress = lprogress * 100; krell->full_scale = 100; krell->previous = 0; gkrellm_update_krell(seti, krell, lprogress); gkrellm_draw_layers(seti); } } fclose(f); } } } static void pipe_command(Setiproc *mp) { gchar buf[128]; if (mp->command == NULL || *(mp->command) == '\0') return; snprintf(buf, sizeof(buf), "%s 1>ls.txt", mp->command); if (GK.debug) printf("pipe_command: %s\n", buf); if ((mp->pipe = popen(buf, "r")) == NULL) return; fcntl(fileno(mp->pipe), F_SETFL, O_NONBLOCK); } /* User has clicked panel. We should try to start/stop seti@home software */ static gint seti_panel_click(GtkWidget *widget, GdkEventButton *ev) { if (ev->button == 1) { if (GK.debug) printf("Right click on seti@home. Will try to start/stop software\n"); if (seti_prog_state) { seti_user_agent.command = g_strdup("killall -STOP setiathome"); seti_prog_state=0; } else { seti_user_agent.command = g_strdup("killall -CONT setiathome"); seti_prog_state=1; } pipe_command(&seti_user_agent); } } static gint seti_expose_event (GtkWidget *widget, GdkEventExpose *event) { if (widget == seti->drawing_area) { gdk_draw_pixmap(widget->window, widget->style->fg_gc[GTK_WIDGET_STATE (widget)], seti->pixmap, event->area.x, event->area.y, event->area.x, event->area.y, event->area.width, event->area.height); } return FALSE; } /* * Creating seti-monitor */ void create_seti(GtkWidget *vbox, gint first_create) { Style *style; GdkImlibImage *bg_image; TextStyle *ts; gint w; static Style seti_style; #ifdef USE_FS_STYLE_WHICH_MAY_SHOW_A_DIFF_ONLY_IN_THE_DEFAULT_THEME #define MY_STYLE FS_STYLE #else #define MY_STYLE DEFAULT_STYLE #endif /* Allocate a panel structure. plug->label and plug->textstyle | structures will also be allocated... */ if (first_create) { seti = gkrellm_panel_new0(); seti_label = ("Seti"); seti_decal = gkrellm_decal_new0(); } else { gkrellm_destroy_decal_list(seti); gkrellm_destroy_krell_list(seti); } style = gkrellm_style_new0(); seti_style = *gkrellm_meter_style(gkrellm_lookup_meter_style_id(UPTIME_STYLE_NAME)); seti_krell = gkrellm_create_krell(seti, gkrellm_krell_meter_image(MY_STYLE), style); /* Measure the lenght of string "Seti" in pixels and move decal to there | */ seti->textstyle = gkrellm_meter_textstyle(gkrellm_lookup_meter_style_id(UPTIME_STYLE_NAME)); ts = seti->textstyle; w = gdk_string_width(ts->font, "Seti") + 2; if (w > UC.chart_width - 2 * seti_style.margin) w = UC.chart_width - 2 * seti_style.margin; seti_decal = gkrellm_create_text_decal(seti, "Seti", ts, &seti_style, -1, -1, w); seti_decal->x = (UC.chart_width - seti_decal->w) / 2; /* | Configure panel sets panel height etc. */ gkrellm_configure_panel(seti, NULL, style); /* Add margin to panel height for clearer appearance. */ seti->label->h_panel += seti_style.margin; bg_image = gkrellm_bg_meter_image(MY_STYLE); gkrellm_create_panel(vbox, seti, bg_image); gkrellm_monitor_height_adjust(seti->h); /* Actual text-drawing is done here */ gkrellm_draw_decal_text(seti, seti_decal, seti_label, 10); gkrellm_draw_layers(seti); if (first_create) { gtk_signal_connect(GTK_OBJECT (seti->drawing_area), "expose_event", (GtkSignalFunc) seti_expose_event, NULL); gtk_signal_connect(GTK_OBJECT(seti->drawing_area),"button_release_event", (GtkSignalFunc) seti_panel_click, NULL); } /* Read the functions first time... */ update_seti(); } /* * Configuration page * Configuration contains path to 'state.sah' */ static GtkWidget *seti_path_entry; static gchar *seti_info_text = "Seti@home progress meter shows current progress in \n" "seti-workunit.\n\n" "Progress value is read every ten seconds from \n" "'state.sah' file. User can change the filename\n" "using 'File location' tab.\n\n" "File is parsed for line 'prog=0.nnnnnnn' and\n" "that value is simply converted to krell movement.\n\n" "Seti@home client can be started & stopped by pressing\n" "left mouse button over seti-monitor.\n\n" "Version 0.10.0 \n\nCopyright 2000, Henry Palonen \n" "http://www.yty.net/h/gkrellm"; static void create_seti_tab(GtkWidget *tab_vbox) { GtkWidget *hbox; GtkWidget *label; GtkWidget *vbox; GtkWidget *tabs; GtkWidget *text; GtkWidget *scrolled; 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); /* File location tab */ vbox = create_tab(tabs, "File location"); seti_path_entry = gtk_entry_new_with_max_length(255); gtk_box_pack_start(GTK_BOX(vbox), seti_path_entry, FALSE, FALSE, 2); gtk_entry_set_text(GTK_ENTRY(seti_path_entry), seti_file_path); /* Info tab */ vbox = 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); gtk_text_insert(GTK_TEXT(text), NULL, NULL, NULL, seti_info_text, -1); gtk_text_set_editable(GTK_TEXT(text), FALSE); gtk_container_add(GTK_CONTAINER(scrolled), text); } /* * Saving config */ static void save_seti_config(FILE *f) { fprintf(f, "seti filename %s\n", seti_file_path); } /* * Loading config */ static void load_seti_config(gchar *arg) { gchar seti_config[64], item[256]; gint n; n = sscanf(arg, "%s %[^\n]", seti_config, item); if (n == 2) { if (GK.debug) printf("seti_config=%s item=<%s>\n", seti_config, item); if (strcmp(seti_config, "filename") == 0) seti_file_path = g_strdup(item); } } /* * Applying config. * This includes only updating seti_file_path variable. */ static void apply_seti_config() { gchar *s; s = gtk_entry_get_text(GTK_ENTRY(seti_path_entry)); if (strcmp(s, seti_file_path)) { seti_file_path = g_strdup(s); } } static Monitor plugin_mon = { "Seti", /* Name, for config tab. */ 0, /* Id, 0 if a plugin */ create_seti, /* The create function */ update_seti, /* The update function */ create_seti_tab, /* The config tab create function */ apply_seti_config, /* Apply the config function */ save_seti_config, /* Save user config */ load_seti_config, /* Load user config */ "seti", /* config keyword */ NULL, /* Undefined 2 */ NULL, /* Undefined 1 */ NULL, /* Undefined 0 */ MON_APM, /* Insert plugin before this monitor */ NULL, /* Handle if a plugin, filled in by GKrellM */ NULL /* path if a plugin, filled in by GKrellM */ }; Monitor * init_plugin() { seti_file_path = "/home/luser/setiathome/state.sah"; return &plugin_mon; }