X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=otk%2Fwidget.cc;h=1a0c7d9ea40828b9a81daddb5e54f6b0d2bd38e8;hb=a91a6f97daeb058f346246081e1c83a788787f9b;hp=8ab57708f276981e9907f101ca9fa43087b7f1df;hpb=ef231de58a738c83bf505e184fbafa9077f7452e;p=chaz%2Fopenbox diff --git a/otk/widget.cc b/otk/widget.cc index 8ab57708..1a0c7d9e 100644 --- a/otk/widget.cc +++ b/otk/widget.cc @@ -26,7 +26,7 @@ Widget::Widget(int screen, EventDispatcher *ed, Direction direction, int bevel, ExposureMask | StructureNotifyMask), _alignment(RenderStyle::CenterJustify), _direction(direction), - _max_size(UINT_MAX, UINT_MAX), + _max_size(INT_MAX, INT_MAX), _visible(false), _bordercolor(0), _borderwidth(0), @@ -49,7 +49,7 @@ Widget::Widget(Widget *parent, Direction direction, int bevel) ExposureMask | StructureNotifyMask), _alignment(RenderStyle::CenterJustify), _direction(direction), - _max_size(UINT_MAX, UINT_MAX), + _max_size(INT_MAX, INT_MAX), _visible(false), _bordercolor(0), _borderwidth(0), @@ -63,6 +63,7 @@ Widget::Widget(Widget *parent, Direction direction, int bevel) parent->addChild(this); if (parent->visible()) parent->layout(); _dispatcher->registerHandler(_window, this); + styleChanged(*RenderStyle::style(_screen)); } Widget::~Widget() @@ -85,6 +86,8 @@ void Widget::show(bool children) } } if (!_visible) { + if (_parent) _parent->calcDefaultSizes(); + else resize(_area.size()); // constrain sizes _visible = true; XMapWindow(**display, _window); update(); @@ -96,7 +99,10 @@ void Widget::hide() if (_visible) { _visible = false; XUnmapWindow(**display, _window); - if (_parent) _parent->layout(); + if (_parent) { + _parent->calcDefaultSizes(); + _parent->layout(); + } } } @@ -110,9 +116,10 @@ void Widget::update() { if (!_visible) return; _dirty = true; - if (parent()) - parent()->layout(); // relay-out us and our siblings - else { + if (_parent) { + _parent->calcDefaultSizes(); + _parent->layout(); // relay-out us and our siblings + } else { render(); layout(); } @@ -120,29 +127,36 @@ void Widget::update() void Widget::moveresize(const Rect &r) { - unsigned int w, h; - w = std::min(std::max(r.width(), minSize().width()), maxSize().width()); - h = std::min(std::max(r.height(), minSize().height()), maxSize().height()); + int w, h; + w = std::max(std::min(r.width(), maxSize().width()), minSize().width()); + h = std::max(std::min(r.height(), maxSize().height()), minSize().height()); - if (r.x() == area().x() && r.y() == area().y() && - w == area().width() && h == area().height()) { + bool sizechange = !(w == area().width() && h == area().height()); + + if (r.x() == area().x() && r.y() == area().y() && !sizechange) return; // no change, don't cause a big layout chain to occur! - } internal_moveresize(r.x(), r.y(), w, h); - update(); + if (sizechange) + update(); } -void Widget::internal_moveresize(int x, int y, unsigned w, unsigned int h) +void Widget::internal_moveresize(int x, int y, int w, int h) { assert(w > 0); assert(h > 0); assert(_borderwidth >= 0); _dirty = true; - XMoveResizeWindow(**display, _window, x, y, - w - _borderwidth * 2, - h - _borderwidth * 2); + if (!(x == _area.x() && y == _area.y())) { + if (!(w == _area.width() && h == _area.height())) + XMoveResizeWindow(**display, _window, x, y, + w - _borderwidth * 2, + h - _borderwidth * 2); + else + XMoveWindow(**display, _window, x, y); + } else + XResizeWindow(**display, _window, w - _borderwidth*2, h - _borderwidth*2); _ignore_config++; _area = Rect(x, y, w, h); @@ -185,6 +199,50 @@ void Widget::createWindow(bool overrideredir) ++_ignore_config; } +void Widget::calcDefaultSizes() +{ + std::list::const_iterator it, end = _children.end(); + int min_biggest = 0, max_biggest = 0; + int min_sum = _bevel + _borderwidth * 2; + int max_sum = _bevel + _borderwidth * 2; + bool fullmax = false; + + for (it = _children.begin(); it != end; ++it) { + const otk::Size &min = (*it)->minSize(); + const otk::Size &max = (*it)->maxSize(); + if (_direction == Horizontal) { + if (min.height() > min_biggest) min_biggest = min.height(); + if (max.height() > max_biggest) max_biggest = max.height(); + min_sum += _bevel + min.width(); + if (max.width() == INT_MAX) + fullmax = true; + else if (!fullmax) + max_sum += _bevel + max.width(); + } else { + if (min.width() > min_biggest) min_biggest = min.width(); + if (max.width() > max_biggest) max_biggest = max.width(); + min_sum += _bevel + min.height(); + if (max.height() == INT_MAX) + fullmax = true; + else if (!fullmax) + max_sum += _bevel + max.height(); + } + } + if (_direction == Horizontal) { + _min_size = otk::Size(min_sum + (_bevel + _borderwidth) * 2, + min_biggest + (_bevel + _borderwidth) * 2); + _max_size = otk::Size((fullmax ? INT_MAX : + max_sum + (_bevel + _borderwidth) * 2), + max_biggest); + } else { + _min_size = otk::Size(min_biggest + (_bevel + _borderwidth) * 2, + min_sum + (_bevel + _borderwidth) * 2); + _max_size = otk::Size(max_biggest, (fullmax ? INT_MAX : max_sum + + (_bevel + _borderwidth) * 2)); + } + update(); +} + void Widget::setBorderWidth(int w) { assert(w >= 0); @@ -238,39 +296,31 @@ void Widget::layoutHorz() std::list::iterator it, end; // work with just the visible children - std::list visible = _children; - for (it = visible.begin(), end = visible.end(); it != end;) { - std::list::iterator next = it; ++next; - if (!(*it)->visible()) - visible.erase(it); - it = next; - } + std::list visible; + for (it = _children.begin(), end = _children.end(); it != end; ++it) + if ((*it)->visible()) + visible.push_back(*it); if (visible.empty()) return; - if ((unsigned)(_borderwidth * 2 + _bevel * 2) > _area.width() || - (unsigned)(_borderwidth * 2 + _bevel * 2) > _area.height()) - return; // not worth laying anything out! - - int x, y; unsigned int w, h; // working area + int x, y, w, h; // working area x = y = _bevel; w = _area.width() - _borderwidth * 2 - _bevel * 2; h = _area.height() - _borderwidth * 2 - _bevel * 2; + if (w < 0 || h < 0) return; // not worth laying anything out! int free = w - (visible.size() - 1) * _bevel; if (free < 0) free = 0; - unsigned int each; + int each; - std::list adjustable = visible; + std::list adjustable; // find the 'free' space, and how many children will be using it - for (it = adjustable.begin(), end = adjustable.end(); it != end;) { - std::list::iterator next = it; ++next; + for (it = visible.begin(), end = visible.end(); it != end; ++it) { free -= (*it)->minSize().width(); if (free < 0) free = 0; - if ((*it)->maxSize().width() - (*it)->minSize().width() <= 0) - adjustable.erase(it); - it = next; + if ((*it)->maxSize().width() - (*it)->minSize().width() > 0) + adjustable.push_back(*it); } // some widgets may have max widths that restrict them, find the 'true' // amount of free space after these widgets are not included @@ -279,7 +329,7 @@ void Widget::layoutHorz() each = free / adjustable.size(); for (it = adjustable.begin(), end = adjustable.end(); it != end;) { std::list::iterator next = it; ++next; - unsigned int m = (*it)->maxSize().width() - (*it)->minSize().width(); + int m = (*it)->maxSize().width() - (*it)->minSize().width(); if (m > 0 && m < each) { free -= m; if (free < 0) free = 0; @@ -298,7 +348,7 @@ void Widget::layoutHorz() else each = 0; for (it = visible.begin(), end = visible.end(); it != end; ++it) { - unsigned int w; + int w; // is the widget adjustable? std::list::const_iterator found = std::find(adjustable.begin(), adjustable.end(), *it); @@ -311,8 +361,8 @@ void Widget::layoutHorz() } // align it vertically int yy = y; - unsigned int hh = std::max(std::min(h, (*it)->_max_size.height()), - (*it)->_min_size.height()); + int hh = std::max(std::min(h, (*it)->_max_size.height()), + (*it)->_min_size.height()); if (hh < h) { switch(_alignment) { case RenderStyle::RightBottomJustify: @@ -337,39 +387,31 @@ void Widget::layoutVert() std::list::iterator it, end; // work with just the visible children - std::list visible = _children; - for (it = visible.begin(), end = visible.end(); it != end;) { - std::list::iterator next = it; ++next; - if (!(*it)->visible()) - visible.erase(it); - it = next; - } + std::list visible; + for (it = _children.begin(), end = _children.end(); it != end; ++it) + if ((*it)->visible()) + visible.push_back(*it); if (visible.empty()) return; - if ((unsigned)(_borderwidth * 2 + _bevel * 2) > _area.width() || - (unsigned)(_borderwidth * 2 + _bevel * 2) > _area.height()) - return; // not worth laying anything out! - - int x, y; unsigned int w, h; // working area + int x, y, w, h; // working area x = y = _bevel; w = _area.width() - _borderwidth * 2 - _bevel * 2; h = _area.height() - _borderwidth * 2 - _bevel * 2; + if (w < 0 || h < 0) return; // not worth laying anything out! int free = h - (visible.size() - 1) * _bevel; if (free < 0) free = 0; - unsigned int each; + int each; - std::list adjustable = visible; + std::list adjustable; // find the 'free' space, and how many children will be using it - for (it = adjustable.begin(), end = adjustable.end(); it != end;) { - std::list::iterator next = it; ++next; + for (it = visible.begin(), end = visible.end(); it != end; ++it) { free -= (*it)->minSize().height(); if (free < 0) free = 0; - if ((*it)->maxSize().height() - (*it)->minSize().height() <= 0) - adjustable.erase(it); - it = next; + if ((*it)->maxSize().height() - (*it)->minSize().height() > 0) + adjustable.push_back(*it); } // some widgets may have max heights that restrict them, find the 'true' // amount of free space after these widgets are not included @@ -378,7 +420,7 @@ void Widget::layoutVert() each = free / adjustable.size(); for (it = adjustable.begin(), end = adjustable.end(); it != end;) { std::list::iterator next = it; ++next; - unsigned int m = (*it)->maxSize().height() - (*it)->minSize().height(); + int m = (*it)->maxSize().height() - (*it)->minSize().height(); if (m > 0 && m < each) { free -= m; if (free < 0) free = 0; @@ -393,11 +435,11 @@ void Widget::layoutVert() // place/size the widgets if (!adjustable.empty()) - each = free / adjustable.size(); + each = free / adjustable.size(); else each = 0; for (it = visible.begin(), end = visible.end(); it != end; ++it) { - unsigned int h; + int h; // is the widget adjustable? std::list::const_iterator found = std::find(adjustable.begin(), adjustable.end(), *it); @@ -410,8 +452,8 @@ void Widget::layoutVert() } // align it horizontally int xx = x; - unsigned int ww = std::max(std::min(w, (*it)->_max_size.width()), - (*it)->_min_size.width()); + int ww = std::max(std::min(w, (*it)->_max_size.width()), + (*it)->_min_size.width()); if (ww < w) { switch(_alignment) { case RenderStyle::RightBottomJustify: @@ -433,9 +475,16 @@ void Widget::layoutVert() void Widget::render() { - if (!_texture || !_dirty) return; - if ((unsigned)_borderwidth * 2 > _area.width() || - (unsigned)_borderwidth * 2 > _area.height()) + if (!_dirty) return; + if (!_texture) { + // set a solid color as the default background + XSetWindowBackground(**display, _window, + RenderStyle::style(_screen)-> + titlebarUnfocusBackground()->color().pixel()); + return; + } + if (_borderwidth * 2 > _area.width() || + _borderwidth * 2 > _area.height()) return; // no surface to draw on Surface *s = new Surface(_screen, Size(_area.width() - _borderwidth * 2, @@ -450,6 +499,7 @@ void Widget::render() // delete the old surface *after* its pixmap isn't in use anymore if (_surface) delete _surface; + s->freePixelData(); // done rendering with this surface _surface = s; _dirty = false; @@ -462,6 +512,11 @@ void Widget::renderChildren() (*it)->render(); } +void Widget::styleChanged(const RenderStyle &) +{ + refresh(); +} + void Widget::exposeHandler(const XExposeEvent &e) { EventHandler::exposeHandler(e); @@ -475,14 +530,14 @@ void Widget::configureHandler(const XConfigureEvent &e) } else { // only interested in these for top level windows if (_parent) return; - + XEvent ev; ev.xconfigure.width = e.width; ev.xconfigure.height = e.height; while (XCheckTypedWindowEvent(**display, window(), ConfigureNotify, &ev)); - if (!((unsigned)ev.xconfigure.width == area().width() && - (unsigned)ev.xconfigure.height == area().height())) { + if (!(ev.xconfigure.width == area().width() && + ev.xconfigure.height == area().height())) { _area = Rect(_area.position(), Size(e.width, e.height)); update(); }