#include "i18n.hh"
#include "blackbox.hh"
+#include "Font.hh"
#include "GCCache.hh"
#include "Iconmenu.hh"
#include "Image.hh"
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;
/*
blackbox->saveWindowSearch(frame.plate, this);
blackbox->saveWindowSearch(client.window, this);
- screen->addStrut(&client.strut);
- updateStrut();
-
// determine if this is a transient window
getTransientInfo();
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()))
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();
}
#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())
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) {
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();
}
void BlackboxWindow::reconfigure(void) {
upsize();
-
- client.rect.setPos(frame.rect.left() + frame.margin.left,
- frame.rect.top() + frame.margin.top);
-
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);
}
-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,
+ blackbox->getLowerRightAngleCursor());
+ // 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);
}
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,
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();
} else if (frame.handle) {
destroyHandle();
}
+ XSync(blackbox->getXDisplay(), False);
}
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
*/
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))
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<signed>(client.min_width))
+ client.max_width = sizehint.max_width;
+ else
+ client.max_width = client.min_width;
+
+ if (sizehint.max_height > static_cast<signed>(client.min_height))
+ client.max_height = sizehint.max_height;
+ else
+ client.max_height = client.min_height;
}
if (sizehint.flags & PResizeInc) {
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;
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) {
functions |= Func_Close;
}
}
- delete mwm_hint;
+ delete [] mwm_hint;
}
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);
reconfigure();
}
- delete blackbox_hint;
+ delete [] blackbox_hint;
return True;
}
}
+/*
+ * 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);
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);
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());
}
}
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) {
wkspc->setLastFocusedWindow(this);
return True;
}
-
- if (! client.rect.intersects(screen->getRect())) {
+#endif
+ 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,
ce.xclient.data.l[4] = 0l;
XSendEvent(blackbox->getXDisplay(), client.window, False,
NoEventMask, &ce);
+ XFlush(blackbox->getXDisplay());
}
return ret;
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();
ce.xclient.data.l[3] = 0l;
ce.xclient.data.l[4] = 0l;
XSendEvent(blackbox->getXDisplay(), client.window, False, NoEventMask, &ce);
+ XFlush(blackbox->getXDisplay());
}
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;
}
const Rect &screen_area = screen->availableArea();
frame.changing = screen_area;
- constrain(TopLeft);
switch(button) {
case 1:
break;
}
+ constrain(TopLeft);
+
if (flags.shaded) {
blackbox_attrib.flags ^= AttribShaded;
blackbox_attrib.attrib ^= AttribShaded;
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);
}
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);
}
-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)
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();
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) {
(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()) &&
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(),
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)
}
-void BlackboxWindow::redrawMaximizeButton(bool pressed) {
+void BlackboxWindow::redrawMaximizeButton(bool pressed) const {
if (! pressed) {
if (flags.focused) {
if (frame.fbutton)
}
-void BlackboxWindow::redrawCloseButton(bool pressed) {
+void BlackboxWindow::redrawCloseButton(bool pressed) const {
if (! pressed) {
if (flags.focused) {
if (frame.fbutton)
}
-void BlackboxWindow::mapRequestEvent(XMapRequestEvent *re) {
+void BlackboxWindow::mapRequestEvent(const XMapRequestEvent *re) {
if (re->window != client.window)
return;
}
-void BlackboxWindow::unmapNotifyEvent(XUnmapEvent *ue) {
+void BlackboxWindow::unmapNotifyEvent(const XUnmapEvent *ue) {
if (ue->window != client.window)
return;
}
-void BlackboxWindow::destroyNotifyEvent(XDestroyWindowEvent *de) {
+void BlackboxWindow::destroyNotifyEvent(const XDestroyWindowEvent *de) {
if (de->window != client.window)
return;
}
-void BlackboxWindow::reparentNotifyEvent(XReparentEvent *re) {
+void BlackboxWindow::reparentNotifyEvent(const XReparentEvent *re) {
if (re->window != client.window || re->parent == frame.plate)
return;
}
-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:
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();
}
}
default:
- if (atom == xatom->getAtom(XAtom::wm_protocols)) {
+ if (pe->atom == xatom->getAtom(XAtom::wm_protocols)) {
getWMProtocols();
if ((decorations & Decor_Close) && (! frame.close_button)) {
}
if (windowmenu) windowmenu->reconfigure();
}
- } else if (atom == xatom->getAtom(XAtom::net_wm_strut)) {
+ } else if (pe->atom == xatom->getAtom(XAtom::net_wm_strut)) {
updateStrut();
}
}
-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)
}
-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) {
}
-void BlackboxWindow::buttonPressEvent(XButtonEvent *be) {
+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) {
redrawMaximizeButton(True);
} else if (be->button == 1 || (be->button == 3 && be->state == Mod1Mask)) {
} 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<signed>(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<signed>(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<signed>(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) {
}
-void BlackboxWindow::buttonReleaseEvent(XButtonEvent *re) {
+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) {
if ((re->x >= 0 && re->x <= static_cast<signed>(frame.button_w)) &&
(re->y >= 0 && re->y <= static_cast<signed>(frame.button_w))) {
}
+
void BlackboxWindow::beginMove(int x_root, int y_root) {
assert(! (flags.resizing || flags.moving));
default:
assert(false); // unhandled Corner
+ return; // unreachable, for the compiler
}
XGrabServer(blackbox->getXDisplay());
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);
}
-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) {
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);
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);
}
// 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);
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;
}
-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) {
default:
break;
}
-
- return text_len;
}