1348 lines
40 KiB
C
1348 lines
40 KiB
C
/* Copyright 1989 GROUPE BULL -- See license conditions in file COPYRIGHT
|
|
* Copyright 1989 Massachusetts Institute of Technology
|
|
*/
|
|
/*************************************************\
|
|
* *
|
|
* BULL WINDOW MANAGER for X11 . *
|
|
* *
|
|
* MODULE handling interactions with user *
|
|
* *
|
|
\*************************************************/
|
|
|
|
/* include */
|
|
|
|
#include <stdio.h>
|
|
#include "EXTERN.h"
|
|
#include "wool.h"
|
|
#include "wl_atom.h"
|
|
#include "gwm.h"
|
|
#include "wl_number.h"
|
|
#include "wl_string.h"
|
|
#include "wl_pixmap.h"
|
|
#include "wl_cursor.h"
|
|
|
|
/* local */
|
|
|
|
static int inner_ulx, inner_uly;/* ul corner of inner window */
|
|
static int inner_lrbx, inner_lrby;/* lr corner of inner window, counted
|
|
from the lr corner of outer window
|
|
*/
|
|
/* inner dims are the inner of the client window */
|
|
#define MAKE_INNER_DIMS \
|
|
{ int tmp;\
|
|
tmp = cw -> inner_x + cw -> box.borderwidth;\
|
|
inner_ulx = Max(1, tmp);\
|
|
tmp = cw -> inner_y + cw -> box.borderwidth;\
|
|
inner_uly = Max(1, tmp);\
|
|
tmp = lrx - ulx - cw -> inner_width - cw -> \
|
|
box.borderwidth - cw -> inner_x - 2 * cw -> inner_borderwidth + 1;\
|
|
inner_lrbx = Max(1, tmp);\
|
|
tmp = lry - uly - cw -> inner_height - cw ->\
|
|
box.borderwidth - cw -> inner_y - 2 * cw -> inner_borderwidth + 1;\
|
|
inner_lrby = Max(1, tmp);\
|
|
}
|
|
|
|
static int xdir, ydir; /* resize dirs */
|
|
char * MakeUserDims(), *MakePairUserDims();
|
|
|
|
/* global */
|
|
|
|
extern Wob GetTarget();
|
|
extern WOOL_OBJECT MeterClose();
|
|
|
|
/* routines */
|
|
|
|
/*
|
|
* type of grid:
|
|
* 0 outer rectangle of the window (default)
|
|
* 1 outer rectangle divided in 9 (uwm-style)
|
|
* 2 outer rectangle with center cross (X) inside
|
|
* 3 outer rectangle + inner (client) outline
|
|
* 4 styles 1 and 3 combined
|
|
* 5 2-pixel wide grid
|
|
*/
|
|
|
|
#define MAX_GRID_SEGMENTS 1024
|
|
|
|
int
|
|
StoreBox(type, box, ulx, uly, lrx, lry)
|
|
int type; /* the type of grid */
|
|
XSegment box[];
|
|
int ulx; /* Upper left X coordinate. */
|
|
int uly; /* Upper left Y coordinate. */
|
|
int lrx; /* Lower right X coordinate. */
|
|
int lry; /* Lower right Y coordinate. */
|
|
{
|
|
int number_of_segments = 8;
|
|
|
|
box[0].x1 = ulx;
|
|
box[0].y1 = uly;
|
|
box[0].x2 = lrx;
|
|
box[0].y2 = uly;
|
|
|
|
box[1].x1 = lrx;
|
|
box[1].y1 = uly;
|
|
box[1].x2 = lrx;
|
|
box[1].y2 = lry;
|
|
|
|
box[2].x1 = lrx;
|
|
box[2].y1 = lry;
|
|
box[2].x2 = ulx;
|
|
box[2].y2 = lry;
|
|
|
|
box[3].x1 = ulx;
|
|
box[3].y1 = lry;
|
|
box[3].x2 = ulx;
|
|
box[3].y2 = uly;
|
|
|
|
switch (type) {
|
|
case 5: /* MwmLike grid */
|
|
box[4].x1 = ulx + 1;
|
|
box[4].y1 = uly + 1;
|
|
box[4].x2 = lrx - 1;
|
|
box[4].y2 = uly + 1;
|
|
|
|
box[5].x1 = ulx + 1;
|
|
box[5].y1 = uly + 1;
|
|
box[5].x2 = ulx + 1;
|
|
box[5].y2 = lry - 1;
|
|
|
|
box[6].x1 = ulx + 1;
|
|
box[6].y1 = lry - 1;
|
|
box[6].x2 = lrx - 1;
|
|
box[6].y2 = lry - 1;
|
|
|
|
box[7].x1 = lrx - 1;
|
|
box[7].y1 = uly + 1;
|
|
box[7].x2 = lrx - 1;
|
|
box[7].y2 = lry - 1;
|
|
|
|
return (8) ;
|
|
|
|
case 4: /* 9-squares grid + inner outline */
|
|
box[8].x1 = ulx + (lrx - ulx) / 3;
|
|
box[8].y1 = uly;
|
|
box[8].x2 = box[8].x1;
|
|
box[8].y2 = lry;
|
|
|
|
box[9].x1 = lrx - (lrx - ulx) / 3;
|
|
box[9].y1 = uly;
|
|
box[9].x2 = box[9].x1;
|
|
box[9].y2 = lry;
|
|
|
|
box[10].x1 = ulx;
|
|
box[10].y1 = uly + (lry - uly) / 3;
|
|
box[10].x2 = lrx;
|
|
box[10].y2 = box[10].y1;
|
|
|
|
box[11].x1 = ulx;
|
|
box[11].y1 = lry - (lry - uly) / 3;
|
|
box[11].x2 = lrx;
|
|
box[11].y2 = box[11].y1;
|
|
|
|
number_of_segments = 12;
|
|
|
|
case 3: /* + inner outline */
|
|
if (inner_uly) {
|
|
box[4].x1 = ulx + inner_ulx;
|
|
box[4].y1 = uly + inner_uly;
|
|
box[4].x2 = lrx - inner_lrbx;
|
|
box[4].y2 = box[4].y1;
|
|
} else {
|
|
box[4].x1 = box[4].y1 = box[4].x2 = box[4].y2 = 0;
|
|
}
|
|
if (inner_lrbx) {
|
|
box[5].x1 = lrx - inner_lrbx;
|
|
box[5].y1 = uly + inner_uly;
|
|
box[5].x2 = box[5].x1;
|
|
box[5].y2 = lry - inner_lrby;
|
|
} else {
|
|
box[5].x1 = box[5].y1 = box[5].x2 = box[5].y2 = 0;
|
|
}
|
|
if (inner_lrby) {
|
|
box[6].x1 = lrx - inner_lrbx;
|
|
box[6].y1 = lry - inner_lrby;
|
|
box[6].x2 = ulx + inner_ulx;
|
|
box[6].y2 = lry - inner_lrby;
|
|
} else {
|
|
box[6].x1 = box[6].y1 = box[6].x2 = box[6].y2 = 0;
|
|
}
|
|
if (inner_ulx) {
|
|
box[7].x1 = ulx + inner_ulx;
|
|
box[7].y1 = lry - inner_lrby;
|
|
box[7].x2 = ulx + inner_ulx;
|
|
box[7].y2 = uly + inner_uly;
|
|
} else {
|
|
box[7].x1 = box[7].y1 = box[7].x2 = box[7].y2 = 0;
|
|
}
|
|
|
|
return number_of_segments;
|
|
|
|
case 2: /* cross grid */
|
|
box[4].x1 = ulx;
|
|
box[4].y1 = uly;
|
|
box[4].x2 = lrx;
|
|
box[4].y2 = lry;
|
|
|
|
box[5].x1 = ulx;
|
|
box[5].y1 = lry;
|
|
box[5].x2 = lrx;
|
|
box[5].y2 = uly;
|
|
|
|
return (6);
|
|
|
|
case 1: /* 9-squares grid */
|
|
box[4].x1 = ulx + (lrx - ulx) / 3;
|
|
box[4].y1 = uly;
|
|
box[4].x2 = box[4].x1;
|
|
box[4].y2 = lry;
|
|
|
|
box[5].x1 = lrx - (lrx - ulx) / 3;
|
|
box[5].y1 = uly;
|
|
box[5].x2 = box[5].x1;
|
|
box[5].y2 = lry;
|
|
|
|
box[6].x1 = ulx;
|
|
box[6].y1 = uly + (lry - uly) / 3;
|
|
box[6].x2 = lrx;
|
|
box[6].y2 = box[6].y1;
|
|
|
|
box[7].x1 = ulx;
|
|
box[7].y1 = lry - (lry - uly) / 3;
|
|
box[7].x2 = lrx;
|
|
box[7].y2 = box[7].y1;
|
|
|
|
return (8);
|
|
|
|
default: /* simple outer square */
|
|
return (4);
|
|
}
|
|
}
|
|
int
|
|
AddBox(Nprevious, type , box, ulx, uly, lrx, lry)
|
|
int type, Nprevious; /* the type of grid */
|
|
XSegment box[];
|
|
int ulx; /* Upper left X coordinate. */
|
|
int uly; /* Upper left Y coordinate. */
|
|
int lrx; /* Lower right X coordinate. */
|
|
int lry; /* Lower right Y coordinate. */
|
|
{
|
|
int number_of_segments = 8;
|
|
|
|
box[Nprevious + 0].x1 = ulx;
|
|
box[Nprevious + 0].y1 = uly;
|
|
box[Nprevious + 0].x2 = lrx;
|
|
box[Nprevious + 0].y2 = uly;
|
|
|
|
box[Nprevious + 1].x1 = lrx;
|
|
box[Nprevious + 1].y1 = uly;
|
|
box[Nprevious + 1].x2 = lrx;
|
|
box[Nprevious + 1].y2 = lry;
|
|
|
|
box[Nprevious + 2].x1 = lrx;
|
|
box[Nprevious + 2].y1 = lry;
|
|
box[Nprevious + 2].x2 = ulx;
|
|
box[Nprevious + 2].y2 = lry;
|
|
|
|
box[Nprevious + 3].x1 = ulx;
|
|
box[Nprevious + 3].y1 = lry;
|
|
box[Nprevious + 3].x2 = ulx;
|
|
box[Nprevious + 3].y2 = uly;
|
|
|
|
/* simple outer square */
|
|
return (Nprevious + 4);
|
|
}
|
|
|
|
WOOL_OBJECT
|
|
UserMoveWindow(cw)
|
|
ClientWindow cw;
|
|
{
|
|
int prev_x; /* Previous evt window X location. */
|
|
int prev_y; /* Previous evt window Y location. */
|
|
int cur_x; /* Current event window X location. */
|
|
int cur_y; /* Current event window Y location. */
|
|
int root_x; /* Root window X location. */
|
|
int root_y; /* Root window Y location. */
|
|
int ulx, uly; /* Event window upper left X, Y. */
|
|
int lrx, lry; /* Event window lower right X, Y. */
|
|
int num_vectors; /* Number of vectors in box. */
|
|
unsigned int ptrmask; /* state of ptr when queried */
|
|
Window sub_window; /* Query mouse event sub-window. */
|
|
Window root; /* Query mouse event root. */
|
|
XEvent button_event; /* Button event packet. */
|
|
XSegment box[MAX_GRID_SEGMENTS]; /* Box vertex buffer. */
|
|
unsigned long mask = ButtonPressMask | ButtonReleaseMask;
|
|
int called_from_press; /* aborts on press! */
|
|
int called_from_press_button; /* aborts on press! */
|
|
WOOL_Cursor cursor;
|
|
|
|
/* Get Position of pointer of the event */
|
|
XQueryPointer(dpy, Context->root,
|
|
&root, &sub_window,
|
|
&root_x, &root_y, &cur_x, &cur_y, &ptrmask);
|
|
if (root != Context->root) { /* cursor is on another screen */
|
|
return (WOOL_OBJECT) WLNumber_make(1);
|
|
}
|
|
if (TriggeringEvent && TriggeringEvent->type == ButtonPress) {
|
|
cur_x = TriggeringEvent->xbutton.x_root;
|
|
cur_y = TriggeringEvent->xbutton.y_root;
|
|
called_from_press = 1;
|
|
called_from_press_button = TriggeringEvent->xbutton.button;
|
|
/* if button has been released, aborts! */
|
|
if (GWM_UserSynchronous && !(ptrmask &
|
|
(Button1Mask << (called_from_press_button - Button1))))
|
|
return (WOOL_OBJECT) WLNumber_make(3);
|
|
}
|
|
else {
|
|
/* put the pointer always inside the window */
|
|
cur_x = Max(cur_x, cw->box.x);
|
|
cur_y = Max(cur_y, cw->box.y);
|
|
cur_x = Min(cur_x, cw->box.x + cw->box.width +
|
|
2 * cw->box.borderwidth);
|
|
cur_y = Min(cur_y, cw->box.y + cw->box.height +
|
|
2 * cw->box.borderwidth);
|
|
called_from_press = 0;
|
|
}
|
|
|
|
cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursor, (WA_cursor));
|
|
if (XGrabPointer(dpy, Context->root, FALSE, mask,
|
|
GrabModeAsync, GrabModeAsync, None,
|
|
(cursor == (WOOL_Cursor) NIL ? None : cursor->cursor),
|
|
CurrentTime)
|
|
!= GrabSuccess)
|
|
return (WOOL_OBJECT) WLNumber_make(0);
|
|
if (GWM_GrabServer)
|
|
XGrabServer(dpy);
|
|
XSetForeground(dpy, Context->gc.Draw, Context->pixel.GridColor);
|
|
|
|
/* Initialize movement variables. */
|
|
ulx = cw->box.x;
|
|
uly = cw->box.y;
|
|
lrx = cw->box.x + cw->box.width + (cw->box.borderwidth * 2) - 1;
|
|
lry = cw->box.y + cw->box.height + (cw->box.borderwidth * 2) - 1;
|
|
MAKE_INNER_DIMS
|
|
|
|
/* Store the box. */
|
|
num_vectors = StoreBox(GWM_Movegrid, box, ulx, uly, lrx, lry);
|
|
|
|
/* Initialize the previous location variables. */
|
|
prev_x = cur_x;
|
|
prev_y = cur_y;
|
|
|
|
/* Now draw the box. */
|
|
XDrawSegments(dpy, Context->root, Context->gc.Draw, box, num_vectors);
|
|
if (GWM_Move_meter) {
|
|
MeterOpen("(100,100)");
|
|
MeterUpdate(MakePairUserDims(ulx, uly));
|
|
}
|
|
|
|
/* Main loop. */
|
|
while (TRUE) {
|
|
if (XCheckMaskEvent(dpy, ButtonReleaseMask | ButtonPressMask,
|
|
&button_event)) {
|
|
/* The button was released, so move the window. */
|
|
XDrawSegments(dpy, Context->root, Context->gc.Draw,
|
|
box, num_vectors);
|
|
if (!called_from_press || button_event.type == ButtonRelease) {
|
|
/* MOVE HOOK */
|
|
XMoveWindow(dpy, cw->hook, /* only move if released */
|
|
button_event.xbutton.x_root + ulx - prev_x,
|
|
button_event.xbutton.y_root + uly - prev_y);
|
|
cw->box.x = button_event.xbutton.x_root + ulx - prev_x;
|
|
cw->box.y = button_event.xbutton.y_root + uly - prev_y;
|
|
SendSyntheticMoveEvent(cw);
|
|
if (button_event.type == ButtonPress)
|
|
wait_for_button_release(button_event.xbutton.button);
|
|
if (GWM_Move_meter)
|
|
MeterClose();
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
if (GWM_GrabServer)
|
|
XUngrabServer(dpy);
|
|
return NIL;
|
|
}
|
|
else { /* another buttonpress = abort! */
|
|
wait_for_button_release(button_event.xbutton.button);
|
|
wait_for_button_release(called_from_press_button);
|
|
if (GWM_Move_meter)
|
|
MeterClose();
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
if (GWM_GrabServer)
|
|
XUngrabServer(dpy);
|
|
return (WOOL_OBJECT) WLNumber_make(2);
|
|
}
|
|
}
|
|
/* track ghost window */
|
|
XQueryPointer(dpy,
|
|
RootWindow(dpy, Context->screen), &root, &sub_window,
|
|
&root_x, &root_y, &cur_x, &cur_y, &ptrmask);
|
|
if ((cur_x != prev_x) || (cur_y != prev_y)) {
|
|
/* erase the old box first! */
|
|
XDrawSegments(dpy, Context->root, Context->gc.Draw, box,
|
|
num_vectors);
|
|
ulx += cur_x - prev_x; /* change Box position. */
|
|
uly += cur_y - prev_y;
|
|
lrx += cur_x - prev_x;
|
|
lry += cur_y - prev_y;
|
|
if (GWM_confine_windows) {
|
|
if (ulx < 0) {
|
|
lrx -= ulx;
|
|
ulx = 0;
|
|
}
|
|
if (uly < 0) {
|
|
lry -= uly;
|
|
uly = 0;
|
|
}
|
|
if (lrx >= Context->width) {
|
|
ulx -= (lrx - Context->width) + 1;
|
|
lrx = Context->width - 1;
|
|
}
|
|
if (lry >= Context->height) {
|
|
uly -= (lry - Context->height) + 1;
|
|
lry = Context->height - 1;
|
|
}
|
|
}
|
|
num_vectors = StoreBox(GWM_Movegrid, box, ulx, uly, lrx, lry);
|
|
/* Draw the new box. */
|
|
XDrawSegments(dpy, Context->root, Context->gc.Draw, box,
|
|
num_vectors);
|
|
if (GWM_Move_meter)
|
|
MeterUpdate(MakePairUserDims(ulx, uly));
|
|
}
|
|
/* Save old box position. */
|
|
prev_x = cur_x;
|
|
prev_y = cur_y;
|
|
}
|
|
}
|
|
|
|
/* move several windows at once */
|
|
WOOL_OBJECT
|
|
UserMoveSeveralWindows(Ncw, cwl)
|
|
ClientWindow cwl[];
|
|
int Ncw;
|
|
{
|
|
int prev_x; /* Previous evt window X location. */
|
|
int prev_y; /* Previous evt window Y location. */
|
|
int cur_x; /* Current event window X location. */
|
|
int cur_y; /* Current event window Y location. */
|
|
int root_x; /* Root window X location. */
|
|
int root_y; /* Root window Y location. */
|
|
int ulx, uly; /* Event window upper left X, Y. */
|
|
int lrx, lry; /* Event window lower right X, Y. */
|
|
int num_vectors; /* Number of vectors in box. */
|
|
unsigned int ptrmask; /* state of ptr when queried */
|
|
Window sub_window; /* Query mouse event sub-window. */
|
|
Window root; /* Query mouse event root. */
|
|
XEvent button_event; /* Button event packet. */
|
|
XSegment box[MAX_GRID_SEGMENTS]; /* Box vertex buffer. */
|
|
unsigned long mask = ButtonPressMask | ButtonReleaseMask;
|
|
int called_from_press; /* aborts on press! */
|
|
int called_from_press_button; /* aborts on press! */
|
|
WOOL_Cursor cursor;
|
|
int max_num_vectors;
|
|
ClientWindow cw;
|
|
int i;
|
|
|
|
if (Ncw < 1)
|
|
return (WOOL_OBJECT) WLNumber_make(0);
|
|
cw = cwl[0];
|
|
|
|
/* Get Position of pointer of the event */
|
|
XQueryPointer(dpy, Context->root,
|
|
&root, &sub_window,
|
|
&root_x, &root_y, &cur_x, &cur_y, &ptrmask);
|
|
if (root != Context->root) { /* cursor is on another screen */
|
|
return (WOOL_OBJECT) WLNumber_make(1);
|
|
}
|
|
if (TriggeringEvent && TriggeringEvent->type == ButtonPress) {
|
|
cur_x = TriggeringEvent->xbutton.x_root;
|
|
cur_y = TriggeringEvent->xbutton.y_root;
|
|
called_from_press = 1;
|
|
called_from_press_button = TriggeringEvent->xbutton.button;
|
|
/* if button has been released, aborts! */
|
|
if (GWM_UserSynchronous && !(ptrmask &
|
|
(Button1Mask << (called_from_press_button - Button1))))
|
|
return (WOOL_OBJECT) WLNumber_make(3);
|
|
}
|
|
else {
|
|
/* put the pointer always inside the window */
|
|
cur_x = Max(cur_x, cw->box.x);
|
|
cur_y = Max(cur_y, cw->box.y);
|
|
cur_x = Min(cur_x, cw->box.x + cw->box.width +
|
|
2 * cw->box.borderwidth);
|
|
cur_y = Min(cur_y, cw->box.y + cw->box.height +
|
|
2 * cw->box.borderwidth);
|
|
called_from_press = 0;
|
|
}
|
|
|
|
cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursor, (WA_cursor));
|
|
if (XGrabPointer(dpy, Context->root, FALSE, mask,
|
|
GrabModeAsync, GrabModeAsync, None,
|
|
(cursor == (WOOL_Cursor) NIL ? None : cursor->cursor),
|
|
CurrentTime)
|
|
!= GrabSuccess)
|
|
return (WOOL_OBJECT) WLNumber_make(0);
|
|
if (GWM_GrabServer)
|
|
XGrabServer(dpy);
|
|
XSetForeground(dpy, Context->gc.Draw, Context->pixel.GridColor);
|
|
|
|
/* Initialize movement variables. */
|
|
ulx = cw->box.x;
|
|
uly = cw->box.y;
|
|
lrx = cw->box.x + cw->box.width + (cw->box.borderwidth * 2) - 1;
|
|
lry = cw->box.y + cw->box.height + (cw->box.borderwidth * 2) - 1;
|
|
MAKE_INNER_DIMS
|
|
|
|
/* Store the box. */
|
|
num_vectors = StoreBox(GWM_Movegrid, box, ulx, uly, lrx, lry);
|
|
for (i = 1; i < Ncw; i++)
|
|
num_vectors = AddBox(num_vectors, GWM_Movegrid,
|
|
box, cwl[i]->box.x, cwl[i]->box.y,
|
|
cwl[i]->box.x + cwl[i]->box.width + (cwl[i]->box.borderwidth * 2) - 1,
|
|
cwl[i]->box.y + cwl[i]->box.height + (cwl[i]->box.borderwidth * 2) - 1);
|
|
max_num_vectors = num_vectors;
|
|
/* Initialize the previous location variables. */
|
|
prev_x = cur_x;
|
|
prev_y = cur_y;
|
|
|
|
/* Now draw the box. */
|
|
XDrawSegments(dpy, Context->root, Context->gc.Draw, box, num_vectors);
|
|
if (GWM_Move_meter) {
|
|
MeterOpen("(100,100)");
|
|
MeterUpdate(MakePairUserDims(ulx, uly));
|
|
}
|
|
|
|
/* Main loop. */
|
|
while (TRUE) {
|
|
if (XCheckMaskEvent(dpy, ButtonReleaseMask | ButtonPressMask,
|
|
&button_event)) {
|
|
/* The button was released, so move the window. */
|
|
XDrawSegments(dpy, Context->root, Context->gc.Draw,
|
|
box, num_vectors);
|
|
if (!called_from_press || button_event.type == ButtonRelease) {
|
|
int WindowIndex;
|
|
int DeltaX, DeltaY;
|
|
|
|
DeltaX = button_event.xbutton.x_root - prev_x+ulx-cw->box.x;
|
|
DeltaY = button_event.xbutton.y_root - prev_y+uly-cw->box.y;
|
|
/* MOVE HOOK */
|
|
#ifdef ToBeDeleted
|
|
XMoveWindow(dpy, cw->hook, /* only move if released */
|
|
DeltaX + cw->box.x, DeltaY+ cw->box.y);
|
|
cw->box.x += DeltaX;
|
|
cw->box.y += DeltaY;
|
|
SendSyntheticMoveEvent(cw);
|
|
#endif
|
|
for (WindowIndex = 0 ; WindowIndex < Ncw; WindowIndex++)
|
|
{
|
|
XMoveWindow(dpy, cwl[WindowIndex]->hook,
|
|
cwl[WindowIndex]->box.x + DeltaX,
|
|
cwl[WindowIndex]->box.y + DeltaY);
|
|
cwl[WindowIndex]->box.x += DeltaX;
|
|
cwl[WindowIndex]->box.y += DeltaY;
|
|
SendSyntheticMoveEvent(cwl[WindowIndex]);
|
|
}
|
|
|
|
if (button_event.type == ButtonPress)
|
|
wait_for_button_release(button_event.xbutton.button);
|
|
if (GWM_Move_meter)
|
|
MeterClose();
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
if (GWM_GrabServer)
|
|
XUngrabServer(dpy);
|
|
return NIL;
|
|
}
|
|
else { /* another buttonpress = abort! */
|
|
wait_for_button_release(button_event.xbutton.button);
|
|
wait_for_button_release(called_from_press_button);
|
|
if (GWM_Move_meter)
|
|
MeterClose();
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
if (GWM_GrabServer)
|
|
XUngrabServer(dpy);
|
|
return (WOOL_OBJECT) WLNumber_make(2);
|
|
}
|
|
}
|
|
/* track ghost window */
|
|
XQueryPointer(dpy,
|
|
RootWindow(dpy, Context->screen), &root, &sub_window,
|
|
&root_x, &root_y, &cur_x, &cur_y, &ptrmask);
|
|
if ((cur_x != prev_x) || (cur_y != prev_y)) {
|
|
/* erase the old box first! */
|
|
XDrawSegments(dpy, Context->root, Context->gc.Draw, box,
|
|
num_vectors);
|
|
ulx += cur_x - prev_x; /* change Box position. */
|
|
uly += cur_y - prev_y;
|
|
lrx += cur_x - prev_x;
|
|
lry += cur_y - prev_y;
|
|
if (GWM_confine_windows) {
|
|
if (ulx < 0) {
|
|
lrx -= ulx;
|
|
ulx = 0;
|
|
}
|
|
if (uly < 0) {
|
|
lry -= uly;
|
|
uly = 0;
|
|
}
|
|
if (lrx >= Context->width) {
|
|
ulx -= (lrx - Context->width) + 1;
|
|
lrx = Context->width - 1;
|
|
}
|
|
if (lry >= Context->height) {
|
|
uly -= (lry - Context->height) + 1;
|
|
lry = Context->height - 1;
|
|
}
|
|
}
|
|
num_vectors = StoreBox(GWM_Movegrid, box, ulx, uly, lrx, lry);
|
|
for (i = num_vectors; i < max_num_vectors; i++) {
|
|
box[i].x1 += cur_x - prev_x;
|
|
box[i].x2 += cur_x - prev_x;
|
|
box[i].y1 += cur_y - prev_y;
|
|
box[i].y2 += cur_y - prev_y;
|
|
}
|
|
num_vectors = max_num_vectors;
|
|
/* Draw the new box. */
|
|
XDrawSegments(dpy, Context->root, Context->gc.Draw, box,
|
|
num_vectors);
|
|
if (GWM_Move_meter)
|
|
MeterUpdate(MakePairUserDims(ulx, uly));
|
|
}
|
|
/* Save old box position. */
|
|
prev_x = cur_x;
|
|
prev_y = cur_y;
|
|
}
|
|
}
|
|
|
|
WOOL_OBJECT
|
|
UserResizeWindow(cw)
|
|
ClientWindow cw;
|
|
{
|
|
int prev_x2; /* Previous evt window X location. */
|
|
int prev_y2; /* Previous evt window Y location. */
|
|
int init_x, init_y;
|
|
int init_x2, init_y2;
|
|
int x1, y1; /* fixed point */
|
|
int x2, y2; /* varying point */
|
|
int cur_x; /* Current event window X location. */
|
|
int cur_y; /* Current event window Y location. */
|
|
int root_x; /* Root window X location. */
|
|
int root_y; /* Root window Y location. */
|
|
int ulx, uly; /* Event window upper left X, Y. */
|
|
int lrx, lry; /* Event window lower right X, Y. */
|
|
int init_ulx, init_uly; /* Init window upper left X and Y. */
|
|
int init_lrx, init_lry; /* Init window lower right X and Y. */
|
|
int num_vectors; /* Number of vectors in box. */
|
|
unsigned int ptrmask; /* state of ptr when queried */
|
|
Window sub_window; /* Query mouse event sub-window. */
|
|
Window root; /* Query mouse event root. */
|
|
XEvent button_event; /* Button event packet. */
|
|
XSegment box[MAX_GRID_SEGMENTS]; /* Box vertex buffer. */
|
|
unsigned long mask = ButtonPressMask | ButtonReleaseMask;
|
|
int inner_width, inner_height;
|
|
int called_from_press; /* aborts on press! */
|
|
int called_from_press_button; /* aborts on press! */
|
|
WOOL_Cursor cursor;
|
|
|
|
/* Get Position of pointer of the event */
|
|
XQueryPointer(dpy, Context -> root,
|
|
&root, &sub_window,
|
|
&root_x, &root_y, &cur_x, &cur_y, &ptrmask);
|
|
if (root != Context -> root) { /* cursor is on another screen */
|
|
return (WOOL_OBJECT) WLNumber_make(1);
|
|
}
|
|
if (TriggeringEvent && TriggeringEvent -> type == ButtonPress) {
|
|
cur_x = TriggeringEvent -> xbutton.x_root;
|
|
cur_y = TriggeringEvent -> xbutton.y_root;
|
|
called_from_press = 1;
|
|
called_from_press_button = TriggeringEvent -> xbutton.button;
|
|
/* if button has been released, aborts! */
|
|
if (GWM_UserSynchronous && !(ptrmask &
|
|
(Button1Mask << (called_from_press_button - Button1))))
|
|
return (WOOL_OBJECT) WLNumber_make(3);
|
|
} else {
|
|
/* put the pointer always inside the window */
|
|
cur_x = Max(cur_x, cw -> box.x);
|
|
cur_y = Max(cur_y, cw -> box.y);
|
|
cur_x = Min(cur_x, cw -> box.x + cw -> box.width +
|
|
2 * cw -> box.borderwidth);
|
|
cur_y = Min(cur_y, cw -> box.y + cw -> box.height +
|
|
2 * cw -> box.borderwidth);
|
|
called_from_press = 0;
|
|
}
|
|
|
|
init_x = cur_x;
|
|
init_y = cur_y;
|
|
|
|
cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursor, (WA_cursor));
|
|
if (XGrabPointer(dpy, Context -> root, FALSE, mask,
|
|
GrabModeAsync, GrabModeAsync, None,
|
|
(cursor == (WOOL_Cursor) NIL ? None : cursor -> cursor),
|
|
CurrentTime)
|
|
!= GrabSuccess)
|
|
return (WOOL_OBJECT) WLNumber_make(0);
|
|
if (GWM_GrabServer)
|
|
XGrabServer(dpy);
|
|
XSetForeground(dpy, Context -> gc.Draw, Context -> pixel.GridColor);
|
|
|
|
/* Initialize movement variables. */
|
|
init_ulx = ulx = cw -> box.x;
|
|
init_uly = uly = cw -> box.y;
|
|
init_lrx = lrx = cw -> box.x + cw -> box.width +
|
|
(cw -> box.borderwidth * 2) - 1;
|
|
init_lry = lry = cw -> box.y + cw -> box.height +
|
|
(cw -> box.borderwidth * 2) - 1;
|
|
MAKE_INNER_DIMS
|
|
|
|
/* determine the direction of resize 0, 1 or 2 */
|
|
xdir = ((cur_x - ulx) * 3) / (lrx - ulx);
|
|
ydir = ((cur_y - uly) * 3) / (lry - uly);
|
|
/* handle cur_x == lrx case */
|
|
if (xdir == 3)
|
|
xdir = 2;
|
|
if (ydir == 3)
|
|
ydir = 2;
|
|
/* determine the fixed & varying points */
|
|
if (xdir) {
|
|
x1 = ulx;
|
|
x2 = lrx;
|
|
} else {
|
|
x1 = lrx;
|
|
x2 = ulx;
|
|
}
|
|
if (ydir) {
|
|
y1 = uly;
|
|
y2 = lry;
|
|
} else {
|
|
y1 = lry;
|
|
y2 = uly;
|
|
}
|
|
|
|
/* Initialize the previous location variables. */
|
|
init_x2 = prev_x2 = x2;
|
|
init_y2 = prev_y2 = y2;
|
|
|
|
/* Store the box. */
|
|
num_vectors = StoreBox(GWM_Resizegrid, box, Min(x1, x2), Min(y1, y2),
|
|
Max(x1, x2), Max(y1, y2));
|
|
/* Now draw the box. */
|
|
XDrawSegments(dpy, Context -> root, Context -> gc.Draw, box, num_vectors);
|
|
if (GWM_Resize_meter) {
|
|
MeterOpen("80x24");
|
|
MeterUpdate(MakeUserDims(&(cw -> cached_props -> normal_hints),
|
|
cw -> inner_width, cw -> inner_height));
|
|
}
|
|
/* Main loop. */
|
|
while (TRUE) {
|
|
if (XCheckMaskEvent(dpy, ButtonReleaseMask | ButtonPressMask,
|
|
&button_event)) {
|
|
/* The button was released, so move the window. */
|
|
XDrawSegments(dpy, Context -> root, Context -> gc.Draw,
|
|
box, num_vectors);
|
|
/* OK, let's resize! */
|
|
if (!called_from_press || button_event.type == ButtonRelease) {
|
|
int delta, borderwidth, depth;
|
|
|
|
delta = Min(x1, x2) - init_ulx;
|
|
cw -> box.x += delta;
|
|
delta = Min(y1, y2) - init_uly;
|
|
cw -> box.y += delta;
|
|
delta = Max(x1, x2) - init_lrx - (Min(x1, x2) - init_ulx);
|
|
cw -> inner_width += delta;
|
|
cw -> box.width += delta;
|
|
delta = Max(y1, y2) - init_lry - (Min(y1, y2) - init_uly);
|
|
cw -> inner_height += delta;
|
|
cw -> box.height += delta;
|
|
XResizeWindow(dpy, cw -> client,
|
|
cw -> inner_width, cw -> inner_height);
|
|
ReconfigureClientWindow(cw, cw -> client);
|
|
if (button_event.type == ButtonPress)
|
|
wait_for_button_release(button_event.xbutton.button);
|
|
if (GWM_Resize_meter)
|
|
MeterClose();
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
if (GWM_GrabServer)
|
|
XUngrabServer(dpy);
|
|
return NIL;
|
|
} else { /* another buttonpress = abort! */
|
|
wait_for_button_release(button_event.xbutton.button);
|
|
wait_for_button_release(called_from_press_button);
|
|
if (GWM_Resize_meter)
|
|
MeterClose();
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
if (GWM_GrabServer)
|
|
XUngrabServer(dpy);
|
|
return (WOOL_OBJECT) WLNumber_make(2);
|
|
}
|
|
}
|
|
/* track ghost window */
|
|
XQueryPointer(dpy,
|
|
RootWindow(dpy, Context -> screen), &root, &sub_window,
|
|
&root_x, &root_y, &cur_x, &cur_y, &ptrmask);
|
|
x2 = validate_dir(xdir, cur_x - init_x, cw -> inner_width);
|
|
y2 = validate_dir(ydir, cur_y - init_y, cw -> inner_height);
|
|
inner_width = cw -> inner_width + (xdir ? x2 : -x2);
|
|
inner_height = cw -> inner_height + (ydir ? y2 : -y2);
|
|
conform_to_hints(&(cw -> cached_props -> normal_hints),
|
|
&inner_width, &inner_height);
|
|
x2 = init_x2 + (xdir ? inner_width - cw -> inner_width :
|
|
cw -> inner_width - inner_width);
|
|
y2 = init_y2 + (ydir ? inner_height - cw -> inner_height :
|
|
cw -> inner_height - inner_height);
|
|
if (GWM_confine_windows) {
|
|
int readjust = 0;
|
|
if (x2 < 0) {
|
|
x2 = 0;
|
|
inner_width = (cw -> box.x - x2) + cw -> inner_width;
|
|
readjust = 1;
|
|
} else if (x2 >= Context -> width) {
|
|
x2 = Context -> width;
|
|
inner_width = cw -> inner_width + x2
|
|
- (cw -> box.x + cw->box.width + 2*(cw->box.borderwidth));
|
|
readjust = 1;
|
|
}
|
|
|
|
if (y2<0) {
|
|
y2 = 0;
|
|
inner_height = (cw -> box.y - y2) + cw -> inner_height;
|
|
readjust = 1;
|
|
} else if (y2 >= Context -> height) {
|
|
y2 = Context -> height;
|
|
inner_height = cw -> inner_height + y2
|
|
- (cw->box.y + cw->box.height + 2*(cw->box.borderwidth));
|
|
readjust = 1;
|
|
}
|
|
if (readjust) {
|
|
conform_to_hints(&(cw -> cached_props -> normal_hints),
|
|
&inner_width, &inner_height);
|
|
x2 = init_x2 + (xdir ? inner_width - cw -> inner_width :
|
|
cw -> inner_width - inner_width);
|
|
y2 = init_y2 + (ydir ? inner_height - cw -> inner_height :
|
|
cw -> inner_height - inner_height);
|
|
}
|
|
}
|
|
if ((x2 != prev_x2) || (y2 != prev_y2)) {
|
|
/* erase the old box first! */
|
|
XDrawSegments(dpy, Context -> root, Context -> gc.Draw, box,
|
|
num_vectors);
|
|
num_vectors = StoreBox(GWM_Resizegrid, box,
|
|
Min(x1, x2), Min(y1, y2),
|
|
Max(x1, x2), Max(y1, y2));
|
|
/* Draw the new box. */
|
|
XDrawSegments(dpy, Context -> root, Context -> gc.Draw, box,
|
|
num_vectors);
|
|
if (GWM_Resize_meter)
|
|
MeterUpdate(MakeUserDims(
|
|
&(cw -> cached_props -> normal_hints),
|
|
inner_width, inner_height));
|
|
/* Save old box position. */
|
|
prev_x2 = x2;
|
|
prev_y2 = y2;
|
|
}
|
|
}
|
|
}
|
|
|
|
int
|
|
validate_dir(dir, delta, margin)
|
|
int dir, delta, margin;
|
|
{
|
|
switch (dir) {
|
|
case 0:
|
|
return Min(margin, delta);
|
|
case 2:
|
|
return Max(-margin, delta);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int
|
|
conform_to_hints(hints, width, height)
|
|
XSizeHints *hints;
|
|
int *width, *height;
|
|
{
|
|
if (hints -> flags & PMinSize) {
|
|
if (*width < hints -> min_width)
|
|
*width = hints -> min_width;
|
|
if (*height < hints -> min_height)
|
|
*height = hints -> min_height;
|
|
}
|
|
if (hints -> flags & PMaxSize) {
|
|
if (*width > hints -> max_width)
|
|
*width = hints -> max_width;
|
|
if (*height > hints -> max_height)
|
|
*height = hints -> max_height;
|
|
}
|
|
if (hints -> flags & PAspect) {
|
|
if (hints -> min_aspect.y * (*width)
|
|
< hints -> min_aspect.x * (*height)) {
|
|
if (xdir == 1) {
|
|
*height = ((*width) * hints -> min_aspect.y)
|
|
/ hints -> min_aspect.x;
|
|
} else {
|
|
*width = ((*height) * hints -> min_aspect.x)
|
|
/ hints -> min_aspect.y;
|
|
}
|
|
}
|
|
if (hints -> max_aspect.y * (*width)
|
|
> hints -> max_aspect.x * (*height)) {
|
|
if (ydir == 1) {
|
|
*width = ((*height) * hints -> max_aspect.x)
|
|
/ hints -> max_aspect.y;
|
|
} else {
|
|
*height = ((*width) * hints -> max_aspect.y)
|
|
/ hints -> max_aspect.x;
|
|
}
|
|
}
|
|
}
|
|
#ifdef NOBASEDIMS
|
|
if (hints -> flags & PResizeInc) {
|
|
*width = hints -> min_width + hints -> width_inc *
|
|
(((*width) - hints -> min_width) / hints -> width_inc);
|
|
*height = hints -> min_height + hints -> height_inc *
|
|
(((*height) - hints -> min_height) / hints -> height_inc);
|
|
}
|
|
#else /* NOBASEDIMS */
|
|
if (hints -> flags & PResizeInc) {
|
|
*width = hints -> base_width + hints -> width_inc *
|
|
(((*width) - hints -> base_width) / hints -> width_inc);
|
|
*height = hints -> base_height + hints -> height_inc *
|
|
(((*height) - hints -> base_height) / hints -> height_inc);
|
|
}
|
|
#endif /* NOBASEDIMS */
|
|
}
|
|
|
|
/*
|
|
* Updates the sizehints for consitency with themselves and the screen dims.
|
|
*/
|
|
|
|
CheckConsistency(hints)
|
|
XSizeHints *hints;
|
|
{
|
|
#ifndef NOBASEDIMS
|
|
if((hints -> flags & PMinSize) && !(hints -> flags & PBaseSize)) {
|
|
hints -> flags |= PBaseSize;
|
|
hints -> base_width = hints -> min_width;
|
|
hints -> base_height = hints -> min_height;
|
|
}
|
|
if((hints -> flags & PResizeInc) && !(hints -> flags & PBaseSize)) {
|
|
hints -> base_width = 0;
|
|
hints -> base_height = 0;
|
|
}
|
|
#else /* NOBASEDIMS */
|
|
if((hints -> flags & PResizeInc) && !(hints -> flags & PMinSize)) {
|
|
hints -> min_width = 0;
|
|
hints -> min_height = 0;
|
|
}
|
|
#endif /* NOBASEDIMS */
|
|
if (hints -> flags & PResizeInc &&
|
|
(hints -> width_inc <= 0 || hints -> height_inc <= 0)) {
|
|
hints -> height_inc = hints -> width_inc = 1;
|
|
trace(0, "Bogus increment hints\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* user feedback
|
|
*/
|
|
|
|
static char meter_str[20];
|
|
|
|
char *
|
|
MakePairUserDims(x, y)
|
|
int x, y;
|
|
{
|
|
sprintf(meter_str, "(%d, %d)", x, y );
|
|
return meter_str;
|
|
}
|
|
|
|
char *
|
|
MakeUserDims(hints, width, height)
|
|
XSizeHints *hints;
|
|
int width, height;
|
|
{
|
|
unsigned int rw, rh;
|
|
|
|
pixel_to_logical_size(hints, width, height, &rw, &rh);
|
|
sprintf(meter_str, "%d x %d", rw, rh);
|
|
return meter_str;
|
|
}
|
|
|
|
pixel_to_logical_size(hints, width, height, rw, rh)
|
|
XSizeHints *hints;
|
|
unsigned int width, height, *rw, *rh;
|
|
{
|
|
*rw = width;
|
|
*rh = height;
|
|
#ifdef NOBASEDIMS
|
|
if (hints->flags & PResizeInc) {
|
|
*rw = ((width) - hints->min_width) / hints->width_inc;
|
|
*rh = ((height) - hints->min_height) / hints->height_inc;
|
|
}
|
|
#else /* NOBASEDIMS */
|
|
if (hints->flags & PResizeInc) {
|
|
*rw = ((width) - hints->base_width) / hints->width_inc;
|
|
*rh = ((height) - hints->base_height) / hints->height_inc;
|
|
}
|
|
#endif /* NOBASEDIMS */
|
|
}
|
|
|
|
logical_to_pixel_size(hints, width, height, rw, rh)
|
|
XSizeHints *hints;
|
|
unsigned int width, height, *rw, *rh;
|
|
{
|
|
*rw = width;
|
|
*rh = height;
|
|
#ifdef NOBASEDIMS
|
|
if (hints -> flags & PResizeInc) {
|
|
*rw = hints -> min_width + width * hints -> width_inc;
|
|
*rh = hints -> min_height + height * hints -> height_inc;
|
|
}
|
|
#else /* NOBASEDIMS */
|
|
if (hints -> flags & PResizeInc) {
|
|
*rw = hints -> base_width + width * hints -> width_inc;
|
|
*rh = hints -> base_height + height * hints -> height_inc;
|
|
}
|
|
#endif /* NOBASEDIMS */
|
|
}
|
|
|
|
Cursor
|
|
get_zone_cursor(zone)
|
|
int zone;
|
|
{
|
|
WOOL_Cursor cursor ;
|
|
|
|
switch (zone)
|
|
{
|
|
case 0:
|
|
cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorNW, (WA_cursorNW));
|
|
break;
|
|
case 1:
|
|
cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorN, (WA_cursorN));
|
|
break;
|
|
case 2:
|
|
cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorNE, (WA_cursorNE));
|
|
break;
|
|
case 3:
|
|
cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorW, (WA_cursorW));
|
|
break;
|
|
case 5:
|
|
cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorE, (WA_cursorE));
|
|
break;
|
|
case 6:
|
|
cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorSW, (WA_cursorSW));
|
|
break;
|
|
case 7:
|
|
cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorS, (WA_cursorS));
|
|
break;
|
|
case 8:
|
|
cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursorSE, (WA_cursorSE));
|
|
break;
|
|
default: cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursor, (WA_cursor));
|
|
}
|
|
return (cursor == (WOOL_Cursor) NIL ? None : cursor -> cursor);
|
|
}
|
|
|
|
/* MWM-like resize
|
|
* code by Frederic Charton
|
|
*/
|
|
|
|
WOOL_OBJECT
|
|
MwmLikeUserResizeWindow(cw)
|
|
ClientWindow cw;
|
|
{
|
|
int prev_x2; /* Previous evt window X location. */
|
|
int prev_y2; /* Previous evt window Y location. */
|
|
int init_x, init_y;
|
|
int init_x2, init_y2;
|
|
int x1, y1; /* fixed point */
|
|
int x2, y2; /* varying point */
|
|
int cur_x; /* Current event window X location. */
|
|
int cur_y; /* Current event window Y location. */
|
|
int root_x; /* Root window X location. */
|
|
int root_y; /* Root window Y location. */
|
|
int ulx, uly; /* Event window upper left X, Y. */
|
|
int lrx, lry; /* Event window lower right X, Y. */
|
|
int init_ulx, init_uly; /* Init window upper left X and Y. */
|
|
int init_lrx, init_lry; /* Init window lower right X and Y. */
|
|
int num_vectors; /* Number of vectors in box. */
|
|
unsigned int ptrmask; /* state of ptr when queried */
|
|
Window sub_window; /* Query mouse event sub-window. */
|
|
Window root; /* Query mouse event root. */
|
|
XEvent button_event; /* Button event packet. */
|
|
XSegment box[MAX_GRID_SEGMENTS]; /* Box vertex buffer. */
|
|
unsigned long mask = ButtonPressMask | ButtonReleaseMask;
|
|
int inner_width, inner_height;
|
|
int called_from_press; /* aborts on press! */
|
|
int called_from_press_button; /* aborts on press! */
|
|
int zone;
|
|
int new_xdir, new_ydir, new_zone;
|
|
WOOL_Cursor cursor;
|
|
|
|
/* Get Position of pointer of the event */
|
|
XQueryPointer(dpy, Context -> root,
|
|
&root, &sub_window,
|
|
&root_x, &root_y, &cur_x, &cur_y, &ptrmask);
|
|
if (root != Context -> root) { /* cursor is on another screen */
|
|
return (WOOL_OBJECT) WLNumber_make(1);
|
|
}
|
|
if (TriggeringEvent && TriggeringEvent -> type == ButtonPress) {
|
|
cur_x = TriggeringEvent -> xbutton.x_root;
|
|
cur_y = TriggeringEvent -> xbutton.y_root;
|
|
called_from_press = 1;
|
|
called_from_press_button = TriggeringEvent -> xbutton.button;
|
|
/* if button has been released, aborts! */
|
|
if (GWM_UserSynchronous && !(ptrmask &
|
|
(Button1Mask << (called_from_press_button - Button1))))
|
|
return (WOOL_OBJECT) WLNumber_make(3);
|
|
} else {
|
|
/* put the pointer always inside the window */
|
|
cur_x = Max(cur_x, cw -> box.x);
|
|
cur_y = Max(cur_y, cw -> box.y);
|
|
cur_x = Min(cur_x, cw -> box.x + cw -> box.width +
|
|
2 * cw -> box.borderwidth);
|
|
cur_y = Min(cur_y, cw -> box.y + cw -> box.height +
|
|
2 * cw -> box.borderwidth);
|
|
called_from_press = 0;
|
|
}
|
|
|
|
init_x = cur_x;
|
|
init_y = cur_y;
|
|
|
|
cursor = (WOOL_Cursor) WOOL_send(WOOL_eval, WA_cursor, (WA_cursor));
|
|
if (XGrabPointer(dpy, Context -> root, FALSE, mask,
|
|
GrabModeAsync, GrabModeAsync, None,
|
|
(cursor == (WOOL_Cursor) NIL ? None : cursor -> cursor),
|
|
CurrentTime)
|
|
!= GrabSuccess)
|
|
return (WOOL_OBJECT) WLNumber_make(0);
|
|
if (GWM_GrabServer)
|
|
XGrabServer(dpy);
|
|
XSetForeground(dpy, Context -> gc.Draw, Context -> pixel.GridColor);
|
|
|
|
/* Initialize movement variables. */
|
|
init_ulx = ulx = cw -> box.x;
|
|
init_uly = uly = cw -> box.y;
|
|
init_lrx = lrx = cw -> box.x + cw -> box.width +
|
|
(cw -> box.borderwidth * 2) - 1;
|
|
init_lry = lry = cw -> box.y + cw -> box.height +
|
|
(cw -> box.borderwidth * 2) - 1;
|
|
MAKE_INNER_DIMS
|
|
|
|
/* determine the direction of resize 0, 1 or 2 */
|
|
if (GWM_window_cutting_size > 0) {
|
|
if (cur_x < (ulx + GWM_window_cutting_size))
|
|
xdir = 0;
|
|
else if (cur_x > (lrx - GWM_window_cutting_size))
|
|
xdir = 2;
|
|
else
|
|
xdir = 1;
|
|
if (cur_y < (uly + GWM_window_cutting_size))
|
|
ydir = 0;
|
|
else if (cur_y > (lry - GWM_window_cutting_size))
|
|
ydir = 2;
|
|
else
|
|
ydir = 1;
|
|
} else {
|
|
xdir = ((cur_x - ulx) * 3) / (lrx - ulx);
|
|
ydir = ((cur_y - uly) * 3) / (lry - uly);
|
|
/* handle cur_x == lrx case */
|
|
if (xdir == 3)
|
|
xdir = 2;
|
|
if (ydir == 3)
|
|
ydir = 2;
|
|
}
|
|
|
|
/* determine the fixed & varying points */
|
|
if (xdir) {
|
|
x1 = ulx;
|
|
x2 = lrx;
|
|
} else {
|
|
x1 = lrx;
|
|
x2 = ulx;
|
|
}
|
|
if (ydir) {
|
|
y1 = uly;
|
|
y2 = lry;
|
|
} else {
|
|
y1 = lry;
|
|
y2 = uly;
|
|
}
|
|
|
|
zone = 3 * ydir + xdir;
|
|
XChangeActivePointerGrab(dpy, mask, get_zone_cursor(zone), CurrentTime);
|
|
|
|
/* Initialize the previous location variables. */
|
|
init_x2 = prev_x2 = x2;
|
|
init_y2 = prev_y2 = y2;
|
|
|
|
/* Store the box. */
|
|
num_vectors = StoreBox(GWM_Resizegrid, box, Min(x1, x2), Min(y1, y2),
|
|
Max(x1, x2), Max(y1, y2));
|
|
/* Now draw the box. */
|
|
XDrawSegments(dpy, Context -> root, Context -> gc.Draw, box, num_vectors);
|
|
if (GWM_Resize_meter) {
|
|
MeterOpen("80x24");
|
|
MeterUpdate(MakeUserDims(&(cw -> cached_props -> normal_hints),
|
|
cw -> inner_width, cw -> inner_height));
|
|
}
|
|
/* Main loop. */
|
|
while (TRUE) {
|
|
if (XCheckMaskEvent(dpy, ButtonReleaseMask | ButtonPressMask,
|
|
&button_event)) {
|
|
/* The button was released, so move the window. */
|
|
XDrawSegments(dpy, Context -> root, Context -> gc.Draw,
|
|
box, num_vectors);
|
|
/* OK, let's resize! */
|
|
if (!called_from_press || button_event.type == ButtonRelease) {
|
|
int delta, borderwidth, depth;
|
|
|
|
delta = Min(x1, x2) - init_ulx;
|
|
cw -> box.x += delta;
|
|
delta = Min(y1, y2) - init_uly;
|
|
cw -> box.y += delta;
|
|
delta = Max(x1, x2) - init_lrx - (Min(x1, x2) - init_ulx);
|
|
cw -> inner_width += delta;
|
|
cw -> box.width += delta;
|
|
delta = Max(y1, y2) - init_lry - (Min(y1, y2) - init_uly);
|
|
cw -> inner_height += delta;
|
|
cw -> box.height += delta;
|
|
XResizeWindow(dpy, cw -> client,
|
|
cw -> inner_width, cw -> inner_height);
|
|
ReconfigureClientWindow(cw, cw -> client);
|
|
if (button_event.type == ButtonPress)
|
|
wait_for_button_release(button_event.xbutton.button);
|
|
if (GWM_Resize_meter)
|
|
MeterClose();
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
if (GWM_GrabServer)
|
|
XUngrabServer(dpy);
|
|
return NIL;
|
|
} else { /* another buttonpress = abort! */
|
|
wait_for_button_release(button_event.xbutton.button);
|
|
wait_for_button_release(called_from_press_button);
|
|
if (GWM_Resize_meter)
|
|
MeterClose();
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
if (GWM_GrabServer)
|
|
XUngrabServer(dpy);
|
|
return (WOOL_OBJECT) WLNumber_make(2);
|
|
}
|
|
}
|
|
/* track ghost window */
|
|
XQueryPointer(dpy,
|
|
RootWindow(dpy, Context -> screen), &root, &sub_window,
|
|
&root_x, &root_y, &cur_x, &cur_y, &ptrmask);
|
|
x2 = validate_dir(xdir, cur_x - init_x, cw -> inner_width);
|
|
y2 = validate_dir(ydir, cur_y - init_y, cw -> inner_height);
|
|
inner_width = cw -> inner_width + (xdir ? x2 : -x2);
|
|
inner_height = cw -> inner_height + (ydir ? y2 : -y2);
|
|
if (inner_width < 2 * GWM_window_cutting_size)
|
|
inner_width = 2 * GWM_window_cutting_size;
|
|
if (inner_height < 2 * GWM_window_cutting_size)
|
|
inner_height = 2 * GWM_window_cutting_size;
|
|
conform_to_hints(&(cw -> cached_props -> normal_hints),
|
|
&inner_width, &inner_height);
|
|
x2 = init_x2 + (xdir ? inner_width - cw -> inner_width :
|
|
cw -> inner_width - inner_width);
|
|
y2 = init_y2 + (ydir ? inner_height - cw -> inner_height :
|
|
cw -> inner_height - inner_height);
|
|
if (GWM_confine_windows) {
|
|
int readjust = 0;
|
|
if (x2 < 0) {
|
|
x2 = 0;
|
|
inner_width = (cw -> box.x - x2) + cw -> inner_width;
|
|
readjust = 1;
|
|
} else if (x2 >= Context -> width) {
|
|
x2 = Context -> width;
|
|
inner_width = cw -> inner_width + x2
|
|
- (cw -> box.x + cw->box.width + 2*(cw->box.borderwidth));
|
|
readjust = 1;
|
|
}
|
|
|
|
if (y2<0) {
|
|
y2 = 0;
|
|
inner_height = (cw -> box.y - y2) + cw -> inner_height;
|
|
readjust = 1;
|
|
} else if (y2 >= Context -> height) {
|
|
y2 = Context -> height;
|
|
inner_height = cw -> inner_height + y2
|
|
- (cw->box.y + cw->box.height + 2*(cw->box.borderwidth));
|
|
readjust = 1;
|
|
}
|
|
if (readjust) {
|
|
conform_to_hints(&(cw -> cached_props -> normal_hints),
|
|
&inner_width, &inner_height);
|
|
x2 = init_x2 + (xdir ? inner_width - cw -> inner_width :
|
|
cw -> inner_width - inner_width);
|
|
y2 = init_y2 + (ydir ? inner_height - cw -> inner_height :
|
|
cw -> inner_height - inner_height);
|
|
}
|
|
}
|
|
if (GWM_Mwm_catch_corners &&
|
|
(GWM_window_cutting_size > 0)) {
|
|
ulx = Min(x1, x2);
|
|
uly = Min(y1, y2);
|
|
lrx = Max(x1, x2);
|
|
lry = Max(y1, y2);
|
|
new_xdir = xdir;
|
|
if (xdir == 1)
|
|
if (cur_x < (ulx + GWM_window_cutting_size))
|
|
new_xdir = 0;
|
|
else if (cur_x > (lrx - GWM_window_cutting_size))
|
|
new_xdir = 2;
|
|
new_ydir = ydir;
|
|
if (ydir == 1)
|
|
if (cur_y < (uly + GWM_window_cutting_size))
|
|
new_ydir = 0;
|
|
else if (cur_y > (lry - GWM_window_cutting_size))
|
|
new_ydir = 2;
|
|
new_zone = 3 * new_ydir + new_xdir;
|
|
if (new_zone != zone) {
|
|
XChangeActivePointerGrab(dpy, mask,
|
|
get_zone_cursor(new_zone), CurrentTime);
|
|
zone = new_zone;
|
|
/* determine if the varying point is changing */
|
|
if ((xdir == 1) && (new_xdir == 0))
|
|
init_x2 = x1;
|
|
if ((ydir == 1) && (new_ydir == 0))
|
|
init_y2 = y1;
|
|
xdir = new_xdir;
|
|
ydir = new_ydir;
|
|
init_x = init_x2;
|
|
init_y = init_y2;
|
|
/* determine the new points */
|
|
if (xdir) {
|
|
x1 = ulx;
|
|
x2 = lrx;
|
|
} else {
|
|
x1 = lrx;
|
|
x2 = ulx;
|
|
}
|
|
if (ydir) {
|
|
y1 = uly;
|
|
y2 = lry;
|
|
} else {
|
|
y1 = lry;
|
|
y2 = uly;
|
|
}
|
|
}
|
|
}
|
|
if ((x2 != prev_x2) || (y2 != prev_y2)) {
|
|
/* erase the old box first! */
|
|
XDrawSegments(dpy, Context -> root, Context -> gc.Draw, box,
|
|
num_vectors);
|
|
num_vectors = StoreBox(GWM_Resizegrid, box,
|
|
Min(x1, x2), Min(y1, y2), Max(x1, x2), Max(y1, y2));
|
|
/* Draw the new box. */
|
|
XDrawSegments(dpy, Context -> root, Context -> gc.Draw, box,
|
|
num_vectors);
|
|
if (GWM_Resize_meter)
|
|
MeterUpdate(MakeUserDims(
|
|
&(cw -> cached_props -> normal_hints),
|
|
inner_width, inner_height));
|
|
/* Save old box position. */
|
|
prev_x2 = x2;
|
|
prev_y2 = y2;
|
|
}
|
|
}
|
|
}
|