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