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
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
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"
46 #include "execcontext.h"
51 #include "menuparameters.h"
52 #include "module_list.h"
53 #include "module_interface.h"
61 #include "decorations.h"
63 #include "eventhandler.h"
64 #include "eventmask.h"
65 #include "colormaps.h"
68 #include "move_resize.h"
69 #include "functions.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
85 int cmsDelayDefault
= 10; /* milliseconds */
87 /* current geometry of size window */
88 static rectangle sizew_g
=
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 ----- */
118 * draw_move_resize_grid - move a window outline
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
)
141 m
= (height
- 5) / 2;
151 for (i
= 0; i
< n
; 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
;
165 rects
[i
].width
= width
- (off
<< 1);
166 rects
[i
].height
= height
- (n
<< 1);
169 if (height
- (n
<< 1) >= 10)
171 int off
= (height
- (n
<< 1)) / 3 + n
;
173 rects
[i
].y
= y
+ off
;
174 rects
[i
].width
= width
- (n
<< 1);
175 rects
[i
].height
= height
- (off
<< 1);
188 unsigned is_enabled
: 1;
196 static void draw_move_resize_grid(int x
, int y
, int width
, int height
)
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
)
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;
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
);
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
);
237 XDrawRectangles(dpy
, Scr
.Root
, Scr
.XorGC
, rects
, nrects
);
244 void switch_move_resize_grid(Bool state
)
248 if (move_resize_grid
.flags
.is_enabled
)
250 draw_move_resize_grid(0, 0, 0, 0);
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
);
276 static int ParsePositionArgumentSuffix(
277 float *ret_factor
, char *suffix
, float wfactor
, float sfactor
)
290 *ret_factor
= wfactor
;
294 *ret_factor
= sfactor
;
302 static int __get_shift(int val
, float factor
)
308 shift
= (int)(val
* factor
+ 0.5);
312 shift
= (int)(val
* factor
- 0.5);
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
)
326 if (s1
== 0 || *s1
== 0)
330 wfactor
= (float)window_size
/ 100;
331 /* get start position */
336 final_pos
= window_pos
;
347 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &JunkX
,
348 &JunkY
, &x
, &y
, &JunkMask
) == False
)
350 /* pointer is on a different screen - that's okay here
356 final_pos
= (is_x
) ? x
: y
;
362 final_pos
= screen_pos
;
370 if (sscanf(s1
, "-%d%n", &val
, &n
) >= 1)
372 /* i.e. -1, -+1 or --1 */
373 final_pos
+= (screen_size
- window_size
);
377 sscanf(s1
, "+%d%n", &val
, &n
) >= 1 ||
378 sscanf(s1
, "%d%n", &val
, &n
) >= 1)
380 /* i.e. 1, +1, ++1 or +-1 */
384 /* syntax error, ignore rest of string */
389 n
= ParsePositionArgumentSuffix(
390 &f
, s1
, wfactor
, sfactor
);
392 final_pos
+= __get_shift(val
, f
);
396 /* loop over shift arguments */
404 if (sscanf(s1
, "-%d%n", &val
, &n
) >= 1)
406 /* i.e. -1, -+1 or --1 */
410 sscanf(s1
, "+%d%n", &val
, &n
) >= 1 ||
411 sscanf(s1
, "%d%n", &val
, &n
) >= 1)
413 /* i.e. 1, +1, ++1 or +-1 */
417 /* syntax error, ignore rest of string */
422 n
= ParsePositionArgumentSuffix(&f
, s1
, wfactor
, sfactor
);
424 final_pos
+= __get_shift(val
, f
);
426 *pFinalPos
= final_pos
;
431 /* GetMoveArguments is used for Move & AnimatedMove
432 * It lets you specify in all the following ways
433 * 20 30 Absolute percent position, from left edge and top
434 * -50 50 Absolute percent position, from right edge and top
435 * 10p 5p Absolute pixel position
436 * 10p -0p Absolute pixel position, from bottom
437 * w+5 w-10p Relative position, right 5%, up ten pixels
438 * m+5 m-10p Pointer relative position, right 5%, up ten pixels
439 * Returns 2 when x & y have parsed without error, 0 otherwise
441 int GetMoveArguments(
442 char **paction
, int w
, int h
, int *pFinalX
, int *pFinalY
,
443 Bool
*fWarp
, Bool
*fPointer
, Bool fKeep
)
452 int scr_w
= Scr
.MyDisplayWidth
;
453 int scr_h
= Scr
.MyDisplayHeight
;
461 action
= GetNextToken(action
, &s1
);
462 if (s1
&& fPointer
&& StrEquals(s1
, "pointer"))
469 if (s1
&& StrEquals(s1
, "screen"))
474 fscreen_scr_arg
* parg
;
477 token
= PeekToken(action
, &action
);
478 scr
= FScreenGetScreenArgument(token
, FSCREEN_SPEC_PRIMARY
);
479 if (scr
== FSCREEN_XYPOS
)
481 arg
.xypos
.x
= *pFinalX
;
482 arg
.xypos
.y
= *pFinalY
;
489 FScreenGetScrRect(parg
, scr
, &scr_x
, &scr_y
, &scr_w
, &scr_h
);
490 action
= GetNextToken(action
, &s1
);
492 action
= GetNextToken(action
, &s2
);
495 warp
= PeekToken(action
, &naction
);
496 if (StrEquals(warp
, "Warp"))
503 if (s1
!= NULL
&& s2
!= NULL
)
506 if (fKeep
== True
&& StrEquals(s1
, "keep"))
511 GetOnePositionArgument(
512 s1
, *pFinalX
, w
, pFinalX
, (float)scr_w
/ 100,
517 if (fKeep
== True
&& StrEquals(s2
, "keep"))
522 GetOnePositionArgument(
523 s2
, *pFinalY
, h
, pFinalY
, (float)scr_h
/ 100,
524 scr_h
, scr_y
, False
))
530 /* make sure warping is off for interactive moves */
536 /* not enough arguments, switch to current page. */
539 *pFinalX
= Scr
.MyDisplayWidth
+ *pFinalX
;
543 *pFinalY
= Scr
.MyDisplayHeight
+ *pFinalY
;
560 static int ParseOneResizeArgument(
561 char *arg
, int scr_size
, int base_size
, int size_inc
, int add_size
,
566 int add_base_size
= 0;
567 int cch
= strlen(arg
);
574 if (StrEquals(arg
, "keep"))
576 /* do not change size */
579 if (arg
[cch
-1] == 'p')
584 else if (arg
[cch
-1] == 'c')
587 add_base_size
= base_size
;
592 factor
= (float)scr_size
/ 100.0;
594 if (strcmp(arg
,"w") == 0)
596 /* do not change size */
598 else if (sscanf(arg
,"w-%d",&val
) == 1)
600 tmp_size
= (int)(val
* factor
+ 0.5);
601 if (tmp_size
< *ret_size
)
603 *ret_size
-= tmp_size
;
610 else if (sscanf(arg
,"w+%d",&val
) == 1 || sscanf(arg
,"w%d",&val
) == 1)
612 tmp_size
= (int)(val
* factor
+ 0.5);
613 if (-tmp_size
< *ret_size
)
615 *ret_size
+= tmp_size
;
622 else if (sscanf(arg
,"-%d",&val
) == 1)
624 tmp_size
= (int)(val
* factor
+ 0.5);
625 if (tmp_size
< scr_size
+ add_size
)
627 *ret_size
= scr_size
- tmp_size
+ add_size
;
634 else if (sscanf(arg
,"+%d",&val
) == 1 || sscanf(arg
,"%d",&val
) == 1)
636 tmp_size
= (int)(val
* factor
+ 0.5);
637 if (-tmp_size
< add_size
+ add_base_size
)
639 *ret_size
= tmp_size
+ add_size
+ add_base_size
;
654 static int GetResizeArguments(
655 char **paction
, int x
, int y
, int w_base
, int h_base
, int w_inc
,
656 int h_inc
, size_borders
*sb
, int *pFinalW
, int *pFinalH
,
657 direction_t
*ret_dir
, Bool
*is_direction_fixed
,
658 Bool
*do_warp_to_border
)
667 int has_frame_option
;
670 *is_direction_fixed
= False
;
671 *do_warp_to_border
= False
;
676 token
= PeekToken(*paction
, &naction
);
681 if (StrEquals(token
, "bottomright") || StrEquals(token
, "br"))
683 int nx
= x
+ *pFinalW
- 1;
684 int ny
= y
+ *pFinalH
- 1;
686 n
= GetMoveArguments(
687 &naction
, 0, 0, &nx
, &ny
, NULL
, NULL
, True
);
692 *pFinalW
= nx
- x
+ 1;
693 *pFinalH
= ny
- y
+ 1;
698 has_frame_option
= 0;
699 for ( ; ; token
= PeekToken(naction
, &naction
))
701 if (StrEquals(token
, "frame"))
703 has_frame_option
= 1;
705 else if (StrEquals(token
, "direction"))
711 *ret_dir
= gravity_parse_dir_argument(
712 naction
, &naction
, DIR_NONE
);
713 if (*ret_dir
!= DIR_NONE
)
715 *is_direction_fixed
= True
;
718 else if (StrEquals(token
, "fixeddirection"))
720 *is_direction_fixed
= True
;
722 else if (StrEquals(token
, "warptoborder"))
724 *do_warp_to_border
= True
;
731 if (has_frame_option
)
738 w_add
= sb
->total_size
.width
;
739 h_add
= sb
->total_size
.height
;
744 s1
= safestrdup(token
);
746 naction
= GetNextToken(naction
, &s2
);
758 n
+= ParseOneResizeArgument(
759 s1
, Scr
.MyDisplayWidth
, w_base
, w_inc
, w_add
, pFinalW
);
760 n
+= ParseOneResizeArgument(
761 s2
, Scr
.MyDisplayHeight
, h_base
, h_inc
, h_add
, pFinalH
);
778 static int GetResizeMoveArguments(
779 char **paction
, int w_base
, int h_base
, int w_inc
, int h_inc
,
780 size_borders
*sb
, int *pFinalX
, int *pFinalY
,
781 int *pFinalW
, int *pFinalH
, Bool
*fWarp
, Bool
*fPointer
)
783 char *action
= *paction
;
791 if (GetResizeArguments(
792 &action
, *pFinalX
, *pFinalY
, w_base
, h_base
, w_inc
, h_inc
,
793 sb
, pFinalW
, pFinalH
, &dir
, &dummy
, &dummy
) < 2)
797 if (GetMoveArguments(
798 &action
, *pFinalW
, *pFinalH
, pFinalX
, pFinalY
, fWarp
,
808 /* Positions the SizeWindow on the current ("moused") xinerama-screen */
809 static void position_geometry_window(const XEvent
*eventp
)
813 fscreen_scr_arg fscr
;
815 fscr
.mouse_ev
= (XEvent
*)eventp
;
816 /* Probably should remove this positioning code from {builtins,fvwm}.c?
818 if (Scr
.gs
.do_emulate_mwm
)
820 FScreenCenterOnScreen(
821 &fscr
, FSCREEN_CURRENT
, &x
, &y
, sizew_g
.width
,
826 FScreenGetScrRect(&fscr
, FSCREEN_CURRENT
, &x
, &y
, NULL
, NULL
);
828 if (x
!= sizew_g
.x
|| y
!= sizew_g
.y
)
830 switch_move_resize_grid(False
);
831 XMoveWindow(dpy
, Scr
.SizeWindow
, x
, y
);
832 switch_move_resize_grid(True
);
840 void resize_geometry_window(void)
844 int cset
= Scr
.DefaultColorset
;
846 Scr
.SizeStringWidth
=
847 FlocaleTextWidth(Scr
.DefaultFont
, GEOMETRY_WINDOW_STRING
,
848 sizeof(GEOMETRY_WINDOW_STRING
) - 1);
849 w
= Scr
.SizeStringWidth
+ 2 * GEOMETRY_WINDOW_BW
;
850 h
= Scr
.DefaultFont
->height
+ 2 * GEOMETRY_WINDOW_BW
;
851 if (w
!= sizew_g
.width
|| h
!= sizew_g
.height
)
853 XResizeWindow(dpy
, Scr
.SizeWindow
, w
, h
);
860 dpy
, Scr
.SizeWindow
, w
, h
, &Colorset
[cset
], Pdepth
,
865 XSetWindowBackground(dpy
, Scr
.SizeWindow
, Scr
.StdBack
);
874 * DisplayPosition - display the position in the dimensions window
877 * tmp_win - the current fvwm window
878 * x, y - position of the window
882 static void DisplayPosition(
883 const FvwmWindow
*tmp_win
, const XEvent
*eventp
, int x
, int y
,int Init
)
887 fscreen_scr_arg fscr
;
888 FlocaleWinString fstr
;
890 if (Scr
.gs
.do_hide_position_window
)
894 position_geometry_window(eventp
);
895 /* Translate x,y into local screen coordinates,
896 * in case Xinerama is used. */
899 FScreenTranslateCoordinates(
900 NULL
, FSCREEN_GLOBAL
, &fscr
, FSCREEN_XYPOS
, &x
, &y
);
901 (void)sprintf(str
, GEOMETRY_WINDOW_POS_STRING
, x
, y
);
904 XClearWindow(dpy
, Scr
.SizeWindow
);
908 /* just clear indside the relief lines to reduce flicker */
909 XClearArea(dpy
, Scr
.SizeWindow
,
910 GEOMETRY_WINDOW_BW
, GEOMETRY_WINDOW_BW
,
911 Scr
.SizeStringWidth
, Scr
.DefaultFont
->height
, False
);
917 dpy
, Scr
.SizeWindow
, 0, 0,
918 Scr
.SizeStringWidth
+ GEOMETRY_WINDOW_BW
* 2 - 1,
919 Scr
.DefaultFont
->height
+ GEOMETRY_WINDOW_BW
* 2 - 1,
920 Scr
.StdReliefGC
, Scr
.StdShadowGC
, GEOMETRY_WINDOW_BW
);
922 offset
= (Scr
.SizeStringWidth
-
923 FlocaleTextWidth(Scr
.DefaultFont
, str
, strlen(str
))) / 2;
924 offset
+= GEOMETRY_WINDOW_BW
;
926 memset(&fstr
, 0, sizeof(fstr
));
927 if (Scr
.DefaultColorset
>= 0)
929 fstr
.colorset
= &Colorset
[Scr
.DefaultColorset
];
930 fstr
.flags
.has_colorset
= True
;
933 fstr
.win
= Scr
.SizeWindow
;
936 fstr
.y
= Scr
.DefaultFont
->ascent
+ GEOMETRY_WINDOW_BW
;
937 FlocaleDrawString(dpy
, Scr
.DefaultFont
, &fstr
, 0);
946 * DisplaySize - display the size in the dimensions window
949 * tmp_win - the current fvwm window
950 * width - the width of the rubber band
951 * height - the height of the rubber band
954 static void DisplaySize(
955 const FvwmWindow
*tmp_win
, const XEvent
*eventp
, int width
,
956 int height
, Bool Init
, Bool resetLast
)
959 int dwidth
,dheight
,offset
;
961 static int last_width
= 0;
962 static int last_height
= 0;
963 FlocaleWinString fstr
;
965 if (Scr
.gs
.do_hide_resize_window
)
969 position_geometry_window(eventp
);
975 if (last_width
== width
&& last_height
== height
)
980 last_height
= height
;
982 get_window_borders(tmp_win
, &b
);
983 dheight
= height
- b
.total_size
.height
;
984 dwidth
= width
- b
.total_size
.width
;
985 dwidth
-= tmp_win
->hints
.base_width
;
986 dheight
-= tmp_win
->hints
.base_height
;
987 dwidth
/= tmp_win
->hints
.width_inc
;
988 dheight
/= tmp_win
->hints
.height_inc
;
990 (void)sprintf(str
, GEOMETRY_WINDOW_SIZE_STRING
, dwidth
, dheight
);
993 XClearWindow(dpy
,Scr
.SizeWindow
);
997 /* just clear indside the relief lines to reduce flicker */
999 dpy
, Scr
.SizeWindow
, GEOMETRY_WINDOW_BW
,
1000 GEOMETRY_WINDOW_BW
, Scr
.SizeStringWidth
,
1001 Scr
.DefaultFont
->height
, False
);
1007 dpy
, Scr
.SizeWindow
, 0, 0,
1008 Scr
.SizeStringWidth
+ GEOMETRY_WINDOW_BW
* 2 - 1,
1009 Scr
.DefaultFont
->height
+ GEOMETRY_WINDOW_BW
*2 - 1,
1010 Scr
.StdReliefGC
, Scr
.StdShadowGC
, GEOMETRY_WINDOW_BW
);
1012 offset
= (Scr
.SizeStringWidth
-
1013 FlocaleTextWidth(Scr
.DefaultFont
, str
, strlen(str
))) / 2;
1014 offset
+= GEOMETRY_WINDOW_BW
;
1015 memset(&fstr
, 0, sizeof(fstr
));
1016 if (Scr
.DefaultColorset
>= 0)
1018 fstr
.colorset
= &Colorset
[Scr
.DefaultColorset
];
1019 fstr
.flags
.has_colorset
= True
;
1022 fstr
.win
= Scr
.SizeWindow
;
1023 fstr
.gc
= Scr
.StdGC
;
1025 fstr
.y
= Scr
.DefaultFont
->ascent
+ GEOMETRY_WINDOW_BW
;
1026 FlocaleDrawString(dpy
, Scr
.DefaultFont
, &fstr
, 0);
1031 static Bool
resize_move_window(F_CMD_ARGS
)
1040 Bool fPointer
= False
;
1045 FvwmWindow
*fw
= exc
->w
.fw
;
1046 Window w
= exc
->w
.w
;
1048 if (!is_function_allowed(F_MOVE
, NULL
, fw
, RQORIG_PROGRAM_US
, False
))
1052 if (!is_function_allowed(F_RESIZE
, NULL
, fw
, RQORIG_PROGRAM_US
, True
))
1057 /* gotta have a window */
1060 dpy
, w
, &JunkRoot
, &x
, &y
, (unsigned int*)&FinalW
,
1061 (unsigned int*)&FinalH
, (unsigned int*)&JunkBW
,
1062 (unsigned int*)&JunkDepth
))
1071 get_window_borders(fw
, &b
);
1072 n
= GetResizeMoveArguments(
1074 fw
->hints
.base_width
, fw
->hints
.base_height
,
1075 fw
->hints
.width_inc
, fw
->hints
.height_inc
,
1076 &b
, &FinalX
, &FinalY
, &FinalW
, &FinalH
, &fWarp
, &fPointer
);
1082 if (IS_MAXIMIZED(fw
))
1084 /* must redraw the buttons now so that the 'maximize' button
1085 * does not stay depressed. */
1086 SET_MAXIMIZED(fw
, 0);
1087 border_draw_decorations(
1088 fw
, PART_BUTTONS
, (fw
== Scr
.Hilite
), True
, CLEAR_ALL
,
1091 dx
= FinalX
- fw
->g
.frame
.x
;
1092 dy
= FinalY
- fw
->g
.frame
.y
;
1093 /* size will be less or equal to requested */
1094 constrain_size(fw
, NULL
, &FinalW
, &FinalH
, 0, 0, 0);
1098 fw
, FinalX
, FinalY
, FinalW
, fw
->g
.frame
.height
, False
);
1102 frame_setup_window(fw
, FinalX
, FinalY
, FinalW
, FinalH
, True
);
1107 dpy
, None
, None
, 0, 0, 0, 0, FinalX
- x
, FinalY
- y
);
1109 if (IS_MAXIMIZED(fw
))
1116 fw
->g
.normal
.x
+= dx
;
1117 fw
->g
.normal
.y
+= dy
;
1119 has_focus
= (fw
== get_focus_window())? True
: False
;
1120 update_absolute_geometry(fw
);
1121 maximize_adjust_offset(fw
);
1123 GNOME_SetWinArea(fw
);
1128 void CMD_ResizeMove(F_CMD_ARGS
)
1130 FvwmWindow
*fw
= exc
->w
.fw
;
1132 if (IS_EWMH_FULLSCREEN(fw
))
1134 /* do not unmaximize ! */
1135 CMD_ResizeMoveMaximize(F_PASS_ARGS
);
1138 resize_move_window(F_PASS_ARGS
);
1143 static void InteractiveMove(
1144 Window
*win
, const exec_context_t
*exc
, int *FinalX
, int *FinalY
,
1145 Bool do_start_at_pointer
)
1147 int origDragX
,origDragY
,DragX
, DragY
, DragWidth
, DragHeight
;
1148 int XOffset
, YOffset
;
1150 Bool do_move_opaque
= False
;
1154 if (Scr
.bo
.do_install_root_cmap
)
1156 InstallRootColormap();
1160 InstallFvwmColormap();
1162 /* warp the pointer to the cursor position from before menu appeared */
1163 /* domivogt (17-May-1999): an XFlush should not hurt anyway, so do it
1164 * unconditionally to remove the external */
1167 if (do_start_at_pointer
)
1170 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &DragX
,
1171 &DragY
, &JunkX
, &JunkY
, &JunkMask
) == False
)
1173 /* pointer is on a different screen */
1180 /* Although a move is usually done with a button depressed we
1181 * have to check for ButtonRelease too since the event may be
1183 fev_get_evpos_or_query(
1184 dpy
, Scr
.Root
, exc
->x
.elast
, &DragX
, &DragY
);
1189 dpy
, w
, &JunkRoot
, &origDragX
, &origDragY
,
1190 (unsigned int*)&DragWidth
, (unsigned int*)&DragHeight
,
1191 (unsigned int*)&JunkBW
, (unsigned int*)&JunkDepth
))
1193 MyXUngrabServer(dpy
);
1196 MyXGrabKeyboard(dpy
);
1197 if (do_start_at_pointer
)
1203 if (IS_ICONIFIED(exc
->w
.fw
))
1205 do_move_opaque
= True
;
1207 else if (IS_MAPPED(exc
->w
.fw
))
1212 areapct
*= ((float)DragWidth
/ (float)Scr
.MyDisplayWidth
);
1213 areapct
*= ((float)DragHeight
/ (float)Scr
.MyDisplayHeight
);
1216 if (Scr
.OpaqueSize
< 0 ||
1217 (float)areapct
<= (float)Scr
.OpaqueSize
)
1219 do_move_opaque
= True
;
1224 MyXUngrabServer(dpy
);
1228 Scr
.flags
.is_wire_frame_displayed
= True
;
1231 if (!do_move_opaque
&& IS_ICONIFIED(exc
->w
.fw
))
1233 XUnmapWindow(dpy
,w
);
1236 XOffset
= origDragX
- DragX
;
1237 YOffset
= origDragY
- DragY
;
1238 if (!Scr
.gs
.do_hide_position_window
)
1240 position_geometry_window(NULL
);
1241 XMapRaised(dpy
,Scr
.SizeWindow
);
1244 exc
, XOffset
, YOffset
, DragWidth
, DragHeight
, FinalX
, FinalY
,
1245 do_move_opaque
, CRS_MOVE
);
1246 if (!Scr
.gs
.do_hide_position_window
)
1248 XUnmapWindow(dpy
,Scr
.SizeWindow
);
1250 if (Scr
.bo
.do_install_root_cmap
)
1252 UninstallRootColormap();
1256 UninstallFvwmColormap();
1259 if (!do_move_opaque
)
1261 /* Throw away some events that dont interest us right now. */
1262 discard_events(EnterWindowMask
|LeaveWindowMask
);
1263 Scr
.flags
.is_wire_frame_displayed
= False
;
1264 MyXUngrabServer(dpy
);
1266 MyXUngrabKeyboard(dpy
);
1271 /* Perform the movement of the window. ppctMovement *must* have a 1.0 entry
1272 * somewhere in ins list of floats, and movement will stop when it hits a 1.0
1274 static void AnimatedMoveAnyWindow(
1275 FvwmWindow
*fw
, Window w
, int startX
, int startY
, int endX
,
1276 int endY
, Bool fWarpPointerToo
, int cmsDelay
, float *ppctMovement
,
1277 MenuRepaintTransparentParameters
*pmrtp
)
1279 int pointerX
, pointerY
;
1280 int currentX
, currentY
;
1285 unsigned int draw_parts
= PART_NONE
;
1287 if (!is_function_allowed(F_MOVE
, NULL
, fw
, RQORIG_PROGRAM_US
, False
))
1292 /* set our defaults */
1293 if (ppctMovement
== NULL
)
1295 ppctMovement
= rgpctMovementDefault
;
1299 cmsDelay
= cmsDelayDefault
;
1302 if (startX
< 0 || startY
< 0)
1306 dpy
, w
, &JunkRoot
, ¤tX
, ¤tY
,
1307 (unsigned int*)&JunkWidth
,
1308 (unsigned int*)&JunkHeight
,
1309 (unsigned int*)&JunkBW
,
1310 (unsigned int*)&JunkDepth
))
1325 deltaX
= endX
- startX
;
1326 deltaY
= endY
- startY
;
1330 if (deltaX
== 0 && deltaY
== 0)
1332 /* go nowhere fast */
1336 if (fw
&& w
== FW_W_FRAME(fw
))
1338 draw_parts
= border_get_transparent_decorations_part(fw
);
1341 /* Needed for aborting */
1342 MyXGrabKeyboard(dpy
);
1345 currentX
= startX
+ deltaX
* (*ppctMovement
);
1346 currentY
= startY
+ deltaY
* (*ppctMovement
);
1347 if (lastX
== currentX
&& lastY
== currentY
)
1349 /* don't waste time in the same spot */
1354 update_transparent_menu_bg(
1355 pmrtp
, lastX
, lastY
, currentX
, currentY
,
1358 XMoveWindow(dpy
,w
,currentX
,currentY
);
1361 repaint_transparent_menu(
1363 currentX
, currentY
, endX
, endY
, True
);
1365 else if (draw_parts
!= PART_NONE
)
1367 border_draw_decorations(
1369 ((fw
== get_focus_window())) ?
1371 True
, CLEAR_ALL
, NULL
, NULL
);
1373 if (fw
&& pmrtp
== NULL
&& IS_TEAR_OFF_MENU(fw
))
1375 menu_redraw_transparent_tear_off_menu(fw
, False
);
1377 if (fWarpPointerToo
== True
)
1380 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
,
1381 &JunkX
, &JunkY
, &pointerX
, &pointerY
,
1382 &JunkMask
) == False
)
1384 /* pointer is on a different screen */
1385 pointerX
= currentX
;
1386 pointerY
= currentY
;
1390 pointerX
+= currentX
- lastX
;
1391 pointerY
+= currentY
- lastY
;
1394 dpy
, None
, Scr
.Root
, 0, 0, 0, 0, pointerX
,
1397 if (fw
&& !IS_SHADED(fw
) && !Scr
.bo
.do_disable_configure_notify
)
1399 /* send configure notify event for windows that care
1400 * about their location */
1401 SendConfigureNotify(
1402 fw
, currentX
, currentY
,
1404 fw
->g
.frame
.height
, 0, False
);
1405 #ifdef FVWM_DEBUG_MSGS
1406 fvwm_msg(DBG
,"AnimatedMoveAnyWindow",
1407 "Sent ConfigureNotify (w == %d, h == %d)",
1409 fw
->g
.frame
.height
);
1415 fw
->g
.frame
.x
= currentX
;
1416 fw
->g
.frame
.y
= currentY
;
1417 update_absolute_geometry(fw
);
1418 maximize_adjust_offset(fw
);
1419 BroadcastConfig(M_CONFIGURE_WINDOW
, fw
);
1420 FlushAllMessageQueues();
1423 usleep(cmsDelay
* 1000); /* usleep takes microseconds */
1424 /* this didn't work for me -- maybe no longer necessary since
1425 * we warn the user when they use > .5 seconds as a
1426 * between-frame delay time.
1428 * domivogt (28-apr-1999): That is because the keyboard was not
1429 * grabbed. works nicely now.
1431 if (FCheckMaskEvent(
1432 dpy
, ButtonPressMask
|ButtonReleaseMask
|KeyPressMask
,
1435 /* finish the move immediately */
1438 update_transparent_menu_bg(
1439 pmrtp
, lastX
, lastY
,
1440 currentX
, currentY
, endX
, endY
);
1442 XMoveWindow(dpy
,w
,endX
,endY
);
1445 repaint_transparent_menu(
1447 endX
, endY
, endX
, endY
, True
);
1454 } while (*ppctMovement
!= 1.0 && ppctMovement
++);
1455 MyXUngrabKeyboard(dpy
);
1459 GNOME_SetWinArea(fw
);
1465 /* used for moving menus, not a client window */
1466 void AnimatedMoveOfWindow(
1467 Window w
, int startX
, int startY
, int endX
, int endY
,
1468 Bool fWarpPointerToo
, int cmsDelay
, float *ppctMovement
,
1469 MenuRepaintTransparentParameters
*pmrtp
)
1471 AnimatedMoveAnyWindow(
1472 NULL
, w
, startX
, startY
, endX
, endY
, fWarpPointerToo
,
1473 cmsDelay
, ppctMovement
, pmrtp
);
1478 /* used for moving client windows */
1479 void AnimatedMoveFvwmWindow(
1480 FvwmWindow
*fw
, Window w
, int startX
, int startY
, int endX
,
1481 int endY
, Bool fWarpPointerToo
, int cmsDelay
, float *ppctMovement
)
1483 AnimatedMoveAnyWindow(
1484 fw
, w
, startX
, startY
, endX
, endY
, fWarpPointerToo
,
1485 cmsDelay
, ppctMovement
, NULL
);
1490 int placement_binding(int button
, KeySym keysym
, int modifier
, char *action
)
1496 ERR
, "placement_binding",
1497 "sorry, placement keybindings not allowed. yet.");
1504 ERR
, "placement_binding",
1505 "sorry, placement binding modifiers not allowed. yet.");
1508 if (strcmp(action
,"-") == 0 ||
1509 strcasecmp(action
,"CancelPlacement") == 0)
1511 if (keysym
== 0) /* must be button binding */
1515 move_drag_finish_button_mask
= 0;
1516 move_interactive_finish_button_mask
= 0;
1518 else if (button
> 0 && button
<=
1519 NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)
1521 move_drag_finish_button_mask
&=
1523 move_interactive_finish_button_mask
&=
1528 else if (strcasecmp(action
,"CancelPlacementDrag") == 0)
1530 if (keysym
== 0) /* must be button binding */
1534 move_drag_finish_button_mask
= 0;
1536 else if (button
> 0 && button
<=
1537 NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)
1539 move_drag_finish_button_mask
&=
1544 else if (strcasecmp(action
,"CancelPlacementInteractive") == 0)
1546 if (keysym
== 0) /* must be button binding */
1550 move_interactive_finish_button_mask
= 0;
1552 else if (button
> 0 && button
<=
1553 NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)
1555 move_interactive_finish_button_mask
&=
1560 else if (strcasecmp(action
,"PlaceWindow") == 0)
1562 if (keysym
== 0) /* must be button binding */
1566 move_interactive_finish_button_mask
=
1567 move_drag_finish_button_mask
=
1568 (1<<NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)-1;
1570 else if (button
> 0 && button
<=
1571 NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)
1573 move_drag_finish_button_mask
|= (1<<(button
-1));
1574 move_interactive_finish_button_mask
|=
1579 else if (strcasecmp(action
,"PlaceWindowDrag") == 0)
1581 if (keysym
== 0) /* must be button binding */
1585 move_drag_finish_button_mask
=
1586 (1<<NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)-1;
1588 else if (button
> 0 && button
<=
1589 NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)
1591 move_drag_finish_button_mask
|= (1<<(button
-1));
1595 else if (strcasecmp(action
,"PlaceWindowInteractive") == 0)
1597 if (keysym
== 0) /* must be button binding */
1601 move_interactive_finish_button_mask
=
1602 (1<<NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)-1;
1604 else if (button
> 0 && button
<=
1605 NUMBER_OF_EXTENDED_MOUSE_BUTTONS
)
1607 move_interactive_finish_button_mask
|=
1615 ERR
, "placement_binding",
1616 "invalid action %s", action
);
1625 * Start a window move operation
1629 FvwmWindow
*fw
, int x
, int y
, int old_x
, int old_y
,
1630 Bool do_move_animated
, Bool do_warp_pointer
)
1634 Bool has_icon_title
;
1635 Bool has_icon_picture
;
1640 set_icon_position(fw
, x
, y
);
1641 broadcast_icon_geometry(fw
, False
);
1642 has_icon_title
= get_visible_icon_title_geometry(fw
, >
);
1643 has_icon_picture
= get_visible_icon_picture_geometry(fw
, &gp
);
1644 if (has_icon_picture
)
1646 tw
= FW_W_ICON_PIXMAP(fw
);
1650 else if (has_icon_title
)
1652 tw
= FW_W_ICON_TITLE(fw
);
1660 if (do_move_animated
)
1662 AnimatedMoveOfWindow(
1663 tw
, -1, -1, tx
, ty
, do_warp_pointer
, -1, NULL
, NULL
);
1664 do_warp_pointer
= 0;
1668 XMoveWindow(dpy
, FW_W_ICON_TITLE(fw
), gt
.x
, gt
.y
);
1670 if (has_icon_picture
)
1672 XMoveWindow(dpy
, FW_W_ICON_PIXMAP(fw
), gp
.x
, gp
.y
);
1673 if (fw
->Desk
== Scr
.CurrentDesk
)
1675 XMapWindow(dpy
, FW_W_ICON_PIXMAP(fw
));
1678 XMapWindow(dpy
, FW_W_ICON_TITLE(fw
));
1682 if (do_warp_pointer
)
1684 FWarpPointer(dpy
, None
, None
, 0, 0, 0, 0, x
- old_x
, y
- old_y
);
1690 static void __move_window(F_CMD_ARGS
, Bool do_animate
, int mode
)
1700 Bool fPointer
= False
;
1703 FvwmWindow
*fw
= exc
->w
.fw
;
1706 if (!is_function_allowed(F_MOVE
, NULL
, fw
, RQORIG_PROGRAM_US
, False
))
1710 /* gotta have a window */
1712 if (IS_ICONIFIED(fw
))
1714 if (FW_W_ICON_PIXMAP(fw
) != None
)
1716 w
= FW_W_ICON_PIXMAP(fw
);
1717 XUnmapWindow(dpy
,FW_W_ICON_TITLE(fw
));
1721 w
= FW_W_ICON_TITLE(fw
);
1723 if (w
== None
&& (mode
== MOVE_PAGE
|| mode
== MOVE_SCREEN
))
1730 dpy
, w
, &JunkRoot
, &x
, &y
, (unsigned int*)&width
,
1731 (unsigned int*)&height
, (unsigned int*)&JunkBW
,
1732 (unsigned int*)&JunkDepth
))
1736 if (mode
== MOVE_PAGE
&& IS_STICKY_ACROSS_PAGES(fw
))
1740 if (mode
== MOVE_PAGE
)
1751 get_absolute_geometry(&t
, &r
);
1752 get_page_offset_rectangle(&page_x
, &page_y
, &t
);
1753 if (!get_page_arguments(action
, &page_x
, &page_y
))
1758 s
.x
= page_x
- Scr
.Vx
;
1759 s
.y
= page_y
- Scr
.Vy
;
1760 s
.width
= Scr
.MyDisplayWidth
;
1761 s
.height
= Scr
.MyDisplayHeight
;
1762 fvwmrect_move_into_rectangle(&r
, &s
);
1766 else if (mode
== MOVE_SCREEN
)
1774 fscreen
= FScreenGetScreenArgument(
1775 action
, FSCREEN_SPEC_CURRENT
);
1777 NULL
, fscreen
, &s
.x
, &s
.y
, &s
.width
, &s
.height
);
1784 p
.x
= page_x
- Scr
.Vx
;
1785 p
.y
= page_y
- Scr
.Vy
;
1786 p
.width
= Scr
.MyDisplayWidth
;
1787 p
.height
= Scr
.MyDisplayHeight
;
1788 /* move to page first */
1789 fvwmrect_move_into_rectangle(&r
, &p
);
1790 /* then move to screen */
1791 fvwmrect_move_into_rectangle(&r
, &s
);
1799 n
= GetMoveArguments(
1800 &action
, width
, height
, &FinalX
, &FinalY
, &fWarp
,
1803 if (n
!= 2 || fPointer
)
1805 InteractiveMove(&w
, exc
, &FinalX
, &FinalY
, fPointer
);
1807 else if (IS_ICONIFIED(fw
))
1809 SET_ICON_MOVED(fw
, 1);
1813 if (w
== FW_W_FRAME(fw
))
1815 dx
= FinalX
- fw
->g
.frame
.x
;
1816 dy
= FinalY
- fw
->g
.frame
.y
;
1819 AnimatedMoveFvwmWindow(
1820 fw
, w
, -1, -1, FinalX
, FinalY
, fWarp
, -1,
1824 fw
, FinalX
, FinalY
, fw
->g
.frame
.width
,
1825 fw
->g
.frame
.height
, True
);
1826 if (fWarp
& !do_animate
)
1829 dpy
, None
, None
, 0, 0, 0, 0, FinalX
- x
,
1832 if (IS_MAXIMIZED(fw
))
1839 fw
->g
.normal
.x
+= dx
;
1840 fw
->g
.normal
.y
+= dy
;
1842 update_absolute_geometry(fw
);
1843 maximize_adjust_offset(fw
);
1845 GNOME_SetWinArea(fw
);
1847 else /* icon window */
1849 __move_icon(fw
, FinalX
, FinalY
, x
, y
, do_animate
, fWarp
);
1852 focus_grab_buttons_on_layer(fw
->layer
);
1857 void CMD_Move(F_CMD_ARGS
)
1859 __move_window(F_PASS_ARGS
, False
, MOVE_NORMAL
);
1864 void CMD_AnimatedMove(F_CMD_ARGS
)
1866 __move_window(F_PASS_ARGS
, True
, MOVE_NORMAL
);
1871 void CMD_MoveToPage(F_CMD_ARGS
)
1873 __move_window(F_PASS_ARGS
, False
, MOVE_PAGE
);
1878 void CMD_MoveToScreen(F_CMD_ARGS
)
1880 __move_window(F_PASS_ARGS
, False
, MOVE_SCREEN
);
1885 /* This function does the SnapAttraction stuff. It takes x and y coordinates
1886 * (*px and *py) and returns the snapped values. */
1887 static void DoSnapAttract(
1888 FvwmWindow
*fw
, int Width
, int Height
, int *px
, int *py
)
1890 int nyt
,nxl
,dist
,closestLeft
,closestRight
,closestBottom
,closestTop
;
1893 /* resist based on window edges */
1894 closestTop
= fw
->snap_attraction
.proximity
;
1895 closestBottom
= fw
->snap_attraction
.proximity
;
1896 closestRight
= fw
->snap_attraction
.proximity
;
1897 closestLeft
= fw
->snap_attraction
.proximity
;
1903 self
.height
= Height
;
1908 rc
= get_visible_icon_title_geometry(fw
, &g
);
1911 self
.height
+= g
.height
;
1916 * Snap grid handling
1918 if (fw
->snap_grid_x
> 1 && nxl
== -99999)
1920 if (*px
!= *px
/ fw
->snap_grid_x
* fw
->snap_grid_x
)
1922 *px
= (*px
+ ((*px
>= 0) ?
1923 fw
->snap_grid_x
: -fw
->snap_grid_x
) /
1924 2) / fw
->snap_grid_x
* fw
->snap_grid_x
;
1927 if (fw
->snap_grid_y
> 1 && nyt
== -99999)
1929 if (*py
!= *py
/ fw
->snap_grid_y
* fw
->snap_grid_y
)
1931 *py
= (*py
+ ((*py
>= 0) ?
1932 fw
->snap_grid_y
: -fw
->snap_grid_y
) /
1933 2) / fw
->snap_grid_y
* fw
->snap_grid_y
;
1940 /* snap to other windows or icons*/
1941 if (fw
->snap_attraction
.proximity
> 0 &&
1942 (fw
->snap_attraction
.mode
& (SNAP_ICONS
| SNAP_WINDOWS
| SNAP_SAME
)))
1945 int maskout
= (SNAP_SCREEN
| SNAP_SCREEN_WINDOWS
|
1946 SNAP_SCREEN_ICONS
| SNAP_SCREEN_ALL
);
1948 for (tmp
= Scr
.FvwmRoot
.next
; tmp
; tmp
= tmp
->next
)
1952 if (fw
->Desk
!= tmp
->Desk
|| fw
== tmp
)
1956 /* check snapping type */
1957 switch (fw
->snap_attraction
.mode
& ~(maskout
))
1959 case SNAP_WINDOWS
: /* we only snap windows */
1960 if (IS_ICONIFIED(tmp
) || IS_ICONIFIED(fw
))
1965 case SNAP_ICONS
: /* we only snap icons */
1966 if (!IS_ICONIFIED(tmp
) || !IS_ICONIFIED(fw
))
1971 case SNAP_SAME
: /* we don't snap unequal */
1972 if (IS_ICONIFIED(tmp
) != IS_ICONIFIED(fw
))
1981 /* get other window dimensions */
1982 get_visible_window_or_icon_geometry(tmp
, &other
);
1983 /* prevent that window snaps off screen */
1986 other
.x
-= fw
->snap_attraction
.proximity
+ 10000;
1987 other
.width
+= fw
->snap_attraction
.proximity
+ 10000;
1991 other
.y
-= fw
->snap_attraction
.proximity
+ 10000;
1992 other
.height
+= fw
->snap_attraction
.proximity
+ 10000;
1994 if (other
.x
+ other
.width
>= Scr
.MyDisplayWidth
)
1996 other
.width
+= fw
->snap_attraction
.proximity
+ 10000;
1998 if (other
.y
+ other
.height
>= Scr
.MyDisplayHeight
)
2000 other
.height
+= fw
->snap_attraction
.proximity
+ 10000;
2003 /* snap horizontally */
2005 other
.y
+ other
.height
> *py
&&
2006 other
.y
< *py
+ self
.height
)
2008 dist
= abs(other
.x
- (*px
+ self
.width
));
2009 if (dist
< closestRight
)
2011 closestRight
= dist
;
2012 if (*px
+ self
.width
>= other
.x
&&
2014 other
.x
+ fw
->snap_attraction
.proximity
)
2016 nxl
= other
.x
- self
.width
;
2018 if (*px
+ self
.width
>=
2019 other
.x
- fw
->snap_attraction
.proximity
&&
2020 *px
+ self
.width
< other
.x
)
2022 nxl
= other
.x
- self
.width
;
2025 dist
= abs(other
.x
+ other
.width
- *px
);
2026 if (dist
< closestLeft
)
2029 if (*px
<= other
.x
+ other
.width
&&
2030 *px
> other
.x
+ other
.width
-
2031 fw
->snap_attraction
.proximity
)
2033 nxl
= other
.x
+ other
.width
;
2035 if (*px
<= other
.x
+ other
.width
+
2036 fw
->snap_attraction
.proximity
&&
2037 *px
> other
.x
+ other
.width
)
2039 nxl
= other
.x
+ other
.width
;
2043 /* snap vertically */
2045 other
.x
+ other
.width
> *px
&&
2046 other
.x
< *px
+ self
.width
)
2048 dist
= abs(other
.y
- (*py
+ self
.height
));
2049 if (dist
< closestBottom
)
2051 closestBottom
= dist
;
2052 if (*py
+ self
.height
>= other
.y
&&
2053 *py
+ self
.height
< other
.y
+
2054 fw
->snap_attraction
.proximity
)
2056 nyt
= other
.y
- self
.height
;
2058 if (*py
+ self
.height
>=
2059 other
.y
- fw
->snap_attraction
.proximity
&&
2060 *py
+ self
.height
< other
.y
)
2062 nyt
= other
.y
- self
.height
;
2065 dist
= abs(other
.y
+ other
.height
- *py
);
2066 if (dist
< closestTop
)
2070 other
.y
+ other
.height
&&
2071 *py
> other
.y
+ other
.height
-
2072 fw
->snap_attraction
.proximity
)
2074 nyt
= other
.y
+ other
.height
;
2076 if (*py
<= other
.y
+ other
.height
+
2077 fw
->snap_attraction
.proximity
&&
2078 *py
> other
.y
+ other
.height
)
2080 nyt
= other
.y
+ other
.height
;
2085 } /* snap to other windows */
2087 /* snap to screen egdes */
2088 if (fw
->snap_attraction
.proximity
> 0 && (
2089 ( fw
->snap_attraction
.mode
& SNAP_SCREEN
&& (
2090 fw
->snap_attraction
.mode
& SNAP_SAME
||
2091 ( IS_ICONIFIED(fw
) &&
2092 fw
->snap_attraction
.mode
& SNAP_ICONS
) ||
2093 ( !IS_ICONIFIED(fw
) &&
2094 fw
->snap_attraction
.mode
& SNAP_WINDOWS
))) ||
2095 ( !IS_ICONIFIED(fw
) &&
2096 fw
->snap_attraction
.mode
& SNAP_SCREEN_WINDOWS
) ||
2097 ( IS_ICONIFIED(fw
) &&
2098 fw
->snap_attraction
.mode
& SNAP_SCREEN_ICONS
) ||
2099 fw
->snap_attraction
.mode
& SNAP_SCREEN_ALL
))
2102 if (!(Scr
.MyDisplayWidth
< (*px
) ||
2103 (*px
+ self
.width
) < 0))
2105 dist
= abs(Scr
.MyDisplayHeight
- (*py
+ self
.height
));
2106 if (dist
< closestBottom
)
2108 closestBottom
= dist
;
2109 if (*py
+ self
.height
>=
2110 Scr
.MyDisplayHeight
&&
2112 Scr
.MyDisplayHeight
+ fw
->snap_attraction
.proximity
)
2114 nyt
= Scr
.MyDisplayHeight
-
2117 if (*py
+ self
.height
>=
2118 Scr
.MyDisplayHeight
- fw
->snap_attraction
.proximity
&&
2119 *py
+ self
.height
< Scr
.MyDisplayHeight
)
2121 nyt
= Scr
.MyDisplayHeight
-
2126 if (dist
< closestTop
)
2129 if ((*py
<= 0)&&(*py
> - fw
->snap_attraction
.proximity
))
2133 if ((*py
<= fw
->snap_attraction
.proximity
)&&(*py
> 0))
2138 } /* horizontally */
2140 if (!(Scr
.MyDisplayHeight
< (*py
) ||
2141 (*py
+ self
.height
) < 0))
2144 Scr
.MyDisplayWidth
- (*px
+ self
.width
));
2145 if (dist
< closestRight
)
2147 closestRight
= dist
;
2149 if (*px
+ self
.width
>= Scr
.MyDisplayWidth
&&
2151 Scr
.MyDisplayWidth
+ fw
->snap_attraction
.proximity
)
2153 nxl
= Scr
.MyDisplayWidth
- self
.width
;
2156 if (*px
+ self
.width
>=
2157 Scr
.MyDisplayWidth
- fw
->snap_attraction
.proximity
&&
2158 *px
+ self
.width
< Scr
.MyDisplayWidth
)
2160 nxl
= Scr
.MyDisplayWidth
- self
.width
;
2164 if (dist
< closestLeft
)
2169 (*px
> - fw
->snap_attraction
.proximity
))
2173 if ((*px
<= fw
->snap_attraction
.proximity
) &&
2180 } /* snap to screen edges */
2192 * Resist moving windows beyond the edge of the screen
2194 if (fw
->edge_resistance_move
> 0)
2196 /* snap to right edge */
2198 *px
+ Width
>= Scr
.MyDisplayWidth
&&
2199 *px
+ Width
< Scr
.MyDisplayWidth
+
2200 fw
->edge_resistance_move
)
2202 *px
= Scr
.MyDisplayWidth
- Width
;
2204 /* snap to left edge */
2205 else if ((*px
<= 0) && (*px
> -fw
->edge_resistance_move
))
2209 /* snap to bottom edge */
2211 *py
+ Height
>= Scr
.MyDisplayHeight
&&
2212 *py
+ Height
< Scr
.MyDisplayHeight
+
2213 fw
->edge_resistance_move
)
2215 *py
= Scr
.MyDisplayHeight
- Height
;
2217 /* snap to top edge */
2218 else if (*py
<= 0 && *py
> -fw
->edge_resistance_move
)
2223 /* Resist moving windows between xineramascreens */
2224 if (fw
->edge_resistance_xinerama_move
> 0 && FScreenIsEnabled())
2228 Bool do_recalc_rectangle
= False
;
2230 FScreenGetResistanceRect(
2231 *px
, *py
, Width
, Height
, &scr_x0
, &scr_y0
, &scr_x1
,
2234 /* snap to right edge */
2235 if (scr_x1
< Scr
.MyDisplayWidth
&&
2236 *px
+ Width
>= scr_x1
&& *px
+ Width
<
2237 scr_x1
+ fw
->edge_resistance_xinerama_move
)
2239 *px
= scr_x1
- Width
;
2240 do_recalc_rectangle
= True
;
2242 /* snap to left edge */
2245 *px
<= scr_x0
&& scr_x0
- *px
<
2246 fw
->edge_resistance_xinerama_move
)
2249 do_recalc_rectangle
= True
;
2251 if (do_recalc_rectangle
)
2253 /* Snapping in X direction can move the window off a
2254 * screen. Thus, it may no longer be necessary to snap
2255 * in Y direction. */
2256 FScreenGetResistanceRect(
2257 *px
, *py
, Width
, Height
, &scr_x0
, &scr_y0
,
2260 /* snap to bottom edge */
2261 if (scr_y1
< Scr
.MyDisplayHeight
&&
2262 *py
+ Height
>= scr_y1
&& *py
+ Height
<
2263 scr_y1
+ fw
->edge_resistance_xinerama_move
)
2265 *py
= scr_y1
- Height
;
2267 /* snap to top edge */
2270 *py
<= scr_y0
&& scr_y0
- *py
<
2271 fw
->edge_resistance_xinerama_move
)
2282 * Move the rubberband around, return with the new window location
2284 * Returns True if the window has to be resized after the move.
2288 const exec_context_t
*exc
, int XOffset
, int YOffset
, int Width
,
2289 int Height
, int *FinalX
, int *FinalY
, Bool do_move_opaque
, int cursor
)
2291 extern Window bad_window
;
2292 Bool is_finished
= False
;
2293 Bool is_aborted
= False
;
2294 int xl
,xl2
,yt
,yt2
,delta_x
,delta_y
,paged
;
2295 unsigned int button_mask
= 0;
2297 int dx
= Scr
.EdgeScrollX
? Scr
.EdgeScrollX
: Scr
.MyDisplayWidth
;
2298 int dy
= Scr
.EdgeScrollY
? Scr
.EdgeScrollY
: Scr
.MyDisplayHeight
;
2299 const int vx
= Scr
.Vx
;
2300 const int vy
= Scr
.Vy
;
2305 int x_virtual_offset
= 0;
2306 int y_virtual_offset
= 0;
2307 Bool sent_cn
= False
;
2308 Bool do_resize_too
= False
;
2311 Window move_w
= None
;
2312 int orig_icon_x
= 0;
2313 int orig_icon_y
= 0;
2314 Bool do_snap
= True
;
2315 Bool was_snapped
= False
;
2316 /* if Alt is initially pressed don't enable no-snap until Alt is
2318 Bool nosnap_enabled
= False
;
2319 /* Must not set placed by button if the event is a modified KeyEvent */
2321 FvwmWindow
*fw
= exc
->w
.fw
;
2322 unsigned int draw_parts
= PART_NONE
;
2325 if (!GrabEm(cursor
, GRAB_NORMAL
))
2330 if (!IS_MAPPED(fw
) && !IS_ICONIFIED(fw
))
2332 do_move_opaque
= False
;
2335 if (IS_ICONIFIED(fw
))
2337 if (FW_W_ICON_PIXMAP(fw
) != None
)
2339 move_w
= FW_W_ICON_PIXMAP(fw
);
2341 else if (FW_W_ICON_TITLE(fw
) != None
)
2343 move_w
= FW_W_ICON_TITLE(fw
);
2348 move_w
= FW_W_FRAME(fw
);
2352 dpy
, move_w
, &JunkRoot
, &x_bak
, &y_bak
,
2353 (unsigned int*)&JunkWidth
, (unsigned int*)&JunkHeight
,
2354 (unsigned int*)&JunkBW
, (unsigned int*)&JunkDepth
))
2356 /* This is allright here since the window may not be mapped
2360 if (IS_ICONIFIED(fw
))
2364 get_visible_icon_geometry(fw
, &g
);
2369 /* make a copy of the fw structure for sending to the pager */
2370 memcpy(&fw_copy
, fw
, sizeof(FvwmWindow
));
2371 /* prevent flicker when paging */
2372 SET_WINDOW_BEING_MOVED_OPAQUE(fw
, do_move_opaque
);
2375 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &xl
, &yt
,
2376 &JunkX
, &JunkY
, &button_mask
) == False
)
2378 /* pointer is on a different screen */
2387 button_mask
&= DEFAULT_ALL_BUTTONS_MASK
;
2391 /* draw initial outline */
2392 if (!IS_ICONIFIED(fw
) &&
2393 ((!do_move_opaque
&& !Scr
.gs
.do_emulate_mwm
) || !IS_MAPPED(fw
)))
2395 draw_move_resize_grid(xl
, yt
, Width
- 1, Height
- 1);
2398 if (move_w
== FW_W_FRAME(fw
) && do_move_opaque
)
2400 draw_parts
= border_get_transparent_decorations_part(fw
);
2402 DisplayPosition(fw
, exc
->x
.elast
, xl
, yt
, True
);
2404 memset(&e
, 0, sizeof(e
));
2406 /* Unset the placed by button mask.
2407 * If the move is canceled this will remain as zero.
2409 fw
->placed_by_button
= 0;
2410 while (!is_finished
&& bad_window
!= FW_W(fw
))
2418 /* wait until there is an interesting event */
2422 dpy
, ButtonPressMask
| ButtonReleaseMask
|
2423 KeyPressMask
| PointerMotionMask
|
2424 ButtonMotionMask
| ExposureMask
, &e
)))
2428 fev_get_last_event(&le
);
2434 &le
, dx
, dy
, &xl
, &yt
, &delta_x
, &delta_y
,
2435 False
, False
, True
, fw
->edge_delay_ms_move
);
2437 /* Fake an event to force window reposition */
2440 x_virtual_offset
= 0;
2445 y_virtual_offset
= 0;
2451 fw
, Width
, Height
, &xl
, &yt
);
2454 fev_make_null_event(&e
, dpy
);
2455 e
.type
= MotionNotify
;
2456 e
.xmotion
.time
= fev_get_evtime();
2457 e
.xmotion
.x_root
= xl
- XOffset
;
2458 e
.xmotion
.y_root
= yt
- YOffset
;
2459 e
.xmotion
.same_screen
= True
;
2464 /* block until an event arrives */
2465 /* dv (2004-07-01): With XFree 4.1.0.1, some Mouse
2466 * events are not reported to fvwm when the pointer
2467 * moves very fast and suddenly stops in the corner of
2468 * the screen. Handle EnterNotify/LeaveNotify events
2469 * too to get an idea where the pointer might be. */
2471 dpy
, ButtonPressMask
| ButtonReleaseMask
|
2472 KeyPressMask
| PointerMotionMask
|
2473 ButtonMotionMask
| ExposureMask
|
2474 EnterWindowMask
| LeaveWindowMask
, &e
);
2477 /* discard extra events before a logical release */
2478 if (e
.type
== MotionNotify
||
2479 e
.type
== EnterNotify
|| e
.type
== LeaveNotify
)
2481 while (FPending(dpy
) > 0 &&
2483 dpy
, ButtonMotionMask
|
2484 PointerMotionMask
| ButtonPressMask
|
2485 ButtonRelease
| KeyPressMask
|
2486 EnterWindowMask
| LeaveWindowMask
, &e
))
2488 if (e
.type
== ButtonPress
||
2489 e
.type
== ButtonRelease
||
2496 if (e
.type
== EnterNotify
|| e
.type
== LeaveNotify
)
2502 /* Query the pointer to catch the latest information.
2503 * This *is* necessary. */
2505 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &x
,
2506 &y
, &JunkX
, &JunkY
, &JunkMask
) == True
)
2508 fev_make_null_event(&e2
, dpy
);
2509 e2
.type
= MotionNotify
;
2510 e2
.xmotion
.time
= fev_get_evtime();
2511 e2
.xmotion
.x_root
= x
;
2512 e2
.xmotion
.y_root
= y
;
2513 e2
.xmotion
.state
= JunkMask
;
2514 e2
.xmotion
.same_screen
= True
;
2520 /* pointer is on a different screen,
2524 is_fake_event
= False
;
2525 /* Handle a limited number of key press events to allow
2526 * mouseless operation */
2527 if (e
.type
== KeyPress
)
2530 &e
, fw
, &x_virtual_offset
,
2531 &y_virtual_offset
, ButtonRelease
);
2533 is_fake_event
= (e
.type
!= KeyPress
);
2538 if (!(e
.xkey
.state
& Mod1Mask
))
2540 nosnap_enabled
= True
;
2542 do_snap
= nosnap_enabled
&&
2543 (e
.xkey
.state
& Mod1Mask
) ? False
: True
;
2545 /* simple code to bag out of move - CKH */
2546 if (XLookupKeysym(&(e
.xkey
), 0) == XK_Escape
)
2548 if (!do_move_opaque
)
2550 switch_move_resize_grid(False
);
2552 if (!IS_ICONIFIED(fw
))
2556 *FinalX
= fw
->g
.frame
.x
;
2557 *FinalY
= fw
->g
.frame
.y
;
2562 *FinalX
= orig_icon_x
;
2563 *FinalY
= orig_icon_y
;
2570 if (e
.xbutton
.button
<= NUMBER_OF_MOUSE_BUTTONS
&&
2571 ((Button1Mask
<< (e
.xbutton
.button
- 1)) &
2574 /* No new button was pressed, just a delayed
2578 if (!IS_MAPPED(fw
) &&
2579 ((e
.xbutton
.button
== 2 && !Scr
.gs
.do_emulate_mwm
)
2581 (e
.xbutton
.button
== 1 && Scr
.gs
.do_emulate_mwm
&&
2582 (e
.xbutton
.state
& ShiftMask
))))
2584 do_resize_too
= True
;
2585 /* Fallthrough to button-release */
2587 else if (!button_mask
&& e
.xbutton
.button
<=
2588 NUMBER_OF_EXTENDED_MOUSE_BUTTONS
&&
2589 e
.xbutton
.button
> 0 &&
2590 (move_interactive_finish_button_mask
&
2591 (1<<(e
.xbutton
.button
-1))))
2593 do_resize_too
= False
;
2596 else if (button_mask
&& e
.xbutton
.button
<=
2597 NUMBER_OF_EXTENDED_MOUSE_BUTTONS
&&
2598 e
.xbutton
.button
> 0 &&
2599 (move_drag_finish_button_mask
&
2600 (1<<(e
.xbutton
.button
-1))))
2602 do_resize_too
= False
;
2603 /* Fallthrough to button-release */
2607 /* Abort the move if
2608 * - the move started with a pressed button
2609 * and another button was pressed during the
2611 * - Any button not in the
2612 * move_finish_button_mask is pressed
2614 /* if (button_mask) */
2615 /* - button_mask will always be set here.
2616 * only add an if if we want to be able to
2617 * place windows dragged by other means
2618 * than releasing the initial button.
2621 if (!do_move_opaque
)
2623 switch_move_resize_grid(False
);
2625 if (!IS_ICONIFIED(fw
))
2627 *FinalX
= fw
->g
.frame
.x
;
2628 *FinalY
= fw
->g
.frame
.y
;
2632 *FinalX
= orig_icon_x
;
2633 *FinalY
= orig_icon_y
;
2643 fw
->placed_by_button
= e
.xbutton
.button
;
2645 if (!do_move_opaque
)
2647 switch_move_resize_grid(False
);
2649 xl2
= e
.xbutton
.x_root
+ XOffset
+ x_virtual_offset
;
2650 yt2
= e
.xbutton
.y_root
+ YOffset
+ y_virtual_offset
;
2651 /* ignore the position of the button release if it was
2652 * on a different page. */
2653 if (!(((xl
< 0 && xl2
>= 0) ||
2654 (xl
>= 0 && xl2
< 0) ||
2655 (yt
< 0 && yt2
>= 0) ||
2656 (yt
>= 0 && yt2
< 0)) &&
2657 (abs(xl
- xl2
) > Scr
.MyDisplayWidth
/ 2 ||
2658 abs(yt
- yt2
) > Scr
.MyDisplayHeight
/ 2)))
2663 if (xl
!= xl_orig
|| yt
!= yt_orig
|| vx
!= Scr
.Vx
||
2664 vy
!= Scr
.Vy
|| was_snapped
)
2666 /* only snap if the window actually moved! */
2670 fw
, Width
, Height
, &xl
, &yt
);
2682 if (e
.xmotion
.same_screen
== False
)
2686 if (!(e
.xmotion
.state
& Mod1Mask
))
2688 nosnap_enabled
= True
;
2690 do_snap
= nosnap_enabled
&&
2691 (e
.xmotion
.state
& Mod1Mask
) ? False
: True
;
2692 xl
= e
.xmotion
.x_root
;
2693 yt
= e
.xmotion
.y_root
;
2694 if (xl
> 0 && xl
< Scr
.MyDisplayWidth
- 1)
2696 /* pointer was moved away from the left/right
2697 * border with the mouse, reset the virtual x
2699 x_virtual_offset
= 0;
2701 if (yt
> 0 && yt
< Scr
.MyDisplayHeight
- 1)
2703 /* pointer was moved away from the top/bottom
2704 * border with the mouse, reset the virtual y
2706 y_virtual_offset
= 0;
2708 xl
+= XOffset
+ x_virtual_offset
;
2709 yt
+= YOffset
+ y_virtual_offset
;
2713 DoSnapAttract(fw
, Width
, Height
, &xl
, &yt
);
2717 /* check Paging request once and only once after
2718 * outline redrawn redraw after paging if needed
2720 for (paged
= 0; paged
<= 1; paged
++)
2722 if (!do_move_opaque
)
2724 draw_move_resize_grid(
2725 xl
, yt
, Width
- 1, Height
- 1);
2729 if (IS_ICONIFIED(fw
))
2731 set_icon_position(fw
, xl
, yt
);
2732 move_icon_to_position(fw
);
2733 broadcast_icon_geometry(
2739 dpy
, FW_W_FRAME(fw
),
2743 DisplayPosition(fw
, &e
, xl
, yt
, False
);
2745 /* prevent window from lagging behind mouse
2746 * when paging - mab */
2751 xl
= e
.xmotion
.x_root
;
2752 yt
= e
.xmotion
.y_root
;
2753 fev_get_last_event(&le
);
2755 &le
, dx
, dy
, &xl
, &yt
,
2756 &delta_x
, &delta_y
, False
,
2758 fw
->edge_delay_ms_move
);
2761 x_virtual_offset
= 0;
2766 y_virtual_offset
= 0;
2776 if (!delta_x
&& !delta_y
)
2787 if (!do_move_opaque
)
2789 /* must undraw the rubber band in case the
2790 * event causes some drawing */
2791 switch_move_resize_grid(False
);
2794 if (!do_move_opaque
)
2796 draw_move_resize_grid(
2797 xl
, yt
, Width
- 1, Height
- 1);
2805 xl
+= x_virtual_offset
;
2806 yt
+= y_virtual_offset
;
2807 if (do_move_opaque
&& !IS_ICONIFIED(fw
) &&
2808 !IS_SHADED(fw
) && !Scr
.bo
.do_disable_configure_notify
)
2810 /* send configure notify event for windows that care
2811 * about their location; don't send anything if
2812 * position didn't change */
2813 if (!sent_cn
|| cnx
!= xl
|| cny
!= yt
)
2818 SendConfigureNotify(
2819 fw
, xl
, yt
, Width
, Height
, 0,
2821 #ifdef FVWM_DEBUG_MSGS
2823 DBG
, "frame_setup_window",
2824 "Sent ConfigureNotify (w %d, h %d)",
2831 if (!IS_ICONIFIED(fw
))
2833 fw_copy
.g
.frame
.x
= xl
;
2834 fw_copy
.g
.frame
.y
= yt
;
2836 if (xl
!= old_xl
|| yt
!= old_yt
)
2838 /* only do this with opaque moves, (i.e. the
2839 * server is not grabbed) */
2840 if (draw_parts
!= PART_NONE
)
2842 border_draw_decorations(
2844 ((fw
== get_focus_window())) ?
2846 True
, CLEAR_ALL
, NULL
, NULL
);
2848 if (IS_TEAR_OFF_MENU(fw
))
2850 menu_redraw_transparent_tear_off_menu(
2853 BroadcastConfig(M_CONFIGURE_WINDOW
, &fw_copy
);
2854 FlushAllMessageQueues();
2857 } /* while (!is_finished) */
2859 if (!Scr
.gs
.do_hide_position_window
)
2861 XUnmapWindow(dpy
,Scr
.SizeWindow
);
2863 if (is_aborted
|| bad_window
== FW_W(fw
))
2865 if (vx
!= Scr
.Vx
|| vy
!= Scr
.Vy
)
2867 MoveViewport(vx
, vy
, False
);
2869 if (is_aborted
&& do_move_opaque
)
2871 XMoveWindow(dpy
, move_w
, x_bak
, y_bak
);
2872 if (draw_parts
!= PART_NONE
)
2874 border_draw_decorations(
2876 ((fw
== get_focus_window())) ?
2878 True
, CLEAR_ALL
, NULL
, NULL
);
2880 menu_redraw_transparent_tear_off_menu(fw
, False
);
2882 if (bad_window
== FW_W(fw
))
2884 XUnmapWindow(dpy
, move_w
);
2885 border_undraw_decorations(fw
);
2889 if (!is_aborted
&& bad_window
!= FW_W(fw
) && IS_ICONIFIED(fw
))
2891 SET_ICON_MOVED(fw
, 1);
2893 UngrabEm(GRAB_NORMAL
);
2896 /* Don't wait for buttons to come up when user is placing a new
2897 * window and wants to resize it. */
2898 WaitForButtonsUp(True
);
2900 SET_WINDOW_BEING_MOVED_OPAQUE(fw
, 0);
2903 return do_resize_too
;
2906 void CMD_MoveThreshold(F_CMD_ARGS
)
2910 if (GetIntegerArguments(action
, NULL
, &val
, 1) < 1 || val
< 0)
2912 Scr
.MoveThreshold
= DEFAULT_MOVE_THRESHOLD
;
2916 Scr
.MoveThreshold
= val
;
2922 void CMD_OpaqueMoveSize(F_CMD_ARGS
)
2926 if (GetIntegerArguments(action
, NULL
, &val
, 1) < 1)
2928 if (strncasecmp(action
, "unlimited", 9) == 0)
2930 Scr
.OpaqueSize
= -1;
2934 Scr
.OpaqueSize
= DEFAULT_OPAQUE_MOVE_SIZE
;
2939 Scr
.OpaqueSize
= val
;
2946 static char *hide_options
[] =
2954 void CMD_HideGeometryWindow(F_CMD_ARGS
)
2956 char *token
= PeekToken(action
, NULL
);
2958 Scr
.gs
.do_hide_position_window
= 0;
2959 Scr
.gs
.do_hide_resize_window
= 0;
2960 switch(GetTokenIndex(token
, hide_options
, 0, NULL
))
2965 Scr
.gs
.do_hide_position_window
= 1;
2968 Scr
.gs
.do_hide_resize_window
= 1;
2971 Scr
.gs
.do_hide_position_window
= 1;
2972 Scr
.gs
.do_hide_resize_window
= 1;
2978 void CMD_SnapAttraction(F_CMD_ARGS
)
2983 len
= strlen(action
);
2985 cmd
= safemalloc(len
);
2986 sprintf(cmd
, "Style * SnapAttraction %s", action
);
2988 OLD
, "CMD_SnapAttraction",
2989 "The command SnapAttraction is obsolete. Please use the"
2990 " following command instead:");
2991 fvwm_msg(OLD
, "", cmd
);
2994 FUNC_DONT_REPEAT
| FUNC_DONT_EXPAND_COMMAND
);
3000 void CMD_SnapGrid(F_CMD_ARGS
)
3005 len
= strlen(action
);
3007 cmd
= safemalloc(len
);
3008 sprintf(cmd
, "Style * SnapGrid %s", action
);
3010 OLD
, "CMD_SnapGrid",
3011 "The command SnapGrid is obsolete. Please use the following"
3012 " command instead:");
3013 fvwm_msg(OLD
, "", cmd
);
3016 FUNC_DONT_REPEAT
| FUNC_DONT_EXPAND_COMMAND
);
3022 static Pixmap XorPixmap
= None
;
3024 void CMD_XorValue(F_CMD_ARGS
)
3030 if (GetIntegerArguments(action
, NULL
, &val
, 1) != 1)
3035 PictureUseDefaultVisual();
3036 gcm
= GCFunction
|GCLineWidth
|GCForeground
|GCFillStyle
|GCSubwindowMode
;
3037 gcv
.subwindow_mode
= IncludeInferiors
;
3038 gcv
.function
= GXxor
;
3040 /* use passed in value, or try to calculate appropriate value if 0 */
3043 gcv.foreground = (val1)?(val1):((((unsigned long) 1) <<
3046 /* Xlib programming manual suggestion: */
3047 gcv
.foreground
= (val
)?
3048 (val
):(PictureBlackPixel() ^ PictureWhitePixel());
3049 gcv
.fill_style
= FillSolid
;
3050 gcv
.subwindow_mode
= IncludeInferiors
;
3052 /* modify XorGC, only create once */
3055 XChangeGC(dpy
, Scr
.XorGC
, gcm
, &gcv
);
3059 Scr
.XorGC
= fvwmlib_XCreateGC(dpy
, Scr
.Root
, gcm
, &gcv
);
3062 /* free up XorPixmap if neccesary */
3063 if (XorPixmap
!= None
) {
3064 XFreePixmap(dpy
, XorPixmap
);
3067 PictureUseFvwmVisual();
3073 void CMD_XorPixmap(F_CMD_ARGS
)
3079 FvwmPictureAttributes fpa
;
3081 action
= GetNextToken(action
, &PixmapName
);
3082 if (PixmapName
== NULL
)
3084 /* return to default value. */
3086 CMD_XorValue(F_PASS_ARGS
);
3089 /* get the picture in the root visual, colorlimit is ignored because the
3090 * pixels will be freed */
3091 fpa
.mask
= FPAM_NO_COLOR_LIMIT
| FPAM_NO_ALPHA
;
3092 PictureUseDefaultVisual();
3093 xp
= PGetFvwmPicture(dpy
, Scr
.Root
, NULL
, PixmapName
, fpa
);
3096 fvwm_msg(ERR
,"SetXORPixmap","Can't find pixmap %s", PixmapName
);
3098 PictureUseFvwmVisual();
3102 /* free up old pixmap */
3103 if (XorPixmap
!= None
)
3105 XFreePixmap(dpy
, XorPixmap
);
3108 /* make a copy of the picture pixmap */
3109 XorPixmap
= XCreatePixmap(dpy
, Scr
.Root
, xp
->width
, xp
->height
, Pdepth
);
3110 XCopyArea(dpy
, xp
->picture
, XorPixmap
, DefaultGC(dpy
, Scr
.screen
), 0, 0,
3111 xp
->width
, xp
->height
, 0, 0);
3112 /* destroy picture and free colors */
3113 PDestroyFvwmPicture(dpy
, xp
);
3114 PictureUseFvwmVisual();
3116 /* create Graphics context */
3117 gcm
= GCFunction
|GCLineWidth
|GCTile
|GCFillStyle
|GCSubwindowMode
;
3118 gcv
.subwindow_mode
= IncludeInferiors
;
3119 gcv
.function
= GXxor
;
3120 /* line width of 1 is necessary for Exceed servers */
3122 gcv
.tile
= XorPixmap
;
3123 gcv
.fill_style
= FillTiled
;
3124 gcv
.subwindow_mode
= IncludeInferiors
;
3125 /* modify XorGC, only create once */
3128 XChangeGC(dpy
, Scr
.XorGC
, gcm
, &gcv
);
3132 Scr
.XorGC
= fvwmlib_XCreateGC(dpy
, Scr
.Root
, gcm
, &gcv
);
3139 /* ----------------------------- resizing code ----------------------------- */
3141 static void __resize_get_dir_from_window(
3142 int *ret_xmotion
, int *ret_ymotion
, FvwmWindow
*fw
, Window context_w
)
3144 if (context_w
!= Scr
.Root
&& context_w
!= None
)
3146 if (context_w
== FW_W_SIDE(fw
, 0)) /* top */
3150 else if (context_w
== FW_W_SIDE(fw
, 1)) /* right */
3154 else if (context_w
== FW_W_SIDE(fw
, 2)) /* bottom */
3158 else if (context_w
== FW_W_SIDE(fw
, 3)) /* left */
3162 else if (context_w
== FW_W_CORNER(fw
, 0)) /* upper-left */
3167 else if (context_w
== FW_W_CORNER(fw
, 1)) /* upper-right */
3172 else if (context_w
== FW_W_CORNER(fw
, 2)) /* lower left */
3177 else if (context_w
== FW_W_CORNER(fw
, 3)) /* lower right */
3187 static void __resize_get_dir_proximity(
3188 int *ret_xmotion
, int *ret_ymotion
, FvwmWindow
*fw
, int x_off
,
3189 int y_off
, int px
, int py
)
3194 if (px
< 0 || x_off
< 0 || py
< 0 || y_off
< 0)
3198 /* Now find the place to warp to. We simply use the sectors
3199 * drawn when we start resizing the window. */
3201 tx
= orig
->width
/ 10 - 1;
3202 ty
= orig
->height
/ 10 - 1;
3207 tx
= max(fw
->boundary_width
, tx
);
3208 ty
= max(fw
->boundary_width
, ty
);
3213 else if (x_off
< tx
)
3221 else if (y_off
< ty
)
3229 static void __resize_get_refpos(
3230 int *ret_x
, int *ret_y
, int xmotion
, int ymotion
, int w
, int h
,
3237 else if (xmotion
< 0)
3249 else if (ymotion
< 0)
3262 * __resize_step - move the rubberband around. This is called for
3263 * each motion event when we are resizing
3266 * x_root - the X corrdinate in the root window
3267 * y_root - the Y corrdinate in the root window
3268 * x_off - x offset of pointer from border (input/output)
3269 * y_off - y offset of pointer from border (input/output)
3270 * drag - resize internal structure
3271 * orig - resize internal structure
3272 * xmotionp - pointer to xmotion in resize_window
3273 * ymotionp - pointer to ymotion in resize_window
3276 static void __resize_step(
3277 const exec_context_t
*exc
, int x_root
, int y_root
, int *x_off
,
3278 int *y_off
, rectangle
*drag
, const rectangle
*orig
, int *xmotionp
,
3279 int *ymotionp
, Bool do_resize_opaque
, Bool is_direction_fixed
)
3287 x2
= x_root
- *x_off
;
3289 if (is_direction_fixed
== True
&& (*xmotionp
!= 0 || *ymotionp
!= 0))
3293 else if (x2
<= orig
->x
||
3294 (*xmotionp
== 1 && x2
< orig
->x
+ orig
->width
- 1))
3298 else if (x2
>= orig
->x
+ orig
->width
- 1 ||
3299 (*xmotionp
== -1 && x2
> orig
->x
))
3317 drag
->width
= orig
->x
+ orig
->width
- x_root
;
3321 if (*xmotionp
!= -1)
3328 drag
->width
= 1 + x_root
- drag
->x
;
3334 y2
= y_root
- *y_off
;
3336 if (is_direction_fixed
== True
&& (*xmotionp
!= 0 || *ymotionp
!= 0))
3340 else if (y2
<= orig
->y
||
3341 (*ymotionp
== 1 && y2
< orig
->y
+ orig
->height
- 1))
3345 else if (y2
>= orig
->y
+ orig
->height
- 1 ||
3346 (*ymotionp
== -1 && y2
> orig
->y
))
3364 drag
->height
= orig
->y
+ orig
->height
- y_root
;
3368 if (*ymotionp
!= -1)
3375 drag
->height
= 1 + y_root
- drag
->y
;
3384 /* round up to nearest OK size to keep pointer inside
3387 exc
->w
.fw
, exc
->x
.elast
, &drag
->width
, &drag
->height
,
3388 *xmotionp
, *ymotionp
, CS_ROUND_UP
);
3391 drag
->x
= orig
->x
+ orig
->width
- drag
->width
;
3395 drag
->y
= orig
->y
+ orig
->height
- drag
->height
;
3397 if (!do_resize_opaque
)
3399 draw_move_resize_grid(
3400 drag
->x
, drag
->y
, drag
->width
- 1,
3406 exc
->w
.fw
, drag
->x
, drag
->y
, drag
->width
,
3407 drag
->height
, False
);
3410 DisplaySize(exc
->w
.fw
, exc
->x
.elast
, drag
->width
, drag
->height
, False
, False
);
3415 /* Starts a window resize operation */
3416 static Bool
__resize_window(F_CMD_ARGS
)
3418 extern Window bad_window
;
3419 FvwmWindow
*fw
= exc
->w
.fw
;
3420 Bool is_finished
= False
, is_done
= False
, is_aborted
= False
;
3421 Bool do_send_cn
= False
;
3422 Bool do_resize_opaque
;
3423 Bool do_warp_to_border
;
3424 Bool is_direction_fixed
;
3425 Bool fButtonAbort
= False
;
3426 Bool fForceRedraw
= False
;
3427 Bool called_from_title
= False
;
3428 int x
,y
,delta_x
,delta_y
,stashed_x
,stashed_y
;
3429 Window ResizeWindow
;
3430 int dx
= Scr
.EdgeScrollX
? Scr
.EdgeScrollX
: Scr
.MyDisplayWidth
;
3431 int dy
= Scr
.EdgeScrollY
? Scr
.EdgeScrollY
: Scr
.MyDisplayHeight
;
3432 const int vx
= Scr
.Vx
;
3433 const int vy
= Scr
.Vy
;
3435 unsigned int button_mask
= 0;
3438 rectangle
*drag
= &sdrag
;
3439 const rectangle
*orig
= &sorig
;
3440 const window_g g_backup
= fw
->g
;
3444 unsigned edge_wrap_x
;
3445 unsigned edge_wrap_y
;
3450 frame_move_resize_args mr_args
= NULL
;
3460 ResizeWindow
= FW_W_FRAME(fw
);
3461 if (fev_get_evpos_or_query(dpy
, Scr
.Root
, exc
->x
.etrigger
, &px
, &py
) ==
3463 XTranslateCoordinates(
3464 dpy
, Scr
.Root
, ResizeWindow
, px
, py
, &px
, &py
,
3465 &JunkChild
) == False
)
3467 /* pointer is on a different screen - that's okay here */
3471 button_mask
&= DEFAULT_ALL_BUTTONS_MASK
;
3473 if (!is_function_allowed(F_RESIZE
, NULL
, fw
, RQORIG_PROGRAM_US
, True
))
3479 if (IS_SHADED(fw
) || !IS_MAPPED(fw
))
3481 do_resize_opaque
= False
;
3482 evmask
= XEVMASK_RESIZE
;
3486 do_resize_opaque
= DO_RESIZE_OPAQUE(fw
);
3487 evmask
= XEVMASK_RESIZE_OPAQUE
;
3490 /* no suffix = % of screen, 'p' = pixels, 'c' = increment units */
3493 get_unshaded_geometry(fw
, drag
);
3497 drag
->width
= fw
->g
.frame
.width
;
3498 drag
->height
= fw
->g
.frame
.height
;
3501 get_window_borders(fw
, &b
);
3502 n
= GetResizeArguments(
3503 &action
, fw
->g
.frame
.x
, fw
->g
.frame
.y
,
3504 fw
->hints
.base_width
, fw
->hints
.base_height
,
3505 fw
->hints
.width_inc
, fw
->hints
.height_inc
,
3506 &b
, &(drag
->width
), &(drag
->height
),
3507 &dir
, &is_direction_fixed
, &do_warp_to_border
);
3513 /* size will be less or equal to requested */
3518 get_unshaded_geometry(fw
, &new_g
);
3519 SET_MAXIMIZED(fw
, 0);
3521 fw
, NULL
, &drag
->width
, &drag
->height
, xmotion
,
3524 fw
->hints
.win_gravity
, &new_g
,
3525 drag
->width
- new_g
.width
,
3526 drag
->height
- new_g
.height
);
3527 fw
->g
.normal
= new_g
;
3528 get_shaded_geometry(fw
, &shaded_g
, &new_g
);
3530 fw
, shaded_g
.x
, shaded_g
.y
, shaded_g
.width
,
3531 shaded_g
.height
, False
);
3535 new_g
= fw
->g
.frame
;
3536 SET_MAXIMIZED(fw
, 0);
3538 fw
, NULL
, &drag
->width
, &drag
->height
, xmotion
,
3541 fw
->hints
.win_gravity
, &new_g
,
3542 drag
->width
- new_g
.width
,
3543 drag
->height
- new_g
.height
);
3545 fw
, new_g
.x
, new_g
.y
, drag
->width
,
3546 drag
->height
, False
);
3548 update_absolute_geometry(fw
);
3549 maximize_adjust_offset(fw
);
3550 GNOME_SetWinArea(fw
);
3551 ResizeWindow
= None
;
3555 was_maximized
= IS_MAXIMIZED(fw
);
3556 SET_MAXIMIZED(fw
, 0);
3559 /* must redraw the buttons now so that the 'maximize' button
3560 * does not stay depressed. */
3561 border_draw_decorations(
3562 fw
, PART_BUTTONS
, (fw
== Scr
.Hilite
), True
, CLEAR_ALL
,
3566 if (Scr
.bo
.do_install_root_cmap
)
3568 InstallRootColormap();
3572 InstallFvwmColormap();
3574 if (!GrabEm(CRS_RESIZE
, GRAB_NORMAL
))
3580 /* handle problems with edge-wrapping while resizing */
3581 edge_wrap_x
= Scr
.flags
.do_edge_wrap_x
;
3582 edge_wrap_y
= Scr
.flags
.do_edge_wrap_y
;
3583 Scr
.flags
.do_edge_wrap_x
= 0;
3584 Scr
.flags
.do_edge_wrap_y
= 0;
3586 if (!do_resize_opaque
)
3591 dpy
, (Drawable
)ResizeWindow
, &JunkRoot
, &drag
->x
, &drag
->y
,
3592 (unsigned int*)&drag
->width
, (unsigned int*)&drag
->height
,
3593 (unsigned int*)&JunkBW
, (unsigned int*)&JunkDepth
))
3595 UngrabEm(GRAB_NORMAL
);
3596 if (!do_resize_opaque
)
3598 MyXUngrabServer(dpy
);
3604 SET_MAXIMIZED(fw
, was_maximized
);
3605 get_unshaded_geometry(fw
, drag
);
3606 SET_MAXIMIZED(fw
, 0);
3608 if (do_resize_opaque
)
3610 mr_args
= frame_create_move_resize_args(
3611 fw
, FRAME_MR_OPAQUE
, &fw
->g
.frame
, &fw
->g
.frame
, 0,
3616 Scr
.flags
.is_wire_frame_displayed
= True
;
3618 MyXGrabKeyboard(dpy
);
3624 /* pop up a resize dimensions window */
3625 if (!Scr
.gs
.do_hide_resize_window
)
3627 position_geometry_window(NULL
);
3628 XMapRaised(dpy
, Scr
.SizeWindow
);
3630 DisplaySize(fw
, exc
->x
.elast
, orig
->width
, orig
->height
, True
, True
);
3632 if (dir
!= DIR_NONE
)
3636 grav
= gravity_dir_to_grav(dir
);
3637 gravity_get_offsets(grav
, &xmotion
, &ymotion
);
3641 if (xmotion
== 0 && ymotion
== 0)
3643 __resize_get_dir_from_window(&xmotion
, &ymotion
, fw
, PressedW
);
3645 if (FW_W_TITLE(fw
) != None
&& PressedW
== FW_W_TITLE(fw
))
3647 /* title was pressed to start the resize */
3648 called_from_title
= True
;
3652 for (i
= NUMBER_OF_TITLE_BUTTONS
; i
--; )
3654 /* see if the title button was pressed to that the
3656 if (FW_W_BUTTON(fw
, i
) != None
&&
3657 FW_W_BUTTON(fw
, i
) == PressedW
)
3660 called_from_title
= True
;
3664 /* don't warp if the resize was triggered by a press somwhere on the
3666 if (PressedW
!= Scr
.Root
&& xmotion
== 0 && ymotion
== 0 &&
3669 __resize_get_dir_proximity(
3670 &xmotion
, &ymotion
, fw
, orig
->width
- px
,
3671 orig
->height
- py
, px
, py
);
3672 if (xmotion
!= 0 || ymotion
!= 0)
3674 do_warp_to_border
= True
;
3679 __resize_get_refpos(
3680 &ref_x
, &ref_y
, xmotion
, ymotion
, orig
->width
,
3685 switch (SHADED_DIR(fw
))
3706 switch (SHADED_DIR(fw
))
3727 __resize_get_refpos(
3728 &ref_x
, &ref_y
, xmotion
, ymotion
, fw
->g
.frame
.width
,
3729 fw
->g
.frame
.height
, fw
);
3733 if (do_warp_to_border
== True
)
3738 dx
= (xmotion
== 0) ? px
: ref_x
;
3739 dy
= (ymotion
== 0) ? py
: ref_y
;
3740 /* warp the pointer to the border */
3742 dpy
, None
, ResizeWindow
, 0, 0, 1, 1, dx
, dy
);
3745 else if (xmotion
!= 0 || ymotion
!= 0)
3747 /* keep the distance between pointer and border */
3748 x_off
= (xmotion
== 0) ? 0 : ref_x
- px
;
3749 y_off
= (ymotion
== 0) ? 0 : ref_y
- py
;
3753 /* wait until the pointer hits a border before making a
3754 * decision about the resize direction */
3757 /* draw the rubber-band window */
3758 if (!do_resize_opaque
)
3760 draw_move_resize_grid(
3761 drag
->x
, drag
->y
, drag
->width
- 1, drag
->height
- 1);
3763 /* kick off resizing without requiring any motion if invoked with a key
3765 if (exc
->x
.elast
->type
== KeyPress
)
3771 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &stashed_x
,
3772 &stashed_y
, &JunkX
, &JunkY
, &JunkMask
) == False
)
3774 /* pointer is on a different screen */
3781 exc
, stashed_x
, stashed_y
, &xo
, &yo
, drag
, orig
,
3782 &xmotion
, &ymotion
, do_resize_opaque
, True
);
3786 stashed_x
= stashed_y
= -1;
3789 /* loop to resize */
3790 memset(&ev
, 0, sizeof(ev
));
3791 while (!is_finished
&& bad_window
!= FW_W(fw
))
3795 /* block until there is an interesting event */
3797 (!FPending(dpy
) || !FCheckMaskEvent(dpy
, evmask
, &ev
)))
3800 &ev
, dx
, dy
, &x
, &y
, &delta_x
, &delta_y
, False
,
3801 False
, True
, fw
->edge_delay_ms_resize
);
3804 /* Fake an event to force window reposition */
3805 ev
.type
= MotionNotify
;
3806 ev
.xmotion
.time
= fev_get_evtime();
3807 fForceRedraw
= True
;
3815 evmask
| EnterWindowMask
| LeaveWindowMask
,
3818 if (ev
.type
== MotionNotify
||
3819 ev
.type
== EnterNotify
|| ev
.type
== LeaveNotify
)
3823 is_motion
= (ev
.type
== MotionNotify
) ? True
: False
;
3824 /* discard any extra motion events before a release */
3825 /* dv (2004-07-01): With XFree 4.1.0.1, some Mouse
3826 * events are not reported to fvwm when the pointer
3827 * moves very fast and suddenly stops in the corner of
3828 * the screen. Handle EnterNotify/LeaveNotify events
3829 * too to get an idea where the pointer might be. */
3832 dpy
, ButtonMotionMask
|
3833 PointerMotionMask
| ButtonReleaseMask
|
3834 ButtonPressMask
| EnterWindowMask
|
3835 LeaveWindowMask
, &ev
) == True
)
3837 if (ev
.type
== ButtonRelease
||
3838 ev
.type
== ButtonPress
||
3839 ev
.type
== KeyPress
)
3845 if (ev
.type
== EnterNotify
|| ev
.type
== LeaveNotify
)
3851 /* Query the pointer to catch the latest information.
3852 * This *is* necessary. */
3854 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &x
,
3855 &y
, &JunkX
, &JunkY
, &JunkMask
) == True
)
3857 /* Must NOT use button_mask here, or resize
3858 * will not work with num lock */
3859 fev_make_null_event(&e2
, dpy
);
3860 e2
.type
= MotionNotify
;
3861 e2
.xmotion
.time
= fev_get_evtime();
3862 e2
.xmotion
.x_root
= x
;
3863 e2
.xmotion
.y_root
= y
;
3864 e2
.xmotion
.state
= JunkMask
;
3865 e2
.xmotion
.same_screen
= True
;
3867 fev_fake_event(&ev
);
3871 /* pointer is on a different screen,
3877 /* Handle a limited number of key press events to allow
3878 * mouseless operation */
3879 if (ev
.type
== KeyPress
)
3881 Keyboard_shortcuts(&ev
, fw
, NULL
, NULL
, ButtonRelease
);
3882 if (ev
.type
== ButtonRelease
)
3891 if (ev
.xbutton
.button
<= NUMBER_OF_MOUSE_BUTTONS
&&
3892 ((Button1Mask
<< (ev
.xbutton
.button
- 1)) &
3895 /* No new button was pressed, just a delayed
3899 /* Abort the resize if
3900 * - the move started with a pressed button and
3901 * another button was pressed during the operation
3902 * - no button was started at the beginning and any
3903 * button except button 1 was pressed. */
3904 if (button_mask
|| (ev
.xbutton
.button
!= 1))
3906 fButtonAbort
= True
;
3916 /* simple code to bag out of move - CKH */
3918 XLookupKeysym(&ev
.xkey
, 0) == XK_Escape
)
3933 if (ev
.xmotion
.same_screen
== False
)
3939 x
= ev
.xmotion
.x_root
;
3940 y
= ev
.xmotion
.y_root
;
3941 /* resize before paging request to prevent
3942 * resize from lagging * mouse - mab */
3944 exc
, x
, y
, &x_off
, &y_off
, drag
, orig
,
3945 &xmotion
, &ymotion
, do_resize_opaque
,
3946 is_direction_fixed
);
3947 /* need to move the viewport */
3949 &ev
, dx
, dy
, &x
, &y
, &delta_x
,
3950 &delta_y
, False
, False
, False
,
3951 fw
->edge_delay_ms_resize
);
3953 /* redraw outline if we paged - mab */
3954 if (delta_x
!= 0 || delta_y
!= 0)
3962 exc
, x
, y
, &x_off
, &y_off
, drag
, orig
,
3963 &xmotion
, &ymotion
, do_resize_opaque
,
3964 is_direction_fixed
);
3966 fForceRedraw
= False
;
3970 case PropertyNotify
:
3973 exec_context_changes_t ecc
;
3975 ecc
.x
.etrigger
= &ev
;
3976 ea
.exc
= exc_clone_context(exc
, &ecc
, ECC_ETRIGGER
);
3977 HandlePropertyNotify(&ea
);
3978 exc_destroy_context(ea
.exc
);
3988 if (!do_resize_opaque
)
3990 /* must undraw the rubber band in case the
3991 * event causes some drawing */
3992 switch_move_resize_grid(False
);
3994 dispatch_event(&ev
);
3995 if (!do_resize_opaque
)
3997 draw_move_resize_grid(
3998 drag
->x
, drag
->y
, drag
->width
- 1,
4004 if (do_resize_opaque
)
4006 /* only do this with opaque resizes, (i.e. the
4007 * server is not grabbed) */
4008 BroadcastConfig(M_CONFIGURE_WINDOW
, fw
);
4009 FlushAllMessageQueues();
4014 /* erase the rubber-band */
4015 if (!do_resize_opaque
)
4017 switch_move_resize_grid(False
);
4019 /* pop down the size window */
4020 if (!Scr
.gs
.do_hide_resize_window
)
4022 XUnmapWindow(dpy
, Scr
.SizeWindow
);
4024 if (is_aborted
|| bad_window
== FW_W(fw
))
4026 /* return pointer if aborted resize was invoked with key */
4030 dpy
, None
, Scr
.Root
, 0, 0, 0, 0, stashed_x
,
4035 /* since we aborted the resize, the window is still
4037 SET_MAXIMIZED(fw
, 1);
4039 if (do_resize_opaque
)
4051 exc
, sorig
.x
, sorig
.y
, &xo
, &yo
, &g
, orig
,
4052 &xmotion
, &ymotion
, do_resize_opaque
, True
);
4054 if (vx
!= Scr
.Vx
|| vy
!= Scr
.Vy
)
4056 MoveViewport(vx
, vy
, False
);
4058 /* restore all geometry-related info */
4060 if (bad_window
== FW_W(fw
))
4062 XUnmapWindow(dpy
, FW_W_FRAME(fw
));
4063 border_undraw_decorations(fw
);
4067 else if (!is_aborted
&& bad_window
!= FW_W(fw
))
4071 /* size will be >= to requested */
4073 fw
, exc
->x
.elast
, &drag
->width
, &drag
->height
,
4074 xmotion
, ymotion
, CS_ROUND_UP
);
4077 get_shaded_geometry(fw
, &new_g
, drag
);
4083 if (do_resize_opaque
)
4085 frame_update_move_resize_args(mr_args
, &new_g
);
4090 fw
, new_g
.x
, new_g
.y
, new_g
.width
,
4091 new_g
.height
, False
);
4095 fw
->g
.normal
.width
= drag
->width
;
4096 fw
->g
.normal
.height
= drag
->height
;
4099 if (is_aborted
&& was_maximized
)
4102 border_draw_decorations(
4103 fw
, PART_BUTTONS
, (fw
== Scr
.Hilite
), True
, CLEAR_ALL
,
4106 if (Scr
.bo
.do_install_root_cmap
)
4108 UninstallRootColormap();
4112 UninstallFvwmColormap();
4114 ResizeWindow
= None
;
4115 if (!do_resize_opaque
)
4117 /* Throw away some events that dont interest us right now. */
4118 discard_events(EnterWindowMask
|LeaveWindowMask
);
4119 Scr
.flags
.is_wire_frame_displayed
= False
;
4120 MyXUngrabServer(dpy
);
4122 if (mr_args
!= NULL
)
4124 frame_free_move_resize_args(fw
, mr_args
);
4126 if (do_send_cn
== True
)
4138 SendConfigureNotify(fw
, g
.x
, g
.y
, g
.width
, g
.height
, 0, True
);
4140 MyXUngrabKeyboard(dpy
);
4141 WaitForButtonsUp(True
);
4142 UngrabEm(GRAB_NORMAL
);
4143 Scr
.flags
.do_edge_wrap_x
= edge_wrap_x
;
4144 Scr
.flags
.do_edge_wrap_y
= edge_wrap_y
;
4145 update_absolute_geometry(fw
);
4146 maximize_adjust_offset(fw
);
4147 GNOME_SetWinArea(fw
);
4156 void CMD_Resize(F_CMD_ARGS
)
4158 FvwmWindow
*fw
= exc
->w
.fw
;
4160 if (IS_EWMH_FULLSCREEN(fw
))
4162 /* do not unmaximize ! */
4163 CMD_ResizeMaximize(F_PASS_ARGS
);
4167 __resize_window(F_PASS_ARGS
);
4172 /* ----------------------------- maximizing code --------------------------- */
4174 Bool
is_window_sticky_across_pages(FvwmWindow
*fw
)
4176 if (IS_STICKY_ACROSS_PAGES(fw
) ||
4177 (IS_ICONIFIED(fw
) && IS_ICON_STICKY_ACROSS_PAGES(fw
)))
4187 Bool
is_window_sticky_across_desks(FvwmWindow
*fw
)
4189 if (IS_STICKY_ACROSS_DESKS(fw
) ||
4190 (IS_ICONIFIED(fw
) && IS_ICON_STICKY_ACROSS_DESKS(fw
)))
4200 static void move_sticky_window_to_same_page(
4201 int *x11
, int *x12
, int *y11
, int *y12
,
4202 int x21
, int x22
, int y21
, int y22
)
4204 /* make sure the x coordinate is on the same page as the reference
4210 *x11
-= Scr
.MyDisplayWidth
;
4211 *x12
-= Scr
.MyDisplayWidth
;
4214 else if (*x12
<= x21
)
4218 *x11
+= Scr
.MyDisplayWidth
;
4219 *x12
+= Scr
.MyDisplayWidth
;
4222 /* make sure the y coordinate is on the same page as the reference
4228 *y11
-= Scr
.MyDisplayHeight
;
4229 *y12
-= Scr
.MyDisplayHeight
;
4232 else if (*y12
<= y21
)
4236 *y11
+= Scr
.MyDisplayHeight
;
4237 *y12
+= Scr
.MyDisplayHeight
;
4244 static void MaximizeHeight(
4245 FvwmWindow
*win
, int win_width
, int win_x
, int *win_height
,
4246 int *win_y
, Bool grow_up
, Bool grow_down
, int top_border
,
4247 int bottom_border
, int *layers
)
4250 int x11
, x12
, x21
, x22
;
4251 int y11
, y12
, y21
, y22
;
4256 x11
= win_x
; /* Start x */
4257 y11
= *win_y
; /* Start y */
4258 x12
= x11
+ win_width
; /* End x */
4259 y12
= y11
+ *win_height
; /* End y */
4260 new_y1
= top_border
;
4261 new_y2
= bottom_border
;
4263 for (cwin
= Scr
.FvwmRoot
.next
; cwin
; cwin
= cwin
->next
)
4266 (cwin
->Desk
!= win
->Desk
&&
4267 !is_window_sticky_across_desks(cwin
)))
4271 if ((layers
[0] >= 0 && cwin
->layer
< layers
[0]) ||
4272 (layers
[1] >= 0 && cwin
->layer
> layers
[1]))
4276 rc
= get_visible_window_or_icon_geometry(cwin
, &g
);
4283 x22
= x21
+ g
.width
;
4284 y22
= y21
+ g
.height
;
4285 if (is_window_sticky_across_pages(cwin
))
4287 move_sticky_window_to_same_page(
4288 &x21
, &x22
, &new_y1
, &new_y2
, x11
, x12
, y11
,
4292 /* Are they in the same X space? */
4293 if (!((x22
<= x11
) || (x21
>= x12
)))
4295 if ((y22
<= y11
) && (y22
>= new_y1
))
4299 else if ((y12
<= y21
) && (new_y2
>= y21
))
4313 *win_height
= new_y2
- new_y1
;
4319 static void MaximizeWidth(
4320 FvwmWindow
*win
, int *win_width
, int *win_x
, int win_height
,
4321 int win_y
, Bool grow_left
, Bool grow_right
, int left_border
,
4322 int right_border
, int *layers
)
4325 int x11
, x12
, x21
, x22
;
4326 int y11
, y12
, y21
, y22
;
4331 x11
= *win_x
; /* Start x */
4332 y11
= win_y
; /* Start y */
4333 x12
= x11
+ *win_width
; /* End x */
4334 y12
= y11
+ win_height
; /* End y */
4335 new_x1
= left_border
;
4336 new_x2
= right_border
;
4338 for (cwin
= Scr
.FvwmRoot
.next
; cwin
; cwin
= cwin
->next
)
4341 (cwin
->Desk
!= win
->Desk
&&
4342 !is_window_sticky_across_desks(cwin
)))
4346 if ((layers
[0] >= 0 && cwin
->layer
< layers
[0]) ||
4347 (layers
[1] >= 0 && cwin
->layer
> layers
[1]))
4351 rc
= get_visible_window_or_icon_geometry(cwin
, &g
);
4358 x22
= x21
+ g
.width
;
4359 y22
= y21
+ g
.height
;
4360 if (is_window_sticky_across_pages(cwin
))
4362 move_sticky_window_to_same_page(
4363 &new_x1
, &new_x2
, &y21
, &y22
, x11
, x12
, y11
,
4367 /* Are they in the same Y space? */
4368 if (!((y22
<= y11
) || (y21
>= y12
)))
4370 if ((x22
<= x11
) && (x22
>= new_x1
))
4374 else if ((x12
<= x21
) && (new_x2
>= x21
))
4388 *win_width
= new_x2
- new_x1
;
4394 static void unmaximize_fvwm_window(
4399 SET_MAXIMIZED(fw
, 0);
4400 get_relative_geometry(&new_g
, &fw
->g
.normal
);
4403 get_shaded_geometry(fw
, &new_g
, &new_g
);
4406 fw
, new_g
.x
, new_g
.y
, new_g
.width
, new_g
.height
, True
);
4407 border_draw_decorations(
4408 fw
, PART_ALL
, (Scr
.Hilite
== fw
), True
, CLEAR_ALL
, NULL
, NULL
);
4409 if (IS_EWMH_FULLSCREEN(fw
))
4411 SET_EWMH_FULLSCREEN(fw
, False
);
4412 if (DO_EWMH_USE_STACKING_HINTS(fw
))
4414 new_layer(fw
, fw
->ewmh_normal_layer
);
4416 apply_decor_change(fw
);
4421 static void maximize_fvwm_window(
4422 FvwmWindow
*fw
, rectangle
*geometry
)
4424 SET_MAXIMIZED(fw
, 1);
4425 fw
->g
.max_defect
.width
= 0;
4426 fw
->g
.max_defect
.height
= 0;
4428 fw
, NULL
, &geometry
->width
, &geometry
->height
, 0, 0,
4429 CS_UPDATE_MAX_DEFECT
);
4430 fw
->g
.max
= *geometry
;
4433 get_shaded_geometry(fw
, geometry
, &fw
->g
.max
);
4436 fw
, geometry
->x
, geometry
->y
, geometry
->width
,
4437 geometry
->height
, True
);
4438 border_draw_decorations(
4439 fw
, PART_ALL
, (Scr
.Hilite
== fw
), True
, CLEAR_ALL
, NULL
, NULL
);
4440 update_absolute_geometry(fw
);
4441 /* remember the offset between old and new position in case the
4442 * maximized window is moved more than the screen width/height. */
4443 fw
->g
.max_offset
.x
= fw
->g
.normal
.x
- fw
->g
.max
.x
;
4444 fw
->g
.max_offset
.y
= fw
->g
.normal
.y
- fw
->g
.max
.y
;
4446 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
);
4455 * (Un)Maximize a window.
4458 void CMD_Maximize(F_CMD_ARGS
)
4461 int val1
, val2
, val1_unit
, val2_unit
;
4465 Bool grow_up
= False
;
4466 Bool grow_down
= False
;
4467 Bool grow_left
= False
;
4468 Bool grow_right
= False
;
4469 Bool do_force_maximize
= False
;
4470 Bool is_screen_given
= False
;
4471 Bool ignore_working_area
= False
;
4472 int layers
[2] = { -1, -1 };
4473 Bool global_flag_parsed
= False
;
4477 FvwmWindow
*fw
= exc
->w
.fw
;
4480 !is_function_allowed(
4481 F_MAXIMIZE
, NULL
, fw
, RQORIG_PROGRAM_US
, False
))
4486 /* Check for "global" flag ("absolute" is for compatibility with E) */
4487 while (!global_flag_parsed
)
4489 token
= PeekToken(action
, &taction
);
4492 global_flag_parsed
= True
;
4496 if (StrEquals(token
, "screen"))
4500 is_screen_given
= True
;
4501 token
= PeekToken(taction
, &action
);
4502 scr
= FScreenGetScreenArgument(
4503 token
, FSCREEN_SPEC_PRIMARY
);
4505 NULL
, scr
, &scr_x
, &scr_y
, &scr_w
,
4508 else if (StrEquals(token
, "ewmhiwa"))
4510 ignore_working_area
= True
;
4513 else if (StrEquals(token
, "growonwindowlayer"))
4515 layers
[0] = fw
->layer
;
4516 layers
[1] = fw
->layer
;
4519 else if (StrEquals(token
, "growonlayers"))
4523 n
= GetIntegerArguments(
4524 taction
, &action
, layers
, 2);
4533 global_flag_parsed
= True
;
4537 toggle
= ParseToggleArgument(action
, &action
, -1, 0);
4538 if (toggle
== 0 && !IS_MAXIMIZED(fw
))
4543 if (toggle
== 1 && IS_MAXIMIZED(fw
))
4545 /* Fake that the window is not maximized. */
4546 do_force_maximize
= True
;
4549 /* find the new page and geometry */
4550 new_g
.x
= fw
->g
.frame
.x
;
4551 new_g
.y
= fw
->g
.frame
.y
;
4552 new_g
.width
= fw
->g
.frame
.width
;
4553 new_g
.height
= fw
->g
.frame
.height
;
4554 get_page_offset_check_visible(&page_x
, &page_y
, fw
);
4556 /* Check if we should constrain rectangle to some Xinerama screen */
4557 if (!is_screen_given
)
4559 fscreen_scr_arg fscr
;
4561 fscr
.xypos
.x
= fw
->g
.frame
.x
+ fw
->g
.frame
.width
/ 2 - page_x
;
4562 fscr
.xypos
.y
= fw
->g
.frame
.y
+ fw
->g
.frame
.height
/ 2 - page_y
;
4564 &fscr
, FSCREEN_XYPOS
, &scr_x
, &scr_y
, &scr_w
, &scr_h
);
4567 if (!ignore_working_area
)
4569 EWMH_GetWorkAreaIntersection(
4570 fw
, &scr_x
, &scr_y
, &scr_w
, &scr_h
,
4571 EWMH_MAXIMIZE_MODE(fw
));
4574 fprintf(stderr
, "%s: page=(%d,%d), scr=(%d,%d, %dx%d)\n", __FUNCTION__
,
4575 page_x
, page_y
, scr_x
, scr_y
, scr_w
, scr_h
);
4578 /* parse first parameter */
4580 token
= PeekToken(action
, &taction
);
4581 if (token
&& StrEquals(token
, "grow"))
4588 else if (token
&& StrEquals(token
, "growleft"))
4594 else if (token
&& StrEquals(token
, "growright"))
4602 if (GetOnePercentArgument(token
, &val1
, &val1_unit
) == 0)
4609 /* handle negative offsets */
4610 if (val1_unit
== scr_w
)
4616 val1
= scr_w
+ val1
;
4621 /* parse second parameter */
4623 token
= PeekToken(taction
, NULL
);
4624 if (token
&& StrEquals(token
, "grow"))
4631 else if (token
&& StrEquals(token
, "growup"))
4637 else if (token
&& StrEquals(token
, "growdown"))
4645 if (GetOnePercentArgument(token
, &val2
, &val2_unit
) == 0)
4652 /* handle negative offsets */
4653 if (val2_unit
== scr_h
)
4659 val2
= scr_h
+ val2
;
4665 fprintf(stderr
, "%s: page=(%d,%d), scr=(%d,%d, %dx%d)\n", __FUNCTION__
,
4666 page_x
, page_y
, scr_x
, scr_y
, scr_w
, scr_h
);
4669 if (IS_MAXIMIZED(fw
) && !do_force_maximize
)
4671 unmaximize_fvwm_window(fw
);
4675 /* handle command line arguments */
4676 if (grow_up
|| grow_down
)
4679 fw
, new_g
.width
, new_g
.x
, &new_g
.height
,
4680 &new_g
.y
, grow_up
, grow_down
, page_y
+ scr_y
,
4681 page_y
+ scr_y
+ scr_h
, layers
);
4685 new_g
.height
= val2
* val2_unit
/ 100;
4686 new_g
.y
= page_y
+ scr_y
;
4688 if (grow_left
|| grow_right
)
4691 fw
, &new_g
.width
, &new_g
.x
, new_g
.height
,
4692 new_g
.y
, grow_left
, grow_right
,
4693 page_x
+ scr_x
, page_x
+ scr_x
+ scr_w
,
4698 new_g
.width
= val1
* val1_unit
/ 100;
4699 new_g
.x
= page_x
+ scr_x
;
4701 if (val1
== 0 && val2
== 0)
4703 new_g
.x
= page_x
+ scr_x
;
4704 new_g
.y
= page_y
+ scr_y
;
4705 new_g
.height
= scr_h
;
4706 new_g
.width
= scr_w
;
4708 /* now maximize it */
4709 maximize_fvwm_window(fw
, &new_g
);
4711 EWMH_SetWMState(fw
, False
);
4712 GNOME_SetWinArea(fw
);
4719 * Same as CMD_Resize and CMD_ResizeMove, but the window ends up maximized
4720 * without touching the normal geometry.
4723 void CMD_ResizeMaximize(F_CMD_ARGS
)
4728 FvwmWindow
*fw
= exc
->w
.fw
;
4730 /* keep a copy of the old geometry */
4731 normal_g
= fw
->g
.normal
;
4732 /* resize the window normally */
4733 was_resized
= __resize_window(F_PASS_ARGS
);
4734 if (was_resized
== True
)
4736 /* set the new geometry as the maximized geometry and restore
4737 * the old normal geometry */
4738 max_g
= fw
->g
.normal
;
4741 fw
->g
.normal
= normal_g
;
4742 /* and mark it as maximized */
4743 maximize_fvwm_window(fw
, &max_g
);
4745 EWMH_SetWMState(fw
, False
);
4750 void CMD_ResizeMoveMaximize(F_CMD_ARGS
)
4755 FvwmWindow
*fw
= exc
->w
.fw
;
4757 /* keep a copy of the old geometry */
4758 normal_g
= fw
->g
.normal
;
4759 /* resize the window normally */
4760 was_resized
= resize_move_window(F_PASS_ARGS
);
4761 if (was_resized
== True
)
4763 /* set the new geometry as the maximized geometry and restore
4764 * the old normal geometry */
4765 max_g
= fw
->g
.normal
;
4768 fw
->g
.normal
= normal_g
;
4769 /* and mark it as maximized */
4770 maximize_fvwm_window(fw
, &max_g
);
4772 EWMH_SetWMState(fw
, False
);
4777 /* ----------------------------- stick code -------------------------------- */
4779 int stick_across_pages(F_CMD_ARGS
, int toggle
)
4781 FvwmWindow
*fw
= exc
->w
.fw
;
4783 if ((toggle
== 1 && IS_STICKY_ACROSS_PAGES(fw
)) ||
4784 (toggle
== 0 && !IS_STICKY_ACROSS_PAGES(fw
)))
4788 if (IS_STICKY_ACROSS_PAGES(fw
))
4790 SET_STICKY_ACROSS_PAGES(fw
, 0);
4794 if (!IsRectangleOnThisPage(&fw
->g
.frame
, Scr
.CurrentDesk
))
4797 __move_window(F_PASS_ARGS
, False
, MOVE_PAGE
);
4799 SET_STICKY_ACROSS_PAGES(fw
, 1);
4805 int stick_across_desks(F_CMD_ARGS
, int toggle
)
4807 FvwmWindow
*fw
= exc
->w
.fw
;
4809 if ((toggle
== 1 && IS_STICKY_ACROSS_DESKS(fw
)) ||
4810 (toggle
== 0 && !IS_STICKY_ACROSS_DESKS(fw
)))
4815 if (IS_STICKY_ACROSS_DESKS(fw
))
4817 SET_STICKY_ACROSS_DESKS(fw
, 0);
4818 fw
->Desk
= Scr
.CurrentDesk
;
4819 GNOME_SetDeskCount();
4824 if (fw
->Desk
!= Scr
.CurrentDesk
)
4826 do_move_window_to_desk(fw
, Scr
.CurrentDesk
);
4828 SET_STICKY_ACROSS_DESKS(fw
, 1);
4834 static void __handle_stick_exit(
4835 FvwmWindow
*fw
, int do_not_draw
, int do_silently
)
4837 if (do_not_draw
== 0)
4839 border_draw_decorations(
4840 fw
, PART_TITLE
| PART_BUTTONS
, (Scr
.Hilite
==fw
), True
,
4841 CLEAR_ALL
, NULL
, NULL
);
4845 BroadcastConfig(M_CONFIGURE_WINDOW
,fw
);
4846 EWMH_SetWMState(fw
, False
);
4847 EWMH_SetWMDesktop(fw
);
4854 void handle_stick_across_pages(
4855 F_CMD_ARGS
, int toggle
, int do_not_draw
, int do_silently
)
4857 FvwmWindow
*fw
= exc
->w
.fw
;
4860 did_change
= stick_across_pages(F_PASS_ARGS
, toggle
);
4863 __handle_stick_exit(fw
, do_not_draw
, do_silently
);
4869 void handle_stick_across_desks(
4870 F_CMD_ARGS
, int toggle
, int do_not_draw
, int do_silently
)
4872 FvwmWindow
*fw
= exc
->w
.fw
;
4875 did_change
= stick_across_desks(F_PASS_ARGS
, toggle
);
4878 __handle_stick_exit(fw
, do_not_draw
, do_silently
);
4885 F_CMD_ARGS
, int toggle_page
, int toggle_desk
, int do_not_draw
,
4888 FvwmWindow
*fw
= exc
->w
.fw
;
4892 did_change
|= stick_across_desks(F_PASS_ARGS
, toggle_desk
);
4893 did_change
|= stick_across_pages(F_PASS_ARGS
, toggle_page
);
4896 __handle_stick_exit(fw
, do_not_draw
, do_silently
);
4902 void CMD_Stick(F_CMD_ARGS
)
4906 toggle
= ParseToggleArgument(action
, &action
, -1, 0);
4907 if (toggle
== -1 && IS_STICKY_ACROSS_DESKS(exc
->w
.fw
) !=
4908 IS_STICKY_ACROSS_PAGES(exc
->w
.fw
))
4910 /* don't switch between only stickypage and only stickydesk.
4911 * rather switch it off completely */
4914 handle_stick(F_PASS_ARGS
, toggle
, toggle
, 0, 0);
4919 void CMD_StickAcrossPages(F_CMD_ARGS
)
4923 toggle
= ParseToggleArgument(action
, &action
, -1, 0);
4924 handle_stick_across_pages(F_PASS_ARGS
, toggle
, 0, 0);
4929 void CMD_StickAcrossDesks(F_CMD_ARGS
)
4933 toggle
= ParseToggleArgument(action
, &action
, -1, 0);
4934 handle_stick_across_desks(F_PASS_ARGS
, toggle
, 0, 0);