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