1/* 2 * Copyright 1989 Massachusetts Institute of Technology 3 * Copyright 1992 Claude Lecommandeur. 4 */ 5 6/*********************************************************************** 7 * 8 * $XConsortium: iconmgr.c,v 1.48 91/09/10 15:27:07 dave Exp $ 9 * 10 * Icon Manager routines 11 * 12 * 09-Mar-89 Tom LaStrange File Created 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#include <string.h> 27#include <strings.h> 28 29#include <X11/Xatom.h> 30 31#include "util.h" 32#include "iconmgr.h" 33#include "icons_builtin.h" 34#include "screen.h" 35#include "drawing.h" 36#include "functions_defs.h" 37#include "list.h" 38#include "occupation.h" 39#include "otp.h" 40#include "add_window.h" 41#include "gram.tab.h" 42#include "vscreen.h" 43#include "win_decorations.h" 44#include "win_resize.h" 45#include "win_utils.h" 46#include "xparsegeometry.h" 47 48 49/* Where we start drawing the name in the icon manager */ 50static int iconmgr_textx; 51 52static WList *Active = NULL; 53static WList *Current = NULL; 54WList *DownIconManager = NULL; 55 56/*********************************************************************** 57 * 58 * Procedure: 59 * CreateIconManagers - creat all the icon manager windows 60 * for this screen. 61 * 62 * Returned Value: 63 * none 64 * 65 * Inputs: 66 * none 67 * 68 *********************************************************************** 69 */ 70 71void CreateIconManagers(void) 72{ 73 WorkSpace *ws; 74 75 if(Scr->NoIconManagers) { 76 return; 77 } 78 79 /* 80 * Move past the iconified icon to start the text. 81 * XXX Semi-arbitrary magic add'l padding, to deal with various inner 82 * positioning of the icon subwindow. Be smarter (or at least 83 * clearer) about this... 84 */ 85 iconmgr_textx = im_iconified_icon_width + 11; 86 if(Scr->use3Diconmanagers) { 87 iconmgr_textx += Scr->IconManagerShadowDepth; 88 } 89 90 if(Scr->siconifyPm == None) { 91 Scr->siconifyPm = Create2DIconManagerIcon(); 92 } 93 94 // This loop is confusing. The inner for() loops p over the ->next 95 // elements in the list, which is all the iconmgr's in the workspace. 96 // The outer for() loops q over the ->nextv (<-- extra 'v' on the 97 // end), which is a link to the head of the iconmgr list for the 98 // _next_ workspace. 99 ws = Scr->workSpaceMgr.workSpaceList; 100 for(IconMgr *q = Scr->iconmgr; q != NULL; q = q->nextv) { 101 for(IconMgr *p = q; p != NULL; p = p->next) { 102 int gx, gy; 103 char imname[100]; 104 int mask; 105 int gravity; 106 int bw; 107 Pixel background; 108 109 snprintf(imname, sizeof(imname), "%s Icon Manager", p->name); 110 111 if(!p->geometry || !strlen(p->geometry)) { 112 p->geometry = "+0+0"; 113 } 114 mask = RLayoutXParseGeometry(Scr->Layout, p->geometry, 115 &gx, &gy, 116 (unsigned int *) &p->width, (unsigned int *)&p->height); 117 118 bw = LookInList(Scr->NoBorder, imname, NULL) ? 0 : 119 (Scr->ThreeDBorderWidth ? Scr->ThreeDBorderWidth : Scr->BorderWidth); 120 121 if(mask & XNegative) { 122 gx += Scr->rootw - p->width - 2 * bw; 123 gravity = (mask & YNegative) ? SouthEastGravity : NorthEastGravity; 124 } 125 else { 126 gravity = (mask & YNegative) ? SouthWestGravity : NorthWestGravity; 127 } 128 if(mask & YNegative) { 129 gy += Scr->rooth - p->height - 2 * bw; 130 } 131 132 background = Scr->IconManagerC.back; 133 GetColorFromList(Scr->IconManagerBL, p->name, NULL, 134 &background); 135 136 if(p->width < 1) { 137 p->width = 1; 138 } 139 if(p->height < 1) { 140 p->height = 1; 141 } 142 p->w = XCreateSimpleWindow(dpy, Scr->Root, 143 gx, gy, p->width, p->height, 1, 144 Scr->Black, background); 145 146 147 /* Scr->workSpaceMgr.activeWSPC = ws; */ 148 149 /* Setup various WM properties on the iconmgr's window */ 150 { 151 char *icon_name; 152 XWMHints wmhints; 153 XClassHint clhints; 154 155 if(p->icon_name) { 156 icon_name = strdup(p->icon_name); 157 } 158 else { 159 asprintf(&icon_name, "%s Icons", p->name); 160 } 161 162 wmhints.initial_state = NormalState; 163 wmhints.input = True; 164 wmhints.flags = InputHint | StateHint; 165 166 clhints.res_name = icon_name; 167 clhints.res_class = "TwmIconManager"; 168 169 XmbSetWMProperties(dpy, p->w, imname, icon_name, NULL, 0, NULL, 170 &wmhints, &clhints); 171 free(icon_name); 172 } 173 174 175 p->twm_win = AddWindow(p->w, AWT_ICON_MANAGER, p, Scr->currentvs); 176 177 // SetupOccupation() called from AddWindow() doesn't setup 178 // occupation for icon managers, nor clear vs if occupation 179 // lacks. So make it occupy the one we're setting up, or the 180 // 1st if we ran out somehow... 181 if(ws) { 182 p->twm_win->occupation = 1 << ws->number; 183 184 // ConfigureWorkSpaceManager() ran before us, so we can 185 // tell whether we're in the ws to reveal this IM. 186 if(ws->number != Scr->currentvs->wsw->currentwspc->number) { 187 p->twm_win->vs = NULL; 188 } 189 } 190 else { 191 p->twm_win->occupation = 1; 192 } 193 194#ifdef DEBUG_ICONMGR 195 fprintf(stderr, 196 "CreateIconManagers: IconMgr %p: twm_win=%p win=0x%lx " 197 "name='%s' x=%d y=%d w=%d h=%d occupation=%x\n", 198 p, p->twm_win, p->twm_win->w, p->name, 199 gx, gy, p->width, p->height, p->twm_win->occupation); 200#endif 201 202 { 203 XSizeHints sizehints; 204 205 sizehints.flags = PWinGravity; 206 sizehints.win_gravity = gravity; 207 XSetWMSizeHints(dpy, p->w, &sizehints, XA_WM_NORMAL_HINTS); 208 } 209 210 p->twm_win->mapped = false; 211 SetMapStateProp(p->twm_win, WithdrawnState); 212 if(p->twm_win && (p->twm_win->wmhints->initial_state == IconicState)) { 213 p->twm_win->isicon = true; 214 } 215 else if(!Scr->NoIconManagers && Scr->ShowIconManager) { 216 p->twm_win->isicon = false; 217 } 218 else { 219 p->twm_win->isicon = true; 220 } 221 } 222 if(ws != NULL) { 223 ws = ws->next; 224 } 225 } 226 227 if(Scr->workSpaceManagerActive) { 228 Scr->workSpaceMgr.workSpaceList->iconmgr = Scr->iconmgr; 229 } 230 231 232 /* 233 * Grab buttons/keystrokes for icon managers appropriately. 234 * Normally, this is done in AddWindow(), but it explicitly skips it 235 * for icon managers. It's not at all clear why GrabButtons() would 236 * do so; I don't think it needs to. GrabKeys() does do some looping 237 * over the Scr->iconmgr list at the end though, so it's possible we 238 * need to delay calling it until now when the list is all filled up. 239 * This needs further investigation; it may be that the special case 240 * and this code can be removed. X-ref comments in add_window.c 241 * about it. 242 */ 243 for(IconMgr *q = Scr->iconmgr; q != NULL; q = q->nextv) { 244 for(IconMgr *p = q; p != NULL; p = p->next) { 245 GrabButtons(p->twm_win); 246 GrabKeys(p->twm_win); 247 } 248 } 249 250} 251 252/*********************************************************************** 253 * 254 * Procedure: 255 * AllocateIconManager - allocate a new icon manager 256 * 257 * Inputs: 258 * name - the name of this icon manager 259 * icon_name - the name of the associated icon 260 * geom - a geometry string to eventually parse 261 * columns - the number of columns this icon manager has 262 * 263 *********************************************************************** 264 */ 265 266IconMgr *AllocateIconManager(char *name, char *icon_name, char *geom, 267 int columns) 268{ 269 IconMgr *p; 270 271#ifdef DEBUG_ICONMGR 272 fprintf(stderr, "AllocateIconManager\n"); 273 fprintf(stderr, " name=\"%s\" icon_name=\"%s\", geom=\"%s\", col=%d\n", 274 name, icon_name, geom, columns); 275#endif 276 277 if(Scr->NoIconManagers) { 278 return NULL; 279 } 280 281 if(columns < 1) { 282 columns = 1; 283 } 284 p = calloc(1, sizeof(IconMgr)); 285 p->name = name; 286 p->icon_name = icon_name; 287 p->geometry = geom; 288 p->columns = columns; 289 p->scr = Scr; 290 p->width = 150; 291 p->height = 10; 292 293 if(Scr->iconmgr == NULL) { 294 Scr->iconmgr = p; 295 Scr->iconmgr->lasti = p; 296 } 297 else { 298 Scr->iconmgr->lasti->next = p; 299 p->prev = Scr->iconmgr->lasti; 300 Scr->iconmgr->lasti = p; 301 } 302 return(p); 303} 304 305 306/* 307 * Each workspace has its own [set of] icon manager[s]. The initial main 308 * one was setup via AllocateIconManager() early in startup. The others 309 * were setup during parsing the config file. Then this gets called late 310 * in startup, after all the workspaces are setup, to copy them all into 311 * each one. 312 * 313 * Note this is distinct from CreateIconManagers(); that creates and 314 * draws the windows, this creates and connects up the data structures. 315 */ 316void AllocateOtherIconManagers(void) 317{ 318 IconMgr *imfirst; // First IM on each workspace 319 WorkSpace *ws; 320 321 /* No defined workspaces? Nothing to do. */ 322 if(! Scr->workSpaceManagerActive) { 323 return; 324 } 325 326 /* The first workspace just gets the ones we already have */ 327 ws = Scr->workSpaceMgr.workSpaceList; 328 ws->iconmgr = Scr->iconmgr; 329 330 /* From the second on, we start copying */ 331 imfirst = ws->iconmgr; 332 for(ws = ws->next; ws != NULL; ws = ws->next) { 333 IconMgr *ip, *previ, *p = NULL; 334 335 /* Copy in the first iconmgr */ 336 ws->iconmgr = malloc(sizeof(IconMgr)); 337 *ws->iconmgr = *imfirst; 338 339 /* 340 * This first is now the nextv to the first in the previous WS, 341 * and we don't [yet] have a nextv of our own. 342 * */ 343 imfirst->nextv = ws->iconmgr; 344 ws->iconmgr->nextv = NULL; 345 346 /* 347 * Start from the second, and copy them each from the prior 348 * workspace we just went through. 349 * */ 350 previ = ws->iconmgr; 351 for(ip = imfirst->next; ip != NULL; ip = ip->next) { 352 /* Copy the base bits */ 353 p = malloc(sizeof(IconMgr)); 354 *p = *ip; 355 356 /* Link up the double-links, and there's no nextv [yet] */ 357 previ->next = p; 358 p->prev = previ; 359 p->next = NULL; 360 p->nextv = NULL; 361 362 /* We're now the nextv to that one in the old workspace */ 363 ip->nextv = p; 364 365 /* And back around to the next one to copy into this WS */ 366 previ = p; 367 } 368 369 /* Each one has a pointer to the last IM in this WS, so save those */ 370 for(ip = ws->iconmgr; ip != NULL; ip = ip->next) { 371 ip->lasti = p; 372 } 373 374 /* 375 * And back around to the next workspace, which works from those 376 * we made for this WS. We go from imfirst rather than 377 * Scr->iconmgr so the ip->nextv rewrites are correct above; we 378 * have to fill them in on the next loop. 379 */ 380 imfirst = ws->iconmgr; 381 } 382} 383 384 385/*********************************************************************** 386 * 387 * Procedure: 388 * MoveIconManager - move the pointer around in an icon manager 389 * 390 * Inputs: 391 * dir - one of the following: 392 * F_FORWICONMGR - forward in the window list 393 * F_BACKICONMGR - backward in the window list 394 * F_UPICONMGR - up one row 395 * F_DOWNICONMGR - down one row 396 * F_LEFTICONMGR - left one column 397 * F_RIGHTICONMGR - right one column 398 * 399 * Special Considerations: 400 * none 401 * 402 *********************************************************************** 403 */ 404 405void MoveIconManager(int dir) 406{ 407 IconMgr *ip; 408 WList *tmp = NULL; 409 int cur_row, cur_col, new_row, new_col; 410 int row_inc, col_inc; 411 bool got_it; 412 413 if(!Current) { 414 return; 415 } 416 417 cur_row = Current->row; 418 cur_col = Current->col; 419 ip = Current->iconmgr; 420 421 row_inc = 0; 422 col_inc = 0; 423 got_it = false; 424 425 switch(dir) { 426 case F_FORWICONMGR: 427 if((tmp = Current->next) == NULL) { 428 tmp = ip->first; 429 } 430 got_it = true; 431 break; 432 433 case F_BACKICONMGR: 434 if((tmp = Current->prev) == NULL) { 435 tmp = ip->last; 436 } 437 got_it = true; 438 break; 439 440 case F_UPICONMGR: 441 row_inc = -1; 442 break; 443 444 case F_DOWNICONMGR: 445 row_inc = 1; 446 break; 447 448 case F_LEFTICONMGR: 449 col_inc = -1; 450 break; 451 452 case F_RIGHTICONMGR: 453 col_inc = 1; 454 break; 455 } 456 457 /* If got_it is false ast this point then we got a left, right, 458 * up, or down, command. We will enter this loop until we find 459 * a window to warp to. 460 */ 461 new_row = cur_row; 462 new_col = cur_col; 463 464 while(!got_it) { 465 new_row += row_inc; 466 new_col += col_inc; 467 if(new_row < 0) { 468 new_row = ip->cur_rows - 1; 469 } 470 if(new_col < 0) { 471 new_col = ip->cur_columns - 1; 472 } 473 if(new_row >= ip->cur_rows) { 474 new_row = 0; 475 } 476 if(new_col >= ip->cur_columns) { 477 new_col = 0; 478 } 479 480 /* Now let's go through the list to see if there is an entry with this 481 * new position 482 */ 483 for(tmp = ip->first; tmp != NULL; tmp = tmp->next) { 484 if(tmp->row == new_row && tmp->col == new_col) { 485 got_it = true; 486 break; 487 } 488 } 489 } 490 491 if(!got_it) { 492 fprintf(stderr, 493 "%s: unable to find window (%d, %d) in icon manager\n", 494 ProgramName, new_row, new_col); 495 return; 496 } 497 498 if(tmp == NULL) { 499 return; 500 } 501 502 /* raise the frame so the icon manager is visible */ 503 if(ip->twm_win->mapped) { 504 OtpRaise(ip->twm_win, WinWin); 505 XWarpPointer(dpy, None, tmp->icon, 0, 0, 0, 0, 5, 5); 506 } 507 else { 508 if(tmp->twm->title_height) { 509 int tbx = Scr->TBInfo.titlex; 510 int x = tmp->twm->highlightxr; 511 XWarpPointer(dpy, None, tmp->twm->title_w, 0, 0, 0, 0, 512 tbx + (x - tbx) / 2, 513 Scr->TitleHeight / 4); 514 } 515 else { 516 XWarpPointer(dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5); 517 } 518 } 519} 520 521/*********************************************************************** 522 * 523 * Procedure: 524 * MoveMappedIconManager - move the pointer around in an icon manager 525 * 526 * Inputs: 527 * dir - one of the following: 528 * F_FORWMAPICONMGR - forward in the window list 529 * F_BACKMAPICONMGR - backward in the window list 530 * 531 * Special Considerations: 532 * none 533 * 534 *********************************************************************** 535 */ 536 537void MoveMappedIconManager(int dir) 538{ 539 IconMgr *ip; 540 WList *tmp = NULL; 541 WList *orig = NULL; 542 bool got_it; 543 544 if(!Current) { 545 Current = Active; 546 } 547 if(!Current) { 548 return; 549 } 550 551 ip = Current->iconmgr; 552 553 got_it = false; 554 tmp = Current; 555 orig = Current; 556 557 while(!got_it) { 558 switch(dir) { 559 case F_FORWMAPICONMGR: 560 if((tmp = tmp->next) == NULL) { 561 tmp = ip->first; 562 } 563 break; 564 565 case F_BACKMAPICONMGR: 566 if((tmp = tmp->prev) == NULL) { 567 tmp = ip->last; 568 } 569 break; 570 } 571 if(tmp->twm->mapped) { 572 got_it = true; 573 break; 574 } 575 if(tmp == orig) { 576 break; 577 } 578 } 579 580 if(!got_it) { 581 fprintf(stderr, "%s: unable to find open window in icon manager\n", 582 ProgramName); 583 return; 584 } 585 586 if(tmp == NULL) { 587 return; 588 } 589 590 /* raise the frame so the icon manager is visible */ 591 if(ip->twm_win->mapped) { 592 OtpRaise(ip->twm_win, WinWin); 593 XWarpPointer(dpy, None, tmp->icon, 0, 0, 0, 0, 5, 5); 594 } 595 else { 596 if(tmp->twm->title_height) { 597 XWarpPointer(dpy, None, tmp->twm->title_w, 0, 0, 0, 0, 598 tmp->twm->title_width / 2, 599 Scr->TitleHeight / 4); 600 } 601 else { 602 XWarpPointer(dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5); 603 } 604 } 605} 606 607/*********************************************************************** 608 * 609 * Procedure: 610 * JumpIconManager - jump from one icon manager to another, 611 * possibly even on another screen 612 * 613 * Inputs: 614 * dir - one of the following: 615 * F_NEXTICONMGR - go to the next icon manager 616 * F_PREVICONMGR - go to the previous one 617 * 618 *********************************************************************** 619 */ 620 621void JumpIconManager(int dir) 622{ 623 IconMgr *ip, *tmp_ip = NULL; 624 bool got_it = false; 625 ScreenInfo *sp; 626 int screen; 627 628 if(!Current) { 629 return; 630 } 631 632 633#define ITER(i) (dir == F_NEXTICONMGR ? (i)->next : (i)->prev) 634#define IPOFSP(sp) (dir == F_NEXTICONMGR ? sp->iconmgr : sp->iconmgr->lasti) 635#define TEST(ip) if ((ip)->count != 0 && (ip)->twm_win->mapped) \ 636 { got_it = true; break; } 637 638 ip = Current->iconmgr; 639 for(tmp_ip = ITER(ip); tmp_ip; tmp_ip = ITER(tmp_ip)) { 640 TEST(tmp_ip); 641 } 642 643 if(!got_it) { 644 int origscreen = ip->scr->screen; 645 int inc = (dir == F_NEXTICONMGR ? 1 : -1); 646 647 for(screen = origscreen + inc; ; screen += inc) { 648 if(screen >= NumScreens) { 649 screen = 0; 650 } 651 else if(screen < 0) { 652 screen = NumScreens - 1; 653 } 654 655 sp = ScreenList[screen]; 656 if(sp) { 657 for(tmp_ip = IPOFSP(sp); tmp_ip; tmp_ip = ITER(tmp_ip)) { 658 TEST(tmp_ip); 659 } 660 } 661 if(got_it || screen == origscreen) { 662 break; 663 } 664 } 665 } 666 667#undef ITER 668#undef IPOFSP 669#undef TEST 670 671 if(!got_it) { 672 XBell(dpy, 0); 673 return; 674 } 675 676 /* raise the frame so it is visible */ 677 OtpRaise(tmp_ip->twm_win, WinWin); 678 if(tmp_ip->active) { 679 XWarpPointer(dpy, None, tmp_ip->active->icon, 0, 0, 0, 0, 5, 5); 680 } 681 else { 682 XWarpPointer(dpy, None, tmp_ip->w, 0, 0, 0, 0, 5, 5); 683 } 684} 685 686/*********************************************************************** 687 * 688 * Procedure: 689 * AddIconManager - add a window to an icon manager 690 * 691 * Inputs: 692 * tmp_win - the TwmWindow structure 693 * 694 *********************************************************************** 695 */ 696 697WList *AddIconManager(TwmWindow *tmp_win) 698{ 699 WList *tmp, *old; 700 IconMgr *ip; 701 702 /* Some window types don't wind up in icon managers ever */ 703 if(tmp_win->isiconmgr || tmp_win->istransient || tmp_win->iswspmgr 704 || tmp_win->w == Scr->workSpaceMgr.occupyWindow->w) { 705 return NULL; 706 } 707 708 /* Icon managers can be shut off wholesale in the config */ 709 if(Scr->NoIconManagers) { 710 return NULL; 711 } 712 713 /* Config could declare not to IMify this type of window in two ways */ 714 if(LookInList(Scr->IconMgrNoShow, tmp_win->name, &tmp_win->class)) { 715 return NULL; 716 } 717 if(Scr->IconManagerDontShow 718 && !LookInList(Scr->IconMgrShow, tmp_win->name, &tmp_win->class)) { 719 return NULL; 720 } 721 722 /* Dredge up the appropriate IM */ 723 if((ip = (IconMgr *)LookInList(Scr->IconMgrs, tmp_win->name, 724 &tmp_win->class)) == NULL) { 725 if(Scr->workSpaceManagerActive) { 726 ip = Scr->workSpaceMgr.workSpaceList->iconmgr; 727 } 728 else { 729 ip = Scr->iconmgr; 730 } 731 } 732 733 /* IM's exist in all workspaces, so loop through WSen */ 734 tmp = NULL; 735 old = tmp_win->iconmanagerlist; 736 while(ip != NULL) { 737 int h; 738 unsigned long valuemask; /* mask for create windows */ 739 XSetWindowAttributes attributes; /* attributes for create windows */ 740 741 /* Is the window in this workspace? */ 742 if((tmp_win->occupation & ip->twm_win->occupation) == 0) { 743 /* Nope, skip onward */ 744 ip = ip->nextv; 745 continue; 746 } 747 748 /* Yep, create entry and stick it in */ 749 tmp = calloc(1, sizeof(WList)); 750 tmp->iconmgr = ip; 751 tmp->twm = tmp_win; 752 753 InsertInIconManager(ip, tmp, tmp_win); 754 755 /* IM color settings, shared worldwide */ 756 tmp->cp.fore = Scr->IconManagerC.fore; 757 tmp->cp.back = Scr->IconManagerC.back; 758 tmp->highlight = Scr->IconManagerHighlight; 759 760 GetColorFromList(Scr->IconManagerFL, tmp_win->name, 761 &tmp_win->class, &tmp->cp.fore); 762 GetColorFromList(Scr->IconManagerBL, tmp_win->name, 763 &tmp_win->class, &tmp->cp.back); 764 GetColorFromList(Scr->IconManagerHighlightL, tmp_win->name, 765 &tmp_win->class, &tmp->highlight); 766 767 /* 768 * If we're using 3d icon managers, each line item has its own 769 * icon; see comment on creation function for details. With 2d 770 * icon managers, it's the same for all of them, so it's stored 771 * screen-wide. 772 */ 773 if(Scr->use3Diconmanagers) { 774 if(!Scr->BeNiceToColormap) { 775 GetShadeColors(&tmp->cp); 776 } 777 tmp->iconifypm = Create3DIconManagerIcon(tmp->cp); 778 } 779 780 /* Refigure the height of the whole IM */ 781 h = Scr->IconManagerFont.avg_height 782 + 2 * (ICON_MGR_OBORDER + ICON_MGR_OBORDER); 783 if(h < (im_iconified_icon_height + 4)) { 784 h = im_iconified_icon_height + 4; 785 } 786 787 ip->height = h * ip->count; 788 tmp->me = ip->count; 789 tmp->x = -1; 790 tmp->y = -1; 791 tmp->height = -1; 792 tmp->width = -1; 793 794 795 /* Make a window for this row in the IM */ 796 valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor); 797 attributes.background_pixel = tmp->cp.back; 798 attributes.border_pixel = tmp->cp.back; 799 attributes.event_mask = (KeyPressMask | ButtonPressMask | 800 ButtonReleaseMask | ExposureMask); 801 if(Scr->IconManagerFocus) { 802 attributes.event_mask |= (EnterWindowMask | LeaveWindowMask); 803 } 804 attributes.cursor = Scr->IconMgrCursor; 805 tmp->w = XCreateWindow(dpy, ip->w, 0, 0, 1, 806 h, 0, 807 CopyFromParent, CopyFromParent, 808 CopyFromParent, 809 valuemask, &attributes); 810 811 812 /* Setup the icon for it too */ 813 valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor); 814 attributes.background_pixel = tmp->cp.back; 815 attributes.border_pixel = Scr->Black; 816 attributes.event_mask = (ButtonReleaseMask | ButtonPressMask 817 | ExposureMask); 818 attributes.cursor = Scr->ButtonCursor; 819 /* The precise location will be set it in PackIconManager. */ 820 tmp->icon = XCreateWindow(dpy, tmp->w, 0, 0, 821 im_iconified_icon_width, 822 im_iconified_icon_height, 823 0, CopyFromParent, 824 CopyFromParent, 825 CopyFromParent, 826 valuemask, &attributes); 827 828 829 /* Bump housekeeping for the IM */ 830 ip->count += 1; 831 PackIconManager(ip); 832 if(Scr->WindowMask) { 833 XRaiseWindow(dpy, Scr->WindowMask); 834 } 835 XMapWindow(dpy, tmp->w); 836 837 XSaveContext(dpy, tmp->w, TwmContext, (XPointer) tmp_win); 838 XSaveContext(dpy, tmp->w, ScreenContext, (XPointer) Scr); 839 XSaveContext(dpy, tmp->icon, TwmContext, (XPointer) tmp_win); 840 XSaveContext(dpy, tmp->icon, ScreenContext, (XPointer) Scr); 841 842 if(!ip->twm_win->isicon) { 843 if(visible(ip->twm_win)) { 844 SetMapStateProp(ip->twm_win, NormalState); 845 XMapWindow(dpy, ip->w); 846 XMapWindow(dpy, ip->twm_win->frame); 847 } 848 ip->twm_win->mapped = true; 849 } 850 851 852 /* 853 * Stick this entry on the head of our list of "IM entries we 854 * created", and loop around to the next WS for this IM. 855 */ 856 tmp->nextv = old; 857 old = tmp; 858 ip = ip->nextv; 859 } 860 861 /* If we didn't create at least one thing, we're done here */ 862 if(tmp == NULL) { 863 return NULL; 864 } 865 866 /* Stash where the window is IM-listed */ 867 tmp_win->iconmanagerlist = tmp; 868 869 /* ??? */ 870 if(! visible(tmp->iconmgr->twm_win)) { 871 old = tmp; 872 tmp = tmp->nextv; 873 while(tmp != NULL) { 874 if(visible(tmp->iconmgr->twm_win)) { 875 break; 876 } 877 old = tmp; 878 tmp = tmp->nextv; 879 } 880 if(tmp != NULL) { 881 old->nextv = tmp->nextv; 882 tmp->nextv = tmp_win->iconmanagerlist; 883 tmp_win->iconmanagerlist = tmp; 884 } 885 } 886 887 /* Hand back the list places we added */ 888 return tmp_win->iconmanagerlist; 889} 890 891/*********************************************************************** 892 * 893 * Procedure: 894 * InsertInIconManager - put an allocated entry into an icon 895 * manager 896 * 897 * Inputs: 898 * ip - the icon manager pointer 899 * tmp - the entry to insert 900 * 901 *********************************************************************** 902 */ 903 904void InsertInIconManager(IconMgr *ip, WList *tmp, TwmWindow *tmp_win) 905{ 906 WList *tmp1; 907 bool added; 908 909 added = false; 910 if(ip->first == NULL) { 911 ip->first = tmp; 912 tmp->prev = NULL; 913 ip->last = tmp; 914 added = true; 915 } 916 else if(Scr->SortIconMgr) { 917 for(tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) { 918 int compresult; 919 if(Scr->CaseSensitive) { 920 compresult = strcmp(tmp_win->icon_name, tmp1->twm->icon_name); 921 } 922 else { 923 compresult = strcasecmp(tmp_win->icon_name, tmp1->twm->icon_name); 924 } 925 if(compresult < 0) { 926 tmp->next = tmp1; 927 tmp->prev = tmp1->prev; 928 tmp1->prev = tmp; 929 if(tmp->prev == NULL) { 930 ip->first = tmp; 931 } 932 else { 933 tmp->prev->next = tmp; 934 } 935 added = true; 936 break; 937 } 938 } 939 } 940 941 if(!added) { 942 ip->last->next = tmp; 943 tmp->prev = ip->last; 944 ip->last = tmp; 945 } 946} 947 948void RemoveFromIconManager(IconMgr *ip, WList *tmp) 949{ 950 if(tmp->prev == NULL) { 951 ip->first = tmp->next; 952 } 953 else { 954 tmp->prev->next = tmp->next; 955 } 956 957 if(tmp->next == NULL) { 958 ip->last = tmp->prev; 959 } 960 else { 961 tmp->next->prev = tmp->prev; 962 } 963 964 /* pebl: If the list was the current and tmp was the last in the list 965 reset current list */ 966 if(Current == tmp) { 967 Current = ip->first; 968 } 969} 970 971/*********************************************************************** 972 * 973 * Procedure: 974 * RemoveIconManager - remove a window from the icon manager 975 * 976 * Inputs: 977 * tmp_win - the TwmWindow structure 978 * 979 *********************************************************************** 980 */ 981 982void RemoveIconManager(TwmWindow *tmp_win) 983{ 984 IconMgr *ip; 985 WList *tmp, *tmp1, *save; 986 987 if(tmp_win->iconmanagerlist == NULL) { 988 return; 989 } 990 991 tmp = tmp_win->iconmanagerlist; 992 tmp1 = NULL; 993 994 while(tmp != NULL) { 995 ip = tmp->iconmgr; 996 if((tmp_win->occupation & ip->twm_win->occupation) != 0) { 997 tmp1 = tmp; 998 tmp = tmp->nextv; 999 continue; 1000 } 1001 RemoveFromIconManager(ip, tmp); 1002 1003 XDeleteContext(dpy, tmp->icon, TwmContext); 1004 XDeleteContext(dpy, tmp->icon, ScreenContext); 1005 XDestroyWindow(dpy, tmp->icon); 1006 XDeleteContext(dpy, tmp->w, TwmContext); 1007 XDeleteContext(dpy, tmp->w, ScreenContext); 1008 XDestroyWindow(dpy, tmp->w); 1009 ip->count -= 1; 1010 1011 PackIconManager(ip); 1012 1013 if(ip->count == 0) { 1014 XUnmapWindow(dpy, ip->twm_win->frame); 1015 ip->twm_win->mapped = false; 1016 } 1017 if(tmp1 == NULL) { 1018 tmp_win->iconmanagerlist = tmp_win->iconmanagerlist->nextv; 1019 } 1020 else { 1021 tmp1->nextv = tmp->nextv; 1022 } 1023 1024 save = tmp; 1025 tmp = tmp->nextv; 1026 free(save); 1027 } 1028} 1029 1030void CurrentIconManagerEntry(WList *current) 1031{ 1032 Current = current; 1033} 1034 1035void ActiveIconManager(WList *active) 1036{ 1037 active->active = true; 1038 Active = active; 1039 Active->iconmgr->active = active; 1040 Current = Active; 1041 DrawIconManagerBorder(active, false); 1042} 1043 1044void NotActiveIconManager(WList *active) 1045{ 1046 active->active = false; 1047 DrawIconManagerBorder(active, false); 1048} 1049 1050void DrawIconManagerBorder(WList *tmp, bool fill) 1051{ 1052 if(Scr->use3Diconmanagers) { 1053 Draw3DBorder(tmp->w, 0, 0, tmp->width, tmp->height, 1054 Scr->IconManagerShadowDepth, tmp->cp, 1055 (tmp->active && Scr->Highlight ? on : off), 1056 fill, false); 1057 } 1058 else { 1059 XSetForeground(dpy, Scr->NormalGC, tmp->cp.fore); 1060 XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 2, 2, tmp->width - 5, 1061 tmp->height - 5); 1062 1063 XSetForeground(dpy, Scr->NormalGC, 1064 (tmp->active && Scr->Highlight 1065 ? tmp->highlight : tmp->cp.back)); 1066 1067 XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 0, 0, tmp->width - 1, 1068 tmp->height - 1); 1069 XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 1, 1, tmp->width - 3, 1070 tmp->height - 3); 1071 } 1072} 1073 1074/*********************************************************************** 1075 * 1076 * Procedure: 1077 * SortIconManager - sort the dude 1078 * 1079 * Inputs: 1080 * ip - a pointer to the icon manager struture 1081 * 1082 *********************************************************************** 1083 */ 1084 1085void SortIconManager(IconMgr *ip) 1086{ 1087 WList *tmp1, *tmp2; 1088 int done; 1089 1090 if(ip == NULL) { 1091 ip = Active->iconmgr; 1092 } 1093 1094 done = false; 1095 do { 1096 for(tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) { 1097 int compresult; 1098 if((tmp2 = tmp1->next) == NULL) { 1099 done = true; 1100 break; 1101 } 1102 if(Scr->CaseSensitive) { 1103 compresult = strcmp(tmp1->twm->icon_name, tmp2->twm->icon_name); 1104 } 1105 else { 1106 compresult = strcasecmp(tmp1->twm->icon_name, tmp2->twm->icon_name); 1107 } 1108 if(compresult > 0) { 1109 /* take it out and put it back in */ 1110 RemoveFromIconManager(ip, tmp2); 1111 InsertInIconManager(ip, tmp2, tmp2->twm); 1112 break; 1113 } 1114 } 1115 } 1116 while(!done); 1117 PackIconManager(ip); 1118} 1119 1120/*********************************************************************** 1121 * 1122 * Procedure: 1123 * PackIconManager - pack the icon manager windows following 1124 * an addition or deletion 1125 * 1126 * Inputs: 1127 * ip - a pointer to the icon manager struture 1128 * 1129 *********************************************************************** 1130 */ 1131 1132void PackIconManagers(void) 1133{ 1134 TwmWindow *twm_win; 1135 1136 for(twm_win = Scr->FirstWindow; twm_win != NULL; twm_win = twm_win->next) { 1137 if(twm_win->iconmgrp) { 1138 PackIconManager(twm_win->iconmgrp); 1139 } 1140 } 1141} 1142 1143void PackIconManager(IconMgr *ip) 1144{ 1145 int newwidth, i, row, col, maxcol, colinc, rowinc, wheight, wwidth; 1146 int new_x, new_y; 1147 int savewidth; 1148 WList *tmp; 1149 int mask; 1150 1151 wheight = Scr->IconManagerFont.avg_height 1152 + 2 * (ICON_MGR_OBORDER + ICON_MGR_IBORDER); 1153 if(wheight < (im_iconified_icon_height + 4)) { 1154 wheight = im_iconified_icon_height + 4; 1155 } 1156 1157 wwidth = ip->width / ip->columns; 1158 1159 rowinc = wheight; 1160 colinc = wwidth; 1161 1162 row = 0; 1163 col = ip->columns; 1164 maxcol = 0; 1165 for(i = 0, tmp = ip->first; tmp != NULL; i++, tmp = tmp->next) { 1166 tmp->me = i; 1167 if(++col >= ip->columns) { 1168 col = 0; 1169 row += 1; 1170 } 1171 if(col > maxcol) { 1172 maxcol = col; 1173 } 1174 1175 new_x = col * colinc; 1176 new_y = (row - 1) * rowinc; 1177 1178 /* if the position or size has not changed, don't touch it */ 1179 if(tmp->x != new_x || tmp->y != new_y || 1180 tmp->width != wwidth || tmp->height != wheight) { 1181 XMoveResizeWindow(dpy, tmp->w, new_x, new_y, wwidth, wheight); 1182 if(tmp->height != wheight) 1183 XMoveWindow(dpy, tmp->icon, ICON_MGR_OBORDER + ICON_MGR_IBORDER, 1184 (wheight - im_iconified_icon_height) / 2); 1185 1186 tmp->row = row - 1; 1187 tmp->col = col; 1188 tmp->x = new_x; 1189 tmp->y = new_y; 1190 tmp->width = wwidth; 1191 tmp->height = wheight; 1192 } 1193 } 1194 maxcol += 1; 1195 1196 ip->cur_rows = row; 1197 ip->cur_columns = maxcol; 1198 ip->height = row * rowinc; 1199 if(ip->height == 0) { 1200 ip->height = rowinc; 1201 } 1202 newwidth = maxcol * colinc; 1203 if(newwidth == 0) { 1204 newwidth = colinc; 1205 } 1206 1207 XResizeWindow(dpy, ip->w, newwidth, ip->height); 1208 1209 mask = RLayoutXParseGeometry(Scr->Layout, ip->geometry, &JunkX, &JunkY, 1210 &JunkWidth, &JunkHeight); 1211 if(mask & XNegative) { 1212 ip->twm_win->frame_x += ip->twm_win->frame_width - newwidth - 1213 2 * ip->twm_win->frame_bw3D; 1214 } 1215 if(mask & YNegative) { 1216 ip->twm_win->frame_y += ip->twm_win->frame_height - ip->height - 1217 2 * ip->twm_win->frame_bw3D - ip->twm_win->title_height; 1218 } 1219 savewidth = ip->width; 1220 if(ip->twm_win) 1221 SetupWindow(ip->twm_win, 1222 ip->twm_win->frame_x, ip->twm_win->frame_y, 1223 newwidth + 2 * ip->twm_win->frame_bw3D, 1224 ip->height + ip->twm_win->title_height + 2 * ip->twm_win->frame_bw3D, -1); 1225 ip->width = savewidth; 1226} 1227 1228void dump_iconmanager(IconMgr *mgr, char *label) 1229{ 1230 fprintf(stderr, "IconMgr %s %p name='%s' geom='%s'\n", 1231 label, 1232 mgr, 1233 mgr->name, 1234 mgr->geometry); 1235 fprintf(stderr, "next = %p, prev = %p, lasti = %p, nextv = %p\n", 1236 mgr->next, 1237 mgr->prev, 1238 mgr->lasti, 1239 mgr->nextv); 1240} 1241 1242 1243/* 1244 * Draw the window name into the icon manager line 1245 */ 1246void 1247DrawIconManagerIconName(TwmWindow *tmp_win) 1248{ 1249 WList *iconmanagerlist = tmp_win->iconmanagerlist; 1250 XRectangle ink_rect, logical_rect; 1251 1252 XmbTextExtents(Scr->IconManagerFont.font_set, 1253 tmp_win->icon_name, strlen(tmp_win->icon_name), 1254 &ink_rect, &logical_rect); 1255 1256 if(UpdateFont(&Scr->IconManagerFont, logical_rect.height)) { 1257 PackIconManagers(); 1258 } 1259 1260 // Write in the title 1261 FB(iconmanagerlist->cp.fore, iconmanagerlist->cp.back); 1262 1263 /* XXX This is a completely absurd way of writing this */ 1264 ((Scr->use3Diconmanagers && (Scr->Monochrome != COLOR)) ? 1265 XmbDrawImageString : XmbDrawString) 1266 (dpy, 1267 iconmanagerlist->w, 1268 Scr->IconManagerFont.font_set, 1269 Scr->NormalGC, 1270 iconmgr_textx, 1271 (Scr->IconManagerFont.avg_height - logical_rect.height) / 2 1272 + (- logical_rect.y) 1273 + ICON_MGR_OBORDER 1274 + ICON_MGR_IBORDER, 1275 tmp_win->icon_name, 1276 strlen(tmp_win->icon_name)); 1277 1278 // Draw the border around it. Our "border" isn't an X border, it's 1279 // just our own drawing inside the X window. Since XmbDrawString() 1280 // believes it has all the space in the window to fill, it might 1281 // scribble into the space where we're drawing the border, so draw 1282 // the border after the text to cover it up. 1283 DrawIconManagerBorder(iconmanagerlist, false); 1284} 1285 1286 1287/* 1288 * Copy the icon into the icon manager for a window that's iconified. 1289 * This is slightly different for the 3d vs 2d case, since the 3d is just 1290 * copying a pixmap in, while the 2d is drawing a bitmap in with the 1291 * fg/bg colors appropriate to the line. 1292 */ 1293void 1294ShowIconifiedIcon(TwmWindow *tmp_win) 1295{ 1296 WList *iconmanagerlist = tmp_win->iconmanagerlist; 1297 1298 if(Scr->use3Diconmanagers && iconmanagerlist->iconifypm) { 1299 XCopyArea(dpy, iconmanagerlist->iconifypm, 1300 iconmanagerlist->icon, 1301 Scr->NormalGC, 0, 0, 1302 im_iconified_icon_width, im_iconified_icon_height, 0, 0); 1303 } 1304 else { 1305 FB(iconmanagerlist->cp.fore, iconmanagerlist->cp.back); 1306 XCopyPlane(dpy, Scr->siconifyPm, iconmanagerlist->icon, 1307 Scr->NormalGC, 0, 0, 1308 im_iconified_icon_width, im_iconified_icon_height, 0, 0, 1); 1309 } 1310} 1311