Merge branch 'central-widget'
[krunner.git] / xautolock_diy.c
blobb9df2f8957e65cef0ce44da7db718d385ed6d5b7
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 *****************************************************************************/
30 #include <X11/Xlib.h>
31 #include <stdlib.h>
32 #include <time.h>
34 #include "xautolock_c.h"
36 static void selectEvents (Window window, Bool substructureOnly);
39 * Window queue management.
41 typedef struct item
43 Window window;
44 time_t creationtime;
45 struct item* next;
46 } xautolock_anItem, *xautolock_item;
48 static struct
50 Display* display;
51 struct item* head;
52 struct item* tail;
53 } queue;
55 static void
56 addToQueue (Window window)
58 xautolock_item newItem = malloc(sizeof(xautolock_anItem));
60 newItem->window = window;
61 newItem->creationtime = time (0);
62 newItem->next = 0;
64 if (!queue.head) queue.head = newItem;
65 if ( queue.tail) queue.tail->next = newItem;
67 queue.tail = newItem;
70 static void
71 processQueue (time_t age)
73 if (queue.head)
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;
82 free (current);
83 current = queue.head;
86 if (!queue.head) queue.tail = 0;
91 * Function for selecting all interesting events on a given
92 * (tree of) window(s).
94 static void
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 ))
105 return;
107 * Start by querying the server about the root and parent windows.
109 if (!XQueryTree (queue.display, window, &root, &parent,
110 &children, &nofChildren))
112 return;
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
120 * we don't have to.
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.
128 #if 0
129 if (substructureOnly)
131 (void) XSelectInput (queue.display, window, SubstructureNotifyMask);
133 else
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))
141 #else
143 if (!XGetWindowAttributes (queue.display, window, &attribs))
144 #endif
146 return;
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
157 int mask = SubstructureNotifyMask | attribs.your_event_mask;
158 if( !substructureOnly )
160 mask |= ( ( attribs.all_event_masks
161 | attribs.do_not_propagate_mask)
162 & KeyPressMask );
164 (void) XSelectInput (queue.display, window, mask );
166 #endif
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
179 * isn't required...
181 if (!XQueryTree (queue.display, window, &root, &parent,
182 &children, &nofChildren))
184 return;
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);
198 #if 0
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.
204 void
205 processEvents (void)
207 while (XPending (queue.display))
209 XEvent event;
211 if (XCheckMaskEvent (queue.display, SubstructureNotifyMask, &event))
213 if (event.type == CreateNotify)
215 addToQueue (event.xcreatewindow.window);
218 else
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)
230 resetTriggers ();
235 * Check the window queue for entries that are older than
236 * CREATION_DELAY seconds.
238 processQueue ((time_t) CREATION_DELAY);
240 #else
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);
266 #endif
270 * Function for initialising the whole shebang.
272 void
273 xautolock_initDiy (Display* d)
275 int s;
277 queue.display = d;
278 queue.tail = 0;
279 queue.head = 0;
281 for (s = -1; ++s < ScreenCount (d); )
283 Window root = RootWindowOfScreen (ScreenOfDisplay (d, s));
284 addToQueue (root);
285 #if 0
286 selectEvents (root, True);
287 #endif