1
2 /* jlh */
3
4 /*
5 this file is part of: wmblob
6
7 the GNU GPL license applies to this file, see file COPYING for details.
8 author: jean-luc herren.
9 */
10
11 #include <stdio.h>
12 #include <gtk/gtk.h>
13 #include <glib.h>
14 #include <sys/utsname.h>
15 #include <string.h>
16 #include <stdlib.h>
17
18 #include "config.h"
19 #include "wmblob.h"
20 #include "rcfile.h"
21
22 static int gtk_failed = 0; /* non-zero if gtk has failed initialization */
23 static SETTINGS new_settings;
24 static int exit_dialog;
25
26 /* pointer to important widgets */
27
28 static GtkWidget *dialog_window;
29
30 static GtkWidget *wg_color[3];
31
32 static GtkWidget *wg_n_blobs;
33 static GtkWidget *wg_multiplication;
34 static GtkWidget *wg_gravity;
35
36 static GtkWidget *wg_blob_size;
37 static GtkWidget *wg_blob_falloff;
38 static GtkWidget *wg_blob_presence;
39
40 static GtkWidget *wg_border_size;
41 static GtkWidget *wg_border_falloff;
42 static GtkWidget *wg_border_presence;
43
44 static GtkWidget *wg_preset_list;
45
46 static GtkWidget *color_dialog;
47
48 /* all prototypes */
49
50 static void set_from_settings(SETTINGS *);
51 static gboolean callback_expose(GtkWidget *, GdkEventExpose *, gpointer);
52 static gboolean callback_close(GtkWidget *, gpointer);
53 static gboolean callback_exit(GtkWidget *, gpointer);
54 static gboolean callback_preset_load(GtkWidget *, gpointer);
55 static gboolean callback_preset_save(GtkWidget *, gpointer);
56 static gboolean callback_preset_delete(GtkWidget *, gpointer);
57 static gboolean callback_about(GtkWidget *, gpointer);
58 static void callback_color_clicked(GtkWidget *, gpointer);
59 static void callback_color_okay(GtkWidget *, gpointer);
60 static void callback_color_cancel(GtkWidget *, gpointer);
61 static GtkWidget *create_color_button(int);
62 static GtkWidget *hbox_with_label(GtkWidget *, const char *);
63 static GtkWidget *new_frame(GtkWidget *, const char *);
64 static GtkWidget *vbox_spin_button(GtkWidget *, const char *, int, int);
65 static GtkWidget *create_dialog_left();
66 static void fill_in_presets(GtkWidget *);
67 static GtkWidget *create_dialog_right();
68 static GtkWidget *create_dialog();
69
70
71 /* set dialog state from the given settings */
72
set_from_settings(SETTINGS * settings)73 static void set_from_settings(SETTINGS *settings)
74 {
75 GdkColor col;
76 int i;
77
78 new_settings = *settings;
79 gtk_spin_button_set_value(GTK_SPIN_BUTTON(wg_n_blobs),
80 settings->n_blobs);
81 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(wg_gravity),
82 settings->gravity);
83
84 gtk_spin_button_set_value(GTK_SPIN_BUTTON(wg_blob_size),
85 settings->blob_size);
86 gtk_spin_button_set_value(GTK_SPIN_BUTTON(wg_blob_falloff),
87 settings->blob_falloff);
88 gtk_spin_button_set_value(GTK_SPIN_BUTTON(wg_blob_presence),
89 settings->blob_presence);
90
91 gtk_spin_button_set_value(GTK_SPIN_BUTTON(wg_border_size),
92 settings->border_size);
93 gtk_spin_button_set_value(GTK_SPIN_BUTTON(wg_border_falloff),
94 settings->border_falloff);
95 gtk_spin_button_set_value(GTK_SPIN_BUTTON(wg_border_presence),
96 settings->border_presence);
97
98 gtk_spin_button_set_value(GTK_SPIN_BUTTON(wg_multiplication),
99 settings->multiplication);
100
101 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(wg_preset_list)->entry), "");
102
103 for (i = 0; i < 3; i++)
104 {
105 col.red = settings->color[i].r * 256;
106 col.green = settings->color[i].g * 256;
107 col.blue = settings->color[i].b * 256;
108
109 gtk_widget_modify_bg(
110 gtk_bin_get_child(GTK_BIN(wg_color[i])),
111 GTK_STATE_NORMAL, &col);
112 }
113 }
114
115
116 /* draw the area in the colored buttons */
117
callback_expose(GtkWidget * widget,GdkEventExpose * event,gpointer data)118 static gboolean callback_expose(GtkWidget *widget, GdkEventExpose *event,
119 gpointer data)
120 {
121 GtkStyle *style;
122
123 style = gtk_widget_get_style (widget);
124
125 gdk_draw_rectangle(widget->window,
126 style->bg_gc[GTK_STATE_NORMAL],
127 TRUE,
128 event->area.x, event->area.y,
129 event->area.width, event->area.height);
130
131 return(TRUE);
132 }
133
134
135 /* handler for the close button */
136
callback_close(GtkWidget * widget,gpointer data)137 static gboolean callback_close(GtkWidget *widget, gpointer data)
138 {
139 exit_dialog = 1;
140 return(TRUE);
141 }
142
143
144 /* handler for the exit button */
145
callback_exit(GtkWidget * widget,gpointer data)146 static gboolean callback_exit(GtkWidget *widget, gpointer data)
147 {
148 exit_dialog = 1;
149 exit_wmblob = 1;
150 return(TRUE);
151 }
152
153
154 /* handler for the load preset button */
155
callback_preset_load(GtkWidget * widget,gpointer data)156 static gboolean callback_preset_load(GtkWidget *widget, gpointer data)
157 {
158 SETTINGS set;
159 const char *p;
160
161 p = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(wg_preset_list)->entry));
162
163 if (preset_load(p, &set))
164 set_from_settings(&set);
165 p = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(wg_preset_list)->entry));
166
167 return(TRUE);
168 }
169
170
171 /* handler for the save preset button */
172
callback_preset_save(GtkWidget * widget,gpointer data)173 static gboolean callback_preset_save(GtkWidget *widget, gpointer data)
174 {
175 const char *p;
176 char *tmp;
177
178 p = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(wg_preset_list)->entry));
179 if (!*p) return(TRUE);
180
181 /* no comma! */
182 if (strchr(p, ',')) return(TRUE);
183
184 tmp = strdup(p);
185
186 preset_save(tmp, &new_settings);
187 fill_in_presets(GTK_WIDGET(wg_preset_list));
188
189 gtk_entry_set_text(GTK_ENTRY(GTK_COMBO(wg_preset_list)->entry), tmp);
190 free(tmp);
191
192 return(TRUE);
193 }
194
195
196 /* handler for the delete preset button */
197
callback_preset_delete(GtkWidget * widget,gpointer data)198 static gboolean callback_preset_delete(GtkWidget *widget, gpointer data)
199 {
200 const char *p;
201
202 p = gtk_entry_get_text(GTK_ENTRY(GTK_COMBO(wg_preset_list)->entry));
203 preset_delete(p);
204
205 fill_in_presets(GTK_WIDGET(wg_preset_list));
206
207 return(TRUE);
208 }
209
210
211 /* handler for the about button */
212
callback_about(GtkWidget * widget,gpointer data)213 static gboolean callback_about(GtkWidget *widget, gpointer data)
214 {
215 char buf[256];
216 struct utsname system;
217 GtkWidget *dialog;
218 char *add;
219
220 uname(&system);
221
222 if (strcmp(system.sysname, "Linux") == 0 ||
223 strcmp(system.sysname, "linux") == 0)
224 add = ", this is GOOD.";
225 else
226 add = "";
227
228 sprintf(buf,
229 "This is " PACKAGE_STRING "\n"
230 "coded by jlh (aka jean-luc herren)\n\n"
231 "You're running %s%s", system.sysname, add);
232
233 dialog = gtk_message_dialog_new(GTK_WINDOW(dialog_window),
234 GTK_DIALOG_DESTROY_WITH_PARENT,
235 GTK_MESSAGE_INFO,
236 GTK_BUTTONS_CLOSE,
237 buf);
238
239 g_signal_connect_swapped(GTK_OBJECT(dialog), "response",
240 G_CALLBACK(gtk_widget_destroy),
241 GTK_OBJECT(dialog));
242
243 gtk_window_set_transient_for(GTK_WINDOW(dialog),
244 GTK_WINDOW(dialog_window));
245 gtk_window_set_modal(GTK_WINDOW(dialog), TRUE);
246 gtk_widget_show_all(dialog);
247
248 return(TRUE);
249 }
250
251
252 /* handler for the apply button */
253
callback_apply(GtkWidget * widget,gpointer data)254 static gboolean callback_apply(GtkWidget *widget, gpointer data)
255 {
256 new_settings.gravity = gtk_toggle_button_get_active(
257 GTK_TOGGLE_BUTTON(wg_gravity));
258 new_settings.n_blobs = gtk_spin_button_get_value_as_int(
259 GTK_SPIN_BUTTON(wg_n_blobs));
260
261 new_settings.blob_size = gtk_spin_button_get_value_as_int(
262 GTK_SPIN_BUTTON(wg_blob_size));
263 new_settings.blob_falloff = gtk_spin_button_get_value_as_int(
264 GTK_SPIN_BUTTON(wg_blob_falloff));
265 new_settings.blob_presence = gtk_spin_button_get_value_as_int(
266 GTK_SPIN_BUTTON(wg_blob_presence));
267
268 new_settings.border_size = gtk_spin_button_get_value_as_int(
269 GTK_SPIN_BUTTON(wg_border_size));
270 new_settings.border_falloff = gtk_spin_button_get_value_as_int(
271 GTK_SPIN_BUTTON(wg_border_falloff));
272 new_settings.border_presence = gtk_spin_button_get_value_as_int(
273 GTK_SPIN_BUTTON(wg_border_presence));
274
275 new_settings.multiplication = gtk_spin_button_get_value_as_int(
276 GTK_SPIN_BUTTON(wg_multiplication));
277
278 /* the color informations are already in new_settings */
279
280 apply_settings(&new_settings);
281 settings_save();
282
283 return(TRUE);
284 }
285
286
287 /* handler for the three colored buttons. open a color selection dialog */
288
callback_color_clicked(GtkWidget * widget,gpointer data)289 static void callback_color_clicked(GtkWidget *widget, gpointer data)
290 {
291 GtkWidget *button;
292 GtkColorSelection *colorsel;
293 GdkColor col;
294 int i;
295
296 i = GPOINTER_TO_INT(data);
297
298 col.red = new_settings.color[i].r * 256;
299 col.green = new_settings.color[i].g * 256;
300 col.blue = new_settings.color[i].b * 256;
301
302 color_dialog = gtk_color_selection_dialog_new("Changing color");
303
304 colorsel = GTK_COLOR_SELECTION(
305 GTK_COLOR_SELECTION_DIALOG(color_dialog)->colorsel);
306
307 /* set up the okay button */
308 button = GTK_COLOR_SELECTION_DIALOG(color_dialog)->ok_button;
309 g_signal_connect(G_OBJECT(button), "clicked",
310 G_CALLBACK(callback_color_okay), data);
311
312 /* set up the cancel button */
313 button = GTK_COLOR_SELECTION_DIALOG(color_dialog)->cancel_button;
314 g_signal_connect(G_OBJECT(button), "clicked",
315 G_CALLBACK(callback_color_cancel), data);
316
317 /* remove the help button */
318 button = GTK_COLOR_SELECTION_DIALOG(color_dialog)->help_button;
319 gtk_widget_destroy(button);
320
321 gtk_color_selection_set_previous_color(colorsel, &col);
322 gtk_color_selection_set_current_color(colorsel, &col);
323 gtk_color_selection_set_has_palette(colorsel, TRUE);
324
325 gtk_window_set_transient_for(GTK_WINDOW(color_dialog),
326 GTK_WINDOW(dialog_window));
327 gtk_window_set_modal(GTK_WINDOW(color_dialog), TRUE);
328 gtk_widget_show_all(color_dialog);
329 }
330
331
332 /* handler for the okay button of the color section dialog */
333
callback_color_okay(GtkWidget * dialog,gpointer data)334 static void callback_color_okay(GtkWidget *dialog, gpointer data)
335 {
336 GtkColorSelection *colorsel;
337 GdkColor col;
338 int i;
339
340 i = GPOINTER_TO_INT(data);
341 colorsel = GTK_COLOR_SELECTION(
342 GTK_COLOR_SELECTION_DIALOG(color_dialog)->colorsel);
343
344 gtk_color_selection_get_current_color(colorsel, &col);
345 gtk_widget_modify_bg(gtk_bin_get_child(GTK_BIN(wg_color[i])),
346 GTK_STATE_NORMAL, &col);
347
348 new_settings.color[i].r = col.red / 256;
349 new_settings.color[i].g = col.green / 256;
350 new_settings.color[i].b = col.blue / 256;
351
352 gtk_widget_destroy(color_dialog);
353 }
354
355
356 /* handler for the cancel button of the color section dialog */
357
callback_color_cancel(GtkWidget * dialog,gpointer data)358 static void callback_color_cancel(GtkWidget *dialog, gpointer data)
359 {
360 gtk_widget_destroy(color_dialog);
361 }
362
363
364 /* create a button with a color area in it */
365
create_color_button(int i)366 static GtkWidget *create_color_button(int i)
367 {
368 GtkWidget *button;
369 GtkWidget *area;
370
371 button = gtk_button_new();
372 area = gtk_drawing_area_new();
373
374 g_signal_connect(G_OBJECT(button), "clicked",
375 G_CALLBACK(callback_color_clicked), GINT_TO_POINTER(i));
376 g_signal_connect(G_OBJECT(area), "expose_event",
377 G_CALLBACK(callback_expose), NULL);
378
379 gtk_widget_set_size_request(area, 24, 16);
380 gtk_container_add(GTK_CONTAINER(button), area);
381
382 return(button);
383 }
384
385
386 /* return a hbox containing a label and the given widget */
387
hbox_with_label(GtkWidget * widget,const char * name)388 static GtkWidget *hbox_with_label(GtkWidget *widget, const char *name)
389 {
390 GtkWidget *hbox;
391 GtkWidget *label;
392
393 hbox = gtk_hbox_new(FALSE, 5);
394
395 label = gtk_label_new(name);
396 gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0);
397 gtk_box_pack_end(GTK_BOX(hbox), widget, FALSE, FALSE, 0);
398
399 return(hbox);
400 }
401
402
403 /* add a frame to parent and put a vbox in it (returned) */
404
new_frame(GtkWidget * parent,const char * name)405 static GtkWidget *new_frame(GtkWidget *parent, const char *name)
406 {
407 GtkWidget *frame, *vbox;
408
409 frame = gtk_frame_new(name);
410 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_ETCHED_IN);
411 gtk_box_pack_start(GTK_BOX(parent), frame, FALSE, FALSE, 0);
412
413 vbox = gtk_vbox_new(FALSE, 5);
414 gtk_container_add(GTK_CONTAINER(frame), vbox);
415 gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
416
417 return(vbox);
418 }
419
420
421 /* create a spin button with a label and append it to the given vbox.
422 return the spin button */
423
vbox_spin_button(GtkWidget * vbox,const char * name,int min,int max)424 static GtkWidget *vbox_spin_button(GtkWidget *vbox, const char *name,
425 int min, int max)
426 {
427 GtkWidget *spin, *box;
428
429 spin = gtk_spin_button_new_with_range(min, max, 1);
430 box = hbox_with_label(spin, name);
431 gtk_box_pack_start(GTK_BOX(vbox), box, FALSE, FALSE, 0);
432
433 return(spin);
434 }
435
436
437 /* create and return a vbox containing the left half of the dialog */
438
create_dialog_left()439 static GtkWidget *create_dialog_left()
440 {
441 GtkWidget *left, *vbox;
442 GtkWidget *widget;
443 GtkWidget *table;
444
445 left = gtk_vbox_new(FALSE, 5);
446
447 vbox = new_frame(left, "Global");
448
449 /* spin button for number of blobs */
450
451 wg_n_blobs = vbox_spin_button(vbox, "Blob count:", 1, MAX_N_BLOBS);
452
453 /* check boxes */
454
455 wg_multiplication = vbox_spin_button(vbox, "Overlay Effect:", 0, 127);
456
457 wg_gravity = gtk_check_button_new_with_mnemonic("_Gravity");
458 gtk_box_pack_start(GTK_BOX(vbox), wg_gravity, TRUE, TRUE, 0);
459
460 /* color buttons */
461
462 vbox = new_frame(left, "Colors");
463
464 table = gtk_table_new(2, 3, FALSE);
465 gtk_box_pack_start(GTK_BOX(vbox), table, FALSE, FALSE, 0);
466
467 widget = gtk_label_new("Center:");
468 gtk_misc_set_alignment (GTK_MISC(widget), 0, 1);
469 gtk_table_attach(GTK_TABLE(table), widget, 0, 1, 0, 1,
470 GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 0);
471 wg_color[0] = create_color_button(0);
472 gtk_table_attach_defaults(GTK_TABLE(table), wg_color[0], 1, 2, 0, 1);
473
474 widget = gtk_label_new("Glow:");
475 gtk_misc_set_alignment (GTK_MISC(widget), 0, 1);
476 gtk_table_attach(GTK_TABLE(table), widget, 0, 1, 1, 2,
477 GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 0);
478 wg_color[1] = create_color_button(1);
479 gtk_table_attach_defaults(GTK_TABLE(table), wg_color[1], 1, 2, 1, 2);
480
481 widget = gtk_label_new("Background:");
482 gtk_misc_set_alignment (GTK_MISC(widget), 0, 1);
483 gtk_table_attach(GTK_TABLE(table), widget, 0, 1, 2, 3,
484 GTK_EXPAND | GTK_FILL, GTK_EXPAND, 0, 0);
485 wg_color[2] = create_color_button(2);
486 gtk_table_attach_defaults(GTK_TABLE(table), wg_color[2], 1, 2, 2, 3);
487
488 /* blob style */
489
490 vbox = new_frame(left, "Blob style");
491
492 wg_blob_size = vbox_spin_button(vbox, "Size:", 0, 220);
493 wg_blob_falloff = vbox_spin_button(vbox, "Falloff:", 0, 255);
494 wg_blob_presence = vbox_spin_button(vbox, "Presence:", 0, 255);
495
496 /* border style */
497
498 vbox = new_frame(left, "Border style");
499
500 wg_border_size = vbox_spin_button(vbox, "Size:", 0, 127);
501 wg_border_falloff = vbox_spin_button(vbox, "Falloff:", 0, 255);
502 wg_border_presence = vbox_spin_button(vbox, "Presence:", 0, 255);
503
504 return(left);
505 }
506
507
508 /* fill the given combo widget with the preset list */
509
fill_in_presets(GtkWidget * combo)510 static void fill_in_presets(GtkWidget *combo)
511 {
512 GList *items;
513 GList *preset;
514
515 preset = preset_list;
516 items = NULL;
517
518 while (preset)
519 {
520 items = g_list_append(items, preset->data);
521 preset = g_list_next(preset);
522 }
523
524 if (!items)
525 items = g_list_append(items, "");
526
527 /* sort via strcmp() */
528 items = g_list_sort_with_data(items, (GCompareDataFunc)strcmp, NULL);
529
530 gtk_combo_set_popdown_strings(GTK_COMBO(combo), items);
531
532 g_list_free(items);
533 }
534
535
536 /* create and return a vbox containing the right half of the dialog */
537
create_dialog_right()538 static GtkWidget *create_dialog_right()
539 {
540 GtkWidget *right;
541 GtkWidget *widget;
542 GtkWidget *vbox;
543
544 right = gtk_vbox_new(FALSE, 10);
545
546 /* save, apply, close, exit */
547
548 widget = gtk_button_new_with_mnemonic("_Apply");
549 g_signal_connect(G_OBJECT(widget), "clicked",
550 G_CALLBACK(callback_apply), NULL);
551 gtk_box_pack_start(GTK_BOX(right), widget, FALSE, FALSE, 0);
552
553
554 widget = gtk_button_new_with_mnemonic("_Close dialog");
555 g_signal_connect(G_OBJECT(widget), "clicked",
556 G_CALLBACK(callback_close), NULL);
557 gtk_box_pack_start(GTK_BOX(right), widget, FALSE, FALSE, 0);
558
559 widget = gtk_button_new_with_mnemonic("E_xit wmblob");
560 g_signal_connect(G_OBJECT(widget), "clicked",
561 G_CALLBACK(callback_exit), NULL);
562 gtk_box_pack_start(GTK_BOX(right), widget, FALSE, FALSE, 0);
563
564 widget = gtk_button_new_with_mnemonic("A_bout...");
565 g_signal_connect(G_OBJECT(widget), "clicked",
566 G_CALLBACK(callback_about), NULL);
567 gtk_box_pack_start(GTK_BOX(right), widget, FALSE, FALSE, 0);
568
569 /* preset stuff */
570
571 vbox = new_frame(right, "Presets");
572
573 widget = gtk_button_new_with_mnemonic("_Load");
574 g_signal_connect(G_OBJECT(widget), "clicked",
575 G_CALLBACK(callback_preset_load), NULL);
576 gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
577
578 widget = gtk_button_new_with_mnemonic("_Save");
579 g_signal_connect(G_OBJECT(widget), "clicked",
580 G_CALLBACK(callback_preset_save), NULL);
581 gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
582
583 widget = gtk_button_new_with_mnemonic("_Delete");
584 g_signal_connect(G_OBJECT(widget), "clicked",
585 G_CALLBACK(callback_preset_delete), NULL);
586 gtk_box_pack_start(GTK_BOX(vbox), widget, FALSE, FALSE, 0);
587
588 wg_preset_list = gtk_combo_new();
589 fill_in_presets(wg_preset_list);
590 gtk_widget_set_size_request(wg_preset_list, 128, 20);
591 gtk_box_pack_start(GTK_BOX(vbox), wg_preset_list, FALSE, FALSE, 0);
592
593 return(right);
594 }
595
596
597 /* create and return the complete dialog */
598
create_dialog()599 static GtkWidget *create_dialog()
600 {
601 GtkWidget *dialog, *hbox;
602 GtkWidget *left, *right;
603
604 /* create main window */
605
606 dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
607 gtk_window_set_title(GTK_WINDOW(dialog), "wmblob settings");
608 gtk_container_set_border_width(GTK_CONTAINER(dialog), 8);
609 g_signal_connect(G_OBJECT(dialog), "delete-event",
610 G_CALLBACK(callback_close), NULL);
611
612 /* box structure */
613
614 left = create_dialog_left();
615 right = create_dialog_right();
616
617 hbox = gtk_hbox_new(FALSE, 10);
618 gtk_container_add(GTK_CONTAINER(hbox), left);
619 gtk_container_add(GTK_CONTAINER(hbox), right);
620 gtk_container_add(GTK_CONTAINER(dialog), hbox);
621
622 gtk_widget_show_all(dialog);
623
624 return(dialog);
625 }
626
627
628 /* do initializations for this file */
629
init_dialog_c(int * argc,char *** argv)630 int init_dialog_c(int *argc, char ***argv)
631 {
632 if (!gtk_init_check(argc, argv))
633 {
634 printf("wmblob: gtk_init() has failed, "
635 "no settings dialog available\n");
636 gtk_failed = 1;
637 return(0);
638 }
639
640 return(1);
641 }
642
643
644 /* open the dialog */
645
dialog_open()646 int dialog_open()
647 {
648 if (gtk_failed) return(0);
649
650 dialog_window = create_dialog();
651 exit_dialog = 0;
652
653 set_from_settings(¤t_settings);
654
655 return(1);
656 }
657
658
659 /* handle pending events for the dialog */
660
dialog_loop()661 int dialog_loop()
662 {
663 if (gtk_failed) return(0);
664
665 while (gtk_events_pending())
666 gtk_main_iteration();
667
668 if (exit_dialog)
669 {
670 gtk_widget_destroy(dialog_window);
671
672 while (gtk_events_pending())
673 gtk_main_iteration();
674
675 return(0);
676 }
677
678 return(1);
679 }
680
681