835 lines
23 KiB
C
835 lines
23 KiB
C
/*
|
|
* 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 windows
|
|
*
|
|
***********************************************************************/
|
|
|
|
#include "config.h"
|
|
|
|
#include <stdio.h>
|
|
#include <signal.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <X11/keysym.h>
|
|
#include "fvwm.h"
|
|
#include "menus.h"
|
|
#include "misc.h"
|
|
#include "parse.h"
|
|
#include "screen.h"
|
|
#include "module.h"
|
|
|
|
extern XEvent Event;
|
|
extern int menuFromFrameOrWindowOrTitlebar;
|
|
Bool NeedToResizeToo;
|
|
|
|
/* 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 */
|
|
|
|
/* 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 */
|
|
void AnimatedMoveOfWindow(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;
|
|
|
|
/* set our defaults */
|
|
if (ppctMovement == NULL) ppctMovement = rgpctMovementDefault;
|
|
if (cmsDelay < 0) cmsDelay = cmsDelayDefault;
|
|
|
|
if (startX < 0 || startY < 0)
|
|
{
|
|
XGetGeometry(dpy, w, &JunkRoot, ¤tX, ¤tY,
|
|
&JunkWidth, &JunkHeight, &JunkBW, &JunkDepth);
|
|
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) return; /* go nowhere fast */
|
|
do {
|
|
currentX = startX + deltaX * (*ppctMovement);
|
|
currentY = startY + deltaY * (*ppctMovement);
|
|
XMoveWindow(dpy,w,currentX,currentY);
|
|
if (fWarpPointerToo == TRUE) {
|
|
XQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,
|
|
&JunkX,&JunkY,&pointerX,&pointerY,&JunkMask);
|
|
pointerX += currentX - lastX;
|
|
pointerY += currentY - lastY;
|
|
XWarpPointer(dpy,None,Scr.Root,0,0,0,0,
|
|
pointerX,pointerY);
|
|
}
|
|
XFlush(dpy);
|
|
usleep(cmsDelay*1000); /* usleep takes microseconds */
|
|
#ifdef GJB_ALLOW_ABORTING_ANIMATED_MOVES
|
|
/* 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 */
|
|
if (XCheckMaskEvent(dpy,
|
|
ButtonPressMask|ButtonReleaseMask|KeyPressMask,
|
|
&Event)) {
|
|
/* finish the move immediately */
|
|
XMoveWindow(dpy,w,endX,endY);
|
|
XFlush(dpy);
|
|
return;
|
|
}
|
|
#endif
|
|
lastX = currentX;
|
|
lastY = currentY;
|
|
}
|
|
while (*ppctMovement != 1.0 && ppctMovement++);
|
|
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* Start a window move operation
|
|
*
|
|
****************************************************************************/
|
|
void move_window_doit(XEvent *eventp,Window w,FvwmWindow *tmp_win,
|
|
unsigned long context, char *action,int* Module,
|
|
Bool fAnimated, Bool fMoveToPage)
|
|
{
|
|
int FinalX, FinalY;
|
|
int n;
|
|
int x,y;
|
|
int width, height;
|
|
int page[2];
|
|
Bool fWarp = FALSE;
|
|
|
|
if (DeferExecution(eventp,&w,&tmp_win,&context, MOVE,ButtonPress))
|
|
return;
|
|
|
|
if (tmp_win == NULL)
|
|
return;
|
|
|
|
/* gotta have a window */
|
|
w = tmp_win->frame;
|
|
if(tmp_win->flags & ICONIFIED)
|
|
{
|
|
if(tmp_win->icon_pixmap_w != None)
|
|
{
|
|
XUnmapWindow(dpy,tmp_win->icon_w);
|
|
w = tmp_win->icon_pixmap_w;
|
|
}
|
|
else
|
|
w = tmp_win->icon_w;
|
|
}
|
|
|
|
XGetGeometry(dpy, w, &JunkRoot, &x, &y,
|
|
&width, &height, &JunkBW, &JunkDepth);
|
|
if (fMoveToPage)
|
|
{
|
|
fAnimated = FALSE;
|
|
FinalX = x % Scr.MyDisplayWidth;
|
|
FinalY = y % Scr.MyDisplayHeight;
|
|
if (GetIntegerArguments(action, NULL, page, 2) == 2)
|
|
{
|
|
if (page[0] < 0 || page[1] < 0 ||
|
|
page[0]*Scr.MyDisplayWidth > Scr.VxMax ||
|
|
page[1]*Scr.MyDisplayHeight > Scr.VyMax)
|
|
{
|
|
fvwm_msg(ERR, "move_window_doit",
|
|
"MoveToPage: invalid page number");
|
|
return;
|
|
}
|
|
tmp_win->flags &= ~STICKY;
|
|
FinalX += page[0]*Scr.MyDisplayWidth - Scr.Vx;
|
|
FinalY += page[1]*Scr.MyDisplayHeight - Scr.Vy;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
n = GetMoveArguments(action,x,y,width+tmp_win->bw,height+tmp_win->bw,
|
|
&FinalX,&FinalY,&fWarp);
|
|
if (n != 2)
|
|
InteractiveMove(&w,tmp_win,&FinalX,&FinalY,eventp);
|
|
}
|
|
|
|
if (w == tmp_win->frame)
|
|
{
|
|
if (fAnimated) {
|
|
AnimatedMoveOfWindow(w,-1,-1,FinalX,FinalY,fWarp,-1,NULL);
|
|
}
|
|
SetupFrame (tmp_win, FinalX, FinalY,
|
|
tmp_win->frame_width, tmp_win->frame_height,FALSE);
|
|
if (fWarp & !fAnimated)
|
|
XWarpPointer(dpy, None, None, 0, 0, 0, 0, FinalX - x, FinalY - y);
|
|
}
|
|
else /* icon window */
|
|
{
|
|
tmp_win->flags |= ICON_MOVED;
|
|
tmp_win->icon_x_loc = FinalX ;
|
|
tmp_win->icon_xl_loc = FinalX -
|
|
(tmp_win->icon_w_width - tmp_win->icon_p_width)/2;
|
|
tmp_win->icon_y_loc = FinalY;
|
|
BroadcastPacket(M_ICON_LOCATION, 7,
|
|
tmp_win->w, tmp_win->frame,
|
|
(unsigned long)tmp_win,
|
|
tmp_win->icon_x_loc, tmp_win->icon_y_loc,
|
|
tmp_win->icon_w_width,
|
|
tmp_win->icon_w_height + tmp_win->icon_p_height);
|
|
if (fAnimated) {
|
|
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 (fAnimated) {
|
|
AnimatedMoveOfWindow(tmp_win->icon_pixmap_w, -1,-1,
|
|
tmp_win->icon_x_loc,FinalY,fWarp,-1,NULL);
|
|
} else {
|
|
XMoveWindow(dpy, tmp_win->icon_pixmap_w, tmp_win->icon_x_loc,
|
|
FinalY);
|
|
if (fWarp)
|
|
XWarpPointer(dpy, None, None, 0, 0, 0, 0, FinalX - x,
|
|
FinalY - y);
|
|
}
|
|
XMapWindow(dpy,w);
|
|
}
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void move_window(XEvent *eventp,Window w,FvwmWindow *tmp_win,
|
|
unsigned long context, char *action,int* Module)
|
|
{
|
|
move_window_doit(eventp,w,tmp_win,context,action,Module,FALSE,FALSE);
|
|
}
|
|
|
|
void animated_move_window(XEvent *eventp,Window w,FvwmWindow *tmp_win,
|
|
unsigned long context, char *action,int* Module)
|
|
{
|
|
move_window_doit(eventp,w,tmp_win,context,action,Module,TRUE,FALSE);
|
|
}
|
|
|
|
void move_window_to_page(XEvent *eventp,Window w,FvwmWindow *tmp_win,
|
|
unsigned long context, char *action,int* Module)
|
|
{
|
|
move_window_doit(eventp,w,tmp_win,context,action,Module,FALSE,TRUE);
|
|
}
|
|
|
|
typedef struct _FvwmMoveable
|
|
{
|
|
int w;
|
|
int h;
|
|
int x;
|
|
int y;
|
|
} FvwmMoveable;
|
|
|
|
/* 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, int Width, int Height,
|
|
int *px, int *py)
|
|
{
|
|
int nyt,nxl,dist,closestLeft,closestRight,closestBottom,closestTop;
|
|
FvwmMoveable self, other;
|
|
FvwmWindow *tmp;
|
|
|
|
/* START OF SNAPATTRACTION BLOCK, mirrored in ButtonRelease */
|
|
/* resist based on window edges */
|
|
tmp = Scr.FvwmRoot.next;
|
|
closestTop = Scr.SnapAttraction;
|
|
closestBottom = Scr.SnapAttraction;
|
|
closestRight = Scr.SnapAttraction;
|
|
closestLeft = Scr.SnapAttraction;
|
|
nxl = -1;
|
|
nyt = -1;
|
|
self.x = *px;
|
|
self.y = *py;
|
|
if(tmp_win->flags&ICONIFIED)
|
|
{
|
|
self.w = Width;
|
|
self.h = Height;
|
|
}
|
|
else
|
|
{
|
|
self.w = Width + 2 * tmp_win->bw;
|
|
self.h = Height + 2 * tmp_win->bw;
|
|
}
|
|
while(Scr.SnapAttraction >= 0 && tmp)
|
|
{
|
|
if(Scr.SnapMode == 0) /* All */
|
|
{
|
|
/* NOOP */
|
|
}
|
|
if(Scr.SnapMode == 1) /* SameType */
|
|
{
|
|
if( (tmp->flags&ICONIFIED) != (tmp_win->flags&ICONIFIED) )
|
|
{ tmp = tmp->next; continue; }
|
|
}
|
|
if(Scr.SnapMode == 2) /* Icons */
|
|
{
|
|
if( !(tmp->flags&ICONIFIED) || !(tmp_win->flags&ICONIFIED) )
|
|
{ tmp = tmp->next; continue; }
|
|
}
|
|
if(Scr.SnapMode == 3) /* Windows */
|
|
{
|
|
if( (tmp->flags&ICONIFIED) || (tmp_win->flags&ICONIFIED) )
|
|
{ tmp = tmp->next; continue; }
|
|
}
|
|
if (tmp_win != tmp && (tmp_win->Desk == tmp->Desk))
|
|
{
|
|
if(tmp->flags&ICONIFIED)
|
|
{
|
|
if(tmp->icon_p_height > 0)
|
|
{
|
|
other.w = tmp->icon_p_width;
|
|
other.h = tmp->icon_p_height;
|
|
}
|
|
else
|
|
{
|
|
other.w = tmp->icon_w_width;
|
|
other.h = tmp->icon_w_height;
|
|
}
|
|
other.x = tmp->icon_x_loc;
|
|
other.y = tmp->icon_y_loc;
|
|
}
|
|
else
|
|
{
|
|
other.w = tmp->frame_width + 2 * tmp->bw;
|
|
other.h = tmp->frame_height + 2 * tmp->bw;
|
|
other.x = tmp->frame_x;
|
|
other.y = tmp->frame_y;
|
|
}
|
|
if(!((other.y + other.h) < (*py) ||
|
|
(other.y) > (*py + self.h) ))
|
|
{
|
|
dist = abs(other.x - (*px + self.w));
|
|
if(dist < closestRight)
|
|
{
|
|
closestRight = dist;
|
|
if(((*px + self.w) >= other.x)&&
|
|
((*px + self.w) < other.x+Scr.SnapAttraction))
|
|
nxl = other.x - self.w;
|
|
|
|
if(((*px + self.w) >= other.x - Scr.SnapAttraction)&&
|
|
((*px + self.w) < other.x))
|
|
nxl = other.x - self.w;
|
|
}
|
|
dist = abs(other.x + other.w - *px);
|
|
if(dist < closestLeft)
|
|
{
|
|
closestLeft = dist;
|
|
if((*px <= other.x + other.w)&&
|
|
(*px > other.x + other.w - Scr.SnapAttraction))
|
|
nxl = other.x + other.w;
|
|
if((*px <= other.x + other.w + Scr.SnapAttraction)&&
|
|
(*px > other.x + other.w))
|
|
nxl = other.x + other.w;
|
|
}
|
|
}
|
|
if(!((other.x + other.w) < (*px) || (other.x) > (*px + self.w) ))
|
|
{
|
|
dist = abs(other.y - (*py + self.h));
|
|
if(dist < closestBottom)
|
|
{
|
|
closestBottom = dist;
|
|
if(((*py + self.h) >= other.y)&&
|
|
((*py + self.h) < other.y+Scr.SnapAttraction))
|
|
nyt = other.y - self.h;
|
|
if(((*py + self.h) >= other.y - Scr.SnapAttraction)&&
|
|
((*py + self.h) < other.y))
|
|
nyt = other.y - self.h;
|
|
}
|
|
dist = abs(other.y + other.h - *py);
|
|
if(dist < closestTop)
|
|
{
|
|
closestTop = dist;
|
|
if((*py <= other.y + other.h)&&
|
|
(*py > other.y + other.h - Scr.SnapAttraction))
|
|
nyt = other.y + other.h;
|
|
if((*py <= other.y + other.h + Scr.SnapAttraction)&&
|
|
(*py > other.y + other.h))
|
|
nyt = other.y + other.h;
|
|
}
|
|
}
|
|
}
|
|
tmp = tmp->next;
|
|
}
|
|
if(nxl == -1)
|
|
{
|
|
if(*px != *px / Scr.SnapGridX * Scr.SnapGridX)
|
|
{
|
|
*px = (*px+Scr.SnapGridX/2) / Scr.SnapGridX * Scr.SnapGridX;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*px = nxl;
|
|
}
|
|
if(nyt == -1)
|
|
{
|
|
if(*py != *py / Scr.SnapGridY * Scr.SnapGridY)
|
|
{
|
|
*py = (*py+Scr.SnapGridY/2) / Scr.SnapGridY * Scr.SnapGridY;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
*py = nyt;
|
|
}
|
|
/* END OF SNAPATTRACTION BLOCK, mirrored in ButtonRelease */
|
|
}
|
|
|
|
/****************************************************************************
|
|
*
|
|
* Move the rubberband around, return with the new window location
|
|
*
|
|
****************************************************************************/
|
|
void moveLoop(FvwmWindow *tmp_win, int XOffset, int YOffset, int Width,
|
|
int Height, int *FinalX, int *FinalY,Bool opaque_move,
|
|
Bool AddWindow)
|
|
{
|
|
Bool finished = False;
|
|
Bool done;
|
|
int xl,yt,delta_x,delta_y,paged;
|
|
unsigned int button_mask = 0;
|
|
unsigned int bw = tmp_win->bw;
|
|
|
|
XQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild,&xl, &yt,
|
|
&JunkX, &JunkY, &button_mask);
|
|
button_mask &= Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask;
|
|
xl += XOffset;
|
|
yt += YOffset;
|
|
|
|
if(((!opaque_move)&&(!Scr.gs.EmulateMWM))||(AddWindow))
|
|
MoveOutline(Scr.Root, xl, yt, Width - 1 + 2 * bw, Height - 1 + 2 * bw);
|
|
|
|
DisplayPosition(tmp_win,xl,yt,True);
|
|
|
|
while (!finished)
|
|
{
|
|
/* block until there is an interesting event */
|
|
XMaskEvent(dpy, ButtonPressMask | ButtonReleaseMask | KeyPressMask |
|
|
PointerMotionMask | ButtonMotionMask | ExposureMask, &Event);
|
|
StashEventTime(&Event);
|
|
|
|
/* discard any extra motion events before a logical release */
|
|
if (Event.type == MotionNotify)
|
|
{
|
|
while(XCheckMaskEvent(dpy, PointerMotionMask | ButtonMotionMask |
|
|
ButtonPressMask |ButtonRelease, &Event))
|
|
{
|
|
StashEventTime(&Event);
|
|
if(Event.type == ButtonRelease) break;
|
|
}
|
|
}
|
|
|
|
done = FALSE;
|
|
/* Handle a limited number of key press events to allow mouseless
|
|
* operation */
|
|
if (Event.type == KeyPress)
|
|
Keyboard_shortcuts(&Event, tmp_win, ButtonRelease);
|
|
switch(Event.type)
|
|
{
|
|
case KeyPress:
|
|
/* simple code to bag out of move - CKH */
|
|
if (XLookupKeysym(&(Event.xkey),0) == XK_Escape)
|
|
{
|
|
if(!opaque_move)
|
|
MoveOutline(Scr.Root, 0, 0, 0, 0);
|
|
*FinalX = tmp_win->frame_x;
|
|
*FinalY = tmp_win->frame_y;
|
|
finished = TRUE;
|
|
}
|
|
done = TRUE;
|
|
break;
|
|
case ButtonPress:
|
|
XAllowEvents(dpy,ReplayPointer,CurrentTime);
|
|
if (((Event.xbutton.button == 1) && (button_mask & Button1Mask)) ||
|
|
((Event.xbutton.button == 2) && (button_mask & Button2Mask)) ||
|
|
((Event.xbutton.button == 3) && (button_mask & Button3Mask)) ||
|
|
((Event.xbutton.button == 4) && (button_mask & Button4Mask)) ||
|
|
((Event.xbutton.button == 5) && (button_mask & Button5Mask)))
|
|
{
|
|
/* No new button was pressed, just a delayed event */
|
|
done = 1;
|
|
break;
|
|
}
|
|
if(((Event.xbutton.button == 2)&&(!Scr.gs.EmulateMWM))||
|
|
((Event.xbutton.button == 1)&&(Scr.gs.EmulateMWM)&&
|
|
(Event.xbutton.state & ShiftMask)))
|
|
{
|
|
NeedToResizeToo = 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 started at the beginning and any button
|
|
* except button 1 was pressed. */
|
|
if (button_mask || (Event.xbutton.button != 1))
|
|
{
|
|
if(!opaque_move)
|
|
MoveOutline(Scr.Root, 0, 0, 0, 0);
|
|
*FinalX = tmp_win->frame_x;
|
|
*FinalY = tmp_win->frame_y;
|
|
finished = TRUE;
|
|
}
|
|
done = 1;
|
|
break;
|
|
}
|
|
case ButtonRelease:
|
|
if(!opaque_move)
|
|
MoveOutline(Scr.Root, 0, 0, 0, 0);
|
|
xl = Event.xmotion.x_root + XOffset;
|
|
yt = Event.xmotion.y_root + YOffset;
|
|
|
|
DoSnapAttract(tmp_win, Width, Height, &xl, &yt);
|
|
|
|
/* Resist moving windows over the edge of the screen! */
|
|
if(((xl + Width) >= Scr.MyDisplayWidth)&&
|
|
((xl + Width) < Scr.MyDisplayWidth+Scr.MoveResistance))
|
|
xl = Scr.MyDisplayWidth - Width - 2 * bw;
|
|
if((xl <= 0)&&(xl > -Scr.MoveResistance))
|
|
xl = 0;
|
|
if(((yt + Height) >= Scr.MyDisplayHeight)&&
|
|
((yt + Height) < Scr.MyDisplayHeight+Scr.MoveResistance))
|
|
yt = Scr.MyDisplayHeight - Height - 2 * bw;
|
|
if((yt <= 0)&&(yt > -Scr.MoveResistance))
|
|
yt = 0;
|
|
|
|
*FinalX = xl;
|
|
*FinalY = yt;
|
|
|
|
done = TRUE;
|
|
finished = TRUE;
|
|
break;
|
|
|
|
case MotionNotify:
|
|
xl = Event.xmotion.x_root;
|
|
yt = Event.xmotion.y_root;
|
|
/* HandlePaging(Scr.MyDisplayWidth,Scr.MyDisplayHeight,&xl,&yt,
|
|
&delta_x,&delta_y,False); mab */
|
|
/* redraw the rubberband */
|
|
xl += XOffset;
|
|
yt += YOffset;
|
|
|
|
DoSnapAttract(tmp_win, Width, Height, &xl, &yt);
|
|
|
|
/* Resist moving windows over the edge of the screen! */
|
|
if(((xl + Width) >= Scr.MyDisplayWidth)&&
|
|
((xl + Width) < Scr.MyDisplayWidth+Scr.MoveResistance))
|
|
xl = Scr.MyDisplayWidth - Width - 2 * bw;
|
|
if((xl <= 0)&&(xl > -Scr.MoveResistance))
|
|
xl = 0;
|
|
if(((yt + Height) >= Scr.MyDisplayHeight)&&
|
|
((yt + Height) < Scr.MyDisplayHeight+Scr.MoveResistance))
|
|
yt = Scr.MyDisplayHeight - Height - 2 * bw;
|
|
if((yt <= 0)&&(yt > -Scr.MoveResistance))
|
|
yt = 0;
|
|
|
|
/* check Paging request once and only once after outline redrawn */
|
|
/* redraw after paging if needed - mab */
|
|
paged=0;
|
|
while(paged<=1)
|
|
{
|
|
if(!opaque_move)
|
|
MoveOutline(Scr.Root, xl, yt, Width - 1 + 2 * bw, Height - 1 + 2 * bw);
|
|
else
|
|
{
|
|
if (tmp_win->flags & ICONIFIED)
|
|
{
|
|
tmp_win->icon_x_loc = xl ;
|
|
tmp_win->icon_xl_loc = xl -
|
|
(tmp_win->icon_w_width - tmp_win->icon_p_width)/2;
|
|
tmp_win->icon_y_loc = yt;
|
|
if(tmp_win->icon_pixmap_w != None)
|
|
XMoveWindow (dpy, tmp_win->icon_pixmap_w,
|
|
tmp_win->icon_x_loc,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,xl,yt,False);
|
|
|
|
/* prevent window from lagging behind mouse when paging - mab */
|
|
if(paged==0)
|
|
{
|
|
int dx;
|
|
int dy;
|
|
|
|
xl = Event.xmotion.x_root;
|
|
yt = Event.xmotion.y_root;
|
|
dx = Scr.EdgeScrollX ? Scr.EdgeScrollX : Scr.MyDisplayWidth;
|
|
dy = Scr.EdgeScrollY ? Scr.EdgeScrollY : Scr.MyDisplayHeight;
|
|
HandlePaging(dx, dy, &xl,&yt, &delta_x,&delta_y,False);
|
|
xl += XOffset;
|
|
yt += YOffset;
|
|
if ( (delta_x==0) && (delta_y==0))
|
|
/* break from while paged */
|
|
break;
|
|
}
|
|
paged++;
|
|
} /* end while paged */
|
|
|
|
done = TRUE;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
} /* switch */
|
|
if(!done)
|
|
{
|
|
if(!opaque_move)
|
|
MoveOutline(Scr.Root,0,0,0,0);
|
|
DispatchEvent();
|
|
if(!opaque_move)
|
|
MoveOutline(Scr.Root, xl, yt, Width - 1 + 2 * bw, Height - 1 + 2 * bw);
|
|
}
|
|
}
|
|
if (!NeedToResizeToo)
|
|
/* Don't wait for buttons to come up when user is placing a new window
|
|
* and wants to resize it. */
|
|
WaitForButtonsUp();
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* Procedure:
|
|
* DisplayPosition - display the position in the dimensions window
|
|
*
|
|
* Inputs:
|
|
* tmp_win - the current fvwm window
|
|
* x, y - position of the window
|
|
*
|
|
************************************************************************/
|
|
|
|
void DisplayPosition (FvwmWindow *tmp_win, int x, int y,int Init)
|
|
{
|
|
char str [100];
|
|
int offset;
|
|
|
|
(void) snprintf (str, sizeof(str), " %+-4d %+-4d ", x, y);
|
|
if(Init)
|
|
{
|
|
XClearWindow(dpy,Scr.SizeWindow);
|
|
if(Scr.d_depth >= 2)
|
|
RelieveWindow(tmp_win,Scr.SizeWindow,0,0,
|
|
Scr.SizeStringWidth+ SIZE_HINDENT*2,
|
|
Scr.StdFont.height + SIZE_VINDENT*2,
|
|
Scr.StdReliefGC,
|
|
Scr.StdShadowGC, FULL_HILITE);
|
|
|
|
}
|
|
else
|
|
{
|
|
XClearArea(dpy,Scr.SizeWindow,SIZE_HINDENT,SIZE_VINDENT,
|
|
Scr.SizeStringWidth, Scr.StdFont.height,False);
|
|
}
|
|
|
|
offset = (Scr.SizeStringWidth + SIZE_HINDENT*2
|
|
- XTextWidth(Scr.StdFont.font,str,strlen(str)))/2;
|
|
XDrawString (dpy, Scr.SizeWindow, Scr.StdGC,
|
|
offset,
|
|
Scr.StdFont.font->ascent + SIZE_VINDENT,
|
|
str, strlen(str));
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* For menus, move, and resize operations, we can effect keyboard
|
|
* shortcuts by warping the pointer.
|
|
*
|
|
****************************************************************************/
|
|
void Keyboard_shortcuts(XEvent *Event, FvwmWindow *w, int ReturnEvent)
|
|
{
|
|
int x,y,x_root,y_root;
|
|
int x_move_size = 0, y_move_size = 0;
|
|
int x_move,y_move;
|
|
|
|
KeySym keysym;
|
|
|
|
if (w)
|
|
{
|
|
x_move_size = w->hints.width_inc;
|
|
y_move_size = w->hints.height_inc;
|
|
}
|
|
if (y_move_size < 5) y_move_size = 5;
|
|
if (x_move_size < 5) x_move_size = 5;
|
|
if(Event->xkey.state & ControlMask)
|
|
x_move_size = y_move_size = 1;
|
|
if(Event->xkey.state & ShiftMask)
|
|
x_move_size = y_move_size = 100;
|
|
|
|
keysym = XLookupKeysym(&Event->xkey,0);
|
|
|
|
x_move = 0;
|
|
y_move = 0;
|
|
switch(keysym)
|
|
{
|
|
case XK_Up:
|
|
case XK_KP_8:
|
|
case XK_k:
|
|
case XK_p:
|
|
y_move = -y_move_size;
|
|
break;
|
|
case XK_Down:
|
|
case XK_KP_2:
|
|
case XK_n:
|
|
case XK_j:
|
|
y_move = y_move_size;
|
|
break;
|
|
case XK_Left:
|
|
case XK_KP_4:
|
|
case XK_b:
|
|
case XK_h:
|
|
x_move = -x_move_size;
|
|
break;
|
|
case XK_Right:
|
|
case XK_KP_6:
|
|
case XK_f:
|
|
case XK_l:
|
|
x_move = x_move_size;
|
|
break;
|
|
case XK_KP_1:
|
|
x_move = -x_move_size;
|
|
y_move = y_move_size;
|
|
break;
|
|
case XK_KP_3:
|
|
x_move = x_move_size;
|
|
y_move = y_move_size;
|
|
break;
|
|
case XK_KP_7:
|
|
x_move = -x_move_size;
|
|
y_move = -y_move_size;
|
|
break;
|
|
case XK_KP_9:
|
|
x_move = x_move_size;
|
|
y_move = -y_move_size;
|
|
break;
|
|
case XK_Return:
|
|
case XK_KP_Enter:
|
|
case XK_space:
|
|
/* beat up the event */
|
|
Event->type = ReturnEvent;
|
|
break;
|
|
case XK_Escape:
|
|
/* simple code to bag out of move - CKH */
|
|
/* return keypress event instead */
|
|
Event->type = KeyPress;
|
|
Event->xkey.keycode = XKeysymToKeycode(Event->xkey.display,keysym);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
XQueryPointer( dpy, Scr.Root, &JunkRoot, &Event->xany.window,
|
|
&x_root, &y_root, &x, &y, &JunkMask);
|
|
|
|
if((x_move != 0)||(y_move != 0))
|
|
{
|
|
/* beat up the event */
|
|
XWarpPointer(dpy, None, Scr.Root, 0, 0, 0, 0, x_root+x_move,
|
|
y_root+y_move);
|
|
|
|
/* beat up the event */
|
|
Event->type = MotionNotify;
|
|
Event->xkey.x += x_move;
|
|
Event->xkey.y += y_move;
|
|
Event->xkey.x_root += x_move;
|
|
Event->xkey.y_root += y_move;
|
|
}
|
|
}
|
|
|
|
|
|
void InteractiveMove(Window *win, FvwmWindow *tmp_win, int *FinalX, int *FinalY, XEvent *eventp)
|
|
{
|
|
int origDragX,origDragY,DragX, DragY, DragWidth, DragHeight;
|
|
int XOffset, YOffset;
|
|
Window w;
|
|
|
|
Bool opaque_move = False;
|
|
|
|
w = *win;
|
|
|
|
InstallRootColormap();
|
|
if (menuFromFrameOrWindowOrTitlebar)
|
|
{
|
|
/* warp the pointer to the cursor position from before menu appeared*/
|
|
XFlush(dpy);
|
|
}
|
|
|
|
/* Although a move is usually done with a button depressed we have to check
|
|
* for ButtonRelease too since the event may be faked. */
|
|
if (eventp->type == ButtonPress || eventp->type == ButtonRelease)
|
|
{
|
|
DragX = eventp->xbutton.x_root;
|
|
DragY = eventp->xbutton.y_root;
|
|
}
|
|
else
|
|
XQueryPointer(dpy, Scr.Root, &JunkRoot, &JunkChild, &DragX, &DragY,
|
|
&JunkX, &JunkY, &JunkMask);
|
|
|
|
if(!GrabEm(MOVE))
|
|
{
|
|
XBell(dpy, 0);
|
|
return;
|
|
}
|
|
|
|
XGetGeometry(dpy, w, &JunkRoot, &origDragX, &origDragY,
|
|
(unsigned int *)&DragWidth, (unsigned int *)&DragHeight,
|
|
&JunkBW, &JunkDepth);
|
|
|
|
if(DragWidth*DragHeight <
|
|
(Scr.OpaqueSize*Scr.MyDisplayWidth*Scr.MyDisplayHeight)/100)
|
|
opaque_move = True;
|
|
else
|
|
MyXGrabServer(dpy);
|
|
|
|
if((!opaque_move)&&(tmp_win->flags & ICONIFIED))
|
|
XUnmapWindow(dpy,w);
|
|
|
|
XOffset = origDragX - DragX;
|
|
YOffset = origDragY - DragY;
|
|
XMapRaised(dpy,Scr.SizeWindow);
|
|
moveLoop(tmp_win, XOffset,YOffset,DragWidth,DragHeight, FinalX,FinalY,
|
|
opaque_move,False);
|
|
|
|
XUnmapWindow(dpy,Scr.SizeWindow);
|
|
UninstallRootColormap();
|
|
|
|
if(!opaque_move)
|
|
MyXUngrabServer(dpy);
|
|
UngrabEm();
|
|
|
|
}
|