1 /* GKrellM
2 |  Copyright (C) 1999-2019 Bill Wilson
3 |
4 |  Author:  Bill Wilson    billw@gkrellm.net
5 |  Latest versions might be found at:  http://gkrellm.net
6 |
7 |
8 |  GKrellM is free software: you can redistribute it and/or modify it
9 |  under the terms of the GNU General Public License as published by
10 |  the Free Software Foundation, either version 3 of the License, or
11 |  (at your option) any later version.
12 |
13 |  GKrellM is distributed in the hope that it will be useful, but WITHOUT
14 |  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 |  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
16 |  License for more details.
17 |
18 |  You should have received a copy of the GNU General Public License
19 |  along with this program. If not, see http://www.gnu.org/licenses/
20 |
21 |
22 |  Additional permission under GNU GPL version 3 section 7
23 |
24 |  If you modify this program, or any covered work, by linking or
25 |  combining it with the OpenSSL project's OpenSSL library (or a
26 |  modified version of that library), containing parts covered by
27 |  the terms of the OpenSSL or SSLeay licenses, you are granted
28 |  additional permission to convey the resulting work.
29 |  Corresponding Source for a non-source form of such a combination
30 |  shall include the source code for the parts of OpenSSL used as well
31 |  as that of the covered work.
32 */
33 
34 #include "gkrellm.h"
35 #include "gkrellm-private.h"
36 
37 #if defined(WIN32)
38 
39 #define DEFAULT_CLOCK_FORMAT "%#I:%M <span foreground=\"$A\"><small>%S</small></span>"
40 #define ALT1_CLOCK_FORMAT "%#I:%M <span foreground=\"$A\"><small>%p</small></span>"
41 #define ALT2_CLOCK_FORMAT "%#H:%M <span foreground=\"$A\"><small>%S</small></span>"
42 #define DEFAULT_CAL_FORMAT "%a <span foreground=\"$A\"><big><big>%#d</big></big></span> %b"
43 #define ALT1_CAL_FORMAT "<big>%a %b <span foreground=\"$A\">%#d</span></big>"
44 #define ALT2_CAL_FORMAT "%a <span foreground=\"cyan2\"><span font_desc=\"16.5\"><i>%#d</i></span></span> %b"
45 
46 #else
47 
48 #define DEFAULT_CLOCK_FORMAT \
49 		_("%l:%M <span foreground=\"$A\"><small>%S</small></span>")
50 #define ALT1_CLOCK_FORMAT "%l:%M <span foreground=\"$A\"><small>%p</small></span>"
51 #define ALT2_CLOCK_FORMAT "%k:%M <span foreground=\"$A\"><small>%S</small></span>"
52 
53 #define DEFAULT_CAL_FORMAT \
54 		_("%a <span foreground=\"$A\"><big><big>%e</big></big></span> %b")
55 #define ALT1_CAL_FORMAT  "<big>%a %b <span foreground=\"$A\">%e</span></big>"
56 #define ALT2_CAL_FORMAT "%a <span foreground=\"cyan2\"><span font_desc=\"16.5\"><i>%e</i></span></span> %b"
57 
58 #endif
59 
60 
61 static GkrellmMonitor
62 				*mon_clock,
63 				*mon_cal;
64 
65 static GkrellmPanel
66 				*pclock,
67 				*pcal;
68 
69 static GtkWidget
70 				*cal_vbox,
71 				*clock_vbox;
72 
73 static GkrellmDecal
74 				*d_cal,
75 				*d_clock;
76 
77 
78 static GkrellmLauncher
79 				clock_launch,
80 				cal_launch;
81 
82 static gboolean	cal_enable,
83 				clock_enable,
84 				loop_chime_enable;
85 
86 
87 static gchar	*cal_format,
88 				*clock_format;
89 
90 static gchar	*cal_alt_color_string,
91 				*clock_alt_color_string;
92 
93 static gint		clock_style_id,
94 				cal_style_id;
95 
96 
97 static gchar	*hour_chime_command,
98 				*quarter_chime_command;
99 static gboolean	chime_block;
100 
101 typedef struct
102 	{
103 	gchar	*command;
104 	gint	count;
105 	}
106 	ChimeData;
107 
108 
109 struct tm		gkrellm_current_tm;
110 
111 
112 
113 struct tm *
gkrellm_get_current_time(void)114 gkrellm_get_current_time(void)
115 	{
116 	return &gkrellm_current_tm;
117 	}
118 
119 
120 static gpointer
chime_func(gpointer data)121 chime_func(gpointer data)
122 	{
123 	ChimeData	*chime = (ChimeData *)data;
124 	gint		counter;
125 
126 	if (strlen(chime->command))
127 		{
128 		if (chime->count > 12)
129 			chime->count -= 12;
130 
131 		for (counter = 0; counter < chime -> count; counter ++)
132 			g_spawn_command_line_sync(chime->command,
133 						NULL, NULL, NULL, NULL /* GError */);
134 		}
135 	g_free(chime->command);
136 	g_free(chime);
137 	return NULL;
138 	}
139 
140 static void
get_color_name(GdkColor * color,gchar ** color_string)141 get_color_name(GdkColor *color, gchar **color_string)
142 	{
143 	gchar	*cstring;
144 
145 	cstring = g_strdup_printf("#%2.2x%2.2x%2.2x",
146 			(color->red >> 8) & 0xff,
147 			(color->green >> 8) & 0xff,
148 			(color->blue >> 8) & 0xff );
149 	gkrellm_dup_string(color_string, cstring);
150 	g_free(cstring);
151 	}
152 
153 static void
format_alt_color(gchar * src_string,gchar * buf,gint size,gchar * alt_color)154 format_alt_color(gchar *src_string, gchar *buf, gint size, gchar *alt_color)
155 	{
156 	gint		len;
157 	gchar		*s;
158 
159 	if (!buf || size < 1)
160 		return;
161 	--size;
162 	*buf = '\0';
163 	if (!src_string)
164 		return;
165 
166 	for (s = src_string; *s != '\0' && size > 0; ++s)
167 		{
168 		len = 1;
169 		if (*s == '$' && *(s + 1) != '\0')
170 			{
171 			switch(*(s + 1))
172 				{
173 				case 'A':
174 					len = snprintf(buf, size, "%s", alt_color);
175 					break;
176 				default:
177 					*buf = *s;
178 					if (size > 1)
179 						{
180 						*(buf + 1) = *(s + 1);
181 						++len;
182 						}
183 					break;
184 				}
185 			++s;
186 			}
187 		else
188 			*buf = *s;
189 		size -= len;
190 		buf += len;
191 		}
192 	*buf = '\0';
193 	}
194 
195 static gchar *
strftime_format(gchar * format,gchar * alt_color)196 strftime_format(gchar *format, gchar *alt_color)
197 	{
198 	struct tm	*t;
199 	gchar		*locale_format = NULL;
200 	gchar		buf1[512], buf2[512];
201 
202 	if (_GK.client_mode)
203 		t = gkrellm_client_server_time();
204 	else
205 		t = &gkrellm_current_tm;
206 
207 	locale_format = g_locale_from_utf8(format, -1, NULL, NULL, NULL);
208 	if (!locale_format)
209 		locale_format = g_strdup(format);
210 	strftime(buf1, sizeof(buf1), locale_format, t);
211 	g_free (locale_format);
212 	format_alt_color(buf1, buf2, sizeof(buf2), alt_color);
213 
214 // g_debug("%s\n", buf2);
215 
216 	return g_locale_to_utf8 (buf2, -1, NULL, NULL, NULL);
217 	}
218 
219 static gint
expose_event(GtkWidget * widget,GdkEventExpose * ev)220 expose_event(GtkWidget *widget, GdkEventExpose *ev)
221 	{
222 	GdkPixmap	*pixmap = NULL;
223 
224 	if (widget == pcal->drawing_area)
225 		pixmap = pcal->pixmap;
226 	else if (widget == pclock->drawing_area)
227 		pixmap = pclock->pixmap;
228 	if (pixmap)
229 		gdk_draw_drawable(widget->window, gkrellm_draw_GC(1), pixmap,
230 				ev->area.x, ev->area.y, ev->area.x, ev->area.y,
231 				ev->area.width, ev->area.height);
232 	return FALSE;
233 	}
234 
235 static gint
cb_panel_press(GtkWidget * widget,GdkEventButton * ev)236 cb_panel_press(GtkWidget *widget, GdkEventButton *ev)
237 	{
238 	if (ev->button == 3)
239 		gkrellm_open_config_window(mon_clock);
240 	return FALSE;
241 	}
242 
243 static void
cal_visibility(void)244 cal_visibility(void)
245 	{
246 	if (cal_enable)
247 		{
248 		gkrellm_panel_show(pcal);
249 		gkrellm_spacers_show(mon_cal);
250 		}
251 	else
252 		{
253 		gkrellm_panel_hide(pcal);
254 		gkrellm_spacers_hide(mon_cal);
255 		}
256 	}
257 
258 static void
create_calendar_panel(GtkWidget * vbox,gint first_create)259 create_calendar_panel(GtkWidget *vbox, gint first_create)
260 	{
261 	GkrellmStyle		*style;
262 	GkrellmTextstyle	*ts;
263 	gchar				*cal_string;
264 
265 	if (first_create)
266 		pcal = gkrellm_panel_new0();
267 	style = gkrellm_meter_style(cal_style_id);
268 
269 	ts = gkrellm_meter_alt_textstyle(cal_style_id);
270 	get_color_name(&ts->color, &cal_alt_color_string);
271 
272 	cal_string = strftime_format(cal_format, cal_alt_color_string);
273 	d_cal = gkrellm_create_decal_text_markup(pcal, cal_string,
274 				gkrellm_meter_textstyle(cal_style_id), style, -1, -1, -1);
275 	g_free(cal_string);
276 
277 	gkrellm_panel_configure(pcal, NULL, style);
278 	gkrellm_panel_create(vbox, mon_cal, pcal);
279 
280 	if (first_create)
281 		{
282 		/* Help the motion out hack. If starting a move in host panel and mouse
283 		|  jerks into the pclock/pcal drawing areas, we stop moving unless:
284 		*/
285 		extern void gkrellm_motion(GtkWidget *, GdkEventMotion *, gpointer);
286 
287 		g_signal_connect(G_OBJECT(pcal->drawing_area), "motion_notify_event",
288 				G_CALLBACK(gkrellm_motion), NULL);
289 
290 		g_signal_connect(G_OBJECT (pcal->drawing_area), "expose_event",
291 				G_CALLBACK(expose_event), NULL);
292 		g_signal_connect(G_OBJECT(pcal->drawing_area), "button_press_event",
293 				G_CALLBACK(cb_panel_press), NULL);
294 		}
295 	gkrellm_setup_launcher(pcal, &cal_launch, METER_PANEL_TYPE, 0);
296 
297 	cal_visibility();
298 	}
299 
300 static void
draw_cal(void)301 draw_cal(void)
302 	{
303 	gchar			*utf8, *cal_string;
304 	gint			w, h;
305 
306 	if (!cal_enable)
307 		return;
308 
309 	cal_string = strftime_format(cal_format, cal_alt_color_string);
310 	if (!g_utf8_validate(cal_string, -1, NULL))
311 		{
312 	    if ((utf8 = g_locale_to_utf8(cal_string, -1, NULL, NULL, NULL))
313 				!= NULL)
314 			{
315 			g_free(cal_string);
316 			cal_string = utf8;
317 			}
318 		}
319 
320 	/* Get string extents in case a string change => need to resize the
321 	|  panel.  A string change can also change the decal y_ink (possibly
322 	|  without changing decal size).
323 	*/
324 	gkrellm_text_markup_extents(d_cal->text_style.font,
325 			cal_string, strlen(cal_string), &w, &h, NULL, &d_cal->y_ink);
326 
327 	w += d_cal->text_style.effect;
328 	if (h + d_cal->text_style.effect != d_cal->h)
329 		{
330 		gkrellm_panel_destroy(pcal);
331 		create_calendar_panel(cal_vbox, TRUE);
332 		}
333 
334 	gkrellm_draw_decal_markup(pcal, d_cal, cal_string);
335 	gkrellm_decal_text_set_offset(d_cal, (d_cal->w - w) / 2, 0);
336 
337 	gkrellm_draw_panel_layers(pcal);
338 	g_free(cal_string);
339 	}
340 
341 static void
create_calendar(GtkWidget * vbox,gint first_create)342 create_calendar(GtkWidget *vbox, gint first_create)
343 	{
344 	cal_vbox = vbox;
345 	create_calendar_panel(vbox, first_create);
346 	draw_cal();
347 	}
348 
349 static void
clock_visibility(void)350 clock_visibility(void)
351 	{
352 	if (clock_enable)
353 		{
354 		gkrellm_panel_show(pclock);
355 		gkrellm_spacers_show(mon_clock);
356 		}
357 	else
358 		{
359 		gkrellm_panel_hide(pclock);
360 		gkrellm_spacers_hide(mon_clock);
361 		}
362 	}
363 
364 static void
create_clock_panel(GtkWidget * vbox,gint first_create)365 create_clock_panel(GtkWidget *vbox, gint first_create)
366 	{
367 	GkrellmStyle		*style;
368 	GkrellmTextstyle	*ts;
369 	gchar				*clock_string;
370 
371 	if (first_create)
372 		pclock = gkrellm_panel_new0();
373 	style = gkrellm_meter_style(clock_style_id);
374 
375 	ts = gkrellm_meter_alt_textstyle(clock_style_id);
376 	get_color_name(&ts->color, &clock_alt_color_string);
377 
378 	clock_string = strftime_format(clock_format, clock_alt_color_string);
379 	d_clock = gkrellm_create_decal_text_markup(pclock, clock_string,
380 				gkrellm_meter_textstyle(clock_style_id), style, -1, -1, -1);
381 	g_free(clock_string);
382 
383 	gkrellm_panel_configure(pclock, NULL, style);
384 	gkrellm_panel_create(vbox, mon_clock, pclock);
385 
386 	if (first_create)
387 		{
388 		g_signal_connect(G_OBJECT (pclock->drawing_area), "expose_event",
389 				G_CALLBACK(expose_event), NULL);
390 		g_signal_connect(G_OBJECT(pclock->drawing_area), "button_press_event",
391 				G_CALLBACK(cb_panel_press), NULL);
392 		}
393 	gkrellm_setup_launcher(pclock, &clock_launch, METER_PANEL_TYPE, 0);
394 
395 	clock_visibility();
396 	}
397 
398 static void
draw_clock(gboolean check_size)399 draw_clock(gboolean check_size)
400 	{
401 	gchar	*utf8, *clock_string;
402 	gint	w,h;
403 
404 	if (!clock_enable)
405 		return;
406 
407 	clock_string = strftime_format(clock_format, clock_alt_color_string);
408 	if (!g_utf8_validate(clock_string, -1, NULL))
409 		{
410 		if ((utf8 = g_locale_to_utf8(clock_string, -1, NULL, NULL, NULL))
411 				!= NULL)
412 			{
413 			g_free(clock_string);
414 			clock_string = utf8;
415 			}
416 		}
417 
418 	if (check_size)
419 		{
420 		/* Get string extents in case a string change => need to resize the
421 		|  panel.  A string change can also change the decal y_ink (possibly
422 		|  without changing decal size).
423 		*/
424 		gkrellm_text_markup_extents(d_clock->text_style.font,
425 				clock_string, strlen(clock_string),
426 				&w, &h, NULL, &d_clock->y_ink);
427 		w += d_clock->text_style.effect;
428 		if (h + d_clock->text_style.effect != d_clock->h)
429 			{
430 			gkrellm_panel_destroy(pclock);
431 			create_clock_panel(clock_vbox, TRUE);
432 			}
433 		gkrellm_decal_text_set_offset(d_clock, (d_clock->w - w) / 2, 0);
434 		}
435 	gkrellm_draw_decal_markup(pclock, d_clock, clock_string);
436 	gkrellm_draw_panel_layers(pclock);
437 	g_free(clock_string);
438 	}
439 
440 
441 static void
create_clock(GtkWidget * vbox,gint first_create)442 create_clock(GtkWidget *vbox, gint first_create)
443 	{
444 	clock_vbox = vbox;
445 	create_clock_panel(vbox, first_create);
446 	draw_clock(TRUE);
447 	}
448 
449 static void
update_clock(void)450 update_clock(void)
451 	{
452 	GThread			*gth;
453 	struct tm		*ptm;
454 	static gint		min_prev, hour_prev = -1, sec_prev = -1;
455 	ChimeData		*chime;
456 	gboolean		hour_tick;
457 
458 	if (_GK.client_mode)
459 		{
460 		ptm = gkrellm_client_server_time();
461 		if (sec_prev == ptm->tm_sec)
462 			return;
463 		sec_prev = ptm->tm_sec;
464 		}
465 	else
466 		{
467 		if (!GK.second_tick)
468 			return;
469 		ptm = &gkrellm_current_tm;
470 		}
471 
472 	hour_tick = (ptm->tm_hour != hour_prev);
473 	if (   ptm->tm_min != min_prev
474 		|| hour_tick
475 	   )
476 		{
477 		draw_cal();
478 		if (ptm->tm_hour != hour_prev && hour_prev != -1)
479 			{
480 			if (!chime_block && hour_chime_command && *hour_chime_command)
481 				{
482 				chime = g_new0(ChimeData, 1);
483 				chime -> command = g_strdup(hour_chime_command);
484 				chime -> count = loop_chime_enable ? ptm->tm_hour : 1;
485 				gth = g_thread_new("chime", chime_func, chime);
486 				g_thread_unref(gth);
487 				}
488 			}
489 		else
490 			{
491 			if (   !chime_block && (ptm->tm_min % 15) == 0
492 				&& quarter_chime_command && *quarter_chime_command
493 			   )
494 				{
495 				chime = g_new0(ChimeData, 1);
496 				chime -> command = g_strdup(quarter_chime_command);
497 				chime -> count = 1;
498 				gth = g_thread_new("chime", chime_func, chime);
499 				g_thread_unref(gth);
500 				}
501 			}
502 		}
503 	draw_clock(hour_tick);
504 	min_prev = ptm->tm_min;
505 	hour_prev = ptm->tm_hour;
506 	}
507 
508 
509 #define	CLOCK_CONFIG_KEYWORD	"clock_cal"
510 
511 static void
save_clock_cal_config(FILE * f)512 save_clock_cal_config(FILE *f)
513 	{
514 	fprintf(f, "%s clock_launch %s\n", CLOCK_CONFIG_KEYWORD,
515 				clock_launch.command);
516 	fprintf(f, "%s clock_tooltip %s\n", CLOCK_CONFIG_KEYWORD,
517 				clock_launch.tooltip_comment);
518 	fprintf(f, "%s cal_launch %s\n", CLOCK_CONFIG_KEYWORD,
519 				cal_launch.command);
520 	fprintf(f, "%s cal_tooltip %s\n", CLOCK_CONFIG_KEYWORD,
521 				cal_launch.tooltip_comment);
522 	fprintf(f, "%s hour_chime_command %s\n", CLOCK_CONFIG_KEYWORD,
523 				hour_chime_command);
524 	fprintf(f, "%s quarter_chime_command %s\n", CLOCK_CONFIG_KEYWORD,
525 				quarter_chime_command);
526     fprintf(f, "%s loop_chime_enable %d\n", CLOCK_CONFIG_KEYWORD,
527                loop_chime_enable);
528 	fprintf(f, "%s clock_options %d\n", CLOCK_CONFIG_KEYWORD,
529 				clock_enable);
530 	fprintf(f, "%s cal_options %d\n", CLOCK_CONFIG_KEYWORD,
531 				cal_enable);
532 	fprintf(f, "%s cal_format %s\n", CLOCK_CONFIG_KEYWORD,
533 				cal_format);
534 	fprintf(f, "%s clock_format %s\n", CLOCK_CONFIG_KEYWORD,
535 				clock_format);
536 	}
537 
538 static void
load_clock_cal_config(gchar * arg)539 load_clock_cal_config(gchar *arg)
540 	{
541 	gchar	config[32], item[CFG_BUFSIZE];
542 	gint	n;
543 
544 	n = sscanf(arg, "%31s %[^\n]", config, item);
545 	if (n == 2)
546 		{
547 		if (!strcmp(config, "clock_launch"))
548 			clock_launch.command = g_strdup(item);
549 		else if (!strcmp(config, "clock_tooltip"))
550 			clock_launch.tooltip_comment = g_strdup(item);
551 		else if (!strcmp(config, "cal_launch"))
552 			cal_launch.command = g_strdup(item);
553 		else if (!strcmp(config, "cal_tooltip"))
554 			cal_launch.tooltip_comment = g_strdup(item);
555 		else if (!strcmp(config, "hour_chime_command"))
556 			gkrellm_dup_string(&hour_chime_command, item);
557 		else if (!strcmp(config, "quarter_chime_command"))
558 			gkrellm_dup_string(&quarter_chime_command, item);
559 		else if (!strcmp(config, "loop_chime_enable"))
560 			sscanf(item, "%d", &loop_chime_enable);
561 		else if (!strcmp(config, "clock_options"))
562 			sscanf(item, "%d", &clock_enable);
563 		else if (!strcmp(config, "cal_options"))
564 			sscanf(item, "%d", &cal_enable);
565 		else if (!strcmp(config, "cal_format"))
566 			gkrellm_dup_string(&cal_format, item);
567 		else if (!strcmp(config, "clock_format"))
568 			gkrellm_dup_string(&clock_format, item);
569 		}
570 	}
571 
572 /* --------------------------------------------------------------------- */
573 static GtkWidget	*cal_launch_entry,
574 					*cal_tooltip_entry,
575 					*clock_launch_entry,
576 					*clock_tooltip_entry,
577                     *hour_chime_entry,
578                     *quarter_chime_entry,
579 					*clock_enable_button,
580 					*cal_enable_button,
581 					*loop_chime_button;
582 
583 static GtkWidget	*cal_format_combo_box,
584 					*clock_format_combo_box;
585 
586 
587 static void
cb_clock_cal(GtkWidget * widget,gpointer data)588 cb_clock_cal(GtkWidget *widget, gpointer data)
589 	{
590 	loop_chime_enable = GTK_TOGGLE_BUTTON(loop_chime_button)->active;
591 
592 	clock_enable = GTK_TOGGLE_BUTTON(clock_enable_button)->active;
593 	clock_visibility();
594 
595 	cal_enable = GTK_TOGGLE_BUTTON(cal_enable_button)->active;
596 	cal_visibility();
597 
598 	draw_cal();
599 	draw_clock(TRUE);
600 	}
601 
602 static void
cb_launch_entry(GtkWidget * widget,gpointer data)603 cb_launch_entry(GtkWidget *widget, gpointer data)
604 	{
605 	gint	which = GPOINTER_TO_INT(data);
606 
607 	if (which)
608 		gkrellm_apply_launcher(&cal_launch_entry, &cal_tooltip_entry,
609 					pcal, &cal_launch, gkrellm_launch_button_cb);
610 	else
611 		gkrellm_apply_launcher(&clock_launch_entry, &clock_tooltip_entry,
612 					pclock, &clock_launch, gkrellm_launch_button_cb);
613 	}
614 
615 static void
cb_chime_entry(GtkWidget * widget,gpointer data)616 cb_chime_entry(GtkWidget *widget, gpointer data)
617 	{
618 	gint	which    = (GPOINTER_TO_INT(data)) & 0x1;
619 	gint	activate = (GPOINTER_TO_INT(data)) & 0x10;
620 
621 	/* If editing the chime commands, block them until config is destroyed
622 	|  or we get a "activate".
623 	*/
624 	chime_block = activate ? FALSE : TRUE;
625 	if (which)
626 	    gkrellm_dup_string(&hour_chime_command,
627 				gkrellm_gtk_entry_get_text(&hour_chime_entry));
628 	else
629 	    gkrellm_dup_string(&quarter_chime_command,
630 				gkrellm_gtk_entry_get_text(&quarter_chime_entry));
631 	}
632 
633 static void
cal_format_cb(GtkWidget * widget,gpointer data)634 cal_format_cb(GtkWidget *widget, gpointer data)
635 	{
636 	gchar	*s, *check;
637 	GtkWidget *entry;
638 
639 	entry = gtk_bin_get_child(GTK_BIN(cal_format_combo_box));
640 	s = gkrellm_gtk_entry_get_text(&entry);
641 
642 	check = strftime_format(s, cal_alt_color_string);
643 
644 	/* In case Pango markup tags, don't accept line unless valid markup.
645 	|  Ie, markup like <span ...> xxx </span> or <b> xxx </b>
646 	*/
647 	if (   strchr(check, '<') != NULL
648 	    && !pango_parse_markup(check, -1, 0, NULL, NULL, NULL, NULL)
649 	   )
650 		{
651 		g_free(check);
652 		return;
653 		}
654 
655 	g_free(check);
656 	if (gkrellm_dup_string(&cal_format, s))
657 		draw_cal();
658 	}
659 
660 static void
clock_format_cb(GtkWidget * widget,gpointer data)661 clock_format_cb(GtkWidget *widget, gpointer data)
662 	{
663 	gchar	*s, *check;
664 	GtkWidget *entry;
665 
666 	entry = gtk_bin_get_child(GTK_BIN(clock_format_combo_box));
667 	s = gkrellm_gtk_entry_get_text(&entry);
668 
669 	check = strftime_format(s, clock_alt_color_string);
670 
671 	if (   strchr(check, '<') != NULL
672 	    && !pango_parse_markup(check, -1, 0, NULL, NULL, NULL, NULL)
673 	   )
674 		{
675 		g_free(check);
676 		return;
677 		}
678 
679 	g_free(check);
680 	if (gkrellm_dup_string(&clock_format, s))
681 		draw_clock(TRUE);
682 	}
683 
684 static void
config_destroyed(void)685 config_destroyed(void)
686 	{
687 	chime_block = FALSE;
688 	}
689 
690 
691 static gchar    *clock_info_text[] =
692 {
693 N_("<h>Clock/Calendar Format Strings\n"),
694 N_("The display format strings should contain strftime conversion\n"
695 "characters and Pango text attribute markup strings.\n"),
696 "\n",
697 N_("For the clock, the provided default strings will display a 12 hour\n"
698 "clock with seconds, a 12 hour clock with AM/PM indicator, or a 24 hour\n"
699 "clock with seconds.\n"),
700 "\n",
701 N_("The special $A substitution variable expands to the current theme\n"
702 "alternate color and is for use with the Pango \"foreground\" attribute.\n")
703 };
704 
705 
706 static void
create_clock_tab(GtkWidget * tab_vbox)707 create_clock_tab(GtkWidget *tab_vbox)
708 	{
709 	GtkWidget	*tabs;
710 	GtkWidget	*table, *vbox, *vbox1, *hbox, *label, *text;
711 	gint		i;
712 
713 	tabs = gtk_notebook_new();
714 	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs), GTK_POS_TOP);
715 	gtk_box_pack_start(GTK_BOX(tab_vbox), tabs, TRUE, TRUE, 0);
716 	g_signal_connect(G_OBJECT(tabs),"destroy",
717 				G_CALLBACK(config_destroyed), NULL);
718 
719 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Options"));
720 
721 	vbox1 = gkrellm_gtk_category_vbox(vbox, _("Calendar"), 4, 0, TRUE);
722 	gkrellm_gtk_check_button_connected(vbox1, &cal_enable_button,
723 				cal_enable, FALSE, FALSE, 2,
724 				cb_clock_cal, NULL,
725 				_("Enable"));
726 	hbox = gtk_hbox_new(FALSE, 0);
727 	gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 6);
728 	label = gtk_label_new(_("Display format string:"));
729 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
730 	cal_format_combo_box = gtk_combo_box_entry_new_text();
731 	gtk_box_pack_start(GTK_BOX(vbox1), cal_format_combo_box, FALSE, FALSE, 0);
732 	gtk_combo_box_append_text(GTK_COMBO_BOX(cal_format_combo_box), cal_format);
733 	gtk_combo_box_append_text(GTK_COMBO_BOX(cal_format_combo_box), DEFAULT_CAL_FORMAT);
734 	gtk_combo_box_append_text(GTK_COMBO_BOX(cal_format_combo_box), ALT1_CAL_FORMAT);
735 	gtk_combo_box_append_text(GTK_COMBO_BOX(cal_format_combo_box), ALT2_CAL_FORMAT);
736 	gtk_combo_box_set_active(GTK_COMBO_BOX(cal_format_combo_box), 0);
737 	g_signal_connect(G_OBJECT(GTK_COMBO_BOX(cal_format_combo_box)), "changed",
738 			G_CALLBACK(cal_format_cb), NULL);
739 
740 	vbox1 = gkrellm_gtk_category_vbox(vbox, _("Clock"), 4, 0, TRUE);
741 	gkrellm_gtk_check_button_connected(vbox1, &clock_enable_button,
742 				clock_enable, FALSE, FALSE, 6,
743 				cb_clock_cal, NULL,
744 				_("Enable"));
745 	hbox = gtk_hbox_new(FALSE, 0);
746 	gtk_box_pack_start(GTK_BOX(vbox1), hbox, FALSE, FALSE, 6);
747 	label = gtk_label_new(_("Display format string:"));
748 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 2);
749 	clock_format_combo_box = gtk_combo_box_entry_new_text();
750 	gtk_box_pack_start(GTK_BOX(vbox1), clock_format_combo_box, FALSE, FALSE, 0);
751 	gtk_combo_box_append_text(GTK_COMBO_BOX(clock_format_combo_box), clock_format);
752 	gtk_combo_box_append_text(GTK_COMBO_BOX(clock_format_combo_box), DEFAULT_CLOCK_FORMAT);
753 	gtk_combo_box_append_text(GTK_COMBO_BOX(clock_format_combo_box), ALT1_CLOCK_FORMAT);
754 	gtk_combo_box_append_text(GTK_COMBO_BOX(clock_format_combo_box), ALT2_CLOCK_FORMAT);
755 	gtk_combo_box_set_active(GTK_COMBO_BOX(clock_format_combo_box), 0);
756 	g_signal_connect(G_OBJECT(GTK_COMBO_BOX(clock_format_combo_box)), "changed",
757 			G_CALLBACK(clock_format_cb), NULL);
758 
759 /* -- Setup tab */
760 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Setup"));
761 
762 	vbox1 = gkrellm_gtk_category_vbox(vbox, _("Clock Chime Commands"),
763 				4, 0, TRUE);
764 	table = gkrellm_gtk_launcher_table_new(vbox1, 2);
765 
766 	gkrellm_gtk_config_launcher(table, 0, &hour_chime_entry, NULL,
767 			_("Hour"), NULL);
768 	gtk_entry_set_text(GTK_ENTRY(hour_chime_entry), hour_chime_command);
769 	g_signal_connect(G_OBJECT(hour_chime_entry), "changed",
770 			G_CALLBACK(cb_chime_entry), GINT_TO_POINTER(1));
771 	g_signal_connect(G_OBJECT(hour_chime_entry), "activate",
772 			G_CALLBACK(cb_chime_entry), GINT_TO_POINTER(0x11));
773 
774 	gkrellm_gtk_config_launcher(table, 1, &quarter_chime_entry, NULL,
775 			_("Quarter hour"), NULL);
776     gtk_entry_set_text(GTK_ENTRY(quarter_chime_entry), quarter_chime_command);
777 	g_signal_connect(G_OBJECT(quarter_chime_entry), "changed",
778 			G_CALLBACK(cb_chime_entry), GINT_TO_POINTER(0));
779 	g_signal_connect(G_OBJECT(quarter_chime_entry), "activate",
780 			G_CALLBACK(cb_chime_entry), GINT_TO_POINTER(0x10));
781 
782 	gkrellm_gtk_check_button_connected(vbox1, &loop_chime_button,
783 			loop_chime_enable, FALSE, FALSE, 6,
784 			cb_clock_cal, NULL,
785 			_("Loop hour chime command"));
786 
787 	vbox = gkrellm_gtk_category_vbox(vbox, _("Launch Commands"),
788 				4, 0, TRUE);
789 	table = gkrellm_gtk_launcher_table_new(vbox, 2);
790 
791 	gkrellm_gtk_config_launcher(table, 0,  &cal_launch_entry,
792 				&cal_tooltip_entry, _("Calendar"), &cal_launch);
793 
794 	/* --Info tab */
795 	vbox = gkrellm_gtk_framed_notebook_page(tabs, _("Info"));
796 	text = gkrellm_gtk_scrolled_text_view(vbox, NULL,
797 				GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
798 	for (i = 0; i < sizeof(clock_info_text)/sizeof(gchar *); ++i)
799 		gkrellm_gtk_text_view_append(text, _(clock_info_text[i]));
800 	g_signal_connect(G_OBJECT(cal_launch_entry), "changed",
801 			G_CALLBACK(cb_launch_entry), GINT_TO_POINTER(1));
802 	g_signal_connect(G_OBJECT(cal_tooltip_entry), "changed",
803 			G_CALLBACK(cb_launch_entry), GINT_TO_POINTER(1));
804 
805 	gkrellm_gtk_config_launcher(table, 1,  &clock_launch_entry,
806 				&clock_tooltip_entry, _("Clock"), &clock_launch);
807 	g_signal_connect(G_OBJECT(clock_launch_entry), "changed",
808 			G_CALLBACK(cb_launch_entry), GINT_TO_POINTER(0));
809 	g_signal_connect(G_OBJECT(clock_tooltip_entry), "changed",
810 			G_CALLBACK(cb_launch_entry), GINT_TO_POINTER(0));
811 	}
812 
813 
814 static GkrellmMonitor	monitor_clock =
815 	{
816 	N_("Clock"),		/* Name, for config tab.	*/
817 	MON_CLOCK,			/* Id,  0 if a plugin		*/
818 	create_clock,		/* The create function		*/
819 	update_clock,		/* The update function		*/
820 	create_clock_tab,	/* The config tab create function	*/
821 	NULL,				/* Instant apply	*/
822 
823 	save_clock_cal_config,	/* Save user conifg			*/
824 	load_clock_cal_config,	/* Load user config			*/
825 	CLOCK_CONFIG_KEYWORD, /* config keyword			*/
826 
827 	NULL,				/* Undef 2	*/
828 	NULL,				/* Undef 1	*/
829 	NULL,				/* Undef 0	*/
830 
831 	0,					/* insert_before_id - place plugin before this mon */
832 
833 	NULL,				/* Handle if a plugin, filled in by GKrellM		*/
834 	NULL				/* path if a plugin, filled in by GKrellM		*/
835 	};
836 
837 GkrellmMonitor *
gkrellm_init_clock_monitor(void)838 gkrellm_init_clock_monitor(void)
839 	{
840 	clock_enable = TRUE;
841     monitor_clock.name = _(monitor_clock.name);
842     loop_chime_enable   = FALSE;
843     hour_chime_command = g_strdup("");
844     quarter_chime_command = g_strdup("");
845 
846 	gkrellm_dup_string(&clock_format, DEFAULT_CLOCK_FORMAT);
847 
848 	clock_style_id = gkrellm_add_meter_style(&monitor_clock, CLOCK_STYLE_NAME);
849 	mon_clock = &monitor_clock;
850 	return &monitor_clock;
851 	}
852 
853 static GkrellmMonitor	monitor_cal =
854 	{
855 	N_("Calendar"),	/* Name, for config tab.	*/
856 	MON_CAL,		/* Id,  0 if a plugin		*/
857 	create_calendar, /* The create function		*/
858 	NULL,			/* The update function		*/
859 	NULL,			/* The config tab create function	*/
860 	NULL,			/* Apply the config function		*/
861 
862 	NULL,			/* Save user conifg			*/
863 	NULL,			/* Load user config			*/
864 	NULL,			/* config keyword			*/
865 
866 	NULL,			/* Undef 2	*/
867 	NULL,			/* Undef 1	*/
868 	NULL,			/* Undef 0	*/
869 
870 	0,				/* insert_before_id - place plugin before this mon */
871 
872 	NULL,			/* Handle if a plugin, filled in by GKrellM		*/
873 	NULL			/* path if a plugin, filled in by GKrellM		*/
874 	};
875 
876 GkrellmMonitor *
gkrellm_init_cal_monitor(void)877 gkrellm_init_cal_monitor(void)
878 	{
879 	cal_enable = TRUE;
880     monitor_cal.name = _(monitor_cal.name);
881 
882 	gkrellm_dup_string(&cal_format, DEFAULT_CAL_FORMAT);
883 
884 	cal_style_id = gkrellm_add_meter_style(&monitor_cal, CAL_STYLE_NAME);
885 	mon_cal = &monitor_cal;
886 	return &monitor_cal;
887 	}
888 
889