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