X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2FWindow.cc;h=23bc9800a4d3f795ed6e2ed80449ed2a96d98c3e;hb=1d4391b09c12a0615bb6be65f9af514db4eed709;hp=7c5b823bc2df3587cf0ac0bee9500d2636590b60;hpb=578a5cc980dd39430fe803a4ca9719075e78e986;p=chaz%2Fopenbox diff --git a/src/Window.cc b/src/Window.cc index 7c5b823b..23bc9800 100644 --- a/src/Window.cc +++ b/src/Window.cc @@ -44,6 +44,7 @@ extern "C" { #include "i18n.hh" #include "blackbox.hh" +#include "Font.hh" #include "GCCache.hh" #include "Iconmenu.hh" #include "Image.hh" @@ -133,13 +134,14 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { frame.fgrip_pixel = 0; frame.utitle = frame.ftitle = frame.uhandle = frame.fhandle = None; frame.ulabel = frame.flabel = frame.ubutton = frame.fbutton = None; - frame.pbutton = frame.ugrip = frame.fgrip = decorations; + frame.pbutton = frame.ugrip = frame.fgrip = None; decorations = Decor_Titlebar | Decor_Border | Decor_Handle | Decor_Iconify | Decor_Maximize; functions = Func_Resize | Func_Move | Func_Iconify | Func_Maximize; client.wm_hint_flags = client.normal_hint_flags = 0; + client.window_group = None; client.transient_for = 0; /* @@ -187,9 +189,6 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { blackbox->saveWindowSearch(frame.plate, this); blackbox->saveWindowSearch(client.window, this); - screen->addStrut(&client.strut); - updateStrut(); - // determine if this is a transient window getTransientInfo(); @@ -205,11 +204,14 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { return; case Type_Dock: - // docks (such as kicker) cannot be moved, and appear on all workspaces + case Type_Menu: + // docks (such as kicker) and menus (as used by kde for the 'desktop menu' + // which mimics apple, cannot be moved, and appear on all workspaces + // also, these have no decorations functions &= ~(Func_Move); + decorations &= ~Decor_Titlebar; flags.stuck = True; case Type_Toolbar: - case Type_Menu: case Type_Utility: // these windows have minimal decorations, only a titlebar, and cannot // be resized or iconified @@ -251,14 +253,16 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { bool place_window = True; if (blackbox->isStartup() || isTransient() || client.normal_hint_flags & (PPosition|USPosition)) { - setGravityOffsets(); + applyGravity(frame.rect); - - if (blackbox->isStartup() || - client.rect.intersects(screen->availableArea())) + if (blackbox->isStartup() || client.rect.intersects(screen->getRect())) place_window = False; } + // add the window's strut. note this is done *after* placing the window. + screen->addStrut(&client.strut); + updateStrut(); + if (decorations & Decor_Titlebar) createTitlebar(); @@ -271,33 +275,6 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { } #endif // SHAPE - if ((! screen->isSloppyFocus()) || screen->doClickRaise()) { - // grab button 1 for changing focus/raising - blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask, - GrabModeSync, GrabModeSync, None, None); - } - - if (functions & Func_Move) - blackbox->grabButton(Button1, Mod1Mask, frame.window, True, - ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, - GrabModeAsync, frame.window, - blackbox->getMoveCursor()); - blackbox->grabButton(Button2, Mod1Mask, frame.window, True, - ButtonReleaseMask, GrabModeAsync, GrabModeAsync, - None, None); - if (functions & Func_Resize) - blackbox->grabButton(Button3, Mod1Mask, frame.window, True, - ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, - GrabModeAsync, None, - blackbox->getLowerRightAngleCursor()); - - positionWindows(); - decorate(); - - if (decorations & Decor_Titlebar) - XMapSubwindows(blackbox->getXDisplay(), frame.title); - XMapSubwindows(blackbox->getXDisplay(), frame.window); - windowmenu = new Windowmenu(this); if (blackbox_attrib.workspace >= screen->getWorkspaceCount()) @@ -329,16 +306,15 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { if (flags.shaded) { flags.shaded = False; + unsigned long orig_state = current_state; shade(); - + /* - Because the iconic'ness of shaded windows is lost, we need to set the - state to NormalState so that shaded windows on other workspaces will not - get shown on the first workspace. At this point in the life of a window, current_state should only be set to IconicState if the window was an *icon*, not if it was shaded. */ - current_state = NormalState; + if (orig_state != IconicState) + current_state = NormalState; } if (flags.stuck) { @@ -359,8 +335,14 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) { fact never set to Iconic since there is no way for us to tell if a sticky window was iconified previously. */ + + positionWindows(); + decorate(); + grabButtons(); + + XMapSubwindows(blackbox->getXDisplay(), frame.window); - setFocusFlag(False); + redrawWindowFrame(); } @@ -443,7 +425,7 @@ Window BlackboxWindow::createToplevelWindow(void) { ButtonMotionMask | EnterWindowMask; return XCreateWindow(blackbox->getXDisplay(), screen->getRootWindow(), - -1, -1, 1, 1, frame.border_w, screen->getDepth(), + 0, 0, 1, 1, frame.border_w, screen->getDepth(), InputOutput, screen->getVisual(), create_mask, &attrib_create); } @@ -483,10 +465,14 @@ void BlackboxWindow::associateClientWindow(void) { XSelectInput(blackbox->getXDisplay(), frame.plate, SubstructureRedirectMask); XGrabServer(blackbox->getXDisplay()); - XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask); - XReparentWindow(blackbox->getXDisplay(), client.window, frame.plate, 0, 0); + + unsigned long event_mask = PropertyChangeMask | FocusChangeMask | + StructureNotifyMask; XSelectInput(blackbox->getXDisplay(), client.window, - PropertyChangeMask | FocusChangeMask | StructureNotifyMask); + event_mask & ~StructureNotifyMask); + XReparentWindow(blackbox->getXDisplay(), client.window, frame.plate, 0, 0); + XSelectInput(blackbox->getXDisplay(), client.window, event_mask); + XUngrabServer(blackbox->getXDisplay()); XRaiseWindow(blackbox->getXDisplay(), frame.plate); @@ -836,19 +822,15 @@ void BlackboxWindow::positionButtons(bool redecorate_label) { void BlackboxWindow::reconfigure(void) { + restoreGravity(client.rect); upsize(); - - client.rect.setPos(frame.rect.left() + frame.margin.left, - frame.rect.top() + frame.margin.top); - + applyGravity(frame.rect); positionWindows(); decorate(); + redrawWindowFrame(); - XClearWindow(blackbox->getXDisplay(), frame.window); - setFocusFlag(flags.focused); - - configure(frame.rect.x(), frame.rect.y(), - frame.rect.width(), frame.rect.height()); + ungrabButtons(); + grabButtons(); if (windowmenu) { windowmenu->move(windowmenu->getX(), frame.rect.y() + frame.title_h); @@ -857,14 +839,35 @@ void BlackboxWindow::reconfigure(void) { } -void BlackboxWindow::updateFocusModel(void) { - if ((! screen->isSloppyFocus()) || screen->doClickRaise()) { +void BlackboxWindow::grabButtons(void) { + if ((! screen->isSloppyFocus()) || screen->doClickRaise()) // grab button 1 for changing focus/raising blackbox->grabButton(Button1, 0, frame.plate, True, ButtonPressMask, - GrabModeSync, GrabModeSync, None, None); - } else { + GrabModeSync, GrabModeSync, frame.plate, None); + + if (functions & Func_Move) + blackbox->grabButton(Button1, Mod1Mask, frame.window, True, + ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, + GrabModeAsync, frame.window, + blackbox->getMoveCursor()); + if (functions & Func_Resize) + blackbox->grabButton(Button3, Mod1Mask, frame.window, True, + ButtonReleaseMask | ButtonMotionMask, GrabModeAsync, + GrabModeAsync, frame.window, None); + // alt+middle lowers the window + blackbox->grabButton(Button2, Mod1Mask, frame.window, True, + ButtonReleaseMask, GrabModeAsync, GrabModeAsync, + frame.window, None); +} + + +void BlackboxWindow::ungrabButtons(void) { + if ((! screen->isSloppyFocus()) || screen->doClickRaise()) blackbox->ungrabButton(Button1, 0, frame.plate); - } + + blackbox->ungrabButton(Button1, Mod1Mask, frame.window); + blackbox->ungrabButton(Button2, Mod1Mask, frame.window); + blackbox->ungrabButton(Button3, Mod1Mask, frame.window); } @@ -872,7 +875,8 @@ void BlackboxWindow::positionWindows(void) { XMoveResizeWindow(blackbox->getXDisplay(), frame.window, frame.rect.x(), frame.rect.y(), frame.inside_w, (flags.shaded) ? frame.title_h : frame.inside_h); - XSetWindowBorderWidth(blackbox->getXDisplay(), frame.window, frame.border_w); + XSetWindowBorderWidth(blackbox->getXDisplay(), frame.window, + frame.border_w); XSetWindowBorderWidth(blackbox->getXDisplay(), frame.plate, frame.mwm_border_w); XMoveResizeWindow(blackbox->getXDisplay(), frame.plate, @@ -881,6 +885,9 @@ void BlackboxWindow::positionWindows(void) { client.rect.width(), client.rect.height()); XMoveResizeWindow(blackbox->getXDisplay(), client.window, 0, 0, client.rect.width(), client.rect.height()); + // ensure client.rect contains the real location + client.rect.setPos(frame.rect.left() + frame.margin.left, + frame.rect.top() + frame.margin.top); if (decorations & Decor_Titlebar) { if (frame.title == None) createTitlebar(); @@ -923,6 +930,7 @@ void BlackboxWindow::positionWindows(void) { } else if (frame.handle) { destroyHandle(); } + XSync(blackbox->getXDisplay(), False); } @@ -1089,9 +1097,12 @@ void BlackboxWindow::getWMHints(void) { // add window to the appropriate group BWindowGroup *group = blackbox->searchGroup(client.window_group); - if (! group) // no group found, create it! - group = new BWindowGroup(blackbox, client.window_group); - group->addWindow(this); + if (! group) { // no group found, create it! + new BWindowGroup(blackbox, client.window_group); + group = blackbox->searchGroup(client.window_group); + } + if (group) + group->addWindow(this); } client.wm_hint_flags = wmhint->flags; @@ -1110,6 +1121,11 @@ void BlackboxWindow::getWMNormalHints(void) { client.min_width = client.min_height = client.width_inc = client.height_inc = 1; client.base_width = client.base_height = 0; + client.win_gravity = NorthWestGravity; +#if 0 + client.min_aspect_x = client.min_aspect_y = + client.max_aspect_x = client.max_aspect_y = 1; +#endif /* use the full screen, not the strut modified size. otherwise when the @@ -1118,11 +1134,7 @@ void BlackboxWindow::getWMNormalHints(void) { */ const Rect& screen_area = screen->getRect(); client.max_width = screen_area.width(); - client.max_height = screen_area.height(); - client.min_aspect_x = client.min_aspect_y = - client.max_aspect_x = client.max_aspect_y = 1; - client.win_gravity = NorthWestGravity; if (! XGetWMNormalHints(blackbox->getXDisplay(), client.window, &sizehint, &icccm_mask)) @@ -1131,13 +1143,22 @@ void BlackboxWindow::getWMNormalHints(void) { client.normal_hint_flags = sizehint.flags; if (sizehint.flags & PMinSize) { - client.min_width = sizehint.min_width; - client.min_height = sizehint.min_height; + if (sizehint.min_width >= 0) + client.min_width = sizehint.min_width; + if (sizehint.min_height >= 0) + client.min_height = sizehint.min_height; } if (sizehint.flags & PMaxSize) { - client.max_width = sizehint.max_width; - client.max_height = sizehint.max_height; + if (sizehint.max_width > static_cast(client.min_width)) + client.max_width = sizehint.max_width; + else + client.max_width = client.min_width; + + if (sizehint.max_height > static_cast(client.min_height)) + client.max_height = sizehint.max_height; + else + client.max_height = client.min_height; } if (sizehint.flags & PResizeInc) { @@ -1145,12 +1166,14 @@ void BlackboxWindow::getWMNormalHints(void) { client.height_inc = sizehint.height_inc; } +#if 0 // we do not support this at the moment if (sizehint.flags & PAspect) { client.min_aspect_x = sizehint.min_aspect.x; client.min_aspect_y = sizehint.min_aspect.y; client.max_aspect_x = sizehint.max_aspect.x; client.max_aspect_y = sizehint.max_aspect.y; } +#endif if (sizehint.flags & PBaseSize) { client.base_width = sizehint.base_width; @@ -1226,9 +1249,12 @@ void BlackboxWindow::getMWMHints(void) { num = PropMwmHintsElements; if (! xatom->getValue(client.window, XAtom::motif_wm_hints, XAtom::motif_wm_hints, num, - (unsigned long **)&mwm_hint) || - num < PropMwmHintsElements) + (unsigned long **)&mwm_hint)) return; + if (num < PropMwmHintsElements) { + delete [] mwm_hint; + return; + } if (mwm_hint->flags & MwmHintsDecorations) { if (mwm_hint->decorations & MwmDecorAll) { @@ -1269,7 +1295,7 @@ void BlackboxWindow::getMWMHints(void) { functions |= Func_Close; } } - delete mwm_hint; + delete [] mwm_hint; } @@ -1287,9 +1313,12 @@ bool BlackboxWindow::getBlackboxHints(void) { num = PropBlackboxHintsElements; if (! xatom->getValue(client.window, XAtom::blackbox_hints, XAtom::blackbox_hints, num, - (unsigned long **)&blackbox_hint) || - num < PropBlackboxHintsElements) + (unsigned long **)&blackbox_hint)) return False; + if (num < PropBlackboxHintsElements) { + delete [] blackbox_hint; + return False; + } if (blackbox_hint->flags & AttribShaded) flags.shaded = (blackbox_hint->attrib & AttribShaded); @@ -1351,7 +1380,7 @@ bool BlackboxWindow::getBlackboxHints(void) { reconfigure(); } - delete blackbox_hint; + delete [] blackbox_hint; return True; } @@ -1429,11 +1458,18 @@ BlackboxWindow *BlackboxWindow::getTransientFor(void) const { } +/* + * This function is responsible for updating both the client and the frame + * rectangles. + * According to the ICCCM a client message is not sent for a resize, only a + * move. + */ void BlackboxWindow::configure(int dx, int dy, unsigned int dw, unsigned int dh) { - bool send_event = (frame.rect.x() != dx || frame.rect.y() != dy); + bool send_event = ((frame.rect.x() != dx || frame.rect.y() != dy) && + ! flags.moving); - if ((dw != frame.rect.width()) || (dh != frame.rect.height())) { + if (dw != frame.rect.width() || dh != frame.rect.height()) { frame.rect.setRect(dx, dy, dw, dh); frame.inside_w = frame.rect.width() - (frame.border_w * 2); frame.inside_h = frame.rect.height() - (frame.border_w * 2); @@ -1454,18 +1490,22 @@ void BlackboxWindow::configure(int dx, int dy, positionWindows(); decorate(); - setFocusFlag(flags.focused); - redrawAllButtons(); + redrawWindowFrame(); } else { frame.rect.setPos(dx, dy); XMoveWindow(blackbox->getXDisplay(), frame.window, frame.rect.x(), frame.rect.y()); - + /* + we may have been called just after an opaque window move, so even though + the old coords match the new ones no ConfigureNotify has been sent yet. + There are likely other times when this will be relevant as well. + */ if (! flags.moving) send_event = True; } - if (send_event && ! flags.moving) { + if (send_event) { + // if moving, the update and event will occur when the move finishes client.rect.setPos(frame.rect.left() + frame.margin.left, frame.rect.top() + frame.margin.top); @@ -1483,10 +1523,10 @@ void BlackboxWindow::configure(int dx, int dy, event.xconfigure.above = frame.window; event.xconfigure.override_redirect = False; - XSendEvent(blackbox->getXDisplay(), client.window, True, - NoEventMask, &event); - + XSendEvent(blackbox->getXDisplay(), client.window, False, + StructureNotifyMask, &event); screen->updateNetizenConfigNotify(&event); + XFlush(blackbox->getXDisplay()); } } @@ -1527,8 +1567,10 @@ void BlackboxWindow::configureShape(void) { bool BlackboxWindow::setInputFocus(void) { if (flags.focused) return True; - assert(! flags.iconic); - + assert(! flags.iconic && + (flags.stuck || // window must be on the current workspace or sticky + blackbox_attrib.workspace == screen->getCurrentWorkspaceID())); +#if 0 // if the window is not visible, mark the window as wanting focus rather // than give it focus. if (! flags.visible) { @@ -1536,13 +1578,19 @@ bool BlackboxWindow::setInputFocus(void) { wkspc->setLastFocusedWindow(this); return True; } - - if (! client.rect.intersects(screen->getRect())) { - // client is outside the screen, move it to the center - configure((screen->getWidth() - frame.rect.width()) / 2, - (screen->getHeight() - frame.rect.height()) / 2, - frame.rect.width(), frame.rect.height()); - } +#endif + /* + We only do this check for normal windows and dialogs because other windows + do this on purpose, such as kde's kicker, and we don't want to go moving + it. + */ + if (window_type == Type_Normal || window_type == Type_Dialog) + if (! frame.rect.intersects(screen->getRect())) { + // client is outside the screen, move it to the center + configure((screen->getWidth() - frame.rect.width()) / 2, + (screen->getHeight() - frame.rect.height()) / 2, + frame.rect.width(), frame.rect.height()); + } if (client.transientList.size() > 0) { // transfer focus to any modal transients @@ -1580,6 +1628,7 @@ bool BlackboxWindow::setInputFocus(void) { ce.xclient.data.l[4] = 0l; XSendEvent(blackbox->getXDisplay(), client.window, False, NoEventMask, &ce); + XFlush(blackbox->getXDisplay()); } return ret; @@ -1603,11 +1652,13 @@ void BlackboxWindow::iconify(void) { * split second, leaving us with a ghost window... so, we need to do this * while the X server is grabbed */ + unsigned long event_mask = PropertyChangeMask | FocusChangeMask | + StructureNotifyMask; XGrabServer(blackbox->getXDisplay()); - XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask); - XUnmapWindow(blackbox->getXDisplay(), client.window); XSelectInput(blackbox->getXDisplay(), client.window, - PropertyChangeMask | FocusChangeMask | StructureNotifyMask); + event_mask & ~StructureNotifyMask); + XUnmapWindow(blackbox->getXDisplay(), client.window); + XSelectInput(blackbox->getXDisplay(), client.window, event_mask); XUngrabServer(blackbox->getXDisplay()); XUnmapWindow(blackbox->getXDisplay(), frame.window); @@ -1635,6 +1686,7 @@ void BlackboxWindow::iconify(void) { if (! (*it)->flags.iconic) (*it)->iconify(); } } + screen->updateStackingList(); } @@ -1648,13 +1700,24 @@ void BlackboxWindow::show(void) { XMapWindow(blackbox->getXDisplay(), client.window); XMapSubwindows(blackbox->getXDisplay(), frame.window); XMapWindow(blackbox->getXDisplay(), frame.window); + +#ifdef DEBUG + int real_x, real_y; + Window child; + XTranslateCoordinates(blackbox->getXDisplay(), client.window, + screen->getRootWindow(), + 0, 0, &real_x, &real_y, &child); + fprintf(stderr, "%s -- assumed: (%d, %d), real: (%d, %d)\n", getTitle(), + client.rect.left(), client.rect.top(), real_x, real_y); + assert(client.rect.left() == real_x && client.rect.top() == real_y); +#endif } void BlackboxWindow::deiconify(bool reassoc, bool raise) { if (flags.iconic || reassoc) screen->reassociateWindow(this, BSENTINEL, False); - else if (blackbox_attrib.workspace != screen->getCurrentWorkspace()->getID()) + else if (blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) return; show(); @@ -1685,6 +1748,7 @@ void BlackboxWindow::close(void) { ce.xclient.data.l[3] = 0l; ce.xclient.data.l[4] = 0l; XSendEvent(blackbox->getXDisplay(), client.window, False, NoEventMask, &ce); + XFlush(blackbox->getXDisplay()); } @@ -1703,10 +1767,12 @@ void BlackboxWindow::withdraw(void) { XGrabServer(blackbox->getXDisplay()); - XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask); - XUnmapWindow(blackbox->getXDisplay(), client.window); + unsigned long event_mask = PropertyChangeMask | FocusChangeMask | + StructureNotifyMask; XSelectInput(blackbox->getXDisplay(), client.window, - PropertyChangeMask | FocusChangeMask | StructureNotifyMask); + event_mask & ~StructureNotifyMask); + XUnmapWindow(blackbox->getXDisplay(), client.window); + XSelectInput(blackbox->getXDisplay(), client.window, event_mask); XUngrabServer(blackbox->getXDisplay()); @@ -1741,7 +1807,7 @@ void BlackboxWindow::maximize(unsigned int button) { blackbox_attrib.premax_x = blackbox_attrib.premax_y = 0; blackbox_attrib.premax_w = blackbox_attrib.premax_h = 0; - redrawAllButtons(); + redrawAllButtons(); // in case it is not called in configure() setState(current_state); return; } @@ -1755,7 +1821,6 @@ void BlackboxWindow::maximize(unsigned int button) { const Rect &screen_area = screen->availableArea(); frame.changing = screen_area; - constrain(TopLeft); switch(button) { case 1: @@ -1780,6 +1845,8 @@ void BlackboxWindow::maximize(unsigned int button) { break; } + constrain(TopLeft); + if (flags.shaded) { blackbox_attrib.flags ^= AttribShaded; blackbox_attrib.attrib ^= AttribShaded; @@ -1792,7 +1859,7 @@ void BlackboxWindow::maximize(unsigned int button) { frame.changing.width(), frame.changing.height()); if (flags.focused) screen->getWorkspace(blackbox_attrib.workspace)->raiseWindow(this); - redrawAllButtons(); + redrawAllButtons(); // in case it is not called in configure() setState(current_state); } @@ -1820,6 +1887,14 @@ void BlackboxWindow::remaximize(void) { void BlackboxWindow::setWorkspace(unsigned int n) { blackbox_attrib.flags |= AttribWorkspace; blackbox_attrib.workspace = n; + if (n == BSENTINEL) { // iconified window + /* + we set the workspace to 'all workspaces' so that taskbars will show the + window. otherwise, it made uniconifying a window imposible without the + blackbox workspace menu + */ + n = 0xffffffff; + } xatom->setValue(client.window, XAtom::net_wm_desktop, XAtom::cardinal, n); } @@ -1839,7 +1914,7 @@ void BlackboxWindow::shade(void) { frame.margin.bottom); } else { if (! (decorations & Decor_Titlebar)) - return; + return; // can't shade it without a titlebar! XResizeWindow(blackbox->getXDisplay(), frame.window, frame.inside_w, frame.title_h); @@ -1900,13 +1975,7 @@ void BlackboxWindow::stick(void) { } -void BlackboxWindow::setFocusFlag(bool focus) { - // only focus a window if it is visible - if (focus && !flags.visible) - return; - - flags.focused = focus; - +void BlackboxWindow::redrawWindowFrame(void) const { if (decorations & Decor_Titlebar) { if (flags.focused) { if (frame.ftitle) @@ -1982,6 +2051,17 @@ void BlackboxWindow::setFocusFlag(bool focus) { XSetWindowBorder(blackbox->getXDisplay(), frame.plate, frame.uborder_pixel); } +} + + +void BlackboxWindow::setFocusFlag(bool focus) { + // only focus a window if it is visible + if (focus && !flags.visible) + return; + + flags.focused = focus; + + redrawWindowFrame(); if (screen->isSloppyFocus() && screen->doAutoRaise()) { if (isFocused()) timer->start(); @@ -1997,8 +2077,8 @@ void BlackboxWindow::installColormap(bool install) { int i = 0, ncmap = 0; Colormap *cmaps = XListInstalledColormaps(blackbox->getXDisplay(), client.window, &ncmap); - XWindowAttributes wattrib; if (cmaps) { + XWindowAttributes wattrib; if (XGetWindowAttributes(blackbox->getXDisplay(), client.window, &wattrib)) { if (install) { @@ -2099,26 +2179,25 @@ void BlackboxWindow::restoreAttributes(void) { (unsigned long **)&net)) return; if (num < PropBlackboxAttributesElements) { - delete net; + delete [] net; return; } if (net->flags & AttribShaded && net->attrib & AttribShaded) { flags.shaded = False; + unsigned long orig_state = current_state; shade(); /* - Because the iconic'ness of shaded windows is lost, we need to set the - state to NormalState so that shaded windows on other workspaces will not - get shown on the first workspace. At this point in the life of a window, current_state should only be set to IconicState if the window was an *icon*, not if it was shaded. */ - current_state = NormalState; + if (orig_state != IconicState) + current_state = WithdrawnState; } - if ((net->workspace != screen->getCurrentWorkspaceID()) && - (net->workspace < screen->getWorkspaceCount())) + if (net->workspace != screen->getCurrentWorkspaceID() && + net->workspace < screen->getWorkspaceCount()) screen->reassociateWindow(this, net->workspace, True); if ((blackbox_attrib.workspace != screen->getCurrentWorkspaceID()) && @@ -2162,88 +2241,138 @@ void BlackboxWindow::restoreAttributes(void) { blackbox_attrib.premax_h = h; } - // with the state set it will then be the map events job to read the window's - // state and behave accordingly + // with the state set it will then be the map event's job to read the + // window's state and behave accordingly - delete net; + delete [] net; } /* - * Positions the frame according the the client window position and window - * gravity. + * Positions the Rect r according the the client window position and + * window gravity. */ -void BlackboxWindow::setGravityOffsets(void) { - // x coordinates for each gravity type - const int x_west = client.rect.x(); - const int x_east = client.rect.right() - frame.inside_w + 1; - const int x_center = client.rect.left() + - ((client.rect.width() - frame.rect.width()) / 2); - // y coordinates for each gravity type - const int y_north = client.rect.y(); - const int y_south = client.rect.bottom() - frame.inside_h + 1; - const int y_center = client.rect.top() + - ((client.rect.height() - frame.rect.height()) / 2); +void BlackboxWindow::applyGravity(Rect &r) { + // apply horizontal window gravity + switch (client.win_gravity) { + default: + case NorthWestGravity: + case SouthWestGravity: + case WestGravity: + r.setX(client.rect.x()); + break; + + case NorthGravity: + case SouthGravity: + case CenterGravity: + r.setX(client.rect.x() - (frame.margin.left + frame.margin.right) / 2); + break; + + case NorthEastGravity: + case SouthEastGravity: + case EastGravity: + r.setX(client.rect.x() - frame.margin.left - frame.margin.right + 2); + break; + + case ForgetGravity: + case StaticGravity: + r.setX(client.rect.x() - frame.margin.left); + break; + } + // apply vertical window gravity switch (client.win_gravity) { default: - case NorthWestGravity: frame.rect.setPos(x_west, y_north); break; - case NorthGravity: frame.rect.setPos(x_center, y_north); break; - case NorthEastGravity: frame.rect.setPos(x_east, y_north); break; - case SouthWestGravity: frame.rect.setPos(x_west, y_south); break; - case SouthGravity: frame.rect.setPos(x_center, y_south); break; - case SouthEastGravity: frame.rect.setPos(x_east, y_south); break; - case WestGravity: frame.rect.setPos(x_west, y_center); break; - case CenterGravity: frame.rect.setPos(x_center, y_center); break; - case EastGravity: frame.rect.setPos(x_east, y_center); break; + case NorthWestGravity: + case NorthEastGravity: + case NorthGravity: + r.setY(client.rect.y()); + break; + + case CenterGravity: + case EastGravity: + case WestGravity: + r.setY(client.rect.y() - (frame.margin.top + frame.margin.bottom) / 2); + break; + + case SouthWestGravity: + case SouthEastGravity: + case SouthGravity: + r.setY(client.rect.y() - frame.margin.top - frame.margin.bottom + 2); + break; case ForgetGravity: case StaticGravity: - frame.rect.setPos(client.rect.x() - frame.margin.left, - client.rect.y() - frame.margin.top); + r.setY(client.rect.y() - frame.margin.top); break; } } /* - * The reverse of the setGravityOffsets function. Uses the frame window's - * position to find the window's reference point. + * The reverse of the applyGravity function. + * + * Positions the Rect r according to the frame window position and + * window gravity. */ -void BlackboxWindow::restoreGravity(void) { - // x coordinates for each gravity type - const int x_west = frame.rect.x(); - const int x_east = frame.rect.x() + frame.inside_w - client.rect.width(); - const int x_center = frame.rect.x() - - ((client.rect.width() - frame.rect.width()) / 2); - // y coordinates for each gravity type - const int y_north = frame.rect.y(); - const int y_south = frame.rect.y() + frame.inside_h - client.rect.height(); - const int y_center = frame.rect.y() - - ((client.rect.height() - frame.rect.height()) / 2); - - switch(client.win_gravity) { +void BlackboxWindow::restoreGravity(Rect &r) { + // restore horizontal window gravity + switch (client.win_gravity) { default: - case NorthWestGravity: client.rect.setPos(x_west, y_north); break; - case NorthGravity: client.rect.setPos(x_center, y_north); break; - case NorthEastGravity: client.rect.setPos(x_east, y_north); break; - case SouthWestGravity: client.rect.setPos(x_west, y_south); break; - case SouthGravity: client.rect.setPos(x_center, y_south); break; - case SouthEastGravity: client.rect.setPos(x_east, y_south); break; - case WestGravity: client.rect.setPos(x_west, y_center); break; - case CenterGravity: client.rect.setPos(x_center, y_center); break; - case EastGravity: client.rect.setPos(x_east, y_center); break; + case NorthWestGravity: + case SouthWestGravity: + case WestGravity: + r.setX(frame.rect.x()); + break; + + case NorthGravity: + case SouthGravity: + case CenterGravity: + r.setX(frame.rect.x() + (frame.margin.left + frame.margin.right) / 2); + break; + + case NorthEastGravity: + case SouthEastGravity: + case EastGravity: + r.setX(frame.rect.x() + frame.margin.left + frame.margin.right - 2); + break; case ForgetGravity: case StaticGravity: - client.rect.setPos(frame.rect.left() + frame.margin.left, - frame.rect.top() + frame.margin.top); + r.setX(frame.rect.x() + frame.margin.left); + break; + } + + // restore vertical window gravity + switch (client.win_gravity) { + default: + case NorthWestGravity: + case NorthEastGravity: + case NorthGravity: + r.setY(frame.rect.y()); + break; + + case CenterGravity: + case EastGravity: + case WestGravity: + r.setY(frame.rect.y() + (frame.margin.top + frame.margin.bottom) / 2); + break; + + case SouthWestGravity: + case SouthEastGravity: + case SouthGravity: + r.setY(frame.rect.y() + frame.margin.top + frame.margin.bottom - 2); + break; + + case ForgetGravity: + case StaticGravity: + r.setY(frame.rect.y() + frame.margin.top); break; } } -void BlackboxWindow::redrawLabel(void) { +void BlackboxWindow::redrawLabel(void) const { if (flags.focused) { if (frame.flabel) XSetWindowBackgroundPixmap(blackbox->getXDisplay(), @@ -2263,31 +2392,23 @@ void BlackboxWindow::redrawLabel(void) { WindowStyle *style = screen->getWindowStyle(); - int pos = frame.bevel_w * 2, - dlen = style->doJustify(client.title.c_str(), pos, frame.label_w, - frame.bevel_w * 4, i18n.multibyte()); - - BPen pen((flags.focused) ? style->l_text_focus : style->l_text_unfocus, - style->font); - if (i18n.multibyte()) - XmbDrawString(blackbox->getXDisplay(), frame.label, style->fontset, - pen.gc(), pos, - (1 - style->fontset_extents->max_ink_extent.y), - client.title.c_str(), dlen); - else - XDrawString(blackbox->getXDisplay(), frame.label, pen.gc(), pos, - (style->font->ascent + 1), client.title.c_str(), dlen); + int pos = frame.bevel_w * 2; + style->doJustify(client.title.c_str(), pos, frame.label_w, frame.bevel_w * 4); + style->font->drawString(frame.label, pos, 1, + (flags.focused ? style->l_text_focus : + style->l_text_unfocus), + client.title); } -void BlackboxWindow::redrawAllButtons(void) { +void BlackboxWindow::redrawAllButtons(void) const { if (frame.iconify_button) redrawIconifyButton(False); if (frame.maximize_button) redrawMaximizeButton(flags.maximized); if (frame.close_button) redrawCloseButton(False); } -void BlackboxWindow::redrawIconifyButton(bool pressed) { +void BlackboxWindow::redrawIconifyButton(bool pressed) const { if (! pressed) { if (flags.focused) { if (frame.fbutton) @@ -2321,7 +2442,7 @@ void BlackboxWindow::redrawIconifyButton(bool pressed) { } -void BlackboxWindow::redrawMaximizeButton(bool pressed) { +void BlackboxWindow::redrawMaximizeButton(bool pressed) const { if (! pressed) { if (flags.focused) { if (frame.fbutton) @@ -2357,7 +2478,7 @@ void BlackboxWindow::redrawMaximizeButton(bool pressed) { } -void BlackboxWindow::redrawCloseButton(bool pressed) { +void BlackboxWindow::redrawCloseButton(bool pressed) const { if (! pressed) { if (flags.focused) { if (frame.fbutton) @@ -2393,7 +2514,7 @@ void BlackboxWindow::redrawCloseButton(bool pressed) { } -void BlackboxWindow::mapRequestEvent(XMapRequestEvent *re) { +void BlackboxWindow::mapRequestEvent(const XMapRequestEvent *re) { if (re->window != client.window) return; @@ -2426,7 +2547,7 @@ void BlackboxWindow::mapRequestEvent(XMapRequestEvent *re) { } -void BlackboxWindow::unmapNotifyEvent(XUnmapEvent *ue) { +void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent *ue) { if (ue->window != client.window) return; @@ -2439,7 +2560,7 @@ void BlackboxWindow::unmapNotifyEvent(XUnmapEvent *ue) { } -void BlackboxWindow::destroyNotifyEvent(XDestroyWindowEvent *de) { +void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent *de) { if (de->window != client.window) return; @@ -2452,7 +2573,7 @@ void BlackboxWindow::destroyNotifyEvent(XDestroyWindowEvent *de) { } -void BlackboxWindow::reparentNotifyEvent(XReparentEvent *re) { +void BlackboxWindow::reparentNotifyEvent(const XReparentEvent *re) { if (re->window != client.window || re->parent == frame.plate) return; @@ -2468,8 +2589,16 @@ void BlackboxWindow::reparentNotifyEvent(XReparentEvent *re) { } -void BlackboxWindow::propertyNotifyEvent(Atom atom) { - switch(atom) { +void BlackboxWindow::propertyNotifyEvent(const XPropertyEvent *pe) { + if (pe->state == PropertyDelete) + return; + +#ifdef DEBUG + fprintf(stderr, "BlackboxWindow::propertyNotifyEvent(): for 0x%lx\n", + client.window); +#endif + + switch(pe->atom) { case XA_WM_CLASS: case XA_WM_CLIENT_MACHINE: case XA_WM_COMMAND: @@ -2514,14 +2643,21 @@ void BlackboxWindow::propertyNotifyEvent(Atom atom) { if ((client.normal_hint_flags & PMinSize) && (client.normal_hint_flags & PMaxSize)) { + // the window now can/can't resize itself, so the buttons need to be + // regrabbed. + ungrabButtons(); if (client.max_width <= client.min_width && client.max_height <= client.min_height) { decorations &= ~(Decor_Maximize | Decor_Handle); functions &= ~(Func_Resize | Func_Maximize); } else { - decorations |= Decor_Maximize | Decor_Handle; - functions |= Func_Resize | Func_Maximize; + if (! isTransient()) { + decorations |= Decor_Maximize | Decor_Handle; + functions |= Func_Maximize; + } + functions |= Func_Resize; } + grabButtons(); setAllowedActions(); } @@ -2536,7 +2672,7 @@ void BlackboxWindow::propertyNotifyEvent(Atom atom) { } default: - if (atom == xatom->getAtom(XAtom::wm_protocols)) { + if (pe->atom == xatom->getAtom(XAtom::wm_protocols)) { getWMProtocols(); if ((decorations & Decor_Close) && (! frame.close_button)) { @@ -2547,7 +2683,7 @@ void BlackboxWindow::propertyNotifyEvent(Atom atom) { } if (windowmenu) windowmenu->reconfigure(); } - } else if (atom == xatom->getAtom(XAtom::net_wm_strut)) { + } else if (pe->atom == xatom->getAtom(XAtom::net_wm_strut)) { updateStrut(); } @@ -2556,7 +2692,11 @@ void BlackboxWindow::propertyNotifyEvent(Atom atom) { } -void BlackboxWindow::exposeEvent(XExposeEvent *ee) { +void BlackboxWindow::exposeEvent(const XExposeEvent *ee) { +#ifdef DEBUG + fprintf(stderr, "BlackboxWindow::exposeEvent() for 0x%lx\n", client.window); +#endif + if (frame.label == ee->window && (decorations & Decor_Titlebar)) redrawLabel(); else if (frame.close_button == ee->window) @@ -2568,30 +2708,33 @@ void BlackboxWindow::exposeEvent(XExposeEvent *ee) { } -void BlackboxWindow::configureRequestEvent(XConfigureRequestEvent *cr) { +void BlackboxWindow::configureRequestEvent(const XConfigureRequestEvent *cr) { if (cr->window != client.window || flags.iconic) return; - int cx = frame.rect.x(), cy = frame.rect.y(); - unsigned int cw = frame.rect.width(), ch = frame.rect.height(); - if (cr->value_mask & CWBorderWidth) client.old_bw = cr->border_width; - if (cr->value_mask & CWX) - cx = cr->x - frame.margin.left; + if (cr->value_mask & (CWX | CWY | CWWidth | CWHeight)) { + Rect req = frame.rect; - if (cr->value_mask & CWY) - cy = cr->y - frame.margin.top; + if (cr->value_mask & (CWX | CWY)) { + if (cr->value_mask & CWX) + client.rect.setX(cr->x); + if (cr->value_mask & CWY) + client.rect.setY(cr->y); - if (cr->value_mask & CWWidth) - cw = cr->width + frame.margin.left + frame.margin.right; + applyGravity(req); + } - if (cr->value_mask & CWHeight) - ch = cr->height + frame.margin.top + frame.margin.bottom; + if (cr->value_mask & CWWidth) + req.setWidth(cr->width + frame.margin.left + frame.margin.right); - if (frame.rect != Rect(cx, cy, cw, ch)) - configure(cx, cy, cw, ch); + if (cr->value_mask & CWHeight) + req.setHeight(cr->height + frame.margin.top + frame.margin.bottom); + + configure(req.x(), req.y(), req.width(), req.height()); + } if (cr->value_mask & CWStackMode) { switch (cr->detail) { @@ -2610,8 +2753,13 @@ void BlackboxWindow::configureRequestEvent(XConfigureRequestEvent *cr) { } -void BlackboxWindow::buttonPressEvent(XButtonEvent *be) { - if (frame.maximize_button == be->window) { +void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) { +#ifdef DEBUG + fprintf(stderr, "BlackboxWindow::buttonPressEvent() for 0x%lx\n", + client.window); +#endif + + if (frame.maximize_button == be->window && be->button <= 3) { redrawMaximizeButton(True); } else if (be->button == 1 || (be->button == 3 && be->state == Mod1Mask)) { if (! flags.focused) @@ -2631,7 +2779,7 @@ void BlackboxWindow::buttonPressEvent(XButtonEvent *be) { if (frame.title == be->window || frame.label == be->window) { if (((be->time - lastButtonPressTime) <= blackbox->getDoubleClickInterval()) || - (be->state & ControlMask)) { + (be->state == ControlMask)) { lastButtonPressTime = 0; shade(); } else { @@ -2649,84 +2797,87 @@ void BlackboxWindow::buttonPressEvent(XButtonEvent *be) { } else if (windowmenu && be->button == 3 && (frame.title == be->window || frame.label == be->window || frame.handle == be->window || frame.window == be->window)) { - int mx = 0, my = 0; - - if (frame.title == be->window || frame.label == be->window) { - mx = be->x_root - (windowmenu->getWidth() / 2); - my = frame.rect.y() + frame.title_h + frame.border_w; - } else if (frame.handle == be->window) { - mx = be->x_root - (windowmenu->getWidth() / 2); - my = frame.rect.bottom() - frame.handle_h - (frame.border_w * 3) - - windowmenu->getHeight(); + if (windowmenu->isVisible()) { + windowmenu->hide(); } else { - mx = be->x_root - (windowmenu->getWidth() / 2); - - if (be->y <= static_cast(frame.bevel_w)) - my = frame.rect.y() + frame.title_h; - else - my = be->y_root - (windowmenu->getHeight() / 2); - } - - // snap the window menu into a corner if necessary - we check the - // position of the menu with the coordinates of the client to - // make the comparisions easier. - // XXX: this needs some work! - if (mx > client.rect.right() - - static_cast(windowmenu->getWidth())) - mx = frame.rect.right() - windowmenu->getWidth() - frame.border_w + 1; - if (mx < client.rect.left()) - mx = frame.rect.x(); - - if (my > client.rect.bottom() - - static_cast(windowmenu->getHeight())) - my = frame.rect.bottom() - windowmenu->getHeight() - frame.border_w + 1; - if (my < client.rect.top()) - my = frame.rect.y() + ((decorations & Decor_Titlebar) ? - frame.title_h : 0); - - if (windowmenu) { - if (! windowmenu->isVisible()) { - windowmenu->move(mx, my); - windowmenu->show(); - XRaiseWindow(blackbox->getXDisplay(), windowmenu->getWindowID()); - XRaiseWindow(blackbox->getXDisplay(), - windowmenu->getSendToMenu()->getWindowID()); - } else { - windowmenu->hide(); - } + int mx = be->x_root - windowmenu->getWidth() / 2, + my = be->y_root - windowmenu->getHeight() / 2; + + // snap the window menu into a corner/side if necessary + int left_edge, right_edge, top_edge, bottom_edge; + + /* + the " + (frame.border_w * 2) - 1" bits are to get the proper width + and height of the menu, as the sizes returned by it do not include + the borders. + */ + left_edge = frame.rect.x(); + right_edge = frame.rect.right() - + (windowmenu->getWidth() + (frame.border_w * 2) - 1); + top_edge = client.rect.top() - (frame.border_w + frame.mwm_border_w); + bottom_edge = client.rect.bottom() - + (windowmenu->getHeight() + (frame.border_w * 2) - 1) + + (frame.border_w + frame.mwm_border_w); + + if (mx < left_edge) + mx = left_edge; + if (mx > right_edge) + mx = right_edge; + if (my < top_edge) + my = top_edge; + if (my > bottom_edge) + my = bottom_edge; + + windowmenu->move(mx, my); + windowmenu->show(); + XRaiseWindow(blackbox->getXDisplay(), windowmenu->getWindowID()); + XRaiseWindow(blackbox->getXDisplay(), + windowmenu->getSendToMenu()->getWindowID()); } // mouse wheel up } else if (be->button == 4) { if ((be->window == frame.label || - be->window == frame.title) && + be->window == frame.title || + be->window == frame.maximize_button || + be->window == frame.iconify_button || + be->window == frame.close_button) && ! flags.shaded) shade(); // mouse wheel down } else if (be->button == 5) { if ((be->window == frame.label || - be->window == frame.title) && + be->window == frame.title || + be->window == frame.maximize_button || + be->window == frame.iconify_button || + be->window == frame.close_button) && flags.shaded) shade(); } } -void BlackboxWindow::buttonReleaseEvent(XButtonEvent *re) { - if (re->window == frame.maximize_button) { +void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) { +#ifdef DEBUG + fprintf(stderr, "BlackboxWindow::buttonReleaseEvent() for 0x%lx\n", + client.window); +#endif + + if (re->window == frame.maximize_button && + re->button >= 1 && re->button <= 3) { if ((re->x >= 0 && re->x <= static_cast(frame.button_w)) && (re->y >= 0 && re->y <= static_cast(frame.button_w))) { maximize(re->button); } else { redrawMaximizeButton(flags.maximized); } - } else if (re->window == frame.iconify_button) { + } else if (re->window == frame.iconify_button && re->button == 1) { if ((re->x >= 0 && re->x <= static_cast(frame.button_w)) && (re->y >= 0 && re->y <= static_cast(frame.button_w))) { iconify(); } else { redrawIconifyButton(False); } - } else if (re->window == frame.close_button) { + } else if (re->window == frame.close_button & re->button == 1) { if ((re->x >= 0 && re->x <= static_cast(frame.button_w)) && (re->y >= 0 && re->y <= static_cast(frame.button_w))) close(); @@ -2742,6 +2893,7 @@ void BlackboxWindow::buttonReleaseEvent(XButtonEvent *re) { } + void BlackboxWindow::beginMove(int x_root, int y_root) { assert(! (flags.resizing || flags.moving)); @@ -3029,6 +3181,7 @@ void BlackboxWindow::beginResize(int x_root, int y_root, Corner dir) { default: assert(false); // unhandled Corner + return; // unreachable, for the compiler } XGrabServer(blackbox->getXDisplay()); @@ -3067,29 +3220,30 @@ void BlackboxWindow::doResize(int x_root, int y_root) { Corner anchor; switch (resize_dir) { - case BottomLeft: - anchor = TopRight; - frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x), - frame.rect.height() + (y_root - frame.grab_y)); - break; - case BottomRight: - anchor = TopLeft; - frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x), - frame.rect.height() + (y_root - frame.grab_y)); - break; - case TopLeft: - anchor = BottomRight; - frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x), - frame.rect.height() - (y_root - frame.grab_y)); - break; - case TopRight: - anchor = BottomLeft; - frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x), - frame.rect.height() - (y_root - frame.grab_y)); - break; + case BottomLeft: + anchor = TopRight; + frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x), + frame.rect.height() + (y_root - frame.grab_y)); + break; + case BottomRight: + anchor = TopLeft; + frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x), + frame.rect.height() + (y_root - frame.grab_y)); + break; + case TopLeft: + anchor = BottomRight; + frame.changing.setSize(frame.rect.width() - (x_root - frame.grab_x), + frame.rect.height() - (y_root - frame.grab_y)); + break; + case TopRight: + anchor = BottomLeft; + frame.changing.setSize(frame.rect.width() + (x_root - frame.grab_x), + frame.rect.height() - (y_root - frame.grab_y)); + break; - default: - assert(false); // unhandled Corner + default: + assert(false); // unhandled Corner + return; // unreachable, for the compiler } constrain(anchor, &gw, &gh); @@ -3132,25 +3286,47 @@ void BlackboxWindow::endResize(void) { } -void BlackboxWindow::motionNotifyEvent(XMotionEvent *me) { +void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) { +#ifdef DEBUG + fprintf(stderr, "BlackboxWindow::motionNotifyEvent() for 0x%lx\n", + client.window); +#endif + if (flags.moving) { doMove(me->x_root, me->y_root); } else if (flags.resizing) { doResize(me->x_root, me->y_root); } else { - if (! flags.resizing && (me->state & Button1Mask) && - (functions & Func_Move) && + if (!flags.resizing && me->state & Button1Mask && (functions & Func_Move) && (frame.title == me->window || frame.label == me->window || frame.handle == me->window || frame.window == me->window)) { beginMove(me->x_root, me->y_root); } else if ((functions & Func_Resize) && - (((me->state & Button1Mask) && - (me->window == frame.right_grip || - me->window == frame.left_grip)) || - (me->state & (Mod1Mask | Button3Mask) && - me->window == frame.window))) { - beginResize(me->x_root, me->y_root, - (me->window == frame.left_grip) ? BottomLeft : BottomRight); + (me->state & Button1Mask && (me->window == frame.right_grip || + me->window == frame.left_grip)) || + (me->state & Button3Mask && me->state & Mod1Mask && + me->window == frame.window)) { + unsigned int zones = screen->getResizeZones(); + Corner corner; + + if (me->window == frame.left_grip) { + corner = BottomLeft; + } else if (me->window == frame.right_grip || zones == 1) { + corner = BottomRight; + } else { + bool top; + bool left = (me->x_root - frame.rect.x() <= + static_cast(frame.rect.width() / 2)); + if (zones == 2) + top = False; + else // (zones == 4) + top = (me->y_root - frame.rect.y() <= + static_cast(frame.rect.height() / 2)); + corner = (top ? (left ? TopLeft : TopRight) : + (left ? BottomLeft : BottomRight)); + } + + beginResize(me->x_root, me->y_root, corner); } } } @@ -3187,7 +3363,10 @@ void BlackboxWindow::restore(bool remap) { XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask); XSelectInput(blackbox->getXDisplay(), frame.plate, NoEventMask); - restoreGravity(); + // do not leave a shaded window as an icon unless it was an icon + if (flags.shaded && ! flags.iconic) setState(NormalState); + + restoreGravity(client.rect); XUnmapWindow(blackbox->getXDisplay(), frame.window); XUnmapWindow(blackbox->getXDisplay(), client.window); @@ -3308,7 +3487,7 @@ void BlackboxWindow::changeBlackboxHints(BlackboxHints *net) { if (flags.shaded && ! (decorations & Decor_Titlebar)) shade(); - if (frame.window) { + if (flags.visible && frame.window) { XMapSubwindows(blackbox->getXDisplay(), frame.window); XMapWindow(blackbox->getXDisplay(), frame.window); } @@ -3342,12 +3521,7 @@ void BlackboxWindow::upsize(void) { // the height of the titlebar is based upon the height of the font being // used to display the window's title WindowStyle *style = screen->getWindowStyle(); - if (i18n.multibyte()) - frame.title_h = (style->fontset_extents->max_ink_extent.height + - (frame.bevel_w * 2) + 2); - else - frame.title_h = (style->font->ascent + style->font->descent + - (frame.bevel_w * 2) + 2); + frame.title_h = style->font->height() + (frame.bevel_w * 2) + 2; frame.label_h = frame.title_h - (frame.bevel_w * 2); frame.button_w = (frame.label_h - 2); @@ -3437,8 +3611,18 @@ void BlackboxWindow::constrain(Corner anchor, int *pw, int *ph) { dh -= base_height; dh /= client.height_inc; - if (pw) *pw = dw; - if (ph) *ph = dh; + if (pw) { + if (client.width_inc == 1) + *pw = dw + base_width; + else + *pw = dw; + } + if (ph) { + if (client.height_inc == 1) + *ph = dh + base_height; + else + *ph = dh; + } dw *= client.width_inc; dw += base_width; @@ -3480,21 +3664,14 @@ void BlackboxWindow::constrain(Corner anchor, int *pw, int *ph) { } -int WindowStyle::doJustify(const char *text, int &start_pos, - unsigned int max_length, unsigned int modifier, - bool multibyte) const { - size_t text_len = strlen(text); +void WindowStyle::doJustify(const std::string &text, int &start_pos, + unsigned int max_length, + unsigned int modifier) const { + size_t text_len = text.size(); unsigned int length; do { - if (multibyte) { - XRectangle ink, logical; - XmbTextExtents(fontset, text, text_len, &ink, &logical); - length = logical.width; - } else { - length = XTextWidth(font, text, text_len); - } - length += modifier; + length = font->measureString(string(text, 0, text_len)) + modifier; } while (length > max_length && text_len-- > 0); switch (justify) { @@ -3510,8 +3687,6 @@ int WindowStyle::doJustify(const char *text, int &start_pos, default: break; } - - return text_len; } @@ -3524,16 +3699,8 @@ BWindowGroup::BWindowGroup(Blackbox *b, Window _group) return; } - /* - watch for destroy notify on the group window (in addition to - any other events we are looking for) - - since some managed windows can also be window group controllers, - we need to make sure that we don't clobber the event mask for the - managed window - */ XSelectInput(blackbox->getXDisplay(), group, - wattrib.your_event_mask | StructureNotifyMask); + PropertyChangeMask | FocusChangeMask | StructureNotifyMask); blackbox->saveGroupSearch(group, this); }