Tidy-up todo-3.0
[fvwm.git] / fvwm / move_resize.c
blob9902341f9da74b014507832f68dbca9b6797bc9f
1 /* -*-c-*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * This module is all original code
19 * by Rob Nation
20 * Copyright 1993, Robert Nation
21 * You may use this code for any purpose, as long as the original
22 * copyright remains in the source code and all documentation
27 * code for moving and resizing windows
31 #include "config.h"
33 #include <stdio.h>
34 #include <math.h>
35 #include <X11/keysym.h>
37 #include "libs/fvwmlib.h"
38 #include "libs/FScreen.h"
39 #include "libs/Picture.h"
40 #include "libs/Grab.h"
41 #include "libs/Parse.h"
42 #include "libs/Graphics.h"
43 #include "fvwm.h"
44 #include "externs.h"
45 #include "cursor.h"
46 #include "execcontext.h"
47 #include "commands.h"
48 #include "misc.h"
49 #include "screen.h"
50 #include "menus.h"
51 #include "menuparameters.h"
52 #include "module_list.h"
53 #include "module_interface.h"
54 #include "focus.h"
55 #include "borders.h"
56 #include "frame.h"
57 #include "geometry.h"
58 #include "gnome.h"
59 #include "ewmh.h"
60 #include "virtual.h"
61 #include "decorations.h"
62 #include "events.h"
63 #include "eventhandler.h"
64 #include "eventmask.h"
65 #include "colormaps.h"
66 #include "update.h"
67 #include "stack.h"
68 #include "move_resize.h"
69 #include "functions.h"
70 #include "style.h"
72 /* ----- move globals ----- */
74 #define MOVE_NORMAL 0x00
75 #define MOVE_PAGE 0x01
76 #define MOVE_SCREEN 0x02
78 /* Animated move stuff added by Greg J. Badros, gjb@cs.washington.edu */
80 float rgpctMovementDefault[32] =
82 -.01, 0, .01, .03,.08,.18,.3,.45,.60,.75,.85,.90,.94,.97,.99,1.0
83 /* must end in 1.0 */
85 int cmsDelayDefault = 10; /* milliseconds */
87 /* current geometry of size window */
88 static rectangle sizew_g =
90 -1,
91 -1,
92 -1,
96 static int move_interactive_finish_button_mask =
97 ((1<<(NUMBER_OF_EXTENDED_MOUSE_BUTTONS))-1) & ~0x2;
98 static int move_drag_finish_button_mask =
99 ((1<<(NUMBER_OF_EXTENDED_MOUSE_BUTTONS))-1) & ~0x3;
101 /* ----- end of move globals ----- */
103 /* ----- resize globals ----- */
105 /* DO NOT USE (STATIC) GLOBALS IN THIS MODULE!
106 * Since some functions are called from other modules unwanted side effects
107 * (i.e. bugs.) would be created */
109 extern Window PressedW;
111 static void draw_move_resize_grid(int x, int y, int width, int height);
113 /* ----- end of resize globals ----- */
117 * Procedure:
118 * draw_move_resize_grid - move a window outline
120 * Inputs:
121 * root - the window we are outlining
122 * x - upper left x coordinate
123 * y - upper left y coordinate
124 * width - the width of the rectangle
125 * height - the height of the rectangle
128 static int get_outline_rects(
129 XRectangle *rects, int x, int y, int width, int height)
131 int i;
132 int n;
133 int m;
135 n = 3;
136 m = (width - 5) / 2;
137 if (m < n)
139 n = m;
141 m = (height - 5) / 2;
142 if (m < n)
144 n = m;
146 if (n < 1)
148 n = 1;
151 for (i = 0; i < n; i++)
153 rects[i].x = x + i;
154 rects[i].y = y + i;
155 rects[i].width = width - (i << 1);
156 rects[i].height = height - (i << 1);
158 if (width - (n << 1) >= 5 && height - (n << 1) >= 5)
160 if (width - (n << 1) >= 10)
162 int off = (width - (n << 1)) / 3 + n;
163 rects[i].x = x + off;
164 rects[i].y = y + n;
165 rects[i].width = width - (off << 1);
166 rects[i].height = height - (n << 1);
167 i++;
169 if (height - (n << 1) >= 10)
171 int off = (height - (n << 1)) / 3 + n;
172 rects[i].x = x + n;
173 rects[i].y = y + off;
174 rects[i].width = width - (n << 1);
175 rects[i].height = height - (off << 1);
176 i++;
180 return i;
183 struct
185 rectangle geom;
186 struct
188 unsigned is_enabled : 1;
189 } flags;
190 } move_resize_grid =
192 { 0, 0, 0, 0 },
193 { 0 }
196 static void draw_move_resize_grid(int x, int y, int width, int height)
198 int nrects = 0;
199 XRectangle rects[10];
201 if (move_resize_grid.flags.is_enabled &&
202 x == move_resize_grid.geom.x &&
203 y == move_resize_grid.geom.y &&
204 width == move_resize_grid.geom.width &&
205 height == move_resize_grid.geom.height)
207 return;
210 memset(rects, 0, 10 * sizeof(XRectangle));
211 /* place the resize rectangle into the array of rectangles */
212 /* interleave them for best visual look */
213 /* draw the new one, if any */
214 if (move_resize_grid.flags.is_enabled
215 /*move_resize_grid.geom.width && move_resize_grid.geom.height*/)
217 move_resize_grid.flags.is_enabled = 0;
218 nrects +=
219 get_outline_rects(
220 &(rects[0]), move_resize_grid.geom.x,
221 move_resize_grid.geom.y,
222 move_resize_grid.geom.width,
223 move_resize_grid.geom.height);
225 if (width && height)
227 move_resize_grid.flags.is_enabled = 1;
228 move_resize_grid.geom.x = x;
229 move_resize_grid.geom.y = y;
230 move_resize_grid.geom.width = width;
231 move_resize_grid.geom.height = height;
232 nrects += get_outline_rects(
233 &(rects[nrects]), x, y, width, height);
235 if (nrects > 0)
237 XDrawRectangles(dpy, Scr.Root, Scr.XorGC, rects, nrects);
238 XFlush(dpy);
241 return;
244 void switch_move_resize_grid(Bool state)
246 if (state == False)
248 if (move_resize_grid.flags.is_enabled)
250 draw_move_resize_grid(0, 0, 0, 0);
252 else
254 move_resize_grid.geom.x = 0;
255 move_resize_grid.geom.y = 0;
256 move_resize_grid.geom.width = 0;
257 move_resize_grid.geom.height = 0;
260 else if (!move_resize_grid.flags.is_enabled)
262 if (move_resize_grid.geom.width &&
263 move_resize_grid.geom.height)
265 draw_move_resize_grid(
266 move_resize_grid.geom.x,
267 move_resize_grid.geom.y,
268 move_resize_grid.geom.width,
269 move_resize_grid.geom.height);
273 return;
276 static int ParsePositionArgumentSuffix(
277 float *ret_factor, char *suffix, float wfactor, float sfactor)
279 int n;
281 switch (*suffix)
283 case 'p':
284 case 'P':
285 *ret_factor = 1.0;
286 n = 1;
287 break;
288 case 'w':
289 case 'W':
290 *ret_factor = wfactor;
291 n = 1;
292 break;
293 default:
294 *ret_factor = sfactor;
295 n = 0;
296 break;
299 return n;
302 static int __get_shift(int val, float factor)
304 int shift;
306 if (val >= 0)
308 shift = (int)(val * factor + 0.5);
310 else
312 shift = (int)(val * factor - 0.5);
315 return shift;
318 /* The vars are named for the x-direction, but this is used for both x and y */
319 static int GetOnePositionArgument(
320 char *s1, int window_pos, int window_size, int *pFinalPos,
321 float sfactor, int screen_size, int screen_pos, Bool is_x)
323 int final_pos;
324 float wfactor;
326 if (s1 == 0 || *s1 == 0)
328 return 0;
330 wfactor = (float)window_size / 100;
331 /* get start position */
332 switch (*s1)
334 case 'w':
335 case 'W':
336 final_pos = window_pos;
337 s1++;
338 break;
339 case 'm':
340 case 'M':
342 int x;
343 int y;
345 if (
346 FQueryPointer(
347 dpy, Scr.Root, &JunkRoot, &JunkChild, &JunkX,
348 &JunkY, &x, &y, &JunkMask) == False)
350 /* pointer is on a different screen - that's okay here
352 final_pos = 0;
354 else
356 final_pos = (is_x) ? x : y;
358 s1++;
359 break;
361 default:
362 final_pos = screen_pos;
363 if (*s1 != 0)
365 int val;
366 int n;
367 float f;
369 /* parse value */
370 if (sscanf(s1, "-%d%n", &val, &n) >= 1)
372 /* i.e. -1, -+1 or --1 */
373 final_pos += (screen_size - window_size);
374 val = -val;
376 else if (
377 sscanf(s1, "+%d%n", &val, &n) >= 1 ||
378 sscanf(s1, "%d%n", &val, &n) >= 1)
380 /* i.e. 1, +1, ++1 or +-1 */
382 else
384 /* syntax error, ignore rest of string */
385 break;
387 s1 += n;
388 /* parse suffix */
389 n = ParsePositionArgumentSuffix(
390 &f, s1, wfactor, sfactor);
391 s1 += n;
392 final_pos += __get_shift(val, f);
394 break;
396 /* loop over shift arguments */
397 while (*s1 != 0)
399 int val;
400 int n;
401 float f;
403 /* parse value */
404 if (sscanf(s1, "%d%n", &val, &n) < 1)
406 /* syntax error, ignore rest of string */
407 break;
409 s1 += n;
410 /* parse suffix */
411 n = ParsePositionArgumentSuffix(&f, s1, wfactor, sfactor);
412 s1 += n;
413 final_pos += __get_shift(val, f);
415 *pFinalPos = final_pos;
417 return 1;
420 /* GetMoveArguments is used for Move & AnimatedMove
421 * It lets you specify in all the following ways
422 * 20 30 Absolute percent position, from left edge and top
423 * -50 50 Absolute percent position, from right edge and top
424 * 10p 5p Absolute pixel position
425 * 10p -0p Absolute pixel position, from bottom
426 * w+5 w-10p Relative position, right 5%, up ten pixels
427 * m+5 m-10p Pointer relative position, right 5%, up ten pixels
428 * Returns 2 when x & y have parsed without error, 0 otherwise
430 int GetMoveArguments(
431 char **paction, int w, int h, int *pFinalX, int *pFinalY,
432 Bool *fWarp, Bool *fPointer, Bool fKeep)
434 char *s1 = NULL;
435 char *s2 = NULL;
436 char *warp = NULL;
437 char *action;
438 char *naction;
439 int scr_x = 0;
440 int scr_y = 0;
441 int scr_w = Scr.MyDisplayWidth;
442 int scr_h = Scr.MyDisplayHeight;
443 int retval = 0;
445 if (!paction)
447 return 0;
449 action = *paction;
450 action = GetNextToken(action, &s1);
451 if (s1 && fPointer && StrEquals(s1, "pointer"))
453 *fPointer = True;
454 *paction = action;
455 free(s1);
456 return 0;
458 if (s1 && StrEquals(s1, "screen"))
460 char *token;
461 int scr;
462 fscreen_scr_arg arg;
463 fscreen_scr_arg* parg;
465 free(s1);
466 token = PeekToken(action, &action);
467 scr = FScreenGetScreenArgument(token, FSCREEN_SPEC_PRIMARY);
468 if (scr == FSCREEN_XYPOS)
470 arg.xypos.x = *pFinalX;
471 arg.xypos.y = *pFinalY;
472 parg = &arg;
474 else
476 parg = NULL;
478 FScreenGetScrRect(parg, scr, &scr_x, &scr_y, &scr_w, &scr_h);
479 action = GetNextToken(action, &s1);
481 action = GetNextToken(action, &s2);
482 if (fWarp)
484 warp = PeekToken(action, &naction);
485 if (StrEquals(warp, "Warp"))
487 *fWarp = True;
488 action = naction;
492 if (s1 != NULL && s2 != NULL)
494 retval = 0;
495 if (fKeep == True && StrEquals(s1, "keep"))
497 retval++;
499 else if (
500 GetOnePositionArgument(
501 s1, *pFinalX, w, pFinalX, (float)scr_w / 100,
502 scr_w, scr_x, True))
504 retval++;
506 if (fKeep == True && StrEquals(s2, "keep"))
508 retval++;
510 else if (
511 GetOnePositionArgument(
512 s2, *pFinalY, h, pFinalY, (float)scr_h / 100,
513 scr_h, scr_y, False))
515 retval++;
517 if (retval == 0)
519 /* make sure warping is off for interactive moves */
520 *fWarp = False;
523 else
525 /* not enough arguments, switch to current page. */
526 while (*pFinalX < 0)
528 *pFinalX = Scr.MyDisplayWidth + *pFinalX;
530 while (*pFinalY < 0)
532 *pFinalY = Scr.MyDisplayHeight + *pFinalY;
536 if (s1)
538 free(s1);
540 if (s2)
542 free(s2);
544 *paction = action;
546 return retval;
549 static int ParseOneResizeArgument(
550 char *arg, int scr_size, int base_size, int size_inc, int add_size,
551 int *ret_size)
553 float factor;
554 int val;
555 int add_base_size = 0;
556 int cch = strlen(arg);
557 int tmp_size;
559 if (cch == 0)
561 return 0;
563 if (StrEquals(arg, "keep"))
565 /* do not change size */
566 return 1;
568 if (arg[cch-1] == 'p')
570 factor = 1;
571 arg[cch-1] = '\0';
573 else if (arg[cch-1] == 'c')
575 factor = size_inc;
576 add_base_size = base_size;
577 arg[cch-1] = '\0';
579 else
581 factor = (float)scr_size / 100.0;
583 if (strcmp(arg,"w") == 0)
585 /* do not change size */
587 else if (sscanf(arg,"w-%d",&val) == 1)
589 tmp_size = (int)(val * factor + 0.5);
590 if (tmp_size < *ret_size)
592 *ret_size -= tmp_size;
594 else
596 *ret_size = 0;
599 else if (sscanf(arg,"w+%d",&val) == 1 || sscanf(arg,"w%d",&val) == 1)
601 tmp_size = (int)(val * factor + 0.5);
602 if (-tmp_size < *ret_size)
604 *ret_size += tmp_size;
606 else
608 *ret_size = 0;
611 else if (sscanf(arg,"-%d",&val) == 1)
613 tmp_size = (int)(val * factor + 0.5);
614 if (tmp_size < scr_size + add_size)
616 *ret_size = scr_size - tmp_size + add_size;
618 else
620 *ret_size = 0;
623 else if (sscanf(arg,"+%d",&val) == 1 || sscanf(arg,"%d",&val) == 1)
625 tmp_size = (int)(val * factor + 0.5);
626 if (-tmp_size < add_size + add_base_size)
628 *ret_size = tmp_size + add_size + add_base_size;
630 else
632 *ret_size = 0;
635 else
637 return 0;
640 return 1;
643 static int GetResizeArguments(
644 char **paction, int x, int y, int w_base, int h_base, int w_inc,
645 int h_inc, size_borders *sb, int *pFinalW, int *pFinalH,
646 direction_t *ret_dir, Bool *is_direction_fixed,
647 Bool *do_warp_to_border)
649 int n;
650 char *naction;
651 char *token;
652 char *s1;
653 char *s2;
654 int w_add;
655 int h_add;
656 int has_frame_option;
658 *ret_dir = DIR_NONE;
659 *is_direction_fixed = False;
660 *do_warp_to_border = False;
661 if (!paction)
663 return 0;
665 token = PeekToken(*paction, &naction);
666 if (!token)
668 return 0;
670 if (StrEquals(token, "bottomright") || StrEquals(token, "br"))
672 int nx = x + *pFinalW - 1;
673 int ny = y + *pFinalH - 1;
675 n = GetMoveArguments(
676 &naction, 0, 0, &nx, &ny, NULL, NULL, True);
677 if (n < 2)
679 return 0;
681 *pFinalW = nx - x + 1;
682 *pFinalH = ny - y + 1;
683 *paction = naction;
685 return n;
687 has_frame_option = 0;
688 for ( ; ; token = PeekToken(naction, &naction))
690 if (StrEquals(token, "frame"))
692 has_frame_option = 1;
694 else if (StrEquals(token, "direction"))
696 if (token == NULL)
698 return 0;
700 *ret_dir = gravity_parse_dir_argument(
701 naction, &naction, DIR_NONE);
702 if (*ret_dir != DIR_NONE)
704 *is_direction_fixed = True;
707 else if (StrEquals(token, "fixeddirection"))
709 *is_direction_fixed = True;
711 else if (StrEquals(token, "warptoborder"))
713 *do_warp_to_border = True;
715 else
717 break;
720 if (has_frame_option)
722 w_add = 0;
723 h_add = 0;
725 else
727 w_add = sb->total_size.width;
728 h_add = sb->total_size.height;
730 s1 = NULL;
731 if (token != NULL)
733 s1 = safestrdup(token);
735 naction = GetNextToken(naction, &s2);
736 if (!s2)
738 if (s1 != NULL)
740 free(s1);
742 return 0;
744 *paction = naction;
746 n = 0;
747 n += ParseOneResizeArgument(
748 s1, Scr.MyDisplayWidth, w_base, w_inc, w_add, pFinalW);
749 n += ParseOneResizeArgument(
750 s2, Scr.MyDisplayHeight, h_base, h_inc, h_add, pFinalH);
751 if (s1 != NULL)
753 free(s1);
755 if (s2 != NULL)
757 free(s2);
759 if (n < 2)
761 n = 0;
764 return n;
767 static int GetResizeMoveArguments(
768 char **paction, int w_base, int h_base, int w_inc, int h_inc,
769 size_borders *sb, int *pFinalX, int *pFinalY,
770 int *pFinalW, int *pFinalH, Bool *fWarp, Bool *fPointer)
772 char *action = *paction;
773 direction_t dir;
774 Bool dummy;
776 if (!paction)
778 return 0;
780 if (GetResizeArguments(
781 &action, *pFinalX, *pFinalY, w_base, h_base, w_inc, h_inc,
782 sb, pFinalW, pFinalH, &dir, &dummy, &dummy) < 2)
784 return 0;
786 if (GetMoveArguments(
787 &action, *pFinalW, *pFinalH, pFinalX, pFinalY, fWarp,
788 NULL, True) < 2)
790 return 0;
792 *paction = action;
794 return 4;
797 /* Positions the SizeWindow on the current ("moused") xinerama-screen */
798 static void position_geometry_window(const XEvent *eventp)
800 int x;
801 int y;
802 fscreen_scr_arg fscr;
804 fscr.mouse_ev = (XEvent *)eventp;
805 /* Probably should remove this positioning code from {builtins,fvwm}.c?
807 if (Scr.gs.do_emulate_mwm)
809 FScreenCenterOnScreen(
810 &fscr, FSCREEN_CURRENT, &x, &y, sizew_g.width,
811 sizew_g.height);
813 else
815 FScreenGetScrRect(&fscr, FSCREEN_CURRENT, &x, &y, NULL, NULL);
817 if (x != sizew_g.x || y != sizew_g.y)
819 switch_move_resize_grid(False);
820 XMoveWindow(dpy, Scr.SizeWindow, x, y);
821 switch_move_resize_grid(True);
822 sizew_g.x = x;
823 sizew_g.y = y;
826 return;
829 void resize_geometry_window(void)
831 int w;
832 int h;
833 int cset = Scr.DefaultColorset;
835 Scr.SizeStringWidth =
836 FlocaleTextWidth(Scr.DefaultFont, GEOMETRY_WINDOW_STRING,
837 sizeof(GEOMETRY_WINDOW_STRING) - 1);
838 w = Scr.SizeStringWidth + 2 * GEOMETRY_WINDOW_BW;
839 h = Scr.DefaultFont->height + 2 * GEOMETRY_WINDOW_BW;
840 if (w != sizew_g.width || h != sizew_g.height)
842 XResizeWindow(dpy, Scr.SizeWindow, w, h);
843 sizew_g.width = w;
844 sizew_g.height = h;
846 if (cset >= 0)
848 SetWindowBackground(
849 dpy, Scr.SizeWindow, w, h, &Colorset[cset], Pdepth,
850 Scr.StdGC, False);
852 else
854 XSetWindowBackground(dpy, Scr.SizeWindow, Scr.StdBack);
857 return;
862 * Procedure:
863 * DisplayPosition - display the position in the dimensions window
865 * Inputs:
866 * tmp_win - the current fvwm window
867 * x, y - position of the window
871 static void DisplayPosition(
872 const FvwmWindow *tmp_win, const XEvent *eventp, int x, int y,int Init)
874 char str[100];
875 int offset;
876 fscreen_scr_arg fscr;
877 FlocaleWinString fstr;
879 if (Scr.gs.do_hide_position_window)
881 return;
883 position_geometry_window(eventp);
884 /* Translate x,y into local screen coordinates,
885 * in case Xinerama is used. */
886 fscr.xypos.x = x;
887 fscr.xypos.y = y;
888 FScreenTranslateCoordinates(
889 NULL, FSCREEN_GLOBAL, &fscr, FSCREEN_XYPOS, &x, &y);
890 (void)sprintf(str, GEOMETRY_WINDOW_POS_STRING, x, y);
891 if (Init)
893 XClearWindow(dpy, Scr.SizeWindow);
895 else
897 /* just clear indside the relief lines to reduce flicker */
898 XClearArea(dpy, Scr.SizeWindow,
899 GEOMETRY_WINDOW_BW, GEOMETRY_WINDOW_BW,
900 Scr.SizeStringWidth, Scr.DefaultFont->height, False);
903 if (Pdepth >= 2)
905 RelieveRectangle(
906 dpy, Scr.SizeWindow, 0, 0,
907 Scr.SizeStringWidth + GEOMETRY_WINDOW_BW * 2 - 1,
908 Scr.DefaultFont->height + GEOMETRY_WINDOW_BW * 2 - 1,
909 Scr.StdReliefGC, Scr.StdShadowGC, GEOMETRY_WINDOW_BW);
911 offset = (Scr.SizeStringWidth -
912 FlocaleTextWidth(Scr.DefaultFont, str, strlen(str))) / 2;
913 offset += GEOMETRY_WINDOW_BW;
915 memset(&fstr, 0, sizeof(fstr));
916 if (Scr.DefaultColorset >= 0)
918 fstr.colorset = &Colorset[Scr.DefaultColorset];
919 fstr.flags.has_colorset = True;
921 fstr.str = str;
922 fstr.win = Scr.SizeWindow;
923 fstr.gc = Scr.StdGC;
924 fstr.x = offset;
925 fstr.y = Scr.DefaultFont->ascent + GEOMETRY_WINDOW_BW;
926 FlocaleDrawString(dpy, Scr.DefaultFont, &fstr, 0);
928 return;
934 * Procedure:
935 * DisplaySize - display the size in the dimensions window
937 * Inputs:
938 * tmp_win - the current fvwm window
939 * width - the width of the rubber band
940 * height - the height of the rubber band
943 static void DisplaySize(
944 const FvwmWindow *tmp_win, const XEvent *eventp, int width,
945 int height, Bool Init, Bool resetLast)
947 char str[100];
948 int dwidth,dheight,offset;
949 size_borders b;
950 static int last_width = 0;
951 static int last_height = 0;
952 FlocaleWinString fstr;
954 if (Scr.gs.do_hide_resize_window)
956 return;
958 position_geometry_window(eventp);
959 if (resetLast)
961 last_width = 0;
962 last_height = 0;
964 if (last_width == width && last_height == height)
966 return;
968 last_width = width;
969 last_height = height;
971 get_window_borders(tmp_win, &b);
972 dheight = height - b.total_size.height;
973 dwidth = width - b.total_size.width;
974 dwidth -= tmp_win->hints.base_width;
975 dheight -= tmp_win->hints.base_height;
976 dwidth /= tmp_win->hints.width_inc;
977 dheight /= tmp_win->hints.height_inc;
979 (void)sprintf(str, GEOMETRY_WINDOW_SIZE_STRING, dwidth, dheight);
980 if (Init)
982 XClearWindow(dpy,Scr.SizeWindow);
984 else
986 /* just clear indside the relief lines to reduce flicker */
987 XClearArea(
988 dpy, Scr.SizeWindow, GEOMETRY_WINDOW_BW,
989 GEOMETRY_WINDOW_BW, Scr.SizeStringWidth,
990 Scr.DefaultFont->height, False);
993 if (Pdepth >= 2)
995 RelieveRectangle(
996 dpy, Scr.SizeWindow, 0, 0,
997 Scr.SizeStringWidth + GEOMETRY_WINDOW_BW * 2 - 1,
998 Scr.DefaultFont->height + GEOMETRY_WINDOW_BW*2 - 1,
999 Scr.StdReliefGC, Scr.StdShadowGC, GEOMETRY_WINDOW_BW);
1001 offset = (Scr.SizeStringWidth -
1002 FlocaleTextWidth(Scr.DefaultFont, str, strlen(str))) / 2;
1003 offset += GEOMETRY_WINDOW_BW;
1004 memset(&fstr, 0, sizeof(fstr));
1005 if (Scr.DefaultColorset >= 0)
1007 fstr.colorset = &Colorset[Scr.DefaultColorset];
1008 fstr.flags.has_colorset = True;
1010 fstr.str = str;
1011 fstr.win = Scr.SizeWindow;
1012 fstr.gc = Scr.StdGC;
1013 fstr.x = offset;
1014 fstr.y = Scr.DefaultFont->ascent + GEOMETRY_WINDOW_BW;
1015 FlocaleDrawString(dpy, Scr.DefaultFont, &fstr, 0);
1017 return;
1020 static Bool resize_move_window(F_CMD_ARGS)
1022 int FinalX = 0;
1023 int FinalY = 0;
1024 int FinalW = 0;
1025 int FinalH = 0;
1026 int n;
1027 int x,y;
1028 Bool fWarp = False;
1029 Bool fPointer = False;
1030 Bool has_focus;
1031 int dx;
1032 int dy;
1033 size_borders b;
1034 FvwmWindow *fw = exc->w.fw;
1035 Window w = exc->w.w;
1037 if (!is_function_allowed(F_MOVE, NULL, fw, RQORIG_PROGRAM_US, False))
1039 return False;
1041 if (!is_function_allowed(F_RESIZE, NULL, fw, RQORIG_PROGRAM_US, True))
1043 return False;
1046 /* gotta have a window */
1047 w = FW_W_FRAME(fw);
1048 if (!XGetGeometry(
1049 dpy, w, &JunkRoot, &x, &y, (unsigned int*)&FinalW,
1050 (unsigned int*)&FinalH, (unsigned int*)&JunkBW,
1051 (unsigned int*)&JunkDepth))
1053 XBell(dpy, 0);
1054 return False;
1057 FinalX = x;
1058 FinalY = y;
1060 get_window_borders(fw, &b);
1061 n = GetResizeMoveArguments(
1062 &action,
1063 fw->hints.base_width, fw->hints.base_height,
1064 fw->hints.width_inc, fw->hints.height_inc,
1065 &b, &FinalX, &FinalY, &FinalW, &FinalH, &fWarp, &fPointer);
1066 if (n < 4)
1068 return False;
1071 if (IS_MAXIMIZED(fw))
1073 /* must redraw the buttons now so that the 'maximize' button
1074 * does not stay depressed. */
1075 SET_MAXIMIZED(fw, 0);
1076 border_draw_decorations(
1077 fw, PART_BUTTONS, (fw == Scr.Hilite), True, CLEAR_ALL,
1078 NULL, NULL);
1080 dx = FinalX - fw->g.frame.x;
1081 dy = FinalY - fw->g.frame.y;
1082 /* size will be less or equal to requested */
1083 constrain_size(fw, NULL, &FinalW, &FinalH, 0, 0, 0);
1084 if (IS_SHADED(fw))
1086 frame_setup_window(
1087 fw, FinalX, FinalY, FinalW, fw->g.frame.height, False);
1089 else
1091 frame_setup_window(fw, FinalX, FinalY, FinalW, FinalH, True);
1093 if (fWarp)
1095 FWarpPointer(
1096 dpy, None, None, 0, 0, 0, 0, FinalX - x, FinalY - y);
1098 if (IS_MAXIMIZED(fw))
1100 fw->g.max.x += dx;
1101 fw->g.max.y += dy;
1103 else
1105 fw->g.normal.x += dx;
1106 fw->g.normal.y += dy;
1108 has_focus = (fw == get_focus_window())? True : False;
1109 update_absolute_geometry(fw);
1110 maximize_adjust_offset(fw);
1111 XFlush(dpy);
1112 GNOME_SetWinArea(fw);
1114 return True;
1117 void CMD_ResizeMove(F_CMD_ARGS)
1119 FvwmWindow *fw = exc->w.fw;
1121 if (IS_EWMH_FULLSCREEN(fw))
1123 /* do not unmaximize ! */
1124 CMD_ResizeMoveMaximize(F_PASS_ARGS);
1125 return;
1127 resize_move_window(F_PASS_ARGS);
1129 return;
1132 static void InteractiveMove(
1133 Window *win, const exec_context_t *exc, int *FinalX, int *FinalY,
1134 Bool do_start_at_pointer)
1136 int origDragX,origDragY,DragX, DragY, DragWidth, DragHeight;
1137 int XOffset, YOffset;
1138 Window w;
1139 Bool do_move_opaque = False;
1141 w = *win;
1143 if (Scr.bo.do_install_root_cmap)
1145 InstallRootColormap();
1147 else
1149 InstallFvwmColormap();
1151 /* warp the pointer to the cursor position from before menu appeared */
1152 /* domivogt (17-May-1999): an XFlush should not hurt anyway, so do it
1153 * unconditionally to remove the external */
1154 XFlush(dpy);
1156 if (do_start_at_pointer)
1158 if (FQueryPointer(
1159 dpy, Scr.Root, &JunkRoot, &JunkChild, &DragX,
1160 &DragY, &JunkX, &JunkY, &JunkMask) == False)
1162 /* pointer is on a different screen */
1163 DragX = 0;
1164 DragY = 0;
1167 else
1169 /* Although a move is usually done with a button depressed we
1170 * have to check for ButtonRelease too since the event may be
1171 * faked. */
1172 fev_get_evpos_or_query(
1173 dpy, Scr.Root, exc->x.elast, &DragX, &DragY);
1176 MyXGrabServer(dpy);
1177 if (!XGetGeometry(
1178 dpy, w, &JunkRoot, &origDragX, &origDragY,
1179 (unsigned int*)&DragWidth, (unsigned int*)&DragHeight,
1180 (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth))
1182 MyXUngrabServer(dpy);
1183 return;
1185 MyXGrabKeyboard(dpy);
1186 if (do_start_at_pointer)
1188 origDragX = DragX;
1189 origDragY = DragY;
1192 if (IS_ICONIFIED(exc->w.fw))
1194 do_move_opaque = True;
1196 else if (IS_MAPPED(exc->w.fw))
1198 float areapct;
1200 areapct = 100.0;
1201 areapct *= ((float)DragWidth / (float)Scr.MyDisplayWidth);
1202 areapct *= ((float)DragHeight / (float)Scr.MyDisplayHeight);
1203 /* round up */
1204 areapct += 0.1;
1205 if (Scr.OpaqueSize < 0 ||
1206 (float)areapct <= (float)Scr.OpaqueSize)
1208 do_move_opaque = True;
1211 if (do_move_opaque)
1213 MyXUngrabServer(dpy);
1215 else
1217 Scr.flags.is_wire_frame_displayed = True;
1220 if (!do_move_opaque && IS_ICONIFIED(exc->w.fw))
1222 XUnmapWindow(dpy,w);
1225 XOffset = origDragX - DragX;
1226 YOffset = origDragY - DragY;
1227 if (!Scr.gs.do_hide_position_window)
1229 position_geometry_window(NULL);
1230 XMapRaised(dpy,Scr.SizeWindow);
1232 __move_loop(
1233 exc, XOffset, YOffset, DragWidth, DragHeight, FinalX, FinalY,
1234 do_move_opaque, CRS_MOVE);
1235 if (!Scr.gs.do_hide_position_window)
1237 XUnmapWindow(dpy,Scr.SizeWindow);
1239 if (Scr.bo.do_install_root_cmap)
1241 UninstallRootColormap();
1243 else
1245 UninstallFvwmColormap();
1248 if (!do_move_opaque)
1250 /* Throw away some events that dont interest us right now. */
1251 discard_events(EnterWindowMask|LeaveWindowMask);
1252 Scr.flags.is_wire_frame_displayed = False;
1253 MyXUngrabServer(dpy);
1255 MyXUngrabKeyboard(dpy);
1257 return;
1260 /* Perform the movement of the window. ppctMovement *must* have a 1.0 entry
1261 * somewhere in ins list of floats, and movement will stop when it hits a 1.0
1262 * entry */
1263 static void AnimatedMoveAnyWindow(
1264 FvwmWindow *fw, Window w, int startX, int startY, int endX,
1265 int endY, Bool fWarpPointerToo, int cmsDelay, float *ppctMovement,
1266 MenuRepaintTransparentParameters *pmrtp)
1268 int pointerX, pointerY;
1269 int currentX, currentY;
1270 int lastX, lastY;
1271 int deltaX, deltaY;
1272 Bool first = True;
1273 XEvent evdummy;
1274 unsigned int draw_parts = PART_NONE;
1276 if (!is_function_allowed(F_MOVE, NULL, fw, RQORIG_PROGRAM_US, False))
1278 return;
1281 /* set our defaults */
1282 if (ppctMovement == NULL)
1284 ppctMovement = rgpctMovementDefault;
1286 if (cmsDelay < 0)
1288 cmsDelay = cmsDelayDefault;
1291 if (startX < 0 || startY < 0)
1293 if (
1294 !XGetGeometry(
1295 dpy, w, &JunkRoot, &currentX, &currentY,
1296 (unsigned int*)&JunkWidth,
1297 (unsigned int*)&JunkHeight,
1298 (unsigned int*)&JunkBW,
1299 (unsigned int*)&JunkDepth))
1301 XBell(dpy, 0);
1302 return;
1304 if (startX < 0)
1306 startX = currentX;
1308 if (startY < 0)
1310 startY = currentY;
1314 deltaX = endX - startX;
1315 deltaY = endY - startY;
1316 lastX = startX;
1317 lastY = startY;
1319 if (deltaX == 0 && deltaY == 0)
1321 /* go nowhere fast */
1322 return;
1325 if (fw && w == FW_W_FRAME(fw))
1327 draw_parts = border_get_transparent_decorations_part(fw);
1330 /* Needed for aborting */
1331 MyXGrabKeyboard(dpy);
1334 currentX = startX + deltaX * (*ppctMovement);
1335 currentY = startY + deltaY * (*ppctMovement);
1336 if (lastX == currentX && lastY == currentY)
1338 /* don't waste time in the same spot */
1339 continue;
1341 if (pmrtp != NULL)
1343 update_transparent_menu_bg(
1344 pmrtp, lastX, lastY, currentX, currentY,
1345 endX, endY);
1347 XMoveWindow(dpy,w,currentX,currentY);
1348 if (pmrtp != NULL)
1350 repaint_transparent_menu(
1351 pmrtp, first,
1352 currentX, currentY, endX, endY, True);
1354 else if (draw_parts != PART_NONE)
1356 border_draw_decorations(
1357 fw, draw_parts,
1358 ((fw == get_focus_window())) ?
1359 True : False,
1360 True, CLEAR_ALL, NULL, NULL);
1362 if (fw && pmrtp == NULL && IS_TEAR_OFF_MENU(fw))
1364 menu_redraw_transparent_tear_off_menu(fw, False);
1366 if (fWarpPointerToo == True)
1368 if (FQueryPointer(
1369 dpy, Scr.Root, &JunkRoot, &JunkChild,
1370 &JunkX, &JunkY, &pointerX, &pointerY,
1371 &JunkMask) == False)
1373 /* pointer is on a different screen */
1374 pointerX = currentX;
1375 pointerY = currentY;
1377 else
1379 pointerX += currentX - lastX;
1380 pointerY += currentY - lastY;
1382 FWarpPointer(
1383 dpy, None, Scr.Root, 0, 0, 0, 0, pointerX,
1384 pointerY);
1386 if (fw && !IS_SHADED(fw) && !Scr.bo.do_disable_configure_notify)
1388 /* send configure notify event for windows that care
1389 * about their location */
1390 SendConfigureNotify(
1391 fw, currentX, currentY,
1392 fw->g.frame.width,
1393 fw->g.frame.height, 0, False);
1394 #ifdef FVWM_DEBUG_MSGS
1395 fvwm_msg(DBG,"AnimatedMoveAnyWindow",
1396 "Sent ConfigureNotify (w == %d, h == %d)",
1397 fw->g.frame.width,
1398 fw->g.frame.height);
1399 #endif
1401 XFlush(dpy);
1402 if (fw)
1404 fw->g.frame.x = currentX;
1405 fw->g.frame.y = currentY;
1406 update_absolute_geometry(fw);
1407 maximize_adjust_offset(fw);
1408 BroadcastConfig(M_CONFIGURE_WINDOW, fw);
1409 FlushAllMessageQueues();
1412 usleep(cmsDelay * 1000); /* usleep takes microseconds */
1413 /* this didn't work for me -- maybe no longer necessary since
1414 * we warn the user when they use > .5 seconds as a
1415 * between-frame delay time.
1417 * domivogt (28-apr-1999): That is because the keyboard was not
1418 * grabbed. works nicely now.
1420 if (FCheckMaskEvent(
1421 dpy, ButtonPressMask|ButtonReleaseMask|KeyPressMask,
1422 &evdummy))
1424 /* finish the move immediately */
1425 if (pmrtp != NULL)
1427 update_transparent_menu_bg(
1428 pmrtp, lastX, lastY,
1429 currentX, currentY, endX, endY);
1431 XMoveWindow(dpy,w,endX,endY);
1432 if (pmrtp != NULL)
1434 repaint_transparent_menu(
1435 pmrtp, first,
1436 endX, endY, endX, endY, True);
1438 break;
1440 lastX = currentX;
1441 lastY = currentY;
1442 first = False;
1443 } while (*ppctMovement != 1.0 && ppctMovement++);
1444 MyXUngrabKeyboard(dpy);
1445 XFlush(dpy);
1446 if (fw)
1448 GNOME_SetWinArea(fw);
1451 return;
1454 /* used for moving menus, not a client window */
1455 void AnimatedMoveOfWindow(
1456 Window w, int startX, int startY, int endX, int endY,
1457 Bool fWarpPointerToo, int cmsDelay, float *ppctMovement,
1458 MenuRepaintTransparentParameters *pmrtp)
1460 AnimatedMoveAnyWindow(
1461 NULL, w, startX, startY, endX, endY, fWarpPointerToo,
1462 cmsDelay, ppctMovement, pmrtp);
1464 return;
1467 /* used for moving client windows */
1468 void AnimatedMoveFvwmWindow(
1469 FvwmWindow *fw, Window w, int startX, int startY, int endX,
1470 int endY, Bool fWarpPointerToo, int cmsDelay, float *ppctMovement)
1472 AnimatedMoveAnyWindow(
1473 fw, w, startX, startY, endX, endY, fWarpPointerToo,
1474 cmsDelay, ppctMovement, NULL);
1476 return;
1479 int placement_binding(int button, KeySym keysym, int modifier, char *action)
1481 if (keysym != 0)
1483 /* fixme */
1484 fvwm_msg(
1485 ERR, "placement_binding",
1486 "sorry, placement keybindings not allowed. yet.");
1487 return 1;
1489 if (modifier != 0)
1491 /* fixme */
1492 fvwm_msg(
1493 ERR, "placement_binding",
1494 "sorry, placement binding modifiers not allowed. yet.");
1495 return 1;
1497 if (strcmp(action,"-") == 0 ||
1498 strcasecmp(action,"CancelPlacement") == 0)
1500 if (keysym == 0) /* must be button binding */
1502 if (button == 0)
1504 move_drag_finish_button_mask = 0;
1505 move_interactive_finish_button_mask = 0;
1507 else if (button > 0 && button <=
1508 NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
1510 move_drag_finish_button_mask &=
1511 ~(1<<(button-1));
1512 move_interactive_finish_button_mask &=
1513 ~(1<<(button-1));
1517 else if (strcasecmp(action,"CancelPlacementDrag") == 0)
1519 if (keysym == 0) /* must be button binding */
1521 if (button == 0)
1523 move_drag_finish_button_mask = 0;
1525 else if (button > 0 && button <=
1526 NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
1528 move_drag_finish_button_mask &=
1529 ~(1<<(button-1));
1533 else if (strcasecmp(action,"CancelPlacementInteractive") == 0)
1535 if (keysym == 0) /* must be button binding */
1537 if (button == 0)
1539 move_interactive_finish_button_mask = 0;
1541 else if (button > 0 && button <=
1542 NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
1544 move_interactive_finish_button_mask &=
1545 ~(1<<(button-1));
1549 else if (strcasecmp(action,"PlaceWindow") == 0)
1551 if (keysym == 0) /* must be button binding */
1553 if (button == 0)
1555 move_interactive_finish_button_mask =
1556 move_drag_finish_button_mask =
1557 (1<<NUMBER_OF_EXTENDED_MOUSE_BUTTONS)-1;
1559 else if (button > 0 && button <=
1560 NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
1562 move_drag_finish_button_mask |= (1<<(button-1));
1563 move_interactive_finish_button_mask |=
1564 (1<<(button-1));
1568 else if (strcasecmp(action,"PlaceWindowDrag") == 0)
1570 if (keysym == 0) /* must be button binding */
1572 if (button == 0)
1574 move_drag_finish_button_mask =
1575 (1<<NUMBER_OF_EXTENDED_MOUSE_BUTTONS)-1;
1577 else if (button > 0 && button <=
1578 NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
1580 move_drag_finish_button_mask |= (1<<(button-1));
1584 else if (strcasecmp(action,"PlaceWindowInteractive") == 0)
1586 if (keysym == 0) /* must be button binding */
1588 if (button == 0)
1590 move_interactive_finish_button_mask =
1591 (1<<NUMBER_OF_EXTENDED_MOUSE_BUTTONS)-1;
1593 else if (button > 0 && button <=
1594 NUMBER_OF_EXTENDED_MOUSE_BUTTONS)
1596 move_interactive_finish_button_mask |=
1597 (1<<(button-1));
1601 else
1603 fvwm_msg(
1604 ERR, "placement_binding",
1605 "invalid action %s", action);
1608 return 0;
1614 * Start a window move operation
1617 void __move_icon(
1618 FvwmWindow *fw, int x, int y, int old_x, int old_y,
1619 Bool do_move_animated, Bool do_warp_pointer)
1621 rectangle gt;
1622 rectangle gp;
1623 Bool has_icon_title;
1624 Bool has_icon_picture;
1625 Window tw;
1626 int tx;
1627 int ty;
1629 set_icon_position(fw, x, y);
1630 broadcast_icon_geometry(fw, False);
1631 has_icon_title = get_visible_icon_title_geometry(fw, &gt);
1632 has_icon_picture = get_visible_icon_picture_geometry(fw, &gp);
1633 if (has_icon_picture)
1635 tw = FW_W_ICON_PIXMAP(fw);
1636 tx = gp.x;
1637 ty = gp.y;
1639 else if (has_icon_title)
1641 tw = FW_W_ICON_TITLE(fw);
1642 tx = gt.x;
1643 ty = gt.y;
1645 else
1647 return;
1649 if (do_move_animated)
1651 AnimatedMoveOfWindow(
1652 tw, -1, -1, tx, ty, do_warp_pointer, -1, NULL, NULL);
1653 do_warp_pointer = 0;
1655 if (has_icon_title)
1657 XMoveWindow(dpy, FW_W_ICON_TITLE(fw), gt.x, gt.y);
1659 if (has_icon_picture)
1661 XMoveWindow(dpy, FW_W_ICON_PIXMAP(fw), gp.x, gp.y);
1662 if (fw->Desk == Scr.CurrentDesk)
1664 XMapWindow(dpy, FW_W_ICON_PIXMAP(fw));
1665 if (has_icon_title)
1667 XMapWindow(dpy, FW_W_ICON_TITLE(fw));
1671 if (do_warp_pointer)
1673 FWarpPointer(dpy, None, None, 0, 0, 0, 0, x - old_x, y - old_y);
1676 return;
1679 static void __move_window(F_CMD_ARGS, Bool do_animate, int mode)
1681 int FinalX = 0;
1682 int FinalY = 0;
1683 int n;
1684 int x;
1685 int y;
1686 int width, height;
1687 int page_x, page_y;
1688 Bool fWarp = False;
1689 Bool fPointer = False;
1690 int dx;
1691 int dy;
1692 FvwmWindow *fw = exc->w.fw;
1693 Window w;
1695 if (!is_function_allowed(F_MOVE, NULL, fw, RQORIG_PROGRAM_US, False))
1697 return;
1699 /* gotta have a window */
1700 w = FW_W_FRAME(fw);
1701 if (IS_ICONIFIED(fw))
1703 if (FW_W_ICON_PIXMAP(fw) != None)
1705 w = FW_W_ICON_PIXMAP(fw);
1706 XUnmapWindow(dpy,FW_W_ICON_TITLE(fw));
1708 else
1710 w = FW_W_ICON_TITLE(fw);
1712 if (w == None && (mode == MOVE_PAGE || mode == MOVE_SCREEN))
1714 w = FW_W_FRAME(fw);
1717 if (
1718 !XGetGeometry(
1719 dpy, w, &JunkRoot, &x, &y, (unsigned int*)&width,
1720 (unsigned int*)&height, (unsigned int*)&JunkBW,
1721 (unsigned int*)&JunkDepth))
1723 return;
1725 if (mode == MOVE_PAGE && IS_STICKY_ACROSS_PAGES(fw))
1727 return;
1729 if (mode == MOVE_PAGE)
1731 rectangle r;
1732 rectangle s;
1733 rectangle t;
1735 do_animate = False;
1736 r.x = x;
1737 r.y = y;
1738 r.width = width;
1739 r.height = height;
1740 get_absolute_geometry(&t, &r);
1741 get_page_offset_rectangle(&page_x, &page_y, &t);
1742 if (!get_page_arguments(action, &page_x, &page_y))
1744 page_x = Scr.Vx;
1745 page_y = Scr.Vy;
1747 s.x = page_x - Scr.Vx;
1748 s.y = page_y - Scr.Vy;
1749 s.width = Scr.MyDisplayWidth;
1750 s.height = Scr.MyDisplayHeight;
1751 fvwmrect_move_into_rectangle(&r, &s);
1752 FinalX = r.x;
1753 FinalY = r.y;
1755 else if (mode == MOVE_SCREEN)
1757 rectangle r;
1758 rectangle s;
1759 rectangle p;
1760 int fscreen;
1762 do_animate = False;
1763 fscreen = FScreenGetScreenArgument(
1764 action, FSCREEN_SPEC_CURRENT);
1765 FScreenGetScrRect(
1766 NULL, fscreen, &s.x, &s.y, &s.width, &s.height);
1767 page_x = Scr.Vx;
1768 page_y = Scr.Vy;
1769 r.x = x;
1770 r.y = y;
1771 r.width = width;
1772 r.height = height;
1773 p.x = page_x - Scr.Vx;
1774 p.y = page_y - Scr.Vy;
1775 p.width = Scr.MyDisplayWidth;
1776 p.height = Scr.MyDisplayHeight;
1777 /* move to page first */
1778 fvwmrect_move_into_rectangle(&r, &p);
1779 /* then move to screen */
1780 fvwmrect_move_into_rectangle(&r, &s);
1781 FinalX = r.x;
1782 FinalY = r.y;
1784 else
1786 FinalX = x;
1787 FinalY = y;
1788 n = GetMoveArguments(
1789 &action, width, height, &FinalX, &FinalY, &fWarp,
1790 &fPointer, True);
1792 if (n != 2 || fPointer)
1794 InteractiveMove(&w, exc, &FinalX, &FinalY, fPointer);
1796 else if (IS_ICONIFIED(fw))
1798 SET_ICON_MOVED(fw, 1);
1802 if (w == FW_W_FRAME(fw))
1804 dx = FinalX - fw->g.frame.x;
1805 dy = FinalY - fw->g.frame.y;
1806 if (do_animate)
1808 AnimatedMoveFvwmWindow(
1809 fw, w, -1, -1, FinalX, FinalY, fWarp, -1,
1810 NULL);
1812 frame_setup_window(
1813 fw, FinalX, FinalY, fw->g.frame.width,
1814 fw->g.frame.height, True);
1815 if (fWarp & !do_animate)
1817 FWarpPointer(
1818 dpy, None, None, 0, 0, 0, 0, FinalX - x,
1819 FinalY - y);
1821 if (IS_MAXIMIZED(fw))
1823 fw->g.max.x += dx;
1824 fw->g.max.y += dy;
1826 else
1828 fw->g.normal.x += dx;
1829 fw->g.normal.y += dy;
1831 update_absolute_geometry(fw);
1832 maximize_adjust_offset(fw);
1833 XFlush(dpy);
1834 GNOME_SetWinArea(fw);
1836 else /* icon window */
1838 __move_icon(fw, FinalX, FinalY, x, y, do_animate, fWarp);
1839 XFlush(dpy);
1841 focus_grab_buttons_on_layer(fw->layer);
1843 return;
1846 void CMD_Move(F_CMD_ARGS)
1848 __move_window(F_PASS_ARGS, False, MOVE_NORMAL);
1850 return;
1853 void CMD_AnimatedMove(F_CMD_ARGS)
1855 __move_window(F_PASS_ARGS, True, MOVE_NORMAL);
1857 return;
1860 void CMD_MoveToPage(F_CMD_ARGS)
1862 __move_window(F_PASS_ARGS, False, MOVE_PAGE);
1864 return;
1867 void CMD_MoveToScreen(F_CMD_ARGS)
1869 __move_window(F_PASS_ARGS, False, MOVE_SCREEN);
1871 return;
1874 /* This function does the SnapAttraction stuff. It takes x and y coordinates
1875 * (*px and *py) and returns the snapped values. */
1876 static void DoSnapAttract(
1877 FvwmWindow *fw, int Width, int Height, int *px, int *py)
1879 int nyt,nxl,dist,closestLeft,closestRight,closestBottom,closestTop;
1880 rectangle self;
1882 /* resist based on window edges */
1883 closestTop = fw->snap_attraction.proximity;
1884 closestBottom = fw->snap_attraction.proximity;
1885 closestRight = fw->snap_attraction.proximity;
1886 closestLeft = fw->snap_attraction.proximity;
1887 nxl = -99999;
1888 nyt = -99999;
1889 self.x = *px;
1890 self.y = *py;
1891 self.width = Width;
1892 self.height = Height;
1894 rectangle g;
1895 Bool rc;
1897 rc = get_visible_icon_title_geometry(fw, &g);
1898 if (rc == True)
1900 self.height += g.height;
1905 * Snap grid handling
1907 if (fw->snap_grid_x > 1 && nxl == -99999)
1909 if (*px != *px / fw->snap_grid_x * fw->snap_grid_x)
1911 *px = (*px + ((*px >= 0) ?
1912 fw->snap_grid_x : -fw->snap_grid_x) /
1913 2) / fw->snap_grid_x * fw->snap_grid_x;
1916 if (fw->snap_grid_y > 1 && nyt == -99999)
1918 if (*py != *py / fw->snap_grid_y * fw->snap_grid_y)
1920 *py = (*py + ((*py >= 0) ?
1921 fw->snap_grid_y : -fw->snap_grid_y) /
1922 2) / fw->snap_grid_y * fw->snap_grid_y;
1927 * snap attraction
1929 /* snap to other windows or icons*/
1930 if (fw->snap_attraction.proximity > 0 &&
1931 (fw->snap_attraction.mode & (SNAP_ICONS | SNAP_WINDOWS | SNAP_SAME)))
1933 FvwmWindow *tmp;
1934 int maskout = (SNAP_SCREEN | SNAP_SCREEN_WINDOWS |
1935 SNAP_SCREEN_ICONS | SNAP_SCREEN_ALL);
1937 for (tmp = Scr.FvwmRoot.next; tmp; tmp = tmp->next)
1939 rectangle other;
1941 if (fw->Desk != tmp->Desk || fw == tmp)
1943 continue;
1945 /* check snapping type */
1946 switch (fw->snap_attraction.mode & ~(maskout))
1948 case SNAP_WINDOWS: /* we only snap windows */
1949 if (IS_ICONIFIED(tmp) || IS_ICONIFIED(fw))
1951 continue;
1953 break;
1954 case SNAP_ICONS: /* we only snap icons */
1955 if (!IS_ICONIFIED(tmp) || !IS_ICONIFIED(fw))
1957 continue;
1959 break;
1960 case SNAP_SAME: /* we don't snap unequal */
1961 if (IS_ICONIFIED(tmp) != IS_ICONIFIED(fw))
1963 continue;
1965 break;
1966 default: /* All */
1967 /* NOOP */
1968 break;
1970 /* get other window dimensions */
1971 get_visible_window_or_icon_geometry(tmp, &other);
1972 /* prevent that window snaps off screen */
1973 if (other.x <= 0)
1975 other.x -= fw->snap_attraction.proximity + 10000;
1976 other.width += fw->snap_attraction.proximity + 10000;
1978 if (other.y <= 0)
1980 other.y -= fw->snap_attraction.proximity + 10000;
1981 other.height += fw->snap_attraction.proximity + 10000;
1983 if (other.x + other.width >= Scr.MyDisplayWidth)
1985 other.width += fw->snap_attraction.proximity + 10000;
1987 if (other.y + other.height >= Scr.MyDisplayHeight)
1989 other.height += fw->snap_attraction.proximity + 10000;
1992 /* snap horizontally */
1993 if (
1994 other.y + other.height > *py &&
1995 other.y < *py + self.height)
1997 dist = abs(other.x - (*px + self.width));
1998 if (dist < closestRight)
2000 closestRight = dist;
2001 if (*px + self.width >= other.x &&
2002 *px + self.width <
2003 other.x + fw->snap_attraction.proximity)
2005 nxl = other.x - self.width;
2007 if (*px + self.width >=
2008 other.x - fw->snap_attraction.proximity &&
2009 *px + self.width < other.x)
2011 nxl = other.x - self.width;
2014 dist = abs(other.x + other.width - *px);
2015 if (dist < closestLeft)
2017 closestLeft = dist;
2018 if (*px <= other.x + other.width &&
2019 *px > other.x + other.width -
2020 fw->snap_attraction.proximity)
2022 nxl = other.x + other.width;
2024 if (*px <= other.x + other.width +
2025 fw->snap_attraction.proximity &&
2026 *px > other.x + other.width)
2028 nxl = other.x + other.width;
2032 /* snap vertically */
2033 if (
2034 other.x + other.width > *px &&
2035 other.x < *px + self.width)
2037 dist = abs(other.y - (*py + self.height));
2038 if (dist < closestBottom)
2040 closestBottom = dist;
2041 if (*py + self.height >= other.y &&
2042 *py + self.height < other.y +
2043 fw->snap_attraction.proximity)
2045 nyt = other.y - self.height;
2047 if (*py + self.height >=
2048 other.y - fw->snap_attraction.proximity &&
2049 *py + self.height < other.y)
2051 nyt = other.y - self.height;
2054 dist = abs(other.y + other.height - *py);
2055 if (dist < closestTop)
2057 closestTop = dist;
2058 if (*py <=
2059 other.y + other.height &&
2060 *py > other.y + other.height -
2061 fw->snap_attraction.proximity)
2063 nyt = other.y + other.height;
2065 if (*py <= other.y + other.height +
2066 fw->snap_attraction.proximity &&
2067 *py > other.y + other.height)
2069 nyt = other.y + other.height;
2073 } /* for */
2074 } /* snap to other windows */
2076 /* snap to screen egdes */
2077 if (fw->snap_attraction.proximity > 0 && (
2078 ( fw->snap_attraction.mode & SNAP_SCREEN && (
2079 fw->snap_attraction.mode & SNAP_SAME ||
2080 ( IS_ICONIFIED(fw) &&
2081 fw->snap_attraction.mode & SNAP_ICONS ) ||
2082 ( !IS_ICONIFIED(fw) &&
2083 fw->snap_attraction.mode & SNAP_WINDOWS ))) ||
2084 ( !IS_ICONIFIED(fw) &&
2085 fw->snap_attraction.mode & SNAP_SCREEN_WINDOWS ) ||
2086 ( IS_ICONIFIED(fw) &&
2087 fw->snap_attraction.mode & SNAP_SCREEN_ICONS ) ||
2088 fw->snap_attraction.mode & SNAP_SCREEN_ALL ))
2090 /* horizontally */
2091 if (!(Scr.MyDisplayWidth < (*px) ||
2092 (*px + self.width) < 0))
2094 dist = abs(Scr.MyDisplayHeight - (*py + self.height));
2095 if (dist < closestBottom)
2097 closestBottom = dist;
2098 if (*py + self.height >=
2099 Scr.MyDisplayHeight &&
2100 *py + self.height <
2101 Scr.MyDisplayHeight + fw->snap_attraction.proximity)
2103 nyt = Scr.MyDisplayHeight -
2104 self.height;
2106 if (*py + self.height >=
2107 Scr.MyDisplayHeight - fw->snap_attraction.proximity &&
2108 *py + self.height < Scr.MyDisplayHeight)
2110 nyt = Scr.MyDisplayHeight -
2111 self.height;
2114 dist = abs(*py);
2115 if (dist < closestTop)
2117 closestTop = dist;
2118 if ((*py <= 0)&&(*py > - fw->snap_attraction.proximity))
2120 nyt = 0;
2122 if ((*py <= fw->snap_attraction.proximity)&&(*py > 0))
2124 nyt = 0;
2127 } /* horizontally */
2128 /* vertically */
2129 if (!(Scr.MyDisplayHeight < (*py) ||
2130 (*py + self.height) < 0))
2132 dist = abs(
2133 Scr.MyDisplayWidth - (*px + self.width));
2134 if (dist < closestRight)
2136 closestRight = dist;
2138 if (*px + self.width >= Scr.MyDisplayWidth &&
2139 *px + self.width <
2140 Scr.MyDisplayWidth + fw->snap_attraction.proximity)
2142 nxl = Scr.MyDisplayWidth - self.width;
2145 if (*px + self.width >=
2146 Scr.MyDisplayWidth - fw->snap_attraction.proximity &&
2147 *px + self.width < Scr.MyDisplayWidth)
2149 nxl = Scr.MyDisplayWidth - self.width;
2152 dist = abs(*px);
2153 if (dist < closestLeft)
2155 closestLeft = dist;
2157 if ((*px <= 0) &&
2158 (*px > - fw->snap_attraction.proximity))
2160 nxl = 0;
2162 if ((*px <= fw->snap_attraction.proximity) &&
2163 (*px > 0))
2165 nxl = 0;
2168 } /* vertically */
2169 } /* snap to screen edges */
2171 if (nxl != -99999)
2173 *px = nxl;
2175 if (nyt != -99999)
2177 *py = nyt;
2181 * Resist moving windows beyond the edge of the screen
2183 if (fw->edge_resistance_move > 0)
2185 /* snap to right edge */
2186 if (
2187 *px + Width >= Scr.MyDisplayWidth &&
2188 *px + Width < Scr.MyDisplayWidth +
2189 fw->edge_resistance_move)
2191 *px = Scr.MyDisplayWidth - Width;
2193 /* snap to left edge */
2194 else if ((*px <= 0) && (*px > -fw->edge_resistance_move))
2196 *px = 0;
2198 /* snap to bottom edge */
2199 if (
2200 *py + Height >= Scr.MyDisplayHeight &&
2201 *py + Height < Scr.MyDisplayHeight +
2202 fw->edge_resistance_move)
2204 *py = Scr.MyDisplayHeight - Height;
2206 /* snap to top edge */
2207 else if (*py <= 0 && *py > -fw->edge_resistance_move)
2209 *py = 0;
2212 /* Resist moving windows between xineramascreens */
2213 if (fw->edge_resistance_xinerama_move > 0 && FScreenIsEnabled())
2215 int scr_x0, scr_y0;
2216 int scr_x1, scr_y1;
2217 Bool do_recalc_rectangle = False;
2219 FScreenGetResistanceRect(
2220 *px, *py, Width, Height, &scr_x0, &scr_y0, &scr_x1,
2221 &scr_y1);
2223 /* snap to right edge */
2224 if (scr_x1 < Scr.MyDisplayWidth &&
2225 *px + Width >= scr_x1 && *px + Width <
2226 scr_x1 + fw->edge_resistance_xinerama_move)
2228 *px = scr_x1 - Width;
2229 do_recalc_rectangle = True;
2231 /* snap to left edge */
2232 else if (
2233 scr_x0 > 0 &&
2234 *px <= scr_x0 && scr_x0 - *px <
2235 fw->edge_resistance_xinerama_move)
2237 *px = scr_x0;
2238 do_recalc_rectangle = True;
2240 if (do_recalc_rectangle)
2242 /* Snapping in X direction can move the window off a
2243 * screen. Thus, it may no longer be necessary to snap
2244 * in Y direction. */
2245 FScreenGetResistanceRect(
2246 *px, *py, Width, Height, &scr_x0, &scr_y0,
2247 &scr_x1, &scr_y1);
2249 /* snap to bottom edge */
2250 if (scr_y1 < Scr.MyDisplayHeight &&
2251 *py + Height >= scr_y1 && *py + Height <
2252 scr_y1 + fw->edge_resistance_xinerama_move)
2254 *py = scr_y1 - Height;
2256 /* snap to top edge */
2257 else if (
2258 scr_y0 > 0 &&
2259 *py <= scr_y0 && scr_y0 - *py <
2260 fw->edge_resistance_xinerama_move)
2262 *py = scr_y0;
2266 return;
2271 * Move the rubberband around, return with the new window location
2273 * Returns True if the window has to be resized after the move.
2276 Bool __move_loop(
2277 const exec_context_t *exc, int XOffset, int YOffset, int Width,
2278 int Height, int *FinalX, int *FinalY, Bool do_move_opaque, int cursor)
2280 extern Window bad_window;
2281 Bool is_finished = False;
2282 Bool is_aborted = False;
2283 int xl,xl2,yt,yt2,delta_x,delta_y,paged;
2284 unsigned int button_mask = 0;
2285 FvwmWindow fw_copy;
2286 int dx = Scr.EdgeScrollX ? Scr.EdgeScrollX : Scr.MyDisplayWidth;
2287 int dy = Scr.EdgeScrollY ? Scr.EdgeScrollY : Scr.MyDisplayHeight;
2288 const int vx = Scr.Vx;
2289 const int vy = Scr.Vy;
2290 int xl_orig = 0;
2291 int yt_orig = 0;
2292 int cnx = 0;
2293 int cny = 0;
2294 int x_virtual_offset = 0;
2295 int y_virtual_offset = 0;
2296 Bool sent_cn = False;
2297 Bool do_resize_too = False;
2298 int x_bak;
2299 int y_bak;
2300 Window move_w = None;
2301 int orig_icon_x = 0;
2302 int orig_icon_y = 0;
2303 Bool do_snap = True;
2304 Bool was_snapped = False;
2305 /* if Alt is initially pressed don't enable no-snap until Alt is
2306 * released */
2307 Bool nosnap_enabled = False;
2308 /* Must not set placed by button if the event is a modified KeyEvent */
2309 Bool is_fake_event;
2310 FvwmWindow *fw = exc->w.fw;
2311 unsigned int draw_parts = PART_NONE;
2312 XEvent e;
2314 if (!GrabEm(cursor, GRAB_NORMAL))
2316 XBell(dpy, 0);
2317 return False;
2319 if (!IS_MAPPED(fw) && !IS_ICONIFIED(fw))
2321 do_move_opaque = False;
2323 bad_window = None;
2324 if (IS_ICONIFIED(fw))
2326 if (FW_W_ICON_PIXMAP(fw) != None)
2328 move_w = FW_W_ICON_PIXMAP(fw);
2330 else if (FW_W_ICON_TITLE(fw) != None)
2332 move_w = FW_W_ICON_TITLE(fw);
2335 else
2337 move_w = FW_W_FRAME(fw);
2339 if (
2340 !XGetGeometry(
2341 dpy, move_w, &JunkRoot, &x_bak, &y_bak,
2342 (unsigned int*)&JunkWidth, (unsigned int*)&JunkHeight,
2343 (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth))
2345 /* This is allright here since the window may not be mapped
2346 * yet. */
2349 if (IS_ICONIFIED(fw))
2351 rectangle g;
2353 get_visible_icon_geometry(fw, &g);
2354 orig_icon_x = g.x;
2355 orig_icon_y = g.y;
2358 /* make a copy of the fw structure for sending to the pager */
2359 memcpy(&fw_copy, fw, sizeof(FvwmWindow));
2360 /* prevent flicker when paging */
2361 SET_WINDOW_BEING_MOVED_OPAQUE(fw, do_move_opaque);
2363 if (FQueryPointer(
2364 dpy, Scr.Root, &JunkRoot, &JunkChild, &xl, &yt,
2365 &JunkX, &JunkY, &button_mask) == False)
2367 /* pointer is on a different screen */
2368 xl = 0;
2369 yt = 0;
2371 else
2373 xl += XOffset;
2374 yt += YOffset;
2376 button_mask &= DEFAULT_ALL_BUTTONS_MASK;
2377 xl_orig = xl;
2378 yt_orig = yt;
2380 /* draw initial outline */
2381 if (!IS_ICONIFIED(fw) &&
2382 ((!do_move_opaque && !Scr.gs.do_emulate_mwm) || !IS_MAPPED(fw)))
2384 draw_move_resize_grid(xl, yt, Width - 1, Height - 1);
2387 if (move_w == FW_W_FRAME(fw) && do_move_opaque)
2389 draw_parts = border_get_transparent_decorations_part(fw);
2391 DisplayPosition(fw, exc->x.elast, xl, yt, True);
2393 memset(&e, 0, sizeof(e));
2395 /* Unset the placed by button mask.
2396 * If the move is canceled this will remain as zero.
2398 fw->placed_by_button = 0;
2399 while (!is_finished && bad_window != FW_W(fw))
2401 int rc = 0;
2402 int old_xl;
2403 int old_yt;
2405 old_xl = xl;
2406 old_yt = yt;
2407 /* wait until there is an interesting event */
2408 while (rc != -1 &&
2409 (!FPending(dpy) ||
2410 !FCheckMaskEvent(
2411 dpy, ButtonPressMask | ButtonReleaseMask |
2412 KeyPressMask | PointerMotionMask |
2413 ButtonMotionMask | ExposureMask, &e)))
2415 XEvent le;
2417 fev_get_last_event(&le);
2419 xl -= XOffset;
2420 yt -= YOffset;
2422 rc = HandlePaging(
2423 &le, dx, dy, &xl, &yt, &delta_x, &delta_y,
2424 False, False, True, fw->edge_delay_ms_move);
2426 /* Fake an event to force window reposition */
2427 if (delta_x)
2429 x_virtual_offset = 0;
2431 xl += XOffset;
2432 if (delta_y)
2434 y_virtual_offset = 0;
2436 yt += YOffset;
2437 if (do_snap)
2439 DoSnapAttract(
2440 fw, Width, Height, &xl, &yt);
2441 was_snapped = True;
2443 fev_make_null_event(&e, dpy);
2444 e.type = MotionNotify;
2445 e.xmotion.time = fev_get_evtime();
2446 e.xmotion.x_root = xl - XOffset;
2447 e.xmotion.y_root = yt - YOffset;
2448 e.xmotion.same_screen = True;
2449 break;
2451 if (rc == -1)
2453 /* block until an event arrives */
2454 /* dv (2004-07-01): With XFree 4.1.0.1, some Mouse
2455 * events are not reported to fvwm when the pointer
2456 * moves very fast and suddenly stops in the corner of
2457 * the screen. Handle EnterNotify/LeaveNotify events
2458 * too to get an idea where the pointer might be. */
2459 FMaskEvent(
2460 dpy, ButtonPressMask | ButtonReleaseMask |
2461 KeyPressMask | PointerMotionMask |
2462 ButtonMotionMask | ExposureMask |
2463 EnterWindowMask | LeaveWindowMask, &e);
2466 /* discard extra events before a logical release */
2467 if (e.type == MotionNotify ||
2468 e.type == EnterNotify || e.type == LeaveNotify)
2470 while (FPending(dpy) > 0 &&
2471 FCheckMaskEvent(
2472 dpy, ButtonMotionMask |
2473 PointerMotionMask | ButtonPressMask |
2474 ButtonRelease | KeyPressMask |
2475 EnterWindowMask | LeaveWindowMask, &e))
2477 if (e.type == ButtonPress ||
2478 e.type == ButtonRelease ||
2479 e.type == KeyPress)
2481 break;
2485 if (e.type == EnterNotify || e.type == LeaveNotify)
2487 XEvent e2;
2488 int x;
2489 int y;
2491 /* Query the pointer to catch the latest information.
2492 * This *is* necessary. */
2493 if (FQueryPointer(
2494 dpy, Scr.Root, &JunkRoot, &JunkChild, &x,
2495 &y, &JunkX, &JunkY, &JunkMask) == True)
2497 fev_make_null_event(&e2, dpy);
2498 e2.type = MotionNotify;
2499 e2.xmotion.time = fev_get_evtime();
2500 e2.xmotion.x_root = x;
2501 e2.xmotion.y_root = y;
2502 e2.xmotion.state = JunkMask;
2503 e2.xmotion.same_screen = True;
2504 e = e2;
2505 fev_fake_event(&e);
2507 else
2509 /* pointer is on a different screen,
2510 * ignore event */
2513 is_fake_event = False;
2514 /* Handle a limited number of key press events to allow
2515 * mouseless operation */
2516 if (e.type == KeyPress)
2518 Keyboard_shortcuts(
2519 &e, fw, &x_virtual_offset,
2520 &y_virtual_offset, ButtonRelease);
2522 is_fake_event = (e.type != KeyPress);
2524 switch (e.type)
2526 case KeyPress:
2527 if (!(e.xkey.state & Mod1Mask))
2529 nosnap_enabled = True;
2531 do_snap = nosnap_enabled &&
2532 (e.xkey.state & Mod1Mask) ? False : True;
2534 /* simple code to bag out of move - CKH */
2535 if (XLookupKeysym(&(e.xkey), 0) == XK_Escape)
2537 if (!do_move_opaque)
2539 switch_move_resize_grid(False);
2541 if (!IS_ICONIFIED(fw))
2543 if (do_move_opaque)
2545 *FinalX = fw->g.frame.x;
2546 *FinalY = fw->g.frame.y;
2549 else
2551 *FinalX = orig_icon_x;
2552 *FinalY = orig_icon_y;
2554 is_aborted = True;
2555 is_finished = True;
2557 break;
2558 case ButtonPress:
2559 if (e.xbutton.button <= NUMBER_OF_MOUSE_BUTTONS &&
2560 ((Button1Mask << (e.xbutton.button - 1)) &
2561 button_mask))
2563 /* No new button was pressed, just a delayed
2564 * event */
2565 break;
2567 if (!IS_MAPPED(fw) &&
2568 ((e.xbutton.button == 2 && !Scr.gs.do_emulate_mwm)
2570 (e.xbutton.button == 1 && Scr.gs.do_emulate_mwm &&
2571 (e.xbutton.state & ShiftMask))))
2573 do_resize_too = True;
2574 /* Fallthrough to button-release */
2576 else if (!button_mask && e.xbutton.button <=
2577 NUMBER_OF_EXTENDED_MOUSE_BUTTONS &&
2578 e.xbutton.button > 0 &&
2579 (move_interactive_finish_button_mask &
2580 (1<<(e.xbutton.button-1))))
2582 do_resize_too = False;
2583 break;
2585 else if (button_mask && e.xbutton.button <=
2586 NUMBER_OF_EXTENDED_MOUSE_BUTTONS &&
2587 e.xbutton.button > 0 &&
2588 (move_drag_finish_button_mask &
2589 (1<<(e.xbutton.button-1))))
2591 do_resize_too = False;
2592 /* Fallthrough to button-release */
2594 else
2596 /* Abort the move if
2597 * - the move started with a pressed button
2598 * and another button was pressed during the
2599 * operation
2600 * - Any button not in the
2601 * move_finish_button_mask is pressed
2603 /* if (button_mask) */
2604 /* - button_mask will always be set here.
2605 * only add an if if we want to be able to
2606 * place windows dragged by other means
2607 * than releasing the initial button.
2610 if (!do_move_opaque)
2612 switch_move_resize_grid(False);
2614 if (!IS_ICONIFIED(fw))
2616 *FinalX = fw->g.frame.x;
2617 *FinalY = fw->g.frame.y;
2619 else
2621 *FinalX = orig_icon_x;
2622 *FinalY = orig_icon_y;
2624 is_aborted = True;
2625 is_finished = True;
2627 break;
2629 case ButtonRelease:
2630 if (!is_fake_event)
2632 fw->placed_by_button = e.xbutton.button;
2634 if (!do_move_opaque)
2636 switch_move_resize_grid(False);
2638 xl2 = e.xbutton.x_root + XOffset + x_virtual_offset;
2639 yt2 = e.xbutton.y_root + YOffset + y_virtual_offset;
2640 /* ignore the position of the button release if it was
2641 * on a different page. */
2642 if (!(((xl < 0 && xl2 >= 0) ||
2643 (xl >= 0 && xl2 < 0) ||
2644 (yt < 0 && yt2 >= 0) ||
2645 (yt >= 0 && yt2 < 0)) &&
2646 (abs(xl - xl2) > Scr.MyDisplayWidth / 2 ||
2647 abs(yt - yt2) > Scr.MyDisplayHeight / 2)))
2649 xl = xl2;
2650 yt = yt2;
2652 if (xl != xl_orig || yt != yt_orig || vx != Scr.Vx ||
2653 vy != Scr.Vy || was_snapped)
2655 /* only snap if the window actually moved! */
2656 if (do_snap)
2658 DoSnapAttract(
2659 fw, Width, Height, &xl, &yt);
2660 was_snapped = True;
2664 *FinalX = xl;
2665 *FinalY = yt;
2667 is_finished = True;
2668 break;
2670 case MotionNotify:
2671 if (e.xmotion.same_screen == False)
2673 continue;
2675 if (!(e.xmotion.state & Mod1Mask))
2677 nosnap_enabled = True;
2679 do_snap = nosnap_enabled &&
2680 (e.xmotion.state & Mod1Mask) ? False : True;
2681 xl = e.xmotion.x_root;
2682 yt = e.xmotion.y_root;
2683 if (xl > 0 && xl < Scr.MyDisplayWidth - 1)
2685 /* pointer was moved away from the left/right
2686 * border with the mouse, reset the virtual x
2687 * offset */
2688 x_virtual_offset = 0;
2690 if (yt > 0 && yt < Scr.MyDisplayHeight - 1)
2692 /* pointer was moved away from the top/bottom
2693 * border with the mouse, reset the virtual y
2694 * offset */
2695 y_virtual_offset = 0;
2697 xl += XOffset + x_virtual_offset;
2698 yt += YOffset + y_virtual_offset;
2700 if (do_snap)
2702 DoSnapAttract(fw, Width, Height, &xl, &yt);
2703 was_snapped = True;
2706 /* check Paging request once and only once after
2707 * outline redrawn redraw after paging if needed
2708 * - mab */
2709 for (paged = 0; paged <= 1; paged++)
2711 if (!do_move_opaque)
2713 draw_move_resize_grid(
2714 xl, yt, Width - 1, Height - 1);
2716 else
2718 if (IS_ICONIFIED(fw))
2720 set_icon_position(fw, xl, yt);
2721 move_icon_to_position(fw);
2722 broadcast_icon_geometry(
2723 fw, False);
2725 else
2727 XMoveWindow(
2728 dpy, FW_W_FRAME(fw),
2729 xl, yt);
2732 DisplayPosition(fw, &e, xl, yt, False);
2734 /* prevent window from lagging behind mouse
2735 * when paging - mab */
2736 if (paged == 0)
2738 XEvent le;
2740 xl = e.xmotion.x_root;
2741 yt = e.xmotion.y_root;
2742 fev_get_last_event(&le);
2743 HandlePaging(
2744 &le, dx, dy, &xl, &yt,
2745 &delta_x, &delta_y, False,
2746 False, False,
2747 fw->edge_delay_ms_move);
2748 if (delta_x)
2750 x_virtual_offset = 0;
2752 xl += XOffset;
2753 if (delta_y)
2755 y_virtual_offset = 0;
2757 yt += YOffset;
2758 if (do_snap)
2760 DoSnapAttract(
2761 fw, Width, Height,
2762 &xl, &yt);
2763 was_snapped = True;
2765 if (!delta_x && !delta_y)
2767 /* break from while
2768 * (paged <= 1) */
2769 break;
2773 break;
2775 case Expose:
2776 if (!do_move_opaque)
2778 /* must undraw the rubber band in case the
2779 * event causes some drawing */
2780 switch_move_resize_grid(False);
2782 dispatch_event(&e);
2783 if (!do_move_opaque)
2785 draw_move_resize_grid(
2786 xl, yt, Width - 1, Height - 1);
2788 break;
2790 default:
2791 /* cannot happen */
2792 break;
2793 } /* switch */
2794 xl += x_virtual_offset;
2795 yt += y_virtual_offset;
2796 if (do_move_opaque && !IS_ICONIFIED(fw) &&
2797 !IS_SHADED(fw) && !Scr.bo.do_disable_configure_notify)
2799 /* send configure notify event for windows that care
2800 * about their location; don't send anything if
2801 * position didn't change */
2802 if (!sent_cn || cnx != xl || cny != yt)
2804 cnx = xl;
2805 cny = yt;
2806 sent_cn = True;
2807 SendConfigureNotify(
2808 fw, xl, yt, Width, Height, 0,
2809 False);
2810 #ifdef FVWM_DEBUG_MSGS
2811 fvwm_msg(
2812 DBG, "frame_setup_window",
2813 "Sent ConfigureNotify (w %d, h %d)",
2814 Width, Height);
2815 #endif
2818 if (do_move_opaque)
2820 if (!IS_ICONIFIED(fw))
2822 fw_copy.g.frame.x = xl;
2823 fw_copy.g.frame.y = yt;
2825 if (xl != old_xl || yt != old_yt)
2827 /* only do this with opaque moves, (i.e. the
2828 * server is not grabbed) */
2829 if (draw_parts != PART_NONE)
2831 border_draw_decorations(
2832 fw, draw_parts,
2833 ((fw == get_focus_window())) ?
2834 True : False,
2835 True, CLEAR_ALL, NULL, NULL);
2837 if (IS_TEAR_OFF_MENU(fw))
2839 menu_redraw_transparent_tear_off_menu(
2840 fw, False);
2842 BroadcastConfig(M_CONFIGURE_WINDOW, &fw_copy);
2843 FlushAllMessageQueues();
2846 } /* while (!is_finished) */
2848 if (!Scr.gs.do_hide_position_window)
2850 XUnmapWindow(dpy,Scr.SizeWindow);
2852 if (is_aborted || bad_window == FW_W(fw))
2854 if (vx != Scr.Vx || vy != Scr.Vy)
2856 MoveViewport(vx, vy, False);
2858 if (is_aborted && do_move_opaque)
2860 XMoveWindow(dpy, move_w, x_bak, y_bak);
2861 if (draw_parts != PART_NONE)
2863 border_draw_decorations(
2864 fw, draw_parts,
2865 ((fw == get_focus_window())) ?
2866 True : False,
2867 True, CLEAR_ALL, NULL, NULL);
2869 menu_redraw_transparent_tear_off_menu(fw, False);
2871 if (bad_window == FW_W(fw))
2873 XUnmapWindow(dpy, move_w);
2874 border_undraw_decorations(fw);
2875 XBell(dpy, 0);
2878 if (!is_aborted && bad_window != FW_W(fw) && IS_ICONIFIED(fw))
2880 SET_ICON_MOVED(fw, 1);
2882 UngrabEm(GRAB_NORMAL);
2883 if (!do_resize_too)
2885 /* Don't wait for buttons to come up when user is placing a new
2886 * window and wants to resize it. */
2887 WaitForButtonsUp(True);
2889 SET_WINDOW_BEING_MOVED_OPAQUE(fw, 0);
2890 bad_window = None;
2892 return do_resize_too;
2895 void CMD_MoveThreshold(F_CMD_ARGS)
2897 int val = 0;
2899 if (GetIntegerArguments(action, NULL, &val, 1) < 1 || val < 0)
2901 Scr.MoveThreshold = DEFAULT_MOVE_THRESHOLD;
2903 else
2905 Scr.MoveThreshold = val;
2908 return;
2911 void CMD_OpaqueMoveSize(F_CMD_ARGS)
2913 int val;
2915 if (GetIntegerArguments(action, NULL, &val, 1) < 1)
2917 if (strncasecmp(action, "unlimited", 9) == 0)
2919 Scr.OpaqueSize = -1;
2921 else
2923 Scr.OpaqueSize = DEFAULT_OPAQUE_MOVE_SIZE;
2926 else
2928 Scr.OpaqueSize = val;
2931 return;
2935 static char *hide_options[] =
2937 "never",
2938 "move",
2939 "resize",
2940 NULL
2943 void CMD_HideGeometryWindow(F_CMD_ARGS)
2945 char *token = PeekToken(action, NULL);
2947 Scr.gs.do_hide_position_window = 0;
2948 Scr.gs.do_hide_resize_window = 0;
2949 switch(GetTokenIndex(token, hide_options, 0, NULL))
2951 case 0:
2952 break;
2953 case 1:
2954 Scr.gs.do_hide_position_window = 1;
2955 break;
2956 case 2:
2957 Scr.gs.do_hide_resize_window = 1;
2958 break;
2959 default:
2960 Scr.gs.do_hide_position_window = 1;
2961 Scr.gs.do_hide_resize_window = 1;
2962 break;
2964 return;
2967 void CMD_SnapAttraction(F_CMD_ARGS)
2969 char *cmd;
2970 size_t len;
2972 len = strlen(action);
2973 len += 99;
2974 cmd = safemalloc(len);
2975 sprintf(cmd, "Style * SnapAttraction %s", action);
2976 fvwm_msg(
2977 OLD, "CMD_SnapAttraction",
2978 "The command SnapAttraction is obsolete. Please use the"
2979 " following command instead:");
2980 fvwm_msg(OLD, "", cmd);
2981 execute_function(
2982 cond_rc, exc, cmd,
2983 FUNC_DONT_REPEAT | FUNC_DONT_EXPAND_COMMAND);
2984 free(cmd);
2986 return;
2989 void CMD_SnapGrid(F_CMD_ARGS)
2991 char *cmd;
2992 size_t len;
2994 len = strlen(action);
2995 len += 99;
2996 cmd = safemalloc(len);
2997 sprintf(cmd, "Style * SnapGrid %s", action);
2998 fvwm_msg(
2999 OLD, "CMD_SnapGrid",
3000 "The command SnapGrid is obsolete. Please use the following"
3001 " command instead:");
3002 fvwm_msg(OLD, "", cmd);
3003 execute_function(
3004 cond_rc, exc, cmd,
3005 FUNC_DONT_REPEAT | FUNC_DONT_EXPAND_COMMAND);
3006 free(cmd);
3008 return;
3011 static Pixmap XorPixmap = None;
3013 void CMD_XorValue(F_CMD_ARGS)
3015 int val;
3016 XGCValues gcv;
3017 unsigned long gcm;
3019 if (GetIntegerArguments(action, NULL, &val, 1) != 1)
3021 val = 0;
3024 PictureUseDefaultVisual();
3025 gcm = GCFunction|GCLineWidth|GCForeground|GCFillStyle|GCSubwindowMode;
3026 gcv.subwindow_mode = IncludeInferiors;
3027 gcv.function = GXxor;
3028 gcv.line_width = 1;
3029 /* use passed in value, or try to calculate appropriate value if 0 */
3030 /* ctwm method: */
3032 gcv.foreground = (val1)?(val1):((((unsigned long) 1) <<
3033 Scr.d_depth) - 1);
3035 /* Xlib programming manual suggestion: */
3036 gcv.foreground = (val)?
3037 (val):(PictureBlackPixel() ^ PictureWhitePixel());
3038 gcv.fill_style = FillSolid;
3039 gcv.subwindow_mode = IncludeInferiors;
3041 /* modify XorGC, only create once */
3042 if (Scr.XorGC)
3044 XChangeGC(dpy, Scr.XorGC, gcm, &gcv);
3046 else
3048 Scr.XorGC = fvwmlib_XCreateGC(dpy, Scr.Root, gcm, &gcv);
3051 /* free up XorPixmap if neccesary */
3052 if (XorPixmap != None) {
3053 XFreePixmap(dpy, XorPixmap);
3054 XorPixmap = None;
3056 PictureUseFvwmVisual();
3058 return;
3062 void CMD_XorPixmap(F_CMD_ARGS)
3064 char *PixmapName;
3065 FvwmPicture *xp;
3066 XGCValues gcv;
3067 unsigned long gcm;
3068 FvwmPictureAttributes fpa;
3070 action = GetNextToken(action, &PixmapName);
3071 if (PixmapName == NULL)
3073 /* return to default value. */
3074 action = "0";
3075 CMD_XorValue(F_PASS_ARGS);
3076 return;
3078 /* get the picture in the root visual, colorlimit is ignored because the
3079 * pixels will be freed */
3080 fpa.mask = FPAM_NO_COLOR_LIMIT | FPAM_NO_ALPHA;
3081 PictureUseDefaultVisual();
3082 xp = PGetFvwmPicture(dpy, Scr.Root, NULL, PixmapName, fpa);
3083 if (xp == NULL)
3085 fvwm_msg(ERR,"SetXORPixmap","Can't find pixmap %s", PixmapName);
3086 free(PixmapName);
3087 PictureUseFvwmVisual();
3088 return;
3090 free(PixmapName);
3091 /* free up old pixmap */
3092 if (XorPixmap != None)
3094 XFreePixmap(dpy, XorPixmap);
3097 /* make a copy of the picture pixmap */
3098 XorPixmap = XCreatePixmap(dpy, Scr.Root, xp->width, xp->height, Pdepth);
3099 XCopyArea(dpy, xp->picture, XorPixmap, DefaultGC(dpy, Scr.screen), 0, 0,
3100 xp->width, xp->height, 0, 0);
3101 /* destroy picture and free colors */
3102 PDestroyFvwmPicture(dpy, xp);
3103 PictureUseFvwmVisual();
3105 /* create Graphics context */
3106 gcm = GCFunction|GCLineWidth|GCTile|GCFillStyle|GCSubwindowMode;
3107 gcv.subwindow_mode = IncludeInferiors;
3108 gcv.function = GXxor;
3109 /* line width of 1 is necessary for Exceed servers */
3110 gcv.line_width = 1;
3111 gcv.tile = XorPixmap;
3112 gcv.fill_style = FillTiled;
3113 gcv.subwindow_mode = IncludeInferiors;
3114 /* modify XorGC, only create once */
3115 if (Scr.XorGC)
3117 XChangeGC(dpy, Scr.XorGC, gcm, &gcv);
3119 else
3121 Scr.XorGC = fvwmlib_XCreateGC(dpy, Scr.Root, gcm, &gcv);
3124 return;
3128 /* ----------------------------- resizing code ----------------------------- */
3130 static void __resize_get_dir_from_window(
3131 int *ret_xmotion, int *ret_ymotion, FvwmWindow *fw, Window context_w)
3133 if (context_w != Scr.Root && context_w != None)
3135 if (context_w == FW_W_SIDE(fw, 0)) /* top */
3137 *ret_ymotion = 1;
3139 else if (context_w == FW_W_SIDE(fw, 1)) /* right */
3141 *ret_xmotion = -1;
3143 else if (context_w == FW_W_SIDE(fw, 2)) /* bottom */
3145 *ret_ymotion = -1;
3147 else if (context_w == FW_W_SIDE(fw, 3)) /* left */
3149 *ret_xmotion = 1;
3151 else if (context_w == FW_W_CORNER(fw, 0)) /* upper-left */
3153 *ret_xmotion = 1;
3154 *ret_ymotion = 1;
3156 else if (context_w == FW_W_CORNER(fw, 1)) /* upper-right */
3158 *ret_xmotion = -1;
3159 *ret_ymotion = 1;
3161 else if (context_w == FW_W_CORNER(fw, 2)) /* lower left */
3163 *ret_xmotion = 1;
3164 *ret_ymotion = -1;
3166 else if (context_w == FW_W_CORNER(fw, 3)) /* lower right */
3168 *ret_xmotion = -1;
3169 *ret_ymotion = -1;
3173 return;
3176 static void __resize_get_dir_proximity(
3177 int *ret_xmotion, int *ret_ymotion, FvwmWindow *fw, int x_off,
3178 int y_off, int px, int py)
3180 int tx;
3181 int ty;
3183 if (px < 0 || x_off < 0 || py < 0 || y_off < 0)
3185 return;
3187 /* Now find the place to warp to. We simply use the sectors
3188 * drawn when we start resizing the window. */
3189 #if 0
3190 tx = orig->width / 10 - 1;
3191 ty = orig->height / 10 - 1;
3192 #else
3193 tx = 0;
3194 ty = 0;
3195 #endif
3196 tx = max(fw->boundary_width, tx);
3197 ty = max(fw->boundary_width, ty);
3198 if (px < tx)
3200 *ret_xmotion = 1;
3202 else if (x_off < tx)
3204 *ret_xmotion = -1;
3206 if (py < ty)
3208 *ret_ymotion = 1;
3210 else if (y_off < ty)
3212 *ret_ymotion = -1;
3215 return;
3218 static void __resize_get_refpos(
3219 int *ret_x, int *ret_y, int xmotion, int ymotion, int w, int h,
3220 FvwmWindow *fw)
3222 if (xmotion > 0)
3224 *ret_x = 0;
3226 else if (xmotion < 0)
3228 *ret_x = w - 1;
3230 else
3232 *ret_x = w / 2;
3234 if (ymotion > 0)
3236 *ret_y = 0;
3238 else if (ymotion < 0)
3240 *ret_y = h - 1;
3242 else
3244 *ret_y = h / 2;
3247 return;
3250 /* Procedure:
3251 * __resize_step - move the rubberband around. This is called for
3252 * each motion event when we are resizing
3254 * Inputs:
3255 * x_root - the X corrdinate in the root window
3256 * y_root - the Y corrdinate in the root window
3257 * x_off - x offset of pointer from border (input/output)
3258 * y_off - y offset of pointer from border (input/output)
3259 * drag - resize internal structure
3260 * orig - resize internal structure
3261 * xmotionp - pointer to xmotion in resize_window
3262 * ymotionp - pointer to ymotion in resize_window
3265 static void __resize_step(
3266 const exec_context_t *exc, int x_root, int y_root, int *x_off,
3267 int *y_off, rectangle *drag, const rectangle *orig, int *xmotionp,
3268 int *ymotionp, Bool do_resize_opaque, Bool is_direction_fixed)
3270 int action = 0;
3271 int x2;
3272 int y2;
3273 int xdir;
3274 int ydir;
3276 x2 = x_root - *x_off;
3277 x_root += *x_off;
3278 if (is_direction_fixed == True && (*xmotionp != 0 || *ymotionp != 0))
3280 xdir = *xmotionp;
3282 else if (x2 <= orig->x ||
3283 (*xmotionp == 1 && x2 < orig->x + orig->width - 1))
3285 xdir = 1;
3287 else if (x2 >= orig->x + orig->width - 1 ||
3288 (*xmotionp == -1 && x2 > orig->x))
3290 xdir = -1;
3292 else
3294 xdir = 0;
3296 switch (xdir)
3298 case 1:
3299 if (*xmotionp != 1)
3301 *x_off = -*x_off;
3302 x_root = x2;
3303 *xmotionp = 1;
3305 drag->x = x_root;
3306 drag->width = orig->x + orig->width - x_root;
3307 action = 1;
3308 break;
3309 case -1:
3310 if (*xmotionp != -1)
3312 *x_off = -*x_off;
3313 x_root = x2;
3314 *xmotionp = -1;
3316 drag->x = orig->x;
3317 drag->width = 1 + x_root - drag->x;
3318 action = 1;
3319 break;
3320 default:
3321 break;
3323 y2 = y_root - *y_off;
3324 y_root += *y_off;
3325 if (is_direction_fixed == True && (*xmotionp != 0 || *ymotionp != 0))
3327 ydir = *ymotionp;
3329 else if (y2 <= orig->y ||
3330 (*ymotionp == 1 && y2 < orig->y + orig->height - 1))
3332 ydir = 1;
3334 else if (y2 >= orig->y + orig->height - 1 ||
3335 (*ymotionp == -1 && y2 > orig->y))
3337 ydir = -1;
3339 else
3341 ydir = 0;
3343 switch (ydir)
3345 case 1:
3346 if (*ymotionp != 1)
3348 *y_off = -*y_off;
3349 y_root = y2;
3350 *ymotionp = 1;
3352 drag->y = y_root;
3353 drag->height = orig->y + orig->height - y_root;
3354 action = 1;
3355 break;
3356 case -1:
3357 if (*ymotionp != -1)
3359 *y_off = -*y_off;
3360 y_root = y2;
3361 *ymotionp = -1;
3363 drag->y = orig->y;
3364 drag->height = 1 + y_root - drag->y;
3365 action = 1;
3366 break;
3367 default:
3368 break;
3371 if (action)
3373 /* round up to nearest OK size to keep pointer inside
3374 * rubberband */
3375 constrain_size(
3376 exc->w.fw, exc->x.elast, &drag->width, &drag->height,
3377 *xmotionp, *ymotionp, CS_ROUND_UP);
3378 if (*xmotionp == 1)
3380 drag->x = orig->x + orig->width - drag->width;
3382 if (*ymotionp == 1)
3384 drag->y = orig->y + orig->height - drag->height;
3386 if (!do_resize_opaque)
3388 draw_move_resize_grid(
3389 drag->x, drag->y, drag->width - 1,
3390 drag->height - 1);
3392 else
3394 frame_setup_window(
3395 exc->w.fw, drag->x, drag->y, drag->width,
3396 drag->height, False);
3399 DisplaySize(exc->w.fw, exc->x.elast, drag->width, drag->height, False, False);
3401 return;
3404 /* Starts a window resize operation */
3405 static Bool __resize_window(F_CMD_ARGS)
3407 extern Window bad_window;
3408 FvwmWindow *fw = exc->w.fw;
3409 Bool is_finished = False, is_done = False, is_aborted = False;
3410 Bool do_send_cn = False;
3411 Bool do_resize_opaque;
3412 Bool do_warp_to_border;
3413 Bool is_direction_fixed;
3414 Bool fButtonAbort = False;
3415 Bool fForceRedraw = False;
3416 Bool called_from_title = False;
3417 int x,y,delta_x,delta_y,stashed_x,stashed_y;
3418 Window ResizeWindow;
3419 int dx = Scr.EdgeScrollX ? Scr.EdgeScrollX : Scr.MyDisplayWidth;
3420 int dy = Scr.EdgeScrollY ? Scr.EdgeScrollY : Scr.MyDisplayHeight;
3421 const int vx = Scr.Vx;
3422 const int vy = Scr.Vy;
3423 int n;
3424 unsigned int button_mask = 0;
3425 rectangle sdrag;
3426 rectangle sorig;
3427 rectangle *drag = &sdrag;
3428 const rectangle *orig = &sorig;
3429 const window_g g_backup = fw->g;
3430 int ymotion = 0;
3431 int xmotion = 0;
3432 int was_maximized;
3433 unsigned edge_wrap_x;
3434 unsigned edge_wrap_y;
3435 int px;
3436 int py;
3437 int i;
3438 size_borders b;
3439 frame_move_resize_args mr_args = NULL;
3440 long evmask;
3441 XEvent ev;
3442 int ref_x;
3443 int ref_y;
3444 int x_off;
3445 int y_off;
3446 direction_t dir;
3448 bad_window = False;
3449 ResizeWindow = FW_W_FRAME(fw);
3450 if (fev_get_evpos_or_query(dpy, Scr.Root, exc->x.etrigger, &px, &py) ==
3451 False ||
3452 XTranslateCoordinates(
3453 dpy, Scr.Root, ResizeWindow, px, py, &px, &py,
3454 &JunkChild) == False)
3456 /* pointer is on a different screen - that's okay here */
3457 px = 0;
3458 py = 0;
3460 button_mask &= DEFAULT_ALL_BUTTONS_MASK;
3462 if (!is_function_allowed(F_RESIZE, NULL, fw, RQORIG_PROGRAM_US, True))
3464 XBell(dpy, 0);
3465 return False;
3468 if (IS_SHADED(fw) || !IS_MAPPED(fw))
3470 do_resize_opaque = False;
3471 evmask = XEVMASK_RESIZE;
3473 else
3475 do_resize_opaque = DO_RESIZE_OPAQUE(fw);
3476 evmask = XEVMASK_RESIZE_OPAQUE;
3479 /* no suffix = % of screen, 'p' = pixels, 'c' = increment units */
3480 if (IS_SHADED(fw))
3482 get_unshaded_geometry(fw, drag);
3484 else
3486 drag->width = fw->g.frame.width;
3487 drag->height = fw->g.frame.height;
3490 get_window_borders(fw, &b);
3491 n = GetResizeArguments(
3492 &action, fw->g.frame.x, fw->g.frame.y,
3493 fw->hints.base_width, fw->hints.base_height,
3494 fw->hints.width_inc, fw->hints.height_inc,
3495 &b, &(drag->width), &(drag->height),
3496 &dir, &is_direction_fixed, &do_warp_to_border);
3498 if (n == 2)
3500 rectangle new_g;
3502 /* size will be less or equal to requested */
3503 if (IS_SHADED(fw))
3505 rectangle shaded_g;
3507 get_unshaded_geometry(fw, &new_g);
3508 SET_MAXIMIZED(fw, 0);
3509 constrain_size(
3510 fw, NULL, &drag->width, &drag->height, xmotion,
3511 ymotion, 0);
3512 gravity_resize(
3513 fw->hints.win_gravity, &new_g,
3514 drag->width - new_g.width,
3515 drag->height - new_g.height);
3516 fw->g.normal = new_g;
3517 get_shaded_geometry(fw, &shaded_g, &new_g);
3518 frame_setup_window(
3519 fw, shaded_g.x, shaded_g.y, shaded_g.width,
3520 shaded_g.height, False);
3522 else
3524 new_g = fw->g.frame;
3525 SET_MAXIMIZED(fw, 0);
3526 constrain_size(
3527 fw, NULL, &drag->width, &drag->height, xmotion,
3528 ymotion, 0);
3529 gravity_resize(
3530 fw->hints.win_gravity, &new_g,
3531 drag->width - new_g.width,
3532 drag->height - new_g.height);
3533 frame_setup_window(
3534 fw, new_g.x, new_g.y, drag->width,
3535 drag->height, False);
3537 update_absolute_geometry(fw);
3538 maximize_adjust_offset(fw);
3539 GNOME_SetWinArea(fw);
3540 ResizeWindow = None;
3541 return True;
3544 was_maximized = IS_MAXIMIZED(fw);
3545 SET_MAXIMIZED(fw, 0);
3546 if (was_maximized)
3548 /* must redraw the buttons now so that the 'maximize' button
3549 * does not stay depressed. */
3550 border_draw_decorations(
3551 fw, PART_BUTTONS, (fw == Scr.Hilite), True, CLEAR_ALL,
3552 NULL, NULL);
3555 if (Scr.bo.do_install_root_cmap)
3557 InstallRootColormap();
3559 else
3561 InstallFvwmColormap();
3563 if (!GrabEm(CRS_RESIZE, GRAB_NORMAL))
3565 XBell(dpy, 0);
3566 return False;
3569 /* handle problems with edge-wrapping while resizing */
3570 edge_wrap_x = Scr.flags.do_edge_wrap_x;
3571 edge_wrap_y = Scr.flags.do_edge_wrap_y;
3572 Scr.flags.do_edge_wrap_x = 0;
3573 Scr.flags.do_edge_wrap_y = 0;
3575 if (!do_resize_opaque)
3577 MyXGrabServer(dpy);
3579 if (!XGetGeometry(
3580 dpy, (Drawable)ResizeWindow, &JunkRoot, &drag->x, &drag->y,
3581 (unsigned int*)&drag->width, (unsigned int*)&drag->height,
3582 (unsigned int*)&JunkBW, (unsigned int*)&JunkDepth))
3584 UngrabEm(GRAB_NORMAL);
3585 if (!do_resize_opaque)
3587 MyXUngrabServer(dpy);
3589 return False;
3591 if (IS_SHADED(fw))
3593 SET_MAXIMIZED(fw, was_maximized);
3594 get_unshaded_geometry(fw, drag);
3595 SET_MAXIMIZED(fw, 0);
3597 if (do_resize_opaque)
3599 mr_args = frame_create_move_resize_args(
3600 fw, FRAME_MR_OPAQUE, &fw->g.frame, &fw->g.frame, 0,
3601 DIR_NONE);
3603 else
3605 Scr.flags.is_wire_frame_displayed = True;
3607 MyXGrabKeyboard(dpy);
3609 sorig = *drag;
3610 ymotion = 0;
3611 xmotion = 0;
3613 /* pop up a resize dimensions window */
3614 if (!Scr.gs.do_hide_resize_window)
3616 position_geometry_window(NULL);
3617 XMapRaised(dpy, Scr.SizeWindow);
3619 DisplaySize(fw, exc->x.elast, orig->width, orig->height, True, True);
3621 if (dir != DIR_NONE)
3623 int grav;
3625 grav = gravity_dir_to_grav(dir);
3626 gravity_get_offsets(grav, &xmotion, &ymotion);
3627 xmotion = -xmotion;
3628 ymotion = -ymotion;
3630 if (xmotion == 0 && ymotion == 0)
3632 __resize_get_dir_from_window(&xmotion, &ymotion, fw, PressedW);
3634 if (FW_W_TITLE(fw) != None && PressedW == FW_W_TITLE(fw))
3636 /* title was pressed to start the resize */
3637 called_from_title = True;
3639 else
3641 for (i = NUMBER_OF_TITLE_BUTTONS; i--; )
3643 /* see if the title button was pressed to that the
3644 * resize */
3645 if (FW_W_BUTTON(fw, i) != None &&
3646 FW_W_BUTTON(fw, i) == PressedW)
3648 /* yes */
3649 called_from_title = True;
3653 /* don't warp if the resize was triggered by a press somwhere on the
3654 * title bar */
3655 if (PressedW != Scr.Root && xmotion == 0 && ymotion == 0 &&
3656 !called_from_title)
3658 __resize_get_dir_proximity(
3659 &xmotion, &ymotion, fw, orig->width - px,
3660 orig->height - py, px, py);
3661 if (xmotion != 0 || ymotion != 0)
3663 do_warp_to_border = True;
3666 if (!IS_SHADED(fw))
3668 __resize_get_refpos(
3669 &ref_x, &ref_y, xmotion, ymotion, orig->width,
3670 orig->height, fw);
3672 else
3674 switch (SHADED_DIR(fw))
3676 case DIR_N:
3677 case DIR_NW:
3678 case DIR_NE:
3679 if (ymotion == -1)
3681 ymotion = 0;
3683 break;
3684 case DIR_S:
3685 case DIR_SW:
3686 case DIR_SE:
3687 if (ymotion == 1)
3689 ymotion = 0;
3691 break;
3692 default:
3693 break;
3695 switch (SHADED_DIR(fw))
3697 case DIR_E:
3698 case DIR_NE:
3699 case DIR_SE:
3700 if (xmotion == 1)
3702 xmotion = 0;
3704 break;
3705 case DIR_W:
3706 case DIR_NW:
3707 case DIR_SW:
3708 if (xmotion == -1)
3710 xmotion = 0;
3712 break;
3713 default:
3714 break;
3716 __resize_get_refpos(
3717 &ref_x, &ref_y, xmotion, ymotion, fw->g.frame.width,
3718 fw->g.frame.height, fw);
3720 x_off = 0;
3721 y_off = 0;
3722 if (do_warp_to_border == True)
3724 int dx;
3725 int dy;
3727 dx = (xmotion == 0) ? px : ref_x;
3728 dy = (ymotion == 0) ? py : ref_y;
3729 /* warp the pointer to the border */
3730 FWarpPointer(
3731 dpy, None, ResizeWindow, 0, 0, 1, 1, dx, dy);
3732 XFlush(dpy);
3734 else if (xmotion != 0 || ymotion != 0)
3736 /* keep the distance between pointer and border */
3737 x_off = (xmotion == 0) ? 0 : ref_x - px;
3738 y_off = (ymotion == 0) ? 0 : ref_y - py;
3740 else
3742 /* wait until the pointer hits a border before making a
3743 * decision about the resize direction */
3746 /* draw the rubber-band window */
3747 if (!do_resize_opaque)
3749 draw_move_resize_grid(
3750 drag->x, drag->y, drag->width - 1, drag->height - 1);
3752 /* kick off resizing without requiring any motion if invoked with a key
3753 * press */
3754 if (exc->x.elast->type == KeyPress)
3756 int xo;
3757 int yo;
3759 if (FQueryPointer(
3760 dpy, Scr.Root, &JunkRoot, &JunkChild, &stashed_x,
3761 &stashed_y, &JunkX, &JunkY, &JunkMask) == False)
3763 /* pointer is on a different screen */
3764 stashed_x = 0;
3765 stashed_y = 0;
3767 xo = 0;
3768 yo = 0;
3769 __resize_step(
3770 exc, stashed_x, stashed_y, &xo, &yo, drag, orig,
3771 &xmotion, &ymotion, do_resize_opaque, True);
3773 else
3775 stashed_x = stashed_y = -1;
3778 /* loop to resize */
3779 memset(&ev, 0, sizeof(ev));
3780 while (!is_finished && bad_window != FW_W(fw))
3782 int rc = 0;
3784 /* block until there is an interesting event */
3785 while (rc != -1 &&
3786 (!FPending(dpy) || !FCheckMaskEvent(dpy, evmask, &ev)))
3788 rc = HandlePaging(
3789 &ev, dx, dy, &x, &y, &delta_x, &delta_y, False,
3790 False, True, fw->edge_delay_ms_resize);
3791 if (rc == 1)
3793 /* Fake an event to force window reposition */
3794 ev.type = MotionNotify;
3795 ev.xmotion.time = fev_get_evtime();
3796 fForceRedraw = True;
3797 break;
3800 if (rc == -1)
3802 FMaskEvent(
3803 dpy,
3804 evmask | EnterWindowMask | LeaveWindowMask,
3805 &ev);
3807 if (ev.type == MotionNotify ||
3808 ev.type == EnterNotify || ev.type == LeaveNotify)
3810 Bool is_motion;
3812 is_motion = (ev.type == MotionNotify) ? True : False;
3813 /* discard any extra motion events before a release */
3814 /* dv (2004-07-01): With XFree 4.1.0.1, some Mouse
3815 * events are not reported to fvwm when the pointer
3816 * moves very fast and suddenly stops in the corner of
3817 * the screen. Handle EnterNotify/LeaveNotify events
3818 * too to get an idea where the pointer might be. */
3819 while (
3820 FCheckMaskEvent(
3821 dpy, ButtonMotionMask |
3822 PointerMotionMask | ButtonReleaseMask |
3823 ButtonPressMask | EnterWindowMask |
3824 LeaveWindowMask, &ev) == True)
3826 if (ev.type == ButtonRelease ||
3827 ev.type == ButtonPress ||
3828 ev.type == KeyPress)
3830 break;
3834 if (ev.type == EnterNotify || ev.type == LeaveNotify)
3836 XEvent e2;
3837 int x;
3838 int y;
3840 /* Query the pointer to catch the latest information.
3841 * This *is* necessary. */
3842 if (FQueryPointer(
3843 dpy, Scr.Root, &JunkRoot, &JunkChild, &x,
3844 &y, &JunkX, &JunkY, &JunkMask) == True)
3846 /* Must NOT use button_mask here, or resize
3847 * will not work with num lock */
3848 fev_make_null_event(&e2, dpy);
3849 e2.type = MotionNotify;
3850 e2.xmotion.time = fev_get_evtime();
3851 e2.xmotion.x_root = x;
3852 e2.xmotion.y_root = y;
3853 e2.xmotion.state = JunkMask;
3854 e2.xmotion.same_screen = True;
3855 ev = e2;
3856 fev_fake_event(&ev);
3858 else
3860 /* pointer is on a different screen,
3861 * ignore event */
3865 is_done = False;
3866 /* Handle a limited number of key press events to allow
3867 * mouseless operation */
3868 if (ev.type == KeyPress)
3870 Keyboard_shortcuts(&ev, fw, NULL, NULL, ButtonRelease);
3871 if (ev.type == ButtonRelease)
3873 do_send_cn = True;
3876 switch (ev.type)
3878 case ButtonPress:
3879 is_done = True;
3880 if (ev.xbutton.button <= NUMBER_OF_MOUSE_BUTTONS &&
3881 ((Button1Mask << (ev.xbutton.button - 1)) &
3882 button_mask))
3884 /* No new button was pressed, just a delayed
3885 * event */
3886 break;
3888 /* Abort the resize if
3889 * - the move started with a pressed button and
3890 * another button was pressed during the operation
3891 * - no button was started at the beginning and any
3892 * button except button 1 was pressed. */
3893 if (button_mask || (ev.xbutton.button != 1))
3895 fButtonAbort = True;
3896 /* fall through */
3898 else
3900 is_finished = True;
3901 do_send_cn = True;
3902 break;
3904 case KeyPress:
3905 /* simple code to bag out of move - CKH */
3906 if (fButtonAbort ||
3907 XLookupKeysym(&ev.xkey, 0) == XK_Escape)
3909 is_aborted = True;
3910 do_send_cn = True;
3911 is_finished = True;
3913 is_done = True;
3914 break;
3916 case ButtonRelease:
3917 is_finished = True;
3918 is_done = True;
3919 break;
3921 case MotionNotify:
3922 if (ev.xmotion.same_screen == False)
3924 continue;
3926 if (!fForceRedraw)
3928 x = ev.xmotion.x_root;
3929 y = ev.xmotion.y_root;
3930 /* resize before paging request to prevent
3931 * resize from lagging * mouse - mab */
3932 __resize_step(
3933 exc, x, y, &x_off, &y_off, drag, orig,
3934 &xmotion, &ymotion, do_resize_opaque,
3935 is_direction_fixed);
3936 /* need to move the viewport */
3937 HandlePaging(
3938 &ev, dx, dy, &x, &y, &delta_x,
3939 &delta_y, False, False, False,
3940 fw->edge_delay_ms_resize);
3942 /* redraw outline if we paged - mab */
3943 if (delta_x != 0 || delta_y != 0)
3945 sorig.x -= delta_x;
3946 sorig.y -= delta_y;
3947 drag->x -= delta_x;
3948 drag->y -= delta_y;
3950 __resize_step(
3951 exc, x, y, &x_off, &y_off, drag, orig,
3952 &xmotion, &ymotion, do_resize_opaque,
3953 is_direction_fixed);
3955 fForceRedraw = False;
3956 is_done = True;
3957 break;
3959 case PropertyNotify:
3961 evh_args_t ea;
3962 exec_context_changes_t ecc;
3964 ecc.x.etrigger = &ev;
3965 ea.exc = exc_clone_context(exc, &ecc, ECC_ETRIGGER);
3966 HandlePropertyNotify(&ea);
3967 exc_destroy_context(ea.exc);
3968 is_done = True;
3969 break;
3972 default:
3973 break;
3975 if (!is_done)
3977 if (!do_resize_opaque)
3979 /* must undraw the rubber band in case the
3980 * event causes some drawing */
3981 switch_move_resize_grid(False);
3983 dispatch_event(&ev);
3984 if (!do_resize_opaque)
3986 draw_move_resize_grid(
3987 drag->x, drag->y, drag->width - 1,
3988 drag->height - 1);
3991 else
3993 if (do_resize_opaque)
3995 /* only do this with opaque resizes, (i.e. the
3996 * server is not grabbed) */
3997 BroadcastConfig(M_CONFIGURE_WINDOW, fw);
3998 FlushAllMessageQueues();
4003 /* erase the rubber-band */
4004 if (!do_resize_opaque)
4006 switch_move_resize_grid(False);
4008 /* pop down the size window */
4009 if (!Scr.gs.do_hide_resize_window)
4011 XUnmapWindow(dpy, Scr.SizeWindow);
4013 if (is_aborted || bad_window == FW_W(fw))
4015 /* return pointer if aborted resize was invoked with key */
4016 if (stashed_x >= 0)
4018 FWarpPointer(
4019 dpy, None, Scr.Root, 0, 0, 0, 0, stashed_x,
4020 stashed_y);
4022 if (was_maximized)
4024 /* since we aborted the resize, the window is still
4025 * maximized */
4026 SET_MAXIMIZED(fw, 1);
4028 if (do_resize_opaque)
4030 int xo;
4031 int yo;
4032 rectangle g;
4034 xo = 0;
4035 yo = 0;
4036 xmotion = 1;
4037 ymotion = 1;
4038 g = sorig;
4039 __resize_step(
4040 exc, sorig.x, sorig.y, &xo, &yo, &g, orig,
4041 &xmotion, &ymotion, do_resize_opaque, True);
4043 if (vx != Scr.Vx || vy != Scr.Vy)
4045 MoveViewport(vx, vy, False);
4047 /* restore all geometry-related info */
4048 fw->g = g_backup;
4049 if (bad_window == FW_W(fw))
4051 XUnmapWindow(dpy, FW_W_FRAME(fw));
4052 border_undraw_decorations(fw);
4053 XBell(dpy, 0);
4056 else if (!is_aborted && bad_window != FW_W(fw))
4058 rectangle new_g;
4060 /* size will be >= to requested */
4061 constrain_size(
4062 fw, exc->x.elast, &drag->width, &drag->height,
4063 xmotion, ymotion, CS_ROUND_UP);
4064 if (IS_SHADED(fw))
4066 get_shaded_geometry(fw, &new_g, drag);
4068 else
4070 new_g = *drag;
4072 if (do_resize_opaque)
4074 frame_update_move_resize_args(mr_args, &new_g);
4076 else
4078 frame_setup_window(
4079 fw, new_g.x, new_g.y, new_g.width,
4080 new_g.height, False);
4082 if (IS_SHADED(fw))
4084 fw->g.normal.width = drag->width;
4085 fw->g.normal.height = drag->height;
4088 if (is_aborted && was_maximized)
4090 /* force redraw */
4091 border_draw_decorations(
4092 fw, PART_BUTTONS, (fw == Scr.Hilite), True, CLEAR_ALL,
4093 NULL, NULL);
4095 if (Scr.bo.do_install_root_cmap)
4097 UninstallRootColormap();
4099 else
4101 UninstallFvwmColormap();
4103 ResizeWindow = None;
4104 if (!do_resize_opaque)
4106 /* Throw away some events that dont interest us right now. */
4107 discard_events(EnterWindowMask|LeaveWindowMask);
4108 Scr.flags.is_wire_frame_displayed = False;
4109 MyXUngrabServer(dpy);
4111 if (mr_args != NULL)
4113 frame_free_move_resize_args(fw, mr_args);
4115 if (do_send_cn == True)
4117 rectangle g;
4119 if (is_aborted)
4121 g = sorig;
4123 else
4125 g = *drag;
4127 SendConfigureNotify(fw, g.x, g.y, g.width, g.height, 0, True);
4129 MyXUngrabKeyboard(dpy);
4130 WaitForButtonsUp(True);
4131 UngrabEm(GRAB_NORMAL);
4132 Scr.flags.do_edge_wrap_x = edge_wrap_x;
4133 Scr.flags.do_edge_wrap_y = edge_wrap_y;
4134 update_absolute_geometry(fw);
4135 maximize_adjust_offset(fw);
4136 GNOME_SetWinArea(fw);
4137 if (is_aborted)
4139 return False;
4142 return True;
4145 void CMD_Resize(F_CMD_ARGS)
4147 FvwmWindow *fw = exc->w.fw;
4149 if (IS_EWMH_FULLSCREEN(fw))
4151 /* do not unmaximize ! */
4152 CMD_ResizeMaximize(F_PASS_ARGS);
4153 return;
4156 __resize_window(F_PASS_ARGS);
4158 return;
4161 /* ----------------------------- maximizing code --------------------------- */
4163 Bool is_window_sticky_across_pages(FvwmWindow *fw)
4165 if (IS_STICKY_ACROSS_PAGES(fw) ||
4166 (IS_ICONIFIED(fw) && IS_ICON_STICKY_ACROSS_PAGES(fw)))
4168 return True;
4170 else
4172 return False;
4176 Bool is_window_sticky_across_desks(FvwmWindow *fw)
4178 if (IS_STICKY_ACROSS_DESKS(fw) ||
4179 (IS_ICONIFIED(fw) && IS_ICON_STICKY_ACROSS_DESKS(fw)))
4181 return True;
4183 else
4185 return False;
4189 static void move_sticky_window_to_same_page(
4190 int *x11, int *x12, int *y11, int *y12,
4191 int x21, int x22, int y21, int y22)
4193 /* make sure the x coordinate is on the same page as the reference
4194 * window */
4195 if (*x11 >= x22)
4197 while (*x11 >= x22)
4199 *x11 -= Scr.MyDisplayWidth;
4200 *x12 -= Scr.MyDisplayWidth;
4203 else if (*x12 <= x21)
4205 while (*x12 <= x21)
4207 *x11 += Scr.MyDisplayWidth;
4208 *x12 += Scr.MyDisplayWidth;
4211 /* make sure the y coordinate is on the same page as the reference
4212 * window */
4213 if (*y11 >= y22)
4215 while (*y11 >= y22)
4217 *y11 -= Scr.MyDisplayHeight;
4218 *y12 -= Scr.MyDisplayHeight;
4221 else if (*y12 <= y21)
4223 while (*y12 <= y21)
4225 *y11 += Scr.MyDisplayHeight;
4226 *y12 += Scr.MyDisplayHeight;
4230 return;
4233 static void MaximizeHeight(
4234 FvwmWindow *win, int win_width, int win_x, int *win_height,
4235 int *win_y, Bool grow_up, Bool grow_down, int top_border,
4236 int bottom_border, int *layers)
4238 FvwmWindow *cwin;
4239 int x11, x12, x21, x22;
4240 int y11, y12, y21, y22;
4241 int new_y1, new_y2;
4242 rectangle g;
4243 Bool rc;
4245 x11 = win_x; /* Start x */
4246 y11 = *win_y; /* Start y */
4247 x12 = x11 + win_width; /* End x */
4248 y12 = y11 + *win_height; /* End y */
4249 new_y1 = top_border;
4250 new_y2 = bottom_border;
4252 for (cwin = Scr.FvwmRoot.next; cwin; cwin = cwin->next)
4254 if (cwin == win ||
4255 (cwin->Desk != win->Desk &&
4256 !is_window_sticky_across_desks(cwin)))
4258 continue;
4260 if ((layers[0] >= 0 && cwin->layer < layers[0]) ||
4261 (layers[1] >= 0 && cwin->layer > layers[1]))
4263 continue;
4265 rc = get_visible_window_or_icon_geometry(cwin, &g);
4266 if (rc == False)
4268 continue;
4270 x21 = g.x;
4271 y21 = g.y;
4272 x22 = x21 + g.width;
4273 y22 = y21 + g.height;
4274 if (is_window_sticky_across_pages(cwin))
4276 move_sticky_window_to_same_page(
4277 &x21, &x22, &new_y1, &new_y2, x11, x12, y11,
4278 y12);
4281 /* Are they in the same X space? */
4282 if (!((x22 <= x11) || (x21 >= x12)))
4284 if ((y22 <= y11) && (y22 >= new_y1))
4286 new_y1 = y22;
4288 else if ((y12 <= y21) && (new_y2 >= y21))
4290 new_y2 = y21;
4294 if (!grow_up)
4296 new_y1 = y11;
4298 if (!grow_down)
4300 new_y2 = y12;
4302 *win_height = new_y2 - new_y1;
4303 *win_y = new_y1;
4305 return;
4308 static void MaximizeWidth(
4309 FvwmWindow *win, int *win_width, int *win_x, int win_height,
4310 int win_y, Bool grow_left, Bool grow_right, int left_border,
4311 int right_border, int *layers)
4313 FvwmWindow *cwin;
4314 int x11, x12, x21, x22;
4315 int y11, y12, y21, y22;
4316 int new_x1, new_x2;
4317 rectangle g;
4318 Bool rc;
4320 x11 = *win_x; /* Start x */
4321 y11 = win_y; /* Start y */
4322 x12 = x11 + *win_width; /* End x */
4323 y12 = y11 + win_height; /* End y */
4324 new_x1 = left_border;
4325 new_x2 = right_border;
4327 for (cwin = Scr.FvwmRoot.next; cwin; cwin = cwin->next)
4329 if (cwin == win ||
4330 (cwin->Desk != win->Desk &&
4331 !is_window_sticky_across_desks(cwin)))
4333 continue;
4335 if ((layers[0] >= 0 && cwin->layer < layers[0]) ||
4336 (layers[1] >= 0 && cwin->layer > layers[1]))
4338 continue;
4340 rc = get_visible_window_or_icon_geometry(cwin, &g);
4341 if (rc == False)
4343 continue;
4345 x21 = g.x;
4346 y21 = g.y;
4347 x22 = x21 + g.width;
4348 y22 = y21 + g.height;
4349 if (is_window_sticky_across_pages(cwin))
4351 move_sticky_window_to_same_page(
4352 &new_x1, &new_x2, &y21, &y22, x11, x12, y11,
4353 y12);
4356 /* Are they in the same Y space? */
4357 if (!((y22 <= y11) || (y21 >= y12)))
4359 if ((x22 <= x11) && (x22 >= new_x1))
4361 new_x1 = x22;
4363 else if ((x12 <= x21) && (new_x2 >= x21))
4365 new_x2 = x21;
4369 if (!grow_left)
4371 new_x1 = x11;
4373 if (!grow_right)
4375 new_x2 = x12;
4377 *win_width = new_x2 - new_x1;
4378 *win_x = new_x1;
4380 return;
4383 static void unmaximize_fvwm_window(
4384 FvwmWindow *fw)
4386 rectangle new_g;
4388 SET_MAXIMIZED(fw, 0);
4389 get_relative_geometry(&new_g, &fw->g.normal);
4390 if (IS_SHADED(fw))
4392 get_shaded_geometry(fw, &new_g, &new_g);
4394 frame_setup_window(
4395 fw, new_g.x, new_g.y, new_g.width, new_g.height, True);
4396 border_draw_decorations(
4397 fw, PART_ALL, (Scr.Hilite == fw), True, CLEAR_ALL, NULL, NULL);
4398 if (IS_EWMH_FULLSCREEN(fw))
4400 SET_EWMH_FULLSCREEN(fw, False);
4401 if (DO_EWMH_USE_STACKING_HINTS(fw))
4403 new_layer(fw, fw->ewmh_normal_layer);
4405 apply_decor_change(fw);
4407 return;
4410 static void maximize_fvwm_window(
4411 FvwmWindow *fw, rectangle *geometry)
4413 SET_MAXIMIZED(fw, 1);
4414 fw->g.max_defect.width = 0;
4415 fw->g.max_defect.height = 0;
4416 constrain_size(
4417 fw, NULL, &geometry->width, &geometry->height, 0, 0,
4418 CS_UPDATE_MAX_DEFECT);
4419 fw->g.max = *geometry;
4420 if (IS_SHADED(fw))
4422 get_shaded_geometry(fw, geometry, &fw->g.max);
4424 frame_setup_window(
4425 fw, geometry->x, geometry->y, geometry->width,
4426 geometry->height, True);
4427 border_draw_decorations(
4428 fw, PART_ALL, (Scr.Hilite == fw), True, CLEAR_ALL, NULL, NULL);
4429 update_absolute_geometry(fw);
4430 /* remember the offset between old and new position in case the
4431 * maximized window is moved more than the screen width/height. */
4432 fw->g.max_offset.x = fw->g.normal.x - fw->g.max.x;
4433 fw->g.max_offset.y = fw->g.normal.y - fw->g.max.y;
4434 #if 0
4435 fprintf(stderr,"%d %d %d %d, g.max_offset.x = %d, g.max_offset.y = %d, %d %d %d %d\n", fw->g.max.x, fw->g.max.y, fw->g.max.width, fw->g.max.height, fw->g.max_offset.x, fw->g.max_offset.y, fw->g.normal.x, fw->g.normal.y, fw->g.normal.width, fw->g.normal.height);
4436 #endif
4438 return;
4443 * Procedure:
4444 * (Un)Maximize a window.
4447 void CMD_Maximize(F_CMD_ARGS)
4449 int page_x, page_y;
4450 int val1, val2, val1_unit, val2_unit;
4451 int toggle;
4452 char *token;
4453 char *taction;
4454 Bool grow_up = False;
4455 Bool grow_down = False;
4456 Bool grow_left = False;
4457 Bool grow_right = False;
4458 Bool do_force_maximize = False;
4459 Bool is_screen_given = False;
4460 Bool ignore_working_area = False;
4461 int layers[2] = { -1, -1 };
4462 Bool global_flag_parsed = False;
4463 int scr_x, scr_y;
4464 int scr_w, scr_h;
4465 rectangle new_g;
4466 FvwmWindow *fw = exc->w.fw;
4468 if (
4469 !is_function_allowed(
4470 F_MAXIMIZE, NULL, fw, RQORIG_PROGRAM_US, False))
4472 XBell(dpy, 0);
4473 return;
4475 /* Check for "global" flag ("absolute" is for compatibility with E) */
4476 while (!global_flag_parsed)
4478 token = PeekToken(action, &taction);
4479 if (!token)
4481 global_flag_parsed = True;
4483 else
4485 if (StrEquals(token, "screen"))
4487 int scr;
4489 is_screen_given = True;
4490 token = PeekToken(taction, &action);
4491 scr = FScreenGetScreenArgument(
4492 token, FSCREEN_SPEC_PRIMARY);
4493 FScreenGetScrRect(
4494 NULL, scr, &scr_x, &scr_y, &scr_w,
4495 &scr_h);
4497 else if (StrEquals(token, "ewmhiwa"))
4499 ignore_working_area = True;
4500 action = taction;
4502 else if (StrEquals(token, "growonwindowlayer"))
4504 layers[0] = fw->layer;
4505 layers[1] = fw->layer;
4506 action = taction;
4508 else if (StrEquals(token, "growonlayers"))
4510 int n;
4512 n = GetIntegerArguments(
4513 taction, &action, layers, 2);
4514 if (n != 2)
4516 layers[0] = -1;
4517 layers[1] = -1;
4520 else
4522 global_flag_parsed = True;
4526 toggle = ParseToggleArgument(action, &action, -1, 0);
4527 if (toggle == 0 && !IS_MAXIMIZED(fw))
4529 return;
4532 if (toggle == 1 && IS_MAXIMIZED(fw))
4534 /* Fake that the window is not maximized. */
4535 do_force_maximize = True;
4538 /* find the new page and geometry */
4539 new_g.x = fw->g.frame.x;
4540 new_g.y = fw->g.frame.y;
4541 new_g.width = fw->g.frame.width;
4542 new_g.height = fw->g.frame.height;
4543 get_page_offset_check_visible(&page_x, &page_y, fw);
4545 /* Check if we should constrain rectangle to some Xinerama screen */
4546 if (!is_screen_given)
4548 fscreen_scr_arg fscr;
4550 fscr.xypos.x = fw->g.frame.x + fw->g.frame.width / 2 - page_x;
4551 fscr.xypos.y = fw->g.frame.y + fw->g.frame.height / 2 - page_y;
4552 FScreenGetScrRect(
4553 &fscr, FSCREEN_XYPOS, &scr_x, &scr_y, &scr_w, &scr_h);
4556 if (!ignore_working_area)
4558 EWMH_GetWorkAreaIntersection(
4559 fw, &scr_x, &scr_y, &scr_w, &scr_h,
4560 EWMH_MAXIMIZE_MODE(fw));
4562 #if 0
4563 fprintf(stderr, "%s: page=(%d,%d), scr=(%d,%d, %dx%d)\n", __FUNCTION__,
4564 page_x, page_y, scr_x, scr_y, scr_w, scr_h);
4565 #endif
4567 /* parse first parameter */
4568 val1_unit = scr_w;
4569 token = PeekToken(action, &taction);
4570 if (token && StrEquals(token, "grow"))
4572 grow_left = True;
4573 grow_right = True;
4574 val1 = 100;
4575 val1_unit = scr_w;
4577 else if (token && StrEquals(token, "growleft"))
4579 grow_left = True;
4580 val1 = 100;
4581 val1_unit = scr_w;
4583 else if (token && StrEquals(token, "growright"))
4585 grow_right = True;
4586 val1 = 100;
4587 val1_unit = scr_w;
4589 else
4591 if (GetOnePercentArgument(token, &val1, &val1_unit) == 0)
4593 val1 = 100;
4594 val1_unit = scr_w;
4596 else if (val1 < 0)
4598 /* handle negative offsets */
4599 if (val1_unit == scr_w)
4601 val1 = 100 + val1;
4603 else
4605 val1 = scr_w + val1;
4610 /* parse second parameter */
4611 val2_unit = scr_h;
4612 token = PeekToken(taction, NULL);
4613 if (token && StrEquals(token, "grow"))
4615 grow_up = True;
4616 grow_down = True;
4617 val2 = 100;
4618 val2_unit = scr_h;
4620 else if (token && StrEquals(token, "growup"))
4622 grow_up = True;
4623 val2 = 100;
4624 val2_unit = scr_h;
4626 else if (token && StrEquals(token, "growdown"))
4628 grow_down = True;
4629 val2 = 100;
4630 val2_unit = scr_h;
4632 else
4634 if (GetOnePercentArgument(token, &val2, &val2_unit) == 0)
4636 val2 = 100;
4637 val2_unit = scr_h;
4639 else if (val2 < 0)
4641 /* handle negative offsets */
4642 if (val2_unit == scr_h)
4644 val2 = 100 + val2;
4646 else
4648 val2 = scr_h + val2;
4653 #if 0
4654 fprintf(stderr, "%s: page=(%d,%d), scr=(%d,%d, %dx%d)\n", __FUNCTION__,
4655 page_x, page_y, scr_x, scr_y, scr_w, scr_h);
4656 #endif
4658 if (IS_MAXIMIZED(fw) && !do_force_maximize)
4660 unmaximize_fvwm_window(fw);
4662 else /* maximize */
4664 /* handle command line arguments */
4665 if (grow_up || grow_down)
4667 MaximizeHeight(
4668 fw, new_g.width, new_g.x, &new_g.height,
4669 &new_g.y, grow_up, grow_down, page_y + scr_y,
4670 page_y + scr_y + scr_h, layers);
4672 else if (val2 > 0)
4674 new_g.height = val2 * val2_unit / 100;
4675 new_g.y = page_y + scr_y;
4677 if (grow_left || grow_right)
4679 MaximizeWidth(
4680 fw, &new_g.width, &new_g.x, new_g.height,
4681 new_g.y, grow_left, grow_right,
4682 page_x + scr_x, page_x + scr_x + scr_w,
4683 layers);
4685 else if (val1 >0)
4687 new_g.width = val1 * val1_unit / 100;
4688 new_g.x = page_x + scr_x;
4690 if (val1 == 0 && val2 == 0)
4692 new_g.x = page_x + scr_x;
4693 new_g.y = page_y + scr_y;
4694 new_g.height = scr_h;
4695 new_g.width = scr_w;
4697 /* now maximize it */
4698 maximize_fvwm_window(fw, &new_g);
4700 EWMH_SetWMState(fw, False);
4701 GNOME_SetWinArea(fw);
4703 return;
4708 * Same as CMD_Resize and CMD_ResizeMove, but the window ends up maximized
4709 * without touching the normal geometry.
4712 void CMD_ResizeMaximize(F_CMD_ARGS)
4714 rectangle normal_g;
4715 rectangle max_g;
4716 Bool was_resized;
4717 FvwmWindow *fw = exc->w.fw;
4719 /* keep a copy of the old geometry */
4720 normal_g = fw->g.normal;
4721 /* resize the window normally */
4722 was_resized = __resize_window(F_PASS_ARGS);
4723 if (was_resized == True)
4725 /* set the new geometry as the maximized geometry and restore
4726 * the old normal geometry */
4727 max_g = fw->g.normal;
4728 max_g.x -= Scr.Vx;
4729 max_g.y -= Scr.Vy;
4730 fw->g.normal = normal_g;
4731 /* and mark it as maximized */
4732 maximize_fvwm_window(fw, &max_g);
4734 EWMH_SetWMState(fw, False);
4736 return;
4739 void CMD_ResizeMoveMaximize(F_CMD_ARGS)
4741 rectangle normal_g;
4742 rectangle max_g;
4743 Bool was_resized;
4744 FvwmWindow *fw = exc->w.fw;
4746 /* keep a copy of the old geometry */
4747 normal_g = fw->g.normal;
4748 /* resize the window normally */
4749 was_resized = resize_move_window(F_PASS_ARGS);
4750 if (was_resized == True)
4752 /* set the new geometry as the maximized geometry and restore
4753 * the old normal geometry */
4754 max_g = fw->g.normal;
4755 max_g.x -= Scr.Vx;
4756 max_g.y -= Scr.Vy;
4757 fw->g.normal = normal_g;
4758 /* and mark it as maximized */
4759 maximize_fvwm_window(fw, &max_g);
4761 EWMH_SetWMState(fw, False);
4763 return;
4766 /* ----------------------------- stick code -------------------------------- */
4768 int stick_across_pages(F_CMD_ARGS, int toggle)
4770 FvwmWindow *fw = exc->w.fw;
4772 if ((toggle == 1 && IS_STICKY_ACROSS_PAGES(fw)) ||
4773 (toggle == 0 && !IS_STICKY_ACROSS_PAGES(fw)))
4775 return 0;
4777 if (IS_STICKY_ACROSS_PAGES(fw))
4779 SET_STICKY_ACROSS_PAGES(fw, 0);
4781 else
4783 if (!IsRectangleOnThisPage(&fw->g.frame, Scr.CurrentDesk))
4785 action = "";
4786 __move_window(F_PASS_ARGS, False, MOVE_PAGE);
4788 SET_STICKY_ACROSS_PAGES(fw, 1);
4791 return 1;
4794 int stick_across_desks(F_CMD_ARGS, int toggle)
4796 FvwmWindow *fw = exc->w.fw;
4798 if ((toggle == 1 && IS_STICKY_ACROSS_DESKS(fw)) ||
4799 (toggle == 0 && !IS_STICKY_ACROSS_DESKS(fw)))
4801 return 0;
4804 if (IS_STICKY_ACROSS_DESKS(fw))
4806 SET_STICKY_ACROSS_DESKS(fw, 0);
4807 fw->Desk = Scr.CurrentDesk;
4808 GNOME_SetDeskCount();
4809 GNOME_SetDesk(fw);
4811 else
4813 if (fw->Desk != Scr.CurrentDesk)
4815 do_move_window_to_desk(fw, Scr.CurrentDesk);
4817 SET_STICKY_ACROSS_DESKS(fw, 1);
4820 return 1;
4823 static void __handle_stick_exit(
4824 FvwmWindow *fw, int do_not_draw, int do_silently)
4826 if (do_not_draw == 0)
4828 border_draw_decorations(
4829 fw, PART_TITLE | PART_BUTTONS, (Scr.Hilite==fw), True,
4830 CLEAR_ALL, NULL, NULL);
4832 if (!do_silently)
4834 BroadcastConfig(M_CONFIGURE_WINDOW,fw);
4835 EWMH_SetWMState(fw, False);
4836 EWMH_SetWMDesktop(fw);
4837 GNOME_SetHints(fw);
4840 return;
4843 void handle_stick_across_pages(
4844 F_CMD_ARGS, int toggle, int do_not_draw, int do_silently)
4846 FvwmWindow *fw = exc->w.fw;
4847 int did_change;
4849 did_change = stick_across_pages(F_PASS_ARGS, toggle);
4850 if (did_change)
4852 __handle_stick_exit(fw, do_not_draw, do_silently);
4855 return;
4858 void handle_stick_across_desks(
4859 F_CMD_ARGS, int toggle, int do_not_draw, int do_silently)
4861 FvwmWindow *fw = exc->w.fw;
4862 int did_change;
4864 did_change = stick_across_desks(F_PASS_ARGS, toggle);
4865 if (did_change)
4867 __handle_stick_exit(fw, do_not_draw, do_silently);
4870 return;
4873 void handle_stick(
4874 F_CMD_ARGS, int toggle_page, int toggle_desk, int do_not_draw,
4875 int do_silently)
4877 FvwmWindow *fw = exc->w.fw;
4878 int did_change;
4880 did_change = 0;
4881 did_change |= stick_across_desks(F_PASS_ARGS, toggle_desk);
4882 did_change |= stick_across_pages(F_PASS_ARGS, toggle_page);
4883 if (did_change)
4885 __handle_stick_exit(fw, do_not_draw, do_silently);
4888 return;
4891 void CMD_Stick(F_CMD_ARGS)
4893 int toggle;
4895 toggle = ParseToggleArgument(action, &action, -1, 0);
4896 if (toggle == -1 && IS_STICKY_ACROSS_DESKS(exc->w.fw) !=
4897 IS_STICKY_ACROSS_PAGES(exc->w.fw))
4899 /* don't switch between only stickypage and only stickydesk.
4900 * rather switch it off completely */
4901 toggle = 0;
4903 handle_stick(F_PASS_ARGS, toggle, toggle, 0, 0);
4905 return;
4908 void CMD_StickAcrossPages(F_CMD_ARGS)
4910 int toggle;
4912 toggle = ParseToggleArgument(action, &action, -1, 0);
4913 handle_stick_across_pages(F_PASS_ARGS, toggle, 0, 0);
4915 return;
4918 void CMD_StickAcrossDesks(F_CMD_ARGS)
4920 int toggle;
4922 toggle = ParseToggleArgument(action, &action, -1, 0);
4923 handle_stick_across_desks(F_PASS_ARGS, toggle, 0, 0);
4925 return;