# include <X11/extensions/scrnsaver.h>
#endif /* HAVE_MIT_SAVER_EXTENSION */
+#ifdef HAVE_XF86VMODE
+# include <X11/extensions/xf86vmode.h>
+#endif /* HAVE_XF86VMODE */
#ifdef HAVE_XHPDISABLERESET
# include <X11/XHPlib.h>
Button4MotionMask | Button5MotionMask | ButtonMotionMask)
+static const char *
+grab_string(int status)
+{
+ switch (status)
+ {
+ case GrabSuccess: return "GrabSuccess";
+ case AlreadyGrabbed: return "AlreadyGrabbed";
+ case GrabInvalidTime: return "GrabInvalidTime";
+ case GrabNotViewable: return "GrabNotViewable";
+ case GrabFrozen: return "GrabFrozen";
+ default:
+ {
+ static char foo[255];
+ sprintf(foo, "unknown status: %d", status);
+ return foo;
+ }
+ }
+}
+
static int
grab_kbd(saver_info *si, Window w)
{
if (p->verbose_p)
fprintf(stderr, "%s: grabbing keyboard on 0x%x... %s.\n",
- blurb(), (unsigned long) w,
- (status == GrabSuccess ? "GrabSuccess" :
- status == AlreadyGrabbed ? "AlreadyGrabbed" :
- status == GrabInvalidTime ? "GrabInvalidTime" :
- status == GrabNotViewable ? "GrabNotViewable" :
- status == GrabFrozen ? "GrabFrozen" :
- "???"));
-
+ blurb(), (unsigned long) w, grab_string(status));
return status;
}
-static const char *
-grab_string(int status)
-{
- switch (status)
- {
- case GrabSuccess: return "GrabSuccess"; break;
- case AlreadyGrabbed: return "AlreadyGrabbed"; break;
- case GrabInvalidTime: return "GrabInvalidTime"; break;
- case GrabNotViewable: return "GrabNotViewable"; break;
- case GrabFrozen: return "GrabFrozen"; break;
- default:
- {
- static char foo[255];
- sprintf(foo, "unknown status: %d", status);
- return foo;
- }
- }
-}
-
static int
grab_mouse (saver_info *si, Window w, Cursor cursor)
{
saver_preferences *p = &si->prefs;
int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
- GrabModeAsync, GrabModeAsync, None,
+ GrabModeAsync, GrabModeAsync, w,
cursor, CurrentTime);
if (status == GrabSuccess)
si->mouse_grab_window = w;
}
-Bool
+static Bool
grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor)
{
Status mstatus, kstatus;
mstatus == GrabSuccess);
}
-void
+static void
ungrab_keyboard_and_mouse (saver_info *si)
{
ungrab_mouse (si);
}
+int
+move_mouse_grab (saver_info *si, Window to, Cursor cursor)
+{
+ Window old = si->mouse_grab_window;
+
+ if (old == 0)
+ return grab_mouse (si, to, cursor);
+ else
+ {
+ saver_preferences *p = &si->prefs;
+ int status;
+
+ XSync (si->dpy, False);
+ XGrabServer (si->dpy); /* ############ DANGER! */
+ XSync (si->dpy, False);
+
+ if (p->verbose_p)
+ fprintf(stderr, "%s: grabbing server...\n", blurb());
+
+ ungrab_mouse (si);
+ status = grab_mouse (si, to, cursor);
+
+ if (status != GrabSuccess) /* Augh! */
+ {
+ sleep (1); /* Note dramatic evil of sleeping
+ with server grabbed. */
+ XSync (si->dpy, False);
+ status = grab_mouse (si, to, cursor);
+ }
+
+ if (status != GrabSuccess) /* Augh! Try to get the old one back... */
+ grab_mouse (si, to, cursor);
+
+ XUngrabServer (si->dpy);
+ XSync (si->dpy, False); /* ###### (danger over) */
+
+ if (p->verbose_p)
+ fprintf(stderr, "%s: ungrabbing server.\n", blurb());
+
+ return status;
+ }
+}
+
+
/* Prints an error message to stderr and returns True if there is another
xscreensaver running already. Silently returns False otherwise. */
Bool
}
+/* Returns the area of the screen which the xscreensaver window should cover.
+ Normally this is the whole screen, but if the X server's root window is
+ actually larger than the monitor's displayable area, then we want to
+ operate in the currently-visible portion of the desktop instead.
+ */
+void
+get_screen_viewport (saver_screen_info *ssi,
+ int *x_ret, int *y_ret,
+ int *w_ret, int *h_ret,
+ Bool verbose_p)
+{
+ int w = WidthOfScreen (ssi->screen);
+ int h = HeightOfScreen (ssi->screen);
+
+#ifdef HAVE_XF86VMODE
+ saver_info *si = ssi->global;
+ int screen_no = screen_number (ssi->screen);
+ int event, error;
+ int dot;
+ XF86VidModeModeLine ml;
+ int x, y;
+
+ if (XF86VidModeQueryExtension (si->dpy, &event, &error) &&
+ XF86VidModeGetModeLine (si->dpy, screen_no, &dot, &ml) &&
+ XF86VidModeGetViewPort (si->dpy, screen_no, &x, &y))
+ {
+ char msg[512];
+ *x_ret = x;
+ *y_ret = y;
+ *w_ret = ml.hdisplay;
+ *h_ret = ml.vdisplay;
+
+ if (*x_ret == 0 && *y_ret == 0 && *w_ret == w && *h_ret == h)
+ /* There is no viewport -- the screen does not scroll. */
+ return;
+
+ sprintf (msg, "%s: vp is %dx%d+%d+%d",
+ blurb(), *w_ret, *h_ret, *x_ret, *y_ret);
+
+
+ /* Apparently, though the server stores the X position in increments of
+ 1 pixel, it will only make changes to the *display* in some other
+ increment. With XF86_SVGA on a Thinkpad, the display only updates
+ in multiples of 8 pixels when in 8-bit mode, and in multiples of 4
+ pixels in 16-bit mode. I don't know what it does in 24- and 32-bit
+ mode, because I don't have enough video memory to find out.
+
+ I consider it a bug that XF86VidModeGetViewPort() is telling me the
+ server's *target* scroll position rather than the server's *actual*
+ scroll position. David Dawes agrees, and says they may fix this in
+ XFree86 4.0, but it's notrivial.
+
+ He also confirms that this behavior is server-dependent, so the
+ actual scroll position cannot be reliably determined by the client.
+ So... that means the only solution is to provide a ``sandbox''
+ around the blackout window -- we make the window be up to N pixels
+ larger than the viewport on both the left and right sides. That
+ means some part of the outer edges of each hack might not be
+ visible, but screw it.
+
+ I'm going to guess that 16 pixels is enough, and that the Y dimension
+ doesn't have this problem.
+
+ The drawback of doing this, of course, is that some of the screenhacks
+ will still look pretty stupid -- for example, "slidescreen" will cut
+ off the left and right edges of the grid, etc.
+ */
+# define FUDGE 16
+ if (x > 0 && x < w - ml.hdisplay) /* not at left edge or right edge */
+ {
+ /* Round X position down to next lower multiple of FUDGE.
+ Increase width by 2*FUDGE in case some server rounds up.
+ */
+ *x_ret = ((x - 1) / FUDGE) * FUDGE;
+ *w_ret += (FUDGE * 2);
+ }
+# undef FUDGE
+
+ if (*x_ret != x ||
+ *y_ret != y ||
+ *w_ret != ml.hdisplay ||
+ *h_ret != ml.vdisplay)
+ sprintf (msg + strlen(msg), "; fudged to %dx%d+%d+%d",
+ *w_ret, *h_ret, *x_ret, *y_ret);
+
+ if (verbose_p)
+ fprintf (stderr, "%s.\n", msg);
+
+ return;
+ }
+
+#endif /* HAVE_XF86VMODE */
+
+ *x_ret = 0;
+ *y_ret = 0;
+ *w_ret = w;
+ *h_ret = h;
+}
+
+
static void
initialize_screensaver_window_1 (saver_screen_info *ssi)
{
saver_info *si = ssi->global;
saver_preferences *p = &si->prefs;
- Bool install_cmap_p = (ssi->install_cmap_p || p->install_cmap_p);
+ Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
/* This resets the screensaver window as fully as possible, since there's
no way of knowing what some random client may have done to us in the
XColor black;
XSetWindowAttributes attrs;
unsigned long attrmask;
- int width = WidthOfScreen (ssi->screen);
- int height = HeightOfScreen (ssi->screen);
+ int x, y, width, height;
static Bool printed_visual_info = False; /* only print the message once. */
+ get_screen_viewport (si->default_screen, &x, &y, &width, &height,
+ (p->verbose_p && !si->screen_blanked_p));
+
black.red = black.green = black.blue = 0;
if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
ssi->cmap = 0;
if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
+ /* It's not the default visual, so we have no choice but to install. */
install_cmap_p = True;
if (install_cmap_p)
{
XWindowChanges changes;
unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
- changes.x = 0;
- changes.y = 0;
+ changes.x = x;
+ changes.y = y;
changes.width = width;
changes.height = height;
changes.border_width = 0;
else
{
ssi->screensaver_window =
- XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen), 0, 0,
- width, height, 0, ssi->current_depth, InputOutput,
+ XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen),
+ x, y, width, height,
+ 0, ssi->current_depth, InputOutput,
ssi->current_visual, attrmask, &attrs);
+
reset_stderr (ssi);
store_activate_time(si, True);
if (p->verbose_p)
if (si->demoing_p)
inhibit_fade = True;
- initialize_screensaver_window (si);
+ if (si->emergency_lock_p)
+ inhibit_fade = True;
+
+ if (!dont_clear)
+ initialize_screensaver_window (si);
+
reset_watchdog_timer (si, True);
- if (p->fade_p && p->fading_possible_p && !inhibit_fade)
+ if (p->fade_p && si->fading_possible_p && !inhibit_fade)
{
Window *current_windows = (Window *)
calloc(sizeof(Window), si->nscreens);
}
}
-void
+Bool
blank_screen (saver_info *si)
{
int i;
+ Bool ok;
/* 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.
*/
- grab_keyboard_and_mouse (si,
- /*si->screens[0].screensaver_window,*/
- RootWindowOfScreen(si->screens[0].screen),
- (si->demoing_p
- ? 0
- : si->screens[0].cursor));
+ ok = grab_keyboard_and_mouse (si,
+ /*si->screens[0].screensaver_window,*/
+ RootWindowOfScreen(si->screens[0].screen),
+ (si->demoing_p
+ ? 0
+ : si->screens[0].cursor));
+
+
+ if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
+ /* If we're using a server extension, then failure to get a grab is
+ not a big deal -- even without the grab, we will still be able
+ to un-blank when there is user activity, since the server will
+ tell us. */
+ ok = True;
+
+ if (!ok)
+ return False;
for (i = 0; i < si->nscreens; i++)
{
store_vroot_property (si->dpy,
ssi->screensaver_window,
ssi->screensaver_window);
+
+#ifdef HAVE_XF86VMODE
+ {
+ int ev, er;
+ if (!XF86VidModeQueryExtension (si->dpy, &ev, &er) ||
+ !XF86VidModeGetViewPort (si->dpy, i,
+ &ssi->blank_vp_x,
+ &ssi->blank_vp_y))
+ ssi->blank_vp_x = ssi->blank_vp_y = -1;
+ }
+#endif /* HAVE_XF86VMODE */
}
store_activate_time (si, si->screen_blanked_p);
raise_window (si, False, False, False);
#endif
si->screen_blanked_p = True;
+ si->last_wall_clock_time = 0;
+
+ return True;
}
void
unblank_screen (saver_info *si)
{
saver_preferences *p = &si->prefs;
- Bool unfade_p = (p->fading_possible_p && p->unfade_p);
+ Bool unfade_p = (si->fading_possible_p && p->unfade_p);
int i;
monitor_power_on (si);
XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
si->screen_blanked_p = False;
+ si->last_wall_clock_time = 0;
}
saver_preferences *p = &si->prefs;
Bool install_cmap_p = p->install_cmap_p;
Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
- Visual *new_v;
+ Visual *new_v = 0;
Bool got_it;
if (visual_name && *visual_name)
visual_name = "default";
install_cmap_p = False;
}
- new_v = get_visual (ssi->screen, visual_name, True, False);
+#ifdef DAEMON_USE_GL
+ else if (!strcmp(visual_name, "gl") ||
+ !strcmp(visual_name, "GL"))
+ {
+ new_v = get_gl_visual (ssi->screen);
+ if (!new_v && p->verbose_p)
+ fprintf (stderr, "%s: no GL visuals.\n", progname);
+ }
+#endif /* DAEMON_USE_GL */
+
+ if (!new_v)
+ new_v = get_visual (ssi->screen, visual_name, True, False);
}
else
{
got_it = !!new_v;
if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
+ /* It's not the default visual, so we have no choice but to install. */
install_cmap_p = True;
ssi->install_cmap_p = install_cmap_p;