icons.c revision 3e747e6d
1/*
2 *
3Copyright 1989, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24 * */
25/* $XFree86: xc/programs/twm/icons.c,v 1.6 2001/12/14 20:01:08 dawes Exp $ */
26
27/**********************************************************************
28 *
29 * $Xorg: icons.c,v 1.4 2001/02/09 02:05:36 xorgcvs Exp $
30 *
31 * Icon releated routines
32 *
33 * 10-Apr-89 Tom LaStrange        Initial Version.
34 *
35 **********************************************************************/
36
37#include <stdio.h>
38#include "twm.h"
39#include "screen.h"
40#include "icons.h"
41#include "gram.h"
42#include "parse.h"
43#include "util.h"
44
45#define iconWidth(w)	(Scr->IconBorderWidth * 2 + w->icon_w_width)
46#define iconHeight(w)	(Scr->IconBorderWidth * 2 + w->icon_w_height)
47
48static void splitEntry ( IconEntry *ie, int grav1, int grav2, int w, int h );
49static IconEntry * FindIconEntry ( TwmWindow *tmp_win, IconRegion **irp );
50static IconEntry * prevIconEntry ( IconEntry *ie, IconRegion *ir );
51static void mergeEntries ( IconEntry *old, IconEntry *ie );
52
53static void
54splitEntry (IconEntry *ie, int grav1, int grav2, int w, int h)
55{
56    IconEntry	*new;
57
58    switch (grav1) {
59    case D_NORTH:
60    case D_SOUTH:
61	if (w != ie->w)
62	    splitEntry (ie, grav2, grav1, w, ie->h);
63	if (h != ie->h) {
64	    new = (IconEntry *)malloc (sizeof (IconEntry));
65	    new->twm_win = 0;
66	    new->used = 0;
67	    new->next = ie->next;
68	    ie->next = new;
69	    new->x = ie->x;
70	    new->h = (ie->h - h);
71	    new->w = ie->w;
72	    ie->h = h;
73	    if (grav1 == D_SOUTH) {
74		new->y = ie->y;
75		ie->y = new->y + new->h;
76	    } else
77		new->y = ie->y + ie->h;
78	}
79	break;
80    case D_EAST:
81    case D_WEST:
82	if (h != ie->h)
83	    splitEntry (ie, grav2, grav1, ie->w, h);
84	if (w != ie->w) {
85	    new = (IconEntry *)malloc (sizeof (IconEntry));
86	    new->twm_win = 0;
87	    new->used = 0;
88	    new->next = ie->next;
89	    ie->next = new;
90	    new->y = ie->y;
91	    new->w = (ie->w - w);
92	    new->h = ie->h;
93	    ie->w = w;
94	    if (grav1 == D_EAST) {
95		new->x = ie->x;
96		ie->x = new->x + new->w;
97	    } else
98		new->x = ie->x + ie->w;
99	}
100	break;
101    }
102}
103
104int
105roundUp (int v, int multiple)
106{
107    return ((v + multiple - 1) / multiple) * multiple;
108}
109
110void
111PlaceIcon(TwmWindow *tmp_win, int def_x, int def_y, int *final_x, int *final_y)
112{
113    IconRegion	*ir;
114    IconEntry	*ie;
115    int		w = 0, h = 0;
116
117    ie = 0;
118    for (ir = Scr->FirstRegion; ir; ir = ir->next) {
119	w = roundUp (iconWidth (tmp_win), ir->stepx);
120	h = roundUp (iconHeight (tmp_win), ir->stepy);
121	for (ie = ir->entries; ie; ie=ie->next) {
122	    if (ie->used)
123		continue;
124	    if (ie->w >= w && ie->h >= h)
125		break;
126	}
127	if (ie)
128	    break;
129    }
130    if (ie) {
131	splitEntry (ie, ir->grav1, ir->grav2, w, h);
132	ie->used = 1;
133	ie->twm_win = tmp_win;
134	*final_x = ie->x + (ie->w - iconWidth (tmp_win)) / 2;
135	*final_y = ie->y + (ie->h - iconHeight (tmp_win)) / 2;
136    } else {
137	*final_x = def_x;
138	*final_y = def_y;
139    }
140    return;
141}
142
143static IconEntry *
144FindIconEntry (TwmWindow *tmp_win, IconRegion **irp)
145{
146    IconRegion	*ir;
147    IconEntry	*ie;
148
149    for (ir = Scr->FirstRegion; ir; ir = ir->next) {
150	for (ie = ir->entries; ie; ie=ie->next)
151	    if (ie->twm_win == tmp_win) {
152		if (irp)
153		    *irp = ir;
154		return ie;
155	    }
156    }
157    return 0;
158}
159
160void
161IconUp (TwmWindow *tmp_win)
162{
163    int		x, y;
164    int		defx, defy;
165    struct IconRegion *ir;
166
167    /*
168     * If the client specified a particular location, let's use it (this might
169     * want to be an option at some point).  Otherwise, try to fit within the
170     * icon region.
171     */
172    if (tmp_win->wmhints && (tmp_win->wmhints->flags & IconPositionHint))
173      return;
174
175    if (tmp_win->icon_moved) {
176	if (!XGetGeometry (dpy, tmp_win->icon_w, &JunkRoot, &defx, &defy,
177			   &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth))
178	  return;
179
180	x = defx + ((int) JunkWidth) / 2;
181	y = defy + ((int) JunkHeight) / 2;
182
183	for (ir = Scr->FirstRegion; ir; ir = ir->next) {
184	    if (x >= ir->x && x < (ir->x + ir->w) &&
185		y >= ir->y && y < (ir->y + ir->h))
186	      break;
187	}
188	if (!ir) return;		/* outside icon regions, leave alone */
189    }
190
191    defx = -100;
192    defy = -100;
193    PlaceIcon(tmp_win, defx, defy, &x, &y);
194    if (x != defx || y != defy) {
195	XMoveWindow (dpy, tmp_win->icon_w, x, y);
196	tmp_win->icon_moved = FALSE;	/* since we've restored it */
197    }
198}
199
200static IconEntry *
201prevIconEntry (IconEntry *ie, IconRegion *ir)
202{
203    IconEntry	*ip;
204
205    if (ie == ir->entries)
206	return 0;
207    for (ip = ir->entries; ip->next != ie; ip=ip->next)
208	;
209    return ip;
210}
211
212/**
213 * old is being freed; and is adjacent to ie.  Merge
214 * regions together
215 */
216static void
217mergeEntries (IconEntry *old, IconEntry *ie)
218{
219    if (old->y == ie->y) {
220	ie->w = old->w + ie->w;
221	if (old->x < ie->x)
222	    ie->x = old->x;
223    } else {
224	ie->h = old->h + ie->h;
225	if (old->y < ie->y)
226	    ie->y = old->y;
227    }
228}
229
230void
231IconDown (TwmWindow *tmp_win)
232{
233    IconEntry	*ie, *ip, *in;
234    IconRegion	*ir;
235
236    ie = FindIconEntry (tmp_win, &ir);
237    if (ie) {
238	ie->twm_win = 0;
239	ie->used = 0;
240	ip = prevIconEntry (ie, ir);
241	in = ie->next;
242	for (;;) {
243	    if (ip && ip->used == 0 &&
244	       ((ip->x == ie->x && ip->w == ie->w) ||
245	        (ip->y == ie->y && ip->h == ie->h)))
246	    {
247	    	ip->next = ie->next;
248	    	mergeEntries (ie, ip);
249	    	free ((char *) ie);
250		ie = ip;
251	    	ip = prevIconEntry (ip, ir);
252	    } else if (in && in->used == 0 &&
253	       ((in->x == ie->x && in->w == ie->w) ||
254	        (in->y == ie->y && in->h == ie->h)))
255	    {
256	    	ie->next = in->next;
257	    	mergeEntries (in, ie);
258	    	free ((char *) in);
259	    	in = ie->next;
260	    } else
261		break;
262	}
263    }
264}
265
266void
267AddIconRegion(char *geom, int grav1, int grav2, int stepx, int stepy)
268{
269    IconRegion *ir;
270    int mask;
271
272    ir = (IconRegion *)malloc(sizeof(IconRegion));
273    ir->next = NULL;
274    if (Scr->LastRegion)
275	Scr->LastRegion->next = ir;
276    Scr->LastRegion = ir;
277    if (!Scr->FirstRegion)
278	Scr->FirstRegion = ir;
279
280    ir->entries = NULL;
281    ir->grav1 = grav1;
282    ir->grav2 = grav2;
283    if (stepx <= 0)
284	stepx = 1;
285    if (stepy <= 0)
286	stepy = 1;
287    ir->stepx = stepx;
288    ir->stepy = stepy;
289    ir->x = ir->y = ir->w = ir->h = 0;
290
291    mask = XParseGeometry(geom, &ir->x, &ir->y, (unsigned int *)&ir->w, (unsigned int *)&ir->h);
292
293    if (mask & XNegative)
294	ir->x += Scr->MyDisplayWidth - ir->w;
295
296    if (mask & YNegative)
297	ir->y += Scr->MyDisplayHeight - ir->h;
298    ir->entries = (IconEntry *)malloc(sizeof(IconEntry));
299    ir->entries->next = 0;
300    ir->entries->x = ir->x;
301    ir->entries->y = ir->y;
302    ir->entries->w = ir->w;
303    ir->entries->h = ir->h;
304    ir->entries->twm_win = 0;
305    ir->entries->used = 0;
306}
307
308#ifdef comment
309void
310FreeIconEntries (IconRegion *ir)
311{
312    IconEntry	*ie, *tmp;
313
314    for (ie = ir->entries; ie; ie=tmp)
315    {
316	tmp = ie->next;
317	free ((char *) ie);
318    }
319}
320
321void
322FreeIconRegions()
323{
324    IconRegion *ir, *tmp;
325
326    for (ir = Scr->FirstRegion; ir != NULL;)
327    {
328	tmp = ir;
329	FreeIconEntries (ir);
330	ir = ir->next;
331	free((char *) tmp);
332    }
333    Scr->FirstRegion = NULL;
334    Scr->LastRegion = NULL;
335}
336#endif
337
338void
339CreateIconWindow(TwmWindow *tmp_win, int def_x, int def_y)
340{
341    unsigned long event_mask;
342    unsigned long valuemask;		/* mask for create windows */
343    XSetWindowAttributes attributes;	/* attributes for create windows */
344    Pixmap pm = None;			/* tmp pixmap variable */
345    int final_x, final_y;
346    int x;
347
348
349    FB(tmp_win->iconc.fore, tmp_win->iconc.back);
350
351    tmp_win->forced = FALSE;
352    tmp_win->icon_not_ours = FALSE;
353
354    /* now go through the steps to get an icon window,  if ForceIcon is
355     * set, then no matter what else is defined, the bitmap from the
356     * .twmrc file is used
357     */
358    if (Scr->ForceIcon)
359    {
360	char *icon_name;
361	Pixmap bm;
362
363	icon_name = LookInNameList(Scr->IconNames, tmp_win->full_name);
364        if (icon_name == NULL)
365	    icon_name = LookInList(Scr->IconNames, tmp_win->full_name,
366				   &tmp_win->class);
367
368	bm = None;
369	if (icon_name != NULL)
370	{
371	    if ((bm = (Pixmap)LookInNameList(Scr->Icons, icon_name)) == None)
372	    {
373		if ((bm = GetBitmap (icon_name)) != None)
374		    AddToList(&Scr->Icons, icon_name, (char *)bm);
375	    }
376	}
377
378	if (bm != None)
379	{
380	    XGetGeometry(dpy, bm, &JunkRoot, &JunkX, &JunkY,
381		(unsigned int *) &tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height,
382		&JunkBW, &JunkDepth);
383
384	    pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width,
385		tmp_win->icon_height, Scr->d_depth);
386
387	    /* the copy plane works on color ! */
388	    XCopyPlane(dpy, bm, pm, Scr->NormalGC,
389		0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
390
391	    tmp_win->forced = TRUE;
392	}
393    }
394
395    /* if the pixmap is still NULL, we didn't get one from the above code,
396     * that could mean that ForceIcon was not set, or that the window
397     * was not in the Icons list, now check the WM hints for an icon
398     */
399    if (pm == None && tmp_win->wmhints &&
400	tmp_win->wmhints->flags & IconPixmapHint)
401    {
402
403	XGetGeometry(dpy,   tmp_win->wmhints->icon_pixmap,
404             &JunkRoot, &JunkX, &JunkY,
405	     (unsigned int *)&tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height, &JunkBW, &JunkDepth);
406
407	pm = XCreatePixmap(dpy, Scr->Root,
408			   tmp_win->icon_width, tmp_win->icon_height,
409			   Scr->d_depth);
410
411	XCopyPlane(dpy, tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC,
412	    0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
413    }
414
415    /* if we still haven't got an icon, let's look in the Icon list
416     * if ForceIcon is not set
417     */
418    if (pm == None && !Scr->ForceIcon)
419    {
420	char *icon_name;
421	Pixmap bm;
422
423	icon_name = LookInNameList(Scr->IconNames, tmp_win->full_name);
424        if (icon_name == NULL)
425	    icon_name = LookInList(Scr->IconNames, tmp_win->full_name,
426				   &tmp_win->class);
427
428	bm = None;
429	if (icon_name != NULL)
430	{
431	    if ((bm = (Pixmap)LookInNameList(Scr->Icons, icon_name)) == None)
432	    {
433		if ((bm = GetBitmap (icon_name)) != None)
434		    AddToList(&Scr->Icons, icon_name, (char *)bm);
435	    }
436	}
437
438	if (bm != None)
439	{
440	    XGetGeometry(dpy, bm, &JunkRoot, &JunkX, &JunkY,
441		(unsigned int *)&tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height,
442		&JunkBW, &JunkDepth);
443
444	    pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width,
445		tmp_win->icon_height, Scr->d_depth);
446
447	    /* the copy plane works on color ! */
448	    XCopyPlane(dpy, bm, pm, Scr->NormalGC,
449		0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
450	}
451    }
452
453    /* if we still don't have an icon, assign the UnknownIcon */
454
455    if (pm == None && Scr->UnknownPm != None)
456    {
457	tmp_win->icon_width = Scr->UnknownWidth;
458	tmp_win->icon_height = Scr->UnknownHeight;
459
460	pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width,
461	    tmp_win->icon_height, Scr->d_depth);
462
463	/* the copy plane works on color ! */
464	XCopyPlane(dpy, Scr->UnknownPm, pm, Scr->NormalGC,
465	    0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 );
466    }
467
468    if (pm == None)
469    {
470	tmp_win->icon_height = 0;
471	tmp_win->icon_width = 0;
472	valuemask = 0;
473    }
474    else
475    {
476	valuemask = CWBackPixmap;
477	attributes.background_pixmap = pm;
478    }
479
480    tmp_win->icon_w_width = MyFont_TextWidth(&Scr->IconFont,
481	tmp_win->icon_name, strlen(tmp_win->icon_name));
482
483    tmp_win->icon_w_width += 6;
484    if (tmp_win->icon_w_width < tmp_win->icon_width)
485    {
486	tmp_win->icon_x = (tmp_win->icon_width - tmp_win->icon_w_width)/2;
487	tmp_win->icon_x += 3;
488	tmp_win->icon_w_width = tmp_win->icon_width;
489    }
490    else
491    {
492	tmp_win->icon_x = 3;
493    }
494    tmp_win->icon_y = tmp_win->icon_height + Scr->IconFont.height;
495    tmp_win->icon_w_height = tmp_win->icon_height + Scr->IconFont.height + 4;
496
497    event_mask = 0;
498    if (tmp_win->wmhints && tmp_win->wmhints->flags & IconWindowHint)
499    {
500	tmp_win->icon_w = tmp_win->wmhints->icon_window;
501	if (tmp_win->forced ||
502	    XGetGeometry(dpy, tmp_win->icon_w, &JunkRoot, &JunkX, &JunkY,
503		     (unsigned int *)&tmp_win->icon_w_width, (unsigned int *)&tmp_win->icon_w_height,
504		     &JunkBW, &JunkDepth) == 0)
505	{
506	    tmp_win->icon_w = None;
507	    tmp_win->wmhints->flags &= ~IconWindowHint;
508	}
509	else
510	{
511	    tmp_win->icon_not_ours = TRUE;
512	    event_mask = EnterWindowMask | LeaveWindowMask;
513	}
514    }
515    else
516    {
517	tmp_win->icon_w = None;
518    }
519
520    if (tmp_win->icon_w == None)
521    {
522	tmp_win->icon_w = XCreateSimpleWindow(dpy, Scr->Root,
523	    0,0,
524	    tmp_win->icon_w_width, tmp_win->icon_w_height,
525	    Scr->IconBorderWidth, tmp_win->icon_border, tmp_win->iconc.back);
526	event_mask = ExposureMask;
527    }
528
529    XSelectInput (dpy, tmp_win->icon_w,
530		  KeyPressMask | ButtonPressMask | ButtonReleaseMask |
531		  event_mask);
532
533    tmp_win->icon_bm_w = None;
534    if (pm != None &&
535	(! (tmp_win->wmhints && tmp_win->wmhints->flags & IconWindowHint)))
536    {
537	int y;
538
539	y = 0;
540	if (tmp_win->icon_w_width == tmp_win->icon_width)
541	    x = 0;
542	else
543	    x = (tmp_win->icon_w_width - tmp_win->icon_width)/2;
544
545	tmp_win->icon_bm_w = XCreateWindow (dpy, tmp_win->icon_w, x, y,
546					    (unsigned int)tmp_win->icon_width,
547					    (unsigned int)tmp_win->icon_height,
548					    (unsigned int) 0, Scr->d_depth,
549					    (unsigned int) CopyFromParent,
550					    Scr->d_visual, valuemask,
551					    &attributes);
552    }
553
554    /* I need to figure out where to put the icon window now, because
555     * getting here means that I am going to make the icon visible
556     */
557    if (tmp_win->wmhints &&
558	tmp_win->wmhints->flags & IconPositionHint)
559    {
560	final_x = tmp_win->wmhints->icon_x;
561	final_y = tmp_win->wmhints->icon_y;
562    }
563    else
564    {
565	PlaceIcon(tmp_win, def_x, def_y, &final_x, &final_y);
566    }
567
568    if (final_x > Scr->MyDisplayWidth)
569	final_x = Scr->MyDisplayWidth - tmp_win->icon_w_width -
570	    (2 * Scr->IconBorderWidth);
571
572    if (final_y > Scr->MyDisplayHeight)
573	final_y = Scr->MyDisplayHeight - tmp_win->icon_height -
574	    Scr->IconFont.height - 4 - (2 * Scr->IconBorderWidth);
575
576    XMoveWindow(dpy, tmp_win->icon_w, final_x, final_y);
577    tmp_win->iconified = TRUE;
578
579    XMapSubwindows(dpy, tmp_win->icon_w);
580    XSaveContext(dpy, tmp_win->icon_w, TwmContext, (caddr_t)tmp_win);
581    XSaveContext(dpy, tmp_win->icon_w, ScreenContext, (caddr_t)Scr);
582    XDefineCursor(dpy, tmp_win->icon_w, Scr->IconCursor);
583    if (pm) XFreePixmap (dpy, pm);
584    return;
585}
586