1 /* -copyright-
2 #-#
3 #-# xsnow: let it snow on your desktop
4 #-# Copyright (C) 1984,1988,1990,1993-1995,2000-2001 Rick Jansen
5 #-# 2019,2020,2021 Willem Vermin
6 #-#
7 #-# This program is free software: you can redistribute it and/or modify
8 #-# it under the terms of the GNU General Public License as published by
9 #-# the Free Software Foundation, either version 3 of the License, or
10 #-# (at your option) any later version.
11 #-#
12 #-# This program is distributed in the hope that it will be useful,
13 #-# but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 #-# GNU General Public License for more details.
16 #-#
17 #-# You should have received a copy of the GNU General Public License
18 #-# along with this program. If not, see <http://www.gnu.org/licenses/>.
19 #-#
20 */
21
22 /* How to implement a new button
23 *
24 * The generation of code to add a button and/or a flag is dependent
25 * on definitions in 'doit.h' and 'buttons.h'.
26 *
27 * doit.h
28 * definition of names of flags, together with default values and vintage values
29 * example:
30 * DOIT_I(HaloBright ,25 ,25 )
31 *
32 * DOIT_I: for flags with an integer value
33 * DOIT_L: for flags with a large value (for example a window-id)
34 * DOIT_S: for flags with a char* value (colors, mostly)
35 *
36 * Macro DOIT will call macro's that are not meant for read/write from .xsnowrc
37 * Macro DOIT_ALL calls all DOIT_* macro's
38 * This will result in:
39 * see flags.h:
40 * creation of member HaloBright in type FLAGS (see flags.h)
41 * see flags.c:
42 * definition of default value in DefaultFlags.HaloBright (25)
43 * definition of vintage value in VintageFlags.Halobright (0)
44 * definition of WriteFlags() to write the flags to .xsnowrc
45 * definition of ReadFlags() to read flags from .xsnowrc
46 *
47 *
48 * buttons.h
49 * definition of button-related entities.
50 * example:
51 * BUTTON(scalecode ,xsnow_celestials ,HaloBright ,1 )
52 * this takes care that flag 'HaloBright' is associated with a button
53 * in the 'celestials' tab with the glade-id 'id-HaloBright' and that a value
54 * of 1 is used in the expansion of scalecode.
55 * In this case, the button should be a GtkScale button.
56 *
57 * The macro ALL_BUTTONS takes care that scalecode is called as
58 * scalecode(xsnow_celestials,HaloBright,1)
59 * and that all other BUTTON macro's are called
60 *
61 * The following types of buttons are implemented:
62 * GtkScale (macro scalecode)
63 * GtkToggle(macro togglecode)
64 * GtkColor (macro colorcode)
65 *
66 * In this way, the following items are generated:
67 *
68 * ui.c:
69 * define type Buttons, containing all flags in buttons.h
70 * associate the elements of Buttons with the corresponding
71 * glade-id's
72 * define call-backs
73 * these call backs have names like 'button_xsnow_celestials_HaloBright'
74 * the code ensures that for example Flags.HaloBright gets the value
75 * of the corresponding button.
76 * create a function settings1(), that sets all buttons in the state
77 * defined by the corresponding Flags. For example, if
78 * Flags.HaloBright = 40, the corresponding GtkScale button will be set
79 * to this value.
80 * connects signals of buttons to the corresponding call-backs, for example,
81 * button with glade-id 'id-HaloBright', when changed, will result in
82 * a call of button_xsnow_celestials_HaloBright().
83 * create function set_default_tab(int tab, int vintage) that gives the
84 * buttons in the given tab (for example 'xsnow_celestials') and the
85 * corresponding flags their default (vintage = 0) or vintage (vintage=1)
86 * value. One will notice, that some buttons need extra care, for example
87 * flag TreeType in xsnow_scenery.
88 *
89 * glade, ui.xml
90 *
91 * Glade is used to maintain 'ui.xml', where the creation of the tabs and the
92 * placement of the buttons is arranged.
93 * For the buttons in 'buttons.h' a callback is arranged in 'ui.c', so in general
94 * there is no need to do something with the 'signals' properties of these buttons.
95 * Things that are needed:
96 * - button text, maybe using a GtkLabel
97 * - tooltip
98 * - for scale buttons: a GtkScale, defining for example min and max values
99 * - placement
100 * - for few buttons: a css class. Example: BelowConfirm
101 * In Makefile.am, ui.xml is converted to an include file: ui_xml.h
102 * So, when compiled, the program does not need an external file for it's GtkBuilder.
103 *
104 *
105 * Handling of changed flags.
106 *
107 * In 'flags.h' the macros UIDO and UIDOS are defined. They take care of the
108 * standard action to be used when a flag has been changed: simply copy
109 * the new value to OldFlags and increment Flags.Changes. OldFlags is initialized
110 * at the start of the program, and is used to check if a flag has been changed.
111 *
112 * UIDO (for integer valued flags) and UIDOS (for char* valued flags) take
113 * two parameters:
114 * - the name of the flag to check
115 * - C-code to execute if the value of the flag has been changed.
116 *
117 * In main.c the flags in the 'settings' tab are handled, and calls are
118 * made to for example scenery_ui() which is supposed to handle flags related
119 * with the 'scenery' tab.
120 * If Flags.Changes > 0, the flags are written to .xsnowrc.
121 *
122 * Documentation of flags
123 *
124 * This is take care of in 'docs.c'.
125 *
126 */
127
128 #include "buttons.h"
129 // undef NEWLINE if one wants to examine the by cpp generated code:
130 // cpp ui.c | sed 's/NEWLINE/\n/g'
131 #define NEWLINE
132 //#undef NEWLINE
133 #ifdef NEWLINE
134 #include <gtk/gtk.h>
135 #include <stdlib.h>
136 #include <glib.h>
137 #include <glib/gprintf.h>
138 #include <math.h>
139 #include <unistd.h>
140 #include <string.h>
141 #include <assert.h>
142
143 #include "birds.h"
144 #include "clocks.h"
145 #include "csvpos.h"
146 #include "flags.h"
147 #include "pixmaps.h"
148 #include "snow.h"
149 #include "ui.h"
150 #include "ui_xml.h"
151 #include "utils.h"
152 #include "version.h"
153 #include "windows.h"
154 #include "xsnow.h"
155
156 #ifndef DEBUG
157 #define DEBUG
158 #endif
159 #undef DEBUG
160
161 #include "debug.h"
162 #endif /* NEWLINE */
163
164 #ifdef __cplusplus
165 #define MODULE_EXPORT extern "C" G_MODULE_EXPORT
166 #else
167 #define MODULE_EXPORT G_MODULE_EXPORT
168 #endif
169
170
171 #define PREFIX_SANTA "santa-"
172 #define PREFIX_TREE "tree-"
173
174 #define SANTA2(x) SANTA(x) SANTA(x ## r)
175 #define SANTA_ALL SANTA2(0) SANTA2(1) SANTA2(2) SANTA2(3) SANTA2(4)
176
177 #define TREE_ALL TREE(0) TREE(1) TREE(2) TREE(3) TREE(4) TREE(5) TREE(6) TREE(7)
178
179 #define DEFAULT(name) DefaultFlags.name
180 #define VINTAGE(name) VintageFlags.name
181
182 static GtkBuilder *builder;
183 static GtkWidget *mean_distance;
184 static GtkWidget *range;
185 static GtkWidget *desktop_type;
186 static GtkContainer *birdsgrid;
187 static GtkContainer *moonbox;
188 static GtkImage *preview;
189 #define nsbuffer 512
190 static char sbuffer[nsbuffer];
191
192 static void set_buttons(void);
193 static void set_santa_buttons(void);
194 static void set_tree_buttons(void);
195 static void handle_css(void);
196 static void birdscb(GtkWidget *w, void *m);
197 static int below_confirm_ticker(void *);
198 static int ui_running = False;
199 static void show_bct_countdown(void);
200 static void yesyes(GtkWidget *w, gpointer data);
201 static void nono(GtkWidget *w, gpointer data);
202 static void activate (GtkApplication *app);
203 static void set_default_tab(int tab, int vintage);
204 static void set_belowall_default();
205 static void handle_theme(void);
206 static void update_preview_cb (GtkFileChooser *file_chooser, gpointer data);
207 static void my_gtk_label_set_text(GtkLabel *label, const gchar *str);
208
209 static int human_interaction = 1;
210 GtkWidget *nflakeslabel;
211
212 static guint bct_id = 0;
213 static int bct_countdown;
214
215 static GtkWidget *hauptfenster;
216 static GtkStyleContext *hauptfenstersc;
217
ui_ui()218 void ui_ui()
219 {
220 UIDO (ThemeXsnow, handle_theme(););
221 }
222
handle_theme()223 void handle_theme()
224 {
225 if(!ui_running)
226 return;
227 if (Flags.ThemeXsnow)
228 {
229 gtk_style_context_add_class(hauptfenstersc,"xsnow");
230 }
231 else
232 {
233 gtk_style_context_remove_class(hauptfenstersc,"xsnow");
234 }
235 }
236
237
238 MODULE_EXPORT
button_iconify()239 void button_iconify()
240 {
241 P("button_iconify\n");
242 gtk_window_iconify(GTK_WINDOW(hauptfenster));
243 }
244
245 typedef struct _santa_button
246 {
247 char *imid;
248 GtkWidget *button;
249 gdouble value;
250 } santa_button;
251
252 #define NBUTTONS (2*(MAXSANTA+1))
253 // NBUTTONS is number of Santa's too choose from
254 #define SANTA(x) NEWLINE santa_button santa_ ## x;
255 static struct _santa_buttons
256 {
257 SANTA_ALL
258 } santa_buttons;
259 #include "undefall.inc"
260
261
262 #define SANTA(x) NEWLINE &santa_buttons.santa_ ## x,
263 static santa_button *santa_barray[NBUTTONS]=
264 {
265 SANTA_ALL
266 };
267 #include "undefall.inc"
268
init_santa_buttons()269 static void init_santa_buttons()
270 {
271 #define SANTA(x) \
272 NEWLINE santa_buttons.santa_ ## x.button = GTK_WIDGET(gtk_builder_get_object(builder,PREFIX_SANTA #x));
273 SANTA_ALL;
274 #include "undefall.inc"
275 #define SANTA(x) \
276 NEWLINE gtk_widget_set_name(santa_buttons.santa_ ## x.button,PREFIX_SANTA #x);
277 SANTA_ALL;
278 #include "undefall.inc"
279
280 }
281
set_santa_buttons()282 static void set_santa_buttons()
283 {
284 int n = 2*Flags.SantaSize;
285 if (Flags.Rudolf)
286 n++;
287 if (n<NBUTTONS)
288 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(santa_barray[n]->button),TRUE);
289 }
290
291 MODULE_EXPORT
button_santa(GtkWidget * w)292 void button_santa(GtkWidget *w)
293 {
294 if(!human_interaction) return;
295 if(!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w))) return;
296 const gchar *s = gtk_widget_get_name(w)+strlen(PREFIX_SANTA);
297 int santa_type = atoi(s);
298 int have_rudolf = ('r' == s[strlen(s)-1]);
299 P("button_santa: Santa %d Rudolf %d s: %s name: %s\n",santa_type,have_rudolf,s,gtk_widget_get_name(w));
300 Flags.SantaSize = santa_type;
301 Flags.Rudolf = have_rudolf;
302 }
303
304 MODULE_EXPORT
button_defaults_santa()305 void button_defaults_santa()
306 {
307 P("button_defaults_santa defaults\n");
308 set_default_tab(xsnow_santa,0);
309 }
310
311 MODULE_EXPORT
button_vintage_santa()312 void button_vintage_santa()
313 {
314 P("button_defaults_santa vintage\n");
315 set_default_tab(xsnow_santa,1);
316 }
317
318 typedef struct _tree_button
319 {
320 GtkWidget *button;
321 }tree_button;
322
323 #define TREE(x) NEWLINE tree_button tree_ ## x;
324 static struct _tree_buttons
325 {
326 TREE_ALL
327 } tree_buttons;
328 #include "undefall.inc"
329
330
331 // creating type Buttons: Button.NStars etc.
332
333 #define togglecode(type,name,m) NEWLINE GtkWidget *name;
334 #define scalecode togglecode
335 #define colorcode togglecode
336 #define filecode togglecode
337 static struct _Button
338 {
339 ALL_BUTTONS
340 } Button;
341 #include "undefall.inc"
342
343 // create init_buttons: connect with glade-id
344 // glade-id will be: "id-name", eg: "id-SnowFlakesFactor"
345 #define ID "id"
346
347 #define togglecode(type,name,m) \
348 NEWLINE P("%s %s\n",#name,#type); \
349 NEWLINE Button.name = GTK_WIDGET(gtk_builder_get_object(builder,ID "-" #name));
350 #define scalecode togglecode
351 #define colorcode togglecode
352 #define filecode togglecode
353
init_buttons1()354 static void init_buttons1()
355 {
356 P("\nstart init_buttons1\n\n");
357 ALL_BUTTONS
358 P("\nend init_buttons1\n\n");
359 }
360 #include "undefall.inc"
361
362 // define call backs
363
364 #define buttoncb(type,name) button_##type##_##name
365 #define togglecode(type,name,m) \
366 NEWLINE MODULE_EXPORT void buttoncb(type,name)(GtkWidget *w) \
367 NEWLINE { \
368 NEWLINE if(!human_interaction) return; \
369 NEWLINE gint active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w)); \
370 NEWLINE if(active) Flags.name = TRUE; else Flags.name = FALSE; \
371 NEWLINE if(m<0) Flags.name = !Flags.name; \
372 NEWLINE }
373
374 #define scalecode(type,name,m) \
375 NEWLINE MODULE_EXPORT void buttoncb(type,name)(GtkWidget *w)\
376 NEWLINE {\
377 NEWLINE if(!human_interaction) return; \
378 NEWLINE gdouble value; \
379 NEWLINE value = gtk_range_get_value(GTK_RANGE(w)); \
380 NEWLINE Flags.name = m*lrint(value); \
381 NEWLINE }
382
383 #define colorcode(type,name,m) \
384 NEWLINE MODULE_EXPORT void buttoncb(type,name)(GtkWidget *w) \
385 NEWLINE { \
386 NEWLINE if(!human_interaction) return; \
387 NEWLINE GdkRGBA color; \
388 NEWLINE gtk_color_chooser_get_rgba(GTK_COLOR_CHOOSER(w),&color); \
389 NEWLINE free(Flags.name); \
390 NEWLINE rgba2color(&color,&Flags.name); \
391 NEWLINE }
392
393 #define filecode(type,name,m) \
394 NEWLINE MODULE_EXPORT void buttoncb(type,name)(GtkWidget *w) \
395 NEWLINE { \
396 NEWLINE if(!human_interaction) return; \
397 NEWLINE gchar *filename; \
398 NEWLINE filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(w)); \
399 NEWLINE free(Flags.name); \
400 NEWLINE Flags.name = strdup(filename); \
401 NEWLINE g_free(filename); \
402 NEWLINE }
403
404 ALL_BUTTONS
405 #include "undefall.inc"
406
407 // define set_buttons
408 //
409 #define togglecode(type,name,m)\
410 NEWLINE P("toggle %s %s %d %d\n",#name,#type,m,Flags.name); \
411 NEWLINE if (m) { \
412 NEWLINE if(m>0) gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Button.name),Flags.name);\
413 NEWLINE else gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Button.name),!Flags.name);\
414 NEWLINE }
415 #define scalecode(type,name,m) \
416 NEWLINE P("range %s %s %d %d\n",#name,#type,m,Flags.name); \
417 NEWLINE gtk_range_set_value(GTK_RANGE(Button.name), m*((gdouble)Flags.name));
418 #define colorcode(type,name,m) \
419 NEWLINE P("color %s %s %d %s\n",#name,#type,m,Flags.name); \
420 NEWLINE gdk_rgba_parse(&color,Flags.name); \
421 NEWLINE gtk_color_chooser_set_rgba(GTK_COLOR_CHOOSER(Button.name),&color);
422 #define filecode(type,name,m) \
423 NEWLINE P("file %s %s %d %s\n",#name,#type,m,Flags.name); \
424 NEWLINE gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(Button.name),Flags.BackgroundFile);
425
set_buttons1()426 static void set_buttons1()
427 {
428 GdkRGBA color;
429 ALL_BUTTONS
430 }
431 #include "undefall.inc"
432
433 // define signal_connect
434
435 #define togglecode(type,name,m) \
436 NEWLINE P("%s %s\n",#name,#type); \
437 NEWLINE g_signal_connect(G_OBJECT(Button.name),"toggled", G_CALLBACK(buttoncb(type,name)),NULL);
438 #define scalecode(type,name,m) \
439 NEWLINE P("%s %s\n",#name,#type); \
440 NEWLINE g_signal_connect(G_OBJECT(Button.name),"value-changed", G_CALLBACK(buttoncb(type,name)),NULL);
441 #define colorcode(type,name,m) \
442 NEWLINE P("%s %s\n",#name,#type); \
443 NEWLINE g_signal_connect(G_OBJECT(Button.name),"color-set", G_CALLBACK(buttoncb(type,name)),NULL);
444 #define filecode(type,name,m) \
445 NEWLINE P("%s %s\n",#name,#type); \
446 NEWLINE g_signal_connect(G_OBJECT(Button.name),"file-set", G_CALLBACK(buttoncb(type,name)),NULL);
447
connect_signals()448 static void connect_signals()
449 {
450 P("\nstart connect_signals\n\n");
451 ALL_BUTTONS
452 P("\nend connect_signals\n\n");
453 }
454 #include "undefall.inc"
455
456
report_tree_type(int p,gint active)457 static void report_tree_type(int p, gint active)
458 {
459 P("Tree: %d %d %s\n",p,active,Flags.TreeType);
460 int *a;
461 int n;
462 csvpos(Flags.TreeType,&a,&n);
463 if(active)
464 {
465 a = (int *)realloc(a,sizeof(*a)*(n+1));
466 a[n] = p;
467 n++;
468 }
469 else
470 {
471 int i;
472 for (i=0; i<n; i++)
473 if(a[i] == p)
474 a[i] = -1;
475 }
476 int *b = (int *)malloc(sizeof(*b)*n);
477 int i,m=0;
478 for(i=0; i<n; i++)
479 {
480 int j;
481 int unique = (a[i] >= 0);
482 if(unique)
483 for (j=0; j<m; j++)
484 if(a[i] == b[j])
485 {
486 unique = 0;
487 break;
488 }
489 if(unique)
490 {
491 b[m] = a[i];
492 m++;
493 }
494 }
495 free(Flags.TreeType);
496 vsc(&Flags.TreeType,b,m);
497 free(a);
498 free(b);
499 P("Tree_Type set to %s\n",Flags.TreeType);
500 }
501
button_tree(GtkWidget * w)502 MODULE_EXPORT void button_tree(GtkWidget *w)
503 {
504 if(!human_interaction) return;
505 gint active;
506 active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
507 const gchar *s = gtk_widget_get_name(w)+strlen(PREFIX_TREE);
508 int p = atoi(s);
509 report_tree_type(p,active);
510 P("button_tree: tree: %d active: %d\n",p,active);
511 }
512
513
514 MODULE_EXPORT
button_defaults_scenery()515 void button_defaults_scenery()
516 {
517 P("button_defaults_scenery\n");
518 set_default_tab(xsnow_scenery,0);
519 }
520
521 MODULE_EXPORT
button_vintage_scenery()522 void button_vintage_scenery()
523 {
524 P("button_vintage_scenery\n");
525 set_default_tab(xsnow_scenery,1);
526 }
527
528
init_tree_buttons()529 static void init_tree_buttons()
530 {
531
532 #define TREE(x) \
533 NEWLINE tree_buttons.tree_##x.button = GTK_WIDGET(gtk_builder_get_object(builder,PREFIX_TREE #x));
534 TREE_ALL;
535 #include "undefall.inc"
536 #define TREE(x) \
537 NEWLINE gtk_widget_set_name(tree_buttons.tree_##x.button,PREFIX_TREE #x);
538 TREE_ALL;
539 #include "undefall.inc"
540 }
541
init_santa_pixmaps()542 static void init_santa_pixmaps()
543 {
544 #define SANTA(x) NEWLINE santa_buttons.santa_ ## x.imid = (char *)PREFIX_SANTA # x "-imid";
545 SANTA_ALL;
546 #include "undefall.inc"
547
548 int i;
549 GtkImage *image;
550 GdkPixbuf *pixbuf;
551 for (i=0; i<NBUTTONS; i++)
552 {
553 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)Santas[i/2][i%2][0]);
554 image = GTK_IMAGE(gtk_builder_get_object(builder,santa_barray[i]->imid));
555 gtk_image_set_from_pixbuf(image,pixbuf);
556 g_object_unref(pixbuf);
557 }
558 }
559
init_tree_pixmaps()560 static void init_tree_pixmaps()
561 {
562 GtkImage *image;
563 GdkPixbuf *pixbuf;
564 #define TREE(x) \
565 NEWLINE pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)xpmtrees[x]);\
566 NEWLINE image = GTK_IMAGE(gtk_builder_get_object(builder,"treeimage" # x));\
567 NEWLINE gtk_image_set_from_pixbuf(image,pixbuf); \
568 NEWLINE g_object_unref(pixbuf);
569
570 TREE_ALL;
571 #include "undefall.inc"
572 }
573
init_hello_pixmaps()574 static void init_hello_pixmaps()
575 {
576 GtkImage *image;
577 GdkPixbuf *pixbuf, *pixbuf1;
578 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)xsnow_logo);
579 pixbuf1 = gdk_pixbuf_scale_simple(pixbuf,64,64,GDK_INTERP_BILINEAR);
580 image = GTK_IMAGE(gtk_builder_get_object(builder,"hello-image1"));
581 gtk_image_set_from_pixbuf(image,pixbuf1);
582 image = GTK_IMAGE(gtk_builder_get_object(builder,"hello-image2"));
583 gtk_image_set_from_pixbuf(image,pixbuf1);
584 g_object_unref(pixbuf);
585 g_object_unref(pixbuf1);
586 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)xpmtrees[0]);
587 image = GTK_IMAGE(gtk_builder_get_object(builder,"hello-image3"));
588 gtk_image_set_from_pixbuf(image,pixbuf);
589 image = GTK_IMAGE(gtk_builder_get_object(builder,"hello-image4"));
590 gtk_image_set_from_pixbuf(image,pixbuf);
591 g_object_unref(pixbuf);
592 }
593
init_pixmaps()594 static void init_pixmaps()
595 {
596 init_santa_pixmaps();
597 init_tree_pixmaps();
598 init_hello_pixmaps();
599 }
600
set_tree_buttons()601 static void set_tree_buttons()
602 {
603
604 #define TREE(x)\
605 NEWLINE gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tree_buttons.tree_##x.button),FALSE);
606 TREE_ALL;
607 #include "undefall.inc"
608 int i;
609 int *a,n;
610 csvpos(Flags.TreeType,&a,&n);
611
612 for (i=0; i<n; i++)
613 {
614 P("set_tree_buttons::::::::::::::::::::: %s %d %d\n",Flags.TreeType,n,a[i]);
615 switch (a[i])
616 {
617 #define TREE(x) \
618 NEWLINE case x: gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(tree_buttons.tree_##x.button),TRUE);\
619 NEWLINE break;
620 TREE_ALL;
621 #include "undefall.inc"
622 }
623 }
624 free(a);
625 }
626
627 typedef struct _general_button
628 {
629 GtkWidget *button;
630 }general_button;
631
632
633
button_below(GtkWidget * w)634 MODULE_EXPORT void button_below(GtkWidget *w)
635 {
636 /*
637 * In some desktop environments putting our transparent click-through window
638 * above all other windows results in a un-clickable desktop.
639 * Therefore, we ask for confirmation by clicking on a button.
640 * If this succeeds, then there is no problem.
641 * If the user cannot click, the timer runs out and the BelowAll
642 * setting is switched to TRUE.
643 */
644 if(!human_interaction) return;
645 gint active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
646 P("button_below: %d\n",Flags.BelowAll);
647 if(active)
648 Flags.BelowAll = 1;
649 else
650 {
651 Flags.BelowAll = 0;
652 bct_countdown = 9;
653 show_bct_countdown();
654 gtk_widget_hide(Button.BelowAll);
655 gtk_widget_show(Button.BelowConfirm);
656 bct_id = add_to_mainloop(PRIORITY_DEFAULT,time_below_confirm,below_confirm_ticker);
657 }
658 }
button_below_confirm()659 MODULE_EXPORT void button_below_confirm()
660 {
661 gtk_widget_hide(Button.BelowConfirm);
662 gtk_widget_show(Button.BelowAll);
663 remove_from_mainloop(&bct_id);
664 }
665
init_general_buttons()666 static void init_general_buttons()
667 {
668 g_signal_connect(Button.BelowAll, "toggled", G_CALLBACK (button_below), NULL);
669 g_signal_connect(Button.BelowConfirm, "toggled", G_CALLBACK(button_below_confirm), NULL);
670
671 my_gtk_label_set_text(GTK_LABEL(gtk_builder_get_object(builder,"id-version")),"xsnow version " VERSION);
672
673 gtk_widget_hide(Button.BelowConfirm);
674 }
675
676
677
show_bct_countdown()678 void show_bct_countdown()
679 {
680 sprintf(sbuffer,"Click to\nconfirm %d",bct_countdown);
681 gtk_button_set_label(GTK_BUTTON(Button.BelowConfirm),sbuffer);
682
683 }
684
below_confirm_ticker(void * d)685 int below_confirm_ticker(void *d)
686 {
687 bct_countdown--;
688 show_bct_countdown();
689 if (bct_countdown>0)
690 return TRUE;
691 else
692 {
693 set_belowall_default();
694 return FALSE;
695 }
696 (void)d;
697 }
698
set_belowall_default()699 void set_belowall_default()
700 {
701 P("set_belowall_default: %d\n",bct_id);
702 remove_from_mainloop(&bct_id);
703 Flags.BelowAll = 1;
704 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Button.BelowAll),Flags.BelowAll);
705 gtk_widget_hide(Button.BelowConfirm);
706 gtk_widget_show(Button.BelowAll);
707 }
708
709
710
711 MODULE_EXPORT
button_quit()712 void button_quit()
713 {
714 Flags.Done = 1;
715 P("button_quit: %d\n",Flags.Done);
716 }
717
718
719 MODULE_EXPORT
button_defaults_general()720 void button_defaults_general()
721 {
722 P("button_defaults_general\n");
723 set_default_tab(xsnow_settings,0);
724 }
725
726 MODULE_EXPORT
button_vintage_general()727 void button_vintage_general()
728 {
729 P("button_defaults_general vintage\n");
730 set_default_tab(xsnow_settings,1);
731 }
732
733 typedef struct _snow_button
734 {
735 GtkWidget *button;
736 }snow_button;
737
738
739 MODULE_EXPORT
button_defaults_snow()740 void button_defaults_snow()
741 {
742 P("button_defaults_snow\n");
743 set_default_tab(xsnow_snow,0);
744 }
745
746 MODULE_EXPORT
button_vintage_snow()747 void button_vintage_snow()
748 {
749 P("button_vintage_snow\n");
750 set_default_tab(xsnow_snow,1);
751 }
752
ui_set_birds_header(const char * text)753 void ui_set_birds_header(const char *text)
754 {
755 if(!ui_running)
756 return;
757 GtkWidget *birds_header = GTK_WIDGET(gtk_builder_get_object(builder,"birds-header"));
758 my_gtk_label_set_text(GTK_LABEL(birds_header),text);
759 }
760
ui_set_celestials_header(const char * text)761 void ui_set_celestials_header(const char *text)
762 {
763 if(!ui_running)
764 return;
765 GtkWidget *celestials_header = GTK_WIDGET(gtk_builder_get_object(builder,"celestials-header"));
766 char *a = strdup(gtk_label_get_text(GTK_LABEL(celestials_header)));
767 a = (char *) realloc(a,strlen(a)+2+strlen(text));
768 strcat(a,"\n");
769 strcat(a,text);
770 my_gtk_label_set_text(GTK_LABEL(celestials_header),a);
771 free(a);
772 }
773
774
button_defaults_birds()775 MODULE_EXPORT void button_defaults_birds()
776 {
777 P("button_defaults_birds\n");
778 set_default_tab(xsnow_birds,0);
779 }
780
button_vintage_birds()781 MODULE_EXPORT void button_vintage_birds()
782 {
783 P("button_vintage_birds\n");
784 set_default_tab(xsnow_birds,1);
785 }
786
button_birds_restart()787 MODULE_EXPORT void button_birds_restart()
788 {
789 P("button_birds_restart\n");
790 Flags.BirdsRestart = 1;
791 }
792
button_wind_activate()793 MODULE_EXPORT void button_wind_activate()
794 {
795 P("button_wind_activate\n");
796 Flags.WindNow = 1;
797 }
798
button_xscreensaver_activate()799 MODULE_EXPORT void button_xscreensaver_activate()
800 {
801 int rc = system("xscreensaver-command -activate");
802 (void) rc;
803 }
804
set_default_tab(int tab,int vintage)805 void set_default_tab(int tab, int vintage)
806 {
807 int h = human_interaction;
808 human_interaction = 0;
809 char *background = strdup(Flags.BackgroundFile); // don't want to clear backgroundfile
810 if(vintage)
811 {
812 #define togglecode(type,name,m) \
813 NEWLINE if (type == tab) Flags.name = VINTAGE(name);
814 #define scalecode togglecode
815 #define colorcode(type,name,m) \
816 NEWLINE if (type == tab) \
817 NEWLINE { free(Flags.name); Flags.name = strdup(VINTAGE(name)); }
818 #define filecode colorcode
819
820 ALL_BUTTONS;
821 #include "undefall.inc"
822 switch(tab)
823 {
824 case xsnow_scenery:
825 free(Flags.TreeType);
826 Flags.TreeType = strdup(VINTAGE(TreeType));
827 break;
828 case xsnow_snow:
829 Flags.VintageFlakes = 1;
830 break;
831 case xsnow_santa:
832 Flags.SantaSize = VINTAGE(SantaSize);
833 Flags.Rudolf = VINTAGE(Rudolf);
834 break;
835 case xsnow_settings:
836 set_belowall_default();
837 free(Flags.BackgroundFile);
838 Flags.BackgroundFile = strdup(background);
839 break;
840 }
841 }
842 else
843 #define togglecode(type,name,m) \
844 NEWLINE if (type == tab) Flags.name = DEFAULT(name);
845 #define scalecode togglecode
846 #define colorcode(type,name,m) \
847 NEWLINE if (type == tab) \
848 NEWLINE { free(Flags.name); Flags.name = strdup(DEFAULT(name)); }
849 #define filecode colorcode
850 {
851 ALL_BUTTONS;
852 #include "undefall.inc"
853 switch(tab)
854 {
855 case xsnow_scenery:
856 free(Flags.TreeType);
857 Flags.TreeType = strdup(DEFAULT(TreeType));
858 break;
859 case xsnow_snow:
860 Flags.VintageFlakes = 0;
861 break;
862 case xsnow_santa:
863 Flags.SantaSize = DEFAULT(SantaSize);
864 Flags.Rudolf = DEFAULT(Rudolf);
865 break;
866 case xsnow_settings:
867 set_belowall_default();
868 free(Flags.BackgroundFile);
869 Flags.BackgroundFile = strdup(background);
870 break;
871 }
872 }
873 set_buttons();
874 human_interaction = h;
875 free(background);
876 }
877
878 MODULE_EXPORT
button_defaults_celestials()879 void button_defaults_celestials()
880 {
881 P("button_defaults_wind\n");
882 set_default_tab(xsnow_celestials,0);
883 }
884
885 MODULE_EXPORT
button_vintage_celestials()886 void button_vintage_celestials()
887 {
888 P("button_vintage_wind\n");
889 set_default_tab(xsnow_celestials,1);
890 }
891
init_buttons()892 static void init_buttons()
893 {
894 init_buttons1();
895 init_santa_buttons();
896 init_tree_buttons();
897 init_general_buttons();
898 nflakeslabel = GTK_WIDGET(gtk_builder_get_object(builder,"nflakes"));
899 }
900
set_buttons()901 static void set_buttons()
902 {
903 human_interaction = 0;
904 set_buttons1();
905 set_santa_buttons();
906 set_tree_buttons();
907 human_interaction = 1;
908 }
909
all_default(int vintage)910 void all_default(int vintage)
911 {
912 /* xsnow_settings is deliberately not included here */
913 set_default_tab(xsnow_santa,vintage);
914 set_default_tab(xsnow_scenery,vintage);
915 set_default_tab(xsnow_snow,vintage);
916 set_default_tab(xsnow_celestials,vintage);
917 set_default_tab(xsnow_birds,vintage);
918 set_belowall_default();
919 }
920
button_all_defaults()921 MODULE_EXPORT void button_all_defaults()
922 {
923 P("button_all_defaults\n");
924 all_default(0);
925 }
926
button_all_vintage()927 MODULE_EXPORT void button_all_vintage()
928 {
929 P("button_all_vintage\n");
930 all_default(1);
931 }
932
ui_show_nflakes(int n)933 void ui_show_nflakes(int n)
934 {
935 if(!ui_running)
936 return;
937 snprintf(sbuffer,nsbuffer,"%6d",n);
938 my_gtk_label_set_text(GTK_LABEL(nflakeslabel),sbuffer);
939 }
940
ui_show_range_etc()941 void ui_show_range_etc()
942 {
943 if(!ui_running)
944 return;
945 snprintf(sbuffer,nsbuffer,"Range: %d\n",(int)birds_get_range());
946 my_gtk_label_set_text(GTK_LABEL(range),sbuffer);
947 snprintf(sbuffer,nsbuffer,"Mean dist: %d\n",(int)birds_get_mean_dist());
948 my_gtk_label_set_text(GTK_LABEL(mean_distance),sbuffer);
949 }
950
ui_show_desktop_type(const char * s)951 void ui_show_desktop_type(const char *s)
952 {
953 if(!ui_running)
954 return;
955 snprintf(sbuffer,nsbuffer,"Desktop type: %s",s);
956 my_gtk_label_set_text(GTK_LABEL(desktop_type),sbuffer);
957 }
958
ui_set_sticky(int x)959 void ui_set_sticky(int x)
960 {
961 if(!ui_running)
962 return;
963 if (x)
964 gtk_window_stick(GTK_WINDOW(hauptfenster));
965 else
966 gtk_window_unstick(GTK_WINDOW(hauptfenster));
967 }
968
969 // https://docs.gtk.org/gtk3/iface.FileChooser.html
update_preview_cb(GtkFileChooser * file_chooser,gpointer data)970 void update_preview_cb (GtkFileChooser *file_chooser, gpointer data)
971 {
972 GtkWidget *preview;
973 char *filename;
974 GdkPixbuf *pixbuf;
975 gboolean have_preview;
976
977 preview = GTK_WIDGET (data);
978 filename = gtk_file_chooser_get_preview_filename (file_chooser);
979 if(!IsReadableFile(filename))
980 {
981 g_free(filename);
982 return;
983 }
984
985 int w = global.SnowWinWidth/10;
986
987 //pixbuf = gdk_pixbuf_new_from_file_at_size (filename, 128, 128, NULL);
988 pixbuf = gdk_pixbuf_new_from_file_at_size (filename, w, w, NULL);
989 have_preview = (pixbuf != NULL);
990 g_free (filename);
991
992 gtk_image_set_from_pixbuf (GTK_IMAGE (preview), pixbuf);
993 if (pixbuf)
994 g_object_unref (pixbuf);
995
996 gtk_file_chooser_set_use_preview_label(file_chooser, FALSE);
997 gtk_file_chooser_set_preview_widget_active (file_chooser, have_preview);
998 }
999
ui()1000 void ui()
1001 {
1002 ui_running = True;
1003 builder = gtk_builder_new_from_string (xsnow_xml, -1);
1004 gtk_builder_connect_signals (builder, builder);
1005 hauptfenster = GTK_WIDGET (gtk_builder_get_object(builder, "hauptfenster"));
1006 mean_distance = GTK_WIDGET (gtk_builder_get_object(builder, "birds-mean-distance"));
1007 range = GTK_WIDGET (gtk_builder_get_object(builder, "birds-range"));
1008 desktop_type = GTK_WIDGET (gtk_builder_get_object(builder, "settings-show-desktop-type"));
1009 birdsgrid = GTK_CONTAINER(gtk_builder_get_object(builder, "grid_birds"));
1010 moonbox = GTK_CONTAINER(gtk_builder_get_object(builder, "moon-box"));
1011
1012 hauptfenstersc = gtk_widget_get_style_context(hauptfenster);
1013
1014 handle_css();
1015
1016 gtk_window_set_title(GTK_WINDOW(hauptfenster),"XsnoW");
1017 gtk_widget_show_all (hauptfenster);
1018
1019 init_buttons();
1020 connect_signals();
1021 init_pixmaps();
1022 set_buttons();
1023 preview = GTK_IMAGE(gtk_image_new());
1024 gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER(Button.BackgroundFile), GTK_WIDGET(preview));
1025 g_signal_connect (GTK_FILE_CHOOSER(Button.BackgroundFile), "update-preview",
1026 G_CALLBACK (update_preview_cb), preview);
1027
1028 if (Flags.HideMenu)
1029 gtk_window_iconify(GTK_WINDOW(hauptfenster));
1030
1031 }
1032
1033 // Set the style provider for the widgets
apply_css_provider(GtkWidget * widget,GtkCssProvider * cssstyleProvider)1034 static void apply_css_provider (GtkWidget *widget, GtkCssProvider *cssstyleProvider)
1035 {
1036 P("apply_css_provider %s\n",gtk_widget_get_name(GTK_WIDGET(widget)));
1037
1038 gtk_style_context_add_provider ( gtk_widget_get_style_context(widget),
1039 GTK_STYLE_PROVIDER(cssstyleProvider) ,
1040 GTK_STYLE_PROVIDER_PRIORITY_APPLICATION );
1041
1042 // For container widgets, apply to every child widget on the container
1043 if (GTK_IS_CONTAINER (widget))
1044 {
1045 gtk_container_forall( GTK_CONTAINER (widget),
1046 (GtkCallback)apply_css_provider ,
1047 cssstyleProvider);
1048 }
1049 }
1050
1051
handle_css()1052 void handle_css()
1053 {
1054 const char *css =
1055 // I wish how I could copy the Adwaita settings ...
1056 //".xsnow button { padding-left: 16px; padding-right: 16px; padding-top: 4px; padding-bottom: 4px;}"
1057 //".xsnow headerbar button { padding-left: 10px; padding-right: 10px; padding-top: 4px; padding-bottom: 4px;}"
1058 //".xsnow headerbar.titlebar { border-color: rgb(213,208,204); border-style:solid; border-bottom-left-radius: 0px; border-bottom-right-radius: 0px; border-top-left-radius: 8px; border-top-right-radius: 8px;}"
1059 //".xsnow headerbar label.title { padding-left: 12px; padding-right:12px;}"
1060 //".xsnow button.color {padding: 4px; }"
1061 //".xsnow headerbar stackswitcher button.radio label { color: #065522; }"
1062 //".xsnow headerbar stackswitcher button.radio { box-shadow: 0px 0px; border-top-width: 0px; }"
1063
1064 // These are not colors, but nevertheless I think we should do this always:
1065 "scale { padding: 1em; }" // padding in slider buttons
1066 "button.radio { min-width: 10px; }" // make window as narrow as possible
1067 "label.busymessage { border-radius: 4px; min-height: 3.5em }" // info message in welcome tab
1068
1069 // colors: (the buttons in the headerbar need some work)
1070 ".xsnow * { border-color: #B4EEB4; }" // border colors
1071 ".xsnow button { background: #CCF0D8; }" // color of normal buttons
1072 ".xsnow button.radio, .xsnow button.toggle { background: #E2FDEC; }" // color of radio and toggle buttons
1073 ".xsnow radiobutton:active, .xsnow button:active { background: #0DAB44; }" // color of buttons while being activated
1074 ".xsnow radiobutton:checked, .xsnow button:checked { background: #6AF69B; }" // color of checked buttons
1075 ".xsnow headerbar { background: #B3F4CA; }" // color of headerbar
1076 ".xsnow scale slider { background: #D4EDDD; }" // color of sliders
1077 ".xsnow scale trough { background: #0DAB44; }" // color of trough of sliders
1078 ".xsnow stack { background: #EAFBF0; }" // color of main area
1079 ".xsnow * { color: #065522; }" // foreground color (text)
1080 ".xsnow *:disabled * { color: #8FB39B; }" // foreground color for disabled items
1081 ".busy stack { background: #FFC0CB; }" // background color when too busy
1082 ".busy .cpuload slider { background: #FF0000; }" // color of some sliders when too busy
1083 "button.confirm { background: #FFFF00; }" // color for confirm above windows
1084 ".xsnow button.confirm { background-color: #FFFF00; }" // yes we need both, but why?
1085 "label.busymessage { background: #FFC0CB; }" // info message in welcome tab
1086 ;
1087
1088 static GtkCssProvider *cssProvider = NULL;
1089 if (!cssProvider)
1090 {
1091 cssProvider = gtk_css_provider_new();
1092 gtk_css_provider_load_from_data (cssProvider, css,-1,NULL);
1093 apply_css_provider(hauptfenster, cssProvider);
1094 }
1095
1096 handle_theme();
1097
1098 }
1099
1100 // if m==1: change some colors of the ui
1101 // if m==0: change back to default colors
1102
ui_background(int m)1103 void ui_background(int m)
1104 {
1105 if(!ui_running)
1106 return;
1107 if(m)
1108 gtk_style_context_add_class(hauptfenstersc,"busy");
1109 else
1110 gtk_style_context_remove_class(hauptfenstersc,"busy");
1111
1112 }
1113
1114
1115 // m=0: make active
1116 // m=1: make inactive
1117 // however, see transparency and below
ui_gray_erase(int m)1118 void ui_gray_erase(int m)
1119 {
1120 gtk_widget_set_sensitive(Button.BelowAll, m);
1121 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(Button.BelowAll),1);
1122 }
1123
1124
1125 // m=0: make active
1126 // m=1: make inactive
ui_gray_below(int m)1127 void ui_gray_below(int m)
1128 {
1129 gtk_widget_set_sensitive(Button.BelowAll, !m);
1130 }
1131
birdscb(GtkWidget * w,void * m)1132 void birdscb(GtkWidget *w, void *m)
1133 {
1134 gtk_widget_set_sensitive(w,!(int *)m);
1135 }
1136
ui_gray_birds(int m)1137 void ui_gray_birds(int m)
1138 {
1139 if(!ui_running)
1140 return;
1141 gtk_container_foreach(birdsgrid, birdscb, &m);
1142 gtk_container_foreach(moonbox, birdscb, &m);
1143 }
1144
ui_gtk_version()1145 char * ui_gtk_version()
1146 {
1147 static char s[20];
1148 snprintf(s,20,"%d.%d.%d",gtk_get_major_version(),gtk_get_minor_version(),gtk_get_micro_version());
1149 return s;
1150 }
1151
ui_gtk_required()1152 char * ui_gtk_required()
1153 {
1154 static char s[20];
1155 snprintf(s,20,"%d.%d.%d",GTK_MAJOR,GTK_MINOR,GTK_MICRO);
1156 return s;
1157 }
1158
1159 // returns:
1160 // 0: gtk version in use too low
1161 // 1: gtk version in use OK
ui_checkgtk()1162 int ui_checkgtk()
1163 {
1164 if ((int)gtk_get_major_version() > GTK_MAJOR)
1165 return 1;
1166 if ((int)gtk_get_major_version() < GTK_MAJOR)
1167 return 0;
1168 if ((int)gtk_get_minor_version() > GTK_MINOR)
1169 return 1;
1170 if ((int)gtk_get_minor_version() < GTK_MINOR)
1171 return 0;
1172 if ((int)gtk_get_micro_version() >= GTK_MICRO)
1173 return 1;
1174 return 0;
1175 }
1176
1177 // to be used if gtk version is too low
1178 // returns 1: user clicked 'Run with ...'
1179 // returns 0: user clicked 'Quit'
1180 static int RC;
ui_run_nomenu()1181 int ui_run_nomenu()
1182 {
1183 GtkApplication *app;
1184 app = gtk_application_new ("nl.ratrabbit.example", G_APPLICATION_FLAGS_NONE);
1185 g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
1186 g_application_run (G_APPLICATION (app), 0, NULL);
1187 g_object_unref (app);
1188 return RC;
1189 }
1190
activate(GtkApplication * app)1191 static void activate (GtkApplication *app)
1192 {
1193 GtkWidget *window;
1194 GtkWidget *grid;
1195 GtkWidget *button;
1196 GtkWidget *label;
1197
1198
1199 /* create a new window, and set its title */
1200 window = gtk_application_window_new (app);
1201 gtk_window_set_position (GTK_WINDOW(window), GTK_WIN_POS_CENTER);
1202 gtk_window_set_title (GTK_WINDOW (window), "Xsnow");
1203 gtk_window_set_decorated (GTK_WINDOW(window), FALSE);
1204 gtk_window_set_keep_above (GTK_WINDOW(window), TRUE);
1205 gtk_container_set_border_width (GTK_CONTAINER (window), 10);
1206
1207 /* Here we construct the container that is going pack our buttons */
1208 grid = gtk_grid_new ();
1209
1210 /* Pack the container in the window */
1211 gtk_container_add (GTK_CONTAINER (window), grid);
1212
1213 snprintf(sbuffer,nsbuffer,
1214 "You are using GTK-%s, but you need at least GTK-%s to view\n"
1215 "the user interface.\n"
1216 "Use the option '-nomenu' to disable the user interface.\n"
1217 "If you want to try the user interface anyway, use the flag '-checkgtk 0'.\n\n"
1218 "See 'man xsnow' or 'xsnow -h' to see the command line options.\n"
1219 "Alternatively, you could edit ~/.xsnowrc to set options.\n",
1220 ui_gtk_version(),ui_gtk_required());
1221 label = gtk_label_new(sbuffer);
1222
1223 /* Place the label in cell (0,0) and make it fill 2 cells horizontally */
1224
1225 gtk_grid_attach(GTK_GRID(grid),label,0,0,2,1);
1226 button = gtk_button_new_with_label ("Run without user interface");
1227 g_signal_connect(button,"clicked",G_CALLBACK(yesyes),window);
1228
1229 /* Place the first button in the grid cell (0, 1), and make it fill
1230 * just 1 cell horizontally and vertically (ie no spanning)
1231 */
1232 gtk_grid_attach (GTK_GRID (grid), button, 0, 1, 1, 1);
1233
1234 button = gtk_button_new_with_label ("Quit");
1235 g_signal_connect(button, "clicked", G_CALLBACK (nono), window);
1236
1237 /* Place the second button in the grid cell (1, 1), and make it fill
1238 * just 1 cell horizontally and vertically (ie no spanning)
1239 */
1240 gtk_grid_attach (GTK_GRID (grid), button, 1, 1, 1, 1);
1241
1242 /* Now that we are done packing our widgets, we show them all
1243 * in one go, by calling gtk_widget_show_all() on the window.
1244 * This call recursively calls gtk_widget_show() on all widgets
1245 * that are contained in the window, directly or indirectly.
1246 */
1247 gtk_widget_show_all (window);
1248 }
1249
yesyes(GtkWidget * w,gpointer window)1250 void yesyes(GtkWidget *w, gpointer window)
1251 {
1252 RC = (w != NULL);
1253 gtk_widget_destroy(GTK_WIDGET(window));
1254 }
1255
nono(GtkWidget * w,gpointer window)1256 void nono(GtkWidget *w, gpointer window)
1257 {
1258 RC = (w == NULL);
1259 gtk_widget_destroy(GTK_WIDGET(window));
1260 }
1261
1262 // next function is not used, I leave it here as a template, who knows...
1263 // see also ui.xml
ui_error_x11()1264 void ui_error_x11()
1265 {
1266 GtkWidget *errorfenster;
1267 GObject *button;
1268 builder = gtk_builder_new_from_string (xsnow_xml, -1);
1269 gtk_builder_connect_signals (builder, builder);
1270 errorfenster = GTK_WIDGET(gtk_builder_get_object (builder, "error_x11_fenster"));
1271 button = gtk_builder_get_object(builder,"error_x11_ok_button");
1272 g_signal_connect (button,"clicked",G_CALLBACK(gtk_main_quit),NULL);
1273
1274 GtkImage *image;
1275 GdkPixbuf *pixbuf;
1276 pixbuf = gdk_pixbuf_new_from_xpm_data ((const char **)xsnow_logo);
1277 image = GTK_IMAGE(gtk_builder_get_object(builder,"error-x11-image1"));
1278 gtk_image_set_from_pixbuf(image,pixbuf);
1279 image = GTK_IMAGE(gtk_builder_get_object(builder,"error-x11-image2"));
1280 gtk_image_set_from_pixbuf(image,pixbuf);
1281 g_object_unref(pixbuf);
1282
1283 gtk_widget_show_all (errorfenster);
1284 gtk_main();
1285 }
1286
my_gtk_label_set_text(GtkLabel * label,const gchar * str)1287 void my_gtk_label_set_text(GtkLabel *label, const gchar *str)
1288 {
1289 if(ui_running)
1290 gtk_label_set_text(label, str);
1291 }
1292