Mercurial > pidgin
view src/idle.c @ 268:f8a29745247c
[gaim-migrate @ 278]
Two star college football players need to pass the final to play in the big
game. The professor loves football, but knows these guys aren't the brightest
bulbs in teh box, so he gives them a special final, puts them in a room by
themselves, and gives them an hour.
The guys look at each other, and start in on the final, which has only one
question: "What did Old MacDonald have?"
One guy looks at the other and says, "Do you know the answer to this?"
The other guy says, "Duh, a farm."
"How do you spell that?"
"Stupid! EIEIO!"
committer: Tailor Script <tailor@pidgin.im>
author | Eric Warmenhoven <eric@warmenhoven.org> |
---|---|
date | Thu, 25 May 2000 18:58:21 +0000 (2000-05-25) |
parents | 2846a03bda67 |
children | 5bad25457843 |
line wrap: on
line source
#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