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