Mercurial > pidgin.yaz
diff src/idle.c @ 1:2846a03bda67
[gaim-migrate @ 10]
The other missing files :)
committer: Tailor Script <tailor@pidgin.im>
author | Rob Flynn <gaim@robflynn.com> |
---|---|
date | Thu, 23 Mar 2000 03:13:54 +0000 |
parents | |
children | 5bad25457843 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/idle.c Thu Mar 23 03:13:54 2000 +0000 @@ -0,0 +1,648 @@ +#if 0 +//---------------------------------------------------------------------------- +// This is a somewhat modified kscreensaver. +// The original copyright notice follows +// +//---------------------------------------------------------------------------- +// +// KDE screensavers +// +// This module is a heavily modified xautolock. +// The orignal copyright notice follows +// + +/***************************************************************************** + * + * xautolock + * ========= + * + * Authors : S. De Troch (SDT) + M. Eyckmans (MCE) + * + * Date : 22/07/90 + * + * --------------------------------------------------------------------------- + * + * Copyright 1990, 1992-1995 by S. De Troch and MCE. + * + * Permission to use, copy, modify and distribute this software and the + * supporting documentation without fee is hereby granted, provided that + * + * 1 : Both the above copyright notice and this permission notice + * appear in all copies of both the software and the supporting + * documentation. + * 2 : No financial profit is made out of it. + * + * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL THEY BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL + * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA + * OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + *****************************************************************************/ + + + +/* + * Have a guess what this does... + * ============================== + * + * Warning for swm & tvtwm users : xautolock should *not* be compiled + * with vroot.h, because it needs to know the real root window. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#if defined(hpux) || defined (__hpux) +#ifndef _HPUX_SOURCE +#define _HPUX_SOURCE +#endif /* _HPUX_SOURCE */ +#endif /* hpux || __hpux */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#ifdef VMS +#include <ssdef.h> +#include <processes.h> /* really needed? */ +#endif /* VMS */ + +#include <X11/Xlib.h> +#include <X11/Xatom.h> +#include <X11/Xresource.h> + +#include <time.h> +#include <signal.h> +#include <sys/wait.h> +#include <sys/types.h> + +#ifdef HAVE_SYS_M_WAIT_H +#include <sys/m_wait.h> +#endif + +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <stdlib.h> + +#include <gdk/gdkx.h> +#include <gtk/gtk.h> +#include "gaim.h" + +void initAutoLock(); +void cleanupAutoLock(); + +/* + * Usefull macros and customization stuff + * ====================================== + */ +#define PP(x) x + +#ifdef VMS +#define ALL_OK 1 /* for use by exit () */ +#define PROBLEMS SS$_ABORT + /* for use by exit () */ +#else /* VMS */ +#define ALL_OK 0 /* for use by exit () */ +#define PROBLEMS 1 /* for use by exit () */ +#endif /* VMS */ + + +#define CREATION_DELAY 30 /* should be > 10 and + < min (45,(MIN_MINUTES*30)) */ +#define TIME_CHANGE_LIMIT 120 /* if the time changes by more + than x secs then we will + assume someone has changed + date or machine has suspended */ + + +#ifndef HasVFork +#define vfork fork +#endif /* HasVFork */ + +#define Error0(str) fprintf (stderr, str) +#define SetTrigger(delta) trigger = time ((time_t*) NULL) + delta + +static caddr_t ch_ptr; /* this is dirty */ +#define Skeleton(t,s) (ch_ptr = (Caddrt) malloc ((Unsigned) s), \ + (ch_ptr == (Caddrt) NULL) \ + ? (Error0 ("Out of memory.\n"), \ + exit (PROBLEMS), \ + /*NOTREACHED*/ (t*) NULL \ + ) \ + : (t*) ch_ptr \ + ) \ + +#define New(tp) Skeleton (tp, sizeof (tp)) + + + +/* + * New types + * ========= + */ +#if defined (apollo) || defined (news1800) +typedef int (*XErrorHandler) PP((Display*, + XErrorEvent*)); +#endif /* apollo || news1800 */ + +#if defined (news1800) || defined (sun386) +typedef int pid_t; +#endif /* news1800 || sun386*/ + +#ifdef VMS +typedef long pid_t; +#endif /* VMS */ + +#define Void void /* no typedef because of VAX */ +typedef int Int; +typedef char Char; +typedef char* String; +typedef int Boolean; +typedef caddr_t Caddrt; +typedef unsigned int Unsigned; +typedef unsigned long Huge; + +typedef struct QueueItem_ + { + Window window; /* as it says */ + time_t creationtime; /* as it says */ + struct QueueItem_* next; /* as it says */ + struct QueueItem_* prev; /* as it says */ + } aQueueItem, *QueueItem; + +typedef struct Queue_ + { + struct QueueItem_* head; /* as it says */ + struct QueueItem_* tail; /* as it says */ + } aQueue, *Queue; + + +/* + * Function declarations + * ===================== + */ +#if defined(news1800) +extern Void* malloc PP((Unsigned)); +#endif /* news1800 */ + +static int EvaluateCounter PP((Display*)); +static int QueryPointer PP((Display*, int)); +static int ProcessEvents PP((Display*, Queue, int)); +static Queue NewQueue PP((Void)); +static Void AddToQueue PP((Queue, Window)); +static Void ProcessQueue PP((Queue, Display*, time_t)); +static Void SelectEvents PP((Display*, Window, Boolean)); + + +/* + * Global variables + * ================ + */ +static time_t trigger = 0; /* as it says */ +static time_t time_limit = IDLE_REPORT_TIME; /* as it says */ + +/* + * Functions related to the window queue + * ===================================== + * + * Function for creating a new queue + * --------------------------------- + */ +static Queue NewQueue () + +{ + Queue queue; /* return value */ + + queue = New (aQueue); + queue->tail = New (aQueueItem); + queue->head = New (aQueueItem); + + queue->tail->next = queue->head; + queue->head->prev = queue->tail; + queue->tail->prev = queue->head->next = (QueueItem) NULL; + + return queue; +} + + +/* + * Function for adding an item to a queue + * -------------------------------------- + */ +static Void AddToQueue (Queue queue, Window window) +{ + QueueItem newq; /* new item */ + + newq = New (aQueueItem); + + newq->window = window; + newq->creationtime = time ((time_t*) NULL); + newq->next = queue->tail->next; + newq->prev = queue->tail; + queue->tail->next->prev = newq; + queue->tail->next = newq; +} + +/* + * Function for processing those entries that are old enough + * --------------------------------------------------------- + */ +static Void ProcessQueue (Queue queue, Display *d, time_t age) +{ + QueueItem current; /* as it says */ + time_t now; /* as it says */ + + time (&now); + current = queue->head->prev; + + while ( current->prev && current->creationtime + age < now ) + { + SelectEvents (d, current->window, False); + current = current->prev; + free (current->next); + } + + current->next = queue->head; + queue->head->prev = current; +} + + +static Void FreeQueue( Queue queue ) +{ + QueueItem current; /* as it says */ + + current = queue->head->prev; + + while ( current->prev ) + { + current = current->prev; + free(current->next); + } + + free(current); + free(queue); +} + + +/* + * Functions related to (the lack of) user activity + * ================================================ + * + * Function for processing the event queue + * --------------------------------------- + */ +static int ProcessEvents (Display *d, Queue queue, int until_idle) +{ + XEvent event; /* as it says */ + + /* + * Read whatever is available for reading. + */ + while (XPending (d)) + { + if (XCheckMaskEvent (d, SubstructureNotifyMask, &event)) + { + if ((event.type == CreateNotify) && until_idle) + { + AddToQueue (queue, event.xcreatewindow.window); + } + } + else + { + XNextEvent (d, &event); + } + + + /* + * Reset the counter if and only if the event is a KeyPress + * event *and* was not generated by XSendEvent (). + */ + if ( event.type == KeyPress && !event.xany.send_event ) + { + if (!until_idle) /* We've become un-idle */ + return 1; + SetTrigger (time_limit); + } + } + + + /* + * Check the window queue for entries that are older than + * CREATION_DELAY seconds. + */ + ProcessQueue (queue, d, (time_t) CREATION_DELAY); + return 0; +} + + +/* + * Function for monitoring pointer movements + * ----------------------------------------- + */ +static int QueryPointer (Display *d, int until_idle) +{ + Window dummy_w; /* as it says */ + Int dummy_c; /* as it says */ + Unsigned mask; /* modifier mask */ + Int root_x; /* as it says */ + Int root_y; /* as it says */ + Int i; /* loop counter */ + static Window root; /* root window the pointer is on */ + static Screen* screen; /* screen the pointer is on */ + static Unsigned prev_mask = 0; /* as it says */ + static Int prev_root_x = -1; /* as it says */ + static Int prev_root_y = -1; /* as it says */ + static Boolean first_call = TRUE; /* as it says */ + + + /* + * Have a guess... + */ + if (first_call) + { + first_call = FALSE; + root = DefaultRootWindow (d); + screen = ScreenOfDisplay (d, DefaultScreen (d)); + } + + + /* + * Find out whether the pointer has moved. Using XQueryPointer for this + * is gross, but it also is the only way never to mess up propagation + * of pointer events. + * + * Remark : Unlike XNextEvent(), XPending () doesn't notice if the + * connection to the server is lost. For this reason, earlier + * versions of xautolock periodically called XNoOp (). But + * why not let XQueryPointer () do the job for us, since + * we now call that periodically anyway? + */ + if (!XQueryPointer (d, root, &root, &dummy_w, &root_x, &root_y, + &dummy_c, &dummy_c, &mask)) + { + /* + * Pointer has moved to another screen, so let's find out which one. + */ + for (i = -1; ++i < ScreenCount (d); ) + { + if (root == RootWindow (d, i)) + { + screen = ScreenOfDisplay (d, i); + break; + } + } + } + + if ( root_x != prev_root_x + || root_y != prev_root_y + || mask != prev_mask + ) + { + prev_root_x = root_x; + prev_root_y = root_y; + prev_mask = mask; + SetTrigger (time_limit); + if (!until_idle) + return 1; + } + + return 0; + +} + +/* + * Function for deciding whether to lock + * ------------------------------------- + */ +static int EvaluateCounter (Display *d) +{ + time_t now = 0; /* as it says */ + + /* + * Now trigger the notifier if required. + */ + time (&now); + + /* + * Finally fire up the locker if time has come. + */ + if (now >= trigger) + { + SetTrigger (time_limit); + return TRUE; + } + + return FALSE; +} + +/* + * Function for selecting events on a tree of windows + * -------------------------------------------------- + */ +static Void SelectEvents (Display *d, Window window, Boolean substructure_only) +{ + Window root; /* root window of this window */ + Window parent; /* parent of this window */ + Window* children; /* children of this window */ + Unsigned nof_children = 0; /* number of children */ + Unsigned i; /* loop counter */ + XWindowAttributes attribs; /* attributes of the window */ + + + /* + * Start by querying the server about parent and child windows. + */ + if (!XQueryTree (d, window, &root, &parent, &children, &nof_children)) + { + return; + } + + + /* + * 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. + */ + if (substructure_only) + { + XSelectInput (d, window, SubstructureNotifyMask); + } + else + { + if (parent == None) /* the *real* rootwindow */ + { + attribs.all_event_masks = + attribs.do_not_propagate_mask = KeyPressMask; + } + else if (XGetWindowAttributes (d, window, &attribs) == 0) + { + return; + } + + XSelectInput (d, window, SubstructureNotifyMask + | ( ( attribs.all_event_masks + | attribs.do_not_propagate_mask) + & KeyPressMask)); + } + + + /* + * Now do the same thing for all children. + */ + for (i = 0; i < nof_children; ++i) + { + SelectEvents (d, children[i], substructure_only); + } + + if (nof_children) XFree ((Char*) children); +} + + +int catchFalseAlarms( Display *d, XErrorEvent *x ) +{ + return 0; +} + +Queue windowQueue; +Window hiddenWin; /* hidden window */ + +void initAutoLock() +{ + Display* d; /* display pointer */ + Window r; /* root window */ + Int s; /* screen index */ + XSetWindowAttributes attribs; /* for dummy window */ + int (*oldHandler)(Display *, XErrorEvent *); + + d = GDK_DISPLAY(); + + oldHandler = XSetErrorHandler( catchFalseAlarms ); + XSync (d, 0); + + windowQueue = NewQueue (); + + for (s = -1; ++s < ScreenCount (d); ) + { + AddToQueue (windowQueue, r = RootWindowOfScreen (ScreenOfDisplay (d, s))); + SelectEvents (d, r, True); + } + + /* + * Get ourselves a dummy window in order to allow display and/or + * session managers etc. to use XKillClient() on us (e.g. xdm when + * not using XDMCP). + * + * I'm not sure whether the window needs to be mapped for xdm, but + * the default set up Sun uses for OpenWindows and olwm definitely + * requires it to be mapped. + */ + attribs.override_redirect = True; + hiddenWin = XCreateWindow (d, DefaultRootWindow (d), -100, -100, 1, 1, 0, + CopyFromParent, InputOnly, CopyFromParent, CWOverrideRedirect, + &attribs); + + XMapWindow (d, hiddenWin ); + + XSetErrorHandler( oldHandler ); +} + +/* I don't think this should be needed, but leaving the code here + in case I change my mind. */ +/* +void cleanupAutoLock() +{ + int (*oldHandler)(Display *, XErrorEvent *); + oldHandler = XSetErrorHandler( catchFalseAlarms ); + + FreeQueue( windowQueue ); + XDestroyWindow( GDK_DISPLAY(), hiddenWin ); + XSetErrorHandler( oldHandler ); +} +*/ + +/* + * Main function + * ------------- + */ +void waitIdle( int timeout, int until_idle ) +{ + Display* d; /* display pointer */ + int (*oldHandler)(Display *, XErrorEvent *); + time_t now, prev; + + time_limit = timeout; + + d = GDK_DISPLAY(); + + oldHandler = XSetErrorHandler( catchFalseAlarms ); + + SetTrigger (time_limit); + + time(&prev); + + /* + * Main event loop. + */ + while ( 1 ) + { + if (ProcessEvents (d, windowQueue, until_idle)) + break; + if (QueryPointer (d, until_idle)) + break; + + if (until_idle) { + time(&now); + + if ((now > prev && now - prev > TIME_CHANGE_LIMIT) || + (prev > now && prev - now > TIME_CHANGE_LIMIT+1)) + { + /* the time has changed in one large jump. This could be because the + date was changed, or the machine was suspended. We'll just + reset the triger. */ + SetTrigger (time_limit); + } + + prev = now; + + if ( EvaluateCounter (d) ) + break; + } + + /* + * It seems that, on some operating systems (VMS to name just one), + * sleep () can be vastly inaccurate: sometimes 60 calls to sleep (1) + * add up to only 30 seconds or even less of sleeping. Therefore, + * as of patchlevel 9 we no longer rely on it for keeping track of + * time. The only reason why we still call it, is to make xautolock + * (which after all uses a busy-form-of-waiting algorithm), less + * processor hungry. + */ + sleep (1); + } + + XSetErrorHandler( oldHandler ); + +} + +void idle_main(pid_t gaimpid) { + initAutoLock(); + while (1) { + waitIdle(IDLE_REPORT_TIME, 1); + kill(gaimpid, SIGALRM); + sleep(1); /* Just to be safe */ + waitIdle(1, 0); + kill(gaimpid, SIGALRM); + } +} + + +#endif \ No newline at end of file