CTWM
Loading...
Searching...
No Matches
/usr/src/RPM/BUILD/ctwm-4.1.0/functions_win_moveresize.c
Go to the documentation of this file.
1/*
2 * Functions related to moving/resizing windows.
3 */
4
5#include "ctwm.h"
6
7#include <stdio.h>
8#include <stdlib.h>
9
10#include "colormaps.h"
11#include "events.h"
12#include "event_handlers.h"
13#include "functions.h"
14#include "functions_defs.h"
15#include "functions_internal.h"
16#include "icons.h"
17#include "otp.h"
18#include "parse.h"
19#include "r_area.h"
20#include "r_layout.h"
21#include "screen.h"
22#include "util.h"
23#include "vscreen.h"
24#include "win_decorations.h"
25#include "win_ops.h"
26#include "win_resize.h"
27#include "win_utils.h"
28#include "workspace_manager.h"
29#include "xparsegeometry.h"
30
31
32/*
33 * MoveFillDir-ectional specifiers, used in jump/pack/fill
34 */
42
43/* Internal util */
45
46
47/*
48 * Constrained move variables
49 *
50 * Used in the resize handling, but needed over in event code for
51 * ButtonRelease as well.
52 */
53bool ConstMove = false;
61
62/*
63 * Which move-ish function is in progress. This is _almost_ really a
64 * local var in the movewindow() function, but we also reference it in
65 * the HandleButtonRelease() event handler because that has to know
66 * which move variant we're doing to figure out whether it has to
67 * constrain the final coordinates in various ways.
68 */
70
71/*
72 * Globals used to keep track of whether the mouse has moved during a
73 * resize function.
74 */
77
78
79
80/*
81 * Now, on to the actual handlers.
82 */
83
84
85/*
86 *********************************************************
87 *
88 * First, the various methods of moving windows around.
89 *
90 *********************************************************
91 */
92
93/*
94 * Simple f.move and related
95 */
96static void movewindow(EF_FULLPROTO);
113
114/* f.move and friends backend */
115static void
117{
118 int origX, origY;
119 bool moving_icon;
120 bool fromtitlebar;
121 const Window dragroot = Scr->XineramaRoot;
122 const Window rootw = eventp->xbutton.root;
123
124 /* Better not be a menu open */
125 PopDownMenu();
126
127 /* Stash up just which f.move* variant we are */
128 MoveFunction = func;
129
130 /*
131 * Figure whether we're moving opaquely.
132 */
133 if(tmp_win->OpaqueMove) {
134 if(Scr->OpaqueMoveThreshold >= 200) {
135 Scr->OpaqueMove = true;
136 }
137 else {
138 const unsigned long sw = tmp_win->frame_width
139 * tmp_win->frame_height;
140 const unsigned long ss = Scr->rootw * Scr->rooth;
141 const float sf = Scr->OpaqueMoveThreshold / 100.0;
142
143 if(sw > (ss * sf)) {
144 Scr->OpaqueMove = false;
145 }
146 else {
147 Scr->OpaqueMove = true;
148 }
149 }
150 }
151 else {
152 Scr->OpaqueMove = false;
153 }
154
155#ifdef WINBOX
156 /* If it's in a WindowBox, adjust coordinates as necessary */
157 if(tmp_win->winbox) {
158 XTranslateCoordinates(dpy, dragroot, tmp_win->winbox->window,
159 eventp->xbutton.x_root, eventp->xbutton.y_root,
160 &(eventp->xbutton.x_root), &(eventp->xbutton.y_root), &JunkChild);
161 }
162#endif
163
164 /*
165 * XXX pulldown=true only when we're triggering from a ButtonRelease
166 * in a menu, and this warp should only be going somewhere if we hit
167 * the winbox case above and had to translate the coordinates? But,
168 * in that case, the coordinates would be changed to be relative to
169 * the winbox window, and here we're positioning relative to Root?
170 */
171 if(pulldown)
172 XWarpPointer(dpy, None, Scr->Root,
173 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
174
175 /*
176 * Stub out handlers for enter/leave notifications while we do stuff.
177 * They get reset toward the end of the ButtonRelease handler.
178 */
181
182 if(!Scr->NoGrabServer || !Scr->OpaqueMove) {
184 }
185
186 /*
187 * Setup size for the window showing current location as we move it.
188 * The same window is used for resize ops too, where it might be a
189 * different size.
190 */
191 Scr->SizeStringOffset = SIZE_HINDENT;
192 MoveResizeSizeWindow(eventp->xbutton.x_root, eventp->xbutton.y_root,
193 Scr->SizeStringWidth + SIZE_HINDENT * 2,
194 Scr->SizeFont.height + SIZE_VINDENT * 2);
195 XMapRaised(dpy, Scr->SizeWindow);
196
197 /*
198 * Use XGrabPointer() to configure how we get events locations
199 * reported relative to what root.
200 */
201 {
202#ifdef WINBOX
203 const Window grabwin = (tmp_win->winbox ? tmp_win->winbox->window
204 : Scr->XineramaRoot);
205#else
206 const Window grabwin = Scr->XineramaRoot;
207#endif
208
212 GrabModeAsync, GrabModeAsync, grabwin, Scr->MoveCursor,
214 }
215
216 /*
217 * Set w to what we're actually moving. If it's an icon, we always
218 * move it opaquely anyway. If it's a window (that's not iconofied),
219 * we move the frame.
220 */
221 moving_icon = false;
222 if(context == C_ICON && tmp_win->icon && tmp_win->icon->w) {
223 w = tmp_win->icon->w;
224 DragX = eventp->xbutton.x;
225 DragY = eventp->xbutton.y;
226 moving_icon = true;
227 if(tmp_win->OpaqueMove) {
228 Scr->OpaqueMove = true;
229 }
230 }
231 else if(! tmp_win->icon || w != tmp_win->icon->w) {
233 eventp->xbutton.x,
234 eventp->xbutton.y,
235 &DragX, &DragY, &JunkChild);
236
237 w = tmp_win->frame;
238 }
239
241
242 /* Get x/y relative to parent window, i.e. the virtual screen, Root.
243 * XMoveWindow() moves are relative to this.
244 * MoveOutline()s however are drawn from the XineramaRoot since they
245 * may cross virtual screens.
246 */
249 &JunkDepth);
250
251 origX = eventp->xbutton.x_root;
252 origY = eventp->xbutton.y_root;
255
256 /*
257 * Setup ConstrainedMove if this is a double-click. That means
258 * setting the flags, and moving the pointer off to the middle of the
259 * window.
260 *
261 * Only do the constrained move if timer is set; need to check it
262 * in case of stupid or wicked fast servers
263 */
265 (eventp->xbutton.time - last_time) < ConstrainedMoveTime) {
266 int width, height;
267
268 ConstMove = true;
270 ConstMoveX = eventp->xbutton.x_root - DragX - DragBW;
271 ConstMoveY = eventp->xbutton.y_root - DragY - DragBW;
272 width = DragWidth + 2 * DragBW;
273 height = DragHeight + 2 * DragBW;
274 ConstMoveXL = ConstMoveX + width / 3;
275 ConstMoveXR = ConstMoveX + 2 * (width / 3);
276 ConstMoveYT = ConstMoveY + height / 3;
277 ConstMoveYB = ConstMoveY + 2 * (height / 3);
278
280 0, 0, 0, 0, DragWidth / 2, DragHeight / 2);
281
283 &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
284 }
285 last_time = eventp->xbutton.time;
286
287 /* If not moving opaquely, setup the outline bits */
288 if(!Scr->OpaqueMove) {
290 if(!Scr->MoveDelta) {
291 /*
292 * Draw initial outline. This was previously done the
293 * first time though the outer loop by dropping out of
294 * the XCheckMaskEvent inner loop down to one of the
295 * MoveOutline's below.
296 */
298 origDragX - DragBW + Scr->currentvs->x,
299 origDragY - DragBW + Scr->currentvs->y,
300 DragWidth + 2 * DragBW, DragHeight + 2 * DragBW,
301 tmp_win->frame_bw,
302 moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
303 /*
304 * This next line causes HandleReleaseNotify to call
305 * XRaiseWindow(). This is solely to preserve the
306 * previous behaviour that raises a window being moved
307 * on button release even if you never actually moved
308 * any distance (unless you move less than MoveDelta or
309 * NoRaiseMove is set or OpaqueMove is set).
310 */
311 DragWindow = w;
312 }
313 }
314
315 /*
316 * Init whether triggered from something on the titlebar (e.g., a
317 * TitleButton bound to f.move). We need to keep this var in a scope
318 * outside the event loop below because the resetting of it in there
319 * is supposed to have effect on future loops.
320 */
322
324 /* warp the pointer to the middle of the window */
325 XWarpPointer(dpy, None, Scr->Root, 0, 0, 0, 0,
326 origDragX + DragWidth / 2,
327 origDragY + DragHeight / 2);
328 XFlush(dpy);
329 }
330
331 /* Fill in the position window with where we're starting */
333
334 /*
335 * Internal event loop for doing the moving.
336 */
337 while(1) {
342
343 /* block until there is an interesting event */
348
349 /* throw away enter and leave events until release */
350 if(Event.xany.type == EnterNotify ||
351 Event.xany.type == LeaveNotify) {
352 continue;
353 }
354
355 /* discard any extra motion events before a logical release */
356 if(Event.type == MotionNotify) {
358 if(Event.type == releaseEvent) {
359 break;
360 }
361 }
362
363 /* test to see if we have a second button press to abort move */
365 if(Event.type == ButtonPress && DragWindow != None) {
366 Cursor cur;
367 if(Scr->OpaqueMove) {
369 if(moving_icon) {
370 tmp_win->icon->w_x = origDragX;
371 tmp_win->icon->w_y = origDragY;
372 }
373 }
374 else {
375 MoveOutline(dragroot, 0, 0, 0, 0, 0, 0);
376 }
378
379 XUnmapWindow(dpy, Scr->SizeWindow);
380 cur = LeftButt;
381 if(Event.xbutton.button == Button2) {
382 cur = MiddleButt;
383 }
384 else if(Event.xbutton.button >= Button3) {
385 cur = RightButt;
386 }
387
388 XGrabPointer(dpy, Scr->Root, True,
391 Scr->Root, cur, CurrentTime);
392 func_reset_cursor = false; // Leave cursor alone
393 return;
394 }
395 }
396
397 if(fromtitlebar && Event.type == ButtonPress) {
398 fromtitlebar = false;
399 CurrentDragX = origX = Event.xbutton.x_root;
400 CurrentDragY = origY = Event.xbutton.y_root;
401 XTranslateCoordinates(dpy, rootw, tmp_win->frame,
402 origX, origY,
403 &DragX, &DragY, &JunkChild);
404 continue;
405 }
406
407 if(!DispatchEvent2()) {
408 continue;
409 }
410
411 if(Cancel) {
412 WindowMoved = false;
413 if(!Scr->OpaqueMove) {
415 }
416 func_reset_cursor = false; // Leave cursor alone
417 return;
418 }
419 if(Event.type == releaseEvent) {
420 MoveOutline(dragroot, 0, 0, 0, 0, 0, 0);
421 if(moving_icon &&
422 ((CurrentDragX != origDragX ||
423 CurrentDragY != origDragY))) {
424 tmp_win->icon_moved = true;
425 }
426 if(!Scr->OpaqueMove && menuFromFrameOrWindowOrTitlebar) {
427 int xl = Event.xbutton.x_root - (DragWidth / 2),
428 yt = Event.xbutton.y_root - (DragHeight / 2);
429 if(!moving_icon &&
431 TryToPack(tmp_win, &xl, &yt);
432 }
434 }
437 }
438 break;
439 }
440
441 /* something left to do only if the pointer moved */
442 if(Event.type != MotionNotify) {
443 continue;
444 }
445
446 /* Get info about where the pointer is */
447 XQueryPointer(dpy, rootw, &(eventp->xmotion.root), &JunkChild,
448 &(eventp->xmotion.x_root), &(eventp->xmotion.y_root),
449 &JunkX, &JunkY, &JunkMask);
450
451 /*
452 * Tweak up for root. XXX Is this even right? There are too
453 * many Root's, and this corrects for a specific one, but I'm not
454 * sure it's the right one...
455 */
457
458 /* Tweak for window box, if this is in one */
459#ifdef WINBOX
460 if(tmp_win->winbox) {
461 XTranslateCoordinates(dpy, dragroot, tmp_win->winbox->window,
462 eventp->xmotion.x_root, eventp->xmotion.y_root,
463 &(eventp->xmotion.x_root), &(eventp->xmotion.y_root), &JunkChild);
464 }
465#endif
466
467 /*
468 * If we haven't moved MoveDelta yet, we're not yet sure we're
469 * doing anything, so just loop back around.
470 */
471 if(DragWindow == None &&
472 abs(eventp->xmotion.x_root - origX) < Scr->MoveDelta &&
473 abs(eventp->xmotion.y_root - origY) < Scr->MoveDelta) {
474 continue;
475 }
476
477 /*
478 * Now we know we're moving whatever the window is.
479 */
480 DragWindow = w;
481
482 /* Raise when the move starts if we should */
483 if(!Scr->NoRaiseMove && Scr->OpaqueMove && !WindowMoved) {
484 TwmWindow *t;
485
486 /*
487 * XXX In several of the error cases listed in here, it's
488 * seems almost that we should just abort the whole move
489 * process immediately if any of them are hit, because things
490 * get nonsensical.
491 */
492
493 /* Find TwmWindow bits related to what we're dragging */
495 fprintf(stderr, "%s(): Can't find TwmWindow.\n", __func__);
496 /* XXX abort? */
497 t = NULL;
498 }
499
500 if(t != tmp_win) {
501 fprintf(stderr, "%s(): DragWindow isn't tmp_win!\n", __func__);
502 /* XXX abort? */
503 }
504
505 if(t == NULL) {
506 /* Don't try doing this stuff... */
507 }
508 else if(DragWindow == t->frame) {
509 if(moving_icon) {
510 fprintf(stderr, "%s(): moving_icon is true incorrectly!\n",
511 __func__);
512 }
513 OtpRaise(t, WinWin);
514 }
515 else if(t->icon && DragWindow == t->icon->w) {
516 if(!moving_icon) {
517 fprintf(stderr, "%s(): moving_icon is false incorrectly!\n",
518 __func__);
519 }
521 }
522 else {
523 fprintf(stderr, "%s(): Couldn't figure what to raise.\n",
524 __func__);
525 }
526 }
527
528 WindowMoved = true;
529
530 /*
531 * Handle moving the step
532 */
533 if(ConstMove) {
534 /* Did we already decide it's constrained? Do that. */
535 switch(ConstMoveDir) {
536 case MOVE_NONE: {
537 /* Haven't figured direction yet, so do so */
538 if(eventp->xmotion.x_root < ConstMoveXL ||
539 eventp->xmotion.x_root > ConstMoveXR) {
541 }
542
543 if(eventp->xmotion.y_root < ConstMoveYT ||
544 eventp->xmotion.y_root > ConstMoveYB) {
546 }
547
549 &JunkX, &JunkY, &DragX, &DragY, &JunkMask);
550 break;
551 }
552
553 /* We know which dir it's contrained to, so figure amount */
554 case MOVE_VERT:
555 ConstMoveY = eventp->xmotion.y_root - DragY - DragBW;
556 break;
557
558 case MOVE_HORIZ:
559 ConstMoveX = eventp->xmotion.x_root - DragX - DragBW;
560 break;
561 }
562
563 /* We've got a move to do, so do it */
564 if(ConstMoveDir != MOVE_NONE) {
565 int xl, yt, width, height;
566
567 xl = ConstMoveX;
568 yt = ConstMoveY;
569 width = DragWidth + 2 * DragBW;
570 height = DragHeight + 2 * DragBW;
571
572 if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
573 TryToGrid(tmp_win, &xl, &yt);
574 }
575 if(!moving_icon && MoveFunction == F_MOVEPUSH && Scr->OpaqueMove) {
577 }
578
579 if(!moving_icon &&
581 TryToPack(tmp_win, &xl, &yt);
582 }
583
584 if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
585 ConstrainByBorders(tmp_win, &xl, width, &yt, height);
586 }
589 if(Scr->OpaqueMove) {
592 tmp_win->frame_width, tmp_win->frame_height, -1);
593 }
594 else {
596 if(moving_icon) {
597 tmp_win->icon->w_x = xl;
598 tmp_win->icon->w_y = yt;
599 }
600 }
601 WMapSetupWindow(tmp_win, xl, yt, -1, -1);
602 }
603 else {
604 MoveOutline(dragroot, xl + Scr->currentvs->x,
605 yt + Scr->currentvs->y, width, height,
606 tmp_win->frame_bw,
607 moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
608 }
609 }
610 }
611 else if(DragWindow != None) {
612 /*
613 * There's a non-constrained move to process
614 *
615 * This is split out for virtual screens. In that case, it's
616 * possible to drag windows from one workspace to another, and
617 * as such, these need to be adjusted to the root, rather
618 * than this virtual screen...
619 */
620 const int xroot = eventp->xmotion.x_root;
621 const int yroot = eventp->xmotion.y_root;
622 const int width = DragWidth + 2 * DragBW;
623 const int height = DragHeight + 2 * DragBW;
624 int xl, yt;
625
627 xl = xroot - DragX - DragBW;
628 yt = yroot - DragY - DragBW;
629 }
630 else {
631 xl = xroot - (DragWidth / 2);
632 yt = yroot - (DragHeight / 2);
633 }
634
635 if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
636 TryToGrid(tmp_win, &xl, &yt);
637 }
638 if(!moving_icon && MoveFunction == F_MOVEPUSH && Scr->OpaqueMove) {
640 }
641
642 if(!moving_icon &&
644 TryToPack(tmp_win, &xl, &yt);
645 }
646
647 if(Scr->DontMoveOff && MoveFunction != F_FORCEMOVE) {
648 ConstrainByBorders(tmp_win, &xl, width, &yt, height);
649 }
650
653 if(Scr->OpaqueMove) {
656 tmp_win->frame_width, tmp_win->frame_height, -1);
657 }
658 else {
660 if(moving_icon) {
661 tmp_win->icon->w_x = xl;
662 tmp_win->icon->w_y = yt;
663 }
664 }
665 if(! moving_icon) {
666 WMapSetupWindow(tmp_win, xl, yt, -1, -1);
667 }
668 }
669 else {
670 MoveOutline(dragroot, xl + Scr->currentvs->x,
671 yt + Scr->currentvs->y, width, height,
672 tmp_win->frame_bw,
673 moving_icon ? 0 : tmp_win->title_height + tmp_win->frame_bw3D);
674 }
675 }
676
677 /* We've moved a step, so update the displayed position */
679 }
680
681 /* Done, so hide away the position display window */
682 XUnmapWindow(dpy, Scr->SizeWindow);
683
684 /* Restore colormap if we replaced it */
685 if(!Scr->OpaqueMove && DragWindow == None) {
687 }
688
689 return;
690}
691
692
693/*
694 * f.pack -- moving until collision
695 *
696 * XXX Collapse this down; no need for an extra level of indirection on
697 * the function calling.
698 */
699static void packwindow(TwmWindow *tmp_win, const char *direction);
701{
702 if(tmp_win->squeezed) {
703 XBell(dpy, 0);
704 return;
705 }
706 packwindow(tmp_win, action);
707}
708
709static void
711{
712 int cons, newx, newy;
713 int x, y, px, py, junkX, junkY;
714 unsigned int junkK;
716
717 if(!strcmp(direction, "left")) {
719 if(cons == -1) {
720 return;
721 }
722 newx = cons;
723 newy = tmp_win->frame_y;
724 }
725 else if(!strcmp(direction, "right")) {
727 if(cons == -1) {
728 return;
729 }
730 newx = cons;
731 newx -= tmp_win->frame_width + 2 * tmp_win->frame_bw;
732 newy = tmp_win->frame_y;
733 }
734 else if(!strcmp(direction, "top")) {
736 if(cons == -1) {
737 return;
738 }
739 newx = tmp_win->frame_x;
740 newy = cons;
741 }
742 else if(!strcmp(direction, "bottom")) {
744 if(cons == -1) {
745 return;
746 }
747 newx = tmp_win->frame_x;
748 newy = cons;
749 newy -= tmp_win->frame_height + 2 * tmp_win->frame_bw;
750 }
751 else {
752 return;
753 }
754
755 XQueryPointer(dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &x, &y, &junkK);
756 px = x - tmp_win->frame_x + newx;
757 py = y - tmp_win->frame_y + newy;
758 XWarpPointer(dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, px, py);
760 XMoveWindow(dpy, tmp_win->frame, newx, newy);
761 SetupWindow(tmp_win, newx, newy, tmp_win->frame_width,
762 tmp_win->frame_height, -1);
763}
764
765
766/*
767 * f.jump* -- moving incrementally in various directions
768 */
769static void jump(TwmWindow *tmp_win, MoveFillDir direction, const char *action);
771{
772 jump(tmp_win, MFD_LEFT, action);
773}
775{
776 jump(tmp_win, MFD_RIGHT, action);
777}
779{
780 jump(tmp_win, MFD_BOTTOM, action);
781}
783{
784 jump(tmp_win, MFD_TOP, action);
785}
786
787static void
789{
790 int fx, fy, px, py, step, status, cons;
791 int fwidth, fheight;
792 int junkX, junkY;
793 unsigned int junkK;
795
796 if(tmp_win->squeezed) {
797 XBell(dpy, 0);
798 return;
799 }
800
801 if(! action) {
802 return;
803 }
804 status = sscanf(action, "%d", &step);
805 if(status != 1) {
806 return;
807 }
808 if(step < 1) {
809 return;
810 }
811
812 fx = tmp_win->frame_x;
813 fy = tmp_win->frame_y;
814 XQueryPointer(dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &px, &py, &junkK);
815 px -= fx;
816 py -= fy;
817
818 fwidth = tmp_win->frame_width + 2 * tmp_win->frame_bw;
819 fheight = tmp_win->frame_height + 2 * tmp_win->frame_bw;
820 switch(direction) {
821 case MFD_LEFT:
823 if(cons == -1) {
824 return;
825 }
826 fx -= step * Scr->XMoveGrid;
827 if(fx < cons) {
828 fx = cons;
829 }
830 break;
831 case MFD_RIGHT:
833 if(cons == -1) {
834 return;
835 }
836 fx += step * Scr->XMoveGrid;
837 if(fx + fwidth > cons) {
838 fx = cons - fwidth;
839 }
840 break;
841 case MFD_TOP:
843 if(cons == -1) {
844 return;
845 }
846 fy -= step * Scr->YMoveGrid;
847 if(fy < cons) {
848 fy = cons;
849 }
850 break;
851 case MFD_BOTTOM:
853 if(cons == -1) {
854 return;
855 }
856 fy += step * Scr->YMoveGrid;
857 if(fy + fheight > cons) {
858 fy = cons - fheight;
859 }
860 break;
861 }
862 /* Pebl Fixme: don't warp if jump happens through iconmgr */
863 XWarpPointer(dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, fx + px, fy + py);
864 if(!Scr->NoRaiseMove) {
866 }
867 SetupWindow(tmp_win, fx, fy, tmp_win->frame_width, tmp_win->frame_height, -1);
868}
869
870
871
872/*
873 *********************************************************
874 *
875 * Next up, straightforward resizing operations
876 *
877 *********************************************************
878 */
879
880/*
881 * Standard f.resize
882 */
884{
885 PopDownMenu();
886 if(tmp_win->squeezed) {
887 XBell(dpy, 0);
888 return;
889 }
892
894
895 if(pulldown)
896 XWarpPointer(dpy, None, Scr->Root,
897 0, 0, 0, 0, eventp->xbutton.x_root, eventp->xbutton.y_root);
898
899 if(!tmp_win->icon || (w != tmp_win->icon->w)) { /* can't resize icons */
900
901 /* fromMenu = False; ????? */
902 if((Context == C_FRAME || Context == C_WINDOW || Context == C_TITLE
903 || Context == C_ROOT)
904 && cur_fromMenu()) {
906 }
907 else {
908 /*
909 * see if this is being done from the titlebar
910 */
911 bool from3dborder = (eventp->xbutton.window == tmp_win->frame);
912 bool fromtitlebar = !from3dborder &&
913 belongs_to_twm_window(tmp_win, eventp->xbutton.window);
914
915 /* Save pointer position so we can tell if it was moved or
916 not during the resize. */
917 ResizeOrigX = eventp->xbutton.x_root;
918 ResizeOrigY = eventp->xbutton.y_root;
919
921 func_reset_cursor = false; // Leave special cursor alone
922
923 do {
928
929 if(fromtitlebar && Event.type == ButtonPress) {
930 fromtitlebar = false;
931 continue;
932 }
933
934 if(Event.type == MotionNotify) {
935 /* discard any extra motion events before a release */
936 while
939 if(Event.type == ButtonRelease) {
940 break;
941 }
942 }
943
944 if(!DispatchEvent2()) {
945 continue;
946 }
947
948 }
949 while(!(Event.type == ButtonRelease || Cancel));
950 }
951 }
952 return;
953}
954
955
956/*
957 * The various zoom resizes
958 */
960{
961 fullzoom(tmp_win, func);
962}
964{
965 fullzoom(tmp_win, func);
966}
968{
969 fullzoom(tmp_win, func);
970}
976{
977 fullzoom(tmp_win, func);
978}
980{
981 fullzoom(tmp_win, func);
982}
984{
985 fullzoom(tmp_win, func);
986}
988{
989 fullzoom(tmp_win, func);
990}
991
993{
994 fullzoom(tmp_win, func);
995}
997{
998 fullzoom(tmp_win, func);
999}
1001{
1002 fullzoom(tmp_win, func);
1003}
1005{
1006 fullzoom(tmp_win, func);
1007}
1009{
1010 fullzoom(tmp_win, func);
1011}
1013{
1014 fullzoom(tmp_win, func);
1015}
1017{
1018 fullzoom(tmp_win, func);
1019}
1021{
1022 fullzoom(tmp_win, func);
1023}
1024
1025
1026/*
1027 * f.fill - resizing until collision
1028 *
1029 * XXX Similar to f.pack's, collapse away this extra level of function.
1030 */
1031static void fillwindow(TwmWindow *tmp_win, const char *direction);
1033{
1034 if(tmp_win->squeezed) {
1035 XBell(dpy, 0);
1036 return;
1037 }
1038 fillwindow(tmp_win, action);
1039}
1040
1041static void
1043{
1044 int cons, newx, newy, save;
1045 unsigned int neww, newh;
1046 int i;
1047 const int winx = tmp_win->frame_x;
1048 const int winy = tmp_win->frame_y;
1049 const int winw = tmp_win->frame_width + 2 * tmp_win->frame_bw;
1050 const int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
1051
1052 if(!strcmp(direction, "left")) {
1054 if(cons == -1) {
1055 return;
1056 }
1057 newx = cons;
1058 newy = tmp_win->frame_y;
1059 neww = winw + winx - newx;
1060 newh = winh;
1061 neww -= 2 * tmp_win->frame_bw;
1062 newh -= 2 * tmp_win->frame_bw;
1064 }
1065 else if(!strcmp(direction, "right")) {
1066 for(i = 0; i < 2; i++) {
1068 if(cons == -1) {
1069 return;
1070 }
1071 newx = tmp_win->frame_x;
1072 newy = tmp_win->frame_y;
1073 neww = cons - winx;
1074 newh = winh;
1075 save = neww;
1076 neww -= 2 * tmp_win->frame_bw;
1077 newh -= 2 * tmp_win->frame_bw;
1079 if((neww != winw) || (newh != winh) ||
1080 (cons == Scr->rootw - Scr->BorderRight)) {
1081 break;
1082 }
1083 neww = save;
1085 }
1086 }
1087 else if(!strcmp(direction, "top")) {
1089 if(cons == -1) {
1090 return;
1091 }
1092 newx = tmp_win->frame_x;
1093 newy = cons;
1094 neww = winw;
1095 newh = winh + winy - newy;
1096 neww -= 2 * tmp_win->frame_bw;
1097 newh -= 2 * tmp_win->frame_bw;
1099 }
1100 else if(!strcmp(direction, "bottom")) {
1101 for(i = 0; i < 2; i++) {
1103 if(cons == -1) {
1104 return;
1105 }
1106 newx = tmp_win->frame_x;
1107 newy = tmp_win->frame_y;
1108 neww = winw;
1109 newh = cons - winy;
1110 save = newh;
1111 neww -= 2 * tmp_win->frame_bw;
1112 newh -= 2 * tmp_win->frame_bw;
1114 if((neww != winw) || (newh != winh) ||
1115 (cons == Scr->rooth - Scr->BorderBottom)) {
1116 break;
1117 }
1118 newh = save;
1120 }
1121 }
1122 else if(!strcmp(direction, "vertical")) {
1123 if(tmp_win->zoomed == ZOOM_NONE) {
1124 tmp_win->save_frame_height = tmp_win->frame_height;
1125 tmp_win->save_frame_width = tmp_win->frame_width;
1126 tmp_win->save_frame_y = tmp_win->frame_y;
1127 tmp_win->save_frame_x = tmp_win->frame_x;
1128
1129 tmp_win->frame_y++;
1131 tmp_win->frame_y--;
1133 newh -= 2 * tmp_win->frame_bw;
1134
1135 newx = tmp_win->frame_x;
1136 neww = tmp_win->frame_width;
1137
1139
1140 /* if the bottom of the window has moved up
1141 * it will be pushed down */
1142 if(newy + newh < tmp_win->save_frame_y + tmp_win->save_frame_height) {
1143 newy = tmp_win->save_frame_y +
1144 tmp_win->save_frame_height - newh;
1145 }
1146 tmp_win->zoomed = F_ZOOM;
1148 }
1149 else {
1150 fullzoom(tmp_win, tmp_win->zoomed);
1151 }
1152 return;
1153 }
1154 else {
1155 return;
1156 }
1158}
1159
1160
1161
1162/*
1163 *********************************************************
1164 *
1165 * Resizing/moving to specified geometries
1166 *
1167 *********************************************************
1168 */
1169
1170/*
1171 * Resizing to a window's idea of its "normal" size, from WM_NORMAL_HINTS
1172 * property.
1173 */
1175{
1176 int grav, x, y;
1177 unsigned int width, height, swidth, sheight;
1178
1179 grav = ((tmp_win->hints.flags & PWinGravity)
1180 ? tmp_win->hints.win_gravity : NorthWestGravity);
1181
1182 if(!(tmp_win->hints.flags & USSize) && !(tmp_win->hints.flags & PSize)) {
1183 return;
1184 }
1185
1186 width = tmp_win->hints.width + 2 * tmp_win->frame_bw3D;
1187 height = tmp_win->hints.height + 2 * tmp_win->frame_bw3D +
1188 tmp_win->title_height;
1189 ConstrainSize(tmp_win, &width, &height);
1190
1191 x = tmp_win->frame_x;
1192 y = tmp_win->frame_y;
1193 swidth = tmp_win->frame_width;
1194 sheight = tmp_win->frame_height;
1195
1196 switch(grav) {
1197 case ForgetGravity:
1198 case StaticGravity:
1199 case NorthWestGravity:
1200 case NorthGravity:
1201 case WestGravity:
1202 case CenterGravity:
1203 break;
1204
1205 case NorthEastGravity:
1206 case EastGravity:
1207 x += swidth - width;
1208 break;
1209
1210 case SouthWestGravity:
1211 case SouthGravity:
1212 y += sheight - height;
1213 break;
1214
1215 case SouthEastGravity:
1216 x += swidth - width;
1217 y += sheight - height;
1218 break;
1219 }
1220
1221 SetupWindow(tmp_win, x, y, width, height, -1);
1222 return;
1223}
1224
1225
1226/*
1227 * Setting a window to a specific specified geometry string.
1228 */
1230{
1231 int x, y, mask;
1232 unsigned int width, height;
1233 int px = 20, py = 30;
1234
1235 mask = RLayoutXParseGeometry(Scr->Layout, action, &x, &y, &width, &height);
1236 if(!(mask & WidthValue)) {
1237 width = tmp_win->frame_width;
1238 }
1239 else {
1240 width += 2 * tmp_win->frame_bw3D;
1241 }
1242 if(!(mask & HeightValue)) {
1243 height = tmp_win->frame_height;
1244 }
1245 else {
1246 height += 2 * tmp_win->frame_bw3D + tmp_win->title_height;
1247 }
1248 ConstrainSize(tmp_win, &width, &height);
1249 if(mask & XValue) {
1250 if(mask & XNegative) {
1251 x += Scr->rootw - width;
1252 }
1253 }
1254 else {
1255 x = tmp_win->frame_x;
1256 }
1257 if(mask & YValue) {
1258 if(mask & YNegative) {
1259 y += Scr->rooth - height;
1260 }
1261 }
1262 else {
1263 y = tmp_win->frame_y;
1264 }
1265
1266 {
1267 int junkX, junkY;
1268 unsigned int junkK;
1269 Window junkW;
1270 XQueryPointer(dpy, Scr->Root, &junkW, &junkW, &junkX, &junkY, &px, &py, &junkK);
1271 }
1272 px -= tmp_win->frame_x;
1273 if(px > width) {
1274 px = width / 2;
1275 }
1276 py -= tmp_win->frame_y;
1277 if(py > height) {
1278 px = height / 2;
1279 }
1280
1281 SetupWindow(tmp_win, x, y, width, height, -1);
1282 XWarpPointer(dpy, Scr->Root, Scr->Root, 0, 0, 0, 0, x + px, y + py);
1283 return;
1284}
1285
1286
1287/*
1288 * Making a specified alteration to a window's size
1289 */
1291{
1292 /* XXX Only use of this func; should we collapse? */
1293 ChangeSize(action, tmp_win);
1294}
1295
1296
1297/*
1298 * Stashing and flipping back to a geometry
1299 */
1304
1309
1310
1311
1312
1313/*
1314 *********************************************************
1315 *
1316 * Misc utils used in the above
1317 *
1318 *********************************************************
1319 */
1320
1321/*
1322 * Used in the various move/fill/pack/etc bits
1323 */
1324static int
1326{
1327 TwmWindow *t;
1328 int ret, limit;
1329 const int winx = tmp_win->frame_x;
1330 const int winy = tmp_win->frame_y;
1331 const int winw = tmp_win->frame_width + 2 * tmp_win->frame_bw;
1332 const int winh = tmp_win->frame_height + 2 * tmp_win->frame_bw;
1333
1334 RArea area = RAreaNew(winx, winy, winw, winh);
1335
1336 switch(direction) {
1337 case MFD_LEFT:
1338 limit = RLayoutFindMonitorLeftEdge(Scr->BorderedLayout, &area);
1339 if(winx < limit) {
1340 return -1;
1341 }
1342 ret = limit;
1343 break;
1344 case MFD_RIGHT:
1345 limit = RLayoutFindMonitorRightEdge(Scr->BorderedLayout, &area);
1346 if(winx + winw > limit) {
1347 return -1;
1348 }
1349 ret = limit + 1;
1350 break;
1351 case MFD_TOP:
1352 limit = RLayoutFindMonitorTopEdge(Scr->BorderedLayout, &area);
1353 if(winy < limit) {
1354 return -1;
1355 }
1356 ret = limit;
1357 break;
1358 case MFD_BOTTOM:
1359 limit = RLayoutFindMonitorBottomEdge(Scr->BorderedLayout, &area);
1360 if(winy + winh > limit) {
1361 return -1;
1362 }
1363 ret = limit + 1;
1364 break;
1365 default:
1366 return -1;
1367 }
1368 for(t = Scr->FirstWindow; t != NULL; t = t->next) {
1369 const int w = t->frame_width + 2 * t->frame_bw;
1370 const int h = t->frame_height + 2 * t->frame_bw;
1371
1372 if(t == tmp_win) {
1373 continue;
1374 }
1375 if(!visible(t)) {
1376 continue;
1377 }
1378 if(!t->mapped) {
1379 continue;
1380 }
1381
1382 switch(direction) {
1383 case MFD_LEFT:
1384 if(winx <= t->frame_x + w) {
1385 continue;
1386 }
1387 if(winy >= t->frame_y + h) {
1388 continue;
1389 }
1390 if(winy + winh <= t->frame_y) {
1391 continue;
1392 }
1393 ret = MAX(ret, t->frame_x + w);
1394 break;
1395 case MFD_RIGHT:
1396 if(winx + winw >= t->frame_x) {
1397 continue;
1398 }
1399 if(winy >= t->frame_y + h) {
1400 continue;
1401 }
1402 if(winy + winh <= t->frame_y) {
1403 continue;
1404 }
1405 ret = MIN(ret, t->frame_x);
1406 break;
1407 case MFD_TOP:
1408 if(winy <= t->frame_y + h) {
1409 continue;
1410 }
1411 if(winx >= t->frame_x + w) {
1412 continue;
1413 }
1414 if(winx + winw <= t->frame_x) {
1415 continue;
1416 }
1417 ret = MAX(ret, t->frame_y + h);
1418 break;
1419 case MFD_BOTTOM:
1420 if(winy + winh >= t->frame_y) {
1421 continue;
1422 }
1423 if(winx >= t->frame_x + w) {
1424 continue;
1425 }
1426 if(winx + winw <= t->frame_x) {
1427 continue;
1428 }
1429 ret = MIN(ret, t->frame_y);
1430 break;
1431 }
1432 }
1433 return ret;
1434}
1435
1436
1437/*
1438 * Is Window w part of the conglomerate of metawindows we put around the
1439 * real window for TwmWindow t? Note that this does _not_ check if w is
1440 * the actual window we built the TwmWindow t around.
1441 */
1442static bool
1444{
1445 /* Safety */
1446 if(!t) {
1447 return false;
1448 }
1449
1450 /* Part of the framing we put around the window? */
1451 if(w == t->frame || w == t->title_w
1452 || w == t->hilite_wl || w == t->hilite_wr) {
1453 return true;
1454 }
1455
1456 /* Part of the icon bits? */
1457 if(t->icon && (w == t->icon->w || w == t->icon->bm_w)) {
1458 return true;
1459 }
1460
1461 /* One of the title button windows? */
1462 if(t->titlebuttons) {
1463 TBWindow *tbw;
1464 int nb = Scr->TBInfo.nleft + Scr->TBInfo.nright;
1465 for(tbw = t->titlebuttons ; nb > 0 ; tbw++, nb--) {
1466 if(tbw->window == w) {
1467 return true;
1468 }
1469 }
1470 }
1471
1472 /* Then no */
1473 return false;
1474}
static int PlaceX
Definition add_window.c:82
void UninstallRootColormap(void)
Definition colormaps.c:213
void InstallRootColormap(void)
Definition colormaps.c:173
int JunkY
Definition ctwm.h:358
Cursor LeftButt
Definition ctwm_main.c:117
Window JunkRoot
Definition ctwm_main.c:142
int JunkX
Definition ctwm_main.c:143
Display * dpy
Definition ctwm_main.c:84
#define C_ROOT
Definition ctwm.h:78
XContext TwmContext
Definition ctwm_main.c:119
unsigned int JunkMask
Definition ctwm.h:359
#define C_TITLE
Definition ctwm.h:76
#define C_WINDOW
Definition ctwm.h:75
Cursor MiddleButt
Definition ctwm_main.c:116
#define C_FRAME
Definition ctwm.h:79
Window JunkChild
Definition ctwm.h:357
#define ZOOM_NONE
Definition ctwm.h:111
Cursor RightButt
Definition ctwm_main.c:115
#define C_ICON
Definition ctwm.h:77
unsigned int JunkDepth
Definition ctwm.h:359
#define Scr
unsigned int DragBW
Definition event_core.c:75
int CurrentDragY
Definition event_core.c:77
int CurrentDragX
Definition event_core.c:76
bool Cancel
Definition event_core.c:94
int origDragX
Definition event_core.c:69
unsigned int DragWidth
Definition event_core.c:73
unsigned int DragHeight
Definition event_core.c:74
int origDragY
Definition event_core.c:70
int DragY
Definition event_core.c:72
bool DispatchEvent2(void)
Definition event_core.c:343
XEvent Event
Definition event_core.c:66
event_proc EventHandler[256]
Definition event_core.c:64
Window DragWindow
Definition event_core.c:68
int DragX
Definition event_core.c:71
int Context
Definition event_core.c:65
void HandleUnknown(void)
void FixRootEvent(XEvent *e)
bool WindowMoved
Definition functions.c:52
bool func_reset_cursor
Definition functions.c:65
Time last_time
Definition functions.c:71
CMoveDir
Definition functions.h:14
@ MOVE_VERT
Definition functions.h:16
@ MOVE_NONE
Definition functions.h:15
@ MOVE_HORIZ
Definition functions.h:17
#define DFHANDLER(func)
#define EF_ARGS
#define EF_FULLPROTO
static void movewindow(int func, void *action, Window w, TwmWindow *tmp_win, XEvent *eventp, int context, bool pulldown)
static void packwindow(TwmWindow *tmp_win, const char *direction)
static void jump(TwmWindow *tmp_win, MoveFillDir direction, const char *action)
static bool belongs_to_twm_window(TwmWindow *t, Window w)
static int FindConstraint(TwmWindow *tmp_win, MoveFillDir direction)
CMoveDir ConstMoveDir
static void fillwindow(TwmWindow *tmp_win, const char *direction)
int frame_x
X position on screen of frame.
int y
Definition menus.c:70
bool menuFromFrameOrWindowOrTitlebar
Definition menus.c:60
int x
Definition menus.c:69
void PopDownMenu(void)
Definition menus.c:1442
bool cur_fromMenu(void)
Definition menus.c:482
void OtpRaise(TwmWindow *twm_win, WinType wintype)
Definition otp.c:763
@ WinWin
Definition otp.h:14
@ IconWin
Definition otp.h:14
int ConstrainedMoveTime
Definition parse.c:92
RArea RAreaNew(int x, int y, int width, int height)
Construct an RArea from given components.
Definition r_area.c:19
int RLayoutFindMonitorTopEdge(const RLayout *self, const RArea *area)
Find the top edge of the bottom-most monitor that contains the most of a given RArea.
Definition r_layout.c:684
int RLayoutFindMonitorRightEdge(const RLayout *self, const RArea *area)
Find the right edge of the left-most monitor that contains the most of a given RArea.
Definition r_layout.c:764
int RLayoutFindMonitorBottomEdge(const RLayout *self, const RArea *area)
Find the bottom edge of the top-most monitor that contains the most of a given RArea.
Definition r_layout.c:645
int RLayoutFindMonitorLeftEdge(const RLayout *self, const RArea *area)
Find the left edge of the right-most monitor that contains the most of a given RArea.
Definition r_layout.c:724
#define SIZE_VINDENT
Internal padding in the size window.
Definition screen.h:59
#define SIZE_HINDENT
Internal padding in the size window.
Definition screen.h:58
A particular extent of space.
Definition r_structs.h:16
Info and control for every X Window we take over.
#define MIN(x, y)
Definition util.h:39
#define MAX(x, y)
Definition util.h:36
void SetupWindow(TwmWindow *tmp_win, int x, int y, int w, int h, int bw)
void MoveOutline(Window root, int x, int y, int width, int height, int bw, int th)
Definition win_ops.c:317
void ChangeSize(char *in_string, TwmWindow *tmp_win)
void StartResize(XEvent *evp, TwmWindow *tmp_win, bool fromtitlebar, bool from3dborder)
Definition win_resize.c:183
void ConstrainSize(TwmWindow *tmp_win, unsigned int *widthp, unsigned int *heightp)
Definition win_resize.c:727
void restoregeometry(TwmWindow *tmp_win)
void resizeFromCenter(Window w, TwmWindow *tmp_win)
void OpaqueResizeSize(TwmWindow *tmp_win)
Definition win_resize.c:138
void fullzoom(TwmWindow *tmp_win, int func)
Definition win_resize.c:896
void savegeometry(TwmWindow *tmp_win)
void DisplayPosition(const TwmWindow *_unused_tmp_win, int x, int y)
Definition win_utils.c:466
bool visible(const TwmWindow *tmp_win)
Definition win_utils.c:341
void MoveResizeSizeWindow(int x, int y, unsigned int width, unsigned int height)
Definition win_utils.c:495
void ConstrainByBorders(TwmWindow *twmwin, int *left, int width, int *top, int height)
Definition win_utils.c:825
void TryToPush(TwmWindow *tmp_win, int x, int y)
Definition win_utils.c:617
void TryToGrid(TwmWindow *tmp_win, int *x, int *y)
Definition win_utils.c:705
void TryToPack(TwmWindow *tmp_win, int *x, int *y)
Definition win_utils.c:560
void WMapSetupWindow(TwmWindow *win, int x, int y, int w, int h)
int RLayoutXParseGeometry(RLayout *layout, const char *geometry, int *x, int *y, unsigned int *width, unsigned int *height)
Parse an X Geometry out to get the positions and sizes.