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 >ree.frame_top_pixmap, >ree.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 >ree.frame_bottom_pixmap, >ree.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 >ree.frame_left_pixmap, >ree.frame_left_mask,
1171 _GK.frame_left_width, _GK.monitor_height);
1172 gkrellm_scale_piximage_to_pixmap(_GK.frame_right_piximage,
1173 >ree.frame_right_pixmap, >ree.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