679 lines
19 KiB
C
679 lines
19 KiB
C
/* 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 <unistd.h>
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <X11/Xlib.h>
|
||
#include <X11/Xutil.h>
|
||
#include <X11/extensions/shape.h>
|
||
#include <time.h>
|
||
#include <X11/Xatom.h>
|
||
#include <string.h>
|
||
|
||
#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 [<flags>] [windowname [command [args ...]]]\n"
|
||
" Will swallow the first X-Window it finds with a WM_NAME or\n"
|
||
" WM_CLASS matching <windowname>\n"
|
||
"\n"
|
||
" Flags:\n"
|
||
" -h: prints this message and exits\n"
|
||
" -geometry <string>: use specified geometry for swallowed\n"
|
||
" window\n"
|
||
" -display <string>: 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 <string>: on mouseclick, execute <string>\n"
|
||
" instead of passing the Event to the\n"
|
||
" swallowed window.\n"
|
||
" -id [0x]<hexnumber>: swallow window with id <hexnumber>\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; argnum<argc && *argv[argnum]=='-'; lastarg=++argnum) {
|
||
if (!strncmp(argv[argnum],"-h",2) ||
|
||
!strncmp(argv[argnum],"--",2)) {
|
||
usage(argv[0]);
|
||
exit(0);
|
||
} else if (!strcmp(argv[argnum],"-geometry")||
|
||
!strcmp(argv[argnum],"-geom"))
|
||
geometry=argv[++argnum];
|
||
else if (!strcmp(argv[argnum],"-display"))
|
||
display_name = argv[++argnum];
|
||
else if (!strcmp(argv[argnum],"-noshape"))
|
||
shape=FALSE;
|
||
else if (!strcmp(argv[argnum],"-shape"))
|
||
shape=TRUE;
|
||
else if (!strcmp(argv[argnum],"-unmanaged"))
|
||
unmanaged=TRUE;
|
||
else if (!strcmp(argv[argnum],"-managed"))
|
||
unmanaged=FALSE;
|
||
else if (!strcmp(argv[argnum],"-nofocus"))
|
||
focus=FALSE;
|
||
else if (!strcmp(argv[argnum],"-focus"))
|
||
focus=TRUE;
|
||
else if (!strcmp(argv[argnum],"-getclick")) {
|
||
execstring=(char *)malloc(strlen(argv[++argnum])+1+2);
|
||
strcpy(execstring, argv[argnum]);
|
||
strcat(execstring, " &");
|
||
getclick=TRUE;
|
||
} else if (!strcmp(argv[argnum],"-id"))
|
||
winid=strtol(argv[++argnum], NULL, 16);
|
||
else {
|
||
usage(argv[0]);
|
||
exit(0);
|
||
}
|
||
}
|
||
return lastarg; /*Return number of first argument, that is neither a switch nor
|
||
an argument to a switch */
|
||
}
|
||
|
||
|
||
/* Print a NULL-terminated list of char* onto file stream */
|
||
int printlist(FILE * stream, char * string, char **stringlist) {
|
||
int i=0;
|
||
|
||
fprintf(stream, string);
|
||
if (stringlist!=NULL) {
|
||
while (stringlist[i]!=NULL) {
|
||
fprintf(stream, " <20>");
|
||
fprintf(stream, stringlist[i]);
|
||
fprintf(stream, "<EFBFBD> ");
|
||
++i;
|
||
}
|
||
} else {
|
||
return(TRUE);
|
||
}
|
||
return(FALSE);
|
||
}
|
||
|
||
/* Select SubstructureNotify on the root-window, start the command, then look
|
||
if we get Create Events for a matching window, set winid */
|
||
Window startandfind (int argc, char *oldargv[], char* class) {
|
||
int found=0;
|
||
XEvent Event;
|
||
Window winreturn=(Window)0;
|
||
Window wintmp=(Window)0;
|
||
|
||
#ifdef DEBUG
|
||
fprintf(stderr, "Checking for name: %s\n", class);
|
||
fflush(stderr);
|
||
#endif
|
||
|
||
XSelectInput(dpy, Root, FIND_EVENTS);
|
||
if (!execstuff(argc, oldargv))
|
||
return FALSE; /* execstuff failed, should not return, but
|
||
nevertheless...*/
|
||
while (!found) {
|
||
while (!found && XPending(dpy)) {
|
||
/* FIXME: We hang, when the application starts, but we
|
||
cannot find the window! */
|
||
XNextEvent(dpy, &Event);
|
||
switch (Event.type) { /* Switch, in case we check for more than one
|
||
Event-Type one day */
|
||
/* We're waiting for the wm to reparent the window! */
|
||
case ReparentNotify:
|
||
#ifdef DEBUG
|
||
fprintf (stderr, "wmswallow: Got ReparentNotify Event\n");
|
||
fflush(stderr);
|
||
#endif
|
||
wintmp=Event.xreparent.window;
|
||
if (checkwindow(wintmp, class)) {
|
||
winreturn=wintmp;
|
||
found=TRUE;
|
||
} else if ((winreturn=findnamedwindowacc(class, wintmp))) {
|
||
found=TRUE;
|
||
}
|
||
break;
|
||
case CreateNotify: case MapNotify:
|
||
wintmp=Event.xcreatewindow.window;
|
||
#ifdef DEBUG
|
||
fprintf (stderr, "wmswallow: Got CreateNotify Event for window "
|
||
"0x%lx\n", wintmp);
|
||
fflush(stderr);
|
||
#endif
|
||
if (unmanaged) {
|
||
if (checkwindow(wintmp, class)) {
|
||
winreturn=wintmp;
|
||
found=TRUE;
|
||
} else if ((winreturn=findnamedwindowacc(class, wintmp))) {
|
||
found=TRUE;
|
||
}
|
||
}
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
XSelectInput(dpy, Root, None);
|
||
#ifdef DEBUG
|
||
fprintf (stderr, "wmswallow: found it"
|
||
"0x%lx\n", wintmp);
|
||
fflush(stderr);
|
||
#endif
|
||
|
||
waitformap(winreturn);
|
||
/* Ok, the window has been created, Reparented by WindowMaker and mapped */
|
||
/* What else can we do to make sure the window was created? */
|
||
|
||
sleep(1); /* doze just a sec, should be more than enough in any case */
|
||
|
||
return winreturn;
|
||
}
|
||
|
||
/* Execute a command */
|
||
int execstuff (int argc, char *oldargv[]) {
|
||
char **argv;
|
||
int i, success, forked;
|
||
|
||
argv=(char **)malloc((argc+1)*sizeof(char *));
|
||
|
||
for (i=0; i<argc; i++) {
|
||
argv[i]=oldargv[i];
|
||
}
|
||
argv[i]=NULL;
|
||
|
||
forked=fork();
|
||
if (forked==-1) {
|
||
perror("Could not fork");
|
||
exit(1);
|
||
}
|
||
if (forked) {
|
||
#ifdef DEBUG
|
||
printlist(stderr, "Trying to execute:", argv);
|
||
fprintf(stderr, "\n");
|
||
#endif
|
||
success=execvp(argv[0],argv);
|
||
if (success!=0) {
|
||
printlist(stderr, "Could not execute:", argv);
|
||
fprintf(stderr, "\n");
|
||
exit(1);
|
||
}
|
||
} /* Removed the sleep, since it keeps us from getting the Create Event */
|
||
free(argv);
|
||
return(TRUE);
|
||
}
|
||
|
||
void waitformap (Window win) {
|
||
int found=0;
|
||
XEvent Event;
|
||
|
||
XSelectInput(dpy, win, READY_EVENTS);
|
||
found=0;
|
||
while (!found && XPending(dpy)) {
|
||
if (XCheckMaskEvent(dpy, READY_EVENTS, &Event))
|
||
if (Event.type==MapNotify)
|
||
if (Event.xmap.window==win)
|
||
found=TRUE;
|
||
}
|
||
#ifdef DEBUG
|
||
fprintf (stderr, "wmswallow: Got MapNotify Event for window 0x%lx\n", win);
|
||
fflush(stderr);
|
||
#endif
|
||
while (XCheckTypedWindowEvent(dpy, win, MapNotify, &Event))
|
||
; /* Flush the map Events */
|
||
XSelectInput(dpy, win, None);
|
||
}
|
||
|
||
/* Find window which matches WM_NAME or WM_CLASS */
|
||
Window findnamedwindow (char *class) {
|
||
/* Get All Children of the Root-Window */
|
||
Window result;
|
||
if ((result=(findnamedwindowacc (class, Root)))!=0)
|
||
return result;
|
||
else {
|
||
fprintf(stderr, "Could not find %s\n", class);
|
||
exit (1);
|
||
}
|
||
}
|
||
|
||
/* Recursively walk through all the windows and their children to find the
|
||
first one that matches WM_NAME or WM_CLASS */
|
||
/* Only called by findnamedwindow() */
|
||
Window findnamedwindowacc (char *class, Window window) {
|
||
Window root_return;
|
||
Window parent_return;
|
||
Window *children_return;
|
||
unsigned int nchildren_return;
|
||
Window runner;
|
||
Window result;
|
||
int i;
|
||
|
||
children_return=(Window *)NULL;
|
||
result=(Window)0;
|
||
|
||
if (checkwindow(window, class))
|
||
return window;
|
||
|
||
if (XQueryTree (dpy, window, &root_return, &parent_return,
|
||
&children_return, &nchildren_return)&&nchildren_return>0) {
|
||
for
|
||
(i=0,runner=*children_return;i<nchildren_return;
|
||
runner=children_return[++i]) {
|
||
if ((result=findnamedwindowacc(class, runner))!=0)
|
||
break; /* Leave this loop */ /* It's one of the children */
|
||
}
|
||
/* end of for loop*/ /* checked all windows to no avail */
|
||
} /* If the if (XQueryTree...)-part wasn't executed, wmswallow could not get
|
||
Windows (probably no children) */
|
||
if (children_return)
|
||
XFree(children_return);
|
||
return result;
|
||
}
|
||
|
||
/* Checks if the window has WM_NAME or WM_CLASS properties fitting *class */
|
||
int checkwindow (Window window, char *class) {
|
||
XClassHint class_hints;
|
||
XTextProperty prop;
|
||
|
||
int found=0;
|
||
|
||
class_hints.res_name = class_hints.res_class = prop.value =(char *) NULL;
|
||
|
||
/* Check WM_CLASS properties name and class */
|
||
if (XGetClassHint(dpy, window, &class_hints)) {
|
||
if (!strcmp(class_hints.res_name, class) ||
|
||
!strcmp(class_hints.res_class, class)) {
|
||
found = 1; /* It's this window! */
|
||
}
|
||
#ifdef DEBUG
|
||
fprintf (stderr, "wmswallow: checkwindow: 0x%lx, class: %s, name: %s\n",
|
||
win, class_hints.res_class, class_hints.res_name);
|
||
fflush(stderr);
|
||
#endif
|
||
}
|
||
/* Check WM_NAME property */
|
||
if (!found && XGetWMName(dpy, window, &prop))
|
||
if (prop.nitems && !strcmp(prop.value, class)) {
|
||
found = 1; /* (-: It's really this window, and we're lucky we guessed its
|
||
name correctly :-) */
|
||
}
|
||
#ifdef DEBUG
|
||
fprintf (stderr, "wmswallow: WM_NAME: %s\n",
|
||
prop.value);
|
||
fflush(stderr);
|
||
#endif
|
||
|
||
/* Clean up */
|
||
if (prop.value)
|
||
XFree(prop.value);
|
||
if (class_hints.res_class)
|
||
XFree(class_hints.res_class);
|
||
if (class_hints.res_name)
|
||
XFree(class_hints.res_name);
|
||
return found;
|
||
}
|