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_string(int status)
101 case GrabSuccess: return "GrabSuccess"; break;
102 case AlreadyGrabbed: return "AlreadyGrabbed"; break;
103 case GrabInvalidTime: return "GrabInvalidTime"; break;
104 case GrabNotViewable: return "GrabNotViewable"; break;
105 case GrabFrozen: return "GrabFrozen"; break;
108 static char foo[255];
109 sprintf(foo, "unknown status: %d", status);
116 grab_kbd(saver_info *si, Window w)
118 saver_preferences *p = &si->prefs;
119 int status = XGrabKeyboard (si->dpy, w, True,
120 /* I don't really understand Sync vs Async,
121 but these seem to work... */
122 GrabModeSync, GrabModeAsync,
124 if (status == GrabSuccess)
125 si->keyboard_grab_window = w;
128 fprintf(stderr, "%s: grabbing keyboard on 0x%x... %s.\n",
129 blurb(), (unsigned long) w, grab_string(status));
135 grab_mouse (saver_info *si, Window w, Cursor cursor)
137 saver_preferences *p = &si->prefs;
138 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
139 GrabModeAsync, GrabModeAsync, None,
140 cursor, CurrentTime);
141 if (status == GrabSuccess)
142 si->mouse_grab_window = w;
145 fprintf(stderr, "%s: grabbing mouse on 0x%x... %s.\n",
146 blurb(), (unsigned long) w, grab_string(status));
152 ungrab_kbd(saver_info *si)
154 saver_preferences *p = &si->prefs;
155 XUngrabKeyboard(si->dpy, CurrentTime);
157 fprintf(stderr, "%s: ungrabbing keyboard (was 0x%x).\n", blurb(),
158 (unsigned long) si->keyboard_grab_window);
159 si->keyboard_grab_window = 0;
164 ungrab_mouse(saver_info *si)
166 saver_preferences *p = &si->prefs;
167 XUngrabPointer(si->dpy, CurrentTime);
169 fprintf(stderr, "%s: ungrabbing mouse (was 0x%x).\n", blurb(),
170 (unsigned long) si->mouse_grab_window);
171 si->mouse_grab_window = 0;
176 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor)
178 Status mstatus, kstatus;
179 XSync (si->dpy, False);
181 kstatus = grab_kbd (si, window);
182 if (kstatus != GrabSuccess)
183 { /* try again in a second */
185 kstatus = grab_kbd (si, window);
186 if (kstatus != GrabSuccess)
187 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
188 blurb(), grab_string(kstatus));
191 mstatus = grab_mouse (si, window, cursor);
192 if (mstatus != GrabSuccess)
193 { /* try again in a second */
195 mstatus = grab_mouse (si, window, cursor);
196 if (mstatus != GrabSuccess)
197 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
198 blurb(), grab_string(mstatus));
201 return (kstatus == GrabSuccess ||
202 mstatus == GrabSuccess);
206 ungrab_keyboard_and_mouse (saver_info *si)
213 /* Prints an error message to stderr and returns True if there is another
214 xscreensaver running already. Silently returns False otherwise. */
216 ensure_no_screensaver_running (Display *dpy, Screen *screen)
220 Window root = RootWindowOfScreen (screen);
221 Window root2, parent, *kids;
223 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
225 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
231 for (i = 0; i < nkids; i++)
235 unsigned long nitems, bytesafter;
238 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
239 False, XA_STRING, &type, &format, &nitems,
240 &bytesafter, (unsigned char **) &version)
245 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
246 False, XA_STRING, &type, &format, &nitems,
247 &bytesafter, (unsigned char **) &id)
253 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
254 blurb(), DisplayString (dpy), (int) kids [i], id);
259 if (kids) XFree ((char *) kids);
261 XSetErrorHandler (old_handler);
267 /* Virtual-root hackery */
270 ERROR! You must not include vroot.h in this file.
274 store_vroot_property (Display *dpy, Window win, Window value)
279 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
281 (win == screensaver_window ? "ScreenSaver" :
282 (win == real_vroot ? "VRoot" :
283 (win == real_vroot_value ? "Vroot_value" : "???"))),
285 (value == screensaver_window ? "ScreenSaver" :
286 (value == real_vroot ? "VRoot" :
287 (value == real_vroot_value ? "Vroot_value" : "???"))));
289 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
290 (unsigned char *) &value, 1);
294 remove_vroot_property (Display *dpy, Window win)
298 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
299 (win == screensaver_window ? "ScreenSaver" :
300 (win == real_vroot ? "VRoot" :
301 (win == real_vroot_value ? "Vroot_value" : "???"))));
303 XDeleteProperty (dpy, win, XA_VROOT);
308 kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p)
312 unsigned long nitems, bytesafter;
315 /* If the user has been using xv or xsetroot as a screensaver (to display
316 an image on the screensaver window, as a kind of slideshow) then the
317 pixmap and its associated color cells have been put in RetainPermanent
318 CloseDown mode. Since we're not destroying the xscreensaver window,
319 but merely unmapping it, we need to free these resources or those
320 colormap cells will stay allocated while the screensaver is off. (We
321 could just delete the screensaver window and recreate it later, but
322 that could cause other problems.) This code does an atomic read-and-
323 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
324 cause the RetainPermanent resources of the client which created it
325 (and which no longer exists) to be freed.
327 if (XGetWindowProperty (dpy, window, XA_XSETROOT_ID, 0, 1,
328 True, AnyPropertyType, &type, &format, &nitems,
329 &bytesafter, (unsigned char **) &dataP)
333 if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
334 nitems == 1 && bytesafter == 0)
337 fprintf (stderr, "%s: destroying xsetroot data (0x%lX).\n",
339 XKillClient (dpy, *dataP);
342 fprintf (stderr, "%s: deleted unrecognised _XSETROOT_ID property: \n\
343 %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n",
344 blurb(), (unsigned long) dataP, (dataP ? *dataP : 0), type,
345 format, nitems, bytesafter);
350 static void handle_signals (saver_info *si, Bool on_p);
353 save_real_vroot (saver_screen_info *ssi)
355 saver_info *si = ssi->global;
356 Display *dpy = si->dpy;
357 Screen *screen = ssi->screen;
359 Window root = RootWindowOfScreen (screen);
360 Window root2, parent, *kids;
362 XErrorHandler old_handler;
364 /* It's possible that a window might be deleted between our call to
365 XQueryTree() and our call to XGetWindowProperty(). Don't die if
366 that happens (but just ignore that window, it's not the one we're
367 interested in anyway.)
370 old_handler = XSetErrorHandler (BadWindow_ehandler);
374 ssi->real_vroot_value = 0;
375 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
381 for (i = 0; i < nkids; i++)
385 unsigned long nitems, bytesafter;
388 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
389 &type, &format, &nitems, &bytesafter,
390 (unsigned char **) &vrootP)
397 if (*vrootP == ssi->screensaver_window) abort ();
399 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
400 blurb(), (int) ssi->real_vroot, (int) kids [i]);
403 ssi->real_vroot = kids [i];
404 ssi->real_vroot_value = *vrootP;
408 XSetErrorHandler (old_handler);
413 handle_signals (si, True);
414 remove_vroot_property (si->dpy, ssi->real_vroot);
418 XFree ((char *) kids);
423 restore_real_vroot_2 (saver_screen_info *ssi)
425 saver_info *si = ssi->global;
426 saver_preferences *p = &si->prefs;
427 if (p->verbose_p && ssi->real_vroot)
429 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
430 blurb(), (unsigned long) ssi->real_vroot);
431 remove_vroot_property (si->dpy, ssi->screensaver_window);
434 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
436 ssi->real_vroot_value = 0;
437 /* make sure the property change gets there before this process
438 terminates! We might be doing this because we have intercepted
439 SIGTERM or something. */
440 XSync (si->dpy, False);
447 restore_real_vroot_1 (saver_info *si)
450 Bool did_any = False;
451 for (i = 0; i < si->nscreens; i++)
453 saver_screen_info *ssi = &si->screens[i];
454 if (restore_real_vroot_2 (ssi))
461 restore_real_vroot (saver_info *si)
463 if (restore_real_vroot_1 (si))
464 handle_signals (si, False);
468 /* Signal hackery to ensure that the vroot doesn't get left in an
473 signal_name(int signal)
476 case SIGHUP: return "SIGHUP";
477 case SIGINT: return "SIGINT";
478 case SIGQUIT: return "SIGQUIT";
479 case SIGILL: return "SIGILL";
480 case SIGTRAP: return "SIGTRAP";
482 case SIGABRT: return "SIGABRT";
484 case SIGFPE: return "SIGFPE";
485 case SIGKILL: return "SIGKILL";
486 case SIGBUS: return "SIGBUS";
487 case SIGSEGV: return "SIGSEGV";
488 case SIGPIPE: return "SIGPIPE";
489 case SIGALRM: return "SIGALRM";
490 case SIGTERM: return "SIGTERM";
492 case SIGSTOP: return "SIGSTOP";
495 case SIGCONT: return "SIGCONT";
498 case SIGUSR1: return "SIGUSR1";
501 case SIGUSR2: return "SIGUSR2";
504 case SIGEMT: return "SIGEMT";
507 case SIGSYS: return "SIGSYS";
510 case SIGCHLD: return "SIGCHLD";
513 case SIGPWR: return "SIGPWR";
516 case SIGWINCH: return "SIGWINCH";
519 case SIGURG: return "SIGURG";
522 case SIGIO: return "SIGIO";
525 case SIGVTALRM: return "SIGVTALRM";
528 case SIGXCPU: return "SIGXCPU";
531 case SIGXFSZ: return "SIGXFSZ";
534 case SIGDANGER: return "SIGDANGER";
539 sprintf(buf, "signal %d\n", signal);
548 restore_real_vroot_handler (int sig)
550 saver_info *si = global_si_kludge; /* I hate C so much... */
552 signal (sig, SIG_DFL);
553 if (restore_real_vroot_1 (si))
554 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
555 blurb(), signal_name(sig));
556 kill (getpid (), sig);
560 catch_signal (saver_info *si, int sig, Bool on_p)
563 signal (sig, SIG_DFL);
566 if (((long) signal (sig, restore_real_vroot_handler)) == -1L)
569 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
571 saver_exit (si, 1, 0);
577 handle_signals (saver_info *si, Bool on_p)
580 if (on_p) fprintf (stderr, "handling signals\n");
581 else fprintf (stderr, "unhandling signals\n");
584 catch_signal (si, SIGHUP, on_p);
585 catch_signal (si, SIGINT, on_p);
586 catch_signal (si, SIGQUIT, on_p);
587 catch_signal (si, SIGILL, on_p);
588 catch_signal (si, SIGTRAP, on_p);
589 catch_signal (si, SIGIOT, on_p);
590 catch_signal (si, SIGABRT, on_p);
592 catch_signal (si, SIGEMT, on_p);
594 catch_signal (si, SIGFPE, on_p);
595 catch_signal (si, SIGBUS, on_p);
596 catch_signal (si, SIGSEGV, on_p);
598 catch_signal (si, SIGSYS, on_p);
600 catch_signal (si, SIGTERM, on_p);
602 catch_signal (si, SIGXCPU, on_p);
605 catch_signal (si, SIGXFSZ, on_p);
608 catch_signal (si, SIGDANGER, on_p);
613 saver_exit (saver_info *si, int status, const char *dump_core_reason)
615 saver_preferences *p = &si->prefs;
616 static Bool exiting = False;
625 vrs = restore_real_vroot_1 (si);
626 emergency_kill_subproc (si);
628 if (vrs && (p->verbose_p || status != 0))
629 fprintf (real_stderr, "%s: vroot restored, exiting.\n", blurb());
630 else if (p->verbose_p)
631 fprintf (real_stderr, "%s: no vroot to restore; exiting.\n", blurb());
635 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
636 if (status == 0) status = 1;
637 else if (status == 1) status = -1;
640 bugp = !!dump_core_reason;
642 if (si->prefs.debug_p && !dump_core_reason)
643 dump_core_reason = "because of -debug";
645 if (dump_core_reason)
647 /* Note that the Linux man page for setuid() says If uid is
648 different from the old effective uid, the process will be
649 forbidden from leaving core dumps.
651 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
653 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
658 "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
659 "\t\tfor bug reporting information.\n\n",
662 # if defined(HAVE_GETCWD)
663 if (!getcwd (cwd, sizeof(cwd)))
664 # elif defined(HAVE_GETWD)
667 strcpy(cwd, "unknown.");
669 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
670 describe_uids (si, real_stderr);
672 /* Do this to drop a core file, so that we can get a stack trace. */
680 /* Managing the actual screensaver window */
683 window_exists_p (Display *dpy, Window window)
685 XErrorHandler old_handler;
686 XWindowAttributes xgwa;
688 old_handler = XSetErrorHandler (BadWindow_ehandler);
689 XGetWindowAttributes (dpy, window, &xgwa);
691 XSetErrorHandler (old_handler);
692 return (xgwa.screen != 0);
696 store_saver_id (saver_screen_info *ssi)
698 XClassHint class_hints;
699 saver_info *si = ssi->global;
700 unsigned long pid = (unsigned long) getpid ();
702 struct passwd *p = getpwuid (getuid ());
703 const char *name, *host;
706 /* First store the name and class on the window.
708 class_hints.res_name = progname;
709 class_hints.res_class = progclass;
710 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
711 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
713 /* Then store the xscreensaver version number.
715 XChangeProperty (si->dpy, ssi->screensaver_window,
716 XA_SCREENSAVER_VERSION,
717 XA_STRING, 8, PropModeReplace,
718 (unsigned char *) si->version,
719 strlen (si->version));
721 /* Now store the XSCREENSAVER_ID property, that says what user and host
722 xscreensaver is running as.
725 if (p && p->pw_name && *p->pw_name)
729 sprintf (buf, "%lu", (unsigned long) p->pw_uid);
735 # if defined(HAVE_UNAME)
738 if (uname (&uts) < 0)
744 host = getenv("SYS$NODE");
745 # else /* !HAVE_UNAME && !VMS */
747 # endif /* !HAVE_UNAME && !VMS */
749 id = (char *) malloc (strlen(name) + strlen(host) + 50);
750 sprintf (id, "%lu (%s@%s)", pid, name, host);
752 XChangeProperty (si->dpy, ssi->screensaver_window,
753 XA_SCREENSAVER_ID, XA_STRING,
755 (unsigned char *) id, strlen (id));
761 initialize_screensaver_window_1 (saver_screen_info *ssi)
763 saver_info *si = ssi->global;
764 saver_preferences *p = &si->prefs;
765 Bool install_cmap_p = ssi->install_cmap_p; /* not p->install_cmap_p */
767 /* This resets the screensaver window as fully as possible, since there's
768 no way of knowing what some random client may have done to us in the
769 meantime. We could just destroy and recreate the window, but that has
770 its own set of problems...
773 XSetWindowAttributes attrs;
774 unsigned long attrmask;
775 int width = WidthOfScreen (ssi->screen);
776 int height = HeightOfScreen (ssi->screen);
777 static Bool printed_visual_info = False; /* only print the message once. */
779 black.red = black.green = black.blue = 0;
781 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
784 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
785 /* It's not the default visual, so we have no choice but to install. */
786 install_cmap_p = True;
792 ssi->cmap = XCreateColormap (si->dpy,
793 RootWindowOfScreen (ssi->screen),
794 ssi->current_visual, AllocNone);
795 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
796 ssi->black_pixel = black.pixel;
801 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
804 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
805 if (ssi->cmap != ssi->demo_cmap &&
806 ssi->cmap != def_cmap)
807 XFreeColormap (si->dpy, ssi->cmap);
809 ssi->cmap = def_cmap;
810 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
813 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
814 CWBackPixel | CWBackingPixel | CWBorderPixel);
815 attrs.override_redirect = True;
817 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
818 actually be reading these events during normal operation; but we still
819 need to see Button events for demo-mode to work properly.
821 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
822 ButtonPressMask | ButtonReleaseMask |
825 attrs.backing_store = NotUseful;
826 attrs.colormap = ssi->cmap;
827 attrs.background_pixel = ssi->black_pixel;
828 attrs.backing_pixel = ssi->black_pixel;
829 attrs.border_pixel = ssi->black_pixel;
831 if (p->debug_p) width = width / 2;
833 if (!p->verbose_p || printed_visual_info)
835 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
837 fprintf (stderr, "%s: using default visual ", blurb());
838 describe_visual (stderr, ssi->screen, ssi->current_visual,
843 fprintf (stderr, "%s: using visual: ", blurb());
844 describe_visual (stderr, ssi->screen, ssi->current_visual,
846 fprintf (stderr, "%s: default visual: ", blurb());
847 describe_visual (stderr, ssi->screen,
848 DefaultVisualOfScreen (ssi->screen),
849 ssi->install_cmap_p);
851 printed_visual_info = True;
853 #ifdef HAVE_MIT_SAVER_EXTENSION
854 if (si->using_mit_saver_extension)
856 XScreenSaverInfo *info;
857 Window root = RootWindowOfScreen (ssi->screen);
860 /* This call sets the server screensaver timeouts to what we think
861 they should be (based on the resources and args xscreensaver was
862 started with.) It's important that we do this to sync back up
863 with the server - if we have turned on prematurely, as by an
864 ACTIVATE ClientMessage, then the server may decide to activate
865 the screensaver while it's already active. That's ok for us,
866 since we would know to ignore that ScreenSaverActivate event,
867 but a side effect of this would be that the server would map its
868 saver window (which we then hide again right away) meaning that
869 the bits currently on the screen get blown away. Ugly. */
871 /* #### Ok, that doesn't work - when we tell the server that the
872 screensaver is "off" it sends us a Deactivate event, which is
873 sensible... but causes the saver to never come on. Hmm. */
874 disable_builtin_screensaver (si, True);
878 /* #### The MIT-SCREEN-SAVER extension gives us access to the
879 window that the server itself uses for saving the screen.
880 However, using this window in any way, in particular, calling
881 XScreenSaverSetAttributes() as below, tends to make the X server
882 crash. So fuck it, let's try and get along without using it...
884 It's also inconvenient to use this window because it doesn't
885 always exist (though the ID is constant.) So to use this
886 window, we'd have to reimplement the ACTIVATE ClientMessage to
887 tell the *server* to tell *us* to turn on, to cause the window
888 to get created at the right time. Gag. */
889 XScreenSaverSetAttributes (si->dpy, root,
890 0, 0, width, height, 0,
891 current_depth, InputOutput, visual,
893 XSync (si->dpy, False);
896 info = XScreenSaverAllocInfo ();
897 XScreenSaverQueryInfo (si->dpy, root, info);
898 ssi->server_mit_saver_window = info->window;
899 if (! ssi->server_mit_saver_window) abort ();
902 #endif /* HAVE_MIT_SAVER_EXTENSION */
904 if (ssi->screensaver_window)
906 XWindowChanges changes;
907 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
910 changes.width = width;
911 changes.height = height;
912 changes.border_width = 0;
914 XConfigureWindow (si->dpy, ssi->screensaver_window,
915 changesmask, &changes);
916 XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
921 ssi->screensaver_window =
922 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen), 0, 0,
923 width, height, 0, ssi->current_depth, InputOutput,
924 ssi->current_visual, attrmask, &attrs);
926 store_activate_time(si, True);
928 fprintf (stderr, "%s: saver window is 0x%lx.\n",
929 blurb(), (unsigned long) ssi->screensaver_window);
933 store_saver_id (ssi);
938 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
940 BlackPixelOfScreen (ssi->screen),
941 BlackPixelOfScreen (ssi->screen),
943 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
945 XFreePixmap (si->dpy, bit);
948 XSetWindowBackground (si->dpy, ssi->screensaver_window, ssi->black_pixel);
951 XUndefineCursor (si->dpy, ssi->screensaver_window);
953 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
957 initialize_screensaver_window (saver_info *si)
960 for (i = 0; i < si->nscreens; i++)
961 initialize_screensaver_window_1 (&si->screens[i]);
966 raise_window (saver_info *si,
967 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
969 saver_preferences *p = &si->prefs;
975 initialize_screensaver_window (si);
976 reset_watchdog_timer (si, True);
978 if (p->fade_p && p->fading_possible_p && !inhibit_fade)
980 Window *current_windows = (Window *)
981 calloc(sizeof(Window), si->nscreens);
982 Colormap *current_maps = (Colormap *)
983 calloc(sizeof(Colormap), si->nscreens);
985 for (i = 0; i < si->nscreens; i++)
987 saver_screen_info *ssi = &si->screens[i];
988 current_windows[i] = ssi->screensaver_window;
989 current_maps[i] = (between_hacks_p
991 : DefaultColormapOfScreen (ssi->screen));
992 /* Ensure that the default background of the window is really black,
993 not a pixmap or something. (This does not clear the window.) */
994 XSetWindowBackground (si->dpy, ssi->screensaver_window,
998 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
1000 XGrabServer (si->dpy); /* ############ DANGER! */
1002 /* Clear the stderr layer on each screen.
1005 for (i = 0; i < si->nscreens; i++)
1007 saver_screen_info *ssi = &si->screens[i];
1008 if (ssi->stderr_overlay_window)
1009 /* Do this before the fade, since the stderr cmap won't fade
1010 even if we uninstall it (beats me...) */
1014 /* Note! The server is grabbed, and this will take several seconds
1016 fade_screens (si->dpy, current_maps, current_windows,
1017 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
1020 free(current_windows);
1022 current_windows = 0;
1024 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
1026 #ifdef HAVE_MIT_SAVER_EXTENSION
1027 for (i = 0; i < si->nscreens; i++)
1029 saver_screen_info *ssi = &si->screens[i];
1030 if (ssi->server_mit_saver_window &&
1031 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1032 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1034 #endif /* HAVE_MIT_SAVER_EXTENSION */
1036 XUngrabServer (si->dpy);
1037 XSync (si->dpy, False); /* ###### (danger over) */
1041 for (i = 0; i < si->nscreens; i++)
1043 saver_screen_info *ssi = &si->screens[i];
1045 XClearWindow (si->dpy, ssi->screensaver_window);
1046 if (!dont_clear || ssi->stderr_overlay_window)
1048 XMapRaised (si->dpy, ssi->screensaver_window);
1049 #ifdef HAVE_MIT_SAVER_EXTENSION
1050 if (ssi->server_mit_saver_window &&
1051 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1052 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1053 #endif /* HAVE_MIT_SAVER_EXTENSION */
1057 for (i = 0; i < si->nscreens; i++)
1059 saver_screen_info *ssi = &si->screens[i];
1061 XInstallColormap (si->dpy, ssi->cmap);
1066 blank_screen (saver_info *si)
1071 /* Note: we do our grabs on the root window, not on the screensaver window.
1072 If we grabbed on the saver window, then the demo mode and lock dialog
1073 boxes wouldn't get any events.
1075 ok = grab_keyboard_and_mouse (si,
1076 /*si->screens[0].screensaver_window,*/
1077 RootWindowOfScreen(si->screens[0].screen),
1080 : si->screens[0].cursor));
1083 if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1084 /* If we're using a server extension, then failure to get a grab is
1085 not a big deal -- even without the grab, we will still be able
1086 to un-blank when there is user activity, since the server will
1093 for (i = 0; i < si->nscreens; i++)
1095 saver_screen_info *ssi = &si->screens[i];
1097 save_real_vroot (ssi);
1098 store_vroot_property (si->dpy,
1099 ssi->screensaver_window,
1100 ssi->screensaver_window);
1102 store_activate_time (si, si->screen_blanked_p);
1103 raise_window (si, False, False, False);
1105 #ifdef HAVE_XHPDISABLERESET
1106 if (si->locked_p && !hp_locked_p)
1108 XHPDisableReset (si->dpy); /* turn off C-Sh-Reset */
1113 #ifdef HAVE_VT_LOCKSWITCH
1115 lock_vt (si, True); /* turn off C-Alt-Fn */
1118 si->screen_blanked_p = True;
1124 unblank_screen (saver_info *si)
1126 saver_preferences *p = &si->prefs;
1127 Bool unfade_p = (p->fading_possible_p && p->unfade_p);
1130 monitor_power_on (si);
1132 store_activate_time (si, True);
1133 reset_watchdog_timer (si, False);
1140 Window *current_windows = (Window *)
1141 calloc(sizeof(Window), si->nscreens);
1143 for (i = 0; i < si->nscreens; i++)
1145 saver_screen_info *ssi = &si->screens[i];
1146 current_windows[i] = ssi->screensaver_window;
1147 /* Ensure that the default background of the window is really black,
1148 not a pixmap or something. (This does not clear the window.) */
1149 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1153 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1156 XSync (si->dpy, False);
1157 XGrabServer (si->dpy); /* ############ DANGER! */
1158 XSync (si->dpy, False);
1160 /* Clear the stderr layer on each screen.
1162 for (i = 0; i < si->nscreens; i++)
1164 saver_screen_info *ssi = &si->screens[i];
1168 XUngrabServer (si->dpy);
1169 XSync (si->dpy, False); /* ###### (danger over) */
1172 fade_screens (si->dpy, 0, current_windows,
1173 p->fade_seconds/1000, p->fade_ticks,
1176 free(current_windows);
1177 current_windows = 0;
1179 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1183 for (i = 0; i < si->nscreens; i++)
1185 saver_screen_info *ssi = &si->screens[i];
1188 Colormap c = DefaultColormapOfScreen (ssi->screen);
1189 /* avoid technicolor */
1190 XClearWindow (si->dpy, ssi->screensaver_window);
1191 if (c) XInstallColormap (si->dpy, c);
1193 XUnmapWindow (si->dpy, ssi->screensaver_window);
1198 /* If the focus window does has a non-default colormap, then install
1199 that colormap as well. (On SGIs, this will cause both the root map
1200 and the focus map to be installed simultaniously. It'd be nice to
1201 pick up the other colormaps that had been installed, too; perhaps
1202 XListInstalledColormaps could be used for that?)
1207 XGetInputFocus (si->dpy, &focus, &revert_to);
1208 if (focus && focus != PointerRoot && focus != None)
1210 XWindowAttributes xgwa;
1212 XGetWindowAttributes (si->dpy, focus, &xgwa);
1213 if (xgwa.colormap &&
1214 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1215 XInstallColormap (si->dpy, xgwa.colormap);
1220 for (i = 0; i < si->nscreens; i++)
1222 saver_screen_info *ssi = &si->screens[i];
1223 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1226 store_activate_time(si, False); /* store unblank time */
1228 ungrab_keyboard_and_mouse (si);
1229 restore_real_vroot (si);
1231 #ifdef HAVE_XHPDISABLERESET
1234 XHPEnableReset (si->dpy); /* turn C-Sh-Reset back on */
1235 hp_locked_p = False;
1239 #ifdef HAVE_VT_LOCKSWITCH
1240 lock_vt (si, False); /* turn C-Alt-Fn back on */
1243 /* Unmap the windows a second time, dammit -- just to avoid a race
1244 with the screen-grabbing hacks. (I'm not sure if this is really
1245 necessary; I'm stabbing in the dark now.)
1247 for (i = 0; i < si->nscreens; i++)
1248 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1250 si->screen_blanked_p = False;
1255 store_activate_time (saver_info *si, Bool use_last_p)
1257 static time_t last_time = 0;
1258 time_t now = ((use_last_p && last_time) ? last_time : time ((time_t) 0));
1259 CARD32 now32 = (CARD32) now;
1263 for (i = 0; i < si->nscreens; i++)
1265 saver_screen_info *ssi = &si->screens[i];
1266 if (!ssi->screensaver_window) continue;
1267 XChangeProperty (si->dpy, ssi->screensaver_window, XA_SCREENSAVER_TIME,
1268 XA_INTEGER, 32, PropModeReplace,
1269 (unsigned char *) &now32, 1);
1275 select_visual (saver_screen_info *ssi, const char *visual_name)
1277 saver_info *si = ssi->global;
1278 saver_preferences *p = &si->prefs;
1279 Bool install_cmap_p = p->install_cmap_p;
1280 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1284 if (visual_name && *visual_name)
1286 if (!strcmp(visual_name, "default-i"))
1288 visual_name = "default";
1289 install_cmap_p = True;
1291 else if (!strcmp(visual_name, "default-n"))
1293 visual_name = "default";
1294 install_cmap_p = False;
1296 new_v = get_visual (ssi->screen, visual_name, True, False);
1300 new_v = ssi->default_visual;
1305 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1306 /* It's not the default visual, so we have no choice but to install. */
1307 install_cmap_p = True;
1309 ssi->install_cmap_p = install_cmap_p;
1312 ((ssi->current_visual != new_v) ||
1313 (install_cmap_p != was_installed_p)))
1315 Colormap old_c = ssi->cmap;
1316 Window old_w = ssi->screensaver_window;
1320 fprintf (stderr, "%s: switching to visual ", blurb());
1321 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1323 fprintf (stderr, "%s: from ", blurb());
1324 describe_visual (stderr, ssi->screen, ssi->current_visual,
1330 ssi->current_visual = new_v;
1331 ssi->current_depth = visual_depth(ssi->screen, new_v);
1333 ssi->screensaver_window = 0;
1335 initialize_screensaver_window_1 (ssi);
1337 /* stderr_overlay_window is a child of screensaver_window, so we need
1338 to destroy that as well (actually, we just need to invalidate and
1339 drop our pointers to it, but this will destroy it, which is ok so
1340 long as it happens before old_w itself is destroyed.) */
1343 raise_window (si, True, True, False);
1344 store_vroot_property (si->dpy,
1345 ssi->screensaver_window, ssi->screensaver_window);
1346 store_activate_time (si, True);
1350 /* Transfer the grabs from the old window to the new.
1351 Actually I think none of this is necessary, since we always
1352 hold our grabs on the root window, but I wrote this before
1353 re-discovering that...
1357 /* If we're destroying the window that holds our mouse grab,
1358 transfer the grab to the new window. (Grab the server while
1359 so doing, to avoid a race condition.)
1361 if (old_w == si->mouse_grab_window)
1363 XGrabServer (si->dpy); /* ############ DANGER! */
1365 grab_mouse (si, ssi->screensaver_window,
1369 XUngrabServer (si->dpy);
1370 XSync (si->dpy, False); /* ###### (danger over) */
1373 /* If we're destroying the window that holds our keyboard grab,
1374 transfer the grab to the new window. (Grab the server while
1375 so doing, to avoid a race condition.)
1377 if (old_w == si->keyboard_grab_window)
1379 XGrabServer (si->dpy); /* ############ DANGER! */
1381 grab_kbd(si, ssi->screensaver_window);
1382 XUngrabServer (si->dpy);
1383 XSync (si->dpy, False); /* ###### (danger over) */
1386 /* Now we can destroy this window without horking our grabs. */
1388 XDestroyWindow (si->dpy, old_w);
1391 fprintf (stderr, "%s: destroyed old saver window 0x%lx.\n",
1392 blurb(), (unsigned long) old_w);
1395 old_c != DefaultColormapOfScreen (ssi->screen) &&
1396 old_c != ssi->demo_cmap)
1397 XFreeColormap (si->dpy, old_c);
1406 #ifdef HAVE_VT_LOCKSWITCH
1408 lock_vt (saver_info *si, Bool lock_p)
1410 saver_preferences *p = &si->prefs;
1411 static Bool locked_p = False;
1412 const char *dev_console = "/dev/console";
1415 if (lock_p == locked_p)
1418 if (lock_p && !p->lock_vt_p)
1421 fd = open (dev_console, O_RDWR);
1425 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
1426 (lock_p ? "lock" : "unlock"),
1428 #if 0 /* #### doesn't work yet, so don't bother complaining */
1434 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
1439 fprintf (stderr, "%s: %s VTs\n", blurb(),
1440 (lock_p ? "locked" : "unlocked"));
1445 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
1446 (lock_p ? "lock" : "unlock"));
1447 #if 0 /* #### doesn't work yet, so don't bother complaining */
1454 #endif /* HAVE_VT_LOCKSWITCH */