menus.c revision 645f5050
1/*****************************************************************************/ 2/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/ 3/** Salt Lake City, Utah **/ 4/** Portions Copyright 1989 by the Massachusetts Institute of Technology **/ 5/** Cambridge, Massachusetts **/ 6/** **/ 7/** All Rights Reserved **/ 8/** **/ 9/** Permission to use, copy, modify, and distribute this software and **/ 10/** its documentation for any purpose and without fee is hereby **/ 11/** granted, provided that the above copyright notice appear in all **/ 12/** copies and that both that copyright notice and this permis- **/ 13/** sion notice appear in supporting documentation, and that the **/ 14/** names of Evans & Sutherland and M.I.T. not be used in advertising **/ 15/** in publicity pertaining to distribution of the software without **/ 16/** specific, written prior permission. **/ 17/** **/ 18/** EVANS & SUTHERLAND AND M.I.T. DISCLAIM ALL WARRANTIES WITH REGARD **/ 19/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/ 20/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND OR **/ 21/** M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/ 22/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/ 23/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/ 24/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/ 25/** OR PERFORMANCE OF THIS SOFTWARE. **/ 26/*****************************************************************************/ 27/* 28 * [ ctwm ] 29 * 30 * Copyright 1992 Claude Lecommandeur. 31 * 32 * Permission to use, copy, modify and distribute this software [ctwm] and 33 * its documentation for any purpose is hereby granted without fee, provided 34 * that the above copyright notice appear in all copies and that both that 35 * copyright notice and this permission notice appear in supporting documen- 36 * tation, and that the name of Claude Lecommandeur not be used in adverti- 37 * sing or publicity pertaining to distribution of the software without 38 * specific, written prior permission. Claude Lecommandeur make no represen- 39 * tations about the suitability of this software for any purpose. It is 40 * provided "as is" without express or implied warranty. 41 * 42 * Claude Lecommandeur DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 43 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO 44 * EVENT SHALL Claude Lecommandeur BE LIABLE FOR ANY SPECIAL, INDIRECT OR 45 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF 46 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR 47 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 48 * PERFORMANCE OF THIS SOFTWARE. 49 * 50 * Author: Claude Lecommandeur [ lecom@sic.epfl.ch ][ April 1992 ] 51 */ 52 53 54/*********************************************************************** 55 * 56 * $XConsortium: menus.c,v 1.186 91/07/17 13:58:00 dave Exp $ 57 * 58 * twm menu code 59 * 60 * 17-Nov-87 Thomas E. LaStrange File created 61 * 62 * Do the necessary modification to be integrated in ctwm. 63 * Can no longer be used for the standard twm. 64 * 65 * 22-April-92 Claude Lecommandeur. 66 * 67 * 68 ***********************************************************************/ 69 70#if defined(USE_SIGNALS) && defined(__sgi) 71# define _BSD_SIGNALS 72#endif 73 74#include <stdio.h> 75#include <signal.h> 76 77#ifdef VMS 78#include <stdlib.h> 79#include <string.h> 80#include <unixio.h> 81#include <file.h> 82#include <decw$include/Xos.h> 83#include <decw$include/Xatom.h> 84#else 85#include <X11/Xos.h> 86#include <X11/Xatom.h> 87#endif 88#include "twm.h" 89#include "ctwm.h" 90#include "gc.h" 91#include "menus.h" 92#include "resize.h" 93#include "events.h" 94#include "list.h" 95#include "util.h" 96#include "parse.h" 97#include "screen.h" 98#include "icons.h" 99#include "add_window.h" 100#include "windowbox.h" 101#include "workmgr.h" 102#include "cursor.h" 103#include "gnomewindefs.h" 104#ifdef SOUNDS 105# include "sound.h" 106#endif 107#ifdef VMS 108# include <X11Xmu/CharSet.h> 109# include <decw$bitmaps/menu12.xbm> 110# include <X11SM/SMlib.h> 111# include "vms_cmd_services.h" 112# include <lib$routines.h> 113#else 114# include <X11/Xmu/CharSet.h> 115# include <X11/SM/SMlib.h> 116#endif 117#include "version.h" 118 119#if defined(MACH) || defined(__MACH__) || defined(sony_news) || defined(NeXT) 120#define lrand48 random 121#endif 122#if defined(VMS) || defined(__DARWIN__) 123#define lrand48 rand 124#endif 125 126#ifndef VMS 127#define MAX(x,y) ((x)>(y)?(x):(y)) 128#define MIN(x,y) ((x)<(y)?(x):(y)) 129#endif 130#define ABS(x) ((x)<0?-(x):(x)) 131 132int RootFunction = 0; 133MenuRoot *ActiveMenu = NULL; /* the active menu */ 134MenuItem *ActiveItem = NULL; /* the active menu item */ 135int MoveFunction; /* either F_MOVE or F_FORCEMOVE */ 136int WindowMoved = FALSE; 137int menuFromFrameOrWindowOrTitlebar = FALSE; 138char *CurrentSelectedWorkspace; 139int AlternateKeymap; 140Bool AlternateContext; 141 142extern char *captivename; 143 144int ConstMove = FALSE; /* constrained move variables */ 145int ConstMoveDir; 146int ConstMoveX; 147int ConstMoveY; 148int ConstMoveXL; 149int ConstMoveXR; 150int ConstMoveYT; 151int ConstMoveYB; 152 153/* Globals used to keep track of whether the mouse has moved during 154 a resize function. */ 155int ResizeOrigX; 156int ResizeOrigY; 157 158int MenuDepth = 0; /* number of menus up */ 159static struct { 160 int x; 161 int y; 162} MenuOrigins[MAXMENUDEPTH]; 163static Cursor LastCursor; 164static Bool addingdefaults = False; 165 166void jump (TwmWindow *tmp_win, int direction, char *action); 167void waitamoment (float timeout); 168 169extern char *Action; 170extern int Context; 171extern TwmWindow *ButtonWindow, *Tmp_win; 172extern XEvent ButtonEvent; 173extern char *InitFile; 174extern int ConstrainedMoveTime; 175static void Identify (TwmWindow *t); 176 177#define SHADOWWIDTH 5 /* in pixels */ 178 179#ifdef GNOME 180 extern Atom _XA_WIN_STATE; 181#endif /* GNOME */ 182 183 184 185/*********************************************************************** 186 * 187 * Procedure: 188 * InitMenus - initialize menu roots 189 * 190 *********************************************************************** 191 */ 192 193void InitMenus(void) 194{ 195 Scr->DefaultFunction.func = 0; 196 Scr->WindowFunction.func = 0; 197 Scr->ChangeWorkspaceFunction.func = 0; 198 Scr->DeIconifyFunction.func = 0; 199 Scr->IconifyFunction.func = 0; 200 201 Scr->FuncKeyRoot.next = NULL; 202 Scr->FuncButtonRoot.next = NULL; 203} 204 205 206 207/*********************************************************************** 208 * 209 * Procedure: 210 * AddFuncKey - add a function key to the list 211 * 212 * Inputs: 213 * name - the name of the key 214 * cont - the context to look for the key press in 215 * mods - modifier keys that need to be pressed 216 * func - the function to perform 217 * win_name- the window name (if any) 218 * action - the action string associated with the function (if any) 219 * 220 *********************************************************************** 221 */ 222 223Bool AddFuncKey (char *name, int cont, int mods, int func, 224 MenuRoot *menu, char *win_name, char *action) 225{ 226 FuncKey *tmp; 227 KeySym keysym; 228 KeyCode keycode; 229 230 /* 231 * Don't let a 0 keycode go through, since that means AnyKey to the 232 * XGrabKey call in GrabKeys(). 233 */ 234 if ((keysym = XStringToKeysym(name)) == NoSymbol || 235 (keycode = XKeysymToKeycode(dpy, keysym)) == 0) 236 { 237 return False; 238 } 239 240 /* see if there already is a key defined for this context */ 241 for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) 242 { 243 if (tmp->keysym == keysym && 244 tmp->cont == cont && 245 tmp->mods == mods) 246 break; 247 } 248 if (tmp && addingdefaults) return (True); 249 250 if (tmp == NULL) 251 { 252 tmp = (FuncKey *) malloc(sizeof(FuncKey)); 253 tmp->next = Scr->FuncKeyRoot.next; 254 Scr->FuncKeyRoot.next = tmp; 255 } 256 257 tmp->name = name; 258 tmp->keysym = keysym; 259 tmp->keycode = keycode; 260 tmp->cont = cont; 261 tmp->mods = mods; 262 tmp->func = func; 263 tmp->menu = menu; 264 tmp->win_name = win_name; 265 tmp->action = action; 266 267 return True; 268} 269 270/*********************************************************************** 271 * 272 * Procedure: 273 * AddFuncButton - add a function button to the list 274 * 275 * Inputs: 276 * num - the num of the button 277 * cont - the context to look for the key press in 278 * mods - modifier keys that need to be pressed 279 * func - the function to perform 280 * menu - the menu (if any) 281 * item - the menu item (if any) 282 * 283 *********************************************************************** 284 */ 285 286Bool AddFuncButton (int num, int cont, int mods, int func, 287 MenuRoot *menu, MenuItem *item) 288{ 289 FuncButton *tmp; 290 291 /* see if there already is a key defined for this context */ 292 for (tmp = Scr->FuncButtonRoot.next; tmp != NULL; tmp = tmp->next) { 293 if ((tmp->num == num) && (tmp->cont == cont) && (tmp->mods == mods)) 294 break; 295 } 296 if (tmp && addingdefaults) return (True); 297 298 if (tmp == NULL) { 299 tmp = (FuncButton*) malloc (sizeof (FuncButton)); 300 tmp->next = Scr->FuncButtonRoot.next; 301 Scr->FuncButtonRoot.next = tmp; 302 } 303 304 tmp->num = num; 305 tmp->cont = cont; 306 tmp->mods = mods; 307 tmp->func = func; 308 tmp->menu = menu; 309 tmp->item = item; 310 311 return True; 312} 313 314 315 316static TitleButton *cur_tb = NULL; 317 318void ModifyCurrentTB(int button, int mods, int func, char *action, 319 MenuRoot *menuroot) 320{ 321 TitleButtonFunc *tbf; 322 323 if (!cur_tb) { 324 fprintf (stderr, "%s: can't find titlebutton\n", ProgramName); 325 return; 326 } 327 for (tbf = cur_tb->funs; tbf; tbf = tbf->next) { 328 if (tbf->num == button && tbf->mods == mods) 329 break; 330 } 331 if (!tbf) { 332 tbf = (TitleButtonFunc *)malloc(sizeof(TitleButtonFunc)); 333 if (!tbf) { 334 fprintf (stderr, "%s: out of memory\n", ProgramName); 335 return; 336 } 337 tbf->next = cur_tb->funs; 338 cur_tb->funs = tbf; 339 } 340 tbf->num = button; 341 tbf->mods = mods; 342 tbf->func = func; 343 tbf->action = action; 344 tbf->menuroot = menuroot; 345} 346 347int CreateTitleButton (char *name, int func, char *action, MenuRoot *menuroot, 348 Bool rightside, Bool append) 349{ 350 int button; 351 cur_tb = (TitleButton *) malloc (sizeof(TitleButton)); 352 353 if (!cur_tb) { 354 fprintf (stderr, 355 "%s: unable to allocate %lu bytes for title button\n", 356 ProgramName, (unsigned long) sizeof(TitleButton)); 357 return 0; 358 } 359 360 cur_tb->next = NULL; 361 cur_tb->name = name; /* note that we are not copying */ 362 cur_tb->image = None; /* WARNING, values not set yet */ 363 cur_tb->width = 0; /* see InitTitlebarButtons */ 364 cur_tb->height = 0; /* ditto */ 365 cur_tb->rightside = rightside; 366 cur_tb->funs = NULL; 367 if (rightside) { 368 Scr->TBInfo.nright++; 369 } else { 370 Scr->TBInfo.nleft++; 371 } 372 373 for(button = 0; button < MAX_BUTTONS; button++){ 374 ModifyCurrentTB(button + 1, 0, func, action, menuroot); 375 } 376 377 /* 378 * Cases for list: 379 * 380 * 1. empty list, prepend left put at head of list 381 * 2. append left, prepend right put in between left and right 382 * 3. append right put at tail of list 383 * 384 * Do not refer to widths and heights yet since buttons not created 385 * (since fonts not loaded and heights not known). 386 */ 387 if ((!Scr->TBInfo.head) || ((!append) && (!rightside))) { /* 1 */ 388 cur_tb->next = Scr->TBInfo.head; 389 Scr->TBInfo.head = cur_tb; 390 } else if (append && rightside) { /* 3 */ 391 register TitleButton *t; 392 for /* SUPPRESS 530 */ 393 (t = Scr->TBInfo.head; t->next; t = t->next); 394 t->next = cur_tb; 395 cur_tb->next = NULL; 396 } else { /* 2 */ 397 register TitleButton *t, *prev = NULL; 398 for (t = Scr->TBInfo.head; t && !t->rightside; t = t->next) { 399 prev = t; 400 } 401 if (prev) { 402 cur_tb->next = prev->next; 403 prev->next = cur_tb; 404 } else { 405 cur_tb->next = Scr->TBInfo.head; 406 Scr->TBInfo.head = cur_tb; 407 } 408 } 409 410 return 1; 411} 412 413 414 415/* 416 * InitTitlebarButtons - Do all the necessary stuff to load in a titlebar 417 * button. If we can't find the button, then put in a question; if we can't 418 * find the question mark, something is wrong and we are probably going to be 419 * in trouble later on. 420 */ 421void InitTitlebarButtons (void) 422{ 423 TitleButton *tb; 424 int h; 425 426 /* 427 * initialize dimensions 428 */ 429 Scr->TBInfo.width = (Scr->TitleHeight - 430 2 * (Scr->FramePadding + Scr->ButtonIndent)); 431 if (Scr->use3Dtitles) 432 Scr->TBInfo.pad = ((Scr->TitlePadding > 1) 433 ? ((Scr->TitlePadding + 1) / 2) : 0); 434 else 435 Scr->TBInfo.pad = ((Scr->TitlePadding > 1) 436 ? ((Scr->TitlePadding + 1) / 2) : 1); 437 h = Scr->TBInfo.width - 2 * Scr->TBInfo.border; 438 439 /* 440 * add in some useful buttons and bindings so that novices can still 441 * use the system. 442 */ 443 if (!Scr->NoDefaults) { 444 /* insert extra buttons */ 445 if (Scr->use3Dtitles) { 446 if (!CreateTitleButton (TBPM_3DDOT, F_ICONIFY, "", (MenuRoot *) NULL, 447 False, False)) { 448 fprintf (stderr, "%s: unable to add iconify button\n", ProgramName); 449 } 450 if (!CreateTitleButton (TBPM_3DRESIZE, F_RESIZE, "", (MenuRoot *) NULL, 451 True, True)) { 452 fprintf (stderr, "%s: unable to add resize button\n", ProgramName); 453 } 454 } 455 else { 456 if (!CreateTitleButton (TBPM_ICONIFY, F_ICONIFY, "", (MenuRoot *) NULL, 457 False, False)) { 458 fprintf (stderr, "%s: unable to add iconify button\n", ProgramName); 459 } 460 if (!CreateTitleButton (TBPM_RESIZE, F_RESIZE, "", (MenuRoot *) NULL, 461 True, True)) { 462 fprintf (stderr, "%s: unable to add resize button\n", ProgramName); 463 } 464 } 465 addingdefaults = True; 466 AddDefaultBindings (); 467 addingdefaults = False; 468 } 469 ComputeCommonTitleOffsets (); 470 471 /* 472 * load in images and do appropriate centering 473 */ 474 475 for (tb = Scr->TBInfo.head; tb; tb = tb->next) { 476 tb->image = GetImage (tb->name, Scr->TitleC); 477 if (!tb->image) { 478 tb->image = GetImage (TBPM_QUESTION, Scr->TitleC); 479 if (!tb->image) { /* cannot happen (see util.c) */ 480 fprintf (stderr, "%s: unable to add titlebar button \"%s\"\n", 481 ProgramName, tb->name); 482 } 483 } 484 tb->width = tb->image->width; 485 tb->height = tb->image->height; 486 tb->dstx = (h - tb->width + 1) / 2; 487 if (tb->dstx < 0) { /* clip to minimize copying */ 488 tb->srcx = -(tb->dstx); 489 tb->width = h; 490 tb->dstx = 0; 491 } else { 492 tb->srcx = 0; 493 } 494 tb->dsty = (h - tb->height + 1) / 2; 495 if (tb->dsty < 0) { 496 tb->srcy = -(tb->dsty); 497 tb->height = h; 498 tb->dsty = 0; 499 } else { 500 tb->srcy = 0; 501 } 502 } 503} 504 505 506void PaintEntry(MenuRoot *mr, MenuItem *mi, int exposure) 507{ 508 if (Scr->use3Dmenus) 509 Paint3DEntry (mr, mi, exposure); 510 else 511 PaintNormalEntry (mr, mi, exposure); 512 if (mi->state) mr->lastactive = mi; 513} 514 515void Paint3DEntry(MenuRoot *mr, MenuItem *mi, int exposure) 516{ 517 int y_offset; 518 int text_y; 519 GC gc; 520 521 y_offset = mi->item_num * Scr->EntryHeight + Scr->MenuShadowDepth; 522 text_y = y_offset + Scr->MenuFont.y + 2; 523 524 if (mi->func != F_TITLE) { 525 int x, y; 526 527 gc = Scr->NormalGC; 528 if (mi->state) { 529 Draw3DBorder (mr->w, Scr->MenuShadowDepth, y_offset, 530 mr->width - 2 * Scr->MenuShadowDepth, Scr->EntryHeight, 1, 531 mi->highlight, off, True, False); 532 FB(mi->highlight.fore, mi->highlight.back); 533 XmbDrawImageString(dpy, mr->w, Scr->MenuFont.font_set, gc, 534 mi->x + Scr->MenuShadowDepth, text_y, mi->item, mi->strlen); 535 } 536 else { 537 if (mi->user_colors || !exposure) { 538 XSetForeground (dpy, gc, mi->normal.back); 539 XFillRectangle (dpy, mr->w, gc, 540 Scr->MenuShadowDepth, y_offset, 541 mr->width - 2 * Scr->MenuShadowDepth, Scr->EntryHeight); 542 FB (mi->normal.fore, mi->normal.back); 543 } 544 else { 545 gc = Scr->MenuGC; 546 } 547 XmbDrawImageString (dpy, mr->w, Scr->MenuFont.font_set, gc, 548 mi->x + Scr->MenuShadowDepth, text_y, 549 mi->item, mi->strlen); 550 if (mi->separated) { 551 FB (Scr->MenuC.shadd, Scr->MenuC.shadc); 552 XDrawLine (dpy, mr->w, Scr->NormalGC, 553 Scr->MenuShadowDepth, 554 y_offset + Scr->EntryHeight - 2, 555 mr->width - Scr->MenuShadowDepth, 556 y_offset + Scr->EntryHeight - 2); 557 FB (Scr->MenuC.shadc, Scr->MenuC.shadd); 558 XDrawLine (dpy, mr->w, Scr->NormalGC, 559 Scr->MenuShadowDepth, 560 y_offset + Scr->EntryHeight - 1, 561 mr->width - Scr->MenuShadowDepth, 562 y_offset + Scr->EntryHeight - 1); 563 } 564 } 565 566 if (mi->func == F_MENU) { 567 /* create the pull right pixmap if needed */ 568 if (Scr->pullPm == None) 569 { 570 Scr->pullPm = Create3DMenuIcon (Scr->MenuFont.height, &Scr->pullW, 571 &Scr->pullH, Scr->MenuC); 572 } 573 x = mr->width - Scr->pullW - Scr->MenuShadowDepth - 2; 574 y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2) + 2; 575 XCopyArea (dpy, Scr->pullPm, mr->w, gc, 0, 0, Scr->pullW, Scr->pullH, x, y); 576 } 577 } 578 else 579 { 580 Draw3DBorder (mr->w, Scr->MenuShadowDepth, y_offset, 581 mr->width - 2 * Scr->MenuShadowDepth, Scr->EntryHeight, 1, 582 mi->normal, off, True, False); 583 FB (mi->normal.fore, mi->normal.back); 584 XmbDrawImageString(dpy, mr->w, Scr->MenuFont.font_set, Scr->NormalGC, 585 mi->x + 2, text_y, mi->item, mi->strlen); 586 } 587} 588 589 590 591void PaintNormalEntry(MenuRoot *mr, MenuItem *mi, int exposure) 592{ 593 int y_offset; 594 int text_y; 595 GC gc; 596 597 y_offset = mi->item_num * Scr->EntryHeight; 598 text_y = y_offset + Scr->MenuFont.y; 599 600 if (mi->func != F_TITLE) 601 { 602 int x, y; 603 604 if (mi->state) 605 { 606 XSetForeground(dpy, Scr->NormalGC, mi->highlight.back); 607 608 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset, 609 mr->width, Scr->EntryHeight); 610 FB(mi->highlight.fore, mi->highlight.back); 611 XmbDrawString(dpy, mr->w, Scr->MenuFont.font_set, Scr->NormalGC, 612 mi->x, text_y, mi->item, mi->strlen); 613 614 gc = Scr->NormalGC; 615 } 616 else 617 { 618 if (mi->user_colors || !exposure) 619 { 620 XSetForeground(dpy, Scr->NormalGC, mi->normal.back); 621 622 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset, 623 mr->width, Scr->EntryHeight); 624 625 FB(mi->normal.fore, mi->normal.back); 626 gc = Scr->NormalGC; 627 } 628 else { 629 gc = Scr->MenuGC; 630 } 631 XmbDrawString(dpy, mr->w, Scr->MenuFont.font_set, gc, mi->x, 632 text_y, mi->item, mi->strlen); 633 if (mi->separated) 634 XDrawLine (dpy, mr->w, gc, 0, y_offset + Scr->EntryHeight - 1, 635 mr->width, y_offset + Scr->EntryHeight - 1); 636 } 637 638 if (mi->func == F_MENU) 639 { 640 /* create the pull right pixmap if needed */ 641 if (Scr->pullPm == None) 642 { 643 Scr->pullPm = CreateMenuIcon (Scr->MenuFont.height, 644 &Scr->pullW, &Scr->pullH); 645 } 646 x = mr->width - Scr->pullW - 5; 647 y = y_offset + ((Scr->MenuFont.height - Scr->pullH) / 2); 648 XCopyPlane(dpy, Scr->pullPm, mr->w, gc, 0, 0, 649 Scr->pullW, Scr->pullH, x, y, 1); 650 } 651 } 652 else 653 { 654 int y; 655 656 XSetForeground(dpy, Scr->NormalGC, mi->normal.back); 657 658 /* fill the rectangle with the title background color */ 659 XFillRectangle(dpy, mr->w, Scr->NormalGC, 0, y_offset, 660 mr->width, Scr->EntryHeight); 661 662 { 663 XSetForeground(dpy, Scr->NormalGC, mi->normal.fore); 664 /* now draw the dividing lines */ 665 if (y_offset) 666 XDrawLine (dpy, mr->w, Scr->NormalGC, 0, y_offset, 667 mr->width, y_offset); 668 y = ((mi->item_num+1) * Scr->EntryHeight)-1; 669 XDrawLine(dpy, mr->w, Scr->NormalGC, 0, y, mr->width, y); 670 } 671 672 FB(mi->normal.fore, mi->normal.back); 673 /* finally render the title */ 674 XmbDrawString(dpy, mr->w, Scr->MenuFont.font_set, Scr->NormalGC, mi->x, 675 text_y, mi->item, mi->strlen); 676 } 677} 678 679void PaintMenu(MenuRoot *mr, XEvent *e) 680{ 681 MenuItem *mi; 682 683 if (Scr->use3Dmenus) { 684 Draw3DBorder (mr->w, 0, 0, mr->width, mr->height, 685 Scr->MenuShadowDepth, Scr->MenuC, off, False, False); 686 } 687 for (mi = mr->first; mi != NULL; mi = mi->next) 688 { 689 int y_offset = mi->item_num * Scr->EntryHeight; 690 691 /* be smart about handling the expose, redraw only the entries 692 * that we need to 693 */ 694 if (e->xexpose.y <= (y_offset + Scr->EntryHeight) && 695 (e->xexpose.y + e->xexpose.height) >= y_offset) 696 { 697 PaintEntry(mr, mi, True); 698 } 699 } 700 XSync(dpy, 0); 701} 702 703 704 705void MakeWorkspacesMenu (void) 706{ 707 static char **actions = NULL; 708 WorkSpace *wlist; 709 char **act; 710 711 if (! Scr->Workspaces) return; 712 AddToMenu (Scr->Workspaces, "TWM Workspaces", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR); 713 if (! actions) { 714 int count = 0; 715 716 for (wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL; wlist = wlist->next) { 717 count++; 718 } 719 count++; 720 actions = (char**) malloc (count * sizeof (char*)); 721 act = actions; 722 for (wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL; wlist = wlist->next) { 723 *act = (char*) malloc (strlen ("WGOTO : ") + strlen (wlist->name) + 1); 724 sprintf (*act, "WGOTO : %s", wlist->name); 725 act++; 726 } 727 *act = NULL; 728 } 729 act = actions; 730 for (wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL; wlist = wlist->next) { 731 AddToMenu (Scr->Workspaces, wlist->name, *act, Scr->Windows, F_MENU, NULL, NULL); 732 act++; 733 } 734 Scr->Workspaces->pinned = False; 735 MakeMenu (Scr->Workspaces); 736} 737 738static Bool fromMenu; 739 740int UpdateMenu(void) 741{ 742 MenuItem *mi; 743 int i, x, y, x_root, y_root, entry; 744 int done; 745 MenuItem *badItem = NULL; 746 747 fromMenu = TRUE; 748 749 while (TRUE) 750 { 751 /* block until there is an event */ 752 if (!menuFromFrameOrWindowOrTitlebar) { 753 XMaskEvent(dpy, 754 ButtonPressMask | ButtonReleaseMask | 755 KeyPressMask | KeyReleaseMask | 756 EnterWindowMask | ExposureMask | 757 VisibilityChangeMask | LeaveWindowMask | 758 ButtonMotionMask, &Event); 759 } 760 if (Event.type == MotionNotify) { 761 /* discard any extra motion events before a release */ 762 while(XCheckMaskEvent(dpy, 763 ButtonMotionMask | ButtonReleaseMask, &Event)) 764 if (Event.type == ButtonRelease) 765 break; 766 } 767 768 if (!DispatchEvent ()) 769 continue; 770 771 if ((! ActiveMenu) || Cancel) { 772 menuFromFrameOrWindowOrTitlebar = FALSE; 773 fromMenu = FALSE; 774 return (0); 775 } 776 777 if (Event.type != MotionNotify) 778 continue; 779 780 done = FALSE; 781 XQueryPointer( dpy, ActiveMenu->w, &JunkRoot, &JunkChild, 782 &x_root, &y_root, &x, &y, &JunkMask); 783 784 /* if we haven't recieved the enter notify yet, wait */ 785 if (ActiveMenu && !ActiveMenu->entered) 786 continue; 787 788 XFindContext(dpy, ActiveMenu->w, ScreenContext, (XPointer *)&Scr); 789 790 if (x < 0 || y < 0 || 791 x >= ActiveMenu->width || y >= ActiveMenu->height) 792 { 793 if (ActiveItem && ActiveItem->func != F_TITLE) 794 { 795 ActiveItem->state = 0; 796 PaintEntry(ActiveMenu, ActiveItem, False); 797 } 798 ActiveItem = NULL; 799 continue; 800 } 801 802 /* look for the entry that the mouse is in */ 803 entry = y / Scr->EntryHeight; 804 for (i = 0, mi = ActiveMenu->first; mi != NULL; i++, mi=mi->next) 805 { 806 if (i == entry) 807 break; 808 } 809 810 /* if there is an active item, we might have to turn it off */ 811 if (ActiveItem) 812 { 813 /* is the active item the one we are on ? */ 814 if (ActiveItem->item_num == entry && ActiveItem->state) 815 done = TRUE; 816 817 /* if we weren't on the active entry, let's turn the old 818 * active one off 819 */ 820 if (!done && ActiveItem->func != F_TITLE) 821 { 822 ActiveItem->state = 0; 823 PaintEntry(ActiveMenu, ActiveItem, False); 824 } 825 } 826 827 /* if we weren't on the active item, change the active item and turn 828 * it on 829 */ 830 if (!done) 831 { 832 ActiveItem = mi; 833 if (ActiveItem && ActiveItem->func != F_TITLE && !ActiveItem->state) 834 { 835 ActiveItem->state = 1; 836 PaintEntry(ActiveMenu, ActiveItem, False); 837 } 838 } 839 840 /* now check to see if we were over the arrow of a pull right entry */ 841 if (ActiveItem && ActiveItem->func == F_MENU && 842 ((ActiveMenu->width - x) < (ActiveMenu->width / 3))) 843 { 844 MenuRoot *save = ActiveMenu; 845 int savex = MenuOrigins[MenuDepth - 1].x; 846 int savey = MenuOrigins[MenuDepth - 1].y; 847 848 if (MenuDepth < MAXMENUDEPTH) { 849 if (ActiveMenu == Scr->Workspaces) 850 CurrentSelectedWorkspace = ActiveItem->item; 851 PopUpMenu (ActiveItem->sub, 852 (savex + (((2 * ActiveMenu->width) / 3) - 1)), 853 (savey + ActiveItem->item_num * Scr->EntryHeight) 854 /*(savey + ActiveItem->item_num * Scr->EntryHeight + 855 (Scr->EntryHeight >> 1))*/, False); 856 CurrentSelectedWorkspace = NULL; 857 } else if (!badItem) { 858 XBell (dpy, 0); 859 badItem = ActiveItem; 860 } 861 862 /* if the menu did get popped up, unhighlight the active item */ 863 if (save != ActiveMenu && ActiveItem->state) 864 { 865 ActiveItem->state = 0; 866 PaintEntry(save, ActiveItem, False); 867 ActiveItem = NULL; 868 } 869 } 870 if (badItem != ActiveItem) badItem = NULL; 871 XFlush(dpy); 872 } 873} 874 875 876 877/*********************************************************************** 878 * 879 * Procedure: 880 * NewMenuRoot - create a new menu root 881 * 882 * Returned Value: 883 * (MenuRoot *) 884 * 885 * Inputs: 886 * name - the name of the menu root 887 * 888 *********************************************************************** 889 */ 890 891MenuRoot *NewMenuRoot(char *name) 892{ 893 MenuRoot *tmp; 894 895#define UNUSED_PIXEL ((unsigned long) (~0)) /* more than 24 bits */ 896 897 tmp = (MenuRoot *) malloc(sizeof(MenuRoot)); 898 tmp->highlight.fore = UNUSED_PIXEL; 899 tmp->highlight.back = UNUSED_PIXEL; 900 tmp->name = name; 901 tmp->prev = NULL; 902 tmp->first = NULL; 903 tmp->last = NULL; 904 tmp->defaultitem = NULL; 905 tmp->items = 0; 906 tmp->width = 0; 907 tmp->mapped = NEVER_MAPPED; 908 tmp->pull = FALSE; 909 tmp->w = None; 910 tmp->shadow = None; 911 tmp->real_menu = FALSE; 912 913 if (Scr->MenuList == NULL) 914 { 915 Scr->MenuList = tmp; 916 Scr->MenuList->next = NULL; 917 } 918 919 if (Scr->LastMenu == NULL) 920 { 921 Scr->LastMenu = tmp; 922 Scr->LastMenu->next = NULL; 923 } 924 else 925 { 926 Scr->LastMenu->next = tmp; 927 Scr->LastMenu = tmp; 928 Scr->LastMenu->next = NULL; 929 } 930 931 if (strcmp(name, TWM_WINDOWS) == 0) 932 Scr->Windows = tmp; 933 934 if (strcmp(name, TWM_ICONS) == 0) 935 Scr->Icons = tmp; 936 937 if (strcmp(name, TWM_WORKSPACES) == 0) { 938 Scr->Workspaces = tmp; 939 if (!Scr->Windows) NewMenuRoot (TWM_WINDOWS); 940 } 941 if (strcmp(name, TWM_ALLWINDOWS) == 0) 942 Scr->AllWindows = tmp; 943 944 /* Added by dl 2004 */ 945 if (strcmp(name, TWM_ALLICONS) == 0) 946 Scr->AllIcons = tmp; 947 948 /* Added by Dan Lilliehorn (dl@dl.nu) 2000-02-29 */ 949 if (strcmp(name, TWM_KEYS) == 0) 950 Scr->Keys = tmp; 951 952 if (strcmp(name, TWM_VISIBLE) == 0) 953 Scr->Visible = tmp; 954 955 /* End addition */ 956 957 return (tmp); 958} 959 960 961 962/*********************************************************************** 963 * 964 * Procedure: 965 * AddToMenu - add an item to a root menu 966 * 967 * Returned Value: 968 * (MenuItem *) 969 * 970 * Inputs: 971 * menu - pointer to the root menu to add the item 972 * item - the text to appear in the menu 973 * action - the string to possibly execute 974 * sub - the menu root if it is a pull-right entry 975 * func - the numeric function 976 * fore - foreground color string 977 * back - background color string 978 * 979 *********************************************************************** 980 */ 981 982MenuItem *AddToMenu(MenuRoot *menu, char *item, char *action, 983 MenuRoot *sub, int func, char *fore, char *back) 984{ 985 MenuItem *tmp; 986 int width; 987 char *itemname; 988 XRectangle ink_rect; 989 XRectangle logical_rect; 990 991#ifdef DEBUG_MENUS 992 fprintf(stderr, "adding menu item=\"%s\", action=%s, sub=%d, f=%d\n", 993 item, action, sub, func); 994#endif 995 996 tmp = (MenuItem *) malloc(sizeof(MenuItem)); 997 tmp->root = menu; 998 999 if (menu->first == NULL) 1000 { 1001 menu->first = tmp; 1002 tmp->prev = NULL; 1003 } 1004 else 1005 { 1006 menu->last->next = tmp; 1007 tmp->prev = menu->last; 1008 } 1009 menu->last = tmp; 1010 1011 if ((menu == Scr->Workspaces) || 1012 (menu == Scr->Windows) || 1013 (menu == Scr->Icons) || 1014 (menu == Scr->AllWindows) || 1015 1016 /* Added by dl 2004 */ 1017 (menu == Scr->AllIcons) || 1018 1019 /* Added by Dan Lillehorn (dl@dl.nu) 2000-02-29 */ 1020 (menu == Scr->Keys) || 1021 (menu == Scr->Visible)) { 1022 1023 itemname = item; 1024 } else 1025 if (*item == '*') { 1026 itemname = item + 1; 1027 menu->defaultitem = tmp; 1028 } 1029 else { 1030 itemname = item; 1031 } 1032 1033 tmp->item = itemname; 1034 tmp->strlen = strlen(itemname); 1035 tmp->action = action; 1036 tmp->next = NULL; 1037 tmp->sub = NULL; 1038 tmp->state = 0; 1039 tmp->func = func; 1040 tmp->separated = 0; 1041 1042 if (!Scr->HaveFonts) CreateFonts(); 1043 1044 XmbTextExtents(Scr->MenuFont.font_set, 1045 itemname, tmp->strlen, 1046 &ink_rect, &logical_rect); 1047 width = logical_rect.width; 1048 1049 if (width <= 0) 1050 width = 1; 1051 if (width > menu->width) 1052 menu->width = width; 1053 1054 tmp->user_colors = FALSE; 1055 if (Scr->Monochrome == COLOR && fore != NULL) 1056 { 1057 int save; 1058 1059 save = Scr->FirstTime; 1060 Scr->FirstTime = TRUE; 1061 GetColor(COLOR, &tmp->normal.fore, fore); 1062 GetColor(COLOR, &tmp->normal.back, back); 1063 if (Scr->use3Dmenus && !Scr->BeNiceToColormap) GetShadeColors (&tmp->normal); 1064 Scr->FirstTime = save; 1065 tmp->user_colors = TRUE; 1066 } 1067 if (sub != NULL) 1068 { 1069 tmp->sub = sub; 1070 menu->pull = TRUE; 1071 } 1072 tmp->item_num = menu->items++; 1073 1074 return (tmp); 1075} 1076 1077 1078void MakeMenus(void) 1079{ 1080 MenuRoot *mr; 1081 1082 for (mr = Scr->MenuList; mr != NULL; mr = mr->next) 1083 { 1084 if (mr->real_menu == FALSE) 1085 continue; 1086 1087 mr->pinned = False; 1088 MakeMenu(mr); 1089 } 1090} 1091 1092 1093 1094int MakeMenu(MenuRoot *mr) 1095{ 1096 MenuItem *start, *end, *cur, *tmp; 1097 XColor f1, f2, f3; 1098 XColor b1, b2, b3; 1099 XColor save_fore, save_back; 1100 int num, i; 1101 int fred, fgreen, fblue; 1102 int bred, bgreen, bblue; 1103 int width, borderwidth; 1104 unsigned long valuemask; 1105 XSetWindowAttributes attributes; 1106 Colormap cmap = Scr->RootColormaps.cwins[0]->colormap->c; 1107 XRectangle ink_rect; 1108 XRectangle logical_rect; 1109 1110 Scr->EntryHeight = Scr->MenuFont.height + 4; 1111 1112 /* lets first size the window accordingly */ 1113 if (mr->mapped == NEVER_MAPPED) 1114 { 1115 if (mr->pull == TRUE) { 1116 mr->width += 16 + 10; 1117 } 1118 width = mr->width + 10; 1119 for (cur = mr->first; cur != NULL; cur = cur->next) { 1120 if (cur->func != F_TITLE) 1121 cur->x = 5; 1122 else { 1123 XmbTextExtents(Scr->MenuFont.font_set, cur->item, cur->strlen, 1124 &ink_rect, &logical_rect); 1125 cur->x = width - logical_rect.width; 1126 cur->x /= 2; 1127 } 1128 } 1129 mr->height = mr->items * Scr->EntryHeight; 1130 mr->width += 10; 1131 if (Scr->use3Dmenus) { 1132 mr->width += 2 * Scr->MenuShadowDepth; 1133 mr->height += 2 * Scr->MenuShadowDepth; 1134 } 1135 if (Scr->Shadow && ! mr->pinned) 1136 { 1137 /* 1138 * Make sure that you don't draw into the shadow window or else 1139 * the background bits there will get saved 1140 */ 1141 valuemask = (CWBackPixel | CWBorderPixel); 1142 attributes.background_pixel = Scr->MenuShadowColor; 1143 attributes.border_pixel = Scr->MenuShadowColor; 1144 if (Scr->SaveUnder) { 1145 valuemask |= CWSaveUnder; 1146 attributes.save_under = True; 1147 } 1148 mr->shadow = XCreateWindow (dpy, Scr->Root, 0, 0, 1149 (unsigned int) mr->width, 1150 (unsigned int) mr->height, 1151 (unsigned int)0, 1152 CopyFromParent, 1153 (unsigned int) CopyFromParent, 1154 (Visual *) CopyFromParent, 1155 valuemask, &attributes); 1156 } 1157 1158 valuemask = (CWBackPixel | CWBorderPixel | CWEventMask); 1159 attributes.background_pixel = Scr->MenuC.back; 1160 attributes.border_pixel = Scr->MenuC.fore; 1161 if (mr->pinned) { 1162 attributes.event_mask = (ExposureMask | EnterWindowMask 1163 | LeaveWindowMask | ButtonPressMask 1164 | ButtonReleaseMask | PointerMotionMask 1165 | ButtonMotionMask 1166 ); 1167 attributes.cursor = Scr->MenuCursor; 1168 valuemask |= CWCursor; 1169 } 1170 else 1171 attributes.event_mask = (ExposureMask | EnterWindowMask); 1172 1173 if (Scr->SaveUnder && ! mr->pinned) { 1174 valuemask |= CWSaveUnder; 1175 attributes.save_under = True; 1176 } 1177 if (Scr->BackingStore) { 1178 valuemask |= CWBackingStore; 1179 attributes.backing_store = Always; 1180 } 1181 borderwidth = Scr->use3Dmenus ? 0 : 1; 1182 mr->w = XCreateWindow (dpy, Scr->Root, 0, 0, (unsigned int) mr->width, 1183 (unsigned int) mr->height, (unsigned int) borderwidth, 1184 CopyFromParent, (unsigned int) CopyFromParent, 1185 (Visual *) CopyFromParent, 1186 valuemask, &attributes); 1187 1188 1189 XSaveContext(dpy, mr->w, MenuContext, (XPointer)mr); 1190 XSaveContext(dpy, mr->w, ScreenContext, (XPointer)Scr); 1191 1192 mr->mapped = UNMAPPED; 1193 } 1194 1195 if (Scr->use3Dmenus && (Scr->Monochrome == COLOR) && (mr->highlight.back == UNUSED_PIXEL)) { 1196 XColor xcol; 1197 char colname [32]; 1198 short save; 1199 1200 xcol.pixel = Scr->MenuC.back; 1201 XQueryColor (dpy, cmap, &xcol); 1202 sprintf (colname, "#%04x%04x%04x", 1203 5 * ((int)xcol.red / 6), 1204 5 * ((int)xcol.green / 6), 1205 5 * ((int)xcol.blue / 6)); 1206 save = Scr->FirstTime; 1207 Scr->FirstTime = True; 1208 GetColor (Scr->Monochrome, &mr->highlight.back, colname); 1209 Scr->FirstTime = save; 1210 } 1211 1212 if (Scr->use3Dmenus && (Scr->Monochrome == COLOR) && (mr->highlight.fore == UNUSED_PIXEL)) { 1213 XColor xcol; 1214 char colname [32]; 1215 short save; 1216 1217 xcol.pixel = Scr->MenuC.fore; 1218 XQueryColor (dpy, cmap, &xcol); 1219 sprintf (colname, "#%04x%04x%04x", 1220 5 * ((int)xcol.red / 6), 1221 5 * ((int)xcol.green / 6), 1222 5 * ((int)xcol.blue / 6)); 1223 save = Scr->FirstTime; 1224 Scr->FirstTime = True; 1225 GetColor (Scr->Monochrome, &mr->highlight.fore, colname); 1226 Scr->FirstTime = save; 1227 } 1228 if (Scr->use3Dmenus && !Scr->BeNiceToColormap) GetShadeColors (&mr->highlight); 1229 1230 /* get the default colors into the menus */ 1231 for (tmp = mr->first; tmp != NULL; tmp = tmp->next) 1232 { 1233 if (!tmp->user_colors) { 1234 if (tmp->func != F_TITLE) { 1235 tmp->normal.fore = Scr->MenuC.fore; 1236 tmp->normal.back = Scr->MenuC.back; 1237 } else { 1238 tmp->normal.fore = Scr->MenuTitleC.fore; 1239 tmp->normal.back = Scr->MenuTitleC.back; 1240 } 1241 } 1242 1243 if (mr->highlight.fore != UNUSED_PIXEL) 1244 { 1245 tmp->highlight.fore = mr->highlight.fore; 1246 tmp->highlight.back = mr->highlight.back; 1247 } 1248 else 1249 { 1250 tmp->highlight.fore = tmp->normal.back; 1251 tmp->highlight.back = tmp->normal.fore; 1252 } 1253 if (Scr->use3Dmenus && !Scr->BeNiceToColormap) { 1254 if (tmp->func != F_TITLE) 1255 GetShadeColors (&tmp->highlight); 1256 else 1257 GetShadeColors (&tmp->normal); 1258 } 1259 } 1260 mr->pmenu = NULL; 1261 1262 if (Scr->Monochrome == MONOCHROME || !Scr->InterpolateMenuColors) 1263 return 0; 1264 1265 start = mr->first; 1266 while (TRUE) 1267 { 1268 for (; start != NULL; start = start->next) 1269 { 1270 if (start->user_colors) 1271 break; 1272 } 1273 if (start == NULL) 1274 break; 1275 1276 for (end = start->next; end != NULL; end = end->next) 1277 { 1278 if (end->user_colors) 1279 break; 1280 } 1281 if (end == NULL) 1282 break; 1283 1284 /* we have a start and end to interpolate between */ 1285 num = end->item_num - start->item_num; 1286 1287 f1.pixel = start->normal.fore; 1288 XQueryColor(dpy, cmap, &f1); 1289 f2.pixel = end->normal.fore; 1290 XQueryColor(dpy, cmap, &f2); 1291 1292 b1.pixel = start->normal.back; 1293 XQueryColor(dpy, cmap, &b1); 1294 b2.pixel = end->normal.back; 1295 XQueryColor(dpy, cmap, &b2); 1296 1297 fred = ((int)f2.red - (int)f1.red) / num; 1298 fgreen = ((int)f2.green - (int)f1.green) / num; 1299 fblue = ((int)f2.blue - (int)f1.blue) / num; 1300 1301 bred = ((int)b2.red - (int)b1.red) / num; 1302 bgreen = ((int)b2.green - (int)b1.green) / num; 1303 bblue = ((int)b2.blue - (int)b1.blue) / num; 1304 1305 f3 = f1; 1306 f3.flags = DoRed | DoGreen | DoBlue; 1307 1308 b3 = b1; 1309 b3.flags = DoRed | DoGreen | DoBlue; 1310 1311 start->highlight.back = start->normal.fore; 1312 start->highlight.fore = start->normal.back; 1313 num -= 1; 1314 for (i = 0, cur = start->next; i < num; i++, cur = cur->next) 1315 { 1316 f3.red += fred; 1317 f3.green += fgreen; 1318 f3.blue += fblue; 1319 save_fore = f3; 1320 1321 b3.red += bred; 1322 b3.green += bgreen; 1323 b3.blue += bblue; 1324 save_back = b3; 1325 1326 XAllocColor(dpy, cmap, &f3); 1327 XAllocColor(dpy, cmap, &b3); 1328 cur->highlight.back = cur->normal.fore = f3.pixel; 1329 cur->highlight.fore = cur->normal.back = b3.pixel; 1330 cur->user_colors = True; 1331 1332 f3 = save_fore; 1333 b3 = save_back; 1334 } 1335 start = end; 1336 start->highlight.back = start->normal.fore; 1337 start->highlight.fore = start->normal.back; 1338 } 1339 return 1; 1340} 1341 1342 1343 1344/*********************************************************************** 1345 * 1346 * Procedure: 1347 * PopUpMenu - pop up a pull down menu 1348 * 1349 * Inputs: 1350 * menu - the root pointer of the menu to pop up 1351 * x, y - location of upper left of menu 1352 * center - whether or not to center horizontally over position 1353 * 1354 *********************************************************************** 1355 */ 1356 1357Bool PopUpMenu (MenuRoot *menu, int x, int y, Bool center) 1358{ 1359 int WindowNameCount; 1360 TwmWindow **WindowNames; 1361 TwmWindow *tmp_win2,*tmp_win3; 1362 int i; 1363 int xl, yt; 1364 Bool clipped; 1365#ifdef CLAUDE 1366 char tmpname3 [256], tmpname4 [256]; 1367 int hasmoz = 0; 1368#endif 1369 if (!menu) return False; 1370 1371 InstallRootColormap(); 1372 1373 if ((menu == Scr->Windows) || 1374 (menu == Scr->Icons) || 1375 (menu == Scr->AllWindows) || 1376 /* Added by Dan 'dl' Lilliehorn 040607 */ 1377 (menu == Scr->AllIcons) || 1378 /* Added by Dan Lilliehorn (dl@dl.nu) 2000-02-29 */ 1379 (menu == Scr->Visible)) 1380 { 1381 TwmWindow *tmp_win; 1382 WorkSpace *ws; 1383 Boolean all, icons, visible_, allicons; /* visible, allicons: 1384 Added by dl */ 1385 int func; 1386 1387 /* this is the twm windows menu, let's go ahead and build it */ 1388 1389 all = (menu == Scr->AllWindows); 1390 icons = (menu == Scr->Icons); 1391 visible_ = (menu == Scr->Visible); /* Added by dl */ 1392 allicons = (menu == Scr->AllIcons); 1393 DestroyMenu (menu); 1394 1395 menu->first = NULL; 1396 menu->last = NULL; 1397 menu->items = 0; 1398 menu->width = 0; 1399 menu->mapped = NEVER_MAPPED; 1400 menu->highlight.fore = UNUSED_PIXEL; 1401 menu->highlight.back = UNUSED_PIXEL; 1402 if (menu == Scr->Windows) 1403 AddToMenu(menu, "TWM Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR); 1404 else 1405 if (menu == Scr->Icons) 1406 AddToMenu(menu, "TWM Icons", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR); 1407 else 1408 if (menu == Scr->Visible) /* Added by dl 2000 */ 1409 AddToMenu(menu, "TWM Visible", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR); 1410 else 1411 if (menu == Scr->AllIcons) /* Added by dl 2004 */ 1412 AddToMenu(menu, "TWM All Icons", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR); 1413 else 1414 AddToMenu(menu, "TWM All Windows", NULLSTR, NULL, F_TITLE,NULLSTR,NULLSTR); 1415 1416 ws = NULL; 1417 1418 if (! (all || allicons) 1419 && CurrentSelectedWorkspace && Scr->workSpaceManagerActive) { 1420 for (ws = Scr->workSpaceMgr.workSpaceList; ws != NULL; ws = ws->next) { 1421 if (strcmp (ws->name, CurrentSelectedWorkspace) == 0) break; 1422 } 1423 } 1424 if (!Scr->currentvs) return False; 1425 if (!ws) ws = Scr->currentvs->wsw->currentwspc; 1426 1427 for (tmp_win = Scr->FirstWindow, WindowNameCount = 0; 1428 tmp_win != NULL; 1429 tmp_win = tmp_win->next) { 1430 if (tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) continue; 1431 if (Scr->ShortAllWindowsMenus && (tmp_win->wspmgr || tmp_win->iconmgr)) continue; 1432 1433 if (!(all || allicons) && !OCCUPY (tmp_win, ws)) continue; 1434 if (allicons && !tmp_win->isicon) continue; 1435 if (icons && !tmp_win->isicon) continue; 1436 if (visible_ && tmp_win->isicon) continue; /* added by dl */ 1437 WindowNameCount++; 1438 } 1439 WindowNames = (TwmWindow **)malloc(sizeof(TwmWindow *)*WindowNameCount); 1440 WindowNameCount = 0; 1441 for (tmp_win = Scr->FirstWindow; 1442 tmp_win != NULL; 1443 tmp_win = tmp_win->next) 1444 { 1445 if (LookInList (Scr->IconMenuDontShow, tmp_win->full_name, &tmp_win->class)) continue; 1446 1447 if (tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win) continue; 1448 if (Scr->ShortAllWindowsMenus && 1449 tmp_win == Scr->currentvs->wsw->twm_win) continue; 1450 if (Scr->ShortAllWindowsMenus && tmp_win->iconmgr) continue; 1451 1452 if (!(all || allicons)&& ! OCCUPY (tmp_win, ws)) continue; 1453 if (allicons && !tmp_win->isicon) continue; 1454 if (icons && !tmp_win->isicon) continue; 1455 if (visible_ && tmp_win->isicon) continue; /* added by dl */ 1456 tmp_win2 = tmp_win; 1457 1458 for (i = 0; i < WindowNameCount; i++) { 1459 int compresult; 1460 char *tmpname1, *tmpname2; 1461 tmpname1 = tmp_win2->name; 1462 tmpname2 = WindowNames[i]->name; 1463#ifdef CLAUDE 1464 if (strlen (tmpname1) == 1) tmpname1 = " No title"; 1465 if (strlen (tmpname2) == 1) tmpname2 = " No title"; 1466 1467 if (!strncasecmp (tmp_win2->class.res_class, "navigator", 9) || 1468 !strncasecmp (tmp_win2->class.res_class, "mozilla", 7)) { 1469 tmpname3 [0] = ' '; tmpname3 [1] = '\0'; 1470 strcat (tmpname3, tmpname1); 1471 } else { 1472 strcpy (tmpname3, tmpname1); 1473 } 1474 if (!strncasecmp (WindowNames[i]->class.res_class, "navigator", 9) || 1475 !strncasecmp (WindowNames[i]->class.res_class, "mozilla", 7)) { 1476 tmpname4 [0] = ' '; tmpname4 [1] = '\0'; 1477 strcat (tmpname4, tmpname2); 1478 } else { 1479 strcpy (tmpname4, tmpname2); 1480 } 1481 tmpname1 = tmpname3; 1482 tmpname2 = tmpname4; 1483#endif 1484 if (Scr->CaseSensitive) 1485 compresult = strcmp(tmpname1,tmpname2); 1486 else 1487 compresult = XmuCompareISOLatin1(tmpname1,tmpname2); 1488 if (compresult < 0) { 1489 tmp_win3 = tmp_win2; 1490 tmp_win2 = WindowNames[i]; 1491 WindowNames[i] = tmp_win3; 1492 } 1493 } 1494 WindowNames[WindowNameCount] = tmp_win2; 1495 WindowNameCount++; 1496 } 1497 func = (all || allicons || CurrentSelectedWorkspace) ? F_WINWARP : 1498 F_POPUP; 1499 for (i = 0; i < WindowNameCount; i++) 1500 { 1501 char *tmpname; 1502 tmpname = WindowNames[i]->name; 1503#ifdef CLAUDE 1504 if (!strncasecmp (WindowNames[i]->class.res_class, "navigator", 9) || 1505 !strncasecmp (WindowNames[i]->class.res_class, "mozilla", 7) || 1506 !strncasecmp (WindowNames[i]->class.res_class, "netscape", 8) || 1507 !strncasecmp (WindowNames[i]->class.res_class, "konqueror", 9)) { 1508 hasmoz = 1; 1509 } 1510 if (hasmoz && strncasecmp (WindowNames[i]->class.res_class, "navigator", 9) && 1511 strncasecmp (WindowNames[i]->class.res_class, "mozilla", 7) && 1512 strncasecmp (WindowNames[i]->class.res_class, "netscape", 8) && 1513 strncasecmp (WindowNames[i]->class.res_class, "konqueror", 9)) { 1514 menu->last->separated = 1; 1515 hasmoz = 0; 1516 } 1517#endif 1518 AddToMenu(menu, tmpname, (char *)WindowNames[i], 1519 NULL, func,NULL,NULL); 1520 } 1521 free(WindowNames); 1522 1523 menu->pinned = False; 1524 MakeMenu(menu); 1525 } 1526 1527 /* Keys added by dl */ 1528 1529 if (menu == Scr->Keys) { 1530 FuncKey *tmpKey; 1531 char *tmpStr, *tmpStr2; 1532 char modStr[5]; 1533 char *oldact = 0; 1534 int oldmod = 0; 1535 int tmpLen; 1536 1537 DestroyMenu (menu); 1538 1539 menu->first = NULL; 1540 menu->last = NULL; 1541 menu->items = 0; 1542 menu->width = 0; 1543 menu->mapped = NEVER_MAPPED; 1544 menu->highlight.fore = UNUSED_PIXEL; 1545 menu->highlight.back = UNUSED_PIXEL; 1546 1547 AddToMenu(menu, "Twm Keys", NULLSTR, NULL, F_TITLE, NULLSTR, NULLSTR); 1548 1549 for (tmpKey = Scr->FuncKeyRoot.next; tmpKey != NULL; tmpKey = tmpKey->next) { 1550 if (tmpKey->func != F_EXEC) continue; 1551 if ((tmpKey->action == oldact) && (tmpKey->mods == oldmod)) continue; 1552 strcpy (modStr, ""); 1553 switch (tmpKey->mods) { 1554 case 1: strcpy (modStr, "S"); break; 1555 case 4: strcpy (modStr, "C"); break; 1556 case 5: strcpy (modStr, "S + C"); break; 1557 case 8: strcpy (modStr, "M"); break; 1558 case 9: strcpy (modStr, "S + M"); break; 1559 case 12: strcpy (modStr, "C + M"); break; 1560 default: break; 1561 } 1562 tmpLen = (strlen (tmpKey->name) + strlen (modStr) + 5); 1563 tmpStr = malloc (sizeof(char) * tmpLen); 1564 sprintf (tmpStr,"[%s + %s]", tmpKey->name, modStr); 1565 tmpStr2 = malloc (sizeof(char) * (strlen (tmpKey->action) + tmpLen + 2)); 1566 sprintf (tmpStr2, "%s %s", tmpStr, tmpKey->action); 1567 1568 AddToMenu (menu, tmpStr2, tmpKey->action, NULL, tmpKey->func, NULLSTR, NULLSTR); 1569 oldact = tmpKey->action; 1570 oldmod = tmpKey->mods; 1571 } 1572 menu->pinned = False; 1573 MakeMenu(menu); 1574 } 1575 if (menu->w == None || menu->items == 0) return False; 1576 1577 /* Prevent recursively bringing up menus. */ 1578 if ((!menu->pinned) && (menu->mapped == MAPPED)) return False; 1579 1580 /* 1581 * Dynamically set the parent; this allows pull-ups to also be main 1582 * menus, or to be brought up from more than one place. 1583 */ 1584 menu->prev = ActiveMenu; 1585 1586 if (menu->pinned) { 1587 ActiveMenu = menu; 1588 menu->mapped = MAPPED; 1589 menu->entered = TRUE; 1590 MenuOrigins [MenuDepth].x = menu->x; 1591 MenuOrigins [MenuDepth].y = menu->y; 1592 MenuDepth++; 1593 1594 XRaiseWindow (dpy, menu->w); 1595 return (True); 1596 } 1597 1598 XGrabPointer(dpy, Scr->Root, True, 1599 ButtonPressMask | ButtonReleaseMask | PointerMotionMask | 1600 ButtonMotionMask | PointerMotionHintMask, 1601 GrabModeAsync, GrabModeAsync, 1602 Scr->Root, 1603 Scr->MenuCursor, CurrentTime); 1604 1605 XGrabKeyboard (dpy, Scr->Root, True, GrabModeAsync, GrabModeAsync, CurrentTime); 1606 1607 ActiveMenu = menu; 1608 menu->mapped = MAPPED; 1609 menu->entered = FALSE; 1610 1611 if (center) { 1612 x -= (menu->width / 2); 1613 y -= (Scr->EntryHeight / 2); /* sticky menus would be nice here */ 1614 } 1615 1616 /* 1617 * clip to screen 1618 */ 1619 clipped = FALSE; 1620 if (x + menu->width > Scr->rootw) { 1621 x = Scr->rootw - menu->width; 1622 clipped = TRUE; 1623 } 1624 if (x < 0) { 1625 x = 0; 1626 clipped = TRUE; 1627 } 1628 if (y + menu->height > Scr->rooth) { 1629 y = Scr->rooth - menu->height; 1630 clipped = TRUE; 1631 } 1632 if (y < 0) { 1633 y = 0; 1634 clipped = TRUE; 1635 } 1636 MenuOrigins[MenuDepth].x = x; 1637 MenuOrigins[MenuDepth].y = y; 1638 MenuDepth++; 1639 1640 if (Scr->Root != Scr->CaptiveRoot) { 1641 XReparentWindow (dpy, menu->shadow, Scr->Root, x, y); 1642 XReparentWindow (dpy, menu->w, Scr->Root, x, y); 1643 } else 1644 XMoveWindow (dpy, menu->w, x, y); 1645 if (Scr->Shadow) { 1646 XMoveWindow (dpy, menu->shadow, x + SHADOWWIDTH, y + SHADOWWIDTH); 1647 XRaiseWindow (dpy, menu->shadow); 1648 } 1649 XMapRaised(dpy, menu->w); 1650if (!Scr->NoWarpToMenuTitle && clipped && center) { 1651 xl = x + (menu->width / 2); 1652 yt = y + (Scr->EntryHeight / 2); 1653 XWarpPointer (dpy, Scr->Root, Scr->Root, x, y, menu->width, menu->height, xl, yt); 1654 } 1655 if (Scr->Shadow) XMapWindow (dpy, menu->shadow); 1656 XSync(dpy, 0); 1657 return True; 1658} 1659 1660 1661 1662/*********************************************************************** 1663 * 1664 * Procedure: 1665 * PopDownMenu - unhighlight the current menu selection and 1666 * take down the menus 1667 * 1668 *********************************************************************** 1669 */ 1670 1671int PopDownMenu(void) 1672{ 1673 MenuRoot *tmp; 1674 1675 if (ActiveMenu == NULL) 1676 return (1); 1677 1678 if (ActiveItem) 1679 { 1680 ActiveItem->state = 0; 1681 PaintEntry(ActiveMenu, ActiveItem, False); 1682 } 1683 1684 for (tmp = ActiveMenu; tmp != NULL; tmp = tmp->prev) 1685 { 1686 if (! tmp->pinned) HideMenu (tmp); 1687 UninstallRootColormap(); 1688 } 1689 1690 XFlush(dpy); 1691 ActiveMenu = NULL; 1692 ActiveItem = NULL; 1693 MenuDepth = 0; 1694 XUngrabKeyboard (dpy, CurrentTime); 1695 if (Context == C_WINDOW || Context == C_FRAME || Context == C_TITLE || Context == C_ICON) 1696 menuFromFrameOrWindowOrTitlebar = TRUE; 1697 1698 return 1; 1699} 1700 1701 1702 1703Bool HideMenu (MenuRoot *menu) 1704{ 1705 if (!menu) return False; 1706 1707 if (Scr->Shadow) { 1708 XUnmapWindow (dpy, menu->shadow); 1709 } 1710 XUnmapWindow (dpy, menu->w); 1711 menu->mapped = UNMAPPED; 1712 1713 return True; 1714} 1715 1716/*********************************************************************** 1717 * 1718 * Procedure: 1719 * FindMenuRoot - look for a menu root 1720 * 1721 * Returned Value: 1722 * (MenuRoot *) - a pointer to the menu root structure 1723 * 1724 * Inputs: 1725 * name - the name of the menu root 1726 * 1727 *********************************************************************** 1728 */ 1729 1730MenuRoot *FindMenuRoot(char *name) 1731{ 1732 MenuRoot *tmp; 1733 1734 for (tmp = Scr->MenuList; tmp != NULL; tmp = tmp->next) 1735 { 1736 if (strcmp(name, tmp->name) == 0) 1737 return (tmp); 1738 } 1739 return NULL; 1740} 1741 1742 1743 1744static Bool belongs_to_twm_window (register TwmWindow *t, register Window w) 1745{ 1746 if (!t) return False; 1747 1748 if (w == t->frame || w == t->title_w || w == t->hilite_wl || w == t->hilite_wr || 1749 (t->icon && (w == t->icon->w || w == t->icon->bm_w))) return True; 1750 1751 if (t && t->titlebuttons) { 1752 register TBWindow *tbw; 1753 register int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; 1754 for (tbw = t->titlebuttons; nb > 0; tbw++, nb--) { 1755 if (tbw->window == w) return True; 1756 } 1757 } 1758 return False; 1759} 1760 1761 1762 1763 1764/*********************************************************************** 1765 * 1766 * Procedure: 1767 * resizeFromCenter - 1768 * 1769 *********************************************************************** 1770 */ 1771 1772void resizeFromCenter(Window w, TwmWindow *tmp_win) 1773{ 1774 int lastx, lasty, bw2; 1775 int namelen; 1776 XRectangle inc_rect; 1777 XRectangle logical_rect; 1778 1779 namelen = strlen (tmp_win->name); 1780 bw2 = tmp_win->frame_bw * 2; 1781 AddingW = tmp_win->attr.width + bw2 + 2 * tmp_win->frame_bw3D; 1782 AddingH = tmp_win->attr.height + tmp_win->title_height + bw2 + 2 * tmp_win->frame_bw3D; 1783 1784 XmbTextExtents(Scr->SizeFont.font_set, tmp_win->name, namelen, 1785 &inc_rect, &logical_rect); 1786 1787 XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY, 1788 &DragWidth, &DragHeight, 1789 &JunkBW, &JunkDepth); 1790 1791 XWarpPointer(dpy, None, w, 1792 0, 0, 0, 0, DragWidth/2, DragHeight/2); 1793 XQueryPointer (dpy, Scr->Root, &JunkRoot, 1794 &JunkChild, &JunkX, &JunkY, 1795 &AddingX, &AddingY, &JunkMask); 1796 1797 lastx = -10000; 1798 lasty = -10000; 1799 1800 MenuStartResize(tmp_win, origDragX, origDragY, DragWidth, DragHeight); 1801 while (TRUE) 1802 { 1803 XMaskEvent(dpy, 1804 ButtonPressMask | PointerMotionMask | ExposureMask, &Event); 1805 1806 if (Event.type == MotionNotify) { 1807 /* discard any extra motion events before a release */ 1808 while(XCheckMaskEvent(dpy, 1809 ButtonMotionMask | ButtonPressMask, &Event)) 1810 if (Event.type == ButtonPress) 1811 break; 1812 } 1813 1814 if (Event.type == ButtonPress) 1815 { 1816 MenuEndResize(tmp_win); 1817 XMoveResizeWindow(dpy, w, AddingX, AddingY, AddingW, AddingH); 1818 break; 1819 } 1820 1821 if (Event.type != MotionNotify) { 1822 DispatchEvent2 (); 1823 continue; 1824 } 1825 1826 /* 1827 * XXX - if we are going to do a loop, we ought to consider 1828 * using multiple GXxor lines so that we don't need to 1829 * grab the server. 1830 */ 1831 XQueryPointer(dpy, Scr->Root, &JunkRoot, &JunkChild, 1832 &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask); 1833 1834 if (lastx != AddingX || lasty != AddingY) 1835 { 1836 MenuDoResize(AddingX, AddingY, tmp_win); 1837 1838 lastx = AddingX; 1839 lasty = AddingY; 1840 } 1841 1842 } 1843} 1844 1845 1846 1847/*********************************************************************** 1848 * 1849 * Procedure: 1850 * ExecuteFunction - execute a twm root function 1851 * 1852 * Inputs: 1853 * func - the function to execute 1854 * action - the menu action to execute 1855 * w - the window to execute this function on 1856 * tmp_win - the twm window structure 1857 * event - the event that caused the function 1858 * context - the context in which the button was pressed 1859 * pulldown- flag indicating execution from pull down menu 1860 * 1861 * Returns: 1862 * TRUE if should continue with remaining actions else FALSE to abort 1863 * 1864 *********************************************************************** 1865 */ 1866 1867int ExecuteFunction(int func, void *action, Window w, TwmWindow *tmp_win, 1868 XEvent *eventp, int context, int pulldown) 1869{ 1870 static Time last_time = 0; 1871 char tmp[200]; 1872 char *ptr; 1873 char buff[MAX_FILE_SIZE]; 1874 int count, fd; 1875 Window rootw; 1876 int origX, origY; 1877 int do_next_action = TRUE; 1878 int moving_icon = FALSE; 1879 Bool fromtitlebar = False; 1880 Bool from3dborder = False; 1881 TwmWindow *t; 1882 1883 RootFunction = 0; 1884 if (Cancel) 1885 return TRUE; /* XXX should this be FALSE? */ 1886 1887 switch (func) 1888 { 1889 case F_UPICONMGR: 1890 case F_LEFTICONMGR: 1891 case F_RIGHTICONMGR: 1892 case F_DOWNICONMGR: 1893 case F_FORWICONMGR: 1894 case F_BACKICONMGR: 1895 case F_NEXTICONMGR: 1896 case F_PREVICONMGR: 1897 case F_NOP: 1898 case F_TITLE: 1899 case F_DELTASTOP: 1900 case F_RAISELOWER: 1901 case F_WARPTOSCREEN: 1902 case F_WARPTO: 1903 case F_WARPRING: 1904 case F_WARPTOICONMGR: 1905 case F_COLORMAP: 1906 case F_ALTKEYMAP: 1907 case F_ALTCONTEXT: 1908 break; 1909 1910 default: 1911 XGrabPointer(dpy, Scr->Root, True, 1912 ButtonPressMask | ButtonReleaseMask, 1913 GrabModeAsync, GrabModeAsync, 1914 Scr->Root, Scr->WaitCursor, CurrentTime); 1915 break; 1916 } 1917 1918 switch (func) 1919 { 1920#ifdef SOUNDS 1921 case F_TOGGLESOUND: 1922 toggle_sound(); 1923 break; 1924 case F_REREADSOUNDS: 1925 reread_sounds(); 1926 break; 1927#endif 1928 case F_NOP: 1929 case F_TITLE: 1930 break; 1931 1932 case F_DELTASTOP: 1933 if (WindowMoved) do_next_action = FALSE; 1934 break; 1935 1936 case F_RESTART: { 1937 DoRestart(eventp->xbutton.time); 1938 break; 1939 } 1940 case F_UPICONMGR: 1941 case F_DOWNICONMGR: 1942 case F_LEFTICONMGR: 1943 case F_RIGHTICONMGR: 1944 case F_FORWICONMGR: 1945 case F_BACKICONMGR: 1946 MoveIconManager(func); 1947 break; 1948 1949 case F_FORWMAPICONMGR: 1950 case F_BACKMAPICONMGR: 1951 MoveMappedIconManager(func); 1952 break; 1953 1954 case F_NEXTICONMGR: 1955 case F_PREVICONMGR: 1956 JumpIconManager(func); 1957 break; 1958 1959 case F_SHOWLIST: 1960 if (Scr->NoIconManagers) break; 1961 ShowIconManager (); 1962 break; 1963 1964 case F_STARTANIMATION : 1965 StartAnimation (); 1966 break; 1967 1968 case F_STOPANIMATION : 1969 StopAnimation (); 1970 break; 1971 1972 case F_SPEEDUPANIMATION : 1973 ModifyAnimationSpeed (1); 1974 break; 1975 1976 case F_SLOWDOWNANIMATION : 1977 ModifyAnimationSpeed (-1); 1978 break; 1979 1980 case F_HIDELIST: 1981 if (Scr->NoIconManagers) break; 1982 HideIconManager (); 1983 break; 1984 1985 case F_SHOWWORKMGR: 1986 if (! Scr->workSpaceManagerActive) break; 1987 DeIconify (Scr->currentvs->wsw->twm_win); 1988 RaiseWindow(Scr->currentvs->wsw->twm_win); 1989 break; 1990 1991 case F_HIDEWORKMGR: 1992 if (! Scr->workSpaceManagerActive) break; 1993 Iconify (Scr->currentvs->wsw->twm_win, eventp->xbutton.x_root - 5, 1994 eventp->xbutton.y_root - 5); 1995 break; 1996 1997 case F_TOGGLEWORKMGR: 1998 if (! Scr->workSpaceManagerActive) break; 1999 if (Scr->currentvs->wsw->twm_win->mapped) 2000 Iconify (Scr->currentvs->wsw->twm_win, eventp->xbutton.x_root - 5, 2001 eventp->xbutton.y_root - 5); 2002 else { 2003 DeIconify (Scr->currentvs->wsw->twm_win); 2004 RaiseWindow(Scr->currentvs->wsw->twm_win); 2005 } 2006 break; 2007 2008 case F_TOGGLESTATE : 2009 WMapToggleState (Scr->currentvs); 2010 break; 2011 2012 case F_SETBUTTONSTATE : 2013 WMapSetButtonsState (Scr->currentvs); 2014 break; 2015 2016 case F_SETMAPSTATE : 2017 WMapSetMapState (Scr->currentvs); 2018 break; 2019 2020 case F_PIN : 2021 if (! ActiveMenu) break; 2022 if (ActiveMenu->pinned) { 2023 XUnmapWindow (dpy, ActiveMenu->w); 2024 ActiveMenu->mapped = UNMAPPED; 2025 } 2026 else { 2027 XWindowAttributes attr; 2028 MenuRoot *menu; 2029 2030 if (ActiveMenu->pmenu == NULL) { 2031 menu = (MenuRoot*) malloc (sizeof (struct MenuRoot)); 2032 *menu = *ActiveMenu; 2033 menu->pinned = True; 2034 menu->mapped = NEVER_MAPPED; 2035 menu->width -= 10; 2036 if (menu->pull) menu->width -= 16 + 10; 2037 MakeMenu (menu); 2038 ActiveMenu->pmenu = menu; 2039 } 2040 else menu = ActiveMenu->pmenu; 2041 if (menu->mapped == MAPPED) break; 2042 XGetWindowAttributes (dpy, ActiveMenu->w, &attr); 2043 menu->x = attr.x; 2044 menu->y = attr.y; 2045 XMoveWindow (dpy, menu->w, menu->x, menu->y); 2046 XMapRaised (dpy, menu->w); 2047 menu->mapped = MAPPED; 2048 } 2049 PopDownMenu(); 2050 break; 2051 2052 case F_MOVEMENU: 2053 break; 2054 2055 case F_FITTOCONTENT : 2056 if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE; 2057 if (!tmp_win->iswinbox) { 2058 XBell (dpy, 0); 2059 break; 2060 } 2061 fittocontent (tmp_win); 2062 break; 2063 2064 case F_VANISH: 2065 if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE; 2066 2067 WMgrRemoveFromCurrentWorkSpace (Scr->currentvs, tmp_win); 2068 break; 2069 2070 case F_WARPHERE: 2071 WMgrAddToCurrentWorkSpaceAndWarp (Scr->currentvs, action); 2072 break; 2073 2074 case F_ADDTOWORKSPACE: 2075 if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE; 2076 AddToWorkSpace (action, tmp_win); 2077 break; 2078 2079 case F_REMOVEFROMWORKSPACE: 2080 if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE; 2081 RemoveFromWorkSpace (action, tmp_win); 2082 break; 2083 2084 case F_TOGGLEOCCUPATION: 2085 if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE; 2086 ToggleOccupation (action, tmp_win); 2087 break; 2088 2089 case F_MOVETONEXTWORKSPACE: 2090 if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE; 2091 MoveToNextWorkSpace(Scr->currentvs,tmp_win); 2092 break; 2093 2094 case F_MOVETOPREVWORKSPACE: 2095 if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE; 2096 MoveToPrevWorkSpace(Scr->currentvs,tmp_win); 2097 break; 2098 2099 case F_MOVETONEXTWORKSPACEANDFOLLOW: 2100 if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE; 2101 MoveToNextWorkSpaceAndFollow(Scr->currentvs,tmp_win); 2102 break; 2103 2104 case F_MOVETOPREVWORKSPACEANDFOLLOW: 2105 if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE; 2106 MoveToPrevWorkSpaceAndFollow(Scr->currentvs,tmp_win); 2107 break; 2108 2109 case F_SORTICONMGR: 2110 if (DeferExecution(context, func, Scr->SelectCursor)) 2111 return TRUE; 2112 2113 { 2114 int save_sort; 2115 2116 save_sort = Scr->SortIconMgr; 2117 Scr->SortIconMgr = TRUE; 2118 2119 if (context == C_ICONMGR) 2120 SortIconManager((IconMgr *) NULL); 2121 else if (tmp_win->iconmgr) 2122 SortIconManager(tmp_win->iconmgrp); 2123 else 2124 XBell(dpy, 0); 2125 2126 Scr->SortIconMgr = save_sort; 2127 } 2128 break; 2129 2130 case F_ALTKEYMAP: { 2131 int alt, stat_; 2132 2133 if (! action) return TRUE; 2134 stat_ = sscanf (action, "%d", &alt); 2135 if (stat_ != 1) return TRUE; 2136 if ((alt < 1) || (alt > 5)) return TRUE; 2137 AlternateKeymap = Alt1Mask << (alt - 1); 2138 XGrabPointer (dpy, Scr->Root, True, ButtonPressMask | ButtonReleaseMask, 2139 GrabModeAsync, GrabModeAsync, 2140 Scr->Root, Scr->AlterCursor, CurrentTime); 2141 XGrabKeyboard (dpy, Scr->Root, True, GrabModeAsync, GrabModeAsync, CurrentTime); 2142 return TRUE; 2143 } 2144 2145 case F_ALTCONTEXT: { 2146 AlternateContext = True; 2147 XGrabPointer (dpy, Scr->Root, False, ButtonPressMask | ButtonReleaseMask, 2148 GrabModeAsync, GrabModeAsync, 2149 Scr->Root, Scr->AlterCursor, CurrentTime); 2150 XGrabKeyboard (dpy, Scr->Root, False, GrabModeAsync, GrabModeAsync, CurrentTime); 2151 return TRUE; 2152 } 2153 case F_IDENTIFY: 2154 if (DeferExecution(context, func, Scr->SelectCursor)) 2155 return TRUE; 2156 2157 Identify(tmp_win); 2158 break; 2159 2160 case F_INITSIZE: { 2161 int grav, x, y; 2162 unsigned int width, height, swidth, sheight; 2163 2164 if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE; 2165 grav = ((tmp_win->hints.flags & PWinGravity) 2166 ? tmp_win->hints.win_gravity : NorthWestGravity); 2167 2168 if (!(tmp_win->hints.flags & USSize) && !(tmp_win->hints.flags & PSize)) break; 2169 2170 width = tmp_win->hints.width + 2 * tmp_win->frame_bw3D; 2171 height = tmp_win->hints.height + 2 * tmp_win->frame_bw3D + tmp_win->title_height; 2172 ConstrainSize (tmp_win, &width, &height); 2173 2174 x = tmp_win->frame_x; 2175 y = tmp_win->frame_y; 2176 swidth = tmp_win->frame_width; 2177 sheight = tmp_win->frame_height; 2178 switch (grav) { 2179 case ForgetGravity : 2180 case StaticGravity : 2181 case NorthWestGravity : 2182 case NorthGravity : 2183 case WestGravity : 2184 case CenterGravity : 2185 break; 2186 2187 case NorthEastGravity : 2188 case EastGravity : 2189 x += swidth - width; 2190 break; 2191 2192 case SouthWestGravity : 2193 case SouthGravity : 2194 y += sheight - height; 2195 break; 2196 2197 case SouthEastGravity : 2198 x += swidth - width; 2199 y += sheight - height; 2200 break; 2201 } 2202 SetupWindow (tmp_win, x, y, width, height, -1); 2203 break; 2204 } 2205 2206 case F_MOVERESIZE: { 2207 int x, y, mask; 2208 unsigned int width, height; 2209 int px = 20, py = 30; 2210 2211 if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE; 2212 mask = XParseGeometry (action, &x, &y, &width, &height); 2213 if (!(mask & WidthValue)) width = tmp_win->frame_width; 2214 else width += 2 * tmp_win->frame_bw3D; 2215 if (!(mask & HeightValue)) height = tmp_win->frame_height; 2216 else height += 2 * tmp_win->frame_bw3D + tmp_win->title_height; 2217 ConstrainSize (tmp_win, &width, &height); 2218 if (mask & XValue) { 2219 if (mask & XNegative) x += Scr->rootw - width; 2220 } else x = tmp_win->frame_x; 2221 if (mask & YValue) { 2222 if (mask & YNegative) y += Scr->rooth - height; 2223 } else y = tmp_win->frame_y; 2224 2225 { 2226 int junkX, junkY; 2227 unsigned int junkK; 2228 Window junkW; 2229 XQueryPointer (dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &px, &py, &junkK); 2230 } 2231 px -= tmp_win->frame_x; if (px > width) px = width / 2; 2232 py -= tmp_win->frame_y; if (py > height) px = height / 2; 2233 SetupWindow (tmp_win, x, y, width, height, -1); 2234 XWarpPointer (dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, x + px, y + py); 2235 break; 2236 } 2237 2238 case F_VERSION: 2239 Identify ((TwmWindow *) NULL); 2240 break; 2241 2242 case F_AUTORAISE: 2243 if (DeferExecution(context, func, Scr->SelectCursor)) 2244 return TRUE; 2245 2246 tmp_win->auto_raise = !tmp_win->auto_raise; 2247 if (tmp_win->auto_raise) ++(Scr->NumAutoRaises); 2248 else --(Scr->NumAutoRaises); 2249 break; 2250 2251 case F_AUTOLOWER: 2252 if (DeferExecution(context, func, Scr->SelectCursor)) 2253 return TRUE; 2254 2255 tmp_win->auto_lower = !tmp_win->auto_lower; 2256 if (tmp_win->auto_lower) ++(Scr->NumAutoLowers); 2257 else --(Scr->NumAutoLowers); 2258 break; 2259 2260 case F_BEEP: 2261 XBell(dpy, 0); 2262 break; 2263 2264 case F_POPUP: 2265 tmp_win = (TwmWindow *)action; 2266 if (! tmp_win) break; 2267 if (Scr->WindowFunction.func != 0) 2268 { 2269 ExecuteFunction(Scr->WindowFunction.func, 2270 Scr->WindowFunction.item->action, 2271 w, tmp_win, eventp, C_FRAME, FALSE); 2272 } 2273 else 2274 { 2275 DeIconify(tmp_win); 2276 RaiseWindow (tmp_win); 2277 } 2278 break; 2279 2280 case F_WINWARP: 2281 tmp_win = (TwmWindow *)action; 2282 2283 if (! tmp_win) break; 2284 if (Scr->WarpUnmapped || tmp_win->mapped) { 2285 if (!tmp_win->mapped) DeIconify (tmp_win); 2286 WarpToWindow (tmp_win, Scr->RaiseOnWarp); 2287 } 2288 break; 2289 2290 case F_RESIZE: 2291 EventHandler[EnterNotify] = HandleUnknown; 2292 EventHandler[LeaveNotify] = HandleUnknown; 2293 if (DeferExecution(context, func, Scr->MoveCursor)) 2294 return TRUE; 2295 2296 PopDownMenu(); 2297 if (tmp_win->squeezed) { 2298 XBell (dpy, 0); 2299 break; 2300 } 2301 if (tmp_win->OpaqueResize) { 2302 /* 2303 * OpaqueResize defaults to a thousand. Assume that any number 2304 * >= 1000 is "infinity" and don't bother calculating. 2305 */ 2306 if (Scr->OpaqueResizeThreshold >= 1000) 2307 Scr->OpaqueResize = TRUE; 2308 else { 2309 /* 2310 * scrsz will hold the number of pixels in your resolution, 2311 * which can get big. [signed] int may not cut it. 2312 */ 2313 unsigned long winsz, scrsz; 2314 winsz = tmp_win->frame_width * tmp_win->frame_height; 2315 scrsz = Scr->rootw * Scr->rooth; 2316 if (winsz > (scrsz * (Scr->OpaqueResizeThreshold / 100.0))) 2317 Scr->OpaqueResize = FALSE; 2318 else 2319 Scr->OpaqueResize = TRUE; 2320 } 2321 } 2322 else 2323 Scr->OpaqueResize = FALSE; 2324 2325 if (pulldown) 2326 XWarpPointer(dpy, None, Scr->Root, 2327 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root); 2328 2329 if (!tmp_win->icon || (w != tmp_win->icon->w)) { /* can't resize icons */ 2330 2331/* fromMenu = False; ????? */ 2332 if ((Context == C_FRAME || Context == C_WINDOW || Context == C_TITLE) 2333 && fromMenu) 2334 resizeFromCenter(w, tmp_win); 2335 else { 2336 /* 2337 * see if this is being done from the titlebar 2338 */ 2339 from3dborder = (eventp->xbutton.window == tmp_win->frame); 2340 fromtitlebar = !from3dborder && 2341 belongs_to_twm_window (tmp_win, eventp->xbutton.window); 2342 2343 /* Save pointer position so we can tell if it was moved or 2344 not during the resize. */ 2345 ResizeOrigX = eventp->xbutton.x_root; 2346 ResizeOrigY = eventp->xbutton.y_root; 2347 2348 StartResize (eventp, tmp_win, fromtitlebar, from3dborder); 2349 2350 do { 2351 XMaskEvent(dpy, 2352 ButtonPressMask | ButtonReleaseMask | 2353 EnterWindowMask | LeaveWindowMask | 2354 ButtonMotionMask | VisibilityChangeMask | ExposureMask, &Event); 2355 2356 if (fromtitlebar && Event.type == ButtonPress) { 2357 fromtitlebar = False; 2358 continue; 2359 } 2360 2361 if (Event.type == MotionNotify) { 2362 /* discard any extra motion events before a release */ 2363 while 2364 (XCheckMaskEvent 2365 (dpy, ButtonMotionMask | ButtonReleaseMask, &Event)) 2366 if (Event.type == ButtonRelease) 2367 break; 2368 } 2369 2370 if (!DispatchEvent2 ()) continue; 2371 2372 } while (!(Event.type == ButtonRelease || Cancel)); 2373 return TRUE; 2374 } 2375 } 2376 break; 2377 2378 2379 case F_ZOOM: 2380 case F_HORIZOOM: 2381 case F_FULLZOOM: 2382 case F_LEFTZOOM: 2383 case F_RIGHTZOOM: 2384 case F_TOPZOOM: 2385 case F_BOTTOMZOOM: 2386 if (DeferExecution(context, func, Scr->SelectCursor)) 2387 return TRUE; 2388 if (tmp_win->squeezed) { 2389 XBell(dpy, 0); 2390 break; 2391 } 2392 fullzoom(tmp_win, func); 2393 break; 2394 2395 case F_PACK: 2396 if (DeferExecution(context, func, Scr->SelectCursor)) return TRUE; 2397 if (tmp_win->squeezed) { XBell(dpy, 0); break; } 2398 packwindow (tmp_win, action); 2399 break; 2400 2401 case F_FILL: 2402 if (DeferExecution(context, func, Scr->SelectCursor)) return TRUE; 2403 if (tmp_win->squeezed) { XBell(dpy, 0); break; } 2404 fillwindow (tmp_win, action); 2405 break; 2406 2407 case F_JUMPLEFT: 2408 if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE; 2409 if (tmp_win->squeezed) { XBell(dpy, 0); break; } 2410 jump (tmp_win, J_LEFT, action); 2411 break; 2412 case F_JUMPRIGHT: 2413 if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE; 2414 if (tmp_win->squeezed) { XBell(dpy, 0); break; } 2415 jump (tmp_win, J_RIGHT, action); 2416 break; 2417 case F_JUMPDOWN: 2418 if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE; 2419 if (tmp_win->squeezed) { XBell(dpy, 0); break; } 2420 jump (tmp_win, J_BOTTOM, action); 2421 break; 2422 case F_JUMPUP: 2423 if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE; 2424 if (tmp_win->squeezed) { XBell(dpy, 0); break; } 2425 jump (tmp_win, J_TOP, action); 2426 break; 2427 2428 case F_SAVEGEOMETRY: 2429 if (DeferExecution(context, func, Scr->SelectCursor)) return TRUE; 2430 savegeometry (tmp_win); 2431 break; 2432 2433 case F_RESTOREGEOMETRY: 2434 if (DeferExecution(context, func, Scr->SelectCursor)) return TRUE; 2435 restoregeometry (tmp_win); 2436 break; 2437 2438 case F_HYPERMOVE: { 2439 Bool cont = True; 2440 Window root = RootWindow (dpy, Scr->screen); 2441 Cursor cursor; 2442 CaptiveCTWM cctwm0, cctwm; 2443 2444 if (DeferExecution(context, func, Scr->MoveCursor)) return TRUE; 2445 2446 if (tmp_win->iswinbox || tmp_win->wspmgr) { 2447 XBell (dpy, 0); 2448 break; 2449 } 2450 cctwm0 = GetCaptiveCTWMUnderPointer (); 2451 cursor = MakeStringCursor (cctwm0.name); 2452 free (cctwm0.name); 2453 if (DeferExecution (context, func, Scr->MoveCursor)) return TRUE; 2454 2455 XGrabPointer (dpy, root, True, 2456 ButtonPressMask | ButtonMotionMask | ButtonReleaseMask, 2457 GrabModeAsync, GrabModeAsync, root, cursor, CurrentTime); 2458 while (cont) { 2459 XMaskEvent (dpy, ButtonPressMask | ButtonMotionMask | 2460 ButtonReleaseMask, &Event); 2461 switch (Event.xany.type) { 2462 case ButtonPress : 2463 cont = False; 2464 break; 2465 2466 case ButtonRelease : 2467 cont = False; 2468 cctwm = GetCaptiveCTWMUnderPointer (); 2469 free (cctwm.name); 2470 if (cctwm.root == Scr->Root) break; 2471 SetNoRedirect (tmp_win->w); 2472 XUngrabButton (dpy, AnyButton, AnyModifier, tmp_win->w); 2473 XReparentWindow (dpy, tmp_win->w, cctwm.root, 0, 0); 2474 XMapWindow (dpy, tmp_win->w); 2475 break; 2476 2477 case MotionNotify : 2478 cctwm = GetCaptiveCTWMUnderPointer (); 2479 if (cctwm.root != cctwm0.root) { 2480 XFreeCursor (dpy, cursor); 2481 cursor = MakeStringCursor (cctwm.name); 2482 cctwm0 = cctwm; 2483 XChangeActivePointerGrab (dpy, 2484 ButtonPressMask | ButtonMotionMask | ButtonReleaseMask, 2485 cursor, CurrentTime); 2486 } 2487 free (cctwm.name); 2488 break; 2489 } 2490 } 2491 ButtonPressed = -1; 2492 XUngrabPointer (dpy, CurrentTime); 2493 XFreeCursor (dpy, cursor); 2494 break; 2495 } 2496 2497 case F_MOVE: 2498 case F_FORCEMOVE: 2499 case F_MOVEPACK: 2500 case F_MOVEPUSH: { 2501 Window grabwin, dragroot; 2502 2503 if (DeferExecution(context, func, Scr->MoveCursor)) 2504 return TRUE; 2505 2506 PopDownMenu(); 2507 if (tmp_win->OpaqueMove) { 2508 int sw, ss; 2509 float sf; 2510 2511 sw = tmp_win->frame_width * tmp_win->frame_height; 2512 ss = Scr->rootw * Scr->rooth; 2513 sf = Scr->OpaqueMoveThreshold / 100.0; 2514 if (sw > (ss * sf)) 2515 Scr->OpaqueMove = FALSE; 2516 else 2517 Scr->OpaqueMove = TRUE; 2518 } 2519 else 2520 Scr->OpaqueMove = FALSE; 2521 2522 dragroot = Scr->XineramaRoot; 2523 2524 if (tmp_win->winbox) { 2525 XTranslateCoordinates (dpy, dragroot, tmp_win->winbox->window, 2526 eventp->xbutton.x_root, eventp->xbutton.y_root, 2527 &(eventp->xbutton.x_root), &(eventp->xbutton.y_root), &JunkChild); 2528 } 2529 rootw = eventp->xbutton.root; 2530 MoveFunction = func; 2531 2532 if (pulldown) 2533 XWarpPointer(dpy, None, Scr->Root, 2534 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root); 2535 2536 EventHandler[EnterNotify] = HandleUnknown; 2537 EventHandler[LeaveNotify] = HandleUnknown; 2538 2539 if (!Scr->NoGrabServer || !Scr->OpaqueMove) { 2540 XGrabServer(dpy); 2541 } 2542 2543 Scr->SizeStringOffset = SIZE_HINDENT; 2544 XResizeWindow (dpy, Scr->SizeWindow, 2545 Scr->SizeStringWidth + SIZE_HINDENT * 2, 2546 Scr->SizeFont.height + SIZE_VINDENT * 2); 2547 XMapRaised (dpy, Scr->SizeWindow); 2548 2549 grabwin = Scr->XineramaRoot; 2550 if (tmp_win->winbox) grabwin = tmp_win->winbox->window; 2551 XGrabPointer(dpy, grabwin, True, 2552 ButtonPressMask | ButtonReleaseMask | 2553 ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */ 2554 GrabModeAsync, GrabModeAsync, grabwin, Scr->MoveCursor, CurrentTime); 2555 2556 if (context == C_ICON && tmp_win->icon && tmp_win->icon->w) 2557 { 2558 w = tmp_win->icon->w; 2559 DragX = eventp->xbutton.x; 2560 DragY = eventp->xbutton.y; 2561 moving_icon = TRUE; 2562 if (tmp_win->OpaqueMove) Scr->OpaqueMove = TRUE; 2563 } 2564 2565 else if (! tmp_win->icon || w != tmp_win->icon->w) 2566 { 2567 XTranslateCoordinates(dpy, w, tmp_win->frame, 2568 eventp->xbutton.x, 2569 eventp->xbutton.y, 2570 &DragX, &DragY, &JunkChild); 2571 2572 w = tmp_win->frame; 2573 } 2574 2575 DragWindow = None; 2576 2577 /* Get x/y relative to parent window, i.e. the virtual screen, Root. 2578 * XMoveWindow() moves are relative to this. 2579 * MoveOutline()s however are drawn from the XineramaRoot since they 2580 * may cross virtual screens. 2581 */ 2582 XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY, 2583 &DragWidth, &DragHeight, &DragBW, 2584 &JunkDepth); 2585 2586 JunkBW = DragBW; 2587 origX = eventp->xbutton.x_root; 2588 origY = eventp->xbutton.y_root; 2589 CurrentDragX = origDragX; 2590 CurrentDragY = origDragY; 2591 2592 /* 2593 * only do the constrained move if timer is set; need to check it 2594 * in case of stupid or wicked fast servers 2595 */ 2596 if (ConstrainedMoveTime && 2597 (eventp->xbutton.time - last_time) < ConstrainedMoveTime) 2598 { 2599 int width, height; 2600 2601 ConstMove = TRUE; 2602 ConstMoveDir = MOVE_NONE; 2603 ConstMoveX = eventp->xbutton.x_root - DragX - JunkBW; 2604 ConstMoveY = eventp->xbutton.y_root - DragY - JunkBW; 2605 width = DragWidth + 2 * JunkBW; 2606 height = DragHeight + 2 * JunkBW; 2607 ConstMoveXL = ConstMoveX + width/3; 2608 ConstMoveXR = ConstMoveX + 2*(width/3); 2609 ConstMoveYT = ConstMoveY + height/3; 2610 ConstMoveYB = ConstMoveY + 2*(height/3); 2611 2612 XWarpPointer(dpy, None, w, 2613 0, 0, 0, 0, DragWidth/2, DragHeight/2); 2614 2615 XQueryPointer(dpy, w, &JunkRoot, &JunkChild, 2616 &JunkX, &JunkY, &DragX, &DragY, &JunkMask); 2617 } 2618 last_time = eventp->xbutton.time; 2619 2620 if (!Scr->OpaqueMove) 2621 { 2622 InstallRootColormap(); 2623 if (!Scr->MoveDelta) 2624 { 2625 /* 2626 * Draw initial outline. This was previously done the 2627 * first time though the outer loop by dropping out of 2628 * the XCheckMaskEvent inner loop down to one of the 2629 * MoveOutline's below. 2630 */ 2631 MoveOutline(dragroot, 2632 origDragX - JunkBW + Scr->currentvs->x, 2633 origDragY - JunkBW + Scr->currentvs->y, 2634 DragWidth + 2 * JunkBW, DragHeight + 2 * JunkBW, 2635 tmp_win->frame_bw, 2636 moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D); 2637 /* 2638 * This next line causes HandleReleaseNotify to call 2639 * XRaiseWindow(). This is solely to preserve the 2640 * previous behaviour that raises a window being moved 2641 * on button release even if you never actually moved 2642 * any distance (unless you move less than MoveDelta or 2643 * NoRaiseMove is set or OpaqueMove is set). 2644 */ 2645 DragWindow = w; 2646 } 2647 } 2648 2649 /* 2650 * see if this is being done from the titlebar 2651 */ 2652 fromtitlebar = belongs_to_twm_window (tmp_win, eventp->xbutton.window); 2653 2654 if (menuFromFrameOrWindowOrTitlebar) { 2655 /* warp the pointer to the middle of the window */ 2656 XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0, 2657 origDragX + DragWidth / 2, 2658 origDragY + DragHeight / 2); 2659 XFlush(dpy); 2660 } 2661 2662 DisplayPosition (tmp_win, CurrentDragX, CurrentDragY); 2663 while (TRUE) 2664 { 2665 long releaseEvent = menuFromFrameOrWindowOrTitlebar ? 2666 ButtonPress : ButtonRelease; 2667 long movementMask = menuFromFrameOrWindowOrTitlebar ? 2668 PointerMotionMask : ButtonMotionMask; 2669 2670 /* block until there is an interesting event */ 2671 XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask | 2672 EnterWindowMask | LeaveWindowMask | 2673 ExposureMask | movementMask | 2674 VisibilityChangeMask, &Event); 2675 2676 /* throw away enter and leave events until release */ 2677 if (Event.xany.type == EnterNotify || 2678 Event.xany.type == LeaveNotify) continue; 2679 2680 if (Event.type == MotionNotify) { 2681 /* discard any extra motion events before a logical release */ 2682 while(XCheckMaskEvent(dpy, 2683 movementMask | releaseEvent, &Event)) 2684 if (Event.type == releaseEvent) { 2685 break; 2686 } 2687 } 2688 2689 /* test to see if we have a second button press to abort move */ 2690 if (!menuFromFrameOrWindowOrTitlebar) 2691 if (Event.type == ButtonPress && DragWindow != None) { 2692 Cursor cur; 2693 if (Scr->OpaqueMove) { 2694 XMoveWindow (dpy, DragWindow, origDragX, origDragY); 2695 } else { 2696 MoveOutline(dragroot, 0, 0, 0, 0, 0, 0); 2697 } 2698 DragWindow = None; 2699 2700 XUnmapWindow (dpy, Scr->SizeWindow); 2701 cur = LeftButt; 2702 if (Event.xbutton.button == Button2) 2703 cur = MiddleButt; 2704 else if (Event.xbutton.button >= Button3) 2705 cur = RightButt; 2706 2707 XGrabPointer (dpy, Scr->Root, True, 2708 ButtonReleaseMask | ButtonPressMask, 2709 GrabModeAsync, GrabModeAsync, 2710 Scr->Root, cur, CurrentTime); 2711 return TRUE; 2712 } 2713 2714 if (fromtitlebar && Event.type == ButtonPress) { 2715 fromtitlebar = False; 2716 CurrentDragX = origX = Event.xbutton.x_root; 2717 CurrentDragY = origY = Event.xbutton.y_root; 2718 XTranslateCoordinates (dpy, rootw, tmp_win->frame, 2719 origX, origY, 2720 &DragX, &DragY, &JunkChild); 2721 continue; 2722 } 2723 2724 if (!DispatchEvent2 ()) continue; 2725 2726 if (Cancel) 2727 { 2728 WindowMoved = FALSE; 2729 if (!Scr->OpaqueMove) 2730 UninstallRootColormap(); 2731 return TRUE; /* XXX should this be FALSE? */ 2732 } 2733 if (Event.type == releaseEvent) 2734 { 2735 MoveOutline(dragroot, 0, 0, 0, 0, 0, 0); 2736 if (moving_icon && 2737 ((CurrentDragX != origDragX || 2738 CurrentDragY != origDragY))) 2739 tmp_win->icon_moved = TRUE; 2740 if (!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar) { 2741 int xl = Event.xbutton.x_root - (DragWidth / 2), 2742 yt = Event.xbutton.y_root - (DragHeight / 2); 2743 if (!moving_icon && 2744 (MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH)) 2745 TryToPack (tmp_win, &xl, &yt); 2746 XMoveWindow(dpy, DragWindow, xl, yt); 2747 } 2748 if (menuFromFrameOrWindowOrTitlebar) DragWindow = None; 2749 break; 2750 } 2751 2752 /* something left to do only if the pointer moved */ 2753 if (Event.type != MotionNotify) 2754 continue; 2755 2756 XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild, 2757 &(eventp->xmotion.x_root), &(eventp->xmotion.y_root), 2758 &JunkX, &JunkY, &JunkMask); 2759 2760 FixRootEvent (eventp); 2761 if (tmp_win->winbox) { 2762 XTranslateCoordinates (dpy, dragroot, tmp_win->winbox->window, 2763 eventp->xmotion.x_root, eventp->xmotion.y_root, 2764 &(eventp->xmotion.x_root), &(eventp->xmotion.y_root), &JunkChild); 2765 } 2766 if (DragWindow == None && 2767 abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta && 2768 abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta) 2769 continue; 2770 2771 DragWindow = w; 2772 2773 if (!Scr->NoRaiseMove && Scr->OpaqueMove && !WindowMoved) 2774 RaiseFrame(DragWindow); 2775 2776 WindowMoved = TRUE; 2777 2778 if (ConstMove) 2779 { 2780 switch (ConstMoveDir) 2781 { 2782 case MOVE_NONE: 2783 if (eventp->xmotion.x_root < ConstMoveXL || 2784 eventp->xmotion.x_root > ConstMoveXR) 2785 ConstMoveDir = MOVE_HORIZ; 2786 2787 if (eventp->xmotion.y_root < ConstMoveYT || 2788 eventp->xmotion.y_root > ConstMoveYB) 2789 ConstMoveDir = MOVE_VERT; 2790 2791 XQueryPointer(dpy, DragWindow, &JunkRoot, &JunkChild, 2792 &JunkX, &JunkY, &DragX, &DragY, &JunkMask); 2793 break; 2794 2795 case MOVE_VERT: 2796 ConstMoveY = eventp->xmotion.y_root - DragY - JunkBW; 2797 break; 2798 2799 case MOVE_HORIZ: 2800 ConstMoveX= eventp->xmotion.x_root - DragX - JunkBW; 2801 break; 2802 } 2803 2804 if (ConstMoveDir != MOVE_NONE) 2805 { 2806 int xl, yt, width, height; 2807 2808 xl = ConstMoveX; 2809 yt = ConstMoveY; 2810 width = DragWidth + 2 * JunkBW; 2811 height = DragHeight + 2 * JunkBW; 2812 2813 if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) 2814 TryToGrid (tmp_win, &xl, &yt); 2815 if (!moving_icon && MoveFunction == F_MOVEPUSH && Scr->OpaqueMove) 2816 TryToPush (tmp_win, xl, yt, 0); 2817 2818 if (!moving_icon && 2819 (MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH)) 2820 TryToPack (tmp_win, &xl, &yt); 2821 2822 if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) 2823 { 2824 ConstrainByBorders (tmp_win, &xl, width, &yt, height); 2825 } 2826 CurrentDragX = xl; 2827 CurrentDragY = yt; 2828 if (Scr->OpaqueMove) { 2829 if (MoveFunction == F_MOVEPUSH && !moving_icon) { 2830 SetupWindow (tmp_win, xl, yt, 2831 tmp_win->frame_width, tmp_win->frame_height, -1); 2832 } else { 2833 XMoveWindow(dpy, DragWindow, xl, yt); 2834 } 2835 WMapSetupWindow (tmp_win, xl, yt, -1, -1); 2836 } 2837 else { 2838 MoveOutline(dragroot, xl + Scr->currentvs->x, 2839 yt + Scr->currentvs->y, width, height, 2840 tmp_win->frame_bw, 2841 moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D); 2842 } 2843 } 2844 } 2845 else if (DragWindow != None) 2846 { 2847 int xroot, yroot; 2848 int xl, yt, width, height; 2849 2850 2851 /* 2852 * this is split out for virtual screens. In that case, it's 2853 * possible to drag windows from one workspace to another, and 2854 * as such, these need to be adjusted to the root, rather 2855 * than this virtual screen... 2856 */ 2857 xroot = eventp->xmotion.x_root; 2858 yroot = eventp->xmotion.y_root; 2859 2860 if (!menuFromFrameOrWindowOrTitlebar) { 2861 xl = xroot - DragX - JunkBW; 2862 yt = yroot - DragY - JunkBW; 2863 } 2864 else { 2865 xl = xroot - (DragWidth / 2); 2866 yt = yroot - (DragHeight / 2); 2867 } 2868 width = DragWidth + 2 * JunkBW; 2869 height = DragHeight + 2 * JunkBW; 2870 2871 if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) 2872 TryToGrid (tmp_win, &xl, &yt); 2873 if (!moving_icon && MoveFunction == F_MOVEPUSH && Scr->OpaqueMove) 2874 TryToPush (tmp_win, xl, yt, 0); 2875 2876 if (!moving_icon && 2877 (MoveFunction == F_MOVEPACK || MoveFunction == F_MOVEPUSH)) 2878 TryToPack (tmp_win, &xl, &yt); 2879 2880 if (Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) 2881 { 2882 ConstrainByBorders (tmp_win, &xl, width, &yt, height); 2883 } 2884 2885 CurrentDragX = xl; 2886 CurrentDragY = yt; 2887 if (Scr->OpaqueMove) { 2888 if (MoveFunction == F_MOVEPUSH && !moving_icon) { 2889 SetupWindow (tmp_win, xl, yt, 2890 tmp_win->frame_width, tmp_win->frame_height, -1); 2891 } else { 2892 XMoveWindow(dpy, DragWindow, xl, yt); 2893 } 2894 if (! moving_icon) WMapSetupWindow (tmp_win, xl, yt, -1, -1); 2895 } 2896 else { 2897 MoveOutline(dragroot, xl + Scr->currentvs->x, 2898 yt + Scr->currentvs->y, width, height, 2899 tmp_win->frame_bw, 2900 moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D); 2901 } 2902 } 2903 DisplayPosition (tmp_win, CurrentDragX, CurrentDragY); 2904 } 2905 XUnmapWindow (dpy, Scr->SizeWindow); 2906 2907 if (!Scr->OpaqueMove && DragWindow == None) 2908 UninstallRootColormap(); 2909 break; 2910 } 2911 case F_MOVETITLEBAR: 2912 { 2913 Window grabwin; 2914 int deltax = 0, newx = 0; 2915 int origNum; 2916 SqueezeInfo *si; 2917 2918 if (DeferExecution(context, func, Scr->MoveCursor)) 2919 return TRUE; 2920 2921 PopDownMenu(); 2922 if (tmp_win->squeezed || 2923 !tmp_win->squeeze_info || 2924 !tmp_win->title_w || 2925 context == C_ICON ) { 2926 XBell (dpy, 0); 2927 break; 2928 } 2929 2930 /* If the SqueezeInfo isn't copied yet, do it now */ 2931 if (!tmp_win->squeeze_info_copied) { 2932 SqueezeInfo *s = malloc(sizeof(SqueezeInfo)); 2933 if (!s) 2934 break; 2935 *s = *tmp_win->squeeze_info; 2936 tmp_win->squeeze_info = s; 2937 tmp_win->squeeze_info_copied = 1; 2938 } 2939 si = tmp_win->squeeze_info; 2940 2941 if (si->denom != 0) { 2942 int target_denom = tmp_win->frame_width; 2943 /* 2944 * If not pixel based, scale the denominator to equal the 2945 * window width, so the numerator equals pixels. 2946 * That way we can just modify it by pixel units, just 2947 * like the other case. 2948 */ 2949 2950 if (si->denom != target_denom) { 2951 float scale = (float)target_denom / si->denom; 2952 si->num *= scale; 2953 si->denom = target_denom; /* s->denom *= scale; */ 2954 } 2955 } 2956 2957 /* now move the mouse */ 2958 if (tmp_win->winbox) { 2959 XTranslateCoordinates (dpy, Scr->Root, tmp_win->winbox->window, 2960 eventp->xbutton.x_root, eventp->xbutton.y_root, 2961 &eventp->xbutton.x_root, &eventp->xbutton.y_root, &JunkChild); 2962 } 2963 /* 2964 * the event is always a button event, since key events 2965 * are "weeded out" - although incompletely only 2966 * F_MOVE and F_RESIZE - in HandleKeyPress(). 2967 */ 2968 rootw = eventp->xbutton.root; 2969 2970 EventHandler[EnterNotify] = HandleUnknown; 2971 EventHandler[LeaveNotify] = HandleUnknown; 2972 2973 if (!Scr->NoGrabServer) { 2974 XGrabServer(dpy); 2975 } 2976 2977 grabwin = Scr->Root; 2978 if (tmp_win->winbox) grabwin = tmp_win->winbox->window; 2979 XGrabPointer(dpy, grabwin, True, 2980 ButtonPressMask | ButtonReleaseMask | 2981 ButtonMotionMask | PointerMotionMask, /* PointerMotionHintMask */ 2982 GrabModeAsync, GrabModeAsync, grabwin, Scr->MoveCursor, CurrentTime); 2983 2984#if 0 /* what's this for ? */ 2985 if (! tmp_win->icon || w != tmp_win->icon->w) 2986 { 2987 XTranslateCoordinates(dpy, w, tmp_win->frame, 2988 eventp->xbutton.x, 2989 eventp->xbutton.y, 2990 &DragX, &DragY, &JunkChild); 2991 2992 w = tmp_win->frame; 2993 } 2994#endif 2995 2996 DragWindow = None; 2997 2998 XGetGeometry(dpy, tmp_win->title_w, &JunkRoot, &origDragX, &origDragY, 2999 &DragWidth, &DragHeight, &DragBW, 3000 &JunkDepth); 3001 3002 origX = eventp->xbutton.x_root; 3003 origNum = si->num; 3004 3005 if (menuFromFrameOrWindowOrTitlebar) { 3006 /* warp the pointer to the middle of the window */ 3007 XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0, 3008 origDragX + DragWidth / 2, 3009 origDragY + DragHeight / 2); 3010 XFlush(dpy); 3011 } 3012 3013 while (TRUE) 3014 { 3015 long releaseEvent = menuFromFrameOrWindowOrTitlebar ? 3016 ButtonPress : ButtonRelease; 3017 long movementMask = menuFromFrameOrWindowOrTitlebar ? 3018 PointerMotionMask : ButtonMotionMask; 3019 3020 /* block until there is an interesting event */ 3021 XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask | 3022 EnterWindowMask | LeaveWindowMask | 3023 ExposureMask | movementMask | 3024 VisibilityChangeMask, &Event); 3025 3026 /* throw away enter and leave events until release */ 3027 if (Event.xany.type == EnterNotify || 3028 Event.xany.type == LeaveNotify) continue; 3029 3030 if (Event.type == MotionNotify) { 3031 /* discard any extra motion events before a logical release */ 3032 while (XCheckMaskEvent(dpy, 3033 movementMask | releaseEvent, &Event)) { 3034 if (Event.type == releaseEvent) { 3035 break; 3036 } 3037 } 3038 } 3039 3040 if (!DispatchEvent2()) 3041 continue; 3042 3043 if (Event.type == releaseEvent) 3044 break; 3045 3046 /* something left to do only if the pointer moved */ 3047 if (Event.type != MotionNotify) 3048 continue; 3049 3050 /* get current pointer pos, useful when there is lag */ 3051 XQueryPointer(dpy, rootw, &eventp->xmotion.root, &JunkChild, 3052 &eventp->xmotion.x_root, &eventp->xmotion.y_root, 3053 &JunkX, &JunkY, &JunkMask); 3054 3055 FixRootEvent(eventp); 3056 if (tmp_win->winbox) { 3057 XTranslateCoordinates(dpy, Scr->Root, tmp_win->winbox->window, 3058 eventp->xmotion.x_root, eventp->xmotion.y_root, 3059 &eventp->xmotion.x_root, &eventp->xmotion.y_root, &JunkChild); 3060 } 3061 3062 if (!Scr->NoRaiseMove && Scr->OpaqueMove && !WindowMoved) 3063 RaiseFrame(w); 3064 3065 deltax = eventp->xmotion.x_root - origX; 3066 newx = origNum + deltax; 3067 3068 /* 3069 * Clamp to left and right. 3070 * If we're in pixel size, keep within [ 0, frame_width >. 3071 * If we're proportional, don't cross the 0. 3072 * Also don't let the nominator get bigger than the denominator. 3073 * Keep within [ -denom, -1] or [ 0, denom >. 3074 */ 3075 { 3076 int wtmp = tmp_win->frame_width; /* or si->denom; if it were != 0 */ 3077 if (origNum < 0) { 3078 if (newx >= 0) 3079 newx = -1; 3080 else if (newx < -wtmp) 3081 newx = -wtmp; 3082 } else if (origNum >= 0) { 3083 if (newx < 0) 3084 newx = 0; 3085 else if (newx >= wtmp) 3086 newx = wtmp - 1; 3087 } 3088 } 3089 3090 si->num = newx; 3091 /* This, finally, actually moves the title bar */ 3092 /* XXX pressing a second button should cancel and undo this */ 3093 SetFrameShape(tmp_win); 3094 } 3095 break; 3096 } 3097 case F_FUNCTION: 3098 { 3099 MenuRoot *mroot; 3100 MenuItem *mitem; 3101 3102 if ((mroot = FindMenuRoot(action)) == NULL) 3103 { 3104 if (!action) action = "undef"; 3105 fprintf (stderr, "%s: couldn't find function \"%s\"\n", 3106 ProgramName, (char *)action); 3107 return TRUE; 3108 } 3109 3110 if (NeedToDefer(mroot) && DeferExecution(context, func, Scr->SelectCursor)) 3111 return TRUE; 3112 else 3113 { 3114 for (mitem = mroot->first; mitem != NULL; mitem = mitem->next) 3115 { 3116 if (!ExecuteFunction (mitem->func, mitem->action, w, 3117 tmp_win, eventp, context, pulldown)) 3118 /* pebl FIXME: the focus should be updated here, 3119 or the function would operate on the same window */ 3120 break; 3121 } 3122 } 3123 } 3124 break; 3125 3126 case F_DEICONIFY: 3127 case F_ICONIFY: 3128 if (DeferExecution(context, func, Scr->SelectCursor)) 3129 return TRUE; 3130 3131 if (tmp_win->isicon) 3132 { 3133 DeIconify(tmp_win); 3134 } 3135 else if (func == F_ICONIFY) 3136 { 3137 Iconify (tmp_win, eventp->xbutton.x_root - 5, 3138 eventp->xbutton.y_root - 5); 3139 } 3140 break; 3141 3142 case F_SQUEEZE: 3143 if (DeferExecution(context, func, Scr->SelectCursor)) 3144 return TRUE; 3145 3146 Squeeze (tmp_win); 3147 break; 3148 3149 case F_SHOWBGRD: 3150 ShowBackground (Scr->currentvs); 3151 break; 3152 3153 case F_RAISELOWER: 3154 if (DeferExecution(context, func, Scr->SelectCursor)) 3155 return TRUE; 3156 3157 if (!WindowMoved) { 3158 if (tmp_win->icon && w == tmp_win->icon->w) { 3159 RaiseLowerFrame(w, ONTOP_DEFAULT); 3160 } else { 3161 RaiseLower(tmp_win); 3162 WMapRaiseLower (tmp_win); 3163 } 3164 } 3165 break; 3166 3167 case F_RAISE: 3168 if (DeferExecution(context, func, Scr->SelectCursor)) 3169 return TRUE; 3170 3171 /* check to make sure raise is not from the WindowFunction */ 3172 if (tmp_win->icon && (w == tmp_win->icon->w) && Context != C_ROOT) 3173 XRaiseWindow(dpy, tmp_win->icon->w); 3174 else { 3175 RaiseWindow (tmp_win); 3176 WMapRaise (tmp_win); 3177 } 3178 break; 3179 3180 case F_LOWER: 3181 if (DeferExecution(context, func, Scr->SelectCursor)) 3182 return TRUE; 3183 3184 if (tmp_win->icon && (w == tmp_win->icon->w)) 3185 XLowerWindow(dpy, tmp_win->icon->w); 3186 else { 3187 LowerWindow(tmp_win); 3188 WMapLower (tmp_win); 3189 } 3190 break; 3191 3192 case F_RAISEICONS: 3193 for (t = Scr->FirstWindow; t != NULL; t = t->next) { 3194 if (t->icon && t->icon->w) { 3195 XRaiseWindow (dpy, t->icon->w); 3196 } 3197 } 3198 break; 3199 3200 case F_FOCUS: 3201 if (DeferExecution(context, func, Scr->SelectCursor)) 3202 return TRUE; 3203 3204 if (tmp_win->isicon == FALSE) 3205 { 3206 if (!Scr->FocusRoot && Scr->Focus == tmp_win) 3207 { 3208 FocusOnRoot(); 3209 } 3210 else 3211 { 3212 InstallWindowColormaps (0, tmp_win); 3213 SetFocus (tmp_win, eventp->xbutton.time); 3214 Scr->FocusRoot = FALSE; 3215 } 3216 } 3217 break; 3218 3219 case F_DESTROY: 3220 if (DeferExecution(context, func, Scr->DestroyCursor)) 3221 return TRUE; 3222 3223 if (tmp_win->iconmgr || tmp_win->iswinbox || tmp_win->wspmgr 3224 || (Scr->workSpaceMgr.occupyWindow 3225 && tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) { 3226 XBell(dpy, 0); 3227 break; 3228 } 3229 XKillClient(dpy, tmp_win->w); 3230 if (ButtonPressed != -1) { 3231 XEvent kev; 3232 3233 XMaskEvent (dpy, ButtonReleaseMask, &kev); 3234 if (kev.xbutton.window == tmp_win->w) kev.xbutton.window = Scr->Root; 3235 XPutBackEvent (dpy, &kev); 3236 } 3237 break; 3238 3239 case F_DELETE: 3240 if (DeferExecution(context, func, Scr->DestroyCursor)) 3241 return TRUE; 3242 3243 if (tmp_win->iconmgr) { /* don't send ourself a message */ 3244 HideIconManager (); 3245 break; 3246 } 3247 if (tmp_win->iswinbox || tmp_win->wspmgr 3248 || (Scr->workSpaceMgr.occupyWindow 3249 && tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) { 3250 XBell (dpy, 0); 3251 break; 3252 } 3253 if (tmp_win->protocols & DoesWmDeleteWindow) { 3254 SendDeleteWindowMessage (tmp_win, LastTimestamp()); 3255 if (ButtonPressed != -1) { 3256 XEvent kev; 3257 3258 XMaskEvent (dpy, ButtonReleaseMask, &kev); 3259 if (kev.xbutton.window == tmp_win->w) kev.xbutton.window = Scr->Root; 3260 XPutBackEvent (dpy, &kev); 3261 } 3262 break; 3263 } 3264 XBell (dpy, 0); 3265 break; 3266 3267 case F_DELETEORDESTROY: 3268 if (DeferExecution(context, func, Scr->DestroyCursor)) return TRUE; 3269 3270 if (tmp_win->iconmgr) { 3271 HideIconManager (); 3272 break; 3273 } 3274 if (tmp_win->iswinbox || tmp_win->wspmgr 3275 || (Scr->workSpaceMgr.occupyWindow 3276 && tmp_win == Scr->workSpaceMgr.occupyWindow->twm_win)) { 3277 XBell (dpy, 0); 3278 break; 3279 } 3280 if (tmp_win->protocols & DoesWmDeleteWindow) { 3281 SendDeleteWindowMessage (tmp_win, LastTimestamp()); 3282 } else { 3283 XKillClient(dpy, tmp_win->w); 3284 } 3285 if (ButtonPressed != -1) { 3286 XEvent kev; 3287 3288 XMaskEvent (dpy, ButtonReleaseMask, &kev); 3289 if (kev.xbutton.window == tmp_win->w) kev.xbutton.window = Scr->Root; 3290 XPutBackEvent (dpy, &kev); 3291 } 3292 break; 3293 3294 case F_SAVEYOURSELF: 3295 if (DeferExecution (context, func, Scr->SelectCursor)) 3296 return TRUE; 3297 3298 if (tmp_win->protocols & DoesWmSaveYourself) 3299 SendSaveYourselfMessage (tmp_win, LastTimestamp()); 3300 else 3301 XBell (dpy, 0); 3302 break; 3303 3304 case F_CIRCLEUP: 3305 XCirculateSubwindowsUp(dpy, Scr->Root); 3306 break; 3307 3308 case F_CIRCLEDOWN: 3309 XCirculateSubwindowsDown(dpy, Scr->Root); 3310 break; 3311 3312 case F_EXEC: 3313 PopDownMenu(); 3314 if (!Scr->NoGrabServer) { 3315 XUngrabServer (dpy); 3316 XSync (dpy, 0); 3317 } 3318 XUngrabPointer (dpy, CurrentTime); 3319 XSync (dpy, 0); 3320 Execute(action); 3321 break; 3322 3323 case F_UNFOCUS: 3324 FocusOnRoot(); 3325 break; 3326 3327 case F_CUT: 3328 strcpy(tmp, action); 3329 strcat(tmp, "\n"); 3330 XStoreBytes(dpy, tmp, strlen(tmp)); 3331 break; 3332 3333 case F_CUTFILE: 3334 ptr = XFetchBytes(dpy, &count); 3335 if (ptr) { 3336 if (sscanf (ptr, "%s", tmp) == 1) { 3337 XFree (ptr); 3338 ptr = ExpandFilename(tmp); 3339 if (ptr) { 3340#ifdef VMS 3341 fd = open (ptr, O_RDONLY, 0); 3342#else 3343 fd = open (ptr, 0); 3344#endif 3345 if (fd >= 0) { 3346 count = read (fd, buff, MAX_FILE_SIZE - 1); 3347 if (count > 0) XStoreBytes (dpy, buff, count); 3348 close(fd); 3349 } else { 3350 fprintf (stderr, 3351 "%s: unable to open cut file \"%s\"\n", 3352 ProgramName, tmp); 3353 } 3354 if (ptr != tmp) free (ptr); 3355 } 3356 } else { 3357 XFree(ptr); 3358 } 3359 } else { 3360 fprintf(stderr, "%s: cut buffer is empty\n", ProgramName); 3361 } 3362 break; 3363 3364 case F_WARPTOSCREEN: 3365 { 3366 if (strcmp (action, WARPSCREEN_NEXT) == 0) { 3367 WarpToScreen (Scr->screen + 1, 1); 3368 } else if (strcmp (action, WARPSCREEN_PREV) == 0) { 3369 WarpToScreen (Scr->screen - 1, -1); 3370 } else if (strcmp (action, WARPSCREEN_BACK) == 0) { 3371 WarpToScreen (PreviousScreen, 0); 3372 } else { 3373 WarpToScreen (atoi (action), 0); 3374 } 3375 } 3376 break; 3377 3378 case F_COLORMAP: 3379 { 3380 if (strcmp (action, COLORMAP_NEXT) == 0) { 3381 BumpWindowColormap (tmp_win, 1); 3382 } else if (strcmp (action, COLORMAP_PREV) == 0) { 3383 BumpWindowColormap (tmp_win, -1); 3384 } else { 3385 BumpWindowColormap (tmp_win, 0); 3386 } 3387 } 3388 break; 3389 3390 case F_WARPTO: 3391 { 3392 register TwmWindow *tw; 3393 int len; 3394 3395 len = strlen(action); 3396 3397#ifdef WARPTO_FROM_ICONMGR 3398 if (len == 0 && tmp_win && tmp_win->iconmgr) 3399 { 3400 printf ("curren iconmgr entry: %s", tmp_win->iconmgr->Current); 3401 } 3402#endif /* #ifdef WARPTO_FROM_ICONMGR */ 3403 for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) { 3404 if (!strncmp(action, tw->full_name, len)) break; 3405 if (match (action, tw->full_name)) break; 3406 } 3407 if (!tw) { 3408 for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) { 3409 if (!strncmp(action, tw->class.res_name, len)) break; 3410 if (match (action, tw->class.res_name)) break; 3411 } 3412 if (!tw) { 3413 for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) { 3414 if (!strncmp(action, tw->class.res_class, len)) break; 3415 if (match (action, tw->class.res_class)) break; 3416 } 3417 } 3418 } 3419 3420 if (tw) { 3421 if (Scr->WarpUnmapped || tw->mapped) { 3422 if (!tw->mapped) DeIconify (tw); 3423 WarpToWindow (tw, Scr->RaiseOnWarp); 3424 } 3425 } else { 3426 XBell (dpy, 0); 3427 } 3428 } 3429 break; 3430 3431 case F_WARPTOICONMGR: 3432 { 3433 TwmWindow *tw; 3434 int len; 3435 Window raisewin = None, iconwin = None; 3436 3437 len = strlen(action); 3438 if (len == 0) { 3439 if (tmp_win && tmp_win->iconmanagerlist) { 3440 raisewin = tmp_win->iconmanagerlist->iconmgr->twm_win->frame; 3441 iconwin = tmp_win->iconmanagerlist->icon; 3442 } else if (Scr->iconmgr->active) { 3443 raisewin = Scr->iconmgr->twm_win->frame; 3444 iconwin = Scr->iconmgr->active->w; 3445 } 3446 } else { 3447 for (tw = Scr->FirstWindow; tw != NULL; tw = tw->next) { 3448 if (strncmp (action, tw->icon_name, len) == 0) { 3449 if (tw->iconmanagerlist && 3450 tw->iconmanagerlist->iconmgr->twm_win->mapped) { 3451 raisewin = tw->iconmanagerlist->iconmgr->twm_win->frame; 3452 break; 3453 } 3454 } 3455 } 3456 } 3457 3458 if (raisewin) { 3459 RaiseFrame(raisewin); 3460 XWarpPointer (dpy, None, iconwin, 0,0,0,0, 5, 5); 3461 } else { 3462 XBell (dpy, 0); 3463 } 3464 } 3465 break; 3466 3467 case F_RING: /* Taken from vtwm version 5.3 */ 3468 if (DeferExecution (context, func, Scr->SelectCursor)) return TRUE; 3469 if ( tmp_win->ring.next || tmp_win->ring.prev ) { 3470 /* It's in the ring, let's take it out. */ 3471 TwmWindow *prev = tmp_win->ring.prev, *next = tmp_win->ring.next; 3472 3473 /* 3474 * 1. Unlink window 3475 * 2. If window was only thing in ring, null out ring 3476 * 3. If window was ring leader, set to next (or null) 3477 */ 3478 if (prev) prev->ring.next = next; 3479 if (next) next->ring.prev = prev; 3480 if (Scr->Ring == tmp_win) 3481 Scr->Ring = (next != tmp_win ? next : (TwmWindow *) NULL); 3482 3483 if (!Scr->Ring || Scr->RingLeader == tmp_win) 3484 Scr->RingLeader = Scr->Ring; 3485 tmp_win->ring.next = tmp_win->ring.prev = NULL; 3486 } else { 3487 /* Not in the ring, so put it in. */ 3488 if (Scr->Ring) { 3489 tmp_win->ring.next = Scr->Ring->ring.next; 3490 if (Scr->Ring->ring.next->ring.prev) 3491 Scr->Ring->ring.next->ring.prev = tmp_win; 3492 Scr->Ring->ring.next = tmp_win; 3493 tmp_win->ring.prev = Scr->Ring; 3494 } else { 3495 tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win; 3496 } 3497 } 3498 /*tmp_win->ring.cursor_valid = False;*/ 3499 break; 3500 3501 case F_WARPRING: 3502 switch (((char *)action)[0]) { 3503 case 'n': 3504 WarpAlongRing (&eventp->xbutton, True); 3505 break; 3506 case 'p': 3507 WarpAlongRing (&eventp->xbutton, False); 3508 break; 3509 default: 3510 XBell (dpy, 0); 3511 break; 3512 } 3513 break; 3514 3515 case F_FILE: 3516 action = ExpandFilename(action); 3517#ifdef VMS 3518 fd = open (action, O_RDONLY, 0); 3519#else 3520 fd = open(action, 0); 3521#endif 3522 if (fd >= 0) 3523 { 3524 count = read(fd, buff, MAX_FILE_SIZE - 1); 3525 if (count > 0) 3526 XStoreBytes(dpy, buff, count); 3527 3528 close(fd); 3529 } 3530 else 3531 { 3532 fprintf (stderr, "%s: unable to open file \"%s\"\n", 3533 ProgramName, (char *)action); 3534 } 3535 break; 3536 3537 case F_REFRESH: 3538 { 3539 XSetWindowAttributes attributes; 3540 unsigned long valuemask; 3541 3542 valuemask = (CWBackPixel | CWBackingStore | CWSaveUnder); 3543 attributes.background_pixel = Scr->Black; 3544 attributes.backing_store = NotUseful; 3545 attributes.save_under = False; 3546 w = XCreateWindow (dpy, Scr->Root, 0, 0, 3547 (unsigned int) Scr->rootw, 3548 (unsigned int) Scr->rooth, 3549 (unsigned int) 0, 3550 CopyFromParent, (unsigned int) CopyFromParent, 3551 (Visual *) CopyFromParent, valuemask, 3552 &attributes); 3553 XMapWindow (dpy, w); 3554 XDestroyWindow (dpy, w); 3555 XFlush (dpy); 3556 } 3557 break; 3558 3559 case F_OCCUPY: 3560 if (DeferExecution(context, func, Scr->SelectCursor)) 3561 return TRUE; 3562 Occupy (tmp_win); 3563 break; 3564 3565 case F_OCCUPYALL: 3566 if (DeferExecution(context, func, Scr->SelectCursor)) 3567 return TRUE; 3568 OccupyAll (tmp_win); 3569 break; 3570 3571 case F_GOTOWORKSPACE: 3572 GotoWorkSpaceByName (Scr->currentvs, action); 3573 break; 3574 3575 case F_PREVWORKSPACE: 3576 GotoPrevWorkSpace (Scr->currentvs); 3577 break; 3578 3579 case F_NEXTWORKSPACE: 3580 GotoNextWorkSpace (Scr->currentvs); 3581 break; 3582 3583 case F_RIGHTWORKSPACE: 3584 GotoRightWorkSpace (Scr->currentvs); 3585 break; 3586 3587 case F_LEFTWORKSPACE: 3588 GotoLeftWorkSpace (Scr->currentvs); 3589 break; 3590 3591 case F_UPWORKSPACE: 3592 GotoUpWorkSpace (Scr->currentvs); 3593 break; 3594 3595 case F_DOWNWORKSPACE: 3596 GotoDownWorkSpace (Scr->currentvs); 3597 break; 3598 3599 case F_MENU: 3600 if (action && ! strncmp (action, "WGOTO : ", 8)) { 3601 GotoWorkSpaceByName (/* XXXXX */ Scr->currentvs, 3602 ((char *)action) + 8); 3603 } 3604 else { 3605 MenuItem *item; 3606 3607 item = ActiveItem; 3608 while (item && item->sub) { 3609 if (!item->sub->defaultitem) break; 3610 if (item->sub->defaultitem->func != F_MENU) break; 3611 item = item->sub->defaultitem; 3612 } 3613 if (item && item->sub && item->sub->defaultitem) { 3614 ExecuteFunction (item->sub->defaultitem->func, 3615 item->sub->defaultitem->action, 3616 w, tmp_win, eventp, context, pulldown); 3617 } 3618 } 3619 break; 3620 3621 case F_WINREFRESH: 3622 if (DeferExecution(context, func, Scr->SelectCursor)) 3623 return TRUE; 3624 3625 if (context == C_ICON && tmp_win->icon && tmp_win->icon->w) 3626 w = XCreateSimpleWindow(dpy, tmp_win->icon->w, 3627 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black); 3628 else 3629 w = XCreateSimpleWindow(dpy, tmp_win->frame, 3630 0, 0, 9999, 9999, 0, Scr->Black, Scr->Black); 3631 3632 XMapWindow(dpy, w); 3633 XDestroyWindow(dpy, w); 3634 XFlush(dpy); 3635 break; 3636 3637 case F_ADOPTWINDOW: 3638 adoptWindow (); 3639 break; 3640 3641 case F_TRACE: 3642 DebugTrace (action); 3643 break; 3644 3645 case F_CHANGESIZE: 3646 ChangeSize (action, tmp_win); 3647 break; 3648 3649 case F_QUIT: 3650 Done(0); 3651 break; 3652 } 3653 3654 if (ButtonPressed == -1) XUngrabPointer(dpy, CurrentTime); 3655 return do_next_action; 3656} 3657 3658 3659 3660/*********************************************************************** 3661 * 3662 * Procedure: 3663 * DeferExecution - defer the execution of a function to the 3664 * next button press if the context is C_ROOT 3665 * 3666 * Inputs: 3667 * context - the context in which the mouse button was pressed 3668 * func - the function to defer 3669 * cursor - the cursor to display while waiting 3670 * 3671 *********************************************************************** 3672 */ 3673 3674int DeferExecution(int context, int func, Cursor cursor) 3675{ 3676 if ((context == C_ROOT) || (context == C_ALTERNATE)) 3677 { 3678 LastCursor = cursor; 3679 if (func == F_ADOPTWINDOW) { 3680 XGrabPointer(dpy, Scr->Root, True, 3681 ButtonPressMask | ButtonReleaseMask, 3682 GrabModeAsync, GrabModeAsync, 3683 None, cursor, CurrentTime); 3684 } else { 3685 XGrabPointer(dpy, Scr->Root, True, 3686 ButtonPressMask | ButtonReleaseMask, 3687 GrabModeAsync, GrabModeAsync, 3688 Scr->Root, cursor, CurrentTime); 3689 } 3690 RootFunction = func; 3691 3692 return (TRUE); 3693 } 3694 3695 return (FALSE); 3696} 3697 3698 3699 3700/*********************************************************************** 3701 * 3702 * Procedure: 3703 * ReGrab - regrab the pointer with the LastCursor; 3704 * 3705 *********************************************************************** 3706 */ 3707 3708void ReGrab(void) 3709{ 3710 XGrabPointer(dpy, Scr->Root, True, 3711 ButtonPressMask | ButtonReleaseMask, 3712 GrabModeAsync, GrabModeAsync, 3713 Scr->Root, LastCursor, CurrentTime); 3714} 3715 3716 3717 3718/*********************************************************************** 3719 * 3720 * Procedure: 3721 * NeedToDefer - checks each function in the list to see if it 3722 * is one that needs to be defered. 3723 * 3724 * Inputs: 3725 * root - the menu root to check 3726 * 3727 *********************************************************************** 3728 */ 3729 3730int NeedToDefer(MenuRoot *root) 3731{ 3732 MenuItem *mitem; 3733 3734 for (mitem = root->first; mitem != NULL; mitem = mitem->next) 3735 { 3736 switch (mitem->func) 3737 { 3738 case F_IDENTIFY: 3739 case F_RESIZE: 3740 case F_MOVE: 3741 case F_FORCEMOVE: 3742 case F_DEICONIFY: 3743 case F_ICONIFY: 3744 case F_RAISELOWER: 3745 case F_RAISE: 3746 case F_LOWER: 3747 case F_FOCUS: 3748 case F_DESTROY: 3749 case F_WINREFRESH: 3750 case F_ZOOM: 3751 case F_FULLZOOM: 3752 case F_HORIZOOM: 3753 case F_RIGHTZOOM: 3754 case F_LEFTZOOM: 3755 case F_TOPZOOM: 3756 case F_BOTTOMZOOM: 3757 case F_SQUEEZE: 3758 case F_AUTORAISE: 3759 case F_AUTOLOWER: 3760 return TRUE; 3761 } 3762 } 3763 return FALSE; 3764} 3765 3766 3767 3768/*********************************************************************** 3769 * 3770 * Procedure: 3771 * Execute - execute the string by /bin/sh 3772 * 3773 * Inputs: 3774 * s - the string containing the command 3775 * 3776 *********************************************************************** 3777 */ 3778 3779void Execute(char *s) 3780{ 3781#ifdef VMS 3782 createProcess(s); 3783#else 3784 static char buf[256]; 3785 char *ds = DisplayString (dpy); 3786 char *colon, *dot1; 3787 char oldDisplay[256]; 3788 char *doisplay; 3789 int restorevar = 0; 3790 Bool replace; 3791 char *subs, *name, *news; 3792 int len; 3793 3794 oldDisplay[0] = '\0'; 3795 doisplay=getenv("DISPLAY"); 3796 if (doisplay) 3797 strcpy (oldDisplay, doisplay); 3798 3799 /* 3800 * Build a display string using the current screen number, so that 3801 * X programs which get fired up from a menu come up on the screen 3802 * that they were invoked from, unless specifically overridden on 3803 * their command line. 3804 */ 3805 colon = strrchr (ds, ':'); 3806 if (colon) { /* if host[:]:dpy */ 3807 strcpy (buf, "DISPLAY="); 3808 strcat (buf, ds); 3809 colon = buf + 8 + (colon - ds); /* use version in buf */ 3810 dot1 = strchr (colon, '.'); /* first period after colon */ 3811 if (!dot1) dot1 = colon + strlen (colon); /* if not there, append */ 3812 (void) sprintf (dot1, ".%d", Scr->screen); 3813 putenv (buf); 3814 restorevar = 1; 3815 } 3816 replace = False; 3817 subs = strstr (s, "$currentworkspace"); 3818 name = GetCurrentWorkSpaceName (Scr->currentvs); 3819 if (subs && name) { 3820 len = strlen (s) - strlen ("$currentworkspace") + strlen (name); 3821 news = (char*) malloc (len + 1); 3822 *subs = '\0'; 3823 strcpy (news, s); 3824 *subs = '$'; 3825 strcat (news, name); 3826 subs += strlen ("$currentworkspace"); 3827 strcat (news, subs); 3828 s = news; 3829 replace = True; 3830 } 3831 subs = strstr (s, "$redirect"); 3832 if (subs) { 3833 if (captive) { 3834 name = (char*) malloc (21 + strlen (captivename) + 1); 3835 sprintf (name, "-xrm 'ctwm.redirect:%s'", captivename); 3836 } else { 3837 name = (char*) malloc (1); 3838 *name = '\0'; 3839 } 3840 len = strlen (s) - strlen ("$redirect") + strlen (name); 3841 news = (char*) malloc (len + 1); 3842 *subs = '\0'; 3843 strcpy (news, s); 3844 *subs = '$'; 3845 strcat (news, name); 3846 subs += strlen ("$redirect"); 3847 strcat (news, subs); 3848 s = news; 3849 free (name); 3850 replace = True; 3851 } 3852#ifdef USE_SIGNALS 3853 { 3854 SigProc sig; 3855 3856 sig = signal (SIGALRM, SIG_IGN); 3857 (void) system (s); 3858 signal (SIGALRM, sig); 3859 } 3860#else /* USE_SIGNALS */ 3861 (void) system (s); 3862#endif /* USE_SIGNALS */ 3863 3864 if (restorevar) { /* why bother? */ 3865 (void) sprintf (buf, "DISPLAY=%s", oldDisplay); 3866 putenv (buf); 3867 } 3868 if (replace) free (s); 3869#endif 3870} 3871 3872 3873 3874Window lowerontop = -1; 3875 3876void PlaceTransients (TwmWindow *tmp_win, int where) 3877{ 3878 int sp, sc; 3879 TwmWindow *t; 3880 XWindowChanges xwc; 3881 xwc.stack_mode = where; 3882 3883 sp = tmp_win->frame_width * tmp_win->frame_height; 3884 for (t = Scr->FirstWindow; t != NULL; t = t->next) { 3885 if (t != tmp_win && 3886 ((t->transient && t->transientfor == tmp_win->w) || 3887 t->group == tmp_win->w)) { 3888 if (t->frame) { 3889 sc = t->frame_width * t->frame_height; 3890 if (sc < ((sp * Scr->TransientOnTop) / 100)) { 3891 xwc.sibling = tmp_win->frame; 3892 XConfigureWindow(dpy, t->frame, CWSibling | CWStackMode, &xwc); 3893 if (lowerontop == t->frame) { 3894 lowerontop = (Window)-1; 3895 } 3896 } 3897 } 3898 } 3899 } 3900} 3901 3902#include <assert.h> 3903 3904void PlaceOntop (int ontop, int where) 3905{ 3906 TwmWindow *t; 3907 XWindowChanges xwc; 3908 xwc.stack_mode = where; 3909 3910 lowerontop = (Window)-1; 3911 3912 for (t = Scr->FirstWindow; t != NULL; t = t->next) { 3913 if (t->ontoppriority > ontop) { 3914 XConfigureWindow(dpy, t->frame, CWStackMode, &xwc); 3915 PlaceTransients(t, Above); 3916 if (lowerontop == (Window)-1) { 3917 lowerontop = t->frame; 3918 } 3919 } 3920 } 3921} 3922 3923void MapRaised (TwmWindow *tmp_win) 3924{ 3925 XMapWindow(dpy, tmp_win->frame); 3926 RaiseWindow(tmp_win); 3927} 3928 3929void RaiseWindow (TwmWindow *tmp_win) 3930{ 3931 XWindowChanges xwc; 3932 int xwcm; 3933 3934 if (tmp_win->ontoppriority == ONTOP_MAX) { 3935 XRaiseWindow(dpy, tmp_win->frame); 3936 if (lowerontop == (Window)-1) { 3937 lowerontop = tmp_win->frame; 3938 } else if (lowerontop == tmp_win->frame) { 3939 lowerontop = (Window)-1; 3940 } 3941 } else { 3942 if (lowerontop == (Window)-1) { 3943 PlaceOntop(tmp_win->ontoppriority, Above); 3944 } 3945 xwcm = CWStackMode; 3946 if (lowerontop != (Window)-1) { 3947 xwc.stack_mode = Below; 3948 xwc.sibling = lowerontop; 3949 xwcm |= CWSibling; 3950 } else { 3951 xwc.stack_mode = Above; 3952 } 3953 XConfigureWindow(dpy, tmp_win->frame, xwcm, &xwc); 3954 } 3955 PlaceTransients(tmp_win, Above); 3956} 3957 3958void RaiseLower (TwmWindow *tmp_win) 3959{ 3960 XWindowChanges xwc; 3961 3962 PlaceOntop(tmp_win->ontoppriority, Below); 3963 PlaceTransients(tmp_win, Below); 3964 lowerontop = (Window)-1; 3965 xwc.stack_mode = Opposite; 3966 XConfigureWindow(dpy, tmp_win->frame, CWStackMode, &xwc); 3967 PlaceOntop(tmp_win->ontoppriority, Above); 3968 PlaceTransients(tmp_win, Above); 3969} 3970 3971void RaiseLowerFrame (Window frame, int ontop) 3972{ 3973 XWindowChanges xwc; 3974 3975 PlaceOntop(ontop, Below); 3976 lowerontop = (Window)-1; 3977 xwc.stack_mode = Opposite; 3978 XConfigureWindow(dpy, frame, CWStackMode, &xwc); 3979 PlaceOntop(ontop, Above); 3980} 3981 3982void LowerWindow (TwmWindow *tmp_win) 3983{ 3984 XLowerWindow(dpy, tmp_win->frame); 3985 if (tmp_win->frame == lowerontop) { 3986 lowerontop = (Window)-1; 3987 } 3988 PlaceTransients(tmp_win, Above); 3989} 3990 3991void RaiseFrame (Window frame) 3992{ 3993 TwmWindow *tmp_win; 3994 3995 tmp_win = GetTwmWindow(frame); 3996 3997 if (tmp_win != NULL) { 3998 RaiseWindow(tmp_win); 3999 } else { 4000 XRaiseWindow(dpy, frame); 4001 } 4002} 4003 4004/*********************************************************************** 4005 * 4006 * Procedure: 4007 * FocusOnRoot - put input focus on the root window 4008 * 4009 *********************************************************************** 4010 */ 4011 4012void FocusOnRoot(void) 4013{ 4014 SetFocus ((TwmWindow *) NULL, LastTimestamp()); 4015 InstallColormaps(0, &Scr->RootColormaps); 4016 if (! Scr->ClickToFocus) Scr->FocusRoot = TRUE; 4017} 4018 4019static void ReMapOne(TwmWindow *t, TwmWindow *leader) 4020{ 4021 if (t->icon_on) 4022 Zoom(t->icon->w, t->frame); 4023 else if (leader->icon) 4024 Zoom(leader->icon->w, t->frame); 4025 4026 if (!t->squeezed) 4027 XMapWindow(dpy, t->w); 4028 t->mapped = TRUE; 4029 if (Scr->Root != Scr->CaptiveRoot) /* XXX dubious test */ 4030 XReparentWindow (dpy, t->frame, Scr->Root, t->frame_x, t->frame_y); 4031 if (Scr->NoRaiseDeicon) 4032 XMapWindow(dpy, t->frame); 4033 else 4034 MapRaised(t); 4035 SetMapStateProp(t, NormalState); 4036 4037 if (t->icon && t->icon->w) { 4038 XUnmapWindow(dpy, t->icon->w); 4039 IconDown(t); 4040 if (Scr->ShrinkIconTitles) 4041 t->icon->title_shrunk = True; 4042 } 4043 if (t->iconmanagerlist) { 4044 WList *wl; 4045 4046 for (wl = t->iconmanagerlist; wl != NULL; wl = wl->nextv) 4047 XUnmapWindow(dpy, wl->icon); 4048 } 4049 t->isicon = FALSE; 4050 t->icon_on = FALSE; 4051 WMapDeIconify(t); 4052} 4053 4054static void ReMapTransients(TwmWindow *tmp_win) 4055{ 4056 TwmWindow *t; 4057 4058 /* find t such that it is a transient or group member window */ 4059 for (t = Scr->FirstWindow; t != NULL; t = t->next) { 4060 if (t != tmp_win && 4061 ((t->transient && t->transientfor == tmp_win->w) || 4062 (t->group == tmp_win->w && t->isicon))) { 4063 ReMapOne(t, tmp_win); 4064 } 4065 } 4066} 4067 4068void DeIconify(TwmWindow *tmp_win) 4069{ 4070 TwmWindow *t = tmp_win; 4071 int isicon = FALSE; 4072 4073 /* de-iconify the main window */ 4074 if (Scr->WindowMask) 4075 XRaiseWindow (dpy, Scr->WindowMask); 4076 if (tmp_win->isicon) 4077 { 4078 isicon = TRUE; 4079 if (tmp_win->icon_on && tmp_win->icon && tmp_win->icon->w) 4080 Zoom(tmp_win->icon->w, tmp_win->frame); 4081 else if (tmp_win->group != (Window) 0) 4082 { 4083 t = GetTwmWindow(tmp_win->group); 4084 if (t && t->icon_on && t->icon && t->icon->w) 4085 { 4086 Zoom(t->icon->w, tmp_win->frame); 4087 } 4088 } 4089 } 4090 4091 ReMapOne(tmp_win, t); 4092 4093 if (isicon && 4094 (Scr->WarpCursor || 4095 LookInList(Scr->WarpCursorL, tmp_win->full_name, &tmp_win->class))) 4096 WarpToWindow (tmp_win, 0); 4097 4098 /* now de-iconify and window group transients */ 4099 ReMapTransients(tmp_win); 4100 4101 if (! Scr->WindowMask && Scr->DeIconifyFunction.func != 0) { 4102 char *action; 4103 XEvent event; 4104 4105 action = Scr->DeIconifyFunction.item ? 4106 Scr->DeIconifyFunction.item->action : NULL; 4107 ExecuteFunction (Scr->DeIconifyFunction.func, action, 4108 (Window) 0, tmp_win, &event, C_ROOT, FALSE); 4109 } 4110 XSync (dpy, 0); 4111} 4112 4113 4114static void UnmapTransients(TwmWindow *tmp_win, int iconify, unsigned long eventMask) 4115{ 4116 TwmWindow *t; 4117 4118 for (t = Scr->FirstWindow; t != NULL; t = t->next) { 4119 if (t != tmp_win && 4120 ((t->transient && t->transientfor == tmp_win->w) || 4121 t->group == tmp_win->w)) { 4122 if (iconify) { 4123 if (t->icon_on) 4124 Zoom(t->icon->w, tmp_win->icon->w); 4125 else if (tmp_win->icon) 4126 Zoom(t->frame, tmp_win->icon->w); 4127 } 4128 4129 /* 4130 * Prevent the receipt of an UnmapNotify, since that would 4131 * cause a transition to the Withdrawn state. 4132 */ 4133 t->mapped = FALSE; 4134 XSelectInput(dpy, t->w, eventMask & ~StructureNotifyMask); 4135 XUnmapWindow(dpy, t->w); 4136 XUnmapWindow(dpy, t->frame); 4137 XSelectInput(dpy, t->w, eventMask); 4138 if (t->icon && t->icon->w) XUnmapWindow(dpy, t->icon->w); 4139 SetMapStateProp(t, IconicState); 4140 if (t == Scr->Focus) { 4141 SetFocus ((TwmWindow *) NULL, LastTimestamp()); 4142 if (! Scr->ClickToFocus) Scr->FocusRoot = TRUE; 4143 } 4144 if (t->iconmanagerlist) 4145 XMapWindow(dpy, t->iconmanagerlist->icon); 4146 t->isicon = TRUE; 4147 t->icon_on = FALSE; 4148 WMapIconify (t); 4149 } 4150 } 4151} 4152 4153void Iconify(TwmWindow *tmp_win, int def_x, int def_y) 4154{ 4155 TwmWindow *t; 4156 int iconify; 4157 XWindowAttributes winattrs; 4158 unsigned long eventMask; 4159 WList *wl; 4160 Window leader = (Window)-1; 4161 Window blanket = (Window)-1; 4162 4163 iconify = (!tmp_win->iconify_by_unmapping); 4164 t = (TwmWindow*) 0; 4165 if (tmp_win->transient) { 4166 leader = tmp_win->transientfor; 4167 t = GetTwmWindow(leader); 4168 } 4169 else 4170 if ((leader = tmp_win->group) != 0 && leader != tmp_win->w) { 4171 t = GetTwmWindow(leader); 4172 } 4173 if (t && t->icon_on) iconify = False; 4174 if (iconify) 4175 { 4176 if (!tmp_win->icon || !tmp_win->icon->w) 4177 CreateIconWindow(tmp_win, def_x, def_y); 4178 else 4179 IconUp(tmp_win); 4180 if (visible (tmp_win)) { 4181 if (Scr->WindowMask) { 4182 XRaiseWindow (dpy, Scr->WindowMask); 4183 XMapWindow(dpy, tmp_win->icon->w); 4184 } 4185 else 4186 XMapRaised(dpy, tmp_win->icon->w); 4187 } 4188 } 4189 if (tmp_win->iconmanagerlist) { 4190 for (wl = tmp_win->iconmanagerlist; wl != NULL; wl = wl->nextv) { 4191 XMapWindow(dpy, wl->icon); 4192 } 4193 } 4194 4195 XGetWindowAttributes(dpy, tmp_win->w, &winattrs); 4196 eventMask = winattrs.your_event_mask; 4197 4198 /* iconify transients and window group first */ 4199 UnmapTransients(tmp_win, iconify, eventMask); 4200 4201 if (iconify) Zoom(tmp_win->frame, tmp_win->icon->w); 4202 4203 /* 4204 * Prevent the receipt of an UnmapNotify, since that would 4205 * cause a transition to the Withdrawn state. 4206 */ 4207 tmp_win->mapped = FALSE; 4208 4209 if ((Scr->IconifyStyle != ICONIFY_NORMAL) && !Scr->WindowMask) { 4210 XSetWindowAttributes attr; 4211 XGetWindowAttributes(dpy, tmp_win->frame, &winattrs); 4212 attr.backing_store = NotUseful; 4213 attr.save_under = False; 4214 blanket = XCreateWindow (dpy, Scr->Root, winattrs.x, winattrs.y, 4215 winattrs.width, winattrs.height, (unsigned int) 0, 4216 CopyFromParent, (unsigned int) CopyFromParent, 4217 (Visual *) CopyFromParent, CWBackingStore | CWSaveUnder, &attr); 4218 XMapWindow (dpy, blanket); 4219 } 4220 XSelectInput(dpy, tmp_win->w, eventMask & ~StructureNotifyMask); 4221 XUnmapWindow(dpy, tmp_win->w); 4222 XUnmapWindow(dpy, tmp_win->frame); 4223 XSelectInput(dpy, tmp_win->w, eventMask); 4224 SetMapStateProp(tmp_win, IconicState); 4225 4226 if ((Scr->IconifyStyle != ICONIFY_NORMAL) && !Scr->WindowMask) { 4227 switch (Scr->IconifyStyle) { 4228 case ICONIFY_MOSAIC: MosaicFade (tmp_win, blanket); break; 4229 case ICONIFY_ZOOMIN: ZoomInWindow (tmp_win, blanket); break; 4230 case ICONIFY_ZOOMOUT: ZoomOutWindow (tmp_win, blanket); break; 4231 case ICONIFY_SWEEP: SweepWindow (tmp_win, blanket); break; 4232 } 4233 XDestroyWindow (dpy, blanket); 4234 } 4235 if (tmp_win == Scr->Focus) { 4236 SetFocus ((TwmWindow *) NULL, LastTimestamp()); 4237 if (! Scr->ClickToFocus) Scr->FocusRoot = TRUE; 4238 } 4239 tmp_win->isicon = TRUE; 4240 tmp_win->icon_on = iconify ? TRUE : FALSE; 4241 WMapIconify (tmp_win); 4242 if (! Scr->WindowMask && Scr->IconifyFunction.func != 0) { 4243 char *action; 4244 XEvent event; 4245 4246 action = Scr->IconifyFunction.item ? Scr->IconifyFunction.item->action : NULL; 4247 ExecuteFunction (Scr->IconifyFunction.func, action, 4248 (Window) 0, tmp_win, &event, C_ROOT, FALSE); 4249 } 4250 XSync (dpy, 0); 4251} 4252 4253void AutoSqueeze (TwmWindow *tmp_win) 4254{ 4255 if (tmp_win->iconmgr) return; 4256 if (Scr->RaiseWhenAutoUnSqueeze && tmp_win->squeezed) XRaiseWindow (dpy, tmp_win->frame); 4257 Squeeze (tmp_win); 4258} 4259 4260void Squeeze (TwmWindow *tmp_win) 4261{ 4262 long fx, fy, savex, savey; 4263 int neww, newh, south; 4264 int grav = ((tmp_win->hints.flags & PWinGravity) 4265 ? tmp_win->hints.win_gravity : NorthWestGravity); 4266 XWindowAttributes winattrs; 4267 unsigned long eventMask; 4268#ifdef GNOME 4269 unsigned char *prop; 4270 unsigned long nitems, bytesafter; 4271 Atom actual_type; 4272 int actual_format; 4273 long gwkspc; 4274#endif /* GNOME */ 4275 if (tmp_win->squeezed) { 4276 tmp_win->squeezed = False; 4277#ifdef GNOME 4278 XGetWindowAttributes (dpy, tmp_win->w, &winattrs); 4279 eventMask = winattrs.your_event_mask; 4280 XSelectInput (dpy, tmp_win->w, eventMask & ~PropertyChangeMask); 4281 if (XGetWindowProperty (dpy, tmp_win->w, _XA_WIN_STATE, 0L, 32, False, 4282 XA_CARDINAL, &actual_type, &actual_format, 4283 &nitems, &bytesafter, &prop) 4284 != Success || nitems == 0) { 4285 gwkspc = 0; 4286 } else { 4287 gwkspc = (int)*prop; 4288 XFree ((char *)prop); 4289 } 4290 gwkspc &= ~WIN_STATE_SHADED; 4291 XChangeProperty (dpy, tmp_win->w, _XA_WIN_STATE, XA_CARDINAL, 32, 4292 PropModeReplace, (unsigned char *)&gwkspc, 1); 4293 XSelectInput(dpy, tmp_win->w, eventMask); 4294#endif /* GNOME */ 4295 if (!tmp_win->isicon) XMapWindow (dpy, tmp_win->w); 4296 SetupWindow (tmp_win, tmp_win->actual_frame_x, tmp_win->actual_frame_y, 4297 tmp_win->actual_frame_width, tmp_win->actual_frame_height, -1); 4298 ReMapTransients(tmp_win); 4299 return; 4300 } 4301 4302 newh = tmp_win->title_height + 2 * tmp_win->frame_bw3D; 4303 if (newh < 3) { XBell (dpy, 0); return; } 4304 switch (grav) { 4305 case SouthWestGravity : 4306 case SouthGravity : 4307 case SouthEastGravity : 4308 south = True; break; 4309 default : 4310 south = False; break; 4311 } 4312 if (tmp_win->title_height && !tmp_win->AlwaysSqueezeToGravity) south = False; 4313 4314 tmp_win->squeezed = True; 4315 tmp_win->actual_frame_width = tmp_win->frame_width; 4316 tmp_win->actual_frame_height = tmp_win->frame_height; 4317 savex = fx = tmp_win->frame_x; 4318 savey = fy = tmp_win->frame_y; 4319 neww = tmp_win->actual_frame_width; 4320 if (south) fy += tmp_win->frame_height - newh; 4321 if (tmp_win->squeeze_info) { 4322 fx += tmp_win->title_x - tmp_win->frame_bw3D; 4323 neww = tmp_win->title_width + 2 * (tmp_win->frame_bw + tmp_win->frame_bw3D); 4324 } 4325 XGetWindowAttributes(dpy, tmp_win->w, &winattrs); 4326 eventMask = winattrs.your_event_mask; 4327#ifdef GNOME 4328 XSelectInput (dpy, tmp_win->w, eventMask & ~(StructureNotifyMask | PropertyChangeMask)); 4329 if (XGetWindowProperty (dpy, tmp_win->w, _XA_WIN_STATE, 0L, 32, False, 4330 XA_CARDINAL, &actual_type, &actual_format, &nitems, 4331 &bytesafter, &prop) 4332 != Success || nitems == 0) { 4333 gwkspc = 0; 4334 } else { 4335 gwkspc = (int)*prop; 4336 XFree ((char *)prop); 4337 } 4338 gwkspc |= WIN_STATE_SHADED; 4339 XChangeProperty (dpy, tmp_win->w, _XA_WIN_STATE, XA_CARDINAL, 32, 4340 PropModeReplace, (unsigned char *)&gwkspc, 1); 4341#else 4342 XSelectInput (dpy, tmp_win->w, eventMask & ~StructureNotifyMask); 4343#endif /* GNOME */ 4344 XUnmapWindow(dpy, tmp_win->w); 4345 XSelectInput(dpy, tmp_win->w, eventMask); 4346 4347 if (fx + neww >= Scr->rootw - Scr->BorderRight) 4348 fx = Scr->rootw - Scr->BorderRight - neww; 4349 if (fy + newh >= Scr->rooth - Scr->BorderBottom) 4350 fy = Scr->rooth - Scr->BorderBottom - newh; 4351 SetupWindow (tmp_win, fx, fy, neww, newh, -1); 4352 tmp_win->actual_frame_x = savex; 4353 tmp_win->actual_frame_y = savey; 4354 4355 /* Now make the group members disappear */ 4356 UnmapTransients(tmp_win, 0, eventMask); 4357} 4358 4359static void Identify (TwmWindow *t) 4360{ 4361 int i, n, twidth, width, height; 4362 int x, y; 4363 unsigned int wwidth, wheight, bw, depth; 4364 Window junk; 4365 int px, py, dummy; 4366 unsigned udummy; 4367 unsigned char *prop; 4368 unsigned long nitems, bytesafter; 4369 Atom actual_type; 4370 int actual_format; 4371 XRectangle inc_rect; 4372 XRectangle logical_rect; 4373 Bool first = True; 4374 4375 n = 0; 4376 (void) sprintf(Info[n++], "Twm version: %s", Version); 4377 (void) sprintf(Info[n], "Compile time options :"); 4378#ifdef XPM 4379 (void) strcat (Info[n], " XPM"); 4380 first = False; 4381#endif 4382#ifdef IMCONV 4383 if (!first) (void) strcat(Info[n], ", "); 4384 (void) strcat (Info[n], "IMCONV"); 4385 first = False; 4386#endif 4387#ifdef USEM4 4388 if (!first) (void) strcat(Info[n], ", "); 4389 (void) strcat (Info[n], "USEM4"); 4390 first = False; 4391#endif 4392#ifdef GNOME 4393 if (!first) (void) strcat(Info[n], ", "); 4394 (void) strcat (Info[n], "GNOME"); 4395 first = False; 4396#endif 4397#ifdef SOUNDS 4398 if (!first) (void) strcat(Info[n], ", "); 4399 (void) strcat (Info[n], "SOUNDS"); 4400 first = False; 4401#endif 4402#ifdef DEBUG 4403 if (!first) (void) strcat(Info[n], ", "); 4404 (void) strcat (Info[n], "debug"); 4405 first = False; 4406#endif 4407 if (!first) (void) strcat(Info[n], ", "); 4408 (void) strcat (Info[n], "I18N"); 4409 first = False; 4410 n++; 4411 Info[n++][0] = '\0'; 4412 4413 if (t) { 4414 XGetGeometry (dpy, t->w, &JunkRoot, &JunkX, &JunkY, 4415 &wwidth, &wheight, &bw, &depth); 4416 (void) XTranslateCoordinates (dpy, t->w, Scr->Root, 0, 0, 4417 &x, &y, &junk); 4418 (void) sprintf(Info[n++], "Name = \"%s\"", t->full_name); 4419 (void) sprintf(Info[n++], "Class.res_name = \"%s\"", t->class.res_name); 4420 (void) sprintf(Info[n++], "Class.res_class = \"%s\"", t->class.res_class); 4421 Info[n++][0] = '\0'; 4422 (void) sprintf(Info[n++], "Geometry/root (UL) = %dx%d+%d+%d (Inner: %dx%d+%d+%d)", 4423 wwidth + 2 * (bw + t->frame_bw3D), 4424 wheight + 2 * (bw + t->frame_bw3D) + t->title_height, 4425 x - (bw + t->frame_bw3D), 4426 y - (bw + t->frame_bw3D + t->title_height), 4427 wwidth, wheight, x, y); 4428 (void) sprintf(Info[n++], "Geometry/root (LR) = %dx%d-%d-%d (Inner: %dx%d-%d-%d)", 4429 wwidth + 2 * (bw + t->frame_bw3D), 4430 wheight + 2 * (bw + t->frame_bw3D) + t->title_height, 4431 Scr->rootw - (x + wwidth + bw + t->frame_bw3D), 4432 Scr->rooth - (y + wheight + bw + t->frame_bw3D), 4433 wwidth, wheight, 4434 Scr->rootw - (x + wwidth), Scr->rooth - (y + wheight)); 4435 (void) sprintf(Info[n++], "Border width = %d", bw); 4436 (void) sprintf(Info[n++], "3D border width = %d", t->frame_bw3D); 4437 (void) sprintf(Info[n++], "Depth = %d", depth); 4438 4439 if (XGetWindowProperty (dpy, t->w, _XA_WM_CLIENT_MACHINE, 0L, 64, False, 4440 XA_STRING, &actual_type, &actual_format, &nitems, 4441 &bytesafter, &prop) == Success) { 4442 if (nitems && prop) { 4443 (void) sprintf(Info[n++], "Client machine = %s", (char*)prop); 4444 XFree ((char *) prop); 4445 } 4446 } 4447 Info[n++][0] = '\0'; 4448 } 4449 4450 (void) sprintf(Info[n++], "Click to dismiss...."); 4451 4452 /* figure out the width and height of the info window */ 4453 height = n * (Scr->DefaultFont.height+2); 4454 width = 1; 4455 for (i = 0; i < n; i++) 4456 { 4457 XmbTextExtents(Scr->DefaultFont.font_set, Info[i], 4458 strlen(Info[i]), &inc_rect, &logical_rect); 4459 4460 twidth = logical_rect.width; 4461 if (twidth > width) 4462 width = twidth; 4463 } 4464 if (InfoLines) XUnmapWindow(dpy, Scr->InfoWindow); 4465 4466 width += 10; /* some padding */ 4467 height += 10; /* some padding */ 4468 if (XQueryPointer (dpy, Scr->Root, &JunkRoot, &JunkChild, 4469 &dummy, &dummy, &px, &py, &udummy)) { 4470 px -= (width / 2); 4471 py -= (height / 3); 4472 if (px + width + BW2 >= Scr->rootw) 4473 px = Scr->rootw - width - BW2; 4474 if (py + height + BW2 >= Scr->rooth) 4475 py = Scr->rooth - height - BW2; 4476 if (px < 0) px = 0; 4477 if (py < 0) py = 0; 4478 } else { 4479 px = py = 0; 4480 } 4481 XMoveResizeWindow(dpy, Scr->InfoWindow, px, py, width, height); 4482 XMapRaised(dpy, Scr->InfoWindow); 4483 InfoLines = n; 4484 InfoWidth = width; 4485 InfoHeight = height; 4486} 4487 4488 4489 4490 void SetMapStateProp(TwmWindow *tmp_win, int state) 4491{ 4492 unsigned long data[2]; /* "suggested" by ICCCM version 1 */ 4493 4494 data[0] = (unsigned long) state; 4495 data[1] = (unsigned long) (tmp_win->iconify_by_unmapping ? None : 4496 (tmp_win->icon ? tmp_win->icon->w : None)); 4497 4498 XChangeProperty (dpy, tmp_win->w, _XA_WM_STATE, _XA_WM_STATE, 32, 4499 PropModeReplace, (unsigned char *) data, 2); 4500} 4501 4502 4503 4504Bool GetWMState (Window w, int *statep, Window *iwp) 4505{ 4506 Atom actual_type; 4507 int actual_format; 4508 unsigned long nitems, bytesafter; 4509 unsigned long *datap = NULL; 4510 Bool retval = False; 4511 4512 if (XGetWindowProperty (dpy, w, _XA_WM_STATE, 0L, 2L, False, _XA_WM_STATE, 4513 &actual_type, &actual_format, &nitems, &bytesafter, 4514 (unsigned char **) &datap) != Success || !datap) 4515 return False; 4516 4517 if (nitems <= 2) { /* "suggested" by ICCCM version 1 */ 4518 *statep = (int) datap[0]; 4519 *iwp = (Window) datap[1]; 4520 retval = True; 4521 } 4522 4523 XFree ((char *) datap); 4524 return retval; 4525} 4526 4527 4528 4529int WarpToScreen (int n, int inc) 4530{ 4531 Window dumwin; 4532 int x, y, dumint; 4533 unsigned int dummask; 4534 ScreenInfo *newscr = NULL; 4535 4536 while (!newscr) { 4537 /* wrap around */ 4538 if (n < 0) 4539 n = NumScreens - 1; 4540 else if (n >= NumScreens) 4541 n = 0; 4542 4543 newscr = ScreenList[n]; 4544 if (!newscr) { /* make sure screen is managed */ 4545 if (inc) { /* walk around the list */ 4546 n += inc; 4547 continue; 4548 } 4549 fprintf (stderr, "%s: unable to warp to unmanaged screen %d\n", 4550 ProgramName, n); 4551 XBell (dpy, 0); 4552 return (1); 4553 } 4554 } 4555 4556 if (Scr->screen == n) return (0); /* already on that screen */ 4557 4558 PreviousScreen = Scr->screen; 4559 XQueryPointer (dpy, Scr->Root, &dumwin, &dumwin, &x, &y, 4560 &dumint, &dumint, &dummask); 4561 4562 XWarpPointer (dpy, None, newscr->Root, 0, 0, 0, 0, x, y); 4563 Scr = newscr; 4564 return (0); 4565} 4566 4567 4568 4569 4570/* 4571 * BumpWindowColormap - rotate our internal copy of WM_COLORMAP_WINDOWS 4572 */ 4573 4574int BumpWindowColormap (TwmWindow *tmp, int inc) 4575{ 4576 int i, j, previously_installed; 4577 ColormapWindow **cwins; 4578 4579 if (!tmp) return (1); 4580 4581 if (inc && tmp->cmaps.number_cwins > 0) { 4582 cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)* 4583 tmp->cmaps.number_cwins); 4584 if (cwins) { 4585 if ((previously_installed = 4586 /* SUPPRESS 560 */(Scr->cmapInfo.cmaps == &tmp->cmaps && 4587 tmp->cmaps.number_cwins))) { 4588 for (i = tmp->cmaps.number_cwins; i-- > 0; ) 4589 tmp->cmaps.cwins[i]->colormap->state = 0; 4590 } 4591 4592 for (i = 0; i < tmp->cmaps.number_cwins; i++) { 4593 j = i - inc; 4594 if (j >= tmp->cmaps.number_cwins) 4595 j -= tmp->cmaps.number_cwins; 4596 else if (j < 0) 4597 j += tmp->cmaps.number_cwins; 4598 cwins[j] = tmp->cmaps.cwins[i]; 4599 } 4600 4601 free((char *) tmp->cmaps.cwins); 4602 4603 tmp->cmaps.cwins = cwins; 4604 4605 if (tmp->cmaps.number_cwins > 1) 4606 memset (tmp->cmaps.scoreboard, 0, 4607 ColormapsScoreboardLength(&tmp->cmaps)); 4608 4609 if (previously_installed) { 4610 InstallColormaps(PropertyNotify, NULL); 4611 } 4612 } 4613 } else 4614 FetchWmColormapWindows (tmp); 4615 return (1); 4616} 4617 4618 4619 4620void ShowIconManager (void) 4621{ 4622 IconMgr *i; 4623 WorkSpace *wl; 4624 4625 if (! Scr->workSpaceManagerActive) return; 4626 4627 if (Scr->NoIconManagers) return; 4628 for (wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) { 4629 for (i = wl->iconmgr; i != NULL; i = i->next) { 4630 if (i->count == 0) continue; 4631 if (visible (i->twm_win)) { 4632 SetMapStateProp (i->twm_win, NormalState); 4633 XMapWindow (dpy, i->twm_win->w); 4634 MapRaised (i->twm_win); 4635 if (i->twm_win->icon && i->twm_win->icon->w) 4636 XUnmapWindow (dpy, i->twm_win->icon->w); 4637 } 4638 i->twm_win->mapped = TRUE; 4639 i->twm_win->isicon = FALSE; 4640 } 4641 } 4642} 4643 4644 4645void HideIconManager (void) 4646{ 4647 IconMgr *i; 4648 WorkSpace *wl; 4649 4650 if (Scr->NoIconManagers) return; 4651 for (wl = Scr->workSpaceMgr.workSpaceList; wl != NULL; wl = wl->next) { 4652 for (i = wl->iconmgr; i != NULL; i = i->next) { 4653 SetMapStateProp (i->twm_win, WithdrawnState); 4654 XUnmapWindow(dpy, i->twm_win->frame); 4655 if (i->twm_win->icon && i->twm_win->icon->w) XUnmapWindow (dpy, i->twm_win->icon->w); 4656 i->twm_win->mapped = FALSE; 4657 i->twm_win->isicon = TRUE; 4658 } 4659 } 4660} 4661 4662 4663 4664 4665void DestroyMenu (MenuRoot *menu) 4666{ 4667 MenuItem *item; 4668 4669 if (menu->w) { 4670 XDeleteContext (dpy, menu->w, MenuContext); 4671 XDeleteContext (dpy, menu->w, ScreenContext); 4672 if (Scr->Shadow) XDestroyWindow (dpy, menu->shadow); 4673 XDestroyWindow(dpy, menu->w); 4674 } 4675 4676 for (item = menu->first; item; ) { 4677 MenuItem *tmp = item; 4678 item = item->next; 4679 free ((char *) tmp); 4680 } 4681} 4682 4683 4684 4685/* 4686 * warping routines 4687 */ 4688 4689void WarpAlongRing (XButtonEvent *ev, Bool forward) 4690{ 4691 TwmWindow *r, *head; 4692 4693 if (Scr->RingLeader) 4694 head = Scr->RingLeader; 4695 else if (!(head = Scr->Ring)) 4696 return; 4697 4698 if (forward) { 4699 for (r = head->ring.next; r != head; r = r->ring.next) { 4700 if (!r) break; 4701 if (r->mapped && (Scr->WarpRingAnyWhere || visible (r))) break; 4702 } 4703 } else { 4704 for (r = head->ring.prev; r != head; r = r->ring.prev) { 4705 if (!r) break; 4706 if (r->mapped && (Scr->WarpRingAnyWhere || visible (r))) break; 4707 } 4708 } 4709 4710 /* Note: (Scr->Focus != r) is necessary when we move to a workspace that 4711 has a single window and we want warping to warp to it. */ 4712 if (r && (r != head || Scr->Focus != r)) { 4713 TwmWindow *p = Scr->RingLeader, *t; 4714 4715 Scr->RingLeader = r; 4716 WarpToWindow (r, 1); 4717 4718 if (p && p->mapped && 4719 (t = GetTwmWindow(ev->window)) && 4720 p == t) { 4721 p->ring.cursor_valid = True; 4722 p->ring.curs_x = ev->x_root - t->frame_x; 4723 p->ring.curs_y = ev->y_root - t->frame_y; 4724#ifdef DEBUG 4725 fprintf(stderr, "WarpAlongRing: cursor_valid := True; x := %d (%d-%d), y := %d (%d-%d)\n", Tmp_win->ring.curs_x, ev->x_root, t->frame_x, Tmp_win->ring.curs_y, ev->y_root, t->frame_y); 4726#endif 4727 /* 4728 * The check if the cursor position is inside the window is now 4729 * done in WarpToWindow(). 4730 */ 4731 } 4732 } 4733} 4734 4735 4736 4737void WarpToWindow (TwmWindow *t, int must_raise) 4738{ 4739 int x, y; 4740 4741 if (t->ring.cursor_valid) { 4742 x = t->ring.curs_x; 4743 y = t->ring.curs_y; 4744#ifdef DEBUG 4745 fprintf(stderr, "WarpToWindow: cursor_valid; x == %d, y == %d\n", x, y); 4746#endif 4747 4748 /* 4749 * XXX is this correct with 3D borders? Easier check possible? 4750 * frame_bw is for the left border. 4751 */ 4752 if (x < t->frame_bw) 4753 x = t->frame_bw; 4754 if (x >= t->frame_width + t->frame_bw) 4755 x = t->frame_width + t->frame_bw - 1; 4756 if (y < t->title_height + t->frame_bw) 4757 y = t->title_height + t->frame_bw; 4758 if (y >= t->frame_height + t->frame_bw) 4759 y = t->frame_height + t->frame_bw - 1; 4760#ifdef DEBUG 4761 fprintf(stderr, "WarpToWindow: adjusted ; x := %d, y := %d\n", x, y); 4762#endif 4763 } else { 4764 x = t->frame_width / 2; 4765 y = t->frame_height / 2; 4766#ifdef DEBUG 4767 fprintf(stderr, "WarpToWindow: middle; x := %d, y := %d\n", x, y); 4768#endif 4769 } 4770#if 0 4771 int dest_x, dest_y; 4772 Window child; 4773 4774 /* 4775 * Check if the proposed position actually is visible. If not, raise the window. 4776 * "If the coordinates are contained in a mapped 4777 * child of dest_w, that child is returned to child_return." 4778 * We'll need to check for the right child window; the frame probably. 4779 * (What about XXX window boxes?) 4780 * 4781 * Alternatively, use XQueryPointer() which returns the root window 4782 * the pointer is in, but XXX that won't work for VirtualScreens. 4783 */ 4784 if (XTranslateCoordinates(dpy, t->frame, Scr->Root, x, y, &dest_x, &dest_y, &child)) { 4785 if (child != t->frame) 4786 must_raise = 1; 4787 } 4788#endif 4789 if (t->auto_raise || must_raise) AutoRaiseWindow (t); 4790 if (! visible (t)) { 4791 WorkSpace *wlist; 4792 4793 for (wlist = Scr->workSpaceMgr.workSpaceList; wlist != NULL; wlist = wlist->next) { 4794 if (OCCUPY (t, wlist)) break; 4795 } 4796 if (wlist != NULL) GotoWorkSpace (Scr->currentvs, wlist); 4797 } 4798 XWarpPointer (dpy, None, Scr->Root, 0, 0, 0, 0, x + t->frame_x, y + t->frame_y); 4799#ifdef DEBUG 4800 { 4801 Window root_return; 4802 Window child_return; 4803 int root_x_return; 4804 int root_y_return; 4805 int win_x_return; 4806 int win_y_return; 4807 unsigned int mask_return; 4808 4809 if (XQueryPointer(dpy, t->frame, &root_return, &child_return, &root_x_return, &root_y_return, &win_x_return, &win_y_return, &mask_return)) { 4810 fprintf(stderr, "XQueryPointer: root_return=%x, child_return=%x, root_x_return=%d, root_y_return=%d, win_x_return=%d, win_y_return=%d\n", root_return, child_return, root_x_return, root_y_return, win_x_return, win_y_return); 4811 } 4812 } 4813#endif 4814} 4815 4816 4817 4818 4819/* 4820 * ICCCM Client Messages - Section 4.2.8 of the ICCCM dictates that all 4821 * client messages will have the following form: 4822 * 4823 * event type ClientMessage 4824 * message type _XA_WM_PROTOCOLS 4825 * window tmp->w 4826 * format 32 4827 * data[0] message atom 4828 * data[1] time stamp 4829 */ 4830static void send_clientmessage (Window w, Atom a, Time timestamp) 4831{ 4832 XClientMessageEvent ev; 4833 4834 ev.type = ClientMessage; 4835 ev.window = w; 4836 ev.message_type = _XA_WM_PROTOCOLS; 4837 ev.format = 32; 4838 ev.data.l[0] = a; 4839 ev.data.l[1] = timestamp; 4840 XSendEvent (dpy, w, False, 0L, (XEvent *) &ev); 4841} 4842 4843void SendDeleteWindowMessage (TwmWindow *tmp, Time timestamp) 4844{ 4845 send_clientmessage (tmp->w, _XA_WM_DELETE_WINDOW, timestamp); 4846} 4847 4848void SendSaveYourselfMessage (TwmWindow *tmp, Time timestamp) 4849{ 4850 send_clientmessage (tmp->w, _XA_WM_SAVE_YOURSELF, timestamp); 4851} 4852 4853 4854void SendTakeFocusMessage (TwmWindow *tmp, Time timestamp) 4855{ 4856 send_clientmessage (tmp->w, _XA_WM_TAKE_FOCUS, timestamp); 4857} 4858 4859int MoveMenu (XEvent *eventp) 4860{ 4861 int XW, YW, newX, newY, cont; 4862 Bool newev; 4863 unsigned long event_mask; 4864 XEvent ev; 4865 4866 if (! ActiveMenu) return (1); 4867 if (! ActiveMenu->pinned) return (1); 4868 4869 XW = eventp->xbutton.x_root - ActiveMenu->x; 4870 YW = eventp->xbutton.y_root - ActiveMenu->y; 4871 XGrabPointer (dpy, ActiveMenu->w, True, 4872 ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, 4873 GrabModeAsync, GrabModeAsync, 4874 None, Scr->MoveCursor, CurrentTime); 4875 4876 newX = ActiveMenu->x; 4877 newY = ActiveMenu->y; 4878 cont = TRUE; 4879 event_mask = ButtonPressMask | ButtonMotionMask | ButtonReleaseMask | ExposureMask; 4880 XMaskEvent (dpy, event_mask, &ev); 4881 while (cont) { 4882 ev.xbutton.x_root -= Scr->rootx; 4883 ev.xbutton.y_root -= Scr->rooty; 4884 switch (ev.xany.type) { 4885 case ButtonRelease : 4886 cont = FALSE; 4887 case MotionNotify : 4888 if (!cont) { 4889 newev = False; 4890 while (XCheckMaskEvent (dpy, ButtonMotionMask | ButtonReleaseMask, &ev)) { 4891 newev = True; 4892 if (ev.type == ButtonRelease) break; 4893 } 4894 if (ev.type == ButtonRelease) continue; 4895 if (newev) { 4896 ev.xbutton.x_root -= Scr->rootx; 4897 ev.xbutton.y_root -= Scr->rooty; 4898 } 4899 } 4900 newX = ev.xbutton.x_root - XW; 4901 newY = ev.xbutton.y_root - YW; 4902 if (Scr->DontMoveOff) 4903 { 4904 ConstrainByBorders1 (&newX, ActiveMenu->width, 4905 &newY, ActiveMenu->height); 4906 } 4907 XMoveWindow (dpy, ActiveMenu->w, newX, newY); 4908 XMaskEvent (dpy, event_mask, &ev); 4909 break; 4910 case ButtonPress : 4911 cont = FALSE; 4912 newX = ActiveMenu->x; 4913 newY = ActiveMenu->y; 4914 break; 4915 case Expose: 4916 case NoExpose: 4917 Event = ev; 4918 DispatchEvent (); 4919 XMaskEvent (dpy, event_mask, &ev); 4920 break; 4921 } 4922 } 4923 XUngrabPointer (dpy, CurrentTime); 4924 if (ev.xany.type == ButtonRelease) ButtonPressed = -1; 4925 /*XPutBackEvent (dpy, &ev);*/ 4926 XMoveWindow (dpy, ActiveMenu->w, newX, newY); 4927 ActiveMenu->x = newX; 4928 ActiveMenu->y = newY; 4929 MenuOrigins [MenuDepth - 1].x = newX; 4930 MenuOrigins [MenuDepth - 1].y = newY; 4931 4932 return (1); 4933} 4934 4935/*********************************************************************** 4936 * 4937 * Procedure: 4938 * DisplayPosition - display the position in the dimensions window 4939 * 4940 * Inputs: 4941 * tmp_win - the current twm window 4942 * x, y - position of the window 4943 * 4944 *********************************************************************** 4945 */ 4946 4947void DisplayPosition (TwmWindow *tmp_win, int x, int y) 4948{ 4949 char str [100]; 4950 char signx = '+'; 4951 char signy = '+'; 4952 4953 if (x < 0) { 4954 x = -x; 4955 signx = '-'; 4956 } 4957 if (y < 0) { 4958 y = -y; 4959 signy = '-'; 4960 } 4961 (void) sprintf (str, " %c%-4d %c%-4d ", signx, x, signy, y); 4962 XRaiseWindow (dpy, Scr->SizeWindow); 4963 4964 Draw3DBorder (Scr->SizeWindow, 0, 0, 4965 Scr->SizeStringOffset + Scr->SizeStringWidth + SIZE_HINDENT, 4966 Scr->SizeFont.height + SIZE_VINDENT * 2, 4967 2, Scr->DefaultC, off, False, False); 4968 4969 FB(Scr->DefaultC.fore, Scr->DefaultC.back); 4970 XmbDrawImageString (dpy, Scr->SizeWindow, Scr->SizeFont.font_set, 4971 Scr->NormalGC, Scr->SizeStringOffset, 4972 Scr->SizeFont.ascent + SIZE_VINDENT , str, 13); 4973} 4974 4975void MosaicFade (TwmWindow *tmp_win, Window blanket) 4976{ 4977 int srect; 4978 int i, j, nrects; 4979 Pixmap mask; 4980 GC gc; 4981 XGCValues gcv; 4982 XRectangle *rectangles; 4983 int width = tmp_win->frame_width; 4984 int height = tmp_win->frame_height; 4985 4986 srect = (width < height) ? (width / 20) : (height / 20); 4987 mask = XCreatePixmap (dpy, blanket, width, height, 1); 4988 4989 gcv.foreground = 1; 4990 gc = XCreateGC (dpy, mask, GCForeground, &gcv); 4991 XFillRectangle (dpy, mask, gc, 0, 0, width, height); 4992 gcv.function = GXclear; 4993 XChangeGC (dpy, gc, GCFunction, &gcv); 4994 4995 nrects = ((width * height) / (srect * srect)) / 10; 4996 rectangles = (XRectangle*) malloc (nrects * sizeof (XRectangle)); 4997 for (j = 0; j < nrects; j++) { 4998 rectangles [j].width = srect; 4999 rectangles [j].height = srect; 5000 } 5001 for (i = 0; i < 10; i++) { 5002 for (j = 0; j < nrects; j++) { 5003 rectangles [j].x = ((lrand48 () % width) / srect) * srect; 5004 rectangles [j].y = ((lrand48 () % height) / srect) * srect; 5005 } 5006 XFillRectangles (dpy, mask, gc, rectangles, nrects); 5007 XShapeCombineMask (dpy, blanket, ShapeBounding, 0, 0, mask, ShapeSet); 5008 XFlush (dpy); 5009 waitamoment (0.020); 5010 } 5011 XFreePixmap (dpy, mask); 5012 XFreeGC (dpy, gc); 5013 free (rectangles); 5014} 5015 5016void ZoomInWindow (TwmWindow *tmp_win, Window blanket) 5017{ 5018 Pixmap mask; 5019 GC gc, gcn; 5020 XGCValues gcv; 5021 5022 int i, nsteps = 20; 5023 int w = tmp_win->frame_width; 5024 int h = tmp_win->frame_height; 5025 int step = (MAX (w, h)) / (2.0 * nsteps); 5026 5027 mask = XCreatePixmap (dpy, blanket, w, h, 1); 5028 gcv.foreground = 1; 5029 gc = XCreateGC (dpy, mask, GCForeground, &gcv); 5030 gcv.function = GXclear; 5031 gcn = XCreateGC (dpy, mask, GCForeground | GCFunction, &gcv); 5032 5033 for (i = 0; i < nsteps; i++) { 5034 XFillRectangle (dpy, mask, gcn, 0, 0, w, h); 5035 XFillArc (dpy, mask, gc, (w / 2) - ((nsteps - i) * step), 5036 (h / 2) - ((nsteps - i) * step), 5037 2 * (nsteps - i) * step, 5038 2 * (nsteps - i) * step, 5039 0, 360*64); 5040 XShapeCombineMask (dpy, blanket, ShapeBounding, 0, 0, mask, ShapeSet); 5041 XFlush (dpy); 5042 waitamoment (0.020); 5043 } 5044} 5045 5046void ZoomOutWindow (TwmWindow *tmp_win, Window blanket) 5047{ 5048 Pixmap mask; 5049 GC gc; 5050 XGCValues gcv; 5051 5052 int i, nsteps = 20; 5053 int w = tmp_win->frame_width; 5054 int h = tmp_win->frame_height; 5055 int step = (MAX (w, h)) / (2.0 * nsteps); 5056 5057 mask = XCreatePixmap (dpy, blanket, w, h, 1); 5058 gcv.foreground = 1; 5059 gc = XCreateGC (dpy, mask, GCForeground, &gcv); 5060 XFillRectangle (dpy, mask, gc, 0, 0, w, h); 5061 gcv.function = GXclear; 5062 XChangeGC (dpy, gc, GCFunction, &gcv); 5063 5064 for (i = 0; i < nsteps; i++) { 5065 XFillArc (dpy, mask, gc, (w / 2) - (i * step), 5066 (h / 2) - (i * step), 5067 2 * i * step, 5068 2 * i * step, 5069 0, 360*64); 5070 XShapeCombineMask (dpy, blanket, ShapeBounding, 0, 0, mask, ShapeSet); 5071 XFlush (dpy); 5072 waitamoment (0.020); 5073 } 5074} 5075 5076void FadeWindow (TwmWindow *tmp_win, Window blanket) 5077{ 5078 Pixmap mask, stipple; 5079 GC gc; 5080 XGCValues gcv; 5081 static unsigned char stipple_bits[] = { 0x0F, 0x0F, 5082 0xF0, 0xF0, 5083 0x0F, 0x0F, 5084 0xF0, 0xF0, 5085 0x0F, 0x0F, 5086 0xF0, 0xF0, 5087 0x0F, 0x0F, 5088 0xF0, 0xF0, 5089 }; 5090 int w = tmp_win->frame_width; 5091 int h = tmp_win->frame_height; 5092 5093 stipple = XCreateBitmapFromData (dpy, blanket, (char *)stipple_bits, 8, 8); 5094 mask = XCreatePixmap (dpy, blanket, w, h, 1); 5095 gcv.background = 0; 5096 gcv.foreground = 1; 5097 gcv.stipple = stipple; 5098 gcv.fill_style = FillOpaqueStippled; 5099 gc = XCreateGC (dpy, mask, GCBackground | GCForeground | GCFillStyle | GCStipple, &gcv); 5100 XFillRectangle (dpy, mask, gc, 0, 0, w, h); 5101 5102 XShapeCombineMask (dpy, blanket, ShapeBounding, 0, 0, mask, ShapeSet); 5103 XFlush (dpy); 5104 waitamoment (10.0); 5105 XFreePixmap (dpy, stipple); 5106} 5107 5108void SweepWindow (TwmWindow *tmp_win, Window blanket) 5109{ 5110 float step = 0.0; 5111 int i, nsteps = 20; 5112 int dir = 0, dist = tmp_win->frame_x, dist1; 5113 5114 dist1 = tmp_win->frame_y; 5115 if (dist1 < dist) { dir = 1; dist = dist1; } 5116 dist1 = tmp_win->vs->w - (tmp_win->frame_x + tmp_win->frame_width); 5117 if (dist1 < dist) { dir = 2; dist = dist1; } 5118 dist1 = tmp_win->vs->h - (tmp_win->frame_y + tmp_win->frame_height); 5119 if (dist1 < dist) { dir = 3; dist = dist1; } 5120 5121 switch (dir) { 5122 case 0: step = tmp_win->frame_x + tmp_win->frame_width; break; 5123 case 1: step = tmp_win->frame_y + tmp_win->frame_height; break; 5124 case 2: step = tmp_win->vs->w - tmp_win->frame_x; break; 5125 case 3: step = tmp_win->vs->h - tmp_win->frame_y; break; 5126 } 5127 step /= (float) nsteps; 5128 step /= (float) nsteps; 5129 for (i = 0; i < 20; i++) { 5130 int x = tmp_win->frame_x; 5131 int y = tmp_win->frame_y; 5132 switch (dir) { 5133 case 0: x -= i * i * step; break; 5134 case 1: y -= i * i * step; break; 5135 case 2: x += i * i * step; break; 5136 case 3: y += i * i * step; break; 5137 } 5138 XMoveWindow (dpy, blanket, x, y); 5139 XFlush (dpy); 5140 waitamoment (0.020); 5141 } 5142} 5143 5144void waitamoment (float timeout) 5145{ 5146#ifdef VMS 5147 lib$wait (&timeout); 5148#else 5149 struct timeval timeoutstruct; 5150 int usec = timeout * 1000000; 5151 timeoutstruct.tv_usec = usec % (unsigned long) 1000000; 5152 timeoutstruct.tv_sec = usec / (unsigned long) 1000000; 5153 select (0, (void *) 0, (void *) 0, (void *) 0, &timeoutstruct); 5154#endif 5155} 5156 5157void packwindow (TwmWindow *tmp_win, char *direction) 5158{ 5159 int cons, newx, newy; 5160 int x, y, px, py, junkX, junkY; 5161 unsigned int junkK; 5162 Window junkW; 5163 5164 if (!strcmp (direction, "left")) { 5165 cons = FindConstraint (tmp_win, J_LEFT); 5166 if (cons == -1) return; 5167 newx = cons; 5168 newy = tmp_win->frame_y; 5169 } else 5170 if (!strcmp (direction, "right")) { 5171 cons = FindConstraint (tmp_win, J_RIGHT); 5172 if (cons == -1) return; 5173 newx = cons; 5174 newx -= tmp_win->frame_width + 2 * tmp_win->frame_bw; 5175 newy = tmp_win->frame_y; 5176 } else 5177 if (!strcmp (direction, "top")) { 5178 cons = FindConstraint (tmp_win, J_TOP); 5179 if (cons == -1) return; 5180 newx = tmp_win->frame_x; 5181 newy = cons; 5182 } else 5183 if (!strcmp (direction, "bottom")) { 5184 cons = FindConstraint (tmp_win, J_BOTTOM); 5185 if (cons == -1) return; 5186 newx = tmp_win->frame_x; 5187 newy = cons; 5188 newy -= tmp_win->frame_height + 2 * tmp_win->frame_bw; 5189 } else return; 5190 5191 XQueryPointer (dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &x, &y, &junkK); 5192 px = x - tmp_win->frame_x + newx; 5193 py = y - tmp_win->frame_y + newy; 5194 XWarpPointer (dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, px, py); 5195 XRaiseWindow(dpy, tmp_win->frame); 5196 XMoveWindow (dpy, tmp_win->frame, newx, newy); 5197 SetupWindow (tmp_win, newx, newy, tmp_win->frame_width, tmp_win->frame_height, -1); 5198} 5199 5200void fillwindow (TwmWindow *tmp_win, char *direction) 5201{ 5202 int cons, newx, newy, save; 5203 unsigned int neww, newh; 5204 int i; 5205 int winx = tmp_win->frame_x; 5206 int winy = tmp_win->frame_y; 5207 int winw = tmp_win->frame_width + 2 * tmp_win->frame_bw; 5208 int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw; 5209 5210 if (!strcmp (direction, "left")) { 5211 cons = FindConstraint (tmp_win, J_LEFT); 5212 if (cons == -1) return; 5213 newx = cons; 5214 newy = tmp_win->frame_y; 5215 neww = winw + winx - newx; 5216 newh = winh; 5217 neww -= 2 * tmp_win->frame_bw; 5218 newh -= 2 * tmp_win->frame_bw; 5219 ConstrainSize (tmp_win, &neww, &newh); 5220 } else 5221 if (!strcmp (direction, "right")) { 5222 for (i = 0; i < 2; i++) { 5223 cons = FindConstraint (tmp_win, J_RIGHT); 5224 if (cons == -1) return; 5225 newx = tmp_win->frame_x; 5226 newy = tmp_win->frame_y; 5227 neww = cons - winx; 5228 newh = winh; 5229 save = neww; 5230 neww -= 2 * tmp_win->frame_bw; 5231 newh -= 2 * tmp_win->frame_bw; 5232 ConstrainSize (tmp_win, &neww, &newh); 5233 if ((neww != winw) || (newh != winh) || 5234 (cons == Scr->rootw - Scr->BorderRight)) 5235 break; 5236 neww = save; 5237 SetupWindow (tmp_win, newx, newy, neww, newh, -1); 5238 } 5239 } else 5240 if (!strcmp (direction, "top")) { 5241 cons = FindConstraint (tmp_win, J_TOP); 5242 if (cons == -1) return; 5243 newx = tmp_win->frame_x; 5244 newy = cons; 5245 neww = winw; 5246 newh = winh + winy - newy; 5247 neww -= 2 * tmp_win->frame_bw; 5248 newh -= 2 * tmp_win->frame_bw; 5249 ConstrainSize (tmp_win, &neww, &newh); 5250 } else 5251 if (!strcmp (direction, "bottom")) { 5252 for (i = 0; i < 2; i++) { 5253 cons = FindConstraint (tmp_win, J_BOTTOM); 5254 if (cons == -1) return; 5255 newx = tmp_win->frame_x; 5256 newy = tmp_win->frame_y; 5257 neww = winw; 5258 newh = cons - winy; 5259 save = newh; 5260 neww -= 2 * tmp_win->frame_bw; 5261 newh -= 2 * tmp_win->frame_bw; 5262 ConstrainSize (tmp_win, &neww, &newh); 5263 if ((neww != winw) || (newh != winh) || 5264 (cons == Scr->rooth - Scr->BorderBottom)) 5265 break; 5266 newh = save; 5267 SetupWindow (tmp_win, newx, newy, neww, newh, -1); 5268 } 5269 } 5270 else if (!strcmp (direction, "vertical")) 5271 { 5272 if (tmp_win->zoomed == ZOOM_NONE) 5273 { 5274 tmp_win->save_frame_height = tmp_win->frame_height; 5275 tmp_win->save_frame_width = tmp_win->frame_width; 5276 tmp_win->save_frame_y = tmp_win->frame_y; 5277 tmp_win->save_frame_x = tmp_win->frame_x; 5278 5279 tmp_win->frame_y++; 5280 newy = FindConstraint (tmp_win, J_TOP); 5281 tmp_win->frame_y--; 5282 newh = FindConstraint (tmp_win, J_BOTTOM) - newy; 5283 newh -= 2 * tmp_win->frame_bw; 5284 5285 newx = tmp_win->frame_x; 5286 neww = tmp_win->frame_width; 5287 5288 ConstrainSize (tmp_win, &neww, &newh); 5289 5290 /* if the bottom of the window has moved up 5291 * it will be pushed down */ 5292 if (newy + newh < 5293 tmp_win->save_frame_y + tmp_win->save_frame_height) 5294 newy = tmp_win->save_frame_y + 5295 tmp_win->save_frame_height - newh; 5296 tmp_win->zoomed = F_ZOOM; 5297 SetupWindow (tmp_win, newx, newy, neww, newh, -1); 5298 } 5299 else 5300 { 5301 fullzoom (tmp_win, tmp_win->zoomed); 5302 } 5303 return; 5304 } 5305 else return; 5306 SetupWindow (tmp_win, newx, newy, neww, newh, -1); 5307} 5308 5309void jump (TwmWindow *tmp_win, int direction, char *action) 5310{ 5311 int fx, fy, px, py, step, status, cons; 5312 int fwidth, fheight; 5313 int junkX, junkY; 5314 unsigned int junkK; 5315 Window junkW; 5316 5317 if (! action) return; 5318 status = sscanf (action, "%d", &step); 5319 if (status != 1) return; 5320 if (step < 1) return; 5321 5322 fx = tmp_win->frame_x; 5323 fy = tmp_win->frame_y; 5324 XQueryPointer (dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &px, &py, &junkK); 5325 px -= fx; py -= fy; 5326 5327 fwidth = tmp_win->frame_width + 2 * tmp_win->frame_bw; 5328 fheight = tmp_win->frame_height + 2 * tmp_win->frame_bw; 5329 switch (direction) { 5330 case J_LEFT : 5331 cons = FindConstraint (tmp_win, J_LEFT); 5332 if (cons == -1) return; 5333 fx -= step * Scr->XMoveGrid; 5334 if (fx < cons) fx = cons; 5335 break; 5336 case J_RIGHT : 5337 cons = FindConstraint (tmp_win, J_RIGHT); 5338 if (cons == -1) return; 5339 fx += step * Scr->XMoveGrid; 5340 if (fx + fwidth > cons) fx = cons - fwidth; 5341 break; 5342 case J_TOP : 5343 cons = FindConstraint (tmp_win, J_TOP); 5344 if (cons == -1) return; 5345 fy -= step * Scr->YMoveGrid; 5346 if (fy < cons) fy = cons; 5347 break; 5348 case J_BOTTOM : 5349 cons = FindConstraint (tmp_win, J_BOTTOM); 5350 if (cons == -1) return; 5351 fy += step * Scr->YMoveGrid; 5352 if (fy + fheight > cons) fy = cons - fheight; 5353 break; 5354 } 5355 /* Pebl Fixme: don't warp if jump happens through iconmgr */ 5356 XWarpPointer (dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, fx + px, fy + py); 5357 if (!Scr->NoRaiseMove) 5358 XRaiseWindow (dpy, tmp_win->frame); 5359 SetupWindow (tmp_win, fx, fy, tmp_win->frame_width, tmp_win->frame_height, -1); 5360} 5361 5362int FindConstraint (TwmWindow *tmp_win, int direction) 5363{ 5364 TwmWindow *t; 5365 int w, h; 5366 int winx = tmp_win->frame_x; 5367 int winy = tmp_win->frame_y; 5368 int winw = tmp_win->frame_width + 2 * tmp_win->frame_bw; 5369 int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw; 5370 int ret; 5371 5372 switch (direction) { 5373 case J_LEFT : if (winx < Scr->BorderLeft) return -1; 5374 ret = Scr->BorderLeft; break; 5375 case J_RIGHT : if (winx + winw > Scr->rootw - Scr->BorderRight) return -1; 5376 ret = Scr->rootw - Scr->BorderRight; break; 5377 case J_TOP : if (winy < Scr->BorderTop) return -1; 5378 ret = Scr->BorderTop; break; 5379 case J_BOTTOM : if (winy + winh > Scr->rooth - Scr->BorderBottom) return -1; 5380 ret = Scr->rooth - Scr->BorderBottom; break; 5381 default : return -1; 5382 } 5383 for (t = Scr->FirstWindow; t != NULL; t = t->next) { 5384 if (t == tmp_win) continue; 5385 if (!visible (t)) continue; 5386 if (!t->mapped) continue; 5387 w = t->frame_width + 2 * t->frame_bw; 5388 h = t->frame_height + 2 * t->frame_bw; 5389 5390 switch (direction) { 5391 case J_LEFT : 5392 if (winx <= t->frame_x + w) continue; 5393 if (winy >= t->frame_y + h) continue; 5394 if (winy + winh <= t->frame_y ) continue; 5395 ret = MAX (ret, t->frame_x + w); 5396 break; 5397 case J_RIGHT : 5398 if (winx + winw >= t->frame_x ) continue; 5399 if (winy >= t->frame_y + h) continue; 5400 if (winy + winh <= t->frame_y ) continue; 5401 ret = MIN (ret, t->frame_x); 5402 break; 5403 case J_TOP : 5404 if (winy <= t->frame_y + h) continue; 5405 if (winx >= t->frame_x + w) continue; 5406 if (winx + winw <= t->frame_x ) continue; 5407 ret = MAX (ret, t->frame_y + h); 5408 break; 5409 case J_BOTTOM : 5410 if (winy + winh >= t->frame_y ) continue; 5411 if (winx >= t->frame_x + w) continue; 5412 if (winx + winw <= t->frame_x ) continue; 5413 ret = MIN (ret, t->frame_y); 5414 break; 5415 } 5416 } 5417 return ret; 5418} 5419 5420void TryToPack (TwmWindow *tmp_win, int *x, int *y) 5421{ 5422 TwmWindow *t; 5423 int newx, newy; 5424 int w, h; 5425 int winw = tmp_win->frame_width + 2 * tmp_win->frame_bw; 5426 int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw; 5427 5428 newx = *x; 5429 newy = *y; 5430 for (t = Scr->FirstWindow; t != NULL; t = t->next) { 5431 if (t == tmp_win) continue; 5432 if (t->winbox != tmp_win->winbox) continue; 5433 if (t->vs != tmp_win->vs) continue; 5434 if (!t->mapped) continue; 5435 5436 w = t->frame_width + 2 * t->frame_bw; 5437 h = t->frame_height + 2 * t->frame_bw; 5438 if (newx >= t->frame_x + w) continue; 5439 if (newy >= t->frame_y + h) continue; 5440 if (newx + winw <= t->frame_x) continue; 5441 if (newy + winh <= t->frame_y) continue; 5442 5443 if (newx + Scr->MovePackResistance > t->frame_x + w) { /* left */ 5444 newx = MAX (newx, t->frame_x + w); 5445 continue; 5446 } 5447 if (newx + winw < t->frame_x + Scr->MovePackResistance) { /* right */ 5448 newx = MIN (newx, t->frame_x - winw); 5449 continue; 5450 } 5451 if (newy + Scr->MovePackResistance > t->frame_y + h) { /* top */ 5452 newy = MAX (newy, t->frame_y + h); 5453 continue; 5454 } 5455 if (newy + winh < t->frame_y + Scr->MovePackResistance) { /* bottom */ 5456 newy = MIN (newy, t->frame_y - winh); 5457 continue; 5458 } 5459 } 5460 *x = newx; 5461 *y = newy; 5462} 5463 5464void TryToPush (TwmWindow *tmp_win, int x, int y, int dir) 5465{ 5466 TwmWindow *t; 5467 int newx, newy, ndir; 5468 Boolean move; 5469 int w, h; 5470 int winw = tmp_win->frame_width + 2 * tmp_win->frame_bw; 5471 int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw; 5472 5473 for (t = Scr->FirstWindow; t != NULL; t = t->next) { 5474 if (t == tmp_win) continue; 5475 if (t->winbox != tmp_win->winbox) continue; 5476 if (t->vs != tmp_win->vs) continue; 5477 if (!t->mapped) continue; 5478 5479 w = t->frame_width + 2 * t->frame_bw; 5480 h = t->frame_height + 2 * t->frame_bw; 5481 if (x >= t->frame_x + w) continue; 5482 if (y >= t->frame_y + h) continue; 5483 if (x + winw <= t->frame_x) continue; 5484 if (y + winh <= t->frame_y) continue; 5485 5486 move = False; 5487 if ((dir == 0 || dir == J_LEFT) && 5488 (x + Scr->MovePackResistance > t->frame_x + w)) { 5489 newx = x - w; 5490 newy = t->frame_y; 5491 ndir = J_LEFT; 5492 move = True; 5493 } 5494 else 5495 if ((dir == 0 || dir == J_RIGHT) && 5496 (x + winw < t->frame_x + Scr->MovePackResistance)) { 5497 newx = x + winw; 5498 newy = t->frame_y; 5499 ndir = J_RIGHT; 5500 move = True; 5501 } 5502 else 5503 if ((dir == 0 || dir == J_TOP) && 5504 (y + Scr->MovePackResistance > t->frame_y + h)) { 5505 newx = t->frame_x; 5506 newy = y - h; 5507 ndir = J_TOP; 5508 move = True; 5509 } 5510 else 5511 if ((dir == 0 || dir == J_BOTTOM) && 5512 (y + winh < t->frame_y + Scr->MovePackResistance)) { 5513 newx = t->frame_x; 5514 newy = y + winh; 5515 ndir = J_BOTTOM; 5516 move = True; 5517 } 5518 if (move) { 5519 TryToPush (t, newx, newy, ndir); 5520 TryToPack (t, &newx, &newy); 5521 ConstrainByBorders (tmp_win, 5522 &newx, t->frame_width + 2 * t->frame_bw, 5523 &newy, t->frame_height + 2 * t->frame_bw); 5524 SetupWindow (t, newx, newy, t->frame_width, t->frame_height, -1); 5525 } 5526 } 5527} 5528 5529void TryToGrid (TwmWindow *tmp_win, int *x, int *y) 5530{ 5531 int w = tmp_win->frame_width + 2 * tmp_win->frame_bw; 5532 int h = tmp_win->frame_height + 2 * tmp_win->frame_bw; 5533 int grav = ((tmp_win->hints.flags & PWinGravity) 5534 ? tmp_win->hints.win_gravity : NorthWestGravity); 5535 5536 switch (grav) { 5537 case ForgetGravity : 5538 case StaticGravity : 5539 case NorthWestGravity : 5540 case NorthGravity : 5541 case WestGravity : 5542 case CenterGravity : 5543 *x = ((*x - Scr->BorderLeft) / Scr->XMoveGrid) * Scr->XMoveGrid 5544 + Scr->BorderLeft; 5545 *y = ((*y - Scr->BorderTop) / Scr->YMoveGrid) * Scr->YMoveGrid 5546 + Scr->BorderTop; 5547 break; 5548 case NorthEastGravity : 5549 case EastGravity : 5550 *x = (((*x + w - Scr->BorderLeft) / Scr->XMoveGrid) * 5551 Scr->XMoveGrid) - w + Scr->BorderLeft; 5552 *y = ((*y - Scr->BorderTop) / Scr->YMoveGrid) * 5553 Scr->YMoveGrid + Scr->BorderTop; 5554 break; 5555 case SouthWestGravity : 5556 case SouthGravity : 5557 *x = ((*x - Scr->BorderLeft) / Scr->XMoveGrid) * Scr->XMoveGrid 5558 + Scr->BorderLeft; 5559 *y = (((*y + h - Scr->BorderTop) / Scr->YMoveGrid) * Scr->YMoveGrid) 5560 - h + Scr->BorderTop; 5561 break; 5562 case SouthEastGravity : 5563 *x = (((*x + w - Scr->BorderLeft) / Scr->XMoveGrid) * 5564 Scr->XMoveGrid) - w + Scr->BorderLeft; 5565 *y = (((*y + h - Scr->BorderTop) / Scr->YMoveGrid) * 5566 Scr->YMoveGrid) - h + Scr->BorderTop; 5567 break; 5568 } 5569} 5570 5571int WarpCursorToDefaultEntry (MenuRoot *menu) 5572{ 5573 MenuItem *item; 5574 Window root; 5575 int i, x, y, xl, yt; 5576 unsigned int w, h, bw, d; 5577 5578 for (i = 0, item = menu->first; item != menu->last; item = item->next) { 5579 if (item == menu->defaultitem) break; 5580 i++; 5581 } 5582 if (!XGetGeometry (dpy, menu->w, &root, &x, &y, &w, &h, &bw, &d)) return 0; 5583 xl = x + (menu->width / 2); 5584 yt = y + (i + 0.5) * Scr->EntryHeight; 5585 5586 XWarpPointer (dpy, Scr->Root, Scr->Root, 5587 Event.xbutton.x_root, Event.xbutton.y_root, 5588 menu->width, menu->height, xl, yt); 5589 return 1; 5590} 5591 5592