unclutter-8/000075500000000000000000000000001125771730100132525ustar00rootroot00000000000000unclutter-8/Imakefile000064400000000000000000000000731125771730100150630ustar00rootroot00000000000000LOCAL_LIBRARIES = $(XLIB) SimpleProgramTarget(unclutter) unclutter-8/Makefile000064400000000000000000000037141125771730100147170ustar00rootroot00000000000000# Makefile for unclutter. Throw this away and use the Imakefile if you can. TOP = . CURRENT_DIR = . CC = gcc LKED = $(CC) INSTALL = install MAKE = make MV = mv RM = rm -f TAGS = ctags MFLAGS = -$(MAKEFLAGS) INSTPGMFLAGS = -c -s INSTMANFLAGS = -c TOP_INCLUDES = -I$(INCROOT) CDEBUGFLAGS = -O ALLINCLUDES = $(STD_INCLUDES) $(TOP_INCLUDES) $(INCLUDES) $(EXTRA_INCLUDES) ALLDEFINES = $(ALLINCLUDES) $(STD_DEFINES) $(PROTO_DEFINES) $(DEFINES) $(COMPATFLAGS) CFLAGS = $(CDEBUGFLAGS) $(CCOPTIONS) $(ALLDEFINES) LDLIBS = $(SYS_LIBRARIES) $(EXTRA_LIBRARIES) LDOPTIONS = $(CDEBUGFLAGS) $(CCOPTIONS) RM_CMD = $(RM) *.CKP *.ln *.BAK *.bak *.o core errs ,* *~ *.a .emacs_* tags TAGS make.log MakeOut IRULESRC = $(CONFIGDIR) IMAKE_CMD = $(IMAKE) -DUseInstalled -I$(IRULESRC) $(IMAKE_DEFINES) BINDIR = $(DESTDIR)/usr/bin/X11 INCROOT = $(DESTDIR)/usr/include MANPATH = $(DESTDIR)/usr/catman/x11_man MANSOURCEPATH = $(MANPATH)/man MANDIR = $(MANSOURCEPATH)1 IMAKE = imake XLIB = $(EXTENSIONLIB) -lX11 LOCAL_LIBRARIES = $(XLIB) OBJS = unclutter.o SRCS = unclutter.c PROGRAM = unclutter all:: unclutter unclutter: $(OBJS) $(DEPLIBS) $(RM) $@ $(LKED) -o $@ $(OBJS) $(LDOPTIONS) $(LOCAL_LIBRARIES) $(LDLIBS) $(EXTRA_LOAD_FLAGS) install:: unclutter $(INSTALL) -c $(INSTPGMFLAGS) unclutter $(BINDIR) install.man:: unclutter.man $(INSTALL) -c $(INSTMANFLAGS) unclutter.man $(MANDIR)/unclutter.1 clean:: $(RM) $(PROGRAM) $(RM_CMD) \#* Makefile:: -@if [ -f Makefile ]; then \ echo " $(RM) Makefile.bak; $(MV) Makefile Makefile.bak"; \ $(RM) Makefile.bak; $(MV) Makefile Makefile.bak; \ else exit 0; fi $(IMAKE_CMD) -DTOPDIR=$(TOP) -DCURDIR=$(CURRENT_DIR) tags:: $(TAGS) -w *.[ch] $(TAGS) -xw *.[ch] > TAGS unclutter-8/README000064400000000000000000000034141125771730100141340ustar00rootroot00000000000000unclutter is a program which runs permanently in the background of an X11 session. It checks on the X11 pointer (cursor) position every few seconds, and when it finds it has not moved (and no buttons are pressed on the mouse, and the cursor is not in the root window) it creates a small sub-window as a child of the window the cursor is in. The new window installs a cursor of size 1x1 but a mask of all 0, ie an invisible cursor. This allows you to see all the text in an xterm or xedit, for example. The human factors crowd would agree it should make things less distracting. Once created, the program waits for the pointer to leave the window and then destroys it, restoring the original situation. Button events are passed transparently through to the parent window. They will usually cause the cursor to reappear because an active grab will be made by the program while the button is down, so the pointer will apparently leave the window, even though its x y position doesnt change. The first version of this program used a grab to remove the cursor. This method is still available with a "-grab" option to the program. Thanks for their help with "remote debugging" with xscope of various servers to dave edsall@iastate.edu Roland McGrath Rainer Sinkwitz Michael L. Brown astroatc!ftms!brown@cs.wisc.edu patti@hosehead.hf.intel.com and, for vroot.h, Andreas Stolcke , and, for finding and fixing the bug where server button grabs render unclutter mute, Charles Hannum and to all those who tested various development versions sent by mail. The program is released into the public domain. Only the considerate will leave credit for the author. Mark M Martin. mmm@cetia.fr sep 1992. unclutter-8/patchlevel.h000064400000000000000000000016611125771730100155560ustar00rootroot00000000000000/* * unclutter: * level 0: initial release * level 1: -grab option to use old method, new method creates small input * only sub-window. (distributed by mail only, not posted) * level 2: use Andreas Stolcke's vroot.h for tvtwm and similar winmans. * level 3: -not option takes list of windows to avoid and -visible ignores * visibility events for some servers. * level 4: create an unused window so that xdm can find us to kill. * level 5: send an EnterNotify pseudo event to client to pretend did not leave * window. Useful for emacs. -noevents option will cancel. * level 6: replace XQueryPointer by looking for EnterNotify event, else * get confused during button grabs and never remove cursor again. * [Bug found and fixed thanks to Charles Hannum ] * level 7: manage all screens on display. * level 8: -keystroke option from Bill Trost trost@cloud.rain.com. */ #define PATCHLEVEL 8 unclutter-8/unclutter.c000064400000000000000000000263751125771730100154600ustar00rootroot00000000000000/* * unclutter: remove idle cursor image from screen so that it doesnt * obstruct the area you are looking at. * doesn't do it if cursor is in root window or a button is down. * polls mouse to see if is stationary, or waits for a keyup event on the * screen. These will only arrive in windows of applications that dont * wait for keyup themselves. We could only do better by using the XTest * extensions and so getting all keystroke events. * Tries to cope with jitter if you have a mouse that twitches. * Unfortunately, clients like emacs set different text cursor * shapes depending on whether they have pointer focus or not. * Try to kid them with a synthetic EnterNotify event. * Whereas version 1 did a grab cursor, version 2 creates a small subwindow. * This may work better with some window managers. * Some servers return a Visibility event when the subwindow is mapped. * Sometimes this is Unobscured, or even FullyObscured. Ignore these and * rely on LeaveNotify events. (An InputOnly window is not supposed to get * visibility events.) * Mark M Martin. cetia feb 1994 mmm@cetia.fr * keystroke code from Bill Trost trost@cloud.rain.com */ #include #include #include #include #include #include "vroot.h" char *progname; pexit(str)char *str;{ fprintf(stderr,"%s: %s\n",progname,str); exit(1); } usage(){ pexit("usage:\n\ -display \n\ -idle time between polls to detect idleness.\n\ -keystroke wait for keystroke before idling.\n\ -jitter pixels mouse can twitch without moving\n\ -grab use grabpointer method not createwindow\n\ -reset reset the timer whenever cursor becomes\n\ visible even if it hasn't moved\n\ -root apply to cursor on root window too\n\ -onescreen apply only to given screen of display\n\ -visible ignore visibility events\n\ -noevents dont send pseudo events\n\ -not names... dont apply to windows whose wm-name begins.\n\ (must be last argument)"); } #define ALMOSTEQUAL(a,b) (abs(a-b)<=jitter) #define ANYBUTTON (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask) /* Since the small window we create is a child of the window the pointer is * in, it can be destroyed by its adoptive parent. Hence our destroywindow() * can return an error, saying it no longer exists. Similarly, the parent * window can disappear while we are trying to create the child. Trap and * ignore these errors. */ int (*defaulthandler)(); int errorhandler(display,error) Display *display; XErrorEvent *error; { if(error->error_code!=BadWindow) (*defaulthandler)(display,error); } char **names; /* -> argv list of names to avoid */ /* * return true if window has a wm_name and the start of it matches * one of the given names to avoid */ nameinlist(display,window) Display *display; Window window; { char **cpp; char *name; if(names==0)return 0; if(XFetchName (display, window, &name)){ for(cpp = names;*cpp!=0;cpp++){ if(strncmp(*cpp,name,strlen(*cpp))==0) break; } XFree(name); return(*cpp!=0); } return 0; } /* * create a small 1x1 curssor with all pixels masked out on the given screen. */ createnullcursor(display,root) Display *display; Window root; { Pixmap cursormask; XGCValues xgc; GC gc; XColor dummycolour; Cursor cursor; cursormask = XCreatePixmap(display, root, 1, 1, 1/*depth*/); xgc.function = GXclear; gc = XCreateGC(display, cursormask, GCFunction, &xgc); XFillRectangle(display, cursormask, gc, 0, 0, 1, 1); dummycolour.pixel = 0; dummycolour.red = 0; dummycolour.flags = 04; cursor = XCreatePixmapCursor(display, cursormask, cursormask, &dummycolour,&dummycolour, 0,0); XFreePixmap(display,cursormask); XFreeGC(display,gc); return cursor; } main(argc,argv)char **argv;{ Display *display; int screen,oldx = -99,oldy = -99,numscreens; int doroot = 0, jitter = 0, idletime = 5, usegrabmethod = 0, waitagain = 0, dovisible = 1, doevents = 1, onescreen = 0; Cursor *cursor; Window *realroot; Window root; char *displayname = 0; progname = *argv; argc--; while(argv++,argc-->0){ if(strcmp(*argv,"-idle")==0){ argc--,argv++; if(argc<0)usage(); idletime = atoi(*argv); }else if(strcmp(*argv,"-keystroke")==0){ idletime = -1; }else if(strcmp(*argv,"-jitter")==0){ argc--,argv++; if(argc<0)usage(); jitter = atoi(*argv); }else if(strcmp(*argv,"-noevents")==0){ doevents = 0; }else if(strcmp(*argv,"-root")==0){ doroot = 1; }else if(strcmp(*argv,"-grab")==0){ usegrabmethod = 1; }else if(strcmp(*argv,"-reset")==0){ waitagain = 1; }else if(strcmp(*argv,"-onescreen")==0){ onescreen = 1; }else if(strcmp(*argv,"-visible")==0){ dovisible = 0; }else if(strcmp(*argv,"-not")==0){ /* take rest of srg list */ names = ++argv; if(*names==0)names = 0; /* no args follow */ argc = 0; }else if(strcmp(*argv,"-display")==0 || strcmp(*argv,"-d")==0){ argc--,argv++; if(argc<0)usage(); displayname = *argv; }else usage(); } display = XOpenDisplay(displayname); if(display==0)pexit("could not open display"); numscreens = ScreenCount(display); cursor = (Cursor*) malloc(numscreens*sizeof(Cursor)); realroot = (Window*) malloc(numscreens*sizeof(Window)); /* each screen needs its own empty cursor. * note each real root id so can find which screen we are on */ for(screen = 0;screen=numscreens) pexit("not on a known screen"); } root = VirtualRootWindow(display,screen); }else if((!doroot && windowin==None) || (modifs & ANYBUTTON) || !(ALMOSTEQUAL(rootx,oldx) && ALMOSTEQUAL(rooty,oldy))){ oldx = rootx, oldy = rooty; }else if(windowin==None){ windowin = root; break; }else if(windowin!=lastwindowavoided){ /* descend tree of windows under cursor to bottommost */ Window childin; int toavoid = xFalse; lastwindowavoided = childin = windowin; do{ windowin = childin; if(nameinlist (display, windowin)){ toavoid = xTrue; break; } }while(XQueryPointer(display, windowin, &dummywin, &childin, &rootx, &rooty, &winx, &winy, &modifs) && childin!=None); if(!toavoid){ lastwindowavoided = None; break; } } if(idletime>=0) sleep(idletime); } /* wait again next time */ if(waitagain) oldx = -1-jitter; if(usegrabmethod){ if(XGrabPointer(display, root, 0, PointerMotionMask|ButtonPressMask|ButtonReleaseMask, GrabModeAsync, GrabModeAsync, None, cursor[screen], CurrentTime)==GrabSuccess){ /* wait for a button event or large cursor motion */ XEvent event; do{ XNextEvent(display,&event); }while(event.type==KeyRelease || (event.type==MotionNotify && ALMOSTEQUAL(rootx,event.xmotion.x) && ALMOSTEQUAL(rooty,event.xmotion.y))); XUngrabPointer(display, CurrentTime); } }else{ XSetWindowAttributes attributes; XEvent event; Window cursorwindow; /* create small input-only window under cursor * as a sub window of the window currently under the cursor */ attributes.event_mask = LeaveWindowMask | EnterWindowMask | StructureNotifyMask | FocusChangeMask; if(dovisible) attributes.event_mask |= VisibilityChangeMask; attributes.override_redirect = True; attributes.cursor = cursor[screen]; cursorwindow = XCreateWindow (display, windowin, winx-jitter, winy-jitter, jitter*2+1, jitter*2+1, 0, CopyFromParent, InputOnly, CopyFromParent, CWOverrideRedirect | CWEventMask | CWCursor, &attributes); /* discard old events for previously created windows */ XSync(display,True); XMapWindow(display,cursorwindow); /* * Dont wait for expose/map cos override and inputonly(?). * Check that created window captured the pointer by looking * for inevitable EnterNotify event that must follow MapNotify. * [Bug fix thanks to Charles Hannum ] */ XSync(display,False); if(!XCheckTypedWindowEvent(display, cursorwindow, EnterNotify, &event)) oldx = -1-jitter; /* slow down retry */ else{ if(doevents){ /* * send a pseudo EnterNotify event to the parent window * to try to convince application that we didnt really leave it */ event.xcrossing.type = EnterNotify; event.xcrossing.display = display; event.xcrossing.window = windowin; event.xcrossing.root = root; event.xcrossing.subwindow = None; event.xcrossing.time = CurrentTime; event.xcrossing.x = winx; event.xcrossing.y = winy; event.xcrossing.x_root = rootx; event.xcrossing.y_root = rooty; event.xcrossing.mode = NotifyNormal; event.xcrossing.same_screen = True; event.xcrossing.focus = True; event.xcrossing.state = modifs; (void)XSendEvent(display,windowin, True/*propagate*/,EnterWindowMask,&event); } /* wait till pointer leaves window */ do{ XNextEvent(display,&event); }while(event.type!=LeaveNotify && event.type!=FocusOut && event.type!=UnmapNotify && event.type!=ConfigureNotify && event.type!=CirculateNotify && event.type!=ReparentNotify && event.type!=DestroyNotify && (event.type!=VisibilityNotify || event.xvisibility.state==VisibilityUnobscured) ); /* check if a second unclutter is running cos they thrash */ if(event.type==LeaveNotify && event.xcrossing.window==cursorwindow && event.xcrossing.detail==NotifyInferior) pexit("someone created a sub-window to my sub-window! giving up"); } XDestroyWindow(display, cursorwindow); } } } unclutter-8/unclutter.man000064400000000000000000000066021125771730100160000ustar00rootroot00000000000000.\"unclutter man .TH UNCLUTTER 1X .SH NAME unclutter \- remove idle cursor image from screen .SH SYNOPSIS .B unclutter .RB [ -display | -d .IR display ] .RB [ -idle .IR seconds ] .RB [ -keystroke ] .RB [ -jitter .IR pixels ] .RB [ -grab ] .RB [ -noevents ] .RB [ -reset ] .RB [ -root ] .RB [ -onescreen ] .RB [ -not ] .I "name ... .SH DESCRIPTION .B unclutter removes the cursor image from the screen so that it does not obstruct the area you are looking at after it has not moved for a given time. It does not do this if the cursor is in the root window or a button is down. It tries to ignore jitter (small movements due to noise) if you have a mouse that twitches. .SH OPTIONS .TP -display is followed by the display to open. .TP -idle is followed by the number of seconds between polls for idleness. The default is 5. .TP -keystroke tells .B unclutter not to use a timeout to determine when to remove the cursor, but to instead wait until a key has been pressed (released, really). .TP -jitter is followed by the amount of movement of the pointer that is to be ignored and considered as random noise. The default is 0. .TP -grab means use the original method of grabbing the pointer in order to remove the cursor. This often doesn't interoperate too well with some window managers. .TP -noevents stops unclutter sending a pseudo EnterNotify event to the X client whose cursor has been stolen. Sending the event helps programs like emacs think that they have not lost the pointer focus. This option is provided for backwards compatibility in case some clients get upset. .TP -reset resets the timeout for idleness after the cursor is restored for some reason (such as a window being pushed or popped) even though the x y coordinates of the cursor have not changed. Normally, the cursor would immediately be removed again. .TP -root means remove the cursor even if it is on the root background, where in principle it should not be obscuring anything useful. .TP -onescreen restricts unclutter to the single screen specified as display, or the default screen for the display. Normally, unclutter will unclutter all the screens on a display. .TP -not is followed by a list of window names where the cursor should not be removed. The first few characters of the WM_NAME property on the window need to match one the listed names. This argument must be the last on the command line. .SH LIMITATIONS The -keystroke option may not work (that is, the cursor will not disappear) with clients that request KeyRelease events. Games and Xt applications using KeyUp in their translation tables are most likely to suffer from this problem. The most feasible solution is to extend unclutter to use the XTest extension to get all keyboard and mouse events, though this of course requires XTest to be in the server too. .PP The -keystroke option does not distinguish modifier keys from keys which actually generate characters. If desired this could be implemented in a simple way by using XLookupString to see if any characters are returned. .SH DIAGNOSTICS The message .sp someone created a sub-window to my sub-window! .sp means that unclutter thinks a second unclutter is running, and tried to steal the cursor by creating a sub-window to the sub-window already used to steal the cursor. This situation quickly deteriorates into a fight no one can win, so it is detected when possible and the program gives up. .SH AUTHOR Mark M Martin. cetia 7feb1994. mmm@cetia.fr unclutter-8/vroot.h000064400000000000000000000054571125771730100146070ustar00rootroot00000000000000/* * Article 12523 of comp.windows.x: * From: stolcke@ICSI.Berkeley.EDU (Andreas Stolcke) * Subject: Converting programs to virtual root * Date: 8 Sep 90 02:26:14 GMT * * Andreas Stolcke * International Computer Science Institute stolcke@icsi.Berkeley.EDU * 1957 Center St., Suite 600, Berkeley, CA 94704 (415) 642-4274 ext. 126 * * vroot.h -- Virtual Root Window handling header file * * This header file redefines the X11 macros RootWindow and DefaultRootWindow, * making them look for a virtual root window as provided by certain `virtual' * window managers like swm and tvtwm. If none is found, the ordinary root * window is returned, thus retaining backward compatibility with standard * window managers. * The function implementing the virtual root lookup remembers the result of * its last invocation to avoid overhead in the case of repeated calls * on the same display and screen arguments. * The lookup code itself is taken from Tom LaStrange's ssetroot program. * * Most simple root window changing X programs can be converted to using * virtual roots by just including * * #include "vroot.h" * * after all the X11 header files. It has been tested on such popular * X clients as xphoon, xfroot, xloadimage, and xaqua. * * Andreas Stolcke , 9/7/90 * - replaced all NULL's with properly cast 0's, 5/6/91 * - free children list (suggested by Mark Martin ), 5/16/91 */ #define DONTOPTIMISE /* unclutter needs to search from scratch each time */ #include #include static Window VirtualRootWindow(dpy, screen) Display *dpy; { static Display *save_dpy = (Display *)0; static int save_screen = -1; static Window root = (Window)0; #ifdef DONTOPTIMISE { #else if (dpy != save_dpy || screen != save_screen) { #endif Atom __SWM_VROOT = None; int i; Window rootReturn, parentReturn, *children; unsigned int numChildren; root = RootWindow(dpy, screen); /* go look for a virtual root */ __SWM_VROOT = XInternAtom(dpy, "__SWM_VROOT", False); if (XQueryTree(dpy, root, &rootReturn, &parentReturn, &children, &numChildren)) { for (i = 0; i < numChildren; i++) { Atom actual_type; int actual_format; unsigned long nitems, bytesafter; Window *newRoot = (Window *)0; if (XGetWindowProperty(dpy, children[i], __SWM_VROOT, 0, 1, False, XA_WINDOW, &actual_type, &actual_format, &nitems, &bytesafter, (unsigned char **) &newRoot) == Success && newRoot) { root = *newRoot; break; } } if (children) XFree((char *)children); } save_dpy = dpy; save_screen = screen; } return root; } #undef DefaultRootWindow #define DefaultRootWindow(dpy) RootWindow(dpy, DefaultScreen(dpy)) #undef RootWindow #define RootWindow(dpy,screen) VirtualRootWindow(dpy,screen)