1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-19 12:28:22 +01:00
Files
wmaker/src/moveres.c
Carlos R. Mafra 0350b8445a Remove unneeded extern's in .c files
They were not being used in those files, so let's remove them.
2010-04-14 18:39:28 +02:00

2256 lines
61 KiB
C

/*
* Window Maker window manager
*
* Copyright (c) 1997-2003 Alfredo K. Kojima
*
* 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.
*/
#include "wconfig.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "WindowMaker.h"
#include "framewin.h"
#include "window.h"
#include "client.h"
#include "icon.h"
#include "dock.h"
#include "funcs.h"
#include "actions.h"
#include "workspace.h"
#include "geomview.h"
#include "screen.h"
#include "xinerama.h"
#include <WINGs/WINGsP.h>
/* How many different types of geometry/position
display thingies are there? */
#define NUM_DISPLAYS 5
#define LEFT 1
#define RIGHT 2
#define HORIZONTAL (LEFT|RIGHT)
#define UP 4
#define DOWN 8
#define VERTICAL (UP|DOWN)
/* True if window currently has a border. This also includes borderless
* windows which are currently selected
*/
#define HAS_BORDER_WITH_SELECT(w) ((w)->flags.selected || HAS_BORDER(w))
/****** Global Variables ******/
extern Cursor wCursor[WCUR_LAST];
extern WPreferences wPreferences;
/*
*----------------------------------------------------------------------
* checkMouseSamplingRate-
* For lowering the mouse motion sampling rate for machines where
* it's too high (SGIs). If it returns False then the event should be
* ignored.
*----------------------------------------------------------------------
*/
static Bool checkMouseSamplingRate(XEvent * ev)
{
static Time previousMotion = 0;
if (ev->type == MotionNotify) {
if (ev->xmotion.time - previousMotion < DELAY_BETWEEN_MOUSE_SAMPLING) {
return False;
} else {
previousMotion = ev->xmotion.time;
}
}
return True;
}
/*
*----------------------------------------------------------------------
* moveGeometryDisplayCentered
*
* routine that moves the geometry/position window on scr so it is
* centered over the given coordinates (x,y). Also the window position
* is clamped so it stays on the screen at all times.
*----------------------------------------------------------------------
*/
static void moveGeometryDisplayCentered(WScreen * scr, int x, int y)
{
unsigned int w = WMWidgetWidth(scr->gview);
unsigned int h = WMWidgetHeight(scr->gview);
int x1 = 0, y1 = 0, x2 = scr->scr_width, y2 = scr->scr_height;
x -= w / 2;
y -= h / 2;
/* dead area check */
if (scr->xine_info.count) {
WMRect rect;
int head, flags;
rect.pos.x = x;
rect.pos.y = y;
rect.size.width = w;
rect.size.height = h;
head = wGetRectPlacementInfo(scr, rect, &flags);
if (flags & (XFLAG_DEAD | XFLAG_PARTIAL)) {
rect = wGetRectForHead(scr, head);
x1 = rect.pos.x;
y1 = rect.pos.y;
x2 = x1 + rect.size.width;
y2 = y1 + rect.size.height;
}
}
if (x < x1 + 1)
x = x1 + 1;
else if (x > (x2 - w))
x = x2 - w;
if (y < y1 + 1)
y = y1 + 1;
else if (y > (y2 - h))
y = y2 - h;
WMMoveWidget(scr->gview, x, y);
}
static void showPosition(WWindow * wwin, int x, int y)
{
WScreen *scr = wwin->screen_ptr;
if (wPreferences.move_display == WDIS_NEW) {
#if 0
int width = wwin->frame->core->width;
int height = wwin->frame->core->height;
GC lgc = scr->line_gc;
XSetForeground(dpy, lgc, scr->line_pixel);
sprintf(num, "%i", x);
XDrawLine(dpy, scr->root_win, lgc, 0, y - 1, scr->scr_width, y - 1);
XDrawLine(dpy, scr->root_win, lgc, 0, y + height + 2, scr->scr_width, y + height + 2);
XDrawLine(dpy, scr->root_win, lgc, x - 1, 0, x - 1, scr->scr_height);
XDrawLine(dpy, scr->root_win, lgc, x + width + 2, 0, x + width + 2, scr->scr_height);
#endif
} else {
WSetGeometryViewShownPosition(scr->gview, x, y);
}
}
static void cyclePositionDisplay(WWindow * wwin, int x, int y, int w, int h)
{
WScreen *scr = wwin->screen_ptr;
WMRect rect;
wPreferences.move_display++;
wPreferences.move_display %= NUM_DISPLAYS;
if (wPreferences.move_display == WDIS_NEW) {
wPreferences.move_display++;
wPreferences.move_display %= NUM_DISPLAYS;
}
if (wPreferences.move_display == WDIS_NONE) {
WMUnmapWidget(scr->gview);
} else {
if (wPreferences.move_display == WDIS_CENTER) {
rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width / 2,
rect.pos.y + rect.size.height / 2);
} else if (wPreferences.move_display == WDIS_TOPLEFT) {
rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
} else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
moveGeometryDisplayCentered(scr, x + w / 2, y + h / 2);
}
WMMapWidget(scr->gview);
}
}
static void mapPositionDisplay(WWindow * wwin, int x, int y, int w, int h)
{
WScreen *scr = wwin->screen_ptr;
WMRect rect;
if (wPreferences.move_display == WDIS_NEW || wPreferences.move_display == WDIS_NONE) {
return;
} else if (wPreferences.move_display == WDIS_CENTER) {
rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width / 2,
rect.pos.y + rect.size.height / 2);
} else if (wPreferences.move_display == WDIS_TOPLEFT) {
rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
} else if (wPreferences.move_display == WDIS_FRAME_CENTER) {
moveGeometryDisplayCentered(scr, x + w / 2, y + h / 2);
}
WMMapWidget(scr->gview);
WSetGeometryViewShownPosition(scr->gview, x, y);
}
static void showGeometry(WWindow * wwin, int x1, int y1, int x2, int y2, int direction)
{
WScreen *scr = wwin->screen_ptr;
Window root = scr->root_win;
GC gc = scr->line_gc;
int ty, by, my, x, y, mx, s;
char num[16];
XSegment segment[4];
int fw, fh;
/* This seems necessary for some odd reason (too lazy to write x1-1 and
* x2-1 everywhere below in the code). But why only for x? */
x1--;
x2--;
if (HAS_BORDER_WITH_SELECT(wwin)) {
x1 += FRAME_BORDER_WIDTH;
x2 += FRAME_BORDER_WIDTH;
y1 += FRAME_BORDER_WIDTH;
y2 += FRAME_BORDER_WIDTH;
}
ty = y1 + wwin->frame->top_width;
by = y2 - wwin->frame->bottom_width;
if (wPreferences.size_display == WDIS_NEW) {
fw = XTextWidth(scr->tech_draw_font, "8888", 4);
fh = scr->tech_draw_font->ascent + scr->tech_draw_font->descent;
XSetForeground(dpy, gc, scr->line_pixel);
/* vertical geometry */
if (((direction & LEFT) && (x2 < scr->scr_width - fw)) || (x1 < fw)) {
x = x2;
s = -15;
} else {
x = x1;
s = 15;
}
my = (ty + by) / 2;
/* top arrow & end bar */
segment[0].x1 = x - (s + 6);
segment[0].y1 = ty;
segment[0].x2 = x - (s - 10);
segment[0].y2 = ty;
/* arrowhead */
segment[1].x1 = x - (s - 2);
segment[1].y1 = ty + 1;
segment[1].x2 = x - (s - 5);
segment[1].y2 = ty + 7;
segment[2].x1 = x - (s - 2);
segment[2].y1 = ty + 1;
segment[2].x2 = x - (s + 1);
segment[2].y2 = ty + 7;
/* line */
segment[3].x1 = x - (s - 2);
segment[3].y1 = ty + 1;
segment[3].x2 = x - (s - 2);
segment[3].y2 = my - fh / 2 - 1;
XDrawSegments(dpy, root, gc, segment, 4);
/* bottom arrow & end bar */
segment[0].y1 = by;
segment[0].y2 = by;
/* arrowhead */
segment[1].y1 = by - 1;
segment[1].y2 = by - 7;
segment[2].y1 = by - 1;
segment[2].y2 = by - 7;
/* line */
segment[3].y1 = my + fh / 2 + 2;
segment[3].y2 = by - 1;
XDrawSegments(dpy, root, gc, segment, 4);
snprintf(num, sizeof(num), "%i", (by - ty - wwin->normal_hints->base_height) /
wwin->normal_hints->height_inc);
fw = XTextWidth(scr->tech_draw_font, num, strlen(num));
/* Display the height. */
XSetFont(dpy, gc, scr->tech_draw_font->fid);
XDrawString(dpy, root, gc, x - s + 3 - fw / 2, my + scr->tech_draw_font->ascent - fh / 2 + 1, num,
strlen(num));
/* horizontal geometry */
if (y1 < 15) {
y = y2;
s = -15;
} else {
y = y1;
s = 15;
}
mx = x1 + (x2 - x1) / 2;
snprintf(num, sizeof(num), "%i", (x2 - x1 - wwin->normal_hints->base_width) /
wwin->normal_hints->width_inc);
fw = XTextWidth(scr->tech_draw_font, num, strlen(num));
/* left arrow & end bar */
segment[0].x1 = x1;
segment[0].y1 = y - (s + 6);
segment[0].x2 = x1;
segment[0].y2 = y - (s - 10);
/* arrowhead */
segment[1].x1 = x1 + 7;
segment[1].y1 = y - (s + 1);
segment[1].x2 = x1 + 1;
segment[1].y2 = y - (s - 2);
segment[2].x1 = x1 + 1;
segment[2].y1 = y - (s - 2);
segment[2].x2 = x1 + 7;
segment[2].y2 = y - (s - 5);
/* line */
segment[3].x1 = x1 + 1;
segment[3].y1 = y - (s - 2);
segment[3].x2 = mx - fw / 2 - 2;
segment[3].y2 = y - (s - 2);
XDrawSegments(dpy, root, gc, segment, 4);
/* right arrow & end bar */
segment[0].x1 = x2 + 1;
segment[0].x2 = x2 + 1;
/* arrowhead */
segment[1].x1 = x2 - 6;
segment[1].x2 = x2;
segment[2].x1 = x2;
segment[2].x2 = x2 - 6;
/* line */
segment[3].x1 = mx + fw / 2 + 2;
segment[3].x2 = x2;
XDrawSegments(dpy, root, gc, segment, 4);
/* Display the width. */
XDrawString(dpy, root, gc, mx - fw / 2 + 1, y - s + scr->tech_draw_font->ascent - fh / 2 + 1, num,
strlen(num));
} else {
WSetGeometryViewShownSize(scr->gview, (x2 - x1 - wwin->normal_hints->base_width)
/ wwin->normal_hints->width_inc,
(by - ty - wwin->normal_hints->base_height)
/ wwin->normal_hints->height_inc);
}
}
static void cycleGeometryDisplay(WWindow * wwin, int x, int y, int w, int h, int dir)
{
WScreen *scr = wwin->screen_ptr;
WMRect rect;
wPreferences.size_display++;
wPreferences.size_display %= NUM_DISPLAYS;
if (wPreferences.size_display == WDIS_NEW || wPreferences.size_display == WDIS_NONE) {
WMUnmapWidget(scr->gview);
} else {
if (wPreferences.size_display == WDIS_CENTER) {
rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width / 2,
rect.pos.y + rect.size.height / 2);
} else if (wPreferences.size_display == WDIS_TOPLEFT) {
rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
} else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
moveGeometryDisplayCentered(scr, x + w / 2, y + h / 2);
}
WMMapWidget(scr->gview);
showGeometry(wwin, x, y, x + w, y + h, dir);
}
}
static void mapGeometryDisplay(WWindow * wwin, int x, int y, int w, int h)
{
WScreen *scr = wwin->screen_ptr;
WMRect rect;
if (wPreferences.size_display == WDIS_NEW || wPreferences.size_display == WDIS_NONE)
return;
if (wPreferences.size_display == WDIS_CENTER) {
rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
moveGeometryDisplayCentered(scr, rect.pos.x + rect.size.width / 2,
rect.pos.y + rect.size.height / 2);
} else if (wPreferences.size_display == WDIS_TOPLEFT) {
rect = wGetRectForHead(scr, wGetHeadForWindow(wwin));
moveGeometryDisplayCentered(scr, rect.pos.x + 1, rect.pos.y + 1);
} else if (wPreferences.size_display == WDIS_FRAME_CENTER) {
moveGeometryDisplayCentered(scr, x + w / 2, y + h / 2);
}
WMMapWidget(scr->gview);
showGeometry(wwin, x, y, x + w, y + h, 0);
}
static void doWindowMove(WWindow * wwin, WMArray * array, int dx, int dy)
{
WWindow *tmpw;
WScreen *scr = wwin->screen_ptr;
int x, y;
if (!array || !WMGetArrayItemCount(array)) {
wWindowMove(wwin, wwin->frame_x + dx, wwin->frame_y + dy);
} else {
WMArrayIterator iter;
WM_ITERATE_ARRAY(array, tmpw, iter) {
x = tmpw->frame_x + dx;
y = tmpw->frame_y + dy;
#if 1 /* XXX: with xinerama patch was #if 0, check this */
/* don't let windows become unreachable */
if (x + (int)tmpw->frame->core->width < 20)
x = 20 - (int)tmpw->frame->core->width;
else if (x + 20 > scr->scr_width)
x = scr->scr_width - 20;
if (y + (int)tmpw->frame->core->height < 20)
y = 20 - (int)tmpw->frame->core->height;
else if (y + 20 > scr->scr_height)
y = scr->scr_height - 20;
#else
wScreenBringInside(scr, &x, &y,
(int)tmpw->frame->core->width, (int)tmpw->frame->core->height);
#endif
wWindowMove(tmpw, x, y);
}
}
}
static void drawTransparentFrame(WWindow * wwin, int x, int y, int width, int height)
{
Window root = wwin->screen_ptr->root_win;
GC gc = wwin->screen_ptr->frame_gc;
int h = 0;
int bottom = 0;
if (HAS_BORDER_WITH_SELECT(wwin)) {
x += FRAME_BORDER_WIDTH;
y += FRAME_BORDER_WIDTH;
}
if (HAS_TITLEBAR(wwin) && !wwin->flags.shaded) {
h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance +
TITLEBAR_EXTEND_SPACE) * 2;
}
if (HAS_RESIZEBAR(wwin) && !wwin->flags.shaded) {
/* Can't use wwin-frame->bottom_width because, in some cases
(e.g. interactive placement), frame does not point to anything. */
bottom = RESIZEBAR_HEIGHT;
}
XDrawRectangle(dpy, root, gc, x - 1, y - 1, width + 1, height + 1);
if (h > 0) {
XDrawLine(dpy, root, gc, x, y + h - 1, x + width, y + h - 1);
}
if (bottom > 0) {
XDrawLine(dpy, root, gc, x, y + height - bottom, x + width, y + height - bottom);
}
}
static void drawFrames(WWindow * wwin, WMArray * array, int dx, int dy)
{
WWindow *tmpw;
int scr_width = wwin->screen_ptr->scr_width;
int scr_height = wwin->screen_ptr->scr_height;
int x, y;
if (!array) {
x = wwin->frame_x + dx;
y = wwin->frame_y + dy;
drawTransparentFrame(wwin, x, y, wwin->frame->core->width, wwin->frame->core->height);
} else {
WMArrayIterator iter;
WM_ITERATE_ARRAY(array, tmpw, iter) {
x = tmpw->frame_x + dx;
y = tmpw->frame_y + dy;
/* don't let windows become unreachable */
#if 1 /* XXX: was 0 in XINERAMA patch, check */
if (x + (int)tmpw->frame->core->width < 20)
x = 20 - (int)tmpw->frame->core->width;
else if (x + 20 > scr_width)
x = scr_width - 20;
if (y + (int)tmpw->frame->core->height < 20)
y = 20 - (int)tmpw->frame->core->height;
else if (y + 20 > scr_height)
y = scr_height - 20;
#else
wScreenBringInside(wwin->screen_ptr, &x, &y,
(int)tmpw->frame->core->width, (int)tmpw->frame->core->height);
#endif
drawTransparentFrame(tmpw, x, y, tmpw->frame->core->width, tmpw->frame->core->height);
}
}
}
static void flushMotion()
{
XEvent ev;
XSync(dpy, False);
while (XCheckMaskEvent(dpy, ButtonMotionMask, &ev)) ;
}
static void crossWorkspace(WScreen * scr, WWindow * wwin, int opaque_move, int new_workspace, int rewind)
{
/* do not let window be unmapped */
if (opaque_move) {
wwin->flags.changing_workspace = 1;
wWindowChangeWorkspace(wwin, new_workspace);
}
/* go to new workspace */
wWorkspaceChange(scr, new_workspace);
wwin->flags.changing_workspace = 0;
if (rewind)
XWarpPointer(dpy, None, None, 0, 0, 0, 0, scr->scr_width - 20, 0);
else
XWarpPointer(dpy, None, None, 0, 0, 0, 0, -(scr->scr_width - 20), 0);
flushMotion();
if (!opaque_move) {
XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
| ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
GrabModeAsync, None, wCursor[WCUR_MOVE], CurrentTime);
}
}
typedef struct {
/* arrays of WWindows sorted by the respective border position */
WWindow **topList; /* top border */
WWindow **leftList; /* left border */
WWindow **rightList; /* right border */
WWindow **bottomList; /* bottom border */
int count;
/* index of window in the above lists indicating the relative position
* of the window with the others */
int topIndex;
int leftIndex;
int rightIndex;
int bottomIndex;
int rubCount; /* for workspace switching */
int winWidth, winHeight; /* width/height of the window */
int realX, realY; /* actual position of the window */
int calcX, calcY; /* calculated position of window */
int omouseX, omouseY; /* old mouse position */
int mouseX, mouseY; /* last known position of the pointer */
} MoveData;
#define WTOP(w) (w)->frame_y
#define WLEFT(w) (w)->frame_x
#define WRIGHT(w) ((w)->frame_x + (int)(w)->frame->core->width - 1 + \
(HAS_BORDER_WITH_SELECT(w) ? 2*FRAME_BORDER_WIDTH : 0))
#define WBOTTOM(w) ((w)->frame_y + (int)(w)->frame->core->height - 1 + \
(HAS_BORDER_WITH_SELECT(w) ? 2*FRAME_BORDER_WIDTH : 0))
static int compareWTop(const void *a, const void *b)
{
WWindow *wwin1 = *(WWindow **) a;
WWindow *wwin2 = *(WWindow **) b;
if (WTOP(wwin1) > WTOP(wwin2))
return -1;
else if (WTOP(wwin1) < WTOP(wwin2))
return 1;
else
return 0;
}
static int compareWLeft(const void *a, const void *b)
{
WWindow *wwin1 = *(WWindow **) a;
WWindow *wwin2 = *(WWindow **) b;
if (WLEFT(wwin1) > WLEFT(wwin2))
return -1;
else if (WLEFT(wwin1) < WLEFT(wwin2))
return 1;
else
return 0;
}
static int compareWRight(const void *a, const void *b)
{
WWindow *wwin1 = *(WWindow **) a;
WWindow *wwin2 = *(WWindow **) b;
if (WRIGHT(wwin1) < WRIGHT(wwin2))
return -1;
else if (WRIGHT(wwin1) > WRIGHT(wwin2))
return 1;
else
return 0;
}
static int compareWBottom(const void *a, const void *b)
{
WWindow *wwin1 = *(WWindow **) a;
WWindow *wwin2 = *(WWindow **) b;
if (WBOTTOM(wwin1) < WBOTTOM(wwin2))
return -1;
else if (WBOTTOM(wwin1) > WBOTTOM(wwin2))
return 1;
else
return 0;
}
static void updateResistance(WWindow * wwin, MoveData * data, int newX, int newY)
{
int i;
int newX2 = newX + data->winWidth;
int newY2 = newY + data->winHeight;
Bool ok = False;
if (newX < data->realX) {
if (data->rightIndex > 0 && newX < WRIGHT(data->rightList[data->rightIndex - 1])) {
ok = True;
} else if (data->leftIndex <= data->count - 1 && newX2 <= WLEFT(data->leftList[data->leftIndex])) {
ok = True;
}
} else if (newX > data->realX) {
if (data->leftIndex > 0 && newX2 > WLEFT(data->leftList[data->leftIndex - 1])) {
ok = True;
} else if (data->rightIndex <= data->count - 1
&& newX >= WRIGHT(data->rightList[data->rightIndex])) {
ok = True;
}
}
if (!ok) {
if (newY < data->realY) {
if (data->bottomIndex > 0 && newY < WBOTTOM(data->bottomList[data->bottomIndex - 1])) {
ok = True;
} else if (data->topIndex <= data->count - 1
&& newY2 <= WTOP(data->topList[data->topIndex])) {
ok = True;
}
} else if (newY > data->realY) {
if (data->topIndex > 0 && newY2 > WTOP(data->topList[data->topIndex - 1])) {
ok = True;
} else if (data->bottomIndex <= data->count - 1
&& newY >= WBOTTOM(data->bottomList[data->bottomIndex])) {
ok = True;
}
}
}
if (!ok)
return;
/* TODO: optimize this */
if (data->realY < WBOTTOM(data->bottomList[0])) {
data->bottomIndex = 0;
}
if (data->realX < WRIGHT(data->rightList[0])) {
data->rightIndex = 0;
}
if ((data->realX + data->winWidth) > WLEFT(data->leftList[0])) {
data->leftIndex = 0;
}
if ((data->realY + data->winHeight) > WTOP(data->topList[0])) {
data->topIndex = 0;
}
for (i = 0; i < data->count; i++) {
if (data->realY > WBOTTOM(data->bottomList[i])) {
data->bottomIndex = i + 1;
}
if (data->realX > WRIGHT(data->rightList[i])) {
data->rightIndex = i + 1;
}
if ((data->realX + data->winWidth) < WLEFT(data->leftList[i])) {
data->leftIndex = i + 1;
}
if ((data->realY + data->winHeight) < WTOP(data->topList[i])) {
data->topIndex = i + 1;
}
}
}
static void freeMoveData(MoveData * data)
{
if (data->topList)
wfree(data->topList);
if (data->leftList)
wfree(data->leftList);
if (data->rightList)
wfree(data->rightList);
if (data->bottomList)
wfree(data->bottomList);
}
static void updateMoveData(WWindow * wwin, MoveData * data)
{
WScreen *scr = wwin->screen_ptr;
WWindow *tmp;
int i;
data->count = 0;
tmp = scr->focused_window;
while (tmp) {
if (tmp != wwin && scr->current_workspace == tmp->frame->workspace
&& !tmp->flags.miniaturized
&& !tmp->flags.hidden && !tmp->flags.obscured && !WFLAGP(tmp, sunken)) {
data->topList[data->count] = tmp;
data->leftList[data->count] = tmp;
data->rightList[data->count] = tmp;
data->bottomList[data->count] = tmp;
data->count++;
}
tmp = tmp->prev;
}
if (data->count == 0) {
data->topIndex = 0;
data->leftIndex = 0;
data->rightIndex = 0;
data->bottomIndex = 0;
return;
}
/* order from closest to the border of the screen to farthest */
qsort(data->topList, data->count, sizeof(WWindow **), compareWTop);
qsort(data->leftList, data->count, sizeof(WWindow **), compareWLeft);
qsort(data->rightList, data->count, sizeof(WWindow **), compareWRight);
qsort(data->bottomList, data->count, sizeof(WWindow **), compareWBottom);
/* figure the position of the window relative to the others */
data->topIndex = -1;
data->leftIndex = -1;
data->rightIndex = -1;
data->bottomIndex = -1;
if (WTOP(wwin) < WBOTTOM(data->bottomList[0])) {
data->bottomIndex = 0;
}
if (WLEFT(wwin) < WRIGHT(data->rightList[0])) {
data->rightIndex = 0;
}
if (WRIGHT(wwin) > WLEFT(data->leftList[0])) {
data->leftIndex = 0;
}
if (WBOTTOM(wwin) > WTOP(data->topList[0])) {
data->topIndex = 0;
}
for (i = 0; i < data->count; i++) {
if (WTOP(wwin) >= WBOTTOM(data->bottomList[i])) {
data->bottomIndex = i + 1;
}
if (WLEFT(wwin) >= WRIGHT(data->rightList[i])) {
data->rightIndex = i + 1;
}
if (WRIGHT(wwin) <= WLEFT(data->leftList[i])) {
data->leftIndex = i + 1;
}
if (WBOTTOM(wwin) <= WTOP(data->topList[i])) {
data->topIndex = i + 1;
}
}
}
static void initMoveData(WWindow * wwin, MoveData * data)
{
int i;
WWindow *tmp;
memset(data, 0, sizeof(MoveData));
for (i = 0, tmp = wwin->screen_ptr->focused_window; tmp != NULL; tmp = tmp->prev, i++) ;
if (i > 1) {
data->topList = wmalloc(sizeof(WWindow *) * i);
data->leftList = wmalloc(sizeof(WWindow *) * i);
data->rightList = wmalloc(sizeof(WWindow *) * i);
data->bottomList = wmalloc(sizeof(WWindow *) * i);
updateMoveData(wwin, data);
}
data->realX = wwin->frame_x;
data->realY = wwin->frame_y;
data->calcX = wwin->frame_x;
data->calcY = wwin->frame_y;
data->winWidth = wwin->frame->core->width + (HAS_BORDER_WITH_SELECT(wwin) ? 2 * FRAME_BORDER_WIDTH : 0);
data->winHeight = wwin->frame->core->height + (HAS_BORDER_WITH_SELECT(wwin) ? 2 * FRAME_BORDER_WIDTH : 0);
}
static Bool checkWorkspaceChange(WWindow * wwin, MoveData * data, Bool opaqueMove)
{
WScreen *scr = wwin->screen_ptr;
Bool changed = False;
if (data->mouseX <= 1) {
if (scr->current_workspace > 0) {
crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace - 1, True);
changed = True;
data->rubCount = 0;
} else if (scr->current_workspace == 0 && wPreferences.ws_cycle) {
crossWorkspace(scr, wwin, opaqueMove, scr->workspace_count - 1, True);
changed = True;
data->rubCount = 0;
}
} else if (data->mouseX >= scr->scr_width - 2) {
if (scr->current_workspace == scr->workspace_count - 1) {
if (wPreferences.ws_cycle || scr->workspace_count == MAX_WORKSPACES) {
crossWorkspace(scr, wwin, opaqueMove, 0, False);
changed = True;
data->rubCount = 0;
}
/* if user insists on trying to go to next workspace even when
* it's already the last, create a new one */
else if (data->omouseX == data->mouseX && wPreferences.ws_advance) {
/* detect user "rubbing" the window against the edge */
if (data->rubCount > 0 && data->omouseY - data->mouseY > MOVE_THRESHOLD) {
data->rubCount = -(data->rubCount + 1);
} else if (data->rubCount <= 0 && data->mouseY - data->omouseY > MOVE_THRESHOLD) {
data->rubCount = -data->rubCount + 1;
}
}
/* create a new workspace */
if (abs(data->rubCount) > 2) {
/* go to next workspace */
wWorkspaceNew(scr);
crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace + 1, False);
changed = True;
data->rubCount = 0;
}
} else if (scr->current_workspace < scr->workspace_count) {
/* go to next workspace */
crossWorkspace(scr, wwin, opaqueMove, scr->current_workspace + 1, False);
changed = True;
data->rubCount = 0;
}
} else {
data->rubCount = 0;
}
return changed;
}
static void
updateWindowPosition(WWindow * wwin, MoveData * data, Bool doResistance,
Bool opaqueMove, int newMouseX, int newMouseY)
{
WScreen *scr = wwin->screen_ptr;
int dx, dy; /* how much mouse moved */
int winL, winR, winT, winB; /* requested new window position */
int newX, newY; /* actual new window position */
Bool hresist, vresist;
Bool updateIndex;
Bool attract;
hresist = False;
vresist = False;
updateIndex = False;
/* check the direction of the movement */
dx = newMouseX - data->mouseX;
dy = newMouseY - data->mouseY;
data->omouseX = data->mouseX;
data->omouseY = data->mouseY;
data->mouseX = newMouseX;
data->mouseY = newMouseY;
winL = data->calcX + dx;
winR = data->calcX + data->winWidth + dx;
winT = data->calcY + dy;
winB = data->calcY + data->winHeight + dy;
newX = data->realX;
newY = data->realY;
if (doResistance) {
int l_edge, r_edge;
int edge_l, edge_r;
int t_edge, b_edge;
int edge_t, edge_b;
int resist;
resist = WIN_RESISTANCE(wPreferences.edge_resistance);
attract = wPreferences.attract;
/* horizontal movement: check horizontal edge resistances */
if (dx || dy) {
WMRect rect;
int i, head;
/* window is the leftmost window: check against screen edge */
/* Add inter head resistance 1/2 (if needed) */
head = wGetHeadForPointerLocation(scr);
rect = wGetRectForHead(scr, head);
l_edge = WMAX(scr->totalUsableArea[head].x1, rect.pos.x);
edge_l = l_edge - resist;
edge_r = WMIN(scr->totalUsableArea[head].x2, rect.pos.x + rect.size.width);
r_edge = edge_r + resist;
/* 1 */
if ((data->rightIndex >= 0) && (data->rightIndex <= data->count)) {
WWindow *looprw;
for (i = data->rightIndex - 1; i >= 0; i--) {
looprw = data->rightList[i];
if (!(data->realY > WBOTTOM(looprw)
|| (data->realY + data->winHeight) < WTOP(looprw))) {
if (attract || ((data->realX < (WRIGHT(looprw) + 2)) && dx < 0)) {
l_edge = WRIGHT(looprw) + 1;
resist = WIN_RESISTANCE(wPreferences.edge_resistance);
}
break;
}
}
if (attract) {
for (i = data->rightIndex; i < data->count; i++) {
looprw = data->rightList[i];
if (!(data->realY > WBOTTOM(looprw)
|| (data->realY + data->winHeight) < WTOP(looprw))) {
r_edge = WRIGHT(looprw) + 1;
resist = WIN_RESISTANCE(wPreferences.edge_resistance);
break;
}
}
}
}
if ((data->leftIndex >= 0) && (data->leftIndex <= data->count)) {
WWindow *looprw;
for (i = data->leftIndex - 1; i >= 0; i--) {
looprw = data->leftList[i];
if (!(data->realY > WBOTTOM(looprw)
|| (data->realY + data->winHeight) < WTOP(looprw))) {
if (attract
|| (((data->realX + data->winWidth) > (WLEFT(looprw) - 1))
&& dx > 0)) {
edge_r = WLEFT(looprw);
resist = WIN_RESISTANCE(wPreferences.edge_resistance);
}
break;
}
}
if (attract)
for (i = data->leftIndex; i < data->count; i++) {
looprw = data->leftList[i];
if (!(data->realY > WBOTTOM(looprw)
|| (data->realY + data->winHeight) < WTOP(looprw))) {
edge_l = WLEFT(looprw);
resist = WIN_RESISTANCE(wPreferences.edge_resistance);
break;
}
}
}
/*
printf("%d %d\n",winL,winR);
printf("l_ %d r_ %d _l %d _r %d\n",l_edge,r_edge,edge_l,edge_r);
*/
if ((winL - l_edge) < (r_edge - winL)) {
if (resist > 0) {
if ((attract && winL <= l_edge + resist && winL >= l_edge - resist)
|| (dx < 0 && winL <= l_edge && winL >= l_edge - resist)) {
newX = l_edge;
hresist = True;
}
}
} else {
if (resist > 0 && attract && winL >= r_edge - resist && winL <= r_edge + resist) {
newX = r_edge;
hresist = True;
}
}
if ((winR - edge_l) < (edge_r - winR)) {
if (resist > 0 && attract && winR <= edge_l + resist && winR >= edge_l - resist) {
newX = edge_l - data->winWidth;
hresist = True;
}
} else {
if (resist > 0) {
if ((attract && winR >= edge_r - resist && winR <= edge_r + resist)
|| (dx > 0 && winR >= edge_r && winR <= edge_r + resist)) {
newX = edge_r - data->winWidth;
hresist = True;
}
}
}
/* VeRT */
/* Add inter head resistance 2/2 (if needed) */
t_edge = WMAX(scr->totalUsableArea[head].y1, rect.pos.y);
edge_t = t_edge - resist;
edge_b = WMIN(scr->totalUsableArea[head].y2, rect.pos.y + rect.size.height);
b_edge = edge_b + resist;
if ((data->bottomIndex >= 0) && (data->bottomIndex <= data->count)) {
WWindow *looprw;
for (i = data->bottomIndex - 1; i >= 0; i--) {
looprw = data->bottomList[i];
if (!(data->realX > WRIGHT(looprw)
|| (data->realX + data->winWidth) < WLEFT(looprw))) {
if (attract || ((data->realY < (WBOTTOM(looprw) + 2)) && dy < 0)) {
t_edge = WBOTTOM(looprw) + 1;
resist = WIN_RESISTANCE(wPreferences.edge_resistance);
}
break;
}
}
if (attract) {
for (i = data->bottomIndex; i < data->count; i++) {
looprw = data->bottomList[i];
if (!(data->realX > WRIGHT(looprw)
|| (data->realX + data->winWidth) < WLEFT(looprw))) {
b_edge = WBOTTOM(looprw) + 1;
resist = WIN_RESISTANCE(wPreferences.edge_resistance);
break;
}
}
}
}
if ((data->topIndex >= 0) && (data->topIndex <= data->count)) {
WWindow *looprw;
for (i = data->topIndex - 1; i >= 0; i--) {
looprw = data->topList[i];
if (!(data->realX > WRIGHT(looprw)
|| (data->realX + data->winWidth) < WLEFT(looprw))) {
if (attract
|| (((data->realY + data->winHeight) > (WTOP(looprw) - 1))
&& dy > 0)) {
edge_b = WTOP(looprw);
resist = WIN_RESISTANCE(wPreferences.edge_resistance);
}
break;
}
}
if (attract)
for (i = data->topIndex; i < data->count; i++) {
looprw = data->topList[i];
if (!(data->realX > WRIGHT(looprw)
|| (data->realX + data->winWidth) < WLEFT(looprw))) {
edge_t = WTOP(looprw);
resist = WIN_RESISTANCE(wPreferences.edge_resistance);
break;
}
}
}
if ((winT - t_edge) < (b_edge - winT)) {
if (resist > 0) {
if ((attract && winT <= t_edge + resist && winT >= t_edge - resist)
|| (dy < 0 && winT <= t_edge && winT >= t_edge - resist)) {
newY = t_edge;
vresist = True;
}
}
} else {
if (resist > 0 && attract && winT >= b_edge - resist && winT <= b_edge + resist) {
newY = b_edge;
vresist = True;
}
}
if ((winB - edge_t) < (edge_b - winB)) {
if (resist > 0 && attract && winB <= edge_t + resist && winB >= edge_t - resist) {
newY = edge_t - data->winHeight;
vresist = True;
}
} else {
if (resist > 0) {
if ((attract && winB >= edge_b - resist && winB <= edge_b + resist)
|| (dy > 0 && winB >= edge_b && winB <= edge_b + resist)) {
newY = edge_b - data->winHeight;
vresist = True;
}
}
}
}
/* END VeRT */
}
/* update window position */
data->calcX += dx;
data->calcY += dy;
if (((dx > 0 && data->calcX - data->realX > 0)
|| (dx < 0 && data->calcX - data->realX < 0)) && !hresist)
newX = data->calcX;
if (((dy > 0 && data->calcY - data->realY > 0)
|| (dy < 0 && data->calcY - data->realY < 0)) && !vresist)
newY = data->calcY;
if (data->realX != newX || data->realY != newY) {
if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
showPosition(wwin, data->realX, data->realY);
}
if (opaqueMove) {
doWindowMove(wwin, scr->selected_windows, newX - wwin->frame_x, newY - wwin->frame_y);
} else {
/* erase frames */
drawFrames(wwin, scr->selected_windows,
data->realX - wwin->frame_x, data->realY - wwin->frame_y);
}
if (!scr->selected_windows && wPreferences.move_display == WDIS_FRAME_CENTER) {
moveGeometryDisplayCentered(scr, newX + data->winWidth / 2, newY + data->winHeight / 2);
}
if (!opaqueMove) {
/* draw frames */
drawFrames(wwin, scr->selected_windows, newX - wwin->frame_x, newY - wwin->frame_y);
}
if (!scr->selected_windows) {
showPosition(wwin, newX, newY);
}
}
/* recalc relative window position */
if (doResistance && (data->realX != newX || data->realY != newY)) {
updateResistance(wwin, data, newX, newY);
}
data->realX = newX;
data->realY = newY;
}
#define _KS KEY_CONTROL_WINDOW_WEIGHT
#define MOVABLE_BIT 0x01
#define RESIZABLE_BIT 0x02
int wKeyboardMoveResizeWindow(WWindow * wwin)
{
WScreen *scr = wwin->screen_ptr;
Window root = scr->root_win;
XEvent event;
int w = wwin->frame->core->width;
int h = wwin->frame->core->height;
int scr_width = wwin->screen_ptr->scr_width;
int scr_height = wwin->screen_ptr->scr_height;
int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
int src_x = wwin->frame_x;
int src_y = wwin->frame_y;
int done, off_x, off_y, ww, wh;
int kspeed = _KS;
Time lastTime = 0;
KeyCode shiftl, shiftr, ctrll, ctrlmode;
KeySym keysym = NoSymbol;
int moment = 0;
int modes = ((IS_MOVABLE(wwin) ? MOVABLE_BIT : 0) | (IS_RESIZABLE(wwin) ? RESIZABLE_BIT : 0));
int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
? wGetHeadForWindow(wwin)
: scr->xine_info.primary_head);
shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
ctrll = XKeysymToKeycode(dpy, XK_Control_L);
ctrlmode = done = off_x = off_y = 0;
if (modes == RESIZABLE_BIT) {
ctrlmode = 1;
}
XSync(dpy, False);
wusleep(10000);
XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
if (!wwin->flags.selected) {
wUnselectWindows(scr);
}
XGrabServer(dpy);
XGrabPointer(dpy, scr->root_win, True, PointerMotionMask
| ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime);
if (wwin->flags.shaded || scr->selected_windows) {
if (scr->selected_windows)
drawFrames(wwin, scr->selected_windows, off_x, off_y);
else
drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
if (!scr->selected_windows)
mapPositionDisplay(wwin, src_x, src_y, w, h);
} else {
drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
}
ww = w;
wh = h;
while (1) {
/*
looper.ox=off_x;
looper.oy=off_y;
*/
do {
WMMaskEvent(dpy, KeyPressMask | ButtonReleaseMask
| ButtonPressMask | ExposureMask, &event);
if (event.type == Expose) {
WMHandleEvent(&event);
}
} while (event.type == Expose);
if (wwin->flags.shaded || scr->selected_windows) {
if (scr->selected_windows)
drawFrames(wwin, scr->selected_windows, off_x, off_y);
else
drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
/*** I HATE EDGE RESISTANCE - ]d ***/
} else {
drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, ww, wh);
}
if (ctrlmode)
showGeometry(wwin, src_x + off_x, src_y + off_y, src_x + off_x + ww, src_y + off_y + wh,
0);
XUngrabServer(dpy);
XSync(dpy, False);
switch (event.type) {
case KeyPress:
/* accelerate */
if (event.xkey.time - lastTime > 50) {
kspeed /= (1 + (event.xkey.time - lastTime) / 100);
} else {
if (kspeed < 20) {
kspeed++;
}
}
if (kspeed < _KS)
kspeed = _KS;
lastTime = event.xkey.time;
if (modes == (MOVABLE_BIT | RESIZABLE_BIT)) {
if ((event.xkey.state & ControlMask) && !wwin->flags.shaded) {
ctrlmode = 1;
wUnselectWindows(scr);
} else {
ctrlmode = 0;
}
}
if (event.xkey.keycode == shiftl || event.xkey.keycode == shiftr) {
if (ctrlmode)
cycleGeometryDisplay(wwin, src_x + off_x, src_y + off_y, ww, wh, 0);
else
cyclePositionDisplay(wwin, src_x + off_x, src_y + off_y, ww, wh);
} else {
keysym = XLookupKeysym(&event.xkey, 0);
switch (keysym) {
case XK_Return:
done = 2;
break;
case XK_Escape:
done = 1;
break;
case XK_Up:
#ifdef XK_KP_Up
case XK_KP_Up:
#endif
case XK_k:
if (ctrlmode) {
if (moment != UP)
h = wh;
h -= kspeed;
moment = UP;
if (h < 1)
h = 1;
} else
off_y -= kspeed;
break;
case XK_Down:
#ifdef XK_KP_Down
case XK_KP_Down:
#endif
case XK_j:
if (ctrlmode) {
if (moment != DOWN)
h = wh;
h += kspeed;
moment = DOWN;
} else
off_y += kspeed;
break;
case XK_Left:
#ifdef XK_KP_Left
case XK_KP_Left:
#endif
case XK_h:
if (ctrlmode) {
if (moment != LEFT)
w = ww;
w -= kspeed;
if (w < 1)
w = 1;
moment = LEFT;
} else
off_x -= kspeed;
break;
case XK_Right:
#ifdef XK_KP_Right
case XK_KP_Right:
#endif
case XK_l:
if (ctrlmode) {
if (moment != RIGHT)
w = ww;
w += kspeed;
moment = RIGHT;
} else
off_x += kspeed;
break;
}
ww = w;
wh = h;
wh -= vert_border;
wWindowConstrainSize(wwin, (unsigned int *)&ww, (unsigned int *)&wh);
wh += vert_border;
if (wPreferences.ws_cycle) {
if (src_x + off_x + ww < 20) {
if (!scr->current_workspace) {
wWorkspaceChange(scr, scr->workspace_count - 1);
} else
wWorkspaceChange(scr, scr->current_workspace - 1);
off_x += scr_width;
} else if (src_x + off_x + 20 > scr_width) {
if (scr->current_workspace == scr->workspace_count - 1) {
wWorkspaceChange(scr, 0);
} else
wWorkspaceChange(scr, scr->current_workspace + 1);
off_x -= scr_width;
}
} else {
if (src_x + off_x + ww < 20)
off_x = 20 - ww - src_x;
else if (src_x + off_x + 20 > scr_width)
off_x = scr_width - 20 - src_x;
}
if (src_y + off_y + wh < 20) {
off_y = 20 - wh - src_y;
} else if (src_y + off_y + 20 > scr_height) {
off_y = scr_height - 20 - src_y;
}
}
break;
case ButtonPress:
case ButtonRelease:
done = 1;
break;
case Expose:
WMHandleEvent(&event);
while (XCheckTypedEvent(dpy, Expose, &event)) {
WMHandleEvent(&event);
}
break;
default:
WMHandleEvent(&event);
break;
}
XGrabServer(dpy);
/*xxx */
if (wwin->flags.shaded && !scr->selected_windows) {
moveGeometryDisplayCentered(scr, src_x + off_x + w / 2, src_y + off_y + h / 2);
} else {
if (ctrlmode) {
WMUnmapWidget(scr->gview);
mapGeometryDisplay(wwin, src_x + off_x, src_y + off_y, ww, wh);
} else if (!scr->selected_windows) {
WMUnmapWidget(scr->gview);
mapPositionDisplay(wwin, src_x + off_x, src_y + off_y, ww, wh);
}
}
if (wwin->flags.shaded || scr->selected_windows) {
if (scr->selected_windows)
drawFrames(wwin, scr->selected_windows, off_x, off_y);
else
drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
} else {
drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, ww, wh);
}
if (ctrlmode) {
showGeometry(wwin, src_x + off_x, src_y + off_y, src_x + off_x + ww, src_y + off_y + wh,
0);
} else if (!scr->selected_windows)
showPosition(wwin, src_x + off_x, src_y + off_y);
if (done) {
scr->keymove_tick = 0;
/*
WMDeleteTimerWithClientData(&looper);
*/
if (wwin->flags.shaded || scr->selected_windows) {
if (scr->selected_windows)
drawFrames(wwin, scr->selected_windows, off_x, off_y);
else
drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, w, h);
} else {
drawTransparentFrame(wwin, src_x + off_x, src_y + off_y, ww, wh);
}
if (ctrlmode) {
showGeometry(wwin, src_x + off_x, src_y + off_y, src_x + off_x + ww,
src_y + off_y + wh, 0);
WMUnmapWidget(scr->gview);
} else
WMUnmapWidget(scr->gview);
XUngrabKeyboard(dpy, CurrentTime);
XUngrabPointer(dpy, CurrentTime);
XUngrabServer(dpy);
if (done == 2) {
if (wwin->flags.shaded || scr->selected_windows) {
if (!scr->selected_windows) {
wWindowMove(wwin, src_x + off_x, src_y + off_y);
wWindowSynthConfigureNotify(wwin);
} else {
WMArrayIterator iter;
WWindow *foo;
doWindowMove(wwin, scr->selected_windows, off_x, off_y);
WM_ITERATE_ARRAY(scr->selected_windows, foo, iter) {
wWindowSynthConfigureNotify(foo);
}
}
} else {
if (wwin->client.width != ww) {
wwin->flags.user_changed_width = 1;
wwin->flags.maximized &= ~(MAX_HORIZONTAL | MAX_MAXIMUS);
}
if (wwin->client.height != wh - vert_border) {
wwin->flags.user_changed_height = 1;
wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS);
}
wWindowConfigure(wwin, src_x + off_x, src_y + off_y, ww, wh - vert_border);
wWindowSynthConfigureNotify(wwin);
}
wWindowChangeWorkspace(wwin, scr->current_workspace);
wSetFocusTo(scr, wwin);
}
if (wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 &&
head != wGetHeadForWindow(wwin)) {
wArrangeIcons(scr, True);
}
return 1;
}
}
}
/*
*----------------------------------------------------------------------
* wMouseMoveWindow--
* Move the named window and the other selected ones (if any),
* interactively. Also shows the position of the window, if only one
* window is being moved.
* If the window is not on the selected window list, the selected
* windows are deselected.
* If shift is pressed during the operation, the position display
* is changed to another type.
*
* Returns:
* True if the window was moved, False otherwise.
*
* Side effects:
* The window(s) position is changed, and the client(s) are
* notified about that.
* The position display configuration may be changed.
*----------------------------------------------------------------------
*/
int wMouseMoveWindow(WWindow * wwin, XEvent * ev)
{
WScreen *scr = wwin->screen_ptr;
XEvent event;
Window root = scr->root_win;
KeyCode shiftl, shiftr;
Bool done = False;
int started = 0;
int warped = 0;
/* This needs not to change while moving, else bad things can happen */
int opaqueMove = wPreferences.opaque_move;
MoveData moveData;
int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
? wGetHeadForWindow(wwin)
: scr->xine_info.primary_head);
if (!IS_MOVABLE(wwin))
return False;
if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
XSetWindowAttributes attr;
attr.save_under = True;
XChangeWindowAttributes(dpy, wwin->frame->core->window, CWSaveUnder, &attr);
}
initMoveData(wwin, &moveData);
moveData.mouseX = ev->xmotion.x_root;
moveData.mouseY = ev->xmotion.y_root;
if (!wwin->flags.selected) {
/* this window is not selected, unselect others and move only wwin */
wUnselectWindows(scr);
}
shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
while (!done) {
if (warped) {
int junk;
Window junkw;
/* XWarpPointer() doesn't seem to generate Motion events, so
* we've got to simulate them */
XQueryPointer(dpy, root, &junkw, &junkw, &event.xmotion.x_root,
&event.xmotion.y_root, &junk, &junk, (unsigned *)&junk);
} else {
WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
| PointerMotionHintMask
| ButtonReleaseMask | ButtonPressMask | ExposureMask, &event);
if (event.type == MotionNotify) {
/* compress MotionNotify events */
while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
if (!checkMouseSamplingRate(&event))
continue;
}
}
switch (event.type) {
case KeyPress:
if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
&& started && !scr->selected_windows) {
if (!opaqueMove) {
drawFrames(wwin, scr->selected_windows,
moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
}
if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
showPosition(wwin, moveData.realX, moveData.realY);
XUngrabServer(dpy);
}
cyclePositionDisplay(wwin, moveData.realX, moveData.realY,
moveData.winWidth, moveData.winHeight);
if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
XGrabServer(dpy);
showPosition(wwin, moveData.realX, moveData.realY);
}
if (!opaqueMove) {
drawFrames(wwin, scr->selected_windows,
moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
}
/*} else {
WMHandleEvent(&event); this causes problems needs fixing */
}
break;
case MotionNotify:
if (started) {
updateWindowPosition(wwin, &moveData,
scr->selected_windows == NULL
&& wPreferences.edge_resistance > 0,
opaqueMove, event.xmotion.x_root, event.xmotion.y_root);
if (!warped && !wPreferences.no_autowrap) {
int oldWorkspace = scr->current_workspace;
if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
showPosition(wwin, moveData.realX, moveData.realY);
XUngrabServer(dpy);
}
if (!opaqueMove) {
drawFrames(wwin, scr->selected_windows,
moveData.realX - wwin->frame_x,
moveData.realY - wwin->frame_y);
}
if (checkWorkspaceChange(wwin, &moveData, opaqueMove)) {
if (scr->current_workspace != oldWorkspace
&& wPreferences.edge_resistance > 0
&& scr->selected_windows == NULL)
updateMoveData(wwin, &moveData);
warped = 1;
}
if (!opaqueMove) {
drawFrames(wwin, scr->selected_windows,
moveData.realX - wwin->frame_x,
moveData.realY - wwin->frame_y);
}
if (wPreferences.move_display == WDIS_NEW && !scr->selected_windows) {
XSync(dpy, False);
showPosition(wwin, moveData.realX, moveData.realY);
XGrabServer(dpy);
}
} else {
warped = 0;
}
} else if (abs(ev->xmotion.x_root - event.xmotion.x_root) >= MOVE_THRESHOLD
|| abs(ev->xmotion.y_root - event.xmotion.y_root) >= MOVE_THRESHOLD) {
XChangeActivePointerGrab(dpy, ButtonMotionMask
| ButtonReleaseMask | ButtonPressMask,
wCursor[WCUR_MOVE], CurrentTime);
started = 1;
XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
if (!scr->selected_windows)
mapPositionDisplay(wwin, moveData.realX, moveData.realY,
moveData.winWidth, moveData.winHeight);
if (started && !opaqueMove)
drawFrames(wwin, scr->selected_windows, 0, 0);
if (!opaqueMove || (wPreferences.move_display == WDIS_NEW
&& !scr->selected_windows)) {
XGrabServer(dpy);
if (wPreferences.move_display == WDIS_NEW)
showPosition(wwin, moveData.realX, moveData.realY);
}
}
break;
case ButtonPress:
break;
case ButtonRelease:
if (event.xbutton.button != ev->xbutton.button)
break;
if (started) {
XEvent e;
if (!opaqueMove) {
drawFrames(wwin, scr->selected_windows,
moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
XSync(dpy, 0);
doWindowMove(wwin, scr->selected_windows,
moveData.realX - wwin->frame_x,
moveData.realY - wwin->frame_y);
}
#ifndef CONFIGURE_WINDOW_WHILE_MOVING
wWindowSynthConfigureNotify(wwin);
#endif
XUngrabKeyboard(dpy, CurrentTime);
XUngrabServer(dpy);
if (!opaqueMove) {
wWindowChangeWorkspace(wwin, scr->current_workspace);
wSetFocusTo(scr, wwin);
}
if (wPreferences.move_display == WDIS_NEW)
showPosition(wwin, moveData.realX, moveData.realY);
/* discard all enter/leave events that happened until
* the time the button was released */
while (XCheckTypedEvent(dpy, EnterNotify, &e)) {
if (e.xcrossing.time > event.xbutton.time) {
XPutBackEvent(dpy, &e);
break;
}
}
while (XCheckTypedEvent(dpy, LeaveNotify, &e)) {
if (e.xcrossing.time > event.xbutton.time) {
XPutBackEvent(dpy, &e);
break;
}
}
if (!scr->selected_windows) {
/* get rid of the geometry window */
WMUnmapWidget(scr->gview);
}
}
done = True;
break;
default:
if (started && !opaqueMove) {
drawFrames(wwin, scr->selected_windows,
moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
XUngrabServer(dpy);
WMHandleEvent(&event);
XSync(dpy, False);
XGrabServer(dpy);
drawFrames(wwin, scr->selected_windows,
moveData.realX - wwin->frame_x, moveData.realY - wwin->frame_y);
} else {
WMHandleEvent(&event);
}
break;
}
}
if (wPreferences.opaque_move && !wPreferences.use_saveunders) {
XSetWindowAttributes attr;
attr.save_under = False;
XChangeWindowAttributes(dpy, wwin->frame->core->window, CWSaveUnder, &attr);
}
freeMoveData(&moveData);
if (started && wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 &&
head != wGetHeadForWindow(wwin)) {
wArrangeIcons(scr, True);
}
return started;
}
#define RESIZEBAR 1
#define HCONSTRAIN 2
static int getResizeDirection(WWindow * wwin, int x, int y, int dx, int dy, int flags)
{
int w = wwin->frame->core->width - 1;
int cw = wwin->frame->resizebar_corner_width;
int dir;
/* if not resizing through the resizebar */
if (!(flags & RESIZEBAR)) {
int xdir = (abs(x) < (wwin->client.width / 2)) ? LEFT : RIGHT;
int ydir = (abs(y) < (wwin->client.height / 2)) ? UP : DOWN;
if (abs(dx) < 2 || abs(dy) < 2) {
if (abs(dy) > abs(dx))
xdir = 0;
else
ydir = 0;
}
return (xdir | ydir);
}
/* window is too narrow. allow diagonal resize */
if (cw * 2 >= w) {
int ydir;
if (flags & HCONSTRAIN)
ydir = 0;
else
ydir = DOWN;
if (x < cw)
return (LEFT | ydir);
else
return (RIGHT | ydir);
}
/* vertical resize */
if ((x > cw) && (x < w - cw))
return DOWN;
if (x < cw)
dir = LEFT;
else
dir = RIGHT;
if ((abs(dy) > 0) && !(flags & HCONSTRAIN))
dir |= DOWN;
return dir;
}
void wMouseResizeWindow(WWindow * wwin, XEvent * ev)
{
XEvent event;
WScreen *scr = wwin->screen_ptr;
Window root = scr->root_win;
int vert_border = wwin->frame->top_width + wwin->frame->bottom_width;
int fw = wwin->frame->core->width;
int fh = wwin->frame->core->height;
int fx = wwin->frame_x;
int fy = wwin->frame_y;
int is_resizebar = (wwin->frame->resizebar && ev->xany.window == wwin->frame->resizebar->window);
int orig_x, orig_y;
int started;
int dw, dh;
int rw = fw, rh = fh;
int rx1, ry1, rx2, ry2;
int res = 0;
KeyCode shiftl, shiftr;
int h = 0;
int orig_fx = fx;
int orig_fy = fy;
int orig_fw = fw;
int orig_fh = fh;
int head = ((wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1)
? wGetHeadForWindow(wwin)
: scr->xine_info.primary_head);
if (!IS_RESIZABLE(wwin))
return;
if (wwin->flags.shaded) {
wwarning("internal error: tryein");
return;
}
orig_x = ev->xbutton.x_root;
orig_y = ev->xbutton.y_root;
started = 0;
wUnselectWindows(scr);
rx1 = fx;
rx2 = fx + fw - 1;
ry1 = fy;
ry2 = fy + fh - 1;
shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
if (HAS_TITLEBAR(wwin))
h = WMFontHeight(wwin->screen_ptr->title_font) + (wPreferences.window_title_clearance +
TITLEBAR_EXTEND_SPACE) * 2;
else
h = 0;
while (1) {
WMMaskEvent(dpy, KeyPressMask | ButtonMotionMask
| ButtonReleaseMask | PointerMotionHintMask | ButtonPressMask | ExposureMask, &event);
if (!checkMouseSamplingRate(&event))
continue;
switch (event.type) {
case KeyPress:
showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
if ((event.xkey.keycode == shiftl || event.xkey.keycode == shiftr)
&& started) {
drawTransparentFrame(wwin, fx, fy, fw, fh);
cycleGeometryDisplay(wwin, fx, fy, fw, fh, res);
drawTransparentFrame(wwin, fx, fy, fw, fh);
}
showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
break;
case MotionNotify:
if (started) {
while (XCheckMaskEvent(dpy, ButtonMotionMask, &event)) ;
dw = 0;
dh = 0;
orig_fx = fx;
orig_fy = fy;
orig_fw = fw;
orig_fh = fh;
if (res & LEFT)
dw = orig_x - event.xmotion.x_root;
else if (res & RIGHT)
dw = event.xmotion.x_root - orig_x;
if (res & UP)
dh = orig_y - event.xmotion.y_root;
else if (res & DOWN)
dh = event.xmotion.y_root - orig_y;
orig_x = event.xmotion.x_root;
orig_y = event.xmotion.y_root;
rw += dw;
rh += dh;
fw = rw;
fh = rh - vert_border;
wWindowConstrainSize(wwin, (unsigned int *)&fw, (unsigned int *)&fh);
fh += vert_border;
if (res & LEFT)
fx = rx2 - fw + 1;
else if (res & RIGHT)
fx = rx1;
if (res & UP)
fy = ry2 - fh + 1;
else if (res & DOWN)
fy = ry1;
} else if (abs(orig_x - event.xmotion.x_root) >= MOVE_THRESHOLD
|| abs(orig_y - event.xmotion.y_root) >= MOVE_THRESHOLD) {
int tx, ty;
Window junkw;
int flags;
XTranslateCoordinates(dpy, root, wwin->frame->core->window,
orig_x, orig_y, &tx, &ty, &junkw);
/* check if resizing through resizebar */
if (is_resizebar)
flags = RESIZEBAR;
else
flags = 0;
if (is_resizebar && ((ev->xbutton.state & ShiftMask)
|| abs(orig_y - event.xmotion.y_root) < HRESIZE_THRESHOLD))
flags |= HCONSTRAIN;
res = getResizeDirection(wwin, tx, ty,
orig_x - event.xmotion.x_root,
orig_y - event.xmotion.y_root, flags);
if (res == (UP | LEFT))
XChangeActivePointerGrab(dpy, ButtonMotionMask
| ButtonReleaseMask | ButtonPressMask,
wCursor[WCUR_TOPLEFTRESIZE], CurrentTime);
else if (res == (UP | RIGHT))
XChangeActivePointerGrab(dpy, ButtonMotionMask
| ButtonReleaseMask | ButtonPressMask,
wCursor[WCUR_TOPRIGHTRESIZE], CurrentTime);
else if (res == (DOWN | LEFT))
XChangeActivePointerGrab(dpy, ButtonMotionMask
| ButtonReleaseMask | ButtonPressMask,
wCursor[WCUR_BOTTOMLEFTRESIZE], CurrentTime);
else if (res == (DOWN | RIGHT))
XChangeActivePointerGrab(dpy, ButtonMotionMask
| ButtonReleaseMask | ButtonPressMask,
wCursor[WCUR_BOTTOMRIGHTRESIZE], CurrentTime);
else if (res == DOWN || res == UP)
XChangeActivePointerGrab(dpy, ButtonMotionMask
| ButtonReleaseMask | ButtonPressMask,
wCursor[WCUR_VERTICALRESIZE], CurrentTime);
else if (res & (DOWN | UP))
XChangeActivePointerGrab(dpy, ButtonMotionMask
| ButtonReleaseMask | ButtonPressMask,
wCursor[WCUR_VERTICALRESIZE], CurrentTime);
else if (res & (LEFT | RIGHT))
XChangeActivePointerGrab(dpy, ButtonMotionMask
| ButtonReleaseMask | ButtonPressMask,
wCursor[WCUR_HORIZONRESIZE], CurrentTime);
XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
XGrabServer(dpy);
/* Draw the resize frame for the first time. */
mapGeometryDisplay(wwin, fx, fy, fw, fh);
drawTransparentFrame(wwin, fx, fy, fw, fh);
showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
started = 1;
}
if (started) {
if (wPreferences.size_display == WDIS_FRAME_CENTER) {
drawTransparentFrame(wwin, orig_fx, orig_fy, orig_fw, orig_fh);
moveGeometryDisplayCentered(scr, fx + fw / 2, fy + fh / 2);
drawTransparentFrame(wwin, fx, fy, fw, fh);
} else {
drawTransparentFrame(wwin, orig_fx, orig_fy, orig_fw, orig_fh);
drawTransparentFrame(wwin, fx, fy, fw, fh);
}
if (fh != orig_fh || fw != orig_fw) {
if (wPreferences.size_display == WDIS_NEW) {
showGeometry(wwin, orig_fx, orig_fy, orig_fx + orig_fw,
orig_fy + orig_fh, res);
}
showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
}
}
break;
case ButtonPress:
break;
case ButtonRelease:
if (event.xbutton.button != ev->xbutton.button)
break;
if (started) {
showGeometry(wwin, fx, fy, fx + fw, fy + fh, res);
drawTransparentFrame(wwin, fx, fy, fw, fh);
XUngrabKeyboard(dpy, CurrentTime);
WMUnmapWidget(scr->gview);
XUngrabServer(dpy);
if (wwin->client.width != fw) {
wwin->flags.user_changed_width = 1;
wwin->flags.maximized &= ~(MAX_HORIZONTAL | MAX_MAXIMUS);
}
if (wwin->client.height != fh - vert_border) {
wwin->flags.user_changed_height = 1;
wwin->flags.maximized &= ~(MAX_VERTICAL | MAX_LEFTHALF | MAX_RIGHTHALF | MAX_MAXIMUS);
}
wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
}
return;
default:
WMHandleEvent(&event);
}
}
if (wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 && head != wGetHeadForWindow(wwin)) {
wArrangeIcons(scr, True);
}
}
#undef LEFT
#undef RIGHT
#undef HORIZONTAL
#undef UP
#undef DOWN
#undef VERTICAL
#undef HCONSTRAIN
#undef RESIZEBAR
void wUnselectWindows(WScreen * scr)
{
WWindow *wwin;
if (!scr->selected_windows)
return;
while (WMGetArrayItemCount(scr->selected_windows)) {
wwin = WMGetFromArray(scr->selected_windows, 0);
if (wwin->flags.miniaturized && wwin->icon && wwin->icon->selected)
wIconSelect(wwin->icon);
wSelectWindow(wwin, False);
}
WMFreeArray(scr->selected_windows);
scr->selected_windows = NULL;
}
static void selectWindowsInside(WScreen * scr, int x1, int y1, int x2, int y2)
{
WWindow *tmpw;
/* select the windows and put them in the selected window list */
tmpw = scr->focused_window;
while (tmpw != NULL) {
if (!(tmpw->flags.miniaturized || tmpw->flags.hidden)) {
if ((tmpw->frame->workspace == scr->current_workspace || IS_OMNIPRESENT(tmpw))
&& (tmpw->frame_x >= x1) && (tmpw->frame_y >= y1)
&& (tmpw->frame->core->width + tmpw->frame_x <= x2)
&& (tmpw->frame->core->height + tmpw->frame_y <= y2)) {
wSelectWindow(tmpw, True);
}
}
tmpw = tmpw->prev;
}
}
void wSelectWindows(WScreen * scr, XEvent * ev)
{
XEvent event;
Window root = scr->root_win;
GC gc = scr->frame_gc;
int xp = ev->xbutton.x_root;
int yp = ev->xbutton.y_root;
int w = 0, h = 0;
int x = xp, y = yp;
if (XGrabPointer(dpy, scr->root_win, False, ButtonMotionMask
| ButtonReleaseMask | ButtonPressMask, GrabModeAsync,
GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
return;
}
XGrabServer(dpy);
wUnselectWindows(scr);
XDrawRectangle(dpy, root, gc, xp, yp, w, h);
while (1) {
WMMaskEvent(dpy, ButtonReleaseMask | PointerMotionMask | ButtonPressMask, &event);
switch (event.type) {
case MotionNotify:
XDrawRectangle(dpy, root, gc, x, y, w, h);
x = event.xmotion.x_root;
if (x < xp) {
w = xp - x;
} else {
w = x - xp;
x = xp;
}
y = event.xmotion.y_root;
if (y < yp) {
h = yp - y;
} else {
h = y - yp;
y = yp;
}
XDrawRectangle(dpy, root, gc, x, y, w, h);
break;
case ButtonPress:
break;
case ButtonRelease:
if (event.xbutton.button != ev->xbutton.button)
break;
XDrawRectangle(dpy, root, gc, x, y, w, h);
XUngrabServer(dpy);
XUngrabPointer(dpy, CurrentTime);
selectWindowsInside(scr, x, y, x + w, y + h);
return;
default:
WMHandleEvent(&event);
break;
}
}
}
void InteractivePlaceWindow(WWindow * wwin, int *x_ret, int *y_ret, unsigned width, unsigned height)
{
WScreen *scr = wwin->screen_ptr;
Window root = scr->root_win;
int x, y, h = 0;
XEvent event;
KeyCode shiftl, shiftr;
Window junkw;
int junk;
if (XGrabPointer(dpy, root, True, PointerMotionMask | ButtonPressMask,
GrabModeAsync, GrabModeAsync, None, wCursor[WCUR_DEFAULT], CurrentTime) != Success) {
*x_ret = 0;
*y_ret = 0;
return;
}
if (HAS_TITLEBAR(wwin)) {
h = WMFontHeight(scr->title_font) + (wPreferences.window_title_clearance +
TITLEBAR_EXTEND_SPACE) * 2;
height += h;
}
if (HAS_RESIZEBAR(wwin)) {
height += RESIZEBAR_HEIGHT;
}
XGrabKeyboard(dpy, root, False, GrabModeAsync, GrabModeAsync, CurrentTime);
XQueryPointer(dpy, root, &junkw, &junkw, &x, &y, &junk, &junk, (unsigned *)&junk);
mapPositionDisplay(wwin, x - width / 2, y - h / 2, width, height);
drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
shiftl = XKeysymToKeycode(dpy, XK_Shift_L);
shiftr = XKeysymToKeycode(dpy, XK_Shift_R);
while (1) {
WMMaskEvent(dpy, PointerMotionMask | ButtonPressMask | ExposureMask | KeyPressMask, &event);
if (!checkMouseSamplingRate(&event))
continue;
switch (event.type) {
case KeyPress:
if ((event.xkey.keycode == shiftl)
|| (event.xkey.keycode == shiftr)) {
drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
cyclePositionDisplay(wwin, x - width / 2, y - h / 2, width, height);
drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
}
break;
case MotionNotify:
drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
x = event.xmotion.x_root;
y = event.xmotion.y_root;
if (wPreferences.move_display == WDIS_FRAME_CENTER)
moveGeometryDisplayCentered(scr, x, y + (height - h) / 2);
showPosition(wwin, x - width / 2, y - h / 2);
drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
break;
case ButtonPress:
drawTransparentFrame(wwin, x - width / 2, y - h / 2, width, height);
XSync(dpy, 0);
*x_ret = x - width / 2;
*y_ret = y - h / 2;
XUngrabPointer(dpy, CurrentTime);
XUngrabKeyboard(dpy, CurrentTime);
/* get rid of the geometry window */
WMUnmapWidget(scr->gview);
return;
default:
WMHandleEvent(&event);
break;
}
}
}