Home | History | Annotate | Line # | Download | only in dist
      1 /*
      2  * Copyright 1989 Massachusetts Institute of Technology
      3  * Copyright 1992 Claude Lecommandeur.
      4  */
      5 
      6 /**********************************************************************
      7  *
      8  * $XConsortium: icons.c,v 1.22 91/07/12 09:58:38 dave Exp $
      9  *
     10  * Icon releated routines
     11  *
     12  * 10-Apr-89 Tom LaStrange        Initial Version.
     13  *
     14  * Do the necessary modification to be integrated in ctwm.
     15  * Can no longer be used for the standard twm.
     16  *
     17  * 22-April-92 Claude Lecommandeur.
     18  *
     19  *
     20  **********************************************************************/
     21 
     22 #include "ctwm.h"
     23 
     24 #include <stdio.h>
     25 #include <stdlib.h>
     26 
     27 #include <X11/extensions/shape.h>
     28 
     29 #include "drawing.h"
     30 #include "screen.h"
     31 #include "iconmgr.h"
     32 #include "icons.h"
     33 #include "otp.h"
     34 #include "list.h"
     35 #include "parse.h"
     36 #include "util.h"
     37 #include "animate.h"
     38 #include "image.h"
     39 #include "win_utils.h"
     40 #include "workspace_manager.h"
     41 #include "xparsegeometry.h"
     42 
     43 
     44 static void splitIconRegionEntry(IconEntry *ie, RegGravity grav1,
     45                                  RegGravity grav2, int w, int h);
     46 static void PlaceIcon(TwmWindow *tmp_win, int def_x, int def_y,
     47                       int *final_x, int *final_y);
     48 static IconEntry *FindIconEntry(TwmWindow *tmp_win, IconRegion **irp);
     49 static IconEntry *prevIconEntry(IconEntry *ie, IconRegion *ir);
     50 static void mergeEntries(IconEntry *old, IconEntry *ie);
     51 static void ReshapeIcon(Icon *icon);
     52 static int roundUp(int v, int multiple);
     53 static Image *LookupIconNameOrClass(TwmWindow *tmp_win, Icon *icon,
     54                                     char **pattern);
     55 
     56 
     57 
     58 /*
     59  ****************************************************************
     60  *
     61  * First some bits related to figuring out where icons go.  Lots of
     62  * IconRegion handling stuff, handling of IconEntry tracking, etc.
     63  *
     64  ****************************************************************
     65  */
     66 
     67 
     68 /*
     69  * This function operates in very weird and obtuse ways, especially in
     70  * how it handles vertical vs. horizontal in weird recursive calls.  Part
     71  * of this is what previously allowed specs with "hgrav vgrav" instead of
     72  * the proper "vgrav hgrav" to sorta-work.  This should be broken up at
     73  * some point into clean h/v functions, but because of the recursion it's
     74  * not exactly trivial.  The parsing code now enforces v/h, so at least
     75  * things can be known to come in in the right order initially.  Revisit
     76  * someday.
     77  */
     78 static void
     79 splitIconRegionEntry(IconEntry *ie, RegGravity grav1, RegGravity grav2,
     80                      int w, int h)
     81 {
     82 	switch(grav1) {
     83 		case GRAV_NORTH:
     84 		case GRAV_SOUTH:
     85 			if(w != ie->w) {
     86 				splitIconRegionEntry(ie, grav2, grav1, w, ie->h);
     87 			}
     88 			if(h != ie->h) {
     89 				IconEntry *new = calloc(1, sizeof(IconEntry));
     90 				new->next = ie->next;
     91 				ie->next = new;
     92 				new->x = ie->x;
     93 				new->h = (ie->h - h);
     94 				new->w = ie->w;
     95 				ie->h = h;
     96 				if(grav1 == GRAV_SOUTH) {
     97 					new->y = ie->y;
     98 					ie->y = new->y + new->h;
     99 				}
    100 				else {
    101 					new->y = ie->y + ie->h;
    102 				}
    103 			}
    104 			break;
    105 		case GRAV_EAST:
    106 		case GRAV_WEST:
    107 			if(h != ie->h) {
    108 				splitIconRegionEntry(ie, grav2, grav1, ie->w, h);
    109 			}
    110 			if(w != ie->w) {
    111 				IconEntry *new = calloc(1, sizeof(IconEntry));
    112 				new->next = ie->next;
    113 				ie->next = new;
    114 				new->y = ie->y;
    115 				new->w = (ie->w - w);
    116 				new->h = ie->h;
    117 				ie->w = w;
    118 				if(grav1 == GRAV_EAST) {
    119 					new->x = ie->x;
    120 					ie->x = new->x + new->w;
    121 				}
    122 				else {
    123 					new->x = ie->x + ie->w;
    124 				}
    125 			}
    126 			break;
    127 	}
    128 }
    129 
    130 
    131 /*
    132  * Backend for parsing IconRegion config
    133  */
    134 name_list **
    135 AddIconRegion(const char *geom, RegGravity grav1, RegGravity grav2,
    136               int stepx, int stepy,
    137               const char *ijust, const char *just, const char *align)
    138 {
    139 	IconRegion *ir;
    140 	int mask, tmp;
    141 
    142 	ir = malloc(sizeof(IconRegion));
    143 	ir->next = NULL;
    144 
    145 	if(Scr->LastRegion) {
    146 		Scr->LastRegion->next = ir;
    147 	}
    148 	Scr->LastRegion = ir;
    149 	if(!Scr->FirstRegion) {
    150 		Scr->FirstRegion = ir;
    151 	}
    152 
    153 	ir->entries = NULL;
    154 	ir->clientlist = NULL;
    155 	ir->grav1 = grav1;
    156 	ir->grav2 = grav2;
    157 	if(stepx <= 0) {
    158 		stepx = 1;
    159 	}
    160 	if(stepy <= 0) {
    161 		stepy = 1;
    162 	}
    163 	ir->stepx = stepx;
    164 	ir->stepy = stepy;
    165 	ir->x = ir->y = ir->w = ir->h = 0;
    166 
    167 	mask = RLayoutXParseGeometry(Scr->Layout, geom, &ir->x, &ir->y,
    168 	                             (unsigned int *)&ir->w, (unsigned int *)&ir->h);
    169 
    170 	if(mask & XNegative) {
    171 		ir->x += Scr->rootw - ir->w;
    172 	}
    173 	if(mask & YNegative) {
    174 		ir->y += Scr->rooth - ir->h;
    175 	}
    176 
    177 	ir->entries = calloc(1, sizeof(IconEntry));
    178 	ir->entries->x = ir->x;
    179 	ir->entries->y = ir->y;
    180 	ir->entries->w = ir->w;
    181 	ir->entries->h = ir->h;
    182 
    183 	if((tmp = ParseTitleJustification(ijust)) < 0) {
    184 		twmrc_error_prefix();
    185 		fprintf(stderr, "ignoring invalid IconRegion argument \"%s\"\n", ijust);
    186 		tmp = TJ_UNDEF;
    187 	}
    188 	ir->TitleJustification = tmp;
    189 
    190 	if((tmp = ParseIRJustification(just)) < 0) {
    191 		twmrc_error_prefix();
    192 		fprintf(stderr, "ignoring invalid IconRegion argument \"%s\"\n", just);
    193 		tmp = IRJ_UNDEF;
    194 	}
    195 	ir->Justification = tmp;
    196 
    197 	if((tmp = ParseAlignement(align)) < 0) {
    198 		twmrc_error_prefix();
    199 		fprintf(stderr, "ignoring invalid IconRegion argument \"%s\"\n", align);
    200 		tmp = IRA_UNDEF;
    201 	}
    202 	ir->Alignement = tmp;
    203 
    204 	return(&(ir->clientlist));
    205 }
    206 
    207 
    208 /*
    209  * Figure out where to put a window's icon based on the IconRegion
    210  * specifications given in config.  Passed def_[xy] which are used
    211  * if we don't find a better location ourselves.  Returns the chosen
    212  * location in final_[xy], and also sets the IconRegion in tmp_win->icon
    213  * if we chose one.
    214  */
    215 static void
    216 PlaceIcon(TwmWindow *tmp_win, int def_x, int def_y,
    217           int *final_x, int *final_y)
    218 {
    219 	IconRegion  *ir, *oldir;
    220 	IconEntry   *ie;
    221 	int         w, h;
    222 
    223 	const int iconWidth = tmp_win->icon->border_width * 2
    224 	                      + (Scr->ShrinkIconTitles ? tmp_win->icon->width
    225 	                         : tmp_win->icon->w_width);
    226 	const int iconHeight = tmp_win->icon->border_width * 2
    227 	                       + tmp_win->icon->w_height;
    228 
    229 	/*
    230 	 * First, check to see if the window is in a region's client list
    231 	 * (i.e., the win-list on an IconRegion specifier in the config).
    232 	 */
    233 	ie = NULL;
    234 	for(ir = Scr->FirstRegion; ir; ir = ir->next) {
    235 		if(LookInList(ir->clientlist, tmp_win->name, &tmp_win->class)) {
    236 			/*
    237 			 * Found one that claims it.  Figure the necessary local
    238 			 * size, based on the icon's side itself and the grid for
    239 			 * this IR.
    240 			 */
    241 			w = roundUp(iconWidth, ir->stepx);
    242 			h = roundUp(iconHeight, ir->stepy);
    243 
    244 			/* Find a currently-unused region that's big enough */
    245 			for(ie = ir->entries; ie; ie = ie->next) {
    246 				if(ie->used) {
    247 					continue;
    248 				}
    249 				if(ie->w >= w && ie->h >= h) {
    250 					/* Bingo */
    251 					break;
    252 				}
    253 			}
    254 
    255 			/* If we found one, we're done here */
    256 			if(ie) {
    257 				break;
    258 			}
    259 		}
    260 	}
    261 
    262 
    263 	/*
    264 	 * If we found a slot in a region claiming it, ie is set to the
    265 	 * IconEntry.  If not, start over and find the first available berth.
    266 	 */
    267 	if(!ie) {
    268 		for(ir = Scr->FirstRegion; ir; ir = ir->next) {
    269 			w = roundUp(iconWidth, ir->stepx);
    270 			h = roundUp(iconHeight, ir->stepy);
    271 			for(ie = ir->entries; ie; ie = ie->next) {
    272 				if(ie->used) {
    273 					continue;
    274 				}
    275 				if(ie->w >= w && ie->h >= h) {
    276 					/* Bingo */
    277 					break;
    278 				}
    279 			}
    280 			if(ie) {
    281 				break;
    282 			}
    283 		}
    284 	}
    285 
    286 	/* Stash for comparison */
    287 	oldir = tmp_win->icon->ir;
    288 
    289 	/*
    290 	 * If we found an appropriate region, use it.  Else, we have no
    291 	 * better idea, so use the x/y coords the caller passed us as our
    292 	 * basis.
    293 	 */
    294 	if(ie) {
    295 		/* XXX whatever sIRE() does */
    296 		splitIconRegionEntry(ie, ir->grav1, ir->grav2, w, h);
    297 
    298 		/* Adjust horizontal positioning based on IconRegionJustification */
    299 		switch(ir->Justification) {
    300 			case IRJ_LEFT:
    301 				*final_x = ie->x;
    302 				break;
    303 			case IRJ_UNDEF:
    304 			case IRJ_CENTER:
    305 				*final_x = ie->x + (ie->w - iconWidth) / 2;
    306 				break;
    307 			case IRJ_RIGHT:
    308 				*final_x = ie->x + ie->w - iconWidth;
    309 				break;
    310 			case IRJ_BORDER:
    311 				if(ir->grav2 == GRAV_EAST) {
    312 					*final_x = ie->x + ie->w - iconWidth;
    313 				}
    314 				else {
    315 					*final_x = ie->x;
    316 				}
    317 				break;
    318 		}
    319 
    320 		/* And vertical based on IconRegionAlignement */
    321 		switch(ir->Alignement) {
    322 			case IRA_TOP :
    323 				*final_y = ie->y;
    324 				break;
    325 			case IRA_UNDEF :
    326 			case IRA_CENTER :
    327 				*final_y = ie->y + (ie->h - iconHeight) / 2;
    328 				break;
    329 			case IRA_BOTTOM :
    330 				*final_y = ie->y + ie->h - iconHeight;
    331 				break;
    332 			case IRA_BORDER :
    333 				if(ir->grav1 == GRAV_SOUTH) {
    334 					*final_y = ie->y + ie->h - iconHeight;
    335 				}
    336 				else {
    337 					*final_y = ie->y;
    338 				}
    339 				break;
    340 		}
    341 
    342 		/* Tell the win/icon what region it's in, and the entry what's in it */
    343 		tmp_win->icon->ir = ir;
    344 		ie->used = true;
    345 		ie->twm_win = tmp_win;
    346 	}
    347 	else {
    348 		/* No better idea, tell caller to use theirs */
    349 		*final_x = def_x;
    350 		*final_y = def_y;
    351 		tmp_win->icon->ir = NULL;
    352 		return;
    353 		/* XXX Should we be doing the below in this case too? */
    354 	}
    355 
    356 	/* Alterations if ShrinkIconTitles is set */
    357 	if(Scr->ShrinkIconTitles && tmp_win->icon->has_title) {
    358 		*final_x -= GetIconOffset(tmp_win->icon);
    359 		if(tmp_win->icon->ir != oldir) {
    360 			ReshapeIcon(tmp_win->icon);
    361 		}
    362 	}
    363 
    364 	return;
    365 }
    366 
    367 
    368 /*
    369  * Look up an IconEntry holding the icon for a given window, and
    370  * optionally stash its IconRegion in irp.  Used internally in
    371  * IconDown().
    372  */
    373 static IconEntry *
    374 FindIconEntry(TwmWindow *tmp_win, IconRegion **irp)
    375 {
    376 	IconRegion  *ir;
    377 	IconEntry   *ie;
    378 
    379 	for(ir = Scr->FirstRegion; ir; ir = ir->next) {
    380 		for(ie = ir->entries; ie; ie = ie->next)
    381 			if(ie->twm_win == tmp_win) {
    382 				if(irp) {
    383 					*irp = ir;
    384 				}
    385 				return ie;
    386 			}
    387 	}
    388 	return NULL;
    389 }
    390 
    391 
    392 /*
    393  * Find prior IE in list.  Used internally in IconDown().
    394  */
    395 static IconEntry *
    396 prevIconEntry(IconEntry *ie, IconRegion *ir)
    397 {
    398 	IconEntry   *ip;
    399 
    400 	if(ie == ir->entries) {
    401 		return NULL;
    402 	}
    403 	for(ip = ir->entries; ip->next != ie; ip = ip->next)
    404 		;
    405 	return ip;
    406 }
    407 
    408 
    409 /*
    410  * Merge two adjacent IconEntry's.  old is being freed; and is adjacent
    411  * to ie.  Merge regions together.
    412  */
    413 static void
    414 mergeEntries(IconEntry *old, IconEntry *ie)
    415 {
    416 	if(old->y == ie->y) {
    417 		ie->w = old->w + ie->w;
    418 		if(old->x < ie->x) {
    419 			ie->x = old->x;
    420 		}
    421 	}
    422 	else {
    423 		ie->h = old->h + ie->h;
    424 		if(old->y < ie->y) {
    425 			ie->y = old->y;
    426 		}
    427 	}
    428 }
    429 
    430 
    431 
    432 
    433 /*
    434  ****************************************************************
    435  *
    436  * Next, the bits related to creating and putting together the icon
    437  * windows, as well as destroying them.
    438  *
    439  ****************************************************************
    440  */
    441 
    442 
    443 /*
    444  * Create the window scaffolding for an icon.  Called when we need to
    445  * make one, e.g. the first time a window is iconified.
    446  */
    447 void
    448 CreateIconWindow(TwmWindow *tmp_win, int def_x, int def_y)
    449 {
    450 	unsigned long event_mask;
    451 	unsigned long valuemask;            /* mask for create windows */
    452 	XSetWindowAttributes attributes;    /* attributes for create windows */
    453 	int final_x, final_y;
    454 	int x;
    455 	Icon        *icon;
    456 	Image       *image = NULL;
    457 	char        *pattern;
    458 
    459 	icon = malloc(sizeof(struct Icon));
    460 
    461 	icon->otp           = NULL;
    462 	icon->border        = Scr->IconBorderColor;
    463 	icon->iconc.fore    = Scr->IconC.fore;
    464 	icon->iconc.back    = Scr->IconC.back;
    465 	icon->title_shrunk  = false;
    466 
    467 	GetColorFromList(Scr->IconBorderColorL, tmp_win->name, &tmp_win->class,
    468 	                 &icon->border);
    469 	GetColorFromList(Scr->IconForegroundL, tmp_win->name, &tmp_win->class,
    470 	                 &icon->iconc.fore);
    471 	GetColorFromList(Scr->IconBackgroundL, tmp_win->name, &tmp_win->class,
    472 	                 &icon->iconc.back);
    473 	if(Scr->use3Diconmanagers && !Scr->BeNiceToColormap) {
    474 		GetShadeColors(&icon->iconc);
    475 	}
    476 
    477 	FB(icon->iconc.fore, icon->iconc.back);
    478 
    479 	icon->match   = match_none;
    480 	icon->image   = NULL;
    481 	icon->ir      = NULL;
    482 
    483 	tmp_win->forced = false;
    484 	icon->w_not_ours = false;
    485 
    486 	pattern = NULL;
    487 
    488 	/* now go through the steps to get an icon window,  if ForceIcon is
    489 	 * set, then no matter what else is defined, the bitmap from the
    490 	 * .twmrc file is used
    491 	 */
    492 	if(Scr->ForceIcon) {
    493 		image = LookupIconNameOrClass(tmp_win, icon, &pattern);
    494 	}
    495 
    496 #ifdef EWMH
    497 	/*
    498 	 * Look to see if there is a _NET_WM_ICON property to provide an icon.
    499 	 */
    500 	if(image == NULL) {
    501 		image = EwmhGetIcon(Scr, tmp_win);
    502 		if(image != NULL) {
    503 			icon->match   = match_net_wm_icon;
    504 			icon->width   = image->width;
    505 			icon->height  = image->height;
    506 			icon->image   = image;
    507 		}
    508 	}
    509 #endif /* EWMH */
    510 
    511 	/* if the pixmap is still NULL, we didn't get one from the above code,
    512 	 * that could mean that ForceIcon was not set, or that the window
    513 	 * was not in the Icons list, now check the WM hints for an icon
    514 	 */
    515 	if(image == NULL && tmp_win->wmhints->flags & IconPixmapHint) {
    516 		unsigned int IconDepth, IconWidth, IconHeight;
    517 
    518 		if(XGetGeometry(dpy, tmp_win->wmhints->icon_pixmap,
    519 		                &JunkRoot, &JunkX, &JunkY, &IconWidth, &IconHeight, &JunkBW, &IconDepth)) {
    520 			image = AllocImage();
    521 			image->width  = IconWidth;
    522 			image->height = IconHeight;
    523 			image->pixmap = XCreatePixmap(dpy, Scr->Root, image->width,
    524 			                              image->height, Scr->d_depth);
    525 			if(IconDepth == Scr->d_depth)
    526 				XCopyArea(dpy, tmp_win->wmhints->icon_pixmap, image->pixmap, Scr->NormalGC,
    527 				          0, 0, image->width, image->height, 0, 0);
    528 			else
    529 				XCopyPlane(dpy, tmp_win->wmhints->icon_pixmap, image->pixmap, Scr->NormalGC,
    530 				           0, 0, image->width, image->height, 0, 0, 1);
    531 
    532 			icon->width   = image->width;
    533 			icon->height  = image->height;
    534 			icon->match   = match_icon_pixmap_hint;
    535 
    536 			if((tmp_win->wmhints->flags & IconMaskHint) &&
    537 			                XGetGeometry(dpy, tmp_win->wmhints->icon_mask,
    538 			                             &JunkRoot, &JunkX, &JunkY, &IconWidth, &IconHeight, &JunkBW, &IconDepth) &&
    539 			                (IconDepth == 1)) {
    540 				GC gc;
    541 
    542 				image->mask = XCreatePixmap(dpy, Scr->Root, IconWidth, IconHeight, 1);
    543 				if(image->mask) {
    544 					gc = XCreateGC(dpy, image->mask, 0, NULL);
    545 					if(gc) {
    546 						XCopyArea(dpy, tmp_win->wmhints->icon_mask, image->mask, gc,
    547 						          0, 0, IconWidth, IconHeight, 0, 0);
    548 						XFreeGC(dpy, gc);
    549 					}
    550 				}
    551 			}
    552 			icon->image = image;
    553 		}
    554 	}
    555 
    556 	/* if we still haven't got an icon, let's look in the Icon list
    557 	 * if ForceIcon is not set
    558 	 */
    559 	if(image == NULL && !Scr->ForceIcon) {
    560 		image = LookupIconNameOrClass(tmp_win, icon, &pattern);
    561 	}
    562 
    563 	/* if we still don't have an icon, assign the UnknownIcon */
    564 	if(image == NULL && Scr->UnknownImage != NULL) {
    565 		image = Scr->UnknownImage;
    566 		icon->match   = match_unknown_default;
    567 		icon->width   = image->width;
    568 		icon->height  = image->height;
    569 		icon->image   = image;
    570 	}
    571 
    572 	if(image == NULL) {
    573 		icon->height = 0;
    574 		icon->width  = 0;
    575 		valuemask    = 0;
    576 	}
    577 	else {
    578 		valuemask = CWBackPixmap;
    579 		attributes.background_pixmap = image->pixmap;
    580 	}
    581 
    582 	icon->border_width = Scr->IconBorderWidth;
    583 	if(Scr->NoIconTitlebar ||
    584 	                LookInNameList(Scr->NoIconTitle, tmp_win->icon_name) ||
    585 	                LookInList(Scr->NoIconTitle, tmp_win->name, &tmp_win->class)) {
    586 		icon->w_width  = icon->width;
    587 		icon->w_height = icon->height;
    588 		icon->x = 0;
    589 		icon->y = 0;
    590 		icon->has_title = false;
    591 	}
    592 	else {
    593 		XRectangle inc_rect;
    594 		XRectangle logical_rect;
    595 
    596 		XmbTextExtents(Scr->IconFont.font_set,
    597 		               tmp_win->icon_name, strlen(tmp_win->icon_name),
    598 		               &inc_rect, &logical_rect);
    599 		icon->w_width = logical_rect.width;
    600 
    601 		icon->w_width += 2 * (Scr->IconManagerShadowDepth + ICON_MGR_IBORDER);
    602 		if(icon->w_width > Scr->MaxIconTitleWidth) {
    603 			icon->w_width = Scr->MaxIconTitleWidth;
    604 		}
    605 		if(icon->w_width < icon->width) {
    606 			icon->x  = (icon->width - icon->w_width) / 2;
    607 			icon->x += Scr->IconManagerShadowDepth + ICON_MGR_IBORDER;
    608 			icon->w_width = icon->width;
    609 		}
    610 		else {
    611 			icon->x = Scr->IconManagerShadowDepth + ICON_MGR_IBORDER;
    612 		}
    613 		icon->y = icon->height + Scr->IconFont.height + Scr->IconManagerShadowDepth;
    614 		icon->w_height = icon->height + Scr->IconFont.height +
    615 		                 2 * (Scr->IconManagerShadowDepth + ICON_MGR_IBORDER);
    616 		icon->has_title = true;
    617 		if(icon->height) {
    618 			icon->border_width = 0;
    619 		}
    620 	}
    621 
    622 	event_mask = 0;
    623 	if(tmp_win->wmhints->flags & IconWindowHint) {
    624 		icon->w = tmp_win->wmhints->icon_window;
    625 		if(tmp_win->forced ||
    626 		                XGetGeometry(dpy, icon->w, &JunkRoot, &JunkX, &JunkY,
    627 		                             (unsigned int *)&icon->w_width, (unsigned int *)&icon->w_height,
    628 		                             &JunkBW, &JunkDepth) == 0) {
    629 			icon->w = None;
    630 			tmp_win->wmhints->flags &= ~IconWindowHint;
    631 		}
    632 		else {
    633 			image = NULL;
    634 			icon->w_not_ours = true;
    635 			icon->width  = icon->w_width;
    636 			icon->height = icon->w_height;
    637 			icon->image  = image;
    638 			icon->has_title = false;
    639 			event_mask = 0;
    640 		}
    641 	}
    642 	else {
    643 		icon->w = None;
    644 	}
    645 
    646 	if((image != NULL) &&
    647 	                image->mask != None &&
    648 	                !(tmp_win->wmhints->flags & IconWindowHint)) {
    649 		icon->border_width = 0;
    650 	}
    651 	if(icon->w == None) {
    652 		icon->w = XCreateSimpleWindow(dpy, Scr->Root,
    653 		                              0, 0,
    654 		                              icon->w_width, icon->w_height,
    655 		                              icon->border_width, icon->border, icon->iconc.back);
    656 		event_mask = ExposureMask;
    657 	}
    658 
    659 	if(Scr->AutoRaiseIcons || Scr->ShrinkIconTitles) {
    660 		event_mask |= EnterWindowMask | LeaveWindowMask;
    661 	}
    662 	event_mask |= KeyPressMask | ButtonPressMask | ButtonReleaseMask;
    663 
    664 	if(icon->w_not_ours) {
    665 		XWindowAttributes wattr;
    666 
    667 		XGetWindowAttributes(dpy, icon->w, &wattr);
    668 		if(wattr.all_event_masks & ButtonPressMask) {
    669 			event_mask &= ~ButtonPressMask;
    670 		}
    671 	}
    672 	XSelectInput(dpy, icon->w, event_mask);
    673 
    674 	if(icon->width == 0) {
    675 		icon->width = icon->w_width;
    676 	}
    677 	icon->bm_w = None;
    678 	if(image && !(tmp_win->wmhints->flags & IconWindowHint)) {
    679 		XRectangle rect;
    680 
    681 		x = GetIconOffset(icon);
    682 		icon->bm_w = XCreateWindow(dpy, icon->w, x, 0,
    683 		                           icon->width,
    684 		                           icon->height,
    685 		                           0, Scr->d_depth,
    686 		                           CopyFromParent,
    687 		                           Scr->d_visual, valuemask,
    688 		                           &attributes);
    689 		if(image->mask) {
    690 			XShapeCombineMask(dpy, icon->bm_w, ShapeBounding, 0, 0, image->mask, ShapeSet);
    691 			XShapeCombineMask(dpy, icon->w,    ShapeBounding, x, 0, image->mask, ShapeSet);
    692 		}
    693 		else if(icon->has_title) {
    694 			rect.x      = x;
    695 			rect.y      = 0;
    696 			rect.width  = icon->width;
    697 			rect.height = icon->height;
    698 			XShapeCombineRectangles(dpy, icon->w, ShapeBounding,
    699 			                        0, 0, &rect, 1, ShapeSet, 0);
    700 		}
    701 		if(icon->has_title) {
    702 			if(Scr->ShrinkIconTitles) {
    703 				rect.x      = x;
    704 				rect.y      = icon->height;
    705 				rect.width  = icon->width;
    706 				rect.height = icon->w_height - icon->height;
    707 				icon->title_shrunk = true;
    708 			}
    709 			else {
    710 				rect.x      = 0;
    711 				rect.y      = icon->height;
    712 				rect.width  = icon->w_width;
    713 				rect.height = icon->w_height - icon->height;
    714 				icon->title_shrunk = false;
    715 			}
    716 			XShapeCombineRectangles(dpy, icon->w, ShapeBounding,
    717 			                        0, 0, &rect, 1, ShapeUnion, 0);
    718 		}
    719 	}
    720 
    721 	if(pattern != NULL) {
    722 		AddToList(&tmp_win->iconslist, pattern, icon);
    723 	}
    724 
    725 	tmp_win->icon = icon;
    726 	/* I need to figure out where to put the icon window now, because
    727 	 * getting here means that I am going to make the icon visible
    728 	 */
    729 	final_x = final_y = 0;
    730 	if(tmp_win->wmhints->flags & IconPositionHint) {
    731 		final_x = tmp_win->wmhints->icon_x;
    732 		final_y = tmp_win->wmhints->icon_y;
    733 	}
    734 	else {
    735 		if(visible(tmp_win)) {
    736 			PlaceIcon(tmp_win, def_x, def_y, &final_x, &final_y);
    737 		}
    738 	}
    739 
    740 	if(visible(tmp_win) || (tmp_win->wmhints->flags & IconPositionHint)) {
    741 		if(final_x > Scr->rootw) {
    742 			final_x = Scr->rootw - icon->w_width - (2 * Scr->IconBorderWidth);
    743 		}
    744 		if(Scr->ShrinkIconTitles && icon->bm_w) {
    745 			if(final_x + (icon->w_width - icon->width) < 0) {
    746 				final_x = 0;
    747 			}
    748 		}
    749 		else {
    750 			if(final_x < 0) {
    751 				final_x = 0;
    752 			}
    753 		}
    754 		if(final_y > Scr->rooth)
    755 			final_y = Scr->rooth - icon->height -
    756 			          Scr->IconFont.height - 6 - (2 * Scr->IconBorderWidth);
    757 		if(final_y < 0) {
    758 			final_y = 0;
    759 		}
    760 
    761 		XMoveWindow(dpy, icon->w, final_x, final_y);
    762 		icon->w_x = final_x;
    763 		icon->w_y = final_y;
    764 	}
    765 	tmp_win->iconified = true;
    766 	OtpAdd(tmp_win, IconWin);
    767 
    768 	XMapSubwindows(dpy, icon->w);
    769 	XSaveContext(dpy, icon->w, TwmContext, (XPointer)tmp_win);
    770 	XSaveContext(dpy, icon->w, ScreenContext, (XPointer)Scr);
    771 	XDefineCursor(dpy, icon->w, Scr->IconCursor);
    772 	MaybeAnimate = true;
    773 }
    774 
    775 
    776 /*
    777  * Delete TwmWindow.iconslist.
    778  * Call it before deleting TwmWindow.icon, since we need to check
    779  * that we're not deleting that Icon.
    780  */
    781 void
    782 DeleteIconsList(TwmWindow *tmp_win)
    783 {
    784 	/*
    785 	 * Only the list itself needs to be freed, since the pointers it
    786 	 * contains point into various lists that belong to Scr.
    787 	 *
    788 	 * Rhialto: Hmmmm not quite sure about that! CreateIconWindow() above
    789 	 * always allocates a struct Icon, and doesn't attach it to Scr...
    790 	 * It is probably correct for the Image pointers inside those Icons though.
    791 	 */
    792 	name_list *nptr;
    793 	name_list *next;
    794 
    795 	for(nptr = tmp_win->iconslist; nptr != NULL;) {
    796 		next = nptr->next;
    797 		Icon *icon = (Icon *)nptr->ptr;
    798 		if(icon != tmp_win->icon) {
    799 			DeleteIcon(icon);
    800 		}
    801 		free(nptr->name);
    802 		free(nptr);
    803 		nptr = next;
    804 	}
    805 	tmp_win->iconslist = NULL;
    806 }
    807 
    808 
    809 /*
    810  * Delete a single Icon.  Called iteratively from DeleteIconList(), and
    811  * directly during window destruction.
    812  */
    813 void
    814 DeleteIcon(Icon *icon)
    815 {
    816 	if(icon->w && !icon->w_not_ours) {
    817 		XDestroyWindow(dpy, icon->w);
    818 	}
    819 	ReleaseIconImage(icon);
    820 	free(icon);
    821 }
    822 
    823 
    824 /*
    825  * Delete the Image from an icon, if it is not a shared one.  match_list
    826  * ands match_unknown_default need not be freed.
    827  *
    828  * Formerly ReleaseImage()
    829  */
    830 void
    831 ReleaseIconImage(Icon *icon)
    832 {
    833 	if(icon->match == match_icon_pixmap_hint ||
    834 	                icon->match == match_net_wm_icon) {
    835 		FreeImage(icon->image);
    836 	}
    837 }
    838 
    839 
    840 
    841 
    842 /*
    843  ****************************************************************
    844  *
    845  * Bringing an icon up or down.
    846  *
    847  ****************************************************************
    848  */
    849 
    850 
    851 /*
    852  * Show up an icon.  Note that neither IconUp nor IconDown actually map
    853  * or unmap the icon window; that's handled by the callers.  These
    854  * functions limit themselves to figuring out where it should be, moving
    855  * it (still unmapped) there, and linking/unlinking it from the iconentry
    856  * lists.
    857  */
    858 void
    859 IconUp(TwmWindow *tmp_win)
    860 {
    861 	int         x, y;
    862 	int         defx, defy;
    863 
    864 	/*
    865 	 * If the client specified a particular location, let's use it (this might
    866 	 * want to be an option at some point).  Otherwise, try to fit within the
    867 	 * icon region.
    868 	 */
    869 	if(tmp_win->wmhints->flags & IconPositionHint) {
    870 		return;
    871 	}
    872 
    873 	if(tmp_win->icon_moved) {
    874 		struct IconRegion *ir;
    875 		unsigned int iww, iwh;
    876 
    877 		if(!XGetGeometry(dpy, tmp_win->icon->w, &JunkRoot, &defx, &defy,
    878 		                 &iww, &iwh, &JunkBW, &JunkDepth)) {
    879 			return;
    880 		}
    881 
    882 		x = defx + ((int) iww) / 2;
    883 		y = defy + ((int) iwh) / 2;
    884 
    885 		for(ir = Scr->FirstRegion; ir; ir = ir->next) {
    886 			if(x >= ir->x && x < (ir->x + ir->w) &&
    887 			                y >= ir->y && y < (ir->y + ir->h)) {
    888 				break;
    889 			}
    890 		}
    891 		if(!ir) {
    892 			return;        /* outside icon regions, leave alone */
    893 		}
    894 	}
    895 
    896 	defx = -100;
    897 	defy = -100;
    898 	PlaceIcon(tmp_win, defx, defy, &x, &y);
    899 	if(x != defx || y != defy) {
    900 		XMoveWindow(dpy, tmp_win->icon->w, x, y);
    901 		tmp_win->icon->w_x = x;
    902 		tmp_win->icon->w_y = y;
    903 		tmp_win->icon_moved = false;    /* since we've restored it */
    904 	}
    905 	MaybeAnimate = true;
    906 	return;
    907 }
    908 
    909 
    910 /*
    911  * Remove an icon from its displayed IconEntry.  x-ref comment on
    912  * IconUp().
    913  */
    914 void
    915 IconDown(TwmWindow *tmp_win)
    916 {
    917 	IconEntry   *ie, *ip, *in;
    918 	IconRegion  *ir;
    919 
    920 	ie = FindIconEntry(tmp_win, &ir);
    921 	if(ie) {
    922 		ie->twm_win = NULL;
    923 		ie->used = false;
    924 		ip = prevIconEntry(ie, ir);
    925 		in = ie->next;
    926 		for(;;) {
    927 			if(ip && ip->used == false &&
    928 			                ((ip->x == ie->x && ip->w == ie->w) ||
    929 			                 (ip->y == ie->y && ip->h == ie->h))) {
    930 				ip->next = ie->next;
    931 				mergeEntries(ie, ip);
    932 				free(ie);
    933 				ie = ip;
    934 				ip = prevIconEntry(ip, ir);
    935 			}
    936 			else if(in && in->used == false &&
    937 			                ((in->x == ie->x && in->w == ie->w) ||
    938 			                 (in->y == ie->y && in->h == ie->h))) {
    939 				ie->next = in->next;
    940 				mergeEntries(in, ie);
    941 				free(in);
    942 				in = ie->next;
    943 			}
    944 			else {
    945 				break;
    946 			}
    947 		}
    948 	}
    949 }
    950 
    951 
    952 
    953 
    954 /*
    955  ****************************************************************
    956  *
    957  * Funcs related to drawing the icon.
    958  *
    959  ****************************************************************
    960  */
    961 
    962 
    963 /*
    964  * Slightly misnamed: draws the text label under an icon.
    965  */
    966 void
    967 PaintIcon(TwmWindow *tmp_win)
    968 {
    969 	int         width, twidth, mwidth, len, x;
    970 	Icon        *icon;
    971 	XRectangle ink_rect;
    972 	XRectangle logical_rect;
    973 
    974 	if(!tmp_win || !tmp_win->icon) {
    975 		return;
    976 	}
    977 	icon = tmp_win->icon;
    978 	if(!icon->has_title) {
    979 		return;
    980 	}
    981 
    982 	x     = 0;
    983 	width = icon->w_width;
    984 	if(Scr->ShrinkIconTitles && icon->title_shrunk) {
    985 		x     = GetIconOffset(icon);
    986 		width = icon->width;
    987 	}
    988 	len    = strlen(tmp_win->icon_name);
    989 	XmbTextExtents(Scr->IconFont.font_set,
    990 	               tmp_win->icon_name, len,
    991 	               &ink_rect, &logical_rect);
    992 	twidth = logical_rect.width;
    993 	mwidth = width - 2 * (Scr->IconManagerShadowDepth + ICON_MGR_IBORDER);
    994 	if(Scr->use3Diconmanagers) {
    995 		Draw3DBorder(icon->w, x, icon->height, width,
    996 		             Scr->IconFont.height +
    997 		             2 * (Scr->IconManagerShadowDepth + ICON_MGR_IBORDER),
    998 		             Scr->IconManagerShadowDepth, icon->iconc, off, false, false);
    999 	}
   1000 	while((len > 0) && (twidth > mwidth)) {
   1001 		len--;
   1002 		XmbTextExtents(Scr->IconFont.font_set,
   1003 		               tmp_win->icon_name, len,
   1004 		               &ink_rect, &logical_rect);
   1005 		twidth = logical_rect.width;
   1006 	}
   1007 	FB(icon->iconc.fore, icon->iconc.back);
   1008 	XmbDrawString(dpy, icon->w, Scr->IconFont.font_set, Scr->NormalGC,
   1009 	              x + ((mwidth - twidth) / 2) +
   1010 	              Scr->IconManagerShadowDepth + ICON_MGR_IBORDER,
   1011 	              icon->y, tmp_win->icon_name, len);
   1012 }
   1013 
   1014 
   1015 /*
   1016  * Handling for ShrinkIconTitles; when pointer is away from them, shrink
   1017  * the titles down to the width of the image, and expand back out when it
   1018  * enters.
   1019  */
   1020 void
   1021 ShrinkIconTitle(TwmWindow *tmp_win)
   1022 {
   1023 	Icon        *icon;
   1024 	XRectangle  rect;
   1025 
   1026 	if(!tmp_win || !tmp_win->icon) {
   1027 		return;
   1028 	}
   1029 	icon = tmp_win->icon;
   1030 	if(!icon->has_title) {
   1031 		return;
   1032 	}
   1033 	if(icon->w_width == icon->width) {
   1034 		return;
   1035 	}
   1036 	if(icon->height  == 0) {
   1037 		return;
   1038 	}
   1039 
   1040 	rect.x      = GetIconOffset(icon);
   1041 	rect.y      = 0;
   1042 	rect.width  = icon->width;
   1043 	rect.height = icon->w_height;
   1044 	XShapeCombineRectangles(dpy, icon->w, ShapeBounding, 0, 0, &rect, 1,
   1045 	                        ShapeIntersect, 0);
   1046 	icon->title_shrunk = true;
   1047 	XClearArea(dpy, icon->w, 0, icon->height, icon->w_width,
   1048 	           icon->w_height - icon->height, True);
   1049 }
   1050 
   1051 
   1052 void
   1053 ExpandIconTitle(TwmWindow *tmp_win)
   1054 {
   1055 	Icon        *icon;
   1056 	XRectangle  rect;
   1057 
   1058 	if(!tmp_win || !tmp_win->icon) {
   1059 		return;
   1060 	}
   1061 	icon = tmp_win->icon;
   1062 	if(!icon->has_title) {
   1063 		return;
   1064 	}
   1065 	if(icon->w_width == icon->width) {
   1066 		return;
   1067 	}
   1068 	if(icon->height  == 0) {
   1069 		return;
   1070 	}
   1071 
   1072 	rect.x      = 0;
   1073 	rect.y      = icon->height;
   1074 	rect.width  = icon->w_width;
   1075 	rect.height = icon->w_height - icon->height;
   1076 	XShapeCombineRectangles(dpy, icon->w, ShapeBounding, 0, 0, &rect, 1, ShapeUnion,
   1077 	                        0);
   1078 	icon->title_shrunk = false;
   1079 	XClearArea(dpy, icon->w, 0, icon->height, icon->w_width,
   1080 	           icon->w_height - icon->height, True);
   1081 }
   1082 
   1083 
   1084 /*
   1085  * Setup X Shape'ing around icons and their titles.
   1086  *
   1087  * XXX should this be checking HasShape?  It seems to be called
   1088  * unconditionally...
   1089  */
   1090 static void
   1091 ReshapeIcon(Icon *icon)
   1092 {
   1093 	int x;
   1094 	XRectangle  rect;
   1095 
   1096 	if(!icon) {
   1097 		return;
   1098 	}
   1099 	x = GetIconOffset(icon);
   1100 	XMoveWindow(dpy, icon->bm_w, x, 0);
   1101 
   1102 	if(icon->image && icon->image->mask) {
   1103 		XShapeCombineMask(dpy, icon->w, ShapeBounding, x, 0, icon->image->mask,
   1104 		                  ShapeSet);
   1105 	}
   1106 	else {
   1107 		rect.x      = x;
   1108 		rect.y      = 0;
   1109 		rect.width  = icon->width;
   1110 		rect.height = icon->height;
   1111 		XShapeCombineRectangles(dpy, icon->w, ShapeBounding, 0, 0, &rect, 1, ShapeSet,
   1112 		                        0);
   1113 	}
   1114 	rect.x      = x;
   1115 	rect.y      = icon->height;
   1116 	rect.width  = icon->width;
   1117 	rect.height = icon->w_height - icon->height;
   1118 	XShapeCombineRectangles(dpy, icon->w, ShapeBounding, 0, 0, &rect, 1, ShapeUnion,
   1119 	                        0);
   1120 }
   1121 
   1122 
   1123 /*
   1124  * Figure horizontal positioning/offset for the icon image within its
   1125  * window.
   1126  */
   1127 int
   1128 GetIconOffset(Icon *icon)
   1129 {
   1130 	TitleJust justif;
   1131 
   1132 	if(!icon) {
   1133 		return 0;
   1134 	}
   1135 
   1136 	justif = icon->ir ? icon->ir->TitleJustification : Scr->IconJustification;
   1137 	switch(justif) {
   1138 		case TJ_LEFT:
   1139 			return 0;
   1140 
   1141 		case TJ_CENTER:
   1142 			return ((icon->w_width - icon->width) / 2);
   1143 
   1144 		case TJ_RIGHT:
   1145 			return (icon->w_width - icon->width);
   1146 
   1147 		default:
   1148 			/* Can't happen? */
   1149 			fprintf(stderr, "%s(): Invalid TitleJustification %d\n",
   1150 			        __func__, justif);
   1151 			return 0;
   1152 	}
   1153 }
   1154 
   1155 
   1156 /*
   1157  * [Re-]lookup the image for an icon and [re-]layout it.
   1158  */
   1159 void
   1160 RedoIcon(TwmWindow *win)
   1161 {
   1162 	Icon *icon, *old_icon;
   1163 	char *pattern;
   1164 
   1165 	old_icon = win->icon;
   1166 
   1167 	if(old_icon && (old_icon->w_not_ours || old_icon->match != match_list)) {
   1168 		RedoIconName(win);
   1169 		return;
   1170 	}
   1171 	icon = NULL;
   1172 	if((pattern = LookPatternInNameList(Scr->IconNames, win->icon_name))) {
   1173 		icon = LookInNameList(win->iconslist, pattern);
   1174 	}
   1175 	else if((pattern = LookPatternInNameList(Scr->IconNames, win->name))) {
   1176 		icon = LookInNameList(win->iconslist, pattern);
   1177 	}
   1178 	else if((pattern = LookPatternInList(Scr->IconNames, win->name,
   1179 	                                     &win->class))) {
   1180 		icon = LookInNameList(win->iconslist, pattern);
   1181 	}
   1182 	if(pattern == NULL) {
   1183 		RedoIconName(win);
   1184 		return;
   1185 	}
   1186 	if(icon != NULL) {
   1187 		if(old_icon == icon) {
   1188 			RedoIconName(win);
   1189 			return;
   1190 		}
   1191 		if(win->icon_on && visible(win)) {
   1192 			IconDown(win);
   1193 			if(old_icon && old_icon->w) {
   1194 				XUnmapWindow(dpy, old_icon->w);
   1195 			}
   1196 			win->icon = icon;
   1197 			OtpReassignIcon(win, old_icon);
   1198 			IconUp(win);
   1199 			OtpRaise(win, IconWin);
   1200 			XMapWindow(dpy, win->icon->w);
   1201 		}
   1202 		else {
   1203 			win->icon = icon;
   1204 			OtpReassignIcon(win, old_icon);
   1205 		}
   1206 		RedoIconName(win);
   1207 	}
   1208 	else {
   1209 		if(win->icon_on && visible(win)) {
   1210 			IconDown(win);
   1211 			if(old_icon && old_icon->w) {
   1212 				XUnmapWindow(dpy, old_icon->w);
   1213 			}
   1214 			/*
   1215 			 * If the icon name/class was found on one of the above lists,
   1216 			 * the call to CreateIconWindow() will find it again there
   1217 			 * and keep track of it on win->iconslist for eventual
   1218 			 * deallocation. (It is now checked that the current struct
   1219 			 * Icon is also already on that list)
   1220 			 */
   1221 			OtpFreeIcon(win);
   1222 			bool saveForceIcon = Scr->ForceIcon;
   1223 			Scr->ForceIcon = true;
   1224 			CreateIconWindow(win, -100, -100);
   1225 			Scr->ForceIcon = saveForceIcon;
   1226 			OtpRaise(win, IconWin);
   1227 			XMapWindow(dpy, win->icon->w);
   1228 		}
   1229 		else {
   1230 			OtpFreeIcon(win);
   1231 			win->icon = NULL;
   1232 			WMapUpdateIconName(win);
   1233 		}
   1234 		RedoIconName(win);
   1235 	}
   1236 }
   1237 
   1238 
   1239 /*
   1240  * Resize the icon window, and reposition the image and name within it.
   1241  * (a lot of the actual repositioning gets done during the later expose).
   1242  */
   1243 void
   1244 RedoIconName(TwmWindow *win)
   1245 {
   1246 	int x;
   1247 	XRectangle ink_rect;
   1248 	XRectangle logical_rect;
   1249 
   1250 	if(Scr->NoIconTitlebar ||
   1251 	                LookInNameList(Scr->NoIconTitle, win->icon_name) ||
   1252 	                LookInList(Scr->NoIconTitle, win->name, &win->class)) {
   1253 		WMapUpdateIconName(win);
   1254 		return;
   1255 	}
   1256 	if(win->iconmanagerlist) {
   1257 		/* let the expose event cause the repaint */
   1258 		XClearArea(dpy, win->iconmanagerlist->w, 0, 0, 0, 0, True);
   1259 
   1260 		if(Scr->SortIconMgr) {
   1261 			SortIconManager(win->iconmanagerlist->iconmgr);
   1262 		}
   1263 	}
   1264 
   1265 	if(!win->icon  || !win->icon->w) {
   1266 		WMapUpdateIconName(win);
   1267 		return;
   1268 	}
   1269 
   1270 	if(win->icon->w_not_ours) {
   1271 		WMapUpdateIconName(win);
   1272 		return;
   1273 	}
   1274 
   1275 	XmbTextExtents(Scr->IconFont.font_set,
   1276 	               win->icon_name, strlen(win->icon_name),
   1277 	               &ink_rect, &logical_rect);
   1278 	win->icon->w_width = logical_rect.width;
   1279 	win->icon->w_width += 2 * (Scr->IconManagerShadowDepth + ICON_MGR_IBORDER);
   1280 	if(win->icon->w_width > Scr->MaxIconTitleWidth) {
   1281 		win->icon->w_width = Scr->MaxIconTitleWidth;
   1282 	}
   1283 
   1284 	if(win->icon->w_width < win->icon->width) {
   1285 		win->icon->x = (win->icon->width - win->icon->w_width) / 2;
   1286 		win->icon->x += Scr->IconManagerShadowDepth + ICON_MGR_IBORDER;
   1287 		win->icon->w_width = win->icon->width;
   1288 	}
   1289 	else {
   1290 		win->icon->x = Scr->IconManagerShadowDepth + ICON_MGR_IBORDER;
   1291 	}
   1292 
   1293 	x = GetIconOffset(win->icon);
   1294 	win->icon->y = win->icon->height + Scr->IconFont.height +
   1295 	               Scr->IconManagerShadowDepth;
   1296 	win->icon->w_height = win->icon->height + Scr->IconFont.height +
   1297 	                      2 * (Scr->IconManagerShadowDepth + ICON_MGR_IBORDER);
   1298 
   1299 	XResizeWindow(dpy, win->icon->w, win->icon->w_width,
   1300 	              win->icon->w_height);
   1301 	if(win->icon->bm_w) {
   1302 		XRectangle rect;
   1303 
   1304 		XMoveWindow(dpy, win->icon->bm_w, x, 0);
   1305 		XMapWindow(dpy, win->icon->bm_w);
   1306 		if(win->icon->image && win->icon->image->mask) {
   1307 			XShapeCombineMask(dpy, win->icon->bm_w, ShapeBounding, 0, 0,
   1308 			                  win->icon->image->mask, ShapeSet);
   1309 			XShapeCombineMask(dpy, win->icon->w, ShapeBounding, x, 0,
   1310 			                  win->icon->image->mask, ShapeSet);
   1311 		}
   1312 		else if(win->icon->has_title) {
   1313 			rect.x      = x;
   1314 			rect.y      = 0;
   1315 			rect.width  = win->icon->width;
   1316 			rect.height = win->icon->height;
   1317 			XShapeCombineRectangles(dpy, win->icon->w, ShapeBounding,
   1318 			                        0, 0, &rect, 1, ShapeSet, 0);
   1319 		}
   1320 		if(win->icon->has_title) {
   1321 			if(Scr->ShrinkIconTitles && win->icon->title_shrunk) {
   1322 				rect.x      = x;
   1323 				rect.y      = win->icon->height;
   1324 				rect.width  = win->icon->width;
   1325 				rect.height = win->icon->w_height - win->icon->height;
   1326 			}
   1327 			else {
   1328 				rect.x      = 0;
   1329 				rect.y      = win->icon->height;
   1330 				rect.width  = win->icon->w_width;
   1331 				rect.height = win->icon->w_height - win->icon->height;
   1332 			}
   1333 			XShapeCombineRectangles(dpy,  win->icon->w, ShapeBounding, 0,
   1334 			                        0, &rect, 1, ShapeUnion, 0);
   1335 		}
   1336 	}
   1337 	if(Scr->ShrinkIconTitles &&
   1338 	                win->icon->title_shrunk &&
   1339 	                win->icon_on && (visible(win))) {
   1340 		IconDown(win);
   1341 		IconUp(win);
   1342 	}
   1343 	if(win->isicon) {
   1344 		XClearArea(dpy, win->icon->w, 0, 0, 0, 0, True);
   1345 	}
   1346 
   1347 	WMapUpdateIconName(win);
   1348 }
   1349 
   1350 
   1351 
   1352 
   1353 /*
   1354  ****************************************************************
   1355  *
   1356  * Misc internal utils.
   1357  *
   1358  ****************************************************************
   1359  */
   1360 
   1361 
   1362 /*
   1363  * What it says on the tin.
   1364  */
   1365 static int
   1366 roundUp(int v, int multiple)
   1367 {
   1368 	return ((v + multiple - 1) / multiple) * multiple;
   1369 }
   1370 
   1371 
   1372 /*
   1373  * Find the image set in Icons{} for a TwmWindow if possible.  Return the
   1374  * image, record its provenance inside *icon, and pass back what pattern
   1375  * it matched in **pattern.
   1376  */
   1377 static Image *
   1378 LookupIconNameOrClass(TwmWindow *tmp_win, Icon *icon, char **pattern)
   1379 {
   1380 	char *icon_name = NULL;
   1381 	Image *image;
   1382 	Matchtype matched = match_none;
   1383 
   1384 	icon_name = LookInNameList(Scr->IconNames, tmp_win->icon_name);
   1385 	if(icon_name != NULL) {
   1386 		*pattern = LookPatternInNameList(Scr->IconNames, tmp_win->icon_name);
   1387 		matched = match_list;
   1388 	}
   1389 
   1390 	if(matched == match_none) {
   1391 		icon_name = LookInNameList(Scr->IconNames, tmp_win->name);
   1392 		if(icon_name != NULL) {
   1393 			*pattern = LookPatternInNameList(Scr->IconNames, tmp_win->name);
   1394 			matched = match_list;
   1395 		}
   1396 	}
   1397 
   1398 	if(matched == match_none) {
   1399 		icon_name = LookInList(Scr->IconNames, tmp_win->name, &tmp_win->class);
   1400 		if(icon_name != NULL) {
   1401 			*pattern = LookPatternInList(Scr->IconNames, tmp_win->name,
   1402 			                             &tmp_win->class);
   1403 			matched = match_list;
   1404 		}
   1405 	}
   1406 
   1407 	if((image  = GetImage(icon_name, icon->iconc)) != NULL) {
   1408 		icon->match  = matched;
   1409 		icon->image  = image;
   1410 		icon->width  = image->width;
   1411 		icon->height = image->height;
   1412 		tmp_win->forced = true;
   1413 	}
   1414 	else {
   1415 		icon->match = match_none;
   1416 		*pattern = NULL;
   1417 	}
   1418 
   1419 	return image;
   1420 }
   1421