iconmgr.c revision c2535118
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 int mask; 61 char str[100]; 62 char str1[100]; 63 Pixel background; 64 char *icon_name; 65 66 if (Scr->NoIconManagers) 67 return; 68 69 if (Scr->siconifyPm == None) 70 { 71 Scr->siconifyPm = XCreatePixmapFromBitmapData(dpy, Scr->Root, 72 (char *)siconify_bits, siconify_width, siconify_height, 1, 0, 1); 73 } 74 75 for (p = &Scr->iconmgr; p != NULL; p = p->next) 76 { 77 mask = XParseGeometry(p->geometry, &JunkX, &JunkY, 78 (unsigned int *) &p->width, (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, p->width, p->height, 1, 94 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 { 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 *AllocateIconManager(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, geom, columns); 131#endif 132 133 if (Scr->NoIconManagers) 134 return NULL; 135 136 p = 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 MoveIconManager(int dir) 171{ 172 IconMgr *ip; 173 WList *tmp = NULL; 174 int cur_row, cur_col, new_row, new_col; 175 int row_inc, col_inc; 176 int got_it; 177 178 if (!Active) return; 179 180 cur_row = Active->row; 181 cur_col = Active->col; 182 ip = Active->iconmgr; 183 184 row_inc = 0; 185 col_inc = 0; 186 got_it = FALSE; 187 188 switch (dir) 189 { 190 case F_FORWICONMGR: 191 if ((tmp = Active->next) == NULL) 192 tmp = ip->first; 193 got_it = TRUE; 194 break; 195 196 case F_BACKICONMGR: 197 if ((tmp = Active->prev) == NULL) 198 tmp = ip->last; 199 got_it = TRUE; 200 break; 201 202 case F_UPICONMGR: 203 row_inc = -1; 204 break; 205 206 case F_DOWNICONMGR: 207 row_inc = 1; 208 break; 209 210 case F_LEFTICONMGR: 211 col_inc = -1; 212 break; 213 214 case F_RIGHTICONMGR: 215 col_inc = 1; 216 break; 217 } 218 219 /* If got_it is FALSE ast this point then we got a left, right, 220 * up, or down, command. We will enter this loop until we find 221 * a window to warp to. 222 */ 223 new_row = cur_row; 224 new_col = cur_col; 225 226 while (!got_it) 227 { 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 { 244 if (tmp->row == new_row && tmp->col == new_col) 245 { 246 got_it = TRUE; 247 break; 248 } 249 } 250 } 251 252 if (!got_it) 253 { 254 fprintf (stderr, 255 "%s: unable to find window (%d, %d) in icon manager\n", 256 ProgramName, new_row, new_col); 257 return; 258 } 259 260 if (tmp == NULL) 261 return; 262 263 /* raise the frame so the icon manager is visible */ 264 if (ip->twm_win->mapped) { 265 XRaiseWindow(dpy, ip->twm_win->frame); 266 XWarpPointer(dpy, None, tmp->icon, 0,0,0,0, 5, 5); 267 } else { 268 if (tmp->twm->title_height) { 269 int tbx = Scr->TBInfo.titlex; 270 int x = tmp->twm->highlightx; 271 XWarpPointer (dpy, None, tmp->twm->title_w, 0, 0, 0, 0, 272 tbx + (x - tbx) / 2, 273 Scr->TitleHeight / 4); 274 } else { 275 XWarpPointer (dpy, None, tmp->twm->w, 0, 0, 0, 0, 5, 5); 276 } 277 } 278} 279 280/** 281 * jump from one icon manager to another, possibly even on another screen 282 * \param dir one of the following: 283 * - F_NEXTICONMGR - go to the next icon manager 284 * - F_PREVICONMGR - go to the previous one 285 */ 286 287void JumpIconManager(int dir) 288{ 289 IconMgr *ip, *tmp_ip = NULL; 290 int got_it = FALSE; 291 ScreenInfo *sp; 292 int screen; 293 294 if (!Active) return; 295 296 297#define ITER(i) (dir == F_NEXTICONMGR ? (i)->next : (i)->prev) 298#define IPOFSP(sp) (dir == F_NEXTICONMGR ? &(sp->iconmgr) : sp->iconmgr.lasti) 299#define TEST(ip) if ((ip)->count != 0 && (ip)->twm_win->mapped) \ 300 { got_it = TRUE; break; } 301 302 ip = Active->iconmgr; 303 for (tmp_ip = ITER(ip); tmp_ip; tmp_ip = ITER(tmp_ip)) { 304 TEST (tmp_ip); 305 } 306 307 if (!got_it) { 308 int origscreen = ip->scr->screen; 309 int inc = (dir == F_NEXTICONMGR ? 1 : -1); 310 311 for (screen = origscreen + inc; ; screen += inc) { 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) break; 324 } 325 } 326 327#undef ITER 328#undef IPOFSP 329#undef TEST 330 331 if (!got_it) { 332 Bell(XkbBI_MinorError,0,None); 333 return; 334 } 335 336 /* raise the frame so it is visible */ 337 XRaiseWindow(dpy, tmp_ip->twm_win->frame); 338 if (tmp_ip->active) 339 XWarpPointer(dpy, None, tmp_ip->active->icon, 0,0,0,0, 5, 5); 340 else 341 XWarpPointer(dpy, None, tmp_ip->w, 0,0,0,0, 5, 5); 342} 343 344/** 345 * add a window to an icon manager 346 * 347 * \param tmp_win the TwmWindow structure 348 */ 349WList *AddIconManager(TwmWindow *tmp_win) 350{ 351 WList *tmp; 352 int h; 353 unsigned long valuemask; /* mask for create windows */ 354 XSetWindowAttributes attributes; /* attributes for create windows */ 355 IconMgr *ip; 356 357 tmp_win->list = NULL; 358 359 if (tmp_win->iconmgr || tmp_win->transient || Scr->NoIconManagers) 360 return NULL; 361 362 if (LookInList(Scr->IconMgrNoShow, tmp_win->full_name, &tmp_win->class)) 363 return NULL; 364 if (Scr->IconManagerDontShow && 365 !LookInList(Scr->IconMgrShow, tmp_win->full_name, &tmp_win->class)) 366 return NULL; 367 if ((ip = (IconMgr *)LookInList(Scr->IconMgrs, tmp_win->full_name, 368 &tmp_win->class)) == NULL) 369 ip = &Scr->iconmgr; 370 371 tmp = malloc(sizeof(WList)); 372 tmp->iconmgr = ip; 373 tmp->next = NULL; 374 tmp->active = FALSE; 375 tmp->down = FALSE; 376 377 InsertInIconManager(ip, tmp, tmp_win); 378 379 tmp->twm = tmp_win; 380 381 tmp->fore = Scr->IconManagerC.fore; 382 tmp->back = Scr->IconManagerC.back; 383 tmp->highlight = Scr->IconManagerHighlight; 384 385 GetColorFromList(Scr->IconManagerFL, tmp_win->full_name, &tmp_win->class, 386 &tmp->fore); 387 GetColorFromList(Scr->IconManagerBL, tmp_win->full_name, &tmp_win->class, 388 &tmp->back); 389 GetColorFromList(Scr->IconManagerHighlightL, tmp_win->full_name, 390 &tmp_win->class, &tmp->highlight); 391 392 h = Scr->IconManagerFont.height + 10; 393 if (h < (siconify_height + 4)) 394 h = siconify_height + 4; 395 396 ip->height = h * ip->count; 397 tmp->me = ip->count; 398 tmp->x = -1; 399 tmp->y = -1; 400 401 valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor); 402 attributes.background_pixel = tmp->back; 403 attributes.border_pixel = tmp->back; 404 attributes.event_mask = (KeyPressMask | ButtonPressMask | 405 ButtonReleaseMask | ExposureMask | 406 EnterWindowMask | LeaveWindowMask); 407 attributes.cursor = Scr->IconMgrCursor; 408 tmp->w = XCreateWindow (dpy, ip->w, 0, 0, (unsigned int) 1, 409 (unsigned int) h, (unsigned int) 0, 410 CopyFromParent, (unsigned int) CopyFromParent, 411 (Visual *) CopyFromParent, valuemask, &attributes); 412 413 414 valuemask = (CWBackPixel | CWBorderPixel | CWEventMask | CWCursor); 415 attributes.background_pixel = tmp->back; 416 attributes.border_pixel = Scr->Black; 417 attributes.event_mask = (ButtonReleaseMask| ButtonPressMask | 418 ExposureMask); 419 attributes.cursor = Scr->ButtonCursor; 420 tmp->icon = XCreateWindow (dpy, tmp->w, 5, (int) (h - siconify_height)/2, 421 (unsigned int) siconify_width, 422 (unsigned int) siconify_height, 423 (unsigned int) 0, CopyFromParent, 424 (unsigned int) CopyFromParent, 425 (Visual *) CopyFromParent, 426 valuemask, &attributes); 427 428 ip->count += 1; 429 PackIconManager(ip); 430 XMapWindow(dpy, tmp->w); 431 432 XSaveContext(dpy, tmp->w, IconManagerContext, (caddr_t) tmp); 433 XSaveContext(dpy, tmp->w, TwmContext, (caddr_t) tmp_win); 434 XSaveContext(dpy, tmp->w, ScreenContext, (caddr_t) Scr); 435 XSaveContext(dpy, tmp->icon, TwmContext, (caddr_t) tmp_win); 436 XSaveContext(dpy, tmp->icon, ScreenContext, (caddr_t) Scr); 437 tmp_win->list = tmp; 438 439 if (!ip->twm_win->icon) 440 { 441 XMapWindow(dpy, ip->w); 442 XMapWindow(dpy, ip->twm_win->frame); 443 } 444 445 if (Active == NULL) Active = tmp; 446 447 return (tmp); 448} 449 450/** 451 * put an allocated entry into an icon manager 452 * 453 * \param ip the icon manager pointer 454 * \param tmp the entry to insert 455 */ 456static void InsertInIconManager(IconMgr *ip, WList *tmp, TwmWindow *tmp_win) 457{ 458 WList *tmp1; 459 int added; 460 int (*compar)(const char *, const char *) 461 = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1); 462 463 added = FALSE; 464 if (ip->first == NULL) 465 { 466 ip->first = tmp; 467 tmp->prev = NULL; 468 ip->last = tmp; 469 added = TRUE; 470 } 471 else if (Scr->SortIconMgr) 472 { 473 for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) 474 { 475 if ((*compar)(tmp_win->icon_name, tmp1->twm->icon_name) < 0) 476 { 477 tmp->next = tmp1; 478 tmp->prev = tmp1->prev; 479 tmp1->prev = tmp; 480 if (tmp->prev == NULL) 481 ip->first = tmp; 482 else 483 tmp->prev->next = tmp; 484 added = TRUE; 485 break; 486 } 487 } 488 } 489 490 if (!added) 491 { 492 ip->last->next = tmp; 493 tmp->prev = ip->last; 494 ip->last = tmp; 495 } 496} 497 498static void RemoveFromIconManager(IconMgr *ip, WList *tmp) 499{ 500 if (tmp->prev == NULL) 501 ip->first = tmp->next; 502 else 503 tmp->prev->next = tmp->next; 504 505 if (tmp->next == NULL) 506 ip->last = tmp->prev; 507 else 508 tmp->next->prev = tmp->prev; 509} 510 511/** 512 * remove a window from the icon manager 513 * \param tmp_win the TwmWindow structure 514 */ 515void RemoveIconManager(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 { 543 XUnmapWindow(dpy, ip->twm_win->frame); 544 } 545 546} 547 548void ActiveIconManager(WList *active) 549{ 550 active->active = TRUE; 551 Active = active; 552 Active->iconmgr->active = active; 553 DrawIconManagerBorder(active); 554} 555 556void NotActiveIconManager(WList *active) 557{ 558 active->active = FALSE; 559 DrawIconManagerBorder(active); 560} 561 562void DrawIconManagerBorder(WList *tmp) 563{ 564 { 565 XSetForeground(dpy, Scr->NormalGC, tmp->fore); 566 XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 2, 2, 567 tmp->width-5, tmp->height-5); 568 569 if (tmp->active && Scr->Highlight) 570 XSetForeground(dpy, Scr->NormalGC, tmp->highlight); 571 else 572 XSetForeground(dpy, Scr->NormalGC, tmp->back); 573 574 XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 0, 0, 575 tmp->width-1, tmp->height-1); 576 XDrawRectangle(dpy, tmp->w, Scr->NormalGC, 1, 1, 577 tmp->width-3, tmp->height-3); 578 } 579} 580 581/** 582 * sort The Dude 583 * 584 * \param ip a pointer to the icon manager struture 585 */ 586void SortIconManager(IconMgr *ip) 587{ 588 WList *tmp1, *tmp2; 589 int done; 590 int (*compar)(const char *, const char *) 591 = (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1); 592 593 if (ip == NULL) 594 ip = Active->iconmgr; 595 596 done = FALSE; 597 do 598 { 599 for (tmp1 = ip->first; tmp1 != NULL; tmp1 = tmp1->next) 600 { 601 if ((tmp2 = tmp1->next) == NULL) 602 { 603 done = TRUE; 604 break; 605 } 606 if ((*compar)(tmp1->twm->icon_name, tmp2->twm->icon_name) > 0) 607 { 608 /* take it out and put it back in */ 609 RemoveFromIconManager(ip, tmp2); 610 InsertInIconManager(ip, tmp2, tmp2->twm); 611 break; 612 } 613 } 614 } 615 while (!done); 616 PackIconManager(ip); 617} 618 619/** 620 * pack the icon manager windows following 621 * an addition or deletion 622 * 623 * \param ip a pointer to the icon manager struture 624 */ 625void PackIconManager(IconMgr *ip) 626{ 627 int newwidth, i, row, col, maxcol, colinc, rowinc, wheight, wwidth; 628 int new_x, new_y; 629 int savewidth; 630 WList *tmp; 631 632 wheight = Scr->IconManagerFont.height + 10; 633 if (wheight < (siconify_height + 4)) 634 wheight = siconify_height + 4; 635 636 wwidth = ip->width / ip->columns; 637 638 rowinc = wheight; 639 colinc = wwidth; 640 641 row = 0; 642 col = ip->columns; 643 maxcol = 0; 644 for (i = 0, tmp = ip->first; tmp != NULL; i++, tmp = tmp->next) 645 { 646 tmp->me = i; 647 if (++col >= ip->columns) 648 { 649 col = 0; 650 row += 1; 651 } 652 if (col > maxcol) 653 maxcol = col; 654 655 new_x = col * colinc; 656 new_y = (row-1) * rowinc; 657 658 /* if the position or size has not changed, don't touch it */ 659 if (tmp->x != new_x || tmp->y != new_y || 660 tmp->width != wwidth || tmp->height != wheight) 661 { 662 XMoveResizeWindow(dpy, tmp->w, new_x, new_y, wwidth, wheight); 663 664 tmp->row = row-1; 665 tmp->col = col; 666 tmp->x = new_x; 667 tmp->y = new_y; 668 tmp->width = wwidth; 669 tmp->height = wheight; 670 } 671 } 672 maxcol += 1; 673 674 ip->cur_rows = row; 675 ip->cur_columns = maxcol; 676 ip->height = row * rowinc; 677 if (ip->height == 0) 678 ip->height = rowinc; 679 newwidth = maxcol * colinc; 680 if (newwidth == 0) 681 newwidth = colinc; 682 683 XResizeWindow(dpy, ip->w, newwidth, ip->height); 684 685 savewidth = ip->width; 686 if (ip->twm_win) 687 SetupWindow (ip->twm_win, 688 ip->twm_win->frame_x, ip->twm_win->frame_y, 689 newwidth, ip->height + ip->twm_win->title_height, -1); 690 ip->width = savewidth; 691} 692