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 * window resizing borrowed from the "wm" window manager 55 * 56 * 11-Dec-87 Thomas E. LaStrange File created 57 * 58 ***********************************************************************/ 59 60#include <stdio.h> 61#include "twm.h" 62#include "parse.h" 63#include "util.h" 64#include "resize.h" 65#include "iconmgr.h" 66#include "add_window.h" 67#include "screen.h" 68#include "events.h" 69 70static void DisplaySize(TwmWindow *tmp_win, int width, int height); 71 72#define MINHEIGHT 0 /* had been 32 */ 73#define MINWIDTH 0 /* had been 60 */ 74 75static int dragx; /* all these variables are used */ 76static int dragy; /* in resize operations */ 77static int dragWidth; 78static int dragHeight; 79 80static int origx; 81static int origy; 82static int origWidth; 83static int origHeight; 84 85static int clampTop; 86static int clampBottom; 87static int clampLeft; 88static int clampRight; 89static int clampDX; 90static int clampDY; 91 92static int last_width; 93static int last_height; 94 95static void 96do_auto_clamp(TwmWindow *tmp_win, XEvent *evp) 97{ 98 Window junkRoot; 99 int x, y, h, v, junkbw; 100 unsigned int junkMask; 101 102 switch (evp->type) { 103 case ButtonPress: 104 x = evp->xbutton.x_root; 105 y = evp->xbutton.y_root; 106 break; 107 case KeyPress: 108 x = evp->xkey.x_root; 109 y = evp->xkey.y_root; 110 break; 111 default: 112 if (!XQueryPointer(dpy, Scr->Root, &junkRoot, &junkRoot, 113 &x, &y, &junkbw, &junkbw, &junkMask)) 114 return; 115 } 116 117 h = ((x - dragx) / (dragWidth < 3 ? 1 : (dragWidth / 3))); 118 v = ((y - dragy - tmp_win->title_height) / 119 (dragHeight < 3 ? 1 : (dragHeight / 3))); 120 121 if (h <= 0) { 122 clampLeft = 1; 123 clampDX = (x - dragx); 124 } 125 else if (h >= 2) { 126 clampRight = 1; 127 clampDX = (x - dragx - dragWidth); 128 } 129 130 if (v <= 0) { 131 clampTop = 1; 132 clampDY = (y - dragy); 133 } 134 else if (v >= 2) { 135 clampBottom = 1; 136 clampDY = (y - dragy - dragHeight); 137 } 138} 139 140/** 141 * begin a window resize operation 142 * \param ev the event structure (button press) 143 * \param tmp_win the TwmWindow pointer 144 * \param fromtitlebar action invoked from titlebar button 145 */ 146void 147StartResize(XEvent *evp, TwmWindow *tmp_win, Bool fromtitlebar) 148{ 149 Window junkRoot; 150 unsigned int junkbw, junkDepth; 151 152 ResizeWindow = tmp_win->frame; 153 XGrabServer(dpy); 154 XGrabPointer(dpy, Scr->Root, True, 155 ButtonPressMask | ButtonReleaseMask | 156 ButtonMotionMask | PointerMotionHintMask, 157 GrabModeAsync, GrabModeAsync, 158 Scr->Root, Scr->ResizeCursor, CurrentTime); 159 160 XGetGeometry(dpy, (Drawable) tmp_win->frame, &junkRoot, 161 &dragx, &dragy, (unsigned int *) &dragWidth, 162 (unsigned int *) &dragHeight, &junkbw, &junkDepth); 163 dragx += tmp_win->frame_bw; 164 dragy += tmp_win->frame_bw; 165 origx = dragx; 166 origy = dragy; 167 origWidth = dragWidth; 168 origHeight = dragHeight; 169 clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0; 170 171 if (Scr->AutoRelativeResize && !fromtitlebar) 172 do_auto_clamp(tmp_win, evp); 173 174 Scr->SizeStringOffset = SIZE_HINDENT; 175 XResizeWindow(dpy, Scr->SizeWindow, 176 (unsigned) (Scr->SizeStringWidth + SIZE_HINDENT * 2), 177 (unsigned) (Scr->SizeFont.height + SIZE_VINDENT * 2)); 178 XMapRaised(dpy, Scr->SizeWindow); 179 InstallRootColormap(); 180 last_width = 0; 181 last_height = 0; 182 DisplaySize(tmp_win, origWidth, origHeight); 183 MoveOutline(Scr->Root, dragx - tmp_win->frame_bw, 184 dragy - tmp_win->frame_bw, dragWidth + 2 * tmp_win->frame_bw, 185 dragHeight + 2 * tmp_win->frame_bw, 186 tmp_win->frame_bw, tmp_win->title_height); 187} 188 189void 190MenuStartResize(TwmWindow *tmp_win, int x, int y, int w, int h) 191{ 192 XGrabServer(dpy); 193 XGrabPointer(dpy, Scr->Root, True, 194 ButtonPressMask | ButtonMotionMask | PointerMotionMask, 195 GrabModeAsync, GrabModeAsync, 196 Scr->Root, Scr->ResizeCursor, CurrentTime); 197 dragx = x + tmp_win->frame_bw; 198 dragy = y + tmp_win->frame_bw; 199 origx = dragx; 200 origy = dragy; 201 dragWidth = origWidth = w; /* - 2 * tmp_win->frame_bw; */ 202 dragHeight = origHeight = h; /* - 2 * tmp_win->frame_bw; */ 203 clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0; 204 last_width = 0; 205 last_height = 0; 206 Scr->SizeStringOffset = SIZE_HINDENT; 207 XResizeWindow(dpy, Scr->SizeWindow, 208 (unsigned) (Scr->SizeStringWidth + SIZE_HINDENT * 2), 209 (unsigned) (Scr->SizeFont.height + SIZE_VINDENT * 2)); 210 XMapRaised(dpy, Scr->SizeWindow); 211 DisplaySize(tmp_win, origWidth, origHeight); 212 MoveOutline(Scr->Root, dragx - tmp_win->frame_bw, 213 dragy - tmp_win->frame_bw, 214 dragWidth + 2 * tmp_win->frame_bw, 215 dragHeight + 2 * tmp_win->frame_bw, 216 tmp_win->frame_bw, tmp_win->title_height); 217} 218 219/** 220 * begin a windorew resize operation from AddWindow 221 * \param tmp_win the TwmWindow pointer 222 */ 223void 224AddStartResize(TwmWindow *tmp_win, int x, int y, int w, int h) 225{ 226 XGrabServer(dpy); 227 XGrabPointer(dpy, Scr->Root, True, 228 ButtonReleaseMask | ButtonMotionMask | PointerMotionHintMask, 229 GrabModeAsync, GrabModeAsync, 230 Scr->Root, Scr->ResizeCursor, CurrentTime); 231 232 dragx = x + tmp_win->frame_bw; 233 dragy = y + tmp_win->frame_bw; 234 origx = dragx; 235 origy = dragy; 236 dragWidth = origWidth = w - 2 * tmp_win->frame_bw; 237 dragHeight = origHeight = h - 2 * tmp_win->frame_bw; 238 clampTop = clampBottom = clampLeft = clampRight = clampDX = clampDY = 0; 239/***** 240 if (Scr->AutoRelativeResize) { 241 clampRight = clampBottom = 1; 242 } 243*****/ 244 last_width = 0; 245 last_height = 0; 246 DisplaySize(tmp_win, origWidth, origHeight); 247} 248 249void 250MenuDoResize(int x_root, int y_root, TwmWindow *tmp_win) 251{ 252 int action; 253 254 action = 0; 255 256 x_root -= clampDX; 257 y_root -= clampDY; 258 259 if (clampTop) { 260 int delta = y_root - dragy; 261 262 if (dragHeight - delta < MINHEIGHT) { 263 delta = dragHeight - MINHEIGHT; 264 clampTop = 0; 265 } 266 dragy += delta; 267 dragHeight -= delta; 268 action = 1; 269 } 270 else if (y_root <= dragy /* || 271 y_root == findRootInfo(root)->rooty */ ) { 272 dragy = y_root; 273 dragHeight = origy + origHeight - y_root; 274 clampBottom = 0; 275 clampTop = 1; 276 clampDY = 0; 277 action = 1; 278 } 279 if (clampLeft) { 280 int delta = x_root - dragx; 281 282 if (dragWidth - delta < MINWIDTH) { 283 delta = dragWidth - MINWIDTH; 284 clampLeft = 0; 285 } 286 dragx += delta; 287 dragWidth -= delta; 288 action = 1; 289 } 290 else if (x_root <= dragx /* || 291 x_root == findRootInfo(root)->rootx */ ) { 292 dragx = x_root; 293 dragWidth = origx + origWidth - x_root; 294 clampRight = 0; 295 clampLeft = 1; 296 clampDX = 0; 297 action = 1; 298 } 299 if (clampBottom) { 300 int delta = y_root - dragy - dragHeight; 301 302 if (dragHeight + delta < MINHEIGHT) { 303 delta = MINHEIGHT - dragHeight; 304 clampBottom = 0; 305 } 306 dragHeight += delta; 307 action = 1; 308 } 309 else if (y_root >= dragy + dragHeight) { 310 dragy = origy; 311 dragHeight = 1 + y_root - dragy; 312 clampTop = 0; 313 clampBottom = 1; 314 clampDY = 0; 315 action = 1; 316 } 317 if (clampRight) { 318 int delta = x_root - dragx - dragWidth; 319 320 if (dragWidth + delta < MINWIDTH) { 321 delta = MINWIDTH - dragWidth; 322 clampRight = 0; 323 } 324 dragWidth += delta; 325 action = 1; 326 } 327 else if (x_root >= dragx + dragWidth) { 328 dragx = origx; 329 dragWidth = 1 + x_root - origx; 330 clampLeft = 0; 331 clampRight = 1; 332 clampDX = 0; 333 action = 1; 334 } 335 336 if (action) { 337 ConstrainSize(tmp_win, &dragWidth, &dragHeight); 338 if (clampLeft) 339 dragx = origx + origWidth - dragWidth; 340 if (clampTop) 341 dragy = origy + origHeight - dragHeight; 342 MoveOutline(Scr->Root, 343 dragx - tmp_win->frame_bw, 344 dragy - tmp_win->frame_bw, 345 dragWidth + 2 * tmp_win->frame_bw, 346 dragHeight + 2 * tmp_win->frame_bw, 347 tmp_win->frame_bw, tmp_win->title_height); 348 } 349 350 DisplaySize(tmp_win, dragWidth, dragHeight); 351} 352 353/** 354 * move the rubberband around. This is called for each motion event when 355 * we are resizing 356 * 357 * \param x_root the X coordinate in the root window 358 * \param y_root the Y coordinate in the root window 359 * \param tmp_win the current twm window 360 */ 361void 362DoResize(int x_root, int y_root, TwmWindow *tmp_win) 363{ 364 int action; 365 366 action = 0; 367 368 x_root -= clampDX; 369 y_root -= clampDY; 370 371 if (clampTop) { 372 int delta = y_root - dragy; 373 374 if (dragHeight - delta < MINHEIGHT) { 375 delta = dragHeight - MINHEIGHT; 376 clampTop = 0; 377 } 378 dragy += delta; 379 dragHeight -= delta; 380 action = 1; 381 } 382 else if (y_root <= dragy /* || 383 y_root == findRootInfo(root)->rooty */ ) { 384 dragy = y_root; 385 dragHeight = origy + origHeight - y_root; 386 clampBottom = 0; 387 clampTop = 1; 388 clampDY = 0; 389 action = 1; 390 } 391 if (clampLeft) { 392 int delta = x_root - dragx; 393 394 if (dragWidth - delta < MINWIDTH) { 395 delta = dragWidth - MINWIDTH; 396 clampLeft = 0; 397 } 398 dragx += delta; 399 dragWidth -= delta; 400 action = 1; 401 } 402 else if (x_root <= dragx /* || 403 x_root == findRootInfo(root)->rootx */ ) { 404 dragx = x_root; 405 dragWidth = origx + origWidth - x_root; 406 clampRight = 0; 407 clampLeft = 1; 408 clampDX = 0; 409 action = 1; 410 } 411 if (clampBottom) { 412 int delta = y_root - dragy - dragHeight; 413 414 if (dragHeight + delta < MINHEIGHT) { 415 delta = MINHEIGHT - dragHeight; 416 clampBottom = 0; 417 } 418 dragHeight += delta; 419 action = 1; 420 } 421 else if (y_root >= dragy + dragHeight - 1 /* || 422 y_root == findRootInfo(root)->rooty 423 + findRootInfo(root)->rootheight - 1 */ ) { 424 dragy = origy; 425 dragHeight = 1 + y_root - dragy; 426 clampTop = 0; 427 clampBottom = 1; 428 clampDY = 0; 429 action = 1; 430 } 431 if (clampRight) { 432 int delta = x_root - dragx - dragWidth; 433 434 if (dragWidth + delta < MINWIDTH) { 435 delta = MINWIDTH - dragWidth; 436 clampRight = 0; 437 } 438 dragWidth += delta; 439 action = 1; 440 } 441 else if (x_root >= dragx + dragWidth - 1 /* || 442 x_root == findRootInfo(root)->rootx + 443 findRootInfo(root)->rootwidth - 1 */ ) { 444 dragx = origx; 445 dragWidth = 1 + x_root - origx; 446 clampLeft = 0; 447 clampRight = 1; 448 clampDX = 0; 449 action = 1; 450 } 451 452 if (action) { 453 ConstrainSize(tmp_win, &dragWidth, &dragHeight); 454 if (clampLeft) 455 dragx = origx + origWidth - dragWidth; 456 if (clampTop) 457 dragy = origy + origHeight - dragHeight; 458 MoveOutline(Scr->Root, 459 dragx - tmp_win->frame_bw, 460 dragy - tmp_win->frame_bw, 461 dragWidth + 2 * tmp_win->frame_bw, 462 dragHeight + 2 * tmp_win->frame_bw, 463 tmp_win->frame_bw, tmp_win->title_height); 464 } 465 466 DisplaySize(tmp_win, dragWidth, dragHeight); 467} 468 469/** 470 * display the size in the dimensions window. 471 * 472 * \param tmp_win the current twm window 473 * \param width the width of the rubber band 474 * \param height the height of the rubber band 475 */ 476static void 477DisplaySize(TwmWindow *tmp_win, int width, int height) 478{ 479 char str[100]; 480 int dwidth; 481 int dheight; 482 483 if (last_width == width && last_height == height) 484 return; 485 486 last_width = width; 487 last_height = height; 488 489 dheight = height - tmp_win->title_height; 490 dwidth = width; 491 492 /* 493 * ICCCM says that PMinSize is the default is no PBaseSize is given, 494 * and vice-versa. 495 */ 496 if (tmp_win->hints.flags & (PMinSize | PBaseSize) && 497 tmp_win->hints.flags & PResizeInc) { 498 if (tmp_win->hints.flags & PBaseSize) { 499 dwidth -= tmp_win->hints.base_width; 500 dheight -= tmp_win->hints.base_height; 501 } 502 else { 503 dwidth -= tmp_win->hints.min_width; 504 dheight -= tmp_win->hints.min_height; 505 } 506 } 507 508 if (tmp_win->hints.flags & PResizeInc) { 509 dwidth /= tmp_win->hints.width_inc; 510 dheight /= tmp_win->hints.height_inc; 511 } 512 513 (void) snprintf(str, sizeof(str), " %4d x %-4d ", dwidth, dheight); 514 XRaiseWindow(dpy, Scr->SizeWindow); 515 MyFont_ChangeGC(Scr->DefaultC.fore, Scr->DefaultC.back, &Scr->SizeFont); 516 MyFont_DrawImageString(dpy, Scr->SizeWindow, &Scr->SizeFont, 517 Scr->NormalGC, Scr->SizeStringOffset, 518 Scr->SizeFont.ascent + SIZE_VINDENT, str, 13); 519} 520 521/** 522 * finish the resize operation 523 */ 524void 525EndResize(void) 526{ 527 TwmWindow *tmp_win; 528 529#ifdef DEBUG 530 fprintf(stderr, "EndResize\n"); 531#endif 532 533 MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0); 534 XUnmapWindow(dpy, Scr->SizeWindow); 535 536 XFindContext(dpy, ResizeWindow, TwmContext, (XPointer *) &tmp_win); 537 538 ConstrainSize(tmp_win, &dragWidth, &dragHeight); 539 540 if (dragWidth != tmp_win->frame_width || 541 dragHeight != tmp_win->frame_height) 542 tmp_win->zoomed = ZOOM_NONE; 543 544 SetupWindow(tmp_win, dragx - tmp_win->frame_bw, dragy - tmp_win->frame_bw, 545 dragWidth, dragHeight, -1); 546 547 if (tmp_win->iconmgr) { 548 int ncols = tmp_win->iconmgrp->cur_columns; 549 550 if (ncols == 0) 551 ncols = 1; 552 553 tmp_win->iconmgrp->width = (int) ((dragWidth * 554 (long) tmp_win->iconmgrp->columns) 555 / ncols); 556 PackIconManager(tmp_win->iconmgrp); 557 } 558 559 if (!Scr->NoRaiseResize) 560 XRaiseWindow(dpy, tmp_win->frame); 561 562 UninstallRootColormap(); 563 564 ResizeWindow = None; 565} 566 567void 568MenuEndResize(TwmWindow *tmp_win) 569{ 570 MoveOutline(Scr->Root, 0, 0, 0, 0, 0, 0); 571 XUnmapWindow(dpy, Scr->SizeWindow); 572 ConstrainSize(tmp_win, &dragWidth, &dragHeight); 573 AddingX = dragx - tmp_win->frame_bw; 574 AddingY = dragy - tmp_win->frame_bw; 575 AddingW = dragWidth; /* + (2 * tmp_win->frame_bw); */ 576 AddingH = dragHeight; /* + (2 * tmp_win->frame_bw); */ 577 SetupWindow(tmp_win, AddingX, AddingY, AddingW, AddingH, -1); 578} 579 580/** 581 * finish the resize operation for AddWindo<w 582 */ 583void 584AddEndResize(TwmWindow *tmp_win) 585{ 586 587#ifdef DEBUG 588 fprintf(stderr, "AddEndResize\n"); 589#endif 590 591 ConstrainSize(tmp_win, &dragWidth, &dragHeight); 592 AddingX = dragx - tmp_win->frame_bw; 593 AddingY = dragy - tmp_win->frame_bw; 594 AddingW = dragWidth + (2 * tmp_win->frame_bw); 595 AddingH = dragHeight + (2 * tmp_win->frame_bw); 596} 597 598/** 599 * adjust the given width and height to account for the constraints imposed 600 * by size hints. 601 * 602 * The general algorithm, especially the aspect ratio stuff, is 603 * borrowed from uwm's CheckConsistency routine. 604 */ 605void 606ConstrainSize(TwmWindow *tmp_win, int *widthp, int *heightp) 607{ 608#define makemult(a,b) ((b==1) ? (a) : (((int)((a)/(b))) * (b)) ) 609#define _min(a,b) (((a) < (b)) ? (a) : (b)) 610 611 int minWidth, minHeight, maxWidth, maxHeight, xinc, yinc; 612 int baseWidth, baseHeight; 613 int dwidth = *widthp, dheight = *heightp; 614 615 dheight -= tmp_win->title_height; 616 617 if (tmp_win->hints.flags & PMinSize) { 618 minWidth = tmp_win->hints.min_width; 619 minHeight = tmp_win->hints.min_height; 620 } 621 else if (tmp_win->hints.flags & PBaseSize) { 622 minWidth = tmp_win->hints.base_width; 623 minHeight = tmp_win->hints.base_height; 624 } 625 else 626 minWidth = minHeight = 1; 627 628 if (tmp_win->hints.flags & PBaseSize) { 629 baseWidth = tmp_win->hints.base_width; 630 baseHeight = tmp_win->hints.base_height; 631 } 632 else if (tmp_win->hints.flags & PMinSize) { 633 baseWidth = tmp_win->hints.min_width; 634 baseHeight = tmp_win->hints.min_height; 635 } 636 else 637 baseWidth = baseHeight = 0; 638 639 if (tmp_win->hints.flags & PMaxSize) { 640 maxWidth = _min(Scr->MaxWindowWidth, tmp_win->hints.max_width); 641 maxHeight = _min(Scr->MaxWindowHeight, tmp_win->hints.max_height); 642 } 643 else { 644 maxWidth = Scr->MaxWindowWidth; 645 maxHeight = Scr->MaxWindowHeight; 646 } 647 648 if (tmp_win->hints.flags & PResizeInc) { 649 xinc = tmp_win->hints.width_inc; 650 yinc = tmp_win->hints.height_inc; 651 } 652 else 653 xinc = yinc = 1; 654 655 /* 656 * First, clamp to min and max values 657 */ 658 if (dwidth < minWidth) 659 dwidth = minWidth; 660 if (dheight < minHeight) 661 dheight = minHeight; 662 663 if (dwidth > maxWidth) 664 dwidth = maxWidth; 665 if (dheight > maxHeight) 666 dheight = maxHeight; 667 668 /* 669 * Second, fit to base + N * inc 670 */ 671 dwidth = ((dwidth - baseWidth) / xinc * xinc) + baseWidth; 672 dheight = ((dheight - baseHeight) / yinc * yinc) + baseHeight; 673 674 /* 675 * Third, adjust for aspect ratio 676 */ 677#define maxAspectX tmp_win->hints.max_aspect.x 678#define maxAspectY tmp_win->hints.max_aspect.y 679#define minAspectX tmp_win->hints.min_aspect.x 680#define minAspectY tmp_win->hints.min_aspect.y 681 /* 682 * The math looks like this: 683 * 684 * minAspectX dwidth maxAspectX 685 * ---------- <= ------- <= ---------- 686 * minAspectY dheight maxAspectY 687 * 688 * If that is multiplied out, then the width and height are 689 * invalid in the following situations: 690 * 691 * minAspectX * dheight > minAspectY * dwidth 692 * maxAspectX * dheight < maxAspectY * dwidth 693 * 694 */ 695 696 if (tmp_win->hints.flags & PAspect) { 697 int delta; 698 699 if (minAspectX * dheight > minAspectY * dwidth) { 700 delta = makemult(minAspectX * dheight / minAspectY - dwidth, xinc); 701 if (dwidth + delta <= maxWidth) 702 dwidth += delta; 703 else { 704 delta = makemult(dheight - dwidth * minAspectY / minAspectX, 705 yinc); 706 if (dheight - delta >= minHeight) 707 dheight -= delta; 708 } 709 } 710 711 if (maxAspectX * dheight < maxAspectY * dwidth) { 712 delta = makemult(dwidth * maxAspectY / maxAspectX - dheight, yinc); 713 if (dheight + delta <= maxHeight) 714 dheight += delta; 715 else { 716 delta = makemult(dwidth - maxAspectX * dheight / maxAspectY, 717 xinc); 718 if (dwidth - delta >= minWidth) 719 dwidth -= delta; 720 } 721 } 722 } 723 724 /* 725 * Fourth, account for border width and title height 726 */ 727 *widthp = dwidth; 728 *heightp = dheight + tmp_win->title_height; 729} 730 731/** 732 * set window sizes, this was called from either AddWindow, EndResize, or 733 * HandleConfigureNotify. 734 * 735 * Special Considerations: 736 * This routine will check to make sure the window is not completely off the 737 * display, if it is, it'll bring some of it back on. 738 * 739 * The tmp_win->frame_XXX variables should NOT be updated with the values of 740 * x,y,w,h prior to calling this routine, since the new values are compared 741 * against the old to see whether a synthetic ConfigureNotify event should be 742 * sent. (It should be sent if the window was moved but not resized.) 743 * 744 * \param tmp_win the TwmWindow pointer 745 * \param x the x coordinate of the upper-left outer corner of the frame 746 * \param y the y coordinate of the upper-left outer corner of the frame 747 * \param w the width of the frame window w/o border 748 * \param h the height of the frame window w/o border 749 * \param bw the border width of the frame window or -1 not to change 750 */ 751void 752SetupWindow(TwmWindow *tmp_win, int x, int y, int w, int h, int bw) 753{ 754 SetupFrame(tmp_win, x, y, w, h, bw, False); 755} 756 757/** 758 * \param sendEvent whether or not to force a send 759 */ 760void 761SetupFrame(TwmWindow *tmp_win, int x, int y, int w, int h, int bw, 762 Bool sendEvent) 763{ 764 XEvent client_event; 765 XWindowChanges frame_wc, xwc; 766 unsigned long frame_mask, xwcm; 767 int title_width, title_height; 768 int reShape; 769 770#ifdef DEBUG 771 fprintf(stderr, "SetupWindow: x=%d, y=%d, w=%d, h=%d, bw=%d\n", 772 x, y, w, h, bw); 773#endif 774 775 if (x >= Scr->MyDisplayWidth) 776 x = Scr->MyDisplayWidth - 16; /* one "average" cursor width */ 777 if (y >= Scr->MyDisplayHeight) 778 y = Scr->MyDisplayHeight - 16; /* one "average" cursor width */ 779 if (bw < 0) 780 bw = tmp_win->frame_bw; /* -1 means current frame width */ 781 782 if (tmp_win->iconmgr) { 783 tmp_win->iconmgrp->width = w; 784 h = tmp_win->iconmgrp->height + tmp_win->title_height; 785 } 786 787 /* 788 * According to the July 27, 1988 ICCCM draft, we should send a 789 * "synthetic" ConfigureNotify event to the client if the window 790 * was moved but not resized. 791 */ 792 if (((x != tmp_win->frame_x || y != tmp_win->frame_y) && 793 (w == tmp_win->frame_width && h == tmp_win->frame_height)) || 794 (bw != tmp_win->frame_bw)) 795 sendEvent = TRUE; 796 797 xwcm = CWWidth; 798 title_width = xwc.width = w; 799 title_height = Scr->TitleHeight + bw; 800 801 ComputeWindowTitleOffsets(tmp_win, xwc.width, True); 802 803 reShape = (tmp_win->wShaped ? TRUE : FALSE); 804 if (tmp_win->squeeze_info) { /* check for title shaping */ 805 title_width = tmp_win->rightx + Scr->TBInfo.rightoff; 806 if (title_width < xwc.width) { 807 xwc.width = title_width; 808 if (tmp_win->frame_height != h || 809 tmp_win->frame_width != w || 810 tmp_win->frame_bw != bw || title_width != tmp_win->title_width) 811 reShape = TRUE; 812 } 813 else { 814 if (!tmp_win->wShaped) 815 reShape = TRUE; 816 title_width = xwc.width; 817 } 818 } 819 820 tmp_win->title_width = title_width; 821 if (tmp_win->title_height) 822 tmp_win->title_height = title_height; 823 824 if (tmp_win->title_w) { 825 if (bw != tmp_win->frame_bw) { 826 xwc.border_width = bw; 827 tmp_win->title_x = xwc.x = -bw; 828 tmp_win->title_y = xwc.y = -bw; 829 xwcm |= (CWX | CWY | CWBorderWidth); 830 } 831 832 XConfigureWindow(dpy, tmp_win->title_w, (unsigned) xwcm, &xwc); 833 } 834 835 if (tmp_win->attr.width != w) 836 tmp_win->widthEverChangedByUser = True; 837 838 if (tmp_win->attr.height != (h - tmp_win->title_height)) 839 tmp_win->heightEverChangedByUser = True; 840 841 tmp_win->attr.width = w; 842 tmp_win->attr.height = h - tmp_win->title_height; 843 844 XMoveResizeWindow(dpy, tmp_win->w, 0, tmp_win->title_height, 845 (unsigned) w, (unsigned) (h - tmp_win->title_height)); 846 847 /* 848 * fix up frame and assign size/location values in tmp_win 849 */ 850 frame_mask = 0; 851 if (bw != tmp_win->frame_bw) { 852 frame_wc.border_width = tmp_win->frame_bw = bw; 853 frame_mask |= CWBorderWidth; 854 } 855 frame_wc.x = tmp_win->frame_x = x; 856 frame_wc.y = tmp_win->frame_y = y; 857 frame_wc.width = tmp_win->frame_width = w; 858 frame_wc.height = tmp_win->frame_height = h; 859 frame_mask |= (CWX | CWY | CWWidth | CWHeight); 860 XConfigureWindow(dpy, tmp_win->frame, (unsigned) frame_mask, &frame_wc); 861 862 /* 863 * fix up highlight window 864 */ 865 if (tmp_win->title_height && tmp_win->hilite_w) { 866 xwc.width = (tmp_win->rightx - tmp_win->highlightx); 867 if (Scr->TBInfo.nright > 0) 868 xwc.width -= Scr->TitlePadding; 869 if (xwc.width <= 0) { 870 xwc.x = Scr->MyDisplayWidth; /* move offscreen */ 871 xwc.width = 1; 872 } 873 else { 874 xwc.x = tmp_win->highlightx; 875 } 876 877 xwcm = CWX | CWWidth; 878 XConfigureWindow(dpy, tmp_win->hilite_w, (unsigned) xwcm, &xwc); 879 } 880 881 if (HasShape && reShape) { 882 SetFrameShape(tmp_win); 883 } 884 885 if (sendEvent) { 886 client_event.type = ConfigureNotify; 887 client_event.xconfigure.display = dpy; 888 889 client_event.xconfigure.event = tmp_win->w; 890 client_event.xconfigure.window = tmp_win->w; 891 client_event.xconfigure.x = (x + tmp_win->frame_bw - tmp_win->old_bw); 892 client_event.xconfigure.y = (y + tmp_win->frame_bw + 893 tmp_win->title_height - tmp_win->old_bw); 894 client_event.xconfigure.width = tmp_win->frame_width; 895 client_event.xconfigure.height = tmp_win->frame_height - 896 tmp_win->title_height; 897 client_event.xconfigure.border_width = tmp_win->old_bw; 898 /* Real ConfigureNotify events say we're above title window, so ... */ 899 /* what if we don't have a title ????? */ 900 client_event.xconfigure.above = tmp_win->frame; 901 client_event.xconfigure.override_redirect = False; 902 XSendEvent(dpy, tmp_win->w, False, StructureNotifyMask, &client_event); 903 } 904} 905 906/** 907 * zooms window to full height of screen or to full height and width of screen. 908 * (Toggles so that it can undo the zoom - even when switching between fullzoom 909 * and vertical zoom.) 910 * 911 * \param tmp_win the TwmWindow pointer 912 */ 913void 914fullzoom(TwmWindow *tmp_win, int flag) 915{ 916 Window junkRoot; 917 unsigned int junkbw, junkDepth; 918 int basex, basey; 919 920 XGetGeometry(dpy, (Drawable) tmp_win->frame, &junkRoot, 921 &dragx, &dragy, (unsigned int *) &dragWidth, 922 (unsigned int *) &dragHeight, &junkbw, &junkDepth); 923 924 basex = 0; 925 basey = 0; 926 927 if (tmp_win->zoomed == flag) { 928 dragHeight = tmp_win->save_frame_height; 929 dragWidth = tmp_win->save_frame_width; 930 dragx = tmp_win->save_frame_x; 931 dragy = tmp_win->save_frame_y; 932 tmp_win->zoomed = ZOOM_NONE; 933 } 934 else { 935 int frame_bw_times_2; 936 937 if (tmp_win->zoomed == ZOOM_NONE) { 938 tmp_win->save_frame_x = dragx; 939 tmp_win->save_frame_y = dragy; 940 tmp_win->save_frame_width = dragWidth; 941 tmp_win->save_frame_height = dragHeight; 942 tmp_win->zoomed = (short) flag; 943 } 944 else 945 tmp_win->zoomed = (short) flag; 946 947 frame_bw_times_2 = 2 * tmp_win->frame_bw; 948 949 switch (flag) { 950 case ZOOM_NONE: 951 break; 952 case F_ZOOM: 953 dragHeight = Scr->MyDisplayHeight - frame_bw_times_2; 954 dragy = basey; 955 break; 956 case F_HORIZOOM: 957 dragx = basex; 958 dragWidth = Scr->MyDisplayWidth - frame_bw_times_2; 959 break; 960 case F_FULLZOOM: 961 dragx = basex; 962 dragy = basey; 963 dragHeight = Scr->MyDisplayHeight - frame_bw_times_2; 964 dragWidth = Scr->MyDisplayWidth - frame_bw_times_2; 965 break; 966 case F_LEFTZOOM: 967 dragx = basex; 968 dragy = basey; 969 dragHeight = Scr->MyDisplayHeight - frame_bw_times_2; 970 dragWidth = Scr->MyDisplayWidth / 2 - frame_bw_times_2; 971 break; 972 case F_RIGHTZOOM: 973 dragx = basex + Scr->MyDisplayWidth / 2; 974 dragy = basey; 975 dragHeight = Scr->MyDisplayHeight - frame_bw_times_2; 976 dragWidth = Scr->MyDisplayWidth / 2 - frame_bw_times_2; 977 break; 978 case F_TOPZOOM: 979 dragx = basex; 980 dragy = basey; 981 dragHeight = Scr->MyDisplayHeight / 2 - frame_bw_times_2; 982 dragWidth = Scr->MyDisplayWidth - frame_bw_times_2; 983 break; 984 case F_BOTTOMZOOM: 985 dragx = basex; 986 dragy = basey + Scr->MyDisplayHeight / 2; 987 dragHeight = Scr->MyDisplayHeight / 2 - frame_bw_times_2; 988 dragWidth = Scr->MyDisplayWidth - frame_bw_times_2; 989 break; 990 } 991 } 992 993 if (!Scr->NoRaiseResize) 994 XRaiseWindow(dpy, tmp_win->frame); 995 996 ConstrainSize(tmp_win, &dragWidth, &dragHeight); 997 998 SetupWindow(tmp_win, dragx, dragy, dragWidth, dragHeight, -1); 999 XUngrabPointer(dpy, CurrentTime); 1000 XUngrabServer(dpy); 1001} 1002 1003void 1004SetFrameShape(TwmWindow *tmp) 1005{ 1006 /* 1007 * see if the titlebar needs to move 1008 */ 1009 if (tmp->title_w) { 1010 int oldx = tmp->title_x, oldy = tmp->title_y; 1011 1012 ComputeTitleLocation(tmp); 1013 if (oldx != tmp->title_x || oldy != tmp->title_y) 1014 XMoveWindow(dpy, tmp->title_w, tmp->title_x, tmp->title_y); 1015 } 1016 1017 /* 1018 * The frame consists of the shape of the contents window offset by 1019 * title_height or'ed with the shape of title_w (which is always 1020 * rectangular). 1021 */ 1022 if (tmp->wShaped) { 1023 /* 1024 * need to do general case 1025 */ 1026 XShapeCombineShape(dpy, tmp->frame, ShapeBounding, 1027 0, tmp->title_height, tmp->w, 1028 ShapeBounding, ShapeSet); 1029 if (tmp->title_w) { 1030 XShapeCombineShape(dpy, tmp->frame, ShapeBounding, 1031 tmp->title_x + tmp->frame_bw, 1032 tmp->title_y + tmp->frame_bw, 1033 tmp->title_w, ShapeBounding, ShapeUnion); 1034 } 1035 } 1036 else { 1037 /* 1038 * can optimize rectangular contents window 1039 */ 1040 if (tmp->squeeze_info) { 1041 XRectangle newBounding[2]; 1042 XRectangle newClip[2]; 1043 int fbw2 = 2 * tmp->frame_bw; 1044 1045 /* 1046 * Build the border clipping rectangles; one around title, one 1047 * around window. The title_[xy] field already have had frame_bw 1048 * subtracted off them so that they line up properly in the frame. 1049 * 1050 * The frame_width and frame_height do *not* include borders. 1051 */ 1052 /* border */ 1053 newBounding[0].x = (short) tmp->title_x; 1054 newBounding[0].y = (short) tmp->title_y; 1055 newBounding[0].width = (unsigned short) (tmp->title_width + fbw2); 1056 newBounding[0].height = (unsigned short) tmp->title_height; 1057 newBounding[1].x = (short) -tmp->frame_bw; 1058 newBounding[1].y = (short) Scr->TitleHeight; 1059 newBounding[1].width = (unsigned short) (tmp->attr.width + fbw2); 1060 newBounding[1].height = (unsigned short) (tmp->attr.height + fbw2); 1061 XShapeCombineRectangles(dpy, tmp->frame, ShapeBounding, 0, 0, 1062 newBounding, 2, ShapeSet, YXBanded); 1063 /* insides */ 1064 newClip[0].x = (short) (tmp->title_x + tmp->frame_bw); 1065 newClip[0].y = 0; 1066 newClip[0].width = (unsigned short) tmp->title_width; 1067 newClip[0].height = (unsigned short) Scr->TitleHeight; 1068 newClip[1].x = 0; 1069 newClip[1].y = (short) tmp->title_height; 1070 newClip[1].width = (unsigned short) tmp->attr.width; 1071 newClip[1].height = (unsigned short) tmp->attr.height; 1072 XShapeCombineRectangles(dpy, tmp->frame, ShapeClip, 0, 0, 1073 newClip, 2, ShapeSet, YXBanded); 1074 } 1075 else { 1076 (void) XShapeCombineMask(dpy, tmp->frame, ShapeBounding, 0, 0, 1077 None, ShapeSet); 1078 (void) XShapeCombineMask(dpy, tmp->frame, ShapeClip, 0, 0, 1079 None, ShapeSet); 1080 } 1081 } 1082} 1083 1084/* 1085 * Squeezed Title: 1086 * 1087 * tmp->title_x 1088 * 0 | 1089 * tmp->title_y ........+--------------+......... -+,- tmp->frame_bw 1090 * 0 : ......| +----------+ |....... : -++ 1091 * : : | | | | : : ||-Scr->TitleHeight 1092 * : : | | | | : : || 1093 * +-------+ +----------+ +--------+ -+|-tmp->title_height 1094 * | +---------------------------+ | --+ 1095 * | | | | 1096 * | | | | 1097 * | | | | 1098 * | | | | 1099 * | | | | 1100 * | +---------------------------+ | 1101 * +-------------------------------+ 1102 * 1103 * 1104 * Unsqueezed Title: 1105 * 1106 * tmp->title_x 1107 * | 0 1108 * tmp->title_y +-------------------------------+ -+,tmp->frame_bw 1109 * 0 | +---------------------------+ | -+' 1110 * | | | | |-Scr->TitleHeight 1111 * | | | | | 1112 * + +---------------------------+ + -+ 1113 * |-+---------------------------+-| 1114 * | | | | 1115 * | | | | 1116 * | | | | 1117 * | | | | 1118 * | | | | 1119 * | +---------------------------+ | 1120 * +-------------------------------+ 1121 * 1122 * 1123 * 1124 * Dimensions and Positions: 1125 * 1126 * frame origin (0, 0) 1127 * frame upper left border (-tmp->frame_bw, -tmp->frame_bw) 1128 * frame size w/o border tmp->frame_width , tmp->frame_height 1129 * frame/title border width tmp->frame_bw 1130 * extra title height w/o bdr tmp->title_height = TitleHeight + frame_bw 1131 * title window height Scr->TitleHeight 1132 * title origin w/o border (tmp->title_x, tmp->title_y) 1133 * client origin (0, Scr->TitleHeight + tmp->frame_bw) 1134 * client size tmp->attr.width , tmp->attr.height 1135 * 1136 * When shaping, need to remember that the width and height of rectangles 1137 * are really deltax and deltay to lower right handle corner, so they need 1138 * to have -1 subtracted from would normally be the actual extents. 1139 */ 1140