add_window.c revision df1c27a6
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 * Copyright 1992 Claude Lecommandeur. 8 */ 9 10/********************************************************************** 11 * 12 * $XConsortium: add_window.c,v 1.153 91/07/10 13:17:26 dave Exp $ 13 * 14 * Add a new window, put the titlbar and other stuff around 15 * the window 16 * 17 * 31-Mar-88 Tom LaStrange Initial Version. 18 * 19 * Do the necessary modification to be integrated in ctwm. 20 * Can no longer be used for the standard twm. 21 * 22 * 22-April-92 Claude Lecommandeur. 23 * 24 **********************************************************************/ 25 26#include "ctwm.h" 27 28#include <stdio.h> 29#include <stdlib.h> 30#include <string.h> 31#include <sys/time.h> 32 33#include <X11/Xatom.h> 34#include <X11/extensions/shape.h> 35 36#include "add_window.h" 37#ifdef CAPTIVE 38#include "captive.h" 39#endif 40#include "colormaps.h" 41#include "ctwm_atoms.h" 42#include "functions.h" 43#include "events.h" 44#ifdef EWMH 45# include "ewmh_atoms.h" 46#endif 47#include "gram.tab.h" 48#include "icons.h" 49#include "iconmgr.h" 50#include "image.h" 51#include "list.h" 52#include "mwmhints.h" 53#include "occupation.h" 54#include "otp.h" 55#include "parse.h" 56#include "r_area.h" 57#include "r_layout.h" 58#include "screen.h" 59#ifdef SESSION 60#include "session.h" 61#endif 62#include "util.h" 63#include "vscreen.h" 64#ifdef WINBOX 65#include "windowbox.h" 66#endif 67#include "win_decorations.h" 68#include "win_ops.h" 69#include "win_regions.h" 70#include "win_resize.h" 71#include "win_ring.h" 72#include "win_utils.h" 73#include "workspace_manager.h" 74#include "xparsegeometry.h" 75 76 77int AddingX; 78int AddingY; 79unsigned int AddingW; 80unsigned int AddingH; 81 82static int PlaceX = -1; 83static int PlaceY = -1; 84#ifdef VSCREEN 85static void DealWithNonSensicalGeometries(Display *dpy, Window vroot, 86 TwmWindow *tmp_win); 87#endif 88 89char NoName[] = "Untitled"; /* name if no name is specified */ 90bool resizeWhenAdd; 91 92 93 94/*********************************************************************** 95 * 96 * Procedure: 97 * AddWindow - add a new window to the twm list 98 * 99 * Returned Value: 100 * (TwmWindow *) - pointer to the TwmWindow structure 101 * 102 * Inputs: 103 * w - the window id of the window to add 104 * wtype - flag to tell if this is a normal window or some ctwm 105 * internal one. 106 * 107 * iconp - pointer to icon manager struct 108 * 109 *********************************************************************** 110 */ 111 112TwmWindow * 113AddWindow(Window w, AWType wtype, IconMgr *iconp, VirtualScreen *vs) 114{ 115 TwmWindow *tmp_win; /* new twm window structure */ 116 bool ask_user; /* don't know where to put the window */ 117 int gravx, gravy; /* gravity signs for positioning */ 118 int namelen; 119 int bw2; 120#ifdef SESSION 121 short restore_icon_x, restore_icon_y; 122 bool restore_iconified = false; 123 bool restore_icon_info_present = false; 124#endif 125 bool restoredFromPrevSession = false; 126 int saved_occupation = 0; /* <== [ Matthew McNeill Feb 1997 ] == */ 127 bool random_placed = false; 128#ifdef WINBOX 129 WindowBox *winbox; 130#endif 131 Window vroot; 132 133#ifdef DEBUG 134 fprintf(stderr, "AddWindow: w = 0x%x\n", w); 135#endif 136 137#ifdef CAPTIVE 138 /* 139 * Possibly this window should be in a captive sub-ctwm? If so, we 140 * shouldn't mess with it at all. 141 */ 142 if(!CLarg.is_captive && RedirectToCaptive(w)) { 143 /* XXX x-ref comment by SetNoRedirect() */ 144 return (NULL); 145 } 146#endif 147 148 149 /* 150 * Allocate and initialize our tracking struct 151 */ 152 tmp_win = calloc(1, sizeof(TwmWindow)); 153 if(tmp_win == NULL) { 154 fprintf(stderr, "%s: Unable to allocate memory to manage window ID %lx.\n", 155 ProgramName, w); 156 return NULL; 157 } 158 159 /* 160 * Some of these initializations are strictly unnecessary, since they 161 * evaluate out to 0, and calloc() gives us an already zero'd buffer. 162 * I'm leaving them anyway because a couple unnecessary stores are 163 * near enough to free considering everything we're doing, that the 164 * value as documentation stupendously outweighs the cost. 165 */ 166 tmp_win->w = w; 167 tmp_win->zoomed = ZOOM_NONE; 168 tmp_win->isiconmgr = (wtype == AWT_ICON_MANAGER); 169 tmp_win->iconmgrp = iconp; 170 tmp_win->iswspmgr = (wtype == AWT_WORKSPACE_MANAGER); 171 tmp_win->isoccupy = (wtype == AWT_OCCUPY); 172#ifdef WINBOX 173 tmp_win->iswinbox = (wtype == AWT_WINDOWBOX); 174#endif 175 tmp_win->vs = vs; 176 tmp_win->parent_vs = vs; 177 tmp_win->savevs = NULL; 178 tmp_win->cmaps.number_cwins = 0; 179 tmp_win->savegeometry.width = -1; 180 tmp_win->widthEverChangedByUser = false; 181 tmp_win->heightEverChangedByUser = false; 182 tmp_win->nameChanged = false; 183 tmp_win->squeezed = false; 184 tmp_win->iconified = false; 185 tmp_win->isicon = false; 186 tmp_win->icon_on = false; 187 tmp_win->ring.cursor_valid = false; 188 tmp_win->squeeze_info = NULL; 189 tmp_win->squeeze_info_copied = false; 190 191 192 193 /* 194 * Fetch a few bits of info about the window from the server, and 195 * tell the server to tell us about property changes; we'll need to 196 * know what happens. 197 * 198 * It's important that these remain relatively disconnected "early" 199 * bits; generally, they shouldn't rely on anything but the X Window 200 * in tmp_win->w to do their stuff. e.g., anything that relies on 201 * other values in our ctwm TwmWindow tmp_win (window name, various 202 * flags, etc) has to come later. 203 */ 204 XSelectInput(dpy, tmp_win->w, PropertyChangeMask); 205 XGetWindowAttributes(dpy, tmp_win->w, &tmp_win->attr); 206 FetchWmProtocols(tmp_win); 207 FetchWmColormapWindows(tmp_win); 208#ifdef EWMH 209 EwmhGetProperties(tmp_win); 210#endif /* EWMH */ 211 212 213 /* 214 * Some other simple early initialization that has to follow those 215 * bits. 216 */ 217 tmp_win->old_bw = tmp_win->attr.border_width; 218 219 220 /* 221 * Setup window name and class bits. A lot of following code starts 222 * to care about this; in particular, anything looking in our 223 * name_lists generally goes by the name/class, so we need to get 224 * these set pretty early in the process. 225 */ 226 tmp_win->names.ctwm_wm_name = GetWMPropertyString(tmp_win->w, 227 XA_CTWM_WM_NAME); 228#ifdef EWMH 229 tmp_win->names.net_wm_name = GetWMPropertyString(tmp_win->w, 230 XA__NET_WM_NAME); 231#endif 232 tmp_win->names.wm_name = GetWMPropertyString(tmp_win->w, XA_WM_NAME); 233 set_window_name(tmp_win); 234 namelen = strlen(tmp_win->name); 235 236 /* Setup class. x-ref XXX in ctwm_main() about NoClass */ 237 tmp_win->class = NoClass; 238 XGetClassHint(dpy, tmp_win->w, &tmp_win->class); 239 if(tmp_win->class.res_name == NULL) { 240 tmp_win->class.res_name = NoName; 241 } 242 if(tmp_win->class.res_class == NULL) { 243 tmp_win->class.res_class = NoName; 244 } 245 246 /* Grab the icon name too */ 247 tmp_win->names.ctwm_wm_icon_name = GetWMPropertyString(tmp_win->w, 248 XA_CTWM_WM_ICON_NAME); 249#ifdef EWMH 250 tmp_win->names.net_wm_icon_name = GetWMPropertyString(tmp_win->w, 251 XA__NET_WM_ICON_NAME); 252#endif 253 tmp_win->names.wm_icon_name = GetWMPropertyString(tmp_win->w, 254 XA_WM_ICON_NAME); 255 set_window_icon_name(tmp_win); 256 257 258 /* Convenience macro */ 259#define CHKL(lst) IsInList(Scr->lst, tmp_win) 260 261 262 /* Is it a transient? Or should we ignore that it is? */ 263 tmp_win->istransient = XGetTransientForHint(dpy, tmp_win->w, 264 &tmp_win->transientfor); 265 if(tmp_win->istransient) { 266 /* 267 * XXX Should this be looking up transientfor instead of tmp_win? 268 * It seems like IgnoreTransient {} would list the windows that 269 * have transients we should ignore, while this condition makes 270 * it list the transient window names we should ignore. Probably 271 * not trivial to fix if that's right, since it might b0rk 272 * existing configs... 273 */ 274 if(CHKL(IgnoreTransientL)) { 275 tmp_win->istransient = false; 276 } 277 } 278 279 280#ifdef SESSION 281 /* 282 * Look up saved X Session info for the window if we have it. 283 */ 284 { 285 short saved_x, saved_y; 286 unsigned short saved_width, saved_height; 287 bool width_ever_changed_by_user; 288 bool height_ever_changed_by_user; 289 290 if(GetWindowConfig(tmp_win, 291 &saved_x, &saved_y, &saved_width, &saved_height, 292 &restore_iconified, &restore_icon_info_present, 293 &restore_icon_x, &restore_icon_y, 294 &width_ever_changed_by_user, 295 &height_ever_changed_by_user, 296 &saved_occupation)) { 297 /* Got saved info, use it */ 298 restoredFromPrevSession = true; 299 300 tmp_win->attr.x = saved_x; 301 tmp_win->attr.y = saved_y; 302 303 tmp_win->widthEverChangedByUser = width_ever_changed_by_user; 304 tmp_win->heightEverChangedByUser = height_ever_changed_by_user; 305 306 if(width_ever_changed_by_user) { 307 tmp_win->attr.width = saved_width; 308 } 309 310 if(height_ever_changed_by_user) { 311 tmp_win->attr.height = saved_height; 312 } 313 } 314 } 315#endif 316 317 318 /* 319 * Clip window to maximum size (either built-in ceiling, or 320 * config MaxWindowSize). 321 * 322 * Should look at window gravity? 323 */ 324 if(tmp_win->attr.width > Scr->MaxWindowWidth) { 325 tmp_win->attr.width = Scr->MaxWindowWidth; 326 } 327 if(tmp_win->attr.height > Scr->MaxWindowHeight) { 328 tmp_win->attr.height = Scr->MaxWindowHeight; 329 } 330 331 332 /* 333 * Setup WM_HINTS bits. If we get nothing, we hardcode an 334 * assumption. 335 */ 336 tmp_win->wmhints = XGetWMHints(dpy, tmp_win->w); 337 if(!tmp_win->wmhints) { 338 tmp_win->wmhints = gen_synthetic_wmhints(tmp_win); 339 if(!tmp_win->wmhints) { 340 fprintf(stderr, "Failed allocating memory for hints!\n"); 341 free(tmp_win); // XXX leaky 342 return NULL; 343 } 344 } 345 346#ifdef SESSION 347 /* 348 * Override a few bits with saved stuff from previous session, if we 349 * have it. 350 */ 351 if(restore_iconified) { 352 tmp_win->wmhints->initial_state = IconicState; 353 tmp_win->wmhints->flags |= StateHint; 354 } 355 356 if(restore_icon_info_present) { 357 tmp_win->wmhints->icon_x = restore_icon_x; 358 tmp_win->wmhints->icon_y = restore_icon_y; 359 tmp_win->wmhints->flags |= IconPositionHint; 360 } 361#endif 362 363 /* Munge as necessary for other stuff */ 364 munge_wmhints(tmp_win, tmp_win->wmhints); 365 366 367 /* 368 * Various flags that may be screen-wide or window specific. 369 */ 370 tmp_win->highlight = Scr->Highlight && !CHKL(NoHighlight); 371 tmp_win->stackmode = Scr->StackMode && !CHKL(NoStackModeL); 372 tmp_win->titlehighlight = Scr->TitleHighlight && !CHKL(NoTitleHighlight); 373 tmp_win->AlwaysSqueezeToGravity = Scr->AlwaysSqueezeToGravity 374 || CHKL(AlwaysSqueezeToGravityL); 375 tmp_win->DontSetInactive = CHKL(DontSetInactive); 376 tmp_win->AutoSqueeze = CHKL(AutoSqueeze); 377 tmp_win->StartSqueezed = 378#ifdef EWMH 379 (tmp_win->ewmhFlags & EWMH_STATE_SHADED) || 380#endif /* EWMH */ 381 CHKL(StartSqueezed); 382 383 tmp_win->auto_raise = Scr->AutoRaiseDefault || CHKL(AutoRaise); 384 if(tmp_win->auto_raise) { 385 Scr->NumAutoRaises++; 386 } 387 388 tmp_win->auto_lower = Scr->AutoLowerDefault || CHKL(AutoLower); 389 if(tmp_win->auto_lower) { 390 Scr->NumAutoLowers++; 391 } 392 393 tmp_win->OpaqueMove = Scr->DoOpaqueMove; 394 if(CHKL(OpaqueMoveList)) { 395 tmp_win->OpaqueMove = true; 396 } 397 else if(CHKL(NoOpaqueMoveList)) { 398 tmp_win->OpaqueMove = false; 399 } 400 401 tmp_win->OpaqueResize = Scr->DoOpaqueResize; 402 if(CHKL(OpaqueResizeList)) { 403 tmp_win->OpaqueResize = true; 404 } 405 else if(CHKL(NoOpaqueResizeList)) { 406 tmp_win->OpaqueResize = false; 407 } 408 409 410 /* 411 * If a window is listed in IconifyByUnmapping {}, we always iconify 412 * by unmapping. Else, if it's DontIconifyByUnmapping {} or is an 413 * icon manager, we don't i_b_u. Else, we go with the Scr-wide 414 * default. 415 */ 416 { 417 bool ibum = CHKL(IconifyByUn); 418 if(!ibum) { 419 if(tmp_win->isiconmgr || CHKL(DontIconify)) { 420 ibum = false; // redundant 421 } 422 else { 423 ibum = Scr->IconifyByUnmapping; 424 } 425 } 426 tmp_win->iconify_by_unmapping = ibum; 427 } 428 429 430 /* 431 * For transient windows or group members, we copy in UBMFA from its 432 * parent/leader/etc if we can find it. Otherwise, it's just whether 433 * it's in the config list. 434 */ 435 tmp_win->UnmapByMovingFarAway = CHKL(UnmapByMovingFarAway); 436 if(tmp_win->istransient || tmp_win->group) { 437 TwmWindow *t = NULL; 438 if(tmp_win->istransient) { 439 t = GetTwmWindow(tmp_win->transientfor); 440 } 441 if(!t && tmp_win->group) { 442 t = GetTwmWindow(tmp_win->group); 443 } 444 if(t) { 445 tmp_win->UnmapByMovingFarAway = t->UnmapByMovingFarAway; 446 } 447 } 448 449 450 /* 451 * Link it up into the window ring if we should. If it's in 452 * WindowRing {}, we should. Otherwise, we shouldn't unless 453 * WindowRingAll is set. If it is, we still exclude several special 454 * ctwm windows, stuff in WindowRingExclude {}, and some special EWMH 455 * settings. 456 */ 457 if(CHKL(WindowRingL) || 458 (Scr->WindowRingAll && !tmp_win->iswspmgr 459 && !tmp_win->isiconmgr 460#ifdef EWMH 461 && EwmhOnWindowRing(tmp_win) 462#endif /* EWMH */ 463 && !CHKL(WindowRingExcludeL))) { 464 AddWindowToRing(tmp_win); 465 } 466 else { 467 InitWindowNotOnRing(tmp_win); 468 } 469 470 471 /* 472 * Setup squeezing info. We don't bother unless the server has Shape 473 * available, and the window isn't in our DontSqueezeTitle list. 474 * Else, we do/not based on the SqueezeTitle setting. Note that 475 * "SqueezeTitle" being specified at all squeezes everything; its 476 * argument list lets you set specific squeeze params for specific 477 * windows, but other windows still get the default. 478 * 479 * Note that this does not have to be freed yet since it is coming 480 * from the screen list or from default_squeeze. Places that change 481 * it [re]set squeeze_info_copied, and then the destroy handler looks 482 * at that to determine whether to free squeeze_info. 483 * 484 * XXX Technically, the HasShape test is redundant, since the config 485 * file parsing would never set Scr->SqueezeTitle unless HasShape 486 * were true anyway... 487 */ 488 if(HasShape && Scr->SqueezeTitle && !CHKL(DontSqueezeTitleL)) { 489 tmp_win->squeeze_info = LookInListWin(Scr->SqueezeTitleL, tmp_win); 490 if(!tmp_win->squeeze_info) { 491 static SqueezeInfo default_squeeze = { SIJ_LEFT, 0, 0 }; 492 tmp_win->squeeze_info = &default_squeeze; 493 } 494 } 495 496 497 /* 498 * Motif WM hints are used in setting up border and titlebar bits, so 499 * put them in a block here to scope the MWM var. 500 */ 501 { 502 MotifWmHints mwmHints; 503 bool have_title; 504 505 GetMWMHints(tmp_win->w, &mwmHints); 506 507 /* 508 * Figure border bits. These are all exclusive cases, so it 509 * winds up being first-match. 510 * 511 * - EWMH, MWM hints, and NoBorder{} can tell us to use none. 512 * - ThreeDBorderWidth means use it and no regular 2d frame_bw. 513 * - ClientBorderWidth tells us to use the XWindowAttributes 514 * border size rather than ours. 515 * - Else, our BorderWidth is the [2d] border size. 516 * 517 * X-ref comments in win_decorations.c:SetBorderCursor() about 518 * the somewhat differing treatment of 3d vs non-3d border widths 519 * and their effects on the window coordinates. 520 */ 521 tmp_win->frame_bw3D = Scr->ThreeDBorderWidth; 522 if( 523#ifdef EWMH 524 !EwmhHasBorder(tmp_win) || 525#endif /* EWMH */ 526 (mwm_has_border(&mwmHints) == 0) || 527 CHKL(NoBorder)) { 528 tmp_win->frame_bw = 0; 529 tmp_win->frame_bw3D = 0; 530 } 531 else if(tmp_win->frame_bw3D != 0) { 532 tmp_win->frame_bw = 0; 533 } 534 else if(Scr->ClientBorderWidth) { 535 tmp_win->frame_bw = tmp_win->old_bw; 536 } 537 else { 538 tmp_win->frame_bw = Scr->BorderWidth; 539 } 540 bw2 = tmp_win->frame_bw * 2; // Used repeatedly later 541 542 543 /* 544 * Now, what about the titlebar? 545 * 546 * - Default to showing, 547 * - Then EWMH gets to say no in some special cases, 548 * - Then MWM can say yes/no (or refuse to say anything), 549 * - NoTitle (general setting) gets to override all of that, 550 * - Specific MakeTitle beats general NoTitle, 551 * - And specific NoTitle overrides MakeTitle. 552 */ 553 have_title = true; 554 ALLOW_DEAD_STORE(have_title); 555#ifdef EWMH 556 have_title = EwmhHasTitle(tmp_win); 557#endif /* EWMH */ 558 if(mwm_sets_title(&mwmHints)) { 559 have_title = mwm_has_title(&mwmHints); 560 } 561 if(Scr->NoTitlebar) { 562 have_title = false; 563 } 564 if(CHKL(MakeTitle)) { 565 have_title = true; 566 } 567 if(CHKL(NoTitle)) { 568 have_title = false; 569 } 570 571 /* 572 * Now mark up how big to make it. title_height sets how tall 573 * the titlebar is, with magic treating 0 as "don't make a 574 * titlebar". We only care about adding frame_bw and never 575 * frame_bw3D, since the 3d case interprets all the inner 576 * coordinates differently (x-ref above x-ref). 577 * 578 * Transients may not be decorated regardless of the above 579 * figuring, so handle that here too. 580 */ 581 if(tmp_win->istransient && !Scr->DecorateTransients) { 582 tmp_win->title_height = 0; 583 } 584 else if(have_title) { 585 tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw; 586 } 587 else { 588 tmp_win->title_height = 0; 589 } 590 } 591 592 593#ifdef EWMH 594 /* 595 * Now that we know the title_height and the frame border width, we 596 * can set an EWMH property to tell the client how much we're adding 597 * around them. 598 */ 599 EwmhSet_NET_FRAME_EXTENTS(tmp_win); 600#endif 601 602 603 /* 604 * Need the GetWindowAttributes() call and setting ->old_bw and 605 * ->frame_bw3D for some of the math in looking up the 606 * WM_NORMAL_HINTS bits, so now we can do that. 607 */ 608 GetWindowSizeHints(tmp_win); 609 610 611 /* Maybe we're ordering it to start off iconified? */ 612 if(CHKL(StartIconified)) { 613 tmp_win->wmhints->initial_state = IconicState; 614 tmp_win->wmhints->flags |= StateHint; 615 } 616 617 618 /* 619 * Figure gravity bits. When restoring from a previous session, we 620 * always use NorthWest gravity. 621 */ 622 if(restoredFromPrevSession) { 623 gravx = gravy = -1; 624 } 625 else { 626 GetGravityOffsets(tmp_win, &gravx, &gravy); 627 } 628 629 630 /* So far that's the end of where we're using this */ 631#undef CHKL 632 633 634 /* 635 * Now we start getting more into the active bits of things. Start 636 * figuring out how we'll decide where to position it. ask_user is 637 * slightly misnamed, as it doesn't actually mean ask the user, but 638 * rather whether the user/WM gets to choose or whether the 639 * application does. That is, we only case about whether or not 640 * RandomPlacement if(ask_user==true) anyway. ask_user=false means 641 * we just go with what's in the window's XWindowAttributes bits. 642 * 643 * We don't even consider overriding the window if: 644 * 645 * - It's a transient, or 646 * - the WM_NORMAL_HINTS property gave us a user-specified position 647 * (USPosition), or 648 * - the hints gave us a a program-specific position (PPosition), and 649 * the UsePPosition config param specifies we should use it. 650 * 651 * x-ref ICCCM discussion of WM_NORMAL_HINTS for some details on the 652 * flags 653 * (https://www.x.org/releases/X11R7.7/doc/xorg-docs/icccm/icccm.html#Client_Properties) 654 */ 655 ask_user = true; 656 if(tmp_win->istransient) { 657 ask_user = false; 658 } 659 else if(tmp_win->hints.flags & USPosition) { 660 ask_user = false; 661 } 662 else if(tmp_win->hints.flags & PPosition) { 663 if(Scr->UsePPosition == PPOS_ON) { 664 ask_user = false; 665 } 666 else if(Scr->UsePPosition == PPOS_NON_ZERO 667 && (tmp_win->attr.x != 0 || tmp_win->attr.y != 0)) { 668 ask_user = false; 669 } 670 } 671 672 673 /* 674 * Set the window occupation. If we pulled previous Session info, 675 * saved_occupation may have data from it that will be used; 676 * otherwise it's already zeroed and has no effect. X-ref XXX 677 * comment on SetupOccupation() for notes on order of application of 678 * various sources for occupation. 679 * 680 * Note that SetupOccupation() may update tmp_win->{parent_,}vs if 681 * needed to make the window visible in another vscreen. It may also 682 * set tmp_win->vs to NULL if it has no occupation in the current 683 * workspace. 684 */ 685 SetupOccupation(tmp_win, saved_occupation); 686 687 688#ifdef WINBOX 689 /* Does it go in a window box? */ 690 winbox = findWindowBox(tmp_win); 691#endif 692 693 694 /* 695 * Set some values for the frame size. 696 * 697 * These get redone down below when we create the frame, when they're 698 * actually useful. So why bother here? There is some code down in 699 * the block where we prompt for a window position that calls some 700 * functions that need plausible values in them. However, those code 701 * blocks calculate and set values themselves, so there shouldn't be 702 * any actual need for them here. Left #if'd out for the present in 703 * case something turns up; this should be GC'd at some point if 704 * nothing does. 705 */ 706#if 0 707 tmp_win->frame_width = tmp_win->attr.width + 2 * tmp_win->frame_bw3D; 708 tmp_win->frame_height = tmp_win->attr.height + 2 * tmp_win->frame_bw3D + 709 tmp_win->title_height; 710 ConstrainSize(tmp_win, &tmp_win->frame_width, &tmp_win->frame_height); 711#endif 712 713 714 /* 715 * See if there's a WindowRegion we should honor. If so, it'll set 716 * the X/Y coords, and we'll want to accept them instead of doing our 717 * own (or the user's) positioning. 718 * 719 * This needs the frame_{width,height}. 720 */ 721 if(PlaceWindowInRegion(tmp_win, &(tmp_win->attr.x), &(tmp_win->attr.y))) { 722 ask_user = false; 723 } 724 725 726 /* 727 * Maybe we have WindowGeometries {} set for it? If so, we'll take 728 * that as our specifics too. 729 */ 730 { 731 char *geom = LookInListWin(Scr->WindowGeometries, tmp_win); 732 if(geom) { 733 int mask = RLayoutXParseGeometry(Scr->Layout, geom, 734 &tmp_win->attr.x, &tmp_win->attr.y, 735 (unsigned int *) &tmp_win->attr.width, 736 (unsigned int *) &tmp_win->attr.height); 737 738 if(mask & XNegative) { 739 tmp_win->attr.x += Scr->rootw - tmp_win->attr.width; 740 } 741 if(mask & YNegative) { 742 tmp_win->attr.y += Scr->rooth - tmp_win->attr.height; 743 } 744 ask_user = false; 745 } 746 } 747 748 749 /* Figure up what root window we should be working in */ 750 if(tmp_win->parent_vs) { 751 vroot = tmp_win->parent_vs->window; 752 } 753 else { 754 vroot = Scr->Root; /* never */ 755 tmp_win->parent_vs = Scr->currentvs; 756 } 757#ifdef WINBOX 758 if(winbox) { 759 vroot = winbox->window; 760 } 761#endif 762 763 764 /* 765 * Handle positioning of the window. If we're very early in startup 766 * (setting up ctwm's own windows, taking over windows already on the 767 * screen), or restoring defined session stuff, or otherwise 768 * ask_user=false'd above, we just take the already set position 769 * info. Otherwise, we handle it via RandomPlacement or user outline 770 * setting. 771 * 772 * XXX Somebody should go through these blocks in more detail, 773 * they're sure to need further cleaning and commenting. IWBNI they 774 * could be encapsulated well enough to move out into separate 775 * functions, for extra readability... 776 */ 777 if(HandlingEvents && ask_user && !restoredFromPrevSession) { 778 if((Scr->RandomPlacement == RP_ALL) || 779 ((Scr->RandomPlacement == RP_UNMAPPED) && 780 ((tmp_win->wmhints->initial_state == IconicState) || 781 (! visible(tmp_win))))) { 782 /* just stick it somewhere */ 783 784#ifdef DEBUG 785 fprintf(stderr, 786 "DEBUG[RandomPlacement]: win: %dx%d+%d+%d, screen: %dx%d, title height: %d, random: +%d+%d\n", 787 tmp_win->attr.width, tmp_win->attr.height, 788 tmp_win->attr.x, tmp_win->attr.y, 789 Scr->rootw, Scr->rooth, 790 tmp_win->title_height, 791 PlaceX, PlaceY); 792#endif 793 794 /* Initiallise PlaceX and PlaceY */ 795 if(PlaceX < 0 && PlaceY < 0) { 796 if(Scr->RandomDisplacementX >= 0) { 797 PlaceX = Scr->BorderLeft + 5; 798 } 799 else { 800 PlaceX = Scr->rootw - tmp_win->attr.width - Scr->BorderRight - 5; 801 } 802 if(Scr->RandomDisplacementY >= 0) { 803 PlaceY = Scr->BorderTop + 5; 804 } 805 else 806 PlaceY = Scr->rooth - tmp_win->attr.height - tmp_win->title_height 807 - Scr->BorderBottom - 5; 808 } 809 810 /* For a positive horizontal displacement, if the right edge 811 of the window would fall outside of the screen, start over 812 by placing the left edge of the window 5 pixels inside 813 the left edge of the screen.*/ 814 if(Scr->RandomDisplacementX >= 0 815 && (PlaceX + tmp_win->attr.width 816 > Scr->rootw - Scr->BorderRight - 5)) { 817 PlaceX = Scr->BorderLeft + 5; 818 } 819 820 /* For a negative horizontal displacement, if the left edge 821 of the window would fall outside of the screen, start over 822 by placing the right edge of the window 5 pixels inside 823 the right edge of the screen.*/ 824 if(Scr->RandomDisplacementX < 0 && PlaceX < Scr->BorderLeft + 5) { 825 PlaceX = Scr->rootw - tmp_win->attr.width - Scr->BorderRight - 5; 826 } 827 828 /* For a positive vertical displacement, if the bottom edge 829 of the window would fall outside of the screen, start over 830 by placing the top edge of the window 5 pixels inside the 831 top edge of the screen. Because we add the title height 832 further down, we need to count with it here as well. */ 833 if(Scr->RandomDisplacementY >= 0 834 && (PlaceY + tmp_win->attr.height + tmp_win->title_height 835 > Scr->rooth - Scr->BorderBottom - 5)) { 836 PlaceY = Scr->BorderTop + 5; 837 } 838 839 /* For a negative vertical displacement, if the top edge of 840 the window would fall outside of the screen, start over by 841 placing the bottom edge of the window 5 pixels inside the 842 bottom edge of the screen. Because we add the title height 843 further down, we need to count with it here as well. */ 844 if(Scr->RandomDisplacementY < 0 && PlaceY < Scr->BorderTop + 5) 845 PlaceY = Scr->rooth - tmp_win->attr.height - tmp_win->title_height 846 - Scr->BorderBottom - 5; 847 848 /* Assign the current random placement to the new window, as 849 a preliminary measure. Add the title height so things will 850 look right. */ 851 tmp_win->attr.x = PlaceX; 852 tmp_win->attr.y = PlaceY + tmp_win->title_height; 853 854 /* If the window is not supposed to move off the screen, check 855 that it's still within the screen, and if not, attempt to 856 correct the situation. */ 857 if(Scr->DontMoveOff) { 858 int available; 859 860#ifdef DEBUG 861 fprintf(stderr, 862 "DEBUG[DontMoveOff]: win: %dx%d+%d+%d, screen: %dx%d, bw2: %d, bw3D: %d\n", 863 tmp_win->attr.width, tmp_win->attr.height, 864 tmp_win->attr.x, tmp_win->attr.y, 865 Scr->rootw, Scr->rooth, 866 bw2, tmp_win->frame_bw3D); 867#endif 868 869 /* If the right edge of the window is outside the right edge 870 of the screen, we need to move the window left. Note that 871 this can only happen with windows that are less than 50 872 pixels less wide than the screen. */ 873 if((tmp_win->attr.x + tmp_win->attr.width) > Scr->rootw) { 874 available = Scr->rootw - tmp_win->attr.width 875 - 2 * tmp_win->frame_bw3D - bw2; 876 877#ifdef DEBUG 878 fprintf(stderr, "DEBUG[DontMoveOff]: availableX: %d\n", 879 available); 880#endif 881 882 /* If the window is wider than the screen or exactly the width 883 of the screen, the availability is exactly 0. The result 884 will be to have the window placed as much to the left as 885 possible. */ 886 if(available <= 0) { 887 available = 0; 888 } 889 890 /* Place the window exactly between the left and right edge of 891 the screen when possible. If available was originally less 892 than zero, it means the window's left edge will be against 893 the screen's left edge, and the window's right edge will be 894 outside the screen. */ 895 tmp_win->attr.x = available / 2; 896 } 897 898 /* If the bottom edge of the window is outside the bottom edge 899 of the screen, we need to move the window up. Note that 900 this can only happen with windows that are less than 50 901 pixels less tall than the screen. Don't forget to count 902 with the title height and the frame widths. */ 903 if((tmp_win->attr.y + tmp_win->attr.height) > Scr->rooth) { 904 available = Scr->rooth - tmp_win->attr.height 905 - tmp_win->title_height 906 - 2 * tmp_win->frame_bw3D - bw2; 907 908#ifdef DEBUG 909 fprintf(stderr, "DEBUG[DontMoveOff]: availableY: %d\n", 910 available); 911#endif 912 913 /* If the window is taller than the screen or exactly the 914 height of the screen, the availability is exactly 0. 915 The result will be to have the window placed as much to 916 the top as possible. */ 917 if(available <= 0) { 918 available = 0; 919 } 920 921 /* Place the window exactly between the top and bottom edge of 922 the screen when possible. If available was originally less 923 than zero, it means the window's top edge will be against 924 the screen's top edge, and the window's bottom edge will be 925 outside the screen. Again, don't forget to add the title 926 height. */ 927 tmp_win->attr.y = available / 2 + tmp_win->title_height; 928 } 929 930#ifdef DEBUG 931 fprintf(stderr, 932 "DEBUG[DontMoveOff]: win: %dx%d+%d+%d, screen: %dx%d\n", 933 tmp_win->attr.width, tmp_win->attr.height, 934 tmp_win->attr.x, tmp_win->attr.y, 935 Scr->rootw, Scr->rooth); 936#endif 937 } 938 939 /* We know that if the window's left edge has moved compared to 940 PlaceX, it will have moved to the left. If it was moved less 941 than 15 pixel either way, change the next "random position" 942 30 pixels down and right. */ 943 if(PlaceX - tmp_win->attr.x < 15 944 || PlaceY - (tmp_win->attr.y - tmp_win->title_height) < 15) { 945 PlaceX += Scr->RandomDisplacementX; 946 PlaceY += Scr->RandomDisplacementY; 947 } 948 949 random_placed = true; 950 } 951 else if(!(tmp_win->wmhints->flags & StateHint && 952 tmp_win->wmhints->initial_state == IconicState)) { 953 /* else prompt */ 954 bool firsttime = true; 955 int found = 0; 956 int width, height; 957 XEvent event; 958 959 /* better wait until all the mouse buttons have been 960 * released. 961 */ 962 while(1) { 963 unsigned int qpmask; 964 Window qproot; 965 int stat; 966 967 XUngrabServer(dpy); 968 XSync(dpy, 0); 969 XGrabServer(dpy); 970 971 qpmask = 0; 972 if(!XQueryPointer(dpy, Scr->Root, &qproot, 973 &JunkChild, &JunkX, &JunkY, 974 &AddingX, &AddingY, &qpmask)) { 975 qpmask = 0; 976 } 977 978 /* Clear out any but the Button bits */ 979 qpmask &= (Button1Mask | Button2Mask | Button3Mask | 980 Button4Mask | Button5Mask); 981 982 /* 983 * watch out for changing screens 984 */ 985 if(firsttime) { 986 if(qproot != Scr->Root) { 987 int scrnum; 988 for(scrnum = 0; scrnum < NumScreens; scrnum++) { 989 if(qproot == RootWindow(dpy, scrnum)) { 990 break; 991 } 992 } 993 if(scrnum != NumScreens) { 994 PreviousScreen = scrnum; 995 } 996 } 997 if(Scr->currentvs) { 998 vroot = Scr->currentvs->window; 999 } 1000 firsttime = false; 1001 } 1002#ifdef WINBOX 1003 if(winbox) { 1004 vroot = winbox->window; 1005 } 1006#endif 1007 1008 /* 1009 * wait for buttons to come up; yuck 1010 */ 1011 if(qpmask != 0) { 1012 continue; 1013 } 1014 1015 /* 1016 * this will cause a warp to the indicated root 1017 */ 1018 stat = XGrabPointer(dpy, vroot, False, 1019 ButtonPressMask | ButtonReleaseMask | 1020 PointerMotionMask | PointerMotionHintMask, 1021 GrabModeAsync, GrabModeAsync, 1022 vroot, UpperLeftCursor, CurrentTime); 1023 if(stat == GrabSuccess) { 1024 break; 1025 } 1026 } 1027 1028 { 1029 XRectangle ink_rect; 1030 XRectangle logical_rect; 1031 1032 XmbTextExtents(Scr->SizeFont.font_set, 1033 tmp_win->name, namelen, 1034 &ink_rect, &logical_rect); 1035 width = SIZE_HINDENT + ink_rect.width; 1036 height = Scr->SizeFont.height + SIZE_VINDENT * 2; 1037 1038 XmbTextExtents(Scr->SizeFont.font_set, 1039 ": ", 2, NULL, &logical_rect); 1040 Scr->SizeStringOffset = width + logical_rect.width; 1041 } 1042 1043 MoveResizeSizeWindow(AddingX, AddingY, 1044 Scr->SizeStringOffset + Scr->SizeStringWidth + SIZE_HINDENT, 1045 height); 1046 XMapRaised(dpy, Scr->SizeWindow); 1047 InstallRootColormap(); 1048 FB(Scr->DefaultC.fore, Scr->DefaultC.back); 1049 XmbDrawImageString(dpy, Scr->SizeWindow, Scr->SizeFont.font_set, 1050 Scr->NormalGC, SIZE_HINDENT, 1051 SIZE_VINDENT + Scr->SizeFont.ascent, 1052 tmp_win->name, namelen); 1053 1054#ifdef WINBOX 1055 if(winbox) { 1056 ConstrainedToWinBox(tmp_win, AddingX, AddingY, &AddingX, &AddingY); 1057 } 1058#endif 1059 1060 AddingW = tmp_win->attr.width + bw2 + 2 * tmp_win->frame_bw3D; 1061 AddingH = tmp_win->attr.height + tmp_win->title_height + 1062 bw2 + 2 * tmp_win->frame_bw3D; 1063 MoveOutline(vroot, AddingX, AddingY, AddingW, AddingH, 1064 tmp_win->frame_bw, tmp_win->title_height + tmp_win->frame_bw3D); 1065 1066 XmbDrawImageString(dpy, Scr->SizeWindow, Scr->SizeFont.font_set, 1067 Scr->NormalGC, width, 1068 SIZE_VINDENT + Scr->SizeFont.ascent, ": ", 2); 1069 DisplayPosition(tmp_win, AddingX, AddingY); 1070 1071 /* 1072 * The TryTo*() and DoResize() calls below rely on having 1073 * frame_{width,height} set, so set them. 1074 */ 1075 tmp_win->frame_width = AddingW - bw2; 1076 tmp_win->frame_height = AddingH - bw2; 1077 /*SetFocus (NULL, CurrentTime);*/ 1078 while(1) { 1079 if(Scr->OpenWindowTimeout) { 1080 const int fd = ConnectionNumber(dpy); 1081 while(!XCheckMaskEvent(dpy, ButtonMotionMask | ButtonPressMask, &event)) { 1082 fd_set mask; 1083 struct timeval timeout = { 1084 .tv_sec = Scr->OpenWindowTimeout, 1085 .tv_usec = 0, 1086 }; 1087 1088 FD_ZERO(&mask); 1089 FD_SET(fd, &mask); 1090 found = select(fd + 1, &mask, NULL, NULL, &timeout); 1091 if(found == 0) { 1092 break; 1093 } 1094 } 1095 if(found == 0) { 1096 break; 1097 } 1098 } 1099 else { 1100 found = 1; 1101 XMaskEvent(dpy, ButtonPressMask | PointerMotionMask, &event); 1102 } 1103 if(event.type == MotionNotify) { 1104 /* discard any extra motion events before a release */ 1105 while(XCheckMaskEvent(dpy, 1106 ButtonMotionMask | ButtonPressMask, &event)) 1107 if(event.type == ButtonPress) { 1108 break; 1109 } 1110 } 1111 FixRootEvent(&event); 1112 if(event.type == ButtonPress) { 1113 AddingX = event.xbutton.x_root; 1114 AddingY = event.xbutton.y_root; 1115 1116 /* TryTo*() need tmp_win->frame_{width,height} */ 1117 TryToGrid(tmp_win, &AddingX, &AddingY); 1118 if(Scr->PackNewWindows) { 1119 TryToPack(tmp_win, &AddingX, &AddingY); 1120 } 1121 1122 /* DontMoveOff prohibits user from off-screen placement */ 1123 if(Scr->DontMoveOff) { 1124 ConstrainByBorders(tmp_win, &AddingX, AddingW, &AddingY, AddingH); 1125 } 1126 break; 1127 } 1128 1129 if(event.type != MotionNotify) { 1130 continue; 1131 } 1132 1133 XQueryPointer(dpy, vroot, &JunkRoot, &JunkChild, 1134 &JunkX, &JunkY, &AddingX, &AddingY, &JunkMask); 1135 1136 TryToGrid(tmp_win, &AddingX, &AddingY); 1137 if(Scr->PackNewWindows) { 1138 TryToPack(tmp_win, &AddingX, &AddingY); 1139 } 1140 if(Scr->DontMoveOff) { 1141 ConstrainByBorders(tmp_win, &AddingX, AddingW, &AddingY, AddingH); 1142 } 1143 MoveOutline(vroot, AddingX, AddingY, AddingW, AddingH, 1144 tmp_win->frame_bw, tmp_win->title_height + tmp_win->frame_bw3D); 1145 1146 DisplayPosition(tmp_win, AddingX, AddingY); 1147 } 1148 1149 if(found) { 1150 if(event.xbutton.button == Button2) { 1151 int lastx, lasty; 1152 XRectangle logical_rect; 1153 1154 XmbTextExtents(Scr->SizeFont.font_set, 1155 ": ", 2, NULL, &logical_rect); 1156 Scr->SizeStringOffset = width + logical_rect.width; 1157 1158 MoveResizeSizeWindow(event.xbutton.x_root, event.xbutton.y_root, 1159 Scr->SizeStringOffset + Scr->SizeStringWidth + SIZE_HINDENT, 1160 height); 1161 1162 XmbDrawImageString(dpy, Scr->SizeWindow, Scr->SizeFont.font_set, 1163 Scr->NormalGC, width, 1164 SIZE_VINDENT + Scr->SizeFont.ascent, ": ", 2); 1165 1166 if(0/*Scr->AutoRelativeResize*/) { 1167 int dx = (tmp_win->attr.width / 4); 1168 int dy = (tmp_win->attr.height / 4); 1169 1170#define HALF_AVE_CURSOR_SIZE 8 /* so that it is visible */ 1171 if(dx < HALF_AVE_CURSOR_SIZE + Scr->BorderLeft) { 1172 dx = HALF_AVE_CURSOR_SIZE + Scr->BorderLeft; 1173 } 1174 if(dy < HALF_AVE_CURSOR_SIZE + Scr->BorderTop) { 1175 dy = HALF_AVE_CURSOR_SIZE + Scr->BorderTop; 1176 } 1177#undef HALF_AVE_CURSOR_SIZE 1178 dx += (tmp_win->frame_bw + 1); 1179 dy += (bw2 + tmp_win->title_height + 1); 1180 if(AddingX + dx >= Scr->rootw - Scr->BorderRight) { 1181 dx = Scr->rootw - Scr->BorderRight - AddingX - 1; 1182 } 1183 if(AddingY + dy >= Scr->rooth - Scr->BorderBottom) { 1184 dy = Scr->rooth - Scr->BorderBottom - AddingY - 1; 1185 } 1186 if(dx > 0 && dy > 0) { 1187 XWarpPointer(dpy, None, None, 0, 0, 0, 0, dx, dy); 1188 } 1189 } 1190 else { 1191 XWarpPointer(dpy, None, vroot, 0, 0, 0, 0, 1192 AddingX + AddingW / 2, AddingY + AddingH / 2); 1193 } 1194 AddStartResize(tmp_win, AddingX, AddingY, AddingW, AddingH); 1195 1196 lastx = -10000; 1197 lasty = -10000; 1198 while(1) { 1199 XMaskEvent(dpy, 1200 ButtonReleaseMask | ButtonMotionMask, &event); 1201 1202 if(event.type == MotionNotify) { 1203 /* discard any extra motion events before a release */ 1204 while(XCheckMaskEvent(dpy, 1205 ButtonMotionMask | ButtonReleaseMask, &event)) 1206 if(event.type == ButtonRelease) { 1207 break; 1208 } 1209 } 1210 FixRootEvent(&event); 1211 1212 if(event.type == ButtonRelease) { 1213 AddEndResize(tmp_win); 1214 break; 1215 } 1216 1217 if(event.type != MotionNotify) { 1218 continue; 1219 } 1220 1221 /* 1222 * XXX - if we are going to do a loop, we ought to consider 1223 * using multiple GXxor lines so that we don't need to 1224 * grab the server. 1225 */ 1226 XQueryPointer(dpy, vroot, &JunkRoot, &JunkChild, 1227 &JunkX, &JunkY, &AddingX, &AddingY, 1228 &JunkMask); 1229 1230 if(lastx != AddingX || lasty != AddingY) { 1231 resizeWhenAdd = true; 1232 /* 1233 * DR() calls SetupWindow(), which uses 1234 * frame_{width,height}. 1235 */ 1236 DoResize(AddingX, AddingY, tmp_win); 1237 resizeWhenAdd = false; 1238 1239 lastx = AddingX; 1240 lasty = AddingY; 1241 } 1242 1243 } 1244 } 1245 else if(event.xbutton.button == Button3) { 1246 RArea area; 1247 int max_bottom, max_right; 1248 1249 area = RAreaNew(AddingX, AddingY, AddingW, AddingH); 1250 1251 max_bottom = RLayoutFindMonitorBottomEdge(Scr->BorderedLayout, &area) - bw2; 1252 max_right = RLayoutFindMonitorRightEdge(Scr->BorderedLayout, &area) - bw2; 1253 1254 /* 1255 * Make window go to bottom of screen, and clip to right edge. 1256 * This is useful when popping up large windows and fixed 1257 * column text windows. 1258 */ 1259 if(AddingX + AddingW - 1 > max_right) { 1260 AddingW = max_right - AddingX + 1; 1261 } 1262 AddingH = max_bottom - AddingY + 1; 1263 1264 ConstrainSize(tmp_win, &AddingW, &AddingH); /* w/o borders */ 1265 AddingW += bw2; 1266 AddingH += bw2; 1267 XMaskEvent(dpy, ButtonReleaseMask, &event); 1268 } 1269 else { 1270 XMaskEvent(dpy, ButtonReleaseMask, &event); 1271 } 1272 } 1273 MoveOutline(vroot, 0, 0, 0, 0, 0, 0); 1274 XUnmapWindow(dpy, Scr->SizeWindow); 1275 UninstallRootColormap(); 1276 XUngrabPointer(dpy, CurrentTime); 1277 1278 tmp_win->attr.x = AddingX; 1279 tmp_win->attr.y = AddingY + tmp_win->title_height; 1280 tmp_win->attr.width = AddingW - bw2 - 2 * tmp_win->frame_bw3D; 1281 tmp_win->attr.height = AddingH - tmp_win->title_height - 1282 bw2 - 2 * tmp_win->frame_bw3D; 1283 1284 XUngrabServer(dpy); 1285 } 1286 } 1287 else { 1288 /* 1289 * Put it where asked, mod title bar. If the gravity is towards 1290 * the top, move it by the title height. 1291 */ 1292 if(gravy < 0) { 1293 tmp_win->attr.y -= gravy * tmp_win->title_height; 1294 } 1295 } 1296 1297 1298#ifdef DEBUG 1299 fprintf(stderr, " position window %d, %d %dx%d\n", 1300 tmp_win->attr.x, 1301 tmp_win->attr.y, 1302 tmp_win->attr.width, 1303 tmp_win->attr.height); 1304#endif 1305 1306 1307 /* 1308 * Possibly need to tweak what it thinks of as its position to 1309 * account for borders. XXX Verify conditionalization and math. 1310 */ 1311 if(!Scr->ClientBorderWidth) { 1312 int delta = tmp_win->attr.border_width - tmp_win->frame_bw - 1313 tmp_win->frame_bw3D; 1314 tmp_win->attr.x += gravx * delta; 1315 tmp_win->attr.y += gravy * delta; 1316 } 1317 1318 1319 /* 1320 * Init the title width to the window's width. This will be right as 1321 * long as you're not SqueezeTitle'ing; if you are, we rejigger it in 1322 * SetupFrame(). 1323 */ 1324 tmp_win->title_width = tmp_win->attr.width; 1325 1326 1327 /* 1328 * Figure initial screen size of writing out the window name. This 1329 * is needed when laying out titlebar bits (down in the call chain 1330 * inside SetupFrame()). The event handler updates this when it 1331 * changes. 1332 */ 1333 { 1334 XRectangle logical_rect; 1335 XmbTextExtents(Scr->TitleBarFont.font_set, tmp_win->name, namelen, 1336 NULL, &logical_rect); 1337 tmp_win->name_width = logical_rect.width; 1338 } 1339 1340 1341 /* Remove original border if there is one; we make our own now */ 1342 if(tmp_win->old_bw) { 1343 XSetWindowBorderWidth(dpy, tmp_win->w, 0); 1344 } 1345 1346 1347 /* 1348 * Setup various color bits 1349 */ 1350#define SETC(lst, save) GetColorFromList(Scr->lst, tmp_win->name, \ 1351 &tmp_win->class, &tmp_win->save) 1352 1353 /* No distinction fore/back for borders in the lists */ 1354 tmp_win->borderC.fore = Scr->BorderColorC.fore; 1355 tmp_win->borderC.back = Scr->BorderColorC.back; 1356 SETC(BorderColorL, borderC.fore); 1357 SETC(BorderColorL, borderC.back); 1358 1359 tmp_win->border_tile.fore = Scr->BorderTileC.fore; 1360 tmp_win->border_tile.back = Scr->BorderTileC.back; 1361 SETC(BorderTileForegroundL, border_tile.fore); 1362 SETC(BorderTileBackgroundL, border_tile.back); 1363 1364 tmp_win->title.fore = Scr->TitleC.fore; 1365 tmp_win->title.back = Scr->TitleC.back; 1366 SETC(TitleForegroundL, title.fore); 1367 SETC(TitleBackgroundL, title.back); 1368 1369#undef SETC 1370 1371 /* Shading on 3d bits */ 1372 if(Scr->use3Dtitles && !Scr->BeNiceToColormap) { 1373 GetShadeColors(&tmp_win->title); 1374 } 1375 if(Scr->use3Dborders && !Scr->BeNiceToColormap) { 1376 GetShadeColors(&tmp_win->borderC); 1377 GetShadeColors(&tmp_win->border_tile); 1378 } 1379 1380 1381 /* 1382 * Following bits are more active, and we want to make sure nothing 1383 * else gets to do anything with the server while we're doing it. 1384 * 1385 * Minor investigations seems to suggest we could pull a number of 1386 * these things out (mostly to later, but probably some to earlier) 1387 * so we keep the server grabbed for a shorter period of time. I'm 1388 * not putting significant effort into finding out what we could pull 1389 * out because it's already plenty fast, but there is probably fruit 1390 * that could be plucked if somebody finds it not so. 1391 */ 1392 XGrabServer(dpy); 1393 1394 1395 /* 1396 * Make sure the client window still exists. We don't want to leave an 1397 * orphan frame window if it doesn't. Since we now have the server 1398 * grabbed, the window can't disappear later without having been 1399 * reparented, so we'll get a DestroyNotify for it. We won't have 1400 * gotten one for anything up to here, however. 1401 */ 1402 if(XGetGeometry(dpy, tmp_win->w, &JunkRoot, &JunkX, &JunkY, 1403 &JunkWidth, &JunkHeight, &JunkBW, &JunkDepth) == 0) { 1404 UnlinkWindowFromRing(tmp_win); 1405 1406 /* XXX Leaky as all hell */ 1407 free(tmp_win); 1408 XUngrabServer(dpy); 1409 return(NULL); 1410 } 1411 1412 1413 /* Link the window into our list of all the TwmWindow's */ 1414 tmp_win->next = Scr->FirstWindow; 1415 if(Scr->FirstWindow != NULL) { 1416 Scr->FirstWindow->prev = tmp_win; 1417 } 1418 tmp_win->prev = NULL; 1419 Scr->FirstWindow = tmp_win; 1420 1421 1422 1423 /* 1424 * Start creating the other X windows we wrap around it for 1425 * decorations. X-ref discussion in win_decorations.c for the 1426 * details of what they all are and why they're there. 1427 * 1428 * XXX Good candidate for moving out into a helper function... 1429 */ 1430 1431 1432 /* 1433 * First, the frame 1434 */ 1435 { 1436 unsigned long valuemask; 1437 XSetWindowAttributes attributes; 1438 1439 /* 1440 * Figure size/position. 1441 */ 1442 tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw 1443 - tmp_win->frame_bw - tmp_win->frame_bw3D; 1444 tmp_win->frame_y = tmp_win->attr.y - tmp_win->title_height 1445 + tmp_win->old_bw 1446 - tmp_win->frame_bw - tmp_win->frame_bw3D; 1447 tmp_win->frame_width = tmp_win->attr.width + 2 * tmp_win->frame_bw3D; 1448 tmp_win->frame_height = tmp_win->attr.height + 2 * tmp_win->frame_bw3D 1449 + tmp_win->title_height; 1450 1451 /* Adjust based on hints */ 1452 ConstrainSize(tmp_win, &tmp_win->frame_width, &tmp_win->frame_height); 1453 1454 /* 1455 * Adjust as necessary to keep things on-screen. If we [ctwm] 1456 * chose the position, CBB() involves checking things like 1457 * MoveOffResistance etc to keep it on. 1458 */ 1459 if(random_placed) { 1460 ConstrainByBorders(tmp_win, &tmp_win->frame_x, tmp_win->frame_width, 1461 &tmp_win->frame_y, tmp_win->frame_height); 1462 } 1463 1464 /* No matter what, make sure SOME part of the window is on-screen */ 1465 { 1466 RArea area; 1467 int min_x, min_y, max_bottom, max_right; 1468 const RLayout *layout = Scr->BorderedLayout; 1469 1470 area = RAreaNew(tmp_win->frame_x, tmp_win->frame_y, 1471 (int)tmp_win->frame_width, 1472 (int)tmp_win->frame_height); 1473 1474#ifdef EWMH 1475 // Hack: windows with EWMH struts defined are trying to 1476 // reserve a bit of the screen for themselves. We currently 1477 // do that by hacking strut'ed space into the BorderedLayout, 1478 // which is a bogus way of doing things. But it also means 1479 // that here we're forcing the windows to be outside their 1480 // own struts, which is nonsensical. 1481 // 1482 // Hack around that by making strut'd windows just use 1483 // Layout, rather than BorderedLayout. This is Wrong(tm) 1484 // because the whole point of BorderedLayout is space 1485 // reservation by the user, which we'd now be ignoring. Also 1486 // just because a window has its own struts doesn't mean it 1487 // should get to ignore everyone else's struts too. However, 1488 // this is at least consistent with pre-4.1.0 behavior, so 1489 // it's not a _new_ bug. And forcing windows outside their 1490 // own reservation is way stupider... 1491 if(tmp_win->ewmhFlags & EWMH_HAS_STRUT) { 1492 layout = Scr->Layout; 1493 } 1494#endif 1495 1496 RLayoutFindTopBottomEdges(layout, &area, 1497 &min_y, &max_bottom); 1498 RLayoutFindLeftRightEdges(layout, &area, 1499 &min_x, &max_right); 1500 1501 // These conditions would only be true if the window was 1502 // completely off-screen; in that case, the RLayout* calls 1503 // above would have found the closest edges to move it to. 1504 // We wind up sticking it in the top-left of the 1505 // bottom-right-most monitor it would touch. 1506 if(area.x > max_right || area.y > max_bottom || 1507 area.x + area.width <= min_x || 1508 area.y + area.height <= min_y) { 1509 tmp_win->frame_x = min_x; 1510 tmp_win->frame_y = min_y; 1511 } 1512 } 1513 1514#ifdef VSCREEN 1515 /* May need adjusting for vscreens too */ 1516 DealWithNonSensicalGeometries(dpy, vroot, tmp_win); 1517#endif 1518 1519 1520 /* 1521 * Setup the X attributes for the frame. 1522 */ 1523 valuemask = CWBackPixmap | CWBorderPixel | CWBackPixel 1524 | CWCursor | CWEventMask; 1525 attributes.background_pixmap = None; 1526 attributes.border_pixel = tmp_win->border_tile.back; 1527 attributes.background_pixel = tmp_win->border_tile.back; 1528 attributes.cursor = Scr->FrameCursor; 1529 attributes.event_mask = (SubstructureRedirectMask 1530 | ButtonPressMask | ButtonReleaseMask 1531 | EnterWindowMask | LeaveWindowMask 1532 | ExposureMask); 1533 1534 /* 1535 * If we have BorderResizeCursors, we need to know about motions 1536 * in the window to know when to change (e.g., for corners). 1537 */ 1538 if(Scr->BorderCursors) { 1539 attributes.event_mask |= PointerMotionMask; 1540 } 1541 1542 /* 1543 * If the real window specified save_under or a specific gravity, 1544 * set them on the frame too. 1545 */ 1546 if(tmp_win->attr.save_under) { 1547 attributes.save_under = True; 1548 valuemask |= CWSaveUnder; 1549 } 1550 if(tmp_win->hints.flags & PWinGravity) { 1551 attributes.win_gravity = tmp_win->hints.win_gravity; 1552 valuemask |= CWWinGravity; 1553 } 1554 1555 1556 /* And create */ 1557 tmp_win->frame = XCreateWindow(dpy, vroot, 1558 tmp_win->frame_x, tmp_win->frame_y, 1559 tmp_win->frame_width, 1560 tmp_win->frame_height, 1561 tmp_win->frame_bw, 1562 Scr->d_depth, CopyFromParent, 1563 Scr->d_visual, valuemask, &attributes); 1564 if(Scr->NameDecorations) { 1565 XStoreName(dpy, tmp_win->frame, "CTWM frame"); 1566 } 1567 } 1568 1569 1570 /* 1571 * Next, the titlebar, if we have one 1572 */ 1573 if(tmp_win->title_height) { 1574 unsigned long valuemask; 1575 XSetWindowAttributes attributes; 1576 int x, y; 1577 1578 /* 1579 * We need to know about keys/buttons and exposure of the 1580 * titlebar, for bindings and repaining. And leave to X server 1581 * bits about border/background. 1582 */ 1583 valuemask = (CWEventMask | CWDontPropagate 1584 | CWBorderPixel | CWBackPixel); 1585 attributes.event_mask = (KeyPressMask | ButtonPressMask 1586 | ButtonReleaseMask | ExposureMask); 1587 attributes.do_not_propagate_mask = PointerMotionMask; 1588 attributes.border_pixel = tmp_win->borderC.back; 1589 attributes.background_pixel = tmp_win->title.back; 1590 1591 1592 /* Create */ 1593 x = y = tmp_win->frame_bw3D - tmp_win->frame_bw; 1594 tmp_win->title_w = XCreateWindow(dpy, tmp_win->frame, x, y, 1595 tmp_win->attr.width, 1596 Scr->TitleHeight, tmp_win->frame_bw, 1597 Scr->d_depth, CopyFromParent, 1598 Scr->d_visual, valuemask, &attributes); 1599 if(Scr->NameDecorations) { 1600 XStoreName(dpy, tmp_win->title_w, "CTWM titlebar"); 1601 } 1602 } 1603 else { 1604 tmp_win->title_w = None; 1605 tmp_win->squeeze_info = NULL; 1606 } 1607 1608 1609 /* 1610 * If we're highlighting borders on focus, we need the pixmap to do 1611 * it. 1612 * 1613 * XXX I'm not at all sure this can't just be global and shared, so 1614 * we don't have to create one per window... 1615 */ 1616 if(tmp_win->highlight) { 1617 char *which; 1618 1619 if(Scr->use3Dtitles && (Scr->Monochrome != COLOR)) { 1620 which = "black"; 1621 } 1622 else { 1623 which = "gray"; 1624 } 1625 tmp_win->gray = mk_blackgray_pixmap(which, vroot, 1626 tmp_win->border_tile.fore, 1627 tmp_win->border_tile.back); 1628 1629 tmp_win->hasfocusvisible = true; 1630 SetFocusVisualAttributes(tmp_win, false); 1631 } 1632 else { 1633 tmp_win->gray = None; 1634 } 1635 1636 1637 /* 1638 * Setup OTP bits for stacking 1639 */ 1640 OtpAdd(tmp_win, WinWin); 1641 1642 1643 /* 1644 * Setup the stuff inside the titlebar window, if we have it. If we 1645 * don't, fake up the coordinates where the titlebar would be for 1646 * <reasons>. 1647 */ 1648 if(tmp_win->title_w) { 1649 ComputeTitleLocation(tmp_win); 1650 CreateWindowTitlebarButtons(tmp_win); 1651 XMoveWindow(dpy, tmp_win->title_w, 1652 tmp_win->title_x, tmp_win->title_y); 1653 XDefineCursor(dpy, tmp_win->title_w, Scr->TitleCursor); 1654 } 1655 else { 1656 tmp_win->title_x = tmp_win->frame_bw3D - tmp_win->frame_bw; 1657 tmp_win->title_y = tmp_win->frame_bw3D - tmp_win->frame_bw; 1658 } 1659 1660 1661 /* 1662 * Setup various events we want to hear about related to this window. 1663 */ 1664 { 1665 unsigned long valuemask; 1666 XSetWindowAttributes attributes; 1667 1668 valuemask = (CWEventMask | CWDontPropagate); 1669 attributes.event_mask = (StructureNotifyMask | PropertyChangeMask 1670 | ColormapChangeMask | VisibilityChangeMask 1671 | FocusChangeMask 1672 | EnterWindowMask | LeaveWindowMask); 1673 attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask 1674 | PointerMotionMask; 1675 XChangeWindowAttributes(dpy, tmp_win->w, valuemask, &attributes); 1676 } 1677 1678 1679 /* 1680 * Map up the title window if we have one. As a sub-window of the 1681 * frame, it'll only actually show up in the screen if the frame 1682 * does, of course. 1683 */ 1684 if(tmp_win->title_w) { 1685 XMapWindow(dpy, tmp_win->title_w); 1686 } 1687 1688 1689 /* 1690 * If the server's got Shape, look up info about the window's 1691 * Shape'ing, and subscribe to notifications about changes in it. 1692 * Actually, it's only the bounding we care about; the rest is 1693 * thrown away. 1694 */ 1695 if(HasShape) { 1696 int xws, yws, xbs, ybs; 1697 unsigned wws, hws, wbs, hbs; 1698 int boundingShaped, clipShaped; 1699 1700 XShapeSelectInput(dpy, tmp_win->w, ShapeNotifyMask); 1701 XShapeQueryExtents(dpy, tmp_win->w, 1702 &boundingShaped, &xws, &yws, &wws, &hws, 1703 &clipShaped, &xbs, &ybs, &wbs, &hbs); 1704 tmp_win->wShaped = boundingShaped; 1705 } 1706 1707 1708 /* 1709 * If it's a normal window (i.e., not one of ctwm's internal ones), 1710 * add it to the "save set", which means that even if ctwm disappears 1711 * without doing any cleanup, it'll still show back up on the screen 1712 * like normal. Otherwise, if you kill or segfault ctwm, all the 1713 * other things you're running get their windows lost. 1714 * 1715 * XXX Conditional may be a little on the short side; I'm not sure it 1716 * catches all of our internals... 1717 */ 1718 if(!(tmp_win->isiconmgr || tmp_win->iswspmgr || tmp_win->isoccupy)) { 1719 XAddToSaveSet(dpy, tmp_win->w); 1720 } 1721 1722 1723 /* 1724 * Now reparent the real window into our frame. 1725 */ 1726 XReparentWindow(dpy, tmp_win->w, tmp_win->frame, tmp_win->frame_bw3D, 1727 tmp_win->title_height + tmp_win->frame_bw3D); 1728 1729 /* 1730 * Reparenting generates an UnmapNotify event, followed by a 1731 * MapNotify. Set the map state to false to prevent a transition 1732 * back to WithdrawnState in HandleUnmapNotify. ->mapped gets set 1733 * correctly again in HandleMapNotify. 1734 */ 1735 tmp_win->mapped = false; 1736 1737 1738 /* 1739 * Call SetupFrame() which does all sorta of magic figuring to set 1740 * the various coordinates and offsets and whatnot for all the pieces 1741 * inside our frame. 1742 */ 1743 SetupFrame(tmp_win, tmp_win->frame_x, tmp_win->frame_y, 1744 tmp_win->frame_width, tmp_win->frame_height, -1, true); 1745 1746 1747 /* 1748 * Don't setup the icon window and its bits; when the window is 1749 * iconified the first time, that handler will do what needs to be 1750 * done for it, so we don't have to. 1751 */ 1752 1753 1754 /* 1755 * If it's anything other than our own icon manager, setup button/key 1756 * bindings for it. For icon managers, this is done for them at the 1757 * end of CreateIconManagers(), not here. X-ref comments there and 1758 * on the function defs below for some discussion about whether it 1759 * _should_ work this way. 1760 */ 1761 if(!tmp_win->isiconmgr) { 1762 GrabButtons(tmp_win); 1763 GrabKeys(tmp_win); 1764 } 1765 1766 1767 /* Add this window to the appropriate icon manager[s] */ 1768 AddIconManager(tmp_win); 1769 1770 1771 /* 1772 * Stash up info about this TwmWindow and its screen in contexts on 1773 * the real window and our various decorations around it. This is 1774 * how we find out what TwmWindow things like events are happening 1775 * in. 1776 */ 1777#define SETCTXS(win) do { \ 1778 XSaveContext(dpy, win, TwmContext, (XPointer) tmp_win); \ 1779 XSaveContext(dpy, win, ScreenContext, (XPointer) Scr); \ 1780 } while(0) 1781 1782 /* The real window and our frame */ 1783 SETCTXS(tmp_win->w); 1784 SETCTXS(tmp_win->frame); 1785 1786 /* Cram that all into any titlebar [sub]windows too */ 1787 if(tmp_win->title_height) { 1788 int i; 1789 int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; 1790 1791 SETCTXS(tmp_win->title_w); 1792 1793 for(i = 0; i < nb; i++) { 1794 SETCTXS(tmp_win->titlebuttons[i].window); 1795 } 1796 if(tmp_win->hilite_wl) { 1797 SETCTXS(tmp_win->hilite_wl); 1798 } 1799 if(tmp_win->hilite_wr) { 1800 SETCTXS(tmp_win->hilite_wr); 1801 } 1802 if(tmp_win->lolite_wl) { 1803 SETCTXS(tmp_win->lolite_wl); 1804 } 1805 if(tmp_win->lolite_wr) { 1806 SETCTXS(tmp_win->lolite_wr); 1807 } 1808 } 1809 1810#undef SETCTXS 1811 1812 /* 1813 * OK, that's all we need to do while the server's grabbed. After 1814 * this point, other clients might sneak in stuff between our 1815 * actions, so they can't be considered atomic anymore. 1816 */ 1817 XUngrabServer(dpy); 1818 1819 1820 /* 1821 * If we were in the middle of a menu activated function that was 1822 * deferred (x-ref comments on DeferExecution()), re-grab to re-set 1823 * the special cursor, since we may have reset it above. 1824 * 1825 * Why could that possibly happen? It would require a window coming 1826 * up and needing to be Add'd in the middle of selecting a window to 1827 * apply a function to, which is a pretty rare case, but I s'pose not 1828 * impossible... 1829 */ 1830 if(RootFunction) { 1831 ReGrab(); 1832 } 1833 1834 1835 /* 1836 * Add to the workspace manager. Unless this IS the workspace 1837 * manager, in which case that would just be silly. 1838 */ 1839 if(!tmp_win->iswspmgr) { 1840 WMapAddWindow(tmp_win); 1841 } 1842 1843 1844#ifdef CAPTIVE 1845 /* 1846 * If ths window being created is a new captive [sub-]ctwm, we setup 1847 * a property on it for unclear reasons. x-ref comments on the 1848 * function. 1849 */ 1850 SetPropsIfCaptiveCtwm(tmp_win); 1851#endif 1852 1853 1854 /* 1855 * Init saved geometry with the current, as if f.savegeometry was 1856 * called on the window right away. That way f.restoregeometry can't 1857 * get confuzzled. 1858 */ 1859 savegeometry(tmp_win); 1860 1861 1862 /* 1863 * And that's it; we created all the bits! 1864 */ 1865 return tmp_win; 1866} 1867 1868 1869 1870 1871/* 1872 * XXX GrabButtons() and GrabKeys() are in a slightly odd state. They're 1873 * almost strictly a piece of the window-adding process, which is why 1874 * they're here. They're not static because the icon manager setup in 1875 * CreateIconManagers() calls them explicitly, because they're also 1876 * explicitly skipped in AddWindow() for icon manager windows. I'm not 1877 * sure that's necessary; x-ref comment in CIM() about some ideas on the 1878 * matter. 1879 * 1880 * This should be resolved. Until it is, they're left exported so the 1881 * iconmgr code can all them, and they're left here (rather than moved to 1882 * win_utils) on the guess that it may well be resolvable and so they'd 1883 * stay here and be staticized in the end. 1884 */ 1885 1886/*********************************************************************** 1887 * 1888 * Procedure: 1889 * GrabButtons - grab needed buttons for the window 1890 * 1891 * Inputs: 1892 * tmp_win - the twm window structure to use 1893 * 1894 *********************************************************************** 1895 */ 1896 1897#define grabbutton(button, modifier, window, pointer_mode) \ 1898 XGrabButton (dpy, button, modifier, window, \ 1899 True, ButtonPressMask | ButtonReleaseMask, \ 1900 pointer_mode, GrabModeAsync, None, \ 1901 Scr->FrameCursor); 1902 1903void GrabButtons(TwmWindow *tmp_win) 1904{ 1905 FuncButton *tmp; 1906 int i; 1907 unsigned int ModifierMask[8] = { ShiftMask, ControlMask, LockMask, 1908 Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, 1909 Mod5Mask 1910 }; 1911 1912 for(tmp = Scr->FuncButtonRoot.next; tmp != NULL; tmp = tmp->next) { 1913 if((tmp->cont != C_WINDOW) || (tmp->func == 0)) { 1914 continue; 1915 } 1916 grabbutton(tmp->num, tmp->mods, tmp_win->frame, GrabModeAsync); 1917 1918 for(i = 0 ; i < 8 ; i++) { 1919 if((Scr->IgnoreModifier & ModifierMask [i]) && !(tmp->mods & ModifierMask [i])) 1920 grabbutton(tmp->num, tmp->mods | ModifierMask [i], 1921 tmp_win->frame, GrabModeAsync); 1922 } 1923 } 1924 if(Scr->ClickToFocus) { 1925 grabbutton(AnyButton, None, tmp_win->w, GrabModeSync); 1926 for(i = 0 ; i < 8 ; i++) { 1927 grabbutton(AnyButton, ModifierMask [i], tmp_win->w, GrabModeSync); 1928 } 1929 } 1930 else if(Scr->RaiseOnClick) { 1931 grabbutton(Scr->RaiseOnClickButton, None, tmp_win->w, GrabModeSync); 1932 for(i = 0 ; i < 8 ; i++) { 1933 grabbutton(Scr->RaiseOnClickButton, 1934 ModifierMask [i], tmp_win->w, GrabModeSync); 1935 } 1936 } 1937} 1938#undef grabbutton 1939 1940/*********************************************************************** 1941 * 1942 * Procedure: 1943 * GrabKeys - grab needed keys for the window 1944 * 1945 * Inputs: 1946 * tmp_win - the twm window structure to use 1947 * 1948 *********************************************************************** 1949 */ 1950 1951#define grabkey(funckey, modifier, window) \ 1952 XGrabKey(dpy, funckey->keycode, funckey->mods | modifier, window, True, \ 1953 GrabModeAsync, GrabModeAsync); 1954#define ungrabkey(funckey, modifier, window) \ 1955 XUngrabKey (dpy, funckey->keycode, funckey->mods | modifier, window); 1956 1957void GrabKeys(TwmWindow *tmp_win) 1958{ 1959 FuncKey *tmp; 1960 IconMgr *p; 1961 int i; 1962 unsigned int ModifierMask[8] = { ShiftMask, ControlMask, LockMask, 1963 Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, 1964 Mod5Mask 1965 }; 1966 1967 for(tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) { 1968 switch(tmp->cont) { 1969 case C_WINDOW: 1970 /* case C_WORKSPACE: */ 1971#define AltMask (Alt1Mask | Alt2Mask | Alt3Mask | Alt4Mask | Alt5Mask) 1972 if(tmp->mods & AltMask) { 1973 break; 1974 } 1975#undef AltMask 1976 1977 grabkey(tmp, 0, tmp_win->w); 1978 1979 for(i = 0 ; i < 8 ; i++) { 1980 if((Scr->IgnoreModifier & ModifierMask [i]) && 1981 !(tmp->mods & ModifierMask [i])) { 1982 grabkey(tmp, ModifierMask [i], tmp_win->w); 1983 } 1984 } 1985 break; 1986 1987 case C_ICON: 1988 if(!tmp_win->icon || tmp_win->icon->w) { 1989 break; 1990 } 1991 1992 grabkey(tmp, 0, tmp_win->icon->w); 1993 1994 for(i = 0 ; i < 8 ; i++) { 1995 if((Scr->IgnoreModifier & ModifierMask [i]) && 1996 !(tmp->mods & ModifierMask [i])) { 1997 grabkey(tmp, ModifierMask [i], tmp_win->icon->w); 1998 } 1999 } 2000 break; 2001 2002 case C_TITLE: 2003 if(!tmp_win->title_w) { 2004 break; 2005 } 2006 2007 grabkey(tmp, 0, tmp_win->title_w); 2008 2009 for(i = 0 ; i < 8 ; i++) { 2010 if((Scr->IgnoreModifier & ModifierMask [i]) && 2011 !(tmp->mods & ModifierMask [i])) { 2012 grabkey(tmp, ModifierMask [i], tmp_win->title_w); 2013 } 2014 } 2015 break; 2016 2017 case C_NAME: 2018 grabkey(tmp, 0, tmp_win->w); 2019 for(i = 0 ; i < 8 ; i++) { 2020 if((Scr->IgnoreModifier & ModifierMask [i]) && 2021 !(tmp->mods & ModifierMask [i])) { 2022 grabkey(tmp, ModifierMask [i], tmp_win->w); 2023 } 2024 } 2025 if(tmp_win->icon && tmp_win->icon->w) { 2026 grabkey(tmp, 0, tmp_win->icon->w); 2027 2028 for(i = 0 ; i < 8 ; i++) { 2029 if((Scr->IgnoreModifier & ModifierMask [i]) && 2030 !(tmp->mods & ModifierMask [i])) { 2031 grabkey(tmp, ModifierMask [i], tmp_win->icon->w); 2032 } 2033 } 2034 } 2035 if(tmp_win->title_w) { 2036 grabkey(tmp, 0, tmp_win->title_w); 2037 2038 for(i = 0 ; i < 8 ; i++) { 2039 if((Scr->IgnoreModifier & ModifierMask [i]) && 2040 !(tmp->mods & ModifierMask [i])) { 2041 grabkey(tmp, ModifierMask [i], tmp_win->title_w); 2042 } 2043 } 2044 } 2045 break; 2046 2047#ifdef EWMH_DESKTOP_ROOT 2048 case C_ROOT: 2049 if(tmp_win->ewmhWindowType != wt_Desktop) { 2050 break; 2051 } 2052 2053 grabkey(tmp, 0, tmp_win->w); 2054 2055 for(i = 0 ; i < 8 ; i++) { 2056 if((Scr->IgnoreModifier & ModifierMask [i]) && 2057 !(tmp->mods & ModifierMask [i])) { 2058 grabkey(tmp, ModifierMask [i], tmp_win->w); 2059 } 2060 } 2061 break; 2062#endif /* EWMH */ 2063 2064 /* 2065 case C_ROOT: 2066 XGrabKey(dpy, tmp->keycode, tmp->mods, Scr->Root, True, 2067 GrabModeAsync, GrabModeAsync); 2068 break; 2069 */ 2070 } 2071 } 2072 for(tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) { 2073 if(tmp->cont == C_ICONMGR && !Scr->NoIconManagers) { 2074 for(p = Scr->iconmgr; p != NULL; p = p->next) { 2075 ungrabkey(tmp, 0, p->twm_win->w); 2076 2077 for(i = 0 ; i < 8 ; i++) { 2078 if((Scr->IgnoreModifier & ModifierMask [i]) && 2079 !(tmp->mods & ModifierMask [i])) { 2080 ungrabkey(tmp, ModifierMask [i], p->twm_win->w); 2081 } 2082 } 2083 } 2084 } 2085 } 2086} 2087#undef grabkey 2088#undef ungrabkey 2089 2090 2091#ifdef VSCREEN 2092/* 2093 * This is largely for Xinerama support with VirtualScreens. 2094 * In this case, windows may be on something other then the main screen 2095 * on startup, or the mapping may be relative to the right side of the 2096 * screen, which is on a different monitor, which will cause issues with 2097 * the virtual screens. 2098 * 2099 * It probably needs to be congnizant of windows that are actually owned by 2100 * other workspaces, and ignore them (this needs to be revisited), or perhaps 2101 * that functionality is appropriate in AddWindow(). This needs to be dug into 2102 * more deply. 2103 * 2104 * this approach assumes screens that are next to each other horizontally, 2105 * Other possibilities need to be investigated and accounted for. 2106 */ 2107static void 2108DealWithNonSensicalGeometries(Display *mydpy, Window vroot, 2109 TwmWindow *tmp_win) 2110{ 2111 Window vvroot; 2112 int x, y; 2113 unsigned int w, h; 2114 unsigned int j; 2115 VirtualScreen *myvs, *vs; 2116 int dropx = 0; 2117 2118 if(! vroot) { 2119 return; 2120 } 2121 2122 if(!(XGetGeometry(mydpy, vroot, &vvroot, &x, &y, &w, &h, &j, &j))) { 2123 return; 2124 } 2125 2126 myvs = findIfVScreenOf(x, y); 2127 2128 /* 2129 * probably need to rethink this for unmapped vs's. ugh. 2130 */ 2131 if(!myvs) { 2132 return; 2133 } 2134 2135 for(vs = myvs->next; vs; vs = vs->next) { 2136 dropx += vs->w; 2137 } 2138 2139 for(vs = Scr->vScreenList; vs && vs != myvs; vs = vs->next) { 2140 dropx -= vs->w; 2141 } 2142 2143 if(tmp_win->frame_x > 0 && tmp_win->frame_x >= w) { 2144 tmp_win->frame_x -= abs(dropx); 2145 } 2146 else { 2147 } 2148 2149} 2150#endif // VSCREEN 2151