~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to krunner/screensaver/xautolock_diy.c

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*****************************************************************************
 
2
 *
 
3
 * Authors: Michel Eyckmans (MCE) & Stefan De Troch (SDT)
 
4
 *
 
5
 * Content: This file is part of version 2.x of xautolock. It implements
 
6
 *          the stuff used when the program is not using a screen saver
 
7
 *          extension and thus has to use the good old "do it yourself"
 
8
 *          approach for detecting user activity.
 
9
 *
 
10
 *          The basic idea is that we initially traverse the window tree,
 
11
 *          selecting SubstructureNotify on all windows and adding each
 
12
 *          window to a temporary list. About +- 30 seconds later, we 
 
13
 *          scan this list, now asking for KeyPress events. The delay
 
14
 *          is needed in order to interfere as little as possible with
 
15
 *          the event propagation mechanism. Whenever a new window is 
 
16
 *          created by an application, a similar process takes place. 
 
17
 *
 
18
 *          Please send bug reports etc. to eyckmans@imec.be.
 
19
 * 
 
20
 * --------------------------------------------------------------------------
 
21
 * 
 
22
 * Copyright 1990,1992-1999,2001-2002 by Stefan De Troch and Michel Eyckmans.
 
23
 * 
 
24
 * Versions 2.0 and above of xautolock are available under version 2 of the
 
25
 * GNU GPL. Earlier versions are available under other conditions. For more
 
26
 * information, see the License file.
 
27
 *
 
28
 *****************************************************************************/
 
29
 
 
30
#include <X11/Xlib.h>
 
31
#include <stdlib.h>
 
32
#include <time.h>
 
33
 
 
34
#include "xautolock_c.h"
 
35
 
 
36
static void selectEvents (Window window, Bool substructureOnly);
 
37
 
 
38
/*
 
39
 *  Window queue management.
 
40
 */
 
41
typedef struct item
 
42
{
 
43
  Window       window;
 
44
  time_t       creationtime;
 
45
  struct item* next;
 
46
} xautolock_anItem, *xautolock_item;
 
47
 
 
48
static struct 
 
49
{
 
50
  Display*     display;
 
51
  struct item* head;
 
52
  struct item* tail;
 
53
} queue;
 
54
 
 
55
static void
 
56
addToQueue (Window window)
 
57
{
 
58
  xautolock_item newItem = malloc(sizeof(xautolock_anItem));
 
59
 
 
60
  newItem->window = window;
 
61
  newItem->creationtime = time (0);
 
62
  newItem->next = 0;
 
63
 
 
64
  if (!queue.head) queue.head = newItem;
 
65
  if ( queue.tail) queue.tail->next = newItem;
 
66
 
 
67
  queue.tail = newItem;
 
68
}
 
69
 
 
70
static void
 
71
processQueue (time_t age)
 
72
{
 
73
  if (queue.head)
 
74
  {
 
75
    time_t now = time (0);
 
76
    xautolock_item current = queue.head;
 
77
 
 
78
    while (current && current->creationtime + age < now)
 
79
    {
 
80
      selectEvents (current->window, False);
 
81
      queue.head = current->next;
 
82
      free (current);
 
83
      current = queue.head;
 
84
    }
 
85
 
 
86
    if (!queue.head) queue.tail = 0;
 
87
  }
 
88
}
 
89
 
 
90
/*
 
91
 *  Function for selecting all interesting events on a given 
 
92
 *  (tree of) window(s).
 
93
 */
 
94
static void 
 
95
selectEvents (Window window, Bool substructureOnly)
 
96
{
 
97
  Window            root;              /* root window of the window */
 
98
  Window            parent;            /* parent of the window      */
 
99
  Window*           children;          /* children of the window    */
 
100
  unsigned          nofChildren = 0;   /* number of children        */
 
101
  unsigned          i;                 /* loop counter              */
 
102
  XWindowAttributes attribs;           /* attributes of the window  */
 
103
 
 
104
  if( xautolock_ignoreWindow( window ))
 
105
      return;
 
106
 /*
 
107
  *  Start by querying the server about the root and parent windows.
 
108
  */
 
109
  if (!XQueryTree (queue.display, window, &root, &parent,
 
110
                   &children, &nofChildren))
 
111
  {
 
112
    return;
 
113
  }
 
114
 
 
115
  if (nofChildren) (void) XFree ((char*) children);
 
116
 
 
117
 /*
 
118
  *  Build the appropriate event mask. The basic idea is that we don't
 
119
  *  want to interfere with the normal event propagation mechanism if
 
120
  *  we don't have to.
 
121
  *
 
122
  *  On the root window, we need to ask for both substructureNotify 
 
123
  *  and KeyPress events. On all other windows, we always need 
 
124
  *  substructureNotify, but only need Keypress if some other client
 
125
  *  also asked for them, or if they are not being propagated up the
 
126
  *  window tree.
 
127
  */
 
128
#if 0
 
129
  if (substructureOnly)
 
130
  {
 
131
    (void) XSelectInput (queue.display, window, SubstructureNotifyMask);
 
132
  }
 
133
  else
 
134
  {
 
135
    if (parent == None) /* the *real* rootwindow */
 
136
    {
 
137
      attribs.all_event_masks = 
 
138
      attribs.do_not_propagate_mask = KeyPressMask;
 
139
    }
 
140
    else if (!XGetWindowAttributes (queue.display, window, &attribs))
 
141
#else
 
142
    {
 
143
    if (!XGetWindowAttributes (queue.display, window, &attribs))
 
144
#endif
 
145
    {
 
146
      return;
 
147
    }
 
148
 
 
149
#if 0
 
150
    (void) XSelectInput (queue.display, window, 
 
151
                           SubstructureNotifyMask
 
152
                         | (  (  attribs.all_event_masks
 
153
                               | attribs.do_not_propagate_mask)
 
154
                            & KeyPressMask));
 
155
#else
 
156
    {
 
157
    int mask = SubstructureNotifyMask | attribs.your_event_mask;
 
158
    if( !substructureOnly )
 
159
        {
 
160
        mask |=            (  (  attribs.all_event_masks
 
161
                               | attribs.do_not_propagate_mask)
 
162
                            & KeyPressMask  );
 
163
        }
 
164
    (void) XSelectInput (queue.display, window, mask );
 
165
    }
 
166
#endif
 
167
 
 
168
  }
 
169
 
 
170
 /*
 
171
  *  Now ask for the list of children again, since it might have changed
 
172
  *  in between the last time and us selecting SubstructureNotifyMask.
 
173
  *
 
174
  *  There is a (very small) chance that we might process a subtree twice:
 
175
  *  child windows that have been created after our XSelectinput() has
 
176
  *  been processed but before we get to the XQueryTree() bit will be 
 
177
  *  in this situation. This is harmless. It could be avoided by using
 
178
  *  XGrabServer(), but that'd be an impolite thing to do, and since it
 
179
  *  isn't required...
 
180
  */
 
181
  if (!XQueryTree (queue.display, window, &root, &parent,
 
182
                   &children, &nofChildren))
 
183
  {
 
184
    return;
 
185
  }
 
186
 
 
187
 /*
 
188
  *  Now do the same thing for all children.
 
189
  */
 
190
  for (i = 0; i < nofChildren; ++i)
 
191
  {
 
192
    selectEvents (children[i], substructureOnly);
 
193
  }
 
194
 
 
195
  if (nofChildren) (void) XFree ((char*) children);
 
196
}
 
197
 
 
198
#if 0
 
199
/*
 
200
 *  Function for processing any events that have come in since 
 
201
 *  last time. It is crucial that this function does not block
 
202
 *  in case nothing interesting happened.
 
203
 */
 
204
void
 
205
processEvents (void)
 
206
{
 
207
  while (XPending (queue.display))
 
208
  {
 
209
    XEvent event;
 
210
 
 
211
    if (XCheckMaskEvent (queue.display, SubstructureNotifyMask, &event))
 
212
    {
 
213
      if (event.type == CreateNotify)
 
214
      {
 
215
        addToQueue (event.xcreatewindow.window);
 
216
      }
 
217
    }
 
218
    else
 
219
    {
 
220
      (void) XNextEvent (queue.display, &event);
 
221
    }
 
222
 
 
223
   /*
 
224
    *  Reset the triggers if and only if the event is a
 
225
    *  KeyPress event *and* was not generated by XSendEvent().
 
226
    */
 
227
    if (   event.type == KeyPress
 
228
        && !event.xany.send_event)
 
229
    {
 
230
      resetTriggers ();
 
231
    }
 
232
  }
 
233
 
 
234
 /*
 
235
  *  Check the window queue for entries that are older than
 
236
  *  CREATION_DELAY seconds.
 
237
  */
 
238
  processQueue ((time_t) CREATION_DELAY);
 
239
}
 
240
#else
 
241
void xautolock_processEvent( XEvent* event )
 
242
{
 
243
      if (event->type == CreateNotify)
 
244
      {
 
245
        addToQueue (event->xcreatewindow.window);
 
246
      }
 
247
   /*
 
248
    *  Reset the triggers if and only if the event is a
 
249
    *  KeyPress event *and* was not generated by XSendEvent().
 
250
    */
 
251
    if (   event->type == KeyPress
 
252
        && !event->xany.send_event)
 
253
    {
 
254
      xautolock_resetTriggers ();
 
255
    }
 
256
}
 
257
 
 
258
void xautolock_processQueue()
 
259
{
 
260
 /*
 
261
  *  Check the window queue for entries that are older than
 
262
  *  CREATION_DELAY seconds.
 
263
  */
 
264
  processQueue ((time_t) CREATION_DELAY);
 
265
}
 
266
#endif
 
267
 
 
268
 
 
269
/*
 
270
 *  Function for initialising the whole shebang.
 
271
 */
 
272
void
 
273
xautolock_initDiy (Display* d)
 
274
{
 
275
  int s;
 
276
 
 
277
  queue.display = d;
 
278
  queue.tail = 0;
 
279
  queue.head = 0; 
 
280
 
 
281
  for (s = -1; ++s < ScreenCount (d); )
 
282
  {
 
283
    Window root = RootWindowOfScreen (ScreenOfDisplay (d, s));
 
284
    addToQueue (root);
 
285
#if 0
 
286
    selectEvents (root, True);
 
287
#endif
 
288
  }
 
289
}