1645f5050Syouri/*
2645f5050Syouri * Copyright 1989 Massachusetts Institute of Technology
30bbfda8aSnia * Copyright 1992 Claude Lecommandeur.
4645f5050Syouri */
5645f5050Syouri
6645f5050Syouri/**********************************************************************
7645f5050Syouri *
8645f5050Syouri * $XConsortium: icons.c,v 1.22 91/07/12 09:58:38 dave Exp $
9645f5050Syouri *
10645f5050Syouri * Icon releated routines
11645f5050Syouri *
12645f5050Syouri * 10-Apr-89 Tom LaStrange        Initial Version.
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
270bbfda8aSnia#include <X11/extensions/shape.h>
280bbfda8aSnia
290bbfda8aSnia#include "drawing.h"
30645f5050Syouri#include "screen.h"
310bbfda8aSnia#include "iconmgr.h"
32645f5050Syouri#include "icons.h"
330bbfda8aSnia#include "otp.h"
34645f5050Syouri#include "list.h"
35645f5050Syouri#include "parse.h"
36645f5050Syouri#include "util.h"
370bbfda8aSnia#include "animate.h"
380bbfda8aSnia#include "image.h"
390bbfda8aSnia#include "win_utils.h"
400bbfda8aSnia#include "workspace_manager.h"
41df1c27a6Snia#include "xparsegeometry.h"
42df1c27a6Snia
430bbfda8aSnia
440bbfda8aSniastatic void splitIconRegionEntry(IconEntry *ie, RegGravity grav1,
450bbfda8aSnia                                 RegGravity grav2, int w, int h);
460bbfda8aSniastatic void PlaceIcon(TwmWindow *tmp_win, int def_x, int def_y,
470bbfda8aSnia                      int *final_x, int *final_y);
480bbfda8aSniastatic IconEntry *FindIconEntry(TwmWindow *tmp_win, IconRegion **irp);
490bbfda8aSniastatic IconEntry *prevIconEntry(IconEntry *ie, IconRegion *ir);
500bbfda8aSniastatic void mergeEntries(IconEntry *old, IconEntry *ie);
510bbfda8aSniastatic void ReshapeIcon(Icon *icon);
520bbfda8aSniastatic int roundUp(int v, int multiple);
530bbfda8aSniastatic Image *LookupIconNameOrClass(TwmWindow *tmp_win, Icon *icon,
540bbfda8aSnia                                    char **pattern);
55645f5050Syouri
56645f5050Syouri
57645f5050Syouri
580bbfda8aSnia/*
590bbfda8aSnia ****************************************************************
600bbfda8aSnia *
610bbfda8aSnia * First some bits related to figuring out where icons go.  Lots of
620bbfda8aSnia * IconRegion handling stuff, handling of IconEntry tracking, etc.
630bbfda8aSnia *
640bbfda8aSnia ****************************************************************
650bbfda8aSnia */
660bbfda8aSnia
670bbfda8aSnia
680bbfda8aSnia/*
690bbfda8aSnia * This function operates in very weird and obtuse ways, especially in
700bbfda8aSnia * how it handles vertical vs. horizontal in weird recursive calls.  Part
710bbfda8aSnia * of this is what previously allowed specs with "hgrav vgrav" instead of
720bbfda8aSnia * the proper "vgrav hgrav" to sorta-work.  This should be broken up at
730bbfda8aSnia * some point into clean h/v functions, but because of the recursion it's
740bbfda8aSnia * not exactly trivial.  The parsing code now enforces v/h, so at least
750bbfda8aSnia * things can be known to come in in the right order initially.  Revisit
760bbfda8aSnia * someday.
770bbfda8aSnia */
780bbfda8aSniastatic void
790bbfda8aSniasplitIconRegionEntry(IconEntry *ie, RegGravity grav1, RegGravity grav2,
800bbfda8aSnia                     int w, int h)
81645f5050Syouri{
820bbfda8aSnia	switch(grav1) {
830bbfda8aSnia		case GRAV_NORTH:
840bbfda8aSnia		case GRAV_SOUTH:
850bbfda8aSnia			if(w != ie->w) {
860bbfda8aSnia				splitIconRegionEntry(ie, grav2, grav1, w, ie->h);
870bbfda8aSnia			}
880bbfda8aSnia			if(h != ie->h) {
890bbfda8aSnia				IconEntry *new = calloc(1, sizeof(IconEntry));
900bbfda8aSnia				new->next = ie->next;
910bbfda8aSnia				ie->next = new;
920bbfda8aSnia				new->x = ie->x;
930bbfda8aSnia				new->h = (ie->h - h);
940bbfda8aSnia				new->w = ie->w;
950bbfda8aSnia				ie->h = h;
960bbfda8aSnia				if(grav1 == GRAV_SOUTH) {
970bbfda8aSnia					new->y = ie->y;
980bbfda8aSnia					ie->y = new->y + new->h;
990bbfda8aSnia				}
1000bbfda8aSnia				else {
1010bbfda8aSnia					new->y = ie->y + ie->h;
1020bbfda8aSnia				}
1030bbfda8aSnia			}
1040bbfda8aSnia			break;
1050bbfda8aSnia		case GRAV_EAST:
1060bbfda8aSnia		case GRAV_WEST:
1070bbfda8aSnia			if(h != ie->h) {
1080bbfda8aSnia				splitIconRegionEntry(ie, grav2, grav1, ie->w, h);
1090bbfda8aSnia			}
1100bbfda8aSnia			if(w != ie->w) {
1110bbfda8aSnia				IconEntry *new = calloc(1, sizeof(IconEntry));
1120bbfda8aSnia				new->next = ie->next;
1130bbfda8aSnia				ie->next = new;
1140bbfda8aSnia				new->y = ie->y;
1150bbfda8aSnia				new->w = (ie->w - w);
1160bbfda8aSnia				new->h = ie->h;
1170bbfda8aSnia				ie->w = w;
1180bbfda8aSnia				if(grav1 == GRAV_EAST) {
1190bbfda8aSnia					new->x = ie->x;
1200bbfda8aSnia					ie->x = new->x + new->w;
1210bbfda8aSnia				}
1220bbfda8aSnia				else {
1230bbfda8aSnia					new->x = ie->x + ie->w;
1240bbfda8aSnia				}
1250bbfda8aSnia			}
1260bbfda8aSnia			break;
1270bbfda8aSnia	}
128645f5050Syouri}
129645f5050Syouri
1300bbfda8aSnia
1310bbfda8aSnia/*
1320bbfda8aSnia * Backend for parsing IconRegion config
1330bbfda8aSnia */
1340bbfda8aSnianame_list **
1350bbfda8aSniaAddIconRegion(const char *geom, RegGravity grav1, RegGravity grav2,
1360bbfda8aSnia              int stepx, int stepy,
1370bbfda8aSnia              const char *ijust, const char *just, const char *align)
138645f5050Syouri{
1390bbfda8aSnia	IconRegion *ir;
1400bbfda8aSnia	int mask, tmp;
1410bbfda8aSnia
1420bbfda8aSnia	ir = malloc(sizeof(IconRegion));
1430bbfda8aSnia	ir->next = NULL;
1440bbfda8aSnia
1450bbfda8aSnia	if(Scr->LastRegion) {
1460bbfda8aSnia		Scr->LastRegion->next = ir;
1470bbfda8aSnia	}
1480bbfda8aSnia	Scr->LastRegion = ir;
1490bbfda8aSnia	if(!Scr->FirstRegion) {
1500bbfda8aSnia		Scr->FirstRegion = ir;
1510bbfda8aSnia	}
1520bbfda8aSnia
1530bbfda8aSnia	ir->entries = NULL;
1540bbfda8aSnia	ir->clientlist = NULL;
1550bbfda8aSnia	ir->grav1 = grav1;
1560bbfda8aSnia	ir->grav2 = grav2;
1570bbfda8aSnia	if(stepx <= 0) {
1580bbfda8aSnia		stepx = 1;
1590bbfda8aSnia	}
1600bbfda8aSnia	if(stepy <= 0) {
1610bbfda8aSnia		stepy = 1;
1620bbfda8aSnia	}
1630bbfda8aSnia	ir->stepx = stepx;
1640bbfda8aSnia	ir->stepy = stepy;
1650bbfda8aSnia	ir->x = ir->y = ir->w = ir->h = 0;
1660bbfda8aSnia
167df1c27a6Snia	mask = RLayoutXParseGeometry(Scr->Layout, geom, &ir->x, &ir->y,
168df1c27a6Snia	                             (unsigned int *)&ir->w, (unsigned int *)&ir->h);
1690bbfda8aSnia
1700bbfda8aSnia	if(mask & XNegative) {
1710bbfda8aSnia		ir->x += Scr->rootw - ir->w;
1720bbfda8aSnia	}
1730bbfda8aSnia	if(mask & YNegative) {
1740bbfda8aSnia		ir->y += Scr->rooth - ir->h;
1750bbfda8aSnia	}
1760bbfda8aSnia
1770bbfda8aSnia	ir->entries = calloc(1, sizeof(IconEntry));
1780bbfda8aSnia	ir->entries->x = ir->x;
1790bbfda8aSnia	ir->entries->y = ir->y;
1800bbfda8aSnia	ir->entries->w = ir->w;
1810bbfda8aSnia	ir->entries->h = ir->h;
1820bbfda8aSnia
1830bbfda8aSnia	if((tmp = ParseTitleJustification(ijust)) < 0) {
1840bbfda8aSnia		twmrc_error_prefix();
1850bbfda8aSnia		fprintf(stderr, "ignoring invalid IconRegion argument \"%s\"\n", ijust);
1860bbfda8aSnia		tmp = TJ_UNDEF;
1870bbfda8aSnia	}
1880bbfda8aSnia	ir->TitleJustification = tmp;
1890bbfda8aSnia
1900bbfda8aSnia	if((tmp = ParseIRJustification(just)) < 0) {
1910bbfda8aSnia		twmrc_error_prefix();
1920bbfda8aSnia		fprintf(stderr, "ignoring invalid IconRegion argument \"%s\"\n", just);
1930bbfda8aSnia		tmp = IRJ_UNDEF;
1940bbfda8aSnia	}
1950bbfda8aSnia	ir->Justification = tmp;
1960bbfda8aSnia
1970bbfda8aSnia	if((tmp = ParseAlignement(align)) < 0) {
1980bbfda8aSnia		twmrc_error_prefix();
1990bbfda8aSnia		fprintf(stderr, "ignoring invalid IconRegion argument \"%s\"\n", align);
2000bbfda8aSnia		tmp = IRA_UNDEF;
2010bbfda8aSnia	}
2020bbfda8aSnia	ir->Alignement = tmp;
2030bbfda8aSnia
2040bbfda8aSnia	return(&(ir->clientlist));
205645f5050Syouri}
206645f5050Syouri
2070bbfda8aSnia
2080bbfda8aSnia/*
2090bbfda8aSnia * Figure out where to put a window's icon based on the IconRegion
2100bbfda8aSnia * specifications given in config.  Passed def_[xy] which are used
2110bbfda8aSnia * if we don't find a better location ourselves.  Returns the chosen
2120bbfda8aSnia * location in final_[xy], and also sets the IconRegion in tmp_win->icon
2130bbfda8aSnia * if we chose one.
2140bbfda8aSnia */
2150bbfda8aSniastatic void
2160bbfda8aSniaPlaceIcon(TwmWindow *tmp_win, int def_x, int def_y,
2170bbfda8aSnia          int *final_x, int *final_y)
218645f5050Syouri{
2190bbfda8aSnia	IconRegion  *ir, *oldir;
2200bbfda8aSnia	IconEntry   *ie;
2210bbfda8aSnia	int         w, h;
2220bbfda8aSnia
2230bbfda8aSnia	const int iconWidth = tmp_win->icon->border_width * 2
2240bbfda8aSnia	                      + (Scr->ShrinkIconTitles ? tmp_win->icon->width
2250bbfda8aSnia	                         : tmp_win->icon->w_width);
2260bbfda8aSnia	const int iconHeight = tmp_win->icon->border_width * 2
2270bbfda8aSnia	                       + tmp_win->icon->w_height;
2280bbfda8aSnia
2290bbfda8aSnia	/*
2300bbfda8aSnia	 * First, check to see if the window is in a region's client list
2310bbfda8aSnia	 * (i.e., the win-list on an IconRegion specifier in the config).
2320bbfda8aSnia	 */
2330bbfda8aSnia	ie = NULL;
2340bbfda8aSnia	for(ir = Scr->FirstRegion; ir; ir = ir->next) {
2350bbfda8aSnia		if(LookInList(ir->clientlist, tmp_win->name, &tmp_win->class)) {
2360bbfda8aSnia			/*
2370bbfda8aSnia			 * Found one that claims it.  Figure the necessary local
2380bbfda8aSnia			 * size, based on the icon's side itself and the grid for
2390bbfda8aSnia			 * this IR.
2400bbfda8aSnia			 */
2410bbfda8aSnia			w = roundUp(iconWidth, ir->stepx);
2420bbfda8aSnia			h = roundUp(iconHeight, ir->stepy);
2430bbfda8aSnia
2440bbfda8aSnia			/* Find a currently-unused region that's big enough */
2450bbfda8aSnia			for(ie = ir->entries; ie; ie = ie->next) {
2460bbfda8aSnia				if(ie->used) {
2470bbfda8aSnia					continue;
2480bbfda8aSnia				}
2490bbfda8aSnia				if(ie->w >= w && ie->h >= h) {
2500bbfda8aSnia					/* Bingo */
2510bbfda8aSnia					break;
2520bbfda8aSnia				}
2530bbfda8aSnia			}
2540bbfda8aSnia
2550bbfda8aSnia			/* If we found one, we're done here */
2560bbfda8aSnia			if(ie) {
2570bbfda8aSnia				break;
2580bbfda8aSnia			}
2590bbfda8aSnia		}
2600bbfda8aSnia	}
2610bbfda8aSnia
2620bbfda8aSnia
2630bbfda8aSnia	/*
2640bbfda8aSnia	 * If we found a slot in a region claiming it, ie is set to the
2650bbfda8aSnia	 * IconEntry.  If not, start over and find the first available berth.
2660bbfda8aSnia	 */
2670bbfda8aSnia	if(!ie) {
2680bbfda8aSnia		for(ir = Scr->FirstRegion; ir; ir = ir->next) {
2690bbfda8aSnia			w = roundUp(iconWidth, ir->stepx);
2700bbfda8aSnia			h = roundUp(iconHeight, ir->stepy);
2710bbfda8aSnia			for(ie = ir->entries; ie; ie = ie->next) {
2720bbfda8aSnia				if(ie->used) {
2730bbfda8aSnia					continue;
2740bbfda8aSnia				}
2750bbfda8aSnia				if(ie->w >= w && ie->h >= h) {
2760bbfda8aSnia					/* Bingo */
2770bbfda8aSnia					break;
2780bbfda8aSnia				}
2790bbfda8aSnia			}
2800bbfda8aSnia			if(ie) {
2810bbfda8aSnia				break;
2820bbfda8aSnia			}
2830bbfda8aSnia		}
2840bbfda8aSnia	}
2850bbfda8aSnia
2860bbfda8aSnia	/* Stash for comparison */
2870bbfda8aSnia	oldir = tmp_win->icon->ir;
2880bbfda8aSnia
2890bbfda8aSnia	/*
2900bbfda8aSnia	 * If we found an appropriate region, use it.  Else, we have no
2910bbfda8aSnia	 * better idea, so use the x/y coords the caller passed us as our
2920bbfda8aSnia	 * basis.
2930bbfda8aSnia	 */
2940bbfda8aSnia	if(ie) {
2950bbfda8aSnia		/* XXX whatever sIRE() does */
2960bbfda8aSnia		splitIconRegionEntry(ie, ir->grav1, ir->grav2, w, h);
2970bbfda8aSnia
2980bbfda8aSnia		/* Adjust horizontal positioning based on IconRegionJustification */
2990bbfda8aSnia		switch(ir->Justification) {
3000bbfda8aSnia			case IRJ_LEFT:
3010bbfda8aSnia				*final_x = ie->x;
3020bbfda8aSnia				break;
3030bbfda8aSnia			case IRJ_UNDEF:
3040bbfda8aSnia			case IRJ_CENTER:
3050bbfda8aSnia				*final_x = ie->x + (ie->w - iconWidth) / 2;
3060bbfda8aSnia				break;
3070bbfda8aSnia			case IRJ_RIGHT:
3080bbfda8aSnia				*final_x = ie->x + ie->w - iconWidth;
3090bbfda8aSnia				break;
3100bbfda8aSnia			case IRJ_BORDER:
3110bbfda8aSnia				if(ir->grav2 == GRAV_EAST) {
3120bbfda8aSnia					*final_x = ie->x + ie->w - iconWidth;
3130bbfda8aSnia				}
3140bbfda8aSnia				else {
3150bbfda8aSnia					*final_x = ie->x;
3160bbfda8aSnia				}
3170bbfda8aSnia				break;
3180bbfda8aSnia		}
3190bbfda8aSnia
3200bbfda8aSnia		/* And vertical based on IconRegionAlignement */
3210bbfda8aSnia		switch(ir->Alignement) {
3220bbfda8aSnia			case IRA_TOP :
3230bbfda8aSnia				*final_y = ie->y;
3240bbfda8aSnia				break;
3250bbfda8aSnia			case IRA_UNDEF :
3260bbfda8aSnia			case IRA_CENTER :
3270bbfda8aSnia				*final_y = ie->y + (ie->h - iconHeight) / 2;
3280bbfda8aSnia				break;
3290bbfda8aSnia			case IRA_BOTTOM :
3300bbfda8aSnia				*final_y = ie->y + ie->h - iconHeight;
3310bbfda8aSnia				break;
3320bbfda8aSnia			case IRA_BORDER :
3330bbfda8aSnia				if(ir->grav1 == GRAV_SOUTH) {
3340bbfda8aSnia					*final_y = ie->y + ie->h - iconHeight;
3350bbfda8aSnia				}
3360bbfda8aSnia				else {
3370bbfda8aSnia					*final_y = ie->y;
3380bbfda8aSnia				}
3390bbfda8aSnia				break;
3400bbfda8aSnia		}
3410bbfda8aSnia
3420bbfda8aSnia		/* Tell the win/icon what region it's in, and the entry what's in it */
3430bbfda8aSnia		tmp_win->icon->ir = ir;
3440bbfda8aSnia		ie->used = true;
3450bbfda8aSnia		ie->twm_win = tmp_win;
3460bbfda8aSnia	}
3470bbfda8aSnia	else {
3480bbfda8aSnia		/* No better idea, tell caller to use theirs */
3490bbfda8aSnia		*final_x = def_x;
3500bbfda8aSnia		*final_y = def_y;
3510bbfda8aSnia		tmp_win->icon->ir = NULL;
3520bbfda8aSnia		return;
3530bbfda8aSnia		/* XXX Should we be doing the below in this case too? */
3540bbfda8aSnia	}
3550bbfda8aSnia
3560bbfda8aSnia	/* Alterations if ShrinkIconTitles is set */
3570bbfda8aSnia	if(Scr->ShrinkIconTitles && tmp_win->icon->has_title) {
3580bbfda8aSnia		*final_x -= GetIconOffset(tmp_win->icon);
3590bbfda8aSnia		if(tmp_win->icon->ir != oldir) {
3600bbfda8aSnia			ReshapeIcon(tmp_win->icon);
3610bbfda8aSnia		}
3620bbfda8aSnia	}
3630bbfda8aSnia
364645f5050Syouri	return;
365645f5050Syouri}
366645f5050Syouri
3670bbfda8aSnia
3680bbfda8aSnia/*
3690bbfda8aSnia * Look up an IconEntry holding the icon for a given window, and
3700bbfda8aSnia * optionally stash its IconRegion in irp.  Used internally in
3710bbfda8aSnia * IconDown().
3720bbfda8aSnia */
3730bbfda8aSniastatic IconEntry *
3740bbfda8aSniaFindIconEntry(TwmWindow *tmp_win, IconRegion **irp)
375645f5050Syouri{
3760bbfda8aSnia	IconRegion  *ir;
3770bbfda8aSnia	IconEntry   *ie;
3780bbfda8aSnia
3790bbfda8aSnia	for(ir = Scr->FirstRegion; ir; ir = ir->next) {
3800bbfda8aSnia		for(ie = ir->entries; ie; ie = ie->next)
3810bbfda8aSnia			if(ie->twm_win == tmp_win) {
3820bbfda8aSnia				if(irp) {
3830bbfda8aSnia					*irp = ir;
3840bbfda8aSnia				}
3850bbfda8aSnia				return ie;
3860bbfda8aSnia			}
3870bbfda8aSnia	}
3880bbfda8aSnia	return NULL;
389645f5050Syouri}
390645f5050Syouri
3910bbfda8aSnia
3920bbfda8aSnia/*
3930bbfda8aSnia * Find prior IE in list.  Used internally in IconDown().
3940bbfda8aSnia */
3950bbfda8aSniastatic IconEntry *
3960bbfda8aSniaprevIconEntry(IconEntry *ie, IconRegion *ir)
397645f5050Syouri{
3980bbfda8aSnia	IconEntry   *ip;
3990bbfda8aSnia
4000bbfda8aSnia	if(ie == ir->entries) {
4010bbfda8aSnia		return NULL;
4020bbfda8aSnia	}
4030bbfda8aSnia	for(ip = ir->entries; ip->next != ie; ip = ip->next)
4040bbfda8aSnia		;
4050bbfda8aSnia	return ip;
406645f5050Syouri}
407645f5050Syouri
408645f5050Syouri
4090bbfda8aSnia/*
4100bbfda8aSnia * Merge two adjacent IconEntry's.  old is being freed; and is adjacent
4110bbfda8aSnia * to ie.  Merge regions together.
4120bbfda8aSnia */
4130bbfda8aSniastatic void
4140bbfda8aSniamergeEntries(IconEntry *old, IconEntry *ie)
4150bbfda8aSnia{
4160bbfda8aSnia	if(old->y == ie->y) {
4170bbfda8aSnia		ie->w = old->w + ie->w;
4180bbfda8aSnia		if(old->x < ie->x) {
4190bbfda8aSnia			ie->x = old->x;
4200bbfda8aSnia		}
4210bbfda8aSnia	}
4220bbfda8aSnia	else {
4230bbfda8aSnia		ie->h = old->h + ie->h;
4240bbfda8aSnia		if(old->y < ie->y) {
4250bbfda8aSnia			ie->y = old->y;
4260bbfda8aSnia		}
4270bbfda8aSnia	}
428645f5050Syouri}
429645f5050Syouri
4300bbfda8aSnia
4310bbfda8aSnia
4320bbfda8aSnia
4330bbfda8aSnia/*
4340bbfda8aSnia ****************************************************************
4350bbfda8aSnia *
4360bbfda8aSnia * Next, the bits related to creating and putting together the icon
4370bbfda8aSnia * windows, as well as destroying them.
4380bbfda8aSnia *
4390bbfda8aSnia ****************************************************************
440645f5050Syouri */
441645f5050Syouri
4420bbfda8aSnia
4430bbfda8aSnia/*
4440bbfda8aSnia * Create the window scaffolding for an icon.  Called when we need to
4450bbfda8aSnia * make one, e.g. the first time a window is iconified.
4460bbfda8aSnia */
4470bbfda8aSniavoid
4480bbfda8aSniaCreateIconWindow(TwmWindow *tmp_win, int def_x, int def_y)
449645f5050Syouri{
4500bbfda8aSnia	unsigned long event_mask;
4510bbfda8aSnia	unsigned long valuemask;            /* mask for create windows */
4520bbfda8aSnia	XSetWindowAttributes attributes;    /* attributes for create windows */
4530bbfda8aSnia	int final_x, final_y;
4540bbfda8aSnia	int x;
4550bbfda8aSnia	Icon        *icon;
4560bbfda8aSnia	Image       *image = NULL;
4570bbfda8aSnia	char        *pattern;
4580bbfda8aSnia
4590bbfda8aSnia	icon = malloc(sizeof(struct Icon));
4600bbfda8aSnia
4610bbfda8aSnia	icon->otp           = NULL;
4620bbfda8aSnia	icon->border        = Scr->IconBorderColor;
4630bbfda8aSnia	icon->iconc.fore    = Scr->IconC.fore;
4640bbfda8aSnia	icon->iconc.back    = Scr->IconC.back;
4650bbfda8aSnia	icon->title_shrunk  = false;
4660bbfda8aSnia
4670bbfda8aSnia	GetColorFromList(Scr->IconBorderColorL, tmp_win->name, &tmp_win->class,
4680bbfda8aSnia	                 &icon->border);
4690bbfda8aSnia	GetColorFromList(Scr->IconForegroundL, tmp_win->name, &tmp_win->class,
4700bbfda8aSnia	                 &icon->iconc.fore);
4710bbfda8aSnia	GetColorFromList(Scr->IconBackgroundL, tmp_win->name, &tmp_win->class,
4720bbfda8aSnia	                 &icon->iconc.back);
4730bbfda8aSnia	if(Scr->use3Diconmanagers && !Scr->BeNiceToColormap) {
4740bbfda8aSnia		GetShadeColors(&icon->iconc);
4750bbfda8aSnia	}
4760bbfda8aSnia
4770bbfda8aSnia	FB(icon->iconc.fore, icon->iconc.back);
4780bbfda8aSnia
4790bbfda8aSnia	icon->match   = match_none;
4800bbfda8aSnia	icon->image   = NULL;
4810bbfda8aSnia	icon->ir      = NULL;
4820bbfda8aSnia
4830bbfda8aSnia	tmp_win->forced = false;
4840bbfda8aSnia	icon->w_not_ours = false;
4850bbfda8aSnia
4860bbfda8aSnia	pattern = NULL;
4870bbfda8aSnia
4880bbfda8aSnia	/* now go through the steps to get an icon window,  if ForceIcon is
4890bbfda8aSnia	 * set, then no matter what else is defined, the bitmap from the
4900bbfda8aSnia	 * .twmrc file is used
4910bbfda8aSnia	 */
4920bbfda8aSnia	if(Scr->ForceIcon) {
4930bbfda8aSnia		image = LookupIconNameOrClass(tmp_win, icon, &pattern);
4940bbfda8aSnia	}
4950bbfda8aSnia
4960bbfda8aSnia#ifdef EWMH
4970bbfda8aSnia	/*
4980bbfda8aSnia	 * Look to see if there is a _NET_WM_ICON property to provide an icon.
4990bbfda8aSnia	 */
5000bbfda8aSnia	if(image == NULL) {
5010bbfda8aSnia		image = EwmhGetIcon(Scr, tmp_win);
5020bbfda8aSnia		if(image != NULL) {
5030bbfda8aSnia			icon->match   = match_net_wm_icon;
5040bbfda8aSnia			icon->width   = image->width;
5050bbfda8aSnia			icon->height  = image->height;
5060bbfda8aSnia			icon->image   = image;
5070bbfda8aSnia		}
5080bbfda8aSnia	}
5090bbfda8aSnia#endif /* EWMH */
5100bbfda8aSnia
5110bbfda8aSnia	/* if the pixmap is still NULL, we didn't get one from the above code,
5120bbfda8aSnia	 * that could mean that ForceIcon was not set, or that the window
5130bbfda8aSnia	 * was not in the Icons list, now check the WM hints for an icon
5140bbfda8aSnia	 */
5150bbfda8aSnia	if(image == NULL && tmp_win->wmhints->flags & IconPixmapHint) {
5160bbfda8aSnia		unsigned int IconDepth, IconWidth, IconHeight;
5170bbfda8aSnia
5180bbfda8aSnia		if(XGetGeometry(dpy, tmp_win->wmhints->icon_pixmap,
5190bbfda8aSnia		                &JunkRoot, &JunkX, &JunkY, &IconWidth, &IconHeight, &JunkBW, &IconDepth)) {
5200bbfda8aSnia			image = AllocImage();
5210bbfda8aSnia			image->width  = IconWidth;
5220bbfda8aSnia			image->height = IconHeight;
5230bbfda8aSnia			image->pixmap = XCreatePixmap(dpy, Scr->Root, image->width,
5240bbfda8aSnia			                              image->height, Scr->d_depth);
5250bbfda8aSnia			if(IconDepth == Scr->d_depth)
5260bbfda8aSnia				XCopyArea(dpy, tmp_win->wmhints->icon_pixmap, image->pixmap, Scr->NormalGC,
5270bbfda8aSnia				          0, 0, image->width, image->height, 0, 0);
5280bbfda8aSnia			else
5290bbfda8aSnia				XCopyPlane(dpy, tmp_win->wmhints->icon_pixmap, image->pixmap, Scr->NormalGC,
5300bbfda8aSnia				           0, 0, image->width, image->height, 0, 0, 1);
5310bbfda8aSnia
5320bbfda8aSnia			icon->width   = image->width;
5330bbfda8aSnia			icon->height  = image->height;
5340bbfda8aSnia			icon->match   = match_icon_pixmap_hint;
5350bbfda8aSnia
5360bbfda8aSnia			if((tmp_win->wmhints->flags & IconMaskHint) &&
5370bbfda8aSnia			                XGetGeometry(dpy, tmp_win->wmhints->icon_mask,
5380bbfda8aSnia			                             &JunkRoot, &JunkX, &JunkY, &IconWidth, &IconHeight, &JunkBW, &IconDepth) &&
5390bbfda8aSnia			                (IconDepth == 1)) {
5400bbfda8aSnia				GC gc;
5410bbfda8aSnia
5420bbfda8aSnia				image->mask = XCreatePixmap(dpy, Scr->Root, IconWidth, IconHeight, 1);
5430bbfda8aSnia				if(image->mask) {
5440bbfda8aSnia					gc = XCreateGC(dpy, image->mask, 0, NULL);
5450bbfda8aSnia					if(gc) {
5460bbfda8aSnia						XCopyArea(dpy, tmp_win->wmhints->icon_mask, image->mask, gc,
5470bbfda8aSnia						          0, 0, IconWidth, IconHeight, 0, 0);
5480bbfda8aSnia						XFreeGC(dpy, gc);
5490bbfda8aSnia					}
5500bbfda8aSnia				}
5510bbfda8aSnia			}
5520bbfda8aSnia			icon->image = image;
5530bbfda8aSnia		}
5540bbfda8aSnia	}
5550bbfda8aSnia
5560bbfda8aSnia	/* if we still haven't got an icon, let's look in the Icon list
5570bbfda8aSnia	 * if ForceIcon is not set
5580bbfda8aSnia	 */
5590bbfda8aSnia	if(image == NULL && !Scr->ForceIcon) {
5600bbfda8aSnia		image = LookupIconNameOrClass(tmp_win, icon, &pattern);
5610bbfda8aSnia	}
5620bbfda8aSnia
5630bbfda8aSnia	/* if we still don't have an icon, assign the UnknownIcon */
5640bbfda8aSnia	if(image == NULL && Scr->UnknownImage != NULL) {
5650bbfda8aSnia		image = Scr->UnknownImage;
5660bbfda8aSnia		icon->match   = match_unknown_default;
5670bbfda8aSnia		icon->width   = image->width;
5680bbfda8aSnia		icon->height  = image->height;
5690bbfda8aSnia		icon->image   = image;
5700bbfda8aSnia	}
5710bbfda8aSnia
5720bbfda8aSnia	if(image == NULL) {
5730bbfda8aSnia		icon->height = 0;
5740bbfda8aSnia		icon->width  = 0;
5750bbfda8aSnia		valuemask    = 0;
5760bbfda8aSnia	}
5770bbfda8aSnia	else {
5780bbfda8aSnia		valuemask = CWBackPixmap;
5790bbfda8aSnia		attributes.background_pixmap = image->pixmap;
5800bbfda8aSnia	}
5810bbfda8aSnia
5820bbfda8aSnia	icon->border_width = Scr->IconBorderWidth;
5830bbfda8aSnia	if(Scr->NoIconTitlebar ||
5840bbfda8aSnia	                LookInNameList(Scr->NoIconTitle, tmp_win->icon_name) ||
5850bbfda8aSnia	                LookInList(Scr->NoIconTitle, tmp_win->name, &tmp_win->class)) {
5860bbfda8aSnia		icon->w_width  = icon->width;
5870bbfda8aSnia		icon->w_height = icon->height;
5880bbfda8aSnia		icon->x = 0;
5890bbfda8aSnia		icon->y = 0;
5900bbfda8aSnia		icon->has_title = false;
5910bbfda8aSnia	}
5920bbfda8aSnia	else {
5930bbfda8aSnia		XRectangle inc_rect;
5940bbfda8aSnia		XRectangle logical_rect;
5950bbfda8aSnia
5960bbfda8aSnia		XmbTextExtents(Scr->IconFont.font_set,
5970bbfda8aSnia		               tmp_win->icon_name, strlen(tmp_win->icon_name),
5980bbfda8aSnia		               &inc_rect, &logical_rect);
5990bbfda8aSnia		icon->w_width = logical_rect.width;
6000bbfda8aSnia
6010bbfda8aSnia		icon->w_width += 2 * (Scr->IconManagerShadowDepth + ICON_MGR_IBORDER);
6020bbfda8aSnia		if(icon->w_width > Scr->MaxIconTitleWidth) {
6030bbfda8aSnia			icon->w_width = Scr->MaxIconTitleWidth;
6040bbfda8aSnia		}
6050bbfda8aSnia		if(icon->w_width < icon->width) {
6060bbfda8aSnia			icon->x  = (icon->width - icon->w_width) / 2;
6070bbfda8aSnia			icon->x += Scr->IconManagerShadowDepth + ICON_MGR_IBORDER;
6080bbfda8aSnia			icon->w_width = icon->width;
6090bbfda8aSnia		}
6100bbfda8aSnia		else {
6110bbfda8aSnia			icon->x = Scr->IconManagerShadowDepth + ICON_MGR_IBORDER;
6120bbfda8aSnia		}
6130bbfda8aSnia		icon->y = icon->height + Scr->IconFont.height + Scr->IconManagerShadowDepth;
6140bbfda8aSnia		icon->w_height = icon->height + Scr->IconFont.height +
6150bbfda8aSnia		                 2 * (Scr->IconManagerShadowDepth + ICON_MGR_IBORDER);
6160bbfda8aSnia		icon->has_title = true;
6170bbfda8aSnia		if(icon->height) {
6180bbfda8aSnia			icon->border_width = 0;
6190bbfda8aSnia		}
6200bbfda8aSnia	}
6210bbfda8aSnia
6220bbfda8aSnia	event_mask = 0;
6230bbfda8aSnia	if(tmp_win->wmhints->flags & IconWindowHint) {
6240bbfda8aSnia		icon->w = tmp_win->wmhints->icon_window;
6250bbfda8aSnia		if(tmp_win->forced ||
6260bbfda8aSnia		                XGetGeometry(dpy, icon->w, &JunkRoot, &JunkX, &JunkY,
6270bbfda8aSnia		                             (unsigned int *)&icon->w_width, (unsigned int *)&icon->w_height,
6280bbfda8aSnia		                             &JunkBW, &JunkDepth) == 0) {
6290bbfda8aSnia			icon->w = None;
6300bbfda8aSnia			tmp_win->wmhints->flags &= ~IconWindowHint;
6310bbfda8aSnia		}
6320bbfda8aSnia		else {
6330bbfda8aSnia			image = NULL;
6340bbfda8aSnia			icon->w_not_ours = true;
6350bbfda8aSnia			icon->width  = icon->w_width;
6360bbfda8aSnia			icon->height = icon->w_height;
6370bbfda8aSnia			icon->image  = image;
6380bbfda8aSnia			icon->has_title = false;
6390bbfda8aSnia			event_mask = 0;
6400bbfda8aSnia		}
6410bbfda8aSnia	}
6420bbfda8aSnia	else {
6430bbfda8aSnia		icon->w = None;
6440bbfda8aSnia	}
6450bbfda8aSnia
6460bbfda8aSnia	if((image != NULL) &&
6470bbfda8aSnia	                image->mask != None &&
6480bbfda8aSnia	                !(tmp_win->wmhints->flags & IconWindowHint)) {
6490bbfda8aSnia		icon->border_width = 0;
6500bbfda8aSnia	}
6510bbfda8aSnia	if(icon->w == None) {
6520bbfda8aSnia		icon->w = XCreateSimpleWindow(dpy, Scr->Root,
6530bbfda8aSnia		                              0, 0,
6540bbfda8aSnia		                              icon->w_width, icon->w_height,
6550bbfda8aSnia		                              icon->border_width, icon->border, icon->iconc.back);
6560bbfda8aSnia		event_mask = ExposureMask;
6570bbfda8aSnia	}
6580bbfda8aSnia
6590bbfda8aSnia	if(Scr->AutoRaiseIcons || Scr->ShrinkIconTitles) {
6600bbfda8aSnia		event_mask |= EnterWindowMask | LeaveWindowMask;
6610bbfda8aSnia	}
6620bbfda8aSnia	event_mask |= KeyPressMask | ButtonPressMask | ButtonReleaseMask;
6630bbfda8aSnia
6640bbfda8aSnia	if(icon->w_not_ours) {
6650bbfda8aSnia		XWindowAttributes wattr;
6660bbfda8aSnia
6670bbfda8aSnia		XGetWindowAttributes(dpy, icon->w, &wattr);
6680bbfda8aSnia		if(wattr.all_event_masks & ButtonPressMask) {
6690bbfda8aSnia			event_mask &= ~ButtonPressMask;
6700bbfda8aSnia		}
6710bbfda8aSnia	}
6720bbfda8aSnia	XSelectInput(dpy, icon->w, event_mask);
6730bbfda8aSnia
6740bbfda8aSnia	if(icon->width == 0) {
6750bbfda8aSnia		icon->width = icon->w_width;
6760bbfda8aSnia	}
6770bbfda8aSnia	icon->bm_w = None;
6780bbfda8aSnia	if(image && !(tmp_win->wmhints->flags & IconWindowHint)) {
6790bbfda8aSnia		XRectangle rect;
6800bbfda8aSnia
6810bbfda8aSnia		x = GetIconOffset(icon);
6820bbfda8aSnia		icon->bm_w = XCreateWindow(dpy, icon->w, x, 0,
6830bbfda8aSnia		                           icon->width,
6840bbfda8aSnia		                           icon->height,
6850bbfda8aSnia		                           0, Scr->d_depth,
6860bbfda8aSnia		                           CopyFromParent,
6870bbfda8aSnia		                           Scr->d_visual, valuemask,
6880bbfda8aSnia		                           &attributes);
6890bbfda8aSnia		if(image->mask) {
6900bbfda8aSnia			XShapeCombineMask(dpy, icon->bm_w, ShapeBounding, 0, 0, image->mask, ShapeSet);
6910bbfda8aSnia			XShapeCombineMask(dpy, icon->w,    ShapeBounding, x, 0, image->mask, ShapeSet);
6920bbfda8aSnia		}
6930bbfda8aSnia		else if(icon->has_title) {
6940bbfda8aSnia			rect.x      = x;
6950bbfda8aSnia			rect.y      = 0;
6960bbfda8aSnia			rect.width  = icon->width;
6970bbfda8aSnia			rect.height = icon->height;
6980bbfda8aSnia			XShapeCombineRectangles(dpy, icon->w, ShapeBounding,
6990bbfda8aSnia			                        0, 0, &rect, 1, ShapeSet, 0);
7000bbfda8aSnia		}
7010bbfda8aSnia		if(icon->has_title) {
7020bbfda8aSnia			if(Scr->ShrinkIconTitles) {
7030bbfda8aSnia				rect.x      = x;
7040bbfda8aSnia				rect.y      = icon->height;
7050bbfda8aSnia				rect.width  = icon->width;
7060bbfda8aSnia				rect.height = icon->w_height - icon->height;
7070bbfda8aSnia				icon->title_shrunk = true;
7080bbfda8aSnia			}
7090bbfda8aSnia			else {
7100bbfda8aSnia				rect.x      = 0;
7110bbfda8aSnia				rect.y      = icon->height;
7120bbfda8aSnia				rect.width  = icon->w_width;
7130bbfda8aSnia				rect.height = icon->w_height - icon->height;
7140bbfda8aSnia				icon->title_shrunk = false;
7150bbfda8aSnia			}
7160bbfda8aSnia			XShapeCombineRectangles(dpy, icon->w, ShapeBounding,
7170bbfda8aSnia			                        0, 0, &rect, 1, ShapeUnion, 0);
7180bbfda8aSnia		}
7190bbfda8aSnia	}
7200bbfda8aSnia
7210bbfda8aSnia	if(pattern != NULL) {
7220bbfda8aSnia		AddToList(&tmp_win->iconslist, pattern, icon);
7230bbfda8aSnia	}
7240bbfda8aSnia
7250bbfda8aSnia	tmp_win->icon = icon;
7260bbfda8aSnia	/* I need to figure out where to put the icon window now, because
7270bbfda8aSnia	 * getting here means that I am going to make the icon visible
7280bbfda8aSnia	 */
7290bbfda8aSnia	final_x = final_y = 0;
7300bbfda8aSnia	if(tmp_win->wmhints->flags & IconPositionHint) {
7310bbfda8aSnia		final_x = tmp_win->wmhints->icon_x;
7320bbfda8aSnia		final_y = tmp_win->wmhints->icon_y;
7330bbfda8aSnia	}
7340bbfda8aSnia	else {
7350bbfda8aSnia		if(visible(tmp_win)) {
7360bbfda8aSnia			PlaceIcon(tmp_win, def_x, def_y, &final_x, &final_y);
7370bbfda8aSnia		}
7380bbfda8aSnia	}
7390bbfda8aSnia
7400bbfda8aSnia	if(visible(tmp_win) || (tmp_win->wmhints->flags & IconPositionHint)) {
7410bbfda8aSnia		if(final_x > Scr->rootw) {
7420bbfda8aSnia			final_x = Scr->rootw - icon->w_width - (2 * Scr->IconBorderWidth);
7430bbfda8aSnia		}
7440bbfda8aSnia		if(Scr->ShrinkIconTitles && icon->bm_w) {
7450bbfda8aSnia			if(final_x + (icon->w_width - icon->width) < 0) {
7460bbfda8aSnia				final_x = 0;
7470bbfda8aSnia			}
7480bbfda8aSnia		}
7490bbfda8aSnia		else {
7500bbfda8aSnia			if(final_x < 0) {
7510bbfda8aSnia				final_x = 0;
7520bbfda8aSnia			}
7530bbfda8aSnia		}
7540bbfda8aSnia		if(final_y > Scr->rooth)
7550bbfda8aSnia			final_y = Scr->rooth - icon->height -
7560bbfda8aSnia			          Scr->IconFont.height - 6 - (2 * Scr->IconBorderWidth);
7570bbfda8aSnia		if(final_y < 0) {
7580bbfda8aSnia			final_y = 0;
7590bbfda8aSnia		}
7600bbfda8aSnia
7610bbfda8aSnia		XMoveWindow(dpy, icon->w, final_x, final_y);
7620bbfda8aSnia		icon->w_x = final_x;
7630bbfda8aSnia		icon->w_y = final_y;
7640bbfda8aSnia	}
7650bbfda8aSnia	tmp_win->iconified = true;
7660bbfda8aSnia	OtpAdd(tmp_win, IconWin);
7670bbfda8aSnia
7680bbfda8aSnia	XMapSubwindows(dpy, icon->w);
7690bbfda8aSnia	XSaveContext(dpy, icon->w, TwmContext, (XPointer)tmp_win);
7700bbfda8aSnia	XSaveContext(dpy, icon->w, ScreenContext, (XPointer)Scr);
7710bbfda8aSnia	XDefineCursor(dpy, icon->w, Scr->IconCursor);
7720bbfda8aSnia	MaybeAnimate = true;
773645f5050Syouri}
774645f5050Syouri
7750bbfda8aSnia
7760bbfda8aSnia/*
7770bbfda8aSnia * Delete TwmWindow.iconslist.
7780bbfda8aSnia * Call it before deleting TwmWindow.icon, since we need to check
7790bbfda8aSnia * that we're not deleting that Icon.
7800bbfda8aSnia */
7810bbfda8aSniavoid
7820bbfda8aSniaDeleteIconsList(TwmWindow *tmp_win)
783645f5050Syouri{
7840bbfda8aSnia	/*
7850bbfda8aSnia	 * Only the list itself needs to be freed, since the pointers it
7860bbfda8aSnia	 * contains point into various lists that belong to Scr.
7870bbfda8aSnia	 *
7880bbfda8aSnia	 * Rhialto: Hmmmm not quite sure about that! CreateIconWindow() above
7890bbfda8aSnia	 * always allocates a struct Icon, and doesn't attach it to Scr...
7900bbfda8aSnia	 * It is probably correct for the Image pointers inside those Icons though.
7910bbfda8aSnia	 */
7920bbfda8aSnia	name_list *nptr;
7930bbfda8aSnia	name_list *next;
7940bbfda8aSnia
7950bbfda8aSnia	for(nptr = tmp_win->iconslist; nptr != NULL;) {
7960bbfda8aSnia		next = nptr->next;
7970bbfda8aSnia		Icon *icon = (Icon *)nptr->ptr;
7980bbfda8aSnia		if(icon != tmp_win->icon) {
7990bbfda8aSnia			DeleteIcon(icon);
8000bbfda8aSnia		}
8010bbfda8aSnia		free(nptr->name);
8020bbfda8aSnia		free(nptr);
8030bbfda8aSnia		nptr = next;
8040bbfda8aSnia	}
8050bbfda8aSnia	tmp_win->iconslist = NULL;
806645f5050Syouri}
807645f5050Syouri
8080bbfda8aSnia
8090bbfda8aSnia/*
8100bbfda8aSnia * Delete a single Icon.  Called iteratively from DeleteIconList(), and
8110bbfda8aSnia * directly during window destruction.
8120bbfda8aSnia */
8130bbfda8aSniavoid
8140bbfda8aSniaDeleteIcon(Icon *icon)
815645f5050Syouri{
8160bbfda8aSnia	if(icon->w && !icon->w_not_ours) {
8170bbfda8aSnia		XDestroyWindow(dpy, icon->w);
8180bbfda8aSnia	}
8190bbfda8aSnia	ReleaseIconImage(icon);
8200bbfda8aSnia	free(icon);
821645f5050Syouri}
822645f5050Syouri
823645f5050Syouri
8240bbfda8aSnia/*
8250bbfda8aSnia * Delete the Image from an icon, if it is not a shared one.  match_list
8260bbfda8aSnia * ands match_unknown_default need not be freed.
8270bbfda8aSnia *
8280bbfda8aSnia * Formerly ReleaseImage()
8290bbfda8aSnia */
8300bbfda8aSniavoid
8310bbfda8aSniaReleaseIconImage(Icon *icon)
8320bbfda8aSnia{
8330bbfda8aSnia	if(icon->match == match_icon_pixmap_hint ||
8340bbfda8aSnia	                icon->match == match_net_wm_icon) {
8350bbfda8aSnia		FreeImage(icon->image);
8360bbfda8aSnia	}
837645f5050Syouri}
8380bbfda8aSnia
8390bbfda8aSnia
8400bbfda8aSnia
8410bbfda8aSnia
8420bbfda8aSnia/*
8430bbfda8aSnia ****************************************************************
8440bbfda8aSnia *
8450bbfda8aSnia * Bringing an icon up or down.
8460bbfda8aSnia *
8470bbfda8aSnia ****************************************************************
8480bbfda8aSnia */
8490bbfda8aSnia
8500bbfda8aSnia
8510bbfda8aSnia/*
8520bbfda8aSnia * Show up an icon.  Note that neither IconUp nor IconDown actually map
8530bbfda8aSnia * or unmap the icon window; that's handled by the callers.  These
8540bbfda8aSnia * functions limit themselves to figuring out where it should be, moving
8550bbfda8aSnia * it (still unmapped) there, and linking/unlinking it from the iconentry
8560bbfda8aSnia * lists.
8570bbfda8aSnia */
8580bbfda8aSniavoid
8590bbfda8aSniaIconUp(TwmWindow *tmp_win)
860645f5050Syouri{
8610bbfda8aSnia	int         x, y;
8620bbfda8aSnia	int         defx, defy;
8630bbfda8aSnia
8640bbfda8aSnia	/*
8650bbfda8aSnia	 * If the client specified a particular location, let's use it (this might
8660bbfda8aSnia	 * want to be an option at some point).  Otherwise, try to fit within the
8670bbfda8aSnia	 * icon region.
8680bbfda8aSnia	 */
8690bbfda8aSnia	if(tmp_win->wmhints->flags & IconPositionHint) {
8700bbfda8aSnia		return;
8710bbfda8aSnia	}
8720bbfda8aSnia
8730bbfda8aSnia	if(tmp_win->icon_moved) {
8740bbfda8aSnia		struct IconRegion *ir;
8750bbfda8aSnia		unsigned int iww, iwh;
8760bbfda8aSnia
8770bbfda8aSnia		if(!XGetGeometry(dpy, tmp_win->icon->w, &JunkRoot, &defx, &defy,
8780bbfda8aSnia		                 &iww, &iwh, &JunkBW, &JunkDepth)) {
8790bbfda8aSnia			return;
8800bbfda8aSnia		}
8810bbfda8aSnia
8820bbfda8aSnia		x = defx + ((int) iww) / 2;
8830bbfda8aSnia		y = defy + ((int) iwh) / 2;
8840bbfda8aSnia
8850bbfda8aSnia		for(ir = Scr->FirstRegion; ir; ir = ir->next) {
8860bbfda8aSnia			if(x >= ir->x && x < (ir->x + ir->w) &&
8870bbfda8aSnia			                y >= ir->y && y < (ir->y + ir->h)) {
8880bbfda8aSnia				break;
8890bbfda8aSnia			}
8900bbfda8aSnia		}
8910bbfda8aSnia		if(!ir) {
8920bbfda8aSnia			return;        /* outside icon regions, leave alone */
8930bbfda8aSnia		}
8940bbfda8aSnia	}
8950bbfda8aSnia
8960bbfda8aSnia	defx = -100;
8970bbfda8aSnia	defy = -100;
8980bbfda8aSnia	PlaceIcon(tmp_win, defx, defy, &x, &y);
8990bbfda8aSnia	if(x != defx || y != defy) {
9000bbfda8aSnia		XMoveWindow(dpy, tmp_win->icon->w, x, y);
9010bbfda8aSnia		tmp_win->icon->w_x = x;
9020bbfda8aSnia		tmp_win->icon->w_y = y;
9030bbfda8aSnia		tmp_win->icon_moved = false;    /* since we've restored it */
9040bbfda8aSnia	}
9050bbfda8aSnia	MaybeAnimate = true;
9060bbfda8aSnia	return;
907645f5050Syouri}
908645f5050Syouri
9090bbfda8aSnia
9100bbfda8aSnia/*
9110bbfda8aSnia * Remove an icon from its displayed IconEntry.  x-ref comment on
9120bbfda8aSnia * IconUp().
9130bbfda8aSnia */
9140bbfda8aSniavoid
9150bbfda8aSniaIconDown(TwmWindow *tmp_win)
916645f5050Syouri{
9170bbfda8aSnia	IconEntry   *ie, *ip, *in;
9180bbfda8aSnia	IconRegion  *ir;
9190bbfda8aSnia
9200bbfda8aSnia	ie = FindIconEntry(tmp_win, &ir);
9210bbfda8aSnia	if(ie) {
9220bbfda8aSnia		ie->twm_win = NULL;
9230bbfda8aSnia		ie->used = false;
9240bbfda8aSnia		ip = prevIconEntry(ie, ir);
9250bbfda8aSnia		in = ie->next;
9260bbfda8aSnia		for(;;) {
9270bbfda8aSnia			if(ip && ip->used == false &&
9280bbfda8aSnia			                ((ip->x == ie->x && ip->w == ie->w) ||
9290bbfda8aSnia			                 (ip->y == ie->y && ip->h == ie->h))) {
9300bbfda8aSnia				ip->next = ie->next;
9310bbfda8aSnia				mergeEntries(ie, ip);
9320bbfda8aSnia				free(ie);
9330bbfda8aSnia				ie = ip;
9340bbfda8aSnia				ip = prevIconEntry(ip, ir);
9350bbfda8aSnia			}
9360bbfda8aSnia			else if(in && in->used == false &&
9370bbfda8aSnia			                ((in->x == ie->x && in->w == ie->w) ||
9380bbfda8aSnia			                 (in->y == ie->y && in->h == ie->h))) {
9390bbfda8aSnia				ie->next = in->next;
9400bbfda8aSnia				mergeEntries(in, ie);
9410bbfda8aSnia				free(in);
9420bbfda8aSnia				in = ie->next;
9430bbfda8aSnia			}
9440bbfda8aSnia			else {
9450bbfda8aSnia				break;
9460bbfda8aSnia			}
9470bbfda8aSnia		}
9480bbfda8aSnia	}
9490bbfda8aSnia}
950645f5050Syouri
9510bbfda8aSnia
9520bbfda8aSnia
9530bbfda8aSnia
9540bbfda8aSnia/*
9550bbfda8aSnia ****************************************************************
9560bbfda8aSnia *
9570bbfda8aSnia * Funcs related to drawing the icon.
9580bbfda8aSnia *
9590bbfda8aSnia ****************************************************************
9600bbfda8aSnia */
9610bbfda8aSnia
9620bbfda8aSnia
9630bbfda8aSnia/*
9640bbfda8aSnia * Slightly misnamed: draws the text label under an icon.
9650bbfda8aSnia */
9660bbfda8aSniavoid
9670bbfda8aSniaPaintIcon(TwmWindow *tmp_win)
9680bbfda8aSnia{
9690bbfda8aSnia	int         width, twidth, mwidth, len, x;
9700bbfda8aSnia	Icon        *icon;
9710bbfda8aSnia	XRectangle ink_rect;
972645f5050Syouri	XRectangle logical_rect;
973645f5050Syouri
9740bbfda8aSnia	if(!tmp_win || !tmp_win->icon) {
9750bbfda8aSnia		return;
9760bbfda8aSnia	}
9770bbfda8aSnia	icon = tmp_win->icon;
9780bbfda8aSnia	if(!icon->has_title) {
9790bbfda8aSnia		return;
9800bbfda8aSnia	}
9810bbfda8aSnia
9820bbfda8aSnia	x     = 0;
9830bbfda8aSnia	width = icon->w_width;
9840bbfda8aSnia	if(Scr->ShrinkIconTitles && icon->title_shrunk) {
9850bbfda8aSnia		x     = GetIconOffset(icon);
9860bbfda8aSnia		width = icon->width;
9870bbfda8aSnia	}
9880bbfda8aSnia	len    = strlen(tmp_win->icon_name);
989645f5050Syouri	XmbTextExtents(Scr->IconFont.font_set,
9900bbfda8aSnia	               tmp_win->icon_name, len,
9910bbfda8aSnia	               &ink_rect, &logical_rect);
9920bbfda8aSnia	twidth = logical_rect.width;
9930bbfda8aSnia	mwidth = width - 2 * (Scr->IconManagerShadowDepth + ICON_MGR_IBORDER);
9940bbfda8aSnia	if(Scr->use3Diconmanagers) {
9950bbfda8aSnia		Draw3DBorder(icon->w, x, icon->height, width,
9960bbfda8aSnia		             Scr->IconFont.height +
9970bbfda8aSnia		             2 * (Scr->IconManagerShadowDepth + ICON_MGR_IBORDER),
9980bbfda8aSnia		             Scr->IconManagerShadowDepth, icon->iconc, off, false, false);
9990bbfda8aSnia	}
10000bbfda8aSnia	while((len > 0) && (twidth > mwidth)) {
10010bbfda8aSnia		len--;
10020bbfda8aSnia		XmbTextExtents(Scr->IconFont.font_set,
10030bbfda8aSnia		               tmp_win->icon_name, len,
10040bbfda8aSnia		               &ink_rect, &logical_rect);
10050bbfda8aSnia		twidth = logical_rect.width;
10060bbfda8aSnia	}
10070bbfda8aSnia	FB(icon->iconc.fore, icon->iconc.back);
10080bbfda8aSnia	XmbDrawString(dpy, icon->w, Scr->IconFont.font_set, Scr->NormalGC,
10090bbfda8aSnia	              x + ((mwidth - twidth) / 2) +
10100bbfda8aSnia	              Scr->IconManagerShadowDepth + ICON_MGR_IBORDER,
10110bbfda8aSnia	              icon->y, tmp_win->icon_name, len);
1012645f5050Syouri}
1013645f5050Syouri
1014645f5050Syouri
10150bbfda8aSnia/*
10160bbfda8aSnia * Handling for ShrinkIconTitles; when pointer is away from them, shrink
10170bbfda8aSnia * the titles down to the width of the image, and expand back out when it
10180bbfda8aSnia * enters.
10190bbfda8aSnia */
10200bbfda8aSniavoid
10210bbfda8aSniaShrinkIconTitle(TwmWindow *tmp_win)
1022645f5050Syouri{
10230bbfda8aSnia	Icon        *icon;
10240bbfda8aSnia	XRectangle  rect;
10250bbfda8aSnia
10260bbfda8aSnia	if(!tmp_win || !tmp_win->icon) {
10270bbfda8aSnia		return;
10280bbfda8aSnia	}
10290bbfda8aSnia	icon = tmp_win->icon;
10300bbfda8aSnia	if(!icon->has_title) {
10310bbfda8aSnia		return;
10320bbfda8aSnia	}
10330bbfda8aSnia	if(icon->w_width == icon->width) {
10340bbfda8aSnia		return;
10350bbfda8aSnia	}
10360bbfda8aSnia	if(icon->height  == 0) {
10370bbfda8aSnia		return;
10380bbfda8aSnia	}
10390bbfda8aSnia
10400bbfda8aSnia	rect.x      = GetIconOffset(icon);
10410bbfda8aSnia	rect.y      = 0;
10420bbfda8aSnia	rect.width  = icon->width;
10430bbfda8aSnia	rect.height = icon->w_height;
10440bbfda8aSnia	XShapeCombineRectangles(dpy, icon->w, ShapeBounding, 0, 0, &rect, 1,
10450bbfda8aSnia	                        ShapeIntersect, 0);
10460bbfda8aSnia	icon->title_shrunk = true;
10470bbfda8aSnia	XClearArea(dpy, icon->w, 0, icon->height, icon->w_width,
10480bbfda8aSnia	           icon->w_height - icon->height, True);
1049645f5050Syouri}
1050645f5050Syouri
10510bbfda8aSnia
10520bbfda8aSniavoid
10530bbfda8aSniaExpandIconTitle(TwmWindow *tmp_win)
1054645f5050Syouri{
10550bbfda8aSnia	Icon        *icon;
10560bbfda8aSnia	XRectangle  rect;
10570bbfda8aSnia
10580bbfda8aSnia	if(!tmp_win || !tmp_win->icon) {
10590bbfda8aSnia		return;
10600bbfda8aSnia	}
10610bbfda8aSnia	icon = tmp_win->icon;
10620bbfda8aSnia	if(!icon->has_title) {
10630bbfda8aSnia		return;
10640bbfda8aSnia	}
10650bbfda8aSnia	if(icon->w_width == icon->width) {
10660bbfda8aSnia		return;
10670bbfda8aSnia	}
10680bbfda8aSnia	if(icon->height  == 0) {
10690bbfda8aSnia		return;
10700bbfda8aSnia	}
10710bbfda8aSnia
10720bbfda8aSnia	rect.x      = 0;
10730bbfda8aSnia	rect.y      = icon->height;
10740bbfda8aSnia	rect.width  = icon->w_width;
10750bbfda8aSnia	rect.height = icon->w_height - icon->height;
10760bbfda8aSnia	XShapeCombineRectangles(dpy, icon->w, ShapeBounding, 0, 0, &rect, 1, ShapeUnion,
10770bbfda8aSnia	                        0);
10780bbfda8aSnia	icon->title_shrunk = false;
10790bbfda8aSnia	XClearArea(dpy, icon->w, 0, icon->height, icon->w_width,
10800bbfda8aSnia	           icon->w_height - icon->height, True);
1081645f5050Syouri}
1082645f5050Syouri
10830bbfda8aSnia
10840bbfda8aSnia/*
10850bbfda8aSnia * Setup X Shape'ing around icons and their titles.
10860bbfda8aSnia *
10870bbfda8aSnia * XXX should this be checking HasShape?  It seems to be called
10880bbfda8aSnia * unconditionally...
10890bbfda8aSnia */
10900bbfda8aSniastatic void
10910bbfda8aSniaReshapeIcon(Icon *icon)
1092645f5050Syouri{
10930bbfda8aSnia	int x;
10940bbfda8aSnia	XRectangle  rect;
1095645f5050Syouri
10960bbfda8aSnia	if(!icon) {
10970bbfda8aSnia		return;
10980bbfda8aSnia	}
10990bbfda8aSnia	x = GetIconOffset(icon);
11000bbfda8aSnia	XMoveWindow(dpy, icon->bm_w, x, 0);
1101645f5050Syouri
11020bbfda8aSnia	if(icon->image && icon->image->mask) {
11030bbfda8aSnia		XShapeCombineMask(dpy, icon->w, ShapeBounding, x, 0, icon->image->mask,
11040bbfda8aSnia		                  ShapeSet);
11050bbfda8aSnia	}
11060bbfda8aSnia	else {
11070bbfda8aSnia		rect.x      = x;
11080bbfda8aSnia		rect.y      = 0;
11090bbfda8aSnia		rect.width  = icon->width;
11100bbfda8aSnia		rect.height = icon->height;
11110bbfda8aSnia		XShapeCombineRectangles(dpy, icon->w, ShapeBounding, 0, 0, &rect, 1, ShapeSet,
11120bbfda8aSnia		                        0);
11130bbfda8aSnia	}
1114645f5050Syouri	rect.x      = x;
11150bbfda8aSnia	rect.y      = icon->height;
1116645f5050Syouri	rect.width  = icon->width;
11170bbfda8aSnia	rect.height = icon->w_height - icon->height;
11180bbfda8aSnia	XShapeCombineRectangles(dpy, icon->w, ShapeBounding, 0, 0, &rect, 1, ShapeUnion,
11190bbfda8aSnia	                        0);
11200bbfda8aSnia}
11210bbfda8aSnia
11220bbfda8aSnia
11230bbfda8aSnia/*
11240bbfda8aSnia * Figure horizontal positioning/offset for the icon image within its
11250bbfda8aSnia * window.
11260bbfda8aSnia */
11270bbfda8aSniaint
11280bbfda8aSniaGetIconOffset(Icon *icon)
11290bbfda8aSnia{
11300bbfda8aSnia	TitleJust justif;
11310bbfda8aSnia
11320bbfda8aSnia	if(!icon) {
11330bbfda8aSnia		return 0;
11340bbfda8aSnia	}
11350bbfda8aSnia
11360bbfda8aSnia	justif = icon->ir ? icon->ir->TitleJustification : Scr->IconJustification;
11370bbfda8aSnia	switch(justif) {
11380bbfda8aSnia		case TJ_LEFT:
11390bbfda8aSnia			return 0;
11400bbfda8aSnia
11410bbfda8aSnia		case TJ_CENTER:
11420bbfda8aSnia			return ((icon->w_width - icon->width) / 2);
11430bbfda8aSnia
11440bbfda8aSnia		case TJ_RIGHT:
11450bbfda8aSnia			return (icon->w_width - icon->width);
11460bbfda8aSnia
11470bbfda8aSnia		default:
11480bbfda8aSnia			/* Can't happen? */
11490bbfda8aSnia			fprintf(stderr, "%s(): Invalid TitleJustification %d\n",
11500bbfda8aSnia			        __func__, justif);
11510bbfda8aSnia			return 0;
11520bbfda8aSnia	}
1153645f5050Syouri}
1154645f5050Syouri
11550bbfda8aSnia
11560bbfda8aSnia/*
11570bbfda8aSnia * [Re-]lookup the image for an icon and [re-]layout it.
11580bbfda8aSnia */
11590bbfda8aSniavoid
11600bbfda8aSniaRedoIcon(TwmWindow *win)
1161645f5050Syouri{
11620bbfda8aSnia	Icon *icon, *old_icon;
11630bbfda8aSnia	char *pattern;
11640bbfda8aSnia
11650bbfda8aSnia	old_icon = win->icon;
11660bbfda8aSnia
11670bbfda8aSnia	if(old_icon && (old_icon->w_not_ours || old_icon->match != match_list)) {
11680bbfda8aSnia		RedoIconName(win);
11690bbfda8aSnia		return;
11700bbfda8aSnia	}
11710bbfda8aSnia	icon = NULL;
11720bbfda8aSnia	if((pattern = LookPatternInNameList(Scr->IconNames, win->icon_name))) {
11730bbfda8aSnia		icon = LookInNameList(win->iconslist, pattern);
11740bbfda8aSnia	}
11750bbfda8aSnia	else if((pattern = LookPatternInNameList(Scr->IconNames, win->name))) {
11760bbfda8aSnia		icon = LookInNameList(win->iconslist, pattern);
11770bbfda8aSnia	}
11780bbfda8aSnia	else if((pattern = LookPatternInList(Scr->IconNames, win->name,
11790bbfda8aSnia	                                     &win->class))) {
11800bbfda8aSnia		icon = LookInNameList(win->iconslist, pattern);
11810bbfda8aSnia	}
11820bbfda8aSnia	if(pattern == NULL) {
11830bbfda8aSnia		RedoIconName(win);
11840bbfda8aSnia		return;
11850bbfda8aSnia	}
11860bbfda8aSnia	if(icon != NULL) {
11870bbfda8aSnia		if(old_icon == icon) {
11880bbfda8aSnia			RedoIconName(win);
11890bbfda8aSnia			return;
11900bbfda8aSnia		}
11910bbfda8aSnia		if(win->icon_on && visible(win)) {
11920bbfda8aSnia			IconDown(win);
11930bbfda8aSnia			if(old_icon && old_icon->w) {
11940bbfda8aSnia				XUnmapWindow(dpy, old_icon->w);
11950bbfda8aSnia			}
11960bbfda8aSnia			win->icon = icon;
11970bbfda8aSnia			OtpReassignIcon(win, old_icon);
11980bbfda8aSnia			IconUp(win);
11990bbfda8aSnia			OtpRaise(win, IconWin);
12000bbfda8aSnia			XMapWindow(dpy, win->icon->w);
12010bbfda8aSnia		}
12020bbfda8aSnia		else {
12030bbfda8aSnia			win->icon = icon;
12040bbfda8aSnia			OtpReassignIcon(win, old_icon);
12050bbfda8aSnia		}
12060bbfda8aSnia		RedoIconName(win);
12070bbfda8aSnia	}
12080bbfda8aSnia	else {
12090bbfda8aSnia		if(win->icon_on && visible(win)) {
12100bbfda8aSnia			IconDown(win);
12110bbfda8aSnia			if(old_icon && old_icon->w) {
12120bbfda8aSnia				XUnmapWindow(dpy, old_icon->w);
12130bbfda8aSnia			}
12140bbfda8aSnia			/*
12150bbfda8aSnia			 * If the icon name/class was found on one of the above lists,
12160bbfda8aSnia			 * the call to CreateIconWindow() will find it again there
12170bbfda8aSnia			 * and keep track of it on win->iconslist for eventual
12180bbfda8aSnia			 * deallocation. (It is now checked that the current struct
12190bbfda8aSnia			 * Icon is also already on that list)
12200bbfda8aSnia			 */
12210bbfda8aSnia			OtpFreeIcon(win);
12220bbfda8aSnia			bool saveForceIcon = Scr->ForceIcon;
12230bbfda8aSnia			Scr->ForceIcon = true;
12240bbfda8aSnia			CreateIconWindow(win, -100, -100);
12250bbfda8aSnia			Scr->ForceIcon = saveForceIcon;
12260bbfda8aSnia			OtpRaise(win, IconWin);
12270bbfda8aSnia			XMapWindow(dpy, win->icon->w);
12280bbfda8aSnia		}
12290bbfda8aSnia		else {
12300bbfda8aSnia			OtpFreeIcon(win);
12310bbfda8aSnia			win->icon = NULL;
12320bbfda8aSnia			WMapUpdateIconName(win);
12330bbfda8aSnia		}
12340bbfda8aSnia		RedoIconName(win);
12350bbfda8aSnia	}
12360bbfda8aSnia}
12370bbfda8aSnia
12380bbfda8aSnia
12390bbfda8aSnia/*
12400bbfda8aSnia * Resize the icon window, and reposition the image and name within it.
12410bbfda8aSnia * (a lot of the actual repositioning gets done during the later expose).
12420bbfda8aSnia */
12430bbfda8aSniavoid
12440bbfda8aSniaRedoIconName(TwmWindow *win)
12450bbfda8aSnia{
12460bbfda8aSnia	int x;
12470bbfda8aSnia	XRectangle ink_rect;
12480bbfda8aSnia	XRectangle logical_rect;
12490bbfda8aSnia
12500bbfda8aSnia	if(Scr->NoIconTitlebar ||
12510bbfda8aSnia	                LookInNameList(Scr->NoIconTitle, win->icon_name) ||
12520bbfda8aSnia	                LookInList(Scr->NoIconTitle, win->name, &win->class)) {
12530bbfda8aSnia		WMapUpdateIconName(win);
12540bbfda8aSnia		return;
12550bbfda8aSnia	}
12560bbfda8aSnia	if(win->iconmanagerlist) {
12570bbfda8aSnia		/* let the expose event cause the repaint */
12580bbfda8aSnia		XClearArea(dpy, win->iconmanagerlist->w, 0, 0, 0, 0, True);
12590bbfda8aSnia
12600bbfda8aSnia		if(Scr->SortIconMgr) {
12610bbfda8aSnia			SortIconManager(win->iconmanagerlist->iconmgr);
12620bbfda8aSnia		}
12630bbfda8aSnia	}
12640bbfda8aSnia
12650bbfda8aSnia	if(!win->icon  || !win->icon->w) {
12660bbfda8aSnia		WMapUpdateIconName(win);
12670bbfda8aSnia		return;
12680bbfda8aSnia	}
1269645f5050Syouri
12700bbfda8aSnia	if(win->icon->w_not_ours) {
12710bbfda8aSnia		WMapUpdateIconName(win);
12720bbfda8aSnia		return;
12730bbfda8aSnia	}
1274645f5050Syouri
12750bbfda8aSnia	XmbTextExtents(Scr->IconFont.font_set,
12760bbfda8aSnia	               win->icon_name, strlen(win->icon_name),
12770bbfda8aSnia	               &ink_rect, &logical_rect);
12780bbfda8aSnia	win->icon->w_width = logical_rect.width;
12790bbfda8aSnia	win->icon->w_width += 2 * (Scr->IconManagerShadowDepth + ICON_MGR_IBORDER);
12800bbfda8aSnia	if(win->icon->w_width > Scr->MaxIconTitleWidth) {
12810bbfda8aSnia		win->icon->w_width = Scr->MaxIconTitleWidth;
12820bbfda8aSnia	}
1283645f5050Syouri
12840bbfda8aSnia	if(win->icon->w_width < win->icon->width) {
12850bbfda8aSnia		win->icon->x = (win->icon->width - win->icon->w_width) / 2;
12860bbfda8aSnia		win->icon->x += Scr->IconManagerShadowDepth + ICON_MGR_IBORDER;
12870bbfda8aSnia		win->icon->w_width = win->icon->width;
12880bbfda8aSnia	}
12890bbfda8aSnia	else {
12900bbfda8aSnia		win->icon->x = Scr->IconManagerShadowDepth + ICON_MGR_IBORDER;
12910bbfda8aSnia	}
1292645f5050Syouri
12930bbfda8aSnia	x = GetIconOffset(win->icon);
12940bbfda8aSnia	win->icon->y = win->icon->height + Scr->IconFont.height +
12950bbfda8aSnia	               Scr->IconManagerShadowDepth;
12960bbfda8aSnia	win->icon->w_height = win->icon->height + Scr->IconFont.height +
12970bbfda8aSnia	                      2 * (Scr->IconManagerShadowDepth + ICON_MGR_IBORDER);
12980bbfda8aSnia
12990bbfda8aSnia	XResizeWindow(dpy, win->icon->w, win->icon->w_width,
13000bbfda8aSnia	              win->icon->w_height);
13010bbfda8aSnia	if(win->icon->bm_w) {
13020bbfda8aSnia		XRectangle rect;
13030bbfda8aSnia
13040bbfda8aSnia		XMoveWindow(dpy, win->icon->bm_w, x, 0);
13050bbfda8aSnia		XMapWindow(dpy, win->icon->bm_w);
13060bbfda8aSnia		if(win->icon->image && win->icon->image->mask) {
13070bbfda8aSnia			XShapeCombineMask(dpy, win->icon->bm_w, ShapeBounding, 0, 0,
13080bbfda8aSnia			                  win->icon->image->mask, ShapeSet);
13090bbfda8aSnia			XShapeCombineMask(dpy, win->icon->w, ShapeBounding, x, 0,
13100bbfda8aSnia			                  win->icon->image->mask, ShapeSet);
13110bbfda8aSnia		}
13120bbfda8aSnia		else if(win->icon->has_title) {
13130bbfda8aSnia			rect.x      = x;
13140bbfda8aSnia			rect.y      = 0;
13150bbfda8aSnia			rect.width  = win->icon->width;
13160bbfda8aSnia			rect.height = win->icon->height;
13170bbfda8aSnia			XShapeCombineRectangles(dpy, win->icon->w, ShapeBounding,
13180bbfda8aSnia			                        0, 0, &rect, 1, ShapeSet, 0);
13190bbfda8aSnia		}
13200bbfda8aSnia		if(win->icon->has_title) {
13210bbfda8aSnia			if(Scr->ShrinkIconTitles && win->icon->title_shrunk) {
13220bbfda8aSnia				rect.x      = x;
13230bbfda8aSnia				rect.y      = win->icon->height;
13240bbfda8aSnia				rect.width  = win->icon->width;
13250bbfda8aSnia				rect.height = win->icon->w_height - win->icon->height;
13260bbfda8aSnia			}
13270bbfda8aSnia			else {
13280bbfda8aSnia				rect.x      = 0;
13290bbfda8aSnia				rect.y      = win->icon->height;
13300bbfda8aSnia				rect.width  = win->icon->w_width;
13310bbfda8aSnia				rect.height = win->icon->w_height - win->icon->height;
13320bbfda8aSnia			}
13330bbfda8aSnia			XShapeCombineRectangles(dpy,  win->icon->w, ShapeBounding, 0,
13340bbfda8aSnia			                        0, &rect, 1, ShapeUnion, 0);
13350bbfda8aSnia		}
13360bbfda8aSnia	}
13370bbfda8aSnia	if(Scr->ShrinkIconTitles &&
13380bbfda8aSnia	                win->icon->title_shrunk &&
13390bbfda8aSnia	                win->icon_on && (visible(win))) {
13400bbfda8aSnia		IconDown(win);
13410bbfda8aSnia		IconUp(win);
13420bbfda8aSnia	}
13430bbfda8aSnia	if(win->isicon) {
13440bbfda8aSnia		XClearArea(dpy, win->icon->w, 0, 0, 0, 0, True);
13450bbfda8aSnia	}
1346645f5050Syouri
13470bbfda8aSnia	WMapUpdateIconName(win);
1348645f5050Syouri}
1349645f5050Syouri
13500bbfda8aSnia
13510bbfda8aSnia
13520bbfda8aSnia
13530bbfda8aSnia/*
13540bbfda8aSnia ****************************************************************
13550bbfda8aSnia *
13560bbfda8aSnia * Misc internal utils.
13570bbfda8aSnia *
13580bbfda8aSnia ****************************************************************
13590bbfda8aSnia */
13600bbfda8aSnia
13610bbfda8aSnia
13620bbfda8aSnia/*
13630bbfda8aSnia * What it says on the tin.
13640bbfda8aSnia */
13650bbfda8aSniastatic int
13660bbfda8aSniaroundUp(int v, int multiple)
1367645f5050Syouri{
13680bbfda8aSnia	return ((v + multiple - 1) / multiple) * multiple;
1369645f5050Syouri}
1370645f5050Syouri
13710bbfda8aSnia
13720bbfda8aSnia/*
13730bbfda8aSnia * Find the image set in Icons{} for a TwmWindow if possible.  Return the
13740bbfda8aSnia * image, record its provenance inside *icon, and pass back what pattern
13750bbfda8aSnia * it matched in **pattern.
13760bbfda8aSnia */
13770bbfda8aSniastatic Image *
13780bbfda8aSniaLookupIconNameOrClass(TwmWindow *tmp_win, Icon *icon, char **pattern)
13790bbfda8aSnia{
13800bbfda8aSnia	char *icon_name = NULL;
13810bbfda8aSnia	Image *image;
13820bbfda8aSnia	Matchtype matched = match_none;
13830bbfda8aSnia
13840bbfda8aSnia	icon_name = LookInNameList(Scr->IconNames, tmp_win->icon_name);
13850bbfda8aSnia	if(icon_name != NULL) {
13860bbfda8aSnia		*pattern = LookPatternInNameList(Scr->IconNames, tmp_win->icon_name);
13870bbfda8aSnia		matched = match_list;
13880bbfda8aSnia	}
13890bbfda8aSnia
13900bbfda8aSnia	if(matched == match_none) {
13910bbfda8aSnia		icon_name = LookInNameList(Scr->IconNames, tmp_win->name);
13920bbfda8aSnia		if(icon_name != NULL) {
13930bbfda8aSnia			*pattern = LookPatternInNameList(Scr->IconNames, tmp_win->name);
13940bbfda8aSnia			matched = match_list;
13950bbfda8aSnia		}
13960bbfda8aSnia	}
13970bbfda8aSnia
13980bbfda8aSnia	if(matched == match_none) {
13990bbfda8aSnia		icon_name = LookInList(Scr->IconNames, tmp_win->name, &tmp_win->class);
14000bbfda8aSnia		if(icon_name != NULL) {
14010bbfda8aSnia			*pattern = LookPatternInList(Scr->IconNames, tmp_win->name,
14020bbfda8aSnia			                             &tmp_win->class);
14030bbfda8aSnia			matched = match_list;
14040bbfda8aSnia		}
14050bbfda8aSnia	}
14060bbfda8aSnia
14070bbfda8aSnia	if((image  = GetImage(icon_name, icon->iconc)) != NULL) {
14080bbfda8aSnia		icon->match  = matched;
14090bbfda8aSnia		icon->image  = image;
14100bbfda8aSnia		icon->width  = image->width;
14110bbfda8aSnia		icon->height = image->height;
14120bbfda8aSnia		tmp_win->forced = true;
14130bbfda8aSnia	}
14140bbfda8aSnia	else {
14150bbfda8aSnia		icon->match = match_none;
14160bbfda8aSnia		*pattern = NULL;
14170bbfda8aSnia	}
14180bbfda8aSnia
14190bbfda8aSnia	return image;
14200bbfda8aSnia}
1421