00001
00002
00003 #ifdef HAVE_CONFIG_H
00004 # include "../config.h"
00005 #endif // HAVE_CONFIG_H
00006
00007 #include "widget.hh"
00008 #include "display.hh"
00009 #include "assassin.hh"
00010 #include "screeninfo.hh"
00011 #include "focuslabel.hh"
00012 #include <algorithm>
00013 #include <iostream>
00014
00015 namespace otk {
00016
00017 Widget::Widget(Widget *parent, Direction direction)
00018 : EventHandler(),
00019 _dirty(false), _focused(false),
00020 _parent(parent), _style(parent->style()), _direction(direction),
00021 _cursor(parent->cursor()), _bevel_width(parent->bevelWidth()),
00022 _ignore_config(0),
00023 _visible(false), _grabbed_mouse(false),
00024 _grabbed_keyboard(false), _stretchable_vert(false),
00025 _stretchable_horz(false), _texture(0), _bg_pixmap(0), _bg_pixel(0),
00026 _bcolor(0), _bwidth(0), _rect(0, 0, 1, 1), _screen(parent->screen()),
00027 _fixed_width(false), _fixed_height(false),
00028 _surface(0),
00029 _event_dispatcher(parent->eventDispatcher())
00030 {
00031 assert(parent);
00032 parent->addChild(this);
00033 create();
00034 _event_dispatcher->registerHandler(_window, this);
00035 }
00036
00037 Widget::Widget(EventDispatcher *event_dispatcher, RenderStyle *style,
00038 Direction direction, Cursor cursor, int bevel_width,
00039 bool override_redirect)
00040 : EventHandler(),
00041 _dirty(false),_focused(false),
00042 _parent(0), _style(style), _direction(direction), _cursor(cursor),
00043 _bevel_width(bevel_width), _ignore_config(0), _visible(false),
00044 _grabbed_mouse(false), _grabbed_keyboard(false),
00045 _stretchable_vert(false), _stretchable_horz(false), _texture(0),
00046 _bg_pixmap(0), _bg_pixel(0), _bcolor(0), _bwidth(0), _rect(0, 0, 1, 1),
00047 _screen(style->screen()), _fixed_width(false), _fixed_height(false),
00048 _surface(0),
00049 _event_dispatcher(event_dispatcher)
00050 {
00051 assert(event_dispatcher);
00052 assert(style);
00053 create(override_redirect);
00054 _event_dispatcher->registerHandler(_window, this);
00055 }
00056
00057 Widget::~Widget()
00058 {
00059 if (_visible)
00060 hide();
00061
00062 if (_surface)
00063 delete _surface;
00064
00065 _event_dispatcher->clearHandler(_window);
00066
00067 std::for_each(_children.begin(), _children.end(), PointerAssassin());
00068
00069 if (_parent)
00070 _parent->removeChild(this);
00071
00072 XDestroyWindow(**display, _window);
00073 }
00074
00075 void Widget::create(bool override_redirect)
00076 {
00077 const ScreenInfo *scr_info = display->screenInfo(_screen);
00078 Window p_window = _parent ? _parent->window() : scr_info->rootWindow();
00079
00080 _rect.setRect(0, 0, 1, 1);
00081
00082 XSetWindowAttributes attrib_create;
00083 unsigned long create_mask = CWBackPixmap | CWBorderPixel | CWEventMask;
00084
00085 attrib_create.background_pixmap = None;
00086 attrib_create.colormap = scr_info->colormap();
00087 attrib_create.event_mask = ButtonPressMask | ButtonReleaseMask |
00088 ButtonMotionMask | ExposureMask | StructureNotifyMask;
00089
00090 if (override_redirect) {
00091 create_mask |= CWOverrideRedirect;
00092 attrib_create.override_redirect = true;
00093 }
00094
00095 if (_cursor) {
00096 create_mask |= CWCursor;
00097 attrib_create.cursor = _cursor;
00098 }
00099
00100 _window = XCreateWindow(**display, p_window, _rect.x(),
00101 _rect.y(), _rect.width(), _rect.height(), 0,
00102 scr_info->depth(), InputOutput,
00103 scr_info->visual(), create_mask, &attrib_create);
00104 _ignore_config++;
00105 }
00106
00107 void Widget::setWidth(int w)
00108 {
00109 assert(w > 0);
00110 _fixed_width = true;
00111 setGeometry(_rect.x(), _rect.y(), w, _rect.height());
00112 }
00113
00114 void Widget::setHeight(int h)
00115 {
00116 assert(h > 0);
00117 _fixed_height = true;
00118 setGeometry(_rect.x(), _rect.y(), _rect.width(), h);
00119 }
00120
00121 void Widget::move(const Point &to)
00122 {
00123 move(to.x(), to.y());
00124 }
00125
00126 void Widget::move(int x, int y)
00127 {
00128 _rect.setPos(x, y);
00129 XMoveWindow(**display, _window, x, y);
00130 _ignore_config++;
00131 }
00132
00133 void Widget::resize(const Point &to)
00134 {
00135 resize(to.x(), to.y());
00136 }
00137
00138 void Widget::resize(int w, int h)
00139 {
00140 assert(w > 0 && h > 0);
00141 _fixed_width = _fixed_height = true;
00142 setGeometry(_rect.x(), _rect.y(), w, h);
00143 }
00144
00145 void Widget::setGeometry(const Rect &new_geom)
00146 {
00147 setGeometry(new_geom.x(), new_geom.y(), new_geom.width(), new_geom.height());
00148 }
00149
00150 void Widget::setGeometry(const Point &topleft, int width, int height)
00151 {
00152 setGeometry(topleft.x(), topleft.y(), width, height);
00153 }
00154
00155 void Widget::setGeometry(int x, int y, int width, int height)
00156 {
00157 _rect = Rect(x, y, width, height);
00158 _dirty = true;
00159
00160
00161 Widget *p = _parent;
00162 while (p) {
00163 p->_dirty = true;
00164 p = p->_parent;
00165 }
00166
00167
00168
00169 XResizeWindow(**display, _window, width, height);
00170 XMoveWindow(**display, _window, x, y);
00171 _ignore_config+=2;
00172 }
00173
00174 void Widget::show(bool recursive)
00175 {
00176 if (_visible)
00177 return;
00178
00179
00180 if (_dirty)
00181 update();
00182
00183 if (recursive) {
00184 WidgetList::iterator it = _children.begin(), end = _children.end();
00185 for (; it != end; ++it)
00186 (*it)->show(recursive);
00187 }
00188
00189 XMapWindow(**display, _window);
00190 _visible = true;
00191 }
00192
00193 void Widget::hide(bool recursive)
00194 {
00195 if (! _visible)
00196 return;
00197
00198 if (recursive) {
00199 WidgetList::iterator it = _children.begin(), end = _children.end();
00200 for (; it != end; ++it)
00201 (*it)->hide();
00202 }
00203
00204 XUnmapWindow(**display, _window);
00205 _visible = false;
00206 }
00207
00208 void Widget::focus(void)
00209 {
00210 _focused = true;
00211
00212 Widget::WidgetList::iterator it = _children.begin(),
00213 end = _children.end();
00214 for (; it != end; ++it)
00215 (*it)->focus();
00216 }
00217
00218 void Widget::unfocus(void)
00219 {
00220 _focused = false;
00221
00222 Widget::WidgetList::iterator it = _children.begin(),
00223 end = _children.end();
00224 for (; it != end; ++it)
00225 (*it)->unfocus();
00226 }
00227
00228 bool Widget::grabMouse(void)
00229 {
00230 Status ret = XGrabPointer(**display, _window, True,
00231 (ButtonPressMask | ButtonReleaseMask |
00232 ButtonMotionMask | EnterWindowMask |
00233 LeaveWindowMask | PointerMotionMask),
00234 GrabModeSync, GrabModeAsync, None, None,
00235 CurrentTime);
00236 _grabbed_mouse = (ret == GrabSuccess);
00237 return _grabbed_mouse;
00238 }
00239
00240 void Widget::ungrabMouse(void)
00241 {
00242 if (! _grabbed_mouse)
00243 return;
00244
00245 XUngrabPointer(**display, CurrentTime);
00246 _grabbed_mouse = false;
00247 }
00248
00249 bool Widget::grabKeyboard(void)
00250 {
00251 Status ret = XGrabKeyboard(**display, _window, True,
00252 GrabModeSync, GrabModeAsync, CurrentTime);
00253 _grabbed_keyboard = (ret == GrabSuccess);
00254 return _grabbed_keyboard;
00255
00256 }
00257
00258 void Widget::ungrabKeyboard(void)
00259 {
00260 if (! _grabbed_keyboard)
00261 return;
00262
00263 XUngrabKeyboard(**display, CurrentTime);
00264 _grabbed_keyboard = false;
00265 }
00266
00267 void Widget::render(void)
00268 {
00269 if (!_texture) {
00270 XSetWindowBackgroundPixmap(**display, _window, ParentRelative);
00271 return;
00272 }
00273
00274 Surface *s = _surface;
00275
00276 _surface = new Surface(_screen, _rect.size());
00277 display->renderControl(_screen)->drawBackground(*_surface, *_texture);
00278
00279 renderForeground();
00280
00281 XSetWindowBackgroundPixmap(**display, _window, _surface->pixmap());
00282
00283 if (s)
00284 delete s;
00285 }
00286
00287 void Widget::adjust(void)
00288 {
00289 if (_direction == Horizontal)
00290 adjustHorz();
00291 else
00292 adjustVert();
00293 }
00294
00295 void Widget::adjustHorz(void)
00296 {
00297 if (_children.size() == 0)
00298 return;
00299
00300 Widget *tmp;
00301 WidgetList::iterator it, end = _children.end();
00302
00303 int tallest = 0;
00304 int width = _bevel_width;
00305 WidgetList stretchable;
00306
00307 for (it = _children.begin(); it != end; ++it) {
00308 tmp = *it;
00309 if (tmp->isStretchableVert())
00310 tmp->setHeight(_rect.height() > _bevel_width * 2 ?
00311 _rect.height() - _bevel_width * 2 : _bevel_width);
00312 if (tmp->isStretchableHorz())
00313 stretchable.push_back(tmp);
00314 else
00315 width += tmp->_rect.width() + _bevel_width;
00316
00317 if (tmp->_rect.height() > tallest)
00318 tallest = tmp->_rect.height();
00319 }
00320
00321 if (stretchable.size() > 0) {
00322 WidgetList::iterator str_it = stretchable.begin(),
00323 str_end = stretchable.end();
00324
00325 int str_width = _rect.width() - width / stretchable.size();
00326
00327 for (; str_it != str_end; ++str_it)
00328 (*str_it)->setWidth(str_width > _bevel_width ? str_width - _bevel_width
00329 : _bevel_width);
00330 }
00331
00332 Widget *prev_widget = 0;
00333
00334 for (it = _children.begin(); it != end; ++it) {
00335 tmp = *it;
00336 int x, y;
00337
00338 if (prev_widget)
00339 x = prev_widget->_rect.x() + prev_widget->_rect.width() + _bevel_width;
00340 else
00341 x = _bevel_width;
00342 y = (tallest - tmp->_rect.height()) / 2 + _bevel_width;
00343
00344 tmp->move(x, y);
00345
00346 prev_widget = tmp;
00347 }
00348 internalResize(width, tallest + _bevel_width * 2);
00349 }
00350
00351 void Widget::adjustVert(void)
00352 {
00353 if (_children.size() == 0)
00354 return;
00355
00356 Widget *tmp;
00357 WidgetList::iterator it, end = _children.end();
00358
00359 int widest = 0;
00360 int height = _bevel_width;
00361 WidgetList stretchable;
00362
00363 for (it = _children.begin(); it != end; ++it) {
00364 tmp = *it;
00365 if (tmp->isStretchableHorz())
00366 tmp->setWidth(_rect.width() > _bevel_width * 2 ?
00367 _rect.width() - _bevel_width * 2 : _bevel_width);
00368 if (tmp->isStretchableVert())
00369 stretchable.push_back(tmp);
00370 else
00371 height += tmp->_rect.height() + _bevel_width;
00372
00373 if (tmp->_rect.width() > widest)
00374 widest = tmp->_rect.width();
00375 }
00376
00377 if (stretchable.size() > 0) {
00378 WidgetList::iterator str_it = stretchable.begin(),
00379 str_end = stretchable.end();
00380
00381 int str_height = _rect.height() - height / stretchable.size();
00382
00383 for (; str_it != str_end; ++str_it)
00384 (*str_it)->setHeight(str_height > _bevel_width ?
00385 str_height - _bevel_width : _bevel_width);
00386 }
00387 if (stretchable.size() > 0)
00388 height = _rect.height();
00389
00390 Widget *prev_widget = 0;
00391
00392 for (it = _children.begin(); it != end; ++it) {
00393 tmp = *it;
00394 int x, y;
00395
00396 if (prev_widget)
00397 y = prev_widget->_rect.y() + prev_widget->_rect.height() + _bevel_width;
00398 else
00399 y = _bevel_width;
00400 x = (widest - tmp->_rect.width()) / 2 + _bevel_width;
00401
00402 tmp->move(x, y);
00403
00404 prev_widget = tmp;
00405 }
00406
00407 internalResize(widest + _bevel_width * 2, height);
00408 }
00409
00410 void Widget::update()
00411 {
00412 WidgetList::iterator it = _children.begin(), end = _children.end();
00413 for (; it != end; ++it)
00414 (*it)->update();
00415
00416 if (_dirty) {
00417 adjust();
00418 render();
00419 XClearWindow(**display, _window);
00420 }
00421
00422 _dirty = false;
00423 }
00424
00425 void Widget::internalResize(int w, int h)
00426 {
00427 assert(w > 0 && h > 0);
00428
00429 bool fw = _fixed_width, fh = _fixed_height;
00430
00431 if (! fw && ! fh)
00432 resize(w, h);
00433 else if (! fw)
00434 resize(w, _rect.height());
00435 else if (! fh)
00436 resize(_rect.width(), h);
00437
00438 _fixed_width = fw;
00439 _fixed_height = fh;
00440 }
00441
00442 void Widget::addChild(Widget *child, bool front)
00443 {
00444 assert(child);
00445 if (front)
00446 _children.push_front(child);
00447 else
00448 _children.push_back(child);
00449 }
00450
00451 void Widget::removeChild(Widget *child)
00452 {
00453 assert(child);
00454 WidgetList::iterator it, end = _children.end();
00455 for (it = _children.begin(); it != end; ++it) {
00456 if ((*it) == child)
00457 break;
00458 }
00459
00460 if (it != _children.end())
00461 _children.erase(it);
00462 }
00463
00464 void Widget::setStyle(RenderStyle *style)
00465 {
00466 assert(style);
00467 _style = style;
00468 _dirty = true;
00469
00470 WidgetList::iterator it, end = _children.end();
00471 for (it = _children.begin(); it != end; ++it)
00472 (*it)->setStyle(style);
00473 }
00474
00475
00476 void Widget::setEventDispatcher(EventDispatcher *disp)
00477 {
00478 if (_event_dispatcher)
00479 _event_dispatcher->clearHandler(_window);
00480 _event_dispatcher = disp;
00481 _event_dispatcher->registerHandler(_window, this);
00482 }
00483
00484 void Widget::exposeHandler(const XExposeEvent &e)
00485 {
00486 EventHandler::exposeHandler(e);
00487
00488 }
00489
00490 void Widget::configureHandler(const XConfigureEvent &e)
00491 {
00492 EventHandler::configureHandler(e);
00493
00494 if (_ignore_config) {
00495 _ignore_config--;
00496 } else {
00497 int width = e.width;
00498 int height = e.height;
00499
00500 XEvent ev;
00501 while (XCheckTypedWindowEvent(**display, _window, ConfigureNotify, &ev)) {
00502 width = ev.xconfigure.width;
00503 height = ev.xconfigure.height;
00504 }
00505
00506 if (!(width == _rect.width() && height == _rect.height())) {
00507 _dirty = true;
00508 _rect.setSize(width, height);
00509 }
00510 update();
00511 }
00512 }
00513
00514 }