iconmgr.c revision f66df612
13e747e6dSmrg/*
2ffd25bcaSmrg *
33e747e6dSmrgCopyright 1989,1998  The Open Group
43e747e6dSmrg
53e747e6dSmrgPermission to use, copy, modify, distribute, and sell this software and its
63e747e6dSmrgdocumentation for any purpose is hereby granted without fee, provided that
73e747e6dSmrgthe above copyright notice appear in all copies and that both that
83e747e6dSmrgcopyright notice and this permission notice appear in supporting
93e747e6dSmrgdocumentation.
103e747e6dSmrg
113e747e6dSmrgThe above copyright notice and this permission notice shall be included in
123e747e6dSmrgall copies or substantial portions of the Software.
133e747e6dSmrg
143e747e6dSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
153e747e6dSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
163e747e6dSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
173e747e6dSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
183e747e6dSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
193e747e6dSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
203e747e6dSmrg
213e747e6dSmrgExcept as contained in this notice, the name of The Open Group shall not be
223e747e6dSmrgused in advertising or otherwise to promote the sale, use or other dealings
233e747e6dSmrgin this Software without prior written authorization from The Open Group.
243e747e6dSmrg * */
253e747e6dSmrg
263e747e6dSmrg/***********************************************************************
273e747e6dSmrg *
283e747e6dSmrg * Icon Manager routines
293e747e6dSmrg *
30f66df612Smrg * 09-Mar-89 Tom LaStrange              File Created
313e747e6dSmrg *
323e747e6dSmrg ***********************************************************************/
333e747e6dSmrg
343e747e6dSmrg#include <stdio.h>
353e747e6dSmrg#include "twm.h"
363e747e6dSmrg#include "util.h"
373e747e6dSmrg#include "parse.h"
383e747e6dSmrg#include "screen.h"
393e747e6dSmrg#include "resize.h"
403e747e6dSmrg#include "add_window.h"
413e747e6dSmrg#include "siconify.bm"
423e747e6dSmrg#include <X11/Xos.h>
433e747e6dSmrg#include <X11/Xmu/CharSet.h>
44c2535118Smrg
45f66df612Smrgstatic void InsertInIconManager(IconMgr *ip, WList *tmp, TwmWindow *tmp_win);
463e747e6dSmrg
47f66df612Smrgint iconmgr_textx = siconify_width + 11;
48c2535118Smrgstatic WList *Active = NULL;
493e747e6dSmrgWList *DownIconManager = NULL;
503e747e6dSmrgint iconifybox_width = siconify_width;
513e747e6dSmrgint iconifybox_height = siconify_height;
523e747e6dSmrg
533e747e6dSmrg/**
543e747e6dSmrg * create all the icon manager windows for this screen.
553e747e6dSmrg */
56c2535118Smrgvoid
57c2535118SmrgCreateIconManagers(void)
583e747e6dSmrg{
593e747e6dSmrg    IconMgr *p;
603e747e6dSmrg    char str[100];
613e747e6dSmrg    char str1[100];
623e747e6dSmrg    Pixel background;
63f66df612Smrg    const char *icon_name;
643e747e6dSmrg
653e747e6dSmrg    if (Scr->NoIconManagers)
66f66df612Smrg        return;
673e747e6dSmrg
68f66df612Smrg    if (Scr->siconifyPm == None) {
69f66df612Smrg        Scr->siconifyPm = XCreatePixmapFromBitmapData(dpy, Scr->Root,
70f66df612Smrg                                                      (char *) siconify_bits,
71f66df612Smrg                                                      siconify_width,
72f66df612Smrg                                                      siconify_height, 1, 0, 1);
733e747e6dSmrg    }
743e747e6dSmrg
75f66df612Smrg    for (p = &Scr->iconmgr; p != NULL; p = p->next) {
76f66df612Smrg        int mask = XParseGeometry(p->geometry, &JunkX, &JunkY,
77f66df612Smrg                                  (unsigned int *) &p->width,
78f66df612Smrg                                  (unsigned int *) &p->height);
793e747e6dSmrg
80f66df612Smrg        if (mask & XNegative)
81f66df612Smrg            JunkX = Scr->MyDisplayWidth - p->width -
82f66df612Smrg                (2 * Scr->BorderWidth) + JunkX;
833e747e6dSmrg
84f66df612Smrg        if (mask & YNegative)
85f66df612Smrg            JunkY = Scr->MyDisplayHeight - p->height -
86f66df612Smrg                (2 * Scr->BorderWidth) + JunkY;
873e747e6dSmrg
88f66df612Smrg        background = Scr->IconManagerC.back;
89f66df612Smrg        GetColorFromList(Scr->IconManagerBL, p->name, (XClassHint *) NULL,
90f66df612Smrg                         &background);
913e747e6dSmrg
92f66df612Smrg        p->w = XCreateSimpleWindow(dpy, Scr->Root,
93f66df612Smrg                                   JunkX, JunkY, (unsigned) p->width,
94f66df612Smrg                                   (unsigned) p->height, 1, Scr->Black,
95f66df612Smrg                                   background);
963e747e6dSmrg
97f66df612Smrg        snprintf(str, sizeof(str), "%s Icon Manager", p->name);
98f66df612Smrg        snprintf(str1, sizeof(str1), "%s Icons", p->name);
99f66df612Smrg        if (p->icon_name)
100f66df612Smrg            icon_name = p->icon_name;
101f66df612Smrg        else
102f66df612Smrg            icon_name = str1;
1033e747e6dSmrg
104f66df612Smrg        XSetStandardProperties(dpy, p->w, str, icon_name, None, NULL, 0, NULL);
1053e747e6dSmrg
106f66df612Smrg        p->twm_win = AddWindow(p->w, TRUE, p);
107f66df612Smrg        SetMapStateProp(p->twm_win, WithdrawnState);
1083e747e6dSmrg    }
109f66df612Smrg    for (p = &Scr->iconmgr; p != NULL; p = p->next) {
110f66df612Smrg        GrabButtons(p->twm_win);
111f66df612Smrg        GrabKeys(p->twm_win);
1123e747e6dSmrg    }
1133e747e6dSmrg}
1143e747e6dSmrg
1153e747e6dSmrg/**
1163e747e6dSmrg * allocate a new icon manager
1173e747e6dSmrg *
1183e747e6dSmrg *  \param name     the name of this icon manager
1193e747e6dSmrg *  \param con_name the name of the associated icon
120f66df612Smrg *  \param geom     a geometry string to eventually parse
121f66df612Smrg *      \param columns  the number of columns this icon manager has
1223e747e6dSmrg */
123f66df612SmrgIconMgr *
124f66df612SmrgAllocateIconManager(char *name, char *icon_name, char *geom, int columns)
1253e747e6dSmrg{
1263e747e6dSmrg    IconMgr *p;
1273e747e6dSmrg
1283e747e6dSmrg#ifdef DEBUG_ICONMGR
1293e747e6dSmrg    fprintf(stderr, "AllocateIconManager\n");
1303e747e6dSmrg    fprintf(stderr, "  name=\"%s\" icon_name=\"%s\", geom=\"%s\", col=%d\n",
131f66df612Smrg            name, icon_name ? icon_name : "<null>", geom, columns);
1323e747e6dSmrg#endif
1333e747e6dSmrg
1343e747e6dSmrg    if (Scr->NoIconManagers)
135f66df612Smrg        return NULL;
1363e747e6dSmrg
137c2535118Smrg    p = malloc(sizeof(IconMgr));
1383e747e6dSmrg    p->name = name;
1393e747e6dSmrg    p->icon_name = icon_name;
1403e747e6dSmrg    p->geometry = geom;
1413e747e6dSmrg    p->columns = columns;
1423e747e6dSmrg    p->first = NULL;
1433e747e6dSmrg    p->last = NULL;
1443e747e6dSmrg    p->active = NULL;
1453e747e6dSmrg    p->scr = Scr;
1463e747e6dSmrg    p->count = 0;
1473e747e6dSmrg    p->x = 0;
1483e747e6dSmrg    p->y = 0;
1493e747e6dSmrg    p->width = 150;
1503e747e6dSmrg    p->height = 10;
1513e747e6dSmrg
1523e747e6dSmrg    Scr->iconmgr.lasti->next = p;
1533e747e6dSmrg    p->prev = Scr->iconmgr.lasti;
1543e747e6dSmrg    Scr->iconmgr.lasti = p;
1553e747e6dSmrg    p->next = NULL;
1563e747e6dSmrg
157f66df612Smrg    return (p);
1583e747e6dSmrg}
1593e747e6dSmrg
1603e747e6dSmrg/**
1613e747e6dSmrg * move the pointer around in an icon manager
1623e747e6dSmrg *
1633e747e6dSmrg *  \param dir one of the following:
1643e747e6dSmrg *    - F_FORWICONMGR:  forward in the window list
1653e747e6dSmrg *    - F_BACKICONMGR:  backward in the window list
1663e747e6dSmrg *    - F_UPICONMGR:    up one row
1673e747e6dSmrg *    - F_DOWNICONMG:   down one row
1683e747e6dSmrg *    - F_LEFTICONMGR:  left one column
1693e747e6dSmrg *    - F_RIGHTICONMGR: right one column
1703e747e6dSmrg */
171f66df612Smrgvoid
172f66df612SmrgMoveIconManager(int dir)
1733e747e6dSmrg{
1743e747e6dSmrg    IconMgr *ip;
1753e747e6dSmrg    WList *tmp = NULL;
1763e747e6dSmrg    int cur_row, cur_col, new_row, new_col;
1773e747e6dSmrg    int row_inc, col_inc;
1783e747e6dSmrg    int got_it;
1793e747e6dSmrg
180f66df612Smrg    if (!Active)
181f66df612Smrg        return;
1823e747e6dSmrg
1833e747e6dSmrg    cur_row = Active->row;
1843e747e6dSmrg    cur_col = Active->col;
1853e747e6dSmrg    ip = Active->iconmgr;
1863e747e6dSmrg
1873e747e6dSmrg    row_inc = 0;
1883e747e6dSmrg    col_inc = 0;
1893e747e6dSmrg    got_it = FALSE;
1903e747e6dSmrg
191f66df612Smrg    switch (dir) {
192f66df612Smrg    case F_FORWICONMGR:
193f66df612Smrg        if ((tmp = Active->next) == NULL)
194f66df612Smrg            tmp = ip->first;
195f66df612Smrg        got_it = TRUE;
196f66df612Smrg        break;
197f66df612Smrg
198f66df612Smrg    case F_BACKICONMGR:
199f66df612Smrg        if ((tmp = Active->prev) == NULL)
200f66df612Smrg            tmp = ip->last;
201f66df612Smrg        got_it = TRUE;
202f66df612Smrg        break;
203f66df612Smrg
204f66df612Smrg    case F_UPICONMGR:
205f66df612Smrg        row_inc = -1;
206f66df612Smrg        break;
207f66df612Smrg
208f66df612Smrg    case F_DOWNICONMGR:
209f66df612Smrg        row_inc = 1;
210f66df612Smrg        break;
211f66df612Smrg
212f66df612Smrg    case F_LEFTICONMGR:
213f66df612Smrg        col_inc = -1;
214f66df612Smrg        break;
215f66df612Smrg
216f66df612Smrg    case F_RIGHTICONMGR:
217f66df612Smrg        col_inc = 1;
218f66df612Smrg        break;
2193e747e6dSmrg    }
2203e747e6dSmrg
2213e747e6dSmrg    /* If got_it is FALSE ast this point then we got a left, right,
2223e747e6dSmrg     * up, or down, command.  We will enter this loop until we find
2233e747e6dSmrg     * a window to warp to.
2243e747e6dSmrg     */
2253e747e6dSmrg    new_row = cur_row;
2263e747e6dSmrg    new_col = cur_col;
2273e747e6dSmrg
228f66df612Smrg    while (!got_it) {
229f66df612Smrg        new_row += row_inc;
230f66df612Smrg        new_col += col_inc;
231f66df612Smrg        if (new_row < 0)
232f66df612Smrg            new_row = ip->cur_rows - 1;
233f66df612Smrg        if (new_col < 0)
234f66df612Smrg            new_col = ip->cur_columns - 1;
235f66df612Smrg        if (new_row >= ip->cur_rows)
236f66df612Smrg            new_row = 0;
237f66df612Smrg        if (new_col >= ip->cur_columns)
238f66df612Smrg            new_col = 0;
239f66df612Smrg
240f66df612Smrg        /* Now let's go through the list to see if there is an entry with this
241f66df612Smrg         * new position
242f66df612Smrg         */
243f66df612Smrg        for (tmp = ip->first; tmp != NULL; tmp = tmp->next) {
244f66df612Smrg            if (tmp->row == new_row && tmp->col == new_col) {
245f66df612Smrg                got_it = TRUE;
246f66df612Smrg                break;
247f66df612Smrg            }
248f66df612Smrg        }
2493e747e6dSmrg    }
2503e747e6dSmrg
251f66df612Smrg    if (!got_it) {
252f66df612Smrg        twmWarning("unable to find window (%d, %d) in icon manager",
253f66df612Smrg                   new_row, new_col);
254f66df612Smrg        return;
2553e747e6dSmrg    }
2563e747e6dSmrg
2573e747e6dSmrg    if (tmp == NULL)
258f66df612Smrg        return;
2593e747e6dSmrg
2603e747e6dSmrg    /* raise the frame so the icon manager is visible */
2613e747e6dSmrg    if (ip->twm_win->mapped) {
262f66df612Smrg        XRaiseWindow(dpy, ip->twm_win->frame);
263f66df612Smrg        XWarpPointer(dpy, None, tmp->icon, 0, 0, 0, 0, 5, 5);
264f66df612Smrg    }
265f66df612Smrg    else {
266f66df612Smrg        if (tmp->twm->title_height) {
267f66df612Smrg            int tbx = Scr->TBInfo.titlex;
268f66df612Smrg            int x = tmp->twm->highlightx;
269f66df612Smrg
270f66df612Smrg            XWarpPointer(dpy, None, tmp->twm->title_w, 0, 0, 0, 0,
271f66df612Smrg                         tbx + (x - tbx) / 2, Scr->TitleHeight / 4);
272f66df612Smrg        }
273f66df612Smrg        else {
274f66df612Smrg            XWarpPointer(dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5);
275f66df612Smrg        }
2763e747e6dSmrg    }
2773e747e6dSmrg}
2783e747e6dSmrg
2793e747e6dSmrg/**
2803e747e6dSmrg * jump from one icon manager to another, possibly even on another screen
2813e747e6dSmrg *  \param dir one of the following:
282ffd25bcaSmrg *    - F_NEXTICONMGR - go to the next icon manager
2833e747e6dSmrg *    - F_PREVICONMGR - go to the previous one
2843e747e6dSmrg */
2853e747e6dSmrg
286f66df612Smrgvoid
287f66df612SmrgJumpIconManager(int dir)
2883e747e6dSmrg{
2893e747e6dSmrg    IconMgr *ip, *tmp_ip = NULL;
2903e747e6dSmrg    int got_it = FALSE;
2913e747e6dSmrg
292f66df612Smrg    if (!Active)
293f66df612Smrg        return;
2943e747e6dSmrg
2953e747e6dSmrg#define ITER(i) (dir == F_NEXTICONMGR ? (i)->next : (i)->prev)
2963e747e6dSmrg#define IPOFSP(sp) (dir == F_NEXTICONMGR ? &(sp->iconmgr) : sp->iconmgr.lasti)
2973e747e6dSmrg#define TEST(ip) if ((ip)->count != 0 && (ip)->twm_win->mapped) \
298f66df612Smrg                 { got_it = TRUE; break; }
2993e747e6dSmrg
3003e747e6dSmrg    ip = Active->iconmgr;
3013e747e6dSmrg    for (tmp_ip = ITER(ip); tmp_ip; tmp_ip = ITER(tmp_ip)) {
302f66df612Smrg        TEST(tmp_ip);
3033e747e6dSmrg    }
3043e747e6dSmrg
3053e747e6dSmrg    if (!got_it) {
306f66df612Smrg        int origscreen = ip->scr->screen;
307f66df612Smrg        int inc = (dir == F_NEXTICONMGR ? 1 : -1);
308f66df612Smrg        int screen;
309f66df612Smrg
310f66df612Smrg        for (screen = origscreen + inc;; screen += inc) {
311f66df612Smrg            ScreenInfo *sp;
312f66df612Smrg
313f66df612Smrg            if (screen >= NumScreens)
314f66df612Smrg                screen = 0;
315f66df612Smrg            else if (screen < 0)
316f66df612Smrg                screen = NumScreens - 1;
317f66df612Smrg
318f66df612Smrg            sp = ScreenList[screen];
319f66df612Smrg            if (sp) {
320f66df612Smrg                for (tmp_ip = IPOFSP(sp); tmp_ip; tmp_ip = ITER(tmp_ip)) {
321f66df612Smrg                    TEST(tmp_ip);
322f66df612Smrg                }
323f66df612Smrg            }
324f66df612Smrg            if (got_it || screen == origscreen)
325f66df612Smrg                break;
326f66df612Smrg        }
3273e747e6dSmrg    }
3283e747e6dSmrg
3293e747e6dSmrg#undef ITER
3303e747e6dSmrg#undef IPOFSP
3313e747e6dSmrg#undef TEST
3323e747e6dSmrg
3333e747e6dSmrg    if (!got_it) {
334f66df612Smrg        Bell(XkbBI_MinorError, 0, None);
335f66df612Smrg        return;
3363e747e6dSmrg    }
3373e747e6dSmrg
3383e747e6dSmrg    /* raise the frame so it is visible */
3393e747e6dSmrg    XRaiseWindow(dpy, tmp_ip->twm_win->frame);
3403e747e6dSmrg    if (tmp_ip->active)
341f66df612Smrg        XWarpPointer(dpy, None, tmp_ip->active->icon, 0, 0, 0, 0, 5, 5);
3423e747e6dSmrg    else
343f66df612Smrg        XWarpPointer(dpy, None, tmp_ip->w, 0, 0, 0, 0, 5, 5);
3443e747e6dSmrg}
3453e747e6dSmrg
3463e747e6dSmrg/**
3473e747e6dSmrg * add a window to an icon manager
3483e747e6dSmrg *
3493e747e6dSmrg *  \param tmp_win the TwmWindow structure
3503e747e6dSmrg */
351f66df612SmrgWList *
352f66df612SmrgAddIconManager(TwmWindow *tmp_win)
3533e747e6dSmrg{
3543e747e6dSmrg    WList *tmp;
3553e747e6dSmrg    int h;
356f66df612Smrg    unsigned long valuemask;    /* mask for create windows */
357f66df612Smrg    XSetWindowAttributes attributes;    /* attributes for create windows */
3583e747e6dSmrg    IconMgr *ip;
3593e747e6dSmrg
3603e747e6dSmrg    tmp_win->list = NULL;
3613e747e6dSmrg
3623e747e6dSmrg    if (tmp_win->iconmgr || tmp_win->transient || Scr->NoIconManagers)
363f66df612Smrg        return NULL;
3643e747e6dSmrg
3653e747e6dSmrg    if (LookInList(Scr->IconMgrNoShow, tmp_win->full_name, &tmp_win->class))
366f66df612Smrg        return NULL;
3673e747e6dSmrg    if (Scr->IconManagerDontShow &&
368f66df612Smrg        !LookInList(Scr->IconMgrShow, tmp_win->full_name, &tmp_win->class))
369f66df612Smrg        return NULL;
370f66df612Smrg    if ((ip = (IconMgr *) LookInList(Scr->IconMgrs, tmp_win->full_name,
371f66df612Smrg                                     &tmp_win->class)) == NULL)
372f66df612Smrg        ip = &Scr->iconmgr;
3733e747e6dSmrg
374c2535118Smrg    tmp = malloc(sizeof(WList));
3753e747e6dSmrg    tmp->iconmgr = ip;
3763e747e6dSmrg    tmp->next = NULL;
3773e747e6dSmrg    tmp->active = FALSE;
3783e747e6dSmrg    tmp->down = FALSE;
3793e747e6dSmrg
3803e747e6dSmrg    InsertInIconManager(ip, tmp, tmp_win);
3813e747e6dSmrg
3823e747e6dSmrg    tmp->twm = tmp_win;
3833e747e6dSmrg
3843e747e6dSmrg    tmp->fore = Scr->IconManagerC.fore;
3853e747e6dSmrg    tmp->back = Scr->IconManagerC.back;
3863e747e6dSmrg    tmp->highlight = Scr->IconManagerHighlight;
3873e747e6dSmrg
3883e747e6dSmrg    GetColorFromList(Scr->IconManagerFL, tmp_win->full_name, &tmp_win->class,
389f66df612Smrg                     &tmp->fore);
3903e747e6dSmrg    GetColorFromList(Scr->IconManagerBL, tmp_win->full_name, &tmp_win->class,
391f66df612Smrg                     &tmp->back);
3923e747e6dSmrg    GetColorFromList(Scr->IconManagerHighlightL, tmp_win->full_name,
393f66df612Smrg                     &tmp_win->class, &tmp->highlight);
3943e747e6dSmrg
3953e747e6dSmrg    h = Scr->IconManagerFont.height + 10;
3963e747e6dSmrg    if (h < (siconify_height + 4))
397f66df612Smrg        h = siconify_height + 4;
3983e747e6dSmrg
3993e747e6dSmrg    ip->height = h * ip->count;
4003e747e6dSmrg    tmp->me = ip->count;
4013e747e6dSmrg    tmp->x = -1;
4023e747e6dSmrg    tmp->y = -1;
403ffd25bcaSmrg
4043e747e6dSmrg    valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
4053e747e6dSmrg    attributes.background_pixel = tmp->back;
4063e747e6dSmrg    attributes.border_pixel = tmp->back;
4073e747e6dSmrg    attributes.event_mask = (KeyPressMask | ButtonPressMask |
408f66df612Smrg                             ButtonReleaseMask | ExposureMask |
409f66df612Smrg                             EnterWindowMask | LeaveWindowMask);
4103e747e6dSmrg    attributes.cursor = Scr->IconMgrCursor;
411f66df612Smrg    tmp->w = XCreateWindow(dpy, ip->w, 0, 0, (unsigned int) 1,
412f66df612Smrg                           (unsigned int) h, (unsigned int) 0,
413f66df612Smrg                           CopyFromParent, (unsigned int) CopyFromParent,
414f66df612Smrg                           (Visual *) CopyFromParent, valuemask, &attributes);
4153e747e6dSmrg
4163e747e6dSmrg    valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
4173e747e6dSmrg    attributes.background_pixel = tmp->back;
4183e747e6dSmrg    attributes.border_pixel = Scr->Black;
419f66df612Smrg    attributes.event_mask = (ButtonReleaseMask | ButtonPressMask |
420f66df612Smrg                             ExposureMask);
4213e747e6dSmrg    attributes.cursor = Scr->ButtonCursor;
422f66df612Smrg    tmp->icon = XCreateWindow(dpy, tmp->w, 5, (int) (h - siconify_height) / 2,
423f66df612Smrg                              (unsigned int) siconify_width,
424f66df612Smrg                              (unsigned int) siconify_height,
425f66df612Smrg                              (unsigned int) 0, CopyFromParent,
426f66df612Smrg                              (unsigned int) CopyFromParent,
427f66df612Smrg                              (Visual *) CopyFromParent,
428f66df612Smrg                              valuemask, &attributes);
4293e747e6dSmrg
4303e747e6dSmrg    ip->count += 1;
4313e747e6dSmrg    PackIconManager(ip);
4323e747e6dSmrg    XMapWindow(dpy, tmp->w);
4333e747e6dSmrg
434f66df612Smrg    XSaveContext(dpy, tmp->w, IconManagerContext, (XPointer) tmp);
435f66df612Smrg    XSaveContext(dpy, tmp->w, TwmContext, (XPointer) tmp_win);
436f66df612Smrg    XSaveContext(dpy, tmp->w, ScreenContext, (XPointer) Scr);
437f66df612Smrg    XSaveContext(dpy, tmp->icon, TwmContext, (XPointer) tmp_win);
438f66df612Smrg    XSaveContext(dpy, tmp->icon, ScreenContext, (XPointer) Scr);
4393e747e6dSmrg    tmp_win->list = tmp;
4403e747e6dSmrg
441f66df612Smrg    if (!ip->twm_win->icon) {
442f66df612Smrg        XMapWindow(dpy, ip->w);
443f66df612Smrg        XMapWindow(dpy, ip->twm_win->frame);
4443e747e6dSmrg    }
4453e747e6dSmrg
446f66df612Smrg    if (Active == NULL)
447f66df612Smrg        Active = tmp;
4483e747e6dSmrg
4493e747e6dSmrg    return (tmp);
4503e747e6dSmrg}
4513e747e6dSmrg
4523e747e6dSmrg/**
4533e747e6dSmrg * put an allocated entry into an icon manager
4543e747e6dSmrg *
4553e747e6dSmrg *  \param ip  the icon manager pointer
4563e747e6dSmrg *  \param tmp the entry to insert
4573e747e6dSmrg */
458f66df612Smrgstatic void
459f66df612SmrgInsertInIconManager(IconMgr *ip, WList *tmp, TwmWindow *tmp_win)
4603e747e6dSmrg{
4613e747e6dSmrg    WList *tmp1;
4623e747e6dSmrg    int added;
463f66df612Smrg    int (*compar) (const char *, const char *)
464f66df612Smrg        = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
4653e747e6dSmrg
4663e747e6dSmrg    added = FALSE;
467f66df612Smrg    if (ip->first == NULL) {
468f66df612Smrg        ip->first = tmp;
469f66df612Smrg        tmp->prev = NULL;
470f66df612Smrg        ip->last = tmp;
471f66df612Smrg        added = TRUE;
4723e747e6dSmrg    }
473f66df612Smrg    else if (Scr->SortIconMgr) {
474f66df612Smrg        for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) {
475f66df612Smrg            if ((*compar) (tmp_win->icon_name, tmp1->twm->icon_name) < 0) {
476f66df612Smrg                tmp->next = tmp1;
477f66df612Smrg                tmp->prev = tmp1->prev;
478f66df612Smrg                tmp1->prev = tmp;
479f66df612Smrg                if (tmp->prev == NULL)
480f66df612Smrg                    ip->first = tmp;
481f66df612Smrg                else
482f66df612Smrg                    tmp->prev->next = tmp;
483f66df612Smrg                added = TRUE;
484f66df612Smrg                break;
485f66df612Smrg            }
486f66df612Smrg        }
4873e747e6dSmrg    }
4883e747e6dSmrg
489f66df612Smrg    if (!added) {
490f66df612Smrg        ip->last->next = tmp;
491f66df612Smrg        tmp->prev = ip->last;
492f66df612Smrg        ip->last = tmp;
4933e747e6dSmrg    }
4943e747e6dSmrg}
4953e747e6dSmrg
496f66df612Smrgstatic void
497f66df612SmrgRemoveFromIconManager(IconMgr *ip, WList *tmp)
4983e747e6dSmrg{
4993e747e6dSmrg    if (tmp->prev == NULL)
500f66df612Smrg        ip->first = tmp->next;
5013e747e6dSmrg    else
502f66df612Smrg        tmp->prev->next = tmp->next;
5033e747e6dSmrg
5043e747e6dSmrg    if (tmp->next == NULL)
505f66df612Smrg        ip->last = tmp->prev;
5063e747e6dSmrg    else
507f66df612Smrg        tmp->next->prev = tmp->prev;
5083e747e6dSmrg}
5093e747e6dSmrg
5103e747e6dSmrg/**
5113e747e6dSmrg * remove a window from the icon manager
5123e747e6dSmrg *  \param tmp_win the TwmWindow structure
5133e747e6dSmrg */
514f66df612Smrgvoid
515f66df612SmrgRemoveIconManager(TwmWindow *tmp_win)
5163e747e6dSmrg{
5173e747e6dSmrg    IconMgr *ip;
5183e747e6dSmrg    WList *tmp;
5193e747e6dSmrg
5203e747e6dSmrg    if (tmp_win->list == NULL)
521f66df612Smrg        return;
5223e747e6dSmrg
5233e747e6dSmrg    tmp = tmp_win->list;
5243e747e6dSmrg    tmp_win->list = NULL;
5253e747e6dSmrg    ip = tmp->iconmgr;
5263e747e6dSmrg
5273e747e6dSmrg    RemoveFromIconManager(ip, tmp);
528ffd25bcaSmrg
5293e747e6dSmrg    XDeleteContext(dpy, tmp->icon, TwmContext);
5303e747e6dSmrg    XDeleteContext(dpy, tmp->icon, ScreenContext);
5313e747e6dSmrg    XDestroyWindow(dpy, tmp->icon);
5323e747e6dSmrg    XDeleteContext(dpy, tmp->w, IconManagerContext);
5333e747e6dSmrg    XDeleteContext(dpy, tmp->w, TwmContext);
5343e747e6dSmrg    XDeleteContext(dpy, tmp->w, ScreenContext);
5353e747e6dSmrg    XDestroyWindow(dpy, tmp->w);
5363e747e6dSmrg    ip->count -= 1;
537c2535118Smrg    free(tmp);
5383e747e6dSmrg
5393e747e6dSmrg    PackIconManager(ip);
5403e747e6dSmrg
541f66df612Smrg    if (ip->count == 0) {
542f66df612Smrg        XUnmapWindow(dpy, ip->twm_win->frame);
5433e747e6dSmrg    }
5443e747e6dSmrg
5453e747e6dSmrg}
5463e747e6dSmrg
547f66df612Smrgvoid
548f66df612SmrgActiveIconManager(WList *active)
5493e747e6dSmrg{
5503e747e6dSmrg    active->active = TRUE;
5513e747e6dSmrg    Active = active;
5523e747e6dSmrg    Active->iconmgr->active = active;
5533e747e6dSmrg    DrawIconManagerBorder(active);
5543e747e6dSmrg}
5553e747e6dSmrg
556f66df612Smrgvoid
557f66df612SmrgNotActiveIconManager(WList *active)
5583e747e6dSmrg{
5593e747e6dSmrg    active->active = FALSE;
5603e747e6dSmrg    DrawIconManagerBorder(active);
5613e747e6dSmrg}
5623e747e6dSmrg
563f66df612Smrgvoid
564f66df612SmrgDrawIconManagerBorder(WList *tmp)
5653e747e6dSmrg{
5663e747e6dSmrg    {
567f66df612Smrg        XSetForeground(dpy, Scr->NormalGC, tmp->fore);
568f66df612Smrg        XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 2, 2,
569f66df612Smrg                       (unsigned) (tmp->width - 5),
570f66df612Smrg                       (unsigned) (tmp->height - 5));
571f66df612Smrg
572f66df612Smrg        if (tmp->active && Scr->Highlight)
573f66df612Smrg            XSetForeground(dpy, Scr->NormalGC, tmp->highlight);
574f66df612Smrg        else
575f66df612Smrg            XSetForeground(dpy, Scr->NormalGC, tmp->back);
576f66df612Smrg
577f66df612Smrg        XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 0, 0,
578f66df612Smrg                       (unsigned) (tmp->width - 1),
579f66df612Smrg                       (unsigned) (tmp->height - 1));
580f66df612Smrg        XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 1, 1,
581f66df612Smrg                       (unsigned) (tmp->width - 3),
582f66df612Smrg                       (unsigned) (tmp->height - 3));
5833e747e6dSmrg    }
5843e747e6dSmrg}
5853e747e6dSmrg
5863e747e6dSmrg/**
5873e747e6dSmrg * sort The Dude
5883e747e6dSmrg *
589f66df612Smrg *  \param ip a pointer to the icon manager structure
5903e747e6dSmrg */
591f66df612Smrgvoid
592f66df612SmrgSortIconManager(IconMgr *ip)
5933e747e6dSmrg{
5943e747e6dSmrg    WList *tmp1, *tmp2;
5953e747e6dSmrg    int done;
596f66df612Smrg    int (*compar) (const char *, const char *)
597f66df612Smrg        = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
5983e747e6dSmrg
5993e747e6dSmrg    if (ip == NULL)
600f66df612Smrg        ip = Active->iconmgr;
6013e747e6dSmrg
6023e747e6dSmrg    done = FALSE;
603f66df612Smrg    do {
604f66df612Smrg        for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) {
605f66df612Smrg            if ((tmp2 = tmp1->next) == NULL) {
606f66df612Smrg                done = TRUE;
607f66df612Smrg                break;
608f66df612Smrg            }
609f66df612Smrg            if ((*compar) (tmp1->twm->icon_name, tmp2->twm->icon_name) > 0) {
610f66df612Smrg                /* take it out and put it back in */
611f66df612Smrg                RemoveFromIconManager(ip, tmp2);
612f66df612Smrg                InsertInIconManager(ip, tmp2, tmp2->twm);
613f66df612Smrg                break;
614f66df612Smrg            }
615f66df612Smrg        }
6163e747e6dSmrg    }
6173e747e6dSmrg    while (!done);
6183e747e6dSmrg    PackIconManager(ip);
6193e747e6dSmrg}
6203e747e6dSmrg
6213e747e6dSmrg/**
622ffd25bcaSmrg * pack the icon manager windows following
623f66df612Smrg *              an addition or deletion
6243e747e6dSmrg *
625f66df612Smrg *  \param ip a pointer to the icon manager structure
6263e747e6dSmrg */
627f66df612Smrgvoid
628f66df612SmrgPackIconManager(IconMgr *ip)
6293e747e6dSmrg{
630f66df612Smrg    int newwidth, i, row, col, maxcol, colinc, rowinc, wheight, wwidth;
6313e747e6dSmrg    int savewidth;
6323e747e6dSmrg    WList *tmp;
6333e747e6dSmrg
6343e747e6dSmrg    wheight = Scr->IconManagerFont.height + 10;
6353e747e6dSmrg    if (wheight < (siconify_height + 4))
636f66df612Smrg        wheight = siconify_height + 4;
6373e747e6dSmrg
6383e747e6dSmrg    wwidth = ip->width / ip->columns;
6393e747e6dSmrg
6403e747e6dSmrg    rowinc = wheight;
6413e747e6dSmrg    colinc = wwidth;
6423e747e6dSmrg
6433e747e6dSmrg    row = 0;
6443e747e6dSmrg    col = ip->columns;
6453e747e6dSmrg    maxcol = 0;
646f66df612Smrg
647f66df612Smrg    for (i = 0, tmp = ip->first; tmp != NULL; i++, tmp = tmp->next) {
648f66df612Smrg        int new_x, new_y;
649f66df612Smrg
650f66df612Smrg        tmp->me = i;
651f66df612Smrg        if (++col >= ip->columns) {
652f66df612Smrg            col = 0;
653f66df612Smrg            row += 1;
654f66df612Smrg        }
655f66df612Smrg        if (col > maxcol)
656f66df612Smrg            maxcol = col;
657f66df612Smrg
658f66df612Smrg        new_x = col * colinc;
659f66df612Smrg        new_y = (row - 1) * rowinc;
660f66df612Smrg
661f66df612Smrg        /* if the position or size has not changed, don't touch it */
662f66df612Smrg        if (tmp->x != new_x || tmp->y != new_y ||
663f66df612Smrg            tmp->width != wwidth || tmp->height != wheight) {
664f66df612Smrg            XMoveResizeWindow(dpy, tmp->w,
665f66df612Smrg                              new_x, new_y,
666f66df612Smrg                              (unsigned) wwidth, (unsigned) wheight);
667f66df612Smrg
668f66df612Smrg            tmp->row = row - 1;
669f66df612Smrg            tmp->col = col;
670f66df612Smrg            tmp->x = new_x;
671f66df612Smrg            tmp->y = new_y;
672f66df612Smrg            tmp->width = wwidth;
673f66df612Smrg            tmp->height = wheight;
674f66df612Smrg        }
6753e747e6dSmrg    }
6763e747e6dSmrg    maxcol += 1;
6773e747e6dSmrg
6783e747e6dSmrg    ip->cur_rows = row;
6793e747e6dSmrg    ip->cur_columns = maxcol;
6803e747e6dSmrg    ip->height = row * rowinc;
6813e747e6dSmrg    if (ip->height == 0)
682f66df612Smrg        ip->height = rowinc;
6833e747e6dSmrg    newwidth = maxcol * colinc;
6843e747e6dSmrg    if (newwidth == 0)
685f66df612Smrg        newwidth = colinc;
6863e747e6dSmrg
687f66df612Smrg    XResizeWindow(dpy, ip->w, (unsigned) newwidth, (unsigned) ip->height);
6883e747e6dSmrg
6893e747e6dSmrg    savewidth = ip->width;
6903e747e6dSmrg    if (ip->twm_win)
691f66df612Smrg        SetupWindow(ip->twm_win,
692f66df612Smrg                    ip->twm_win->frame_x, ip->twm_win->frame_y,
693f66df612Smrg                    newwidth, ip->height + ip->twm_win->title_height, -1);
6943e747e6dSmrg    ip->width = savewidth;
6953e747e6dSmrg}
696