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 #include "gkrellm-sysdeps.h"
37 
38 #include "pixmaps/mem/krell_buffers.xpm"
39 #include "pixmaps/mem/krell_cache.xpm"
40 
41   /* The mem monitor has two extra krells which can be themed.
42   |  So, the theme "mem" subdir can have:
43   |      bg_panel.png
44   |      krell.png
45   |      krell_buffers.png		# an extension image, defaults to included xpm
46   |      krell_cache.png		# an extension image, defaults to included xpm
47   |
48   |  The gkrellmrc can have theme extension variables for these extra krells:
49   |      set_integer mem_krell_buffers_yoff n
50   |      set_integer mem_krell_buffers_depth n
51   |      set_integer mem_krell_buffers_x_hot n
52   |      set_integer mem_krell_cache_yoff n
53   |      set_integer mem_krell_cache_depth n
54   |      set_integer mem_krell_cache_x_hot n
55   */
56 
57 #define	MIN_GRID_RES		20
58 #define	MAX_GRID_RES		100000
59 #define DEFAULT_GRID_RES	1000
60 
61 #define DEFAULT_SWAP_CHART_HEIGHT 20
62 
63 #define	DEFAULT_FORMAT	_("$t - $f free")
64 
65 #define MEG(x)	((gulong)(((x) + (1 << 19)) >> 20))
66 
67 typedef struct
68 	{
69 	GkrellmPanel *panel;
70 	GkrellmKrell *krell_used,	/* Meter styled, shows fraction used	*/
71 				*krell_delta,	/* Chart styled, for page in/out deltas */
72 				*krell_buffers,
73 				*krell_cache;
74 	gchar		*label,
75 				*data_format,	/* Format string for scrolling text		*/
76 				*data_format_shadow; /* shadow format for gdk_draw compat */
77 	gint		style_id;
78 	gint		x_label;
79 	GkrellmDecal *decal_label;
80 	gboolean	label_is_data,
81 				restore_label,	/* Helper to know when to toggle data fmt off*/
82 				mouse_entered,
83 				all_krells;
84 	gint		enabled;
85 	GkrellmLauncher	launch;
86 
87 	GkrellmAlert *alert;
88 
89 	guint64		total,		/* Total memory or swap in system */
90 				used,		/* Amount of memory (calculated) or swap used  */
91 				free,		/* Not used by swap	monitor */
92 				shared,		/* Not used by swap	monitor */
93 				buffers,	/* Not used by swap	monitor */
94 				cached;		/* Not used by swap	monitor */
95 	}
96 	MeminfoMeter;
97 
98 typedef struct
99 	{
100 	GtkWidget			*vbox;
101 	GkrellmChart		*chart;
102 	GkrellmChartdata	*in_cd,
103 						*out_cd;
104 	GkrellmChartconfig	*chart_config;
105 	gboolean			enabled;
106 	gboolean			extra_info;
107 
108 	gulong				page_in,
109 						page_out;
110 	}
111 	MeminfoChart;
112 
113 
114 static GkrellmMonitor	*mon_mem,
115 						*mon_swap;
116 
117 static MeminfoMeter	mem,
118 					swap;
119 static MeminfoChart	swap_chart;
120 
121 static gint			x_scroll,
122 					x_mon_motion,
123 					x_moved,
124 					ascent;
125 
126 static MeminfoMeter	*mon_in_motion;
127 
128 
129 static void	(*read_mem_data)();
130 static void	(*read_swap_data)();
131 
132 
133 static gint
setup_meminfo_interface(void)134 setup_meminfo_interface(void)
135 	{
136 	if (!read_mem_data && !_GK.client_mode && gkrellm_sys_mem_init())
137 		{
138 		read_mem_data = gkrellm_sys_mem_read_data;
139 		read_swap_data = gkrellm_sys_swap_read_data;
140 		}
141 	return read_mem_data ? TRUE : FALSE;
142 	}
143 
144 void
gkrellm_mem_client_divert(void (* read_mem_func)(),void (* read_swap_func)())145 gkrellm_mem_client_divert(void (*read_mem_func)(), void (*read_swap_func)())
146 	{
147 	read_mem_data = read_mem_func;
148 	read_swap_data = read_swap_func;
149 	}
150 
151 void
gkrellm_mem_assign_data(guint64 total,guint64 used,guint64 free,guint64 shared,guint64 buffers,guint64 cached)152 gkrellm_mem_assign_data(guint64 total, guint64 used, guint64 free,
153                 guint64 shared, guint64 buffers, guint64 cached)
154 	{
155 	mem.total = total;
156 	mem.used = used;
157 	mem.free = free;
158 	mem.shared = shared;
159 	mem.buffers = buffers;
160 	mem.cached = cached;
161 	}
162 
163 void
gkrellm_swap_assign_data(guint64 total,guint64 used,gulong swap_in,gulong swap_out)164 gkrellm_swap_assign_data(guint64 total, guint64 used,
165                 gulong swap_in, gulong swap_out)
166 	{
167 	swap.total = total;
168 	swap.used = used;
169 	swap_chart.page_in = swap_in;
170 	swap_chart.page_out = swap_out;
171 	}
172 
173 
174   /* Reading system memory data can be expensive,
175   |  so I do some dynamic adjustments on how often I do the updates.
176   |  I increase the update rate if system activity is detected.
177   |  This is an effort to get good meter response and to
178   |  not contribute to cpu chart activity during quiet times, ie maintain
179   |  a good S/N where I'm the noise.
180   */
181 #define PIPE_SIZE	3
182 static gint		mem_pipe[PIPE_SIZE],
183 				swap_pipe[PIPE_SIZE];
184 static gint		force_update	= TRUE;
185 
186 gboolean
force_meminfo_update(void)187 force_meminfo_update(void)
188 	{
189 	gint	i, force;
190 
191 	force = force_update ? TRUE : FALSE;
192 	force_update = FALSE;
193 	if (GK.second_tick)
194 		{
195 		for (i = 1; i < PIPE_SIZE; ++i)
196 			if (mem_pipe[i] || swap_pipe[i])
197 				force = TRUE;
198 		if (_GK.cpu_sys_activity > 3)
199 			force = TRUE;
200 		}
201 	return force;
202 	}
203 
204 static gint
format_meminfo_data(MeminfoMeter * mm,gchar * src_string,gchar * buf,gint size)205 format_meminfo_data(MeminfoMeter *mm, gchar *src_string, gchar *buf, gint size)
206 	{
207 	gulong		t, u, f, ur, fr;
208 	gchar		*s, *label;
209 	gint		len;
210 	gboolean	raw;
211 
212 	if (!buf || size < 1)
213 		return -1;
214 	--size;
215 	*buf = '\0';
216 	if (!src_string)
217 		return -1;
218 	label = mm->label;
219 	t = MEG(mm->total);
220 	u = MEG(mm->used);
221 	f = t - u;
222 
223 	fr = MEG(mem.free);
224 	ur = u + MEG(mem.shared + mem.buffers + mem.cached);
225 
226 	for (s = src_string; *s != '\0' && size > 0; ++s)
227 		{
228 		len = 1;
229 		raw = FALSE;
230 		if (*s == '$' && *(s + 1) != '\0')
231 			{
232 			if (*(s + 2) == 'r')  /* print raw free/used */
233 				raw = TRUE;
234 			switch(*(s + 1))
235 				{
236 				case 'l':
237 					len = snprintf(buf, size, "%s", label);
238 					break;
239 				case 't':
240 					len = snprintf(buf, size, "%ldM", t);
241 					break;
242 				case 'u':
243 					len = snprintf(buf, size, "%ldM", raw ? ur : u);
244 					break;
245 				case 'U':
246 					if (t > 0)
247 						len = snprintf(buf, size, "%ld%%",
248 							100 * (raw ? ur : u) / t);
249 					break;
250 				case 'f':
251 					len = snprintf(buf, size, "%ldM", raw ? fr : f);
252 					break;
253 				case 'F':
254 					if (t > 0)
255 						len = snprintf(buf, size, "%ld%%",
256 							100 * (raw ? fr : f) / t);
257 					break;
258 				case 's':
259 					if (mm == &mem)
260 						len = snprintf(buf, size, "%ldM", MEG(mem.shared));
261 					break;
262 				case 'b':
263 					if (mm == &mem)
264 						len = snprintf(buf, size, "%ldM",MEG(mem.buffers));
265 					break;
266 				case 'c':
267 					if (mm == &mem)
268 						len = snprintf(buf, size, "%ldM", MEG(mem.cached));
269 					break;
270 				case 'H':
271 						len = snprintf(buf, size, "%s",
272 									gkrellm_sys_get_host_name());
273 					break;
274 				default:
275 					*buf = *s;
276 					if (size > 1)
277 						{
278 						*(buf + 1) = *(s + 1);
279 						++len;
280 						}
281 					break;
282 				}
283 			++s;
284 			if (raw)
285 				++s;
286 			}
287 		else
288 			*buf = *s;
289 		size -= len;
290 		buf += len;
291 		}
292 	*buf = '\0';
293 	return t + u + 1;		/* A way to know if decal text changed. */
294 	}
295 
296 static gint
draw_decal_label(MeminfoMeter * mm,gint draw_to_screen)297 draw_decal_label(MeminfoMeter *mm, gint draw_to_screen)
298 	{
299 	GkrellmDecal		*d;
300 	GkrellmTextstyle	ts_save;
301 	gchar				buf[128];
302 	gint				x_off, w = 0;
303 
304 	d = mm->decal_label;
305 	if (! mm->label_is_data)
306 		{
307 		gkrellm_decal_text_set_offset(d, mm->x_label, 0);
308 		gkrellm_draw_decal_text(mm->panel, d, mm->label, 0);
309 		}
310     else
311         {
312 		ts_save = d->text_style;
313 		d->text_style = *gkrellm_meter_alt_textstyle(mm->style_id);
314 
315 		format_meminfo_data(mm, mm->data_format_shadow, buf, sizeof(buf));
316 		gkrellm_decal_scroll_text_set_markup(mm->panel, d, buf);
317 		gkrellm_decal_scroll_text_get_size(d, &w, NULL);
318 		if (w  > d->w)
319 			x_off = d->w / 3 - x_scroll;
320 		else
321 			x_off = 0;
322 		gkrellm_decal_text_set_offset(d, x_off, 0);
323 
324 		d->text_style = ts_save;
325 		}
326 	if (draw_to_screen)
327 		gkrellm_draw_panel_layers(mm->panel);
328 	return w;
329 	}
330 
331 static void
cb_command_process(GkrellmAlert * alert,gchar * src,gchar * dst,gint len,MeminfoMeter * m)332 cb_command_process(GkrellmAlert *alert, gchar *src, gchar *dst, gint len,
333 			MeminfoMeter *m)
334 	{
335 	format_meminfo_data(m, src, dst, len);
336 	}
337 
338 static void
record_activity(gint * pipe,gint modified)339 record_activity(gint *pipe, gint modified)
340 	{
341 	gint	i;
342 
343 	for (i = PIPE_SIZE - 1; i > 0; --i)
344 		pipe[i] = pipe[i-1];
345 	pipe[0] = modified;
346 	}
347 
348 
349 static GkrellmSizeAbbrev	swap_blocks_abbrev[] =
350 	{
351 	{ KB_SIZE(1),		1,				"%.0f" },
352 	{ KB_SIZE(20),		KB_SIZE(1),		"%.1fK" },
353 	{ MB_SIZE(1),		KB_SIZE(1),		"%.0fK" },
354 	{ MB_SIZE(20),		MB_SIZE(1),		"%.1fM" }
355 	};
356 
357 
358 static gchar    *text_format,
359 				*text_format_locale;
360 
361 static void
format_chart_text(MeminfoChart * mc,gchar * buf,gint size)362 format_chart_text(MeminfoChart *mc, gchar *buf, gint size)
363 	{
364 	GkrellmChart	*cp;
365 	gchar	c, *s;
366 	size_t	tbl_size;
367 	gint	len, in_blocks, out_blocks, blocks;
368 
369 	--size;
370 	*buf = '\0';
371 	cp = mc->chart;
372 	in_blocks = gkrellm_get_current_chartdata(mc->in_cd);
373 	out_blocks = gkrellm_get_current_chartdata(mc->out_cd);
374 	tbl_size = sizeof(swap_blocks_abbrev) / sizeof(GkrellmSizeAbbrev);
375 	for (s = text_format_locale; *s != '\0' && size > 0; ++s)
376 		{
377 		len = 1;
378 		if (*s == '$' && *(s + 1) != '\0')
379 			{
380 			blocks = -1;
381 			if ((c = *(s + 1)) == 'T')
382 				blocks = in_blocks + out_blocks;
383 			else if (c == 'M')
384 				blocks = gkrellm_get_chart_scalemax(cp);
385 			else if (c == 'i')
386 				blocks = in_blocks;
387 			else if (c == 'o')
388 				blocks = out_blocks;
389 			else
390 				{
391 				*buf = *s;
392 				if (size > 1)
393 					{
394 					*(buf + 1) = *(s + 1);
395 					++len;
396 					}
397 				}
398 			if (blocks >= 0)
399 				len = gkrellm_format_size_abbrev(buf, size, (gfloat) blocks,
400 						&swap_blocks_abbrev[0], tbl_size);
401 			++s;
402 			}
403 		else
404 			*buf = *s;
405 		size -= len;
406 		buf += len;
407 		}
408 	*buf = '\0';
409 	}
410 
411 static void
draw_extra(MeminfoChart * mc)412 draw_extra(MeminfoChart *mc)
413     {
414     gchar       buf[128];
415 
416 	if (!mc->extra_info)
417 		return;
418 	format_chart_text(mc, buf, sizeof(buf));
419 	gkrellm_draw_chart_text(mc->chart, DEFAULT_STYLE_ID, buf);	/* XXX */
420 	}
421 
422 static void
refresh_chart(MeminfoChart * mc)423 refresh_chart(MeminfoChart *mc)
424 	{
425 	if (mc->chart)
426 		{
427 		gkrellm_draw_chartdata(mc->chart);
428 		draw_extra(mc);
429 		gkrellm_draw_chart_to_screen(mc->chart);
430 		}
431 	}
432 
433 static gint
cb_extra(GtkWidget * widget,GdkEventButton * ev,gpointer data)434 cb_extra(GtkWidget *widget, GdkEventButton *ev, gpointer data)
435 	{
436 	MeminfoChart	*mc	= (MeminfoChart *) data;
437 
438 	if (ev->button == 1 && ev->type == GDK_BUTTON_PRESS)
439 		{
440 		mc->extra_info = !mc->extra_info;
441 		gkrellm_config_modified();
442 		refresh_chart(mc);
443 		}
444 	else if (   ev->button == 3
445 			 || (ev->button == 1 && ev->type == GDK_2BUTTON_PRESS)
446 			)
447 		gkrellm_chartconfig_window_create(mc->chart);
448 	return FALSE;
449 	}
450 
451 static void
update_meminfo(void)452 update_meminfo(void)
453 	{
454 	GkrellmChart	*cp;
455 	gulong			u, b, c, used;
456 	gint			w_scroll, w, full_scale;
457 
458 	if (! (mem.enabled || swap.enabled || swap_chart.enabled))
459 		return;
460 	if (GK.five_second_tick || force_meminfo_update())
461 		(*read_mem_data)();
462 	(*read_swap_data)();
463 
464 	if (GK.second_tick)
465 		{
466 		MeminfoChart	*mc	= &swap_chart;
467 
468 		if ((cp = mc->chart) != NULL && GK.second_tick)
469 			{
470 			gkrellm_store_chartdata(cp, 0, mc->page_out, mc->page_in);
471 			refresh_chart(mc);
472 			}
473 		}
474 	if (mem.enabled)
475 		{
476 		full_scale = (gint) (mem.total >> 12);
477 		gkrellm_set_krell_full_scale(mem.krell_used, full_scale, 1);
478 		gkrellm_set_krell_full_scale(mem.krell_buffers, full_scale, 1);
479 		gkrellm_set_krell_full_scale(mem.krell_cache, full_scale, 1);
480 
481 		used = u = (gulong) (mem.used >> 12);
482 		b = u + (gulong)(mem.buffers >> 12);
483 		c = b + (gulong)(mem.cached >> 12);
484 		if (   (mem.label_is_data && mon_in_motion && x_moved)
485 			|| mem.mouse_entered
486 		   )
487 			u = b = c = 0;
488 		gkrellm_update_krell(mem.panel, mem.krell_used, u);
489 		gkrellm_update_krell(mem.panel, mem.krell_buffers, b);
490 		gkrellm_update_krell(mem.panel, mem.krell_cache, c);
491 		record_activity(mem_pipe, mem.krell_used->modified);
492 		if (mem.alert && GK.second_tick)
493 			gkrellm_check_alert(mem.alert,
494 						100.0 * (gfloat) used / (gfloat) full_scale);
495 		}
496 	if (swap.enabled)
497 		{
498 		full_scale = (gint) (swap.total >> 12);
499 		gkrellm_set_krell_full_scale(swap.krell_used, full_scale, 1);
500 		used = u = (gulong)(swap.used >> 12);
501 		if (   (swap.label_is_data && mon_in_motion && x_moved)
502 			|| swap.mouse_entered
503 		   )
504 			u = 0;
505 		gkrellm_update_krell(swap.panel, swap.krell_used, u);
506 		record_activity(swap_pipe, swap.krell_used->modified);
507 		if (swap.alert && GK.second_tick)
508 			gkrellm_check_alert(swap.alert,
509 						100.0 * (gfloat) used / (gfloat) full_scale);
510 		}
511 	if (swap.krell_delta && swap.enabled)
512 		gkrellm_update_krell(swap.panel, swap.krell_delta,
513 				swap_chart.page_in + swap_chart.page_out);
514 
515 	w = w_scroll = 0;
516 	if (mem.label_is_data && mon_in_motion != &mem && mem.enabled)
517 		w_scroll = draw_decal_label(&mem, 1);
518 	if (swap.label_is_data && mon_in_motion != &swap && swap.enabled)
519 		{
520 		if ((w = draw_decal_label(&swap, 1)) > w_scroll)
521 			w_scroll = w;
522 		}
523 	if (!mon_in_motion)
524 		{
525 		if (w_scroll > mem.decal_label->w)
526 			x_scroll = (x_scroll + ((gkrellm_update_HZ() < 7) ? 2 : 1))
527 						% (w_scroll - mem.decal_label->w / 3);
528 		else
529 			x_scroll = 0;
530 		}
531 	gkrellm_draw_panel_layers(mem.panel);
532 	gkrellm_draw_panel_layers(swap.panel);
533 	}
534 
535 static gint
meminfo_expose_event(GtkWidget * widget,GdkEventExpose * ev)536 meminfo_expose_event(GtkWidget *widget, GdkEventExpose *ev)
537 	{
538 	GdkPixmap	*pixmap	= NULL;
539 
540 	if (widget == mem.panel->drawing_area)
541 		pixmap = mem.panel->pixmap;
542 	else if (widget == swap.panel->drawing_area)
543 		pixmap = swap.panel->pixmap;
544 	else if (swap_chart.chart && widget == swap_chart.chart->drawing_area)
545 		pixmap = swap_chart.chart->pixmap;
546 	if (pixmap)
547 		gdk_draw_drawable(widget->window, gkrellm_draw_GC(1), pixmap,
548 				ev->area.x, ev->area.y, ev->area.x, ev->area.y,
549 				ev->area.width, ev->area.height);
550 	return FALSE;
551 	}
552 
553 static gint
cb_panel_enter(GtkWidget * w,GdkEventButton * ev,MeminfoMeter * mm)554 cb_panel_enter(GtkWidget *w, GdkEventButton *ev, MeminfoMeter *mm)
555 	{
556 	if (mm->label_is_data)
557 		mm->mouse_entered = TRUE;
558 	return FALSE;
559 	}
560 
561 static gint
cb_panel_leave(GtkWidget * w,GdkEventButton * ev,MeminfoMeter * mm)562 cb_panel_leave(GtkWidget *w, GdkEventButton *ev, MeminfoMeter *mm)
563 	{
564 	mm->mouse_entered = FALSE;
565 	return FALSE;
566 	}
567 
568 static gint
cb_panel_release(GtkWidget * widget,GdkEventButton * ev)569 cb_panel_release(GtkWidget *widget, GdkEventButton *ev)
570 	{
571     if (ev->button == 3)
572 		return FALSE;
573 	if (mon_in_motion)
574 		{
575 		if (mon_in_motion->restore_label)
576 			{
577 			if (mon_in_motion->label_is_data)
578 				gkrellm_config_modified();
579 			mon_in_motion->label_is_data = FALSE;
580 			draw_decal_label(mon_in_motion, 1);
581 			}
582 		mon_in_motion->restore_label = TRUE;
583 		}
584 	mon_in_motion = NULL;
585 	x_moved = FALSE;
586 	return FALSE;
587 	}
588 
589 static gint
cb_panel_press(GtkWidget * widget,GdkEventButton * ev,MeminfoMeter * mm)590 cb_panel_press(GtkWidget *widget, GdkEventButton *ev, MeminfoMeter *mm)
591     {
592 	if (ev->button == 3)
593 		{
594 		gkrellm_open_config_window(mon_mem);
595 		return FALSE;
596 		}
597 	if (   ev->button == 1 && mm->launch.button
598 		&& gkrellm_in_decal(mm->launch.button->decal, ev)
599 	   )
600 		return FALSE;
601 	if (widget == mem.panel->drawing_area)
602 		mon_in_motion = &mem;
603 	else if (widget == swap.panel->drawing_area)
604 		mon_in_motion = &swap;
605 	else
606 		return FALSE;
607 	if (! mon_in_motion->label_is_data)
608 		{
609 		mon_in_motion->label_is_data = TRUE;
610 		mon_in_motion->restore_label = FALSE;
611 		mon_in_motion->mouse_entered = TRUE;
612 		gkrellm_config_modified();
613 		}
614 	x_mon_motion = ev->x;
615 	draw_decal_label(mon_in_motion, 1);
616 	x_moved = FALSE;
617 	return FALSE;
618 	}
619 
620 static gint
cb_panel_motion(GtkWidget * widget,GdkEventButton * ev)621 cb_panel_motion(GtkWidget *widget, GdkEventButton *ev)
622 	{
623 	GdkModifierType	state;
624 	GkrellmDecal	*d;
625 	PangoFontDescription *font_desc;
626 	gchar			buf[128];
627 	gint			w, x_delta;
628 
629 	state = ev->state;
630 	if (   ! mon_in_motion
631 		|| ! (state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK))
632 		|| ! mon_in_motion->label_is_data
633 	   )
634 		{
635 		mon_in_motion = NULL;
636 		return FALSE;
637 		}
638 	d = mon_in_motion->decal_label;
639 	font_desc = gkrellm_meter_alt_textstyle(mon_in_motion->style_id)->font;
640 
641 	format_meminfo_data(mon_in_motion, mon_in_motion->data_format_shadow,
642 				buf, sizeof(buf));
643 	w = gkrellm_gdk_string_width(font_desc, buf);
644 	if (w > d->w)
645 		{
646 		x_delta = ev->x - x_mon_motion;
647 		x_mon_motion = ev->x;
648 		d->x_off += x_delta;
649 		if (d->x_off < -w)
650 			d->x_off = -w;
651 		if (d->x_off > d->w)
652 			d->x_off = d->w;
653 		x_scroll = d->w / 3 - d->x_off;
654 		if (mem.label_is_data)
655 			draw_decal_label(&mem, 1);
656 		if (swap.label_is_data)
657 			draw_decal_label(&swap, 1);
658 		mon_in_motion->restore_label = FALSE;
659 		}
660 	x_moved = TRUE;
661 	return FALSE;
662 	}
663 
664 static void
setup_scaling(GkrellmChartconfig * cf,MeminfoChart * mc)665 setup_scaling(GkrellmChartconfig *cf, MeminfoChart *mc)
666 	{
667 	GkrellmChart	*cp	  = mc->chart;
668 	gint	res   = DEFAULT_GRID_RES,
669 			grids = FULL_SCALE_GRIDS;
670 
671 	if (cp)
672 		{
673 		grids = gkrellm_get_chartconfig_fixed_grids(cp->config);
674 		res = gkrellm_get_chartconfig_grid_resolution(cp->config);
675 		}
676 	if (grids == 0)
677 		grids = FULL_SCALE_GRIDS;
678 
679 	if (swap.krell_delta)
680 		swap.krell_delta->full_scale = res * grids / gkrellm_update_HZ();
681 	}
682 
683 static void
destroy_chart(MeminfoChart * mc)684 destroy_chart(MeminfoChart *mc)
685 	{
686 	if (! mc->chart)
687 		return;
688 	gkrellm_chart_destroy(mc->chart);
689 	mc->chart = NULL;
690 	mc->enabled = FALSE;
691 	}
692 
693 static void
create_chart(MeminfoChart * mc,gint first_create)694 create_chart(MeminfoChart *mc, gint first_create)
695 	{
696 	GkrellmChart				*cp;
697 	static GkrellmPiximage		*piximage;
698 
699 	if (first_create)
700 		mc->chart = gkrellm_chart_new0();
701 	cp = mc->chart;
702 
703 	if (gkrellm_load_piximage("bg_chart", NULL, &piximage, SWAP_STYLE_NAME))
704 		gkrellm_chart_bg_piximage_override(cp, piximage,
705 					gkrellm_bg_grid_piximage(swap.style_id));
706 	gkrellm_set_chart_height_default(cp, DEFAULT_SWAP_CHART_HEIGHT);
707 	gkrellm_chart_create(mc->vbox, mon_swap, cp, &mc->chart_config);
708 	mc->out_cd = gkrellm_add_default_chartdata(cp, _("Swap Out"));
709 	mc->in_cd = gkrellm_add_default_chartdata(cp, _("Swap In"));
710 	gkrellm_set_draw_chart_function(cp, refresh_chart, mc);
711 	gkrellm_chartconfig_fixed_grids_connect(cp->config,
712 		setup_scaling, mc);
713 	gkrellm_chartconfig_grid_resolution_connect(cp->config,
714 		setup_scaling, mc);
715 	gkrellm_chartconfig_grid_resolution_adjustment(cp->config, TRUE,
716 		0, (gfloat) MIN_GRID_RES, (gfloat) MAX_GRID_RES, 0, 0, 0, 70);
717 	gkrellm_chartconfig_grid_resolution_label(cp->config,
718 	        _("Swap in/out pages per sec"));
719 	if (gkrellm_get_chartconfig_grid_resolution(cp->config) < MIN_GRID_RES)
720 		gkrellm_set_chartconfig_grid_resolution(cp->config, DEFAULT_GRID_RES);
721 
722 	gkrellm_alloc_chartdata(cp);
723 
724 	if (first_create)
725 		{
726 		g_signal_connect(G_OBJECT(cp->drawing_area), "expose_event",
727 					G_CALLBACK(meminfo_expose_event), NULL);
728 		g_signal_connect(G_OBJECT(cp->drawing_area), "button_press_event",
729 					G_CALLBACK(cb_extra), mc);
730 		gtk_widget_show(mc->vbox);
731 		}
732 	else
733 		refresh_chart(mc);	/* Avoid second lag at theme/size switches */
734 	mc->enabled = TRUE;
735 	ascent = 0;
736 	}
737 
738 static void
connect_panel_signals(GkrellmPanel * p,MeminfoMeter * mm)739 connect_panel_signals(GkrellmPanel *p, MeminfoMeter *mm)
740 		{
741 		g_signal_connect(G_OBJECT (p->drawing_area), "expose_event",
742 					G_CALLBACK(meminfo_expose_event), NULL);
743 		g_signal_connect(G_OBJECT(p->drawing_area), "button_press_event",
744 					G_CALLBACK(cb_panel_press), mm);
745 		g_signal_connect(G_OBJECT(p->drawing_area), "button_release_event",
746 					G_CALLBACK(cb_panel_release), NULL);
747 		g_signal_connect(G_OBJECT(p->drawing_area), "motion_notify_event",
748 					G_CALLBACK(cb_panel_motion), NULL);
749 		g_signal_connect(G_OBJECT(p->drawing_area), "enter_notify_event",
750 					G_CALLBACK(cb_panel_enter), mm);
751 		g_signal_connect(G_OBJECT(p->drawing_area), "leave_notify_event",
752 					G_CALLBACK(cb_panel_leave), mm);
753 		}
754 
755 static void
create_mem_panel(GtkWidget * vbox,gint first_create)756 create_mem_panel(GtkWidget *vbox, gint first_create)
757 	{
758 	GkrellmPiximage	*im = NULL;
759 	MeminfoMeter	*mm;
760 	GkrellmPanel	*p;
761 	GkrellmTextstyle *ts;
762 	GkrellmStyle	*s;
763 	gchar			*expand, buf[64], *u;
764 	gint			w_label, label_x_position, label_y_off;
765 
766 	mm = &mem;
767 	if (first_create)
768 		mm->panel = gkrellm_panel_new0();
769 	if (!mem.all_krells)	/* Krells are not in panel krell list where */
770 		{					/* they would be automatically destroyed. */
771 		gkrellm_destroy_krell(mem.krell_buffers);
772 		gkrellm_destroy_krell(mem.krell_cache);
773 		}
774 	p = mm->panel;
775 
776 	/* I've got two extra krells for buffers and cache.  Use the #included
777 	|  images unless themer has customized.
778 	*/
779 	s = gkrellm_copy_style(gkrellm_meter_style(mm->style_id));
780 
781 	s->krell_yoff = 0;
782 	s->krell_depth = 1;
783 	s->krell_x_hot = -1;
784 	gkrellm_get_gkrellmrc_integer("mem_krell_cache_depth", &s->krell_depth);
785 	gkrellm_get_gkrellmrc_integer("mem_krell_cache_x_hot", &s->krell_x_hot);
786 	gkrellm_get_gkrellmrc_integer("mem_krell_cache_yoff", &s->krell_yoff);
787 	expand = gkrellm_get_gkrellmrc_string("mem_krell_cache_expand");
788 	gkrellm_set_krell_expand(s, expand);
789 	g_free(expand);
790 	gkrellm_load_piximage("krell_cache", krell_cache_xpm, &im, MEM_STYLE_NAME);
791 	mm->krell_cache = gkrellm_create_krell(p, im, s);
792 	gkrellm_monotonic_krell_values(mm->krell_cache, FALSE);
793 
794 	s->krell_yoff = 0;
795 	s->krell_depth = 1;
796 	s->krell_x_hot = -1;
797 	gkrellm_get_gkrellmrc_integer("mem_krell_buffers_depth", &s->krell_depth);
798 	gkrellm_get_gkrellmrc_integer("mem_krell_buffers_x_hot", &s->krell_x_hot);
799 	gkrellm_get_gkrellmrc_integer("mem_krell_buffers_yoff", &s->krell_yoff);
800 	expand = gkrellm_get_gkrellmrc_string("mem_krell_buffers_expand");
801 	gkrellm_set_krell_expand(s, expand);
802 	g_free(expand);
803 	gkrellm_load_piximage("krell_buffers", krell_buffers_xpm,
804 						 &im,MEM_STYLE_NAME);
805 	mm->krell_buffers = gkrellm_create_krell(p, im, s);
806 	gkrellm_monotonic_krell_values(mm->krell_buffers, FALSE);
807 
808 	/* Unlike the style pointer passed to gkrellm_panel_configure(), the krells
809 	|  don't need the style to persist.
810 	*/
811 	g_free(s);
812 	if (im)
813 		gkrellm_destroy_piximage(im);
814 
815 	s = gkrellm_meter_style(mm->style_id);
816 	gkrellm_panel_label_get_position(s, &label_x_position, &label_y_off);
817 
818 	mm->krell_used = gkrellm_create_krell(p,
819 						gkrellm_krell_meter_piximage(mm->style_id), s);
820 	gkrellm_monotonic_krell_values(mm->krell_used, FALSE);
821 
822 	if (mem.label)
823 		g_free(mem.label);
824 	if (label_x_position == GKRELLM_LABEL_NONE)
825 		mem.label = g_strdup("");
826 	else
827 		mem.label = g_strdup(_("Mem"));
828 	if (!g_utf8_validate(mem.label, -1, NULL))
829 		{
830 		u = g_locale_to_utf8(mem.label, -1, NULL, NULL, NULL);
831 		g_free(mem.label);
832 		mem.label = u;
833 		}
834 
835 	snprintf(buf, sizeof(buf), "%sMemfj8", mem.label);
836 	mm->decal_label = gkrellm_create_decal_text(p, buf,
837 				gkrellm_meter_textstyle(mm->style_id), s, -1,
838 				(label_y_off > 0) ? label_y_off : -1,
839 				-1);
840 	gkrellm_panel_configure(p, NULL, s);
841 	gkrellm_panel_create(vbox, mon_mem, p);
842 
843 	ts = &mm->decal_label->text_style;
844 	w_label = gkrellm_gdk_string_width(ts->font, mm->label) + ts->effect;
845 	mm->x_label = gkrellm_label_x_position(label_x_position,
846 				mm->decal_label->w,
847 				w_label, 0);
848 	draw_decal_label(mm, 0);
849 
850 	if (first_create)
851 		connect_panel_signals(p, mm);
852 
853 	mm->launch.margin.left = - mm->x_label + 2;
854 	mm->launch.margin.right = -(mm->decal_label->w - mm->x_label - w_label) +2;
855 	gkrellm_setup_decal_launcher(p, &mm->launch, mm->decal_label);
856 
857 	if (!mm->enabled)
858 		gkrellm_panel_hide(p);
859 	if (!mem.all_krells)
860 		{
861 		gkrellm_remove_krell(mem.panel, mem.krell_buffers);
862 		gkrellm_remove_krell(mem.panel, mem.krell_cache);
863 		}
864 	}
865 
866 static void
create_swap_panel(GtkWidget * vbox,gint first_create)867 create_swap_panel(GtkWidget *vbox, gint first_create)
868 	{
869 	MeminfoMeter	*mm;
870 	GkrellmPanel	*p;
871 	GkrellmStyle	*style, *panel_style;
872 	GkrellmTextstyle *ts;
873 	gchar			buf[64], *u;
874 	gint			w_label, label_x_position, label_y_off;
875 
876 	mm = &swap;
877 	if (first_create)
878 		mm->panel = gkrellm_panel_new0();
879 	p = mm->panel;
880 
881 	style = gkrellm_meter_style(mm->style_id);
882 	gkrellm_panel_label_get_position(style, &label_x_position, &label_y_off);
883 
884 	/* Need a chart styled krell on the swap meter panel, but want it to track
885 	|  the meter krell margins.
886 	*/
887 	panel_style = gkrellm_copy_style(gkrellm_panel_style(DEFAULT_STYLE_ID));
888 	panel_style->krell_left_margin = style->krell_left_margin;
889 	panel_style->krell_right_margin = style->krell_right_margin;
890 	mm->krell_delta = gkrellm_create_krell(p,
891 			gkrellm_krell_panel_piximage(DEFAULT_STYLE_ID), panel_style);
892 	g_free(panel_style);	/* unlike panels, krell styles need not persist */
893 
894 	mm->krell_used = gkrellm_create_krell(p,
895 				gkrellm_krell_meter_piximage(mm->style_id), style);
896 	gkrellm_monotonic_krell_values(mm->krell_used, FALSE);
897 
898 	if (swap.label)
899 		g_free(swap.label);
900 	if (label_x_position == GKRELLM_LABEL_NONE)
901 		swap.label = g_strdup("");
902 	else
903 		swap.label = g_strdup(_("Swap"));
904 	if (!g_utf8_validate(swap.label, -1, NULL))
905 		{
906 		u = g_locale_to_utf8(swap.label, -1, NULL, NULL, NULL);
907 		g_free(swap.label);
908 		swap.label = u;
909 		}
910 
911 	snprintf(buf, sizeof(buf), "%sMemfj8", swap.label);
912 	mm->decal_label = gkrellm_create_decal_text(p, buf,
913 				gkrellm_meter_textstyle(mm->style_id), style, -1,
914 				(label_y_off > 0) ? label_y_off : -1,
915 				-1);
916 
917 	gkrellm_panel_configure(p, NULL, style);
918 	gkrellm_panel_create(vbox, mon_swap, p);
919 
920 	ts = &mm->decal_label->text_style;
921 	w_label = gkrellm_gdk_string_width(ts->font, mm->label) + ts->effect;
922 	mm->x_label = gkrellm_label_x_position(label_x_position,
923 				mm->decal_label->w,
924 				w_label, 0);
925 	draw_decal_label(mm, 0);
926 
927 	if (first_create)
928 		connect_panel_signals(p, mm);
929 
930 	mm->launch.margin.left = - mm->x_label + 1;
931 	mm->launch.margin.right = -(mm->decal_label->w - mm->x_label - w_label) +1;
932 	gkrellm_setup_decal_launcher(p, &mm->launch, mm->decal_label);
933 
934 	if (!mm->enabled)
935 		gkrellm_panel_hide(p);
936 	}
937 
938 static void
spacer_visibility(void)939 spacer_visibility(void)
940 	{
941 	gint	top, bot;
942 
943 	top = swap_chart.enabled ? GKRELLM_SPACER_CHART : GKRELLM_SPACER_METER;
944 	bot = (swap_chart.enabled && !(mem.enabled || swap.enabled)) ?
945 				GKRELLM_SPACER_CHART : GKRELLM_SPACER_METER;
946 	gkrellm_spacers_set_types(mon_mem, top, bot);
947 
948 	if (mem.enabled || swap.enabled || swap_chart.enabled)
949 		gkrellm_spacers_show(mon_mem);
950 	else
951 		gkrellm_spacers_hide(mon_mem);
952 	}
953 
954   /* No separate swap monitor create function.  Use create_mem() to create
955   |  swap chart, mem meter, and swap meter so they will all be a unit in
956   |  the same vbox.
957   */
958 static void
create_mem(GtkWidget * vbox,gint first_create)959 create_mem(GtkWidget *vbox, gint first_create)
960 	{
961 	if (first_create)
962 		{
963 		swap_chart.vbox = gtk_vbox_new(FALSE, 0);
964 		gtk_box_pack_start(GTK_BOX(vbox), swap_chart.vbox, FALSE, FALSE, 0);
965 
966 		(*read_mem_data)();
967 		(*read_swap_data)();
968 		}
969 	if (swap_chart.enabled)
970 		create_chart(&swap_chart, first_create);
971 	create_mem_panel(vbox, first_create);
972 	create_swap_panel(vbox, first_create);
973 	setup_scaling(NULL, &swap_chart);
974 	spacer_visibility();
975 	}
976 
977 
978 #define	MEM_CONFIG_KEYWORD	"meminfo"
979 
980 static void
cb_alert_trigger(GkrellmAlert * alert,MeminfoMeter * m)981 cb_alert_trigger(GkrellmAlert *alert, MeminfoMeter *m)
982 	{
983 	/* Full panel alert, default decal.
984 	*/
985 	alert->panel = m->panel;
986 	}
987 
988 static void
create_alert(MeminfoMeter * m)989 create_alert(MeminfoMeter *m)
990 	{
991 	gchar	*label;
992 
993 	if (m == &mem)
994 		label = _("Memory");
995 	else
996 		label = _("Swap");
997 	m->alert = gkrellm_alert_create(NULL, label,
998 			_("Percent Usage"),
999 			TRUE, FALSE, TRUE,
1000 			100, 10, 1, 10, 0);
1001 	gkrellm_alert_trigger_connect(m->alert, cb_alert_trigger, m);
1002 	gkrellm_alert_command_process_connect(m->alert, cb_command_process, m);
1003 	}
1004 
1005 static void
save_meminfo_config(FILE * f)1006 save_meminfo_config(FILE *f)
1007 	{
1008 	fprintf(f, "%s mem_meter %d %d %d\n", MEM_CONFIG_KEYWORD,
1009 				mem.enabled, mem.label_is_data, mem.all_krells);
1010 	fprintf(f, "%s swap_meter %d %d\n", MEM_CONFIG_KEYWORD,
1011 				swap.enabled, swap.label_is_data);
1012 	fprintf(f, "%s swap_chart %d %d\n", MEM_CONFIG_KEYWORD,
1013 				swap_chart.enabled, swap_chart.extra_info);
1014 	gkrellm_save_chartconfig(f, swap_chart.chart_config,
1015 				MEM_CONFIG_KEYWORD, NULL);
1016 
1017 	fprintf(f, "%s mem_launch %s\n", MEM_CONFIG_KEYWORD,
1018 				mem.launch.command);
1019 	fprintf(f, "%s mem_tooltip %s\n", MEM_CONFIG_KEYWORD,
1020 				mem.launch.tooltip_comment);
1021 	fprintf(f, "%s mem_data_format %s\n", MEM_CONFIG_KEYWORD,mem.data_format);
1022 
1023 	fprintf(f, "%s swap_launch %s\n", MEM_CONFIG_KEYWORD,
1024 				swap.launch.command);
1025 	fprintf(f, "%s swap_tooltip %s\n", MEM_CONFIG_KEYWORD,
1026 				swap.launch.tooltip_comment);
1027 	fprintf(f, "%s swap_data_format %s\n", MEM_CONFIG_KEYWORD,
1028 				swap.data_format);
1029 
1030 	fprintf(f, "%s text_format %s\n", MEM_CONFIG_KEYWORD, text_format);
1031 
1032 	if (mem.alert)
1033 		gkrellm_save_alertconfig(f, mem.alert, MEM_CONFIG_KEYWORD, "mem");
1034 	if (swap.alert)
1035 		gkrellm_save_alertconfig(f, swap.alert, MEM_CONFIG_KEYWORD, "swap");
1036 	}
1037 
1038 static void
load_meminfo_config(gchar * arg)1039 load_meminfo_config(gchar *arg)
1040 	{
1041 	MeminfoMeter *m = NULL;
1042 	gchar		config[32], name[16], item[CFG_BUFSIZE], item1[CFG_BUFSIZE];
1043 	gint		n;
1044 
1045 	n = sscanf(arg, "%31s %[^\n]", config, item);
1046 	if (n == 2)
1047 		{
1048 		if (strcmp(config, "mem_meter") == 0)
1049 			{
1050 			sscanf(item, "%d %d %d", &mem.enabled,
1051 					&mem.label_is_data, &mem.all_krells);
1052 			if (mem.label_is_data)
1053 				mem.restore_label = TRUE;
1054 			}
1055 		else if (strcmp(config, "swap_meter") == 0)
1056 			{
1057 			sscanf(item, "%d %d", &swap.enabled, &swap.label_is_data);
1058 			if (swap.label_is_data)
1059 				swap.restore_label = TRUE;
1060 			}
1061 		else if (strcmp(config, "swap_chart") == 0)
1062 			sscanf(item, "%d %d", &swap_chart.enabled, &swap_chart.extra_info);
1063 		else if (!strcmp(config, GKRELLM_CHARTCONFIG_KEYWORD))
1064 			gkrellm_load_chartconfig(&swap_chart.chart_config, item, 2);
1065 		else if (!strcmp(config, "mem_launch"))
1066 			mem.launch.command = g_strdup(item);
1067 		else if (!strcmp(config, "mem_tooltip"))
1068 			mem.launch.tooltip_comment = g_strdup(item);
1069 		else if (!strcmp(config, "mem_data_format"))
1070 			gkrellm_locale_dup_string(&mem.data_format, item,
1071 						&mem.data_format_shadow);
1072 		else if (!strcmp(config, "swap_launch"))
1073 			swap.launch.command = g_strdup(item);
1074 		else if (!strcmp(config, "swap_tooltip"))
1075 			swap.launch.tooltip_comment = g_strdup(item);
1076 		else if (!strcmp(config, "swap_data_format"))
1077 			gkrellm_locale_dup_string(&swap.data_format, item,
1078 						&swap.data_format_shadow);
1079 		else if (!strcmp(config, "text_format"))
1080 			gkrellm_locale_dup_string(&text_format, item, &text_format_locale);
1081 		else if (!strcmp(config, GKRELLM_ALERTCONFIG_KEYWORD))
1082 			{
1083 			if (sscanf(item, "%15s %[^\n]", name, item1) == 2)
1084 				{
1085 				if (!strcmp(name, "mem"))
1086 					m = &mem;
1087 				else if (!strcmp(name, "swap"))
1088 					m = & swap;
1089 				if (m)
1090 					{
1091 					if (!m->alert)
1092 						create_alert(m);
1093 					gkrellm_load_alertconfig(&m->alert, item1);
1094 					}
1095 				}
1096 			}
1097 		}
1098 	}
1099 
1100 /* --------------------------------------------------------------------- */
1101 
1102 static GtkWidget	*mem_launch_entry,
1103 					*mem_tooltip_entry,
1104 					*swap_launch_entry,
1105 					*swap_tooltip_entry;
1106 
1107 static GtkWidget	*mem_format_combo_box,
1108 					*swap_format_combo_box;
1109 
1110 static GtkWidget	*text_format_combo_box;
1111 
1112 static GtkWidget	*mem_alert_button,
1113 					*swap_alert_button;
1114 
1115 
1116 static void
cb_text_format(GtkWidget * widget,gpointer data)1117 cb_text_format(GtkWidget *widget, gpointer data)
1118 	{
1119 	gchar	*s;
1120 	GtkWidget *entry;
1121 
1122 	entry = gtk_bin_get_child(GTK_BIN(text_format_combo_box));
1123 	s = gkrellm_gtk_entry_get_text(&entry);
1124 	gkrellm_locale_dup_string(&text_format, s, &text_format_locale);
1125 	refresh_chart(&swap_chart);
1126 	}
1127 
1128 static void
cb_mem_enable(GtkWidget * button,gpointer data)1129 cb_mem_enable(GtkWidget *button, gpointer data)
1130     {
1131 	gboolean enabled;
1132 
1133 	enabled = GTK_TOGGLE_BUTTON(button)->active;
1134 	gkrellm_panel_enable_visibility(mem.panel, enabled, &mem.enabled);
1135 	spacer_visibility();
1136 	gtk_widget_set_sensitive(mem_alert_button, enabled);
1137 	}
1138 
1139 static void
cb_swap_enable(GtkWidget * button,gpointer data)1140 cb_swap_enable(GtkWidget *button, gpointer data)
1141     {
1142 	gboolean enabled;
1143 
1144 	enabled = GTK_TOGGLE_BUTTON(button)->active;
1145 	gkrellm_panel_enable_visibility(swap.panel, enabled, &swap.enabled);
1146 	spacer_visibility();
1147 	gtk_widget_set_sensitive(swap_alert_button, enabled);
1148 	}
1149 
1150 static void
cb_swap_chart_enable(GtkWidget * button,gpointer data)1151 cb_swap_chart_enable(GtkWidget *button, gpointer data)
1152     {
1153 	gboolean enabled;
1154 
1155 	enabled = GTK_TOGGLE_BUTTON(button)->active;
1156 	if (enabled && !swap_chart.enabled)
1157 		create_chart(&swap_chart, TRUE);
1158 	else if (!enabled && swap_chart.enabled)
1159 		destroy_chart(&swap_chart);
1160 	setup_scaling(NULL, &swap_chart);
1161 	spacer_visibility();
1162 	}
1163 
1164 static void
cb_launch_entry(GtkWidget * widget,gpointer data)1165 cb_launch_entry(GtkWidget *widget, gpointer data)
1166 	{
1167 	if (GPOINTER_TO_INT(data) == 0)
1168 		gkrellm_apply_launcher(&mem_launch_entry, &mem_tooltip_entry,
1169 					mem.panel, &mem.launch, gkrellm_launch_button_cb);
1170 	else
1171 		gkrellm_apply_launcher(&swap_launch_entry, &swap_tooltip_entry,
1172 					swap.panel, &swap.launch, gkrellm_launch_button_cb);
1173 	}
1174 
1175 static void
cb_all_krells(GtkWidget * button,gpointer data)1176 cb_all_krells(GtkWidget *button, gpointer data)
1177     {
1178 	gboolean enabled;
1179 
1180 	enabled = GTK_TOGGLE_BUTTON(button)->active;
1181 	if (enabled && !mem.all_krells)
1182 		{		/* krell list order needs to be: cache, buffer, used */
1183 		gkrellm_insert_krell(mem.panel, mem.krell_buffers, FALSE);
1184 		gkrellm_insert_krell(mem.panel, mem.krell_cache, FALSE);
1185 		}
1186 	else if (!enabled && mem.all_krells)
1187 		{
1188 		gkrellm_remove_krell(mem.panel, mem.krell_buffers);
1189 		gkrellm_remove_krell(mem.panel, mem.krell_cache);
1190 		}
1191 	mem.all_krells = enabled;
1192 	}
1193 
1194 static void
cb_mem_format(GtkWidget * widget,gpointer data)1195 cb_mem_format(GtkWidget *widget, gpointer data)
1196 	{
1197 	gchar	*s;
1198 	GtkWidget *entry;
1199 
1200 	entry = gtk_bin_get_child(GTK_BIN(mem_format_combo_box));
1201 	s = gkrellm_gtk_entry_get_text(&entry);
1202 
1203 	/* In case Pango markup tags, don't accept line unless valid markup.
1204 	|  Ie, markup like <span ...> xxx </span> or <b> xxx </b>
1205 	*/
1206 	if (   strchr(s, '<') != NULL
1207 		&& !pango_parse_markup(s, -1, 0, NULL, NULL, NULL, NULL)
1208 	   )
1209 		return;
1210 
1211 	if (gkrellm_locale_dup_string(&mem.data_format, s,
1212 				&mem.data_format_shadow))
1213 		mem.decal_label->value = -1;	/* Force redraw */
1214 	}
1215 
1216 static void
cb_swap_format(GtkWidget * widget,gpointer data)1217 cb_swap_format(GtkWidget *widget, gpointer data)
1218 	{
1219 	gchar	*s;
1220 	GtkWidget *entry;
1221 
1222 	entry = gtk_bin_get_child(GTK_BIN(swap_format_combo_box));
1223 	s = gkrellm_gtk_entry_get_text(&entry);
1224 
1225 	if (   strchr(s, '<') != NULL
1226 		&& !pango_parse_markup(s, -1, 0, NULL, NULL, NULL, NULL)
1227 	   )
1228 		return;
1229 
1230 	if (gkrellm_locale_dup_string(&swap.data_format, s,
1231 				&swap.data_format_shadow))
1232 		swap.decal_label->value = -1;
1233 	}
1234 
1235 static void
cb_set_alert(GtkWidget * button,MeminfoMeter * m)1236 cb_set_alert(GtkWidget *button, MeminfoMeter *m)
1237 	{
1238 	if (!m->alert)
1239 		create_alert(m);
1240 	gkrellm_alert_config_window(&m->alert);
1241 	}
1242 
1243 #define	DEFAULT_TEXT_FORMAT	"$T"
1244 
1245 static gchar	*mem_info_text[] =
1246 {
1247 N_("<h>Used and Free\n"),
1248 N_("The used and free memory here are calculated from the kernel reported\n"
1249 "used and free by subtracting or adding the buffers and cache memory.  See\n"
1250 "the README and compare to the \"-/+ buffers/cache:\" line from the free\n"
1251 "command.  If you show three memory krells, the kernel \"raw free\" is\n"
1252 "the space after the rightmost krell.\n"),
1253 "\n",
1254 N_("<h>Chart Labels\n"),
1255 N_("Substitution variables for the format string for chart labels:\n"),
1256 N_("\t$M    maximum chart value\n"),
1257 N_("\t$T    total swap in blocks + swap out blocks\n"),
1258 N_("\t$i    swap in blocks\n"),
1259 N_("\t$o    swap out blocks\n"),
1260 "\n",
1261 N_("<h>Panel Labels\n"),
1262 N_("Substitution variables for the format string for the Mem and Swap\n"
1263 "panels (a MiB is a binary megabyte - 2^20):\n"),
1264 
1265 N_("For memory and swap:\n"),
1266 N_("\t$t    total MiB\n"),
1267 N_("\t$u    used MiB\n"),
1268 N_("\t$f    free MiB\n"),
1269 N_("\t$U    used %\n"),
1270 N_("\t$F    free %\n"),
1271 N_("\t$l    the panel label"),
1272 "\n",
1273 N_("For memory only:\n"),
1274 N_("\t$s    shared MiB\n"),
1275 N_("\t$b    buffered MiB\n"),
1276 N_("\t$c    cached MiB\n"),
1277 "\n",
1278 N_("The free and used variables may have a 'r' qualifier for printing\n"
1279    "raw free and raw used values.  For example: $fr for raw free.\n"),
1280 "\n",
1281 N_("Substitution variables may be used in alert commands.\n"),
1282 
1283 "\n",
1284 N_("<h>Mouse Button Actions:\n"),
1285 N_("<b>\tLeft "),
1286 N_("click on a panel to scroll a programmable display of\n"
1287 "\t\tof memory or swap usage.\n")
1288 
1289 
1290 };
1291 
1292 static void
create_meminfo_tab(GtkWidget * tab_vbox)1293 create_meminfo_tab(GtkWidget *tab_vbox)
1294 	{
1295 	GtkWidget		*tabs;
1296 	GtkWidget		*vbox, *vbox1;
1297 	GtkWidget		*table;
1298 	GtkWidget		*hbox;
1299 	GtkWidget		*text, *label;
1300 	gint			i;
1301 
1302 	tabs = gtk_notebook_new();
1303 	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs), GTK_POS_TOP);
1304 	gtk_box_pack_start(GTK_BOX(tab_vbox), tabs, TRUE, TRUE, 0);
1305 
1306 /* --Options Tab */
1307 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Options"));
1308 
1309 	vbox1 = gkrellm_gtk_category_vbox(vbox,
1310 				_("Swap"),
1311 				4, 0, TRUE);
1312     gkrellm_gtk_check_button_connected(vbox1, NULL,
1313 				swap_chart.enabled, FALSE, FALSE, 0,
1314 				cb_swap_chart_enable, NULL,
1315 				_("Enable swap pages in/out chart"));
1316 	hbox = gtk_hbox_new(FALSE, 0);
1317 	gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, TRUE, 5);
1318     gkrellm_gtk_check_button_connected(hbox, NULL,
1319 				swap.enabled, FALSE, FALSE, 0,
1320 				cb_swap_enable, GINT_TO_POINTER(1),
1321 				_("Enable swap meter"));
1322 	gkrellm_gtk_alert_button(hbox, &swap_alert_button, FALSE, FALSE, 4, FALSE,
1323 				cb_set_alert, &swap);
1324 	if (!swap.enabled)
1325 		gtk_widget_set_sensitive(swap_alert_button, FALSE);
1326 
1327 	vbox1 = gkrellm_gtk_category_vbox(vbox,
1328 				_("Memory"),
1329 				4, 0, TRUE);
1330 	hbox = gtk_hbox_new(FALSE, 0);
1331 	gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, TRUE, 5);
1332     gkrellm_gtk_check_button_connected(hbox, NULL,
1333 				mem.enabled, FALSE, FALSE, 0,
1334 				cb_mem_enable, NULL,
1335 				_("Enable memory meter"));
1336 	gkrellm_gtk_alert_button(hbox, &mem_alert_button, FALSE, FALSE, 4, FALSE,
1337 				cb_set_alert, &mem);
1338 	if (!mem.enabled)
1339 		gtk_widget_set_sensitive(mem_alert_button, FALSE);
1340     gkrellm_gtk_check_button_connected(vbox1, NULL,
1341 				mem.all_krells, FALSE, FALSE, 0,
1342 				cb_all_krells, NULL,
1343 		_("Show three memory krells:   [used | buffers | cache | raw free]"));
1344 
1345 /* -- Setup tab */
1346 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Setup"));
1347 
1348 	vbox1 = gkrellm_gtk_category_vbox(vbox,
1349 				_("Format String for Chart Labels"),
1350 				4, 0, TRUE);
1351 	text_format_combo_box = gtk_combo_box_entry_new_text();
1352 	gtk_box_pack_start(GTK_BOX(vbox1), text_format_combo_box, FALSE, FALSE, 2);
1353 
1354 	gtk_combo_box_append_text(GTK_COMBO_BOX(text_format_combo_box),
1355 		text_format);
1356 	gtk_combo_box_append_text(GTK_COMBO_BOX(text_format_combo_box),
1357 		DEFAULT_TEXT_FORMAT);
1358 	gtk_combo_box_append_text(GTK_COMBO_BOX(text_format_combo_box),
1359 		"$T\\C\\f$M");
1360 	gtk_combo_box_append_text(GTK_COMBO_BOX(text_format_combo_box),
1361 		"\\c\\f$M\\b$T");
1362 	gtk_combo_box_append_text(GTK_COMBO_BOX(text_format_combo_box),
1363 		"\\ww\\C\\f$M\\D2\\f\\ai\\.$i\\D1\\f\\ao\\.$o");
1364 	gtk_combo_box_append_text(GTK_COMBO_BOX(text_format_combo_box),
1365 		"\\ww\\C\\f$M\\D3\\f\\ai\\.$i\\D0\\f\\ao\\.$o");
1366 	gtk_combo_box_set_active(GTK_COMBO_BOX(text_format_combo_box), 0);
1367 	g_signal_connect(G_OBJECT(GTK_COMBO_BOX(text_format_combo_box)), "changed",
1368 			G_CALLBACK(cb_text_format), NULL);
1369 
1370 	vbox1 = gkrellm_gtk_category_vbox(vbox,
1371 				_("Format String for Panel Labels"),
1372 				4, 6, TRUE);
1373 	hbox = gtk_hbox_new(FALSE, 0);
1374 	gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0);
1375 	mem_format_combo_box = gtk_combo_box_entry_new_text();
1376 	gtk_box_pack_start(GTK_BOX(hbox), mem_format_combo_box, TRUE, TRUE, 0);
1377 	gtk_combo_box_append_text(GTK_COMBO_BOX(mem_format_combo_box),
1378 		mem.data_format);
1379 	gtk_combo_box_append_text(GTK_COMBO_BOX(mem_format_combo_box),
1380 		DEFAULT_FORMAT);
1381 	gtk_combo_box_append_text(GTK_COMBO_BOX(mem_format_combo_box),
1382 		_("$t - $u used"));
1383 	gtk_combo_box_append_text(GTK_COMBO_BOX(mem_format_combo_box),
1384 		_("$t - $U"));
1385 	gtk_combo_box_append_text(GTK_COMBO_BOX(mem_format_combo_box),
1386 		_("$t - $u used  $s sh  $b bf  $c ca"));
1387 	gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(mem_format_combo_box))),
1388 			mem.data_format);
1389 	g_signal_connect(G_OBJECT(GTK_COMBO_BOX(mem_format_combo_box)), "changed",
1390 			G_CALLBACK(cb_mem_format), NULL);
1391 	label = gtk_label_new(_("Mem"));
1392 	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
1393 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1394 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 4);
1395 
1396 	hbox = gtk_hbox_new(FALSE, 0);
1397 	gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0);
1398 	swap_format_combo_box = gtk_combo_box_entry_new_text();
1399 	gtk_box_pack_start(GTK_BOX(hbox), swap_format_combo_box, TRUE, TRUE, 0);
1400 	gtk_combo_box_append_text(GTK_COMBO_BOX(swap_format_combo_box),
1401 		swap.data_format);
1402 	gtk_combo_box_append_text(GTK_COMBO_BOX(swap_format_combo_box),
1403 		DEFAULT_FORMAT);
1404 	gtk_combo_box_append_text(GTK_COMBO_BOX(swap_format_combo_box),
1405 		_("$t - $u used"));
1406 	gtk_combo_box_append_text(GTK_COMBO_BOX(swap_format_combo_box),
1407 		_("$t - $U"));
1408 	gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(swap_format_combo_box))),
1409 			swap.data_format);
1410 	g_signal_connect(G_OBJECT(GTK_COMBO_BOX(swap_format_combo_box)), "changed",
1411 			G_CALLBACK(cb_swap_format), NULL);
1412 	label = gtk_label_new(_("Swap"));
1413 	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
1414 	gtk_misc_set_alignment(GTK_MISC(label), 0, 0.5);
1415 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 4);
1416 
1417 	vbox1 = gkrellm_gtk_category_vbox(vbox,
1418 				_("Launch Commands"),
1419 				4, 0, TRUE);
1420 	table = gkrellm_gtk_launcher_table_new(vbox1, 2);
1421 	gkrellm_gtk_config_launcher(table, 0,  &mem_launch_entry,
1422 				&mem_tooltip_entry, _("Mem"), &(mem.launch));
1423 	g_signal_connect(G_OBJECT(mem_launch_entry), "changed",
1424 				G_CALLBACK(cb_launch_entry), GINT_TO_POINTER(0));
1425 	g_signal_connect(G_OBJECT(mem_tooltip_entry), "changed",
1426 				G_CALLBACK(cb_launch_entry), GINT_TO_POINTER(0));
1427 
1428 	gkrellm_gtk_config_launcher(table, 1,  &swap_launch_entry,
1429 				&swap_tooltip_entry, _("Swap"), &(swap.launch));
1430 	g_signal_connect(G_OBJECT(swap_launch_entry), "changed",
1431 				G_CALLBACK(cb_launch_entry), GINT_TO_POINTER(1));
1432 	g_signal_connect(G_OBJECT(swap_tooltip_entry), "changed",
1433 				G_CALLBACK(cb_launch_entry), GINT_TO_POINTER(1));
1434 
1435 /* --Info tab */
1436 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Info"));
1437 	text = gkrellm_gtk_scrolled_text_view(vbox, NULL,
1438 				GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1439 	for (i = 0; i < sizeof(mem_info_text)/sizeof(gchar *); ++i)
1440 		gkrellm_gtk_text_view_append(text, _(mem_info_text[i]));
1441 	}
1442 
1443 
1444   /* The meminfo monitor is a bit of a hybrid.  To provide for easy theming,
1445   |  the mem, swap, and swap_chart monitors are created as separate monitors,
1446   |  but they all have several common routines (update, config, ...).  Where
1447   |  a common routine is used, it is entered in only one of the GkrellmMonitor
1448   |  structures, and NULL is entered in the others.
1449   */
1450 static GkrellmMonitor	monitor_mem =
1451 	{
1452 	N_("Memory"),		/* Name, for config tab.	*/
1453 	MON_MEM,			/* Id,  0 if a plugin		*/
1454 	create_mem,			/* The create function		*/
1455 	update_meminfo,		/* The update function		*/
1456 	create_meminfo_tab, /* The config tab create function	*/
1457 	NULL, 				/* Instant apply */
1458 
1459 	save_meminfo_config, /* Save user conifg			*/
1460 	load_meminfo_config, /* Load user config			*/
1461 	MEM_CONFIG_KEYWORD, /* config keyword			*/
1462 
1463 	NULL,				/* Undef 2	*/
1464 	NULL,				/* Undef 1	*/
1465 	NULL,				/* Undef 0	*/
1466 
1467 	0,					/* insert_before_id - place plugin before this mon */
1468 
1469 	NULL,				/* Handle if a plugin, filled in by GKrellM		*/
1470 	NULL				/* path if a plugin, filled in by GKrellM		*/
1471 	};
1472 
1473 GkrellmMonitor *
gkrellm_init_mem_monitor(void)1474 gkrellm_init_mem_monitor(void)
1475 	{
1476 	monitor_mem.name = _(monitor_mem.name);
1477 	mon_mem = &monitor_mem;
1478 	mem.style_id = gkrellm_add_meter_style(mon_mem, MEM_STYLE_NAME);
1479 
1480 	gkrellm_locale_dup_string(&mem.data_format, DEFAULT_FORMAT,
1481 			&mem.data_format_shadow);
1482 	mem.enabled = TRUE;
1483 
1484 	if (setup_meminfo_interface())
1485 		return &monitor_mem;
1486 	return NULL;
1487 	}
1488 
1489 
1490 static GkrellmMonitor	monitor_swap =
1491 	{
1492 	NULL,			/* Name, for config tab. Done in mon_mem*/
1493 	MON_SWAP,		/* Id,  0 if a plugin		*/
1494 	NULL,			/* The create function		*/
1495 	NULL,			/* The update function		*/
1496 	NULL,			/* The config tab create function	*/
1497 	NULL,			/* Apply the config function		*/
1498 	NULL,			/* Save user conifg			*/
1499 	NULL,			/* Load user config			*/
1500 	NULL,			/* config keyword			*/
1501 	NULL,			/* Undef 2	*/
1502 	NULL,			/* Undef 1	*/
1503 	NULL,			/* Undef 0	*/
1504 	0,				/* insert_before_id - place plugin before this mon */
1505 	NULL,			/* Handle if a plugin, filled in by GKrellM		*/
1506 	NULL			/* path if a plugin, filled in by GKrellM		*/
1507 	};
1508 
1509 GkrellmMonitor *
gkrellm_init_swap_monitor(void)1510 gkrellm_init_swap_monitor(void)
1511 	{
1512 	mon_swap = &monitor_swap;
1513 	swap.style_id = gkrellm_add_meter_style(mon_swap, SWAP_STYLE_NAME);
1514 
1515 	gkrellm_locale_dup_string(&swap.data_format, DEFAULT_FORMAT,
1516 			&swap.data_format_shadow);
1517 	swap.enabled = TRUE;
1518 
1519 	swap_chart.enabled = FALSE;
1520 	swap_chart.extra_info = TRUE;
1521 	gkrellm_locale_dup_string(&text_format, DEFAULT_TEXT_FORMAT,
1522 					&text_format_locale);
1523 
1524 	if (setup_meminfo_interface())	/* XXX */
1525 		return &monitor_swap;
1526 	return NULL;
1527 	}
1528