Files
wmaker/src/moveres.c
T
dan 9aca0d5f6e - Check whether libXft is at least version 2.1.2 else refuse to compile.
- Fixed bug in icon chooser dialog that could cause a segmentation fault
  in some cases (Pascal Hofstee <caelian@gmail.com>)
- Fixed crash in asm code in wrlib, with new versions of gcc.
- Fixed bug in the x86_PseudoColor_32_to_8() function which incorrectly
  used the r, g, b fields in the conversion.
- Fixed x86 ASM code in wrlib to work on 64 bit architectures.
- Fixed the focus flicker seen with some apps (notably gtk2)
  (Alexey Spiridonov <snarkmaster@gmail.com>)
- Fixed all crashing bugs that were generated by wmaker starting with the
  WMState file missing.
- Added NetWM support (a modified version of the patch originaly written
  by Peter Zijlstra <a.p.zijlstra@chello.nl>)
- Applied patch to enhance the Virtual Desktop behaviour, and to integrate
  it with the NetWM code (Peter Zijlstra <a.p.zijlstra@chello.nl>)
- Applied a few xinerama and placement fixes (Peter Zijlstra
    <a.p.zijlstra@chello.nl>)
- Fixed memory leak in dock code.
- Fixed and enhanced the text wrapping in WINGs.
- Fixed the layout of some elements in WPrefs.app
- Added workaround for aplications that don't set the required hints on the
  client leader window, but they set them on normal windows (observer with
  KDE 3.3.0 mainly). This will allow these apps to get an appicon again.
  (they should be fixed still)
- Added workaround for applications that do not set a command with
  XSetCommand(), but instead they set the _NET_WM_PID property. This works
  with operating systems that offer a /proc interface similar to what linux
  has. (This also is to fix problems with KDE 3.3.0 apps, but not only them).
- Fixed bug with autostart and exit scripts not being executed if user
  GNUstep path was different from ~/GNUstep (when setting GNUSTEP_USER_ROOT)
- Added utf8 support in WINGs (removed old X core font code)
- Added utility to convert old font names to new font names in style files
2004-10-12 01:34:32 +00:00

2435 lines
78 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 "wcore.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>
#ifdef KWM_HINTS
#include "kwm.h"
#endif
/* 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 Time LastTimestamp;
extern Cursor wCursor[WCUR_LAST];
extern WPreferences wPreferences;
extern Atom _XA_WM_PROTOCOLS;
/*
*----------------------------------------------------------------------
* 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 {
#ifdef VIRTUAL_DESKTOP
WSetGeometryViewShownPosition(scr->gview,
x + scr->workspaces[scr->current_workspace]->view_x,
y + scr->workspaces[scr->current_workspace]->view_y);
#else
WSetGeometryViewShownPosition(scr->gview, x, y);
#endif
}
}
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, &ww, &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;
if (wwin->client.height != wh - vert_border)
wwin->flags.user_changed_height = 1;
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);
}
#if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
wWorkspaceResizeViewPort(scr, scr->current_workspace);
#endif
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);
#ifdef GHOST_WINDOW_MOVE
RImage *rimg = InitGhostWindowMove(scr);
#endif
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);
}
#ifdef DEBUG
puts("Moving window");
#endif
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);
}
}
#ifdef DEBUG
puts("End move window");
#endif
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);
}
#if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
if (started)
wWorkspaceResizeViewPort(scr, scr->current_workspace);
#endif
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;
#ifdef DEBUG
puts("Resizing window");
#endif
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, &fw, &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;
if (wwin->client.height != fh - vert_border)
wwin->flags.user_changed_height = 1;
wWindowConfigure(wwin, fx, fy, fw, fh - vert_border);
}
#ifdef DEBUG
puts("End resize window");
#endif
return;
default:
WMHandleEvent(&event);
}
}
if (wPreferences.auto_arrange_icons && wXineramaHeads(scr) > 1 &&
head != wGetHeadForWindow(wwin)) {
wArrangeIcons(scr, True);
}
#if defined(NETWM_HINTS) && defined(VIRTUAL_DESKTOP)
wWorkspaceResizeViewPort(scr, scr->current_workspace);
#endif
}
#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;
}
#ifndef LITE
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;
#ifdef DEBUG
puts("Selecting windows");
#endif
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);
#ifdef KWM_HINTS
wKWMSelectRootRegion(scr, xp, yp, w, h,
event.xbutton.state & ControlMask);
#endif /* KWM_HINTS */
#ifdef DEBUG
puts("End window selection");
#endif
return;
default:
WMHandleEvent(&event);
break;
}
}
}
#endif /* !LITE */
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;
}
}
}