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