Generic_Window_Manager/user.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;
}
}
}