menus.c revision ffd25bca
1/*****************************************************************************/ 2/* 3 4Copyright 1989, 1998 The Open Group 5 6Permission to use, copy, modify, distribute, and sell this software and its 7documentation for any purpose is hereby granted without fee, provided that 8the above copyright notice appear in all copies and that both that 9copyright notice and this permission notice appear in supporting 10documentation. 11 12The above copyright notice and this permission notice shall be included in 13all copies or substantial portions of the Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall not be 23used in advertising or otherwise to promote the sale, use or other dealings 24in this Software without prior written authorization from The Open Group. 25 26*/ 27/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/ 28/** Salt Lake City, Utah **/ 29/** Cambridge, Massachusetts **/ 30/** **/ 31/** All Rights Reserved **/ 32/** **/ 33/** Permission to use, copy, modify, and distribute this software and **/ 34/** its documentation for any purpose and without fee is hereby **/ 35/** granted, provided that the above copyright notice appear in all **/ 36/** copies and that both that copyright notice and this permis- **/ 37/** sion notice appear in supporting documentation, and that the **/ 38/** name of Evans & Sutherland not be used in advertising **/ 39/** in publicity pertaining to distribution of the software without **/ 40/** specific, written prior permission. **/ 41/** **/ 42/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/ 43/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/ 44/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/ 45/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/ 46/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/ 47/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/ 48/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/ 49/** OR PERFORMANCE OF THIS SOFTWARE. **/ 50/*****************************************************************************/ 51 52 53/*********************************************************************** 54 * 55 * twm menu code 56 * 57 * 17-Nov-87 Thomas E. LaStrange File created 58 * 59 ***********************************************************************/ 60 61#ifdef HAVE_CONFIG_H 62# include "config.h" 63#endif 64 65#include <stdio.h> 66#include <X11/Xos.h> 67#include "twm.h" 68#include "gc.h" 69#include "menus.h" 70#include "resize.h" 71#include "events.h" 72#include "util.h" 73#include "parse.h" 74#include "gram.h" 75#include "screen.h" 76#include "menus.h" 77#include "iconmgr.h" 78#include "add_window.h" 79#include "icons.h" 80#include "session.h" 81#include <X11/Xmu/CharSet.h> 82#include "version.h" 83#include <X11/extensions/sync.h> 84#include <X11/SM/SMlib.h> 85 86int RootFunction = 0; 87MenuRoot *ActiveMenu = NULL; /**< the active menu */ 88MenuItem *ActiveItem = NULL; /**< the active menu item */ 89int MoveFunction; /**< either F_MOVE or F_FORCEMOVE */ 90int WindowMoved = FALSE; 91int menuFromFrameOrWindowOrTitlebar = FALSE; 92 93int ConstMove = FALSE; /**< constrained move variables */ 94int ConstMoveDir; 95int ConstMoveX; 96int ConstMoveY; 97int ConstMoveXL; 98int ConstMoveXR; 99int ConstMoveYT; 100int ConstMoveYB; 101 102/* Globals used to keep track of whether the mouse has moved during 103 a resize function. */ 104int ResizeOrigX; 105int ResizeOrigY; 106 107int MenuDepth = 0; /**< number of menus up */ 108static struct { 109 int x; 110 int y; 111} MenuOrigins[MAXMENUDEPTH]; 112static Cursor LastCursor; 113 114static Bool belongs_to_twm_window ( TwmWindow *t, Window w ); 115static void Identify ( TwmWindow *t ); 116static void send_clientmessage ( Window w, Atom a, Time timestamp ); 117 118#define SHADOWWIDTH 5 /* in pixels */ 119 120 121 122 123/** 124 * initialize menu roots 125 */ 126void 127InitMenus() 128{ 129 int i, j, k; 130 FuncKey *key, *tmp; 131 132 for (i = 0; i < MAX_BUTTONS+1; i++) 133 for (j = 0; j < NUM_CONTEXTS; j++) 134 for (k = 0; k < MOD_SIZE; k++) 135 { 136 Scr->Mouse[i][j][k].func = 0; 137 Scr->Mouse[i][j][k].item = NULL; 138 } 139 140 Scr->DefaultFunction.func = 0; 141 Scr->WindowFunction.func = 0; 142 143 if (FirstScreen) 144 { 145 for (key = Scr->FuncKeyRoot.next; key != NULL;) 146 { 147 free(key->name); 148 tmp = key; 149 key = key->next; 150 free((char *) tmp); 151 } 152 Scr->FuncKeyRoot.next = NULL; 153 } 154 155} 156 157 158 159/** 160 * add a function key to the list 161 * 162 * \param name the name of the key 163 * \param cont the context to look for the key press in 164 * \param mods modifier keys that need to be pressed 165 * \param func the function to perform 166 * \param win_name the window name (if any) 167 * \param action the action string associated with the function (if any) 168 */ 169Bool AddFuncKey (char *name, int cont, int mods, int func, char *win_name, 170 char *action) 171{ 172 FuncKey *tmp; 173 KeySym keysym; 174 KeyCode keycode; 175 176 /* 177 * Don't let a 0 keycode go through, since that means AnyKey to the 178 * XGrabKey call in GrabKeys(). 179 */ 180 if ((keysym = XStringToKeysym(name)) == NoSymbol || 181 (keycode = XKeysymToKeycode(dpy, keysym)) == 0) 182 { 183 return False; 184 } 185 186 /* see if there already is a key defined for this context */ 187 for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) 188 { 189 if (tmp->keysym == keysym && 190 tmp->cont == cont && 191 tmp->mods == mods) 192 break; 193 } 194 195 if (tmp == NULL) 196 { 197 tmp = (FuncKey *) malloc(sizeof(FuncKey)); 198 tmp->next = Scr->FuncKeyRoot.next; 199 Scr->FuncKeyRoot.next = tmp; 200 } 201 202 tmp->name = name; 203 tmp->keysym = keysym; 204 tmp->keycode = keycode; 205 tmp->cont = cont; 206 tmp->mods = mods; 207 tmp->func = func; 208 tmp->win_name = win_name; 209 tmp->action = action; 210 211 return True; 212} 213 214 215 216int CreateTitleButton (char *name, int func, char *action, MenuRoot *menuroot, 217 Bool rightside, Bool append) 218{ 219 TitleButton *tb = (TitleButton *) malloc (sizeof(TitleButton)); 220 221 if (!tb) { 222 fprintf (stderr, 223 "%s: unable to allocate %ld bytes for title button\n", 224 ProgramName, (unsigned long)sizeof(TitleButton)); 225 return 0; 226 } 227 228 tb->next = NULL; 229 tb->name = name; /* note that we are not copying */ 230 tb->bitmap = None; /* WARNING, values not set yet */ 231 tb->width = 0; /* see InitTitlebarButtons */ 232 tb->height = 0; /* ditto */ 233 tb->func = func; 234 tb->action = action; 235 tb->menuroot = menuroot; 236 tb->rightside = rightside; 237 if (rightside) { 238 Scr->TBInfo.nright++; 239 } else { 240 Scr->TBInfo.nleft++; 241 } 242 243 /* 244 * Cases for list: 245 * 246 * 1. empty list, prepend left put at head of list 247 * 2. append left, prepend right put in between left and right 248 * 3. append right put at tail of list 249 * 250 * Do not refer to widths and heights yet since buttons not created 251 * (since fonts not loaded and heights not known). 252 */ 253 if ((!Scr->TBInfo.head) || ((!append) && (!rightside))) { /* 1 */ 254 tb->next = Scr->TBInfo.head; 255 Scr->TBInfo.head = tb; 256 } else if (append && rightside) { /* 3 */ 257 register TitleButton *t; 258 for /* SUPPRESS 530 */ 259 (t = Scr->TBInfo.head; t->next; t = t->next); 260 t->next = tb; 261 tb->next = NULL; 262 } else { /* 2 */ 263 register TitleButton *t, *prev = NULL; 264 for (t = Scr->TBInfo.head; t && !t->rightside; t = t->next) { 265 prev = t; 266 } 267 if (prev) { 268 tb->next = prev->next; 269 prev->next = tb; 270 } else { 271 tb->next = Scr->TBInfo.head; 272 Scr->TBInfo.head = tb; 273 } 274 } 275 276 return 1; 277} 278 279 280 281/** 282 * Do all the necessary stuff to load in a titlebar button. If we can't find 283 * the button, then put in a question; if we can't find the question mark, 284 * something is wrong and we are probably going to be in trouble later on. 285 */ 286void InitTitlebarButtons () 287{ 288 TitleButton *tb; 289 int h; 290 291 /* 292 * initialize dimensions 293 */ 294 Scr->TBInfo.width = (Scr->TitleHeight - 295 2 * (Scr->FramePadding + Scr->ButtonIndent)); 296 Scr->TBInfo.pad = ((Scr->TitlePadding > 1) 297 ? ((Scr->TitlePadding + 1) / 2) : 1); 298 h = Scr->TBInfo.width - 2 * Scr->TBInfo.border; 299 300 /* 301 * add in some useful buttons and bindings so that novices can still 302 * use the system. 303 */ 304 if (!Scr->NoDefaults) { 305 /* insert extra buttons */ 306 if (!CreateTitleButton (TBPM_ICONIFY, F_ICONIFY, "", (MenuRoot *) NULL, 307 False, False)) { 308 fprintf (stderr, "%s: unable to add iconify button\n", 309 ProgramName); 310 } 311 if (!CreateTitleButton (TBPM_RESIZE, F_RESIZE, "", (MenuRoot *) NULL, 312 True, True)) { 313 fprintf (stderr, "%s: unable to add resize button\n", 314 ProgramName); 315 } 316 AddDefaultBindings (); 317 } 318 ComputeCommonTitleOffsets (); 319 320 /* 321 * load in images and do appropriate centering 322 */ 323 324 for (tb = Scr->TBInfo.head; tb; tb = tb->next) { 325 tb->bitmap = FindBitmap (tb->name, &tb->width, &tb->height); 326 if (!tb->bitmap) { 327 tb->bitmap = FindBitmap (TBPM_QUESTION, &tb->width, &tb->height); 328 if (!tb->bitmap) { /* cannot happen (see util.c) */ 329 fprintf (stderr, 330 "%s: unable to add titlebar button \"%s\"\n", 331 ProgramName, tb->name); 332 } 333 } 334 335 tb->dstx = (h - tb->width + 1) / 2; 336 if (tb->dstx < 0) { /* clip to minimize copying */ 337 tb->srcx = -(tb->dstx); 338 tb->width = h; 339 tb->dstx = 0; 340 } else { 341 tb->srcx = 0; 342 } 343 tb->dsty = (h - tb->height + 1) / 2; 344 if (tb->dsty < 0) { 345 tb->srcy = -(tb->dsty); 346 tb->height = h; 347 tb->dsty = 0; 348 } else { 349 tb->srcy = 0; 350 } 351 } 352} 353 354 355 356void 357PaintEntry(MenuRoot *mr, MenuItem *mi, int exposure) 358{ 359 int y_offset; 360 int text_y; 361 GC gc; 362 363#ifdef DEBUG_MENUS 364 fprintf(stderr, "Paint entry\n"); 365#endif 366 y_offset = mi->item_num * Scr->EntryHeight; 367 text_y = y_offset + Scr->MenuFont.y; 368 369 if (mi->func != F_TITLE) 370 { 371 int x, y; 372 373 if (mi->state) 374 { 375 XSetForeground(dpy, Scr->NormalGC, mi->hi_back); 376 377 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset, 378 mr->width, Scr->EntryHeight); 379 380 MyFont_ChangeGC(mi->hi_fore, mi->hi_back, &Scr->MenuFont); 381 382 MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, Scr->NormalGC, mi->x, 383 text_y, mi->item, mi->strlen); 384 385 gc = Scr->NormalGC; 386 } 387 else 388 { 389 if (mi->user_colors || !exposure) 390 { 391 XSetForeground(dpy, Scr->NormalGC, mi->back); 392 393 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset, 394 mr->width, Scr->EntryHeight); 395 396 MyFont_ChangeGC(mi->fore, mi->back, &Scr->MenuFont); 397 gc = Scr->NormalGC; 398 } 399 else 400 gc = Scr->MenuGC; 401 402 MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, gc, 403 mi->x, text_y, mi->item, mi->strlen); 404 405 } 406 407 if (mi->func == F_MENU) 408 { 409 /* create the pull right pixmap if needed */ 410 if (Scr->pullPm == None) 411 { 412 Scr->pullPm = CreateMenuIcon (Scr->MenuFont.height, 413 &Scr->pullW, &Scr->pullH); 414 } 415 x = mr->width - Scr->pullW - 5; 416 y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2); 417 XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0, 418 Scr->pullW, Scr->pullH, x, y, 1); 419 } 420 } 421 else 422 { 423 int y; 424 425 XSetForeground(dpy, Scr->NormalGC, mi->back); 426 427 /* fill the rectangle with the title background color */ 428 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset, 429 mr->width, Scr->EntryHeight); 430 431 { 432 XSetForeground(dpy, Scr->NormalGC, mi->fore); 433 /* now draw the dividing lines */ 434 if (y_offset) 435 XDrawLine (dpy, mr->w, Scr->NormalGC, 0, y_offset, 436 mr->width, y_offset); 437 y = ((mi->item_num+1) * Scr->EntryHeight)-1; 438 XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y); 439 } 440 441 MyFont_ChangeGC(mi->fore, mi->back, &Scr->MenuFont); 442 /* finally render the title */ 443 MyFont_DrawString(dpy, mr->w, &Scr->MenuFont, Scr->NormalGC, mi->x, 444 text_y, mi->item, mi->strlen); 445 } 446} 447 448 449void 450PaintMenu(MenuRoot *mr, XEvent *e) 451{ 452 MenuItem *mi; 453 454 for (mi = mr->first; mi != NULL; mi = mi->next) 455 { 456 int y_offset = mi->item_num * Scr->EntryHeight; 457 458 /* be smart about handling the expose, redraw only the entries 459 * that we need to 460 */ 461 if (e->xexpose.y < (y_offset + Scr->EntryHeight) && 462 (e->xexpose.y + e->xexpose.height) > y_offset) 463 { 464 PaintEntry(mr, mi, True); 465 } 466 } 467 XSync(dpy, 0); 468} 469 470 471 472static Bool fromMenu; 473 474void 475UpdateMenu() 476{ 477 MenuItem *mi; 478 int i, x, y, x_root, y_root, entry; 479 int done; 480 MenuItem *badItem = NULL; 481 XPointer context_data; 482 483 fromMenu = TRUE; 484 485 while (TRUE) 486 { 487 /* block until there is an event */ 488 if (!menuFromFrameOrWindowOrTitlebar) { 489 XMaskEvent(dpy, 490 ButtonPressMask | ButtonReleaseMask | 491 EnterWindowMask | ExposureMask | 492 VisibilityChangeMask | LeaveWindowMask | 493 ButtonMotionMask, &Event); 494 } 495 if (Event.type == MotionNotify) { 496 /* discard any extra motion events before a release */ 497 while(XCheckMaskEvent(dpy, 498 ButtonMotionMask | ButtonReleaseMask, &Event)) 499 if (Event.type == ButtonRelease) 500 break; 501 } 502 503 if (!DispatchEvent ()) 504 continue; 505 506 if (Event.type == ButtonRelease || Cancel) { 507 menuFromFrameOrWindowOrTitlebar = FALSE; 508 fromMenu = FALSE; 509 return; 510 } 511 512 if (Event.type != MotionNotify) 513 continue; 514 515 if (!ActiveMenu) 516 continue; 517 518 done = FALSE; 519 XQueryPointer( dpy, ActiveMenu->w, &JunkRoot, &JunkChild, 520 &x_root, &y_root, &x, &y, &JunkMask); 521 522 /* if we haven't recieved the enter notify yet, wait */ 523 if (!ActiveMenu->entered) 524 continue; 525 526 if (XFindContext(dpy, ActiveMenu->w, ScreenContext, &context_data) == 0) 527 Scr = (struct ScreenInfo *) context_data; 528 529 if (x < 0 || y < 0 || 530 x >= ActiveMenu->width || y >= ActiveMenu->height) 531 { 532 if (ActiveItem && ActiveItem->func != F_TITLE) 533 { 534 ActiveItem->state = 0; 535 PaintEntry(ActiveMenu, ActiveItem, False); 536 } 537 ActiveItem = NULL; 538 continue; 539 } 540 541 /* look for the entry that the mouse is in */ 542 entry = y / Scr->EntryHeight; 543 for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next) 544 { 545 if (i == entry) 546 break; 547 } 548 549 /* if there is an active item, we might have to turn it off */ 550 if (ActiveItem) 551 { 552 /* is the active item the one we are on ? */ 553 if (ActiveItem->item_num == entry && ActiveItem->state) 554 done = TRUE; 555 556 /* if we weren't on the active entry, let's turn the old 557 * active one off 558 */ 559 if (!done && ActiveItem->func != F_TITLE) 560 { 561 ActiveItem->state = 0; 562 PaintEntry(ActiveMenu, ActiveItem, False); 563 } 564 } 565 566 /* if we weren't on the active item, change the active item and turn 567 * it on 568 */ 569 if (!done) 570 { 571 ActiveItem = mi; 572 if (ActiveItem && ActiveItem->func != F_TITLE && !ActiveItem->state) 573 { 574 ActiveItem->state = 1; 575 PaintEntry(ActiveMenu, ActiveItem, False); 576 } 577 } 578 579 /* now check to see if we were over the arrow of a pull right entry */ 580 if (ActiveItem && ActiveItem->func == F_MENU && 581 ((ActiveMenu->width - x) < (ActiveMenu->width >> 1))) 582 { 583 MenuRoot *save = ActiveMenu; 584 int savex = MenuOrigins[MenuDepth - 1].x; 585 int savey = MenuOrigins[MenuDepth - 1].y; 586 587 if (MenuDepth < MAXMENUDEPTH) { 588 PopUpMenu (ActiveItem->sub, 589 (savex + (ActiveMenu->width >> 1)), 590 (savey + ActiveItem->item_num * Scr->EntryHeight) 591 /*(savey + ActiveItem->item_num * Scr->EntryHeight + 592 (Scr->EntryHeight >> 1))*/, False); 593 } else if (!badItem) { 594 Bell(XkbBI_MinorError,0,None); 595 badItem = ActiveItem; 596 } 597 598 /* if the menu did get popped up, unhighlight the active item */ 599 if (save != ActiveMenu && ActiveItem->state) 600 { 601 ActiveItem->state = 0; 602 PaintEntry(save, ActiveItem, False); 603 ActiveItem = NULL; 604 } 605 } 606 if (badItem != ActiveItem) badItem = NULL; 607 XFlush(dpy); 608 } 609 610} 611 612 613 614/** 615 * create a new menu root 616 * 617 * \param name the name of the menu root 618 */ 619MenuRoot * 620NewMenuRoot(char *name) 621{ 622 MenuRoot *tmp; 623 624#define UNUSED_PIXEL ((unsigned long) (~0)) /* more than 24 bits */ 625 626 tmp = (MenuRoot *) malloc(sizeof(MenuRoot)); 627 tmp->hi_fore = UNUSED_PIXEL; 628 tmp->hi_back = UNUSED_PIXEL; 629 tmp->name = name; 630 tmp->prev = NULL; 631 tmp->first = NULL; 632 tmp->last = NULL; 633 tmp->items = 0; 634 tmp->width = 0; 635 tmp->mapped = NEVER_MAPPED; 636 tmp->pull = FALSE; 637 tmp->w = None; 638 tmp->shadow = None; 639 tmp->real_menu = FALSE; 640 641 if (Scr->MenuList == NULL) 642 { 643 Scr->MenuList = tmp; 644 Scr->MenuList->next = NULL; 645 } 646 647 if (Scr->LastMenu == NULL) 648 { 649 Scr->LastMenu = tmp; 650 Scr->LastMenu->next = NULL; 651 } 652 else 653 { 654 Scr->LastMenu->next = tmp; 655 Scr->LastMenu = tmp; 656 Scr->LastMenu->next = NULL; 657 } 658 659 if (strcmp(name, TWM_WINDOWS) == 0) 660 Scr->Windows = tmp; 661 662 return (tmp); 663} 664 665 666 667/** 668 * add an item to a root menu 669 * 670 * \param menu pointer to the root menu to add the item 671 * \param item the text to appear in the menu 672 * \param action the string to possibly execute 673 * \param sub the menu root if it is a pull-right entry 674 * \param func the numeric function 675 * \param fore foreground color string 676 * \param back background color string 677 */ 678MenuItem * 679AddToMenu(MenuRoot *menu, char *item, char *action, MenuRoot *sub, int func, 680 char *fore, char *back) 681{ 682 MenuItem *tmp; 683 int width; 684 685#ifdef DEBUG_MENUS 686 fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n", 687 item, action, sub, func); 688#endif 689 690 tmp = (MenuItem *) malloc(sizeof(MenuItem)); 691 tmp->root = menu; 692 693 if (menu->first == NULL) 694 { 695 menu->first = tmp; 696 tmp->prev = NULL; 697 } 698 else 699 { 700 menu->last->next = tmp; 701 tmp->prev = menu->last; 702 } 703 menu->last = tmp; 704 705 tmp->item = item; 706 tmp->strlen = strlen(item); 707 tmp->action = action; 708 tmp->next = NULL; 709 tmp->sub = NULL; 710 tmp->state = 0; 711 tmp->func = func; 712 713 if (!Scr->HaveFonts) CreateFonts(); 714 width = MyFont_TextWidth(&Scr->MenuFont, item, tmp->strlen); 715 if (width <= 0) 716 width = 1; 717 if (width > menu->width) 718 menu->width = width; 719 720 tmp->user_colors = FALSE; 721 if (Scr->Monochrome == COLOR && fore != NULL) 722 { 723 int save; 724 725 save = Scr->FirstTime; 726 Scr->FirstTime = TRUE; 727 GetColor(COLOR, &tmp->fore, fore); 728 GetColor(COLOR, &tmp->back, back); 729 Scr->FirstTime = save; 730 tmp->user_colors = TRUE; 731 } 732 if (sub != NULL) 733 { 734 tmp->sub = sub; 735 menu->pull = TRUE; 736 } 737 tmp->item_num = menu->items++; 738 739 return (tmp); 740} 741 742 743void 744MakeMenus() 745{ 746 MenuRoot *mr; 747 748 for (mr = Scr->MenuList; mr != NULL; mr = mr->next) 749 { 750 if (mr->real_menu == FALSE) 751 continue; 752 753 MakeMenu(mr); 754 } 755} 756 757 758void 759MakeMenu(MenuRoot *mr) 760{ 761 MenuItem *start, *end, *cur, *tmp; 762 XColor f1, f2, f3; 763 XColor b1, b2, b3; 764 XColor save_fore, save_back; 765 int num, i; 766 int fred, fgreen, fblue; 767 int bred, bgreen, bblue; 768 int width; 769 unsigned long valuemask; 770 XSetWindowAttributes attributes; 771 Colormap cmap = Scr->TwmRoot.cmaps.cwins[0]->colormap->c; 772 773 Scr->EntryHeight = Scr->MenuFont.height + 4; 774 775 /* lets first size the window accordingly */ 776 if (mr->mapped == NEVER_MAPPED) 777 { 778 if (mr->pull == TRUE) 779 { 780 mr->width += 16 + 10; 781 } 782 783 width = mr->width + 10; 784 785 for (cur = mr->first; cur != NULL; cur = cur->next) 786 { 787 if (cur->func != F_TITLE) 788 cur->x = 5; 789 else 790 { 791 cur->x = width - MyFont_TextWidth(&Scr->MenuFont, cur->item, 792 cur->strlen); 793 cur->x /= 2; 794 } 795 } 796 mr->height = mr->items * Scr->EntryHeight; 797 mr->width += 10; 798 799 if (Scr->Shadow) 800 { 801 /* 802 * Make sure that you don't draw into the shadow window or else 803 * the background bits there will get saved 804 */ 805 valuemask = (CWBackPixel | CWBorderPixel); 806 attributes.background_pixel = Scr->MenuShadowColor; 807 attributes.border_pixel = Scr->MenuShadowColor; 808 if (Scr->SaveUnder) { 809 valuemask |= CWSaveUnder; 810 attributes.save_under = True; 811 } 812 mr->shadow = XCreateWindow (dpy, Scr->Root, 0, 0, 813 (unsigned int) mr->width, 814 (unsigned int) mr->height, 815 (unsigned int)0, 816 CopyFromParent, 817 (unsigned int) CopyFromParent, 818 (Visual *) CopyFromParent, 819 valuemask, &attributes); 820 } 821 822 valuemask = (CWBackPixel | CWBorderPixel | CWEventMask); 823 attributes.background_pixel = Scr->MenuC.back; 824 attributes.border_pixel = Scr->MenuBorderColor; 825 attributes.event_mask = (ExposureMask | EnterWindowMask); 826 if (Scr->SaveUnder) { 827 valuemask |= CWSaveUnder; 828 attributes.save_under = True; 829 } 830 if (Scr->BackingStore) { 831 valuemask |= CWBackingStore; 832 attributes.backing_store = Always; 833 } 834 mr->w = XCreateWindow (dpy, Scr->Root, 0, 0, (unsigned int) mr->width, 835 (unsigned int) mr->height, 836 (unsigned int) Scr->MenuBorderWidth, 837 CopyFromParent, (unsigned int) CopyFromParent, 838 (Visual *) CopyFromParent, 839 valuemask, &attributes); 840 841 842 XSaveContext(dpy, mr->w, MenuContext, (caddr_t)mr); 843 XSaveContext(dpy, mr->w, ScreenContext, (caddr_t)Scr); 844 845 mr->mapped = UNMAPPED; 846 } 847 848 /* get the default colors into the menus */ 849 for (tmp = mr->first; tmp != NULL; tmp = tmp->next) 850 { 851 if (!tmp->user_colors) { 852 if (tmp->func != F_TITLE) { 853 tmp->fore = Scr->MenuC.fore; 854 tmp->back = Scr->MenuC.back; 855 } else { 856 tmp->fore = Scr->MenuTitleC.fore; 857 tmp->back = Scr->MenuTitleC.back; 858 } 859 } 860 861 if (mr->hi_fore != UNUSED_PIXEL) 862 { 863 tmp->hi_fore = mr->hi_fore; 864 tmp->hi_back = mr->hi_back; 865 } 866 else 867 { 868 tmp->hi_fore = tmp->back; 869 tmp->hi_back = tmp->fore; 870 } 871 } 872 873 if (Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors) 874 return; 875 876 start = mr->first; 877 while (TRUE) 878 { 879 for (; start != NULL; start = start->next) 880 { 881 if (start->user_colors) 882 break; 883 } 884 if (start == NULL) 885 break; 886 887 for (end = start->next; end != NULL; end = end->next) 888 { 889 if (end->user_colors) 890 break; 891 } 892 if (end == NULL) 893 break; 894 895 /* we have a start and end to interpolate between */ 896 num = end->item_num - start->item_num; 897 898 f1.pixel = start->fore; 899 XQueryColor(dpy, cmap, &f1); 900 f2.pixel = end->fore; 901 XQueryColor(dpy, cmap, &f2); 902 903 b1.pixel = start->back; 904 XQueryColor(dpy, cmap, &b1); 905 b2.pixel = end->back; 906 XQueryColor(dpy, cmap, &b2); 907 908 fred = ((int)f2.red - (int)f1.red) / num; 909 fgreen = ((int)f2.green - (int)f1.green) / num; 910 fblue = ((int)f2.blue - (int)f1.blue) / num; 911 912 bred = ((int)b2.red - (int)b1.red) / num; 913 bgreen = ((int)b2.green - (int)b1.green) / num; 914 bblue = ((int)b2.blue - (int)b1.blue) / num; 915 916 f3 = f1; 917 f3.flags = DoRed | DoGreen | DoBlue; 918 919 b3 = b1; 920 b3.flags = DoRed | DoGreen | DoBlue; 921 922 num -= 1; 923 for (i = 0, cur = start->next; i < num && cur; i++, cur = cur->next) 924 { 925 f3.red += fred; 926 f3.green += fgreen; 927 f3.blue += fblue; 928 save_fore = f3; 929 930 b3.red += bred; 931 b3.green += bgreen; 932 b3.blue += bblue; 933 save_back = b3; 934 935 XAllocColor(dpy, cmap, &f3); 936 XAllocColor(dpy, cmap, &b3); 937 cur->hi_back = cur->fore = f3.pixel; 938 cur->hi_fore = cur->back = b3.pixel; 939 cur->user_colors = True; 940 941 f3 = save_fore; 942 b3 = save_back; 943 } 944 start = end; 945 } 946} 947 948 949 950/** 951 * pop up a pull down menu. 952 * 953 * \param menu the root pointer of the menu to pop up 954 * \param x,y location of upper left of menu 955 * \param center whether or not to center horizontally over position 956 */ 957Bool 958PopUpMenu (MenuRoot *menu, int x, int y, Bool center) 959{ 960 int WindowNameCount; 961 TwmWindow **WindowNames; 962 TwmWindow *tmp_win2,*tmp_win3; 963 int i; 964 int (*compar)(const char *, const char *) = 965 (Scr->CaseSensitive ? strcmp : XmuCompareISOLatin1); 966 967 if (!menu) return False; 968 969 InstallRootColormap(); 970 971 if (menu == Scr->Windows) 972 { 973 TwmWindow *tmp_win; 974 975 /* this is the twm windows menu, let's go ahead and build it */ 976 977 DestroyMenu (menu); 978 979 menu->first = NULL; 980 menu->last = NULL; 981 menu->items = 0; 982 menu->width = 0; 983 menu->mapped = NEVER_MAPPED; 984 AddToMenu(menu, "TWM Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR); 985 986 for(tmp_win = Scr->TwmRoot.next , WindowNameCount=0; 987 tmp_win != NULL; 988 tmp_win = tmp_win->next) 989 WindowNameCount++; 990 if (WindowNameCount != 0) 991 { 992 WindowNames = 993 (TwmWindow **)malloc(sizeof(TwmWindow *)*WindowNameCount); 994 WindowNames[0] = Scr->TwmRoot.next; 995 for(tmp_win = Scr->TwmRoot.next->next , WindowNameCount=1; 996 tmp_win != NULL; 997 tmp_win = tmp_win->next,WindowNameCount++) 998 { 999 tmp_win2 = tmp_win; 1000 for (i=0;i<WindowNameCount;i++) 1001 { 1002 if ((*compar)(tmp_win2->name,WindowNames[i]->name) < 0) 1003 { 1004 tmp_win3 = tmp_win2; 1005 tmp_win2 = WindowNames[i]; 1006 WindowNames[i] = tmp_win3; 1007 } 1008 } 1009 WindowNames[WindowNameCount] = tmp_win2; 1010 } 1011 for (i=0; i<WindowNameCount; i++) 1012 { 1013 AddToMenu(menu, WindowNames[i]->name, (char *)WindowNames[i], 1014 NULL, F_POPUP,NULL,NULL); 1015 } 1016 free(WindowNames); 1017 } 1018 1019 MakeMenu(menu); 1020 } 1021 1022 if (menu->w == None || menu->items == 0) return False; 1023 1024 /* Prevent recursively bringing up menus. */ 1025 if (menu->mapped == MAPPED) return False; 1026 1027 /* 1028 * Dynamically set the parent; this allows pull-ups to also be main 1029 * menus, or to be brought up from more than one place. 1030 */ 1031 menu->prev = ActiveMenu; 1032 1033 XGrabPointer(dpy, Scr->Root, True, 1034 ButtonPressMask | ButtonReleaseMask | 1035 ButtonMotionMask | PointerMotionHintMask, 1036 GrabModeAsync, GrabModeAsync, 1037 Scr->Root, Scr->MenuCursor, CurrentTime); 1038 1039 ActiveMenu = menu; 1040 menu->mapped = MAPPED; 1041 menu->entered = FALSE; 1042 1043 if (center) { 1044 x -= (menu->width / 2); 1045 y -= (Scr->EntryHeight / 2); /* sticky menus would be nice here */ 1046 } 1047 1048 /* 1049 * clip to screen 1050 */ 1051 if (x + menu->width > Scr->MyDisplayWidth) { 1052 x = Scr->MyDisplayWidth - menu->width; 1053 } 1054 if (x < 0) x = 0; 1055 if (y + menu->height > Scr->MyDisplayHeight) { 1056 y = Scr->MyDisplayHeight - menu->height; 1057 } 1058 if (y < 0) y = 0; 1059 1060 MenuOrigins[MenuDepth].x = x; 1061 MenuOrigins[MenuDepth].y = y; 1062 MenuDepth++; 1063 1064 XMoveWindow(dpy, menu->w, x, y); 1065 if (Scr->Shadow) { 1066 XMoveWindow (dpy, menu->shadow, x + SHADOWWIDTH, y + SHADOWWIDTH); 1067 } 1068 if (Scr->Shadow) { 1069 XRaiseWindow (dpy, menu->shadow); 1070 } 1071 XMapRaised(dpy, menu->w); 1072 if (Scr->Shadow) { 1073 XMapWindow (dpy, menu->shadow); 1074 } 1075 XSync(dpy, 0); 1076 return True; 1077} 1078 1079 1080 1081/** 1082 * unhighlight the current menu selection and take down the menus 1083 */ 1084void 1085PopDownMenu() 1086{ 1087 MenuRoot *tmp; 1088 1089 if (ActiveMenu == NULL) 1090 return; 1091 1092 if (ActiveItem) 1093 { 1094 ActiveItem->state = 0; 1095 PaintEntry(ActiveMenu, ActiveItem, False); 1096 } 1097 1098 for (tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev) 1099 { 1100 if (Scr->Shadow) { 1101 XUnmapWindow (dpy, tmp->shadow); 1102 } 1103 XUnmapWindow(dpy, tmp->w); 1104 tmp->mapped = UNMAPPED; 1105 UninstallRootColormap(); 1106 } 1107 1108 XFlush(dpy); 1109 ActiveMenu = NULL; 1110 ActiveItem = NULL; 1111 MenuDepth = 0; 1112 if (Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE) 1113 menuFromFrameOrWindowOrTitlebar = TRUE; 1114} 1115 1116 1117 1118/** 1119 * look for a menu root 1120 * 1121 * \return a pointer to the menu root structure 1122 * 1123 * \param name the name of the menu root 1124 */ 1125MenuRoot * 1126FindMenuRoot(char *name) 1127{ 1128 MenuRoot *tmp; 1129 1130 for (tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next) 1131 { 1132 if (strcmp(name, tmp->name) == 0) 1133 return (tmp); 1134 } 1135 return NULL; 1136} 1137 1138 1139 1140static Bool 1141belongs_to_twm_window (TwmWindow *t, Window w) 1142{ 1143 if (!t) return False; 1144 1145 if (w == t->frame || w == t->title_w || w == t->hilite_w || 1146 w == t->icon_w || w == t->icon_bm_w) return True; 1147 1148 if (t && t->titlebuttons) { 1149 register TBWindow *tbw; 1150 register int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; 1151 for (tbw = t->titlebuttons; nb > 0; tbw++, nb--) { 1152 if (tbw->window == w) return True; 1153 } 1154 } 1155 return False; 1156} 1157 1158 1159 1160void 1161resizeFromCenter(Window w, TwmWindow *tmp_win) 1162{ 1163 int lastx, lasty, bw2; 1164 XEvent event; 1165#if 0 1166 int namelen; 1167 int width, height; 1168 1169 namelen = strlen (tmp_win->name); 1170#endif 1171 bw2 = tmp_win->frame_bw * 2; 1172 AddingW = tmp_win->attr.width + bw2; 1173 AddingH = tmp_win->attr.height + tmp_win->title_height + bw2; 1174#if 0 1175 width = (SIZE_HINDENT + MyFont_TextWidth (&Scr->SizeFont, 1176 tmp_win->name, namelen)); 1177 height = Scr->SizeFont.height + SIZE_VINDENT * 2; 1178#endif 1179 XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY, 1180 (unsigned int *)&DragWidth, (unsigned int *)&DragHeight, 1181 &JunkBW, &JunkDepth); 1182 XWarpPointer(dpy, None, w, 1183 0, 0, 0, 0, DragWidth/2, DragHeight/2); 1184 XQueryPointer (dpy, Scr->Root, &JunkRoot, 1185 &JunkChild, &JunkX, &JunkY, 1186 &AddingX, &AddingY, &JunkMask); 1187#if 0 1188 Scr->SizeStringOffset = width + 1189 MyFont_TextWidth(&Scr->SizeFont, ": ", 2); 1190 XResizeWindow (dpy, Scr->SizeWindow, Scr->SizeStringOffset + 1191 Scr->SizeStringWidth, height); 1192 MyFont_DrawImageString (dpy, Scr->SizeWindow, &Scr->SizeFont, Scr->NormalGC, 1193 width, SIZE_VINDENT + Scr->SizeFont.ascent, 1194 ": ", 2); 1195#endif 1196 lastx = -10000; 1197 lasty = -10000; 1198#if 0 1199 MoveOutline(Scr->Root, 1200 origDragX - JunkBW, origDragY - JunkBW, 1201 DragWidth * JunkBW, DragHeight * JunkBW, 1202 tmp_win->frame_bw, 1203 tmp_win->title_height); 1204#endif 1205 MenuStartResize(tmp_win, origDragX, origDragY, DragWidth, DragHeight); 1206 while (TRUE) 1207 { 1208 XMaskEvent(dpy, 1209 ButtonPressMask | PointerMotionMask, &event); 1210 1211 if (event.type == MotionNotify) { 1212 /* discard any extra motion events before a release */ 1213 while(XCheckMaskEvent(dpy, 1214 ButtonMotionMask | ButtonPressMask, &event)) 1215 if (event.type == ButtonPress) 1216 break; 1217 } 1218 1219 if (event.type == ButtonPress) 1220 { 1221 MenuEndResize(tmp_win); 1222 XMoveResizeWindow(dpy, w, AddingX, AddingY, AddingW, AddingH); 1223 break; 1224 } 1225 1226/* if (!DispatchEvent ()) continue; */ 1227 1228 if (event.type != MotionNotify) { 1229 continue; 1230 } 1231 1232 /* 1233 * XXX - if we are going to do a loop, we ought to consider 1234 * using multiple GXxor lines so that we don't need to 1235 * grab the server. 1236 */ 1237 XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild, 1238 &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask); 1239 1240 if (lastx != AddingX || lasty != AddingY) 1241 { 1242 MenuDoResize(AddingX, AddingY, tmp_win); 1243 1244 lastx = AddingX; 1245 lasty = AddingY; 1246 } 1247 1248 } 1249} 1250 1251 1252 1253/** \fn ExecuteFunction 1254 * execute a twm root function. 1255 * 1256 * \param func the function to execute 1257 * \param action the menu action to execute 1258 * \param w the window to execute this function on 1259 * \param tmp_win the twm window structure 1260 * \param event the event that caused the function 1261 * \param context the context in which the button was pressed 1262 * \param pulldown flag indicating execution from pull down menu 1263 * 1264 * \return TRUE if should continue with remaining actions, 1265 * else FALSE to abort 1266 */ 1267 1268int 1269WarpThere(TwmWindow *t) 1270{ 1271 if (Scr->WarpUnmapped || t->mapped) { 1272 if (!t->mapped) DeIconify (t); 1273 if (!Scr->NoRaiseWarp) XRaiseWindow (dpy, t->frame); 1274 WarpToWindow (t); 1275 return 1; 1276 } 1277 return 0; 1278} 1279 1280 1281int 1282ExecuteFunction(int func, char *action, Window w, TwmWindow *tmp_win, 1283 XEvent *eventp, int context, int pulldown) 1284{ 1285 static Time last_time = 0; 1286 char tmp[200]; 1287 char *ptr; 1288 char buff[MAX_FILE_SIZE]; 1289 int count, fd; 1290 Window rootw; 1291 int origX, origY; 1292 int do_next_action = TRUE; 1293 int moving_icon = FALSE; 1294 Bool fromtitlebar = False; 1295 1296 RootFunction = 0; 1297 if (Cancel) 1298 return TRUE; /* XXX should this be FALSE? */ 1299 1300 switch (func) 1301 { 1302 case F_UPICONMGR: 1303 case F_LEFTICONMGR: 1304 case F_RIGHTICONMGR: 1305 case F_DOWNICONMGR: 1306 case F_FORWICONMGR: 1307 case F_BACKICONMGR: 1308 case F_NEXTICONMGR: 1309 case F_PREVICONMGR: 1310 case F_NOP: 1311 case F_TITLE: 1312 case F_DELTASTOP: 1313 case F_RAISELOWER: 1314 case F_WARPTOSCREEN: 1315 case F_WARPTO: 1316 case F_WARPRING: 1317 case F_WARPTOICONMGR: 1318 case F_WARPNEXT: 1319 case F_WARPPREV: 1320 case F_COLORMAP: 1321 break; 1322 default: 1323 XGrabPointer(dpy, Scr->Root, True, 1324 ButtonPressMask | ButtonReleaseMask, 1325 GrabModeAsync, GrabModeAsync, 1326 Scr->Root, Scr->WaitCursor, CurrentTime); 1327 break; 1328 } 1329 1330 switch (func) 1331 { 1332 case F_NOP: 1333 case F_TITLE: 1334 break; 1335 1336 case F_DELTASTOP: 1337 if (WindowMoved) do_next_action = FALSE; 1338 break; 1339 1340 case F_RESTART: 1341 { 1342 XSync (dpy, 0); 1343 Reborder (eventp->xbutton.time); 1344 XSync (dpy, 0); 1345 if (smcConn) 1346 SmcCloseConnection (smcConn, 0, NULL); 1347 execvp(*Argv, Argv); 1348 fprintf (stderr, "%s: unable to restart: %s\n", ProgramName, *Argv); 1349 break; 1350 } 1351 1352 case F_UPICONMGR: 1353 case F_DOWNICONMGR: 1354 case F_LEFTICONMGR: 1355 case F_RIGHTICONMGR: 1356 case F_FORWICONMGR: 1357 case F_BACKICONMGR: 1358 MoveIconManager(func); 1359 break; 1360 1361 case F_NEXTICONMGR: 1362 case F_PREVICONMGR: 1363 JumpIconManager(func); 1364 break; 1365 1366 case F_SHOWLIST: 1367 if (Scr->NoIconManagers) 1368 break; 1369 DeIconify(Scr->iconmgr.twm_win); 1370 XRaiseWindow(dpy, Scr->iconmgr.twm_win->frame); 1371 break; 1372 1373 case F_HIDELIST: 1374 if (Scr->NoIconManagers) 1375 break; 1376 HideIconManager (); 1377 break; 1378 1379 case F_SORTICONMGR: 1380 if (DeferExecution(context, func, Scr->SelectCursor)) 1381 return TRUE; 1382 1383 { 1384 int save_sort; 1385 1386 save_sort = Scr->SortIconMgr; 1387 Scr->SortIconMgr = TRUE; 1388 1389 if (context == C_ICONMGR) 1390 SortIconManager((IconMgr *) NULL); 1391 else if (tmp_win->iconmgr) 1392 SortIconManager(tmp_win->iconmgrp); 1393 else 1394 Bell(XkbBI_Info,0,tmp_win->w); 1395 1396 Scr->SortIconMgr = save_sort; 1397 } 1398 break; 1399 1400 case F_IDENTIFY: 1401 if (DeferExecution(context, func, Scr->SelectCursor)) 1402 return TRUE; 1403 1404 Identify(tmp_win); 1405 break; 1406 1407 case F_VERSION: 1408 Identify ((TwmWindow *) NULL); 1409 break; 1410 1411 case F_AUTORAISE: 1412 if (DeferExecution(context, func, Scr->SelectCursor)) 1413 return TRUE; 1414 1415 tmp_win->auto_raise = !tmp_win->auto_raise; 1416 if (tmp_win->auto_raise) ++(Scr->NumAutoRaises); 1417 else --(Scr->NumAutoRaises); 1418 break; 1419 1420 case F_BEEP: 1421 Bell(XkbBI_Info,0,None); 1422 break; 1423 1424 case F_POPUP: 1425 tmp_win = (TwmWindow *)action; 1426 if (Scr->WindowFunction.func != 0) 1427 { 1428 ExecuteFunction(Scr->WindowFunction.func, 1429 Scr->WindowFunction.item->action, 1430 w, tmp_win, eventp, C_FRAME, FALSE); 1431 } 1432 else 1433 { 1434 DeIconify(tmp_win); 1435 XRaiseWindow (dpy, tmp_win->frame); 1436 } 1437 break; 1438 1439 case F_RESIZE: 1440 EventHandler[EnterNotify] = HandleUnknown; 1441 EventHandler[LeaveNotify] = HandleUnknown; 1442 if (DeferExecution(context, func, Scr->MoveCursor)) 1443 return TRUE; 1444 1445 PopDownMenu(); 1446 1447 if (pulldown) 1448 XWarpPointer(dpy, None, Scr->Root, 1449 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root); 1450 1451 if (w != tmp_win->icon_w) { /* can't resize icons */ 1452 1453 if ((Context == C_FRAME || Context == C_WINDOW || Context == C_TITLE) 1454 && fromMenu) 1455 resizeFromCenter(w, tmp_win); 1456 else { 1457 /* 1458 * see if this is being done from the titlebar 1459 */ 1460 fromtitlebar = 1461 belongs_to_twm_window (tmp_win, eventp->xbutton.window); 1462 1463 /* Save pointer position so we can tell if it was moved or 1464 not during the resize. */ 1465 ResizeOrigX = eventp->xbutton.x_root; 1466 ResizeOrigY = eventp->xbutton.y_root; 1467 1468 StartResize (eventp, tmp_win, fromtitlebar); 1469 1470 do { 1471 XMaskEvent(dpy, 1472 ButtonPressMask | ButtonReleaseMask | 1473 EnterWindowMask | LeaveWindowMask | 1474 ButtonMotionMask, &Event); 1475 1476 if (fromtitlebar && Event.type == ButtonPress) { 1477 fromtitlebar = False; 1478 continue; 1479 } 1480 1481 if (Event.type == MotionNotify) { 1482 /* discard any extra motion events before a release */ 1483 while 1484 (XCheckMaskEvent 1485 (dpy, ButtonMotionMask | ButtonReleaseMask, &Event)) 1486 if (Event.type == ButtonRelease) 1487 break; 1488 } 1489 1490 if (!DispatchEvent ()) continue; 1491 1492 } while (!(Event.type == ButtonRelease || Cancel)); 1493 return TRUE; 1494 } 1495 } 1496 break; 1497 1498 1499 case F_ZOOM: 1500 case F_HORIZOOM: 1501 case F_FULLZOOM: 1502 case F_LEFTZOOM: 1503 case F_RIGHTZOOM: 1504 case F_TOPZOOM: 1505 case F_BOTTOMZOOM: 1506 if (DeferExecution(context, func, Scr->SelectCursor)) 1507 return TRUE; 1508 fullzoom(tmp_win, func); 1509 break; 1510 1511 case F_MOVE: 1512 case F_FORCEMOVE: 1513 if (DeferExecution(context, func, Scr->MoveCursor)) 1514 return TRUE; 1515 1516 PopDownMenu(); 1517 rootw = eventp->xbutton.root; 1518 MoveFunction = func; 1519 1520 if (pulldown) 1521 XWarpPointer(dpy, None, Scr->Root, 1522 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root); 1523 1524 EventHandler[EnterNotify] = HandleUnknown; 1525 EventHandler[LeaveNotify] = HandleUnknown; 1526 1527 if (!Scr->NoGrabServer || !Scr->OpaqueMove) { 1528 XGrabServer(dpy); 1529 } 1530 XGrabPointer(dpy, eventp->xbutton.root, True, 1531 ButtonPressMask | ButtonReleaseMask | 1532 ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */ 1533 GrabModeAsync, GrabModeAsync, 1534 Scr->Root, Scr->MoveCursor, CurrentTime); 1535 1536 if (context == C_ICON && tmp_win->icon_w) 1537 { 1538 w = tmp_win->icon_w; 1539 DragX = eventp->xbutton.x; 1540 DragY = eventp->xbutton.y; 1541 moving_icon = TRUE; 1542 } 1543 1544 else if (w != tmp_win->icon_w) 1545 { 1546 XTranslateCoordinates(dpy, w, tmp_win->frame, 1547 eventp->xbutton.x, 1548 eventp->xbutton.y, 1549 &DragX, &DragY, &JunkChild); 1550 1551 w = tmp_win->frame; 1552 } 1553 1554 DragWindow = None; 1555 1556 XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY, 1557 (unsigned int *)&DragWidth, (unsigned int *)&DragHeight, &JunkBW, 1558 &JunkDepth); 1559 1560 origX = eventp->xbutton.x_root; 1561 origY = eventp->xbutton.y_root; 1562 CurrentDragX = origDragX; 1563 CurrentDragY = origDragY; 1564 1565 /* 1566 * only do the constrained move if timer is set; need to check it 1567 * in case of stupid or wicked fast servers 1568 */ 1569 if (ConstrainedMoveTime && 1570 (eventp->xbutton.time - last_time) < ConstrainedMoveTime) 1571 { 1572 int width, height; 1573 1574 ConstMove = TRUE; 1575 ConstMoveDir = MOVE_NONE; 1576 ConstMoveX = eventp->xbutton.x_root - DragX - JunkBW; 1577 ConstMoveY = eventp->xbutton.y_root - DragY - JunkBW; 1578 width = DragWidth + 2 * JunkBW; 1579 height = DragHeight + 2 * JunkBW; 1580 ConstMoveXL = ConstMoveX + width/3; 1581 ConstMoveXR = ConstMoveX + 2*(width/3); 1582 ConstMoveYT = ConstMoveY + height/3; 1583 ConstMoveYB = ConstMoveY + 2*(height/3); 1584 1585 XWarpPointer(dpy, None, w, 1586 0, 0, 0, 0, DragWidth/2, DragHeight/2); 1587 1588 XQueryPointer(dpy, w, &JunkRoot, &JunkChild, 1589 &JunkX, &JunkY, &DragX, &DragY, &JunkMask); 1590 } 1591 last_time = eventp->xbutton.time; 1592 1593 if (!Scr->OpaqueMove) 1594 { 1595 InstallRootColormap(); 1596 if (!Scr->MoveDelta) 1597 { 1598 /* 1599 * Draw initial outline. This was previously done the 1600 * first time though the outer loop by dropping out of 1601 * the XCheckMaskEvent inner loop down to one of the 1602 * MoveOutline's below. 1603 */ 1604 MoveOutline(rootw, 1605 origDragX - JunkBW, origDragY - JunkBW, 1606 DragWidth + 2 * JunkBW, DragHeight + 2 * JunkBW, 1607 tmp_win->frame_bw, 1608 moving_icon ? 0 : tmp_win->title_height); 1609 /* 1610 * This next line causes HandleReleaseNotify to call 1611 * XRaiseWindow(). This is solely to preserve the 1612 * previous behaviour that raises a window being moved 1613 * on button release even if you never actually moved 1614 * any distance (unless you move less than MoveDelta or 1615 * NoRaiseMove is set or OpaqueMove is set). 1616 */ 1617 DragWindow = w; 1618 } 1619 } 1620 1621 /* 1622 * see if this is being done from the titlebar 1623 */ 1624 fromtitlebar = belongs_to_twm_window (tmp_win, eventp->xbutton.window); 1625 1626 if (menuFromFrameOrWindowOrTitlebar) { 1627 /* warp the pointer to the middle of the window */ 1628 XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0, 1629 origDragX + DragWidth / 2, 1630 origDragY + DragHeight / 2); 1631 XFlush(dpy); 1632 } 1633 1634 while (TRUE) 1635 { 1636 long releaseEvent = menuFromFrameOrWindowOrTitlebar ? 1637 ButtonPress : ButtonRelease; 1638 long movementMask = menuFromFrameOrWindowOrTitlebar ? 1639 PointerMotionMask : ButtonMotionMask; 1640 1641 /* block until there is an interesting event */ 1642 XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask | 1643 EnterWindowMask | LeaveWindowMask | 1644 ExposureMask | movementMask | 1645 VisibilityChangeMask, &Event); 1646 1647 /* throw away enter and leave events until release */ 1648 if (Event.xany.type == EnterNotify || 1649 Event.xany.type == LeaveNotify) continue; 1650 1651 if (Event.type == MotionNotify) { 1652 /* discard any extra motion events before a logical release */ 1653 while(XCheckMaskEvent(dpy, 1654 movementMask | releaseEvent, &Event)) 1655 if (Event.type == releaseEvent) 1656 break; 1657 } 1658 1659 /* test to see if we have a second button press to abort move */ 1660 if (!menuFromFrameOrWindowOrTitlebar && !MovedFromKeyPress) { 1661 if (Event.type == ButtonPress && DragWindow != None) { 1662 if (Scr->OpaqueMove) 1663 XMoveWindow (dpy, DragWindow, origDragX, origDragY); 1664 else 1665 MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0); 1666 DragWindow = None; 1667 } 1668 } 1669 if (fromtitlebar && Event.type == ButtonPress) { 1670 fromtitlebar = False; 1671 CurrentDragX = origX = Event.xbutton.x_root; 1672 CurrentDragY = origY = Event.xbutton.y_root; 1673 XTranslateCoordinates (dpy, rootw, tmp_win->frame, 1674 origX, origY, 1675 &DragX, &DragY, &JunkChild); 1676 continue; 1677 } 1678 1679 if (!DispatchEvent2 ()) continue; 1680 1681 if (Cancel) 1682 { 1683 WindowMoved = FALSE; 1684 if (!Scr->OpaqueMove) 1685 UninstallRootColormap(); 1686 return TRUE; /* XXX should this be FALSE? */ 1687 } 1688 if (Event.type == releaseEvent) 1689 { 1690 MoveOutline(rootw, 0, 0, 0, 0, 0, 0); 1691 if (moving_icon && 1692 ((CurrentDragX != origDragX || 1693 CurrentDragY != origDragY))) 1694 tmp_win->icon_moved = TRUE; 1695 if (!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar) 1696 XMoveWindow(dpy, DragWindow, 1697 Event.xbutton.x_root - DragWidth / 2, 1698 Event.xbutton.y_root - DragHeight / 2); 1699 break; 1700 } 1701 1702 /* something left to do only if the pointer moved */ 1703 if (Event.type != MotionNotify) 1704 continue; 1705 1706 XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild, 1707 &(eventp->xmotion.x_root), &(eventp->xmotion.y_root), 1708 &JunkX, &JunkY, &JunkMask); 1709 1710 if (DragWindow == None && 1711 abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta && 1712 abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta) 1713 continue; 1714 1715 WindowMoved = TRUE; 1716 DragWindow = w; 1717 1718 if (!Scr->NoRaiseMove && Scr->OpaqueMove) /* can't restore... */ 1719 XRaiseWindow(dpy, DragWindow); 1720 1721 if (ConstMove) 1722 { 1723 switch (ConstMoveDir) 1724 { 1725 case MOVE_NONE: 1726 if (eventp->xmotion.x_root < ConstMoveXL || 1727 eventp->xmotion.x_root > ConstMoveXR) 1728 ConstMoveDir = MOVE_HORIZ; 1729 1730 if (eventp->xmotion.y_root < ConstMoveYT || 1731 eventp->xmotion.y_root > ConstMoveYB) 1732 ConstMoveDir = MOVE_VERT; 1733 1734 XQueryPointer(dpy, DragWindow, &JunkRoot, &JunkChild, 1735 &JunkX, &JunkY, &DragX, &DragY, &JunkMask); 1736 break; 1737 1738 case MOVE_VERT: 1739 ConstMoveY = eventp->xmotion.y_root - DragY - JunkBW; 1740 break; 1741 1742 case MOVE_HORIZ: 1743 ConstMoveX= eventp->xmotion.x_root - DragX - JunkBW; 1744 break; 1745 } 1746 1747 if (ConstMoveDir != MOVE_NONE) 1748 { 1749 int xl, yt, xr, yb, w, h; 1750 1751 xl = ConstMoveX; 1752 yt = ConstMoveY; 1753 w = DragWidth + 2 * JunkBW; 1754 h = DragHeight + 2 * JunkBW; 1755 1756 if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) 1757 { 1758 xr = xl + w; 1759 yb = yt + h; 1760 1761 if (xl < 0) 1762 xl = 0; 1763 if (xr > Scr->MyDisplayWidth) 1764 xl = Scr->MyDisplayWidth - w; 1765 1766 if (yt < 0) 1767 yt = 0; 1768 if (yb > Scr->MyDisplayHeight) 1769 yt = Scr->MyDisplayHeight - h; 1770 } 1771 CurrentDragX = xl; 1772 CurrentDragY = yt; 1773 if (Scr->OpaqueMove) 1774 XMoveWindow(dpy, DragWindow, xl, yt); 1775 else 1776 MoveOutline(eventp->xmotion.root, xl, yt, w, h, 1777 tmp_win->frame_bw, 1778 moving_icon ? 0 : tmp_win->title_height); 1779 } 1780 } 1781 else if (DragWindow != None) 1782 { 1783 int xl, yt, xr, yb, w, h; 1784 if (!menuFromFrameOrWindowOrTitlebar) { 1785 xl = eventp->xmotion.x_root - DragX - JunkBW; 1786 yt = eventp->xmotion.y_root - DragY - JunkBW; 1787 } 1788 else { 1789 xl = eventp->xmotion.x_root - (DragWidth / 2); 1790 yt = eventp->xmotion.y_root - (DragHeight / 2); 1791 } 1792 w = DragWidth + 2 * JunkBW; 1793 h = DragHeight + 2 * JunkBW; 1794 1795 if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) 1796 { 1797 xr = xl + w; 1798 yb = yt + h; 1799 1800 if (xl < 0) 1801 xl = 0; 1802 if (xr > Scr->MyDisplayWidth) 1803 xl = Scr->MyDisplayWidth - w; 1804 1805 if (yt < 0) 1806 yt = 0; 1807 if (yb > Scr->MyDisplayHeight) 1808 yt = Scr->MyDisplayHeight - h; 1809 } 1810 1811 CurrentDragX = xl; 1812 CurrentDragY = yt; 1813 if (Scr->OpaqueMove) 1814 XMoveWindow(dpy, DragWindow, xl, yt); 1815 else 1816 MoveOutline(eventp->xmotion.root, xl, yt, w, h, 1817 tmp_win->frame_bw, 1818 moving_icon ? 0 : tmp_win->title_height); 1819 } 1820 1821 } 1822 MovedFromKeyPress = False; 1823 1824 1825 if (!Scr->OpaqueMove && DragWindow == None) 1826 UninstallRootColormap(); 1827 1828 break; 1829 1830 case F_FUNCTION: 1831 { 1832 MenuRoot *mroot; 1833 MenuItem *mitem; 1834 1835 if ((mroot = FindMenuRoot(action)) == NULL) 1836 { 1837 fprintf (stderr, "%s: couldn't find function \"%s\"\n", 1838 ProgramName, action); 1839 return TRUE; 1840 } 1841 1842 if (NeedToDefer(mroot) && DeferExecution(context, func, Scr->SelectCursor)) 1843 return TRUE; 1844 else 1845 { 1846 for (mitem = mroot->first; mitem != NULL; mitem = mitem->next) 1847 { 1848 if (!ExecuteFunction (mitem->func, mitem->action, w, 1849 tmp_win, eventp, context, pulldown)) 1850 break; 1851 } 1852 } 1853 } 1854 break; 1855 1856 case F_DEICONIFY: 1857 case F_ICONIFY: 1858 if (DeferExecution(context, func, Scr->SelectCursor)) 1859 return TRUE; 1860 1861 if (tmp_win->icon) 1862 { 1863 DeIconify(tmp_win); 1864 } 1865 else if (func == F_ICONIFY) 1866 { 1867 Iconify (tmp_win, eventp->xbutton.x_root - 5, 1868 eventp->xbutton.y_root - 5); 1869 } 1870 break; 1871 1872 case F_RAISELOWER: 1873 if (DeferExecution(context, func, Scr->SelectCursor)) 1874 return TRUE; 1875 1876 if (!WindowMoved) { 1877 XWindowChanges xwc; 1878 1879 xwc.stack_mode = Opposite; 1880 if (w != tmp_win->icon_w) 1881 w = tmp_win->frame; 1882 XConfigureWindow (dpy, w, CWStackMode, &xwc); 1883 } 1884 break; 1885 1886 case F_RAISE: 1887 if (DeferExecution(context, func, Scr->SelectCursor)) 1888 return TRUE; 1889 1890 /* check to make sure raise is not from the WindowFunction */ 1891 if (w == tmp_win->icon_w && Context != C_ROOT) 1892 XRaiseWindow(dpy, tmp_win->icon_w); 1893 else 1894 XRaiseWindow(dpy, tmp_win->frame); 1895 1896 break; 1897 1898 case F_LOWER: 1899 if (DeferExecution(context, func, Scr->SelectCursor)) 1900 return TRUE; 1901 1902 if (w == tmp_win->icon_w) 1903 XLowerWindow(dpy, tmp_win->icon_w); 1904 else 1905 XLowerWindow(dpy, tmp_win->frame); 1906 1907 break; 1908 1909 case F_FOCUS: 1910 if (DeferExecution(context, func, Scr->SelectCursor)) 1911 return TRUE; 1912 1913 if (tmp_win->icon == FALSE) 1914 { 1915 if (!Scr->FocusRoot && Scr->Focus == tmp_win) 1916 { 1917 FocusOnRoot(); 1918 } 1919 else 1920 { 1921 if (Scr->Focus != NULL) { 1922 SetBorder (Scr->Focus, False); 1923 if (Scr->Focus->hilite_w) 1924 XUnmapWindow (dpy, Scr->Focus->hilite_w); 1925 } 1926 1927 InstallWindowColormaps (0, tmp_win); 1928 if (tmp_win->hilite_w) XMapWindow (dpy, tmp_win->hilite_w); 1929 SetBorder (tmp_win, True); 1930 if (!tmp_win->wmhints || tmp_win->wmhints->input) 1931 SetFocus (tmp_win, eventp->xbutton.time); 1932 Scr->FocusRoot = FALSE; 1933 Scr->Focus = tmp_win; 1934 } 1935 } 1936 break; 1937 1938 case F_DESTROY: 1939 if (DeferExecution(context, func, Scr->DestroyCursor)) 1940 return TRUE; 1941 1942 if (tmp_win->iconmgr) 1943 Bell(XkbBI_MinorError,0,tmp_win->w); 1944 else 1945 XKillClient(dpy, tmp_win->w); 1946 break; 1947 1948 case F_DELETE: 1949 if (DeferExecution(context, func, Scr->DestroyCursor)) 1950 return TRUE; 1951 1952 if (tmp_win->iconmgr) /* don't send ourself a message */ 1953 HideIconManager (); 1954 else if (tmp_win->protocols & DoesWmDeleteWindow) 1955 SendDeleteWindowMessage (tmp_win, LastTimestamp()); 1956 else 1957 Bell(XkbBI_MinorError,0,tmp_win->w); 1958 break; 1959 1960 case F_SAVEYOURSELF: 1961 if (DeferExecution (context, func, Scr->SelectCursor)) 1962 return TRUE; 1963 1964 if (tmp_win->protocols & DoesWmSaveYourself) 1965 SendSaveYourselfMessage (tmp_win, LastTimestamp()); 1966 else 1967 Bell(XkbBI_MinorError,0,tmp_win->w); 1968 break; 1969 1970 case F_CIRCLEUP: 1971 XCirculateSubwindowsUp(dpy, Scr->Root); 1972 break; 1973 1974 case F_CIRCLEDOWN: 1975 XCirculateSubwindowsDown(dpy, Scr->Root); 1976 break; 1977 1978 case F_EXEC: 1979 PopDownMenu(); 1980 if (!Scr->NoGrabServer) { 1981 XUngrabServer (dpy); 1982 XSync (dpy, 0); 1983 } 1984 Execute(action); 1985 break; 1986 1987 case F_UNFOCUS: 1988 FocusOnRoot(); 1989 break; 1990 1991 case F_CUT: 1992 strcpy(tmp, action); 1993 strcat(tmp, "\n"); 1994 XStoreBytes(dpy, tmp, strlen(tmp)); 1995 break; 1996 1997 case F_CUTFILE: 1998 ptr = XFetchBytes(dpy, &count); 1999 if (ptr) { 2000 if (sscanf (ptr, "%s", tmp) == 1) { 2001 XFree (ptr); 2002 ptr = ExpandFilename(tmp); 2003 if (ptr) { 2004 fd = open (ptr, O_RDONLY); 2005 if (fd >= 0) { 2006 count = read (fd, buff, MAX_FILE_SIZE - 1); 2007 if (count > 0) XStoreBytes (dpy, buff, count); 2008 close(fd); 2009 } else { 2010 fprintf (stderr, 2011 "%s: unable to open cut file \"%s\"\n", 2012 ProgramName, tmp); 2013 } 2014 if (ptr != tmp) free (ptr); 2015 } 2016 } else { 2017 XFree(ptr); 2018 } 2019 } else { 2020 fprintf(stderr, "%s: cut buffer is empty\n", ProgramName); 2021 } 2022 break; 2023 2024 case F_WARPTOSCREEN: 2025 { 2026 if (strcmp (action, WARPSCREEN_NEXT) == 0) { 2027 WarpToScreen (Scr->screen + 1, 1); 2028 } else if (strcmp (action, WARPSCREEN_PREV) == 0) { 2029 WarpToScreen (Scr->screen - 1, -1); 2030 } else if (strcmp (action, WARPSCREEN_BACK) == 0) { 2031 WarpToScreen (PreviousScreen, 0); 2032 } else { 2033 WarpToScreen (atoi (action), 0); 2034 } 2035 } 2036 break; 2037 2038 case F_COLORMAP: 2039 { 2040 if (strcmp (action, COLORMAP_NEXT) == 0) { 2041 BumpWindowColormap (tmp_win, 1); 2042 } else if (strcmp (action, COLORMAP_PREV) == 0) { 2043 BumpWindowColormap (tmp_win, -1); 2044 } else { 2045 BumpWindowColormap (tmp_win, 0); 2046 } 2047 } 2048 break; 2049 2050 case F_WARPPREV: 2051 case F_WARPNEXT: 2052 { 2053 register TwmWindow *t; 2054 static TwmWindow *savedwarp = NULL; 2055 TwmWindow *of, *l, *n; 2056 int c=0; 2057 2058#define wseq(w) (func == F_WARPNEXT ? (w)->next : (w)->prev) 2059#define nwin(w) ((w) && (n=wseq(w)) != NULL && n != &Scr->TwmRoot ? n : l) 2060#define bwin(w) (!(w)||(w)->iconmgr||(w)==of||!(Scr->WarpUnmapped||(w)->mapped)) 2061 2062 of=(Scr->Focus ? Scr->Focus : &Scr->TwmRoot); 2063 2064 for(t=Scr->TwmRoot.next; t; t=t->next) if(!bwin(t)) break; 2065 if(!t) break; /* no windows we can use */ 2066 2067 if(func == F_WARPPREV) for(l=of; l->next; l=l->next) ; 2068 else l = Scr->TwmRoot.next; 2069 2070 for(t=of; bwin(t) && c < 2; t=nwin(t)) if(t == of) c++; 2071 2072 if(bwin(t) || c >= 2) Bell(XkbBI_MinorError,0,None); 2073 else { 2074 if(of && of == savedwarp) { 2075 Iconify(of, 0, 0); 2076 savedwarp = NULL; 2077 } 2078 if(!t->mapped) savedwarp = t; else savedwarp = NULL; 2079 WarpThere(t); 2080 } 2081 break; 2082 } 2083 2084 case F_WARPTO: 2085 { 2086 register TwmWindow *t; 2087 int len; 2088 2089 len = strlen(action); 2090 2091 for (t = Scr->TwmRoot.next; t != NULL; t = t->next) { 2092 if (!strncmp(action, t->name, len)) 2093 if (WarpThere(t)) break; 2094 } 2095 if (!t) { 2096 for (t = Scr->TwmRoot.next; t != NULL; t = t->next) { 2097 if (!strncmp(action, t->class.res_name, len)) 2098 if (WarpThere(t)) break; 2099 } 2100 if (!t) { 2101 for (t = Scr->TwmRoot.next; t != NULL; t = t->next) { 2102 if (!strncmp(action, t->class.res_class, len)) 2103 if (WarpThere(t)) break; 2104 } 2105 } 2106 } 2107 2108 if (!t) 2109 Bell(XkbBI_MinorError,0,None); 2110 } 2111 break; 2112 2113 case F_WARPTOICONMGR: 2114 { 2115 TwmWindow *t; 2116 int len; 2117 Window raisewin = None, iconwin = None; 2118 2119 len = strlen(action); 2120 if (len == 0) { 2121 if (tmp_win && tmp_win->list) { 2122 raisewin = tmp_win->list->iconmgr->twm_win->frame; 2123 iconwin = tmp_win->list->icon; 2124 } else if (Scr->iconmgr.active) { 2125 raisewin = Scr->iconmgr.twm_win->frame; 2126 iconwin = Scr->iconmgr.active->w; 2127 } 2128 } else { 2129 for (t = Scr->TwmRoot.next; t != NULL; t = t->next) { 2130 if (strncmp (action, t->icon_name, len) == 0) { 2131 if (t->list && t->list->iconmgr->twm_win->mapped) { 2132 raisewin = t->list->iconmgr->twm_win->frame; 2133 iconwin = t->list->icon; 2134 break; 2135 } 2136 } 2137 } 2138 } 2139 2140 if (raisewin) { 2141 XRaiseWindow (dpy, raisewin); 2142 XWarpPointer (dpy, None, iconwin, 0,0,0,0, 5, 5); 2143 } else { 2144 Bell(XkbBI_MinorError,0,None); 2145 } 2146 } 2147 break; 2148 2149 case F_WARPRING: 2150 switch (action[0]) { 2151 case 'n': 2152 WarpAlongRing (&eventp->xbutton, True); 2153 break; 2154 case 'p': 2155 WarpAlongRing (&eventp->xbutton, False); 2156 break; 2157 default: 2158 Bell(XkbBI_MinorError,0,None); 2159 break; 2160 } 2161 break; 2162 2163 case F_FILE: 2164 ptr = ExpandFilename(action); 2165 fd = open(ptr, O_RDONLY); 2166 if (fd >= 0) 2167 { 2168 count = read(fd, buff, MAX_FILE_SIZE - 1); 2169 if (count > 0) 2170 XStoreBytes(dpy, buff, count); 2171 2172 close(fd); 2173 } 2174 else 2175 { 2176 fprintf (stderr, "%s: unable to open file \"%s\"\n", 2177 ProgramName, ptr); 2178 } 2179 if (ptr != action) free(ptr); 2180 break; 2181 2182 case F_REFRESH: 2183 { 2184 XSetWindowAttributes attributes; 2185 unsigned long valuemask; 2186 2187 valuemask = (CWBackPixel | CWBackingStore | CWSaveUnder); 2188 attributes.background_pixel = Scr->Black; 2189 attributes.backing_store = NotUseful; 2190 attributes.save_under = False; 2191 w = XCreateWindow (dpy, Scr->Root, 0, 0, 2192 (unsigned int) Scr->MyDisplayWidth, 2193 (unsigned int) Scr->MyDisplayHeight, 2194 (unsigned int) 0, 2195 CopyFromParent, (unsigned int) CopyFromParent, 2196 (Visual *) CopyFromParent, valuemask, 2197 &attributes); 2198 XMapWindow (dpy, w); 2199 XDestroyWindow (dpy, w); 2200 XFlush (dpy); 2201 } 2202 break; 2203 2204 case F_WINREFRESH: 2205 if (DeferExecution(context, func, Scr->SelectCursor)) 2206 return TRUE; 2207 2208 if (context == C_ICON && tmp_win->icon_w) 2209 w = XCreateSimpleWindow(dpy, tmp_win->icon_w, 2210 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black); 2211 else 2212 w = XCreateSimpleWindow(dpy, tmp_win->frame, 2213 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black); 2214 2215 XMapWindow(dpy, w); 2216 XDestroyWindow(dpy, w); 2217 XFlush(dpy); 2218 break; 2219 2220 case F_QUIT: 2221 Done(NULL, NULL); 2222 break; 2223 2224 case F_PRIORITY: 2225 if (HasSync) 2226 { 2227 if (DeferExecution (context, func, Scr->SelectCursor)) 2228 return TRUE; 2229 (void)XSyncSetPriority(dpy, tmp_win->w, atoi(action)); 2230 } 2231 break; 2232 case F_STARTWM: 2233 execlp("/bin/sh", "sh", "-c", action, (void *)NULL); 2234 fprintf (stderr, "%s: unable to start: %s\n", ProgramName, *Argv); 2235 break; 2236 2237 } 2238 2239 if (ButtonPressed == -1) XUngrabPointer(dpy, CurrentTime); 2240 return do_next_action; 2241} 2242 2243 2244 2245/** 2246 * defer the execution of a function to the next button press if the context 2247 * is C_ROOT 2248 * 2249 * \param context the context in which the mouse button was pressed 2250 * \param func the function to defer 2251 * \param cursor cursor the cursor to display while waiting 2252 */ 2253int 2254DeferExecution(int context, int func, Cursor cursor) 2255{ 2256 if (context == C_ROOT) 2257 { 2258 LastCursor = cursor; 2259 XGrabPointer(dpy, Scr->Root, True, 2260 ButtonPressMask | ButtonReleaseMask, 2261 GrabModeAsync, GrabModeAsync, 2262 Scr->Root, cursor, CurrentTime); 2263 2264 RootFunction = func; 2265 2266 return (TRUE); 2267 } 2268 2269 return (FALSE); 2270} 2271 2272 2273 2274/** 2275 *regrab the pointer with the LastCursor; 2276 */ 2277void 2278ReGrab() 2279{ 2280 XGrabPointer(dpy, Scr->Root, True, 2281 ButtonPressMask | ButtonReleaseMask, 2282 GrabModeAsync, GrabModeAsync, 2283 Scr->Root, LastCursor, CurrentTime); 2284} 2285 2286 2287 2288/** 2289 * checks each function in the list to see if it is one that needs 2290 * to be deferred. 2291 * 2292 * \param root the menu root to check 2293 */ 2294Bool 2295NeedToDefer(MenuRoot *root) 2296{ 2297 MenuItem *mitem; 2298 2299 for (mitem = root->first; mitem != NULL; mitem = mitem->next) 2300 { 2301 switch (mitem->func) 2302 { 2303 case F_IDENTIFY: 2304 case F_RESIZE: 2305 case F_MOVE: 2306 case F_FORCEMOVE: 2307 case F_DEICONIFY: 2308 case F_ICONIFY: 2309 case F_RAISELOWER: 2310 case F_RAISE: 2311 case F_LOWER: 2312 case F_FOCUS: 2313 case F_DESTROY: 2314 case F_WINREFRESH: 2315 case F_ZOOM: 2316 case F_FULLZOOM: 2317 case F_HORIZOOM: 2318 case F_RIGHTZOOM: 2319 case F_LEFTZOOM: 2320 case F_TOPZOOM: 2321 case F_BOTTOMZOOM: 2322 case F_AUTORAISE: 2323 return TRUE; 2324 } 2325 } 2326 return FALSE; 2327} 2328 2329 2330 2331#if defined(sun) && defined(SVR4) 2332#include <sys/wait.h> 2333 2334/** 2335 * execute the string by /bin/sh 2336 * \param s the string containing the command 2337 */ 2338static int 2339System (char *s) 2340{ 2341 int pid, status; 2342 if ((pid = fork ()) == 0) { 2343 (void) setpgrp(); 2344 execl ("/bin/sh", "sh", "-c", s, 0); 2345 } else 2346 waitpid (pid, &status, 0); 2347 return status; 2348} 2349#define system(s) System(s) 2350 2351#endif 2352 2353void 2354Execute(char *s) 2355{ 2356 /* FIXME: is all this stuff needed? There could be security problems here. */ 2357 static char buf[256]; 2358 char *ds = DisplayString (dpy); 2359 char *colon, *dot1; 2360 char oldDisplay[256]; 2361 char *doisplay; 2362 int restorevar = 0; 2363 2364 oldDisplay[0] = '\0'; 2365 doisplay=getenv("DISPLAY"); 2366 if (doisplay) 2367 strcpy (oldDisplay, doisplay); 2368 2369 /* 2370 * Build a display string using the current screen number, so that 2371 * X programs which get fired up from a menu come up on the screen 2372 * that they were invoked from, unless specifically overridden on 2373 * their command line. 2374 */ 2375 colon = strrchr (ds, ':'); 2376 if (colon) { /* if host[:]:dpy */ 2377 strcpy (buf, "DISPLAY="); 2378 strcat (buf, ds); 2379 colon = buf + 8 + (colon - ds); /* use version in buf */ 2380 dot1 = strchr (colon, '.'); /* first period after colon */ 2381 if (!dot1) dot1 = colon + strlen (colon); /* if not there, append */ 2382 (void) sprintf (dot1, ".%d", Scr->screen); 2383 putenv (buf); 2384 restorevar = 1; 2385 } 2386 2387 (void) system (s); 2388 2389 if (restorevar) { /* why bother? */ 2390 (void) snprintf (buf, sizeof(buf), "DISPLAY=%s", oldDisplay); 2391 putenv (buf); 2392 } 2393} 2394 2395 2396 2397/** 2398 * put input focus on the root window. 2399 */ 2400void 2401FocusOnRoot() 2402{ 2403 SetFocus ((TwmWindow *) NULL, LastTimestamp()); 2404 if (Scr->Focus != NULL) 2405 { 2406 SetBorder (Scr->Focus, False); 2407 if (Scr->Focus->hilite_w) XUnmapWindow (dpy, Scr->Focus->hilite_w); 2408 } 2409 InstallWindowColormaps(0, &Scr->TwmRoot); 2410 Scr->Focus = NULL; 2411 Scr->FocusRoot = TRUE; 2412} 2413 2414void 2415DeIconify(TwmWindow *tmp_win) 2416{ 2417 TwmWindow *t; 2418 2419 /* de-iconify the main window */ 2420 if (tmp_win->icon) 2421 { 2422 if (tmp_win->icon_on) 2423 Zoom(tmp_win->icon_w, tmp_win->frame); 2424 else if (tmp_win->group != (Window) 0) 2425 { 2426 for (t = Scr->TwmRoot.next; t != NULL; t = t->next) 2427 { 2428 if (tmp_win->group == t->w && t->icon_on) 2429 { 2430 Zoom(t->icon_w, tmp_win->frame); 2431 break; 2432 } 2433 } 2434 } 2435 } 2436 2437 XMapWindow(dpy, tmp_win->w); 2438 tmp_win->mapped = TRUE; 2439 if (Scr->NoRaiseDeicon) 2440 XMapWindow(dpy, tmp_win->frame); 2441 else 2442 XMapRaised(dpy, tmp_win->frame); 2443 SetMapStateProp(tmp_win, NormalState); 2444 2445 if (tmp_win->icon_w) { 2446 XUnmapWindow(dpy, tmp_win->icon_w); 2447 IconDown (tmp_win); 2448 } 2449 if (tmp_win->list) 2450 XUnmapWindow(dpy, tmp_win->list->icon); 2451 if ((Scr->WarpCursor || 2452 LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->class)) && 2453 tmp_win->icon) 2454 WarpToWindow (tmp_win); 2455 tmp_win->icon = FALSE; 2456 tmp_win->icon_on = FALSE; 2457 2458 2459 /* now de-iconify transients */ 2460 for (t = Scr->TwmRoot.next; t != NULL; t = t->next) 2461 { 2462 if (t->transient && t->transientfor == tmp_win->w) 2463 { 2464 if (t->icon_on) 2465 Zoom(t->icon_w, t->frame); 2466 else 2467 Zoom(tmp_win->icon_w, t->frame); 2468 2469 XMapWindow(dpy, t->w); 2470 t->mapped = TRUE; 2471 if (Scr->NoRaiseDeicon) 2472 XMapWindow(dpy, t->frame); 2473 else 2474 XMapRaised(dpy, t->frame); 2475 SetMapStateProp(t, NormalState); 2476 2477 if (t->icon_w) { 2478 XUnmapWindow(dpy, t->icon_w); 2479 IconDown (t); 2480 } 2481 if (t->list) XUnmapWindow(dpy, t->list->icon); 2482 t->icon = FALSE; 2483 t->icon_on = FALSE; 2484 } 2485 } 2486 2487 XSync (dpy, 0); 2488} 2489 2490 2491 2492void 2493Iconify(TwmWindow *tmp_win, int def_x, int def_y) 2494{ 2495 TwmWindow *t; 2496 int iconify; 2497 XWindowAttributes winattrs; 2498 unsigned long eventMask; 2499 2500 iconify = ((!tmp_win->iconify_by_unmapping) || tmp_win->transient); 2501 if (iconify) 2502 { 2503 if (tmp_win->icon_w == (Window) 0) 2504 CreateIconWindow(tmp_win, def_x, def_y); 2505 else 2506 IconUp(tmp_win); 2507 XMapRaised(dpy, tmp_win->icon_w); 2508 } 2509 if (tmp_win->list) 2510 XMapWindow(dpy, tmp_win->list->icon); 2511 2512 XGetWindowAttributes(dpy, tmp_win->w, &winattrs); 2513 eventMask = winattrs.your_event_mask; 2514 2515 /* iconify transients first */ 2516 for (t = Scr->TwmRoot.next; t != NULL; t = t->next) 2517 { 2518 if (t->transient && t->transientfor == tmp_win->w) 2519 { 2520 if (iconify) 2521 { 2522 if (t->icon_on) 2523 Zoom(t->icon_w, tmp_win->icon_w); 2524 else 2525 Zoom(t->frame, tmp_win->icon_w); 2526 } 2527 2528 /* 2529 * Prevent the receipt of an UnmapNotify, since that would 2530 * cause a transition to the Withdrawn state. 2531 */ 2532 t->mapped = FALSE; 2533 XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask); 2534 XUnmapWindow(dpy, t->w); 2535 XSelectInput(dpy, t->w, eventMask); 2536 XUnmapWindow(dpy, t->frame); 2537 if (t->icon_w) 2538 XUnmapWindow(dpy, t->icon_w); 2539 SetMapStateProp(t, IconicState); 2540 SetBorder (t, False); 2541 if (t == Scr->Focus) 2542 { 2543 SetFocus ((TwmWindow *) NULL, LastTimestamp()); 2544 Scr->Focus = NULL; 2545 Scr->FocusRoot = TRUE; 2546 } 2547 if (t->list) XMapWindow(dpy, t->list->icon); 2548 t->icon = TRUE; 2549 t->icon_on = FALSE; 2550 } 2551 } 2552 2553 if (iconify) 2554 Zoom(tmp_win->frame, tmp_win->icon_w); 2555 2556 /* 2557 * Prevent the receipt of an UnmapNotify, since that would 2558 * cause a transition to the Withdrawn state. 2559 */ 2560 tmp_win->mapped = FALSE; 2561 XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask); 2562 XUnmapWindow(dpy, tmp_win->w); 2563 XSelectInput(dpy, tmp_win->w, eventMask); 2564 XUnmapWindow(dpy, tmp_win->frame); 2565 SetMapStateProp(tmp_win, IconicState); 2566 2567 SetBorder (tmp_win, False); 2568 if (tmp_win == Scr->Focus) 2569 { 2570 SetFocus ((TwmWindow *) NULL, LastTimestamp()); 2571 Scr->Focus = NULL; 2572 Scr->FocusRoot = TRUE; 2573 } 2574 tmp_win->icon = TRUE; 2575 if (iconify) 2576 tmp_win->icon_on = TRUE; 2577 else 2578 tmp_win->icon_on = FALSE; 2579 XSync (dpy, 0); 2580} 2581 2582 2583 2584static void 2585Identify (TwmWindow *t) 2586{ 2587 int i, n, twidth, width, height; 2588 int x, y; 2589 unsigned int wwidth, wheight, bw, depth; 2590 Window junk; 2591 int px, py, dummy; 2592 unsigned udummy; 2593 2594 n = 0; 2595 snprintf(Info[n++], INFO_SIZE, "Twm version: %s", Version); 2596 Info[n++][0] = '\0'; 2597 2598 if (t) { 2599 XGetGeometry (dpy, t->w, &JunkRoot, &JunkX, &JunkY, 2600 &wwidth, &wheight, &bw, &depth); 2601 (void) XTranslateCoordinates (dpy, t->w, Scr->Root, 0, 0, 2602 &x, &y, &junk); 2603 snprintf(Info[n++], INFO_SIZE, 2604 "Name = \"%s\"", t->full_name); 2605 snprintf(Info[n++], INFO_SIZE, 2606 "Class.res_name = \"%s\"", t->class.res_name); 2607 snprintf(Info[n++], INFO_SIZE, 2608 "Class.res_class = \"%s\"", t->class.res_class); 2609 Info[n++][0] = '\0'; 2610 snprintf(Info[n++], INFO_SIZE, 2611 "Geometry/root = %dx%d+%d+%d", wwidth, wheight, x, y); 2612 snprintf(Info[n++], INFO_SIZE, "Border width = %d", bw); 2613 snprintf(Info[n++], INFO_SIZE, "Depth = %d", depth); 2614 if (HasSync) 2615 { 2616 int priority; 2617 (void)XSyncGetPriority(dpy, t->w, &priority); 2618 snprintf(Info[n++], INFO_SIZE, "Priority = %d", priority); 2619 } 2620 } 2621 2622 Info[n++][0] = '\0'; 2623 snprintf(Info[n++], INFO_SIZE, "Click to dismiss...."); 2624 2625 /* figure out the width and height of the info window */ 2626 height = n * (Scr->DefaultFont.height+2); 2627 width = 1; 2628 for (i = 0; i < n; i++) 2629 { 2630 twidth = MyFont_TextWidth(&Scr->DefaultFont, Info[i], 2631 strlen(Info[i])); 2632 if (twidth > width) 2633 width = twidth; 2634 } 2635 if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow); 2636 2637 width += 10; /* some padding */ 2638 if (XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild, &px, &py, 2639 &dummy, &dummy, &udummy)) { 2640 px -= (width / 2); 2641 py -= (height / 3); 2642 if (px + width + BW2 >= Scr->MyDisplayWidth) 2643 px = Scr->MyDisplayWidth - width - BW2; 2644 if (py + height + BW2 >= Scr->MyDisplayHeight) 2645 py = Scr->MyDisplayHeight - height - BW2; 2646 if (px < 0) px = 0; 2647 if (py < 0) py = 0; 2648 } else { 2649 px = py = 0; 2650 } 2651 XMoveResizeWindow(dpy, Scr->InfoWindow, px, py, width, height); 2652 XMapRaised(dpy, Scr->InfoWindow); 2653 InfoLines = n; 2654} 2655 2656 2657void 2658SetMapStateProp(TwmWindow *tmp_win, int state) 2659{ 2660 unsigned long data[2]; /* "suggested" by ICCCM version 1 */ 2661 2662 data[0] = (unsigned long) state; 2663 data[1] = (unsigned long) (tmp_win->iconify_by_unmapping ? None : 2664 tmp_win->icon_w); 2665 2666 XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32, 2667 PropModeReplace, (unsigned char *) data, 2); 2668} 2669 2670 2671 2672Bool 2673GetWMState (Window w, int *statep, Window *iwp) 2674{ 2675 Atom actual_type; 2676 int actual_format; 2677 unsigned long nitems, bytesafter; 2678 unsigned char *prop_return = NULL; 2679 Bool retval = False; 2680 2681 if (XGetWindowProperty (dpy, w, _XA_WM_STATE, 0L, 2L, False, _XA_WM_STATE, 2682 &actual_type, &actual_format, &nitems, &bytesafter, 2683 &prop_return) != Success || !prop_return) 2684 return False; 2685 2686 if (nitems <= 2) { /* "suggested" by ICCCM version 1 */ 2687 unsigned long *datap = (unsigned long *) prop_return; 2688 *statep = (int) datap[0]; 2689 *iwp = (Window) datap[1]; 2690 retval = True; 2691 } 2692 2693 XFree (prop_return); 2694 return retval; 2695} 2696 2697 2698void 2699WarpToScreen (int n, int inc) 2700{ 2701 Window dumwin; 2702 int x, y, dumint; 2703 unsigned int dummask; 2704 ScreenInfo *newscr = NULL; 2705 2706 while (!newscr) { 2707 /* wrap around */ 2708 if (n < 0) 2709 n = NumScreens - 1; 2710 else if (n >= NumScreens) 2711 n = 0; 2712 2713 newscr = ScreenList[n]; 2714 if (!newscr) { /* make sure screen is managed */ 2715 if (inc) { /* walk around the list */ 2716 n += inc; 2717 continue; 2718 } 2719 fprintf (stderr, "%s: unable to warp to unmanaged screen %d\n", 2720 ProgramName, n); 2721 Bell(XkbBI_MinorError,0,None); 2722 return; 2723 } 2724 } 2725 2726 if (Scr->screen == n) return; /* already on that screen */ 2727 2728 PreviousScreen = Scr->screen; 2729 XQueryPointer (dpy, Scr->Root, &dumwin, &dumwin, &x, &y, 2730 &dumint, &dumint, &dummask); 2731 2732 XWarpPointer (dpy, None, newscr->Root, 0, 0, 0, 0, x, y); 2733 return; 2734} 2735 2736 2737 2738 2739/** 2740 * rotate our internal copy of WM_COLORMAP_WINDOWS 2741 */ 2742void 2743BumpWindowColormap (TwmWindow *tmp, int inc) 2744{ 2745 int i, j, previously_installed; 2746 ColormapWindow **cwins; 2747 2748 if (!tmp) return; 2749 2750 if (inc && tmp->cmaps.number_cwins > 0) { 2751 cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)* 2752 tmp->cmaps.number_cwins); 2753 if (cwins) { 2754 if ((previously_installed = 2755 /* SUPPRESS 560 */(Scr->cmapInfo.cmaps == &tmp->cmaps && 2756 tmp->cmaps.number_cwins))) { 2757 for (i = tmp->cmaps.number_cwins; i-- > 0; ) 2758 tmp->cmaps.cwins[i]->colormap->state = 0; 2759 } 2760 2761 for (i = 0; i < tmp->cmaps.number_cwins; i++) { 2762 j = i - inc; 2763 if (j >= tmp->cmaps.number_cwins) 2764 j -= tmp->cmaps.number_cwins; 2765 else if (j < 0) 2766 j += tmp->cmaps.number_cwins; 2767 cwins[j] = tmp->cmaps.cwins[i]; 2768 } 2769 2770 free((char *) tmp->cmaps.cwins); 2771 2772 tmp->cmaps.cwins = cwins; 2773 2774 if (tmp->cmaps.number_cwins > 1) 2775 bzero (tmp->cmaps.scoreboard, 2776 ColormapsScoreboardLength(&tmp->cmaps)); 2777 2778 if (previously_installed) 2779 InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL); 2780 } 2781 } else 2782 FetchWmColormapWindows (tmp); 2783} 2784 2785 2786void 2787HideIconManager () 2788{ 2789 SetMapStateProp (Scr->iconmgr.twm_win, WithdrawnState); 2790 XUnmapWindow(dpy, Scr->iconmgr.twm_win->frame); 2791 if (Scr->iconmgr.twm_win->icon_w) 2792 XUnmapWindow (dpy, Scr->iconmgr.twm_win->icon_w); 2793 Scr->iconmgr.twm_win->mapped = FALSE; 2794 Scr->iconmgr.twm_win->icon = TRUE; 2795} 2796 2797 2798 2799void 2800SetBorder (TwmWindow *tmp, Bool onoroff) 2801{ 2802 if (tmp->highlight) { 2803 if (onoroff) { 2804 XSetWindowBorder (dpy, tmp->frame, tmp->border); 2805 if (tmp->title_w) 2806 XSetWindowBorder (dpy, tmp->title_w, tmp->border); 2807 } else { 2808 XSetWindowBorderPixmap (dpy, tmp->frame, tmp->gray); 2809 if (tmp->title_w) 2810 XSetWindowBorderPixmap (dpy, tmp->title_w, tmp->gray); 2811 } 2812 } 2813} 2814 2815 2816void 2817DestroyMenu (MenuRoot *menu) 2818{ 2819 MenuItem *item; 2820 2821 if (menu->w) { 2822 XDeleteContext (dpy, menu->w, MenuContext); 2823 XDeleteContext (dpy, menu->w, ScreenContext); 2824 if (Scr->Shadow) XDestroyWindow (dpy, menu->shadow); 2825 XDestroyWindow(dpy, menu->w); 2826 } 2827 2828 for (item = menu->first; item; ) { 2829 MenuItem *tmp = item; 2830 item = item->next; 2831 free ((char *) tmp); 2832 } 2833} 2834 2835 2836 2837/* 2838 * warping routines 2839 */ 2840 2841void 2842WarpAlongRing (XButtonEvent *ev, Bool forward) 2843{ 2844 TwmWindow *r, *head; 2845 2846 if (Scr->RingLeader) 2847 head = Scr->RingLeader; 2848 else if (!(head = Scr->Ring)) 2849 return; 2850 2851 if (forward) { 2852 for (r = head->ring.next; r != head; r = r->ring.next) { 2853 if (!r || r->mapped) break; 2854 } 2855 } else { 2856 for (r = head->ring.prev; r != head; r = r->ring.prev) { 2857 if (!r || r->mapped) break; 2858 } 2859 } 2860 2861 if (r && r != head) { 2862 TwmWindow *p = Scr->RingLeader, *t; 2863 XPointer context_data; 2864 2865 Scr->RingLeader = r; 2866 WarpToWindow (r); 2867 2868 if (XFindContext (dpy, ev->window, TwmContext, &context_data) == 0) 2869 t = (TwmWindow *) context_data; 2870 else 2871 t = NULL; 2872 2873 if (p && p->mapped && p == t) { 2874 p->ring.cursor_valid = True; 2875 p->ring.curs_x = ev->x_root - t->frame_x; 2876 p->ring.curs_y = ev->y_root - t->frame_y; 2877 if (p->ring.curs_x < -p->frame_bw || 2878 p->ring.curs_x >= p->frame_width + p->frame_bw || 2879 p->ring.curs_y < -p->frame_bw || 2880 p->ring.curs_y >= p->frame_height + p->frame_bw) { 2881 /* somehow out of window */ 2882 p->ring.curs_x = p->frame_width / 2; 2883 p->ring.curs_y = p->frame_height / 2; 2884 } 2885 } 2886 } 2887} 2888 2889 2890 2891void 2892WarpToWindow (TwmWindow *t) 2893{ 2894 int x, y; 2895 2896 if (t->auto_raise || !Scr->NoRaiseWarp) AutoRaiseWindow (t); 2897 if (t->ring.cursor_valid) { 2898 x = t->ring.curs_x; 2899 y = t->ring.curs_y; 2900 } else { 2901 x = t->frame_width / 2; 2902 y = t->frame_height / 2; 2903 } 2904 XWarpPointer (dpy, None, t->frame, 0, 0, 0, 0, x, y); 2905} 2906 2907 2908 2909 2910/* 2911 * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all 2912 * client messages will have the following form: 2913 * 2914 * event type ClientMessage 2915 * message type _XA_WM_PROTOCOLS 2916 * window tmp->w 2917 * format 32 2918 * data[0] message atom 2919 * data[1] time stamp 2920 */ 2921static void 2922send_clientmessage (Window w, Atom a, Time timestamp) 2923{ 2924 XClientMessageEvent ev; 2925 2926 ev.type = ClientMessage; 2927 ev.window = w; 2928 ev.message_type = _XA_WM_PROTOCOLS; 2929 ev.format = 32; 2930 ev.data.l[0] = a; 2931 ev.data.l[1] = timestamp; 2932 XSendEvent (dpy, w, False, 0L, (XEvent *) &ev); 2933} 2934 2935void 2936SendDeleteWindowMessage (TwmWindow *tmp, Time timestamp) 2937{ 2938 send_clientmessage (tmp->w, _XA_WM_DELETE_WINDOW, timestamp); 2939} 2940 2941void 2942SendSaveYourselfMessage (TwmWindow *tmp, Time timestamp) 2943{ 2944 send_clientmessage (tmp->w, _XA_WM_SAVE_YOURSELF, timestamp); 2945} 2946 2947void 2948SendTakeFocusMessage (TwmWindow *tmp, Time timestamp) 2949{ 2950 send_clientmessage (tmp->w, _XA_WM_TAKE_FOCUS, timestamp); 2951} 2952