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++);
263 label = gtk_label_new (head);
265 sprintf (buf, "warning_dialog.%s.font", name);
266 GTK_WIDGET (label)->style = gtk_style_copy (GTK_WIDGET (label)->style);
267 GTK_WIDGET (label)->style->font =
268 gdk_font_load (get_string_resource (buf, "Dialog.Label.Font"));
271 gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
272 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
273 label, TRUE, TRUE, 0);
274 gtk_widget_show (label);
285 label = gtk_label_new ("");
286 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->vbox),
287 label, TRUE, TRUE, 0);
288 gtk_widget_show (label);
290 label = gtk_hbutton_box_new ();
291 gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
292 label, TRUE, TRUE, 0);
294 ok = gtk_button_new_with_label ("OK");
295 gtk_container_add (GTK_CONTAINER (label), ok);
297 if (restart_button_p)
299 cancel = gtk_button_new_with_label ("Cancel");
300 gtk_container_add (GTK_CONTAINER (label), cancel);
303 gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
304 gtk_container_set_border_width (GTK_CONTAINER (dialog), 10);
305 gtk_window_set_title (GTK_WINDOW (dialog), progclass);
306 gtk_widget_show (ok);
308 gtk_widget_show (cancel);
309 gtk_widget_show (label);
310 gtk_widget_show (dialog);
311 /* gtk_window_set_default (GTK_WINDOW (dialog), ok);*/
313 if (restart_button_p)
315 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
316 GTK_SIGNAL_FUNC (warning_dialog_restart_cb),
318 gtk_signal_connect_object (GTK_OBJECT (cancel), "clicked",
319 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
324 gtk_signal_connect_object (GTK_OBJECT (ok), "clicked",
325 GTK_SIGNAL_FUNC (warning_dialog_dismiss_cb),
328 gdk_window_set_transient_for (GTK_WIDGET (dialog)->window,
329 GTK_WIDGET (parent)->window);
331 gdk_window_show (GTK_WIDGET (dialog)->window);
332 gdk_window_raise (GTK_WIDGET (dialog)->window);
339 run_cmd (GtkWidget *widget, Atom command, int arg)
344 apply_changes_and_save (widget);
345 status = xscreensaver_command (gdk_display, command, arg, False, &err);
350 sprintf (buf, "Error:\n\n%s", err);
352 strcpy (buf, "Unknown error!");
353 warning_dialog (widget, buf, False, 100);
360 run_hack (GtkWidget *widget, int which, Bool report_errors_p)
362 if (which < 0) return;
363 apply_changes_and_save (widget);
365 run_cmd (widget, XA_DEMO, which + 1);
369 xscreensaver_command (gdk_display, XA_DEMO, which + 1, False, &s);
380 exit_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
382 apply_changes_and_save (GTK_WIDGET (menuitem));
387 wm_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
389 apply_changes_and_save (widget);
395 cut_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
398 warning_dialog (GTK_WIDGET (menuitem),
400 "cut unimplemented\n", False, 1);
405 copy_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
408 warning_dialog (GTK_WIDGET (menuitem),
410 "copy unimplemented\n", False, 1);
415 paste_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
418 warning_dialog (GTK_WIDGET (menuitem),
420 "paste unimplemented\n", False, 1);
425 about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
428 char *s = strdup (screensaver_id + 4);
431 s2 = strchr (s, ',');
435 sprintf (buf, "%s\n%s\n\n"
436 "For updates, check http://www.jwz.org/xscreensaver/",
440 warning_dialog (GTK_WIDGET (menuitem), buf, False, 100);
445 doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
447 /* prefs_pair *pair = (prefs_pair *) client_data; */
448 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
450 saver_preferences *p = pair->a;
453 if (!p->help_url || !*p->help_url)
455 warning_dialog (GTK_WIDGET (menuitem),
457 "No Help URL has been specified.\n", False, 100);
461 help_command = (char *) malloc (strlen (p->load_url_command) +
462 (strlen (p->help_url) * 2) + 20);
463 strcpy (help_command, "( ");
464 sprintf (help_command + strlen(help_command),
465 p->load_url_command, p->help_url, p->help_url);
466 strcat (help_command, " ) &");
467 system (help_command);
473 activate_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
475 run_cmd (GTK_WIDGET (menuitem), XA_ACTIVATE, 0);
480 lock_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
482 run_cmd (GTK_WIDGET (menuitem), XA_LOCK, 0);
487 kill_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
489 run_cmd (GTK_WIDGET (menuitem), XA_EXIT, 0);
494 restart_menu_cb (GtkWidget *widget, gpointer user_data)
497 run_cmd (GTK_WIDGET (widget), XA_RESTART, 0);
499 apply_changes_and_save (GTK_WIDGET (widget));
500 xscreensaver_command (gdk_display, XA_EXIT, 0, False, NULL);
502 system ("xscreensaver -nosplash &");
507 static int _selected_hack_number = -1;
510 selected_hack_number (GtkWidget *toplevel)
513 GtkViewport *vp = GTK_VIEWPORT (name_to_widget (toplevel, "viewport"));
514 GtkList *list_widget = GTK_LIST (GTK_BIN(vp)->child);
515 GList *slist = list_widget->selection;
516 GtkWidget *selected = (slist ? GTK_WIDGET (slist->data) : 0);
517 int which = (selected
518 ? gtk_list_child_position (list_widget, GTK_WIDGET (selected))
522 return _selected_hack_number;
528 demo_write_init_file (GtkWidget *widget, saver_preferences *p)
530 if (!write_init_file (p, short_version, False))
534 const char *f = init_file_name();
536 warning_dialog (widget,
537 "Error:\n\nCouldn't determine init file name!\n",
541 char *b = (char *) malloc (strlen(f) + 1024);
542 sprintf (b, "Error:\n\nCouldn't write %s\n", f);
543 warning_dialog (widget, b, False, 100);
552 apply_changes_and_save_1 (GtkWidget *widget)
554 /* prefs_pair *pair = (prefs_pair *) client_data; */
555 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
556 saver_preferences *p = pair->a;
557 GtkList *list_widget =
558 GTK_LIST (name_to_widget (widget, "list"));
559 int which = selected_hack_number (widget);
561 GtkEntry *cmd = GTK_ENTRY (name_to_widget (widget, "cmd_text"));
562 GtkToggleButton *enabled =
563 GTK_TOGGLE_BUTTON (name_to_widget (widget, "enabled"));
564 GtkCombo *vis = GTK_COMBO (name_to_widget (widget, "visual_combo"));
566 Bool enabled_p = gtk_toggle_button_get_active (enabled);
567 const char *visual = gtk_entry_get_text (GTK_ENTRY (GTK_COMBO (vis)->entry));
568 const char *command = gtk_entry_get_text (cmd);
573 if (which < 0) return -1;
575 if (maybe_reload_init_file (widget, pair) != 0)
578 /* Sanity-check and canonicalize whatever the user typed into the combo box.
580 if (!strcasecmp (visual, "")) visual = "";
581 else if (!strcasecmp (visual, "any")) visual = "";
582 else if (!strcasecmp (visual, "default")) visual = "Default";
583 else if (!strcasecmp (visual, "default-n")) visual = "Default-N";
584 else if (!strcasecmp (visual, "default-i")) visual = "Default-I";
585 else if (!strcasecmp (visual, "best")) visual = "Best";
586 else if (!strcasecmp (visual, "mono")) visual = "Mono";
587 else if (!strcasecmp (visual, "monochrome")) visual = "Mono";
588 else if (!strcasecmp (visual, "gray")) visual = "Gray";
589 else if (!strcasecmp (visual, "grey")) visual = "Gray";
590 else if (!strcasecmp (visual, "color")) visual = "Color";
591 else if (!strcasecmp (visual, "gl")) visual = "GL";
592 else if (!strcasecmp (visual, "staticgray")) visual = "StaticGray";
593 else if (!strcasecmp (visual, "staticcolor")) visual = "StaticColor";
594 else if (!strcasecmp (visual, "truecolor")) visual = "TrueColor";
595 else if (!strcasecmp (visual, "grayscale")) visual = "GrayScale";
596 else if (!strcasecmp (visual, "greyscale")) visual = "GrayScale";
597 else if (!strcasecmp (visual, "pseudocolor")) visual = "PseudoColor";
598 else if (!strcasecmp (visual, "directcolor")) visual = "DirectColor";
599 else if (1 == sscanf (visual, " %ld %c", &id, &c)) ;
600 else if (1 == sscanf (visual, " 0x%lx %c", &id, &c)) ;
603 gdk_beep (); /* unparsable */
605 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry), "Any");
608 ensure_selected_item_visible (GTK_WIDGET (list_widget));
610 if (!p->screenhacks[which]->visual)
611 p->screenhacks[which]->visual = strdup ("");
612 if (!p->screenhacks[which]->command)
613 p->screenhacks[which]->command = strdup ("");
615 if (p->screenhacks[which]->enabled_p != enabled_p ||
616 !!strcasecmp (p->screenhacks[which]->visual, visual) ||
617 !!strcasecmp (p->screenhacks[which]->command, command))
619 /* Something was changed -- store results into the struct,
622 free (p->screenhacks[which]->visual);
623 free (p->screenhacks[which]->command);
624 p->screenhacks[which]->visual = strdup (visual);
625 p->screenhacks[which]->command = strdup (command);
626 p->screenhacks[which]->enabled_p = enabled_p;
628 return demo_write_init_file (widget, p);
631 /* No changes made */
635 void prefs_ok_cb (GtkButton *button, gpointer user_data);
638 apply_changes_and_save (GtkWidget *widget)
640 prefs_ok_cb ((GtkButton *) widget, 0);
641 return apply_changes_and_save_1 (widget);
646 run_this_cb (GtkButton *button, gpointer user_data)
648 int which = selected_hack_number (GTK_WIDGET (button));
649 if (which < 0) return;
650 if (0 == apply_changes_and_save (GTK_WIDGET (button)))
651 run_hack (GTK_WIDGET (button), which, True);
656 manual_cb (GtkButton *button, gpointer user_data)
658 /* prefs_pair *pair = (prefs_pair *) client_data; */
659 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
660 saver_preferences *p = pair->a;
661 GtkList *list_widget =
662 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
663 int which = selected_hack_number (GTK_WIDGET (button));
664 char *name, *name2, *cmd, *s;
665 if (which < 0) return;
666 apply_changes_and_save (GTK_WIDGET (button));
667 ensure_selected_item_visible (GTK_WIDGET (list_widget));
669 name = strdup (p->screenhacks[which]->command);
671 while (isspace (*name2)) name2++;
673 while (*s && !isspace (*s)) s++;
675 s = strrchr (name2, '/');
678 cmd = get_string_resource ("manualCommand", "ManualCommand");
681 char *cmd2 = (char *) malloc (strlen (cmd) + strlen (name2) + 100);
683 sprintf (cmd2 + strlen (cmd2),
685 name2, name2, name2, name2);
686 strcat (cmd2, " ) &");
692 warning_dialog (GTK_WIDGET (button),
693 "Error:\n\nno `manualCommand' resource set.",
702 run_next_cb (GtkButton *button, gpointer user_data)
704 /* prefs_pair *pair = (prefs_pair *) client_data; */
705 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
706 saver_preferences *p = pair->a;
708 GtkList *list_widget =
709 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
710 int which = selected_hack_number (GTK_WIDGET (button));
717 if (which >= p->screenhacks_count)
720 apply_changes_and_save (GTK_WIDGET (button));
721 gtk_list_select_item (GTK_LIST (list_widget), which);
722 ensure_selected_item_visible (GTK_WIDGET (list_widget));
723 populate_demo_window (GTK_WIDGET (button), which, pair);
724 run_hack (GTK_WIDGET (button), which, False);
729 run_prev_cb (GtkButton *button, gpointer user_data)
731 /* prefs_pair *pair = (prefs_pair *) client_data; */
732 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
733 saver_preferences *p = pair->a;
735 GtkList *list_widget =
736 GTK_LIST (name_to_widget (GTK_WIDGET (button), "list"));
737 int which = selected_hack_number (GTK_WIDGET (button));
740 which = p->screenhacks_count - 1;
745 which = p->screenhacks_count - 1;
747 apply_changes_and_save (GTK_WIDGET (button));
748 gtk_list_select_item (GTK_LIST (list_widget), which);
749 ensure_selected_item_visible (GTK_WIDGET (list_widget));
750 populate_demo_window (GTK_WIDGET (button), which, pair);
751 run_hack (GTK_WIDGET (button), which, False);
755 /* Helper for the text fields that contain time specifications:
756 this parses the text, and does error checking.
759 hack_time_text (GtkWidget *widget, const char *line, Time *store, Bool sec_p)
764 value = parse_time ((char *) line, sec_p, True);
765 value *= 1000; /* Time measures in microseconds */
771 "Unparsable time format: \"%s\"\n",
773 warning_dialog (widget, b, False, 100);
782 prefs_ok_cb (GtkButton *button, gpointer user_data)
784 /* prefs_pair *pair = (prefs_pair *) client_data; */
785 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
787 saver_preferences *p = pair->a;
788 saver_preferences *p2 = pair->b;
789 Bool changed = False;
791 # define SECONDS(field, name) \
792 hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
793 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
797 # define MINUTES(field, name) \
798 hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
799 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
803 # define INTEGER(field, name) do { \
804 char *line = gtk_entry_get_text (\
805 GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))); \
806 unsigned int value; \
810 else if (sscanf (line, "%u%c", &value, &c) != 1) \
813 sprintf (b, "Error:\n\n" "Not an integer: \"%s\"\n", line); \
814 warning_dialog (GTK_WIDGET (button), b, False, 100); \
820 # define CHECKBOX(field, name) \
821 field = gtk_toggle_button_get_active (\
822 GTK_TOGGLE_BUTTON (name_to_widget (GTK_WIDGET(button), (name))))
824 MINUTES (&p2->timeout, "timeout_text");
825 MINUTES (&p2->cycle, "cycle_text");
826 SECONDS (&p2->fade_seconds, "fade_text");
827 INTEGER (&p2->fade_ticks, "ticks_text");
828 MINUTES (&p2->lock_timeout, "lock_text");
829 SECONDS (&p2->passwd_timeout, "pass_text");
830 CHECKBOX (p2->verbose_p, "verbose_button");
831 CHECKBOX (p2->install_cmap_p, "install_button");
832 CHECKBOX (p2->fade_p, "fade_button");
833 CHECKBOX (p2->unfade_p, "unfade_button");
834 CHECKBOX (p2->lock_p, "lock_button");
841 # define COPY(field) \
842 if (p->field != p2->field) changed = True; \
848 COPY(passwd_timeout);
852 COPY(install_cmap_p);
858 populate_prefs_page (GTK_WIDGET (button), pair);
861 demo_write_init_file (GTK_WIDGET (button), p);
866 prefs_cancel_cb (GtkButton *button, gpointer user_data)
868 /* prefs_pair *pair = (prefs_pair *) client_data; */
869 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
872 populate_prefs_page (GTK_WIDGET (button), pair);
877 pref_changed_cb (GtkButton *button, gpointer user_data)
879 if (! initializing_p)
880 apply_changes_and_save (GTK_WIDGET (button));
885 list_doubleclick_cb (GtkWidget *button, GdkEventButton *event,
886 gpointer client_data)
888 if (event->type == GDK_2BUTTON_PRESS)
890 GtkList *list = GTK_LIST (name_to_widget (button, "list"));
891 int which = gtk_list_child_position (list, GTK_WIDGET (button));
894 run_hack (GTK_WIDGET (button), which, True);
902 list_select_cb (GtkList *list, GtkWidget *child)
904 /* prefs_pair *pair = (prefs_pair *) client_data; */
905 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
907 int which = gtk_list_child_position (list, GTK_WIDGET (child));
908 apply_changes_and_save (GTK_WIDGET (list));
909 populate_demo_window (GTK_WIDGET (list), which, pair);
913 list_unselect_cb (GtkList *list, GtkWidget *child)
915 /* prefs_pair *pair = (prefs_pair *) client_data; */
916 prefs_pair *pair = global_prefs_pair; /* I hate C so much... */
918 apply_changes_and_save (GTK_WIDGET (list));
919 populate_demo_window (GTK_WIDGET (list), -1, pair);
923 /* Populating the various widgets
927 /* Formats a `Time' into "H:MM:SS". (Time is microseconds.)
930 format_time (char *buf, Time time)
933 unsigned int h = 0, m = 0;
944 sprintf (buf, "%u:%02u:%02u", h, m, s);
949 make_pretty_name (const char *shell_command)
951 char *s = strdup (shell_command);
955 for (s2 = s; *s2; s2++) /* truncate at first whitespace */
962 s2 = strrchr (s, '/'); /* if pathname, take last component */
970 if (strlen (s) > 50) /* 51 is hereby defined as "unreasonable" */
973 sprintf (res_name, "hacks.%s.name", s); /* resource? */
974 s2 = get_string_resource (res_name, res_name);
978 for (s2 = s; *s2; s2++) /* if it has any capitals, return it */
979 if (*s2 >= 'A' && *s2 <= 'Z')
982 if (s[0] >= 'a' && s[0] <= 'z') /* else cap it */
984 if (s[0] == 'X' && s[1] >= 'a' && s[1] <= 'z') /* (magic leading X) */
990 /* Finds the number of the last hack to run, and makes that item be
994 scroll_to_current_hack (GtkWidget *toplevel, prefs_pair *pair)
996 saver_preferences *p = pair->a;
999 unsigned long nitems, bytesafter;
1001 Display *dpy = gdk_display;
1005 if (XGetWindowProperty (dpy, RootWindow (dpy, 0), /* always screen #0 */
1006 XA_SCREENSAVER_STATUS,
1007 0, 3, False, XA_INTEGER,
1008 &type, &format, &nitems, &bytesafter,
1009 (unsigned char **) &data)
1011 && type == XA_INTEGER
1014 which = (int) data[2] - 1;
1016 if (data) free (data);
1021 list = GTK_LIST (name_to_widget (toplevel, "list"));
1022 apply_changes_and_save (toplevel);
1023 if (which < p->screenhacks_count)
1025 gtk_list_select_item (list, which);
1026 ensure_selected_item_visible (GTK_WIDGET (list));
1027 populate_demo_window (toplevel, which, pair);
1034 populate_hack_list (GtkWidget *toplevel, prefs_pair *pair)
1036 saver_preferences *p = pair->a;
1037 GtkList *list = GTK_LIST (name_to_widget (toplevel, "list"));
1038 screenhack **hacks = p->screenhacks;
1041 for (h = hacks; h && *h; h++)
1044 char *pretty_name = (h[0]->name
1045 ? strdup (h[0]->name)
1046 : make_pretty_name (h[0]->command));
1048 line = gtk_list_item_new_with_label (pretty_name);
1051 gtk_container_add (GTK_CONTAINER (list), line);
1052 gtk_signal_connect (GTK_OBJECT (line), "button_press_event",
1053 GTK_SIGNAL_FUNC (list_doubleclick_cb),
1056 GTK_WIDGET (GTK_BIN(line)->child)->style =
1057 gtk_style_copy (GTK_WIDGET (text_line)->style);
1059 gtk_widget_show (line);
1062 gtk_signal_connect (GTK_OBJECT (list), "select_child",
1063 GTK_SIGNAL_FUNC (list_select_cb),
1065 gtk_signal_connect (GTK_OBJECT (list), "unselect_child",
1066 GTK_SIGNAL_FUNC (list_unselect_cb),
1072 populate_prefs_page (GtkWidget *top, prefs_pair *pair)
1074 saver_preferences *p = pair->a;
1077 format_time (s, p->timeout);
1078 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "timeout_text")), s);
1079 format_time (s, p->cycle);
1080 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "cycle_text")), s);
1081 format_time (s, p->lock_timeout);
1082 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "lock_text")), s);
1083 format_time (s, p->passwd_timeout);
1084 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "pass_text")), s);
1085 format_time (s, p->fade_seconds);
1086 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "fade_text")), s);
1087 sprintf (s, "%u", p->fade_ticks);
1088 gtk_entry_set_text (GTK_ENTRY (name_to_widget (top, "ticks_text")), s);
1090 gtk_toggle_button_set_active (
1091 GTK_TOGGLE_BUTTON (name_to_widget (top, "verbose_button")),
1093 gtk_toggle_button_set_active (
1094 GTK_TOGGLE_BUTTON (name_to_widget (top, "install_button")),
1096 gtk_toggle_button_set_active (
1097 GTK_TOGGLE_BUTTON (name_to_widget (top, "fade_button")),
1099 gtk_toggle_button_set_active (
1100 GTK_TOGGLE_BUTTON (name_to_widget (top, "unfade_button")),
1102 gtk_toggle_button_set_active (
1103 GTK_TOGGLE_BUTTON (name_to_widget (top, "lock_button")),
1108 Bool found_any_writable_cells = False;
1109 Display *dpy = gdk_display;
1110 int nscreens = ScreenCount(dpy);
1112 for (i = 0; i < nscreens; i++)
1114 Screen *s = ScreenOfDisplay (dpy, i);
1115 if (has_writable_cells (s, DefaultVisualOfScreen (s)))
1117 found_any_writable_cells = True;
1122 gtk_widget_set_sensitive (
1123 GTK_WIDGET (name_to_widget (top, "fade_label")),
1124 found_any_writable_cells);
1125 gtk_widget_set_sensitive (
1126 GTK_WIDGET (name_to_widget (top, "ticks_label")),
1127 found_any_writable_cells);
1128 gtk_widget_set_sensitive (
1129 GTK_WIDGET (name_to_widget (top, "fade_text")),
1130 found_any_writable_cells);
1131 gtk_widget_set_sensitive (
1132 GTK_WIDGET (name_to_widget (top, "ticks_text")),
1133 found_any_writable_cells);
1134 gtk_widget_set_sensitive (
1135 GTK_WIDGET (name_to_widget (top, "install_button")),
1136 found_any_writable_cells);
1137 gtk_widget_set_sensitive (
1138 GTK_WIDGET (name_to_widget (top, "fade_button")),
1139 found_any_writable_cells);
1140 gtk_widget_set_sensitive (
1141 GTK_WIDGET (name_to_widget (top, "unfade_button")),
1142 found_any_writable_cells);
1149 sensitize_demo_widgets (GtkWidget *toplevel, Bool sensitive_p)
1151 const char *names[] = { "cmd_label", "cmd_text", "enabled",
1152 "visual", "visual_combo",
1155 for (i = 0; i < countof(names); i++)
1157 GtkWidget *w = name_to_widget (toplevel, names[i]);
1158 gtk_widget_set_sensitive (GTK_WIDGET(w), sensitive_p);
1161 /* I don't know how to handle these yet... */
1163 const char *names2[] = { "cut_menu", "copy_menu", "paste_menu" };
1164 for (i = 0; i < countof(names2); i++)
1166 GtkWidget *w = name_to_widget (toplevel, names2[i]);
1167 gtk_widget_set_sensitive (GTK_WIDGET(w), False);
1173 /* Even though we've given these text fields a maximum number of characters,
1174 their default size is still about 30 characters wide -- so measure out
1175 a string in their font, and resize them to just fit that.
1178 fix_text_entry_sizes (GtkWidget *toplevel)
1180 const char *names[] = { "timeout_text", "cycle_text", "fade_text",
1181 "ticks_text", "lock_text", "pass_text" };
1186 for (i = 0; i < countof(names); i++)
1188 w = GTK_WIDGET (name_to_widget (toplevel, names[i]));
1190 width = gdk_text_width (w->style->font, "00:00:00_", 9);
1191 gtk_widget_set_usize (w, width, -2);
1194 /* Now fix the size of the combo box.
1196 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "visual_combo"));
1197 w = GTK_COMBO (w)->entry;
1198 width = gdk_text_width (w->style->font, "PseudoColor___", 14);
1199 gtk_widget_set_usize (w, width, -2);
1202 /* Now fix the size of the list.
1204 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel), "list"));
1205 width = gdk_text_width (w->style->font, "nnnnnnnnnnnnnnnnnnnnnn", 22);
1206 gtk_widget_set_usize (w, width, -2);
1213 /* Pixmaps for the up and down arrow buttons (yeah, this is sleazy...)
1216 static char *up_arrow_xpm[] = {
1239 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1240 the end of the array (Gtk 1.2.5.) */
1241 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1242 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1245 static char *down_arrow_xpm[] = {
1268 /* Need these here because gdk_pixmap_create_from_xpm_d() walks off
1269 the end of the array (Gtk 1.2.5.) */
1270 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000",
1271 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
1275 pixmapify_button (GtkWidget *toplevel, int down_p)
1279 GtkWidget *pixmapwid;
1283 w = GTK_WIDGET (name_to_widget (GTK_WIDGET (toplevel),
1284 (down_p ? "next" : "prev")));
1285 style = gtk_widget_get_style (w);
1287 pixmap = gdk_pixmap_create_from_xpm_d (w->window, &mask,
1288 &style->bg[GTK_STATE_NORMAL],
1290 ? (gchar **) down_arrow_xpm
1291 : (gchar **) up_arrow_xpm));
1292 pixmapwid = gtk_pixmap_new (pixmap, mask);
1293 gtk_widget_show (pixmapwid);
1294 gtk_container_remove (GTK_CONTAINER (w), GTK_BIN (w)->child);
1295 gtk_container_add (GTK_CONTAINER (w), pixmapwid);
1299 map_next_button_cb (GtkWidget *w, gpointer user_data)
1301 pixmapify_button (w, 1);
1305 map_prev_button_cb (GtkWidget *w, gpointer user_data)
1307 pixmapify_button (w, 0);
1312 /* Work around a Gtk bug that causes label widgets to wrap text too early.
1316 you_are_not_a_unique_or_beautiful_snowflake (GtkWidget *label,
1317 GtkAllocation *allocation,
1321 GtkWidgetAuxInfo *aux_info;
1323 aux_info = gtk_object_get_data (GTK_OBJECT (label), "gtk-aux-info");
1325 aux_info->width = allocation->width;
1326 aux_info->height = -2;
1330 gtk_widget_size_request (label, &req);
1334 /* Feel the love. Thanks to Nat Friedman for finding this workaround.
1337 eschew_gtk_lossage (GtkWidget *toplevel)
1339 GtkWidgetAuxInfo *aux_info;
1340 GtkWidget *label = GTK_WIDGET (name_to_widget (toplevel, "doc"));
1342 aux_info = g_new0 (GtkWidgetAuxInfo, 1);
1343 aux_info->width = label->allocation.width;
1344 aux_info->height = -2;
1348 gtk_object_set_data (GTK_OBJECT (label), "gtk-aux-info", aux_info);
1350 gtk_signal_connect (GTK_OBJECT (label), "size_allocate",
1351 you_are_not_a_unique_or_beautiful_snowflake, NULL);
1353 gtk_widget_queue_resize (label);
1358 get_hack_blurb (screenhack *hack)
1361 char *prog_name = strdup (hack->command);
1362 char *pretty_name = (hack->name
1363 ? strdup (hack->name)
1364 : make_pretty_name (hack->command));
1365 char doc_name[255], doc_class[255];
1368 for (s = prog_name; *s && !isspace(*s); s++)
1371 s = strrchr (prog_name, '/');
1372 if (s) strcpy (prog_name, s+1);
1374 sprintf (doc_name, "hacks.%s.documentation", pretty_name);
1375 sprintf (doc_class, "hacks.%s.documentation", prog_name);
1379 doc_string = get_string_resource (doc_name, doc_class);
1382 for (s = doc_string; *s; s++)
1386 /* skip over whitespace at beginning of line */
1388 while (*s && (*s == ' ' || *s == '\t'))
1391 else if (*s == ' ' || *s == '\t')
1393 /* compress all other horizontal whitespace. */
1396 for (s2 = s; *s2 && (*s2 == ' ' || *s2 == '\t'); s2++)
1398 if (s2 > s) strcpy (s, s2);
1403 while (*s && isspace (*s)) /* Strip trailing whitespace */
1406 /* Delete whitespace at end of each line. */
1407 for (; s > doc_string; s--)
1408 if (*s == '\n' && (s[-1] == ' ' || s[-1] == '\t'))
1411 s2 > doc_string && (*s2 == ' ' || *s2 == '\t');
1415 if (s2 < s) strcpy (s2, s);
1419 /* Delete leading blank lines. */
1420 for (s = doc_string; *s == '\n'; s++)
1422 if (s > doc_string) strcpy (doc_string, s);
1426 static int doc_installed = 0;
1427 if (doc_installed == 0)
1429 if (get_boolean_resource ("hacks.documentation.isInstalled",
1430 "hacks.documentation.isInstalled"))
1436 if (doc_installed < 0)
1438 strdup ("Error:\n\n"
1439 "The documentation strings do not appear to be "
1440 "installed. This is probably because there is "
1441 "an \"XScreenSaver\" app-defaults file installed "
1442 "that is from an older version of the program. "
1443 "To fix this problem, delete that file, or "
1444 "install a current version (either will work.)");
1446 doc_string = strdup ("");
1454 populate_demo_window (GtkWidget *toplevel, int which, prefs_pair *pair)
1456 saver_preferences *p = pair->a;
1457 screenhack *hack = (which >= 0 && which < p->screenhacks_count
1458 ? p->screenhacks[which] : 0);
1459 GtkFrame *frame = GTK_FRAME (name_to_widget (toplevel, "frame"));
1460 GtkLabel *doc = GTK_LABEL (name_to_widget (toplevel, "doc"));
1461 GtkEntry *cmd = GTK_ENTRY (name_to_widget (toplevel, "cmd_text"));
1462 GtkToggleButton *enabled =
1463 GTK_TOGGLE_BUTTON (name_to_widget (toplevel, "enabled"));
1464 GtkCombo *vis = GTK_COMBO (name_to_widget (toplevel, "visual_combo"));
1466 char *pretty_name = (hack
1468 ? strdup (hack->name)
1469 : make_pretty_name (hack->command))
1471 char *doc_string = hack ? get_hack_blurb (hack) : 0;
1473 gtk_frame_set_label (frame, (pretty_name ? pretty_name : ""));
1474 gtk_label_set_text (doc, (doc_string ? doc_string : ""));
1475 gtk_entry_set_text (cmd, (hack ? hack->command : ""));
1476 gtk_entry_set_position (cmd, 0);
1477 gtk_toggle_button_set_active (enabled, (hack ? hack->enabled_p : False));
1478 gtk_entry_set_text (GTK_ENTRY (GTK_COMBO (vis)->entry),
1480 ? (hack->visual && *hack->visual
1485 gtk_container_resize_children (GTK_CONTAINER (GTK_WIDGET (doc)->parent));
1487 sensitize_demo_widgets (toplevel, (hack ? True : False));
1489 if (pretty_name) free (pretty_name);
1490 if (doc_string) free (doc_string);
1492 _selected_hack_number = which;
1497 widget_deleter (GtkWidget *widget, gpointer data)
1499 /* #### Well, I want to destroy these widgets, but if I do that, they get
1500 referenced again, and eventually I get a SEGV. So instead of
1501 destroying them, I'll just hide them, and leak a bunch of memory
1502 every time the disk file changes. Go go go Gtk!
1504 #### Ok, that's a lie, I get a crash even if I just hide the widget
1505 and don't ever delete it. Fuck!
1508 gtk_widget_destroy (widget);
1510 gtk_widget_hide (widget);
1516 maybe_reload_init_file (GtkWidget *widget, prefs_pair *pair)
1519 saver_preferences *p = pair->a;
1521 static Bool reentrant_lock = False;
1522 if (reentrant_lock) return 0;
1523 reentrant_lock = True;
1525 if (init_file_changed_p (p))
1527 const char *f = init_file_name();
1532 if (!f || !*f) return 0;
1533 b = (char *) malloc (strlen(f) + 1024);
1536 "file \"%s\" has changed, reloading.\n",
1538 warning_dialog (widget, b, False, 100);
1543 which = selected_hack_number (widget);
1544 list = GTK_LIST (name_to_widget (widget, "list"));
1545 gtk_container_foreach (GTK_CONTAINER (list), widget_deleter, NULL);
1546 populate_hack_list (widget, pair);
1547 gtk_list_select_item (list, which);
1548 populate_prefs_page (widget, pair);
1549 populate_demo_window (widget, which, pair);
1550 ensure_selected_item_visible (GTK_WIDGET (list));
1555 reentrant_lock = False;
1561 /* The main demo-mode command loop.
1566 mapper (XrmDatabase *db, XrmBindingList bindings, XrmQuarkList quarks,
1567 XrmRepresentation *type, XrmValue *value, XPointer closure)
1570 for (i = 0; quarks[i]; i++)
1572 if (bindings[i] == XrmBindTightly)
1573 fprintf (stderr, (i == 0 ? "" : "."));
1574 else if (bindings[i] == XrmBindLoosely)
1575 fprintf (stderr, "*");
1577 fprintf (stderr, " ??? ");
1578 fprintf(stderr, "%s", XrmQuarkToString (quarks[i]));
1581 fprintf (stderr, ": %s\n", (char *) value->addr);
1589 the_network_is_not_the_computer (GtkWidget *parent)
1591 Display *dpy = gdk_display;
1592 char *rversion, *ruser, *rhost;
1593 char *luser, *lhost;
1595 struct passwd *p = getpwuid (getuid ());
1596 const char *d = DisplayString (dpy);
1598 # if defined(HAVE_UNAME)
1600 if (uname (&uts) < 0)
1601 lhost = "<UNKNOWN>";
1603 lhost = uts.nodename;
1605 strcpy (lhost, getenv("SYS$NODE"));
1606 # else /* !HAVE_UNAME && !VMS */
1607 strcat (lhost, "<UNKNOWN>");
1608 # endif /* !HAVE_UNAME && !VMS */
1610 if (p && p->pw_name)
1615 server_xscreensaver_version (dpy, &rversion, &ruser, &rhost);
1617 /* Make a buffer that's big enough for a number of copies of all the
1618 strings, plus some. */
1619 msg = (char *) malloc (10 * ((rversion ? strlen(rversion) : 0) +
1620 (ruser ? strlen(ruser) : 0) +
1621 (rhost ? strlen(rhost) : 0) +
1628 if (!rversion || !*rversion)
1632 "The XScreenSaver daemon doesn't seem to be running\n"
1633 "on display \"%s\". Launch it now?",
1636 else if (p && ruser && *ruser && !!strcmp (ruser, p->pw_name))
1638 /* Warn that the two processes are running as different users.
1642 "%s is running as user \"%s\" on host \"%s\".\n"
1643 "But the xscreensaver managing display \"%s\"\n"
1644 "is running as user \"%s\" on host \"%s\".\n"
1646 "Since they are different users, they won't be reading/writing\n"
1647 "the same ~/.xscreensaver file, so %s isn't\n"
1648 "going to work right.\n"
1650 "You should either re-run %s as \"%s\", or re-run\n"
1651 "xscreensaver as \"%s\".\n"
1653 "Restart the xscreensaver daemon now?\n",
1654 progname, luser, lhost,
1656 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1658 progname, (ruser ? ruser : "???"),
1661 else if (rhost && *rhost && !!strcmp (rhost, lhost))
1663 /* Warn that the two processes are running on different hosts.
1667 "%s is running as user \"%s\" on host \"%s\".\n"
1668 "But the xscreensaver managing display \"%s\"\n"
1669 "is running as user \"%s\" on host \"%s\".\n"
1671 "If those two machines don't share a file system (that is,\n"
1672 "if they don't see the same ~%s/.xscreensaver file) then\n"
1673 "%s won't work right.\n"
1675 "Restart the daemon on \"%s\" as \"%s\" now?\n",
1676 progname, luser, lhost,
1678 (ruser ? ruser : "???"), (rhost ? rhost : "???"),
1683 else if (!!strcmp (rversion, short_version))
1685 /* Warn that the version numbers don't match.
1689 "This is %s version %s.\n"
1690 "But the xscreensaver managing display \"%s\"\n"
1691 "is version %s. This could cause problems.\n"
1693 "Restart the xscreensaver daemon now?\n",
1694 progname, short_version,
1701 warning_dialog (parent, msg, True, 1);
1707 /* We use this error handler so that X errors are preceeded by the name
1708 of the program that generated them.
1711 demo_ehandler (Display *dpy, XErrorEvent *error)
1713 fprintf (stderr, "\nX error in %s:\n", progname);
1714 if (XmuPrintDefaultErrorMessage (dpy, error, stderr))
1717 fprintf (stderr, " (nonfatal.)\n");
1722 /* We use this error handler so that Gtk/Gdk errors are preceeded by the name
1723 of the program that generated them; and also that we can ignore one
1724 particular bogus error message that Gdk madly spews.
1727 g_log_handler (const gchar *log_domain, GLogLevelFlags log_level,
1728 const gchar *message, gpointer user_data)
1730 /* Ignore the message "Got event for unknown window: 0x...".
1731 Apparently some events are coming in for the xscreensaver window
1732 (presumably reply events related to the ClientMessage) and Gdk
1733 feels the need to complain about them. So, just suppress any
1734 messages that look like that one.
1736 if (strstr (message, "unknown window"))
1739 fprintf (stderr, "%s: %s-%s: %s%s", blurb(), log_domain,
1740 (log_level == G_LOG_LEVEL_ERROR ? "error" :
1741 log_level == G_LOG_LEVEL_CRITICAL ? "critical" :
1742 log_level == G_LOG_LEVEL_WARNING ? "warning" :
1743 log_level == G_LOG_LEVEL_MESSAGE ? "message" :
1744 log_level == G_LOG_LEVEL_INFO ? "info" :
1745 log_level == G_LOG_LEVEL_DEBUG ? "debug" : "???"),
1747 ((!*message || message[strlen(message)-1] != '\n')
1752 static char *defaults[] = {
1753 #include "XScreenSaver_ad.h"
1758 #ifdef HAVE_CRAPPLET
1759 static struct poptOption crapplet_options[] = {
1760 {NULL, '\0', 0, NULL, 0}
1762 #endif /* HAVE_CRAPPLET */
1766 fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n", \
1771 map_window_cb (GtkWidget *w, gpointer user_data)
1773 Boolean oi = initializing_p;
1774 initializing_p = True;
1775 eschew_gtk_lossage (w);
1776 ensure_selected_item_visible (GTK_WIDGET(name_to_widget(w, "list")));
1777 initializing_p = oi;
1782 main (int argc, char **argv)
1785 prefs_pair Pair, *pair;
1786 saver_preferences P, P2, *p, *p2;
1790 Widget toplevel_shell;
1791 GtkWidget *gtk_window;
1792 char *real_progname = argv[0];
1795 initializing_p = True;
1797 s = strrchr (real_progname, '/');
1798 if (s) real_progname = s+1;
1805 memset (p, 0, sizeof (*p));
1806 memset (p2, 0, sizeof (*p2));
1808 global_prefs_pair = pair; /* I hate C so much... */
1810 progname = real_progname;
1812 short_version = (char *) malloc (5);
1813 memcpy (short_version, screensaver_id + 17, 4);
1814 short_version [4] = 0;
1817 /* Register our error message logger for every ``log domain'' known.
1818 There's no way to do this globally, so I grepped the Gtk/Gdk sources
1819 for all of the domains that seem to be in use.
1822 const char * const domains[] = { "Gtk", "Gdk", "GLib", "GModule",
1823 "GThread", "Gnome", "GnomeUI", 0 };
1824 for (i = 0; domains[i]; i++)
1825 g_log_set_handler (domains[i], G_LOG_LEVEL_MASK, g_log_handler, 0);
1828 /* This is gross, but Gtk understands --display and not -display...
1830 for (i = 1; i < argc; i++)
1831 if (argv[i][0] && argv[i][1] &&
1832 !strncmp(argv[i], "-display", strlen(argv[i])))
1833 argv[i] = "--display";
1836 /* We need to parse this arg really early... Sigh. */
1837 for (i = 1; i < argc; i++)
1839 (!strcmp(argv[i], "--crapplet") ||
1840 !strcmp(argv[i], "--capplet")))
1842 # ifdef HAVE_CRAPPLET
1845 for (j = i; j < argc; j++) /* remove it from the list */
1846 argv[j] = argv[j+1];
1849 # else /* !HAVE_CRAPPLET */
1850 fprintf (stderr, "%s: not compiled with --crapplet support\n",
1854 # endif /* !HAVE_CRAPPLET */
1857 /* Let Gtk open the X connection, then initialize Xt to use that
1858 same connection. Doctor Frankenstein would be proud.
1860 # ifdef HAVE_CRAPPLET
1863 GnomeClient *client;
1864 GnomeClientFlags flags = 0;
1866 int init_results = gnome_capplet_init ("screensaver-properties",
1868 argc, argv, NULL, 0, NULL);
1870 0 upon successful initialization;
1871 1 if --init-session-settings was passed on the cmdline;
1872 2 if --ignore was passed on the cmdline;
1875 So the 1 signifies just to init the settings, and quit, basically.
1876 (Meaning launch the xscreensaver daemon.)
1879 if (init_results < 0)
1882 g_error ("An initialization error occurred while "
1883 "starting xscreensaver-capplet.\n");
1885 fprintf (stderr, "%s: gnome_capplet_init failed: %d\n",
1886 real_progname, init_results);
1891 client = gnome_master_client ();
1894 flags = gnome_client_get_flags (client);
1896 if (flags & GNOME_CLIENT_IS_CONNECTED)
1899 gnome_startup_acquire_token ("GNOME_SCREENSAVER_PROPERTIES",
1900 gnome_client_get_id (client));
1903 char *session_args[20];
1905 session_args[i++] = real_progname;
1906 session_args[i++] = "--capplet";
1907 session_args[i++] = "--init-session-settings";
1908 session_args[i] = 0;
1909 gnome_client_set_priority (client, 20);
1910 gnome_client_set_restart_style (client, GNOME_RESTART_ANYWAY);
1911 gnome_client_set_restart_command (client, i, session_args);
1915 gnome_client_set_restart_style (client, GNOME_RESTART_NEVER);
1918 gnome_client_flush (client);
1921 if (init_results == 1)
1923 system ("xscreensaver -nosplash &");
1929 # endif /* HAVE_CRAPPLET */
1931 gtk_init (&argc, &argv);
1935 /* We must read exactly the same resources as xscreensaver.
1936 That means we must have both the same progclass *and* progname,
1937 at least as far as the resource database is concerned. So,
1938 put "xscreensaver" in argv[0] while initializing Xt.
1940 argv[0] = "xscreensaver";
1944 /* Teach Xt to use the Display that Gtk/Gdk have already opened.
1946 XtToolkitInitialize ();
1947 app = XtCreateApplicationContext ();
1949 XtAppSetFallbackResources (app, defaults);
1950 XtDisplayInitialize (app, dpy, progname, progclass, 0, 0, &argc, argv);
1951 toplevel_shell = XtAppCreateShell (progname, progclass,
1952 applicationShellWidgetClass,
1955 dpy = XtDisplay (toplevel_shell);
1956 db = XtDatabase (dpy);
1957 XtGetApplicationNameAndClass (dpy, &progname, &progclass);
1958 XSetErrorHandler (demo_ehandler);
1961 /* After doing Xt-style command-line processing, complain about any
1962 unrecognized command-line arguments.
1964 for (i = 1; i < argc; i++)
1967 if (s[0] == '-' && s[1] == '-')
1969 if (!strcmp (s, "-prefs"))
1971 else if (crapplet_p)
1972 /* There are lots of random args that we don't care about when we're
1973 started as a crapplet, so just ignore unknown args in that case. */
1977 fprintf (stderr, "%s: unknown option: %s\n", real_progname, argv[i]);
1983 /* Load the init file, which may end up consulting the X resource database
1984 and the site-wide app-defaults file. Note that at this point, it's
1985 important that `progname' be "xscreensaver", rather than whatever
1992 /* Now that Xt has been initialized, and the resources have been read,
1993 we can set our `progname' variable to something more in line with
1996 progname = real_progname;
2000 /* Print out all the resources we read. */
2002 XrmName name = { 0 };
2003 XrmClass class = { 0 };
2005 XrmEnumerateDatabase (db, &name, &class, XrmEnumAllLevels, mapper,
2011 /* Intern the atoms that xscreensaver_command() needs.
2013 XA_VROOT = XInternAtom (dpy, "__SWM_VROOT", False);
2014 XA_SCREENSAVER = XInternAtom (dpy, "SCREENSAVER", False);
2015 XA_SCREENSAVER_VERSION = XInternAtom (dpy, "_SCREENSAVER_VERSION",False);
2016 XA_SCREENSAVER_STATUS = XInternAtom (dpy, "_SCREENSAVER_STATUS", False);
2017 XA_SCREENSAVER_ID = XInternAtom (dpy, "_SCREENSAVER_ID", False);
2018 XA_SCREENSAVER_RESPONSE = XInternAtom (dpy, "_SCREENSAVER_RESPONSE", False);
2019 XA_SELECT = XInternAtom (dpy, "SELECT", False);
2020 XA_DEMO = XInternAtom (dpy, "DEMO", False);
2021 XA_ACTIVATE = XInternAtom (dpy, "ACTIVATE", False);
2022 XA_BLANK = XInternAtom (dpy, "BLANK", False);
2023 XA_LOCK = XInternAtom (dpy, "LOCK", False);
2024 XA_EXIT = XInternAtom (dpy, "EXIT", False);
2025 XA_RESTART = XInternAtom (dpy, "RESTART", False);
2028 /* Create the window and all its widgets.
2030 gtk_window = create_xscreensaver_demo ();
2031 toplevel_widget = gtk_window;
2033 /* Set the window's title. */
2036 char *v = (char *) strdup(strchr(screensaver_id, ' '));
2037 char *s1, *s2, *s3, *s4;
2038 s1 = (char *) strchr(v, ' '); s1++;
2039 s2 = (char *) strchr(s1, ' ');
2040 s3 = (char *) strchr(v, '('); s3++;
2041 s4 = (char *) strchr(s3, ')');
2044 sprintf (title, "%.50s %.50s, %.50s", progclass, s1, s3);
2045 gtk_window_set_title (GTK_WINDOW (gtk_window), title);
2049 /* Various other widget initializations...
2051 gtk_signal_connect (GTK_OBJECT (gtk_window), "delete_event",
2052 GTK_SIGNAL_FUNC (wm_close_cb), NULL);
2054 populate_hack_list (gtk_window, pair);
2055 populate_prefs_page (gtk_window, pair);
2056 sensitize_demo_widgets (gtk_window, False);
2057 fix_text_entry_sizes (gtk_window);
2058 scroll_to_current_hack (gtk_window, pair);
2060 gtk_signal_connect (
2061 GTK_OBJECT (name_to_widget (GTK_WIDGET (gtk_window), "list")),
2062 "map", GTK_SIGNAL_FUNC(map_window_cb), 0);
2063 gtk_signal_connect (
2064 GTK_OBJECT (name_to_widget (GTK_WIDGET (gtk_window), "prev")),
2065 "map", GTK_SIGNAL_FUNC(map_prev_button_cb), 0);
2066 gtk_signal_connect (
2067 GTK_OBJECT (name_to_widget (GTK_WIDGET (gtk_window), "next")),
2068 "map", GTK_SIGNAL_FUNC(map_next_button_cb), 0);
2071 /* Handle the -prefs command-line argument. */
2074 GtkNotebook *notebook =
2075 GTK_NOTEBOOK (name_to_widget (gtk_window, "notebook"));
2076 gtk_notebook_set_page (notebook, 1);
2079 # ifdef HAVE_CRAPPLET
2083 GtkWidget *top_vbox;
2085 capplet = capplet_widget_new ();
2087 top_vbox = GTK_BIN (gtk_window)->child;
2089 gtk_widget_ref (top_vbox);
2090 gtk_container_remove (GTK_CONTAINER (gtk_window), top_vbox);
2091 GTK_OBJECT_SET_FLAGS (top_vbox, GTK_FLOATING);
2093 /* In crapplet-mode, take off the menubar. */
2094 gtk_widget_hide (name_to_widget (gtk_window, "menubar"));
2096 gtk_container_add (GTK_CONTAINER (capplet), top_vbox);
2097 gtk_widget_show (capplet);
2098 gtk_widget_hide (gtk_window);
2100 /* Hook up the Control Center's redundant Help button, too. */
2101 gtk_signal_connect (GTK_OBJECT (capplet), "help",
2102 GTK_SIGNAL_FUNC (doc_menu_cb), 0);
2104 /* Issue any warnings about the running xscreensaver daemon. */
2105 the_network_is_not_the_computer (top_vbox);
2108 # endif /* HAVE_CRAPPLET */
2110 gtk_widget_show (gtk_window);
2112 /* Issue any warnings about the running xscreensaver daemon. */
2113 the_network_is_not_the_computer (gtk_window);
2116 /* Run the Gtk event loop, and not the Xt event loop. This means that
2117 if there were Xt timers or fds registered, they would never get serviced,
2118 and if there were any Xt widgets, they would never have events delivered.
2119 Fortunately, we're using Gtk for all of the UI, and only initialized
2120 Xt so that we could process the command line and use the X resource
2123 initializing_p = False;
2125 # ifdef HAVE_CRAPPLET
2127 capplet_gtk_main ();
2129 # endif /* HAVE_CRAPPLET */
2135 #endif /* HAVE_GTK -- whole file */