/* 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 #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; } } }