-/* xscreensaver, Copyright (c) 1992-2008 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1992-2014 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 };
- 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.
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.
{ "-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",
static int merged_options_size;
static char **merged_defaults;
+
static void
merge_options (void)
{
strcat (newr, oldr);
*s = newr;
}
+ else
+ *s = strdup (*s);
}
}
}
-#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,
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
(! (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)))
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
}
+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)
{
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);
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, window, fpst2, closure);
+#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
}
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;
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;
{
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);
}
!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]);
exit (help_p ? 0 : 1);
}
+ {
+ char **s;
+ for (s = merged_defaults; *s; s++)
+ free(*s);
+ }
+
free (merged_options);
free (merged_defaults);
merged_options = 0;
window = VirtualRootWindowOfScreen (XtScreen (toplevel));
XtDestroyWidget (toplevel);
XGetWindowAttributes (dpy, window, &xgwa);
+ /* With RANDR, the root window can resize! */
+ XSelectInput (dpy, window, xgwa.your_event_mask | StructureNotifyMask);
visual_warning (xgwa.screen, window, xgwa.visual, xgwa.colormap, False);
}
else
# 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);