📄 xautolock.c
字号:
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 ) { time (&now); if ( now >= ( trigger - time_limit ) + corner_delay ) { /* * If the pointer has not moved since the previous call and * is inside one of the 4 corners, we act according to the * contents of the "corners" array. * * If root_x and root_y are less than zero, don't lock even if * FORCE_LOCK is set in the upper-left corner. Why? 'cause * on initial server startup, IF the pointer is never moved, * XQueryPointer returns values less than zero (only some * servers, Openwindows 2.0 and 3.0 in particular). */ if ( root_x <= corner_size && root_x >= 0 && root_y <= corner_size && root_y >= 0) { return corners[0]; } else if ( root_x >= WidthOfScreen (screen) - corner_size - 1 && root_y <= corner_size) { return corners[1]; } else if ( root_x <= corner_size && root_y >= HeightOfScreen (screen) - corner_size - 1 ) { return corners[2]; } else if ( root_x >= WidthOfScreen (screen) - corner_size - 1 && root_y >= HeightOfScreen (screen) - corner_size - 1 ) { return corners[3]; } } } else { prev_root_x = root_x; prev_root_y = root_y; prev_mask = mask; SetTrigger (time_limit); } return 0;}/* * Function for deciding whether to lock * ------------------------------------- */static int EvaluateCounter (Display *){ 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 *, XErrorEvent * ){ return 0;}void setCorners( const char *cstring ){ char p; for ( int i = 0; i < 4; i++ ) { p = cstring[i]; if ( p == 0 ) break; switch ( p ) { case 'l': corners[i] = FORCE_LOCK; break; case 's': corners[i] = FORCE_SAVE; break; default: corners[i] = IGNORE; } }}volatile int timeoutNow = FALSE;void forceTimeout(){ timeoutNow = TRUE;}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 = qt_xdisplay(); 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 );}void cleanupAutoLock(){ int (*oldHandler)(Display *, XErrorEvent *); oldHandler = XSetErrorHandler( catchFalseAlarms ); FreeQueue( windowQueue ); XDestroyWindow( qt_xdisplay(), hiddenWin ); XSetErrorHandler( oldHandler );}/* * Main function * ------------- */int waitTimeout( int timeout ){ Display* d; /* display pointer */ int rv; int (*oldHandler)(Display *, XErrorEvent *); time_t now, prev; time_limit = timeout; d = qt_xdisplay(); oldHandler = XSetErrorHandler( catchFalseAlarms ); SetTrigger (time_limit); time(&prev); /* * Main event loop. */ while ( 1 ) { if ( timeoutNow ) { // this happens, when you send the screensaver a SIGUSR1 // this emits, that you want to lock the screen! rv = FORCE_LOCK; timeoutNow = FALSE; break; } ProcessEvents (d, windowQueue); rv = QueryPointer (d); if ( rv != IGNORE ) break; 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) ) { rv = IGNORE; 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 ); return rv;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -