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