/* 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 <X11/xpm.h>
#include "icon.h"
#include "desktop.h"
#include "sceme.h"
#include "action.h"
#include "clienttree.h"
Icon::Icon(Desktop *p,Client *c, char *aname) : client(c),parent(p) {
flags = TF_ISICON;
pixmap = 0;
iconwin = 0;
window = 0;
name = 0;
spm = 0;
cmd = 0;
Action *action = 0;
if (aname && aname[0]=='@')
action = (Action *)rman->GetInfo(SE_ACTION,aname+1);
x = UNDEF;
y = UNDEF;
if (client && !action) {
if (client->flags & CF_ICONPOSKNOWN) {
x = client->IconX;
y = client->IconY;
}
} else if (action) {
if ((action->flags & AC_ICONX) && (action->flags & AC_ICONY)) {
x = action->IconX;
y = action->IconY;
}
}
if (action)
name = strdup(action->name);
if (aname) {
cmd = strdup(aname);
if (!name)
name = strdup(aname);
}
if (action)
spm = action->iconpm; //dirty
}
Icon::Icon(Desktop *p,Icon *i, bool copy): parent(p) {
flags = TF_ISICON;
pixmap = 0;
iconwin = 0;
window = 0;
name = 0;
spm = 0;
cmd = 0;
x = UNDEF;
y = UNDEF;
client = i->client;
if (i->cmd)
cmd = strdup(i->cmd);
if (i->name) {
name = new char[strlen(i->name)+1];
strcpy(name,i->name);
}
spm = i->spm;
if (client && !cmd && copy) {
cmd = strdup("g");
}
}
void Icon::Init() {
if (x==UNDEF || y==UNDEF)
GetPosition();
ChangeName(name);
XSetWindowAttributes attr;
attr.override_redirect = true;
attr.background_pixel = parent->Sc->colors[C_IBG].pixel;
attr.border_pixel = parent->Sc->colors[C_IBD].pixel ;
attr.event_mask = (ButtonMask | ExposureMask);
window = XCreateWindow(dpy, parent->window, x - w/2, y, w, h,1,
CopyFromParent,
CopyFromParent,CopyFromParent,CWBorderPixel | CWEventMask | CWBackPixel | CWOverrideRedirect,&attr);
attr.background_pixel = parent->Sc->colors[C_IBG].pixel;
if (spm)
GetXPMFile(spm,&attr); // dirty
if (!iconwin && client && client->iconpm)
GetXPMFile(client->iconpm,&attr);
if (!iconwin && client) {
Client *focus = client->Focus();
if (focus) {
XWMHints *hints = XGetWMHints(dpy, focus->window);
if (hints) {
if(hints->flags & IconWindowHint) {
GetIconWindow(hints);
} else
if ((hints->flags & IconPixmapHint)) {
GetIconBitmap(hints,&attr);
}
XFree(hints);
}
}
}
if (!iconwin && client && client->Sc->iconpm)
GetXPMFile(client->Sc->iconpm,&attr);
if (parent->flags & DF_ICONSRAISED) {
XRaiseWindow(dpy,window);
if (iconwin)
XRaiseWindow(dpy,iconwin);
} else {
XLowerWindow(dpy,window);
if (iconwin)
XLowerWindow(dpy,iconwin);
}
XMapWindow(dpy,window);
if (iconwin)
XMapWindow(dpy,iconwin);
if (window)
ct->windows.insert(WmapPair(window,this));
if (iconwin)
ct->windows.insert(WmapPair(iconwin,this));
}
inline int Min(int x,int y) {
return (x < y) ? x : y;
}
// we are lazy
#define MINIX MinIX
#define MINIY MinIY
#define GRIDX parent->Sc->GridX
#define GRIDY parent->Sc->GridY
#define ISPACELEFT parent->Sc->ISLeft
#define ISPACERIGHT parent->Sc->ISRight
#define ISPACETOP parent->Sc->ISTop
#define ISPACEBOTTOM parent->Sc->ISBottom
void Icon::GetPosition() {
MinIX = parent->Sc->MinIX;
MinIY = parent->Sc->MinIY;
parent->Translate(&MinIX,&MinIY);
int nx = (parent->width - MINIX) / GRIDX;
int ny = (parent->height - MINIY) / GRIDY;
x=0; y=0;
// avoid almost-endless loops
if (nx > 200)
nx = 200;
if (ny > 200)
ny = 200;
if (nx < 0)
nx = 1;
if (ny < 0)
ny = 1;
bool Grid[nx][ny];
for (int i = 0;i!=nx;++i)
for (int j = 0;j!=ny;++j)
Grid[i][j] = true;
for (Icon *ii=parent->firsticon;ii;ii=ii->next) {
if (ii == this)
continue;
int x1 = (ii->x - Min(ii->w/2,ISPACELEFT)
- MINIX - ISPACERIGHT + GRIDX-1) / GRIDX; // the / - operator sucks with negative numbers
int y1 = (ii->y - Min((ii->iconwin ? ii->iconh : 0),ISPACETOP)
- MINIY - ISPACEBOTTOM + GRIDX-1) / GRIDY;
int x2 = (ii->x + Min(ii->w/2,ISPACERIGHT)
- MINIX + ISPACELEFT) / GRIDX;
int y2 = (ii->y + Min(ii->h,ISPACEBOTTOM)
- MINIY + ISPACETOP) / GRIDY;
if (x1 < 0)
x1 = 0;
if (y1 < 0)
y1 = 0;
++x2;++y2;
if (x2 > nx)
x2 = nx;
if (y2 > ny)
y2 = ny;
for (int i = x1;i<x2;++i)
for (int j = y1;j<y2;++j)
Grid[i][j] = false;
}
for (int i = 0;i<nx+ny-1;++i)
for (int j = 0;j!=i+1;++j)
if (j<nx && i-j<ny && Grid[j][i-j]) {
x = j*GRIDX + MINIX;
y = (i-j)*GRIDY + MINIY;
goto next; // ugly
}
next:
if (!x)
x = MINIX;
if (!y)
y = MINIY;
for (Client *cc=parent->firstchild;cc;cc=cc->next)
if (cc->mapped) {
int x1 = (cc->x - cc->Sc->BW - MINIX - ISPACERIGHT + GRIDX - 1) / GRIDX;
int y1 = (cc->y - cc->THeight - cc->Sc->BW - MINIY - ISPACEBOTTOM + GRIDY - 1) / GRIDY;
int x2 = (cc->x + cc->width + cc->Sc->BW - MINIX + ISPACELEFT) / GRIDX;
int y2 = (cc->y + cc->height + cc->Sc->BW - MINIY + ISPACETOP) / GRIDY;
if (x1 < 0)
x1 = 0;
if (y1 < 0)
y1 = 0;
++x2;++y2;
if (x2 > nx)
x2 = nx;
if (y2 > ny)
y2 = ny;
for (int i = x1;i<x2;++i)
for (int j = y1;j<y2;++j) {
Grid[i][j] = false;
}
}
for (int i = 0;i<nx+ny-1;++i)
for (int j = 0;j!=i+1;++j)
if (j<nx && i-j<ny && Grid[j][i-j]) {
x = j*GRIDX + MINIX;
y = (i-j)*GRIDY + MINIY;
return;
}
}
void Icon::Move() {
int dx = (x + snap - MINIX) % GRIDX - snap;
int dy = (y + snap - MINIY) % GRIDY - snap;
if (abs(dx)<=snap && abs(dy)<=snap) {
x-=dx;
y-=dy;
}
XMoveWindow(dpy, window,x - w/2,y);
if (iconwin)
XMoveWindow(dpy, iconwin, x-iconw/2, y-iconh-2);
}
void Icon::ChangeName(char *newname) {
char *str = 0;
char *iconname = 0;
if (!name || newname != name) {
if (!newname && client && !cmd) {
str = client->name ? client->name : client->wmname;
XGetIconName(dpy,client->window,&iconname);
if (!iconname || !iconname[0])
newname = 0; else
newname = iconname;
}
if (!newname)
newname = "Icon";
char save = '\0';
if (strlen(newname) > MAXICON)
save = newname[MAXICON];
name = strdup(newname);
if (save)
newname[MAXICON] = save;
if (name && str && !strcmp(name, str)) {
free(name); // Save memory
name = 0;
}
if (iconname)
XFree(iconname);
}
str = name ? name : str;
XFontSetExtents *e;
e = XExtentsOfFontSet(parent->Sc->fonts[FO_ICON]);
w = XmbTextEscapement(parent->Sc->fonts[FO_ICON], str, strlen(str)) + 2*SPACE;
h = e->max_logical_extent.height*4/5 + e->max_logical_extent.height/5 + 2*SPACE;
if (window)
XMoveResizeWindow(dpy, window, x - w/2, y, w, h);
}
void Icon::GetIconBitmap(XWMHints *hints,XSetWindowAttributes *attr) {
int dummyx,dummyy;
unsigned int dummybw;
Window dummyroot;
XGetGeometry(dpy, hints->icon_pixmap, &dummyroot, &dummyx, &dummyy,
(unsigned int *)&iconw,
(unsigned int *)&iconh, &dummybw, &depth);
pixmap = hints->icon_pixmap;
#ifdef SHAPE
/* if (hints->flags & IconMaskHint)
{
tmp_win->icon_maskPixmap = hints->icon_mask;
}*/
#endif
iconwin = XCreateWindow(dpy, parent->window, x-iconw/2, y-iconh-2, iconw,
iconh, 0, CopyFromParent,
CopyFromParent,CopyFromParent,CWBorderPixel | CWEventMask | CWBackPixel | CWOverrideRedirect,attr);
}
void Icon::GetIconWindow(XWMHints *hints) {
int dummyx,dummyy;
unsigned int dummybw;
Window dummyroot;
iconwin = hints->icon_window;
XGetGeometry(dpy, iconwin, &dummyroot, &dummyx, &dummyy,
(unsigned int *)&iconw,
(unsigned int *)&iconh, &dummybw, &depth);
iconh +=4; // windows seem to supply their own border
pixmap = 0;// hints->icon_pixmap;
flags |= IF_APPICON;
XReparentWindow(dpy,iconwin,parent->window,x-iconw/2,y-iconh-2);
XAddToSaveSet(dpy,iconwin);
XMapWindow(dpy,iconwin);
XSelectInput(dpy,iconwin,(ButtonPressMask | ButtonReleaseMask | Button2MotionMask));
}
bool Icon::GetXPMFile(RPixmap *pm,XSetWindowAttributes *attr) {
pixmap = pm->GetPixmap();
if (!pixmap)
return false;
spm = pm;
iconw = pm->w;
iconh = pm->h;
depth = DefaultDepth(dpy,screen);
#ifdef SHAPE
/* if (tmp_win->icon_maskPixmap)
tmp_win->flags |= SHAPED_ICON;
*/
#endif
iconwin = XCreateWindow(dpy, parent->window, x-iconw/2, y-iconh-2, iconw,
iconh, 0, CopyFromParent,
CopyFromParent,CopyFromParent,CWBorderPixel | CWEventMask | CWBackPixel | CWOverrideRedirect,attr);
return true;
}
void Icon::ReDraw() {
if (!window || !parent->visible)
return;
char *str;
if (client) {
str = name ? name : (client->name ? client->name : client->wmname);
} else
str = name;
XFontSetExtents *e;
e = XExtentsOfFontSet(parent->Sc->fonts[FO_ICON]);
XmbDrawString(dpy, window, parent->Sc->fonts[FO_ICON], parent->Sc->icon_gc,
SPACE, SPACE + e->max_logical_extent.height*4/5,
str, strlen(str));
if (pixmap != None) {
if (depth == (unsigned int)DefaultDepth(dpy,screen)) {
XCopyArea(dpy,pixmap,iconwin,parent->Sc->icon_gc,0,0,iconw-4,iconh-4,2,2);
} else {
XCopyPlane(dpy,pixmap,iconwin,parent->Sc->icon_gc,0,0,iconw-4,iconh-4,2,2,1);
}
}
}
void Icon::Execute() {
parent->Client::GetFocus(); //!!!!!
if (cmd)
UEH->ExecCommand(client,0,cmd,true);
if (client && !cmd)
client->Map();
}
bool Icon::IsIn(Window win, int xx, int yy) {
if (win == iconwin) {
return (0<=xx && xx<=iconw && 0<=yy && yy<=iconh);
}
if (win == window) {
return (0<=xx && xx<=w && 0<=yy && yy<=h);
}
return false;
}
void Icon::Remove() {
if (window) {
ct->windows.erase(window);
XUnmapWindow(dpy,window);
XDestroyWindow(dpy, window);
window = 0;
}
if (iconwin) {
ct->windows.erase(iconwin);
XUnmapWindow(dpy,iconwin);
if (flags & IF_APPICON) {
XReparentWindow(dpy,iconwin,root,0,0);
XUnmapWindow(dpy,iconwin);
} else {
XDestroyWindow(dpy, iconwin);
}
iconwin = 0;
}
if (spm)
spm->FreePixmap();
if (UEH->CurrentIcon == this) {
UEH->CurrentIcon = 0;
UEH->Current = ct->RootDesktop;
}
}
Icon::~Icon() {
if (client && !cmd) {
// x = i*GRIDX + MINIX;
// y = i*GRIDY + MINIY;
if (((x-MINIX) % GRIDX) || ((y-MINIY) % GRIDY)) {
client->flags |= CF_ICONPOSKNOWN;
client->IconX = x;
client->IconY = y;
} else {
client->flags &= ~CF_ICONPOSKNOWN;
}
}
if (name)
free(name);
if (cmd)
free(cmd);
}
syntax highlighted by Code2HTML, v. 0.9.1