1645f5050Syouri/*
2645f5050Syouri * Copyright 1989 Massachusetts Institute of Technology
30bbfda8aSnia * Copyright 1992 Claude Lecommandeur.
4645f5050Syouri */
5645f5050Syouri
6645f5050Syouri/***********************************************************************
7645f5050Syouri *
8645f5050Syouri * $XConsortium: iconmgr.c,v 1.48 91/09/10 15:27:07 dave Exp $
9645f5050Syouri *
10645f5050Syouri * Icon Manager routines
11645f5050Syouri *
120bbfda8aSnia * 09-Mar-89 Tom LaStrange              File Created
13645f5050Syouri *
14645f5050Syouri * Do the necessary modification to be integrated in ctwm.
15645f5050Syouri * Can no longer be used for the standard twm.
16645f5050Syouri *
17645f5050Syouri * 22-April-92 Claude Lecommandeur.
18645f5050Syouri *
19645f5050Syouri *
20645f5050Syouri ***********************************************************************/
21645f5050Syouri
220bbfda8aSnia#include "ctwm.h"
230bbfda8aSnia
24645f5050Syouri#include <stdio.h>
250bbfda8aSnia#include <stdlib.h>
260bbfda8aSnia#include <string.h>
270bbfda8aSnia#include <strings.h>
280bbfda8aSnia
29645f5050Syouri#include <X11/Xatom.h>
300bbfda8aSnia
31645f5050Syouri#include "util.h"
320bbfda8aSnia#include "iconmgr.h"
330bbfda8aSnia#include "icons_builtin.h"
34645f5050Syouri#include "screen.h"
350bbfda8aSnia#include "drawing.h"
360bbfda8aSnia#include "functions_defs.h"
370bbfda8aSnia#include "list.h"
380bbfda8aSnia#include "occupation.h"
390bbfda8aSnia#include "otp.h"
40645f5050Syouri#include "add_window.h"
410bbfda8aSnia#include "gram.tab.h"
42df1c27a6Snia#include "vscreen.h"
430bbfda8aSnia#include "win_decorations.h"
440bbfda8aSnia#include "win_resize.h"
450bbfda8aSnia#include "win_utils.h"
46df1c27a6Snia#include "xparsegeometry.h"
470bbfda8aSnia
480bbfda8aSnia
490bbfda8aSnia/* Where we start drawing the name in the icon manager */
500bbfda8aSniastatic int iconmgr_textx;
51645f5050Syouri
520bbfda8aSniastatic WList *Active = NULL;
530bbfda8aSniastatic WList *Current = NULL;
54645f5050SyouriWList *DownIconManager = NULL;
55645f5050Syouri
56645f5050Syouri/***********************************************************************
57645f5050Syouri *
58645f5050Syouri *  Procedure:
590bbfda8aSnia *      CreateIconManagers - creat all the icon manager windows
600bbfda8aSnia *              for this screen.
61645f5050Syouri *
62645f5050Syouri *  Returned Value:
630bbfda8aSnia *      none
64645f5050Syouri *
65645f5050Syouri *  Inputs:
660bbfda8aSnia *      none
67645f5050Syouri *
68645f5050Syouri ***********************************************************************
69645f5050Syouri */
70645f5050Syouri
71645f5050Syourivoid CreateIconManagers(void)
72645f5050Syouri{
730bbfda8aSnia	WorkSpace    *ws;
740bbfda8aSnia
750bbfda8aSnia	if(Scr->NoIconManagers) {
760bbfda8aSnia		return;
770bbfda8aSnia	}
780bbfda8aSnia
790bbfda8aSnia	/*
800bbfda8aSnia	 * Move past the iconified icon to start the text.
810bbfda8aSnia	 * XXX Semi-arbitrary magic add'l padding, to deal with various inner
820bbfda8aSnia	 * positioning of the icon subwindow.  Be smarter (or at least
830bbfda8aSnia	 * clearer) about this...
840bbfda8aSnia	 */
850bbfda8aSnia	iconmgr_textx = im_iconified_icon_width + 11;
860bbfda8aSnia	if(Scr->use3Diconmanagers) {
870bbfda8aSnia		iconmgr_textx += Scr->IconManagerShadowDepth;
880bbfda8aSnia	}
890bbfda8aSnia
900bbfda8aSnia	if(Scr->siconifyPm == None) {
910bbfda8aSnia		Scr->siconifyPm = Create2DIconManagerIcon();
920bbfda8aSnia	}
930bbfda8aSnia
94df1c27a6Snia	// This loop is confusing.  The inner for() loops p over the ->next
95df1c27a6Snia	// elements in the list, which is all the iconmgr's in the workspace.
96df1c27a6Snia	// The outer for() loops q over the ->nextv (<-- extra 'v' on the
97df1c27a6Snia	// end), which is a link to the head of the iconmgr list for the
98df1c27a6Snia	// _next_ workspace.
990bbfda8aSnia	ws = Scr->workSpaceMgr.workSpaceList;
1000bbfda8aSnia	for(IconMgr *q = Scr->iconmgr; q != NULL; q = q->nextv) {
1010bbfda8aSnia		for(IconMgr *p = q; p != NULL; p = p->next) {
1020bbfda8aSnia			int gx, gy;
1030bbfda8aSnia			char imname[100];
1040bbfda8aSnia			int mask;
1050bbfda8aSnia			int gravity;
1060bbfda8aSnia			int bw;
1070bbfda8aSnia			Pixel background;
1080bbfda8aSnia
1090bbfda8aSnia			snprintf(imname, sizeof(imname), "%s Icon Manager", p->name);
1100bbfda8aSnia
1110bbfda8aSnia			if(!p->geometry || !strlen(p->geometry)) {
1120bbfda8aSnia				p->geometry = "+0+0";
1130bbfda8aSnia			}
114df1c27a6Snia			mask = RLayoutXParseGeometry(Scr->Layout, p->geometry,
115df1c27a6Snia			                             &gx, &gy,
116df1c27a6Snia			                             (unsigned int *) &p->width, (unsigned int *)&p->height);
1170bbfda8aSnia
1180bbfda8aSnia			bw = LookInList(Scr->NoBorder, imname, NULL) ? 0 :
1190bbfda8aSnia			     (Scr->ThreeDBorderWidth ? Scr->ThreeDBorderWidth : Scr->BorderWidth);
1200bbfda8aSnia
1210bbfda8aSnia			if(mask & XNegative) {
1220bbfda8aSnia				gx += Scr->rootw - p->width - 2 * bw;
1230bbfda8aSnia				gravity = (mask & YNegative) ? SouthEastGravity : NorthEastGravity;
1240bbfda8aSnia			}
1250bbfda8aSnia			else {
1260bbfda8aSnia				gravity = (mask & YNegative) ? SouthWestGravity : NorthWestGravity;
1270bbfda8aSnia			}
1280bbfda8aSnia			if(mask & YNegative) {
1290bbfda8aSnia				gy += Scr->rooth - p->height - 2 * bw;
1300bbfda8aSnia			}
1310bbfda8aSnia
1320bbfda8aSnia			background = Scr->IconManagerC.back;
1330bbfda8aSnia			GetColorFromList(Scr->IconManagerBL, p->name, NULL,
1340bbfda8aSnia			                 &background);
1350bbfda8aSnia
1360bbfda8aSnia			if(p->width  < 1) {
1370bbfda8aSnia				p->width  = 1;
1380bbfda8aSnia			}
1390bbfda8aSnia			if(p->height < 1) {
1400bbfda8aSnia				p->height = 1;
1410bbfda8aSnia			}
1420bbfda8aSnia			p->w = XCreateSimpleWindow(dpy, Scr->Root,
1430bbfda8aSnia			                           gx, gy, p->width, p->height, 1,
1440bbfda8aSnia			                           Scr->Black, background);
1450bbfda8aSnia
1460bbfda8aSnia
1470bbfda8aSnia			/* Scr->workSpaceMgr.activeWSPC = ws; */
1480bbfda8aSnia
1490bbfda8aSnia			/* Setup various WM properties on the iconmgr's window */
1500bbfda8aSnia			{
1510bbfda8aSnia				char *icon_name;
1520bbfda8aSnia				XWMHints wmhints;
1530bbfda8aSnia				XClassHint clhints;
1540bbfda8aSnia
1550bbfda8aSnia				if(p->icon_name) {
1560bbfda8aSnia					icon_name = strdup(p->icon_name);
1570bbfda8aSnia				}
1580bbfda8aSnia				else {
1590bbfda8aSnia					asprintf(&icon_name, "%s Icons", p->name);
1600bbfda8aSnia				}
1610bbfda8aSnia
1620bbfda8aSnia				wmhints.initial_state = NormalState;
1630bbfda8aSnia				wmhints.input         = True;
1640bbfda8aSnia				wmhints.flags         = InputHint | StateHint;
1650bbfda8aSnia
1660bbfda8aSnia				clhints.res_name  = icon_name;
1670bbfda8aSnia				clhints.res_class = "TwmIconManager";
1680bbfda8aSnia
1690bbfda8aSnia				XmbSetWMProperties(dpy, p->w, imname, icon_name, NULL, 0, NULL,
1700bbfda8aSnia				                   &wmhints, &clhints);
1710bbfda8aSnia				free(icon_name);
1720bbfda8aSnia			}
1730bbfda8aSnia
1740bbfda8aSnia
1750bbfda8aSnia			p->twm_win = AddWindow(p->w, AWT_ICON_MANAGER, p, Scr->currentvs);
176df1c27a6Snia
177df1c27a6Snia			// SetupOccupation() called from AddWindow() doesn't setup
178df1c27a6Snia			// occupation for icon managers, nor clear vs if occupation
179df1c27a6Snia			// lacks.  So make it occupy the one we're setting up, or the
180df1c27a6Snia			// 1st if we ran out somehow...
1810bbfda8aSnia			if(ws) {
1820bbfda8aSnia				p->twm_win->occupation = 1 << ws->number;
183df1c27a6Snia
184df1c27a6Snia				// ConfigureWorkSpaceManager() ran before us, so we can
185df1c27a6Snia				// tell whether we're in the ws to reveal this IM.
186df1c27a6Snia				if(ws->number != Scr->currentvs->wsw->currentwspc->number) {
1870bbfda8aSnia					p->twm_win->vs = NULL;
1880bbfda8aSnia				}
1890bbfda8aSnia			}
1900bbfda8aSnia			else {
1910bbfda8aSnia				p->twm_win->occupation = 1;
1920bbfda8aSnia			}
193df1c27a6Snia
1940bbfda8aSnia#ifdef DEBUG_ICONMGR
1950bbfda8aSnia			fprintf(stderr,
196df1c27a6Snia			        "CreateIconManagers: IconMgr %p: twm_win=%p win=0x%lx "
197df1c27a6Snia			        "name='%s' x=%d y=%d w=%d h=%d occupation=%x\n",
198df1c27a6Snia			        p, p->twm_win, p->twm_win->w, p->name,
199df1c27a6Snia			        gx, gy,  p->width, p->height, p->twm_win->occupation);
2000bbfda8aSnia#endif
2010bbfda8aSnia
2020bbfda8aSnia			{
2030bbfda8aSnia				XSizeHints sizehints;
2040bbfda8aSnia
2050bbfda8aSnia				sizehints.flags       = PWinGravity;
2060bbfda8aSnia				sizehints.win_gravity = gravity;
2070bbfda8aSnia				XSetWMSizeHints(dpy, p->w, &sizehints, XA_WM_NORMAL_HINTS);
2080bbfda8aSnia			}
2090bbfda8aSnia
2100bbfda8aSnia			p->twm_win->mapped = false;
2110bbfda8aSnia			SetMapStateProp(p->twm_win, WithdrawnState);
2120bbfda8aSnia			if(p->twm_win && (p->twm_win->wmhints->initial_state == IconicState)) {
2130bbfda8aSnia				p->twm_win->isicon = true;
2140bbfda8aSnia			}
2150bbfda8aSnia			else if(!Scr->NoIconManagers && Scr->ShowIconManager) {
2160bbfda8aSnia				p->twm_win->isicon = false;
2170bbfda8aSnia			}
2180bbfda8aSnia			else {
2190bbfda8aSnia				p->twm_win->isicon = true;
2200bbfda8aSnia			}
2210bbfda8aSnia		}
2220bbfda8aSnia		if(ws != NULL) {
2230bbfda8aSnia			ws = ws->next;
2240bbfda8aSnia		}
2250bbfda8aSnia	}
2260bbfda8aSnia
2270bbfda8aSnia	if(Scr->workSpaceManagerActive) {
2280bbfda8aSnia		Scr->workSpaceMgr.workSpaceList->iconmgr = Scr->iconmgr;
2290bbfda8aSnia	}
2300bbfda8aSnia
2310bbfda8aSnia
2320bbfda8aSnia	/*
2330bbfda8aSnia	 * Grab buttons/keystrokes for icon managers appropriately.
2340bbfda8aSnia	 * Normally, this is done in AddWindow(), but it explicitly skips it
2350bbfda8aSnia	 * for icon managers.  It's not at all clear why GrabButtons() would
2360bbfda8aSnia	 * do so; I don't think it needs to.  GrabKeys() does do some looping
2370bbfda8aSnia	 * over the Scr->iconmgr list at the end though, so it's possible we
2380bbfda8aSnia	 * need to delay calling it until now when the list is all filled up.
2390bbfda8aSnia	 * This needs further investigation; it may be that the special case
2400bbfda8aSnia	 * and this code can be removed.  X-ref comments in add_window.c
2410bbfda8aSnia	 * about it.
2420bbfda8aSnia	 */
2430bbfda8aSnia	for(IconMgr *q = Scr->iconmgr; q != NULL; q = q->nextv) {
2440bbfda8aSnia		for(IconMgr *p = q; p != NULL; p = p->next) {
2450bbfda8aSnia			GrabButtons(p->twm_win);
2460bbfda8aSnia			GrabKeys(p->twm_win);
2470bbfda8aSnia		}
248645f5050Syouri	}
249645f5050Syouri
250645f5050Syouri}
251645f5050Syouri
252645f5050Syouri/***********************************************************************
253645f5050Syouri *
254645f5050Syouri *  Procedure:
2550bbfda8aSnia *      AllocateIconManager - allocate a new icon manager
256645f5050Syouri *
257645f5050Syouri *  Inputs:
2580bbfda8aSnia *      name    - the name of this icon manager
2590bbfda8aSnia *      icon_name - the name of the associated icon
2600bbfda8aSnia *      geom    - a geometry string to eventually parse
2610bbfda8aSnia *      columns - the number of columns this icon manager has
262645f5050Syouri *
263645f5050Syouri ***********************************************************************
264645f5050Syouri */
265645f5050Syouri
266645f5050SyouriIconMgr *AllocateIconManager(char *name, char *icon_name, char *geom,
2670bbfda8aSnia                             int columns)
268645f5050Syouri{
2690bbfda8aSnia	IconMgr *p;
270645f5050Syouri
271645f5050Syouri#ifdef DEBUG_ICONMGR
2720bbfda8aSnia	fprintf(stderr, "AllocateIconManager\n");
2730bbfda8aSnia	fprintf(stderr, "  name=\"%s\" icon_name=\"%s\", geom=\"%s\", col=%d\n",
2740bbfda8aSnia	        name, icon_name, geom, columns);
275645f5050Syouri#endif
276645f5050Syouri
2770bbfda8aSnia	if(Scr->NoIconManagers) {
2780bbfda8aSnia		return NULL;
2790bbfda8aSnia	}
2800bbfda8aSnia
2810bbfda8aSnia	if(columns < 1) {
2820bbfda8aSnia		columns = 1;
2830bbfda8aSnia	}
2840bbfda8aSnia	p = calloc(1, sizeof(IconMgr));
2850bbfda8aSnia	p->name      = name;
2860bbfda8aSnia	p->icon_name = icon_name;
2870bbfda8aSnia	p->geometry  = geom;
2880bbfda8aSnia	p->columns   = columns;
2890bbfda8aSnia	p->scr       = Scr;
2900bbfda8aSnia	p->width     = 150;
2910bbfda8aSnia	p->height    = 10;
2920bbfda8aSnia
2930bbfda8aSnia	if(Scr->iconmgr == NULL) {
2940bbfda8aSnia		Scr->iconmgr = p;
2950bbfda8aSnia		Scr->iconmgr->lasti = p;
2960bbfda8aSnia	}
2970bbfda8aSnia	else {
2980bbfda8aSnia		Scr->iconmgr->lasti->next = p;
2990bbfda8aSnia		p->prev = Scr->iconmgr->lasti;
3000bbfda8aSnia		Scr->iconmgr->lasti = p;
3010bbfda8aSnia	}
3020bbfda8aSnia	return(p);
3030bbfda8aSnia}
3040bbfda8aSnia
3050bbfda8aSnia
3060bbfda8aSnia/*
3070bbfda8aSnia * Each workspace has its own [set of] icon manager[s].  The initial main
3080bbfda8aSnia * one was setup via AllocateIconManager() early in startup.  The others
3090bbfda8aSnia * were setup during parsing the config file.  Then this gets called late
3100bbfda8aSnia * in startup, after all the workspaces are setup, to copy them all into
3110bbfda8aSnia * each one.
3120bbfda8aSnia *
3130bbfda8aSnia * Note this is distinct from CreateIconManagers(); that creates and
3140bbfda8aSnia * draws the windows, this creates and connects up the data structures.
3150bbfda8aSnia */
3160bbfda8aSniavoid AllocateOtherIconManagers(void)
3170bbfda8aSnia{
3180bbfda8aSnia	IconMgr   *imfirst; // First IM on each workspace
3190bbfda8aSnia	WorkSpace *ws;
3200bbfda8aSnia
3210bbfda8aSnia	/* No defined workspaces?  Nothing to do. */
3220bbfda8aSnia	if(! Scr->workSpaceManagerActive) {
3230bbfda8aSnia		return;
3240bbfda8aSnia	}
3250bbfda8aSnia
3260bbfda8aSnia	/* The first workspace just gets the ones we already have */
3270bbfda8aSnia	ws = Scr->workSpaceMgr.workSpaceList;
3280bbfda8aSnia	ws->iconmgr = Scr->iconmgr;
3290bbfda8aSnia
3300bbfda8aSnia	/* From the second on, we start copying */
3310bbfda8aSnia	imfirst = ws->iconmgr;
3320bbfda8aSnia	for(ws = ws->next; ws != NULL; ws = ws->next) {
3330bbfda8aSnia		IconMgr *ip, *previ, *p = NULL;
3340bbfda8aSnia
3350bbfda8aSnia		/* Copy in the first iconmgr */
3360bbfda8aSnia		ws->iconmgr  = malloc(sizeof(IconMgr));
3370bbfda8aSnia		*ws->iconmgr = *imfirst;
3380bbfda8aSnia
3390bbfda8aSnia		/*
3400bbfda8aSnia		 * This first is now the nextv to the first in the previous WS,
3410bbfda8aSnia		 * and we don't [yet] have a nextv of our own.
3420bbfda8aSnia		 * */
3430bbfda8aSnia		imfirst->nextv = ws->iconmgr;
3440bbfda8aSnia		ws->iconmgr->nextv = NULL;
3450bbfda8aSnia
3460bbfda8aSnia		/*
3470bbfda8aSnia		 * Start from the second, and copy them each from the prior
3480bbfda8aSnia		 * workspace we just went through.
3490bbfda8aSnia		 * */
3500bbfda8aSnia		previ = ws->iconmgr;
3510bbfda8aSnia		for(ip = imfirst->next; ip != NULL; ip = ip->next) {
3520bbfda8aSnia			/* Copy the base bits */
3530bbfda8aSnia			p  = malloc(sizeof(IconMgr));
3540bbfda8aSnia			*p = *ip;
3550bbfda8aSnia
3560bbfda8aSnia			/* Link up the double-links, and there's no nextv [yet] */
3570bbfda8aSnia			previ->next = p;
3580bbfda8aSnia			p->prev     = previ;
3590bbfda8aSnia			p->next     = NULL;
3600bbfda8aSnia			p->nextv    = NULL;
3610bbfda8aSnia
3620bbfda8aSnia			/* We're now the nextv to that one in the old workspace */
3630bbfda8aSnia			ip->nextv  = p;
3640bbfda8aSnia
3650bbfda8aSnia			/* And back around to the next one to copy into this WS */
3660bbfda8aSnia			previ = p;
3670bbfda8aSnia		}
3680bbfda8aSnia
3690bbfda8aSnia		/* Each one has a pointer to the last IM in this WS, so save those */
3700bbfda8aSnia		for(ip = ws->iconmgr; ip != NULL; ip = ip->next) {
3710bbfda8aSnia			ip->lasti = p;
3720bbfda8aSnia		}
3730bbfda8aSnia
3740bbfda8aSnia		/*
3750bbfda8aSnia		 * And back around to the next workspace, which works from those
3760bbfda8aSnia		 * we made for this WS.  We go from imfirst rather than
3770bbfda8aSnia		 * Scr->iconmgr so the ip->nextv rewrites are correct above; we
3780bbfda8aSnia		 * have to fill them in on the next loop.
3790bbfda8aSnia		 */
3800bbfda8aSnia		imfirst = ws->iconmgr;
3810bbfda8aSnia	}
382645f5050Syouri}
383645f5050Syouri
3840bbfda8aSnia
385645f5050Syouri/***********************************************************************
386645f5050Syouri *
387645f5050Syouri *  Procedure:
3880bbfda8aSnia *      MoveIconManager - move the pointer around in an icon manager
389645f5050Syouri *
390645f5050Syouri *  Inputs:
3910bbfda8aSnia *      dir     - one of the following:
3920bbfda8aSnia *                      F_FORWICONMGR   - forward in the window list
3930bbfda8aSnia *                      F_BACKICONMGR   - backward in the window list
3940bbfda8aSnia *                      F_UPICONMGR     - up one row
3950bbfda8aSnia *                      F_DOWNICONMGR   - down one row
3960bbfda8aSnia *                      F_LEFTICONMGR   - left one column
3970bbfda8aSnia *                      F_RIGHTICONMGR  - right one column
398645f5050Syouri *
399645f5050Syouri *  Special Considerations:
4000bbfda8aSnia *      none
401645f5050Syouri *
402645f5050Syouri ***********************************************************************
403645f5050Syouri */
404645f5050Syouri
405645f5050Syourivoid MoveIconManager(int dir)
406645f5050Syouri{
4070bbfda8aSnia	IconMgr *ip;
4080bbfda8aSnia	WList *tmp = NULL;
4090bbfda8aSnia	int cur_row, cur_col, new_row, new_col;
4100bbfda8aSnia	int row_inc, col_inc;
4110bbfda8aSnia	bool got_it;
4120bbfda8aSnia
4130bbfda8aSnia	if(!Current) {
4140bbfda8aSnia		return;
4150bbfda8aSnia	}
4160bbfda8aSnia
4170bbfda8aSnia	cur_row = Current->row;
4180bbfda8aSnia	cur_col = Current->col;
4190bbfda8aSnia	ip = Current->iconmgr;
4200bbfda8aSnia
4210bbfda8aSnia	row_inc = 0;
4220bbfda8aSnia	col_inc = 0;
4230bbfda8aSnia	got_it = false;
4240bbfda8aSnia
4250bbfda8aSnia	switch(dir) {
4260bbfda8aSnia		case F_FORWICONMGR:
4270bbfda8aSnia			if((tmp = Current->next) == NULL) {
4280bbfda8aSnia				tmp = ip->first;
4290bbfda8aSnia			}
4300bbfda8aSnia			got_it = true;
4310bbfda8aSnia			break;
4320bbfda8aSnia
4330bbfda8aSnia		case F_BACKICONMGR:
4340bbfda8aSnia			if((tmp = Current->prev) == NULL) {
4350bbfda8aSnia				tmp = ip->last;
4360bbfda8aSnia			}
4370bbfda8aSnia			got_it = true;
4380bbfda8aSnia			break;
4390bbfda8aSnia
4400bbfda8aSnia		case F_UPICONMGR:
4410bbfda8aSnia			row_inc = -1;
4420bbfda8aSnia			break;
4430bbfda8aSnia
4440bbfda8aSnia		case F_DOWNICONMGR:
4450bbfda8aSnia			row_inc = 1;
4460bbfda8aSnia			break;
4470bbfda8aSnia
4480bbfda8aSnia		case F_LEFTICONMGR:
4490bbfda8aSnia			col_inc = -1;
4500bbfda8aSnia			break;
4510bbfda8aSnia
4520bbfda8aSnia		case F_RIGHTICONMGR:
4530bbfda8aSnia			col_inc = 1;
4540bbfda8aSnia			break;
4550bbfda8aSnia	}
4560bbfda8aSnia
4570bbfda8aSnia	/* If got_it is false ast this point then we got a left, right,
4580bbfda8aSnia	 * up, or down, command.  We will enter this loop until we find
4590bbfda8aSnia	 * a window to warp to.
460645f5050Syouri	 */
4610bbfda8aSnia	new_row = cur_row;
4620bbfda8aSnia	new_col = cur_col;
4630bbfda8aSnia
4640bbfda8aSnia	while(!got_it) {
4650bbfda8aSnia		new_row += row_inc;
4660bbfda8aSnia		new_col += col_inc;
4670bbfda8aSnia		if(new_row < 0) {
4680bbfda8aSnia			new_row = ip->cur_rows - 1;
4690bbfda8aSnia		}
4700bbfda8aSnia		if(new_col < 0) {
4710bbfda8aSnia			new_col = ip->cur_columns - 1;
4720bbfda8aSnia		}
4730bbfda8aSnia		if(new_row >= ip->cur_rows) {
4740bbfda8aSnia			new_row = 0;
4750bbfda8aSnia		}
4760bbfda8aSnia		if(new_col >= ip->cur_columns) {
4770bbfda8aSnia			new_col = 0;
4780bbfda8aSnia		}
4790bbfda8aSnia
4800bbfda8aSnia		/* Now let's go through the list to see if there is an entry with this
4810bbfda8aSnia		 * new position
4820bbfda8aSnia		 */
4830bbfda8aSnia		for(tmp = ip->first; tmp != NULL; tmp = tmp->next) {
4840bbfda8aSnia			if(tmp->row == new_row && tmp->col == new_col) {
4850bbfda8aSnia				got_it = true;
4860bbfda8aSnia				break;
4870bbfda8aSnia			}
4880bbfda8aSnia		}
4890bbfda8aSnia	}
4900bbfda8aSnia
4910bbfda8aSnia	if(!got_it) {
4920bbfda8aSnia		fprintf(stderr,
4930bbfda8aSnia		        "%s:  unable to find window (%d, %d) in icon manager\n",
4940bbfda8aSnia		        ProgramName, new_row, new_col);
4950bbfda8aSnia		return;
4960bbfda8aSnia	}
4970bbfda8aSnia
4980bbfda8aSnia	if(tmp == NULL) {
4990bbfda8aSnia		return;
5000bbfda8aSnia	}
5010bbfda8aSnia
5020bbfda8aSnia	/* raise the frame so the icon manager is visible */
5030bbfda8aSnia	if(ip->twm_win->mapped) {
5040bbfda8aSnia		OtpRaise(ip->twm_win, WinWin);
5050bbfda8aSnia		XWarpPointer(dpy, None, tmp->icon, 0, 0, 0, 0, 5, 5);
5060bbfda8aSnia	}
5070bbfda8aSnia	else {
5080bbfda8aSnia		if(tmp->twm->title_height) {
5090bbfda8aSnia			int tbx = Scr->TBInfo.titlex;
5100bbfda8aSnia			int x = tmp->twm->highlightxr;
5110bbfda8aSnia			XWarpPointer(dpy, None, tmp->twm->title_w, 0, 0, 0, 0,
5120bbfda8aSnia			             tbx + (x - tbx) / 2,
5130bbfda8aSnia			             Scr->TitleHeight / 4);
5140bbfda8aSnia		}
5150bbfda8aSnia		else {
5160bbfda8aSnia			XWarpPointer(dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5);
5170bbfda8aSnia		}
5180bbfda8aSnia	}
519645f5050Syouri}
520645f5050Syouri
521645f5050Syouri/***********************************************************************
522645f5050Syouri *
523645f5050Syouri *  Procedure:
5240bbfda8aSnia *      MoveMappedIconManager - move the pointer around in an icon manager
525645f5050Syouri *
526645f5050Syouri *  Inputs:
5270bbfda8aSnia *      dir     - one of the following:
5280bbfda8aSnia *                      F_FORWMAPICONMGR        - forward in the window list
5290bbfda8aSnia *                      F_BACKMAPICONMGR        - backward in the window list
530645f5050Syouri *
531645f5050Syouri *  Special Considerations:
5320bbfda8aSnia *      none
533645f5050Syouri *
534645f5050Syouri ***********************************************************************
535645f5050Syouri */
536645f5050Syouri
537645f5050Syourivoid MoveMappedIconManager(int dir)
538645f5050Syouri{
5390bbfda8aSnia	IconMgr *ip;
5400bbfda8aSnia	WList *tmp = NULL;
5410bbfda8aSnia	WList *orig = NULL;
5420bbfda8aSnia	bool got_it;
5430bbfda8aSnia
5440bbfda8aSnia	if(!Current) {
5450bbfda8aSnia		Current = Active;
5460bbfda8aSnia	}
5470bbfda8aSnia	if(!Current) {
5480bbfda8aSnia		return;
5490bbfda8aSnia	}
5500bbfda8aSnia
5510bbfda8aSnia	ip = Current->iconmgr;
5520bbfda8aSnia
5530bbfda8aSnia	got_it = false;
5540bbfda8aSnia	tmp = Current;
5550bbfda8aSnia	orig = Current;
5560bbfda8aSnia
5570bbfda8aSnia	while(!got_it) {
5580bbfda8aSnia		switch(dir) {
5590bbfda8aSnia			case F_FORWMAPICONMGR:
5600bbfda8aSnia				if((tmp = tmp->next) == NULL) {
5610bbfda8aSnia					tmp = ip->first;
5620bbfda8aSnia				}
5630bbfda8aSnia				break;
5640bbfda8aSnia
5650bbfda8aSnia			case F_BACKMAPICONMGR:
5660bbfda8aSnia				if((tmp = tmp->prev) == NULL) {
5670bbfda8aSnia					tmp = ip->last;
5680bbfda8aSnia				}
5690bbfda8aSnia				break;
5700bbfda8aSnia		}
5710bbfda8aSnia		if(tmp->twm->mapped) {
5720bbfda8aSnia			got_it = true;
5730bbfda8aSnia			break;
5740bbfda8aSnia		}
5750bbfda8aSnia		if(tmp == orig) {
5760bbfda8aSnia			break;
5770bbfda8aSnia		}
5780bbfda8aSnia	}
5790bbfda8aSnia
5800bbfda8aSnia	if(!got_it) {
5810bbfda8aSnia		fprintf(stderr, "%s:  unable to find open window in icon manager\n",
5820bbfda8aSnia		        ProgramName);
5830bbfda8aSnia		return;
5840bbfda8aSnia	}
5850bbfda8aSnia
5860bbfda8aSnia	if(tmp == NULL) {
5870bbfda8aSnia		return;
5880bbfda8aSnia	}
5890bbfda8aSnia
5900bbfda8aSnia	/* raise the frame so the icon manager is visible */
5910bbfda8aSnia	if(ip->twm_win->mapped) {
5920bbfda8aSnia		OtpRaise(ip->twm_win, WinWin);
5930bbfda8aSnia		XWarpPointer(dpy, None, tmp->icon, 0, 0, 0, 0, 5, 5);
5940bbfda8aSnia	}
5950bbfda8aSnia	else {
5960bbfda8aSnia		if(tmp->twm->title_height) {
5970bbfda8aSnia			XWarpPointer(dpy, None, tmp->twm->title_w, 0, 0, 0, 0,
5980bbfda8aSnia			             tmp->twm->title_width / 2,
5990bbfda8aSnia			             Scr->TitleHeight / 4);
6000bbfda8aSnia		}
6010bbfda8aSnia		else {
6020bbfda8aSnia			XWarpPointer(dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5);
6030bbfda8aSnia		}
6040bbfda8aSnia	}
605645f5050Syouri}
606645f5050Syouri
607645f5050Syouri/***********************************************************************
608645f5050Syouri *
609645f5050Syouri *  Procedure:
6100bbfda8aSnia *      JumpIconManager - jump from one icon manager to another,
6110bbfda8aSnia *              possibly even on another screen
612645f5050Syouri *
613645f5050Syouri *  Inputs:
6140bbfda8aSnia *      dir     - one of the following:
6150bbfda8aSnia *                      F_NEXTICONMGR   - go to the next icon manager
6160bbfda8aSnia *                      F_PREVICONMGR   - go to the previous one
617645f5050Syouri *
618645f5050Syouri ***********************************************************************
619645f5050Syouri */
620645f5050Syouri
6210bbfda8aSniavoid JumpIconManager(int dir)
622645f5050Syouri{
6230bbfda8aSnia	IconMgr *ip, *tmp_ip = NULL;
6240bbfda8aSnia	bool got_it = false;
6250bbfda8aSnia	ScreenInfo *sp;
6260bbfda8aSnia	int screen;
627645f5050Syouri
6280bbfda8aSnia	if(!Current) {
6290bbfda8aSnia		return;
6300bbfda8aSnia	}
631645f5050Syouri
632645f5050Syouri
633645f5050Syouri#define ITER(i) (dir == F_NEXTICONMGR ? (i)->next : (i)->prev)
634645f5050Syouri#define IPOFSP(sp) (dir == F_NEXTICONMGR ? sp->iconmgr : sp->iconmgr->lasti)
635645f5050Syouri#define TEST(ip) if ((ip)->count != 0 && (ip)->twm_win->mapped) \
6360bbfda8aSnia                 { got_it = true; break; }
6370bbfda8aSnia
6380bbfda8aSnia	ip = Current->iconmgr;
6390bbfda8aSnia	for(tmp_ip = ITER(ip); tmp_ip; tmp_ip = ITER(tmp_ip)) {
6400bbfda8aSnia		TEST(tmp_ip);
6410bbfda8aSnia	}
6420bbfda8aSnia
6430bbfda8aSnia	if(!got_it) {
6440bbfda8aSnia		int origscreen = ip->scr->screen;
6450bbfda8aSnia		int inc = (dir == F_NEXTICONMGR ? 1 : -1);
6460bbfda8aSnia
6470bbfda8aSnia		for(screen = origscreen + inc; ; screen += inc) {
6480bbfda8aSnia			if(screen >= NumScreens) {
6490bbfda8aSnia				screen = 0;
6500bbfda8aSnia			}
6510bbfda8aSnia			else if(screen < 0) {
6520bbfda8aSnia				screen = NumScreens - 1;
6530bbfda8aSnia			}
6540bbfda8aSnia
6550bbfda8aSnia			sp = ScreenList[screen];
6560bbfda8aSnia			if(sp) {
6570bbfda8aSnia				for(tmp_ip = IPOFSP(sp); tmp_ip; tmp_ip = ITER(tmp_ip)) {
6580bbfda8aSnia					TEST(tmp_ip);
6590bbfda8aSnia				}
6600bbfda8aSnia			}
6610bbfda8aSnia			if(got_it || screen == origscreen) {
6620bbfda8aSnia				break;
6630bbfda8aSnia			}
664645f5050Syouri		}
665645f5050Syouri	}
666645f5050Syouri
667645f5050Syouri#undef ITER
668645f5050Syouri#undef IPOFSP
669645f5050Syouri#undef TEST
670645f5050Syouri
6710bbfda8aSnia	if(!got_it) {
6720bbfda8aSnia		XBell(dpy, 0);
6730bbfda8aSnia		return;
6740bbfda8aSnia	}
6750bbfda8aSnia
6760bbfda8aSnia	/* raise the frame so it is visible */
6770bbfda8aSnia	OtpRaise(tmp_ip->twm_win, WinWin);
6780bbfda8aSnia	if(tmp_ip->active) {
6790bbfda8aSnia		XWarpPointer(dpy, None, tmp_ip->active->icon, 0, 0, 0, 0, 5, 5);
6800bbfda8aSnia	}
6810bbfda8aSnia	else {
6820bbfda8aSnia		XWarpPointer(dpy, None, tmp_ip->w, 0, 0, 0, 0, 5, 5);
6830bbfda8aSnia	}
684645f5050Syouri}
685645f5050Syouri
686645f5050Syouri/***********************************************************************
687645f5050Syouri *
688645f5050Syouri *  Procedure:
6890bbfda8aSnia *      AddIconManager - add a window to an icon manager
690645f5050Syouri *
691645f5050Syouri *  Inputs:
6920bbfda8aSnia *      tmp_win - the TwmWindow structure
693645f5050Syouri *
694645f5050Syouri ***********************************************************************
695645f5050Syouri */
696645f5050Syouri
697645f5050SyouriWList *AddIconManager(TwmWindow *tmp_win)
698645f5050Syouri{
6990bbfda8aSnia	WList *tmp, *old;
7000bbfda8aSnia	IconMgr *ip;
7010bbfda8aSnia
7020bbfda8aSnia	/* Some window types don't wind up in icon managers ever */
7030bbfda8aSnia	if(tmp_win->isiconmgr || tmp_win->istransient || tmp_win->iswspmgr
7040bbfda8aSnia	                || tmp_win->w == Scr->workSpaceMgr.occupyWindow->w) {
7050bbfda8aSnia		return NULL;
7060bbfda8aSnia	}
7070bbfda8aSnia
7080bbfda8aSnia	/* Icon managers can be shut off wholesale in the config */
7090bbfda8aSnia	if(Scr->NoIconManagers) {
7100bbfda8aSnia		return NULL;
7110bbfda8aSnia	}
7120bbfda8aSnia
7130bbfda8aSnia	/* Config could declare not to IMify this type of window in two ways */
7140bbfda8aSnia	if(LookInList(Scr->IconMgrNoShow, tmp_win->name, &tmp_win->class)) {
7150bbfda8aSnia		return NULL;
7160bbfda8aSnia	}
7170bbfda8aSnia	if(Scr->IconManagerDontShow
7180bbfda8aSnia	                && !LookInList(Scr->IconMgrShow, tmp_win->name, &tmp_win->class)) {
7190bbfda8aSnia		return NULL;
7200bbfda8aSnia	}
7210bbfda8aSnia
7220bbfda8aSnia	/* Dredge up the appropriate IM */
7230bbfda8aSnia	if((ip = (IconMgr *)LookInList(Scr->IconMgrs, tmp_win->name,
7240bbfda8aSnia	                               &tmp_win->class)) == NULL) {
7250bbfda8aSnia		if(Scr->workSpaceManagerActive) {
7260bbfda8aSnia			ip = Scr->workSpaceMgr.workSpaceList->iconmgr;
7270bbfda8aSnia		}
7280bbfda8aSnia		else {
7290bbfda8aSnia			ip = Scr->iconmgr;
7300bbfda8aSnia		}
7310bbfda8aSnia	}
7320bbfda8aSnia
7330bbfda8aSnia	/* IM's exist in all workspaces, so loop through WSen */
7340bbfda8aSnia	tmp = NULL;
7350bbfda8aSnia	old = tmp_win->iconmanagerlist;
7360bbfda8aSnia	while(ip != NULL) {
7370bbfda8aSnia		int h;
7380bbfda8aSnia		unsigned long valuemask;         /* mask for create windows */
7390bbfda8aSnia		XSetWindowAttributes attributes; /* attributes for create windows */
7400bbfda8aSnia
7410bbfda8aSnia		/* Is the window in this workspace? */
7420bbfda8aSnia		if((tmp_win->occupation & ip->twm_win->occupation) == 0) {
7430bbfda8aSnia			/* Nope, skip onward */
7440bbfda8aSnia			ip = ip->nextv;
7450bbfda8aSnia			continue;
7460bbfda8aSnia		}
7470bbfda8aSnia
7480bbfda8aSnia		/* Yep, create entry and stick it in */
7490bbfda8aSnia		tmp = calloc(1, sizeof(WList));
7500bbfda8aSnia		tmp->iconmgr = ip;
7510bbfda8aSnia		tmp->twm = tmp_win;
7520bbfda8aSnia
7530bbfda8aSnia		InsertInIconManager(ip, tmp, tmp_win);
7540bbfda8aSnia
7550bbfda8aSnia		/* IM color settings, shared worldwide */
7560bbfda8aSnia		tmp->cp.fore   = Scr->IconManagerC.fore;
7570bbfda8aSnia		tmp->cp.back   = Scr->IconManagerC.back;
7580bbfda8aSnia		tmp->highlight = Scr->IconManagerHighlight;
7590bbfda8aSnia
7600bbfda8aSnia		GetColorFromList(Scr->IconManagerFL, tmp_win->name,
7610bbfda8aSnia		                 &tmp_win->class, &tmp->cp.fore);
7620bbfda8aSnia		GetColorFromList(Scr->IconManagerBL, tmp_win->name,
7630bbfda8aSnia		                 &tmp_win->class, &tmp->cp.back);
7640bbfda8aSnia		GetColorFromList(Scr->IconManagerHighlightL, tmp_win->name,
7650bbfda8aSnia		                 &tmp_win->class, &tmp->highlight);
7660bbfda8aSnia
7670bbfda8aSnia		/*
7680bbfda8aSnia		 * If we're using 3d icon managers, each line item has its own
7690bbfda8aSnia		 * icon; see comment on creation function for details.  With 2d
7700bbfda8aSnia		 * icon managers, it's the same for all of them, so it's stored
7710bbfda8aSnia		 * screen-wide.
7720bbfda8aSnia		 */
7730bbfda8aSnia		if(Scr->use3Diconmanagers) {
7740bbfda8aSnia			if(!Scr->BeNiceToColormap) {
7750bbfda8aSnia				GetShadeColors(&tmp->cp);
7760bbfda8aSnia			}
7770bbfda8aSnia			tmp->iconifypm = Create3DIconManagerIcon(tmp->cp);
7780bbfda8aSnia		}
7790bbfda8aSnia
7800bbfda8aSnia		/* Refigure the height of the whole IM */
7810bbfda8aSnia		h = Scr->IconManagerFont.avg_height
7820bbfda8aSnia		    + 2 * (ICON_MGR_OBORDER + ICON_MGR_OBORDER);
7830bbfda8aSnia		if(h < (im_iconified_icon_height + 4)) {
7840bbfda8aSnia			h = im_iconified_icon_height + 4;
7850bbfda8aSnia		}
7860bbfda8aSnia
7870bbfda8aSnia		ip->height = h * ip->count;
7880bbfda8aSnia		tmp->me = ip->count;
7890bbfda8aSnia		tmp->x = -1;
7900bbfda8aSnia		tmp->y = -1;
7910bbfda8aSnia		tmp->height = -1;
7920bbfda8aSnia		tmp->width = -1;
7930bbfda8aSnia
7940bbfda8aSnia
7950bbfda8aSnia		/* Make a window for this row in the IM */
7960bbfda8aSnia		valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
7970bbfda8aSnia		attributes.background_pixel = tmp->cp.back;
7980bbfda8aSnia		attributes.border_pixel = tmp->cp.back;
7990bbfda8aSnia		attributes.event_mask = (KeyPressMask | ButtonPressMask |
8000bbfda8aSnia		                         ButtonReleaseMask | ExposureMask);
8010bbfda8aSnia		if(Scr->IconManagerFocus) {
8020bbfda8aSnia			attributes.event_mask |= (EnterWindowMask | LeaveWindowMask);
8030bbfda8aSnia		}
8040bbfda8aSnia		attributes.cursor = Scr->IconMgrCursor;
8050bbfda8aSnia		tmp->w = XCreateWindow(dpy, ip->w, 0, 0, 1,
8060bbfda8aSnia		                       h, 0,
8070bbfda8aSnia		                       CopyFromParent, CopyFromParent,
8080bbfda8aSnia		                       CopyFromParent,
8090bbfda8aSnia		                       valuemask, &attributes);
8100bbfda8aSnia
8110bbfda8aSnia
8120bbfda8aSnia		/* Setup the icon for it too */
8130bbfda8aSnia		valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor);
8140bbfda8aSnia		attributes.background_pixel = tmp->cp.back;
8150bbfda8aSnia		attributes.border_pixel = Scr->Black;
8160bbfda8aSnia		attributes.event_mask = (ButtonReleaseMask | ButtonPressMask
8170bbfda8aSnia		                         | ExposureMask);
8180bbfda8aSnia		attributes.cursor = Scr->ButtonCursor;
8190bbfda8aSnia		/* The precise location will be set it in PackIconManager.  */
8200bbfda8aSnia		tmp->icon = XCreateWindow(dpy, tmp->w, 0, 0,
8210bbfda8aSnia		                          im_iconified_icon_width,
8220bbfda8aSnia		                          im_iconified_icon_height,
8230bbfda8aSnia		                          0, CopyFromParent,
8240bbfda8aSnia		                          CopyFromParent,
8250bbfda8aSnia		                          CopyFromParent,
8260bbfda8aSnia		                          valuemask, &attributes);
8270bbfda8aSnia
8280bbfda8aSnia
8290bbfda8aSnia		/* Bump housekeeping for the IM */
8300bbfda8aSnia		ip->count += 1;
8310bbfda8aSnia		PackIconManager(ip);
8320bbfda8aSnia		if(Scr->WindowMask) {
8330bbfda8aSnia			XRaiseWindow(dpy, Scr->WindowMask);
8340bbfda8aSnia		}
8350bbfda8aSnia		XMapWindow(dpy, tmp->w);
8360bbfda8aSnia
8370bbfda8aSnia		XSaveContext(dpy, tmp->w, TwmContext, (XPointer) tmp_win);
8380bbfda8aSnia		XSaveContext(dpy, tmp->w, ScreenContext, (XPointer) Scr);
8390bbfda8aSnia		XSaveContext(dpy, tmp->icon, TwmContext, (XPointer) tmp_win);
8400bbfda8aSnia		XSaveContext(dpy, tmp->icon, ScreenContext, (XPointer) Scr);
8410bbfda8aSnia
8420bbfda8aSnia		if(!ip->twm_win->isicon) {
8430bbfda8aSnia			if(visible(ip->twm_win)) {
8440bbfda8aSnia				SetMapStateProp(ip->twm_win, NormalState);
8450bbfda8aSnia				XMapWindow(dpy, ip->w);
8460bbfda8aSnia				XMapWindow(dpy, ip->twm_win->frame);
8470bbfda8aSnia			}
8480bbfda8aSnia			ip->twm_win->mapped = true;
8490bbfda8aSnia		}
8500bbfda8aSnia
8510bbfda8aSnia
8520bbfda8aSnia		/*
8530bbfda8aSnia		 * Stick this entry on the head of our list of "IM entries we
8540bbfda8aSnia		 * created", and loop around to the next WS for this IM.
8550bbfda8aSnia		 */
8560bbfda8aSnia		tmp->nextv = old;
8570bbfda8aSnia		old = tmp;
8580bbfda8aSnia		ip = ip->nextv;
8590bbfda8aSnia	}
8600bbfda8aSnia
8610bbfda8aSnia	/* If we didn't create at least one thing, we're done here */
8620bbfda8aSnia	if(tmp == NULL) {
8630bbfda8aSnia		return NULL;
8640bbfda8aSnia	}
8650bbfda8aSnia
8660bbfda8aSnia	/* Stash where the window is IM-listed */
8670bbfda8aSnia	tmp_win->iconmanagerlist = tmp;
8680bbfda8aSnia
8690bbfda8aSnia	/* ??? */
8700bbfda8aSnia	if(! visible(tmp->iconmgr->twm_win)) {
8710bbfda8aSnia		old = tmp;
8720bbfda8aSnia		tmp = tmp->nextv;
8730bbfda8aSnia		while(tmp != NULL) {
8740bbfda8aSnia			if(visible(tmp->iconmgr->twm_win)) {
8750bbfda8aSnia				break;
8760bbfda8aSnia			}
8770bbfda8aSnia			old = tmp;
8780bbfda8aSnia			tmp = tmp->nextv;
8790bbfda8aSnia		}
8800bbfda8aSnia		if(tmp != NULL) {
8810bbfda8aSnia			old->nextv = tmp->nextv;
8820bbfda8aSnia			tmp->nextv = tmp_win->iconmanagerlist;
8830bbfda8aSnia			tmp_win->iconmanagerlist = tmp;
8840bbfda8aSnia		}
8850bbfda8aSnia	}
8860bbfda8aSnia
8870bbfda8aSnia	/* Hand back the list places we added */
8880bbfda8aSnia	return tmp_win->iconmanagerlist;
889645f5050Syouri}
890645f5050Syouri
891645f5050Syouri/***********************************************************************
892645f5050Syouri *
893645f5050Syouri *  Procedure:
8940bbfda8aSnia *      InsertInIconManager - put an allocated entry into an icon
8950bbfda8aSnia *              manager
896645f5050Syouri *
897645f5050Syouri *  Inputs:
8980bbfda8aSnia *      ip      - the icon manager pointer
8990bbfda8aSnia *      tmp     - the entry to insert
900645f5050Syouri *
901645f5050Syouri ***********************************************************************
902645f5050Syouri */
903645f5050Syouri
904645f5050Syourivoid InsertInIconManager(IconMgr *ip, WList *tmp, TwmWindow *tmp_win)
905645f5050Syouri{
9060bbfda8aSnia	WList *tmp1;
9070bbfda8aSnia	bool added;
9080bbfda8aSnia
9090bbfda8aSnia	added = false;
9100bbfda8aSnia	if(ip->first == NULL) {
9110bbfda8aSnia		ip->first = tmp;
9120bbfda8aSnia		tmp->prev = NULL;
9130bbfda8aSnia		ip->last = tmp;
9140bbfda8aSnia		added = true;
9150bbfda8aSnia	}
9160bbfda8aSnia	else if(Scr->SortIconMgr) {
9170bbfda8aSnia		for(tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) {
9180bbfda8aSnia			int compresult;
9190bbfda8aSnia			if(Scr->CaseSensitive) {
9200bbfda8aSnia				compresult = strcmp(tmp_win->icon_name, tmp1->twm->icon_name);
9210bbfda8aSnia			}
9220bbfda8aSnia			else {
9230bbfda8aSnia				compresult = strcasecmp(tmp_win->icon_name, tmp1->twm->icon_name);
9240bbfda8aSnia			}
9250bbfda8aSnia			if(compresult < 0) {
9260bbfda8aSnia				tmp->next = tmp1;
9270bbfda8aSnia				tmp->prev = tmp1->prev;
9280bbfda8aSnia				tmp1->prev = tmp;
9290bbfda8aSnia				if(tmp->prev == NULL) {
9300bbfda8aSnia					ip->first = tmp;
9310bbfda8aSnia				}
9320bbfda8aSnia				else {
9330bbfda8aSnia					tmp->prev->next = tmp;
9340bbfda8aSnia				}
9350bbfda8aSnia				added = true;
9360bbfda8aSnia				break;
9370bbfda8aSnia			}
9380bbfda8aSnia		}
9390bbfda8aSnia	}
9400bbfda8aSnia
9410bbfda8aSnia	if(!added) {
9420bbfda8aSnia		ip->last->next = tmp;
9430bbfda8aSnia		tmp->prev = ip->last;
9440bbfda8aSnia		ip->last = tmp;
9450bbfda8aSnia	}
946645f5050Syouri}
947645f5050Syouri
948645f5050Syourivoid RemoveFromIconManager(IconMgr *ip, WList *tmp)
949645f5050Syouri{
9500bbfda8aSnia	if(tmp->prev == NULL) {
9510bbfda8aSnia		ip->first = tmp->next;
9520bbfda8aSnia	}
9530bbfda8aSnia	else {
9540bbfda8aSnia		tmp->prev->next = tmp->next;
9550bbfda8aSnia	}
9560bbfda8aSnia
9570bbfda8aSnia	if(tmp->next == NULL) {
9580bbfda8aSnia		ip->last = tmp->prev;
9590bbfda8aSnia	}
9600bbfda8aSnia	else {
9610bbfda8aSnia		tmp->next->prev = tmp->prev;
9620bbfda8aSnia	}
9630bbfda8aSnia
9640bbfda8aSnia	/* pebl: If the list was the current and tmp was the last in the list
9650bbfda8aSnia	   reset current list */
9660bbfda8aSnia	if(Current == tmp) {
9670bbfda8aSnia		Current = ip->first;
9680bbfda8aSnia	}
969645f5050Syouri}
970645f5050Syouri
971645f5050Syouri/***********************************************************************
972645f5050Syouri *
973645f5050Syouri *  Procedure:
9740bbfda8aSnia *      RemoveIconManager - remove a window from the icon manager
975645f5050Syouri *
976645f5050Syouri *  Inputs:
9770bbfda8aSnia *      tmp_win - the TwmWindow structure
978645f5050Syouri *
979645f5050Syouri ***********************************************************************
980645f5050Syouri */
981645f5050Syouri
982645f5050Syourivoid RemoveIconManager(TwmWindow *tmp_win)
983645f5050Syouri{
9840bbfda8aSnia	IconMgr *ip;
9850bbfda8aSnia	WList *tmp, *tmp1, *save;
9860bbfda8aSnia
9870bbfda8aSnia	if(tmp_win->iconmanagerlist == NULL) {
9880bbfda8aSnia		return;
9890bbfda8aSnia	}
9900bbfda8aSnia
9910bbfda8aSnia	tmp  = tmp_win->iconmanagerlist;
9920bbfda8aSnia	tmp1 = NULL;
9930bbfda8aSnia
9940bbfda8aSnia	while(tmp != NULL) {
9950bbfda8aSnia		ip = tmp->iconmgr;
9960bbfda8aSnia		if((tmp_win->occupation & ip->twm_win->occupation) != 0) {
9970bbfda8aSnia			tmp1 = tmp;
9980bbfda8aSnia			tmp  = tmp->nextv;
9990bbfda8aSnia			continue;
10000bbfda8aSnia		}
10010bbfda8aSnia		RemoveFromIconManager(ip, tmp);
10020bbfda8aSnia
10030bbfda8aSnia		XDeleteContext(dpy, tmp->icon, TwmContext);
10040bbfda8aSnia		XDeleteContext(dpy, tmp->icon, ScreenContext);
10050bbfda8aSnia		XDestroyWindow(dpy, tmp->icon);
10060bbfda8aSnia		XDeleteContext(dpy, tmp->w, TwmContext);
10070bbfda8aSnia		XDeleteContext(dpy, tmp->w, ScreenContext);
10080bbfda8aSnia		XDestroyWindow(dpy, tmp->w);
10090bbfda8aSnia		ip->count -= 1;
10100bbfda8aSnia
10110bbfda8aSnia		PackIconManager(ip);
10120bbfda8aSnia
10130bbfda8aSnia		if(ip->count == 0) {
10140bbfda8aSnia			XUnmapWindow(dpy, ip->twm_win->frame);
10150bbfda8aSnia			ip->twm_win->mapped = false;
10160bbfda8aSnia		}
10170bbfda8aSnia		if(tmp1 == NULL) {
10180bbfda8aSnia			tmp_win->iconmanagerlist = tmp_win->iconmanagerlist->nextv;
10190bbfda8aSnia		}
10200bbfda8aSnia		else {
10210bbfda8aSnia			tmp1->nextv = tmp->nextv;
10220bbfda8aSnia		}
10230bbfda8aSnia
10240bbfda8aSnia		save = tmp;
10250bbfda8aSnia		tmp = tmp->nextv;
10260bbfda8aSnia		free(save);
10270bbfda8aSnia	}
1028645f5050Syouri}
1029645f5050Syouri
10300bbfda8aSniavoid CurrentIconManagerEntry(WList *current)
1031645f5050Syouri{
10320bbfda8aSnia	Current = current;
1033645f5050Syouri}
1034645f5050Syouri
1035645f5050Syourivoid ActiveIconManager(WList *active)
1036645f5050Syouri{
10370bbfda8aSnia	active->active = true;
10380bbfda8aSnia	Active = active;
10390bbfda8aSnia	Active->iconmgr->active = active;
10400bbfda8aSnia	Current = Active;
10410bbfda8aSnia	DrawIconManagerBorder(active, false);
1042645f5050Syouri}
1043645f5050Syouri
1044645f5050Syourivoid NotActiveIconManager(WList *active)
1045645f5050Syouri{
10460bbfda8aSnia	active->active = false;
10470bbfda8aSnia	DrawIconManagerBorder(active, false);
1048645f5050Syouri}
1049645f5050Syouri
10500bbfda8aSniavoid DrawIconManagerBorder(WList *tmp, bool fill)
1051645f5050Syouri{
10520bbfda8aSnia	if(Scr->use3Diconmanagers) {
10530bbfda8aSnia		Draw3DBorder(tmp->w, 0, 0, tmp->width, tmp->height,
10540bbfda8aSnia		             Scr->IconManagerShadowDepth, tmp->cp,
10550bbfda8aSnia		             (tmp->active && Scr->Highlight ? on : off),
10560bbfda8aSnia		             fill, false);
10570bbfda8aSnia	}
10580bbfda8aSnia	else {
10590bbfda8aSnia		XSetForeground(dpy, Scr->NormalGC, tmp->cp.fore);
10600bbfda8aSnia		XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 2, 2, tmp->width - 5,
10610bbfda8aSnia		               tmp->height - 5);
10620bbfda8aSnia
10630bbfda8aSnia		XSetForeground(dpy, Scr->NormalGC,
10640bbfda8aSnia		               (tmp->active && Scr->Highlight
10650bbfda8aSnia		                ? tmp->highlight : tmp->cp.back));
10660bbfda8aSnia
10670bbfda8aSnia		XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 0, 0, tmp->width - 1,
10680bbfda8aSnia		               tmp->height - 1);
10690bbfda8aSnia		XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 1, 1, tmp->width - 3,
10700bbfda8aSnia		               tmp->height - 3);
10710bbfda8aSnia	}
1072645f5050Syouri}
1073645f5050Syouri
1074645f5050Syouri/***********************************************************************
1075645f5050Syouri *
1076645f5050Syouri *  Procedure:
10770bbfda8aSnia *      SortIconManager - sort the dude
1078645f5050Syouri *
1079645f5050Syouri *  Inputs:
10800bbfda8aSnia *      ip      - a pointer to the icon manager struture
1081645f5050Syouri *
1082645f5050Syouri ***********************************************************************
1083645f5050Syouri */
1084645f5050Syouri
1085645f5050Syourivoid SortIconManager(IconMgr *ip)
1086645f5050Syouri{
10870bbfda8aSnia	WList *tmp1, *tmp2;
10880bbfda8aSnia	int done;
10890bbfda8aSnia
10900bbfda8aSnia	if(ip == NULL) {
10910bbfda8aSnia		ip = Active->iconmgr;
10920bbfda8aSnia	}
10930bbfda8aSnia
10940bbfda8aSnia	done = false;
10950bbfda8aSnia	do {
10960bbfda8aSnia		for(tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) {
10970bbfda8aSnia			int compresult;
10980bbfda8aSnia			if((tmp2 = tmp1->next) == NULL) {
10990bbfda8aSnia				done = true;
11000bbfda8aSnia				break;
11010bbfda8aSnia			}
11020bbfda8aSnia			if(Scr->CaseSensitive) {
11030bbfda8aSnia				compresult = strcmp(tmp1->twm->icon_name, tmp2->twm->icon_name);
11040bbfda8aSnia			}
11050bbfda8aSnia			else {
11060bbfda8aSnia				compresult = strcasecmp(tmp1->twm->icon_name, tmp2->twm->icon_name);
11070bbfda8aSnia			}
11080bbfda8aSnia			if(compresult > 0) {
11090bbfda8aSnia				/* take it out and put it back in */
11100bbfda8aSnia				RemoveFromIconManager(ip, tmp2);
11110bbfda8aSnia				InsertInIconManager(ip, tmp2, tmp2->twm);
11120bbfda8aSnia				break;
11130bbfda8aSnia			}
11140bbfda8aSnia		}
11150bbfda8aSnia	}
11160bbfda8aSnia	while(!done);
11170bbfda8aSnia	PackIconManager(ip);
1118645f5050Syouri}
1119645f5050Syouri
1120645f5050Syouri/***********************************************************************
1121645f5050Syouri *
1122645f5050Syouri *  Procedure:
11230bbfda8aSnia *      PackIconManager - pack the icon manager windows following
11240bbfda8aSnia *              an addition or deletion
1125645f5050Syouri *
1126645f5050Syouri *  Inputs:
11270bbfda8aSnia *      ip      - a pointer to the icon manager struture
1128645f5050Syouri *
1129645f5050Syouri ***********************************************************************
1130645f5050Syouri */
1131645f5050Syouri
11320bbfda8aSniavoid PackIconManagers(void)
11330bbfda8aSnia{
11340bbfda8aSnia	TwmWindow *twm_win;
11350bbfda8aSnia
11360bbfda8aSnia	for(twm_win = Scr->FirstWindow; twm_win != NULL; twm_win = twm_win->next) {
11370bbfda8aSnia		if(twm_win->iconmgrp) {
11380bbfda8aSnia			PackIconManager(twm_win->iconmgrp);
11390bbfda8aSnia		}
11400bbfda8aSnia	}
11410bbfda8aSnia}
11420bbfda8aSnia
1143645f5050Syourivoid PackIconManager(IconMgr *ip)
1144645f5050Syouri{
11450bbfda8aSnia	int newwidth, i, row, col, maxcol,  colinc, rowinc, wheight, wwidth;
11460bbfda8aSnia	int new_x, new_y;
11470bbfda8aSnia	int savewidth;
11480bbfda8aSnia	WList *tmp;
11490bbfda8aSnia	int mask;
11500bbfda8aSnia
11510bbfda8aSnia	wheight = Scr->IconManagerFont.avg_height
11520bbfda8aSnia	          + 2 * (ICON_MGR_OBORDER + ICON_MGR_IBORDER);
11530bbfda8aSnia	if(wheight < (im_iconified_icon_height + 4)) {
11540bbfda8aSnia		wheight = im_iconified_icon_height + 4;
11550bbfda8aSnia	}
11560bbfda8aSnia
11570bbfda8aSnia	wwidth = ip->width / ip->columns;
11580bbfda8aSnia
11590bbfda8aSnia	rowinc = wheight;
11600bbfda8aSnia	colinc = wwidth;
11610bbfda8aSnia
11620bbfda8aSnia	row = 0;
11630bbfda8aSnia	col = ip->columns;
11640bbfda8aSnia	maxcol = 0;
11650bbfda8aSnia	for(i = 0, tmp = ip->first; tmp != NULL; i++, tmp = tmp->next) {
11660bbfda8aSnia		tmp->me = i;
11670bbfda8aSnia		if(++col >= ip->columns) {
11680bbfda8aSnia			col = 0;
11690bbfda8aSnia			row += 1;
11700bbfda8aSnia		}
11710bbfda8aSnia		if(col > maxcol) {
11720bbfda8aSnia			maxcol = col;
11730bbfda8aSnia		}
11740bbfda8aSnia
11750bbfda8aSnia		new_x = col * colinc;
11760bbfda8aSnia		new_y = (row - 1) * rowinc;
11770bbfda8aSnia
11780bbfda8aSnia		/* if the position or size has not changed, don't touch it */
11790bbfda8aSnia		if(tmp->x != new_x || tmp->y != new_y ||
11800bbfda8aSnia		                tmp->width != wwidth || tmp->height != wheight) {
11810bbfda8aSnia			XMoveResizeWindow(dpy, tmp->w, new_x, new_y, wwidth, wheight);
11820bbfda8aSnia			if(tmp->height != wheight)
11830bbfda8aSnia				XMoveWindow(dpy, tmp->icon, ICON_MGR_OBORDER + ICON_MGR_IBORDER,
11840bbfda8aSnia				            (wheight - im_iconified_icon_height) / 2);
11850bbfda8aSnia
11860bbfda8aSnia			tmp->row = row - 1;
11870bbfda8aSnia			tmp->col = col;
11880bbfda8aSnia			tmp->x = new_x;
11890bbfda8aSnia			tmp->y = new_y;
11900bbfda8aSnia			tmp->width = wwidth;
11910bbfda8aSnia			tmp->height = wheight;
11920bbfda8aSnia		}
11930bbfda8aSnia	}
11940bbfda8aSnia	maxcol += 1;
11950bbfda8aSnia
11960bbfda8aSnia	ip->cur_rows = row;
11970bbfda8aSnia	ip->cur_columns = maxcol;
11980bbfda8aSnia	ip->height = row * rowinc;
11990bbfda8aSnia	if(ip->height == 0) {
12000bbfda8aSnia		ip->height = rowinc;
12010bbfda8aSnia	}
12020bbfda8aSnia	newwidth = maxcol * colinc;
12030bbfda8aSnia	if(newwidth == 0) {
12040bbfda8aSnia		newwidth = colinc;
12050bbfda8aSnia	}
12060bbfda8aSnia
12070bbfda8aSnia	XResizeWindow(dpy, ip->w, newwidth, ip->height);
12080bbfda8aSnia
1209df1c27a6Snia	mask = RLayoutXParseGeometry(Scr->Layout, ip->geometry, &JunkX, &JunkY,
1210df1c27a6Snia	                             &JunkWidth, &JunkHeight);
12110bbfda8aSnia	if(mask & XNegative) {
12120bbfda8aSnia		ip->twm_win->frame_x += ip->twm_win->frame_width - newwidth -
12130bbfda8aSnia		                        2 * ip->twm_win->frame_bw3D;
12140bbfda8aSnia	}
12150bbfda8aSnia	if(mask & YNegative) {
12160bbfda8aSnia		ip->twm_win->frame_y += ip->twm_win->frame_height - ip->height -
12170bbfda8aSnia		                        2 * ip->twm_win->frame_bw3D - ip->twm_win->title_height;
12180bbfda8aSnia	}
12190bbfda8aSnia	savewidth = ip->width;
12200bbfda8aSnia	if(ip->twm_win)
12210bbfda8aSnia		SetupWindow(ip->twm_win,
12220bbfda8aSnia		            ip->twm_win->frame_x, ip->twm_win->frame_y,
12230bbfda8aSnia		            newwidth + 2 * ip->twm_win->frame_bw3D,
12240bbfda8aSnia		            ip->height + ip->twm_win->title_height + 2 * ip->twm_win->frame_bw3D, -1);
12250bbfda8aSnia	ip->width = savewidth;
12260bbfda8aSnia}
12270bbfda8aSnia
12280bbfda8aSniavoid dump_iconmanager(IconMgr *mgr, char *label)
12290bbfda8aSnia{
12300bbfda8aSnia	fprintf(stderr, "IconMgr %s %p name='%s' geom='%s'\n",
12310bbfda8aSnia	        label,
12320bbfda8aSnia	        mgr,
12330bbfda8aSnia	        mgr->name,
12340bbfda8aSnia	        mgr->geometry);
12350bbfda8aSnia	fprintf(stderr, "next = %p, prev = %p, lasti = %p, nextv = %p\n",
12360bbfda8aSnia	        mgr->next,
12370bbfda8aSnia	        mgr->prev,
12380bbfda8aSnia	        mgr->lasti,
12390bbfda8aSnia	        mgr->nextv);
12400bbfda8aSnia}
12410bbfda8aSnia
12420bbfda8aSnia
12430bbfda8aSnia/*
12440bbfda8aSnia * Draw the window name into the icon manager line
12450bbfda8aSnia */
12460bbfda8aSniavoid
12470bbfda8aSniaDrawIconManagerIconName(TwmWindow *tmp_win)
12480bbfda8aSnia{
12490bbfda8aSnia	WList *iconmanagerlist = tmp_win->iconmanagerlist;
12500bbfda8aSnia	XRectangle ink_rect, logical_rect;
12510bbfda8aSnia
12520bbfda8aSnia	XmbTextExtents(Scr->IconManagerFont.font_set,
12530bbfda8aSnia	               tmp_win->icon_name, strlen(tmp_win->icon_name),
12540bbfda8aSnia	               &ink_rect, &logical_rect);
12550bbfda8aSnia
12560bbfda8aSnia	if(UpdateFont(&Scr->IconManagerFont, logical_rect.height)) {
12570bbfda8aSnia		PackIconManagers();
12580bbfda8aSnia	}
12590bbfda8aSnia
1260df1c27a6Snia	// Write in the title
12610bbfda8aSnia	FB(iconmanagerlist->cp.fore, iconmanagerlist->cp.back);
12620bbfda8aSnia
12630bbfda8aSnia	/* XXX This is a completely absurd way of writing this */
12640bbfda8aSnia	((Scr->use3Diconmanagers && (Scr->Monochrome != COLOR)) ?
12650bbfda8aSnia	 XmbDrawImageString : XmbDrawString)
12660bbfda8aSnia	(dpy,
12670bbfda8aSnia	 iconmanagerlist->w,
12680bbfda8aSnia	 Scr->IconManagerFont.font_set,
12690bbfda8aSnia	 Scr->NormalGC,
12700bbfda8aSnia	 iconmgr_textx,
12710bbfda8aSnia	 (Scr->IconManagerFont.avg_height - logical_rect.height) / 2
12720bbfda8aSnia	 + (- logical_rect.y)
12730bbfda8aSnia	 + ICON_MGR_OBORDER
12740bbfda8aSnia	 + ICON_MGR_IBORDER,
12750bbfda8aSnia	 tmp_win->icon_name,
12760bbfda8aSnia	 strlen(tmp_win->icon_name));
1277df1c27a6Snia
1278df1c27a6Snia	// Draw the border around it.  Our "border" isn't an X border, it's
1279df1c27a6Snia	// just our own drawing inside the X window.  Since XmbDrawString()
1280df1c27a6Snia	// believes it has all the space in the window to fill, it might
1281df1c27a6Snia	// scribble into the space where we're drawing the border, so draw
1282df1c27a6Snia	// the border after the text to cover it up.
1283df1c27a6Snia	DrawIconManagerBorder(iconmanagerlist, false);
12840bbfda8aSnia}
12850bbfda8aSnia
12860bbfda8aSnia
12870bbfda8aSnia/*
12880bbfda8aSnia * Copy the icon into the icon manager for a window that's iconified.
12890bbfda8aSnia * This is slightly different for the 3d vs 2d case, since the 3d is just
12900bbfda8aSnia * copying a pixmap in, while the 2d is drawing a bitmap in with the
12910bbfda8aSnia * fg/bg colors appropriate to the line.
12920bbfda8aSnia */
12930bbfda8aSniavoid
12940bbfda8aSniaShowIconifiedIcon(TwmWindow *tmp_win)
12950bbfda8aSnia{
12960bbfda8aSnia	WList *iconmanagerlist = tmp_win->iconmanagerlist;
12970bbfda8aSnia
12980bbfda8aSnia	if(Scr->use3Diconmanagers && iconmanagerlist->iconifypm) {
12990bbfda8aSnia		XCopyArea(dpy, iconmanagerlist->iconifypm,
13000bbfda8aSnia		          iconmanagerlist->icon,
13010bbfda8aSnia		          Scr->NormalGC, 0, 0,
13020bbfda8aSnia		          im_iconified_icon_width, im_iconified_icon_height, 0, 0);
13030bbfda8aSnia	}
13040bbfda8aSnia	else {
13050bbfda8aSnia		FB(iconmanagerlist->cp.fore, iconmanagerlist->cp.back);
13060bbfda8aSnia		XCopyPlane(dpy, Scr->siconifyPm, iconmanagerlist->icon,
13070bbfda8aSnia		           Scr->NormalGC, 0, 0,
13080bbfda8aSnia		           im_iconified_icon_width, im_iconified_icon_height, 0, 0, 1);
13090bbfda8aSnia	}
1310645f5050Syouri}
1311