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 <sys/utsname.h> /* for uname() */
24 # endif /* HAVE_UNAME */
27 #include <X11/Xproto.h> /* for CARD32 */
29 #include <X11/Xutil.h> /* for XSetClassHint() */
30 #include <X11/Xatom.h>
31 #include <X11/Xos.h> /* for time() */
32 #include <signal.h> /* for the signal names */
34 #ifdef HAVE_MIT_SAVER_EXTENSION
35 # include <X11/extensions/scrnsaver.h>
36 #endif /* HAVE_MIT_SAVER_EXTENSION */
39 #ifdef HAVE_XHPDISABLERESET
40 # include <X11/XHPlib.h>
42 /* Calls to XHPDisableReset and XHPEnableReset must be balanced,
43 or BadAccess errors occur. (Ok for this to be global, since it
44 affects the whole machine, not just the current screen.) */
45 Bool hp_locked_p = False;
47 #endif /* HAVE_XHPDISABLERESET */
50 /* This file doesn't need the Xt headers, so stub these types out... */
52 #define XtAppContext void*
53 #define XrmDatabase void*
54 #define XtIntervalId void*
55 #define XtPointer void*
58 #include "xscreensaver.h"
63 #ifdef HAVE_VT_LOCKSWITCH
65 # include <sys/ioctl.h>
67 static void lock_vt (saver_info *si, Bool lock_p);
68 #endif /* HAVE_VT_LOCKSWITCH */
71 extern int kill (pid_t, int); /* signal() is in sys/signal.h... */
73 Atom XA_VROOT, XA_XSETROOT_ID;
74 Atom XA_SCREENSAVER, XA_SCREENSAVER_VERSION, XA_SCREENSAVER_ID;
75 Atom XA_SCREENSAVER_TIME;
78 extern saver_info *global_si_kludge; /* I hate C so much... */
81 static void store_activate_time (saver_info *si, Bool use_last_p);
83 #define ALL_POINTER_EVENTS \
84 (ButtonPressMask | ButtonReleaseMask | EnterWindowMask | \
85 LeaveWindowMask | PointerMotionMask | PointerMotionHintMask | \
86 Button1MotionMask | Button2MotionMask | Button3MotionMask | \
87 Button4MotionMask | Button5MotionMask | ButtonMotionMask)
91 grab_kbd(saver_info *si, Window w)
93 saver_preferences *p = &si->prefs;
94 int status = XGrabKeyboard (si->dpy, w, True,
95 /* I don't really understand Sync vs Async,
96 but these seem to work... */
97 GrabModeSync, GrabModeAsync,
99 if (status == GrabSuccess)
100 si->keyboard_grab_window = w;
103 fprintf(stderr, "%s: grabbing keyboard on 0x%x... %s.\n",
104 blurb(), (unsigned long) w,
105 (status == GrabSuccess ? "GrabSuccess" :
106 status == AlreadyGrabbed ? "AlreadyGrabbed" :
107 status == GrabInvalidTime ? "GrabInvalidTime" :
108 status == GrabNotViewable ? "GrabNotViewable" :
109 status == GrabFrozen ? "GrabFrozen" :
116 grab_string(int status)
120 case GrabSuccess: return "GrabSuccess"; break;
121 case AlreadyGrabbed: return "AlreadyGrabbed"; break;
122 case GrabInvalidTime: return "GrabInvalidTime"; break;
123 case GrabNotViewable: return "GrabNotViewable"; break;
124 case GrabFrozen: return "GrabFrozen"; break;
127 static char foo[255];
128 sprintf(foo, "unknown status: %d", status);
136 grab_mouse (saver_info *si, Window w, Cursor cursor)
138 saver_preferences *p = &si->prefs;
139 int status = XGrabPointer (si->dpy, w, True, ALL_POINTER_EVENTS,
140 GrabModeAsync, GrabModeAsync, None,
141 cursor, CurrentTime);
142 if (status == GrabSuccess)
143 si->mouse_grab_window = w;
146 fprintf(stderr, "%s: grabbing mouse on 0x%x... %s.\n",
147 blurb(), (unsigned long) w, grab_string(status));
153 ungrab_kbd(saver_info *si)
155 saver_preferences *p = &si->prefs;
156 XUngrabKeyboard(si->dpy, CurrentTime);
158 fprintf(stderr, "%s: ungrabbing keyboard (was 0x%x).\n", blurb(),
159 (unsigned long) si->keyboard_grab_window);
160 si->keyboard_grab_window = 0;
165 ungrab_mouse(saver_info *si)
167 saver_preferences *p = &si->prefs;
168 XUngrabPointer(si->dpy, CurrentTime);
170 fprintf(stderr, "%s: ungrabbing mouse (was 0x%x).\n", blurb(),
171 (unsigned long) si->mouse_grab_window);
172 si->mouse_grab_window = 0;
177 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor)
180 XSync (si->dpy, False);
182 status = grab_kbd (si, window);
183 if (status != GrabSuccess)
184 { /* try again in a second */
186 status = grab_kbd (si, window);
187 if (status != GrabSuccess)
188 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
189 blurb(), grab_string(status));
192 status = grab_mouse (si, window, cursor);
193 if (status != GrabSuccess)
194 { /* try again in a second */
196 status = grab_mouse (si, window, cursor);
197 if (status != GrabSuccess)
198 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
199 blurb(), grab_string(status));
204 ungrab_keyboard_and_mouse (saver_info *si)
211 /* Prints an error message to stderr and returns True if there is another
212 xscreensaver running already. Silently returns False otherwise. */
214 ensure_no_screensaver_running (Display *dpy, Screen *screen)
218 Window root = RootWindowOfScreen (screen);
219 Window root2, parent, *kids;
221 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
223 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
229 for (i = 0; i < nkids; i++)
233 unsigned long nitems, bytesafter;
236 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
237 False, XA_STRING, &type, &format, &nitems,
238 &bytesafter, (unsigned char **) &version)
243 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
244 False, XA_STRING, &type, &format, &nitems,
245 &bytesafter, (unsigned char **) &id)
251 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
252 blurb(), DisplayString (dpy), (int) kids [i], id);
257 if (kids) XFree ((char *) kids);
259 XSetErrorHandler (old_handler);
265 /* Virtual-root hackery */
268 ERROR! You must not include vroot.h in this file.
272 store_vroot_property (Display *dpy, Window win, Window value)
277 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
279 (win == screensaver_window ? "ScreenSaver" :
280 (win == real_vroot ? "VRoot" :
281 (win == real_vroot_value ? "Vroot_value" : "???"))),
283 (value == screensaver_window ? "ScreenSaver" :
284 (value == real_vroot ? "VRoot" :
285 (value == real_vroot_value ? "Vroot_value" : "???"))));
287 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
288 (unsigned char *) &value, 1);
292 remove_vroot_property (Display *dpy, Window win)
296 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
297 (win == screensaver_window ? "ScreenSaver" :
298 (win == real_vroot ? "VRoot" :
299 (win == real_vroot_value ? "Vroot_value" : "???"))));
301 XDeleteProperty (dpy, win, XA_VROOT);
306 kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p)
310 unsigned long nitems, bytesafter;
313 /* If the user has been using xv or xsetroot as a screensaver (to display
314 an image on the screensaver window, as a kind of slideshow) then the
315 pixmap and its associated color cells have been put in RetainPermanent
316 CloseDown mode. Since we're not destroying the xscreensaver window,
317 but merely unmapping it, we need to free these resources or those
318 colormap cells will stay allocated while the screensaver is off. (We
319 could just delete the screensaver window and recreate it later, but
320 that could cause other problems.) This code does an atomic read-and-
321 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
322 cause the RetainPermanent resources of the client which created it
323 (and which no longer exists) to be freed.
325 if (XGetWindowProperty (dpy, window, XA_XSETROOT_ID, 0, 1,
326 True, AnyPropertyType, &type, &format, &nitems,
327 &bytesafter, (unsigned char **) &dataP)
331 if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
332 nitems == 1 && bytesafter == 0)
335 fprintf (stderr, "%s: destroying xsetroot data (0x%lX).\n",
337 XKillClient (dpy, *dataP);
340 fprintf (stderr, "%s: deleted unrecognised _XSETROOT_ID property: \n\
341 %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n",
342 blurb(), (unsigned long) dataP, (dataP ? *dataP : 0), type,
343 format, nitems, bytesafter);
348 static void handle_signals (saver_info *si, Bool on_p);
351 save_real_vroot (saver_screen_info *ssi)
353 saver_info *si = ssi->global;
354 Display *dpy = si->dpy;
355 Screen *screen = ssi->screen;
357 Window root = RootWindowOfScreen (screen);
358 Window root2, parent, *kids;
362 ssi->real_vroot_value = 0;
363 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
369 for (i = 0; i < nkids; i++)
373 unsigned long nitems, bytesafter;
376 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
377 &type, &format, &nitems, &bytesafter,
378 (unsigned char **) &vrootP)
385 if (*vrootP == ssi->screensaver_window) abort ();
387 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
388 blurb(), (int) ssi->real_vroot, (int) kids [i]);
391 ssi->real_vroot = kids [i];
392 ssi->real_vroot_value = *vrootP;
397 handle_signals (si, True);
398 remove_vroot_property (si->dpy, ssi->real_vroot);
402 XFree ((char *) kids);
407 restore_real_vroot_2 (saver_screen_info *ssi)
409 saver_info *si = ssi->global;
410 saver_preferences *p = &si->prefs;
411 if (p->verbose_p && ssi->real_vroot)
413 "%s: restoring __SWM_VROOT property on the real vroot (0x%lx).\n",
414 blurb(), (unsigned long) ssi->real_vroot);
415 remove_vroot_property (si->dpy, ssi->screensaver_window);
418 store_vroot_property (si->dpy, ssi->real_vroot, ssi->real_vroot_value);
420 ssi->real_vroot_value = 0;
421 /* make sure the property change gets there before this process
422 terminates! We might be doing this because we have intercepted
423 SIGTERM or something. */
424 XSync (si->dpy, False);
431 restore_real_vroot_1 (saver_info *si)
434 Bool did_any = False;
435 for (i = 0; i < si->nscreens; i++)
437 saver_screen_info *ssi = &si->screens[i];
438 if (restore_real_vroot_2 (ssi))
445 restore_real_vroot (saver_info *si)
447 if (restore_real_vroot_1 (si))
448 handle_signals (si, False);
452 /* Signal hackery to ensure that the vroot doesn't get left in an
457 signal_name(int signal)
460 case SIGHUP: return "SIGHUP";
461 case SIGINT: return "SIGINT";
462 case SIGQUIT: return "SIGQUIT";
463 case SIGILL: return "SIGILL";
464 case SIGTRAP: return "SIGTRAP";
466 case SIGABRT: return "SIGABRT";
468 case SIGFPE: return "SIGFPE";
469 case SIGKILL: return "SIGKILL";
470 case SIGBUS: return "SIGBUS";
471 case SIGSEGV: return "SIGSEGV";
472 case SIGPIPE: return "SIGPIPE";
473 case SIGALRM: return "SIGALRM";
474 case SIGTERM: return "SIGTERM";
476 case SIGSTOP: return "SIGSTOP";
479 case SIGCONT: return "SIGCONT";
482 case SIGUSR1: return "SIGUSR1";
485 case SIGUSR2: return "SIGUSR2";
488 case SIGEMT: return "SIGEMT";
491 case SIGSYS: return "SIGSYS";
494 case SIGCHLD: return "SIGCHLD";
497 case SIGPWR: return "SIGPWR";
500 case SIGWINCH: return "SIGWINCH";
503 case SIGURG: return "SIGURG";
506 case SIGIO: return "SIGIO";
509 case SIGVTALRM: return "SIGVTALRM";
512 case SIGXCPU: return "SIGXCPU";
515 case SIGXFSZ: return "SIGXFSZ";
518 case SIGDANGER: return "SIGDANGER";
523 sprintf(buf, "signal %d\n", signal);
532 restore_real_vroot_handler (int sig)
534 saver_info *si = global_si_kludge; /* I hate C so much... */
536 signal (sig, SIG_DFL);
537 if (restore_real_vroot_1 (si))
538 fprintf (real_stderr, "\n%s: %s intercepted, vroot restored.\n",
539 blurb(), signal_name(sig));
540 kill (getpid (), sig);
544 catch_signal (saver_info *si, int sig, Bool on_p)
547 signal (sig, SIG_DFL);
550 if (((long) signal (sig, restore_real_vroot_handler)) == -1L)
553 sprintf (buf, "%s: couldn't catch %s", blurb(), signal_name(sig));
555 saver_exit (si, 1, 0);
561 handle_signals (saver_info *si, Bool on_p)
564 if (on_p) fprintf (stderr, "handling signals\n");
565 else fprintf (stderr, "unhandling signals\n");
568 catch_signal (si, SIGHUP, on_p);
569 catch_signal (si, SIGINT, on_p);
570 catch_signal (si, SIGQUIT, on_p);
571 catch_signal (si, SIGILL, on_p);
572 catch_signal (si, SIGTRAP, on_p);
573 catch_signal (si, SIGIOT, on_p);
574 catch_signal (si, SIGABRT, on_p);
576 catch_signal (si, SIGEMT, on_p);
578 catch_signal (si, SIGFPE, on_p);
579 catch_signal (si, SIGBUS, on_p);
580 catch_signal (si, SIGSEGV, on_p);
582 catch_signal (si, SIGSYS, on_p);
584 catch_signal (si, SIGTERM, on_p);
586 catch_signal (si, SIGXCPU, on_p);
589 catch_signal (si, SIGXFSZ, on_p);
592 catch_signal (si, SIGDANGER, on_p);
597 saver_exit (saver_info *si, int status, const char *dump_core_reason)
599 saver_preferences *p = &si->prefs;
600 static Bool exiting = False;
609 vrs = restore_real_vroot_1 (si);
610 emergency_kill_subproc (si);
612 if (vrs && (p->verbose_p || status != 0))
613 fprintf (real_stderr, "%s: vroot restored, exiting.\n", blurb());
614 else if (p->verbose_p)
615 fprintf (real_stderr, "%s: no vroot to restore; exiting.\n", blurb());
619 #ifdef VMS /* on VMS, 1 is the "normal" exit code instead of 0. */
620 if (status == 0) status = 1;
621 else if (status == 1) status = -1;
624 bugp = !!dump_core_reason;
626 if (si->prefs.debug_p && !dump_core_reason)
627 dump_core_reason = "because of -debug";
629 if (dump_core_reason)
631 /* Note that the Linux man page for setuid() says If uid is
632 different from the old effective uid, the process will be
633 forbidden from leaving core dumps.
635 char cwd[4096]; /* should really be PATH_MAX, but who cares. */
637 fprintf(real_stderr, "%s: dumping core (%s)\n", blurb(),
642 "%s: see http://www.jwz.org/xscreensaver/bugs.html\n"
643 "\t\tfor bug reporting information.\n\n",
646 # if defined(HAVE_GETCWD)
647 if (!getcwd (cwd, sizeof(cwd)))
648 # elif defined(HAVE_GETWD)
651 strcpy(cwd, "unknown.");
653 fprintf (real_stderr, "%s: current directory is %s\n", blurb(), cwd);
654 describe_uids (si, real_stderr);
656 /* Do this to drop a core file, so that we can get a stack trace. */
664 /* Managing the actual screensaver window */
667 window_exists_p (Display *dpy, Window window)
669 XErrorHandler old_handler;
670 XWindowAttributes xgwa;
672 old_handler = XSetErrorHandler (BadWindow_ehandler);
673 XGetWindowAttributes (dpy, window, &xgwa);
675 XSetErrorHandler (old_handler);
676 return (xgwa.screen != 0);
680 initialize_screensaver_window_1 (saver_screen_info *ssi)
682 saver_info *si = ssi->global;
683 saver_preferences *p = &si->prefs;
684 Bool install_cmap_p = (ssi->install_cmap_p || p->install_cmap_p);
686 /* This resets the screensaver window as fully as possible, since there's
687 no way of knowing what some random client may have done to us in the
688 meantime. We could just destroy and recreate the window, but that has
689 its own set of problems...
692 XClassHint class_hints;
693 XSetWindowAttributes attrs;
694 unsigned long attrmask;
695 int width = WidthOfScreen (ssi->screen);
696 int height = HeightOfScreen (ssi->screen);
698 static Bool printed_visual_info = False; /* only print the message once. */
700 black.red = black.green = black.blue = 0;
702 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
705 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
706 install_cmap_p = True;
712 ssi->cmap = XCreateColormap (si->dpy, RootWindowOfScreen (ssi->screen),
713 ssi->current_visual, AllocNone);
714 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
715 ssi->black_pixel = black.pixel;
720 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
723 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
724 if (ssi->cmap != ssi->demo_cmap &&
725 ssi->cmap != def_cmap)
726 XFreeColormap (si->dpy, ssi->cmap);
728 ssi->cmap = def_cmap;
729 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
732 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
733 CWBackPixel | CWBackingPixel | CWBorderPixel);
734 attrs.override_redirect = True;
736 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
737 actually be reading these events during normal operation; but we still
738 need to see Button events for demo-mode to work properly.
740 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
741 ButtonPressMask | ButtonReleaseMask |
744 attrs.backing_store = NotUseful;
745 attrs.colormap = ssi->cmap;
746 attrs.background_pixel = ssi->black_pixel;
747 attrs.backing_pixel = ssi->black_pixel;
748 attrs.border_pixel = ssi->black_pixel;
750 if (p->debug_p) width = width / 2;
752 if (!p->verbose_p || printed_visual_info)
754 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
756 fprintf (stderr, "%s: using default visual ", blurb());
757 describe_visual (stderr, ssi->screen, ssi->current_visual,
762 fprintf (stderr, "%s: using visual: ", blurb());
763 describe_visual (stderr, ssi->screen, ssi->current_visual,
765 fprintf (stderr, "%s: default visual: ", blurb());
766 describe_visual (stderr, ssi->screen,
767 DefaultVisualOfScreen (ssi->screen),
768 ssi->install_cmap_p);
770 printed_visual_info = True;
772 #ifdef HAVE_MIT_SAVER_EXTENSION
773 if (p->use_mit_saver_extension)
775 XScreenSaverInfo *info;
776 Window root = RootWindowOfScreen (ssi->screen);
779 /* This call sets the server screensaver timeouts to what we think
780 they should be (based on the resources and args xscreensaver was
781 started with.) It's important that we do this to sync back up
782 with the server - if we have turned on prematurely, as by an
783 ACTIVATE ClientMessage, then the server may decide to activate
784 the screensaver while it's already active. That's ok for us,
785 since we would know to ignore that ScreenSaverActivate event,
786 but a side effect of this would be that the server would map its
787 saver window (which we then hide again right away) meaning that
788 the bits currently on the screen get blown away. Ugly. */
790 /* #### Ok, that doesn't work - when we tell the server that the
791 screensaver is "off" it sends us a Deactivate event, which is
792 sensible... but causes the saver to never come on. Hmm. */
793 disable_builtin_screensaver (si, True);
797 /* #### The MIT-SCREEN-SAVER extension gives us access to the
798 window that the server itself uses for saving the screen.
799 However, using this window in any way, in particular, calling
800 XScreenSaverSetAttributes() as below, tends to make the X server
801 crash. So fuck it, let's try and get along without using it...
803 It's also inconvenient to use this window because it doesn't
804 always exist (though the ID is constant.) So to use this
805 window, we'd have to reimplement the ACTIVATE ClientMessage to
806 tell the *server* to tell *us* to turn on, to cause the window
807 to get created at the right time. Gag. */
808 XScreenSaverSetAttributes (si->dpy, root,
809 0, 0, width, height, 0,
810 current_depth, InputOutput, visual,
812 XSync (si->dpy, False);
815 info = XScreenSaverAllocInfo ();
816 XScreenSaverQueryInfo (si->dpy, root, info);
817 ssi->server_mit_saver_window = info->window;
818 if (! ssi->server_mit_saver_window) abort ();
821 #endif /* HAVE_MIT_SAVER_EXTENSION */
823 if (ssi->screensaver_window)
825 XWindowChanges changes;
826 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
829 changes.width = width;
830 changes.height = height;
831 changes.border_width = 0;
833 XConfigureWindow (si->dpy, ssi->screensaver_window,
834 changesmask, &changes);
835 XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
840 ssi->screensaver_window =
841 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen), 0, 0,
842 width, height, 0, ssi->current_depth, InputOutput,
843 ssi->current_visual, attrmask, &attrs);
845 store_activate_time(si, True);
847 fprintf (stderr, "%s: saver window is 0x%lx.\n",
848 blurb(), (unsigned long) ssi->screensaver_window);
851 #ifdef HAVE_MIT_SAVER_EXTENSION
852 if (!p->use_mit_saver_extension ||
853 window_exists_p (si->dpy, ssi->screensaver_window))
854 /* When using the MIT-SCREEN-SAVER extension, the window pointed to
855 by screensaver_window only exists while the saver is active.
856 So we must be careful to only try and manipulate it while it
858 (#### The above comment would be true if the MIT extension actually
859 worked, but it's not true today -- see `server_mit_saver_window'.)
861 #endif /* HAVE_MIT_SAVER_EXTENSION */
863 class_hints.res_name = progname;
864 class_hints.res_class = progclass;
865 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
866 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
867 XChangeProperty (si->dpy, ssi->screensaver_window,
868 XA_SCREENSAVER_VERSION,
869 XA_STRING, 8, PropModeReplace,
870 (unsigned char *) si->version,
871 strlen (si->version));
873 sprintf (id, "%lu on host ", (unsigned long) getpid ());
875 # if defined(HAVE_UNAME)
878 if (uname (&uts) < 0)
881 strcat (id, uts.nodename);
884 strcat (id, getenv("SYS$NODE"));
885 # else /* !HAVE_UNAME && !VMS */
887 # endif /* !HAVE_UNAME && !VMS */
889 XChangeProperty (si->dpy, ssi->screensaver_window,
890 XA_SCREENSAVER_ID, XA_STRING,
891 8, PropModeReplace, (unsigned char *) id, strlen (id));
896 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
898 BlackPixelOfScreen (ssi->screen),
899 BlackPixelOfScreen (ssi->screen),
901 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
903 XFreePixmap (si->dpy, bit);
906 XSetWindowBackground (si->dpy, ssi->screensaver_window,
909 XUndefineCursor (si->dpy, ssi->screensaver_window);
911 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
916 initialize_screensaver_window (saver_info *si)
919 for (i = 0; i < si->nscreens; i++)
920 initialize_screensaver_window_1 (&si->screens[i]);
925 raise_window (saver_info *si,
926 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
928 saver_preferences *p = &si->prefs;
931 initialize_screensaver_window (si);
932 reset_watchdog_timer (si, True);
934 if (p->fade_p && si->fading_possible_p && !inhibit_fade && !si->demo_mode_p)
936 Window *current_windows = (Window *)
937 calloc(sizeof(Window), si->nscreens);
938 Colormap *current_maps = (Colormap *)
939 calloc(sizeof(Colormap), si->nscreens);
941 for (i = 0; i < si->nscreens; i++)
943 saver_screen_info *ssi = &si->screens[i];
944 current_windows[i] = ssi->screensaver_window;
945 current_maps[i] = (between_hacks_p
947 : DefaultColormapOfScreen (ssi->screen));
948 /* Ensure that the default background of the window is really black,
949 not a pixmap or something. (This does not clear the window.) */
950 XSetWindowBackground (si->dpy, ssi->screensaver_window,
954 if (p->verbose_p) fprintf (stderr, "%s: fading...\n", blurb());
956 XGrabServer (si->dpy); /* ############ DANGER! */
958 /* Clear the stderr layer on each screen.
961 for (i = 0; i < si->nscreens; i++)
963 saver_screen_info *ssi = &si->screens[i];
964 if (ssi->stderr_overlay_window)
965 /* Do this before the fade, since the stderr cmap won't fade
966 even if we uninstall it (beats me...) */
970 /* Note! The server is grabbed, and this will take several seconds
972 fade_screens (si->dpy, current_maps, current_windows,
973 p->fade_seconds/1000, p->fade_ticks, True, !dont_clear);
976 free(current_windows);
980 if (p->verbose_p) fprintf (stderr, "%s: fading done.\n", blurb());
982 #ifdef HAVE_MIT_SAVER_EXTENSION
983 for (i = 0; i < si->nscreens; i++)
985 saver_screen_info *ssi = &si->screens[i];
986 if (ssi->server_mit_saver_window &&
987 window_exists_p (si->dpy, ssi->server_mit_saver_window))
988 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
990 #endif /* HAVE_MIT_SAVER_EXTENSION */
992 XUngrabServer (si->dpy);
993 XSync (si->dpy, False); /* ###### (danger over) */
997 for (i = 0; i < si->nscreens; i++)
999 saver_screen_info *ssi = &si->screens[i];
1001 XClearWindow (si->dpy, ssi->screensaver_window);
1002 if (!dont_clear || ssi->stderr_overlay_window)
1004 XMapRaised (si->dpy, ssi->screensaver_window);
1005 #ifdef HAVE_MIT_SAVER_EXTENSION
1006 if (ssi->server_mit_saver_window &&
1007 window_exists_p (si->dpy, ssi->server_mit_saver_window))
1008 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
1009 #endif /* HAVE_MIT_SAVER_EXTENSION */
1013 for (i = 0; i < si->nscreens; i++)
1015 saver_screen_info *ssi = &si->screens[i];
1017 XInstallColormap (si->dpy, ssi->cmap);
1022 blank_screen (saver_info *si)
1026 /* Note: we do our grabs on the root window, not on the screensaver window.
1027 If we grabbed on the saver window, then the demo mode and lock dialog
1028 boxes wouldn't get any events.
1030 grab_keyboard_and_mouse (si,
1031 /*si->screens[0].screensaver_window,*/
1032 RootWindowOfScreen(si->screens[0].screen),
1033 (si->demo_mode_p ? 0 : si->screens[0].cursor));
1035 for (i = 0; i < si->nscreens; i++)
1037 saver_screen_info *ssi = &si->screens[i];
1039 save_real_vroot (ssi);
1040 store_vroot_property (si->dpy,
1041 ssi->screensaver_window,
1042 ssi->screensaver_window);
1044 store_activate_time (si, si->screen_blanked_p);
1045 raise_window (si, False, False, False);
1047 #ifdef HAVE_XHPDISABLERESET
1048 if (si->locked_p && !hp_locked_p)
1050 XHPDisableReset (si->dpy); /* turn off C-Sh-Reset */
1055 #ifdef HAVE_VT_LOCKSWITCH
1057 lock_vt (si, True); /* turn off C-Alt-Fn */
1060 si->screen_blanked_p = True;
1064 unblank_screen (saver_info *si)
1066 saver_preferences *p = &si->prefs;
1069 monitor_power_on (si);
1071 store_activate_time (si, True);
1072 reset_watchdog_timer (si, False);
1074 if (p->unfade_p && si->fading_possible_p && !si->demo_mode_p)
1076 Window *current_windows = (Window *)
1077 calloc(sizeof(Window), si->nscreens);
1079 for (i = 0; i < si->nscreens; i++)
1081 saver_screen_info *ssi = &si->screens[i];
1082 current_windows[i] = ssi->screensaver_window;
1083 /* Ensure that the default background of the window is really black,
1084 not a pixmap or something. (This does not clear the window.) */
1085 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1089 if (p->verbose_p) fprintf (stderr, "%s: unfading...\n", blurb());
1092 XSync (si->dpy, False);
1093 XGrabServer (si->dpy); /* ############ DANGER! */
1094 XSync (si->dpy, False);
1096 /* Clear the stderr layer on each screen.
1098 for (i = 0; i < si->nscreens; i++)
1100 saver_screen_info *ssi = &si->screens[i];
1104 XUngrabServer (si->dpy);
1105 XSync (si->dpy, False); /* ###### (danger over) */
1108 fade_screens (si->dpy, 0, current_windows,
1109 p->fade_seconds/1000, p->fade_ticks,
1112 free(current_windows);
1113 current_windows = 0;
1115 if (p->verbose_p) fprintf (stderr, "%s: unfading done.\n", blurb());
1119 for (i = 0; i < si->nscreens; i++)
1121 saver_screen_info *ssi = &si->screens[i];
1124 Colormap c = DefaultColormapOfScreen (ssi->screen);
1125 /* avoid technicolor */
1126 XClearWindow (si->dpy, ssi->screensaver_window);
1127 if (c) XInstallColormap (si->dpy, c);
1129 XUnmapWindow (si->dpy, ssi->screensaver_window);
1134 /* If the focus window does has a non-default colormap, then install
1135 that colormap as well. (On SGIs, this will cause both the root map
1136 and the focus map to be installed simultaniously. It'd be nice to
1137 pick up the other colormaps that had been installed, too; perhaps
1138 XListInstalledColormaps could be used for that?)
1143 XGetInputFocus (si->dpy, &focus, &revert_to);
1144 if (focus && focus != PointerRoot && focus != None)
1146 XWindowAttributes xgwa;
1148 XGetWindowAttributes (si->dpy, focus, &xgwa);
1149 if (xgwa.colormap &&
1150 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1151 XInstallColormap (si->dpy, xgwa.colormap);
1156 for (i = 0; i < si->nscreens; i++)
1158 saver_screen_info *ssi = &si->screens[i];
1159 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1162 store_activate_time(si, False); /* store unblank time */
1164 ungrab_keyboard_and_mouse (si);
1165 restore_real_vroot (si);
1167 #ifdef HAVE_XHPDISABLERESET
1170 XHPEnableReset (si->dpy); /* turn C-Sh-Reset back on */
1171 hp_locked_p = False;
1175 #ifdef HAVE_VT_LOCKSWITCH
1176 lock_vt (si, False); /* turn C-Alt-Fn back on */
1179 /* Unmap the windows a second time, dammit -- just to avoid a race
1180 with the screen-grabbing hacks. (I'm not sure if this is really
1181 necessary; I'm stabbing in the dark now.)
1183 for (i = 0; i < si->nscreens; i++)
1184 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1186 si->screen_blanked_p = False;
1191 store_activate_time (saver_info *si, Bool use_last_p)
1193 static time_t last_time = 0;
1194 time_t now = ((use_last_p && last_time) ? last_time : time ((time_t) 0));
1195 CARD32 now32 = (CARD32) now;
1199 for (i = 0; i < si->nscreens; i++)
1201 saver_screen_info *ssi = &si->screens[i];
1202 if (!ssi->screensaver_window) continue;
1203 XChangeProperty (si->dpy, ssi->screensaver_window, XA_SCREENSAVER_TIME,
1204 XA_INTEGER, 32, PropModeReplace,
1205 (unsigned char *) &now32, 1);
1211 select_visual (saver_screen_info *ssi, const char *visual_name)
1213 saver_info *si = ssi->global;
1214 saver_preferences *p = &si->prefs;
1215 Bool install_cmap_p = p->install_cmap_p;
1216 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1220 if (visual_name && *visual_name)
1222 if (!strcmp(visual_name, "default-i"))
1224 visual_name = "default";
1225 install_cmap_p = True;
1227 else if (!strcmp(visual_name, "default-n"))
1229 visual_name = "default";
1230 install_cmap_p = False;
1232 new_v = get_visual (ssi->screen, visual_name, True, False);
1236 new_v = ssi->default_visual;
1241 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1242 install_cmap_p = True;
1244 ssi->install_cmap_p = install_cmap_p;
1247 ((ssi->current_visual != new_v) ||
1248 (install_cmap_p != was_installed_p)))
1250 Colormap old_c = ssi->cmap;
1251 Window old_w = ssi->screensaver_window;
1255 fprintf (stderr, "%s: switching to visual ", blurb());
1256 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1258 fprintf (stderr, "%s: from ", blurb());
1259 describe_visual (stderr, ssi->screen, ssi->current_visual,
1265 ssi->current_visual = new_v;
1266 ssi->current_depth = visual_depth(ssi->screen, new_v);
1268 ssi->screensaver_window = 0;
1270 initialize_screensaver_window_1 (ssi);
1272 /* stderr_overlay_window is a child of screensaver_window, so we need
1273 to destroy that as well (actually, we just need to invalidate and
1274 drop our pointers to it, but this will destroy it, which is ok so
1275 long as it happens before old_w itself is destroyed.) */
1278 raise_window (si, True, True, False);
1279 store_vroot_property (si->dpy,
1280 ssi->screensaver_window, ssi->screensaver_window);
1281 store_activate_time (si, True);
1285 /* Transfer the grabs from the old window to the new.
1286 Actually I think none of this is necessary, since we always
1287 hold our grabs on the root window, but I wrote this before
1288 re-discovering that...
1292 /* If we're destroying the window that holds our mouse grab,
1293 transfer the grab to the new window. (Grab the server while
1294 so doing, to avoid a race condition.)
1296 if (old_w == si->mouse_grab_window)
1298 XGrabServer (si->dpy); /* ############ DANGER! */
1300 grab_mouse(si, ssi->screensaver_window,
1301 (si->demo_mode_p ? 0 : ssi->cursor));
1302 XUngrabServer (si->dpy);
1303 XSync (si->dpy, False); /* ###### (danger over) */
1306 /* If we're destroying the window that holds our keyboard grab,
1307 transfer the grab to the new window. (Grab the server while
1308 so doing, to avoid a race condition.)
1310 if (old_w == si->keyboard_grab_window)
1312 XGrabServer (si->dpy); /* ############ DANGER! */
1314 grab_kbd(si, ssi->screensaver_window);
1315 XUngrabServer (si->dpy);
1316 XSync (si->dpy, False); /* ###### (danger over) */
1319 /* Now we can destroy this window without horking our grabs. */
1321 XDestroyWindow (si->dpy, old_w);
1324 fprintf (stderr, "%s: destroyed old saver window 0x%lx.\n",
1325 blurb(), (unsigned long) old_w);
1328 old_c != DefaultColormapOfScreen (ssi->screen) &&
1329 old_c != ssi->demo_cmap)
1330 XFreeColormap (si->dpy, old_c);
1339 #ifdef HAVE_VT_LOCKSWITCH
1341 lock_vt (saver_info *si, Bool lock_p)
1343 saver_preferences *p = &si->prefs;
1344 static Bool locked_p = False;
1345 const char *dev_console = "/dev/console";
1348 if (lock_p == locked_p)
1351 if (lock_p && !p->lock_vt_p)
1354 fd = open (dev_console, O_RDWR);
1358 sprintf (buf, "%s: couldn't %s VTs: %s", blurb(),
1359 (lock_p ? "lock" : "unlock"),
1361 #if 0 /* #### doesn't work yet, so don't bother complaining */
1367 if (ioctl (fd, (lock_p ? VT_LOCKSWITCH : VT_UNLOCKSWITCH)) == 0)
1372 fprintf (stderr, "%s: %s VTs\n", blurb(),
1373 (lock_p ? "locked" : "unlocked"));
1378 sprintf (buf, "%s: couldn't %s VTs: ioctl", blurb(),
1379 (lock_p ? "lock" : "unlock"));
1380 #if 0 /* #### doesn't work yet, so don't bother complaining */
1387 #endif /* HAVE_VT_LOCKSWITCH */