8378e1cf8b0073b3ff172b62fddfb22f47aa8807
[xscreensaver] / driver / xset.c
1 /* xset.c --- interacting with server extensions and the builtin screensaver.
2  * xscreensaver, Copyright (c) 1991-2008 Jamie Zawinski <jwz@jwz.org>
3  *
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 
10  * implied warranty.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16
17 #include <stdio.h>
18 #include <X11/Xlib.h>
19 #include <X11/Xutil.h>
20 #include <X11/Xatom.h>
21 #include <X11/Xos.h>
22
23 /* This file doesn't need the Xt headers, so stub these types out... */
24 #undef XtPointer
25 #define XtAppContext void*
26 #define XrmDatabase  void*
27 #define XtIntervalId void*
28 #define XtPointer    void*
29 #define Widget       void*
30
31 #include "xscreensaver.h"
32
33 #ifdef _VROOT_H_
34 ERROR!  You must not include vroot.h in this file.
35 #endif
36
37 \f
38 /* MIT SCREEN-SAVER server extension hackery.
39  */
40
41 #ifdef HAVE_MIT_SAVER_EXTENSION
42
43 # include <X11/extensions/scrnsaver.h>
44
45 static int
46 ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
47 {
48   return 0;
49 }
50
51 static void
52 init_mit_saver_extension (saver_info *si)
53 {
54   int i;
55   Pixmap *blank_pix = (Pixmap *) calloc (sizeof(Pixmap), si->nscreens);
56
57   for (i = 0; i < si->nscreens; i++)
58     {
59       saver_screen_info *ssi = &si->screens[i];
60       XID kill_id = 0;
61       Atom kill_type = 0;
62       Window root = RootWindowOfScreen (ssi->screen);
63       blank_pix[i] = XCreatePixmap (si->dpy, root, 1, 1, 1);
64
65       /* Kill off the old MIT-SCREEN-SAVER client if there is one.
66          This tends to generate X errors, though (possibly due to a bug
67          in the server extension itself?) so just ignore errors here. */
68       if (XScreenSaverGetRegistered (si->dpy,
69                                      XScreenNumberOfScreen (ssi->screen),
70                                      &kill_id, &kill_type)
71           && kill_id != blank_pix[i])
72         {
73           XErrorHandler old_handler =
74             XSetErrorHandler (ignore_all_errors_ehandler);
75           XKillClient (si->dpy, kill_id);
76           XSync (si->dpy, False);
77           XSetErrorHandler (old_handler);
78         }
79       XScreenSaverSelectInput (si->dpy, root, ScreenSaverNotifyMask);
80       XScreenSaverRegister (si->dpy,
81                             XScreenNumberOfScreen (ssi->screen),
82                             (XID) blank_pix[i], XA_PIXMAP);
83     }
84   free(blank_pix);
85 }
86 #endif /* HAVE_MIT_SAVER_EXTENSION */
87
88 \f
89 /* SGI SCREEN_SAVER server extension hackery.
90  */
91
92 #ifdef HAVE_SGI_SAVER_EXTENSION
93
94 # include <X11/extensions/XScreenSaver.h>
95
96 static void
97 init_sgi_saver_extension (saver_info *si)
98 {
99   saver_preferences *p = &si->prefs;
100   int i;
101   if (si->screen_blanked_p)
102     /* If you mess with this while the server thinks it's active,
103        the server crashes. */
104     return;
105
106   for (i = 0; i < si->nscreens; i++)
107     {
108       saver_screen_info *ssi = &si->screens[i];
109       XScreenSaverDisable (si->dpy, XScreenNumberOfScreen(ssi->screen));
110       if (! XScreenSaverEnable (si->dpy, XScreenNumberOfScreen(ssi->screen)))
111         {
112           fprintf (stderr,
113        "%s: SGI SCREEN_SAVER extension exists, but can't be initialized;\n\
114                 perhaps some other screensaver program is already running?\n",
115                    blurb());
116           si->using_sgi_saver_extension = False;
117           return;
118         }
119     }
120 }
121
122 #endif /* HAVE_SGI_SAVER_EXTENSION */
123
124
125 \f
126 /* Figuring out what the appropriate XSetScreenSaver() parameters are
127    (one wouldn't expect this to be rocket science.)
128  */
129
130 void
131 disable_builtin_screensaver (saver_info *si, Bool unblank_screen_p)
132 {
133   saver_preferences *p = &si->prefs;
134   int current_server_timeout, current_server_interval;
135   int current_prefer_blank, current_allow_exp;
136   int desired_server_timeout, desired_server_interval;
137   int desired_prefer_blank, desired_allow_exp;
138
139   XGetScreenSaver (si->dpy, &current_server_timeout, &current_server_interval,
140                    &current_prefer_blank, &current_allow_exp);
141
142   desired_server_timeout = current_server_timeout;
143   desired_server_interval = current_server_interval;
144   desired_prefer_blank = current_prefer_blank;
145   desired_allow_exp = current_allow_exp;
146
147   /* On SGIs, if interval is non-zero, it is the number of seconds after
148      screen saving starts at which the monitor should be powered down.
149      Obviously I don't want that, so set it to 0 (meaning "never".)
150
151      Power saving is disabled if DontPreferBlanking, but in that case,
152      we don't get extension events either.  So we can't turn it off that way.
153
154      Note: if you're running Irix 6.3 (O2), you may find that your monitor is
155      powering down anyway, regardless of the xset settings.  This is fixed by
156      installing SGI patches 2447 and 2537.
157    */
158   desired_server_interval = 0;
159
160   /* I suspect (but am not sure) that DontAllowExposures might have
161      something to do with powering off the monitor as well, at least
162      on some systems that don't support XDPMS?  Who knows... */
163   desired_allow_exp = AllowExposures;
164
165   if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
166     {
167       desired_server_timeout = (p->timeout / 1000);
168
169       /* The SGI extension won't give us events unless blanking is on.
170          I think (unsure right now) that the MIT extension is the opposite. */
171       if (si->using_sgi_saver_extension)
172         desired_prefer_blank = PreferBlanking;
173       else
174         desired_prefer_blank = DontPreferBlanking;
175     }
176   else
177     {
178       /* When we're not using an extension, set the server-side timeout to 0,
179          so that the server never gets involved with screen blanking, and we
180          do it all ourselves.  (However, when we *are* using an extension,
181          we tell the server when to notify us, and rather than blanking the
182          screen, the server will send us an X event telling us to blank.)
183        */
184       desired_server_timeout = 0;
185     }
186
187   /* XSetScreenSaver() generates BadValue if either timeout parameter
188      exceeds 15 bits (signed short.)  That is 09:06:07.
189    */
190   if (desired_server_timeout  > 0x7FFF) desired_server_timeout  = 0x7FFF;
191   if (desired_server_interval > 0x7FFF) desired_server_interval = 0x7FFF;
192
193   if (desired_server_timeout != current_server_timeout ||
194       desired_server_interval != current_server_interval ||
195       desired_prefer_blank != current_prefer_blank ||
196       desired_allow_exp != current_allow_exp)
197     {
198       if (p->verbose_p)
199         fprintf (stderr,
200                  "%s: disabling server builtin screensaver:\n"
201                  "%s:  (xset s %d %d; xset s %s; xset s %s)\n",
202                  blurb(), blurb(),
203                  desired_server_timeout, desired_server_interval,
204                  (desired_prefer_blank ? "blank" : "noblank"),
205                  (desired_allow_exp ? "expose" : "noexpose"));
206
207       XSetScreenSaver (si->dpy,
208                        desired_server_timeout, desired_server_interval,
209                        desired_prefer_blank, desired_allow_exp);
210       XSync(si->dpy, False);
211     }
212
213
214 #if defined(HAVE_MIT_SAVER_EXTENSION) || defined(HAVE_SGI_SAVER_EXTENSION)
215   {
216     static Bool extension_initted = False;
217     if (!extension_initted)
218       {
219         extension_initted = True;
220 # ifdef HAVE_MIT_SAVER_EXTENSION
221         if (si->using_mit_saver_extension) init_mit_saver_extension(si);
222 # endif
223 # ifdef HAVE_SGI_SAVER_EXTENSION
224         if (si->using_sgi_saver_extension) init_sgi_saver_extension(si);
225 # endif
226       }
227   }
228 #endif /* HAVE_MIT_SAVER_EXTENSION || HAVE_SGI_SAVER_EXTENSION */
229
230   if (unblank_screen_p)
231     /* Turn off the server builtin saver if it is now running. */
232     XForceScreenSaver (si->dpy, ScreenSaverReset);
233 }