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