icons.c revision c2535118
1/* 2 * 3Copyright 1989, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included in 12all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 21Except as contained in this notice, the name of The Open Group shall not be 22used in advertising or otherwise to promote the sale, use or other dealings 23in this Software without prior written authorization from The Open Group. 24 * */ 25 26/********************************************************************** 27 * 28 * Icon releated routines 29 * 30 * 10-Apr-89 Tom LaStrange Initial Version. 31 * 32 **********************************************************************/ 33 34#include <stdio.h> 35#include "twm.h" 36#include "screen.h" 37#include "icons.h" 38#include "gram.h" 39#include "parse.h" 40#include "util.h" 41 42#define iconWidth(w) (Scr->IconBorderWidth * 2 + w->icon_w_width) 43#define iconHeight(w) (Scr->IconBorderWidth * 2 + w->icon_w_height) 44 45static void splitEntry ( IconEntry *ie, int grav1, int grav2, int w, int h ); 46static IconEntry * FindIconEntry ( TwmWindow *tmp_win, IconRegion **irp ); 47static IconEntry * prevIconEntry ( IconEntry *ie, IconRegion *ir ); 48static void mergeEntries ( IconEntry *old, IconEntry *ie ); 49 50static void 51splitEntry (IconEntry *ie, int grav1, int grav2, int w, int h) 52{ 53 IconEntry *new; 54 55 switch (grav1) { 56 case D_NORTH: 57 case D_SOUTH: 58 if (w != ie->w) 59 splitEntry (ie, grav2, grav1, w, ie->h); 60 if (h != ie->h) { 61 new = malloc (sizeof (IconEntry)); 62 new->twm_win = 0; 63 new->used = 0; 64 new->next = ie->next; 65 ie->next = new; 66 new->x = ie->x; 67 new->h = (ie->h - h); 68 new->w = ie->w; 69 ie->h = h; 70 if (grav1 == D_SOUTH) { 71 new->y = ie->y; 72 ie->y = new->y + new->h; 73 } else 74 new->y = ie->y + ie->h; 75 } 76 break; 77 case D_EAST: 78 case D_WEST: 79 if (h != ie->h) 80 splitEntry (ie, grav2, grav1, ie->w, h); 81 if (w != ie->w) { 82 new = malloc (sizeof (IconEntry)); 83 new->twm_win = 0; 84 new->used = 0; 85 new->next = ie->next; 86 ie->next = new; 87 new->y = ie->y; 88 new->w = (ie->w - w); 89 new->h = ie->h; 90 ie->w = w; 91 if (grav1 == D_EAST) { 92 new->x = ie->x; 93 ie->x = new->x + new->w; 94 } else 95 new->x = ie->x + ie->w; 96 } 97 break; 98 } 99} 100 101static inline int 102roundUp (int v, int multiple) 103{ 104 return ((v + multiple - 1) / multiple) * multiple; 105} 106 107static void 108PlaceIcon(TwmWindow *tmp_win, int def_x, int def_y, int *final_x, int *final_y) 109{ 110 IconRegion *ir; 111 IconEntry *ie; 112 int w = 0, h = 0; 113 114 ie = 0; 115 for (ir = Scr->FirstRegion; ir; ir = ir->next) { 116 w = roundUp (iconWidth (tmp_win), ir->stepx); 117 h = roundUp (iconHeight (tmp_win), ir->stepy); 118 for (ie = ir->entries; ie; ie=ie->next) { 119 if (ie->used) 120 continue; 121 if (ie->w >= w && ie->h >= h) 122 break; 123 } 124 if (ie) 125 break; 126 } 127 if (ie) { 128 splitEntry (ie, ir->grav1, ir->grav2, w, h); 129 ie->used = 1; 130 ie->twm_win = tmp_win; 131 *final_x = ie->x + (ie->w - iconWidth (tmp_win)) / 2; 132 *final_y = ie->y + (ie->h - iconHeight (tmp_win)) / 2; 133 } else { 134 *final_x = def_x; 135 *final_y = def_y; 136 } 137 return; 138} 139 140static IconEntry * 141FindIconEntry (TwmWindow *tmp_win, IconRegion **irp) 142{ 143 IconRegion *ir; 144 IconEntry *ie; 145 146 for (ir = Scr->FirstRegion; ir; ir = ir->next) { 147 for (ie = ir->entries; ie; ie=ie->next) 148 if (ie->twm_win == tmp_win) { 149 if (irp) 150 *irp = ir; 151 return ie; 152 } 153 } 154 return 0; 155} 156 157void 158IconUp (TwmWindow *tmp_win) 159{ 160 int x, y; 161 int defx, defy; 162 struct IconRegion *ir; 163 164 /* 165 * If the client specified a particular location, let's use it (this might 166 * want to be an option at some point). Otherwise, try to fit within the 167 * icon region. 168 */ 169 if (tmp_win->wmhints && (tmp_win->wmhints->flags & IconPositionHint)) 170 return; 171 172 if (tmp_win->icon_moved) { 173 if (!XGetGeometry (dpy, tmp_win->icon_w, &JunkRoot, &defx, &defy, 174 &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth)) 175 return; 176 177 x = defx + ((int) JunkWidth) / 2; 178 y = defy + ((int) JunkHeight) / 2; 179 180 for (ir = Scr->FirstRegion; ir; ir = ir->next) { 181 if (x >= ir->x && x < (ir->x + ir->w) && 182 y >= ir->y && y < (ir->y + ir->h)) 183 break; 184 } 185 if (!ir) return; /* outside icon regions, leave alone */ 186 } 187 188 defx = -100; 189 defy = -100; 190 PlaceIcon(tmp_win, defx, defy, &x, &y); 191 if (x != defx || y != defy) { 192 XMoveWindow (dpy, tmp_win->icon_w, x, y); 193 tmp_win->icon_moved = FALSE; /* since we've restored it */ 194 } 195} 196 197static IconEntry * 198prevIconEntry (IconEntry *ie, IconRegion *ir) 199{ 200 IconEntry *ip; 201 202 if (ie == ir->entries) 203 return 0; 204 for (ip = ir->entries; ip->next != ie; ip=ip->next) 205 ; 206 return ip; 207} 208 209/** 210 * old is being freed; and is adjacent to ie. Merge 211 * regions together 212 */ 213static void 214mergeEntries (IconEntry *old, IconEntry *ie) 215{ 216 if (old->y == ie->y) { 217 ie->w = old->w + ie->w; 218 if (old->x < ie->x) 219 ie->x = old->x; 220 } else { 221 ie->h = old->h + ie->h; 222 if (old->y < ie->y) 223 ie->y = old->y; 224 } 225} 226 227void 228IconDown (TwmWindow *tmp_win) 229{ 230 IconEntry *ie, *ip, *in; 231 IconRegion *ir; 232 233 ie = FindIconEntry (tmp_win, &ir); 234 if (ie) { 235 ie->twm_win = 0; 236 ie->used = 0; 237 ip = prevIconEntry (ie, ir); 238 in = ie->next; 239 for (;;) { 240 if (ip && ip->used == 0 && 241 ((ip->x == ie->x && ip->w == ie->w) || 242 (ip->y == ie->y && ip->h == ie->h))) 243 { 244 ip->next = ie->next; 245 mergeEntries (ie, ip); 246 free (ie); 247 ie = ip; 248 ip = prevIconEntry (ip, ir); 249 } else if (in && in->used == 0 && 250 ((in->x == ie->x && in->w == ie->w) || 251 (in->y == ie->y && in->h == ie->h))) 252 { 253 ie->next = in->next; 254 mergeEntries (in, ie); 255 free (in); 256 in = ie->next; 257 } else 258 break; 259 } 260 } 261} 262 263void 264AddIconRegion(char *geom, int grav1, int grav2, int stepx, int stepy) 265{ 266 IconRegion *ir; 267 int mask; 268 269 ir = malloc(sizeof(IconRegion)); 270 ir->next = NULL; 271 if (Scr->LastRegion) 272 Scr->LastRegion->next = ir; 273 Scr->LastRegion = ir; 274 if (!Scr->FirstRegion) 275 Scr->FirstRegion = ir; 276 277 ir->entries = NULL; 278 ir->grav1 = grav1; 279 ir->grav2 = grav2; 280 if (stepx <= 0) 281 stepx = 1; 282 if (stepy <= 0) 283 stepy = 1; 284 ir->stepx = stepx; 285 ir->stepy = stepy; 286 ir->x = ir->y = ir->w = ir->h = 0; 287 288 mask = XParseGeometry(geom, &ir->x, &ir->y, (unsigned int *)&ir->w, (unsigned int *)&ir->h); 289 290 if (mask & XNegative) 291 ir->x += Scr->MyDisplayWidth - ir->w; 292 293 if (mask & YNegative) 294 ir->y += Scr->MyDisplayHeight - ir->h; 295 ir->entries = malloc(sizeof(IconEntry)); 296 ir->entries->next = 0; 297 ir->entries->x = ir->x; 298 ir->entries->y = ir->y; 299 ir->entries->w = ir->w; 300 ir->entries->h = ir->h; 301 ir->entries->twm_win = 0; 302 ir->entries->used = 0; 303} 304 305#ifdef comment 306void 307FreeIconEntries (IconRegion *ir) 308{ 309 IconEntry *ie, *tmp; 310 311 for (ie = ir->entries; ie; ie=tmp) 312 { 313 tmp = ie->next; 314 free (ie); 315 } 316} 317 318void 319FreeIconRegions(void) 320{ 321 IconRegion *ir, *tmp; 322 323 for (ir = Scr->FirstRegion; ir != NULL;) 324 { 325 tmp = ir; 326 FreeIconEntries (ir); 327 ir = ir->next; 328 free(tmp); 329 } 330 Scr->FirstRegion = NULL; 331 Scr->LastRegion = NULL; 332} 333#endif 334 335void 336CreateIconWindow(TwmWindow *tmp_win, int def_x, int def_y) 337{ 338 unsigned long event_mask; 339 unsigned long valuemask; /* mask for create windows */ 340 XSetWindowAttributes attributes; /* attributes for create windows */ 341 Pixmap pm = None; /* tmp pixmap variable */ 342 int final_x, final_y; 343 int x; 344 345 346 FB(tmp_win->iconc.fore, tmp_win->iconc.back); 347 348 tmp_win->forced = FALSE; 349 tmp_win->icon_not_ours = FALSE; 350 351 /* now go through the steps to get an icon window, if ForceIcon is 352 * set, then no matter what else is defined, the bitmap from the 353 * .twmrc file is used 354 */ 355 if (Scr->ForceIcon) 356 { 357 char *icon_name; 358 Pixmap bm; 359 360 icon_name = LookInNameList(Scr->IconNames, tmp_win->full_name); 361 if (icon_name == NULL) 362 icon_name = LookInList(Scr->IconNames, tmp_win->full_name, 363 &tmp_win->class); 364 365 bm = None; 366 if (icon_name != NULL) 367 { 368 if ((bm = (Pixmap)LookInNameList(Scr->Icons, icon_name)) == None) 369 { 370 if ((bm = GetBitmap (icon_name)) != None) 371 AddToList(&Scr->Icons, icon_name, (char *)bm); 372 } 373 } 374 375 if (bm != None) 376 { 377 XGetGeometry(dpy, bm, &JunkRoot, &JunkX, &JunkY, 378 (unsigned int *) &tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height, 379 &JunkBW, &JunkDepth); 380 381 pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width, 382 tmp_win->icon_height, Scr->d_depth); 383 384 /* the copy plane works on color ! */ 385 XCopyPlane(dpy, bm, pm, Scr->NormalGC, 386 0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 ); 387 388 tmp_win->forced = TRUE; 389 } 390 } 391 392 /* if the pixmap is still NULL, we didn't get one from the above code, 393 * that could mean that ForceIcon was not set, or that the window 394 * was not in the Icons list, now check the WM hints for an icon 395 */ 396 if (pm == None && tmp_win->wmhints && 397 tmp_win->wmhints->flags & IconPixmapHint) 398 { 399 400 XGetGeometry(dpy, tmp_win->wmhints->icon_pixmap, 401 &JunkRoot, &JunkX, &JunkY, 402 (unsigned int *)&tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height, &JunkBW, &JunkDepth); 403 404 pm = XCreatePixmap(dpy, Scr->Root, 405 tmp_win->icon_width, tmp_win->icon_height, 406 Scr->d_depth); 407 408 XCopyPlane(dpy, tmp_win->wmhints->icon_pixmap, pm, Scr->NormalGC, 409 0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 ); 410 } 411 412 /* if we still haven't got an icon, let's look in the Icon list 413 * if ForceIcon is not set 414 */ 415 if (pm == None && !Scr->ForceIcon) 416 { 417 char *icon_name; 418 Pixmap bm; 419 420 icon_name = LookInNameList(Scr->IconNames, tmp_win->full_name); 421 if (icon_name == NULL) 422 icon_name = LookInList(Scr->IconNames, tmp_win->full_name, 423 &tmp_win->class); 424 425 bm = None; 426 if (icon_name != NULL) 427 { 428 if ((bm = (Pixmap)LookInNameList(Scr->Icons, icon_name)) == None) 429 { 430 if ((bm = GetBitmap (icon_name)) != None) 431 AddToList(&Scr->Icons, icon_name, (char *)bm); 432 } 433 } 434 435 if (bm != None) 436 { 437 XGetGeometry(dpy, bm, &JunkRoot, &JunkX, &JunkY, 438 (unsigned int *)&tmp_win->icon_width, (unsigned int *)&tmp_win->icon_height, 439 &JunkBW, &JunkDepth); 440 441 pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width, 442 tmp_win->icon_height, Scr->d_depth); 443 444 /* the copy plane works on color ! */ 445 XCopyPlane(dpy, bm, pm, Scr->NormalGC, 446 0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 ); 447 } 448 } 449 450 /* if we still don't have an icon, assign the UnknownIcon */ 451 452 if (pm == None && Scr->UnknownPm != None) 453 { 454 tmp_win->icon_width = Scr->UnknownWidth; 455 tmp_win->icon_height = Scr->UnknownHeight; 456 457 pm = XCreatePixmap(dpy, Scr->Root, tmp_win->icon_width, 458 tmp_win->icon_height, Scr->d_depth); 459 460 /* the copy plane works on color ! */ 461 XCopyPlane(dpy, Scr->UnknownPm, pm, Scr->NormalGC, 462 0,0, tmp_win->icon_width, tmp_win->icon_height, 0, 0, 1 ); 463 } 464 465 if (pm == None) 466 { 467 tmp_win->icon_height = 0; 468 tmp_win->icon_width = 0; 469 valuemask = 0; 470 } 471 else 472 { 473 valuemask = CWBackPixmap; 474 attributes.background_pixmap = pm; 475 } 476 477 tmp_win->icon_w_width = MyFont_TextWidth(&Scr->IconFont, 478 tmp_win->icon_name, strlen(tmp_win->icon_name)); 479 480 tmp_win->icon_w_width += 6; 481 if (tmp_win->icon_w_width < tmp_win->icon_width) 482 { 483 tmp_win->icon_x = (tmp_win->icon_width - tmp_win->icon_w_width)/2; 484 tmp_win->icon_x += 3; 485 tmp_win->icon_w_width = tmp_win->icon_width; 486 } 487 else 488 { 489 tmp_win->icon_x = 3; 490 } 491 tmp_win->icon_y = tmp_win->icon_height + Scr->IconFont.height; 492 tmp_win->icon_w_height = tmp_win->icon_height + Scr->IconFont.height + 4; 493 494 event_mask = 0; 495 if (tmp_win->wmhints && tmp_win->wmhints->flags & IconWindowHint) 496 { 497 tmp_win->icon_w = tmp_win->wmhints->icon_window; 498 if (tmp_win->forced || 499 XGetGeometry(dpy, tmp_win->icon_w, &JunkRoot, &JunkX, &JunkY, 500 (unsigned int *)&tmp_win->icon_w_width, (unsigned int *)&tmp_win->icon_w_height, 501 &JunkBW, &JunkDepth) == 0) 502 { 503 tmp_win->icon_w = None; 504 tmp_win->wmhints->flags &= ~IconWindowHint; 505 } 506 else 507 { 508 tmp_win->icon_not_ours = TRUE; 509 event_mask = EnterWindowMask | LeaveWindowMask; 510 } 511 } 512 else 513 { 514 tmp_win->icon_w = None; 515 } 516 517 if (tmp_win->icon_w == None) 518 { 519 tmp_win->icon_w = XCreateSimpleWindow(dpy, Scr->Root, 520 0,0, 521 tmp_win->icon_w_width, tmp_win->icon_w_height, 522 Scr->IconBorderWidth, tmp_win->icon_border, tmp_win->iconc.back); 523 event_mask = ExposureMask; 524 } 525 526 XSelectInput (dpy, tmp_win->icon_w, 527 KeyPressMask | ButtonPressMask | ButtonReleaseMask | 528 event_mask); 529 530 tmp_win->icon_bm_w = None; 531 if (pm != None && 532 (! (tmp_win->wmhints && tmp_win->wmhints->flags & IconWindowHint))) 533 { 534 int y; 535 536 y = 0; 537 if (tmp_win->icon_w_width == tmp_win->icon_width) 538 x = 0; 539 else 540 x = (tmp_win->icon_w_width - tmp_win->icon_width)/2; 541 542 tmp_win->icon_bm_w = XCreateWindow (dpy, tmp_win->icon_w, x, y, 543 (unsigned int)tmp_win->icon_width, 544 (unsigned int)tmp_win->icon_height, 545 (unsigned int) 0, Scr->d_depth, 546 (unsigned int) CopyFromParent, 547 Scr->d_visual, valuemask, 548 &attributes); 549 } 550 551 /* I need to figure out where to put the icon window now, because 552 * getting here means that I am going to make the icon visible 553 */ 554 if (tmp_win->wmhints && 555 tmp_win->wmhints->flags & IconPositionHint) 556 { 557 final_x = tmp_win->wmhints->icon_x; 558 final_y = tmp_win->wmhints->icon_y; 559 } 560 else 561 { 562 PlaceIcon(tmp_win, def_x, def_y, &final_x, &final_y); 563 } 564 565 if (final_x > Scr->MyDisplayWidth) 566 final_x = Scr->MyDisplayWidth - tmp_win->icon_w_width - 567 (2 * Scr->IconBorderWidth); 568 569 if (final_y > Scr->MyDisplayHeight) 570 final_y = Scr->MyDisplayHeight - tmp_win->icon_height - 571 Scr->IconFont.height - 4 - (2 * Scr->IconBorderWidth); 572 573 XMoveWindow(dpy, tmp_win->icon_w, final_x, final_y); 574 tmp_win->iconified = TRUE; 575 576 XMapSubwindows(dpy, tmp_win->icon_w); 577 XSaveContext(dpy, tmp_win->icon_w, TwmContext, (caddr_t)tmp_win); 578 XSaveContext(dpy, tmp_win->icon_w, ScreenContext, (caddr_t)Scr); 579 XDefineCursor(dpy, tmp_win->icon_w, Scr->IconCursor); 580 if (pm) XFreePixmap (dpy, pm); 581 return; 582} 583