X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fframe.cc;h=5ffdc726ada7ea2bb9be421e99203d02fc664e97;hb=e4fa1c5a71fd8719ead9c9b9211c142c4970dcca;hp=a945413d35a62b4e25a34ef1879df84a58f40933;hpb=d8de17b58e2fee1414e0970bc372b661abe259a6;p=chaz%2Fopenbox diff --git a/src/frame.cc b/src/frame.cc index a945413d..5ffdc726 100644 --- a/src/frame.cc +++ b/src/frame.cc @@ -10,336 +10,439 @@ extern "C" { #endif // SHAPE } -#include "openbox.hh" #include "frame.hh" #include "client.hh" +#include "openbox.hh" #include "otk/display.hh" #include -#include // TEMP +#include namespace ob { -OBFrame::OBFrame(OBClient *client, otk::Style *style) - : otk::OtkWidget(Openbox::instance, style), - _client(client), - _screen(otk::OBDisplay::screenInfo(client->screen())), - _plate(this), - _titlebar(this), - _button_close(&_titlebar), - _button_iconify(&_titlebar), - _button_max(&_titlebar), - _button_stick(&_titlebar), - _label(&_titlebar), - _handle(this), - _grip_left(&_handle), - _grip_right(&_handle), - _decorations(client->decorations()) +const long Frame::event_mask; + +Window createWindow(const otk::ScreenInfo *info, Window parent, + unsigned long mask, XSetWindowAttributes *attrib) { - assert(client); - assert(style); - - unmanaged(); - _titlebar.unmanaged(); - _button_close.unmanaged(); - _button_iconify.unmanaged(); - _button_max.unmanaged(); - _button_stick.unmanaged(); - _label.unmanaged(); - _handle.unmanaged(); - _grip_left.unmanaged(); - _grip_right.unmanaged(); - _plate.unmanaged(); - - _plate.show(); - - _button_close.setText("X"); - _button_iconify.setText("I"); - _button_max.setText("M"); - _button_stick.setText("S"); - _label.setText(_client->title()); - - _style = 0; - setStyle(style); - - grabClient(); + return XCreateWindow(**otk::display, parent, 0, 0, 1, 1, 0, + info->depth(), InputOutput, info->visual(), + mask, attrib); + } - -OBFrame::~OBFrame() +Frame::Frame(Client *client) + : _client(client), + _visible(false), + _plate(0), + _title(0), + _label(0), + _handle(0), + _lgrip(0), + _rgrip(0), + _buttons(0), + _numbuttons(0), + _titleorder(0), + _frame_sur(0), + _title_sur(0), + _label_sur(0), + _handle_sur(0), + _grip_sur(0), + _buttons_sur(0) { - releaseClient(false); + assert(client); + + XSetWindowAttributes attrib; + unsigned long mask; + const otk::ScreenInfo *info = otk::display->screenInfo(client->screen()); + + // create all of the decor windows (except title bar buttons) + mask = CWOverrideRedirect | CWEventMask; + attrib.event_mask = Frame::event_mask; + attrib.override_redirect = true; + _frame = createWindow(info, info->rootWindow(), mask, &attrib); + + mask = 0; + _plate = createWindow(info, _frame, mask, &attrib); + mask = CWEventMask; + attrib.event_mask = (ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | + ExposureMask); + _title = createWindow(info, _frame, mask, &attrib); + _label = createWindow(info, _title, mask, &attrib); + _handle = createWindow(info, _frame, mask, &attrib); + mask |= CWCursor; + attrib.cursor = openbox->cursors().ll_angle; + _lgrip = createWindow(info, _handle, mask, &attrib); + attrib.cursor = openbox->cursors().lr_angle; + _rgrip = createWindow(info, _handle, mask, &attrib); + + // the other stuff is shown based on decor settings + XMapWindow(**otk::display, _plate); + XMapWindow(**otk::display, _lgrip); + XMapWindow(**otk::display, _rgrip); + XMapWindow(**otk::display, _label); + + applyStyle(*otk::RenderStyle::style(_client->screen())); + + // XXX load buttons + _numbuttons = 0; + _buttons = new Window[0]; + _buttons_sur = new otk::Surface*[0]; + _titleorder = new unsigned int[1]; + _titleorder[0] = (unsigned)-1; + + // register all of the windows with the event dispatcher + Window *w = allWindows(); + for (unsigned int i = 0; w[i]; ++i) + openbox->registerHandler(w[i], this); + delete [] w; } +Frame::~Frame() +{ + // unregister all of the windows with the event dispatcher + Window *w = allWindows(); + for (unsigned int i = 0; w[i]; ++i) + openbox->clearHandler(w[i]); + delete [] w; + + for (unsigned int i = 0; i < _numbuttons; ++i) { + XDestroyWindow(**otk::display, _buttons[i]); + delete _buttons_sur[i]; + } + XDestroyWindow(**otk::display, _rgrip); + XDestroyWindow(**otk::display, _lgrip); + XDestroyWindow(**otk::display, _handle); + XDestroyWindow(**otk::display, _label); + XDestroyWindow(**otk::display, _title); + XDestroyWindow(**otk::display, _frame); + + if (_frame_sur) delete _frame_sur; + if (_title_sur) delete _title_sur; + if (_label_sur) delete _label_sur; + if (_handle_sur) delete _handle_sur; + if (_grip_sur) delete _grip_sur; + + delete [] _buttons; + delete [] _titleorder; + delete [] _buttons_sur; +} -void OBFrame::setStyle(otk::Style *style) +void Frame::show() { - assert(style); - - otk::OtkWidget::setStyle(style); - // set the grips' textures - _grip_left.setTexture(style->getGripFocus()); - _grip_left.setUnfocusTexture(style->getGripUnfocus()); - _grip_left.setPressedFocusTexture(style->getGripFocus()); - _grip_left.setPressedUnfocusTexture(style->getGripUnfocus()); - _grip_right.setTexture(style->getGripFocus()); - _grip_right.setUnfocusTexture(style->getGripUnfocus()); - _grip_right.setPressedFocusTexture(style->getGripFocus()); - _grip_right.setPressedUnfocusTexture(style->getGripUnfocus()); - - _titlebar.setTexture(style->getTitleFocus()); - _titlebar.setUnfocusTexture(style->getTitleUnfocus()); - _handle.setTexture(style->getHandleFocus()); - _handle.setUnfocusTexture(style->getHandleUnfocus()); - - // if a style was previously set, then 'replace' is true, cause we're - // replacing a style - bool replace = (_style); + if (!_visible) { + _visible = true; + XMapWindow(**otk::display, _frame); + } +} - if (replace) { - // XXX: do shit here whatever - // XXX: save the position based on gravity +void Frame::hide() +{ + if (_visible) { + _visible = false; + XUnmapWindow(**otk::display, _frame); } - - _style = style; - - // XXX: change when focus changes! - XSetWindowBorder(otk::OBDisplay::display, _plate.getWindow(), - _style->getFrameFocus()->color().pixel()); - - XSetWindowBorder(otk::OBDisplay::display, getWindow(), - _style->getBorderColor()->pixel()); - XSetWindowBorder(otk::OBDisplay::display, _titlebar.getWindow(), - _style->getBorderColor()->pixel()); - XSetWindowBorder(otk::OBDisplay::display, _grip_left.getWindow(), - _style->getBorderColor()->pixel()); - XSetWindowBorder(otk::OBDisplay::display, _grip_right.getWindow(), - _style->getBorderColor()->pixel()); - XSetWindowBorder(otk::OBDisplay::display, _handle.getWindow(), - _style->getBorderColor()->pixel()); - - // if !replace, then adjust() will get called after the client is grabbed! - if (replace) - adjust(); // size/position everything } +MouseContext::MC Frame::mouseContext(Window win) const +{ + if (win == _frame) return MouseContext::Frame; + if (win == _title || + win == _label) return MouseContext::Titlebar; + if (win == _handle) return MouseContext::Handle; + if (win == _plate) return MouseContext::Window; + if (win == _lgrip || + win == _rgrip) return MouseContext::Grip; + return (MouseContext::MC) -1; +} + +Window *Frame::allWindows() const +{ + Window *w = new Window[7 + _numbuttons + 1]; + unsigned int i = 0; + w[i++] = _frame; + w[i++] = _plate; + w[i++] = _title; + w[i++] = _label; + w[i++] = _handle; + w[i++] = _lgrip; + w[i++] = _rgrip; + for (unsigned int j = 0; j < _numbuttons; ++j) + w[j + i++] = _buttons[j]; + w[i] = 0; + return w; +} -void OBFrame::adjust() +void Frame::applyStyle(const otk::RenderStyle &style) { - // XXX: only if not overridden or something!!! MORE LOGIC HERE!! - _decorations = _client->decorations(); - _decorations = 0xffffffff; + // set static border colors + XSetWindowBorder(**otk::display, _frame, style.frameBorderColor()->pixel()); + XSetWindowBorder(**otk::display, _title, style.frameBorderColor()->pixel()); + XSetWindowBorder(**otk::display, _handle, style.frameBorderColor()->pixel()); + XSetWindowBorder(**otk::display, _lgrip, style.frameBorderColor()->pixel()); + XSetWindowBorder(**otk::display, _rgrip, style.frameBorderColor()->pixel()); + + // size all the fixed-size elements + geom.font_height = style.labelFont()->height(); + if (geom.font_height < 1) geom.font_height = 1; + geom.button_size = geom.font_height - 2; + if (geom.button_size < 1) geom.button_size = 1; + geom.handle_height = style.handleWidth(); + if (geom.handle_height < 1) geom.handle_height = 1; + geom.bevel = style.bevelWidth(); - int width; // the width of the client and its border - int bwidth; // width to make borders - int cbwidth; // width of the inner client border + XResizeWindow(**otk::display, _lgrip, geom.grip_width(), geom.handle_height); + XResizeWindow(**otk::display, _rgrip, geom.grip_width(), geom.handle_height); - if (_decorations & OBClient::Decor_Border) { - bwidth = _style->getBorderWidth(); - cbwidth = _style->getFrameWidth(); - } else - bwidth = cbwidth = 0; - // inside this function _size is the size EXCLUDING the outer border - // at the end of this function it becomes the size INCLUDING the outer border - _size.left = _size.top = _size.bottom = _size.right = cbwidth; - width = _client->area().width() + cbwidth * 2; - - XSetWindowBorderWidth(otk::OBDisplay::display, _plate.getWindow(), cbwidth); - - XSetWindowBorderWidth(otk::OBDisplay::display, getWindow(), bwidth); - XSetWindowBorderWidth(otk::OBDisplay::display, _titlebar.getWindow(), - bwidth); - XSetWindowBorderWidth(otk::OBDisplay::display, _grip_left.getWindow(), - bwidth); - XSetWindowBorderWidth(otk::OBDisplay::display, _grip_right.getWindow(), - bwidth); - XSetWindowBorderWidth(otk::OBDisplay::display, _handle.getWindow(), bwidth); - - if (_decorations & OBClient::Decor_Titlebar) { - // set the titlebar size - _titlebar.setGeometry(-bwidth, - -bwidth, - width, - (_style->getFont().height() + - _style->getBevelWidth() * 2)); - _size.top += _titlebar.height() + bwidth; - - // set the label size - _label.setGeometry(0, _style->getBevelWidth(), - width, _style->getFont().height()); - // set the buttons sizes - if (_decorations & OBClient::Decor_Iconify) - _button_iconify.setGeometry(0, _style->getBevelWidth() + 1, - _label.height() - 2, - _label.height() - 2); - if (_decorations & OBClient::Decor_Maximize) - _button_max.setGeometry(0, _style->getBevelWidth() + 1, - _label.height() - 2, - _label.height() - 2); - if (_decorations & OBClient::Decor_Sticky) - _button_stick.setGeometry(0, _style->getBevelWidth() + 1, - _label.height() - 2, - _label.height() - 2); - if (_decorations & OBClient::Decor_Close) - _button_close.setGeometry(0, _style->getBevelWidth() + 1, - _label.height() - 2, - _label.height() - 2); - - // separation between titlebar elements - const int sep = _style->getBevelWidth() + 1; - - std::string layout = "SLIMC"; // XXX: get this from somewhere - // XXX: it is REQUIRED that by this point, the string only has one of each - // possible letter, all of the letters are valid, and L exists somewhere in - // the string! - - // the size of the label. this ASSUMES the layout has only buttons other - // that the ONE LABEL!! - // adds an extra sep so that there's a space on either side of the - // titlebar.. note: x = sep, below. - _label.setWidth(width - sep * 2 - - (_button_iconify.width() + sep) * (layout.size() - 1)); - - int x = sep; - for (int i = 0, len = layout.size(); i < len; ++i) { - switch (layout[i]) { - case 'I': - _button_iconify.move(x, _button_iconify.getRect().y()); - x += _button_iconify.width(); - break; - case 'L': - _label.move(x, _label.getRect().y()); - x += _label.width(); - break; - case 'M': - _button_max.move(x, _button_max.getRect().y()); - x += _button_max.width(); - break; - case 'S': - _button_stick.move(x, _button_stick.getRect().y()); - x += _button_stick.width(); - break; - case 'C': - _button_close.move(x, _button_close.getRect().y()); - x += _button_close.width(); - break; - default: - assert(false); // the layout string is invalid! - } - x += sep; - } - } + for (unsigned int i = 0; i < _numbuttons; ++i) + XResizeWindow(**otk::display, _buttons[i], + geom.button_size, geom.button_size); +} - if (_decorations & OBClient::Decor_Handle) { - _handle.setGeometry(-bwidth, - _size.top + _client->area().height() + cbwidth, - width, _style->getHandleWidth()); - _grip_left.setGeometry(-bwidth, - -bwidth, - // XXX: get a Point class in otk and use that for - // the 'buttons size' since theyre all the same - _button_iconify.width() * 2, - _handle.height()); - _grip_right.setGeometry(((_handle.getRect().right() + 1) - - _button_iconify.width() * 2), - -bwidth, - // XXX: get a Point class in otk and use that for - // the 'buttons size' since theyre all the same - _button_iconify.width() * 2, - _handle.height()); - _size.bottom += _handle.height() + bwidth; - } +void Frame::styleChanged(const otk::RenderStyle &style) +{ + applyStyle(style); + // size/position everything + adjustSize(); + adjustPosition(); +} - // position/size all the windows - - resize(_size.left + _size.right + _client->area().width(), - _size.top + _size.bottom + _client->area().height()); - - _plate.setGeometry(_size.left - cbwidth, _size.top - cbwidth, - _client->area().width(), _client->area().height()); - - // map/unmap all the windows - if (_decorations & OBClient::Decor_Titlebar) { - _label.show(); - if (_decorations & OBClient::Decor_Iconify) - _button_iconify.show(); - else - _button_iconify.hide(); - if (_decorations & OBClient::Decor_Maximize) - _button_max.show(); - else - _button_max.hide(); - if (_decorations & OBClient::Decor_Sticky) - _button_stick.show(); - else - _button_stick.hide(); - if (_decorations & OBClient::Decor_Close) - _button_close.show(); - else - _button_close.hide(); - _titlebar.show(); +void Frame::adjustFocus() +{ + // XXX optimizations later... + adjustSize(); +} + +void Frame::adjustTitle() +{ + // XXX optimizations later... + adjustSize(); +} + +static void render(int screen, const otk::Size &size, Window win, + otk::Surface **surface, + const otk::RenderTexture &texture) +{ + otk::Surface *s = new otk::Surface(screen, size); + otk::display->renderControl(screen)->drawBackground(*s, texture); + XSetWindowBackgroundPixmap(**otk::display, win, s->pixmap()); + XClearWindow(**otk::display, win); + if (*surface) delete *surface; + *surface = s; +} + +void Frame::adjustSize() +{ + Client::DecorationFlags decorations = _client->decorations(); + const otk::RenderStyle *style = otk::RenderStyle::style(_client->screen()); + + if (decorations & Client::Decor_Border) { + geom.bwidth = style->frameBorderWidth(); + geom.cbwidth = style->clientBorderWidth(); } else { - _titlebar.hide(true); + geom.bwidth = geom.cbwidth = 0; } + _innersize.left = _innersize.top = _innersize.bottom = _innersize.right = + geom.cbwidth; + geom.width = _client->area().width() + geom.cbwidth * 2; + assert(geom.width > 0); + + // set border widths + XSetWindowBorderWidth(**otk::display, _plate, geom.cbwidth); + XSetWindowBorderWidth(**otk::display, _frame, geom.bwidth); + XSetWindowBorderWidth(**otk::display, _title, geom.bwidth); + XSetWindowBorderWidth(**otk::display, _handle, geom.bwidth); + XSetWindowBorderWidth(**otk::display, _lgrip, geom.bwidth); + XSetWindowBorderWidth(**otk::display, _rgrip, geom.bwidth); + + // position/size and map/unmap all the windows + + if (decorations & Client::Decor_Titlebar) { + XMoveResizeWindow(**otk::display, _title, -geom.bwidth, -geom.bwidth, + geom.width, geom.title_height()); + _innersize.top += geom.title_height() + geom.bwidth; + XMapWindow(**otk::display, _title); - if (_decorations & OBClient::Decor_Handle) - _handle.show(true); - else - _handle.hide(true); + // layout the title bar elements + layoutTitle(); + } else + XUnmapWindow(**otk::display, _title); + + if (decorations & Client::Decor_Handle) { + geom.handle_y = _innersize.top + _client->area().height() + geom.cbwidth; + XMoveResizeWindow(**otk::display, _handle, -geom.bwidth, geom.handle_y, + geom.width, geom.handle_height); + XMoveWindow(**otk::display, _lgrip, -geom.bwidth, -geom.bwidth); + XMoveWindow(**otk::display, _rgrip, + -geom.bwidth + geom.width - geom.grip_width(), + -geom.bwidth); + _innersize.bottom += geom.handle_height + geom.bwidth; + XMapWindow(**otk::display, _handle); + } else + XUnmapWindow(**otk::display, _handle); - // inside this function _size is the size EXCLUDING the outer border - // at the end of this function it becomes the size INCLUDING the outer border - _size.left += bwidth; - _size.right += bwidth; - _size.top += bwidth; - _size.bottom += bwidth; + XResizeWindow(**otk::display, _frame, geom.width, + (_client->shaded() ? geom.title_height() : + _innersize.top + _innersize.bottom + + _client->area().height())); + + // do this in two steps because clients whose gravity is set to + // 'Static' don't end up getting moved at all with an XMoveResizeWindow + XMoveWindow(**otk::display, _plate, _innersize.left - geom.cbwidth, + _innersize.top - geom.cbwidth); + XResizeWindow(**otk::display, _plate, _client->area().width(), + _client->area().height()); + + _size.left = _innersize.left + geom.bwidth; + _size.right = _innersize.right + geom.bwidth; + _size.top = _innersize.top + geom.bwidth; + _size.bottom = _innersize.bottom + geom.bwidth; + + _area = otk::Rect(_area.position(), otk::Size(_client->area().width() + + _size.left + _size.right, + _client->area().height() + + _size.top + _size.bottom)); + + // render all the elements + int screen = _client->screen(); + bool focus = _client->focused(); + if (decorations & Client::Decor_Titlebar) { + render(screen, otk::Size(geom.width, geom.title_height()), _title, + &_title_sur, *(focus ? style->titlebarFocusBackground() : + style->titlebarUnfocusBackground())); + + renderLabel(); + } - // XXX: more is gunna have to happen here + if (decorations & Client::Decor_Handle) { + render(screen, otk::Size(geom.width, geom.handle_height), _handle, + &_handle_sur, *(focus ? style->handleFocusBackground() : + style->handleUnfocusBackground())); + render(screen, otk::Size(geom.grip_width(), geom.handle_height), _lgrip, + &_grip_sur, *(focus ? style->gripFocusBackground() : + style->gripUnfocusBackground())); + XSetWindowBackgroundPixmap(**otk::display, _rgrip, _grip_sur->pixmap()); + XClearWindow(**otk::display, _rgrip); + } + XSetWindowBorder(**otk::display, _plate, + focus ? style->clientBorderFocusColor()->pixel() : + style->clientBorderUnfocusColor()->pixel()); + adjustShape(); +} - update(); +void Frame::renderLabel() +{ + const otk::RenderStyle *style = otk::RenderStyle::style(_client->screen()); + const otk::RenderControl *control = + otk::display->renderControl(_client->screen()); + const otk::Font *font = style->labelFont(); + + otk::Surface *s = new otk::Surface(_client->screen(), + otk::Size(geom.label_width, + geom.label_height())); + control->drawBackground(*s, *(_client->focused() ? + style->labelFocusBackground() : + style->labelUnfocusBackground())); + + otk::ustring t = _client->title(); // the actual text to draw + int x = geom.bevel; // x coord for the text + + if ((unsigned)x * 2 > geom.label_width) return; // no room at all + + // find a string that will fit inside the area for text + otk::ustring::size_type text_len = t.size(); + unsigned int length; + unsigned int maxsize = geom.label_width - geom.bevel * 2; + + do { + t.resize(text_len); + length = font->measureString(t); + } while (length > maxsize && text_len-- > 0); + + if (text_len <= 0) return; // won't fit anything + + // justify the text + switch (style->labelTextJustify()) { + case otk::RenderStyle::RightBottomJustify: + x += maxsize - length; + break; + case otk::RenderStyle::CenterJustify: + x += (maxsize - length) / 2; + break; + case otk::RenderStyle::LeftTopJustify: + break; + } + + control->drawString(*s, *font, x, 0, + *(_client->focused() ? style->textFocusColor() : + style->textUnfocusColor()), t); + + XSetWindowBackgroundPixmap(**otk::display, _label, s->pixmap()); + XClearWindow(**otk::display, _label); + if (_label_sur) delete _label_sur; + _label_sur = s; } +void Frame::layoutTitle() +{ + geom.label_width = geom.width - geom.bevel * 2; + if (geom.label_width < 1) geom.label_width = 1; + XMoveResizeWindow(**otk::display, _label, geom.bevel, geom.bevel, + geom.label_width, geom.font_height); +} -void OBFrame::adjustShape() +void Frame::adjustPosition() +{ + int x, y; + x = _client->area().x(); + y = _client->area().y(); + clientGravity(x, y); + XMoveWindow(**otk::display, _frame, x, y); + _area = otk::Rect(otk::Point(x, y), _area.size()); +} + + +void Frame::adjustShape() { #ifdef SHAPE + Client::DecorationFlags decorations = _client->decorations(); + if (!_client->shaped()) { // clear the shape on the frame window - XShapeCombineMask(otk::OBDisplay::display, getWindow(), ShapeBounding, - _size.left, - _size.top, + XShapeCombineMask(**otk::display, _frame, ShapeBounding, + _innersize.left, + _innersize.top, None, ShapeSet); } else { // make the frame's shape match the clients - XShapeCombineShape(otk::OBDisplay::display, getWindow(), ShapeBounding, - _size.left, - _size.top, + XShapeCombineShape(**otk::display, _frame, ShapeBounding, + _innersize.left, + _innersize.top, _client->window(), ShapeBounding, ShapeSet); - int num = 0; + int num = 0; XRectangle xrect[2]; - /* - if (decorations & Decor_Titlebar) { - xrect[0].x = xrect[0].y = -frame.border_w; - xrect[0].width = frame.rect.width(); - xrect[0].height = frame.title_h + (frame.border_w * 2); - ++num; + if (decorations & Client::Decor_Titlebar) { + xrect[0].x = -geom.bevel; + xrect[0].y = -geom.bevel; + xrect[0].width = geom.width + geom.bwidth * 2; + xrect[0].height = geom.title_height() + geom.bwidth * 2; + ++num; } - if (decorations & Decor_Handle) { - xrect[1].x = -frame.border_w; - xrect[1].y = frame.rect.height() - frame.margin.bottom + - frame.mwm_border_w - frame.border_w; - xrect[1].width = frame.rect.width(); - xrect[1].height = frame.handle_h + (frame.border_w * 2); - ++num; - }*/ + if (decorations & Client::Decor_Handle) { + xrect[1].x = -geom.bevel; + xrect[1].y = geom.handle_y; + xrect[1].width = geom.width + geom.bwidth * 2; + xrect[1].height = geom.handle_height + geom.bwidth * 2; + ++num; + } - XShapeCombineRectangles(otk::OBDisplay::display, getWindow(), + XShapeCombineRectangles(**otk::display, _frame, ShapeBounding, 0, 0, xrect, num, ShapeUnion, Unsorted); } @@ -347,106 +450,162 @@ void OBFrame::adjustShape() } -void OBFrame::grabClient() +void Frame::adjustState() { - - // select the event mask on the frame - //XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask); +// XXX _button_alldesk.update(); +// XXX _button_max.update(); +} + +void Frame::grabClient() +{ // reparent the client to the frame - XReparentWindow(otk::OBDisplay::display, _client->window(), - _plate.getWindow(), 0, 0); - _client->ignore_unmaps++; + XReparentWindow(**otk::display, _client->window(), _plate, 0, 0); + /* + When reparenting the client window, it is usually not mapped yet, since + this occurs from a MapRequest. However, in the case where Openbox is + starting up, the window is already mapped, so we'll see unmap events for + it. There are 2 unmap events generated that we see, one with the 'event' + member set the root window, and one set to the client, but both get handled + and need to be ignored. + */ + if (openbox->state() == Openbox::State_Starting) + _client->ignore_unmaps += 2; + + // select the event mask on the client's parent (to receive config/map req's) + XSelectInput(**otk::display, _plate, SubstructureRedirectMask); - // raise the client above the frame - //XRaiseWindow(otk::OBDisplay::display, _client->window()); // map the client so it maps when the frame does - XMapWindow(otk::OBDisplay::display, _client->window()); + XMapWindow(**otk::display, _client->window()); - adjust(); - applyGravity(); + adjustSize(); + adjustPosition(); } -void OBFrame::releaseClient(bool remap) +void Frame::releaseClient() { - // check if the app has already reparented its window to the root window XEvent ev; - if (XCheckTypedWindowEvent(otk::OBDisplay::display, _client->window(), + + // check if the app has already reparented its window away + if (XCheckTypedWindowEvent(**otk::display, _client->window(), ReparentNotify, &ev)) { - remap = true; // XXX: why do we remap the window if they already - // reparented to root? + XPutBackEvent(**otk::display, &ev); + // re-map the window since the unmanaging process unmaps it + XMapWindow(**otk::display, _client->window()); } else { - // according to the ICCCM - if the client doesn't reparent to - // root, then we have to do it for them - XReparentWindow(otk::OBDisplay::display, _client->window(), - _screen->getRootWindow(), + // according to the ICCCM - if the client doesn't reparent itself, then we + // will reparent the window to root for them + XReparentWindow(**otk::display, _client->window(), + otk::display->screenInfo(_client->screen())->rootWindow(), _client->area().x(), _client->area().y()); } - - // if we want to remap the window, do so now - if (remap) - XMapWindow(otk::OBDisplay::display, _client->window()); } -void OBFrame::applyGravity() +void Frame::clientGravity(int &x, int &y) { - int x, y; - // apply horizontal window gravity + // horizontal switch (_client->gravity()) { default: case NorthWestGravity: case SouthWestGravity: case WestGravity: - x = _client->area().x(); break; case NorthGravity: case SouthGravity: case CenterGravity: - x = _client->area().x() - (_size.left + _size.right) / 2; + x -= (_size.left + _size.right) / 2; break; case NorthEastGravity: case SouthEastGravity: case EastGravity: - x = _client->area().x() - _size.left - _size.right + 2; + x -= _size.left + _size.right; break; case ForgetGravity: case StaticGravity: - x = _client->area().x() - _size.left; + x -= _size.left; break; } - // apply vertical window gravity + // vertical switch (_client->gravity()) { default: case NorthWestGravity: case NorthEastGravity: case NorthGravity: - y = _client->area().y(); break; case CenterGravity: case EastGravity: case WestGravity: - y = _client->area().y() - (_size.top + _size.bottom) / 2; + y -= (_size.top + _size.bottom) / 2; break; case SouthWestGravity: case SouthEastGravity: case SouthGravity: - y = _client->area().y() - _size.top - _size.bottom + 2; + y -= _size.top + _size.bottom; break; case ForgetGravity: case StaticGravity: - y = _client->area().y() - _size.top; + y -= _size.top; + break; + } +} + + +void Frame::frameGravity(int &x, int &y) +{ + // horizontal + switch (_client->gravity()) { + default: + case NorthWestGravity: + case WestGravity: + case SouthWestGravity: + break; + case NorthGravity: + case CenterGravity: + case SouthGravity: + x += (_size.left + _size.right) / 2; + break; + case NorthEastGravity: + case EastGravity: + case SouthEastGravity: + x += _size.left + _size.right; + break; + case StaticGravity: + case ForgetGravity: + x += _size.left; + break; + } + + // vertical + switch (_client->gravity()) { + default: + case NorthWestGravity: + case WestGravity: + case SouthWestGravity: + break; + case NorthGravity: + case CenterGravity: + case SouthGravity: + y += (_size.top + _size.bottom) / 2; + break; + case NorthEastGravity: + case EastGravity: + case SouthEastGravity: + y += _size.top + _size.bottom; + break; + case StaticGravity: + case ForgetGravity: + y += _size.top; break; } - move(x, y); }