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