iconmgr.c revision 6d8e82c3
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 Manager routines 29 * 30 * 09-Mar-89 Tom LaStrange File Created 31 * 32 ***********************************************************************/ 33 34#include <stdio.h> 35#include "twm.h" 36#include "util.h" 37#include "parse.h" 38#include "screen.h" 39#include "resize.h" 40#include "add_window.h" 41#include "siconify.bm" 42#include <X11/Xos.h> 43#include <X11/Xmu/CharSet.h> 44 45static void InsertInIconManager(IconMgr *ip, WList *tmp, TwmWindow *tmp_win); 46 47int iconmgr_textx = siconify_width + 11; 48static WList *Active = NULL; 49WList *DownIconManager = NULL; 50int iconifybox_width = siconify_width; 51int iconifybox_height = siconify_height; 52 53/** 54 * create all the icon manager windows for this screen. 55 */ 56void 57CreateIconManagers(void) 58{ 59 IconMgr *p; 60 char str[100]; 61 char str1[100]; 62 Pixel background; 63 const char *icon_name; 64 65 if (Scr->NoIconManagers) 66 return; 67 68 if (Scr->siconifyPm == None) { 69 Scr->siconifyPm = XCreatePixmapFromBitmapData(dpy, Scr->Root, 70 (char *) siconify_bits, 71 siconify_width, 72 siconify_height, 1, 0, 1); 73 } 74 75 for (p = &Scr->iconmgr; p != NULL; p = p->next) { 76 int x = 0; 77 int y = 0; 78 int mask = XParseGeometry(p->geometry, &x, &y, 79 (unsigned int *) &p->width, 80 (unsigned int *) &p->height); 81 82 if (mask & XNegative) 83 x += Scr->MyDisplayWidth - p->width - (2 * Scr->BorderWidth); 84 85 if (mask & YNegative) 86 y += Scr->MyDisplayHeight - p->height - (2 * Scr->BorderWidth); 87 88 background = Scr->IconManagerC.back; 89 GetColorFromList(Scr->IconManagerBL, p->name, (XClassHint *) NULL, 90 &background); 91 92 p->w = XCreateSimpleWindow(dpy, Scr->Root, x, y, 93 (unsigned) p->width, (unsigned) p->height, 94 1, Scr->Black, background); 95 96 snprintf(str, sizeof(str), "%s Icon Manager", p->name); 97 snprintf(str1, sizeof(str1), "%s Icons", p->name); 98 if (p->icon_name) 99 icon_name = p->icon_name; 100 else 101 icon_name = str1; 102 103 XSetStandardProperties(dpy, p->w, str, icon_name, None, NULL, 0, NULL); 104 105 p->twm_win = AddWindow(p->w, TRUE, p); 106 SetMapStateProp(p->twm_win, WithdrawnState); 107 } 108 for (p = &Scr->iconmgr; p != NULL; p = p->next) { 109 GrabButtons(p->twm_win); 110 GrabKeys(p->twm_win); 111 } 112} 113 114/** 115 * allocate a new icon manager 116 * 117 * \param name the name of this icon manager 118 * \param con_name the name of the associated icon 119 * \param geom a geometry string to eventually parse 120 * \param columns the number of columns this icon manager has 121 */ 122IconMgr * 123AllocateIconManager(char *name, char *icon_name, char *geom, int columns) 124{ 125 IconMgr *p; 126 127#ifdef DEBUG_ICONMGR 128 fprintf(stderr, "AllocateIconManager\n"); 129 fprintf(stderr, " name=\"%s\" icon_name=\"%s\", geom=\"%s\", col=%d\n", 130 name, icon_name ? icon_name : "<null>", geom, columns); 131#endif 132 133 if (Scr->NoIconManagers) 134 return NULL; 135 136 p = (IconMgr *) malloc(sizeof(IconMgr)); 137 p->name = name; 138 p->icon_name = icon_name; 139 p->geometry = geom; 140 p->columns = columns; 141 p->first = NULL; 142 p->last = NULL; 143 p->active = NULL; 144 p->scr = Scr; 145 p->count = 0; 146 p->x = 0; 147 p->y = 0; 148 p->width = 150; 149 p->height = 10; 150 151 Scr->iconmgr.lasti->next = p; 152 p->prev = Scr->iconmgr.lasti; 153 Scr->iconmgr.lasti = p; 154 p->next = NULL; 155 156 return (p); 157} 158 159/** 160 * move the pointer around in an icon manager 161 * 162 * \param dir one of the following: 163 * - F_FORWICONMGR: forward in the window list 164 * - F_BACKICONMGR: backward in the window list 165 * - F_UPICONMGR: up one row 166 * - F_DOWNICONMG: down one row 167 * - F_LEFTICONMGR: left one column 168 * - F_RIGHTICONMGR: right one column 169 */ 170void 171MoveIconManager(int dir) 172{ 173 IconMgr *ip; 174 WList *tmp = NULL; 175 int cur_row, cur_col, new_row, new_col; 176 int row_inc, col_inc; 177 int got_it; 178 179 if (!Active) 180 return; 181 182 cur_row = Active->row; 183 cur_col = Active->col; 184 ip = Active->iconmgr; 185 186 row_inc = 0; 187 col_inc = 0; 188 got_it = FALSE; 189 190 switch (dir) { 191 case F_FORWICONMGR: 192 if ((tmp = Active->next) == NULL) 193 tmp = ip->first; 194 got_it = TRUE; 195 break; 196 197 case F_BACKICONMGR: 198 if ((tmp = Active->prev) == NULL) 199 tmp = ip->last; 200 got_it = TRUE; 201 break; 202 203 case F_UPICONMGR: 204 row_inc = -1; 205 break; 206 207 case F_DOWNICONMGR: 208 row_inc = 1; 209 break; 210 211 case F_LEFTICONMGR: 212 col_inc = -1; 213 break; 214 215 case F_RIGHTICONMGR: 216 col_inc = 1; 217 break; 218 } 219 220 /* If got_it is FALSE ast this point then we got a left, right, 221 * up, or down, command. We will enter this loop until we find 222 * a window to warp to. 223 */ 224 new_row = cur_row; 225 new_col = cur_col; 226 227 while (!got_it) { 228 new_row += row_inc; 229 new_col += col_inc; 230 if (new_row < 0) 231 new_row = ip->cur_rows - 1; 232 if (new_col < 0) 233 new_col = ip->cur_columns - 1; 234 if (new_row >= ip->cur_rows) 235 new_row = 0; 236 if (new_col >= ip->cur_columns) 237 new_col = 0; 238 239 /* Now let's go through the list to see if there is an entry with this 240 * new position 241 */ 242 for (tmp = ip->first; tmp != NULL; tmp = tmp->next) { 243 if (tmp->row == new_row && tmp->col == new_col) { 244 got_it = TRUE; 245 break; 246 } 247 } 248 } 249 250 if (!got_it) { 251 twmWarning("unable to find window (%d, %d) in icon manager", 252 new_row, new_col); 253 return; 254 } 255 256 if (tmp == NULL) 257 return; 258 259 /* raise the frame so the icon manager is visible */ 260 if (ip->twm_win->mapped) { 261 XRaiseWindow(dpy, ip->twm_win->frame); 262 XWarpPointer(dpy, None, tmp->icon, 0, 0, 0, 0, 5, 5); 263 } 264 else { 265 if (tmp->twm->title_height) { 266 int tbx = Scr->TBInfo.titlex; 267 int x = tmp->twm->highlightx; 268 269 XWarpPointer(dpy, None, tmp->twm->title_w, 0, 0, 0, 0, 270 tbx + (x - tbx) / 2, Scr->TitleHeight / 4); 271 } 272 else { 273 XWarpPointer(dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5); 274 } 275 } 276} 277 278/** 279 * jump from one icon manager to another, possibly even on another screen 280 * \param dir one of the following: 281 * - F_NEXTICONMGR - go to the next icon manager 282 * - F_PREVICONMGR - go to the previous one 283 */ 284 285void 286JumpIconManager(int dir) 287{ 288 IconMgr *ip, *tmp_ip = NULL; 289 int got_it = FALSE; 290 291 if (!Active) 292 return; 293 294#define ITER(i) (dir == F_NEXTICONMGR ? (i)->next : (i)->prev) 295#define IPOFSP(sp) (dir == F_NEXTICONMGR ? &(sp->iconmgr) : sp->iconmgr.lasti) 296#define TEST(ip) if ((ip)->count != 0 && (ip)->twm_win->mapped) \ 297 { got_it = TRUE; break; } 298 299 ip = Active->iconmgr; 300 for (tmp_ip = ITER(ip); tmp_ip; tmp_ip = ITER(tmp_ip)) { 301 TEST(tmp_ip); 302 } 303 304 if (!got_it) { 305 int origscreen = ip->scr->screen; 306 int inc = (dir == F_NEXTICONMGR ? 1 : -1); 307 int screen; 308 309 for (screen = origscreen + inc;; screen += inc) { 310 ScreenInfo *sp; 311 312 if (screen >= NumScreens) 313 screen = 0; 314 else if (screen < 0) 315 screen = NumScreens - 1; 316 317 sp = ScreenList[screen]; 318 if (sp) { 319 for (tmp_ip = IPOFSP(sp); tmp_ip; tmp_ip = ITER(tmp_ip)) { 320 TEST(tmp_ip); 321 } 322 } 323 if (got_it || screen == origscreen) 324 break; 325 } 326 } 327 328#undef ITER 329#undef IPOFSP 330#undef TEST 331 332 if (!got_it) { 333 Bell(XkbBI_MinorError, 0, None); 334 return; 335 } 336 337 /* raise the frame so it is visible */ 338 XRaiseWindow(dpy, tmp_ip->twm_win->frame); 339 if (tmp_ip->active) 340 XWarpPointer(dpy, None, tmp_ip->active->icon, 0, 0, 0, 0, 5, 5); 341 else 342 XWarpPointer(dpy, None, tmp_ip->w, 0, 0, 0, 0, 5, 5); 343} 344 345/** 346 * add a window to an icon manager 347 * 348 * \param tmp_win the TwmWindow structure 349 */ 350WList * 351AddIconManager(TwmWindow *tmp_win) 352{ 353 WList *tmp; 354 int h; 355 unsigned long valuemask; /* mask for create windows */ 356 XSetWindowAttributes attributes; /* attributes for create windows */ 357 IconMgr *ip; 358 359 tmp_win->list = NULL; 360 361 if (tmp_win->iconmgr || tmp_win->transient || Scr->NoIconManagers) 362 return NULL; 363 364 if (LookInList(Scr->IconMgrNoShow, tmp_win->full_name, &tmp_win->xclass)) 365 return NULL; 366 if (Scr->IconManagerDontShow && 367 !LookInList(Scr->IconMgrShow, tmp_win->full_name, &tmp_win->xclass)) 368 return NULL; 369 if ((ip = (IconMgr *) LookInList(Scr->IconMgrs, tmp_win->full_name, 370 &tmp_win->xclass)) == NULL) 371 ip = &Scr->iconmgr; 372 373 tmp = (WList *) malloc(sizeof(WList)); 374 tmp->iconmgr = ip; 375 tmp->next = NULL; 376 tmp->active = FALSE; 377 tmp->down = FALSE; 378 379 InsertInIconManager(ip, tmp, tmp_win); 380 381 tmp->twm = tmp_win; 382 383 tmp->fore = Scr->IconManagerC.fore; 384 tmp->back = Scr->IconManagerC.back; 385 tmp->highlight = Scr->IconManagerHighlight; 386 387 GetColorFromList(Scr->IconManagerFL, tmp_win->full_name, &tmp_win->xclass, 388 &tmp->fore); 389 GetColorFromList(Scr->IconManagerBL, tmp_win->full_name, &tmp_win->xclass, 390 &tmp->back); 391 GetColorFromList(Scr->IconManagerHighlightL, tmp_win->full_name, 392 &tmp_win->xclass, &tmp->highlight); 393 394 h = Scr->IconManagerFont.height + 10; 395 if (h < (siconify_height + 4)) 396 h = siconify_height + 4; 397 398 ip->height = h * ip->count; 399 tmp->me = ip->count; 400 tmp->x = -1; 401 tmp->y = -1; 402 403 valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor); 404 attributes.background_pixel = tmp->back; 405 attributes.border_pixel = tmp->back; 406 attributes.event_mask = (KeyPressMask | ButtonPressMask | 407 ButtonReleaseMask | ExposureMask | 408 EnterWindowMask | LeaveWindowMask); 409 attributes.cursor = Scr->IconMgrCursor; 410 tmp->w = XCreateWindow(dpy, ip->w, 0, 0, (unsigned int) 1, 411 (unsigned int) h, (unsigned int) 0, 412 CopyFromParent, (unsigned int) CopyFromParent, 413 (Visual *) CopyFromParent, valuemask, &attributes); 414 415 valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor); 416 attributes.background_pixel = tmp->back; 417 attributes.border_pixel = Scr->Black; 418 attributes.event_mask = (ButtonReleaseMask | ButtonPressMask | 419 ExposureMask); 420 attributes.cursor = Scr->ButtonCursor; 421 tmp->icon = XCreateWindow(dpy, tmp->w, 5, (int) (h - siconify_height) / 2, 422 (unsigned int) siconify_width, 423 (unsigned int) siconify_height, 424 (unsigned int) 0, CopyFromParent, 425 (unsigned int) CopyFromParent, 426 (Visual *) CopyFromParent, 427 valuemask, &attributes); 428 429 ip->count += 1; 430 PackIconManager(ip); 431 XMapWindow(dpy, tmp->w); 432 433 XSaveContext(dpy, tmp->w, IconManagerContext, (XPointer) tmp); 434 XSaveContext(dpy, tmp->w, TwmContext, (XPointer) tmp_win); 435 XSaveContext(dpy, tmp->w, ScreenContext, (XPointer) Scr); 436 XSaveContext(dpy, tmp->icon, TwmContext, (XPointer) tmp_win); 437 XSaveContext(dpy, tmp->icon, ScreenContext, (XPointer) Scr); 438 tmp_win->list = tmp; 439 440 if (!ip->twm_win->icon) { 441 XMapWindow(dpy, ip->w); 442 XMapWindow(dpy, ip->twm_win->frame); 443 } 444 445 if (Active == NULL) 446 Active = tmp; 447 448 return (tmp); 449} 450 451/** 452 * put an allocated entry into an icon manager 453 * 454 * \param ip the icon manager pointer 455 * \param tmp the entry to insert 456 */ 457static void 458InsertInIconManager(IconMgr *ip, WList *tmp, TwmWindow *tmp_win) 459{ 460 WList *tmp1; 461 int added; 462 int (*compar) (const char *, const char *) 463 = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1); 464 465 added = FALSE; 466 if (ip->first == NULL) { 467 ip->first = tmp; 468 tmp->prev = NULL; 469 ip->last = tmp; 470 added = TRUE; 471 } 472 else if (Scr->SortIconMgr) { 473 for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) { 474 if ((*compar) (tmp_win->icon_name, tmp1->twm->icon_name) < 0) { 475 tmp->next = tmp1; 476 tmp->prev = tmp1->prev; 477 tmp1->prev = tmp; 478 if (tmp->prev == NULL) 479 ip->first = tmp; 480 else 481 tmp->prev->next = tmp; 482 added = TRUE; 483 break; 484 } 485 } 486 } 487 488 if (!added) { 489 ip->last->next = tmp; 490 tmp->prev = ip->last; 491 ip->last = tmp; 492 } 493} 494 495static void 496RemoveFromIconManager(IconMgr *ip, WList *tmp) 497{ 498 if (tmp->prev == NULL) 499 ip->first = tmp->next; 500 else 501 tmp->prev->next = tmp->next; 502 503 if (tmp->next == NULL) 504 ip->last = tmp->prev; 505 else 506 tmp->next->prev = tmp->prev; 507} 508 509/** 510 * remove a window from the icon manager 511 * \param tmp_win the TwmWindow structure 512 */ 513void 514RemoveIconManager(TwmWindow *tmp_win) 515{ 516 IconMgr *ip; 517 WList *tmp; 518 519 if (tmp_win->list == NULL) 520 return; 521 522 tmp = tmp_win->list; 523 tmp_win->list = NULL; 524 ip = tmp->iconmgr; 525 526 RemoveFromIconManager(ip, tmp); 527 528 XDeleteContext(dpy, tmp->icon, TwmContext); 529 XDeleteContext(dpy, tmp->icon, ScreenContext); 530 XDestroyWindow(dpy, tmp->icon); 531 XDeleteContext(dpy, tmp->w, IconManagerContext); 532 XDeleteContext(dpy, tmp->w, TwmContext); 533 XDeleteContext(dpy, tmp->w, ScreenContext); 534 XDestroyWindow(dpy, tmp->w); 535 ip->count -= 1; 536 free(tmp); 537 538 PackIconManager(ip); 539 540 if (ip->count == 0) { 541 XUnmapWindow(dpy, ip->twm_win->frame); 542 } 543 544} 545 546void 547ActiveIconManager(WList *active) 548{ 549 active->active = TRUE; 550 Active = active; 551 Active->iconmgr->active = active; 552 DrawIconManagerBorder(active); 553} 554 555void 556NotActiveIconManager(WList *active) 557{ 558 active->active = FALSE; 559 DrawIconManagerBorder(active); 560} 561 562void 563DrawIconManagerBorder(WList *tmp) 564{ 565 { 566 XSetForeground(dpy, Scr->NormalGC, tmp->fore); 567 XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 2, 2, 568 (unsigned) (tmp->width - 5), 569 (unsigned) (tmp->height - 5)); 570 571 if (tmp->active && Scr->Highlight) 572 XSetForeground(dpy, Scr->NormalGC, tmp->highlight); 573 else 574 XSetForeground(dpy, Scr->NormalGC, tmp->back); 575 576 XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 0, 0, 577 (unsigned) (tmp->width - 1), 578 (unsigned) (tmp->height - 1)); 579 XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 1, 1, 580 (unsigned) (tmp->width - 3), 581 (unsigned) (tmp->height - 3)); 582 } 583} 584 585/** 586 * sort The Dude 587 * 588 * \param ip a pointer to the icon manager structure 589 */ 590void 591SortIconManager(IconMgr *ip) 592{ 593 WList *tmp1, *tmp2; 594 int done; 595 int (*compar) (const char *, const char *) 596 = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1); 597 598 if (ip == NULL) 599 ip = Active->iconmgr; 600 601 done = FALSE; 602 do { 603 for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) { 604 if ((tmp2 = tmp1->next) == NULL) { 605 done = TRUE; 606 break; 607 } 608 if ((*compar) (tmp1->twm->icon_name, tmp2->twm->icon_name) > 0) { 609 /* take it out and put it back in */ 610 RemoveFromIconManager(ip, tmp2); 611 InsertInIconManager(ip, tmp2, tmp2->twm); 612 break; 613 } 614 } 615 } 616 while (!done); 617 PackIconManager(ip); 618} 619 620/** 621 * pack the icon manager windows following 622 * an addition or deletion 623 * 624 * \param ip a pointer to the icon manager structure 625 */ 626void 627PackIconManager(IconMgr *ip) 628{ 629 int newwidth, i, row, col, maxcol, colinc, rowinc, wheight, wwidth; 630 int savewidth; 631 WList *tmp; 632 633 wheight = Scr->IconManagerFont.height + 10; 634 if (wheight < (siconify_height + 4)) 635 wheight = siconify_height + 4; 636 637 wwidth = ip->width / ip->columns; 638 639 rowinc = wheight; 640 colinc = wwidth; 641 642 row = 0; 643 col = ip->columns; 644 maxcol = 0; 645 646 for (i = 0, tmp = ip->first; tmp != NULL; i++, tmp = tmp->next) { 647 int new_x, new_y; 648 649 tmp->me = i; 650 if (++col >= ip->columns) { 651 col = 0; 652 row += 1; 653 } 654 if (col > maxcol) 655 maxcol = col; 656 657 new_x = col * colinc; 658 new_y = (row - 1) * rowinc; 659 660 /* if the position or size has not changed, don't touch it */ 661 if (tmp->x != new_x || tmp->y != new_y || 662 tmp->width != wwidth || tmp->height != wheight) { 663 XMoveResizeWindow(dpy, tmp->w, 664 new_x, new_y, 665 (unsigned) wwidth, (unsigned) wheight); 666 667 tmp->row = row - 1; 668 tmp->col = col; 669 tmp->x = new_x; 670 tmp->y = new_y; 671 tmp->width = wwidth; 672 tmp->height = wheight; 673 } 674 } 675 maxcol += 1; 676 677 ip->cur_rows = row; 678 ip->cur_columns = maxcol; 679 ip->height = row * rowinc; 680 if (ip->height == 0) 681 ip->height = rowinc; 682 newwidth = maxcol * colinc; 683 if (newwidth == 0) 684 newwidth = colinc; 685 686 XResizeWindow(dpy, ip->w, (unsigned) newwidth, (unsigned) ip->height); 687 688 savewidth = ip->width; 689 if (ip->twm_win) 690 SetupWindow(ip->twm_win, 691 ip->twm_win->frame_x, ip->twm_win->frame_y, 692 newwidth, ip->height + ip->twm_win->title_height, -1); 693 ip->width = savewidth; 694} 695