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