http://ftp.x.org/contrib/applications/xscreensaver-3.23.tar.gz
[xscreensaver] / driver / demo-Gtk.c
index 2b07ab0ce892fa2905e0b3c2b43d820d111b6e4b..e027622726179ec964043ce7a4009d6e2a588bb6 100644 (file)
@@ -1,5 +1,5 @@
 /* demo-Gtk.c --- implements the interactive demo-mode and options dialogs.
- * xscreensaver, Copyright (c) 1993-1998 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1993-1999 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -101,7 +101,7 @@ static void populate_demo_window (GtkWidget *toplevel,
                                   int which, prefs_pair *pair);
 static void populate_prefs_page (GtkWidget *top, prefs_pair *pair);
 static int apply_changes_and_save (GtkWidget *widget);
-
+static int maybe_reload_init_file (GtkWidget *widget, prefs_pair *pair);
 
 \f
 /* Some random utility functions
@@ -186,6 +186,9 @@ ensure_selected_item_visible (GtkWidget *widget)
   ratio_t = ((double) child_y) / ((double) children_h);
   ratio_b = ((double) child_y + child_h) / ((double) children_h);
 
+  if (adj->upper == 0.0)  /* no items in list */
+    return;
+
   if (ratio_t < (adj->value / adj->upper) ||
       ratio_b > ((adj->value + adj->page_size) / adj->upper))
     {
@@ -279,9 +282,7 @@ warning_dialog (GtkWidget *parent, const char *message, int center)
   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (dialog)->action_area),
                       label, TRUE, TRUE, 0);
 
-  ok = gtk_button_new_with_label (
-                          get_string_resource ("warning_dialog.ok.label",
-                                               "warning_dialog.Button.Label"));
+  ok = gtk_button_new_with_label ("OK");
   gtk_container_add (GTK_CONTAINER (label), ok);
 
   gtk_window_set_position (GTK_WINDOW (dialog), GTK_WIN_POS_CENTER);
@@ -332,7 +333,7 @@ run_hack (GtkWidget *widget, int which, Bool report_errors_p)
   if (which < 0) return;
   apply_changes_and_save (widget);
   if (report_errors_p)
-    run_cmd (widget, XA_ACTIVATE, 0);
+    run_cmd (widget, XA_DEMO, which + 1);
   else
     {
       char *s = 0;
@@ -542,6 +543,9 @@ apply_changes_and_save (GtkWidget *widget)
 
   if (which < 0) return -1;
 
+  if (maybe_reload_init_file (widget, pair) != 0)
+    return 1;
+
   /* Sanity-check and canonicalize whatever the user typed into the combo box.
    */
   if      (!strcasecmp (visual, ""))                   visual = "";
@@ -713,7 +717,7 @@ run_prev_cb (GtkButton *button, gpointer user_data)
    this parses the text, and does error checking.
  */
 static void 
-hack_time_text (const char *line, Time *store, Bool sec_p)
+hack_time_text (GtkWidget *widget, const char *line, Time *store, Bool sec_p)
 {
   if (*line)
     {
@@ -721,7 +725,14 @@ hack_time_text (const char *line, Time *store, Bool sec_p)
       value = parse_time ((char *) line, sec_p, True);
       value *= 1000;   /* Time measures in microseconds */
       if (value < 0)
-        /* gdk_beep () */;
+       {
+         char b[255];
+         sprintf (b,
+                  "Error:\n\n"
+                  "Unparsable time format: \"%s\"\n",
+                  line);
+         warning_dialog (widget, b, 100);
+       }
       else
        *store = value;
     }
@@ -739,13 +750,13 @@ prefs_ok_cb (GtkButton *button, gpointer user_data)
   Bool changed = False;
 
 # define SECONDS(field, name) \
-  hack_time_text (gtk_entry_get_text (\
+  hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
                     GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
                   (field), \
                   True)
 
 # define MINUTES(field, name) \
-  hack_time_text (gtk_entry_get_text (\
+  hack_time_text (GTK_WIDGET(button), gtk_entry_get_text (\
                     GTK_ENTRY (name_to_widget (GTK_WIDGET(button), (name)))), \
                   (field), \
                   False)
@@ -758,7 +769,11 @@ prefs_ok_cb (GtkButton *button, gpointer user_data)
     if (! *line) \
       ; \
     else if (sscanf (line, "%u%c", &value, &c) != 1) \
-     gdk_beep(); \
+      { \
+       char b[255]; \
+       sprintf (b, "Error:\n\n" "Not an integer: \"%s\"\n", line); \
+       warning_dialog (GTK_WIDGET (button), b, 100); \
+      } \
    else \
      *(field) = value; \
   } while(0)
@@ -931,6 +946,7 @@ make_pretty_name (const char *shell_command)
 static void
 scroll_to_current_hack (GtkWidget *toplevel, prefs_pair *pair)
 {
+  saver_preferences *p =  pair->a;
   Atom type;
   int format;
   unsigned long nitems, bytesafter;
@@ -957,9 +973,12 @@ scroll_to_current_hack (GtkWidget *toplevel, prefs_pair *pair)
 
   list = GTK_LIST (name_to_widget (toplevel, "list"));
   apply_changes_and_save (toplevel);
-  gtk_list_select_item (list, which);
-  ensure_selected_item_visible (GTK_WIDGET (list));
-  populate_demo_window (toplevel, which, pair);
+  if (which < p->screenhacks_count)
+    {
+      gtk_list_select_item (list, which);
+      ensure_selected_item_visible (GTK_WIDGET (list));
+      populate_demo_window (toplevel, which, pair);
+    }
 }
 
 
@@ -972,7 +991,7 @@ populate_hack_list (GtkWidget *toplevel, prefs_pair *pair)
   screenhack **hacks = p->screenhacks;
   screenhack **h;
 
-  for (h = hacks; *h; h++)
+  for (h = hacks; h && *h; h++)
     {
       GtkWidget *line;
       char *pretty_name = (h[0]->name
@@ -1183,6 +1202,7 @@ static char *down_arrow_xpm[] = {
   "+   c #D6D6D6",
   "@   c #000000",
 
+  "               ",
   " ------------- ",
   " -+++++++++++@ ",
   "  -+++++++++@  ",
@@ -1383,7 +1403,8 @@ static void
 populate_demo_window (GtkWidget *toplevel, int which, prefs_pair *pair)
 {
   saver_preferences *p = pair->a;
-  screenhack *hack = (which >= 0 ? p->screenhacks[which] : 0);
+  screenhack *hack = (which >= 0 && which < p->screenhacks_count
+                     ? p->screenhacks[which] : 0);
   GtkFrame *frame = GTK_FRAME (name_to_widget (toplevel, "frame"));
   GtkLabel *doc = GTK_LABEL (name_to_widget (toplevel, "doc"));
   GtkEntry *cmd = GTK_ENTRY (name_to_widget (toplevel, "cmd_text"));
@@ -1421,6 +1442,69 @@ populate_demo_window (GtkWidget *toplevel, int which, prefs_pair *pair)
 }
 
 
+static void
+widget_deleter (GtkWidget *widget, gpointer data)
+{
+  /* #### Well, I want to destroy these widgets, but if I do that, they get
+     referenced again, and eventually I get a SEGV.  So instead of
+     destroying them, I'll just hide them, and leak a bunch of memory
+     every time the disk file changes.  Go go go Gtk!
+
+     #### Ok, that's a lie, I get a crash even if I just hide the widget
+     and don't ever delete it.  Fuck!
+   */
+#if 0
+  gtk_widget_destroy (widget);
+#else
+  gtk_widget_hide (widget);
+#endif
+}
+
+
+static int
+maybe_reload_init_file (GtkWidget *widget, prefs_pair *pair)
+{
+  int status = 0;
+  saver_preferences *p =  pair->a;
+
+  static Bool reentrant_lock = False;
+  if (reentrant_lock) return 0;
+  reentrant_lock = True;
+
+  if (init_file_changed_p (p))
+    {
+      const char *f = init_file_name();
+      char *b;
+      int which;
+      GtkList *list;
+
+      if (!f || !*f) return 0;
+      b = (char *) malloc (strlen(f) + 1024);
+      sprintf (b,
+               "Warning:\n\n"
+               "file \"%s\" has changed, reloading.\n",
+               f);
+      warning_dialog (widget, b, 100);
+      free (b);
+
+      load_init_file (p);
+
+      which = selected_hack_number (widget);
+      list = GTK_LIST (name_to_widget (widget, "list"));
+      gtk_container_foreach (GTK_CONTAINER (list), widget_deleter, NULL);
+      populate_hack_list (widget, pair);
+      gtk_list_select_item (list, which);
+      populate_prefs_page (widget, pair);
+      populate_demo_window (widget, which, pair);
+      ensure_selected_item_visible (GTK_WIDGET (list));
+
+      status = 1;
+    }
+
+  reentrant_lock = False;
+  return status;
+}
+
 
 \f
 /* The main demo-mode command loop.
@@ -1714,6 +1798,7 @@ main (int argc, char **argv)
        prefs = True;
       else
        {
+         fprintf (stderr, "%s: unknown option: %s\n", real_progname, argv[i]);
          fprintf (stderr, "usage: %s [ -display dpy-string ] [ -prefs ]\n",
                   real_progname);
          exit (1);