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 #include "log-private.h"
38 
39 // GTK+-win32 automatically uses the application-icon
40 #if GTK_CHECK_VERSION(2,4,0) && !defined(WIN32)
41 #include "icon.xpm"
42 #endif
43 
44 #include <signal.h>
45 
46 
47 struct GkrellmConfig	_GK;
48 GkrellmTicks			GK;
49 
50 struct
51 	{
52 	GtkWidget	*window;		/* Top level window	*/
53 	GtkWidget	*vbox;
54 
55 	GtkWidget	*top0_event_box;	/* Top frame event box */
56 	GtkWidget	*top0_vbox;			/* Top frame			*/
57 
58 	GtkWidget	*middle_hbox;
59 	  GtkWidget	*left_event_box;	/* Holds left vbox.		*/
60 	  GtkWidget	*left_vbox;			/* Holds left frame.	*/
61 
62 	  GtkWidget	*middle_vbox;		/* A handle for sliding shut */
63 	  GtkWidget	*monitor_vbox;		/* All monitors go in here.	*/
64 		GtkWidget	*top1_event_box;	/* First event box */
65 		GtkWidget	*top1_vbox;			/* hostname	*/
66 
67 	  GtkWidget	*right_event_box;	/* Holds right vbox.	*/
68 	  GtkWidget	*right_vbox;		/* Holds right frame.	*/
69 
70 	GtkWidget	*bottom_vbox;	/* Bottom frame	*/
71 
72 	GdkPixmap	*frame_left_pixmap;
73 	GdkBitmap	*frame_left_mask;
74 	GdkPixmap	*frame_right_pixmap;
75 	GdkBitmap	*frame_right_mask;
76 
77 	GdkPixmap	*frame_top_pixmap;
78 	GdkBitmap	*frame_top_mask;
79 	GdkPixmap	*frame_bottom_pixmap;
80 	GdkBitmap	*frame_bottom_mask;
81 
82 	GdkPixmap	*window_transparency_mask;
83 	}
84 	gtree;
85 
86 
87 static GtkWidget *top_window;
88 GList			*gkrellm_monitor_list;
89 time_t			gkrellm_time_now;
90 
91 static GtkUIManager	*ui_manager;
92 
93 static gchar	*geometry;
94 
95 static gint		y_pack;
96 
97 static gint		monitor_previous_height;
98 static gint		monitors_visible	= TRUE;
99 static gint		mask_monitors_visible = TRUE;
100 static gint		check_rootpixmap_transparency;
101 
102 static gboolean	no_transparency,
103 				do_intro,
104 				decorated,
105 				configure_position_lock;
106 
107 static void		apply_frame_transparency(gboolean force);
108 
109 
110 #define	N_FALLBACK_FONTS	3
111 
112 static gchar	*fail_large_font[N_FALLBACK_FONTS] =
113 {
114 "Serif 10",
115 "Ariel 10",
116 "fixed"
117 };
118 
119 static gchar	*fail_normal_font[N_FALLBACK_FONTS] =
120 {
121 "Serif 9",
122 "Ariel 9",
123 "fixed"
124 };
125 
126 static gchar	*fail_small_font[N_FALLBACK_FONTS] =
127 {
128 "Serif 8",
129 "Ariel 8",
130 "fixed"
131 };
132 
133 
134 static gchar	*intro_msg =
135 N_(	"You can configure your monitors by right clicking on\n"
136 	"the top frame of GKrellM or by hitting the F1 key\n"
137 	"with the mouse in the GKrellM window.\n\n"
138 	"Read the Info pages in the config for setup help.");
139 
140 
141 static void
load_font(gchar * font_string,PangoFontDescription ** gk_font,gchar ** fallback_fonts)142 load_font(gchar *font_string, PangoFontDescription **gk_font,
143 				gchar **fallback_fonts)
144 	{
145 	PangoFontDescription	*font_desc = NULL;
146 	gint		i;
147 
148 	if (font_string)
149 		font_desc = pango_font_description_from_string(font_string);
150 	gkrellm_debug(DEBUG_GUI, "load_font: %s %p\n", font_string, font_desc);
151 
152 	if (!font_desc)
153 		{
154 		for (i = 0; !font_desc && i < N_FALLBACK_FONTS; ++i)
155 			{
156 			font_desc = pango_font_description_from_string(fallback_fonts[i]);
157 			gkrellm_debug(DEBUG_GUI, "load_font trying fallback: %s\n",
158 						fallback_fonts[i]);
159 			}
160 		}
161 	if (*gk_font)
162 		pango_font_description_free(*gk_font);
163 	*gk_font = font_desc;
164 	}
165 
166 static void
setup_fonts()167 setup_fonts()
168 	{
169 	load_font(_GK.large_font_string, &_GK.large_font, fail_large_font);
170 	load_font(_GK.normal_font_string, &_GK.normal_font, fail_normal_font);
171 	load_font(_GK.small_font_string, &_GK.small_font, fail_small_font);
172 	if (!_GK.large_font || !_GK.normal_font || !_GK.small_font)
173 		{
174 		g_print(_("Error: Could not load all fonts.\n"));
175 		exit(0);
176 		}
177 	_GK.font_load_count += 1;
178 	}
179 
180 void
gkrellm_map_color_string(gchar * color_string,GdkColor * color)181 gkrellm_map_color_string(gchar *color_string, GdkColor *color)
182 	{
183 	static GdkColormap	*colormap;
184 
185 	if (colormap == NULL)
186 		colormap = gtk_widget_get_colormap(top_window);
187 	if (color->red || color->green || color->blue)
188 		gdk_colormap_free_colors(colormap, color, 1);
189 	if (!color_string)
190 		color_string = "black";
191 	gdk_color_parse(color_string, color);
192 	gdk_colormap_alloc_color(colormap, color, FALSE, TRUE);
193 	}
194 
195 static void
setup_colors()196 setup_colors()
197 	{
198 	GtkWidget	*win	= top_window;
199 
200 	gkrellm_map_color_string(_GK.chart_in_color, &_GK.in_color);
201 	gkrellm_map_color_string(_GK.chart_in_color_grid, &_GK.in_color_grid);
202 
203 	gkrellm_map_color_string(_GK.chart_out_color, &_GK.out_color);
204 	gkrellm_map_color_string(_GK.chart_out_color_grid, &_GK.out_color_grid);
205 
206 	gkrellm_map_color_string("#000000", &_GK.background_color);
207 	gkrellm_map_color_string("#FFFFFF", &_GK.white_color);
208 
209 	if (_GK.draw1_GC == NULL)
210 		{
211 		_GK.draw1_GC = gdk_gc_new( win->window );
212 		gdk_gc_copy( _GK.draw1_GC, win->style->white_gc );
213 		}
214 	if (_GK.draw2_GC == NULL)
215 		{
216 		_GK.draw2_GC = gdk_gc_new( win->window );
217 		gdk_gc_copy( _GK.draw2_GC, win->style->white_gc );
218 		}
219 	if (_GK.draw3_GC == NULL)
220 		{
221 		_GK.draw3_GC = gdk_gc_new( win->window );
222 		gdk_gc_copy( _GK.draw3_GC, win->style->white_gc );
223 		}
224 	if (_GK.draw_stencil_GC == NULL)
225 		{
226 		_GK.draw_stencil_GC = gdk_gc_new( win->window );
227 		gdk_gc_copy(_GK.draw_stencil_GC, win->style->white_gc );
228 		}
229 	if (_GK.text_GC == NULL)
230 		{
231 		_GK.text_GC = gdk_gc_new( win->window );
232 		gdk_gc_copy( _GK.text_GC, win->style->white_gc );
233 		}
234 
235 	/* Set up the depth 1 GCs
236 	*/
237 	/* g_print("white pixel = %ld\n", _GK.white_color.pixel); */
238 	if (_GK.bit1_GC == NULL)
239 		{
240 		GdkBitmap	*dummy_bitmap;
241 		GdkColor	bit_color;
242 
243 		dummy_bitmap = gdk_pixmap_new(top_window->window, 16, 16, 1);
244 		_GK.bit1_GC = gdk_gc_new(dummy_bitmap);
245 		_GK.bit0_GC = gdk_gc_new(dummy_bitmap);
246 		bit_color.pixel = 1;
247 		gdk_gc_set_foreground(_GK.bit1_GC, &bit_color);
248 		bit_color.pixel = 0;
249 		gdk_gc_set_foreground(_GK.bit0_GC, &bit_color);
250 		g_object_unref(G_OBJECT(dummy_bitmap));
251 		}
252 	}
253 
254 
255 static gint	save_position_countdown;
256 
257 static void
set_or_save_position(gint save)258 set_or_save_position(gint save)
259 	{
260 	FILE		*f;
261 	gchar		*path;
262 	gint		x, y;
263 	static gint	x_last = -1,
264 				y_last = -1;
265 
266 	path = gkrellm_make_data_file_name(NULL, "startup_position");
267 	if (save)
268 		{
269 		if (!configure_position_lock && y_pack < 0)
270 			{	/* Most recent configure event may have happened before
271 				|  gkrellm has removed it's lock, so get gdk's cached values.
272 				|  Eg. gkrellm is moved < 2 sec after startup by the window
273 				|  manager.  See cb_configure_notify().
274 				|  But don't update _GK.y_position if current gkrellm position
275 				|  reflects a packed move (ie, not a user set position).
276 				*/
277 			gdk_window_get_position(top_window->window,
278 					&_GK.x_position, &_GK.y_position);
279 			}
280 		if (   !_GK.no_config
281 		    && (_GK.x_position != x_last || _GK.y_position != y_last)
282 			&& (f = g_fopen(path, "w")) != NULL
283 		   )
284 			{
285 			x_last = _GK.x_position;
286 			y_last = _GK.y_position;
287 			fprintf(f, "%d %d\n", _GK.x_position, _GK.y_position);
288 			fclose(f);
289 			gkrellm_debug(DEBUG_POSITION, "save_position: %d %d\n", x_last, y_last);
290 			}
291 		save_position_countdown = 0;
292 		}
293 	else if (!_GK.withdrawn)  /* In slit conflicts with setting position */
294 		{
295 		if ((f = g_fopen(path, "r")) != NULL)
296 			{
297 			x = y = 0;
298 			fscanf(f, "%d %d", &x, &y);
299 			fclose(f);
300 
301 			if (   x >= 0 && x < _GK.w_display - 10
302 				&& y >= 0 && y < _GK.h_display - 25
303 			   )
304 				{
305 				_GK.x_position = x_last = x;
306 				_GK.y_position = y_last = y;
307 				_GK.position_valid = TRUE;
308 				gdk_window_move(gtree.window->window, x, y);
309 				gkrellm_debug(DEBUG_POSITION, "startup_position moveto %d %d (valid)\n", x, y);
310 				}
311 			}
312 		}
313 	g_free(path);
314 	}
315 
316 
317 static gint
update_monitors()318 update_monitors()
319 	{
320 	GList			*list;
321 	GkrellmMonitor			*mon;
322 	struct tm		*pCur, *pPrev;
323 	static time_t	time_prev;
324 
325 	time(&_GK.time_now);
326 	GK.second_tick = (_GK.time_now == time_prev) ? FALSE : TRUE;
327 	time_prev = _GK.time_now;
328 
329 	if (GK.second_tick)
330 		{
331 		pPrev = &gkrellm_current_tm;
332 		pCur = localtime(&_GK.time_now);
333 		GK.two_second_tick  = ((pCur->tm_sec % 2) == 0) ? TRUE : FALSE;
334 		GK.five_second_tick = ((pCur->tm_sec % 5) == 0) ? TRUE : FALSE;
335 		GK.ten_second_tick  = ((pCur->tm_sec % 10) == 0) ? TRUE : FALSE;
336 		GK.minute_tick = (pCur->tm_min  != pPrev->tm_min)  ? TRUE : FALSE;
337 		GK.hour_tick   = (pCur->tm_hour != pPrev->tm_hour) ? TRUE : FALSE;
338 		GK.day_tick    = (pCur->tm_mday != pPrev->tm_mday) ? TRUE : FALSE;
339 
340 		/* Copy localtime() data to my global struct tm data so clock (or
341 		|  anybody) has access to current struct tm data.  Must copy so
342 		|  data is not munged by plugins which might call localtime().
343 		*/
344 		gkrellm_current_tm = *pCur;
345 		}
346 	else
347 		{
348 		GK.two_second_tick = FALSE;
349 		GK.five_second_tick = FALSE;
350 		GK.ten_second_tick = FALSE;
351 		GK.minute_tick = FALSE;
352 		GK.hour_tick = FALSE;
353 		GK.day_tick = FALSE;
354 		}
355 
356 	gkrellm_alert_update();
357 	for (list = gkrellm_monitor_list; list; list = list->next)
358 		{
359 		mon = (GkrellmMonitor *) list->data;
360 		gkrellm_record_state(UPDATE_MONITOR, mon);
361 		if (mon->update_monitor && mon->privat->enabled)
362 			(*(mon->update_monitor))();
363 		}
364 	gkrellm_record_state(INTERNAL, NULL);
365 	++GK.timer_ticks;
366 
367 	if (save_position_countdown > 0 && --save_position_countdown == 0)
368 		set_or_save_position(1);
369 	if (configure_position_lock && (GK.timer_ticks / _GK.update_HZ) > 1)
370 		configure_position_lock = FALSE;
371 
372 
373 	/* Update if background has changed */
374 	if (   GK.second_tick && !no_transparency
375 		&& gkrellm_winop_updated_background()
376 		&& check_rootpixmap_transparency == 0
377 	   )
378 		check_rootpixmap_transparency = 1;
379 
380 	if (_GK.need_frame_packing)
381 		{
382 		gkrellm_pack_side_frames();
383 		apply_frame_transparency(TRUE);
384 		if (!no_transparency)
385 			gkrellm_winop_apply_rootpixmap_transparency();
386 		check_rootpixmap_transparency = 0;
387 		}
388 
389 	if (check_rootpixmap_transparency > 0)
390 		if (--check_rootpixmap_transparency == 0 && !no_transparency)
391 			gkrellm_winop_apply_rootpixmap_transparency();
392 
393 	if (   GK.minute_tick && _GK.config_modified
394 		&& !gkrellm_config_window_shown()
395 	   )
396 		gkrellm_save_user_config();
397 
398 	return TRUE;			/* restarts timeout */
399 	}
400 
401 void
gkrellm_start_timer(gint Hz)402 gkrellm_start_timer(gint Hz)
403 	{
404 	static guint	timeout_id	= 0;
405 	gint		interval;
406 
407 	if (timeout_id)
408 		g_source_remove(timeout_id);
409 	timeout_id = 0;
410 	if (Hz > 0)
411 		{
412 		interval = 1000 / Hz;
413 		interval = interval * 60 / 63;	/* Compensate for overhead XXX */
414 		timeout_id = g_timeout_add(interval,
415 						(GtkFunction) update_monitors,NULL);
416 		}
417 	}
418 
419 GtkWidget *
gkrellm_get_top_window()420 gkrellm_get_top_window()
421 	{
422 	return top_window;
423 	}
424 
425 GkrellmTicks *
gkrellm_ticks(void)426 gkrellm_ticks(void)
427 	{
428 	return &GK;
429 	}
430 
431 gint
gkrellm_get_timer_ticks(void)432 gkrellm_get_timer_ticks(void)
433 	{
434 	return GK.timer_ticks;
435 	}
436 
437 
438   /* Nice set of effects I have here...  Either shadow effect or none.
439   |  Returning 1 means shadow effect and the return value is also used by
440   |  callers to increment height fields to allow for the offset shadow draw.
441   */
442 gint
gkrellm_effect_string_value(gchar * effect_string)443 gkrellm_effect_string_value(gchar *effect_string)
444 	{
445 	if (effect_string)
446 		return (strcmp(effect_string, "shadow") == 0) ? 1 : 0;
447 	return 0;
448 	}
449 
450   /* Before 1.0.3 text, decals, krells used top/bottom borders for placement.
451   |  This is to allow themes to transition to using top/bottom_margin.
452   */
453 void
gkrellm_get_top_bottom_margins(GkrellmStyle * style,gint * top,gint * bottom)454 gkrellm_get_top_bottom_margins(GkrellmStyle *style, gint *top, gint *bottom)
455 	{
456 	gint	t = 0,
457 			b = 0;
458 
459 	if (style)
460 		{
461 		if (   _GK.use_top_bottom_margins		/* XXX */
462 			|| g_list_find(_GK.chart_style_list, style)
463 		   )
464 			{
465 			t = style->margin.top;
466 			b = style->margin.bottom;
467 			}
468 		else
469 			{
470 			t = style->border.top * _GK.theme_scale / 100;
471 			b = style->border.bottom * _GK.theme_scale / 100;
472 			}
473 		}
474 	if (top)
475 		*top = t;
476 	if (bottom)
477 		*bottom = b;
478 	}
479 
480 GkrellmMargin *
gkrellm_get_style_margins(GkrellmStyle * style)481 gkrellm_get_style_margins(GkrellmStyle *style)
482 	{
483 	static GkrellmMargin	m_default = {0,0,0,0};
484 
485 	if (!style)
486 		return &m_default;
487 	gkrellm_get_top_bottom_margins(style,
488 				&style->margin.top, &style->margin.bottom);		/* XXX */
489 	return &style->margin;
490 	}
491 
492 void
gkrellm_set_style_margins(GkrellmStyle * style,GkrellmMargin * margin)493 gkrellm_set_style_margins(GkrellmStyle *style, GkrellmMargin *margin)
494 	{
495 	if (style && margin)
496 		style->margin = *margin;
497 	}
498 
499 void
gkrellm_draw_string(GdkDrawable * drawable,GkrellmTextstyle * ts,gint x,gint y,gchar * s)500 gkrellm_draw_string(GdkDrawable *drawable, GkrellmTextstyle *ts,
501 			gint x, gint y, gchar *s)
502 	{
503 	if (!drawable || !ts || !s)
504 		return;
505 	if (ts->effect)
506 		{
507 		gdk_gc_set_foreground(_GK.text_GC, &ts->shadow_color);
508 		gkrellm_gdk_draw_string(drawable, ts->font, _GK.text_GC,
509 					x + 1, y + 1, s);
510 		}
511 	gdk_gc_set_foreground(_GK.text_GC, &ts->color);
512 	gkrellm_gdk_draw_string(drawable, ts->font, _GK.text_GC, x, y, s);
513 	}
514 
515 void
gkrellm_draw_text(GdkDrawable * drawable,GkrellmTextstyle * ts,gint x,gint y,gchar * s,gint len)516 gkrellm_draw_text(GdkDrawable *drawable, GkrellmTextstyle *ts, gint x, gint y,
517 			gchar *s, gint len)
518 	{
519 	if (!drawable || !ts || !s)
520 		return;
521 	if (ts->effect)
522 		{
523 		gdk_gc_set_foreground(_GK.text_GC, &ts->shadow_color);
524 		gkrellm_gdk_draw_text(drawable, ts->font, _GK.text_GC,
525 					x + 1, y + 1, s, len);
526 		}
527 	gdk_gc_set_foreground(_GK.text_GC, &ts->color);
528 	gkrellm_gdk_draw_text(drawable, ts->font, _GK.text_GC, x, y, s, len);
529 	}
530 
531 gint
gkrellm_label_x_position(gint position,gint w_field,gint w_label,gint margin)532 gkrellm_label_x_position(gint position, gint w_field, gint w_label,
533 				gint margin)
534 	{
535 	gint	x;
536 
537 	x = w_field * position / GKRELLM_LABEL_MAX;
538 	x -= w_label / 2;
539 	if (x > w_field - w_label - margin)
540 		x = w_field - w_label - margin;
541 	if (x < margin)
542 		x = margin;
543 	return x;
544 	}
545 
546 /* ---------------------------------------------------------------------- */
547 #define	RESISTANCE_PIXELS	35
548 
549 static gint		moving_gkrellm	= FALSE;
550 static gint		x_press_event, y_press_event;
551 static gint		gkrellm_width, gkrellm_height;
552 
553 void
gkrellm_motion(GtkWidget * widget,GdkEventMotion * ev,gpointer data)554 gkrellm_motion(GtkWidget *widget, GdkEventMotion *ev, gpointer data)
555 	{
556 	gint			x_pointer, y_pointer, x, y, right_zone, bottom_zone;
557 	GdkModifierType	m;
558 
559 	if (moving_gkrellm)
560 		{
561 		m = ev->state;
562 		if (!(m & GDK_BUTTON1_MASK))
563 			{
564 			moving_gkrellm = FALSE;
565 			return;
566 			}
567 		/* Catch up to the pointer so GKrellM does not lag the pointer motion.
568 		*/
569 		gkrellm_winop_flush_motion_events();
570 		gdk_window_get_pointer(NULL, &x_pointer, &y_pointer, &m);
571 
572 		/* Subtract press event coordinates to account for pointer offset
573 		|  into top_window.  Have edge resistance to the move.
574 		*/
575 		x = x_pointer - x_press_event;
576 		y = y_pointer - y_press_event;
577 		right_zone = _GK.w_display - gkrellm_width;
578 		bottom_zone = _GK.h_display - gkrellm_height;
579 
580 		if (_GK.x_position >= 0 && x < 0 && x > -RESISTANCE_PIXELS)
581 			x = 0;
582 		if (   _GK.x_position <= right_zone
583 			&& x > right_zone && x < right_zone + RESISTANCE_PIXELS
584 		   )
585 			x = right_zone;
586 		if (_GK.y_position >= 0 && y < 0 && y > -RESISTANCE_PIXELS)
587 			y = 0;
588 		if (   _GK.y_position <= bottom_zone
589 			&& y > bottom_zone && y < bottom_zone + RESISTANCE_PIXELS
590 		   )
591 			y = bottom_zone;
592 
593 		/* Moves to x,y position relative to root.
594 		*/
595 		_GK.y_position = y;
596 		_GK.x_position = x;
597 		_GK.position_valid = TRUE;
598 		gdk_window_move(top_window->window, x, y);
599 		}
600 	}
601 
602 void
gkrellm_menu_popup(void)603 gkrellm_menu_popup(void)
604 	{
605             gtk_menu_popup(GTK_MENU(gtk_ui_manager_get_widget(ui_manager, "/popup")), NULL, NULL, NULL, NULL,
606 					0, gtk_get_current_event_time());
607 	}
608 
609 static void
top_frame_button_release(GtkWidget * widget,GdkEventButton * ev,gpointer data)610 top_frame_button_release(GtkWidget *widget, GdkEventButton *ev, gpointer data)
611 	{
612 	if (!no_transparency)
613 		gkrellm_winop_apply_rootpixmap_transparency();
614 	moving_gkrellm = FALSE;
615 	gkrellm_debug(DEBUG_POSITION, "gkrellm moveto: x_pos=%d y_pos=%d\n",
616 				_GK.x_position, _GK.y_position);
617 	}
618 
619 static gboolean
top_frame_button_press(GtkWidget * widget,GdkEventButton * ev,gpointer data)620 top_frame_button_press(GtkWidget *widget, GdkEventButton *ev, gpointer data)
621 	{
622 	gint			x_pointer, y_pointer;
623 	GdkModifierType	m;
624 	time_t			time_check;
625 
626 	gdk_window_get_pointer(NULL, &x_pointer, &y_pointer, &m);
627 	_GK.w_display = gdk_screen_get_width(gdk_screen_get_default());
628 	_GK.h_display = gdk_screen_get_height(gdk_screen_get_default());
629 	gkrellm_width = _GK.chart_width
630 				+ _GK.frame_left_width + _GK.frame_right_width;
631 	gkrellm_height = _GK.monitor_height + _GK.total_frame_height;
632 
633 	/* If system time is changed, gtk_timeout_add() setting gets
634 	|  confused, so put some duct tape here ...
635 	*/
636 	time(&time_check);
637 	if (time_check > _GK.time_now + 2 || time_check < _GK.time_now)
638 		gkrellm_start_timer(_GK.update_HZ);
639 
640 	if (ev->button == 3)
641 		{
642 		gtk_menu_popup(GTK_MENU(gtk_ui_manager_get_widget(ui_manager, "/popup")), NULL, NULL, NULL, NULL,
643 					ev->button, ev->time);
644 		return FALSE;
645 		}
646 	gtk_window_present(GTK_WINDOW(top_window));
647 
648 	if (   _GK.client_mode
649 	    && gkrellm_client_server_connect_state() == DISCONNECTED
650 	   )
651 		gkrellm_client_mode_connect_thread();
652 
653 	if (!_GK.withdrawn)		/* Move window unless in the slit */
654 		{
655 		/* I need pointer coords relative to top_window.  So, add in offsets
656 		|  to hostname window if that is where we pressed.
657 		*/
658 		x_press_event = ev->x;
659 		y_press_event = ev->y;
660 		if (widget == gtree.top1_event_box)
661 			{
662 			x_press_event += _GK.frame_left_width;
663 			y_press_event += _GK.frame_top_height;
664 			}
665 		moving_gkrellm = TRUE;
666 		configure_position_lock = FALSE;
667 		}
668 	return FALSE;
669 	}
670 
671 #define	CLOSE_LEFT	0
672 #define	CLOSE_RIGHT	1
673 
674 
675   /* If any frame images have transparency (masks != NULL) use the
676   |  frame masks to construct a main window sized mask.
677   */
678 static void
apply_frame_transparency(gboolean force)679 apply_frame_transparency(gboolean force)
680 	{
681 	GtkWidget			*win;
682 	gint				w, h;
683 	static gint			w_prev, h_prev;
684 
685 	if (decorated)
686 		return;
687 
688 	win = gtree.window;
689 	w = _GK.chart_width + _GK.frame_left_width + _GK.frame_right_width;
690 	h = _GK.monitor_height + _GK.total_frame_height;
691 	if (!gtree.window_transparency_mask || w != w_prev || h != h_prev)
692 		{
693 		if (gtree.window_transparency_mask)
694 			g_object_unref(G_OBJECT(gtree.window_transparency_mask));
695 		gtree.window_transparency_mask = gdk_pixmap_new(win->window, w, h, 1);
696 		w_prev = w;
697 		h_prev = h;
698 		}
699 	else if (!force && monitors_visible == mask_monitors_visible)
700 		return;
701 
702 	/* Set entire shape mask to 1, then write in the frame masks.
703 	*/
704 	gdk_draw_rectangle(gtree.window_transparency_mask, _GK.bit1_GC, TRUE,
705 				0, 0, w, h);
706 
707 	if (monitors_visible)
708 		{
709 		if (gtree.frame_top_mask)
710 			gdk_draw_drawable(gtree.window_transparency_mask, _GK.bit1_GC,
711 				gtree.frame_top_mask, 0, 0,  0, 0,  w, _GK.frame_top_height);
712 		if (gtree.frame_bottom_mask)
713 			gdk_draw_drawable(gtree.window_transparency_mask, _GK.bit1_GC,
714 				gtree.frame_bottom_mask,
715 				0, 0, 0, h - _GK.frame_bottom_height,
716 				w, _GK.frame_bottom_height);
717 
718 		if (gtree.frame_left_mask)
719 			gdk_draw_drawable(gtree.window_transparency_mask, _GK.bit1_GC,
720 				gtree.frame_left_mask,
721 				0, 0,  0, _GK.frame_top_height,
722 				_GK.frame_left_width, _GK.monitor_height);
723 
724 		if (gtree.frame_right_mask)
725 			gdk_draw_drawable(gtree.window_transparency_mask, _GK.bit1_GC,
726 				gtree.frame_right_mask,
727 				0, 0,  w - _GK.frame_right_width, _GK.frame_top_height,
728 				_GK.frame_right_width, _GK.monitor_height);
729 		}
730 	else	/* Top and bottom frames are not visible and GKrellM is shut */
731 		{
732 		if (gtree.frame_left_mask)
733 			gdk_draw_drawable(gtree.window_transparency_mask, _GK.bit1_GC,
734 				gtree.frame_left_mask,
735 				0, 0,  0, 0,
736 				_GK.frame_left_width, _GK.monitor_height);
737 
738 		if (gtree.frame_right_mask)
739 			gdk_draw_drawable(gtree.window_transparency_mask, _GK.bit1_GC,
740 				gtree.frame_right_mask,
741 				0, 0,  _GK.frame_left_width, 0,
742 				_GK.frame_right_width, _GK.monitor_height);
743 		}
744 
745 	gtk_widget_shape_combine_mask(gtree.window,
746 						gtree.window_transparency_mask, 0, 0);
747 	mask_monitors_visible = monitors_visible;
748 	}
749 
750 static gboolean
side_frame_button_press(GtkWidget * widget,GdkEventButton * ev,gpointer data)751 side_frame_button_press(GtkWidget *widget, GdkEventButton *ev, gpointer data)
752 	{
753 	static gint		direction;
754 	gint			x_gkrell, y_gkrell;
755 
756 	if (ev->button == 3)
757 		{
758 		gtk_menu_popup(GTK_MENU(gtk_ui_manager_get_widget(ui_manager, "/popup")), NULL, NULL, NULL, NULL,
759 					ev->button, ev->time);
760 		return FALSE;
761 		}
762 	if (decorated || _GK.withdrawn)
763 		return FALSE;
764 	gdk_window_get_origin(gtree.window->window, &x_gkrell, &y_gkrell);
765 	direction = (x_gkrell < _GK.w_display / 2) ? CLOSE_LEFT : CLOSE_RIGHT;
766 
767 	if (ev->button == 2 || (_GK.m2 && ev->button == 1))
768 		{
769 		monitors_visible = !monitors_visible;
770 		if (monitors_visible)
771 			{
772 			gtk_widget_show(gtree.middle_vbox);
773 			gtk_widget_show(gtree.top0_vbox);
774 			gtk_widget_show(gtree.bottom_vbox);
775 			while (gtk_events_pending())
776 				gtk_main_iteration ();
777 			if (direction == CLOSE_RIGHT)
778 				gdk_window_move(gtree.window->window,
779 								x_gkrell - _GK.chart_width, y_gkrell);
780 			}
781 		else
782 			{
783 			gtk_widget_hide(gtree.top0_vbox);
784 			gtk_widget_hide(gtree.bottom_vbox);
785 			gtk_widget_hide(gtree.middle_vbox);
786 			while (gtk_events_pending())
787 				gtk_main_iteration ();
788 			if (direction == CLOSE_RIGHT)
789 				gdk_window_move(gtree.window->window,
790 								x_gkrell + _GK.chart_width, y_gkrell);
791 			}
792 		gdk_flush();  /* Avoid double click race */
793 		}
794 	return FALSE;
795 	}
796 
797 
798 static void
create_frame_top(GtkWidget * vbox)799 create_frame_top(GtkWidget *vbox)
800 	{
801 	static GtkWidget	*ft_vbox;
802 	static GtkWidget	*ft_image;
803 	GkrellmPiximage		*im;
804 	gint				w, h;
805 
806 	if (decorated)
807 		return;
808 	im = _GK.frame_top_piximage;
809 
810 	w = _GK.chart_width + _GK.frame_left_width + _GK.frame_right_width;
811 	h = (_GK.frame_top_height > 0) ? _GK.frame_top_height
812 				: gdk_pixbuf_get_height(im->pixbuf);
813 //	h = h * _GK.theme_scale / 100;
814 
815 	_GK.frame_top_height = h;
816 
817 	_GK.total_frame_height += h;
818 	gkrellm_scale_piximage_to_pixmap(im,
819 				&gtree.frame_top_pixmap, &gtree.frame_top_mask, w, h);
820 
821 	if (!ft_vbox)
822 		{
823 		ft_vbox = gtk_vbox_new(FALSE, 0);
824 		gtk_container_add(GTK_CONTAINER(vbox), ft_vbox);
825 		gtk_widget_show(ft_vbox);
826 
827 		ft_image = gtk_image_new_from_pixmap(gtree.frame_top_pixmap, NULL);
828 		gtk_box_pack_start(GTK_BOX(ft_vbox), ft_image, FALSE, FALSE, 0);
829 		gtk_widget_show(ft_image);
830 		}
831 	else
832 		gtk_image_set_from_pixmap(GTK_IMAGE(ft_image),
833 				gtree.frame_top_pixmap, NULL);
834 	}
835 
836 static void
create_frame_bottom(GtkWidget * vbox)837 create_frame_bottom(GtkWidget *vbox)
838 	{
839 	static GtkWidget	*fb_vbox;
840 	static GtkWidget	*fb_image;
841 	GkrellmPiximage		*im;
842 	gint				w, h;
843 
844 	if (decorated)
845 		return;
846 	im = _GK.frame_bottom_piximage;
847 
848 	w = _GK.chart_width + _GK.frame_left_width + _GK.frame_right_width;
849 	h = (_GK.frame_bottom_height > 0) ? _GK.frame_bottom_height
850 				: gdk_pixbuf_get_height(im->pixbuf);
851 //	h = h * _GK.theme_scale / 100;
852 
853 	_GK.frame_bottom_height = h;
854 
855 	_GK.total_frame_height += h;
856 	gkrellm_scale_piximage_to_pixmap(im,
857 				&gtree.frame_bottom_pixmap, &gtree.frame_bottom_mask, w, h);
858 	if (fb_vbox == NULL)
859 		{
860 		fb_vbox = gtk_vbox_new(FALSE, 0);
861 		gtk_container_add(GTK_CONTAINER(vbox), fb_vbox);
862 		gtk_widget_show(fb_vbox);
863 
864 		fb_image = gtk_image_new_from_pixmap(gtree.frame_bottom_pixmap, NULL);
865 		gtk_box_pack_start(GTK_BOX(fb_vbox), fb_image, FALSE, FALSE, 0);
866 		gtk_widget_show(fb_image);
867 		}
868 	else
869 		gtk_image_set_from_pixmap(GTK_IMAGE(fb_image),
870 				gtree.frame_bottom_pixmap, NULL);
871 	}
872 
873 static void
frame_transparency_warning(void)874 frame_transparency_warning(void)
875     {
876     static gint warned = -1;
877 
878 	if (warned != _GK.theme_reload_count && _GK.command_line_theme)
879 		fprintf(stderr,
880 "Warning: frame overlap transparency may not work.  If any of the frame,\n"
881 "         chart, panel, spacer, or cap images have transparency, then all\n"
882 "         may need transparency.\n");
883 	warned = _GK.theme_reload_count;
884 	}
885 
886 static void
draw_cap(GkrellmPiximage * piximage,gint y_mon,gint h_mon,gint h_spacer,gboolean top,gboolean left)887 draw_cap(GkrellmPiximage *piximage, gint y_mon, gint h_mon, gint h_spacer,
888 		gboolean top, gboolean left)
889 	{
890 	GdkPixmap	*pixmap = NULL;
891 	GdkBitmap	*mask = NULL;
892 	GdkBitmap	*frame_mask;
893 	gint		y, x_dst, h_pix, w_pix, h_cap;
894 
895 	if (!piximage || !piximage->pixbuf)
896 		return;
897 	h_pix = gdk_pixbuf_get_height(piximage->pixbuf);
898 	w_pix = gdk_pixbuf_get_width(piximage->pixbuf);
899 //	h_pix = h_pix * _GK.theme_scale / 100;
900 //	w_pix = w_pix * _GK.theme_scale / 100;
901 
902 	y = top ? y_mon + h_spacer : y_mon + h_mon - h_pix - h_spacer;
903 	if (y < y_mon)
904 		y = y_mon;
905 
906 	h_cap = (y + h_pix <= y_mon + h_mon) ? h_pix : y_mon + h_mon - y;
907 	if (h_cap <= 0)
908 		return;
909 
910 	x_dst = left ? 0 : _GK.frame_right_width - w_pix;
911 	gkrellm_scale_piximage_to_pixmap(piximage, &pixmap, &mask, w_pix, h_pix);
912 	gdk_draw_drawable(
913 				left ? gtree.frame_left_pixmap : gtree.frame_right_pixmap,
914 				_GK.draw1_GC, pixmap, 0, 0, x_dst, y, w_pix, h_cap);
915 
916 	frame_mask = left ? gtree.frame_left_mask : gtree.frame_right_mask;
917 	if (mask && frame_mask)
918 		gdk_draw_drawable(frame_mask, _GK.bit1_GC, mask,
919 				0, 0, x_dst, y, w_pix, h_cap);
920 	else if (mask || frame_mask)
921 		frame_transparency_warning();
922 
923 	gkrellm_free_pixmap(&pixmap);
924 	gkrellm_free_bitmap(&mask);
925 	}
926 
927 static void
draw_frame_caps(GkrellmMonitor * mon)928 draw_frame_caps(GkrellmMonitor *mon)
929 	{
930 	GkrellmMonprivate	*mp = mon->privat;
931 	gint				y, h, h_left, h_right;
932 
933 	if (!mp->main_vbox || mp->cap_images_off)
934 		return;
935 	y = mp->main_vbox->allocation.y;
936 	h = mp->main_vbox->allocation.height;
937 	if (mon != gkrellm_mon_host())
938 		y -= _GK.frame_top_height;
939 
940 	h_left = h_right = 0;
941 	if (mp->top_spacer.piximage && _GK.frame_left_spacer_overlap)
942 		h_left = mp->top_spacer.height;
943 	if (mp->top_spacer.piximage && _GK.frame_right_spacer_overlap)
944 		h_right = mp->top_spacer.height;
945 
946 	if (mp->top_type == GKRELLM_SPACER_CHART)
947 		{
948 		draw_cap(_GK.cap_top_left_chart_piximage, y, h, h_left, 1, 1);
949 		draw_cap(_GK.cap_top_right_chart_piximage, y, h, h_right, 1, 0);
950 		}
951 	else
952 		{
953 		draw_cap(_GK.cap_top_left_meter_piximage, y, h, h_left, 1, 1);
954 		draw_cap(_GK.cap_top_right_meter_piximage, y, h, h_right, 1, 0);
955 		}
956 
957 	h_left = h_right = 0;
958 	if (mp->bottom_spacer.piximage && _GK.frame_left_spacer_overlap)
959 		h_left = mp->bottom_spacer.height;
960 	if (mp->bottom_spacer.piximage && _GK.frame_right_spacer_overlap)
961 		h_right = mp->bottom_spacer.height;
962 
963 	if (mp->bottom_type == GKRELLM_SPACER_CHART)
964 		{
965 		draw_cap(_GK.cap_bottom_left_chart_piximage, y, h, h_left, 0, 1);
966 		draw_cap(_GK.cap_bottom_right_chart_piximage, y, h, h_right, 0, 0);
967 		}
968 	else
969 		{
970 		draw_cap(_GK.cap_bottom_left_meter_piximage, y, h, h_left, 0, 1);
971 		draw_cap(_GK.cap_bottom_right_meter_piximage, y, h, h_right, 0, 0);
972 		}
973 	}
974 
975 static void
draw_left_frame_overlap(GdkPixbuf * pixbuf,GkrellmBorder * border,gint y_frame,gint overlap,gint height)976 draw_left_frame_overlap(GdkPixbuf *pixbuf, GkrellmBorder *border,
977 			gint y_frame, gint overlap, gint height)
978 	{
979 	GkrellmPiximage		piximage;
980 	GdkPixmap			*pixmap = NULL;
981 	GdkBitmap			*mask = NULL;
982 	gint				h_pixbuf;
983 
984 	if (overlap <= 0)
985 		return;
986 	h_pixbuf = gdk_pixbuf_get_height(pixbuf);
987 	piximage.pixbuf = gdk_pixbuf_new_subpixbuf(pixbuf, 0, 0,
988 						overlap, h_pixbuf);
989 	piximage.border = *border;
990 	gkrellm_scale_piximage_to_pixmap(&piximage, &pixmap, &mask,
991 						overlap, height);
992 	g_object_unref(G_OBJECT(piximage.pixbuf));
993 	gdk_draw_drawable(gtree.frame_left_pixmap, _GK.draw1_GC, pixmap,
994 					0, 0, _GK.frame_left_width - overlap, y_frame,
995 					overlap, height);
996 	if (mask && gtree.frame_left_mask)
997 		gdk_draw_drawable(gtree.frame_left_mask, _GK.bit1_GC, mask,
998 					0, 0, _GK.frame_left_width - overlap, y_frame,
999 					overlap, height);
1000 	else if (mask || gtree.frame_left_mask)
1001 		frame_transparency_warning();
1002 
1003 	gkrellm_free_pixmap(&pixmap);
1004 	gkrellm_free_bitmap(&mask);
1005 	}
1006 
1007 static void
draw_right_frame_overlap(GdkPixbuf * pixbuf,GkrellmBorder * border,gint y_frame,gint overlap,gint height)1008 draw_right_frame_overlap(GdkPixbuf *pixbuf, GkrellmBorder *border,
1009 			gint y_frame, gint overlap, gint height)
1010 	{
1011 	GkrellmPiximage		piximage;
1012 	GdkPixmap			*pixmap = NULL;
1013 	GdkBitmap			*mask = NULL;
1014 	gint				w_pixbuf, h_pixbuf;
1015 
1016 	if (overlap <= 0)
1017 		return;
1018 	w_pixbuf = gdk_pixbuf_get_width(pixbuf);
1019 	h_pixbuf = gdk_pixbuf_get_height(pixbuf);
1020 	piximage.pixbuf = gdk_pixbuf_new_subpixbuf(pixbuf,
1021 						w_pixbuf - overlap, 0, overlap, h_pixbuf);
1022 	piximage.border = *border;
1023 	gkrellm_scale_piximage_to_pixmap(&piximage, &pixmap, &mask,
1024 					overlap, height);
1025 	g_object_unref(G_OBJECT(piximage.pixbuf));
1026 	gdk_draw_drawable(gtree.frame_right_pixmap, _GK.draw1_GC, pixmap,
1027 					0, 0, 0, y_frame, overlap, height);
1028 	if (mask && gtree.frame_right_mask)
1029 		gdk_draw_drawable(gtree.frame_right_mask, _GK.bit1_GC, mask,
1030 					0, 0, 0, y_frame, overlap, height);
1031 	else if (mask || gtree.frame_right_mask)
1032 		frame_transparency_warning();
1033 
1034 	gkrellm_free_pixmap(&pixmap);
1035 	gkrellm_free_bitmap(&mask);
1036 	}
1037 
1038 static void
draw_frame_overlaps(void)1039 draw_frame_overlaps(void)
1040 	{
1041 	GList				*list;
1042 	GkrellmMonitor		*mon;
1043 	GkrellmMonprivate	*mp;
1044 	GkrellmChart		*cp;
1045 	GkrellmPanel		*p;
1046 	GkrellmMargin		*m;
1047 	gint				y;
1048 	static GkrellmBorder zero_border;
1049 
1050 	for (list = gkrellm_get_chart_list(); list; list = list->next)
1051 		{
1052 		cp = (GkrellmChart *) list->data;
1053 		mon = (GkrellmMonitor *) cp->monitor;
1054 		if (!mon->privat->enabled || !cp->shown || cp->y_mapped < 0)
1055 			continue;
1056 
1057 		m = gkrellm_get_style_margins(cp->style);
1058 		y = cp->y_mapped - _GK.frame_top_height;
1059 
1060 		draw_left_frame_overlap(cp->bg_piximage->pixbuf,
1061 					&_GK.frame_left_chart_border, y - m->top,
1062 					_GK.frame_left_chart_overlap, cp->h + m->top + m->bottom);
1063 		draw_right_frame_overlap(cp->bg_piximage->pixbuf,
1064 					&_GK.frame_right_chart_border, y - m->top,
1065 					_GK.frame_right_chart_overlap, cp->h + m->top + m->bottom);
1066 		}
1067 	for (list = gkrellm_get_panel_list(); list; list = list->next)
1068 		{
1069 		p = (GkrellmPanel *) list->data;
1070 		mon = (GkrellmMonitor *) p->monitor;
1071 		if (!mon->privat->enabled || !p->shown || p->y_mapped < 0)
1072 			continue;
1073 		y = p->y_mapped;
1074 
1075 		/* Special case:  hostname is in an event box and its y_mapped is
1076 		|  relative to that event box window, or 0.  All other panels/charts
1077 		|  are relative to the top level window which includes the top frame.
1078 		*/
1079 		if (mon != gkrellm_mon_host())
1080 			y -= _GK.frame_top_height;
1081 
1082 		draw_left_frame_overlap(p->bg_piximage->pixbuf,
1083 					&_GK.frame_left_panel_border, y,
1084 					_GK.frame_left_panel_overlap, p->h);
1085 		draw_right_frame_overlap(p->bg_piximage->pixbuf,
1086 					&_GK.frame_right_panel_border, y,
1087 					_GK.frame_right_panel_overlap, p->h);
1088 		}
1089 	for (list = gkrellm_monitor_list; list; list = list->next)
1090 		{
1091 		mon = (GkrellmMonitor *) list->data;
1092 		mp = mon->privat;
1093 		if (!mp->enabled || !mp->spacers_shown)
1094 			continue;
1095 		if (mp->top_spacer.image && !mp->spacer_overlap_off)
1096 			{
1097 			y = mp->top_spacer.image->allocation.y;
1098 			if (mon != gkrellm_mon_host())
1099 				y -= _GK.frame_top_height;
1100 			draw_left_frame_overlap(mp->top_spacer.piximage->pixbuf,
1101 					&zero_border, y,
1102 					_GK.frame_left_spacer_overlap, mp->top_spacer.height);
1103 			draw_right_frame_overlap(mp->top_spacer.piximage->pixbuf,
1104 					&zero_border, y,
1105 					_GK.frame_right_spacer_overlap, mp->top_spacer.height);
1106 			}
1107 		if (mp->bottom_spacer.image && !mp->spacer_overlap_off)
1108 			{
1109 			y = mp->bottom_spacer.image->allocation.y;
1110 			if (mon != gkrellm_mon_host())
1111 				y -= _GK.frame_top_height;
1112 			draw_left_frame_overlap(mp->bottom_spacer.piximage->pixbuf,
1113 					&zero_border, y,
1114 					_GK.frame_left_spacer_overlap, mp->bottom_spacer.height);
1115 			draw_right_frame_overlap(mp->bottom_spacer.piximage->pixbuf,
1116 					&zero_border, y,
1117 					_GK.frame_right_spacer_overlap, mp->bottom_spacer.height);
1118 			}
1119 		draw_frame_caps(mon);
1120 		}
1121 	}
1122 
1123 static gint	freeze_packing;
1124 
1125 void
gkrellm_freeze_side_frame_packing(void)1126 gkrellm_freeze_side_frame_packing(void)
1127 	{
1128 	freeze_packing += 1;
1129 	}
1130 
1131 void
gkrellm_thaw_side_frame_packing(void)1132 gkrellm_thaw_side_frame_packing(void)
1133 	{
1134 	if (freeze_packing > 0)
1135 		{
1136 		freeze_packing -= 1;
1137 		if (freeze_packing == 0)
1138 			gkrellm_pack_side_frames();
1139 		}
1140 	}
1141 
1142 void
gkrellm_pack_side_frames(void)1143 gkrellm_pack_side_frames(void)
1144 	{
1145 	static GtkWidget	*lf_image, *rf_image;
1146 	gint				x_gkrell, y_gkrell, y_bottom;
1147 	gint				w, h;
1148 	gboolean			was_on_bottom;
1149 
1150 	if (   ! _GK.initialized
1151 		|| (   monitor_previous_height == _GK.monitor_height
1152 			&& !_GK.need_frame_packing
1153 		   )
1154 		|| freeze_packing
1155 	   )
1156 		return;
1157 	_GK.need_frame_packing = FALSE;
1158 	if (decorated)
1159 		{
1160 		_GK.frame_left_width = 0;
1161 		_GK.frame_right_width = 0;
1162 		return;
1163 		}
1164 
1165 	gdk_window_get_origin(gtree.window->window, &x_gkrell, &y_gkrell);
1166 	gdk_drawable_get_size(gtree.window->window, &w, &h);
1167 	was_on_bottom = (y_gkrell + h >= _GK.h_display) ? TRUE : FALSE;
1168 
1169 	gkrellm_scale_piximage_to_pixmap(_GK.frame_left_piximage,
1170 				&gtree.frame_left_pixmap, &gtree.frame_left_mask,
1171 				_GK.frame_left_width, _GK.monitor_height);
1172 	gkrellm_scale_piximage_to_pixmap(_GK.frame_right_piximage,
1173 				&gtree.frame_right_pixmap, &gtree.frame_right_mask,
1174 				_GK.frame_right_width, _GK.monitor_height);
1175 	draw_frame_overlaps();
1176 
1177 	if (!lf_image)
1178 		{
1179 		lf_image = gtk_image_new_from_pixmap(gtree.frame_left_pixmap, NULL);
1180 		gtk_box_pack_start(GTK_BOX(gtree.left_vbox), lf_image,
1181 					FALSE, FALSE, 0);
1182 		gtk_widget_show(lf_image);
1183 		}
1184 	else
1185 		gtk_image_set_from_pixmap(GTK_IMAGE(lf_image),
1186 					gtree.frame_left_pixmap, NULL);
1187 
1188 	if (!rf_image)
1189 		{
1190 		rf_image = gtk_image_new_from_pixmap(gtree.frame_right_pixmap, NULL);
1191 		gtk_box_pack_start(GTK_BOX(gtree.right_vbox), rf_image,
1192 					FALSE, FALSE, 0);
1193 		gtk_widget_show(rf_image);
1194 		}
1195 	else
1196 		gtk_image_set_from_pixmap(GTK_IMAGE(rf_image),
1197 					gtree.frame_right_pixmap, NULL);
1198 
1199 	/* If height changed so that all of GKrellM would be visible if at last
1200 	|  user set _GK.y_position, then make sure we are really at the user set
1201 	|  _GK.y_position.   This is a y memory effect in case a previous
1202 	|  side frame packing caused a y move.
1203 	*/
1204 	h = _GK.monitor_height + _GK.total_frame_height;
1205 	y_bottom = _GK.h_display - (_GK.y_position + h);
1206 	if (y_bottom >= 0)
1207 		{
1208 		if (_GK.y_position != y_gkrell && _GK.position_valid)
1209 			{
1210 			gdk_window_move(gtree.window->window,
1211 							_GK.x_position, _GK.y_position);
1212 			gkrellm_debug(DEBUG_POSITION,
1213 				"pack moveto %d %d=y_position (y_gkrell=%d y_bot=%d)\n",
1214 				_GK.x_position, _GK.y_position, y_gkrell, y_bottom);
1215 			}
1216 		y_pack = -1;
1217 		}
1218 	else	/* Otherwise, do a y move to maximize visibility */
1219 		{
1220 		/* If GKrellM grows in height and bottom is moved off screen, move so
1221 		|  that all of GKrellM is visible.
1222 		*/
1223 		y_bottom = _GK.h_display - (y_gkrell + h);
1224 		if (y_bottom < 0)
1225 			{
1226 			if ((y_pack = y_gkrell + y_bottom) < 0)
1227 				y_pack = 0;
1228 			if (_GK.position_valid)
1229 				{
1230 				gdk_window_move(gtree.window->window, _GK.x_position, y_pack);
1231 				gkrellm_debug(DEBUG_POSITION,
1232 					"pack moveto %d %d=y_pack (y_gkrell=%d y_bot=%d)\n",
1233 					_GK.x_position, y_pack, y_gkrell, y_bottom);
1234 				}
1235 			}
1236 		/* If GKrellM bottom edge was <= screen bottom, then move to make
1237 		|  resized GKrellM still on bottom whether window has shrunk or grown.
1238 		*/
1239 		else if (was_on_bottom)
1240 			{
1241 			if ((y_pack = _GK.h_display - h) < 0)
1242 				y_pack = 0;
1243 			if (_GK.position_valid)
1244 				{
1245 				gdk_window_move(gtree.window->window, _GK.x_position, y_pack);
1246 				gkrellm_debug(DEBUG_POSITION,
1247 					"pack moveto %d %d=y_pack (y_gkrell=%d on_bottom)\n",
1248 					_GK.x_position, y_pack, y_gkrell);
1249 				}
1250 			}
1251 		}
1252 	monitor_previous_height = _GK.monitor_height;
1253 	check_rootpixmap_transparency = 3;
1254 	}
1255 
1256 static gint	on_edge[4];		/* left, right, top, bottom */
1257 
1258 static void
edge_record()1259 edge_record()
1260 	{
1261 	gint	x, y, w, h;
1262 
1263 	gdk_window_get_origin(gtree.window->window, &x, &y);
1264 	gdk_drawable_get_size(gtree.window->window, &w, &h);
1265 	on_edge[0] = (x <= 0) ? TRUE : FALSE;
1266 	on_edge[1] = (x + w >= _GK.w_display) ? TRUE : FALSE;
1267 	on_edge[2] = (y <= 0) ? TRUE : FALSE;
1268 	on_edge[3] = (y + h >= _GK.h_display) ? TRUE : FALSE;
1269 	}
1270 
1271 static void
fix_edges()1272 fix_edges()
1273 	{
1274 	gint	x, y, w, h, x0, y0, y_bottom;
1275 
1276 	if (!_GK.position_valid)
1277 		return;
1278 	gdk_window_get_origin(gtree.window->window, &x, &y);
1279 	w = _GK.chart_width + _GK.frame_left_width + _GK.frame_right_width;
1280 	h = _GK.monitor_height + _GK.total_frame_height;
1281 
1282 	x0 = x;
1283 	y0 = y;
1284 	if (x < 0 || on_edge[0])
1285 		x = 0;
1286 	if (x > _GK.w_display - w || on_edge[1])
1287 		x = _GK.w_display - w;
1288 	if (y < 0 || on_edge[2])
1289 		y = 0;
1290 	if (y > _GK.h_display - h || on_edge[3])
1291 		y = _GK.h_display - h;
1292 
1293 	/* Make sure we bias to last user set _GK.y_position
1294 	*/
1295 	y_bottom = _GK.h_display - (_GK.y_position + h);
1296 	if (y_bottom >= 0)
1297 		y = _GK.y_position;
1298 	if (x != x0 || y != y0)
1299 		{
1300 		/* A theme change move adjustment to keep all visible, but treat this
1301 		|  as a packing move so can bias to the last user set _GK.y_position.
1302 		*/
1303 		gdk_window_move(gtree.window->window, x, y);
1304 		if (y != _GK.y_position)
1305 			y_pack = y;
1306 		gkrellm_debug(DEBUG_POSITION,
1307 			"fix_edges: %d %d (y_pos=%d)\n", x, y, _GK.y_position);
1308 		}
1309 	}
1310 
1311   /* Put an image in the spacer and chart top/bottom margin boxes accounting
1312   |  for regions excluded by frame overlaps.
1313   */
1314 gboolean
gkrellm_render_spacer(GkrellmSpacer * spacer,gint y_src,gint h_src,gint l_overlap,gint r_overlap)1315 gkrellm_render_spacer(GkrellmSpacer *spacer, gint y_src, gint h_src,
1316 			gint l_overlap, gint r_overlap)
1317 	{
1318 	GkrellmPiximage	piximage;
1319 	GdkPixbuf		*pixbuf;
1320 	gint			w_pixbuf, h_pixbuf, w_overlap;
1321 
1322 	pixbuf = spacer->piximage->pixbuf;
1323 	w_pixbuf = gdk_pixbuf_get_width(pixbuf);
1324 	h_pixbuf = gdk_pixbuf_get_height(pixbuf);
1325 	w_overlap = l_overlap + r_overlap;
1326 
1327 	if (   spacer->height <= 0
1328 		|| h_src > h_pixbuf || y_src < 0 || w_overlap >= w_pixbuf
1329 	   )
1330 		{
1331 		if (spacer->height > 0)
1332 			g_warning("Bad image size for spacer or bg_chart.\n");
1333 		return FALSE;
1334 		}
1335 	piximage.border = spacer->piximage->border;
1336 	gkrellm_border_adjust(&piximage.border, -l_overlap, -r_overlap,
1337 				-piximage.border.top, -piximage.border.bottom);
1338 
1339 	piximage.pixbuf = gdk_pixbuf_new_subpixbuf(pixbuf, l_overlap, y_src,
1340 				w_pixbuf - w_overlap, (h_src == 0) ? h_pixbuf : h_src);
1341 	gkrellm_scale_piximage_to_pixmap(&piximage, &spacer->clean_pixmap,
1342 				&spacer->mask, _GK.chart_width, spacer->height);
1343 	g_object_unref(G_OBJECT(piximage.pixbuf));
1344 	gkrellm_clone_pixmap(&spacer->pixmap, &spacer->clean_pixmap);
1345 	spacer->image = gtk_image_new_from_pixmap(spacer->pixmap, spacer->mask);
1346 	gtk_container_add(GTK_CONTAINER(spacer->vbox), spacer->image);
1347 	gtk_widget_show_all(spacer->vbox);
1348 	return TRUE;
1349 	}
1350 
1351 static void
render_monitor_spacers(GkrellmMonitor * mon)1352 render_monitor_spacers(GkrellmMonitor *mon)
1353 	{
1354 	GkrellmMonprivate	*mp = mon->privat;
1355 	GkrellmSpacer		*top_spacer, *bottom_spacer;
1356 
1357 	top_spacer = &mp->top_spacer;
1358 	bottom_spacer = &mp->bottom_spacer;
1359 	if (top_spacer->image)
1360 		gtk_widget_destroy(top_spacer->image);
1361 	if (bottom_spacer->image)
1362 		gtk_widget_destroy(bottom_spacer->image);
1363 	top_spacer->image = bottom_spacer->image = NULL;
1364 
1365 	if (top_spacer->piximage)
1366 		{
1367 		if (top_spacer->height < 0)
1368 			top_spacer->height = (mp->style_type == CHART_PANEL_TYPE) ?
1369 					_GK.spacer_top_height_chart : _GK.spacer_top_height_meter;
1370 		gkrellm_render_spacer(top_spacer, 0, 0,
1371 				_GK.frame_left_spacer_overlap, _GK.frame_right_spacer_overlap);
1372 		_GK.monitor_height += top_spacer->height;
1373 		}
1374 	else
1375 		gtk_widget_hide(top_spacer->vbox);
1376 
1377 	if (bottom_spacer->piximage)
1378 		{
1379 		if (bottom_spacer->height < 0)
1380 			bottom_spacer->height = (mp->style_type == CHART_PANEL_TYPE) ?
1381 					_GK.spacer_bottom_height_chart :
1382 					_GK.spacer_bottom_height_meter;
1383 		gkrellm_render_spacer(bottom_spacer, 0, 0,
1384 				_GK.frame_left_spacer_overlap, _GK.frame_right_spacer_overlap);
1385 		_GK.monitor_height += bottom_spacer->height;
1386 		}
1387 	else
1388 		gtk_widget_hide(bottom_spacer->vbox);
1389 	mon->privat->spacers_shown = TRUE;	/* ie, trying to show if they exist */
1390 	}
1391 
1392 void
gkrellm_spacers_set_types(GkrellmMonitor * mon,gint top_type,gint bot_type)1393 gkrellm_spacers_set_types(GkrellmMonitor *mon, gint top_type, gint bot_type)
1394 	{
1395 	GkrellmMonprivate	*mp = (GkrellmMonprivate *) mon->privat;
1396 	GkrellmSpacer		*ts, *bs;
1397 	gboolean			shown;
1398 
1399 	mp->top_type = top_type;
1400 	mp->bottom_type = bot_type;
1401 
1402 	ts = &mp->top_spacer;
1403 	bs = &mp->bottom_spacer;
1404 	shown = mp->spacers_shown;
1405 
1406 	if (ts->piximage)
1407 		{
1408 		if (mp->spacers_shown)
1409 			_GK.monitor_height -= ts->height;
1410 		gkrellm_destroy_piximage(ts->piximage);
1411 		}
1412 	if (bs->piximage)
1413 		{
1414 		if (mp->spacers_shown)
1415 			_GK.monitor_height -= bs->height;
1416 		gkrellm_destroy_piximage(bs->piximage);
1417 		}
1418 	ts->piximage = gkrellm_clone_piximage((top_type == GKRELLM_SPACER_CHART) ?
1419 			_GK.spacer_top_chart_piximage : _GK.spacer_top_meter_piximage);
1420 	gkrellm_set_piximage_border(ts->piximage, &_GK.spacer_top_border);
1421 
1422 	bs->piximage = gkrellm_clone_piximage((bot_type == GKRELLM_SPACER_CHART) ?
1423 				_GK.spacer_bottom_chart_piximage :
1424 				_GK.spacer_bottom_meter_piximage);
1425 	gkrellm_set_piximage_border(bs->piximage, &_GK.spacer_bottom_border);
1426 
1427 	ts->height = (top_type == GKRELLM_SPACER_CHART) ?
1428 				_GK.spacer_top_height_chart : _GK.spacer_top_height_meter;
1429 	bs->height = (bot_type == GKRELLM_SPACER_CHART) ?
1430 				_GK.spacer_bottom_height_chart :
1431 				_GK.spacer_bottom_height_meter;
1432 
1433 	gkrellm_freeze_side_frame_packing();
1434 	render_monitor_spacers(mon);
1435 	if (!shown)
1436 		gkrellm_spacers_hide(mon);
1437 	gkrellm_thaw_side_frame_packing();
1438 	}
1439 
1440   /* Builtin monitors need to control spacer visibility when they are
1441   |  enabled/disabled.  Plugins have this done for them when enabling.
1442   */
1443 void
gkrellm_spacers_show(GkrellmMonitor * mon)1444 gkrellm_spacers_show(GkrellmMonitor *mon)
1445 	{
1446 	GkrellmMonprivate	*mp;
1447 
1448 	if (!mon)
1449 		return;
1450 	mp = mon->privat;
1451 	if (mp->spacers_shown)
1452 		return;
1453 	if (mp->top_spacer.piximage)
1454 		{
1455 		gtk_widget_show(mp->top_spacer.vbox);
1456 		_GK.monitor_height += mp->top_spacer.height;
1457 		}
1458 	if (mp->bottom_spacer.piximage)
1459 		{
1460 		gtk_widget_show(mp->bottom_spacer.vbox);
1461 		_GK.monitor_height += mp->bottom_spacer.height;
1462 		}
1463 	mp->spacers_shown = TRUE;
1464 	gkrellm_pack_side_frames();
1465 	if (mon == gkrellm_mon_host())
1466 		gtk_widget_show(gtree.top1_event_box);
1467 	}
1468 
1469 void
gkrellm_spacers_hide(GkrellmMonitor * mon)1470 gkrellm_spacers_hide(GkrellmMonitor *mon)
1471 	{
1472 	GkrellmMonprivate	*mp;
1473 
1474 	if (!mon)
1475 		return;
1476 	mp = mon->privat;
1477 	if (!mp->spacers_shown)
1478 		return;
1479 	if (mp->top_spacer.piximage)
1480 		{
1481 		gtk_widget_hide(mp->top_spacer.vbox);
1482 		_GK.monitor_height -= mp->top_spacer.height;
1483 		}
1484 	if (mp->bottom_spacer.piximage)
1485 		{
1486 		gtk_widget_hide(mp->bottom_spacer.vbox);
1487 		_GK.monitor_height -= mp->bottom_spacer.height;
1488 		}
1489 	mp->spacers_shown = FALSE;
1490 	gkrellm_pack_side_frames();
1491 	if (mon == gkrellm_mon_host())
1492 		gtk_widget_hide(gtree.top1_event_box);
1493 	}
1494 
1495 static void
create_widget_tree()1496 create_widget_tree()
1497 	{
1498 	gchar		*title;
1499 #if GTK_CHECK_VERSION(2,4,0) && !defined(WIN32)
1500 	GdkPixbuf	*icon;
1501 #endif
1502 
1503 	gtree.window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
1504 	gtk_widget_set_name(gtree.window, PACKAGE);
1505 
1506 #if GTK_CHECK_VERSION(2,4,0) && !defined(WIN32)
1507 	icon = gdk_pixbuf_new_from_xpm_data((const gchar **) icon_xpm);
1508 	gtk_window_set_default_icon(icon);
1509 #endif
1510 
1511 	title = gkrellm_make_config_file_name(NULL, PACKAGE);
1512 	gtk_window_set_title(GTK_WINDOW(gtree.window), title);
1513 //	gtk_window_set_wmclass(GTK_WINDOW(gtree.window), title, "Gkrellm");
1514 	g_free(title);
1515 
1516 	gtree.vbox = gtk_vbox_new(FALSE, 0);
1517 	gtk_container_add(GTK_CONTAINER(gtree.window), gtree.vbox);
1518 
1519 	gtree.top0_event_box = gtk_event_box_new();
1520 	gtk_container_add(GTK_CONTAINER(gtree.vbox), gtree.top0_event_box);
1521 	gtree.top0_vbox = gtk_vbox_new(FALSE, 0);
1522 	gtk_container_add(GTK_CONTAINER(gtree.top0_event_box), gtree.top0_vbox);
1523 
1524 	/* The middle hbox has left frame, monitors & a right frame.
1525 	*/
1526 	gtree.middle_hbox = gtk_hbox_new(FALSE, 0);
1527 	gtk_container_add(GTK_CONTAINER(gtree.vbox), gtree.middle_hbox);
1528 
1529 	gtree.left_event_box = gtk_event_box_new();
1530 	gtk_container_add(GTK_CONTAINER(gtree.middle_hbox), gtree.left_event_box);
1531 	gtree.left_vbox = gtk_vbox_new(FALSE, 0);
1532 	gtk_container_add(GTK_CONTAINER(gtree.left_event_box), gtree.left_vbox);
1533 
1534 	gtree.middle_vbox = gtk_vbox_new(FALSE, 0);
1535 	gtk_container_add(GTK_CONTAINER(gtree.middle_hbox), gtree.middle_vbox);
1536 
1537 	/* Hostname will go in an event box for moving gkrellm */
1538 	gtree.top1_event_box = gtk_event_box_new();
1539 	gtk_container_add(GTK_CONTAINER(gtree.middle_vbox), gtree.top1_event_box);
1540 	gtree.top1_vbox = gtk_vbox_new(FALSE, 0);
1541 	gtk_container_add(GTK_CONTAINER(gtree.top1_event_box), gtree.top1_vbox);
1542 
1543 	gtree.monitor_vbox = gtk_vbox_new(FALSE, 0);
1544 	gtk_container_add(GTK_CONTAINER(gtree.middle_vbox), gtree.monitor_vbox);
1545 
1546 	gtree.right_event_box = gtk_event_box_new();
1547 	gtk_container_add(GTK_CONTAINER(gtree.middle_hbox), gtree.right_event_box);
1548 	gtree.right_vbox = gtk_vbox_new(FALSE, 0);
1549 	gtk_container_add(GTK_CONTAINER(gtree.right_event_box), gtree.right_vbox);
1550 
1551 	gtree.bottom_vbox = gtk_vbox_new(FALSE, 0);
1552 	gtk_container_add(GTK_CONTAINER(gtree.vbox), gtree.bottom_vbox);
1553 
1554 	gtk_widget_realize(gtree.window);
1555 
1556 	/* Set the toplevel window size handling to be under program control.
1557 	*/
1558 	gtk_window_set_resizable((GtkWindow *) gtree.window, FALSE);
1559 
1560 	if (!decorated)
1561 		gtk_window_set_decorated((GtkWindow *) gtree.window, FALSE);
1562 
1563 	gtk_widget_show_all(gtree.vbox);
1564 
1565 	/* Probably don't need to realize all these here. Just a little paranoia.
1566 	*/
1567 	gtk_widget_realize(gtree.vbox);
1568 	gtk_widget_realize(gtree.top0_vbox);
1569 	gtk_widget_realize(gtree.middle_hbox);
1570 	gtk_widget_realize(gtree.left_vbox);
1571 	gtk_widget_realize(gtree.middle_vbox);
1572 	gtk_widget_realize(gtree.monitor_vbox);
1573 	gtk_widget_realize(gtree.top1_vbox);
1574 	gtk_widget_realize(gtree.right_vbox);
1575 	gtk_widget_realize(gtree.bottom_vbox);
1576 	}
1577 
1578 
1579 static gint
cb_client_event(GtkWidget * widget,GdkEventClient * event,gpointer data)1580 cb_client_event(GtkWidget  *widget, GdkEventClient *event, gpointer data)
1581 	{
1582 	static GdkAtom	atom_gkrellm_read_theme = GDK_NONE;
1583 
1584 	if (!atom_gkrellm_read_theme)
1585 		atom_gkrellm_read_theme = gdk_atom_intern("_GKRELLM_READ_THEME",FALSE);
1586 
1587 	if (event->message_type == atom_gkrellm_read_theme)
1588 		gkrellm_read_theme_event(NULL);
1589 	return FALSE;
1590 	}
1591 
1592   /* Callback called when configure_event is received.  This can
1593   |  be for window raise, lower, resize, move & maybe others
1594   */
1595 static gint
cb_size_allocate(GtkWidget * w,GtkAllocation * size,gpointer data)1596 cb_size_allocate(GtkWidget *w, GtkAllocation *size, gpointer data)
1597 	{
1598 //	g_message("x = %d, y = %d, width = %d, height = %d, data = %p\n",
1599 //			size->x,size->y,size->width,size->height,data);
1600 	return FALSE;
1601 	}
1602 
1603 static gboolean
cb_map_event(GtkWidget * widget,GdkEvent * event,gpointer data)1604 cb_map_event(GtkWidget *widget, GdkEvent *event, gpointer data)
1605 	{
1606 	/* Some window managers don't recognize when _NET_WM_STATE property is set
1607 	|  prior to window mapping.  As a temporary hack send extra _NET_WM_STATE
1608 	|  changed messages in an attempt to get these window managers to work.
1609 	*/
1610 	if (_GK.sticky_state)
1611 		gtk_window_stick(GTK_WINDOW(top_window));
1612 	if (_GK.state_skip_pager)
1613 		gkrellm_winop_state_skip_pager(TRUE);
1614 	if (_GK.state_skip_taskbar)
1615 		gkrellm_winop_state_skip_taskbar(TRUE);
1616 	if (_GK.state_above)
1617 		gkrellm_winop_state_above(TRUE);
1618 	else if (_GK.state_below)
1619 		gkrellm_winop_state_below(TRUE);
1620 
1621 	return FALSE;
1622 	}
1623 
1624 static gboolean
cb_configure_notify(GtkWidget * widget,GdkEventConfigure * ev,gpointer data)1625 cb_configure_notify(GtkWidget *widget, GdkEventConfigure *ev, gpointer data)
1626 	{
1627 	gboolean	size_change, position_change;
1628 	gint        x, y, w, h, w_gkrellm, h_gkrellm;
1629 	static gint	x_prev, y_prev, w_prev, h_prev;
1630 
1631 	_GK.w_display = gdk_screen_get_width(gdk_screen_get_default());
1632 	_GK.h_display = gdk_screen_get_height(gdk_screen_get_default());
1633 
1634 #if !defined(WIN32)
1635 	gdk_window_get_position(widget->window, &x, &y);
1636 #else
1637 	/* Windows Gtk bug? */
1638 	x = ev->x;
1639 	y = ev->y;
1640 #endif
1641 
1642 	gdk_drawable_get_size(gtree.window->window, &w, &h);
1643 
1644 	w_gkrellm = _GK.chart_width + _GK.frame_left_width + _GK.frame_right_width;
1645 	h_gkrellm = _GK.monitor_height + _GK.total_frame_height;
1646 
1647 	/* If window manager decorated, I can't allow a user to resize GKrellM
1648 	|  via the window manager.  So, try to turn it into a no-op.
1649 	*/
1650 	if (   decorated && monitors_visible
1651 		&& (w_gkrellm != w || h_gkrellm != h)
1652 	   )
1653 		{
1654 		gdk_window_resize(top_window->window, w_gkrellm, h_gkrellm);
1655 		w = w_gkrellm;
1656 		h = h_gkrellm;
1657 		}
1658 	size_change = (w != w_prev) | (h != h_prev);
1659 	position_change = (x != x_prev) | (y != y_prev);
1660 
1661 	if (size_change)
1662 		apply_frame_transparency(FALSE);
1663 
1664 	/* This is abit of a hose... I have to defer applying the root pixmap
1665 	|  because windows just appearing by gtk_widget_show() are not in the
1666 	|  right place yet even though configure notify is sent.
1667 	*/
1668 	if ((size_change || position_change) && !moving_gkrellm)
1669 		check_rootpixmap_transparency = 3;
1670 	x_prev = x;
1671 	y_prev = y;
1672 	w_prev = w;
1673 	h_prev = h;
1674 
1675 	/* At startup can be a race for configure events to be reporting correct
1676 	|  move to position and pack_side_frames() first call.  Initial configure
1677 	|  events will be intermediate x,y values as initial mapping happens, so
1678 	|  using configure event position values is delayed.
1679 	*/
1680 	if (!configure_position_lock)
1681 		{
1682 		if (x >= 0 && x < _GK.w_display - 10)
1683 			_GK.x_position = x;
1684 		if (y >= 0 && y < _GK.h_display - 5 && y != y_pack)
1685 			_GK.y_position = y;
1686 		_GK.position_valid = TRUE;
1687 		if (!moving_gkrellm)
1688 			gkrellm_debug(DEBUG_POSITION,
1689 				"configure-event: x_pos=%d y_pos=%d x=%d y=%d y_pack=%d\n",
1690 				_GK.x_position, _GK.y_position, x, y, y_pack);
1691 		}
1692 	else
1693 		{
1694 		gkrellm_debug(DEBUG_POSITION,
1695 			"locked configure-event: x=%d y=%d\n", x, y);
1696 		}
1697 
1698 	if (size_change || position_change)
1699 		gkrellm_winop_update_struts();
1700 
1701 	if (do_intro)
1702 		{
1703 		do_intro = FALSE;
1704 		gkrellm_message_dialog(_("GKrellM Introduction"), _(intro_msg));
1705 		}
1706 
1707 	/* If GKrellM is killed (signal, shutdown, etc) it might not get
1708 	|  a chance to save its position.  So write the position file
1709 	|  10 seconds after window moves stop.
1710 	*/
1711 	if (_GK.save_position)
1712 		save_position_countdown = 10 * _GK.update_HZ;
1713 	return FALSE;
1714 	}
1715 
1716 void
gkrellm_save_all()1717 gkrellm_save_all()
1718 	{
1719 	gkrellm_net_save_data();
1720 	gkrellm_inet_save_data();
1721 	if (_GK.save_position)
1722 		set_or_save_position(1);
1723 	if (_GK.config_modified)
1724 		gkrellm_save_user_config();
1725 	gkrellm_save_theme_config();
1726 	}
1727 
1728 static void
check_gkrellm_directories(void)1729 check_gkrellm_directories(void)
1730 	{
1731 	gchar	*t, *u;
1732 
1733 	if (gkrellm_make_home_subdir(GKRELLM_DIR, NULL))
1734 		do_intro = TRUE;	/* Defer it until main window realizes */
1735 
1736 	gkrellm_make_home_subdir(GKRELLM_PLUGINS_DIR, NULL);
1737 	gkrellm_make_home_subdir(GKRELLM_THEMES_DIR, NULL);
1738 	gkrellm_make_home_subdir(GKRELLM_DATA_DIR, NULL);
1739 
1740 	/* If no user_config specified, force a check for host-specific config
1741 	*/
1742 	if (!_GK.config_suffix)
1743 		{
1744 		_GK.found_host_config = TRUE;
1745 		t = gkrellm_make_config_file_name(gkrellm_homedir(),
1746 							GKRELLM_THEME_CONFIG);
1747 		u = gkrellm_make_config_file_name(gkrellm_homedir(),
1748 							GKRELLM_USER_CONFIG);
1749 		if (!g_file_test(u, G_FILE_TEST_IS_REGULAR))
1750 			{
1751 			g_free(u);
1752 			u = gkrellm_make_config_file_name(gkrellm_homedir(),
1753 							GKRELLM_2_1_14_CONFIG);
1754 			}
1755 		if (   !g_file_test(u, G_FILE_TEST_IS_REGULAR)
1756 			&& !g_file_test(t, G_FILE_TEST_IS_REGULAR)
1757 		   )
1758 			_GK.found_host_config = FALSE;
1759 		g_free(t);
1760 		g_free(u);
1761 		}
1762 	}
1763 
1764 
1765 static gint
cb_delete_event(GtkWidget * widget,GdkEvent * event,gpointer data)1766 cb_delete_event(GtkWidget *widget, GdkEvent *event, gpointer data)
1767 	{
1768 	/* Return FALSE to get GTK to emit the "destroy" signal.
1769 	|  Return TRUE to not destroy the window (for verify dialog pop up).
1770 	*/
1771 	return(FALSE);
1772 	}
1773 
1774 static void
cb_destroy_event()1775 cb_destroy_event()
1776 	{
1777 	gtk_main_quit();
1778 	}
1779 
1780 static gchar	*usage_string[] =
1781 {
1782 N_("usage: gkrellm [options]\n"
1783    "options:\n"),
1784 N_("   -t, --theme theme_dir    Select a theme directory.\n"),
1785 N_("   -g, --geometry +x+y      Position the window on the screen.\n"),
1786 N_("       --wm                 Allow window manager decorations.\n"),
1787 N_("       --m2                 Left button side frame shading (for 2 btn mice).\n"),
1788 N_("       --nt                 No transparency.\n"),
1789 N_("   -w, --withdrawn          Draw GKrellM in withdrawn mode.\n"),
1790 N_("   -c, --config suffix      Use alternate config files generated by\n"
1791    "                            appending \"suffix\" to config file names.\n"),
1792 N_("   -f, --force-host-config  Creates config files generated by appending the\n"
1793    "                            hostname to config file names.  Subsequent runs\n"
1794    "                            automatically will use these configs unless a\n"
1795    "                            specific config is specified with --config.\n"
1796    "                            This is a convenience for allowing remote runs\n"
1797    "                            with independent configs in a shared home dir\n"
1798    "                            and for the hostname to be in the window title.\n"
1799    "                            This option has no effect in client mode.\n"),
1800 N_("   -s, --server hostname    Run in client mode: connect to \"hostname\" and\n"
1801    "                            read monitor data from a gkrellmd server.\n"),
1802 N_("   -P, --port server_port   Use \"server_port\" for the server connection.\n"),
1803 N_("       --nc                 No config mode prevents configuration changes.\n"),
1804 N_("       --config-clean       Clean out unused configs on config write.\n"),
1805 N_("       --nolock             Allow multiple gkrellm instances.\n"),
1806 N_("   -p, --plugin plugin.so   While developing, load your plugin under test.\n"),
1807 N_("       --demo               Force enabling of many monitors so themers can\n"
1808    "                            see everything. All config saving is inhibited.\n"),
1809    "   -l, --logfile path       Enable error/debugging to a log file.\n",
1810 N_("   -v, --version            Print GKrellM version number and exit.\n"),
1811 N_("   -d, --debug-level n      Turn debugging on for selective code sections.\n"),
1812 
1813 N_("\ndebug-level numbers are (bitwise OR to debug multiple sections):\n"
1814 "     0x10    mail\n"
1815 "     0x20    net\n"
1816 "     0x40    timer button\n"
1817 "     0x80    sensors\n"
1818 "     0x800   inet\n"
1819 "     0x1000  dump gkrellmd server data\n"
1820 "     0x2000  GUI\n"
1821 "     0x8000  battery\n"
1822 "     0x20000 plugin \n"
1823 "\n")
1824 };
1825 
1826 static void
usage()1827 usage()
1828 	{
1829 #ifdef WIN32
1830 	GtkWidget *dialog, *content_area, *scrolled, *text_view;
1831 
1832 	dialog = gtk_dialog_new_with_buttons(_("GKrellM"), NULL, GTK_DIALOG_MODAL,
1833 		GTK_STOCK_OK, GTK_RESPONSE_OK, NULL);
1834 	content_area = gtk_dialog_get_content_area(GTK_DIALOG(dialog));
1835 
1836 	scrolled = gtk_scrolled_window_new(NULL, NULL);
1837 	gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled),
1838 			GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
1839 	gtk_widget_set_size_request(scrolled, 400, 300);
1840 	gtk_container_add(GTK_CONTAINER(content_area), scrolled);
1841 
1842 	text_view = gtk_text_view_new();
1843 	gtk_text_view_set_editable(GTK_TEXT_VIEW(text_view), FALSE);
1844 	gtk_text_view_set_cursor_visible(GTK_TEXT_VIEW(text_view), FALSE);
1845 	gtk_container_add(GTK_CONTAINER(scrolled), text_view);
1846 
1847 	gkrellm_gtk_text_view_append_strings(text_view, usage_string,
1848 		sizeof(usage_string) / sizeof(gchar *));
1849 
1850 	gtk_widget_show_all(dialog);
1851 	gtk_dialog_run(GTK_DIALOG(dialog));
1852 	gtk_widget_destroy(dialog);
1853 #else
1854 	gint	i;
1855 
1856 	for (i = 0; i < (sizeof(usage_string) / sizeof(gchar *)); ++i)
1857 		g_print("%s", _(usage_string[i]));
1858 #endif
1859 	}
1860 
1861 
1862 GtkWidget *
gkrellm_monitor_vbox(void)1863 gkrellm_monitor_vbox(void)
1864 	{
1865 	return gtree.monitor_vbox;
1866 	}
1867 
1868 void
gkrellm_build()1869 gkrellm_build()
1870 	{
1871 	GkrellmMonitor		*mon;
1872 	GList		*list;
1873 	static gint	first_create	= TRUE;
1874 
1875 	_GK.initialized = FALSE;
1876 	monitor_previous_height = 0;
1877 	_GK.total_frame_height = 0;
1878 	_GK.any_transparency = FALSE;
1879 	gkrellm_winop_reset();
1880 	gkrellm_start_timer(0);
1881 
1882 	if (!first_create)
1883 		edge_record();
1884 	gkrellm_alert_reset_all();
1885 	gkrellm_panel_cleanup();
1886 
1887 	gkrellm_theme_config();
1888 	if (first_create)
1889 		gkrellm_load_user_config(NULL, TRUE);
1890 	setup_colors();
1891 	setup_fonts();
1892 	gkrellm_load_theme_piximages();
1893 	gkrellm_chart_setup();
1894 	gkrellm_freeze_side_frame_packing();
1895 
1896 	create_frame_top(gtree.top0_vbox);
1897 
1898 	_GK.monitor_height = 0;
1899 	for (list = gkrellm_monitor_list; list; list = list->next)
1900 		{
1901 		mon = (GkrellmMonitor *) list->data;
1902 		if (mon->privat->main_vbox)
1903 			{
1904 			if (first_create)
1905 				{
1906 				if (mon == gkrellm_mon_host())
1907 					gtk_box_pack_start(GTK_BOX(gtree.top1_vbox),
1908 								mon->privat->main_vbox, FALSE, FALSE, 0);
1909 				else
1910 					gtk_box_pack_start(GTK_BOX(gtree.monitor_vbox),
1911 								mon->privat->main_vbox, FALSE, FALSE, 0);
1912 				gtk_box_pack_start(GTK_BOX(mon->privat->main_vbox),
1913 							mon->privat->top_spacer.vbox, FALSE, FALSE, 0);
1914 				gtk_box_pack_start(GTK_BOX(mon->privat->main_vbox),
1915 							mon->privat->vbox, FALSE, FALSE, 0);
1916 				gtk_box_pack_start(GTK_BOX(mon->privat->main_vbox),
1917 							mon->privat->bottom_spacer.vbox, FALSE, FALSE, 0);
1918 				}
1919 			if (mon->create_monitor && mon->privat->enabled)
1920 				{
1921 				gkrellm_record_state(CREATE_MONITOR, mon);
1922 				gtk_widget_show(mon->privat->vbox);
1923 				gtk_widget_show(mon->privat->main_vbox);
1924 				render_monitor_spacers(mon);
1925 				(*(mon->create_monitor))(mon->privat->vbox,
1926 							mon->privat->created ? FALSE : TRUE);
1927 				mon->privat->created = TRUE;
1928 				}
1929 			gkrellm_record_state(INTERNAL, NULL);
1930 			}
1931 		}
1932 	create_frame_bottom(gtree.bottom_vbox);
1933 
1934 	_GK.initialized = TRUE;
1935 	gkrellm_thaw_side_frame_packing();
1936 	gkrellm_start_timer(_GK.update_HZ);
1937 	if (!first_create)
1938 		{
1939 		fix_edges();
1940 		if (!no_transparency)
1941 			gkrellm_winop_apply_rootpixmap_transparency();
1942 		}
1943 	first_create = FALSE;
1944 	}
1945 
1946 static void
add_builtin(GkrellmMonitor * mon)1947 add_builtin(GkrellmMonitor *mon)
1948 	{
1949 	if (!mon)
1950 		return;
1951 	gkrellm_monitor_list = g_list_append(gkrellm_monitor_list, mon);
1952 	if (!mon->privat)				/* Won't be null if style was added */
1953 		mon->privat = g_new0(GkrellmMonprivate, 1);
1954 	if (mon->create_monitor)
1955 		{
1956 		mon->privat->main_vbox = gtk_vbox_new(FALSE, 0);
1957 		mon->privat->top_spacer.vbox = gtk_vbox_new(FALSE, 0);
1958 		mon->privat->vbox = gtk_vbox_new(FALSE, 0);
1959 		mon->privat->bottom_spacer.vbox = gtk_vbox_new(FALSE, 0);
1960 		}
1961 	mon->privat->enabled = TRUE;
1962 	}
1963 
1964 static void
load_builtin_monitors()1965 load_builtin_monitors()
1966 	{
1967 	gkrellm_add_chart_style(NULL, "*");
1968 	gkrellm_add_meter_style(NULL, "*");
1969 
1970 	/* The sensors config does not have a create or update, but it does
1971 	|  have an apply which needs to be called before the cpu or proc apply.
1972 	|  So just put sensors config first.
1973 	*/
1974 	add_builtin(gkrellm_init_sensors_config_monitor());
1975 	add_builtin(gkrellm_init_host_monitor());
1976 	add_builtin(gkrellm_init_cal_monitor());
1977 	add_builtin(gkrellm_init_clock_monitor());
1978 	add_builtin(gkrellm_init_cpu_monitor());
1979 	add_builtin(gkrellm_init_proc_monitor());
1980 	add_builtin(gkrellm_init_sensor_monitor());
1981 	add_builtin(gkrellm_init_disk_monitor());
1982 	add_builtin(gkrellm_init_inet_monitor());
1983 	add_builtin(gkrellm_init_net_monitor());
1984 	add_builtin(gkrellm_init_timer_monitor());
1985 	add_builtin(gkrellm_init_mem_monitor());
1986 	add_builtin(gkrellm_init_swap_monitor());
1987 	add_builtin(gkrellm_init_fs_monitor());
1988 	add_builtin(gkrellm_init_mail_monitor());
1989 	add_builtin(gkrellm_init_battery_monitor());
1990 	add_builtin(gkrellm_init_uptime_monitor());
1991 	}
1992 
1993 static void
gkrellm_exit(gint exit_code)1994 gkrellm_exit(gint exit_code)
1995 	{
1996 	gkrellm_sys_main_cleanup();
1997 	gkrellm_log_cleanup();
1998 	exit(exit_code);
1999 	}
2000 
2001 static void
_signal_quit(gint sig)2002 _signal_quit(gint sig)
2003 	{
2004 	gkrellm_save_all();
2005 	gkrellm_exit(1);
2006 	}
2007 
2008 void
gkrellm_record_state(enum GkrellmState state,GkrellmMonitor * mon)2009 gkrellm_record_state(enum GkrellmState state, GkrellmMonitor *mon)
2010 	{
2011 	_GK.gkrellm_state = state;
2012 	_GK.active_monitor = mon;
2013 	}
2014 
2015 static void
gkrellm_abort(gint sig)2016 gkrellm_abort(gint sig)
2017 	{
2018 	gchar			*fault,
2019 					*state,
2020 					buf[512];
2021 	gboolean		do_xmessage = TRUE;
2022 	GkrellmMonitor	*mon 	= _GK.active_monitor;
2023 
2024 	if (sig == SIGSEGV)
2025 		fault = _("segmentation fault");
2026 	else if (sig == SIGFPE)
2027 		fault = _("floating point exception");
2028 	else
2029 		fault = _("aborted");
2030 
2031 	if (_GK.gkrellm_state == INITIALIZING)
2032 		state = _("initializing");
2033 	else if (_GK.gkrellm_state == INIT_MONITOR)
2034 		state = "init_monitor";
2035 	else if (_GK.gkrellm_state == CREATE_MONITOR)
2036 		state = "create_monitor";
2037 	else if (_GK.gkrellm_state == UPDATE_MONITOR)
2038 		state = "update_monitor";
2039 	else if (_GK.gkrellm_state == CREATE_CONFIG)
2040 		state = "create_config";
2041 	else if (_GK.gkrellm_state == LOAD_CONFIG)
2042 		state = "load_user_config";
2043 	else if (_GK.gkrellm_state == SAVE_CONFIG)
2044 		state = "save_user_config";
2045 	else if (_GK.gkrellm_state == APPLY_CONFIG)
2046 		state = "apply_config";
2047 	else
2048 		{
2049 		state = "?";
2050 		do_xmessage = FALSE;
2051 		}
2052 
2053 	// FIXME: xmessage is only available on X11
2054 	snprintf(buf, sizeof(buf), "xmessage gkrellm %s:  %s  (%s)", fault,
2055 				(mon && mon->name) ? mon->name : "", state);
2056 	g_warning("%s\n", buf + 9);
2057 	if (do_xmessage)
2058 		g_spawn_command_line_async(buf, NULL);
2059 
2060 	signal(SIGABRT, SIG_DFL);
2061 	abort();
2062 	}
2063 
2064 static void
setup_signal_handler(void)2065 setup_signal_handler(void)
2066 	{
2067 #ifndef WIN32
2068 	signal(SIGPIPE, SIG_IGN);
2069 	signal(SIGQUIT, _signal_quit);
2070 #endif
2071 	signal(SIGINT, _signal_quit);
2072 	signal(SIGTERM, _signal_quit);
2073 	}
2074 
2075 void
gkrellm_sys_setup_connect(void (* setup_func)())2076 gkrellm_sys_setup_connect(void (*setup_func)())
2077 	{
2078 	_GK.sys_setup_func = setup_func;
2079 	}
2080 
2081 gint
main(gint argc,gchar ** argv)2082 main(gint argc, gchar **argv)
2083 	{
2084 	gint						i;
2085 	gchar						*s;
2086 	enum GkrellmConnectResult	connect_result;
2087 	GtkWidget					*dlg;
2088 
2089 	gkrellm_sys_main_init();
2090 
2091 #ifdef ENABLE_NLS
2092 	gtk_set_locale();
2093 #endif
2094 	gtk_init(&argc, &argv);		/* Will call gdk_init() */
2095 	gkrellm_log_init();
2096 	gtk_widget_push_colormap(gdk_rgb_get_colormap());
2097 
2098 #ifdef ENABLE_NLS
2099 #ifdef LOCALEDIR
2100 #if defined(WIN32)
2101 	gchar *install_path;
2102 	gchar *locale_dir;
2103 	// Prepend app install path to locale dir
2104 	install_path = g_win32_get_package_installation_directory_of_module(NULL);
2105 	if (install_path != NULL)
2106 		{
2107 	    locale_dir = g_build_filename(install_path, LOCALEDIR, NULL);
2108 		if (locale_dir != NULL)
2109 			{
2110 			bindtextdomain(PACKAGE, locale_dir);
2111 			g_free(locale_dir);
2112 			}
2113 	    g_free(install_path);
2114 		}
2115 #else
2116 	bindtextdomain(PACKAGE, LOCALEDIR);
2117 #endif /* !WIN32 */
2118 #endif /* LOCALEDIR */
2119 	textdomain(PACKAGE);
2120 	bind_textdomain_codeset(PACKAGE, "UTF-8");
2121 #endif	/* ENABLE_NLS */
2122 
2123 	_GK.start_time = time(0);
2124 	gkrellm_current_tm = *(localtime(&_GK.start_time));
2125 
2126 	_GK.initialized = FALSE;
2127 	gkrellm_record_state(INITIALIZING, NULL);
2128 	signal(SIGFPE, gkrellm_abort);
2129 	signal(SIGSEGV, gkrellm_abort);
2130 	signal(SIGABRT, gkrellm_abort);
2131 
2132 	for (i = 1; i < argc; ++i)
2133 		{
2134 		s = argv[i];
2135 		if (*s == '-')
2136 			{
2137 			++s;
2138 			if (*s == '-')
2139 				++s;
2140 			}
2141 		if ((!strcmp(s, "t") || !strcmp(s, "theme")) && i < argc - 1)
2142 			{
2143 			_GK.theme_path = g_strdup(argv[++i]);
2144 			_GK.command_line_theme = g_strdup(_GK.theme_path);
2145 			}
2146 		else if (!strcmp(s, "sm-client-id") && i < argc - 1)
2147 			_GK.session_id = g_strdup(argv[++i]);
2148 		else if ((!strcmp(s, "s") || !strcmp(s, "server")) && i < argc - 1)
2149 			{
2150 			_GK.server = g_strdup(argv[++i]);
2151 			_GK.client_mode = TRUE;
2152 			}
2153 		else if ((!strcmp(s, "P") || !strcmp(s, "port")) && i < argc-1)
2154 			_GK.server_port = (gint) strtoul(argv[++i], NULL, 0);
2155 		else if ((!strcmp(s, "p") || !strcmp(s, "plugin")) && i < argc - 1)
2156 			_GK.command_line_plugin = g_strdup(argv[++i]);
2157 		else if ((!strcmp(s, "config") || !strcmp(s, "c")) && i < argc - 1)
2158 			_GK.config_suffix = g_strdup(argv[++i]);
2159 		else if ((!strcmp(s, "geometry") || !strcmp(s, "g")) && i < argc - 1)
2160 			geometry = argv[++i];
2161 		else if (!strcmp(s, "wm"))
2162 			_GK.command_line_decorated = TRUE;
2163 		else if (!strcmp(s, "m2"))
2164 			_GK.m2 = TRUE;
2165 		else if ( (! strcmp(s, "withdrawn")) || (! strcmp(s, "w")))
2166 			_GK.withdrawn = TRUE;
2167 		else if (!strcmp(s, "force-host-config") || !strcmp(s, "f"))
2168 			{
2169 			_GK.force_host_config = TRUE;
2170 			gkrellm_config_modified();
2171 			}
2172 		else if (!strcmp(s, "nt"))
2173 			no_transparency = TRUE;
2174 		else if (!strcmp(s, "nc"))
2175 			_GK.no_config = TRUE;
2176 		else if ((!strcmp(s, "debug-level") || !strcmp(s, "d")) && i < argc-1)
2177 			_GK.debug_level = (gint) strtoul(argv[++i], NULL, 0);
2178 		else if ((!strcmp(s, "logfile") || !strcmp(s, "l")) && i < argc-1)
2179 			gkrellm_log_set_filename(argv[++i]);
2180 		else if (!strncmp(s, "debug", 5))
2181 			{
2182 			if (s[5] != '\0')
2183 				_GK.debug = atoi(s + 5);
2184 			else
2185 				_GK.debug = 1;
2186 			}
2187 		else if (!strcmp(s, "nolock"))
2188 			_GK.nolock = TRUE;
2189 		else if (!strcmp(s, "without-libsensors"))		/* temporary */
2190 			_GK.without_libsensors = TRUE;
2191 		else if (!strcmp(s, "use-acpi-battery"))		/* temporary */
2192 			_GK.use_acpi_battery = TRUE;
2193 		else if (!strcmp(s, "config-clean"))
2194 			{
2195 			_GK.config_clean = TRUE;
2196 			_GK.config_modified = TRUE;
2197 			}
2198 		else if (!strcmp(s, "demo"))
2199 			++_GK.demo;
2200 		else if (!strcmp(s, "test"))
2201 			_GK.test += 1;
2202 		else if (!strcmp(s, "version") || !strcmp(s, "v"))
2203 			{
2204 			g_print("%s %d.%d.%d%s\n", PACKAGE, GKRELLM_VERSION_MAJOR,
2205 					GKRELLM_VERSION_MINOR, GKRELLM_VERSION_REV,
2206 					GKRELLM_EXTRAVERSION);
2207 			exit(0);
2208 			}
2209 		else if (strcmp(s, "help") == 0 || strcmp(s, "h") == 0)
2210 			{
2211 			usage();
2212 			exit(0);
2213 			}
2214 		else
2215 			{
2216 			g_print(_("Bad arg: %s\n"), argv[i]);
2217 			usage();
2218 			exit(0);
2219 			}
2220 		}
2221 
2222 	if (_GK.debug_level > 0)
2223 		g_debug("--- GKrellM %d.%d.%d ---\n", GKRELLM_VERSION_MAJOR,
2224 			GKRELLM_VERSION_MINOR, GKRELLM_VERSION_REV);
2225 
2226 	if (_GK.sys_setup_func)
2227 		(*_GK.sys_setup_func)(argc, argv);
2228 
2229 	_GK.w_display = gdk_screen_get_width(gdk_screen_get_default());
2230 	_GK.h_display = gdk_screen_get_height(gdk_screen_get_default());
2231 
2232 	if (_GK.server)
2233 		{
2234 		connect_result = gkrellm_client_mode_connect();
2235 		while (connect_result == BAD_CONNECT)
2236 			{
2237 			gint	result;
2238 
2239 			dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2240 					GTK_MESSAGE_ERROR, GTK_BUTTONS_YES_NO,
2241 					"GKrellM cannot connect to server:\n"
2242 					"\t%s:%d\n\n"
2243 					"Do you want to retry?",
2244 					_GK.server, _GK.server_port);
2245 			result = gtk_dialog_run(GTK_DIALOG(dlg));
2246 			gtk_widget_destroy(dlg);
2247 			if (result == GTK_RESPONSE_YES)
2248 				connect_result = gkrellm_client_mode_connect();
2249 			else
2250 				break;
2251 			}
2252 		if (connect_result == BAD_SETUP)
2253 			{
2254 			dlg = gtk_message_dialog_new(NULL, GTK_DIALOG_MODAL,
2255 					GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE,
2256 					"GKrellM cannot get initial setup from server:\n"
2257 					"\t\t%s:%d\n",
2258 					_GK.server, _GK.server_port);
2259 			gtk_dialog_run(GTK_DIALOG(dlg));
2260 			gtk_widget_destroy(dlg);
2261 			}
2262 		if (connect_result != GOOD_CONNECT)
2263 			{
2264 			gkrellm_exit(0);
2265 			return 0;
2266 			}
2267 		}
2268 
2269 	check_gkrellm_directories();
2270 	gkrellm_load_user_config(NULL, FALSE);
2271 	decorated = (_GK.command_line_decorated || _GK.decorated);
2272 	if (   _GK.command_line_plugin || _GK.command_line_theme
2273 		|| _GK.debug_level > 0 || _GK.debug > 0 || _GK.nolock
2274 	   )
2275 		_GK.allow_multiple_instances_real = TRUE;
2276 	_GK.allow_multiple_instances_real |= _GK.allow_multiple_instances;
2277 
2278 	create_widget_tree();
2279 	top_window = gtree.window;
2280 
2281 	load_builtin_monitors();
2282 	gkrellm_plugins_load();
2283 
2284 	gkrellm_build();
2285 	gkrellm_make_themes_list();
2286 
2287 	if ((_GK.gtk_settings = gtk_settings_get_default()) != NULL)
2288 		{
2289 		g_object_get(_GK.gtk_settings,
2290 					"gtk-theme-name", &_GK.gtk_theme_name, NULL);
2291 		g_signal_connect(_GK.gtk_settings, "notify::gtk-theme-name",
2292 					G_CALLBACK(gkrellm_read_theme_event), NULL);
2293 		}
2294 
2295 	g_signal_connect(G_OBJECT(gtree.window), "delete_event",
2296 				G_CALLBACK(cb_delete_event), NULL);
2297 	g_signal_connect(G_OBJECT(gtree.window), "destroy",
2298 				G_CALLBACK(cb_destroy_event), NULL);
2299 	g_signal_connect(G_OBJECT(gtree.window), "configure_event",
2300 				G_CALLBACK(cb_configure_notify), NULL);
2301 	g_signal_connect(G_OBJECT(gtree.window), "map_event",
2302 				G_CALLBACK(cb_map_event), NULL);
2303 	g_signal_connect(G_OBJECT(gtree.window), "size_allocate",
2304 				G_CALLBACK(cb_size_allocate), NULL);
2305 	g_signal_connect(G_OBJECT(gtree.window), "client_event",
2306 				G_CALLBACK(cb_client_event), NULL);
2307 
2308 	g_signal_connect(G_OBJECT(gtree.top0_event_box), "button_press_event",
2309 				G_CALLBACK(top_frame_button_press), NULL );
2310 	g_signal_connect(G_OBJECT(gtree.top1_event_box), "button_press_event",
2311 				G_CALLBACK(top_frame_button_press), NULL );
2312 	g_signal_connect(G_OBJECT(gtree.top0_event_box), "motion_notify_event",
2313 				G_CALLBACK(gkrellm_motion), NULL);
2314 	g_signal_connect(G_OBJECT(gtree.top1_event_box), "motion_notify_event",
2315 				G_CALLBACK(gkrellm_motion), NULL);
2316 	g_signal_connect(G_OBJECT(gtree.top0_event_box), "button_release_event",
2317 				G_CALLBACK(top_frame_button_release), NULL );
2318 	g_signal_connect(G_OBJECT(gtree.top1_event_box), "button_release_event",
2319 				G_CALLBACK(top_frame_button_release), NULL );
2320 
2321 	g_signal_connect(G_OBJECT(gtree.left_event_box), "button_press_event",
2322 				G_CALLBACK(side_frame_button_press), NULL );
2323 	g_signal_connect(G_OBJECT(gtree.right_event_box), "button_press_event",
2324 				G_CALLBACK(side_frame_button_press), NULL );
2325 
2326 	ui_manager = gkrellm_create_ui_manager_popup();
2327 
2328 	if (_GK.sticky_state)
2329 		gtk_window_stick(GTK_WINDOW(top_window));
2330 	gkrellm_winop_options(argc, argv);
2331 	gtk_widget_show(gtree.window);
2332 	gkrellm_winop_withdrawn();
2333 
2334 	if (geometry || _GK.save_position)
2335 		configure_position_lock = TRUE;		/* see cb_configure_notify */
2336 
2337 	if (geometry)		/* Command line placement overrides */
2338 		gkrellm_winop_place_gkrellm(geometry);
2339 	else if (_GK.save_position)
2340 		set_or_save_position(0);
2341 
2342 	gkrellm_start_timer(_GK.update_HZ);
2343 	setup_signal_handler();
2344 	gtk_main();
2345 
2346 	gkrellm_save_all();
2347 
2348 	/* disconnect from gkrellm-server if we're a client */
2349 	if (_GK.server)
2350 		{
2351 		gkrellm_client_mode_disconnect();
2352 		}
2353 	gkrellm_exit(0);
2354 
2355 	return 0;
2356 	}
2357