Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

/otk/widget.cc

Go to the documentation of this file.
00001 // -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
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); // just some initial values
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   // make all parents dirty too
00161   Widget *p = _parent;
00162   while (p) {
00163     p->_dirty = true;
00164     p = p->_parent;
00165   }
00166 
00167   // don't use an XMoveResizeWindow here, because it doesn't seem to move
00168   // windows with StaticGravity? This works, that didn't.
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   // make sure the internal state isn't mangled
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; // save the current surface
00275   
00276   _surface = new Surface(_screen, _rect.size());
00277   display->renderControl(_screen)->drawBackground(*_surface, *_texture);
00278 
00279   renderForeground(); // for inherited types to render onto the _surface
00280 
00281   XSetWindowBackgroundPixmap(**display, _window, _surface->pixmap());
00282 
00283   if (s)
00284     delete s; // delete the old surface *after* its pixmap isn't in use anymore
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 //  XClearArea(**display, _window, e.x, e.y, e.width, e.height, false);
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 }

Generated on Tue Feb 4 22:58:57 2003 for Openbox by doxygen1.3-rc2