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