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
);
2419 &le
, dx
, dy
, &xl
, &yt
, &delta_x
, &delta_y
,
2420 False
, False
, True
, fw
->edge_delay_ms_move
);
2423 /* Fake an event to force window reposition */
2426 x_virtual_offset
= 0;
2431 y_virtual_offset
= 0;
2437 fw
, Width
, Height
, &xl
, &yt
);
2440 fev_make_null_event(&e
, dpy
);
2441 e
.type
= MotionNotify
;
2442 e
.xmotion
.time
= fev_get_evtime();
2443 e
.xmotion
.x_root
= xl
- XOffset
;
2444 e
.xmotion
.y_root
= yt
- YOffset
;
2445 e
.xmotion
.same_screen
= True
;
2451 /* block until an event arrives */
2452 /* dv (2004-07-01): With XFree 4.1.0.1, some Mouse
2453 * events are not reported to fvwm when the pointer
2454 * moves very fast and suddenly stops in the corner of
2455 * the screen. Handle EnterNotify/LeaveNotify events
2456 * too to get an idea where the pointer might be. */
2458 dpy
, ButtonPressMask
| ButtonReleaseMask
|
2459 KeyPressMask
| PointerMotionMask
|
2460 ButtonMotionMask
| ExposureMask
|
2461 EnterWindowMask
| LeaveWindowMask
, &e
);
2464 /* discard extra events before a logical release */
2465 if (e
.type
== MotionNotify
||
2466 e
.type
== EnterNotify
|| e
.type
== LeaveNotify
)
2468 while (FPending(dpy
) > 0 &&
2470 dpy
, ButtonMotionMask
|
2471 PointerMotionMask
| ButtonPressMask
|
2472 ButtonRelease
| KeyPressMask
|
2473 EnterWindowMask
| LeaveWindowMask
, &e
))
2475 if (e
.type
== ButtonPress
||
2476 e
.type
== ButtonRelease
||
2483 if (e
.type
== EnterNotify
|| e
.type
== LeaveNotify
)
2489 /* Query the pointer to catch the latest information.
2490 * This *is* necessary. */
2492 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &x
,
2493 &y
, &JunkX
, &JunkY
, &JunkMask
) == True
)
2495 fev_make_null_event(&e2
, dpy
);
2496 e2
.type
= MotionNotify
;
2497 e2
.xmotion
.time
= fev_get_evtime();
2498 e2
.xmotion
.x_root
= x
;
2499 e2
.xmotion
.y_root
= y
;
2500 e2
.xmotion
.state
= JunkMask
;
2501 e2
.xmotion
.same_screen
= True
;
2507 /* pointer is on a different screen,
2511 is_fake_event
= False
;
2512 /* Handle a limited number of key press events to allow
2513 * mouseless operation */
2514 if (e
.type
== KeyPress
)
2517 &e
, fw
, &x_virtual_offset
,
2518 &y_virtual_offset
, ButtonRelease
);
2520 is_fake_event
= (e
.type
!= KeyPress
);
2525 if (!(e
.xkey
.state
& Mod1Mask
))
2527 nosnap_enabled
= True
;
2529 do_snap
= nosnap_enabled
&&
2530 (e
.xkey
.state
& Mod1Mask
) ? False
: True
;
2532 /* simple code to bag out of move - CKH */
2533 if (XLookupKeysym(&(e
.xkey
), 0) == XK_Escape
)
2535 if (!do_move_opaque
)
2537 switch_move_resize_grid(False
);
2539 if (!IS_ICONIFIED(fw
))
2543 *FinalX
= fw
->g
.frame
.x
;
2544 *FinalY
= fw
->g
.frame
.y
;
2549 *FinalX
= orig_icon_x
;
2550 *FinalY
= orig_icon_y
;
2557 if (e
.xbutton
.button
<= NUMBER_OF_MOUSE_BUTTONS
&&
2558 ((Button1Mask
<< (e
.xbutton
.button
- 1)) &
2561 /* No new button was pressed, just a delayed
2565 if (!IS_MAPPED(fw
) &&
2566 ((e
.xbutton
.button
== 2 && !Scr
.gs
.do_emulate_mwm
)
2568 (e
.xbutton
.button
== 1 && Scr
.gs
.do_emulate_mwm
&&
2569 (e
.xbutton
.state
& ShiftMask
))))
2571 do_resize_too
= True
;
2572 /* Fallthrough to button-release */
2574 else if (!button_mask
&& e
.xbutton
.button
<=
2575 NUMBER_OF_EXTENDED_MOUSE_BUTTONS
&&
2576 e
.xbutton
.button
> 0 &&
2577 (move_interactive_finish_button_mask
&
2578 (1<<(e
.xbutton
.button
-1))))
2580 do_resize_too
= False
;
2583 else if (button_mask
&& e
.xbutton
.button
<=
2584 NUMBER_OF_EXTENDED_MOUSE_BUTTONS
&&
2585 e
.xbutton
.button
> 0 &&
2586 (move_drag_finish_button_mask
&
2587 (1<<(e
.xbutton
.button
-1))))
2589 do_resize_too
= False
;
2590 /* Fallthrough to button-release */
2594 /* Abort the move if
2595 * - the move started with a pressed button
2596 * and another button was pressed during the
2598 * - Any button not in the
2599 * move_finish_button_mask is pressed
2601 /* if (button_mask) */
2602 /* - button_mask will always be set here.
2603 * only add an if if we want to be able to
2604 * place windows dragged by other means
2605 * than releasing the initial button.
2608 if (!do_move_opaque
)
2610 switch_move_resize_grid(False
);
2612 if (!IS_ICONIFIED(fw
))
2614 *FinalX
= fw
->g
.frame
.x
;
2615 *FinalY
= fw
->g
.frame
.y
;
2619 *FinalX
= orig_icon_x
;
2620 *FinalY
= orig_icon_y
;
2630 fw
->placed_by_button
= e
.xbutton
.button
;
2632 if (!do_move_opaque
)
2634 switch_move_resize_grid(False
);
2636 xl2
= e
.xbutton
.x_root
+ XOffset
+ x_virtual_offset
;
2637 yt2
= e
.xbutton
.y_root
+ YOffset
+ y_virtual_offset
;
2638 /* ignore the position of the button release if it was
2639 * on a different page. */
2640 if (!(((xl
< 0 && xl2
>= 0) ||
2641 (xl
>= 0 && xl2
< 0) ||
2642 (yt
< 0 && yt2
>= 0) ||
2643 (yt
>= 0 && yt2
< 0)) &&
2644 (abs(xl
- xl2
) > Scr
.MyDisplayWidth
/ 2 ||
2645 abs(yt
- yt2
) > Scr
.MyDisplayHeight
/ 2)))
2650 if (xl
!= xl_orig
|| yt
!= yt_orig
|| vx
!= Scr
.Vx
||
2651 vy
!= Scr
.Vy
|| was_snapped
)
2653 /* only snap if the window actually moved! */
2657 fw
, Width
, Height
, &xl
, &yt
);
2669 if (e
.xmotion
.same_screen
== False
)
2673 if (!(e
.xmotion
.state
& Mod1Mask
))
2675 nosnap_enabled
= True
;
2677 do_snap
= nosnap_enabled
&&
2678 (e
.xmotion
.state
& Mod1Mask
) ? False
: True
;
2679 xl
= e
.xmotion
.x_root
;
2680 yt
= e
.xmotion
.y_root
;
2681 if (xl
> 0 && xl
< Scr
.MyDisplayWidth
- 1)
2683 /* pointer was moved away from the left/right
2684 * border with the mouse, reset the virtual x
2686 x_virtual_offset
= 0;
2688 if (yt
> 0 && yt
< Scr
.MyDisplayHeight
- 1)
2690 /* pointer was moved away from the top/bottom
2691 * border with the mouse, reset the virtual y
2693 y_virtual_offset
= 0;
2695 xl
+= XOffset
+ x_virtual_offset
;
2696 yt
+= YOffset
+ y_virtual_offset
;
2700 DoSnapAttract(fw
, Width
, Height
, &xl
, &yt
);
2704 /* check Paging request once and only once after
2705 * outline redrawn redraw after paging if needed
2707 for (paged
= 0; paged
<= 1; paged
++)
2709 if (!do_move_opaque
)
2711 draw_move_resize_grid(
2712 xl
, yt
, Width
- 1, Height
- 1);
2716 if (IS_ICONIFIED(fw
))
2718 set_icon_position(fw
, xl
, yt
);
2719 move_icon_to_position(fw
);
2720 broadcast_icon_geometry(
2726 dpy
, FW_W_FRAME(fw
),
2730 DisplayPosition(fw
, &e
, xl
, yt
, False
);
2732 /* prevent window from lagging behind mouse
2733 * when paging - mab */
2738 xl
= e
.xmotion
.x_root
;
2739 yt
= e
.xmotion
.y_root
;
2740 fev_get_last_event(&le
);
2742 &le
, dx
, dy
, &xl
, &yt
,
2743 &delta_x
, &delta_y
, False
,
2745 fw
->edge_delay_ms_move
);
2748 x_virtual_offset
= 0;
2753 y_virtual_offset
= 0;
2763 if (!delta_x
&& !delta_y
)
2774 if (!do_move_opaque
)
2776 /* must undraw the rubber band in case the
2777 * event causes some drawing */
2778 switch_move_resize_grid(False
);
2781 if (!do_move_opaque
)
2783 draw_move_resize_grid(
2784 xl
, yt
, Width
- 1, Height
- 1);
2792 xl
+= x_virtual_offset
;
2793 yt
+= y_virtual_offset
;
2794 if (do_move_opaque
&& !IS_ICONIFIED(fw
) &&
2795 !IS_SHADED(fw
) && !Scr
.bo
.do_disable_configure_notify
)
2797 /* send configure notify event for windows that care
2798 * about their location; don't send anything if
2799 * position didn't change */
2800 if (!sent_cn
|| cnx
!= xl
|| cny
!= yt
)
2805 SendConfigureNotify(
2806 fw
, xl
, yt
, Width
, Height
, 0,
2808 #ifdef FVWM_DEBUG_MSGS
2810 DBG
, "frame_setup_window",
2811 "Sent ConfigureNotify (w %d, h %d)",
2818 if (!IS_ICONIFIED(fw
))
2820 fw_copy
.g
.frame
.x
= xl
;
2821 fw_copy
.g
.frame
.y
= yt
;
2823 if (xl
!= old_xl
|| yt
!= old_yt
)
2825 /* only do this with opaque moves, (i.e. the
2826 * server is not grabbed) */
2827 if (draw_parts
!= PART_NONE
)
2829 border_draw_decorations(
2831 ((fw
== get_focus_window())) ?
2833 True
, CLEAR_ALL
, NULL
, NULL
);
2835 if (IS_TEAR_OFF_MENU(fw
))
2837 menu_redraw_transparent_tear_off_menu(
2840 BroadcastConfig(M_CONFIGURE_WINDOW
, &fw_copy
);
2841 FlushAllMessageQueues();
2844 } /* while (!is_finished) */
2846 if (!Scr
.gs
.do_hide_position_window
)
2848 XUnmapWindow(dpy
,Scr
.SizeWindow
);
2850 if (is_aborted
|| bad_window
== FW_W(fw
))
2852 if (vx
!= Scr
.Vx
|| vy
!= Scr
.Vy
)
2854 MoveViewport(vx
, vy
, False
);
2856 if (is_aborted
&& do_move_opaque
)
2858 XMoveWindow(dpy
, move_w
, x_bak
, y_bak
);
2859 if (draw_parts
!= PART_NONE
)
2861 border_draw_decorations(
2863 ((fw
== get_focus_window())) ?
2865 True
, CLEAR_ALL
, NULL
, NULL
);
2867 menu_redraw_transparent_tear_off_menu(fw
, False
);
2869 if (bad_window
== FW_W(fw
))
2871 XUnmapWindow(dpy
, move_w
);
2872 border_undraw_decorations(fw
);
2876 if (!is_aborted
&& bad_window
!= FW_W(fw
) && IS_ICONIFIED(fw
))
2878 SET_ICON_MOVED(fw
, 1);
2880 UngrabEm(GRAB_NORMAL
);
2883 /* Don't wait for buttons to come up when user is placing a new
2884 * window and wants to resize it. */
2885 WaitForButtonsUp(True
);
2887 SET_WINDOW_BEING_MOVED_OPAQUE(fw
, 0);
2890 return do_resize_too
;
2893 void CMD_MoveThreshold(F_CMD_ARGS
)
2897 if (GetIntegerArguments(action
, NULL
, &val
, 1) < 1 || val
< 0)
2899 Scr
.MoveThreshold
= DEFAULT_MOVE_THRESHOLD
;
2903 Scr
.MoveThreshold
= val
;
2909 void CMD_OpaqueMoveSize(F_CMD_ARGS
)
2913 if (GetIntegerArguments(action
, NULL
, &val
, 1) < 1)
2915 if (strncasecmp(action
, "unlimited", 9) == 0)
2917 Scr
.OpaqueSize
= -1;
2921 Scr
.OpaqueSize
= DEFAULT_OPAQUE_MOVE_SIZE
;
2926 Scr
.OpaqueSize
= val
;
2933 static char *hide_options
[] =
2941 void CMD_HideGeometryWindow(F_CMD_ARGS
)
2943 char *token
= PeekToken(action
, NULL
);
2945 Scr
.gs
.do_hide_position_window
= 0;
2946 Scr
.gs
.do_hide_resize_window
= 0;
2947 switch(GetTokenIndex(token
, hide_options
, 0, NULL
))
2952 Scr
.gs
.do_hide_position_window
= 1;
2955 Scr
.gs
.do_hide_resize_window
= 1;
2958 Scr
.gs
.do_hide_position_window
= 1;
2959 Scr
.gs
.do_hide_resize_window
= 1;
2965 void CMD_SnapAttraction(F_CMD_ARGS
)
2970 len
= strlen(action
);
2972 cmd
= safemalloc(len
);
2973 sprintf(cmd
, "Style * SnapAttraction %s", action
);
2975 OLD
, "CMD_SnapAttraction",
2976 "The command SnapAttraction is obsolete. Please use the"
2977 " following command instead:");
2978 fvwm_msg(OLD
, "", cmd
);
2981 FUNC_DONT_REPEAT
| FUNC_DONT_EXPAND_COMMAND
);
2987 void CMD_SnapGrid(F_CMD_ARGS
)
2992 len
= strlen(action
);
2994 cmd
= safemalloc(len
);
2995 sprintf(cmd
, "Style * SnapGrid %s", action
);
2997 OLD
, "CMD_SnapGrid",
2998 "The command SnapGrid is obsolete. Please use the following"
2999 " command instead:");
3000 fvwm_msg(OLD
, "", cmd
);
3003 FUNC_DONT_REPEAT
| FUNC_DONT_EXPAND_COMMAND
);
3009 static Pixmap XorPixmap
= None
;
3011 void CMD_XorValue(F_CMD_ARGS
)
3017 if (GetIntegerArguments(action
, NULL
, &val
, 1) != 1)
3022 PictureUseDefaultVisual();
3023 gcm
= GCFunction
|GCLineWidth
|GCForeground
|GCFillStyle
|GCSubwindowMode
;
3024 gcv
.subwindow_mode
= IncludeInferiors
;
3025 gcv
.function
= GXxor
;
3027 /* use passed in value, or try to calculate appropriate value if 0 */
3030 gcv.foreground = (val1)?(val1):((((unsigned long) 1) <<
3033 /* Xlib programming manual suggestion: */
3034 gcv
.foreground
= (val
)?
3035 (val
):(PictureBlackPixel() ^ PictureWhitePixel());
3036 gcv
.fill_style
= FillSolid
;
3037 gcv
.subwindow_mode
= IncludeInferiors
;
3039 /* modify XorGC, only create once */
3042 XChangeGC(dpy
, Scr
.XorGC
, gcm
, &gcv
);
3046 Scr
.XorGC
= fvwmlib_XCreateGC(dpy
, Scr
.Root
, gcm
, &gcv
);
3049 /* free up XorPixmap if neccesary */
3050 if (XorPixmap
!= None
) {
3051 XFreePixmap(dpy
, XorPixmap
);
3054 PictureUseFvwmVisual();
3060 void CMD_XorPixmap(F_CMD_ARGS
)
3066 FvwmPictureAttributes fpa
;
3068 action
= GetNextToken(action
, &PixmapName
);
3069 if (PixmapName
== NULL
)
3071 /* return to default value. */
3073 CMD_XorValue(F_PASS_ARGS
);
3076 /* get the picture in the root visual, colorlimit is ignored because the
3077 * pixels will be freed */
3078 fpa
.mask
= FPAM_NO_COLOR_LIMIT
| FPAM_NO_ALPHA
;
3079 PictureUseDefaultVisual();
3080 xp
= PGetFvwmPicture(dpy
, Scr
.Root
, NULL
, PixmapName
, fpa
);
3083 fvwm_msg(ERR
,"SetXORPixmap","Can't find pixmap %s", PixmapName
);
3085 PictureUseFvwmVisual();
3089 /* free up old pixmap */
3090 if (XorPixmap
!= None
)
3092 XFreePixmap(dpy
, XorPixmap
);
3095 /* make a copy of the picture pixmap */
3096 XorPixmap
= XCreatePixmap(dpy
, Scr
.Root
, xp
->width
, xp
->height
, Pdepth
);
3097 XCopyArea(dpy
, xp
->picture
, XorPixmap
, DefaultGC(dpy
, Scr
.screen
), 0, 0,
3098 xp
->width
, xp
->height
, 0, 0);
3099 /* destroy picture and free colors */
3100 PDestroyFvwmPicture(dpy
, xp
);
3101 PictureUseFvwmVisual();
3103 /* create Graphics context */
3104 gcm
= GCFunction
|GCLineWidth
|GCTile
|GCFillStyle
|GCSubwindowMode
;
3105 gcv
.subwindow_mode
= IncludeInferiors
;
3106 gcv
.function
= GXxor
;
3107 /* line width of 1 is necessary for Exceed servers */
3109 gcv
.tile
= XorPixmap
;
3110 gcv
.fill_style
= FillTiled
;
3111 gcv
.subwindow_mode
= IncludeInferiors
;
3112 /* modify XorGC, only create once */
3115 XChangeGC(dpy
, Scr
.XorGC
, gcm
, &gcv
);
3119 Scr
.XorGC
= fvwmlib_XCreateGC(dpy
, Scr
.Root
, gcm
, &gcv
);
3126 /* ----------------------------- resizing code ----------------------------- */
3128 static void __resize_get_dir_from_window(
3129 int *ret_xmotion
, int *ret_ymotion
, FvwmWindow
*fw
, Window context_w
)
3131 if (context_w
!= Scr
.Root
&& context_w
!= None
)
3133 if (context_w
== FW_W_SIDE(fw
, 0)) /* top */
3137 else if (context_w
== FW_W_SIDE(fw
, 1)) /* right */
3141 else if (context_w
== FW_W_SIDE(fw
, 2)) /* bottom */
3145 else if (context_w
== FW_W_SIDE(fw
, 3)) /* left */
3149 else if (context_w
== FW_W_CORNER(fw
, 0)) /* upper-left */
3154 else if (context_w
== FW_W_CORNER(fw
, 1)) /* upper-right */
3159 else if (context_w
== FW_W_CORNER(fw
, 2)) /* lower left */
3164 else if (context_w
== FW_W_CORNER(fw
, 3)) /* lower right */
3174 static void __resize_get_dir_proximity(
3175 int *ret_xmotion
, int *ret_ymotion
, FvwmWindow
*fw
, int x_off
,
3176 int y_off
, int px
, int py
)
3181 if (px
< 0 || x_off
< 0 || py
< 0 || y_off
< 0)
3185 /* Now find the place to warp to. We simply use the sectors
3186 * drawn when we start resizing the window. */
3188 tx
= orig
->width
/ 10 - 1;
3189 ty
= orig
->height
/ 10 - 1;
3194 tx
= max(fw
->boundary_width
, tx
);
3195 ty
= max(fw
->boundary_width
, ty
);
3200 else if (x_off
< tx
)
3208 else if (y_off
< ty
)
3216 static void __resize_get_refpos(
3217 int *ret_x
, int *ret_y
, int xmotion
, int ymotion
, int w
, int h
,
3224 else if (xmotion
< 0)
3236 else if (ymotion
< 0)
3249 * __resize_step - move the rubberband around. This is called for
3250 * each motion event when we are resizing
3253 * x_root - the X corrdinate in the root window
3254 * y_root - the Y corrdinate in the root window
3255 * x_off - x offset of pointer from border (input/output)
3256 * y_off - y offset of pointer from border (input/output)
3257 * drag - resize internal structure
3258 * orig - resize internal structure
3259 * xmotionp - pointer to xmotion in resize_window
3260 * ymotionp - pointer to ymotion in resize_window
3263 static void __resize_step(
3264 const exec_context_t
*exc
, int x_root
, int y_root
, int *x_off
,
3265 int *y_off
, rectangle
*drag
, const rectangle
*orig
, int *xmotionp
,
3266 int *ymotionp
, Bool do_resize_opaque
, Bool is_direction_fixed
)
3275 x2
= x_root
- *x_off
;
3277 if (is_direction_fixed
== True
&& (*xmotionp
!= 0 || *ymotionp
!= 0))
3281 else if (x2
<= orig
->x
||
3282 (*xmotionp
== 1 && x2
< orig
->x
+ orig
->width
- 1))
3286 else if (x2
>= orig
->x
+ orig
->width
- 1 ||
3287 (*xmotionp
== -1 && x2
> orig
->x
))
3305 drag
->width
= orig
->x
+ orig
->width
- x_root
;
3309 if (*xmotionp
!= -1)
3316 drag
->width
= 1 + x_root
- drag
->x
;
3322 y2
= y_root
- *y_off
;
3324 if (is_direction_fixed
== True
&& (*xmotionp
!= 0 || *ymotionp
!= 0))
3328 else if (y2
<= orig
->y
||
3329 (*ymotionp
== 1 && y2
< orig
->y
+ orig
->height
- 1))
3333 else if (y2
>= orig
->y
+ orig
->height
- 1 ||
3334 (*ymotionp
== -1 && y2
> orig
->y
))
3352 drag
->height
= orig
->y
+ orig
->height
- y_root
;
3356 if (*ymotionp
!= -1)
3363 drag
->height
= 1 + y_root
- drag
->y
;
3372 /* round up to nearest OK size to keep pointer inside
3375 exc
->w
.fw
, exc
->x
.elast
, &drag
->width
, &drag
->height
,
3376 *xmotionp
, *ymotionp
, CS_ROUND_UP
);
3379 drag
->x
= orig
->x
+ orig
->width
- drag
->width
;
3383 drag
->y
= orig
->y
+ orig
->height
- drag
->height
;
3385 if (!do_resize_opaque
)
3387 draw_move_resize_grid(
3388 drag
->x
, drag
->y
, drag
->width
- 1,
3394 exc
->w
.fw
, drag
->x
, drag
->y
, drag
->width
,
3395 drag
->height
, False
);
3398 e
.type
= MotionNotify
;
3399 e
.xbutton
.x_root
= x_root
;
3400 e
.xbutton
.y_root
= y_root
;
3401 DisplaySize(exc
->w
.fw
, &e
, drag
->width
, drag
->height
, False
, False
);
3406 /* Starts a window resize operation */
3407 static Bool
__resize_window(F_CMD_ARGS
)
3409 extern Window bad_window
;
3410 FvwmWindow
*fw
= exc
->w
.fw
;
3411 Bool is_finished
= False
, is_done
= False
, is_aborted
= False
;
3412 Bool do_send_cn
= False
;
3413 Bool do_resize_opaque
;
3414 Bool do_warp_to_border
;
3415 Bool is_direction_fixed
;
3416 Bool fButtonAbort
= False
;
3417 Bool fForceRedraw
= False
;
3418 Bool called_from_title
= False
;
3419 int x
,y
,delta_x
,delta_y
,stashed_x
,stashed_y
;
3420 Window ResizeWindow
;
3421 int dx
= Scr
.EdgeScrollX
? Scr
.EdgeScrollX
: Scr
.MyDisplayWidth
;
3422 int dy
= Scr
.EdgeScrollY
? Scr
.EdgeScrollY
: Scr
.MyDisplayHeight
;
3423 const int vx
= Scr
.Vx
;
3424 const int vy
= Scr
.Vy
;
3426 unsigned int button_mask
= 0;
3429 rectangle
*drag
= &sdrag
;
3430 const rectangle
*orig
= &sorig
;
3431 const window_g g_backup
= fw
->g
;
3435 unsigned edge_wrap_x
;
3436 unsigned edge_wrap_y
;
3441 frame_move_resize_args mr_args
= NULL
;
3451 ResizeWindow
= FW_W_FRAME(fw
);
3452 if (fev_get_evpos_or_query(dpy
, Scr
.Root
, exc
->x
.etrigger
, &px
, &py
) ==
3454 XTranslateCoordinates(
3455 dpy
, Scr
.Root
, ResizeWindow
, px
, py
, &px
, &py
,
3456 &JunkChild
) == False
)
3458 /* pointer is on a different screen - that's okay here */
3462 button_mask
&= DEFAULT_ALL_BUTTONS_MASK
;
3464 if (!is_function_allowed(F_RESIZE
, NULL
, fw
, RQORIG_PROGRAM_US
, True
))
3470 if (IS_SHADED(fw
) || !IS_MAPPED(fw
))
3472 do_resize_opaque
= False
;
3473 evmask
= XEVMASK_RESIZE
;
3477 do_resize_opaque
= DO_RESIZE_OPAQUE(fw
);
3478 evmask
= XEVMASK_RESIZE_OPAQUE
;
3481 /* no suffix = % of screen, 'p' = pixels, 'c' = increment units */
3484 get_unshaded_geometry(fw
, drag
);
3488 drag
->width
= fw
->g
.frame
.width
;
3489 drag
->height
= fw
->g
.frame
.height
;
3492 get_window_borders(fw
, &b
);
3493 n
= GetResizeArguments(
3494 &action
, fw
->g
.frame
.x
, fw
->g
.frame
.y
,
3495 fw
->hints
.base_width
, fw
->hints
.base_height
,
3496 fw
->hints
.width_inc
, fw
->hints
.height_inc
,
3497 &b
, &(drag
->width
), &(drag
->height
),
3498 &dir
, &is_direction_fixed
, &do_warp_to_border
);
3504 /* size will be less or equal to requested */
3509 get_unshaded_geometry(fw
, &new_g
);
3510 SET_MAXIMIZED(fw
, 0);
3512 fw
, NULL
, &drag
->width
, &drag
->height
, xmotion
,
3515 fw
->hints
.win_gravity
, &new_g
,
3516 drag
->width
- new_g
.width
,
3517 drag
->height
- new_g
.height
);
3518 fw
->g
.normal
= new_g
;
3519 get_shaded_geometry(fw
, &shaded_g
, &new_g
);
3521 fw
, shaded_g
.x
, shaded_g
.y
, shaded_g
.width
,
3522 shaded_g
.height
, False
);
3526 new_g
= fw
->g
.frame
;
3527 SET_MAXIMIZED(fw
, 0);
3529 fw
, NULL
, &drag
->width
, &drag
->height
, xmotion
,
3532 fw
->hints
.win_gravity
, &new_g
,
3533 drag
->width
- new_g
.width
,
3534 drag
->height
- new_g
.height
);
3536 fw
, new_g
.x
, new_g
.y
, drag
->width
,
3537 drag
->height
, False
);
3539 update_absolute_geometry(fw
);
3540 maximize_adjust_offset(fw
);
3541 GNOME_SetWinArea(fw
);
3542 ResizeWindow
= None
;
3546 was_maximized
= IS_MAXIMIZED(fw
);
3547 SET_MAXIMIZED(fw
, 0);
3550 /* must redraw the buttons now so that the 'maximize' button
3551 * does not stay depressed. */
3552 border_draw_decorations(
3553 fw
, PART_BUTTONS
, (fw
== Scr
.Hilite
), True
, CLEAR_ALL
,
3557 if (Scr
.bo
.do_install_root_cmap
)
3559 InstallRootColormap();
3563 InstallFvwmColormap();
3565 if (!GrabEm(CRS_RESIZE
, GRAB_NORMAL
))
3571 /* handle problems with edge-wrapping while resizing */
3572 edge_wrap_x
= Scr
.flags
.do_edge_wrap_x
;
3573 edge_wrap_y
= Scr
.flags
.do_edge_wrap_y
;
3574 Scr
.flags
.do_edge_wrap_x
= 0;
3575 Scr
.flags
.do_edge_wrap_y
= 0;
3577 if (!do_resize_opaque
)
3582 dpy
, (Drawable
)ResizeWindow
, &JunkRoot
, &drag
->x
, &drag
->y
,
3583 (unsigned int*)&drag
->width
, (unsigned int*)&drag
->height
,
3584 (unsigned int*)&JunkBW
, (unsigned int*)&JunkDepth
))
3586 UngrabEm(GRAB_NORMAL
);
3587 if (!do_resize_opaque
)
3589 MyXUngrabServer(dpy
);
3595 SET_MAXIMIZED(fw
, was_maximized
);
3596 get_unshaded_geometry(fw
, drag
);
3597 SET_MAXIMIZED(fw
, 0);
3599 if (do_resize_opaque
)
3601 mr_args
= frame_create_move_resize_args(
3602 fw
, FRAME_MR_OPAQUE
, &fw
->g
.frame
, &fw
->g
.frame
, 0,
3607 Scr
.flags
.is_wire_frame_displayed
= True
;
3609 MyXGrabKeyboard(dpy
);
3615 /* pop up a resize dimensions window */
3616 if (!Scr
.gs
.do_hide_resize_window
)
3618 position_geometry_window(NULL
);
3619 XMapRaised(dpy
, Scr
.SizeWindow
);
3621 DisplaySize(fw
, exc
->x
.elast
, orig
->width
, orig
->height
, True
, True
);
3623 if (dir
!= DIR_NONE
)
3627 grav
= gravity_dir_to_grav(dir
);
3628 gravity_get_offsets(grav
, &xmotion
, &ymotion
);
3632 if (xmotion
== 0 && ymotion
== 0)
3634 __resize_get_dir_from_window(&xmotion
, &ymotion
, fw
, PressedW
);
3636 if (FW_W_TITLE(fw
) != None
&& PressedW
== FW_W_TITLE(fw
))
3638 /* title was pressed to start the resize */
3639 called_from_title
= True
;
3643 for (i
= NUMBER_OF_TITLE_BUTTONS
; i
--; )
3645 /* see if the title button was pressed to that the
3647 if (FW_W_BUTTON(fw
, i
) != None
&&
3648 FW_W_BUTTON(fw
, i
) == PressedW
)
3651 called_from_title
= True
;
3655 /* don't warp if the resize was triggered by a press somwhere on the
3657 if (PressedW
!= Scr
.Root
&& xmotion
== 0 && ymotion
== 0 &&
3660 __resize_get_dir_proximity(
3661 &xmotion
, &ymotion
, fw
, orig
->width
- px
,
3662 orig
->height
- py
, px
, py
);
3663 if (xmotion
!= 0 || ymotion
!= 0)
3665 do_warp_to_border
= True
;
3670 __resize_get_refpos(
3671 &ref_x
, &ref_y
, xmotion
, ymotion
, orig
->width
,
3676 switch (SHADED_DIR(fw
))
3697 switch (SHADED_DIR(fw
))
3718 __resize_get_refpos(
3719 &ref_x
, &ref_y
, xmotion
, ymotion
, fw
->g
.frame
.width
,
3720 fw
->g
.frame
.height
, fw
);
3724 if (do_warp_to_border
== True
)
3729 dx
= (xmotion
== 0) ? px
: ref_x
;
3730 dy
= (ymotion
== 0) ? py
: ref_y
;
3731 /* warp the pointer to the border */
3733 dpy
, None
, ResizeWindow
, 0, 0, 1, 1, dx
, dy
);
3736 else if (xmotion
!= 0 || ymotion
!= 0)
3738 /* keep the distance between pointer and border */
3739 x_off
= (xmotion
== 0) ? 0 : ref_x
- px
;
3740 y_off
= (ymotion
== 0) ? 0 : ref_y
- py
;
3744 /* wait until the pointer hits a border before making a
3745 * decision about the resize direction */
3748 /* draw the rubber-band window */
3749 if (!do_resize_opaque
)
3751 draw_move_resize_grid(
3752 drag
->x
, drag
->y
, drag
->width
- 1, drag
->height
- 1);
3754 /* kick off resizing without requiring any motion if invoked with a key
3756 if (exc
->x
.elast
->type
== KeyPress
)
3762 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &stashed_x
,
3763 &stashed_y
, &JunkX
, &JunkY
, &JunkMask
) == False
)
3765 /* pointer is on a different screen */
3772 exc
, stashed_x
, stashed_y
, &xo
, &yo
, drag
, orig
,
3773 &xmotion
, &ymotion
, do_resize_opaque
, True
);
3777 stashed_x
= stashed_y
= -1;
3780 /* loop to resize */
3781 memset(&ev
, 0, sizeof(ev
));
3782 while (!is_finished
&& bad_window
!= FW_W(fw
))
3786 /* block until there is an interesting event */
3788 (!FPending(dpy
) || !FCheckMaskEvent(dpy
, evmask
, &ev
)))
3791 &ev
, dx
, dy
, &x
, &y
, &delta_x
, &delta_y
, False
,
3792 False
, True
, fw
->edge_delay_ms_resize
);
3795 /* Fake an event to force window reposition */
3796 ev
.type
= MotionNotify
;
3797 ev
.xmotion
.time
= fev_get_evtime();
3798 fForceRedraw
= True
;
3806 evmask
| EnterWindowMask
| LeaveWindowMask
,
3809 if (ev
.type
== MotionNotify
||
3810 ev
.type
== EnterNotify
|| ev
.type
== LeaveNotify
)
3814 is_motion
= (ev
.type
== MotionNotify
) ? True
: False
;
3815 /* discard any extra motion events before a release */
3816 /* dv (2004-07-01): With XFree 4.1.0.1, some Mouse
3817 * events are not reported to fvwm when the pointer
3818 * moves very fast and suddenly stops in the corner of
3819 * the screen. Handle EnterNotify/LeaveNotify events
3820 * too to get an idea where the pointer might be. */
3823 dpy
, ButtonMotionMask
|
3824 PointerMotionMask
| ButtonReleaseMask
|
3825 ButtonPressMask
| EnterWindowMask
|
3826 LeaveWindowMask
, &ev
) == True
)
3828 if (ev
.type
== ButtonRelease
||
3829 ev
.type
== ButtonPress
||
3830 ev
.type
== KeyPress
)
3836 if (ev
.type
== EnterNotify
|| ev
.type
== LeaveNotify
)
3842 /* Query the pointer to catch the latest information.
3843 * This *is* necessary. */
3845 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &x
,
3846 &y
, &JunkX
, &JunkY
, &JunkMask
) == True
)
3848 /* Must NOT use button_mask here, or resize
3849 * will not work with num lock */
3850 fev_make_null_event(&e2
, dpy
);
3851 e2
.type
= MotionNotify
;
3852 e2
.xmotion
.time
= fev_get_evtime();
3853 e2
.xmotion
.x_root
= x
;
3854 e2
.xmotion
.y_root
= y
;
3855 e2
.xmotion
.state
= JunkMask
;
3856 e2
.xmotion
.same_screen
= True
;
3858 fev_fake_event(&ev
);
3862 /* pointer is on a different screen,
3868 /* Handle a limited number of key press events to allow
3869 * mouseless operation */
3870 if (ev
.type
== KeyPress
)
3872 Keyboard_shortcuts(&ev
, fw
, NULL
, NULL
, ButtonRelease
);
3873 if (ev
.type
== ButtonRelease
)
3882 if (ev
.xbutton
.button
<= NUMBER_OF_MOUSE_BUTTONS
&&
3883 ((Button1Mask
<< (ev
.xbutton
.button
- 1)) &
3886 /* No new button was pressed, just a delayed
3890 /* Abort the resize if
3891 * - the move started with a pressed button and
3892 * another button was pressed during the operation
3893 * - no button was started at the beginning and any
3894 * button except button 1 was pressed. */
3895 if (button_mask
|| (ev
.xbutton
.button
!= 1))
3897 fButtonAbort
= True
;
3907 /* simple code to bag out of move - CKH */
3909 XLookupKeysym(&ev
.xkey
, 0) == XK_Escape
)
3924 if (ev
.xmotion
.same_screen
== False
)
3930 x
= ev
.xmotion
.x_root
;
3931 y
= ev
.xmotion
.y_root
;
3932 /* resize before paging request to prevent
3933 * resize from lagging * mouse - mab */
3935 exc
, x
, y
, &x_off
, &y_off
, drag
, orig
,
3936 &xmotion
, &ymotion
, do_resize_opaque
,
3937 is_direction_fixed
);
3938 /* need to move the viewport */
3940 &ev
, dx
, dy
, &x
, &y
, &delta_x
,
3941 &delta_y
, False
, False
, False
,
3942 fw
->edge_delay_ms_resize
);
3944 /* redraw outline if we paged - mab */
3945 if (delta_x
!= 0 || delta_y
!= 0)
3953 exc
, x
, y
, &x_off
, &y_off
, drag
, orig
,
3954 &xmotion
, &ymotion
, do_resize_opaque
,
3955 is_direction_fixed
);
3957 fForceRedraw
= False
;
3961 case PropertyNotify
:
3964 exec_context_changes_t ecc
;
3966 ecc
.x
.etrigger
= &ev
;
3967 ea
.exc
= exc_clone_context(exc
, &ecc
, ECC_ETRIGGER
);
3968 HandlePropertyNotify(&ea
);
3969 exc_destroy_context(ea
.exc
);
3979 if (!do_resize_opaque
)
3981 /* must undraw the rubber band in case the
3982 * event causes some drawing */
3983 switch_move_resize_grid(False
);
3985 dispatch_event(&ev
);
3986 if (!do_resize_opaque
)
3988 draw_move_resize_grid(
3989 drag
->x
, drag
->y
, drag
->width
- 1,
3995 if (do_resize_opaque
)
3997 /* only do this with opaque resizes, (i.e. the
3998 * server is not grabbed) */
3999 BroadcastConfig(M_CONFIGURE_WINDOW
, fw
);
4000 FlushAllMessageQueues();
4005 /* erase the rubber-band */
4006 if (!do_resize_opaque
)
4008 switch_move_resize_grid(False
);
4010 /* pop down the size window */
4011 if (!Scr
.gs
.do_hide_resize_window
)
4013 XUnmapWindow(dpy
, Scr
.SizeWindow
);
4015 if (is_aborted
|| bad_window
== FW_W(fw
))
4017 /* return pointer if aborted resize was invoked with key */
4021 dpy
, None
, Scr
.Root
, 0, 0, 0, 0, stashed_x
,
4026 /* since we aborted the resize, the window is still
4028 SET_MAXIMIZED(fw
, 1);
4030 if (do_resize_opaque
)
4042 exc
, sorig
.x
, sorig
.y
, &xo
, &yo
, &g
, orig
,
4043 &xmotion
, &ymotion
, do_resize_opaque
, True
);
4045 if (vx
!= Scr
.Vx
|| vy
!= Scr
.Vy
)
4047 MoveViewport(vx
, vy
, False
);
4049 /* restore all geometry-related info */
4051 if (bad_window
== FW_W(fw
))
4053 XUnmapWindow(dpy
, FW_W_FRAME(fw
));
4054 border_undraw_decorations(fw
);
4058 else if (!is_aborted
&& bad_window
!= FW_W(fw
))
4062 /* size will be >= to requested */
4064 fw
, exc
->x
.elast
, &drag
->width
, &drag
->height
,
4065 xmotion
, ymotion
, CS_ROUND_UP
);
4068 get_shaded_geometry(fw
, &new_g
, drag
);
4074 if (do_resize_opaque
)
4076 frame_update_move_resize_args(mr_args
, &new_g
);
4081 fw
, new_g
.x
, new_g
.y
, new_g
.width
,
4082 new_g
.height
, False
);
4086 fw
->g
.normal
.width
= drag
->width
;
4087 fw
->g
.normal
.height
= drag
->height
;
4090 if (is_aborted
&& was_maximized
)
4093 border_draw_decorations(
4094 fw
, PART_BUTTONS
, (fw
== Scr
.Hilite
), True
, CLEAR_ALL
,
4097 if (Scr
.bo
.do_install_root_cmap
)
4099 UninstallRootColormap();
4103 UninstallFvwmColormap();
4105 ResizeWindow
= None
;
4106 if (!do_resize_opaque
)
4108 /* Throw away some events that dont interest us right now. */
4109 discard_events(EnterWindowMask
|LeaveWindowMask
);
4110 Scr
.flags
.is_wire_frame_displayed
= False
;
4111 MyXUngrabServer(dpy
);
4113 if (mr_args
!= NULL
)
4115 frame_free_move_resize_args(fw
, mr_args
);
4117 if (do_send_cn
== True
)
4129 SendConfigureNotify(fw
, g
.x
, g
.y
, g
.width
, g
.height
, 0, True
);
4131 MyXUngrabKeyboard(dpy
);
4132 WaitForButtonsUp(True
);
4133 UngrabEm(GRAB_NORMAL
);
4134 Scr
.flags
.do_edge_wrap_x
= edge_wrap_x
;
4135 Scr
.flags
.do_edge_wrap_y
= edge_wrap_y
;
4136 update_absolute_geometry(fw
);
4137 maximize_adjust_offset(fw
);
4138 GNOME_SetWinArea(fw
);
4147 void CMD_Resize(F_CMD_ARGS
)
4149 FvwmWindow
*fw
= exc
->w
.fw
;
4151 if (IS_EWMH_FULLSCREEN(fw
))
4153 /* do not unmaximize ! */
4154 CMD_ResizeMaximize(F_PASS_ARGS
);
4158 __resize_window(F_PASS_ARGS
);
4163 /* ----------------------------- maximizing code --------------------------- */
4165 Bool
is_window_sticky_across_pages(FvwmWindow
*fw
)
4167 if (IS_STICKY_ACROSS_PAGES(fw
) ||
4168 (IS_ICONIFIED(fw
) && IS_ICON_STICKY_ACROSS_PAGES(fw
)))
4178 Bool
is_window_sticky_across_desks(FvwmWindow
*fw
)
4180 if (IS_STICKY_ACROSS_DESKS(fw
) ||
4181 (IS_ICONIFIED(fw
) && IS_ICON_STICKY_ACROSS_DESKS(fw
)))
4191 static void move_sticky_window_to_same_page(
4192 int *x11
, int *x12
, int *y11
, int *y12
,
4193 int x21
, int x22
, int y21
, int y22
)
4195 /* make sure the x coordinate is on the same page as the reference
4201 *x11
-= Scr
.MyDisplayWidth
;
4202 *x12
-= Scr
.MyDisplayWidth
;
4205 else if (*x12
<= x21
)
4209 *x11
+= Scr
.MyDisplayWidth
;
4210 *x12
+= Scr
.MyDisplayWidth
;
4213 /* make sure the y coordinate is on the same page as the reference
4219 *y11
-= Scr
.MyDisplayHeight
;
4220 *y12
-= Scr
.MyDisplayHeight
;
4223 else if (*y12
<= y21
)
4227 *y11
+= Scr
.MyDisplayHeight
;
4228 *y12
+= Scr
.MyDisplayHeight
;
4235 static void MaximizeHeight(
4236 FvwmWindow
*win
, int win_width
, int win_x
, int *win_height
,
4237 int *win_y
, Bool grow_up
, Bool grow_down
, int top_border
,
4238 int bottom_border
, int *layers
)
4241 int x11
, x12
, x21
, x22
;
4242 int y11
, y12
, y21
, y22
;
4247 x11
= win_x
; /* Start x */
4248 y11
= *win_y
; /* Start y */
4249 x12
= x11
+ win_width
; /* End x */
4250 y12
= y11
+ *win_height
; /* End y */
4251 new_y1
= top_border
;
4252 new_y2
= bottom_border
;
4254 for (cwin
= Scr
.FvwmRoot
.next
; cwin
; cwin
= cwin
->next
)
4257 (cwin
->Desk
!= win
->Desk
&&
4258 !is_window_sticky_across_desks(cwin
)))
4262 if ((layers
[0] >= 0 && cwin
->layer
< layers
[0]) ||
4263 (layers
[1] >= 0 && cwin
->layer
> layers
[1]))
4267 rc
= get_visible_window_or_icon_geometry(cwin
, &g
);
4274 x22
= x21
+ g
.width
;
4275 y22
= y21
+ g
.height
;
4276 if (is_window_sticky_across_pages(cwin
))
4278 move_sticky_window_to_same_page(
4279 &x21
, &x22
, &new_y1
, &new_y2
, x11
, x12
, y11
,
4283 /* Are they in the same X space? */
4284 if (!((x22
<= x11
) || (x21
>= x12
)))
4286 if ((y22
<= y11
) && (y22
>= new_y1
))
4290 else if ((y12
<= y21
) && (new_y2
>= y21
))
4304 *win_height
= new_y2
- new_y1
;
4310 static void MaximizeWidth(
4311 FvwmWindow
*win
, int *win_width
, int *win_x
, int win_height
,
4312 int win_y
, Bool grow_left
, Bool grow_right
, int left_border
,
4313 int right_border
, int *layers
)
4316 int x11
, x12
, x21
, x22
;
4317 int y11
, y12
, y21
, y22
;
4322 x11
= *win_x
; /* Start x */
4323 y11
= win_y
; /* Start y */
4324 x12
= x11
+ *win_width
; /* End x */
4325 y12
= y11
+ win_height
; /* End y */
4326 new_x1
= left_border
;
4327 new_x2
= right_border
;
4329 for (cwin
= Scr
.FvwmRoot
.next
; cwin
; cwin
= cwin
->next
)
4332 (cwin
->Desk
!= win
->Desk
&&
4333 !is_window_sticky_across_desks(cwin
)))
4337 if ((layers
[0] >= 0 && cwin
->layer
< layers
[0]) ||
4338 (layers
[1] >= 0 && cwin
->layer
> layers
[1]))
4342 rc
= get_visible_window_or_icon_geometry(cwin
, &g
);
4349 x22
= x21
+ g
.width
;
4350 y22
= y21
+ g
.height
;
4351 if (is_window_sticky_across_pages(cwin
))
4353 move_sticky_window_to_same_page(
4354 &new_x1
, &new_x2
, &y21
, &y22
, x11
, x12
, y11
,
4358 /* Are they in the same Y space? */
4359 if (!((y22
<= y11
) || (y21
>= y12
)))
4361 if ((x22
<= x11
) && (x22
>= new_x1
))
4365 else if ((x12
<= x21
) && (new_x2
>= x21
))
4379 *win_width
= new_x2
- new_x1
;
4385 static void unmaximize_fvwm_window(
4390 SET_MAXIMIZED(fw
, 0);
4391 get_relative_geometry(&new_g
, &fw
->g
.normal
);
4394 get_shaded_geometry(fw
, &new_g
, &new_g
);
4397 fw
, new_g
.x
, new_g
.y
, new_g
.width
, new_g
.height
, True
);
4398 border_draw_decorations(
4399 fw
, PART_ALL
, (Scr
.Hilite
== fw
), True
, CLEAR_ALL
, NULL
, NULL
);
4400 if (IS_EWMH_FULLSCREEN(fw
))
4402 SET_EWMH_FULLSCREEN(fw
, False
);
4403 if (DO_EWMH_USE_STACKING_HINTS(fw
))
4405 new_layer(fw
, fw
->ewmh_normal_layer
);
4407 apply_decor_change(fw
);
4412 static void maximize_fvwm_window(
4413 FvwmWindow
*fw
, rectangle
*geometry
)
4415 SET_MAXIMIZED(fw
, 1);
4416 fw
->g
.max_defect
.width
= 0;
4417 fw
->g
.max_defect
.height
= 0;
4419 fw
, NULL
, &geometry
->width
, &geometry
->height
, 0, 0,
4420 CS_UPDATE_MAX_DEFECT
);
4421 fw
->g
.max
= *geometry
;
4424 get_shaded_geometry(fw
, geometry
, &fw
->g
.max
);
4427 fw
, geometry
->x
, geometry
->y
, geometry
->width
,
4428 geometry
->height
, True
);
4429 border_draw_decorations(
4430 fw
, PART_ALL
, (Scr
.Hilite
== fw
), True
, CLEAR_ALL
, NULL
, NULL
);
4431 update_absolute_geometry(fw
);
4432 /* remember the offset between old and new position in case the
4433 * maximized window is moved more than the screen width/height. */
4434 fw
->g
.max_offset
.x
= fw
->g
.normal
.x
- fw
->g
.max
.x
;
4435 fw
->g
.max_offset
.y
= fw
->g
.normal
.y
- fw
->g
.max
.y
;
4437 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
);
4446 * (Un)Maximize a window.
4449 void CMD_Maximize(F_CMD_ARGS
)
4452 int val1
, val2
, val1_unit
, val2_unit
;
4456 Bool grow_up
= False
;
4457 Bool grow_down
= False
;
4458 Bool grow_left
= False
;
4459 Bool grow_right
= False
;
4460 Bool do_force_maximize
= False
;
4461 Bool is_screen_given
= False
;
4462 Bool ignore_working_area
= False
;
4463 int layers
[2] = { -1, -1 };
4464 Bool global_flag_parsed
= False
;
4468 FvwmWindow
*fw
= exc
->w
.fw
;
4471 !is_function_allowed(
4472 F_MAXIMIZE
, NULL
, fw
, RQORIG_PROGRAM_US
, False
))
4477 /* Check for "global" flag ("absolute" is for compatibility with E) */
4478 while (!global_flag_parsed
)
4480 token
= PeekToken(action
, &taction
);
4483 global_flag_parsed
= True
;
4487 if (StrEquals(token
, "screen"))
4491 is_screen_given
= True
;
4492 token
= PeekToken(taction
, &action
);
4493 scr
= FScreenGetScreenArgument(
4494 token
, FSCREEN_SPEC_PRIMARY
);
4496 NULL
, scr
, &scr_x
, &scr_y
, &scr_w
,
4499 else if (StrEquals(token
, "ewmhiwa"))
4501 ignore_working_area
= True
;
4504 else if (StrEquals(token
, "growonwindowlayer"))
4506 layers
[0] = fw
->layer
;
4507 layers
[1] = fw
->layer
;
4510 else if (StrEquals(token
, "growonlayers"))
4514 n
= GetIntegerArguments(
4515 taction
, &action
, layers
, 2);
4524 global_flag_parsed
= True
;
4528 toggle
= ParseToggleArgument(action
, &action
, -1, 0);
4529 if (toggle
== 0 && !IS_MAXIMIZED(fw
))
4534 if (toggle
== 1 && IS_MAXIMIZED(fw
))
4536 /* Fake that the window is not maximized. */
4537 do_force_maximize
= True
;
4540 /* find the new page and geometry */
4541 new_g
.x
= fw
->g
.frame
.x
;
4542 new_g
.y
= fw
->g
.frame
.y
;
4543 new_g
.width
= fw
->g
.frame
.width
;
4544 new_g
.height
= fw
->g
.frame
.height
;
4545 get_page_offset_check_visible(&page_x
, &page_y
, fw
);
4547 /* Check if we should constrain rectangle to some Xinerama screen */
4548 if (!is_screen_given
)
4550 fscreen_scr_arg fscr
;
4552 fscr
.xypos
.x
= fw
->g
.frame
.x
+ fw
->g
.frame
.width
/ 2 - page_x
;
4553 fscr
.xypos
.y
= fw
->g
.frame
.y
+ fw
->g
.frame
.height
/ 2 - page_y
;
4555 &fscr
, FSCREEN_XYPOS
, &scr_x
, &scr_y
, &scr_w
, &scr_h
);
4558 if (!ignore_working_area
)
4560 EWMH_GetWorkAreaIntersection(
4561 fw
, &scr_x
, &scr_y
, &scr_w
, &scr_h
,
4562 EWMH_MAXIMIZE_MODE(fw
));
4565 fprintf(stderr
, "%s: page=(%d,%d), scr=(%d,%d, %dx%d)\n", __FUNCTION__
,
4566 page_x
, page_y
, scr_x
, scr_y
, scr_w
, scr_h
);
4569 /* parse first parameter */
4571 token
= PeekToken(action
, &taction
);
4572 if (token
&& StrEquals(token
, "grow"))
4579 else if (token
&& StrEquals(token
, "growleft"))
4585 else if (token
&& StrEquals(token
, "growright"))
4593 if (GetOnePercentArgument(token
, &val1
, &val1_unit
) == 0)
4600 /* handle negative offsets */
4601 if (val1_unit
== scr_w
)
4607 val1
= scr_w
+ val1
;
4612 /* parse second parameter */
4614 token
= PeekToken(taction
, NULL
);
4615 if (token
&& StrEquals(token
, "grow"))
4622 else if (token
&& StrEquals(token
, "growup"))
4628 else if (token
&& StrEquals(token
, "growdown"))
4636 if (GetOnePercentArgument(token
, &val2
, &val2_unit
) == 0)
4643 /* handle negative offsets */
4644 if (val2_unit
== scr_h
)
4650 val2
= scr_h
+ val2
;
4656 fprintf(stderr
, "%s: page=(%d,%d), scr=(%d,%d, %dx%d)\n", __FUNCTION__
,
4657 page_x
, page_y
, scr_x
, scr_y
, scr_w
, scr_h
);
4660 if (IS_MAXIMIZED(fw
) && !do_force_maximize
)
4662 unmaximize_fvwm_window(fw
);
4666 /* handle command line arguments */
4667 if (grow_up
|| grow_down
)
4670 fw
, new_g
.width
, new_g
.x
, &new_g
.height
,
4671 &new_g
.y
, grow_up
, grow_down
, page_y
+ scr_y
,
4672 page_y
+ scr_y
+ scr_h
, layers
);
4676 new_g
.height
= val2
* val2_unit
/ 100;
4677 new_g
.y
= page_y
+ scr_y
;
4679 if (grow_left
|| grow_right
)
4682 fw
, &new_g
.width
, &new_g
.x
, new_g
.height
,
4683 new_g
.y
, grow_left
, grow_right
,
4684 page_x
+ scr_x
, page_x
+ scr_x
+ scr_w
,
4689 new_g
.width
= val1
* val1_unit
/ 100;
4690 new_g
.x
= page_x
+ scr_x
;
4692 if (val1
== 0 && val2
== 0)
4694 new_g
.x
= page_x
+ scr_x
;
4695 new_g
.y
= page_y
+ scr_y
;
4696 new_g
.height
= scr_h
;
4697 new_g
.width
= scr_w
;
4699 /* now maximize it */
4700 maximize_fvwm_window(fw
, &new_g
);
4702 EWMH_SetWMState(fw
, False
);
4703 GNOME_SetWinArea(fw
);
4710 * Same as CMD_Resize and CMD_ResizeMove, but the window ends up maximized
4711 * without touching the normal geometry.
4714 void CMD_ResizeMaximize(F_CMD_ARGS
)
4719 FvwmWindow
*fw
= exc
->w
.fw
;
4721 /* keep a copy of the old geometry */
4722 normal_g
= fw
->g
.normal
;
4723 /* resize the window normally */
4724 was_resized
= __resize_window(F_PASS_ARGS
);
4725 if (was_resized
== True
)
4727 /* set the new geometry as the maximized geometry and restore
4728 * the old normal geometry */
4729 max_g
= fw
->g
.normal
;
4732 fw
->g
.normal
= normal_g
;
4733 /* and mark it as maximized */
4734 maximize_fvwm_window(fw
, &max_g
);
4736 EWMH_SetWMState(fw
, False
);
4741 void CMD_ResizeMoveMaximize(F_CMD_ARGS
)
4746 FvwmWindow
*fw
= exc
->w
.fw
;
4748 /* keep a copy of the old geometry */
4749 normal_g
= fw
->g
.normal
;
4750 /* resize the window normally */
4751 was_resized
= resize_move_window(F_PASS_ARGS
);
4752 if (was_resized
== True
)
4754 /* set the new geometry as the maximized geometry and restore
4755 * the old normal geometry */
4756 max_g
= fw
->g
.normal
;
4759 fw
->g
.normal
= normal_g
;
4760 /* and mark it as maximized */
4761 maximize_fvwm_window(fw
, &max_g
);
4763 EWMH_SetWMState(fw
, False
);
4768 /* ----------------------------- stick code -------------------------------- */
4770 int stick_across_pages(F_CMD_ARGS
, int toggle
)
4772 FvwmWindow
*fw
= exc
->w
.fw
;
4774 if ((toggle
== 1 && IS_STICKY_ACROSS_PAGES(fw
)) ||
4775 (toggle
== 0 && !IS_STICKY_ACROSS_PAGES(fw
)))
4779 if (IS_STICKY_ACROSS_PAGES(fw
))
4781 SET_STICKY_ACROSS_PAGES(fw
, 0);
4785 if (!IsRectangleOnThisPage(&fw
->g
.frame
, Scr
.CurrentDesk
))
4788 __move_window(F_PASS_ARGS
, False
, MOVE_PAGE
);
4790 SET_STICKY_ACROSS_PAGES(fw
, 1);
4796 int stick_across_desks(F_CMD_ARGS
, int toggle
)
4798 FvwmWindow
*fw
= exc
->w
.fw
;
4800 if ((toggle
== 1 && IS_STICKY_ACROSS_DESKS(fw
)) ||
4801 (toggle
== 0 && !IS_STICKY_ACROSS_DESKS(fw
)))
4806 if (IS_STICKY_ACROSS_DESKS(fw
))
4808 SET_STICKY_ACROSS_DESKS(fw
, 0);
4809 fw
->Desk
= Scr
.CurrentDesk
;
4810 GNOME_SetDeskCount();
4815 if (fw
->Desk
!= Scr
.CurrentDesk
)
4817 do_move_window_to_desk(fw
, Scr
.CurrentDesk
);
4819 SET_STICKY_ACROSS_DESKS(fw
, 1);
4825 static void __handle_stick_exit(
4826 FvwmWindow
*fw
, int do_not_draw
, int do_silently
)
4828 if (do_not_draw
== 0)
4830 border_draw_decorations(
4831 fw
, PART_TITLE
| PART_BUTTONS
, (Scr
.Hilite
==fw
), True
,
4832 CLEAR_ALL
, NULL
, NULL
);
4836 BroadcastConfig(M_CONFIGURE_WINDOW
,fw
);
4837 EWMH_SetWMState(fw
, False
);
4838 EWMH_SetWMDesktop(fw
);
4845 void handle_stick_across_pages(
4846 F_CMD_ARGS
, int toggle
, int do_not_draw
, int do_silently
)
4848 FvwmWindow
*fw
= exc
->w
.fw
;
4851 did_change
= stick_across_pages(F_PASS_ARGS
, toggle
);
4854 __handle_stick_exit(fw
, do_not_draw
, do_silently
);
4860 void handle_stick_across_desks(
4861 F_CMD_ARGS
, int toggle
, int do_not_draw
, int do_silently
)
4863 FvwmWindow
*fw
= exc
->w
.fw
;
4866 did_change
= stick_across_desks(F_PASS_ARGS
, toggle
);
4869 __handle_stick_exit(fw
, do_not_draw
, do_silently
);
4876 F_CMD_ARGS
, int toggle_page
, int toggle_desk
, int do_not_draw
,
4879 FvwmWindow
*fw
= exc
->w
.fw
;
4883 did_change
|= stick_across_desks(F_PASS_ARGS
, toggle_desk
);
4884 did_change
|= stick_across_pages(F_PASS_ARGS
, toggle_page
);
4887 __handle_stick_exit(fw
, do_not_draw
, do_silently
);
4893 void CMD_Stick(F_CMD_ARGS
)
4897 toggle
= ParseToggleArgument(action
, &action
, -1, 0);
4898 if (toggle
== -1 && IS_STICKY_ACROSS_DESKS(exc
->w
.fw
) !=
4899 IS_STICKY_ACROSS_PAGES(exc
->w
.fw
))
4901 /* don't switch between only stickypage and only stickydesk.
4902 * rather switch it off completely */
4905 handle_stick(F_PASS_ARGS
, toggle
, toggle
, 0, 0);
4910 void CMD_StickAcrossPages(F_CMD_ARGS
)
4914 toggle
= ParseToggleArgument(action
, &action
, -1, 0);
4915 handle_stick_across_pages(F_PASS_ARGS
, toggle
, 0, 0);
4920 void CMD_StickAcrossDesks(F_CMD_ARGS
)
4924 toggle
= ParseToggleArgument(action
, &action
, -1, 0);
4925 handle_stick_across_desks(F_PASS_ARGS
, toggle
, 0, 0);