1 /*
2  * GKrellMBgChg: a GKrellM plugin to change the desktop wallpaper
3  * Copyright (C) 2002-2010 Stefan Bender
4  * Author: Stefan Bender <stefan@bender-suhl.de>
5  *
6  * This program is free software which I release under the GNU General Public
7  * License. You may redistribute and/or modify this program under the terms of
8  * that license as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * For more information, see the README and LICENSE files.
21  */
22 #include <stdio.h>
23 #include <stdlib.h>
24 #if !defined(WIN32)
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #endif
29 
30 #include "gkrellmbgchg.h"
31 
32 /* Uncomment this or add -DGKBG_DEBUG to compiler's option to see a
33    lot of debug output. */
34 /* #define GKBG_DEBUG */
35 #ifdef GKBG_DEBUG
36 #define GKBG_debug(fmt, ...) fprintf(stderr, "debug: " fmt "\n", ##__VA_ARGS__)
37 #else
38 #define GKBG_debug(fmt, ...)
39 #endif
40 
41 static GtkWidget *gkrellm_vbox;
42 
43 static GkrellmKrell *krell_time;
44 static GkrellmPanel *panel;
45 static GkrellmMonitor *monitor;
46 static GkrellmDecal *decal_wu;
47 static GkrellmTicks *pGK;
48 static gint style_id;
49 
50 /* all the stuff we need goes into this */
51 struct bg_ctx {
52 	GList *idb;
53 	GList *idb_orig;
54 	GRand *bgchg_rand;
55 	GtkTooltips *tip;
56 	gint32 cur_img;
57 	gint seconds_left;
58 	gint locked;
59 };
60 /* so we have only this global (still) */
61 static struct bg_ctx *pbg_ctx;
62 
63 /* config widgets */
64 static GtkWidget *entry_format_str;
65 static GtkWidget *entry_idb;
66 static GtkWidget *wait_seconds_spin_button;
67 static GtkWidget *scroll_adj_spin_button;
68 static GtkWidget *entry_command;
69 static GtkWidget *parse_cmd_entry;
70 #if !defined(WIN32)
71 static GtkWidget *auto_update_entry;
72 #endif
73 static GtkWidget *ignore_entry;
74 static GtkWidget *randomise_entry;
75 static GtkWidget *reset_entry;
76 static GtkWidget *reset_entry2;
77 static GtkWidget *change_on_load;
78 static GtkWidget *change_on_apply;
79 static GtkWidget *remember_locked_state;
80 static GtkWidget *remember_image_number;
81 static GtkWidget *simple_scroll_adj;
82 static GtkWidget *center_text;
83 static GtkWidget *display_text;
84 static GtkWidget *display_krell;
85 
86 struct bg_monitor {
87 	gint wait_seconds;			/* sec. between updates */
88 	gint randomise;				/* randomise images? */
89 	gint reset;				/* reset the counter if lock is released */
90 	gint reset_config;				/* reset the counter on "apply" */
91 	gchar format_string[128];	/* output format string */
92 	gchar command[256];			/* command to change bg */
93 	gboolean parse_cmd_output;	/* parse command's output */
94 	gchar idb[256];				/* full path to image database */
95 	gint change_on_load;		/* change image on load */
96 	gint change_on_apply;		/* change image on config changes */
97 	gint remember_locked_state;
98 	gint locked_last_run;		/* was it locked the last time? */
99 	gint remember_image_number;
100 	gint32 image_nr_last_run;	/* the number when we last shut down */
101 	gint simple_scroll_adj;		/* mouse wheel adjusts timer w/o "shift" */
102 	gint scroll_adj_time;		/* time that the mouse wheel adjusts */
103 	gboolean center_text;		/* Center time text */
104 	gboolean display_text;		/* Display text countdown */
105 	gboolean display_krell;		/* Display krell - slider */
106 	gboolean ignore;			/* discard files we can not stat */
107 #if !defined(WIN32)
108 	gboolean auto_update;			/* auto update image list if changed? */
109 	time_t idb_mtime;			/* IDB file mtime */
110 #endif
111 };
112 
113 static struct bg_monitor bgmon = {
114 	.wait_seconds = 600,
115 	.randomise = 1,
116 	.reset = 0,
117 	.reset_config = 0,
118 	.format_string = "$t",
119 #if defined(WIN32)
120 	.command = "",
121 #else
122 	.command = "Esetroot -f",
123 #endif
124 	.parse_cmd_output = 0,
125 	.idb = "~/images.idb",
126 	.change_on_load = 0,
127 	.change_on_apply = 0,
128 	.remember_locked_state = 0,
129 	.locked_last_run = 0,
130 	.remember_image_number = 0,
131 	.image_nr_last_run = -1,
132 	.simple_scroll_adj = 0,
133 	.scroll_adj_time = 60,
134 	.center_text = 1,
135 	.display_text = 1,
136 	.display_krell = 1,
137 	.ignore = 0
138 #if !defined(WIN32)
139 	,
140 	.auto_update = 0,
141 	.idb_mtime = 0
142 #endif
143 };
144 
145 struct idb_entry {
146 	gchar *filename;
147 };
148 
149 /* returns the pointer to the successfully opened file and
150  * NULL if something weird happened or the file was not modified
151  * and `force' was not set (to 1). */
open_imagelist(gchar * filename,int force)152 FILE *open_imagelist( gchar *filename, int force )
153 {
154 	FILE *file;
155 	gchar *tmp;
156 #if !defined(WIN32)
157 	struct stat buf;
158 #endif
159 	if( filename ) {
160 		if( !strncmp( filename, "~/", MIN(2, strlen(filename)) ) )
161 			tmp = g_strdup_printf( "%s/%s", g_get_home_dir(), filename+2 );
162 		else
163 			tmp = g_strdup_printf( "%s", filename );
164 	} else return NULL;
165 	GKBG_debug("bgmon.idb = %s; tmp = %s", bgmon.idb, tmp);
166 
167 #if !defined(WIN32)
168 	/* don't load if no force and not modified */
169 	if( stat( tmp, &buf ) == -1 ) {
170 		/* something went wrong, we just don't care what for now */
171 		GKBG_debug("stat: error on `%s'", tmp);
172 		return NULL;
173 	}
174 	if( !force && bgmon.idb_mtime == buf.st_mtime) {
175 		GKBG_debug("%s was not modified", tmp);
176 		return NULL;
177 	}
178 #endif
179 
180 	GKBG_debug("opening database `%s'", tmp);
181 	if( (file = fopen( tmp, "r" )) == NULL) {
182 		/* fwiw, print an error message to stderr */
183 		fprintf( stderr, _("Could not open image database. (%s)\n"), _(tmp) );
184 		if( tmp!=bgmon.idb ) g_free( tmp );
185 		return NULL;
186 	}
187 	if( tmp!=bgmon.idb ) g_free( tmp );
188 
189 #if !defined(WIN32)
190 	bgmon.idb_mtime = buf.st_mtime;
191 #endif
192 
193 	return file;
194 }
195 
196 /* Randomise image list in a non-repeating manner. */
randomise_image_list()197 static void randomise_image_list()
198 {
199 	GList *gl = NULL;
200 	GList *entry = NULL, *tentry = NULL;
201 	guint gll = g_list_length( pbg_ctx->idb );
202 	int i, tmp;
203 	gint32 randval;
204 	gint gli[gll];
205 
206 	/* Save the original list */
207 	pbg_ctx->idb_orig = g_list_copy(pbg_ctx->idb);
208 
209 	/* Randomise the index list */
210 	for( i = 0; i < gll; i++ ) gli[i] = i;
211 	for( i = 0; i < gll; i++ ) {
212 		randval = g_rand_int_range( pbg_ctx->bgchg_rand, 0, gll );
213 		tmp = gli[i];
214 		gli[i] = gli[randval];
215 		gli[randval] = tmp;
216 	};
217 
218 	/* save old image entry */
219 	if( pbg_ctx->cur_img > -1 && pbg_ctx->cur_img < gll )
220 		entry = g_list_nth( pbg_ctx->idb, pbg_ctx->cur_img );
221 
222 	/* Create new list from randomised index list */
223 	for( i = 0; i < gll; i++ )
224 		gl = g_list_append( gl, ((struct idb_entry *)g_list_nth( pbg_ctx->idb, gli[i] )->data));
225 
226 	/* exchange entries if remembering is set and the image is in the list */
227 	if( bgmon.remember_image_number && entry ) {
228 		i = g_list_index( gl, entry->data);
229 		tentry = g_list_nth( gl, i );
230 		gl = g_list_remove_link( gl, tentry );
231 		gl = g_list_prepend( gl, tentry->data );
232 	}
233 
234 	/* Switch to the randomised list */
235 	g_list_free(pbg_ctx->idb); pbg_ctx->idb = gl;
236 
237 	/* begin with zero */
238 	pbg_ctx->cur_img = 0;
239 
240 	/* Uncomment code below to show indices and filenames */
241 	/*
242 	   for( i = 0; i < gll; i++ ) printf(" %d ", gli[i]);
243 	   fprintf(stderr, "\n");
244 
245 	   gchar *fname = NULL;
246 	   for( i = 0; i < gll; i++ ) {
247 	   fname = g_strdup( ((struct idb_entry *)g_list_nth( pbg_ctx->idb, i )->data)->filename );
248 	   fprintf(stderr, "%d  <%s>\n", i, fname );
249 	   }
250 	   g_free( fname );
251 	*/
252 }
253 
254 /* returns 0 if list was updated (= normal operation), 1 otherwise */
255 /* force - whether to load list even if not modified */
update_image_list(int force)256 static int update_image_list(int force)
257 {
258 	gchar *tmp = NULL;
259 #if !defined(MAXPATHLEN)
260 	gchar *tmp2 = NULL;
261 #endif
262 	gchar c;
263 	gint num=1;
264 	FILE *idb_file;
265 	struct idb_entry *idb_e;
266 
267 	if((idb_file = open_imagelist( bgmon.idb, force )) == NULL) return 1;
268 
269 	if(pbg_ctx->idb != NULL) { g_list_free(pbg_ctx->idb); pbg_ctx->idb = NULL; }
270 
271 	tmp = g_malloc( num*BUFFSIZE );
272 	while(!feof(idb_file)) {
273 
274 		/* skip leading blanks and tabs */
275 		while( ((c = fgetc( idb_file )) == 0x20 || c == '\t') && !feof( idb_file ));
276 
277 		if( c == '#' ) { /* skip entry */
278 			while( ((char)fgetc( idb_file ) != '\n') && !feof( idb_file ) );
279 			continue;
280 		}
281 
282 		if( c == '\n' ) continue;
283 
284 		*tmp=c; /* copy entry */
285 		/* abort on error and eof when no bytes were read */
286 		if( !fgets( tmp+1, (num*BUFFSIZE)-1, idb_file ) ) continue;
287 #if !defined(MAXPATHLEN)
288 		while( tmp[strlen(tmp)-1]!='\n' && !feof( idb_file ) ) {
289 			if( (tmp2 = g_realloc( tmp, ++num*BUFFSIZE )) == NULL ) break;
290 			tmp = tmp2;
291 			if( !fgets( tmp+strlen(tmp), BUFFSIZE, idb_file ) ) break;
292 		}
293 #endif
294 		if( tmp[strlen(tmp)-1]=='\n' )
295 			tmp[strlen(tmp)-1] = 0x00; /* strip trailing newline */
296 #if defined(MAXPATHLEN)
297 		else if( !feof( idb_file ) )
298 			/* skip to eol or eof */
299 			while( ((char)fgetc( idb_file ) != '\n') && !feof( idb_file ) );
300 #endif
301 
302 		/* ignore the file if doesn't exist */
303 		if( bgmon.ignore && !g_file_test( tmp, G_FILE_TEST_EXISTS ) ) {
304 			GKBG_debug( "ignoring `%s'", tmp );
305 		} else {
306 			idb_e = (struct idb_entry *)calloc( 1, sizeof( struct idb_entry ));
307 			idb_e->filename = g_strdup( tmp );
308 			pbg_ctx->idb = g_list_append( pbg_ctx->idb, idb_e );
309 		}
310 
311 	}
312 
313 	g_free( tmp );
314 	fclose(idb_file);
315 
316 	if( bgmon.randomise )
317 		randomise_image_list();
318 	else
319 		pbg_ctx->cur_img = bgmon.image_nr_last_run;
320 
321 	return 0;
322 }
323 
324 
325 
326 
update_image(gint32 inr)327 static void update_image(gint32 inr)
328 {
329 	gchar *fname = NULL, *tiptext = NULL, *ch, *tmp = NULL, *tag, *value;
330 	gint count = 0;
331 	double val;
332 	guint gll = g_list_length( pbg_ctx->idb );
333 
334 	GKBG_debug("update_image(%i) [%i]", inr, gll);
335 
336 
337 #if !defined(WIN32)
338 	/*
339 	 * Auto update
340 	 */
341 	if( bgmon.auto_update && !update_image_list(0)) {
342 		GKBG_debug("list modified.");
343 		inr = -1;
344 	}
345 #endif
346 
347 
348 	/*
349 	 * Choose file
350 	 */
351 	/* nothing to change, if there are not at least 2 images,
352 	   however, if list was just updated image in it may be different. */
353 	if( !gll || (inr!=-1 && gll==1) ) return;
354 	/* start over, if the number is larger than the database's length */
355 	if( gll < inr ) inr = -1;
356 
357 	/* If randomising, images are already randomised; hence we just
358 	   increment index no matter what. */
359 	if( inr == -1) { /* -1 means change */
360 		if( ++pbg_ctx->cur_img >= gll ) {
361 			if( bgmon.randomise ) randomise_image_list();
362 			pbg_ctx->cur_img=0;
363 		}
364 		/* make sure GKrellM will save the image number */
365 		gkrellm_config_modified();
366 	} else pbg_ctx->cur_img = inr;
367 	fname = g_strdup( ((struct idb_entry *)g_list_nth( pbg_ctx->idb, pbg_ctx->cur_img )->data)->filename );
368 
369 
370 
371 	/*
372 	 * Make command string
373 	 */
374 	pbg_ctx->seconds_left = bgmon.wait_seconds;
375 #if defined(WIN32)
376 	if (bgmon.parse_cmd_output) {
377 #endif
378 
379 	for (ch = bgmon.command; *ch; ) {
380 		if (*ch++=='%') {
381 			switch (*ch) {
382 			case '%': if (count==0) count = 1; break;
383 			case 's': ++count; break;
384 			default:  count = 2;
385 			}
386 			if (*ch) ++ch;
387 		}
388 	}
389 
390 	/* If there was exactly one '%s' in command use it as format */
391 	tmp = count==1
392 		? g_strdup_printf( bgmon.command, g_shell_quote(fname) )
393 		: g_strdup_printf( "%s %s", bgmon.command, g_shell_quote(fname) );
394 	GKBG_debug("command: %s", tmp);
395 
396 #if defined(WIN32)
397 	}
398 #endif
399 
400 
401 	/*
402 	 * Parse output
403 	 */
404 	if (bgmon.parse_cmd_output) {
405 
406 		if (!g_spawn_command_line_sync(tmp, &ch, NULL, &count, NULL)) {
407 			count = 1;
408 		}
409 		free(tmp);
410 
411 		/* Failed */
412 		if (count) {
413 			pbg_ctx->seconds_left = 10;
414 			return;
415 		}
416 
417 		/* Parse */
418 		for (tmp = ch; *ch; ) {
419 			for (tag = ch; *ch && *ch!=':'; ++ch);
420 			if (!*ch) break;
421 			*ch++ = 0;
422 			for (value = ch; *ch && *ch!='\n'; ++ch);
423 			if (!*ch) break;
424 			*ch++ = 0;
425 
426 			if (!strcmp(tag, "file")) {
427 				if (fname) free(fname);
428 				fname = g_strdup(value);
429 			} else if (!strcmp(tag, "tooltip")) {
430 				if (tiptext) free(tiptext);
431 				tiptext = g_strdup(value);
432 			} else if (strcmp(tag, "time")) {
433 				continue;
434 			}
435 
436 			if (*value=='+' || *value=='-') {
437 				count = strtol(value, &value, 0);
438 				if (!*value) pbg_ctx->seconds_left += count;
439 			} else if (*value=='*' || *value=='x') {
440 				val = strtod(value+1, &value);
441 				if (!*value && val>0) pbg_ctx->seconds_left *= val;
442 			} else if (*value=='/') {
443 				val = strtod(value+1, &value);
444 				if (!*value && val>0) pbg_ctx->seconds_left /= val;
445 			} else if (*value=='<') {
446 				count = strtol(value+1, &value, 0);
447 				if (!*value && value>0 && pbg_ctx->seconds_left<count)
448 					pbg_ctx->seconds_left = count;
449 			} else if (*value=='>') {
450 				count = strtol(value+1, &value, 0);
451 				if (!*value && value>0 && pbg_ctx->seconds_left>count)
452 					pbg_ctx->seconds_left = count;
453 			} else {
454 				count = strtol(value, &value, 0);
455 				if (!*value && count>=0) pbg_ctx->seconds_left = count;
456 			}
457 		}
458 		free(tmp);
459 
460 
461 #if !defined(WIN32)
462 	/*
463 	 * Don't parse output
464 	 */
465 	} else {
466 		g_spawn_command_line_async( tmp, NULL );
467 		g_free( tmp );
468 #endif
469 	}
470 
471 
472 #if defined(WIN32)
473 	/*
474 	 * Set background under Win32
475 	 */
476 	SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, fname, 0);
477 #endif
478 
479 
480 	/*
481 	 * Set tool tip text
482 	 */
483 	if( tiptext == NULL && fname ) {
484 		for (tiptext = ch = fname; *ch; ++ch) {
485 			if (*ch=='/' && *(ch+1)) tiptext = ch+1;
486 		}
487 		tiptext = g_locale_to_utf8( tiptext, -1, NULL, NULL, NULL);
488 	}
489 	gtk_tooltips_set_tip( pbg_ctx->tip, panel->drawing_area, tiptext, NULL );
490 	gtk_tooltips_enable( pbg_ctx->tip );
491 	g_free( tiptext );
492 	g_free( fname );
493 }
494 
495 
496 
497 
update_decals_text(gchar * text)498 static void update_decals_text( gchar *text )
499 {
500 	gchar *s, buf[48];
501 
502 	if( pbg_ctx->locked ) return;
503 
504 	text[0] = '\0';
505 	for( s=bgmon.format_string; *s!='\0'; s++ ) {
506 		buf[0] = *s; buf[1]='\0';
507 		if( *s == '$' && *(s+1) !='\0' )
508 		switch( *(s+1) ) {
509 			case 's':
510 				g_snprintf( buf, 12, "%d", pbg_ctx->seconds_left );
511 				s++;
512 				break;
513 			case 'S':
514 				g_snprintf( buf, 12, "%d", bgmon.wait_seconds - pbg_ctx->seconds_left );
515 				s++;
516 				break;
517 			case 'm':
518 				g_snprintf( buf, 12, "%d", pbg_ctx->seconds_left / 60 );
519 				s++;
520 				break;
521 			case 'M':
522 				g_snprintf( buf, 12, "%d", (bgmon.wait_seconds-pbg_ctx->seconds_left) / 60 );
523 				s++;
524 				break;
525 			case 't':
526 				if (bgmon.wait_seconds > 3600) { /* If over an hour, display hh:mm */
527 					gint hours = pbg_ctx->seconds_left / 3600;
528 					g_snprintf( buf, 12, "%.2d:%.2d",
529 						hours, (pbg_ctx->seconds_left - hours*3600)/ 60 );
530 				} else
531 					g_snprintf( buf, 12, "%.2d:%.2d",
532 						pbg_ctx->seconds_left / 60, pbg_ctx->seconds_left % 60 );
533 				s++;
534 				break;
535 			case 'T':
536 				if (bgmon.wait_seconds > 3600) { /* If over an hour, display hh:mm */
537 					gint hours = (bgmon.wait_seconds-pbg_ctx->seconds_left) / 3600;
538 					g_snprintf( buf, 12, "%.2d:%.2d",
539 						hours,
540 						(bgmon.wait_seconds-hours*3600-pbg_ctx->seconds_left) / 60 );
541 				} else
542 					g_snprintf( buf, 12, "%.2d:%.2d",
543 						(bgmon.wait_seconds-pbg_ctx->seconds_left) / 60,
544 						(bgmon.wait_seconds-pbg_ctx->seconds_left) % 60 );
545 				s++;
546 				break;
547 		}
548 		strncat( text, buf,
549 			(strlen(text)+strlen(buf)) > TEXTSIZE ? TEXTSIZE - strlen(text) : strlen(buf) );
550 	}
551 	text = g_locale_to_utf8( text, -1, NULL, NULL, NULL );
552 }
553 
update_krell(void)554 static void update_krell(void)
555 {
556 	if ( ! bgmon.display_krell ) return;
557 	gkrellm_update_krell( panel, krell_time, (gulong) bgmon.wait_seconds - pbg_ctx->seconds_left );
558 }
559 
update_plugin(void)560 static void update_plugin(void)
561 {
562 	int w = 0, c = 0;
563 	gchar text[TEXTSIZE] = "locked";
564 
565 	if(pGK->second_tick && !pbg_ctx->locked &&  !(pbg_ctx->seconds_left--)) {
566 		update_image(-1);
567 	}
568 
569 	if(!(pGK->timer_ticks % 2)) return;
570 
571 	if( !pbg_ctx->locked ) update_decals_text( text );
572 
573 	/* No need to do these calculations every time... FIXME */
574 	if ( bgmon.center_text ) {
575 		GkrellmMargin *m =gkrellm_get_style_margins(gkrellm_panel_style(style_id));
576 		w = gkrellm_gdk_string_width(gkrellm_panel_textstyle(style_id)->font, text);
577 		c = (gkrellm_chart_width() - w ) / 2 - m->left;
578 	}
579 	gkrellm_decal_text_set_offset(decal_wu, c, 2);
580 	if ( bgmon.display_text )
581 		gkrellm_draw_decal_text( panel, decal_wu, text, -1 );
582 
583 	update_krell();
584 	gkrellm_draw_panel_layers( panel );
585 }
586 
panel_expose_event(GtkWidget * widget,GdkEventExpose * ev)587 static gint panel_expose_event( GtkWidget *widget, GdkEventExpose *ev)
588 {
589 	if( widget == panel->drawing_area ) {
590 		gdk_draw_pixmap( widget->window,
591 			widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
592 			panel->pixmap,
593 			ev->area.x, ev->area.y,
594 			ev->area.x, ev->area.y,
595 			ev->area.width, ev->area.height );
596 	}
597 	return FALSE;
598 }
599 
cb_panel_scroll(GtkWidget * widget,GdkEventScroll * ev)600 static gint cb_panel_scroll( GtkWidget *widget, GdkEventScroll *ev )
601 {
602 	gint shift_modifier = (ev->state & GDK_SHIFT_MASK) ? !bgmon.simple_scroll_adj : bgmon.simple_scroll_adj;
603 	gint prev_locked = pbg_ctx->locked;
604 
605 	if (ev->direction == GDK_SCROLL_UP) {
606 		if( !shift_modifier ) pbg_ctx->locked = 1;
607 		else pbg_ctx->seconds_left += bgmon.scroll_adj_time;
608 	} else if (ev->direction == GDK_SCROLL_DOWN) {
609 		if( !shift_modifier && pbg_ctx->locked) {
610 			pbg_ctx->locked = 0;
611 			if( bgmon.reset ) pbg_ctx->seconds_left = bgmon.wait_seconds;
612 		} else if( shift_modifier ) {
613 			pbg_ctx->seconds_left -= bgmon.scroll_adj_time;
614 			if( pbg_ctx->seconds_left < 0 ) pbg_ctx->seconds_left = 1;
615 		}
616 	}
617 
618 	/* make sure GKrellM will save the lock state if it changed */
619 	if ( prev_locked != pbg_ctx->locked ) gkrellm_config_modified();
620 
621 	return FALSE;
622 }
623 
cb_button_press(GtkWidget * widget,GdkEventButton * ev)624 static gint cb_button_press( GtkWidget *widget, GdkEventButton *ev )
625 {
626 	gint shift_modifier = (ev->state & GDK_SHIFT_MASK ) ? 1 : 0;
627 
628 	switch( ev->button ) {
629 		/* left */
630 		case 1:
631 			if( shift_modifier ) { /* shift+left -> lock/unlock the bg */
632 				if( pbg_ctx->locked ) {
633 					pbg_ctx->locked = 0;
634 					if( bgmon.reset ) pbg_ctx->seconds_left = bgmon.wait_seconds;
635 				} else pbg_ctx->locked = 1;
636 				/* make sure GKrellM will save the lock state */
637 				gkrellm_config_modified();
638 			} else {
639 				update_image(-1);
640 			}
641 			break;
642 		/* middle */
643 		case 2:
644 			update_image_list(1);
645 			break;
646 		/* right */
647 		case 3:
648 			if( shift_modifier ) {/* shift+right -> lock/unlock the bg */
649 				if( pbg_ctx->locked ) {
650 					pbg_ctx->locked = 0;
651 					if( bgmon.reset ) pbg_ctx->seconds_left = bgmon.wait_seconds;
652 				} else pbg_ctx->locked = 1;
653 				/* make sure GKrellM will save the lock state */
654 				gkrellm_config_modified();
655 			} else
656 				gkrellm_open_config_window( monitor );
657 			break;
658 	}
659 
660 	return FALSE;
661 }
662 
create_plugin(GtkWidget * vbox,gint first_create)663 static void create_plugin( GtkWidget *vbox, gint first_create )
664 {
665 	GkrellmPiximage *krell_img;
666 	GkrellmStyle *style;
667 	GkrellmTextstyle *ts;
668 	gchar text[TEXTSIZE] = "bgchg" ;
669 
670 	gkrellm_vbox = vbox;
671 
672 	if (first_create) panel = gkrellm_panel_new0 ();
673 	else gkrellm_destroy_decal_list( panel );
674 
675 	style = gkrellm_meter_style( style_id );
676 	krell_img = gkrellm_krell_meter_piximage( style_id );
677 	ts = gkrellm_panel_textstyle( style_id );
678 	panel->textstyle = ts;
679 
680 	krell_time = gkrellm_create_krell( panel, krell_img, style );
681 	gkrellm_monotonic_krell_values(krell_time, FALSE);
682 	gkrellm_set_krell_full_scale( krell_time, bgmon.wait_seconds, 1 );
683 	if ( ! bgmon.display_krell )
684 		gkrellm_remove_krell( panel, krell_time );
685 
686 	decal_wu = gkrellm_create_decal_text( panel, "Apif0", ts, style, -1, -1, -1 );
687 
688 	gkrellm_panel_configure( panel, NULL, style );
689 	gkrellm_panel_create( vbox, monitor, panel );
690 
691 	gkrellm_draw_decal_text( panel, decal_wu, text, -1 );
692 
693 	if(first_create) {
694 		g_signal_connect( G_OBJECT (panel->drawing_area), "expose_event",
695 				G_CALLBACK(panel_expose_event), NULL );
696 		g_signal_connect( G_OBJECT (panel->drawing_area), "button_press_event",
697 				G_CALLBACK(cb_button_press), NULL );
698 		g_signal_connect(G_OBJECT(panel->drawing_area),"scroll_event",
699 				G_CALLBACK(cb_panel_scroll), NULL);
700 
701 		pbg_ctx = g_malloc( sizeof(struct bg_ctx) );
702 		memset( pbg_ctx, 0x00, sizeof(struct bg_ctx) );
703 		if (bgmon.remember_image_number) pbg_ctx->cur_img = bgmon.image_nr_last_run;
704 		else pbg_ctx->cur_img = -1;
705 	} else pbg_ctx->cur_img = -1;
706 
707 	pbg_ctx->tip = gtk_tooltips_new();
708 	gtk_tooltips_enable( pbg_ctx->tip );
709 
710 	pbg_ctx->bgchg_rand = g_rand_new_with_seed( (guint32)time(NULL) );
711 
712 	if (bgmon.remember_locked_state) pbg_ctx->locked = bgmon.locked_last_run;
713 	else pbg_ctx->locked = 0;
714 	pbg_ctx->seconds_left = bgmon.wait_seconds;
715 
716 	update_image_list(1);
717 	if (bgmon.change_on_load) update_image( pbg_ctx->cur_img );
718 	update_krell();
719 
720 	gkrellm_draw_panel_layers( panel );
721 }
722 
723 static gchar *plugin_info_text[] = {
724 	"<b>GKrellMBgChg ",
725 	"is a GKrellM plugin which periodically changes\n",
726 	"your desktop background. It also allows you to monitor the time\n",
727 	"between the updates in various ways. It is possible, to force a\n",
728 	"change by clicking on the panel.\n\n",
729 	"<h>Mouse Actions:\n\n",
730 	"<b>- Left ", "changes the background image and resets the timer,\n",
731 	"\t+<Shift> toggles the background lock.\n",
732 	"<b>- Middle ", "reloads the images from the image database\n",
733 	"\t(see \"Image Database\" below).\n",
734 	"<b>- Right ", "opens the GKrellM Background Changer config window.\n",
735 	"\t+<Shift> toggles the background lock.\n\n",
736 	"<b>Mouse Wheel Actions:\n\n",
737 	"<b>- Up ", "\"locks\" the current background image (if you like it very much).\n",
738 	"\t+<Shift> prolongs the timer by the seconds given below.\n",
739 	"<b>- Down ", "\"unlocks\" the image and the counter continues.\n",
740 	"\t+<Shift> shortens the timer by the seconds given below.\n",
741 	"The option \"Mouse wheel adjusts timer\" below exchanges the\n",
742 	"<Shift>-behaviour of the mouse wheel.\n\n",
743 	"<h>Configuration:\n\n",
744 	"<b>- Format String\n",
745 	"\tThe text output format is controlled by this string (default: $s).\n",
746 	"<b>\t$s ", "are the seconds that are remaining to the next update\n",
747 	"<b>\t$S ", "are the seconds that passed since the last change\n",
748 	"<b>\t$m ", "are the minutes that are remaining to the next update\n",
749 	"<b>\t$M ", "are the minutes that passed since the last change\n",
750 	"<b>\t$t ", "is the time remaining to the next update, displayed as '-mm:ss'\n",
751 	"<b>\t$T ", "is the time that passed since the last change, displayed as 'mm:ss'.\n\n",
752 #if defined(WIN32)
753 	"<b>- Background Info Command\n",
754 	"\tProgram to return information such as timeout, filename and tooltip.\n"
755 	"\tIt is used only if Use Background Info Command is checked.\n"
756 	"\tSee ", "<b>README: Tips and Tricks", " for info about output format\n",
757 	"\tand some ideas.\n"
758 	"\tdefault: empty",
759 	"<b>- Use Background Info Command\n",
760 	"\tWhether to use Background Info Command. This option is experimental.\n",
761 	"\tdefault: ", "<b>off\n\n",
762 #else
763 	"<b>- Background Change Command\n",
764 	"\tProgram to use to set the desktop background image (including args).\n",
765 	"\tIf the command has exactly one '%s' it will be replaced by the\n",
766 	"\tproperly quoted background file name.\n",
767 	"\tCommon cases are:\n",
768 	"\tfor plain X11: ", "<b>xsetbg -fullscreen\n",
769 	"\tusing Eterm's Esetroot: ", "<b>Esetroot -f\n",
770 	"\tfor Gnome2 set it to:\n\t\t",
771 	"<b>gconftool-2 --type=string --set /desktop/gnome/background/picture_filename\n",
772 	"\tand for KDE 3.x:\n\t\t",
773 	"<b>dcop kdesktop KBackgroundIface setWallpaper %s 6\n",
774 	"\tdefault: ", "<b>Esetroot -f\n\n",
775 	"<b>- Parse Background Change Command output\n",
776 	"\tWhether to parse output of Background Change Command. This allows\n",
777 	"\tsetting such information as tooltip and timeout from the command.\n",
778 	"\tSee ", "<b>README: Tips and Tricks", " for info about output format\n",
779 	"\tand some ideas. This option is experimental.\n",
780 	"\tdefault: ", "<b>off\n\n",
781 #endif
782 	"<b>- Image Database\n",
783 	"\tFull path to a file containing all the images (full path/line) to be\n",
784 	"\tused by the plugin. (e.g. the output from: ", "<b>find / -name *.jpg | sort", ")\n",
785 	"\tEntries starting with a '#' will be ", "<i>ignored.\n",
786 	"\tdefault: ", "<b>~/images.idb\n\n",
787 #if !defined(WIN32)
788 	"<b>- Auto update image list\n",
789 	"\tSelect whether the image list should be automatically updated \n",
790 	"\twhen the image database file is modified.\n",
791 	"\tdefault: ", "<b>off\n\n",
792 	"<b>- Ignore not found images\n",
793 	"\tIgnore image files that could not be found.\n",
794 	"\tdefault: ", "<b>off\n\n",
795 #endif
796 	"<b>- Randomise images\n",
797 	"\tSelect whether the image list should be randomised or not.\n",
798 	"<b>\tNote: ", "If it is not set, it will ", "<i>always ",
799 	"start at the first image in the list.\n",
800 	"\tdefault: ", "<b>on\n\n",
801 	"<b>- Reset timer on \"lock\" release\n",
802 	"\tReset the timer to the initial value when the \"image lock\" is released.\n",
803 	"\tdefault: ", "<b>off\n\n",
804 	"<b>- Reset timer on config changes\n",
805 	"\tReset the timer on config changes, i.e. when you hit \"apply\" button.\n",
806 	"\tdefault: ", "<b>off\n\n",
807 	"<b>- Change wallpaper on load\n",
808 	"\tChanges the wallpaper when the plugin loads.\n",
809 	"\tdefault: ", "<b>off\n\n",
810 	"<b>- Change wallpaper on config changes\n",
811 	"\tChanges the wallpaper when the config changes.\n",
812 	"\tdefault: ", "<b>off\n\n",
813 	"<b>- Remember \"locked\" state from last run\n",
814 	"\tRemembers whether the current wallpaper was \"locked\"\n",
815 	"\tor not when GKrellM last shut down. Use with change-on-load\n",
816 	"\toption off to load a new wallpaper ", "<i>only", " on request.\n",
817 	"\tdefault: ", "<b>off\n\n",
818 	"<b>- Remember image number from last run\n",
819 	"\tRemembers the image number from the database that was\n",
820 	"\tshown when GKrellM last shut down. It starts the next time with\n",
821 	"\tthis image if the image list didn't change.\n",
822 	"\tdefault: ", "<b>off\n\n",
823 	"<b>- Center text\n",
824 	"\tCenters the displayed text.\n",
825 	"\tdefault: ", "<b>on\n\n",
826 	"<b>- Display text\n",
827 	"\tToggles the text on or off.\n",
828 	"\tdefault: ", "<b>on\n\n",
829 	"<b>- Display krell/slider\n",
830 	"\tToggles the krell on or off.\n",
831 	"\tdefault: ", "<b>on\n\n",
832 	"<b>- Mouse wheel adjusts timer\n",
833 	"\tWhen selected, scrolling the mouse wheel adjusts the time\n",
834 	"\trather than \"lock\" the image. Otherwise the adjustment\n",
835 	"\tworks in combination with the <Shift>-key.\n",
836 	"\tdefault: ", "<b>off\n\n",
837 	"<b>- Mouse wheel adjusts the timer by nnn seconds\n",
838 	"\tThis is the amount of seconds by which the timer is adjusted\n",
839 	"\twhen scrolling the mouse wheel while holding the <Shift>-key.\n",
840 	"\tSee also \"Mouse wheel adjusts timer.\"\n",
841 	"\tdefault: ", "<b>60\n"
842 };
843 
create_bgchg_tab(GtkWidget * tab)844 static void create_bgchg_tab( GtkWidget *tab )
845 {
846 	GtkWidget *tabs, *vbox, *hbox;
847 	GtkWidget *label, *frame;
848 	GtkWidget *text;
849 	GtkAdjustment *adj, *mouse_wheel_adj;
850 	gchar *about_text = NULL;
851 
852 	tabs = gtk_notebook_new();
853 	gtk_notebook_set_tab_pos(GTK_NOTEBOOK(tabs),GTK_POS_TOP);
854 	gtk_box_pack_start(GTK_BOX(tab),tabs,TRUE,TRUE,0);
855 
856 	/* options */
857 	frame = gtk_frame_new(NULL);
858 	gtk_container_border_width(GTK_CONTAINER(frame),3);
859 	label = gtk_label_new(_("Options"));
860 	gtk_notebook_append_page(GTK_NOTEBOOK(tabs),frame,label);
861 
862 	vbox = gtk_vbox_new(FALSE,0);
863 	gtk_container_add(GTK_CONTAINER(frame),vbox);
864 
865 	hbox = gtk_hbox_new(FALSE, 0);
866 	label = gtk_label_new(_("Format String"));
867 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 4);
868 	entry_format_str = gtk_entry_new_with_max_length(127);
869 	gtk_entry_set_text(GTK_ENTRY(entry_format_str),bgmon.format_string);
870 	gtk_box_pack_start(GTK_BOX(hbox), entry_format_str, FALSE, FALSE, 4);
871 	gtk_container_add(GTK_CONTAINER(vbox),hbox);
872 
873 	hbox = gtk_hbox_new(FALSE, 0);
874 #if defined(WIN32)
875 	label = gtk_label_new(_("Background Info Command"));
876 #else
877 	label = gtk_label_new(_("Background Change Command"));
878 #endif
879 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 4);
880 	entry_command = gtk_entry_new_with_max_length(255);
881 	gtk_entry_set_text(GTK_ENTRY(entry_command),bgmon.command);
882 	gtk_box_pack_start(GTK_BOX(hbox), entry_command, TRUE, TRUE, 4);
883 	gtk_container_add(GTK_CONTAINER(vbox),hbox);
884 
885 #if defined(WIN32)
886 	parse_cmd_entry = gtk_check_button_new_with_label( _("Use Background Info Command (experimental)"));
887 #else
888 	parse_cmd_entry = gtk_check_button_new_with_label( _("Parse Background Change Command output (experimental)"));
889 #endif
890 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( parse_cmd_entry ), bgmon.parse_cmd_output );
891 	gtk_container_add( GTK_CONTAINER(vbox), parse_cmd_entry );
892 
893 
894 	hbox = gtk_hbox_new(FALSE, 0);
895 	label = gtk_label_new(_("Image Database"));
896 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 4);
897 	entry_idb = gtk_entry_new_with_max_length(255);
898 	gtk_entry_set_text(GTK_ENTRY(entry_idb),bgmon.idb);
899 	gtk_box_pack_start(GTK_BOX(hbox), entry_idb, TRUE, TRUE, 4);
900 	gtk_container_add(GTK_CONTAINER(vbox),hbox);
901 
902 	hbox = gtk_hbox_new(FALSE, 0);
903 	adj = (GtkAdjustment *) gtk_adjustment_new(bgmon.wait_seconds,
904 			1.0, 99999.0, 1.0, 5.0, 0.0);
905 	wait_seconds_spin_button = gtk_spin_button_new(adj, 0.5, 0);
906 	gtk_spin_button_set_numeric(GTK_SPIN_BUTTON(wait_seconds_spin_button), TRUE);
907 	gtk_box_pack_start(GTK_BOX(hbox), wait_seconds_spin_button, FALSE, FALSE, 4);
908 	label = gtk_label_new(_("Seconds between image changes"));
909 	gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT);
910 	gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 4);
911 	gtk_container_add(GTK_CONTAINER(vbox),hbox);
912 
913 #if !defined(WIN32)
914 	auto_update_entry = gtk_check_button_new_with_label( _("Auto update image list"));
915 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( auto_update_entry ), bgmon.auto_update );
916 	gtk_container_add( GTK_CONTAINER(vbox), auto_update_entry );
917 #endif
918 
919 	ignore_entry = gtk_check_button_new_with_label( _("Ignore not found images"));
920 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( ignore_entry ), bgmon.ignore );
921 	gtk_container_add( GTK_CONTAINER(vbox), ignore_entry );
922 
923 	randomise_entry = gtk_check_button_new_with_label( _("Randomise images"));
924 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( randomise_entry ), bgmon.randomise );
925 	gtk_container_add( GTK_CONTAINER(vbox), randomise_entry );
926 
927 	reset_entry = gtk_check_button_new_with_label( _("Reset timer on \"lock\" release"));
928 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( reset_entry ), bgmon.reset );
929 	gtk_container_add( GTK_CONTAINER(vbox), reset_entry );
930 
931 	reset_entry2 = gtk_check_button_new_with_label( _("Reset timer on config changes"));
932 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( reset_entry2 ), bgmon.reset_config );
933 	gtk_container_add( GTK_CONTAINER(vbox), reset_entry2 );
934 
935 	change_on_load = gtk_check_button_new_with_label(_("Change wallpaper on load"));
936 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( change_on_load ), bgmon.change_on_load );
937 	gtk_container_add( GTK_CONTAINER(vbox), change_on_load );
938 
939 	change_on_apply = gtk_check_button_new_with_label(_("Change wallpaper on config changes"));
940 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( change_on_apply ), bgmon.change_on_apply );
941 	gtk_container_add( GTK_CONTAINER(vbox), change_on_apply );
942 
943 	remember_locked_state = gtk_check_button_new_with_label(_("Remember \"locked\" state from last run"));
944 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( remember_locked_state ), bgmon.remember_locked_state );
945 	gtk_container_add( GTK_CONTAINER(vbox), remember_locked_state );
946 
947 	remember_image_number = gtk_check_button_new_with_label(_("Remember image number from last run"));
948 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( remember_image_number ), bgmon.remember_image_number );
949 	gtk_container_add( GTK_CONTAINER(vbox), remember_image_number );
950 
951 	center_text = gtk_check_button_new_with_label(_("Center text"));
952 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( center_text ), bgmon.center_text );
953 	gtk_container_add( GTK_CONTAINER(vbox), center_text );
954 
955 	display_text = gtk_check_button_new_with_label(_("Display text"));
956 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( display_text ), bgmon.display_text );
957 	gtk_container_add( GTK_CONTAINER(vbox), display_text );
958 
959 	display_krell = gtk_check_button_new_with_label(_("Display krell/slider"));
960 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( display_krell ), bgmon.display_krell );
961 	gtk_container_add( GTK_CONTAINER(vbox), display_krell );
962 
963 	simple_scroll_adj = gtk_check_button_new_with_label(_("Mouse wheel adjusts timer"));
964 	gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( simple_scroll_adj ), bgmon.simple_scroll_adj );
965 	gtk_container_add( GTK_CONTAINER(vbox), simple_scroll_adj );
966 
967 	hbox = gtk_hbox_new (FALSE, 5);
968 	gtk_widget_show (hbox);
969 	gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
970 
971 	label = gtk_label_new (_("Mouse wheel adjusts the timer by"));
972 	gtk_widget_show (label);
973 	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
974 	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
975 
976 	mouse_wheel_adj = (GtkAdjustment *) gtk_adjustment_new (bgmon.scroll_adj_time, 1, 1000, 1, 10, 0);
977 	scroll_adj_spin_button = gtk_spin_button_new (GTK_ADJUSTMENT (mouse_wheel_adj), 1, 0);
978 	gtk_widget_show (scroll_adj_spin_button);
979 	gtk_box_pack_start (GTK_BOX (hbox), scroll_adj_spin_button, FALSE, TRUE, 0);
980 
981 	label = gtk_label_new (_("second(s)"));
982 	gtk_widget_show (label);
983 	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
984 	gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT);
985 
986 	/* info */
987 	vbox = gkrellm_gtk_framed_notebook_page(tabs,_("Info"));
988 	text = gkrellm_gtk_scrolled_text_view(vbox, NULL,
989 			GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
990 	gkrellm_gtk_text_view_append_strings(text, _(plugin_info_text),
991 			sizeof(plugin_info_text) / sizeof(gchar *));
992 
993 	/* about */
994 	about_text = g_strdup_printf(
995 		"GKrellMBgChg %s\n" \
996 		"GKrellM Background Changer Plugin\n\n" \
997 		"Copyright © 2002-2010 Stefan Bender\n" \
998 		"stefan@bender-suhl.de\n" \
999 		"http://www.bender-suhl.de/stefan/english/comp/gkrellmbgchg.html\n\n" \
1000 		"Released under the GNU General Public Licence",
1001 		GKRELLMBGCHG_VERSION);
1002 
1003 	text = gtk_label_new(about_text);
1004 	label = gtk_label_new(_("About"));
1005 	gtk_notebook_append_page(GTK_NOTEBOOK(tabs),text,label);
1006 	g_free(about_text);
1007 }
1008 
apply_config(void)1009 static void apply_config(void)
1010 {
1011 	const gchar *s;
1012 
1013 	/* update config vars */
1014 	bgmon.wait_seconds = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(wait_seconds_spin_button));
1015 	s = gtk_entry_get_text(GTK_ENTRY(entry_format_str));
1016 	strcpy(bgmon.format_string,s);
1017 	s = gtk_entry_get_text(GTK_ENTRY(entry_idb));
1018 	strcpy(bgmon.idb,s);
1019 #if !defined(WIN32)
1020 	bgmon.auto_update = GTK_TOGGLE_BUTTON( auto_update_entry )->active;
1021 #endif
1022 	bgmon.ignore = GTK_TOGGLE_BUTTON( ignore_entry )->active;
1023 	s = gtk_entry_get_text(GTK_ENTRY(entry_command));
1024 	strcpy(bgmon.command,s);
1025 	bgmon.parse_cmd_output = GTK_TOGGLE_BUTTON( parse_cmd_entry )->active;
1026 	bgmon.randomise = GTK_TOGGLE_BUTTON( randomise_entry )->active;
1027 	bgmon.reset = GTK_TOGGLE_BUTTON( reset_entry )->active;
1028 	bgmon.reset_config = GTK_TOGGLE_BUTTON( reset_entry2 )->active;
1029 	bgmon.change_on_load = GTK_TOGGLE_BUTTON( change_on_load )->active;
1030 	bgmon.change_on_apply = GTK_TOGGLE_BUTTON( change_on_apply )->active;
1031 	bgmon.remember_locked_state = GTK_TOGGLE_BUTTON( remember_locked_state )->active;
1032 	bgmon.remember_image_number = GTK_TOGGLE_BUTTON( remember_image_number )->active;
1033 	bgmon.simple_scroll_adj = GTK_TOGGLE_BUTTON( simple_scroll_adj )->active;
1034 	bgmon.display_text = GTK_TOGGLE_BUTTON( display_text )->active;
1035 	bgmon.center_text = GTK_TOGGLE_BUTTON( center_text )->active;
1036 	bgmon.display_krell = GTK_TOGGLE_BUTTON( display_krell )->active;
1037 
1038 	/* create new panel, not the first time */
1039 	if( bgmon.reset_config ) pbg_ctx->seconds_left = bgmon.wait_seconds;
1040 	update_image_list(1);
1041 	if( bgmon.change_on_apply ) update_image(-1);
1042 
1043 	if ( bgmon.display_text )
1044 		gkrellm_make_decal_visible( panel, decal_wu );
1045 	else
1046 		gkrellm_make_decal_invisible( panel, decal_wu );
1047 	if ( bgmon.display_krell )
1048 		gkrellm_insert_krell( panel, krell_time, 1 );
1049 	else
1050 		gkrellm_remove_krell( panel, krell_time );
1051 }
1052 
save_config(FILE * f)1053 static void save_config( FILE *f)
1054 {
1055 	fprintf( f, "%s wait_seconds %d\n", CONFIG_KEYWORD, bgmon.wait_seconds );
1056 #if !defined(WIN32)
1057 	fprintf( f, "%s auto_update %d\n", CONFIG_KEYWORD, bgmon.auto_update );
1058 #endif
1059 	fprintf( f, "%s ignore %d\n", CONFIG_KEYWORD, bgmon.ignore );
1060 	fprintf( f, "%s command %s\n", CONFIG_KEYWORD, bgmon.command );
1061 	fprintf( f, "%s parse_cmd_output %d\n", CONFIG_KEYWORD, bgmon.parse_cmd_output );
1062 	fprintf( f, "%s randomise %d\n", CONFIG_KEYWORD, bgmon.randomise );
1063 	fprintf( f, "%s reset %d\n", CONFIG_KEYWORD, bgmon.reset );
1064 	fprintf( f, "%s reset_config %d\n", CONFIG_KEYWORD, bgmon.reset_config );
1065 	fprintf( f, "%s format_string %s\n", CONFIG_KEYWORD, bgmon.format_string );
1066 	fprintf( f, "%s idb %s\n", CONFIG_KEYWORD, bgmon.idb );
1067 	fprintf( f, "%s change_on_load %d\n", CONFIG_KEYWORD, bgmon.change_on_load );
1068 	fprintf( f, "%s change_on_apply %d\n", CONFIG_KEYWORD, bgmon.change_on_apply );
1069 	fprintf( f, "%s remember_locked_state %d\n", CONFIG_KEYWORD, bgmon.remember_locked_state );
1070 	fprintf( f, "%s locked_last_run %d\n", CONFIG_KEYWORD, pbg_ctx->locked );
1071 	fprintf( f, "%s remember_image_number %d\n", CONFIG_KEYWORD, bgmon.remember_image_number );
1072 	if (!pbg_ctx->idb || pbg_ctx->cur_img < 0) {
1073 		fprintf( f, "%s image_nr_last_run %d\n", CONFIG_KEYWORD, 0 );
1074 	} else if (!pbg_ctx->idb_orig) {
1075 		fprintf( f, "%s image_nr_last_run %d\n", CONFIG_KEYWORD,
1076 		         pbg_ctx->cur_img );
1077 	} else {
1078 		GList *list = g_list_nth(pbg_ctx->idb, pbg_ctx->cur_img);
1079 		fprintf( f, "%s image_nr_last_run %d\n", CONFIG_KEYWORD,
1080 		         list ? g_list_index( pbg_ctx->idb_orig, list->data) : 0);
1081 	}
1082 	fprintf( f, "%s simple_scroll_adj %d\n", CONFIG_KEYWORD, bgmon.simple_scroll_adj );
1083 	fprintf( f, "%s scroll_adj_time %d\n", CONFIG_KEYWORD, bgmon.scroll_adj_time );
1084 	fprintf( f, "%s center_text %d\n", CONFIG_KEYWORD, bgmon.center_text );
1085 	fprintf( f, "%s display_text %d\n", CONFIG_KEYWORD, bgmon.display_text );
1086 	fprintf( f, "%s display_krell %d\n", CONFIG_KEYWORD, bgmon.display_krell );
1087 }
1088 
load_config(gchar * arg)1089 static void load_config( gchar *arg )
1090 {
1091 	gchar *command, *p;
1092 
1093 	for( p = arg; *p && isspace(*p); p++ );
1094 	for( ; *p && !isspace(*p); p++ );
1095 
1096 	command = g_malloc( (p-arg+1)*sizeof(char) );
1097 	memset( command, 0x00, p-arg+1 );
1098 	memcpy( command, arg, p-arg );
1099 
1100 	for( ; *p && isspace(*p); p++ );
1101 
1102 	if( !strcmp(command, "wait_seconds") ) bgmon.wait_seconds = atoi( p );
1103 #if !defined(WIN32)
1104 	else if( !strcmp(command, "auto_update") ) bgmon.auto_update = atoi( p );
1105 #endif
1106 	else if( !strcmp(command, "ignore") ) bgmon.ignore = atoi( p );
1107 	else if( !strcmp(command, "command") ) strcpy( bgmon.command, p );
1108 	else if( !strcmp(command, "parse_cmd_output") ) bgmon.parse_cmd_output = atoi( p );
1109 	else if( !strcmp(command, "randomise") ) bgmon.randomise = atoi( p );
1110 	else if( !strcmp(command, "reset") ) bgmon.reset = atoi( p );
1111 	else if( !strcmp(command, "reset_config") ) bgmon.reset_config = atoi( p );
1112 	else if( !strcmp(command, "format_string") ) strcpy( bgmon.format_string, p );
1113 	else if( !strcmp(command, "idb") ) strcpy( bgmon.idb, p );
1114 	else if( !strcmp(command, "change_on_load") ) bgmon.change_on_load = atoi( p );
1115 	else if( !strcmp(command, "change_on_apply") ) bgmon.change_on_apply = atoi( p );
1116 	else if( !strcmp(command, "remember_locked_state") ) bgmon.remember_locked_state = atoi( p );
1117 	else if( !strcmp(command, "locked_last_run") ) bgmon.locked_last_run = atoi( p );
1118 	else if( !strcmp(command, "remember_image_number") ) bgmon.remember_image_number = atoi( p );
1119 	else if( !strcmp(command, "image_nr_last_run") ) bgmon.image_nr_last_run = atoi( p );
1120 	else if( !strcmp(command, "simple_scroll_adj") ) bgmon.simple_scroll_adj = atoi( p );
1121 	else if( !strcmp(command, "scroll_adj_time") ) bgmon.scroll_adj_time = atoi( p );
1122 	else if( !strcmp(command, "center_text") ) bgmon.center_text = atoi( p );
1123 	else if( !strcmp(command, "display_text") ) bgmon.display_text = atoi( p );
1124 	else if( !strcmp(command, "display_krell") ) bgmon.display_krell = atoi( p );
1125 
1126 	g_free( command );
1127 }
1128 
bgchg_atexit()1129 void bgchg_atexit()
1130 {
1131 	g_free( pbg_ctx );
1132 }
1133 
1134 static GkrellmMonitor plugin_mon = {
1135 	.name = CONFIG_NAME,
1136 	.id = 0,
1137 	.create_monitor = create_plugin,
1138 	.update_monitor = update_plugin,
1139 	.create_config = create_bgchg_tab,
1140 	.apply_config = apply_config,
1141 	.save_user_config = save_config,
1142 	.load_user_config = load_config,
1143 	.config_keyword = CONFIG_KEYWORD,
1144 	.undef2 = NULL,
1145 	.undef1 = NULL,
1146 	.privat = NULL,
1147 	.insert_before_id = PLACEMENT,
1148 	.handle = NULL,
1149 	.path = NULL
1150 };
1151 
1152 #if defined(WIN32)
1153 __declspec(dllexport) GkrellmMonitor *
gkrellm_init_plugin(win32_plugin_callbacks * calls)1154 gkrellm_init_plugin(win32_plugin_callbacks* calls)
1155 #else
1156 GkrellmMonitor *gkrellm_init_plugin()
1157 #endif
1158 {
1159 #if defined(WIN32)
1160 	callbacks = calls;
1161 #endif
1162 
1163 	g_atexit( bgchg_atexit );
1164 
1165 	pGK = gkrellm_ticks();
1166 	style_id = gkrellm_add_meter_style( &plugin_mon, STYLE_NAME );
1167 	monitor = &plugin_mon;
1168 	return &plugin_mon;
1169 }
1170