iconmgr.c revision c2535118
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
26/***********************************************************************
27 *
28 * Icon Manager routines
29 *
30 * 09-Mar-89 Tom LaStrange		File Created
31 *
32 ***********************************************************************/
33
34#include <stdio.h>
35#include "twm.h"
36#include "util.h"
37#include "parse.h"
38#include "screen.h"
39#include "resize.h"
40#include "add_window.h"
41#include "siconify.bm"
42#include <X11/Xos.h>
43#include <X11/Xmu/CharSet.h>
44
45static void InsertInIconManager ( IconMgr *ip, WList *tmp, TwmWindow *tmp_win );
46
47int iconmgr_textx = siconify_width+11;
48static WList *Active = NULL;
49WList *DownIconManager = NULL;
50int iconifybox_width = siconify_width;
51int iconifybox_height = siconify_height;
52
53/**
54 * create all the icon manager windows for this screen.
55 */
56void
57CreateIconManagers(void)
58{
59    IconMgr *p;
60    int mask;
61    char str[100];
62    char str1[100];
63    Pixel background;
64    char *icon_name;
65
66    if (Scr->NoIconManagers)
67	return;
68
69    if (Scr->siconifyPm == None)
70    {
71	Scr->siconifyPm = XCreatePixmapFromBitmapData(dpy, Scr->Root,
72	    (char *)siconify_bits, siconify_width, siconify_height, 1, 0, 1);
73    }
74
75    for (p = &Scr->iconmgr; p != NULL; p = p->next)
76    {
77	mask = XParseGeometry(p->geometry, &JunkX, &JunkY,
78			      (unsigned int *) &p->width, (unsigned int *)&p->height);
79
80	if (mask & XNegative)
81	    JunkX = Scr->MyDisplayWidth - p->width -
82	      (2 * Scr->BorderWidth) + JunkX;
83
84	if (mask & YNegative)
85	    JunkY = Scr->MyDisplayHeight - p->height -
86	      (2 * Scr->BorderWidth) + JunkY;
87
88	background = Scr->IconManagerC.back;
89	GetColorFromList(Scr->IconManagerBL, p->name, (XClassHint *)NULL,
90			 &background);
91
92	p->w = XCreateSimpleWindow(dpy, Scr->Root,
93	    JunkX, JunkY, p->width, p->height, 1,
94	    Scr->Black, background);
95
96	snprintf(str, sizeof(str), "%s Icon Manager", p->name);
97	snprintf(str1, sizeof(str1), "%s Icons", p->name);
98	if (p->icon_name)
99	    icon_name = p->icon_name;
100	else
101	    icon_name = str1;
102
103	XSetStandardProperties(dpy, p->w, str, icon_name, None, NULL, 0, NULL);
104
105	p->twm_win = AddWindow(p->w, TRUE, p);
106	SetMapStateProp (p->twm_win, WithdrawnState);
107    }
108    for (p = &Scr->iconmgr; p != NULL; p = p->next)
109    {
110	GrabButtons(p->twm_win);
111	GrabKeys(p->twm_win);
112    }
113}
114
115/**
116 * allocate a new icon manager
117 *
118 *  \param name     the name of this icon manager
119 *  \param con_name the name of the associated icon
120 *  \param geom	    a geometry string to eventually parse
121 *	\param columns  the number of columns this icon manager has
122 */
123IconMgr *AllocateIconManager(char *name, char *icon_name, char *geom, int columns)
124{
125    IconMgr *p;
126
127#ifdef DEBUG_ICONMGR
128    fprintf(stderr, "AllocateIconManager\n");
129    fprintf(stderr, "  name=\"%s\" icon_name=\"%s\", geom=\"%s\", col=%d\n",
130	name, icon_name, geom, columns);
131#endif
132
133    if (Scr->NoIconManagers)
134	return NULL;
135
136    p = malloc(sizeof(IconMgr));
137    p->name = name;
138    p->icon_name = icon_name;
139    p->geometry = geom;
140    p->columns = columns;
141    p->first = NULL;
142    p->last = NULL;
143    p->active = NULL;
144    p->scr = Scr;
145    p->count = 0;
146    p->x = 0;
147    p->y = 0;
148    p->width = 150;
149    p->height = 10;
150
151    Scr->iconmgr.lasti->next = p;
152    p->prev = Scr->iconmgr.lasti;
153    Scr->iconmgr.lasti = p;
154    p->next = NULL;
155
156    return(p);
157}
158
159/**
160 * move the pointer around in an icon manager
161 *
162 *  \param dir one of the following:
163 *    - F_FORWICONMGR:  forward in the window list
164 *    - F_BACKICONMGR:  backward in the window list
165 *    - F_UPICONMGR:    up one row
166 *    - F_DOWNICONMG:   down one row
167 *    - F_LEFTICONMGR:  left one column
168 *    - F_RIGHTICONMGR: right one column
169 */
170void MoveIconManager(int dir)
171{
172    IconMgr *ip;
173    WList *tmp = NULL;
174    int cur_row, cur_col, new_row, new_col;
175    int row_inc, col_inc;
176    int got_it;
177
178    if (!Active) return;
179
180    cur_row = Active->row;
181    cur_col = Active->col;
182    ip = Active->iconmgr;
183
184    row_inc = 0;
185    col_inc = 0;
186    got_it = FALSE;
187
188    switch (dir)
189    {
190	case F_FORWICONMGR:
191	    if ((tmp = Active->next) == NULL)
192		tmp = ip->first;
193	    got_it = TRUE;
194	    break;
195
196	case F_BACKICONMGR:
197	    if ((tmp = Active->prev) == NULL)
198		tmp = ip->last;
199	    got_it = TRUE;
200	    break;
201
202	case F_UPICONMGR:
203	    row_inc = -1;
204	    break;
205
206	case F_DOWNICONMGR:
207	    row_inc = 1;
208	    break;
209
210	case F_LEFTICONMGR:
211	    col_inc = -1;
212	    break;
213
214	case F_RIGHTICONMGR:
215	    col_inc = 1;
216	    break;
217    }
218
219    /* If got_it is FALSE ast this point then we got a left, right,
220     * up, or down, command.  We will enter this loop until we find
221     * a window to warp to.
222     */
223    new_row = cur_row;
224    new_col = cur_col;
225
226    while (!got_it)
227    {
228	new_row += row_inc;
229	new_col += col_inc;
230	if (new_row < 0)
231	    new_row = ip->cur_rows - 1;
232	if (new_col < 0)
233	    new_col = ip->cur_columns - 1;
234	if (new_row >= ip->cur_rows)
235	    new_row = 0;
236	if (new_col >= ip->cur_columns)
237	    new_col = 0;
238
239	/* Now let's go through the list to see if there is an entry with this
240	 * new position
241	 */
242	for (tmp = ip->first; tmp != NULL; tmp = tmp->next)
243	{
244	    if (tmp->row == new_row && tmp->col == new_col)
245	    {
246		got_it = TRUE;
247		break;
248	    }
249	}
250    }
251
252    if (!got_it)
253    {
254	fprintf (stderr,
255		 "%s:  unable to find window (%d, %d) in icon manager\n",
256		 ProgramName, new_row, new_col);
257	return;
258    }
259
260    if (tmp == NULL)
261      return;
262
263    /* raise the frame so the icon manager is visible */
264    if (ip->twm_win->mapped) {
265	XRaiseWindow(dpy, ip->twm_win->frame);
266	XWarpPointer(dpy, None, tmp->icon, 0,0,0,0, 5, 5);
267    } else {
268	if (tmp->twm->title_height) {
269	    int tbx = Scr->TBInfo.titlex;
270	    int x = tmp->twm->highlightx;
271	    XWarpPointer (dpy, None, tmp->twm->title_w, 0, 0, 0, 0,
272			  tbx + (x - tbx) / 2,
273			  Scr->TitleHeight / 4);
274	} else {
275	    XWarpPointer (dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5);
276	}
277    }
278}
279
280/**
281 * jump from one icon manager to another, possibly even on another screen
282 *  \param dir one of the following:
283 *    - F_NEXTICONMGR - go to the next icon manager
284 *    - F_PREVICONMGR - go to the previous one
285 */
286
287void JumpIconManager(int dir)
288{
289    IconMgr *ip, *tmp_ip = NULL;
290    int got_it = FALSE;
291    ScreenInfo *sp;
292    int screen;
293
294    if (!Active) return;
295
296
297#define ITER(i) (dir == F_NEXTICONMGR ? (i)->next : (i)->prev)
298#define IPOFSP(sp) (dir == F_NEXTICONMGR ? &(sp->iconmgr) : sp->iconmgr.lasti)
299#define TEST(ip) if ((ip)->count != 0 && (ip)->twm_win->mapped) \
300		 { got_it = TRUE; break; }
301
302    ip = Active->iconmgr;
303    for (tmp_ip = ITER(ip); tmp_ip; tmp_ip = ITER(tmp_ip)) {
304	TEST (tmp_ip);
305    }
306
307    if (!got_it) {
308	int origscreen = ip->scr->screen;
309	int inc = (dir == F_NEXTICONMGR ? 1 : -1);
310
311	for (screen = origscreen + inc; ; screen += inc) {
312	    if (screen >= NumScreens)
313	      screen = 0;
314	    else if (screen < 0)
315	      screen = NumScreens - 1;
316
317	    sp = ScreenList[screen];
318	    if (sp) {
319		for (tmp_ip = IPOFSP (sp); tmp_ip; tmp_ip = ITER(tmp_ip)) {
320		    TEST (tmp_ip);
321		}
322	    }
323	    if (got_it || screen == origscreen) break;
324	}
325    }
326
327#undef ITER
328#undef IPOFSP
329#undef TEST
330
331    if (!got_it) {
332	Bell(XkbBI_MinorError,0,None);
333	return;
334    }
335
336    /* raise the frame so it is visible */
337    XRaiseWindow(dpy, tmp_ip->twm_win->frame);
338    if (tmp_ip->active)
339	XWarpPointer(dpy, None, tmp_ip->active->icon, 0,0,0,0, 5, 5);
340    else
341	XWarpPointer(dpy, None, tmp_ip->w, 0,0,0,0, 5, 5);
342}
343
344/**
345 * add a window to an icon manager
346 *
347 *  \param tmp_win the TwmWindow structure
348 */
349WList *AddIconManager(TwmWindow *tmp_win)
350{
351    WList *tmp;
352    int h;
353    unsigned long valuemask;		/* mask for create windows */
354    XSetWindowAttributes attributes;	/* attributes for create windows */
355    IconMgr *ip;
356
357    tmp_win->list = NULL;
358
359    if (tmp_win->iconmgr || tmp_win->transient || Scr->NoIconManagers)
360	return NULL;
361
362    if (LookInList(Scr->IconMgrNoShow, tmp_win->full_name, &tmp_win->class))
363	return NULL;
364    if (Scr->IconManagerDontShow &&
365	!LookInList(Scr->IconMgrShow, tmp_win->full_name, &tmp_win->class))
366	return NULL;
367    if ((ip = (IconMgr *)LookInList(Scr->IconMgrs, tmp_win->full_name,
368	    &tmp_win->class)) == NULL)
369	ip = &Scr->iconmgr;
370
371    tmp = malloc(sizeof(WList));
372    tmp->iconmgr = ip;
373    tmp->next = NULL;
374    tmp->active = FALSE;
375    tmp->down = FALSE;
376
377    InsertInIconManager(ip, tmp, tmp_win);
378
379    tmp->twm = tmp_win;
380
381    tmp->fore = Scr->IconManagerC.fore;
382    tmp->back = Scr->IconManagerC.back;
383    tmp->highlight = Scr->IconManagerHighlight;
384
385    GetColorFromList(Scr->IconManagerFL, tmp_win->full_name, &tmp_win->class,
386	&tmp->fore);
387    GetColorFromList(Scr->IconManagerBL, tmp_win->full_name, &tmp_win->class,
388	&tmp->back);
389    GetColorFromList(Scr->IconManagerHighlightL, tmp_win->full_name,
390	&tmp_win->class, &tmp->highlight);
391
392    h = Scr->IconManagerFont.height + 10;
393    if (h < (siconify_height + 4))
394	h = siconify_height + 4;
395
396    ip->height = h * ip->count;
397    tmp->me = ip->count;
398    tmp->x = -1;
399    tmp->y = -1;
400
401    valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
402    attributes.background_pixel = tmp->back;
403    attributes.border_pixel = tmp->back;
404    attributes.event_mask = (KeyPressMask | ButtonPressMask |
405			     ButtonReleaseMask | ExposureMask |
406			     EnterWindowMask | LeaveWindowMask);
407    attributes.cursor = Scr->IconMgrCursor;
408    tmp->w = XCreateWindow (dpy, ip->w, 0, 0, (unsigned int) 1,
409			    (unsigned int) h, (unsigned int) 0,
410			    CopyFromParent, (unsigned int) CopyFromParent,
411			    (Visual *) CopyFromParent, valuemask, &attributes);
412
413
414    valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
415    attributes.background_pixel = tmp->back;
416    attributes.border_pixel = Scr->Black;
417    attributes.event_mask = (ButtonReleaseMask| ButtonPressMask |
418			     ExposureMask);
419    attributes.cursor = Scr->ButtonCursor;
420    tmp->icon = XCreateWindow (dpy, tmp->w, 5, (int) (h - siconify_height)/2,
421			       (unsigned int) siconify_width,
422			       (unsigned int) siconify_height,
423			       (unsigned int) 0, CopyFromParent,
424			       (unsigned int) CopyFromParent,
425			       (Visual *) CopyFromParent,
426			       valuemask, &attributes);
427
428    ip->count += 1;
429    PackIconManager(ip);
430    XMapWindow(dpy, tmp->w);
431
432    XSaveContext(dpy, tmp->w, IconManagerContext, (caddr_t) tmp);
433    XSaveContext(dpy, tmp->w, TwmContext, (caddr_t) tmp_win);
434    XSaveContext(dpy, tmp->w, ScreenContext, (caddr_t) Scr);
435    XSaveContext(dpy, tmp->icon, TwmContext, (caddr_t) tmp_win);
436    XSaveContext(dpy, tmp->icon, ScreenContext, (caddr_t) Scr);
437    tmp_win->list = tmp;
438
439    if (!ip->twm_win->icon)
440    {
441	XMapWindow(dpy, ip->w);
442	XMapWindow(dpy, ip->twm_win->frame);
443    }
444
445    if (Active == NULL) Active = tmp;
446
447    return (tmp);
448}
449
450/**
451 * put an allocated entry into an icon manager
452 *
453 *  \param ip  the icon manager pointer
454 *  \param tmp the entry to insert
455 */
456static void InsertInIconManager(IconMgr *ip, WList *tmp, TwmWindow *tmp_win)
457{
458    WList *tmp1;
459    int added;
460    int (*compar)(const char *, const char *)
461	= (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
462
463    added = FALSE;
464    if (ip->first == NULL)
465    {
466	ip->first = tmp;
467	tmp->prev = NULL;
468	ip->last = tmp;
469	added = TRUE;
470    }
471    else if (Scr->SortIconMgr)
472    {
473	for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next)
474	{
475	    if ((*compar)(tmp_win->icon_name, tmp1->twm->icon_name) < 0)
476	    {
477		tmp->next = tmp1;
478		tmp->prev = tmp1->prev;
479		tmp1->prev = tmp;
480		if (tmp->prev == NULL)
481		    ip->first = tmp;
482		else
483		    tmp->prev->next = tmp;
484		added = TRUE;
485		break;
486	    }
487	}
488    }
489
490    if (!added)
491    {
492	ip->last->next = tmp;
493	tmp->prev = ip->last;
494	ip->last = tmp;
495    }
496}
497
498static void RemoveFromIconManager(IconMgr *ip, WList *tmp)
499{
500    if (tmp->prev == NULL)
501	ip->first = tmp->next;
502    else
503	tmp->prev->next = tmp->next;
504
505    if (tmp->next == NULL)
506	ip->last = tmp->prev;
507    else
508	tmp->next->prev = tmp->prev;
509}
510
511/**
512 * remove a window from the icon manager
513 *  \param tmp_win the TwmWindow structure
514 */
515void RemoveIconManager(TwmWindow *tmp_win)
516{
517    IconMgr *ip;
518    WList *tmp;
519
520    if (tmp_win->list == NULL)
521	return;
522
523    tmp = tmp_win->list;
524    tmp_win->list = NULL;
525    ip = tmp->iconmgr;
526
527    RemoveFromIconManager(ip, tmp);
528
529    XDeleteContext(dpy, tmp->icon, TwmContext);
530    XDeleteContext(dpy, tmp->icon, ScreenContext);
531    XDestroyWindow(dpy, tmp->icon);
532    XDeleteContext(dpy, tmp->w, IconManagerContext);
533    XDeleteContext(dpy, tmp->w, TwmContext);
534    XDeleteContext(dpy, tmp->w, ScreenContext);
535    XDestroyWindow(dpy, tmp->w);
536    ip->count -= 1;
537    free(tmp);
538
539    PackIconManager(ip);
540
541    if (ip->count == 0)
542    {
543	XUnmapWindow(dpy, ip->twm_win->frame);
544    }
545
546}
547
548void ActiveIconManager(WList *active)
549{
550    active->active = TRUE;
551    Active = active;
552    Active->iconmgr->active = active;
553    DrawIconManagerBorder(active);
554}
555
556void NotActiveIconManager(WList *active)
557{
558    active->active = FALSE;
559    DrawIconManagerBorder(active);
560}
561
562void DrawIconManagerBorder(WList *tmp)
563{
564    {
565	XSetForeground(dpy, Scr->NormalGC, tmp->fore);
566	    XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 2, 2,
567		tmp->width-5, tmp->height-5);
568
569	if (tmp->active && Scr->Highlight)
570	    XSetForeground(dpy, Scr->NormalGC, tmp->highlight);
571	else
572	    XSetForeground(dpy, Scr->NormalGC, tmp->back);
573
574	XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 0, 0,
575	    tmp->width-1, tmp->height-1);
576	XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 1, 1,
577	    tmp->width-3, tmp->height-3);
578    }
579}
580
581/**
582 * sort The Dude
583 *
584 *  \param ip a pointer to the icon manager struture
585 */
586void SortIconManager(IconMgr *ip)
587{
588    WList *tmp1, *tmp2;
589    int done;
590    int (*compar)(const char *, const char *)
591	= (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
592
593    if (ip == NULL)
594	ip = Active->iconmgr;
595
596    done = FALSE;
597    do
598    {
599	for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next)
600	{
601	    if ((tmp2 = tmp1->next) == NULL)
602	    {
603		done = TRUE;
604		break;
605	    }
606	    if ((*compar)(tmp1->twm->icon_name, tmp2->twm->icon_name) > 0)
607	    {
608		/* take it out and put it back in */
609		RemoveFromIconManager(ip, tmp2);
610		InsertInIconManager(ip, tmp2, tmp2->twm);
611		break;
612	    }
613	}
614    }
615    while (!done);
616    PackIconManager(ip);
617}
618
619/**
620 * pack the icon manager windows following
621 *		an addition or deletion
622 *
623 *  \param ip a pointer to the icon manager struture
624 */
625void PackIconManager(IconMgr *ip)
626{
627    int newwidth, i, row, col, maxcol,  colinc, rowinc, wheight, wwidth;
628    int new_x, new_y;
629    int savewidth;
630    WList *tmp;
631
632    wheight = Scr->IconManagerFont.height + 10;
633    if (wheight < (siconify_height + 4))
634	wheight = siconify_height + 4;
635
636    wwidth = ip->width / ip->columns;
637
638    rowinc = wheight;
639    colinc = wwidth;
640
641    row = 0;
642    col = ip->columns;
643    maxcol = 0;
644    for (i = 0, tmp = ip->first; tmp != NULL; i++, tmp = tmp->next)
645    {
646	tmp->me = i;
647	if (++col >= ip->columns)
648	{
649	    col = 0;
650	    row += 1;
651	}
652	if (col > maxcol)
653	    maxcol = col;
654
655	new_x = col * colinc;
656	new_y = (row-1) * rowinc;
657
658	/* if the position or size has not changed, don't touch it */
659	if (tmp->x != new_x || tmp->y != new_y ||
660	    tmp->width != wwidth || tmp->height != wheight)
661	{
662	    XMoveResizeWindow(dpy, tmp->w, new_x, new_y, wwidth, wheight);
663
664	    tmp->row = row-1;
665	    tmp->col = col;
666	    tmp->x = new_x;
667	    tmp->y = new_y;
668	    tmp->width = wwidth;
669	    tmp->height = wheight;
670	}
671    }
672    maxcol += 1;
673
674    ip->cur_rows = row;
675    ip->cur_columns = maxcol;
676    ip->height = row * rowinc;
677    if (ip->height == 0)
678    	ip->height = rowinc;
679    newwidth = maxcol * colinc;
680    if (newwidth == 0)
681	newwidth = colinc;
682
683    XResizeWindow(dpy, ip->w, newwidth, ip->height);
684
685    savewidth = ip->width;
686    if (ip->twm_win)
687      SetupWindow (ip->twm_win,
688		   ip->twm_win->frame_x, ip->twm_win->frame_y,
689		   newwidth, ip->height + ip->twm_win->title_height, -1);
690    ip->width = savewidth;
691}
692