1 /* demo-Gtk.c --- implements the interactive demo-mode and options dialogs.
2 * xscreensaver, Copyright (c) 1993-1999 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
17 #ifdef HAVE_GTK /* whole file */
26 # include <pwd.h> /* for getpwuid() */
32 # include <sys/utsname.h> /* for uname() */
33 #endif /* HAVE_UNAME */
37 #include <X11/Xproto.h> /* for CARD32 */
38 #include <X11/Xatom.h> /* for XA_INTEGER */
39 #include <X11/Intrinsic.h>
40 #include <X11/StringDefs.h>
42 /* We don't actually use any widget internals, but these are included
43 so that gdb will have debug info for the widgets... */
44 #include <X11/IntrinsicP.h>
45 #include <X11/ShellP.h>
49 # include <X11/Xmu/Error.h>
51 # include <Xmu/Error.h>
61 # include <capplet-widget.h>
64 extern Display *gdk_display;
68 #include "resources.h" /* for parse_time() */
69 #include "visual.h" /* for has_writable_cells() */
70 #include "remote.h" /* for xscreensaver_command() */
73 #include "demo-Gtk-widgets.h"
80 #define countof(x) (sizeof((x))/sizeof((*x)))
84 char *progclass = "XScreenSaver";
87 static Bool crapplet_p = False;
88 static Bool initializing_p;
89 static GtkWidget *toplevel_widget;
92 saver_preferences *a, *b;
95 static void *global_prefs_pair; /* I hate C so much... */
97 char *blurb (void) { return progname; }
99 static char *short_version = 0;
102 Atom XA_SCREENSAVER, XA_SCREENSAVER_RESPONSE, XA_SCREENSAVER_VERSION;
103 Atom XA_SCREENSAVER_ID, XA_SCREENSAVER_STATUS, XA_SELECT, XA_DEMO;
104 Atom XA_ACTIVATE, XA_BLANK, XA_LOCK, XA_RESTART, XA_EXIT;
107 static void populate_demo_window (GtkWidget *toplevel,
108 int which, prefs_pair *pair);
109 static void populate_prefs_page (GtkWidget *top, prefs_pair *pair);
110 static int apply_changes_and_save (GtkWidget *widget);
111 static int maybe_reload_init_file (GtkWidget *widget, prefs_pair *pair);
114 /* Some random utility functions
118 name_to_widget (GtkWidget *widget, const char *name)
120 return (GtkWidget *) gtk_object_get_data (GTK_OBJECT(toplevel_widget), name);
124 /* Why this behavior isn't automatic in *either* toolkit, I'll never know.
125 Takes a scroller, viewport, or list as an argument.
128 ensure_selected_item_visible (GtkWidget *widget)
130 GtkScrolledWindow *scroller = 0;
132 GtkList *list_widget = 0;
136 GtkWidget *selected = 0;
139 gint parent_h, child_y, child_h, children_h, ignore;
140 double ratio_t, ratio_b;
142 if (GTK_IS_SCROLLED_WINDOW (widget))
144 scroller = GTK_SCROLLED_WINDOW (widget);
145 vp = GTK_VIEWPORT (GTK_BIN (scroller)->child);
146 list_widget = GTK_LIST (GTK_BIN(vp)->child);
148 else if (GTK_IS_VIEWPORT (widget))
150 vp = GTK_VIEWPORT (widget);
151 scroller = GTK_SCROLLED_WINDOW (GTK_WIDGET (vp)->parent);
152 list_widget = GTK_LIST (GTK_BIN(vp)->child);
154 else if (GTK_IS_LIST (widget))
156 list_widget = GTK_LIST (widget);
157 vp = GTK_VIEWPORT (GTK_WIDGET (list_widget)->parent);
158 scroller = GTK_SCROLLED_WINDOW (GTK_WIDGET (vp)->parent);
163 slist = list_widget->selection;
164 selected = (slist ? GTK_WIDGET (slist->data) : 0);
168 which = gtk_list_child_position (list_widget, GTK_WIDGET (selected));
170 for (kids = gtk_container_children (GTK_CONTAINER (list_widget));
171 kids; kids = kids->next)
174 adj = gtk_scrolled_window_get_vadjustment (scroller);
176 gdk_window_get_geometry (GTK_WIDGET(vp)->window,
177 &ignore, &ignore, &ignore, &parent_h, &ignore);
178 gdk_window_get_geometry (GTK_WIDGET(selected)->window,
179 &ignore, &child_y, &ignore, &child_h, &ignore);
180 children_h = nkids * child_h;
182 ratio_t = ((double) child_y) / ((double) children_h);
183 ratio_b = ((double) child_y + child_h) / ((double) children_h);
185 if (adj->upper == 0.0) /* no items in list */
188 if (ratio_t < (adj->value / adj->upper) ||
189 ratio_b > ((adj->value + adj->page_size) / adj->upper))
192 int slop = parent_h * 0.75; /* how much to overshoot by */
194 if (ratio_t < (adj->value / adj->upper))
196 double ratio_w = ((double) parent_h) / ((double) children_h);
197 double ratio_l = (ratio_b - ratio_t);
198 target = ((ratio_t - ratio_w + ratio_l) * adj->upper);
201 else /* if (ratio_b > ((adj->value + adj->page_size) / adj->upper))*/
203 target = ratio_t * adj->upper;
207 if (target > adj->upper - adj->page_size)
208 target = adj->upper - adj->page_size;
212 gtk_adjustment_set_value (adj, target);
217 warning_dialog_dismiss_cb (GtkWidget *widget, gpointer user_data)
219 GtkWidget *shell = GTK_WIDGET (user_data);
220 while (shell->parent)
221 shell = shell->parent;
222 gtk_widget_destroy (GTK_WIDGET (shell));
226 void restart_menu_cb (GtkWidget *widget, gpointer user_data);
228 static void warning_dialog_restart_cb (GtkWidget *widget, gpointer user_data)
230 restart_menu_cb (widget, user_data);
231 warning_dialog_dismiss_cb (widget, user_data);
235 warning_dialog (GtkWidget *parent, const char *message,
236 Boolean restart_button_p, int center)
238 char *msg = strdup (message);
241 GtkWidget *dialog = gtk_dialog_new ();
242 GtkWidget *label = 0;
244 GtkWidget *cancel = 0;
247 while (parent->parent)
248 parent = parent->parent;
254 char *s = strchr (head, '\n');
257 sprintf (name, "label%d", i++);
261 label = gtk_label_new (head);
262 sprintf (buf, "warning_dialog.%s.font", name);
263 GTK_WIDGET (label)->style = gtk_style_copy (GTK_WIDGET (label)->style);
264 GTK_WIDGET (label)->style->font =
265 gdk_font_load (get_string_resource (buf, "Dialog.Label.Font"));
267 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
268 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
269 label, TRUE, TRUE, 0);
270 gtk_widget_show (label);
281 label = gtk_label_new ("");
282 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
283 label, TRUE, TRUE, 0);
284 gtk_widget_show (label);
286 label = gtk_hbutton_box_new ();
287 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
288 label, TRUE, TRUE, 0);
290 ok = gtk_button_new_with_label ("OK");
291 gtk_container_add (GTK_CONTAINER (label), ok);
293 if (restart_button_p)
295 cancel = gtk_button_new_with_label ("Cancel");
296 gtk_container_add (GTK_CONTAINER (label), cancel);
299 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
300 gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
301 gtk_window_set_title (GTK_WINDOW (dialog), progclass);
302 gtk_widget_show (ok);
304 gtk_widget_show (cancel);
305 gtk_widget_show (label);
306 gtk_widget_show (dialog);
307 /* gtk_window_set_default (GTK_WINDOW (dialog), ok);*/
309 if (restart_button_p)
311 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
312 GTK_SIGNAL_FUNC (warning_dialog_restart_cb),
314 gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked",
315 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
320 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
321 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
324 gdk_window_set_transient_for (GTK_WIDGET (dialog)->window,
325 GTK_WIDGET (parent)->window);
327 gdk_window_show (GTK_WIDGET (dialog)->window);
328 gdk_window_raise (GTK_WIDGET (dialog)->window);
335 run_cmd (GtkWidget *widget, Atom command, int arg)
340 apply_changes_and_save (widget);
341 status = xscreensaver_command (gdk_display, command, arg, False, &err);
346 sprintf (buf, "Error:\n\n%s", err);
348 strcpy (buf, "Unknown error!");
349 warning_dialog (widget, buf, False, 100);
356 run_hack (GtkWidget *widget, int which, Bool report_errors_p)
358 if (which < 0) return;
359 apply_changes_and_save (widget);
361 run_cmd (widget, XA_DEMO, which + 1);
365 xscreensaver_command (gdk_display, XA_DEMO, which + 1, False, &s);
376 exit_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
378 apply_changes_and_save (GTK_WIDGET (menuitem));
383 wm_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
385 apply_changes_and_save (widget);
391 cut_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
394 warning_dialog (GTK_WIDGET (menuitem),
396 "cut unimplemented\n", False, 1);
401 copy_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
404 warning_dialog (GTK_WIDGET (menuitem),
406 "copy unimplemented\n", False, 1);
411 paste_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
414 warning_dialog (GTK_WIDGET (menuitem),
416 "paste unimplemented\n", False, 1);
421 about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
424 char *s = strdup (screensaver_id + 4);
427 s2 = strchr (s, ',');
431 sprintf (buf, "%s\n%s\n\n"
432 "For updates, check http://www.jwz.org/xscreensaver/",
436 warning_dialog (GTK_WIDGET (menuitem), buf, False, 100);
441 doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
443 /* prefs_pair *pair = (prefs_pair *) client_data; */
444 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
446 saver_preferences *p = pair->a;
449 if (!p->help_url || !*p->help_url)
451 warning_dialog (GTK_WIDGET (menuitem),
453 "No Help URL has been specified.\n", False, 100);
457 help_command = (char *) malloc (strlen (p->load_url_command) +
458 (strlen (p->help_url) * 2) + 20);
459 strcpy (help_command, "( ");
460 sprintf (help_command + strlen(help_command),
461 p->load_url_command, p->help_url, p->help_url);
462 strcat (help_command, " ) &");
463 system (help_command);
469 activate_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
471 run_cmd (GTK_WIDGET (menuitem), XA_ACTIVATE, 0);
476 lock_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
478 run_cmd (GTK_WIDGET (menuitem), XA_LOCK, 0);
483 kill_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
485 run_cmd (GTK_WIDGET (menuitem), XA_EXIT, 0);
490 restart_menu_cb (GtkWidget *widget, gpointer user_data)
493 run_cmd (GTK_WIDGET (widget), XA_RESTART, 0);
495 apply_changes_and_save (GTK_WIDGET (widget));
496 xscreensaver_command (gdk_display, XA_EXIT, 0, False, NULL);
498 system ("xscreensaver -nosplash &");
503 static int _selected_hack_number = -1;
506 selected_hack_number (GtkWidget *toplevel)
509 GtkViewport *vp = GTK_VIEWPORT (name_to_widget (toplevel, "viewport"));
510 GtkList *list_widget = GTK_LIST (GTK_BIN(vp)->child);
511 GList *slist = list_widget->selection;
512 GtkWidget *selected = (slist ? GTK_WIDGET (slist->data) : 0);
513 int which = (selected
514 ? gtk_list_child_position (list_widget, GTK_WIDGET (selected))
518 return _selected_hack_number;
524 demo_write_init_file (GtkWidget *widget, saver_preferences *p)
526 if (!write_init_file (p, short_version, False))
530 const char *f = init_file_name();
532 warning_dialog (widget,
533 "Error:\n\nCouldn't determine init file name!\n",
537 char *b = (char *) malloc (strlen(f) + 1024);
538 sprintf (b, "Error:\n\nCouldn't write %s\n", f);
539 warning_dialog (widget, b, False, 100);
548 apply_changes_and_save_1 (GtkWidget *widget)
550 /* prefs_pair *pair = (prefs_pair *) client_data; */
551 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
552 saver_preferences *p = pair->a;
553 GtkList *list_widget =
554 GTK_LIST (name_to_widget (widget, "list"));
555 int which = selected_hack_number (widget);
557 GtkEntry *cmd = GTK_ENTRY (name_to_widget (widget, "cmd_text"));
558 GtkToggleButton *enabled =
559 GTK_TOGGLE_BUTTON (name_to_widget (widget, "enabled"));
560 GtkCombo *vis = GTK_COMBO (name_to_widget (widget, "visual_combo"));
562 Bool enabled_p = gtk_toggle_button_get_active (enabled);
563 const char *visual = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (vis)->entry));
564 const char *command = gtk_entry_get_text (cmd);
569 if (which < 0) return -1;
571 if (maybe_reload_init_file (widget, pair) != 0)
574 /* Sanity-check and canonicalize whatever the user typed into the combo box.
576 if (!strcasecmp (visual, "")) visual = "";
577 else if (!strcasecmp (visual, "any")) visual = "";
578 else if (!strcasecmp (visual, "default")) visual = "Default";
579 else if (!strcasecmp (visual, "default-n")) visual = "Default-N";
580 else if (!strcasecmp (visual, "default-i")) visual = "Default-I";
581 else if (!strcasecmp (visual, "best")) visual = "Best";
582 else if (!strcasecmp (visual, "mono")) visual = "Mono";
583 else if (!strcasecmp (visual, "monochrome")) visual = "Mono";
584 else if (!strcasecmp (visual, "gray")) visual = "Gray";
585 else if (!strcasecmp (visual, "grey")) visual = "Gray";
586 else if (!strcasecmp (visual, "color")) visual = "Color";
587 else if (!strcasecmp (visual, "gl")) visual = "GL";
588 else if (!strcasecmp (visual, "staticgray")) visual = "StaticGray";
589 else if (!strcasecmp (visual, "staticcolor")) visual = "StaticColor";
590 else if (!strcasecmp (visual, "truecolor")) visual = "TrueColor";
591 else if (!strcasecmp (visual, "grayscale")) visual = "GrayScale";
592 else if (!strcasecmp (visual, "greyscale")) visual = "GrayScale";
593 else if (!strcasecmp (visual, "pseudocolor")) visual = "PseudoColor";
594 else if (!strcasecmp (visual, "directcolor")) visual = "DirectColor";
595 else if (1 == sscanf (visual, " %ld %c", &id, &c)) ;
596 else if (1 == sscanf (visual, " 0x%lx %c", &id, &c)) ;
599 gdk_beep (); /* unparsable */
601 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry), "Any");
604 ensure_selected_item_visible (GTK_WIDGET (list_widget));
606 if (!p->screenhacks[which]->visual)
607 p->screenhacks[which]->visual = strdup ("");
608 if (!p->screenhacks[which]->command)
609 p->screenhacks[which]->command = strdup ("");
611 if (p->screenhacks[which]->enabled_p != enabled_p ||
612 !!strcasecmp (p->screenhacks[which]->visual, visual) ||
613 !!strcasecmp (p->screenhacks[which]->command, command))
615 /* Something was changed -- store results into the struct,
618 free (p->screenhacks[which]->visual);
619 free (p->screenhacks[which]->command);
620 p->screenhacks[which]->visual = strdup (visual);
621 p->screenhacks[which]->command = strdup (command);
622 p->screenhacks[which]->enabled_p = enabled_p;
624 return demo_write_init_file (widget, p);
627 /* No changes made */
631 void prefs_ok_cb (GtkButton *button, gpointer user_data);
634 apply_changes_and_save (GtkWidget *widget)
636 prefs_ok_cb ((GtkButton *) widget, 0);
637 return apply_changes_and_save_1 (widget);
642 run_this_cb (GtkButton *button, gpointer user_data)
644 int which = selected_hack_number (GTK_WIDGET (button));
645 if (which < 0) return;
646 if (0 == apply_changes_and_save (GTK_WIDGET (button)))
647 run_hack (GTK_WIDGET (button), which, True);
652 manual_cb (GtkButton *button, gpointer user_data)
654 /* prefs_pair *pair = (prefs_pair *) client_data; */
655 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
656 saver_preferences *p = pair->a;
657 GtkList *list_widget =
658 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
659 int which = selected_hack_number (GTK_WIDGET (button));
660 char *name, *name2, *cmd, *s;
661 if (which < 0) return;
662 apply_changes_and_save (GTK_WIDGET (button));
663 ensure_selected_item_visible (GTK_WIDGET (list_widget));
665 name = strdup (p->screenhacks[which]->command);
667 while (isspace (*name2)) name2++;
669 while (*s && !isspace (*s)) s++;
671 s = strrchr (name2, '/');
674 cmd = get_string_resource ("manualCommand", "ManualCommand");
677 char *cmd2 = (char *) malloc (strlen (cmd) + strlen (name2) + 100);
679 sprintf (cmd2 + strlen (cmd2),
681 name2, name2, name2, name2);
682 strcat (cmd2, " ) &");
688 warning_dialog (GTK_WIDGET (button),
689 "Error:\n\nno `manualCommand' resource set.",
698 run_next_cb (GtkButton *button, gpointer user_data)
700 /* prefs_pair *pair = (prefs_pair *) client_data; */
701 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
702 saver_preferences *p = pair->a;
704 GtkList *list_widget =
705 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
706 int which = selected_hack_number (GTK_WIDGET (button));
713 if (which >= p->screenhacks_count)
716 apply_changes_and_save (GTK_WIDGET (button));
717 gtk_list_select_item (GTK_LIST (list_widget), which);
718 ensure_selected_item_visible (GTK_WIDGET (list_widget));
719 populate_demo_window (GTK_WIDGET (button), which, pair);
720 run_hack (GTK_WIDGET (button), which, False);
725 run_prev_cb (GtkButton *button, gpointer user_data)
727 /* prefs_pair *pair = (prefs_pair *) client_data; */
728 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
729 saver_preferences *p = pair->a;
731 GtkList *list_widget =
732 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
733 int which = selected_hack_number (GTK_WIDGET (button));
736 which = p->screenhacks_count - 1;
741 which = p->screenhacks_count - 1;
743 apply_changes_and_save (GTK_WIDGET (button));
744 gtk_list_select_item (GTK_LIST (list_widget), which);
745 ensure_selected_item_visible (GTK_WIDGET (list_widget));
746 populate_demo_window (GTK_WIDGET (button), which, pair);
747 run_hack (GTK_WIDGET (button), which, False);
751 /* Helper for the text fields that contain time specifications:
752 this parses the text, and does error checking.
755 hack_time_text (GtkWidget *widget, const char *line, Time *store, Bool sec_p)
760 value = parse_time ((char *) line, sec_p, True);
761 value *= 1000; /* Time measures in microseconds */
767 "Unparsable time format: \"%s\"\n",
769 warning_dialog (widget, b, False, 100);
778 prefs_ok_cb (GtkButton *button, gpointer user_data)
780 /* prefs_pair *pair = (prefs_pair *) client_data; */
781 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
783 saver_preferences *p = pair->a;
784 saver_preferences *p2 = pair->b;
785 Bool changed = False;
787 # define SECONDS(field, name) \
788 hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
789 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
793 # define MINUTES(field, name) \
794 hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
795 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
799 # define INTEGER(field, name) do { \
800 char *line = gtk_entry_get_text (\
801 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))); \
802 unsigned int value; \
806 else if (sscanf (line, "%u%c", &value, &c) != 1) \
809 sprintf (b, "Error:\n\n" "Not an integer: \"%s\"\n", line); \
810 warning_dialog (GTK_WIDGET (button), b, False, 100); \
816 # define CHECKBOX(field, name) \
817 field = gtk_toggle_button_get_active (\
818 GTK_TOGGLE_BUTTON (name_to_widget (GTK_WIDGET(button), (name))))
820 MINUTES (&p2->timeout, "timeout_text");
821 MINUTES (&p2->cycle, "cycle_text");
822 SECONDS (&p2->fade_seconds, "fade_text");
823 INTEGER (&p2->fade_ticks, "ticks_text");
824 MINUTES (&p2->lock_timeout, "lock_text");
825 SECONDS (&p2->passwd_timeout, "pass_text");
826 CHECKBOX (p2->verbose_p, "verbose_button");
827 CHECKBOX (p2->install_cmap_p, "install_button");
828 CHECKBOX (p2->fade_p, "fade_button");
829 CHECKBOX (p2->unfade_p, "unfade_button");
830 CHECKBOX (p2->lock_p, "lock_button");
837 # define COPY(field) \
838 if (p->field != p2->field) changed = True; \
844 COPY(passwd_timeout);
848 COPY(install_cmap_p);
854 populate_prefs_page (GTK_WIDGET (button), pair);
857 demo_write_init_file (GTK_WIDGET (button), p);
862 prefs_cancel_cb (GtkButton *button, gpointer user_data)
864 /* prefs_pair *pair = (prefs_pair *) client_data; */
865 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
868 populate_prefs_page (GTK_WIDGET (button), pair);
873 pref_changed_cb (GtkButton *button, gpointer user_data)
875 if (! initializing_p)
876 apply_changes_and_save (GTK_WIDGET (button));
881 list_doubleclick_cb (GtkWidget *button, GdkEventButton *event,
882 gpointer client_data)
884 if (event->type == GDK_2BUTTON_PRESS)
886 GtkList *list = GTK_LIST (name_to_widget (button, "list"));
887 int which = gtk_list_child_position (list, GTK_WIDGET (button));
890 run_hack (GTK_WIDGET (button), which, True);
898 list_select_cb (GtkList *list, GtkWidget *child)
900 /* prefs_pair *pair = (prefs_pair *) client_data; */
901 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
903 int which = gtk_list_child_position (list, GTK_WIDGET (child));
904 apply_changes_and_save (GTK_WIDGET (list));
905 populate_demo_window (GTK_WIDGET (list), which, pair);
909 list_unselect_cb (GtkList *list, GtkWidget *child)
911 /* prefs_pair *pair = (prefs_pair *) client_data; */
912 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
914 apply_changes_and_save (GTK_WIDGET (list));
915 populate_demo_window (GTK_WIDGET (list), -1, pair);
919 /* Populating the various widgets
923 /* Formats a `Time' into "H:MM:SS". (Time is microseconds.)
926 format_time (char *buf, Time time)
929 unsigned int h = 0, m = 0;
940 sprintf (buf, "%u:%02u:%02u", h, m, s);
945 make_pretty_name (const char *shell_command)
947 char *s = strdup (shell_command);
951 for (s2 = s; *s2; s2++) /* truncate at first whitespace */
958 s2 = strrchr (s, '/'); /* if pathname, take last component */
966 if (strlen (s) > 50) /* 51 is hereby defined as "unreasonable" */
969 sprintf (res_name, "hacks.%s.name", s); /* resource? */
970 s2 = get_string_resource (res_name, res_name);
974 for (s2 = s; *s2; s2++) /* if it has any capitals, return it */
975 if (*s2 >= 'A' && *s2 <= 'Z')
978 if (s[0] >= 'a' && s[0] <= 'z') /* else cap it */
980 if (s[0] == 'X' && s[1] >= 'a' && s[1] <= 'z') /* (magic leading X) */
986 /* Finds the number of the last hack to run, and makes that item be
990 scroll_to_current_hack (GtkWidget *toplevel, prefs_pair *pair)
992 saver_preferences *p = pair->a;
995 unsigned long nitems, bytesafter;
997 Display *dpy = gdk_display;
1001 if (XGetWindowProperty (dpy, RootWindow (dpy, 0), /* always screen #0 */
1002 XA_SCREENSAVER_STATUS,
1003 0, 3, False, XA_INTEGER,
1004 &type, &format, &nitems, &bytesafter,
1005 (unsigned char **) &data)
1007 && type == XA_INTEGER
1010 which = (int) data[2] - 1;
1012 if (data) free (data);
1017 list = GTK_LIST (name_to_widget (toplevel, "list"));
1018 apply_changes_and_save (toplevel);
1019 if (which < p->screenhacks_count)
1021 gtk_list_select_item (list, which);
1022 ensure_selected_item_visible (GTK_WIDGET (list));
1023 populate_demo_window (toplevel, which, pair);
1030 populate_hack_list (GtkWidget *toplevel, prefs_pair *pair)
1032 saver_preferences *p = pair->a;
1033 GtkList *list = GTK_LIST (name_to_widget (toplevel, "list"));
1034 screenhack **hacks = p->screenhacks;
1037 for (h = hacks; h && *h; h++)
1040 char *pretty_name = (h[0]->name
1041 ? strdup (h[0]->name)
1042 : make_pretty_name (h[0]->command));
1044 line = gtk_list_item_new_with_label (pretty_name);
1047 gtk_container_add (GTK_CONTAINER (list), line);
1048 gtk_signal_connect (GTK_OBJECT (line), "button_press_event",
1049 GTK_SIGNAL_FUNC (list_doubleclick_cb),
1052 GTK_WIDGET (GTK_BIN(line)->child)->style =
1053 gtk_style_copy (GTK_WIDGET (text_line)->style);
1055 gtk_widget_show (line);
1058 gtk_signal_connect (GTK_OBJECT (list), "select_child",
1059 GTK_SIGNAL_FUNC (list_select_cb),
1061 gtk_signal_connect (GTK_OBJECT (list), "unselect_child",
1062 GTK_SIGNAL_FUNC (list_unselect_cb),
1068 populate_prefs_page (GtkWidget *top, prefs_pair *pair)
1070 saver_preferences *p = pair->a;
1073 format_time (s, p->timeout);
1074 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "timeout_text")), s);
1075 format_time (s, p->cycle);
1076 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "cycle_text")), s);
1077 format_time (s, p->lock_timeout);
1078 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "lock_text")), s);
1079 format_time (s, p->passwd_timeout);
1080 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "pass_text")), s);
1081 format_time (s, p->fade_seconds);
1082 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "fade_text")), s);
1083 sprintf (s, "%u", p->fade_ticks);
1084 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "ticks_text")), s);
1086 gtk_toggle_button_set_active (
1087 GTK_TOGGLE_BUTTON (name_to_widget (top, "verbose_button")),
1089 gtk_toggle_button_set_active (
1090 GTK_TOGGLE_BUTTON (name_to_widget (top, "install_button")),
1092 gtk_toggle_button_set_active (
1093 GTK_TOGGLE_BUTTON (name_to_widget (top, "fade_button")),
1095 gtk_toggle_button_set_active (
1096 GTK_TOGGLE_BUTTON (name_to_widget (top, "unfade_button")),
1098 gtk_toggle_button_set_active (
1099 GTK_TOGGLE_BUTTON (name_to_widget (top, "lock_button")),
1104 Bool found_any_writable_cells = False;
1105 Display *dpy = gdk_display;
1106 int nscreens = ScreenCount(dpy);
1108 for (i = 0; i < nscreens; i++)
1110 Screen *s = ScreenOfDisplay (dpy, i);
1111 if (has_writable_cells (s, DefaultVisualOfScreen (s)))
1113 found_any_writable_cells = True;
1118 gtk_widget_set_sensitive (
1119 GTK_WIDGET (name_to_widget (top, "fade_label")),
1120 found_any_writable_cells);
1121 gtk_widget_set_sensitive (
1122 GTK_WIDGET (name_to_widget (top, "ticks_label")),
1123 found_any_writable_cells);
1124 gtk_widget_set_sensitive (
1125 GTK_WIDGET (name_to_widget (top, "fade_text")),
1126 found_any_writable_cells);
1127 gtk_widget_set_sensitive (
1128 GTK_WIDGET (name_to_widget (top, "ticks_text")),
1129 found_any_writable_cells);
1130 gtk_widget_set_sensitive (
1131 GTK_WIDGET (name_to_widget (top, "install_button")),
1132 found_any_writable_cells);
1133 gtk_widget_set_sensitive (
1134 GTK_WIDGET (name_to_widget (top, "fade_button")),
1135 found_any_writable_cells);
1136 gtk_widget_set_sensitive (
1137 GTK_WIDGET (name_to_widget (top, "unfade_button")),
1138 found_any_writable_cells);
1145 sensitize_demo_widgets (GtkWidget *toplevel, Bool sensitive_p)
1147 const char *names[] = { "cmd_label", "cmd_text", "enabled",
1148 "visual", "visual_combo",
1151 for (i = 0; i < countof(names); i++)
1153 GtkWidget *w = name_to_widget (toplevel, names[i]);
1154 gtk_widget_set_sensitive (GTK_WIDGET(w), sensitive_p);
1157 /* I don't know how to handle these yet... */
1159 const char *names2[] = { "cut_menu", "copy_menu", "paste_menu" };
1160 for (i = 0; i < countof(names2); i++)
1162 GtkWidget *w = name_to_widget (toplevel, names2[i]);
1163 gtk_widget_set_sensitive (GTK_WIDGET(w), False);
1169 /* Even though we've given these text fields a maximum number of characters,
1170 their default size is still about 30 characters wide -- so measure out
1171 a string in their font, and resize them to just fit that.
1174 fix_text_entry_sizes (GtkWidget *toplevel)
1176 const char *names[] = { "timeout_text", "cycle_text", "fade_text",
1177 "ticks_text", "lock_text", "pass_text" };
1182 for (i = 0; i < countof(names); i++)
1184 w = GTK_WIDGET (name_to_widget (toplevel, names[i]));
1186 width = gdk_text_width (w->style->font, "00:00:00_", 9);
1187 gtk_widget_set_usize (w, width, -2);
1190 /* Now fix the size of the combo box.
1192 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "visual_combo"));
1193 w = GTK_COMBO (w)->entry;
1194 width = gdk_text_width (w->style->font, "PseudoColor___", 14);
1195 gtk_widget_set_usize (w, width, -2);
1198 /* Now fix the size of the list.
1200 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "list"));
1201 width = gdk_text_width (w->style->font, "nnnnnnnnnnnnnnnnnnnnnn", 22);
1202 gtk_widget_set_usize (w, width, -2);
1209 /* Pixmaps for the up and down arrow buttons (yeah, this is sleazy...)
1212 static char *up_arrow_xpm[] = {
1235 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1236 the end of the array (Gtk 1.2.5.) */
1237 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1238 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1241 static char *down_arrow_xpm[] = {
1264 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1265 the end of the array (Gtk 1.2.5.) */
1266 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1267 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1271 pixmapify_buttons (GtkWidget *toplevel)
1275 GtkWidget *pixmapwid;
1279 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "next"));
1280 style = gtk_widget_get_style (w);
1282 pixmap = gdk_pixmap_create_from_xpm_d (w->window, &mask,
1283 &style->bg[GTK_STATE_NORMAL],
1284 (gchar **) down_arrow_xpm);
1285 pixmapwid = gtk_pixmap_new (pixmap, mask);
1286 gtk_widget_show (pixmapwid);
1287 gtk_container_remove (GTK_CONTAINER (w), GTK_BIN (w)->child);
1288 gtk_container_add (GTK_CONTAINER (w), pixmapwid);
1290 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "prev"));
1291 style = gtk_widget_get_style (w);
1293 pixmap = gdk_pixmap_create_from_xpm_d (w->window, &mask,
1294 &style->bg[GTK_STATE_NORMAL],
1295 (gchar **) up_arrow_xpm);
1296 pixmapwid = gtk_pixmap_new (pixmap, mask);
1297 gtk_widget_show (pixmapwid);
1298 gtk_container_remove (GTK_CONTAINER (w), GTK_BIN (w)->child);
1299 gtk_container_add (GTK_CONTAINER (w), pixmapwid);
1304 /* Work around a Gtk bug that causes label widgets to wrap text too early.
1308 you_are_not_a_unique_or_beautiful_snowflake (GtkWidget *label,
1309 GtkAllocation *allocation,
1313 GtkWidgetAuxInfo *aux_info;
1315 aux_info = gtk_object_get_data (GTK_OBJECT (label), "gtk-aux-info");
1317 aux_info->width = allocation->width;
1318 aux_info->height = -2;
1322 gtk_widget_size_request (label, &req);
1326 /* Feel the love. Thanks to Nat Friedman for finding this workaround.
1329 eschew_gtk_lossage (GtkWidget *toplevel)
1331 GtkWidgetAuxInfo *aux_info;
1332 GtkWidget *label = GTK_WIDGET (name_to_widget (toplevel, "doc"));
1334 aux_info = g_new0 (GtkWidgetAuxInfo, 1);
1335 aux_info->width = label->allocation.width;
1336 aux_info->height = -2;
1340 gtk_object_set_data (GTK_OBJECT (label), "gtk-aux-info", aux_info);
1342 gtk_signal_connect (GTK_OBJECT (label), "size_allocate",
1343 you_are_not_a_unique_or_beautiful_snowflake, NULL);
1345 gtk_widget_queue_resize (label);
1350 get_hack_blurb (screenhack *hack)
1353 char *prog_name = strdup (hack->command);
1354 char *pretty_name = (hack->name
1355 ? strdup (hack->name)
1356 : make_pretty_name (hack->command));
1357 char doc_name[255], doc_class[255];
1360 for (s = prog_name; *s && !isspace(*s); s++)
1363 s = strrchr (prog_name, '/');
1364 if (s) strcpy (prog_name, s+1);
1366 sprintf (doc_name, "hacks.%s.documentation", pretty_name);
1367 sprintf (doc_class, "hacks.%s.documentation", prog_name);
1371 doc_string = get_string_resource (doc_name, doc_class);
1374 for (s = doc_string; *s; s++)
1378 /* skip over whitespace at beginning of line */
1380 while (*s && (*s == ' ' || *s == '\t'))
1383 else if (*s == ' ' || *s == '\t')
1385 /* compress all other horizontal whitespace. */
1388 for (s2 = s; *s2 && (*s2 == ' ' || *s2 == '\t'); s2++)
1390 if (s2 > s) strcpy (s, s2);
1395 while (*s && isspace (*s)) /* Strip trailing whitespace */
1398 /* Delete whitespace at end of each line. */
1399 for (; s > doc_string; s--)
1400 if (*s == '\n' && (s[-1] == ' ' || s[-1] == '\t'))
1403 s2 > doc_string && (*s2 == ' ' || *s2 == '\t');
1407 if (s2 < s) strcpy (s2, s);
1411 /* Delete leading blank lines. */
1412 for (s = doc_string; *s == '\n'; s++)
1414 if (s > doc_string) strcpy (doc_string, s);
1418 static int doc_installed = 0;
1419 if (doc_installed == 0)
1421 if (get_boolean_resource ("hacks.documentation.isInstalled",
1422 "hacks.documentation.isInstalled"))
1428 if (doc_installed < 0)
1430 strdup ("Error:\n\n"
1431 "The documentation strings do not appear to be "
1432 "installed. This is probably because there is "
1433 "an \"XScreenSaver\" app-defaults file installed "
1434 "that is from an older version of the program. "
1435 "To fix this problem, delete that file, or "
1436 "install a current version (either will work.)");
1438 doc_string = strdup ("");
1446 populate_demo_window (GtkWidget *toplevel, int which, prefs_pair *pair)
1448 saver_preferences *p = pair->a;
1449 screenhack *hack = (which >= 0 && which < p->screenhacks_count
1450 ? p->screenhacks[which] : 0);
1451 GtkFrame *frame = GTK_FRAME (name_to_widget (toplevel, "frame"));
1452 GtkLabel *doc = GTK_LABEL (name_to_widget (toplevel, "doc"));
1453 GtkEntry *cmd = GTK_ENTRY (name_to_widget (toplevel, "cmd_text"));
1454 GtkToggleButton *enabled =
1455 GTK_TOGGLE_BUTTON (name_to_widget (toplevel, "enabled"));
1456 GtkCombo *vis = GTK_COMBO (name_to_widget (toplevel, "visual_combo"));
1458 char *pretty_name = (hack
1460 ? strdup (hack->name)
1461 : make_pretty_name (hack->command))
1463 char *doc_string = hack ? get_hack_blurb (hack) : 0;
1465 gtk_frame_set_label (frame, (pretty_name ? pretty_name : ""));
1466 gtk_label_set_text (doc, (doc_string ? doc_string : ""));
1467 gtk_entry_set_text (cmd, (hack ? hack->command : ""));
1468 gtk_entry_set_position (cmd, 0);
1469 gtk_toggle_button_set_active (enabled, (hack ? hack->enabled_p : False));
1470 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry),
1472 ? (hack->visual && *hack->visual
1477 gtk_container_resize_children (GTK_CONTAINER (GTK_WIDGET (doc)->parent));
1479 sensitize_demo_widgets (toplevel, (hack ? True : False));
1481 if (pretty_name) free (pretty_name);
1482 if (doc_string) free (doc_string);
1484 _selected_hack_number = which;
1489 widget_deleter (GtkWidget *widget, gpointer data)
1491 /* #### Well, I want to destroy these widgets, but if I do that, they get
1492 referenced again, and eventually I get a SEGV. So instead of
1493 destroying them, I'll just hide them, and leak a bunch of memory
1494 every time the disk file changes. Go go go Gtk!
1496 #### Ok, that's a lie, I get a crash even if I just hide the widget
1497 and don't ever delete it. Fuck!
1500 gtk_widget_destroy (widget);
1502 gtk_widget_hide (widget);
1508 maybe_reload_init_file (GtkWidget *widget, prefs_pair *pair)
1511 saver_preferences *p = pair->a;
1513 static Bool reentrant_lock = False;
1514 if (reentrant_lock) return 0;
1515 reentrant_lock = True;
1517 if (init_file_changed_p (p))
1519 const char *f = init_file_name();
1524 if (!f || !*f) return 0;
1525 b = (char *) malloc (strlen(f) + 1024);
1528 "file \"%s\" has changed, reloading.\n",
1530 warning_dialog (widget, b, False, 100);
1535 which = selected_hack_number (widget);
1536 list = GTK_LIST (name_to_widget (widget, "list"));
1537 gtk_container_foreach (GTK_CONTAINER (list), widget_deleter, NULL);
1538 populate_hack_list (widget, pair);
1539 gtk_list_select_item (list, which);
1540 populate_prefs_page (widget, pair);
1541 populate_demo_window (widget, which, pair);
1542 ensure_selected_item_visible (GTK_WIDGET (list));
1547 reentrant_lock = False;
1553 /* The main demo-mode command loop.
1558 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
1559 XrmRepresentation *type, XrmValue *value, XPointer closure)
1562 for (i = 0; quarks[i]; i++)
1564 if (bindings[i] == XrmBindTightly)
1565 fprintf (stderr, (i == 0 ? "" : "."));
1566 else if (bindings[i] == XrmBindLoosely)
1567 fprintf (stderr, "*");
1569 fprintf (stderr, " ??? ");
1570 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
1573 fprintf (stderr, ": %s\n", (char *) value->addr);
1581 the_network_is_not_the_computer (GtkWidget *parent)
1583 Display *dpy = gdk_display;
1584 char *rversion, *ruser, *rhost;
1585 char *luser, *lhost;
1587 struct passwd *p = getpwuid (getuid ());
1588 const char *d = DisplayString (dpy);
1590 # if defined(HAVE_UNAME)
1592 if (uname (&uts) < 0)
1593 lhost = "<UNKNOWN>";
1595 lhost = uts.nodename;
1597 strcpy (lhost, getenv("SYS$NODE"));
1598 # else /* !HAVE_UNAME && !VMS */
1599 strcat (lhost, "<UNKNOWN>");
1600 # endif /* !HAVE_UNAME && !VMS */
1602 if (p && p->pw_name)
1607 server_xscreensaver_version (dpy, &rversion, &ruser, &rhost);
1609 /* Make a buffer that's big enough for a number of copies of all the
1610 strings, plus some. */
1611 msg = (char *) malloc (10 * ((rversion ? strlen(rversion) : 0) +
1612 (ruser ? strlen(ruser) : 0) +
1613 (rhost ? strlen(rhost) : 0) +
1620 if (!rversion || !*rversion)
1624 "The XScreenSaver daemon doesn't seem to be running\n"
1625 "on display \"%s\". Launch it now?",
1628 else if (p && ruser && *ruser && !!strcmp (ruser, p->pw_name))
1630 /* Warn that the two processes are running as different users.
1634 "%s is running as user \"%s\" on host \"%s\".\n"
1635 "But the xscreensaver managing display \"%s\"\n"
1636 "is running as user \"%s\" on host \"%s\".\n"
1638 "Since they are different users, they won't be reading/writing\n"
1639 "the same ~/.xscreensaver file, so %s isn't\n"
1640 "going to work right.\n"
1642 "You should either re-run %s as \"%s\", or re-run\n"
1643 "xscreensaver as \"%s\".\n"
1645 "Restart the xscreensaver daemon now?\n",
1646 progname, luser, lhost,
1648 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1650 progname, (ruser ? ruser : "???"),
1653 else if (rhost && *rhost && !!strcmp (rhost, lhost))
1655 /* Warn that the two processes are running on different hosts.
1659 "%s is running as user \"%s\" on host \"%s\".\n"
1660 "But the xscreensaver managing display \"%s\"\n"
1661 "is running as user \"%s\" on host \"%s\".\n"
1663 "If those two machines don't share a file system (that is,\n"
1664 "if they don't see the same ~%s/.xscreensaver file) then\n"
1665 "%s won't work right.\n"
1667 "Restart the daemon on \"%s\" as \"%s\" now?\n",
1668 progname, luser, lhost,
1670 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1675 else if (!!strcmp (rversion, short_version))
1677 /* Warn that the version numbers don't match.
1681 "This is %s version %s.\n"
1682 "But the xscreensaver managing display \"%s\"\n"
1683 "is version %s. This could cause problems.\n"
1685 "Restart the xscreensaver daemon now?\n",
1686 progname, short_version,
1693 warning_dialog (parent, msg, True, 1);
1699 /* We use this error handler so that X errors are preceeded by the name
1700 of the program that generated them.
1703 demo_ehandler (Display *dpy, XErrorEvent *error)
1705 fprintf (stderr, "\nX error in %s:\n", progname);
1706 if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
1709 fprintf (stderr, " (nonfatal.)\n");
1714 /* We use this error handler so that Gtk/Gdk errors are preceeded by the name
1715 of the program that generated them; and also that we can ignore one
1716 particular bogus error message that Gdk madly spews.
1719 g_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
1720 const gchar *message, gpointer user_data)
1722 /* Ignore the message "Got event for unknown window: 0x...".
1723 Apparently some events are coming in for the xscreensaver window
1724 (presumably reply events related to the ClientMessage) and Gdk
1725 feels the need to complain about them. So, just suppress any
1726 messages that look like that one.
1728 if (strstr (message, "unknown window"))
1731 fprintf (stderr, "%s: %s-%s: %s%s", blurb(), log_domain,
1732 (log_level == G_LOG_LEVEL_ERROR ? "error" :
1733 log_level == G_LOG_LEVEL_CRITICAL ? "critical" :
1734 log_level == G_LOG_LEVEL_WARNING ? "warning" :
1735 log_level == G_LOG_LEVEL_MESSAGE ? "message" :
1736 log_level == G_LOG_LEVEL_INFO ? "info" :
1737 log_level == G_LOG_LEVEL_DEBUG ? "debug" : "???"),
1739 ((!*message || message[strlen(message)-1] != '\n')
1744 static char *defaults[] = {
1745 #include "XScreenSaver_ad.h"
1750 #ifdef HAVE_CRAPPLET
1751 static struct poptOption crapplet_options[] = {
1752 {NULL, '\0', 0, NULL, 0}
1754 #endif /* HAVE_CRAPPLET */
1758 fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n", \
1763 map_window_cb (GtkWidget *w, gpointer user_data)
1765 Boolean oi = initializing_p;
1766 initializing_p = True;
1767 pixmapify_buttons (w);
1768 eschew_gtk_lossage (w);
1769 ensure_selected_item_visible (GTK_WIDGET(name_to_widget(w, "list")));
1770 initializing_p = oi;
1775 main (int argc, char **argv)
1778 # ifdef HAVE_CRAPPLET
1779 GnomeClient *client;
1780 GnomeClientFlags flags;
1782 # endif /* HAVE_CRAPPLET */
1783 prefs_pair Pair, *pair;
1784 saver_preferences P, P2, *p, *p2;
1788 Widget toplevel_shell;
1789 GtkWidget *gtk_window;
1790 char *real_progname = argv[0];
1793 initializing_p = True;
1795 s = strrchr (real_progname, '/');
1796 if (s) real_progname = s+1;
1803 memset (p, 0, sizeof (*p));
1804 memset (p2, 0, sizeof (*p2));
1806 global_prefs_pair = pair; /* I hate C so much... */
1808 progname = real_progname;
1810 short_version = (char *) malloc (5);
1811 memcpy (short_version, screensaver_id + 17, 4);
1812 short_version [4] = 0;
1815 /* Register our error message logger for every ``log domain'' known.
1816 There's no way to do this globally, so I grepped the Gtk/Gdk sources
1817 for all of the domains that seem to be in use.
1820 const char * const domains[] = { "Gtk", "Gdk", "GLib", "GModule",
1821 "GThread", "Gnome", "GnomeUI", 0 };
1822 for (i = 0; domains[i]; i++)
1823 g_log_set_handler (domains[i], G_LOG_LEVEL_MASK, g_log_handler, 0);
1826 /* This is gross, but Gtk understands --display and not -display...
1828 for (i = 1; i < argc; i++)
1829 if (argv[i][0] && argv[i][1] &&
1830 !strncmp(argv[i], "-display", strlen(argv[i])))
1831 argv[i] = "--display";
1834 /* We need to parse this arg really early... Sigh. */
1835 for (i = 1; i < argc; i++)
1837 (!strcmp(argv[i], "--crapplet") ||
1838 !strcmp(argv[i], "--capplet")))
1840 # ifdef HAVE_CRAPPLET
1843 for (j = i; j < argc; j++) /* remove it from the list */
1844 argv[j] = argv[j+1];
1847 # else /* !HAVE_CRAPPLET */
1848 fprintf (stderr, "%s: not compiled with --crapplet support\n",
1852 # endif /* !HAVE_CRAPPLET */
1855 /* Let Gtk open the X connection, then initialize Xt to use that
1856 same connection. Doctor Frankenstein would be proud.
1858 # ifdef HAVE_CRAPPLET
1861 init_results = gnome_capplet_init ("screensaver-properties",
1863 argc, argv, NULL, 0, NULL);
1865 if (init_results < 0)
1868 g_error ("An initialization error occurred while "
1869 "starting xscreensaver-capplet.\n");
1871 fprintf (stderr, "%s: gnome_capplet_init failed: %d\n",
1872 real_progname, init_results);
1877 client = gnome_master_client ();
1880 flags = gnome_client_get_flags (client);
1884 if (flags & GNOME_CLIENT_IS_CONNECTED)
1886 gnome_client_set_restart_style (client, GNOME_RESTART_NEVER);
1887 gnome_client_flush (client);
1891 # endif /* HAVE_CRAPPLET */
1893 gtk_init (&argc, &argv);
1897 /* We must read exactly the same resources as xscreensaver.
1898 That means we must have both the same progclass *and* progname,
1899 at least as far as the resource database is concerned. So,
1900 put "xscreensaver" in argv[0] while initializing Xt.
1902 argv[0] = "xscreensaver";
1906 /* Teach Xt to use the Display that Gtk/Gdk have already opened.
1908 XtToolkitInitialize ();
1909 app = XtCreateApplicationContext ();
1911 XtAppSetFallbackResources (app, defaults);
1912 XtDisplayInitialize (app, dpy, progname, progclass, 0, 0, &argc, argv);
1913 toplevel_shell = XtAppCreateShell (progname, progclass,
1914 applicationShellWidgetClass,
1917 dpy = XtDisplay (toplevel_shell);
1918 db = XtDatabase (dpy);
1919 XtGetApplicationNameAndClass (dpy, &progname, &progclass);
1920 XSetErrorHandler (demo_ehandler);
1923 /* After doing Xt-style command-line processing, complain about any
1924 unrecognized command-line arguments.
1926 for (i = 1; i < argc; i++)
1929 if (s[0] == '-' && s[1] == '-')
1931 if (!strcmp (s, "-prefs"))
1933 else if (crapplet_p)
1934 /* There are lots of random args that we don't care about when we're
1935 started as a crapplet, so just ignore unknown args in that case. */
1939 fprintf (stderr, "%s: unknown option: %s\n", real_progname, argv[i]);
1945 /* Load the init file, which may end up consulting the X resource database
1946 and the site-wide app-defaults file. Note that at this point, it's
1947 important that `progname' be "xscreensaver", rather than whatever
1954 /* Now that Xt has been initialized, and the resources have been read,
1955 we can set our `progname' variable to something more in line with
1958 progname = real_progname;
1962 /* Print out all the resources we read. */
1964 XrmName name = { 0 };
1965 XrmClass class = { 0 };
1967 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
1973 /* Intern the atoms that xscreensaver_command() needs.
1975 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
1976 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
1977 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
1978 XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False);
1979 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
1980 XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
1981 XA_SELECT = XInternAtom (dpy, "SELECT", False);
1982 XA_DEMO = XInternAtom (dpy, "DEMO", False);
1983 XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
1984 XA_BLANK = XInternAtom (dpy, "BLANK", False);
1985 XA_LOCK = XInternAtom (dpy, "LOCK", False);
1986 XA_EXIT = XInternAtom (dpy, "EXIT", False);
1987 XA_RESTART = XInternAtom (dpy, "RESTART", False);
1990 /* Create the window and all its widgets.
1992 gtk_window = create_xscreensaver_demo ();
1993 toplevel_widget = gtk_window;
1995 /* Set the window's title. */
1998 char *v = (char *) strdup(strchr(screensaver_id, ' '));
1999 char *s1, *s2, *s3, *s4;
2000 s1 = (char *) strchr(v, ' '); s1++;
2001 s2 = (char *) strchr(s1, ' ');
2002 s3 = (char *) strchr(v, '('); s3++;
2003 s4 = (char *) strchr(s3, ')');
2006 sprintf (title, "%.50s %.50s, %.50s", progclass, s1, s3);
2007 gtk_window_set_title (GTK_WINDOW (gtk_window), title);
2011 /* Various other widget initializations...
2013 gtk_signal_connect (GTK_OBJECT (gtk_window), "delete_event",
2014 GTK_SIGNAL_FUNC (wm_close_cb), NULL);
2016 populate_hack_list (gtk_window, pair);
2017 populate_prefs_page (gtk_window, pair);
2018 sensitize_demo_widgets (gtk_window, False);
2019 fix_text_entry_sizes (gtk_window);
2020 scroll_to_current_hack (gtk_window, pair);
2022 gtk_signal_connect (
2023 GTK_OBJECT (name_to_widget (GTK_WIDGET (gtk_window), "list")),
2024 "map", GTK_SIGNAL_FUNC(map_window_cb), 0);
2027 /* Handle the -prefs command-line argument. */
2030 GtkNotebook *notebook =
2031 GTK_NOTEBOOK (name_to_widget (gtk_window, "notebook"));
2032 gtk_notebook_set_page (notebook, 1);
2035 # ifdef HAVE_CRAPPLET
2039 GtkWidget *top_vbox;
2041 capplet = capplet_widget_new ();
2043 top_vbox = GTK_BIN (gtk_window)->child;
2045 gtk_widget_ref (top_vbox);
2046 gtk_container_remove (GTK_CONTAINER (gtk_window), top_vbox);
2047 GTK_OBJECT_SET_FLAGS (top_vbox, GTK_FLOATING);
2049 /* This is a crock, but otherwise, the Control Center expands to
2050 be as tall as the screen. */
2051 gtk_window_set_default_size (GTK_WINDOW (top_vbox), 600, 400);
2053 /* In crapplet-mode, take off the menubar. */
2054 gtk_widget_hide (name_to_widget (gtk_window, "menubar"));
2056 gtk_container_add (GTK_CONTAINER (capplet), top_vbox);
2057 gtk_widget_show (capplet);
2058 gtk_widget_hide (gtk_window);
2060 /* Hook up the Control Center's redundant Help button, too. */
2061 gtk_signal_connect (GTK_OBJECT (capplet), "help",
2062 GTK_SIGNAL_FUNC (doc_menu_cb), 0);
2064 /* Issue any warnings about the running xscreensaver daemon. */
2065 the_network_is_not_the_computer (top_vbox);
2068 # endif /* HAVE_CRAPPLET */
2070 gtk_widget_show (gtk_window);
2072 /* Issue any warnings about the running xscreensaver daemon. */
2073 the_network_is_not_the_computer (gtk_window);
2076 /* Run the Gtk event loop, and not the Xt event loop. This means that
2077 if there were Xt timers or fds registered, they would never get serviced,
2078 and if there were any Xt widgets, they would never have events delivered.
2079 Fortunately, we're using Gtk for all of the UI, and only initialized
2080 Xt so that we could process the command line and use the X resource
2083 initializing_p = False;
2085 # ifdef HAVE_CRAPPLET
2087 capplet_gtk_main ();
2089 # endif /* HAVE_CRAPPLET */
2095 #endif /* HAVE_GTK -- whole file */