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