]> Dogcows Code - chaz/openbox/blobdiff - src/Window.cc
add BFont class, with Xft support
[chaz/openbox] / src / Window.cc
index 7df3d64a6c4e4bd2fe034782a83295cf4ba006fc..e179824365885361661ea9dee601236a28c5b21b 100644 (file)
@@ -44,6 +44,7 @@ extern "C" {
 
 #include "i18n.hh"
 #include "blackbox.hh"
+#include "Font.hh"
 #include "GCCache.hh"
 #include "Iconmenu.hh"
 #include "Image.hh"
@@ -251,8 +252,7 @@ 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()))
@@ -330,7 +330,7 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
   if (flags.shaded) {
     flags.shaded = False;
     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
@@ -360,7 +360,7 @@ BlackboxWindow::BlackboxWindow(Blackbox *b, Window w, BScreen *s) {
     window was iconified previously.
   */
 
-  setFocusFlag(False);
+  redrawWindowFrame();
 }
 
 
@@ -844,8 +844,7 @@ void BlackboxWindow::reconfigure(void) {
   positionWindows();
   decorate();
 
-  XClearWindow(blackbox->getXDisplay(), frame.window);
-  setFocusFlag(flags.focused);
+  redrawWindowFrame();
 
   configure(frame.rect.x(), frame.rect.y(),
             frame.rect.width(), frame.rect.height());
@@ -872,7 +871,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,
@@ -1226,9 +1226,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 +1272,7 @@ void BlackboxWindow::getMWMHints(void) {
         functions |= Func_Close;
     }
   }
-  delete mwm_hint;
+  delete [] mwm_hint;
 }
 
 
@@ -1287,9 +1290,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 +1357,7 @@ bool BlackboxWindow::getBlackboxHints(void) {
     reconfigure();
   }
   
-  delete blackbox_hint;
+  delete [] blackbox_hint;
 
   return True;
 }
@@ -1431,9 +1437,9 @@ BlackboxWindow *BlackboxWindow::getTransientFor(void) const {
 
 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 = False;
 
-  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,15 +1460,14 @@ void BlackboxWindow::configure(int dx, int dy,
 
     positionWindows();
     decorate();
-    setFocusFlag(flags.focused);
-    redrawAllButtons();
-  } else {
+    redrawWindowFrame();
+  } else if (frame.rect.x() != dx || frame.rect.y() != dy) {
+    send_event = True;
+
     frame.rect.setPos(dx, dy);
 
     XMoveWindow(blackbox->getXDisplay(), frame.window,
                 frame.rect.x(), frame.rect.y());
-
-    if (! flags.moving) send_event = True;
   }
 
   if (send_event && ! flags.moving) {
@@ -1483,8 +1488,8 @@ 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);
   }
@@ -1537,7 +1542,7 @@ bool BlackboxWindow::setInputFocus(void) {
     return True;
   }
 
-  if (! client.rect.intersects(screen->getRect())) {
+  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,
@@ -1741,7 +1746,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 +1760,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 +1784,8 @@ void BlackboxWindow::maximize(unsigned int button) {
     break;
   }
 
+  constrain(TopLeft);
+
   if (flags.shaded) {
     blackbox_attrib.flags ^= AttribShaded;
     blackbox_attrib.attrib ^= AttribShaded;
@@ -1792,7 +1798,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);
 }
 
@@ -1839,7 +1845,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 +1906,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 +1982,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 +2008,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,7 +2110,7 @@ void BlackboxWindow::restoreAttributes(void) {
                         (unsigned long **)&net))
     return;
   if (num < PropBlackboxAttributesElements) {
-    delete net;
+    delete [] net;
     return;
   }
 
@@ -2162,88 +2173,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);
+    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);
+    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);
+    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);
+    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 +2324,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 +2374,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 +2410,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 +2446,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 +2479,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 +2492,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 +2505,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;
 
@@ -2556,7 +2609,7 @@ void BlackboxWindow::propertyNotifyEvent(Atom atom) {
 }
 
 
-void BlackboxWindow::exposeEvent(XExposeEvent *ee) {
+void BlackboxWindow::exposeEvent(const XExposeEvent *ee) {
   if (frame.label == ee->window && (decorations & Decor_Titlebar))
     redrawLabel();
   else if (frame.close_button == ee->window)
@@ -2568,30 +2621,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 & (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 & CWY)
-    cy = cr->y - frame.margin.top;
+      applyGravity(req);
+    }
 
-  if (cr->value_mask & CWWidth)
-    cw = cr->width + frame.margin.left + frame.margin.right;
+    if (cr->value_mask & CWWidth)
+      req.setWidth(cr->width + frame.margin.left + frame.margin.right);
 
-  if (cr->value_mask & CWHeight)
-    ch = cr->height + frame.margin.top + frame.margin.bottom;
+    if (cr->value_mask & CWHeight)
+      req.setHeight(cr->height + frame.margin.top + frame.margin.bottom);
 
-  if (frame.rect != Rect(cx, cy, cw, ch))
-    configure(cx, cy, cw, ch);
+    configure(req.x(), req.y(), req.width(), req.height());
+  }
 
   if (cr->value_mask & CWStackMode) {
     switch (cr->detail) {
@@ -2610,7 +2666,7 @@ void BlackboxWindow::configureRequestEvent(XConfigureRequestEvent *cr) {
 }
 
 
-void BlackboxWindow::buttonPressEvent(XButtonEvent *be) {
+void BlackboxWindow::buttonPressEvent(const XButtonEvent *be) {
   if (frame.maximize_button == be->window) {
     redrawMaximizeButton(True);
   } else if (be->button == 1 || (be->button == 3 && be->state == Mod1Mask)) {
@@ -2711,7 +2767,7 @@ void BlackboxWindow::buttonPressEvent(XButtonEvent *be) {
 }
 
 
-void BlackboxWindow::buttonReleaseEvent(XButtonEvent *re) {
+void BlackboxWindow::buttonReleaseEvent(const XButtonEvent *re) {
   if (re->window == frame.maximize_button) {
     if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
         (re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
@@ -2742,6 +2798,7 @@ void BlackboxWindow::buttonReleaseEvent(XButtonEvent *re) {
 }
 
 
+
 void BlackboxWindow::beginMove(int x_root, int y_root) {
   assert(! (flags.resizing || flags.moving));
 
@@ -2786,6 +2843,7 @@ void BlackboxWindow::beginMove(int x_root, int y_root) {
   frame.grab_y = y_root - frame.rect.y() - frame.border_w;
 }
 
+
 void BlackboxWindow::doMove(int x_root, int y_root) {
   assert(flags.moving);
   assert(blackbox->getChangingWindow() == this);
@@ -2797,30 +2855,110 @@ void BlackboxWindow::doMove(int x_root, int y_root) {
   const int snap_distance = screen->getEdgeSnapThreshold();
 
   if (snap_distance) {
-    Rect srect = screen->availableArea();
     // window corners
     const int wleft = dx,
-      wright = dx + frame.rect.width() - 1,
-      wtop = dy,
-      wbottom = dy + frame.rect.height() - 1;
+              wright = dx + frame.rect.width() - 1,
+              wtop = dy,
+              wbottom = dy + frame.rect.height() - 1;
+
+    if (screen->getWindowToWindowSnap()) {
+      Workspace *w = screen->getWorkspace(getWorkspaceNumber());
+      assert(w);
+
+      // try snap to another window
+      for (unsigned int i = 0, c = w->getCount(); i < c; ++i) {
+        BlackboxWindow *snapwin = w->getWindow(i);
+        if (snapwin == this)
+          continue;   // don't snap to self
+
+        bool snapped = False;
+        
+        const Rect &winrect = snapwin->frameRect();
+        int dleft = std::abs(wright - winrect.left()),
+           dright = std::abs(wleft - winrect.right()),
+             dtop = std::abs(wbottom - winrect.top()),
+          dbottom = std::abs(wtop - winrect.bottom());
+
+        if (wtop >= (signed)(winrect.y() - frame.rect.height() + 1) &&
+            wtop < (signed)(winrect.y() + winrect.height() - 1)) {
+
+          // snap left of other window?
+          if (dleft < snap_distance && dleft <= dright) {
+            dx = winrect.left() - frame.rect.width();
+            snapped = True;
+          }
+          // snap right of other window?
+          else if (dright < snap_distance) {
+            dx = winrect.right() + 1;
+            snapped = True;
+          }
+
+          if (snapped) {
+            if (screen->getWindowCornerSnap()) {
+              // try corner-snap to its other sides
+              dtop = std::abs(wtop - winrect.top());
+              dbottom = std::abs(wbottom - winrect.bottom());
+              if (dtop < snap_distance && dtop <= dbottom)
+                dy = winrect.top();
+              else if (dbottom < snap_distance)
+                dy = winrect.bottom() - frame.rect.height() + 1;
+            }
+
+            continue;
+          }
+        }
+
+        if (wleft >= (signed)(winrect.x() - frame.rect.width() + 1) &&
+            wleft < (signed)(winrect.x() + winrect.width() - 1)) {
+
+          // snap top of other window?
+          if (dtop < snap_distance && dtop <= dbottom) {
+            dy = winrect.top() - frame.rect.height();
+            snapped = True;
+          }
+          // snap bottom of other window?
+          else if (dbottom < snap_distance) {
+            dy = winrect.bottom() + 1;
+            snapped = True;
+          }
+
+          if (snapped) {
+            if (screen->getWindowCornerSnap()) {
+              // try corner-snap to its other sides
+              dleft = std::abs(wleft - winrect.left());
+              dright = std::abs(wright - winrect.right());
+              if (dleft < snap_distance && dleft <= dright)
+                dx = winrect.left();
+              else if (dright < snap_distance)
+                dx = winrect.right() - frame.rect.width() + 1;
+            }
+
+            continue;
+          }
+        }
+      }
+    }
+
+    // try snap to the screen's available area
+    Rect srect = screen->availableArea();
 
     int dleft = std::abs(wleft - srect.left()),
-      dright = std::abs(wright - srect.right()),
-      dtop = std::abs(wtop - srect.top()),
+       dright = std::abs(wright - srect.right()),
+         dtop = std::abs(wtop - srect.top()),
       dbottom = std::abs(wbottom - srect.bottom());
 
     // snap left?
-    if (dleft < snap_distance && dleft < dright)
+    if (dleft < snap_distance && dleft <= dright)
       dx = srect.left();
     // snap right?
-    else if (dright < snap_distance && dright < dleft)
+    else if (dright < snap_distance)
       dx = srect.right() - frame.rect.width() + 1;
 
     // snap top?
-    if (dtop < snap_distance && dtop < dbottom)
+    if (dtop < snap_distance && dtop <= dbottom)
       dy = srect.top();
     // snap bottom?
-    else if (dbottom < snap_distance && dbottom < dtop)
+    else if (dbottom < snap_distance)
       dy = srect.bottom() - frame.rect.height() + 1;
 
     srect = screen->getRect(); // now get the full screen
@@ -2831,17 +2969,17 @@ void BlackboxWindow::doMove(int x_root, int y_root) {
       dbottom = std::abs(wbottom - srect.bottom());
 
     // snap left?
-    if (dleft < snap_distance && dleft < dright)
+    if (dleft < snap_distance && dleft <= dright)
       dx = srect.left();
     // snap right?
-    else if (dright < snap_distance && dright < dleft)
+    else if (dright < snap_distance)
       dx = srect.right() - frame.rect.width() + 1;
 
     // snap top?
-    if (dtop < snap_distance && dtop < dbottom)
+    if (dtop < snap_distance && dtop <= dbottom)
       dy = srect.top();
     // snap bottom?
-    else if (dbottom < snap_distance && dbottom < dtop)
+    else if (dbottom < snap_distance)
       dy = srect.bottom() - frame.rect.height() + 1;
   }
 
@@ -3051,7 +3189,7 @@ void BlackboxWindow::endResize(void) {
 }
 
 
-void BlackboxWindow::motionNotifyEvent(XMotionEvent *me) {
+void BlackboxWindow::motionNotifyEvent(const XMotionEvent *me) {
   if (flags.moving) {
     doMove(me->x_root, me->y_root);
   } else if (flags.resizing) {
@@ -3106,7 +3244,7 @@ void BlackboxWindow::restore(bool remap) {
   XSelectInput(blackbox->getXDisplay(), client.window, NoEventMask);
   XSelectInput(blackbox->getXDisplay(), frame.plate, NoEventMask);
 
-  restoreGravity();
+  restoreGravity(client.rect);
 
   XUnmapWindow(blackbox->getXDisplay(), frame.window);
   XUnmapWindow(blackbox->getXDisplay(), client.window);
@@ -3227,7 +3365,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);
     }
@@ -3261,12 +3399,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);
@@ -3356,8 +3489,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;
@@ -3399,21 +3542,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);
+int 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) {
This page took 0.041829 seconds and 4 git commands to generate.