1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-1998 Jamie Zawinski <jwz@jwz.org>
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
18 # include <unixlib.h> /* for getpid() */
19 # include "vms-gtod.h" /* for gettimeofday() */
23 # include <pwd.h> /* for getpwuid() */
29 # include <sys/utsname.h> /* for uname() */
30 #endif /* HAVE_UNAME */
33 #include <X11/Xproto.h> /* for CARD32 */
35 #include <X11/Xutil.h> /* for XSetClassHint() */
36 #include <X11/Xatom.h>
37 #include <X11/Xos.h> /* for time() */
38 #include <signal.h> /* for the signal names */
40 #ifdef HAVE_MIT_SAVER_EXTENSION
41 # include <X11/extensions/scrnsaver.h>
42 #endif /* HAVE_MIT_SAVER_EXTENSION */
45 #ifdef HAVE_XHPDISABLERESET
46 # include <X11/XHPlib.h>
48 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
49 or BadAccess errors occur. (Ok for this to be global, since it
50 affects the whole machine, not just the current screen.) */
51 Bool hp_locked_p = False;
53 #endif /* HAVE_XHPDISABLERESET */
56 /* This file doesn't need the Xt headers, so stub these types out... */
58 #define XtAppContext void*
59 #define XrmDatabase void*
60 #define XtIntervalId void*
61 #define XtPointer void*
64 #include "xscreensaver.h"
69 #ifdef HAVE_VT_LOCKSWITCH
71 # include <sys/ioctl.h>
73 static void lock_vt (saver_info *si, Bool lock_p);
74 #endif /* HAVE_VT_LOCKSWITCH */
77 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
79 Atom XA_VROOT, XA_XSETROOT_ID;
80 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
81 Atom XA_SCREENSAVER_TIME;
84 extern saver_info *global_si_kludge; /* I hate C so much... */
87 static void store_activate_time (saver_info *si, Bool use_last_p);
89 #define ALL_POINTER_EVENTS \
90 (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
91 LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
92 Button1MotionMask | Button2MotionMask | Button3MotionMask | \
93 Button4MotionMask | Button5MotionMask | ButtonMotionMask)
97 grab_kbd(saver_info *si, Window w)
99 saver_preferences *p = &si->prefs;
100 int status = XGrabKeyboard (si->dpy, w, True,
101 /* I don't really understand Sync vs Async,
102 but these seem to work... */
103 GrabModeSync, GrabModeAsync,
105 if (status == GrabSuccess)
106 si->keyboard_grab_window = w;
109 fprintf(stderr, "%s: grabbing keyboard on 0x%x... %s.\n",
110 blurb(), (unsigned long) w,
111 (status == GrabSuccess ? "GrabSuccess" :
112 status == AlreadyGrabbed ? "AlreadyGrabbed" :
113 status == GrabInvalidTime ? "GrabInvalidTime" :
114 status == GrabNotViewable ? "GrabNotViewable" :
115 status == GrabFrozen ? "GrabFrozen" :
122 grab_string(int status)
126 case GrabSuccess: return "GrabSuccess"; break;
127 case AlreadyGrabbed: return "AlreadyGrabbed"; break;
128 case GrabInvalidTime: return "GrabInvalidTime"; break;
129 case GrabNotViewable: return "GrabNotViewable"; break;
130 case GrabFrozen: return "GrabFrozen"; break;
133 static char foo[255];
134 sprintf(foo, "unknown status: %d", status);
142 grab_mouse (saver_info *si, Window w, Cursor cursor)
144 saver_preferences *p = &si->prefs;
145 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
146 GrabModeAsync, GrabModeAsync, None,
147 cursor, CurrentTime);
148 if (status == GrabSuccess)
149 si->mouse_grab_window = w;
152 fprintf(stderr, "%s: grabbing mouse on 0x%x... %s.\n",
153 blurb(), (unsigned long) w, grab_string(status));
159 ungrab_kbd(saver_info *si)
161 saver_preferences *p = &si->prefs;
162 XUngrabKeyboard(si->dpy, CurrentTime);
164 fprintf(stderr, "%s: ungrabbing keyboard (was 0x%x).\n", blurb(),
165 (unsigned long) si->keyboard_grab_window);
166 si->keyboard_grab_window = 0;
171 ungrab_mouse(saver_info *si)
173 saver_preferences *p = &si->prefs;
174 XUngrabPointer(si->dpy, CurrentTime);
176 fprintf(stderr, "%s: ungrabbing mouse (was 0x%x).\n", blurb(),
177 (unsigned long) si->mouse_grab_window);
178 si->mouse_grab_window = 0;
183 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor)
185 Status mstatus, kstatus;
186 XSync (si->dpy, False);
188 kstatus = grab_kbd (si, window);
189 if (kstatus != GrabSuccess)
190 { /* try again in a second */
192 kstatus = grab_kbd (si, window);
193 if (kstatus != GrabSuccess)
194 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
195 blurb(), grab_string(kstatus));
198 mstatus = grab_mouse (si, window, cursor);
199 if (mstatus != GrabSuccess)
200 { /* try again in a second */
202 mstatus = grab_mouse (si, window, cursor);
203 if (mstatus != GrabSuccess)
204 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
205 blurb(), grab_string(mstatus));
208 return (kstatus == GrabSuccess ||
209 mstatus == GrabSuccess);
213 ungrab_keyboard_and_mouse (saver_info *si)
220 /* Prints an error message to stderr and returns True if there is another
221 xscreensaver running already. Silently returns False otherwise. */
223 ensure_no_screensaver_running (Display *dpy, Screen *screen)
227 Window root = RootWindowOfScreen (screen);
228 Window root2, parent, *kids;
230 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
232 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
238 for (i = 0; i < nkids; i++)
242 unsigned long nitems, bytesafter;
245 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
246 False, XA_STRING, &type, &format, &nitems,
247 &bytesafter, (unsigned char **) &version)
252 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
253 False, XA_STRING, &type, &format, &nitems,
254 &bytesafter, (unsigned char **) &id)
260 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
261 blurb(), DisplayString (dpy), (int) kids [i], id);
266 if (kids) XFree ((char *) kids);
268 XSetErrorHandler (old_handler);
274 /* Virtual-root hackery */
277 ERROR! You must not include vroot.h in this file.
281 store_vroot_property (Display *dpy, Window win, Window value)
286 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
288 (win == screensaver_window ? "ScreenSaver" :
289 (win == real_vroot ? "VRoot" :
290 (win == real_vroot_value ? "Vroot_value" : "???"))),
292 (value == screensaver_window ? "ScreenSaver" :
293 (value == real_vroot ? "VRoot" :
294 (value == real_vroot_value ? "Vroot_value" : "???"))));
296 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
297 (unsigned char *) &value, 1);
301 remove_vroot_property (Display *dpy, Window win)
305 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
306 (win == screensaver_window ? "ScreenSaver" :
307 (win == real_vroot ? "VRoot" :
308 (win == real_vroot_value ? "Vroot_value" : "???"))));
310 XDeleteProperty (dpy, win, XA_VROOT);
315 kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p)
319 unsigned long nitems, bytesafter;
322 /* If the user has been using xv or xsetroot as a screensaver (to display
323 an image on the screensaver window, as a kind of slideshow) then the
324 pixmap and its associated color cells have been put in RetainPermanent
325 CloseDown mode. Since we're not destroying the xscreensaver window,
326 but merely unmapping it, we need to free these resources or those
327 colormap cells will stay allocated while the screensaver is off. (We
328 could just delete the screensaver window and recreate it later, but
329 that could cause other problems.) This code does an atomic read-and-
330 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
331 cause the RetainPermanent resources of the client which created it
332 (and which no longer exists) to be freed.
334 if (XGetWindowProperty (dpy, window, XA_XSETROOT_ID, 0, 1,
335 True, AnyPropertyType, &type, &format, &nitems,
336 &bytesafter, (unsigned char **) &dataP)
340 if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
341 nitems == 1 && bytesafter == 0)
344 fprintf (stderr, "%s: destroying xsetroot data (0x%lX).\n",
346 XKillClient (dpy, *dataP);
349 fprintf (stderr, "%s: deleted unrecognised _XSETROOT_ID property: \n\
350 %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n",
351 blurb(), (unsigned long) dataP, (dataP ? *dataP : 0), type,
352 format, nitems, bytesafter);
357 static void handle_signals (saver_info *si, Bool on_p);
360 save_real_vroot (saver_screen_info *ssi)
362 saver_info *si = ssi->global;
363 Display *dpy = si->dpy;
364 Screen *screen = ssi->screen;
366 Window root = RootWindowOfScreen (screen);
367 Window root2, parent, *kids;
369 XErrorHandler old_handler;
371 /* It's possible that a window might be deleted between our call to
372 XQueryTree() and our call to XGetWindowProperty(). Don't die if
373 that happens (but just ignore that window, it's not the one we're
374 interested in anyway.)
377 old_handler = XSetErrorHandler (BadWindow_ehandler);
381 ssi->real_vroot_value = 0;
382 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
388 for (i = 0; i < nkids; i++)
392 unsigned long nitems, bytesafter;
395 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
396 &type, &format, &nitems, &bytesafter,
397 (unsigned char **) &vrootP)
404 if (*vrootP == ssi->screensaver_window) abort ();
406 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
407 blurb(), (int) ssi->real_vroot, (int) kids [i]);
410 ssi->real_vroot = kids [i];
411 ssi->real_vroot_value = *vrootP;
415 XSetErrorHandler (old_handler);
420 handle_signals (si, True);
421 remove_vroot_property (si->dpy, ssi->real_vroot);
425 XFree ((char *) kids);
430 restore_real_vroot_2 (saver_screen_info *ssi)
432 saver_info *si = ssi->global;
433 saver_preferences *p = &si->prefs;
434 if (p->verbose_p && ssi->real_vroot)
436 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
437 blurb(), (unsigned long) ssi->real_vroot);
438 remove_vroot_property (si->dpy, ssi->screensaver_window);
441 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
443 ssi->real_vroot_value = 0;
444 /* make sure the property change gets there before this process
445 terminates! We might be doing this because we have intercepted
446 SIGTERM or something. */
447 XSync (si->dpy, False);
454 restore_real_vroot_1 (saver_info *si)
457 Bool did_any = False;
458 for (i = 0; i < si->nscreens; i++)
460 saver_screen_info *ssi = &si->screens[i];
461 if (restore_real_vroot_2 (ssi))
468 restore_real_vroot (saver_info *si)
470 if (restore_real_vroot_1 (si))
471 handle_signals (si, False);
475 /* Signal hackery to ensure that the vroot doesn't get left in an
480 signal_name(int signal)
483 case SIGHUP: return "SIGHUP";
484 case SIGINT: return "SIGINT";
485 case SIGQUIT: return "SIGQUIT";
486 case SIGILL: return "SIGILL";
487 case SIGTRAP: return "SIGTRAP";
489 case SIGABRT: return "SIGABRT";
491 case SIGFPE: return "SIGFPE";
492 case SIGKILL: return "SIGKILL";
493 case SIGBUS: return "SIGBUS";
494 case SIGSEGV: return "SIGSEGV";
495 case SIGPIPE: return "SIGPIPE";
496 case SIGALRM: return "SIGALRM";
497 case SIGTERM: return "SIGTERM";
499 case SIGSTOP: return "SIGSTOP";
502 case SIGCONT: return "SIGCONT";
505 case SIGUSR1: return "SIGUSR1";
508 case SIGUSR2: return "SIGUSR2";
511 case SIGEMT: return "SIGEMT";
514 case SIGSYS: return "SIGSYS";
517 case SIGCHLD: return "SIGCHLD";
520 case SIGPWR: return "SIGPWR";
523 case SIGWINCH: return "SIGWINCH";
526 case SIGURG: return "SIGURG";
529 case SIGIO: return "SIGIO";
532 case SIGVTALRM: return "SIGVTALRM";
535 case SIGXCPU: return "SIGXCPU";
538 case SIGXFSZ: return "SIGXFSZ";
541 case SIGDANGER: return "SIGDANGER";
546 sprintf(buf, "signal %d\n", signal);
555 restore_real_vroot_handler (int sig)
557 saver_info *si = global_si_kludge; /* I hate C so much... */
559 signal (sig, SIG_DFL);
560 if (restore_real_vroot_1 (si))
561 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
562 blurb(), signal_name(sig));
563 kill (getpid (), sig);
567 catch_signal (saver_info *si, int sig, Bool on_p)
570 signal (sig, SIG_DFL);
573 if (((long) signal (sig, restore_real_vroot_handler)) == -1L)
576 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
578 saver_exit (si, 1, 0);
584 handle_signals (saver_info *si, Bool on_p)
587 if (on_p) fprintf (stderr, "handling signals\n");
588 else fprintf (stderr, "unhandling signals\n");
591 catch_signal (si, SIGHUP, on_p);
592 catch_signal (si, SIGINT, on_p);
593 catch_signal (si, SIGQUIT, on_p);
594 catch_signal (si, SIGILL, on_p);
595 catch_signal (si, SIGTRAP, on_p);
596 catch_signal (si, SIGIOT, on_p);
597 catch_signal (si, SIGABRT, on_p);
599 catch_signal (si, SIGEMT, on_p);
601 catch_signal (si, SIGFPE, on_p);
602 catch_signal (si, SIGBUS, on_p);
603 catch_signal (si, SIGSEGV, on_p);
605 catch_signal (si, SIGSYS, on_p);
607 catch_signal (si, SIGTERM, on_p);
609 catch_signal (si, SIGXCPU, on_p);
612 catch_signal (si, SIGXFSZ, on_p);
615 catch_signal (si, SIGDANGER, on_p);
620 saver_exit (saver_info *si, int status, const char *dump_core_reason)
622 saver_preferences *p = &si->prefs;
623 static Bool exiting = False;
632 vrs = restore_real_vroot_1 (si);
633 emergency_kill_subproc (si);
635 if (vrs && (p->verbose_p || status != 0))
636 fprintf (real_stderr, "%s: vroot restored, exiting.\n", blurb());
637 else if (p->verbose_p)
638 fprintf (real_stderr, "%s: no vroot to restore; exiting.\n", blurb());
642 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
643 if (status == 0) status = 1;
644 else if (status == 1) status = -1;
647 bugp = !!dump_core_reason;
649 if (si->prefs.debug_p && !dump_core_reason)
650 dump_core_reason = "because of -debug";
652 if (dump_core_reason)
654 /* Note that the Linux man page for setuid() says If uid is
655 different from the old effective uid, the process will be
656 forbidden from leaving core dumps.
658 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
660 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
665 "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
666 "\t\tfor bug reporting information.\n\n",
669 # if defined(HAVE_GETCWD)
670 if (!getcwd (cwd, sizeof(cwd)))
671 # elif defined(HAVE_GETWD)
674 strcpy(cwd, "unknown.");
676 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
677 describe_uids (si, real_stderr);
679 /* Do this to drop a core file, so that we can get a stack trace. */
687 /* Managing the actual screensaver window */
690 window_exists_p (Display *dpy, Window window)
692 XErrorHandler old_handler;
693 XWindowAttributes xgwa;
695 old_handler = XSetErrorHandler (BadWindow_ehandler);
696 XGetWindowAttributes (dpy, window, &xgwa);
698 XSetErrorHandler (old_handler);
699 return (xgwa.screen != 0);
703 store_saver_id (saver_screen_info *ssi)
705 XClassHint class_hints;
706 saver_info *si = ssi->global;
707 unsigned long pid = (unsigned long) getpid ();
709 struct passwd *p = getpwuid (getuid ());
710 const char *name, *host;
713 /* First store the name and class on the window.
715 class_hints.res_name = progname;
716 class_hints.res_class = progclass;
717 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
718 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
720 /* Then store the xscreensaver version number.
722 XChangeProperty (si->dpy, ssi->screensaver_window,
723 XA_SCREENSAVER_VERSION,
724 XA_STRING, 8, PropModeReplace,
725 (unsigned char *) si->version,
726 strlen (si->version));
728 /* Now store the XSCREENSAVER_ID property, that says what user and host
729 xscreensaver is running as.
732 if (p && p->pw_name && *p->pw_name)
736 sprintf (buf, "%lu", (unsigned long) p->pw_uid);
742 # if defined(HAVE_UNAME)
745 if (uname (&uts) < 0)
751 host = getenv("SYS$NODE");
752 # else /* !HAVE_UNAME && !VMS */
754 # endif /* !HAVE_UNAME && !VMS */
756 id = (char *) malloc (strlen(name) + strlen(host) + 50);
757 sprintf (id, "%lu (%s@%s)", pid, name, host);
759 XChangeProperty (si->dpy, ssi->screensaver_window,
760 XA_SCREENSAVER_ID, XA_STRING,
762 (unsigned char *) id, strlen (id));
768 initialize_screensaver_window_1 (saver_screen_info *ssi)
770 saver_info *si = ssi->global;
771 saver_preferences *p = &si->prefs;
772 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
774 /* This resets the screensaver window as fully as possible, since there's
775 no way of knowing what some random client may have done to us in the
776 meantime. We could just destroy and recreate the window, but that has
777 its own set of problems...
780 XSetWindowAttributes attrs;
781 unsigned long attrmask;
782 int width = WidthOfScreen (ssi->screen);
783 int height = HeightOfScreen (ssi->screen);
784 static Bool printed_visual_info = False; /* only print the message once. */
786 black.red = black.green = black.blue = 0;
788 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
791 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
792 /* It's not the default visual, so we have no choice but to install. */
793 install_cmap_p = True;
799 ssi->cmap = XCreateColormap (si->dpy,
800 RootWindowOfScreen (ssi->screen),
801 ssi->current_visual, AllocNone);
802 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
803 ssi->black_pixel = black.pixel;
808 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
811 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
812 if (ssi->cmap != ssi->demo_cmap &&
813 ssi->cmap != def_cmap)
814 XFreeColormap (si->dpy, ssi->cmap);
816 ssi->cmap = def_cmap;
817 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
820 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
821 CWBackPixel | CWBackingPixel | CWBorderPixel);
822 attrs.override_redirect = True;
824 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
825 actually be reading these events during normal operation; but we still
826 need to see Button events for demo-mode to work properly.
828 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
829 ButtonPressMask | ButtonReleaseMask |
832 attrs.backing_store = NotUseful;
833 attrs.colormap = ssi->cmap;
834 attrs.background_pixel = ssi->black_pixel;
835 attrs.backing_pixel = ssi->black_pixel;
836 attrs.border_pixel = ssi->black_pixel;
838 if (p->debug_p) width = width / 2;
840 if (!p->verbose_p || printed_visual_info)
842 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
844 fprintf (stderr, "%s: using default visual ", blurb());
845 describe_visual (stderr, ssi->screen, ssi->current_visual,
850 fprintf (stderr, "%s: using visual: ", blurb());
851 describe_visual (stderr, ssi->screen, ssi->current_visual,
853 fprintf (stderr, "%s: default visual: ", blurb());
854 describe_visual (stderr, ssi->screen,
855 DefaultVisualOfScreen (ssi->screen),
856 ssi->install_cmap_p);
858 printed_visual_info = True;
860 #ifdef HAVE_MIT_SAVER_EXTENSION
861 if (si->using_mit_saver_extension)
863 XScreenSaverInfo *info;
864 Window root = RootWindowOfScreen (ssi->screen);
867 /* This call sets the server screensaver timeouts to what we think
868 they should be (based on the resources and args xscreensaver was
869 started with.) It's important that we do this to sync back up
870 with the server - if we have turned on prematurely, as by an
871 ACTIVATE ClientMessage, then the server may decide to activate
872 the screensaver while it's already active. That's ok for us,
873 since we would know to ignore that ScreenSaverActivate event,
874 but a side effect of this would be that the server would map its
875 saver window (which we then hide again right away) meaning that
876 the bits currently on the screen get blown away. Ugly. */
878 /* #### Ok, that doesn't work - when we tell the server that the
879 screensaver is "off" it sends us a Deactivate event, which is
880 sensible... but causes the saver to never come on. Hmm. */
881 disable_builtin_screensaver (si, True);
885 /* #### The MIT-SCREEN-SAVER extension gives us access to the
886 window that the server itself uses for saving the screen.
887 However, using this window in any way, in particular, calling
888 XScreenSaverSetAttributes() as below, tends to make the X server
889 crash. So fuck it, let's try and get along without using it...
891 It's also inconvenient to use this window because it doesn't
892 always exist (though the ID is constant.) So to use this
893 window, we'd have to reimplement the ACTIVATE ClientMessage to
894 tell the *server* to tell *us* to turn on, to cause the window
895 to get created at the right time. Gag. */
896 XScreenSaverSetAttributes (si->dpy, root,
897 0, 0, width, height, 0,
898 current_depth, InputOutput, visual,
900 XSync (si->dpy, False);
903 info = XScreenSaverAllocInfo ();
904 XScreenSaverQueryInfo (si->dpy, root, info);
905 ssi->server_mit_saver_window = info->window;
906 if (! ssi->server_mit_saver_window) abort ();
909 #endif /* HAVE_MIT_SAVER_EXTENSION */
911 if (ssi->screensaver_window)
913 XWindowChanges changes;
914 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
917 changes.width = width;
918 changes.height = height;
919 changes.border_width = 0;
921 XConfigureWindow (si->dpy, ssi->screensaver_window,
922 changesmask, &changes);
923 XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
928 ssi->screensaver_window =
929 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen), 0, 0,
930 width, height, 0, ssi->current_depth, InputOutput,
931 ssi->current_visual, attrmask, &attrs);
933 store_activate_time(si, True);
935 fprintf (stderr, "%s: saver window is 0x%lx.\n",
936 blurb(), (unsigned long) ssi->screensaver_window);
940 store_saver_id (ssi);
945 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
947 BlackPixelOfScreen (ssi->screen),
948 BlackPixelOfScreen (ssi->screen),
950 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
952 XFreePixmap (si->dpy, bit);
955 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
958 XUndefineCursor (si->dpy, ssi->screensaver_window);
960 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
964 initialize_screensaver_window (saver_info *si)
967 for (i = 0; i < si->nscreens; i++)
968 initialize_screensaver_window_1 (&si->screens[i]);
973 raise_window (saver_info *si,
974 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
976 saver_preferences *p = &si->prefs;
982 initialize_screensaver_window (si);
983 reset_watchdog_timer (si, True);
985 if (p->fade_p && p->fading_possible_p && !inhibit_fade)
987 Window *current_windows = (Window *)
988 calloc(sizeof(Window), si->nscreens);
989 Colormap *current_maps = (Colormap *)
990 calloc(sizeof(Colormap), si->nscreens);
992 for (i = 0; i < si->nscreens; i++)
994 saver_screen_info *ssi = &si->screens[i];
995 current_windows[i] = ssi->screensaver_window;
996 current_maps[i] = (between_hacks_p
998 : DefaultColormapOfScreen (ssi->screen));
999 /* Ensure that the default background of the window is really black,
1000 not a pixmap or something. (This does not clear the window.) */
1001 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1005 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1007 XGrabServer (si->dpy); /* ############ DANGER! */
1009 /* Clear the stderr layer on each screen.
1012 for (i = 0; i < si->nscreens; i++)
1014 saver_screen_info *ssi = &si->screens[i];
1015 if (ssi->stderr_overlay_window)
1016 /* Do this before the fade, since the stderr cmap won't fade
1017 even if we uninstall it (beats me...) */
1021 /* Note! The server is grabbed, and this will take several seconds
1023 fade_screens (si->dpy, current_maps, current_windows,
1024 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1027 free(current_windows);
1029 current_windows = 0;
1031 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1033 #ifdef HAVE_MIT_SAVER_EXTENSION
1034 for (i = 0; i < si->nscreens; i++)
1036 saver_screen_info *ssi = &si->screens[i];
1037 if (ssi->server_mit_saver_window &&
1038 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1039 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1041 #endif /* HAVE_MIT_SAVER_EXTENSION */
1043 XUngrabServer (si->dpy);
1044 XSync (si->dpy, False); /* ###### (danger over) */
1048 for (i = 0; i < si->nscreens; i++)
1050 saver_screen_info *ssi = &si->screens[i];
1052 XClearWindow (si->dpy, ssi->screensaver_window);
1053 if (!dont_clear || ssi->stderr_overlay_window)
1055 XMapRaised (si->dpy, ssi->screensaver_window);
1056 #ifdef HAVE_MIT_SAVER_EXTENSION
1057 if (ssi->server_mit_saver_window &&
1058 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1059 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1060 #endif /* HAVE_MIT_SAVER_EXTENSION */
1064 for (i = 0; i < si->nscreens; i++)
1066 saver_screen_info *ssi = &si->screens[i];
1068 XInstallColormap (si->dpy, ssi->cmap);
1073 blank_screen (saver_info *si)
1077 /* Note: we do our grabs on the root window, not on the screensaver window.
1078 If we grabbed on the saver window, then the demo mode and lock dialog
1079 boxes wouldn't get any events.
1081 grab_keyboard_and_mouse (si,
1082 /*si->screens[0].screensaver_window,*/
1083 RootWindowOfScreen(si->screens[0].screen),
1086 : si->screens[0].cursor));
1088 for (i = 0; i < si->nscreens; i++)
1090 saver_screen_info *ssi = &si->screens[i];
1092 save_real_vroot (ssi);
1093 store_vroot_property (si->dpy,
1094 ssi->screensaver_window,
1095 ssi->screensaver_window);
1097 store_activate_time (si, si->screen_blanked_p);
1098 raise_window (si, False, False, False);
1100 #ifdef HAVE_XHPDISABLERESET
1101 if (si->locked_p && !hp_locked_p)
1103 XHPDisableReset (si->dpy); /* turn off C-Sh-Reset */
1108 #ifdef HAVE_VT_LOCKSWITCH
1110 lock_vt (si, True); /* turn off C-Alt-Fn */
1113 si->screen_blanked_p = True;
1117 unblank_screen (saver_info *si)
1119 saver_preferences *p = &si->prefs;
1120 Bool unfade_p = (p->fading_possible_p && p->unfade_p);
1123 monitor_power_on (si);
1125 store_activate_time (si, True);
1126 reset_watchdog_timer (si, False);
1133 Window *current_windows = (Window *)
1134 calloc(sizeof(Window), si->nscreens);
1136 for (i = 0; i < si->nscreens; i++)
1138 saver_screen_info *ssi = &si->screens[i];
1139 current_windows[i] = ssi->screensaver_window;
1140 /* Ensure that the default background of the window is really black,
1141 not a pixmap or something. (This does not clear the window.) */
1142 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1146 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1149 XSync (si->dpy, False);
1150 XGrabServer (si->dpy); /* ############ DANGER! */
1151 XSync (si->dpy, False);
1153 /* Clear the stderr layer on each screen.
1155 for (i = 0; i < si->nscreens; i++)
1157 saver_screen_info *ssi = &si->screens[i];
1161 XUngrabServer (si->dpy);
1162 XSync (si->dpy, False); /* ###### (danger over) */
1165 fade_screens (si->dpy, 0, current_windows,
1166 p->fade_seconds/1000, p->fade_ticks,
1169 free(current_windows);
1170 current_windows = 0;
1172 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1176 for (i = 0; i < si->nscreens; i++)
1178 saver_screen_info *ssi = &si->screens[i];
1181 Colormap c = DefaultColormapOfScreen (ssi->screen);
1182 /* avoid technicolor */
1183 XClearWindow (si->dpy, ssi->screensaver_window);
1184 if (c) XInstallColormap (si->dpy, c);
1186 XUnmapWindow (si->dpy, ssi->screensaver_window);
1191 /* If the focus window does has a non-default colormap, then install
1192 that colormap as well. (On SGIs, this will cause both the root map
1193 and the focus map to be installed simultaniously. It'd be nice to
1194 pick up the other colormaps that had been installed, too; perhaps
1195 XListInstalledColormaps could be used for that?)
1200 XGetInputFocus (si->dpy, &focus, &revert_to);
1201 if (focus && focus != PointerRoot && focus != None)
1203 XWindowAttributes xgwa;
1205 XGetWindowAttributes (si->dpy, focus, &xgwa);
1206 if (xgwa.colormap &&
1207 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1208 XInstallColormap (si->dpy, xgwa.colormap);
1213 for (i = 0; i < si->nscreens; i++)
1215 saver_screen_info *ssi = &si->screens[i];
1216 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1219 store_activate_time(si, False); /* store unblank time */
1221 ungrab_keyboard_and_mouse (si);
1222 restore_real_vroot (si);
1224 #ifdef HAVE_XHPDISABLERESET
1227 XHPEnableReset (si->dpy); /* turn C-Sh-Reset back on */
1228 hp_locked_p = False;
1232 #ifdef HAVE_VT_LOCKSWITCH
1233 lock_vt (si, False); /* turn C-Alt-Fn back on */
1236 /* Unmap the windows a second time, dammit -- just to avoid a race
1237 with the screen-grabbing hacks. (I'm not sure if this is really
1238 necessary; I'm stabbing in the dark now.)
1240 for (i = 0; i < si->nscreens; i++)
1241 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1243 si->screen_blanked_p = False;
1248 store_activate_time (saver_info *si, Bool use_last_p)
1250 static time_t last_time = 0;
1251 time_t now = ((use_last_p && last_time) ? last_time : time ((time_t) 0));
1252 CARD32 now32 = (CARD32) now;
1256 for (i = 0; i < si->nscreens; i++)
1258 saver_screen_info *ssi = &si->screens[i];
1259 if (!ssi->screensaver_window) continue;
1260 XChangeProperty (si->dpy, ssi->screensaver_window, XA_SCREENSAVER_TIME,
1261 XA_INTEGER, 32, PropModeReplace,
1262 (unsigned char *) &now32, 1);
1268 select_visual (saver_screen_info *ssi, const char *visual_name)
1270 saver_info *si = ssi->global;
1271 saver_preferences *p = &si->prefs;
1272 Bool install_cmap_p = p->install_cmap_p;
1273 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1277 if (visual_name && *visual_name)
1279 if (!strcmp(visual_name, "default-i"))
1281 visual_name = "default";
1282 install_cmap_p = True;
1284 else if (!strcmp(visual_name, "default-n"))
1286 visual_name = "default";
1287 install_cmap_p = False;
1289 new_v = get_visual (ssi->screen, visual_name, True, False);
1293 new_v = ssi->default_visual;
1298 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1299 /* It's not the default visual, so we have no choice but to install. */
1300 install_cmap_p = True;
1302 ssi->install_cmap_p = install_cmap_p;
1305 ((ssi->current_visual != new_v) ||
1306 (install_cmap_p != was_installed_p)))
1308 Colormap old_c = ssi->cmap;
1309 Window old_w = ssi->screensaver_window;
1313 fprintf (stderr, "%s: switching to visual ", blurb());
1314 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1316 fprintf (stderr, "%s: from ", blurb());
1317 describe_visual (stderr, ssi->screen, ssi->current_visual,
1323 ssi->current_visual = new_v;
1324 ssi->current_depth = visual_depth(ssi->screen, new_v);
1326 ssi->screensaver_window = 0;
1328 initialize_screensaver_window_1 (ssi);
1330 /* stderr_overlay_window is a child of screensaver_window, so we need
1331 to destroy that as well (actually, we just need to invalidate and
1332 drop our pointers to it, but this will destroy it, which is ok so
1333 long as it happens before old_w itself is destroyed.) */
1336 raise_window (si, True, True, False);
1337 store_vroot_property (si->dpy,
1338 ssi->screensaver_window, ssi->screensaver_window);
1339 store_activate_time (si, True);
1343 /* Transfer the grabs from the old window to the new.
1344 Actually I think none of this is necessary, since we always
1345 hold our grabs on the root window, but I wrote this before
1346 re-discovering that...
1350 /* If we're destroying the window that holds our mouse grab,
1351 transfer the grab to the new window. (Grab the server while
1352 so doing, to avoid a race condition.)
1354 if (old_w == si->mouse_grab_window)
1356 XGrabServer (si->dpy); /* ############ DANGER! */
1358 grab_mouse (si, ssi->screensaver_window,
1362 XUngrabServer (si->dpy);
1363 XSync (si->dpy, False); /* ###### (danger over) */
1366 /* If we're destroying the window that holds our keyboard grab,
1367 transfer the grab to the new window. (Grab the server while
1368 so doing, to avoid a race condition.)
1370 if (old_w == si->keyboard_grab_window)
1372 XGrabServer (si->dpy); /* ############ DANGER! */
1374 grab_kbd(si, ssi->screensaver_window);
1375 XUngrabServer (si->dpy);
1376 XSync (si->dpy, False); /* ###### (danger over) */
1379 /* Now we can destroy this window without horking our grabs. */
1381 XDestroyWindow (si->dpy, old_w);
1384 fprintf (stderr, "%s: destroyed old saver window 0x%lx.\n",
1385 blurb(), (unsigned long) old_w);
1388 old_c != DefaultColormapOfScreen (ssi->screen) &&
1389 old_c != ssi->demo_cmap)
1390 XFreeColormap (si->dpy, old_c);
1399 #ifdef HAVE_VT_LOCKSWITCH
1401 lock_vt (saver_info *si, Bool lock_p)
1403 saver_preferences *p = &si->prefs;
1404 static Bool locked_p = False;
1405 const char *dev_console = "/dev/console";
1408 if (lock_p == locked_p)
1411 if (lock_p && !p->lock_vt_p)
1414 fd = open (dev_console, O_RDWR);
1418 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
1419 (lock_p ? "lock" : "unlock"),
1421 #if 0 /* #### doesn't work yet, so don't bother complaining */
1427 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
1432 fprintf (stderr, "%s: %s VTs\n", blurb(),
1433 (lock_p ? "locked" : "unlocked"));
1438 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
1439 (lock_p ? "lock" : "unlock"));
1440 #if 0 /* #### doesn't work yet, so don't bother complaining */
1447 #endif /* HAVE_VT_LOCKSWITCH */