~ubuntu-branches/ubuntu/wily/xscreensaver/wily

1.2.3 by Tormod Volden
Import upstream version 5.13
1
/* xscreensaver, Copyright (c) 1991-2011 Jamie Zawinski <jwz@jwz.org>
1 by Karl Ramm
Import upstream version 3.34
2
 *
3
 * Permission to use, copy, modify, distribute, and sell this software and its
4
 * documentation for any purpose is hereby granted without fee, provided that
5
 * the above copyright notice appear in all copies and that both that
6
 * copyright notice and this permission notice appear in supporting
7
 * documentation.  No representations are made about the suitability of this
8
 * software for any purpose.  It is provided "as is" without express or 
9
 * implied warranty.
10
 */
11
12
/*   ========================================================================
13
 *   First we wait until the keyboard and mouse become idle for the specified
14
 *   amount of time.  We do this in one of three different ways: periodically
15
 *   checking with the XIdle server extension; selecting key and mouse events
16
 *   on (nearly) all windows; or by waiting for the MIT-SCREEN-SAVER extension
17
 *   to send us a "you are idle" event.
18
 *
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
19
 *   Then, we map a full screen black window.
1 by Karl Ramm
Import upstream version 3.34
20
 *
21
 *   We place a __SWM_VROOT property on this window, so that newly-started
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
22
 *   clients will think that this window is a "virtual root" window (as per
23
 *   the logic in the historical "vroot.h" header.)
1 by Karl Ramm
Import upstream version 3.34
24
 *
25
 *   If there is an existing "virtual root" window (one that already had
26
 *   an __SWM_VROOT property) then we remove that property from that window.
27
 *   Otherwise, clients would see that window (the real virtual root) instead
28
 *   of ours (the impostor.)
29
 *
30
 *   Then we pick a random program to run, and start it.  Two assumptions 
31
 *   are made about this program: that it has been specified with whatever
32
 *   command-line options are necessary to make it run on the root window;
33
 *   and that it has been compiled with vroot.h, so that it is able to find
34
 *   the root window when a virtual-root window manager (or this program) is
35
 *   running.
36
 *
37
 *   Then, we wait for keyboard or mouse events to be generated on the window.
38
 *   When they are, we kill the inferior process, unmap the window, and restore
39
 *   the __SWM_VROOT property to the real virtual root window if there was one.
40
 *
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
41
 *   On multi-screen systems, we do the above on each screen, and start
42
 *   multiple programs, each with a different value of $DISPLAY.
43
 *
44
 *   On Xinerama systems, we do a similar thing, but instead create multiple
45
 *   windows on the (only) display, and tell the subprocess which one to use
46
 *   via the $XSCREENSAVER_WINDOW environment variable -- this trick requires
47
 *   a recent (Aug 2003) revision of vroot.h.
48
 *
1.1.6 by Ted Gould
Import upstream version 5.07
49
 *   (See comments in screens.c for more details about Xinerama/RANDR stuff.)
50
 *
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
51
 *   While we are waiting for user activity, we also set up timers so that,
52
 *   after a certain amount of time has passed, we can start a different
53
 *   screenhack.  We do this by killing the running child process with
54
 *   SIGTERM, and then starting a new one in the same way.
1 by Karl Ramm
Import upstream version 3.34
55
 *
56
 *   If there was a real virtual root, meaning that we removed the __SWM_VROOT
57
 *   property from it, meaning we must (absolutely must) restore it before we
58
 *   exit, then we set up signal handlers for most signals (SIGINT, SIGTERM,
59
 *   etc.) that do this.  Most Xlib and Xt routines are not reentrant, so it
60
 *   is not generally safe to call them from signal handlers; however, this
61
 *   program spends most of its time waiting, so the window of opportunity 
62
 *   when code could be called reentrantly is fairly small; and also, the worst
63
 *   that could happen is that the call would fail.  If we've gotten one of
64
 *   these signals, then we're on our way out anyway.  If we didn't restore the
65
 *   __SWM_VROOT property, that would be very bad, so it's worth a shot.  Note
66
 *   that this means that, if you're using a virtual-root window manager, you
67
 *   can really fuck up the world by killing this process with "kill -9".
68
 *
69
 *   This program accepts ClientMessages of type SCREENSAVER; these messages
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
70
 *   may contain the atoms ACTIVATE, DEACTIVATE, etc, meaning to turn the 
1 by Karl Ramm
Import upstream version 3.34
71
 *   screensaver on or off now, regardless of the idleness of the user,
72
 *   and a few other things.  The included "xscreensaver-command" program
73
 *   sends these messsages.
74
 *
75
 *   If we don't have the XIdle, MIT-SCREEN-SAVER, or SGI SCREEN_SAVER
76
 *   extensions, then we do the XAutoLock trick: notice every window that
77
 *   gets created, and wait 30 seconds or so until its creating process has
78
 *   settled down, and then select KeyPress events on those windows which
79
 *   already select for KeyPress events.  It's important that we not select
80
 *   KeyPress on windows which don't select them, because that would
81
 *   interfere with event propagation.  This will break if any program
82
 *   changes its event mask to contain KeyRelease or PointerMotion more than
83
 *   30 seconds after creating the window, but such programs do not seem to
84
 *   occur in nature (I've never seen it happen in all these years.)
85
 *
86
 *   The reason that we can't select KeyPresses on windows that don't have
87
 *   them already is that, when dispatching a KeyPress event, X finds the
88
 *   lowest (leafmost) window in the hierarchy on which *any* client selects
89
 *   for KeyPress, and sends the event to that window.  This means that if a
90
 *   client had a window with subwindows, and expected to receive KeyPress
91
 *   events on the parent window instead of the subwindows, then that client
92
 *   would malfunction if some other client selected KeyPress events on the
93
 *   subwindows.  It is an incredible misdesign that one client can make
94
 *   another client malfunction in this way.
95
 *
96
 *   To detect mouse motion, we periodically wake up and poll the mouse
97
 *   position and button/modifier state, and notice when something has
98
 *   changed.  We make this check every five seconds by default, and since the
99
 *   screensaver timeout has a granularity of one minute, this makes the
100
 *   chance of a false positive very small.  We could detect mouse motion in
101
 *   the same way as keyboard activity, but that would suffer from the same
102
 *   "client changing event mask" problem that the KeyPress events hack does.
103
 *   I think polling is more reliable.
104
 *
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
105
 *   On systems with /proc/interrupts (Linux) we poll that file and note when
106
 *   the interrupt counter numbers on the "keyboard" and "PS/2" lines change.
107
 *   (There is no reliable way, using /proc/interrupts, to detect non-PS/2
108
 *   mice, so it doesn't help for serial or USB mice.)
109
 *
110
 *   None of this crap happens if we're using one of the extensions.  Sadly,
111
 *   the XIdle extension hasn't been available for many years; the SGI
112
 *   extension only exists on SGIs; and the MIT extension, while widely
113
 *   deployed, is garbage in several ways.
1 by Karl Ramm
Import upstream version 3.34
114
 *
115
 *   A third idle-detection option could be implemented (but is not): when
116
 *   running on the console display ($DISPLAY is `localhost`:0) and we're on a
117
 *   machine where /dev/tty and /dev/mouse have reasonable last-modification
118
 *   times, we could just stat() those.  But the incremental benefit of
119
 *   implementing this is really small, so forget I said anything.
120
 *
121
 *   Debugging hints:
122
 *     - Have a second terminal handy.
123
 *     - Be careful where you set your breakpoints, you don't want this to
124
 *       stop under the debugger with the keyboard grabbed or the blackout
125
 *       window exposed.
126
 *     - If you run your debugger under XEmacs, try M-ESC (x-grab-keyboard)
127
 *       to keep your emacs window alive even when xscreensaver has grabbed.
128
 *     - Go read the code related to `debug_p'.
129
 *     - You probably can't set breakpoints in functions that are called on
130
 *       the other side of a call to fork() -- if your subprocesses are
131
 *       dying with signal 5, Trace/BPT Trap, you're losing in this way.
132
 *     - If you aren't using a server extension, don't leave this stopped
133
 *       under the debugger for very long, or the X input buffer will get
134
 *       huge because of the keypress events it's selecting for.  This can
135
 *       make your X server wedge with "no more input buffers."
136
 *
137
 * ======================================================================== */
138
139
#ifdef HAVE_CONFIG_H
140
# include "config.h"
141
#endif
142
143
#include <stdio.h>
144
#include <ctype.h>
145
#include <X11/Xlib.h>
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
146
1.1.10 by Robert Ancell
Import upstream version 5.12
147
#ifdef ENABLE_NLS
148
# include <locale.h>
149
# include <libintl.h>
150
#endif /* ENABLE_NLS */
151
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
152
#include <X11/Xlibint.h>
153
1 by Karl Ramm
Import upstream version 3.34
154
#include <X11/Xatom.h>
155
#include <X11/Intrinsic.h>
156
#include <X11/StringDefs.h>
157
#include <X11/Shell.h>
158
#include <X11/Xos.h>
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
159
#include <time.h>
160
#include <sys/time.h>
1 by Karl Ramm
Import upstream version 3.34
161
#include <netdb.h>	/* for gethostbyname() */
1.1.4 by Oliver Grawert
Import upstream version 5.04
162
#include <sys/types.h>
163
#include <pwd.h>
1 by Karl Ramm
Import upstream version 3.34
164
#ifdef HAVE_XMU
165
# ifndef VMS
166
#  include <X11/Xmu/Error.h>
167
# else  /* !VMS */
168
#  include <Xmu/Error.h>
169
# endif /* !VMS */
170
#else  /* !HAVE_XMU */
171
# include "xmu.h"
172
#endif /* !HAVE_XMU */
173
1.1.6 by Ted Gould
Import upstream version 5.07
174
#ifdef HAVE_MIT_SAVER_EXTENSION
175
#include <X11/extensions/scrnsaver.h>
176
#endif /* HAVE_MIT_SAVER_EXTENSION */
177
1 by Karl Ramm
Import upstream version 3.34
178
#ifdef HAVE_XIDLE_EXTENSION
179
# include <X11/extensions/xidle.h>
180
#endif /* HAVE_XIDLE_EXTENSION */
181
1.1.6 by Ted Gould
Import upstream version 5.07
182
#ifdef HAVE_SGI_VC_EXTENSION
183
# include <X11/extensions/XSGIvc.h>
184
#endif /* HAVE_SGI_VC_EXTENSION */
185
186
#ifdef HAVE_READ_DISPLAY_EXTENSION
187
# include <X11/extensions/readdisplay.h>
188
#endif /* HAVE_READ_DISPLAY_EXTENSION */
189
190
#ifdef HAVE_XSHM_EXTENSION
191
# include <X11/extensions/XShm.h>
192
#endif /* HAVE_XSHM_EXTENSION */
193
194
#ifdef HAVE_DPMS_EXTENSION
195
# include <X11/extensions/dpms.h>
196
#endif /* HAVE_DPMS_EXTENSION */
197
198
199
#ifdef HAVE_DOUBLE_BUFFER_EXTENSION
200
# include <X11/extensions/Xdbe.h>
201
#endif /* HAVE_DOUBLE_BUFFER_EXTENSION */
202
203
#ifdef HAVE_XF86VMODE
204
# include <X11/extensions/xf86vmode.h>
205
#endif /* HAVE_XF86VMODE */
206
207
#ifdef HAVE_XF86MISCSETGRABKEYSSTATE
208
# include <X11/extensions/xf86misc.h>
209
#endif /* HAVE_XF86MISCSETGRABKEYSSTATE */
210
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
211
#ifdef HAVE_XINERAMA
212
# include <X11/extensions/Xinerama.h>
213
#endif /* HAVE_XINERAMA */
214
1.1.6 by Ted Gould
Import upstream version 5.07
215
#ifdef HAVE_RANDR
216
# include <X11/extensions/Xrandr.h>
217
#endif /* HAVE_RANDR */
218
219
1 by Karl Ramm
Import upstream version 3.34
220
#include "xscreensaver.h"
221
#include "version.h"
222
#include "yarandom.h"
223
#include "resources.h"
224
#include "visual.h"
225
#include "usleep.h"
1.1.4 by Oliver Grawert
Import upstream version 5.04
226
#include "auth.h"
1 by Karl Ramm
Import upstream version 3.34
227
228
saver_info *global_si_kludge = 0;	/* I hate C so much... */
229
230
char *progname = 0;
231
char *progclass = 0;
232
XrmDatabase db = 0;
233
234
235
static Atom XA_SCREENSAVER_RESPONSE;
236
static Atom XA_ACTIVATE, XA_DEACTIVATE, XA_CYCLE, XA_NEXT, XA_PREV;
237
static Atom XA_RESTART, XA_SELECT;
238
static Atom XA_THROTTLE, XA_UNTHROTTLE;
239
Atom XA_DEMO, XA_PREFS, XA_EXIT, XA_LOCK, XA_BLANK;
240
241

242
static XrmOptionDescRec options [] = {
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
243
244
  { "-verbose",		   ".verbose",		XrmoptionNoArg, "on" },
245
  { "-silent",		   ".verbose",		XrmoptionNoArg, "off" },
246
247
  /* xscreensaver-demo uses this one */
248
  { "-nosplash",	   ".splash",		XrmoptionNoArg, "off" },
249
  { "-no-splash",	   ".splash",		XrmoptionNoArg, "off" },
250
251
  /* useful for debugging */
252
  { "-no-capture-stderr",  ".captureStderr",	XrmoptionNoArg, "off" },
1.1.6 by Ted Gould
Import upstream version 5.07
253
  { "-log",		   ".logFile",		XrmoptionSepArg, 0 },
1 by Karl Ramm
Import upstream version 3.34
254
};
255
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
256
#ifdef __GNUC__
257
 __extension__     /* shut up about "string length is greater than the length
258
                      ISO C89 compilers are required to support" when including
259
                      the .ad file... */
260
#endif
261
1 by Karl Ramm
Import upstream version 3.34
262
static char *defaults[] = {
263
#include "XScreenSaver_ad.h"
264
 0
265
};
266
267
#ifdef _VROOT_H_
268
ERROR!  You must not include vroot.h in this file.
269
#endif
270
271
static void
272
do_help (saver_info *si)
273
{
274
  fflush (stdout);
275
  fflush (stderr);
276
  fprintf (stdout, "\
1.1.5 by Ted Gould
Import upstream version 5.05
277
xscreensaver %s, copyright (c) 1991-2008 by Jamie Zawinski <jwz@jwz.org>\n\
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
278
\n\
279
  All xscreensaver configuration is via the `~/.xscreensaver' file.\n\
280
  Rather than editing that file by hand, just run `xscreensaver-demo':\n\
281
  that program lets you configure the screen saver graphically,\n\
282
  including timeouts, locking, and display modes.\n\
283
\n",
284
	  si->version);
285
  fprintf (stdout, "\
286
  Just getting started?  Try this:\n\
1 by Karl Ramm
Import upstream version 3.34
287
\n\
288
        xscreensaver &\n\
289
        xscreensaver-demo\n\
290
\n\
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
291
  For updates, online manual, and FAQ, please see the web page:\n\
292
\n\
293
       http://www.jwz.org/xscreensaver/\n\
294
\n");
295
1 by Karl Ramm
Import upstream version 3.34
296
  fflush (stdout);
297
  fflush (stderr);
298
  exit (1);
299
}
300
301
302
char *
303
timestring (void)
304
{
305
  time_t now = time ((time_t *) 0);
306
  char *str = (char *) ctime (&now);
307
  char *nl = (char *) strchr (str, '\n');
308
  if (nl) *nl = 0; /* take off that dang newline */
309
  return str;
310
}
311
1.1.6 by Ted Gould
Import upstream version 5.07
312
static Bool blurb_timestamp_p = True;   /* kludge */
1 by Karl Ramm
Import upstream version 3.34
313
314
const char *
315
blurb (void)
316
{
317
  if (!blurb_timestamp_p)
318
    return progname;
319
  else
320
    {
321
      static char buf[255];
322
      char *ct = timestring();
323
      int n = strlen(progname);
324
      if (n > 100) n = 99;
325
      strncpy(buf, progname, n);
326
      buf[n++] = ':';
327
      buf[n++] = ' ';
328
      strncpy(buf+n, ct+11, 8);
329
      strcpy(buf+n+9, ": ");
330
      return buf;
331
    }
332
}
333
334
335
int
336
saver_ehandler (Display *dpy, XErrorEvent *error)
337
{
338
  saver_info *si = global_si_kludge;	/* I hate C so much... */
339
  int i;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
340
  Bool fatal_p;
1 by Karl Ramm
Import upstream version 3.34
341
342
  if (!real_stderr) real_stderr = stderr;
343
344
  fprintf (real_stderr, "\n"
345
	   "#######################################"
346
	   "#######################################\n\n"
347
	   "%s: X Error!  PLEASE REPORT THIS BUG.\n",
348
	   blurb());
349
350
  for (i = 0; i < si->nscreens; i++)
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
351
    {
352
      saver_screen_info *ssi = &si->screens[i];
353
      fprintf (real_stderr, "%s: screen %d/%d: 0x%x, 0x%x, 0x%x\n",
354
               blurb(), ssi->real_screen_number, ssi->number,
355
               (unsigned int) RootWindowOfScreen (si->screens[i].screen),
356
               (unsigned int) si->screens[i].real_vroot,
357
               (unsigned int) si->screens[i].screensaver_window);
358
    }
1 by Karl Ramm
Import upstream version 3.34
359
360
  fprintf (real_stderr, "\n"
361
	   "#######################################"
362
	   "#######################################\n\n");
363
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
364
  fatal_p = XmuPrintDefaultErrorMessage (dpy, error, real_stderr);
365
366
  fatal_p = True;  /* The only time I've ever seen a supposedly nonfatal error,
367
                      it has been BadImplementation / Xlib sequence lost, which
368
                      are in truth pretty damned fatal.
369
                    */
370
371
  fprintf (real_stderr, "\n");
372
373
  if (! fatal_p)
374
    fprintf (real_stderr, "%s: nonfatal error.\n\n", blurb());
375
  else
1 by Karl Ramm
Import upstream version 3.34
376
    {
377
      if (si->prefs.xsync_p)
378
	{
379
	  saver_exit (si, -1, "because of synchronous X Error");
380
	}
381
      else
382
	{
1.1.6 by Ted Gould
Import upstream version 5.07
383
#ifdef __GNUC__
384
  __extension__   /* don't warn about "string length is greater than the
385
                     length ISO C89 compilers are required to support". */
386
#endif
387
          fprintf (real_stderr,
388
   "#######################################################################\n"
389
   "\n"
1 by Karl Ramm
Import upstream version 3.34
390
   "    If at all possible, please re-run xscreensaver with the command\n"
1.1.6 by Ted Gould
Import upstream version 5.07
391
   "    line arguments `-sync -verbose -log log.txt', and reproduce this\n"
1 by Karl Ramm
Import upstream version 3.34
392
   "    bug.  That will cause xscreensaver to dump a `core' file to the\n"
393
   "    current directory.  Please include the stack trace from that core\n"
1.1.6 by Ted Gould
Import upstream version 5.07
394
   "    file in your bug report.  *DO NOT* mail the core file itself!  That\n"
395
   "    won't work.  A \"log.txt\" file will also be written.  Please *do*\n"
396
   "    include the complete \"log.txt\" file with your bug report.\n"
1 by Karl Ramm
Import upstream version 3.34
397
   "\n"
398
   "    http://www.jwz.org/xscreensaver/bugs.html explains how to create\n"
399
   "    the most useful bug reports, and how to examine core files.\n"
400
   "\n"
401
   "    The more information you can provide, the better.  But please\n"
402
   "    report this bug, regardless!\n"
1.1.6 by Ted Gould
Import upstream version 5.07
403
   "\n"
404
   "#######################################################################\n"
405
   "\n"
1 by Karl Ramm
Import upstream version 3.34
406
   "\n");
407
408
	  saver_exit (si, -1, 0);
409
	}
410
    }
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
411
1 by Karl Ramm
Import upstream version 3.34
412
  return 0;
413
}
414
415
416
/* This error handler is used only while the X connection is being set up;
417
   after we've got a connection, we don't use this handler again.  The only
418
   reason for having this is so that we can present a more idiot-proof error
419
   message than "cannot open display."
420
 */
421
static void 
422
startup_ehandler (String name, String type, String class,
423
                  String defalt,  /* one can't even spel properly
424
                                     in this joke of a language */
425
                  String *av, Cardinal *ac)
426
{
427
  char fmt[512];
428
  String p[10];
429
  saver_info *si = global_si_kludge;	/* I hate C so much... */
430
  XrmDatabase *db = XtAppGetErrorDatabase(si->app);
431
  *fmt = 0;
432
  XtAppGetErrorDatabaseText(si->app, name, type, class, defalt,
433
                            fmt, sizeof(fmt)-1, *db);
434
435
  fprintf (stderr, "%s: ", blurb());
436
437
  memset (p, 0, sizeof(p));
438
  if (*ac > countof (p)) *ac = countof (p);
439
  memcpy ((char *) p, (char *) av, (*ac) * sizeof(*av));
440
  fprintf (stderr, fmt,		/* Did I mention that I hate C? */
441
           p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9]);
442
  fprintf (stderr, "\n");
443
444
  describe_uids (si, stderr);
445
446
  if (si->orig_uid && !strncmp (si->orig_uid, "root/", 5))
447
    {
448
      fprintf (stderr, "\n"
449
          "%s: This is probably because you're logging in as root.  You\n"
450
"              shouldn't log in as root: you should log in as a normal user,\n"
451
"              and then `su' as needed.  If you insist on logging in as\n"
452
"              root, you will have to turn off X's security features before\n"
453
"              xscreensaver will work.\n"
454
               "\n"
455
"              Please read the manual and FAQ for more information:\n",
456
               blurb());
457
    }
458
  else
459
    {
460
      fprintf (stderr, "\n"
461
          "%s: Errors at startup are usually authorization problems.\n"
462
"              But you're not logging in as root (good!) so something\n"
463
"              else must be wrong.  Did you read the manual and the FAQ?\n",
464
           blurb());
465
    }
466
467
  fprintf (stderr, "\n"
468
          "              http://www.jwz.org/xscreensaver/faq.html\n"
469
          "              http://www.jwz.org/xscreensaver/man.html\n"
470
          "\n");
471
472
  fflush (stderr);
473
  fflush (stdout);
474
  exit (1);
475
}
476
477

478
/* The zillions of initializations.
479
 */
480
481
/* Set progname, version, etc.  This is done very early.
482
 */
483
static void
484
set_version_string (saver_info *si, int *argc, char **argv)
485
{
486
  progclass = "XScreenSaver";
487
488
  /* progname is reset later, after we connect to X. */
489
  progname = strrchr(argv[0], '/');
490
  if (progname) progname++;
491
  else progname = argv[0];
492
493
  if (strlen(progname) > 100)	/* keep it short. */
494
    progname[99] = 0;
495
496
  /* The X resource database blows up if argv[0] has a "." in it. */
497
  {
498
    char *s = argv[0];
499
    while ((s = strchr (s, '.')))
500
      *s = '_';
501
  }
502
503
  si->version = (char *) malloc (5);
504
  memcpy (si->version, screensaver_id + 17, 4);
505
  si->version [4] = 0;
506
}
507
508
509
/* Initializations that potentially take place as a priveleged user:
510
   If the xscreensaver executable is setuid root, then these initializations
511
   are run as root, before discarding privileges.
512
 */
513
static void
514
privileged_initialization (saver_info *si, int *argc, char **argv)
515
{
516
#ifndef NO_LOCKING
517
  /* before hack_uid() for proper permissions */
518
  lock_priv_init (*argc, argv, si->prefs.verbose_p);
519
#endif /* NO_LOCKING */
520
521
  hack_uid (si);
522
}
523
524
525
/* Figure out what locking mechanisms are supported.
526
 */
527
static void
528
lock_initialization (saver_info *si, int *argc, char **argv)
529
{
530
#ifdef NO_LOCKING
531
  si->locking_disabled_p = True;
532
  si->nolock_reason = "not compiled with locking support";
533
#else /* !NO_LOCKING */
534
535
  /* Finish initializing locking, now that we're out of privileged code. */
536
  if (! lock_init (*argc, argv, si->prefs.verbose_p))
537
    {
538
      si->locking_disabled_p = True;
539
      si->nolock_reason = "error getting password";
540
    }
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
541
542
  /* If locking is currently enabled, but the environment indicates that
543
     we have been launched as GDM's "Background" program, then disable
544
     locking just in case.
545
   */
546
  if (!si->locking_disabled_p && getenv ("RUNNING_UNDER_GDM"))
547
    {
548
      si->locking_disabled_p = True;
549
      si->nolock_reason = "running under GDM";
550
    }
551
552
  /* If the server is XDarwin (MacOS X) then disable locking.
553
     (X grabs only affect X programs, so you can use Command-Tab
554
     to bring any other Mac program to the front, e.g., Terminal.)
555
   */
556
  if (!si->locking_disabled_p)
557
    {
558
      int op = 0, event = 0, error = 0;
559
      Bool macos_p = False;
560
561
#ifdef __APPLE__
562
      /* Disable locking if *running* on Apple hardware, since we have no
563
         reliable way to determine whether the server is running on MacOS.
564
         Hopefully __APPLE__ means "MacOS" and not "Linux on Mac hardware"
565
         but I'm not really sure about that.
566
       */
567
      macos_p = True;
568
#endif
569
570
      if (!macos_p)
571
        /* This extension exists on the Apple X11 server, but not
572
           on earlier versions of the XDarwin server. */
573
        macos_p = XQueryExtension (si->dpy, "Apple-DRI", &op, &event, &error);
574
575
      if (macos_p)
576
        {
577
          si->locking_disabled_p = True;
578
          si->nolock_reason = "Cannot lock securely on MacOS X";
579
        }
580
    }
581
1.1.7 by Robert Ancell
Import upstream version 5.08
582
  if (si->prefs.debug_p)    /* But allow locking anyway in debug mode. */
583
    si->locking_disabled_p = False;
584
1 by Karl Ramm
Import upstream version 3.34
585
#endif /* NO_LOCKING */
586
}
587
588
589
/* Open the connection to the X server, and intern our Atoms.
590
 */
591
static Widget
592
connect_to_server (saver_info *si, int *argc, char **argv)
593
{
594
  Widget toplevel_shell;
595
596
#ifdef HAVE_PUTENV
597
  char *d = getenv ("DISPLAY");
598
  if (!d || !*d)
599
    {
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
600
      char *ndpy = strdup("DISPLAY=:0.0");
1 by Karl Ramm
Import upstream version 3.34
601
      /* if (si->prefs.verbose_p) */      /* sigh, too early to test this... */
602
        fprintf (stderr,
603
                 "%s: warning: $DISPLAY is not set: defaulting to \"%s\".\n",
604
                 blurb(), ndpy+8);
605
      if (putenv (ndpy))
606
        abort ();
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
607
      /* don't free (ndpy) -- some implementations of putenv (BSD 4.4,
608
         glibc 2.0) copy the argument, but some (libc4,5, glibc 2.1.2)
609
         do not.  So we must leak it (and/or the previous setting). Yay.
610
       */
1 by Karl Ramm
Import upstream version 3.34
611
    }
612
#endif /* HAVE_PUTENV */
613
614
  XSetErrorHandler (saver_ehandler);
615
616
  XtAppSetErrorMsgHandler (si->app, startup_ehandler);
617
  toplevel_shell = XtAppInitialize (&si->app, progclass,
618
				    options, XtNumber (options),
619
				    argc, argv, defaults, 0, 0);
620
  XtAppSetErrorMsgHandler (si->app, 0);
621
622
  si->dpy = XtDisplay (toplevel_shell);
623
  si->prefs.db = XtDatabase (si->dpy);
624
  XtGetApplicationNameAndClass (si->dpy, &progname, &progclass);
625
626
  if(strlen(progname) > 100)	/* keep it short. */
627
    progname [99] = 0;
628
629
  db = si->prefs.db;	/* resources.c needs this */
630
631
  XA_VROOT = XInternAtom (si->dpy, "__SWM_VROOT", False);
632
  XA_SCREENSAVER = XInternAtom (si->dpy, "SCREENSAVER", False);
633
  XA_SCREENSAVER_VERSION = XInternAtom (si->dpy, "_SCREENSAVER_VERSION",False);
634
  XA_SCREENSAVER_ID = XInternAtom (si->dpy, "_SCREENSAVER_ID", False);
635
  XA_SCREENSAVER_STATUS = XInternAtom (si->dpy, "_SCREENSAVER_STATUS", False);
636
  XA_SCREENSAVER_RESPONSE = XInternAtom (si->dpy, "_SCREENSAVER_RESPONSE",
637
					 False);
638
  XA_XSETROOT_ID = XInternAtom (si->dpy, "_XSETROOT_ID", False);
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
639
  XA_ESETROOT_PMAP_ID = XInternAtom (si->dpy, "ESETROOT_PMAP_ID", False);
640
  XA_XROOTPMAP_ID = XInternAtom (si->dpy, "_XROOTPMAP_ID", False);
1 by Karl Ramm
Import upstream version 3.34
641
  XA_ACTIVATE = XInternAtom (si->dpy, "ACTIVATE", False);
642
  XA_DEACTIVATE = XInternAtom (si->dpy, "DEACTIVATE", False);
643
  XA_RESTART = XInternAtom (si->dpy, "RESTART", False);
644
  XA_CYCLE = XInternAtom (si->dpy, "CYCLE", False);
645
  XA_NEXT = XInternAtom (si->dpy, "NEXT", False);
646
  XA_PREV = XInternAtom (si->dpy, "PREV", False);
647
  XA_SELECT = XInternAtom (si->dpy, "SELECT", False);
648
  XA_EXIT = XInternAtom (si->dpy, "EXIT", False);
649
  XA_DEMO = XInternAtom (si->dpy, "DEMO", False);
650
  XA_PREFS = XInternAtom (si->dpy, "PREFS", False);
651
  XA_LOCK = XInternAtom (si->dpy, "LOCK", False);
652
  XA_BLANK = XInternAtom (si->dpy, "BLANK", False);
653
  XA_THROTTLE = XInternAtom (si->dpy, "THROTTLE", False);
654
  XA_UNTHROTTLE = XInternAtom (si->dpy, "UNTHROTTLE", False);
655
656
  return toplevel_shell;
657
}
658
659
660
/* Handle the command-line arguments that were not handled for us by Xt.
661
   Issue an error message and exit if there are unknown options.
662
 */
663
static void
664
process_command_line (saver_info *si, int *argc, char **argv)
665
{
666
  int i;
667
  for (i = 1; i < *argc; i++)
668
    {
669
      if (!strcmp (argv[i], "-debug"))
670
	/* no resource for this one, out of paranoia. */
671
	si->prefs.debug_p = True;
672
673
      else if (!strcmp (argv[i], "-h") ||
674
	       !strcmp (argv[i], "-help") ||
675
	       !strcmp (argv[i], "--help"))
676
	do_help (si);
677
678
      else
679
	{
680
	  const char *s = argv[i];
681
	  fprintf (stderr, "%s: unknown option \"%s\".  Try \"-help\".\n",
682
		   blurb(), s);
683
684
	  if (s[0] == '-' && s[1] == '-') s++;
685
	  if (!strcmp (s, "-activate") ||
686
	      !strcmp (s, "-deactivate") ||
687
	      !strcmp (s, "-cycle") ||
688
	      !strcmp (s, "-next") ||
689
	      !strcmp (s, "-prev") ||
690
	      !strcmp (s, "-exit") ||
691
	      !strcmp (s, "-restart") ||
692
	      !strcmp (s, "-demo") ||
693
	      !strcmp (s, "-prefs") ||
694
	      !strcmp (s, "-preferences") ||
695
	      !strcmp (s, "-lock") ||
696
	      !strcmp (s, "-version") ||
697
	      !strcmp (s, "-time"))
698
	    {
699
700
	      if (!strcmp (s, "-demo") || !strcmp (s, "-prefs"))
701
		fprintf (stderr, "\n\
702
    Perhaps you meant to run the `xscreensaver-demo' program instead?\n");
703
	      else
704
		fprintf (stderr, "\n\
705
    However, `%s' is an option to the `xscreensaver-command' program.\n", s);
706
707
	      fprintf (stderr, "\
708
    The `xscreensaver' program is a daemon that runs in the background.\n\
709
    You control a running xscreensaver process by sending it messages\n\
710
    with `xscreensaver-demo' or `xscreensaver-command'.\n\
711
.   See the man pages for details, or check the web page:\n\
712
    http://www.jwz.org/xscreensaver/\n\n");
713
	    }
714
715
	  exit (1);
716
	}
717
    }
718
}
719
720
721
/* Print out the xscreensaver banner to the tty if applicable;
722
   Issue any other warnings that are called for at this point.
723
 */
724
static void
725
print_banner (saver_info *si)
726
{
727
  saver_preferences *p = &si->prefs;
728
729
  /* This resource gets set some time before the others, so that we know
730
     whether to print the banner (and so that the banner gets printed before
731
     any resource-database-related error messages.)
732
   */
1.1.4 by Oliver Grawert
Import upstream version 5.04
733
  p->verbose_p = (p->debug_p || 
734
                  get_boolean_resource (si->dpy, "verbose", "Boolean"));
1 by Karl Ramm
Import upstream version 3.34
735
736
  /* Ditto, for the locking_disabled_p message. */
1.1.4 by Oliver Grawert
Import upstream version 5.04
737
  p->lock_p = get_boolean_resource (si->dpy, "lock", "Boolean");
1 by Karl Ramm
Import upstream version 3.34
738
739
  if (p->verbose_p)
740
    fprintf (stderr,
1.1.5 by Ted Gould
Import upstream version 5.05
741
	     "%s %s, copyright (c) 1991-2008 "
1 by Karl Ramm
Import upstream version 3.34
742
	     "by Jamie Zawinski <jwz@jwz.org>.\n",
743
	     progname, si->version);
744
745
  if (p->debug_p)
746
    fprintf (stderr, "\n"
747
	     "%s: Warning: running in DEBUG MODE.  Be afraid.\n"
748
	     "\n"
749
	     "\tNote that in debug mode, the xscreensaver window will only\n"
750
	     "\tcover the left half of the screen.  (The idea is that you\n"
751
	     "\tcan still see debugging output in a shell, if you position\n"
752
	     "\tit on the right side of the screen.)\n"
753
	     "\n"
754
	     "\tDebug mode is NOT SECURE.  Do not run with -debug in\n"
755
	     "\tuntrusted environments.\n"
756
	     "\n",
757
	     blurb());
758
759
  if (p->verbose_p)
760
    {
761
      if (!si->uid_message || !*si->uid_message)
762
	describe_uids (si, stderr);
763
      else
764
	{
765
	  if (si->orig_uid && *si->orig_uid)
766
	    fprintf (stderr, "%s: initial effective uid/gid was %s.\n",
767
		     blurb(), si->orig_uid);
768
	  fprintf (stderr, "%s: %s\n", blurb(), si->uid_message);
769
	}
770
771
      fprintf (stderr, "%s: in process %lu.\n", blurb(),
772
	       (unsigned long) getpid());
773
    }
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
774
}
775
776
static void
777
print_lock_failure_banner (saver_info *si)
778
{
779
  saver_preferences *p = &si->prefs;
1 by Karl Ramm
Import upstream version 3.34
780
781
  /* If locking was not able to be initalized for some reason, explain why.
782
     (This has to be done after we've read the lock_p resource.)
783
   */
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
784
  if (si->locking_disabled_p)
1 by Karl Ramm
Import upstream version 3.34
785
    {
786
      p->lock_p = False;
787
      fprintf (stderr, "%s: locking is disabled (%s).\n", blurb(),
788
	       si->nolock_reason);
789
      if (strstr (si->nolock_reason, "passw"))
790
	fprintf (stderr, "%s: does xscreensaver need to be setuid?  "
791
		 "consult the manual.\n", blurb());
792
      else if (strstr (si->nolock_reason, "running as "))
793
	fprintf (stderr, 
794
		 "%s: locking only works when xscreensaver is launched\n"
795
		 "\t by a normal, non-privileged user (e.g., not \"root\".)\n"
796
		 "\t See the manual for details.\n",
797
		 blurb());
798
    }
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
799
1 by Karl Ramm
Import upstream version 3.34
800
}
801
802
1.1.6 by Ted Gould
Import upstream version 5.07
803
/* called from screens.c so that all the Xt crud is here. */
804
void
805
initialize_screen_root_widget (saver_screen_info *ssi)
806
{
807
  saver_info *si = ssi->global;
808
  if (ssi->toplevel_shell)
809
    XtDestroyWidget (ssi->toplevel_shell);
810
  ssi->toplevel_shell =
811
    XtVaAppCreateShell (progname, progclass, 
812
                        applicationShellWidgetClass,
813
                        si->dpy,
814
                        XtNscreen, ssi->screen,
815
                        XtNvisual, ssi->current_visual,
816
                        XtNdepth,  visual_depth (ssi->screen,
817
                                                 ssi->current_visual),
818
                        NULL);
819
}
1.1.5 by Ted Gould
Import upstream version 5.05
820
821
1 by Karl Ramm
Import upstream version 3.34
822
/* Examine all of the display's screens, and populate the `saver_screen_info'
823
   structures.  Make sure this is called after hack_environment() sets $PATH.
824
 */
825
static void
826
initialize_per_screen_info (saver_info *si, Widget toplevel_shell)
827
{
828
  int i;
829
1.1.6 by Ted Gould
Import upstream version 5.07
830
  update_screen_layout (si);
831
832
  /* Check to see whether fading is ever possible -- if any of the
833
     screens on the display has a PseudoColor visual, then fading can
834
     work (on at least some screens.)  If no screen has a PseudoColor
835
     visual, then don't bother ever trying to fade, because it will
836
     just cause a delay without causing any visible effect.
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
837
   */
1 by Karl Ramm
Import upstream version 3.34
838
  for (i = 0; i < si->nscreens; i++)
839
    {
840
      saver_screen_info *ssi = &si->screens[i];
1.1.6 by Ted Gould
Import upstream version 5.07
841
      if (has_writable_cells (ssi->screen, ssi->current_visual) ||
842
          get_visual (ssi->screen, "PseudoColor", True, False) ||
843
          get_visual (ssi->screen, "GrayScale", True, False))
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
844
        {
1.1.6 by Ted Gould
Import upstream version 5.07
845
          si->fading_possible_p = True;
846
          break;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
847
        }
1 by Karl Ramm
Import upstream version 3.34
848
    }
849
850
#ifdef HAVE_XF86VMODE_GAMMA
851
  si->fading_possible_p = True;  /* if we can gamma fade, go for it */
852
#endif
853
}
854
855
856
/* If any server extensions have been requested, try and initialize them.
857
   Issue warnings if requests can't be honored.
858
 */
859
static void
860
initialize_server_extensions (saver_info *si)
861
{
862
  saver_preferences *p = &si->prefs;
863
864
  Bool server_has_xidle_extension_p = False;
865
  Bool server_has_sgi_saver_extension_p = False;
866
  Bool server_has_mit_saver_extension_p = False;
867
  Bool system_has_proc_interrupts_p = False;
1.1.10 by Robert Ancell
Import upstream version 5.12
868
  Bool server_has_xinput_extension_p = False;
1 by Karl Ramm
Import upstream version 3.34
869
  const char *piwhy = 0;
870
871
  si->using_xidle_extension = p->use_xidle_extension;
872
  si->using_sgi_saver_extension = p->use_sgi_saver_extension;
873
  si->using_mit_saver_extension = p->use_mit_saver_extension;
874
  si->using_proc_interrupts = p->use_proc_interrupts;
1.1.10 by Robert Ancell
Import upstream version 5.12
875
  si->using_xinput_extension = p->use_xinput_extension;
1 by Karl Ramm
Import upstream version 3.34
876
877
#ifdef HAVE_XIDLE_EXTENSION
1.1.6 by Ted Gould
Import upstream version 5.07
878
  {
879
    int ev, er;
880
    server_has_xidle_extension_p = XidleQueryExtension (si->dpy, &ev, &er);
881
  }
1 by Karl Ramm
Import upstream version 3.34
882
#endif
883
#ifdef HAVE_SGI_SAVER_EXTENSION
1.1.6 by Ted Gould
Import upstream version 5.07
884
  server_has_sgi_saver_extension_p =
885
    XScreenSaverQueryExtension (si->dpy,
886
                                &si->sgi_saver_ext_event_number,
887
                                &si->sgi_saver_ext_error_number);
1 by Karl Ramm
Import upstream version 3.34
888
#endif
889
#ifdef HAVE_MIT_SAVER_EXTENSION
1.1.6 by Ted Gould
Import upstream version 5.07
890
  server_has_mit_saver_extension_p =
891
    XScreenSaverQueryExtension (si->dpy,
892
                                &si->mit_saver_ext_event_number,
893
                                &si->mit_saver_ext_error_number);
1 by Karl Ramm
Import upstream version 3.34
894
#endif
895
#ifdef HAVE_PROC_INTERRUPTS
896
  system_has_proc_interrupts_p = query_proc_interrupts_available (si, &piwhy);
897
#endif
898
1.1.10 by Robert Ancell
Import upstream version 5.12
899
#ifdef HAVE_XINPUT
900
  server_has_xinput_extension_p = query_xinput_extension (si);
901
#endif
902
1 by Karl Ramm
Import upstream version 3.34
903
  if (!server_has_xidle_extension_p)
904
    si->using_xidle_extension = False;
905
  else if (p->verbose_p)
906
    {
907
      if (si->using_xidle_extension)
908
	fprintf (stderr, "%s: using XIDLE extension.\n", blurb());
909
      else
910
	fprintf (stderr, "%s: not using server's XIDLE extension.\n", blurb());
911
    }
912
913
  if (!server_has_sgi_saver_extension_p)
914
    si->using_sgi_saver_extension = False;
915
  else if (p->verbose_p)
916
    {
917
      if (si->using_sgi_saver_extension)
918
	fprintf (stderr, "%s: using SGI SCREEN_SAVER extension.\n", blurb());
919
      else
920
	fprintf (stderr,
921
		 "%s: not using server's SGI SCREEN_SAVER extension.\n",
922
		 blurb());
923
    }
924
925
  if (!server_has_mit_saver_extension_p)
926
    si->using_mit_saver_extension = False;
927
  else if (p->verbose_p)
928
    {
929
      if (si->using_mit_saver_extension)
930
	fprintf (stderr, "%s: using lame MIT-SCREEN-SAVER extension.\n",
931
		 blurb());
932
      else
933
	fprintf (stderr,
934
		 "%s: not using server's lame MIT-SCREEN-SAVER extension.\n",
935
		 blurb());
936
    }
937
1.1.6 by Ted Gould
Import upstream version 5.07
938
#ifdef HAVE_RANDR
939
  if (XRRQueryExtension (si->dpy,
940
                         &si->randr_event_number, &si->randr_error_number))
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
941
    {
1.1.6 by Ted Gould
Import upstream version 5.07
942
      int nscreens = ScreenCount (si->dpy);  /* number of *real* screens */
943
      int i;
944
1.1.10 by Robert Ancell
Import upstream version 5.12
945
      si->using_randr_extension = TRUE;
946
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
947
      if (p->verbose_p)
1.1.6 by Ted Gould
Import upstream version 5.07
948
	fprintf (stderr, "%s: selecting RANDR events\n", blurb());
949
      for (i = 0; i < nscreens; i++)
950
#  ifdef RRScreenChangeNotifyMask                 /* randr.h 1.5, 2002/09/29 */
951
        XRRSelectInput (si->dpy, RootWindow (si->dpy, i),
952
                        RRScreenChangeNotifyMask);
953
#  else  /* !RRScreenChangeNotifyMask */          /* Xrandr.h 1.4, 2001/06/07 */
954
        XRRScreenChangeSelectInput (si->dpy, RootWindow (si->dpy, i), True);
955
#  endif /* !RRScreenChangeNotifyMask */
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
956
    }
1.1.6 by Ted Gould
Import upstream version 5.07
957
# endif /* HAVE_RANDR */
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
958
1.1.10 by Robert Ancell
Import upstream version 5.12
959
#ifdef HAVE_XINPUT
960
  if (!server_has_xinput_extension_p)
961
    si->using_xinput_extension = False;
962
  else
963
    {
964
      if (si->using_xinput_extension)
965
        init_xinput_extension(si);
966
967
      if (p->verbose_p)
968
        {
969
          if (si->using_xinput_extension)
970
            fprintf (stderr,
971
                     "%s: selecting events from %d XInputExtension devices.\n",
972
                     blurb(), si->num_xinput_devices);
973
          else
974
            fprintf (stderr,
975
                     "%s: not using XInputExtension.\n",
976
                     blurb());
977
        }
978
    }
979
#endif
980
1 by Karl Ramm
Import upstream version 3.34
981
  if (!system_has_proc_interrupts_p)
982
    {
983
      si->using_proc_interrupts = False;
984
      if (p->verbose_p && piwhy)
985
	fprintf (stderr, "%s: not using /proc/interrupts: %s.\n", blurb(),
986
                 piwhy);
987
    }
988
  else if (p->verbose_p)
989
    {
990
      if (si->using_proc_interrupts)
991
	fprintf (stderr,
992
                 "%s: consulting /proc/interrupts for keyboard activity.\n",
993
		 blurb());
994
      else
995
	fprintf (stderr,
996
                "%s: not consulting /proc/interrupts for keyboard activity.\n",
997
		 blurb());
998
    }
999
}
1000
1001
1.1.6 by Ted Gould
Import upstream version 5.07
1002
#ifdef DEBUG_MULTISCREEN
1003
static void
1004
debug_multiscreen_timer (XtPointer closure, XtIntervalId *id)
1005
{
1006
  saver_info *si = (saver_info *) closure;
1007
  saver_preferences *p = &si->prefs;
1008
  if (update_screen_layout (si))
1009
    {
1010
      if (p->verbose_p)
1011
        {
1012
          fprintf (stderr, "%s: new layout:\n", blurb());
1013
          describe_monitor_layout (si);
1014
        }
1015
      resize_screensaver_window (si);
1016
    }
1017
  XtAppAddTimeOut (si->app, 1000*4, debug_multiscreen_timer, (XtPointer) si);
1018
}
1019
#endif /* DEBUG_MULTISCREEN */
1020
1021
1 by Karl Ramm
Import upstream version 3.34
1022
/* For the case where we aren't using an server extensions, select user events
1023
   on all the existing windows, and launch timers to select events on
1024
   newly-created windows as well.
1025
1026
   If a server extension is being used, this does nothing.
1027
 */
1028
static void
1029
select_events (saver_info *si)
1030
{
1031
  saver_preferences *p = &si->prefs;
1032
  int i;
1033
1034
  if (si->using_xidle_extension ||
1035
      si->using_mit_saver_extension ||
1036
      si->using_sgi_saver_extension)
1037
    return;
1038
1039
  if (p->initial_delay)
1040
    {
1041
      if (p->verbose_p)
1042
	{
1043
	  fprintf (stderr, "%s: waiting for %d second%s...", blurb(),
1044
		   (int) p->initial_delay/1000,
1045
		   (p->initial_delay == 1000 ? "" : "s"));
1046
	  fflush (stderr);
1047
	  fflush (stdout);
1048
	}
1049
      usleep (p->initial_delay);
1050
      if (p->verbose_p)
1051
	fprintf (stderr, " done.\n");
1052
    }
1053
1054
  if (p->verbose_p)
1055
    {
1056
      fprintf (stderr, "%s: selecting events on extant windows...", blurb());
1057
      fflush (stderr);
1058
      fflush (stdout);
1059
    }
1060
1061
  /* Select events on the root windows of every screen.  This also selects
1062
     for window creation events, so that new subwindows will be noticed.
1063
   */
1064
  for (i = 0; i < si->nscreens; i++)
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1065
    {
1066
      saver_screen_info *ssi = &si->screens[i];
1067
      if (ssi->real_screen_p)
1068
        start_notice_events_timer (si,
1069
           RootWindowOfScreen (si->screens[i].screen), False);
1070
    }
1 by Karl Ramm
Import upstream version 3.34
1071
1072
  if (p->verbose_p)
1073
    fprintf (stderr, " done.\n");
1.1.6 by Ted Gould
Import upstream version 5.07
1074
1075
# ifdef DEBUG_MULTISCREEN
1076
  if (p->debug_p) debug_multiscreen_timer ((XtPointer) si, 0);
1077
# endif
1 by Karl Ramm
Import upstream version 3.34
1078
}
1079
1080
1081
void
1082
maybe_reload_init_file (saver_info *si)
1083
{
1084
  saver_preferences *p = &si->prefs;
1085
  if (init_file_changed_p (p))
1086
    {
1087
      if (p->verbose_p)
1088
	fprintf (stderr, "%s: file \"%s\" has changed, reloading.\n",
1089
		 blurb(), init_file_name());
1090
1.1.4 by Oliver Grawert
Import upstream version 5.04
1091
      load_init_file (si->dpy, p);
1 by Karl Ramm
Import upstream version 3.34
1092
1093
      /* If a server extension is in use, and p->timeout has changed,
1094
	 we need to inform the server of the new timeout. */
1095
      disable_builtin_screensaver (si, False);
1096
1097
      /* If the DPMS settings in the init file have changed,
1098
         change the settings on the server to match. */
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1099
      sync_server_dpms_settings (si->dpy,
1100
                                 (p->dpms_enabled_p  &&
1101
                                  p->mode != DONT_BLANK),
1 by Karl Ramm
Import upstream version 3.34
1102
                                 p->dpms_standby / 1000,
1103
                                 p->dpms_suspend / 1000,
1104
                                 p->dpms_off / 1000,
1105
                                 False);
1106
    }
1107
}
1108
1109
1110
/* Loop forever:
1111
1112
       - wait until the user is idle;
1113
       - blank the screen;
1114
       - wait until the user is active;
1115
       - unblank the screen;
1116
       - repeat.
1117
1118
 */
1119
static void
1120
main_loop (saver_info *si)
1121
{
1122
  saver_preferences *p = &si->prefs;
1123
  Bool ok_to_unblank;
1.1.6 by Ted Gould
Import upstream version 5.07
1124
  int i;
1 by Karl Ramm
Import upstream version 3.34
1125
1126
  while (1)
1127
    {
1128
      Bool was_locked = False;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1129
1130
      if (p->verbose_p)
1131
	fprintf (stderr, "%s: awaiting idleness.\n", blurb());
1132
1133
      check_for_leaks ("unblanked A");
1 by Karl Ramm
Import upstream version 3.34
1134
      sleep_until_idle (si, True);
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1135
      check_for_leaks ("unblanked B");
1 by Karl Ramm
Import upstream version 3.34
1136
1137
      if (p->verbose_p)
1138
	{
1139
	  if (si->demoing_p)
1140
	    fprintf (stderr, "%s: demoing %d at %s.\n", blurb(),
1141
		     si->selection_mode, timestring());
1142
	  else
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1143
            fprintf (stderr, "%s: blanking screen at %s.\n", blurb(),
1144
                     timestring());
1 by Karl Ramm
Import upstream version 3.34
1145
	}
1146
1147
      maybe_reload_init_file (si);
1148
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1149
      if (p->mode == DONT_BLANK)
1150
        {
1151
          if (p->verbose_p)
1152
            fprintf (stderr, "%s: idle with blanking disabled at %s.\n",
1153
                     blurb(), timestring());
1154
1155
          /* Go around the loop and wait for the next bout of idleness,
1156
             or for the init file to change, or for a remote command to
1157
             come in, or something.
1158
1159
             But, if locked_p is true, go ahead.  This can only happen
1160
             if we're in "disabled" mode but a "lock" clientmessage came
1161
             in: in that case, we should go ahead and blank/lock the screen.
1162
           */
1163
          if (!si->locked_p)
1164
            continue;
1165
        }
1166
1167
      /* Since we're about to blank the screen, kill the de-race timer,
1168
         if any.  It might still be running if we have unblanked and then
1169
         re-blanked in a short period (e.g., when using the "next" button
1170
         in xscreensaver-demo.)
1171
       */
1172
      if (si->de_race_id)
1173
        {
1174
          if (p->verbose_p)
1175
            fprintf (stderr, "%s: stopping de-race timer (%d remaining.)\n",
1176
                     blurb(), si->de_race_ticks);
1177
          XtRemoveTimeOut (si->de_race_id);
1178
          si->de_race_id = 0;
1179
        }
1180
1181
1182
      /* Now, try to blank.
1183
       */
1184
1 by Karl Ramm
Import upstream version 3.34
1185
      if (! blank_screen (si))
1186
        {
1187
          /* We were unable to grab either the keyboard or mouse.
1188
             This means we did not (and must not) blank the screen.
1189
             If we were to blank the screen while some other program
1190
             is holding both the mouse and keyboard grabbed, then
1191
             we would never be able to un-blank it!  We would never
1192
             see any events, and the display would be wedged.
1193
1194
             So, just go around the loop again and wait for the
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1195
             next bout of idleness.  (If the user remains idle, we
1196
             will next try to blank the screen again in no more than
1197
             60 seconds.)
1 by Karl Ramm
Import upstream version 3.34
1198
          */
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1199
          Time retry = 60 * 1000;
1200
          if (p->timeout < retry)
1201
            retry = p->timeout;
1 by Karl Ramm
Import upstream version 3.34
1202
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1203
          if (p->debug_p)
1204
            {
1205
              fprintf (stderr,
1206
                  "%s: DEBUG MODE: unable to grab -- BLANKING ANYWAY.\n",
1207
                       blurb());
1208
            }
1209
          else
1210
            {
1211
              fprintf (stderr,
1 by Karl Ramm
Import upstream version 3.34
1212
                  "%s: unable to grab keyboard or mouse!  Blanking aborted.\n",
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1213
                       blurb());
1214
1215
              schedule_wakeup_event (si, retry, p->debug_p);
1216
              continue;
1217
            }
1 by Karl Ramm
Import upstream version 3.34
1218
        }
1219
1.1.6 by Ted Gould
Import upstream version 5.07
1220
      for (i = 0; i < si->nscreens; i++)
1221
        kill_screenhack (&si->screens[i]);
1 by Karl Ramm
Import upstream version 3.34
1222
1.1.6 by Ted Gould
Import upstream version 5.07
1223
      raise_window (si, True, True, False);
1224
      if (si->throttled_p)
1 by Karl Ramm
Import upstream version 3.34
1225
        fprintf (stderr, "%s: not launching hack (throttled.)\n", blurb());
1.1.6 by Ted Gould
Import upstream version 5.07
1226
      else
1227
        for (i = 0; i < si->nscreens; i++)
1228
          spawn_screenhack (&si->screens[i]);
1 by Karl Ramm
Import upstream version 3.34
1229
1.2.4 by Jose Luis Rivas
Import upstream version 5.14
1230
      /* If we are blanking only, optionally power down monitor right now.
1231
         To do this, we might need to temporarily re-enable DPMS first.
1232
       */
1233
      if (p->mode == BLANK_ONLY &&
1234
          p->dpms_enabled_p && 
1235
          p->dpms_quickoff_p)
1236
        {
1237
          sync_server_dpms_settings (si->dpy, True,
1238
                                     p->dpms_standby / 1000,
1239
                                     p->dpms_suspend / 1000,
1240
                                     (p->dpms_off
1241
                                      ? (p->dpms_off / 1000)
1242
                                      : 0xFFFF),
1243
                                     False);
1244
          monitor_power_on (si, False);
1245
        }
1.2.3 by Tormod Volden
Import upstream version 5.13
1246
1 by Karl Ramm
Import upstream version 3.34
1247
      /* Don't start the cycle timer in demo mode. */
1248
      if (!si->demoing_p && p->cycle)
1249
	si->cycle_id = XtAppAddTimeOut (si->app,
1250
                                        (si->selection_mode
1251
                                         /* see comment in cycle_timer() */
1252
                                         ? 1000 * 60 * 60
1253
                                         : p->cycle),
1254
                                        cycle_timer,
1255
					(XtPointer) si);
1256
1257
1258
#ifndef NO_LOCKING
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1259
      /* Maybe start locking the screen.
1260
       */
1 by Karl Ramm
Import upstream version 3.34
1261
      {
1262
        Time lock_timeout = p->lock_timeout;
1263
1264
        if (si->emergency_lock_p && p->lock_p && lock_timeout)
1265
          {
1266
            int secs = p->lock_timeout / 1000;
1267
            if (p->verbose_p)
1268
              fprintf (stderr,
1269
                     "%s: locking now, instead of waiting for %d:%02d:%02d.\n",
1270
                       blurb(),
1271
                       (secs / (60 * 60)), ((secs / 60) % 60), (secs % 60));
1272
            lock_timeout = 0;
1273
          }
1274
1275
        si->emergency_lock_p = False;
1276
1277
        if (!si->demoing_p &&           /* if not going into demo mode */
1278
            p->lock_p &&                /* and locking is enabled */
1279
            !si->locking_disabled_p &&  /* and locking is possible */
1280
            lock_timeout == 0)          /* and locking is not timer-deferred */
1281
          set_locked_p (si, True);      /* then lock right now. */
1282
1283
        /* locked_p might be true already because of the above, or because of
1284
           the LOCK ClientMessage.  But if not, and if we're supposed to lock
1285
           after some time, set up a timer to do so.
1286
        */
1287
        if (p->lock_p &&
1288
            !si->locked_p &&
1289
            lock_timeout > 0)
1290
          si->lock_id = XtAppAddTimeOut (si->app, lock_timeout,
1291
                                         activate_lock_timer,
1292
                                         (XtPointer) si);
1293
      }
1294
#endif /* !NO_LOCKING */
1295
1296
1297
      ok_to_unblank = True;
1298
      do {
1299
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1300
        check_for_leaks ("blanked A");
1 by Karl Ramm
Import upstream version 3.34
1301
	sleep_until_idle (si, False);		/* until not idle */
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1302
        check_for_leaks ("blanked B");
1303
1 by Karl Ramm
Import upstream version 3.34
1304
	maybe_reload_init_file (si);
1305
1306
#ifndef NO_LOCKING
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1307
        /* Maybe unlock the screen.
1308
         */
1 by Karl Ramm
Import upstream version 3.34
1309
	if (si->locked_p)
1310
	  {
1311
	    saver_screen_info *ssi = si->default_screen;
1312
	    if (si->locking_disabled_p) abort ();
1313
1314
            was_locked = True;
1315
	    si->dbox_up_p = True;
1.1.6 by Ted Gould
Import upstream version 5.07
1316
            for (i = 0; i < si->nscreens; i++)
1317
              suspend_screenhack (&si->screens[i], True);	  /* suspend */
1 by Karl Ramm
Import upstream version 3.34
1318
	    XUndefineCursor (si->dpy, ssi->screensaver_window);
1319
1320
	    ok_to_unblank = unlock_p (si);
1321
1322
	    si->dbox_up_p = False;
1323
	    XDefineCursor (si->dpy, ssi->screensaver_window, ssi->cursor);
1.1.6 by Ted Gould
Import upstream version 5.07
1324
            for (i = 0; i < si->nscreens; i++)
1325
              suspend_screenhack (&si->screens[i], False);	   /* resume */
1 by Karl Ramm
Import upstream version 3.34
1326
1327
            if (!ok_to_unblank &&
1328
                !screenhack_running_p (si))
1329
              {
1330
                /* If the lock dialog has been dismissed and we're not about to
1331
                   unlock the screen, and there is currently no hack running,
1332
                   then launch one.  (There might be no hack running if DPMS
1333
                   had kicked in.  But DPMS is off now, so bring back the hack)
1334
                 */
1335
                if (si->cycle_id)
1336
                  XtRemoveTimeOut (si->cycle_id);
1337
                si->cycle_id = 0;
1338
                cycle_timer ((XtPointer) si, 0);
1339
              }
1340
	  }
1341
#endif /* !NO_LOCKING */
1342
1343
	} while (!ok_to_unblank);
1344
1345
1346
      if (p->verbose_p)
1347
	fprintf (stderr, "%s: unblanking screen at %s.\n",
1348
		 blurb(), timestring ());
1349
1350
      /* Kill before unblanking, to stop drawing as soon as possible. */
1.1.6 by Ted Gould
Import upstream version 5.07
1351
      for (i = 0; i < si->nscreens; i++)
1352
        kill_screenhack (&si->screens[i]);
1 by Karl Ramm
Import upstream version 3.34
1353
      unblank_screen (si);
1354
1355
      set_locked_p (si, False);
1356
      si->emergency_lock_p = False;
1357
      si->demoing_p = 0;
1358
      si->selection_mode = 0;
1359
1360
      /* If we're throttled, and the user has explicitly unlocked the screen,
1361
         then unthrottle.  If we weren't locked, then don't unthrottle
1362
         automatically, because someone might have just bumped the desk... */
1363
      if (was_locked)
1364
        {
1365
          if (si->throttled_p && p->verbose_p)
1366
            fprintf (stderr, "%s: unthrottled.\n", blurb());
1367
          si->throttled_p = False;
1368
        }
1369
1370
      if (si->cycle_id)
1371
	{
1372
	  XtRemoveTimeOut (si->cycle_id);
1373
	  si->cycle_id = 0;
1374
	}
1375
1376
      if (si->lock_id)
1377
	{
1378
	  XtRemoveTimeOut (si->lock_id);
1379
	  si->lock_id = 0;
1380
	}
1381
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1382
      /* Since we're unblanked now, break race conditions and make
1383
         sure we stay that way (see comment in timers.c.) */
1384
      if (! si->de_race_id)
1385
        de_race_timer ((XtPointer) si, 0);
1 by Karl Ramm
Import upstream version 3.34
1386
    }
1387
}
1388
1389
static void analyze_display (saver_info *si);
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1390
static void fix_fds (void);
1 by Karl Ramm
Import upstream version 3.34
1391
1392
int
1393
main (int argc, char **argv)
1394
{
1395
  Widget shell;
1396
  saver_info the_si;
1397
  saver_info *si = &the_si;
1398
  saver_preferences *p = &si->prefs;
1.1.4 by Oliver Grawert
Import upstream version 5.04
1399
  struct passwd *spasswd;
1 by Karl Ramm
Import upstream version 3.34
1400
  int i;
1401
43 by Mathieu Trudel-Lapierre
* Merge with Debian testing, remaining Ubuntu changes:
1402
  /* It turns out that if we do setlocale (LC_ALL, "") here, people
1403
     running in Japanese locales get font craziness on the password
1404
     dialog, presumably because it is displaying Japanese characters
1405
     in a non-Japanese font.  However, if we don't call setlocale()
1406
     at all, then XLookupString() never returns multi-byte UTF-8
1407
     characters when people type non-Latin1 characters on the
1408
     keyboard.
1409
1410
     The current theory (and at this point, I'm really guessing!) is
1411
     that using LC_CTYPE instead of LC_ALL will make XLookupString()
1412
     behave usefully, without having the side-effect of screwing up
1413
     the fonts on the unlock dialog.
1414
1415
     See https://bugs.launchpad.net/ubuntu/+source/xscreensaver/+bug/671923
1416
     from comment #20 onward.
1417
1418
       -- jwz, 24-Sep-2011
1.2.3 by Tormod Volden
Import upstream version 5.13
1419
   */
1.1.10 by Robert Ancell
Import upstream version 5.12
1420
#ifdef ENABLE_NLS
43 by Mathieu Trudel-Lapierre
* Merge with Debian testing, remaining Ubuntu changes:
1421
  if (!setlocale (LC_CTYPE, ""))
1422
    fprintf (stderr, "%s: warning: could not set default locale\n",
1423
             progname);
1.1.10 by Robert Ancell
Import upstream version 5.12
1424
1425
  bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1426
  textdomain (GETTEXT_PACKAGE);
1427
#endif /* ENABLE_NLS */
1428
1 by Karl Ramm
Import upstream version 3.34
1429
  memset(si, 0, sizeof(*si));
1430
  global_si_kludge = si;	/* I hate C so much... */
1431
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1432
  fix_fds();
1433
1 by Karl Ramm
Import upstream version 3.34
1434
# undef ya_rand_init
1435
  ya_rand_init (0);
1436
1437
  save_argv (argc, argv);
1438
  set_version_string (si, &argc, argv);
1439
  privileged_initialization (si, &argc, argv);
1440
  hack_environment (si);
1441
1.1.4 by Oliver Grawert
Import upstream version 5.04
1442
  spasswd = getpwuid(getuid());
1443
  if (!spasswd)
1444
    {
1445
      fprintf(stderr, "Could not figure out who the current user is!\n");
1446
      return 1;
1447
    }
1448
1449
  si->user = strdup(spasswd->pw_name ? spasswd->pw_name : "(unknown)");
1450
1451
# ifndef NO_LOCKING
1452
  si->unlock_cb = gui_auth_conv;
1453
  si->auth_finished_cb = auth_finished_cb;
1454
# endif /* !NO_LOCKING */
1455
1 by Karl Ramm
Import upstream version 3.34
1456
  shell = connect_to_server (si, &argc, argv);
1457
  process_command_line (si, &argc, argv);
1.1.6 by Ted Gould
Import upstream version 5.07
1458
  stderr_log_file (si);
1 by Karl Ramm
Import upstream version 3.34
1459
  print_banner (si);
1460
1.1.4 by Oliver Grawert
Import upstream version 5.04
1461
  load_init_file(si->dpy, p); /* must be before initialize_per_screen_info() */
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1462
  blurb_timestamp_p = p->timestamp_p;  /* kludge */
1 by Karl Ramm
Import upstream version 3.34
1463
  initialize_per_screen_info (si, shell); /* also sets si->fading_possible_p */
1464
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1465
  /* We can only issue this warning now. */
1 by Karl Ramm
Import upstream version 3.34
1466
  if (p->verbose_p && !si->fading_possible_p && (p->fade_p || p->unfade_p))
1467
    fprintf (stderr,
1468
             "%s: there are no PseudoColor or GrayScale visuals.\n"
1469
             "%s: ignoring the request for fading/unfading.\n",
1470
             blurb(), blurb());
1471
1472
  for (i = 0; i < si->nscreens; i++)
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1473
    {
1474
      saver_screen_info *ssi = &si->screens[i];
1475
      if (ssi->real_screen_p)
1476
        if (ensure_no_screensaver_running (si->dpy, si->screens[i].screen))
1477
          exit (1);
1478
    }
1 by Karl Ramm
Import upstream version 3.34
1479
1480
  lock_initialization (si, &argc, argv);
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1481
  print_lock_failure_banner (si);
1 by Karl Ramm
Import upstream version 3.34
1482
1483
  if (p->xsync_p) XSynchronize (si->dpy, True);
1484
1485
  if (p->verbose_p) analyze_display (si);
1486
  initialize_server_extensions (si);
1487
1488
  si->blank_time = time ((time_t) 0); /* must be before ..._window */
1489
  initialize_screensaver_window (si);
1490
1491
  select_events (si);
1492
  init_sigchld ();
1493
1494
  disable_builtin_screensaver (si, True);
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1495
  sync_server_dpms_settings (si->dpy,
1496
                             (p->dpms_enabled_p  &&
1497
                              p->mode != DONT_BLANK),
1 by Karl Ramm
Import upstream version 3.34
1498
                             p->dpms_standby / 1000,
1499
                             p->dpms_suspend / 1000,
1500
                             p->dpms_off / 1000,
1501
                             False);
1502
1503
  initialize_stderr (si);
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1504
  handle_signals (si);
1 by Karl Ramm
Import upstream version 3.34
1505
1506
  make_splash_dialog (si);
1507
1508
  main_loop (si);		/* doesn't return */
1509
  return 0;
1510
}
1511
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1512
static void
1513
fix_fds (void)
1514
{
1515
  /* Bad Things Happen if stdin, stdout, and stderr have been closed
1516
     (as by the `sh incantation "xscreensaver >&- 2>&-").  When you do
1517
     that, the X connection gets allocated to one of these fds, and
1518
     then some random library writes to stderr, and random bits get
1519
     stuffed down the X pipe, causing "Xlib: sequence lost" errors.
1520
     So, we cause the first three file descriptors to be open to
1521
     /dev/null if they aren't open to something else already.  This
1522
     must be done before any other files are opened (or the closing
1523
     of that other file will again free up one of the "magic" first
1524
     three FDs.)
1525
1526
     We do this by opening /dev/null three times, and then closing
1527
     those fds, *unless* any of them got allocated as #0, #1, or #2,
1528
     in which case we leave them open.  Gag.
1529
1530
     Really, this crap is technically required of *every* X program,
1531
     if you want it to be robust in the face of "2>&-".
1532
   */
1533
  int fd0 = open ("/dev/null", O_RDWR);
1534
  int fd1 = open ("/dev/null", O_RDWR);
1535
  int fd2 = open ("/dev/null", O_RDWR);
1536
  if (fd0 > 2) close (fd0);
1537
  if (fd1 > 2) close (fd1);
1538
  if (fd2 > 2) close (fd2);
1539
}
1540
1541
1 by Karl Ramm
Import upstream version 3.34
1542

1543
/* Processing ClientMessage events.
1544
 */
1545
1546
1547
static Bool error_handler_hit_p = False;
1548
1549
static int
1550
ignore_all_errors_ehandler (Display *dpy, XErrorEvent *error)
1551
{
1552
  error_handler_hit_p = True;
1553
  return 0;
1554
}
1555
1556
/* Sometimes some systems send us ClientMessage events with bogus atoms in
1557
   them.  We only look up the atom names for printing warning messages,
1558
   so don't bomb out when it happens...
1559
 */
1560
static char *
1561
XGetAtomName_safe (Display *dpy, Atom atom)
1562
{
1563
  char *result;
1564
  XErrorHandler old_handler;
1565
  if (!atom) return 0;
1566
1567
  XSync (dpy, False);
1568
  error_handler_hit_p = False;
1569
  old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1570
  result = XGetAtomName (dpy, atom);
1571
  XSync (dpy, False);
1572
  XSetErrorHandler (old_handler);
1573
  XSync (dpy, False);
1574
  if (error_handler_hit_p) result = 0;
1575
1576
  if (result)
1577
    return result;
1578
  else
1579
    {
1580
      char buf[100];
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1581
      sprintf (buf, "<<undefined atom 0x%04X>>", (unsigned int) atom);
1 by Karl Ramm
Import upstream version 3.34
1582
      return strdup (buf);
1583
    }
1584
}
1585
1586
1587
static void
1588
clientmessage_response (saver_info *si, Window w, Bool error,
1589
			const char *stderr_msg,
1590
			const char *protocol_msg)
1591
{
1592
  char *proto;
1593
  int L;
1594
  saver_preferences *p = &si->prefs;
1595
  XErrorHandler old_handler;
1596
1597
  if (error || p->verbose_p)
1598
    fprintf (stderr, "%s: %s\n", blurb(), stderr_msg);
1599
1600
  L = strlen(protocol_msg);
1601
  proto = (char *) malloc (L + 2);
1602
  proto[0] = (error ? '-' : '+');
1603
  strcpy (proto+1, protocol_msg);
1604
  L++;
1605
1606
  /* Ignore all X errors while sending a response to a ClientMessage.
1607
     Pretty much the only way we could get an error here is if the
1608
     window we're trying to send the reply on has been deleted, in
1609
     which case, the sender of the ClientMessage won't see our response
1610
     anyway.
1611
   */
1612
  XSync (si->dpy, False);
1613
  error_handler_hit_p = False;
1614
  old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1615
1616
  XChangeProperty (si->dpy, w, XA_SCREENSAVER_RESPONSE, XA_STRING, 8,
1617
		   PropModeReplace, (unsigned char *) proto, L);
1618
1619
  XSync (si->dpy, False);
1620
  XSetErrorHandler (old_handler);
1621
  XSync (si->dpy, False);
1622
1623
  free (proto);
1624
}
1625
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1626
1627
static void
1628
bogus_clientmessage_warning (saver_info *si, XEvent *event)
1629
{
1.1.5 by Ted Gould
Import upstream version 5.05
1630
#if 0  /* Oh, fuck it.  GNOME likes to spew random ClientMessages at us
1631
          all the time.  This is presumably indicative of an error in
1632
          the sender of that ClientMessage: if we're getting it and 
1633
          ignoring it, then it's not reaching the intended recipient.
1634
          But people complain to me about this all the time ("waaah!
1635
          xscreensaver is printing to it's stderr and that gets my
1636
          panties all in a bunch!")  And I'm sick of hearing about it.
1637
          So we'll just ignore these messages and let GNOME go right
1638
          ahead and continue to stumble along in its malfunction.
1639
        */
1640
1.1.2 by Adam Conrad
Import upstream version 4.23
1641
  saver_preferences *p = &si->prefs;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1642
  char *str = XGetAtomName_safe (si->dpy, event->xclient.message_type);
1643
  Window w = event->xclient.window;
1644
  char wdesc[255];
1645
  int screen = 0;
1.1.2 by Adam Conrad
Import upstream version 4.23
1646
  Bool root_p = False;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1647
1648
  *wdesc = 0;
1649
  for (screen = 0; screen < si->nscreens; screen++)
1650
    if (w == si->screens[screen].screensaver_window)
1651
      {
1652
        strcpy (wdesc, "xscreensaver");
1653
        break;
1654
      }
1655
    else if (w == RootWindow (si->dpy, screen))
1656
      {
1657
        strcpy (wdesc, "root");
1.1.2 by Adam Conrad
Import upstream version 4.23
1658
        root_p = True;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1659
        break;
1660
      }
1661
1.1.2 by Adam Conrad
Import upstream version 4.23
1662
  /* If this ClientMessage was sent to the real root window instead of to the
1663
     xscreensaver window, then it might be intended for someone else who is
1664
     listening on the root window (e.g., the window manager).  So only print
1665
     the warning if: we are in debug mode; or if the bogus message was
1666
     actually sent to one of the xscreensaver-created windows.
1667
   */
1668
  if (root_p && !p->debug_p)
1669
    return;
1670
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1671
  if (!*wdesc)
1672
    {
1673
      XErrorHandler old_handler;
1674
      XClassHint hint;
1675
      XWindowAttributes xgwa;
1676
      memset (&hint, 0, sizeof(hint));
1677
      memset (&xgwa, 0, sizeof(xgwa));
1678
1679
      XSync (si->dpy, False);
1680
      old_handler = XSetErrorHandler (ignore_all_errors_ehandler);
1681
      XGetClassHint (si->dpy, w, &hint);
1682
      XGetWindowAttributes (si->dpy, w, &xgwa);
1683
      XSync (si->dpy, False);
1684
      XSetErrorHandler (old_handler);
1685
      XSync (si->dpy, False);
1686
1687
      screen = (xgwa.screen ? screen_number (xgwa.screen) : -1);
1688
1689
      sprintf (wdesc, "%.20s / %.20s",
1690
               (hint.res_name  ? hint.res_name  : "(null)"),
1691
               (hint.res_class ? hint.res_class : "(null)"));
1692
      if (hint.res_name)  XFree (hint.res_name);
1693
      if (hint.res_class) XFree (hint.res_class);
1694
    }
1695
1696
  fprintf (stderr, "%s: %d: unrecognised ClientMessage \"%s\" received\n",
1697
           blurb(), screen, (str ? str : "(null)"));
1698
  fprintf (stderr, "%s: %d: for window 0x%lx (%s)\n",
1699
           blurb(), screen, (unsigned long) w, wdesc);
1700
  if (str) XFree (str);
1.1.5 by Ted Gould
Import upstream version 5.05
1701
1702
#endif /* 0 */
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1703
}
1704
1.1.5 by Ted Gould
Import upstream version 5.05
1705
1 by Karl Ramm
Import upstream version 3.34
1706
Bool
1707
handle_clientmessage (saver_info *si, XEvent *event, Bool until_idle_p)
1708
{
1709
  saver_preferences *p = &si->prefs;
1710
  Atom type = 0;
1711
  Window window = event->xclient.window;
1712
1713
  /* Preferences might affect our handling of client messages. */
1714
  maybe_reload_init_file (si);
1715
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1716
  if (event->xclient.message_type != XA_SCREENSAVER ||
1717
      event->xclient.format != 32)
1718
    {
1719
      bogus_clientmessage_warning (si, event);
1 by Karl Ramm
Import upstream version 3.34
1720
      return False;
1721
    }
1722
1723
  type = event->xclient.data.l[0];
1724
  if (type == XA_ACTIVATE)
1725
    {
1726
      if (until_idle_p)
1727
	{
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1728
          if (p->mode == DONT_BLANK)
1729
            {
1730
              clientmessage_response(si, window, True,
1731
                         "ACTIVATE ClientMessage received in DONT_BLANK mode.",
1732
                                     "screen blanking is currently disabled.");
1733
              return False;
1734
            }
1735
1 by Karl Ramm
Import upstream version 3.34
1736
	  clientmessage_response(si, window, False,
1737
				 "ACTIVATE ClientMessage received.",
1738
				 "activating.");
1739
	  si->selection_mode = 0;
1740
	  si->demoing_p = False;
1741
1742
          if (si->throttled_p && p->verbose_p)
1743
            fprintf (stderr, "%s: unthrottled.\n", blurb());
1744
	  si->throttled_p = False;
1745
1746
	  if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1747
	    {
1748
	      XForceScreenSaver (si->dpy, ScreenSaverActive);
1749
	      return False;
1750
	    }
1751
	  else
1752
	    {
1753
	      return True;
1754
	    }
1755
	}
1756
      clientmessage_response(si, window, True,
1757
		       "ClientMessage ACTIVATE received while already active.",
1758
			     "already active.");
1759
    }
1760
  else if (type == XA_DEACTIVATE)
1761
    {
1762
      if (! until_idle_p)
1763
	{
1764
          if (si->throttled_p && p->verbose_p)
1765
            fprintf (stderr, "%s: unthrottled.\n", blurb());
1766
	  si->throttled_p = False;
1767
1768
	  clientmessage_response(si, window, False,
1769
				 "DEACTIVATE ClientMessage received.",
1770
				 "deactivating.");
1771
	  if (si->using_mit_saver_extension || si->using_sgi_saver_extension)
1772
	    {
1773
	      XForceScreenSaver (si->dpy, ScreenSaverReset);
1774
	      return False;
1775
	    }
1776
	  else
1777
	    {
1778
	      return True;
1779
	    }
1780
	}
1781
      clientmessage_response(si, window, False,
1782
     "ClientMessage DEACTIVATE received while inactive: resetting idle timer.",
1783
			     "not active: idle timer reset.");
1784
      reset_timers (si);
1785
    }
1786
  else if (type == XA_CYCLE)
1787
    {
1788
      if (! until_idle_p)
1789
	{
1790
	  clientmessage_response(si, window, False,
1791
				 "CYCLE ClientMessage received.",
1792
				 "cycling.");
1793
	  si->selection_mode = 0;	/* 0 means randomize when its time. */
1794
	  si->demoing_p = False;
1795
1796
          if (si->throttled_p && p->verbose_p)
1797
            fprintf (stderr, "%s: unthrottled.\n", blurb());
1798
	  si->throttled_p = False;
1799
1800
	  if (si->cycle_id)
1801
	    XtRemoveTimeOut (si->cycle_id);
1802
	  si->cycle_id = 0;
1803
	  cycle_timer ((XtPointer) si, 0);
1804
	  return False;
1805
	}
1806
      clientmessage_response(si, window, True,
1807
			     "ClientMessage CYCLE received while inactive.",
1808
			     "not active.");
1809
    }
1810
  else if (type == XA_NEXT || type == XA_PREV)
1811
    {
1812
      clientmessage_response(si, window, False,
1813
			     (type == XA_NEXT
1814
			      ? "NEXT ClientMessage received."
1815
			      : "PREV ClientMessage received."),
1816
			     "cycling.");
1817
      si->selection_mode = (type == XA_NEXT ? -1 : -2);
1818
      si->demoing_p = False;
1819
1820
      if (si->throttled_p && p->verbose_p)
1821
        fprintf (stderr, "%s: unthrottled.\n", blurb());
1822
      si->throttled_p = False;
1823
1824
      if (! until_idle_p)
1825
	{
1826
	  if (si->cycle_id)
1827
	    XtRemoveTimeOut (si->cycle_id);
1828
	  si->cycle_id = 0;
1829
	  cycle_timer ((XtPointer) si, 0);
1830
	}
1831
      else
1832
	return True;
1833
    }
1834
  else if (type == XA_SELECT)
1835
    {
1836
      char buf [255];
1837
      char buf2 [255];
1838
      long which = event->xclient.data.l[1];
1839
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1840
      if (p->mode == DONT_BLANK)
1841
        {
1842
          clientmessage_response(si, window, True,
1843
                           "SELECT ClientMessage received in DONT_BLANK mode.",
1844
                                 "screen blanking is currently disabled.");
1845
          return False;
1846
        }
1847
1 by Karl Ramm
Import upstream version 3.34
1848
      sprintf (buf, "SELECT %ld ClientMessage received.", which);
1849
      sprintf (buf2, "activating (%ld).", which);
1850
      clientmessage_response (si, window, False, buf, buf2);
1851
1852
      if (which < 0) which = 0;		/* 0 == "random" */
1853
      si->selection_mode = which;
1854
      si->demoing_p = False;
1855
1856
      if (si->throttled_p && p->verbose_p)
1857
        fprintf (stderr, "%s: unthrottled.\n", blurb());
1858
      si->throttled_p = False;
1859
1860
      if (! until_idle_p)
1861
	{
1862
	  if (si->cycle_id)
1863
	    XtRemoveTimeOut (si->cycle_id);
1864
	  si->cycle_id = 0;
1865
	  cycle_timer ((XtPointer) si, 0);
1866
	}
1867
      else
1868
	return True;
1869
    }
1870
  else if (type == XA_EXIT)
1871
    {
1872
      /* Ignore EXIT message if the screen is locked. */
1873
      if (until_idle_p || !si->locked_p)
1874
	{
1875
	  clientmessage_response (si, window, False,
1876
				  "EXIT ClientMessage received.",
1877
				  "exiting.");
1878
	  if (! until_idle_p)
1879
	    {
1.1.6 by Ted Gould
Import upstream version 5.07
1880
              int i;
1881
              for (i = 0; i < si->nscreens; i++)
1882
                kill_screenhack (&si->screens[i]);
1 by Karl Ramm
Import upstream version 3.34
1883
	      unblank_screen (si);
1884
	      XSync (si->dpy, False);
1885
	    }
1886
	  saver_exit (si, 0, 0);
1887
	}
1888
      else
1889
	clientmessage_response (si, window, True,
1890
				"EXIT ClientMessage received while locked.",
1891
				"screen is locked.");
1892
    }
1893
  else if (type == XA_RESTART)
1894
    {
1895
      /* The RESTART message works whether the screensaver is active or not,
1896
	 unless the screen is locked, in which case it doesn't work.
1897
       */
1898
      if (until_idle_p || !si->locked_p)
1899
	{
1900
	  clientmessage_response (si, window, False,
1901
				  "RESTART ClientMessage received.",
1902
				  "restarting.");
1903
	  if (! until_idle_p)
1904
	    {
1.1.6 by Ted Gould
Import upstream version 5.07
1905
              int i;
1906
              for (i = 0; i < si->nscreens; i++)
1907
                kill_screenhack (&si->screens[i]);
1 by Karl Ramm
Import upstream version 3.34
1908
	      unblank_screen (si);
1909
	      XSync (si->dpy, False);
1910
	    }
1911
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
1912
	  restart_process (si);  /* does not return */
1913
          abort();
1 by Karl Ramm
Import upstream version 3.34
1914
	}
1915
      else
1916
	clientmessage_response (si, window, True,
1917
				"RESTART ClientMessage received while locked.",
1918
				"screen is locked.");
1919
    }
1920
  else if (type == XA_DEMO)
1921
    {
1922
      long arg = event->xclient.data.l[1];
1.1.4 by Oliver Grawert
Import upstream version 5.04
1923
      Bool demo_one_hack_p = (arg == 5000);
1 by Karl Ramm
Import upstream version 3.34
1924
1925
      if (demo_one_hack_p)
1926
	{
1927
	  if (until_idle_p)
1928
	    {
1929
	      long which = event->xclient.data.l[2];
1930
	      char buf [255];
1931
	      char buf2 [255];
1932
	      sprintf (buf, "DEMO %ld ClientMessage received.", which);
1933
	      sprintf (buf2, "demoing (%ld).", which);
1934
	      clientmessage_response (si, window, False, buf, buf2);
1935
1936
	      if (which < 0) which = 0;		/* 0 == "random" */
1937
	      si->selection_mode = which;
1938
	      si->demoing_p = True;
1939
1940
              if (si->throttled_p && p->verbose_p)
1941
                fprintf (stderr, "%s: unthrottled.\n", blurb());
1942
              si->throttled_p = False;
1943
1944
	      return True;
1945
	    }
1946
1947
	  clientmessage_response (si, window, True,
1948
				  "DEMO ClientMessage received while active.",
1949
				  "already active.");
1950
	}
1951
      else
1952
	{
1953
	  clientmessage_response (si, window, True,
1954
				  "obsolete form of DEMO ClientMessage.",
1955
				  "obsolete form of DEMO ClientMessage.");
1956
	}
1957
    }
1958
  else if (type == XA_PREFS)
1959
    {
1960
      clientmessage_response (si, window, True,
1961
			      "the PREFS client-message is obsolete.",
1962
			      "the PREFS client-message is obsolete.");
1963
    }
1964
  else if (type == XA_LOCK)
1965
    {
1966
#ifdef NO_LOCKING
1967
      clientmessage_response (si, window, True,
1968
			      "not compiled with support for locking.",
1969
			      "locking not enabled.");
1970
#else /* !NO_LOCKING */
1971
      if (si->locking_disabled_p)
1972
	clientmessage_response (si, window, True,
1973
		      "LOCK ClientMessage received, but locking is disabled.",
1974
			      "locking not enabled.");
1975
      else if (si->locked_p)
1976
	clientmessage_response (si, window, True,
1977
			   "LOCK ClientMessage received while already locked.",
1978
				"already locked.");
1979
      else
1980
	{
1981
	  char buf [255];
1982
	  char *response = (until_idle_p
1983
			    ? "activating and locking."
1984
			    : "locking.");
1985
	  sprintf (buf, "LOCK ClientMessage received; %s", response);
1986
	  clientmessage_response (si, window, False, buf, response);
1987
	  set_locked_p (si, True);
1988
	  si->selection_mode = 0;
1989
	  si->demoing_p = False;
1990
1991
	  if (si->lock_id)	/* we're doing it now, so lose the timeout */
1992
	    {
1993
	      XtRemoveTimeOut (si->lock_id);
1994
	      si->lock_id = 0;
1995
	    }
1996
1997
	  if (until_idle_p)
1998
	    {
1999
	      if (si->using_mit_saver_extension ||
2000
                  si->using_sgi_saver_extension)
2001
		{
2002
		  XForceScreenSaver (si->dpy, ScreenSaverActive);
2003
		  return False;
2004
		}
2005
	      else
2006
		{
2007
		  return True;
2008
		}
2009
	    }
2010
	}
2011
#endif /* !NO_LOCKING */
2012
    }
2013
  else if (type == XA_THROTTLE)
2014
    {
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2015
      /* The THROTTLE command is deprecated -- it predates the XDPMS
2016
         extension.  Instead of using -throttle, users should instead
2017
         just power off the monitor (e.g., "xset dpms force off".)
2018
         In a few minutes, xscreensaver will notice that the monitor
2019
         is off, and cease running hacks.
2020
       */
1 by Karl Ramm
Import upstream version 3.34
2021
      if (si->throttled_p)
2022
	clientmessage_response (si, window, True,
2023
                                "THROTTLE ClientMessage received, but "
2024
                                "already throttled.",
2025
                                "already throttled.");
2026
      else
2027
	{
2028
	  char buf [255];
2029
	  char *response = "throttled.";
2030
	  si->throttled_p = True;
2031
	  si->selection_mode = 0;
2032
	  si->demoing_p = False;
2033
	  sprintf (buf, "THROTTLE ClientMessage received; %s", response);
2034
	  clientmessage_response (si, window, False, buf, response);
2035
2036
          if (! until_idle_p)
2037
            {
2038
              if (si->cycle_id)
2039
                XtRemoveTimeOut (si->cycle_id);
2040
              si->cycle_id = 0;
2041
              cycle_timer ((XtPointer) si, 0);
2042
            }
2043
	}
2044
    }
2045
  else if (type == XA_UNTHROTTLE)
2046
    {
2047
      if (! si->throttled_p)
2048
	clientmessage_response (si, window, True,
2049
                                "UNTHROTTLE ClientMessage received, but "
2050
                                "not throttled.",
2051
                                "not throttled.");
2052
      else
2053
	{
2054
	  char buf [255];
2055
	  char *response = "unthrottled.";
2056
	  si->throttled_p = False;
2057
	  si->selection_mode = 0;
2058
	  si->demoing_p = False;
2059
	  sprintf (buf, "UNTHROTTLE ClientMessage received; %s", response);
2060
	  clientmessage_response (si, window, False, buf, response);
2061
2062
          if (! until_idle_p)
2063
            {
2064
              if (si->cycle_id)
2065
                XtRemoveTimeOut (si->cycle_id);
2066
              si->cycle_id = 0;
2067
              cycle_timer ((XtPointer) si, 0);
2068
            }
2069
	}
2070
    }
2071
  else
2072
    {
2073
      char buf [1024];
2074
      char *str;
2075
      str = XGetAtomName_safe (si->dpy, type);
2076
2077
      if (str)
2078
	{
2079
	  if (strlen (str) > 80)
2080
	    strcpy (str+70, "...");
2081
	  sprintf (buf, "unrecognised screensaver ClientMessage %s received.",
2082
		   str);
2083
	  free (str);
2084
	}
2085
      else
2086
	{
2087
	  sprintf (buf,
2088
		   "unrecognised screensaver ClientMessage 0x%x received.",
2089
		   (unsigned int) event->xclient.data.l[0]);
2090
	}
2091
2092
      clientmessage_response (si, window, True, buf, buf);
2093
    }
2094
  return False;
2095
}
2096
2097

2098
/* Some random diagnostics printed in -verbose mode.
2099
 */
2100
2101
static void
2102
analyze_display (saver_info *si)
2103
{
2104
  int i, j;
2105
  static struct {
1.1.6 by Ted Gould
Import upstream version 5.07
2106
    const char *name; const char *desc; 
2107
    Bool useful_p;
2108
    Status (*version_fn) (Display *, int *majP, int *minP);
1 by Karl Ramm
Import upstream version 3.34
2109
  } exts[] = {
2110
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2111
   { "SCREEN_SAVER", /* underscore */           "SGI Screen-Saver",
1 by Karl Ramm
Import upstream version 3.34
2112
#     ifdef HAVE_SGI_SAVER_EXTENSION
1.1.6 by Ted Gould
Import upstream version 5.07
2113
        True,  0
1 by Karl Ramm
Import upstream version 3.34
2114
#     else
1.1.6 by Ted Gould
Import upstream version 5.07
2115
        False, 0
1 by Karl Ramm
Import upstream version 3.34
2116
#     endif
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2117
   }, { "SCREEN-SAVER", /* dash */              "SGI Screen-Saver",
1 by Karl Ramm
Import upstream version 3.34
2118
#     ifdef HAVE_SGI_SAVER_EXTENSION
1.1.6 by Ted Gould
Import upstream version 5.07
2119
        True,  0
1 by Karl Ramm
Import upstream version 3.34
2120
#     else
1.1.6 by Ted Gould
Import upstream version 5.07
2121
        False, 0
1 by Karl Ramm
Import upstream version 3.34
2122
#     endif
2123
   }, { "MIT-SCREEN-SAVER",                     "MIT Screen-Saver",
2124
#     ifdef HAVE_MIT_SAVER_EXTENSION
1.1.6 by Ted Gould
Import upstream version 5.07
2125
        True,  XScreenSaverQueryVersion
1 by Karl Ramm
Import upstream version 3.34
2126
#     else
1.1.6 by Ted Gould
Import upstream version 5.07
2127
        False, 0
1 by Karl Ramm
Import upstream version 3.34
2128
#     endif
2129
   }, { "XIDLE",                                "XIdle",           
2130
#     ifdef HAVE_XIDLE_EXTENSION
1.1.6 by Ted Gould
Import upstream version 5.07
2131
        True,  0
1 by Karl Ramm
Import upstream version 3.34
2132
#     else
1.1.6 by Ted Gould
Import upstream version 5.07
2133
        False, 0
1 by Karl Ramm
Import upstream version 3.34
2134
#     endif
2135
   }, { "SGI-VIDEO-CONTROL",                    "SGI Video-Control",
2136
#     ifdef HAVE_SGI_VC_EXTENSION
1.1.6 by Ted Gould
Import upstream version 5.07
2137
        True,  XSGIvcQueryVersion
1 by Karl Ramm
Import upstream version 3.34
2138
#     else
1.1.6 by Ted Gould
Import upstream version 5.07
2139
        False, 0
1 by Karl Ramm
Import upstream version 3.34
2140
#     endif
2141
   }, { "READDISPLAY",                          "SGI Read-Display",
2142
#     ifdef HAVE_READ_DISPLAY_EXTENSION
1.1.6 by Ted Gould
Import upstream version 5.07
2143
        True,  XReadDisplayQueryVersion
1 by Karl Ramm
Import upstream version 3.34
2144
#     else
1.1.6 by Ted Gould
Import upstream version 5.07
2145
        False, 0
1 by Karl Ramm
Import upstream version 3.34
2146
#     endif
2147
   }, { "MIT-SHM",                              "Shared Memory",   
2148
#     ifdef HAVE_XSHM_EXTENSION
1.1.6 by Ted Gould
Import upstream version 5.07
2149
        True, (Status (*) (Display*,int*,int*)) XShmQueryVersion /* 4 args */
1 by Karl Ramm
Import upstream version 3.34
2150
#     else
1.1.6 by Ted Gould
Import upstream version 5.07
2151
        False, 0
1 by Karl Ramm
Import upstream version 3.34
2152
#     endif
2153
   }, { "DOUBLE-BUFFER",                        "Double-Buffering",
2154
#     ifdef HAVE_DOUBLE_BUFFER_EXTENSION
1.1.6 by Ted Gould
Import upstream version 5.07
2155
        True, XdbeQueryExtension
1 by Karl Ramm
Import upstream version 3.34
2156
#     else
1.1.6 by Ted Gould
Import upstream version 5.07
2157
        False, 0
1 by Karl Ramm
Import upstream version 3.34
2158
#     endif
2159
   }, { "DPMS",                                 "Power Management",
2160
#     ifdef HAVE_DPMS_EXTENSION
1.1.6 by Ted Gould
Import upstream version 5.07
2161
        True,  DPMSGetVersion
1 by Karl Ramm
Import upstream version 3.34
2162
#     else
1.1.6 by Ted Gould
Import upstream version 5.07
2163
        False, 0
1 by Karl Ramm
Import upstream version 3.34
2164
#     endif
2165
   }, { "GLX",                                  "GLX",             
2166
#     ifdef HAVE_GL
1.1.6 by Ted Gould
Import upstream version 5.07
2167
        True,  0
1 by Karl Ramm
Import upstream version 3.34
2168
#     else
1.1.6 by Ted Gould
Import upstream version 5.07
2169
        False, 0
1 by Karl Ramm
Import upstream version 3.34
2170
#     endif
2171
   }, { "XFree86-VidModeExtension",             "XF86 Video-Mode", 
2172
#     ifdef HAVE_XF86VMODE
1.1.6 by Ted Gould
Import upstream version 5.07
2173
        True,  XF86VidModeQueryVersion
2174
#     else
2175
        False, 0
2176
#     endif
2177
   }, { "XC-VidModeExtension",                  "XC Video-Mode", 
2178
#     ifdef HAVE_XF86VMODE
2179
        True,  XF86VidModeQueryVersion
2180
#     else
2181
        False, 0
2182
#     endif
2183
   }, { "XFree86-MISC",                         "XF86 Misc", 
2184
#     ifdef HAVE_XF86MISCSETGRABKEYSSTATE
2185
        True,  XF86MiscQueryVersion
2186
#     else
2187
        False, 0
2188
#     endif
2189
   }, { "XC-MISC",                              "XC Misc", 
2190
#     ifdef HAVE_XF86MISCSETGRABKEYSSTATE
2191
        True,  XF86MiscQueryVersion
2192
#     else
2193
        False, 0
1 by Karl Ramm
Import upstream version 3.34
2194
#     endif
2195
   }, { "XINERAMA",                             "Xinerama",
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2196
#     ifdef HAVE_XINERAMA
1.1.6 by Ted Gould
Import upstream version 5.07
2197
        True,  XineramaQueryVersion
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2198
#     else
1.1.6 by Ted Gould
Import upstream version 5.07
2199
        False, 0
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2200
#     endif
2201
   }, { "RANDR",                                "Resize-and-Rotate",
2202
#     ifdef HAVE_RANDR
1.1.6 by Ted Gould
Import upstream version 5.07
2203
        True,  XRRQueryVersion
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2204
#     else
1.1.6 by Ted Gould
Import upstream version 5.07
2205
        False, 0
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2206
#     endif
1.1.6 by Ted Gould
Import upstream version 5.07
2207
   }, { "DRI",		                        "DRI",
2208
        True,  0
1.1.7 by Robert Ancell
Import upstream version 5.08
2209
   }, { "NV-CONTROL",                           "NVidia",
2210
        True,  0
2211
   }, { "NV-GLX",                               "NVidia GLX",
2212
        True,  0
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2213
   }, { "Apple-DRI",                            "Apple-DRI (XDarwin)",
1.1.6 by Ted Gould
Import upstream version 5.07
2214
        True,  0
1.1.10 by Robert Ancell
Import upstream version 5.12
2215
   }, { "XInputExtension",                      "XInput",
2216
        True,  0
1 by Karl Ramm
Import upstream version 3.34
2217
   },
2218
  };
2219
1.1.6 by Ted Gould
Import upstream version 5.07
2220
  fprintf (stderr, "%s: running on display \"%s\"\n", blurb(), 
2221
           DisplayString(si->dpy));
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2222
  fprintf (stderr, "%s: vendor is %s, %d.\n", blurb(),
1 by Karl Ramm
Import upstream version 3.34
2223
	   ServerVendor(si->dpy), VendorRelease(si->dpy));
2224
2225
  fprintf (stderr, "%s: useful extensions:\n", blurb());
2226
  for (i = 0; i < countof(exts); i++)
2227
    {
2228
      int op = 0, event = 0, error = 0;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2229
      char buf [255];
1.1.6 by Ted Gould
Import upstream version 5.07
2230
      int maj = 0, min = 0;
2231
      int dummy1, dummy2, dummy3;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2232
      int j;
1.1.6 by Ted Gould
Import upstream version 5.07
2233
2234
      /* Most of the extension version functions take 3 args,
2235
         writing results into args 2 and 3, but some take more.
2236
         We only ever care about the first two results, but we
2237
         pass in three extra pointers just in case.
2238
       */
2239
      Status (*version_fn_2) (Display*,int*,int*,int*,int*,int*) =
2240
        (Status (*) (Display*,int*,int*,int*,int*,int*)) exts[i].version_fn;
2241
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2242
      if (!XQueryExtension (si->dpy, exts[i].name, &op, &event, &error))
2243
        continue;
2244
      sprintf (buf, "%s:   ", blurb());
2245
      j = strlen (buf);
2246
      strcat (buf, exts[i].desc);
1.1.6 by Ted Gould
Import upstream version 5.07
2247
2248
      if (!version_fn_2)
2249
        ;
2250
      else if (version_fn_2 (si->dpy, &maj, &min, &dummy1, &dummy2, &dummy3))
2251
        sprintf (buf+strlen(buf), " (%d.%d)", maj, min);
2252
      else
2253
        strcat (buf, " (unavailable)");
2254
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2255
      if (!exts[i].useful_p)
1.1.5 by Ted Gould
Import upstream version 5.05
2256
        strcat (buf, " (disabled at compile time)");
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2257
      fprintf (stderr, "%s\n", buf);
1 by Karl Ramm
Import upstream version 3.34
2258
    }
2259
2260
  for (i = 0; i < si->nscreens; i++)
2261
    {
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2262
      saver_screen_info *ssi = &si->screens[i];
1 by Karl Ramm
Import upstream version 3.34
2263
      unsigned long colormapped_depths = 0;
2264
      unsigned long non_mapped_depths = 0;
2265
      XVisualInfo vi_in, *vi_out;
2266
      int out_count;
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2267
2268
      if (!ssi->real_screen_p) continue;
2269
2270
      vi_in.screen = ssi->real_screen_number;
1 by Karl Ramm
Import upstream version 3.34
2271
      vi_out = XGetVisualInfo (si->dpy, VisualScreenMask, &vi_in, &out_count);
2272
      if (!vi_out) continue;
2273
      for (j = 0; j < out_count; j++)
2274
	if (vi_out[j].class == PseudoColor)
2275
	  colormapped_depths |= (1 << vi_out[j].depth);
2276
	else
2277
	  non_mapped_depths  |= (1 << vi_out[j].depth);
2278
      XFree ((char *) vi_out);
2279
2280
      if (colormapped_depths)
2281
	{
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2282
	  fprintf (stderr, "%s: screen %d colormapped depths:", blurb(),
2283
                   ssi->real_screen_number);
1 by Karl Ramm
Import upstream version 3.34
2284
	  for (j = 0; j < 32; j++)
2285
	    if (colormapped_depths & (1 << j))
2286
	      fprintf (stderr, " %d", j);
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2287
	  fprintf (stderr, ".\n");
1 by Karl Ramm
Import upstream version 3.34
2288
	}
2289
      if (non_mapped_depths)
2290
	{
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2291
	  fprintf (stderr, "%s: screen %d non-colormapped depths:",
2292
                   blurb(), ssi->real_screen_number);
1 by Karl Ramm
Import upstream version 3.34
2293
	  for (j = 0; j < 32; j++)
2294
	    if (non_mapped_depths & (1 << j))
2295
	      fprintf (stderr, " %d", j);
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2296
	  fprintf (stderr, ".\n");
1 by Karl Ramm
Import upstream version 3.34
2297
	}
2298
    }
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2299
1.1.6 by Ted Gould
Import upstream version 5.07
2300
  describe_monitor_layout (si);
1 by Karl Ramm
Import upstream version 3.34
2301
}
2302
1.1.6 by Ted Gould
Import upstream version 5.07
2303
1 by Karl Ramm
Import upstream version 3.34
2304
Bool
2305
display_is_on_console_p (saver_info *si)
2306
{
2307
  Bool not_on_console = True;
2308
  char *dpystr = DisplayString (si->dpy);
2309
  char *tail = (char *) strchr (dpystr, ':');
2310
  if (! tail || strncmp (tail, ":0", 2))
2311
    not_on_console = True;
2312
  else
2313
    {
2314
      char dpyname[255], localname[255];
2315
      strncpy (dpyname, dpystr, tail-dpystr);
2316
      dpyname [tail-dpystr] = 0;
2317
      if (!*dpyname ||
2318
	  !strcmp(dpyname, "unix") ||
2319
	  !strcmp(dpyname, "localhost"))
2320
	not_on_console = False;
2321
      else if (gethostname (localname, sizeof (localname)))
2322
	not_on_console = True;  /* can't find hostname? */
1.1.5 by Ted Gould
Import upstream version 5.05
2323
      else if (!strncmp (dpyname, "/tmp/launch-", 12))  /* MacOS X launchd */
2324
	not_on_console = False;
1 by Karl Ramm
Import upstream version 3.34
2325
      else
2326
	{
2327
	  /* We have to call gethostbyname() on the result of gethostname()
2328
	     because the two aren't guarenteed to be the same name for the
2329
	     same host: on some losing systems, one is a FQDN and the other
2330
	     is not.  Here in the wide wonderful world of Unix it's rocket
2331
	     science to obtain the local hostname in a portable fashion.
2332
	     
2333
	     And don't forget, gethostbyname() reuses the structure it
2334
	     returns, so we have to copy the fucker before calling it again.
2335
	     Thank you master, may I have another.
2336
	   */
2337
	  struct hostent *h = gethostbyname (dpyname);
2338
	  if (!h)
2339
	    not_on_console = True;
2340
	  else
2341
	    {
2342
	      char hn [255];
2343
	      struct hostent *l;
2344
	      strcpy (hn, h->h_name);
2345
	      l = gethostbyname (localname);
2346
	      not_on_console = (!l || !!(strcmp (l->h_name, hn)));
2347
	    }
2348
	}
2349
    }
2350
  return !not_on_console;
2351
}
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2352
2353
2354
/* Do a little bit of heap introspection...
2355
 */
2356
void
2357
check_for_leaks (const char *where)
2358
{
2.1.1 by Ralf Hildebrandt
Patch by Joachim Breitner to check more frequently if DPMS kicked in (closes: #303374, #286664).
2359
#if defined(HAVE_SBRK) && defined(LEAK_PARANOIA)
1.1.1 by Ralf Hildebrandt
Import upstream version 4.21
2360
  static unsigned long last_brk = 0;
2361
  int b = (unsigned long) sbrk(0);
2362
  if (last_brk && last_brk < b)
2363
    fprintf (stderr, "%s: %s: brk grew by %luK.\n",
2364
             blurb(), where,
2365
             (((b - last_brk) + 1023) / 1024));
2366
  last_brk = b;
2367
#endif /* HAVE_SBRK */
2368
}