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