From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / screenhack.c
index 443d3f423745562b89165e8df92fa620caad08ec..4850911db59bb5415c966d692e7905d17a846f90 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1992-2008 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1992-2017 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
           Called when a keyboard or mouse event arrives.
           Return True if you handle it in some way, False otherwise.
 
-      static void YOURNAME_event (Display *, Window, void *closure);
+      static void YOURNAME_free (Display *, Window, void *closure);
 
            Called when you are done: free everything you've allocated,
-           including your private `state' structure.
+           including your private `state' structure.  
+
+           NOTE: this is called in windowed-mode when the user typed
+           'q' or clicks on the window's close box; but when
+           xscreensaver terminates this screenhack, it does so by
+           killing the process with SIGSTOP.  So this callback is
+           mostly useless.
 
       static char YOURNAME_defaults [] = { "...", "...", ... , 0 };
 
@@ -68,7 +74,7 @@
       - Do not use global variables: all such info must be stored in the
         private `state' structure.
 
-      - Do not static function-local variables, either.  Put it in `state'.
+      - Do not use static function-local variables, either.  Put it in `state'.
 
         Assume that there are N independent runs of this code going in the
         same address space at the same time: they must not affect each other.
@@ -77,7 +83,6 @@
         of your screen saver module.  See .../hacks/config/README for details.
  */
 
-#define DEBUG_TIMING
 #define DEBUG_PAIR
 
 #include <stdio.h>
 #include "screenhackI.h"
 #include "version.h"
 #include "vroot.h"
+#include "fps.h"
+
+#ifdef HAVE_RECORD_ANIM
+# include "recanim.h"
+#endif
 
 #ifndef _XSCREENSAVER_VROOT_H_
 # error Error!  You have an old version of vroot.h!  Check -I args.
@@ -136,18 +146,27 @@ static XrmOptionDescRec default_options [] = {
   { "-noinstall",".installColormap",   XrmoptionNoArg, "False" },
   { "-visual", ".visualID",            XrmoptionSepArg, 0 },
   { "-window-id", ".windowID",         XrmoptionSepArg, 0 },
+  { "-fps",    ".doFPS",               XrmoptionNoArg, "True" },
+  { "-no-fps",  ".doFPS",              XrmoptionNoArg, "False" },
 
 # ifdef DEBUG_PAIR
   { "-pair",   ".pair",                XrmoptionNoArg, "True" },
 # endif /* DEBUG_PAIR */
+
+# ifdef HAVE_RECORD_ANIM
+  { "-record-animation", ".recordAnim", XrmoptionSepArg, 0 },
+# endif /* HAVE_RECORD_ANIM */
+
   { 0, 0, 0, 0 }
 };
 
 static char *default_defaults[] = {
   ".root:              false",
-  "*geometry:          600x480", /* this should be .geometry, but nooooo... */
+  "*geometry:          1280x720", /* this should be .geometry, but noooo... */
   "*mono:              false",
   "*installColormap:   false",
+  "*doFPS:             false",
+  "*multiSample:       false",
   "*visualID:          default",
   "*windowID:          ",
   "*desktopGrabber:    xscreensaver-getimage %s",
@@ -158,6 +177,7 @@ static XrmOptionDescRec *merged_options;
 static int merged_options_size;
 static char **merged_defaults;
 
+
 static void
 merge_options (void)
 {
@@ -211,6 +231,8 @@ merge_options (void)
          strcat (newr, oldr);
          *s = newr;
        }
+      else
+        *s = strdup (*s);
   }
 }
 
@@ -407,65 +429,6 @@ fix_fds (void)
 }
 
 
-#ifdef DEBUG_TIMING
-
-static void
-check_timing (unsigned long delay)
-{
-  static unsigned long frame_count = 0;
-  static unsigned long delay_sum = 0;
-  static struct timeval prev1 = { 0, };
-  static struct timeval prev2 = { 0, };
-  struct timeval now;
-  double uprev1, uprev2, unow;
-
-# ifdef GETTIMEOFDAY_TWO_ARGS
-  gettimeofday (&now, 0);
-# else
-  gettimeofday (&now);
-# endif
-
-  if (prev1.tv_sec == 0)
-    prev1 = prev2 = now;
-
-  frame_count++;
-
-  uprev1 = prev1.tv_sec + ((double) prev1.tv_usec * 0.000001);
-  uprev2 = prev2.tv_sec + ((double) prev2.tv_usec * 0.000001);
-  unow   =  now.tv_sec  + ((double)   now.tv_usec * 0.000001);
-
-  if (unow >= uprev1 + 1.5)
-    fprintf (stderr,
-             "%s: warning: blocked event processing for %.1f secs!\n",
-             progname, unow - uprev1);
-  prev1 = now;
-
-  if (unow >= uprev2 + 10.0)
-    {
-      double fps   = frame_count / (unow - uprev2);
-      double elapsed = unow - uprev2;
-      double slept = (delay_sum * 0.000001);
-      double sleep_ratio = slept / elapsed;
-
-      if (sleep_ratio < 0.10) {
-        fprintf (stderr, 
-                 "%s: warning: only %.0f%% idle over the"
-                 " last %2.0f secs (at %.1f FPS)\n",
-                 progname, 100 * sleep_ratio, elapsed, fps);
-      }
-
-      prev2 = now;
-      frame_count = 0;
-      delay_sum = 0;
-    }
-
-  delay_sum += delay;
-}
-
-#else  /* !DEBUG_TIMING */
-# define check_timing(delay) /**/
-#endif /* !DEBUG_TIMING */
-
 static Boolean
 screenhack_table_handle_events (Display *dpy,
                                 const struct xscreensaver_function_table *ft,
@@ -491,7 +454,7 @@ screenhack_table_handle_events (Display *dpy,
             ft->reshape_cb (dpy, window, closure,
                             event.xconfigure.width, event.xconfigure.height);
 #ifdef DEBUG_PAIR
-          if (event.xany.window == window2)
+          if (window2 && event.xany.window == window2)
             ft->reshape_cb (dpy, window2, closure2,
                             event.xconfigure.width, event.xconfigure.height);
 #endif
@@ -500,7 +463,7 @@ screenhack_table_handle_events (Display *dpy,
                (! (event.xany.window == window
                    ? ft->event_cb (dpy, window, closure, &event)
 #ifdef DEBUG_PAIR
-                   : event.xany.window == window2
+                   : (window2 && event.xany.window == window2)
                    ? ft->event_cb (dpy, window2, closure2, &event)
 #endif
                    : 0)))
@@ -517,27 +480,37 @@ screenhack_table_handle_events (Display *dpy,
 static Boolean
 usleep_and_process_events (Display *dpy,
                            const struct xscreensaver_function_table *ft,
-                           Window window, void *closure, unsigned long delay
+                           Window window, fps_state *fpst, void *closure,
+                           unsigned long delay
 #ifdef DEBUG_PAIR
-                         , Window window2, void *closure2, unsigned long delay2
+                         , Window window2, fps_state *fpst2, void *closure2,
+                           unsigned long delay2
 #endif
+# ifdef HAVE_RECORD_ANIM
+                         , record_anim_state *anim_state
+# endif
                            )
 {
   do {
-    unsigned long quantum = 100000;  /* 1/10th second */
+    unsigned long quantum = 33333;  /* 30 fps */
     if (quantum > delay) 
       quantum = delay;
     delay -= quantum;
 
     XSync (dpy, False);
-    if (quantum > 0)
-      usleep (quantum);
 
-    check_timing (quantum);
+#ifdef HAVE_RECORD_ANIM
+    if (anim_state) screenhack_record_anim (anim_state);
+#endif
 
-    /* The above isn't quite right in pair-mode: we always run both windows
-       with the timing of window 2.  But, it's just a debugging hack, so
-       that doesn't really matter that much... */
+    if (quantum > 0)
+      {
+        usleep (quantum);
+        if (fpst) fps_slept (fpst, quantum);
+#ifdef DEBUG_PAIR
+        if (fpst2) fps_slept (fpst2, quantum);
+#endif
+      }
 
     if (! screenhack_table_handle_events (dpy, ft, window, closure
 #ifdef DEBUG_PAIR
@@ -551,11 +524,22 @@ usleep_and_process_events (Display *dpy,
 }
 
 
+static void
+screenhack_do_fps (Display *dpy, Window w, fps_state *fpst, void *closure)
+{
+  fps_compute (fpst, 0, -1);
+  fps_draw (fpst);
+}
+
+
 static void
 run_screenhack_table (Display *dpy, 
                       Window window,
 # ifdef DEBUG_PAIR
                       Window window2,
+# endif
+# ifdef HAVE_RECORD_ANIM
+                      record_anim_state *anim_state,
 # endif
                       const struct xscreensaver_function_table *ft)
 {
@@ -567,16 +551,23 @@ run_screenhack_table (Display *dpy,
   void *(*init_cb) (Display *, Window, void *) = 
     (void *(*) (Display *, Window, void *)) ft->init_cb;
 
+  void (*fps_cb) (Display *, Window, fps_state *, void *) = ft->fps_cb;
+
   void *closure = init_cb (dpy, window, ft->setup_arg);
+  fps_state *fpst = fps_init (dpy, window);
 
 #ifdef DEBUG_PAIR
   void *closure2 = 0;
+  fps_state *fpst2 = 0;
   if (window2) closure2 = init_cb (dpy, window2, ft->setup_arg);
+  if (window2) fpst2 = fps_init (dpy, window2);
 #endif
 
   if (! closure)  /* if it returns nothing, it can't possibly be re-entrant. */
     abort();
 
+  if (! fps_cb) fps_cb = screenhack_do_fps;
+
   while (1)
     {
       unsigned long delay = ft->draw_cb (dpy, window, closure);
@@ -585,20 +576,34 @@ run_screenhack_table (Display *dpy,
       if (window2) delay2 = ft->draw_cb (dpy, window2, closure2);
 #endif
 
+      if (fpst) fps_cb (dpy, window, fpst, closure);
+#ifdef DEBUG_PAIR
+      if (fpst2) fps_cb (dpy, window2, fpst2, closure2);
+#endif
+
       if (! usleep_and_process_events (dpy, ft,
-                                       window, closure, delay
+                                       window, fpst, closure, delay
 #ifdef DEBUG_PAIR
-                                       , window2, closure2, delay2
+                                       , window2, fpst2, closure2, delay2
+#endif
+#ifdef HAVE_RECORD_ANIM
+                                       , anim_state
 #endif
                                        ))
         break;
     }
 
+#ifdef HAVE_RECORD_ANIM
+  /* Exiting before target frames hit: write the video anyway. */
+  if (anim_state) screenhack_record_anim_free (anim_state);
+#endif
+
   ft->free_cb (dpy, window, closure);
+  if (fpst) fps_free (fpst);
 
 #ifdef DEBUG_PAIR
-  if (window2)
-    ft->free_cb (dpy, window2, closure2);
+  if (window2) ft->free_cb (dpy, window2, closure2);
+  if (fpst2) fps_free (fpst2);
 #endif
 }
 
@@ -614,11 +619,6 @@ make_shell (Screen *screen, Widget toplevel, int width, int height)
   if (width  <= 0) width  = 600;
   if (height <= 0) height = 480;
 
-# ifdef USE_GL
-  if (!validate_gl_visual (stderr, screen, "window", visual))
-    exit (1);
-# endif /* USE_GL */
-
   if (def_visual_p)
     {
       Window window;
@@ -705,6 +705,9 @@ main (int argc, char **argv)
   Window window2 = 0;
   Widget toplevel2 = 0;
 # endif
+#ifdef HAVE_RECORD_ANIM
+  record_anim_state *anim_state = 0;
+#endif
   XtAppContext app;
   Bool root_p;
   Window on_window = 0;
@@ -755,13 +758,17 @@ main (int argc, char **argv)
   {
     char *v = (char *) strdup(strchr(screensaver_id, ' '));
     char *s1, *s2, *s3, *s4;
+    const char *ot = get_string_resource (dpy, "title", "Title");
     s1 = (char *) strchr(v,  ' '); s1++;
     s2 = (char *) strchr(s1, ' ');
     s3 = (char *) strchr(v,  '('); s3++;
     s4 = (char *) strchr(s3, ')');
     *s2 = 0;
     *s4 = 0;
-    sprintf (version, "%s: from the XScreenSaver %s distribution (%s.)",
+    if (ot && !*ot) ot = 0;
+    sprintf (version, "%.50s%s%s: from the XScreenSaver %s distribution (%s)",
+             (ot ? ot : ""),
+             (ot ? ": " : ""),
             progclass, s1, s3);
     free(v);
   }
@@ -776,7 +783,7 @@ main (int argc, char **argv)
                      !strcmp(argv[1], "--help"));
       fprintf (stderr, "%s\n", version);
       for (s = progclass; *s; s++) fprintf(stderr, " ");
-      fprintf (stderr, "  http://www.jwz.org/xscreensaver/\n\n");
+      fprintf (stderr, "  https://www.jwz.org/xscreensaver/\n\n");
 
       if (!help_p)
        fprintf(stderr, "Unrecognised option: %s\n", argv[1]);
@@ -837,6 +844,12 @@ main (int argc, char **argv)
       exit (help_p ? 0 : 1);
     }
 
+  {
+    char **s;
+    for (s = merged_defaults; *s; s++)
+      free(*s);
+  }
+
   free (merged_options);
   free (merged_defaults);
   merged_options = 0;
@@ -940,12 +953,28 @@ main (int argc, char **argv)
 # undef ya_rand_init
   ya_rand_init (0);
 
+
+#ifdef HAVE_RECORD_ANIM
+  {
+    int frames = get_integer_resource (dpy, "recordAnim", "Integer");
+    if (frames > 0)
+      anim_state = screenhack_record_anim_init (xgwa.screen, window, frames);
+  }
+#endif
+
   run_screenhack_table (dpy, window, 
 # ifdef DEBUG_PAIR
                         window2,
+# endif
+# ifdef HAVE_RECORD_ANIM
+                        anim_state,
 # endif
                         ft);
 
+#ifdef HAVE_RECORD_ANIM
+  if (anim_state) screenhack_record_anim_free (anim_state);
+#endif
+
   XtDestroyWidget (toplevel);
   XtDestroyApplicationContext (app);