1 /*
2   gkrellflynn.c
3 
4   author: Henryk Richter
5 
6   last update: Tue May 7 2002
7 
8   purpose: just an addon toy for gkrellm
9 
10   changelog:
11   0.5 - port to GKrellm 2.0 (thanks to Bill Nalen)
12       - port to Win32 (thanks to Bill Nalen)
13       - kept the code downwards compatible
14 
15   0.4 - port to GKrellm 1.2.x
16 
17   0.3 - stops /proc/stat parsing after the first found cpu line,
18         shows better results on SMP machines
19 
20   0.2 - minor cleanups, about box
21 
22   0.1 - initial version
23 
24 */
25 #ifndef WIN32
26 
27 /* see makefile */
28 #ifdef GKRELLM2
29 #include <gkrellm2/gkrellm.h>
30 #else  /* GKRELLM2 */
31 #include <gkrellm/gkrellm.h>
32 #endif /* GKRELLM2 */
33 
34 #include <sys/time.h>
35 #include <sys/wait.h>
36 
37 #else /* WIN32 */
38 
39 #include <src/gkrellm.h>
40 #include <src/win32-plugin.h>
41 
42 #endif /* WIN32 */
43 
44 
45 #include <stdlib.h>
46 
47 #define FLYNN_MAJOR_VERSION 0
48 #define FLYNN_MINOR_VERSION 5
49 
50 #include "flynn.picture_alpha_big.xpm"
51 #define STYLE_NAME "flynn"
52 
53 #define HEIGHT		74
54 #define IMAGE_WIDTH	48
55 #define IMAGE_HEIGHT	64
56 #define IMAGE_COUNT	27
57 
58 /* 3 different directions to look */
59 #define F_LOOKSTATES	3
60 /* 2 extra states (strength, grin) */
61 #define F_EXTRASTATE1   3
62 #define F_EXTRASTATE2   4
63 /* 5 torture variants per state */
64 #define F_TORTURES	5
65 
66 #define GRIN_TIME	3
67 
68 #if GKRELLM_VERSION_MAJOR < 2
69 static Panel		*panel;
70 static Decal		*flynn = NULL;
71 #else
72 static GkrellmPanel	*panel;
73 static GkrellmDecal	*flynn = NULL;
74 static GkrellmMonitor	*monitor;
75 #endif
76 
77 static gint		style_id;
78 static GdkPixmap	*flynn_image = NULL;
79 static GdkBitmap 	*flynn_mask = NULL;
80 static int              dogrin = 0;
81 
82 /* config stuff */
83 #define PLUGIN_CONFIG_KEYWORD "FlynnA"
84 static GtkWidget *nice_checkbutton;
85 static int nice_checkdisable = 0;
86 static GtkWidget *term_checkbutton;
87 static int term_checkdisable = 0;
88 
89 static GtkWidget *commandline_entry;
90 static gchar command_line[256];
91 static GtkWidget *terminal_entry;
92 static gchar terminal_command_line[256];
93 static int child_started = 0;
94 
flynn_apply_config(void)95 void flynn_apply_config(void)
96 {
97 	nice_checkdisable = GTK_TOGGLE_BUTTON(nice_checkbutton)->active;
98 	term_checkdisable = GTK_TOGGLE_BUTTON(term_checkbutton)->active;
99 	strncpy(command_line, gtk_entry_get_text(GTK_ENTRY(commandline_entry)), 255);
100 	strncpy(terminal_command_line, gtk_entry_get_text(GTK_ENTRY(terminal_entry)), 255);
101 }
102 
flynn_save_config(FILE * f)103 static void flynn_save_config(FILE *f)
104 {
105 	fprintf(f, "%s exclude_nice %d\n", PLUGIN_CONFIG_KEYWORD,nice_checkdisable);
106 	fprintf(f, "%s command_line %s\n", PLUGIN_CONFIG_KEYWORD,command_line);
107 	fprintf(f, "%s run_in_term %d\n", PLUGIN_CONFIG_KEYWORD,term_checkdisable);
108 	fprintf(f, "%s terminal_command %s\n", PLUGIN_CONFIG_KEYWORD,terminal_command_line);
109 }
110 
flynn_load_config(gchar * arg)111 static void flynn_load_config (gchar *arg)
112 {
113     gchar config[64], item[256];
114     gint n;
115 
116     n = sscanf(arg, "%s %[^\n]", config, item);
117     if (n != 2)
118         return;
119 
120         if (strcmp(config, "exclude_nice") == 0 )
121 		sscanf(item, "%d\n", &nice_checkdisable);
122 	if (strcmp(config, "command_line") == 0 )
123 		strncpy(command_line,item,255);
124 	if (strcmp(config, "run_in_term") == 0 )
125 		sscanf(item, "%d\n", &term_checkdisable);
126 	if (strcmp(config, "terminal_command") == 0 )
127 		strncpy(terminal_command_line,item,255);
128 }
129 
130 /* get current cpu usage */
getcpu(void)131 int getcpu( void )
132 {
133 	float scale_factor = 1;
134 #if 0
135         FILE * fin;
136         char buffer[256];
137         char tokens[4] = " \t\n";
138 #endif
139 
140         static long last_user = 0;
141         static long last_nice = 0;
142         static long last_sys = 0;
143         static long last_idle = 0;
144 
145         long user=0, nice=0, sys=0, idle=0, total=0;
146         long d_user, d_nice, d_sys, d_idle;
147         float cpu_use;
148         float percent;
149 
150 	gkrellm_cpu_stats(0, &user, &nice, &sys, &idle);
151 
152 #if 0
153         if ( (fin = fopen("/proc/stat", "r")) == NULL ) {
154                 return(0);
155         }
156 
157         while ( fgets(buffer, 256, fin) ) {
158                 if ( strstr(buffer,"cpu") != NULL ) {
159                         strtok(buffer,tokens);
160                         user = atol(strtok(NULL,tokens));
161                         nice = atol(strtok(NULL,tokens));
162                         sys =  atol(strtok(NULL,tokens));
163                         idle = atol(strtok(NULL,tokens));
164 
165 			break;
166                 }
167         }
168 
169         fclose (fin);
170 #endif
171 
172         d_user = user - last_user;
173         d_nice = nice - last_nice;
174         d_sys  = sys  - last_sys;
175         d_idle = idle - last_idle;
176 
177         last_user = user;
178         last_nice = nice;
179         last_sys  = sys;
180         last_idle = idle;
181 
182         total = d_user + d_sys + d_nice + d_idle;
183 	if( nice_checkdisable == 1 )
184 		d_idle += d_nice;
185 
186         if ( total < 1 )
187                 total = 1.0;
188 
189         cpu_use = 1.0 - ( (float)  d_idle  / (float) total );
190 #if 0
191         printf("   CPU (/proc/stat): %5.2f  ", cpu_use);
192         printf(" (jiffies: user:%ld nice:%ld system:%ld idle:%ld total:%ld)\n",
193                         d_user, d_nice, d_sys, d_idle, total  );
194 #endif
195         percent = cpu_use / scale_factor;
196         if ( percent > .999999 )
197                 percent = .999999;
198 
199         return ( (int)(percent*100) );
200 }
201 
202 
update_plugin()203 static void update_plugin()
204 {
205         static int image_number = 0;
206 	static int flynn_look = 0;
207 	int dir;
208 	int percent;
209 
210 	/* first check looking direction */
211 #if GKRELLM_VERSION_MAJOR < 2
212 	if( GK.second_tick )
213 #else
214 	if( gkrellm_ticks()->second_tick )
215 #endif
216 	{
217 	   /* catch exiting childs if any (no semaphore used, gkrellm is synchronous) */
218 #ifndef WIN32
219 	   if( child_started > 0 )
220 	   {
221 		if( waitpid( -1, NULL, WNOHANG ) > 0 )
222 			child_started--;
223 	   }
224 #endif
225 	   if( dogrin > 0 )
226 	   {
227 		dogrin--;
228 		flynn_look = F_EXTRASTATE2;
229 	   }
230 	   else
231 	   {
232 		dir = (int)( (float)F_LOOKSTATES * (float)rand() / (RAND_MAX+1.0));
233 		switch( dir )
234 		{
235 			case 0:
236 				break;
237 			case 1:
238 				flynn_look++;
239 				break;
240 			case 2:
241 				flynn_look--;
242 				break;
243 			default:
244 				break;
245 		}
246 		if( flynn_look < 0 ) flynn_look = 0;
247 		if( flynn_look >= F_LOOKSTATES ) flynn_look = F_LOOKSTATES-1;
248 	   }
249 		percent = getcpu();
250 
251 		image_number = flynn_look * F_TORTURES + (F_TORTURES * percent / 100);
252 
253 		/*printf("%d\n",image_number);*/
254 	}
255 
256 
257 	/* draw determined frame */
258 	gkrellm_draw_decal_pixmap(panel, flynn, image_number);
259 #if GKRELLM_VERSION_MAJOR < 2
260 	gkrellm_draw_layers(panel);
261 #else
262 	gkrellm_draw_panel_layers(panel);
263 #endif
264 }
265 
panel_expose_event(GtkWidget * widget,GdkEventExpose * ev)266 static gint panel_expose_event(GtkWidget *widget, GdkEventExpose *ev)
267 {
268 	gdk_draw_pixmap(widget->window,
269 	                widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
270 	                panel->pixmap, ev->area.x, ev->area.y, ev->area.x, ev->area.y,
271 	                ev->area.width, ev->area.height);
272     return FALSE;
273 }
274 
panel_click_event(GtkWidget * widget,GdkEventExpose * ev)275 static gint panel_click_event(GtkWidget *widget, GdkEventExpose *ev)
276 {
277 	gchar* argv[32];
278 	gchar localcmd[256];
279 	int i;
280 	pid_t pid;
281 
282 	dogrin = GRIN_TIME;
283 
284 	/* check for command line */
285 	if (strlen(command_line) == 0) return FALSE;
286 
287 	child_started++;
288 
289 	/* forkint status */
290 	pid = fork();
291 	if (pid == 0)
292 	{
293 		/* this is the child process - setup */
294 		i=0;
295 		memset(localcmd,0,256);
296 		/* check for "run in terminal" option */
297 		if (term_checkdisable)
298 		{
299 			strcpy(localcmd,terminal_command_line);
300 		}
301 		/* create command line */
302 		strncat(localcmd,command_line,255);
303 		/* separate command line into argument array */
304 		argv[i] = strtok(localcmd," ");
305 		while (argv[i++] != NULL)
306 		{
307 			argv[i] = strtok(NULL," ");
308 		}
309 		/* exec child process */
310 		/* execv(argv[0],argv); */
311 		execvp(argv[0],argv);
312 		_exit(EXIT_FAILURE);
313 	}
314 
315     return FALSE;
316 }
317 
load_images()318 static void load_images()
319 {
320 #if GKRELLM_VERSION_MAJOR < 2
321 	static GdkImlibImage  *image = NULL;
322 
323 	gkrellm_load_image(NULL, flynn_xpm, &image, NULL);
324 	gkrellm_render_to_pixmap(image, &flynn_image, &flynn_mask, 0, 0);
325 #else
326 	static GkrellmPiximage *image = NULL;
327 	gkrellm_load_piximage(NULL, flynn_xpm, &image, NULL);
328 	gkrellm_scale_piximage_to_pixmap(image, &flynn_image, &flynn_mask, 0, 0);
329 #endif
330 }
331 
create_plugin(GtkWidget * vbox,gint first_create)332 static void create_plugin(GtkWidget *vbox, gint first_create)
333 {
334 #if GKRELLM_VERSION_MAJOR < 2
335 	Style		*style = NULL;
336 #else
337 	GkrellmStyle	*style = NULL;
338 #endif
339 
340 	int            image_x_offset;
341 	int            image_y_offset;
342 
343 	load_images();
344 
345 	if (first_create)
346 	{
347 		panel = gkrellm_panel_new0();
348 	}
349 	else
350 		gkrellm_destroy_decal_list(panel);
351 
352 	style = gkrellm_meter_style(style_id);
353 
354 	image_x_offset = (gkrellm_chart_width() - IMAGE_WIDTH) / 2;
355 	image_y_offset = (HEIGHT - IMAGE_HEIGHT) / 2;
356 
357 	flynn = gkrellm_create_decal_pixmap(panel, flynn_image, flynn_mask,
358 	                                    IMAGE_COUNT,
359 	                                    style, image_x_offset, image_y_offset);
360 
361 	panel->textstyle = gkrellm_meter_textstyle(style_id);
362 	panel->label->h_panel = HEIGHT;
363 
364 #if GKRELLM_VERSION_MAJOR < 2
365 	gkrellm_create_panel(vbox, panel, gkrellm_bg_meter_image(style_id));
366 	gkrellm_monitor_height_adjust(panel->h);
367 #else
368 	gkrellm_panel_configure(panel, "", style);
369 	gkrellm_panel_create(vbox, monitor, panel);
370 #endif
371 
372 	if (first_create)
373 	{
374 		gtk_signal_connect(GTK_OBJECT(panel->drawing_area),
375 		                   "expose_event", (GtkSignalFunc) panel_expose_event,
376 		                   NULL);
377 		gtk_signal_connect(GTK_OBJECT(panel->drawing_area),
378 		                   "button_press_event", (GtkSignalFunc) panel_click_event,
379 		                   NULL);
380 	}
381 
382 	gkrellm_draw_decal_pixmap(panel, flynn, 1 );
383 
384 #if GKRELLM_VERSION_MAJOR < 2
385 	gkrellm_draw_layers(panel);
386 #else
387 	gkrellm_draw_panel_layers(panel);
388 #endif
389 
390 
391 
392 }
393 
flynn_create_plugin_tab(GtkWidget * tab_vbox)394 static void flynn_create_plugin_tab(GtkWidget *tab_vbox)
395 {
396 	GtkWidget           *tabs;
397 	GtkWidget	*vbox,*vbox1,*vbox2;
398 	GtkWidget       *frame, *commandframe;
399 
400 	tabs = gtk_notebook_new();
401 	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs), GTK_POS_TOP);
402 	gtk_box_pack_start(GTK_BOX(tab_vbox), tabs, TRUE, TRUE, 0);
403 
404 	/* Config TAB */
405 	{
406 		{
407 #if GKRELLM_VERSION_MAJOR < 2
408 		 vbox = gkrellm_create_tab(tabs, _("Config"));
409 #else
410 		 vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Config"));
411 #endif
412 
413 		 frame = gtk_frame_new(_("CPU time Calculations"));
414         	 gtk_box_pack_start(GTK_BOX(vbox), frame, TRUE, TRUE, 5);
415         	 vbox1 = gtk_vbox_new (FALSE, 2);
416         	 gtk_container_add(GTK_CONTAINER(frame), vbox1);
417 
418 		 commandframe = gtk_frame_new(_("Command Line (program executed on click)"));
419 		 gtk_box_pack_start(GTK_BOX(vbox), commandframe, TRUE, TRUE, 5);
420 		 vbox2 = gtk_vbox_new (FALSE, 2);
421 		 gtk_container_add(GTK_CONTAINER(commandframe), vbox2);
422 
423 #if GKRELLM_VERSION_MAJOR < 2
424         	 gkrellm_check_button(vbox1, &nice_checkbutton, nice_checkdisable, FALSE, 0,
425                         	      "Exclude Nice time from calculations");
426 #else
427 		 {
428 		  gchar *label = _("Exclude Nice time from calculations");
429         	  gkrellm_gtk_check_button_connected(vbox1, &nice_checkbutton, nice_checkdisable, FALSE, 0,0,
430 			 flynn_apply_config,
431 			 NULL,
432 			 label);
433 		 }
434 #endif
435 		}
436 
437 		/* Set up command line text box */
438 		commandline_entry = gtk_entry_new();
439         	gtk_entry_set_text(GTK_ENTRY(commandline_entry),command_line);
440         	gtk_box_pack_start (GTK_BOX(vbox2), commandline_entry, FALSE, TRUE, 0);
441         	g_signal_connect(G_OBJECT(commandline_entry),"changed",
442                         	 G_CALLBACK(flynn_apply_config),NULL);
443 
444         	/* Set up run in terminal checkbox */
445 #if GKRELLM_VERSION_MAJOR < 2
446         	 gkrellm_check_button(vbox2, &term_checkbutton, term_checkdisable, FALSE, 0,
447                         	      "Run in Terminal");
448 #else
449 		 {
450 		  gchar *label = _("Run in Terminal");
451         	  gkrellm_gtk_check_button_connected(vbox2, &term_checkbutton, term_checkdisable, FALSE, 0,0,
452 			flynn_apply_config,
453 			NULL,
454 			label);
455 		 }
456 #endif
457 		terminal_entry = gtk_entry_new();
458         	gtk_entry_set_text(GTK_ENTRY(terminal_entry),terminal_command_line);
459         	gtk_box_pack_start (GTK_BOX(vbox2), terminal_entry, FALSE, TRUE, 0);
460 	       	g_signal_connect(G_OBJECT(terminal_entry),"changed",
461                         	 G_CALLBACK(flynn_apply_config),NULL);
462 
463 
464 
465 	}
466 
467 	/* ABOUT TAB */
468         {
469             gchar *plugin_about_text;
470             GtkWidget *label, *text;
471 
472             plugin_about_text = g_strdup_printf(
473                 "GKrellFlynn %d.%d\n"
474                 "GKrellM Load Meter Plugin\n\n"
475                 "(C) 2001 Henryk Richter\n"
476                 "<buggs@comlabien.net>\n"
477 		"http://horus.comlabien.net/flynn\n\n"
478                 "Released under the GNU General Public License",
479                 FLYNN_MAJOR_VERSION, FLYNN_MINOR_VERSION);
480 
481             text = gtk_label_new(plugin_about_text);
482             label = gtk_label_new("About");
483             gtk_notebook_append_page(GTK_NOTEBOOK(tabs),text,label);
484             g_free(plugin_about_text);
485         }
486 
487 }
488 
489 #if GKRELLM_VERSION_MAJOR < 2
490  static Monitor  plugin_mon  =
491 #else
492  static GkrellmMonitor  plugin_mon  =
493 #endif
494          {
495          "Flynn",                 /* Name, for config tab.        */
496          0,                       /* Id,  0 if a plugin           */
497          create_plugin,           /* The create_plugin() function */
498          update_plugin,           /* The update_plugin() function */
499          flynn_create_plugin_tab, /* The create_plugin_tab() config function */
500          flynn_apply_config,      /* The apply_plugin_config() function      */
501 
502          flynn_save_config,       /* The save_plugin_config() function  */
503          flynn_load_config,       /* The load_plugin_config() function  */
504          PLUGIN_CONFIG_KEYWORD,                /* config keyword                     */
505 
506          NULL,           /* Undefined 2  */
507          NULL,           /* Undefined 1  */
508          NULL,           /* Undefined 0  */
509 
510          MON_INSERT_AFTER|MON_CLOCK, /* Insert plugin before this monitor.       */
511          NULL,           /* Handle if a plugin, filled in by GKrellM */
512          NULL            /* path if a plugin, filled in by GKrellM   */
513          };
514 
515 #if GKRELLM_VERSION_MAJOR < 2
init_plugin(void)516 Monitor * init_plugin(void)
517 #else
518 #ifdef WIN32
519 __declspec(dllexport) GkrellmMonitor *
520 gkrellm_init_plugin(win32_plugin_callbacks* calls)
521 #else
522 GkrellmMonitor *
523 gkrellm_init_plugin()
524 #endif
525 #endif
526 {
527 #if GKRELLM_VERSION_MAJOR < 2
528 	style_id = gkrellm_add_meter_style(&plugin_mon, STYLE_NAME);
529 #else
530 #if defined(WIN32)
531 	callbacks = calls;
532 	pwin32GK = calls->GK;
533 #endif
534 	style_id = gkrellm_add_meter_style(&plugin_mon, STYLE_NAME);
535 	monitor = &plugin_mon;
536 #endif
537 
538 	/* set defaults */
539 	strcpy( terminal_command_line, "/usr/bin/gnome-terminal -x " );
540 
541 	return &plugin_mon;
542 }
543 
544