1 /* windows.c --- turning the screen black; dealing with visuals, virtual roots.
2 * xscreensaver, Copyright (c) 1991-1998 Jamie Zawinski <jwz@netscape.com>
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: XGrabKeyboard(... 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: XGrabPointer(... 0x%x, 0x%x ...) ==> %s\n",
141 blurb(), (unsigned long) w, (unsigned long) cursor,
142 grab_string(status));
148 ungrab_kbd(saver_info *si)
150 saver_preferences *p = &si->prefs;
151 XUngrabKeyboard(si->dpy, CurrentTime);
153 fprintf(stderr, "%s: XUngrabKeyboard (was 0x%x)\n", blurb(),
154 (unsigned long) si->keyboard_grab_window);
155 si->keyboard_grab_window = 0;
160 ungrab_mouse(saver_info *si)
162 saver_preferences *p = &si->prefs;
163 XUngrabPointer(si->dpy, CurrentTime);
165 fprintf(stderr, "%s: XUngrabPointer (was 0x%x)\n", blurb(),
166 (unsigned long) si->mouse_grab_window);
167 si->mouse_grab_window = 0;
172 grab_keyboard_and_mouse (saver_info *si, Window window, Cursor cursor)
175 XSync (si->dpy, False);
177 status = grab_kbd (si, window);
178 if (status != GrabSuccess)
179 { /* try again in a second */
181 status = grab_kbd (si, window);
182 if (status != GrabSuccess)
183 fprintf (stderr, "%s: couldn't grab keyboard! (%s)\n",
184 blurb(), grab_string(status));
187 status = grab_mouse (si, window, cursor);
188 if (status != GrabSuccess)
189 { /* try again in a second */
191 status = grab_mouse (si, window, cursor);
192 if (status != GrabSuccess)
193 fprintf (stderr, "%s: couldn't grab pointer! (%s)\n",
194 blurb(), grab_string(status));
199 ungrab_keyboard_and_mouse (saver_info *si)
206 /* Prints an error message to stderr and returns True if there is another
207 xscreensaver running already. Silently returns False otherwise. */
209 ensure_no_screensaver_running (Display *dpy, Screen *screen)
213 Window root = RootWindowOfScreen (screen);
214 Window root2, parent, *kids;
216 XErrorHandler old_handler = XSetErrorHandler (BadWindow_ehandler);
218 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
224 for (i = 0; i < nkids; i++)
228 unsigned long nitems, bytesafter;
231 if (XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_VERSION, 0, 1,
232 False, XA_STRING, &type, &format, &nitems,
233 &bytesafter, (unsigned char **) &version)
238 if (!XGetWindowProperty (dpy, kids[i], XA_SCREENSAVER_ID, 0, 512,
239 False, XA_STRING, &type, &format, &nitems,
240 &bytesafter, (unsigned char **) &id)
246 "%s: already running on display %s (window 0x%x)\n from process %s.\n",
247 blurb(), DisplayString (dpy), (int) kids [i], id);
252 if (kids) XFree ((char *) kids);
254 XSetErrorHandler (old_handler);
260 /* Virtual-root hackery */
263 ERROR! You must not include vroot.h in this file.
267 store_vroot_property (Display *dpy, Window win, Window value)
272 "%s: storing XA_VROOT = 0x%x (%s) = 0x%x (%s)\n", blurb(),
274 (win == screensaver_window ? "ScreenSaver" :
275 (win == real_vroot ? "VRoot" :
276 (win == real_vroot_value ? "Vroot_value" : "???"))),
278 (value == screensaver_window ? "ScreenSaver" :
279 (value == real_vroot ? "VRoot" :
280 (value == real_vroot_value ? "Vroot_value" : "???"))));
282 XChangeProperty (dpy, win, XA_VROOT, XA_WINDOW, 32, PropModeReplace,
283 (unsigned char *) &value, 1);
287 remove_vroot_property (Display *dpy, Window win)
291 fprintf (stderr, "%s: removing XA_VROOT from 0x%x (%s)\n", blurb(), win,
292 (win == screensaver_window ? "ScreenSaver" :
293 (win == real_vroot ? "VRoot" :
294 (win == real_vroot_value ? "Vroot_value" : "???"))));
296 XDeleteProperty (dpy, win, XA_VROOT);
301 kill_xsetroot_data (Display *dpy, Window window, Bool verbose_p)
305 unsigned long nitems, bytesafter;
308 /* If the user has been using xv or xsetroot as a screensaver (to display
309 an image on the screensaver window, as a kind of slideshow) then the
310 pixmap and its associated color cells have been put in RetainPermanent
311 CloseDown mode. Since we're not destroying the xscreensaver window,
312 but merely unmapping it, we need to free these resources or those
313 colormap cells will stay allocated while the screensaver is off. (We
314 could just delete the screensaver window and recreate it later, but
315 that could cause other problems.) This code does an atomic read-and-
316 delete of the _XSETROOT_ID property, and if it held a pixmap, then we
317 cause the RetainPermanent resources of the client which created it
318 (and which no longer exists) to be freed.
320 if (XGetWindowProperty (dpy, window, XA_XSETROOT_ID, 0, 1,
321 True, AnyPropertyType, &type, &format, &nitems,
322 &bytesafter, (unsigned char **) &dataP)
326 if (dataP && *dataP && type == XA_PIXMAP && format == 32 &&
327 nitems == 1 && bytesafter == 0)
330 printf ("%s: destroying xsetroot data (0x%lX).\n",
332 XKillClient (dpy, *dataP);
335 fprintf (stderr, "%s: deleted unrecognised _XSETROOT_ID property: \n\
336 %lu, %lu; type: %lu, format: %d, nitems: %lu, bytesafter %ld\n",
337 blurb(), (unsigned long) dataP, (dataP ? *dataP : 0), type,
338 format, nitems, bytesafter);
343 static void handle_signals (saver_info *si, Bool on_p);
346 save_real_vroot (saver_screen_info *ssi)
348 saver_info *si = ssi->global;
349 Display *dpy = si->dpy;
350 Screen *screen = ssi->screen;
352 Window root = RootWindowOfScreen (screen);
353 Window root2, parent, *kids;
357 ssi->real_vroot_value = 0;
358 if (! XQueryTree (dpy, root, &root2, &parent, &kids, &nkids))
364 for (i = 0; i < nkids; i++)
368 unsigned long nitems, bytesafter;
371 if (XGetWindowProperty (dpy, kids[i], XA_VROOT, 0, 1, False, XA_WINDOW,
372 &type, &format, &nitems, &bytesafter,
373 (unsigned char **) &vrootP)
380 if (*vrootP == ssi->screensaver_window) abort ();
382 "%s: more than one virtual root window found (0x%x and 0x%x).\n",
383 blurb(), (int) ssi->real_vroot, (int) kids [i]);
386 ssi->real_vroot = kids [i];
387 ssi->real_vroot_value = *vrootP;
392 handle_signals (si, True);
393 remove_vroot_property (si->dpy, ssi->real_vroot);
397 XFree ((char *) kids);
402 restore_real_vroot_2 (saver_screen_info *ssi)
404 saver_info *si = ssi->global;
405 saver_preferences *p = &si->prefs;
406 if (p->verbose_p && ssi->real_vroot)
407 printf ("%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));
555 handle_signals (saver_info *si, Bool on_p)
558 if (on_p) printf ("handling signals\n");
559 else printf ("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)
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)
619 fprintf(real_stderr, "%s: dumping core (because of -debug)\n", blurb());
620 /* Do this to drop a core file, so that we can get a stack trace. */
628 /* Managing the actual screensaver window */
631 window_exists_p (Display *dpy, Window window)
633 XErrorHandler old_handler;
634 XWindowAttributes xgwa;
636 old_handler = XSetErrorHandler (BadWindow_ehandler);
637 XGetWindowAttributes (dpy, window, &xgwa);
639 XSetErrorHandler (old_handler);
640 return (xgwa.screen != 0);
644 initialize_screensaver_window_1 (saver_screen_info *ssi)
646 saver_info *si = ssi->global;
647 saver_preferences *p = &si->prefs;
648 Bool install_cmap_p = (ssi->install_cmap_p || p->install_cmap_p);
650 /* This resets the screensaver window as fully as possible, since there's
651 no way of knowing what some random client may have done to us in the
652 meantime. We could just destroy and recreate the window, but that has
653 its own set of problems...
656 XClassHint class_hints;
657 XSetWindowAttributes attrs;
658 unsigned long attrmask;
659 int width = WidthOfScreen (ssi->screen);
660 int height = HeightOfScreen (ssi->screen);
662 static Bool printed_visual_info = False; /* only print the message once. */
664 black.red = black.green = black.blue = 0;
666 if (ssi->cmap == DefaultColormapOfScreen (ssi->screen))
669 if (ssi->current_visual != DefaultVisualOfScreen (ssi->screen))
670 install_cmap_p = True;
676 ssi->cmap = XCreateColormap (si->dpy, RootWindowOfScreen (ssi->screen),
677 ssi->current_visual, AllocNone);
678 if (! XAllocColor (si->dpy, ssi->cmap, &black)) abort ();
679 ssi->black_pixel = black.pixel;
684 Colormap def_cmap = DefaultColormapOfScreen (ssi->screen);
687 XFreeColors (si->dpy, ssi->cmap, &ssi->black_pixel, 1, 0);
688 if (ssi->cmap != ssi->demo_cmap &&
689 ssi->cmap != def_cmap)
690 XFreeColormap (si->dpy, ssi->cmap);
692 ssi->cmap = def_cmap;
693 ssi->black_pixel = BlackPixelOfScreen (ssi->screen);
696 attrmask = (CWOverrideRedirect | CWEventMask | CWBackingStore | CWColormap |
697 CWBackPixel | CWBackingPixel | CWBorderPixel);
698 attrs.override_redirect = True;
700 /* When use_mit_saver_extension or use_sgi_saver_extension is true, we won't
701 actually be reading these events during normal operation; but we still
702 need to see Button events for demo-mode to work properly.
704 attrs.event_mask = (KeyPressMask | KeyReleaseMask |
705 ButtonPressMask | ButtonReleaseMask |
708 attrs.backing_store = NotUseful;
709 attrs.colormap = ssi->cmap;
710 attrs.background_pixel = ssi->black_pixel;
711 attrs.backing_pixel = ssi->black_pixel;
712 attrs.border_pixel = ssi->black_pixel;
714 if (p->debug_p) width = width / 2;
716 if (!p->verbose_p || printed_visual_info)
718 else if (ssi->current_visual == DefaultVisualOfScreen (ssi->screen))
720 fprintf (stderr, "%s: using default visual ", blurb());
721 describe_visual (stderr, ssi->screen, ssi->current_visual,
726 fprintf (stderr, "%s: using visual: ", blurb());
727 describe_visual (stderr, ssi->screen, ssi->current_visual,
729 fprintf (stderr, "%s: default visual: ", blurb());
730 describe_visual (stderr, ssi->screen,
731 DefaultVisualOfScreen (ssi->screen),
732 ssi->install_cmap_p);
734 printed_visual_info = True;
736 #ifdef HAVE_MIT_SAVER_EXTENSION
737 if (p->use_mit_saver_extension)
739 XScreenSaverInfo *info;
740 Window root = RootWindowOfScreen (ssi->screen);
743 /* This call sets the server screensaver timeouts to what we think
744 they should be (based on the resources and args xscreensaver was
745 started with.) It's important that we do this to sync back up
746 with the server - if we have turned on prematurely, as by an
747 ACTIVATE ClientMessage, then the server may decide to activate
748 the screensaver while it's already active. That's ok for us,
749 since we would know to ignore that ScreenSaverActivate event,
750 but a side effect of this would be that the server would map its
751 saver window (which we then hide again right away) meaning that
752 the bits currently on the screen get blown away. Ugly. */
754 /* #### Ok, that doesn't work - when we tell the server that the
755 screensaver is "off" it sends us a Deactivate event, which is
756 sensible... but causes the saver to never come on. Hmm. */
757 disable_builtin_screensaver (si, True);
761 /* #### The MIT-SCREEN-SAVER extension gives us access to the
762 window that the server itself uses for saving the screen.
763 However, using this window in any way, in particular, calling
764 XScreenSaverSetAttributes() as below, tends to make the X server
765 crash. So fuck it, let's try and get along without using it...
767 It's also inconvenient to use this window because it doesn't
768 always exist (though the ID is constant.) So to use this
769 window, we'd have to reimplement the ACTIVATE ClientMessage to
770 tell the *server* to tell *us* to turn on, to cause the window
771 to get created at the right time. Gag. */
772 XScreenSaverSetAttributes (si->dpy, root,
773 0, 0, width, height, 0,
774 current_depth, InputOutput, visual,
776 XSync (si->dpy, False);
779 info = XScreenSaverAllocInfo ();
780 XScreenSaverQueryInfo (si->dpy, root, info);
781 ssi->server_mit_saver_window = info->window;
782 if (! ssi->server_mit_saver_window) abort ();
785 #endif /* HAVE_MIT_SAVER_EXTENSION */
787 if (ssi->screensaver_window)
789 XWindowChanges changes;
790 unsigned int changesmask = CWX|CWY|CWWidth|CWHeight|CWBorderWidth;
793 changes.width = width;
794 changes.height = height;
795 changes.border_width = 0;
797 XConfigureWindow (si->dpy, ssi->screensaver_window,
798 changesmask, &changes);
799 XChangeWindowAttributes (si->dpy, ssi->screensaver_window,
804 ssi->screensaver_window =
805 XCreateWindow (si->dpy, RootWindowOfScreen (ssi->screen), 0, 0,
806 width, height, 0, ssi->current_depth, InputOutput,
807 ssi->current_visual, attrmask, &attrs);
809 store_activate_time(si, True);
811 fprintf (stderr, "%s: saver window is 0x%lx.\n",
812 blurb(), (unsigned long) ssi->screensaver_window);
815 #ifdef HAVE_MIT_SAVER_EXTENSION
816 if (!p->use_mit_saver_extension ||
817 window_exists_p (si->dpy, ssi->screensaver_window))
818 /* When using the MIT-SCREEN-SAVER extension, the window pointed to
819 by screensaver_window only exists while the saver is active.
820 So we must be careful to only try and manipulate it while it
822 (#### The above comment would be true if the MIT extension actually
823 worked, but it's not true today -- see `server_mit_saver_window'.)
825 #endif /* HAVE_MIT_SAVER_EXTENSION */
827 class_hints.res_name = progname;
828 class_hints.res_class = progclass;
829 XSetClassHint (si->dpy, ssi->screensaver_window, &class_hints);
830 XStoreName (si->dpy, ssi->screensaver_window, "screensaver");
831 XChangeProperty (si->dpy, ssi->screensaver_window,
832 XA_SCREENSAVER_VERSION,
833 XA_STRING, 8, PropModeReplace,
834 (unsigned char *) si->version,
835 strlen (si->version));
837 sprintf (id, "%lu on host ", (unsigned long) getpid ());
839 # if defined(HAVE_UNAME)
842 if (uname (&uts) < 0)
845 strcat (id, uts.nodename);
848 strcat (id, getenv("SYS$NODE"));
849 # else /* !HAVE_UNAME && !VMS */
851 # endif /* !HAVE_UNAME && !VMS */
853 XChangeProperty (si->dpy, ssi->screensaver_window,
854 XA_SCREENSAVER_ID, XA_STRING,
855 8, PropModeReplace, (unsigned char *) id, strlen (id));
860 bit = XCreatePixmapFromBitmapData (si->dpy, ssi->screensaver_window,
862 BlackPixelOfScreen (ssi->screen),
863 BlackPixelOfScreen (ssi->screen),
865 ssi->cursor = XCreatePixmapCursor (si->dpy, bit, bit, &black, &black,
867 XFreePixmap (si->dpy, bit);
870 XSetWindowBackground (si->dpy, ssi->screensaver_window,
873 XUndefineCursor (si->dpy, ssi->screensaver_window);
875 XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
880 initialize_screensaver_window (saver_info *si)
883 for (i = 0; i < si->nscreens; i++)
884 initialize_screensaver_window_1 (&si->screens[i]);
889 raise_window (saver_info *si,
890 Bool inhibit_fade, Bool between_hacks_p, Bool dont_clear)
892 saver_preferences *p = &si->prefs;
895 initialize_screensaver_window (si);
896 reset_watchdog_timer (si, True);
898 if (p->fade_p && !inhibit_fade && !si->demo_mode_p)
901 Window *current_windows = (Window *)
902 calloc(sizeof(Window), si->nscreens);
903 Colormap *current_maps = (Colormap *)
904 calloc(sizeof(Colormap), si->nscreens);
906 for (i = 0; i < si->nscreens; i++)
908 saver_screen_info *ssi = &si->screens[i];
909 current_windows[i] = ssi->screensaver_window;
910 current_maps[i] = (between_hacks_p
912 : DefaultColormapOfScreen (ssi->screen));
913 /* Ensure that the default background of the window is really black,
914 not a pixmap or something. (This does not clear the window.) */
915 XSetWindowBackground (si->dpy, ssi->screensaver_window,
919 if (p->verbose_p) fprintf (stderr, "%s: fading... ", blurb());
921 XGrabServer (si->dpy); /* ############ DANGER! */
923 /* Clear the stderr layer on each screen.
924 Grab the mouse on the first screen on which the mouse is grabbable
925 (if there are multiple heads, I think you might only be able to
926 grab the mouse on the screen that currently has the mouse? Anyway,
927 we only grab the mouse once, and don't try again after the grab
928 has succeeded.) We grab the mouse on the root window of the screen,
929 not on the screensaver window, since the screensaver window is not
932 for (i = 0; i < si->nscreens; i++)
934 saver_screen_info *ssi = &si->screens[i];
936 /* grab and blacken mouse on the root window (saver not mapped yet)
938 if (grabbed != GrabSuccess)
940 Window root = RootWindowOfScreen(ssi->screen);
941 grabbed = grab_mouse (si, root,
942 (si->demo_mode_p ? 0 : ssi->cursor));
945 if (!dont_clear || ssi->stderr_overlay_window)
946 /* Do this before the fade, since the stderr cmap won't fade
947 even if we uninstall it (beats me...) */
951 /* Note! The server is grabbed, and this will take several seconds
953 fade_screens (si->dpy, current_maps, current_windows,
954 p->fade_seconds, p->fade_ticks, True, !dont_clear);
957 free(current_windows);
961 if (p->verbose_p) fprintf (stderr, "fading done.\n");
963 #ifdef HAVE_MIT_SAVER_EXTENSION
964 for (i = 0; i < si->nscreens; i++)
966 saver_screen_info *ssi = &si->screens[i];
967 if (ssi->server_mit_saver_window &&
968 window_exists_p (si->dpy, ssi->server_mit_saver_window))
969 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
971 #endif /* HAVE_MIT_SAVER_EXTENSION */
973 /* If we had successfully grabbed the mouse, let it go now. */
974 if (grabbed == GrabSuccess)
977 XUngrabServer (si->dpy);
978 XSync (si->dpy, False); /* ###### (danger over) */
982 for (i = 0; i < si->nscreens; i++)
984 saver_screen_info *ssi = &si->screens[i];
986 XClearWindow (si->dpy, ssi->screensaver_window);
987 if (!dont_clear || ssi->stderr_overlay_window)
989 XMapRaised (si->dpy, ssi->screensaver_window);
990 #ifdef HAVE_MIT_SAVER_EXTENSION
991 if (ssi->server_mit_saver_window &&
992 window_exists_p (si->dpy, ssi->server_mit_saver_window))
993 XUnmapWindow (si->dpy, ssi->server_mit_saver_window);
994 #endif /* HAVE_MIT_SAVER_EXTENSION */
998 for (i = 0; i < si->nscreens; i++)
1000 saver_screen_info *ssi = &si->screens[i];
1002 XInstallColormap (si->dpy, ssi->cmap);
1007 blank_screen (saver_info *si)
1010 for (i = 0; i < si->nscreens; i++)
1012 saver_screen_info *ssi = &si->screens[i];
1014 save_real_vroot (ssi);
1015 store_vroot_property (si->dpy,
1016 ssi->screensaver_window,
1017 ssi->screensaver_window);
1019 store_activate_time (si, si->screen_blanked_p);
1020 raise_window (si, False, False, False);
1022 /* Note: we do our grabs on the root window, not on the screensaver window.
1023 If we grabbed on the saver window, then the demo mode and lock dialog
1024 boxes wouldn't get any events.
1026 grab_keyboard_and_mouse (si,
1027 /*si->screens[0].screensaver_window,*/
1028 RootWindowOfScreen(si->screens[0].screen),
1029 (si->demo_mode_p ? 0 : si->screens[0].cursor));
1031 #ifdef HAVE_XHPDISABLERESET
1032 if (si->locked_p && !hp_locked_p)
1034 XHPDisableReset (si->dpy); /* turn off C-Sh-Reset */
1039 si->screen_blanked_p = True;
1043 unblank_screen (saver_info *si)
1045 saver_preferences *p = &si->prefs;
1048 monitor_power_on (si);
1050 store_activate_time (si, True);
1051 reset_watchdog_timer (si, False);
1053 if (p->unfade_p && !si->demo_mode_p)
1056 Window *current_windows = (Window *)
1057 calloc(sizeof(Window), si->nscreens);
1059 for (i = 0; i < si->nscreens; i++)
1061 saver_screen_info *ssi = &si->screens[i];
1062 current_windows[i] = ssi->screensaver_window;
1063 /* Ensure that the default background of the window is really black,
1064 not a pixmap or something. (This does not clear the window.) */
1065 XSetWindowBackground (si->dpy, ssi->screensaver_window,
1069 if (p->verbose_p) fprintf (stderr, "%s: unfading... ", blurb());
1072 XSync (si->dpy, False);
1073 XGrabServer (si->dpy); /* ############ DANGER! */
1074 XSync (si->dpy, False);
1076 /* Clear the stderr layer on each screen.
1077 Grab the mouse on the first screen on which the mouse is grabbable
1078 (if there are multiple heads, I think you might only be able to
1079 grab the mouse on the screen that currently has the mouse? Anyway,
1080 we only grab the mouse once, and don't try again after the grab
1083 for (i = 0; i < si->nscreens; i++)
1085 saver_screen_info *ssi = &si->screens[i];
1086 if (grabbed != GrabSuccess)
1087 grabbed = grab_mouse (si, RootWindowOfScreen (ssi->screen),
1092 XUngrabServer (si->dpy);
1093 XSync (si->dpy, False); /* ###### (danger over) */
1096 fade_screens (si->dpy, 0, current_windows,
1097 p->fade_seconds, p->fade_ticks,
1100 free(current_windows);
1101 current_windows = 0;
1103 if (p->verbose_p) fprintf (stderr, "unfading done.\n");
1105 /* If we had successfully grabbed the mouse, let it go now. */
1106 if (grabbed == GrabSuccess)
1111 for (i = 0; i < si->nscreens; i++)
1113 saver_screen_info *ssi = &si->screens[i];
1116 Colormap c = DefaultColormapOfScreen (ssi->screen);
1117 /* avoid technicolor */
1118 XClearWindow (si->dpy, ssi->screensaver_window);
1119 if (c) XInstallColormap (si->dpy, c);
1121 XUnmapWindow (si->dpy, ssi->screensaver_window);
1126 /* If the focus window does has a non-default colormap, then install
1127 that colormap as well. (On SGIs, this will cause both the root map
1128 and the focus map to be installed simultaniously. It'd be nice to
1129 pick up the other colormaps that had been installed, too; perhaps
1130 XListInstalledColormaps could be used for that?)
1135 XGetInputFocus (si->dpy, &focus, &revert_to);
1136 if (focus && focus != PointerRoot && focus != None)
1138 XWindowAttributes xgwa;
1140 XGetWindowAttributes (si->dpy, focus, &xgwa);
1141 if (xgwa.colormap &&
1142 xgwa.colormap != DefaultColormapOfScreen (xgwa.screen))
1143 XInstallColormap (si->dpy, xgwa.colormap);
1148 for (i = 0; i < si->nscreens; i++)
1150 saver_screen_info *ssi = &si->screens[i];
1151 kill_xsetroot_data (si->dpy, ssi->screensaver_window, p->verbose_p);
1154 store_activate_time(si, False); /* store unblank time */
1156 ungrab_keyboard_and_mouse (si);
1157 restore_real_vroot (si);
1159 #ifdef HAVE_XHPDISABLERESET
1162 XHPEnableReset (si->dpy); /* turn C-Sh-Reset back on */
1163 hp_locked_p = False;
1167 /* Unmap the windows a second time, dammit -- just to avoid a race
1168 with the screen-grabbing hacks. (I'm not sure if this is really
1169 necessary; I'm stabbing in the dark now.)
1171 for (i = 0; i < si->nscreens; i++)
1172 XUnmapWindow (si->dpy, si->screens[i].screensaver_window);
1174 si->screen_blanked_p = False;
1179 store_activate_time (saver_info *si, Bool use_last_p)
1181 static time_t last_time = 0;
1182 time_t now = ((use_last_p && last_time) ? last_time : time ((time_t) 0));
1183 CARD32 now32 = (CARD32) now;
1187 for (i = 0; i < si->nscreens; i++)
1189 saver_screen_info *ssi = &si->screens[i];
1190 if (!ssi->screensaver_window) continue;
1191 XChangeProperty (si->dpy, ssi->screensaver_window, XA_SCREENSAVER_TIME,
1192 XA_INTEGER, 32, PropModeReplace,
1193 (unsigned char *) &now32, 1);
1199 select_visual (saver_screen_info *ssi, const char *visual_name)
1201 saver_info *si = ssi->global;
1202 saver_preferences *p = &si->prefs;
1203 Bool install_cmap_p = p->install_cmap_p;
1204 Bool was_installed_p = (ssi->cmap != DefaultColormapOfScreen(ssi->screen));
1208 if (visual_name && *visual_name)
1210 if (!strcmp(visual_name, "default-i"))
1212 visual_name = "default";
1213 install_cmap_p = True;
1215 else if (!strcmp(visual_name, "default-n"))
1217 visual_name = "default";
1218 install_cmap_p = False;
1220 new_v = get_visual (ssi->screen, visual_name, True, False);
1224 new_v = ssi->default_visual;
1229 if (new_v && new_v != DefaultVisualOfScreen(ssi->screen))
1230 install_cmap_p = True;
1232 ssi->install_cmap_p = install_cmap_p;
1235 ((ssi->current_visual != new_v) ||
1236 (install_cmap_p != was_installed_p)))
1238 Colormap old_c = ssi->cmap;
1239 Window old_w = ssi->screensaver_window;
1243 fprintf (stderr, "%s: switching to visual ", blurb());
1244 describe_visual (stderr, ssi->screen, new_v, install_cmap_p);
1246 fprintf (stderr, "%s: from ", blurb());
1247 describe_visual (stderr, ssi->screen, ssi->current_visual,
1253 ssi->current_visual = new_v;
1254 ssi->current_depth = visual_depth(ssi->screen, new_v);
1256 ssi->screensaver_window = 0;
1258 initialize_screensaver_window_1 (ssi);
1259 raise_window (si, True, True, False);
1260 store_vroot_property (si->dpy,
1261 ssi->screensaver_window, ssi->screensaver_window);
1262 store_activate_time (si, True);
1266 /* Transfer the grabs from the old window to the new.
1267 Actually I think none of this is necessary, since we always
1268 hold our grabs on the root window, but I wrote this before
1269 re-discovering that...
1273 /* If we're destroying the window that holds our mouse grab,
1274 transfer the grab to the new window. (Grab the server while
1275 so doing, to avoid a race condition.)
1277 if (old_w == si->mouse_grab_window)
1279 XGrabServer (si->dpy); /* ############ DANGER! */
1281 grab_mouse(si, ssi->screensaver_window,
1282 (si->demo_mode_p ? 0 : ssi->cursor));
1283 XUngrabServer (si->dpy);
1284 XSync (si->dpy, False); /* ###### (danger over) */
1287 /* If we're destroying the window that holds our keyboard grab,
1288 transfer the grab to the new window. (Grab the server while
1289 so doing, to avoid a race condition.)
1291 if (old_w == si->keyboard_grab_window)
1293 XGrabServer (si->dpy); /* ############ DANGER! */
1295 grab_kbd(si, ssi->screensaver_window);
1296 XUngrabServer (si->dpy);
1297 XSync (si->dpy, False); /* ###### (danger over) */
1300 /* Now we can destroy this window without horking our grabs. */
1302 XDestroyWindow (si->dpy, old_w);
1305 fprintf (stderr, "%s: destroyed old saver window 0x%lx.\n",
1306 blurb(), (unsigned long) old_w);
1309 old_c != DefaultColormapOfScreen (ssi->screen) &&
1310 old_c != ssi->demo_cmap)
1311 XFreeColormap (si->dpy, old_c);