1 /* treewm - an X11 window manager.
2 * Copyright (c) 2001-2002 Thomas J�ger <TheHunter2000 at web dot de>
3 * This code is released under the terms of the GNU GPL.
4 * See the included file LICENSE for details.
5 */
6
7 #include <X11/xpm.h>
8 #include "icon.h"
9 #include "desktop.h"
10 #include "sceme.h"
11 #include "action.h"
12 #include "clienttree.h"
13
Icon(Desktop * p,Client * c,char * aname)14 Icon::Icon(Desktop *p,Client *c, char *aname) : client(c),parent(p) {
15 flags = TF_ISICON;
16 pixmap = 0;
17 iconwin = 0;
18 window = 0;
19 name = 0;
20 spm = 0;
21 cmd = 0;
22 Action *action = 0;
23 if (aname && aname[0]=='@')
24 action = (Action *)rman->GetInfo(SE_ACTION,aname+1);
25 x = UNDEF;
26 y = UNDEF;
27 if (client && !action) {
28 if (client->flags & CF_ICONPOSKNOWN) {
29 x = client->IconX;
30 y = client->IconY;
31 }
32 } else if (action) {
33 if ((action->flags & AC_ICONX) && (action->flags & AC_ICONY)) {
34 x = action->IconX;
35 y = action->IconY;
36 }
37 }
38 if (action)
39 name = strdup(action->name);
40 if (aname) {
41 cmd = strdup(aname);
42 if (!name)
43 name = strdup(aname);
44 }
45 if (action)
46 spm = action->iconpm; //dirty
47 }
48
49
Icon(Desktop * p,Icon * i,bool copy)50 Icon::Icon(Desktop *p,Icon *i, bool copy): parent(p) {
51 flags = TF_ISICON;
52 pixmap = 0;
53 iconwin = 0;
54 window = 0;
55 name = 0;
56 spm = 0;
57 cmd = 0;
58 x = UNDEF;
59 y = UNDEF;
60 client = i->client;
61 if (i->cmd)
62 cmd = strdup(i->cmd);
63 if (i->name) {
64 name = new char[strlen(i->name)+1];
65 strcpy(name,i->name);
66 }
67 spm = i->spm;
68 if (client && !cmd && copy) {
69 cmd = strdup("g");
70 }
71
72 }
73
Init()74 void Icon::Init() {
75 if (x==UNDEF || y==UNDEF)
76 GetPosition();
77 ChangeName(name);
78 XSetWindowAttributes attr;
79 attr.override_redirect = true;
80 attr.background_pixel = parent->Sc->colors[C_IBG].pixel;
81 attr.border_pixel = parent->Sc->colors[C_IBD].pixel ;
82 attr.event_mask = (ButtonMask | ExposureMask);
83 window = XCreateWindow(dpy, parent->window, x - w/2, y, w, h,1,
84 CopyFromParent,
85 CopyFromParent,CopyFromParent,CWBorderPixel | CWEventMask | CWBackPixel | CWOverrideRedirect,&attr);
86 attr.background_pixel = parent->Sc->colors[C_IBG].pixel;
87 if (spm)
88 GetXPMFile(spm,&attr); // dirty
89 if (!iconwin && client && client->iconpm)
90 GetXPMFile(client->iconpm,&attr);
91 if (!iconwin && client) {
92 Client *focus = client->Focus();
93 if (focus) {
94 XWMHints *hints = XGetWMHints(dpy, focus->window);
95 if (hints) {
96 if(hints->flags & IconWindowHint) {
97 GetIconWindow(hints);
98 } else
99 if ((hints->flags & IconPixmapHint)) {
100 GetIconBitmap(hints,&attr);
101 }
102 XFree(hints);
103 }
104 }
105 }
106 if (!iconwin && client && client->Sc->iconpm)
107 GetXPMFile(client->Sc->iconpm,&attr);
108
109 if (parent->flags & DF_ICONSRAISED) {
110 XRaiseWindow(dpy,window);
111 if (iconwin)
112 XRaiseWindow(dpy,iconwin);
113 } else {
114 XLowerWindow(dpy,window);
115 if (iconwin)
116 XLowerWindow(dpy,iconwin);
117 }
118 XMapWindow(dpy,window);
119 if (iconwin)
120 XMapWindow(dpy,iconwin);
121 if (window)
122 ct->windows.insert(WmapPair(window,this));
123 if (iconwin)
124 ct->windows.insert(WmapPair(iconwin,this));
125
126
127
128 }
129
130
Min(int x,int y)131 inline int Min(int x,int y) {
132 return (x < y) ? x : y;
133 }
134
135 // we are lazy
136 #define MINIX MinIX
137 #define MINIY MinIY
138 #define GRIDX parent->Sc->GridX
139 #define GRIDY parent->Sc->GridY
140 #define ISPACELEFT parent->Sc->ISLeft
141 #define ISPACERIGHT parent->Sc->ISRight
142 #define ISPACETOP parent->Sc->ISTop
143 #define ISPACEBOTTOM parent->Sc->ISBottom
144
GetPosition()145 void Icon::GetPosition() {
146 MinIX = parent->Sc->MinIX;
147 MinIY = parent->Sc->MinIY;
148 parent->Translate(&MinIX,&MinIY);
149 int nx = (parent->width - MINIX) / GRIDX;
150 int ny = (parent->height - MINIY) / GRIDY;
151 x=0; y=0;
152 // avoid almost-endless loops
153 if (nx > 200)
154 nx = 200;
155 if (ny > 200)
156 ny = 200;
157 if (nx < 0)
158 nx = 1;
159 if (ny < 0)
160 ny = 1;
161
162 bool Grid[nx][ny];
163 for (int i = 0;i!=nx;++i)
164 for (int j = 0;j!=ny;++j)
165 Grid[i][j] = true;
166
167 for (Icon *ii=parent->firsticon;ii;ii=ii->next) {
168 if (ii == this)
169 continue;
170 int x1 = (ii->x - Min(ii->w/2,ISPACELEFT)
171 - MINIX - ISPACERIGHT + GRIDX-1) / GRIDX; // the / - operator sucks with negative numbers
172 int y1 = (ii->y - Min((ii->iconwin ? ii->iconh : 0),ISPACETOP)
173 - MINIY - ISPACEBOTTOM + GRIDX-1) / GRIDY;
174 int x2 = (ii->x + Min(ii->w/2,ISPACERIGHT)
175 - MINIX + ISPACELEFT) / GRIDX;
176 int y2 = (ii->y + Min(ii->h,ISPACEBOTTOM)
177 - MINIY + ISPACETOP) / GRIDY;
178 if (x1 < 0)
179 x1 = 0;
180 if (y1 < 0)
181 y1 = 0;
182 ++x2;++y2;
183 if (x2 > nx)
184 x2 = nx;
185 if (y2 > ny)
186 y2 = ny;
187 for (int i = x1;i<x2;++i)
188 for (int j = y1;j<y2;++j)
189 Grid[i][j] = false;
190 }
191
192 for (int i = 0;i<nx+ny-1;++i)
193 for (int j = 0;j!=i+1;++j)
194 if (j<nx && i-j<ny && Grid[j][i-j]) {
195 x = j*GRIDX + MINIX;
196 y = (i-j)*GRIDY + MINIY;
197 goto next; // ugly
198 }
199 next:
200 if (!x)
201 x = MINIX;
202 if (!y)
203 y = MINIY;
204
205 for (Client *cc=parent->firstchild;cc;cc=cc->next)
206 if (cc->mapped) {
207 int x1 = (cc->x - cc->Sc->BW - MINIX - ISPACERIGHT + GRIDX - 1) / GRIDX;
208 int y1 = (cc->y - cc->THeight - cc->Sc->BW - MINIY - ISPACEBOTTOM + GRIDY - 1) / GRIDY;
209 int x2 = (cc->x + cc->width + cc->Sc->BW - MINIX + ISPACELEFT) / GRIDX;
210 int y2 = (cc->y + cc->height + cc->Sc->BW - MINIY + ISPACETOP) / GRIDY;
211 if (x1 < 0)
212 x1 = 0;
213 if (y1 < 0)
214 y1 = 0;
215 ++x2;++y2;
216 if (x2 > nx)
217 x2 = nx;
218 if (y2 > ny)
219 y2 = ny;
220 for (int i = x1;i<x2;++i)
221 for (int j = y1;j<y2;++j) {
222 Grid[i][j] = false;
223 }
224 }
225
226 for (int i = 0;i<nx+ny-1;++i)
227 for (int j = 0;j!=i+1;++j)
228 if (j<nx && i-j<ny && Grid[j][i-j]) {
229 x = j*GRIDX + MINIX;
230 y = (i-j)*GRIDY + MINIY;
231 return;
232 }
233 }
234
Move()235 void Icon::Move() {
236 int dx = (x + snap - MINIX) % GRIDX - snap;
237 int dy = (y + snap - MINIY) % GRIDY - snap;
238 if (abs(dx)<=snap && abs(dy)<=snap) {
239 x-=dx;
240 y-=dy;
241 }
242 XMoveWindow(dpy, window,x - w/2,y);
243 if (iconwin)
244 XMoveWindow(dpy, iconwin, x-iconw/2, y-iconh-2);
245 }
246
247
ChangeName(char * newname)248 void Icon::ChangeName(char *newname) {
249 char *str = 0;
250 char *iconname = 0;
251 if (!name || newname != name) {
252 if (!newname && client && !cmd) {
253 str = client->name ? client->name : client->wmname;
254 XGetIconName(dpy,client->window,&iconname);
255 if (!iconname || !iconname[0])
256 newname = 0; else
257 newname = iconname;
258 }
259 if (!newname)
260 newname = "Icon";
261 char save = '\0';
262 if (strlen(newname) > MAXICON)
263 save = newname[MAXICON];
264 name = strdup(newname);
265 if (save)
266 newname[MAXICON] = save;
267 if (name && str && !strcmp(name, str)) {
268 free(name); // Save memory
269 name = 0;
270 }
271 if (iconname)
272 XFree(iconname);
273 }
274 str = name ? name : str;
275 XFontSetExtents *e;
276 e = XExtentsOfFontSet(parent->Sc->fonts[FO_ICON]);
277 w = XmbTextEscapement(parent->Sc->fonts[FO_ICON], str, strlen(str)) + 2*SPACE;
278 h = e->max_logical_extent.height*4/5 + e->max_logical_extent.height/5 + 2*SPACE;
279 if (window)
280 XMoveResizeWindow(dpy, window, x - w/2, y, w, h);
281
282 }
283
284
GetIconBitmap(XWMHints * hints,XSetWindowAttributes * attr)285 void Icon::GetIconBitmap(XWMHints *hints,XSetWindowAttributes *attr) {
286 int dummyx,dummyy;
287 unsigned int dummybw;
288 Window dummyroot;
289 XGetGeometry(dpy, hints->icon_pixmap, &dummyroot, &dummyx, &dummyy,
290 (unsigned int *)&iconw,
291 (unsigned int *)&iconh, &dummybw, &depth);
292 pixmap = hints->icon_pixmap;
293 #ifdef SHAPE
294 /* if (hints->flags & IconMaskHint)
295 {
296 tmp_win->icon_maskPixmap = hints->icon_mask;
297 }*/
298 #endif
299 iconwin = XCreateWindow(dpy, parent->window, x-iconw/2, y-iconh-2, iconw,
300 iconh, 0, CopyFromParent,
301 CopyFromParent,CopyFromParent,CWBorderPixel | CWEventMask | CWBackPixel | CWOverrideRedirect,attr);
302
303 }
304
GetIconWindow(XWMHints * hints)305 void Icon::GetIconWindow(XWMHints *hints) {
306 int dummyx,dummyy;
307 unsigned int dummybw;
308 Window dummyroot;
309 iconwin = hints->icon_window;
310 XGetGeometry(dpy, iconwin, &dummyroot, &dummyx, &dummyy,
311 (unsigned int *)&iconw,
312 (unsigned int *)&iconh, &dummybw, &depth);
313 iconh +=4; // windows seem to supply their own border
314 pixmap = 0;// hints->icon_pixmap;
315 flags |= IF_APPICON;
316 XReparentWindow(dpy,iconwin,parent->window,x-iconw/2,y-iconh-2);
317 XAddToSaveSet(dpy,iconwin);
318 XMapWindow(dpy,iconwin);
319 XSelectInput(dpy,iconwin,(ButtonPressMask | ButtonReleaseMask | Button2MotionMask));
320 }
321
322
GetXPMFile(RPixmap * pm,XSetWindowAttributes * attr)323 bool Icon::GetXPMFile(RPixmap *pm,XSetWindowAttributes *attr) {
324 pixmap = pm->GetPixmap();
325 if (!pixmap)
326 return false;
327 spm = pm;
328 iconw = pm->w;
329 iconh = pm->h;
330 depth = DefaultDepth(dpy,screen);
331 #ifdef SHAPE
332 /* if (tmp_win->icon_maskPixmap)
333 tmp_win->flags |= SHAPED_ICON;
334 */
335 #endif
336
337 iconwin = XCreateWindow(dpy, parent->window, x-iconw/2, y-iconh-2, iconw,
338 iconh, 0, CopyFromParent,
339 CopyFromParent,CopyFromParent,CWBorderPixel | CWEventMask | CWBackPixel | CWOverrideRedirect,attr);
340 return true;
341 }
342
343
ReDraw()344 void Icon::ReDraw() {
345 if (!window || !parent->visible)
346 return;
347 char *str;
348
349 if (client) {
350 str = name ? name : (client->name ? client->name : client->wmname);
351 } else
352 str = name;
353 XFontSetExtents *e;
354 e = XExtentsOfFontSet(parent->Sc->fonts[FO_ICON]);
355 XmbDrawString(dpy, window, parent->Sc->fonts[FO_ICON], parent->Sc->icon_gc,
356 SPACE, SPACE + e->max_logical_extent.height*4/5,
357 str, strlen(str));
358
359 if (pixmap != None) {
360 if (depth == (unsigned int)DefaultDepth(dpy,screen)) {
361 XCopyArea(dpy,pixmap,iconwin,parent->Sc->icon_gc,0,0,iconw-4,iconh-4,2,2);
362 } else {
363 XCopyPlane(dpy,pixmap,iconwin,parent->Sc->icon_gc,0,0,iconw-4,iconh-4,2,2,1);
364 }
365 }
366
367
368 }
369
Execute()370 void Icon::Execute() {
371 parent->Client::GetFocus(); //!!!!!
372 if (cmd)
373 UEH->ExecCommand(client,0,cmd,true);
374 if (client && !cmd)
375 client->Map();
376 }
377
378
IsIn(Window win,int xx,int yy)379 bool Icon::IsIn(Window win, int xx, int yy) {
380 if (win == iconwin) {
381 return (0<=xx && xx<=iconw && 0<=yy && yy<=iconh);
382 }
383 if (win == window) {
384 return (0<=xx && xx<=w && 0<=yy && yy<=h);
385 }
386 return false;
387 }
388
Remove()389 void Icon::Remove() {
390 if (window) {
391 ct->windows.erase(window);
392 XUnmapWindow(dpy,window);
393 XDestroyWindow(dpy, window);
394 window = 0;
395 }
396 if (iconwin) {
397 ct->windows.erase(iconwin);
398 XUnmapWindow(dpy,iconwin);
399 if (flags & IF_APPICON) {
400 XReparentWindow(dpy,iconwin,root,0,0);
401 XUnmapWindow(dpy,iconwin);
402 } else {
403 XDestroyWindow(dpy, iconwin);
404 }
405 iconwin = 0;
406 }
407 if (spm)
408 spm->FreePixmap();
409 if (UEH->CurrentIcon == this) {
410 UEH->CurrentIcon = 0;
411 UEH->Current = ct->RootDesktop;
412 }
413 }
414
~Icon()415 Icon::~Icon() {
416 if (client && !cmd) {
417 // x = i*GRIDX + MINIX;
418 // y = i*GRIDY + MINIY;
419 if (((x-MINIX) % GRIDX) || ((y-MINIY) % GRIDY)) {
420 client->flags |= CF_ICONPOSKNOWN;
421 client->IconX = x;
422 client->IconY = y;
423 } else {
424 client->flags &= ~CF_ICONPOSKNOWN;
425 }
426 }
427 if (name)
428 free(name);
429 if (cmd)
430 free(cmd);
431 }
432