1 /* This program is free software; you can redistribute it and/or modify
2 * it under the terms of the GNU General Public License as published by
3 * the Free Software Foundation; either version 2 of the License, or
4 * (at your option) any later version.
6 * This program is distributed in the hope that it will be useful,
7 * but WITHOUT ANY WARRANTY; without even the implied warranty of
8 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 * GNU General Public License for more details.
11 * You should have received a copy of the GNU General Public License
12 * along with this program; if not, write to the Free Software
13 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 /*****************************************************************************
17 * This module is all original code
19 * Copyright 1993, Robert Nation
20 * You may use this code for any purpose, as long as the original
21 * copyright remains in the source code and all documentation
22 ****************************************************************************/
24 /************************************************************************
26 * code for moving and resizing windows
28 ***********************************************************************/
34 #include "libs/fvwmlib.h"
38 #include "functions.h"
43 #include "move_resize.h"
44 #include "module_interface.h"
48 #include "colormaps.h"
50 #include "decorations.h"
52 #include <X11/keysym.h>
54 /* ----- move globals ----- */
57 /* Animated move stuff added by Greg J. Badros, gjb@cs.washington.edu */
59 float rgpctMovementDefault
[32] = {
60 -.01, 0, .01, .03,.08,.18,.3,.45,.60,.75,.85,.90,.94,.97,.99,1.0
64 int cmsDelayDefault
= 10; /* milliseconds */
65 static void DisplayPosition(FvwmWindow
*, int, int,Bool
);
66 /* ----- end of move globals ----- */
68 /* ----- resize globals ----- */
70 /* DO NOT USE (STATIC) GLOBALS IN THIS MODULE!
71 * Since some functions are called from other modules unwanted side effects
72 * (i.e. bugs.) would be created */
74 extern Window PressedW
;
77 int x_root
, int y_root
, FvwmWindow
*tmp_win
, rectangle
*drag
,
78 rectangle
*orig
, int *xmotionp
, int *ymotionp
, Bool do_resize_opaque
);
79 static void DisplaySize(FvwmWindow
*, int, int, Bool
, Bool
);
80 /* ----- end of resize globals ----- */
82 /* The vars are named for the x-direction, but this is used for both x and y */
83 static int GetOnePositionArgument(
84 char *s1
,int x
,int w
,int *pFinalX
,float factor
, int max
, Bool is_x
)
88 Bool add_pointer_position
= False
;
94 factor
= 1; /* Use pixels, so don't multiply by factor */
97 if (strcmp(s1
,"w") == 0)
101 else if (sscanf(s1
,"w-%d",&val
) == 1)
103 *pFinalX
= x
- (int)(val
*factor
);
105 else if (sscanf(s1
,"w+%d",&val
) == 1 || sscanf(s1
,"w%d",&val
) == 1 )
107 *pFinalX
= x
+ (int)(val
*factor
);
109 else if (sscanf(s1
,"m-%d",&val
) == 1)
111 add_pointer_position
= True
;
112 *pFinalX
= -(int)(val
*factor
);
114 else if (sscanf(s1
,"m+%d",&val
) == 1 || sscanf(s1
,"m%d",&val
) == 1 )
116 add_pointer_position
= True
;
117 *pFinalX
= (int)(val
*factor
);
119 else if (sscanf(s1
,"-%d",&val
) == 1)
121 *pFinalX
= max
-w
- (int)(val
*factor
);
123 else if (sscanf(s1
,"%d",&val
) == 1)
125 *pFinalX
= (int)(val
*factor
);
131 if (add_pointer_position
)
137 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &JunkX
, &JunkY
, &x
, &y
, &JunkMask
);
138 *pFinalX
+= (is_x
) ? x
: y
;
144 /* GetMoveArguments is used for Move & AnimatedMove
145 * It lets you specify in all the following ways
146 * 20 30 Absolute percent position, from left edge and top
147 * -50 50 Absolute percent position, from right edge and top
148 * 10p 5p Absolute pixel position
149 * 10p -0p Absolute pixel position, from bottom
150 * w+5 w-10p Relative position, right 5%, up ten pixels
151 * w+5 w-10p Pointer relative position, right 5%, up ten pixels
152 * Returns 2 when x & y have parsed without error, 0 otherwise
154 static int GetMoveArguments(
155 char **paction
, int w
, int h
, int *pFinalX
, int *pFinalY
,
156 Bool
*fWarp
, Bool
*fPointer
)
163 int scrWidth
= Scr
.MyDisplayWidth
;
164 int scrHeight
= Scr
.MyDisplayHeight
;
170 action
= GetNextToken(action
, &s1
);
171 if (s1
&& fPointer
&& StrEquals(s1
, "pointer"))
179 action
= GetNextToken(action
, &s2
);
182 warp
= PeekToken(action
, &naction
);
183 if (StrEquals(warp
, "Warp"))
191 if (s1
!= NULL
&& s2
!= NULL
)
194 if (StrEquals(s1
, "keep"))
198 else if (GetOnePositionArgument(
199 s1
, *pFinalX
, w
, pFinalX
, (float)scrWidth
/100, scrWidth
, True
))
203 if (StrEquals(s2
, "keep"))
207 else if (GetOnePositionArgument(
208 s2
, *pFinalY
, h
, pFinalY
, (float)scrHeight
/100, scrHeight
, False
))
213 *fWarp
= False
; /* make sure warping is off for interactive moves */
217 /* not enough arguments, switch to current page. */
220 *pFinalX
= Scr
.MyDisplayWidth
+ *pFinalX
;
224 *pFinalY
= Scr
.MyDisplayHeight
+ *pFinalY
;
237 static int ParseOneResizeArgument(
238 char *arg
, int scr_size
, int base_size
, int size_inc
, int bw
, int title_size
,
245 if (StrEquals(arg
, "keep"))
247 /* do not change width */
251 if (GetSuffixedIntegerArguments(arg
, NULL
, &value
, 1, "pc", &suffix
) < 1)
257 /* convert the value/suffix pairs to pixels */
258 unit_table
[0] = scr_size
;
260 unit_table
[2] = 100 * size_inc
;
261 *ret_size
= SuffixToPercentValue(value
, suffix
, unit_table
);
263 *ret_size
+= scr_size
;
268 /* account for base width */
269 *ret_size
+= base_size
;
271 *ret_size
+= title_size
+ 2 * bw
;
279 static int GetResizeArguments(
280 char **paction
, int x
, int y
, int w_base
, int h_base
, int w_inc
, int h_inc
,
281 int bw
, int h_title
, int *pFinalW
, int *pFinalH
)
292 token
= PeekToken(*paction
, &naction
);
295 if (StrEquals(token
, "bottomright") || StrEquals(token
, "br"))
297 int nx
= x
+ *pFinalW
- 1;
298 int ny
= y
+ *pFinalH
- 1;
300 n
= GetMoveArguments(&naction
, 0, 0, &nx
, &ny
, NULL
, NULL
);
303 *pFinalW
= nx
- x
+ 1;
304 *pFinalH
= ny
- y
+ 1;
310 naction
= GetNextToken(naction
, &s2
);
319 n
+= ParseOneResizeArgument(
320 s1
, Scr
.MyDisplayWidth
, w_base
, w_inc
, bw
, 0, pFinalW
);
321 n
+= ParseOneResizeArgument(
322 s2
, Scr
.MyDisplayHeight
, h_base
, h_inc
, bw
, h_title
, pFinalH
);
332 static int GetResizeMoveArguments(
333 char **paction
, int w_base
, int h_base
, int w_inc
, int h_inc
, int bw
,
334 int h_title
, int *pFinalX
, int *pFinalY
, int *pFinalW
, int *pFinalH
,
335 Bool
*fWarp
, Bool
*fPointer
)
337 char *action
= *paction
;
341 if (GetResizeArguments(
342 &action
, *pFinalX
, *pFinalY
, w_base
, h_base
, w_inc
, h_inc
, bw
, h_title
,
343 pFinalW
, pFinalH
) < 2)
347 if (GetMoveArguments(
348 &action
, *pFinalW
, *pFinalH
, pFinalX
, pFinalY
, fWarp
, NULL
) < 2)
357 void resize_move_window(F_CMD_ARGS
)
366 Bool fPointer
= False
;
370 if (DeferExecution(eventp
,&w
,&tmp_win
,&context
, CRS_RESIZE
, ButtonPress
))
372 if (tmp_win
== NULL
|| IS_ICONIFIED(tmp_win
))
374 if (IS_FIXED(tmp_win
))
376 if(check_if_function_allowed(F_RESIZE
,tmp_win
,True
,NULL
) == 0)
382 /* gotta have a window */
384 if (!XGetGeometry(dpy
, w
, &JunkRoot
, &x
, &y
, (unsigned int *)&FinalW
,
385 (unsigned int *)&FinalH
, &JunkBW
, &JunkDepth
))
394 n
= GetResizeMoveArguments(
396 tmp_win
->hints
.base_width
, tmp_win
->hints
.base_height
,
397 tmp_win
->hints
.width_inc
, tmp_win
->hints
.height_inc
,
398 tmp_win
->boundary_width
, tmp_win
->title_g
.height
,
399 &FinalX
, &FinalY
, &FinalW
, &FinalH
, &fWarp
, &fPointer
);
403 if (IS_MAXIMIZED(tmp_win
))
405 /* must redraw the buttons now so that the 'maximize' button does not stay
407 SET_MAXIMIZED(tmp_win
, 0);
409 tmp_win
, DRAW_BUTTONS
, (tmp_win
== Scr
.Hilite
), True
, None
);
411 dx
= FinalX
- tmp_win
->frame_g
.x
;
412 dy
= FinalY
- tmp_win
->frame_g
.y
;
413 /* size will be less or equal to requested */
414 constrain_size(tmp_win
, (unsigned int *)&FinalW
, (unsigned int *)&FinalH
,
416 if (IS_SHADED(tmp_win
))
418 SetupFrame(tmp_win
, FinalX
, FinalY
, FinalW
, tmp_win
->frame_g
.height
, False
);
422 SetupFrame(tmp_win
, FinalX
, FinalY
, FinalW
, FinalH
, True
);
425 XWarpPointer(dpy
, None
, None
, 0, 0, 0, 0, FinalX
- x
, FinalY
- y
);
426 if (IS_MAXIMIZED(tmp_win
))
428 tmp_win
->max_g
.x
+= dx
;
429 tmp_win
->max_g
.y
+= dy
;
433 tmp_win
->normal_g
.x
+= dx
;
434 tmp_win
->normal_g
.y
+= dy
;
436 DrawDecorations(tmp_win
, DRAW_ALL
, True
, True
, None
);
437 update_absolute_geometry(tmp_win
);
438 maximize_adjust_offset(tmp_win
);
440 GNOME_SetWinArea(tmp_win
);
446 static void InteractiveMove(
447 Window
*win
, FvwmWindow
*tmp_win
, int *FinalX
, int *FinalY
, XEvent
*eventp
,
448 Bool do_start_at_pointer
)
450 int origDragX
,origDragY
,DragX
, DragY
, DragWidth
, DragHeight
;
451 int XOffset
, YOffset
;
453 Bool do_move_opaque
= False
;
457 if (Scr
.bo
.InstallRootCmap
)
458 InstallRootColormap();
460 InstallFvwmColormap();
461 /* warp the pointer to the cursor position from before menu appeared*/
462 /* domivogt (17-May-1999): an XFlush should not hurt anyway, so do it
463 * unconditionally to remove the external */
466 if (do_start_at_pointer
)
469 dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
, &DragX
, &DragY
, &JunkX
, &JunkY
,
474 /* Although a move is usually done with a button depressed we have to check
475 * for ButtonRelease too since the event may be faked. */
476 GetLocationFromEventOrQuery(dpy
, Scr
.Root
, &Event
, &DragX
, &DragY
);
479 if(!GrabEm(CRS_MOVE
, GRAB_NORMAL
))
485 if (!XGetGeometry(dpy
, w
, &JunkRoot
, &origDragX
, &origDragY
,
486 (unsigned int *)&DragWidth
, (unsigned int *)&DragHeight
,
487 &JunkBW
, &JunkDepth
))
489 UngrabEm(GRAB_NORMAL
);
492 if (do_start_at_pointer
)
498 if(IS_MAPPED(tmp_win
) && DragWidth
*DragHeight
<
499 (Scr
.OpaqueSize
*Scr
.MyDisplayWidth
*Scr
.MyDisplayHeight
)/100)
500 do_move_opaque
= True
;
501 else if (IS_ICONIFIED(tmp_win
))
502 do_move_opaque
= True
;
505 Scr
.flags
.is_wire_frame_displayed
= True
;
509 if((!do_move_opaque
)&&(IS_ICONIFIED(tmp_win
)))
512 XOffset
= origDragX
- DragX
;
513 YOffset
= origDragY
- DragY
;
514 if (!Scr
.gs
.do_hide_position_window
)
515 XMapRaised(dpy
,Scr
.SizeWindow
);
516 moveLoop(tmp_win
, XOffset
,YOffset
,DragWidth
,DragHeight
, FinalX
,FinalY
,
518 if (Scr
.bo
.InstallRootCmap
)
519 UninstallRootColormap();
521 UninstallFvwmColormap();
526 /* Throw away some events that dont interest us right now. */
527 while (XCheckMaskEvent(dpy
, EnterWindowMask
|LeaveWindowMask
,
530 Scr
.flags
.is_wire_frame_displayed
= False
;
531 MyXUngrabServer(dpy
);
533 UngrabEm(GRAB_NORMAL
);
537 /* Perform the movement of the window. ppctMovement *must* have a 1.0 entry
538 * somewhere in ins list of floats, and movement will stop when it hits a 1.0
540 static void AnimatedMoveAnyWindow(FvwmWindow
*tmp_win
, Window w
, int startX
,
541 int startY
, int endX
, int endY
,
542 Bool fWarpPointerToo
, int cmsDelay
,
543 float *ppctMovement
)
545 int pointerX
, pointerY
;
546 int currentX
, currentY
;
550 if (tmp_win
&& IS_FIXED(tmp_win
))
553 /* set our defaults */
554 if (ppctMovement
== NULL
)
555 ppctMovement
= rgpctMovementDefault
;
557 cmsDelay
= cmsDelayDefault
;
559 if (startX
< 0 || startY
< 0)
561 if (!XGetGeometry(dpy
, w
, &JunkRoot
, ¤tX
, ¤tY
,
562 &JunkWidth
, &JunkHeight
, &JunkBW
, &JunkDepth
))
573 deltaX
= endX
- startX
;
574 deltaY
= endY
- startY
;
578 if (deltaX
== 0 && deltaY
== 0)
579 /* go nowhere fast */
582 /* Needed for aborting */
583 XGrabKeyboard(dpy
, Scr
.Root
, False
, GrabModeAsync
, GrabModeAsync
,
587 currentX
= startX
+ deltaX
* (*ppctMovement
);
588 currentY
= startY
+ deltaY
* (*ppctMovement
);
589 if (lastX
== currentX
&& lastY
== currentY
)
590 /* don't waste time in the same spot */
592 XMoveWindow(dpy
,w
,currentX
,currentY
);
593 if (fWarpPointerToo
== True
)
595 XQueryPointer(dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
,
596 &JunkX
,&JunkY
,&pointerX
,&pointerY
,&JunkMask
);
597 pointerX
+= currentX
- lastX
;
598 pointerY
+= currentY
- lastY
;
599 XWarpPointer(dpy
,None
,Scr
.Root
,0,0,0,0,
602 if (tmp_win
&& !IS_SHADED(tmp_win
))
604 /* send configure notify event for windows that care about their
607 tmp_win
, currentX
, currentY
, tmp_win
->frame_g
.width
,
608 tmp_win
->frame_g
.height
, 0, False
);
609 #ifdef FVWM_DEBUG_MSGS
610 fvwm_msg(DBG
,"AnimatedMoveAnyWindow",
611 "Sent ConfigureNotify (w == %d, h == %d)",
612 tmp_win
->frame_g
.width
, tmp_win
->frame_g
.height
);
618 tmp_win
->frame_g
.x
= currentX
;
619 tmp_win
->frame_g
.y
= currentY
;
620 update_absolute_geometry(tmp_win
);
621 maximize_adjust_offset(tmp_win
);
622 BroadcastConfig(M_CONFIGURE_WINDOW
, tmp_win
);
623 FlushAllMessageQueues();
626 usleep(cmsDelay
* 1000); /* usleep takes microseconds */
627 /* this didn't work for me -- maybe no longer necessary since
628 * we warn the user when they use > .5 seconds as a between-frame delay
631 * domivogt (28-apr-1999): That is because the keyboard was not grabbed.
634 if (XCheckMaskEvent(dpy
, ButtonPressMask
|ButtonReleaseMask
|KeyPressMask
,
637 StashEventTime(&Event
);
638 /* finish the move immediately */
639 XMoveWindow(dpy
,w
,endX
,endY
);
646 (*ppctMovement
!= 1.0 && ppctMovement
++);
647 XUngrabKeyboard(dpy
, CurrentTime
);
650 GNOME_SetWinArea(tmp_win
);
654 /* used for moving menus, not a client window */
655 void AnimatedMoveOfWindow(Window w
, int startX
, int startY
,
656 int endX
, int endY
, Bool fWarpPointerToo
,
657 int cmsDelay
, float *ppctMovement
)
659 AnimatedMoveAnyWindow(NULL
, w
, startX
, startY
, endX
, endY
, fWarpPointerToo
,
660 cmsDelay
, ppctMovement
);
663 /* used for moving client windows */
664 void AnimatedMoveFvwmWindow(FvwmWindow
*tmp_win
, Window w
, int startX
,
665 int startY
, int endX
, int endY
,
666 Bool fWarpPointerToo
, int cmsDelay
,
669 AnimatedMoveAnyWindow(tmp_win
, w
, startX
, startY
, endX
, endY
,
670 fWarpPointerToo
, cmsDelay
, ppctMovement
);
674 /****************************************************************************
676 * Start a window move operation
678 ****************************************************************************/
679 void move_window_doit(F_CMD_ARGS
, Bool do_animate
, Bool do_move_to_page
)
685 unsigned int width
, height
;
688 Bool fPointer
= False
;
692 if (DeferExecution(eventp
,&w
,&tmp_win
,&context
,
693 (do_move_to_page
) ? CRS_SELECT
: CRS_MOVE
, ButtonPress
))
699 if (IS_FIXED(tmp_win
))
702 /* gotta have a window */
704 if(IS_ICONIFIED(tmp_win
))
706 if(tmp_win
->icon_pixmap_w
!= None
)
708 w
= tmp_win
->icon_pixmap_w
;
709 XUnmapWindow(dpy
,tmp_win
->icon_w
);
716 if (!XGetGeometry(dpy
, w
, &JunkRoot
, &x
, &y
, &width
, &height
,
717 &JunkBW
, &JunkDepth
))
728 SET_STICKY(tmp_win
, 0);
730 if (!get_page_arguments(action
, &page_x
, &page_y
))
740 s
.x
= page_x
- Scr
.Vx
;
741 s
.y
= page_y
- Scr
.Vy
;
742 s
.width
= Scr
.MyDisplayWidth
;
743 s
.height
= Scr
.MyDisplayHeight
;
744 move_into_rectangle(&r
, &s
);
748 if (!IntersectsInterval(x
, width
, page_x
- Scr
.Vx
, Scr
.MyDisplayWidth
))
750 FinalX
= x
% Scr
.MyDisplayWidth
;
752 FinalX
+= Scr
.MyDisplayWidth
;
753 FinalX
+= page_x
- Scr
.Vx
;
759 if (!IntersectsInterval(y
, height
, page_y
- Scr
.Vy
, Scr
.MyDisplayHeight
))
761 FinalY
= y
% Scr
.MyDisplayHeight
;
763 FinalY
+= Scr
.MyDisplayHeight
;
764 FinalY
+= page_y
- Scr
.Vy
;
776 n
= GetMoveArguments(
777 &action
, width
, height
, &FinalX
, &FinalY
, &fWarp
, &fPointer
);
779 if (n
!= 2 || fPointer
)
780 InteractiveMove(&w
, tmp_win
, &FinalX
, &FinalY
, eventp
, fPointer
);
783 if (w
== tmp_win
->frame
)
785 dx
= FinalX
- tmp_win
->frame_g
.x
;
786 dy
= FinalY
- tmp_win
->frame_g
.y
;
789 AnimatedMoveFvwmWindow(tmp_win
,w
,-1,-1,FinalX
,FinalY
,fWarp
,-1,NULL
);
791 SetupFrame(tmp_win
, FinalX
, FinalY
,
792 tmp_win
->frame_g
.width
, tmp_win
->frame_g
.height
, True
);
793 if (fWarp
& !do_animate
)
794 XWarpPointer(dpy
, None
, None
, 0, 0, 0, 0, FinalX
- x
, FinalY
- y
);
795 if (IS_MAXIMIZED(tmp_win
))
797 tmp_win
->max_g
.x
+= dx
;
798 tmp_win
->max_g
.y
+= dy
;
802 tmp_win
->normal_g
.x
+= dx
;
803 tmp_win
->normal_g
.y
+= dy
;
805 update_absolute_geometry(tmp_win
);
806 maximize_adjust_offset(tmp_win
);
808 GNOME_SetWinArea(tmp_win
);
810 else /* icon window */
812 tmp_win
->icon_g
.x
= FinalX
;
813 tmp_win
->icon_xl_loc
= FinalX
-
814 (tmp_win
->icon_g
.width
- tmp_win
->icon_p_width
)/2;
815 tmp_win
->icon_g
.y
= FinalY
;
816 BroadcastPacket(M_ICON_LOCATION
, 7,
817 tmp_win
->w
, tmp_win
->frame
,
818 (unsigned long)tmp_win
,
819 tmp_win
->icon_g
.x
, tmp_win
->icon_g
.y
,
820 tmp_win
->icon_p_width
,
821 tmp_win
->icon_g
.height
+ tmp_win
->icon_p_height
);
824 AnimatedMoveOfWindow(tmp_win
->icon_w
,-1,-1,tmp_win
->icon_xl_loc
,
825 FinalY
+tmp_win
->icon_p_height
, fWarp
,-1,NULL
);
829 XMoveWindow(dpy
,tmp_win
->icon_w
, tmp_win
->icon_xl_loc
,
830 FinalY
+tmp_win
->icon_p_height
);
832 XWarpPointer(dpy
, None
, None
, 0, 0, 0, 0, FinalX
- x
, FinalY
- y
);
834 if(tmp_win
->icon_pixmap_w
!= None
)
836 XMapWindow(dpy
,tmp_win
->icon_w
);
839 AnimatedMoveOfWindow(tmp_win
->icon_pixmap_w
, -1,-1,
840 tmp_win
->icon_g
.x
,FinalY
,fWarp
,-1,NULL
);
844 XMoveWindow(dpy
, tmp_win
->icon_pixmap_w
, tmp_win
->icon_g
.x
, FinalY
);
846 XWarpPointer(dpy
, None
, None
, 0, 0, 0, 0, FinalX
- x
, FinalY
- y
);
855 void move_window(F_CMD_ARGS
)
857 move_window_doit(F_PASS_ARGS
, False
, False
);
860 void animated_move_window(F_CMD_ARGS
)
862 move_window_doit(F_PASS_ARGS
, True
, False
);
865 void move_window_to_page(F_CMD_ARGS
)
867 move_window_doit(F_PASS_ARGS
, False
, True
);
870 /* This function does the SnapAttraction stuff. If takes x and y coordinates
871 * (*px and *py) and returns the snapped values. */
872 static void DoSnapAttract(
873 FvwmWindow
*tmp_win
, unsigned int Width
, unsigned int Height
,
876 int nyt
,nxl
,dist
,closestLeft
,closestRight
,closestBottom
,closestTop
;
877 rectangle self
, other
;
880 /* resist based on window edges */
881 tmp
= Scr
.FvwmRoot
.next
;
882 closestTop
= Scr
.SnapAttraction
;
883 closestBottom
= Scr
.SnapAttraction
;
884 closestRight
= Scr
.SnapAttraction
;
885 closestLeft
= Scr
.SnapAttraction
;
891 self
.height
= Height
;
892 if (IS_ICONIFIED(tmp_win
) && !HAS_NO_ICON_TITLE(tmp_win
))
894 self
.height
+= tmp_win
->icon_g
.height
;
896 while(Scr
.SnapAttraction
>= 0 && tmp
)
898 switch (Scr
.SnapMode
)
900 case 1: /* SameType */
901 if( IS_ICONIFIED(tmp
) != IS_ICONIFIED(tmp_win
))
908 if( !IS_ICONIFIED(tmp
) || !IS_ICONIFIED(tmp_win
))
914 case 3: /* Windows */
915 if( IS_ICONIFIED(tmp
) || IS_ICONIFIED(tmp_win
))
926 if (tmp_win
!= tmp
&& (tmp_win
->Desk
== tmp
->Desk
))
928 if(IS_ICONIFIED(tmp
))
930 if(tmp
->icon_p_height
> 0)
932 other
.width
= tmp
->icon_p_width
;
933 other
.height
= tmp
->icon_p_height
;
937 other
.width
= tmp
->icon_g
.width
;
938 other
.height
= tmp
->icon_g
.height
;
940 other
.x
= tmp
->icon_g
.x
;
941 other
.y
= tmp
->icon_g
.y
;
942 if (!HAS_NO_ICON_TITLE(tmp
))
944 other
.height
+= tmp
->icon_g
.height
;
949 other
.width
= tmp
->frame_g
.width
;
950 other
.height
= tmp
->frame_g
.height
;
951 other
.x
= tmp
->frame_g
.x
;
952 other
.y
= tmp
->frame_g
.y
;
954 if(!((other
.y
+ (int)other
.height
) < (*py
) ||
955 (other
.y
) > (*py
+ (int)self
.height
) ))
957 dist
= abs(other
.x
- (*px
+ (int)self
.width
));
958 if(dist
< closestRight
)
961 if(((*px
+ (int)self
.width
) >= other
.x
)&&
962 ((*px
+ (int)self
.width
) < other
.x
+Scr
.SnapAttraction
))
964 nxl
= other
.x
- (int)self
.width
;
966 if(((*px
+ (int)self
.width
) >= other
.x
- Scr
.SnapAttraction
)&&
967 ((*px
+ (int)self
.width
) < other
.x
))
969 nxl
= other
.x
- (int)self
.width
;
972 dist
= abs(other
.x
+ (int)other
.width
- *px
);
973 if(dist
< closestLeft
)
976 if((*px
<= other
.x
+ (int)other
.width
)&&
977 (*px
> other
.x
+ (int)other
.width
- Scr
.SnapAttraction
))
979 nxl
= other
.x
+ (int)other
.width
;
981 if((*px
<= other
.x
+ (int)other
.width
+ Scr
.SnapAttraction
)&&
982 (*px
> other
.x
+ (int)other
.width
))
984 nxl
= other
.x
+ (int)other
.width
;
988 /* ScreenEdges - SJL */
989 if(!(Scr
.MyDisplayHeight
< (*py
) ||
990 (*py
+ (int)self
.height
) < 0) && (Scr
.SnapMode
& 8))
992 dist
= abs(Scr
.MyDisplayWidth
- (*px
+ (int)self
.width
));
994 if(dist
< closestRight
)
998 if(((*px
+ (int)self
.width
) >= Scr
.MyDisplayWidth
)&&
999 ((*px
+ (int)self
.width
) < Scr
.MyDisplayWidth
+
1000 Scr
.SnapAttraction
))
1002 nxl
= Scr
.MyDisplayWidth
- (int)self
.width
;
1005 if(((*px
+ (int)self
.width
) >= Scr
.MyDisplayWidth
-
1006 Scr
.SnapAttraction
)&&
1007 ((*px
+ (int)self
.width
) < Scr
.MyDisplayWidth
))
1009 nxl
= Scr
.MyDisplayWidth
- (int)self
.width
;
1015 if(dist
< closestLeft
)
1020 (*px
> - Scr
.SnapAttraction
))
1024 if((*px
<= Scr
.SnapAttraction
)&&
1032 if(!((other
.x
+ (int)other
.width
) < (*px
) ||
1033 (other
.x
) > (*px
+ (int)self
.width
)))
1035 dist
= abs(other
.y
- (*py
+ (int)self
.height
));
1036 if(dist
< closestBottom
)
1038 closestBottom
= dist
;
1039 if(((*py
+ (int)self
.height
) >= other
.y
)&&
1040 ((*py
+ (int)self
.height
) < other
.y
+Scr
.SnapAttraction
))
1042 nyt
= other
.y
- (int)self
.height
;
1044 if(((*py
+ (int)self
.height
) >= other
.y
- Scr
.SnapAttraction
)&&
1045 ((*py
+ (int)self
.height
) < other
.y
))
1047 nyt
= other
.y
- (int)self
.height
;
1050 dist
= abs(other
.y
+ (int)other
.height
- *py
);
1051 if(dist
< closestTop
)
1054 if((*py
<= other
.y
+ (int)other
.height
)&&
1055 (*py
> other
.y
+ (int)other
.height
- Scr
.SnapAttraction
))
1057 nyt
= other
.y
+ (int)other
.height
;
1059 if((*py
<= other
.y
+ (int)other
.height
+ Scr
.SnapAttraction
)&&
1060 (*py
> other
.y
+ (int)other
.height
))
1062 nyt
= other
.y
+ (int)other
.height
;
1066 /* ScreenEdges - SJL */
1067 if (!(Scr
.MyDisplayWidth
< (*px
) || (*px
+ (int)self
.width
) < 0 )
1068 && (Scr
.SnapMode
& 8))
1070 dist
= abs(Scr
.MyDisplayHeight
- (*py
+ (int)self
.height
));
1072 if(dist
< closestBottom
)
1074 closestBottom
= dist
;
1075 if(((*py
+ (int)self
.height
) >= Scr
.MyDisplayHeight
)&&
1076 ((*py
+ (int)self
.height
) < Scr
.MyDisplayHeight
+
1077 Scr
.SnapAttraction
))
1079 nyt
= Scr
.MyDisplayHeight
- (int)self
.height
;
1081 if(((*py
+ (int)self
.height
) >= Scr
.MyDisplayHeight
-
1082 Scr
.SnapAttraction
)&&
1083 ((*py
+ (int)self
.height
) < Scr
.MyDisplayHeight
))
1085 nyt
= Scr
.MyDisplayHeight
- (int)self
.height
;
1091 if(dist
< closestTop
)
1094 if((*py
<= 0)&&(*py
> - Scr
.SnapAttraction
))
1098 if((*py
<= Scr
.SnapAttraction
)&&(*py
> 0))
1108 /* Snap grid handling */
1111 if(*px
!= *px
/ Scr
.SnapGridX
* Scr
.SnapGridX
)
1113 *px
= (*px
+ ((*px
>= 0) ? Scr
.SnapGridX
: -Scr
.SnapGridX
) / 2) /
1114 Scr
.SnapGridX
* Scr
.SnapGridX
;
1123 if(*py
!= *py
/ Scr
.SnapGridY
* Scr
.SnapGridY
)
1125 *py
= (*py
+ ((*py
>= 0) ? Scr
.SnapGridY
: -Scr
.SnapGridY
) / 2) /
1126 Scr
.SnapGridY
* Scr
.SnapGridY
;
1133 /* Resist moving windows beyond the edge of the screen */
1134 if (((*px
+ Width
) >= Scr
.MyDisplayWidth
)
1135 && ((*px
+ Width
) < Scr
.MyDisplayWidth
+ Scr
.MoveResistance
))
1136 *px
= Scr
.MyDisplayWidth
- Width
;
1137 if ((*px
<= 0) && (*px
> -Scr
.MoveResistance
))
1139 if (((*py
+ Height
) >= Scr
.MyDisplayHeight
)
1140 && ((*py
+ Height
) < Scr
.MyDisplayHeight
+ Scr
.MoveResistance
))
1141 *py
= Scr
.MyDisplayHeight
- Height
;
1142 if ((*py
<= 0) && (*py
> -Scr
.MoveResistance
))
1146 /****************************************************************************
1148 * Move the rubberband around, return with the new window location
1150 * Returns True if the window has to be resized after the move.
1152 ****************************************************************************/
1153 Bool
moveLoop(FvwmWindow
*tmp_win
, int XOffset
, int YOffset
, int Width
,
1154 int Height
, int *FinalX
, int *FinalY
,Bool do_move_opaque
)
1156 extern Window bad_window
;
1157 Bool finished
= False
;
1159 Bool aborted
= False
;
1160 int xl
,xl2
,yt
,yt2
,delta_x
,delta_y
,paged
;
1161 unsigned int button_mask
= 0;
1162 FvwmWindow tmp_win_copy
;
1163 int dx
= Scr
.EdgeScrollX
? Scr
.EdgeScrollX
: Scr
.MyDisplayWidth
;
1164 int dy
= Scr
.EdgeScrollY
? Scr
.EdgeScrollY
: Scr
.MyDisplayHeight
;
1171 Bool sent_cn
= False
;
1172 Bool do_resize_too
= False
;
1173 Bool do_exec_placement_func
= False
;
1176 Window move_w
= None
;
1177 int orig_icon_x
= 0;
1178 int orig_icon_y
= 0;
1180 if (!IS_MAPPED(tmp_win
) && !IS_ICONIFIED(tmp_win
))
1181 do_move_opaque
= False
;
1184 if (IS_ICONIFIED(tmp_win
))
1186 if(tmp_win
->icon_pixmap_w
!= None
)
1187 move_w
= tmp_win
->icon_pixmap_w
;
1188 else if (tmp_win
->icon_w
!= None
)
1189 move_w
= tmp_win
->icon_w
;
1193 move_w
= tmp_win
->frame
;
1195 if (!XGetGeometry(dpy
, move_w
, &JunkRoot
, &x_bak
, &y_bak
,
1196 &JunkWidth
, &JunkHeight
, &JunkBW
,&JunkDepth
))
1198 /* This is allright here since the window may not be mapped yet. */
1201 if (IS_ICONIFIED(tmp_win
))
1203 orig_icon_x
= tmp_win
->icon_g
.x
;
1204 orig_icon_y
= tmp_win
->icon_g
.y
;
1207 /* make a copy of the tmp_win structure for sending to the pager */
1208 memcpy(&tmp_win_copy
, tmp_win
, sizeof(FvwmWindow
));
1209 /* prevent flicker when paging */
1210 SET_WINDOW_BEING_MOVED_OPAQUE(tmp_win
, do_move_opaque
);
1212 XQueryPointer(dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
,&xl
, &yt
,
1213 &JunkX
, &JunkY
, &button_mask
);
1214 button_mask
&= DEFAULT_ALL_BUTTONS_MASK
;
1220 /* draw initial outline */
1221 if (!IS_ICONIFIED(tmp_win
) &&
1222 ((!do_move_opaque
&& !Scr
.gs
.EmulateMWM
) || !IS_MAPPED(tmp_win
)))
1223 MoveOutline(xl
, yt
, Width
- 1, Height
- 1);
1225 DisplayPosition(tmp_win
,xl
,yt
,True
);
1227 while (!finished
&& bad_window
!= tmp_win
->w
)
1229 /* wait until there is an interesting event */
1230 while (!XPending(dpy
) ||
1231 !XCheckMaskEvent(dpy
, ButtonPressMask
| ButtonReleaseMask
|
1232 KeyPressMask
| PointerMotionMask
|
1233 ButtonMotionMask
| ExposureMask
, &Event
))
1235 if (HandlePaging(dx
, dy
, &xl
,&yt
, &delta_x
,&delta_y
, False
, False
, True
))
1237 /* Fake an event to force window reposition */
1240 DoSnapAttract(tmp_win
, Width
, Height
, &xl
, &yt
);
1241 Event
.type
= MotionNotify
;
1242 Event
.xmotion
.time
= lastTimestamp
;
1243 Event
.xmotion
.x_root
= xl
- XOffset
;
1244 Event
.xmotion
.y_root
= yt
- YOffset
;
1248 StashEventTime(&Event
);
1250 /* discard any extra motion events before a logical release */
1251 if (Event
.type
== MotionNotify
)
1255 /*** logic borrowed from icewm ***/
1256 while (XPending(dpy
) > 0 &&
1257 XCheckMaskEvent(dpy
, ButtonMotionMask
| PointerMotionMask
|
1258 ButtonPressMask
| ButtonRelease
| KeyPressMask
,
1261 if (Event
.type
!= new_event
.type
)
1263 XPutBackEvent(dpy
, &new_event
);
1271 /*** end of code borrowed from icewm ***/
1272 StashEventTime(&Event
);
1274 } /* if (Event.type == MotionNotify) */
1277 /* Handle a limited number of key press events to allow mouseless
1279 if (Event
.type
== KeyPress
)
1280 Keyboard_shortcuts(&Event
, tmp_win
, ButtonRelease
);
1284 /* simple code to bag out of move - CKH */
1285 if (XLookupKeysym(&(Event
.xkey
),0) == XK_Escape
)
1288 MoveOutline(0, 0, 0, 0);
1289 if (!IS_ICONIFIED(tmp_win
))
1291 *FinalX
= tmp_win
->frame_g
.x
;
1292 *FinalY
= tmp_win
->frame_g
.y
;
1296 *FinalX
= orig_icon_x
;
1297 *FinalY
= orig_icon_y
;
1305 XAllowEvents(dpy
,ReplayPointer
,CurrentTime
);
1306 if (Event
.xbutton
.button
<= NUMBER_OF_MOUSE_BUTTONS
&&
1307 ((Button1Mask
<< (Event
.xbutton
.button
- 1)) & button_mask
))
1309 /* No new button was pressed, just a delayed event */
1313 if(((Event
.xbutton
.button
== 2)&&(!Scr
.gs
.EmulateMWM
))||
1314 ((Event
.xbutton
.button
== 1)&&(Scr
.gs
.EmulateMWM
)&&
1315 (Event
.xbutton
.state
& ShiftMask
)))
1317 do_resize_too
= True
;
1318 do_exec_placement_func
= False
;
1319 /* Fallthrough to button-release */
1321 else if(Event
.xbutton
.button
== 3)
1323 do_exec_placement_func
= True
;
1324 do_resize_too
= False
;
1325 /* Fallthrough to button-release */
1329 /* Abort the move if
1330 * - the move started with a pressed button and another button
1331 * was pressed during the operation
1332 * - no button was pressed at the beginning and any button
1333 * except button 1 was pressed. */
1334 if (button_mask
|| (Event
.xbutton
.button
!= 1))
1337 MoveOutline(0, 0, 0, 0);
1338 if (!IS_ICONIFIED(tmp_win
))
1340 *FinalX
= tmp_win
->frame_g
.x
;
1341 *FinalY
= tmp_win
->frame_g
.y
;
1345 *FinalX
= orig_icon_x
;
1346 *FinalY
= orig_icon_y
;
1356 MoveOutline(0, 0, 0, 0);
1357 xl2
= Event
.xbutton
.x_root
+ XOffset
;
1358 yt2
= Event
.xbutton
.y_root
+ YOffset
;
1359 /* ignore the position of the button release if it was on a
1360 * different page. */
1361 if (!(((xl
< 0 && xl2
>= 0) || (xl
>= 0 && xl2
< 0) ||
1362 (yt
< 0 && yt2
>= 0) || (yt
>= 0 && yt2
< 0)) &&
1363 (abs(xl
- xl2
) > Scr
.MyDisplayWidth
/ 2 ||
1364 abs(yt
- yt2
) > Scr
.MyDisplayHeight
/ 2)))
1369 if (xl
!= xl_orig
|| yt
!= yt_orig
|| vx
!= Scr
.Vx
|| vy
!= Scr
.Vy
)
1371 /* only snap if the window actually moved! */
1372 DoSnapAttract(tmp_win
, Width
, Height
, &xl
, &yt
);
1383 xl
= Event
.xmotion
.x_root
+ XOffset
;
1384 yt
= Event
.xmotion
.y_root
+ YOffset
;
1386 DoSnapAttract(tmp_win
, Width
, Height
, &xl
, &yt
);
1388 /* check Paging request once and only once after outline redrawn */
1389 /* redraw after paging if needed - mab */
1394 MoveOutline(xl
, yt
, Width
- 1, Height
- 1);
1397 if (IS_ICONIFIED(tmp_win
))
1399 tmp_win
->icon_g
.x
= xl
;
1400 tmp_win
->icon_xl_loc
= xl
-
1401 (tmp_win
->icon_g
.width
- tmp_win
->icon_p_width
)/2;
1402 tmp_win
->icon_g
.y
= yt
;
1403 if(tmp_win
->icon_pixmap_w
!= None
)
1404 XMoveWindow(dpy
, tmp_win
->icon_pixmap_w
, tmp_win
->icon_g
.x
,yt
);
1405 else if (tmp_win
->icon_w
!= None
)
1406 XMoveWindow(dpy
, tmp_win
->icon_w
,tmp_win
->icon_xl_loc
,
1407 yt
+tmp_win
->icon_p_height
);
1411 XMoveWindow(dpy
,tmp_win
->frame
,xl
,yt
);
1414 DisplayPosition(tmp_win
,xl
,yt
,False
);
1416 /* prevent window from lagging behind mouse when paging - mab */
1419 xl
= Event
.xmotion
.x_root
;
1420 yt
= Event
.xmotion
.y_root
;
1422 dx
, dy
, &xl
, &yt
, &delta_x
, &delta_y
, False
, False
, False
);
1425 DoSnapAttract(tmp_win
, Width
, Height
, &xl
, &yt
);
1426 if (!delta_x
&& !delta_y
)
1427 /* break from while (paged)*/
1431 } /* end while (paged) */
1441 if (!do_move_opaque
)
1442 /* must undraw the rubber band in case the event causes some drawing */
1443 MoveOutline(0,0,0,0);
1444 DispatchEvent(False
);
1446 MoveOutline(xl
, yt
, Width
- 1, Height
- 1);
1448 if (do_move_opaque
&& !IS_ICONIFIED(tmp_win
) && !IS_SHADED(tmp_win
))
1450 /* send configure notify event for windows that care about their
1451 * location; don't send anything if position didn't change */
1452 if (!sent_cn
|| cnx
!= xl
|| cny
!= yt
)
1457 SendConfigureNotify(tmp_win
, xl
, yt
, Width
, Height
, 0, False
);
1458 #ifdef FVWM_DEBUG_MSGS
1459 fvwm_msg(DBG
,"SetupFrame","Sent ConfigureNotify (w == %d, h == %d)",
1467 if (!IS_ICONIFIED(tmp_win
))
1469 tmp_win_copy
.frame_g
.x
= xl
;
1470 tmp_win_copy
.frame_g
.y
= yt
;
1472 /* only do this with opaque moves, (i.e. the server is not grabbed) */
1473 BroadcastConfig(M_CONFIGURE_WINDOW
, &tmp_win_copy
);
1474 FlushAllMessageQueues();
1476 } /* while (!finished) */
1478 if (!Scr
.gs
.do_hide_position_window
)
1479 XUnmapWindow(dpy
,Scr
.SizeWindow
);
1480 if (aborted
|| bad_window
== tmp_win
->w
)
1482 if (vx
!= Scr
.Vx
|| vy
!= Scr
.Vy
)
1484 MoveViewport(vx
, vy
, False
);
1486 if (aborted
&& do_move_opaque
)
1488 XMoveWindow(dpy
, move_w
, x_bak
, y_bak
);
1490 if (bad_window
== tmp_win
->w
)
1492 XUnmapWindow(dpy
, move_w
);
1496 if (!aborted
&& bad_window
!= tmp_win
->w
&& IS_ICONIFIED(tmp_win
))
1498 SET_ICON_MOVED(tmp_win
, 1);
1502 /* Don't wait for buttons to come up when user is placing a new window
1503 * and wants to resize it. */
1504 WaitForButtonsUp(True
);
1506 SET_WINDOW_BEING_MOVED_OPAQUE(tmp_win
, 0);
1509 return do_resize_too
;
1512 /***********************************************************************
1515 * DisplayPosition - display the position in the dimensions window
1518 * tmp_win - the current fvwm window
1519 * x, y - position of the window
1521 ************************************************************************/
1523 static void DisplayPosition(FvwmWindow
*tmp_win
, int x
, int y
,int Init
)
1528 if (Scr
.gs
.do_hide_position_window
)
1530 (void) sprintf (str
, " %+-4d %+-4d ", x
, y
);
1533 XClearWindow(dpy
,Scr
.SizeWindow
);
1537 /* just clear indside the relief lines to reduce flicker */
1538 XClearArea(dpy
,Scr
.SizeWindow
,2,2,
1539 Scr
.SizeStringWidth
+ SIZE_HINDENT
*2 - 3,
1540 Scr
.DefaultFont
.height
+ SIZE_VINDENT
*2 - 3,False
);
1544 RelieveRectangle(dpy
,Scr
.SizeWindow
,0,0,
1545 Scr
.SizeStringWidth
+ SIZE_HINDENT
*2 - 1,
1546 Scr
.DefaultFont
.height
+ SIZE_VINDENT
*2 - 1,
1548 Scr
.StdShadowGC
, 2);
1549 offset
= (Scr
.SizeStringWidth
+ SIZE_HINDENT
*2
1550 - XTextWidth(Scr
.DefaultFont
.font
,str
,strlen(str
)))/2;
1552 XmbDrawString (dpy
, Scr
.SizeWindow
, Scr
.DefaultFont
.fontset
, Scr
.StdGC
,
1554 XDrawString (dpy
, Scr
.SizeWindow
, Scr
.StdGC
,
1557 Scr
.DefaultFont
.font
->ascent
+ SIZE_VINDENT
,
1562 void SetMoveThreshold(F_CMD_ARGS
)
1566 if (GetIntegerArguments(action
, NULL
, &val
, 1) < 1 || val
< 0)
1567 Scr
.MoveThreshold
= DEFAULT_MOVE_THRESHOLD
;
1569 Scr
.MoveThreshold
= val
;
1573 void SetOpaque(F_CMD_ARGS
)
1577 if(GetIntegerArguments(action
, NULL
, &val
, 1) < 1 || val
< 0)
1578 Scr
.OpaqueSize
= DEFAULT_OPAQUE_MOVE_SIZE
;
1580 Scr
.OpaqueSize
= val
;
1584 static char *hide_options
[] =
1592 void HideGeometryWindow(F_CMD_ARGS
)
1594 char *token
= PeekToken(action
, NULL
);
1596 Scr
.gs
.do_hide_position_window
= 0;
1597 Scr
.gs
.do_hide_resize_window
= 0;
1598 switch(GetTokenIndex(token
, hide_options
, 0, NULL
))
1603 Scr
.gs
.do_hide_position_window
= 1;
1606 Scr
.gs
.do_hide_resize_window
= 1;
1609 Scr
.gs
.do_hide_position_window
= 1;
1610 Scr
.gs
.do_hide_resize_window
= 1;
1617 void SetSnapAttraction(F_CMD_ARGS
)
1622 if(GetIntegerArguments(action
, &action
, &val
, 1) != 1)
1624 Scr
.SnapAttraction
= DEFAULT_SNAP_ATTRACTION
;
1625 Scr
.SnapMode
= DEFAULT_SNAP_ATTRACTION_MODE
;
1628 Scr
.SnapAttraction
= val
;
1631 Scr
.SnapAttraction
= DEFAULT_SNAP_ATTRACTION
;
1634 action
= GetNextToken(action
, &token
);
1641 if (StrEquals(token
,"All"))
1645 else if (StrEquals(token
,"SameType"))
1649 else if (StrEquals(token
,"Icons"))
1653 else if (StrEquals(token
,"Windows"))
1658 if (Scr
.SnapMode
!= -1)
1661 action
= GetNextToken(action
, &token
);
1669 Scr
.SnapMode
= DEFAULT_SNAP_ATTRACTION_MODE
;
1672 if (StrEquals(token
,"Screen"))
1678 fvwm_msg(ERR
,"SetSnapAttraction", "Invalid argument: %s", token
);
1684 void SetSnapGrid(F_CMD_ARGS
)
1688 if(GetIntegerArguments(action
, NULL
, &val
[0], 2) != 2)
1690 Scr
.SnapGridX
= DEFAULT_SNAP_GRID_X
;
1691 Scr
.SnapGridY
= DEFAULT_SNAP_GRID_Y
;
1695 Scr
.SnapGridX
= val
[0];
1696 if(Scr
.SnapGridX
< 1)
1698 Scr
.SnapGridX
= DEFAULT_SNAP_GRID_X
;
1700 Scr
.SnapGridY
= val
[1];
1701 if(Scr
.SnapGridY
< 1)
1703 Scr
.SnapGridY
= DEFAULT_SNAP_GRID_Y
;
1707 static Pixmap XorPixmap
= None
;
1709 void SetXOR(F_CMD_ARGS
)
1715 if(GetIntegerArguments(action
, NULL
, &val
, 1) != 1)
1720 gcm
= GCFunction
|GCLineWidth
|GCForeground
|GCFillStyle
|GCSubwindowMode
;
1721 gcv
.subwindow_mode
= IncludeInferiors
;
1722 gcv
.function
= GXxor
;
1724 /* use passed in value, or try to calculate appropriate value if 0 */
1727 gcv.foreground = (val1)?(val1):((((unsigned long) 1) << Scr.d_depth) - 1);
1729 /* Xlib programming manual suggestion: */
1730 gcv
.foreground
= (val
)?
1731 (val
):(BlackPixel(dpy
,Scr
.screen
) ^ WhitePixel(dpy
,Scr
.screen
));
1732 gcv
.fill_style
= FillSolid
;
1733 gcv
.subwindow_mode
= IncludeInferiors
;
1735 /* modify XorGC, only create once */
1737 XChangeGC(dpy
, Scr
.XorGC
, gcm
, &gcv
);
1739 Scr
.XorGC
= XCreateGC(dpy
, Scr
.Root
, gcm
, &gcv
);
1741 /* free up XorPixmap if neccesary */
1742 if (XorPixmap
!= None
) {
1743 XFreePixmap(dpy
, XorPixmap
);
1749 void SetXORPixmap(F_CMD_ARGS
)
1756 action
= GetNextToken(action
, &PixmapName
);
1757 if(PixmapName
== NULL
)
1759 /* return to default value. */
1761 SetXOR(F_PASS_ARGS
);
1764 /* get the picture in the root visual, colorlimit is ignored because the
1765 * pixels will be freed */
1767 xp
= GetPicture(dpy
, Scr
.Root
, NULL
, PixmapName
, 0);
1769 fvwm_msg(ERR
,"SetXORPixmap","Can't find pixmap %s", PixmapName
);
1775 /* free up old pixmap */
1776 if (XorPixmap
!= None
)
1777 XFreePixmap(dpy
, XorPixmap
);
1779 /* make a copy of the picture pixmap */
1780 XorPixmap
= XCreatePixmap(dpy
, Scr
.Root
, xp
->width
, xp
->height
, Pdepth
);
1781 XCopyArea(dpy
, xp
->picture
, XorPixmap
, DefaultGC(dpy
, Scr
.screen
), 0, 0,
1782 xp
->width
, xp
->height
, 0, 0);
1783 /* destroy picture and free colors */
1784 DestroyPicture(dpy
, xp
);
1787 /* create Graphics context */
1788 gcm
= GCFunction
|GCLineWidth
|GCTile
|GCFillStyle
|GCSubwindowMode
;
1789 gcv
.subwindow_mode
= IncludeInferiors
;
1790 gcv
.function
= GXxor
;
1791 /* line width of 1 is necessary for Exceed servers */
1793 gcv
.tile
= XorPixmap
;
1794 gcv
.fill_style
= FillTiled
;
1795 gcv
.subwindow_mode
= IncludeInferiors
;
1796 /* modify XorGC, only create once */
1798 XChangeGC(dpy
, Scr
.XorGC
, gcm
, &gcv
);
1800 Scr
.XorGC
= XCreateGC(dpy
, Scr
.Root
, gcm
, &gcv
);
1804 /* ----------------------------- resizing code ----------------------------- */
1806 /***********************************************************************
1808 * window resizing borrowed from the "wm" window manager
1810 ***********************************************************************/
1812 /****************************************************************************
1814 * Starts a window resize operation
1816 ****************************************************************************/
1817 void resize_window(F_CMD_ARGS
)
1819 extern Window bad_window
;
1820 Bool finished
= False
, done
= False
, abort
= False
;
1821 Bool do_resize_opaque
;
1822 int x
,y
,delta_x
,delta_y
,stashed_x
,stashed_y
;
1823 Window ResizeWindow
;
1824 Bool fButtonAbort
= False
;
1825 Bool fForceRedraw
= False
;
1827 unsigned int button_mask
= 0;
1830 rectangle
*drag
= &sdrag
;
1831 rectangle
*orig
= &sorig
;
1836 unsigned edge_wrap_x
;
1837 unsigned edge_wrap_y
;
1841 Bool called_from_title
= False
;
1844 if (DeferExecution(eventp
,&w
,&tmp_win
,&context
, CRS_RESIZE
, ButtonPress
))
1846 if (tmp_win
== NULL
|| IS_ICONIFIED(tmp_win
))
1849 ResizeWindow
= tmp_win
->frame
;
1850 XQueryPointer( dpy
, ResizeWindow
, &JunkRoot
, &JunkChild
,
1851 &JunkX
, &JunkY
, &px
, &py
, &button_mask
);
1852 button_mask
&= DEFAULT_ALL_BUTTONS_MASK
;
1854 if(check_if_function_allowed(F_RESIZE
,tmp_win
,True
,NULL
) == 0)
1860 was_maximized
= IS_MAXIMIZED(tmp_win
);
1861 SET_MAXIMIZED(tmp_win
, 0);
1864 /* must redraw the buttons now so that the 'maximize' button does not stay
1867 tmp_win
, DRAW_BUTTONS
, (tmp_win
== Scr
.Hilite
), True
, None
);
1870 if (IS_SHADED(tmp_win
) || !IS_MAPPED(tmp_win
))
1871 do_resize_opaque
= False
;
1873 do_resize_opaque
= DO_RESIZE_OPAQUE(tmp_win
);
1875 /* no suffix = % of screen, 'p' = pixels, 'c' = increment units */
1876 drag
->width
= tmp_win
->frame_g
.width
;
1877 drag
->height
= tmp_win
->frame_g
.height
;
1878 n
= GetResizeArguments(
1879 &action
, tmp_win
->frame_g
.x
, tmp_win
->frame_g
.y
,
1880 tmp_win
->hints
.base_width
, tmp_win
->hints
.base_height
,
1881 tmp_win
->hints
.width_inc
, tmp_win
->hints
.height_inc
,
1882 tmp_win
->boundary_width
, tmp_win
->title_g
.height
,
1883 &(drag
->width
), &(drag
->height
));
1887 /* size will be less or equal to requested */
1889 tmp_win
, (unsigned int *)&drag
->width
, (unsigned int *)&drag
->height
,
1890 xmotion
, ymotion
, False
);
1891 if (IS_SHADED(tmp_win
))
1893 SetupFrame(tmp_win
, tmp_win
->frame_g
.x
, tmp_win
->frame_g
.y
,
1894 drag
->width
, tmp_win
->frame_g
.height
, False
);
1898 SetupFrame(tmp_win
, tmp_win
->frame_g
.x
, tmp_win
->frame_g
.y
,
1899 drag
->width
, drag
->height
, False
);
1901 DrawDecorations(tmp_win
, DRAW_ALL
, True
, True
, None
);
1902 update_absolute_geometry(tmp_win
);
1903 maximize_adjust_offset(tmp_win
);
1904 GNOME_SetWinArea(tmp_win
);
1905 ResizeWindow
= None
;
1909 if (Scr
.bo
.InstallRootCmap
)
1910 InstallRootColormap();
1912 InstallFvwmColormap();
1914 if(!GrabEm(CRS_RESIZE
, GRAB_NORMAL
))
1920 if (!do_resize_opaque
)
1922 Scr
.flags
.is_wire_frame_displayed
= True
;
1926 /* handle problems with edge-wrapping while resizing */
1927 edge_wrap_x
= Scr
.flags
.edge_wrap_x
;
1928 edge_wrap_y
= Scr
.flags
.edge_wrap_y
;
1929 Scr
.flags
.edge_wrap_x
= 0;
1930 Scr
.flags
.edge_wrap_y
= 0;
1932 if (IS_SHADED(tmp_win
))
1934 if (HAS_BOTTOM_TITLE(tmp_win
))
1935 drag
->height
= tmp_win
->frame_g
.height
;
1939 drag
->height
= tmp_win
->max_g
.height
;
1941 drag
->height
= tmp_win
->normal_g
.height
;
1943 drag
->x
= tmp_win
->frame_g
.x
;
1944 drag
->y
= tmp_win
->frame_g
.y
;
1945 drag
->width
= tmp_win
->frame_g
.width
;
1949 if (!XGetGeometry(dpy
, (Drawable
) ResizeWindow
, &JunkRoot
,
1950 &drag
->x
, &drag
->y
, (unsigned int *)&drag
->width
,
1951 (unsigned int *)&drag
->height
, &JunkBW
,&JunkDepth
))
1953 UngrabEm(GRAB_NORMAL
);
1960 orig
->width
= drag
->width
;
1961 orig
->height
= drag
->height
;
1962 start_g
.x
= drag
->x
;
1963 start_g
.y
= drag
->y
;
1964 start_g
.width
= drag
->width
;
1965 start_g
.height
= drag
->height
;
1968 /* pop up a resize dimensions window */
1969 if (!Scr
.gs
.do_hide_resize_window
)
1970 XMapRaised(dpy
, Scr
.SizeWindow
);
1971 DisplaySize(tmp_win
, orig
->width
, orig
->height
,True
,True
);
1973 if((PressedW
!= Scr
.Root
)&&(PressedW
!= None
))
1975 /* Get the current position to determine which border to resize */
1976 if(PressedW
== tmp_win
->sides
[0]) /* top */
1978 else if(PressedW
== tmp_win
->sides
[1]) /* right */
1980 else if(PressedW
== tmp_win
->sides
[2]) /* bottom */
1982 else if(PressedW
== tmp_win
->sides
[3]) /* left */
1984 else if(PressedW
== tmp_win
->corners
[0]) /* upper-left */
1989 else if(PressedW
== tmp_win
->corners
[1]) /* upper-right */
1994 else if(PressedW
== tmp_win
->corners
[2]) /* lower left */
1999 else if(PressedW
== tmp_win
->corners
[3]) /* lower right */
2006 /* begin of code responsible for warping the pointer to the border when
2007 * starting a resize. */
2008 if (tmp_win
->title_w
!= None
&& PressedW
== tmp_win
->title_w
)
2010 /* title was pressed to thart the resize */
2011 called_from_title
= True
;
2015 for (i
= NUMBER_OF_BUTTONS
; i
--; )
2017 /* see if the title button was pressed to that the resize */
2018 if (tmp_win
->button_w
[i
] != None
&& PressedW
== tmp_win
->button_w
[i
])
2021 called_from_title
= True
;
2025 /* don't warp if the resize was triggered by a press somwhere on the title
2027 if(PressedW
!= Scr
.Root
&& xmotion
== 0 && ymotion
== 0 &&
2030 int dx
= orig
->width
- px
;
2031 int dy
= orig
->height
- py
;
2037 /* Now find the place to warp to. We simply use the sectors drawn when we
2038 * start resizing the window. */
2040 tx
= orig
->width
/ 10 - 1;
2041 ty
= orig
->height
/ 10 - 1;
2046 tx
= max(tmp_win
->boundary_width
, tx
);
2047 ty
= max(tmp_win
->boundary_width
, ty
);
2048 if (px
>= 0 && dx
>= 0 && py
>= 0 && dy
>= 0)
2064 wy
= orig
->height
-1;
2070 wy
= orig
->height
/2;
2080 wx
= orig
->width
- 1;
2087 wx
= orig
->width
- 1;
2088 wy
= orig
->height
-1;
2093 wx
= orig
->width
- 1;
2094 wy
= orig
->height
/2;
2111 wy
= orig
->height
-1;
2119 /* now warp the pointer to the border */
2120 XWarpPointer(dpy
, None
, ResizeWindow
, 0, 0, 1, 1, wx
, wy
);
2124 /* end of code responsible for warping the pointer to the border when
2125 * starting a resize. */
2127 /* draw the rubber-band window */
2128 if (!do_resize_opaque
)
2129 MoveOutline(drag
->x
, drag
->y
, drag
->width
- 1, drag
->height
- 1);
2130 /* kick off resizing without requiring any motion if invoked with a key
2132 if (eventp
->type
== KeyPress
)
2134 XQueryPointer(dpy
, Scr
.Root
, &JunkRoot
, &JunkChild
,
2135 &stashed_x
,&stashed_y
,&JunkX
, &JunkY
, &JunkMask
);
2136 DoResize(stashed_x
, stashed_y
, tmp_win
, drag
, orig
, &xmotion
, &ymotion
,
2140 stashed_x
= stashed_y
= -1;
2142 /* loop to resize */
2143 while(!finished
&& bad_window
!= tmp_win
->w
)
2145 /* block until there is an interesting event */
2146 while (!XCheckMaskEvent(dpy
, ButtonPressMask
| ButtonReleaseMask
|
2147 KeyPressMask
| PointerMotionMask
|
2148 ButtonMotionMask
| ExposureMask
, &Event
))
2150 if (HandlePaging(Scr
.EdgeScrollX
, Scr
.EdgeScrollY
, &x
, &y
,
2151 &delta_x
, &delta_y
, False
, False
, True
))
2153 /* Fake an event to force window reposition */
2154 Event
.type
= MotionNotify
;
2155 Event
.xmotion
.time
= lastTimestamp
;
2156 fForceRedraw
= True
;
2160 StashEventTime(&Event
);
2162 if (Event
.type
== MotionNotify
)
2163 /* discard any extra motion events before a release */
2164 while(XCheckMaskEvent(dpy
, ButtonMotionMask
| PointerMotionMask
|
2165 ButtonReleaseMask
| ButtonPressMask
, &Event
))
2167 StashEventTime(&Event
);
2168 if (Event
.type
== ButtonRelease
|| Event
.type
== ButtonPress
)
2173 /* Handle a limited number of key press events to allow mouseless
2175 if(Event
.type
== KeyPress
)
2176 Keyboard_shortcuts(&Event
, tmp_win
, ButtonRelease
);
2180 XAllowEvents(dpy
,ReplayPointer
,CurrentTime
);
2182 if (Event
.xbutton
.button
<= NUMBER_OF_MOUSE_BUTTONS
&&
2183 ((Button1Mask
<< (Event
.xbutton
.button
- 1)) & button_mask
))
2185 /* No new button was pressed, just a delayed event */
2188 /* Abort the resize if
2189 * - the move started with a pressed button and another button
2190 * was pressed during the operation
2191 * - no button was started at the beginning and any button
2192 * except button 1 was pressed. */
2193 if (button_mask
|| (Event
.xbutton
.button
!= 1))
2194 fButtonAbort
= True
;
2196 /* simple code to bag out of move - CKH */
2197 if (XLookupKeysym(&(Event
.xkey
),0) == XK_Escape
|| fButtonAbort
)
2201 /* return pointer if aborted resize was invoked with key */
2204 XWarpPointer(dpy
, None
, Scr
.Root
, 0, 0, 0, 0, stashed_x
,
2207 if (do_resize_opaque
)
2210 start_g
.x
, start_g
.y
, tmp_win
, &start_g
, orig
, &xmotion
, &ymotion
,
2212 DrawDecorations(tmp_win
, DRAW_ALL
, True
, True
, None
);
2226 x
= Event
.xmotion
.x_root
;
2227 y
= Event
.xmotion
.y_root
;
2228 /* resize before paging request to prevent resize from lagging
2231 x
, y
, tmp_win
, drag
, orig
, &xmotion
, &ymotion
, do_resize_opaque
);
2232 /* need to move the viewport */
2233 HandlePaging(Scr
.EdgeScrollX
, Scr
.EdgeScrollY
, &x
, &y
,
2234 &delta_x
, &delta_y
, False
, False
, False
);
2236 /* redraw outline if we paged - mab */
2237 if (delta_x
!= 0 || delta_y
!= 0)
2245 x
, y
, tmp_win
, drag
, orig
, &xmotion
, &ymotion
, do_resize_opaque
);
2247 fForceRedraw
= False
;
2254 if (!do_resize_opaque
)
2255 /* must undraw the rubber band in case the event causes some drawing */
2256 MoveOutline(0,0,0,0);
2257 DispatchEvent(False
);
2258 if (!do_resize_opaque
)
2259 MoveOutline(drag
->x
, drag
->y
, drag
->width
- 1, drag
->height
- 1);
2263 if (do_resize_opaque
)
2265 /* only do this with opaque resizes, (i.e. the server is not grabbed)
2267 BroadcastConfig(M_CONFIGURE_WINDOW
, tmp_win
);
2268 FlushAllMessageQueues();
2273 /* erase the rubber-band */
2274 if (!do_resize_opaque
)
2275 MoveOutline(0, 0, 0, 0);
2277 /* pop down the size window */
2278 if (!Scr
.gs
.do_hide_resize_window
)
2279 XUnmapWindow(dpy
, Scr
.SizeWindow
);
2281 if(!abort
&& bad_window
!= tmp_win
->w
)
2283 /* size will be >= to requested */
2285 tmp_win
, (unsigned int *)&drag
->width
, (unsigned int *)&drag
->height
,
2286 xmotion
, ymotion
, True
);
2287 if (IS_SHADED(tmp_win
))
2289 if (HAS_BOTTOM_TITLE(tmp_win
))
2291 SetupFrame(tmp_win
, drag
->x
, tmp_win
->frame_g
.y
,
2292 drag
->width
, tmp_win
->frame_g
.height
, False
);
2296 SetupFrame(tmp_win
, drag
->x
, drag
->y
,
2297 drag
->width
, tmp_win
->frame_g
.height
, False
);
2299 tmp_win
->normal_g
.height
= drag
->height
;
2304 tmp_win
, drag
->x
, drag
->y
, drag
->width
, drag
->height
, False
);
2307 if (abort
&& was_maximized
)
2309 /* since we aborted the resize, the window is still maximized */
2310 SET_MAXIMIZED(tmp_win
, 1);
2313 tmp_win
, DRAW_BUTTONS
, (tmp_win
== Scr
.Hilite
), True
, None
);
2316 if (bad_window
== tmp_win
->w
)
2318 XUnmapWindow(dpy
, tmp_win
->frame
);
2322 if (Scr
.bo
.InstallRootCmap
)
2323 UninstallRootColormap();
2325 UninstallFvwmColormap();
2326 ResizeWindow
= None
;
2327 if (!do_resize_opaque
)
2330 /* Throw away some events that dont interest us right now. */
2331 while (XCheckMaskEvent(dpy
, EnterWindowMask
|LeaveWindowMask
,
2334 Scr
.flags
.is_wire_frame_displayed
= False
;
2335 MyXUngrabServer(dpy
);
2339 WaitForButtonsUp(True
);
2340 UngrabEm(GRAB_NORMAL
);
2341 Scr
.flags
.edge_wrap_x
= edge_wrap_x
;
2342 Scr
.flags
.edge_wrap_y
= edge_wrap_y
;
2343 update_absolute_geometry(tmp_win
);
2344 maximize_adjust_offset(tmp_win
);
2345 GNOME_SetWinArea(tmp_win
);
2352 /***********************************************************************
2355 * DoResize - move the rubberband around. This is called for
2356 * each motion event when we are resizing
2359 * x_root - the X corrdinate in the root window
2360 * y_root - the Y corrdinate in the root window
2361 * tmp_win - the current fvwm window
2362 * drag - resize internal structure
2363 * orig - resize internal structure
2364 * xmotionp - pointer to xmotion in resize_window
2365 * ymotionp - pointer to ymotion in resize_window
2367 ************************************************************************/
2368 static void DoResize(
2369 int x_root
, int y_root
, FvwmWindow
*tmp_win
, rectangle
*drag
,
2370 rectangle
*orig
, int *xmotionp
, int *ymotionp
, Bool do_resize_opaque
)
2374 if ((y_root
<= orig
->y
) ||
2375 ((*ymotionp
== 1)&&(y_root
< orig
->y
+orig
->height
-1)))
2378 drag
->height
= orig
->y
+ orig
->height
- y_root
;
2382 else if ((y_root
>= orig
->y
+ orig
->height
- 1)||
2383 ((*ymotionp
== -1)&&(y_root
> orig
->y
)))
2386 drag
->height
= 1 + y_root
- drag
->y
;
2391 if ((x_root
<= orig
->x
)||
2392 ((*xmotionp
== 1)&&(x_root
< orig
->x
+ orig
->width
- 1)))
2395 drag
->width
= orig
->x
+ orig
->width
- x_root
;
2399 if ((x_root
>= orig
->x
+ orig
->width
- 1)||
2400 ((*xmotionp
== -1)&&(x_root
> orig
->x
)))
2403 drag
->width
= 1 + x_root
- orig
->x
;
2410 /* round up to nearest OK size to keep pointer inside rubberband */
2412 tmp_win
, (unsigned int *)&drag
->width
, (unsigned int *)&drag
->height
,
2413 *xmotionp
, *ymotionp
, True
);
2415 drag
->x
= orig
->x
+ orig
->width
- drag
->width
;
2417 drag
->y
= orig
->y
+ orig
->height
- drag
->height
;
2419 if(!do_resize_opaque
)
2421 MoveOutline(drag
->x
, drag
->y
, drag
->width
- 1, drag
->height
- 1);
2426 tmp_win
, drag
->x
, drag
->y
, drag
->width
, drag
->height
, False
);
2429 DisplaySize(tmp_win
, drag
->width
, drag
->height
,False
,False
);
2434 /***********************************************************************
2437 * DisplaySize - display the size in the dimensions window
2440 * tmp_win - the current fvwm window
2441 * width - the width of the rubber band
2442 * height - the height of the rubber band
2444 ***********************************************************************/
2445 static void DisplaySize(FvwmWindow
*tmp_win
, int width
, int height
, Bool Init
,
2449 int dwidth
,dheight
,offset
;
2450 static int last_width
= 0;
2451 static int last_height
= 0;
2453 if (Scr
.gs
.do_hide_resize_window
)
2460 if (last_width
== width
&& last_height
== height
)
2464 last_height
= height
;
2466 dheight
= height
- tmp_win
->title_g
.height
- 2*tmp_win
->boundary_width
;
2467 dwidth
= width
- 2*tmp_win
->boundary_width
;
2469 dwidth
-= tmp_win
->hints
.base_width
;
2470 dheight
-= tmp_win
->hints
.base_height
;
2471 dwidth
/= tmp_win
->hints
.width_inc
;
2472 dheight
/= tmp_win
->hints
.height_inc
;
2474 (void) sprintf (str
, " %4d x %-4d ", dwidth
, dheight
);
2477 XClearWindow(dpy
,Scr
.SizeWindow
);
2481 /* just clear indside the relief lines to reduce flicker */
2482 XClearArea(dpy
,Scr
.SizeWindow
,2,2,
2483 Scr
.SizeStringWidth
+ SIZE_HINDENT
*2 - 3,
2484 Scr
.DefaultFont
.height
+ SIZE_VINDENT
*2 - 3,False
);
2488 RelieveRectangle(dpy
,Scr
.SizeWindow
,0,0,
2489 Scr
.SizeStringWidth
+ SIZE_HINDENT
*2 - 1,
2490 Scr
.DefaultFont
.height
+ SIZE_VINDENT
*2 - 1,
2492 Scr
.StdShadowGC
, 2);
2493 offset
= (Scr
.SizeStringWidth
+ SIZE_HINDENT
*2
2494 - XTextWidth(Scr
.DefaultFont
.font
,str
,strlen(str
)))/2;
2496 XmbDrawString (dpy
, Scr
.SizeWindow
, Scr
.DefaultFont
.fontset
, Scr
.StdGC
,
2497 offset
, Scr
.DefaultFont
.font
->ascent
+ SIZE_VINDENT
, str
, 13);
2499 XDrawString (dpy
, Scr
.SizeWindow
, Scr
.StdGC
,
2500 offset
, Scr
.DefaultFont
.font
->ascent
+ SIZE_VINDENT
, str
, 13);
2505 /***********************************************************************
2508 * MoveOutline - move a window outline
2511 * root - the window we are outlining
2512 * x - upper left x coordinate
2513 * y - upper left y coordinate
2514 * width - the width of the rectangle
2515 * height - the height of the rectangle
2517 ***********************************************************************/
2518 void MoveOutline(int x
, int y
, int width
, int height
)
2520 static int lastx
= 0;
2521 static int lasty
= 0;
2522 static int lastWidth
= 0;
2523 static int lastHeight
= 0;
2526 XRectangle rects
[10];
2528 if (x
== lastx
&& y
== lasty
&& width
== lastWidth
&& height
== lastHeight
)
2531 /* figure out the ordering */
2532 if (width
|| height
)
2534 if (lastWidth
|| lastHeight
)
2536 offset
= interleave
>> 1;
2538 /* place the resize rectangle into the array of rectangles */
2539 /* interleave them for best visual look */
2540 /* draw the new one, if any */
2541 if (width
|| height
)
2544 for (i
=0; i
< 4; i
++)
2546 rects
[i
* interleave
].x
= x
+ i
;
2547 rects
[i
* interleave
].y
= y
+ i
;
2548 rects
[i
* interleave
].width
= width
- (i
<< 1);
2549 rects
[i
* interleave
].height
= height
- (i
<< 1);
2551 rects
[3 * interleave
].y
= y
+3 + (height
-6)/3;
2552 rects
[3 * interleave
].height
= (height
-6)/3;
2553 rects
[4 * interleave
].x
= x
+3 + (width
-6)/3;
2554 rects
[4 * interleave
].y
= y
+3;
2555 rects
[4 * interleave
].width
= (width
-6)/3;
2556 rects
[4 * interleave
].height
= (height
-6);
2559 /* undraw the old one, if any */
2560 if (lastWidth
|| lastHeight
)
2563 for (i
=0; i
< 4; i
++)
2565 rects
[i
* interleave
+ offset
].x
= lastx
+ i
;
2566 rects
[i
* interleave
+ offset
].y
= lasty
+ i
;
2567 rects
[i
* interleave
+ offset
].width
= lastWidth
- (i
<< 1);
2568 rects
[i
* interleave
+ offset
].height
= lastHeight
- (i
<< 1);
2570 rects
[3 * interleave
+ offset
].y
= lasty
+3 + (lastHeight
-6)/3;
2571 rects
[3 * interleave
+ offset
].height
= (lastHeight
-6)/3;
2572 rects
[4 * interleave
+ offset
].x
= lastx
+3 + (lastWidth
-6)/3;
2573 rects
[4 * interleave
+ offset
].y
= lasty
+3;
2574 rects
[4 * interleave
+ offset
].width
= (lastWidth
-6)/3;
2575 rects
[4 * interleave
+ offset
].height
= (lastHeight
-6);
2578 XDrawRectangles(dpy
, Scr
.Root
, Scr
.XorGC
, rects
, interleave
* 5);
2583 lastHeight
= height
;
2589 /* ----------------------------- maximizing code --------------------------- */
2591 static void move_sticky_window_to_same_page(
2592 int *x11
, int *x12
, int *y11
, int *y12
, int x21
, int x22
, int y21
, int y22
)
2594 /* make sure the x coordinate is on the same page as the reference window */
2599 *x11
-= Scr
.MyDisplayWidth
;
2600 *x12
-= Scr
.MyDisplayWidth
;
2603 else if (*x12
<= x21
)
2607 *x11
+= Scr
.MyDisplayWidth
;
2608 *x12
+= Scr
.MyDisplayWidth
;
2611 /* make sure the y coordinate is on the same page as the reference window */
2616 *y11
-= Scr
.MyDisplayHeight
;
2617 *y12
-= Scr
.MyDisplayHeight
;
2620 else if (*y12
<= y21
)
2624 *y11
+= Scr
.MyDisplayHeight
;
2625 *y12
+= Scr
.MyDisplayHeight
;
2630 static void MaximizeHeight(
2631 FvwmWindow
*win
, unsigned int win_width
, int win_x
, unsigned int *win_height
,
2632 int *win_y
, Bool grow_up
, Bool grow_down
)
2635 int x11
, x12
, x21
, x22
;
2636 int y11
, y12
, y21
, y22
;
2640 x11
= win_x
; /* Start x */
2641 y11
= *win_y
; /* Start y */
2642 x12
= x11
+ win_width
; /* End x */
2643 y12
= y11
+ *win_height
; /* End y */
2644 new_y1
= truncate_to_multiple(y11
, Scr
.MyDisplayHeight
);
2645 new_y2
= new_y1
+ Scr
.MyDisplayHeight
;
2647 for (cwin
= Scr
.FvwmRoot
.next
; cwin
; cwin
= cwin
->next
)
2649 if (IS_STICKY(cwin
) || (IS_ICONIFIED(cwin
) && IS_ICON_STICKY(cwin
)))
2653 if (cwin
== win
|| (cwin
->Desk
!= win
->Desk
&& !is_sticky
))
2655 if (IS_ICONIFIED(cwin
))
2657 if(cwin
->icon_w
== None
|| IS_ICON_UNMAPPED(cwin
))
2659 x21
= cwin
->icon_g
.x
;
2660 y21
= cwin
->icon_g
.y
;
2661 x22
= x21
+ cwin
->icon_p_width
;
2662 y22
= y21
+ cwin
->icon_p_height
+ cwin
->icon_g
.height
;
2666 x21
= cwin
->frame_g
.x
;
2667 y21
= cwin
->frame_g
.y
;
2668 x22
= x21
+ cwin
->frame_g
.width
;
2669 y22
= y21
+ cwin
->frame_g
.height
;
2673 move_sticky_window_to_same_page(
2674 &x21
, &x22
, &new_y1
, &new_y2
, x11
, x12
, y11
, y12
);
2677 /* Are they in the same X space? */
2678 if (!((x22
<= x11
) || (x21
>= x12
)))
2680 if ((y22
<= y11
) && (y22
>= new_y1
))
2684 else if ((y12
<= y21
) && (new_y2
>= y21
))
2694 *win_height
= new_y2
- new_y1
;
2698 static void MaximizeWidth(
2699 FvwmWindow
*win
, unsigned int *win_width
, int *win_x
, unsigned int win_height
,
2700 int win_y
, Bool grow_left
, Bool grow_right
)
2703 int x11
, x12
, x21
, x22
;
2704 int y11
, y12
, y21
, y22
;
2708 x11
= *win_x
; /* Start x */
2709 y11
= win_y
; /* Start y */
2710 x12
= x11
+ *win_width
; /* End x */
2711 y12
= y11
+ win_height
; /* End y */
2712 new_x1
= truncate_to_multiple(x11
, Scr
.MyDisplayWidth
);
2713 new_x2
= new_x1
+ Scr
.MyDisplayWidth
;
2715 for (cwin
= Scr
.FvwmRoot
.next
; cwin
; cwin
= cwin
->next
)
2717 if (IS_STICKY(cwin
) || (IS_ICONIFIED(cwin
) && IS_ICON_STICKY(cwin
)))
2721 if (cwin
== win
|| (cwin
->Desk
!= win
->Desk
&& !is_sticky
))
2723 if (IS_ICONIFIED(cwin
))
2725 if(cwin
->icon_w
== None
|| IS_ICON_UNMAPPED(cwin
))
2727 x21
= cwin
->icon_g
.x
;
2728 y21
= cwin
->icon_g
.y
;
2729 x22
= x21
+ cwin
->icon_p_width
;
2730 y22
= y21
+ cwin
->icon_p_height
+ cwin
->icon_g
.height
;
2734 x21
= cwin
->frame_g
.x
;
2735 y21
= cwin
->frame_g
.y
;
2736 x22
= x21
+ cwin
->frame_g
.width
;
2737 y22
= y21
+ cwin
->frame_g
.height
;
2741 move_sticky_window_to_same_page(
2742 &new_x1
, &new_x2
, &y21
, &y22
, x11
, x12
, y11
, y12
);
2745 /* Are they in the same Y space? */
2746 if (!((y22
<= y11
) || (y21
>= y12
)))
2748 if ((x22
<= x11
) && (x22
>= new_x1
))
2752 else if ((x12
<= x21
) && (new_x2
>= x21
))
2762 *win_width
= new_x2
- new_x1
;
2766 /***********************************************************************
2769 * (Un)Maximize a window.
2771 ***********************************************************************/
2772 void Maximize(F_CMD_ARGS
)
2775 int val1
, val2
, val1_unit
, val2_unit
;
2779 Bool grow_up
= False
;
2780 Bool grow_down
= False
;
2781 Bool grow_left
= False
;
2782 Bool grow_right
= False
;
2783 Bool do_force_maximize
= False
;
2786 if (DeferExecution(eventp
,&w
,&tmp_win
,&context
, CRS_SELECT
,ButtonRelease
))
2788 if (tmp_win
== NULL
|| IS_ICONIFIED(tmp_win
))
2791 if (check_if_function_allowed(F_MAXIMIZE
,tmp_win
,True
,NULL
) == 0)
2796 toggle
= ParseToggleArgument(action
, &action
, -1, 0);
2797 if (toggle
== 0 && !IS_MAXIMIZED(tmp_win
))
2800 if (toggle
== 1 && IS_MAXIMIZED(tmp_win
))
2802 /* Fake that the window is not maximized. */
2803 do_force_maximize
= True
;
2806 /* parse first parameter */
2807 val1_unit
= Scr
.MyDisplayWidth
;
2808 token
= PeekToken(action
, &taction
);
2809 if (token
&& StrEquals(token
, "grow"))
2814 val1_unit
= Scr
.MyDisplayWidth
;
2816 else if (token
&& StrEquals(token
, "growleft"))
2820 val1_unit
= Scr
.MyDisplayWidth
;
2822 else if (token
&& StrEquals(token
, "growright"))
2826 val1_unit
= Scr
.MyDisplayWidth
;
2830 if (GetOnePercentArgument(token
, &val1
, &val1_unit
) == 0)
2833 val1_unit
= Scr
.MyDisplayWidth
;
2837 /* handle negative offsets */
2838 if (val1_unit
== Scr
.MyDisplayWidth
)
2844 val1
= Scr
.MyDisplayWidth
+ val1
;
2849 /* parse second parameter */
2850 val2_unit
= Scr
.MyDisplayHeight
;
2851 token
= PeekToken(taction
, NULL
);
2852 if (token
&& StrEquals(token
, "grow"))
2857 val2_unit
= Scr
.MyDisplayHeight
;
2859 else if (token
&& StrEquals(token
, "growup"))
2863 val2_unit
= Scr
.MyDisplayHeight
;
2865 else if (token
&& StrEquals(token
, "growdown"))
2869 val2_unit
= Scr
.MyDisplayHeight
;
2873 if (GetOnePercentArgument(token
, &val2
, &val2_unit
) == 0)
2876 val2_unit
= Scr
.MyDisplayHeight
;
2880 /* handle negative offsets */
2881 if (val2_unit
== Scr
.MyDisplayHeight
)
2887 val2
= Scr
.MyDisplayHeight
+ val2
;
2892 if (IS_MAXIMIZED(tmp_win
) && !do_force_maximize
)
2894 SET_MAXIMIZED(tmp_win
, 0);
2895 get_relative_geometry(&tmp_win
->frame_g
, &tmp_win
->normal_g
);
2896 if (IS_SHADED(tmp_win
))
2897 get_shaded_geometry(tmp_win
, &tmp_win
->frame_g
, &tmp_win
->frame_g
);
2899 tmp_win
, tmp_win
->frame_g
.x
, tmp_win
->frame_g
.y
, tmp_win
->frame_g
.width
,
2900 tmp_win
->frame_g
.height
, True
);
2901 DrawDecorations(tmp_win
, DRAW_ALL
, True
, True
, None
);
2905 /* find the new page and geometry */
2906 new_g
.x
= tmp_win
->frame_g
.x
;
2907 new_g
.y
= tmp_win
->frame_g
.y
;
2908 new_g
.width
= tmp_win
->frame_g
.width
;
2909 new_g
.height
= tmp_win
->frame_g
.height
;
2910 if (IsRectangleOnThisPage(&tmp_win
->frame_g
, tmp_win
->Desk
))
2912 /* maximize on visible page */
2918 /* maximize on the page where the center of the window is */
2919 page_x
= truncate_to_multiple(
2920 tmp_win
->frame_g
.x
+ tmp_win
->frame_g
.width
/ 2,
2921 Scr
.MyDisplayWidth
);
2922 page_y
= truncate_to_multiple(
2923 tmp_win
->frame_g
.y
+ tmp_win
->frame_g
.height
/ 2,
2924 Scr
.MyDisplayHeight
);
2927 /* handle command line arguments */
2928 if (grow_up
|| grow_down
)
2931 tmp_win
, new_g
.width
, new_g
.x
, (unsigned int *)&new_g
.height
,
2932 &new_g
.y
, grow_up
, grow_down
);
2936 new_g
.height
= val2
* val2_unit
/ 100;
2939 if (grow_left
|| grow_right
)
2942 tmp_win
, (unsigned int *)&new_g
.width
, &new_g
.x
, new_g
.height
,
2943 new_g
.y
, grow_left
, grow_right
);
2947 new_g
.width
= val1
* val1_unit
/ 100;
2950 if(val1
== 0 && val2
== 0)
2954 new_g
.height
= Scr
.MyDisplayHeight
;
2955 new_g
.width
= Scr
.MyDisplayWidth
;
2957 /* now maximize it */
2958 SET_MAXIMIZED(tmp_win
, 1);
2959 constrain_size(tmp_win
, (unsigned int *)&new_g
.width
,
2960 (unsigned int *)&new_g
.height
, 0, 0, False
);
2961 tmp_win
->max_g
= new_g
;
2962 if (IS_SHADED(tmp_win
))
2963 get_shaded_geometry(tmp_win
, &new_g
, &tmp_win
->max_g
);
2965 tmp_win
, new_g
.x
, new_g
.y
, new_g
.width
, new_g
.height
, True
);
2966 DrawDecorations(tmp_win
, DRAW_ALL
, (Scr
.Hilite
== tmp_win
), True
, None
);
2967 /* remember the offset between old and new position in case the maximized
2968 * window is moved more than the screen width/height. */
2969 if (!do_force_maximize
)
2971 update_absolute_geometry(tmp_win
);
2973 tmp_win
->max_offset
.x
= tmp_win
->normal_g
.x
- tmp_win
->max_g
.x
;
2974 tmp_win
->max_offset
.y
= tmp_win
->normal_g
.y
- tmp_win
->max_g
.y
;
2976 fprintf(stderr
,"%d %d %d %d, max_offset.x = %d, max_offset.y = %d\n", tmp_win
->max_g
.x
, tmp_win
->max_g
.y
, tmp_win
->max_g
.width
, tmp_win
->max_g
.height
, tmp_win
->max_offset
.x
, tmp_win
->max_offset
.y
);
2979 GNOME_SetWinArea(tmp_win
);
2982 /* ----------------------------- stick code -------------------------------- */
2984 void handle_stick(F_CMD_ARGS
, int toggle
)
2986 if ((toggle
== 1 && IS_STICKY(tmp_win
)) ||
2987 (toggle
== 0 && !IS_STICKY(tmp_win
)))
2990 if(IS_STICKY(tmp_win
))
2992 SET_STICKY(tmp_win
, 0);
2993 tmp_win
->Desk
= Scr
.CurrentDesk
;
2994 GNOME_SetDeskCount();
2995 GNOME_SetDesk(tmp_win
);
2999 if (tmp_win
->Desk
!= Scr
.CurrentDesk
)
3000 do_move_window_to_desk(tmp_win
, Scr
.CurrentDesk
);
3001 SET_STICKY(tmp_win
, 1);
3002 if (!IsRectangleOnThisPage(&tmp_win
->frame_g
, Scr
.CurrentDesk
))
3005 move_window_doit(F_PASS_ARGS
, FALSE
, TRUE
);
3006 /* move_window_doit resets the STICKY flag, so we must set it after the
3008 SET_STICKY(tmp_win
, 1);
3011 BroadcastConfig(M_CONFIGURE_WINDOW
,tmp_win
);
3012 DrawDecorations(tmp_win
, DRAW_TITLE
, (Scr
.Hilite
==tmp_win
), True
, None
);
3013 GNOME_SetHints(tmp_win
);
3016 void stick_function(F_CMD_ARGS
)
3020 if (DeferExecution(eventp
,&w
,&tmp_win
,&context
,CRS_SELECT
,ButtonRelease
))
3023 toggle
= ParseToggleArgument(action
, &action
, -1, 0);
3025 handle_stick(F_PASS_ARGS
, toggle
);