~ubuntu-branches/ubuntu/dapper/xscreensaver/dapper

« back to all changes in this revision

Viewing changes to driver/timers.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2005-10-11 21:00:42 UTC
  • mfrom: (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20051011210042-u7q6zslgevdxspr3
Tags: 4.21-4ubuntu17
updated pt_BR again, fixed to UTF-8 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* timers.c --- detecting when the user is idle, and other timer-related tasks.
2
 
 * xscreensaver, Copyright (c) 1991-1997, 1998
3
 
 *  Jamie Zawinski <jwz@jwz.org>
 
2
 * xscreensaver, Copyright (c) 1991-2004 Jamie Zawinski <jwz@jwz.org>
4
3
 *
5
4
 * Permission to use, copy, modify, distribute, and sell this software and its
6
5
 * documentation for any purpose is hereby granted without fee, provided that
15
14
# include "config.h"
16
15
#endif
17
16
 
18
 
/* #define DEBUG_TIMERS */
19
 
 
20
17
#include <stdio.h>
21
18
#include <X11/Xlib.h>
22
19
#include <X11/Intrinsic.h>
23
20
#include <X11/Xos.h>
 
21
#include <time.h>
 
22
#include <sys/time.h>
24
23
#ifdef HAVE_XMU
25
24
# ifndef VMS
26
25
#  include <X11/Xmu/Error.h>
43
42
#include <X11/extensions/XScreenSaver.h>
44
43
#endif /* HAVE_SGI_SAVER_EXTENSION */
45
44
 
 
45
#ifdef HAVE_RANDR
 
46
#include <X11/extensions/Xrandr.h>
 
47
#endif /* HAVE_RANDR */
 
48
 
46
49
#include "xscreensaver.h"
47
50
 
 
51
#undef ABS
 
52
#define ABS(x)((x)<0?-(x):(x))
 
53
 
 
54
#undef MAX
 
55
#define MAX(x,y)((x)>(y)?(x):(y))
 
56
 
 
57
 
48
58
#ifdef HAVE_PROC_INTERRUPTS
49
59
static Bool proc_interrupts_activity_p (saver_info *si);
50
60
#endif /* HAVE_PROC_INTERRUPTS */
73
83
  fake_event.xany.display = si->dpy;
74
84
  fake_event.xany.window  = 0;
75
85
  XPutBackEvent (si->dpy, &fake_event);
 
86
 
 
87
  /* If we are the timer that just went off, clear the pointer to the id. */
 
88
  if (id)
 
89
    {
 
90
      if (si->timer_id && *id != si->timer_id)
 
91
        abort();  /* oops, scheduled timer twice?? */
 
92
      si->timer_id = 0;
 
93
    }
76
94
}
77
95
 
78
96
 
79
 
static void
 
97
void
80
98
schedule_wakeup_event (saver_info *si, Time when, Bool verbose_p)
81
99
{
 
100
  if (si->timer_id)
 
101
    {
 
102
      if (verbose_p)
 
103
        fprintf (stderr, "%s: idle_timer already running\n", blurb());
 
104
      return;
 
105
    }
 
106
 
82
107
  /* Wake up periodically to ask the server if we are idle. */
83
108
  si->timer_id = XtAppAddTimeOut (si->app, when, idle_timer,
84
109
                                  (XtPointer) si);
85
110
 
86
 
#ifdef DEBUG_TIMERS
87
111
  if (verbose_p)
88
112
    fprintf (stderr, "%s: starting idle_timer (%ld, %ld)\n",
89
113
             blurb(), when, si->timer_id);
90
 
#endif /* DEBUG_TIMERS */
91
114
}
92
115
 
93
116
 
99
122
  unsigned long events;
100
123
  Window root, parent, *kids;
101
124
  unsigned int nkids;
 
125
  int screen_no;
102
126
 
103
127
  if (XtWindowToWidget (si->dpy, window))
104
128
    /* If it's one of ours, don't mess up its event mask. */
109
133
  if (window == root)
110
134
    top_p = False;
111
135
 
 
136
  /* Figure out which screen this window is on, for the diagnostics. */
 
137
  for (screen_no = 0; screen_no < si->nscreens; screen_no++)
 
138
    if (root == RootWindowOfScreen (si->screens[screen_no].screen))
 
139
      break;
 
140
 
112
141
  XGetWindowAttributes (si->dpy, window, &attrs);
113
142
  events = ((attrs.all_event_masks | attrs.do_not_propagate_mask)
114
143
            & KeyPressMask);
125
154
     the mouse or touching the keyboard, we won't know that they've been
126
155
     active, and the screensaver will come on.  That sucks, but I don't
127
156
     know how to get around it.
 
157
 
 
158
     Since X presents mouse wheels as clicks, this applies to those, too:
 
159
     scrolling through a document using only the mouse wheel doesn't
 
160
     count as activity...  Fortunately, /proc/interrupts helps, on
 
161
     systems that have it.  Oh, if it's a PS/2 mouse, not serial or USB.
 
162
     This sucks!
128
163
   */
129
164
  XSelectInput (si->dpy, window, SubstructureNotifyMask | events);
130
165
 
131
 
  if (top_p && p->verbose_p && (events & KeyPressMask))
 
166
  if (top_p && p->debug_p && (events & KeyPressMask))
132
167
    {
133
168
      /* Only mention one window per tree (hack hack). */
134
 
      fprintf (stderr, "%s: selected KeyPress on 0x%lX\n", blurb(),
135
 
               (unsigned long) window);
 
169
      fprintf (stderr, "%s: %d: selected KeyPress on 0x%lX\n",
 
170
               blurb(), screen_no, (unsigned long) window);
136
171
      top_p = False;
137
172
    }
138
173
 
248
283
      si->cycle_id = XtAppAddTimeOut (si->app, how_long, cycle_timer,
249
284
                                      (XtPointer) si);
250
285
 
251
 
# ifdef DEBUG_TIMERS
252
 
      if (p->verbose_p)
 
286
      if (p->debug_p)
253
287
        fprintf (stderr, "%s: starting cycle_timer (%ld, %ld)\n",
254
288
                 blurb(), how_long, si->cycle_id);
255
 
# endif /* DEBUG_TIMERS */
256
289
    }
257
 
# ifdef DEBUG_TIMERS
258
290
  else
259
291
    {
260
 
      if (p->verbose_p)
261
 
        fprintf (stderr, "%s: not starting cycle_timer: how_long == %d\n",
262
 
                 blurb(), how_long);
 
292
      if (p->debug_p)
 
293
        fprintf (stderr, "%s: not starting cycle_timer: how_long == %ld\n",
 
294
                 blurb(), (unsigned long) how_long);
263
295
    }
264
 
# endif /* DEBUG_TIMERS */
265
296
}
266
297
 
267
298
 
288
319
 
289
320
  if (si->timer_id)
290
321
    {
291
 
#ifdef DEBUG_TIMERS
292
 
      if (p->verbose_p)
 
322
      if (p->debug_p)
293
323
        fprintf (stderr, "%s: killing idle_timer  (%ld, %ld)\n",
294
324
                 blurb(), p->timeout, si->timer_id);
295
 
#endif /* DEBUG_TIMERS */
296
325
      XtRemoveTimeOut (si->timer_id);
 
326
      si->timer_id = 0;
297
327
    }
298
328
 
299
 
  schedule_wakeup_event (si, p->timeout, p->verbose_p); /* sets si->timer_id */
 
329
  schedule_wakeup_event (si, p->timeout, p->debug_p); /* sets si->timer_id */
300
330
 
301
331
  if (si->cycle_id) abort ();   /* no cycle timer when inactive */
302
332
 
304
334
}
305
335
 
306
336
 
 
337
/* Returns true if the mouse has moved since the last time we checked.
 
338
   Small motions (of less than "hysteresis" pixels/second) are ignored.
 
339
 */
 
340
static Bool
 
341
pointer_moved_p (saver_screen_info *ssi, Bool mods_p)
 
342
{
 
343
  saver_info *si = ssi->global;
 
344
  saver_preferences *p = &si->prefs;
 
345
 
 
346
  Window root, child;
 
347
  int root_x, root_y, x, y;
 
348
  unsigned int mask;
 
349
  time_t now = time ((time_t *) 0);
 
350
  unsigned int distance, dps;
 
351
  unsigned long seconds = 0;
 
352
  Bool moved_p = False;
 
353
 
 
354
  /* don't check xinerama pseudo-screens. */
 
355
  if (!ssi->real_screen_p) return False;
 
356
 
 
357
  if (!XQueryPointer (si->dpy, ssi->screensaver_window, &root, &child,
 
358
                      &root_x, &root_y, &x, &y, &mask))
 
359
    {
 
360
      /* If XQueryPointer() returns false, the mouse is not on this screen.
 
361
       */
 
362
      x = root_x = -1;
 
363
      y = root_y = -1;
 
364
      root = child = 0;
 
365
      mask = 0;
 
366
    }
 
367
 
 
368
  distance = MAX (ABS (ssi->poll_mouse_last_root_x - root_x),
 
369
                  ABS (ssi->poll_mouse_last_root_y - root_y));
 
370
  seconds = (now - ssi->poll_mouse_last_time);
 
371
 
 
372
 
 
373
  /* When the screen is blanked, we get MotionNotify events, but when not
 
374
     blanked, we poll only every 5 seconds, and that's not enough resolution
 
375
     to do hysteresis based on a 1 second interval.  So, assume that any
 
376
     motion we've seen during the 5 seconds when our eyes were closed happened
 
377
     in the last 1 second instead.
 
378
   */
 
379
  if (seconds > 1) seconds = 1;
 
380
 
 
381
  dps = (seconds <= 0 ? distance : (distance / seconds));
 
382
 
 
383
  /* Motion only counts if the rate is more than N pixels per second.
 
384
   */
 
385
  if (dps >= p->pointer_hysteresis &&
 
386
      distance > 0)
 
387
    moved_p = True;
 
388
 
 
389
  if (ssi->poll_mouse_last_root_x == -1 ||
 
390
      ssi->poll_mouse_last_root_y == -1 ||
 
391
      root_x == -1 ||
 
392
      root_y == -1)
 
393
    moved_p = True;
 
394
 
 
395
  if (p->debug_p && (distance != 0 || moved_p))
 
396
    {
 
397
      fprintf (stderr, "%s: %d: pointer %s", blurb(), ssi->number,
 
398
               (moved_p ? "moved:  " : "ignored:"));
 
399
      if (ssi->poll_mouse_last_root_x == -1)
 
400
        fprintf (stderr, "off screen");
 
401
      else
 
402
        fprintf (stderr, "%d,%d",
 
403
                 ssi->poll_mouse_last_root_x,
 
404
                 ssi->poll_mouse_last_root_y);
 
405
      fprintf (stderr, " -> ");
 
406
      if (root_x == -1)
 
407
        fprintf (stderr, "off screen.");
 
408
      else
 
409
        fprintf (stderr, "%d,%d", root_x, root_y);
 
410
      if (ssi->poll_mouse_last_root_x != -1 && root_x != -1)
 
411
        fprintf (stderr, " (%d,%d; %d/%lu=%d)",
 
412
                 ABS(ssi->poll_mouse_last_root_x - root_x),
 
413
                 ABS(ssi->poll_mouse_last_root_y - root_y),
 
414
                 distance, seconds, dps);
 
415
 
 
416
      fprintf (stderr, ".\n");
 
417
    }
 
418
 
 
419
  if (!moved_p &&
 
420
      mods_p &&
 
421
      mask != ssi->poll_mouse_last_mask)
 
422
    {
 
423
      moved_p = True;
 
424
 
 
425
      if (p->debug_p)
 
426
        fprintf (stderr, "%s: %d: modifiers changed: 0x%04x -> 0x%04x.\n",
 
427
                 blurb(), ssi->number, ssi->poll_mouse_last_mask, mask);
 
428
    }
 
429
 
 
430
  si->last_activity_screen   = ssi;
 
431
  ssi->poll_mouse_last_child = child;
 
432
  ssi->poll_mouse_last_mask  = mask;
 
433
 
 
434
  if (moved_p || seconds > 0)
 
435
    {
 
436
      ssi->poll_mouse_last_time   = now;
 
437
      ssi->poll_mouse_last_root_x = root_x;
 
438
      ssi->poll_mouse_last_root_y = root_y;
 
439
    }
 
440
 
 
441
  return moved_p;
 
442
}
 
443
 
 
444
 
307
445
/* When we aren't using a server extension, this timer is used to periodically
308
446
   wake up and poll the mouse position, which is possibly more reliable than
309
447
   selecting motion events on every window.
325
463
     */
326
464
    abort ();
327
465
 
328
 
  si->check_pointer_timer_id =
 
466
  if (id && *id == si->check_pointer_timer_id)  /* this is us - it's expired */
 
467
    si->check_pointer_timer_id = 0;
 
468
 
 
469
  if (si->check_pointer_timer_id)               /* only queue one at a time */
 
470
    XtRemoveTimeOut (si->check_pointer_timer_id);
 
471
 
 
472
  si->check_pointer_timer_id =                  /* now re-queue */
329
473
    XtAppAddTimeOut (si->app, p->pointer_timeout, check_pointer_timer,
330
474
                     (XtPointer) si);
331
475
 
332
476
  for (i = 0; i < si->nscreens; i++)
333
477
    {
334
478
      saver_screen_info *ssi = &si->screens[i];
335
 
      Window root, child;
336
 
      int root_x, root_y, x, y;
337
 
      unsigned int mask;
338
 
 
339
 
      XQueryPointer (si->dpy, ssi->screensaver_window, &root, &child,
340
 
                     &root_x, &root_y, &x, &y, &mask);
341
 
 
342
 
      if (root_x == ssi->poll_mouse_last_root_x &&
343
 
          root_y == ssi->poll_mouse_last_root_y &&
344
 
          child  == ssi->poll_mouse_last_child &&
345
 
          mask   == ssi->poll_mouse_last_mask)
346
 
        continue;
347
 
 
348
 
      active_p = True;
349
 
 
350
 
#ifdef DEBUG_TIMERS
351
 
      if (p->verbose_p)
352
 
        if (root_x == ssi->poll_mouse_last_root_x &&
353
 
            root_y == ssi->poll_mouse_last_root_y &&
354
 
            child  == ssi->poll_mouse_last_child)
355
 
          fprintf (stderr, "%s: modifiers changed at %s on screen %d.\n",
356
 
                   blurb(), timestring(), i);
357
 
        else
358
 
          fprintf (stderr, "%s: pointer moved at %s on screen %d.\n",
359
 
                   blurb(), timestring(), i);
360
 
 
361
 
# if 0
362
 
      fprintf (stderr, "%s: old: %d %d 0x%x ; new: %d %d 0x%x\n",
363
 
               blurb(), 
364
 
               ssi->poll_mouse_last_root_x,
365
 
               ssi->poll_mouse_last_root_y,
366
 
               (unsigned int) ssi->poll_mouse_last_child,
367
 
               root_x, root_y, (unsigned int) child);
368
 
# endif /* 0 */
369
 
 
370
 
#endif /* DEBUG_TIMERS */
371
 
 
372
 
      si->last_activity_screen    = ssi;
373
 
      ssi->poll_mouse_last_root_x = root_x;
374
 
      ssi->poll_mouse_last_root_y = root_y;
375
 
      ssi->poll_mouse_last_child  = child;
376
 
      ssi->poll_mouse_last_mask   = mask;
 
479
      if (pointer_moved_p (ssi, True))
 
480
        active_p = True;
377
481
    }
378
482
 
379
483
#ifdef HAVE_PROC_INTERRUPTS
381
485
      si->using_proc_interrupts &&
382
486
      proc_interrupts_activity_p (si))
383
487
    {
384
 
# ifdef DEBUG_TIMERS
385
 
      if (p->verbose_p)
386
 
        fprintf (stderr, "%s: /proc/interrupts activity at %s.\n",
387
 
                 blurb(), timestring());
388
 
# endif /* DEBUG_TIMERS */
389
488
      active_p = True;
390
489
    }
391
490
#endif /* HAVE_PROC_INTERRUPTS */
392
491
 
393
 
 
394
492
  if (active_p)
395
493
    reset_timers (si);
396
494
 
422
520
  time_t now = time ((time_t *) 0);
423
521
  long shift = now - si->last_wall_clock_time;
424
522
 
425
 
#ifdef DEBUG_TIMERS
426
 
  if (p->verbose_p)
427
 
    fprintf (stderr, "%s: checking wall clock (%d).\n", blurb(),
428
 
             (si->last_wall_clock_time == 0 ? 0 : shift));
429
 
#endif /* DEBUG_TIMERS */
 
523
  if (p->debug_p)
 
524
    {
 
525
      int i = (si->last_wall_clock_time == 0 ? 0 : shift);
 
526
      fprintf (stderr,
 
527
               "%s: checking wall clock for hibernation (%d:%02d:%02d).\n",
 
528
               blurb(),
 
529
               (i / (60 * 60)), ((i / 60) % 60), (i % 60));
 
530
    }
430
531
 
431
532
  if (si->last_wall_clock_time != 0 &&
432
533
      shift > (p->timeout / 1000))
433
534
    {
434
535
      if (p->verbose_p)
435
 
        fprintf (stderr, "%s: wall clock has jumped by %d:%02d:%02d!\n",
 
536
        fprintf (stderr, "%s: wall clock has jumped by %ld:%02ld:%02ld!\n",
436
537
                 blurb(),
437
538
                 (shift / (60 * 60)), ((shift / 60) % 60), (shift % 60));
438
539
 
573
674
    {
574
675
      if (polling_for_idleness)
575
676
        /* This causes a no-op event to be delivered to us in a while, so that
576
 
           we come back around through the event loop again.  Use of this timer
577
 
           is economical: for example, if the screensaver should come on in 5
578
 
           minutes, and the user has been idle for 2 minutes, then this
579
 
           timeout will go off no sooner than 3 minutes from now.  */
580
 
        schedule_wakeup_event (si, p->timeout, p->verbose_p);
 
677
           we come back around through the event loop again.  */
 
678
        schedule_wakeup_event (si, p->timeout, p->debug_p);
581
679
 
582
680
      if (polling_mouse_position)
583
681
        /* Check to see if the mouse has moved, and set up a repeating timer
594
692
        if (until_idle_p)
595
693
          {
596
694
            Time idle;
 
695
 
 
696
            /* We may be idle; check one last time to see if the mouse has
 
697
               moved, just in case the idle-timer went off within the 5 second
 
698
               window between mouse polling.  If the mouse has moved, then
 
699
               check_pointer_timer() will reset last_activity_time.
 
700
             */
 
701
            if (polling_mouse_position)
 
702
              check_pointer_timer ((XtPointer) si, 0);
 
703
 
597
704
#ifdef HAVE_XIDLE_EXTENSION
598
705
            if (si->using_xidle_extension)
599
706
              {
657
764
              {
658
765
                /* The event went off, but it turns out that the user has not
659
766
                   yet been idle for long enough.  So re-signal the event.
660
 
                   */
 
767
                   Be economical: if we should blank after 5 minutes, and the
 
768
                   user has been idle for 2 minutes, then set this timer to
 
769
                   go off in 3 minutes.
 
770
                 */
661
771
                if (polling_for_idleness)
662
 
                  schedule_wakeup_event (si, p->timeout - idle, p->verbose_p);
 
772
                  schedule_wakeup_event (si, p->timeout - idle, p->debug_p);
663
773
              }
664
774
          }
665
775
        break;
675
785
        if (scanning_all_windows)
676
786
          {
677
787
            Window w = event.xcreatewindow.window;
678
 
#ifdef DEBUG_TIMERS
679
 
            start_notice_events_timer (si, w, p->verbose_p);
680
 
#else  /* !DEBUG_TIMERS */
681
 
            start_notice_events_timer (si, w, False);
682
 
#endif /* !DEBUG_TIMERS */
 
788
            start_notice_events_timer (si, w, p->debug_p);
683
789
          }
684
790
        break;
685
791
 
689
795
      case ButtonRelease:
690
796
      case MotionNotify:
691
797
 
692
 
#ifdef DEBUG_TIMERS
693
 
        if (p->verbose_p)
 
798
        if (p->debug_p)
694
799
          {
 
800
            Window root=0, window=0;
 
801
            int x=-1, y=-1;
 
802
            const char *type = 0;
695
803
            if (event.xany.type == MotionNotify)
696
 
              fprintf (stderr,"%s: MotionNotify at %s\n",blurb(),timestring());
 
804
              {
 
805
                /*type = "MotionNotify";*/
 
806
                root = event.xmotion.root;
 
807
                window = event.xmotion.window;
 
808
                x = event.xmotion.x_root;
 
809
                y = event.xmotion.y_root;
 
810
              }
697
811
            else if (event.xany.type == KeyPress)
698
 
              fprintf (stderr, "%s: KeyPress seen on 0x%X at %s\n", blurb(),
699
 
                       (unsigned int) event.xkey.window, timestring ());
 
812
              {
 
813
                type = "KeyPress";
 
814
                root = event.xkey.root;
 
815
                window = event.xkey.window;
 
816
                x = y = -1;
 
817
              }
700
818
            else if (event.xany.type == ButtonPress)
701
 
              fprintf (stderr, "%s: ButtonPress seen on 0x%X at %s\n", blurb(),
702
 
                       (unsigned int) event.xbutton.window, timestring ());
 
819
              {
 
820
                type = "ButtonPress";
 
821
                root = event.xkey.root;
 
822
                window = event.xkey.window;
 
823
                x = event.xmotion.x_root;
 
824
                y = event.xmotion.y_root;
 
825
              }
 
826
 
 
827
            if (type)
 
828
              {
 
829
                int i;
 
830
                for (i = 0; i < si->nscreens; i++)
 
831
                  if (root == RootWindowOfScreen (si->screens[i].screen))
 
832
                    break;
 
833
                fprintf (stderr,"%s: %d: %s on 0x%lx",
 
834
                         blurb(), i, type, (unsigned long) window);
 
835
 
 
836
                /* Be careful never to do this unless in -debug mode, as
 
837
                   this could expose characters from the unlock password. */
 
838
                if (p->debug_p && event.xany.type == KeyPress)
 
839
                  {
 
840
                    KeySym keysym;
 
841
                    char c = 0;
 
842
                    XLookupString (&event.xkey, &c, 1, &keysym, 0);
 
843
                    fprintf (stderr, " (%s%s)",
 
844
                             (event.xkey.send_event ? "synthetic " : ""),
 
845
                             XKeysymToString (keysym));
 
846
                  }
 
847
 
 
848
                if (x == -1)
 
849
                  fprintf (stderr, "\n");
 
850
                else
 
851
                  fprintf (stderr, " at %d,%d.\n", x, y);
 
852
              }
703
853
          }
704
 
#endif /* DEBUG_TIMERS */
705
854
 
706
855
        /* If any widgets want to handle this event, let them. */
707
856
        dispatch_event (si, &event);
708
857
 
 
858
        
 
859
        /* If we got a MotionNotify event, figure out what screen it
 
860
           was on and poll the mouse there: if the mouse hasn't moved
 
861
           far enough to count as "real" motion, then ignore this
 
862
           event.
 
863
         */
 
864
        if (event.xany.type == MotionNotify)
 
865
          {
 
866
            int i;
 
867
            for (i = 0; i < si->nscreens; i++)
 
868
              if (event.xmotion.root ==
 
869
                  RootWindowOfScreen (si->screens[i].screen))
 
870
                break;
 
871
            if (i < si->nscreens)
 
872
              {
 
873
                if (!pointer_moved_p (&si->screens[i], False))
 
874
                  continue;
 
875
              }
 
876
          }
 
877
 
 
878
 
709
879
        /* We got a user event.
710
880
           If we're waiting for the user to become active, this is it.
711
881
           If we're waiting until the user becomes idle, reset the timers
813
983
        else
814
984
#endif /* HAVE_SGI_SAVER_EXTENSION */
815
985
 
 
986
#ifdef HAVE_RANDR
 
987
        if (event.type == (si->randr_event_number + RRScreenChangeNotify))
 
988
          {
 
989
            /* The Resize and Rotate extension sends an event when the
 
990
               size, rotation, or refresh rate of the screen has changed. */
 
991
 
 
992
            XRRScreenChangeNotifyEvent *xrr_event =
 
993
              (XRRScreenChangeNotifyEvent *) &event;
 
994
            /* XRRRootToScreen is in Xrandr.h 1.4, 2001/06/07 */
 
995
            int screen = XRRRootToScreen (si->dpy, xrr_event->window);
 
996
 
 
997
            if (p->verbose_p)
 
998
              {
 
999
                if (si->screens[screen].width  == xrr_event->width &&
 
1000
                    si->screens[screen].height == xrr_event->height)
 
1001
                  fprintf (stderr,
 
1002
                          "%s: %d: no-op screen size change event (%dx%d)\n",
 
1003
                           blurb(), screen,
 
1004
                           xrr_event->width, xrr_event->height);
 
1005
                else
 
1006
                  fprintf (stderr,
 
1007
                       "%s: %d: screen size changed from %dx%d to %dx%d\n",
 
1008
                           blurb(), screen,
 
1009
                           si->screens[screen].width,
 
1010
                           si->screens[screen].height,
 
1011
                           xrr_event->width, xrr_event->height);
 
1012
              }
 
1013
 
 
1014
# ifdef RRScreenChangeNotifyMask
 
1015
            /* Inform Xlib that it's ok to update its data structures. */
 
1016
            XRRUpdateConfiguration (&event); /* Xrandr.h 1.9, 2002/09/29 */
 
1017
# endif /* RRScreenChangeNotifyMask */
 
1018
 
 
1019
            /* Resize the existing xscreensaver windows and cached ssi data. */
 
1020
            resize_screensaver_window (si);
 
1021
          }
 
1022
        else
 
1023
#endif /* HAVE_RANDR */
 
1024
 
816
1025
          /* Just some random event.  Let the Widgets handle it, if desired. */
817
1026
          dispatch_event (si, &event);
818
1027
      }
908
1117
          0:  309453991   timer
909
1118
          1:    4771729   keyboard
910
1119
   
911
 
       but on later kernels with MP machines, it looks like this:
 
1120
       but in Linux 2.2 and 2.4 kernels with MP machines, it looks like this:
912
1121
 
913
1122
                   CPU0       CPU1
914
1123
          0:    1671450    1672618    IO-APIC-edge  timer
915
1124
          1:      13037      13495    IO-APIC-edge  keyboard
916
1125
 
 
1126
       and in Linux 2.6, it's gotten even goofier: now there are two lines
 
1127
       labelled "i8042".  One of them is the keyboard, and one of them is
 
1128
       the PS/2 mouse -- and of course, you can't tell them apart, except
 
1129
       by wiggling the mouse and noting which one changes:
 
1130
 
 
1131
                   CPU0       CPU1
 
1132
          1:      32051      30864    IO-APIC-edge  i8042
 
1133
         12:     476577     479913    IO-APIC-edge  i8042
 
1134
 
917
1135
       Joy!  So how are we expected to parse that?  Well, this code doesn't
918
 
       parse it: it saves the last line with the string "keyboard" in it, and
919
 
       does a string-comparison to note when it has changed.
920
 
 
921
 
   Thanks to Nat Friedman <nat@nat.org> for figuring out all of this crap.
922
 
 
923
 
   Note that this only checks for lines with "keyboard" or "PS/2 Mouse" in
924
 
   them.  If you have a serial mouse, it won't detect that, it will only detect
925
 
   keyboard activity.  That's because there's no way to tell the difference
926
 
   between a serial mouse and a general serial port, and it would be somewhat
927
 
   unfortunate to have the screensaver turn off when the modem on COM1 burped.
 
1136
       parse it: it saves the first line with the string "keyboard" (or
 
1137
       "i8042") in it, and does a string-comparison to note when it has
 
1138
       changed.  If there are two "i8042" lines, we assume the first is
 
1139
       the keyboard and the second is the mouse (doesn't matter which is
 
1140
       which, really, as long as we don't compare them against each other.)
 
1141
 
 
1142
   Thanks to Nat Friedman <nat@nat.org> for figuring out most of this crap.
 
1143
 
 
1144
   Note that if you have a serial or USB mouse, or a USB keyboard, it won't
 
1145
   detect it.  That's because there's no way to tell the difference between a
 
1146
   serial mouse and a general serial port, and all USB devices look the same
 
1147
   from here.  It would be somewhat unfortunate to have the screensaver turn
 
1148
   off when the modem on COM1 burped, or when a USB disk was accessed.
928
1149
 */
929
1150
 
930
1151
 
965
1186
  static char last_kbd_line[255] = { 0, };
966
1187
  static char last_ptr_line[255] = { 0, };
967
1188
  char new_line[sizeof(last_kbd_line)];
968
 
  Bool got_kbd = False, kbd_diff = False;
969
 
  Bool got_ptr = False, ptr_diff = False;
 
1189
  Bool checked_kbd = False, kbd_changed = False;
 
1190
  Bool checked_ptr = False, ptr_changed = False;
 
1191
  int i8042_count = 0;
970
1192
 
971
1193
  if (!f0)
972
1194
    {
1013
1235
      goto FAIL;
1014
1236
    }
1015
1237
 
1016
 
  /* Now read through the pseudo-file until we find the "keyboard" line. */
 
1238
  /* Now read through the pseudo-file until we find the "keyboard",
 
1239
     "PS/2 mouse", or "i8042" lines. */
1017
1240
 
1018
1241
  while (fgets (new_line, sizeof(new_line)-1, f1))
1019
1242
    {
1020
 
      if (!got_kbd && strstr (new_line, "keyboard"))
1021
 
        {
1022
 
          kbd_diff = (*last_kbd_line && !!strcmp (new_line, last_kbd_line));
 
1243
      Bool i8042_p = !!strstr (new_line, "i8042");
 
1244
      if (i8042_p) i8042_count++;
 
1245
 
 
1246
      if (strchr (new_line, ','))
 
1247
        {
 
1248
          /* Ignore any line that has a comma on it: this is because
 
1249
             a setup like this:
 
1250
 
 
1251
                 12:     930935          XT-PIC  usb-uhci, PS/2 Mouse
 
1252
 
 
1253
             is really bad news.  It *looks* like we can note mouse
 
1254
             activity from that line, but really, that interrupt gets
 
1255
             fired any time any USB device has activity!  So we have
 
1256
             to ignore any shared IRQs.
 
1257
           */
 
1258
        }
 
1259
      else if (!checked_kbd &&
 
1260
               (strstr (new_line, "keyboard") ||
 
1261
                (i8042_p && i8042_count == 1)))
 
1262
        {
 
1263
          /* Assume the keyboard interrupt is the line that says "keyboard",
 
1264
             or the *first* line that says "i8042".
 
1265
           */
 
1266
          kbd_changed = (*last_kbd_line && !!strcmp (new_line, last_kbd_line));
1023
1267
          strcpy (last_kbd_line, new_line);
1024
 
          got_kbd = True;
 
1268
          checked_kbd = True;
1025
1269
        }
1026
 
      else if (!got_ptr && strstr (new_line, "PS/2 Mouse"))
 
1270
      else if (!checked_ptr &&
 
1271
               (strstr (new_line, "PS/2 Mouse") ||
 
1272
                (i8042_p && i8042_count == 2)))
1027
1273
        {
1028
 
          ptr_diff = (*last_ptr_line && !!strcmp (new_line, last_ptr_line));
 
1274
          /* Assume the mouse interrupt is the line that says "PS/2 mouse",
 
1275
             or the *second* line that says "i8042".
 
1276
           */
 
1277
          ptr_changed = (*last_ptr_line && !!strcmp (new_line, last_ptr_line));
1029
1278
          strcpy (last_ptr_line, new_line);
1030
 
          got_ptr = True;
 
1279
          checked_ptr = True;
1031
1280
        }
1032
1281
 
1033
 
      if (got_kbd && got_ptr)
 
1282
      if (checked_kbd && checked_ptr)
1034
1283
        break;
1035
1284
    }
1036
1285
 
1037
 
  if (got_kbd || got_ptr)
 
1286
  if (checked_kbd || checked_ptr)
1038
1287
    {
1039
1288
      fclose (f1);
1040
 
      return (kbd_diff || ptr_diff);
 
1289
 
 
1290
      if (si->prefs.debug_p && (kbd_changed || ptr_changed))
 
1291
        fprintf (stderr, "%s: /proc/interrupts activity: %s\n",
 
1292
                 blurb(),
 
1293
                 ((kbd_changed && ptr_changed) ? "mouse and kbd" :
 
1294
                  kbd_changed ? "kbd" :
 
1295
                  ptr_changed ? "mouse" : "ERR"));
 
1296
 
 
1297
      return (kbd_changed || ptr_changed);
1041
1298
    }
1042
1299
 
1043
1300
 
1088
1345
 
1089
1346
  /* If the DPMS settings on the server have changed, change them back to
1090
1347
     what ~/.xscreensaver says they should be. */
1091
 
  sync_server_dpms_settings (si->dpy, p->dpms_enabled_p,
 
1348
  sync_server_dpms_settings (si->dpy,
 
1349
                             (p->dpms_enabled_p  &&
 
1350
                              p->mode != DONT_BLANK),
1092
1351
                             p->dpms_standby / 1000,
1093
1352
                             p->dpms_suspend / 1000,
1094
1353
                             p->dpms_off / 1000,
1100
1359
 
1101
1360
      if (si->dbox_up_p)
1102
1361
        {
1103
 
#ifdef DEBUG_TIMERS
1104
 
          if (si->prefs.verbose_p)
 
1362
          if (si->prefs.debug_p)
1105
1363
            fprintf (stderr, "%s: dialog box is up: not raising screen.\n",
1106
1364
                     blurb());
1107
 
#endif /* DEBUG_TIMERS */
1108
1365
        }
1109
1366
      else
1110
1367
        {
1111
 
#ifdef DEBUG_TIMERS
1112
 
          if (si->prefs.verbose_p)
 
1368
          if (si->prefs.debug_p)
1113
1369
            fprintf (stderr, "%s: watchdog timer raising %sscreen.\n",
1114
1370
                     blurb(), (running_p ? "" : "and clearing "));
1115
 
#endif /* DEBUG_TIMERS */
1116
1371
 
1117
1372
          raise_window (si, True, True, running_p);
1118
1373
        }
1152
1407
      si->watchdog_id = XtAppAddTimeOut (si->app, p->watchdog_timeout,
1153
1408
                                         watchdog_timer, (XtPointer) si);
1154
1409
 
1155
 
#ifdef DEBUG_TIMERS
1156
 
      if (p->verbose_p)
 
1410
      if (p->debug_p)
1157
1411
        fprintf (stderr, "%s: restarting watchdog_timer (%ld, %ld)\n",
1158
1412
                 blurb(), p->watchdog_timeout, si->watchdog_id);
1159
 
#endif /* DEBUG_TIMERS */
1160
 
 
 
1413
    }
 
1414
}
 
1415
 
 
1416
 
 
1417
/* It's possible that a race condition could have led to the saver
 
1418
   window being unexpectedly still mapped.  This can happen like so:
 
1419
 
 
1420
    - screen is blanked
 
1421
    - hack is launched
 
1422
    - that hack tries to grab a screen image (it does this by
 
1423
      first unmapping the saver window, then remapping it.)
 
1424
    - hack unmaps window
 
1425
    - hack waits
 
1426
    - user becomes active
 
1427
    - hack re-maps window (*)
 
1428
    - driver kills subprocess
 
1429
    - driver unmaps window (**)
 
1430
 
 
1431
   The race is that (*) might have been sent to the server before
 
1432
   the client process was killed, but, due to scheduling randomness,
 
1433
   might not have been received by the server until after (**).
 
1434
   In other words, (*) and (**) might happen out of order, meaning
 
1435
   the driver will unmap the window, and then after that, the
 
1436
   recently-dead client will re-map it.  This leaves the user
 
1437
   locked out (it looks like a desktop, but it's not!)
 
1438
 
 
1439
   To avoid this: after un-blanking the screen, we launch a timer
 
1440
   that wakes up once a second for ten seconds, and makes damned
 
1441
   sure that the window is still unmapped.
 
1442
 */
 
1443
 
 
1444
void
 
1445
de_race_timer (XtPointer closure, XtIntervalId *id)
 
1446
{
 
1447
  saver_info *si = (saver_info *) closure;
 
1448
  saver_preferences *p = &si->prefs;
 
1449
  int secs = 1;
 
1450
 
 
1451
  if (id == 0)  /* if id is 0, this is the initialization call. */
 
1452
    {
 
1453
      si->de_race_ticks = 10;
 
1454
      if (p->verbose_p)
 
1455
        fprintf (stderr, "%s: starting de-race timer (%d seconds.)\n",
 
1456
                 blurb(), si->de_race_ticks);
 
1457
    }
 
1458
  else
 
1459
    {
 
1460
      int i;
 
1461
      XSync (si->dpy, False);
 
1462
      for (i = 0; i < si->nscreens; i++)
 
1463
        {
 
1464
          saver_screen_info *ssi = &si->screens[i];
 
1465
          Window w = ssi->screensaver_window;
 
1466
          XWindowAttributes xgwa;
 
1467
          XGetWindowAttributes (si->dpy, w, &xgwa);
 
1468
          if (xgwa.map_state != IsUnmapped)
 
1469
            {
 
1470
              if (p->verbose_p)
 
1471
                fprintf (stderr,
 
1472
                         "%s: %d: client race! emergency unmap 0x%lx.\n",
 
1473
                         blurb(), i, (unsigned long) w);
 
1474
              XUnmapWindow (si->dpy, w);
 
1475
            }
 
1476
          else if (p->debug_p)
 
1477
            fprintf (stderr, "%s: %d: (de-race of 0x%lx is cool.)\n",
 
1478
                     blurb(), i, (unsigned long) w);
 
1479
        }
 
1480
      XSync (si->dpy, False);
 
1481
 
 
1482
      si->de_race_ticks--;
 
1483
    }
 
1484
 
 
1485
  if (id && *id == si->de_race_id)
 
1486
    si->de_race_id = 0;
 
1487
 
 
1488
  if (si->de_race_id) abort();
 
1489
 
 
1490
  if (si->de_race_ticks <= 0)
 
1491
    {
 
1492
      si->de_race_id = 0;
 
1493
      if (p->verbose_p)
 
1494
        fprintf (stderr, "%s: de-race completed.\n", blurb());
 
1495
    }
 
1496
  else
 
1497
    {
 
1498
      si->de_race_id = XtAppAddTimeOut (si->app, secs * 1000,
 
1499
                                        de_race_timer, closure);
1161
1500
    }
1162
1501
}