still buggy but less buggy than before, more caching and less overhead

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15160 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2005-11-26 14:07:44 +00:00
parent 773be69904
commit 7f705589e2
5 changed files with 229 additions and 150 deletions
@@ -38,7 +38,7 @@ ClientLooper::MessageReceived(BMessage* message)
for (int32 i = 0; i < fViewCount; i++) { for (int32 i = 0; i < fViewCount; i++) {
// the client is slow // the client is slow
snooze(1000L); // snooze(20000L);
// send the command to redraw a view // send the command to redraw a view
BMessage command(MSG_DRAWING_COMMAND); BMessage command(MSG_DRAWING_COMMAND);
command.AddInt32("token", i); command.AddInt32("token", i);
@@ -116,7 +116,19 @@ ViewLayer::AddChild(ViewLayer* layer)
if (fWindow) { if (fWindow) {
layer->AttachedToWindow(fWindow); layer->AttachedToWindow(fWindow);
fWindow->MarkDirty(&layer->ScreenClipping());
// TODO: not correct... need something like
// ViewLayer::ClipToParent(BRect frame)
// {
// frame = frame & Bounds();
// ConvertToParent(&frame);
// fParent->ClipToParent(&frame);
// }
BRect dirty(layer->Frame());
dirty = dirty & Bounds();
ConvertToTop(&dirty);
BRegion dirtyRegion(dirty);
fWindow->MarkContentDirty(&dirtyRegion);
} }
} }
@@ -155,6 +167,7 @@ ViewLayer::RemoveChild(ViewLayer* layer)
} }
if (fWindow) { if (fWindow) {
layer->DetachedFromWindow(); layer->DetachedFromWindow();
// TODO: handle exposed area
} }
return true; return true;
@@ -290,16 +303,14 @@ ViewLayer::SetName(const char* string)
fName.SetTo(string); fName.SetTo(string);
} }
#define HW_MOVE 0 #if 0
// MoveBy // MoveBy
void void
ViewLayer::MoveBy(int32 x, int32 y) ViewLayer::MoveBy(int32 x, int32 y, BRegion* dirtyRegion)
{ {
if (x == 0 && y == 0) if (x == 0 && y == 0)
return; return;
#if HW_MOVE
if (!fIsTopLayer && fWindow) { if (!fIsTopLayer && fWindow) {
// blit to new location (children as well) // blit to new location (children as well)
BRect screenRect; BRect screenRect;
@@ -355,21 +366,46 @@ if (fParent) {
fFrame.OffsetBy(x, y); fFrame.OffsetBy(x, y);
_MoveScreenClipping(x, y, true); _MoveScreenClipping(x, y, true);
} }
#else // HW_MOVE
fFrame.OffsetBy(x, y); fFrame.OffsetBy(x, y);
_MoveScreenClipping(x, y, true);
if (!fIsTopLayer && fWindow) {
BRect screenRect(Bounds());
ConvertToTop(&screenRect);
screenRect = screenRect | screenRect.OffsetByCopy(-x, -y);
BRegion dirty(screenRect);
fWindow->MarkDirty(&dirty);
}
#endif // !HW_MOVE
} }
#else // 0
// MoveBy
void
ViewLayer::MoveBy(int32 x, int32 y, BRegion* dirtyRegion)
{
if (x == 0 && y == 0)
return;
fFrame.OffsetBy(x, y);
InvalidateScreenClipping(true);
if (!fIsTopLayer && dirtyRegion) {
if (fParent) {
// clip to parent
BRect oldScreenRect(Bounds());
oldScreenRect.OffsetByCopy(-x, -y);
ConvertToParent(&oldScreenRect);
BRect screenRect(Bounds());
ConvertToParent(&screenRect);
// TODO: see AddLayer
BRect dirty = oldScreenRect | screenRect;
dirty = dirty & fParent->Bounds();
fParent->ConvertToTop(&dirty);
dirtyRegion->Include(dirty);
} else {
BRect screenRect(Bounds());
screenRect = screenRect | screenRect.OffsetByCopy(-x, -y);
ConvertToTop(&screenRect);
dirtyRegion->Include(screenRect);
}
}
}
#endif // 0
// ResizeBy // ResizeBy
void void
@@ -391,7 +427,7 @@ ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
dirty.Exclude(oldBounds & Bounds()); dirty.Exclude(oldBounds & Bounds());
} }
_InvalidateScreenClipping(true); InvalidateScreenClipping(true);
if (dirty.CountRects() > 0) { if (dirty.CountRects() > 0) {
// exclude children, they are expected to // exclude children, they are expected to
@@ -418,14 +454,14 @@ ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
// ScrollBy // ScrollBy
void void
ViewLayer::ScrollBy(int32 x, int32 y) ViewLayer::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion)
{ {
fScrollingOffset.x += x; fScrollingOffset.x += x;
fScrollingOffset.y += y; fScrollingOffset.y += y;
// TODO: CopyRegion... // TODO: CopyRegion...
// TODO: ... // TODO: ...
_InvalidateScreenClipping(true); InvalidateScreenClipping(true);
} }
// ParentResized // ParentResized
@@ -463,7 +499,7 @@ ViewLayer::ParentResized(int32 x, int32 y, BRegion* dirtyRegion)
// MoveBy will change fFrame, so cache it // MoveBy will change fFrame, so cache it
BRect oldFrame = fFrame; BRect oldFrame = fFrame;
MoveBy(newFrame.left - oldFrame.left, MoveBy(newFrame.left - oldFrame.left,
newFrame.top - oldFrame.top); newFrame.top - oldFrame.top, dirtyRegion);
ResizeBy(newFrame.Width() - oldFrame.Width(), ResizeBy(newFrame.Width() - oldFrame.Width(),
newFrame.Height() - oldFrame.Height(), dirtyRegion); newFrame.Height() - oldFrame.Height(), dirtyRegion);
@@ -472,10 +508,11 @@ ViewLayer::ParentResized(int32 x, int32 y, BRegion* dirtyRegion)
// Draw // Draw
void void
ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, bool deep) ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
BRegion* windowContentClipping,bool deep)
{ {
// we can only draw within our own area // we can only draw within our own area
BRegion redraw(ScreenClipping()); BRegion redraw(ScreenClipping(windowContentClipping));
// add the current clipping // add the current clipping
redraw.IntersectWith(effectiveClipping); redraw.IntersectWith(effectiveClipping);
@@ -494,10 +531,11 @@ ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, bool d
if (deep) { if (deep) {
// before passing the clipping on to children, exclude our // before passing the clipping on to children, exclude our
// own region from the available clipping // own region from the available clipping
effectiveClipping->Exclude(&ScreenClipping()); effectiveClipping->Exclude(&ScreenClipping(windowContentClipping));
for (ViewLayer* child = FirstChild(); child; child = NextChild()) { for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
child->Draw(drawingEngine, effectiveClipping, deep); child->Draw(drawingEngine, effectiveClipping,
windowContentClipping, deep);
} }
} }
} }
@@ -587,25 +625,26 @@ ViewLayer::RebuildClipping(bool deep)
// ScreenClipping // ScreenClipping
BRegion& BRegion&
ViewLayer::ScreenClipping() const ViewLayer::ScreenClipping(BRegion* windowContentClipping, bool force) const
{ {
if (!fScreenClippingValid) { if (!fScreenClippingValid || force) {
fScreenClipping = fLocalClipping; fScreenClipping = fLocalClipping;
ConvertToTop(&fScreenClipping); ConvertToTop(&fScreenClipping);
fScreenClipping.IntersectWith(windowContentClipping);
fScreenClippingValid = true; fScreenClippingValid = true;
} }
return fScreenClipping; return fScreenClipping;
} }
// _InvalidateScreenClipping // InvalidateScreenClipping
void void
ViewLayer::_InvalidateScreenClipping(bool deep) ViewLayer::InvalidateScreenClipping(bool deep)
{ {
fScreenClippingValid = false; fScreenClippingValid = false;
if (deep) { if (deep) {
// invalidate the childrens screen clipping as well // invalidate the childrens screen clipping as well
for (ViewLayer* child = FirstChild(); child; child = NextChild()) { for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
child->_InvalidateScreenClipping(deep); child->InvalidateScreenClipping(deep);
} }
} }
} }
@@ -618,7 +657,7 @@ ViewLayer::_MoveScreenClipping(int32 x, int32 y, bool deep)
fScreenClipping.OffsetBy(x, y); fScreenClipping.OffsetBy(x, y);
if (deep) { if (deep) {
// invalidate the childrens screen clipping as well // move the childrens screen clipping as well
for (ViewLayer* child = FirstChild(); child; child = NextChild()) { for (ViewLayer* child = FirstChild(); child; child = NextChild()) {
child->_MoveScreenClipping(x, y, deep); child->_MoveScreenClipping(x, y, deep);
} }
@@ -62,20 +62,26 @@ class ViewLayer {
inline const char* Name() const inline const char* Name() const
{ return fName.String(); } { return fName.String(); }
void MoveBy(int32 dx, int32 dy); void MoveBy( int32 dx, int32 dy,
void ResizeBy(int32 dx, int32 dy, BRegion* dirtyRegion); BRegion* dirtyRegion);
void ScrollBy(int32 dx, int32 dy);
void ParentResized(int32 dx, int32 dy, void ResizeBy( int32 dx, int32 dy,
BRegion* dirtyRegion);
void ScrollBy( int32 dx, int32 dy,
BRegion* dirtyRegion);
void ParentResized( int32 dx, int32 dy,
BRegion* dirtyRegion); BRegion* dirtyRegion);
// for background clearing // for background clearing
void Draw(DrawingEngine* drawingEngine, void Draw( DrawingEngine* drawingEngine,
BRegion* effectiveClipping, BRegion* effectiveClipping,
BRegion* windowContentClipping,
bool deep = false); bool deep = false);
// to simulate drawing done from client side // to simulate drawing triggered from client side
void ClientDraw(DrawingEngine* drawingEngine, void ClientDraw( DrawingEngine* drawingEngine,
BRegion* effectiveClipping); BRegion* effectiveClipping);
bool IsHidden() const; bool IsHidden() const;
@@ -84,13 +90,15 @@ class ViewLayer {
// clipping // clipping
void RebuildClipping(bool deep); void RebuildClipping(bool deep);
BRegion& ScreenClipping() const; BRegion& ScreenClipping(BRegion* windowContentClipping,
bool force = false) const;
// debugging // debugging
void PrintToStream() const; void PrintToStream() const;
void InvalidateScreenClipping(bool deep);
private: private:
void _InvalidateScreenClipping(bool deep);
void _MoveScreenClipping(int32 x, int32 y, void _MoveScreenClipping(int32 x, int32 y,
bool deep); bool deep);
@@ -18,12 +18,16 @@ WindowLayer::WindowLayer(BRect frame, const char* name,
DrawingEngine* drawingEngine, Desktop* desktop) DrawingEngine* drawingEngine, Desktop* desktop)
: BLooper(name), : BLooper(name),
fFrame(frame), fFrame(frame),
fVisibleRegion(), fVisibleRegion(),
fVisibleContentRegion(),
fBorderRegion(), fBorderRegion(),
fBorderRegionValid(false), fBorderRegionValid(false),
fContentRegion(), fContentRegion(),
fContentRegionValid(false), fContentRegionValid(false),
fEffectiveDrawingRegion(),
fEffectiveDrawingRegionValid(false),
fFocus(false), fFocus(false),
@@ -103,10 +107,18 @@ WindowLayer::MessageReceived(BMessage* message)
void void
WindowLayer::SetClipping(BRegion* stillAvailableOnScreen) WindowLayer::SetClipping(BRegion* stillAvailableOnScreen)
{ {
// this function is only called from the Desktop thread
// start from full region (as if the window was fully visible) // start from full region (as if the window was fully visible)
GetFullRegion(&fVisibleRegion); GetFullRegion(&fVisibleRegion);
// clip to region still available on screen // clip to region still available on screen
fVisibleRegion.IntersectWith(stillAvailableOnScreen); fVisibleRegion.IntersectWith(stillAvailableOnScreen);
GetContentRegion(&fVisibleContentRegion);
fVisibleContentRegion.IntersectWith(&fVisibleRegion);
fEffectiveDrawingRegionValid = false;
fTopLayer->InvalidateScreenClipping(true);
} }
// GetFullRegion // GetFullRegion
@@ -123,45 +135,48 @@ WindowLayer::GetFullRegion(BRegion* region) const
// GetBorderRegion // GetBorderRegion
void void
WindowLayer::GetBorderRegion(BRegion* region) const WindowLayer::GetBorderRegion(BRegion* region)
{ {
if (fBorderRegionValid) { if (!fBorderRegionValid) {
*region = fBorderRegion;
}
// TODO: speed up by avoiding "Exclude()" // TODO: speed up by avoiding "Exclude()"
// start from the frame, extend to include decorator border // start from the frame, extend to include decorator border
region->Set(BRect(fFrame.left - 4, fFrame.top - 4, fBorderRegion.Set(BRect(fFrame.left - 4, fFrame.top - 4,
fFrame.right + 4, fFrame.bottom + 4)); fFrame.right + 4, fFrame.bottom + 4));
region->Exclude(fFrame); fBorderRegion.Exclude(fFrame);
// add the title tab // add the title tab
region->Include(BRect(fFrame.left - 4, fFrame.top - 20, fBorderRegion.Include(BRect(fFrame.left - 4, fFrame.top - 20,
(fFrame.left + fFrame.right) / 2, fFrame.top - 5)); (fFrame.left + fFrame.right) / 2, fFrame.top - 5));
// resize handle // resize handle
// if (B_DOCUMENT_WINDOW_LOOK) // if (B_DOCUMENT_WINDOW_LOOK)
region->Include(BRect(fFrame.right - 10, fFrame.bottom - 10, fBorderRegion.Include(BRect(fFrame.right - 10, fFrame.bottom - 10,
fFrame.right, fFrame.bottom)); fFrame.right, fFrame.bottom));
fBorderRegionValid = true;
}
*region = fBorderRegion;
} }
// GetContentRegion // GetContentRegion
void void
WindowLayer::GetContentRegion(BRegion* region) const WindowLayer::GetContentRegion(BRegion* region)
{ {
if (fContentRegionValid) { if (!fContentRegionValid) {
*region = fContentRegion;
}
// TODO: speed up by avoiding "Exclude()" // TODO: speed up by avoiding "Exclude()"
// start from the frame, extend to include decorator border // start from the frame, extend to include decorator border
region->Set(fFrame); fContentRegion.Set(fFrame);
// resize handle // resize handle
// if (B_DOCUMENT_WINDOW_LOOK) // if (B_DOCUMENT_WINDOW_LOOK)
region->Exclude(BRect(fFrame.right - 10, fFrame.bottom - 10, fContentRegion.Exclude(BRect(fFrame.right - 10, fFrame.bottom - 10,
fFrame.right, fFrame.bottom)); fFrame.right, fFrame.bottom));
fContentRegionValid = true;
}
*region = fContentRegion;
} }
// SetFocus // SetFocus
@@ -189,6 +204,8 @@ WindowLayer::SetFocus(bool focus)
void void
WindowLayer::MoveBy(int32 x, int32 y) WindowLayer::MoveBy(int32 x, int32 y)
{ {
// this function is only called from the desktop thread
if (x == 0 && y == 0) if (x == 0 && y == 0)
return; return;
@@ -204,9 +221,11 @@ WindowLayer::MoveBy(int32 x, int32 y)
if (fPendingUpdateSession) if (fPendingUpdateSession)
fPendingUpdateSession->MoveBy(x, y); fPendingUpdateSession->MoveBy(x, y);
fTopLayer->MoveBy(x, y); fEffectiveDrawingRegionValid = false;
// TODO: move a local dirty region! fTopLayer->MoveBy(x, y, NULL);
// the desktop will take care of dirty regions
} }
// ResizeBy // ResizeBy
@@ -219,18 +238,21 @@ WindowLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
fFrame.right += x; fFrame.right += x;
fFrame.bottom += y; fFrame.bottom += y;
// put the previous border region into the dirty region as well
// to handle the part that was overlapping a layer
dirtyRegion->Include(&fBorderRegion);
fBorderRegionValid = false; fBorderRegionValid = false;
fContentRegionValid = false; fContentRegionValid = false;
fEffectiveDrawingRegionValid = false;
// the border is dirty, put it into // the border is dirty, put it into
// dirtyRegion for a start // dirtyRegion for a start
GetBorderRegion(dirtyRegion); BRegion newBorderRegion;
GetBorderRegion(&newBorderRegion);
// put the previous border region into the dirty region as well dirtyRegion->Include(&newBorderRegion);
// to handle the part that was overlapping a layer
// if B_DOCUMENT_WINDOW_LOOK
dirtyRegion->Include(&fBorderRegion);
// TODO: should this be clipped to the content region?
fTopLayer->ResizeBy(x, y, dirtyRegion); fTopLayer->ResizeBy(x, y, dirtyRegion);
} }
@@ -259,6 +281,19 @@ WindowLayer::MarkDirty(BRegion* regionOnScreen)
fDesktop->MarkDirty(regionOnScreen); fDesktop->MarkDirty(regionOnScreen);
} }
// MarkDirty
void
WindowLayer::MarkContentDirty(BRegion* regionOnScreen)
{
if (fDesktop && fDesktop->LockClipping()) {
regionOnScreen->IntersectWith(&fVisibleContentRegion);
fDesktop->MarkDirty(regionOnScreen);
fDesktop->UnlockClipping();
}
}
/*
// DirtyRegion // DirtyRegion
BRegion BRegion
WindowLayer::DirtyRegion() WindowLayer::DirtyRegion()
@@ -270,7 +305,7 @@ WindowLayer::DirtyRegion()
} }
return dirty; return dirty;
} }
*/
# pragma mark - # pragma mark -
// _DrawContents // _DrawContents
@@ -285,30 +320,23 @@ WindowLayer::_DrawContents(ViewLayer* layer)
if (!layer) if (!layer)
layer = fTopLayer; layer = fTopLayer;
if (!fContentRegionValid) { if (fDesktop->ReadLockClipping()) {
GetContentRegion(&fContentRegion);
fContentRegionValid = true;
}
BRegion effectiveWindowClipping(fContentRegion); BRegion effectiveWindowClipping(fVisibleContentRegion);
// TODO: simplify
// ideally, there would only be a local fDirtyRegion,
// that we need to intersect with. fDirtyRegion would
// already only include fVisibleRegion
effectiveWindowClipping.IntersectWith(&fVisibleRegion);
effectiveWindowClipping.IntersectWith(fDesktop->DirtyRegion()); effectiveWindowClipping.IntersectWith(fDesktop->DirtyRegion());
if (effectiveWindowClipping.Frame().IsValid()) { if (effectiveWindowClipping.Frame().IsValid()) {
// send UPDATE message to the client here // send UPDATE message to the client
_MarkContentDirty(&effectiveWindowClipping); _MarkContentDirty(&effectiveWindowClipping);
layer->Draw(fDrawingEngine, &effectiveWindowClipping, true); layer->Draw(fDrawingEngine, &effectiveWindowClipping,
&fVisibleContentRegion, true);
fDesktop->MarkClean(&fContentRegion); fDesktop->MarkClean(&fContentRegion);
} }
//else {
//printf(" nothing to do\n");
//}
fDesktop->ReadUnlockClipping();
}
} }
// _DrawClient // _DrawClient
@@ -319,22 +347,25 @@ WindowLayer::_DrawClient(int32 token)
if (!layer) if (!layer)
return; return;
BRegion effectiveClipping(layer->ScreenClipping()); if (fDesktop->ReadLockClipping()) {
if (!fEffectiveDrawingRegionValid) {
fEffectiveDrawingRegion = fVisibleContentRegion;
if (fInUpdate) { if (fInUpdate) {
// enforce the dirty region of the update session // enforce the dirty region of the update session
effectiveClipping.IntersectWith(&fCurrentUpdateSession->DirtyRegion()); fEffectiveDrawingRegion.IntersectWith(&fCurrentUpdateSession->DirtyRegion());
} else { } else {
printf("%s - _DrawClient(token: %ld) - not in update\n", Name(), token); printf("%s - _DrawClient(token: %ld) - not in update\n", Name(), token);
}
fEffectiveDrawingRegionValid = true;
} }
if (effectiveClipping.CountRects() > 0 && fDesktop->ReadLockClipping()) { BRegion effectiveClipping(fEffectiveDrawingRegion);
effectiveClipping.IntersectWith(&fVisibleRegion); effectiveClipping.IntersectWith(&layer->ScreenClipping(&fVisibleContentRegion));
// TODO: This step seems too much
BRegion contentRegion;
GetContentRegion(&contentRegion);
effectiveClipping.IntersectWith(&contentRegion);
if (effectiveClipping.CountRects() > 0) {
layer->ClientDraw(fDrawingEngine, &effectiveClipping); layer->ClientDraw(fDrawingEngine, &effectiveClipping);
}
fDesktop->ReadUnlockClipping(); fDesktop->ReadUnlockClipping();
} }
@@ -348,14 +379,11 @@ WindowLayer::_DrawBorder()
#if SLOW_DRAWING #if SLOW_DRAWING
snooze(10000); snooze(10000);
#endif #endif
if (fDesktop->ReadLockClipping()) {
if (!fBorderRegionValid) {
GetBorderRegion(&fBorderRegion);
fBorderRegionValid = true;
}
// construct the region of the border that needs redrawing // construct the region of the border that needs redrawing
BRegion dirtyBorderRegion(fBorderRegion); BRegion dirtyBorderRegion;
GetBorderRegion(&dirtyBorderRegion);
// intersect with our visible region // intersect with our visible region
dirtyBorderRegion.IntersectWith(&fVisibleRegion); dirtyBorderRegion.IntersectWith(&fVisibleRegion);
// intersect with the Desktop's dirty region // intersect with the Desktop's dirty region
@@ -373,9 +401,9 @@ WindowLayer::_DrawBorder()
} }
fDesktop->MarkClean(&dirtyBorderRegion); fDesktop->MarkClean(&dirtyBorderRegion);
} }
//else {
//printf(" nothing to do\n"); fDesktop->ReadUnlockClipping();
//} }
} }
// _MarkContentDirty // _MarkContentDirty
@@ -52,8 +52,8 @@ class WindowLayer : public BLooper {
inline BRegion& VisibleRegion() inline BRegion& VisibleRegion()
{ return fVisibleRegion; } { return fVisibleRegion; }
void GetFullRegion(BRegion* region) const; void GetFullRegion(BRegion* region) const;
void GetBorderRegion(BRegion* region) const; void GetBorderRegion(BRegion* region);
void GetContentRegion(BRegion* region) const; void GetContentRegion(BRegion* region);
void SetFocus(bool focus); void SetFocus(bool focus);
@@ -63,11 +63,12 @@ class WindowLayer : public BLooper {
void AddChild(ViewLayer* layer); void AddChild(ViewLayer* layer);
void MarkDirty(BRegion* regionOnScreen); void MarkDirty(BRegion* regionOnScreen);
void MarkContentDirty(BRegion* regionOnScreen);
DrawingEngine* GetDrawingEngine() const DrawingEngine* GetDrawingEngine() const
{ return fDrawingEngine; } { return fDrawingEngine; }
BRegion DirtyRegion(); // BRegion DirtyRegion();
private: private:
void _DrawContents(ViewLayer* layer = NULL); void _DrawContents(ViewLayer* layer = NULL);
@@ -84,12 +85,15 @@ class WindowLayer : public BLooper {
// Desktop thread, when using it, Desktop::LockClipping() // Desktop thread, when using it, Desktop::LockClipping()
// has to be called // has to be called
BRegion fVisibleRegion; BRegion fVisibleRegion;
BRegion fVisibleContentRegion;
// caching local regions // caching local regions
BRegion fBorderRegion; BRegion fBorderRegion;
bool fBorderRegionValid; bool fBorderRegionValid;
BRegion fContentRegion; BRegion fContentRegion;
bool fContentRegionValid; bool fContentRegionValid;
BRegion fEffectiveDrawingRegion;
bool fEffectiveDrawingRegionValid;
bool fFocus; bool fFocus;