/* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*****************************************************************************
* This module is all original code
* by Rob Nation
* Copyright 1993, Robert Nation
* You may use this code for any purpose, as long as the original
* copyright remains in the source code and all documentation
****************************************************************************/
/************************************************************************
*
* code for moving and resizing windows
*
***********************************************************************/
#include "config.h"
#include <stdio.h>
#include "libs/fvwmlib.h"
#include "libs/Colorset.h"
#include "libs/FScreen.h"
#include "fvwm.h"
#include "externs.h"
#include "cursor.h"
#include "functions.h"
#include "bindings.h"
#include "misc.h"
#include "screen.h"
#include "defaults.h"
#include "move_resize.h"
#include "module_interface.h"
#include "focus.h"
#include "borders.h"
#include "geometry.h"
#include "gnome.h"
#include "colormaps.h"
#include "virtual.h"
#include "decorations.h"
#include "events.h"
#include <X11/keysym.h>
/* ----- move globals ----- */
extern XEvent Event;
#define SNAP_NONE 0x00
#define SNAP_WINDOWS 0x01
#define SNAP_ICONS 0x02
#define SNAP_SAME 0x04
#define SNAP_SCREEN 0x08
#define MOVE_NORMAL 0x00
#define MOVE_PAGE 0x01
#define MOVE_SCREEN 0x02
/* Animated move stuff added by Greg J. Badros, gjb@cs.washington.edu */
float rgpctMovementDefault[32] =
{
-.01, 0, .01, .03,.08,.18,.3,.45,.60,.75,.85,.90,.94,.97,.99,1.0
/* must end in 1.0 */
};
int cmsDelayDefault = 10; /* milliseconds */
/* current geometry of size window */
static rectangle sizew_g =
{
-1,
-1,
-1,
-1
};
/* ----- end of move globals ----- */
/* ----- resize globals ----- */
/* DO NOT USE (STATIC) GLOBALS IN THIS MODULE!
* Since some functions are called from other modules unwanted side effects
* (i.e. bugs.) would be created */
extern Window PressedW;
static void DoResize(
int x_root, int y_root, FvwmWindow *tmp_win, rectangle *drag,
rectangle *orig, int *xmotionp, int *ymotionp, Bool do_resize_opaque);
static void DisplaySize(
FvwmWindow *tmp_win, XEvent *eventp, int width, int height, Bool Init,
Bool resetLast);
static void draw_move_resize_grid(int x, int y, int width, int height);
/* ----- end of resize globals ----- */
/* The vars are named for the x-direction, but this is used for both x and y */
static int GetOnePositionArgument(
char *s1,int x,int w,int *pFinalX,float factor, int max, Bool is_x)
{
int val;
int cch = strlen(s1);
Bool add_pointer_position = False;
if (cch == 0)
return 0;
if (s1[cch-1] == 'p')
{
factor = 1; /* Use pixels, so don't multiply by factor */
s1[cch-1] = '\0';
}
if (strcmp(s1,"w") == 0)
{
*pFinalX = x;
}
else if (sscanf(s1,"w-%d",&val) == 1)
{
*pFinalX = x - (int)(val*factor);
}
else if (sscanf(s1,"w+%d",&val) == 1 || sscanf(s1,"w%d",&val) == 1 )
{
*pFinalX = x + (int)(val*factor);
}
else if (sscanf(s1,"m-%d",&val) == 1)
{
add_pointer_position = True;
*pFinalX = -(int)(val*factor);
}
else if (sscanf(s1,"m+%d",&val) == 1 || sscanf(s1,"m%d",&val) == 1 )
{
add_pointer_position = True;
*pFinalX = (int)(val*factor);
}
else if (sscanf(s1,"-%d",&val) == 1)
{
*pFinalX = max-w - (int)(val*factor);
}
else if (sscanf(s1,"%d",&val) == 1)
{
*pFinalX = (int)(val*factor);
}
else
{
return 0;
}
if (add_pointer_position)
{
int x = 0;
int y = 0;
XQueryPointer(
dpy, Scr.Root, &JunkRoot, &JunkChild, &JunkX, &JunkY, &x, &y, &JunkMask);
*pFinalX += (is_x) ? x : y;
}
return 1;
}
/* GetMoveArguments is used for Move & AnimatedMove
* It lets you specify in all the following ways
* 20 30 Absolute percent position, from left edge and top
* -50 50 Absolute percent position, from right edge and top
* 10p 5p Absolute pixel position
* 10p -0p Absolute pixel position, from bottom
* w+5 w-10p Relative position, right 5%, up ten pixels
* w+5 w-10p Pointer relative position, right 5%, up ten pixels
* Returns 2 when x & y have parsed without error, 0 otherwise
*/
static int GetMoveArguments(
char **paction, int w, int h, int *pFinalX, int *pFinalY,
Bool *fWarp, Bool *fPointer)
{
char *s1 = NULL;
char *s2 = NULL;
char *warp = NULL;
char *action;
char *naction;
int scrWidth = Scr.MyDisplayWidth;
int scrHeight = Scr.MyDisplayHeight;
int retval = 0;
if (!paction)
return 0;
action = *paction;
action = GetNextToken(action, &s1);
if (s1 && fPointer && StrEquals(s1, "pointer"))
{
*fPointer = True;
*paction = action;
free(s1);
return 0;
}
else
{
action = GetNextToken(action, &s2);
if (fWarp)
{
warp = PeekToken(action, &naction);
if (StrEquals(warp, "Warp"))
{
*fWarp = True;
action = naction;
}
}
}
if (s1 != NULL && s2 != NULL)
{
retval = 0;
if (StrEquals(s1, "keep"))
{
retval++;
}
else if (GetOnePositionArgument(
s1, *pFinalX, w, pFinalX, (float)scrWidth/100, scrWidth, True))
{
retval++;
}
if (StrEquals(s2, "keep"))
{
retval++;
}
else if (GetOnePositionArgument(
s2, *pFinalY, h, pFinalY, (float)scrHeight/100, scrHeight, False))
{
retval++;
}
if (retval == 0)
*fWarp = False; /* make sure warping is off for interactive moves */
}
else
{
/* not enough arguments, switch to current page. */
while (*pFinalX < 0)
{
*pFinalX = Scr.MyDisplayWidth + *pFinalX;
}
while (*pFinalY < 0)
{
*pFinalY = Scr.MyDisplayHeight + *pFinalY;
}
}
if (s1)
free(s1);
if (s2)
free(s2);
*paction = action;
return retval;
}
static int ParseOneResizeArgument(
char *arg, int scr_size, int base_size, int size_inc, int bw, int title_size,
int *ret_size)
{
int unit_table[3];
int value;
int suffix;
if (StrEquals(arg, "keep"))
{
/* do not change width */
}
else
{
if (GetSuffixedIntegerArguments(arg, NULL, &value, 1, "pc", &suffix) < 1)
{
return 0;
}
else
{
/* convert the value/suffix pairs to pixels */
unit_table[0] = scr_size;
unit_table[1] = 100;
unit_table[2] = 100 * size_inc;
*ret_size = SuffixToPercentValue(value, suffix, unit_table);
if (*ret_size < 0)
*ret_size += scr_size;
else
{
if (suffix == 2)
{
/* account for base width */
*ret_size += base_size;
}
*ret_size += title_size + 2 * bw;
}
}
}
return 1;
}
static int GetResizeArguments(
char **paction, int x, int y, int w_base, int h_base, int w_inc, int h_inc,
int bw, int h_title, int *pFinalW, int *pFinalH)
{
int n;
char *naction;
char *token;
char *s1;
char *s2;
if (!paction)
return 0;
token = PeekToken(*paction, &naction);
if (!token)
return 0;
if (StrEquals(token, "bottomright") || StrEquals(token, "br"))
{
int nx = x + *pFinalW - 1;
int ny = y + *pFinalH - 1;
n = GetMoveArguments(&naction, 0, 0, &nx, &ny, NULL, NULL);
if (n < 2)
return 0;
*pFinalW = nx - x + 1;
*pFinalH = ny - y + 1;
*paction = naction;
}
else
{
s1 = safestrdup(token);
naction = GetNextToken(naction, &s2);
if (!s2)
{
free(s1);
return 0;
}
*paction = naction;
n = 0;
n += ParseOneResizeArgument(
s1, Scr.MyDisplayWidth, w_base, w_inc, bw, 0, pFinalW);
n += ParseOneResizeArgument(
s2, Scr.MyDisplayHeight, h_base, h_inc, bw, h_title, pFinalH);
free(s1);
free(s2);
if (n < 2)
n = 0;
}
return n;
}
static int GetResizeMoveArguments(
char **paction, int w_base, int h_base, int w_inc, int h_inc, int bw,
int h_title, int *pFinalX, int *pFinalY, int *pFinalW, int *pFinalH,
Bool *fWarp, Bool *fPointer)
{
char *action = *paction;
if (!paction)
return 0;
if (GetResizeArguments(
&action, *pFinalX, *pFinalY, w_base, h_base, w_inc, h_inc, bw, h_title,
pFinalW, pFinalH) < 2)
{
return 0;
}
if (GetMoveArguments(
&action, *pFinalW, *pFinalH, pFinalX, pFinalY, fWarp, NULL) < 2)
{
return 0;
}
*paction = action;
return 4;
}
/* Positions the SizeWindow on the current ("moused") xinerama-screen */
static void position_geometry_window(XEvent *eventp)
{
int x;
int y;
fscreen_scr_arg fscr;
fscr.mouse_ev = eventp;
/* Probably should remove this positioning code from {builtins,fvwm}.c? */
if (Scr.gs.EmulateMWM)
{
FScreenCenterOnScreen(
&fscr, FSCREEN_CURRENT, &x, &y, sizew_g.width, sizew_g.height);
}
else
{
FScreenGetScrRect(&fscr, FSCREEN_CURRENT, &x, &y, NULL, NULL);
}
if (x != sizew_g.x || y != sizew_g.y)
{
switch_move_resize_grid(False);
XMoveWindow(dpy, Scr.SizeWindow, x, y);
switch_move_resize_grid(True);
sizew_g.x = x;
sizew_g.y = y;
}
return;
}
void resize_geometry_window(void)
{
int w;
int h;
int cset = Scr.DefaultColorset;
Scr.SizeStringWidth =
XTextWidth(Scr.DefaultFont.font, GEOMETRY_WINDOW_STRING,
sizeof(GEOMETRY_WINDOW_STRING) - 1);
w = Scr.SizeStringWidth + 2 * GEOMETRY_WINDOW_BW;
h = Scr.DefaultFont.height + 2 * GEOMETRY_WINDOW_BW;
if (w != sizew_g.width || h != sizew_g.height)
{
XResizeWindow(dpy, Scr.SizeWindow, w, h);
sizew_g.width = w;
sizew_g.height = h;
}
if (cset >= 0)
{
SetWindowBackground(
dpy, Scr.SizeWindow, w, h, &Colorset[cset], Pdepth, Scr.StdGC,
False);
}
else
{
XSetWindowBackground(dpy, Scr.SizeWindow, Scr.StdBack);
}
return;
}
/***********************************************************************
*
* Procedure:
* DisplayPosition - display the position in the dimensions window
*
* Inputs:
* tmp_win - the current fvwm window
* x, y - position of the window
*
************************************************************************/
static void DisplayPosition(
FvwmWindow *tmp_win, XEvent *eventp, int x, int y,int Init)
{
char str[100];
int offset;
fscreen_scr_arg fscr;
if (Scr.gs.do_hide_position_window)
return;
position_geometry_window(eventp);
/* Translate x,y into local screen coordinates, in case Xinerama is used. */
fscr.xypos.x = x;
fscr.xypos.y = y;
FScreenTranslateCoordinates(
NULL, FSCREEN_GLOBAL, &fscr, FSCREEN_XYPOS, &x, &y);
(void)sprintf(str, GEOMETRY_WINDOW_POS_STRING, x, y);
if (Init)
{
XClearWindow(dpy, Scr.SizeWindow);
}
else
{
/* just clear indside the relief lines to reduce flicker */
XClearArea(dpy,Scr.SizeWindow, GEOMETRY_WINDOW_BW, GEOMETRY_WINDOW_BW,
Scr.SizeStringWidth, Scr.DefaultFont.height, False);
}
if (Pdepth >= 2)
{
RelieveRectangle(
dpy, Scr.SizeWindow, 0, 0,
Scr.SizeStringWidth + GEOMETRY_WINDOW_BW * 2 - 1,
Scr.DefaultFont.height + GEOMETRY_WINDOW_BW * 2 - 1,
Scr.StdReliefGC, Scr.StdShadowGC, GEOMETRY_WINDOW_BW);
}
offset = (Scr.SizeStringWidth -
XTextWidth(Scr.DefaultFont.font, str, strlen(str))) / 2;
offset += GEOMETRY_WINDOW_BW;
#ifdef I18N_MB
XmbDrawString(dpy, Scr.SizeWindow, Scr.DefaultFont.fontset, Scr.StdGC,
offset,
Scr.DefaultFont.font->ascent + GEOMETRY_WINDOW_BW,
str, strlen(str));
#else
XDrawString(dpy, Scr.SizeWindow, Scr.StdGC,
offset,
Scr.DefaultFont.font->ascent + GEOMETRY_WINDOW_BW,
str, strlen(str));
#endif
}
/***********************************************************************
*
* Procedure:
* DisplaySize - display the size in the dimensions window
*
* Inputs:
* tmp_win - the current fvwm window
* width - the width of the rubber band
* height - the height of the rubber band
*
***********************************************************************/
static void DisplaySize(
FvwmWindow *tmp_win, XEvent *eventp, int width, int height, Bool Init,
Bool resetLast)
{
char str[100];
int dwidth,dheight,offset;
static int last_width = 0;
static int last_height = 0;
if (Scr.gs.do_hide_resize_window)
return;
position_geometry_window(eventp);
if (resetLast)
{
last_width = 0;
last_height = 0;
}
if (last_width == width && last_height == height)
return;
last_width = width;
last_height = height;
dheight = height - tmp_win->title_g.height - 2*tmp_win->boundary_width;
dwidth = width - 2*tmp_win->boundary_width;
dwidth -= tmp_win->hints.base_width;
dheight -= tmp_win->hints.base_height;
dwidth /= tmp_win->hints.width_inc;
dheight /= tmp_win->hints.height_inc;
(void) sprintf (str, GEOMETRY_WINDOW_SIZE_STRING, dwidth, dheight);
if (Init)
{
XClearWindow(dpy,Scr.SizeWindow);
}
else
{
/* just clear indside the relief lines to reduce flicker */
XClearArea(dpy, Scr.SizeWindow, GEOMETRY_WINDOW_BW, GEOMETRY_WINDOW_BW,
Scr.SizeStringWidth, Scr.DefaultFont.height, False);
}
if (Pdepth >= 2)
{
RelieveRectangle(
dpy, Scr.SizeWindow, 0, 0,
Scr.SizeStringWidth + GEOMETRY_WINDOW_BW * 2 - 1,
Scr.DefaultFont.height + GEOMETRY_WINDOW_BW*2 - 1,
Scr.StdReliefGC, Scr.StdShadowGC, GEOMETRY_WINDOW_BW);
}
offset = (Scr.SizeStringWidth -
XTextWidth(Scr.DefaultFont.font, str, strlen(str))) / 2;
offset += GEOMETRY_WINDOW_BW;
#ifdef I18N_MB
XmbDrawString(dpy, Scr.SizeWindow, Scr.DefaultFont.fontset, Scr.StdGC,
offset, Scr.DefaultFont.font->ascent + GEOMETRY_WINDOW_BW,
str, strlen(str));
#else
XDrawString(dpy, Scr.SizeWindow, Scr.StdGC,
offset, Scr.DefaultFont.font->ascent + GEOMETRY_WINDOW_BW,
str, strlen(str));
#endif
}
void CMD_ResizeMove(F_CMD_ARGS)
{
int FinalX = 0;
int FinalY = 0;
int FinalW = 0;
int FinalH = 0;
int n;
int x,y;
Bool fWarp = False;
Bool fPointer = False;
Bool has_focus;
int dx;
int dy;
if (DeferExecution(eventp,&w,&tmp_win,&context, CRS_RESIZE, ButtonPress))
return;
if (tmp_win == NULL)
return;
if (IS_FIXED(tmp_win))
return;
if (check_if_function_allowed(F_RESIZE,tmp_win,True,NULL) == 0)
{
XBell(dpy, 0);
return;
}
/* gotta have a window */
w = tmp_win->frame;
if (!XGetGeometry(dpy, w, &JunkRoot, &x, &y, (unsigned int *)&FinalW,
(unsigned int *)&FinalH, &JunkBW, &JunkDepth))
{
XBell(dpy, 0);
return;
}
FinalX = x;
FinalY = y;
n = GetResizeMoveArguments(
&action,
tmp_win->hints.base_width, tmp_win->hints.base_height,
tmp_win->hints.width_inc, tmp_win->hints.height_inc,
tmp_win->boundary_width, tmp_win->title_g.height,
&FinalX, &FinalY, &FinalW, &FinalH, &fWarp, &fPointer);
if (n < 4)
return;
if (IS_MAXIMIZED(tmp_win))
{
/* must redraw the buttons now so that the 'maximize' button does not stay
* depressed. */
SET_MAXIMIZED(tmp_win, 0);
DrawDecorations(
tmp_win, DRAW_BUTTONS, (tmp_win == Scr.Hilite), True, None);
}
dx = FinalX - tmp_win->frame_g.x;
dy = FinalY - tmp_win->frame_g.y;
/* size will be less or equal to requested */
constrain_size(tmp_win, (unsigned int *)&FinalW, (unsigned int *)&FinalH,
0, 0, 0);
if (IS_SHADED(tmp_win))
{
SetupFrame(tmp_win, FinalX, FinalY, FinalW, tmp_win->frame_g.height, False);
}
else
{
SetupFrame(tmp_win, FinalX, FinalY, FinalW, FinalH, True);
}
if (fWarp)
XWarpPointer(dpy, None, None, 0, 0, 0, 0, FinalX - x, FinalY - y);
if (IS_MAXIMIZED(tmp_win))
{
tmp_win->max_g.x += dx;
tmp_win->max_g.y += dy;
}
else
{
tmp_win->normal_g.x += dx;
tmp_win->normal_g.y += dy;
}
has_focus = (tmp_win == get_focus_window())? True : False;
DrawDecorations(tmp_win, DRAW_ALL, has_focus, True, None);
update_absolute_geometry(tmp_win);
maximize_adjust_offset(tmp_win);
XSync(dpy, 0);
GNOME_SetWinArea(tmp_win);
return;
}
static void InteractiveMove(
Window *win, FvwmWindow *tmp_win, int *FinalX, int *FinalY, XEvent *eventp,
Bool do_start_at_pointer)
{
int origDragX,origDragY,DragX, DragY, DragWidth, DragHeight;
int XOffset, YOffset;
Window w;
Bool do_move_opaque = False;
w = *win;
if (Scr.bo.InstallRootCmap)
InstallRootColormap();
else
InstallFvwmColormap();
/* warp the pointer to the cursor position from before menu appeared */
/* domivogt (17-May-1999): an XFlush should not hurt anyway, so do it
* unconditionally to remove the external */
XFlush(dpy);
if (do_start_at_pointer)
{
if (XQueryPointer(
dpy, Scr.Root, &JunkRoot, &JunkChild, &DragX, &DragY, &JunkX, &JunkY,
&JunkMask) == False)
{
/* pointer is on a different screen */
DragX = 0;
DragY = 0;
}
}
else
{
/* Although a move is usually done with a button depressed we have to check
* for ButtonRelease too since the event may be faked. */
GetLocationFromEventOrQuery(dpy, Scr.Root, &Event, &DragX, &DragY);
}
MyXGrabServer(dpy);
if (!XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
(unsigned int *)&DragWidth, (unsigned int *)&DragHeight,
&JunkBW, &JunkDepth))
{
MyXUngrabServer(dpy);
return;
}
MyXGrabKeyboard(dpy);
if (do_start_at_pointer)
{
origDragX = DragX;
origDragY = DragY;
}
if (IS_ICONIFIED(tmp_win))
do_move_opaque = True;
else if (IS_MAPPED(tmp_win))
{
float areapct;
areapct = 100.0;
areapct *= ((float)DragWidth / (float)Scr.MyDisplayWidth);
areapct *= ((float)DragHeight / (float)Scr.MyDisplayHeight);
/* round up */
areapct += 0.1;
if (Scr.OpaqueSize < 0 || (float)areapct <= (float)Scr.OpaqueSize)
{
do_move_opaque = True;
}
}
if (do_move_opaque)
{
MyXUngrabServer(dpy);
}
else
{
Scr.flags.is_wire_frame_displayed = True;
}
if (!do_move_opaque && IS_ICONIFIED(tmp_win))
XUnmapWindow(dpy,w);
XOffset = origDragX - DragX;
YOffset = origDragY - DragY;
if (!Scr.gs.do_hide_position_window)
{
position_geometry_window(NULL);
XMapRaised(dpy,Scr.SizeWindow);
}
moveLoop(tmp_win, XOffset,YOffset,DragWidth,DragHeight, FinalX,FinalY,
do_move_opaque);
if (!Scr.gs.do_hide_position_window)
{
XUnmapWindow(dpy,Scr.SizeWindow);
}
if (Scr.bo.InstallRootCmap)
UninstallRootColormap();
else
UninstallFvwmColormap();
if (!do_move_opaque)
{
/* Throw away some events that dont interest us right now. */
discard_events(EnterWindowMask|LeaveWindowMask);
Scr.flags.is_wire_frame_displayed = False;
MyXUngrabServer(dpy);
}
MyXUngrabKeyboard(dpy);
return;
}
/* Perform the movement of the window. ppctMovement *must* have a 1.0 entry
* somewhere in ins list of floats, and movement will stop when it hits a 1.0
* entry */
static void AnimatedMoveAnyWindow(
FvwmWindow *tmp_win, Window w, int startX, int startY, int endX, int endY,
Bool fWarpPointerToo, int cmsDelay, float *ppctMovement)
{
int pointerX, pointerY;
int currentX, currentY;
int lastX, lastY;
int deltaX, deltaY;
if (tmp_win && IS_FIXED(tmp_win))
return;
/* set our defaults */
if (ppctMovement == NULL)
ppctMovement = rgpctMovementDefault;
if (cmsDelay < 0)
cmsDelay = cmsDelayDefault;
if (startX < 0 || startY < 0)
{
if (!XGetGeometry(dpy, w, &JunkRoot, ¤tX, ¤tY,
&JunkWidth, &JunkHeight, &JunkBW, &JunkDepth))
{
XBell(dpy, 0);
return;
}
if (startX < 0)
startX = currentX;
if (startY < 0)
startY = currentY;
}
deltaX = endX - startX;
deltaY = endY - startY;
lastX = startX;
lastY = startY;
if (deltaX == 0 && deltaY == 0)
/* go nowhere fast */
return;
/* Needed for aborting */
MyXGrabKeyboard(dpy);
do
{
currentX = startX + deltaX * (*ppctMovement);
currentY = startY + deltaY * (*ppctMovement);
if (lastX == currentX && lastY == currentY)
/* don't waste time in the same spot */
continue;
XMoveWindow(dpy,w,currentX,currentY);
if (fWarpPointerToo == True)
{
if (XQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
&JunkX,&JunkY,&pointerX,&pointerY,&JunkMask) == False)
{
/* pointer is on a different screen */
pointerX = currentX;
pointerY = currentY;
}
else
{
pointerX += currentX - lastX;
pointerY += currentY - lastY;
}
XWarpPointer(dpy,None,Scr.Root,0,0,0,0, pointerX,pointerY);
}
if (tmp_win && !IS_SHADED(tmp_win) && !Scr.bo.DisableConfigureNotify)
{
/* send configure notify event for windows that care about their
* location */
SendConfigureNotify(
tmp_win, currentX, currentY, tmp_win->frame_g.width,
tmp_win->frame_g.height, 0, False);
#ifdef FVWM_DEBUG_MSGS
fvwm_msg(DBG,"AnimatedMoveAnyWindow",
"Sent ConfigureNotify (w == %d, h == %d)",
tmp_win->frame_g.width, tmp_win->frame_g.height);
#endif
}
XFlush(dpy);
if (tmp_win)
{
tmp_win->frame_g.x = currentX;
tmp_win->frame_g.y = currentY;
update_absolute_geometry(tmp_win);
maximize_adjust_offset(tmp_win);
BroadcastConfig(M_CONFIGURE_WINDOW, tmp_win);
FlushAllMessageQueues();
}
usleep(cmsDelay * 1000); /* usleep takes microseconds */
/* this didn't work for me -- maybe no longer necessary since
* we warn the user when they use > .5 seconds as a between-frame delay
* time.
*
* domivogt (28-apr-1999): That is because the keyboard was not grabbed.
* works nicely now.
*/
if (XCheckMaskEvent(dpy, ButtonPressMask|ButtonReleaseMask|KeyPressMask,
&Event))
{
StashEventTime(&Event);
/* finish the move immediately */
XMoveWindow(dpy,w,endX,endY);
break;
}
lastX = currentX;
lastY = currentY;
}
while
(*ppctMovement != 1.0 && ppctMovement++);
MyXUngrabKeyboard(dpy);
XFlush(dpy);
if (tmp_win)
GNOME_SetWinArea(tmp_win);
return;
}
/* used for moving menus, not a client window */
void AnimatedMoveOfWindow(Window w, int startX, int startY,
int endX, int endY, Bool fWarpPointerToo,
int cmsDelay, float *ppctMovement)
{
AnimatedMoveAnyWindow(NULL, w, startX, startY, endX, endY, fWarpPointerToo,
cmsDelay, ppctMovement);
}
/* used for moving client windows */
void AnimatedMoveFvwmWindow(FvwmWindow *tmp_win, Window w, int startX,
int startY, int endX, int endY,
Bool fWarpPointerToo, int cmsDelay,
float *ppctMovement)
{
AnimatedMoveAnyWindow(tmp_win, w, startX, startY, endX, endY,
fWarpPointerToo, cmsDelay, ppctMovement);
}
/****************************************************************************
*
* Start a window move operation
*
****************************************************************************/
static void move_window_doit(F_CMD_ARGS, Bool do_animate, int mode)
{
int FinalX = 0;
int FinalY = 0;
int n;
int x,y;
unsigned int width, height;
int page_x, page_y;
Bool fWarp = False;
Bool fPointer = False;
int dx;
int dy;
if (DeferExecution(
eventp,&w,&tmp_win,&context,
(mode == MOVE_NORMAL) ? CRS_MOVE : CRS_SELECT, ButtonPress))
{
return;
}
if (tmp_win == NULL)
return;
if (IS_FIXED(tmp_win))
return;
if (check_if_function_allowed(F_MOVE, tmp_win, True, NULL) == 0)
{
return;
}
/* gotta have a window */
w = tmp_win->frame;
if(IS_ICONIFIED(tmp_win))
{
if(tmp_win->icon_pixmap_w != None)
{
w = tmp_win->icon_pixmap_w;
XUnmapWindow(dpy,tmp_win->icon_w);
}
else
{
w = tmp_win->icon_w;
}
}
if (!XGetGeometry(dpy, w, &JunkRoot, &x, &y, &width, &height,
&JunkBW, &JunkDepth))
{
return;
}
if (mode == MOVE_PAGE)
{
rectangle r;
rectangle s;
do_animate = False;
SET_STICKY(tmp_win, 0);
if (!get_page_arguments(action, &page_x, &page_y))
{
page_x = Scr.Vx;
page_y = Scr.Vy;
}
r.x = x;
r.y = y;
r.width = width;
r.height = height;
s.x = page_x - Scr.Vx;
s.y = page_y - Scr.Vy;
s.width = Scr.MyDisplayWidth;
s.height = Scr.MyDisplayHeight;
move_into_rectangle(&r, &s);
FinalX = r.x;
FinalY = r.y;
}
else if (mode == MOVE_SCREEN)
{
rectangle r;
rectangle s;
rectangle p;
int fscreen;
do_animate = False;
SET_STICKY(tmp_win, 0);
fscreen = FScreenGetScreenArgument(action, FSCREEN_SPEC_CURRENT);
FScreenGetScrRect(NULL, fscreen, &s.x, &s.y, &s.width, &s.height);
page_x = Scr.Vx;
page_y = Scr.Vy;
r.x = x;
r.y = y;
r.width = width;
r.height = height;
p.x = page_x - Scr.Vx;
p.y = page_y - Scr.Vy;
p.width = Scr.MyDisplayWidth;
p.height = Scr.MyDisplayHeight;
/* move to page first */
move_into_rectangle(&r, &p);
/* then move to screen */
move_into_rectangle(&r, &s);
FinalX = r.x;
FinalY = r.y;
}
else
{
FinalX = x;
FinalY = y;
n = GetMoveArguments(
&action, width, height, &FinalX, &FinalY, &fWarp, &fPointer);
if (n != 2 || fPointer)
InteractiveMove(&w, tmp_win, &FinalX, &FinalY, eventp, fPointer);
else if (IS_ICONIFIED(tmp_win))
{
SET_ICON_MOVED(tmp_win, 1);
}
}
if (w == tmp_win->frame)
{
dx = FinalX - tmp_win->frame_g.x;
dy = FinalY - tmp_win->frame_g.y;
if (do_animate)
{
AnimatedMoveFvwmWindow(tmp_win,w,-1,-1,FinalX,FinalY,fWarp,-1,NULL);
}
SetupFrame(tmp_win, FinalX, FinalY,
tmp_win->frame_g.width, tmp_win->frame_g.height, True);
if (fWarp & !do_animate)
XWarpPointer(dpy, None, None, 0, 0, 0, 0, FinalX - x, FinalY - y);
if (IS_MAXIMIZED(tmp_win))
{
tmp_win->max_g.x += dx;
tmp_win->max_g.y += dy;
}
else
{
tmp_win->normal_g.x += dx;
tmp_win->normal_g.y += dy;
}
update_absolute_geometry(tmp_win);
maximize_adjust_offset(tmp_win);
XSync(dpy, 0);
GNOME_SetWinArea(tmp_win);
}
else /* icon window */
{
tmp_win->icon_g.x = FinalX;
tmp_win->icon_xl_loc = FinalX -
(tmp_win->icon_g.width - tmp_win->icon_p_width)/2;
tmp_win->icon_g.y = FinalY;
BroadcastPacket(M_ICON_LOCATION, 7,
tmp_win->w, tmp_win->frame,
(unsigned long)tmp_win,
tmp_win->icon_g.x, tmp_win->icon_g.y,
tmp_win->icon_p_width,
tmp_win->icon_g.height + tmp_win->icon_p_height);
if (do_animate)
{
AnimatedMoveOfWindow(tmp_win->icon_w,-1,-1,tmp_win->icon_xl_loc,
FinalY+tmp_win->icon_p_height, fWarp,-1,NULL);
}
else
{
XMoveWindow(dpy,tmp_win->icon_w, tmp_win->icon_xl_loc,
FinalY+tmp_win->icon_p_height);
if (fWarp)
XWarpPointer(dpy, None, None, 0, 0, 0, 0, FinalX - x, FinalY - y);
}
if(tmp_win->icon_pixmap_w != None)
{
XMapWindow(dpy,tmp_win->icon_w);
if (do_animate)
{
AnimatedMoveOfWindow(tmp_win->icon_pixmap_w, -1,-1,
tmp_win->icon_g.x,FinalY,fWarp,-1,NULL);
}
else
{
XMoveWindow(dpy, tmp_win->icon_pixmap_w, tmp_win->icon_g.x, FinalY);
if (fWarp)
XWarpPointer(dpy, None, None, 0, 0, 0, 0, FinalX - x, FinalY - y);
}
XMapWindow(dpy,w);
}
XSync(dpy, 0);
}
return;
}
void CMD_Move(F_CMD_ARGS)
{
move_window_doit(F_PASS_ARGS, False, MOVE_NORMAL);
}
void CMD_AnimatedMove(F_CMD_ARGS)
{
move_window_doit(F_PASS_ARGS, True, MOVE_NORMAL);
}
void CMD_MoveToPage(F_CMD_ARGS)
{
move_window_doit(F_PASS_ARGS, False, MOVE_PAGE);
}
void CMD_MoveToScreen(F_CMD_ARGS)
{
move_window_doit(F_PASS_ARGS, False, MOVE_SCREEN);
}
/* This function does the SnapAttraction stuff. If takes x and y coordinates
* (*px and *py) and returns the snapped values. */
static void DoSnapAttract(
FvwmWindow *tmp_win, unsigned int Width, unsigned int Height,
int *px, int *py)
{
int nyt,nxl,dist,closestLeft,closestRight,closestBottom,closestTop;
rectangle self, other;
FvwmWindow *tmp;
/* resist based on window edges */
closestTop = Scr.SnapAttraction;
closestBottom = Scr.SnapAttraction;
closestRight = Scr.SnapAttraction;
closestLeft = Scr.SnapAttraction;
nxl = -99999;
nyt = -99999;
self.x = *px;
self.y = *py;
self.width = Width;
self.height = Height;
if (IS_ICONIFIED(tmp_win) && !HAS_NO_ICON_TITLE(tmp_win))
{
self.height += tmp_win->icon_g.height;
}
/*
* snap attraction
*/
/* snap to other windows */
if ((Scr.SnapMode & (SNAP_ICONS | SNAP_WINDOWS | SNAP_SAME)) &&
Scr.SnapAttraction > 0)
{
for (tmp = Scr.FvwmRoot.next; tmp; tmp = tmp->next)
{
if (tmp_win->Desk != tmp->Desk || tmp_win == tmp)
{
continue;
}
/* check snapping type */
switch (Scr.SnapMode)
{
case 1: /* SameType */
if (IS_ICONIFIED(tmp) != IS_ICONIFIED(tmp_win))
{
continue;
}
break;
case 2: /* Icons */
if (!IS_ICONIFIED(tmp) || !IS_ICONIFIED(tmp_win))
{
continue;
}
break;
case 3: /* Windows */
if (IS_ICONIFIED(tmp) || IS_ICONIFIED(tmp_win))
{
continue;
}
break;
case 0: /* All */
default:
/* NOOP */
break;
}
/* get other window dimensions */
if (IS_ICONIFIED(tmp))
{
if (tmp->icon_p_height > 0)
{
other.width = tmp->icon_p_width;
other.height = tmp->icon_p_height;
}
else
{
other.width = tmp->icon_g.width;
other.height = tmp->icon_g.height;
}
other.x = tmp->icon_g.x;
other.y = tmp->icon_g.y;
if (!HAS_NO_ICON_TITLE(tmp))
{
other.height += tmp->icon_g.height;
}
}
else
{
other.width = tmp->frame_g.width;
other.height = tmp->frame_g.height;
other.x = tmp->frame_g.x;
other.y = tmp->frame_g.y;
}
/* prevent that window snaps off screen */
if (other.x <= 0)
{
other.x -= Scr.SnapAttraction + 10000;
other.width += Scr.SnapAttraction + 10000;
}
if (other.y <= 0)
{
other.y -= Scr.SnapAttraction + 10000;
other.height += Scr.SnapAttraction + 10000;
}
if (other .x + other.width >= Scr.MyDisplayWidth)
{
other.width += Scr.SnapAttraction + 10000;
}
if (other .y + other.height >= Scr.MyDisplayHeight)
{
other.height += Scr.SnapAttraction + 10000;
}
/* snap horizontally */
if (!((other.y + (int)other.height) < (*py) ||
(other.y) > (*py + (int)self.height) ))
{
dist = abs(other.x - (*px + (int)self.width));
if (dist < closestRight)
{
closestRight = dist;
if (((*px + (int)self.width) >= other.x) &&
((*px + (int)self.width) < other.x + Scr.SnapAttraction))
{
nxl = other.x - (int)self.width;
}
if (((*px + (int)self.width) >= other.x - Scr.SnapAttraction) &&
((*px + (int)self.width) < other.x))
{
nxl = other.x - (int)self.width;
}
}
dist = abs(other.x + (int)other.width - *px);
if (dist < closestLeft)
{
closestLeft = dist;
if ((*px <= other.x + (int)other.width) &&
(*px > other.x + (int)other.width - Scr.SnapAttraction))
{
nxl = other.x + (int)other.width;
}
if ((*px <= other.x + (int)other.width + Scr.SnapAttraction) &&
(*px > other.x + (int)other.width))
{
nxl = other.x + (int)other.width;
}
}
} /* horizontally */
/* snap vertically */
if (!((other.x + (int)other.width) < (*px) ||
(other.x) > (*px + (int)self.width)))
{
dist = abs(other.y - (*py + (int)self.height));
if (dist < closestBottom)
{
closestBottom = dist;
if (((*py + (int)self.height) >= other.y) &&
((*py + (int)self.height) < other.y + Scr.SnapAttraction))
{
nyt = other.y - (int)self.height;
}
if (((*py + (int)self.height) >= other.y - Scr.SnapAttraction) &&
((*py + (int)self.height) < other.y))
{
nyt = other.y - (int)self.height;
}
}
dist = abs(other.y + (int)other.height - *py);
if (dist < closestTop)
{
closestTop = dist;
if ((*py <= other.y + (int)other.height) &&
(*py > other.y + (int)other.height - Scr.SnapAttraction))
{
nyt = other.y + (int)other.height;
}
if ((*py <= other.y + (int)other.height + Scr.SnapAttraction) &&
(*py > other.y + (int)other.height))
{
nyt = other.y + (int)other.height;
}
}
} /* vertically */
} /* for */
} /* snap to other windows */
/* snap to screen egdes */
if ((Scr.SnapMode & SNAP_SCREEN) && Scr.SnapAttraction > 0)
{
/* horizontally */
if (!(Scr.MyDisplayWidth < (*px) || (*px + (int)self.width) < 0))
{
dist = abs(Scr.MyDisplayHeight - (*py + (int)self.height));
if (dist < closestBottom)
{
closestBottom = dist;
if (((*py + (int)self.height) >= Scr.MyDisplayHeight) &&
((*py + (int)self.height) < Scr.MyDisplayHeight +
Scr.SnapAttraction))
{
nyt = Scr.MyDisplayHeight - (int)self.height;
}
if (((*py + (int)self.height) >= Scr.MyDisplayHeight -
Scr.SnapAttraction) &&
((*py + (int)self.height) < Scr.MyDisplayHeight))
{
nyt = Scr.MyDisplayHeight - (int)self.height;
}
}
dist = abs(*py);
if (dist < closestTop)
{
closestTop = dist;
if ((*py <= 0)&&(*py > - Scr.SnapAttraction))
{
nyt = 0;
}
if ((*py <= Scr.SnapAttraction)&&(*py > 0))
{
nyt = 0;
}
}
} /* horizontally */
/* vertically */
if (!(Scr.MyDisplayHeight < (*py) || (*py + (int)self.height) < 0))
{
dist = abs(Scr.MyDisplayWidth - (*px + (int)self.width));
if (dist < closestRight)
{
closestRight = dist;
if (((*px + (int)self.width) >= Scr.MyDisplayWidth) &&
((*px + (int)self.width) < Scr.MyDisplayWidth +
Scr.SnapAttraction))
{
nxl = Scr.MyDisplayWidth - (int)self.width;
}
if (((*px + (int)self.width) >= Scr.MyDisplayWidth -
Scr.SnapAttraction) &&
((*px + (int)self.width) < Scr.MyDisplayWidth))
{
nxl = Scr.MyDisplayWidth - (int)self.width;
}
}
dist = abs(*px);
if (dist < closestLeft)
{
closestLeft = dist;
if ((*px <= 0) &&
(*px > - Scr.SnapAttraction))
{
nxl = 0;
}
if ((*px <= Scr.SnapAttraction) &&
(*px > 0))
{
nxl = 0;
}
}
} /* vertically */
} /* snap to screen edges */
if (nxl != -99999)
{
*px = nxl;
}
if (nyt != -99999)
{
*py = nyt;
}
/*
* Snap grid handling
*/
if (Scr.SnapGridX > 1 && nxl == -99999)
{
if (*px != *px / Scr.SnapGridX * Scr.SnapGridX)
{
*px = (*px + ((*px >= 0) ? Scr.SnapGridX : -Scr.SnapGridX) / 2) /
Scr.SnapGridX * Scr.SnapGridX;
}
}
if (Scr.SnapGridY > 1 && nyt == -99999)
{
if (*py != *py / Scr.SnapGridY * Scr.SnapGridY)
{
*py = (*py + ((*py >= 0) ? Scr.SnapGridY : -Scr.SnapGridY) / 2) /
Scr.SnapGridY * Scr.SnapGridY;
}
}
/*
* Resist moving windows beyond the edge of the screen
*/
if (Scr.MoveResistance > 0)
{
/* snap to right edge */
if (((*px + Width) >= Scr.MyDisplayWidth)
&& ((*px + Width) < Scr.MyDisplayWidth + Scr.MoveResistance))
{
*px = Scr.MyDisplayWidth - Width;
}
/* snap to left edge */
else if ((*px <= 0) && (*px > -Scr.MoveResistance))
{
*px = 0;
}
/* snap to bottom edge */
if (((*py + Height) >= Scr.MyDisplayHeight)
&& ((*py + Height) < Scr.MyDisplayHeight + Scr.MoveResistance))
{
*py = Scr.MyDisplayHeight - Height;
}
/* snap to top edge */
else if ((*py <= 0) && (*py > -Scr.MoveResistance))
{
*py = 0;
}
}
/* Resist moving windows between xineramascreens */
if (Scr.XiMoveResistance > 0 && FScreenIsEnabled())
{
int scr_x0, scr_y0, scr_x1, scr_y1;
Bool do_recalc_rectangle = False;
FScreenGetResistanceRect(
*px, *py, Width, Height, &scr_x0, &scr_y0, &scr_x1, &scr_y1);
/* snap to right edge */
if (scr_x1 != Scr.MyDisplayWidth &&
*px + Width >= scr_x1 && *px + Width < scr_x1 + Scr.XiMoveResistance)
{
*px = scr_x1 - Width;
do_recalc_rectangle = True;
}
/* snap to left edge */
else if (scr_x0 != 0 &&
*px <= scr_x0 && scr_x0 - *px < Scr.XiMoveResistance)
{
*px = scr_x0;
do_recalc_rectangle = True;
}
if (do_recalc_rectangle)
{
/* Snapping in X direction can move the window off a screen. Thus, it
* may no longer be necessary to snap in Y direction. */
FScreenGetResistanceRect(
*px, *py, Width, Height, &scr_x0, &scr_y0, &scr_x1, &scr_y1);
}
/* snap to bottom edge */
if (scr_y1 != Scr.MyDisplayHeight &&
*py + Height >= scr_y1 && *py + Height < scr_y1 + Scr.XiMoveResistance)
{
*py = scr_y1 - Height;
}
/* snap to top edge */
else if (scr_y0 != 0 &&
*py <= scr_y0 && scr_y0 - *py < Scr.XiMoveResistance)
{
*py = scr_y0;
}
}
return;
}
/****************************************************************************
*
* Move the rubberband around, return with the new window location
*
* Returns True if the window has to be resized after the move.
*
****************************************************************************/
Bool moveLoop(FvwmWindow *tmp_win, int XOffset, int YOffset, int Width,
int Height, int *FinalX, int *FinalY,Bool do_move_opaque)
{
extern Window bad_window;
Bool finished = False;
Bool aborted = False;
int xl,xl2,yt,yt2,delta_x,delta_y,paged;
unsigned int button_mask = 0;
FvwmWindow tmp_win_copy;
int dx = Scr.EdgeScrollX ? Scr.EdgeScrollX : Scr.MyDisplayWidth;
int dy = Scr.EdgeScrollY ? Scr.EdgeScrollY : Scr.MyDisplayHeight;
int vx = Scr.Vx;
int vy = Scr.Vy;
int xl_orig = 0;
int yt_orig = 0;
int cnx = 0;
int cny = 0;
int x_virtual_offset = 0;
int y_virtual_offset = 0;
Bool sent_cn = False;
Bool do_resize_too = False;
Bool do_exec_placement_func = False;
int x_bak;
int y_bak;
Window move_w = None;
int orig_icon_x = 0;
int orig_icon_y = 0;
if (!GrabEm(CRS_MOVE, GRAB_NORMAL))
{
XBell(dpy, 0);
return False;
}
if (!IS_MAPPED(tmp_win) && !IS_ICONIFIED(tmp_win))
do_move_opaque = False;
bad_window = None;
if (IS_ICONIFIED(tmp_win))
{
if (tmp_win->icon_pixmap_w != None)
move_w = tmp_win->icon_pixmap_w;
else if (tmp_win->icon_w != None)
move_w = tmp_win->icon_w;
}
else
{
move_w = tmp_win->frame;
}
if (!XGetGeometry(dpy, move_w, &JunkRoot, &x_bak, &y_bak,
&JunkWidth, &JunkHeight, &JunkBW,&JunkDepth))
{
/* This is allright here since the window may not be mapped yet. */
}
if (IS_ICONIFIED(tmp_win))
{
orig_icon_x = tmp_win->icon_g.x;
orig_icon_y = tmp_win->icon_g.y;
}
/* make a copy of the tmp_win structure for sending to the pager */
memcpy(&tmp_win_copy, tmp_win, sizeof(FvwmWindow));
/* prevent flicker when paging */
SET_WINDOW_BEING_MOVED_OPAQUE(tmp_win, do_move_opaque);
if (XQueryPointer(
dpy, Scr.Root, &JunkRoot, &JunkChild, &xl, &yt, &JunkX, &JunkY,
&button_mask) == False)
{
/* pointer is on a different screen */
xl = 0;
yt = 0;
}
else
{
xl += XOffset;
yt += YOffset;
}
button_mask &= DEFAULT_ALL_BUTTONS_MASK;
xl_orig = xl;
yt_orig = yt;
/* draw initial outline */
if (!IS_ICONIFIED(tmp_win) &&
((!do_move_opaque && !Scr.gs.EmulateMWM) || !IS_MAPPED(tmp_win)))
draw_move_resize_grid(xl, yt, Width - 1, Height - 1);
DisplayPosition(tmp_win, &Event, xl, yt, True);
while (!finished && bad_window != tmp_win->w)
{
int rc = 0;
/* wait until there is an interesting event */
while (rc != -1 && (!XPending(dpy) ||
!XCheckMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
KeyPressMask | PointerMotionMask |
ButtonMotionMask | ExposureMask, &Event)))
{
rc = HandlePaging(
dx, dy, &xl, &yt, &delta_x, &delta_y, False, False, True);
if (rc == 1)
{
/* Fake an event to force window reposition */
if (delta_x)
{
x_virtual_offset = 0;
}
if (XOffset)
{
xl += XOffset;
}
if (delta_y)
{
y_virtual_offset = 0;
}
if (YOffset)
{
yt += YOffset;
}
DoSnapAttract(tmp_win, Width, Height, &xl, &yt);
Event.type = MotionNotify;
Event.xmotion.time = lastTimestamp;
Event.xmotion.x_root = xl - XOffset;
Event.xmotion.y_root = yt - YOffset;
break;
}
}
if (rc == -1)
{
/* block until an event arrives */
XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
KeyPressMask | PointerMotionMask |
ButtonMotionMask | ExposureMask, &Event);
}
StashEventTime(&Event);
/* discard any extra motion events before a logical release */
if (Event.type == MotionNotify)
{
XEvent new_event;
/*** logic borrowed from icewm ***/
while (XPending(dpy) > 0 &&
XCheckMaskEvent(dpy, ButtonMotionMask | PointerMotionMask |
ButtonPressMask | ButtonRelease | KeyPressMask,
&new_event))
{
if (Event.type != new_event.type)
{
XPutBackEvent(dpy, &new_event);
break;
}
else
{
Event = new_event;
}
}
/*** end of code borrowed from icewm ***/
StashEventTime(&Event);
} /* if (Event.type == MotionNotify) */
/* Handle a limited number of key press events to allow mouseless
* operation */
if (Event.type == KeyPress)
{
Keyboard_shortcuts(
&Event, tmp_win, &x_virtual_offset, &y_virtual_offset, ButtonRelease);
}
switch(Event.type)
{
case KeyPress:
/* simple code to bag out of move - CKH */
if (XLookupKeysym(&(Event.xkey),0) == XK_Escape)
{
if (!do_move_opaque)
switch_move_resize_grid(False);
if (!IS_ICONIFIED(tmp_win))
{
if (do_move_opaque)
{
*FinalX = tmp_win->frame_g.x;
*FinalY = tmp_win->frame_g.y;
}
}
else
{
*FinalX = orig_icon_x;
*FinalY = orig_icon_y;
}
aborted = True;
finished = True;
}
break;
case ButtonPress:
if (Event.xbutton.button <= NUMBER_OF_MOUSE_BUTTONS &&
((Button1Mask << (Event.xbutton.button - 1)) & button_mask))
{
/* No new button was pressed, just a delayed event */
break;
}
if(((Event.xbutton.button == 2)&&(!Scr.gs.EmulateMWM))||
((Event.xbutton.button == 1)&&(Scr.gs.EmulateMWM)&&
(Event.xbutton.state & ShiftMask)))
{
do_resize_too = True;
do_exec_placement_func = False;
SET_PLACED_WB3(tmp_win,False);
/* Fallthrough to button-release */
}
else if(Event.xbutton.button == 3)
{
do_exec_placement_func = True;
do_resize_too = False;
SET_PLACED_WB3(tmp_win,True);
/* Fallthrough to button-release */
}
else
{
/* Abort the move if
* - the move started with a pressed button and another button
* was pressed during the operation
* - no button was pressed at the beginning and any button
* except button 1 was pressed. */
SET_PLACED_WB3(tmp_win,False);
if (button_mask || (Event.xbutton.button != 1))
{
if(!do_move_opaque)
switch_move_resize_grid(False);
if (!IS_ICONIFIED(tmp_win))
{
*FinalX = tmp_win->frame_g.x;
*FinalY = tmp_win->frame_g.y;
}
else
{
*FinalX = orig_icon_x;
*FinalY = orig_icon_y;
}
aborted = True;
finished = True;
}
break;
}
case ButtonRelease:
if(!do_move_opaque)
switch_move_resize_grid(False);
xl2 = Event.xbutton.x_root + XOffset + x_virtual_offset;
yt2 = Event.xbutton.y_root + YOffset + y_virtual_offset;
/* ignore the position of the button release if it was on a
* different page. */
if (!(((xl < 0 && xl2 >= 0) || (xl >= 0 && xl2 < 0) ||
(yt < 0 && yt2 >= 0) || (yt >= 0 && yt2 < 0)) &&
(abs(xl - xl2) > Scr.MyDisplayWidth / 2 ||
abs(yt - yt2) > Scr.MyDisplayHeight / 2)))
{
xl = xl2;
yt = yt2;
}
if (xl != xl_orig || yt != yt_orig || vx != Scr.Vx || vy != Scr.Vy)
{
/* only snap if the window actually moved! */
DoSnapAttract(tmp_win, Width, Height, &xl, &yt);
}
*FinalX = xl;
*FinalY = yt;
finished = True;
break;
case MotionNotify:
if (Event.xmotion.same_screen == False)
{
continue;
}
xl = Event.xmotion.x_root;
yt = Event.xmotion.y_root;
if (xl > 0 && xl < Scr.MyDisplayWidth - 1)
{
/* pointer was moved away from the left/right border with the mouse,
* reset the virtual x offset */
x_virtual_offset = 0;
}
if (yt > 0 && yt < Scr.MyDisplayHeight - 1)
{
/* pointer was moved away from the top/bottom border with the mouse,
* reset the virtual y offset */
y_virtual_offset = 0;
}
xl += XOffset + x_virtual_offset;
yt += YOffset + y_virtual_offset;
DoSnapAttract(tmp_win, Width, Height, &xl, &yt);
/* check Paging request once and only once after outline redrawn */
/* redraw after paging if needed - mab */
paged = 0;
while (paged <= 1)
{
if(!do_move_opaque)
draw_move_resize_grid(xl, yt, Width - 1, Height - 1);
else
{
if (IS_ICONIFIED(tmp_win))
{
tmp_win->icon_g.x = xl ;
tmp_win->icon_xl_loc = xl -
(tmp_win->icon_g.width - tmp_win->icon_p_width)/2;
tmp_win->icon_g.y = yt;
if(tmp_win->icon_pixmap_w != None)
XMoveWindow(dpy, tmp_win->icon_pixmap_w, tmp_win->icon_g.x,yt);
else if (tmp_win->icon_w != None)
XMoveWindow(dpy, tmp_win->icon_w,tmp_win->icon_xl_loc,
yt+tmp_win->icon_p_height);
}
else
{
XMoveWindow(dpy,tmp_win->frame,xl,yt);
}
}
DisplayPosition(tmp_win, &Event, xl, yt, False);
/* prevent window from lagging behind mouse when paging - mab */
if (paged == 0)
{
xl = Event.xmotion.x_root;
yt = Event.xmotion.y_root;
HandlePaging(
dx, dy, &xl, &yt, &delta_x, &delta_y, False, False, False);
if (delta_x)
{
x_virtual_offset = 0;
}
if (XOffset)
{
xl += XOffset;
}
if (delta_y)
{
y_virtual_offset = 0;
}
if (YOffset)
{
yt += YOffset;
}
DoSnapAttract(tmp_win, Width, Height, &xl, &yt);
if (!delta_x && !delta_y)
/* break from while (paged <= 1) */
break;
}
paged++;
} /* end while (paged) */
break;
case Expose:
if (!do_move_opaque)
{
/* must undraw the rubber band in case the event causes some drawing */
switch_move_resize_grid(False);
}
DispatchEvent(False);
if (!do_move_opaque)
draw_move_resize_grid(xl, yt, Width - 1, Height - 1);
break;
default:
/* cannot happen */
break;
} /* switch */
xl += x_virtual_offset;
yt += y_virtual_offset;
if (do_move_opaque && !IS_ICONIFIED(tmp_win) && !IS_SHADED(tmp_win) &&
!Scr.bo.DisableConfigureNotify)
{
/* send configure notify event for windows that care about their
* location; don't send anything if position didn't change */
if (!sent_cn || cnx != xl || cny != yt)
{
cnx = xl;
cny = yt;
sent_cn = True;
SendConfigureNotify(tmp_win, xl, yt, Width, Height, 0, False);
#ifdef FVWM_DEBUG_MSGS
fvwm_msg(
DBG, "SetupFrame","Sent ConfigureNotify (w %d, h %d)", Width, Height);
#endif
}
}
if (do_move_opaque)
{
if (!IS_ICONIFIED(tmp_win))
{
tmp_win_copy.frame_g.x = xl;
tmp_win_copy.frame_g.y = yt;
}
/* only do this with opaque moves, (i.e. the server is not grabbed) */
BroadcastConfig(M_CONFIGURE_WINDOW, &tmp_win_copy);
FlushAllMessageQueues();
}
} /* while (!finished) */
if (!Scr.gs.do_hide_position_window)
XUnmapWindow(dpy,Scr.SizeWindow);
if (aborted || bad_window == tmp_win->w)
{
if (vx != Scr.Vx || vy != Scr.Vy)
{
MoveViewport(vx, vy, False);
}
if (aborted && do_move_opaque)
{
XMoveWindow(dpy, move_w, x_bak, y_bak);
}
if (bad_window == tmp_win->w)
{
XUnmapWindow(dpy, move_w);
XBell(dpy, 0);
}
}
if (!aborted && bad_window != tmp_win->w && IS_ICONIFIED(tmp_win))
{
SET_ICON_MOVED(tmp_win, 1);
}
UngrabEm(GRAB_NORMAL);
if (!do_resize_too)
{
/* Don't wait for buttons to come up when user is placing a new window
* and wants to resize it. */
WaitForButtonsUp(True);
}
SET_WINDOW_BEING_MOVED_OPAQUE(tmp_win, 0);
bad_window = None;
return do_resize_too;
}
void CMD_MoveThreshold(F_CMD_ARGS)
{
int val = 0;
if (GetIntegerArguments(action, NULL, &val, 1) < 1 || val < 0)
Scr.MoveThreshold = DEFAULT_MOVE_THRESHOLD;
else
Scr.MoveThreshold = val;
}
void CMD_OpaqueMoveSize(F_CMD_ARGS)
{
int val;
if (GetIntegerArguments(action, NULL, &val, 1) < 1)
{
if (strncasecmp(action, "unlimited", 9) == 0)
Scr.OpaqueSize = -1;
else
Scr.OpaqueSize = DEFAULT_OPAQUE_MOVE_SIZE;
}
else
Scr.OpaqueSize = val;
}
static char *hide_options[] =
{
"never",
"move",
"resize",
NULL
};
void CMD_HideGeometryWindow(F_CMD_ARGS)
{
char *token = PeekToken(action, NULL);
Scr.gs.do_hide_position_window = 0;
Scr.gs.do_hide_resize_window = 0;
switch(GetTokenIndex(token, hide_options, 0, NULL))
{
case 0:
break;
case 1:
Scr.gs.do_hide_position_window = 1;
break;
case 2:
Scr.gs.do_hide_resize_window = 1;
break;
default:
Scr.gs.do_hide_position_window = 1;
Scr.gs.do_hide_resize_window = 1;
break;
}
return;
}
void CMD_SnapAttraction(F_CMD_ARGS)
{
int val;
char *token;
if (GetIntegerArguments(action, &action, &val, 1) != 1)
{
Scr.SnapAttraction = DEFAULT_SNAP_ATTRACTION;
Scr.SnapMode = DEFAULT_SNAP_ATTRACTION_MODE;
return;
}
Scr.SnapAttraction = val;
if (val < 0)
{
Scr.SnapAttraction = DEFAULT_SNAP_ATTRACTION;
}
if (val == 0)
{
return;
}
token = PeekToken(action, &action);
if (token == NULL)
{
return;
}
if (StrEquals(token,"All"))
{
Scr.SnapMode = SNAP_ICONS | SNAP_WINDOWS;
}
else if (StrEquals(token,"SameType"))
{
Scr.SnapMode = SNAP_SAME;
}
else if (StrEquals(token,"Icons"))
{
Scr.SnapMode = SNAP_ICONS;
}
else if (StrEquals(token,"Windows"))
{
Scr.SnapMode = SNAP_WINDOWS;
}
if (Scr.SnapMode == 0)
{
Scr.SnapMode = DEFAULT_SNAP_ATTRACTION_MODE;
}
else
{
token = PeekToken(action, &action);
if (token == NULL)
{
return;
}
}
if (StrEquals(token, "Screen"))
{
Scr.SnapMode |= SNAP_SCREEN;
}
else
{
fvwm_msg(ERR,"SetSnapAttraction", "Invalid argument: %s", token);
}
return;
}
void CMD_SnapGrid(F_CMD_ARGS)
{
int val[2];
if(GetIntegerArguments(action, NULL, &val[0], 2) != 2)
{
Scr.SnapGridX = DEFAULT_SNAP_GRID_X;
Scr.SnapGridY = DEFAULT_SNAP_GRID_Y;
return;
}
Scr.SnapGridX = val[0];
if(Scr.SnapGridX < 1)
{
Scr.SnapGridX = DEFAULT_SNAP_GRID_X;
}
Scr.SnapGridY = val[1];
if(Scr.SnapGridY < 1)
{
Scr.SnapGridY = DEFAULT_SNAP_GRID_Y;
}
}
static Pixmap XorPixmap = None;
void CMD_XorValue(F_CMD_ARGS)
{
int val;
XGCValues gcv;
unsigned long gcm;
if(GetIntegerArguments(action, NULL, &val, 1) != 1)
{
val = 0;
}
gcm = GCFunction|GCLineWidth|GCForeground|GCFillStyle|GCSubwindowMode;
gcv.subwindow_mode = IncludeInferiors;
gcv.function = GXxor;
gcv.line_width = 0;
/* use passed in value, or try to calculate appropriate value if 0 */
/* ctwm method: */
/*
gcv.foreground = (val1)?(val1):((((unsigned long) 1) << Scr.d_depth) - 1);
*/
/* Xlib programming manual suggestion: */
gcv.foreground = (val)?
(val):(BlackPixel(dpy,Scr.screen) ^ WhitePixel(dpy,Scr.screen));
gcv.fill_style = FillSolid;
gcv.subwindow_mode = IncludeInferiors;
/* modify XorGC, only create once */
if (Scr.XorGC)
XChangeGC(dpy, Scr.XorGC, gcm, &gcv);
else
Scr.XorGC = fvwmlib_XCreateGC(dpy, Scr.Root, gcm, &gcv);
/* free up XorPixmap if neccesary */
if (XorPixmap != None) {
XFreePixmap(dpy, XorPixmap);
XorPixmap = None;
}
}
void CMD_XorPixmap(F_CMD_ARGS)
{
char *PixmapName;
Picture *xp;
XGCValues gcv;
unsigned long gcm;
action = GetNextToken(action, &PixmapName);
if(PixmapName == NULL)
{
/* return to default value. */
action = "0";
CMD_XorValue(F_PASS_ARGS);
return;
}
/* get the picture in the root visual, colorlimit is ignored because the
* pixels will be freed */
UseDefaultVisual();
xp = GetPicture(dpy, Scr.Root, NULL, PixmapName, 0);
if (xp == NULL) {
fvwm_msg(ERR,"SetXORPixmap","Can't find pixmap %s", PixmapName);
free(PixmapName);
UseFvwmVisual();
return;
}
free(PixmapName);
/* free up old pixmap */
if (XorPixmap != None)
XFreePixmap(dpy, XorPixmap);
/* make a copy of the picture pixmap */
XorPixmap = XCreatePixmap(dpy, Scr.Root, xp->width, xp->height, Pdepth);
XCopyArea(dpy, xp->picture, XorPixmap, DefaultGC(dpy, Scr.screen), 0, 0,
xp->width, xp->height, 0, 0);
/* destroy picture and free colors */
DestroyPicture(dpy, xp);
UseFvwmVisual();
/* create Graphics context */
gcm = GCFunction|GCLineWidth|GCTile|GCFillStyle|GCSubwindowMode;
gcv.subwindow_mode = IncludeInferiors;
gcv.function = GXxor;
/* line width of 1 is necessary for Exceed servers */
gcv.line_width = 1;
gcv.tile = XorPixmap;
gcv.fill_style = FillTiled;
gcv.subwindow_mode = IncludeInferiors;
/* modify XorGC, only create once */
if (Scr.XorGC)
XChangeGC(dpy, Scr.XorGC, gcm, &gcv);
else
Scr.XorGC = fvwmlib_XCreateGC(dpy, Scr.Root, gcm, &gcv);
}
/* ----------------------------- resizing code ----------------------------- */
/***********************************************************************
*
* window resizing borrowed from the "wm" window manager
*
***********************************************************************/
/****************************************************************************
*
* Starts a window resize operation
*
****************************************************************************/
void CMD_Resize(F_CMD_ARGS)
{
extern Window bad_window;
Bool finished = False, done = False, abort = False;
Bool do_resize_opaque;
int x,y,delta_x,delta_y,stashed_x,stashed_y;
Window ResizeWindow;
Bool fButtonAbort = False;
Bool fForceRedraw = False;
int n;
unsigned int button_mask = 0;
rectangle sdrag;
rectangle sorig;
rectangle *drag = &sdrag;
rectangle *orig = &sorig;
rectangle start_g;
int ymotion = 0;
int xmotion = 0;
int was_maximized;
unsigned edge_wrap_x;
unsigned edge_wrap_y;
int px;
int py;
int i;
Bool called_from_title = False;
bad_window = False;
if (DeferExecution(eventp,&w,&tmp_win,&context, CRS_RESIZE, ButtonPress))
return;
if (tmp_win == NULL)
return;
ResizeWindow = tmp_win->frame;
XQueryPointer( dpy, ResizeWindow, &JunkRoot, &JunkChild,
&JunkX, &JunkY, &px, &py, &button_mask);
button_mask &= DEFAULT_ALL_BUTTONS_MASK;
if (!check_if_function_allowed(F_RESIZE, tmp_win, True, NULL))
{
XBell(dpy, 0);
return;
}
was_maximized = IS_MAXIMIZED(tmp_win);
SET_MAXIMIZED(tmp_win, 0);
if (was_maximized)
{
/* must redraw the buttons now so that the 'maximize' button does not stay
* depressed. */
DrawDecorations(
tmp_win, DRAW_BUTTONS, (tmp_win == Scr.Hilite), True, None);
}
if (IS_SHADED(tmp_win) || !IS_MAPPED(tmp_win))
do_resize_opaque = False;
else
do_resize_opaque = DO_RESIZE_OPAQUE(tmp_win);
/* no suffix = % of screen, 'p' = pixels, 'c' = increment units */
drag->width = tmp_win->frame_g.width;
drag->height = tmp_win->frame_g.height;
n = GetResizeArguments(
&action, tmp_win->frame_g.x, tmp_win->frame_g.y,
tmp_win->hints.base_width, tmp_win->hints.base_height,
tmp_win->hints.width_inc, tmp_win->hints.height_inc,
tmp_win->boundary_width, tmp_win->title_g.height,
&(drag->width), &(drag->height));
if (n == 2)
{
rectangle new_g;
/* size will be less or equal to requested */
new_g = tmp_win->frame_g;
constrain_size(
tmp_win, (unsigned int *)&drag->width, (unsigned int *)&drag->height,
xmotion, ymotion, 0);
gravity_resize(
tmp_win->hints.win_gravity, &new_g,
drag->width - new_g.width, drag->height - new_g.height);
tmp_win->frame_g = new_g;
if (IS_SHADED(tmp_win))
{
ForceSetupFrame(tmp_win, tmp_win->frame_g.x, tmp_win->frame_g.y,
drag->width, tmp_win->frame_g.height, False);
}
else
{
ForceSetupFrame(tmp_win, tmp_win->frame_g.x, tmp_win->frame_g.y,
drag->width, drag->height, False);
}
DrawDecorations(tmp_win, DRAW_ALL, True, True, None);
update_absolute_geometry(tmp_win);
maximize_adjust_offset(tmp_win);
GNOME_SetWinArea(tmp_win);
ResizeWindow = None;
return;
}
if (Scr.bo.InstallRootCmap)
InstallRootColormap();
else
InstallFvwmColormap();
if(!GrabEm(CRS_RESIZE, GRAB_NORMAL))
{
XBell(dpy, 0);
return;
}
/* handle problems with edge-wrapping while resizing */
edge_wrap_x = Scr.flags.edge_wrap_x;
edge_wrap_y = Scr.flags.edge_wrap_y;
Scr.flags.edge_wrap_x = 0;
Scr.flags.edge_wrap_y = 0;
if (!do_resize_opaque)
{
MyXGrabServer(dpy);
}
if (!XGetGeometry(
dpy, (Drawable) ResizeWindow, &JunkRoot, &drag->x, &drag->y,
(unsigned int *)&drag->width, (unsigned int *)&drag->height,
&JunkBW, &JunkDepth))
{
UngrabEm(GRAB_NORMAL);
if (!do_resize_opaque)
{
MyXUngrabServer(dpy);
}
return;
}
if (IS_SHADED(tmp_win))
{
SET_MAXIMIZED(tmp_win, was_maximized);
get_unshaded_geometry(tmp_win, drag);
SET_MAXIMIZED(tmp_win, 0);
}
if (!do_resize_opaque)
{
Scr.flags.is_wire_frame_displayed = True;
}
MyXGrabKeyboard(dpy);
*orig = *drag;
start_g = *drag;
ymotion = 0;
xmotion = 0;
/* pop up a resize dimensions window */
if (!Scr.gs.do_hide_resize_window)
{
position_geometry_window(NULL);
XMapRaised(dpy, Scr.SizeWindow);
}
DisplaySize(tmp_win, &Event, orig->width, orig->height,True,True);
if((PressedW != Scr.Root)&&(PressedW != None))
{
/* Get the current position to determine which border to resize */
if(PressedW == tmp_win->sides[0]) /* top */
ymotion = 1;
else if(PressedW == tmp_win->sides[1]) /* right */
xmotion = -1;
else if(PressedW == tmp_win->sides[2]) /* bottom */
ymotion = -1;
else if(PressedW == tmp_win->sides[3]) /* left */
xmotion = 1;
else if(PressedW == tmp_win->corners[0]) /* upper-left */
{
ymotion = 1;
xmotion = 1;
}
else if(PressedW == tmp_win->corners[1]) /* upper-right */
{
xmotion = -1;
ymotion = 1;
}
else if(PressedW == tmp_win->corners[2]) /* lower left */
{
ymotion = -1;
xmotion = 1;
}
else if(PressedW == tmp_win->corners[3]) /* lower right */
{
ymotion = -1;
xmotion = -1;
}
}
/* begin of code responsible for warping the pointer to the border when
* starting a resize. */
if (tmp_win->title_w != None && PressedW == tmp_win->title_w)
{
/* title was pressed to thart the resize */
called_from_title = True;
}
else
{
for (i = NUMBER_OF_BUTTONS; i--; )
{
/* see if the title button was pressed to that the resize */
if (tmp_win->button_w[i] != None && PressedW == tmp_win->button_w[i])
{
/* yes */
called_from_title = True;
}
}
}
/* don't warp if the resize was triggered by a press somwhere on the title
* bar */
if(PressedW != Scr.Root && xmotion == 0 && ymotion == 0 &&
!called_from_title)
{
int dx = orig->width - px;
int dy = orig->height - py;
int wx = -1;
int wy = -1;
int tx;
int ty;
/* Now find the place to warp to. We simply use the sectors drawn when we
* start resizing the window. */
#if 0
tx = orig->width / 10 - 1;
ty = orig->height / 10 - 1;
#else
tx = 0;
ty = 0;
#endif
tx = max(tmp_win->boundary_width, tx);
ty = max(tmp_win->boundary_width, ty);
if (px >= 0 && dx >= 0 && py >= 0 && dy >= 0)
{
if (px < tx)
{
if (py < ty)
{
xmotion = 1;
ymotion = 1;
wx = 0;
wy = 0;
}
else if (dy < ty)
{
xmotion = 1;
ymotion = -1;
wx = 0;
wy = orig->height -1;
}
else
{
xmotion = 1;
wx = 0;
wy = orig->height/2;
wy = py;
}
}
else if (dx < tx)
{
if (py < ty)
{
xmotion = -1;
ymotion = 1;
wx = orig->width - 1;
wy = 0;
}
else if (dy < ty)
{
xmotion = -1;
ymotion = -1;
wx = orig->width - 1;
wy = orig->height -1;
}
else
{
xmotion = -1;
wx = orig->width - 1;
wy = orig->height/2;
wy = py;
}
}
else
{
if (py < ty)
{
ymotion = 1;
wx = orig->width/2;
wy = 0;
wx = px;
}
else if (dy < ty)
{
ymotion = -1;
wx = orig->width/2;
wy = orig->height -1;
wx = px;
}
}
}
if (wx != -1)
{
/* now warp the pointer to the border */
XWarpPointer(dpy, None, ResizeWindow, 0, 0, 1, 1, wx, wy);
XFlush(dpy);
}
}
/* end of code responsible for warping the pointer to the border when
* starting a resize. */
/* draw the rubber-band window */
if (!do_resize_opaque)
draw_move_resize_grid(drag->x, drag->y, drag->width - 1, drag->height - 1);
/* kick off resizing without requiring any motion if invoked with a key
* press */
if (eventp->type == KeyPress)
{
XQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
&stashed_x,&stashed_y,&JunkX, &JunkY, &JunkMask);
DoResize(stashed_x, stashed_y, tmp_win, drag, orig, &xmotion, &ymotion,
do_resize_opaque);
}
else
stashed_x = stashed_y = -1;
/* loop to resize */
while(!finished && bad_window != tmp_win->w)
{
int rc = 0;
/* block until there is an interesting event */
while (rc != -1 &&
(!XCheckMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
KeyPressMask | PointerMotionMask |
ButtonMotionMask | ExposureMask, &Event)))
{
rc = HandlePaging(
Scr.EdgeScrollX, Scr.EdgeScrollY, &x, &y, &delta_x, &delta_y,
False, False, True);
if (rc == 1)
{
/* Fake an event to force window reposition */
Event.type = MotionNotify;
Event.xmotion.time = lastTimestamp;
fForceRedraw = True;
break;
}
}
if (rc == -1)
{
XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask |
KeyPressMask | PointerMotionMask |
ButtonMotionMask | ExposureMask, &Event);
}
StashEventTime(&Event);
if (Event.type == MotionNotify)
{
/* discard any extra motion events before a release */
while(XCheckMaskEvent(dpy, ButtonMotionMask | PointerMotionMask |
ButtonReleaseMask | ButtonPressMask, &Event))
{
StashEventTime(&Event);
if (Event.type == ButtonRelease || Event.type == ButtonPress)
break;
}
}
done = False;
/* Handle a limited number of key press events to allow mouseless
* operation */
if(Event.type == KeyPress)
Keyboard_shortcuts(&Event, tmp_win, NULL, NULL, ButtonRelease);
switch(Event.type)
{
case ButtonPress:
done = True;
if (Event.xbutton.button <= NUMBER_OF_MOUSE_BUTTONS &&
((Button1Mask << (Event.xbutton.button - 1)) & button_mask))
{
/* No new button was pressed, just a delayed event */
break;
}
/* Abort the resize if
* - the move started with a pressed button and another button
* was pressed during the operation
* - no button was started at the beginning and any button
* except button 1 was pressed. */
if (button_mask || (Event.xbutton.button != 1))
fButtonAbort = True;
case KeyPress:
/* simple code to bag out of move - CKH */
if (XLookupKeysym(&(Event.xkey),0) == XK_Escape || fButtonAbort)
{
abort = True;
finished = True;
/* return pointer if aborted resize was invoked with key */
if (stashed_x >= 0)
{
XWarpPointer(dpy, None, Scr.Root, 0, 0, 0, 0, stashed_x,
stashed_y);
}
if (do_resize_opaque)
{
DoResize(
start_g.x, start_g.y, tmp_win, &start_g, orig, &xmotion, &ymotion,
do_resize_opaque);
DrawDecorations(tmp_win, DRAW_ALL, True, True, None);
}
}
done = True;
break;
case ButtonRelease:
finished = True;
done = True;
break;
case MotionNotify:
if (Event.xmotion.same_screen == False)
{
continue;
}
if (!fForceRedraw)
{
x = Event.xmotion.x_root;
y = Event.xmotion.y_root;
/* resize before paging request to prevent resize from lagging
* mouse - mab */
DoResize(
x, y, tmp_win, drag, orig, &xmotion, &ymotion, do_resize_opaque);
/* need to move the viewport */
HandlePaging(Scr.EdgeScrollX, Scr.EdgeScrollY, &x, &y,
&delta_x, &delta_y, False, False, False);
}
/* redraw outline if we paged - mab */
if (delta_x != 0 || delta_y != 0)
{
orig->x -= delta_x;
orig->y -= delta_y;
drag->x -= delta_x;
drag->y -= delta_y;
DoResize(
x, y, tmp_win, drag, orig, &xmotion, &ymotion, do_resize_opaque);
}
fForceRedraw = False;
done = True;
break;
default:
break;
}
if(!done)
{
if (!do_resize_opaque)
/* must undraw the rubber band in case the event causes some drawing */
switch_move_resize_grid(False);
DispatchEvent(False);
if (!do_resize_opaque)
draw_move_resize_grid(
drag->x, drag->y, drag->width - 1, drag->height - 1);
}
else
{
if (do_resize_opaque)
{
/* only do this with opaque resizes, (i.e. the server is not grabbed)
*/
BroadcastConfig(M_CONFIGURE_WINDOW, tmp_win);
FlushAllMessageQueues();
}
}
}
/* erase the rubber-band */
if (!do_resize_opaque)
switch_move_resize_grid(False);
/* pop down the size window */
if (!Scr.gs.do_hide_resize_window)
XUnmapWindow(dpy, Scr.SizeWindow);
if(!abort && bad_window != tmp_win->w)
{
/* size will be >= to requested */
constrain_size(
tmp_win, (unsigned int *)&drag->width, (unsigned int *)&drag->height,
xmotion, ymotion, CS_ROUND_UP);
if (IS_SHADED(tmp_win))
{
if (HAS_BOTTOM_TITLE(tmp_win))
{
SetupFrame(tmp_win, drag->x, tmp_win->frame_g.y,
drag->width, tmp_win->frame_g.height, False);
}
else
{
SetupFrame(tmp_win, drag->x, drag->y,
drag->width, tmp_win->frame_g.height, False);
}
tmp_win->normal_g.height = drag->height;
}
else
{
SetupFrame(
tmp_win, drag->x, drag->y, drag->width, drag->height, False);
}
}
if (abort && was_maximized)
{
/* since we aborted the resize, the window is still maximized */
SET_MAXIMIZED(tmp_win, 1);
/* force redraw */
DrawDecorations(
tmp_win, DRAW_BUTTONS, (tmp_win == Scr.Hilite), True, None);
}
if (bad_window == tmp_win->w)
{
XUnmapWindow(dpy, tmp_win->frame);
XBell(dpy, 0);
}
if (Scr.bo.InstallRootCmap)
UninstallRootColormap();
else
UninstallFvwmColormap();
ResizeWindow = None;
if (!do_resize_opaque)
{
/* Throw away some events that dont interest us right now. */
discard_events(EnterWindowMask|LeaveWindowMask);
Scr.flags.is_wire_frame_displayed = False;
MyXUngrabServer(dpy);
}
MyXUngrabKeyboard(dpy);
xmotion = 0;
ymotion = 0;
WaitForButtonsUp(True);
UngrabEm(GRAB_NORMAL);
Scr.flags.edge_wrap_x = edge_wrap_x;
Scr.flags.edge_wrap_y = edge_wrap_y;
update_absolute_geometry(tmp_win);
maximize_adjust_offset(tmp_win);
GNOME_SetWinArea(tmp_win);
return;
}
/***********************************************************************
*
* Procedure:
* DoResize - move the rubberband around. This is called for
* each motion event when we are resizing
*
* Inputs:
* x_root - the X corrdinate in the root window
* y_root - the Y corrdinate in the root window
* tmp_win - the current fvwm window
* drag - resize internal structure
* orig - resize internal structure
* xmotionp - pointer to xmotion in resize_window
* ymotionp - pointer to ymotion in resize_window
*
************************************************************************/
static void DoResize(
int x_root, int y_root, FvwmWindow *tmp_win, rectangle *drag,
rectangle *orig, int *xmotionp, int *ymotionp, Bool do_resize_opaque)
{
int action = 0;
XEvent e;
if ((y_root <= orig->y) ||
((*ymotionp == 1)&&(y_root < orig->y+orig->height-1)))
{
drag->y = y_root;
drag->height = orig->y + orig->height - y_root;
action = 1;
*ymotionp = 1;
}
else if ((y_root >= orig->y + orig->height - 1)||
((*ymotionp == -1)&&(y_root > orig->y)))
{
drag->y = orig->y;
drag->height = 1 + y_root - drag->y;
action = 1;
*ymotionp = -1;
}
if ((x_root <= orig->x)||
((*xmotionp == 1)&&(x_root < orig->x + orig->width - 1)))
{
drag->x = x_root;
drag->width = orig->x + orig->width - x_root;
action = 1;
*xmotionp = 1;
}
if ((x_root >= orig->x + orig->width - 1)||
((*xmotionp == -1)&&(x_root > orig->x)))
{
drag->x = orig->x;
drag->width = 1 + x_root - orig->x;
action = 1;
*xmotionp = -1;
}
if (action)
{
/* round up to nearest OK size to keep pointer inside rubberband */
constrain_size(
tmp_win, (unsigned int *)&drag->width, (unsigned int *)&drag->height,
*xmotionp, *ymotionp, CS_ROUND_UP);
if (*xmotionp == 1)
drag->x = orig->x + orig->width - drag->width;
if (*ymotionp == 1)
drag->y = orig->y + orig->height - drag->height;
if(!do_resize_opaque)
{
draw_move_resize_grid(
drag->x, drag->y, drag->width - 1, drag->height - 1);
}
else
{
SetupFrame(
tmp_win, drag->x, drag->y, drag->width, drag->height, False);
}
}
e.type = MotionNotify;
e.xbutton.x_root = x_root;
e.xbutton.y_root = y_root;
DisplaySize(tmp_win, &e, drag->width, drag->height,False,False);
}
/***********************************************************************
*
* Procedure:
* draw_move_resize_grid - move a window outline
*
* Inputs:
* root - the window we are outlining
* x - upper left x coordinate
* y - upper left y coordinate
* width - the width of the rectangle
* height - the height of the rectangle
*
***********************************************************************/
static int get_outline_rects(
XRectangle *rects, int x, int y, int width, int height)
{
int i;
int n;
int m;
n = 3;
m = (width - 5) / 2;
if (m < n)
{
n = m;
}
m = (height - 5) / 2;
if (m < n)
{
n = m;
}
if (n < 1)
{
n = 1;
}
for (i = 0; i < n; i++)
{
rects[i].x = x + i;
rects[i].y = y + i;
rects[i].width = width - (i << 1);
rects[i].height = height - (i << 1);
}
if (width - (n << 1) >= 5 && height - (n << 1) >= 5)
{
if (width - (n << 1) >= 10)
{
int off = (width - (n << 1)) / 3 + n;
rects[i].x = x + off;
rects[i].y = y + n;
rects[i].width = width - (off << 1);
rects[i].height = height - (n << 1);
i++;
}
if (height - (n << 1) >= 10)
{
int off = (height - (n << 1)) / 3 + n;
rects[i].x = x + n;
rects[i].y = y + off;
rects[i].width = width - (n << 1);
rects[i].height = height - (off << 1);
i++;
}
}
return i;
}
struct
{
rectangle geom;
struct
{
unsigned is_enabled : 1;
} flags;
} move_resize_grid =
{
{ 0, 0, 0, 0 },
{ 0 }
};
static void draw_move_resize_grid(int x, int y, int width, int height)
{
int nrects = 0;
XRectangle rects[10];
if (move_resize_grid.flags.is_enabled &&
x == move_resize_grid.geom.x &&
y == move_resize_grid.geom.y &&
width == move_resize_grid.geom.width &&
height == move_resize_grid.geom.height)
{
return;
}
memset(rects, 0, 10 * sizeof(XRectangle));
/* place the resize rectangle into the array of rectangles */
/* interleave them for best visual look */
/* draw the new one, if any */
if (move_resize_grid.flags.is_enabled
/*move_resize_grid.geom.width && move_resize_grid.geom.height*/)
{
move_resize_grid.flags.is_enabled = 0;
nrects +=
get_outline_rects(
&(rects[0]), move_resize_grid.geom.x, move_resize_grid.geom.y,
move_resize_grid.geom.width, move_resize_grid.geom.height);
}
if (width && height)
{
move_resize_grid.flags.is_enabled = 1;
move_resize_grid.geom.x = x;
move_resize_grid.geom.y = y;
move_resize_grid.geom.width = width;
move_resize_grid.geom.height = height;
nrects += get_outline_rects(&(rects[nrects]), x, y, width, height);
}
if (nrects > 0)
{
XDrawRectangles(dpy, Scr.Root, Scr.XorGC, rects, nrects);
XSync(dpy, 0);
}
return;
}
void switch_move_resize_grid(Bool state)
{
if (state == False)
{
if (move_resize_grid.flags.is_enabled)
{
draw_move_resize_grid(0, 0, 0, 0);
}
else
{
move_resize_grid.geom.x = 0;
move_resize_grid.geom.y = 0;
move_resize_grid.geom.width = 0;
move_resize_grid.geom.height = 0;
}
}
else if (!move_resize_grid.flags.is_enabled)
{
if (move_resize_grid.geom.width && move_resize_grid.geom.height)
{
draw_move_resize_grid(
move_resize_grid.geom.x, move_resize_grid.geom.y,
move_resize_grid.geom.width, move_resize_grid.geom.height);
}
}
return;
}
/* ----------------------------- maximizing code --------------------------- */
static void move_sticky_window_to_same_page(
int *x11, int *x12, int *y11, int *y12, int x21, int x22, int y21, int y22)
{
/* make sure the x coordinate is on the same page as the reference window */
if (*x11 >= x22)
{
while (*x11 >= x22)
{
*x11 -= Scr.MyDisplayWidth;
*x12 -= Scr.MyDisplayWidth;
}
}
else if (*x12 <= x21)
{
while (*x12 <= x21)
{
*x11 += Scr.MyDisplayWidth;
*x12 += Scr.MyDisplayWidth;
}
}
/* make sure the y coordinate is on the same page as the reference window */
if (*y11 >= y22)
{
while (*y11 >= y22)
{
*y11 -= Scr.MyDisplayHeight;
*y12 -= Scr.MyDisplayHeight;
}
}
else if (*y12 <= y21)
{
while (*y12 <= y21)
{
*y11 += Scr.MyDisplayHeight;
*y12 += Scr.MyDisplayHeight;
}
}
}
static void MaximizeHeight(
FvwmWindow *win, unsigned int win_width, int win_x, unsigned int *win_height,
int *win_y, Bool grow_up, Bool grow_down,
int top_border, int bottom_border)
{
FvwmWindow *cwin;
int x11, x12, x21, x22;
int y11, y12, y21, y22;
int new_y1, new_y2;
Bool is_sticky;
x11 = win_x; /* Start x */
y11 = *win_y; /* Start y */
x12 = x11 + win_width; /* End x */
y12 = y11 + *win_height; /* End y */
new_y1 = top_border;
new_y2 = bottom_border;
for (cwin = Scr.FvwmRoot.next; cwin; cwin = cwin->next)
{
if (IS_STICKY(cwin) || (IS_ICONIFIED(cwin) && IS_ICON_STICKY(cwin)))
is_sticky = True;
else
is_sticky = False;
if (cwin == win || (cwin->Desk != win->Desk && !is_sticky))
continue;
if (IS_ICONIFIED(cwin))
{
if(cwin->icon_w == None || IS_ICON_UNMAPPED(cwin))
continue;
x21 = cwin->icon_g.x;
y21 = cwin->icon_g.y;
x22 = x21 + cwin->icon_p_width;
y22 = y21 + cwin->icon_p_height + cwin->icon_g.height;
}
else
{
x21 = cwin->frame_g.x;
y21 = cwin->frame_g.y;
x22 = x21 + cwin->frame_g.width;
y22 = y21 + cwin->frame_g.height;
}
if (is_sticky)
{
move_sticky_window_to_same_page(
&x21, &x22, &new_y1, &new_y2, x11, x12, y11, y12);
}
/* Are they in the same X space? */
if (!((x22 <= x11) || (x21 >= x12)))
{
if ((y22 <= y11) && (y22 >= new_y1))
{
new_y1 = y22;
}
else if ((y12 <= y21) && (new_y2 >= y21))
{
new_y2 = y21;
}
}
}
if (!grow_up)
new_y1 = y11;
if (!grow_down)
new_y2 = y12;
*win_height = new_y2 - new_y1;
*win_y = new_y1;
}
static void MaximizeWidth(
FvwmWindow *win, unsigned int *win_width, int *win_x, unsigned int win_height,
int win_y, Bool grow_left, Bool grow_right,
int left_border, int right_border)
{
FvwmWindow *cwin;
int x11, x12, x21, x22;
int y11, y12, y21, y22;
int new_x1, new_x2;
Bool is_sticky;
x11 = *win_x; /* Start x */
y11 = win_y; /* Start y */
x12 = x11 + *win_width; /* End x */
y12 = y11 + win_height; /* End y */
new_x1 = left_border;
new_x2 = right_border;
for (cwin = Scr.FvwmRoot.next; cwin; cwin = cwin->next)
{
if (IS_STICKY(cwin) || (IS_ICONIFIED(cwin) && IS_ICON_STICKY(cwin)))
is_sticky = True;
else
is_sticky = False;
if (cwin == win || (cwin->Desk != win->Desk && !is_sticky))
continue;
if (IS_ICONIFIED(cwin))
{
if(cwin->icon_w == None || IS_ICON_UNMAPPED(cwin))
continue;
x21 = cwin->icon_g.x;
y21 = cwin->icon_g.y;
x22 = x21 + cwin->icon_p_width;
y22 = y21 + cwin->icon_p_height + cwin->icon_g.height;
}
else
{
x21 = cwin->frame_g.x;
y21 = cwin->frame_g.y;
x22 = x21 + cwin->frame_g.width;
y22 = y21 + cwin->frame_g.height;
}
if (is_sticky)
{
move_sticky_window_to_same_page(
&new_x1, &new_x2, &y21, &y22, x11, x12, y11, y12);
}
/* Are they in the same Y space? */
if (!((y22 <= y11) || (y21 >= y12)))
{
if ((x22 <= x11) && (x22 >= new_x1))
{
new_x1 = x22;
}
else if ((x12 <= x21) && (new_x2 >= x21))
{
new_x2 = x21;
}
}
}
if (!grow_left)
new_x1 = x11;
if (!grow_right)
new_x2 = x12;
*win_width = new_x2 - new_x1;
*win_x = new_x1;
}
/***********************************************************************
*
* Procedure:
* (Un)Maximize a window.
*
***********************************************************************/
void CMD_Maximize(F_CMD_ARGS)
{
int page_x, page_y;
int val1, val2, val1_unit, val2_unit;
int toggle;
char *token;
char *taction;
Bool grow_up = False;
Bool grow_down = False;
Bool grow_left = False;
Bool grow_right = False;
Bool do_force_maximize = False;
Bool is_screen_given = False;
int scr_x, scr_y, scr_w, scr_h;
rectangle new_g;
FvwmWindow *sf;
if (DeferExecution(eventp,&w,&tmp_win,&context, CRS_SELECT,ButtonRelease))
return;
if (tmp_win == NULL)
return;
if (check_if_function_allowed(F_MAXIMIZE,tmp_win,True,NULL) == 0)
{
XBell(dpy, 0);
return;
}
/* Check for "global" flag ("absolute" is for compatibility with E) */
token = PeekToken(action, &taction);
if (token)
{
if (StrEquals(token, "screen"))
{
int scr;
is_screen_given = True;
token = PeekToken(taction, &action);
scr = FScreenGetScreenArgument(token, FSCREEN_SPEC_PRIMARY);
FScreenGetScrRect(NULL, scr, &scr_x, &scr_y, &scr_w, &scr_h);
}
}
toggle = ParseToggleArgument(action, &action, -1, 0);
if (toggle == 0 && !IS_MAXIMIZED(tmp_win))
return;
if (toggle == 1 && IS_MAXIMIZED(tmp_win))
{
/* Fake that the window is not maximized. */
do_force_maximize = True;
}
/* find the new page and geometry */
new_g.x = tmp_win->frame_g.x;
new_g.y = tmp_win->frame_g.y;
new_g.width = tmp_win->frame_g.width;
new_g.height = tmp_win->frame_g.height;
if (IsRectangleOnThisPage(&tmp_win->frame_g, tmp_win->Desk))
{
/* maximize on visible page if any part of the window is visible */
page_x = 0;
page_y = 0;
}
else
{
int xoff = Scr.Vx % Scr.MyDisplayWidth;
int yoff = Scr.Vy % Scr.MyDisplayHeight;
/* maximize on the page where the center of the window is */
page_x = truncate_to_multiple(
tmp_win->frame_g.x + tmp_win->frame_g.width / 2 + xoff,
Scr.MyDisplayWidth) - xoff;
page_y = truncate_to_multiple(
tmp_win->frame_g.y + tmp_win->frame_g.height / 2 + yoff,
Scr.MyDisplayHeight) - yoff;
}
/* Check if we should constrain rectangle to some Xinerama screen */
if (!is_screen_given)
{
fscreen_scr_arg fscr;
fscr.xypos.x = tmp_win->frame_g.x + tmp_win->frame_g.width / 2 - page_x;
fscr.xypos.y = tmp_win->frame_g.y + tmp_win->frame_g.height / 2 - page_y;
FScreenGetScrRect(&fscr, FSCREEN_XYPOS, &scr_x, &scr_y, &scr_w, &scr_h);
}
#if 0
fprintf(stderr, "%s: page=(%d,%d), scr=(%d,%d, %dx%d)\n", __FUNCTION__,
page_x, page_y, scr_x, scr_y, scr_w, scr_h);
#endif
/* parse first parameter */
val1_unit = scr_w;
token = PeekToken(action, &taction);
if (token && StrEquals(token, "grow"))
{
grow_left = True;
grow_right = True;
val1 = 100;
val1_unit = scr_w;
}
else if (token && StrEquals(token, "growleft"))
{
grow_left = True;
val1 = 100;
val1_unit = scr_w;
}
else if (token && StrEquals(token, "growright"))
{
grow_right = True;
val1 = 100;
val1_unit = scr_w;
}
else
{
if (GetOnePercentArgument(token, &val1, &val1_unit) == 0)
{
val1 = 100;
val1_unit = scr_w;
}
else if (val1 < 0)
{
/* handle negative offsets */
if (val1_unit == scr_w)
{
val1 = 100 + val1;
}
else
{
val1 = scr_w + val1;
}
}
}
/* parse second parameter */
val2_unit = scr_h;
token = PeekToken(taction, NULL);
if (token && StrEquals(token, "grow"))
{
grow_up = True;
grow_down = True;
val2 = 100;
val2_unit = scr_h;
}
else if (token && StrEquals(token, "growup"))
{
grow_up = True;
val2 = 100;
val2_unit = scr_h;
}
else if (token && StrEquals(token, "growdown"))
{
grow_down = True;
val2 = 100;
val2_unit = scr_h;
}
else
{
if (GetOnePercentArgument(token, &val2, &val2_unit) == 0)
{
val2 = 100;
val2_unit = scr_h;
}
else if (val2 < 0)
{
/* handle negative offsets */
if (val2_unit == scr_h)
{
val2 = 100 + val2;
}
else
{
val2 = scr_h + val2;
}
}
}
if (IS_MAXIMIZED(tmp_win) && !do_force_maximize)
{
SET_MAXIMIZED(tmp_win, 0);
get_relative_geometry(&tmp_win->frame_g, &tmp_win->normal_g);
if (IS_SHADED(tmp_win))
get_shaded_geometry(tmp_win, &tmp_win->frame_g, &tmp_win->frame_g);
ForceSetupFrame(
tmp_win, tmp_win->frame_g.x, tmp_win->frame_g.y, tmp_win->frame_g.width,
tmp_win->frame_g.height, True);
DrawDecorations(tmp_win, DRAW_ALL, True, True, None);
}
else /* maximize */
{
/* handle command line arguments */
if (grow_up || grow_down)
{
MaximizeHeight(
tmp_win, new_g.width, new_g.x, (unsigned int *)&new_g.height,
&new_g.y, grow_up, grow_down,
page_y + scr_y, page_y + scr_y + scr_h);
}
else if(val2 > 0)
{
new_g.height = val2 * val2_unit / 100;
new_g.y = page_y + scr_y;
}
if (grow_left || grow_right)
{
MaximizeWidth(
tmp_win, (unsigned int *)&new_g.width, &new_g.x, new_g.height,
new_g.y, grow_left, grow_right,
page_x + scr_x, page_x + scr_x + scr_w);
}
else if(val1 >0)
{
new_g.width = val1 * val1_unit / 100;
new_g.x = page_x + scr_x;
}
if(val1 == 0 && val2 == 0)
{
new_g.x = page_x + scr_x;
new_g.y = page_y + scr_y;
new_g.height = scr_h;
new_g.width = scr_w;
}
/* now maximize it */
SET_MAXIMIZED(tmp_win, 1);
tmp_win->max_g_defect.width = 0;
tmp_win->max_g_defect.height = 0;
constrain_size(tmp_win, (unsigned int *)&new_g.width,
(unsigned int *)&new_g.height, 0, 0, CS_UPDATE_MAX_DEFECT);
tmp_win->max_g = new_g;
if (IS_SHADED(tmp_win))
get_shaded_geometry(tmp_win, &new_g, &tmp_win->max_g);
SetupFrame(
tmp_win, new_g.x, new_g.y, new_g.width, new_g.height, True);
DrawDecorations(tmp_win, DRAW_ALL, (Scr.Hilite == tmp_win), True, None);
update_absolute_geometry(tmp_win);
/* remember the offset between old and new position in case the maximized
* window is moved more than the screen width/height. */
tmp_win->max_offset.x = tmp_win->normal_g.x - tmp_win->max_g.x;
tmp_win->max_offset.y = tmp_win->normal_g.y - tmp_win->max_g.y;
#if 0
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);
#endif
}
if ((sf = get_focus_window()))
{
focus_grab_buttons(sf, True);
}
GNOME_SetWinArea(tmp_win);
}
/* ----------------------------- stick code -------------------------------- */
void handle_stick(F_CMD_ARGS, int toggle)
{
FvwmWindow *sf;
if ((toggle == 1 && IS_STICKY(tmp_win)) ||
(toggle == 0 && !IS_STICKY(tmp_win)))
return;
if(IS_STICKY(tmp_win))
{
SET_STICKY(tmp_win, 0);
tmp_win->Desk = Scr.CurrentDesk;
GNOME_SetDeskCount();
GNOME_SetDesk(tmp_win);
}
else
{
if (tmp_win->Desk != Scr.CurrentDesk)
do_move_window_to_desk(tmp_win, Scr.CurrentDesk);
SET_STICKY(tmp_win, 1);
if (!IsRectangleOnThisPage(&tmp_win->frame_g, Scr.CurrentDesk))
{
action = "";
move_window_doit(F_PASS_ARGS, FALSE, MOVE_PAGE);
/* move_window_doit resets the STICKY flag, so we must set it after the
* call! */
SET_STICKY(tmp_win, 1);
}
}
BroadcastConfig(M_CONFIGURE_WINDOW,tmp_win);
DrawDecorations(
tmp_win, DRAW_TITLE | DRAW_BUTTONS, (Scr.Hilite==tmp_win), True, None);
if ((sf = get_focus_window()))
{
focus_grab_buttons(sf, True);
}
GNOME_SetHints(tmp_win);
}
void CMD_Stick(F_CMD_ARGS)
{
int toggle;
if (DeferExecution(eventp,&w,&tmp_win,&context,CRS_SELECT,ButtonRelease))
return;
toggle = ParseToggleArgument(action, &action, -1, 0);
handle_stick(F_PASS_ARGS, toggle);
}
syntax highlighted by Code2HTML, v. 0.9.1