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