X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=otk%2Fwidget.cc;h=1a0c7d9ea40828b9a81daddb5e54f6b0d2bd38e8;hb=b6ad10764e75923ecb55d3dce96415eb991c64ec;hp=c09ac4862566e8c8f93d0f4634ff6e7e33a15065;hpb=9e6b0d5a8d0226232802bdece77665b167f98dae;p=chaz%2Fopenbox diff --git a/otk/widget.cc b/otk/widget.cc index c09ac486..1a0c7d9e 100644 --- a/otk/widget.cc +++ b/otk/widget.cc @@ -1,508 +1,546 @@ // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*- -#ifdef HAVE_CONFIG_H -# include "../config.h" -#endif // HAVE_CONFIG_H - +#include "config.h" #include "widget.hh" #include "display.hh" -#include "assassin.hh" +#include "surface.hh" +#include "rendertexture.hh" +#include "rendercolor.hh" +#include "eventdispatcher.hh" #include "screeninfo.hh" -#include "focuslabel.hh" + +#include +#include #include -#include namespace otk { -Widget::Widget(Widget *parent, Direction direction) - : EventHandler(), - _dirty(false), _focused(false), - _parent(parent), _style(parent->style()), _direction(direction), - _cursor(parent->cursor()), _bevel_width(parent->bevelWidth()), - _ignore_config(0), - _visible(false), _grabbed_mouse(false), - _grabbed_keyboard(false), _stretchable_vert(false), - _stretchable_horz(false), _texture(0), _bg_pixmap(0), _bg_pixel(0), - _bcolor(0), _bwidth(0), _rect(0, 0, 1, 1), _screen(parent->screen()), - _fixed_width(false), _fixed_height(false), +Widget::Widget(int screen, EventDispatcher *ed, Direction direction, int bevel, + bool overrideredir) + : _texture(0), + _screen(screen), + _parent(0), + _window(0), + _surface(0), + _event_mask(ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | + ExposureMask | StructureNotifyMask), + _alignment(RenderStyle::CenterJustify), + _direction(direction), + _max_size(INT_MAX, INT_MAX), + _visible(false), + _bordercolor(0), + _borderwidth(0), + _bevel(bevel), + _dirty(true), + _dispatcher(ed), + _ignore_config(0) +{ + createWindow(overrideredir); + _dispatcher->registerHandler(_window, this); +} + +Widget::Widget(Widget *parent, Direction direction, int bevel) + : _texture(0), + _screen(parent->_screen), + _parent(parent), + _window(0), _surface(0), - _event_dispatcher(parent->eventDispatcher()) + _event_mask(ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | + ExposureMask | StructureNotifyMask), + _alignment(RenderStyle::CenterJustify), + _direction(direction), + _max_size(INT_MAX, INT_MAX), + _visible(false), + _bordercolor(0), + _borderwidth(0), + _bevel(bevel), + _dirty(true), + _dispatcher(parent->_dispatcher), + _ignore_config(0) { assert(parent); + createWindow(false); parent->addChild(this); - create(); - _event_dispatcher->registerHandler(_window, this); -} - -Widget::Widget(EventDispatcher *event_dispatcher, RenderStyle *style, - Direction direction, Cursor cursor, int bevel_width, - bool override_redirect) - : EventHandler(), - _dirty(false),_focused(false), - _parent(0), _style(style), _direction(direction), _cursor(cursor), - _bevel_width(bevel_width), _ignore_config(0), _visible(false), - _grabbed_mouse(false), _grabbed_keyboard(false), - _stretchable_vert(false), _stretchable_horz(false), _texture(0), - _bg_pixmap(0), _bg_pixel(0), _bcolor(0), _bwidth(0), _rect(0, 0, 1, 1), - _screen(style->screen()), _fixed_width(false), _fixed_height(false), - _surface(0), - _event_dispatcher(event_dispatcher) -{ - assert(event_dispatcher); - assert(style); - create(override_redirect); - _event_dispatcher->registerHandler(_window, this); + if (parent->visible()) parent->layout(); + _dispatcher->registerHandler(_window, this); + styleChanged(*RenderStyle::style(_screen)); } Widget::~Widget() { - if (_visible) - hide(); - - if (_surface) - delete _surface; + assert(_children.empty()); // this would be bad. theyd have a hanging _parent - _event_dispatcher->clearHandler(_window); - - std::for_each(_children.begin(), _children.end(), PointerAssassin()); - - if (_parent) - _parent->removeChild(this); + if (_surface) delete _surface; + if (_parent) _parent->removeChild(this); + _dispatcher->clearHandler(_window); XDestroyWindow(**display, _window); } -void Widget::create(bool override_redirect) +void Widget::show(bool children) { - const ScreenInfo *scr_info = display->screenInfo(_screen); - Window p_window = _parent ? _parent->window() : scr_info->rootWindow(); - - _rect.setRect(0, 0, 1, 1); // just some initial values - - XSetWindowAttributes attrib_create; - unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWEventMask; - - attrib_create.background_pixmap = None; - attrib_create.colormap = scr_info->colormap(); - attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask | ExposureMask | StructureNotifyMask; - - if (override_redirect) { - create_mask |= CWOverrideRedirect; - attrib_create.override_redirect = true; + if (children) { + std::list::iterator it , end = _children.end(); + for (it = _children.begin(); it != end; ++it) { + (*it)->show(true); + } } - - if (_cursor) { - create_mask |= CWCursor; - attrib_create.cursor = _cursor; + if (!_visible) { + if (_parent) _parent->calcDefaultSizes(); + else resize(_area.size()); // constrain sizes + _visible = true; + XMapWindow(**display, _window); + update(); } - - _window = XCreateWindow(**display, p_window, _rect.x(), - _rect.y(), _rect.width(), _rect.height(), 0, - scr_info->depth(), InputOutput, - scr_info->visual(), create_mask, &attrib_create); - _ignore_config++; } -void Widget::setWidth(int w) +void Widget::hide() { - assert(w > 0); - _fixed_width = true; - setGeometry(_rect.x(), _rect.y(), w, _rect.height()); -} + if (_visible) { + _visible = false; + XUnmapWindow(**display, _window); + if (_parent) { + _parent->calcDefaultSizes(); + _parent->layout(); + } + } +} -void Widget::setHeight(int h) +void Widget::setEventMask(long e) { - assert(h > 0); - _fixed_height = true; - setGeometry(_rect.x(), _rect.y(), _rect.width(), h); + XSelectInput(**display, _window, e); + _event_mask = e; } -void Widget::move(const Point &to) +void Widget::update() { - move(to.x(), to.y()); + if (!_visible) return; + _dirty = true; + if (_parent) { + _parent->calcDefaultSizes(); + _parent->layout(); // relay-out us and our siblings + } else { + render(); + layout(); + } } -void Widget::move(int x, int y) +void Widget::moveresize(const Rect &r) { - _rect.setPos(x, y); - XMoveWindow(**display, _window, x, y); - _ignore_config++; -} + 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()); -void Widget::resize(const Point &to) -{ - resize(to.x(), to.y()); -} + bool sizechange = !(w == area().width() && h == area().height()); -void Widget::resize(int w, int h) -{ - assert(w > 0 && h > 0); - _fixed_width = _fixed_height = true; - setGeometry(_rect.x(), _rect.y(), w, h); -} + 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); -void Widget::setGeometry(const Rect &new_geom) -{ - setGeometry(new_geom.x(), new_geom.y(), new_geom.width(), new_geom.height()); -} - -void Widget::setGeometry(const Point &topleft, int width, int height) -{ - setGeometry(topleft.x(), topleft.y(), width, height); + if (sizechange) + update(); } -void Widget::setGeometry(int x, int y, int width, int height) +void Widget::internal_moveresize(int x, int y, int w, int h) { - _rect = Rect(x, y, width, height); + assert(w > 0); + assert(h > 0); + assert(_borderwidth >= 0); _dirty = true; + 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++; - // make all parents dirty too - Widget *p = _parent; - while (p) { - p->_dirty = true; - p = p->_parent; - } - - // don't use an XMoveResizeWindow here, because it doesn't seem to move - // windows with StaticGravity? This works, that didn't. - XResizeWindow(**display, _window, width, height); - XMoveWindow(**display, _window, x, y); - _ignore_config+=2; + _area = Rect(x, y, w, h); } -void Widget::show(bool recursive) +void Widget::setAlignment(RenderStyle::Justify a) { - if (_visible) - return; - - // make sure the internal state isn't mangled - if (_dirty) - update(); - - if (recursive) { - WidgetList::iterator it = _children.begin(), end = _children.end(); - for (; it != end; ++it) - (*it)->show(recursive); - } - - XMapWindow(**display, _window); - _visible = true; + _alignment = a; + layout(); } - -void Widget::hide(bool recursive) + +void Widget::createWindow(bool overrideredir) { - if (! _visible) - return; + const ScreenInfo *info = display->screenInfo(_screen); + XSetWindowAttributes attrib; + unsigned long mask = CWEventMask | CWBorderPixel; - if (recursive) { - WidgetList::iterator it = _children.begin(), end = _children.end(); - for (; it != end; ++it) - (*it)->hide(); + attrib.event_mask = _event_mask; + attrib.border_pixel = (_bordercolor ? + _bordercolor->pixel(): + BlackPixel(**display, _screen)); + + if (overrideredir) { + mask |= CWOverrideRedirect; + attrib.override_redirect = true; } - XUnmapWindow(**display, _window); - _visible = false; -} + _window = XCreateWindow(**display, (_parent ? + _parent->_window : + RootWindow(**display, _screen)), + _area.x(), _area.y(), + _area.width(), _area.height(), + _borderwidth, + info->depth(), + InputOutput, + info->visual(), + mask, + &attrib); + assert(_window != None); + ++_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; -void Widget::focus(void) -{ - _focused = true; - - Widget::WidgetList::iterator it = _children.begin(), - end = _children.end(); - for (; it != end; ++it) - (*it)->focus(); + 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::unfocus(void) +void Widget::setBorderWidth(int w) { - _focused = false; + assert(w >= 0); + if (!parent()) return; // top-level windows cannot have borders + if (w == borderWidth()) return; // no change - Widget::WidgetList::iterator it = _children.begin(), - end = _children.end(); - for (; it != end; ++it) - (*it)->unfocus(); -} + _borderwidth = w; + XSetWindowBorderWidth(**display, _window, _borderwidth); -bool Widget::grabMouse(void) -{ - Status ret = XGrabPointer(**display, _window, True, - (ButtonPressMask | ButtonReleaseMask | - ButtonMotionMask | EnterWindowMask | - LeaveWindowMask | PointerMotionMask), - GrabModeSync, GrabModeAsync, None, None, - CurrentTime); - _grabbed_mouse = (ret == GrabSuccess); - return _grabbed_mouse; + calcDefaultSizes(); + update(); } -void Widget::ungrabMouse(void) +void Widget::setMinSize(const Size &s) { - if (! _grabbed_mouse) - return; - - XUngrabPointer(**display, CurrentTime); - _grabbed_mouse = false; + _min_size = s; + update(); } -bool Widget::grabKeyboard(void) +void Widget::setMaxSize(const Size &s) { - Status ret = XGrabKeyboard(**display, _window, True, - GrabModeSync, GrabModeAsync, CurrentTime); - _grabbed_keyboard = (ret == GrabSuccess); - return _grabbed_keyboard; - + _max_size = s; + update(); } -void Widget::ungrabKeyboard(void) +void Widget::setBorderColor(const RenderColor *c) { - if (! _grabbed_keyboard) - return; - - XUngrabKeyboard(**display, CurrentTime); - _grabbed_keyboard = false; + _bordercolor = c; + XSetWindowBorder(**otk::display, _window, + c ? c->pixel() : BlackPixel(**otk::display, _screen)); } -void Widget::render(void) +void Widget::setBevel(int b) { - if (!_texture) return; - - Surface *s = _surface; // save the current surface - - _surface = new Surface(_screen, _rect.size()); - display->renderControl(_screen)->drawBackground(*_surface, *_texture); - - renderForeground(); // for inherited types to render onto the _surface - - XSetWindowBackgroundPixmap(**display, _window, _surface->pixmap()); - - if (s) - delete s; // delete the old surface *after* its pixmap isn't in use anymore + _bevel = b; + calcDefaultSizes(); + layout(); } -void Widget::adjust(void) +void Widget::layout() { + if (_children.empty() || !_visible) return; if (_direction == Horizontal) - adjustHorz(); + layoutHorz(); else - adjustVert(); + layoutVert(); } -void Widget::adjustHorz(void) +void Widget::layoutHorz() { - if (_children.size() == 0) - return; + std::list::iterator it, end; - Widget *tmp; - WidgetList::iterator it, end = _children.end(); + // work with just the visible children + std::list visible; + for (it = _children.begin(), end = _children.end(); it != end; ++it) + if ((*it)->visible()) + visible.push_back(*it); - int tallest = 0; - int width = _bevel_width; - WidgetList stretchable; + if (visible.empty()) return; - for (it = _children.begin(); it != end; ++it) { - tmp = *it; - if (tmp->isStretchableVert()) - tmp->setHeight(_rect.height() > _bevel_width * 2 ? - _rect.height() - _bevel_width * 2 : _bevel_width); - if (tmp->isStretchableHorz()) - stretchable.push_back(tmp); - else - width += tmp->_rect.width() + _bevel_width; + 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! - if (tmp->_rect.height() > tallest) - tallest = tmp->_rect.height(); + int free = w - (visible.size() - 1) * _bevel; + if (free < 0) free = 0; + int each; + + std::list adjustable; + + // find the 'free' space, and how many children will be using it + 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.push_back(*it); } - - if (stretchable.size() > 0) { - WidgetList::iterator str_it = stretchable.begin(), - str_end = stretchable.end(); - - int str_width = _rect.width() - width / stretchable.size(); - - for (; str_it != str_end; ++str_it) - (*str_it)->setWidth(str_width > _bevel_width ? str_width - _bevel_width - : _bevel_width); + // some widgets may have max widths that restrict them, find the 'true' + // amount of free space after these widgets are not included + if (!adjustable.empty()) { + do { + each = free / adjustable.size(); + for (it = adjustable.begin(), end = adjustable.end(); it != end;) { + std::list::iterator next = it; ++next; + int m = (*it)->maxSize().width() - (*it)->minSize().width(); + if (m > 0 && m < each) { + free -= m; + if (free < 0) free = 0; + adjustable.erase(it); + break; // if one is found to be fixed, then the free space needs to + // change, and the rest need to be reexamined + } + it = next; + } + } while (it != end && !adjustable.empty()); } - Widget *prev_widget = 0; - - for (it = _children.begin(); it != end; ++it) { - tmp = *it; - int x, y; - - if (prev_widget) - x = prev_widget->_rect.x() + prev_widget->_rect.width() + _bevel_width; - else - x = _bevel_width; - y = (tallest - tmp->_rect.height()) / 2 + _bevel_width; - - tmp->move(x, y); - - prev_widget = tmp; + // place/size the widgets + if (!adjustable.empty()) + each = free / adjustable.size(); + else + each = 0; + for (it = visible.begin(), end = visible.end(); it != end; ++it) { + int w; + // is the widget adjustable? + std::list::const_iterator + found = std::find(adjustable.begin(), adjustable.end(), *it); + if (found != adjustable.end()) { + // adjustable + w = (*it)->minSize().width() + each; + } else { + // fixed + w = (*it)->minSize().width(); + } + // align it vertically + int yy = y; + int hh = std::max(std::min(h, (*it)->_max_size.height()), + (*it)->_min_size.height()); + if (hh < h) { + switch(_alignment) { + case RenderStyle::RightBottomJustify: + yy += h - hh; + break; + case RenderStyle::CenterJustify: + yy += (h - hh) / 2; + break; + case RenderStyle::LeftTopJustify: + break; + } + } + (*it)->internal_moveresize(x, yy, w, hh); + (*it)->render(); + (*it)->layout(); + x += w + _bevel; } - internalResize(width, tallest + _bevel_width * 2); } -void Widget::adjustVert(void) +void Widget::layoutVert() { - if (_children.size() == 0) - return; - - Widget *tmp; - WidgetList::iterator it, end = _children.end(); + std::list::iterator it, end; - int widest = 0; - int height = _bevel_width; - WidgetList stretchable; + // work with just the visible children + std::list visible; + for (it = _children.begin(), end = _children.end(); it != end; ++it) + if ((*it)->visible()) + visible.push_back(*it); - for (it = _children.begin(); it != end; ++it) { - tmp = *it; - if (tmp->isStretchableHorz()) - tmp->setWidth(_rect.width() > _bevel_width * 2 ? - _rect.width() - _bevel_width * 2 : _bevel_width); - if (tmp->isStretchableVert()) - stretchable.push_back(tmp); - else - height += tmp->_rect.height() + _bevel_width; + if (visible.empty()) return; - if (tmp->_rect.width() > widest) - widest = tmp->_rect.width(); - } + 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! - if (stretchable.size() > 0) { - WidgetList::iterator str_it = stretchable.begin(), - str_end = stretchable.end(); + int free = h - (visible.size() - 1) * _bevel; + if (free < 0) free = 0; + int each; - int str_height = _rect.height() - height / stretchable.size(); + std::list adjustable; - for (; str_it != str_end; ++str_it) - (*str_it)->setHeight(str_height > _bevel_width ? - str_height - _bevel_width : _bevel_width); + // find the 'free' space, and how many children will be using it + 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.push_back(*it); } - - Widget *prev_widget = 0; - - for (it = _children.begin(); it != end; ++it) { - tmp = *it; - int x, y; - - if (prev_widget) - y = prev_widget->_rect.y() + prev_widget->_rect.height() + _bevel_width; - else - y = _bevel_width; - x = (widest - tmp->_rect.width()) / 2 + _bevel_width; - - tmp->move(x, y); - - prev_widget = tmp; + // some widgets may have max heights that restrict them, find the 'true' + // amount of free space after these widgets are not included + if (!adjustable.empty()) { + do { + each = free / adjustable.size(); + for (it = adjustable.begin(), end = adjustable.end(); it != end;) { + std::list::iterator next = it; ++next; + int m = (*it)->maxSize().height() - (*it)->minSize().height(); + if (m > 0 && m < each) { + free -= m; + if (free < 0) free = 0; + adjustable.erase(it); + break; // if one is found to be fixed, then the free space needs to + // change, and the rest need to be reexamined + } + it = next; + } + } while (it != end && !adjustable.empty()); } - internalResize(widest + _bevel_width * 2, height); + // place/size the widgets + if (!adjustable.empty()) + each = free / adjustable.size(); + else + each = 0; + for (it = visible.begin(), end = visible.end(); it != end; ++it) { + int h; + // is the widget adjustable? + std::list::const_iterator + found = std::find(adjustable.begin(), adjustable.end(), *it); + if (found != adjustable.end()) { + // adjustable + h = (*it)->minSize().height() + each; + } else { + // fixed + h = (*it)->minSize().height(); + } + // align it horizontally + int xx = x; + int ww = std::max(std::min(w, (*it)->_max_size.width()), + (*it)->_min_size.width()); + if (ww < w) { + switch(_alignment) { + case RenderStyle::RightBottomJustify: + xx += w - ww; + break; + case RenderStyle::CenterJustify: + xx += (w - ww) / 2; + break; + case RenderStyle::LeftTopJustify: + break; + } + } + (*it)->internal_moveresize(xx, y, ww, h); + (*it)->render(); + (*it)->layout(); + y += h + _bevel; + } } -void Widget::update() +void Widget::render() { - WidgetList::iterator it = _children.begin(), end = _children.end(); - for (; it != end; ++it) - (*it)->update(); - - if (_dirty) { - adjust(); - render(); - XClearWindow(**display, _window); + 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, + _area.height() - _borderwidth * 2)); + display->renderControl(_screen)->drawBackground(*s, *_texture); - _dirty = false; -} + renderForeground(*s); // for inherited types to render onto the _surface -void Widget::internalResize(int w, int h) -{ - assert(w > 0 && h > 0); + XSetWindowBackgroundPixmap(**display, _window, s->pixmap()); + XClearWindow(**display, _window); - bool fw = _fixed_width, fh = _fixed_height; - - if (! fw && ! fh) - resize(w, h); - else if (! fw) - resize(w, _rect.height()); - else if (! fh) - resize(_rect.width(), h); - - _fixed_width = fw; - _fixed_height = fh; -} - -void Widget::addChild(Widget *child, bool front) -{ - assert(child); - if (front) - _children.push_front(child); - else - _children.push_back(child); -} + // delete the old surface *after* its pixmap isn't in use anymore + if (_surface) delete _surface; -void Widget::removeChild(Widget *child) -{ - assert(child); - WidgetList::iterator it, end = _children.end(); - for (it = _children.begin(); it != end; ++it) { - if ((*it) == child) - break; - } + s->freePixelData(); // done rendering with this surface + _surface = s; - if (it != _children.end()) - _children.erase(it); + _dirty = false; } -void Widget::setStyle(RenderStyle *style) +void Widget::renderChildren() { - assert(style); - _style = style; - _dirty = true; - - WidgetList::iterator it, end = _children.end(); + std::list::iterator it, end = _children.end(); for (it = _children.begin(); it != end; ++it) - (*it)->setStyle(style); + (*it)->render(); } - -void Widget::setEventDispatcher(EventDispatcher *disp) +void Widget::styleChanged(const RenderStyle &) { - if (_event_dispatcher) - _event_dispatcher->clearHandler(_window); - _event_dispatcher = disp; - _event_dispatcher->registerHandler(_window, this); + refresh(); } void Widget::exposeHandler(const XExposeEvent &e) { EventHandler::exposeHandler(e); -// XClearArea(**display, _window, e.x, e.y, e.width, e.height, false); + XClearArea(**display, _window, e.x, e.y, e.width, e.height, false); } void Widget::configureHandler(const XConfigureEvent &e) { - EventHandler::configureHandler(e); - if (_ignore_config) { _ignore_config--; } else { - int width = e.width; - int height = e.height; + // only interested in these for top level windows + if (_parent) return; XEvent ev; - while (XCheckTypedWindowEvent(**display, _window, ConfigureNotify, &ev)) { - width = ev.xconfigure.width; - height = ev.xconfigure.height; - } - - if (!(width == _rect.width() && height == _rect.height())) { - _dirty = true; - _rect.setSize(width, height); + ev.xconfigure.width = e.width; + ev.xconfigure.height = e.height; + while (XCheckTypedWindowEvent(**display, window(), ConfigureNotify, &ev)); + + if (!(ev.xconfigure.width == area().width() && + ev.xconfigure.height == area().height())) { + _area = Rect(_area.position(), Size(e.width, e.height)); + update(); } - update(); } }