X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fframe.cc;h=4f466b46d26edbaf053bfc0cae138102cc36e701;hb=b8653c3ab8ee785fc0605a960ac83afb97ac7edf;hp=bb8a74f57064a9fbce6be05d034c7158fba71a4c;hpb=fb3848450e649a05c0bed84a02bc9ab4e563b5d9;p=chaz%2Fopenbox diff --git a/src/frame.cc b/src/frame.cc index bb8a74f5..4f466b46 100644 --- a/src/frame.cc +++ b/src/frame.cc @@ -16,48 +16,45 @@ extern "C" { #include "otk/display.hh" #include -#include // TEMP namespace ob { +const long OBFrame::event_mask; + OBFrame::OBFrame(OBClient *client, otk::Style *style) : otk::OtkWidget(Openbox::instance, style), + OBWidget(Type_Frame), _client(client), _screen(otk::OBDisplay::screenInfo(client->screen())), - _titlebar(this), - _button_close(&_titlebar), - _button_iconify(&_titlebar), - _button_max(&_titlebar), - _button_stick(&_titlebar), - _label(&_titlebar), - _handle(this), - _grip_left(&_handle), - _grip_right(&_handle), + _plate(this, OBWidget::Type_Plate), + _titlebar(this, OBWidget::Type_Titlebar), + _button_close(&_titlebar, OBWidget::Type_CloseButton), + _button_iconify(&_titlebar, OBWidget::Type_IconifyButton), + _button_max(&_titlebar, OBWidget::Type_MaximizeButton), + _button_stick(&_titlebar, OBWidget::Type_StickyButton), + _label(&_titlebar, OBWidget::Type_Label), + _handle(this, OBWidget::Type_Handle), + _grip_left(&_handle, OBWidget::Type_LeftGrip), + _grip_right(&_handle, OBWidget::Type_RightGrip), _decorations(client->decorations()) { 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(); - - _button_close.setText("X"); - _button_iconify.setText("I"); - _button_max.setText("M"); - _button_stick.setText("C"); + XSelectInput(otk::OBDisplay::display, window(), OBFrame::event_mask); + + _grip_left.setCursor(Openbox::instance->cursors().ll_angle); + _grip_right.setCursor(Openbox::instance->cursors().lr_angle); + _label.setText(_client->title()); _style = 0; setStyle(style); + otk::OtkWidget::unfocus(); // stuff starts out appearing focused in otk + + _plate.show(); // the other stuff is shown based on decor settings + grabClient(); } @@ -68,6 +65,13 @@ OBFrame::~OBFrame() } +void OBFrame::setTitle(const std::string &text) +{ + _label.setText(text); + _label.update(); +} + + void OBFrame::setStyle(otk::Style *style) { assert(style); @@ -80,95 +84,100 @@ void OBFrame::setStyle(otk::Style *style) if (replace) { // XXX: do shit here whatever - // XXX: save the position based on gravity } _style = style; - 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()); - - // XXX: if (focused) - XSetWindowBackground(otk::OBDisplay::display, getWindow(), - _style->getFrameFocus()->color().pixel()); - // XXX: else - // XXX: XSetWindowBackground(otk::OBDisplay::display, _window, - // XXX: _style->getFrameUnfocus().color().pixel()); + setBorderColor(_style->getBorderColor()); // if !replace, then adjust() will get called after the client is grabbed! - if (replace) - adjust(); // size/position everything + if (replace) { + // size/position everything + adjustSize(); + adjustPosition(); + } +} + + +void OBFrame::focus() +{ + otk::OtkWidget::focus(); + update(); + _handle.update(); +} + + +void OBFrame::unfocus() +{ + otk::OtkWidget::unfocus(); + update(); } void OBFrame::adjust() +{ + // the party all happens in adjustSize +} + + +void OBFrame::adjustSize() { // XXX: only if not overridden or something!!! MORE LOGIC HERE!! _decorations = _client->decorations(); _decorations = 0xffffffff; - int width; // the width of the client window and the border around it + int width; // the width of the client and its border int bwidth; // width to make borders + int cbwidth; // width of the inner client border + const int bevel = _style->getBevelWidth(); if (_decorations & OBClient::Decor_Border) { bwidth = _style->getBorderWidth(); - _size.left = _size.top = _size.bottom = _size.right = - _style->getFrameWidth(); - width = _client->area().width() + _style->getFrameWidth() * 2; - } else { - bwidth = 0; - _size.left = _size.top = _size.bottom = _size.right = 0; - width = _client->area().width(); - } - 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); - + cbwidth = _style->getFrameWidth(); + } else + bwidth = cbwidth = 0; + _innersize.left = _innersize.top = _innersize.bottom = _innersize.right = + cbwidth; + width = _client->area().width() + cbwidth * 2; + + _plate.setBorderWidth(cbwidth); + + setBorderWidth(bwidth); + _titlebar.setBorderWidth(bwidth); + _grip_left.setBorderWidth(bwidth); + _grip_right.setBorderWidth(bwidth); + _handle.setBorderWidth(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; + _style->getFont()->height() + bevel * 2); + _innersize.top += _titlebar.height() + bwidth; // set the label size - _label.setGeometry(0, _style->getBevelWidth(), - width, _style->getFont().height()); + _label.setGeometry(0, bevel, width, _style->getFont()->height()); // set the buttons sizes if (_decorations & OBClient::Decor_Iconify) - _button_iconify.setGeometry(0, _style->getBevelWidth() + 1, + _button_iconify.setGeometry(0, bevel + 1, _label.height() - 2, _label.height() - 2); if (_decorations & OBClient::Decor_Maximize) - _button_max.setGeometry(0, _style->getBevelWidth() + 1, + _button_max.setGeometry(0, bevel + 1, _label.height() - 2, _label.height() - 2); if (_decorations & OBClient::Decor_Sticky) - _button_stick.setGeometry(0, _style->getBevelWidth() + 1, + _button_stick.setGeometry(0, bevel + 1, _label.height() - 2, _label.height() - 2); if (_decorations & OBClient::Decor_Close) - _button_close.setGeometry(0, _style->getBevelWidth() + 1, + _button_close.setGeometry(0, bevel + 1, _label.height() - 2, _label.height() - 2); // separation between titlebar elements - const int sep = _style->getBevelWidth() + 1; + const int sep = bevel + 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 @@ -179,31 +188,35 @@ void OBFrame::adjust() // 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(_label.width() - - ((_button_iconify.width() + sep) * - (layout.size() - 1) + sep * 2)); + int lwidth = width - sep * 2 - + (_button_iconify.width() + sep) * (layout.size() - 1); + // quick sanity check for really small windows. if this is needed, its + // obviously not going to be displayed right... + // XXX: maybe we should make this look better somehow? constraints? + if (lwidth <= 0) lwidth = 1; + _label.setWidth(lwidth); 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()); + _button_iconify.move(x, _button_iconify.rect().y()); x += _button_iconify.width(); break; case 'L': - _label.move(x, _label.getRect().y()); + _label.move(x, _label.rect().y()); x += _label.width(); break; case 'M': - _button_max.move(x, _button_max.getRect().y()); + _button_max.move(x, _button_max.rect().y()); x += _button_max.width(); break; case 'S': - _button_stick.move(x, _button_stick.getRect().y()); + _button_stick.move(x, _button_stick.rect().y()); x += _button_stick.width(); break; case 'C': - _button_close.move(x, _button_close.getRect().y()); + _button_close.move(x, _button_close.rect().y()); x += _button_close.width(); break; default: @@ -215,8 +228,7 @@ void OBFrame::adjust() if (_decorations & OBClient::Decor_Handle) { _handle.setGeometry(-bwidth, - _size.top + _client->area().height() + - _style->getFrameWidth(), + _innersize.top + _client->area().height() + cbwidth, width, _style->getHandleWidth()); _grip_left.setGeometry(-bwidth, -bwidth, @@ -224,24 +236,24 @@ void OBFrame::adjust() // the 'buttons size' since theyre all the same _button_iconify.width() * 2, _handle.height()); - _grip_right.setGeometry(((_handle.getRect().right() + 1) - + _grip_right.setGeometry(((_handle.rect().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; + _innersize.bottom += _handle.height() + bwidth; } // position/size all the windows - resize(_size.left + _size.right + _client->area().width(), - _size.top + _size.bottom + _client->area().height()); + resize(_innersize.left + _innersize.right + _client->area().width(), + _innersize.top + _innersize.bottom + _client->area().height()); - XMoveWindow(otk::OBDisplay::display, _client->window(), - _size.left, _size.top); + _plate.setGeometry(_innersize.left - cbwidth, _innersize.top - cbwidth, + _client->area().width(), _client->area().height()); // map/unmap all the windows if (_decorations & OBClient::Decor_Titlebar) { @@ -272,7 +284,10 @@ void OBFrame::adjust() else _handle.hide(true); - // XXX: more is gunna have to happen here + _size.left = _innersize.left + bwidth; + _size.right = _innersize.right + bwidth; + _size.top = _innersize.top + bwidth; + _size.bottom = _innersize.bottom + bwidth; adjustShape(); @@ -280,43 +295,53 @@ void OBFrame::adjust() } +void OBFrame::adjustPosition() +{ + int x, y; + clientGravity(x, y); + move(x, y); +} + + void OBFrame::adjustShape() { #ifdef SHAPE + int bwidth = (_decorations & OBClient::Decor_Border) ? + _style->getBorderWidth() : 0; + if (!_client->shaped()) { // clear the shape on the frame window - XShapeCombineMask(otk::OBDisplay::display, getWindow(), ShapeBounding, - _size.left, - _size.top, + XShapeCombineMask(otk::OBDisplay::display, window(), 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::OBDisplay::display, window(), 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 & OBClient::Decor_Titlebar) { + xrect[0].x = _titlebar.rect().x(); + xrect[0].y = _titlebar.rect().y(); + xrect[0].width = _titlebar.width() + bwidth * 2; // XXX: this is useless once the widget handles borders! + xrect[0].height = _titlebar.height() + 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 & OBClient::Decor_Handle) { + xrect[1].x = _handle.rect().x(); + xrect[1].y = _handle.rect().y(); + xrect[1].width = _handle.width() + bwidth * 2; // XXX: this is useless once the widget handles borders! + xrect[1].height = _handle.height() + bwidth * 2; + ++num; + } - XShapeCombineRectangles(otk::OBDisplay::display, getWindow(), + XShapeCombineRectangles(otk::OBDisplay::display, window(), ShapeBounding, 0, 0, xrect, num, ShapeUnion, Unsorted); } @@ -327,19 +352,20 @@ void OBFrame::adjustShape() void OBFrame::grabClient() { - // select the event mask on the frame - //XSelectInput(otk::OBDisplay::display, _window, SubstructureRedirectMask); - // reparent the client to the frame - XReparentWindow(otk::OBDisplay::display, _client->window(), getWindow(), 0, 0); + XReparentWindow(otk::OBDisplay::display, _client->window(), + _plate.window(), 0, 0); _client->ignore_unmaps++; - // raise the client above the frame - //XRaiseWindow(otk::OBDisplay::display, _client->window()); + // select the event mask on the client's parent (to receive config req's) + XSelectInput(otk::OBDisplay::display, _plate.window(), + SubstructureRedirectMask); + // map the client so it maps when the frame does XMapWindow(otk::OBDisplay::display, _client->window()); - - adjust(); + + adjustSize(); + adjustPosition(); } @@ -355,7 +381,7 @@ void OBFrame::releaseClient(bool remap) // 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(), + _screen->rootWindow(), _client->area().x(), _client->area().y()); } @@ -365,47 +391,116 @@ void OBFrame::releaseClient(bool remap) } -Window OBFrame::createChild(Window parent, Cursor cursor) +void OBFrame::clientGravity(int &x, int &y) { - XSetWindowAttributes attrib_create; - unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWEventMask; - - attrib_create.background_pixmap = None; - attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask | ExposureMask; - - if (cursor) { - create_mask |= CWCursor; - attrib_create.cursor = cursor; + x = _client->area().x(); + y = _client->area().y(); + + // horizontal + switch (_client->gravity()) { + default: + case NorthWestGravity: + case SouthWestGravity: + case WestGravity: + break; + + case NorthGravity: + case SouthGravity: + case CenterGravity: + x -= (_size.left + _size.right) / 2; + break; + + case NorthEastGravity: + case SouthEastGravity: + case EastGravity: + x -= _size.left + _size.right; + break; + + case ForgetGravity: + case StaticGravity: + x -= _size.left; + break; } - Window w = XCreateWindow(otk::OBDisplay::display, parent, 0, 0, 1, 1, 0, - _screen->getDepth(), InputOutput, - _screen->getVisual(), create_mask, &attrib_create); - return w; + // vertical + switch (_client->gravity()) { + default: + case NorthWestGravity: + case NorthEastGravity: + case NorthGravity: + break; + + case CenterGravity: + case EastGravity: + case WestGravity: + y -= (_size.top + _size.bottom) / 2; + break; + + case SouthWestGravity: + case SouthEastGravity: + case SouthGravity: + y -= _size.top + _size.bottom; + break; + + case ForgetGravity: + case StaticGravity: + y -= _size.top; + break; + } } -Window OBFrame::createFrame() +void OBFrame::frameGravity(int &x, int &y) { - XSetWindowAttributes attrib_create; - unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWColormap | - CWOverrideRedirect | CWEventMask; - - attrib_create.background_pixmap = None; - attrib_create.colormap = _screen->getColormap(); - attrib_create.override_redirect = True; - attrib_create.event_mask = EnterWindowMask | LeaveWindowMask | ButtonPress; - /* - We catch button presses because other wise they get passed down to the - root window, which will then cause root menus to show when you click the - window's frame. - */ - - return XCreateWindow(otk::OBDisplay::display, _screen->getRootWindow(), - 0, 0, 1, 1, 0, - _screen->getDepth(), InputOutput, _screen->getVisual(), - create_mask, &attrib_create); + x = rect().x(); + y = rect().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; + } } + }