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) {
766d8e82c3Smrg        int x = 0;
776d8e82c3Smrg        int y = 0;
786d8e82c3Smrg        int mask = XParseGeometry(p->geometry, &x, &y,
79f66df612Smrg                                  (unsigned int *) &p->width,
80f66df612Smrg                                  (unsigned int *) &p->height);
813e747e6dSmrg
82f66df612Smrg        if (mask & XNegative)
836d8e82c3Smrg            x += Scr->MyDisplayWidth - p->width - (2 * Scr->BorderWidth);
843e747e6dSmrg
85f66df612Smrg        if (mask & YNegative)
866d8e82c3Smrg            y += Scr->MyDisplayHeight - p->height - (2 * Scr->BorderWidth);
873e747e6dSmrg
88f66df612Smrg        background = Scr->IconManagerC.back;
89f66df612Smrg        GetColorFromList(Scr->IconManagerBL, p->name, (XClassHint *) NULL,
90f66df612Smrg                         &background);
913e747e6dSmrg
926d8e82c3Smrg        p->w = XCreateSimpleWindow(dpy, Scr->Root, x, y,
936d8e82c3Smrg                                   (unsigned) p->width, (unsigned) p->height,
946d8e82c3Smrg                                   1, Scr->Black, background);
953e747e6dSmrg
96f66df612Smrg        snprintf(str, sizeof(str), "%s Icon Manager", p->name);
97f66df612Smrg        snprintf(str1, sizeof(str1), "%s Icons", p->name);
98f66df612Smrg        if (p->icon_name)
99f66df612Smrg            icon_name = p->icon_name;
100f66df612Smrg        else
101f66df612Smrg            icon_name = str1;
1023e747e6dSmrg
103f66df612Smrg        XSetStandardProperties(dpy, p->w, str, icon_name, None, NULL, 0, NULL);
1043e747e6dSmrg
105f66df612Smrg        p->twm_win = AddWindow(p->w, TRUE, p);
106f66df612Smrg        SetMapStateProp(p->twm_win, WithdrawnState);
1073e747e6dSmrg    }
108f66df612Smrg    for (p = &Scr->iconmgr; p != NULL; p = p->next) {
109f66df612Smrg        GrabButtons(p->twm_win);
110f66df612Smrg        GrabKeys(p->twm_win);
1113e747e6dSmrg    }
1123e747e6dSmrg}
1133e747e6dSmrg
1143e747e6dSmrg/**
1153e747e6dSmrg * allocate a new icon manager
1163e747e6dSmrg *
1173e747e6dSmrg *  \param name     the name of this icon manager
1183e747e6dSmrg *  \param con_name the name of the associated icon
119f66df612Smrg *  \param geom     a geometry string to eventually parse
120f66df612Smrg *      \param columns  the number of columns this icon manager has
1213e747e6dSmrg */
122f66df612SmrgIconMgr *
123f66df612SmrgAllocateIconManager(char *name, char *icon_name, char *geom, int columns)
1243e747e6dSmrg{
1253e747e6dSmrg    IconMgr *p;
1263e747e6dSmrg
1273e747e6dSmrg#ifdef DEBUG_ICONMGR
1283e747e6dSmrg    fprintf(stderr, "AllocateIconManager\n");
1293e747e6dSmrg    fprintf(stderr, "  name=\"%s\" icon_name=\"%s\", geom=\"%s\", col=%d\n",
130f66df612Smrg            name, icon_name ? icon_name : "<null>", geom, columns);
1313e747e6dSmrg#endif
1323e747e6dSmrg
1333e747e6dSmrg    if (Scr->NoIconManagers)
134f66df612Smrg        return NULL;
1353e747e6dSmrg
1366d8e82c3Smrg    p = (IconMgr *) malloc(sizeof(IconMgr));
1373e747e6dSmrg    p->name = name;
1383e747e6dSmrg    p->icon_name = icon_name;
1393e747e6dSmrg    p->geometry = geom;
1403e747e6dSmrg    p->columns = columns;
1413e747e6dSmrg    p->first = NULL;
1423e747e6dSmrg    p->last = NULL;
1433e747e6dSmrg    p->active = NULL;
1443e747e6dSmrg    p->scr = Scr;
1453e747e6dSmrg    p->count = 0;
1463e747e6dSmrg    p->x = 0;
1473e747e6dSmrg    p->y = 0;
1483e747e6dSmrg    p->width = 150;
1493e747e6dSmrg    p->height = 10;
1503e747e6dSmrg
1513e747e6dSmrg    Scr->iconmgr.lasti->next = p;
1523e747e6dSmrg    p->prev = Scr->iconmgr.lasti;
1533e747e6dSmrg    Scr->iconmgr.lasti = p;
1543e747e6dSmrg    p->next = NULL;
1553e747e6dSmrg
156f66df612Smrg    return (p);
1573e747e6dSmrg}
1583e747e6dSmrg
1593e747e6dSmrg/**
1603e747e6dSmrg * move the pointer around in an icon manager
1613e747e6dSmrg *
1623e747e6dSmrg *  \param dir one of the following:
1633e747e6dSmrg *    - F_FORWICONMGR:  forward in the window list
1643e747e6dSmrg *    - F_BACKICONMGR:  backward in the window list
1653e747e6dSmrg *    - F_UPICONMGR:    up one row
1663e747e6dSmrg *    - F_DOWNICONMG:   down one row
1673e747e6dSmrg *    - F_LEFTICONMGR:  left one column
1683e747e6dSmrg *    - F_RIGHTICONMGR: right one column
1693e747e6dSmrg */
170f66df612Smrgvoid
171f66df612SmrgMoveIconManager(int dir)
1723e747e6dSmrg{
1733e747e6dSmrg    IconMgr *ip;
1743e747e6dSmrg    WList *tmp = NULL;
1753e747e6dSmrg    int cur_row, cur_col, new_row, new_col;
1763e747e6dSmrg    int row_inc, col_inc;
1773e747e6dSmrg    int got_it;
1783e747e6dSmrg
179f66df612Smrg    if (!Active)
180f66df612Smrg        return;
1813e747e6dSmrg
1823e747e6dSmrg    cur_row = Active->row;
1833e747e6dSmrg    cur_col = Active->col;
1843e747e6dSmrg    ip = Active->iconmgr;
1853e747e6dSmrg
1863e747e6dSmrg    row_inc = 0;
1873e747e6dSmrg    col_inc = 0;
1883e747e6dSmrg    got_it = FALSE;
1893e747e6dSmrg
190f66df612Smrg    switch (dir) {
191f66df612Smrg    case F_FORWICONMGR:
192f66df612Smrg        if ((tmp = Active->next) == NULL)
193f66df612Smrg            tmp = ip->first;
194f66df612Smrg        got_it = TRUE;
195f66df612Smrg        break;
196f66df612Smrg
197f66df612Smrg    case F_BACKICONMGR:
198f66df612Smrg        if ((tmp = Active->prev) == NULL)
199f66df612Smrg            tmp = ip->last;
200f66df612Smrg        got_it = TRUE;
201f66df612Smrg        break;
202f66df612Smrg
203f66df612Smrg    case F_UPICONMGR:
204f66df612Smrg        row_inc = -1;
205f66df612Smrg        break;
206f66df612Smrg
207f66df612Smrg    case F_DOWNICONMGR:
208f66df612Smrg        row_inc = 1;
209f66df612Smrg        break;
210f66df612Smrg
211f66df612Smrg    case F_LEFTICONMGR:
212f66df612Smrg        col_inc = -1;
213f66df612Smrg        break;
214f66df612Smrg
215f66df612Smrg    case F_RIGHTICONMGR:
216f66df612Smrg        col_inc = 1;
217f66df612Smrg        break;
2183e747e6dSmrg    }
2193e747e6dSmrg
2203e747e6dSmrg    /* If got_it is FALSE ast this point then we got a left, right,
2213e747e6dSmrg     * up, or down, command.  We will enter this loop until we find
2223e747e6dSmrg     * a window to warp to.
2233e747e6dSmrg     */
2243e747e6dSmrg    new_row = cur_row;
2253e747e6dSmrg    new_col = cur_col;
2263e747e6dSmrg
227f66df612Smrg    while (!got_it) {
228f66df612Smrg        new_row += row_inc;
229f66df612Smrg        new_col += col_inc;
230f66df612Smrg        if (new_row < 0)
231f66df612Smrg            new_row = ip->cur_rows - 1;
232f66df612Smrg        if (new_col < 0)
233f66df612Smrg            new_col = ip->cur_columns - 1;
234f66df612Smrg        if (new_row >= ip->cur_rows)
235f66df612Smrg            new_row = 0;
236f66df612Smrg        if (new_col >= ip->cur_columns)
237f66df612Smrg            new_col = 0;
238f66df612Smrg
239f66df612Smrg        /* Now let's go through the list to see if there is an entry with this
240f66df612Smrg         * new position
241f66df612Smrg         */
242f66df612Smrg        for (tmp = ip->first; tmp != NULL; tmp = tmp->next) {
243f66df612Smrg            if (tmp->row == new_row && tmp->col == new_col) {
244f66df612Smrg                got_it = TRUE;
245f66df612Smrg                break;
246f66df612Smrg            }
247f66df612Smrg        }
2483e747e6dSmrg    }
2493e747e6dSmrg
250f66df612Smrg    if (!got_it) {
251f66df612Smrg        twmWarning("unable to find window (%d, %d) in icon manager",
252f66df612Smrg                   new_row, new_col);
253f66df612Smrg        return;
2543e747e6dSmrg    }
2553e747e6dSmrg
2563e747e6dSmrg    if (tmp == NULL)
257f66df612Smrg        return;
2583e747e6dSmrg
2593e747e6dSmrg    /* raise the frame so the icon manager is visible */
2603e747e6dSmrg    if (ip->twm_win->mapped) {
261f66df612Smrg        XRaiseWindow(dpy, ip->twm_win->frame);
262f66df612Smrg        XWarpPointer(dpy, None, tmp->icon, 0, 0, 0, 0, 5, 5);
263f66df612Smrg    }
264f66df612Smrg    else {
265f66df612Smrg        if (tmp->twm->title_height) {
266f66df612Smrg            int tbx = Scr->TBInfo.titlex;
267f66df612Smrg            int x = tmp->twm->highlightx;
268f66df612Smrg
269f66df612Smrg            XWarpPointer(dpy, None, tmp->twm->title_w, 0, 0, 0, 0,
270f66df612Smrg                         tbx + (x - tbx) / 2, Scr->TitleHeight / 4);
271f66df612Smrg        }
272f66df612Smrg        else {
273f66df612Smrg            XWarpPointer(dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5);
274f66df612Smrg        }
2753e747e6dSmrg    }
2763e747e6dSmrg}
2773e747e6dSmrg
2783e747e6dSmrg/**
2793e747e6dSmrg * jump from one icon manager to another, possibly even on another screen
2803e747e6dSmrg *  \param dir one of the following:
281ffd25bcaSmrg *    - F_NEXTICONMGR - go to the next icon manager
2823e747e6dSmrg *    - F_PREVICONMGR - go to the previous one
2833e747e6dSmrg */
2843e747e6dSmrg
285f66df612Smrgvoid
286f66df612SmrgJumpIconManager(int dir)
2873e747e6dSmrg{
2883e747e6dSmrg    IconMgr *ip, *tmp_ip = NULL;
2893e747e6dSmrg    int got_it = FALSE;
2903e747e6dSmrg
291f66df612Smrg    if (!Active)
292f66df612Smrg        return;
2933e747e6dSmrg
2943e747e6dSmrg#define ITER(i) (dir == F_NEXTICONMGR ? (i)->next : (i)->prev)
2953e747e6dSmrg#define IPOFSP(sp) (dir == F_NEXTICONMGR ? &(sp->iconmgr) : sp->iconmgr.lasti)
2963e747e6dSmrg#define TEST(ip) if ((ip)->count != 0 && (ip)->twm_win->mapped) \
297f66df612Smrg                 { got_it = TRUE; break; }
2983e747e6dSmrg
2993e747e6dSmrg    ip = Active->iconmgr;
3003e747e6dSmrg    for (tmp_ip = ITER(ip); tmp_ip; tmp_ip = ITER(tmp_ip)) {
301f66df612Smrg        TEST(tmp_ip);
3023e747e6dSmrg    }
3033e747e6dSmrg
3043e747e6dSmrg    if (!got_it) {
305f66df612Smrg        int origscreen = ip->scr->screen;
306f66df612Smrg        int inc = (dir == F_NEXTICONMGR ? 1 : -1);
307f66df612Smrg        int screen;
308f66df612Smrg
309f66df612Smrg        for (screen = origscreen + inc;; screen += inc) {
310f66df612Smrg            ScreenInfo *sp;
311f66df612Smrg
312f66df612Smrg            if (screen >= NumScreens)
313f66df612Smrg                screen = 0;
314f66df612Smrg            else if (screen < 0)
315f66df612Smrg                screen = NumScreens - 1;
316f66df612Smrg
317f66df612Smrg            sp = ScreenList[screen];
318f66df612Smrg            if (sp) {
319f66df612Smrg                for (tmp_ip = IPOFSP(sp); tmp_ip; tmp_ip = ITER(tmp_ip)) {
320f66df612Smrg                    TEST(tmp_ip);
321f66df612Smrg                }
322f66df612Smrg            }
323f66df612Smrg            if (got_it || screen == origscreen)
324f66df612Smrg                break;
325f66df612Smrg        }
3263e747e6dSmrg    }
3273e747e6dSmrg
3283e747e6dSmrg#undef ITER
3293e747e6dSmrg#undef IPOFSP
3303e747e6dSmrg#undef TEST
3313e747e6dSmrg
3323e747e6dSmrg    if (!got_it) {
333f66df612Smrg        Bell(XkbBI_MinorError, 0, None);
334f66df612Smrg        return;
3353e747e6dSmrg    }
3363e747e6dSmrg
3373e747e6dSmrg    /* raise the frame so it is visible */
3383e747e6dSmrg    XRaiseWindow(dpy, tmp_ip->twm_win->frame);
3393e747e6dSmrg    if (tmp_ip->active)
340f66df612Smrg        XWarpPointer(dpy, None, tmp_ip->active->icon, 0, 0, 0, 0, 5, 5);
3413e747e6dSmrg    else
342f66df612Smrg        XWarpPointer(dpy, None, tmp_ip->w, 0, 0, 0, 0, 5, 5);
3433e747e6dSmrg}
3443e747e6dSmrg
3453e747e6dSmrg/**
3463e747e6dSmrg * add a window to an icon manager
3473e747e6dSmrg *
3483e747e6dSmrg *  \param tmp_win the TwmWindow structure
3493e747e6dSmrg */
350f66df612SmrgWList *
351f66df612SmrgAddIconManager(TwmWindow *tmp_win)
3523e747e6dSmrg{
3533e747e6dSmrg    WList *tmp;
3543e747e6dSmrg    int h;
355f66df612Smrg    unsigned long valuemask;    /* mask for create windows */
356f66df612Smrg    XSetWindowAttributes attributes;    /* attributes for create windows */
3573e747e6dSmrg    IconMgr *ip;
3583e747e6dSmrg
3593e747e6dSmrg    tmp_win->list = NULL;
3603e747e6dSmrg
3613e747e6dSmrg    if (tmp_win->iconmgr || tmp_win->transient || Scr->NoIconManagers)
362f66df612Smrg        return NULL;
3633e747e6dSmrg
3646d8e82c3Smrg    if (LookInList(Scr->IconMgrNoShow, tmp_win->full_name, &tmp_win->xclass))
365f66df612Smrg        return NULL;
3663e747e6dSmrg    if (Scr->IconManagerDontShow &&
3676d8e82c3Smrg        !LookInList(Scr->IconMgrShow, tmp_win->full_name, &tmp_win->xclass))
368f66df612Smrg        return NULL;
369f66df612Smrg    if ((ip = (IconMgr *) LookInList(Scr->IconMgrs, tmp_win->full_name,
3706d8e82c3Smrg                                     &tmp_win->xclass)) == NULL)
371f66df612Smrg        ip = &Scr->iconmgr;
3723e747e6dSmrg
3736d8e82c3Smrg    tmp = (WList *) malloc(sizeof(WList));
3743e747e6dSmrg    tmp->iconmgr = ip;
3753e747e6dSmrg    tmp->next = NULL;
3763e747e6dSmrg    tmp->active = FALSE;
3773e747e6dSmrg    tmp->down = FALSE;
3783e747e6dSmrg
3793e747e6dSmrg    InsertInIconManager(ip, tmp, tmp_win);
3803e747e6dSmrg
3813e747e6dSmrg    tmp->twm = tmp_win;
3823e747e6dSmrg
3833e747e6dSmrg    tmp->fore = Scr->IconManagerC.fore;
3843e747e6dSmrg    tmp->back = Scr->IconManagerC.back;
3853e747e6dSmrg    tmp->highlight = Scr->IconManagerHighlight;
3863e747e6dSmrg
3876d8e82c3Smrg    GetColorFromList(Scr->IconManagerFL, tmp_win->full_name, &tmp_win->xclass,
388f66df612Smrg                     &tmp->fore);
3896d8e82c3Smrg    GetColorFromList(Scr->IconManagerBL, tmp_win->full_name, &tmp_win->xclass,
390f66df612Smrg                     &tmp->back);
3913e747e6dSmrg    GetColorFromList(Scr->IconManagerHighlightL, tmp_win->full_name,
3926d8e82c3Smrg                     &tmp_win->xclass, &tmp->highlight);
3933e747e6dSmrg
3943e747e6dSmrg    h = Scr->IconManagerFont.height + 10;
3953e747e6dSmrg    if (h < (siconify_height + 4))
396f66df612Smrg        h = siconify_height + 4;
3973e747e6dSmrg
3983e747e6dSmrg    ip->height = h * ip->count;
3993e747e6dSmrg    tmp->me = ip->count;
4003e747e6dSmrg    tmp->x = -1;
4013e747e6dSmrg    tmp->y = -1;
402ffd25bcaSmrg
4033e747e6dSmrg    valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
4043e747e6dSmrg    attributes.background_pixel = tmp->back;
4053e747e6dSmrg    attributes.border_pixel = tmp->back;
4063e747e6dSmrg    attributes.event_mask = (KeyPressMask | ButtonPressMask |
407f66df612Smrg                             ButtonReleaseMask | ExposureMask |
408f66df612Smrg                             EnterWindowMask | LeaveWindowMask);
4093e747e6dSmrg    attributes.cursor = Scr->IconMgrCursor;
410f66df612Smrg    tmp->w = XCreateWindow(dpy, ip->w, 0, 0, (unsigned int) 1,
411f66df612Smrg                           (unsigned int) h, (unsigned int) 0,
412f66df612Smrg                           CopyFromParent, (unsigned int) CopyFromParent,
413f66df612Smrg                           (Visual *) CopyFromParent, valuemask, &attributes);
4143e747e6dSmrg
4153e747e6dSmrg    valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
4163e747e6dSmrg    attributes.background_pixel = tmp->back;
4173e747e6dSmrg    attributes.border_pixel = Scr->Black;
418f66df612Smrg    attributes.event_mask = (ButtonReleaseMask | ButtonPressMask |
419f66df612Smrg                             ExposureMask);
4203e747e6dSmrg    attributes.cursor = Scr->ButtonCursor;
421f66df612Smrg    tmp->icon = XCreateWindow(dpy, tmp->w, 5, (int) (h - siconify_height) / 2,
422f66df612Smrg                              (unsigned int) siconify_width,
423f66df612Smrg                              (unsigned int) siconify_height,
424f66df612Smrg                              (unsigned int) 0, CopyFromParent,
425f66df612Smrg                              (unsigned int) CopyFromParent,
426f66df612Smrg                              (Visual *) CopyFromParent,
427f66df612Smrg                              valuemask, &attributes);
4283e747e6dSmrg
4293e747e6dSmrg    ip->count += 1;
4303e747e6dSmrg    PackIconManager(ip);
4313e747e6dSmrg    XMapWindow(dpy, tmp->w);
4323e747e6dSmrg
433f66df612Smrg    XSaveContext(dpy, tmp->w, IconManagerContext, (XPointer) tmp);
434f66df612Smrg    XSaveContext(dpy, tmp->w, TwmContext, (XPointer) tmp_win);
435f66df612Smrg    XSaveContext(dpy, tmp->w, ScreenContext, (XPointer) Scr);
436f66df612Smrg    XSaveContext(dpy, tmp->icon, TwmContext, (XPointer) tmp_win);
437f66df612Smrg    XSaveContext(dpy, tmp->icon, ScreenContext, (XPointer) Scr);
4383e747e6dSmrg    tmp_win->list = tmp;
4393e747e6dSmrg
440f66df612Smrg    if (!ip->twm_win->icon) {
441f66df612Smrg        XMapWindow(dpy, ip->w);
442f66df612Smrg        XMapWindow(dpy, ip->twm_win->frame);
4433e747e6dSmrg    }
4443e747e6dSmrg
445f66df612Smrg    if (Active == NULL)
446f66df612Smrg        Active = tmp;
4473e747e6dSmrg
4483e747e6dSmrg    return (tmp);
4493e747e6dSmrg}
4503e747e6dSmrg
4513e747e6dSmrg/**
4523e747e6dSmrg * put an allocated entry into an icon manager
4533e747e6dSmrg *
4543e747e6dSmrg *  \param ip  the icon manager pointer
4553e747e6dSmrg *  \param tmp the entry to insert
4563e747e6dSmrg */
457f66df612Smrgstatic void
458f66df612SmrgInsertInIconManager(IconMgr *ip, WList *tmp, TwmWindow *tmp_win)
4593e747e6dSmrg{
4603e747e6dSmrg    WList *tmp1;
4613e747e6dSmrg    int added;
462f66df612Smrg    int (*compar) (const char *, const char *)
463f66df612Smrg        = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
4643e747e6dSmrg
4653e747e6dSmrg    added = FALSE;
466f66df612Smrg    if (ip->first == NULL) {
467f66df612Smrg        ip->first = tmp;
468f66df612Smrg        tmp->prev = NULL;
469f66df612Smrg        ip->last = tmp;
470f66df612Smrg        added = TRUE;
4713e747e6dSmrg    }
472f66df612Smrg    else if (Scr->SortIconMgr) {
473f66df612Smrg        for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) {
474f66df612Smrg            if ((*compar) (tmp_win->icon_name, tmp1->twm->icon_name) < 0) {
475f66df612Smrg                tmp->next = tmp1;
476f66df612Smrg                tmp->prev = tmp1->prev;
477f66df612Smrg                tmp1->prev = tmp;
478f66df612Smrg                if (tmp->prev == NULL)
479f66df612Smrg                    ip->first = tmp;
480f66df612Smrg                else
481f66df612Smrg                    tmp->prev->next = tmp;
482f66df612Smrg                added = TRUE;
483f66df612Smrg                break;
484f66df612Smrg            }
485f66df612Smrg        }
4863e747e6dSmrg    }
4873e747e6dSmrg
488f66df612Smrg    if (!added) {
489f66df612Smrg        ip->last->next = tmp;
490f66df612Smrg        tmp->prev = ip->last;
491f66df612Smrg        ip->last = tmp;
4923e747e6dSmrg    }
4933e747e6dSmrg}
4943e747e6dSmrg
495f66df612Smrgstatic void
496f66df612SmrgRemoveFromIconManager(IconMgr *ip, WList *tmp)
4973e747e6dSmrg{
4983e747e6dSmrg    if (tmp->prev == NULL)
499f66df612Smrg        ip->first = tmp->next;
5003e747e6dSmrg    else
501f66df612Smrg        tmp->prev->next = tmp->next;
5023e747e6dSmrg
5033e747e6dSmrg    if (tmp->next == NULL)
504f66df612Smrg        ip->last = tmp->prev;
5053e747e6dSmrg    else
506f66df612Smrg        tmp->next->prev = tmp->prev;
5073e747e6dSmrg}
5083e747e6dSmrg
5093e747e6dSmrg/**
5103e747e6dSmrg * remove a window from the icon manager
5113e747e6dSmrg *  \param tmp_win the TwmWindow structure
5123e747e6dSmrg */
513f66df612Smrgvoid
514f66df612SmrgRemoveIconManager(TwmWindow *tmp_win)
5153e747e6dSmrg{
5163e747e6dSmrg    IconMgr *ip;
5173e747e6dSmrg    WList *tmp;
5183e747e6dSmrg
5193e747e6dSmrg    if (tmp_win->list == NULL)
520f66df612Smrg        return;
5213e747e6dSmrg
5223e747e6dSmrg    tmp = tmp_win->list;
5233e747e6dSmrg    tmp_win->list = NULL;
5243e747e6dSmrg    ip = tmp->iconmgr;
5253e747e6dSmrg
5263e747e6dSmrg    RemoveFromIconManager(ip, tmp);
527ffd25bcaSmrg
5283e747e6dSmrg    XDeleteContext(dpy, tmp->icon, TwmContext);
5293e747e6dSmrg    XDeleteContext(dpy, tmp->icon, ScreenContext);
5303e747e6dSmrg    XDestroyWindow(dpy, tmp->icon);
5313e747e6dSmrg    XDeleteContext(dpy, tmp->w, IconManagerContext);
5323e747e6dSmrg    XDeleteContext(dpy, tmp->w, TwmContext);
5333e747e6dSmrg    XDeleteContext(dpy, tmp->w, ScreenContext);
5343e747e6dSmrg    XDestroyWindow(dpy, tmp->w);
5353e747e6dSmrg    ip->count -= 1;
536c2535118Smrg    free(tmp);
5373e747e6dSmrg
5383e747e6dSmrg    PackIconManager(ip);
5393e747e6dSmrg
540f66df612Smrg    if (ip->count == 0) {
541f66df612Smrg        XUnmapWindow(dpy, ip->twm_win->frame);
5423e747e6dSmrg    }
5433e747e6dSmrg
5443e747e6dSmrg}
5453e747e6dSmrg
546f66df612Smrgvoid
547f66df612SmrgActiveIconManager(WList *active)
5483e747e6dSmrg{
5493e747e6dSmrg    active->active = TRUE;
5503e747e6dSmrg    Active = active;
5513e747e6dSmrg    Active->iconmgr->active = active;
5523e747e6dSmrg    DrawIconManagerBorder(active);
5533e747e6dSmrg}
5543e747e6dSmrg
555f66df612Smrgvoid
556f66df612SmrgNotActiveIconManager(WList *active)
5573e747e6dSmrg{
5583e747e6dSmrg    active->active = FALSE;
5593e747e6dSmrg    DrawIconManagerBorder(active);
5603e747e6dSmrg}
5613e747e6dSmrg
562f66df612Smrgvoid
563f66df612SmrgDrawIconManagerBorder(WList *tmp)
5643e747e6dSmrg{
5653e747e6dSmrg    {
566f66df612Smrg        XSetForeground(dpy, Scr->NormalGC, tmp->fore);
567f66df612Smrg        XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 2, 2,
568f66df612Smrg                       (unsigned) (tmp->width - 5),
569f66df612Smrg                       (unsigned) (tmp->height - 5));
570f66df612Smrg
571f66df612Smrg        if (tmp->active && Scr->Highlight)
572f66df612Smrg            XSetForeground(dpy, Scr->NormalGC, tmp->highlight);
573f66df612Smrg        else
574f66df612Smrg            XSetForeground(dpy, Scr->NormalGC, tmp->back);
575f66df612Smrg
576f66df612Smrg        XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 0, 0,
577f66df612Smrg                       (unsigned) (tmp->width - 1),
578f66df612Smrg                       (unsigned) (tmp->height - 1));
579f66df612Smrg        XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 1, 1,
580f66df612Smrg                       (unsigned) (tmp->width - 3),
581f66df612Smrg                       (unsigned) (tmp->height - 3));
5823e747e6dSmrg    }
5833e747e6dSmrg}
5843e747e6dSmrg
5853e747e6dSmrg/**
5863e747e6dSmrg * sort The Dude
5873e747e6dSmrg *
588f66df612Smrg *  \param ip a pointer to the icon manager structure
5893e747e6dSmrg */
590f66df612Smrgvoid
591f66df612SmrgSortIconManager(IconMgr *ip)
5923e747e6dSmrg{
5933e747e6dSmrg    WList *tmp1, *tmp2;
5943e747e6dSmrg    int done;
595f66df612Smrg    int (*compar) (const char *, const char *)
596f66df612Smrg        = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1);
5973e747e6dSmrg
5983e747e6dSmrg    if (ip == NULL)
599f66df612Smrg        ip = Active->iconmgr;
6003e747e6dSmrg
6013e747e6dSmrg    done = FALSE;
602f66df612Smrg    do {
603f66df612Smrg        for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) {
604f66df612Smrg            if ((tmp2 = tmp1->next) == NULL) {
605f66df612Smrg                done = TRUE;
606f66df612Smrg                break;
607f66df612Smrg            }
608f66df612Smrg            if ((*compar) (tmp1->twm->icon_name, tmp2->twm->icon_name) > 0) {
609f66df612Smrg                /* take it out and put it back in */
610f66df612Smrg                RemoveFromIconManager(ip, tmp2);
611f66df612Smrg                InsertInIconManager(ip, tmp2, tmp2->twm);
612f66df612Smrg                break;
613f66df612Smrg            }
614f66df612Smrg        }
6153e747e6dSmrg    }
6163e747e6dSmrg    while (!done);
6173e747e6dSmrg    PackIconManager(ip);
6183e747e6dSmrg}
6193e747e6dSmrg
6203e747e6dSmrg/**
621ffd25bcaSmrg * pack the icon manager windows following
622f66df612Smrg *              an addition or deletion
6233e747e6dSmrg *
624f66df612Smrg *  \param ip a pointer to the icon manager structure
6253e747e6dSmrg */
626f66df612Smrgvoid
627f66df612SmrgPackIconManager(IconMgr *ip)
6283e747e6dSmrg{
629f66df612Smrg    int newwidth, i, row, col, maxcol, colinc, rowinc, wheight, wwidth;
6303e747e6dSmrg    int savewidth;
6313e747e6dSmrg    WList *tmp;
6323e747e6dSmrg
6333e747e6dSmrg    wheight = Scr->IconManagerFont.height + 10;
6343e747e6dSmrg    if (wheight < (siconify_height + 4))
635f66df612Smrg        wheight = siconify_height + 4;
6363e747e6dSmrg
6373e747e6dSmrg    wwidth = ip->width / ip->columns;
6383e747e6dSmrg
6393e747e6dSmrg    rowinc = wheight;
6403e747e6dSmrg    colinc = wwidth;
6413e747e6dSmrg
6423e747e6dSmrg    row = 0;
6433e747e6dSmrg    col = ip->columns;
6443e747e6dSmrg    maxcol = 0;
645f66df612Smrg
646f66df612Smrg    for (i = 0, tmp = ip->first; tmp != NULL; i++, tmp = tmp->next) {
647f66df612Smrg        int new_x, new_y;
648f66df612Smrg
649f66df612Smrg        tmp->me = i;
650f66df612Smrg        if (++col >= ip->columns) {
651f66df612Smrg            col = 0;
652f66df612Smrg            row += 1;
653f66df612Smrg        }
654f66df612Smrg        if (col > maxcol)
655f66df612Smrg            maxcol = col;
656f66df612Smrg
657f66df612Smrg        new_x = col * colinc;
658f66df612Smrg        new_y = (row - 1) * rowinc;
659f66df612Smrg
660f66df612Smrg        /* if the position or size has not changed, don't touch it */
661f66df612Smrg        if (tmp->x != new_x || tmp->y != new_y ||
662f66df612Smrg            tmp->width != wwidth || tmp->height != wheight) {
663f66df612Smrg            XMoveResizeWindow(dpy, tmp->w,
664f66df612Smrg                              new_x, new_y,
665f66df612Smrg                              (unsigned) wwidth, (unsigned) wheight);
666f66df612Smrg
667f66df612Smrg            tmp->row = row - 1;
668f66df612Smrg            tmp->col = col;
669f66df612Smrg            tmp->x = new_x;
670f66df612Smrg            tmp->y = new_y;
671f66df612Smrg            tmp->width = wwidth;
672f66df612Smrg            tmp->height = wheight;
673f66df612Smrg        }
6743e747e6dSmrg    }
6753e747e6dSmrg    maxcol += 1;
6763e747e6dSmrg
6773e747e6dSmrg    ip->cur_rows = row;
6783e747e6dSmrg    ip->cur_columns = maxcol;
6793e747e6dSmrg    ip->height = row * rowinc;
6803e747e6dSmrg    if (ip->height == 0)
681f66df612Smrg        ip->height = rowinc;
6823e747e6dSmrg    newwidth = maxcol * colinc;
6833e747e6dSmrg    if (newwidth == 0)
684f66df612Smrg        newwidth = colinc;
6853e747e6dSmrg
686f66df612Smrg    XResizeWindow(dpy, ip->w, (unsigned) newwidth, (unsigned) ip->height);
6873e747e6dSmrg
6883e747e6dSmrg    savewidth = ip->width;
6893e747e6dSmrg    if (ip->twm_win)
690f66df612Smrg        SetupWindow(ip->twm_win,
691f66df612Smrg                    ip->twm_win->frame_x, ip->twm_win->frame_y,
692f66df612Smrg                    newwidth, ip->height + ip->twm_win->title_height, -1);
6933e747e6dSmrg    ip->width = savewidth;
6943e747e6dSmrg}
695