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