1 /* GKrellM
2 |  Copyright (C) 1999-2019 Bill Wilson
3 |
4 |  Author:  Bill Wilson    billw@gkrellm.net
5 |  Latest versions might be found at:  http://gkrellm.net
6 |
7 |
8 |  GKrellM is free software: you can redistribute it and/or modify it
9 |  under the terms of the GNU General Public License as published by
10 |  the Free Software Foundation, either version 3 of the License, or
11 |  (at your option) any later version.
12 |
13 |  GKrellM is distributed in the hope that it will be useful, but WITHOUT
14 |  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 |  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 |  License for more details.
17 |
18 |  You should have received a copy of the GNU General Public License
19 |  along with this program. If not, see http://www.gnu.org/licenses/
20 |
21 |
22 |  Additional permission under GNU GPL version 3 section 7
23 |
24 |  If you modify this program, or any covered work, by linking or
25 |  combining it with the OpenSSL project's OpenSSL library (or a
26 |  modified version of that library), containing parts covered by
27 |  the terms of the OpenSSL or SSLeay licenses, you are granted
28 |  additional permission to convey the resulting work.
29 |  Corresponding Source for a non-source form of such a combination
30 |  shall include the source code for the parts of OpenSSL used as well
31 |  as that of the covered work.
32 */
33 
34 #include "gkrellm.h"
35 #include "gkrellm-private.h"
36 
37 #include <math.h>
38 
39 static GList	*gkrellm_alert_list,
40 				*alert_plugin_list;
41 
42 
43 static void
run_command(GkrellmAlert * alert,gchar * command)44 run_command(GkrellmAlert *alert, gchar *command)
45 	{
46 	gchar	cmd[1024];
47 
48 	if (!command || !*command)
49 		return;
50 	if (alert->cb_command_process)
51 		(*alert->cb_command_process)(alert, command, cmd, sizeof(cmd),
52 				alert->cb_command_process_data);
53 	else
54 		snprintf(cmd, sizeof(cmd), "%s", command);
55 	g_spawn_command_line_async(cmd, NULL);
56 	}
57 
58 void
gkrellm_render_default_alert_decal(GkrellmAlert * alert)59 gkrellm_render_default_alert_decal(GkrellmAlert *alert)
60 	{
61 	GkrellmPiximage	*im;
62 	GkrellmAlertdecal		*ad;
63 
64 	if (!alert)
65 		return;
66 	ad = &alert->ad;
67 	if (ad->w <= 0 || ad->h <= 0)
68 		return;
69 	if (alert->high.alarm_on || alert->low.alarm_on)
70 		gkrellm_get_decal_alarm_piximage(&im, &ad->nframes);
71 	else if (alert->high.warn_on || alert->low.warn_on)
72 		gkrellm_get_decal_warn_piximage(&im, &ad->nframes);
73 	else
74 		return;
75 	gkrellm_scale_piximage_to_pixmap(im, &ad->pixmap, &ad->mask, ad->w,
76 				ad->h * ad->nframes);
77 	}
78 
79 gboolean
gkrellm_alert_decal_visible(GkrellmAlert * alert)80 gkrellm_alert_decal_visible(GkrellmAlert *alert)
81 	{
82 	if (alert && alert->ad.decal)
83 		return TRUE;
84 	return FALSE;
85 	}
86 
87 static gboolean
create_alert_objects(GkrellmAlert * alert)88 create_alert_objects(GkrellmAlert *alert)
89 	{
90 	GkrellmAlertdecal		*ad;
91 //	GkrellmKrell			*k;
92 
93 	/* Whichever monitor created the alert that is being triggered:
94 	|  1) has set a panel pointer in the create and is done, so I will make
95 	|     here a default panel sized alert decal for him, or
96 	|  2) has not set a panel ptr, but will do so in the callback and then
97 	|     let me make the default alert, or
98 	|  3) has done one of the 2 above panel possibilities, and will also
99 	|     render a custom size/position for the alert decal and set the pixmap.
100 	|     For this case, the alert decal may be a render of the default decal
101 	|     image or may be a custom image from the monitor.  The work needed is
102 	|     setting ad x,y,w,h and nframes and rendering to ad->pixmap.
103 	*/
104 	if (alert->cb_trigger)
105 		(*alert->cb_trigger)(alert, alert->cb_trigger_data);
106 	if (!alert->panel)
107 		return FALSE;		/* Monitor may need trigger deferred */
108 	ad = &alert->ad;
109 	if (!alert->ad.pixmap /* && style is decal alert */)
110 		{
111 		ad->x = 0;
112 		ad->y = 0;
113 		ad->w = alert->panel->w;
114 		ad->h = alert->panel->h;
115 		gkrellm_render_default_alert_decal(alert);
116 		}
117 	/* Don't let create_decal append the decal, I want to insert it first so
118 	|  it will appear under all other panel decals.
119 	*/
120 	ad->decal = gkrellm_create_decal_pixmap(NULL, ad->pixmap, ad->mask,
121 				ad->nframes, NULL, ad->x, ad->y);
122 	gkrellm_insert_decal(alert->panel, ad->decal, FALSE /* prepend */);
123 
124 #if 0
125 	k = gkrellm_create_krell(NULL,
126 			gkrellm_krell_mini_piximage(), gkrellm_krell_mini_style());
127 	k->y0 = 5;
128 	k->full_scale = 100;
129 
130 	alert->ak.krell = k;
131 	gkrellm_insert_krell(alert->panel, k, TRUE);
132 #endif
133 	return TRUE;
134 	}
135 
136 static void
destroy_alert_objects(GkrellmAlert * alert)137 destroy_alert_objects(GkrellmAlert *alert)
138 	{
139 	gkrellm_destroy_decal(alert->ad.decal);
140 	if (alert->ad.pixmap)
141 		g_object_unref(G_OBJECT(alert->ad.pixmap));
142 	alert->ad.pixmap = NULL;
143 	alert->ad.mask = NULL;
144 	alert->ad.decal = NULL;
145 	gkrellm_destroy_krell(alert->ak.krell);
146 	alert->ak.krell = NULL;
147 	}
148 
149 static void
plugin_warn(GkrellmAlert * alert,gboolean state)150 plugin_warn(GkrellmAlert *alert, gboolean state)
151 	{
152 	GList					*list;
153 	GkrellmAlertPlugin		*gap;
154 	GkrellmAlertPluginLink	*apl;
155 
156 	for (list = alert->plugin_list; list; list = list->next)
157 		{
158 		apl = (GkrellmAlertPluginLink *) list->data;
159 		gap = apl->alert_plugin;
160 		if (MONITOR_ENABLED(gap->mon) && gap->warn_func)
161 			(*gap->warn_func)(alert, apl->data, state);
162 		}
163 	}
164 
165 static void
plugin_alarm(GkrellmAlert * alert,gboolean state)166 plugin_alarm(GkrellmAlert *alert, gboolean state)
167 	{
168 	GList					*list;
169 	GkrellmAlertPlugin		*gap;
170 	GkrellmAlertPluginLink	*apl;
171 
172 	for (list = alert->plugin_list; list; list = list->next)
173 		{
174 		apl = (GkrellmAlertPluginLink *) list->data;
175 		gap = apl->alert_plugin;
176 		if (MONITOR_ENABLED(gap->mon) && gap->alarm_func)
177 			(*gap->alarm_func)(alert, apl->data, state);
178 		}
179 	}
180 
181 static void
trigger_warn(GkrellmAlert * alert,GkrellmTrigger * trigger)182 trigger_warn(GkrellmAlert *alert, GkrellmTrigger *trigger)
183 	{
184 	if (!trigger->warn_on)
185 		{
186 		trigger->warn_on = TRUE;
187 		create_alert_objects(alert);
188 		gkrellm_alert_list = g_list_append(gkrellm_alert_list, alert);
189 		if (!alert->suppress_command)
190 			{
191 			run_command(alert, alert->warn_command);
192 			plugin_warn(alert, ON);
193 			}
194 		alert->suppress_command = FALSE;
195 		alert->warn_repeat = alert->warn_repeat_set;
196 		}
197 	}
198 
199 static void
stop_warn(GkrellmAlert * alert,GkrellmTrigger * trigger)200 stop_warn(GkrellmAlert *alert, GkrellmTrigger *trigger)
201 	{
202 	if (trigger->warn_on)
203 		{
204 		plugin_warn(alert, OFF);
205 		trigger->warn_on = FALSE;
206 		destroy_alert_objects(alert);
207 		gkrellm_alert_list = g_list_remove(gkrellm_alert_list, alert);
208 		alert->warn_repeat = 0;
209 		alert->suppress_command = FALSE;
210 		}
211 	}
212 
213 static void
trigger_alarm(GkrellmAlert * alert,GkrellmTrigger * trigger)214 trigger_alarm(GkrellmAlert *alert, GkrellmTrigger *trigger)
215 	{
216 	if (!trigger->alarm_on)
217 		{
218 		trigger->alarm_on = TRUE;
219 		trigger->warn_delay = 0;
220 		create_alert_objects(alert);
221 		gkrellm_alert_list = g_list_append(gkrellm_alert_list, alert);
222 		if (!alert->suppress_command)
223 			{
224 			run_command(alert, alert->alarm_command);
225 			plugin_alarm(alert, ON);
226 			}
227 		alert->suppress_command = FALSE;
228 		alert->alarm_repeat = alert->alarm_repeat_set;
229 		}
230 	}
231 
232 static void
stop_alarm(GkrellmAlert * alert,GkrellmTrigger * trigger)233 stop_alarm(GkrellmAlert *alert, GkrellmTrigger *trigger)
234 	{
235 	if (trigger->alarm_on)
236 		{
237 		plugin_alarm(alert, OFF);
238 		trigger->alarm_on = FALSE;
239 		destroy_alert_objects(alert);
240 		gkrellm_alert_list = g_list_remove(gkrellm_alert_list, alert);
241 		alert->alarm_repeat = 0;;
242 		alert->suppress_command = FALSE;
243 		}
244 	}
245 
246 void
gkrellm_freeze_alert(GkrellmAlert * alert)247 gkrellm_freeze_alert(GkrellmAlert *alert)
248 	{
249 	if (alert)
250 		alert->freeze = TRUE;
251 	}
252 
253 void
gkrellm_thaw_alert(GkrellmAlert * alert)254 gkrellm_thaw_alert(GkrellmAlert *alert)
255 	{
256 	if (alert)
257 		alert->freeze = FALSE;
258 	}
259 
260 static gboolean
check_high_alarm_limit(GkrellmAlert * alert,gfloat value)261 check_high_alarm_limit(GkrellmAlert *alert, gfloat value)
262 	{
263 	GkrellmTrigger	*trigger = &alert->high;
264 
265 	if (value < trigger->alarm_limit)
266 		{
267 		trigger->alarm_delay = alert->delay;
268 		return FALSE;
269 		}
270 	if (trigger->alarm_delay == 0)
271 		{
272 		if (trigger->warn_delay > 0)
273 			trigger->warn_delay -= 1;
274 		return TRUE;
275 		}
276 	trigger->alarm_delay -= 1;
277 	return FALSE;
278 	}
279 
280 static gboolean
check_high_warn_limit(GkrellmAlert * alert,gfloat value)281 check_high_warn_limit(GkrellmAlert *alert, gfloat value)
282 	{
283 	GkrellmTrigger	*trigger = &alert->high;
284 
285 	if (value < trigger->warn_limit)
286 		{
287 		trigger->warn_delay = alert->delay;
288 		return FALSE;
289 		}
290 	if (trigger->warn_delay == 0)
291 		return TRUE;
292 	trigger->warn_delay -= 1;
293 	return FALSE;
294 	}
295 
296 static gboolean
check_low_warn_limit(GkrellmAlert * alert,gfloat value)297 check_low_warn_limit(GkrellmAlert *alert, gfloat value)
298 	{
299 	GkrellmTrigger	*trigger = &alert->low;
300 
301 	if (value > trigger->warn_limit)
302 		{
303 		trigger->warn_delay = alert->delay;
304 		return FALSE;
305 		}
306 	if (trigger->warn_delay == 0)
307 		return TRUE;
308 	trigger->warn_delay -= 1;
309 	return FALSE;
310 	}
311 
312 static gboolean
check_low_alarm_limit(GkrellmAlert * alert,gfloat value)313 check_low_alarm_limit(GkrellmAlert *alert, gfloat value)
314 	{
315 	GkrellmTrigger	*trigger = &alert->low;
316 
317 	if (value > trigger->alarm_limit)
318 		{
319 		trigger->alarm_delay = alert->delay;
320 		return FALSE;
321 		}
322 	if (trigger->alarm_delay == 0)
323 		{
324 		if (trigger->warn_delay > 0)
325 			trigger->warn_delay -= 1;
326 		return TRUE;
327 		}
328 	trigger->alarm_delay -= 1;
329 	return FALSE;
330 	}
331 
332 void
gkrellm_check_alert(GkrellmAlert * alert,gfloat value)333 gkrellm_check_alert(GkrellmAlert *alert, gfloat value)
334 	{
335 	GList					*plist;
336 	GkrellmAlertPlugin		*gap;
337 	GkrellmAlertPluginLink	*apl;
338 
339 	if (!alert || !alert->activated || alert->freeze || !_GK.initialized)
340 		return;
341 
342 	if (alert->delay == 0 || GK.second_tick)
343 		{
344 		if (alert->check_low)
345 			{
346 			if (check_low_alarm_limit(alert, value))
347 				{
348 				stop_alarm(alert, &alert->high);
349 				stop_warn(alert, &alert->high);
350 				stop_warn(alert, &alert->low);
351 				trigger_alarm(alert, &alert->low);
352 				}
353 			else
354 				{
355 				stop_alarm(alert, &alert->low);
356 				if (check_low_warn_limit(alert, value))
357 					{
358 					stop_alarm(alert, &alert->high);
359 					stop_warn(alert, &alert->high);
360 					trigger_warn(alert, &alert->low);
361 					}
362 				else
363 					stop_warn(alert, &alert->low);
364 				}
365 			}
366 		if (alert->check_high)
367 			{
368 			if (check_high_alarm_limit(alert, value))
369 				{
370 				stop_warn(alert, &alert->high);
371 				stop_warn(alert, &alert->low);
372 				stop_alarm(alert, &alert->low);
373 				trigger_alarm(alert, &alert->high);
374 				}
375 			else
376 				{
377 				stop_alarm(alert, &alert->high);
378 				if (check_high_warn_limit(alert, value))
379 					{
380 					stop_warn(alert, &alert->low);
381 					stop_alarm(alert, &alert->low);
382 					trigger_warn(alert, &alert->high);
383 					}
384 				else
385 					stop_warn(alert, &alert->high);
386 				}
387 			}
388 		}
389 
390 	for (plist = alert->plugin_list; plist; plist = plist->next)
391 		{
392 		apl = (GkrellmAlertPluginLink *) plist->data;
393 		gap = apl->alert_plugin;
394 		if (MONITOR_ENABLED(gap->mon) && gap->check_func)
395 			(*gap->check_func)(alert, apl->data, value);
396 		}
397 	}
398 
399 void
gkrellm_alert_trigger_connect(GkrellmAlert * alert,void (* func)(),gpointer data)400 gkrellm_alert_trigger_connect(GkrellmAlert *alert, void (*func)(),
401 			gpointer data)
402 	{
403 	if (!alert)
404 		return;
405 	alert->cb_trigger = func;
406 	alert->cb_trigger_data = data;
407 	}
408 
409 void
gkrellm_alert_stop_connect(GkrellmAlert * alert,void (* func)(),gpointer data)410 gkrellm_alert_stop_connect(GkrellmAlert *alert, void (*func)(), gpointer data)
411 	{
412 	if (!alert)
413 		return;
414 	alert->cb_stop = func;
415 	alert->cb_stop_data = data;
416 	}
417 
418 static void
destroy_alert(GkrellmAlert * alert)419 destroy_alert(GkrellmAlert *alert)
420 	{
421 	GList					*plist, *list;
422 	GkrellmAlertPlugin		*gap;
423 	GkrellmAlertPluginLink	*apl;
424 	gpointer				data;
425 
426 	if (!alert)
427 		return;
428 	if (g_list_find(gkrellm_alert_list, alert))
429 		{
430 		gkrellm_alert_list = g_list_remove(gkrellm_alert_list, alert);
431 		destroy_alert_objects(alert);
432 		}
433 
434 	for (plist = alert_plugin_list; plist; plist = plist->next)
435 		{
436 		data = NULL;
437 		gap = (GkrellmAlertPlugin *) plist->data;
438 		for (list = alert->plugin_list; list; list = list->next)
439 			{
440 			apl = (GkrellmAlertPluginLink *) list->data;
441 			if (apl->alert_plugin == gap)
442 				{
443 				data = apl->data;
444 				break;
445 				}
446 			}
447 		if (MONITOR_ENABLED(gap->mon) && gap->destroy_func)
448 			(*gap->destroy_func)(alert, data);
449 		}
450 	gkrellm_free_glist_and_data(&alert->plugin_list);	/* should all be detached */
451 	g_free(alert->name);
452 	g_free(alert->unit_string);
453 	g_free(alert->alarm_command);
454 	g_free(alert->warn_command);
455 	g_free(alert->id_string);
456 	g_free(alert);
457 	}
458 
459 void
gkrellm_alert_destroy(GkrellmAlert ** ap)460 gkrellm_alert_destroy(GkrellmAlert **ap)
461 	{
462 	if (!ap || !*ap)
463 		return;
464 	gkrellm_alert_window_destroy(ap);
465 	destroy_alert(*ap);
466 	*ap = NULL;
467 	}
468 
469 GkrellmAlert *
gkrellm_alert_create(GkrellmPanel * p,gchar * name,gchar * unit_string,gboolean check_high,gboolean check_low,gboolean do_updates,gfloat max_high,gfloat min_low,gfloat step0,gfloat step1,gint digits)470 gkrellm_alert_create(GkrellmPanel *p, gchar *name, gchar *unit_string,
471 		gboolean check_high, gboolean check_low, gboolean do_updates,
472 		gfloat max_high, gfloat min_low,
473 		gfloat step0, gfloat step1, gint digits)
474 	{
475 	GkrellmAlert	*alert;
476 
477 	alert = g_new0(GkrellmAlert, 1);
478 	alert->panel = p;
479 	alert->name = g_strdup(name);
480 	alert->unit_string = g_strdup(unit_string);
481 	alert->check_high = check_high;
482 	alert->check_low = check_low;
483 	alert->do_panel_updates = do_updates;
484 	alert->max_high = max_high;
485 	alert->min_low = min_low;
486 	alert->step0 = step0;
487 	alert->step1 = step1;
488 	alert->digits = digits;
489 
490 	alert->alarm_command = g_strdup("");
491 	alert->warn_command = g_strdup("");
492 	alert->do_alarm_command = alert->do_warn_command = TRUE;
493 
494 	gkrellm_alert_set_triggers(alert, min_low, min_low, min_low, min_low);
495 	alert->activated = FALSE;
496 	alert->check_hardwired = FALSE;
497 
498 	return alert;
499 	}
500 
501   /* Set alarm trigger values for hardwired alarms which have no config
502   */
503 void
gkrellm_alert_set_triggers(GkrellmAlert * alert,gfloat high_alarm,gfloat high_warn,gfloat low_warn,gfloat low_alarm)504 gkrellm_alert_set_triggers(GkrellmAlert *alert,
505 				gfloat high_alarm, gfloat high_warn,
506 				gfloat low_warn, gfloat low_alarm)
507 	{
508 	if (alert->check_high)
509 		{
510 		alert->high.alarm_limit = high_alarm;
511 		alert->high.warn_limit = high_warn;
512 		}
513 	if (alert->check_low)
514 		{
515 		alert->low.warn_limit = low_warn;
516 		alert->low.alarm_limit = low_alarm;
517 		}
518 	alert->activated = TRUE;
519 	alert->check_hardwired = TRUE;
520 	}
521 
522 
523 void
gkrellm_alert_commands_config(GkrellmAlert * alert,gboolean alarm,gboolean warn)524 gkrellm_alert_commands_config(GkrellmAlert *alert,
525 						gboolean alarm, gboolean warn)
526 	{
527 	alert->do_alarm_command = alarm;
528 	alert->do_warn_command = warn;
529 	}
530 
531 void
gkrellm_alert_set_delay(GkrellmAlert * alert,gint delay)532 gkrellm_alert_set_delay(GkrellmAlert *alert, gint delay)
533 	{
534 	if (!alert)
535 		return;
536 	alert->delay = delay;
537 	alert->low.warn_delay = alert->low.alarm_delay = delay;
538 	alert->high.warn_delay = alert->high.alarm_delay = delay;
539 	}
540 
541 void
gkrellm_alert_delay_config(GkrellmAlert * alert,gint step,gint high,gint low)542 gkrellm_alert_delay_config(GkrellmAlert *alert, gint step,
543 			gint high, gint low)
544 	{
545 	if (!alert || step < 1 || high < step)
546 		return;
547 	low = (low / step) * step;
548 	high = (high / step) * step;
549 
550 	alert->delay_high = (gfloat) high;
551 	alert->delay_low = (gfloat) low;
552 	alert->delay_step = (gfloat) step;
553 	gkrellm_alert_set_delay(alert, low);
554 	}
555 
556 void
gkrellm_alert_dup(GkrellmAlert ** a_dst,GkrellmAlert * a_src)557 gkrellm_alert_dup(GkrellmAlert **a_dst, GkrellmAlert *a_src)
558 	{
559 	GkrellmAlert	*alert;
560 
561 	if (!a_dst || !a_src)
562 		return;
563 	if (*a_dst)
564 		(*a_dst)->plugin_list = NULL;	/* XXX fixme */
565 	gkrellm_alert_destroy(a_dst);
566 	alert = gkrellm_alert_create(a_src->panel, a_src->name,
567 				a_src->unit_string, a_src->check_high, a_src->check_low,
568 				a_src->do_panel_updates, a_src->max_high, a_src->min_low,
569 				a_src->step0, a_src->step1, a_src->digits);
570 	gkrellm_dup_string(&alert->alarm_command, a_src->alarm_command);
571 	gkrellm_dup_string(&alert->warn_command, a_src->warn_command);
572 	alert->warn_repeat_set = a_src->warn_repeat_set;
573 	alert->alarm_repeat_set = a_src->alarm_repeat_set;
574 	alert->low = a_src->low;
575 	alert->high = a_src->high;
576 	gkrellm_alert_set_delay(alert, a_src->delay);
577 	alert->plugin_list = a_src->plugin_list;	/* XXX fixme */
578 
579 	alert->activated = a_src->activated;
580 	*a_dst = alert;
581 	}
582 
583 static void
reset_alert(GkrellmAlert * alert,gboolean suppress)584 reset_alert(GkrellmAlert *alert, gboolean suppress)
585 	{
586 	GkrellmTrigger	*th = &alert->high,
587 					*tl = &alert->low;
588 
589 	if (   suppress
590 		&& (   ((th->alarm_on || tl->alarm_on) && alert->alarm_repeat_set == 0)
591 			|| ((th->warn_on || tl->warn_on) && alert->warn_repeat_set == 0)
592 		   )
593 	   )
594 		alert->suppress_command = TRUE;
595 	th->alarm_on = FALSE;
596 	th->warn_on = FALSE;
597 	tl->alarm_on = FALSE;
598 	tl->warn_on = FALSE;
599 	alert->alarm_repeat = 0;
600 	alert->warn_repeat = 0;
601 	destroy_alert_objects(alert);
602 	}
603 
604 void
gkrellm_reset_alert(GkrellmAlert * alert)605 gkrellm_reset_alert(GkrellmAlert *alert)
606 	{
607 	if (!alert)
608 		return;
609 	if (g_list_find(gkrellm_alert_list, alert))
610 		{
611 		reset_alert(alert, FALSE);
612 		gkrellm_alert_list = g_list_remove(gkrellm_alert_list, alert);
613 		}
614 	}
615 
616 void
gkrellm_reset_alert_soft(GkrellmAlert * alert)617 gkrellm_reset_alert_soft(GkrellmAlert *alert)
618 	{
619 	if (!alert)
620 		return;
621 	if (g_list_find(gkrellm_alert_list, alert))
622 		{
623 		reset_alert(alert, TRUE);
624 		gkrellm_alert_list = g_list_remove(gkrellm_alert_list, alert);
625 		}
626 	}
627 
628 void
gkrellm_reset_panel_alerts(GkrellmPanel * p)629 gkrellm_reset_panel_alerts(GkrellmPanel *p)
630 	{
631 	GList			*list;
632 	GkrellmAlert	*alert;
633 	gboolean		done = FALSE;
634 
635 	if (!p)
636 		return;
637 	while (!done)
638 		{
639 		done = TRUE;	/* Assume won't find any */
640 		for (list = gkrellm_alert_list; list; list = list->next)
641 			{
642 			alert = (GkrellmAlert *) list->data;
643 			if (alert->panel != p)
644 				continue;
645 			done = FALSE;
646 			reset_alert(alert, FALSE);
647 			gkrellm_alert_list = g_list_remove(gkrellm_alert_list, alert);
648 			alert->panel = NULL;
649 			alert->cb_trigger = NULL;
650 			alert->cb_trigger_data = NULL;
651 			alert->cb_stop = NULL;
652 			alert->cb_stop_data = NULL;
653 			break;
654 			}
655 		}
656 	}
657 
658   /* At theme changes, turn all alerts off so there won't be any alert decals
659   |  in monitor lists when they are destroyed.  The alerts should just get
660   |  retriggered.  Surely an alert going off is a good time to change themes.
661   */
662 void
gkrellm_alert_reset_all(void)663 gkrellm_alert_reset_all(void)
664 	{
665 	GList	*list;
666 
667 	for (list = gkrellm_alert_list; list; list = list->next)
668 		reset_alert((GkrellmAlert *) list->data, TRUE);
669 	g_list_free(gkrellm_alert_list);
670 	gkrellm_alert_list = NULL;
671 	}
672 
673 void
gkrellm_alert_update(void)674 gkrellm_alert_update(void)
675 	{
676 	GList					*list, *plist;
677 	GkrellmAlert			*alert;
678 	GkrellmAlertdecal		*ad;
679 	GkrellmAlertkrell		*ak;
680 	GkrellmAlertPlugin		*gap;
681 	GkrellmAlertPluginLink	*apl;
682 
683 	for (list = gkrellm_alert_list; list; list = list->next)
684 		{
685 		alert = (GkrellmAlert *) list->data;
686 		ad = &alert->ad;
687 		ak = &alert->ak;
688 		if (ak->krell)
689 			{
690 			ak->krell_position = (ak->krell_position + 2) % 100;
691 			gkrellm_update_krell(alert->panel, ak->krell, ak->krell_position);
692 			}
693 		if (ad->decal)
694 			{
695 			if (ad->frame <= 0)
696 				ad->dir = 1;
697 			else if (ad->frame >= ad->nframes - 1)
698 				ad->dir = 0;
699 			ad->frame += (ad->dir) ? 1 : -1;
700 			gkrellm_draw_decal_pixmap(alert->panel, ad->decal, ad->frame);
701 			}
702 		if (alert->do_panel_updates)
703 			gkrellm_draw_panel_layers(alert->panel);
704 		if (GK.second_tick)
705 			{
706 			if (alert->alarm_repeat > 0 && --alert->alarm_repeat == 0)
707 				{
708 				run_command(alert, alert->alarm_command);
709 				alert->alarm_repeat = alert->alarm_repeat_set;
710 				}
711 			if (alert->warn_repeat > 0 && --alert->warn_repeat == 0)
712 				{
713 				run_command(alert, alert->warn_command);
714 				alert->warn_repeat = alert->warn_repeat_set;
715 				}
716 			for (plist = alert->plugin_list; plist; plist = plist->next)
717 				{
718 				apl = (GkrellmAlertPluginLink *) plist->data;
719 				gap = apl->alert_plugin;
720 				if (MONITOR_ENABLED(gap->mon) && gap->update_func)
721 					(*gap->update_func)(alert, apl->data);
722 				}
723 			}
724 		}
725 	}
726 
727 gboolean
gkrellm_alert_is_activated(GkrellmAlert * alert)728 gkrellm_alert_is_activated(GkrellmAlert *alert)
729 	{
730 	if (alert)
731 		return alert->activated;
732 	return FALSE;
733 	}
734 
735 void
gkrellm_alert_get_alert_state(GkrellmAlert * alert,gboolean * alarm_state,gboolean * warn_state)736 gkrellm_alert_get_alert_state(GkrellmAlert *alert, gboolean *alarm_state,
737 				gboolean *warn_state)
738 	{
739 	if (!alert)
740 		return;
741 	if (warn_state)
742 		*warn_state = (alert->high.warn_on || alert->low.warn_on);
743 	if (alarm_state)
744 		*alarm_state = (alert->high.alarm_on || alert->low.alarm_on);
745 	}
746 
747 
748 /* ------------------------------------------------------------ */
749 /* Plugin interface to alerts. */
750 
751 GkrellmAlertPlugin *
gkrellm_alert_plugin_add(GkrellmMonitor * mon,gchar * name)752 gkrellm_alert_plugin_add(GkrellmMonitor *mon, gchar *name)
753 	{
754 	GkrellmAlertPlugin	*gap;
755 
756 	if (!mon || !name || !*name)
757 		return NULL;
758 	gap = g_new0(GkrellmAlertPlugin, 1);
759 	gap->mon = mon;
760 	gap->name = g_strdup(name);
761 	alert_plugin_list = g_list_append(alert_plugin_list, gap);
762 	return gap;
763 	}
764 
765 void
gkrellm_alert_plugin_alert_connect(GkrellmAlertPlugin * gap,void (* alarm_func)(),void (* warn_func)(),void (* update_func)(),void (* check_func)(),void (* destroy_func)())766 gkrellm_alert_plugin_alert_connect(GkrellmAlertPlugin *gap,
767 			void (*alarm_func)(), void (*warn_func)(),
768 			void (*update_func)(), void (*check_func)(),
769 			void (*destroy_func)())
770 	{
771 	gap->alarm_func = alarm_func;
772 	gap->warn_func = warn_func;
773 	gap->update_func = update_func;
774 	gap->check_func = check_func;
775 	gap->destroy_func = destroy_func;
776 	}
777 
778 void
gkrellm_alert_plugin_config_connect(GkrellmAlertPlugin * gap,gchar * tab_name,void (* config_create_func)(),void (* config_apply_func),void (* config_save_func)(),void (* config_load_func)())779 gkrellm_alert_plugin_config_connect(GkrellmAlertPlugin *gap, gchar *tab_name,
780 			void (*config_create_func)(), void (*config_apply_func),
781 			void (*config_save_func)(), void (*config_load_func)())
782 	{
783 	if (!gap)
784 		return;
785 	g_free(gap->tab_name);
786 	gap->tab_name = g_strdup(tab_name);
787 	gap->config_create_func = config_create_func;
788 	gap->config_apply_func = config_apply_func;
789 	gap->config_save_func = config_save_func;
790 	gap->config_load_func = config_load_func;
791 	}
792 
793   /* The id_string is so a plugin can get a unique config name for an alert.
794   */
795 gchar *
gkrellm_alert_plugin_config_get_id_string(GkrellmAlert * alert)796 gkrellm_alert_plugin_config_get_id_string(GkrellmAlert *alert)
797 	{
798 	if (alert)
799 		return alert->id_string;
800 	return NULL;
801 	}
802 
803 void
gkrellm_alert_plugin_alert_attach(GkrellmAlertPlugin * gap,GkrellmAlert * alert,gpointer data)804 gkrellm_alert_plugin_alert_attach(GkrellmAlertPlugin *gap,
805 			GkrellmAlert *alert, gpointer data)
806 	{
807 	GkrellmAlertPluginLink	*apl;
808 
809 	if (!gap || !alert)
810 		return;
811 	apl = g_new0(GkrellmAlertPluginLink, 1);
812 	apl->alert_plugin = gap;
813 	apl->data = data;
814 	alert->plugin_list = g_list_append(alert->plugin_list, apl);
815 	}
816 
817 void
gkrellm_alert_plugin_alert_detach(GkrellmAlertPlugin * gap,GkrellmAlert * alert)818 gkrellm_alert_plugin_alert_detach(GkrellmAlertPlugin *gap, GkrellmAlert *alert)
819 	{
820 	GList					*list;
821 	GkrellmAlertPluginLink	*apl;
822 
823 	if (!gap || !alert)
824 		return;
825 	for (list = alert->plugin_list; list; list = list->next)
826 		{
827 		apl = (GkrellmAlertPluginLink *) list->data;
828 		if (apl->alert_plugin == gap)
829 			{
830 			alert->plugin_list = g_list_remove(alert->plugin_list, apl);
831 			g_free(apl);
832 			break;
833 			}
834 		}
835 	}
836 
837 gpointer
gkrellm_alert_plugin_get_data(GkrellmAlertPlugin * gap,GkrellmAlert * alert)838 gkrellm_alert_plugin_get_data(GkrellmAlertPlugin *gap,GkrellmAlert *alert)
839 	{
840 	GList					*list;
841 	GkrellmAlertPluginLink	*apl;
842 
843 	if (!gap || !alert)
844 		return NULL;
845 	for (list = alert->plugin_list; list; list = list->next)
846 		{
847 		apl = (GkrellmAlertPluginLink *) list->data;
848 		if (apl->alert_plugin == gap)
849 			return apl->data;
850 		}
851 	return NULL;
852 	}
853 
854 void
gkrellm_alert_plugin_command_process(GkrellmAlert * alert,gchar * src,gchar * dst,gint dst_size)855 gkrellm_alert_plugin_command_process(GkrellmAlert *alert, gchar *src,
856 			gchar *dst, gint dst_size)
857 	{
858 	if (alert && alert->cb_command_process)
859 		(*alert->cb_command_process)(alert, src, dst, dst_size,
860 				alert->cb_command_process_data);
861 	else
862 		snprintf(dst, dst_size, "%s", src);
863 	}
864 
865 
866 /* ------------------------------------------------------------ */
867 void
gkrellm_alert_command_process_connect(GkrellmAlert * alert,void (* func)(),gpointer data)868 gkrellm_alert_command_process_connect(GkrellmAlert *alert, void (*func)(),
869 						gpointer data)
870 	{
871 	if (!alert)
872 		return;
873 	alert->cb_command_process = func;
874 	alert->cb_command_process_data = data;
875 	}
876 
877 void
gkrellm_alert_config_connect(GkrellmAlert * alert,void (* func)(),gpointer data)878 gkrellm_alert_config_connect(GkrellmAlert *alert, void (*func)(),gpointer data)
879 	{
880 	if (!alert)
881 		return;
882 	alert->cb_config = func;
883 	alert->cb_config_data = data;
884 	}
885 
886 void
gkrellm_alert_config_create_connect(GkrellmAlert * alert,void (* func)(),gpointer data)887 gkrellm_alert_config_create_connect(GkrellmAlert *alert,
888 						void (*func)(), gpointer data)
889 	{
890 	if (!alert)
891 		return;
892 	alert->cb_config_create = func;
893 	alert->cb_config_create_data = data;
894 	}
895 
896 static void
alert_delete(GtkWidget * widget,GkrellmAlert ** ap)897 alert_delete(GtkWidget *widget, GkrellmAlert **ap)
898 	{
899 	GkrellmAlert			*alert;
900 
901 	if (!ap)
902 		return;
903 	alert = *ap;
904 	alert->activated = FALSE;
905 	alert->config_closing = TRUE;
906 	if (alert->cb_config)
907 		(*alert->cb_config)(alert, alert->cb_config_data);
908 	if (alert->config_window)
909 		gtk_widget_destroy(alert->config_window);
910 	destroy_alert(alert);
911 	*ap = NULL;
912 	}
913 
914 static void
alert_close(GtkWidget * widget,GkrellmAlert ** ap)915 alert_close(GtkWidget *widget, GkrellmAlert **ap)
916 	{
917 	GkrellmAlert	*alert;
918 
919 	if (!ap)
920 		return;
921 	alert = *ap;
922 	if (!alert->activated)
923 		alert_delete(NULL, ap);
924 	else if (alert->config_window)
925 		{
926 		gtk_widget_destroy(alert->config_window);
927 		alert->config_window = NULL;
928 		alert->delete_button = NULL;
929 		}
930 	}
931 
932 void
gkrellm_alert_window_destroy(GkrellmAlert ** ap)933 gkrellm_alert_window_destroy(GkrellmAlert **ap)
934 	{
935 	alert_close(NULL, ap);
936 	}
937 
938 static gint
alert_config_window_delete_event(GtkWidget * widget,GdkEvent * ev,GkrellmAlert ** ap)939 alert_config_window_delete_event(GtkWidget *widget, GdkEvent *ev,
940 		GkrellmAlert **ap)
941 	{
942 	alert_close(widget, ap);
943 	return FALSE;
944 	}
945 
946 static void
alert_apply(GtkWidget * widget,GkrellmAlert ** ap)947 alert_apply(GtkWidget *widget, GkrellmAlert **ap)
948 	{
949 	GList					*plist, *list;
950 	GkrellmAlert			*alert;
951 	GkrellmAlertPlugin		*gap;
952 	GkrellmAlertPluginLink	*apl;
953 	gpointer				data;
954 	gchar					*s;
955 	GtkSpinButton			*spin;
956 	gint					n;
957 
958 	alert = *ap;
959 	if (!alert->activated && !alert->config_modified)
960 		return;
961 	if (alert->high.alarm_limit_spin_button)
962 		{
963 		spin = GTK_SPIN_BUTTON(alert->high.alarm_limit_spin_button);
964 		alert->high.alarm_limit = gtk_spin_button_get_value(spin);
965 		spin = GTK_SPIN_BUTTON(alert->high.warn_limit_spin_button);
966 		alert->high.warn_limit = gtk_spin_button_get_value(spin);
967 		}
968 
969 	if (alert->low.alarm_limit_spin_button)
970 		{
971 		spin = GTK_SPIN_BUTTON(alert->low.alarm_limit_spin_button);
972 		alert->low.alarm_limit = gtk_spin_button_get_value(spin);
973 		spin = GTK_SPIN_BUTTON(alert->low.warn_limit_spin_button);
974 		alert->low.warn_limit = gtk_spin_button_get_value(spin);
975 		}
976 
977 	if (alert->high.alarm_limit == 0.0 && alert->low.alarm_limit == 0.0)
978 		return;
979 	if (alert->alarm_command_entry)
980 		{
981 		spin = GTK_SPIN_BUTTON(alert->alarm_repeat_spin_button);
982 		alert->alarm_repeat_set = gtk_spin_button_get_value_as_int(spin);
983 
984 		s = gkrellm_gtk_entry_get_text(&alert->alarm_command_entry);
985 		gkrellm_dup_string(&alert->alarm_command, s);
986 		if (!*s)
987 			alert->alarm_repeat_set = 0;
988 		if (alert->high.alarm_on || alert->low.alarm_on)
989 			alert->alarm_repeat = alert->alarm_repeat_set;
990 		}
991 	if (alert->warn_command_entry)
992 		{
993 		spin = GTK_SPIN_BUTTON(alert->warn_repeat_spin_button);
994 		alert->warn_repeat_set = gtk_spin_button_get_value_as_int(spin);
995 
996 		s = gkrellm_gtk_entry_get_text(&alert->warn_command_entry);
997 		gkrellm_dup_string(&alert->warn_command, s);
998 		if (!*s)
999 			alert->warn_repeat_set = 0;
1000 		if (alert->high.warn_on || alert->low.warn_on)
1001 			alert->warn_repeat = alert->warn_repeat_set;
1002 		}
1003 	if (alert->delay_spin_button)
1004 		{
1005 		spin = GTK_SPIN_BUTTON(alert->delay_spin_button);
1006 		n = gtk_spin_button_get_value_as_int(spin);
1007 		gkrellm_alert_set_delay(alert, n / alert->delay_step);
1008 		}
1009 	alert->activated = TRUE;
1010 
1011 	for (plist = alert_plugin_list; plist; plist = plist->next)
1012 		{
1013 		data = NULL;
1014 		gap = (GkrellmAlertPlugin *) plist->data;
1015 		for (list = alert->plugin_list; list; list = list->next)
1016 			{
1017 			apl = (GkrellmAlertPluginLink *) list->data;
1018 			if (apl->alert_plugin == gap)
1019 				{
1020 				data = apl->data;
1021 				break;
1022 				}
1023 			}
1024 		if (MONITOR_ENABLED(gap->mon) && gap->config_apply_func)
1025 			(*gap->config_apply_func)(alert, data, alert->config_closing);
1026 		}
1027 
1028 	gtk_widget_set_sensitive(alert->delete_button, alert->activated);
1029 	gtk_widget_set_sensitive(alert->icon_box, alert->activated);
1030 	if (alert->cb_config)
1031 		(*alert->cb_config)(alert, alert->cb_config_data);
1032 	gkrellm_config_modified();
1033 	}
1034 
1035 static void
alert_ok(GtkWidget * widget,GkrellmAlert ** ap)1036 alert_ok(GtkWidget *widget, GkrellmAlert **ap)
1037 	{
1038 	(*ap)->config_closing = TRUE;
1039 	alert_apply(NULL, ap);
1040 	alert_close(NULL, ap);
1041 	}
1042 
1043 static void
cb_delay_spin_changed(GtkAdjustment * adjustment,GkrellmAlert * alert)1044 cb_delay_spin_changed(GtkAdjustment *adjustment, GkrellmAlert *alert)
1045 	{
1046 	GtkSpinButton	*spin;
1047 	gint			delay;
1048 
1049 	spin = GTK_SPIN_BUTTON(alert->delay_spin_button);
1050 	delay = gtk_spin_button_get_value_as_int(spin);
1051 	if ((delay % alert->delay_step) != 0)
1052 		{
1053 		delay = delay / alert->delay_step * alert->delay_step;
1054 		gtk_spin_button_set_value(spin, delay);
1055 		}
1056 	alert->config_modified = TRUE;
1057 	gtk_widget_set_sensitive(alert->icon_box, TRUE);
1058 	}
1059 
1060 static void
cb_high_alarm_spin_changed(GtkAdjustment * adjustment,GkrellmAlert * alert)1061 cb_high_alarm_spin_changed(GtkAdjustment *adjustment, GkrellmAlert *alert)
1062 	{
1063 	GtkSpinButton	*spin;
1064 	gfloat			alarm, warn;
1065 
1066 	spin = GTK_SPIN_BUTTON(alert->high.alarm_limit_spin_button);
1067 	alarm = gtk_spin_button_get_value(spin);
1068 	spin = GTK_SPIN_BUTTON(alert->high.warn_limit_spin_button);
1069 	warn = gtk_spin_button_get_value(spin);
1070 	if (alarm < warn)
1071 		gtk_spin_button_set_value(spin, alarm);
1072 	alert->config_modified = TRUE;
1073 	gtk_widget_set_sensitive(alert->icon_box, TRUE);
1074 	}
1075 
1076 static void
cb_high_warn_spin_changed(GtkWidget * adjustment,GkrellmAlert * alert)1077 cb_high_warn_spin_changed(GtkWidget *adjustment, GkrellmAlert *alert)
1078 	{
1079 	GtkSpinButton	*spin;
1080 	gfloat			alarm, warn, low_warn;
1081 
1082 	spin = GTK_SPIN_BUTTON(alert->high.warn_limit_spin_button);
1083 	warn = gtk_spin_button_get_value(spin);
1084 	spin = GTK_SPIN_BUTTON(alert->high.alarm_limit_spin_button);
1085 	alarm = gtk_spin_button_get_value(spin);
1086 	if (alarm < warn)
1087 		gtk_spin_button_set_value(spin, warn);
1088 	if (alert->check_low)
1089 		{
1090 		spin = GTK_SPIN_BUTTON(alert->low.warn_limit_spin_button);
1091 		low_warn = gtk_spin_button_get_value(spin);
1092 		if (low_warn > warn)
1093 			gtk_spin_button_set_value(spin, warn);
1094 		}
1095 	alert->config_modified = TRUE;
1096 	gtk_widget_set_sensitive(alert->icon_box, TRUE);
1097 	}
1098 
1099 static void
cb_low_warn_spin_changed(GtkWidget * adjustment,GkrellmAlert * alert)1100 cb_low_warn_spin_changed(GtkWidget *adjustment, GkrellmAlert *alert)
1101 	{
1102 	GtkSpinButton	*spin;
1103 	gfloat			alarm, warn, high_warn;
1104 
1105 	spin = GTK_SPIN_BUTTON(alert->low.warn_limit_spin_button);
1106 	warn = gtk_spin_button_get_value(spin);
1107 	spin = GTK_SPIN_BUTTON(alert->low.alarm_limit_spin_button);
1108 	alarm = gtk_spin_button_get_value(spin);
1109 	if (alarm > warn)
1110 		gtk_spin_button_set_value(spin, warn);
1111 	if (alert->check_high)
1112 		{
1113 		spin = GTK_SPIN_BUTTON(alert->high.warn_limit_spin_button);
1114 		high_warn = gtk_spin_button_get_value(spin);
1115 		if (high_warn < warn)
1116 			gtk_spin_button_set_value(spin, warn);
1117 		}
1118 	alert->config_modified = TRUE;
1119 	gtk_widget_set_sensitive(alert->icon_box, TRUE);
1120 	}
1121 
1122 static void
cb_low_alarm_spin_changed(GtkWidget * adjustment,GkrellmAlert * alert)1123 cb_low_alarm_spin_changed(GtkWidget *adjustment, GkrellmAlert *alert)
1124 	{
1125 	GtkSpinButton	*spin;
1126 	gfloat			alarm, warn;
1127 
1128 	spin = GTK_SPIN_BUTTON(alert->low.alarm_limit_spin_button);
1129 	alarm = gtk_spin_button_get_value(spin);
1130 	spin = GTK_SPIN_BUTTON(alert->low.warn_limit_spin_button);
1131 	warn = gtk_spin_button_get_value(spin);
1132 	if (alarm > warn)
1133 		gtk_spin_button_set_value(spin, alarm);
1134 	alert->config_modified = TRUE;
1135 	gtk_widget_set_sensitive(alert->icon_box, TRUE);
1136 	}
1137 
1138 void
gkrellm_alert_config_window(GkrellmAlert ** ap)1139 gkrellm_alert_config_window(GkrellmAlert **ap)
1140 	{
1141 	GtkWidget				*tabs;
1142 	GtkWidget				*main_vbox, *tab_vbox, *vbox, *vbox1 = NULL;
1143 	GtkWidget				*hbox, *hbox1, *image;
1144 	GtkWidget				*table = NULL;
1145 	GtkWidget				*button;
1146 	GtkWidget				*label;
1147 	GtkWidget				*separator;
1148 	GList					*plist, *list;
1149 	GkrellmAlert			*alert;
1150 	GkrellmAlertPlugin		*gap;
1151 	GkrellmAlertPluginLink	*apl;
1152 	gpointer				data;
1153 	gchar					*title;
1154 	gint					w, n_tabs = 1;
1155 
1156 	if (!ap || !*ap)
1157 		return;
1158 	alert = *ap;
1159 	if (!alert->config_window)
1160 		{
1161 		alert->config_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1162 		g_signal_connect(G_OBJECT(alert->config_window), "delete_event",
1163 				G_CALLBACK(alert_config_window_delete_event), ap);
1164 		gtk_window_set_title(GTK_WINDOW(alert->config_window),
1165 				_("GKrellM Set Alerts"));
1166 		gtk_window_set_wmclass(GTK_WINDOW(alert->config_window),
1167 				"Gkrellm_conf", "Gkrellm");
1168 
1169 		gtk_container_set_border_width(GTK_CONTAINER(alert->config_window), 4);
1170 		main_vbox = gtk_vbox_new(FALSE, 0);
1171 		gtk_container_add(GTK_CONTAINER(alert->config_window), main_vbox);
1172 
1173 		tabs = gtk_notebook_new();
1174 		gtk_box_pack_start(GTK_BOX(main_vbox), tabs, TRUE, TRUE, 0);
1175 		gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs), GTK_POS_TOP);
1176 
1177 		tab_vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Alerts"));
1178 
1179 		if (alert->name && alert->unit_string)
1180 			title = g_strdup_printf("%s - %s",
1181 						alert->name, alert->unit_string);
1182 		else if (alert->name)
1183 			title = g_strdup_printf("%s", alert->name);
1184 		else
1185 			title = g_strdup_printf("%s", alert->unit_string);
1186 
1187 		vbox = gkrellm_gtk_framed_vbox(tab_vbox, title, 4, FALSE, 4, 3);
1188 		g_free(title);
1189 
1190 		hbox = gtk_hbox_new(FALSE, 0);
1191 		gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
1192 		w = 70;
1193 		if (alert->max_high > 100000)
1194 			w += log(alert->max_high / 100000) * 5;
1195 
1196 		alert->high.alarm_limit_spin_button = NULL;
1197 		alert->high.warn_limit_spin_button = NULL;
1198 		if (alert->check_high  && !alert->check_hardwired)
1199 			{
1200 			vbox1 = gkrellm_gtk_framed_vbox(hbox, _("High Limits"),
1201 						2, FALSE, 2,2);
1202 			gkrellm_gtk_spin_button(vbox1,
1203 					&alert->high.alarm_limit_spin_button,
1204 					alert->high.alarm_limit, alert->min_low, alert->max_high,
1205 					alert->step0, alert->step1,
1206 					alert->digits, w, cb_high_alarm_spin_changed, alert, FALSE,
1207 					_("High alarm limit"));
1208 
1209 			gkrellm_gtk_spin_button(vbox1, &alert->high.warn_limit_spin_button,
1210 					alert->high.warn_limit, alert->min_low, alert->max_high,
1211 					alert->step0, alert->step1,
1212 					alert->digits, w, cb_high_warn_spin_changed, alert, FALSE,
1213 					_("High warn limit"));
1214 			}
1215 
1216 		alert->low.alarm_limit_spin_button = NULL;
1217 		alert->low.warn_limit_spin_button = NULL;
1218 		if (alert->check_low && !alert->check_hardwired)
1219 			{
1220 			vbox1 = gkrellm_gtk_framed_vbox_end(hbox, _("Low Limits"),
1221 					2, FALSE, 2, 2);
1222 			gkrellm_gtk_spin_button(vbox1, &alert->low.warn_limit_spin_button,
1223 					alert->low.warn_limit, alert->min_low, alert->max_high,
1224 					alert->step0, alert->step1,
1225 					alert->digits, w, cb_low_warn_spin_changed, alert, FALSE,
1226 					_("Low warn limit"));
1227 			gkrellm_gtk_spin_button(vbox1, &alert->low.alarm_limit_spin_button,
1228 					alert->low.alarm_limit, alert->min_low, alert->max_high,
1229 					alert->step0, alert->step1,
1230 					alert->digits, w, cb_low_alarm_spin_changed, alert, FALSE,
1231 					_("Low alarm limit"));
1232 			}
1233 		if (alert->delay_step > 0)
1234 			{
1235 			vbox1 = gkrellm_gtk_framed_vbox(vbox, NULL, 2, FALSE, 2, 2);
1236 			gkrellm_gtk_spin_button(vbox1, &alert->delay_spin_button,
1237 					alert->delay * alert->delay_step,
1238 					alert->delay_low, alert->delay_high,
1239 					alert->delay_step, alert->delay_step,
1240 					0, 70, cb_delay_spin_changed, alert, FALSE,
1241 					_("Seconds limit conditions must exist to have an alert"));
1242 			}
1243 		if (alert->cb_config_create)
1244 			{
1245 			vbox1 = gkrellm_gtk_framed_vbox(vbox, NULL, 2, FALSE, 2, 2);
1246 			(*alert->cb_config_create)(alert, vbox1,
1247 						alert->cb_config_create_data);
1248 			}
1249 
1250 		if (alert->do_alarm_command || alert->do_warn_command)
1251 			{
1252 			vbox1 = gkrellm_gtk_framed_vbox(vbox,
1253 					_("Commands - with repeat intervals in seconds"),
1254 					2, FALSE, 2, 2);
1255 			table = gtk_table_new(3 /* across */, 3 /* down */, FALSE);
1256 			gtk_table_set_col_spacings(GTK_TABLE(table), 4);
1257 			gtk_box_pack_start(GTK_BOX(vbox1), table, FALSE, FALSE, 0);
1258 			}
1259 
1260 		alert->alarm_command_entry = alert->alarm_repeat_spin_button = NULL;
1261 		if (alert->do_alarm_command)
1262 			{
1263 			label = gtk_label_new(_("Alarm command:"));
1264 			gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1265 			gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 0, 1);
1266 			alert->alarm_command_entry = gtk_entry_new();
1267 			gtk_entry_set_max_length(GTK_ENTRY(alert->alarm_command_entry),
1268 					255);
1269 			gtk_table_attach_defaults(GTK_TABLE(table),
1270 					alert->alarm_command_entry, 1, 2, 0, 1);
1271 			gtk_entry_set_text(GTK_ENTRY(alert->alarm_command_entry),
1272 					alert->alarm_command);
1273 			gkrellm_gtk_spin_button(NULL, &alert->alarm_repeat_spin_button,
1274 					alert->alarm_repeat_set, 0, 1000,
1275 					1, 10, 0, 60, NULL, NULL, FALSE, NULL);
1276 			gtk_table_attach_defaults(GTK_TABLE(table),
1277 					alert->alarm_repeat_spin_button, 2, 3, 0, 1);
1278 			}
1279 
1280 		alert->warn_command_entry = alert->warn_repeat_spin_button = NULL;
1281 		if (alert->do_warn_command)
1282 			{
1283 			label = gtk_label_new(_("Warn command:"));
1284 			gtk_misc_set_alignment(GTK_MISC(label), 1.0, 0.5);
1285 			gtk_table_attach_defaults(GTK_TABLE(table), label, 0, 1, 1, 2);
1286 			alert->warn_command_entry = gtk_entry_new();
1287 			gtk_entry_set_max_length(GTK_ENTRY(alert->warn_command_entry),
1288 					255);
1289 			gtk_table_attach_defaults(GTK_TABLE(table),
1290 					alert->warn_command_entry, 1, 2, 1, 2);
1291 			gtk_entry_set_text(GTK_ENTRY(alert->warn_command_entry),
1292 					alert->warn_command);
1293 			gtk_widget_set_size_request(alert->warn_command_entry, 300, -1);
1294 			gkrellm_gtk_spin_button(NULL, &alert->warn_repeat_spin_button,
1295 					alert->warn_repeat_set, 0, 1000,
1296 					1, 10, 0, 60, NULL, NULL, FALSE, NULL);
1297 			gtk_table_attach_defaults(GTK_TABLE(table),
1298 					alert->warn_repeat_spin_button, 2, 3, 1, 2);
1299 			}
1300 
1301 		if (alert->do_alarm_command || alert->do_warn_command)
1302 			{
1303 			separator = gtk_hseparator_new();
1304 			gtk_box_pack_start(GTK_BOX(vbox1), separator, FALSE, FALSE, 4);
1305 
1306 			label = gtk_label_new(
1307 		   _("A repeat of zero seconds executes the command once per alert."));
1308 			gtk_misc_set_alignment(GTK_MISC(label), 0.0, 0.5);
1309 			gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
1310 			gtk_box_pack_start(GTK_BOX(vbox1), label, FALSE, FALSE, 0);
1311 			}
1312 
1313 		for (plist = alert_plugin_list; plist; plist = plist->next)
1314 			{
1315 			data = NULL;
1316 			gap = (GkrellmAlertPlugin *) plist->data;
1317 			for (list = alert->plugin_list; list; list = list->next)
1318 				{
1319 				apl = (GkrellmAlertPluginLink *) list->data;
1320 				if (apl->alert_plugin == gap)
1321 					{
1322 					data = apl->data;
1323 					break;
1324 					}
1325 				}
1326 			if (MONITOR_ENABLED(gap->mon) && gap->config_create_func)
1327 				{
1328 				tab_vbox = gkrellm_gtk_framed_notebook_page(tabs,
1329 							gap->tab_name);
1330 				(*gap->config_create_func)(tab_vbox, alert, data);
1331 				++n_tabs;
1332 				}
1333 			}
1334 
1335 		if (n_tabs == 1)
1336 			gtk_notebook_set_show_tabs(GTK_NOTEBOOK(tabs), FALSE);
1337 
1338 		alert->icon_box = gtk_event_box_new();
1339 		hbox1 = gtk_hbox_new(FALSE, 0);
1340 		gtk_box_pack_start(GTK_BOX(main_vbox), hbox1, FALSE, FALSE, 0);
1341 		gtk_box_pack_start(GTK_BOX(hbox1), alert->icon_box, TRUE, FALSE, 0);
1342 		image = gtk_image_new_from_pixbuf(gkrellm_alert_pixbuf());
1343 		gtk_container_add(GTK_CONTAINER(alert->icon_box), image);
1344 		gtk_widget_set_sensitive(alert->icon_box, alert->activated);
1345 
1346 		hbox = gtk_hbutton_box_new();
1347 		gtk_button_box_set_layout(GTK_BUTTON_BOX(hbox), GTK_BUTTONBOX_END);
1348 		gtk_box_set_spacing(GTK_BOX(hbox), 5);
1349 		gtk_box_pack_end(GTK_BOX(hbox1), hbox, FALSE, FALSE, 0);
1350 
1351 		alert->delete_button = gtk_button_new_from_stock(GTK_STOCK_DELETE);
1352 		GTK_WIDGET_SET_FLAGS(alert->delete_button, GTK_CAN_DEFAULT);
1353 		g_signal_connect(G_OBJECT(alert->delete_button), "clicked",
1354 				G_CALLBACK(alert_delete), ap);
1355 		gtk_box_pack_start(GTK_BOX(hbox), alert->delete_button, TRUE, TRUE, 0);
1356 		gtk_widget_set_sensitive(alert->delete_button, alert->activated);
1357 
1358 		button = gtk_button_new_from_stock(GTK_STOCK_APPLY);
1359 		GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1360 		g_signal_connect(G_OBJECT(button), "clicked",
1361 				G_CALLBACK(alert_apply), ap);
1362 		gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
1363 
1364 		button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
1365 		GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1366 		g_signal_connect(G_OBJECT(button), "clicked",
1367 				G_CALLBACK(alert_close), ap);
1368 		gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
1369 
1370 		button = gtk_button_new_from_stock(GTK_STOCK_OK);
1371 		GTK_WIDGET_SET_FLAGS(button, GTK_CAN_DEFAULT);
1372 		g_signal_connect(G_OBJECT(button), "clicked",
1373 				G_CALLBACK(alert_ok), ap);
1374 		gtk_box_pack_start(GTK_BOX(hbox), button, TRUE, TRUE, 0);
1375 		gtk_widget_grab_default(button);
1376 
1377 		gtk_widget_show_all(alert->config_window);
1378 		}
1379 	else
1380 		gtk_window_present(GTK_WINDOW(alert->config_window));
1381 	alert->config_closing = FALSE;
1382 	}
1383 
1384 void
gkrellm_save_alertconfig(FILE * f,GkrellmAlert * alert,gchar * mon_keyword,gchar * name)1385 gkrellm_save_alertconfig(FILE *f, GkrellmAlert *alert,
1386 			gchar *mon_keyword, gchar *name)
1387 	{
1388 	GList					*list;
1389 	GkrellmAlertPlugin		*gap;
1390 	GkrellmAlertPluginLink	*apl;
1391 	gchar					*s, *p;
1392 
1393 	if (!f || !alert || !mon_keyword)
1394 		return;
1395 	if (name)
1396 		s = g_strdup_printf("%s %s %s ", mon_keyword,
1397 				GKRELLM_ALERTCONFIG_KEYWORD, name);
1398 	else
1399 		s = g_strdup_printf("%s %s ", mon_keyword,GKRELLM_ALERTCONFIG_KEYWORD);
1400 
1401 	if (alert->alarm_command && *alert->alarm_command)
1402 		fprintf(f, "%s alarm_command %s\n", s, alert->alarm_command);
1403 	if (alert->warn_command && *alert->warn_command)
1404 		fprintf(f, "%s warn_command %s\n", s, alert->warn_command);
1405 	fprintf(f, "%s values %d %d %d %d\n", s, alert->do_panel_updates,
1406 			alert->check_high, alert->check_low, alert->check_hardwired);
1407 	fprintf(f, "%s repeat %d %d\n", s, alert->alarm_repeat_set,
1408 			alert->warn_repeat_set);
1409 
1410 	/* 2.1.15: scale saved float values to avoid decimal points in the config
1411 	|  because of locale breakage if decimal point changes '.' <-> ',"
1412 	*/
1413 	fprintf(f, "%s limits %.0f %.0f %.0f %.0f\n", s,
1414 				alert->high.alarm_limit * GKRELLM_FLOAT_FACTOR,
1415 				alert->high.warn_limit  * GKRELLM_FLOAT_FACTOR,
1416 				alert->low.warn_limit   * GKRELLM_FLOAT_FACTOR,
1417 				alert->low.alarm_limit  * GKRELLM_FLOAT_FACTOR);
1418 	if (alert->delay_step > 0)
1419 		fprintf(f, "%s delay %d %d %d %d\n", s, alert->delay,
1420 					alert->delay_high, alert->delay_low, alert->delay_step);
1421 
1422 	/* name can be quoted, but the id_string should not have embedded quotes.
1423 	|  id_string is so a plugin can get a unique config name for an alert
1424 	*/
1425 	g_free(alert->id_string);
1426 	p = name;
1427 	if (p && *p == '"')
1428 		++p;
1429 	alert->id_string = g_strconcat(mon_keyword, p ? "-" : NULL, p, NULL);
1430 	if ((p = strrchr(alert->id_string, '"')) != NULL)
1431 		*p = '\0';
1432 	for (p = alert->id_string; *p; ++p)
1433 		if (*p == '/' || *p == ' ')
1434 			*p = '-';
1435 	fprintf(f, "%s id_string %s\n", s, alert->id_string);
1436 
1437 	for (list = alert->plugin_list; list; list = list->next)
1438 		{
1439 		apl = (GkrellmAlertPluginLink *) list->data;
1440 		gap = apl->alert_plugin;
1441 		if (MONITOR_ENABLED(gap->mon) && gap->config_save_func)
1442 			{
1443 			p = g_strconcat(s, "plugin ", gap->name, NULL);
1444 			(*gap->config_save_func)(alert, apl->data, f, p, alert->id_string);
1445 			g_free(p);
1446 			}
1447 		}
1448 	g_free(s);
1449 	}
1450 
1451 void
gkrellm_load_alertconfig(GkrellmAlert ** ap,gchar * config_line)1452 gkrellm_load_alertconfig(GkrellmAlert **ap, gchar *config_line)
1453 	{
1454 	GList					*list;
1455 	GkrellmAlert 			*alert;
1456 	GkrellmAlertPlugin		*gap;
1457 	gchar					config[32], item[CFG_BUFSIZE];
1458 	gchar					name[64], item1[CFG_BUFSIZE];
1459 	gint					n;
1460 
1461 	if (!ap || !config_line)
1462 		return;
1463 	if (!*ap)
1464 		*ap = g_new0(GkrellmAlert, 1);
1465 	alert = *ap;
1466 
1467 	n = sscanf(config_line, "%31s %[^\n]", config, item);
1468 	if (n != 2)
1469 		return;
1470 
1471 	if (!strcmp(config, "alarm_command"))
1472 		gkrellm_dup_string(&alert->alarm_command, item);
1473 	else if (!strcmp(config, "warn_command"))
1474 		gkrellm_dup_string(&alert->warn_command, item);
1475 	else if (!strcmp(config, "values"))
1476 		sscanf(item, "%d %d %d %d", &alert->do_panel_updates,
1477 			&alert->check_high, &alert->check_low, &alert->check_hardwired);
1478 	else if (!strcmp(config, "delay"))
1479 		{
1480 		sscanf(item, "%d %d %d %d", &n,
1481 				&alert->delay_high, &alert->delay_low, &alert->delay_step);
1482 		gkrellm_alert_set_delay(alert, n);
1483 		}
1484 	else if (!strcmp(config, "repeat"))
1485 		sscanf(item, "%d %d", &alert->alarm_repeat_set,
1486 				&alert->warn_repeat_set);
1487 	else if (!strcmp(config, "limits"))
1488 		{
1489 		sscanf(item, "%f %f %f %f",
1490 				&alert->high.alarm_limit, &alert->high.warn_limit,
1491 				&alert->low.warn_limit, &alert->low.alarm_limit);
1492 
1493 		alert->high.alarm_limit /= _GK.float_factor;
1494 		alert->high.warn_limit  /= _GK.float_factor;
1495 		alert->low.warn_limit   /= _GK.float_factor;
1496 		alert->low.alarm_limit  /= _GK.float_factor;
1497 		}
1498 	else if (!strcmp(config, "id_string"))
1499 		{
1500 		gkrellm_dup_string(&alert->id_string, item);
1501 		for (list = alert_plugin_list; list; list = list->next)
1502 			{
1503 			gap = (GkrellmAlertPlugin *) list->data;
1504 			if (MONITOR_ENABLED(gap->mon) && gap->config_load_func)
1505 				(*gap->config_load_func)(alert, "id_string", alert->id_string);
1506 			}
1507 		}
1508 	else if (!strcmp(config, "plugin"))
1509 		{
1510 		if (sscanf(item, "%63s %[^\n]", name, item1) == 2)
1511 			{
1512 			for (list = alert_plugin_list; list; list = list->next)
1513 				{
1514 				gap = (GkrellmAlertPlugin *) list->data;
1515 				if (!strcmp(name, gap->name))
1516 					{
1517 					if (MONITOR_ENABLED(gap->mon) && gap->config_load_func)
1518 						(*gap->config_load_func)(alert,
1519 									item1, alert->id_string);
1520 					break;
1521 					}
1522 				}
1523 			}
1524 		}
1525 	alert->activated = TRUE;
1526 	}
1527 
1528 
1529 /* ------------------------------------------------------------------- */
1530 /* gdk-pixbuf-csource --static --raw alert_inline.png */
1531 
1532 /* GdkPixbuf RGBA C-Source image dump 1-byte-run-length-encoded */
1533 
1534 /*
1535 | pixdata = new GdkPixbuf.Pixdata({
1536 |    magic
1537 |    length
1538 |    pixdata_type
1539 |    rowstride
1540 |    width
1541 |    height
1542 |    pixel_data
1543 */
1544 
1545 /* GdkPixbuf RGBA C-Source image dump */
1546 
1547 static const guint8 alert_inline[] =
1548 { ""
1549   /* Pixbuf magic (0x47646b50) */
1550   "GdkP"
1551   /* length: header (24) + pixel_data (1296) */
1552   "\0\0\5("
1553   /* pixdata_type (0x1010002) */
1554   "\1\1\0\2"
1555   /* rowstride (72) */
1556   "\0\0\0H"
1557   /* width (18) */
1558   "\0\0\0\22"
1559   /* height (18) */
1560   "\0\0\0\22"
1561   /* pixel_data: */
1562   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1563   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1564   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\204}{\377B89\377\20"
1565   "\24\20\377\10\2\10\377\0\2\0\377\30\24\20\3779<9\377\214\212\204\377"
1566   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1567   "\0\0e`T\37732*\377\202]@\377\251eF\377\267g\77\377\265cF\377\243eG\377"
1568   "\202VG\37773$\377io`\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1569   "\0\0\0\0\0\0PVG\377a<*\377\257^\77\377\310\211q\377\333\262\241\377\222"
1570   "\202t\377\311\254\234\377\333\262\233\377\310\211q\377\257^\77\377Z="
1571   "+\377\\bM\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0cfS\377Z=+\377\257"
1572   "^\77\377\320\234\203\377\333\270\241\377\252\217}\377\31\25\23\3772*"
1573   "%\377\342\274\251\377\333\270\241\377\320\234\203\377\257^\77\377Z=+"
1574   "\377|~k\377\0\0\0\0\0\0\0\0\0\0\0\0\204\206{\37773$\377\251_\77\377\301"
1575   "\202b\377\325\253\222\377\341\255\233\377aNE\377\222tb\377\0\0\0\377"
1576   "\310\232\211\377\333\257\233\377\325\253\222\377\302{h\377\251Z\77\377"
1577   "73$\377\0\0\0\0\0\0\0\0\0\0\0\0JAB\377xQ1\377\257[\77\377\320\234\203"
1578   "\377\325\234\203\377\333\236\205\3770#\35\377\333\236\205\377\30\21\17"
1579   "\377aF;\377\325\234\203\377\325\234\203\377\310\222u\377\257[\77\377"
1580   "tJ1\377kik\377\0\0\0\0\0\0\0\0\20\24\20\377\235[G\377\257[\77\377\317"
1581   "\212p\377\325\215u\377vOA\377vOA\377\325\215u\377vM>\377\0\0\0\377\325"
1582   "\213q\377\317\212p\377\317\213v\377\260T8\377\235[G\377)$)\377\0\0\0"
1583   "\0\0\0\0\0\0\2\0\377\251Z\77\377\267X\77\377\310q\\\377\310{c\377.\32"
1584   "\25\377\270lW\377\316z\\\377sA6\377\0\0\0\377sA6\377\317vb\377\301mV"
1585   "\377\257Q\77\377\245R8\377\10\2\10\377\0\0\0\0\0\0\0\0\0\2\0\377\251"
1586   "S\77\377\260T8\377\277N9\377\226M9\377,\25\21\377\205@4\377\205@4\377"
1587   "\200B4\377,\25\21\377+\26\20\377\277N9\377\270K9\377\252M8\377\237N8"
1588   "\377\10\2\10\377\0\0\0\0\0\0\0\0\30\24\30\377\230Y@\377\252S8\377\267"
1589   "R\77\377T)\34\377\200>.\377\300]F\377\307[F\377\300]F\377\200<.\377\0"
1590   "\0\0\377\221J<\377\260L8\377\245J8\377\230VG\377!(!\377\0\0\0\0\0\0\0"
1591   "\0""9<1\377xO@\377\245J8\377\227D1\377\0\0\0\377\266S8\377\302Q\77\377"
1592   "\274S\77\377\274S\77\377\274S\77\377\0\0\0\377N\37\31\377\252F8\377\236"
1593   "F2\377~N@\377cic\377\0\0\0\0\0\0\0\0\234\216\224\37773$\377\237G8\377"
1594   "\22\10\6\377\0\0\0\377N\40\26\377\242\77""1\377\257I2\377\266G8\377N"
1595   "\40\26\377\0\0\0\377\0\0\0\377F\37\26\377\231D9\37773$\377\0\0\0\0\0"
1596   "\0\0\0\0\0\0\0\0\0\0\0ii`\377T3#\377\231E2\377\237G8\377\252F8\377\251"
1597   "B2\377\251B2\377\251B2\377\252F8\377\236@2\377\231@2\377\231E2\377N6"
1598   "#\377{\204q\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0baY\377T3#\377"
1599   "\223D2\377\231E2\377\236@2\377\236@2\377\237<6\377\231E2\377\231@2\377"
1600   "\223@2\377T3#\377ii`\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1601   "\0\0\0\0\0\0t}j\377-4#\377~N@\377\216K9\377\223@2\377\223@2\377\222K"
1602   "@\377xO@\37773$\377{\204q\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1603   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0kik\377!(!\377\10\2\10\377\0"
1604   "\2\0\377)$)\377kik\377\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1605   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1606   "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
1607   "\0\0\0\0\0"};
1608 
1609 
1610 static GdkPixbuf	*alert_pixbuf;
1611 
1612 GdkPixbuf *
gkrellm_alert_pixbuf(void)1613 gkrellm_alert_pixbuf(void)
1614 	{
1615 	guint8		*data = (guint8 *) alert_inline;
1616 	guint		width, height, stride;
1617 	gpointer	pixels;
1618 
1619 	if (!alert_pixbuf)
1620 		{
1621 //		alert_pixbuf = gdk_pixbuf_new_from_inline(-1, alert_inline,
1622 //						FALSE, NULL);
1623 		stride = big_endian_uint(data + 12);
1624 		width  = big_endian_uint(data + 16);
1625 		height = big_endian_uint(data + 20);
1626 
1627 		pixels = g_memdup((gconstpointer)(data + 24), height * stride);
1628 
1629 		alert_pixbuf = gdk_pixbuf_new_from_data(pixels,
1630 				GDK_COLORSPACE_RGB, TRUE, 8, width, height, stride,
1631 				(GdkPixbufDestroyNotify) g_free, pixels);
1632 		}
1633 	return alert_pixbuf;
1634 	}
1635