haiku/src/servers/app/ViewLayer.cpp

1155 lines
26 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2001-2006, Haiku, Inc.
* Distributed under the terms of the MIT license.
*
* Authors:
* DarkWyrm <bpmagic@columbus.rr.com>
* Adi Oanca <adioanca@gmail.com>
* Axel Dörfler, axeld@pinc-software.de
* Stephan Aßmus <superstippi@gmx.de>
*/
#include "ViewLayer.h"
#include "BitmapManager.h"
#include "Desktop.h"
#include "DrawingEngine.h"
#include "ServerApp.h"
#include "ServerBitmap.h"
#include "ServerPicture.h"
#include "ServerWindow.h"
#include "WindowLayer.h"
#include <List.h>
ServerFont: * fixed weird pointer conversion in SetStyle() * fixed a potential mix up in operator=() in case the other ServerFont has fStyle == NULL ServerWindow: * the WindowLayer fTopLayer cannot be deleted by client request, just for safety reasons * the link is flushed if there is no drawing engine, but this case is theoretical only * deleting the ServerWindow object syncs with the client, so that when BBitmaps are deleted, they can be sure there are no pending messages (which would be executed in a nother thread) * there is no timeout anymore when sending messages to the client, which made absolutely no sense AGGTextRenderer: * renamed fFontManager to fFontCache, because that's what it really is * fLastFamilyAndStyle defaulted to the system plain font and therefor that font was never loaded when the font never changed meanwhile DrawingMode: * I'm not quite sure but I think there was the potential of a division by zero, at least I had crashes with "divide error" HWInterface: * fix update when the cursor shape changed in double buffered mode ViewLayer: * since the top layer is never really deleted before its time has come, it is not necessary to set it to NULL in the ViewLayer destructor ViewLayer/WindowLayer: * added a function to collect the view tokens that are affected by an update session EventDispatcher: * use the importance of the message for the timeout in _SendMessage() * drop mouse moved events in the server if we're lagging behind more than 5 ms (Axel, maybe review) View: * there were some problems with the locking of the BWindow looper in RemoveSelf(), since this is called from the window destructor, also of BWindows from BBitmaps, which have never been run (this might need review), at least I seem to have solved the crashing problems introduced by actually deleting the view hirarchy in the BWindow destructor * fixed _Draw() for being used non-recursively, temporarily disabled DrawAfterChildren, which didn't work yet anyways (because views cannot draw over children in the server yet) Window: * small cleanup when deleting shortcuts * sync with the server when having send AS_DELETE_WINDOW (see ServerWindow above) * fixed locking in Begin/EndViewTransaction() * removed folding of _UPDATE_ messages, since there is only one ever in the queue * set the fInTransaction flag during an update, I plan to use this in BView later to flush the link when drawing outside of an update * BView::_Draw() is now called by view token, this gives the next leap forward in speed, the overhead because of drawing clean views was considerable git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15878 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-01-09 01:04:52 +03:00
#include <Message.h>
#include <PortLink.h>
#include <View.h> // for resize modes
#include <stdio.h>
#include <new>
using std::nothrow;
ViewLayer::ViewLayer(BRect frame, const char* name,
int32 token, uint32 resizeMode, uint32 flags)
:
fName(name),
fToken(token),
fFrame(frame),
fScrollingOffset(0.0, 0.0),
fViewColor(RGBColor(255, 255, 255)),
fDrawState(new (nothrow) DrawState),
fViewBitmap(NULL),
fResizeMode(resizeMode),
fFlags(flags),
// ViewLayers start visible by default
fHidden(false),
fVisible(true),
fBackgroundDirty(true),
fEventMask(0),
fEventOptions(0),
fWindow(NULL),
fParent(NULL),
fFirstChild(NULL),
fPreviousSibling(NULL),
fNextSibling(NULL),
fLastChild(NULL),
fCursor(NULL),
fPicture(NULL),
fLocalClipping(Bounds()),
fScreenClipping(),
fScreenClippingValid(false)
{
fFrame.left = float((int32)fFrame.left);
fFrame.top = float((int32)fFrame.top);
fFrame.right = float((int32)fFrame.right);
fFrame.bottom = float((int32)fFrame.bottom);
if (fDrawState)
fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
}
// destructor
ViewLayer::~ViewLayer()
{
if (fViewBitmap != NULL)
gBitmapManager->DeleteBitmap(fViewBitmap);
delete fDrawState;
ServerFont: * fixed weird pointer conversion in SetStyle() * fixed a potential mix up in operator=() in case the other ServerFont has fStyle == NULL ServerWindow: * the WindowLayer fTopLayer cannot be deleted by client request, just for safety reasons * the link is flushed if there is no drawing engine, but this case is theoretical only * deleting the ServerWindow object syncs with the client, so that when BBitmaps are deleted, they can be sure there are no pending messages (which would be executed in a nother thread) * there is no timeout anymore when sending messages to the client, which made absolutely no sense AGGTextRenderer: * renamed fFontManager to fFontCache, because that's what it really is * fLastFamilyAndStyle defaulted to the system plain font and therefor that font was never loaded when the font never changed meanwhile DrawingMode: * I'm not quite sure but I think there was the potential of a division by zero, at least I had crashes with "divide error" HWInterface: * fix update when the cursor shape changed in double buffered mode ViewLayer: * since the top layer is never really deleted before its time has come, it is not necessary to set it to NULL in the ViewLayer destructor ViewLayer/WindowLayer: * added a function to collect the view tokens that are affected by an update session EventDispatcher: * use the importance of the message for the timeout in _SendMessage() * drop mouse moved events in the server if we're lagging behind more than 5 ms (Axel, maybe review) View: * there were some problems with the locking of the BWindow looper in RemoveSelf(), since this is called from the window destructor, also of BWindows from BBitmaps, which have never been run (this might need review), at least I seem to have solved the crashing problems introduced by actually deleting the view hirarchy in the BWindow destructor * fixed _Draw() for being used non-recursively, temporarily disabled DrawAfterChildren, which didn't work yet anyways (because views cannot draw over children in the server yet) Window: * small cleanup when deleting shortcuts * sync with the server when having send AS_DELETE_WINDOW (see ServerWindow above) * fixed locking in Begin/EndViewTransaction() * removed folding of _UPDATE_ messages, since there is only one ever in the queue * set the fInTransaction flag during an update, I plan to use this in BView later to flush the link when drawing outside of an update * BView::_Draw() is now called by view token, this gives the next leap forward in speed, the overhead because of drawing clean views was considerable git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15878 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-01-09 01:04:52 +03:00
// if (fWindow && this == fWindow->TopLayer())
// fWindow->SetTopLayer(NULL);
//
// TODO: Don't know yet if we should also delete fPicture
// iterate over children and delete each one
ViewLayer* layer = fFirstChild;
while (layer) {
ViewLayer* toast = layer;
layer = layer->fNextSibling;
delete toast;
}
}
// Bounds
BRect
ViewLayer::Bounds() const
{
BRect bounds(fScrollingOffset.x, fScrollingOffset.y,
fScrollingOffset.x + fFrame.Width(),
fScrollingOffset.y + fFrame.Height());
return bounds;
}
// ConvertToVisibleInTopView
void
ViewLayer::ConvertToVisibleInTopView(BRect* bounds) const
{
*bounds = *bounds & Bounds();
// NOTE: this step is necessary even if we don't have a parent!
ConvertToParent(bounds);
if (fParent)
fParent->ConvertToVisibleInTopView(bounds);
}
// AttachedToWindow
void
ViewLayer::AttachedToWindow(WindowLayer* window)
{
fWindow = window;
// insert view into local token space
if (fWindow != NULL)
fWindow->ServerWindow()->App()->ViewTokens().SetToken(fToken, B_HANDLER_TOKEN, this);
// attach child views as well
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling())
child->AttachedToWindow(window);
}
// DetachedFromWindow
void
ViewLayer::DetachedFromWindow()
{
// remove view from local token space
if (fWindow != NULL)
fWindow->ServerWindow()->App()->ViewTokens().RemoveToken(fToken);
fWindow = NULL;
// detach child views as well
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling())
child->DetachedFromWindow();
}
// AddChild
void
ViewLayer::AddChild(ViewLayer* layer)
{
if (layer->fParent) {
printf("ViewLayer::AddChild() - ViewLayer already has a parent\n");
return;
}
layer->fParent = this;
if (!fLastChild) {
// no children yet
fFirstChild = layer;
} else {
// append layer to formerly last child
fLastChild->fNextSibling = layer;
layer->fPreviousSibling = fLastChild;
}
fLastChild = layer;
if (layer->IsVisible())
RebuildClipping(false);
if (fWindow) {
layer->AttachedToWindow(fWindow);
if (fVisible && layer->IsVisible()) {
// trigger redraw
BRect clippedFrame = layer->Frame();
ConvertToVisibleInTopView(&clippedFrame);
BRegion dirty(clippedFrame);
fWindow->MarkContentDirty(dirty);
}
}
}
bool
ViewLayer::RemoveChild(ViewLayer* layer)
{
if (layer->fParent != this) {
printf("ViewLayer::RemoveChild(%p - %s) - ViewLayer is not child of this (%p) layer!\n", layer, layer ? layer->Name() : NULL, this);
return false;
}
layer->fParent = NULL;
if (fLastChild == layer)
fLastChild = layer->fPreviousSibling;
// layer->fNextSibling would be NULL
if (fFirstChild == layer )
fFirstChild = layer->fNextSibling;
// layer->fPreviousSibling would be NULL
// connect child before and after layer
if (layer->fPreviousSibling)
layer->fPreviousSibling->fNextSibling = layer->fNextSibling;
if (layer->fNextSibling)
layer->fNextSibling->fPreviousSibling = layer->fPreviousSibling;
// layer has no siblings anymore
layer->fPreviousSibling = NULL;
layer->fNextSibling = NULL;
if (layer->IsVisible())
RebuildClipping(false);
if (fWindow) {
layer->DetachedFromWindow();
if (fVisible && layer->IsVisible()) {
// trigger redraw
BRect clippedFrame = layer->Frame();
ConvertToVisibleInTopView(&clippedFrame);
BRegion dirty(clippedFrame);
fWindow->MarkContentDirty(dirty);
}
}
return true;
}
ViewLayer*
ViewLayer::FirstChild() const
{
return fFirstChild;
}
ViewLayer*
ViewLayer::PreviousSibling() const
{
return fPreviousSibling;
}
ViewLayer*
ViewLayer::NextSibling() const
{
return fNextSibling;
}
ViewLayer*
ViewLayer::LastChild() const
{
return fLastChild;
}
ViewLayer*
ViewLayer::TopLayer()
{
// returns the top level view of the hirarchy,
// it doesn't have to be the top level of a window
if (fParent)
return fParent->TopLayer();
return this;
}
// CountChildren
uint32
ViewLayer::CountChildren(bool deep) const
{
uint32 count = 0;
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling()) {
count++;
if (deep) {
count += child->CountChildren(deep);
}
}
return count;
}
// CollectTokensForChildren
void
ViewLayer::CollectTokensForChildren(BList* tokenMap) const
{
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling()) {
tokenMap->AddItem((void*)child);
child->CollectTokensForChildren(tokenMap);
}
}
// ViewAt
ViewLayer*
ViewLayer::ViewAt(const BPoint& where, BRegion* windowContentClipping)
{
if (!fVisible)
return NULL;
if (ScreenClipping(windowContentClipping).Contains(where))
return this;
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling()) {
ViewLayer* layer = child->ViewAt(where, windowContentClipping);
if (layer)
return layer;
}
return NULL;
}
void
ViewLayer::SetFlags(uint32 flags)
{
fFlags = flags;
fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
}
BPoint
ViewLayer::ScrollingOffset() const
{
return fScrollingOffset;
}
void
ViewLayer::SetDrawingOrigin(BPoint origin)
{
fDrawState->SetOrigin(origin);
// rebuild clipping
if (fDrawState->ClippingRegion())
RebuildClipping(false);
}
BPoint
ViewLayer::DrawingOrigin() const
{
BPoint origin(fDrawState->Origin());
float scale = Scale();
origin.x *= scale;
origin.y *= scale;
return origin;
}
void
ViewLayer::SetScale(float scale)
{
fDrawState->SetScale(scale);
// rebuild clipping
if (fDrawState->ClippingRegion())
RebuildClipping(false);
}
float
ViewLayer::Scale() const
{
return CurrentState()->Scale();
}
void
ViewLayer::SetUserClipping(const BRegion& region)
{
fDrawState->SetClippingRegion(region);
// rebuild clipping (for just this view)
RebuildClipping(false);
}
void
ViewLayer::SetViewBitmap(ServerBitmap* bitmap, BRect sourceRect,
BRect destRect, int32 resizingMode, int32 options)
{
if (fViewBitmap != NULL)
gBitmapManager->DeleteBitmap(fViewBitmap);
// the caller is allowed to delete the bitmap after setting the background
if (bitmap != NULL)
bitmap->Acquire();
fViewBitmap = bitmap;
fBitmapSource = sourceRect;
fBitmapDestination = destRect;
fBitmapResizingMode = resizingMode;
fBitmapOptions = options;
// round off destination rect to avoid problems
// with drawing the view color around the bitmap
fBitmapDestination.OffsetTo(roundf(fBitmapDestination.left),
roundf(fBitmapDestination.top));
fBitmapDestination.right = roundf(fBitmapDestination.right);
fBitmapDestination.bottom = roundf(fBitmapDestination.bottom);
}
void
ViewLayer::ConvertToParent(BPoint* point) const
{
// remove scrolling offset and convert to parent coordinate space
point->x += fFrame.left - fScrollingOffset.x;
point->y += fFrame.top - fScrollingOffset.y;
}
// ConvertToParent
void
ViewLayer::ConvertToParent(BRect* rect) const
{
// remove scrolling offset and convert to parent coordinate space
rect->OffsetBy(fFrame.left - fScrollingOffset.x,
fFrame.top - fScrollingOffset.y);
}
// ConvertToParent
void
ViewLayer::ConvertToParent(BRegion* region) const
{
// remove scrolling offset and convert to parent coordinate space
region->OffsetBy(fFrame.left - fScrollingOffset.x,
fFrame.top - fScrollingOffset.y);
}
// ConvertFromParent
void
ViewLayer::ConvertFromParent(BPoint* point) const
{
// remove scrolling offset and convert to parent coordinate space
point->x += fScrollingOffset.x - fFrame.left;
point->y += fScrollingOffset.y - fFrame.top;
}
// ConvertFromParent
void
ViewLayer::ConvertFromParent(BRect* rect) const
{
// remove scrolling offset and convert to parent coordinate space
rect->OffsetBy(fScrollingOffset.x - fFrame.left,
fScrollingOffset.y - fFrame.top);
}
// ConvertFromParent
void
ViewLayer::ConvertFromParent(BRegion* region) const
{
// remove scrolling offset and convert to parent coordinate space
region->OffsetBy(fScrollingOffset.x - fFrame.left,
fScrollingOffset.y - fFrame.top);
}
//! converts a point from local to screen coordinate system
void
ViewLayer::ConvertToScreen(BPoint* pt) const
{
ConvertToParent(pt);
if (fParent)
fParent->ConvertToScreen(pt);
}
//! converts a rect from local to screen coordinate system
void
ViewLayer::ConvertToScreen(BRect* rect) const
{
ConvertToParent(rect);
if (fParent)
fParent->ConvertToScreen(rect);
}
//! converts a region from local to screen coordinate system
void
ViewLayer::ConvertToScreen(BRegion* reg) const
{
ConvertToParent(reg);
if (fParent)
fParent->ConvertToScreen(reg);
}
//! converts a point from screen to local coordinate system
void
ViewLayer::ConvertFromScreen(BPoint* pt) const
{
ConvertFromParent(pt);
if (fParent)
fParent->ConvertFromScreen(pt);
}
//! converts a rect from screen to local coordinate system
void
ViewLayer::ConvertFromScreen(BRect* rect) const
{
ConvertFromParent(rect);
if (fParent)
fParent->ConvertFromScreen(rect);
}
//! converts a region from screen to local coordinate system
void
ViewLayer::ConvertFromScreen(BRegion* reg) const
{
ConvertFromParent(reg);
if (fParent)
fParent->ConvertFromScreen(reg);
}
//! converts a point from local *drawing* to screen coordinate system
void
ViewLayer::ConvertToScreenForDrawing(BPoint* point) const
{
fDrawState->Transform(point);
// NOTE: from here on, don't use the
// "*ForDrawing()" versions of the parent!
ConvertToScreen(point);
}
//! converts a rect from local *drawing* to screen coordinate system
void
ViewLayer::ConvertToScreenForDrawing(BRect* rect) const
{
fDrawState->Transform(rect);
// NOTE: from here on, don't use the
// "*ForDrawing()" versions of the parent!
ConvertToScreen(rect);
}
//! converts a region from local *drawing* to screen coordinate system
void
ViewLayer::ConvertToScreenForDrawing(BRegion* region) const
{
fDrawState->Transform(region);
// NOTE: from here on, don't use the
// "*ForDrawing()" versions of the parent!
ConvertToScreen(region);
}
//! converts a point from screen to local coordinate system
void
ViewLayer::ConvertFromScreenForDrawing(BPoint* point) const
{
ConvertFromScreen(point);
fDrawState->InverseTransform(point);
}
void
ViewLayer::SetName(const char* string)
{
fName.SetTo(string);
}
// #pragma mark -
void
ViewLayer::MoveBy(int32 x, int32 y, BRegion* dirtyRegion)
{
if (x == 0 && y == 0)
return;
fFrame.OffsetBy(x, y);
// to move on screen, we must not be hidden and we must have a parent
if (fVisible && fParent && dirtyRegion) {
#if 0
// based on redraw on new location
// the place were we are now visible
BRect newVisibleBounds = Bounds();
// we can use the frame of the old
// local clipping to see which parts need invalidation
BRect oldVisibleBounds(Bounds());
oldVisibleBounds.OffsetBy(-x, -y);
ConvertToScreen(&oldVisibleBounds);
ConvertToVisibleInTopView(&newVisibleBounds);
dirtyRegion->Include(oldVisibleBounds);
// newVisibleBounds already is in screen coords
dirtyRegion->Include(newVisibleBounds);
#else
// blitting version, invalidates
// old contents
BRect oldVisibleBounds(Bounds());
oldVisibleBounds.OffsetBy(-x, -y);
ConvertToScreen(&oldVisibleBounds);
BRect newVisibleBounds(Bounds());
// NOTE: using ConvertToVisibleInTopView()
// instead of ConvertToScreen()! see below
ConvertToVisibleInTopView(&newVisibleBounds);
newVisibleBounds.OffsetBy(-x, -y);
// clipping oldVisibleBounds to newVisibleBounds
// makes sure we don't copy parts hidden under
// parent views
BRegion copyRegion(oldVisibleBounds & newVisibleBounds);
fWindow->CopyContents(&copyRegion, x, y);
BRegion dirty(oldVisibleBounds);
newVisibleBounds.OffsetBy(x, y);
dirty.Exclude(newVisibleBounds);
dirtyRegion->Include(&dirty);
#endif
}
if (!fParent) {
// the top view's screen clipping does not change,
// because no parts are clipped away from parent
// views
_MoveScreenClipping(x, y, true);
} else {
// parts might have been revealed from underneath
// the parent, or might now be hidden underneath
// the parent, this is taken care of when building
// the screen clipping
InvalidateScreenClipping(true);
}
}
// ResizeBy
void
ViewLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
{
if (x == 0 && y == 0)
return;
fFrame.right += x;
fFrame.bottom += y;
if (fVisible && dirtyRegion) {
BRect oldBounds(Bounds());
oldBounds.right -= x;
oldBounds.bottom -= y;
BRegion dirty(Bounds());
dirty.Include(oldBounds);
if (!(fFlags & B_FULL_UPDATE_ON_RESIZE)) {
// the dirty region is just the difference of
// old and new bounds
dirty.Exclude(oldBounds & Bounds());
}
InvalidateScreenClipping(true);
if (dirty.CountRects() > 0) {
// exclude children, they are expected to
// include their own dirty regions in ParentResized()
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling()) {
if (child->IsVisible()) {
BRect previousChildVisible(child->Frame() & oldBounds & Bounds());
if (dirty.Frame().Intersects(previousChildVisible)) {
dirty.Exclude(previousChildVisible);
}
}
}
ConvertToScreen(&dirty);
dirtyRegion->Include(&dirty);
}
}
// layout the children
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling())
child->ParentResized(x, y, dirtyRegion);
// at this point, children are at their new locations,
// so we can rebuild the clipping
// TODO: when the implementation of Hide() and Show() is
// complete, see if this should be avoided
RebuildClipping(false);
}
// ParentResized
void
ViewLayer::ParentResized(int32 x, int32 y, BRegion* dirtyRegion)
{
uint16 rm = fResizeMode & 0x0000FFFF;
BRect newFrame = fFrame;
// follow with left side
if ((rm & 0x0F00U) == _VIEW_RIGHT_ << 8)
newFrame.left += x;
else if ((rm & 0x0F00U) == _VIEW_CENTER_ << 8)
newFrame.left += x / 2;
// follow with right side
if ((rm & 0x000FU) == _VIEW_RIGHT_)
newFrame.right += x;
else if ((rm & 0x000FU) == _VIEW_CENTER_)
newFrame.right += x / 2;
// follow with top side
if ((rm & 0xF000U) == _VIEW_BOTTOM_ << 12)
newFrame.top += y;
else if ((rm & 0xF000U) == _VIEW_CENTER_ << 12)
newFrame.top += y / 2;
// follow with bottom side
if ((rm & 0x00F0U) == _VIEW_BOTTOM_ << 4)
newFrame.bottom += y;
else if ((rm & 0x00F0U) == _VIEW_CENTER_ << 4)
newFrame.bottom += y / 2;
if (newFrame != fFrame) {
// careful, MoveBy will change fFrame
int32 widthDiff = (int32)(newFrame.Width() - fFrame.Width());
int32 heightDiff = (int32)(newFrame.Height() - fFrame.Height());
MoveBy(newFrame.left - fFrame.left,
newFrame.top - fFrame.top, dirtyRegion);
ResizeBy(widthDiff, heightDiff, dirtyRegion);
}
}
// ScrollBy
void
ViewLayer::ScrollBy(int32 x, int32 y, BRegion* dirtyRegion)
{
// blitting version, invalidates
// old contents
// remember old bounds for tracking dirty region
BRect oldBounds(Bounds());
// find the area of the view that can be scrolled,
// contents are shifted in the opposite direction from scrolling
BRect stillVisibleBounds(oldBounds);
stillVisibleBounds.OffsetBy(x, y);
// NOTE: using ConvertToVisibleInTopView()
// instead of ConvertToScreen(), this makes
// sure we don't try to move or invalidate an
// area hidden underneath the parent view
ConvertToVisibleInTopView(&oldBounds);
ConvertToVisibleInTopView(&stillVisibleBounds);
fScrollingOffset.x += x;
fScrollingOffset.y += y;
// do the blit, this will make sure
// that other more complex dirty regions
// are taken care of
BRegion copyRegion(stillVisibleBounds);
fWindow->CopyContents(&copyRegion, -x, -y);
// find the dirty region as far as we are
// concerned
BRegion dirty(oldBounds);
stillVisibleBounds.OffsetBy(-x, -y);
dirty.Exclude(stillVisibleBounds);
dirtyRegion->Include(&dirty);
// the screen clipping of this view and it's
// childs is no longer valid
InvalidateScreenClipping(true);
RebuildClipping(false);
}
void
ViewLayer::CopyBits(BRect src, BRect dst, BRegion& windowContentClipping)
{
if (!fVisible || !fWindow)
return;
// TODO: confirm that in R5 this call is affected by origin and scale
// blitting version
int32 xOffset = (int32)(dst.left - src.left);
int32 yOffset = (int32)(dst.top - src.top);
// figure out which part can be blittet
BRect visibleSrc(src);
ConvertToVisibleInTopView(&visibleSrc);
BRect visibleSrcAtDest(src);
visibleSrcAtDest.OffsetBy(xOffset, yOffset);
ConvertToVisibleInTopView(&visibleSrcAtDest);
// clip src to visible at dest
visibleSrcAtDest.OffsetBy(-xOffset, -yOffset);
visibleSrc = visibleSrc & visibleSrcAtDest;
// do the blit, this will make sure
// that other more complex dirty regions
// are taken care of
BRegion copyRegion(visibleSrc);
copyRegion.IntersectWith(&ScreenClipping(&windowContentClipping));
fWindow->CopyContents(&copyRegion, xOffset, yOffset);
// find the dirty region as far as we are concerned
BRect dirtyDst(dst);
ConvertToVisibleInTopView(&dirtyDst);
BRegion dirty(dirtyDst);
// exclude the part that we could copy
visibleSrc.OffsetBy(xOffset, yOffset);
dirty.Exclude(visibleSrc);
dirty.IntersectWith(&ScreenClipping(&windowContentClipping));
fWindow->MarkContentDirty(dirty);
}
// #pragma mark -
void
ViewLayer::PushState()
{
fDrawState = fDrawState->PushState();
fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
}
void
ViewLayer::PopState()
{
if (fDrawState->PreviousState() == NULL) {
fprintf(stderr, "WARNING: User called BView(%s)::PopState(), "
"but there is NO state on stack!\n", Name());
return;
}
bool rebuildClipping = fDrawState->ClippingRegion() != NULL;
fDrawState = fDrawState->PopState();
fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
// rebuild clipping
// (the clipping from the popped state is not effective anymore)
if (rebuildClipping)
RebuildClipping(false);
}
void
ViewLayer::SetEventMask(uint32 eventMask, uint32 options)
{
fEventMask = eventMask;
fEventOptions = options;
}
void
ViewLayer::SetCursor(ServerCursor *cursor)
{
fCursor = cursor;
}
void
ViewLayer::SetPicture(ServerPicture *picture)
{
fPicture = picture;
}
ServerPicture *
ViewLayer::Picture() const
{
return fPicture;
}
void
ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
BRegion* windowContentClipping, bool deep)
{
if (!fVisible)
return;
// child views can not be visible either
if (fViewBitmap != NULL || !fViewColor.IsTransparentMagic()) {
// we can only draw within our own area
BRegion redraw(ScreenClipping(windowContentClipping));
// add the current clipping
redraw.IntersectWith(effectiveClipping);
if (fViewBitmap != NULL) {
// draw view bitmap
// TODO: support other options!
BRect rect = fBitmapDestination;
ConvertToScreenForDrawing(&rect);
// lock the drawing engine for as long as we need the clipping
// to be valid
if (drawingEngine->Lock()) {
drawingEngine->ConstrainClippingRegion(&redraw);
DrawState defaultDrawState;
drawingEngine->DrawBitmap(fViewBitmap, fBitmapSource,
rect, &defaultDrawState);
// NOTE: It is ok not to reset the clipping, that
// would only waste time
drawingEngine->Unlock();
}
redraw.Exclude(rect);
}
if (!fViewColor.IsTransparentMagic()) {
// fill visible region with view color,
// this version of FillRegion ignores any
// clipping, that's why "redraw" needs to
// be correct
drawingEngine->FillRegion(redraw, fViewColor);
}
}
fBackgroundDirty = false;
// let children draw
if (deep) {
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling()) {
child->Draw(drawingEngine, effectiveClipping,
windowContentClipping, deep);
}
}
}
// #pragma mark -
void
ViewLayer::SetHidden(bool hidden)
{
// TODO: test...
if (fHidden != hidden) {
fHidden = hidden;
// recurse into children and update their visible flag
if (fParent) {
bool oldVisible = fVisible;
UpdateVisibleDeep(fParent->IsVisible());
if (oldVisible != fVisible) {
// include or exclude us from the parent area
fParent->RebuildClipping(false);
if (fWindow) {
// trigger a redraw
BRect clippedBounds = Bounds();
ConvertToVisibleInTopView(&clippedBounds);
BRegion dirty(clippedBounds);
fWindow->MarkContentDirty(dirty);
}
}
} else {
UpdateVisibleDeep(true);
}
}
}
// IsHidden
bool
ViewLayer::IsHidden() const
{
return fHidden;
}
// UpdateVisibleDeep
void
ViewLayer::UpdateVisibleDeep(bool parentVisible)
{
fVisible = parentVisible && !fHidden;
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling())
child->UpdateVisibleDeep(fVisible);
}
// MarkBackgroundDirty
void
ViewLayer::MarkBackgroundDirty()
{
fBackgroundDirty = true;
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling())
child->MarkBackgroundDirty();
}
ServerFont: * fixed weird pointer conversion in SetStyle() * fixed a potential mix up in operator=() in case the other ServerFont has fStyle == NULL ServerWindow: * the WindowLayer fTopLayer cannot be deleted by client request, just for safety reasons * the link is flushed if there is no drawing engine, but this case is theoretical only * deleting the ServerWindow object syncs with the client, so that when BBitmaps are deleted, they can be sure there are no pending messages (which would be executed in a nother thread) * there is no timeout anymore when sending messages to the client, which made absolutely no sense AGGTextRenderer: * renamed fFontManager to fFontCache, because that's what it really is * fLastFamilyAndStyle defaulted to the system plain font and therefor that font was never loaded when the font never changed meanwhile DrawingMode: * I'm not quite sure but I think there was the potential of a division by zero, at least I had crashes with "divide error" HWInterface: * fix update when the cursor shape changed in double buffered mode ViewLayer: * since the top layer is never really deleted before its time has come, it is not necessary to set it to NULL in the ViewLayer destructor ViewLayer/WindowLayer: * added a function to collect the view tokens that are affected by an update session EventDispatcher: * use the importance of the message for the timeout in _SendMessage() * drop mouse moved events in the server if we're lagging behind more than 5 ms (Axel, maybe review) View: * there were some problems with the locking of the BWindow looper in RemoveSelf(), since this is called from the window destructor, also of BWindows from BBitmaps, which have never been run (this might need review), at least I seem to have solved the crashing problems introduced by actually deleting the view hirarchy in the BWindow destructor * fixed _Draw() for being used non-recursively, temporarily disabled DrawAfterChildren, which didn't work yet anyways (because views cannot draw over children in the server yet) Window: * small cleanup when deleting shortcuts * sync with the server when having send AS_DELETE_WINDOW (see ServerWindow above) * fixed locking in Begin/EndViewTransaction() * removed folding of _UPDATE_ messages, since there is only one ever in the queue * set the fInTransaction flag during an update, I plan to use this in BView later to flush the link when drawing outside of an update * BView::_Draw() is now called by view token, this gives the next leap forward in speed, the overhead because of drawing clean views was considerable git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15878 a95241bf-73f2-0310-859d-f6bbb57e9c96
2006-01-09 01:04:52 +03:00
// AddTokensForLayersInRegion
void
ViewLayer::AddTokensForLayersInRegion(BMessage* message,
BRegion& region,
BRegion* windowContentClipping)
{
if (region.Intersects(ScreenClipping(windowContentClipping).Frame()))
message->AddInt32("_token", fToken);
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling())
child->AddTokensForLayersInRegion(message, region,
windowContentClipping);
}
// AddTokensForLayersInRegion
void
ViewLayer::AddTokensForLayersInRegion(BPrivate::PortLink& link,
BRegion& region,
BRegion* windowContentClipping)
{
if (region.Intersects(ScreenClipping(windowContentClipping).Frame()))
link.Attach<int32>(fToken);
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling())
child->AddTokensForLayersInRegion(link, region,
windowContentClipping);
}
// PrintToStream
void
ViewLayer::PrintToStream() const
{
printf("ViewLayer: %s\n", Name());
printf(" fToken: %ld\n", fToken);
printf(" fFrame: BRect(%.1f, %.1f, %.1f, %.1f)\n", fFrame.left, fFrame.top, fFrame.right, fFrame.bottom);
printf(" fScrollingOffset: BPoint(%.1f, %.1f)\n", fScrollingOffset.x, fScrollingOffset.y);
printf(" fHidden: %d\n", fHidden);
printf(" fVisible: %d\n", fVisible);
printf(" fWindow: %p\n", fWindow);
printf(" fParent: %p\n", fParent);
printf(" fLocalClipping:\n");
fLocalClipping.PrintToStream();
printf(" fScreenClipping:\n");
fScreenClipping.PrintToStream();
printf(" valid: %d\n", fScreenClippingValid);
printf(" state:\n");
printf(" user clipping: %p\n", fDrawState->ClippingRegion());
printf(" origin: BPoint(%.1f, %.1f)\n", fDrawState->Origin().x, fDrawState->Origin().y);
printf(" scale: %.2f\n", fDrawState->Scale());
printf("\n");
}
// RebuildClipping
void
ViewLayer::RebuildClipping(bool deep)
{
// the clipping spans over the bounds area
fLocalClipping.Set(Bounds());
// exclude all childs from the clipping
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling()) {
if (child->IsVisible())
fLocalClipping.Exclude(child->Frame());
if (deep)
child->RebuildClipping(deep);
}
// add the user clipping in case there is one
if (const BRegion* userClipping = fDrawState->ClippingRegion()) {
// NOTE: in case the user sets a user defined clipping region,
// rebuilding the clipping is a bit more expensive because there
// is no separate "drawing region"... on the other
// hand, views for which this feature is actually used will
// probably not have any children, so it is not that expensive
// after all
BRegion screenUserClipping(*userClipping);
fDrawState->Transform(&screenUserClipping);
fLocalClipping.IntersectWith(&screenUserClipping);
}
fScreenClippingValid = false;
}
// ScreenClipping
BRegion&
ViewLayer::ScreenClipping(BRegion* windowContentClipping, bool force) const
{
if (!fScreenClippingValid || force) {
fScreenClipping = fLocalClipping;
ConvertToScreen(&fScreenClipping);
// see if we parts of our bounds are hidden underneath
// the parent, the local clipping does not account for this
BRect clippedBounds = Bounds();
ConvertToVisibleInTopView(&clippedBounds);
if (clippedBounds.Width() < fScreenClipping.Frame().Width() ||
clippedBounds.Height() < fScreenClipping.Frame().Height()) {
BRegion temp(clippedBounds);
fScreenClipping.IntersectWith(&temp);
}
fScreenClipping.IntersectWith(windowContentClipping);
fScreenClippingValid = true;
}
//printf("###ViewLayer(%s)::ScreenClipping():\n", Name());
//fScreenClipping.PrintToStream();
return fScreenClipping;
}
// InvalidateScreenClipping
void
ViewLayer::InvalidateScreenClipping(bool deep)
{
fScreenClippingValid = false;
if (deep) {
// invalidate the childrens screen clipping as well
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling()) {
child->InvalidateScreenClipping(deep);
}
}
}
// _MoveScreenClipping
void
ViewLayer::_MoveScreenClipping(int32 x, int32 y, bool deep)
{
if (fScreenClippingValid)
fScreenClipping.OffsetBy(x, y);
if (deep) {
// move the childrens screen clipping as well
for (ViewLayer* child = FirstChild(); child; child = child->NextSibling()) {
child->_MoveScreenClipping(x, y, deep);
}
}
}