1
/*****************************************************************************
3
* Authors: Michel Eyckmans (MCE) & Stefan De Troch (SDT)
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.
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.
18
* Please send bug reports etc. to eyckmans@imec.be.
20
* --------------------------------------------------------------------------
22
* Copyright 1990,1992-1999,2001-2002 by Stefan De Troch and Michel Eyckmans.
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.
28
*****************************************************************************/
34
#include "xautolock_c.h"
36
static void selectEvents (Window window, Bool substructureOnly);
39
* Window queue management.
46
} xautolock_anItem, *xautolock_item;
56
addToQueue (Window window)
58
xautolock_item newItem = malloc(sizeof(xautolock_anItem));
60
newItem->window = window;
61
newItem->creationtime = time (0);
64
if (!queue.head) queue.head = newItem;
65
if ( queue.tail) queue.tail->next = newItem;
71
processQueue (time_t age)
75
time_t now = time (0);
76
xautolock_item current = queue.head;
78
while (current && current->creationtime + age < now)
80
selectEvents (current->window, False);
81
queue.head = current->next;
86
if (!queue.head) queue.tail = 0;
91
* Function for selecting all interesting events on a given
92
* (tree of) window(s).
95
selectEvents (Window window, Bool substructureOnly)
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 */
104
if( xautolock_ignoreWindow( window ))
107
* Start by querying the server about the root and parent windows.
109
if (!XQueryTree (queue.display, window, &root, &parent,
110
&children, &nofChildren))
115
if (nofChildren) (void) XFree ((char*) children);
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
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
129
if (substructureOnly)
131
(void) XSelectInput (queue.display, window, SubstructureNotifyMask);
135
if (parent == None) /* the *real* rootwindow */
137
attribs.all_event_masks =
138
attribs.do_not_propagate_mask = KeyPressMask;
140
else if (!XGetWindowAttributes (queue.display, window, &attribs))
143
if (!XGetWindowAttributes (queue.display, window, &attribs))
150
(void) XSelectInput (queue.display, window,
151
SubstructureNotifyMask
152
| ( ( attribs.all_event_masks
153
| attribs.do_not_propagate_mask)
157
int mask = SubstructureNotifyMask | attribs.your_event_mask;
158
if( !substructureOnly )
160
mask |= ( ( attribs.all_event_masks
161
| attribs.do_not_propagate_mask)
164
(void) XSelectInput (queue.display, window, mask );
171
* Now ask for the list of children again, since it might have changed
172
* in between the last time and us selecting SubstructureNotifyMask.
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
181
if (!XQueryTree (queue.display, window, &root, &parent,
182
&children, &nofChildren))
188
* Now do the same thing for all children.
190
for (i = 0; i < nofChildren; ++i)
192
selectEvents (children[i], substructureOnly);
195
if (nofChildren) (void) XFree ((char*) children);
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.
207
while (XPending (queue.display))
211
if (XCheckMaskEvent (queue.display, SubstructureNotifyMask, &event))
213
if (event.type == CreateNotify)
215
addToQueue (event.xcreatewindow.window);
220
(void) XNextEvent (queue.display, &event);
224
* Reset the triggers if and only if the event is a
225
* KeyPress event *and* was not generated by XSendEvent().
227
if ( event.type == KeyPress
228
&& !event.xany.send_event)
235
* Check the window queue for entries that are older than
236
* CREATION_DELAY seconds.
238
processQueue ((time_t) CREATION_DELAY);
241
void xautolock_processEvent( XEvent* event )
243
if (event->type == CreateNotify)
245
addToQueue (event->xcreatewindow.window);
248
* Reset the triggers if and only if the event is a
249
* KeyPress event *and* was not generated by XSendEvent().
251
if ( event->type == KeyPress
252
&& !event->xany.send_event)
254
xautolock_resetTriggers ();
258
void xautolock_processQueue()
261
* Check the window queue for entries that are older than
262
* CREATION_DELAY seconds.
264
processQueue ((time_t) CREATION_DELAY);
270
* Function for initialising the whole shebang.
273
xautolock_initDiy (Display* d)
281
for (s = -1; ++s < ScreenCount (d); )
283
Window root = RootWindowOfScreen (ScreenOfDisplay (d, s));
286
selectEvents (root, True);