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 /* syntax error, ignore rest of string */
411 n
= ParsePositionArgumentSuffix(&f
, s1
, wfactor
, sfactor
);
413 final_pos
+= __get_shift(val
, f
);
415 *pFinalPos
= final_pos
;
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
)
441 int scr_w
= Scr
.MyDisplayWidth
;
442 int scr_h
= Scr
.MyDisplayHeight
;
450 action
= GetNextToken(action
, &s1
);
451 if (s1
&& fPointer
&& StrEquals(s1
, "pointer"))
458 if (s1
&& StrEquals(s1
, "screen"))
463 fscreen_scr_arg
* parg
;
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
;
478 FScreenGetScrRect(parg
, scr
, &scr_x
, &scr_y
, &scr_w
, &scr_h
);
479 action
= GetNextToken(action
, &s1
);
481 action
= GetNextToken(action
, &s2
);
484 warp
= PeekToken(action
, &naction
);
485 if (StrEquals(warp
, "Warp"))
492 if (s1
!= NULL
&& s2
!= NULL
)
495 if (fKeep
== True
&& StrEquals(s1
, "keep"))
500 GetOnePositionArgument(
501 s1
, *pFinalX
, w
, pFinalX
, (float)scr_w
/ 100,
506 if (fKeep
== True
&& StrEquals(s2
, "keep"))
511 GetOnePositionArgument(
512 s2
, *pFinalY
, h
, pFinalY
, (float)scr_h
/ 100,
513 scr_h
, scr_y
, False
))
519 /* make sure warping is off for interactive moves */
525 /* not enough arguments, switch to current page. */
528 *pFinalX
= Scr
.MyDisplayWidth
+ *pFinalX
;
532 *pFinalY
= Scr
.MyDisplayHeight
+ *pFinalY
;
549 static int ParseOneResizeArgument(
550 char *arg
, int scr_size
, int base_size
, int size_inc
, int add_size
,
555 int add_base_size
= 0;
556 int cch
= strlen(arg
);
563 if (StrEquals(arg
, "keep"))
565 /* do not change size */
568 if (arg
[cch
-1] == 'p')
573 else if (arg
[cch
-1] == 'c')
576 add_base_size
= base_size
;
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
;
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
;
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
;
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
;
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
)
656 int has_frame_option
;
659 *is_direction_fixed
= False
;
660 *do_warp_to_border
= False
;
665 token
= PeekToken(*paction
, &naction
);
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
);
681 *pFinalW
= nx
- x
+ 1;
682 *pFinalH
= ny
- y
+ 1;
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"))
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
;
720 if (has_frame_option
)
727 w_add
= sb
->total_size
.width
;
728 h_add
= sb
->total_size
.height
;
733 s1
= safestrdup(token
);
735 naction
= GetNextToken(naction
, &s2
);
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
);
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
;
780 if (GetResizeArguments(
781 &action
, *pFinalX
, *pFinalY
, w_base
, h_base
, w_inc
, h_inc
,
782 sb
, pFinalW
, pFinalH
, &dir
, &dummy
, &dummy
) < 2)
786 if (GetMoveArguments(
787 &action
, *pFinalW
, *pFinalH
, pFinalX
, pFinalY
, fWarp
,
797 /* Positions the SizeWindow on the current ("moused") xinerama-screen */
798 static void position_geometry_window(const XEvent
*eventp
)
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
,
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
);
829 void resize_geometry_window(void)
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
);
849 dpy
, Scr
.SizeWindow
, w
, h
, &Colorset
[cset
], Pdepth
,
854 XSetWindowBackground(dpy
, Scr
.SizeWindow
, Scr
.StdBack
);
863 * DisplayPosition - display the position in the dimensions window
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
)
876 fscreen_scr_arg fscr
;
877 FlocaleWinString fstr
;
879 if (Scr
.gs
.do_hide_position_window
)
883 position_geometry_window(eventp
);
884 /* Translate x,y into local screen coordinates,
885 * in case Xinerama is used. */
888 FScreenTranslateCoordinates(
889 NULL
, FSCREEN_GLOBAL
, &fscr
, FSCREEN_XYPOS
, &x
, &y
);
890 (void)sprintf(str
, GEOMETRY_WINDOW_POS_STRING
, x
, y
);
893 XClearWindow(dpy
, Scr
.SizeWindow
);
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
);
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
;
922 fstr
.win
= Scr
.SizeWindow
;
925 fstr
.y
= Scr
.DefaultFont
->ascent
+ GEOMETRY_WINDOW_BW
;
926 FlocaleDrawString(dpy
, Scr
.DefaultFont
, &fstr
, 0);
935 * DisplaySize - display the size in the dimensions window
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
)
948 int dwidth
,dheight
,offset
;
950 static int last_width
= 0;
951 static int last_height
= 0;
952 FlocaleWinString fstr
;
954 if (Scr
.gs
.do_hide_resize_window
)
958 position_geometry_window(eventp
);
964 if (last_width
== width
&& last_height
== height
)
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
);
982 XClearWindow(dpy
,Scr
.SizeWindow
);
986 /* just clear indside the relief lines to reduce flicker */
988 dpy
, Scr
.SizeWindow
, GEOMETRY_WINDOW_BW
,
989 GEOMETRY_WINDOW_BW
, Scr
.SizeStringWidth
,
990 Scr
.DefaultFont
->height
, False
);
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
;
1011 fstr
.win
= Scr
.SizeWindow
;
1012 fstr
.gc
= Scr
.StdGC
;
1014 fstr
.y
= Scr
.DefaultFont
->ascent
+ GEOMETRY_WINDOW_BW
;
1015 FlocaleDrawString(dpy
, Scr
.DefaultFont
, &fstr
, 0);
1020 static Bool
resize_move_window(F_CMD_ARGS
)
1029 Bool fPointer
= False
;
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
))
1041 if (!is_function_allowed(F_RESIZE
, NULL
, fw
, RQORIG_PROGRAM_US
, True
))
1046 /* gotta have a window */
1049 dpy
, w
, &JunkRoot
, &x
, &y
, (unsigned int*)&FinalW
,
1050 (unsigned int*)&FinalH
, (unsigned int*)&JunkBW
,
1051 (unsigned int*)&JunkDepth
))
1060 get_window_borders(fw
, &b
);
1061 n
= GetResizeMoveArguments(
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
);
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
,
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);
1087 fw
, FinalX
, FinalY
, FinalW
, fw
->g
.frame
.height
, False
);
1091 frame_setup_window(fw
, FinalX
, FinalY
, FinalW
, FinalH
, True
);
1096 dpy
, None
, None
, 0, 0, 0, 0, FinalX
- x
, FinalY
- y
);
1098 if (IS_MAXIMIZED(fw
))
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
);
1112 GNOME_SetWinArea(fw
);
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
);
1127 resize_move_window(F_PASS_ARGS
);
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
;
1139 Bool do_move_opaque
= False
;
1143 if (Scr
.bo
.do_install_root_cmap
)
1145 InstallRootColormap();
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 */
1156 if (do_start_at_pointer
)
1159 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &DragX
,
1160 &DragY
, &JunkX
, &JunkY
, &JunkMask
) == False
)
1162 /* pointer is on a different screen */
1169 /* Although a move is usually done with a button depressed we
1170 * have to check for ButtonRelease too since the event may be
1172 fev_get_evpos_or_query(
1173 dpy
, Scr
.Root
, exc
->x
.elast
, &DragX
, &DragY
);
1178 dpy
, w
, &JunkRoot
, &origDragX
, &origDragY
,
1179 (unsigned int*)&DragWidth
, (unsigned int*)&DragHeight
,
1180 (unsigned int*)&JunkBW
, (unsigned int*)&JunkDepth
))
1182 MyXUngrabServer(dpy
);
1185 MyXGrabKeyboard(dpy
);
1186 if (do_start_at_pointer
)
1192 if (IS_ICONIFIED(exc
->w
.fw
))
1194 do_move_opaque
= True
;
1196 else if (IS_MAPPED(exc
->w
.fw
))
1201 areapct
*= ((float)DragWidth
/ (float)Scr
.MyDisplayWidth
);
1202 areapct
*= ((float)DragHeight
/ (float)Scr
.MyDisplayHeight
);
1205 if (Scr
.OpaqueSize
< 0 ||
1206 (float)areapct
<= (float)Scr
.OpaqueSize
)
1208 do_move_opaque
= True
;
1213 MyXUngrabServer(dpy
);
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
);
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();
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
);
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
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
;
1274 unsigned int draw_parts
= PART_NONE
;
1276 if (!is_function_allowed(F_MOVE
, NULL
, fw
, RQORIG_PROGRAM_US
, False
))
1281 /* set our defaults */
1282 if (ppctMovement
== NULL
)
1284 ppctMovement
= rgpctMovementDefault
;
1288 cmsDelay
= cmsDelayDefault
;
1291 if (startX
< 0 || startY
< 0)
1295 dpy
, w
, &JunkRoot
, ¤tX
, ¤tY
,
1296 (unsigned int*)&JunkWidth
,
1297 (unsigned int*)&JunkHeight
,
1298 (unsigned int*)&JunkBW
,
1299 (unsigned int*)&JunkDepth
))
1314 deltaX
= endX
- startX
;
1315 deltaY
= endY
- startY
;
1319 if (deltaX
== 0 && deltaY
== 0)
1321 /* go nowhere fast */
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 */
1343 update_transparent_menu_bg(
1344 pmrtp
, lastX
, lastY
, currentX
, currentY
,
1347 XMoveWindow(dpy
,w
,currentX
,currentY
);
1350 repaint_transparent_menu(
1352 currentX
, currentY
, endX
, endY
, True
);
1354 else if (draw_parts
!= PART_NONE
)
1356 border_draw_decorations(
1358 ((fw
== get_focus_window())) ?
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
)
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
;
1379 pointerX
+= currentX
- lastX
;
1380 pointerY
+= currentY
- lastY
;
1383 dpy
, None
, Scr
.Root
, 0, 0, 0, 0, pointerX
,
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
,
1393 fw
->g
.frame
.height
, 0, False
);
1394 #ifdef FVWM_DEBUG_MSGS
1395 fvwm_msg(DBG
,"AnimatedMoveAnyWindow",
1396 "Sent ConfigureNotify (w == %d, h == %d)",
1398 fw
->g
.frame
.height
);
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
,
1424 /* finish the move immediately */
1427 update_transparent_menu_bg(
1428 pmrtp
, lastX
, lastY
,
1429 currentX
, currentY
, endX
, endY
);
1431 XMoveWindow(dpy
,w
,endX
,endY
);
1434 repaint_transparent_menu(
1436 endX
, endY
, endX
, endY
, True
);
1443 } while (*ppctMovement
!= 1.0 && ppctMovement
++);
1444 MyXUngrabKeyboard(dpy
);
1448 GNOME_SetWinArea(fw
);
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
);
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
);
1479 int placement_binding(int button
, KeySym keysym
, int modifier
, char *action
)
1485 ERR
, "placement_binding",
1486 "sorry, placement keybindings not allowed. yet.");
1493 ERR
, "placement_binding",
1494 "sorry, placement binding modifiers not allowed. yet.");
1497 if (strcmp(action
,"-") == 0 ||
1498 strcasecmp(action
,"CancelPlacement") == 0)
1500 if (keysym
== 0) /* must be button binding */
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
&=
1512 move_interactive_finish_button_mask
&=
1517 else if (strcasecmp(action
,"CancelPlacementDrag") == 0)
1519 if (keysym
== 0) /* must be button binding */
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
&=
1533 else if (strcasecmp(action
,"CancelPlacementInteractive") == 0)
1535 if (keysym
== 0) /* must be button binding */
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
&=
1549 else if (strcasecmp(action
,"PlaceWindow") == 0)
1551 if (keysym
== 0) /* must be button binding */
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
|=
1568 else if (strcasecmp(action
,"PlaceWindowDrag") == 0)
1570 if (keysym
== 0) /* must be button binding */
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 */
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
|=
1604 ERR
, "placement_binding",
1605 "invalid action %s", action
);
1614 * Start a window move operation
1618 FvwmWindow
*fw
, int x
, int y
, int old_x
, int old_y
,
1619 Bool do_move_animated
, Bool do_warp_pointer
)
1623 Bool has_icon_title
;
1624 Bool has_icon_picture
;
1629 set_icon_position(fw
, x
, y
);
1630 broadcast_icon_geometry(fw
, False
);
1631 has_icon_title
= get_visible_icon_title_geometry(fw
, >
);
1632 has_icon_picture
= get_visible_icon_picture_geometry(fw
, &gp
);
1633 if (has_icon_picture
)
1635 tw
= FW_W_ICON_PIXMAP(fw
);
1639 else if (has_icon_title
)
1641 tw
= FW_W_ICON_TITLE(fw
);
1649 if (do_move_animated
)
1651 AnimatedMoveOfWindow(
1652 tw
, -1, -1, tx
, ty
, do_warp_pointer
, -1, NULL
, NULL
);
1653 do_warp_pointer
= 0;
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
));
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
);
1679 static void __move_window(F_CMD_ARGS
, Bool do_animate
, int mode
)
1689 Bool fPointer
= False
;
1692 FvwmWindow
*fw
= exc
->w
.fw
;
1695 if (!is_function_allowed(F_MOVE
, NULL
, fw
, RQORIG_PROGRAM_US
, False
))
1699 /* gotta have a window */
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
));
1710 w
= FW_W_ICON_TITLE(fw
);
1712 if (w
== None
&& (mode
== MOVE_PAGE
|| mode
== MOVE_SCREEN
))
1719 dpy
, w
, &JunkRoot
, &x
, &y
, (unsigned int*)&width
,
1720 (unsigned int*)&height
, (unsigned int*)&JunkBW
,
1721 (unsigned int*)&JunkDepth
))
1725 if (mode
== MOVE_PAGE
&& IS_STICKY_ACROSS_PAGES(fw
))
1729 if (mode
== MOVE_PAGE
)
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
))
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
);
1755 else if (mode
== MOVE_SCREEN
)
1763 fscreen
= FScreenGetScreenArgument(
1764 action
, FSCREEN_SPEC_CURRENT
);
1766 NULL
, fscreen
, &s
.x
, &s
.y
, &s
.width
, &s
.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
);
1788 n
= GetMoveArguments(
1789 &action
, width
, height
, &FinalX
, &FinalY
, &fWarp
,
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
;
1808 AnimatedMoveFvwmWindow(
1809 fw
, w
, -1, -1, FinalX
, FinalY
, fWarp
, -1,
1813 fw
, FinalX
, FinalY
, fw
->g
.frame
.width
,
1814 fw
->g
.frame
.height
, True
);
1815 if (fWarp
& !do_animate
)
1818 dpy
, None
, None
, 0, 0, 0, 0, FinalX
- x
,
1821 if (IS_MAXIMIZED(fw
))
1828 fw
->g
.normal
.x
+= dx
;
1829 fw
->g
.normal
.y
+= dy
;
1831 update_absolute_geometry(fw
);
1832 maximize_adjust_offset(fw
);
1834 GNOME_SetWinArea(fw
);
1836 else /* icon window */
1838 __move_icon(fw
, FinalX
, FinalY
, x
, y
, do_animate
, fWarp
);
1841 focus_grab_buttons_on_layer(fw
->layer
);
1846 void CMD_Move(F_CMD_ARGS
)
1848 __move_window(F_PASS_ARGS
, False
, MOVE_NORMAL
);
1853 void CMD_AnimatedMove(F_CMD_ARGS
)
1855 __move_window(F_PASS_ARGS
, True
, MOVE_NORMAL
);
1860 void CMD_MoveToPage(F_CMD_ARGS
)
1862 __move_window(F_PASS_ARGS
, False
, MOVE_PAGE
);
1867 void CMD_MoveToScreen(F_CMD_ARGS
)
1869 __move_window(F_PASS_ARGS
, False
, MOVE_SCREEN
);
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
;
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
;
1892 self
.height
= Height
;
1897 rc
= get_visible_icon_title_geometry(fw
, &g
);
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
;
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
)))
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
)
1941 if (fw
->Desk
!= tmp
->Desk
|| fw
== tmp
)
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
))
1954 case SNAP_ICONS
: /* we only snap icons */
1955 if (!IS_ICONIFIED(tmp
) || !IS_ICONIFIED(fw
))
1960 case SNAP_SAME
: /* we don't snap unequal */
1961 if (IS_ICONIFIED(tmp
) != IS_ICONIFIED(fw
))
1970 /* get other window dimensions */
1971 get_visible_window_or_icon_geometry(tmp
, &other
);
1972 /* prevent that window snaps off screen */
1975 other
.x
-= fw
->snap_attraction
.proximity
+ 10000;
1976 other
.width
+= fw
->snap_attraction
.proximity
+ 10000;
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 */
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
&&
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
)
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 */
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
)
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
;
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
))
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
&&
2101 Scr
.MyDisplayHeight
+ fw
->snap_attraction
.proximity
)
2103 nyt
= Scr
.MyDisplayHeight
-
2106 if (*py
+ self
.height
>=
2107 Scr
.MyDisplayHeight
- fw
->snap_attraction
.proximity
&&
2108 *py
+ self
.height
< Scr
.MyDisplayHeight
)
2110 nyt
= Scr
.MyDisplayHeight
-
2115 if (dist
< closestTop
)
2118 if ((*py
<= 0)&&(*py
> - fw
->snap_attraction
.proximity
))
2122 if ((*py
<= fw
->snap_attraction
.proximity
)&&(*py
> 0))
2127 } /* horizontally */
2129 if (!(Scr
.MyDisplayHeight
< (*py
) ||
2130 (*py
+ self
.height
) < 0))
2133 Scr
.MyDisplayWidth
- (*px
+ self
.width
));
2134 if (dist
< closestRight
)
2136 closestRight
= dist
;
2138 if (*px
+ self
.width
>= Scr
.MyDisplayWidth
&&
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
;
2153 if (dist
< closestLeft
)
2158 (*px
> - fw
->snap_attraction
.proximity
))
2162 if ((*px
<= fw
->snap_attraction
.proximity
) &&
2169 } /* snap to screen edges */
2181 * Resist moving windows beyond the edge of the screen
2183 if (fw
->edge_resistance_move
> 0)
2185 /* snap to right edge */
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
))
2198 /* snap to bottom edge */
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
)
2212 /* Resist moving windows between xineramascreens */
2213 if (fw
->edge_resistance_xinerama_move
> 0 && FScreenIsEnabled())
2217 Bool do_recalc_rectangle
= False
;
2219 FScreenGetResistanceRect(
2220 *px
, *py
, Width
, Height
, &scr_x0
, &scr_y0
, &scr_x1
,
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 */
2234 *px
<= scr_x0
&& scr_x0
- *px
<
2235 fw
->edge_resistance_xinerama_move
)
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
,
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 */
2259 *py
<= scr_y0
&& scr_y0
- *py
<
2260 fw
->edge_resistance_xinerama_move
)
2271 * Move the rubberband around, return with the new window location
2273 * Returns True if the window has to be resized after the move.
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;
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
;
2294 int x_virtual_offset
= 0;
2295 int y_virtual_offset
= 0;
2296 Bool sent_cn
= False
;
2297 Bool do_resize_too
= False
;
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
2307 Bool nosnap_enabled
= False
;
2308 /* Must not set placed by button if the event is a modified KeyEvent */
2310 FvwmWindow
*fw
= exc
->w
.fw
;
2311 unsigned int draw_parts
= PART_NONE
;
2314 if (!GrabEm(cursor
, GRAB_NORMAL
))
2319 if (!IS_MAPPED(fw
) && !IS_ICONIFIED(fw
))
2321 do_move_opaque
= False
;
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
);
2337 move_w
= FW_W_FRAME(fw
);
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
2349 if (IS_ICONIFIED(fw
))
2353 get_visible_icon_geometry(fw
, &g
);
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
);
2364 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &xl
, &yt
,
2365 &JunkX
, &JunkY
, &button_mask
) == False
)
2367 /* pointer is on a different screen */
2376 button_mask
&= DEFAULT_ALL_BUTTONS_MASK
;
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
))
2407 /* wait until there is an interesting event */
2411 dpy
, ButtonPressMask
| ButtonReleaseMask
|
2412 KeyPressMask
| PointerMotionMask
|
2413 ButtonMotionMask
| ExposureMask
, &e
)))
2417 fev_get_last_event(&le
);
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 */
2429 x_virtual_offset
= 0;
2434 y_virtual_offset
= 0;
2440 fw
, Width
, Height
, &xl
, &yt
);
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
;
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. */
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 &&
2472 dpy
, ButtonMotionMask
|
2473 PointerMotionMask
| ButtonPressMask
|
2474 ButtonRelease
| KeyPressMask
|
2475 EnterWindowMask
| LeaveWindowMask
, &e
))
2477 if (e
.type
== ButtonPress
||
2478 e
.type
== ButtonRelease
||
2485 if (e
.type
== EnterNotify
|| e
.type
== LeaveNotify
)
2491 /* Query the pointer to catch the latest information.
2492 * This *is* necessary. */
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
;
2509 /* pointer is on a different screen,
2513 is_fake_event
= False
;
2514 /* Handle a limited number of key press events to allow
2515 * mouseless operation */
2516 if (e
.type
== KeyPress
)
2519 &e
, fw
, &x_virtual_offset
,
2520 &y_virtual_offset
, ButtonRelease
);
2522 is_fake_event
= (e
.type
!= 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
))
2545 *FinalX
= fw
->g
.frame
.x
;
2546 *FinalY
= fw
->g
.frame
.y
;
2551 *FinalX
= orig_icon_x
;
2552 *FinalY
= orig_icon_y
;
2559 if (e
.xbutton
.button
<= NUMBER_OF_MOUSE_BUTTONS
&&
2560 ((Button1Mask
<< (e
.xbutton
.button
- 1)) &
2563 /* No new button was pressed, just a delayed
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
;
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 */
2596 /* Abort the move if
2597 * - the move started with a pressed button
2598 * and another button was pressed during the
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
;
2621 *FinalX
= orig_icon_x
;
2622 *FinalY
= orig_icon_y
;
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)))
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! */
2659 fw
, Width
, Height
, &xl
, &yt
);
2671 if (e
.xmotion
.same_screen
== False
)
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
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
2695 y_virtual_offset
= 0;
2697 xl
+= XOffset
+ x_virtual_offset
;
2698 yt
+= YOffset
+ y_virtual_offset
;
2702 DoSnapAttract(fw
, Width
, Height
, &xl
, &yt
);
2706 /* check Paging request once and only once after
2707 * outline redrawn redraw after paging if needed
2709 for (paged
= 0; paged
<= 1; paged
++)
2711 if (!do_move_opaque
)
2713 draw_move_resize_grid(
2714 xl
, yt
, Width
- 1, Height
- 1);
2718 if (IS_ICONIFIED(fw
))
2720 set_icon_position(fw
, xl
, yt
);
2721 move_icon_to_position(fw
);
2722 broadcast_icon_geometry(
2728 dpy
, FW_W_FRAME(fw
),
2732 DisplayPosition(fw
, &e
, xl
, yt
, False
);
2734 /* prevent window from lagging behind mouse
2735 * when paging - mab */
2740 xl
= e
.xmotion
.x_root
;
2741 yt
= e
.xmotion
.y_root
;
2742 fev_get_last_event(&le
);
2744 &le
, dx
, dy
, &xl
, &yt
,
2745 &delta_x
, &delta_y
, False
,
2747 fw
->edge_delay_ms_move
);
2750 x_virtual_offset
= 0;
2755 y_virtual_offset
= 0;
2765 if (!delta_x
&& !delta_y
)
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
);
2783 if (!do_move_opaque
)
2785 draw_move_resize_grid(
2786 xl
, yt
, Width
- 1, Height
- 1);
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
)
2807 SendConfigureNotify(
2808 fw
, xl
, yt
, Width
, Height
, 0,
2810 #ifdef FVWM_DEBUG_MSGS
2812 DBG
, "frame_setup_window",
2813 "Sent ConfigureNotify (w %d, h %d)",
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(
2833 ((fw
== get_focus_window())) ?
2835 True
, CLEAR_ALL
, NULL
, NULL
);
2837 if (IS_TEAR_OFF_MENU(fw
))
2839 menu_redraw_transparent_tear_off_menu(
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(
2865 ((fw
== get_focus_window())) ?
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
);
2878 if (!is_aborted
&& bad_window
!= FW_W(fw
) && IS_ICONIFIED(fw
))
2880 SET_ICON_MOVED(fw
, 1);
2882 UngrabEm(GRAB_NORMAL
);
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);
2892 return do_resize_too
;
2895 void CMD_MoveThreshold(F_CMD_ARGS
)
2899 if (GetIntegerArguments(action
, NULL
, &val
, 1) < 1 || val
< 0)
2901 Scr
.MoveThreshold
= DEFAULT_MOVE_THRESHOLD
;
2905 Scr
.MoveThreshold
= val
;
2911 void CMD_OpaqueMoveSize(F_CMD_ARGS
)
2915 if (GetIntegerArguments(action
, NULL
, &val
, 1) < 1)
2917 if (strncasecmp(action
, "unlimited", 9) == 0)
2919 Scr
.OpaqueSize
= -1;
2923 Scr
.OpaqueSize
= DEFAULT_OPAQUE_MOVE_SIZE
;
2928 Scr
.OpaqueSize
= val
;
2935 static char *hide_options
[] =
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
))
2954 Scr
.gs
.do_hide_position_window
= 1;
2957 Scr
.gs
.do_hide_resize_window
= 1;
2960 Scr
.gs
.do_hide_position_window
= 1;
2961 Scr
.gs
.do_hide_resize_window
= 1;
2967 void CMD_SnapAttraction(F_CMD_ARGS
)
2972 len
= strlen(action
);
2974 cmd
= safemalloc(len
);
2975 sprintf(cmd
, "Style * SnapAttraction %s", action
);
2977 OLD
, "CMD_SnapAttraction",
2978 "The command SnapAttraction is obsolete. Please use the"
2979 " following command instead:");
2980 fvwm_msg(OLD
, "", cmd
);
2983 FUNC_DONT_REPEAT
| FUNC_DONT_EXPAND_COMMAND
);
2989 void CMD_SnapGrid(F_CMD_ARGS
)
2994 len
= strlen(action
);
2996 cmd
= safemalloc(len
);
2997 sprintf(cmd
, "Style * SnapGrid %s", action
);
2999 OLD
, "CMD_SnapGrid",
3000 "The command SnapGrid is obsolete. Please use the following"
3001 " command instead:");
3002 fvwm_msg(OLD
, "", cmd
);
3005 FUNC_DONT_REPEAT
| FUNC_DONT_EXPAND_COMMAND
);
3011 static Pixmap XorPixmap
= None
;
3013 void CMD_XorValue(F_CMD_ARGS
)
3019 if (GetIntegerArguments(action
, NULL
, &val
, 1) != 1)
3024 PictureUseDefaultVisual();
3025 gcm
= GCFunction
|GCLineWidth
|GCForeground
|GCFillStyle
|GCSubwindowMode
;
3026 gcv
.subwindow_mode
= IncludeInferiors
;
3027 gcv
.function
= GXxor
;
3029 /* use passed in value, or try to calculate appropriate value if 0 */
3032 gcv.foreground = (val1)?(val1):((((unsigned long) 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 */
3044 XChangeGC(dpy
, Scr
.XorGC
, gcm
, &gcv
);
3048 Scr
.XorGC
= fvwmlib_XCreateGC(dpy
, Scr
.Root
, gcm
, &gcv
);
3051 /* free up XorPixmap if neccesary */
3052 if (XorPixmap
!= None
) {
3053 XFreePixmap(dpy
, XorPixmap
);
3056 PictureUseFvwmVisual();
3062 void CMD_XorPixmap(F_CMD_ARGS
)
3068 FvwmPictureAttributes fpa
;
3070 action
= GetNextToken(action
, &PixmapName
);
3071 if (PixmapName
== NULL
)
3073 /* return to default value. */
3075 CMD_XorValue(F_PASS_ARGS
);
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
);
3085 fvwm_msg(ERR
,"SetXORPixmap","Can't find pixmap %s", PixmapName
);
3087 PictureUseFvwmVisual();
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 */
3111 gcv
.tile
= XorPixmap
;
3112 gcv
.fill_style
= FillTiled
;
3113 gcv
.subwindow_mode
= IncludeInferiors
;
3114 /* modify XorGC, only create once */
3117 XChangeGC(dpy
, Scr
.XorGC
, gcm
, &gcv
);
3121 Scr
.XorGC
= fvwmlib_XCreateGC(dpy
, Scr
.Root
, gcm
, &gcv
);
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 */
3139 else if (context_w
== FW_W_SIDE(fw
, 1)) /* right */
3143 else if (context_w
== FW_W_SIDE(fw
, 2)) /* bottom */
3147 else if (context_w
== FW_W_SIDE(fw
, 3)) /* left */
3151 else if (context_w
== FW_W_CORNER(fw
, 0)) /* upper-left */
3156 else if (context_w
== FW_W_CORNER(fw
, 1)) /* upper-right */
3161 else if (context_w
== FW_W_CORNER(fw
, 2)) /* lower left */
3166 else if (context_w
== FW_W_CORNER(fw
, 3)) /* lower right */
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
)
3183 if (px
< 0 || x_off
< 0 || py
< 0 || y_off
< 0)
3187 /* Now find the place to warp to. We simply use the sectors
3188 * drawn when we start resizing the window. */
3190 tx
= orig
->width
/ 10 - 1;
3191 ty
= orig
->height
/ 10 - 1;
3196 tx
= max(fw
->boundary_width
, tx
);
3197 ty
= max(fw
->boundary_width
, ty
);
3202 else if (x_off
< tx
)
3210 else if (y_off
< ty
)
3218 static void __resize_get_refpos(
3219 int *ret_x
, int *ret_y
, int xmotion
, int ymotion
, int w
, int h
,
3226 else if (xmotion
< 0)
3238 else if (ymotion
< 0)
3251 * __resize_step - move the rubberband around. This is called for
3252 * each motion event when we are resizing
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
)
3276 x2
= x_root
- *x_off
;
3278 if (is_direction_fixed
== True
&& (*xmotionp
!= 0 || *ymotionp
!= 0))
3282 else if (x2
<= orig
->x
||
3283 (*xmotionp
== 1 && x2
< orig
->x
+ orig
->width
- 1))
3287 else if (x2
>= orig
->x
+ orig
->width
- 1 ||
3288 (*xmotionp
== -1 && x2
> orig
->x
))
3306 drag
->width
= orig
->x
+ orig
->width
- x_root
;
3310 if (*xmotionp
!= -1)
3317 drag
->width
= 1 + x_root
- drag
->x
;
3323 y2
= y_root
- *y_off
;
3325 if (is_direction_fixed
== True
&& (*xmotionp
!= 0 || *ymotionp
!= 0))
3329 else if (y2
<= orig
->y
||
3330 (*ymotionp
== 1 && y2
< orig
->y
+ orig
->height
- 1))
3334 else if (y2
>= orig
->y
+ orig
->height
- 1 ||
3335 (*ymotionp
== -1 && y2
> orig
->y
))
3353 drag
->height
= orig
->y
+ orig
->height
- y_root
;
3357 if (*ymotionp
!= -1)
3364 drag
->height
= 1 + y_root
- drag
->y
;
3373 /* round up to nearest OK size to keep pointer inside
3376 exc
->w
.fw
, exc
->x
.elast
, &drag
->width
, &drag
->height
,
3377 *xmotionp
, *ymotionp
, CS_ROUND_UP
);
3380 drag
->x
= orig
->x
+ orig
->width
- drag
->width
;
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,
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
);
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
;
3424 unsigned int button_mask
= 0;
3427 rectangle
*drag
= &sdrag
;
3428 const rectangle
*orig
= &sorig
;
3429 const window_g g_backup
= fw
->g
;
3433 unsigned edge_wrap_x
;
3434 unsigned edge_wrap_y
;
3439 frame_move_resize_args mr_args
= NULL
;
3449 ResizeWindow
= FW_W_FRAME(fw
);
3450 if (fev_get_evpos_or_query(dpy
, Scr
.Root
, exc
->x
.etrigger
, &px
, &py
) ==
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 */
3460 button_mask
&= DEFAULT_ALL_BUTTONS_MASK
;
3462 if (!is_function_allowed(F_RESIZE
, NULL
, fw
, RQORIG_PROGRAM_US
, True
))
3468 if (IS_SHADED(fw
) || !IS_MAPPED(fw
))
3470 do_resize_opaque
= False
;
3471 evmask
= XEVMASK_RESIZE
;
3475 do_resize_opaque
= DO_RESIZE_OPAQUE(fw
);
3476 evmask
= XEVMASK_RESIZE_OPAQUE
;
3479 /* no suffix = % of screen, 'p' = pixels, 'c' = increment units */
3482 get_unshaded_geometry(fw
, drag
);
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
);
3502 /* size will be less or equal to requested */
3507 get_unshaded_geometry(fw
, &new_g
);
3508 SET_MAXIMIZED(fw
, 0);
3510 fw
, NULL
, &drag
->width
, &drag
->height
, xmotion
,
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
);
3519 fw
, shaded_g
.x
, shaded_g
.y
, shaded_g
.width
,
3520 shaded_g
.height
, False
);
3524 new_g
= fw
->g
.frame
;
3525 SET_MAXIMIZED(fw
, 0);
3527 fw
, NULL
, &drag
->width
, &drag
->height
, xmotion
,
3530 fw
->hints
.win_gravity
, &new_g
,
3531 drag
->width
- new_g
.width
,
3532 drag
->height
- new_g
.height
);
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
;
3544 was_maximized
= IS_MAXIMIZED(fw
);
3545 SET_MAXIMIZED(fw
, 0);
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
,
3555 if (Scr
.bo
.do_install_root_cmap
)
3557 InstallRootColormap();
3561 InstallFvwmColormap();
3563 if (!GrabEm(CRS_RESIZE
, GRAB_NORMAL
))
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
)
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
);
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,
3605 Scr
.flags
.is_wire_frame_displayed
= True
;
3607 MyXGrabKeyboard(dpy
);
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
)
3625 grav
= gravity_dir_to_grav(dir
);
3626 gravity_get_offsets(grav
, &xmotion
, &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
;
3641 for (i
= NUMBER_OF_TITLE_BUTTONS
; i
--; )
3643 /* see if the title button was pressed to that the
3645 if (FW_W_BUTTON(fw
, i
) != None
&&
3646 FW_W_BUTTON(fw
, i
) == PressedW
)
3649 called_from_title
= True
;
3653 /* don't warp if the resize was triggered by a press somwhere on the
3655 if (PressedW
!= Scr
.Root
&& xmotion
== 0 && ymotion
== 0 &&
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
;
3668 __resize_get_refpos(
3669 &ref_x
, &ref_y
, xmotion
, ymotion
, orig
->width
,
3674 switch (SHADED_DIR(fw
))
3695 switch (SHADED_DIR(fw
))
3716 __resize_get_refpos(
3717 &ref_x
, &ref_y
, xmotion
, ymotion
, fw
->g
.frame
.width
,
3718 fw
->g
.frame
.height
, fw
);
3722 if (do_warp_to_border
== True
)
3727 dx
= (xmotion
== 0) ? px
: ref_x
;
3728 dy
= (ymotion
== 0) ? py
: ref_y
;
3729 /* warp the pointer to the border */
3731 dpy
, None
, ResizeWindow
, 0, 0, 1, 1, dx
, dy
);
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
;
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
3754 if (exc
->x
.elast
->type
== KeyPress
)
3760 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &stashed_x
,
3761 &stashed_y
, &JunkX
, &JunkY
, &JunkMask
) == False
)
3763 /* pointer is on a different screen */
3770 exc
, stashed_x
, stashed_y
, &xo
, &yo
, drag
, orig
,
3771 &xmotion
, &ymotion
, do_resize_opaque
, True
);
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
))
3784 /* block until there is an interesting event */
3786 (!FPending(dpy
) || !FCheckMaskEvent(dpy
, evmask
, &ev
)))
3789 &ev
, dx
, dy
, &x
, &y
, &delta_x
, &delta_y
, False
,
3790 False
, True
, fw
->edge_delay_ms_resize
);
3793 /* Fake an event to force window reposition */
3794 ev
.type
= MotionNotify
;
3795 ev
.xmotion
.time
= fev_get_evtime();
3796 fForceRedraw
= True
;
3804 evmask
| EnterWindowMask
| LeaveWindowMask
,
3807 if (ev
.type
== MotionNotify
||
3808 ev
.type
== EnterNotify
|| ev
.type
== LeaveNotify
)
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. */
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
)
3834 if (ev
.type
== EnterNotify
|| ev
.type
== LeaveNotify
)
3840 /* Query the pointer to catch the latest information.
3841 * This *is* necessary. */
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
;
3856 fev_fake_event(&ev
);
3860 /* pointer is on a different screen,
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
)
3880 if (ev
.xbutton
.button
<= NUMBER_OF_MOUSE_BUTTONS
&&
3881 ((Button1Mask
<< (ev
.xbutton
.button
- 1)) &
3884 /* No new button was pressed, just a delayed
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
;
3905 /* simple code to bag out of move - CKH */
3907 XLookupKeysym(&ev
.xkey
, 0) == XK_Escape
)
3922 if (ev
.xmotion
.same_screen
== False
)
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 */
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 */
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)
3951 exc
, x
, y
, &x_off
, &y_off
, drag
, orig
,
3952 &xmotion
, &ymotion
, do_resize_opaque
,
3953 is_direction_fixed
);
3955 fForceRedraw
= False
;
3959 case PropertyNotify
:
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
);
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,
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 */
4019 dpy
, None
, Scr
.Root
, 0, 0, 0, 0, stashed_x
,
4024 /* since we aborted the resize, the window is still
4026 SET_MAXIMIZED(fw
, 1);
4028 if (do_resize_opaque
)
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 */
4049 if (bad_window
== FW_W(fw
))
4051 XUnmapWindow(dpy
, FW_W_FRAME(fw
));
4052 border_undraw_decorations(fw
);
4056 else if (!is_aborted
&& bad_window
!= FW_W(fw
))
4060 /* size will be >= to requested */
4062 fw
, exc
->x
.elast
, &drag
->width
, &drag
->height
,
4063 xmotion
, ymotion
, CS_ROUND_UP
);
4066 get_shaded_geometry(fw
, &new_g
, drag
);
4072 if (do_resize_opaque
)
4074 frame_update_move_resize_args(mr_args
, &new_g
);
4079 fw
, new_g
.x
, new_g
.y
, new_g
.width
,
4080 new_g
.height
, False
);
4084 fw
->g
.normal
.width
= drag
->width
;
4085 fw
->g
.normal
.height
= drag
->height
;
4088 if (is_aborted
&& was_maximized
)
4091 border_draw_decorations(
4092 fw
, PART_BUTTONS
, (fw
== Scr
.Hilite
), True
, CLEAR_ALL
,
4095 if (Scr
.bo
.do_install_root_cmap
)
4097 UninstallRootColormap();
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
)
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
);
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
);
4156 __resize_window(F_PASS_ARGS
);
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
)))
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
)))
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
4199 *x11
-= Scr
.MyDisplayWidth
;
4200 *x12
-= Scr
.MyDisplayWidth
;
4203 else if (*x12
<= x21
)
4207 *x11
+= Scr
.MyDisplayWidth
;
4208 *x12
+= Scr
.MyDisplayWidth
;
4211 /* make sure the y coordinate is on the same page as the reference
4217 *y11
-= Scr
.MyDisplayHeight
;
4218 *y12
-= Scr
.MyDisplayHeight
;
4221 else if (*y12
<= y21
)
4225 *y11
+= Scr
.MyDisplayHeight
;
4226 *y12
+= Scr
.MyDisplayHeight
;
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
)
4239 int x11
, x12
, x21
, x22
;
4240 int y11
, y12
, y21
, y22
;
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
)
4255 (cwin
->Desk
!= win
->Desk
&&
4256 !is_window_sticky_across_desks(cwin
)))
4260 if ((layers
[0] >= 0 && cwin
->layer
< layers
[0]) ||
4261 (layers
[1] >= 0 && cwin
->layer
> layers
[1]))
4265 rc
= get_visible_window_or_icon_geometry(cwin
, &g
);
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
,
4281 /* Are they in the same X space? */
4282 if (!((x22
<= x11
) || (x21
>= x12
)))
4284 if ((y22
<= y11
) && (y22
>= new_y1
))
4288 else if ((y12
<= y21
) && (new_y2
>= y21
))
4302 *win_height
= new_y2
- new_y1
;
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
)
4314 int x11
, x12
, x21
, x22
;
4315 int y11
, y12
, y21
, y22
;
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
)
4330 (cwin
->Desk
!= win
->Desk
&&
4331 !is_window_sticky_across_desks(cwin
)))
4335 if ((layers
[0] >= 0 && cwin
->layer
< layers
[0]) ||
4336 (layers
[1] >= 0 && cwin
->layer
> layers
[1]))
4340 rc
= get_visible_window_or_icon_geometry(cwin
, &g
);
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
,
4356 /* Are they in the same Y space? */
4357 if (!((y22
<= y11
) || (y21
>= y12
)))
4359 if ((x22
<= x11
) && (x22
>= new_x1
))
4363 else if ((x12
<= x21
) && (new_x2
>= x21
))
4377 *win_width
= new_x2
- new_x1
;
4383 static void unmaximize_fvwm_window(
4388 SET_MAXIMIZED(fw
, 0);
4389 get_relative_geometry(&new_g
, &fw
->g
.normal
);
4392 get_shaded_geometry(fw
, &new_g
, &new_g
);
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
);
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;
4417 fw
, NULL
, &geometry
->width
, &geometry
->height
, 0, 0,
4418 CS_UPDATE_MAX_DEFECT
);
4419 fw
->g
.max
= *geometry
;
4422 get_shaded_geometry(fw
, geometry
, &fw
->g
.max
);
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
;
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
);
4444 * (Un)Maximize a window.
4447 void CMD_Maximize(F_CMD_ARGS
)
4450 int val1
, val2
, val1_unit
, val2_unit
;
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
;
4466 FvwmWindow
*fw
= exc
->w
.fw
;
4469 !is_function_allowed(
4470 F_MAXIMIZE
, NULL
, fw
, RQORIG_PROGRAM_US
, False
))
4475 /* Check for "global" flag ("absolute" is for compatibility with E) */
4476 while (!global_flag_parsed
)
4478 token
= PeekToken(action
, &taction
);
4481 global_flag_parsed
= True
;
4485 if (StrEquals(token
, "screen"))
4489 is_screen_given
= True
;
4490 token
= PeekToken(taction
, &action
);
4491 scr
= FScreenGetScreenArgument(
4492 token
, FSCREEN_SPEC_PRIMARY
);
4494 NULL
, scr
, &scr_x
, &scr_y
, &scr_w
,
4497 else if (StrEquals(token
, "ewmhiwa"))
4499 ignore_working_area
= True
;
4502 else if (StrEquals(token
, "growonwindowlayer"))
4504 layers
[0] = fw
->layer
;
4505 layers
[1] = fw
->layer
;
4508 else if (StrEquals(token
, "growonlayers"))
4512 n
= GetIntegerArguments(
4513 taction
, &action
, layers
, 2);
4522 global_flag_parsed
= True
;
4526 toggle
= ParseToggleArgument(action
, &action
, -1, 0);
4527 if (toggle
== 0 && !IS_MAXIMIZED(fw
))
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
;
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
));
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
);
4567 /* parse first parameter */
4569 token
= PeekToken(action
, &taction
);
4570 if (token
&& StrEquals(token
, "grow"))
4577 else if (token
&& StrEquals(token
, "growleft"))
4583 else if (token
&& StrEquals(token
, "growright"))
4591 if (GetOnePercentArgument(token
, &val1
, &val1_unit
) == 0)
4598 /* handle negative offsets */
4599 if (val1_unit
== scr_w
)
4605 val1
= scr_w
+ val1
;
4610 /* parse second parameter */
4612 token
= PeekToken(taction
, NULL
);
4613 if (token
&& StrEquals(token
, "grow"))
4620 else if (token
&& StrEquals(token
, "growup"))
4626 else if (token
&& StrEquals(token
, "growdown"))
4634 if (GetOnePercentArgument(token
, &val2
, &val2_unit
) == 0)
4641 /* handle negative offsets */
4642 if (val2_unit
== scr_h
)
4648 val2
= scr_h
+ val2
;
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
);
4658 if (IS_MAXIMIZED(fw
) && !do_force_maximize
)
4660 unmaximize_fvwm_window(fw
);
4664 /* handle command line arguments */
4665 if (grow_up
|| grow_down
)
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
);
4674 new_g
.height
= val2
* val2_unit
/ 100;
4675 new_g
.y
= page_y
+ scr_y
;
4677 if (grow_left
|| grow_right
)
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
,
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
);
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
)
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
;
4730 fw
->g
.normal
= normal_g
;
4731 /* and mark it as maximized */
4732 maximize_fvwm_window(fw
, &max_g
);
4734 EWMH_SetWMState(fw
, False
);
4739 void CMD_ResizeMoveMaximize(F_CMD_ARGS
)
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
;
4757 fw
->g
.normal
= normal_g
;
4758 /* and mark it as maximized */
4759 maximize_fvwm_window(fw
, &max_g
);
4761 EWMH_SetWMState(fw
, False
);
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
)))
4777 if (IS_STICKY_ACROSS_PAGES(fw
))
4779 SET_STICKY_ACROSS_PAGES(fw
, 0);
4783 if (!IsRectangleOnThisPage(&fw
->g
.frame
, Scr
.CurrentDesk
))
4786 __move_window(F_PASS_ARGS
, False
, MOVE_PAGE
);
4788 SET_STICKY_ACROSS_PAGES(fw
, 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
)))
4804 if (IS_STICKY_ACROSS_DESKS(fw
))
4806 SET_STICKY_ACROSS_DESKS(fw
, 0);
4807 fw
->Desk
= Scr
.CurrentDesk
;
4808 GNOME_SetDeskCount();
4813 if (fw
->Desk
!= Scr
.CurrentDesk
)
4815 do_move_window_to_desk(fw
, Scr
.CurrentDesk
);
4817 SET_STICKY_ACROSS_DESKS(fw
, 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
);
4834 BroadcastConfig(M_CONFIGURE_WINDOW
,fw
);
4835 EWMH_SetWMState(fw
, False
);
4836 EWMH_SetWMDesktop(fw
);
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
;
4849 did_change
= stick_across_pages(F_PASS_ARGS
, toggle
);
4852 __handle_stick_exit(fw
, do_not_draw
, do_silently
);
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
;
4864 did_change
= stick_across_desks(F_PASS_ARGS
, toggle
);
4867 __handle_stick_exit(fw
, do_not_draw
, do_silently
);
4874 F_CMD_ARGS
, int toggle_page
, int toggle_desk
, int do_not_draw
,
4877 FvwmWindow
*fw
= exc
->w
.fw
;
4881 did_change
|= stick_across_desks(F_PASS_ARGS
, toggle_desk
);
4882 did_change
|= stick_across_pages(F_PASS_ARGS
, toggle_page
);
4885 __handle_stick_exit(fw
, do_not_draw
, do_silently
);
4891 void CMD_Stick(F_CMD_ARGS
)
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 */
4903 handle_stick(F_PASS_ARGS
, toggle
, toggle
, 0, 0);
4908 void CMD_StickAcrossPages(F_CMD_ARGS
)
4912 toggle
= ParseToggleArgument(action
, &action
, -1, 0);
4913 handle_stick_across_pages(F_PASS_ARGS
, toggle
, 0, 0);
4918 void CMD_StickAcrossDesks(F_CMD_ARGS
)
4922 toggle
= ParseToggleArgument(action
, &action
, -1, 0);
4923 handle_stick_across_desks(F_PASS_ARGS
, toggle
, 0, 0);