add_window.c revision 6d8e82c3
1/*****************************************************************************/ 2/* 3 4Copyright 1989,1998 The Open Group 5 6Permission to use, copy, modify, distribute, and sell this software and its 7documentation for any purpose is hereby granted without fee, provided that 8the above copyright notice appear in all copies and that both that 9copyright notice and this permission notice appear in supporting 10documentation. 11 12The above copyright notice and this permission notice shall be included in 13all copies or substantial portions of the Software. 14 15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 19AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall not be 23used in advertising or otherwise to promote the sale, use or other dealings 24in this Software without prior written authorization from The Open Group. 25 26*/ 27/** Copyright 1988 by Evans & Sutherland Computer Corporation, **/ 28/** Salt Lake City, Utah **/ 29/** Cambridge, Massachusetts **/ 30/** **/ 31/** All Rights Reserved **/ 32/** **/ 33/** Permission to use, copy, modify, and distribute this software and **/ 34/** its documentation for any purpose and without fee is hereby **/ 35/** granted, provided that the above copyright notice appear in all **/ 36/** copies and that both that copyright notice and this permis- **/ 37/** sion notice appear in supporting documentation, and that the **/ 38/** name of Evans & Sutherland not be used in advertising **/ 39/** in publicity pertaining to distribution of the software without **/ 40/** specific, written prior permission. **/ 41/** **/ 42/** EVANS & SUTHERLAND DISCLAIMs ALL WARRANTIES WITH REGARD **/ 43/** TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANT- **/ 44/** ABILITY AND FITNESS, IN NO EVENT SHALL EVANS & SUTHERLAND **/ 45/** BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAM- **/ 46/** AGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA **/ 47/** OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER **/ 48/** TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE **/ 49/** OR PERFORMANCE OF THIS SOFTWARE. **/ 50/*****************************************************************************/ 51 52/********************************************************************** 53 * 54 * Add a new window, put the titlebar and other stuff around 55 * the window 56 * 57 * 31-Mar-88 Tom LaStrange Initial Version. 58 * 59 **********************************************************************/ 60 61#include <stdio.h> 62#include "twm.h" 63#include <X11/Xatom.h> 64#include "util.h" 65#include "resize.h" 66#include "parse.h" 67#include "list.h" 68#include "events.h" 69#include "menus.h" 70#include "screen.h" 71#include "iconmgr.h" 72#include "session.h" 73#include "add_window.h" 74 75#define short_lookup (short)(long)(void*) 76 77#define gray_width 2 78#define gray_height 2 79static char gray_bits[] = { 80 0x02, 0x01 81}; 82 83int AddingX; 84int AddingY; 85int AddingW; 86int AddingH; 87 88static int PlaceX = 50; 89static int PlaceY = 50; 90 91static void do_add_binding(int button, int context, int modifier, int func); 92static Window CreateHighlightWindow(TwmWindow *tmp_win); 93static void CreateWindowTitlebarButtons(TwmWindow *tmp_win); 94 95char NoName[] = "Untitled"; /* name if no name is specified */ 96 97/** 98 * map gravity to (x,y) offset signs for adding to x and y when window is 99 * mapped to get proper placement. 100 * 101 * \param tmp window from which to get gravity 102 * \param xp,yp return values 103 * 104 */ 105void 106GetGravityOffsets(TwmWindow *tmp, int *xp, int *yp) 107{ 108 /* *INDENT-OFF* */ 109 static struct _gravity_offset { 110 int x, y; 111 } gravity_offsets[11] = { 112 { 0, 0 }, /* ForgetGravity */ 113 { -1, -1 }, /* NorthWestGravity */ 114 { 0, -1 }, /* NorthGravity */ 115 { 1, -1 }, /* NorthEastGravity */ 116 { -1, 0 }, /* WestGravity */ 117 { 0, 0 }, /* CenterGravity */ 118 { 1, 0 }, /* EastGravity */ 119 { -1, 1 }, /* SouthWestGravity */ 120 { 0, 1 }, /* SouthGravity */ 121 { 1, 1 }, /* SouthEastGravity */ 122 { 0, 0 }, /* StaticGravity */ 123 }; 124 /* *INDENT-ON* */ 125 int g = ((tmp->hints.flags & PWinGravity) 126 ? tmp->hints.win_gravity : NorthWestGravity); 127 128 if (g < ForgetGravity || g > StaticGravity) { 129 *xp = *yp = 0; 130 } 131 else { 132 *xp = gravity_offsets[g].x; 133 *yp = gravity_offsets[g].y; 134 } 135} 136 137/** 138 * add a new window to the twm list. 139 * 140 * \return pointer to the TwmWindow structure 141 * 142 * \param w the window id of the window to add 143 * \param iconm flag to tell if this is an icon manager window 144 * \param iconp pointer to icon manager struct 145 */ 146TwmWindow * 147AddWindow(Window w, int iconm, IconMgr *iconp) 148{ 149 TwmWindow *tmp_win; /* new twm window structure */ 150 XEvent event; 151 unsigned long valuemask; /* mask for create windows */ 152 XSetWindowAttributes attributes; /* attributes for create windows */ 153 int ask_user; /* don't know where to put the window */ 154 int gravx, gravy; /* gravity signs for positioning */ 155 int namelen; 156 int bw2; 157 short saved_x, saved_y, restore_icon_x, restore_icon_y; 158 unsigned short saved_width, saved_height; 159 Bool restore_iconified = 0; 160 Bool restore_icon_info_present = 0; 161 int restoredFromPrevSession; 162 Bool width_ever_changed_by_user; 163 Bool height_ever_changed_by_user; 164 char *name; 165 int dummy = 0; 166 unsigned udummy = 0; 167 Window wdummy = None; 168 169#ifdef DEBUG 170 fprintf(stderr, "AddWindow: w = 0x%lx\n", (unsigned long) w); 171#endif 172 173 /* allocate space for the twm window */ 174 tmp_win = (TwmWindow *) calloc(1, sizeof(TwmWindow)); 175 if (tmp_win == NULL) { 176 twmWarning("Unable to allocate memory to manage window ID %lx.", w); 177 return NULL; 178 } 179 tmp_win->w = w; 180 tmp_win->zoomed = ZOOM_NONE; 181 tmp_win->iconmgr = (short) iconm; 182 tmp_win->iconmgrp = iconp; 183 tmp_win->cmaps.number_cwins = 0; 184 185 XSelectInput(dpy, tmp_win->w, PropertyChangeMask); 186 187 XGetWindowAttributes(dpy, tmp_win->w, &tmp_win->attr); 188 189 if (!I18N_FetchName(dpy, tmp_win->w, &name)) 190 name = NULL; 191 tmp_win->xclass = NoClass; 192 XGetClassHint(dpy, tmp_win->w, &tmp_win->xclass); 193 FetchWmProtocols(tmp_win); 194 FetchWmColormapWindows(tmp_win); 195 196 if (name == NULL) 197 tmp_win->name = strdup(NoName); 198 else { 199 tmp_win->name = strdup(name); 200 free(name); 201 } 202 203 if (GetWindowConfig(tmp_win, 204 &saved_x, &saved_y, &saved_width, &saved_height, 205 &restore_iconified, &restore_icon_info_present, 206 &restore_icon_x, &restore_icon_y, 207 &width_ever_changed_by_user, 208 &height_ever_changed_by_user)) { 209 tmp_win->attr.x = saved_x; 210 tmp_win->attr.y = saved_y; 211 212 tmp_win->widthEverChangedByUser = width_ever_changed_by_user; 213 tmp_win->heightEverChangedByUser = height_ever_changed_by_user; 214 215 if (width_ever_changed_by_user) 216 tmp_win->attr.width = saved_width; 217 218 if (height_ever_changed_by_user) 219 tmp_win->attr.height = saved_height; 220 221 restoredFromPrevSession = 1; 222 } 223 else { 224 tmp_win->widthEverChangedByUser = False; 225 tmp_win->heightEverChangedByUser = False; 226 227 restoredFromPrevSession = 0; 228 } 229 230 /* 231 * do initial clip; should look at window gravity 232 */ 233 if (tmp_win->attr.width > Scr->MaxWindowWidth) 234 tmp_win->attr.width = Scr->MaxWindowWidth; 235 if (tmp_win->attr.height > Scr->MaxWindowHeight) 236 tmp_win->attr.height = Scr->MaxWindowHeight; 237 238 tmp_win->wmhints = XGetWMHints(dpy, tmp_win->w); 239 240 if (tmp_win->wmhints) { 241 if (restore_iconified) { 242 tmp_win->wmhints->initial_state = IconicState; 243 tmp_win->wmhints->flags |= StateHint; 244 } 245 246 if (restore_icon_info_present) { 247 tmp_win->wmhints->icon_x = restore_icon_x; 248 tmp_win->wmhints->icon_y = restore_icon_y; 249 tmp_win->wmhints->flags |= IconPositionHint; 250 } 251 } 252 253 if (tmp_win->wmhints && (tmp_win->wmhints->flags & WindowGroupHint)) 254 tmp_win->group = tmp_win->wmhints->window_group; 255 else 256 tmp_win->group = tmp_win->w /* NULL */ ; 257 258 /* 259 * The July 27, 1988 draft of the ICCCM ignores the size and position 260 * fields in the WM_NORMAL_HINTS property. 261 */ 262 263 tmp_win->transient = (short) Transient(tmp_win->w, &tmp_win->transientfor); 264 265 tmp_win->nameChanged = 0; 266 if (tmp_win->xclass.res_name == NULL) 267 tmp_win->xclass.res_name = NoName; 268 if (tmp_win->xclass.res_class == NULL) 269 tmp_win->xclass.res_class = NoName; 270 271 tmp_win->full_name = strdup(tmp_win->name); 272 namelen = (int) strlen(tmp_win->name); 273 274 tmp_win->highlight = Scr->Highlight && 275 (!short_lookup LookInList(Scr->NoHighlight, tmp_win->full_name, 276 &tmp_win->xclass)); 277 278 tmp_win->stackmode = Scr->StackMode && 279 (!short_lookup LookInList(Scr->NoStackModeL, tmp_win->full_name, 280 &tmp_win->xclass)); 281 282 tmp_win->titlehighlight = Scr->TitleHighlight && 283 (!short_lookup LookInList(Scr->NoTitleHighlight, tmp_win->full_name, 284 &tmp_win->xclass)); 285 286 tmp_win->auto_raise = short_lookup LookInList(Scr->AutoRaise, 287 tmp_win->full_name, 288 &tmp_win->xclass); 289 if (tmp_win->auto_raise) 290 Scr->NumAutoRaises++; 291 if (Scr->IconifyByUnmapping) { 292 tmp_win->iconify_by_unmapping = iconm ? FALSE : 293 !short_lookup LookInList(Scr->DontIconify, tmp_win->full_name, 294 &tmp_win->xclass); 295 } 296 else { 297 tmp_win->iconify_by_unmapping = Scr->IconifyByUnmapping; 298 } 299 tmp_win->iconify_by_unmapping |= 300 short_lookup LookInList(Scr->IconifyByUn, tmp_win->full_name, 301 &tmp_win->xclass); 302 303 if (LookInList(Scr->WindowRingL, tmp_win->full_name, &tmp_win->xclass)) { 304 if (Scr->Ring) { 305 tmp_win->ring.next = Scr->Ring->ring.next; 306 if (Scr->Ring->ring.next->ring.prev) 307 Scr->Ring->ring.next->ring.prev = tmp_win; 308 Scr->Ring->ring.next = tmp_win; 309 tmp_win->ring.prev = Scr->Ring; 310 } 311 else { 312 tmp_win->ring.next = tmp_win->ring.prev = Scr->Ring = tmp_win; 313 } 314 } 315 else 316 tmp_win->ring.next = tmp_win->ring.prev = NULL; 317 tmp_win->ring.cursor_valid = False; 318 319 tmp_win->squeeze_info = NULL; 320 /* 321 * get the squeeze information; note that this does not have to be freed 322 * since it is coming from the screen list 323 */ 324 if (HasShape) { 325 if (!LookInList(Scr->DontSqueezeTitleL, tmp_win->full_name, 326 &tmp_win->xclass)) { 327 tmp_win->squeeze_info = (SqueezeInfo *) 328 LookInList(Scr->SqueezeTitleL, tmp_win->full_name, 329 &tmp_win->xclass); 330 if (!tmp_win->squeeze_info) { 331 static SqueezeInfo default_squeeze = { J_LEFT, 0, 0 }; 332 if (Scr->SqueezeTitle) 333 tmp_win->squeeze_info = &default_squeeze; 334 } 335 } 336 } 337 338 tmp_win->old_bw = tmp_win->attr.border_width; 339 340 if (Scr->ClientBorderWidth) { 341 tmp_win->frame_bw = tmp_win->old_bw; 342 } 343 else { 344 tmp_win->frame_bw = Scr->BorderWidth; 345 } 346 bw2 = tmp_win->frame_bw * 2; 347 348 tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw; 349 if (Scr->NoTitlebar) 350 tmp_win->title_height = 0; 351 if (LookInList(Scr->MakeTitle, tmp_win->full_name, &tmp_win->xclass)) 352 tmp_win->title_height = Scr->TitleHeight + tmp_win->frame_bw; 353 if (LookInList(Scr->NoTitle, tmp_win->full_name, &tmp_win->xclass)) 354 tmp_win->title_height = 0; 355 356 /* if it is a transient window, don't put a title on it */ 357 if (tmp_win->transient && !Scr->DecorateTransients) 358 tmp_win->title_height = 0; 359 360 if (LookInList(Scr->StartIconified, tmp_win->full_name, &tmp_win->xclass)) { 361 if (!tmp_win->wmhints) { 362 tmp_win->wmhints = (XWMHints *) malloc(sizeof(XWMHints)); 363 tmp_win->wmhints->flags = 0; 364 } 365 tmp_win->wmhints->initial_state = IconicState; 366 tmp_win->wmhints->flags |= StateHint; 367 } 368 369 GetWindowSizeHints(tmp_win); 370 371 if (restoredFromPrevSession) { 372 /* 373 * When restoring window positions from the previous session, 374 * we always use NorthWest gravity. 375 */ 376 377 gravx = gravy = -1; 378 } 379 else { 380 GetGravityOffsets(tmp_win, &gravx, &gravy); 381 } 382 383 /* 384 * Don't bother user if: 385 * 386 * o the window is a transient, or 387 * 388 * o a USPosition was requested, or 389 * 390 * o a PPosition was requested and UsePPosition is ON or 391 * NON_ZERO if the window is at other than (0,0) 392 */ 393 ask_user = TRUE; 394 if (tmp_win->transient || 395 (tmp_win->hints.flags & USPosition) || 396 ((tmp_win->hints.flags & PPosition) && Scr->UsePPosition && 397 (Scr->UsePPosition == PPOS_ON || 398 tmp_win->attr.x != 0 || tmp_win->attr.y != 0))) 399 ask_user = FALSE; 400 401 /* 402 * do any prompting for position 403 */ 404 if (HandlingEvents && ask_user && !restoredFromPrevSession) { 405 if (Scr->RandomPlacement) { /* just stick it somewhere */ 406 /* Avoid putting the new window off-screen */ 407 if ((PlaceX + tmp_win->attr.width) > Scr->MyDisplayWidth) { 408 PlaceX = Scr->MyDisplayWidth - tmp_win->attr.width; 409 if (PlaceX < 0) 410 PlaceX = 0; 411 if (PlaceX > 50) 412 PlaceX = 50; 413 } 414 if ((PlaceY + tmp_win->attr.height) > Scr->MyDisplayHeight) { 415 PlaceY = Scr->MyDisplayHeight - tmp_win->attr.height; 416 if (PlaceY < 0) 417 PlaceY = 0; 418 if (PlaceY > 50) 419 PlaceY = 50; 420 } 421 422 tmp_win->attr.x = PlaceX; 423 tmp_win->attr.y = PlaceY; 424 PlaceX += 30; 425 PlaceY += 30; 426 } 427 else { /* else prompt */ 428 if (!(tmp_win->wmhints && tmp_win->wmhints->flags & StateHint && 429 tmp_win->wmhints->initial_state == IconicState)) { 430 Bool firsttime = True; 431 int height, width; 432 433 /* better wait until all the mouse buttons have been 434 * released. 435 */ 436 while (TRUE) { 437 int stat; 438 Window root = None; 439 unsigned mask = 0; 440 441 XUngrabServer(dpy); 442 XSync(dpy, 0); 443 XGrabServer(dpy); 444 445 if (!XQueryPointer(dpy, Scr->Root, &root, 446 &wdummy, &dummy, &dummy, 447 &AddingX, &AddingY, &mask)) 448 mask = 0; 449 450 mask &= (Button1Mask | Button2Mask | Button3Mask | 451 Button4Mask | Button5Mask); 452 453 /* 454 * watch out for changing screens 455 */ 456 if (firsttime) { 457 if (root != Scr->Root) { 458 int scrnum; 459 460 for (scrnum = 0; scrnum < NumScreens; scrnum++) { 461 if (root == RootWindow(dpy, scrnum)) 462 break; 463 } 464 465 if (scrnum != NumScreens) 466 PreviousScreen = scrnum; 467 } 468 firsttime = False; 469 } 470 471 /* 472 * wait for buttons to come up; yuck 473 */ 474 if (mask != 0) 475 continue; 476 477 /* 478 * this will cause a warp to the indicated root 479 */ 480 stat = XGrabPointer(dpy, Scr->Root, False, 481 ButtonPressMask | ButtonReleaseMask | 482 PointerMotionMask | 483 PointerMotionHintMask, GrabModeAsync, 484 GrabModeAsync, Scr->Root, 485 UpperLeftCursor, CurrentTime); 486 487 if (stat == GrabSuccess) 488 break; 489 } 490 491 width = (SIZE_HINDENT + MyFont_TextWidth(&Scr->SizeFont, 492 tmp_win->name, 493 namelen)); 494 height = Scr->SizeFont.height + SIZE_VINDENT * 2; 495 496 XResizeWindow(dpy, Scr->SizeWindow, 497 (unsigned) (width + SIZE_HINDENT), 498 (unsigned) height); 499 XMapRaised(dpy, Scr->SizeWindow); 500 InstallRootColormap(); 501 502 MyFont_ChangeGC(Scr->DefaultC.fore, Scr->DefaultC.back, 503 &Scr->SizeFont); 504 MyFont_DrawImageString(dpy, Scr->SizeWindow, &Scr->SizeFont, 505 Scr->NormalGC, 506 SIZE_HINDENT, 507 SIZE_VINDENT + Scr->SizeFont.ascent, 508 tmp_win->name, namelen); 509 510 AddingW = tmp_win->attr.width + bw2; 511 AddingH = tmp_win->attr.height + tmp_win->title_height + bw2; 512 513 if (Scr->DontMoveOff) { 514 /* 515 * Make sure the initial outline comes up on the screen. 516 */ 517 if (AddingX < 0) 518 AddingX = 0; 519 if (AddingX > Scr->MyDisplayWidth - AddingW) 520 AddingX = Scr->MyDisplayWidth - AddingW; 521 522 if (AddingY < 0) 523 AddingY = 0; 524 if (AddingY > Scr->MyDisplayHeight - AddingH) 525 AddingY = Scr->MyDisplayHeight - AddingH; 526 } 527 528 MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH, 529 tmp_win->frame_bw, tmp_win->title_height); 530 531 while (TRUE) { 532 XMaskEvent(dpy, ButtonPressMask | PointerMotionMask, 533 &event); 534 535 if (Event.type == MotionNotify) { 536 /* discard any extra motion events before a release */ 537 while (XCheckMaskEvent(dpy, 538 ButtonMotionMask | 539 ButtonPressMask, &Event)) 540 if (Event.type == ButtonPress) 541 break; 542 } 543 544 if (event.type == ButtonPress) { 545 AddingX = event.xbutton.x_root; 546 AddingY = event.xbutton.y_root; 547 548 /* DontMoveOff prohibits user form off-screen placement */ 549 if (Scr->DontMoveOff) { 550 int AddingR, AddingB; 551 552 AddingR = AddingX + AddingW; 553 AddingB = AddingY + AddingH; 554 555 if (AddingX < 0) 556 AddingX = 0; 557 if (AddingR > Scr->MyDisplayWidth) 558 AddingX = Scr->MyDisplayWidth - AddingW; 559 560 if (AddingY < 0) 561 AddingY = 0; 562 if (AddingB > Scr->MyDisplayHeight) 563 AddingY = Scr->MyDisplayHeight - AddingH; 564 565 } 566 break; 567 } 568 569 if (event.type != MotionNotify) { 570 continue; 571 } 572 573 XQueryPointer(dpy, Scr->Root, &wdummy, &wdummy, 574 &dummy, &dummy, &AddingX, &AddingY, 575 &udummy); 576 577 if (Scr->DontMoveOff) { 578 int AddingR, AddingB; 579 580 AddingR = AddingX + AddingW; 581 AddingB = AddingY + AddingH; 582 583 if (AddingX < 0) 584 AddingX = 0; 585 if (AddingR > Scr->MyDisplayWidth) 586 AddingX = Scr->MyDisplayWidth - AddingW; 587 588 if (AddingY < 0) 589 AddingY = 0; 590 if (AddingB > Scr->MyDisplayHeight) 591 AddingY = Scr->MyDisplayHeight - AddingH; 592 } 593 594 MoveOutline(Scr->Root, AddingX, AddingY, AddingW, AddingH, 595 tmp_win->frame_bw, tmp_win->title_height); 596 597 } 598 599 if (event.xbutton.button == Button2) { 600 int lastx, lasty; 601 602 Scr->SizeStringOffset = width + 603 MyFont_TextWidth(&Scr->SizeFont, ": ", 2); 604 XResizeWindow(dpy, Scr->SizeWindow, 605 (unsigned) (Scr->SizeStringOffset + 606 Scr->SizeStringWidth), 607 (unsigned) height); 608 MyFont_DrawImageString(dpy, Scr->SizeWindow, &Scr->SizeFont, 609 Scr->NormalGC, width, 610 SIZE_VINDENT + Scr->SizeFont.ascent, 611 ": ", 2); 612 if (0 /*Scr->AutoRelativeResize */ ) { 613 int dx = (tmp_win->attr.width / 4); 614 int dy = (tmp_win->attr.height / 4); 615 616#define HALF_AVE_CURSOR_SIZE 8 /* so that it is visible */ 617 if (dx < HALF_AVE_CURSOR_SIZE) 618 dx = HALF_AVE_CURSOR_SIZE; 619 if (dy < HALF_AVE_CURSOR_SIZE) 620 dy = HALF_AVE_CURSOR_SIZE; 621#undef HALF_AVE_CURSOR_SIZE 622 dx += (tmp_win->frame_bw + 1); 623 dy += (bw2 + tmp_win->title_height + 1); 624 if (AddingX + dx >= Scr->MyDisplayWidth) 625 dx = Scr->MyDisplayWidth - AddingX - 1; 626 if (AddingY + dy >= Scr->MyDisplayHeight) 627 dy = Scr->MyDisplayHeight - AddingY - 1; 628 if (dx > 0 && dy > 0) 629 XWarpPointer(dpy, None, None, 0, 0, 0, 0, dx, dy); 630 } 631 else { 632 XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0, 633 AddingX + AddingW / 2, 634 AddingY + AddingH / 2); 635 } 636 AddStartResize(tmp_win, AddingX, AddingY, AddingW, AddingH); 637 638 lastx = -10000; 639 lasty = -10000; 640 while (TRUE) { 641 XMaskEvent(dpy, 642 ButtonReleaseMask | ButtonMotionMask, 643 &event); 644 645 if (Event.type == MotionNotify) { 646 /* discard any extra motion events before a release */ 647 while (XCheckMaskEvent(dpy, 648 ButtonMotionMask | 649 ButtonReleaseMask, &Event)) 650 if (Event.type == ButtonRelease) 651 break; 652 } 653 654 if (event.type == ButtonRelease) { 655 AddEndResize(tmp_win); 656 break; 657 } 658 659 if (event.type != MotionNotify) { 660 continue; 661 } 662 663 /* 664 * XXX - if we are going to do a loop, we ought to consider 665 * using multiple GXxor lines so that we don't need to 666 * grab the server. 667 */ 668 XQueryPointer(dpy, Scr->Root, &wdummy, &wdummy, 669 &dummy, &dummy, &AddingX, &AddingY, 670 &udummy); 671 672 if (lastx != AddingX || lasty != AddingY) { 673 DoResize(AddingX, AddingY, tmp_win); 674 675 lastx = AddingX; 676 lasty = AddingY; 677 } 678 679 } 680 } 681 else if (event.xbutton.button == Button3) { 682 int maxw = Scr->MyDisplayWidth - AddingX; 683 int maxh = Scr->MyDisplayHeight - AddingY; 684 685 /* 686 * Make window go to bottom of screen, and clip to right edge. 687 * This is useful when popping up large windows and fixed 688 * column text windows. 689 */ 690 if (AddingW > maxw) 691 AddingW = maxw; 692 AddingH = maxh; 693 694 AddingW -= bw2; 695 AddingH -= bw2; 696 ConstrainSize(tmp_win, &AddingW, &AddingH); /* w/o borders */ 697 AddingW += bw2; 698 AddingH += bw2; 699 } 700 else { 701 XMaskEvent(dpy, ButtonReleaseMask, &event); 702 } 703 704 MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0); 705 XUnmapWindow(dpy, Scr->SizeWindow); 706 UninstallRootColormap(); 707 XUngrabPointer(dpy, CurrentTime); 708 709 tmp_win->attr.x = AddingX; 710 tmp_win->attr.y = AddingY + tmp_win->title_height; 711 tmp_win->attr.width = AddingW - bw2; 712 tmp_win->attr.height = AddingH - tmp_win->title_height - bw2; 713 714 XUngrabServer(dpy); 715 } 716 } 717 } 718 else { /* put it where asked, mod title bar */ 719 /* if the gravity is towards the top, move it by the title height */ 720 if (gravy < 0) 721 tmp_win->attr.y -= gravy * tmp_win->title_height; 722 } 723 724#ifdef DEBUG 725 fprintf(stderr, " position window %d, %d %dx%d\n", 726 tmp_win->attr.x, 727 tmp_win->attr.y, tmp_win->attr.width, tmp_win->attr.height); 728#endif 729 730 if (!Scr->ClientBorderWidth) { /* need to adjust for twm borders */ 731 int delta = tmp_win->attr.border_width - tmp_win->frame_bw; 732 733 tmp_win->attr.x += gravx * delta; 734 tmp_win->attr.y += gravy * delta; 735 } 736 737 tmp_win->title_width = tmp_win->attr.width; 738 739 if (tmp_win->old_bw) 740 XSetWindowBorderWidth(dpy, tmp_win->w, 0); 741 742 tmp_win->name_width = MyFont_TextWidth(&Scr->TitleBarFont, tmp_win->name, 743 namelen); 744 745 if (!I18N_GetIconName(dpy, tmp_win->w, &name)) { 746 tmp_win->icon_name = strdup(tmp_win->name); 747 } 748 else { 749 if (name == NULL) { 750 tmp_win->icon_name = strdup(tmp_win->name); 751 } 752 else { 753 tmp_win->icon_name = strdup(name); 754 free(name); 755 } 756 } 757 758 tmp_win->iconified = FALSE; 759 tmp_win->icon = FALSE; 760 tmp_win->icon_on = FALSE; 761 762 XGrabServer(dpy); 763 764 /* 765 * Make sure the client window still exists. We don't want to leave an 766 * orphan frame window if it doesn't. Since we now have the server 767 * grabbed, the window can't disappear later without having been 768 * reparented, so we'll get a DestroyNotify for it. We won't have 769 * gotten one for anything up to here, however. 770 */ 771 if (XGetGeometry(dpy, tmp_win->w, &wdummy, &dummy, &dummy, 772 &udummy, &udummy, &udummy, &udummy) == 0) { 773 free(tmp_win); 774 XUngrabServer(dpy); 775 return (NULL); 776 } 777 778 /* add the window into the twm list */ 779 tmp_win->next = Scr->TwmRoot.next; 780 if (Scr->TwmRoot.next != NULL) 781 Scr->TwmRoot.next->prev = tmp_win; 782 tmp_win->prev = &Scr->TwmRoot; 783 Scr->TwmRoot.next = tmp_win; 784 785 /* get all the colors for the window */ 786 787 tmp_win->border = Scr->BorderColor; 788 tmp_win->icon_border = Scr->IconBorderColor; 789 tmp_win->border_tile.fore = Scr->BorderTileC.fore; 790 tmp_win->border_tile.back = Scr->BorderTileC.back; 791 tmp_win->title.fore = Scr->TitleC.fore; 792 tmp_win->title.back = Scr->TitleC.back; 793 tmp_win->iconc.fore = Scr->IconC.fore; 794 tmp_win->iconc.back = Scr->IconC.back; 795 796 GetColorFromList(Scr->BorderColorL, tmp_win->full_name, 797 &tmp_win->xclass, &tmp_win->border); 798 GetColorFromList(Scr->IconBorderColorL, tmp_win->full_name, 799 &tmp_win->xclass, &tmp_win->icon_border); 800 GetColorFromList(Scr->BorderTileForegroundL, tmp_win->full_name, 801 &tmp_win->xclass, &tmp_win->border_tile.fore); 802 GetColorFromList(Scr->BorderTileBackgroundL, tmp_win->full_name, 803 &tmp_win->xclass, &tmp_win->border_tile.back); 804 GetColorFromList(Scr->TitleForegroundL, tmp_win->full_name, 805 &tmp_win->xclass, &tmp_win->title.fore); 806 GetColorFromList(Scr->TitleBackgroundL, tmp_win->full_name, 807 &tmp_win->xclass, &tmp_win->title.back); 808 GetColorFromList(Scr->IconForegroundL, tmp_win->full_name, 809 &tmp_win->xclass, &tmp_win->iconc.fore); 810 GetColorFromList(Scr->IconBackgroundL, tmp_win->full_name, 811 &tmp_win->xclass, &tmp_win->iconc.back); 812 813 /* create windows */ 814 815 tmp_win->frame_x = tmp_win->attr.x + tmp_win->old_bw - tmp_win->frame_bw; 816 tmp_win->frame_y = tmp_win->attr.y - tmp_win->title_height + 817 tmp_win->old_bw - tmp_win->frame_bw; 818 tmp_win->frame_width = tmp_win->attr.width; 819 tmp_win->frame_height = tmp_win->attr.height + tmp_win->title_height; 820 821 valuemask = CWBackPixmap | CWBorderPixel | CWCursor | CWEventMask; 822 attributes.background_pixmap = None; 823 attributes.border_pixel = tmp_win->border; 824 attributes.cursor = Scr->FrameCursor; 825 attributes.event_mask = (SubstructureRedirectMask | 826 ButtonPressMask | ButtonReleaseMask | 827 EnterWindowMask | LeaveWindowMask); 828 if (tmp_win->attr.save_under) { 829 attributes.save_under = True; 830 valuemask |= CWSaveUnder; 831 } 832 833 tmp_win->frame = XCreateWindow(dpy, Scr->Root, tmp_win->frame_x, 834 tmp_win->frame_y, 835 (unsigned int) tmp_win->frame_width, 836 (unsigned int) tmp_win->frame_height, 837 (unsigned int) tmp_win->frame_bw, 838 Scr->d_depth, 839 (unsigned int) CopyFromParent, 840 Scr->d_visual, valuemask, &attributes); 841 842 if (tmp_win->title_height) { 843 valuemask = (CWEventMask | CWBorderPixel | CWBackPixel); 844 attributes.event_mask = (KeyPressMask | ButtonPressMask | 845 ButtonReleaseMask | ExposureMask); 846 attributes.border_pixel = tmp_win->border; 847 attributes.background_pixel = tmp_win->title.back; 848 tmp_win->title_w = XCreateWindow(dpy, tmp_win->frame, 849 -tmp_win->frame_bw, 850 -tmp_win->frame_bw, 851 (unsigned int) tmp_win->attr.width, 852 (unsigned int) Scr->TitleHeight, 853 (unsigned int) tmp_win->frame_bw, 854 Scr->d_depth, 855 (unsigned int) CopyFromParent, 856 Scr->d_visual, valuemask, &attributes); 857 } 858 else { 859 tmp_win->title_w = 0; 860 tmp_win->squeeze_info = NULL; 861 } 862 863 if (tmp_win->highlight) { 864 tmp_win->gray = XCreatePixmapFromBitmapData(dpy, Scr->Root, 865 gray_bits, gray_width, 866 gray_height, 867 tmp_win->border_tile.fore, 868 tmp_win->border_tile.back, 869 (unsigned) Scr->d_depth); 870 871 SetBorder(tmp_win, False); 872 } 873 else 874 tmp_win->gray = None; 875 876 if (tmp_win->title_w) { 877 CreateWindowTitlebarButtons(tmp_win); 878 ComputeTitleLocation(tmp_win); 879 XMoveWindow(dpy, tmp_win->title_w, tmp_win->title_x, tmp_win->title_y); 880 XDefineCursor(dpy, tmp_win->title_w, Scr->TitleCursor); 881 } 882 883 valuemask = (CWEventMask | CWDontPropagate); 884 attributes.event_mask = (StructureNotifyMask | PropertyChangeMask | 885 ColormapChangeMask | VisibilityChangeMask | 886 EnterWindowMask | LeaveWindowMask); 887 attributes.do_not_propagate_mask = ButtonPressMask | ButtonReleaseMask; 888 XChangeWindowAttributes(dpy, tmp_win->w, valuemask, &attributes); 889 890 if (HasShape) 891 XShapeSelectInput(dpy, tmp_win->w, ShapeNotifyMask); 892 893 if (tmp_win->title_w) { 894 XMapWindow(dpy, tmp_win->title_w); 895 } 896 897 if (HasShape) { 898 int xws, yws, xbs, ybs; 899 unsigned wws, hws, wbs, hbs; 900 int boundingShaped, clipShaped; 901 902 XShapeSelectInput(dpy, tmp_win->w, ShapeNotifyMask); 903 XShapeQueryExtents(dpy, tmp_win->w, 904 &boundingShaped, &xws, &yws, &wws, &hws, 905 &clipShaped, &xbs, &ybs, &wbs, &hbs); 906 tmp_win->wShaped = (short) boundingShaped; 907 } 908 909 if (!tmp_win->iconmgr) 910 XAddToSaveSet(dpy, tmp_win->w); 911 912 XReparentWindow(dpy, tmp_win->w, tmp_win->frame, 0, tmp_win->title_height); 913 /* 914 * Reparenting generates an UnmapNotify event, followed by a MapNotify. 915 * Set the map state to FALSE to prevent a transition back to 916 * WithdrawnState in HandleUnmapNotify. Map state gets set correctly 917 * again in HandleMapNotify. 918 */ 919 tmp_win->mapped = FALSE; 920 921 SetupFrame(tmp_win, tmp_win->frame_x, tmp_win->frame_y, 922 tmp_win->frame_width, tmp_win->frame_height, -1, True); 923 924 /* wait until the window is iconified and the icon window is mapped 925 * before creating the icon window 926 */ 927 tmp_win->icon_w = (Window) 0; 928 929 if (!tmp_win->iconmgr) { 930 GrabButtons(tmp_win); 931 GrabKeys(tmp_win); 932 } 933 934 (void) AddIconManager(tmp_win); 935 936 XSaveContext(dpy, tmp_win->w, TwmContext, (XPointer) tmp_win); 937 XSaveContext(dpy, tmp_win->w, ScreenContext, (XPointer) Scr); 938 XSaveContext(dpy, tmp_win->frame, TwmContext, (XPointer) tmp_win); 939 XSaveContext(dpy, tmp_win->frame, ScreenContext, (XPointer) Scr); 940 if (tmp_win->title_height) { 941 int i; 942 int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; 943 944 XSaveContext(dpy, tmp_win->title_w, TwmContext, (XPointer) tmp_win); 945 XSaveContext(dpy, tmp_win->title_w, ScreenContext, (XPointer) Scr); 946 for (i = 0; i < nb; i++) { 947 XSaveContext(dpy, tmp_win->titlebuttons[i].window, TwmContext, 948 (XPointer) tmp_win); 949 XSaveContext(dpy, tmp_win->titlebuttons[i].window, ScreenContext, 950 (XPointer) Scr); 951 } 952 if (tmp_win->hilite_w) { 953 XSaveContext(dpy, tmp_win->hilite_w, TwmContext, 954 (XPointer) tmp_win); 955 XSaveContext(dpy, tmp_win->hilite_w, ScreenContext, (XPointer) Scr); 956 } 957 } 958 959 XUngrabServer(dpy); 960 961 /* if we were in the middle of a menu activated function, regrab 962 * the pointer 963 */ 964 if (RootFunction) 965 ReGrab(); 966 967 return (tmp_win); 968} 969 970/** 971 * checks to see if we should really put a twm frame on the window 972 * 973 * \return TRUE - go ahead and place the window 974 * \return FALSE - don't frame the window 975 * \param w the window to check 976 */ 977int 978MappedNotOverride(Window w) 979{ 980 XWindowAttributes wa; 981 982 XGetWindowAttributes(dpy, w, &wa); 983 return ((wa.map_state != IsUnmapped) && (wa.override_redirect != True)); 984} 985 986/** 987 * attach default bindings so that naive users don't get messed up if they 988 * provide a minimal twmrc. 989 */ 990static void 991do_add_binding(int button, int context, int modifier, int func) 992{ 993 MouseButton *mb = &Scr->Mouse[button][context][modifier]; 994 995 if (mb->func) 996 return; /* already defined */ 997 998 mb->func = func; 999 mb->item = NULL; 1000} 1001 1002void 1003AddDefaultBindings(void) 1004{ 1005 /* 1006 * The bindings are stored in Scr->Mouse, indexed by 1007 * Mouse[button_number][C_context][modifier]. 1008 */ 1009 1010#define NoModifierMask 0 1011 1012 do_add_binding(Button1, C_TITLE, NoModifierMask, F_MOVE); 1013 do_add_binding(Button1, C_ICON, NoModifierMask, F_ICONIFY); 1014 do_add_binding(Button1, C_ICONMGR, NoModifierMask, F_ICONIFY); 1015 1016 do_add_binding(Button2, C_TITLE, NoModifierMask, F_RAISELOWER); 1017 do_add_binding(Button2, C_ICON, NoModifierMask, F_ICONIFY); 1018 do_add_binding(Button2, C_ICONMGR, NoModifierMask, F_ICONIFY); 1019 1020#undef NoModifierMask 1021} 1022 1023/** 1024 * grab needed buttons for the window 1025 * 1026 * \param[in] tmp_win the twm window structure to use 1027 */ 1028void 1029GrabButtons(TwmWindow *tmp_win) 1030{ 1031 int i, j; 1032 1033 for (i = 0; i < MAX_BUTTONS + 1; i++) { 1034 for (j = 0; j < MOD_SIZE; j++) { 1035 if (Scr->Mouse[i][C_WINDOW][j].func != 0) { 1036 /* twm used to do this grab on the application main window, 1037 * tmp_win->w . This was not ICCCM compliant and was changed. 1038 */ 1039 XGrabButton(dpy, (unsigned) i, (unsigned) j, tmp_win->frame, 1040 True, ButtonPressMask | ButtonReleaseMask, 1041 GrabModeAsync, GrabModeAsync, None, 1042 Scr->FrameCursor); 1043 } 1044 } 1045 } 1046} 1047 1048/** 1049 * grab needed keys for the window 1050 * 1051 * \param[in] tmp_win the twm window structure to use 1052 */ 1053void 1054GrabKeys(TwmWindow *tmp_win) 1055{ 1056 FuncKey *tmp; 1057 IconMgr *p; 1058 1059 for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) { 1060 switch (tmp->cont) { 1061 case C_WINDOW: 1062 XGrabKey(dpy, tmp->keycode, (unsigned) tmp->mods, tmp_win->w, True, 1063 GrabModeAsync, GrabModeAsync); 1064 break; 1065 1066 case C_ICON: 1067 if (tmp_win->icon_w) 1068 XGrabKey(dpy, tmp->keycode, (unsigned) tmp->mods, 1069 tmp_win->icon_w, True, GrabModeAsync, GrabModeAsync); 1070 /* FALLTHRU */ 1071 1072 case C_TITLE: 1073 if (tmp_win->title_w) 1074 XGrabKey(dpy, tmp->keycode, (unsigned) tmp->mods, 1075 tmp_win->title_w, True, GrabModeAsync, GrabModeAsync); 1076 break; 1077 1078 case C_NAME: 1079 XGrabKey(dpy, tmp->keycode, (unsigned) tmp->mods, tmp_win->w, True, 1080 GrabModeAsync, GrabModeAsync); 1081 if (tmp_win->icon_w) 1082 XGrabKey(dpy, tmp->keycode, (unsigned) tmp->mods, 1083 tmp_win->icon_w, True, GrabModeAsync, GrabModeAsync); 1084 if (tmp_win->title_w) 1085 XGrabKey(dpy, tmp->keycode, (unsigned) tmp->mods, 1086 tmp_win->title_w, True, GrabModeAsync, GrabModeAsync); 1087 break; 1088 /* 1089 case C_ROOT: 1090 XGrabKey(dpy, tmp->keycode, tmp->mods, Scr->Root, True, 1091 GrabModeAsync, GrabModeAsync); 1092 break; 1093 */ 1094 } 1095 } 1096 for (tmp = Scr->FuncKeyRoot.next; tmp != NULL; tmp = tmp->next) { 1097 if (tmp->cont == C_ICONMGR && !Scr->NoIconManagers) { 1098 for (p = &Scr->iconmgr; p != NULL; p = p->next) { 1099 XUngrabKey(dpy, tmp->keycode, (unsigned) tmp->mods, 1100 p->twm_win->w); 1101 } 1102 } 1103 } 1104} 1105 1106static Window 1107CreateHighlightWindow(TwmWindow *tmp_win) 1108{ 1109 XSetWindowAttributes attributes; /* attributes for create windows */ 1110 Pixmap pm = None; 1111 GC gc; 1112 XGCValues gcv; 1113 unsigned long valuemask; 1114 int h = (Scr->TitleHeight - 2 * Scr->FramePadding); 1115 Window w; 1116 1117 /* 1118 * If a special highlight pixmap was given, use that. Otherwise, 1119 * use a nice, even gray pattern. The old horizontal lines look really 1120 * awful on interlaced monitors (as well as resembling other looks a 1121 * little bit too closely), but can be used by putting 1122 * 1123 * Pixmaps { TitleHighlight "hline2" } 1124 * 1125 * (or whatever the horizontal line bitmap is named) in the startup 1126 * file. If all else fails, use the foreground color to look like a 1127 * solid line. 1128 */ 1129 if (!Scr->hilitePm) { 1130 Scr->hilitePm = XCreateBitmapFromData(dpy, tmp_win->title_w, 1131 gray_bits, gray_width, 1132 gray_height); 1133 Scr->hilite_pm_width = gray_width; 1134 Scr->hilite_pm_height = gray_height; 1135 } 1136 if (Scr->hilitePm) { 1137 pm = XCreatePixmap(dpy, tmp_win->title_w, 1138 (unsigned) Scr->hilite_pm_width, 1139 (unsigned) Scr->hilite_pm_height, 1140 (unsigned) Scr->d_depth); 1141 gcv.foreground = tmp_win->title.fore; 1142 gcv.background = tmp_win->title.back; 1143 gcv.graphics_exposures = False; 1144 gc = XCreateGC(dpy, pm, 1145 (GCForeground | GCBackground | GCGraphicsExposures), 1146 &gcv); 1147 if (gc) { 1148 XCopyPlane(dpy, Scr->hilitePm, pm, gc, 0, 0, 1149 (unsigned) Scr->hilite_pm_width, 1150 (unsigned) Scr->hilite_pm_height, 0, 0, 1); 1151 XFreeGC(dpy, gc); 1152 } 1153 else { 1154 XFreePixmap(dpy, pm); 1155 pm = None; 1156 } 1157 } 1158 if (pm) { 1159 valuemask = CWBackPixmap; 1160 attributes.background_pixmap = pm; 1161 } 1162 else { 1163 valuemask = CWBackPixel; 1164 attributes.background_pixel = tmp_win->title.fore; 1165 } 1166 1167 w = XCreateWindow(dpy, tmp_win->title_w, 0, Scr->FramePadding, 1168 (unsigned int) Scr->TBInfo.width, (unsigned int) h, 1169 (unsigned int) 0, 1170 Scr->d_depth, (unsigned int) CopyFromParent, 1171 Scr->d_visual, valuemask, &attributes); 1172 if (pm) 1173 XFreePixmap(dpy, pm); 1174 return w; 1175} 1176 1177void 1178ComputeCommonTitleOffsets(void) 1179{ 1180 int buttonwidth = (Scr->TBInfo.width + Scr->TBInfo.pad); 1181 1182 Scr->TBInfo.leftx = Scr->TBInfo.rightoff = Scr->FramePadding; 1183 if (Scr->TBInfo.nleft > 0) 1184 Scr->TBInfo.leftx += Scr->ButtonIndent; 1185 Scr->TBInfo.titlex = (Scr->TBInfo.leftx + 1186 (Scr->TBInfo.nleft * buttonwidth) - 1187 Scr->TBInfo.pad + Scr->TitlePadding); 1188 if (Scr->TBInfo.nright > 0) 1189 Scr->TBInfo.rightoff += (Scr->ButtonIndent + 1190 ((Scr->TBInfo.nright * buttonwidth) - 1191 Scr->TBInfo.pad)); 1192 return; 1193} 1194 1195void 1196ComputeWindowTitleOffsets(TwmWindow *tmp_win, int width, Bool squeeze) 1197{ 1198 tmp_win->highlightx = (Scr->TBInfo.titlex + tmp_win->name_width); 1199 if (tmp_win->hilite_w || Scr->TBInfo.nright > 0) 1200 tmp_win->highlightx += Scr->TitlePadding; 1201 tmp_win->rightx = width - Scr->TBInfo.rightoff; 1202 if (squeeze && tmp_win->squeeze_info) { 1203 int rx = (tmp_win->highlightx + 1204 (tmp_win->hilite_w 1205 ? Scr->TBInfo.width * 2 : 0) + 1206 (Scr->TBInfo.nright > 0 ? Scr->TitlePadding : 0) + 1207 Scr->FramePadding); 1208 if (rx < tmp_win->rightx) 1209 tmp_win->rightx = rx; 1210 } 1211 return; 1212} 1213 1214/** 1215 * calculate the position of the title window. We need to take the frame_bw 1216 * into account since we want (0,0) of the title window to line up with (0,0) 1217 * of the frame window. 1218 */ 1219void 1220ComputeTitleLocation(TwmWindow *tmp) 1221{ 1222 tmp->title_x = -tmp->frame_bw; 1223 tmp->title_y = -tmp->frame_bw; 1224 1225 if (tmp->squeeze_info) { 1226 SqueezeInfo *si = tmp->squeeze_info; 1227 int basex; 1228 int maxwidth = tmp->frame_width; 1229 int tw = tmp->title_width; 1230 1231 /* 1232 * figure label base from squeeze info (justification fraction) 1233 */ 1234 if (si->denom == 0) { /* num is pixel based */ 1235 if ((basex = si->num) == 0) { /* look for special cases */ 1236 switch (si->justify) { 1237 case J_RIGHT: 1238 basex = maxwidth; 1239 break; 1240 case J_CENTER: 1241 basex = maxwidth / 2; 1242 break; 1243 } 1244 } 1245 } 1246 else { /* num/denom is fraction */ 1247 basex = ((si->num * maxwidth) / si->denom); 1248 if (si->num < 0) 1249 basex += maxwidth; 1250 } 1251 1252 /* 1253 * adjust for left (nop), center, right justify and clip 1254 */ 1255 switch (si->justify) { 1256 case J_CENTER: 1257 basex -= tw / 2; 1258 break; 1259 case J_RIGHT: 1260 basex -= tw - 1; 1261 break; 1262 } 1263 if (basex > maxwidth - tw + 1) 1264 basex = maxwidth - tw + 1; 1265 if (basex < 0) 1266 basex = 0; 1267 1268 tmp->title_x = basex - tmp->frame_bw; 1269 } 1270} 1271 1272static void 1273CreateWindowTitlebarButtons(TwmWindow *tmp_win) 1274{ 1275 unsigned long valuemask; /* mask for create windows */ 1276 XSetWindowAttributes attributes; /* attributes for create windows */ 1277 int leftx, rightx, y; 1278 TitleButton *tb; 1279 int nb; 1280 1281 if (tmp_win->title_height == 0) { 1282 tmp_win->hilite_w = 0; 1283 return; 1284 } 1285 1286 /* 1287 * create the title bar windows; let the event handler deal with painting 1288 * so that we don't have to spend two pixmaps (or deal with hashing) 1289 */ 1290 ComputeWindowTitleOffsets(tmp_win, tmp_win->attr.width, False); 1291 1292 leftx = y = Scr->TBInfo.leftx; 1293 rightx = tmp_win->rightx; 1294 1295 attributes.win_gravity = NorthWestGravity; 1296 attributes.background_pixel = tmp_win->title.back; 1297 attributes.border_pixel = tmp_win->title.fore; 1298 attributes.event_mask = (ButtonPressMask | ButtonReleaseMask | 1299 ExposureMask); 1300 attributes.cursor = Scr->ButtonCursor; 1301 valuemask = (CWWinGravity | CWBackPixel | CWBorderPixel | CWEventMask | 1302 CWCursor); 1303 1304 tmp_win->titlebuttons = NULL; 1305 nb = Scr->TBInfo.nleft + Scr->TBInfo.nright; 1306 if (nb > 0) { 1307 tmp_win->titlebuttons = (TBWindow *) 1308 malloc((size_t) nb * sizeof(TBWindow)); 1309 if (!tmp_win->titlebuttons) { 1310 twmWarning("unable to allocate %d titlebuttons", nb); 1311 } 1312 else { 1313 TBWindow *tbw; 1314 int boxwidth = (Scr->TBInfo.width + Scr->TBInfo.pad); 1315 unsigned h = 1316 (unsigned) (Scr->TBInfo.width - Scr->TBInfo.border * 2); 1317 1318 for (tb = Scr->TBInfo.head, tbw = tmp_win->titlebuttons; tb; 1319 tb = tb->next, tbw++) { 1320 int x; 1321 1322 if (tb->rightside) { 1323 x = rightx; 1324 rightx += boxwidth; 1325 attributes.win_gravity = NorthEastGravity; 1326 } 1327 else { 1328 x = leftx; 1329 leftx += boxwidth; 1330 attributes.win_gravity = NorthWestGravity; 1331 } 1332 tbw->window = XCreateWindow(dpy, tmp_win->title_w, x, y, h, h, 1333 (unsigned int) Scr->TBInfo.border, 1334 0, (unsigned int) CopyFromParent, 1335 (Visual *) CopyFromParent, 1336 valuemask, &attributes); 1337 tbw->info = tb; 1338 } 1339 } 1340 } 1341 1342 tmp_win->hilite_w = (tmp_win->titlehighlight 1343 ? CreateHighlightWindow(tmp_win) : None); 1344 1345 XMapSubwindows(dpy, tmp_win->title_w); 1346 if (tmp_win->hilite_w) 1347 XUnmapWindow(dpy, tmp_win->hilite_w); 1348 return; 1349} 1350 1351void 1352SetHighlightPixmap(char *filename) 1353{ 1354 unsigned width = 0; 1355 unsigned height = 0; 1356 1357 Pixmap pm = FindBitmap(filename, &width, &height); 1358 1359 if (pm) { 1360 if (Scr->hilitePm) { 1361 XFreePixmap(dpy, Scr->hilitePm); 1362 } 1363 Scr->hilitePm = pm; 1364 Scr->hilite_pm_width = (int) width; 1365 Scr->hilite_pm_height = (int) height; 1366 } 1367} 1368 1369void 1370FetchWmProtocols(TwmWindow *tmp) 1371{ 1372 unsigned long flags = 0L; 1373 Atom *protocols = NULL; 1374 int n; 1375 1376 if (XGetWMProtocols(dpy, tmp->w, &protocols, &n)) { 1377 int i; 1378 Atom *ap; 1379 1380 for (i = 0, ap = protocols; i < n; i++, ap++) { 1381 if (*ap == _XA_WM_TAKE_FOCUS) 1382 flags |= DoesWmTakeFocus; 1383 if (*ap == _XA_WM_SAVE_YOURSELF) 1384 flags |= DoesWmSaveYourself; 1385 if (*ap == _XA_WM_DELETE_WINDOW) 1386 flags |= DoesWmDeleteWindow; 1387 } 1388 if (protocols) 1389 XFree(protocols); 1390 } 1391 tmp->protocols = flags; 1392} 1393 1394TwmColormap * 1395CreateTwmColormap(Colormap c) 1396{ 1397 TwmColormap *cmap; 1398 1399 cmap = (TwmColormap *) calloc(1, sizeof(TwmColormap)); 1400 if (!cmap || XSaveContext(dpy, c, ColormapContext, (XPointer) cmap)) { 1401 if (cmap) 1402 free(cmap); 1403 return (NULL); 1404 } 1405 cmap->c = c; 1406 cmap->state = 0; 1407 cmap->install_req = 0; 1408 cmap->w = None; 1409 cmap->refcnt = 1; 1410 return (cmap); 1411} 1412 1413ColormapWindow * 1414CreateColormapWindow(Window w, Bool creating_parent, Bool property_window) 1415{ 1416 ColormapWindow *cwin; 1417 TwmColormap *cmap; 1418 XWindowAttributes attributes; 1419 1420 cwin = (ColormapWindow *) malloc(sizeof(ColormapWindow)); 1421 if (cwin) { 1422 if (!XGetWindowAttributes(dpy, w, &attributes) || 1423 XSaveContext(dpy, w, ColormapContext, (XPointer) cwin)) { 1424 free(cwin); 1425 return (NULL); 1426 } 1427 1428 if (XFindContext(dpy, attributes.colormap, ColormapContext, 1429 (XPointer *) &cwin->colormap) == XCNOENT) { 1430 cwin->colormap = cmap = CreateTwmColormap(attributes.colormap); 1431 if (!cmap) { 1432 XDeleteContext(dpy, w, ColormapContext); 1433 free(cwin); 1434 return (NULL); 1435 } 1436 } 1437 else { 1438 cwin->colormap->refcnt++; 1439 } 1440 1441 cwin->w = w; 1442 /* 1443 * Assume that windows in colormap list are 1444 * obscured if we are creating the parent window. 1445 * Otherwise, we assume they are unobscured. 1446 */ 1447 cwin->visibility = creating_parent ? 1448 VisibilityPartiallyObscured : VisibilityUnobscured; 1449 cwin->refcnt = 1; 1450 1451 /* 1452 * If this is a ColormapWindow property window and we 1453 * are not monitoring ColormapNotify or VisibilityNotify 1454 * events, we need to. 1455 */ 1456 if (property_window && 1457 (attributes.your_event_mask & 1458 (ColormapChangeMask | VisibilityChangeMask)) != 1459 (ColormapChangeMask | VisibilityChangeMask)) { 1460 XSelectInput(dpy, w, attributes.your_event_mask | 1461 (ColormapChangeMask | VisibilityChangeMask)); 1462 } 1463 } 1464 1465 return (cwin); 1466} 1467 1468void 1469FetchWmColormapWindows(TwmWindow *tmp) 1470{ 1471 int i, j; 1472 Window *cmap_windows = NULL; 1473 Bool can_free_cmap_windows = False; 1474 int number_cmap_windows = 0; 1475 ColormapWindow **cwins = NULL; 1476 int previously_installed; 1477 1478 number_cmap_windows = 0; 1479 1480 /* SUPPRESS 560 */ 1481 if ((previously_installed = 1482 (Scr->cmapInfo.cmaps == &tmp->cmaps && tmp->cmaps.number_cwins))) { 1483 cwins = tmp->cmaps.cwins; 1484 for (i = 0; i < tmp->cmaps.number_cwins; i++) 1485 cwins[i]->colormap->state = 0; 1486 } 1487 1488 if (XGetWMColormapWindows(dpy, tmp->w, &cmap_windows, 1489 &number_cmap_windows) && 1490 number_cmap_windows > 0) { 1491 1492 can_free_cmap_windows = False; 1493 /* 1494 * check if the top level is in the list, add to front if not 1495 */ 1496 for (i = 0; i < number_cmap_windows; i++) { 1497 if (cmap_windows[i] == tmp->w) 1498 break; 1499 } 1500 if (i == number_cmap_windows) { /* not in list */ 1501 Window *new_cmap_windows = (Window *) 1502 malloc(sizeof(Window) * (size_t) (number_cmap_windows + 1)); 1503 1504 if (!new_cmap_windows) { 1505 twmWarning 1506 ("unable to allocate %d element colormap window array", 1507 number_cmap_windows + 1); 1508 goto done; 1509 } 1510 new_cmap_windows[0] = tmp->w; /* add to front */ 1511 for (i = 0; i < number_cmap_windows; i++) { /* append rest */ 1512 new_cmap_windows[i + 1] = cmap_windows[i]; 1513 } 1514 XFree(cmap_windows); 1515 can_free_cmap_windows = True; /* do not use XFree any more */ 1516 cmap_windows = new_cmap_windows; 1517 number_cmap_windows++; 1518 } 1519 1520 cwins = (ColormapWindow **) 1521 malloc(sizeof(ColormapWindow *) * (size_t) number_cmap_windows); 1522 if (cwins) { 1523 for (i = 0; i < number_cmap_windows; i++) { 1524 1525 /* 1526 * Copy any existing entries into new list. 1527 */ 1528 for (j = 0; j < tmp->cmaps.number_cwins; j++) { 1529 if (tmp->cmaps.cwins[j]->w == cmap_windows[i]) { 1530 cwins[i] = tmp->cmaps.cwins[j]; 1531 cwins[i]->refcnt++; 1532 break; 1533 } 1534 } 1535 1536 /* 1537 * If the colormap window is not being pointed by 1538 * some other applications colormap window list, 1539 * create a new entry. 1540 */ 1541 if (j == tmp->cmaps.number_cwins) { 1542 if (XFindContext(dpy, cmap_windows[i], ColormapContext, 1543 (XPointer *) &cwins[i]) == XCNOENT) { 1544 if ((cwins[i] = 1545 CreateColormapWindow(cmap_windows[i], 1546 (tmp->cmaps.number_cwins == 0 1547 ? True 1548 : False), True)) == NULL) { 1549 int k; 1550 1551 for (k = i + 1; k < number_cmap_windows; k++) 1552 cmap_windows[k - 1] = cmap_windows[k]; 1553 i--; 1554 number_cmap_windows--; 1555 } 1556 } 1557 else 1558 cwins[i]->refcnt++; 1559 } 1560 } 1561 } 1562 } 1563 1564 /* No else here, in case we bailed out of clause above. 1565 */ 1566 if (number_cmap_windows == 0) { 1567 1568 number_cmap_windows = 1; 1569 1570 cwins = (ColormapWindow **) malloc(sizeof(ColormapWindow *)); 1571 if (XFindContext(dpy, tmp->w, ColormapContext, (XPointer *) &cwins[0]) 1572 == XCNOENT) { 1573 cwins[0] = 1574 CreateColormapWindow(tmp->w, 1575 (Bool) tmp->cmaps.number_cwins == 0, 1576 False); 1577 if (cwins[0] == NULL) 1578 number_cmap_windows = 0; 1579 } 1580 else 1581 cwins[0]->refcnt++; 1582 } 1583 1584 if (tmp->cmaps.number_cwins) 1585 free_cwins(tmp); 1586 1587 tmp->cmaps.cwins = cwins; 1588 tmp->cmaps.number_cwins = number_cmap_windows; 1589 if (number_cmap_windows > 1) 1590 tmp->cmaps.scoreboard = (char *) 1591 calloc(1, ColormapsScoreboardLength(&tmp->cmaps)); 1592 1593 if (previously_installed) 1594 InstallWindowColormaps(PropertyNotify, (TwmWindow *) NULL); 1595 1596 done: 1597 if (cmap_windows) { 1598 if (can_free_cmap_windows) 1599 free(cmap_windows); 1600 else 1601 XFree(cmap_windows); 1602 } 1603 1604 return; 1605} 1606 1607void 1608GetWindowSizeHints(TwmWindow *tmp) 1609{ 1610 long supplied = 0; 1611 1612 if (!XGetWMNormalHints(dpy, tmp->w, &tmp->hints, &supplied)) 1613 tmp->hints.flags = 0; 1614 1615 if (tmp->hints.flags & PResizeInc) { 1616 if (tmp->hints.width_inc == 0) 1617 tmp->hints.width_inc = 1; 1618 if (tmp->hints.height_inc == 0) 1619 tmp->hints.height_inc = 1; 1620 } 1621 1622 if (!(supplied & PWinGravity) && (tmp->hints.flags & USPosition)) { 1623 static int gravs[] = { SouthEastGravity, SouthWestGravity, 1624 NorthEastGravity, NorthWestGravity 1625 }; 1626 int right = tmp->attr.x + tmp->attr.width + 2 * tmp->old_bw; 1627 int bottom = tmp->attr.y + tmp->attr.height + 2 * tmp->old_bw; 1628 1629 tmp->hints.win_gravity = 1630 gravs[((Scr->MyDisplayHeight - bottom < 1631 tmp->title_height) ? 0 : 2) | ((Scr->MyDisplayWidth - 1632 right < 1633 tmp->title_height) ? 0 : 1634 1)]; 1635 tmp->hints.flags |= PWinGravity; 1636 } 1637} 1638