http://ftp.ksu.edu.tw/FTP/FreeBSD/distfiles/xscreensaver-4.20.tar.gz
[xscreensaver] / driver / demo-Gtk.c
index f220ab0dd558268b70cade6add9e7ba37df02b9f..f9c066c3d81dc0c280350e8c1aeb42025ad49e3b 100644 (file)
@@ -1,5 +1,5 @@
 /* demo-Gtk.c --- implements the interactive demo-mode and options dialogs.
- * xscreensaver, Copyright (c) 1993-2004 Jamie Zawinski <jwz@jwz.org>
+ * xscreensaver, Copyright (c) 1993-2005 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
 #include <gdk/gdkx.h>
 
 #ifdef HAVE_GTK2
-#include <glade/glade-xml.h>
-#endif /* HAVE_GTK2 */
+# include <glade/glade-xml.h>
+# include <gmodule.h>
+#else  /* !HAVE_GTK2 */
+# define G_MODULE_EXPORT /**/
+#endif /* !HAVE_GTK2 */
 
 #if defined(DEFAULT_ICONDIR) && !defined(GLADE_DIR)
 # define GLADE_DIR DEFAULT_ICONDIR
@@ -216,7 +219,7 @@ static int maybe_reload_init_file (state *);
 static void await_xscreensaver (state *);
 
 static void schedule_preview (state *, const char *cmd);
-static void kill_preview_subproc (state *);
+static void kill_preview_subproc (state *, Bool reset_p);
 static void schedule_preview_check (state *);
 
 
@@ -577,6 +580,11 @@ run_cmd (state *s, Atom command, int arg)
 
   flush_dialog_changes_and_save (s);
   status = xscreensaver_command (GDK_DISPLAY(), command, arg, False, &err);
+
+  /* Kludge: ignore the spurious "window unexpectedly deleted" errors... */
+  if (status < 0 && err && strstr (err, "unexpectedly deleted"))
+    status = 0;
+
   if (status < 0)
     {
       char buf [255];
@@ -613,14 +621,18 @@ run_hack (state *s, int list_elt, Bool report_errors_p)
 
 \f
 /* Button callbacks
+
+   According to Eric Lassauge, this G_MODULE_EXPORT crud is needed to make
+   libglade work on Cygwin; apparently all Glade callbacks need this magic
+   extra declaration.  I do not pretend to understand.
  */
 
-void
+G_MODULE_EXPORT void
 exit_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
   flush_dialog_changes_and_save (s);
-  kill_preview_subproc (s);
+  kill_preview_subproc (s, False);
   gtk_main_quit ();
 }
 
@@ -634,7 +646,7 @@ wm_toplevel_close_cb (GtkWidget *widget, GdkEvent *event, gpointer data)
 }
 
 
-void
+G_MODULE_EXPORT void
 about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
 {
   char msg [2048];
@@ -653,9 +665,9 @@ about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
      look as good in the plain-old default Latin1 "C" locale.)
    */
 #ifdef HAVE_GTK2
-  sprintf(copy, ("Copyright \xC2\xA9 1991-2004 %s"), s);
+  sprintf(copy, ("Copyright \xC2\xA9 1991-2005 %s"), s);
 #else  /* !HAVE_GTK2 */
-  sprintf(copy, ("Copyright \251 1991-2004 %s"), s);
+  sprintf(copy, ("Copyright \251 1991-2005 %s"), s);
 #endif /* !HAVE_GTK2 */
 
   sprintf (msg, "%s\n\n%s", copy, desc);
@@ -761,7 +773,7 @@ about_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
 }
 
 
-void
+G_MODULE_EXPORT void
 doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -777,17 +789,18 @@ doc_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
     }
 
   help_command = (char *) malloc (strlen (p->load_url_command) +
-                                 (strlen (p->help_url) * 2) + 20);
+                                 (strlen (p->help_url) * 4) + 20);
   strcpy (help_command, "( ");
   sprintf (help_command + strlen(help_command),
-           p->load_url_command, p->help_url, p->help_url);
+           p->load_url_command,
+           p->help_url, p->help_url, p->help_url, p->help_url);
   strcat (help_command, " ) &");
   system (help_command);
   free (help_command);
 }
 
 
-void
+G_MODULE_EXPORT void
 activate_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -795,7 +808,7 @@ activate_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
 }
 
 
-void
+G_MODULE_EXPORT void
 lock_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -803,7 +816,7 @@ lock_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
 }
 
 
-void
+G_MODULE_EXPORT void
 kill_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -811,7 +824,7 @@ kill_menu_cb (GtkMenuItem *menuitem, gpointer user_data)
 }
 
 
-void
+G_MODULE_EXPORT void
 restart_menu_cb (GtkWidget *widget, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -934,7 +947,7 @@ demo_write_init_file (state *s, saver_preferences *p)
 }
 
 
-void
+G_MODULE_EXPORT void
 run_this_cb (GtkButton *button, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -945,7 +958,7 @@ run_this_cb (GtkButton *button, gpointer user_data)
 }
 
 
-void
+G_MODULE_EXPORT void
 manual_cb (GtkButton *button, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -972,7 +985,7 @@ manual_cb (GtkButton *button, gpointer user_data)
   cmd = get_string_resource ("manualCommand", "ManualCommand");
   if (cmd)
     {
-      char *cmd2 = (char *) malloc (strlen (cmd) + strlen (name2) + 100);
+      char *cmd2 = (char *) malloc (strlen (cmd) + (strlen (name2) * 4) + 100);
       strcpy (cmd2, "( ");
       sprintf (cmd2 + strlen (cmd2),
                cmd,
@@ -1018,7 +1031,7 @@ force_list_select_item (state *s, GtkWidget *list, int list_elt, Bool scroll_p)
 }
 
 
-void
+G_MODULE_EXPORT void
 run_next_cb (GtkButton *button, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -1047,7 +1060,7 @@ run_next_cb (GtkButton *button, gpointer user_data)
 }
 
 
-void
+G_MODULE_EXPORT void
 run_prev_cb (GtkButton *button, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -1549,7 +1562,7 @@ flush_popup_changes_and_save (state *s)
 }
 
 
-void
+G_MODULE_EXPORT void
 pref_changed_cb (GtkWidget *widget, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -1561,7 +1574,7 @@ pref_changed_cb (GtkWidget *widget, gpointer user_data)
     }
 }
 
-gboolean
+G_MODULE_EXPORT gboolean
 pref_changed_event_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data)
 {
   pref_changed_cb (widget, user_data);
@@ -1613,7 +1626,7 @@ mode_menu_item_cb (GtkWidget *widget, gpointer user_data)
 }
 
 
-void
+G_MODULE_EXPORT void
 switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page,
                 gint page_num, gpointer user_data)
 {
@@ -1856,7 +1869,7 @@ browse_image_dir_close (GtkWidget *widget, GdkEvent *event, gpointer user_data)
 }
 
 
-void
+G_MODULE_EXPORT void
 browse_image_dir_cb (GtkButton *button, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -1892,7 +1905,7 @@ browse_image_dir_cb (GtkButton *button, gpointer user_data)
 }
 
 
-void
+G_MODULE_EXPORT  void
 settings_cb (GtkButton *button, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -1915,7 +1928,7 @@ settings_sync_cmd_text (state *s)
 # endif /* HAVE_XML */
 }
 
-void
+G_MODULE_EXPORT void
 settings_adv_cb (GtkButton *button, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -1926,7 +1939,7 @@ settings_adv_cb (GtkButton *button, gpointer user_data)
   gtk_notebook_set_page (notebook, 1);
 }
 
-void
+G_MODULE_EXPORT void
 settings_std_cb (GtkButton *button, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -1939,7 +1952,7 @@ settings_std_cb (GtkButton *button, gpointer user_data)
   gtk_notebook_set_page (notebook, 0);
 }
 
-void
+G_MODULE_EXPORT void
 settings_switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page,
                          gint page_num, gpointer user_data)
 {
@@ -1963,14 +1976,14 @@ settings_switch_page_cb (GtkNotebook *notebook, GtkNotebookPage *page,
 
 
 
-void
+G_MODULE_EXPORT void
 settings_cancel_cb (GtkButton *button, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
   gtk_widget_hide (s->popup_widget);
 }
 
-void
+G_MODULE_EXPORT void
 settings_ok_cb (GtkButton *button, gpointer user_data)
 {
   state *s = global_state_kludge;  /* I hate C so much... */
@@ -2009,7 +2022,7 @@ server_current_hack (void)
   Atom type;
   int format;
   unsigned long nitems, bytesafter;
-  CARD32 *data = 0;
+  unsigned char *dataP = 0;
   Display *dpy = GDK_DISPLAY();
   int hack_number = -1;
 
@@ -2017,14 +2030,17 @@ server_current_hack (void)
                           XA_SCREENSAVER_STATUS,
                           0, 3, False, XA_INTEGER,
                           &type, &format, &nitems, &bytesafter,
-                          (unsigned char **) &data)
+                          &dataP)
       == Success
       && type == XA_INTEGER
       && nitems >= 3
-      && data)
-    hack_number = (int) data[2] - 1;
+      && dataP)
+    {
+      CARD32 *data = (CARD32 *) dataP;
+      hack_number = (int) data[2] - 1;
+    }
 
-  if (data) free (data);
+  if (dataP) XFree (dataP);
 
   return hack_number;
 }
@@ -2427,6 +2443,7 @@ populate_prefs_page (state *s)
 
   {
     Bool found_any_writable_cells = False;
+    Bool fading_possible = False;
     Bool dpms_supported = False;
 
     Display *dpy = GDK_DISPLAY();
@@ -2442,8 +2459,9 @@ populate_prefs_page (state *s)
          }
       }
 
+    fading_possible = found_any_writable_cells;
 #ifdef HAVE_XF86VMODE_GAMMA
-    found_any_writable_cells = True;  /* if we can gamma fade, go for it */
+    fading_possible = True;
 #endif
 
 #ifdef HAVE_DPMS_EXTENSION
@@ -2480,14 +2498,14 @@ populate_prefs_page (state *s)
 
     /* Colormaps
      */
-    SENSITIZE ("cmap_frame",      found_any_writable_cells);
+    SENSITIZE ("cmap_frame",      found_any_writable_cells || fading_possible);
     SENSITIZE ("install_button",  found_any_writable_cells);
-    SENSITIZE ("fade_button",     found_any_writable_cells);
-    SENSITIZE ("unfade_button",   found_any_writable_cells);
+    SENSITIZE ("fade_button",     fading_possible);
+    SENSITIZE ("unfade_button",   fading_possible);
 
-    SENSITIZE ("fade_label",      (found_any_writable_cells &&
+    SENSITIZE ("fade_label",      (fading_possible &&
                                    (p->fade_p || p->unfade_p)));
-    SENSITIZE ("fade_spinbutton", (found_any_writable_cells &&
+    SENSITIZE ("fade_spinbutton", (fading_possible &&
                                    (p->fade_p || p->unfade_p)));
 
 # undef SENSITIZE
@@ -3110,6 +3128,32 @@ clear_preview_window (state *s)
 }
 
 
+static void
+reset_preview_window (state *s)
+{
+  /* On some systems (most recently, MacOS X) OpenGL programs get confused
+     when you kill one and re-start another on the same window.  So maybe
+     it's best to just always destroy and recreate the preview window
+     when changing hacks, instead of always trying to reuse the same one?
+   */
+  GtkWidget *pr = name_to_widget (s, "preview");
+  if (GTK_WIDGET_REALIZED (pr))
+    {
+      Window oid = (pr->window ? GDK_WINDOW_XWINDOW (pr->window) : 0);
+      Window id;
+      gtk_widget_hide (pr);
+      gtk_widget_unrealize (pr);
+      gtk_widget_realize (pr);
+      gtk_widget_show (pr);
+      id = (pr->window ? GDK_WINDOW_XWINDOW (pr->window) : 0);
+      if (s->debug_p)
+        fprintf (stderr, "%s: window id 0x%X -> 0x%X\n", blurb(),
+                 (unsigned int) oid,
+                 (unsigned int) id);
+    }
+}
+
+
 static void
 fix_preview_visual (state *s)
 {
@@ -3324,7 +3368,7 @@ get_best_gl_visual (state *s)
 
 
 static void
-kill_preview_subproc (state *s)
+kill_preview_subproc (state *s, Bool reset_p)
 {
   s->running_preview_error_p = False;
 
@@ -3370,6 +3414,12 @@ kill_preview_subproc (state *s)
     }
 
   reap_zombies (s);
+
+  if (reset_p)
+    {
+      reset_preview_window (s);
+      clear_preview_window (s);
+    }
 }
 
 
@@ -3386,13 +3436,17 @@ launch_preview_subproc (state *s)
   const char *cmd = s->desired_preview_cmd;
 
   GtkWidget *pr = name_to_widget (s, "preview");
-  GdkWindow *window = pr->window;
+  GdkWindow *window;
+
+  reset_preview_window (s);
+
+  window = pr->window;
 
   s->running_preview_error_p = False;
 
   if (s->preview_suppressed_p)
     {
-      kill_preview_subproc (s);
+      kill_preview_subproc (s, False);
       goto DONE;
     }
 
@@ -3412,7 +3466,7 @@ launch_preview_subproc (state *s)
                (unsigned int) id);
     }
 
-  kill_preview_subproc (s);
+  kill_preview_subproc (s, False);
   if (! new_cmd)
     {
       s->running_preview_error_p = True;
@@ -3559,7 +3613,7 @@ update_subproc_timer (gpointer data)
 {
   state *s = (state *) data;
   if (! s->desired_preview_cmd)
-    kill_preview_subproc (s);
+    kill_preview_subproc (s, True);
   else if (!s->running_preview_cmd ||
            !!strcmp (s->desired_preview_cmd, s->running_preview_cmd))
     launch_preview_subproc (s);
@@ -3682,7 +3736,7 @@ screen_blanked_p (void)
   Atom type;
   int format;
   unsigned long nitems, bytesafter;
-  CARD32 *data = 0;
+  unsigned char *dataP = 0;
   Display *dpy = GDK_DISPLAY();
   Bool blanked_p = False;
 
@@ -3690,14 +3744,17 @@ screen_blanked_p (void)
                           XA_SCREENSAVER_STATUS,
                           0, 3, False, XA_INTEGER,
                           &type, &format, &nitems, &bytesafter,
-                          (unsigned char **) &data)
+                          &dataP)
       == Success
       && type == XA_INTEGER
       && nitems >= 3
-      && data)
-    blanked_p = (data[0] == XA_BLANK || data[0] == XA_LOCK);
+      && dataP)
+    {
+      Atom *data = (Atom *) dataP;
+      blanked_p = (data[0] == XA_BLANK || data[0] == XA_LOCK);
+    }
 
-  if (data) free (data);
+  if (dataP) XFree (dataP);
 
   return blanked_p;
 }
@@ -3715,7 +3772,7 @@ check_blanked_timer (gpointer data)
     {
       if (s->debug_p)
         fprintf (stderr, "%s: screen is blanked: killing preview\n", blurb());
-      kill_preview_subproc (s);
+      kill_preview_subproc (s, True);
     }
 
   return True;  /* re-execute timer */
@@ -3896,7 +3953,7 @@ demo_ehandler (Display *dpy, XErrorEvent *error)
   state *s = global_state_kludge;  /* I hate C so much... */
   fprintf (stderr, "\nX error in %s:\n", blurb());
   XmuPrintDefaultErrorMessage (dpy, error, stderr);
-  kill_preview_subproc (s);
+  kill_preview_subproc (s, False);
   exit (-1);
   return 0;
 }
@@ -4598,7 +4655,7 @@ main (int argc, char **argv)
 # endif /* HAVE_CRAPPLET */
     gtk_main ();
 
-  kill_preview_subproc (s);
+  kill_preview_subproc (s, False);
   exit (0);
 }