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
);