summaryrefslogtreecommitdiffstats
path: root/kdesktop/xautolock_diy.c
diff options
context:
space:
mode:
Diffstat (limited to 'kdesktop/xautolock_diy.c')
-rw-r--r--kdesktop/xautolock_diy.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/kdesktop/xautolock_diy.c b/kdesktop/xautolock_diy.c
new file mode 100644
index 000000000..b9df2f895
--- /dev/null
+++ b/kdesktop/xautolock_diy.c
@@ -0,0 +1,289 @@
+/*****************************************************************************
+ *
+ * Authors: Michel Eyckmans (MCE) & Stefan De Troch (SDT)
+ *
+ * Content: This file is part of version 2.x of xautolock. It implements
+ * the stuff used when the program is not using a screen saver
+ * extension and thus has to use the good old "do it yourself"
+ * approach for detecting user activity.
+ *
+ * The basic idea is that we initially traverse the window tree,
+ * selecting SubstructureNotify on all windows and adding each
+ * window to a temporary list. About +- 30 seconds later, we
+ * scan this list, now asking for KeyPress events. The delay
+ * is needed in order to interfere as little as possible with
+ * the event propagation mechanism. Whenever a new window is
+ * created by an application, a similar process takes place.
+ *
+ * Please send bug reports etc. to eyckmans@imec.be.
+ *
+ * --------------------------------------------------------------------------
+ *
+ * Copyright 1990,1992-1999,2001-2002 by Stefan De Troch and Michel Eyckmans.
+ *
+ * Versions 2.0 and above of xautolock are available under version 2 of the
+ * GNU GPL. Earlier versions are available under other conditions. For more
+ * information, see the License file.
+ *
+ *****************************************************************************/
+
+#include <X11/Xlib.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "xautolock_c.h"
+
+static void selectEvents (Window window, Bool substructureOnly);
+
+/*
+ * Window queue management.
+ */
+typedef struct item
+{
+ Window window;
+ time_t creationtime;
+ struct item* next;
+} xautolock_anItem, *xautolock_item;
+
+static struct
+{
+ Display* display;
+ struct item* head;
+ struct item* tail;
+} queue;
+
+static void
+addToQueue (Window window)
+{
+ xautolock_item newItem = malloc(sizeof(xautolock_anItem));
+
+ newItem->window = window;
+ newItem->creationtime = time (0);
+ newItem->next = 0;
+
+ if (!queue.head) queue.head = newItem;
+ if ( queue.tail) queue.tail->next = newItem;
+
+ queue.tail = newItem;
+}
+
+static void
+processQueue (time_t age)
+{
+ if (queue.head)
+ {
+ time_t now = time (0);
+ xautolock_item current = queue.head;
+
+ while (current && current->creationtime + age < now)
+ {
+ selectEvents (current->window, False);
+ queue.head = current->next;
+ free (current);
+ current = queue.head;
+ }
+
+ if (!queue.head) queue.tail = 0;
+ }
+}
+
+/*
+ * Function for selecting all interesting events on a given
+ * (tree of) window(s).
+ */
+static void
+selectEvents (Window window, Bool substructureOnly)
+{
+ Window root; /* root window of the window */
+ Window parent; /* parent of the window */
+ Window* children; /* children of the window */
+ unsigned nofChildren = 0; /* number of children */
+ unsigned i; /* loop counter */
+ XWindowAttributes attribs; /* attributes of the window */
+
+ if( xautolock_ignoreWindow( window ))
+ return;
+ /*
+ * Start by querying the server about the root and parent windows.
+ */
+ if (!XQueryTree (queue.display, window, &root, &parent,
+ &children, &nofChildren))
+ {
+ return;
+ }
+
+ if (nofChildren) (void) XFree ((char*) children);
+
+ /*
+ * Build the appropriate event mask. The basic idea is that we don't
+ * want to interfere with the normal event propagation mechanism if
+ * we don't have to.
+ *
+ * On the root window, we need to ask for both substructureNotify
+ * and KeyPress events. On all other windows, we always need
+ * substructureNotify, but only need Keypress if some other client
+ * also asked for them, or if they are not being propagated up the
+ * window tree.
+ */
+#if 0
+ if (substructureOnly)
+ {
+ (void) XSelectInput (queue.display, window, SubstructureNotifyMask);
+ }
+ else
+ {
+ if (parent == None) /* the *real* rootwindow */
+ {
+ attribs.all_event_masks =
+ attribs.do_not_propagate_mask = KeyPressMask;
+ }
+ else if (!XGetWindowAttributes (queue.display, window, &attribs))
+#else
+ {
+ if (!XGetWindowAttributes (queue.display, window, &attribs))
+#endif
+ {
+ return;
+ }
+
+#if 0
+ (void) XSelectInput (queue.display, window,
+ SubstructureNotifyMask
+ | ( ( attribs.all_event_masks
+ | attribs.do_not_propagate_mask)
+ & KeyPressMask));
+#else
+ {
+ int mask = SubstructureNotifyMask | attribs.your_event_mask;
+ if( !substructureOnly )
+ {
+ mask |= ( ( attribs.all_event_masks
+ | attribs.do_not_propagate_mask)
+ & KeyPressMask );
+ }
+ (void) XSelectInput (queue.display, window, mask );
+ }
+#endif
+
+ }
+
+ /*
+ * Now ask for the list of children again, since it might have changed
+ * in between the last time and us selecting SubstructureNotifyMask.
+ *
+ * There is a (very small) chance that we might process a subtree twice:
+ * child windows that have been created after our XSelectinput() has
+ * been processed but before we get to the XQueryTree() bit will be
+ * in this situation. This is harmless. It could be avoided by using
+ * XGrabServer(), but that'd be an impolite thing to do, and since it
+ * isn't required...
+ */
+ if (!XQueryTree (queue.display, window, &root, &parent,
+ &children, &nofChildren))
+ {
+ return;
+ }
+
+ /*
+ * Now do the same thing for all children.
+ */
+ for (i = 0; i < nofChildren; ++i)
+ {
+ selectEvents (children[i], substructureOnly);
+ }
+
+ if (nofChildren) (void) XFree ((char*) children);
+}
+
+#if 0
+/*
+ * Function for processing any events that have come in since
+ * last time. It is crucial that this function does not block
+ * in case nothing interesting happened.
+ */
+void
+processEvents (void)
+{
+ while (XPending (queue.display))
+ {
+ XEvent event;
+
+ if (XCheckMaskEvent (queue.display, SubstructureNotifyMask, &event))
+ {
+ if (event.type == CreateNotify)
+ {
+ addToQueue (event.xcreatewindow.window);
+ }
+ }
+ else
+ {
+ (void) XNextEvent (queue.display, &event);
+ }
+
+ /*
+ * Reset the triggers if and only if the event is a
+ * KeyPress event *and* was not generated by XSendEvent().
+ */
+ if ( event.type == KeyPress
+ && !event.xany.send_event)
+ {
+ resetTriggers ();
+ }
+ }
+
+ /*
+ * Check the window queue for entries that are older than
+ * CREATION_DELAY seconds.
+ */
+ processQueue ((time_t) CREATION_DELAY);
+}
+#else
+void xautolock_processEvent( XEvent* event )
+{
+ if (event->type == CreateNotify)
+ {
+ addToQueue (event->xcreatewindow.window);
+ }
+ /*
+ * Reset the triggers if and only if the event is a
+ * KeyPress event *and* was not generated by XSendEvent().
+ */
+ if ( event->type == KeyPress
+ && !event->xany.send_event)
+ {
+ xautolock_resetTriggers ();
+ }
+}
+
+void xautolock_processQueue()
+{
+ /*
+ * Check the window queue for entries that are older than
+ * CREATION_DELAY seconds.
+ */
+ processQueue ((time_t) CREATION_DELAY);
+}
+#endif
+
+
+/*
+ * Function for initialising the whole shebang.
+ */
+void
+xautolock_initDiy (Display* d)
+{
+ int s;
+
+ queue.display = d;
+ queue.tail = 0;
+ queue.head = 0;
+
+ for (s = -1; ++s < ScreenCount (d); )
+ {
+ Window root = RootWindowOfScreen (ScreenOfDisplay (d, s));
+ addToQueue (root);
+#if 0
+ selectEvents (root, True);
+#endif
+ }
+}