aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/dw-stacking-context.doc55
-rw-r--r--dw/layout.cc13
-rw-r--r--dw/oofawarewidget.cc52
-rw-r--r--dw/oofawarewidget.hh4
-rw-r--r--dw/ooffloatsmgr.cc18
-rw-r--r--dw/ooffloatsmgr.hh5
-rw-r--r--dw/oofpositionedmgr.cc18
-rw-r--r--dw/oofpositionedmgr.hh2
-rw-r--r--dw/outofflowmgr.hh2
-rw-r--r--dw/stackingcontextmgr.cc47
-rw-r--r--dw/stackingcontextmgr.hh6
-rw-r--r--dw/textblock.cc33
-rw-r--r--dw/textblock.hh2
-rw-r--r--dw/widget.cc52
-rw-r--r--dw/widget.hh2
15 files changed, 223 insertions, 88 deletions
diff --git a/doc/dw-stacking-context.doc b/doc/dw-stacking-context.doc
index 47854546..6138ca5d 100644
--- a/doc/dw-stacking-context.doc
+++ b/doc/dw-stacking-context.doc
@@ -32,11 +32,11 @@ I'm here referring to the simplified description in
<a href="http://www.w3.org/TR/CSS2/visuren.html#z-index">section
9.9.1</a>. The table shows a recommended order for the implementations
of dw::core::Widget::draw and dw::core::Widget::getWidgetAtPoint
-(for the latter, read from bottom to top)<sup>1</sup>:
+(for the latter, read from bottom to top):
<table>
<tr>
-<th> CSS specification <th> Drawing <th> Mouse events<sup>2</sup>
+<th> CSS specification <th> Drawing <th> Mouse events
<tr>
<td> *1. the background and borders of the element forming the
stacking context.*
@@ -46,7 +46,7 @@ of dw::core::Widget::draw and dw::core::Widget::getWidgetAtPoint
<td> *2. the child stacking contexts with negative stack levels (most
negative first).*
<td> dw::core::StackingContextMgr::drawBottom (when defined)
-<td> ...
+<td> dw::core::StackingContextMgr::getBottomWidgetAtPoint (when defined)
<tr>
<td> *3. the in-flow, non-inline-level, non-positioned descendants.*
@@ -56,13 +56,34 @@ of dw::core::Widget::draw and dw::core::Widget::getWidgetAtPoint
1. all in-flow elements are drawn,
2. floats are drawn and
- 3. positioned elements are drawn (latter two done by
+ 3. positioned elements with *z-index: auto* are drawn
+ (latter two done by
dw::oof::OOFAwareWidget::drawOOF, in this order).
This order differs from the specified order, but
since floats and in-flow elements do not overlap,
- this difference has no effect.<sup>3</sup>
-<td rowspan="4"> ...<sup>3</sup>
+ this difference has no effect.
+
+ Drawing in-line elements, floats and positioned
+ elements with *z-index: auto* and should avoid
+ duplicate calls: Widgets drawn by
+ dw::core::StackingContextMgr::drawBottom and by
+ dw::core::StackingContextMgr::drawTop should be
+ excluded here. This can be tested with
+ dw::core::StackingContextMgr::handledByStackingContextMgr.
+
+<td rowspan="4"> Likewise, the implementation should (i) test
+ dw::oof::OOFAwareWidget::getWidgetOOFAtPoint, and
+ (ii) search through the chilren. Also, duplicate
+ calls should be avoided using
+ dw::core::StackingContextMgr::handledByStackingContextMgr.
+
+ There are already the implementations
+ dw::core::Widget::getWidgetAtPoint (ignoring
+ dw::oof::OutOfFlowMgr) and
+ dw::oof::OOFAwareWidget::getWidgetAtPoint (including
+ dw::oof::OutOfFlowMgr).
+
<tr>
<td> *4. the non-positioned floats.*
<tr>
@@ -79,27 +100,15 @@ of dw::core::Widget::draw and dw::core::Widget::getWidgetAtPoint
<td> *6. the child stacking contexts with stack level 0 and the
positioned descendants with stack level 0.*
<td rowspan="2"> dw::core::StackingContextMgr::drawTop (when defined)
-<td rowspan="2"> ...
+<td rowspan="2"> dw::core::StackingContextMgr::getTopWidgetAtPoint
+ (when defined)
<tr>
<td> *7. the child stacking contexts with positive stack levels (least
positive first).*
</table>
-Notes:
-
-<sup>1</sup>) This is not quite in conformance with the specification:
- this description refers to any widget, not only widgets
- establishing a stacking context. Does this make a
- difference?
-
-<sup>2</sup>) Handling mouse events is, at this time, not implemented
- at all.
-
-<sup>3</sup>) Drawing (and handling mouse events, respectively) should
- avoid dublicate calls: Widgets drawn by
- dw::core::StackingContextMgr::drawBottom and by
- dw::core::StackingContextMgr::drawTop should be excluded
- elsewhere. This can be tested with
- dw::core::StackingContextMgr::handledByStackingContextMgr.
+Note: This is not quite in conformance with the specification: this
+description refers to any widget, not only widgets establishing a
+stacking context. Does this make a difference?
*/ \ No newline at end of file
diff --git a/dw/layout.cc b/dw/layout.cc
index d46d2455..600f2088 100644
--- a/dw/layout.cc
+++ b/dw/layout.cc
@@ -1100,12 +1100,17 @@ void Layout::leaveNotify (View *view, ButtonState state)
*/
Widget *Layout::getWidgetAtPoint (int x, int y)
{
- _MSG ("------------------------------------------------------------\n");
- _MSG ("widget at (%d, %d)\n", x, y);
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y);
+ Widget *widget;
+
if (topLevel && topLevel->wasAllocated ())
- return topLevel->getWidgetAtPoint (x, y, 0);
+ widget = topLevel->getWidgetAtPoint (x, y);
else
- return NULL;
+ widget = NULL;
+
+ DBG_OBJ_MSGF ("events", 0, "=> %p", widget);
+ DBG_OBJ_LEAVE ();
+ return widget;
}
diff --git a/dw/oofawarewidget.cc b/dw/oofawarewidget.cc
index 62a1e8d6..99f297ff 100644
--- a/dw/oofawarewidget.cc
+++ b/dw/oofawarewidget.cc
@@ -255,12 +255,12 @@ void OOFAwareWidget::drawOOF (View *view, Rectangle *area)
outOfFlowMgr[i]->draw(view, area);
}
-Widget *OOFAwareWidget::getWidgetOOFAtPoint (int x, int y, int level)
+Widget *OOFAwareWidget::getWidgetOOFAtPoint (int x, int y)
{
for (int i = 0; i < NUM_OOFM; i++) {
Widget *oofWidget =
outOfFlowMgr[i] ?
- outOfFlowMgr[i]->getWidgetAtPoint (x, y, level) : NULL;
+ outOfFlowMgr[i]->getWidgetAtPoint (x, y) : NULL;
if (oofWidget)
return oofWidget;
}
@@ -299,6 +299,54 @@ void OOFAwareWidget::removeChild (Widget *child)
assert (isWidgetOOF (child));
}
+core::Widget *OOFAwareWidget::getWidgetAtPoint (int x, int y)
+{
+ if (x >= allocation.x &&
+ y >= allocation.y &&
+ x <= allocation.x + allocation.width &&
+ y <= allocation.y + getHeight ()) {
+
+ if (stackingContextMgr) {
+ Widget *scmWidget =
+ stackingContextMgr->getTopWidgetAtPoint (x, y);
+ if (scmWidget)
+ return scmWidget;
+ }
+
+ Widget *oofWidget = getWidgetOOFAtPoint (x, y);
+ if (oofWidget)
+ return oofWidget;
+
+ Widget *childAtPoint = NULL;
+ Iterator *it =
+ iterator ((Content::Type)
+ (Content::WIDGET_IN_FLOW | Content::WIDGET_OOF_CONT),
+ false);
+
+ while (childAtPoint == NULL && it->next ()) {
+ Widget *child = it->getContent()->widget;
+ if (!StackingContextMgr::handledByStackingContextMgr (child) &&
+ child->wasAllocated ())
+ childAtPoint = child->getWidgetAtPoint (x, y);
+ }
+
+ it->unref ();
+
+ if (childAtPoint)
+ return childAtPoint;
+
+ if (stackingContextMgr) {
+ Widget *scmWidget =
+ stackingContextMgr->getBottomWidgetAtPoint (x, y);
+ if (scmWidget)
+ return scmWidget;
+ }
+
+ return this;
+ } else
+ return NULL;
+}
+
void OOFAwareWidget::borderChanged (int y, Widget *vloat)
{
assertNotReached ();
diff --git a/dw/oofawarewidget.hh b/dw/oofawarewidget.hh
index afa5964a..81fafa10 100644
--- a/dw/oofawarewidget.hh
+++ b/dw/oofawarewidget.hh
@@ -169,7 +169,7 @@ protected:
void sizeAllocateEnd ();
void containerSizeChangedForChildrenOOF ();
void drawOOF (core::View *view, core::Rectangle *area);
- core::Widget *getWidgetOOFAtPoint (int x, int y, int level);
+ core::Widget *getWidgetOOFAtPoint (int x, int y);
static bool isOOFContainer (Widget *widget, int oofmIndex);
@@ -181,6 +181,8 @@ protected:
void removeChild (Widget *child);
+ core::Widget *getWidgetAtPoint (int x, int y);
+
public:
static int CLASS_ID;
diff --git a/dw/ooffloatsmgr.cc b/dw/ooffloatsmgr.cc
index eecd4faa..8b1df1de 100644
--- a/dw/ooffloatsmgr.cc
+++ b/dw/ooffloatsmgr.cc
@@ -1458,23 +1458,23 @@ void OOFFloatsMgr::markExtremesChange (int ref)
// Nothing to do here.
}
-Widget *OOFFloatsMgr::getWidgetAtPoint (int x, int y, int level)
+Widget *OOFFloatsMgr::getWidgetAtPoint (int x, int y)
{
- Widget *childAtPoint = getFloatWidgetAtPoint (leftFloatsCB, x, y, level);
+ Widget *childAtPoint = getFloatWidgetAtPoint (leftFloatsCB, x, y);
if (childAtPoint == NULL)
- childAtPoint = getFloatWidgetAtPoint (rightFloatsCB, x, y, level);
+ childAtPoint = getFloatWidgetAtPoint (rightFloatsCB, x, y);
return childAtPoint;
}
-Widget *OOFFloatsMgr::getFloatWidgetAtPoint (SortedFloatsVector *list,
- int x, int y, int level)
+Widget *OOFFloatsMgr::getFloatWidgetAtPoint (SortedFloatsVector *list, int x,
+ int y)
{
for (int i = 0; i < list->size(); i++) {
// Could use binary search to be faster.
- Float *vloat = list->get(i);
- if (vloat->getWidget()->wasAllocated ()) {
- Widget *childAtPoint =
- vloat->getWidget()->getWidgetAtPoint (x, y, level + 1);
+ Widget *childWidget = list->get(i)->getWidget ();
+ if (!StackingContextMgr::handledByStackingContextMgr (childWidget) &&
+ childWidget->wasAllocated ()) {
+ Widget *childAtPoint = childWidget->getWidgetAtPoint (x, y);
if (childAtPoint)
return childAtPoint;
}
diff --git a/dw/ooffloatsmgr.hh b/dw/ooffloatsmgr.hh
index 47bcbab4..75bc596e 100644
--- a/dw/ooffloatsmgr.hh
+++ b/dw/ooffloatsmgr.hh
@@ -285,8 +285,7 @@ private:
void drawFloats (SortedFloatsVector *list, core::View *view,
core::Rectangle *area);
- core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y,
- int level);
+ core::Widget *getFloatWidgetAtPoint (SortedFloatsVector *list, int x, int y);
bool collidesV (Float *vloat, Float *other, SFVType type, int *yReal);
bool collidesH (Float *vloat, Float *other, SFVType type);
@@ -343,7 +342,7 @@ public:
void markSizeChange (int ref);
void markExtremesChange (int ref);
- core::Widget *getWidgetAtPoint (int x, int y, int level);
+ core::Widget *getWidgetAtPoint (int x, int y);
static bool _isWidgetOutOfFlow (core::Widget *widget);
static bool _isWidgetHandledByOOFM (core::Widget *widget);
diff --git a/dw/oofpositionedmgr.cc b/dw/oofpositionedmgr.cc
index 4799ec8c..e5c31a98 100644
--- a/dw/oofpositionedmgr.cc
+++ b/dw/oofpositionedmgr.cc
@@ -226,18 +226,22 @@ void OOFPositionedMgr::markExtremesChange (int ref)
{
}
-Widget *OOFPositionedMgr::getWidgetAtPoint (int x, int y, int level)
+Widget *OOFPositionedMgr::getWidgetAtPoint (int x, int y)
{
- for (int i = 0; i < children->size(); i++) {
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPoint", "%d, %d", x, y);
+ Widget *childAtPoint = NULL;
+
+ for (int i = 0; i < children->size() && childAtPoint == NULL; i++) {
Widget *childWidget = children->get(i)->widget;
- if (childWidget->wasAllocated ()) {
- Widget *childAtPoint = childWidget->getWidgetAtPoint (x, y, level + 1);
- if (childAtPoint)
- return childAtPoint;
+ if (!StackingContextMgr::handledByStackingContextMgr (childWidget) &&
+ childWidget->wasAllocated ()) {
+ childAtPoint = childWidget->getWidgetAtPoint (x, y);
}
}
- return NULL;
+ DBG_OBJ_MSGF ("events", 0, "=> %p", childAtPoint);
+ DBG_OBJ_LEAVE ();
+ return childAtPoint;
}
void OOFPositionedMgr::tellPosition (Widget *widget, int x, int y)
diff --git a/dw/oofpositionedmgr.hh b/dw/oofpositionedmgr.hh
index ad469b8f..8ddecd92 100644
--- a/dw/oofpositionedmgr.hh
+++ b/dw/oofpositionedmgr.hh
@@ -68,7 +68,7 @@ public:
void markSizeChange (int ref);
void markExtremesChange (int ref);
- core::Widget *getWidgetAtPoint (int x, int y, int level);
+ core::Widget *getWidgetAtPoint (int x, int y);
void addWidgetInFlow (OOFAwareWidget *widget, OOFAwareWidget *parent,
int externalIndex);
diff --git a/dw/outofflowmgr.hh b/dw/outofflowmgr.hh
index 5b03562d..96091ded 100644
--- a/dw/outofflowmgr.hh
+++ b/dw/outofflowmgr.hh
@@ -29,7 +29,7 @@ public:
virtual void markSizeChange (int ref) = 0;
virtual void markExtremesChange (int ref) = 0;
- virtual core::Widget *getWidgetAtPoint (int x, int y, int level) = 0;
+ virtual core::Widget *getWidgetAtPoint (int x, int y) = 0;
virtual void addWidgetInFlow (OOFAwareWidget *widget,
OOFAwareWidget *parent, int externalIndex) = 0;
diff --git a/dw/stackingcontextmgr.cc b/dw/stackingcontextmgr.cc
index b3573a3f..e57c73f0 100644
--- a/dw/stackingcontextmgr.cc
+++ b/dw/stackingcontextmgr.cc
@@ -101,6 +101,53 @@ void StackingContextMgr::draw (View *view, Rectangle *area, int startZIndex,
DBG_OBJ_LEAVE ();
}
+Widget *StackingContextMgr::getTopWidgetAtPoint (int x, int y)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointTop", "%d, %d", x, y);
+ Widget *widget = getWidgetAtPoint (x, y, 0, INT_MAX);
+ DBG_OBJ_MSGF ("events", 0, "=> %p", widget);
+ DBG_OBJ_LEAVE ();
+ return widget;
+}
+
+Widget *StackingContextMgr::getBottomWidgetAtPoint (int x, int y)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointBottom", "%d, %d", x, y);
+ Widget *widget = getWidgetAtPoint (x, y, INT_MIN, -1);
+ DBG_OBJ_MSGF ("events", 0, "=> %p", widget);
+ DBG_OBJ_LEAVE ();
+ return widget;
+}
+
+Widget *StackingContextMgr::getWidgetAtPoint (int x, int y, int startZIndex,
+ int endZIndex)
+{
+ DBG_OBJ_ENTER ("events", 0, "getWidgetAtPointBottom", "%d, %d", x, y);
+
+ Widget *widgetAtPoint = NULL;
+
+ for (int zIndex = min (maxZIndex, endZIndex);
+ zIndex >= max (minZIndex, startZIndex) && widgetAtPoint == NULL;
+ zIndex--) {
+ DBG_OBJ_MSGF ("events", 1, "searching zIndex = %d", zIndex);
+ DBG_OBJ_MSG_START ();
+
+ for (int i = 0; i < scWidgets->size () && widgetAtPoint == NULL; i++) {
+ Widget *child = scWidgets->get (i);
+ DBG_OBJ_MSGF ("events", 2, "widget %p has zIndex = %d",
+ child, child->getStyle()->zIndex);
+ if (child->getStyle()->zIndex == zIndex && child->wasAllocated ())
+ widgetAtPoint = scWidgets->get(i)->getWidgetAtPoint (x, y);
+ }
+
+ DBG_OBJ_MSG_END ();
+ }
+
+ DBG_OBJ_MSGF ("events", 0, "=> %p", widgetAtPoint);
+ DBG_OBJ_LEAVE ();
+ return widgetAtPoint;
+}
+
} // namespace core
diff --git a/dw/stackingcontextmgr.hh b/dw/stackingcontextmgr.hh
index cbb59231..684fac23 100644
--- a/dw/stackingcontextmgr.hh
+++ b/dw/stackingcontextmgr.hh
@@ -25,7 +25,8 @@ private:
int minZIndex, maxZIndex;
void draw (View *view, Rectangle *area, int startZIndex, int endZIndex);
-
+
+ Widget *getWidgetAtPoint (int x, int y, int startZIndex, int endZIndex);
public:
StackingContextMgr (Widget *widget);
~StackingContextMgr ();
@@ -47,6 +48,9 @@ public:
void drawBottom (View *view, Rectangle *area);
void drawTop (View *view, Rectangle *area);
+
+ Widget *getTopWidgetAtPoint (int x, int y);
+ Widget *getBottomWidgetAtPoint (int x, int y);
};
} // namespace core
diff --git a/dw/textblock.cc b/dw/textblock.cc
index df38a8e7..e914c316 100644
--- a/dw/textblock.cc
+++ b/dw/textblock.cc
@@ -2642,12 +2642,8 @@ void Textblock::breakAdded ()
* This is an optimized version of the general
* dw::core::Widget::getWidgetAtPoint method.
*/
-core::Widget *Textblock::getWidgetAtPoint (int x, int y, int level)
+core::Widget *Textblock::getWidgetAtPoint (int x, int y)
{
- //printf ("%*s-> examining the %s %p (%d, %d, %d x (%d + %d))\n",
- // 3 * level, "", getClassName (), this, allocation.x, allocation.y,
- // allocation.width, allocation.ascent, allocation.descent);
-
int lineIndex, wordIndex;
Line *line;
@@ -2658,10 +2654,16 @@ core::Widget *Textblock::getWidgetAtPoint (int x, int y, int level)
return NULL;
}
- // First, search for widgets out of flow, notably floats, since
- // there are cases where they overlap child textblocks. Should
- // later be refined using z-index.
- Widget *oofWidget = getWidgetOOFAtPoint (x, y, level);
+ // First, ...
+ if (stackingContextMgr) {
+ Widget *scmWidget = stackingContextMgr->getTopWidgetAtPoint (x, y);
+ if (scmWidget)
+ return scmWidget;
+ }
+
+ // Then, search for widgets out of flow, notably floats, since
+ // there are cases where they overlap child textblocks.
+ Widget *oofWidget = getWidgetOOFAtPoint (x, y);
if (oofWidget)
return oofWidget;
@@ -2678,9 +2680,10 @@ core::Widget *Textblock::getWidgetAtPoint (int x, int y, int level)
if (word->content.type == core::Content::WIDGET_IN_FLOW) {
core::Widget * childAtPoint;
- if (word->content.widget->wasAllocated ()) {
- childAtPoint = word->content.widget->getWidgetAtPoint (x, y,
- level + 1);
+ if (!core::StackingContextMgr::handledByStackingContextMgr
+ (word->content.widget) &&
+ word->content.widget->wasAllocated ()) {
+ childAtPoint = word->content.widget->getWidgetAtPoint (x, y);
if (childAtPoint) {
return childAtPoint;
}
@@ -2688,6 +2691,12 @@ core::Widget *Textblock::getWidgetAtPoint (int x, int y, int level)
}
}
+ if (stackingContextMgr) {
+ Widget *scmWidget = stackingContextMgr->getBottomWidgetAtPoint (x, y);
+ if (scmWidget)
+ return scmWidget;
+ }
+
return this;
}
diff --git a/dw/textblock.hh b/dw/textblock.hh
index d376ba48..e55c2ce3 100644
--- a/dw/textblock.hh
+++ b/dw/textblock.hh
@@ -831,7 +831,7 @@ public:
void addParbreak (int space, core::style::Style *style);
void addLinebreak (core::style::Style *style);
- core::Widget *getWidgetAtPoint (int x, int y, int level);
+ core::Widget *getWidgetAtPoint (int x, int y);
void handOverBreak (core::style::Style *style);
void changeLinkColor (int link, int newColor);
void changeWordStyle (int from, int to, core::style::Style *style,
diff --git a/dw/widget.cc b/dw/widget.cc
index 64414008..19083f61 100644
--- a/dw/widget.cc
+++ b/dw/widget.cc
@@ -1389,42 +1389,50 @@ Widget *Widget::getNearestCommonAncestor (Widget *otherWidget)
*
* Used by dw::core::Layout:getWidgetAtPoint.
*/
-Widget *Widget::getWidgetAtPoint (int x, int y, int level)
+Widget *Widget::getWidgetAtPoint (int x, int y)
{
- Iterator *it;
- Widget *childAtPoint;
-
- //printf ("%*s-> examining the %s %p (%d, %d, %d x (%d + %d))\n",
- // 3 * level, "", getClassName (), this, allocation.x, allocation.y,
- // allocation.width, allocation.ascent, allocation.descent);
-
if (x >= allocation.x &&
y >= allocation.y &&
x <= allocation.x + allocation.width &&
y <= allocation.y + getHeight ()) {
- //_MSG ("%*s -> inside\n", 3 * level, "");
- /*
- * Iterate over the children of this widget. Test recursively, whether
- * the point is within the child (or one of its children...). If there
- * is such a child, it is returned. Otherwise, this widget is returned.
- */
- childAtPoint = NULL;
- it = iterator ((Content::Type)
- (Content::WIDGET_IN_FLOW | Content::WIDGET_OOF_CONT),
- false);
+
+ if (stackingContextMgr) {
+ Widget *scmWidget =
+ stackingContextMgr->getTopWidgetAtPoint (x, y);
+ if (scmWidget)
+ return scmWidget;
+ }
+
+ // Iterate over the children of this widget. Test recursively, whether
+ // the point is within the child (or one of its children...). If there
+ // is such a child, it is returned. Otherwise, this widget is returned.
+
+ Widget *childAtPoint = NULL;
+ Iterator *it =
+ iterator ((Content::Type)
+ (Content::WIDGET_IN_FLOW | Content::WIDGET_OOF_CONT),
+ false);
while (childAtPoint == NULL && it->next ()) {
Widget *child = it->getContent()->widget;
- if (child->wasAllocated ())
- childAtPoint = child->getWidgetAtPoint (x, y, level + 1);
+ if (!StackingContextMgr::handledByStackingContextMgr (child) &&
+ child->wasAllocated ())
+ childAtPoint = child->getWidgetAtPoint (x, y);
}
it->unref ();
if (childAtPoint)
return childAtPoint;
- else
- return this;
+
+ if (stackingContextMgr) {
+ Widget *scmWidget =
+ stackingContextMgr->getBottomWidgetAtPoint (x, y);
+ if (scmWidget)
+ return scmWidget;
+ }
+
+ return this;
} else
return NULL;
}
diff --git a/dw/widget.hh b/dw/widget.hh
index ca98308e..9acb6605 100644
--- a/dw/widget.hh
+++ b/dw/widget.hh
@@ -492,7 +492,7 @@ public:
inline Layout *getLayout () { return layout; }
- virtual Widget *getWidgetAtPoint (int x, int y, int level);
+ virtual Widget *getWidgetAtPoint (int x, int y);
void scrollTo (HPosition hpos, VPosition vpos,
int x, int y, int width, int height);