summaryrefslogtreecommitdiffstats
path: root/driver
diff options
context:
space:
mode:
Diffstat (limited to 'driver')
-rw-r--r--driver/XScreenSaver.ad.in10
-rw-r--r--driver/dpms.c23
-rw-r--r--driver/prefs.c8
-rw-r--r--driver/prefs.h2
-rw-r--r--driver/subprocs.c62
-rw-r--r--driver/timers.c15
-rw-r--r--driver/types.h6
-rw-r--r--driver/windows.c75
-rw-r--r--driver/xscreensaver.c12
-rw-r--r--driver/xscreensaver.h2
10 files changed, 210 insertions, 5 deletions
diff --git a/driver/XScreenSaver.ad.in b/driver/XScreenSaver.ad.in
index cfdd1a2..0b51f0c 100644
--- a/driver/XScreenSaver.ad.in
+++ b/driver/XScreenSaver.ad.in
@@ -38,6 +38,7 @@
*dpmsStandby: 2:00:00
*dpmsSuspend: 2:00:00
*dpmsOff: 4:00:00
+*dpmsFullThrottle: False
*grabDesktopImages: True
*grabVideoFrames: False
*chooseRandomImages: @DEFAULT_IMAGES_P@
@@ -142,6 +143,15 @@
@NEW_LOGIN_COMMAND_P@*newLoginCommand: @NEW_LOGIN_COMMAND@
+! External command used to help xscreensaver aquire the mouse/keyboard
+! grab. (I.e. some script that makes VMware release it).
+! This is called before xscreensaver tries to aquire the grab with
+! "pre" as parameter, and again with "post" after xscreensaver is done
+! (trying to) aquire the grab.
+!
+*externalUngrabCommand:
+
+
! Change these at your peril:
!
XScreenSaver.pointerPollTime: 0:00:05
diff --git a/driver/dpms.c b/driver/dpms.c
index a0dd7b8..3a8803c 100644
--- a/driver/dpms.c
+++ b/driver/dpms.c
@@ -86,8 +86,12 @@
#ifdef HAVE_DPMS_EXTENSION
+#define CLAMP_DOWN(var,val,mi) do { int old = (var); (var) -= (val); if ((var) < (mi) || (var) > old) (var) = (mi); } while (0)
+
static Bool error_handler_hit_p = False;
+static int idle_offset = 0;
+
static int
ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
{
@@ -95,6 +99,12 @@ ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
return 0;
}
+void
+store_dpms_offset(int offset)
+{
+ idle_offset = offset < 15 ? 0 : offset;
+}
+
void
sync_server_dpms_settings (Display *dpy, Bool enabled_p, Bool dpms_quickoff_p,
@@ -125,6 +135,13 @@ sync_server_dpms_settings (Display *dpy, Bool enabled_p, Bool dpms_quickoff_p,
if (bogus_p) enabled_p = False;
+ if (idle_offset != 0)
+ {
+ CLAMP_DOWN (standby_secs, idle_offset, 10);
+ CLAMP_DOWN (suspend_secs, idle_offset, 10);
+ CLAMP_DOWN (off_secs, idle_offset, 10);
+ }
+
/* X protocol sends these values in a CARD16, so truncate them to 16 bits.
This means that the maximum timeout is 18:12:15.
*/
@@ -280,6 +297,12 @@ monitor_power_on (saver_info *si, Bool on_p)
#else /* !HAVE_DPMS_EXTENSION */
void
+store_dpms_offset(Display *dpy, Bool reset_p)
+{
+}
+
+
+void
sync_server_dpms_settings (Display *dpy, Bool enabled_p,
Bool dpms_quickoff_p,
int standby_secs, int suspend_secs, int off_secs,
diff --git a/driver/prefs.c b/driver/prefs.c
index 94e7a0c..e5762ff 100644
--- a/driver/prefs.c
+++ b/driver/prefs.c
@@ -270,6 +270,7 @@ static const char * const prefs[] = {
"helpURL", /* not saved */
"loadURL", /* not saved */
"newLoginCommand", /* not saved */
+ "externalUngrabCommand", /* not saved */
"nice",
"memoryLimit",
"fade",
@@ -286,6 +287,7 @@ static const char * const prefs[] = {
"dpmsStandby",
"dpmsSuspend",
"dpmsOff",
+ "dpmsFullThrottle",
"grabDesktopImages",
"grabVideoFrames",
"chooseRandomImages",
@@ -810,6 +812,7 @@ write_init_file (Display *dpy,
CHECK("loadURL") continue; /* don't save */
/* CHECK("newLoginCommand") type = pref_str, s = p->new_login_command; */
CHECK("newLoginCommand") continue; /* don't save */
+ CHECK("externalUngrabCommand") continue; /* don't save */
CHECK("nice") type = pref_int, i = p->nice_inferior;
CHECK("memoryLimit") type = pref_byte, i = p->inferior_memory_limit;
CHECK("fade") type = pref_bool, b = p->fade_p;
@@ -829,6 +832,7 @@ write_init_file (Display *dpy,
CHECK("dpmsStandby") type = pref_time, t = p->dpms_standby;
CHECK("dpmsSuspend") type = pref_time, t = p->dpms_suspend;
CHECK("dpmsOff") type = pref_time, t = p->dpms_off;
+ CHECK("dpmsFullThrottle") continue; /* don't save */
CHECK("grabDesktopImages") type =pref_bool, b = p->grab_desktop_p;
CHECK("grabVideoFrames") type =pref_bool, b = p->grab_video_p;
@@ -1087,6 +1091,7 @@ load_init_file (Display *dpy, saver_preferences *p)
p->dpms_standby = 1000 * get_minutes_resource (dpy, "dpmsStandby", "Time");
p->dpms_suspend = 1000 * get_minutes_resource (dpy, "dpmsSuspend", "Time");
p->dpms_off = 1000 * get_minutes_resource (dpy, "dpmsOff", "Time");
+ p->dpms_full_throttle_p = get_boolean_resource (dpy, "dpmsFullThrottle", "Boolean");
p->grab_desktop_p = get_boolean_resource (dpy, "grabDesktopImages", "Boolean");
p->grab_video_p = get_boolean_resource (dpy, "grabVideoFrames", "Boolean");
@@ -1109,6 +1114,9 @@ load_init_file (Display *dpy, saver_preferences *p)
p->new_login_command = get_string_resource(dpy,
"newLoginCommand",
"NewLoginCommand");
+ p->external_ungrab_command = get_string_resource(dpy,
+ "externalUngrabCommand",
+ "ExternalUngrabCommand");
p->auth_warning_slack = get_integer_resource(dpy, "authWarningSlack",
"Integer");
diff --git a/driver/prefs.h b/driver/prefs.h
index cd1016d..c494eaf 100644
--- a/driver/prefs.h
+++ b/driver/prefs.h
@@ -34,4 +34,6 @@ extern void sync_server_dpms_settings (Display *, Bool enabled_p,
int off_secs,
Bool verbose_p);
+extern void store_dpms_offset(int offset);
+
#endif /* __XSCREENSAVER_PREFS_H__ */
diff --git a/driver/subprocs.c b/driver/subprocs.c
index e251842..6cb96d3 100644
--- a/driver/subprocs.c
+++ b/driver/subprocs.c
@@ -928,6 +928,66 @@ fork_and_exec_1 (saver_info *si, saver_screen_info *ssi, const char *command)
}
+/* Execute command in another process and wait for it to
+ * finish. Return exit code of process, or -1 on error
+ * with fork() or exec().
+ */
+int
+exec_and_wait (saver_info *si, const char *command)
+{
+ pid_t forked;
+ saver_preferences *p = &si->prefs;
+
+ switch ((int) (forked = fork ()))
+ {
+ case -1:
+ {
+ char buf [255];
+ sprintf (buf, "%s: couldn't fork", blurb());
+ perror (buf);
+ return -1;
+ }
+
+ case 0:
+ close (ConnectionNumber (si->dpy)); /* close display fd */
+ limit_subproc_memory (p->inferior_memory_limit, p->verbose_p);
+
+ if (p->verbose_p)
+ fprintf (stderr, "%s: spawning \"%s\" in pid %lu.\n",
+ blurb(), command,
+ (unsigned long) getpid ());
+
+ exec_command (p->shell, command, 0);
+
+ /* If that returned, we were unable to exec the subprocess.
+ Print an error message, if desired.
+ */
+ print_path_error (command);
+
+ exit (-1); /* exits child fork */
+ break;
+
+ default: /* parent */
+ {
+ pid_t retpid;
+ int wstatus;
+ while ((retpid = waitpid (forked, &wstatus, 0)) == -1) {
+ if (errno == EINTR)
+ continue;
+ perror ("Could not waitpid for child.");
+ return -1;
+ }
+ if (WIFEXITED(wstatus))
+ return WEXITSTATUS(wstatus);
+ if (WIFSIGNALED(wstatus))
+ return WTERMSIG(wstatus) + 128;
+ return -1;
+ }
+ }
+ return -1;
+}
+
+
void
spawn_screenhack (saver_screen_info *ssi)
{
@@ -935,7 +995,7 @@ spawn_screenhack (saver_screen_info *ssi)
saver_preferences *p = &si->prefs;
XFlush (si->dpy);
- if (!monitor_powered_on_p (si))
+ if (!p->dpms_full_throttle_p && !monitor_powered_on_p (si))
{
if (si->prefs.verbose_p)
fprintf (stderr,
diff --git a/driver/timers.c b/driver/timers.c
index 5aa568c..b096000 100644
--- a/driver/timers.c
+++ b/driver/timers.c
@@ -695,6 +695,19 @@ swallow_unlock_typeahead_events (saver_info *si, XEvent *e)
memset (buf, 0, sizeof(buf));
}
+void
+flush_events (saver_info *si)
+{
+ int i;
+ XEvent xe;
+ for (i = 0; i < 10; ++i) {
+ while (XtAppPending (si->app) & XtIMXEvent) {
+ XtAppNextEvent (si->app, &xe);
+ dispatch_event (si, &xe);
+ }
+ usleep(5000);
+ }
+}
/* methods of detecting idleness:
@@ -1663,7 +1676,7 @@ watchdog_timer (XtPointer closure, XtIntervalId *id)
raise_window (si, True, True, running_p);
}
- if (screenhack_running_p (si) &&
+ if (!p->dpms_full_throttle_p && screenhack_running_p (si) &&
!monitor_powered_on_p (si))
{
int i;
diff --git a/driver/types.h b/driver/types.h
index ebea9e0..705750b 100644
--- a/driver/types.h
+++ b/driver/types.h
@@ -137,6 +137,7 @@ struct saver_preferences {
Time dpms_standby; /* how long until monitor goes black */
Time dpms_suspend; /* how long until monitor power-saves */
Time dpms_off; /* how long until monitor powers down */
+ Bool dpms_full_throttle_p; /* Never kill or suspend hack when screen is off */
Bool grab_desktop_p; /* These are not used by "xscreensaver" */
Bool grab_video_p; /* itself: they are used by the external */
@@ -164,6 +165,11 @@ struct saver_preferences {
char *help_url; /* Where the help document resides. */
char *load_url_command; /* How one loads URLs. */
char *new_login_command; /* Command for the "New Login" button. */
+ char *external_ungrab_command; /* Command that's supposed to make sure
+ nobody is holding the keyboard or
+ mouse grab. Called with params
+ "pre" and "post" before and after
+ trying to get the grab. */
int auth_warning_slack; /* Don't warn about login failures if they
all happen within this many seconds of
diff --git a/driver/windows.c b/driver/windows.c
index 9e47c45..5854c49 100644
--- a/driver/windows.c
+++ b/driver/windows.c
@@ -35,6 +35,7 @@
#include <X11/Xutil.h> /* for XSetClassHint() */
#include <X11/Xatom.h>
#include <X11/Xos.h> /* for time() */
+#include <X11/extensions/scrnsaver.h>
#include <signal.h> /* for the signal names */
#include <time.h>
#include <sys/time.h>
@@ -235,7 +236,7 @@ ungrab_keyboard_and_mouse (saver_info *si)
static Bool
-grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
+grab_keyboard_and_mouse_real (saver_info *si, Window window, Cursor cursor,
int screen_no)
{
Status mstatus = 0, kstatus = 0;
@@ -320,6 +321,32 @@ grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
}
+static Bool
+grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor,
+ int screen_no)
+{
+ Bool ret;
+ char *euc = si->prefs.external_ungrab_command;
+ char cmd[200];
+ if (euc && *euc)
+ {
+ snprintf (cmd, sizeof(cmd), "%s %s", euc, "pre");
+ exec_and_wait (si, cmd);
+ }
+ ret = grab_keyboard_and_mouse_real (si, window, cursor, screen_no);
+ if (euc && *euc)
+ {
+ snprintf (cmd, sizeof(cmd), "%s %s", euc, "post");
+ exec_and_wait (si, cmd);
+ if (ret) {
+ /* The external command might have generated some x/input events */
+ flush_events (si);
+ }
+ }
+ return ret;
+}
+
+
int
move_mouse_grab (saver_info *si, Window to, Cursor cursor, int to_screen_no)
{
@@ -1639,6 +1666,17 @@ mouse_screen (saver_info *si)
return 0;
}
+static int
+get_idle_time (saver_info *si)
+{
+ int ret = 0;
+ XScreenSaverInfo *info;
+ info = XScreenSaverAllocInfo ();
+ if (info != NULL && XScreenSaverQueryInfo (si->dpy, DefaultRootWindow (si->dpy), info))
+ ret = info->idle / 1000;
+ XFree (info);
+ return ret;
+}
Bool
blank_screen (saver_info *si)
@@ -1647,7 +1685,16 @@ blank_screen (saver_info *si)
Bool ok;
Window w;
int mscreen;
+ int idle_s = 0;
+ Bool screen_on = True;
+ const char *euc = si->prefs.external_ungrab_command;
+ if (euc && *euc)
+ {
+ screen_on = monitor_powered_on_p (si);
+ if (screen_on)
+ idle_s = get_idle_time(si);
+ }
/* Note: we do our grabs on the root window, not on the screensaver window.
If we grabbed on the saver window, then the demo mode and lock dialog
boxes wouldn't get any events.
@@ -1679,6 +1726,31 @@ blank_screen (saver_info *si)
if (!ok)
return False;
+ if (euc && *euc)
+ {
+ /* ungrab hooks might have messed up idle time -- account for that.
+ this might look like the math is backwards, but this handles both
+ cases -- ungrab hook did mess up idle time, and ungrab hook
+ did *not* mess up idle time. In the latter case the value will be
+ zero or negative, so it gets clamped to zero.
+ */
+ if (screen_on)
+ {
+ saver_preferences *p = &si->prefs;
+ store_dpms_offset (idle_s - get_idle_time(si));
+ sync_server_dpms_settings (si->dpy,
+ (p->dpms_enabled_p &&
+ p->mode != DONT_BLANK),
+ p->dpms_quickoff_p,
+ p->dpms_standby / 1000,
+ p->dpms_suspend / 1000,
+ p->dpms_off / 1000,
+ False);
+ }
+ else /* screen was off before, might have been turned on by fake events */
+ monitor_power_on (si, False);
+ }
+
for (i = 0; i < si->nscreens; i++)
{
saver_screen_info *ssi = &si->screens[i];
@@ -1719,6 +1791,7 @@ unblank_screen (saver_info *si)
Bool unfade_p = (si->fading_possible_p && p->unfade_p);
int i;
+ store_dpms_offset (0);
monitor_power_on (si, True);
reset_watchdog_timer (si, False);
diff --git a/driver/xscreensaver.c b/driver/xscreensaver.c
index 40f8207..b9c54f1 100644
--- a/driver/xscreensaver.c
+++ b/driver/xscreensaver.c
@@ -1399,8 +1399,16 @@ main_loop (saver_info *si)
was_locked = True;
si->dbox_up_p = True;
- for (i = 0; i < si->nscreens; i++)
- suspend_screenhack (&si->screens[i], True); /* suspend */
+ if (p->dpms_full_throttle_p)
+ {
+ for (i = 0; i < si->nscreens; i++)
+ if (si->screens[i].pid == 0)
+ spawn_screenhack (&si->screens[i]);
+ usleep(100000);
+ }
+ else
+ for (i = 0; i < si->nscreens; i++)
+ suspend_screenhack (&si->screens[i], True); /* suspend */
XUndefineCursor (si->dpy, ssi->screensaver_window);
ok_to_unblank = unlock_p (si);
diff --git a/driver/xscreensaver.h b/driver/xscreensaver.h
index bed6537..fe84d20 100644
--- a/driver/xscreensaver.h
+++ b/driver/xscreensaver.h
@@ -129,6 +129,7 @@ extern void activate_lock_timer (XtPointer si, XtIntervalId *id);
extern void reset_watchdog_timer (saver_info *si, Bool on_p);
extern void idle_timer (XtPointer si, XtIntervalId *id);
extern void de_race_timer (XtPointer si, XtIntervalId *id);
+void flush_events (saver_info *si);
extern void sleep_until_idle (saver_info *si, Bool until_idle_p);
extern void reset_timers (saver_info *si);
extern void schedule_wakeup_event (saver_info *si, Time when, Bool verbose_p);
@@ -159,6 +160,7 @@ extern void spawn_screenhack (saver_screen_info *ssi);
extern pid_t fork_and_exec (saver_screen_info *ssi, const char *command);
extern pid_t fork_and_exec_1 (saver_info *si, saver_screen_info *ssi,
const char *command);
+extern int exec_and_wait (saver_info *si, const char *command);
extern void kill_screenhack (saver_screen_info *ssi);
int kill_job (saver_info *si, pid_t pid, int signal);
extern void suspend_screenhack (saver_screen_info *ssi, Bool suspend_p);