/* wmswallow.c */ /* #define DEBUG 1 */ /* Sometimes i want to get quick access to this flag :-)*/ /* Time-stamp: <00/05/15 23:13:43 friedel> */ /* Copyright 2000 Friedrich Delgado Friedrichs */ /* Swallow applications in the Windowmaker dock */ /* Originally i started with asbeats 0.2 (by iznogood@bohemians.org) (simply the smallest WindowMaker dockapp i could find, since there was no proper Documentation to find on how to make an app dockable), which i stripped down to have a basic dockable app, and then stole code from fvwm2 to swallow an Application */ /* Man, this was easy! Why did nobody implement this before? (That's me, looking astonished at the first working version at Mon Apr 17 02:16:31 CEST 2000 after only 4 hours of mostly learning how to program the X-Environment and hacking and guessing a little :-) */ #include #include #include #include #include #include #include #include #include #include "version.h" /* That's all we need from xpm.h */ #if ! defined(_XtIntrinsic_h) && ! defined(PIXEL_ALREADY_TYPEDEFED) typedef unsigned long Pixel; /* Index into colormap */ # define PIXEL_ALREADY_TYPEDEFED #endif /* Now we got rid of that stupid libXpm dependency :-) */ #define WIDTH 55 #define HEIGHT 57 /* 55x57 seems to be the default size for a WindowMaker dockapp */ /* settable by "-geometry" switch */ Display *dpy; Window Root; Window iconwin,win; Window swallowed; XSizeHints mysizehints; #define MW_EVENTS (ExposureMask | ButtonPressMask |\ StructureNotifyMask |\ ButtonReleaseMask |\ EnterWindowMask|LeaveWindowMask) #define SW_EVENTS (PropertyChangeMask | StructureNotifyMask |\ ResizeRedirectMask | SubstructureNotifyMask) #define FIND_EVENTS (SubstructureNotifyMask | StructureNotifyMask) #define READY_EVENTS FIND_EVENTS #define FALSE 0 #define TRUE (!FALSE) Pixel GetColor(char *name); void FlushWindow(); void usage (char *progname); int parseargs(int argc, char *argv[]); Window findnamedwindow (char *class); Window findnamedwindowacc (char *class, Window window); int checkwindow (Window window, char *class); int execstuff(int argc, char *oldargv[]); Window startandfind(int argc, char *oldargv[], char* class); int printlist(FILE * stream, char * string, char **stringlist); int flush_expose (Window w); void stealshape (Window w); int sendexpose (Window w); void waitformap (Window win); /* int softenwindow (Window w); */ /* won't work, kept for historical reasons */ /* Parameters that can be customized via commandline switches */ char *execstring=NULL; char *geometry=NULL; int getclick=FALSE; int shape=TRUE; int focus=FALSE; int unmanaged=FALSE; int winid=0; char *display_name=NULL; int main(int argc,char *argv[]) { int screen; int d_depth; XWMHints mywmhints; Pixel back_pix,fore_pix; int i; unsigned int borderwidth; char *wname="wmswallow"; int remainarg, remainargc; XEvent Event; XTextProperty name; XClassHint classHint; remainarg=parseargs(argc, argv); /* remainarg > 0 afterwards */ remainargc=argc-remainarg; #ifdef DEBUG fprintf(stderr, "remainarg: %d, remainargc: %d, argc: %d\n", remainarg, remainargc,argc); fflush(stderr); #endif if (!(dpy = XOpenDisplay(display_name))) { fprintf(stderr,"wmswallow: can't open display %s\n", XDisplayName(display_name)); exit (1); } screen=DefaultScreen(dpy); Root=RootWindow(dpy, screen); /* So, now we've got everything we need to get Events from the XServer */ if (remainargc>1) { winid=startandfind(remainargc-1, argv+remainarg+1, argv[remainarg]); if (winid==0) { perror("wmswallow: startandfind failed"); /* Real error handling in execstuff()*/ exit (1); } } d_depth=DefaultDepth(dpy, screen); /* XConnectionNumber(dpy); */ /* useless */ mysizehints.flags=USSize|USPosition; mysizehints.x=0; mysizehints.y=0; back_pix=GetColor("white"); fore_pix=GetColor("black"); XWMGeometry(dpy, screen, geometry, NULL, (borderwidth =1), &mysizehints, &mysizehints.x, &mysizehints.y, &mysizehints.width, &mysizehints.height, &i); mysizehints.width=WIDTH; mysizehints.height=HEIGHT; if (geometry!=NULL) { #ifdef DEBUG fprintf(stderr,"Setting geometry to: %s\n",geometry); fflush(stderr); #endif XParseGeometry(geometry, &mysizehints.x, &mysizehints.y, &mysizehints.width, &mysizehints.height); } win=XCreateSimpleWindow(dpy, Root, mysizehints.x, mysizehints.y, mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix); iconwin=XCreateSimpleWindow(dpy, win, mysizehints.x, mysizehints.y, mysizehints.width, mysizehints.height, borderwidth, fore_pix, back_pix); XSetWMNormalHints(dpy, win, &mysizehints); classHint.res_name="wmswallow"; classHint.res_class="WMswallow"; XSetClassHint(dpy, win, &classHint); XSelectInput(dpy, win, MW_EVENTS); XSelectInput(dpy, iconwin, MW_EVENTS); if(XStringListToTextProperty(&wname, 1, &name)==0) { fprintf(stderr, "wmswallow: can't allocate window name\n"); exit(-1); } XSetWMName(dpy, win, &name); mywmhints.initial_state = WithdrawnState; mywmhints.icon_window = iconwin; mywmhints.icon_x = mysizehints.x; mywmhints.icon_y = mysizehints.y; mywmhints.window_group = win; mywmhints.flags = StateHint | IconWindowHint | IconPositionHint | WindowGroupHint; XSetWMHints(dpy, win, &mywmhints); XSetCommand(dpy, win, argv, argc); if (winid==0) { swallowed=findnamedwindow(argv[remainarg]); /* Find which window to swallow*/ #ifdef DEBUG fprintf(stderr,"%s has Window-id 0x%lx\n", argv[remainarg], swallowed); fflush(stderr); #endif } else swallowed=winid; /* "Swallow" it */ XReparentWindow(dpy, swallowed, iconwin, 0, 0); if (getclick) { /* softenwindow (swallowed); */ /* Change some attributes */ XSelectInput(dpy, swallowed, SW_EVENTS|ButtonPressMask); } else { XSelectInput(dpy, swallowed, SW_EVENTS); /* Workaround for apps like perfmeter that don't let us get their mouseclicks :-( */ } XSetWindowBorderWidth(dpy, swallowed,0); XMoveResizeWindow(dpy, swallowed, 0, 0, mysizehints.width, mysizehints.height); /* Now we do some special juju for shaped windows: */ /* ...tell the window to repaint itself, please! */ if (shape) { sendexpose(swallowed); /* ... ok, window should be repainted and a shaped window should have updated its mask accordingly! (-: End of shape-juju :-) */ /* Now steal the shape of the Window we just swallowed! */ stealshape(swallowed); } XMapWindow(dpy,win); XMapSubwindows(dpy,win); FlushWindow(); while(1) { while (XPending(dpy)) { XNextEvent(dpy,&Event); switch(Event.type) { case ButtonPress: #ifdef DEBUG fprintf (stderr, "wmswallow: Got ButtonPress Event\n"); fflush(stderr); #endif if (getclick) system(execstring); break; case Expose: if(Event.xexpose.count == 0 ) { #ifdef DEBUG fprintf (stderr, "wmswallow: Got Expose Event, count==0\n"); fflush(stderr); #endif if (shape) stealshape(swallowed); /* Oclock changes its shape! That's why we have to steal it *again* */ FlushWindow(); XMapRaised(dpy,swallowed); /* the following Produces "focus-flicker" */ /* XMapSubwindows(dpy,win); */ /* XMapWindow(dpy,win); */ } break; case EnterNotify: if (focus) XSetInputFocus(dpy, swallowed, RevertToPointerRoot, CurrentTime); break; case LeaveNotify: if (focus) XSetInputFocus(dpy, PointerRoot, RevertToPointerRoot, CurrentTime); break; case DestroyNotify: XCloseDisplay(dpy); exit(0); default: #ifdef DEBUG /* fprintf (stderr, "wmswallow: Got Some Other Event\n"); fflush(stderr); */ #endif break; } } XFlush(dpy); usleep(50000L); } return 1; } /* int softenwindow (Window w) { */ /* XSetWindowAttributes attributes; */ /* attributes.override_redirect=FALSE; */ /* attributes.event_mask=SW_EVENTS|MW_EVENTS; */ /* attributes.do_not_propagate_mask=0; */ /* XChangeWindowAttributes(dpy, w, */ /* CWOverrideRedirect|CWEventMask|CWDontPropagate, */ /* &attributes); */ /* return TRUE; */ /* } */ int sendexpose (Window w) { XExposeEvent xexp; XEvent Event; int retval; xexp.type=Expose; xexp.serial=0; xexp.send_event=TRUE; xexp.display=dpy; xexp.window=w; xexp.x=0; xexp.y=0; xexp.width=mysizehints.width; xexp.height=mysizehints.height; xexp.count=0; Event.xexpose=xexp; retval=XSendEvent(dpy, w, FALSE, ExposureMask, &Event); /* XFlush(dpy); */ /* ... send all queued Events */ /* usleep(5000L); */ /* ... take a tiny doze */ XSync(dpy, FALSE); /* I doubt if this is really better than Flushing and pausing */ return retval; } void stealshape(Window w) { XShapeCombineShape (dpy, iconwin, ShapeBounding, 0, 0, w, ShapeBounding, ShapeSet); /* XShapeCombineShape (dpy, win, ShapeBounding, 0, 0, w, */ /* ShapeBounding, ShapeSet); */ /*Re-read specs! */ /* XShapeCombineShape (dpy, win, ShapeClip, 0, 0, w, */ /* ShapeClip, ShapeSet); */ /* XShapeCombineShape (dpy, iconwin, ShapeClip, 0, 0, w, */ /* ShapeClip, ShapeSet); */ } void nocolor(char *a, char *b) { fprintf(stderr,"wmswallow: can't %s %s\n", a,b); } int flush_expose (Window w) { XEvent dummy; int i=0; while(XCheckTypedWindowEvent(dpy,w,Expose,&dummy)) i++; return i; } void FlushWindow() { flush_expose(swallowed); flush_expose (iconwin); flush_expose(win); } Pixel GetColor(char *name) { XColor color; XWindowAttributes attributes; XGetWindowAttributes(dpy,Root,&attributes); color.pixel=0; if (!XParseColor(dpy,attributes.colormap,name,&color)) nocolor("parse",name); else if(!XAllocColor (dpy,attributes.colormap,&color)) nocolor("alloc",name); return color.pixel; } void usage(char *progname){ printf( "wmswallow Version %s\n" " by Friedrich Delgado Friedrichs (c) 2000\n" "\n" "Usage:\n" " %s [] [windowname [command [args ...]]]\n" " Will swallow the first X-Window it finds with a WM_NAME or\n" " WM_CLASS matching \n" "\n" " Flags:\n" " -h: prints this message and exits\n" " -geometry : use specified geometry for swallowed\n" " window\n" " -display : connect to specified display\n" " -shape: use the shape extension (default)\n" " -noshape: don't use the shape extension\n" " -focus: Window should take focus\n" " -nofocus: Window shouldn't take focus(default)\n" " -managed: Assume window is managed by the\n" " windowmanager (default)\n" " -unmanaged: Assume window is not managed by the\n" " windowmanager\n" " -getclick : on mouseclick, execute \n" " instead of passing the Event to the\n" " swallowed window.\n" " -id [0x]: swallow window with id \n" " The command with args will be executed, before swallowing.\n", VERSION, progname); } /* Parse commandline args, returns first non-switch argnumber */ int parseargs(int argc, char *argv[]){ int argnum; int lastarg=1; if (argc<2) { usage(argv[0]); exit(0); } for(argnum=1; argnum0) { for (i=0,runner=*children_return;i