/* * resize.cc * * Copyright (C) 1995, 1996, 1997, 1997, 1998, 1999, 2000, 2001, 2002 Kenichi Kourai * Copyright (C) 1999, 2000, 2001, 2002 Luiz Blanes * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with blwm; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include #include #include #include "main.h" #include "misc.h" #include "blwm.h" #include "event.h" #include "taskbar.h" #include "tbutton.h" #include "blwmrc.h" #include "paging.h" #include "pager.h" #include "mini.h" #include "info_display.h" static Bool ResizeWithShape(Display* display, XEvent* ev, char* arg); /* * ResizeWindow -- * Resize the window with mouse or keyboard. */ void Blwm::ResizeWindow(unsigned int pos, Bool mouseResize) { XEvent ev; Rect rcNew, rcReal; Dim dNeed; Point ptBase, ptNew, ptMove; Window junkRoot; unsigned int junkBW, junkDepth; Bool first = True; Bool pointer = False; int borderWidth, topBorder, titleHeight, titleEdge; int ctype; if (this == rootBlwm) return; if (!CheckStatus(PRESS_FRAME)) return; XGrabKeyboard(display, root, True, GrabModeAsync, GrabModeAsync, CurrentTime); if (ClickToFocus) XSetInputFocus(display, root, RevertToParent, CurrentTime); if (!OpaqueResize) XGrabServer(display); XGetGeometry(display, frame, &junkRoot, &rcNew.x, &rcNew.y, (unsigned int *)&rcNew.width, (unsigned int *)&rcNew.height, &junkBW, &junkDepth); if (!OpaqueResize) XDrawRectangle(display, root, gcXor, rcNew.x, rcNew.y, rcNew.width, rcNew.height); /* * Remember base line. */ if (pos & P_LEFT) ptBase.x = rcNew.x + rcNew.width; else if (pos & P_RIGHT) ptBase.x = rcNew.x; if (pos & P_TOP) ptBase.y = rcNew.y + rcNew.height; else if (pos & P_BOTTOM) ptBase.y = rcNew.y; /* * Calculate necessary frame size. */ GetBorderAndTitle(borderWidth, topBorder, titleHeight, titleEdge); dNeed.width = borderWidth * 2; dNeed.height = borderWidth + topBorder + titleHeight + titleEdge; if (UseInfoDisplay) { Rect rect(rcNew.x + paging->origin.x, rcNew.y + paging->origin.y, rcNew.width, rcNew.height); infoDisp->NotifyShape(rect); infoDisp->Map(); } while (1) { if (OpaqueResize) XIfEvent(display, &ev, ResizeWithShape, NULL); else XMaskEvent(display, KeyPressMask | PointerMotionMask | ButtonReleaseMask | ButtonPressMask | ExposureMask, &ev); switch (ev.type) { case KeyPress: // when resizing with mouse, ignore key events if (mouseResize) break; if (first) { pointer = True; XGrabPointer(display, root, True, ButtonPressMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, root, None, CurrentTime); } ptNew = Point(ev.xkey.x_root, ev.xkey.y_root); switch (XKeycodeToKeysym(display, ev.xkey.keycode, 0)) { case XK_Up: if (first) { pos = P_TOP; ptBase.y = rcNew.y + rcNew.height; ptNew.y = rcNew.y; XWarpPointer(display, None, root, 0, 0, 0, 0, ptNew.x, ptNew.y); XDefineCursor(display, root, cursor[Y_RESIZE]); first = False; } if (pos == P_LEFT) { pos |= P_TOP; ptBase.y = rcNew.y + rcNew.height; ptNew.y = rcNew.y; XWarpPointer(display, None, root, 0, 0, 0, 0, ptNew.x, ptNew.y); XDefineCursor(display, root, cursor[RD_RESIZE]); } else if (pos == P_RIGHT) { pos |= P_TOP; ptBase.y = rcNew.y + rcNew.height; ptNew.y = rcNew.y; XWarpPointer(display, None, root, 0, 0, 0, 0, ptNew.x, ptNew.y); XDefineCursor(display, root, cursor[LD_RESIZE]); } ptNew.y -= MOVEMENT; break; case XK_Down: if (first) { pos = P_BOTTOM; ptBase.y = rcNew.y; ptNew.y = rcNew.y + rcNew.height; XWarpPointer(display, None, root, 0, 0, 0, 0, ptNew.x, ptNew.y); XDefineCursor(display, root, cursor[Y_RESIZE]); first = False; } if (pos == P_LEFT) { pos |= P_BOTTOM; ptBase.y = rcNew.y; ptNew.y = rcNew.y + rcNew.height; XWarpPointer(display, None, root, 0, 0, 0, 0, ptNew.x, ptNew.y); XDefineCursor(display, root, cursor[LD_RESIZE]); } else if (pos == P_RIGHT) { pos |= P_BOTTOM; ptBase.y = rcNew.y; ptNew.y = rcNew.y + rcNew.height; XWarpPointer(display, None, root, 0, 0, 0, 0, ptNew.x, ptNew.y); XDefineCursor(display, root, cursor[RD_RESIZE]); } ptNew.y += MOVEMENT; break; case XK_Right: if (first) { pos = P_RIGHT; ptBase.x = rcNew.x; ptNew.x = rcNew.x + rcNew.width; XWarpPointer(display, None, root, 0, 0, 0, 0, ptNew.x, ptNew.y); XDefineCursor(display, root, cursor[X_RESIZE]); first = False; } if (pos == P_TOP) { pos |= P_RIGHT; ptBase.x = rcNew.x; ptNew.x = rcNew.x + rcNew.width; XWarpPointer(display, None, root, 0, 0, 0, 0, ptNew.x, ptNew.y); XDefineCursor(display, root, cursor[LD_RESIZE]); } else if (pos == P_BOTTOM) { pos |= P_RIGHT; ptBase.x = rcNew.x; ptNew.x = rcNew.x + rcNew.width; XWarpPointer(display, None, root, 0, 0, 0, 0, ptNew.x, ptNew.y); XDefineCursor(display, root, cursor[RD_RESIZE]); } ptNew.x += MOVEMENT; break; case XK_Left: if (first) { pos = P_LEFT; ptBase.x = rcNew.x + rcNew.width; ptNew.x = rcNew.x; XWarpPointer(display, None, root, 0, 0, 0, 0, ptNew.x, ptNew.y); XDefineCursor(display, root, cursor[X_RESIZE]); first = False; } if (pos == P_TOP) { pos |= P_LEFT; ptBase.x = rcNew.x + rcNew.width; ptNew.x = rcNew.x; XWarpPointer(display, None, root, 0, 0, 0, 0, ptNew.x, ptNew.y); XDefineCursor(display, root, cursor[RD_RESIZE]); } else if (pos == P_BOTTOM) { pos |= P_LEFT; ptBase.x = rcNew.x + rcNew.width; ptNew.x = rcNew.x; XWarpPointer(display, None, root, 0, 0, 0, 0, ptNew.x, ptNew.y); XDefineCursor(display, root, cursor[LD_RESIZE]); } ptNew.x -= MOVEMENT; break; case XK_Return: goto decide; } XWarpPointer(display, None, root, 0, 0, 0, 0, ptNew.x, ptNew.y); // continue case MotionNotify: { Window w = ev.xmotion.window; XEvent ev; while (XCheckTypedWindowEvent(display, w, MotionNotify, &ev)) ; } if (!OpaqueResize) XDrawRectangle(display, root, gcXor, rcNew.x, rcNew.y, rcNew.width, rcNew.height); if (ev.type == MotionNotify) ptNew = Point(ev.xbutton.x_root, ev.xbutton.y_root); ASSERT(paging); ptMove = Point(0, 0); // ptMove = paging->HandlePaging(ptNew); ptNew -= ptMove; ptBase -= ptMove; rcNew.x -= ptMove.x; rcNew.y -= ptMove.y; FixWindowShape(rcNew, pos, ptBase, ptNew, dNeed); if (OpaqueResize) { rcReal = Rect(rcNew.x + paging->origin.x, rcNew.y + paging->origin.y, rcNew.width, rcNew.height); ConfigureNewRect(rcReal, !FullOpaque); RedrawWindow(!FullOpaque); } else XDrawRectangle(display, root, gcXor, rcNew.x, rcNew.y, rcNew.width, rcNew.height); if (UseInfoDisplay) { Rect rect(rcNew.x + paging->origin.x, rcNew.y + paging->origin.y, rcNew.width, rcNew.height); infoDisp->NotifyShape(rect); } break; case ButtonRelease: goto decide; case ButtonPress: if (pointer) goto decide; break; case Expose: event.ExposeProc((const XExposeEvent &)ev); if (UseInfoDisplay) infoDisp->Draw(); break; default: if (shapeSupport) { if (ev.type == event.shapeEventBase + ShapeNotify) { const XShapeEvent& xev = (const XShapeEvent &)ev; event.ShapeNotifyProc(xev); } } break; } } decide: XDefineCursor(display, root, cursor[SYS]); if (!OpaqueResize) { XDrawRectangle(display, root, gcXor, rcNew.x, rcNew.y, rcNew.width, rcNew.height); XUngrabServer(display); } if (UseInfoDisplay) infoDisp->Unmap(); if (ClickToFocus) SetFocusToActiveWindow(); if (pointer) XUngrabPointer(display, CurrentTime); XUngrabKeyboard(display, CurrentTime); if (!OpaqueResize) { ASSERT(paging); rcNew.x += paging->origin.x; rcNew.y += paging->origin.y; ConfigureNewRect(rcNew); RedrawWindow(); } else if (!FullOpaque) { ConfigureNewRect(rc); RedrawWindow(); } if (UseTaskbar && OnTopTaskbar) taskBar->RaiseTaskbar(); if (UsePager && OnTopPager) pager->RaisePager(); ResetStatus(PRESS_FRAME); } static Bool ResizeWithShape(Display* display, XEvent* ev, char* arg) { switch (ev->type) { case KeyPress: case ButtonPress: case ButtonRelease: case MotionNotify: case Expose: return True; default: if (shapeSupport) if (ev->type == event.shapeEventBase + ShapeNotify) return True; break; } return False; } void Blwm::FixWindowShape(Rect& rcNew, unsigned int pos, const Point& ptBase, const Point& ptNew, const Dim& dNeed) { if (pos & P_LEFT) { rcNew.width = RoundOff((ptBase.x - ptNew.x) - dNeed.width - hints.base_width, hints.width_inc) + dNeed.width + hints.base_width; rcNew.x = ptBase.x - rcNew.width; } else if (pos & P_RIGHT) rcNew.width = RoundOff((ptNew.x - ptBase.x) - dNeed.width - hints.base_width, hints.width_inc) + dNeed.width + hints.base_width; if (pos & P_TOP) { rcNew.height = RoundOff((ptBase.y - ptNew.y) - dNeed.height - hints.base_height, hints.height_inc) + dNeed.height + hints.base_height; rcNew.y = ptBase.y - rcNew.height; } else if (pos & P_BOTTOM) rcNew.height = RoundOff((ptNew.y - ptBase.y) - dNeed.height - hints.base_height, hints.height_inc) + dNeed.height + hints.base_height; /* * Check minimum limit of size. */ if ((signed)rcNew.width - dNeed.width <= 0) { rcNew.width = dNeed.width + Max(1, hints.base_width); if (pos & P_LEFT) rcNew.x = ptBase.x - rcNew.width; } else if ((signed)rcNew.width - dNeed.width < hints.min_width) { if (pos & P_LEFT) rcNew.x = ptBase.x - (hints.min_width + dNeed.width); rcNew.width = hints.min_width + dNeed.width; } if ((signed)rcNew.height - dNeed.height <= 0) { rcNew.height = dNeed.height + Max(1, hints.base_height); if (pos & P_TOP) rcNew.y = ptBase.y - rcNew.height; } else if ((signed)rcNew.height - dNeed.height < hints.min_height) { if (pos & P_TOP) rcNew.y = ptBase.y - (hints.min_height + dNeed.height); rcNew.height = hints.min_height + dNeed.height; } /* * Check maximum limit of size. */ if (rcNew.width - dNeed.width > hints.max_width) { if (pos & P_LEFT) rcNew.x = ptBase.x - (hints.max_width + dNeed.width); rcNew.width = hints.max_width + dNeed.width; } if (rcNew.height - dNeed.height > hints.max_height) { if (pos & P_TOP) rcNew.y = ptBase.y - (hints.max_height + dNeed.height); rcNew.height = hints.max_height + dNeed.height; } /* * Check if over taskbar */ if (UseTaskbar && NoResizeOverTaskbar) { switch (taskBar->GetPos()) { case Taskbar::BOTTOM: if ((pos & P_BOTTOM) && rcNew.y + rcNew.height > taskBar->GetRect().y) rcNew.height = taskBar->GetRect().y - rcNew.y; break; case Taskbar::TOP: if ((pos & P_TOP) && rcNew.y < rcScreen.y) { rcNew.height -= (rcScreen.y - rcNew.y); rcNew.y = rcScreen.y; } break; case Taskbar::LEFT: if ((pos & P_LEFT) && rcNew.x < rcScreen.x) { rcNew.width -= rcScreen.x - rcNew.x; rcNew.x = rcScreen.x; } break; case Taskbar::RIGHT: if ((pos & P_RIGHT) && rcNew.x + rcNew.width > taskBar->GetRect().x) rcNew.width = taskBar->GetRect().x - rcNew.x; break; } if (pos & P_LEFT) { rcNew.width = RoundDown(rcNew.width - dNeed.width - hints.base_width, hints.width_inc) + dNeed.width + hints.base_width; rcNew.x = ptBase.x - rcNew.width; } else if (pos & P_RIGHT) rcNew.width = RoundDown(rcNew.width - dNeed.width - hints.base_width, hints.width_inc) + dNeed.width + hints.base_width; if (pos & P_TOP) { rcNew.height = RoundDown(rcNew.height - dNeed.height - hints.base_height, hints.height_inc) + dNeed.height + hints.base_height; rcNew.y = ptBase.y - rcNew.height; } else if (pos & P_BOTTOM) rcNew.height = RoundDown(rcNew.height - dNeed.height - hints.base_height, hints.height_inc) + dNeed.height + hints.base_height; } } /* * GetFixSize -- * Adjust the position and the size of the window according to the window * property. */ Rect Blwm::GetFixSize(const Rect& rc, int max_width, int max_height, int width_inc, int height_inc, int base_width, int base_height) { Rect rect; int borderWidth, topBorder, titleHeight, titleEdge; int outerw, outerh; GetBorderAndTitle(borderWidth, topBorder, titleHeight, titleEdge); outerw = borderWidth * 2; outerh = borderWidth + topBorder + titleHeight + titleEdge; // clip to window defined maximum rect.width = Min(max_width, rc.width - outerw) + outerw; rect.height = Min(max_height, rc.height - outerh) + outerh; // clip to screen rect.width = Min(rect.width, rcScreen.width); rect.height = Min(rect.height, rcScreen.height); rect.x = rc.x; rect.y = rc.y; rect.width = RoundDown(rect.width - base_width - outerw, width_inc) + base_width + outerw; rect.height = RoundDown(rect.height - base_height - outerh, height_inc) + base_height + outerh; return rect; }