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 
39 #define	DEFAULT_DATA_FORMAT	(_("$t - $f free"))
40 #define	ALT1_DATA_FORMAT (_("$t - $u used"))
41 #define	ALT2_DATA_FORMAT (_("$t - $U"))
42 
43 
44   /* Values for force_fs_check	*/
45 #define	FORCE_REDRAW	1
46 #define	FORCE_UPDATE	2
47 
48 #define	FS_MOUNTING_ENABLED(fs)	\
49 				((fs)->fstab_mounting || *((fs)->launch_umount.command))
50 
51 typedef struct
52 	{
53 	gchar		*directory;
54 	gchar		*device;
55 	gchar		*type;
56 	gchar		*options;
57 	}
58 	Mount;
59 
60 typedef struct
61 	{
62 	gint		idx;
63 	GkrellmPanel *panel;
64 	GkrellmDecalbutton *md_button,
65 				*eject_button,
66 				*drawer_button;
67 	GkrellmDecal *mount_decal,
68 				*eject_decal,
69 				*label_decal,
70 				*data_decal;
71 	GkrellmKrell *krell;
72 	gchar		*label,			/* Actual utf8 label */
73 				*label_shadow;	/* Shadow label for gdk_draw functions */
74 	gboolean	label_is_data,
75 				restore_label,
76 				mouse_entered;
77 
78 	Mount		mount;
79 	gboolean	fstab_mounting;
80 	GkrellmLauncher	launch_mount,
81 				launch_umount;
82 
83 	GkrellmAlert *alert;
84 
85 	gboolean	secondary,
86 				show_if_mounted,
87 				is_mounted,
88 				ejectable,
89 				is_nfs_fs;
90 	gchar		*eject_device;
91 	gint		eject_pending;
92 	gint		x_eject_button_target;
93 
94 	GString		*pipe_gstring;		/* output of mount commands */
95 
96 	gulong		krell_factor;		/* avoid krell math overflow */
97 
98 	gboolean	busy;
99 	gint64		blocks,
100 				bfree,
101 				bavail,
102 				bsize;
103 	}
104 	FSmon;
105 
106 static void cb_alert_config(GkrellmAlert *ap, FSmon *fs);
107 
108 static GkrellmMonitor
109 				*mon_fs;
110 
111 static GList	*fs_mon_list,
112 				*mounts_list;
113 static GList	*fstab_list;
114 
115 static gint		uid;
116 
117 void			(*get_mounts_list)(),
118 				(*get_fsusage)(),
119 				(*get_fstab_list)();
120 gboolean		(*get_fstab_modified)();
121 
122 
123 /* If ejecting is available via an ioctl() or if there is an eject command,
124 |  set these up in gkrellm_sys_fs_init() by calling gkrellm_fs_setup_eject().
125 */
126 void			(*eject_cdrom_func)(),
127 				(*close_cdrom_func)();
128 static gchar	*eject_cdrom_command,
129 				*close_cdrom_command;
130 static gboolean	cdrom_thread_busy;		/* for the cdrom_funcs */
131 
132 
133 static GtkWidget
134 				*fs_main_vbox,
135 				*fs_secondary_vbox;
136 
137 static gboolean	fs_check_timeout	= 2,
138 				nfs_check_timeout	= 16;
139 static gint		check_tick;
140 
141 static gint		secondary_monitors_shown;
142 
143 static gint		n_fs_monitors;
144 static gint		force_fs_check;
145 static FSmon	*fs_in_motion;
146 static gint		x_fs_motion;
147 static gint		x_moved;
148 static gint		x_eject_button_open,
149 				x_eject_button_closed;
150 
151 static gint		x_scroll;
152 static gint		data_decal_width;
153 static gint		cdrom_auto_eject;
154 static gint		binary_units;
155 static gboolean	mounting_supported = TRUE,
156 				ejecting_supported = FALSE;
157 static gboolean	have_secondary_panels;
158 static gchar	*data_format,
159 				*data_format_locale;
160 
161 static gint		style_id;
162 
163 static gchar *remote_fs_types[]	=
164 	{
165 	"cifs",
166 	"nfs",
167 	"smbfs"
168 	};
169 
170 
171 static gboolean
setup_fs_interface(void)172 setup_fs_interface(void)
173     {
174 #ifdef WIN32
175 	uid = 0; /* nothing comparable available on windows */
176 #else
177 	uid = getuid();	/* only real root is allowed to mount/umount always */
178 #endif
179 	if (!get_fsusage && !_GK.client_mode && gkrellm_sys_fs_init())
180 		{
181 		get_fsusage = gkrellm_sys_fs_get_fsusage;
182 		get_mounts_list = gkrellm_sys_fs_get_mounts_list;
183 		get_fstab_list = gkrellm_sys_fs_get_fstab_list;
184 		get_fstab_modified = gkrellm_sys_fs_fstab_modified;
185 		}
186 	return get_fsusage ? TRUE : FALSE;
187 	}
188 
189 void
gkrellm_fs_client_divert(void (* get_fsusage_func)(),void (* get_mounts_func)(),void (* get_fstab_func)(),gboolean (* fstab_modified_func)())190 gkrellm_fs_client_divert(void (*get_fsusage_func)(),
191                 void (*get_mounts_func)(), void (*get_fstab_func)(),
192                 gboolean (*fstab_modified_func)())
193 	{
194 	get_fsusage = get_fsusage_func;
195 	get_mounts_list = get_mounts_func;
196 	get_fstab_list = get_fstab_func;
197 	get_fstab_modified = fstab_modified_func;
198 	}
199 
200 void
gkrellm_fs_setup_eject(gchar * eject_tray,gchar * close_tray,void (* eject_func)(),void (* close_func)())201 gkrellm_fs_setup_eject(gchar *eject_tray, gchar *close_tray,
202 			void (*eject_func)(), void (*close_func)())
203 	{
204 	eject_cdrom_command = g_strdup(eject_tray);
205 	close_cdrom_command = g_strdup(close_tray);
206 	eject_cdrom_func = eject_func;
207 	close_cdrom_func = close_func;
208 	if (eject_cdrom_command || eject_cdrom_func)
209 		ejecting_supported = TRUE;
210 	}
211 
212 void
gkrellm_fs_add_to_mounts_list(gchar * dir,gchar * dev,gchar * type)213 gkrellm_fs_add_to_mounts_list(gchar *dir, gchar *dev, gchar *type)
214 	{
215 	Mount	*m;
216 
217 	m = g_new0(Mount, 1);
218 	m->directory = g_strdup(dir);
219 	m->device = g_strdup(dev);
220 	m->type = g_strdup(type);
221 	mounts_list = g_list_append(mounts_list, m);
222 	}
223 
224 void
gkrellm_fs_add_to_fstab_list(gchar * dir,gchar * dev,gchar * type,gchar * opt)225 gkrellm_fs_add_to_fstab_list(gchar *dir, gchar *dev, gchar *type, gchar *opt)
226 	{
227 	Mount	*m;
228 
229 	m = g_new0(Mount, 1);
230 	m->directory = g_strdup(dir);
231 	m->device = g_strdup(dev);
232 	m->type = g_strdup(type);
233 	m->options =  g_strdup(opt);
234 	fstab_list = g_list_append(fstab_list, m);
235 	}
236 
237 void
gkrellm_fs_assign_fsusage_data(gpointer fspointer,gint64 blocks,gint64 bavail,gint64 bfree,gint64 bsize)238 gkrellm_fs_assign_fsusage_data(gpointer fspointer,
239 			gint64 blocks, gint64 bavail, gint64 bfree, gint64 bsize)
240 	{
241 	FSmon	*fs = (FSmon *) fspointer;
242 
243 	fs->blocks = blocks;
244 	fs->bavail = bavail;
245 	fs->bfree  = bfree;
246 	fs->bsize  = bsize;
247 	}
248 
249 void
gkrellm_fs_mounting_unsupported(void)250 gkrellm_fs_mounting_unsupported(void)
251 	{
252 	mounting_supported = FALSE;
253 	}
254 
255 /* ======================================================================== */
256 
257 
258 static Mount *
in_fstab_list(gchar * s)259 in_fstab_list(gchar *s)
260 	{
261 	GList	*list;
262 	Mount	*m;
263 
264 	for (list = fstab_list; list; list = list->next)
265 		{
266 		m = (Mount *)list->data;
267 		if (strcmp(s, m->directory) == 0)
268 			return m;
269 		}
270 	return NULL;
271 	}
272 
273 static void
refresh_mounts_list(void)274 refresh_mounts_list(void)
275 	{
276 	Mount	*m;
277 
278 	while (mounts_list)
279 		{
280 		m = (Mount *) mounts_list->data;
281 		g_free(m->directory);
282 		g_free(m->device);
283 		g_free(m->type);
284 		g_free(mounts_list->data);
285 		mounts_list = g_list_remove(mounts_list, mounts_list->data);
286 		}
287 	(*get_mounts_list)();
288 	}
289 
290 static void
refresh_fstab_list(void)291 refresh_fstab_list(void)
292 	{
293 	Mount	*m;
294 
295 	while (fstab_list)
296 		{
297 		m = (Mount *) fstab_list->data;
298 		g_free(m->device);
299 		g_free(m->directory);
300 		g_free(m->type);
301 		g_free(m->options);
302 		g_free(m);
303 		fstab_list = g_list_remove(fstab_list, fstab_list->data);
304 		}
305 	(*get_fstab_list)();
306 	}
307 
308 static gint
fs_is_mounted(FSmon * fs)309 fs_is_mounted(FSmon *fs)
310 	{
311 	Mount	*m_fs, *m_mounted;
312 	GList	*list;
313 	gint	i;
314 
315 	fs->is_mounted = FALSE;
316 	m_fs = &fs->mount;
317 	for (list = mounts_list; list; list = list->next)
318 		{
319 		m_mounted = (Mount *) list->data;
320 		if (strcmp(m_fs->directory, m_mounted->directory))
321 			continue;
322 		fs->is_mounted = TRUE;
323 		fs->is_nfs_fs = FALSE;
324 		for (i = 0; i < (sizeof(remote_fs_types) / sizeof(gchar *)); ++i)
325 			{
326 			if (!strcmp(m_mounted->type, remote_fs_types[i]))
327 				{
328 				fs->is_nfs_fs = TRUE;
329 				break;
330 				}
331 			}
332 		}
333 	return fs->is_mounted;
334 	}
335 
336 static GkrellmSizeAbbrev	fs_decimal_abbrev[] =
337 	{
338 	{ MB_SIZE(10),		MB_SIZE(1),		"%.2fM" },
339 	{ GB_SIZE(1),		MB_SIZE(1),		"%.0fM" },
340 	{ GB_SIZE(10),		GB_SIZE(1),		"%.2fG" },
341 	{ GB_SIZE(100),		GB_SIZE(1),		"%.1fG" },
342 	{ TB_SIZE(1),		GB_SIZE(1),		"%.0fG" },
343 	{ TB_SIZE(10),		TB_SIZE(1),		"%.2fT" },
344 	{ TB_SIZE(100),		TB_SIZE(1),		"%.1fT" }
345 	};
346 
347 static GkrellmSizeAbbrev	fs_binary_abbrev[] =
348 	{
349 	{ MiB_SIZE(10),		MiB_SIZE(1),	"%.2fM" },
350 	{ GiB_SIZE(1),		MiB_SIZE(1),	"%.0fM" },
351 	{ GiB_SIZE(10),		GiB_SIZE(1),	"%.2fG" },
352 	{ GiB_SIZE(100),	GiB_SIZE(1),	"%.1fG" },
353 	{ TiB_SIZE(1),		GiB_SIZE(1),	"%.0fG" },
354 	{ TiB_SIZE(10),		TiB_SIZE(1),	"%.2fT" },
355 	{ TiB_SIZE(100),	TiB_SIZE(1),	"%.1fT" }
356 	};
357 
358 static gint
format_fs_data(FSmon * fs,gchar * src_string,gchar * buf,gint size)359 format_fs_data(FSmon *fs, gchar *src_string, gchar *buf, gint size)
360 	{
361 	gint64		b, u, a;
362 	gint		len;
363 	gchar		*s;
364 	gchar		tbuf[32], ubuf[32], abuf[32];
365 	gfloat		bsize, val;
366 	GkrellmSizeAbbrev *tbl;
367 	size_t		tbl_size;
368 
369 	if (!buf || size < 1)
370 		return -1;
371 	--size;
372 	*buf = '\0';
373 	if (!src_string)
374 		return -1;
375 
376 	b = fs->blocks;
377 	u = fs->blocks - fs->bfree;
378 	a = fs->bavail;					/* Can be negative on BSD	*/
379 	bsize = (gfloat) fs->bsize;
380 
381 	tbl = binary_units ? &fs_binary_abbrev[0] : &fs_decimal_abbrev[0];
382 	tbl_size = binary_units
383 			? (sizeof(fs_binary_abbrev) / sizeof(GkrellmSizeAbbrev))
384 			: (sizeof(fs_decimal_abbrev) / sizeof(GkrellmSizeAbbrev));
385 
386 	gkrellm_format_size_abbrev(tbuf, sizeof(tbuf), (gfloat) b * bsize,
387 				tbl, tbl_size);
388 	gkrellm_format_size_abbrev(ubuf, sizeof(ubuf), (gfloat) u * bsize,
389 				tbl, tbl_size);
390 	gkrellm_format_size_abbrev(abuf, sizeof(abuf), (gfloat) a * bsize,
391 				tbl, tbl_size);
392 
393 	for (s = src_string; *s != '\0' && size > 0; ++s)
394 		{
395 		len = 1;
396 		if (*s == '$' && *(s + 1) != '\0')
397 			{
398 			switch(*(s + 1))
399 				{
400 				case 'D':
401 					if (fs->mount.directory)
402 						len = snprintf(buf, size, "%s", fs->mount.directory);
403 					break;
404 				case 'l':
405 				case 'L':
406 					len = snprintf(buf, size, "%s", fs->label_shadow);
407 					break;
408 				case 't':
409 					len = snprintf(buf, size, "%s", tbuf);
410 					break;
411 				case 'u':
412 					len = snprintf(buf, size, "%s", ubuf);
413 					break;
414 				case 'U':
415 					if (u + a > 0)
416 						val = 100.0 * (gfloat) u / (gfloat) (u + a);
417 					else
418 						val = 0;
419 					len = snprintf(buf, size, "%.0f%%", val);
420 					break;
421 				case 'f':
422 					len = snprintf(buf, size, "%s", abuf);
423 					break;
424 				case 'F':
425 					if (u + a > 0)
426 						val = 100.0 * (gfloat) a / (gfloat) (u + a);
427 					else
428 						val = 0;
429 					len = snprintf(buf, size, "%.0f%%", val);
430 					break;
431 				case 'H':
432 					len = snprintf(buf, size, "%s",
433 									gkrellm_sys_get_host_name());
434 					break;
435 				default:
436 					*buf = *s;
437 					if (size > 1)
438 						{
439 						*(buf + 1) = *(s + 1);
440 						++len;
441 						}
442 					break;
443 				}
444 			++s;
445 			}
446 		else
447 			*buf = *s;
448 		size -= len;
449 		buf += len;
450 		}
451 	*buf = '\0';
452 	return u + 1;
453 	}
454 
455   /* Draw the fs label or toggle the fs total blocks and blocks avail.
456   */
457 static gint
fs_draw_decal_text(FSmon * fs,gint value)458 fs_draw_decal_text(FSmon *fs, gint value)
459 	{
460 	GkrellmDecal		*d;
461 	GkrellmTextstyle	ts_save;
462 	gchar				buf[128];
463 	gint				x_off, w = 0;
464 
465 	if (value == 0)
466 		{
467 		gkrellm_make_decal_invisible(fs->panel, fs->data_decal);
468 		d = fs->label_decal;
469 		gkrellm_make_decal_visible(fs->panel, d);
470 		gkrellm_decal_text_set_offset(d, 0, 0);
471 		gkrellm_draw_decal_markup(fs->panel, d, fs->label_shadow);
472 		}
473 	else if (!fs->busy)
474 		{
475 		gkrellm_make_decal_invisible(fs->panel, fs->label_decal);
476 		d = fs->data_decal;
477 		gkrellm_make_decal_visible(fs->panel, d);
478 		ts_save = d->text_style;
479 		d->text_style = *gkrellm_meter_alt_textstyle(style_id);
480 
481 		format_fs_data(fs, data_format_locale, buf, sizeof(buf));
482 		gkrellm_decal_scroll_text_set_markup(fs->panel, d, buf);
483 		gkrellm_decal_scroll_text_get_size(d, &w, NULL);
484 		if (w > d->w)
485 			x_off = d->w / 3 - x_scroll;
486 		else
487 			x_off = 0;
488 		gkrellm_decal_text_set_offset(d, x_off, 0);
489 
490 		d->text_style = ts_save;
491 		}
492 	return w;
493 	}
494 
495 static void
cb_command_process(GkrellmAlert * alert,gchar * src,gchar * dst,gint len,FSmon * fs)496 cb_command_process(GkrellmAlert *alert, gchar *src, gchar *dst, gint len,
497 			FSmon *fs)
498 	{
499 	format_fs_data(fs, src, dst, len);
500 	}
501 
502 static gpointer
close_cdrom_thread(void * device)503 close_cdrom_thread(void *device)
504 	{
505 	(*close_cdrom_func)((gchar *) device);
506 	cdrom_thread_busy = FALSE;
507 	return NULL;
508 	}
509 
510 static void
close_tray(FSmon * fs)511 close_tray(FSmon *fs)
512 	{
513 	GThread			*gth;
514 	Mount			*m;
515 	static gchar	*close_target;
516 	gchar			buf[512];
517 
518 	close_target = fs->eject_device;
519 	if (close_cdrom_command)
520 		{
521 		snprintf(buf, sizeof(buf), close_cdrom_command,
522 			*close_target ? close_target : fs->mount.directory);
523 		g_spawn_command_line_async(buf, NULL /* GError */);
524 		}
525 	else if (close_cdrom_func && !cdrom_thread_busy)
526 		{
527 		if (!*close_target && (m = in_fstab_list(fs->mount.directory)) != NULL)
528 			close_target = m->device;
529 		if (*close_target)
530 			{
531 			cdrom_thread_busy = TRUE;
532 			gth = g_thread_new("close_cdrom",
533 							close_cdrom_thread, close_target);
534 			g_thread_unref(gth);
535 			}
536 		}
537 	}
538 
539 static gpointer
eject_cdrom_thread(void * device)540 eject_cdrom_thread(void *device)
541 	{
542 	(*eject_cdrom_func)((gchar *) device);
543 	cdrom_thread_busy = FALSE;
544 	return NULL;
545 	}
546 
547 static void
eject_tray(FSmon * fs)548 eject_tray(FSmon *fs)
549 	{
550 	GThread			*gth;
551 	Mount			*m;
552 	static gchar	*eject_target;
553 	gchar			buf[512];
554 
555 	eject_target = fs->eject_device;
556 	if (eject_cdrom_command)
557 		{
558 		snprintf(buf, sizeof(buf), eject_cdrom_command,
559 			*eject_target ? eject_target : fs->mount.directory);
560 		g_spawn_command_line_async(buf, NULL /* GError */);
561 		}
562 	else if (eject_cdrom_func && !cdrom_thread_busy)
563 		{
564 		if (!*eject_target && (m = in_fstab_list(fs->mount.directory)) != NULL)
565 			eject_target = m->device;
566 		if (*eject_target)
567 			{
568 			cdrom_thread_busy = TRUE;
569 			gth = g_thread_new("eject_cdrom",
570 					eject_cdrom_thread, eject_target);
571 			g_thread_unref(gth);
572 			}
573 		}
574 	}
575 
576 static void
accumulate_pipe_gstring(FSmon * fs)577 accumulate_pipe_gstring(FSmon *fs)
578 	{
579 	gchar	buf[512];
580 	gint	n;
581 
582 	n = fread(buf, 1, sizeof(buf) - 1, fs->launch_mount.pipe);
583 	buf[n] = '\0';
584 	if (n > 0)
585 		{
586 		if (fs->pipe_gstring)
587 			g_string_append(fs->pipe_gstring, buf);
588 		else
589 			fs->pipe_gstring = g_string_new(buf);
590 		}
591 	if (feof(fs->launch_mount.pipe))
592 		{
593 		pclose(fs->launch_mount.pipe);
594 		fs->launch_mount.pipe = NULL;
595 		}
596 	}
597 
598 static void
pipe_command(FSmon * fs,gchar * command)599 pipe_command(FSmon *fs, gchar *command)
600 	{
601 	gchar	buf[512];
602 
603 	if (fs->launch_mount.pipe)	/* Still running? */
604 		return;
605 	snprintf(buf, sizeof(buf), "%s 2>&1", command);
606 	if ((fs->launch_mount.pipe = popen(buf, "r")) == NULL)
607 		return;
608 #ifndef WIN32
609 	fcntl(fileno(fs->launch_mount.pipe), F_SETFL, O_NONBLOCK);
610 #endif
611 	}
612 
613 static void
mount_command(FSmon * fs)614 mount_command(FSmon *fs)
615 	{
616 	gchar	cmd[CFG_BUFSIZE];
617 
618 	if (! FS_MOUNTING_ENABLED(fs))
619 		return;
620 	if (fs->is_mounted)
621 		{
622 		if (fs->fstab_mounting)
623 			snprintf(cmd, sizeof(cmd), "umount '%s'", fs->mount.directory);
624 		else
625 			snprintf(cmd, sizeof(cmd), "%s", fs->launch_umount.command);
626 		fs->label_is_data = FALSE;
627 		fs_draw_decal_text(fs, 0);
628 		pipe_command(fs, cmd);
629 		if (cdrom_auto_eject)
630 			fs->eject_pending = GK.timer_ticks + 5;	/* at least 1/2 sec delay*/
631 		}
632 	else
633 		{
634 		if (fs->ejectable)
635 			close_tray(fs);
636 		if (fs->fstab_mounting)
637 			snprintf(cmd, sizeof(cmd), "mount '%s'", fs->mount.directory);
638 		else
639 			snprintf(cmd, sizeof(cmd), "%s", fs->launch_mount.command);
640 		fs->blocks = fs->bfree = fs->bavail = fs->bsize = 0;
641 		pipe_command(fs, cmd);
642 		}
643 	force_fs_check = FORCE_REDRAW;	/* An update triggers when pipe closes */
644 	}
645 
646 static void
hide_secondary_monitors(void)647 hide_secondary_monitors(void)
648 	{
649 	FSmon	*fs;
650 	GList	*list;
651 
652 	if (!secondary_monitors_shown)
653 		return;
654 	secondary_monitors_shown = FALSE;
655 	gkrellm_freeze_side_frame_packing();
656 	for (list = fs_mon_list; list; list = list->next)
657 		{
658 		fs = (FSmon *) list->data;
659 		if (fs->secondary && (!fs_is_mounted(fs) || !fs->show_if_mounted))
660 			gkrellm_panel_hide(fs->panel);
661 		}
662 	gkrellm_thaw_side_frame_packing();
663 	}
664 
665 static void
show_secondary_monitors(void)666 show_secondary_monitors(void)
667 	{
668 	FSmon	*fs;
669 	GList	*list;
670 
671 	if (secondary_monitors_shown)
672 		return;
673 	secondary_monitors_shown = TRUE;
674 	gkrellm_freeze_side_frame_packing();
675 	for (list = fs_mon_list; list; list = list->next)
676 		{
677 		fs = (FSmon *) list->data;
678 		if (fs->secondary)
679 			gkrellm_panel_show(fs->panel);
680 		}
681 	gkrellm_thaw_side_frame_packing();
682 	}
683 
684 static gpointer
get_fsusage_thread(void * data)685 get_fsusage_thread(void *data)
686 	{
687 	FSmon	*fs = (FSmon *) data;
688 
689 	(*get_fsusage)(fs, fs->mount.directory);
690 	fs->busy = FALSE;
691 	return NULL;
692 	}
693 
694 static gboolean
animate_eject_button(FSmon * fs,gboolean force_close)695 animate_eject_button(FSmon *fs, gboolean force_close)
696 	{
697 	gint	dx, target;
698 
699 	if (force_close)
700 		target = x_eject_button_closed;
701 	else
702 		target = fs->x_eject_button_target;
703 	dx = target - fs->eject_decal->x;
704 	if (dx > 0)
705 		gkrellm_move_decal(fs->panel, fs->eject_decal,
706 			fs->eject_decal->x + 1 + dx / 4, fs->eject_decal->y);
707 	else if (dx < 0)
708 		gkrellm_move_decal(fs->panel, fs->eject_decal,
709 			fs->eject_decal->x - 1 + dx / 4, fs->eject_decal->y);
710 	if (fs->eject_decal->x < x_eject_button_closed)
711 		gkrellm_show_button(fs->eject_button);
712 	else
713 		gkrellm_hide_button(fs->eject_button);
714 	if (fs->eject_decal->x != target)
715 		return TRUE;
716 	return FALSE;
717 	}
718 
719 static void
fs_update(void)720 fs_update(void)
721 	{
722 	GThread			*gth;
723 	FSmon			*fs;
724 	GkrellmPanel	*p;
725 	GkrellmKrell	*k;
726 	GList			*list;
727 	gint64			used, avail;
728 	gint			full_scale, index, w_scroll, w;
729 	gboolean		fs_check, nfs_check, force_check, force_draw,
730 					mounting_enabled;
731 
732 	if (!fs_mon_list)
733 		return;
734 
735 	w = w_scroll = 0;
736 	for (list = fs_mon_list; list; list = list->next)
737 		{
738 		fs = (FSmon *) list->data;
739 		if (fs->label_is_data && !fs_in_motion)
740 			{
741 			w = fs_draw_decal_text(fs, 1);
742 			if (w > w_scroll)
743 				w_scroll = w;
744 			gkrellm_draw_panel_layers(fs->panel);
745 			}
746 		}
747 	if (!fs_in_motion)
748 		{
749 		if (w_scroll > data_decal_width)
750 			x_scroll = (x_scroll + ((gkrellm_update_HZ() < 7) ? 2 : 1))
751 					% (w_scroll - data_decal_width / 3);
752 		else
753 			x_scroll = 0;
754 		}
755 	if (GK.second_tick)
756 		++check_tick;
757 	fs_check = (check_tick % fs_check_timeout) ? FALSE : TRUE;
758 	if (_GK.client_mode)
759 		nfs_check = fs_check;
760 	else
761 		nfs_check = (check_tick % nfs_check_timeout) ? FALSE : TRUE;
762 
763 	if (!force_fs_check && (!GK.second_tick || (!fs_check && !nfs_check)))
764 		return;
765 //g_debug("fs update %d nfs %d force %d\n", fs_check, nfs_check, force_fs_check);
766 
767 	refresh_mounts_list();
768 
769 	force_check = force_draw = FALSE;
770 
771 	for (list = fs_mon_list; list; list = list->next)
772 		{
773 		fs = (FSmon *) list->data;
774 		p  = fs->panel;
775 		k = fs->krell;
776 		mounting_enabled = FS_MOUNTING_ENABLED(fs);
777 		if (fs_is_mounted(fs))
778 			{
779 			if (mounting_enabled)
780 				{	/* Blink it while busy or pipe is open.	*/
781 				if (   (fs->launch_mount.pipe || fs->busy)
782 					&& fs->md_button->cur_index == D_MISC_FS_MOUNTED
783 				   )
784 					index = D_MISC_FS_UMOUNTED;
785 				else
786 					index = D_MISC_FS_MOUNTED;
787 				gkrellm_set_decal_button_index(fs->md_button, index);
788 				}
789 			else
790 				{
791 				if (fs->busy && fs->md_button->cur_index == D_MISC_LED1)
792 					index = D_MISC_LED0;
793 				else
794 					index = mounting_supported ? D_MISC_LED1 : D_MISC_BLANK;
795 				gkrellm_set_decal_button_index(fs->md_button, index);
796 				}
797 			if (   force_fs_check == FORCE_UPDATE
798 				|| (fs_check && !fs->is_nfs_fs)
799 				|| (nfs_check && fs->is_nfs_fs)
800 			   )
801 				{
802 				if (!fs->is_nfs_fs || _GK.client_mode)
803 					(*get_fsusage)(fs, fs->mount.directory);
804 				else if (!fs->busy)
805 					{
806 					fs->busy = TRUE;
807 					gth = g_thread_new("get_fsusage", get_fsusage_thread, fs);
808 					g_thread_unref(gth);
809 					}
810 				if (fs->blocks > 2147483648LL)
811 					fs->krell_factor = 1024 * 1024;
812 				else if (fs->blocks > 2097152LL)
813 					fs->krell_factor = 1024;
814 				else
815 					fs->krell_factor = 1;
816 				}
817 
818 			avail = fs->bavail >= 0 ? fs->bavail : 0;
819 			used = fs->blocks - fs->bfree;
820 
821 			full_scale = (gint) ((used + avail) / (gint64) fs->krell_factor);
822 			used = used / (gint64) fs->krell_factor;
823 
824 			gkrellm_set_krell_full_scale(k, full_scale, 1);
825 
826 			if (!fs->busy)
827 				{
828 				if (   (fs_in_motion && fs->label_is_data && x_moved)
829 					|| fs->mouse_entered
830 				   )
831 					gkrellm_update_krell(p, k, 0);
832 				else
833 					gkrellm_update_krell(p, k, (gulong) used);
834 				if (full_scale > 0)
835 					gkrellm_check_alert(fs->alert,
836 							100.0 * (gfloat) used / (gfloat) full_scale);
837 				}
838 			else
839 				force_draw = TRUE;
840 
841 			if (fs->secondary && fs->show_if_mounted)
842 				gkrellm_panel_show(fs->panel);
843 			if (fs->eject_decal)
844 				force_draw |= animate_eject_button(fs, mounting_supported);
845 			}
846 		else	/* not mounted */
847 			{
848 			gkrellm_reset_alert(fs->alert);
849 			if (mounting_enabled)
850 				{	/* Blink it while pipe is open.	*/
851 				if (   fs->launch_mount.pipe
852 					&& fs->md_button->cur_index == D_MISC_FS_UMOUNTED
853 				   )
854 					index = D_MISC_FS_MOUNTED;
855 				else
856 					index = D_MISC_FS_UMOUNTED;
857 				gkrellm_set_decal_button_index(fs->md_button, index);
858 				}
859 			else
860 				gkrellm_set_decal_button_index(fs->md_button, D_MISC_LED0);
861 			gkrellm_set_krell_full_scale(k, 100, 1);	/* Arbitrary > 0 */
862 			gkrellm_update_krell(p, k, 0);
863 			if (!secondary_monitors_shown && fs->secondary)
864 				gkrellm_panel_hide(fs->panel);
865 			if (fs->eject_decal)
866 				force_draw |= animate_eject_button(fs, FALSE);
867 			}
868 		gkrellm_set_button_sensitive(fs->md_button, mounting_enabled);
869 		if (!fs->label_is_data && fs != fs_in_motion)
870 			fs_draw_decal_text(fs, 0);
871 
872 		if (_GK.client_mode)
873 			{
874 			if (fs->blocks == 0)
875 				gkrellm_remove_krell(p, k);
876 			else
877 				gkrellm_insert_krell(p, k, FALSE);
878 			}
879 
880 		gkrellm_draw_panel_layers(p);
881 
882 		if (   fs->ejectable
883 			&& fs->eject_pending && fs->eject_pending < GK.timer_ticks
884 		   )
885 			{
886 			eject_tray(fs);
887 			fs->eject_pending = 0;
888 			}
889 		if (fs->launch_mount.pipe)
890 			{
891 			accumulate_pipe_gstring(fs);
892 			if (fs->launch_mount.pipe == NULL)	/* Command is done */
893 				{
894 				if (fs->pipe_gstring)
895 					{
896 					gkrellm_message_dialog(_("GKrellM Mount Error"),
897 							fs->pipe_gstring->str);
898 					g_string_free(fs->pipe_gstring, 1);
899 					fs->pipe_gstring = NULL;
900 					}
901 				force_check = TRUE;
902 				}
903 			else
904 				force_draw = TRUE; 	/* Keep it going */
905 			}
906 		}
907 	force_fs_check = force_check ? FORCE_UPDATE : force_draw;
908 	}
909 
910 static gint
fs_expose_event(GtkWidget * widget,GdkEventExpose * ev)911 fs_expose_event(GtkWidget *widget, GdkEventExpose *ev)
912 	{
913 	FSmon	*fs;
914 	GList	*list;
915 
916 	for (list = fs_mon_list; list; list = list->next)
917 		{
918 		fs = (FSmon *) list->data;
919 		if (widget == fs->panel->drawing_area)
920 			{
921 			gdk_draw_drawable(widget->window, gkrellm_draw_GC(1),
922 					fs->panel->pixmap,
923 					ev->area.x, ev->area.y, ev->area.x, ev->area.y,
924 					ev->area.width, ev->area.height);
925 			break;
926 			}
927 		}
928 	return FALSE;
929 	}
930 
931 static gint
cb_panel_enter(GtkWidget * w,GdkEventButton * ev,FSmon * fs)932 cb_panel_enter(GtkWidget *w, GdkEventButton *ev, FSmon *fs)
933 	{
934 	if (fs->label_is_data)
935 		{
936 		fs->mouse_entered = TRUE;
937 		force_fs_check = FORCE_REDRAW;
938 		}
939 	if (fs->ejectable)
940 		{
941 		fs->x_eject_button_target = x_eject_button_open;
942 		force_fs_check = FORCE_REDRAW;
943 		}
944 	if (fs != fs_in_motion)
945 		gkrellm_show_button(fs->drawer_button);
946 	return FALSE;
947 	}
948 
949 static gint
cb_panel_leave(GtkWidget * w,GdkEventButton * ev,FSmon * fs)950 cb_panel_leave(GtkWidget *w, GdkEventButton *ev, FSmon *fs)
951 	{
952 	if (fs->mouse_entered)
953 		force_fs_check = FORCE_REDRAW;
954 	fs->mouse_entered = FALSE;
955 	if (fs->ejectable)
956 		{
957 		fs->x_eject_button_target = x_eject_button_closed;
958 		force_fs_check = FORCE_REDRAW;
959 		}
960 	return FALSE;
961 	}
962 
963 
964 static void
cb_drawer_button(GkrellmDecalbutton * button,FSmon * fs)965 cb_drawer_button(GkrellmDecalbutton *button, FSmon *fs)
966 	{
967 	if (secondary_monitors_shown)
968 		hide_secondary_monitors();
969 	else
970 		show_secondary_monitors();
971 	}
972 
973 static gint
cb_panel_scroll(GtkWidget * widget,GdkEventScroll * ev)974 cb_panel_scroll(GtkWidget *widget, GdkEventScroll *ev)
975 	{
976 	if (ev->direction == GDK_SCROLL_UP)
977 		hide_secondary_monitors();
978 	if (ev->direction == GDK_SCROLL_DOWN)
979 		show_secondary_monitors();
980 	return FALSE;
981 	}
982 
983 static gint
cb_panel_release(GtkWidget * widget,GdkEventButton * ev,FSmon * fs)984 cb_panel_release(GtkWidget *widget, GdkEventButton *ev, FSmon *fs)
985 	{
986 	if (ev->button == 3)
987 		return TRUE;
988 	if (fs_in_motion)
989 		{
990 		if (fs_in_motion->restore_label)
991 			{
992 			if (fs_in_motion->label_is_data)
993 				gkrellm_config_modified();
994 			fs_in_motion->label_is_data = FALSE;
995 			fs_draw_decal_text(fs_in_motion, 0);
996 			gkrellm_show_button(fs_in_motion->drawer_button);
997 			gkrellm_draw_panel_layers(fs_in_motion->panel);
998 			}
999 		fs_in_motion->restore_label = TRUE;
1000 		}
1001 	force_fs_check = FORCE_REDRAW;		/* Move krells back */
1002 	fs_in_motion = NULL;
1003 	x_moved = 0;
1004 	return FALSE;
1005 	}
1006 
1007 static gint
cb_panel_press(GtkWidget * widget,GdkEventButton * ev,FSmon * fs)1008 cb_panel_press(GtkWidget *widget, GdkEventButton *ev, FSmon *fs)
1009 	{
1010 	GkrellmDecal	*d;
1011 
1012 	d = fs->eject_decal ? fs->eject_decal : fs->mount_decal;
1013 
1014 	if (ev->button == 3 && ev->x < d->x)
1015 		{
1016 		gkrellm_open_config_window(mon_fs);
1017 		return TRUE;
1018 		}
1019 #if 0
1020 	if (   ev->button == 1
1021 		&& (   (fs->drawer_button
1022 				&& gkrellm_in_decal(fs->drawer_button->decal, ev))
1023 			|| ev->x >= d->x
1024 		   )
1025 	   )
1026 		return FALSE;
1027 #endif
1028 
1029 	if (!fs->label_is_data)
1030 		{
1031 		fs->label_is_data = TRUE;
1032 		fs->restore_label = FALSE;
1033 		fs->mouse_entered = TRUE;
1034 		gkrellm_config_modified();
1035 		}
1036 	x_fs_motion = ev->x;
1037 	fs_draw_decal_text(fs, 1);
1038 	gkrellm_draw_panel_layers(fs->panel);
1039 	fs_in_motion = fs;
1040 	x_moved = 0;
1041 	gkrellm_hide_button(fs->drawer_button);
1042 	return TRUE;
1043 	}
1044 
1045 static gint
cb_panel_motion(GtkWidget * widget,GdkEventButton * ev)1046 cb_panel_motion(GtkWidget *widget, GdkEventButton *ev)
1047 	{
1048 	GdkModifierType	state;
1049 	GList			*list;
1050 	FSmon			*fs;
1051 	GkrellmDecal	*d;
1052 	gchar			buf[128];
1053 	gint			w, x_delta	= 0;
1054 
1055 	state = ev->state;
1056 	if (   !fs_in_motion
1057 		|| !(state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK))
1058 		|| !fs_in_motion->label_is_data
1059 	   )
1060 		{
1061 		fs_in_motion = NULL;
1062 		return FALSE;
1063 		}
1064 
1065 	d = fs_in_motion->data_decal;
1066 	format_fs_data(fs_in_motion, data_format_locale, buf, sizeof(buf));
1067 	gkrellm_decal_scroll_text_get_size(d, &w, NULL);
1068 	if (w > d->w)
1069 		{
1070 		x_delta = ev->x - x_fs_motion;
1071 		x_fs_motion = ev->x;
1072 		d->x_off += x_delta;
1073 		if (d->x_off < -w)
1074 			d->x_off = -w;
1075 		if (d->x_off > d->w)
1076 			d->x_off = d->w;
1077 		x_scroll = d->w / 3 - d->x_off;
1078 		for (list = fs_mon_list; list; list = list->next)
1079 			{
1080 			fs = (FSmon *) list->data;
1081 			if (fs->label_is_data)
1082 				{
1083 				fs_draw_decal_text(fs, 1);
1084 				gkrellm_draw_panel_layers(fs->panel);
1085 				}
1086 			}
1087 		if (x_moved > 0)
1088 			fs_in_motion->restore_label = FALSE;
1089 		}
1090 	if (x_moved == 0)
1091 		force_fs_check = FORCE_REDRAW;	/* Move krells out of the way */
1092 	x_moved += (x_delta > 0) ? x_delta : -x_delta;
1093 	return FALSE;
1094 	}
1095 
1096 static void
cb_fs_mount_button(GkrellmDecalbutton * button)1097 cb_fs_mount_button(GkrellmDecalbutton *button)
1098 	{
1099 	if (button)
1100 		mount_command((FSmon *) button->data);
1101 	}
1102 
1103 static void
cb_fs_eject_button(GkrellmDecalbutton * button,FSmon * fs)1104 cb_fs_eject_button(GkrellmDecalbutton *button, FSmon *fs)
1105 	{
1106 	if (button)
1107 		eject_tray(fs);
1108 	}
1109 
1110 static void
cb_fs_close_tray(GkrellmDecalbutton * button,FSmon * fs)1111 cb_fs_close_tray(GkrellmDecalbutton *button, FSmon *fs)
1112 	{
1113 	if (button)
1114 		close_tray(fs);
1115 	}
1116 
1117 static void
fs_monitor_create(GtkWidget * vbox,FSmon * fs,gint index,gint first_create)1118 fs_monitor_create(GtkWidget *vbox, FSmon *fs, gint index, gint first_create)
1119 	{
1120 	GkrellmStyle		*style;
1121 	GkrellmTextstyle	*ts;
1122 	GkrellmMargin		*m;
1123 	GkrellmPanel		*p;
1124 	gchar				buf[256];
1125 	gint				h, label_x_position, label_y_off;
1126 	gint				h_data, h_label;
1127 
1128 	if (first_create)
1129 		fs->panel = gkrellm_panel_new0();
1130 	p = fs->panel;
1131 	fs->idx = index;
1132 	++n_fs_monitors;
1133 	fs->krell_factor = 1;
1134 
1135 	style = gkrellm_meter_style(style_id);
1136 	ts = gkrellm_meter_textstyle(style_id);
1137 	m = gkrellm_get_style_margins(style);
1138 
1139 	gkrellm_panel_label_get_position(style, &label_x_position, &label_y_off);
1140 
1141 	format_fs_data(fs, data_format_locale, buf, sizeof(buf));
1142 	fs->data_decal = gkrellm_create_decal_text_markup(p, buf,
1143 			ts, style, -1,
1144 			(label_y_off > 0) ? label_y_off : -1,
1145 			-1);
1146 	gkrellm_decal_get_size(fs->data_decal, NULL, &h_data);
1147 
1148 	fs->label_decal = gkrellm_create_decal_text_markup(p, fs->label_shadow,
1149 			ts, style, -1,
1150 			(label_y_off > 0) ? label_y_off : -1,
1151 			-1);
1152 	gkrellm_decal_get_size(fs->label_decal, NULL, &h_label);
1153 
1154 	if (h_data > h_label)
1155 		gkrellm_move_decal(p, fs->label_decal, fs->label_decal->x,
1156 				fs->label_decal->y + (h_data - h_label + 1) / 2);
1157 	else if (h_data < h_label)
1158 		gkrellm_move_decal(p, fs->data_decal, fs->data_decal->x,
1159 				fs->data_decal->y + (h_label - h_data + 1) / 2);
1160 
1161 	fs->mount_decal = gkrellm_create_decal_pixmap(p,
1162 			gkrellm_decal_misc_pixmap(), gkrellm_decal_misc_mask(),
1163 			N_MISC_DECALS, style, -1, -1);
1164 	fs->mount_decal->x =
1165 				gkrellm_chart_width() - fs->mount_decal->w - m->right;
1166 
1167 	if (fs->ejectable)
1168 		{
1169 		fs->eject_decal = gkrellm_create_decal_pixmap(p,
1170 				gkrellm_decal_misc_pixmap(), gkrellm_decal_misc_mask(),
1171 				N_MISC_DECALS, style, -1, -1);
1172 		if (mounting_supported)
1173 			{
1174 			x_eject_button_closed = fs->mount_decal->x;
1175 			x_eject_button_open = fs->mount_decal->x - fs->eject_decal->w + 1;
1176 			}
1177 		else
1178 			{
1179 			x_eject_button_closed = gkrellm_chart_width() - 2;
1180 			x_eject_button_open = x_eject_button_closed - fs->eject_decal->w;
1181 			}
1182 		fs->x_eject_button_target = x_eject_button_closed;
1183 		fs->eject_decal->x = x_eject_button_closed;
1184 		}
1185 
1186 	/* Usable width to determine various scrolling parameters.
1187 	*/
1188 	data_decal_width = fs->mount_decal->x - fs->data_decal->x;
1189 
1190 	fs->krell = gkrellm_create_krell(p,
1191 						gkrellm_krell_meter_piximage(style_id), style);
1192 	gkrellm_monotonic_krell_values(fs->krell, FALSE);
1193 
1194 	gkrellm_panel_configure(p, NULL, style);
1195 	gkrellm_panel_create(vbox, mon_fs, p);
1196 
1197 	fs->md_button = gkrellm_make_decal_button(p, fs->mount_decal,
1198 			cb_fs_mount_button, fs, D_MISC_FS_UMOUNTED, D_MISC_FS_PRESSED);
1199 	if (index == 0 && have_secondary_panels)
1200 		{
1201 		if ((h = p->h / 2) > 7)
1202 			h = 7;
1203 		fs->drawer_button = gkrellm_make_scaled_button(p, NULL,
1204 					cb_drawer_button, fs, TRUE, TRUE,
1205 					0, 0, 0,	/* NULL image => builtin depth & indices */
1206 					(gkrellm_chart_width() - 20) / 2, 0,
1207 					20, h);
1208 		/* Make it appear under the label decal */
1209 		gkrellm_remove_decal(p, fs->drawer_button->decal);
1210 		gkrellm_insert_decal_nth(p, fs->drawer_button->decal, 0);
1211 		}
1212 	if (fs->eject_decal)
1213 		{
1214 		fs->eject_button = gkrellm_make_decal_button(p, fs->eject_decal,
1215 			cb_fs_eject_button, fs, D_MISC_BUTTON_OUT, D_MISC_BUTTON_IN);
1216 		gkrellm_hide_button(fs->eject_button);
1217 		if (close_cdrom_command || close_cdrom_func)
1218 			gkrellm_decal_button_right_connect(fs->eject_button,
1219 						cb_fs_close_tray, fs);
1220 		}
1221 	if (first_create)
1222 		{
1223 		g_signal_connect(G_OBJECT(p->drawing_area), "expose_event",
1224 				G_CALLBACK(fs_expose_event), NULL);
1225 		g_signal_connect(G_OBJECT(p->drawing_area),"button_press_event",
1226 				G_CALLBACK(cb_panel_press), fs);
1227 		g_signal_connect(G_OBJECT(p->drawing_area),"button_release_event",
1228 				G_CALLBACK(cb_panel_release), fs);
1229 		g_signal_connect(G_OBJECT(p->drawing_area),"scroll_event",
1230 				G_CALLBACK(cb_panel_scroll), fs);
1231 		g_signal_connect(G_OBJECT(p->drawing_area),"motion_notify_event",
1232 				G_CALLBACK(cb_panel_motion), NULL);
1233 		g_signal_connect(G_OBJECT(p->drawing_area), "enter_notify_event",
1234 				G_CALLBACK(cb_panel_enter), fs);
1235 		g_signal_connect(G_OBJECT(p->drawing_area), "leave_notify_event",
1236 				G_CALLBACK(cb_panel_leave), fs);
1237 		if (   !secondary_monitors_shown && fs->secondary
1238 			&& (!fs_is_mounted(fs) || !fs->show_if_mounted))
1239 			gkrellm_panel_hide(fs->panel);
1240 		}
1241 
1242 	fs_draw_decal_text(fs, 0);
1243 	force_fs_check = FORCE_UPDATE;
1244 
1245 	if (fs->launch_mount.command == NULL)
1246 		fs->launch_mount.command = g_strdup("");
1247 	if (fs->launch_umount.command == NULL)
1248 		fs->launch_umount.command = g_strdup("");
1249 	}
1250 
1251 static void
free_fsmon_strings(FSmon * fs)1252 free_fsmon_strings(FSmon *fs)
1253 	{
1254 	g_free(fs->label);
1255 	g_free(fs->label_shadow);
1256 	g_free(fs->mount.directory);
1257 	g_free(fs->eject_device);
1258 	g_free(fs->launch_mount.command);
1259 	g_free(fs->launch_umount.command);
1260 	}
1261 
1262 static void
destroy_fs_monitor(FSmon * fs)1263 destroy_fs_monitor(FSmon *fs)
1264 	{
1265 	gkrellm_reset_alert(fs->alert);
1266 	free_fsmon_strings(fs);
1267 	gkrellm_panel_destroy(fs->panel);
1268 	g_free(fs);
1269 	--n_fs_monitors;
1270 	}
1271 
1272 static void
fs_create(GtkWidget * vbox,gint first_create)1273 fs_create(GtkWidget *vbox, gint first_create)
1274 	{
1275 	GList	*list;
1276 	FSmon	*fs;
1277 	gint	i;
1278 
1279 	if (fs_main_vbox == NULL)
1280 		{
1281 		fs_main_vbox = gtk_vbox_new(FALSE, 0);
1282 		gtk_box_pack_start(GTK_BOX(vbox), fs_main_vbox, FALSE, FALSE, 0);
1283 		gtk_widget_show(fs_main_vbox);
1284 
1285 		fs_secondary_vbox = gtk_vbox_new(FALSE, 0);
1286 		gtk_box_pack_start(GTK_BOX(vbox), fs_secondary_vbox, FALSE, FALSE, 0);
1287 		gtk_widget_show(fs_secondary_vbox);
1288 		secondary_monitors_shown = FALSE;
1289 		}
1290 	n_fs_monitors = 0;
1291 	for (i = 0, list = fs_mon_list; list; ++i, list = list->next)
1292 		{
1293 		fs = (FSmon *)list->data;
1294 		fs_monitor_create(fs->secondary ? fs_secondary_vbox : fs_main_vbox,fs,
1295 					i, first_create);
1296 		}
1297 	if (g_list_length(fs_mon_list) == 0)
1298 		gkrellm_spacers_hide(mon_fs);
1299 	}
1300 
1301 #define	FS_CONFIG_KEYWORD	"fs"
1302 
1303 static void
cb_alert_trigger(GkrellmAlert * alert,FSmon * fs)1304 cb_alert_trigger(GkrellmAlert *alert, FSmon *fs)
1305 	{
1306 	/* Full panel alert, default decal.
1307 	*/
1308 	alert->panel = fs->panel;
1309 	}
1310 
1311 static void
create_alert(FSmon * fs)1312 create_alert(FSmon *fs)
1313 	{
1314 	fs->alert = gkrellm_alert_create(NULL, fs->label,
1315 				_("Percent Usage"),
1316 				TRUE, FALSE, TRUE,
1317 				100, 10, 1, 10, 0);
1318 	gkrellm_alert_trigger_connect(fs->alert, cb_alert_trigger, fs);
1319 	gkrellm_alert_config_connect(fs->alert, cb_alert_config, fs);
1320 	gkrellm_alert_command_process_connect(fs->alert, cb_command_process, fs);
1321 	}
1322 
1323 static void
fs_config_save(FILE * f)1324 fs_config_save(FILE *f)
1325 	{
1326 	GList	*list;
1327 	FSmon	*fs;
1328 	gchar	quoted_label[64], quoted_dir[512];
1329 
1330 	for (list = fs_mon_list; list; list = list->next)
1331 		{
1332 		fs = (FSmon *) list->data;
1333 		snprintf(quoted_label, sizeof(quoted_label), "\"%s\"", fs->label);
1334 		snprintf(quoted_dir, sizeof(quoted_dir), "\"%s\"",fs->mount.directory);
1335 		fprintf(f, "%s %s %s %d %d %d %d %d\n", FS_CONFIG_KEYWORD,
1336 				quoted_label, quoted_dir,
1337 				fs->fstab_mounting, fs->secondary,
1338 				fs->show_if_mounted, fs->label_is_data, fs->ejectable);
1339 		if (*(fs->launch_mount.command))
1340 			fprintf(f, "%s mount_command %s\n", FS_CONFIG_KEYWORD,
1341 					fs->launch_mount.command);
1342 		if (*(fs->launch_umount.command))
1343 			fprintf(f, "%s umount_command %s\n", FS_CONFIG_KEYWORD,
1344 					fs->launch_umount.command);
1345 		if (*(fs->eject_device))
1346 			fprintf(f, "%s eject_device %s\n", FS_CONFIG_KEYWORD,
1347 					fs->eject_device);
1348 		if (fs->alert)
1349 			gkrellm_save_alertconfig(f, fs->alert,
1350 					FS_CONFIG_KEYWORD, quoted_label);
1351 		}
1352 	if (!_GK.client_mode)
1353 		{
1354 		fprintf(f, "%s fs_check_timeout %d\n", FS_CONFIG_KEYWORD,
1355 				fs_check_timeout);
1356 		fprintf(f, "%s nfs_check_timeout %d\n", FS_CONFIG_KEYWORD,
1357 				nfs_check_timeout);
1358 		fprintf(f, "%s auto_eject %d\n", FS_CONFIG_KEYWORD, cdrom_auto_eject);
1359 		}
1360 	fprintf(f, "%s binary_units %d\n", FS_CONFIG_KEYWORD, binary_units);
1361 	fprintf(f, "%s data_format %s\n", FS_CONFIG_KEYWORD, data_format);
1362 	}
1363 
1364 static gboolean
fstab_user_permission(Mount * m)1365 fstab_user_permission(Mount *m)
1366 	{
1367 	struct stat my_stat;
1368 
1369 	stat(m->device, &my_stat);
1370 	if (   strstr(m->options, "user")
1371 		|| (strstr(m->options, "owner") && my_stat.st_uid == uid)
1372 	   )
1373 		return TRUE;
1374 	return FALSE;
1375 	}
1376 
1377 static gint
fix_fstab_mountable_changed(FSmon * fs)1378 fix_fstab_mountable_changed(FSmon *fs)
1379 	{
1380 	Mount	*m;
1381 
1382 	if (!mounting_supported)
1383 		return FALSE;
1384 	m = in_fstab_list(fs->mount.directory);
1385 	if (   (!m || (!fstab_user_permission(m) && uid != 0))
1386 		&& fs->fstab_mounting
1387 	   )
1388 		{
1389 		fs->fstab_mounting = FALSE;
1390 		return TRUE;
1391 		}
1392 	return FALSE;
1393 	}
1394 
1395 static FSmon *
lookup_fs(gchar * name)1396 lookup_fs(gchar *name)
1397 	{
1398 	GList	*list;
1399 	FSmon	*fs;
1400 
1401 	if (!name)
1402 		return NULL;
1403 	for (list = fs_mon_list; list; list = list->next)
1404 		{
1405 		fs = (FSmon *) list->data;
1406 		if (!strcmp(fs->label, name))
1407 			return fs;
1408 		}
1409 	return NULL;
1410 	}
1411 
1412 static void
fs_config_load(gchar * arg)1413 fs_config_load(gchar *arg)
1414 	{
1415 	static FSmon	*fs_prev;
1416 	FSmon			*fs;
1417 	gchar			*cut_label, *cut_dir;
1418 	gchar			config[32], item[CFG_BUFSIZE];
1419 	gchar			name[64], item1[CFG_BUFSIZE];
1420 	gint 			n;
1421 
1422 	if ((n = sscanf(arg, "%31s %[^\n]", config, item)) != 2)
1423 		return;
1424 
1425 	if (!strcmp(config, "fs_check_timeout"))
1426 		{
1427 		sscanf(item, "%d", &fs_check_timeout);
1428 		if (fs_check_timeout < 2)
1429 			fs_check_timeout = 2;
1430 		}
1431 	else if (!strcmp(config, "nfs_check_timeout"))
1432 		{
1433 		sscanf(item, "%d", &nfs_check_timeout);
1434 		if (nfs_check_timeout < 5)
1435 			nfs_check_timeout = 5;
1436 		}
1437 	else if (!strcmp(config, "auto_eject"))
1438 		sscanf(item, "%d", &cdrom_auto_eject);
1439 	else if (!strcmp(config, "binary_units"))
1440 		sscanf(item, "%d", &binary_units);
1441 	else if (!strcmp(config, "data_format"))
1442 		gkrellm_locale_dup_string(&data_format, item, &data_format_locale);
1443 	else if (fs_prev && !strcmp(config, "mount_command"))
1444 		gkrellm_dup_string(&fs_prev->launch_mount.command, item);
1445 	else if (fs_prev && !strcmp(config, "umount_command"))
1446 		gkrellm_dup_string(&fs_prev->launch_umount.command, item);
1447 	else if (fs_prev && !strcmp(config, "eject_device"))
1448 		{
1449 		if (fs_prev->ejectable)
1450 			gkrellm_dup_string(&fs_prev->eject_device, item);
1451 		}
1452 	else if (!strcmp(config, GKRELLM_ALERTCONFIG_KEYWORD))
1453 		{
1454 		if (   sscanf(item, "\"%63[^\"]\" %[^\n]", name, item1) == 2
1455 			&& (fs = lookup_fs(name)) != NULL
1456 		   )
1457 			{
1458 			if (!fs->alert)
1459 				create_alert(fs);
1460 			gkrellm_load_alertconfig(&fs->alert, item1);
1461 			}
1462 		}
1463 	else
1464 		{
1465 		if (   (cut_label = gkrellm_cut_quoted_string(arg, &arg)) != NULL
1466 			&& (cut_dir = gkrellm_cut_quoted_string(arg, &arg)) != NULL
1467 	       )
1468 			{
1469 			fs = g_new0(FSmon, 1);
1470 			gkrellm_locale_dup_string(&fs->label, cut_label,&fs->label_shadow);
1471 
1472 			sscanf(arg, "%d %d %d %d %d", &fs->fstab_mounting,
1473 					&fs->secondary, &fs->show_if_mounted,
1474 					&fs->label_is_data, &fs->ejectable);
1475 			if (fs->fstab_mounting > 1)		/* pre 2.0.0 config fix */
1476 				fs->fstab_mounting = FALSE;
1477 			if (!ejecting_supported)
1478 				fs->ejectable = FALSE;
1479 			if (!mounting_supported)
1480 				fs->fstab_mounting = fs->show_if_mounted = FALSE;
1481 			if (fs->secondary)
1482 				have_secondary_panels = TRUE;
1483 			fs->mount.directory = g_strdup(cut_dir);
1484 			fs->restore_label = fs->label_is_data;
1485 
1486 			fix_fstab_mountable_changed(fs);
1487 			fs->krell_factor = 1;
1488 			fs->launch_mount.command = g_strdup("");
1489 			fs->launch_umount.command = g_strdup("");
1490 			fs->eject_device = g_strdup("");
1491 			fs_mon_list = g_list_append(fs_mon_list, fs);
1492 			fs_prev = fs;	/* XXX */
1493 			}
1494 		}
1495 	}
1496 
1497 
1498 /* --------------------------------------------------------------------- */
1499 
1500 enum
1501 	{
1502 	NAME_COLUMN,
1503 	MOUNT_POINT_COLUMN,
1504 	SHOW_COLUMN,
1505 	FSTAB_COLUMN,
1506 	MOUNT_COMMAND_COLUMN,
1507 	UMOUNT_COMMAND_COLUMN,
1508 	EJECTABLE_COLUMN,
1509 	DEVICE_COLUMN,
1510 	FSMON_COLUMN,
1511 	ALERT_COLUMN,
1512 	SHOW_DATA_COLUMN,
1513 	VISIBLE_COLUMN,
1514 	IMAGE_COLUMN,
1515 	N_COLUMNS
1516 	};
1517 
1518 static GtkTreeView		*treeview;
1519 static GtkTreeRowReference *row_reference;
1520 static GtkTreeSelection	*selection;
1521 
1522 static GtkWidget
1523 				*label_entry,
1524 				*dir_combo_box,
1525 				*mount_entry,
1526 				*umount_entry,
1527 				*mounting_button,
1528 				*ejectable_button,
1529 				*device_entry,
1530 				*secondary_button,
1531 				*show_button,
1532 				*delete_button,
1533 				*new_apply_button;
1534 
1535 static GtkWidget	*alert_button;
1536 
1537 static GtkWidget	*data_format_combo_box;
1538 
1539 static gboolean	(*original_row_drop_possible)();
1540 
1541 
1542 static void
set_tree_store_model_data(GtkTreeStore * tree,GtkTreeIter * iter,FSmon * fs)1543 set_tree_store_model_data(GtkTreeStore *tree, GtkTreeIter *iter, FSmon *fs)
1544 	{
1545 	gtk_tree_store_set(tree, iter,
1546 			NAME_COLUMN, fs->label,
1547 			MOUNT_POINT_COLUMN, fs->mount.directory,
1548 			SHOW_COLUMN, fs->show_if_mounted,
1549 			FSTAB_COLUMN, fs->fstab_mounting,
1550 			MOUNT_COMMAND_COLUMN, fs->launch_mount.command,
1551 			UMOUNT_COMMAND_COLUMN, fs->launch_umount.command,
1552 			EJECTABLE_COLUMN, fs->ejectable,
1553 			DEVICE_COLUMN, fs->eject_device,
1554 			FSMON_COLUMN, fs,
1555 			ALERT_COLUMN, fs->alert,
1556 			SHOW_DATA_COLUMN, fs->label_is_data,
1557 			VISIBLE_COLUMN, TRUE,
1558 			-1);
1559 	if (fs->alert)
1560 		gtk_tree_store_set(tree, iter,
1561 				IMAGE_COLUMN, gkrellm_alert_pixbuf(),
1562 				-1);
1563 	}
1564 
1565 static GtkTreeModel *
create_model(void)1566 create_model(void)
1567 	{
1568 	GtkTreeStore	*tree;
1569 	GtkTreeIter		iter, citer;
1570 	GList			*list;
1571 	FSmon			*fs;
1572 
1573 	tree = gtk_tree_store_new(N_COLUMNS,
1574 				G_TYPE_STRING, G_TYPE_STRING,
1575 				G_TYPE_BOOLEAN, G_TYPE_BOOLEAN,
1576 				G_TYPE_STRING, G_TYPE_STRING,
1577 				G_TYPE_BOOLEAN, G_TYPE_STRING,
1578 				G_TYPE_POINTER, G_TYPE_POINTER,
1579 				G_TYPE_BOOLEAN,
1580 				G_TYPE_BOOLEAN, GDK_TYPE_PIXBUF);
1581 
1582 	gtk_tree_store_append(tree, &iter, NULL);
1583 	gtk_tree_store_set(tree, &iter,
1584 			NAME_COLUMN, _("Primary"),
1585 			VISIBLE_COLUMN, FALSE,
1586 			-1);
1587 	for (list = fs_mon_list; list; list = list->next)
1588 		{
1589 		fs = (FSmon *) list->data;
1590 		if (fs->secondary)
1591 			continue;
1592 		gtk_tree_store_append(tree, &citer, &iter);
1593 		set_tree_store_model_data(tree, &citer, fs);
1594 		}
1595 
1596 	gtk_tree_store_append(tree, &iter, NULL);
1597 	gtk_tree_store_set(tree, &iter,
1598 			NAME_COLUMN, _("Secondary"),
1599 			VISIBLE_COLUMN, FALSE,
1600 			-1);
1601 	for (list = fs_mon_list; list; list = list->next)
1602 		{
1603 		fs = (FSmon *) list->data;
1604 		if (!fs->secondary)
1605 			continue;
1606 		gtk_tree_store_append(tree, &citer, &iter);
1607 		set_tree_store_model_data(tree, &citer, fs);
1608 		}
1609 	return GTK_TREE_MODEL(tree);
1610 	}
1611 
1612 static void
change_row_reference(GtkTreeModel * model,GtkTreePath * path)1613 change_row_reference(GtkTreeModel *model, GtkTreePath *path)
1614 	{
1615 	gtk_tree_row_reference_free(row_reference);
1616 	if (model && path)
1617 		row_reference = gtk_tree_row_reference_new(model, path);
1618 	else
1619 		row_reference = NULL;
1620 	}
1621 
1622 static void
cb_set_alert(GtkWidget * button,gpointer data)1623 cb_set_alert(GtkWidget *button, gpointer data)
1624 	{
1625 	GtkTreeModel	*model;
1626 	GtkTreePath		*path;
1627 	GtkTreeIter		iter;
1628 	FSmon			*fs;
1629 
1630 	if (!row_reference)
1631 		return;
1632 	model = gtk_tree_view_get_model(treeview);
1633 	path = gtk_tree_row_reference_get_path(row_reference);
1634 	gtk_tree_model_get_iter(model, &iter, path);
1635 	gtk_tree_model_get(model, &iter, FSMON_COLUMN, &fs, -1);
1636 
1637 	if (!fs->alert)
1638 		create_alert(fs);
1639 	gkrellm_alert_config_window(&fs->alert);
1640 	gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
1641 						ALERT_COLUMN, fs->alert, -1);
1642 	}
1643 
1644 static gboolean
get_child_iter(GtkTreeModel * model,gchar * parent_node,GtkTreeIter * citer)1645 get_child_iter(GtkTreeModel *model, gchar *parent_node, GtkTreeIter *citer)
1646 	{
1647 	GtkTreePath     *path;
1648 	GtkTreeIter     iter;
1649 
1650 	path = gtk_tree_path_new_from_string(parent_node);
1651 	gtk_tree_model_get_iter(model, &iter, path);
1652 	gtk_tree_path_free(path);
1653 	return gtk_tree_model_iter_children(model, citer, &iter);
1654 	}
1655 
1656   /* Callback for a created or destroyed alert.  Find the sensor in the model
1657   |  and set the IMAGE_COLUMN.
1658   */
1659 static void
cb_alert_config(GkrellmAlert * ap,FSmon * fs)1660 cb_alert_config(GkrellmAlert *ap, FSmon *fs)
1661 	{
1662 	GtkTreeModel    *model;
1663 	GtkTreeIter     iter;
1664 	FSmon			*fs_test;
1665 	GdkPixbuf       *pixbuf;
1666 	gchar           node[2];
1667 	gint            i;
1668 
1669 	if (!gkrellm_config_window_shown())
1670 		return;
1671 	model = gtk_tree_view_get_model(treeview);
1672 	pixbuf = ap->activated ? gkrellm_alert_pixbuf() : NULL;
1673 	for (i = 0; i < 2; ++i)
1674 		{
1675 		node[0] = '0' + i;      /* toplevel Primary or Secondary node */
1676 		node[1] = '\0';
1677 		if (get_child_iter(model, node, &iter))
1678 			do
1679 				{
1680 				gtk_tree_model_get(model, &iter, FSMON_COLUMN, &fs_test, -1);
1681 				if (fs != fs_test)
1682 					continue;
1683 				gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
1684 							IMAGE_COLUMN, pixbuf, -1);
1685 				return;
1686 				}
1687 			while (gtk_tree_model_iter_next(model, &iter));
1688 		}
1689 	}
1690 
1691   /* Watch what is going into the directory combo entry, compare it to
1692   |  fstab entries and accordingly set sensitivity of the mounting_button.
1693   */
1694 static void
cb_combo_changed(GtkComboBox * widget,gpointer user_data)1695 cb_combo_changed(GtkComboBox *widget, gpointer user_data)
1696 	{
1697 	Mount	*m;
1698 	gchar	*s;
1699 	GtkWidget *entry;
1700 
1701 	if (!mounting_supported || _GK.client_mode)
1702 		return;
1703 
1704 	entry = gtk_bin_get_child(GTK_BIN(dir_combo_box));
1705 	s = gkrellm_gtk_entry_get_text(&entry);
1706 	m = in_fstab_list(s);
1707 	if (m && (fstab_user_permission(m) || uid == 0))
1708 		{
1709 		gtk_widget_set_sensitive(mounting_button, TRUE);
1710 		if (GTK_TOGGLE_BUTTON(mounting_button)->active)
1711 			{
1712 			gtk_entry_set_text(GTK_ENTRY(mount_entry), "");
1713 			gtk_entry_set_text(GTK_ENTRY(umount_entry), "");
1714 			gtk_widget_set_sensitive(mount_entry, FALSE);
1715 			gtk_widget_set_sensitive(umount_entry, FALSE);
1716 			}
1717 		}
1718 	else
1719 		{
1720 		if (GTK_TOGGLE_BUTTON(mounting_button)->active)
1721 			gtk_toggle_button_set_active(
1722 						GTK_TOGGLE_BUTTON(mounting_button), FALSE);
1723 		else
1724 			{
1725 			gtk_widget_set_sensitive(mount_entry, TRUE);
1726 			gtk_widget_set_sensitive(umount_entry, TRUE);
1727 			}
1728 		gtk_widget_set_sensitive(mounting_button, FALSE);
1729 		}
1730 	}
1731 
1732 static void
cb_mount_button_clicked(GtkWidget * widget)1733 cb_mount_button_clicked(GtkWidget *widget)
1734 	{
1735 	if (!mounting_supported || _GK.client_mode)
1736 		return;
1737 	if (GTK_TOGGLE_BUTTON(mounting_button)->active)
1738 		{
1739 		gtk_entry_set_text(GTK_ENTRY(mount_entry), "");
1740 		gtk_entry_set_text(GTK_ENTRY(umount_entry), "");
1741 		gtk_widget_set_sensitive(mount_entry, FALSE);
1742 		gtk_widget_set_sensitive(umount_entry, FALSE);
1743 		if (device_entry)
1744 			{
1745 			gtk_entry_set_text(GTK_ENTRY(device_entry), "");
1746 			gtk_widget_set_sensitive(device_entry, FALSE);
1747 			}
1748 		}
1749 	else
1750 		{
1751 		gtk_widget_set_sensitive(mount_entry, TRUE);
1752 		gtk_widget_set_sensitive(umount_entry, TRUE);
1753 		if (   ejectable_button
1754 			&& GTK_TOGGLE_BUTTON(ejectable_button)->active
1755 		   )
1756 			gtk_widget_set_sensitive(device_entry, TRUE);
1757 		}
1758 	}
1759 
1760 static void
cb_ejectable_button_clicked(GtkWidget * widget)1761 cb_ejectable_button_clicked(GtkWidget *widget)
1762 	{
1763 	gboolean	fstab_mounting;
1764 
1765 	if (!mounting_supported || _GK.client_mode)
1766 		return;
1767 	fstab_mounting = GTK_TOGGLE_BUTTON(mounting_button)->active;
1768 	if (GTK_TOGGLE_BUTTON(ejectable_button)->active)
1769 		{
1770 		gtk_widget_set_sensitive(device_entry, !fstab_mounting);
1771 		}
1772 	else
1773 		{
1774 		gtk_entry_set_text(GTK_ENTRY(device_entry), "");
1775 		gtk_widget_set_sensitive(device_entry, FALSE);
1776 		}
1777 	}
1778 
1779 static void
cb_secondary_button_clicked(GtkWidget * widget)1780 cb_secondary_button_clicked(GtkWidget *widget)
1781 	{
1782 	if (!mounting_supported)	/* Show button is in client mode */
1783 		return;
1784 	if (GTK_TOGGLE_BUTTON(secondary_button)->active)
1785 		gtk_widget_set_sensitive(show_button, TRUE);
1786 	else
1787 		{
1788 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_button), FALSE);
1789 		gtk_widget_set_sensitive(show_button, FALSE);
1790 		}
1791 	}
1792 
1793 static void
reset_entries(gboolean level0)1794 reset_entries(gboolean level0)
1795 	{
1796 	gtk_entry_set_text(GTK_ENTRY(label_entry), "");
1797 	gtk_combo_box_set_active(GTK_COMBO_BOX(dir_combo_box), -1);
1798 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(secondary_button), level0);
1799 	if (mounting_button)
1800 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mounting_button),FALSE);
1801 	if (show_button)
1802 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_button), FALSE);
1803 	if (ejectable_button)
1804 		{
1805 		gtk_toggle_button_set_active(
1806 					GTK_TOGGLE_BUTTON(ejectable_button), FALSE);
1807 		if (device_entry)
1808 			gtk_entry_set_text(GTK_ENTRY(device_entry), "");
1809 		}
1810 	if (mount_entry)
1811 		{
1812 		gtk_entry_set_text(GTK_ENTRY(mount_entry), "");
1813 		gtk_entry_set_text(GTK_ENTRY(umount_entry), "");
1814 		}
1815 	change_row_reference(NULL, NULL);
1816 	gtk_tree_selection_unselect_all(selection);
1817 	}
1818 
1819 static FSmon *
fs_new_from_model(GtkTreeModel * model,GtkTreeIter * iter)1820 fs_new_from_model(GtkTreeModel *model, GtkTreeIter *iter)
1821 	{
1822 	FSmon	*fs;
1823 	gchar	*label;
1824 
1825 	fs = g_new0(FSmon, 1);
1826 	gtk_tree_model_get(model, iter,
1827 				NAME_COLUMN, &label,
1828 				MOUNT_POINT_COLUMN, &fs->mount.directory,
1829 				SHOW_COLUMN, &fs->show_if_mounted,
1830 				FSTAB_COLUMN, &fs->fstab_mounting,
1831 				MOUNT_COMMAND_COLUMN, &fs->launch_mount.command,
1832 				UMOUNT_COMMAND_COLUMN, &fs->launch_umount.command,
1833 				EJECTABLE_COLUMN, &fs->ejectable,
1834 				DEVICE_COLUMN, &fs->eject_device,
1835 				ALERT_COLUMN, &fs->alert,
1836 				SHOW_DATA_COLUMN, &fs->label_is_data,
1837 				-1);
1838 	gkrellm_locale_dup_string(&fs->label, label, &fs->label_shadow);
1839 	g_free(label);
1840 	return fs;
1841 	}
1842 
1843 static void
cb_tree_selection_changed(GtkTreeSelection * selection,gpointer data)1844 cb_tree_selection_changed(GtkTreeSelection *selection, gpointer data)
1845 	{
1846 	GtkTreeIter		iter;
1847 	GtkTreeModel	*model;
1848 	GtkTreePath		*path;
1849 	FSmon			*fs;
1850 	gint			*indices, depth, secondary;
1851 
1852 	if (!gtk_tree_selection_get_selected(selection, &model, &iter))
1853 		{
1854 		reset_entries(FALSE);
1855 		gtk_button_set_label(GTK_BUTTON(new_apply_button), GTK_STOCK_NEW);
1856 		gtk_widget_set_sensitive(delete_button, FALSE);
1857 		gtk_widget_set_sensitive(alert_button, FALSE);
1858 		return;
1859 		}
1860 	path = gtk_tree_model_get_path(model, &iter);
1861 	indices = gtk_tree_path_get_indices(path);
1862 	secondary = indices[0];
1863 	depth = gtk_tree_path_get_depth(path);
1864 // g_debug("selection: indices=[%d,%d]:%d, path=%s\n",
1865 //			indices[0], indices[1], gtk_tree_path_get_depth(path),
1866 //			gtk_tree_path_to_string(path));
1867 	change_row_reference(model, path);
1868 	gtk_tree_path_free(path);
1869 
1870 	if (depth == 1)
1871 		{
1872 		reset_entries(secondary);
1873 		gtk_button_set_label(GTK_BUTTON(new_apply_button), GTK_STOCK_NEW);
1874 		gtk_widget_set_sensitive(delete_button, FALSE);
1875 		gtk_widget_set_sensitive(alert_button, FALSE);
1876 		return;
1877 		}
1878 	gtk_button_set_label(GTK_BUTTON(new_apply_button), GTK_STOCK_APPLY);
1879 	gtk_widget_set_sensitive(delete_button, TRUE);
1880 	gtk_widget_set_sensitive(alert_button, TRUE);
1881 
1882 	fs = fs_new_from_model(model, &iter);
1883 	if (!secondary)
1884 		fs->show_if_mounted = FALSE;	/* in case dragged secondary->primary*/
1885 
1886 	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(secondary_button),
1887 					secondary);
1888 	gtk_entry_set_text(GTK_ENTRY(label_entry), fs->label);
1889 	gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(dir_combo_box))),
1890 			fs->mount.directory);
1891 	if (show_button)
1892 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(show_button),
1893 					fs->show_if_mounted);
1894 	if (mounting_button)
1895 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mounting_button),
1896 					fs->fstab_mounting);
1897 	if (ejectable_button)
1898 		{
1899 		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ejectable_button),
1900 					fs->ejectable);
1901 		if (device_entry)
1902 			{
1903 			gtk_entry_set_text(GTK_ENTRY(device_entry), fs->eject_device);
1904 			if (!fs->ejectable)
1905 				gtk_widget_set_sensitive(device_entry, FALSE);
1906 			}
1907 		}
1908 	if (mount_entry)
1909 		{
1910 		gtk_entry_set_text(GTK_ENTRY(mount_entry), fs->launch_mount.command);
1911 		gtk_entry_set_text(GTK_ENTRY(umount_entry), fs->launch_umount.command);
1912 		}
1913 	free_fsmon_strings(fs);
1914 	g_free(fs);
1915 	}
1916 
1917 static void
sync_fs_panels(void)1918 sync_fs_panels(void)
1919 	{
1920 	GtkTreeModel	*model;
1921 	GtkTreePath		*path;
1922 	GtkTreeIter		iter0, iter1, iter;
1923 	GList			*list;
1924 	FSmon			*fs;
1925 
1926 	model = gtk_tree_view_get_model(treeview);
1927 
1928 	path = gtk_tree_path_new_from_string("0");
1929 	gtk_tree_model_get_iter(model, &iter0, path);
1930 	gtk_tree_path_free(path);
1931 
1932 	path = gtk_tree_path_new_from_string("1");
1933 	gtk_tree_model_get_iter(model, &iter1, path);
1934 	gtk_tree_path_free(path);
1935 
1936 	if (   gtk_tree_model_iter_has_child(model, &iter1)
1937 		&& !gtk_tree_model_iter_has_child(model, &iter0)
1938 	   )
1939 		{
1940 		gkrellm_config_message_dialog(_("Entry Error"),
1941 N_("At least one primary fs monitor must exist to click on in order to show\n"
1942 "secondary ones.\n"));
1943 		}
1944 
1945 	for (list = fs_mon_list; list; list = list->next)
1946 		destroy_fs_monitor((FSmon *) list->data);
1947 	g_list_free(fs_mon_list);
1948 	fs_mon_list = NULL;
1949 	n_fs_monitors = 0;
1950 	have_secondary_panels = gtk_tree_model_iter_has_child(model, &iter1);
1951 
1952 	if (gtk_tree_model_iter_children(model, &iter, &iter0))
1953 		{
1954 		do
1955 			{
1956 			fs = fs_new_from_model(model, &iter);
1957 			fs->secondary = FALSE;
1958 			fs->show_if_mounted = FALSE;
1959 			fs_mon_list = g_list_append(fs_mon_list, fs);
1960 			fs_monitor_create(fs_main_vbox, fs, n_fs_monitors, TRUE);
1961 			gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
1962 						FSMON_COLUMN, fs, -1);
1963 			gkrellm_alert_trigger_connect(fs->alert, cb_alert_trigger, fs);
1964 			gkrellm_alert_config_connect(fs->alert, cb_alert_config, fs);
1965 			}
1966 		while (gtk_tree_model_iter_next(model, &iter));
1967 		}
1968 
1969 	if (gtk_tree_model_iter_children(model, &iter, &iter1))
1970 		{
1971 		do
1972 			{
1973 			fs = fs_new_from_model(model, &iter);
1974 			fs->secondary = TRUE;
1975 			fs_mon_list = g_list_append(fs_mon_list, fs);
1976 			fs_monitor_create(fs_secondary_vbox, fs, n_fs_monitors, TRUE);
1977 			gtk_tree_store_set(GTK_TREE_STORE(model), &iter,
1978 						FSMON_COLUMN, fs, -1);
1979 			gkrellm_alert_trigger_connect(fs->alert, cb_alert_trigger, fs);
1980 			gkrellm_alert_config_connect(fs->alert, cb_alert_config, fs);
1981 			}
1982 		while (gtk_tree_model_iter_next(model, &iter));
1983 		}
1984 	else
1985 		secondary_monitors_shown = FALSE;
1986 
1987 	force_fs_check = FORCE_UPDATE;
1988 	if (g_list_length(fs_mon_list) > 0)
1989 		gkrellm_spacers_show(mon_fs);
1990 	else
1991 		gkrellm_spacers_hide(mon_fs);
1992 	}
1993 
1994 static void
add_cb(GtkWidget * widget)1995 add_cb(GtkWidget *widget)
1996 	{
1997 	GtkTreeModel	*model;
1998 	GtkTreePath		*path = NULL;
1999 	GtkTreeIter		iter, parent_iter;
2000 	FSmon			*fs;
2001 	gchar			*label;
2002 	gint			secondary, *indices;
2003 	gboolean		a, b, err = FALSE;
2004 	GtkWidget		*entry;
2005 
2006 	fs = g_new0(FSmon, 1);
2007 	fs->launch_mount.command = g_strdup("");
2008 	fs->launch_umount.command = g_strdup("");
2009 	fs->eject_device = g_strdup("");
2010 
2011 	label = gkrellm_gtk_entry_get_text(&label_entry);
2012 	gkrellm_locale_dup_string(&fs->label, label, &fs->label_shadow);
2013 
2014 	entry = gtk_bin_get_child(GTK_BIN(dir_combo_box));
2015 	fs->mount.directory = g_strdup(gkrellm_gtk_entry_get_text(&entry));
2016 
2017 	if (show_button)
2018 		fs->show_if_mounted = GTK_TOGGLE_BUTTON(show_button)->active;
2019 	if (mounting_button)
2020 		fs->fstab_mounting = GTK_TOGGLE_BUTTON(mounting_button)->active;
2021 	if (mount_entry)
2022 		{
2023 		gkrellm_dup_string(&(fs->launch_mount.command),
2024 					gkrellm_gtk_entry_get_text(&mount_entry));
2025 		gkrellm_dup_string(&(fs->launch_umount.command),
2026 					gkrellm_gtk_entry_get_text(&umount_entry));
2027 		}
2028 	if (ejectable_button)
2029 		{
2030 		fs->ejectable = GTK_TOGGLE_BUTTON(ejectable_button)->active;
2031 		if (fs->ejectable && !fs->fstab_mounting && device_entry)
2032 			gkrellm_dup_string(&(fs->eject_device),
2033 					gkrellm_gtk_entry_get_text(&device_entry));
2034 		}
2035 	if (!*(fs->label) || !*(fs->mount.directory))
2036 		{
2037 		gkrellm_config_message_dialog(_("Entry Error"),
2038 #if !defined(WIN32)
2039 			_("Both a label and a mount point must be entered."));
2040 #else
2041 			"Both a label and a disk must be entered.");
2042 #endif
2043 		err = TRUE;
2044 		}
2045 	a = (*(fs->launch_mount.command) != '\0');
2046 	b = (*(fs->launch_umount.command) != '\0');
2047 	if (mounting_supported && !_GK.client_mode && ((a && !b) || (!a && b)))
2048 		{
2049 		gkrellm_config_message_dialog(_("Entry Error"),
2050 			_("Both mount and umount commands must be entered."));
2051 		err = TRUE;
2052 		}
2053 	if (   mounting_supported && !_GK.client_mode
2054 		&& fs->ejectable && !fs->fstab_mounting && !*fs->eject_device
2055 	   )
2056 		{
2057 		gkrellm_config_message_dialog(_("Entry Error"),
2058 			_("Missing ejectable device entry."));
2059 		err = TRUE;
2060 		}
2061 	if (err)
2062 		{
2063 		free_fsmon_strings(fs);
2064 		g_free(fs);
2065 		return;
2066 		}
2067 
2068 	model = gtk_tree_view_get_model(treeview);
2069 	secondary = GTK_TOGGLE_BUTTON(secondary_button)->active;
2070 	if (row_reference)
2071 		{
2072 		path = gtk_tree_row_reference_get_path(row_reference);
2073 		gtk_tree_model_get_iter(model, &iter, path);
2074 		indices = gtk_tree_path_get_indices(path);
2075 
2076 		/* Have a row ref, but if user changed secondary button, remove the
2077 		|  row ref node and set path NULL so iter will be set as function of
2078 		|  secondary.  row_ref will be invalidated below.
2079 		*/
2080 		if (indices[0] != secondary)
2081 			{
2082 			gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
2083 			path = NULL;
2084 			}
2085 		}
2086 	if (!path)
2087 		{
2088 		gtk_tree_model_iter_nth_child(model, &parent_iter, NULL, secondary);
2089 		gtk_tree_store_append(GTK_TREE_STORE(model), &iter, &parent_iter);
2090 		}
2091 	set_tree_store_model_data(GTK_TREE_STORE(model), &iter, fs);
2092 	if (!path)
2093 		{
2094 		/* If appending (not editing existing node) leave cursor at root level
2095 		|  and clear the entries anticipating another new entry.
2096 		*/
2097 		path = gtk_tree_path_new_from_string(secondary ? "1" : "0");
2098 		gtk_tree_view_set_cursor(treeview, path, NULL, FALSE);
2099 		gtk_tree_path_free(path);
2100 		reset_entries(secondary);
2101 		}
2102 	free_fsmon_strings(fs);
2103 	g_free(fs);
2104 	sync_fs_panels();
2105 	}
2106 
2107 static void
cb_delete(GtkWidget * widget)2108 cb_delete(GtkWidget *widget)
2109 	{
2110 	GtkTreeModel	*model;
2111 	GtkTreePath		*path;
2112 	GtkTreeIter		iter;
2113 	FSmon			*fs;
2114 
2115 	if (!row_reference)
2116 		return;
2117 	model = gtk_tree_view_get_model(treeview);
2118 	path = gtk_tree_row_reference_get_path(row_reference);
2119 	gtk_tree_model_get_iter(model, &iter, path);
2120 
2121 	gtk_tree_model_get(model, &iter, FSMON_COLUMN, &fs, -1);
2122 	gkrellm_alert_destroy(&fs->alert);
2123 
2124 	gtk_tree_store_remove(GTK_TREE_STORE(model), &iter);
2125 	reset_entries(FALSE);
2126 	sync_fs_panels();
2127 	}
2128 
2129 static void
cb_data_format(GtkWidget * widget,gpointer data)2130 cb_data_format(GtkWidget *widget, gpointer data)
2131 	{
2132 	GList			*list;
2133 	FSmon			*fs;
2134 	GkrellmDecal	*d;
2135 	gchar			*s, buf[256];
2136 	gint			h_data, h_label;
2137 	GtkWidget *entry;
2138 
2139 	entry = gtk_bin_get_child(GTK_BIN(data_format_combo_box));
2140 	s = gkrellm_gtk_entry_get_text(&entry);
2141 
2142 	/* In case Pango markup tags, don't accept line unless valid markup.
2143 	|  Ie, markup like <span ...> xxx </span> or <b> xxx </b>
2144 	*/
2145 
2146 	if (   strchr(s, '<') != NULL
2147 		&& !pango_parse_markup(s, -1, 0, NULL, NULL, NULL, NULL)
2148 	   )
2149 		return;
2150 
2151 	if (gkrellm_locale_dup_string(&data_format, s, &data_format_locale))
2152 		{
2153 		for (list = fs_mon_list; list; list = list->next)
2154 			{
2155 			fs = (FSmon *) list->data;
2156 			fs->label_decal->value = -1;	/* Force redraw */
2157 
2158 			d = fs->data_decal;
2159 
2160 			format_fs_data(fs, data_format_locale, buf, sizeof(buf));
2161 			gkrellm_text_markup_extents(d->text_style.font, buf, strlen(buf),
2162 					NULL, &h_data, NULL, NULL);
2163 			h_data += d->text_style.effect;
2164 			h_label = fs->label_decal->h;
2165 
2166 			/* Rebuild fs mon panels if new format string height extents
2167 			|  are wrong for current label/data decals.
2168 			*/
2169 			if (   (d->h >= h_label && h_data != d->h)
2170 			    || (d->h < h_label && h_data >= h_label)
2171 			   )
2172 				{
2173 				sync_fs_panels();
2174 				break;
2175 				}
2176 			if (d->h < h_label && h_data < h_label && d->h != h_data)
2177 				gkrellm_move_decal(fs->panel, d, d->x,
2178 						d->y + (d->h - h_data) / 2);
2179 			}
2180 		}
2181 	}
2182 
2183 static void
cb_auto_eject(GtkWidget * button,gpointer data)2184 cb_auto_eject(GtkWidget *button, gpointer data)
2185 	{
2186 	cdrom_auto_eject = GTK_TOGGLE_BUTTON(button)->active;
2187 	}
2188 
2189 static void
cb_binary_units(GtkWidget * button,gpointer data)2190 cb_binary_units(GtkWidget *button, gpointer data)
2191 	{
2192 	binary_units = GTK_TOGGLE_BUTTON(button)->active;
2193 	}
2194 
2195 static void
cb_check_interval(GtkWidget * widget,GtkSpinButton * spin)2196 cb_check_interval(GtkWidget *widget, GtkSpinButton *spin)
2197 	{
2198 	fs_check_timeout = gtk_spin_button_get_value_as_int(spin);
2199 	}
2200 
2201 static void
cb_nfs_check_interval(GtkWidget * widget,GtkSpinButton * spin)2202 cb_nfs_check_interval(GtkWidget *widget, GtkSpinButton *spin)
2203 	{
2204 	nfs_check_timeout = gtk_spin_button_get_value_as_int(spin);
2205 	}
2206 
2207   /* Allow destination drops only on depth 2 paths and don't allow drops from
2208   |  source depths of 1 (top level nodes).  Note: for some reason if I allow
2209   |  drops on depth 3 nodes (destination is on top of a second level node) I
2210   |  am not getting "drag_end" callbacks.
2211   */
2212 static gboolean
row_drop_possible(GtkTreeDragDest * drag_dest,GtkTreePath * path,GtkSelectionData * selection_data)2213 row_drop_possible(GtkTreeDragDest *drag_dest, GtkTreePath *path,
2214 			GtkSelectionData *selection_data)
2215 	{
2216 	GtkTreePath	*src_path;
2217 
2218 	if (!row_reference)
2219 		return FALSE;
2220 	src_path = gtk_tree_row_reference_get_path(row_reference);
2221 
2222 	if (   gtk_tree_path_get_depth(src_path) == 1
2223 		|| gtk_tree_path_get_depth(path) != 2
2224 	   )
2225 		return FALSE;
2226 
2227 	return (*original_row_drop_possible)(drag_dest, path,
2228 									selection_data);
2229 	}
2230 
2231   /* At each drag, divert the original Gtk row_drop_possible function to my
2232   |  custom row_drop_possible so I can control tree structure.  The original
2233   |  row_drop_possible function must be restored at "drag_end" else other
2234   |  monitors doing drag n' drop could get screwed.
2235   */
2236 static gboolean
cb_drag_begin(GtkWidget * widget,GdkDragContext * context,gpointer data)2237 cb_drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer data)
2238 	{
2239 	GtkTreeModel			*model;
2240 	GtkTreeDragDestIface	*dest_iface;
2241 
2242 	model = gtk_tree_view_get_model(treeview);
2243 	dest_iface = GTK_TREE_DRAG_DEST_GET_IFACE(GTK_TREE_DRAG_DEST(model));
2244 	if (!original_row_drop_possible)
2245 		original_row_drop_possible = dest_iface->row_drop_possible;
2246 	dest_iface->row_drop_possible = row_drop_possible;
2247 	return FALSE;
2248 	}
2249 
2250 static gboolean
cb_drag_end(GtkWidget * widget,GdkDragContext * context,gpointer data)2251 cb_drag_end(GtkWidget *widget, GdkDragContext *context, gpointer data)
2252 	{
2253 	GtkTreeModel			*model;
2254 	GtkTreeDragDestIface	*dest_iface;
2255 
2256 	model = gtk_tree_view_get_model(treeview);
2257 	dest_iface = GTK_TREE_DRAG_DEST_GET_IFACE(GTK_TREE_DRAG_DEST(model));
2258 	dest_iface->row_drop_possible = original_row_drop_possible;
2259 
2260 	reset_entries(FALSE);
2261 	sync_fs_panels();
2262 	return FALSE;
2263 	}
2264 
2265 
2266 static void
create_fs_panels_page(GtkWidget * vbox)2267 create_fs_panels_page(GtkWidget *vbox)
2268 	{
2269 	GtkWidget				*table;
2270 	GtkWidget				*hbox, *hbox1, *vbox1;
2271 	GtkWidget				*label;
2272 	GtkWidget				*scrolled;
2273 	GtkTreeModel			*model;
2274 	GtkCellRenderer			*renderer;
2275 	GList					*list;
2276 
2277 
2278 	hbox = gtk_hbox_new(FALSE, 0);
2279 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
2280 	vbox1 = gkrellm_gtk_framed_vbox(hbox, NULL, 1, TRUE, 0, 2);
2281 
2282 	table = gtk_table_new(2, 2, FALSE);
2283 	gtk_box_pack_start(GTK_BOX(vbox1), table, FALSE, FALSE, 0);
2284 
2285 	label = gtk_label_new(_("Label"));
2286 	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 0, 1,
2287 				GTK_SHRINK, GTK_SHRINK, 2, 1);
2288 	label_entry = gtk_entry_new();
2289 //	gtk_entry_set_max_length(GTK_ENTRY(label_entry), 16);
2290 	gtk_widget_set_size_request(label_entry, 100, -1);
2291 	gtk_table_attach_defaults(GTK_TABLE(table), label_entry, 1, 2, 0, 1);
2292 
2293 #if !defined(WIN32)
2294 	label = gtk_label_new(_("Mount Point"));
2295 #else
2296 	label = gtk_label_new("Disk");
2297 #endif
2298 	gtk_table_attach(GTK_TABLE(table), label, 0, 1, 1, 2,
2299 				GTK_SHRINK, GTK_SHRINK, 2, 1);
2300 	dir_combo_box = gtk_combo_box_entry_new_text();
2301 	gtk_table_attach_defaults(GTK_TABLE(table), dir_combo_box, 1, 2, 1, 2);
2302 	for (list = fstab_list; list; list = list->next)
2303 		{
2304 		gtk_combo_box_append_text(GTK_COMBO_BOX(dir_combo_box),
2305 				((Mount *)list->data)->directory);
2306 		}
2307 	gtk_combo_box_set_active(GTK_COMBO_BOX(dir_combo_box), -1);
2308 	g_signal_connect(G_OBJECT(GTK_COMBO_BOX(dir_combo_box)),
2309 			"changed", G_CALLBACK(cb_combo_changed), NULL);
2310 
2311 	vbox1 = gtk_vbox_new(FALSE, 0);
2312 	gtk_box_pack_start(GTK_BOX(hbox), vbox1, FALSE, FALSE, 0);
2313 	hbox = gtk_hbox_new(FALSE, 0);
2314 	gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 0);
2315 
2316 	gkrellm_gtk_check_button_connected(hbox, &secondary_button, 0,
2317 					TRUE, TRUE, 2, cb_secondary_button_clicked, NULL,
2318 					_("Secondary"));
2319 
2320 
2321 	if (mounting_supported)
2322 		{
2323 		gkrellm_gtk_check_button_connected(hbox, &show_button, 0,
2324 					TRUE, TRUE, 2, NULL, NULL,
2325 					_("Show if mounted"));
2326 		gtk_widget_set_sensitive(show_button, FALSE);
2327 		if (!_GK.client_mode)
2328 			{
2329 			gkrellm_gtk_check_button_connected(vbox1, &mounting_button, 0,
2330 						FALSE, FALSE, 2, cb_mount_button_clicked, NULL,
2331 						_("Enable /etc/fstab mounting"));
2332 			gtk_widget_set_sensitive(mounting_button, FALSE);
2333 			}
2334 		}
2335 
2336 	hbox = gtk_hbox_new(FALSE, 0);
2337 	gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
2338 
2339 	if (ejecting_supported && !_GK.client_mode)
2340 		{
2341 		vbox1 = gkrellm_gtk_framed_vbox(hbox, NULL, 1, FALSE, 0, 2);
2342 
2343 		gkrellm_gtk_check_button_connected(vbox1, &ejectable_button, 0,
2344 					FALSE, FALSE, 0, cb_ejectable_button_clicked, NULL,
2345 					_("Ejectable"));
2346 
2347 		if (mounting_supported)
2348 			{
2349 			hbox1 = gtk_hbox_new(FALSE, 0);
2350 			gtk_box_pack_start(GTK_BOX(vbox1), hbox1, FALSE, FALSE, 0);
2351 			label = gtk_label_new(_("Device"));
2352 			gtk_box_pack_start(GTK_BOX(hbox1), label, FALSE, FALSE, 2);
2353 			device_entry = gtk_entry_new();
2354 			gtk_entry_set_max_length(GTK_ENTRY(device_entry), 64);
2355 			gtk_widget_set_size_request(device_entry, 100, -1);
2356 			gtk_box_pack_start(GTK_BOX(hbox1), device_entry,
2357 					FALSE, FALSE, 2);
2358 			}
2359 		}
2360 
2361 	if (mounting_supported && !_GK.client_mode)
2362 		{
2363 		vbox1 = gkrellm_gtk_framed_vbox(hbox, NULL, 1, TRUE, 0, 2);
2364 		table = gkrellm_gtk_launcher_table_new(vbox1, 1);  /* Won't have tooltip */
2365 		gkrellm_gtk_config_launcher(table, 0, &mount_entry,
2366 					NULL, _("mount"), NULL);
2367 		gkrellm_gtk_config_launcher(table, 1, &umount_entry,
2368 					NULL, _("umount"), NULL);
2369 		}
2370 	hbox = gtk_hbox_new(FALSE, 2);
2371 	gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
2372 
2373 	vbox1 = gtk_vbox_new(FALSE, 0);
2374 	gtk_box_pack_end(GTK_BOX(hbox), vbox1, FALSE, FALSE, 5);
2375 
2376 	gkrellm_gtk_button_connected(vbox1, &new_apply_button, FALSE, FALSE, 4,
2377 			add_cb, NULL, GTK_STOCK_NEW);
2378 	GTK_WIDGET_SET_FLAGS(new_apply_button, GTK_CAN_DEFAULT);
2379 	gtk_widget_grab_default(new_apply_button);
2380 
2381 	gkrellm_gtk_button_connected(vbox1, &delete_button, FALSE, FALSE, 4,
2382 			cb_delete, NULL, GTK_STOCK_DELETE);
2383 	gtk_widget_set_sensitive(delete_button, FALSE);
2384 
2385 	gkrellm_gtk_alert_button(vbox1, &alert_button, FALSE, FALSE, 4, FALSE,
2386 			cb_set_alert, NULL);
2387 	gtk_widget_set_sensitive(alert_button, FALSE);
2388 
2389 	scrolled = gtk_scrolled_window_new(NULL, NULL);
2390 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
2391 			GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2392 	gtk_box_pack_end(GTK_BOX(hbox), scrolled, TRUE, TRUE, 0);
2393 
2394 	model = create_model();
2395 
2396 	treeview = GTK_TREE_VIEW(gtk_tree_view_new_with_model(model));
2397 	g_object_unref(G_OBJECT(model));
2398 	gtk_tree_view_set_rules_hint(treeview, TRUE);
2399 	gtk_tree_view_set_reorderable(treeview, TRUE);
2400 	g_signal_connect(G_OBJECT(treeview), "drag_begin",
2401 				G_CALLBACK(cb_drag_begin), NULL);
2402 	g_signal_connect(G_OBJECT(treeview), "drag_end",
2403 				G_CALLBACK(cb_drag_end), NULL);
2404 
2405 	renderer = gtk_cell_renderer_text_new();
2406 //	g_object_set(G_OBJECT(renderer), "xalign", 0.0, NULL);
2407 	gtk_tree_view_insert_column_with_attributes(treeview, -1, _("Label"),
2408 				renderer,
2409 				"text", NAME_COLUMN, NULL);
2410 	renderer = gtk_cell_renderer_text_new();
2411 	gtk_tree_view_insert_column_with_attributes(treeview, -1, _("Mount Point"),
2412 				renderer,
2413 				"text", MOUNT_POINT_COLUMN,
2414 //				"visible", VISIBLE_COLUMN,
2415 				NULL);
2416 
2417 	renderer = gtk_cell_renderer_pixbuf_new();
2418 	gtk_tree_view_insert_column_with_attributes(treeview, -1, "",
2419 				renderer,
2420 				"pixbuf", IMAGE_COLUMN,
2421 				NULL);
2422 
2423 	gtk_container_add(GTK_CONTAINER(scrolled), GTK_WIDGET(treeview));
2424 
2425 	selection = gtk_tree_view_get_selection(treeview);
2426 	gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);
2427 	g_signal_connect(G_OBJECT(selection), "changed",
2428 				G_CALLBACK(cb_tree_selection_changed), NULL);
2429 	}
2430 
2431 
2432 static gchar *fs_info_text0[] =
2433 {
2434 N_("<h>Mounting\n"),
2435 N_("Enter file system mount points to monitor and enter a label to describe\n"
2436 "the mount point.  The krell shows the ratio of blocks used to total blocks\n"
2437 "available.  Mounting commands can be enabled for mount points in one\n"
2438 "of two ways:\n\n"),
2439 
2440 N_("<b>\t1) Mounting using /etc/fstab: "),
2441 
2442 N_("If a mount point is in your\n"
2443 "\t/etc/fstab and you have mount permission then mount and umount\n"
2444 "\tcommands can be enabled and executed for that mount point simply\n"
2445 "\tby checking the \"Enable /etc/fstab mounting\" option.\n"
2446 "\tMount table entries in /etc/fstab need the \"user\" or \"owner\" option\n"
2447 "\tset to grant this permission unless GKrellM is run as root.\n"
2448 "\tFor example, if you run GKrellM as a normal user and you want\n"
2449 "\tto be able to mount your floppy, your /etc/fstab could have\n"
2450 "\teither of:\n"),
2451 
2452 N_("<i>\t\t/dev/fd0 /mnt/floppy ext2 user,noauto,rw,exec 0 0\n"),
2453 N_("\tor\n"),
2454 N_("<i>\t\t/dev/fd0 /mnt/floppy ext2 user,defaults 0 0\n\n"),
2455 
2456 N_("<b>\t2) Mounting using custom commands: "),
2457 N_("If GKrellM is run as root or if\n"
2458 "\tyou have sudo permission to run the mount commands, then a custom\n"
2459 "\tmount command can be entered into the \"mount command\" entry\n"
2460 "\tbox.  A umount command must also be entered if you choose this\n"
2461 "\tmethod.  Example mount and umount entries using sudo:\n"),
2462 
2463 N_("<i>\t\tsudo /bin/mount -t msdos /dev/fd0 /mnt/A\n"),
2464 N_("<i>\t\tsudo /bin/umount /mnt/A\n"),
2465 
2466 N_("\tNotes: the mount point specified in a custom mount command\n"
2467    "\t(/mnt/A in this example) must be the same as entered in the\n"
2468    "\t\"Mount Point\" entry.  You should have the NOPASSWD option set\n"
2469    "\tin /etc/sudoers if using sudo.\n\n"),
2470 
2471 N_("<h>Primary and Secondary Monitors\n"), /* xgettext:no-c-format */
2472 N_("File system monitors can be created as primary (always visible)\n"
2473 	"or secondary which can be hidden and then shown when they are of\n"
2474 	"interest.  For example, you might make primary file system monitors\n"
2475 	"for root, home, or user so they will be always visible, but make\n"
2476 	"secondary monitors for less frequently used mount points such as\n"
2477 	"floppy, zip, backup partitions, foreign file system types, etc.\n"
2478 	"Secondary FS monitors can also be configured to always be visible if they\n"
2479 	"are mounted by checking the \"Show if mounted\" option.   Using this\n"
2480 	"feature you can show the secondary group, mount a file system, and have\n"
2481 	"that FS monitor remain visible even when the secondary group is hidden.\n"
2482 	"A standard cdrom mount will show as 100% full but a monitor for it\n"
2483 	"could be created with mounting enabled just to have the\n"
2484 	"mount/umount convenience.\n\n")
2485 };
2486 
2487 static gchar *fs_info_text1[] =
2488 {
2489 N_("<h>Panel Labels\n"),
2490 N_("Substitution variables for the format string for file system panels:\n"),
2491 N_("\t$t    total capacity\n"),
2492 N_("\t$u    used space\n"),
2493 N_("\t$f    free space\n"),
2494 N_("\t$U    used %,\n"),
2495 N_("\t$F    free %\n"),
2496 N_("\t$l    the panel label\n"),
2497 #if !defined(WIN32)
2498 N_("\t$D    the mount point\n"),
2499 #else
2500 N_("\t$D    the disk\n"),
2501 #endif
2502 "\n",
2503 N_("Substitution variables may be used in alert commands.\n"),
2504 "\n",
2505 N_("<h>Mouse Button Actions:\n"),
2506 N_("<b>\tLeft "),
2507 N_("click on a panel to scroll a programmable display\n"),
2508 N_("\t\tof file system capacities (default is total and free space).\n"),
2509 N_("<b>\tWheel "),
2510 N_("Shows and hides the secondary file system monitors.\n")
2511 };
2512 
2513 static void
fs_tab_create(GtkWidget * tab_vbox)2514 fs_tab_create(GtkWidget *tab_vbox)
2515 	{
2516 	GtkWidget		*tabs;
2517 	GtkWidget		*vbox, *vbox1;
2518 	GtkWidget		*text;
2519 	gint			i;
2520 
2521 	row_reference = NULL;
2522 	refresh_fstab_list();
2523 
2524 	tabs = gtk_notebook_new();
2525 	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs), GTK_POS_TOP);
2526 	gtk_box_pack_start(GTK_BOX(tab_vbox), tabs, TRUE, TRUE, 0);
2527 
2528 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Panels"));
2529 	create_fs_panels_page(vbox);
2530 
2531 //	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Primary"));
2532 //	fill_fs_tab(vbox, &primary_widgets);
2533 
2534 //	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Secondary"));
2535 //	fill_fs_tab(vbox, &secondary_widgets);
2536 
2537 /* --Setup tab */
2538 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Setup"));
2539 
2540 	vbox1 = gkrellm_gtk_category_vbox(vbox,
2541 				_("Options"),
2542 				4, 0, TRUE);
2543 	gkrellm_gtk_check_button_connected(vbox1, NULL,
2544 			binary_units, FALSE, FALSE, 0,
2545 			cb_binary_units, NULL,
2546 			_("Use binary units (MiB, GiG) for reporting disk capacities."));
2547 
2548 	if (mounting_supported && ejecting_supported && !_GK.client_mode)
2549 		gkrellm_gtk_check_button_connected(vbox1, NULL,
2550 				cdrom_auto_eject, FALSE, FALSE, 0,
2551 				cb_auto_eject, NULL,
2552 				_("Auto eject when ejectable devices are unmounted"));
2553 
2554 	if (!_GK.client_mode)
2555 		{
2556 		vbox1 = gkrellm_gtk_framed_vbox_end(vbox, NULL, 4, FALSE, 0, 2);
2557 		gkrellm_gtk_spin_button(vbox1, NULL,
2558 			(gfloat) fs_check_timeout,
2559 			2.0, 15.0, 1.0, 5.0, 0 /*digits*/, 0 /*width*/,
2560 			cb_check_interval, NULL, FALSE,
2561 			_("Seconds between data updates for local mounted file systems"));
2562 		gkrellm_gtk_spin_button(vbox1, NULL,
2563 			(gfloat) nfs_check_timeout,
2564 			5.0, 60.0, 1.0, 5.0, 0, 0,
2565 			cb_nfs_check_interval, NULL, FALSE,
2566 			_("Seconds between data updates for remote mounted file systems"));
2567 		}
2568 
2569 	vbox1 = gkrellm_gtk_category_vbox(vbox,
2570 				_("Format String for Panel Labels"),
2571 				4, 0, TRUE);
2572 	data_format_combo_box = gtk_combo_box_entry_new_text();
2573 	gtk_box_pack_start(GTK_BOX(vbox1), data_format_combo_box, FALSE, FALSE, 2);
2574 	gtk_combo_box_append_text(GTK_COMBO_BOX(data_format_combo_box), data_format);
2575 	gtk_combo_box_append_text(GTK_COMBO_BOX(data_format_combo_box), DEFAULT_DATA_FORMAT);
2576 	gtk_combo_box_append_text(GTK_COMBO_BOX(data_format_combo_box), ALT1_DATA_FORMAT);
2577 	gtk_combo_box_append_text(GTK_COMBO_BOX(data_format_combo_box), ALT2_DATA_FORMAT);
2578 	gtk_combo_box_set_active(GTK_COMBO_BOX(data_format_combo_box), 0);
2579 	g_signal_connect(G_OBJECT(GTK_COMBO_BOX(data_format_combo_box)), "changed",
2580 			G_CALLBACK(cb_data_format), NULL);
2581 
2582 /* --Info tab */
2583 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Info"));
2584 	text = gkrellm_gtk_scrolled_text_view(vbox, NULL,
2585 				GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
2586 	if (mounting_supported && !_GK.client_mode)
2587 		for (i = 0; i < sizeof(fs_info_text0)/sizeof(gchar *); ++i)
2588 			gkrellm_gtk_text_view_append(text, _(fs_info_text0[i]));
2589 	for (i = 0; i < sizeof(fs_info_text1)/sizeof(gchar *); ++i)
2590 		gkrellm_gtk_text_view_append(text, _(fs_info_text1[i]));
2591 	}
2592 
2593 
2594 
2595 static GkrellmMonitor	monitor_fs =
2596 	{
2597 	N_("File System"),	/* Name, for config tab.	*/
2598 	MON_FS,				/* Id,  0 if a plugin		*/
2599 	fs_create,			/* The create function		*/
2600 	fs_update,			/* The update function		*/
2601 	fs_tab_create,		/* The config tab create function	*/
2602 	NULL,				/* Instant config */
2603 
2604 	fs_config_save,		/* Save user conifg			*/
2605 	fs_config_load,		/* Load user config			*/
2606 	FS_CONFIG_KEYWORD,	/* config keyword			*/
2607 
2608 	NULL,				/* Undef 2	*/
2609 	NULL,				/* Undef 1	*/
2610 	NULL,				/* Undef 0	*/
2611 
2612 	0,					/* insert_before_id - place plugin before this mon */
2613 
2614 	NULL,				/* Handle if a plugin, filled in by GKrellM		*/
2615 	NULL				/* path if a plugin, filled in by GKrellM		*/
2616 	};
2617 
2618 GkrellmMonitor *
gkrellm_init_fs_monitor(void)2619 gkrellm_init_fs_monitor(void)
2620 	{
2621 	monitor_fs.name = _(monitor_fs.name);
2622 	style_id = gkrellm_add_meter_style(&monitor_fs, FS_STYLE_NAME);
2623 	gkrellm_locale_dup_string(&data_format, DEFAULT_DATA_FORMAT,
2624 				&data_format_locale);
2625 
2626 	mon_fs = &monitor_fs;
2627 	if (setup_fs_interface())
2628 		{
2629 		refresh_fstab_list();
2630 		refresh_mounts_list();
2631 		return &monitor_fs;
2632 		}
2633 	return NULL;
2634 	}
2635