/* treewm - an X11 window manager.
* Copyright (c) 2001-2002 Thomas Jäger <TheHunter2000 at web dot de>
* This code is released under the terms of the GNU GPL.
* See the included file LICENSE for details.
*/
#include "clienttree.h"
#include "sceme.h"
#include "clientinfo.h"
#include "manager.h"
#include "uehandler.h"
#include "icon.h"
#include "action.h"
#include <stdlib.h>
#include <X11/Xatom.h>
ClientTree *ct;
ClientTree::ClientTree() : windows() {
XSetWindowAttributes pattr;
notitle = new char[9];
strcpy(notitle,"No Title");
MaxWindow = 0;
Focus = 0;
numcmd = 0;
numregex = 0;
numwmclass = 0;
ct = this;
watch = 0;
int w = DisplayWidth(dpy,screen);
int h = DisplayHeight(dpy, screen);
RootDesktop = new Desktop(0);
ClientInfo *ci = (ClientInfo *)rman->GetInfo(SE_CLIENTINFO, "root");
if (ci)
RootDesktop->SetClientInfo(ci);
RootDesktop->next = 0; // Very important
UEH->SetCurrent(RootDesktop,0);
CurrentDesktop = RootDesktop;
for (int i=0;i!=4;++i)
RootBorder[i] = 0;
RootDesktop->Init();
ct->windows.insert(WmapPair(RootDesktop->window,RootDesktop));
Sceme *Sc = RootDesktop->Sc;
XDefineCursor(dpy, root,Sc->cursors[CU_STD]);
if (Sc->BW <= 0) {
for (int i=0;i!=4;++i)
RootBorder[i] = 0;
return;
}
pattr.override_redirect = true;
pattr.background_pixel = Sc->colors[C_BD].pixel;
pattr.event_mask = EnterWindowMask;
RootBorder[0] = XCreateWindow(dpy, root,
0,0,w,Sc->BW, 0,
DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect|CWEventMask|CWBackPixel, &pattr);
RootBorder[1] = XCreateWindow(dpy, root,
0,0,Sc->BW,h, 0,
DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect|CWEventMask|CWBackPixel, &pattr);
RootBorder[2] = XCreateWindow(dpy, root,
0,h-Sc->BW,w,Sc->BW, 0,
DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect|CWEventMask|CWBackPixel, &pattr);
RootBorder[3] = XCreateWindow(dpy, root,
w-Sc->BW,0,Sc->BW,h, 0,
DefaultDepth(dpy, screen), CopyFromParent, DefaultVisual(dpy, screen),
CWOverrideRedirect|CWEventMask|CWBackPixel, &pattr);
for (int i=0;i!=4;++i)
XMapWindow(dpy,RootBorder[i]);
}
ClientTree::~ClientTree() {
RootDesktop->Remove(R_REMAP);
while (watch) {
WatchList *nw = watch->next;
if (watch->preg) {
regfree(watch->preg);
delete watch->preg;
}
delete watch;
watch = nw;
}
delete RootDesktop;
delete [] notitle;
for (int i=0;i!=4;++i)
if (RootBorder[i])
XDestroyWindow(dpy,RootBorder[i]);
}
Client *ClientTree::FindClient(Window win, Icon **icon) {
WmapIter i = windows.find(win);
if (i == windows.end())
return 0;
if (i->second->flags & TF_ISICON) {
if (icon)
(*icon) = (Icon *)i->second;
return 0;
} else {
return (Client *) i->second;
}
}
void ClientTree::RemoveClientReferences(Client *c) {
if (CurrentDesktop == c)
CurrentDesktop = 0;
if (Focus == c)
Focus = 0;
if (man->WantFocus == c)
man->WantFocus = 0;
if (man->ToBeRaised == c)
man->ToBeRaised = 0;
for (WatchList *i = watch;i;i=i->next)
if (i->parent == c)
i->parent = 0;
for (ClientList *cl=man->FirstReDraw;cl;cl=cl->next)
if (cl->client == c)
cl->client = 0;
for (ClientList *cl=man->MustBeDeleted;cl;cl=cl->next)
if (cl->client == c)
cl->client = 0;
UEH->RemoveClientReferences(c);
RootDesktop->RemoveClientReferences(c);
}
char *ClientTree::GetWindowCommand(Window win) {
Atom real_type;
int real_format;
unsigned long items_read, items_left;
Window *w;
if (XGetWindowProperty(dpy, win, wm_client_leader, 0L, 1L, false,
AnyPropertyType, &real_type, &real_format, &items_read, &items_left,
(unsigned char **) &w) == Success && items_read) {
win = *w;
XFree(w);
}
char **argv;
int argc;
if (XGetCommand(dpy,win,&argv,&argc)) {
char *ret = new char[strlen(argv[0])+1];
strcpy(ret,argv[0]);
XFreeStringList(argv);
return ret;
}
return 0;
}
bool CompareClass(char *str,XClassHint hint) {
int i=1;
if (str[0] != '*') {
if (!hint.res_name)
return false;
i = strlen(hint.res_name);
if (strncasecmp(str,hint.res_name,i))
return false;
}
if (str[i] != '.')
return false;
if (str[++i] != '*') {
if (!hint.res_class)
return false;
if (strcasecmp(str+i,hint.res_class))
return false;
}
return true;
}
WatchList *ClientTree::GetWatches(char *cmd, char *wname, XClassHint wmclass, Desktop *&d) {
WatchList *prev = 0;
WatchList *ret = 0;
int dummy = 0;
if (!watch)
return 0;
for (WatchList *i = watch;i;) {
if ( (i->cmd ? (cmd && !strcmp(cmd,i->cmd)) : true) && // cmd is ok
(i->preg ? (wname && !regexec(i->preg,wname,0,0,dummy)) : true) && // preg is ok
(i->wmclass ? CompareClass(i->wmclass,wmclass) : true) // wmclass is ok
) {
if (i->flags & AC_KEEP) {
WatchList *oret = ret;
ret = new WatchList;
ret->next = oret;
ret->ci = i->ci;
ret->cmd = i->cmd;
ret->flags = i->flags;
ret->parent = i->parent;
ret->preg = i->preg;
ret->wmclass = i->wmclass;
prev = i;
i = i->next;
} else {
WatchList *oret = ret;
ret = i;
if (prev)
prev->next = i->next; else
watch = i->next;
ret->next = oret;
if (i->cmd)
--numcmd;
if (i->wmclass)
--numwmclass;
if (i->preg) {
regfree(i->preg);
--numregex;
delete i->preg;
}
if (prev)
i = prev->next; else
i = watch;
}
} else { // doesn't match
prev = i;
i = i->next;
}
}
return ret;
}
Client* ClientTree::AddWindow(Window win) {
bool desktop = false;
Desktop *d = 0;
char *cmd = 0;
char *wname = 0;
XClassHint wmclass;
if (numcmd)
cmd = GetWindowCommand(win);
if (numregex)
FetchName(win,&wname);
if (numwmclass ? !XGetClassHint(dpy,win,&wmclass) : true) {
wmclass.res_name = 0;
wmclass.res_class = 0;
}
WatchList *wl = GetWatches(cmd,wname,wmclass,d);
if (wname)
XFree(wname);
if (wmclass.res_name)
XFree(wmclass.res_name);
if (wmclass.res_class)
XFree(wmclass.res_class);
if (!d) {
d = CurrentDesktop;
if (!d)
d = RootDesktop;
}
Window tfor;
Client *transfor;
// Sorry that we have to call this function twice
// since Xlib functions that return a value are extremely slow
XGetTransientForHint(dpy, win, &tfor);
// but we'll have to put the window onto the same desktop as transfor
if (tfor) { // don't check watches at all when window has a transient???
transfor=ct->FindClient(tfor,0);
if (transfor) {
for (;transfor->trans;transfor=transfor->trans);
// they are really applications that make themselves
// transient for the root window - no comment
if (transfor->parent)
d = transfor->parent;
}
} else
transfor = NULL;
Client *c = new Client(d,win);
while (wl) {
c->SetClientInfo(wl->ci);
if (wl->flags & AC_CLIENTDESKTOP)
desktop = true;
WatchList *nextwl = wl->next;
delete wl;
wl = nextwl;
}
d->AddChild(c);
if (desktop && !ISDESKTOP(c))
c->RequestDesktop(false);
if (MaxWindow)
c->Maximize(MAX_FULLSCREEN);
return c;
}
void ClientTree::AddWatch(Desktop *p,ClientInfo *ci,char *cmd,char *regex,
char *wmclass, long flags) {
WatchList *wl = watch;
watch = new WatchList;
watch->next = wl;
watch->ci = ci;
watch->parent = p;
watch->cmd = cmd;
watch->wmclass = wmclass;
watch->flags = flags;
if (cmd)
++numcmd;
if (wmclass)
++numwmclass;
if (regex) {
watch->preg = new regex_t;
regcomp(watch->preg,regex,REG_NOSUB|REG_ICASE|REG_EXTENDED);
++numregex;
} else
watch->preg = 0;
}
syntax highlighted by Code2HTML, v. 0.9.1