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() */
20 # if !defined(HAVE_UNAME) && (__VMS_VER >= 70000000)
22 # endif /* !HAVE_UNAME */
26 # include <sys/utsname.h> /* for uname() */
27 # endif /* HAVE_UNAME */
30 #include <X11/Xproto.h> /* for CARD32 */
32 #include <X11/Xutil.h> /* for XSetClassHint() */
33 #include <X11/Xatom.h>
34 #include <X11/Xos.h> /* for time() */
35 #include <signal.h> /* for the signal names */
37 #ifdef HAVE_MIT_SAVER_EXTENSION
38 # include <X11/extensions/scrnsaver.h>
39 #endif /* HAVE_MIT_SAVER_EXTENSION */
42 #ifdef HAVE_XHPDISABLERESET
43 # include <X11/XHPlib.h>
45 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
46 or BadAccess errors occur. (Ok for this to be global, since it
47 affects the whole machine, not just the current screen.) */
48 Bool hp_locked_p = False;
50 #endif /* HAVE_XHPDISABLERESET */
53 /* This file doesn't need the Xt headers, so stub these types out... */
55 #define XtAppContext void*
56 #define XrmDatabase void*
57 #define XtIntervalId void*
58 #define XtPointer void*
61 #include "xscreensaver.h"
65 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
67 Atom XA_VROOT, XA_XSETROOT_ID;
68 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
69 Atom XA_SCREENSAVER_TIME;
72 extern saver_info *global_si_kludge; /* I hate C so much... */
75 static void store_activate_time (saver_info *si, Bool use_last_p);
77 #define ALL_POINTER_EVENTS \
78 (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
79 LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
80 Button1MotionMask | Button2MotionMask | Button3MotionMask | \
81 Button4MotionMask | Button5MotionMask | ButtonMotionMask)
85 grab_kbd(saver_info *si, Window w)
87 saver_preferences *p = &si->prefs;
88 int status = XGrabKeyboard (si->dpy, w, True,
89 /* I don't really understand Sync vs Async,
90 but these seem to work... */
91 GrabModeSync, GrabModeAsync,
93 if (status == GrabSuccess)
94 si->keyboard_grab_window = w;
97 fprintf(stderr, "%s: grabbing keyboard on 0x%x... %s.\n",
98 blurb(), (unsigned long) w,
99 (status == GrabSuccess ? "GrabSuccess" :
100 status == AlreadyGrabbed ? "AlreadyGrabbed" :
101 status == GrabInvalidTime ? "GrabInvalidTime" :
102 status == GrabNotViewable ? "GrabNotViewable" :
103 status == GrabFrozen ? "GrabFrozen" :
110 grab_string(int status)
114 case GrabSuccess: return "GrabSuccess"; break;
115 case AlreadyGrabbed: return "AlreadyGrabbed"; break;
116 case GrabInvalidTime: return "GrabInvalidTime"; break;
117 case GrabNotViewable: return "GrabNotViewable"; break;
118 case GrabFrozen: return "GrabFrozen"; break;
121 static char foo[255];
122 sprintf(foo, "unknown status: %d", status);
130 grab_mouse (saver_info *si, Window w, Cursor cursor)
132 saver_preferences *p = &si->prefs;
133 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
134 GrabModeAsync, GrabModeAsync, None,
135 cursor, CurrentTime);
136 if (status == GrabSuccess)
137 si->mouse_grab_window = w;
140 fprintf(stderr, "%s: grabbing mouse on 0x%x... %s.\n",
141 blurb(), (unsigned long) w, grab_string(status));
147 ungrab_kbd(saver_info *si)
149 saver_preferences *p = &si->prefs;
150 XUngrabKeyboard(si->dpy, CurrentTime);
152 fprintf(stderr, "%s: ungrabbing keyboard (was 0x%x).\n", blurb(),
153 (unsigned long) si->keyboard_grab_window);
154 si->keyboard_grab_window = 0;
159 ungrab_mouse(saver_info *si)
161 saver_preferences *p = &si->prefs;
162 XUngrabPointer(si->dpy, CurrentTime);
164 fprintf(stderr, "%s: ungrabbing mouse (was 0x%x).\n", blurb(),
165 (unsigned long) si->mouse_grab_window);
166 si->mouse_grab_window = 0;
171 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor)
174 XSync (si->dpy, False);
176 status = grab_kbd (si, window);
177 if (status != GrabSuccess)
178 { /* try again in a second */
180 status = grab_kbd (si, window);
181 if (status != GrabSuccess)
182 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
183 blurb(), grab_string(status));
186 status = grab_mouse (si, window, cursor);
187 if (status != GrabSuccess)
188 { /* try again in a second */
190 status = grab_mouse (si, window, cursor);
191 if (status != GrabSuccess)
192 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
193 blurb(), grab_string(status));
198 ungrab_keyboard_and_mouse (saver_info *si)
205 /* Prints an error message to stderr and returns True if there is another
206 xscreensaver running already. Silently returns False otherwise. */
208 ensure_no_screensaver_running (Display *dpy, Screen *screen)
212 Window root = RootWindowOfScreen (screen);
213 Window root2, parent, *kids;
215 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
217 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
223 for (i = 0; i < nkids; i++)
227 unsigned long nitems, bytesafter;
230 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
231 False, XA_STRING, &type, &format, &nitems,
232 &bytesafter, (unsigned char **) &version)
237 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
238 False, XA_STRING, &type, &format, &nitems,
239 &bytesafter, (unsigned char **) &id)
245 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
246 blurb(), DisplayString (dpy), (int) kids [i], id);
251 if (kids) XFree ((char *) kids);
253 XSetErrorHandler (old_handler);
259 /* Virtual-root hackery */
262 ERROR! You must not include vroot.h in this file.
266 store_vroot_property (Display *dpy, Window win, Window value)
271 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
273 (win == screensaver_window ? "ScreenSaver" :
274 (win == real_vroot ? "VRoot" :
275 (win == real_vroot_value ? "Vroot_value" : "???"))),
277 (value == screensaver_window ? "ScreenSaver" :
278 (value == real_vroot ? "VRoot" :
279 (value == real_vroot_value ? "Vroot_value" : "???"))));
281 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
282 (unsigned char *) &value, 1);
286 remove_vroot_property (Display *dpy, Window win)
290 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
291 (win == screensaver_window ? "ScreenSaver" :
292 (win == real_vroot ? "VRoot" :
293 (win == real_vroot_value ? "Vroot_value" : "???"))));
295 XDeleteProperty (dpy, win, XA_VROOT);
300 kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p)
304 unsigned long nitems, bytesafter;
307 /* If the user has been using xv or xsetroot as a screensaver (to display
308 an image on the screensaver window, as a kind of slideshow) then the
309 pixmap and its associated color cells have been put in RetainPermanent
310 CloseDown mode. Since we're not destroying the xscreensaver window,
311 but merely unmapping it, we need to free these resources or those
312 colormap cells will stay allocated while the screensaver is off. (We
313 could just delete the screensaver window and recreate it later, but
314 that could cause other problems.) This code does an atomic read-and-
315 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
316 cause the RetainPermanent resources of the client which created it
317 (and which no longer exists) to be freed.
319 if (XGetWindowProperty (dpy, window, XA_XSETROOT_ID, 0, 1,
320 True, AnyPropertyType, &type, &format, &nitems,
321 &bytesafter, (unsigned char **) &dataP)
325 if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
326 nitems == 1 && bytesafter == 0)
329 fprintf (stderr, "%s: destroying xsetroot data (0x%lX).\n",
331 XKillClient (dpy, *dataP);
334 fprintf (stderr, "%s: deleted unrecognised _XSETROOT_ID property: \n\
335 %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n",
336 blurb(), (unsigned long) dataP, (dataP ? *dataP : 0), type,
337 format, nitems, bytesafter);
342 static void handle_signals (saver_info *si, Bool on_p);
345 save_real_vroot (saver_screen_info *ssi)
347 saver_info *si = ssi->global;
348 Display *dpy = si->dpy;
349 Screen *screen = ssi->screen;
351 Window root = RootWindowOfScreen (screen);
352 Window root2, parent, *kids;
356 ssi->real_vroot_value = 0;
357 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
363 for (i = 0; i < nkids; i++)
367 unsigned long nitems, bytesafter;
370 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
371 &type, &format, &nitems, &bytesafter,
372 (unsigned char **) &vrootP)
379 if (*vrootP == ssi->screensaver_window) abort ();
381 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
382 blurb(), (int) ssi->real_vroot, (int) kids [i]);
385 ssi->real_vroot = kids [i];
386 ssi->real_vroot_value = *vrootP;
391 handle_signals (si, True);
392 remove_vroot_property (si->dpy, ssi->real_vroot);
396 XFree ((char *) kids);
401 restore_real_vroot_2 (saver_screen_info *ssi)
403 saver_info *si = ssi->global;
404 saver_preferences *p = &si->prefs;
405 if (p->verbose_p && ssi->real_vroot)
407 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
408 blurb(), (unsigned long) ssi->real_vroot);
409 remove_vroot_property (si->dpy, ssi->screensaver_window);
412 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
414 ssi->real_vroot_value = 0;
415 /* make sure the property change gets there before this process
416 terminates! We might be doing this because we have intercepted
417 SIGTERM or something. */
418 XSync (si->dpy, False);
425 restore_real_vroot_1 (saver_info *si)
428 Bool did_any = False;
429 for (i = 0; i < si->nscreens; i++)
431 saver_screen_info *ssi = &si->screens[i];
432 if (restore_real_vroot_2 (ssi))
439 restore_real_vroot (saver_info *si)
441 if (restore_real_vroot_1 (si))
442 handle_signals (si, False);
446 /* Signal hackery to ensure that the vroot doesn't get left in an
451 signal_name(int signal)
454 case SIGHUP: return "SIGHUP";
455 case SIGINT: return "SIGINT";
456 case SIGQUIT: return "SIGQUIT";
457 case SIGILL: return "SIGILL";
458 case SIGTRAP: return "SIGTRAP";
460 case SIGABRT: return "SIGABRT";
462 case SIGFPE: return "SIGFPE";
463 case SIGKILL: return "SIGKILL";
464 case SIGBUS: return "SIGBUS";
465 case SIGSEGV: return "SIGSEGV";
466 case SIGPIPE: return "SIGPIPE";
467 case SIGALRM: return "SIGALRM";
468 case SIGTERM: return "SIGTERM";
470 case SIGSTOP: return "SIGSTOP";
473 case SIGCONT: return "SIGCONT";
476 case SIGUSR1: return "SIGUSR1";
479 case SIGUSR2: return "SIGUSR2";
482 case SIGEMT: return "SIGEMT";
485 case SIGSYS: return "SIGSYS";
488 case SIGCHLD: return "SIGCHLD";
491 case SIGPWR: return "SIGPWR";
494 case SIGWINCH: return "SIGWINCH";
497 case SIGURG: return "SIGURG";
500 case SIGIO: return "SIGIO";
503 case SIGVTALRM: return "SIGVTALRM";
506 case SIGXCPU: return "SIGXCPU";
509 case SIGXFSZ: return "SIGXFSZ";
512 case SIGDANGER: return "SIGDANGER";
517 sprintf(buf, "signal %d\n", signal);
526 restore_real_vroot_handler (int sig)
528 saver_info *si = global_si_kludge; /* I hate C so much... */
530 signal (sig, SIG_DFL);
531 if (restore_real_vroot_1 (si))
532 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
533 blurb(), signal_name(sig));
534 kill (getpid (), sig);
538 catch_signal (saver_info *si, int sig, Bool on_p)
541 signal (sig, SIG_DFL);
544 if (((long) signal (sig, restore_real_vroot_handler)) == -1L)
547 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
549 saver_exit (si, 1, 0);
555 handle_signals (saver_info *si, Bool on_p)
558 if (on_p) fprintf (stderr, "handling signals\n");
559 else fprintf (stderr, "unhandling signals\n");
562 catch_signal (si, SIGHUP, on_p);
563 catch_signal (si, SIGINT, on_p);
564 catch_signal (si, SIGQUIT, on_p);
565 catch_signal (si, SIGILL, on_p);
566 catch_signal (si, SIGTRAP, on_p);
567 catch_signal (si, SIGIOT, on_p);
568 catch_signal (si, SIGABRT, on_p);
570 catch_signal (si, SIGEMT, on_p);
572 catch_signal (si, SIGFPE, on_p);
573 catch_signal (si, SIGBUS, on_p);
574 catch_signal (si, SIGSEGV, on_p);
576 catch_signal (si, SIGSYS, on_p);
578 catch_signal (si, SIGTERM, on_p);
580 catch_signal (si, SIGXCPU, on_p);
583 catch_signal (si, SIGXFSZ, on_p);
586 catch_signal (si, SIGDANGER, on_p);
591 saver_exit (saver_info *si, int status, const char *dump_core_reason)
593 saver_preferences *p = &si->prefs;
594 static Bool exiting = False;
602 vrs = restore_real_vroot_1 (si);
603 emergency_kill_subproc (si);
605 if (vrs && (p->verbose_p || status != 0))
606 fprintf (real_stderr, "%s: vroot restored, exiting.\n", blurb());
607 else if (p->verbose_p)
608 fprintf (real_stderr, "%s: no vroot to restore; exiting.\n", blurb());
612 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
613 if (status == 0) status = 1;
614 else if (status == 1) status = -1;
617 if (si->prefs.debug_p && !dump_core_reason)
618 dump_core_reason = "because of -debug";
620 if (dump_core_reason)
623 if (si->locking_disabled_p &&
627 /* If locking is disabled, it's because xscreensaver was launched
628 by root, and has relinquished its user id (most likely we are
629 now running as "nobody".) This means we won't be able to dump
630 core, since "nobody" can't write files; so don't even try.
632 fprintf(real_stderr, "%s: NOT dumping core (%s)\n", blurb(),
638 /* Note that the Linux man page for setuid() says If uid is
639 different from the old effective uid, the process will be
640 forbidden from leaving core dumps.
643 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
644 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
647 # if defined(HAVE_GETCWD)
648 getcwd (cwd, sizeof(cwd));
649 # elif defined(HAVE_GETWD)
652 strcpy(cwd, "unknown.");
654 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
655 describe_uids (si, real_stderr);
657 /* Do this to drop a core file, so that we can get a stack trace. */
666 /* Managing the actual screensaver window */
669 window_exists_p (Display *dpy, Window window)
671 XErrorHandler old_handler;
672 XWindowAttributes xgwa;
674 old_handler = XSetErrorHandler (BadWindow_ehandler);
675 XGetWindowAttributes (dpy, window, &xgwa);
677 XSetErrorHandler (old_handler);
678 return (xgwa.screen != 0);
682 initialize_screensaver_window_1 (saver_screen_info *ssi)
684 saver_info *si = ssi->global;
685 saver_preferences *p = &si->prefs;
686 Bool install_cmap_p = (ssi->install_cmap_p || p->install_cmap_p);
688 /* This resets the screensaver window as fully as possible, since there's
689 no way of knowing what some random client may have done to us in the
690 meantime. We could just destroy and recreate the window, but that has
691 its own set of problems...
694 XClassHint class_hints;
695 XSetWindowAttributes attrs;
696 unsigned long attrmask;
697 int width = WidthOfScreen (ssi->screen);
698 int height = HeightOfScreen (ssi->screen);
700 static Bool printed_visual_info = False; /* only print the message once. */
702 black.red = black.green = black.blue = 0;
704 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
707 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
708 install_cmap_p = True;
714 ssi->cmap = XCreateColormap (si->dpy, RootWindowOfScreen (ssi->screen),
715 ssi->current_visual, AllocNone);
716 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
717 ssi->black_pixel = black.pixel;
722 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
725 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
726 if (ssi->cmap != ssi->demo_cmap &&
727 ssi->cmap != def_cmap)
728 XFreeColormap (si->dpy, ssi->cmap);
730 ssi->cmap = def_cmap;
731 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
734 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
735 CWBackPixel | CWBackingPixel | CWBorderPixel);
736 attrs.override_redirect = True;
738 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
739 actually be reading these events during normal operation; but we still
740 need to see Button events for demo-mode to work properly.
742 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
743 ButtonPressMask | ButtonReleaseMask |
746 attrs.backing_store = NotUseful;
747 attrs.colormap = ssi->cmap;
748 attrs.background_pixel = ssi->black_pixel;
749 attrs.backing_pixel = ssi->black_pixel;
750 attrs.border_pixel = ssi->black_pixel;
752 if (p->debug_p) width = width / 2;
754 if (!p->verbose_p || printed_visual_info)
756 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
758 fprintf (stderr, "%s: using default visual ", blurb());
759 describe_visual (stderr, ssi->screen, ssi->current_visual,
764 fprintf (stderr, "%s: using visual: ", blurb());
765 describe_visual (stderr, ssi->screen, ssi->current_visual,
767 fprintf (stderr, "%s: default visual: ", blurb());
768 describe_visual (stderr, ssi->screen,
769 DefaultVisualOfScreen (ssi->screen),
770 ssi->install_cmap_p);
772 printed_visual_info = True;
774 #ifdef HAVE_MIT_SAVER_EXTENSION
775 if (p->use_mit_saver_extension)
777 XScreenSaverInfo *info;
778 Window root = RootWindowOfScreen (ssi->screen);
781 /* This call sets the server screensaver timeouts to what we think
782 they should be (based on the resources and args xscreensaver was
783 started with.) It's important that we do this to sync back up
784 with the server - if we have turned on prematurely, as by an
785 ACTIVATE ClientMessage, then the server may decide to activate
786 the screensaver while it's already active. That's ok for us,
787 since we would know to ignore that ScreenSaverActivate event,
788 but a side effect of this would be that the server would map its
789 saver window (which we then hide again right away) meaning that
790 the bits currently on the screen get blown away. Ugly. */
792 /* #### Ok, that doesn't work - when we tell the server that the
793 screensaver is "off" it sends us a Deactivate event, which is
794 sensible... but causes the saver to never come on. Hmm. */
795 disable_builtin_screensaver (si, True);
799 /* #### The MIT-SCREEN-SAVER extension gives us access to the
800 window that the server itself uses for saving the screen.
801 However, using this window in any way, in particular, calling
802 XScreenSaverSetAttributes() as below, tends to make the X server
803 crash. So fuck it, let's try and get along without using it...
805 It's also inconvenient to use this window because it doesn't
806 always exist (though the ID is constant.) So to use this
807 window, we'd have to reimplement the ACTIVATE ClientMessage to
808 tell the *server* to tell *us* to turn on, to cause the window
809 to get created at the right time. Gag. */
810 XScreenSaverSetAttributes (si->dpy, root,
811 0, 0, width, height, 0,
812 current_depth, InputOutput, visual,
814 XSync (si->dpy, False);
817 info = XScreenSaverAllocInfo ();
818 XScreenSaverQueryInfo (si->dpy, root, info);
819 ssi->server_mit_saver_window = info->window;
820 if (! ssi->server_mit_saver_window) abort ();
823 #endif /* HAVE_MIT_SAVER_EXTENSION */
825 if (ssi->screensaver_window)
827 XWindowChanges changes;
828 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
831 changes.width = width;
832 changes.height = height;
833 changes.border_width = 0;
835 XConfigureWindow (si->dpy, ssi->screensaver_window,
836 changesmask, &changes);
837 XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
842 ssi->screensaver_window =
843 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen), 0, 0,
844 width, height, 0, ssi->current_depth, InputOutput,
845 ssi->current_visual, attrmask, &attrs);
847 store_activate_time(si, True);
849 fprintf (stderr, "%s: saver window is 0x%lx.\n",
850 blurb(), (unsigned long) ssi->screensaver_window);
853 #ifdef HAVE_MIT_SAVER_EXTENSION
854 if (!p->use_mit_saver_extension ||
855 window_exists_p (si->dpy, ssi->screensaver_window))
856 /* When using the MIT-SCREEN-SAVER extension, the window pointed to
857 by screensaver_window only exists while the saver is active.
858 So we must be careful to only try and manipulate it while it
860 (#### The above comment would be true if the MIT extension actually
861 worked, but it's not true today -- see `server_mit_saver_window'.)
863 #endif /* HAVE_MIT_SAVER_EXTENSION */
865 class_hints.res_name = progname;
866 class_hints.res_class = progclass;
867 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
868 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
869 XChangeProperty (si->dpy, ssi->screensaver_window,
870 XA_SCREENSAVER_VERSION,
871 XA_STRING, 8, PropModeReplace,
872 (unsigned char *) si->version,
873 strlen (si->version));
875 sprintf (id, "%lu on host ", (unsigned long) getpid ());
877 # if defined(HAVE_UNAME)
880 if (uname (&uts) < 0)
883 strcat (id, uts.nodename);
886 strcat (id, getenv("SYS$NODE"));
887 # else /* !HAVE_UNAME && !VMS */
889 # endif /* !HAVE_UNAME && !VMS */
891 XChangeProperty (si->dpy, ssi->screensaver_window,
892 XA_SCREENSAVER_ID, XA_STRING,
893 8, PropModeReplace, (unsigned char *) id, strlen (id));
898 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
900 BlackPixelOfScreen (ssi->screen),
901 BlackPixelOfScreen (ssi->screen),
903 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
905 XFreePixmap (si->dpy, bit);
908 XSetWindowBackground (si->dpy, ssi->screensaver_window,
911 XUndefineCursor (si->dpy, ssi->screensaver_window);
913 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
918 initialize_screensaver_window (saver_info *si)
921 for (i = 0; i < si->nscreens; i++)
922 initialize_screensaver_window_1 (&si->screens[i]);
927 raise_window (saver_info *si,
928 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
930 saver_preferences *p = &si->prefs;
933 initialize_screensaver_window (si);
934 reset_watchdog_timer (si, True);
936 if (p->fade_p && !inhibit_fade && !si->demo_mode_p)
938 Window *current_windows = (Window *)
939 calloc(sizeof(Window), si->nscreens);
940 Colormap *current_maps = (Colormap *)
941 calloc(sizeof(Colormap), si->nscreens);
943 for (i = 0; i < si->nscreens; i++)
945 saver_screen_info *ssi = &si->screens[i];
946 current_windows[i] = ssi->screensaver_window;
947 current_maps[i] = (between_hacks_p
949 : DefaultColormapOfScreen (ssi->screen));
950 /* Ensure that the default background of the window is really black,
951 not a pixmap or something. (This does not clear the window.) */
952 XSetWindowBackground (si->dpy, ssi->screensaver_window,
956 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
958 XGrabServer (si->dpy); /* ############ DANGER! */
960 /* Clear the stderr layer on each screen.
963 for (i = 0; i < si->nscreens; i++)
965 saver_screen_info *ssi = &si->screens[i];
966 if (ssi->stderr_overlay_window)
967 /* Do this before the fade, since the stderr cmap won't fade
968 even if we uninstall it (beats me...) */
972 /* Note! The server is grabbed, and this will take several seconds
974 fade_screens (si->dpy, current_maps, current_windows,
975 p->fade_seconds, p->fade_ticks, True, !dont_clear);
978 free(current_windows);
982 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
984 #ifdef HAVE_MIT_SAVER_EXTENSION
985 for (i = 0; i < si->nscreens; i++)
987 saver_screen_info *ssi = &si->screens[i];
988 if (ssi->server_mit_saver_window &&
989 window_exists_p (si->dpy, ssi->server_mit_saver_window))
990 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
992 #endif /* HAVE_MIT_SAVER_EXTENSION */
994 XUngrabServer (si->dpy);
995 XSync (si->dpy, False); /* ###### (danger over) */
999 for (i = 0; i < si->nscreens; i++)
1001 saver_screen_info *ssi = &si->screens[i];
1003 XClearWindow (si->dpy, ssi->screensaver_window);
1004 if (!dont_clear || ssi->stderr_overlay_window)
1006 XMapRaised (si->dpy, ssi->screensaver_window);
1007 #ifdef HAVE_MIT_SAVER_EXTENSION
1008 if (ssi->server_mit_saver_window &&
1009 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1010 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1011 #endif /* HAVE_MIT_SAVER_EXTENSION */
1015 for (i = 0; i < si->nscreens; i++)
1017 saver_screen_info *ssi = &si->screens[i];
1019 XInstallColormap (si->dpy, ssi->cmap);
1024 blank_screen (saver_info *si)
1028 /* Note: we do our grabs on the root window, not on the screensaver window.
1029 If we grabbed on the saver window, then the demo mode and lock dialog
1030 boxes wouldn't get any events.
1032 grab_keyboard_and_mouse (si,
1033 /*si->screens[0].screensaver_window,*/
1034 RootWindowOfScreen(si->screens[0].screen),
1035 (si->demo_mode_p ? 0 : si->screens[0].cursor));
1037 for (i = 0; i < si->nscreens; i++)
1039 saver_screen_info *ssi = &si->screens[i];
1041 save_real_vroot (ssi);
1042 store_vroot_property (si->dpy,
1043 ssi->screensaver_window,
1044 ssi->screensaver_window);
1046 store_activate_time (si, si->screen_blanked_p);
1047 raise_window (si, False, False, False);
1049 #ifdef HAVE_XHPDISABLERESET
1050 if (si->locked_p && !hp_locked_p)
1052 XHPDisableReset (si->dpy); /* turn off C-Sh-Reset */
1057 si->screen_blanked_p = True;
1061 unblank_screen (saver_info *si)
1063 saver_preferences *p = &si->prefs;
1066 monitor_power_on (si);
1068 store_activate_time (si, True);
1069 reset_watchdog_timer (si, False);
1071 if (p->unfade_p && !si->demo_mode_p)
1073 Window *current_windows = (Window *)
1074 calloc(sizeof(Window), si->nscreens);
1076 for (i = 0; i < si->nscreens; i++)
1078 saver_screen_info *ssi = &si->screens[i];
1079 current_windows[i] = ssi->screensaver_window;
1080 /* Ensure that the default background of the window is really black,
1081 not a pixmap or something. (This does not clear the window.) */
1082 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1086 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1089 XSync (si->dpy, False);
1090 XGrabServer (si->dpy); /* ############ DANGER! */
1091 XSync (si->dpy, False);
1093 /* Clear the stderr layer on each screen.
1095 for (i = 0; i < si->nscreens; i++)
1097 saver_screen_info *ssi = &si->screens[i];
1101 XUngrabServer (si->dpy);
1102 XSync (si->dpy, False); /* ###### (danger over) */
1105 fade_screens (si->dpy, 0, current_windows,
1106 p->fade_seconds, p->fade_ticks,
1109 free(current_windows);
1110 current_windows = 0;
1112 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1116 for (i = 0; i < si->nscreens; i++)
1118 saver_screen_info *ssi = &si->screens[i];
1121 Colormap c = DefaultColormapOfScreen (ssi->screen);
1122 /* avoid technicolor */
1123 XClearWindow (si->dpy, ssi->screensaver_window);
1124 if (c) XInstallColormap (si->dpy, c);
1126 XUnmapWindow (si->dpy, ssi->screensaver_window);
1131 /* If the focus window does has a non-default colormap, then install
1132 that colormap as well. (On SGIs, this will cause both the root map
1133 and the focus map to be installed simultaniously. It'd be nice to
1134 pick up the other colormaps that had been installed, too; perhaps
1135 XListInstalledColormaps could be used for that?)
1140 XGetInputFocus (si->dpy, &focus, &revert_to);
1141 if (focus && focus != PointerRoot && focus != None)
1143 XWindowAttributes xgwa;
1145 XGetWindowAttributes (si->dpy, focus, &xgwa);
1146 if (xgwa.colormap &&
1147 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1148 XInstallColormap (si->dpy, xgwa.colormap);
1153 for (i = 0; i < si->nscreens; i++)
1155 saver_screen_info *ssi = &si->screens[i];
1156 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1159 store_activate_time(si, False); /* store unblank time */
1161 ungrab_keyboard_and_mouse (si);
1162 restore_real_vroot (si);
1164 #ifdef HAVE_XHPDISABLERESET
1167 XHPEnableReset (si->dpy); /* turn C-Sh-Reset back on */
1168 hp_locked_p = False;
1172 /* Unmap the windows a second time, dammit -- just to avoid a race
1173 with the screen-grabbing hacks. (I'm not sure if this is really
1174 necessary; I'm stabbing in the dark now.)
1176 for (i = 0; i < si->nscreens; i++)
1177 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1179 si->screen_blanked_p = False;
1184 store_activate_time (saver_info *si, Bool use_last_p)
1186 static time_t last_time = 0;
1187 time_t now = ((use_last_p && last_time) ? last_time : time ((time_t) 0));
1188 CARD32 now32 = (CARD32) now;
1192 for (i = 0; i < si->nscreens; i++)
1194 saver_screen_info *ssi = &si->screens[i];
1195 if (!ssi->screensaver_window) continue;
1196 XChangeProperty (si->dpy, ssi->screensaver_window, XA_SCREENSAVER_TIME,
1197 XA_INTEGER, 32, PropModeReplace,
1198 (unsigned char *) &now32, 1);
1204 select_visual (saver_screen_info *ssi, const char *visual_name)
1206 saver_info *si = ssi->global;
1207 saver_preferences *p = &si->prefs;
1208 Bool install_cmap_p = p->install_cmap_p;
1209 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1213 if (visual_name && *visual_name)
1215 if (!strcmp(visual_name, "default-i"))
1217 visual_name = "default";
1218 install_cmap_p = True;
1220 else if (!strcmp(visual_name, "default-n"))
1222 visual_name = "default";
1223 install_cmap_p = False;
1225 new_v = get_visual (ssi->screen, visual_name, True, False);
1229 new_v = ssi->default_visual;
1234 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1235 install_cmap_p = True;
1237 ssi->install_cmap_p = install_cmap_p;
1240 ((ssi->current_visual != new_v) ||
1241 (install_cmap_p != was_installed_p)))
1243 Colormap old_c = ssi->cmap;
1244 Window old_w = ssi->screensaver_window;
1248 fprintf (stderr, "%s: switching to visual ", blurb());
1249 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1251 fprintf (stderr, "%s: from ", blurb());
1252 describe_visual (stderr, ssi->screen, ssi->current_visual,
1258 ssi->current_visual = new_v;
1259 ssi->current_depth = visual_depth(ssi->screen, new_v);
1261 ssi->screensaver_window = 0;
1263 initialize_screensaver_window_1 (ssi);
1265 /* stderr_overlay_window is a child of screensaver_window, so we need
1266 to destroy that as well (actually, we just need to invalidate and
1267 drop our pointers to it, but this will destroy it, which is ok so
1268 long as it happens before old_w itself is destroyed.) */
1271 raise_window (si, True, True, False);
1272 store_vroot_property (si->dpy,
1273 ssi->screensaver_window, ssi->screensaver_window);
1274 store_activate_time (si, True);
1278 /* Transfer the grabs from the old window to the new.
1279 Actually I think none of this is necessary, since we always
1280 hold our grabs on the root window, but I wrote this before
1281 re-discovering that...
1285 /* If we're destroying the window that holds our mouse grab,
1286 transfer the grab to the new window. (Grab the server while
1287 so doing, to avoid a race condition.)
1289 if (old_w == si->mouse_grab_window)
1291 XGrabServer (si->dpy); /* ############ DANGER! */
1293 grab_mouse(si, ssi->screensaver_window,
1294 (si->demo_mode_p ? 0 : ssi->cursor));
1295 XUngrabServer (si->dpy);
1296 XSync (si->dpy, False); /* ###### (danger over) */
1299 /* If we're destroying the window that holds our keyboard grab,
1300 transfer the grab to the new window. (Grab the server while
1301 so doing, to avoid a race condition.)
1303 if (old_w == si->keyboard_grab_window)
1305 XGrabServer (si->dpy); /* ############ DANGER! */
1307 grab_kbd(si, ssi->screensaver_window);
1308 XUngrabServer (si->dpy);
1309 XSync (si->dpy, False); /* ###### (danger over) */
1312 /* Now we can destroy this window without horking our grabs. */
1314 XDestroyWindow (si->dpy, old_w);
1317 fprintf (stderr, "%s: destroyed old saver window 0x%lx.\n",
1318 blurb(), (unsigned long) old_w);
1321 old_c != DefaultColormapOfScreen (ssi->screen) &&
1322 old_c != ssi->demo_cmap)
1323 XFreeColormap (si->dpy, old_c);