diff --git a/headers/private/servers/app/Decorator.h b/headers/private/servers/app/Decorator.h index 8d0c8859be..5d6079b0b8 100644 --- a/headers/private/servers/app/Decorator.h +++ b/headers/private/servers/app/Decorator.h @@ -80,16 +80,15 @@ class Decorator { bool GetMinimize(); bool GetZoom(); - virtual void GetSizeLimits(float* minWidth, float* minHeight, - float* maxWidth, float* maxHeight) const; + virtual void GetSizeLimits(int32* minWidth, int32* minHeight, + int32* maxWidth, int32* maxHeight) const; - - void SetFocus(bool is_active); - bool GetFocus() + void SetFocus(bool focussed); + bool IsFocus() { return fIsFocused; }; - ColorSet GetColors() + ColorSet Colors() { return (_colors) ? *_colors : ColorSet(); } - + virtual void GetFootprint(BRegion *region); virtual click_type Clicked(BPoint pt, int32 buttons, diff --git a/headers/private/servers/app/DrawingEngine.h b/headers/private/servers/app/DrawingEngine.h index 439697475b..53135f92f8 100644 --- a/headers/private/servers/app/DrawingEngine.h +++ b/headers/private/servers/app/DrawingEngine.h @@ -28,8 +28,7 @@ class ServerBitmap; class ServerCursor; class ServerFont; -typedef struct -{ +typedef struct { BPoint pt1; BPoint pt2; rgb_color color; @@ -38,176 +37,134 @@ typedef struct class DrawingEngine { public: - DrawingEngine(HWInterface* interface = NULL); - virtual ~DrawingEngine(); + DrawingEngine(HWInterface* interface = NULL); + virtual ~DrawingEngine(); // when implementing, be sure to call the inherited version - status_t Initialize(); - void Shutdown(); + status_t Initialize(); + void Shutdown(); // locking - bool Lock(); - void Unlock(); + bool Lock(); + void Unlock(); - bool WriteLock(); - void WriteUnlock(); + bool WriteLock(); + void WriteUnlock(); // for "changing" hardware - void Update(); + void Update(); - void SetHWInterface(HWInterface* interface); + void SetHWInterface(HWInterface* interface); // for screen shots - bool DumpToFile( const char *path); - ServerBitmap* DumpToBitmap(); + bool DumpToFile(const char *path); + ServerBitmap* DumpToBitmap(); // clipping for all drawing functions, passing a NULL region // will remove any clipping (drawing allowed everywhere) - void ConstrainClippingRegion(BRegion* region); + void ConstrainClippingRegion(const BRegion* region); // drawing functions - void CopyRegion( /*const*/ BRegion* region, - int32 xOffset, - int32 yOffset); + void CopyRegion(/*const*/ BRegion* region, + int32 xOffset, int32 yOffset); - void CopyRegionList( BList* list, - BList* pList, - int32 rCount, - BRegion* clipReg); + void CopyRegionList(BList* list, BList* pList, + int32 rCount, BRegion* clipReg); - void InvertRect( BRect r); + void InvertRect(BRect r); - void DrawBitmap( ServerBitmap *bitmap, - const BRect &source, - const BRect &dest, - const DrawState *d); + void DrawBitmap(ServerBitmap *bitmap, + const BRect &source, const BRect &dest, + const DrawState *d); // drawing primitives - void DrawArc( BRect r, - const float &angle, - const float &span, - const DrawState *d, - bool filled); + void DrawArc(BRect r, const float &angle, + const float &span, + const DrawState *d, + bool filled); - void DrawBezier( BPoint *pts, - const DrawState *d, - bool filled); + void DrawBezier(BPoint *pts, const DrawState *d, + bool filled); - void DrawEllipse( BRect r, - const DrawState *d, - bool filled); + void DrawEllipse(BRect r, const DrawState *d, + bool filled); - void DrawPolygon( BPoint *ptlist, - int32 numpts, - BRect bounds, - const DrawState *d, - bool filled, - bool closed); + void DrawPolygon(BPoint *ptlist, int32 numpts, + BRect bounds, const DrawState *d, + bool filled, bool closed); // this version used by Decorator - void StrokeRect( BRect r, - const RGBColor &color); + void StrokeRect(BRect r, const RGBColor &color); + void FillRect(BRect r, const RGBColor &color); - void FillRect( BRect r, - const RGBColor &color); - - void StrokeRect( BRect r, - const DrawState *d); - - void FillRect( BRect r, - const DrawState *d); + void StrokeRect(BRect r, const DrawState *d); + void FillRect(BRect r, const DrawState *d); // for debugging purposes? - void StrokeRegion( BRegion &r, - const DrawState *d); + void StrokeRegion(BRegion &r, const DrawState *d); + void FillRegion(BRegion &r, const DrawState *d); + void FillRegion(BRegion &r, const RGBColor& color); - void FillRegion( BRegion &r, - const DrawState *d); + void DrawRoundRect(BRect r, float xrad, + float yrad, const DrawState *d, + bool filled); - void DrawRoundRect( BRect r, - const float &xrad, - const float &yrad, - const DrawState *d, - bool filled); + void DrawShape(const BRect &bounds, + int32 opcount, const uint32 *oplist, + int32 ptcount, const BPoint *ptlist, + const DrawState *d, bool filled); - void DrawShape( const BRect &bounds, - const int32 &opcount, - const uint32 *oplist, - const int32 &ptcount, - const BPoint *ptlist, - const DrawState *d, - bool filled); - - void DrawTriangle( BPoint *pts, - const BRect &bounds, - const DrawState *d, - bool filled); + void DrawTriangle(BPoint *pts, const BRect &bounds, + const DrawState *d, bool filled); // this version used by Decorator - void StrokeLine( const BPoint &start, - const BPoint &end, - const RGBColor &color); + void StrokeLine(const BPoint &start, + const BPoint &end, const RGBColor &color); - void StrokeLine( const BPoint &start, - const BPoint &end, - DrawState *d); + void StrokeLine(const BPoint &start, + const BPoint &end, DrawState *d); - void StrokeLineArray(const int32 &numlines, - const LineArrayData *data, - const DrawState *d); + void StrokeLineArray(int32 numlines, + const LineArrayData *data, + const DrawState *d); // this version used by Decorator - void StrokePoint( const BPoint &pt, - const RGBColor &color); + void StrokePoint(const BPoint &pt, + const RGBColor &color); - void StrokePoint( const BPoint &pt, - DrawState *d); + void StrokePoint(const BPoint &pt, + DrawState *d); // -------- text related calls - + // DrawState is NOT const because this call updates the pen position in the passed DrawState - BPoint DrawString( const char* string, - int32 length, - const BPoint& pt, - DrawState* d, - escapement_delta* delta = NULL); + BPoint DrawString(const char* string, int32 length, + const BPoint& pt, DrawState* d, + escapement_delta* delta = NULL); -/* void DrawString( const char *string, - const int32 &length, - const BPoint &pt, - const RGBColor &color, - escapement_delta *delta=NULL);*/ + float StringWidth(const char* string, int32 length, + const DrawState* d, + escapement_delta* delta = NULL); - float StringWidth( const char* string, - int32 length, - const DrawState* d, - escapement_delta* delta = NULL); + float StringWidth(const char* string, + int32 length, const ServerFont& font, + escapement_delta* delta = NULL); - float StringWidth( const char* string, - int32 length, - const ServerFont& font, - escapement_delta* delta = NULL); - - float StringHeight( const char* string, - int32 length, - const DrawState* d); + float StringHeight(const char* string, + int32 length, const DrawState* d); private: - BRect _CopyRect( BRect r, - int32 xOffset, - int32 yOffset) const; + BRect _CopyRect(BRect r, int32 xOffset, + int32 yOffset) const; - void _CopyRect( uint8* bits, - uint32 width, - uint32 height, - uint32 bpr, - int32 xOffset, - int32 yOffset) const; + void _CopyRect(uint8* bits, uint32 width, + uint32 height, uint32 bytesPerRow, + int32 xOffset, int32 yOffset) const; - Painter* fPainter; - HWInterface* fGraphicsCard; - uint32 fAvailableHWAccleration; + Painter* fPainter; + HWInterface* fGraphicsCard; + uint32 fAvailableHWAccleration; }; #endif // DRAWING_ENGINE_H_ diff --git a/src/servers/app/AppServer.cpp b/src/servers/app/AppServer.cpp index 6d9c3d5b80..5e36c4c366 100644 --- a/src/servers/app/AppServer.cpp +++ b/src/servers/app/AppServer.cpp @@ -20,10 +20,10 @@ #include "FontManager.h" #include "HWInterface.h" #include "InputManager.h" -#include "Layer.h" +//#include "Layer.h" #include "RGBColor.h" #include "RegistrarDefs.h" -#include "RootLayer.h" +//#include "RootLayer.h" #include "ScreenManager.h" #include "ServerApp.h" #include "ServerConfig.h" diff --git a/src/servers/app/BGet++.cpp b/src/servers/app/BGet++.cpp index 077bcf8d26..9e189b96ca 100644 --- a/src/servers/app/BGet++.cpp +++ b/src/servers/app/BGet++.cpp @@ -6,11 +6,11 @@ * John Walker * DarkWyrm * Stephan Aßmus - * - * BGET pool allocator */ /* + BGET pool allocator + This class is based on the BGET pool allocator. Original code was in standard ANSI C with a bunch of static variables. The original code was placed into the MemPool class and the original allocation, release, and compacting functions @@ -49,8 +49,8 @@ #define ESent ((ssize_t) (-(((1L << (sizeof(ssize_t) * 8 - 2)) - 1) * 2) - 2)) -MemPool::MemPool() - : fTotalAlloced(0), +MemPool::MemPool(int32 incrementSize) + : fTotalAllocated(0), fGetCount(0), fReleaseCount(0), fNumpblk(0), @@ -58,7 +58,7 @@ MemPool::MemPool() fNumprel(0), fNumdget(0), fNumdrel(0), - fExpIncr(0), + fIncrementSize(incrementSize), fPoolLength(0) { fFreeList.bh = (bhead){ 0, 0 }; @@ -70,19 +70,17 @@ MemPool::~MemPool() { } -// Allocate a buffer from the available space in the memory pool -void* -MemPool::GetBuffer(ssize_t requested_size, bool zero) -{ - ssize_t size = requested_size; - void *buf; +//! Allocate a buffer from the available space in the memory pool +void* +MemPool::GetBuffer(ssize_t requestedSize, bool zero) +{ + ssize_t size = requestedSize; int compactseq = 0; assert(size > 0); - if (size < (ssize_t)SizeQ) - { + if (size < (ssize_t)SizeQ) { // Need at least room for the queue links. size = SizeQ; } @@ -99,158 +97,134 @@ MemPool::GetBuffer(ssize_t requested_size, bool zero) // If a compact function was provided in the call to bectl(), wrap // a loop around the allocation process to allow compaction to // intervene in case we don't find a suitable buffer in the chain. - while (1) - { + while (1) { b = fFreeList.ql.flink; best = &fFreeList; - - + // Scan the free list searching for the first buffer big enough // to hold the requested size buffer. - - while (b != &fFreeList) - { - if (b->bh.bsize >= size) - { - if ((best == &fFreeList) || (b->bh.bsize < best->bh.bsize)) - { + + while (b != &fFreeList) { + if (b->bh.bsize >= size) { + if ((best == &fFreeList) || (b->bh.bsize < best->bh.bsize)) { best = b; } } - + b = b->ql.flink; // Link to next buffer } b = best; - - while (b != &fFreeList) - { - if ((ssize_t) b->bh.bsize >= size) - { - + + while (b != &fFreeList) { + if ((ssize_t) b->bh.bsize >= size) { // Buffer is big enough to satisfy the request. Allocate it to the caller. // We must decide whether the buffer is large enough to split into the part // given to the caller and a free buffer that remains on the free list, or // whether the entire buffer should be removed from the free list and given // to the caller in its entirety. We only split the buffer if enough room // remains for a header plus the minimum quantum of allocation. - - if ((b->bh.bsize - size) > (ssize_t)(SizeQ + (sizeof(struct bhead)))) - { + + if ((b->bh.bsize - size) > (ssize_t)(SizeQ + (sizeof(struct bhead)))) { struct bhead *ba, *bn; - + ba = BH(((char *) b) + (b->bh.bsize - size)); bn = BH(((char *) ba) + size); assert(bn->prevfree == b->bh.bsize); - + // Subtract size from length of free block. b->bh.bsize -= size; - + // Link allocated buffer to the previous free buffer. ba->prevfree = b->bh.bsize; - + // Plug negative size into user buffer. ba->bsize = -(ssize_t) size; - + // Mark buffer after this one not preceded by free block. bn->prevfree = 0; - - fTotalAlloced += size; + + fTotalAllocated += size; fGetCount++; // Increment number of GetBuffer() calls - - buf = (void *) ((((char *) ba) + sizeof(struct bhead))); - return buf; - } - else - { + + return (void *)((((char *)ba) + sizeof(struct bhead))); + } else { struct bhead *ba; ba = BH(((char *) b) + b->bh.bsize); assert(ba->prevfree == b->bh.bsize); - + // The buffer isn't big enough to split. Give the whole // shebang to the caller and remove it from the free list. - + assert(b->ql.blink->ql.flink == b); assert(b->ql.flink->ql.blink == b); b->ql.blink->ql.flink = b->ql.flink; b->ql.flink->ql.blink = b->ql.blink; - - fTotalAlloced += b->bh.bsize; + + fTotalAllocated += b->bh.bsize; fGetCount++; // Increment number of GetBuffer() calls - + // Negate size to mark buffer allocated. b->bh.bsize = -(b->bh.bsize); - + // Zero the back pointer in the next buffer in memory // to indicate that this buffer is allocated. ba->prevfree = 0; - + // Give user buffer starting at queue links. - buf = (void *) &(b->ql); - return buf; + return (void *)&(b->ql); } } b = b->ql.flink; // Link to next buffer } - - + // We failed to find a buffer. If there's a compact function // defined, notify it of the size requested. If it returns // TRUE, try the allocation again. - - if(!CompactMem(size, ++compactseq)) + + if (!CompactMem(size, ++compactseq)) break; } // No buffer available with requested size free. // Don't give up yet -- look in the reserve supply. - if (size > (ssize_t)(fExpIncr - sizeof(struct bhead))) - { + if (size > (ssize_t)(fIncrementSize - sizeof(struct bhead))) { // Request is too large to fit in a single expansion // block. Try to satisy it by a direct buffer acquisition. struct bdhead *bdh; size += sizeof(struct bdhead) - sizeof(struct bhead); - if ((bdh = BDH(AcquireMem((ssize_t) size))) != NULL) - { + if ((bdh = BDH(AcquireMem((ssize_t) size))) != NULL) { // Mark the buffer special by setting the size field // of its header to zero. bdh->bh.bsize = 0; bdh->bh.prevfree = 0; bdh->tsize = size; - - fTotalAlloced += size; - + + fTotalAllocated += size; + // Increment number of GetBuffer() calls fGetCount++; - + // Direct GetBuffer() call count fNumdget++; - - buf = (void *) (bdh + 1); - return buf; + + return (void *)(bdh + 1); } - - } - else - { - - // Try to obtain a new expansion block + } else { + // Try to obtain a new expansion block void *newpool; - if ((newpool = AcquireMem((ssize_t) fExpIncr)) != NULL) - { - AddToPool(newpool, fExpIncr); - - // This can't, I say, can't get into a loop - buf = GetBuffer(requested_size); + if ((newpool = AcquireMem((ssize_t)fIncrementSize)) != NULL) { + AddToPool(newpool, fIncrementSize); - return buf; + // This can't, I say, can't get into a loop + return GetBuffer(requestedSize); } } - // Still no buffer available + // Still no buffer available return NULL; // Code from bgetz -- zeroing code @@ -285,116 +259,110 @@ MemPool::GetBuffer(ssize_t requested_size, bool zero) } -// Reallocate a buffer. This is a minimal implementation, simply in terms -// of ReleaseBuffer() and GetBuffer(). It could be enhanced to allow the -// buffer to grow into adjacent free blocks and to avoid moving data unnecessarily. +/*! + Reallocate a buffer. This is a minimal implementation, simply in terms + of ReleaseBuffer() and GetBuffer(). It could be enhanced to allow the + buffer to grow into adjacent free blocks and to avoid moving data + unnecessarily. +*/ void* MemPool::ReallocateBuffer(void *buf, ssize_t size) { - void *nbuf; - - // Old size of buffer - ssize_t osize; - struct bhead *b; + void *nbuf; - if ((nbuf = GetBuffer(size)) == NULL) - { - // Acquire new buffer + // Old size of buffer + ssize_t osize; + struct bhead *b; + + if ((nbuf = GetBuffer(size)) == NULL) { + // Acquire new buffer return NULL; - } - - if (buf == NULL) - { - return nbuf; - } - b = BH(((char *) buf) - sizeof(struct bhead)); - osize = -b->bsize; + } - if (osize == 0) - { + if (buf == NULL) + return nbuf; + + b = BH(((char *) buf) - sizeof(struct bhead)); + osize = -b->bsize; + + if (osize == 0) { // Buffer acquired directly through acqfcn. struct bdhead *bd; - + bd = BDH(((char *) buf) - sizeof(struct bdhead)); osize = bd->tsize - sizeof(struct bdhead); - } - else + } else osize -= sizeof(struct bhead); - assert(osize > 0); - - // Copy the data - memcpy((char *) nbuf, (char *) buf, (int) ((size < osize) ? size : osize)); - ReleaseBuffer(buf); - return nbuf; + + assert(osize > 0); + + // Copy the data + memcpy((char *) nbuf, (char *) buf, (int) ((size < osize) ? size : osize)); + ReleaseBuffer(buf); + return nbuf; } -// BREL -- Release a buffer. + +//! Release a buffer. void MemPool::ReleaseBuffer(void *buf) { struct bfhead *b, *bn; - b = BFH(((char *) buf) - sizeof(struct bhead)); - - // Increment number of ReleaseBuffer() calls - fReleaseCount++; + b = BFH(((char *)buf) - sizeof(struct bhead)); + + // Increment number of ReleaseBuffer() calls + fReleaseCount++; + + assert(buf != NULL); - assert(buf != NULL); - // Directly-acquired buffer? - if (b->bh.bsize == 0) - { + if (b->bh.bsize == 0) { struct bdhead *bdh; - - bdh = BDH(((char *) buf) - sizeof(struct bdhead)); + + bdh = BDH(((char *)buf) - sizeof(struct bdhead)); assert(b->bh.prevfree == 0); - - fTotalAlloced -= bdh->tsize; - assert(fTotalAlloced >= 0); - + + fTotalAllocated -= bdh->tsize; + assert(fTotalAllocated >= 0); + // Number of direct releases fNumdrel++; - - memset((char *) buf, 0x55, (int) (bdh->tsize - sizeof(struct bdhead))); - + + memset((char *)buf, 0x55, (int)(bdh->tsize - sizeof(struct bdhead))); + // Release it directly. - ReleaseMem((void *) bdh); + ReleaseMem((void *)bdh); return; - } + } - - // Buffer size must be negative, indicating that the buffer is allocated. - if (b->bh.bsize >= 0) - { + // Buffer size must be negative, indicating that the buffer is allocated. + if (b->bh.bsize >= 0) bn = NULL; - } - assert(b->bh.bsize < 0); - // Back pointer in next buffer must be zero, indicating the same thing: - assert(BH((char *) b - b->bh.bsize)->prevfree == 0); + assert(b->bh.bsize < 0); - fTotalAlloced += b->bh.bsize; - assert(fTotalAlloced >= 0); + // Back pointer in next buffer must be zero, indicating the same thing: + assert(BH((char *)b - b->bh.bsize)->prevfree == 0); + fTotalAllocated += b->bh.bsize; + assert(fTotalAllocated >= 0); - // If the back link is nonzero, the previous buffer is free. + // If the back link is nonzero, the previous buffer is free. - if (b->bh.prevfree != 0) - { + if (b->bh.prevfree != 0) { // The previous buffer is free. Consolidate this buffer with it // by adding the length of this buffer to the previous free // buffer. Note that we subtract the size in the buffer being // released, since it's negative to indicate that the buffer is allocated. - + register ssize_t size = b->bh.bsize; - - // Make the previous buffer the one we're working on. + + // Make the previous buffer the one we're working on. assert(BH((char *) b - b->bh.prevfree)->bsize == b->bh.prevfree); b = BFH(((char *) b) - b->bh.prevfree); b->bh.bsize -= size; - } - else - { + } else { // The previous buffer isn't allocated. Insert this buffer on the // free list as an isolated free block. assert(fFreeList.ql.blink->ql.flink == &fFreeList); @@ -404,16 +372,15 @@ MemPool::ReleaseBuffer(void *buf) fFreeList.ql.blink = b; b->ql.blink->ql.flink = b; b->bh.bsize = -b->bh.bsize; - } + } // Now we look at the next buffer in memory, located by advancing from // the start of this buffer by its size, to see if that buffer is // free. If it is, we combine this buffer with the next one in // memory, dechaining the second buffer from the free list. - bn = BFH(((char *) b) + b->bh.bsize); - if (bn->bh.bsize > 0) - { + bn = BFH(((char *) b) + b->bh.bsize); + if (bn->bh.bsize > 0) { // The buffer is free. Remove it from the free list and add // its size to that of our buffer. assert(BH((char *) bn + bn->bh.bsize)->prevfree == bn->bh.bsize); @@ -422,7 +389,7 @@ MemPool::ReleaseBuffer(void *buf) bn->ql.blink->ql.flink = bn->ql.flink; bn->ql.flink->ql.blink = bn->ql.blink; b->bh.bsize += bn->bh.bsize; - + // Finally, advance to the buffer that follows the newly // consolidated free block. We must set its backpointer to the // head of the consolidated free block. We know the next block @@ -430,43 +397,44 @@ MemPool::ReleaseBuffer(void *buf) // guarantees that two free blocks will never be contiguous in // memory. bn = BFH(((char *) b) + b->bh.bsize); - } + } - memset(((char *) b) + sizeof(struct bfhead), 0x55,(int) (b->bh.bsize - sizeof(struct bfhead))); + memset(((char *) b) + sizeof(struct bfhead), 0x55, + (int)(b->bh.bsize - sizeof(struct bfhead))); - assert(bn->bh.bsize < 0); + assert(bn->bh.bsize < 0); - // The next buffer is allocated. Set the backpointer in it to point - // to this buffer; the previous free buffer in memory. - bn->bh.prevfree = b->bh.bsize; + // The next buffer is allocated. Set the backpointer in it to point + // to this buffer; the previous free buffer in memory. + bn->bh.prevfree = b->bh.bsize; // If a block-release function is defined, and this free buffer // constitutes the entire block, release it. Note that fPoolLength // is defined in such a way that the test will fail unless all // pool blocks are the same size. - if (((ssize_t) b->bh.bsize) == (ssize_t)(fPoolLength - sizeof(struct bhead))) - { + if (((ssize_t) b->bh.bsize) == (ssize_t)(fPoolLength - sizeof(struct bhead))) { assert(b->bh.prevfree == 0); assert(BH((char *) b + b->bh.bsize)->bsize == ESent); assert(BH((char *) b + b->bh.bsize)->prevfree == b->bh.bsize); - + // Unlink the buffer from the free list b->ql.blink->ql.flink = b->ql.flink; b->ql.flink->ql.blink = b->ql.blink; - + ReleaseMem(b); - + // Nr of expansion block releases fNumprel++; - + // Total number of blocks fNumpblk--; assert(fNumpblk == fNumpget - fNumprel); - } + } } -// Add a region of memory to the buffer pool. + +//! Add a region of memory to the buffer pool. void MemPool::AddToPool(void *buffer, ssize_t length) { @@ -518,7 +486,8 @@ MemPool::AddToPool(void *buffer, ssize_t length) length -= sizeof(struct bhead); b->bh.bsize = length; - memset(((char *)b) + sizeof(struct bfhead), 0x55, (int)(length - sizeof(struct bfhead))); + memset(((char *)b) + sizeof(struct bfhead), 0x55, + (int)(length - sizeof(struct bfhead))); struct bhead *bn = BH(((char *) b) + length); bn->prevfree = length; @@ -529,212 +498,185 @@ MemPool::AddToPool(void *buffer, ssize_t length) } -// Return buffer allocation free space statistics. +//! Return buffer allocation free space statistics. void MemPool::Stats(ssize_t *curalloc, ssize_t *totfree, ssize_t *maxfree, - long *nget, long *nrel) + long *nget, long *nrel) { - struct bfhead *b = fFreeList.ql.flink; + struct bfhead *b = fFreeList.ql.flink; - *nget = fGetCount; - *nrel = fReleaseCount; - *curalloc = fTotalAlloced; - *totfree = 0; - *maxfree = -1; - while (b != &fFreeList) - { + *nget = fGetCount; + *nrel = fReleaseCount; + *curalloc = fTotalAllocated; + *totfree = 0; + *maxfree = -1; + + while (b != &fFreeList) { assert(b->bh.bsize > 0); *totfree += b->bh.bsize; if (b->bh.bsize > *maxfree) - { *maxfree = b->bh.bsize; - } - + // Link to next buffer b = b->ql.flink; - } + } } -// Return extended statistics +// !Return extended statistics void -MemPool::ExtendedStats(ssize_t *pool_incr, long *npool, long *npget, long *nprel, - long *ndget, long *ndrel) +MemPool::ExtendedStats(ssize_t *pool_incr, long *npool, long *npget, + long *nprel, long *ndget, long *ndrel) { - *pool_incr = (fPoolLength < 0) ? -fExpIncr : fExpIncr; - *npool = fNumpblk; - *npget = fNumpget; - *nprel = fNumprel; - *ndget = fNumdget; - *ndrel = fNumdrel; + *pool_incr = (fPoolLength < 0) ? -fIncrementSize : fIncrementSize; + *npool = fNumpblk; + *npget = fNumpget; + *nprel = fNumprel; + *ndget = fNumdget; + *ndrel = fNumdrel; } -// Dump the data in a buffer. This is called with the user data pointer, -// and backs up to the buffer header. It will dump either a free block -// or an allocated one. +/*! + Dump the data in a buffer. This is called with the user data pointer, + and backs up to the buffer header. It will dump either a free block + or an allocated one. +*/ void MemPool::BufferDump(void *buf) { - struct bfhead *b; - unsigned char *bdump; - ssize_t bdlen; + struct bfhead *b; + unsigned char *bdump; + ssize_t bdlen; - b = BFH(((char *) buf) - sizeof(struct bhead)); - assert(b->bh.bsize != 0); - if (b->bh.bsize < 0) - { + b = BFH(((char *) buf) - sizeof(struct bhead)); + assert(b->bh.bsize != 0); + if (b->bh.bsize < 0) { bdump = (unsigned char *) buf; bdlen = (-b->bh.bsize) - sizeof(struct bhead); - } - else - { + } else { bdump = (unsigned char *) (((char *) b) + sizeof(struct bfhead)); bdlen = b->bh.bsize - sizeof(struct bfhead); - } + } - while (bdlen > 0) - { + while (bdlen > 0) { int i, dupes = 0; ssize_t l = bdlen; char bhex[50], bascii[20]; - + if (l > 16) - { - l = 16; - } - - for (i = 0; i < l; i++) - { - sprintf(bhex + i * 3, "%02X ", bdump[i]); - bascii[i] = isprint(bdump[i]) ? bdump[i] : ' '; + l = 16; + + for (i = 0; i < l; i++) { + sprintf(bhex + i * 3, "%02X ", bdump[i]); + bascii[i] = isprint(bdump[i]) ? bdump[i] : ' '; } bascii[i] = 0; - printf("%-48s %s\n", bhex, bascii); + printf("%-48s %s\n", bhex, bascii); bdump += l; bdlen -= l; - while ((bdlen > 16) && (memcmp((char *) (bdump - 16),(char *) bdump, 16) == 0)) - { - dupes++; - bdump += 16; - bdlen -= 16; + while ((bdlen > 16) && (memcmp((char *) (bdump - 16),(char *) bdump, 16) == 0)) { + dupes++; + bdump += 16; + bdlen -= 16; } - if (dupes > 1) - { - printf(" (%d lines [%d bytes] identical to above line skipped)\n", - dupes, dupes * 16); - } - else - { - if (dupes == 1) - { - bdump -= 16; - bdlen += 16; + if (dupes > 1) { + printf(" (%d lines [%d bytes] identical to above line skipped)\n", + dupes, dupes * 16); + } else { + if (dupes == 1) { + bdump -= 16; + bdlen += 16; } - } - } + } + } } -// Dump a buffer pool. The buffer headers are always listed. If DUMPALLOC is -// nonzero, the contents of allocated buffers are dumped. If DUMPFREE is -// nonzero, free blocks are dumped as well. If FreeWipe checking is enabled, -// free blocks which have been clobbered will always be dumped. + +/*! + Dump a buffer pool. The buffer headers are always listed. If DUMPALLOC is + nonzero, the contents of allocated buffers are dumped. If DUMPFREE is + nonzero, free blocks are dumped as well. If FreeWipe checking is enabled, + free blocks which have been clobbered will always be dumped. +*/ void MemPool::PoolDump(void *buf, bool dumpalloc, bool dumpfree) { - struct bfhead *b = BFH(buf); + struct bfhead *b = BFH(buf); - while (b->bh.bsize != ESent) - { + while (b->bh.bsize != ESent) { ssize_t bs = b->bh.bsize; - - if (bs < 0) - { - bs = -bs; - printf("Allocated buffer: size %6ld bytes.\n", (long) bs); - if (dumpalloc) - { + + if (bs < 0) { + bs = -bs; + printf("Allocated buffer: size %6ld bytes.\n", (long) bs); + if (dumpalloc) BufferDump((void *) (((char *) b) + sizeof(struct bhead))); - } - } - else - { + } else { char *lerr = ""; - assert(bs > 0); - if ((b->ql.blink->ql.flink != b) || (b->ql.flink->ql.blink != b)) - { - lerr = " (Bad free list links)"; - } - printf("Free block: size %6ld bytes.%s\n", - (long) bs, lerr); - - lerr = ((char *) b) + sizeof(struct bfhead); - if ((bs > (ssize_t)sizeof(struct bfhead)) && ((*lerr != 0x55) || - (memcmp(lerr, lerr + 1, (int) (bs - (sizeof(struct bfhead) + 1))) != 0))) - { + assert(bs > 0); + if ((b->ql.blink->ql.flink != b) || (b->ql.flink->ql.blink != b)) + lerr = " (Bad free list links)"; + + printf("Free block: size %6ld bytes.%s\n", + (long) bs, lerr); + + lerr = ((char *) b) + sizeof(struct bfhead); + if (bs > (ssize_t)sizeof(struct bfhead) + && (*lerr != 0x55 + || memcmp(lerr, lerr + 1, (int)(bs - (sizeof(struct bfhead) + 1))) != 0)) { printf("(Contents of above free block have been overstored.)\n"); BufferDump((void *) (((char *) b) + sizeof(struct bhead))); - } - else - { - if (dumpfree) - { + } else { + if (dumpfree) BufferDump((void *) (((char *) b) + sizeof(struct bhead))); - } - } + } } b = BFH(((char *) b) + bs); - } + } } -// Validate a buffer pool. + +//! Validate a buffer pool. int MemPool::Validate(void *buf) { - struct bfhead *b = BFH(buf); - - while (b->bh.bsize != ESent) - { + struct bfhead *b = BFH(buf); + + while (b->bh.bsize != ESent) { ssize_t bs = b->bh.bsize; if (bs < 0) - { - bs = -bs; - } - else - { - char *lerr = ""; - - assert(bs > 0); - if (bs <= 0) - { + bs = -bs; + else { + char *lerr = ""; + + assert(bs > 0); + if (bs <= 0) return 0; - } - - if ((b->ql.blink->ql.flink != b) || (b->ql.flink->ql.blink != b)) - { - printf("Free block: size %6ld bytes. (Bad free list links)\n", - (long) bs); + + if (b->ql.blink->ql.flink != b || b->ql.flink->ql.blink != b) { + printf("Free block: size %6ld bytes. (Bad free list links)\n", + (long) bs); assert(0); return 0; - } - - lerr = ((char *) b) + sizeof(struct bfhead); - if ((bs > (ssize_t)sizeof(struct bfhead)) && ((*lerr != 0x55) || - (memcmp(lerr, lerr + 1,(int) (bs - (sizeof(struct bfhead) + 1))) != 0))) - { + } + + lerr = ((char *) b) + sizeof(struct bfhead); + if (bs > (ssize_t)sizeof(struct bfhead) + && (*lerr != 0x55 + || memcmp(lerr, lerr + 1, (int)(bs - (sizeof(struct bfhead) + 1))) != 0)) { printf("(Contents of above free block have been overstored.)\n"); BufferDump((void *) (((char *) b) + sizeof(struct bhead))); assert(0); return 0; - } - + } } b = BFH(((char *) b) + bs); - } - return 1; + } + return 1; } @@ -763,7 +705,7 @@ MemPool::ReleaseMem(void *buffer) AreaPool::AreaPool(const char* name, size_t initialSize) - : + : MemPool(initialSize), fName(name) { if (initialSize > 0) diff --git a/src/servers/app/BGet++.h b/src/servers/app/BGet++.h index bc47d09751..a16279a85c 100644 --- a/src/servers/app/BGet++.h +++ b/src/servers/app/BGet++.h @@ -6,95 +6,93 @@ * John Walker * DarkWyrm * Stephan Aßmus - * - * BGET pool allocator */ - #ifndef MEM_POOL_H #define MEM_POOL_H + #include + class MemPool { - public: - MemPool(); - virtual ~MemPool(); + public: + MemPool(int32 incrementSize); + virtual ~MemPool(); - void AddToPool(void* buffer, ssize_t len); - void* GetBuffer(ssize_t size, bool zero = false); - void* ReallocateBuffer(void* buffer, ssize_t size); - void ReleaseBuffer(void* buffer); + void AddToPool(void* buffer, ssize_t len); + void* GetBuffer(ssize_t size, bool zero = false); + void* ReallocateBuffer(void* buffer, ssize_t size); + void ReleaseBuffer(void* buffer); + + virtual int* CompactMem(ssize_t sizereq, int sequence); + virtual void* AcquireMem(ssize_t size); + virtual void ReleaseMem(void* buffer); + + void SetPoolIncrement(ssize_t increment); + ssize_t PoolIncrement(); + + // debugging + void Stats(ssize_t* curalloc, ssize_t* totfree, + ssize_t* maxfree, long* nget, long* nrel); + + void ExtendedStats(ssize_t* pool_incr, long* npool, + long* npget, long* nprel, + long* ndget, long* ndrel); + + void BufferDump(void* buf); + void PoolDump(void* pool, bool dumpalloc, + bool dumpfree); + + int Validate(void* buffer); + + private: + // Header in allocated and free buffers + struct bhead { + // Relative link back to previous free buffer in memory or 0 if previous + // buffer is allocated. + ssize_t prevfree; + // Buffer size: positive if free, negative if allocated. + ssize_t bsize; + }; - virtual int* CompactMem(ssize_t sizereq, int sequence); - virtual void* AcquireMem(ssize_t size); - virtual void ReleaseMem(void* buffer); + // Header in directly allocated buffers (by acqfcn) + struct bdhead { + ssize_t tsize; // Total size, including overhead + bhead bh; // Common header + }; + + // Queue links + struct bfhead; + struct qlinks { + bfhead *flink; // Forward link + bfhead *blink; // Backward link + }; + + // Header in free buffers + struct bfhead { + // Common allocated/free header + bhead bh; + // Links on free list + qlinks ql; + }; - void SetPoolIncrement(ssize_t increment); - ssize_t PoolIncrement(); - - // debugging - void Stats(ssize_t* curalloc, ssize_t* totfree, - ssize_t* maxfree, long* nget, long* nrel); - - void ExtendedStats(ssize_t* pool_incr, long* npool, - long* npget, long* nprel, - long* ndget, long* ndrel); - - void BufferDump(void* buf); - void PoolDump(void* pool, bool dumpalloc, - bool dumpfree); - - int Validate(void* buffer); - - private: - - // Header in allocated and free buffers - struct bhead { - // Relative link back to previous free buffer in memory or 0 if previous - // buffer is allocated. - ssize_t prevfree; - // Buffer size: positive if free, negative if allocated. - ssize_t bsize; - }; - - // Header in directly allocated buffers (by acqfcn) - struct bdhead { - ssize_t tsize; // Total size, including overhead - bhead bh; // Common header - }; - - // Queue links - struct bfhead; - struct qlinks { - bfhead *flink; // Forward link - bfhead *blink; // Backward link - }; - - // Header in free buffers - struct bfhead { - // Common allocated/free header - bhead bh; - // Links on free list - qlinks ql; - }; - - ssize_t fTotalAlloced; - long fGetCount; - long fReleaseCount; - long fNumpblk; - long fNumpget; - long fNumprel; - long fNumdget; - long fNumdrel; - ssize_t fExpIncr; - ssize_t fPoolLength; - // List of free buffers - bfhead fFreeList; + ssize_t fTotalAllocated; + long fGetCount; + long fReleaseCount; + long fNumpblk; + long fNumpget; + long fNumprel; + long fNumdget; + long fNumdrel; + ssize_t fIncrementSize; + ssize_t fPoolLength; + // List of free buffers + bfhead fFreeList; }; class AreaPool : public MemPool { public: - AreaPool(const char* name, size_t initialSize = 0); + AreaPool(const char* name, size_t initialSize); virtual ~AreaPool(); virtual void* AcquireMem(ssize_t size); @@ -104,4 +102,4 @@ class AreaPool : public MemPool { const char* fName; }; -#endif +#endif /* MEM_POOL_H */ diff --git a/src/servers/app/BitmapManager.cpp b/src/servers/app/BitmapManager.cpp index b1aa070bc0..e070c941da 100644 --- a/src/servers/app/BitmapManager.cpp +++ b/src/servers/app/BitmapManager.cpp @@ -32,7 +32,7 @@ using std::nothrow; BitmapManager *gBitmapManager = NULL; //! Number of bytes to allocate to each area used for bitmap storage -#define BITMAP_AREA_SIZE B_PAGE_SIZE * 2 +#define BITMAP_AREA_SIZE B_PAGE_SIZE * 16 //! Sets up stuff to be ready to allocate space for bitmaps diff --git a/src/servers/app/DebugInfoManager.cpp b/src/servers/app/DebugInfoManager.cpp index e7b5ee539f..ad6613802f 100644 --- a/src/servers/app/DebugInfoManager.cpp +++ b/src/servers/app/DebugInfoManager.cpp @@ -7,7 +7,7 @@ * */ -#include "RootLayer.h" +//#include "RootLayer.h" #include "DebugInfoManager.h" diff --git a/src/servers/app/Decorator.cpp b/src/servers/app/Decorator.cpp index f6516a089f..6114dae188 100644 --- a/src/servers/app/Decorator.cpp +++ b/src/servers/app/Decorator.cpp @@ -288,8 +288,8 @@ Decorator::GetZoom() // GetSizeLimits void -Decorator::GetSizeLimits(float* minWidth, float* minHeight, - float* maxWidth, float* maxHeight) const +Decorator::GetSizeLimits(int32* minWidth, int32* minHeight, + int32* maxWidth, int32* maxHeight) const { } diff --git a/src/servers/app/DefaultDecorator.cpp b/src/servers/app/DefaultDecorator.cpp index 341b66fd4c..87e6fc728a 100644 --- a/src/servers/app/DefaultDecorator.cpp +++ b/src/servers/app/DefaultDecorator.cpp @@ -184,13 +184,13 @@ DefaultDecorator::MoveBy(BPoint pt) void DefaultDecorator::ResizeBy(float x, float y) { - ResizeBy(BPoint(x,y)); + ResizeBy(BPoint(x, y)); } void DefaultDecorator::ResizeBy(BPoint pt) { - STRACE(("DefaultDecorator: Resize By (%.1f, %.1f)\n",pt.x,pt.y)); + STRACE(("DefaultDecorator: Resize By (%.1f, %.1f)\n", pt.x, pt.y)); // Move all internal rectangles the appropriate amount _frame.right += pt.x; _frame.bottom += pt.y; @@ -250,13 +250,13 @@ DefaultDecorator::Draw() // GetSizeLimits void -DefaultDecorator::GetSizeLimits(float* minWidth, float* minHeight, - float* maxWidth, float* maxHeight) const +DefaultDecorator::GetSizeLimits(int32* minWidth, int32* minHeight, + int32* maxWidth, int32* maxHeight) const { if (_tabrect.IsValid()) - *minWidth = max_c(*minWidth, fMinTabWidth - 2 * fBorderWidth); + *minWidth = (int32)roundf(max_c(*minWidth, fMinTabWidth - 2 * fBorderWidth)); if (_resizerect.IsValid()) - *minHeight = max_c(*minHeight, _resizerect.Height() - fBorderWidth); + *minHeight = (int32)roundf(max_c(*minHeight, _resizerect.Height() - fBorderWidth)); } // GetFootprint @@ -309,7 +309,7 @@ DefaultDecorator::Clicked(BPoint pt, int32 buttons, int32 modifiers) if (!(fFlags & B_NOT_ZOOMABLE) && _zoomrect.Contains(pt)) return DEC_ZOOM; - + if (fLook == B_DOCUMENT_WINDOW_LOOK && _resizerect.Contains(pt)) return DEC_RESIZE; @@ -466,7 +466,7 @@ DefaultDecorator::_DoLayout() // calculate resize rect _resizerect.Set(fBottomBorder.right - 18.0, fBottomBorder.bottom - 18.0, - fBottomBorder.right - 3, fBottomBorder.bottom - 3); + fBottomBorder.right, fBottomBorder.bottom); } // _DrawFrame @@ -559,17 +559,15 @@ STRACE(("_DrawFrame(%f,%f,%f,%f)\n", invalid.left, invalid.top, // Draw the resize thumb if we're supposed to if (!(fFlags & B_NOT_RESIZABLE)) { - r = _resizerect; switch (fLook){ case B_DOCUMENT_WINDOW_LOOK: { - - // Explicitly locking the driver is normally unnecessary. However, we need to do - // this because we are rapidly drawing a series of calls which would not necessarily - // draw correctly if we didn't do so. - float x = r.right; - float y = r.bottom; + // Explicitly locking the driver is normally unnecessary. However, we + // need to do this because we are rapidly drawing a series of calls + // which would not necessarily draw correctly if we didn't do so. + float x = r.right - 3; + float y = r.bottom - 3; _driver->Lock(); _driver->FillRect(BRect(x-13, y-13, x, y), fFrameColors[2]); _driver->StrokeLine(BPoint(x-15, y-15), BPoint(x-15, y-2), fFrameColors[0]); @@ -600,7 +598,7 @@ STRACE(("_DrawFrame(%f,%f,%f,%f)\n", invalid.left, invalid.top, fFrameColors[0]); break; } - + default: { // don't draw resize corner break; @@ -715,7 +713,7 @@ DefaultDecorator::_SetFocus() // SetFocus() performs necessary duties for color swapping and // other things when a window is deactivated or activated. - if (GetFocus()) { + if (IsFocus()) { fButtonHighColor.SetColor(tint_color(_colors->window_tab,B_LIGHTEN_2_TINT)); fButtonLowColor.SetColor(tint_color(_colors->window_tab,B_DARKEN_1_TINT)); fTextColor = _colors->window_tab_text; diff --git a/src/servers/app/DefaultDecorator.h b/src/servers/app/DefaultDecorator.h index 945936f382..5cad3b014c 100644 --- a/src/servers/app/DefaultDecorator.h +++ b/src/servers/app/DefaultDecorator.h @@ -35,8 +35,8 @@ public: virtual void Draw(BRect r); virtual void Draw(); - virtual void GetSizeLimits(float* minWidth, float* minHeight, - float* maxWidth, float* maxHeight) const; + virtual void GetSizeLimits(int32* minWidth, int32* minHeight, + int32* maxWidth, int32* maxHeight) const; virtual void GetFootprint(BRegion *region); diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index fed925451c..1fc9017a3f 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -18,8 +18,6 @@ #include "DrawingEngine.h" #include "HWInterface.h" #include "InputManager.h" -#include "Layer.h" -#include "RootLayer.h" #include "ServerApp.h" #include "ServerConfig.h" #include "ServerScreen.h" @@ -145,12 +143,11 @@ KeyboardFilter::Filter(BMessage* message, EventTarget** _target, bigtime_t now = system_time(); - ::RootLayer* rootLayer = fDesktop->RootLayer(); - rootLayer->Lock(); + fDesktop->ReadLockWindows(); EventTarget* focus = NULL; - if (rootLayer->Focus() != NULL) - focus = &rootLayer->Focus()->Window()->EventTarget(); + if (fDesktop->FocusWindow() != NULL) + focus = &fDesktop->FocusWindow()->EventTarget(); // TODO: this is a try to not steal focus from the current window // in case you enter some text and a window pops up you haven't @@ -168,7 +165,7 @@ KeyboardFilter::Filter(BMessage* message, EventTarget** _target, fLastFocus = focus; } - rootLayer->Unlock(); + fDesktop->ReadUnlockWindows(); // we always allow to switch focus after the enter key has pressed if (key == B_ENTER) @@ -197,13 +194,11 @@ MouseFilter::Filter(BMessage* message, EventTarget** _target, int32* _viewToken) if (message->FindPoint("where", &where) != B_OK) return B_DISPATCH_MESSAGE; - ::RootLayer* rootLayer = fDesktop->RootLayer(); + fDesktop->WriteLockWindows(); - rootLayer->Lock(); - - WindowLayer* window = rootLayer->MouseEventWindow(); + WindowLayer* window = fDesktop->MouseEventWindow(); if (window == NULL) - window = rootLayer->WindowAt(where); + window = fDesktop->WindowAt(where); if (window != NULL) { // dispatch event in the window layers @@ -211,25 +206,25 @@ MouseFilter::Filter(BMessage* message, EventTarget** _target, int32* _viewToken) case B_MOUSE_DOWN: window->MouseDown(message, where, _viewToken); break; - + case B_MOUSE_UP: window->MouseUp(message, where, _viewToken); - rootLayer->SetMouseEventWindow(NULL); + fDesktop->SetMouseEventWindow(NULL); break; - + case B_MOUSE_MOVED: window->MouseMoved(message, where, _viewToken); break; } if (*_viewToken != B_NULL_TOKEN) - *_target = &window->Window()->EventTarget(); + *_target = &window->EventTarget(); else *_target = NULL; } else *_target = NULL; - rootLayer->Unlock(); + fDesktop->WriteUnlockWindows(); return B_DISPATCH_MESSAGE; } @@ -257,17 +252,22 @@ workspaces_on_workspace(int32 index, uint32 workspaces) Desktop::Desktop(uid_t userID) : MessageLooper("desktop"), + fUserID(userID), fSettings(new DesktopSettings::Private()), - fAppListLock("application list"), + fApplicationsLock("application list"), fShutdownSemaphore(-1), - fWindowLayerList(64), + fAllWindows(kAllWindowList), fActiveScreen(NULL), - fCursorManager() + fWindowLock("window lock") { char name[B_OS_NAME_LENGTH]; Desktop::_GetLooperName(name, sizeof(name)); + for (int32 i = 0; i < kMaxWorkspaces; i++) { + fWorkspaces[i].Windows().SetIndex(i); + } + fMessagePort = create_port(DEFAULT_MONITOR_PORT_SIZE, name); if (fMessagePort < B_OK) return; @@ -279,11 +279,6 @@ Desktop::Desktop(uid_t userID) Desktop::~Desktop() { - // root layer only knows the visible WindowLayers, so we delete them all over here - for (int32 i = 0; WindowLayer *border = (WindowLayer *)fWindowLayerList.ItemAt(i); i++) - delete border; - - delete fRootLayer; delete fSettings; delete_port(fMessagePort); @@ -299,11 +294,6 @@ Desktop::Init() // TODO: temporary workaround, fActiveScreen will be removed fActiveScreen = fVirtualScreen.ScreenAt(0); - // TODO: add user identity to the name - char name[32]; - sprintf(name, "RootLayer %d", 1); - fRootLayer = new ::RootLayer(name, this, GetDrawingEngine()); - #if TEST_MODE gInputManager->AddStream(new InputServerStream); #endif @@ -321,6 +311,14 @@ Desktop::Init() fVirtualScreen.HWInterface()->MoveCursorTo(fVirtualScreen.Frame().Width() / 2, fVirtualScreen.Frame().Height() / 2); fVirtualScreen.HWInterface()->SetCursorVisible(true); + + // draw the background + + fScreenRegion = fVirtualScreen.Frame(); + + BRegion stillAvailableOnScreen; + _RebuildClippingForAllWindows(stillAvailableOnScreen); + _SetBackground(stillAvailableOnScreen); } @@ -336,11 +334,11 @@ Desktop::_PrepareQuit() { // let's kill all remaining applications - fAppListLock.Lock(); + fApplicationsLock.Lock(); - int32 count = fAppList.CountItems(); + int32 count = fApplications.CountItems(); for (int32 i = 0; i < count; i++) { - ServerApp *app = (ServerApp*)fAppList.ItemAt(i); + ServerApp *app = fApplications.ItemAt(i); team_id clientTeam = app->ClientTeam(); app->Quit(); @@ -351,7 +349,7 @@ Desktop::_PrepareQuit() if (count > 0) acquire_sem_etc(fShutdownSemaphore, fShutdownCount, B_RELATIVE_TIMEOUT, 250000); - fAppListLock.Unlock(); + fApplicationsLock.Unlock(); } @@ -389,9 +387,9 @@ Desktop::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) if (app->InitCheck() == B_OK && app->Run()) { // add the new ServerApp to the known list of ServerApps - fAppListLock.Lock(); - fAppList.AddItem(app); - fAppListLock.Unlock(); + fApplicationsLock.Lock(); + fApplications.AddItem(app); + fApplicationsLock.Unlock(); } else { delete app; @@ -419,24 +417,24 @@ Desktop::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) if (link.Read(&thread) < B_OK) break; - fAppListLock.Lock(); + fApplicationsLock.Lock(); // Run through the list of apps and nuke the proper one - int32 count = fAppList.CountItems(); + int32 count = fApplications.CountItems(); ServerApp *removeApp = NULL; for (int32 i = 0; i < count; i++) { - ServerApp *app = (ServerApp *)fAppList.ItemAt(i); + ServerApp *app = fApplications.ItemAt(i); if (app != NULL && app->Thread() == thread) { - fAppList.RemoveItem(i); + fApplications.RemoveItemAt(i); removeApp = app; break; } } - fAppListLock.Unlock(); + fApplicationsLock.Unlock(); if (removeApp != NULL) removeApp->Quit(fShutdownSemaphore); @@ -486,10 +484,10 @@ Desktop::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) // test apps to quit. This situation will occur only when the server // is compiled as a regular Be application. - fAppListLock.Lock(); + fApplicationsLock.Lock(); fShutdownSemaphore = create_sem(0, "desktop shutdown"); - fShutdownCount = fAppList.CountItems(); - fAppListLock.Unlock(); + fShutdownCount = fApplications.CountItems(); + fApplicationsLock.Unlock(); fQuitting = true; BroadcastToAllApps(AS_QUIT_APP); @@ -526,15 +524,14 @@ Desktop::_ActivateApp(team_id team) status_t status = B_BAD_TEAM_ID; // search for an unhidden window to give focus to - int32 windowCount = WindowList().CountItems(); - for (int32 i = 0; i < windowCount; ++i) { - // is this layer in fact a WindowLayer? - WindowLayer *windowLayer = WindowList().ItemAt(i); - // if winBorder is valid and not hidden, then we've found our target - if (windowLayer != NULL && !windowLayer->IsHidden() - && windowLayer->App()->ClientTeam() == team) { - fRootLayer->ActivateWindow(windowLayer); + for (WindowLayer* window = fAllWindows.FirstWindow(); window != NULL; + window = window->NextWindow(kAllWindowList)) { + // if window is a normal window of the team, and not hidden, + // we've found our target + if (!window->IsHidden() && window->IsNormal() + && window->ServerWindow()->ClientTeam() == team) { + ActivateWindow(window); return B_OK; } } @@ -552,16 +549,27 @@ Desktop::_ActivateApp(team_id team) void Desktop::BroadcastToAllApps(int32 code) { - BAutolock locker(fAppListLock); + BAutolock locker(fApplicationsLock); - for (int32 i = 0; i < fAppList.CountItems(); i++) { - ServerApp *app = (ServerApp *)fAppList.ItemAt(i); - - app->PostMessage(code); + for (int32 i = 0; i < fApplications.CountItems(); i++) { + fApplications.ItemAt(i)->PostMessage(code); } } +void +Desktop::UpdateWorkspaces() +{ + // TODO: maybe this should be replaced by a SetWorkspacesCount() method + +/* if (fWorkspacesLayer == NULL) + return; + + _WindowsChanged(); +*/ +} + + void Desktop::SetWorkspace(int32 index) { @@ -572,31 +580,119 @@ Desktop::SetWorkspace(int32 index) return; int32 previousIndex = fCurrentWorkspace; + + // build region of windows that are no longer visible in the new workspace + + BRegion dirty; + for (WindowLayer* window = _CurrentWindows().FirstWindow(); + window != NULL; window = window->NextWindow(previousIndex)) { + window->Anchor(previousIndex).position = window->Frame().LeftTop(); + + if (window->OnWorkspace(index)) + continue; + + if (!window->IsHidden()) { + // this window will no longer be visible + dirty.Include(&window->VisibleRegion()); + } + + window->SetCurrentWorkspace(-1); + } + fCurrentWorkspace = index; - fRootLayer->SetWorkspace(index, fWorkspaces[previousIndex], - fWorkspaces[index]); + // show windows, and include them in the changed region - but only + // those that were not visible before (or whose position changed) + + for (WindowLayer* window = _CurrentWindows().FirstWindow(); + window != NULL; window = window->NextWindow(index)) { + BPoint position = window->Anchor(index).position; + + window->SetCurrentWorkspace(index); + + if (window->IsHidden()) + continue; + + if (position == kInvalidWindowPosition) { + // if you enter a workspace for the first time, the position + // of the window in the previous workspace is adopted + position = window->Frame().LeftTop(); + // TODO: make sure the window is still on-screen if it + // was before! + } + + if (!window->OnWorkspace(previousIndex)) { + // this window was not visible before + continue; + } + + if (window->Frame().LeftTop() != position) { + // the window was visible before, but its on-screen location changed + BPoint offset = position - window->Frame().LeftTop(); + MoveWindowBy(window, offset.x, offset.y); + // TODO: be a bit smarter than this... + } + } + + BRegion stillAvailableOnScreen; + _RebuildClippingForAllWindows(stillAvailableOnScreen); + _SetBackground(stillAvailableOnScreen); + + for (WindowLayer* window = _CurrentWindows().FirstWindow(); window != NULL; + window = window->NextWindow(index)) { + if (window->OnWorkspace(previousIndex)) { + // this window was visible before, and is already handled in the above loop + continue; + } + + dirty.Include(&window->VisibleRegion()); + } + + _UpdateFronts(); + SetFocusWindow(FrontWindow()); + + MarkDirty(dirty); + //_WindowsChanged(); } void Desktop::ScreenChanged(Screen* screen) { + // TODO: confirm that everywhere this is used, + // the Window WriteLock is held + +// TODO: can this be removed? I would think it can. +// In fact, this lock should nowhere be used anymore, no? +// BAutolock locker(this); + + // the entire screen is dirty, because we're actually + // operating on an all new buffer in memory + BRegion dirty(screen->Frame()); + // update our cached screen region + fScreenRegion.Set(screen->Frame()); + + BRegion background; + _RebuildClippingForAllWindows(background); + + fBackgroundRegion.MakeEmpty(); + // makes sure that the complete background is redrawn + _SetBackground(background); + + // figure out dirty region + dirty.Exclude(&background); + _TriggerWindowRedrawing(dirty); + + // send B_SCREEN_CHANGED to windows on that screen BMessage update(B_SCREEN_CHANGED); update.AddInt64("when", real_time_clock_usecs()); update.AddRect("frame", screen->Frame()); update.AddInt32("mode", screen->ColorSpace()); - BAutolock locker(this); - - // send B_SCREEN_CHANGED to windows on that screen // TODO: currently ignores the screen argument! - - for (int32 i = fWindowLayerList.CountItems(); i-- > 0;) { - WindowLayer* layer = fWindowLayerList.ItemAt(i); - ServerWindow* window = layer->Window(); - - window->SendMessageToClient(&update); + for (WindowLayer* window = fAllWindows.FirstWindow(); window != NULL; + window = window->NextWindow(kAllWindowList)) { + window->ServerWindow()->SendMessageToClient(&update); } } @@ -604,29 +700,241 @@ Desktop::ScreenChanged(Screen* screen) // #pragma mark - Methods for WindowLayer manipulation -void -Desktop::ActivateWindow(WindowLayer* windowLayer) +WindowList& +Desktop::_CurrentWindows() { - fRootLayer->ActivateWindow(windowLayer); + return fWorkspaces[fCurrentWorkspace].Windows(); +} + + +/*! Search the visible windows for a valid back window + (only normal windows can be back windows) +*/ +void +Desktop::_UpdateBack() +{ + fBack = NULL; + + for (WindowLayer* window = _CurrentWindows().FirstWindow(); + window != NULL; window = window->NextWindow(fCurrentWorkspace)) { + if (window->IsHidden() || !window->SupportsFront()) + continue; + + fBack = window; + break; + } +} + + +/*! Search the visible windows for a valid front window + (only normal windows can be front windows) +*/ +void +Desktop::_UpdateFront() +{ + // TODO: for now, just choose the top window + fFront = NULL; + + for (WindowLayer* window = _CurrentWindows().LastWindow(); + window != NULL; window = window->PreviousWindow(fCurrentWorkspace)) { + if (window->IsHidden() || !window->SupportsFront()) + continue; + + fFront = window; + break; + } } void -Desktop::SendBehindWindow(WindowLayer* windowLayer, WindowLayer* front) +Desktop::_UpdateFronts() { - fRootLayer->SendBehindWindow(windowLayer, front); + _UpdateBack(); + _UpdateFront(); +} + + + +void +Desktop::SetFocusWindow(WindowLayer* focus) +{ + // TODO: test for FFM and B_LOCK_WINDOW_FOCUS + if (focus == fFocus && focus != NULL && (focus->Flags() & B_AVOID_FOCUS) == 0) + return; + + if (WriteLockWindows()) { + // make sure no window is chosen that doesn't want focus + while (focus != NULL && (focus->Flags() & B_AVOID_FOCUS) != 0) { + focus = focus->PreviousWindow(fCurrentWorkspace); + } + + if (fFocus != NULL) + fFocus->SetFocus(false); + + fFocus = focus; + + if (focus != NULL) + focus->SetFocus(true); + + WriteUnlockWindows(); + } +} + + +void +Desktop::_BringWindowsToFront(WindowList& windows, int32 list, + bool wereVisible) +{ + // we don't need to redraw what is currently + // visible of the window + BRegion clean; + + for (WindowLayer* window = windows.FirstWindow(); window != NULL; + window = window->NextWindow(list)) { + if (wereVisible) + clean.Include(&window->VisibleRegion()); + + _CurrentWindows().AddWindow(window, + window->Frontmost(_CurrentWindows().FirstWindow(), + fCurrentWorkspace)); + } + + BRegion dummy; + _RebuildClippingForAllWindows(dummy); + + // redraw what became visible of the window(s) + + BRegion dirty; + for (WindowLayer* window = windows.FirstWindow(); window != NULL; + window = window->NextWindow(list)) { + dirty.Include(&window->VisibleRegion()); + } + + dirty.Exclude(&clean); + MarkDirty(dirty); + + _UpdateFront(); + + if (windows.FirstWindow() == fBack || fBack == NULL) + _UpdateBack(); + + SetFocusWindow(FrontWindow()); +} + + +/*! + \brief Tries to move the specified window to the front of the screen, + and make it the focus window. + + If there are any modal windows on this screen, it might not actually + become the frontmost window, though, as modal windows stay in front + of their subset. +*/ +void +Desktop::ActivateWindow(WindowLayer* window) +{ +// printf("ActivateWindow(%p, %s)\n", window, window ? window->Title() : ""); + + if (window == NULL) { + fBack = NULL; + fFront = NULL; + return; + } + if (window == FrontWindow()) + return; + + // TODO: take care about floating windows + + if (!WriteLockWindows()) + return; + + // we don't need to redraw what is currently + // visible of the window + BRegion clean(window->VisibleRegion()); + WindowList windows(kWorkingList); + + WindowLayer* frontmost = window->Frontmost(); + + _CurrentWindows().RemoveWindow(window); + windows.AddWindow(window); + + if (frontmost != NULL && frontmost->IsModal()) { + // all modal windows follow their subsets to the front + // (ie. they are staying in front of them, but they are + // not supposed to change their order because of that) + + WindowLayer* nextModal; + for (WindowLayer* modal = frontmost; modal != NULL; modal = nextModal) { + // get the next modal window + nextModal = modal->NextWindow(fCurrentWorkspace); + while (nextModal != NULL && !nextModal->IsModal()) { + nextModal = nextModal->NextWindow(fCurrentWorkspace); + } + if (nextModal != NULL && !nextModal->HasInSubset(window)) + nextModal = NULL; + + _CurrentWindows().RemoveWindow(modal); + windows.AddWindow(modal); + } + } + + _BringWindowsToFront(windows, kWorkingList, true); + WriteUnlockWindows(); +} + + +void +Desktop::SendWindowBehind(WindowLayer* window, WindowLayer* behindOf) +{ + if (window == BackWindow() || !WriteLockWindows()) + return; + + // Is this a valid behindOf window? + if (behindOf != NULL && window->HasInSubset(behindOf)) + behindOf = NULL; + + // what is currently visible of the window + // might be dirty after the window is send to back + BRegion dirty(window->VisibleRegion()); + + // detach window and re-attach at desired position + WindowLayer* backmost = window->Backmost(behindOf); + + _CurrentWindows().RemoveWindow(window); + _CurrentWindows().AddWindow(window, backmost + ? backmost->NextWindow(fCurrentWorkspace) : BackWindow()); + + BRegion dummy; + _RebuildClippingForAllWindows(dummy); + + // mark everything dirty that is no longer visible + BRegion clean(window->VisibleRegion()); + dirty.Exclude(&clean); + MarkDirty(dirty); + + // TODO: if this window has any floating windows, remove them here + + _UpdateFronts(); + SetFocusWindow(FrontWindow()); + //_WindowsChanged(); + + WriteUnlockWindows(); } void Desktop::ShowWindow(WindowLayer* window) { - if (!window->IsHidden() || window->Parent() == NULL) { - window->Show(false); + if (!window->IsHidden()) return; - } - fRootLayer->ShowWindow(window); + WriteLockWindows(); + + window->SetHidden(false); + _ShowWindow(window, true); + ActivateWindow(window); + + WriteUnlockWindows(); // If the mouse cursor is directly over the newly visible window, // we'll send a fake mouse moved message to the window, so that @@ -638,42 +946,158 @@ Desktop::ShowWindow(WindowLayer* window) int32 viewToken = B_NULL_TOKEN; - fRootLayer->Lock(); - if (fRootLayer->WindowAt(where) == window) { - Layer* layer = window->LayerAt(where); - if (layer != NULL && layer != window) - viewToken = layer->ViewToken(); + WriteLockWindows(); + + if (WindowAt(where) == window) { + ViewLayer* view = window->ViewAt(where); + if (view != NULL) + viewToken = view->Token(); } - fRootLayer->Unlock(); + WriteUnlockWindows(); if (viewToken != B_NULL_TOKEN) - EventDispatcher().SendFakeMouseMoved(window->Window()->EventTarget(), viewToken); + EventDispatcher().SendFakeMouseMoved(window->EventTarget(), viewToken); } void Desktop::HideWindow(WindowLayer* window) { - if (window->IsHidden() || window->Parent() == NULL) { - window->Hide(false); + if (window->IsHidden()) return; - } - fRootLayer->HideWindow(window); + if (!WriteLockWindows()) + return; + + window->SetHidden(true); + + _HideWindow(window); + _UpdateFronts(); + + if (FocusWindow() == window) + SetFocusWindow(FrontWindow()); + + WriteUnlockWindows(); +} + + +/*! + Shows the window on the screen - it does this independently of the + WindowLayer::IsHidden() state. +*/ +void +Desktop::_ShowWindow(WindowLayer* window, bool affectsOtherWindows) +{ + BRegion background; + _RebuildClippingForAllWindows(background); + _SetBackground(background); + + BRegion dirty(window->VisibleRegion()); + + if (!affectsOtherWindows) { + // everything that is now visible in the + // window needs a redraw, but other windows + // are not affected, we can call ProcessDirtyRegion() + // of the window, and don't have to use MarkDirty() + window->ProcessDirtyRegion(dirty); + } else + MarkDirty(dirty); +} + + +/*! + Hides the window from the screen - it does this independently of the + WindowLayer::IsHidden() state. +*/ +void +Desktop::_HideWindow(WindowLayer* window) +{ + // after rebuilding the clipping, + // this window will not have a visible + // region anymore, so we need to remember + // it now + // (actually that's not true, since + // hidden windows are excluded from the + // clipping calculation, but anyways) + BRegion dirty(window->VisibleRegion()); + + BRegion background; + _RebuildClippingForAllWindows(background); + _SetBackground(background); + + MarkDirty(dirty); } void Desktop::MoveWindowBy(WindowLayer* window, float x, float y) { - fRootLayer->MoveWindowBy(window, x, y); + if (!WriteLockWindows()) + return; + + // the dirty region starts with the visible area of the window being moved + BRegion newDirtyRegion(window->VisibleRegion()); + + window->MoveBy(x, y); + + BRegion background; + _RebuildClippingForAllWindows(background); + + // construct the region that is possible to be blitted + // to move the contents of the window + BRegion copyRegion(window->VisibleRegion()); + copyRegion.OffsetBy(-x, -y); + copyRegion.IntersectWith(&newDirtyRegion); + + // include the the new visible region of the window being + // moved into the dirty region (for now) + newDirtyRegion.Include(&window->VisibleRegion()); + + if (GetDrawingEngine()->Lock()) { + GetDrawingEngine()->CopyRegion(©Region, x, y); + + // in the dirty region, exclude the parts that we + // could move by blitting + copyRegion.OffsetBy(x, y); + newDirtyRegion.Exclude(©Region); + + GetDrawingEngine()->Unlock(); + } + + MarkDirty(newDirtyRegion); + _SetBackground(background); + + //_WindowsChanged(changed); + + WriteUnlockWindows(); } void Desktop::ResizeWindowBy(WindowLayer* window, float x, float y) { - fRootLayer->ResizeWindowBy(window, x, y); + if (!WriteLockWindows()) + return; + + BRegion newDirtyRegion; + BRegion previouslyOccupiedRegion(window->VisibleRegion()); + + window->ResizeBy(x, y, &newDirtyRegion); + + BRegion background; + _RebuildClippingForAllWindows(background); + + previouslyOccupiedRegion.Exclude(&window->VisibleRegion()); + + newDirtyRegion.IntersectWith(&window->VisibleRegion()); + newDirtyRegion.Include(&previouslyOccupiedRegion); + + MarkDirty(newDirtyRegion); + _SetBackground(background); + + //_WindowsChanged(changed); + + WriteUnlockWindows(); } @@ -691,18 +1115,24 @@ Desktop::_ChangeWindowWorkspaces(WindowLayer* window, uint32 oldWorkspaces, if (workspaces_on_workspace(i, oldWorkspaces)) { // window is on this workspace, is it anymore? if (!workspaces_on_workspace(i, newWorkspaces)) { + fWorkspaces[i].Windows().RemoveWindow(window); + window->SetCurrentWorkspace(-1); + if (i == CurrentWorkspace()) - RootLayer()->RemoveWindow(window); - else - fWorkspaces[i].RemoveWindow(window); + _HideWindow(window); } } else { // window was not on this workspace, is it now? if (workspaces_on_workspace(i, newWorkspaces)) { - if (i == CurrentWorkspace()) - RootLayer()->AddWindow(window); - else - fWorkspaces[i].AddWindow(window); + fWorkspaces[i].Windows().AddWindow(window); + window->SetCurrentWorkspace(fCurrentWorkspace); + + if (i == CurrentWorkspace()) { + // this only affects other windows if this windows has floating or + // modal windows that need to be shown as well + // TODO: take care of this + _ShowWindow(window, FrontWindow() == window); + } } } } @@ -727,12 +1157,7 @@ Desktop::AddWindow(WindowLayer *window) { BAutolock _(this); - if (fWindowLayerList.HasItem(window)) { - debugger("AddWindowLayer: WindowLayer already in Desktop list\n"); - return; - } - - fWindowLayerList.AddItem(window); + fAllWindows.AddWindow(window); if (window->Workspaces() == B_CURRENT_WORKSPACE) window->SetWorkspaces(workspace_to_workspaces(CurrentWorkspace())); @@ -746,34 +1171,98 @@ Desktop::RemoveWindow(WindowLayer *window) { BAutolock _(this); - fWindowLayerList.RemoveItem(window); + fAllWindows.RemoveWindow(window); _ChangeWindowWorkspaces(window, window->Workspaces(), 0); // make sure this window won't get any events anymore - if (window->Window() != NULL) - EventDispatcher().RemoveTarget(window->Window()->EventTarget()); + EventDispatcher().RemoveTarget(window->EventTarget()); } void -Desktop::SetWindowLook(WindowLayer *window, window_look look) +Desktop::SetWindowLook(WindowLayer *window, window_look newLook) { - fRootLayer->SetWindowLook(window, look); + if (window->Look() == newLook) + return; + + if (!WriteLockWindows()) + return; + + BRegion dirty; + window->SetLook(newLook, &dirty); + // TODO: test what happens when the window + // finds out it needs to resize itself... + + BRegion stillAvailableOnScreen; + _RebuildClippingForAllWindows(stillAvailableOnScreen); + _SetBackground(stillAvailableOnScreen); + + _TriggerWindowRedrawing(dirty); + + //_WindowsChanged(); + + WriteUnlockWindows(); } void -Desktop::SetWindowFeel(WindowLayer *window, window_feel feel) +Desktop::SetWindowFeel(WindowLayer *window, window_feel newFeel) { - fRootLayer->SetWindowFeel(window, feel); + if (window->Feel() == newFeel) + return; + + BAutolock _(this); + + window->SetFeel(newFeel); + + // TODO: implement window feels! } void -Desktop::SetWindowFlags(WindowLayer *window, uint32 flags) +Desktop::SetWindowFlags(WindowLayer *window, uint32 newFlags) { - fRootLayer->SetWindowFlags(window, flags); + if (window->Flags() == newFlags) + return; + + if (!WriteLockWindows()) + return; + + BRegion dirty; + window->SetFlags(newFlags, &dirty); + // TODO: test what happens when the window + // finds out it needs to resize itself... + + BRegion stillAvailableOnScreen; + _RebuildClippingForAllWindows(stillAvailableOnScreen); + _SetBackground(stillAvailableOnScreen); + + _TriggerWindowRedrawing(dirty); + + //_WindowsChanged(); + + WriteUnlockWindows(); +} + + +WindowLayer* +Desktop::WindowAt(BPoint where) +{ + for (WindowLayer* window = _CurrentWindows().LastWindow(); window; + window = window->PreviousWindow(fCurrentWorkspace)) { + if (window->VisibleRegion().Contains(where)) + return window; + } + + return NULL; +} + + +void +Desktop::SetMouseEventWindow(WindowLayer* window) +{ + fMouseEventWindow = window; } @@ -782,27 +1271,17 @@ Desktop::FindWindowLayerByClientToken(int32 token, team_id teamID) { BAutolock locker(this); - WindowLayer *wb; - for (int32 i = 0; (wb = (WindowLayer *)fWindowLayerList.ItemAt(i)); i++) { - if (wb->Window()->ClientToken() == token - && wb->Window()->ClientTeam() == teamID) - return wb; + for (WindowLayer *window = fAllWindows.FirstWindow(); window != NULL; + window = window->NextWindow(kAllWindowList)) { + if (window->ServerWindow()->ClientToken() == token + && window->ServerWindow()->ClientTeam() == teamID) + return window; } return NULL; } -const BObjectList & -Desktop::WindowList() const -{ - if (!IsLocked()) - debugger("You must lock before getting registered windows list\n"); - - return fWindowLayerList; -} - - void Desktop::WriteWindowList(team_id team, BPrivate::LinkSender& sender) { @@ -811,28 +1290,24 @@ Desktop::WriteWindowList(team_id team, BPrivate::LinkSender& sender) // compute the number of windows int32 count = 0; - if (team >= B_OK) { - for (int32 i = 0; i < fWindowLayerList.CountItems(); i++) { - WindowLayer* layer = fWindowLayerList.ItemAt(i); - if (layer->Window()->ClientTeam() == team) - count++; - } - } else - count = fWindowLayerList.CountItems(); + for (WindowLayer *window = fAllWindows.FirstWindow(); window != NULL; + window = window->NextWindow(kAllWindowList)) { + if (team < B_OK || window->ServerWindow()->ClientTeam() == team) + count++; + } // write list sender.StartMessage(B_OK); sender.Attach(count); - for (int32 i = 0; i < fWindowLayerList.CountItems(); i++) { - WindowLayer* layer = fWindowLayerList.ItemAt(i); - - if (team >= B_OK && layer->Window()->ClientTeam() != team) + for (WindowLayer *window = fAllWindows.FirstWindow(); window != NULL; + window = window->NextWindow(kAllWindowList)) { + if (team >= B_OK && window->ServerWindow()->ClientTeam() != team) continue; - sender.Attach(layer->Window()->ServerToken()); + sender.Attach(window->ServerWindow()->ServerToken()); } sender.Flush(); @@ -845,7 +1320,7 @@ Desktop::WriteWindowInfo(int32 serverToken, BPrivate::LinkSender& sender) BAutolock locker(this); BAutolock tokenLocker(BPrivate::gDefaultTokens); - ServerWindow* window; + ::ServerWindow* window; if (BPrivate::gDefaultTokens.GetToken(serverToken, B_SERVER_TOKEN, (void**)&window) != B_OK) { sender.StartMessage(B_ENTRY_NOT_FOUND); @@ -868,3 +1343,77 @@ Desktop::WriteWindowInfo(int32 serverToken, BPrivate::LinkSender& sender) sender.Flush(); } + +void +Desktop::MarkDirty(BRegion& region) +{ + if (region.CountRects() == 0) + return; + + if (WriteLockWindows()) { + // send redraw messages to all windows intersecting the dirty region + _TriggerWindowRedrawing(region); + + WriteUnlockWindows(); + } +} + + +void +Desktop::_RebuildClippingForAllWindows(BRegion& stillAvailableOnScreen) +{ + // the available region on screen starts with the entire screen area + // each window on the screen will take a portion from that area + + // figure out what the entire screen area is + stillAvailableOnScreen = fScreenRegion; + + // set clipping of each window + for (WindowLayer* window = _CurrentWindows().LastWindow(); window != NULL; + window = window->PreviousWindow(fCurrentWorkspace)) { + if (!window->IsHidden()) { + window->SetClipping(&stillAvailableOnScreen); + // that windows region is not available on screen anymore + stillAvailableOnScreen.Exclude(&window->VisibleRegion()); + } + } +} + + +void +Desktop::_TriggerWindowRedrawing(BRegion& newDirtyRegion) +{ + // send redraw messages to all windows intersecting the dirty region + for (WindowLayer* window = _CurrentWindows().LastWindow(); window != NULL; + window = window->PreviousWindow(fCurrentWorkspace)) { + if (!window->IsHidden() + && newDirtyRegion.Intersects(window->VisibleRegion().Frame())) + window->ProcessDirtyRegion(newDirtyRegion); + } +} + + +void +Desktop::_SetBackground(BRegion& background) +{ + // NOTE: the drawing operation is caried out + // in the clipping region rebuild, but it is + // ok actually, because it also avoids trails on + // moving windows + + // remember the region not covered by any windows + // and redraw the dirty background + BRegion dirtyBackground(background); + dirtyBackground.Exclude(&fBackgroundRegion); + dirtyBackground.IntersectWith(&background); + fBackgroundRegion = background; + if (dirtyBackground.Frame().IsValid()) { + if (GetDrawingEngine()->Lock()) { + GetDrawingEngine()->ConstrainClippingRegion(NULL); + GetDrawingEngine()->FillRegion(dirtyBackground, + fWorkspaces[fCurrentWorkspace].Color()); + + GetDrawingEngine()->Unlock(); + } + } +} diff --git a/src/servers/app/Desktop.h b/src/servers/app/Desktop.h index bc533672bc..85b175d12e 100644 --- a/src/servers/app/Desktop.h +++ b/src/servers/app/Desktop.h @@ -18,31 +18,37 @@ #include "VirtualScreen.h" #include "DesktopSettings.h" #include "MessageLooper.h" +#include "WindowList.h" #include "Workspace.h" #include "WorkspacePrivate.h" +#include + +#include #include #include -#include #include -#include -#include +#include #include +#define USE_MULTI_LOCKER 0 + +#if USE_MULTI_LOCKER +# include "MultiLocker.h" +#else +# include +#endif class BMessage; class DrawingEngine; class HWInterface; -class Layer; -class RootLayer; -class WindowLayer; +class ServerApp; namespace BPrivate { class LinkSender; }; - class Desktop : public MessageLooper, public ScreenOwner { public: Desktop(uid_t userID); @@ -63,7 +69,7 @@ class Desktop : public MessageLooper, public ScreenOwner { { return fActiveScreen; } Screen* ActiveScreen() const { return fActiveScreen; } - ::RootLayer* RootLayer() const { return fRootLayer; } + CursorManager& GetCursorManager() { return fCursorManager; } void ScreenChanged(Screen* screen); @@ -85,11 +91,13 @@ class Desktop : public MessageLooper, public ScreenOwner { { return fCurrentWorkspace; } Workspace::Private& WorkspaceAt(int32 index) { return fWorkspaces[index]; } + void UpdateWorkspaces(); // WindowLayer methods void ActivateWindow(WindowLayer* window); - void SendBehindWindow(WindowLayer* window, WindowLayer* front); + void SendWindowBehind(WindowLayer* window, + WindowLayer* behindOf = NULL); void ShowWindow(WindowLayer* window); void HideWindow(WindowLayer* window); @@ -107,11 +115,38 @@ class Desktop : public MessageLooper, public ScreenOwner { void SetWindowFeel(WindowLayer* window, window_feel feel); void SetWindowFlags(WindowLayer* window, uint32 flags); + WindowLayer* FocusWindow() const { return fFocus; } + WindowLayer* FrontWindow() const { return fFront; } + WindowLayer* BackWindow() const { return fBack; } + + WindowLayer* WindowAt(BPoint where); + + WindowLayer* MouseEventWindow() const { return fMouseEventWindow; } + void SetMouseEventWindow(WindowLayer* window); + + void SetFocusWindow(WindowLayer* window); + WindowLayer* FindWindowLayerByClientToken(int32 token, team_id teamID); //WindowLayer* FindWindowLayerByServerToken(int32 token); - // get list of registed windows - const BObjectList& WindowList() const; +#if USE_MULTI_LOCKER + bool ReadLockWindows() { return fWindowLock.ReadLock(); } + void ReadUnlockWindows() { fWindowLock.ReadUnlock(); } + + bool WriteLockWindows() { return fWindowLock.WriteLock(); } + void WriteUnlockWindows() { fWindowLock.WriteUnlock(); } +#else // USE_MULTI_LOCKER + bool ReadLockWindows() { return fWindowLock.Lock(); } + void ReadUnlockWindows() { fWindowLock.Unlock(); } + + bool WriteLockWindows() { return fWindowLock.Lock(); } + void WriteUnlockWindows() { fWindowLock.Unlock(); } +#endif // USE_MULTI_LOCKER + + void MarkDirty(BRegion& region); + + BRegion& BackgroundRegion() + { return fBackgroundRegion; } void WriteWindowList(team_id team, BPrivate::LinkSender& sender); @@ -119,14 +154,31 @@ class Desktop : public MessageLooper, public ScreenOwner { BPrivate::LinkSender& sender); private: + void _ShowWindow(WindowLayer* window, + bool affectsOtherWindows = true); + void _HideWindow(WindowLayer* window); + void _ChangeWindowWorkspaces(WindowLayer* window, uint32 oldWorkspaces, uint32 newWorkspaces); + void _BringWindowsToFront(WindowList& windows, + int32 list, bool wereVisible); status_t _ActivateApp(team_id team); + + void _RebuildClippingForAllWindows(BRegion& stillAvailableOnScreen); + void _TriggerWindowRedrawing(BRegion& newDirtyRegion); + void _SetBackground(BRegion& background); + + void _UpdateBack(); + void _UpdateFront(); + void _UpdateFronts(); + void _GetLooperName(char* name, size_t size); void _PrepareQuit(); void _DispatchMessage(int32 code, BPrivate::LinkReceiver &link); + WindowList& _CurrentWindows(); + private: friend class DesktopSettings; @@ -137,8 +189,8 @@ class Desktop : public MessageLooper, public ScreenOwner { ::EventDispatcher fEventDispatcher; port_id fInputPort; - BLocker fAppListLock; - BList fAppList; + BLocker fApplicationsLock; + BObjectList fApplications; sem_id fShutdownSemaphore; int32 fShutdownCount; @@ -146,12 +198,28 @@ class Desktop : public MessageLooper, public ScreenOwner { ::Workspace::Private fWorkspaces[32]; int32 fCurrentWorkspace; - BObjectList fWindowLayerList; + WindowList fAllWindows; ::RootLayer* fRootLayer; Screen* fActiveScreen; CursorManager fCursorManager; + +#if USE_MULTI_LOCKER + MultiLocker fWindowLock; +#else + BLocker fWindowLock; +#endif + + BRegion fBackgroundRegion; + BRegion fScreenRegion; + + bool fFocusFollowsMouse; + + WindowLayer* fMouseEventWindow; + WindowLayer* fFocus; + WindowLayer* fFront; + WindowLayer* fBack; }; #endif // DESKTOP_H diff --git a/src/servers/app/EventDispatcher.cpp b/src/servers/app/EventDispatcher.cpp index 44deb3b388..8d6466ed3d 100644 --- a/src/servers/app/EventDispatcher.cpp +++ b/src/servers/app/EventDispatcher.cpp @@ -15,7 +15,6 @@ #include #include -#include #include #include @@ -470,7 +469,14 @@ EventDispatcher::SendFakeMouseMoved(EventTarget& target, int32 viewToken) moved.AddPoint("screen_where", fLastCursorPosition); moved.AddInt32("buttons", fLastButtons); moved.AddInt32("_view_token", viewToken); - + + if (fDraggingMessage) { +/* moved.AddInt32("_msg_data", ); + moved.AddInt32("_msg_base_", ); + moved.AddInt32("_msg_what_", fDragMessage->what);*/ + moved.AddMessage("be:drag_message", &fDragMessage); + } + _SendMessage(target.Messenger(), &moved, kMouseTransitImportance); } @@ -495,6 +501,18 @@ EventDispatcher::SetHWInterface(HWInterface* interface) } +void +EventDispatcher::SetDragMessage(BMessage& message) +{ + printf("EventDispatcher::SetDragMessage()\n"); + + BAutolock _(*this); + + fDragMessage = message; + + fDraggingMessage = true; +} + // #pragma mark - Message methods @@ -575,6 +593,28 @@ EventDispatcher::_UnsetFeedFocus(BMessage* message) } +void +EventDispatcher::_DeliverDragMessage() +{ + printf("EventDispatcher::_DeliverDragMessage()\n"); + + if (fDraggingMessage && fPreviousMouseTarget) { + fDragMessage.RemoveName("_original_what"); + fDragMessage.AddInt32("_original_what", fDragMessage.what); + fDragMessage.what = _MESSAGE_DROPPED_; + +// fDragMessage.AddBool("dropped", true); +printf(" sending message to previous mouse target\n"); + _SendMessage(fPreviousMouseTarget->Messenger(), + &fDragMessage, 100.0); + } + + fDragMessage.MakeEmpty(); + fDragMessage.what = 0; + fDraggingMessage = false; +} + + // #pragma mark - Event loops @@ -604,6 +644,13 @@ EventDispatcher::_EventLoop() if (event->FindPoint("where", &where) == B_OK) fLastCursorPosition = where; + if (fDraggingMessage) { +/* event->AddInt32("_msg_data", ); + event->AddInt32("_msg_base_", ); + event->AddInt32("_msg_what_", fDragMessage->what);*/ + event->AddMessage("be:drag_message", &fDragMessage); + } + if (!HasCursorThread()) { // there is no cursor thread, we need to move the cursor ourselves BAutolock _(fCursorLock); @@ -717,7 +764,7 @@ EventDispatcher::_EventLoop() _UnsetFeedFocus(event); } if (pointerEvent) { - // this is added in the RootLayer mouse processing + // this is added in the Desktop mouse processing // but it's only intended for the focus view event->RemoveName("_view_token"); } @@ -744,6 +791,8 @@ EventDispatcher::_EventLoop() if (event->what == B_MOUSE_UP) { fSuspendFocus = false; _RemoveTemporaryListeners(); + if (fDraggingMessage) + _DeliverDragMessage(); } } diff --git a/src/servers/app/EventDispatcher.h b/src/servers/app/EventDispatcher.h index 678d1b33e9..72c73d0658 100644 --- a/src/servers/app/EventDispatcher.h +++ b/src/servers/app/EventDispatcher.h @@ -10,6 +10,7 @@ #include +#include #include #include #include @@ -83,6 +84,12 @@ class EventDispatcher : public BLocker { bool HasCursorThread(); void SetHWInterface(HWInterface* interface); + void SetDragMessage(BMessage& message); + // the message should be delivered on the next + // "mouse up". + // if the mouse is not pressed, it should + // be delivered to the "current" target right away. + private: status_t _Run(); void _Unset(); @@ -101,6 +108,8 @@ class EventDispatcher : public BLocker { uint32 eventMask, uint32 options, bool temporary); void _RemoveTemporaryListeners(); + void _DeliverDragMessage(); + void _EventLoop(); void _CursorLoop(); @@ -124,6 +133,9 @@ class EventDispatcher : public BLocker { BPoint fLastCursorPosition; int32 fLastButtons; + BMessage fDragMessage; + bool fDraggingMessage; + BLocker fCursorLock; HWInterface* fHWInterface; }; diff --git a/src/servers/app/Jamfile b/src/servers/app/Jamfile index ddab6e499e..84790d66d0 100644 --- a/src/servers/app/Jamfile +++ b/src/servers/app/Jamfile @@ -31,7 +31,6 @@ Server app_server : FontManager.cpp HashTable.cpp InputManager.cpp - Layer.cpp MessageLooper.cpp MultiLocker.cpp OffscreenServerWindow.cpp @@ -40,7 +39,6 @@ Server app_server : PicturePlayer.cpp RAMLinkMsgReader.cpp RGBColor.cpp - RootLayer.cpp ScreenManager.cpp ServerApp.cpp ServerBitmap.cpp @@ -49,10 +47,11 @@ Server app_server : ServerPicture.cpp ServerScreen.cpp ServerWindow.cpp - SubWindowList.cpp SystemPalette.cpp + ViewLayer.cpp VirtualScreen.cpp WindowLayer.cpp + WindowList.cpp Workspace.cpp WorkspacesLayer.cpp diff --git a/src/servers/app/Layer.cpp b/src/servers/app/Layer.cpp deleted file mode 100644 index 07f6bf3e27..0000000000 --- a/src/servers/app/Layer.cpp +++ /dev/null @@ -1,1487 +0,0 @@ -/* - * Copyright (c) 2001-2005, Haiku, Inc. - * Distributed under the terms of the MIT license. - * - * Authors: - * DarkWyrm - * Adi Oanca - * Stephan Aßmus - */ - -/*! - Class used for tracking drawing context and screen clipping. - One Layer per client BWindow (WindowLayer) and each BView therein. -*/ - -#include -#include -#include - -#include -#include -#include -#include - -#include "DebugInfoManager.h" -#include "DrawingEngine.h" -#include "DrawState.h" -#include "PortLink.h" -#include "RootLayer.h" -#include "ServerApp.h" -#include "ServerProtocol.h" -#include "ServerWindow.h" -#include "Layer.h" -#include "ServerBitmap.h" - -//#define DEBUG_LAYER -#ifdef DEBUG_LAYER -# define STRACE(x) printf x -#else -# define STRACE(x) ; -#endif - - -Layer::Layer(BRect frame, const char* name, int32 token, - uint32 resize, uint32 flags, DrawingEngine* driver) - : - fName(name), - fFrame(frame), - fScrollingOffset(0.0, 0.0), - - fDriver(driver), - fRootLayer(NULL), - fWindow(NULL), - - fDrawState(new DrawState), - - fParent(NULL), - fPreviousSibling(NULL), - fNextSibling(NULL), - fFirstChild(NULL), - fLastChild(NULL), - - fViewToken(token), - fFlags(flags), - fResizeMode(resize), - fEventMask(0UL), - fEventOptions(0UL), - - fHidden(false), - fIsTopLayer(false), - fViewColor(255, 255, 255, 255), - - fBackgroundBitmap(NULL), - fOverlayBitmap(NULL) -{ - if (!frame.IsValid()) { - char helper[1024]; - sprintf(helper, "Layer::Layer(BRect(%.1f, %.1f, %.1f, %.1f), name: %s, token: %ld) - frame is invalid\n", - frame.left, frame.top, frame.right, frame.bottom, name, token); - CRITICAL(helper); - fFrame.Set(0, 0, 1, 1); - } - - if (!fDriver) - CRITICAL("You MUST have a valid driver to init a Layer object\n"); - - // NOTE: This flag is forwarded to a DrawState setting, even - // though it is actually not part of a "state". However, - // it is an important detail of a graphics context, and we - // have no other means to pass this setting on to the DrawingEngine - // other than through the DrawState. If we ever add a flag - // B_ANTI_ALIASING to the view flags, it would have to be passed - // in the same way. Though when breaking binary compatibility, - // we might want to make this an actual part of a "state" (with - // a different API to set these). - // Note that the flag is also tested (updated) in Push/PopState and - // SetFlags(). - fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); - - STRACE(("Layer(%s) successfuly created\n", Name())); -} - - -Layer::~Layer() -{ - delete fDrawState; - - if (fWindow != NULL) - fWindow->App()->ViewTokens().RemoveToken(ViewToken()); - - Layer* child = fFirstChild; - while (child != NULL) { - Layer* nextChild = child->fNextSibling; - - delete child; - child = nextChild; - } -} - - -/*! - \brief Adds a child layer to the current one - \param layer a new child layer - \param serverWin the serverwindow to which the layer will belong - - Unlike the BView version, if the layer already belongs to another, then - it spits an error to stdout and returns. -*/ -void -Layer::AddChild(Layer* child, ServerWindow* window) -{ - STRACE(("Layer(%s)::AddChild(%s)\n", Name(), child->Name())); - - if (child->fParent != NULL) { - printf("ERROR: AddChild(): Layer already has a parent\n"); - return; - } - - // attach layer to the tree structure - _AddChildToList(child); - - // if we have no RootLayer yet, then there is no need to set any parameters -- - // they will be set when the RootLayer for this tree will be added - // to the main tree structure. - if (!fRootLayer) { - STRACE(("Layer(%s)::AddChild(%s) END\n", Name(), child->Name())); - return; - } - - // 2) Iterate over the newly-added layer and all its children, setting the - // root layer and server window and also rebuilding the full-size region - // for every descendant of the newly-added layer - - Layer* stop = child; - while (true) { - // action block - - // 2.1) set the RootLayer for this object. - child->SetRootLayer(child->fParent->fRootLayer); - - // 2.2) this Layer must know if it has a ServerWindow object attached. - child->fWindow = window; - - // insert view into local token space - window->App()->ViewTokens().SetToken(child->ViewToken(), - B_HANDLER_TOKEN, child); - - // tree parsing algorithm - if (child->fFirstChild) { - // go deep - child = child->fFirstChild; - } else { - // go right or up - - if (child == stop) // our trip is over - break; - - if (child->fNextSibling) { - // go right - child = child->fNextSibling; - } else { - // go up - while (child->fParent->fNextSibling == NULL && child->fParent != stop) - child = child->fParent; - - if (child->fParent == stop) // that's enough! - break; - - child = child->fParent->fNextSibling; - } - } - } -} - - -/*! - \brief Removes a child layer from the current one - \param layer the layer to remove - - If the layer does not belong to the the current layer, then this function - spits out an error to stdout and returns -*/ -void -Layer::RemoveChild(Layer *child) -{ - STRACE(("Layer(%s)::RemoveChild(%s)\n", Name(), child->Name())); - - if (!child->fParent) { - printf("ERROR: RemoveChild(): Layer doesn't have a parent\n"); - return; - } - if (child->fParent != this) { - printf("ERROR: RemoveChild(): Layer is not a child of this layer\n"); - return; - } - - // remove this layer from the main tree. - - _RemoveChildFromList(child); - child->_ClearVisibleRegions(); - - // iterate over all of the removed-layer's descendants and unset the - // root layer, server window, and all redraw-related regions - - Layer* stop = child; - while (true) { - // action block - - // 2.1) set the RootLayer for this object. - child->SetRootLayer(NULL); - // 2.2) this Layer must know if it has a ServerWindow object attached. - if (child->Window()) - child->Window()->App()->ViewTokens().RemoveToken(child->ViewToken()); - child->fWindow = NULL; - - // tree parsing algorithm - if (child->fFirstChild) { - // go deep - child = child->fFirstChild; - } else { - // go right or up - if (child == stop) // out trip is over - break; - - if (child->fNextSibling) { - // go right - child = child->fNextSibling; - } else { - // go up - while (child->fParent->fNextSibling == NULL && child->fParent != stop) - child = child->fParent; - - if (child->fParent == stop) // that enough! - break; - - child = child->fParent->fNextSibling; - } - } - } -} - - -bool -Layer::_AddChildToList(Layer* child, Layer* before) -{ - if (!child) - return false; - if (child->fParent != NULL) { - debugger("Layer already belongs to someone else"); - return false; - } - if (before != NULL && before->fParent != this) { - debugger("Invalid before layer"); - return false; - } - - if (before != NULL) { - // add view before this one - child->fNextSibling = before; - child->fPreviousSibling = before->fPreviousSibling; - if (child->fPreviousSibling != NULL) - child->fPreviousSibling->fNextSibling = child; - - before->fPreviousSibling = child; - if (fFirstChild == before) - fFirstChild = child; - } else { - // add view to the end of the list - if (fLastChild != NULL) { - fLastChild->fNextSibling = child; - child->fPreviousSibling = fLastChild; - } else { - fFirstChild = child; - child->fPreviousSibling = NULL; - } - - child->fNextSibling = NULL; - fLastChild = child; - } - - child->fParent = this; - return true; -} - - -void -Layer::_RemoveChildFromList(Layer* child) -{ - // update first/last layers - - if (fFirstChild == child) { - // it's the first child - fFirstChild = child->fNextSibling; - } else { - // it must have a previous sibling - child->fPreviousSibling->fNextSibling = child->fNextSibling; - } - - if (fLastChild == child) { - // it's the last child - fLastChild = child->fPreviousSibling; - } else { - // it must have a next sibling - child->fNextSibling->fPreviousSibling = child->fPreviousSibling; - } - - child->fPreviousSibling = NULL; - child->fNextSibling = NULL; - child->fParent = NULL; -} - - -//! Removes the calling layer from the tree -void -Layer::RemoveSelf() -{ - // A Layer removes itself from the tree (duh) - if (fParent == NULL) { - printf("ERROR: RemoveSelf(): Layer doesn't have a parent\n"); - return; - } - fParent->RemoveChild(this); -} - - -/*! - \return true if the child is owned by this Layer, false if not -*/ -bool -Layer::HasChild(Layer* layer) -{ - for (Layer* child = FirstChild(); child; child = child->NextLayer()) { - if (child == layer) - return true; - } - return false; -} - - -//! Returns the number of children -uint32 -Layer::CountChildren() const -{ - uint32 count = 0; - Layer* child = FirstChild(); - while (child != NULL) { - child = child->NextLayer(); - count++; - } - return count; -} - - -/*! - \brief Returns the layer at the given point - \param pt The point to look the layer at - \return The layer containing the point or NULL if no layer found -*/ -Layer* -Layer::LayerAt(BPoint where) -{ - if (fVisible.Contains(where)) - return this; - - if (fFullVisible.Contains(where)) { - for (Layer* child = LastChild(); child; child = child->PreviousLayer()) { - if (Layer* layer = child->LayerAt(where)) - return layer; - } - } - - return NULL; -} - - -Layer* -Layer::FirstChild() const -{ - return fFirstChild; -} - - -Layer* -Layer::NextLayer() const -{ - return fNextSibling; -} - - -Layer* -Layer::PreviousLayer() const -{ - return fPreviousSibling; -} - - -Layer* -Layer::LastChild() const -{ - return fLastChild; -} - - -void -Layer::SetName(const char* name) -{ - fName.SetTo(name); -} - - -void -Layer::SetUserClipping(const BRegion& region) -{ - fDrawState->SetClippingRegion(region); - - // rebuild clipping - _RebuildDrawingRegion(); -} - - -void -Layer::SetFlags(uint32 flags) -{ - fFlags = flags; - fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); -} - - -void -Layer::SetEventMask(uint32 eventMask, uint32 options) -{ - fEventMask = eventMask; - fEventOptions = options; -} - - -void -Layer::Draw(const BRect &rect) -{ -#ifdef DEBUG_LAYER - printf("Layer(%s)::Draw: ", Name()); - rect.PrintToStream(); -#endif - - if (!ViewColor().IsTransparentMagic()) - fDriver->FillRect(rect, ViewColor()); -} - -/*! - \brief Shows the layer - \param invalidate Invalidate the region when showing the layer. defaults to true -*/ -void -Layer::Show(bool invalidate) -{ - STRACE(("Layer(%s)::Show()\n", Name())); - if(!IsHidden()) { - // an ancestor may be hidden. OK, we're not visible, - // but we're changing our visibility state - fHidden = false; - return; - } - - fHidden = false; - - if (invalidate) { - // compute the region this layer wants for itself - BRegion invalid; - GetOnScreenRegion(invalid); - if (invalid.CountRects() > 0) { - fParent->MarkForRebuild(invalid); - GetRootLayer()->MarkForRedraw(invalid); - - fParent->TriggerRebuild(); - GetRootLayer()->TriggerRedraw(); - } - } -} - -/*! - \brief Shows the layer - \param invalidate Invalidate the region when hiding the layer. defaults to true -*/ -void -Layer::Hide(bool invalidate) -{ - STRACE(("Layer(%s)::Hide()\n", Name())); - if (IsHidden()) { - // an ancestor may be hidden. OK, we're not visible, - // but we're changing our visibility state - fHidden = true; - return; - } - - fHidden = true; - if (invalidate && fFullVisible.CountRects() > 0) { - BRegion invalid(fFullVisible); - - fParent->MarkForRebuild(invalid); - GetRootLayer()->MarkForRedraw(invalid); - - fParent->TriggerRebuild(); - GetRootLayer()->TriggerRedraw(); - } -} - -//! Returns true if the layer is hidden -bool -Layer::IsHidden(void) const -{ - if (fHidden) - return true; - - if (fParent != NULL) - return fParent->IsHidden(); - - return fHidden; -} - - -void -Layer::PushState() -{ - fDrawState = fDrawState->PushState(); - fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); -} - - -void -Layer::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) - _RebuildDrawingRegion(); -} - - -//! Matches the BView call of the same name -BRect -Layer::Bounds() const -{ - BRect r(fFrame); - r.OffsetTo(ScrollingOffset()); - return r; -} - - -//! Matches the BView call of the same name -BRect -Layer::Frame() const -{ - return fFrame; -} - - -//! Moves the layer by specified values, complete with redraw -void -Layer::MoveBy(float x, float y) -{ - STRACE(("Layer(%s)::MoveBy()\n", Name())); - - if (x == 0.0f && y == 0.0f) - return; - - // must lock, even if we change frame coordinates - if (fParent && !IsHidden() && GetRootLayer() && GetRootLayer()->Lock()) { - fFrame.OffsetBy(x, y); - - BRegion oldFullVisible(fFullVisible); - - // we'll invalidate the old position and the new, maxmial one. - BRegion invalid; - GetOnScreenRegion(invalid); - invalid.Include(&fFullVisible); - - fParent->MarkForRebuild(invalid); - fParent->TriggerRebuild(); - - // done rebuilding regions, now copy common parts and redraw regions that became visible - - // include the actual and the old fullVisible regions. later, we'll exclude the common parts. - BRegion redrawReg(fFullVisible); - redrawReg.Include(&oldFullVisible); - - // offset to layer's new location so that we can calculate the common region. - oldFullVisible.OffsetBy(x, y); - - // finally we have the region that needs to be redrawn. - redrawReg.Exclude(&oldFullVisible); - - // by intersecting the old fullVisible offseted to layer's new location, with the current - // fullVisible, we'll have the common region which can be copied using HW acceleration. - oldFullVisible.IntersectWith(&fFullVisible); - - // offset back and instruct the HW to do the actual copying. - oldFullVisible.OffsetBy(-x, -y); - GetDrawingEngine()->CopyRegion(&oldFullVisible, x, y); - - GetRootLayer()->MarkForRedraw(redrawReg); - GetRootLayer()->TriggerRedraw(); - - GetRootLayer()->Unlock(); - } else { - // just offset to the new position - fFrame.OffsetBy(x, y); - } - - MovedByHook(x, y); - - _SendViewCoordUpdateMsg(); -} - - -//! Resize the layer by the specified amount, complete with redraw -void -Layer::ResizeBy(float x, float y) -{ - STRACE(("Layer(%s)::ResizeBy()\n", Name())); - - if (x == 0.0f && y == 0.0f) - return; - - // must lock, even if we change frame coordinates - if (fParent && !IsHidden() && GetRootLayer() && GetRootLayer()->Lock()) { - fFrame.Set(fFrame.left, fFrame.top, fFrame.right+x, fFrame.bottom+y); - -// TODO: you should call this hook function AFTER all region rebuilding -// and redrawing stuff - ResizedByHook(x, y, false); - -// TODO: ResizedByHook(x,y,true) is called from inside _ResizeLayerFrameBy -// Should call this AFTER region rebuilding and redrawing. - // resize children using their resize_mask. - for (Layer *child = LastChild(); child != NULL; child = child->PreviousLayer()) - child->_ResizeLayerFrameBy(x, y); - - BRegion oldFullVisible(fFullVisible); - // this is required to invalidate the old border - BRegion oldVisible(fVisible); - - // in case they moved, bottom, right and center aligned layers must be redrawn - BRegion redrawMore; - _RezizeLayerRedrawMore(redrawMore, x, y); - - // we'll invalidate the old area and the new, maxmial one. - BRegion invalid; - GetOnScreenRegion(invalid); - invalid.Include(&fFullVisible); - - fParent->MarkForRebuild(invalid); - fParent->TriggerRebuild(); - - // done rebuilding regions, now redraw regions that became visible - - // what's invalid, are the differences between to old and the new fullVisible region - // 1) in case we grow. - BRegion redrawReg(fFullVisible); - redrawReg.Exclude(&oldFullVisible); - // 2) in case we shrink - BRegion redrawReg2(oldFullVisible); - redrawReg2.Exclude(&fFullVisible); - // 3) combine. - redrawReg.Include(&redrawReg2); - - // for center, right and bottom alligned layers, redraw their old positions - redrawReg.Include(&redrawMore); - - // layers that had their frame modified must be entirely redrawn. - _RezizeLayerRedrawMore(redrawReg, x, y); - - // include layer's visible region in case we want a full update on resize - if (fFlags & B_FULL_UPDATE_ON_RESIZE && fVisible.Frame().IsValid()) { - _ResizeLayerFullUpdateOnResize(redrawReg, x, y); - - redrawReg.Include(&fVisible); - redrawReg.Include(&oldVisible); - } - - GetRootLayer()->MarkForRedraw(redrawReg); - GetRootLayer()->TriggerRedraw(); - - GetRootLayer()->Unlock(); - } else { - // just resize our frame and those of out descendants if their resize mask says so - fFrame.Set(fFrame.left, fFrame.top, fFrame.right+x, fFrame.bottom+y); - -// TODO: you should call this hook function AFTER all region rebuilding -// and redrawing stuff - ResizedByHook(x, y, false); - -// TODO: ResizedByHook(x,y,true) is called from inside _ResizeLayerFrameBy -// Should call this AFTER region rebuilding and redrawing. - // resize children using their resize_mask. - for (Layer *child = LastChild(); child != NULL; child = child->PreviousLayer()) - child->_ResizeLayerFrameBy(x, y); - } - - _SendViewCoordUpdateMsg(); -} - - -//! scrolls the layer by the specified amount, complete with redraw -void -Layer::ScrollBy(float x, float y) -{ - STRACE(("Layer(%s)::ScrollBy()\n", Name())); - - if (x == 0.0f && y == 0.0f) - return; - - fScrollingOffset.x += x; - fScrollingOffset.y += y; - - // must lock, even if we change frame/origin coordinates - if (!IsHidden() && GetRootLayer() && GetRootLayer()->Lock()) { - - // set the region to be invalidated. - BRegion invalid(fFullVisible); - - MarkForRebuild(invalid); - - TriggerRebuild(); - - // for the moment we say that the whole surface needs to be redraw. - BRegion redrawReg(fFullVisible); - - // offset old region so that we can start comparing. - invalid.OffsetBy(x, y); - - // compute the common region. we'll use HW acc to copy this to the new location. - invalid.IntersectWith(&fFullVisible); - GetDrawingEngine()->CopyRegion(&invalid, -x, -y); - - // common region goes back to its original location. then, by excluding - // it from curent fullVisible we'll obtain the region that needs to be redrawn. - invalid.OffsetBy(-x, -y); -// TODO: a quick fix for the scrolling problem!!! FIX THIS! -// redrawReg.Exclude(&invalid); - - GetRootLayer()->MarkForRedraw(redrawReg); - GetRootLayer()->TriggerRedraw(); - - GetRootLayer()->Unlock(); - } - - ScrolledByHook(x, y); - -// TODO: I think we should update the client-side that bounds rect has modified -// SendViewCoordUpdateMsg(); -} - -void -Layer::CopyBits(BRect& src, BRect& dst, int32 xOffset, int32 yOffset) -{ - // NOTE: The correct behaviour is this: - // * The region that is copied is the - // src rectangle, no matter if it fits - // into the dst rectangle. It is copied - // by the offset dst.LeftTop() - src.LeftTop() - // * The dst rectangle is used for invalidation: - // Any area in the dst rectangle that could - // not be copied from src (because either the - // src rectangle was not big enough, or because there - // were parts cut off by the current layer clipping), - // are triggering BView::Draw() to be called - // and for these parts only. - - if (!GetRootLayer()) - return; - - if (!IsHidden() && GetRootLayer()->Lock()) { - // the region that is going to be copied - BRegion copyRegion(src); - - // apply the current clipping of the layer - copyRegion.IntersectWith(&fVisible); - - // offset the region to the destination - // and apply the current clipping there as well - copyRegion.OffsetBy(xOffset, yOffset); - copyRegion.IntersectWith(&fVisible); - - // the region at the destination that needs invalidation - BRegion redrawReg(dst); - // exclude the region drawn by the copy operation -// TODO: quick fix for our scrolling problem. FIX THIS! -// redrawReg.Exclude(©Region); - // apply the current clipping as well - redrawReg.IntersectWith(&fVisible); - - // move the region back for the actual operation - copyRegion.OffsetBy(-xOffset, -yOffset); - - GetDrawingEngine()->CopyRegion(©Region, xOffset, yOffset); - - // trigger the redraw - GetRootLayer()->MarkForRedraw(redrawReg); - GetRootLayer()->TriggerRedraw(); - - GetRootLayer()->Unlock(); - } -} - - -void -Layer::MouseDown(BMessage *msg, BPoint where, int32* _viewToken) -{ - *_viewToken = ViewToken(); -} - - -void -Layer::MouseUp(BMessage *msg, BPoint where, int32* _viewToken) -{ - *_viewToken = ViewToken(); -} - - -void -Layer::MouseMoved(BMessage *msg, BPoint where, int32* _viewToken) -{ - *_viewToken = ViewToken(); -} - - -void -Layer::WorkspaceActivated(int32 index, bool active) -{ -} - - -void -Layer::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces) -{ -} - - -void -Layer::Activated(bool active) -{ -} - - -BPoint -Layer::ScrollingOffset() const -{ - return fScrollingOffset; -} - - -void -Layer::SetDrawingOrigin(BPoint origin) -{ - fDrawState->SetOrigin(origin); - - // rebuild clipping - if (fDrawState->ClippingRegion()) - _RebuildDrawingRegion(); -} - - -BPoint -Layer::DrawingOrigin() const -{ - BPoint origin(fDrawState->Origin()); - float scale = Scale(); - - origin.x *= scale; - origin.y *= scale; - - return origin; -} - - -void -Layer::SetScale(float scale) -{ - fDrawState->SetScale(scale); - - // rebuild clipping - if (fDrawState->ClippingRegion()) - _RebuildDrawingRegion(); -} - - -float -Layer::Scale() const -{ - return CurrentState()->Scale(); -} - -void -Layer::SetViewColor(const RGBColor& color) -{ - fViewColor = color; -} - - -void -Layer::SetBackgroundBitmap(const ServerBitmap* bitmap) -{ - // TODO: What about reference counting? - // "Release" old fBackgroundBitmap and "Aquire" new one? - fBackgroundBitmap = bitmap; -} - -// SetOverlayBitmap -void -Layer::SetOverlayBitmap(const ServerBitmap* bitmap) -{ - // TODO: What about reference counting? - // "Release" old fOverlayBitmap and "Aquire" new one? - fOverlayBitmap = bitmap; -} - -void -Layer::MovedByHook(float dx, float dy) -{ - if (Window() && !IsTopLayer()) - _AddToViewsWithInvalidCoords(); -} - -void -Layer::ResizedByHook(float dx, float dy, bool automatic) -{ - if (Window() && !IsTopLayer()) - _AddToViewsWithInvalidCoords(); -} - -void -Layer::ScrolledByHook(float dx, float dy) -{ - // empty. -} - -//! converts a point from local to parent's coordinate system -void -Layer::ConvertToParent(BPoint* pt) const -{ - pt->x += fFrame.left - fScrollingOffset.x; - pt->y += fFrame.top - fScrollingOffset.y; -} - -//! converts a rect from local to parent's coordinate system -void -Layer::ConvertToParent(BRect* rect) const -{ - rect->OffsetBy(fFrame.left - fScrollingOffset.x, - fFrame.top - fScrollingOffset.y); -} - -//! converts a region from local to parent's coordinate system -void -Layer::ConvertToParent(BRegion* reg) const -{ - reg->OffsetBy(fFrame.left - fScrollingOffset.x, - fFrame.top - fScrollingOffset.y); -} - -//! converts a point from parent's to local coordinate system -void -Layer::ConvertFromParent(BPoint* pt) const -{ - pt->x += fScrollingOffset.x - fFrame.left; - pt->y += fScrollingOffset.y - fFrame.top; -} - -//! converts a rect from parent's to local coordinate system -void -Layer::ConvertFromParent(BRect* rect) const -{ - rect->OffsetBy(fScrollingOffset.x - fFrame.left, - fScrollingOffset.y - fFrame.top); -} - -//! converts a region from parent's to local coordinate system -void -Layer::ConvertFromParent(BRegion* reg) const -{ - reg->OffsetBy(fScrollingOffset.x - fFrame.left, - fScrollingOffset.y - fFrame.top); -} - -//! converts a point from local to screen coordinate system -void -Layer::ConvertToScreen(BPoint* pt) const -{ - ConvertToParent(pt); - - if (fParent) - fParent->ConvertToScreen(pt); -} - -//! converts a rect from local to screen coordinate system -void -Layer::ConvertToScreen(BRect* rect) const -{ - ConvertToParent(rect); - - if (fParent) - fParent->ConvertToScreen(rect); -} - -//! converts a region from local to screen coordinate system -void -Layer::ConvertToScreen(BRegion* reg) const -{ - ConvertToParent(reg); - - if (fParent) - fParent->ConvertToScreen(reg); -} - -//! converts a point from screen to local coordinate system -void -Layer::ConvertFromScreen(BPoint* pt) const -{ - ConvertFromParent(pt); - - if (fParent) - fParent->ConvertFromScreen(pt); -} - -//! converts a rect from screen to local coordinate system -void -Layer::ConvertFromScreen(BRect* rect) const -{ - ConvertFromParent(rect); - - if (fParent) - fParent->ConvertFromScreen(rect); -} - -//! converts a region from screen to local coordinate system -void -Layer::ConvertFromScreen(BRegion* reg) const -{ - ConvertFromParent(reg); - - if (fParent) - fParent->ConvertFromScreen(reg); -} - -//! converts a point from local *drawing* to screen coordinate system -void -Layer::ConvertToScreenForDrawing(BPoint* pt) const -{ - fDrawState->Transform(pt); - // NOTE: from here on, don't use the - // "*ForDrawing()" versions of the parent! - ConvertToScreen(pt); -} - -//! converts a rect from local *drawing* to screen coordinate system -void -Layer::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 -Layer::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 -Layer::ConvertFromScreenForDrawing(BPoint* pt) const -{ - ConvertFromScreen(pt); - fDrawState->InverseTransform(pt); -} - -void -Layer::_ResizeLayerFrameBy(float x, float y) -{ - uint16 rm = fResizeMode & 0x0000FFFF; - BRect newFrame = fFrame; - - if ((rm & 0x0F00U) == _VIEW_LEFT_ << 8) - newFrame.left += 0.0f; - else if ((rm & 0x0F00U) == _VIEW_RIGHT_ << 8) - newFrame.left += x; - else if ((rm & 0x0F00U) == _VIEW_CENTER_ << 8) - newFrame.left += x/2; - - if ((rm & 0x000FU) == _VIEW_LEFT_) - newFrame.right += 0.0f; - else if ((rm & 0x000FU) == _VIEW_RIGHT_) - newFrame.right += x; - else if ((rm & 0x000FU) == _VIEW_CENTER_) - newFrame.right += x/2; - - if ((rm & 0xF000U) == _VIEW_TOP_ << 12) - newFrame.top += 0.0f; - else if ((rm & 0xF000U) == _VIEW_BOTTOM_ << 12) - newFrame.top += y; - else if ((rm & 0xF000U) == _VIEW_CENTER_ << 12) - newFrame.top += y/2; - - if ((rm & 0x00F0U) == _VIEW_TOP_ << 4) - newFrame.bottom += 0.0f; - else if ((rm & 0x00F0U) == _VIEW_BOTTOM_ << 4) - newFrame.bottom += y; - else if ((rm & 0x00F0U) == _VIEW_CENTER_ << 4) - newFrame.bottom += y/2; - - if (newFrame != fFrame) { - float offsetX, offsetY; - float dx, dy; - - dx = newFrame.Width() - fFrame.Width(); - dy = newFrame.Height() - fFrame.Height(); - offsetX = newFrame.left - fFrame.left; - offsetY = newFrame.top - fFrame.top; - - fFrame = newFrame; - - if (offsetX != 0.0f || offsetY != 0.0f) { - MovedByHook(offsetX, offsetY); - } - - if (dx != 0.0f || dy != 0.0f) { - // call hook function - ResizedByHook(dx, dy, true); // automatic - - for (Layer* child = LastChild(); child; child = child->PreviousLayer()) - child->_ResizeLayerFrameBy(dx, dy); - } - } -} - - -void -Layer::_RezizeLayerRedrawMore(BRegion ®, float dx, float dy) -{ - if (dx == 0 && dy == 0) - return; - - for (Layer* child = LastChild(); child; child = child->PreviousLayer()) { - uint16 rm = child->fResizeMode & 0x0000FFFF; - - if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || - (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) { - // NOTE: this is not exactly corect, but it works :-) - // Normaly we shoud've used the child's old, required region - the one returned - // from get_user_region() with the old frame, and the current one. child->Bounds() - // works for the moment so we leave it like this. - - // calculate the old bounds. - BRect oldBounds(child->Bounds()); - if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT) - oldBounds.right -=dx; - if ((rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) - oldBounds.bottom -=dy; - - // compute the region that became visible because we got bigger OR smaller. - BRegion regZ(child->Bounds()); - regZ.Include(oldBounds); - regZ.Exclude(oldBounds & child->Bounds()); - - child->ConvertToScreen(®Z); - - // intersect that with this'(not child's) fullVisible region - regZ.IntersectWith(&fFullVisible); - reg.Include(®Z); - - child->_RezizeLayerRedrawMore(reg, - (rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT? dx: 0, - (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM? dy: 0); - - // above, OR this: - // reg.Include(&child->fFullVisible); - } else if (((rm & 0x0F0F) == (uint16)B_FOLLOW_RIGHT && dx != 0) - || ((rm & 0x0F0F) == (uint16)B_FOLLOW_H_CENTER && dx != 0) - || ((rm & 0xF0F0) == (uint16)B_FOLLOW_BOTTOM && dy != 0) - || ((rm & 0xF0F0) == (uint16)B_FOLLOW_V_CENTER && dy != 0)) { - reg.Include(&child->fFullVisible); - } - } -} - - -void -Layer::_ResizeLayerFullUpdateOnResize(BRegion ®, float dx, float dy) -{ - if (dx == 0 && dy == 0) - return; - - for (Layer* child = LastChild(); child; child = child->PreviousLayer()) { - uint16 rm = child->fResizeMode & 0x0000FFFF; - - if ((rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT || (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM) { - if (child->fFlags & B_FULL_UPDATE_ON_RESIZE && child->fVisible.CountRects() > 0) - reg.Include(&child->fVisible); - - child->_ResizeLayerFullUpdateOnResize(reg, - (rm & 0x0F0F) == (uint16)B_FOLLOW_LEFT_RIGHT? dx: 0, - (rm & 0xF0F0) == (uint16)B_FOLLOW_TOP_BOTTOM? dy: 0); - } - } -} - - -/*! - \brief Returns the region of the layer that is within the screen region -*/ -void -Layer::GetOnScreenRegion(BRegion ®ion) -{ - // 1) set to frame in screen coords - BRect frame(Bounds()); - ConvertToScreen(&frame); - region.Set(frame); - - // 2) intersect with screen region - BRegion screenRegion(GetRootLayer()->Bounds()); - region.IntersectWith(&screenRegion); - -/* - // 3) impose user constrained regions - DrawState *stackData = fDrawState; - while (stackData) { - if (stackData->ClippingRegion()) { - reg.IntersectWith(stackData->ClippingRegion()); - } - stackData = stackData->PreviousState(); - }*/ -} - - -void -Layer::_RebuildVisibleRegions(const BRegion &invalid, - const BRegion &parentLocalVisible, const Layer *startFrom) -{ -/* - // no point in continuing if this layer is hidden. - if (fHidden) - return; - - // no need to go deeper if the parent doesn't have a visible region anymore - // and our fullVisible region is also empty. - if (!parentLocalVisible.Frame().IsValid() && !(fFullVisible.CountRects() > 0)) - return; - - bool fullRebuild = false; - - // intersect maximum wanted region with the invalid region - BRegion common; - GetOnScreenRegion(common); - common.IntersectWith(&invalid); - - // if the resulted region is not valid, this layer is not in the catchment area - // of the region being invalidated - if (!common.CountRects() > 0) - return; - - // now intersect with parent's visible part of the region that was/is invalidated - common.IntersectWith(&parentLocalVisible); - - // exclude the invalid region - fFullVisible.Exclude(&invalid); - fVisible.Exclude(&invalid); - - // put in what's really visible - fFullVisible.Include(&common); - - // allow this layer to hide some parts from its children - _ReserveRegions(common); - - for (Layer *child = LastChild(); child; child = child->PreviousLayer()) { - if (child == startFrom) - fullRebuild = true; - - if (fullRebuild) - child->_RebuildVisibleRegions(invalid, common, child->LastChild()); - - // to let children know much they can take from parent's visible region - common.Exclude(&child->fFullVisible); - } - - // include what's left after all children took what they could. - fVisible.Include(&common); -*/ - -// NOTE: I modified this method for the moment because of some issues that I have -// with the new public methods that I recently introduced. -// This code works very well, the single problem that it has it's that it -// rebuilds all the visible regions of its descendants. -// TODO: only rebuild what's needed. See above code. -// NOTE2: this does not affect the redrawing code. - - // no point in continuing if this layer is hidden. - if (fHidden) - return; - - // no need to go deeper if the parent doesn't have a visible region anymore - if (!parentLocalVisible.Frame().IsValid()) - return; - - BRegion common; - GetOnScreenRegion(common); - - // see how much you can take - common.IntersectWith(&parentLocalVisible); - fFullVisible = common; - fVisible.MakeEmpty(); - - // allow this layer to hide some parts from its children - _ReserveRegions(common); - - for (Layer *child = LastChild(); child; child = child->PreviousLayer()) { - child->_RebuildVisibleRegions(invalid, common, child->LastChild()); - - // to let children know much they can take from parent's visible region - common.Exclude(&child->fFullVisible); - } - - // include what's left after all children took what they could. - fVisible.Include(&common); - - _RebuildDrawingRegion(); -} - - -void -Layer::_RebuildDrawingRegion() -{ - fDrawingRegion = fVisible; - // apply user clipping which is in native coordinate system - if (const BRegion* userClipping = fDrawState->ClippingRegion()) { - BRegion screenUserClipping(*userClipping); - ConvertToScreenForDrawing(&screenUserClipping); - fDrawingRegion.IntersectWith(&screenUserClipping); - } -} - - -void -Layer::_ReserveRegions(BRegion ®) -{ - // Empty for Layer objects -} - - -void -Layer::_ClearVisibleRegions() -{ - fDrawingRegion.MakeEmpty(); - - fVisible.MakeEmpty(); - fFullVisible.MakeEmpty(); - for (Layer *child = LastChild(); child; child = child->PreviousLayer()) - child->_ClearVisibleRegions(); -} - - -/*! Mark a region dirty so that the next region rebuild for us - and our children will take this into account -*/ -void -Layer::MarkForRebuild(const BRegion &dirty) -{ - fDirtyForRebuild.Include(&dirty); -} - - -/*! This will trigger visible region recalculation for us and - our descendants. -*/ -void -Layer::TriggerRebuild() -{ - BRegion totalInvalidReg; - - _GetAllRebuildDirty(&totalInvalidReg); - - if (totalInvalidReg.CountRects() > 0) { - BRegion localFullVisible(fFullVisible); - -// localFullVisible.IntersectWith(&totalInvalidReg); - - _ClearVisibleRegions(); - - _RebuildVisibleRegions(totalInvalidReg, localFullVisible, LastChild()); - } -} - - -//! find out the region for which we must rebuild the visible regions -void -Layer::_GetAllRebuildDirty(BRegion *totalReg) -{ - totalReg->Include(&fDirtyForRebuild); - - for (Layer *child = LastChild(); child; child = child->PreviousLayer()) - child->_GetAllRebuildDirty(totalReg); - - fDirtyForRebuild.MakeEmpty(); -} - - -void -Layer::_AllRedraw(const BRegion& invalid) -{ - if (fVisible.CountRects() > 0) { - BRegion updateReg(fVisible); - updateReg.IntersectWith(&invalid); - - if (updateReg.CountRects() > 0) { - fDriver->ConstrainClippingRegion(&updateReg); - Draw(updateReg.Frame()); - fDriver->ConstrainClippingRegion(NULL); - } - } - - for (Layer *child = LastChild(); child != NULL; child = child->PreviousLayer()) { - if (!child->IsHidden()) { - BRegion common(child->fFullVisible); - common.IntersectWith(&invalid); - - if (common.CountRects() > 0) - child->_AllRedraw(invalid); - } - } -} - - -void -Layer::_AddToViewsWithInvalidCoords() const -{ - if (fWindow) { - fWindow->ClientViewsWithInvalidCoords().AddInt32("_token", fViewToken); - fWindow->ClientViewsWithInvalidCoords().AddPoint("where", fFrame.LeftTop()); - fWindow->ClientViewsWithInvalidCoords().AddFloat("width", fFrame.Width()); - fWindow->ClientViewsWithInvalidCoords().AddFloat("height", fFrame.Height()); - } -} - - -void -Layer::_SendViewCoordUpdateMsg() const -{ - if (fWindow && !fWindow->ClientViewsWithInvalidCoords().IsEmpty()) { - fWindow->SendMessageToClient(&fWindow->ClientViewsWithInvalidCoords()); - fWindow->ClientViewsWithInvalidCoords().MakeEmpty(); - } -} diff --git a/src/servers/app/Layer.h b/src/servers/app/Layer.h deleted file mode 100644 index 4368914228..0000000000 --- a/src/servers/app/Layer.h +++ /dev/null @@ -1,267 +0,0 @@ -/* - * Copyright (c) 2001-2005, Haiku, Inc. - * Distributed under the terms of the MIT license. - * - * Authors: - * DarkWyrm - * Adi Oanca - * Stephan Aßmus - */ -#ifndef _LAYER_H_ -#define _LAYER_H_ - - -#include "RGBColor.h" -#include "ServerWindow.h" - -#include -#include -#include -#include -#include -#include -#include - - -enum { - B_LAYER_NONE = 1, - B_LAYER_MOVE = 2, - B_LAYER_SIMPLE_MOVE = 3, - B_LAYER_RESIZE = 4, - B_LAYER_MASK_RESIZE = 5, -}; - -enum { - B_LAYER_ACTION_NONE = 0, - B_LAYER_ACTION_MOVE, - B_LAYER_ACTION_RESIZE -}; - -class ServerApp; -class RootLayer; -class DrawingEngine; -class DrawState; -class ServerBitmap; - -class PointerEvent { - public: - int32 code; // B_MOUSE_UP, B_MOUSE_DOWN, B_MOUSE_MOVED, - // B_MOUSE_WHEEL_CHANGED - bigtime_t when; - BPoint where; - float wheel_delta_x; - float wheel_delta_y; - int32 modifiers; - int32 buttons; // B_PRIMARY_MOUSE_BUTTON, B_SECONDARY_MOUSE_BUTTON - // B_TERTIARY_MOUSE_BUTTON - int32 clicks; -}; - -class Layer { - public: - Layer(BRect frame, const char* name, - int32 token, uint32 resize, - uint32 flags, DrawingEngine* driver); - virtual ~Layer(); - - // name - virtual void SetName(const char* name); - inline const char* Name() const - { return fName.String(); } - - int32 ViewToken() const { return fViewToken; } - - // children handling - void AddChild(Layer* child, ServerWindow* serverWin); - void RemoveChild(Layer* child); - void RemoveSelf(); - bool HasChild(Layer* layer); - Layer* Parent() const - { return fParent; } - - uint32 CountChildren() const; - Layer* LayerAt(BPoint where); - - Layer* FirstChild() const; - Layer* LastChild() const; - Layer* NextLayer() const; - Layer* PreviousLayer() const; - - void SetAsTopLayer(bool option) - { fIsTopLayer = option; } - inline bool IsTopLayer() const - { return fIsTopLayer; } - - // visible state - void Show(bool invalidate = true); - void Hide(bool invalidate = true); - bool IsHidden() const; - bool IsVisuallyHidden() const; - - // graphic state and attributes - void PushState(); - void PopState(); - DrawState* CurrentState() const { return fDrawState; } - - void SetViewColor(const RGBColor& color); - inline const RGBColor& ViewColor() const - { return fViewColor; } - void SetBackgroundBitmap(const ServerBitmap* bitmap); - inline const ServerBitmap* BackgroundBitmap() const - { return fBackgroundBitmap; } - void SetOverlayBitmap(const ServerBitmap* bitmap); - inline const ServerBitmap* OverlayBitmap() const - { return fOverlayBitmap; } - - // coordinate system - BRect Bounds() const; - BRect Frame() const; - BPoint ScrollingOffset() const; - - void SetDrawingOrigin(BPoint origin); - BPoint DrawingOrigin() const; - - void SetScale(float scale); - float Scale() const; - - void ConvertToParent(BPoint* pt) const; - void ConvertToParent(BRect* rect) const; - void ConvertToParent(BRegion* reg) const; - void ConvertFromParent(BPoint* pt) const; - void ConvertFromParent(BRect* rect) const; - void ConvertFromParent(BRegion* reg) const; - - void ConvertToScreen(BPoint* pt) const; - void ConvertToScreen(BRect* rect) const; - void ConvertToScreen(BRegion* reg) const; - void ConvertFromScreen(BPoint* pt) const; - void ConvertFromScreen(BRect* rect) const; - void ConvertFromScreen(BRegion* reg) const; - - void ConvertToScreenForDrawing(BPoint* pt) const; - void ConvertToScreenForDrawing(BRect* rect) const; - void ConvertToScreenForDrawing(BRegion* reg) const; - - void ConvertFromScreenForDrawing(BPoint* pt) const; - - virtual void MoveBy(float x, float y); - virtual void ResizeBy(float x, float y); - virtual void ScrollBy(float x, float y); - void CopyBits(BRect& src, BRect& dst, - int32 xOffset, int32 yOffset); - - // input handling - virtual void MouseDown(BMessage *msg, BPoint where, int32* _viewToken); - virtual void MouseUp(BMessage *msg, BPoint where, int32* _viewToken); - virtual void MouseMoved(BMessage *msg, BPoint where, int32* _viewToken); - - virtual void WorkspaceActivated(int32 index, bool active); - virtual void WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces); - virtual void Activated(bool active); - - // action hooks - virtual void MovedByHook(float dx, float dy); - virtual void ResizedByHook(float dx, float dy, bool automatic); - virtual void ScrolledByHook(float dx, float dy); - - // app_server objects getters - ServerWindow* Window() const - { return fWindow; } - ServerApp* App() const - { return fWindow ? fWindow->App() : NULL; } - RootLayer* GetRootLayer() const - { return fRootLayer; } - void SetRootLayer(RootLayer* rl) - { fRootLayer = rl; } - DrawingEngine* GetDrawingEngine() const - { return fDriver; } - - void SetEventMask(uint32 eventMask, uint32 options); - uint32 EventMask() const - { return fEventMask; } - uint32 EventOptions() const - { return fEventOptions; } - - inline uint32 ResizeMode() const - { return fResizeMode; } - inline uint32 Flags() const - { return fFlags; } - void SetFlags(uint32 flags); - - // clipping stuff and redraw - void SetUserClipping(const BRegion& region); - // region is expected in layer coordinates - - inline const BRegion& VisibleRegion() const { return fVisible; } - inline const BRegion& FullVisible() const { return fFullVisible; } - inline const BRegion& DrawingRegion() const { return fDrawingRegion; } - - virtual void GetOnScreenRegion(BRegion& region); - - void MarkForRebuild(const BRegion &dirty); - void TriggerRebuild(); - void _GetAllRebuildDirty(BRegion *totalReg); - - virtual void Draw(const BRect& updateRect); - virtual void _AllRedraw(const BRegion& invalid); - - protected: - friend class RootLayer; - friend class ServerWindow; - - bool _AddChildToList(Layer* child, Layer* before = NULL); - void _RemoveChildFromList(Layer* child); - - // private clipping stuff - virtual void _ReserveRegions(BRegion ®); - void _RebuildVisibleRegions( const BRegion &invalid, - const BRegion &parentLocalVisible, - const Layer *startFrom); - void _RebuildDrawingRegion(); - void _ClearVisibleRegions(); - void _ResizeLayerFrameBy(float x, float y); - void _RezizeLayerRedrawMore(BRegion ®, float dx, float dy); - void _ResizeLayerFullUpdateOnResize(BRegion ®, float dx, float dy); - - // for updating client-side coordinates - void _AddToViewsWithInvalidCoords() const; - void _SendViewCoordUpdateMsg() const; - - - BString fName; - BRect fFrame; - BPoint fScrollingOffset; - - BRegion fVisible; - BRegion fFullVisible; - BRegion fDirtyForRebuild; - BRegion fDrawingRegion; - - DrawingEngine* fDriver; - RootLayer* fRootLayer; - ServerWindow* fWindow; - - DrawState* fDrawState; - - Layer* fParent; - Layer* fPreviousSibling; - Layer* fNextSibling; - Layer* fFirstChild; - Layer* fLastChild; - - int32 fViewToken; - uint32 fFlags; - uint32 fResizeMode; - uint32 fEventMask; - uint32 fEventOptions; - - bool fHidden; - bool fIsTopLayer; - RGBColor fViewColor; - - const ServerBitmap* fBackgroundBitmap; - const ServerBitmap* fOverlayBitmap; - -}; - -#endif // _LAYER_H_ diff --git a/src/servers/app/OffscreenWindowLayer.cpp b/src/servers/app/OffscreenWindowLayer.cpp index 7b9f972a3c..70afb81fdb 100644 --- a/src/servers/app/OffscreenWindowLayer.cpp +++ b/src/servers/app/OffscreenWindowLayer.cpp @@ -19,7 +19,7 @@ OffscreenWindowLayer::OffscreenWindowLayer(ServerBitmap* bitmap, - const char* name, ServerWindow* window) + const char* name, ::ServerWindow* window) : WindowLayer(bitmap->Bounds(), name, B_NO_BORDER_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL, 0, 0, window, new DrawingEngine()), @@ -29,6 +29,12 @@ OffscreenWindowLayer::OffscreenWindowLayer(ServerBitmap* bitmap, GetDrawingEngine()->SetHWInterface(fHWInterface); GetDrawingEngine()->Initialize(); GetDrawingEngine()->Update(); + + fVisibleRegion.Set(fFrame); + fVisibleContentRegion.Set(fFrame); + fVisibleContentRegionValid = true; + fContentRegion.Set(fFrame); + fContentRegionValid = true; } diff --git a/src/servers/app/OffscreenWindowLayer.h b/src/servers/app/OffscreenWindowLayer.h index 37e3dc5a21..8cbe3e7936 100644 --- a/src/servers/app/OffscreenWindowLayer.h +++ b/src/servers/app/OffscreenWindowLayer.h @@ -19,7 +19,7 @@ class OffscreenWindowLayer : public WindowLayer { public: OffscreenWindowLayer(ServerBitmap* bitmap, const char* name, - ServerWindow* window); + ::ServerWindow* window); virtual ~OffscreenWindowLayer(); virtual void Draw(const BRect &r); diff --git a/src/servers/app/RootLayer.cpp b/src/servers/app/RootLayer.cpp deleted file mode 100644 index 2d4c7837a8..0000000000 --- a/src/servers/app/RootLayer.cpp +++ /dev/null @@ -1,825 +0,0 @@ -/* - * Copyright 2001-2005, Haiku, Inc. - * Distributed under the terms of the MIT License. - * - * Authors: - * Gabe Yoder - * DarkWyrm - * Adrian Oanca - * Stephan Aßmus - * Axel Dörfler, axeld@pinc-software.de - */ - -/** Class used for the top layer of each workspace's Layer tree */ - - -#include "Decorator.h" -#include "DrawingEngine.h" -#include "HWInterface.h" -#include "Layer.h" -#include "RootLayer.h" -#include "ServerApp.h" -#include "ServerConfig.h" -#include "ServerProtocol.h" -#include "ServerScreen.h" -#include "ServerWindow.h" -#include "WindowLayer.h" -#include "WorkspacePrivate.h" -#include "WorkspacesLayer.h" - -#include -#include -#include -#include -#include - -#include - -#if DISPLAY_HAIKU_LOGO -#include "ServerBitmap.h" -#include "HaikuLogo.h" -static const float kGoldenProportion = (sqrtf(5.0) - 1.0) / 2.0; -#endif - -//#define TRACE_ROOT_LAYER -#ifdef TRACE_ROOT_LAYER -# define STRACE(a) printf a -#else -# define STRACE(a) ; -#endif - - -RootLayer::RootLayer(const char *name, Desktop *desktop, DrawingEngine *driver) - : Layer(BRect(0, 0, 0, 0), name, 0, B_FOLLOW_ALL, B_WILL_DRAW, driver), - fDesktop(desktop), - fDragMessage(NULL), - fMouseEventWindow(NULL), - fAllRegionsLock("root layer region lock"), - - fDirtyForRedraw(), - - fWorkspace(0), - fWorkspacesLayer(NULL), - - fFocus(NULL), - fFront(NULL), - fBack(NULL) -{ - //NOTE: be careful about this one. - fRootLayer = this; - -// Some stuff that will go away in the future but fills some gaps right now -#if ON_SCREEN_DEBUGGING_INFO - fDebugInfo.SetTo(""); -#endif - - fDrawState->SetHighColor(RGBColor(255, 255, 255)); - -#if DISPLAY_HAIKU_LOGO - fLogoBitmap = new UtilityBitmap(BRect(0.0, 0.0, kLogoWidth - 1.0, - kLogoHeight - 1.0), - kLogoFormat, 0); - if (fLogoBitmap->IsValid()) { - int32 size = min_c(sizeof(kLogoBits), fLogoBitmap->BitsLength()); - memcpy(fLogoBitmap->Bits(), kLogoBits, size); - } else { - delete fLogoBitmap; - fLogoBitmap = NULL; - } -#endif // DISPLAY_HAIKU_LOGO - - fHidden = false; - -#if ON_SCREEN_DEBUGGING_INFO - DebugInfoManager::Default()->SetRootLayer(this); -#endif - - fFrame = desktop->VirtualScreen().Frame(); - - // RootLayer starts with valid visible regions - fFullVisible.Set(Bounds()); - fVisible.Set(Bounds()); - - // first make sure we are actualy visible - MarkForRebuild(Bounds()); - MarkForRedraw(Bounds()); - - _UpdateWorkspace(fDesktop->WorkspaceAt(fDesktop->CurrentWorkspace())); - - TriggerRebuild(); - TriggerRedraw(); -} - - -RootLayer::~RootLayer() -{ - delete fDragMessage; - - fFirstChild = NULL; - // this prevents the Layer destructor from freeing our children again - // (the Desktop destructor already took care of that) - - // RootLayer object just uses Screen objects, it is not allowed to delete them. - -#if DISPLAY_HAIKU_LOGO - delete fLogoBitmap; -#endif -} - - -void -RootLayer::MoveBy(float x, float y) -{ -} - - -void -RootLayer::ResizeBy(float x, float y) -{ - if (x == 0 && y == 0) - return; - - // TODO: we should be able to update less here - - //BRect previous = fFrame; - - fFrame.right += x; - fFrame.bottom += y; - - fFullVisible.Set(Bounds()); - fVisible.Set(Bounds()); - - BRegion region(fFrame); - MarkForRebuild(region); - TriggerRebuild(); - - //region.Exclude(previous); - - MarkForRedraw(region); - TriggerRedraw(); -} - - -bool -RootLayer::_SetFocus(WindowLayer* focus, BRegion& update) -{ - // TODO: test for FFM and B_LOCK_WINDOW_FOCUS - - if (focus == fFocus && (focus->WindowFlags() & B_AVOID_FOCUS) == 0) - return true; - - // make sure no window is chosen that doesn't want focus - while (focus != NULL && (focus->WindowFlags() & B_AVOID_FOCUS) != 0) { - focus = (WindowLayer*)focus->PreviousLayer(); - } - - if (fFocus != NULL) { - update.Include(&fFocus->VisibleRegion()); - fFocus->SetFocus(false); - } - - fFocus = focus; - - if (focus != NULL) { - update.Include(&focus->VisibleRegion()); - focus->SetFocus(true); - } - - return true; -} - - -bool -RootLayer::SetFocus(WindowLayer* focus) -{ - BAutolock _(fAllRegionsLock); - - BRegion update; - bool success = _SetFocus(focus, update); - if (!success) - return false; - - MarkForRedraw(update); - TriggerRedraw(); - return true; -} - - -/*! - \brief Tries to move the specified window to the front of the screen. - - If there are any modal windows on this screen, it might not actually - become the frontmost window, though, as modal windows stay in front - of their subset. -*/ -void -RootLayer::_SetFront(WindowLayer* window, BRegion& update) -{ - if (window == NULL) { - fBack = NULL; - fFront = NULL; - return; - } - - if (!window->SupportsFront() && fFront != NULL) - return; - - BRegion previous = window->FullVisible(); - WindowLayer* frontmost = window->Frontmost(); - - _RemoveChildFromList(window); - - if (frontmost != NULL && frontmost->IsModal()) { - // all modal windows follow their subsets to the front - // (ie. they are staying in front of them, but they are - // not supposed to change their order because of that) - - WindowLayer* nextModal; - for (WindowLayer* modal = frontmost; modal != NULL ; modal = nextModal) { - nextModal = (WindowLayer*)modal->NextLayer(); - - if (nextModal == frontmost) { - // since we're adding the modal windows to the end of the list - // we're traversing, we must stop when we've reached the initial - // starting point again - nextModal = NULL; - } else if (nextModal != NULL - && (!nextModal->IsModal() || !nextModal->HasInSubset(window))) - nextModal = NULL; - - previous.Include(&modal->FullVisible()); - WindowLayer* modalFrontmost = modal->Frontmost(); - - _RemoveChildFromList(modal); - _AddChildToList(modal, modalFrontmost); - - BRegion modalRegion; - modal->GetOnScreenRegion(modalRegion); - // TODO: this is not what we want, we'd want the new visible region - update.Include(&modalRegion); - } - } - - _AddChildToList(window, frontmost); - - BRegion windowRegion; - window->GetOnScreenRegion(windowRegion); - // TODO: this is not what we want, we'd want the new visible region - - update.Include(&windowRegion); - update.Exclude(&previous); - - _UpdateFront(); - - if (window == fBack || fBack == NULL) - _UpdateBack(); -} - - -/*! search the visible windows for a valid back window - (only normal windows can be back windows) -*/ -void -RootLayer::_UpdateBack() -{ - fBack = NULL; - - for (WindowLayer* window = (WindowLayer*)FirstChild(); - window != NULL; window = (WindowLayer*)window->NextLayer()) { - if (window->IsHidden() || !window->SupportsFront()) - continue; - - fBack = window; - break; - } -} - - -/*! search the visible windows for a valid front window - (only normal windows can be front windows) -*/ -void -RootLayer::_UpdateFront() -{ - // TODO: for now, just choose the top window - fFront = NULL; - - for (WindowLayer* window = (WindowLayer*)LastChild(); - window != NULL; window = (WindowLayer*)window->PreviousLayer()) { - if (window->IsHidden() || !window->SupportsFront()) - continue; - - fFront = window; - break; - } -} - - -void -RootLayer::_UpdateFronts() -{ - _UpdateBack(); - _UpdateFront(); -} - - -void -RootLayer::ActivateWindow(WindowLayer* window) -{ - BAutolock _(fAllRegionsLock); - - BRegion changed; - _SetFront(window, changed); - - // TODO: if this window has any floating windows, add them here - - MarkForRebuild(changed); - TriggerRebuild(); - - _SetFocus(Front(), changed); - - _WindowsChanged(changed); - MarkForRedraw(changed); - TriggerRedraw(); -} - - -void -RootLayer::SendBehindWindow(WindowLayer* windowLayer, WindowLayer* behindOf) -{ - BAutolock _(fAllRegionsLock); - - if (windowLayer == Back()) - return; - - bool wasFocus = windowLayer == Focus(); - - BRegion changed = windowLayer->FullVisible(); - - _RemoveChildFromList(windowLayer); - if (behindOf == NULL) - behindOf = Back(); - - _AddChildToList(windowLayer, behindOf); - - // TODO: if this window has any floating windows, remove them here - - MarkForRebuild(changed); - TriggerRebuild(); - - _UpdateFronts(); - _SetFocus(Front(), changed); - - changed.Exclude(&windowLayer->FullVisible()); - if (wasFocus != (Focus() == windowLayer)) - changed.Include(&windowLayer->VisibleRegion()); - - _WindowsChanged(changed); - MarkForRedraw(changed); - TriggerRedraw(); -} - - -void -RootLayer::AddWindow(WindowLayer* window) -{ - STRACE(("AddWindowLayer(%p \"%s\")\n", window, window->Name())); - - if (window->SupportsFront()) - _AddChildToList(window, window->Frontmost((WindowLayer*)FirstChild())); - else - _AddChildToList(window, Back()); - - window->SetRootLayer(this); - - if (!window->IsHidden()) - ActivateWindow(window); -} - - -void -RootLayer::RemoveWindow(WindowLayer* window) -{ - if (!window->IsHidden()) - HideWindow(window); - - _RemoveChildFromList(window); - - LayerRemoved(window); - window->SetRootLayer(NULL); -} - - -void -RootLayer::_UpdateWorkspace(Workspace::Private& workspace) -{ - fColor = workspace.Color(); - -#if ON_SCREEN_DEBUGGING_INFO - fDrawState->SetLowColor(fColor); -#endif -} - - -void -RootLayer::SetWorkspace(int32 index, Workspace::Private& previousWorkspace, - Workspace::Private& workspace) -{ - BAutolock _(fAllRegionsLock); - - int32 previousIndex = fWorkspace; - - // build region of windows that are no longer visible in the new workspace - // and move windows to the previous workspace's window list - - BRegion changed; - while (WindowLayer* window = (WindowLayer*)FirstChild()) { - // move the window into the workspace's window list - _RemoveChildFromList(window); - - BPoint position = window->Frame().LeftTop(); - previousWorkspace.AddWindow(window, &position); - - if (window->IsHidden()) - continue; - - if (!window->OnWorkspace(index)) { - // this window will no longer be visible - changed.Include(&window->FullVisible()); - } - } - - fWorkspace = index; - _UpdateWorkspace(workspace); - - // add new windows, and include them in the changed region - but only - // those that were not visible before (or whose position changed) - - while (workspace.CountWindows() != 0) { - window_layer_info* info = workspace.WindowAt(0); - WindowLayer* window = info->window; - BPoint position = info->position; - - // move window into the RootLayer's list - workspace.RemoveWindowAt(0); - _AddChildToList(window); - - if (window->IsHidden()) - continue; - - if (position == kInvalidWindowPosition) { - // if you enter a workspace for the first time, the position - // of the window in the previous workspace is adopted - position = window->Frame().LeftTop(); - // TODO: make sure the window is still on-screen if it - // was before! - } - - if (!window->OnWorkspace(previousIndex)) { - // this window was not visible before - - // TODO: what we really want here is the visible region of the window - BRegion region; - window->GetOnScreenRegion(region); - - changed.Include(®ion); - } else if (window->Frame().LeftTop() != position) { - // the window was visible before, but its on-screen location changed - BPoint offset = position - window->Frame().LeftTop(); - window->MoveBy(offset.x, offset.y); - - // TODO: we're playing dumb here - what we need is a MoveBy() that - // gives us a dirty region back, and since the new clipping code - // will give us just that, we don't take any special measurement - // here - GetOnScreenRegion(changed); - } else { - // the window is still visible and on the same location - continue; - } - } - - _UpdateFronts(); - _SetFocus(Front(), changed); - - MarkForRebuild(changed); - TriggerRebuild(); - - _WindowsChanged(changed); - MarkForRedraw(changed); - TriggerRedraw(); -} - - -void -RootLayer::HideWindow(WindowLayer* window) -{ - BAutolock _(fAllRegionsLock); - - BRegion changed = window->FullVisible(); - window->Hide(); - _UpdateFronts(); - - if (dynamic_cast(window->TopLayer()) != NULL) - fWorkspacesLayer = NULL; - - // TODO: if this window has any floating windows, remove them here - - MarkForRebuild(changed); - TriggerRebuild(); - - if (window == Focus()) - _SetFocus(Front(), changed); - _WindowsChanged(changed); - - MarkForRedraw(changed); - TriggerRedraw(); -} - - -void -RootLayer::ShowWindow(WindowLayer* window, bool toFront) -{ - STRACE(("ShowWindowLayer(%p)\n", window)); - - if (!window->IsHidden()) - return; - - BAutolock _(fAllRegionsLock); - - window->Show(); - BRegion changed = window->FullVisible(); - - if (toFront) - _SetFront(window, changed); - else - _UpdateFront(); - - // TODO: if this window has any floating windows, remove them here - - // TODO: support FFM - if (Front() == window || Focus() == NULL) - _SetFocus(window, changed); - _WindowsChanged(changed); - MarkForRedraw(changed); - TriggerRedraw(); - - if (dynamic_cast(window->TopLayer()) != NULL) - fWorkspacesLayer = window->TopLayer(); -} - - -void -RootLayer::MoveWindowBy(WindowLayer* window, float x, float y) -{ - BAutolock _(fAllRegionsLock); - - // TODO: the MoveBy() should just return a dirty region - window->MoveBy(x, y); - - BRegion changed; - _WindowsChanged(changed); - - if (changed.CountRects() > 0) { - MarkForRedraw(changed); - TriggerRedraw(); - } -} - - -void -RootLayer::ResizeWindowBy(WindowLayer* window, float x, float y) -{ - BAutolock _(fAllRegionsLock); - - // TODO: the MoveBy() should just return a dirty region - window->ResizeBy(x, y); - - BRegion changed; - _WindowsChanged(changed); - - if (changed.CountRects() > 0) { - MarkForRedraw(changed); - TriggerRedraw(); - } -} - - -void -RootLayer::SetWindowLook(WindowLayer *window, window_look newLook) -{ - if (window->Look() == newLook) - return; - - BAutolock _(fAllRegionsLock); - - BRegion changed; - window->SetLook(newLook, window->Parent() ? &changed : NULL); - - if (window->Parent() != NULL) { - MarkForRebuild(changed); - TriggerRebuild(); - } - - _WindowsChanged(changed); - - if (changed.CountRects() > 0) { - MarkForRedraw(changed); - TriggerRedraw(); - } -} - - -void -RootLayer::SetWindowFeel(WindowLayer *window, window_feel newFeel) -{ - if (window->Feel() == newFeel) - return; - - BAutolock _(fAllRegionsLock); - - window->SetFeel(newFeel); - - // TODO: implement window feels! -} - - -void -RootLayer::SetWindowFlags(WindowLayer *window, uint32 newFlags) -{ - if (window->WindowFlags() == newFlags) - return; - - BAutolock _(fAllRegionsLock); - - BRegion changed; - window->SetWindowFlags(newFlags, window->Parent() ? &changed : NULL); - - if (window->Parent() != NULL) { - MarkForRebuild(changed); - TriggerRebuild(); - } - - _WindowsChanged(changed); - - if (changed.CountRects() > 0) { - MarkForRedraw(changed); - TriggerRedraw(); - } -} - - -void -RootLayer::_WindowsChanged(BRegion& region) -{ - if (fWorkspacesLayer == NULL) - return; - - region.Include(&fWorkspacesLayer->VisibleRegion()); -} - - -void -RootLayer::UpdateWorkspaces() -{ - BAutolock _(fAllRegionsLock); - - if (fWorkspacesLayer == NULL) - return; - - BRegion changed; - _WindowsChanged(changed); - - MarkForRedraw(changed); - TriggerRedraw(); -} - - -WindowLayer* -RootLayer::WindowAt(BPoint where) -{ - if (VisibleRegion().Contains(where)) - return NULL; - - for (Layer* child = LastChild(); child; child = child->PreviousLayer()) { - if (child->FullVisible().Contains(where)) - return dynamic_cast(child); - } - - return NULL; -} - - -void -RootLayer::SetMouseEventWindow(WindowLayer* window) -{ - fMouseEventWindow = window; -} - - -void -RootLayer::LayerRemoved(Layer* layer) -{ - if (fMouseEventWindow == layer) - fMouseEventWindow = NULL; - if (fWorkspacesLayer == layer) - fWorkspacesLayer = NULL; -} - - -void -RootLayer::SetDragMessage(BMessage* msg) -{ - if (fDragMessage) { - delete fDragMessage; - fDragMessage = NULL; - } - - if (msg) - fDragMessage = new BMessage(*msg); -} - - -BMessage * -RootLayer::DragMessage() const -{ - return fDragMessage; -} - - -void -RootLayer::Draw(const BRect& rect) -{ - fDriver->FillRect(rect, fColor); - -#if ON_SCREEN_DEBUGGING_INFO - BPoint location(5, 40); - float textHeight = 15.0; // be lazy - const char* p = fDebugInfo.String(); - const char* start = p; - while (*p) { - p++; - if (*p == 0 || *p == '\n') { - fDriver->DrawString(start, p - start, location, - fDrawState); - // NOTE: Eventually, this will be below the screen! - location.y += textHeight; - start = p + 1; - } - } -#endif // ON_SCREEN_DEBUGGING_INFO - -#if DISPLAY_HAIKU_LOGO - if (fLogoBitmap) { - BPoint logoPos; - logoPos.x = floorf(min_c(fFrame.left + fFrame.Width() * kGoldenProportion, - fFrame.right - (kLogoWidth + kLogoHeight / 2.0))); - logoPos.y = floorf(fFrame.bottom - kLogoHeight * 1.5); - BRect bitmapBounds = fLogoBitmap->Bounds(); - fDriver->DrawBitmap(fLogoBitmap, bitmapBounds, - bitmapBounds.OffsetToCopy(logoPos), fDrawState); - } -#endif // DISPLAY_HAIKU_LOGO -} - -#if ON_SCREEN_DEBUGGING_INFO -void -RootLayer::AddDebugInfo(const char* string) -{ - if (Lock()) { - fDebugInfo << string; - MarkForRedraw(VisibleRegion()); - TriggerRedraw(); - Unlock(); - } -} -#endif // ON_SCREEN_DEBUGGING_INFO - - -void -RootLayer::MarkForRedraw(const BRegion &dirty) -{ - BAutolock locker(fAllRegionsLock); - - fDirtyForRedraw.Include(&dirty); -} - - -void -RootLayer::TriggerRedraw() -{ - BAutolock locker(fAllRegionsLock); - -#if 0 - // for debugging - GetDrawingEngine()->ConstrainClippingRegion(&fDirtyForRedraw); - RGBColor color(rand()%255, rand()%255, rand()%255); - GetDrawingEngine()->FillRect(Bounds(), color); - snooze(200000); - GetDrawingEngine()->ConstrainClippingRegion(NULL); -#endif - _AllRedraw(fDirtyForRedraw); - - fDirtyForRedraw.MakeEmpty(); -} - diff --git a/src/servers/app/RootLayer.h b/src/servers/app/RootLayer.h deleted file mode 100644 index 8c5bfb3d36..0000000000 --- a/src/servers/app/RootLayer.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2001-2005, Haiku, Inc. - * Distributed under the terms of the MIT License. - * - * Authors: - * Gabe Yoder - * DarkWyrm - * Adrian Oanca - * Stephan Aßmus - * Axel Dörfler, axeld@pinc-software.de - */ -#ifndef ROOT_LAYER_H -#define ROOT_LAYER_H - - -#include -#include -#include - -#include "DebugInfoManager.h" -#include "Desktop.h" -#include "Layer.h" -#include "Workspace.h" - -class DrawingEngine; -class HWInterface; -class RGBColor; -class Screen; -class WindowLayer; - -namespace BPrivate { - class PortLink; -}; - -#ifndef DISPLAY_HAIKU_LOGO -# define DISPLAY_HAIKU_LOGO 1 -#endif - -#if DISPLAY_HAIKU_LOGO -class UtilityBitmap; -#endif - - -class RootLayer : public Layer { - public: - RootLayer(const char *name, Desktop *desktop, - DrawingEngine *driver); - virtual ~RootLayer(); - - Desktop* GetDesktop() const { return fDesktop; } - - virtual void MoveBy(float x, float y); - virtual void ResizeBy(float x, float y); - virtual void ScrollBy(float x, float y) - { /* not allowed */ } - - void HideWindow(WindowLayer* window); - void ShowWindow(WindowLayer* window, bool toFront = true); - - void MoveWindowBy(WindowLayer* window, float x, float y); - void ResizeWindowBy(WindowLayer* window, float x, float y); - - bool SetFocus(WindowLayer* focus); - WindowLayer* Focus() const { return fFocus; } - WindowLayer* Front() const { return fFront; } - WindowLayer* Back() const { return fBack; } - - void SetWorkspace(int32 index, - Workspace::Private& previousWorkspace, - Workspace::Private& workspace); - - void SetDragMessage(BMessage *msg); - BMessage* DragMessage() const; - - WindowLayer* WindowAt(BPoint where); - - WindowLayer* MouseEventWindow() const { return fMouseEventWindow; } - void SetMouseEventWindow(WindowLayer* layer); - - void LayerRemoved(Layer* layer); - - // Other methods - bool Lock() { return fAllRegionsLock.Lock(); } - void Unlock() { fAllRegionsLock.Unlock(); } - bool IsLocked() { return fAllRegionsLock.IsLocked(); } - - void ActivateWindow(WindowLayer* window); - void SendBehindWindow(WindowLayer* window, WindowLayer* front); - - void SetWindowLook(WindowLayer *window, window_look newLook); - void SetWindowFeel(WindowLayer *window, window_feel newFeel); - void SetWindowFlags(WindowLayer *window, uint32 newFlags); - - void UpdateWorkspaces(); - - void MarkForRedraw(const BRegion &dirty); - void TriggerRedraw(); - - void Draw(const BRect &r); - - thread_id LockingThread() { return fAllRegionsLock.LockingThread(); } - - void AddWindow(WindowLayer* window); - void RemoveWindow(WindowLayer* window); - - private: - bool _SetFocus(WindowLayer* focus, BRegion& update); - void _SetFront(WindowLayer* front, BRegion& update); - void _UpdateBack(); - void _UpdateFront(); - void _UpdateFronts(); - - void _WindowsChanged(BRegion& region); - void _UpdateWorkspace(Workspace::Private& workspace); - - Desktop* fDesktop; - BMessage* fDragMessage; - WindowLayer* fMouseEventWindow; - - BLocker fAllRegionsLock; - - BRegion fDirtyForRedraw; - - int32 fWorkspace; - RGBColor fColor; - Layer* fWorkspacesLayer; - - WindowLayer* fFocus; - WindowLayer* fFront; - WindowLayer* fBack; - -#if ON_SCREEN_DEBUGGING_INFO - friend class DebugInfoManager; - void AddDebugInfo(const char* string); - BString fDebugInfo; -#endif -#if DISPLAY_HAIKU_LOGO - UtilityBitmap* fLogoBitmap; -#endif -}; - -#endif // ROOT_LAYER_H diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index 8085f68f59..aa82343d05 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -38,6 +38,7 @@ #include "CursorManager.h" #include "CursorSet.h" #include "Desktop.h" +#include "DebugInfoManager.h" #include "DecorManager.h" #include "DrawingEngine.h" #include "EventStream.h" @@ -46,7 +47,6 @@ #include "InputManager.h" #include "OffscreenServerWindow.h" #include "RAMLinkMsgReader.h" -#include "RootLayer.h" #include "ServerApp.h" #include "ServerBitmap.h" #include "ServerConfig.h" @@ -93,7 +93,7 @@ ServerApp::ServerApp(Desktop* desktop, port_id clientReplyPort, fAppCursor(NULL), fCursorHidden(false), fIsActive(false), - fSharedMem("shared memory") + fSharedMem("shared memory", 32768) { if (fSignature == "") fSignature = "application/no-signature"; @@ -231,7 +231,7 @@ ServerApp::Run() return false; // Let's tell the client how to talk with us - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Attach(fMessagePort); fLink.Flush(); @@ -531,7 +531,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) void *sharedmem = fSharedMem.GetBuffer(memsize); if (memsize < 1 || sharedmem == NULL) { - fLink.StartMessage(SERVER_FALSE); + fLink.StartMessage(B_ERROR); fLink.Flush(); break; } @@ -540,7 +540,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) area_info info; if (owningArea == B_ERROR || get_area_info(owningArea, &info) < B_OK) { - fLink.StartMessage(SERVER_FALSE); + fLink.StartMessage(B_ERROR); fLink.Flush(); break; } @@ -548,7 +548,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) int32 areaoffset = (addr_t)sharedmem - (addr_t)info.address; STRACE(("Successfully allocated shared memory of size %ld\n",memsize)); - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Attach(owningArea); fLink.Attach(areaoffset); fLink.Flush(); @@ -582,13 +582,14 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) { STRACE(("ServerApp %s: Received decorator update notification\n", Signature())); - for (int32 i = 0; i < fWindowList.CountItems(); i++) { + // TODO: implement or remove AS_UPDATE_DECORATOR +/* for (int32 i = 0; i < fWindowList.CountItems(); i++) { ServerWindow *window = fWindowList.ItemAt(i); window->Lock(); const_cast(window->GetWindowLayer())->UpdateDecorator(); window->Unlock(); } - break; +*/ break; } case AS_SET_DECORATOR: { @@ -606,14 +607,14 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) } case AS_COUNT_DECORATORS: { - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Attach(gDecorManager.CountDecorators()); fLink.Flush(); break; } case AS_GET_DECORATOR: { - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Attach(gDecorManager.GetDecorator()); fLink.Flush(); break; @@ -624,14 +625,12 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) link.Read(&index); BString str(gDecorManager.GetDecoratorName(index)); - if (str.CountChars() > 0) - { - fLink.StartMessage(SERVER_TRUE); + if (str.CountChars() > 0) { + fLink.StartMessage(B_OK); fLink.AttachString(str.String()); - } - else - fLink.StartMessage(SERVER_FALSE); - + } else + fLink.StartMessage(B_ERROR); + fLink.Flush(); break; } @@ -659,16 +658,14 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) { STRACE(("ServerApp %s: Received BBitmap creation request\n", Signature())); // Allocate a bitmap for an application - + // Attached Data: // 1) BRect bounds // 2) color_space space // 3) int32 bitmap_flags // 4) int32 bytes_per_row // 5) int32 screen_id::id - // 6) port_id reply port - // Reply Code: SERVER_TRUE // Reply Data: // 1) int32 server token // 2) area_id id of the area in which the bitmap data resides @@ -694,13 +691,12 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) Signature(), frame.Width(), frame.Height())); if (bitmap && fBitmapList.AddItem((void*)bitmap)) { - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Attach(bitmap->Token()); fLink.Attach(bitmap->Area()); fLink.Attach(bitmap->AreaOffset()); } else { - // alternatively, if something went wrong, we reply with SERVER_FALSE - fLink.StartMessage(SERVER_FALSE); + fLink.StartMessage(B_NO_MEMORY); } fLink.Flush(); @@ -713,10 +709,6 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) // Attached Data: // 1) int32 token - // 2) int32 reply port - - // Reply Code: SERVER_TRUE if successful, - // SERVER_FALSE if the buffer was already deleted or was not found int32 id; link.Read(&id); @@ -725,11 +717,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) STRACE(("ServerApp %s: Deleting Bitmap %ld\n", Signature(), id)); gBitmapManager->DeleteBitmap(bitmap); - fLink.StartMessage(SERVER_TRUE); - } else - fLink.StartMessage(SERVER_FALSE); - - fLink.Flush(); + } break; } #if 0 @@ -787,7 +775,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) if (fDesktop->CurrentWorkspace() >= newCount) fDesktop->SetWorkspace(newCount - 1); else - fDesktop->RootLayer()->UpdateWorkspaces(); + fDesktop->UpdateWorkspaces(); } break; } @@ -838,7 +826,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) case AS_QUERY_CURSOR_HIDDEN: { STRACE(("ServerApp %s: Received IsCursorHidden request\n", Signature())); - fLink.StartMessage(fCursorHidden ? SERVER_TRUE : SERVER_FALSE); + fLink.StartMessage(fCursorHidden ? B_OK : B_ERROR); fLink.Flush(); break; } @@ -886,7 +874,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) if (sync) { // the application is expecting a reply, but plans to do literally nothing // with the data, so we'll just reuse the cursor token variable - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Flush(); } break; @@ -914,7 +902,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) fDesktop->GetCursorManager().AddCursor(fAppCursor); // Synchronous message - BApplication is waiting on the cursor's ID - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Attach(fAppCursor->ID()); fLink.Flush(); break; @@ -940,7 +928,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) DesktopSettings settings(fDesktop); settings.GetScrollBarInfo(info); - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Attach(info); fLink.Flush(); break; @@ -956,7 +944,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) settings.SetScrollBarInfo(info); } - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Flush(); break; } @@ -1006,7 +994,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) STRACE(("ServerApp %s: Get Focus Follows Mouse mode\n", Signature())); DesktopSettings settings(fDesktop); - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Attach(settings.MouseMode()); fLink.Flush(); break; @@ -1018,7 +1006,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) // using a ColorSet object gGUIColorSet.Lock(); - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Attach(gGUIColorSet); fLink.Flush(); @@ -1051,7 +1039,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) color = gGUIColorSet.AttributeToColor(whichColor); gGUIColorSet.Unlock(); - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Attach(color.GetColor32()); fLink.Flush(); break; @@ -1838,14 +1826,14 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) // TODO implement for real if (font.GetBoundingBoxesAsString(charArray, numChars, rectArray, string_escapement, mode, delta)) { - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Attach(rectArray, sizeof(rectArray)); success = true; } } if (!success) - fLink.StartMessage(SERVER_FALSE); + fLink.StartMessage(B_ERROR); fLink.Flush(); break; @@ -1912,7 +1900,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) // TODO implement for real if (font.GetBoundingBoxesForStrings(stringArray, lengthArray, numStrings, rectArray, mode, deltaArray)) { - fLink.StartMessage(SERVER_TRUE); + fLink.StartMessage(B_OK); fLink.Attach(rectArray, sizeof(rectArray)); success = true; } @@ -1922,7 +1910,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) free(stringArray[i]); if (!success) - fLink.StartMessage(SERVER_FALSE); + fLink.StartMessage(B_ERROR); fLink.Flush(); break; @@ -2036,18 +2024,15 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) bool makedefault = false; link.Read(&makedefault); - RootLayer* rootLayer = fDesktop->RootLayer(); - rootLayer->Lock(); - status_t status = fDesktop->ScreenAt(0)->SetMode(mode); - if (status == B_OK) { - BRect bounds = rootLayer->Bounds(); - rootLayer->ResizeBy(mode.virtual_width - 1 - bounds.Width(), - mode.virtual_height - 1 - bounds.Height()); - - gInputManager->UpdateScreenBounds(rootLayer->Bounds()); - fDesktop->ScreenChanged(fDesktop->ScreenAt(0)); + status_t status = B_ERROR; + if (fDesktop->WriteLockWindows()) { + status = fDesktop->ScreenAt(0)->SetMode(mode); + if (status == B_OK) { + gInputManager->UpdateScreenBounds(fDesktop->ScreenAt(0)->Frame()); + fDesktop->ScreenChanged(fDesktop->ScreenAt(0)); + } + fDesktop->WriteUnlockWindows(); } - rootLayer->Unlock(); fLink.StartMessage(status); fLink.Flush(); @@ -2313,7 +2298,7 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) if (link.NeedsReply()) { // the client is now blocking and waiting for a reply! - fLink.StartMessage(SERVER_FALSE); + fLink.StartMessage(B_ERROR); fLink.Flush(); } else puts("message doesn't need a reply!"); @@ -2418,7 +2403,7 @@ ServerApp::RemoveWindow(ServerWindow* window) bool -ServerApp::OnWorkspace(int32 index) +ServerApp::OnWorkspace(int32 index) const { BAutolock locker(fWindowListLock); diff --git a/src/servers/app/ServerApp.h b/src/servers/app/ServerApp.h index dde97ebe00..0a34e1aa84 100644 --- a/src/servers/app/ServerApp.h +++ b/src/servers/app/ServerApp.h @@ -64,7 +64,7 @@ class ServerApp : public MessageLooper { const char *Signature() const { return fSignature.String(); } void RemoveWindow(ServerWindow* window); - bool OnWorkspace(int32 index); + bool OnWorkspace(int32 index) const; int32 CountBitmaps() const; ServerBitmap *FindBitmap(int32 token) const; @@ -98,7 +98,7 @@ class ServerApp : public MessageLooper { BString fSignature; team_id fClientTeam; - BLocker fWindowListLock; + mutable BLocker fWindowListLock; BObjectList fWindowList; BPrivate::BTokenSpace fViewTokens; diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 99922690ad..53baf8b953 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -43,10 +43,8 @@ #include "Desktop.h" #include "DrawingEngine.h" #include "HWInterface.h" -#include "Layer.h" #include "RAMLinkMsgReader.h" #include "RenderingBuffer.h" -#include "RootLayer.h" #include "ServerApp.h" #include "ServerBitmap.h" #include "ServerPicture.h" @@ -140,13 +138,21 @@ ServerWindow::ServerWindow(const char *title, ServerApp *app, fDesktop(app->GetDesktop()), fServerApp(app), fWindowLayer(NULL), + fClientTeam(app->ClientTeam()), + fMessagePort(-1), fClientReplyPort(clientPort), fClientLooperPort(looperPort), + fClientViewsWithInvalidCoords(B_VIEW_RESIZED), + fClientToken(clientToken), + fCurrentLayer(NULL), + fCurrentDrawingRegion(), + fCurrentDrawingRegionValid(false), + fDirectWindowData(NULL) { STRACE(("ServerWindow(%s)::ServerWindow()\n", title)); @@ -236,14 +242,14 @@ ServerWindow::Run() fLink.StartMessage(B_OK); fLink.Attach(fMessagePort); - float minWidth, maxWidth, minHeight, maxHeight; + int32 minWidth, maxWidth, minHeight, maxHeight; fWindowLayer->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight); fLink.Attach(fWindowLayer->Frame()); - fLink.Attach(minWidth); - fLink.Attach(maxWidth); - fLink.Attach(minHeight); - fLink.Attach(maxHeight); + fLink.Attach((float)minWidth); + fLink.Attach((float)maxWidth); + fLink.Attach((float)minHeight); + fLink.Attach((float)maxHeight); fLink.Flush(); return true; @@ -282,7 +288,7 @@ ServerWindow::ReplaceDecorator() debugger("you must lock a ServerWindow object before calling ::ReplaceDecorator()\n"); STRACE(("ServerWindow %s: Replace Decorator\n", fTitle)); - fWindowLayer->UpdateDecorator(); + //fWindowLayer->UpdateDecorator(); } @@ -296,7 +302,11 @@ ServerWindow::Show() if (fQuitting || !fWindowLayer->IsHidden() || fWindowLayer->IsOffscreenWindow()) return; +// TODO: race condition? maybe we need to dispatch a message to the desktop to show/hide us +// instead of doing it from this thread. +fDesktop->ReadUnlockWindows(); fDesktop->ShowWindow(fWindowLayer); +fDesktop->ReadLockWindows(); if (fDirectWindowData != NULL) HandleDirectConnection(B_DIRECT_START | B_BUFFER_RESET); @@ -316,7 +326,11 @@ ServerWindow::Hide() if (fDirectWindowData != NULL) HandleDirectConnection(B_DIRECT_STOP); +// TODO: race condition? maybe we need to dispatch a message to the desktop to show/hide us +// instead of doing it from this thread. +fDesktop->ReadUnlockWindows(); fDesktop->HideWindow(fWindowLayer); +fDesktop->ReadLockWindows(); } @@ -344,7 +358,7 @@ ServerWindow::SetTitle(const char* newTitle) } if (fWindowLayer != NULL) - fWindowLayer->SetName(newTitle); + fWindowLayer->SetTitle(newTitle); } @@ -413,7 +427,7 @@ ServerWindow::GetInfo(window_info& info) info.layer = 0; // ToDo: what is this??? info.feel = fWindowLayer->Feel(); - info.flags = fWindowLayer->WindowFlags(); + info.flags = fWindowLayer->Flags(); info.window_left = (int)floor(fWindowLayer->Frame().left); info.window_top = (int)floor(fWindowLayer->Frame().top); info.window_right = (int)floor(fWindowLayer->Frame().right); @@ -428,8 +442,8 @@ ServerWindow::GetInfo(window_info& info) \brief Sets the font state for a layer \param layer The layer to set the font */ -inline void -ServerWindow::SetLayerFontState(Layer *layer, BPrivate::LinkReceiver &link) +void +ServerWindow::SetLayerFontState(ViewLayer *layer, BPrivate::LinkReceiver &link) { STRACE(("ServerWindow %s: SetLayerFontStateMessage for layer %s\n", fTitle, layer->Name())); @@ -439,20 +453,21 @@ ServerWindow::SetLayerFontState(Layer *layer, BPrivate::LinkReceiver &link) } -inline void -ServerWindow::SetLayerState(Layer *layer, BPrivate::LinkReceiver &link) +void +ServerWindow::SetLayerState(ViewLayer *layer, BPrivate::LinkReceiver &link) { STRACE(("ServerWindow %s: SetLayerState for layer %s\n", Title(), layer->Name())); // NOTE: no need to check for a lock. This is a private method. layer->CurrentState()->ReadFromLink(link); - // TODO: Rebuild clipping here! + // TODO: When is this used?!? + layer->RebuildClipping(true); } -Layer* -ServerWindow::CreateLayerTree(BPrivate::LinkReceiver &link, Layer **_parent) +ViewLayer* +ServerWindow::CreateLayerTree(BPrivate::LinkReceiver &link, ViewLayer **_parent) { // NOTE: no need to check for a lock. This is a private method. @@ -464,7 +479,7 @@ ServerWindow::CreateLayerTree(BPrivate::LinkReceiver &link, Layer **_parent) uint32 flags; bool hidden; int32 parentToken; - char *name = NULL; + char* name = NULL; rgb_color viewColor; link.Read(&token); @@ -481,46 +496,37 @@ ServerWindow::CreateLayerTree(BPrivate::LinkReceiver &link, Layer **_parent) STRACE(("ServerWindow(%s)::CreateLayerTree()-> layer %s, token %ld\n", fTitle, name, token)); - Layer *newLayer; + ViewLayer* newLayer; if (link.Code() == AS_LAYER_CREATE_ROOT - && (fWindowLayer->WindowFlags() & kWorkspacesWindowFlag) != 0) { + && (fWindowLayer->Flags() & kWorkspacesWindowFlag) != 0) { // this is a workspaces window! newLayer = new (nothrow) WorkspacesLayer(frame, name, token, resizeMask, - flags, fWindowLayer->GetDrawingEngine()); + flags); } else { - newLayer = new (nothrow) Layer(frame, name, token, resizeMask, flags, - fWindowLayer->GetDrawingEngine()); + newLayer = new (nothrow) ViewLayer(frame, name, token, resizeMask, flags); } + free(name); + if (newLayer == NULL) return NULL; - free(name); - // there is no way of setting this, other than manually :-) newLayer->SetViewColor(viewColor); - newLayer->fHidden = hidden; - newLayer->fEventMask = eventMask; - newLayer->fEventOptions = eventOptions; + newLayer->SetHidden(hidden); + newLayer->SetEventMask(eventMask, eventOptions); DesktopSettings settings(fDesktop); ServerFont font; settings.GetDefaultPlainFont(font); newLayer->CurrentState()->SetFont(font); -// TODO: rework the clipping stuff to remove RootLayer dependency and then -// remove this hack: -if (fWindowLayer->IsOffscreenWindow()) { - newLayer->fVisible.Set(newLayer->fFrame); - newLayer->fDrawingRegion.Set(newLayer->fFrame); -} - if (_parent) { - Layer *parent; + ViewLayer *parent; if (App()->ViewTokens().GetToken(parentToken, B_HANDLER_TOKEN, (void**)&parent) != B_OK - || parent->Window() != this) { + || parent->Window()->ServerWindow() != this) { CRITICAL("View token not found!\n"); parent = NULL; } @@ -532,728 +538,101 @@ if (fWindowLayer->IsOffscreenWindow()) { } +/*! + Dispatches all window messages, and those view messages that + don't need a valid fCurrentLayer (ie. layer creation). +*/ void ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) { - // TODO: when creating a Layer, check for yet non-existing Layer::InitCheck() - // and take appropriate actions, then checking for fCurrentLayer->fLayerData - // is unnecessary - if ((fCurrentLayer == NULL || fCurrentLayer->CurrentState() == NULL) && - code != AS_LAYER_CREATE_ROOT && code != AS_LAYER_CREATE) { - - printf("ServerWindow %s received unexpected code - message offset %ld before top_view attached.\n", Title(), code - B_OK); - return; - } - - RootLayer *rootLayer = fWindowLayer->GetRootLayer(); - // NOTE: is NULL when fWindowLayer is offscreen! - if (rootLayer) { -#ifdef PROFILE_MESSAGE_LOOP - bigtime_t start = system_time(); -#endif - rootLayer->Lock(); -#ifdef PROFILE_MESSAGE_LOOP - bigtime_t diff = system_time() - start; - if (diff > 10000) - printf("ServerWindow %s: root lock acquisition took %Ld usecs\n", Title(), diff); -#endif - } - switch (code) { - //--------- BView Messages ----------------- - case AS_LAYER_SCROLL: + case AS_SHOW_WINDOW: + STRACE(("ServerWindow %s: Message AS_SHOW_WINDOW\n", Title())); + Show(); + break; + + case AS_HIDE_WINDOW: + STRACE(("ServerWindow %s: Message AS_HIDE_WINDOW\n", Title())); + Hide(); + break; + + case AS_ACTIVATE_WINDOW: { - DTRACE(("ServerWindow %s: Message AS_LAYER_SCROLL: Layer name: %s\n", fTitle, fCurrentLayer->Name())); - float dh; - float dv; + DTRACE(("ServerWindow %s: Message AS_ACTIVATE_WINDOW: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + bool activate = true; - link.Read(&dh); - link.Read(&dv); - fCurrentLayer->ScrollBy(dh, dv); + link.Read(&activate); + if (activate) + fDesktop->ActivateWindow(fWindowLayer); + else + fDesktop->SendWindowBehind(fWindowLayer, NULL); break; } - case AS_LAYER_COPY_BITS: - { - BRect src; - BRect dst; - - link.Read(&src); - link.Read(&dst); - - // TODO: confirm that in R5 this call is affected by origin and scale -// fCurrentLayer->ConvertToScreenForDrawing(&src); -// fCurrentLayer->ConvertToScreenForDrawing(&dst); - fCurrentLayer->ConvertToScreen(&src); - fCurrentLayer->ConvertToScreen(&dst); - - int32 xOffset = (int32)(dst.left - src.left); - int32 yOffset = (int32)(dst.top - src.top); - - fCurrentLayer->CopyBits(src, dst, xOffset, yOffset); - break; - } - case AS_SET_CURRENT_LAYER: + case AS_SEND_BEHIND: { + STRACE(("ServerWindow %s: Message Send_Behind unimplemented\n", Title())); int32 token; - - link.Read(&token); - - Layer *current; - if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN, - (void**)¤t) != B_OK - || current->Window() != this) { - // ToDo: if this happens, we probably want to kill the app and clean up - DTRACE(("ServerWindow %s: Message AS_SET_CURRENT_LAYER: layer not found, token %ld\n", fTitle, token)); - current = NULL; - } else { - DTRACE(("ServerWindow %s: Message AS_SET_CURRENT_LAYER: %s, token %ld\n", fTitle, current->Name(), token)); - fCurrentLayer = current; - } - break; - } - - case AS_LAYER_CREATE_ROOT: - { - STRACE(("ServerWindow %s: Message AS_LAYER_CREATE_ROOT\n", fTitle)); - - // Start receiving top_view data -- pass NULL as the parent view. - // This should be the *only* place where this happens. - if (fCurrentLayer != NULL) - break; - - fWindowLayer->SetTopLayer(CreateLayerTree(link, NULL)); - fCurrentLayer = fWindowLayer->TopLayer(); - break; - } - - case AS_LAYER_CREATE: - { - STRACE(("ServerWindow %s: Message AS_LAYER_CREATE: Layer name: %s\n", fTitle, fCurrentLayer->Name())); - - Layer* parent = NULL; - Layer* newLayer = CreateLayerTree(link, &parent); - if (parent != NULL) - parent->AddChild(newLayer, this); - - if (rootLayer && !newLayer->IsHidden() && parent) { - BRegion invalidRegion; - newLayer->GetOnScreenRegion(invalidRegion); - parent->MarkForRebuild(invalidRegion); - parent->TriggerRebuild(); - if (newLayer->VisibleRegion().Frame().IsValid()) { - rootLayer->MarkForRedraw(newLayer->VisibleRegion()); - rootLayer->TriggerRedraw(); - } - } - break; - } - case AS_LAYER_DELETE: - { - // Received when a view is detached from a window. This is definitely - // the less taxing operation - we call PruneTree() on the removed - // layer, detach the layer itself, delete it, and invalidate the - // area assuming that the view was visible when removed - - Layer *parent = fCurrentLayer->fParent; - - STRACE(("ServerWindow %s: AS_LAYER_DELETE view: %p, parent: %p\n", fTitle, - fCurrentLayer, parent)); - - if (!fCurrentLayer->IsHidden() && parent && rootLayer - && fCurrentLayer->FullVisible().Frame().IsValid()) { - parent->MarkForRebuild(fCurrentLayer->FullVisible()); - rootLayer->MarkForRedraw(fCurrentLayer->FullVisible()); - } - - // here we remove current layer from list. - fCurrentLayer->RemoveSelf(); - - if (parent) - parent->TriggerRebuild(); - - if (rootLayer) { - rootLayer->LayerRemoved(fCurrentLayer); - if (!fCurrentLayer->IsHidden()) - rootLayer->TriggerRedraw(); - } - - if (fCurrentLayer->EventMask() != 0) { - fDesktop->EventDispatcher().RemoveListener(EventTarget(), - fCurrentLayer->ViewToken()); - } - - #ifdef DEBUG_SERVERWINDOW - parent->PrintTree(); - #endif - - delete fCurrentLayer; - // TODO: It is necessary to do this, but I find it very obscure. - fCurrentLayer = parent; - break; - } - case AS_LAYER_SET_STATE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_SET_STATE: Layer name: %s\n", fTitle, fCurrentLayer->Name())); - SetLayerState(fCurrentLayer, link); - // TODO: should this be moved into SetLayerState? - // If it _always_ needs to be done afterwards, then yes! - break; - } - case AS_LAYER_SET_FONT_STATE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_SET_FONT_STATE: Layer name: %s\n", fTitle, fCurrentLayer->Name())); - SetLayerFontState(fCurrentLayer, link); - break; - } - case AS_LAYER_GET_STATE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_GET_STATE: Layer name: %s\n", fTitle, fCurrentLayer->Name())); - - fLink.StartMessage(B_OK); - - // attach state data - fCurrentLayer->CurrentState()->WriteToLink(fLink.Sender()); - fLink.Flush(); - break; - } - case AS_LAYER_SET_EVENT_MASK: - { - STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: Layer name: %s\n", fTitle, fCurrentLayer->Name())); - rootLayer->Unlock(); - // we don't want RootLayer to be locked while we play with the events - - uint32 eventMask, options; - - link.Read(&eventMask); - if (link.Read(&options) == B_OK) { - fCurrentLayer->SetEventMask(eventMask, options); - - if (eventMask != 0 || options != 0) { - fDesktop->EventDispatcher().AddListener(EventTarget(), - fCurrentLayer->ViewToken(), eventMask, options); - } else { - fDesktop->EventDispatcher().RemoveListener(EventTarget(), - fCurrentLayer->ViewToken()); - } - } - - rootLayer->Lock(); - break; - } - case AS_LAYER_SET_MOUSE_EVENT_MASK: - { - STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: Layer name: %s\n", fTitle, fCurrentLayer->Name())); - rootLayer->Unlock(); - // we don't want RootLayer to be locked while we play with the events - - uint32 eventMask, options; - - link.Read(&eventMask); - if (link.Read(&options) == B_OK) { - if (eventMask != 0 || options != 0) { - fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(), - fCurrentLayer->ViewToken(), eventMask, options); - } else { - fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(), - fCurrentLayer->ViewToken()); - } - } - - // TODO: support B_LOCK_WINDOW_FOCUS option in RootLayer - rootLayer->Lock(); - break; - } - case AS_LAYER_MOVE_TO: - { - STRACE(("ServerWindow %s: Message AS_LAYER_MOVE_TO: Layer name: %s\n", - fTitle, fCurrentLayer->Name())); - - float x, y; - link.Read(&x); - link.Read(&y); - - float offsetX = x - fCurrentLayer->fFrame.left; - float offsetY = y - fCurrentLayer->fFrame.top; - - fCurrentLayer->MoveBy(offsetX, offsetY); - break; - } - case AS_LAYER_RESIZE_TO: - { - STRACE(("ServerWindow %s: Message AS_LAYER_RESIZE_TO: Layer name: %s\n", - fTitle, fCurrentLayer->Name())); - - float newWidth, newHeight; - link.Read(&newWidth); - link.Read(&newHeight); - - // TODO: If fCurrentLayer is a window, check for minimum size allowed. - // Need WindowLayer::GetSizeLimits - float deltaWidth = newWidth - fCurrentLayer->fFrame.Width(); - float deltaHeight = newHeight - fCurrentLayer->fFrame.Height(); - - fCurrentLayer->ResizeBy(deltaWidth, deltaHeight); - break; - } - case AS_LAYER_GET_COORD: - { - STRACE(("ServerWindow %s: Message AS_LAYER_GET_COORD: Layer: %s\n", Title(), fCurrentLayer->Name())); - fLink.StartMessage(B_OK); - // our offset in the parent -> will be originX and originY in BView - fLink.Attach(fCurrentLayer->fFrame.left); - fLink.Attach(fCurrentLayer->fFrame.top); - fLink.Attach(fCurrentLayer->Bounds()); - fLink.Flush(); - break; - } - case AS_LAYER_SET_ORIGIN: - { - STRACE(("ServerWindow %s: Message AS_LAYER_SET_ORIGIN: Layer: %s\n", Title(), fCurrentLayer->Name())); - float x, y; - - link.Read(&x); - link.Read(&y); - - fCurrentLayer->SetDrawingOrigin(BPoint(x, y)); - break; - } - case AS_LAYER_GET_ORIGIN: - { - STRACE(("ServerWindow %s: Message AS_LAYER_GET_ORIGIN: Layer: %s\n", Title(), fCurrentLayer->Name())); - fLink.StartMessage(B_OK); - // TODO: rename this where it is used in the BView code! - // (it wants to know scrolling offset, not drawing origin) - fLink.Attach(fCurrentLayer->ScrollingOffset()); - fLink.Flush(); - break; - } - case AS_LAYER_RESIZE_MODE: - { - STRACE(("ServerWindow %s: Message AS_LAYER_RESIZE_MODE: Layer: %s\n", Title(), fCurrentLayer->Name())); - link.Read(&(fCurrentLayer->fResizeMode)); - break; - } - case AS_LAYER_CURSOR: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_CURSOR: Layer: %s - NOT IMPLEMENTED\n", Title(), fCurrentLayer->Name())); - int32 token; + team_id teamID; + status_t status; link.Read(&token); + link.Read(&teamID); - // TODO: implement; I think each Layer should have a member pointing - // to this requested cursor. - - break; - } - case AS_LAYER_SET_FLAGS: - { - uint32 flags; - link.Read(&flags); - fCurrentLayer->SetFlags(flags); - - STRACE(("ServerWindow %s: Message AS_LAYER_SET_FLAGS: Layer: %s\n", Title(), fCurrentLayer->Name())); - break; - } - case AS_LAYER_HIDE: - { - STRACE(("ServerWindow %s: Message AS_LAYER_HIDE: Layer: %s\n", Title(), fCurrentLayer->Name())); - fCurrentLayer->Hide(); - break; - } - case AS_LAYER_SHOW: - { - STRACE(("ServerWindow %s: Message AS_LAYER_SHOW: Layer: %s\n", Title(), fCurrentLayer->Name())); - fCurrentLayer->Show(); - break; - } - case AS_LAYER_SET_LINE_MODE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LINE_MODE: Layer: %s\n", Title(), fCurrentLayer->Name())); - int8 lineCap, lineJoin; - float miterLimit; + WindowLayer *behindOf; + if ((behindOf = fDesktop->FindWindowLayerByClientToken(token, teamID)) != NULL) { + fDesktop->SendWindowBehind(fWindowLayer, behindOf); + status = B_OK; + } else + status = B_NAME_NOT_FOUND; - // TODO: Look into locking scheme relating to Layers and modifying redraw-related members - - link.Read(&lineCap); - link.Read(&lineJoin); - link.Read(&miterLimit); - - fCurrentLayer->CurrentState()->SetLineCapMode((cap_mode)lineCap); - fCurrentLayer->CurrentState()->SetLineJoinMode((join_mode)lineJoin); - fCurrentLayer->CurrentState()->SetMiterLimit(miterLimit); - - break; - } - case AS_LAYER_GET_LINE_MODE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_GET_LINE_MODE: Layer: %s\n", Title(), fCurrentLayer->Name())); - fLink.StartMessage(B_OK); - fLink.Attach((int8)(fCurrentLayer->CurrentState()->LineCapMode())); - fLink.Attach((int8)(fCurrentLayer->CurrentState()->LineJoinMode())); - fLink.Attach(fCurrentLayer->CurrentState()->MiterLimit()); - fLink.Flush(); - - break; - } - case AS_LAYER_PUSH_STATE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_PUSH_STATE: Layer: %s\n", Title(), fCurrentLayer->Name())); - - fCurrentLayer->PushState(); - - break; - } - case AS_LAYER_POP_STATE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_POP_STATE: Layer: %s\n", Title(), fCurrentLayer->Name())); - - fCurrentLayer->PopState(); - - break; - } - case AS_LAYER_SET_SCALE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_SET_SCALE: Layer: %s\n", Title(), fCurrentLayer->Name())); - float scale; - link.Read(&scale); - - fCurrentLayer->SetScale(scale); - break; - } - case AS_LAYER_GET_SCALE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_GET_SCALE: Layer: %s\n", Title(), fCurrentLayer->Name())); - - fLink.StartMessage(B_OK); - fLink.Attach(fCurrentLayer->CurrentState()->Scale()); + fLink.StartMessage(status); fLink.Flush(); break; } - case AS_LAYER_SET_PEN_LOC: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_LOC: Layer: %s\n", Title(), fCurrentLayer->Name())); - float x, y; - link.Read(&x); - link.Read(&y); - - fCurrentLayer->CurrentState()->SetPenLocation(BPoint(x, y)); - break; - } - case AS_LAYER_GET_PEN_LOC: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_LOC: Layer: %s\n", Title(), fCurrentLayer->Name())); - fLink.StartMessage(B_OK); - fLink.Attach(fCurrentLayer->CurrentState()->PenLocation()); - fLink.Flush(); - - break; - } - case AS_LAYER_SET_PEN_SIZE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_SIZE: Layer: %s\n", Title(), fCurrentLayer->Name())); - float penSize; - link.Read(&penSize); - fCurrentLayer->CurrentState()->SetPenSize(penSize); - - break; - } - case AS_LAYER_GET_PEN_SIZE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_SIZE: Layer: %s\n", Title(), fCurrentLayer->Name())); - fLink.StartMessage(B_OK); - fLink.Attach(fCurrentLayer->CurrentState()->PenSize()); - fLink.Flush(); - - break; - } - case AS_LAYER_SET_VIEW_COLOR: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_SET_VIEW_COLOR: Layer: %s\n", Title(), fCurrentLayer->Name())); - rgb_color c; - - link.Read(&c, sizeof(rgb_color)); - - fCurrentLayer->SetViewColor(RGBColor(c)); - - if (rootLayer && !fCurrentLayer->IsHidden()) { - rootLayer->MarkForRedraw(fCurrentLayer->VisibleRegion()); - rootLayer->TriggerRedraw(); - } - break; - } - - case AS_LAYER_GET_HIGH_COLOR: - DTRACE(("ServerWindow %s: Message AS_LAYER_GET_HIGH_COLOR: Layer: %s\n", - Title(), fCurrentLayer->Name())); - - fLink.StartMessage(B_OK); - fLink.Attach(fCurrentLayer->CurrentState()->HighColor().GetColor32()); - fLink.Flush(); + case B_QUIT_REQUESTED: + STRACE(("ServerWindow %s received quit request\n", Title())); + NotifyQuitRequested(); break; - case AS_LAYER_GET_LOW_COLOR: - DTRACE(("ServerWindow %s: Message AS_LAYER_GET_LOW_COLOR: Layer: %s\n", - Title(), fCurrentLayer->Name())); - - fLink.StartMessage(B_OK); - fLink.Attach(fCurrentLayer->CurrentState()->LowColor().GetColor32()); - fLink.Flush(); - break; - - case AS_LAYER_GET_VIEW_COLOR: - DTRACE(("ServerWindow %s: Message AS_LAYER_GET_VIEW_COLOR: Layer: %s\n", - Title(), fCurrentLayer->Name())); - - fLink.StartMessage(B_OK); - fLink.Attach(fCurrentLayer->ViewColor().GetColor32()); - fLink.Flush(); - break; - - case AS_LAYER_SET_BLEND_MODE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_SET_BLEND_MODE: Layer: %s\n", Title(), fCurrentLayer->Name())); - int8 srcAlpha, alphaFunc; - - link.Read(&srcAlpha); - link.Read(&alphaFunc); - - fCurrentLayer->CurrentState()->SetBlendingMode((source_alpha)srcAlpha, - (alpha_function)alphaFunc); - - break; - } - case AS_LAYER_GET_BLEND_MODE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_GET_BLEND_MODE: Layer: %s\n", Title(), fCurrentLayer->Name())); - fLink.StartMessage(B_OK); - fLink.Attach((int8)(fCurrentLayer->CurrentState()->AlphaSrcMode())); - fLink.Attach((int8)(fCurrentLayer->CurrentState()->AlphaFncMode())); - fLink.Flush(); - - break; - } - case AS_LAYER_SET_DRAW_MODE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_SET_DRAW_MODE: Layer: %s\n", Title(), fCurrentLayer->Name())); - int8 drawingMode; - - link.Read(&drawingMode); - - fCurrentLayer->CurrentState()->SetDrawingMode((drawing_mode)drawingMode); - - break; - } - case AS_LAYER_GET_DRAW_MODE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_GET_DRAW_MODE: Layer: %s\n", Title(), fCurrentLayer->Name())); - fLink.StartMessage(B_OK); - fLink.Attach((int8)(fCurrentLayer->CurrentState()->GetDrawingMode())); - fLink.Flush(); - - break; - } - case AS_LAYER_PRINT_ALIASING: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_PRINT_ALIASING: Layer: %s\n", Title(), fCurrentLayer->Name())); - bool fontAliasing; - link.Read(&fontAliasing); - fCurrentLayer->CurrentState()->SetForceFontAliasing(fontAliasing); - - break; - } - case AS_LAYER_CLIP_TO_PICTURE: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_CLIP_TO_PICTURE: Layer: %s\n", Title(), fCurrentLayer->Name())); - // TODO: you are not allowed to use Layer regions here!!! - // If there is no other way, then first lock RootLayer object first. - - int32 pictureToken; - BPoint where; - bool inverse = false; - - link.Read(&pictureToken); - link.Read(&where); - link.Read(&inverse); - - // search for a picture with the specified token. - ServerPicture *picture = fServerApp->FindPicture(pictureToken); - // TODO: Increase that picture's reference count.(~ allocate a picture) - if (picture == NULL) - break; - - BRegion region; - // TODO: I think we also need the BView's token - // I think PictureToRegion would fit better into the Layer class (?) - if (PictureToRegion(picture, region, inverse, where) < B_OK) - break; - - fCurrentLayer->CurrentState()->SetClippingRegion(region); - - if (rootLayer && !(fCurrentLayer->IsHidden()) && !fWindowLayer->InUpdate()) { - BRegion invalidRegion; - fCurrentLayer->GetOnScreenRegion(invalidRegion); - - // TODO: this is broken! a smaller area may be invalidated! - - fCurrentLayer->fParent->MarkForRebuild(invalidRegion); - fCurrentLayer->fParent->TriggerRebuild(); - rootLayer->MarkForRedraw(invalidRegion); - rootLayer->TriggerRedraw(); - } - - break; - } - - case AS_LAYER_GET_CLIP_REGION: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_GET_CLIP_REGION: Layer: %s\n", Title(), fCurrentLayer->Name())); - - // if this Layer is hidden, it is clear that its visible region is void. - if (fCurrentLayer->IsHidden()) { - fLink.StartMessage(B_OK); - fLink.Attach(0L); - fLink.Flush(); - } else { - BRegion drawingRegion = fCurrentLayer->DrawingRegion(); - int32 rectCount = drawingRegion.CountRects(); - - fLink.StartMessage(B_OK); - fLink.Attach(rectCount); - - for (int32 i = 0; i < rectCount; i++) { - BRect converted(drawingRegion.RectAt(i)); - fCurrentLayer->ConvertFromScreen(&converted); - fLink.Attach(converted); - } - - fLink.Flush(); - } - - break; - } - case AS_LAYER_SET_CLIP_REGION: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_SET_CLIP_REGION: Layer: %s\n", Title(), fCurrentLayer->Name())); - - int32 rectCount; - link.Read(&rectCount); - - BRegion region; - for (int32 i = 0; i < rectCount; i++) { - BRect r; - link.Read(&r); - region.Include(r); - } - fCurrentLayer->SetUserClipping(region); - - break; - } - case AS_LAYER_INVAL_RECT: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_INVAL_RECT: Layer: %s\n", Title(), fCurrentLayer->Name())); - - // NOTE: looks like this call is NOT affected by origin and scale on R5 - // so this implementation is "correct" - BRect invalRect; - - link.Read(&invalRect); - - if (rootLayer && !fCurrentLayer->IsHidden()) { - BRect converted(invalRect.LeftTop(), invalRect.RightBottom()); - - fCurrentLayer->ConvertToScreen(&converted); - - BRegion invalidRegion(converted); - invalidRegion.IntersectWith(&fCurrentLayer->VisibleRegion()); - rootLayer->MarkForRedraw(invalidRegion); - rootLayer->TriggerRedraw(); - } - break; - } - case AS_LAYER_INVAL_REGION: - { - DTRACE(("ServerWindow %s: Message AS_LAYER_INVAL_RECT: Layer: %s\n", Title(), fCurrentLayer->Name())); - - // NOTE: looks like this call is NOT affected by origin and scale on R5 - // so this implementation is "correct" - BRegion invalidReg; - int32 noOfRects; - BRect rect; - - link.Read(&noOfRects); - - for (int i = 0; i < noOfRects; i++) { - link.Read(&rect); - invalidReg.Include(rect); - } - - if (rootLayer && !fCurrentLayer->IsHidden()) { - fCurrentLayer->ConvertToScreen(&invalidReg); - - rootLayer->MarkForRedraw(invalidReg); - rootLayer->TriggerRedraw(); - } - break; - } - case AS_BEGIN_UPDATE: - { - DTRACE(("ServerWindowo %s: AS_BEGIN_UPDATE\n", Title())); - fWindowLayer->UpdateStart(); - break; - } - case AS_END_UPDATE: - { - DTRACE(("ServerWindowo %s: AS_END_UPDATE\n", Title())); - fWindowLayer->UpdateEnd(); - break; - } - - // ********** END: BView Messages *********** - - // ********* BWindow Messages *********** - case AS_LAYER_DELETE_ROOT: - { - // Received when a window deletes its internal top view - - // TODO: Implement AS_LAYER_DELETE_ROOT - STRACE(("ServerWindow %s: Message Delete_Layer_Root unimplemented\n", Title())); - break; - } case AS_BEGIN_TRANSACTION: { STRACE(("ServerWindow %s: Message AS_BEGIN_TRANSACTION unimplemented\n", Title())); // TODO: we could probably do a bit more here... - fWindowLayer->DisableUpdateRequests(); +// TODO: AS_BEGIN_TRANSACTION + //fWindowLayer->DisableUpdateRequests(); break; } case AS_END_TRANSACTION: { STRACE(("ServerWindow %s: Message AS_END_TRANSACTION unimplemented\n", Title())); - fWindowLayer->EnableUpdateRequests(); +// TODO: AS_END_TRANSACTION + //fWindowLayer->EnableUpdateRequests(); break; } case AS_ENABLE_UPDATES: { STRACE(("ServerWindow %s: Message AS_ENABLE_UPDATES unimplemented\n", Title())); - fWindowLayer->EnableUpdateRequests(); +// TODO: AS_ENABLE_UPDATES + //fWindowLayer->EnableUpdateRequests(); break; } case AS_DISABLE_UPDATES: { STRACE(("ServerWindow %s: Message AS_DISABLE_UPDATES unimplemented\n", Title())); - fWindowLayer->DisableUpdateRequests(); +// TODO: AS_DISABLE_UPDATES + //fWindowLayer->DisableUpdateRequests(); break; } case AS_NEEDS_UPDATE: { STRACE(("ServerWindow %s: Message Needs_Update unimplemented\n", Title())); - if (fWindowLayer->CulmulatedUpdateRegion().Frame().IsValid()) + if (fWindowLayer->NeedsUpdate()) fLink.StartMessage(B_OK); else fLink.StartMessage(B_ERROR); @@ -1433,89 +812,766 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) // 3) float minimum height // 4) float maximum height - float minWidth; - float maxWidth; - float minHeight; - float maxHeight; - - link.Read(&minWidth); - link.Read(&maxWidth); - link.Read(&minHeight); - link.Read(&maxHeight); - + // TODO: for now, move the client to int32 as well! + int32 minWidth, maxWidth, minHeight, maxHeight; + float value; + link.Read(&value); minWidth = (int32)value; + link.Read(&value); maxWidth = (int32)value; + link.Read(&value); minHeight = (int32)value; + link.Read(&value); maxHeight = (int32)value; +/* + link.Read(&minWidth); + link.Read(&maxWidth); + link.Read(&minHeight); + link.Read(&maxHeight); +*/ // TODO: setting size limits can change the window size, and therefore, // it should be done by the Desktop class as well. - fWindowLayer->SetSizeLimits(minWidth, maxWidth, minHeight, maxHeight); + fWindowLayer->SetSizeLimits(minWidth, maxWidth, + minHeight, maxHeight); // and now, sync the client to the limits that we were able to enforce - fWindowLayer->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight); + fWindowLayer->GetSizeLimits(&minWidth, &maxWidth, + &minHeight, &maxHeight); fLink.StartMessage(B_OK); fLink.Attach(fWindowLayer->Frame()); - fLink.Attach(minWidth); - fLink.Attach(maxWidth); - fLink.Attach(minHeight); - fLink.Attach(maxHeight); + fLink.Attach((float)minWidth); + fLink.Attach((float)maxWidth); + fLink.Attach((float)minHeight); + fLink.Attach((float)maxHeight); fLink.Flush(); break; } - // Some BView drawing messages, but which don't need clipping - case AS_LAYER_SET_HIGH_COLOR: + + case AS_REDRAW: + // command issued by Desktop only (via WindowLayer::ProcessDirtyRegion()) + DTRACE(("ServerWindow %s: AS_REDRAW\n", Title())); + fWindowLayer->RedrawDirtyRegion(); + break; + + case AS_BEGIN_UPDATE: + DTRACE(("ServerWindowo %s: AS_BEGIN_UPDATE\n", Title())); + fWindowLayer->BeginUpdate(); + break; + + case AS_END_UPDATE: + DTRACE(("ServerWindowo %s: AS_END_UPDATE\n", Title())); + fWindowLayer->EndUpdate(); + break; + + case AS_LAYER_DELETE_ROOT: { - DTRACE(("ServerWindow %s: Message AS_LAYER_SET_HIGH_COLOR: Layer: %s\n", Title(), fCurrentLayer->Name())); + // Received when a window deletes its internal top view + + // TODO: Implement AS_LAYER_DELETE_ROOT + STRACE(("ServerWindow %s: Message Delete_Layer_Root unimplemented\n", Title())); + break; + } + + case AS_GET_MOUSE: + { +fDesktop->ReadUnlockWindows(); + DTRACE(("ServerWindow %s: Message AS_GET_MOUSE\n", fTitle)); + + // Returns + // 1) BPoint mouse location + // 2) int32 button state + + BPoint where; + int32 buttons; + fDesktop->EventDispatcher().GetMouse(where, buttons); + + fLink.StartMessage(B_OK); + fLink.Attach(where); + fLink.Attach(buttons); + fLink.Flush(); +fDesktop->ReadLockWindows(); + break; + } + + case AS_SET_CURRENT_LAYER: + { + int32 token; + link.Read(&token); + + ViewLayer *current; + if (App()->ViewTokens().GetToken(token, B_HANDLER_TOKEN, + (void**)¤t) != B_OK + || current->Window()->ServerWindow() != this) { + // ToDo: if this happens, we probably want to kill the app and clean up + fprintf(stderr, "ServerWindow %s: Message AS_SET_CURRENT_LAYER: layer not found, token %ld\n", fTitle, token); + current = NULL; + } else { + DTRACE(("ServerWindow %s: Message AS_SET_CURRENT_LAYER: %s, token %ld\n", fTitle, current->Name(), token)); + _SetCurrentLayer(current); + } + break; + } + + case AS_LAYER_CREATE_ROOT: + { + STRACE(("ServerWindow %s: Message AS_LAYER_CREATE_ROOT\n", fTitle)); + + // Start receiving top_view data -- pass NULL as the parent view. + // This should be the *only* place where this happens. + if (fCurrentLayer != NULL) { + fprintf(stderr, "ServerWindow %s: Message AS_LAYER_CREATE_ROOT: fCurrentLayer already set!!\n", fTitle); + break; + } + + _SetCurrentLayer(CreateLayerTree(link, NULL)); + fWindowLayer->SetTopLayer(fCurrentLayer); + break; + } + + case AS_LAYER_CREATE: + { + STRACE(("ServerWindow %s: Message AS_LAYER_CREATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); + + ViewLayer* parent = NULL; + ViewLayer* newLayer = CreateLayerTree(link, &parent); + if (parent != NULL && newLayer != NULL) + parent->AddChild(newLayer); + else + fprintf(stderr, "ServerWindow %s: Message AS_LAYER_CREATE: parent or newLayer NULL!!\n", fTitle); + break; + } + + default: + // TODO: when creating a ViewLayer, check for yet non-existing ViewLayer::InitCheck() + // and take appropriate actions, then checking for fCurrentLayer->fLayerData + // is unnecessary + if (fCurrentLayer == NULL || fCurrentLayer->CurrentState() == NULL) { + printf("ServerWindow %s received unexpected code - message offset %ld before top_view attached.\n", Title(), code - B_OK); + return; + } + + _DispatchViewMessage(code, link); + break; + } +} + + +/*! + Dispatches all view messages that need a valid fCurrentLayer. +*/ +void +ServerWindow::_DispatchViewMessage(int32 code, + BPrivate::LinkReceiver &link) +{ + switch (code) { + case AS_LAYER_SCROLL: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_SCROLL: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); + float dh; + float dv; + + link.Read(&dh); + link.Read(&dv); + fWindowLayer->ScrollViewBy(fCurrentLayer, dh, dv); + break; + } + case AS_LAYER_COPY_BITS: + { + BRect src; + BRect dst; + + link.Read(&src); + link.Read(&dst); + + BRegion contentRegion; + // TODO: avoid copy operation maybe? + fWindowLayer->GetContentRegion(&contentRegion); + fCurrentLayer->CopyBits(src, dst, contentRegion); + break; + } + case AS_LAYER_DELETE: + { + // Received when a view is detached from a window. This is definitely + // the less taxing operation - we call PruneTree() on the removed + // layer, detach the layer itself, delete it, and invalidate the + // area assuming that the view was visible when removed + ViewLayer *parent = fCurrentLayer->Parent(); + + STRACE(("ServerWindow %s: AS_LAYER_DELETE view: %p, parent: %p\n", fTitle, + fCurrentLayer, parent)); + + if (parent != NULL) + parent->RemoveChild(fCurrentLayer); + + if (fCurrentLayer->EventMask() != 0) { + fDesktop->EventDispatcher().RemoveListener(EventTarget(), + fCurrentLayer->Token()); + } + + delete fCurrentLayer; + // TODO: It is necessary to do this, but I find it very obscure. + fCurrentLayer = parent; + break; + } + case AS_LAYER_SET_STATE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_SET_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); + SetLayerState(fCurrentLayer, link); + break; + } + case AS_LAYER_SET_FONT_STATE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_SET_FONT_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); + SetLayerFontState(fCurrentLayer, link); + break; + } + case AS_LAYER_GET_STATE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_GET_STATE: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); + + fLink.StartMessage(B_OK); + + // attach state data + fCurrentLayer->CurrentState()->WriteToLink(fLink.Sender()); + fLink.Flush(); + break; + } + case AS_LAYER_SET_EVENT_MASK: + { + STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); + uint32 eventMask, options; + + link.Read(&eventMask); + if (link.Read(&options) == B_OK) { + fDesktop->ReadUnlockWindows(); + fCurrentLayer->SetEventMask(eventMask, options); + + if (eventMask != 0 || options != 0) { + fDesktop->EventDispatcher().AddListener(EventTarget(), + fCurrentLayer->Token(), eventMask, options); + } else { + fDesktop->EventDispatcher().RemoveListener(EventTarget(), + fCurrentLayer->Token()); + } + fDesktop->ReadLockWindows(); + } + break; + } + case AS_LAYER_SET_MOUSE_EVENT_MASK: + { + STRACE(("ServerWindow %s: Message AS_LAYER_SET_MOUSE_EVENT_MASK: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); + uint32 eventMask, options; + + link.Read(&eventMask); + if (link.Read(&options) == B_OK) { + fDesktop->ReadUnlockWindows(); + if (eventMask != 0 || options != 0) { + fDesktop->EventDispatcher().AddTemporaryListener(EventTarget(), + fCurrentLayer->Token(), eventMask, options); + } else { + fDesktop->EventDispatcher().RemoveTemporaryListener(EventTarget(), + fCurrentLayer->Token()); + } + fDesktop->ReadLockWindows(); + } + + // TODO: support B_LOCK_WINDOW_FOCUS option in Desktop + break; + } + case AS_LAYER_MOVE_TO: + { + STRACE(("ServerWindow %s: Message AS_LAYER_MOVE_TO: ViewLayer name: %s\n", + fTitle, fCurrentLayer->Name())); + + float x, y; + link.Read(&x); + link.Read(&y); + + float offsetX = x - fCurrentLayer->Frame().left; + float offsetY = y - fCurrentLayer->Frame().top; + + if (fDesktop->ReadLockWindows()) { + BRegion dirty; + fCurrentLayer->MoveBy(offsetX, offsetY, &dirty); + + // TODO: think about how to avoid this hack: + // the parent clipping needs to be updated, it is not + // done in ResizeBy() since it would need to avoid + // too much computations when children are resized because + // follow modes + if (ViewLayer* parent = fCurrentLayer->Parent()) + parent->RebuildClipping(false); + + fWindowLayer->MarkContentDirty(dirty); + fDesktop->ReadUnlockWindows(); + } + break; + } + case AS_LAYER_RESIZE_TO: + { + STRACE(("ServerWindow %s: Message AS_LAYER_RESIZE_TO: ViewLayer name: %s\n", + fTitle, fCurrentLayer->Name())); + + float newWidth, newHeight; + link.Read(&newWidth); + link.Read(&newHeight); + + float deltaWidth = newWidth - fCurrentLayer->Frame().Width(); + float deltaHeight = newHeight - fCurrentLayer->Frame().Height(); + + if (fDesktop->ReadLockWindows()) { + BRegion dirty; + fCurrentLayer->ResizeBy(deltaWidth, deltaHeight, &dirty); + + // TODO: see above + if (ViewLayer* parent = fCurrentLayer->Parent()) + parent->RebuildClipping(false); + + fWindowLayer->MarkContentDirty(dirty); + fDesktop->ReadUnlockWindows(); + } + break; + } + case AS_LAYER_GET_COORD: + { + fDesktop->ReadLockWindows(); + + STRACE(("ServerWindow %s: Message AS_LAYER_GET_COORD: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + fLink.StartMessage(B_OK); + // our offset in the parent -> will be originX and originY in BView + fLink.Attach(fCurrentLayer->Frame().left); + fLink.Attach(fCurrentLayer->Frame().top); + fLink.Attach(fCurrentLayer->Bounds()); + fLink.Flush(); + + fDesktop->ReadUnlockWindows(); + break; + } + case AS_LAYER_SET_ORIGIN: + { + STRACE(("ServerWindow %s: Message AS_LAYER_SET_ORIGIN: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + + float x, y; + link.Read(&x); + link.Read(&y); + + fCurrentLayer->SetDrawingOrigin(BPoint(x, y)); + break; + } + case AS_LAYER_GET_ORIGIN: + { + STRACE(("ServerWindow %s: Message AS_LAYER_GET_ORIGIN: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + fLink.StartMessage(B_OK); + // TODO: rename this where it is used in the BView code! + // (it wants to know scrolling offset, not drawing origin) + fLink.Attach(fCurrentLayer->ScrollingOffset()); + fLink.Flush(); + break; + } + case AS_LAYER_RESIZE_MODE: + { + STRACE(("ServerWindow %s: Message AS_LAYER_RESIZE_MODE: ViewLayer: %s\n", + Title(), fCurrentLayer->Name())); + + uint32 resizeMode; + if (link.Read(&resizeMode) == B_OK) + fCurrentLayer->SetResizeMode(resizeMode); + break; + } + case AS_LAYER_CURSOR: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_CURSOR: ViewLayer: %s - NOT IMPLEMENTED\n", Title(), fCurrentLayer->Name())); + int32 token; + + link.Read(&token); + + // TODO: implement; I think each ViewLayer should have a member pointing + // to this requested cursor. + + break; + } + case AS_LAYER_SET_FLAGS: + { + uint32 flags; + link.Read(&flags); + fCurrentLayer->SetFlags(flags); + + STRACE(("ServerWindow %s: Message AS_LAYER_SET_FLAGS: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + break; + } + case AS_LAYER_HIDE: + { + STRACE(("ServerWindow %s: Message AS_LAYER_HIDE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); +// TODO: test + fCurrentLayer->SetHidden(true); + break; + } + case AS_LAYER_SHOW: + { + STRACE(("ServerWindow %s: Message AS_LAYER_SHOW: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); +// TODO: test + fCurrentLayer->SetHidden(false); + break; + } + case AS_LAYER_SET_LINE_MODE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LINE_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + int8 lineCap, lineJoin; + float miterLimit; + + link.Read(&lineCap); + link.Read(&lineJoin); + link.Read(&miterLimit); + + fCurrentLayer->CurrentState()->SetLineCapMode((cap_mode)lineCap); + fCurrentLayer->CurrentState()->SetLineJoinMode((join_mode)lineJoin); + fCurrentLayer->CurrentState()->SetMiterLimit(miterLimit); + + break; + } + case AS_LAYER_GET_LINE_MODE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_GET_LINE_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + fLink.StartMessage(B_OK); + fLink.Attach((int8)(fCurrentLayer->CurrentState()->LineCapMode())); + fLink.Attach((int8)(fCurrentLayer->CurrentState()->LineJoinMode())); + fLink.Attach(fCurrentLayer->CurrentState()->MiterLimit()); + fLink.Flush(); + + break; + } + case AS_LAYER_PUSH_STATE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_PUSH_STATE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + + fCurrentLayer->PushState(); + + break; + } + case AS_LAYER_POP_STATE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_POP_STATE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + + fCurrentLayer->PopState(); + + break; + } + case AS_LAYER_SET_SCALE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_SET_SCALE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + float scale; + link.Read(&scale); + + fCurrentLayer->SetScale(scale); + break; + } + case AS_LAYER_GET_SCALE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_GET_SCALE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + + fLink.StartMessage(B_OK); + fLink.Attach(fCurrentLayer->CurrentState()->Scale()); + fLink.Flush(); + break; + } + case AS_LAYER_SET_PEN_LOC: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_LOC: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + float x, y; + + link.Read(&x); + link.Read(&y); + + fCurrentLayer->CurrentState()->SetPenLocation(BPoint(x, y)); + break; + } + case AS_LAYER_GET_PEN_LOC: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_LOC: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + fLink.StartMessage(B_OK); + fLink.Attach(fCurrentLayer->CurrentState()->PenLocation()); + fLink.Flush(); + + break; + } + case AS_LAYER_SET_PEN_SIZE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PEN_SIZE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + float penSize; + link.Read(&penSize); + fCurrentLayer->CurrentState()->SetPenSize(penSize); + + break; + } + case AS_LAYER_GET_PEN_SIZE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_GET_PEN_SIZE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + fLink.StartMessage(B_OK); + fLink.Attach(fCurrentLayer->CurrentState()->PenSize()); + fLink.Flush(); + + break; + } + case AS_LAYER_SET_VIEW_COLOR: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_SET_VIEW_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); rgb_color c; link.Read(&c, sizeof(rgb_color)); + + fCurrentLayer->SetViewColor(RGBColor(c)); + break; + } + + case AS_LAYER_GET_HIGH_COLOR: + DTRACE(("ServerWindow %s: Message AS_LAYER_GET_HIGH_COLOR: ViewLayer: %s\n", + Title(), fCurrentLayer->Name())); + + fLink.StartMessage(B_OK); + fLink.Attach(fCurrentLayer->CurrentState()->HighColor().GetColor32()); + fLink.Flush(); + break; + + case AS_LAYER_GET_LOW_COLOR: + DTRACE(("ServerWindow %s: Message AS_LAYER_GET_LOW_COLOR: ViewLayer: %s\n", + Title(), fCurrentLayer->Name())); + + fLink.StartMessage(B_OK); + fLink.Attach(fCurrentLayer->CurrentState()->LowColor().GetColor32()); + fLink.Flush(); + break; + + case AS_LAYER_GET_VIEW_COLOR: + DTRACE(("ServerWindow %s: Message AS_LAYER_GET_VIEW_COLOR: ViewLayer: %s\n", + Title(), fCurrentLayer->Name())); + + fLink.StartMessage(B_OK); + fLink.Attach(fCurrentLayer->ViewColor().GetColor32()); + fLink.Flush(); + break; + + case AS_LAYER_SET_BLEND_MODE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_SET_BLEND_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + int8 srcAlpha, alphaFunc; + + link.Read(&srcAlpha); + link.Read(&alphaFunc); + + fCurrentLayer->CurrentState()->SetBlendingMode((source_alpha)srcAlpha, + (alpha_function)alphaFunc); + + break; + } + case AS_LAYER_GET_BLEND_MODE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_GET_BLEND_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + fLink.StartMessage(B_OK); + fLink.Attach((int8)(fCurrentLayer->CurrentState()->AlphaSrcMode())); + fLink.Attach((int8)(fCurrentLayer->CurrentState()->AlphaFncMode())); + fLink.Flush(); + + break; + } + case AS_LAYER_SET_DRAW_MODE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_SET_DRAW_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + int8 drawingMode; + + link.Read(&drawingMode); + + fCurrentLayer->CurrentState()->SetDrawingMode((drawing_mode)drawingMode); + + break; + } + case AS_LAYER_GET_DRAW_MODE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_GET_DRAW_MODE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + fLink.StartMessage(B_OK); + fLink.Attach((int8)(fCurrentLayer->CurrentState()->GetDrawingMode())); + fLink.Flush(); + + break; + } + case AS_LAYER_PRINT_ALIASING: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_PRINT_ALIASING: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + bool fontAliasing; + link.Read(&fontAliasing); + fCurrentLayer->CurrentState()->SetForceFontAliasing(fontAliasing); + + break; + } + case AS_LAYER_CLIP_TO_PICTURE: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_CLIP_TO_PICTURE: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + // TODO: you are not allowed to use ViewLayer regions here!!! + // If there is no other way, then first lock RootLayer object first. + + int32 pictureToken; + BPoint where; + bool inverse = false; + + link.Read(&pictureToken); + link.Read(&where); + link.Read(&inverse); + + // search for a picture with the specified token. + ServerPicture *picture = fServerApp->FindPicture(pictureToken); + // TODO: Increase that picture's reference count.(~ allocate a picture) + if (picture == NULL) + break; + + BRegion region; + // TODO: I think we also need the BView's token + // I think PictureToRegion would fit better into the ViewLayer class (?) + if (PictureToRegion(picture, region, inverse, where) < B_OK) + break; + + fCurrentLayer->CurrentState()->SetClippingRegion(region); + +// TODO: reenable AS_LAYER_CLIP_TO_PICTURE +#if 0 + if (rootLayer && !(fCurrentLayer->IsHidden()) && !fWindowLayer->InUpdate()) { + BRegion invalidRegion; + fCurrentLayer->GetOnScreenRegion(invalidRegion); + + // TODO: this is broken! a smaller area may be invalidated! + + fCurrentLayer->fParent->MarkForRebuild(invalidRegion); + fCurrentLayer->fParent->TriggerRebuild(); + rootLayer->MarkForRedraw(invalidRegion); + rootLayer->TriggerRedraw(); + } +#endif + break; + } + + case AS_LAYER_GET_CLIP_REGION: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_GET_CLIP_REGION: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + + // if this ViewLayer is hidden, it is clear that its visible region is void. + if (fCurrentLayer->IsHidden()) { + fLink.StartMessage(B_OK); + fLink.Attach(0L); + fLink.Flush(); + } else { + BRegion drawingRegion = fCurrentLayer->LocalClipping(); + int32 rectCount = drawingRegion.CountRects(); + + fLink.StartMessage(B_OK); + fLink.Attach(rectCount); + + for (int32 i = 0; i < rectCount; i++) { + fLink.Attach(drawingRegion.RectAt(i)); + } + + fLink.Flush(); + } + + break; + } + case AS_LAYER_SET_CLIP_REGION: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_SET_CLIP_REGION: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + + int32 rectCount; + link.Read(&rectCount); + + BRegion region; + for (int32 i = 0; i < rectCount; i++) { + BRect r; + link.Read(&r); + region.Include(r); + } + fCurrentLayer->SetUserClipping(region); + break; + } + + case AS_LAYER_INVAL_RECT: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_INVAL_RECT: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + + // NOTE: looks like this call is NOT affected by origin and scale on R5 + // so this implementation is "correct" + BRect invalidRect; + if (link.Read(&invalidRect) == B_OK) { + BRegion dirty(invalidRect); + fWindowLayer->InvalidateView(fCurrentLayer, dirty); + } + break; + } + case AS_LAYER_INVAL_REGION: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_INVAL_RECT: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + + // NOTE: looks like this call is NOT affected by origin and scale on R5 + // so this implementation is "correct" + BRegion dirty; + int32 rectCount; + BRect rect; + + link.Read(&rectCount); + + for (int i = 0; i < rectCount; i++) { + link.Read(&rect); + dirty.Include(rect); + } + + fWindowLayer->InvalidateView(fCurrentLayer, dirty); + break; + } + + case AS_LAYER_SET_HIGH_COLOR: + { + DTRACE(("ServerWindow %s: Message AS_LAYER_SET_HIGH_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + + rgb_color c; + link.Read(&c, sizeof(rgb_color)); fCurrentLayer->CurrentState()->SetHighColor(RGBColor(c)); - break; } case AS_LAYER_SET_LOW_COLOR: { - DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LOW_COLOR: Layer: %s\n", Title(), fCurrentLayer->Name())); + DTRACE(("ServerWindow %s: Message AS_LAYER_SET_LOW_COLOR: ViewLayer: %s\n", Title(), fCurrentLayer->Name())); + rgb_color c; - link.Read(&c, sizeof(rgb_color)); - + fCurrentLayer->CurrentState()->SetLowColor(RGBColor(c)); - break; } case AS_LAYER_SET_PATTERN: { - DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PATTERN: Layer: %s\n", fTitle, fCurrentLayer->Name())); + DTRACE(("ServerWindow %s: Message AS_LAYER_SET_PATTERN: ViewLayer: %s\n", fTitle, fCurrentLayer->Name())); + pattern pat; - link.Read(&pat, sizeof(pattern)); - + fCurrentLayer->CurrentState()->SetPattern(Pattern(pat)); - break; } case AS_MOVEPENTO: { DTRACE(("ServerWindow %s: Message AS_MOVEPENTO\n", Title())); - + float x,y; - link.Read(&x); link.Read(&y); + if (fCurrentLayer && fCurrentLayer->CurrentState()) fCurrentLayer->CurrentState()->SetPenLocation(BPoint(x, y)); - break; } case AS_SETPENSIZE: { DTRACE(("ServerWindow %s: Message AS_SETPENSIZE\n", Title())); + float size; - link.Read(&size); + if (fCurrentLayer && fCurrentLayer->CurrentState()) fCurrentLayer->CurrentState()->SetPenSize(size); - break; } case AS_SET_FONT: @@ -1576,37 +1632,55 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) } case AS_LAYER_DRAG_IMAGE: { - // TODO: Implement AS_LAYER_DRAG_IMAGE - STRACE(("ServerWindow %s: Message AS_DRAG_IMAGE unimplemented\n", Title())); - DTRACE(("ServerWindow %s: Message AS_DRAG_IMAGE unimplemented\n", Title())); + // TODO: flesh out AS_LAYER_DRAG_IMAGE + STRACE(("ServerWindow %s: Message AS_DRAG_IMAGE\n", Title())); + + int32 bitmapToken; + drawing_mode dragMode; + BPoint offset; + int32 bufferSize; + + link.Read(&bitmapToken); + link.Read((int32*)&dragMode); + link.Read(&offset); + link.Read(&bufferSize); + + if (bufferSize > 0) { + char* buffer = new (nothrow) char[bufferSize]; + BMessage dragMessage; + if (link.Read(buffer, bufferSize) == B_OK + && dragMessage.Unflatten(buffer) == B_OK) { +// ServerBitmap* bitmap = fServerApp->FindBitmap(bitmapToken); + fDesktop->EventDispatcher().SetDragMessage(dragMessage/*, bitmap*/); + } + delete[] buffer; + } + break; } case AS_LAYER_DRAG_RECT: { - // TODO: Implement AS_LAYER_DRAG_RECT - STRACE(("ServerWindow %s: Message AS_DRAG_RECT unimplemented\n", Title())); - DTRACE(("ServerWindow %s: Message AS_DRAG_RECT unimplemented\n", Title())); - break; - } - case AS_GET_MOUSE: - { - DTRACE(("ServerWindow %s: Message AS_GET_MOUSE\n", fTitle)); + // TODO: flesh out AS_LAYER_DRAG_RECT + STRACE(("ServerWindow %s: Message AS_DRAG_RECT\n", Title())); - // Returns - // 1) BPoint mouse location - // 2) int32 button state - rootLayer->Unlock(); + BRect dragRect; + BPoint offset; + int32 bufferSize; + + link.Read(&dragRect); + link.Read(&offset); + link.Read(&bufferSize); - BPoint where; - int32 buttons; - fDesktop->EventDispatcher().GetMouse(where, buttons); + if (bufferSize > 0) { + char* buffer = new (nothrow) char[bufferSize]; + BMessage dragMessage; + if (link.Read(buffer, bufferSize) == B_OK + && dragMessage.Unflatten(buffer) == B_OK) { + fDesktop->EventDispatcher().SetDragMessage(dragMessage/*, dragRect*/); + } + delete[] buffer; + } - fLink.StartMessage(B_OK); - fLink.Attach(where); - fLink.Attach(buttons); - fLink.Flush(); - - rootLayer->Lock(); break; } @@ -1615,7 +1689,7 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) // TODO: Use token or get rid of it. int32 serverToken; link.Read(&serverToken); - + if (_EnableDirectWindowMode() == B_OK) { fLink.StartMessage(B_OK); struct dw_sync_data syncData = { @@ -1623,50 +1697,60 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) fDirectWindowData->direct_sem, fDirectWindowData->direct_sem_ack }; - + fLink.Attach(&syncData, sizeof(syncData)); - } else fLink.StartMessage(B_ERROR); - + fLink.Flush(); - break; } - + default: - _DispatchGraphicsMessage(code, link); + if (fDesktop->ReadLockWindows()) { + _DispatchViewDrawingMessage(code, link); + fDesktop->ReadUnlockWindows(); + } break; } - - if (rootLayer) - rootLayer->Unlock(); } -// -------------------- Graphics messages ---------------------------------- +/*! + Dispatches all view drawing messages. + The desktop clipping must be read locked when entering this method. + Requires a valid fCurrentLayer. +*/ void -ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) +ServerWindow::_DispatchViewDrawingMessage(int32 code, BPrivate::LinkReceiver &link) { - // NOTE: fCurrentLayer and fCurrentLayer->fLayerData cannot be NULL, - // _DispatchGraphicsMessage() is called from _DispatchMessage() which - // checks both these conditions - BRegion rreg(fCurrentLayer->DrawingRegion()); - - if (fWindowLayer->InUpdate()) - rreg.IntersectWith(&fWindowLayer->RegionToBeUpdated()); - - DrawingEngine* driver = fWindowLayer->GetDrawingEngine(); - if (!driver) { - // ?!? - DTRACE(("ServerWindow %s: no display driver!!\n", Title())); + if (!fCurrentLayer->IsVisible() || !fWindowLayer->IsVisible()) { + if (link.NeedsReply()) { + printf("ServerWindow::DispatchViewDrawingMessage() got message %ld that needs a reply!\n", code); + // the client is now blocking and waiting for a reply! + fLink.StartMessage(B_ERROR); + fLink.Flush(); + } return; } - driver->ConstrainClippingRegion(&rreg); -// rgb_color rrr = fCurrentLayer->CurrentState()->viewcolor.GetColor32(); -// RGBColor c(rand()%255,rand()%255,rand()%255); -// driver->FillRect(BRect(0,0,639,479), c); + DrawingEngine* drawingEngine = fWindowLayer->GetDrawingEngine(); + if (!drawingEngine) { + // ?!? + DTRACE(("ServerWindow %s: no drawing engine!!\n", Title())); + return; + } + + if (!fCurrentDrawingRegionValid || fWindowLayer->DrawingRegionChanged(fCurrentLayer)) { + fWindowLayer->GetEffectiveDrawingRegion(fCurrentLayer, fCurrentDrawingRegion); + fCurrentDrawingRegionValid = true; + } + + // prevent other ServerWindows from messing with the drawing engine + // as long as each uses the same instance... TODO: remove the locking + // when each has its own + drawingEngine->Lock(); + drawingEngine->ConstrainClippingRegion(&fCurrentDrawingRegion); switch (code) { case AS_STROKE_LINE: @@ -1685,7 +1769,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) BPoint penPos = p2; fCurrentLayer->ConvertToScreenForDrawing(&p1); fCurrentLayer->ConvertToScreenForDrawing(&p2); - driver->StrokeLine(p1, p2, fCurrentLayer->CurrentState()); + drawingEngine->StrokeLine(p1, p2, fCurrentLayer->CurrentState()); // We update the pen here because many DrawingEngine calls which do not update the // pen position actually call StrokeLine @@ -1704,7 +1788,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(&rect); fCurrentLayer->ConvertToScreenForDrawing(&rect); - driver->InvertRect(rect); + drawingEngine->InvertRect(rect); break; } case AS_STROKE_RECT: @@ -1717,27 +1801,26 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(&right); link.Read(&bottom); BRect rect(left,top,right,bottom); - - fCurrentLayer->ConvertToScreenForDrawing(&rect); - driver->StrokeRect(rect, fCurrentLayer->CurrentState()); + fCurrentLayer->ConvertToScreenForDrawing(&rect); + drawingEngine->StrokeRect(rect, fCurrentLayer->CurrentState()); break; } case AS_FILL_RECT: { DTRACE(("ServerWindow %s: Message AS_FILL_RECT\n", Title())); - + BRect rect; link.Read(&rect); fCurrentLayer->ConvertToScreenForDrawing(&rect); - driver->FillRect(rect, fCurrentLayer->CurrentState()); + drawingEngine->FillRect(rect, fCurrentLayer->CurrentState()); break; } case AS_LAYER_DRAW_BITMAP_SYNC_AT_POINT: case AS_LAYER_DRAW_BITMAP_ASYNC_AT_POINT: { - DTRACE(("ServerWindow %s: Message AS_LAYER_DRAW_BITMAP_(A)SYNC_AT_POINT: Layer name: %s\n", fTitle, fCurrentLayer->Name())); + DTRACE(("ServerWindow %s: Message AS_LAYER_DRAW_BITMAP_(A)SYNC_AT_POINT: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); int32 bitmapToken; BPoint point; link.Read(&bitmapToken); @@ -1749,7 +1832,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) BRect dst = src.OffsetToCopy(point); fCurrentLayer->ConvertToScreenForDrawing(&dst); - driver->DrawBitmap(bitmap, src, dst, fCurrentLayer->CurrentState()); + drawingEngine->DrawBitmap(bitmap, src, dst, fCurrentLayer->CurrentState()); } // TODO: how should AS_LAYER_DRAW_BITMAP_SYNC_AT_POINT sync with the client? @@ -1761,7 +1844,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) case AS_LAYER_DRAW_BITMAP_SYNC_IN_RECT: case AS_LAYER_DRAW_BITMAP_ASYNC_IN_RECT: { - DTRACE(("ServerWindow %s: Message AS_LAYER_DRAW_BITMAP_(A)SYNC_IN_RECT: Layer name: %s\n", fTitle, fCurrentLayer->Name())); + DTRACE(("ServerWindow %s: Message AS_LAYER_DRAW_BITMAP_(A)SYNC_IN_RECT: ViewLayer name: %s\n", fTitle, fCurrentLayer->Name())); int32 bitmapToken; BRect srcRect, dstRect; @@ -1773,7 +1856,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) if (bitmap) { fCurrentLayer->ConvertToScreenForDrawing(&dstRect); - driver->DrawBitmap(bitmap, srcRect, dstRect, fCurrentLayer->CurrentState()); + drawingEngine->DrawBitmap(bitmap, srcRect, dstRect, fCurrentLayer->CurrentState()); } // TODO: how should AS_LAYER_DRAW_BITMAP_SYNC_IN_RECT sync with the client? @@ -1783,52 +1866,49 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) case AS_FILL_ARC: { DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ARC\n", Title())); - + float angle, span; BRect r; - + link.Read(&r); link.Read(&angle); link.Read(&span); fCurrentLayer->ConvertToScreenForDrawing(&r); - driver->DrawArc(r, angle, span, fCurrentLayer->CurrentState(), code == AS_FILL_ARC); - + drawingEngine->DrawArc(r, angle, span, fCurrentLayer->CurrentState(), code == AS_FILL_ARC); break; } case AS_STROKE_BEZIER: case AS_FILL_BEZIER: { DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_BEZIER\n", Title())); - + BPoint pts[4]; for (int32 i = 0; i < 4; i++) { link.Read(&(pts[i])); fCurrentLayer->ConvertToScreenForDrawing(&pts[i]); } - - driver->DrawBezier(pts, fCurrentLayer->CurrentState(), code == AS_FILL_BEZIER); + drawingEngine->DrawBezier(pts, fCurrentLayer->CurrentState(), code == AS_FILL_BEZIER); break; } case AS_STROKE_ELLIPSE: case AS_FILL_ELLIPSE: { DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ELLIPSE\n", Title())); - + BRect rect; link.Read(&rect); fCurrentLayer->ConvertToScreenForDrawing(&rect); - driver->DrawEllipse(rect, fCurrentLayer->CurrentState(), code == AS_FILL_ELLIPSE); - + drawingEngine->DrawEllipse(rect, fCurrentLayer->CurrentState(), code == AS_FILL_ELLIPSE); break; } case AS_STROKE_ROUNDRECT: case AS_FILL_ROUNDRECT: { DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_ROUNDRECT\n", Title())); - + BRect rect; float xrad,yrad; link.Read(&rect); @@ -1836,8 +1916,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(&yrad); fCurrentLayer->ConvertToScreenForDrawing(&rect); - driver->DrawRoundRect(rect, xrad, yrad, fCurrentLayer->CurrentState(), code == AS_FILL_ROUNDRECT); - + drawingEngine->DrawRoundRect(rect, xrad, yrad, fCurrentLayer->CurrentState(), code == AS_FILL_ROUNDRECT); break; } case AS_STROKE_TRIANGLE: @@ -1856,8 +1935,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(&rect); fCurrentLayer->ConvertToScreenForDrawing(&rect); - driver->DrawTriangle(pts, rect, fCurrentLayer->CurrentState(), code == AS_FILL_TRIANGLE); - + drawingEngine->DrawTriangle(pts, rect, fCurrentLayer->CurrentState(), code == AS_FILL_TRIANGLE); break; } case AS_STROKE_POLYGON: @@ -1876,28 +1954,25 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) BPoint* pointList = new(nothrow) BPoint[pointCount]; if (link.Read(pointList, pointCount * sizeof(BPoint)) >= B_OK) { - for (int32 i = 0; i < pointCount; i++) fCurrentLayer->ConvertToScreenForDrawing(&pointList[i]); - - driver->DrawPolygon(pointList, pointCount, polyFrame, - fCurrentLayer->CurrentState(), code == AS_FILL_POLYGON, - isClosed && pointCount > 2); - + + drawingEngine->DrawPolygon(pointList, pointCount, polyFrame, + fCurrentLayer->CurrentState(), code == AS_FILL_POLYGON, + isClosed && pointCount > 2); } delete[] pointList; - break; } case AS_STROKE_SHAPE: case AS_FILL_SHAPE: { DTRACE(("ServerWindow %s: Message AS_STROKE/FILL_SHAPE\n", Title())); - + BRect shapeFrame; int32 opCount; int32 ptCount; - + link.Read(&shapeFrame); link.Read(&opCount); link.Read(&ptCount); @@ -1909,20 +1984,19 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) for (int32 i = 0; i < ptCount; i++) fCurrentLayer->ConvertToScreenForDrawing(&ptList[i]); - - driver->DrawShape(shapeFrame, opCount, opList, ptCount, ptList, - fCurrentLayer->CurrentState(), code == AS_FILL_SHAPE); + + drawingEngine->DrawShape(shapeFrame, opCount, opList, ptCount, ptList, + fCurrentLayer->CurrentState(), code == AS_FILL_SHAPE); } delete[] opList; delete[] ptList; - break; } case AS_FILL_REGION: { DTRACE(("ServerWindow %s: Message AS_FILL_REGION\n", Title())); - + int32 count; link.Read(&count); @@ -1941,31 +2015,30 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) } fCurrentLayer->ConvertToScreenForDrawing(®ion); - driver->FillRegion(region, fCurrentLayer->CurrentState()); + drawingEngine->FillRegion(region, fCurrentLayer->CurrentState()); delete[] rects; // TODO: create support for clipping_rect usage for faster BRegion display. - // Tweaks to DrawingEngine are necessary along with conversion routines in Layer + // Tweaks to DrawingEngine are necessary along with conversion routines in ViewLayer break; } case AS_STROKE_LINEARRAY: { DTRACE(("ServerWindow %s: Message AS_STROKE_LINEARRAY\n", Title())); - + // Attached Data: // 1) int32 Number of lines in the array // 2) array of struct _array_data_ objects, as defined in ViewAux.h - - int32 linecount; - - link.Read(&linecount); - if (linecount > 0) { - LineArrayData linedata[linecount]; - LineArrayData* index; - for (int32 i = 0; i < linecount; i++) { - index = &linedata[i]; + int32 lineCount; + + link.Read(&lineCount); + if (lineCount > 0) { + LineArrayData lineData[lineCount]; + + for (int32 i = 0; i < lineCount; i++) { + LineArrayData* index = &lineData[i]; link.Read(&(index->pt1.x)); link.Read(&(index->pt1.y)); @@ -1976,7 +2049,8 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) fCurrentLayer->ConvertToScreenForDrawing(&index->pt1); fCurrentLayer->ConvertToScreenForDrawing(&index->pt2); } - driver->StrokeLineArray(linecount, linedata, fCurrentLayer->CurrentState()); + drawingEngine->StrokeLineArray(lineCount, lineData, + fCurrentLayer->CurrentState()); } break; } @@ -1987,18 +2061,19 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) int32 length; BPoint location; escapement_delta delta; - + link.Read(&length); link.Read(&location); link.Read(&delta); link.ReadString(&string); - + fCurrentLayer->ConvertToScreenForDrawing(&location); - BPoint penLocation = driver->DrawString(string, length, location, - fCurrentLayer->CurrentState(), &delta); + BPoint penLocation = drawingEngine->DrawString(string, length, location, + fCurrentLayer->CurrentState(), &delta); + fCurrentLayer->ConvertFromScreenForDrawing(&penLocation); fCurrentLayer->CurrentState()->SetPenLocation(penLocation); - + free(string); break; } @@ -2024,7 +2099,7 @@ ServerWindow::_DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link) break; } - driver->ConstrainClippingRegion(NULL); + drawingEngine->Unlock(); } @@ -2066,88 +2141,20 @@ ServerWindow::_MessageLooper() printf("ServerWindow %s: lock acquisition took %Ld usecs\n", Title(), diff); #endif - switch (code) { - case AS_DELETE_WINDOW: - case kMsgQuitLooper: - // this means the client has been killed - STRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message code\n", - Title())); + if (code == AS_DELETE_WINDOW || code == kMsgQuitLooper) { + // this means the client has been killed + STRACE(("ServerWindow %s received 'AS_DELETE_WINDOW' message code\n", + Title())); - quitLoop = true; + quitLoop = true; - // ToDo: what's this? - //RootLayer *rootLayer = fWindowLayer->GetRootLayer(); - - // we are preparing to delete a ServerWindow, RootLayer should be aware - // of that and stop for a moment. - // also we must wait a bit for the associated WindowLayer to become hidden - //while(1) { - // rootLayer->Lock(); - // if (IsHidden()) - // break; - // else - // rootLayer->Unlock(); - //} - - // ServerWindow's destructor takes care of pulling this object off the desktop. - if (!fWindowLayer->IsHidden()) - CRITICAL("ServerWindow: a window must be hidden before it's deleted\n"); - break; - - // TODO: these are here temporarily, as they don't lock the root layer - case AS_SHOW_WINDOW: - STRACE(("ServerWindow %s: Message AS_SHOW_WINDOW\n", Title())); - Show(); - break; - - case AS_HIDE_WINDOW: - STRACE(("ServerWindow %s: Message AS_HIDE_WINDOW\n", Title())); - Hide(); - break; - - case AS_ACTIVATE_WINDOW: - { - DTRACE(("ServerWindow %s: Message AS_ACTIVATE_WINDOW: Layer: %s\n", Title(), fCurrentLayer->Name())); - bool activate = true; - - receiver.Read(&activate); - - if (activate) - fDesktop->ActivateWindow(fWindowLayer); - else - fDesktop->SendBehindWindow(fWindowLayer, NULL); - break; - } - case AS_SEND_BEHIND: - { - STRACE(("ServerWindow %s: Message Send_Behind unimplemented\n", Title())); - int32 token; - team_id teamID; - status_t status; - - receiver.Read(&token); - receiver.Read(&teamID); - - WindowLayer *behindOf; - if ((behindOf = fDesktop->FindWindowLayerByClientToken(token, teamID)) != NULL) { - fDesktop->SendBehindWindow(fWindowLayer, behindOf); - status = B_OK; - } else - status = B_NAME_NOT_FOUND; - - fLink.StartMessage(status); - fLink.Flush(); - break; - } - - case B_QUIT_REQUESTED: - STRACE(("ServerWindow %s received quit request\n", Title())); - NotifyQuitRequested(); - break; - - default: - _DispatchMessage(code, receiver); - break; + // ServerWindow's destructor takes care of pulling this object off the desktop. + if (!fWindowLayer->IsHidden()) + CRITICAL("ServerWindow: a window must be hidden before it's deleted\n"); + } else { + fDesktop->ReadLockWindows(); + _DispatchMessage(code, receiver); + fDesktop->ReadUnlockWindows(); } #ifdef PROFILE_MESSAGE_LOOP @@ -2267,10 +2274,12 @@ ServerWindow::HandleDirectConnection(int bufferState, int driverState) // TODO: Is there a simpler way to obtain this result ? // We just want the region INSIDE the window, border excluded. - BRegion clipRegion = const_cast(layer->FullVisible()); + BRegion clipRegion; +// TODO: fix HandleDirectConnection() +/* = const_cast(layer->FullVisible()); BRegion exclude = const_cast(layer->VisibleRegion()); clipRegion.Exclude(&exclude); - +*/ fDirectWindowData->direct_info->clip_list_count = min_c(clipRegion.CountRects(), kMaxClipRectsCount); fDirectWindowData->direct_info->clip_bounds = clipRegion.FrameInt(); @@ -2302,6 +2311,16 @@ ServerWindow::HandleDirectConnection(int bufferState, int driverState) } +void +ServerWindow::_SetCurrentLayer(ViewLayer* layer) +{ + if (fCurrentLayer != layer) { + fCurrentLayer = layer; + fCurrentDrawingRegionValid = false; + } +} + + status_t ServerWindow::PictureToRegion(ServerPicture *picture, BRegion ®ion, bool inverse, BPoint where) diff --git a/src/servers/app/ServerWindow.h b/src/servers/app/ServerWindow.h index 050fd8e129..c957a4a7a5 100644 --- a/src/servers/app/ServerWindow.h +++ b/src/servers/app/ServerWindow.h @@ -38,7 +38,7 @@ class Decorator; class WindowLayer; class Workspace; class RootLayer; -class Layer; +class ViewLayer; class ServerPicture; struct dw_data; struct window_info; @@ -97,7 +97,8 @@ public: // related thread/team_id(s). inline team_id ClientTeam() const { return fClientTeam; } - void HandleDirectConnection(int bufferState = -1, int driverState = -1); + void HandleDirectConnection(int bufferState = -1, + int driverState = -1); inline int32 ClientToken() const { return fClientToken; } inline int32 ServerToken() const { return fServerToken; } @@ -106,19 +107,27 @@ public: private: // methods for retrieving and creating a tree strcture of Layers. - Layer* CreateLayerTree(BPrivate::LinkReceiver &link, Layer **_parent); - void SetLayerState(Layer *layer, BPrivate::LinkReceiver &link); - void SetLayerFontState(Layer *layer, BPrivate::LinkReceiver &link); + ViewLayer* CreateLayerTree(BPrivate::LinkReceiver &link, + ViewLayer **_parent); + void SetLayerState(ViewLayer *layer, + BPrivate::LinkReceiver &link); + void SetLayerFontState(ViewLayer *layer, + BPrivate::LinkReceiver &link); // message handling methods. void _DispatchMessage(int32 code, BPrivate::LinkReceiver &link); - void _DispatchGraphicsMessage(int32 code, BPrivate::LinkReceiver &link); + void _DispatchViewMessage(int32 code, + BPrivate::LinkReceiver &link); + void _DispatchViewDrawingMessage(int32 code, + BPrivate::LinkReceiver &link); void _MessageLooper(); virtual void _PrepareQuit(); virtual void _GetLooperName(char* name, size_t size); status_t _EnableDirectWindowMode(); - + + void _SetCurrentLayer(ViewLayer* view); + // TODO: Move me elsewhere status_t PictureToRegion(ServerPicture *picture, BRegion &, @@ -146,7 +155,9 @@ private: int32 fServerToken; int32 fClientToken; - Layer* fCurrentLayer; + ViewLayer* fCurrentLayer; + BRegion fCurrentDrawingRegion; + bool fCurrentDrawingRegionValid; dw_data* fDirectWindowData; }; diff --git a/src/servers/app/SubWindowList.cpp b/src/servers/app/SubWindowList.cpp deleted file mode 100644 index 72fc3576c3..0000000000 --- a/src/servers/app/SubWindowList.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2001-2005, Haiku. - * Distributed under the terms of the MIT License. - * - * Authors: - * Adrian Oanca - */ - -/** List class for tracking floating and modal windows */ - -#include "SubWindowList.h" -#include "WindowLayer.h" -#include "ServerWindow.h" - -#include - -#include - - -SubWindowList::SubWindowList() -{ -} - - -SubWindowList::~SubWindowList() -{ -} - - -void -SubWindowList::AddWindowLayer(WindowLayer *windowLayer) -{ - if (HasItem(windowLayer)) - return; - - int32 borderFeel = windowLayer->Feel();; - int32 location = 0; - - for (; location < CountItems(); location++) { - int32 feelTemp = ((WindowLayer*)ItemAt(location))->Feel(); - - // in short: if 'windowLayer' is a floating window and 'temp' a modal one - if ((borderFeel == B_FLOATING_SUBSET_WINDOW_FEEL - || borderFeel == B_FLOATING_APP_WINDOW_FEEL - || borderFeel == B_FLOATING_ALL_WINDOW_FEEL) - && (feelTemp == B_MODAL_SUBSET_WINDOW_FEEL - || feelTemp == B_MODAL_APP_WINDOW_FEEL - || feelTemp == B_MODAL_ALL_WINDOW_FEEL)) { - // means we found the place for our window('windowLayer') - break; - } - } - AddItem(windowLayer, location); -} - - -void -SubWindowList::AddSubWindowList(SubWindowList *list) -{ - int32 i = 0; - for (; i < CountItems(); i++) { - int32 feel = ((WindowLayer*)ItemAt(i))->Feel(); - if (feel == B_MODAL_SUBSET_WINDOW_FEEL - || feel == B_MODAL_APP_WINDOW_FEEL - || feel == B_MODAL_ALL_WINDOW_FEEL) - break; - } - - for (int32 j = 0; j < list->CountItems(); j++) { - void *item = list->ItemAt(j); - int32 feel = ((WindowLayer*)item)->Feel(); - if (feel == B_MODAL_SUBSET_WINDOW_FEEL - || feel == B_MODAL_APP_WINDOW_FEEL - || feel == B_MODAL_ALL_WINDOW_FEEL) { - AddItem(item, CountItems()); - } else { - AddItem(item, i); - i++; - } - } -} - - -void -SubWindowList::PrintToStream() const -{ - printf("Floating and modal windows list:\n"); - WindowLayer* windowLayer = NULL; - - for (int32 i=0; iName()); - - if (windowLayer->Feel() == B_FLOATING_SUBSET_WINDOW_FEEL) - printf("\t%s\n", "B_FLOATING_SUBSET_WINDOW_FEEL"); - - if (windowLayer->Feel() == B_FLOATING_APP_WINDOW_FEEL) - printf("\t%s\n", "B_FLOATING_APP_WINDOW_FEEL"); - - if (windowLayer->Feel() == B_FLOATING_ALL_WINDOW_FEEL) - printf("\t%s\n", "B_FLOATING_ALL_WINDOW_FEEL"); - - if (windowLayer->Feel() == B_MODAL_SUBSET_WINDOW_FEEL) - printf("\t%s\n", "B_MODAL_SUBSET_WINDOW_FEEL"); - - if (windowLayer->Feel() == B_MODAL_APP_WINDOW_FEEL) - printf("\t%s\n", "B_MODAL_APP_WINDOW_FEEL"); - - if (windowLayer->Feel() == B_MODAL_ALL_WINDOW_FEEL) - printf("\t%s\n", "B_MODAL_ALL_WINDOW_FEEL"); - - // this should NOT happen - if (windowLayer->Feel() == B_NORMAL_WINDOW_FEEL) - printf("\t%s\n", "B_NORMAL_WINDOW_FEEL"); - } -} diff --git a/src/servers/app/SubWindowList.h b/src/servers/app/SubWindowList.h deleted file mode 100644 index 1f79c3206d..0000000000 --- a/src/servers/app/SubWindowList.h +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2001-2005, Haiku. - * Distributed under the terms of the MIT License. - * - * Authors: - * Adrian Oanca - */ -#ifndef _SUB_WINDOW_LIST_H_ -#define _SUB_WINDOW_LIST_H_ - - -#include -#include - - -class WindowLayer; - -class SubWindowList : public BList { - public: - SubWindowList(); - virtual ~SubWindowList(); - - void AddWindowLayer(WindowLayer *windowLayer); - - // special - void AddSubWindowList(SubWindowList *list); - - // debugging methods - void PrintToStream() const; -}; - -#endif /* _SUB_WINDOW_LIST_H_ */ diff --git a/src/servers/app/ViewLayer.cpp b/src/servers/app/ViewLayer.cpp new file mode 100644 index 0000000000..2f9ee4e219 --- /dev/null +++ b/src/servers/app/ViewLayer.cpp @@ -0,0 +1,1017 @@ +/* + * Copyright (c) 2001-2005, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * DarkWyrm + * Adi Oanca + * Stephan Aßmus + */ + + +#include "ViewLayer.h" + +#include "Desktop.h" +#include "DrawingEngine.h" +#include "ServerApp.h" +#include "ServerWindow.h" +#include "WindowLayer.h" + +#include +#include // for resize modes + +#include + + +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), + + fResizeMode(resizeMode), + fFlags(flags), + + // ViewLayers start visible by default + fHidden(false), + fVisible(true), + + fEventMask(0), + fEventOptions(0), + + fWindow(NULL), + fParent(NULL), + + fFirstChild(NULL), + fPreviousSibling(NULL), + fNextSibling(NULL), + fLastChild(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); +} + +// destructor +ViewLayer::~ViewLayer() +{ + delete fDrawState; + + // 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 + RebuildClipping(false); +} + + +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(©Region, 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(©Region, -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) +{ +printf("ViewLayer(%s)::CopyBits()\n", Name()); + 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(©Region, 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::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, + BRegion* windowContentClipping, bool deep) +{ + // we can only draw within our own area + BRegion redraw(ScreenClipping(windowContentClipping)); + // add the current clipping + redraw.IntersectWith(effectiveClipping); + + if (!fViewColor.IsTransparentMagic()) { + // fill visible region with view color + drawingEngine->FillRegion(redraw, fViewColor); + } + + // let children draw + if (deep) { + // before passing the clipping on to children, exclude our + // own region from the available clipping + effectiveClipping->Exclude(&ScreenClipping(windowContentClipping)); + + 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); +} + +// 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); + } + } +} + diff --git a/src/servers/app/ViewLayer.h b/src/servers/app/ViewLayer.h new file mode 100644 index 0000000000..49c790f313 --- /dev/null +++ b/src/servers/app/ViewLayer.h @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2001-2005, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * DarkWyrm + * Adi Oanca + * Stephan Aßmus + */ +#ifndef VIEW_LAYER_H +#define VIEW_LAYER_H + + +#include "RGBColor.h" + +#include +#include +#include + +class BList; + +class DrawState; +class DrawingEngine; +class WindowLayer; + + +class ViewLayer { + public: + ViewLayer(BRect frame, const char* name, + int32 token, uint32 resizeMode, + uint32 flags); + + virtual ~ViewLayer(); + + void SetName(const char* string); + const char* Name() const + { return fName.String(); } + + int32 Token() const + { return fToken; } + + BRect Frame() const + { return fFrame; } + BRect Bounds() const; + + void SetResizeMode(uint32 resizeMode) + { fResizeMode = resizeMode; } + uint32 Flags() const + { return fFlags; } + void SetFlags(uint32 flags); + + BPoint ScrollingOffset() const; + + void SetDrawingOrigin(BPoint origin); + BPoint DrawingOrigin() const; + + void SetScale(float scale); + float Scale() const; + + void SetUserClipping(const BRegion& region); + // region is expected in layer coordinates + + // converts the given frame up the view hierarchy and + // clips to each views bounds + void ConvertToVisibleInTopView(BRect* bounds) const; + + void AttachedToWindow(WindowLayer* window); + void DetachedFromWindow(); + WindowLayer* Window() const { return fWindow; } + + // tree stuff + void AddChild(ViewLayer* layer); + bool RemoveChild(ViewLayer* layer); + + inline ViewLayer* Parent() const + { return fParent; } + + ViewLayer* FirstChild() const; + ViewLayer* LastChild() const; + ViewLayer* PreviousSibling() const; + ViewLayer* NextSibling() const; + + ViewLayer* TopLayer(); + + uint32 CountChildren(bool deep = false) const; + void CollectTokensForChildren(BList* tokenMap) const; + + ViewLayer* ViewAt(const BPoint& where, + BRegion* windowContentClipping); + + // coordinate conversion + void ConvertToParent(BPoint* point) const; + void ConvertToParent(BRect* rect) const; + void ConvertToParent(BRegion* region) const; + + void ConvertFromParent(BPoint* point) const; + void ConvertFromParent(BRect* rect) const; + void ConvertFromParent(BRegion* region) const; + + void ConvertToScreen(BPoint* point) const; + void ConvertToScreen(BRect* rect) const; + void ConvertToScreen(BRegion* region) const; + + void ConvertFromScreen(BPoint* point) const; + void ConvertFromScreen(BRect* rect) const; + void ConvertFromScreen(BRegion* region) const; + + void ConvertToScreenForDrawing(BPoint* point) const; + void ConvertToScreenForDrawing(BRect* rect) const; + void ConvertToScreenForDrawing(BRegion* region) const; + + void ConvertFromScreenForDrawing(BPoint* point) const; + // used when updating the pen position + + void MoveBy(int32 dx, int32 dy, + BRegion* dirtyRegion); + + void ResizeBy(int32 dx, int32 dy, + BRegion* dirtyRegion); + + void ScrollBy(int32 dx, int32 dy, + BRegion* dirtyRegion); + + void ParentResized(int32 dx, int32 dy, + BRegion* dirtyRegion); + + void CopyBits(BRect src, BRect dst, + BRegion& windowContentClipping); + + const BRegion& LocalClipping() const { return fLocalClipping; } + + const RGBColor& ViewColor() const + { return fViewColor; } + void SetViewColor(const RGBColor& color) + { fViewColor = color; } + + void PushState(); + void PopState(); + DrawState* CurrentState() const { return fDrawState; } + + void SetEventMask(uint32 eventMask, uint32 options); + uint32 EventMask() const + { return fEventMask; } + uint32 EventOptions() const + { return fEventOptions; } + + // for background clearing + virtual void Draw(DrawingEngine* drawingEngine, + BRegion* effectiveClipping, + BRegion* windowContentClipping, + bool deep = false); + + void SetHidden(bool hidden); + bool IsHidden() const; + + // takes into account parent views hidden status + bool IsVisible() const + { return fVisible; } + // update visible status for this view and all children + // according to the parents visibility + void UpdateVisibleDeep(bool parentVisible); + + // clipping + void RebuildClipping(bool deep); + BRegion& ScreenClipping(BRegion* windowContentClipping, + bool force = false) const; + void InvalidateScreenClipping(bool deep); + bool IsScreenClippingValid() const + { return fScreenClippingValid; } + + // debugging + void PrintToStream() const; + + protected: + void _MoveScreenClipping(int32 x, int32 y, + bool deep); + + BString fName; + int32 fToken; + // area within parent coordinate space + BRect fFrame; + // scrolling offset + BPoint fScrollingOffset; + + RGBColor fViewColor; + DrawState* fDrawState; + + uint32 fResizeMode; + uint32 fFlags; + bool fHidden; + bool fVisible; + + uint32 fEventMask; + uint32 fEventOptions; + + WindowLayer* fWindow; + ViewLayer* fParent; + + ViewLayer* fFirstChild; + ViewLayer* fPreviousSibling; + ViewLayer* fNextSibling; + ViewLayer* fLastChild; + + // clipping + BRegion fLocalClipping; + + mutable BRegion fScreenClipping; + mutable bool fScreenClippingValid; + +}; + +#endif // LAYER_H diff --git a/src/servers/app/WindowLayer.cpp b/src/servers/app/WindowLayer.cpp index d12ec1f4fa..d71eef6d61 100644 --- a/src/servers/app/WindowLayer.cpp +++ b/src/servers/app/WindowLayer.cpp @@ -9,86 +9,116 @@ */ -#include -#include -#include -#include -#include // for mouse button defines +#include "WindowLayer.h" -#include -#include #include "DebugInfoManager.h" - #include "Decorator.h" #include "DecorManager.h" #include "Desktop.h" +#include "DrawingEngine.h" #include "MessagePrivate.h" #include "PortLink.h" -#include "RootLayer.h" #include "ServerApp.h" #include "ServerWindow.h" -#include "WindowLayer.h" #include "Workspace.h" +#include + +#include +#include +#include // for mouse button defines + +#include +#include + // Toggle debug output -//#define DEBUG_WINBORDER -//#define DEBUG_WINBORDER_CLICK +//#define DEBUG_WINDOW_LAYER +//#define DEBUG_WINDOW_LAYER_CLICK -#ifdef DEBUG_WINBORDER -# include +#ifdef DEBUG_WINDOW_LAYER # define STRACE(x) printf x #else # define STRACE(x) ; #endif -#ifdef DEBUG_WINBORDER_CLICK -# include +#ifdef DEBUG_WINDOW_LAYER_CLICK # define STRACE_CLICK(x) printf x #else # define STRACE_CLICK(x) ; #endif +// if the background clearing is delayed until +// the client draws the view, we have less flickering +// when contents have to be redrawn because of resizing +// a window or because the client invalidates parts. +// when redrawing something that has been exposed from underneath +// other windows, the other window will be seen longer at +// its previous position though if the exposed parts are not +// cleared right away. maybe there ought to be a flag in +// the update session, which tells us the cause of the update +#define DELAYED_BACKGROUND_CLEARING 0 -WindowLayer::WindowLayer(const BRect &frame, - const char *name, window_look look, window_feel feel, - uint32 flags, uint32 workspaces, - ServerWindow *window, DrawingEngine *driver) - : Layer(frame, name, B_NULL_TOKEN, B_FOLLOW_NONE, 0UL, driver), - fDecorator(NULL), - fTopLayer(NULL), +// IMPORTANT: nested ReadLockWindows()s are not supported (by MultiLocker) - fCumulativeRegion(), - fInUpdateRegion(), +using std::nothrow; - fDecRegion(), - fRebuildDecRegion(true), +// constructor +WindowLayer::WindowLayer(const BRect& frame, const char *name, + window_look look, window_feel feel, + uint32 flags, uint32 workspaces, + ::ServerWindow* window, + DrawingEngine* drawingEngine) + : + fTitle(name), + fFrame(frame), - fMouseButtons(0), - fLastMousePosition(-1.0, -1.0), + fVisibleRegion(), + fVisibleContentRegion(), + fVisibleContentRegionValid(false), + fDirtyRegion(), - fIsFocus(false), + fBorderRegion(), + fBorderRegionValid(false), + fContentRegion(), + fContentRegionValid(false), + fEffectiveDrawingRegion(), + fEffectiveDrawingRegionValid(false), - fIsClosing(false), - fIsMinimizing(false), - fIsZooming(false), - fIsResizing(false), - fIsSlidingTab(false), - fIsDragging(false), + fIsClosing(false), + fIsMinimizing(false), + fIsZooming(false), + fIsResizing(false), + fIsSlidingTab(false), + fIsDragging(false), - fUpdateRequestsEnabled(true), - fInUpdate(false), - fRequestSent(false), + fDecorator(NULL), + fTopLayer(NULL), + fWindow(window), + fDrawingEngine(drawingEngine), + fDesktop(window->Desktop()), - fLook(look), - fFeel(feel), - fWindowFlags(flags), - fWorkspaces(workspaces), + fCurrentUpdateSession(), + fPendingUpdateSession(), + fUpdateRequested(false), + fInUpdate(false), - fMinWidth(1.0), - fMaxWidth(32768.0), - fMinHeight(1.0), - fMaxHeight(32768.0) + // windows start hidden + fHidden(true), + fIsFocus(false), + + fLook(look), + fFeel(feel), + fFlags(flags), + fWorkspaces(workspaces), + fCurrentWorkspace(-1), + + fMinWidth(1), + fMaxWidth(32768), + fMinHeight(1), + fMaxHeight(32768), + + fReadLocked(false) { // make sure our arguments are valid if (!IsValidLook(fLook)) @@ -97,14 +127,8 @@ WindowLayer::WindowLayer(const BRect &frame, fFeel = B_NORMAL_WINDOW_FEEL; fFlags &= ValidWindowFlags(); - // unlike BViews, windows start off as hidden - fHidden = true; - fWindow = window; - fFlags = B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE; - if (fLook != B_NO_BORDER_WINDOW_LOOK) { - fDecorator = gDecorManager.AllocateDecorator(window->Desktop(), frame, - name, fLook, fWindowFlags); + fDecorator = gDecorManager.AllocateDecorator(fDesktop, frame, name, fLook, fFlags); if (fDecorator) fDecorator->GetSizeLimits(&fMinWidth, &fMinHeight, &fMaxWidth, &fMaxHeight); } @@ -118,11 +142,11 @@ WindowLayer::WindowLayer(const BRect &frame, uint16 width, height; uint32 colorSpace; float frequency; - if (window->Desktop()->ScreenAt(0)) { - window->Desktop()->ScreenAt(0)->GetMode(width, height, colorSpace, frequency); + if (fDesktop->ScreenAt(0)) { + fDesktop->ScreenAt(0)->GetMode(width, height, colorSpace, frequency); // TODO: MOVE THIS AWAY!!! RemoveBy contains calls to virtual methods! Also, there is not TopLayer()! fFrame.OffsetTo(B_ORIGIN); - WindowLayer::ResizeBy(width - frame.Width(), height - frame.Height()); +// ResizeBy(width - frame.Width(), height - frame.Height(), NULL); } } @@ -132,88 +156,276 @@ WindowLayer::WindowLayer(const BRect &frame, STRACE(("\tWindow %s\n", window ? window->Title() : "NULL")); } - +// destructor WindowLayer::~WindowLayer() { - STRACE(("WindowLayer(%s)::~WindowLayer()\n", Name())); - + delete fTopLayer; delete fDecorator; } - - -//! redraws a certain section of the window border +/* +// MessageReceived void -WindowLayer::Draw(const BRect& updateRect) +WindowLayer::MessageReceived(BMessage* message) { - #ifdef DEBUG_WINBORDER - printf("WindowLayer(%s)::Draw() : ", Name()); - r.PrintToStream(); - #endif - - // if we have a visible region, it is decorator's one. - if (fDecorator) { - fDecorator->SetFocus(IsFocus()); - fDecorator->Draw(updateRect); + switch (message->what) { + case MSG_REDRAW: { + // there is only one MSG_REDRAW in the queue at anytime + if (fDesktop->ReadLockWindows()) { + + _DrawBorder(); + _TriggerContentRedraw(); + + // reset the dirty region, since + // we're fully clean. If the desktop + // thread wanted to mark something + // dirty in the mean time, it was + // blocking on the global region lock to + // get write access, since we held the + // read lock for the whole time. + fDirtyRegion.MakeEmpty(); + + fDesktop->ReadUnlockWindows(); + } else { +//printf("%s MSG_REDRAW -> pending redraws\n", Name()); + } + break; + } + case MSG_BEGIN_UPDATE: + _BeginUpdate(); + break; + case MSG_END_UPDATE: + _EndUpdate(); + break; + case MSG_DRAWING_COMMAND: { + int32 token; + if (message->FindInt32("token", &token) >= B_OK) + _DrawClient(token); + break; + } + case MSG_DRAW_POLYGON: { + int32 token; + BPoint polygon[4]; + if (message->FindInt32("token", &token) >= B_OK && + message->FindPoint("point", 0, &polygon[0]) >= B_OK && + message->FindPoint("point", 1, &polygon[1]) >= B_OK && + message->FindPoint("point", 2, &polygon[2]) >= B_OK && + message->FindPoint("point", 3, &polygon[3]) >= B_OK) { + + _DrawClientPolygon(token, polygon); + } + break; + + } + + case MSG_INVALIDATE_VIEW: { + int32 token; + if (message->FindInt32("token", &token) >= B_OK) + InvalidateView(token); + break; + } + + case MSG_SHOW: + if (IsHidden()) { + fDesktop->ShowWindow(this); + } + break; + default: + BLooper::MessageReceived(message); + break; } } - -//! Moves the winborder with redraw -void -WindowLayer::MoveBy(float x, float y) +// QuitRequested +bool +WindowLayer::QuitRequested() { - if (x == 0.0f && y == 0.0f) + if (fDesktop && fDesktop->WriteLockWindows()) { + fDesktop->WindowDied(this); + + fClient->Lock(); + fClient->Quit(); + + fDesktop->WriteUnlockWindows(); + } + return true; +} +*/ + +// ReadLockWindows +bool +WindowLayer::ReadLockWindows() +{ + if (fDesktop) + fReadLocked = fDesktop->ReadLockWindows(); + else + fReadLocked = true; + + return fReadLocked; +} + +// ReadUnlockWindows +void +WindowLayer::ReadUnlockWindows() +{ + if (fReadLocked) { + if (fDesktop) + fDesktop->ReadUnlockWindows(); + fReadLocked = false; + } +} + +// SetClipping +void +WindowLayer::SetClipping(BRegion* stillAvailableOnScreen) +{ + // this function is only called from the Desktop thread + + // start from full region (as if the window was fully visible) + GetFullRegion(&fVisibleRegion); + // clip to region still available on screen + fVisibleRegion.IntersectWith(stillAvailableOnScreen); + + fVisibleContentRegionValid = false; + fEffectiveDrawingRegionValid = false; + + // TODO: Window()->HandleDirectConnection(B_DIRECT_STOP); +} + +// GetFullRegion +void +WindowLayer::GetFullRegion(BRegion* region) +{ + // TODO: if someone needs to call this from + // the outside, the clipping needs to be readlocked! + + GetBorderRegion(region); + + // start from the frame, extend to include decorator border + region->Include(fFrame); + +} + +// GetBorderRegion +void +WindowLayer::GetBorderRegion(BRegion* region) +{ + // TODO: if someone needs to call this from + // the outside, the clipping needs to be readlocked! + + if (!fBorderRegionValid) { + // TODO: checkup Decorator::GetFootPrint() to see if it is as fast as this: +/* fBorderRegion.Set(BRect(fFrame.left - 4, fFrame.top - 20, + (fFrame.left + fFrame.right) / 2, fFrame.top - 5)); + fBorderRegion.Include(BRect(fFrame.left - 4, fFrame.top - 4, + fFrame.right + 4, fFrame.top - 1)); + fBorderRegion.Include(BRect(fFrame.left - 4, fFrame.top, + fFrame.left - 1, fFrame.bottom)); + fBorderRegion.Include(BRect(fFrame.right + 1, fFrame.top, + fFrame.right + 4, fFrame.bottom - 11)); + fBorderRegion.Include(BRect(fFrame.left - 4, fFrame.bottom + 1, + fFrame.right - 11, fFrame.bottom + 4)); + fBorderRegion.Include(BRect(fFrame.right - 10, fFrame.bottom - 10, + fFrame.right + 4, fFrame.bottom + 4));*/ + + // TODO: remove and use Decorator::GetFootPrint() + // start from the frame, extend to include decorator border + if (fDecorator) { + fDecorator->GetFootprint(&fBorderRegion); + } + fBorderRegionValid = true; + } + + *region = fBorderRegion; +} + + +void +WindowLayer::GetContentRegion(BRegion* region) +{ + // TODO: if someone needs to call this from + // the outside, the clipping needs to be readlocked! + + if (!fContentRegionValid) { + _UpdateContentRegion(); + } + + *region = fContentRegion; +} + + +BRegion& +WindowLayer::VisibleContentRegion() +{ + // TODO: if someone needs to call this from + // the outside, the clipping needs to be readlocked! + + // regions expected to be locked + if (!fVisibleContentRegionValid) { + GetContentRegion(&fVisibleContentRegion); + fVisibleContentRegion.IntersectWith(&fVisibleRegion); + } + return fVisibleContentRegion; +} + + +// #pragma mark - + + +void +WindowLayer::MoveBy(int32 x, int32 y) +{ + // this function is only called from the desktop thread + + if ((x == 0 && y == 0) || !ReadLockWindows()) return; - // lock here because we play with some regions - if (GetRootLayer()) { - // TODO: MoveBy and ResizeBy() are usually called - // from the rootlayer's thread. HandleDirectConnection() could - // block the calling thread for ~3 seconds in the worst case, - // and while it would be acceptable if called from the - // ServerWindow's thread (only the window would be blocked), in this case - // it's not, as also the mouse movement is driven by rootlayer. - // Find some way to call DirectConnected() from the ServerWindow's thread, - // by sending a message from here or whatever. - // (Tested with BeSnes9x and works fine, though) - Window()->HandleDirectConnection(B_DIRECT_STOP); - - if (GetRootLayer()->Lock()) { - fDecRegion.OffsetBy(x, y); + fWindow->HandleDirectConnection(B_DIRECT_STOP); - fCumulativeRegion.OffsetBy(x, y); - fInUpdateRegion.OffsetBy(x, y); + fFrame.OffsetBy(x, y); - if (fDecorator) - fDecorator->MoveBy(x, y); + fWindow->HandleDirectConnection(B_DIRECT_START | B_BUFFER_MOVED); - Layer::MoveBy(x, y); + // take along the dirty region which have not + // processed yet + fDirtyRegion.OffsetBy(x, y); - GetRootLayer()->Unlock(); - } + if (fBorderRegionValid) + fBorderRegion.OffsetBy(x, y); + if (fContentRegionValid) + fContentRegion.OffsetBy(x, y); - Window()->HandleDirectConnection(B_DIRECT_START | B_BUFFER_MOVED); - } else { - // just offset to the new position - if (fDecorator) - fDecorator->MoveBy(x, y); + if (fCurrentUpdateSession.IsUsed()) + fCurrentUpdateSession.MoveBy(x, y); + if (fPendingUpdateSession.IsUsed()) + fPendingUpdateSession.MoveBy(x, y); - Layer::MoveBy(x, y); - } + fEffectiveDrawingRegionValid = false; + + if (fDecorator) + fDecorator->MoveBy(x, y); + + if (fTopLayer != NULL) + fTopLayer->MoveBy(x, y, NULL); + + // the desktop will take care of dirty regions // dispatch a message to the client informing about the changed size BMessage msg(B_WINDOW_MOVED); - msg.AddInt64("when", system_time()); - msg.AddPoint("where", Frame().LeftTop()); - Window()->SendMessageToClient(&msg); + msg.AddInt64("when", system_time()); + msg.AddPoint("where", fFrame.LeftTop()); + fWindow->SendMessageToClient(&msg); + + ReadUnlockWindows(); } void -WindowLayer::ResizeBy(float x, float y) +WindowLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion) { - float wantWidth = fFrame.Width() + x; - float wantHeight = fFrame.Height() + y; + // this function is only called from the desktop thread + + int32 wantWidth = fFrame.IntegerWidth() + x; + int32 wantHeight = fFrame.IntegerHeight() + y; // enforce size limits if (wantWidth < fMinWidth) @@ -226,180 +438,359 @@ WindowLayer::ResizeBy(float x, float y) if (wantHeight > fMaxHeight) wantHeight = fMaxHeight; - x = wantWidth - fFrame.Width(); - y = wantHeight - fFrame.Height(); + x = wantWidth - fFrame.IntegerWidth(); + y = wantHeight - fFrame.IntegerHeight(); - if (x == 0.0 && y == 0.0) + if ((x == 0 && y == 0) || !ReadLockWindows()) return; - // this method can be called from a ServerWindow thread or from a RootLayer one, - // so lock - if (GetRootLayer()) { - Window()->HandleDirectConnection(B_DIRECT_STOP); - - if (GetRootLayer()->Lock()) { - fRebuildDecRegion = true; + fWindow->HandleDirectConnection(B_DIRECT_STOP); - if (fDecorator) - fDecorator->ResizeBy(x, y); + fFrame.right += x; + fFrame.bottom += y; - Layer::ResizeBy(x, y); + fWindow->HandleDirectConnection(B_DIRECT_START | B_BUFFER_RESIZED); - GetRootLayer()->Unlock(); - } + // put the previous border region into the dirty region as well + // to handle the part that was overlapping a layer + if (dirtyRegion) + dirtyRegion->Include(&fBorderRegion); - Window()->HandleDirectConnection(B_DIRECT_START | B_BUFFER_RESIZED); - } else { - if (fDecorator) - fDecorator->ResizeBy(x, y); + fBorderRegionValid = false; + fContentRegionValid = false; + fEffectiveDrawingRegionValid = false; - Layer::ResizeBy(x, y); + if (fDecorator) + fDecorator->ResizeBy(x, y); + + // the border is dirty, put it into + // dirtyRegion for a start + BRegion newBorderRegion; + GetBorderRegion(&newBorderRegion); + if (dirtyRegion) { + dirtyRegion->Include(&newBorderRegion); } + if (fTopLayer != NULL) + fTopLayer->ResizeBy(x, y, dirtyRegion); + // send a message to the client informing about the changed size BRect frame(Frame()); BMessage msg(B_WINDOW_RESIZED); msg.AddInt64("when", system_time()); msg.AddInt32("width", frame.IntegerWidth()); msg.AddInt32("height", frame.IntegerHeight()); - Window()->SendMessageToClient(&msg); + fWindow->SendMessageToClient(&msg); + + ReadUnlockWindows(); } void -WindowLayer::SetName(const char* name) +WindowLayer::ScrollViewBy(ViewLayer* view, int32 dx, int32 dy) { - Layer::SetName(name); + // this can be executed from any thread, but if the + // desktop thread is executing this, it should have + // the write lock, otherwise it is not prevented + // from executing this at the same time as the window + // is doing something else here! - // rebuild the clipping for the title area - // and redraw it. + if (!view || view == fTopLayer || (dx == 0 && dy == 0)) + return; - if (fDecorator) { - BRegion updateRegion; - fDecorator->SetTitle(name, &updateRegion); + if (fDesktop && fDesktop->ReadLockWindows()) { + BRegion dirty; + view->ScrollBy(dx, dy, &dirty); - fRebuildDecRegion = true; - GetRootLayer()->MarkForRebuild(updateRegion); - GetRootLayer()->TriggerRebuild(); + _MarkContentDirty(&dirty); - GetRootLayer()->MarkForRedraw(updateRegion); - GetRootLayer()->TriggerRedraw(); + fDesktop->ReadUnlockWindows(); + } +} + + +//! Takes care of invalidating parts that could not be copied +void +WindowLayer::CopyContents(BRegion* region, int32 xOffset, int32 yOffset) +{ + if (!fHidden && fDesktop && fDesktop->ReadLockWindows()) { + BRegion newDirty(*region); + + // clip the region to the visible contents at the + // source and destination location (not that VisibleContentRegion() + // is used once to make sure it is valid, then fVisibleContentRegion + // is used directly) + region->IntersectWith(&VisibleContentRegion()); + if (region->CountRects() > 0) { + region->OffsetBy(xOffset, yOffset); + region->IntersectWith(&fVisibleContentRegion); + if (region->CountRects() > 0) { + // if the region still contains any rects + // offset to source location again + region->OffsetBy(-xOffset, -yOffset); + // the part which we can copy is not dirty + newDirty.Exclude(region); + + if (fDrawingEngine->Lock()) { + fDrawingEngine->CopyRegion(region, xOffset, yOffset); + fDrawingEngine->Unlock(); + } + + // move along the already dirty regions that are common + // with the region that we could copy + _ShiftPartOfRegion(&fDirtyRegion, region, xOffset, yOffset); + if (fCurrentUpdateSession.IsUsed()) + _ShiftPartOfRegion(&fCurrentUpdateSession.DirtyRegion(), region, xOffset, yOffset); + if (fPendingUpdateSession.IsUsed()) + _ShiftPartOfRegion(&fPendingUpdateSession.DirtyRegion(), region, xOffset, yOffset); + + } + } + // what is left visible from the original region + // at the destination after the region which could be + // copied has been excluded, is considered dirty + // NOTE: it may look like dirty regions are not moved + // if no region could be copied, but that's alright, + // since these parts will now be in newDirty anyways + // (with the right offset) + newDirty.OffsetBy(xOffset, yOffset); + newDirty.IntersectWith(&fVisibleContentRegion); + if (newDirty.CountRects() > 0) + ProcessDirtyRegion(newDirty); + + fDesktop->ReadUnlockWindows(); + } +} + + +// #pragma mark - + + +void +WindowLayer::SetTopLayer(ViewLayer* topLayer) +{ + // the top layer is special, it has a coordinate system + // as if it was attached directly to the desktop, therefor, + // the coordinate conversion through the layer tree works + // as expected, since the top layer has no "parent" but has + // fFrame as if it had + + fTopLayer = topLayer; + + // make sure the location of the top layer on screen matches ours + fTopLayer->MoveBy(fFrame.left - fTopLayer->Frame().left, + fFrame.top - fTopLayer->Frame().top, NULL); + + // make sure the size of the top layer matches ours + fTopLayer->ResizeBy(fFrame.Width() - fTopLayer->Frame().Width(), + fFrame.Height() - fTopLayer->Frame().Height(), NULL); + + fTopLayer->AttachedToWindow(this); +} + + +ViewLayer* +WindowLayer::ViewAt(const BPoint& where) +{ + ViewLayer* view = NULL; + + if (ReadLockWindows()) { + if (!fContentRegionValid) + _UpdateContentRegion(); + + view = fTopLayer->ViewAt(where, &fContentRegion); + + ReadUnlockWindows(); + } + return view; +} + + +window_anchor& +WindowLayer::Anchor(int32 index) +{ + return fAnchor[index]; +} + + +WindowLayer* +WindowLayer::NextWindow(int32 index) +{ + return fAnchor[index].next; +} + + +WindowLayer* +WindowLayer::PreviousWindow(int32 index) +{ + return fAnchor[index].previous; +} + + +// #pragma mark - + + +void +WindowLayer::GetEffectiveDrawingRegion(ViewLayer* layer, BRegion& region) +{ + if (!fEffectiveDrawingRegionValid) { + fEffectiveDrawingRegion = VisibleContentRegion(); + if (fInUpdate) { + // enforce the dirty region of the update session + fEffectiveDrawingRegion.IntersectWith(&fCurrentUpdateSession.DirtyRegion()); + } else { + // not in update, the view can draw everywhere + } + + fEffectiveDrawingRegionValid = true; + } + + // TODO: this is a region that needs to be cached later in the server + // when the current layer in ServerWindow is set, and we are currently + // in an update (fInUpdate), than we can set this region and remember + // it for the comming drawing commands until the current layer changes + // again or fEffectiveDrawingRegionValid is suddenly false. + region = fEffectiveDrawingRegion; + if (!fContentRegionValid) + _UpdateContentRegion(); + + region.IntersectWith(&layer->ScreenClipping(&fContentRegion)); +} + +bool +WindowLayer::DrawingRegionChanged(ViewLayer* layer) const +{ + return !fEffectiveDrawingRegionValid || !layer->IsScreenClippingValid(); +} + + +void +WindowLayer::ProcessDirtyRegion(BRegion& region) +{ + // if this is exectuted in the desktop thread, + // it means that the window thread currently + // blocks to get the read lock, if it is + // executed from the window thread, it should + // have the read lock and the desktop thread + // is blocking to get the write lock. IAW, this + // is only executed in one thread. + if (fDirtyRegion.CountRects() == 0) { + // the window needs to be informed + // when the dirty region was empty. + // NOTE: when the window thread has processed + // the dirty region in MessageReceived(), + // it will make the region empty again, + // when it is empty here, we need to send + // the message to initiate the next update round. + // Until the message is processed in the window + // thread, the desktop thread can add parts to + // the region as it likes. + ServerWindow()->PostMessage(AS_REDRAW); + } + + // this is executed from the desktop thread + fDirtyRegion.Include(®ion); +} + + +void +WindowLayer::RedrawDirtyRegion() +{ + if (!fDesktop || !fDesktop->ReadLockWindows()) + return; + + if (IsVisible()) { + _DrawBorder(); + _TriggerContentRedraw(); + } + + // reset the dirty region, since + // we're fully clean. If the desktop + // thread wanted to mark something + // dirty in the mean time, it was + // blocking on the global region lock to + // get write access, since we held the + // read lock for the whole time. + fDirtyRegion.MakeEmpty(); + + fDesktop->ReadUnlockWindows(); +} + + +void +WindowLayer::MarkDirty(BRegion& regionOnScreen) +{ + // for marking any part of the desktop dirty + // this will get write access to the global + // region lock, and result in ProcessDirtyRegion() + // to be called for any windows affected + if (fDesktop) + fDesktop->MarkDirty(regionOnScreen); +} + + +void +WindowLayer::MarkContentDirty(BRegion& regionOnScreen) +{ + // for triggering AS_REDRAW + // since this won't affect other windows, read locking + // is sufficient. If there was no dirty region before, + // an update message is triggered + if (!fHidden && fDesktop && fDesktop->ReadLockWindows()) { + regionOnScreen.IntersectWith(&VisibleContentRegion()); + ProcessDirtyRegion(regionOnScreen); + + fDesktop->ReadUnlockWindows(); } } void -WindowLayer::UpdateStart() +WindowLayer::InvalidateView(ViewLayer* layer, BRegion& layerRegion) { - // During updates we only want to draw what's in the update region - fInUpdate = true; - fRequestSent = false; -} + if (layer && !fHidden && fDesktop && fDesktop->ReadLockWindows()) { + if (!layer->IsVisible()) { + fDesktop->ReadUnlockWindows(); + return; + } + if (!fContentRegionValid) + _UpdateContentRegion(); + layer->ConvertToScreen(&layerRegion); + layerRegion.IntersectWith(&layer->ScreenClipping(&fContentRegion)); + // TODO: would be nice if this didn't fire off a REDRAW message, + // but currently, it is cleaner to do it, so that backgrounds are + // properly cleared in _TriggerContentRedraw() + MarkContentDirty(layerRegion); -void -WindowLayer::UpdateEnd() -{ - // The usual case. Drawing is permitted in the whole visible area. - - fInUpdate = false; - - fInUpdateRegion.MakeEmpty(); - - if (fCumulativeRegion.CountRects() > 0) { - GetRootLayer()->MarkForRedraw(fCumulativeRegion); - GetRootLayer()->TriggerRedraw(); + fDesktop->ReadUnlockWindows(); } } - +// EnableUpdateRequests void WindowLayer::EnableUpdateRequests() { - fUpdateRequestsEnabled = true; - if (fCumulativeRegion.CountRects() > 0) { +// fUpdateRequestsEnabled = true; +/* if (fCumulativeRegion.CountRects() > 0) { GetRootLayer()->MarkForRedraw(fCumulativeRegion); GetRootLayer()->TriggerRedraw(); - } + }*/ } -//! Sets the minimum and maximum sizes of the window -void -WindowLayer::SetSizeLimits(float minWidth, float maxWidth, - float minHeight, float maxHeight) -{ - if (minWidth < 0) - minWidth = 0; - - if (minHeight < 0) - minHeight = 0; - - fMinWidth = minWidth; - fMaxWidth = maxWidth; - fMinHeight = minHeight; - fMaxHeight = maxHeight; - - // give the Decorator a say in this too - if (fDecorator) - fDecorator->GetSizeLimits(&fMinWidth, &fMinHeight, - &fMaxWidth, &fMaxHeight); - - if (fMaxWidth < fMinWidth) - fMaxWidth = fMinWidth; - - if (fMaxHeight < fMinHeight) - fMaxHeight = fMinHeight; - - // Automatically resize the window to fit these new limits - // if it does not already. - - // On R5, Windows don't automatically resize, but since - // BWindow::ResizeTo() even honors the limits, I would guess - // this is a bug that we don't have to adopt. - // Note that most current apps will do unnecessary resizing - // after having set the limits, but the overhead is neglible. - - float minWidthDiff = fMinWidth - fFrame.Width(); - float minHeightDiff = fMinHeight - fFrame.Height(); - float maxWidthDiff = fMaxWidth - fFrame.Width(); - float maxHeightDiff = fMaxHeight - fFrame.Height(); - - float xDiff = 0.0; - if (minWidthDiff > 0.0) // we're currently smaller than minWidth - xDiff = minWidthDiff; - else if (maxWidthDiff < 0.0) // we're currently larger than maxWidth - xDiff = maxWidthDiff; - - float yDiff = 0.0; - if (minHeightDiff > 0.0) // we're currently smaller than minHeight - yDiff = minHeightDiff; - else if (maxHeightDiff < 0.0) // we're currently larger than maxHeight - yDiff = maxHeightDiff; - - ResizeBy(xDiff, yDiff); -} +// #pragma mark - void -WindowLayer::GetSizeLimits(float* minWidth, float* maxWidth, - float* minHeight, float* maxHeight) const +WindowLayer::MouseDown(BMessage* msg, BPoint where, int32* _viewToken) { - *minWidth = fMinWidth; - *maxWidth = fMaxWidth; - *minHeight = fMinHeight; - *maxHeight = fMaxHeight; -} - - -void -WindowLayer::MouseDown(BMessage *msg, BPoint where, int32* _viewToken) -{ - Desktop* desktop = Window()->App()->GetDesktop(); + // TODO: move into Decorator + if (!fBorderRegionValid) + GetBorderRegion(&fBorderRegion); // default action is to drag the WindowLayer - Layer *target = LayerAt(where); - if (target == this) { + if (fBorderRegion.Contains(where)) { // clicking WindowLayer visible area click_type action = DEC_DRAG; @@ -456,31 +847,39 @@ WindowLayer::MouseDown(BMessage *msg, BPoint where, int32* _viewToken) // based on what the Decorator returned, properly place this window. if (action == DEC_MOVETOBACK) { - desktop->SendBehindWindow(this, NULL); + fDesktop->SendWindowBehind(this); } else { - GetRootLayer()->SetMouseEventWindow(this); - desktop->ActivateWindow(this); + fDesktop->SetMouseEventWindow(this); + fDesktop->ActivateWindow(this); } - } else if (target != NULL) { - // clicking a simple Layer. - if (!IsFocus()) { - DesktopSettings desktopSettings(desktop); + } else { + if (ViewLayer* view = ViewAt(where)) { +//printf("clicked: %s\n", view->Name()); +//view->PrintToStream(); + // clicking a simple ViewLayer + if (!IsFocus()) { + DesktopSettings desktopSettings(fDesktop); - // not in FFM mode? - if (desktopSettings.MouseMode() == B_NORMAL_MOUSE) - desktop->ActivateWindow(this); + // not in FFM mode? + if (desktopSettings.MouseMode() == B_NORMAL_MOUSE) + fDesktop->ActivateWindow(this); - if ((WindowFlags() & (B_WILL_ACCEPT_FIRST_CLICK | B_AVOID_FOCUS)) == 0) - return; + // eat the click if we don't accept first click + if ((Flags() & (B_WILL_ACCEPT_FIRST_CLICK | B_AVOID_FOCUS)) != 0) + *_viewToken = view->Token(); + } else { + // always fill out view token if we already have focus + *_viewToken = view->Token(); + } + } else { +//printf("clicked: nowhere\n"); } - - target->MouseDown(msg, where, _viewToken); } } void -WindowLayer::MouseUp(BMessage *msg, BPoint where, int32* _viewToken) +WindowLayer::MouseUp(BMessage* msg, BPoint where, int32* _viewToken) { bool invalidate = false; if (fDecorator) { @@ -495,7 +894,7 @@ WindowLayer::MouseUp(BMessage *msg, BPoint where, int32* _viewToken) fDecorator->SetZoom(false); if (action == DEC_ZOOM) { invalidate = true; - Window()->NotifyZoom(); + fWindow->NotifyZoom(); } } if (fIsClosing) { @@ -503,7 +902,7 @@ WindowLayer::MouseUp(BMessage *msg, BPoint where, int32* _viewToken) fDecorator->SetClose(false); if (action == DEC_CLOSE) { invalidate = true; - Window()->NotifyQuitRequested(); + fWindow->NotifyQuitRequested(); } } if (fIsMinimizing) { @@ -511,7 +910,7 @@ WindowLayer::MouseUp(BMessage *msg, BPoint where, int32* _viewToken) fDecorator->SetMinimize(false); if (action == DEC_MINIMIZE) { invalidate = true; - Window()->NotifyMinimize(true); + fWindow->NotifyMinimize(true); } } } @@ -519,9 +918,8 @@ WindowLayer::MouseUp(BMessage *msg, BPoint where, int32* _viewToken) fIsResizing = false; fIsSlidingTab = false; - Layer* target = LayerAt(where); - if (target != NULL && target != this) - target->MouseUp(msg, where, _viewToken); + if (ViewLayer* view = ViewAt(where)) + *_viewToken = view->Token(); } @@ -545,16 +943,16 @@ WindowLayer::MouseMoved(BMessage *msg, BPoint where, int32* _viewToken) if (fIsDragging) { BPoint delta = where - fLastMousePosition; - Window()->Desktop()->MoveWindowBy(this, delta.x, delta.y); + fDesktop->MoveWindowBy(this, delta.x, delta.y); } if (fIsResizing) { BPoint delta = where - fLastMousePosition; - if (WindowFlags() & B_NOT_V_RESIZABLE) + if (Flags() & B_NOT_V_RESIZABLE) delta.y = 0; - if (WindowFlags() & B_NOT_H_RESIZABLE) + if (Flags() & B_NOT_H_RESIZABLE) delta.x = 0; - Window()->Desktop()->ResizeWindowBy(this, delta.x, delta.y); + fDesktop->ResizeWindowBy(this, delta.x, delta.y); } if (fIsSlidingTab) { // TODO: implement @@ -563,27 +961,28 @@ WindowLayer::MouseMoved(BMessage *msg, BPoint where, int32* _viewToken) fLastMousePosition = where; // change focus in FFM mode - Desktop* desktop = Window()->Desktop(); - DesktopSettings desktopSettings(desktop); + DesktopSettings desktopSettings(fDesktop); if (desktopSettings.MouseMode() != B_NORMAL_MOUSE && !IsFocus()) - GetRootLayer()->SetFocus(this); + fDesktop->SetFocusWindow(this); - Layer* target = LayerAt(where); - if (target != NULL && target != this) - target->MouseMoved(msg, where, _viewToken); + if (ViewLayer* view = ViewAt(where)) + *_viewToken = view->Token(); } +// #pragma mark - + + void WindowLayer::WorkspaceActivated(int32 index, bool active) { BMessage activatedMsg(B_WORKSPACE_ACTIVATED); - activatedMsg.AddInt64("when", real_time_clock_usecs()); + activatedMsg.AddInt64("when", system_time()); activatedMsg.AddInt32("workspace", index); activatedMsg.AddBool("active", active); - Window()->SendMessageToClient(&activatedMsg); + ServerWindow()->SendMessageToClient(&activatedMsg); } @@ -593,11 +992,11 @@ WindowLayer::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces) fWorkspaces = newWorkspaces; BMessage changedMsg(B_WORKSPACES_CHANGED); - changedMsg.AddInt64("when", real_time_clock_usecs()); + changedMsg.AddInt64("when", system_time()); changedMsg.AddInt32("old", oldWorkspaces); changedMsg.AddInt32("new", newWorkspaces); - Window()->SendMessageToClient(&changedMsg); + ServerWindow()->SendMessageToClient(&changedMsg); } @@ -606,7 +1005,120 @@ WindowLayer::Activated(bool active) { BMessage msg(B_WINDOW_ACTIVATED); msg.AddBool("active", active); - Window()->SendMessageToClient(&msg); + ServerWindow()->SendMessageToClient(&msg); +} + + +//# pragma mark - + + +void +WindowLayer::SetTitle(const char* name) +{ + // rebuild the clipping for the title area + // and redraw it. + + fTitle = name; + +/* TODO: SetTitle + if (fDecorator) { + // TODO: need locking here too + BRegion updateRegion; + fDecorator->SetTitle(name, &updateRegion); + + if (fVisible && fDesktop & fDesktop->WriteLockWindows()) { + // .... + fDesktop->WriteUnlockWindows(); + } + } +*/ +} + + +void +WindowLayer::SetFocus(bool focus) +{ + // executed from Desktop thread + // it holds the clipping write lock, + // so the window thread cannot be + // accessing fIsFocus + + BRegion dirty(fBorderRegion); + dirty.IntersectWith(&fVisibleRegion); + fDesktop->MarkDirty(dirty); + + fIsFocus = focus; + if (fDecorator) + fDecorator->SetFocus(focus); + + Activated(focus); +} + + +void +WindowLayer::SetHidden(bool hidden) +{ + // the desktop takes care of dirty regions + if (fHidden != hidden) { + fHidden = hidden; + + fTopLayer->SetHidden(hidden); + + // TODO: anything else? + } +} + + +bool +WindowLayer::IsVisible() const +{ + if (IsOffscreenWindow()) + return true; + + if (IsHidden()) + return false; + +/* + if (fVisibleRegion.CountRects() == 0) + return false; +*/ + return fCurrentWorkspace >= 0 && fCurrentWorkspace < kWorkingList; +} + + +void +WindowLayer::SetSizeLimits(int32 minWidth, int32 maxWidth, + int32 minHeight, int32 maxHeight) +{ + if (minWidth < 0) + minWidth = 0; + + if (minHeight < 0) + minHeight = 0; + + fMinWidth = minWidth; + fMaxWidth = maxWidth; + fMinHeight = minHeight; + fMaxHeight = maxHeight; + + // give the Decorator a say in this too + if (fDecorator) { + fDecorator->GetSizeLimits(&fMinWidth, &fMinHeight, + &fMaxWidth, &fMaxHeight); + } + + _ObeySizeLimits(); +} + + +void +WindowLayer::GetSizeLimits(int32* minWidth, int32* maxWidth, + int32* minHeight, int32* maxHeight) const +{ + *minWidth = fMinWidth; + *maxWidth = fMaxWidth; + *minHeight = fMinHeight; + *maxHeight = fMaxHeight; } @@ -627,54 +1139,84 @@ WindowLayer::TabLocation() const } -//! Sets the decorator focus to active or inactive colors void -WindowLayer::HighlightDecorator(bool active) +WindowLayer::SetLook(window_look look, BRegion* updateRegion) { - STRACE(("Decorator->Highlight\n")); - if (fDecorator) - fDecorator->SetFocus(active); + if (fDecorator == NULL && look != B_NO_BORDER_WINDOW_LOOK) { + // we need a new decorator + fDecorator = gDecorManager.AllocateDecorator(fDesktop, Frame(), + Title(), fLook, fFlags); + } + + fLook = look; + + fBorderRegionValid = false; + // the border very likely changed + fContentRegionValid = false; + // mabye a resize handle was added... + fEffectiveDrawingRegionValid = false; + // ...and therefor the drawing region is + // likely not valid anymore either + + if (fDecorator != NULL) { + DesktopSettings settings(fDesktop); + fDecorator->SetLook(settings, look, updateRegion); + + // we might need to resize the window! + fDecorator->GetSizeLimits(&fMinWidth, &fMinHeight, &fMaxWidth, &fMaxHeight); + _ObeySizeLimits(); + } + + if (look == B_NO_BORDER_WINDOW_LOOK) { + // we don't need a decorator for this window + delete fDecorator; + fDecorator = NULL; + } } void -WindowLayer::UpdateColors() +WindowLayer::SetFeel(window_feel feel) { - // Unimplemented. Hook function for handling when system GUI colors change - STRACE(("WindowLayer %s: UpdateColors unimplemented\n", Name())); + // if the subset list is no longer needed, clear it + if ((fFeel == B_MODAL_SUBSET_WINDOW_FEEL || fFeel == B_FLOATING_SUBSET_WINDOW_FEEL) + && (feel != B_MODAL_SUBSET_WINDOW_FEEL && feel != B_FLOATING_SUBSET_WINDOW_FEEL)) + fSubsets.MakeEmpty(); + + fFeel = feel; + + // having modal windows with B_AVOID_FRONT or B_AVOID_FOCUS doesn't + // make that much sense, so we filter those flags out on demand + fFlags &= ~ValidWindowFlags(fFeel); } void -WindowLayer::UpdateDecorator() +WindowLayer::SetFlags(uint32 flags, BRegion* updateRegion) { - // Unimplemented. Hook function for handling when the system decorator changes - STRACE(("WindowLayer %s: UpdateDecorator unimplemented\n", Name())); + fFlags = flags & ~ValidWindowFlags(fFeel); + + if (fDecorator == NULL) + return; + + fDecorator->SetFlags(flags, updateRegion); + + fBorderRegionValid = false; + // the border might have changed (smaller/larger tab) + + // we might need to resize the window! + if (fDecorator) { + fDecorator->GetSizeLimits(&fMinWidth, &fMinHeight, &fMaxWidth, &fMaxHeight); + _ObeySizeLimits(); + } } - -void -WindowLayer::UpdateFont() -{ - // Unimplemented. Hook function for handling when a system font changes - STRACE(("WindowLayer %s: UpdateFont unimplemented\n", Name())); -} - - -void -WindowLayer::UpdateScreen() -{ - // Unimplemented. Hook function for handling when the screen resolution changes - STRACE(("WindowLayer %s: UpdateScreen unimplemented\n", Name())); -} - - /*! \brief Returns wether or not the window is visible on the specified workspace. - A modal or floating window may be visible on all workscreens one - of its subset windows are visible. + A modal or floating window may be visible on a workscreen if one + of its subset windows is visible there. */ bool WindowLayer::OnWorkspace(int32 index) const @@ -686,7 +1228,7 @@ WindowLayer::OnWorkspace(int32 index) const if (fFeel == B_MODAL_APP_WINDOW_FEEL || fFeel == B_FLOATING_APP_WINDOW_FEEL) - return Window()->App()->OnWorkspace(index); + return ServerWindow()->App()->OnWorkspace(index); if (fFeel == B_MODAL_SUBSET_WINDOW_FEEL || fFeel == B_FLOATING_SUBSET_WINDOW_FEEL) { @@ -711,61 +1253,6 @@ WindowLayer::SupportsFront() } -void -WindowLayer::SetLook(window_look look, BRegion* updateRegion) -{ - if (fDecorator == NULL && look != B_NO_BORDER_WINDOW_LOOK) { - // we need a new decorator - fDecorator = gDecorManager.AllocateDecorator(Window()->Desktop(), Frame(), - Name(), fLook, fWindowFlags); - } - - fLook = look; - fRebuildDecRegion = true; - - if (fDecorator != NULL) { - DesktopSettings settings(Window()->Desktop()); - fDecorator->SetLook(settings, look, updateRegion); - - // TODO: we might need to resize the window! - //fDecorator->GetSizeLimits(&fMinWidth, &fMinHeight, &fMaxWidth, &fMaxHeight); - } - - if (look == B_NO_BORDER_WINDOW_LOOK) { - // we don't need a decorator for this window - delete fDecorator; - fDecorator = NULL; - } -} - - -void -WindowLayer::SetFeel(window_feel feel) -{ - fFeel = feel; - - // having modal windows with B_AVOID_FRONT or B_AVOID_FOCUS doesn't - // make that much sense, so we filter those flags out on demand - fWindowFlags &= ~ValidWindowFlags(fFeel); -} - - -void -WindowLayer::SetWindowFlags(uint32 flags, BRegion* updateRegion) -{ - fWindowFlags = flags & ~ValidWindowFlags(fFeel); - - if (fDecorator == NULL) - return; - - fDecorator->SetFlags(flags, updateRegion); - fRebuildDecRegion = true; - - // TODO: we might need to resize the window! - //fDecorator->GetSizeLimits(&fMinWidth, &fMinHeight, &fMaxWidth, &fMaxHeight); -} - - bool WindowLayer::IsModal() const { @@ -780,31 +1267,74 @@ WindowLayer::IsFloating() const } +bool +WindowLayer::IsNormal() const +{ + return !IsFloatingFeel(fFeel) && !IsModalFeel(fFeel); +} + + +/*! + \brief Returns the windows that's in behind of the backmost position + this window can get. + Returns NULL is this window can be the backmost window. +*/ +WindowLayer* +WindowLayer::Backmost(WindowLayer* window, int32 workspace) +{ + if (workspace == -1) + workspace = fCurrentWorkspace; + + if (fFeel == kDesktopWindowFeel) + return NULL; + else if (fFeel == B_FLOATING_ALL_WINDOW_FEEL) + return window ? window : PreviousWindow(workspace); + + if (window == NULL) + window = PreviousWindow(workspace); + + for (; window != NULL; window = window->PreviousWindow(workspace)) { + if (window->IsHidden() || window == this) + continue; + + if (HasInSubset(window)) + return window; + } + + return NULL; +} + + /*! \brief Returns the windows that's in front of the frontmost position this window can get. Returns NULL is this window can be the frontmost window. */ WindowLayer* -WindowLayer::Frontmost(WindowLayer* first) +WindowLayer::Frontmost(WindowLayer* first, int32 workspace) { + if (workspace == -1) + workspace = fCurrentWorkspace; + + if (fFeel == kDesktopWindowFeel) + return first ? first : NextWindow(workspace); + if (fFeel == B_FLOATING_ALL_WINDOW_FEEL) return NULL; if (first == NULL) - first = (WindowLayer*)NextLayer(); + first = NextWindow(workspace); for (WindowLayer* window = first; window != NULL; - window = (WindowLayer*)window->NextLayer()) { - if (window->IsHidden()) + window = window->NextWindow(workspace)) { + if (window->IsHidden() || window == this) continue; // no one can be in front of a floating all window if (window->Feel() == B_FLOATING_ALL_WINDOW_FEEL) return window; - if (fFeel == B_NORMAL_WINDOW_FEEL - && window->HasInSubset(this)) + if (window->HasInSubset(this)) return window; } @@ -815,14 +1345,6 @@ WindowLayer::Frontmost(WindowLayer* first) bool WindowLayer::AddToSubset(WindowLayer* window) { - if (fFeel == B_FLOATING_ALL_WINDOW_FEEL - || fFeel == B_MODAL_ALL_WINDOW_FEEL) - return true; - - if (fFeel == B_FLOATING_APP_WINDOW_FEEL - || fFeel == B_MODAL_APP_WINDOW_FEEL) - return window->Window()->App() == Window()->App(); - return fSubsets.AddItem(window); } @@ -830,12 +1352,6 @@ WindowLayer::AddToSubset(WindowLayer* window) void WindowLayer::RemoveFromSubset(WindowLayer* window) { - if (fFeel == B_FLOATING_ALL_WINDOW_FEEL - || fFeel == B_MODAL_ALL_WINDOW_FEEL - || fFeel == B_FLOATING_APP_WINDOW_FEEL - || fFeel == B_MODAL_APP_WINDOW_FEEL) - return; - fSubsets.RemoveItem(window); } @@ -843,134 +1359,54 @@ WindowLayer::RemoveFromSubset(WindowLayer* window) bool WindowLayer::HasInSubset(WindowLayer* window) { + if (fFeel == B_MODAL_APP_WINDOW_FEEL && window->Feel() == B_MODAL_ALL_WINDOW_FEEL + || fFeel == B_NORMAL_WINDOW_FEEL + || fFeel == window->Feel()) + return false; + if (fFeel == B_FLOATING_ALL_WINDOW_FEEL || fFeel == B_MODAL_ALL_WINDOW_FEEL) return true; if (fFeel == B_FLOATING_APP_WINDOW_FEEL || fFeel == B_MODAL_APP_WINDOW_FEEL) - return window->Window()->App() == Window()->App(); + return window->ServerWindow()->App() == ServerWindow()->App(); return fSubsets.HasItem(window); } -click_type -WindowLayer::_ActionFor(const BMessage *msg) const +bool +WindowLayer::SameSubset(WindowLayer* window) { - BPoint where(0,0); - int32 buttons = 0; - int32 modifiers = 0; + // TODO: this is probably not needed at all, but it doesn't hurt to have it in svn + if (fFeel == B_MODAL_ALL_WINDOW_FEEL || window->Feel() == B_MODAL_ALL_WINDOW_FEEL) + return fFeel == window->Feel(); - msg->FindPoint("where", &where); - msg->FindInt32("buttons", &buttons); - msg->FindInt32("modifiers", &modifiers); + if (fFeel == B_MODAL_APP_WINDOW_FEEL || window->Feel() == B_MODAL_APP_WINDOW_FEEL) + return ServerWindow()->App() == window->ServerWindow()->App(); - if (fDecorator) - return fDecorator->Clicked(where, buttons, modifiers); - - return DEC_NONE; -} - - -void -WindowLayer::set_decorator_region(BRect bounds) -{ - fRebuildDecRegion = false; - - if (fDecorator) { - fDecRegion.MakeEmpty(); - fDecorator->GetFootprint(&fDecRegion); - } -} - - -void -WindowLayer::_ReserveRegions(BRegion ®) -{ - BRegion reserve(reg); - reserve.IntersectWith(&fDecRegion); - fVisible.Include(&reserve); - reg.Exclude(&reserve); -} - - -void -WindowLayer::GetOnScreenRegion(BRegion& region) -{ - if (fRebuildDecRegion) - set_decorator_region(Bounds()); - - BRect frame(Bounds()); - ConvertToScreen(&frame); - region.Set(frame); - - region.Include(&fDecRegion); - - BRegion screenRegion(GetRootLayer()->Bounds()); - region.IntersectWith(&screenRegion); -} - - -void -WindowLayer::RequestClientRedraw(const BRegion &invalid) -{ - BRegion updateReg(fTopLayer->FullVisible()); - updateReg.IntersectWith(&invalid); - - if (updateReg.CountRects() == 0) - return; - - fCumulativeRegion.Include(&updateReg); - - if (fUpdateRequestsEnabled && !InUpdate() && !fRequestSent) { - fInUpdateRegion = fCumulativeRegion; - fRequestSent = true; // this is here to avoid a possible de-synchronization - - BRect rect(fInUpdateRegion.Frame()); - ConvertFromScreen(&rect); - - BMessage msg(_UPDATE_); - msg.AddRect("_rect", rect); - msg.AddRect("debug_rect", fInUpdateRegion.Frame()); - - if (Window()->SendMessageToClient(&msg) == B_OK) { - fCumulativeRegion.MakeEmpty(); - } else { - fRequestSent = false; - fInUpdateRegion.MakeEmpty(); + if (fFeel == B_MODAL_SUBSET_WINDOW_FEEL) { + // we basically need to check if the subsets have anything in common + for (int32 i = fSubsets.CountItems(); i-- > 0;) { + if (window->HasInSubset(fSubsets.ItemAt(i))) + return true; } } -} - - -void -WindowLayer::_AllRedraw(const BRegion &invalid) -{ - // send _UPDATE_ message to client - RequestClientRedraw(invalid); - - Layer::_AllRedraw(invalid); -} - - -void -WindowLayer::SetTopLayer(Layer* layer) -{ - if (fTopLayer != NULL) { - RemoveChild(fTopLayer); - fTopLayer->SetAsTopLayer(false); + if (window->Feel() == B_MODAL_SUBSET_WINDOW_FEEL) { + for (int32 i = window->fSubsets.CountItems(); i-- > 0;) { + if (HasInSubset(window->fSubsets.ItemAt(i))) + return true; + } } - fTopLayer = layer; - - if (layer != NULL) { - AddChild(fTopLayer, Window()); - fTopLayer->SetAsTopLayer(true); - } + return false; } +// #pragma mark - static + + /*static*/ bool WindowLayer::IsValidLook(window_look look) @@ -1052,3 +1488,324 @@ WindowLayer::ValidWindowFlags(window_feel feel) return flags; } + + +// #pragma mark - private + +// _ShiftPartOfRegion +void +WindowLayer::_ShiftPartOfRegion(BRegion* region, BRegion* regionToShift, + int32 xOffset, int32 yOffset) +{ + BRegion common(*regionToShift); + // see if there is a common part at all + common.IntersectWith(region); + if (common.CountRects() > 0) { + // cut the common part from the region, + // offset that to destination and include again + region->Exclude(&common); + common.OffsetBy(xOffset, yOffset); + region->Include(&common); + } +} + + +void +WindowLayer::_TriggerContentRedraw() +{ + BRegion dirtyContentRegion(VisibleContentRegion()); + dirtyContentRegion.IntersectWith(&fDirtyRegion); + + if (dirtyContentRegion.CountRects() > 0) { + // send UPDATE message to the client + _MarkContentDirty(&dirtyContentRegion); + + if (!fContentRegionValid) + _UpdateContentRegion(); + + if (fDrawingEngine->Lock()) { + fDrawingEngine->ConstrainClippingRegion(&dirtyContentRegion); +#if DELAYED_BACKGROUND_CLEARING + fTopLayer->Draw(fDrawingEngine, &dirtyContentRegion, + &fContentRegion, false); +#else + fTopLayer->Draw(fDrawingEngine, &dirtyContentRegion, + &fContentRegion, true); +#endif + fDrawingEngine->Unlock(); + } + } +} + + +void +WindowLayer::_DrawBorder() +{ + // this is executed in the window thread, but only + // in respond to a REDRAW message having been received, the + // clipping lock is held for reading + + if (!fDecorator) + return; + + // construct the region of the border that needs redrawing + BRegion dirtyBorderRegion; + GetBorderRegion(&dirtyBorderRegion); + // intersect with our visible region + dirtyBorderRegion.IntersectWith(&fVisibleRegion); + // intersect with the dirty region + dirtyBorderRegion.IntersectWith(&fDirtyRegion); + + if (dirtyBorderRegion.CountRects() > 0) { +// TODO: decorator drawing with update region... + fDrawingEngine->ConstrainClippingRegion(&dirtyBorderRegion); + fDecorator->Draw(dirtyBorderRegion.Frame()); + fDrawingEngine->ConstrainClippingRegion(NULL); + } +} + + +/*! + pre: the clipping is readlocked (this function is + only called from _TriggerContentRedraw()), which + in turn is only called from MessageReceived() with + the clipping lock held +*/ +void +WindowLayer::_MarkContentDirty(BRegion* contentDirtyRegion) +{ + if (contentDirtyRegion->CountRects() <= 0) + return; + + // add to pending + fPendingUpdateSession.SetUsed(true); + fPendingUpdateSession.Include(contentDirtyRegion); + + // clip pending update session from current + // update session, it makes no sense to draw stuff + // already needing a redraw anyways. Theoretically, + // this could be done smarter (clip layers from pending + // that have not yet been redrawn in the current update + // session) + if (fCurrentUpdateSession.IsUsed()) { + fCurrentUpdateSession.Exclude(contentDirtyRegion); + fEffectiveDrawingRegionValid = false; + } + + if (!fUpdateRequested) { + // send this to client + _SendUpdateMessage(); + // as long as we have not received + // the "begin update" command, the + // pending session does not become the + // current +// TODO: problem: since we sent the update regions frame, +// we should not add to the pending session after we +// sent the update message!!! + } else { + if (!fCurrentUpdateSession.IsUsed()) + fprintf(stderr, "WindowLayer(%s)::_MarkContentDirty() - pending region changed before BeginUpdate()!\n", Title()); + } +} + +// _SendUpdateMessage +void +WindowLayer::_SendUpdateMessage() +{ + BMessage message(_UPDATE_); + BRect updateRect = fPendingUpdateSession.DirtyRegion().Frame(); + updateRect.OffsetBy(-fFrame.left, -fFrame.top); + message.AddRect("_rect", updateRect); + ServerWindow()->SendMessageToClient(&message); + fUpdateRequested = true; + + // TODO: the toggling between the update sessions is too + // expensive, optimize with some pointer tricks + fCurrentUpdateSession = fPendingUpdateSession; + fPendingUpdateSession.SetUsed(false); +} + + +void +WindowLayer::BeginUpdate() +{ + // NOTE: since we might "shift" parts of the + // internal dirty regions from the desktop thread + // in response to WindowLayer::ResizeBy(), which + // might move arround views, this function needs to block + // on the global clipping lock so that the internal + // dirty regions are not messed with from the Desktop thread + // and ServerWindow thread at the same time. + if (!fDesktop->ReadLockWindows()) + return; + + if (fUpdateRequested && fCurrentUpdateSession.IsUsed()) { + // all drawing command from the client + // will have the dirty region from the update + // session enforced + fInUpdate = true; + fEffectiveDrawingRegionValid = false; + } + + fDesktop->ReadUnlockWindows(); +} + + +void +WindowLayer::EndUpdate() +{ + // NOTE: see comment in _BeginUpdate() + if (!fDesktop->ReadLockWindows()) + return; + + if (fInUpdate) { + fCurrentUpdateSession.SetUsed(false); + + fInUpdate = false; + fEffectiveDrawingRegionValid = false; + } + if (fPendingUpdateSession.IsUsed()) { + // send this to client + _SendUpdateMessage(); + } else { + fUpdateRequested = false; + } + + fDesktop->ReadUnlockWindows(); +} + + +void +WindowLayer::_UpdateContentRegion() +{ + // TODO: speed up by avoiding "Exclude()" + // start from the frame, extend to include decorator border + fContentRegion.Set(fFrame); + + // resize handle + if (fDecorator) { + if (!fBorderRegionValid) + GetBorderRegion(&fBorderRegion); + + fContentRegion.Exclude(&fBorderRegion); + } + + fContentRegionValid = true; +} + + +click_type +WindowLayer::_ActionFor(const BMessage* msg) const +{ + BPoint where(0, 0); + int32 buttons = 0; + int32 modifiers = 0; + + msg->FindPoint("where", &where); + msg->FindInt32("buttons", &buttons); + msg->FindInt32("modifiers", &modifiers); + + if (fDecorator) + return fDecorator->Clicked(where, buttons, modifiers); + + return DEC_NONE; +} + +// _ObeySizeLimits +void +WindowLayer::_ObeySizeLimits() +{ + // make sure we even have valid size limits + if (fMaxWidth < fMinWidth) + fMaxWidth = fMinWidth; + + if (fMaxHeight < fMinHeight) + fMaxHeight = fMinHeight; + + // Automatically resize the window to fit these new limits + // if it does not already. + + // On R5, Windows don't automatically resize, but since + // BWindow::ResizeTo() even honors the limits, I would guess + // this is a bug that we don't have to adopt. + // Note that most current apps will do unnecessary resizing + // after having set the limits, but the overhead is neglible. + + float minWidthDiff = fMinWidth - fFrame.Width(); + float minHeightDiff = fMinHeight - fFrame.Height(); + float maxWidthDiff = fMaxWidth - fFrame.Width(); + float maxHeightDiff = fMaxHeight - fFrame.Height(); + + float xDiff = 0.0; + if (minWidthDiff > 0.0) // we're currently smaller than minWidth + xDiff = minWidthDiff; + else if (maxWidthDiff < 0.0) // we're currently larger than maxWidth + xDiff = maxWidthDiff; + + float yDiff = 0.0; + if (minHeightDiff > 0.0) // we're currently smaller than minHeight + yDiff = minHeightDiff; + else if (maxHeightDiff < 0.0) // we're currently larger than maxHeight + yDiff = maxHeightDiff; + + if (fDesktop) + fDesktop->ResizeWindowBy(this, xDiff, yDiff); + else + ResizeBy(xDiff, yDiff, NULL); +} + +// #pragma mark - UpdateSession + +// constructor +WindowLayer::UpdateSession::UpdateSession() + : fDirtyRegion(), + fInUse(false) +{ +} + +// destructor +WindowLayer::UpdateSession::~UpdateSession() +{ +} + +// Include +void +WindowLayer::UpdateSession::Include(BRegion* additionalDirty) +{ + fDirtyRegion.Include(additionalDirty); +} + + +void +WindowLayer::UpdateSession::Exclude(BRegion* dirtyInNextSession) +{ + fDirtyRegion.Exclude(dirtyInNextSession); +} + + +void +WindowLayer::UpdateSession::MoveBy(int32 x, int32 y) +{ + fDirtyRegion.OffsetBy(x, y); +} + + +void +WindowLayer::UpdateSession::SetUsed(bool used) +{ + fInUse = used; + if (!fInUse) + fDirtyRegion.MakeEmpty(); +} + + +WindowLayer::UpdateSession& +WindowLayer::UpdateSession::operator=(const WindowLayer::UpdateSession& other) +{ + fDirtyRegion = other.fDirtyRegion; + fInUse = other.fInUse; + return *this; +} + + + diff --git a/src/servers/app/WindowLayer.h b/src/servers/app/WindowLayer.h index 12c4174e38..89cbb4b7b1 100644 --- a/src/servers/app/WindowLayer.h +++ b/src/servers/app/WindowLayer.h @@ -12,98 +12,135 @@ #include "Decorator.h" -#include "Layer.h" +#include "ViewLayer.h" +#include "ServerWindow.h" +#include "WindowList.h" #include -#include +#include #include -class ServerWindow; +class ClientLooper; class Decorator; -class DrawingEngine; class Desktop; +class DrawingEngine; +class EventDispatcher; +class WindowLayer; -class WindowLayer : public Layer { +// TODO: move this into a proper place +#define AS_REDRAW 'rdrw' + + +class WindowLayer { public: - WindowLayer(const BRect &frame, - const char *name, window_look look, - window_feel feel, uint32 flags, - uint32 workspaces, ServerWindow *window, - DrawingEngine *driver); + WindowLayer(const BRect& frame, + const char *name, window_look look, + window_feel feel, uint32 flags, + uint32 workspaces, + ::ServerWindow* window, + DrawingEngine* drawingEngine); virtual ~WindowLayer(); - virtual void Draw(const BRect &r); + BRect Frame() const { return fFrame; } + const char* Title() const { return fTitle.String(); } - virtual void MoveBy(float x, float y); - virtual void ResizeBy(float x, float y); - virtual void ScrollBy(float x, float y) - { /* not allowed */ } + window_anchor& Anchor(int32 index); + WindowLayer* NextWindow(int32 index); + WindowLayer* PreviousWindow(int32 index); - virtual void SetName(const char* name); + ::Desktop* Desktop() const { return fDesktop; } + ::Decorator* Decorator() const { return fDecorator; } + ::ServerWindow* ServerWindow() const { return fWindow; } + ::EventTarget& EventTarget() const { return fWindow->EventTarget(); } - virtual bool IsOffscreenWindow() const - { return false; } + // for convenience, handles window not attached to Desktop + bool ReadLockWindows(); + void ReadUnlockWindows(); - virtual void GetOnScreenRegion(BRegion& region); + // setting and getting the "hard" clipping, you need to have + // WriteLock()ed the clipping! + void SetClipping(BRegion* stillAvailableOnScreen); + // you need to have ReadLock()ed the clipping! + inline BRegion& VisibleRegion() { return fVisibleRegion; } + BRegion& VisibleContentRegion(); + + // TODO: not protected by a lock, but noone should need this anyways + // make private? when used inside WindowLayer, it has the ReadLock() + void GetFullRegion(BRegion* region); + void GetBorderRegion(BRegion* region); + void GetContentRegion(BRegion* region); + + void MoveBy(int32 x, int32 y); + void ResizeBy(int32 x, int32 y, BRegion* dirtyRegion); + + void ScrollViewBy(ViewLayer* view, int32 dx, int32 dy); + + void SetTopLayer(ViewLayer* topLayer); + + ViewLayer* ViewAt(const BPoint& where); + + virtual bool IsOffscreenWindow() const { return false; } + + void GetEffectiveDrawingRegion(ViewLayer* layer, BRegion& region); + bool DrawingRegionChanged(ViewLayer* layer) const; + + // generic version, used by the Desktop + void ProcessDirtyRegion(BRegion& regionOnScreen); + void RedrawDirtyRegion(); + + // can be used from inside classes that don't + // need to know about Desktop (first version uses Desktop) + void MarkDirty(BRegion& regionOnScreen); + // this version does not use the Desktop + void MarkContentDirty(BRegion& regionOnScreen); + // shortcut for invalidating just one view + void InvalidateView(ViewLayer* view, BRegion& layerRegion); - void UpdateStart(); - void UpdateEnd(); - inline bool InUpdate() const - { return fInUpdate; } - inline const BRegion& RegionToBeUpdated() const - { return fInUpdateRegion; } - inline const BRegion& CulmulatedUpdateRegion() const - { return fCumulativeRegion; } void EnableUpdateRequests(); - inline void DisableUpdateRequests() - { fUpdateRequestsEnabled = false; } + void DisableUpdateRequests(); - void SetSizeLimits(float minWidth, - float maxWidth, - float minHeight, - float maxHeight); + void BeginUpdate(); + void EndUpdate(); - void GetSizeLimits(float* minWidth, - float* maxWidth, - float* minHeight, - float* maxHeight) const; + bool NeedsUpdate() const + { return fUpdateRequested; } - virtual void MouseDown(BMessage* message, BPoint where, int32* _viewToken); - virtual void MouseUp(BMessage* message, BPoint where, int32* _viewToken); - virtual void MouseMoved(BMessage* message, BPoint where, int32* _viewToken); + DrawingEngine* GetDrawingEngine() const + { return fDrawingEngine; } -// click_type ActionFor(const BMessage *msg) -// { return _ActionFor(evt); } + void CopyContents(BRegion* region, + int32 xOffset, int32 yOffset); - virtual void WorkspaceActivated(int32 index, bool active); - virtual void WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces); - virtual void Activated(bool active); + void MouseDown(BMessage* message, BPoint where, int32* _viewToken); + void MouseUp(BMessage* message, BPoint where, int32* _viewToken); + void MouseMoved(BMessage* message, BPoint where, int32* _viewToken); - void UpdateColors(); - void UpdateDecorator(); - void UpdateFont(); - void UpdateScreen(); + // some hooks to inform the client window + // TODO: move this to ServerWindow maybe? + void WorkspaceActivated(int32 index, bool active); + void WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces); + void Activated(bool active); + // changing some properties + void SetTitle(const char* name); + + void SetFocus(bool focus); bool IsFocus() const { return fIsFocus; } - void SetFocus(bool focus) { fIsFocus = focus; } - inline Decorator* GetDecorator() const { return fDecorator; } + void SetHidden(bool hidden); + inline bool IsHidden() const { return fHidden; } - window_look Look() const { return fLook; } - window_feel Feel() const { return fFeel; } - uint32 WindowFlags() const { return fWindowFlags; } + void SetCurrentWorkspace(int32 index) + { fCurrentWorkspace = index; } + bool IsVisible() const; - void SetLook(window_look look, BRegion* updateRegion); - void SetFeel(window_feel feel); - void SetWindowFlags(uint32 flags, BRegion* updateRegion); + // TODO: make this int32 stuff + void SetSizeLimits(int32 minWidth, int32 maxWidth, + int32 minHeight, int32 maxHeight); - uint32 Workspaces() const { return fWorkspaces; } - void SetWorkspaces(uint32 workspaces) - { fWorkspaces = workspaces; } - bool OnWorkspace(int32 index) const; - - bool SupportsFront(); + void GetSizeLimits(int32* minWidth, int32* maxWidth, + int32* minHeight, int32* maxHeight) const; // 0.0 -> left .... 1.0 -> right void SetTabLocation(float location); @@ -111,20 +148,33 @@ class WindowLayer : public Layer { void HighlightDecorator(bool active); + void SetLook(window_look look, BRegion* updateRegion); + void SetFeel(window_feel feel); + void SetFlags(uint32 flags, BRegion* updateRegion); + + window_look Look() const { return fLook; } + window_feel Feel() const { return fFeel; } + uint32 Flags() const { return fFlags; } + + // window manager stuff + uint32 Workspaces() const { return fWorkspaces; } + void SetWorkspaces(uint32 workspaces) + { fWorkspaces = workspaces; } + bool OnWorkspace(int32 index) const; + + bool SupportsFront(); + bool IsModal() const; bool IsFloating() const; + bool IsNormal() const; - WindowLayer* Frontmost(WindowLayer* first = NULL); + WindowLayer* Frontmost(WindowLayer* first = NULL, int32 workspace = -1); + WindowLayer* Backmost(WindowLayer* first = NULL, int32 workspace = -1); bool AddToSubset(WindowLayer* window); void RemoveFromSubset(WindowLayer* window); bool HasInSubset(WindowLayer* window); - - void RequestClientRedraw(const BRegion& invalid); - - void SetTopLayer(Layer* layer); - inline Layer* TopLayer() const - { return fTopLayer; } + bool SameSubset(WindowLayer* window); static bool IsValidLook(window_look look); static bool IsValidFeel(window_feel feel); @@ -135,33 +185,58 @@ class WindowLayer : public Layer { static uint32 ValidWindowFlags(window_feel feel); protected: - virtual void _AllRedraw(const BRegion& invalid); + friend class Desktop; + // TODO: for now (list management) - private: - void set_decorator_region(BRect frame); - virtual void _ReserveRegions(BRegion ®); + void _ShiftPartOfRegion(BRegion* region, BRegion* regionToShift, + int32 xOffset, int32 yOffset); - friend class RootLayer; + // different types of drawing + void _TriggerContentRedraw(); + void _DrawBorder(); - click_type _ActionFor(const BMessage *msg) const; + // handling update sessions + void _MarkContentDirty(BRegion* contentDirtyRegion); + void _SendUpdateMessage(); - Decorator* fDecorator; - Layer* fTopLayer; + void _UpdateContentRegion(); - BRegion fCumulativeRegion; - BRegion fInUpdateRegion; + click_type _ActionFor(const BMessage* msg) const; - BRegion fDecRegion; - bool fRebuildDecRegion; + void _ObeySizeLimits(); - int32 fMouseButtons; - BPoint fLastMousePosition; - BPoint fResizingClickOffset; + BString fTitle; + // TODO: no fp rects anywhere + BRect fFrame; - bool fIsFocus; + window_anchor fAnchor[kWorkingList + 1]; + // one for each desktop, and one working anchor + + // the visible region is only recalculated from the + // Desktop thread, when using it, Desktop::ReadLockClipping() + // has to be called + + BRegion fVisibleRegion; + BRegion fVisibleContentRegion; + bool fVisibleContentRegionValid; + // our part of the "global" dirty region + // it is calculated from the desktop thread, + // but we can write to it when we read locked + // the clipping, since it is local and the desktop + // thread is blocked + BRegion fDirtyRegion; + + // caching local regions + BRegion fBorderRegion; + bool fBorderRegionValid; + BRegion fContentRegion; + bool fContentRegionValid; + BRegion fEffectiveDrawingRegion; + bool fEffectiveDrawingRegionValid; BObjectList fSubsets; +// TODO: remove those some day (let the decorator handle that stuff) bool fIsClosing; bool fIsMinimizing; bool fIsZooming; @@ -169,21 +244,72 @@ class WindowLayer : public Layer { bool fIsSlidingTab; bool fIsDragging; - bool fBringToFrontOnRelease; +// bool fBringToFrontOnRelease; - bool fUpdateRequestsEnabled; + ::Decorator* fDecorator; + ViewLayer* fTopLayer; + ::ServerWindow* fWindow; + DrawingEngine* fDrawingEngine; + ::Desktop* fDesktop; + + BPoint fLastMousePosition; +// BPoint fResizingClickOffset; + + // The synchronization, which client drawing commands + // belong to the redraw of which dirty region is handled + // through an UpdateSession. When the client has + // been informed that it should redraw stuff, then + // this is the current update session. All new + // redraw requests from the Desktop will go + // into the pending update session. + class UpdateSession { + public: + UpdateSession(); + virtual ~UpdateSession(); + + void Include(BRegion* additionalDirty); + void Exclude(BRegion* dirtyInNextSession); + + inline BRegion& DirtyRegion() + { return fDirtyRegion; } + + void MoveBy(int32 x, int32 y); + + void SetUsed(bool used); + inline bool IsUsed() const + { return fInUse; } + + UpdateSession& operator=(const UpdateSession& other); + + private: + BRegion fDirtyRegion; + bool fInUse; + }; + + BRegion fDecoratorRegion; + + UpdateSession fCurrentUpdateSession; + UpdateSession fPendingUpdateSession; + // these two flags are supposed to ensure a sane + // and consistent update session + bool fUpdateRequested; bool fInUpdate; - bool fRequestSent; + + bool fHidden; + bool fIsFocus; window_look fLook; window_feel fFeel; - uint32 fWindowFlags; + uint32 fFlags; uint32 fWorkspaces; + int32 fCurrentWorkspace; - float fMinWidth; - float fMaxWidth; - float fMinHeight; - float fMaxHeight; + int32 fMinWidth; + int32 fMaxWidth; + int32 fMinHeight; + int32 fMaxHeight; + + mutable bool fReadLocked; }; -#endif // WINDOW_LAYER_H +#endif // WINDOW_LAYER_H diff --git a/src/servers/app/WindowList.cpp b/src/servers/app/WindowList.cpp new file mode 100644 index 0000000000..0f5349488e --- /dev/null +++ b/src/servers/app/WindowList.cpp @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2005, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "WindowLayer.h" + + +const BPoint kInvalidWindowPosition = BPoint(INFINITY, INFINITY); + + +window_anchor::window_anchor() + : + next(NULL), + previous(NULL), + position(kInvalidWindowPosition) +{ +} + + +// #pragma mark - + + +WindowList::WindowList(int32 index) + : + fIndex(index), + fFirstWindow(NULL), + fLastWindow(NULL) +{ +} + + +WindowList::~WindowList() +{ +} + + +void +WindowList::SetIndex(int32 index) +{ + fIndex = index; +} + + +void +WindowList::AddWindow(WindowLayer* window, WindowLayer* before) +{ + window_anchor& windowAnchor = window->Anchor(fIndex); + + if (before != NULL) { + window_anchor& beforeAnchor = before->Anchor(fIndex); + + // add view before this one + windowAnchor.next = before; + windowAnchor.previous = beforeAnchor.previous; + if (windowAnchor.previous != NULL) + windowAnchor.previous->Anchor(fIndex).next = window; + + beforeAnchor.previous = window; + if (fFirstWindow == before) + fFirstWindow = window; + } else { + // add view to the end of the list + if (fLastWindow != NULL) { + fLastWindow->Anchor(fIndex).next = window; + windowAnchor.previous = fLastWindow; + } else { + fFirstWindow = window; + windowAnchor.previous = NULL; + } + + windowAnchor.next = NULL; + fLastWindow = window; + } +} + + +void +WindowList::RemoveWindow(WindowLayer* window) +{ +// TODO: Axel, the same window can be removed in the same list +// more than once, would that be a bug? + window_anchor& windowAnchor = window->Anchor(fIndex); + + if (fFirstWindow == window) { + // it's the first child + fFirstWindow = windowAnchor.next; + } else { + // it must have a previous sibling if it was not + // previously removed from this list + if (windowAnchor.previous) + windowAnchor.previous->Anchor(fIndex).next = windowAnchor.next; + } + + if (fLastWindow == window) { + // it's the last child + fLastWindow = windowAnchor.previous; + } else { + // it must have a next sibling if it was not + // previously removed from this list + if (windowAnchor.next) + windowAnchor.next->Anchor(fIndex).previous = windowAnchor.previous; + } + + windowAnchor.previous = NULL; + windowAnchor.next = NULL; +} + diff --git a/src/servers/app/WindowList.h b/src/servers/app/WindowList.h new file mode 100644 index 0000000000..aac054fad7 --- /dev/null +++ b/src/servers/app/WindowList.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2005, Haiku, Inc. + * Distributed under the terms of the MIT license. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef WINDOW_LIST_H +#define WINDOW_LIST_H + + +#include +#include + + +class WindowLayer; + + +class WindowList { + public: + WindowList(int32 index = 0); + ~WindowList(); + + void SetIndex(int32 index); + int32 Index() const { return fIndex; } + + WindowLayer* FirstWindow() { return fFirstWindow; } + WindowLayer* LastWindow() { return fLastWindow; } + + void AddWindow(WindowLayer* window, WindowLayer* before = NULL); + void RemoveWindow(WindowLayer* window); + + private: + int32 fIndex; + WindowLayer* fFirstWindow; + WindowLayer* fLastWindow; +}; + +enum window_lists { + kAllWindowList = 32, + kFloatingList, + kWorkingList, +}; + +struct window_anchor { + window_anchor(); + + WindowLayer* next; + WindowLayer* previous; + BPoint position; +}; + +extern const BPoint kInvalidWindowPosition; + +#endif // WINDOW_LIST_H diff --git a/src/servers/app/Workspace.cpp b/src/servers/app/Workspace.cpp index 8c7c2090d8..3d92179a9e 100644 --- a/src/servers/app/Workspace.cpp +++ b/src/servers/app/Workspace.cpp @@ -7,8 +7,9 @@ */ -#include "RootLayer.h" +#include "Desktop.h" #include "Workspace.h" +#include "WorkspacePrivate.h" #include "WindowLayer.h" #include @@ -17,13 +18,9 @@ static RGBColor kDefaultColor = RGBColor(51, 102, 152); -const BPoint kInvalidWindowPosition = BPoint(INFINITY, INFINITY); Workspace::Private::Private() - : - fWindows(20, true) - // this list owns its items { _SetDefaults(); } @@ -34,47 +31,6 @@ Workspace::Private::~Private() } -bool -Workspace::Private::AddWindow(WindowLayer* window, BPoint* position) -{ - window_layer_info* info = new (nothrow) window_layer_info; - if (info == NULL) - return false; - - info->position = position ? *position : kInvalidWindowPosition; - info->window = window; - - bool success = fWindows.AddItem(info); - if (!success) - delete info; - - return success; -} - - -void -Workspace::Private::RemoveWindow(WindowLayer* window) -{ - for (int32 i = fWindows.CountItems(); i-- > 0;) { - window_layer_info* info = fWindows.ItemAt(i); - - if (info->window == window) { - fWindows.RemoveItemAt(i); - delete info; - return; - } - } -} - - -void -Workspace::Private::RemoveWindowAt(int32 index) -{ - window_layer_info* info = fWindows.RemoveItemAt(index); - delete info; -} - - void Workspace::Private::SetDisplaysFromDesktop(Desktop* desktop) { @@ -137,26 +93,21 @@ Workspace::Color() const status_t Workspace::GetNextWindow(WindowLayer*& _window, BPoint& _leftTop) { - if (fCurrentWorkspace) { - if (fCurrent == NULL) - fCurrent = (WindowLayer*)fDesktop.RootLayer()->FirstChild(); - else - fCurrent = (WindowLayer*)fCurrent->NextLayer(); - - if (fCurrent == NULL) - return B_ENTRY_NOT_FOUND; + if (fCurrent == NULL) + fCurrent = fWorkspace.Windows().FirstWindow(); + else + fCurrent = fCurrent->NextWindow(fWorkspace.Index()); - _window = fCurrent; - _leftTop = fCurrent->Frame().LeftTop(); - return B_OK; - } - - window_layer_info* info = fWorkspace.WindowAt(fIndex++); - if (info == NULL) + if (fCurrent == NULL) return B_ENTRY_NOT_FOUND; - _window = info->window; - _leftTop = info->position; + _window = fCurrent; + + if (fCurrentWorkspace) + _leftTop = fCurrent->Frame().LeftTop(); + else + _leftTop = fCurrent->Anchor(fWorkspace.Index()).position; + return B_OK; } @@ -164,7 +115,6 @@ Workspace::GetNextWindow(WindowLayer*& _window, BPoint& _leftTop) void Workspace::RewindWindows() { - fIndex = 0; fCurrent = NULL; } diff --git a/src/servers/app/Workspace.h b/src/servers/app/Workspace.h index c16197a1d1..efd116575b 100644 --- a/src/servers/app/Workspace.h +++ b/src/servers/app/Workspace.h @@ -35,7 +35,6 @@ class Workspace { private: Workspace::Private& fWorkspace; Desktop& fDesktop; - int32 fIndex; WindowLayer* fCurrent; bool fCurrentWorkspace; }; diff --git a/src/servers/app/WorkspacePrivate.h b/src/servers/app/WorkspacePrivate.h index 3fa2846013..5d7e7ddbd9 100644 --- a/src/servers/app/WorkspacePrivate.h +++ b/src/servers/app/WorkspacePrivate.h @@ -10,38 +10,28 @@ #include "RGBColor.h" +#include "WindowList.h" #include "Workspace.h" +#include #include #include -class RootLayer; -class WindowLayer; - - struct display_info { BString identifier; BPoint origin; display_mode mode; }; -struct window_layer_info { - BPoint position; - WindowLayer* window; -}; - class Workspace::Private { public: Private(); ~Private(); - bool AddWindow(WindowLayer* window, BPoint* point = NULL); - void RemoveWindow(WindowLayer* window); - void RemoveWindowAt(int32 index); + int32 Index() const { return fWindows.Index(); } - int32 CountWindows() const { return fWindows.CountItems(); } - window_layer_info* WindowAt(int32 index) const { return fWindows.ItemAt(index); } + WindowList& Windows() { return fWindows; } // displays @@ -61,7 +51,7 @@ class Workspace::Private { private: void _SetDefaults(); - BObjectList fWindows; + WindowList fWindows; WindowLayer* fFront; WindowLayer* fFocus; @@ -70,6 +60,4 @@ class Workspace::Private { RGBColor fColor; }; -extern const BPoint kInvalidWindowPosition; - #endif /* WORKSPACE_PRIVATE_H */ diff --git a/src/servers/app/WorkspacesLayer.cpp b/src/servers/app/WorkspacesLayer.cpp index d1a9b13df5..a8e1a9933c 100644 --- a/src/servers/app/WorkspacesLayer.cpp +++ b/src/servers/app/WorkspacesLayer.cpp @@ -8,20 +8,21 @@ */ -#include -#include +#include "WorkspacesLayer.h" #include "AppServer.h" +#include "Desktop.h" #include "DrawingEngine.h" -#include "RootLayer.h" #include "WindowLayer.h" #include "Workspace.h" -#include "WorkspacesLayer.h" +#include +#include + WorkspacesLayer::WorkspacesLayer(BRect frame, const char* name, - int32 token, uint32 resizeMode, uint32 flags, DrawingEngine* driver) - : Layer(frame, name, token, resizeMode, flags, driver) + int32 token, uint32 resizeMode, uint32 flags) + : ViewLayer(frame, name, token, resizeMode, flags) { fDrawState->SetLowColor(RGBColor(255, 255, 255)); fDrawState->SetHighColor(RGBColor(0, 0, 0)); @@ -98,7 +99,7 @@ WorkspacesLayer::_WindowFrame(const BRect& workspaceFrame, void -WorkspacesLayer::_DrawWindow(const BRect& workspaceFrame, +WorkspacesLayer::_DrawWindow(DrawingEngine* drawingEngine, const BRect& workspaceFrame, const BRect& screenFrame, WindowLayer* window, BPoint windowPosition, BRegion& backgroundRegion, bool active) { @@ -108,12 +109,12 @@ WorkspacesLayer::_DrawWindow(const BRect& workspaceFrame, BPoint offset = window->Frame().LeftTop() - windowPosition; BRect frame = _WindowFrame(workspaceFrame, screenFrame, window->Frame(), windowPosition); - BRect tabFrame = window->GetDecorator()->TabRect(); + BRect tabFrame = window->Decorator()->TabRect(); tabFrame = _WindowFrame(workspaceFrame, screenFrame, tabFrame, tabFrame.LeftTop() - offset); // ToDo: let decorator do this! - RGBColor yellow = window->GetDecorator()->GetColors().window_tab; + RGBColor yellow = window->Decorator()->Colors().window_tab; RGBColor gray(180, 180, 180); RGBColor white(255, 255, 255); @@ -134,12 +135,12 @@ WorkspacesLayer::_DrawWindow(const BRect& workspaceFrame, backgroundRegion.Exclude(tabFrame); backgroundRegion.Exclude(frame); - GetDrawingEngine()->StrokeLine(tabFrame.LeftTop(), tabFrame.RightBottom(), yellow); + drawingEngine->StrokeLine(tabFrame.LeftTop(), tabFrame.RightBottom(), yellow); - GetDrawingEngine()->StrokeRect(frame, gray); + drawingEngine->StrokeRect(frame, gray); frame.InsetBy(1, 1); - GetDrawingEngine()->FillRect(frame, white); + drawingEngine->FillRect(frame, white); // draw title @@ -170,7 +171,7 @@ WorkspacesLayer::_DrawWindow(const BRect& workspaceFrame, void -WorkspacesLayer::_DrawWorkspace(int32 index) +WorkspacesLayer::_DrawWorkspace(DrawingEngine* drawingEngine, int32 index) { BRect rect = _WorkspaceAt(index); @@ -179,7 +180,7 @@ WorkspacesLayer::_DrawWorkspace(int32 index) if (active) { // draw active frame RGBColor black(0, 0, 0); - GetDrawingEngine()->StrokeRect(rect, black); + drawingEngine->StrokeRect(rect, black); } rect.InsetBy(1, 1); @@ -190,7 +191,7 @@ WorkspacesLayer::_DrawWorkspace(int32 index) // draw windows - BRegion backgroundRegion = VisibleRegion(); + BRegion backgroundRegion = fLocalClipping; // ToDo: would be nice to get the real update region here @@ -203,23 +204,23 @@ WorkspacesLayer::_DrawWorkspace(int32 index) BRegion workspaceRegion(rect); backgroundRegion.IntersectWith(&workspaceRegion); - GetDrawingEngine()->ConstrainClippingRegion(&backgroundRegion); + drawingEngine->ConstrainClippingRegion(&backgroundRegion); WindowLayer* window; BPoint leftTop; while (workspace.GetNextWindow(window, leftTop) == B_OK) { - _DrawWindow(rect, screenFrame, window, leftTop, - backgroundRegion, active); + _DrawWindow(drawingEngine, rect, screenFrame, window, + leftTop, backgroundRegion, active); } // draw background - GetDrawingEngine()->ConstrainClippingRegion(&backgroundRegion); - GetDrawingEngine()->FillRect(rect, color); + drawingEngine->ConstrainClippingRegion(&backgroundRegion); + drawingEngine->FillRect(rect, color); // TODO: ConstrainClippingRegion() should accept a const parameter !! - BRegion cRegion(VisibleRegion()); - GetDrawingEngine()->ConstrainClippingRegion(&cRegion); + BRegion cRegion(fLocalClipping); + drawingEngine->ConstrainClippingRegion(&cRegion); } @@ -231,7 +232,8 @@ WorkspacesLayer::_DarkenColor(RGBColor& color) const void -WorkspacesLayer::Draw(const BRect& updateRect) +WorkspacesLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping, + BRegion* windowContentClipping, bool deep) { int32 columns, rows; _GetGrid(columns, rows); @@ -241,9 +243,9 @@ WorkspacesLayer::Draw(const BRect& updateRect) // make sure the grid around the active workspace is not drawn // to reduce flicker BRect activeRect = _WorkspaceAt(Window()->Desktop()->CurrentWorkspace()); - BRegion gridRegion(VisibleRegion()); + BRegion gridRegion(fLocalClipping); gridRegion.Exclude(activeRect); - GetDrawingEngine()->ConstrainClippingRegion(&gridRegion); + drawingEngine->ConstrainClippingRegion(&gridRegion); BRect frame = Frame(); BPoint pt(0,0); @@ -252,33 +254,33 @@ WorkspacesLayer::Draw(const BRect& updateRect) // horizontal lines - GetDrawingEngine()->StrokeLine(BPoint(frame.left, frame.top), + drawingEngine->StrokeLine(BPoint(frame.left, frame.top), BPoint(frame.right, frame.top), ViewColor()); for (int32 row = 0; row < rows; row++) { BRect rect = _WorkspaceAt(row * columns); - GetDrawingEngine()->StrokeLine(BPoint(frame.left, rect.bottom), + drawingEngine->StrokeLine(BPoint(frame.left, rect.bottom), BPoint(frame.right, rect.bottom), ViewColor()); } // vertical lines - GetDrawingEngine()->StrokeLine(BPoint(frame.left, frame.top), + drawingEngine->StrokeLine(BPoint(frame.left, frame.top), BPoint(frame.left, frame.bottom), ViewColor()); for (int32 column = 0; column < columns; column++) { BRect rect = _WorkspaceAt(column); - GetDrawingEngine()->StrokeLine(BPoint(rect.right, frame.top), + drawingEngine->StrokeLine(BPoint(rect.right, frame.top), BPoint(rect.right, frame.bottom), ViewColor()); } - BRegion cRegion(VisibleRegion()); - GetDrawingEngine()->ConstrainClippingRegion(&cRegion); + BRegion cRegion(fLocalClipping); + drawingEngine->ConstrainClippingRegion(&cRegion); // draw workspaces for (int32 i = rows * columns; i-- > 0;) { - _DrawWorkspace(i); + _DrawWorkspace(drawingEngine, i); } } @@ -298,7 +300,7 @@ WorkspacesLayer::MouseDown(BMessage* message, BPoint where, int32* _viewToken) } } - Layer::MouseDown(message, where, _viewToken); + //ViewLayer::MouseDown(message, where, _viewToken); } diff --git a/src/servers/app/WorkspacesLayer.h b/src/servers/app/WorkspacesLayer.h index b86c4c0ae0..24a4e8887d 100644 --- a/src/servers/app/WorkspacesLayer.h +++ b/src/servers/app/WorkspacesLayer.h @@ -9,18 +9,21 @@ #define WORKSPACES_LAYER_H -#include "Layer.h" +#include "ViewLayer.h" class WindowLayer; -class WorkspacesLayer : public Layer { +class WorkspacesLayer : public ViewLayer { public: WorkspacesLayer(BRect frame, const char* name, int32 token, - uint32 resize, uint32 flags, DrawingEngine* driver); + uint32 resize, uint32 flags); virtual ~WorkspacesLayer(); - virtual void Draw(const BRect& updateRect); + virtual void Draw(DrawingEngine* drawingEngine, + BRegion* effectiveClipping, + BRegion* windowContentClipping, + bool deep = false); virtual void MouseDown(BMessage* message, BPoint where, int32* _viewToken); private: @@ -30,11 +33,11 @@ class WorkspacesLayer : public Layer { const BRect& screenFrame, const BRect& windowFrame, BPoint windowPosition); - void _DrawWindow(const BRect& workspaceFrame, + void _DrawWindow(DrawingEngine* drawingEngine, const BRect& workspaceFrame, const BRect& screenFrame, WindowLayer* window, BPoint windowPosition, BRegion& backgroundRegion, bool active); - void _DrawWorkspace(int32 index); + void _DrawWorkspace(DrawingEngine* drawingEngine, int32 index); void _DarkenColor(RGBColor& color) const; }; diff --git a/src/servers/app/drawing/DrawingEngine.cpp b/src/servers/app/drawing/DrawingEngine.cpp index 0b9905817d..cf9155b9b5 100644 --- a/src/servers/app/drawing/DrawingEngine.cpp +++ b/src/servers/app/drawing/DrawingEngine.cpp @@ -120,16 +120,16 @@ DrawingEngine::Update() } } -// SetHWInterface + void DrawingEngine::SetHWInterface(HWInterface* interface) { fGraphicsCard = interface; } -// ConstrainClippingRegion + void -DrawingEngine::ConstrainClippingRegion(BRegion *region) +DrawingEngine::ConstrainClippingRegion(const BRegion* region) { if (Lock()) { if (!region) { @@ -377,7 +377,7 @@ DrawingEngine::CopyRegion(/*const*/ BRegion* region, // CopyRegionList // -// * used to move windows arround on screen +// * used to move windows around on screen // TODO: Since the regions are passed to CopyRegion() one by one, // the case of different regions overlapping each other at source // and/or dest locations is not handled. @@ -395,7 +395,6 @@ DrawingEngine::CopyRegionList(BList* list, BList* pList, // This needs to be investigated, I'm doing this because of // gut feeling. if (WriteLock()) { - for (int32 i = 0; i < rCount; i++) { BRegion* region = (BRegion*)list->ItemAt(i); BPoint* offset = (BPoint*)pList->ItemAt(i); @@ -583,7 +582,6 @@ DrawingEngine::StrokeRect(BRect r, const RGBColor &color) make_rect_valid(r); BRect clipped = fPainter->ClipRect(r); if (clipped.IsValid()) { - fGraphicsCard->HideSoftwareCursor(clipped); fPainter->StrokeRect(r, color.GetColor32()); @@ -671,13 +669,12 @@ DrawingEngine::FillRect(BRect r, const DrawState *d) r = fPainter->ClipRect(r); if (r.IsValid()) { fGraphicsCard->HideSoftwareCursor(r); - + bool doInSoftware = true; // try hardware optimized version first - if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) && - (d->GetDrawingMode() == B_OP_COPY || - d->GetDrawingMode() == B_OP_OVER)) { - + if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0 + && (d->GetDrawingMode() == B_OP_COPY + || d->GetDrawingMode() == B_OP_OVER)) { if (d->GetPattern() == B_SOLID_HIGH) { BRegion region(r); region.IntersectWith(fPainter->ClippingRegion()); @@ -691,13 +688,12 @@ DrawingEngine::FillRect(BRect r, const DrawState *d) } } if (doInSoftware) { - fPainter->SetDrawState(d); fPainter->FillRect(r); - + fGraphicsCard->Invalidate(r); } - + fGraphicsCard->ShowSoftwareCursor(); } @@ -715,16 +711,16 @@ DrawingEngine::StrokeRegion(BRegion& r, const DrawState *d) clipped = fPainter->ClipRect(clipped); if (clipped.IsValid()) { fGraphicsCard->HideSoftwareCursor(clipped); - + fPainter->SetDrawState(d); - + BRect touched = fPainter->StrokeRect(r.RectAt(0)); - + int32 count = r.CountRects(); for (int32 i = 1; i < count; i++) { touched = touched | fPainter->StrokeRect(r.RectAt(i)); } - + fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); } @@ -744,13 +740,12 @@ DrawingEngine::FillRegion(BRegion& r, const DrawState *d) BRect clipped = fPainter->ClipRect(r.Frame()); if (clipped.IsValid()) { fGraphicsCard->HideSoftwareCursor(clipped); - + bool doInSoftware = true; // try hardware optimized version first - if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) && - (d->GetDrawingMode() == B_OP_COPY || - d->GetDrawingMode() == B_OP_OVER)) { - + if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0 + && (d->GetDrawingMode() == B_OP_COPY + || d->GetDrawingMode() == B_OP_OVER)) { if (d->GetPattern() == B_SOLID_HIGH) { fGraphicsCard->FillRegion(r, d->HighColor()); doInSoftware = false; @@ -759,20 +754,20 @@ DrawingEngine::FillRegion(BRegion& r, const DrawState *d) doInSoftware = false; } } + if (doInSoftware) { - fPainter->SetDrawState(d); - + BRect touched = fPainter->FillRect(r.RectAt(0)); - + int32 count = r.CountRects(); for (int32 i = 1; i < count; i++) { touched = touched | fPainter->FillRect(r.RectAt(i)); } - + fGraphicsCard->Invalidate(touched); } - + fGraphicsCard->ShowSoftwareCursor(); } @@ -780,58 +775,96 @@ DrawingEngine::FillRegion(BRegion& r, const DrawState *d) } } -// DrawRoundRect + +// FillRegion void -DrawingEngine::DrawRoundRect(BRect r, const float &xrad, - const float &yrad, const DrawState *d, - bool filled) +DrawingEngine::FillRegion(BRegion& r, const RGBColor& color) { - if (Lock()) { - // NOTE: the stroke does not extend past "r" in R5, - // though I consider this unexpected behaviour. - make_rect_valid(r); - BRect clipped = fPainter->ClipRect(r); + // NOTE: Write locking because we might use HW acceleration. + // This needs to be investigated, I'm doing this because of + // gut feeling. + if (WriteLock()) { + BRect clipped = fPainter->ClipRect(r.Frame()); if (clipped.IsValid()) { fGraphicsCard->HideSoftwareCursor(clipped); - - fPainter->SetDrawState(d); - BRect touched = filled ? fPainter->FillRoundRect(r, xrad, yrad) - : fPainter->StrokeRoundRect(r, xrad, yrad); - - fGraphicsCard->Invalidate(touched); + + bool doInSoftware = true; + // try hardware optimized version first + if ((fAvailableHWAccleration & HW_ACC_FILL_REGION) != 0) { + fGraphicsCard->FillRegion(r, color); + doInSoftware = false; + } + + if (doInSoftware) { + + int32 count = r.CountRects(); + for (int32 i = 0; i < count; i++) { + fPainter->FillRect(r.RectAt(i), color.GetColor32()); + } + BRect touched = r.Frame(); + + fGraphicsCard->Invalidate(touched); + } + fGraphicsCard->ShowSoftwareCursor(); } - Unlock(); + WriteUnlock(); } } -// DrawShape + void -DrawingEngine::DrawShape(const BRect& bounds, const int32& opCount, - const uint32* opList, const int32& ptCount, - const BPoint* ptList, const DrawState* d, - bool filled) +DrawingEngine::DrawRoundRect(BRect r, float xrad, float yrad, + const DrawState* d, bool filled) { - if (Lock()) { - fGraphicsCard->HideSoftwareCursor(); + if (!Lock()) + return; + + // NOTE: the stroke does not extend past "r" in R5, + // though I consider this unexpected behaviour. + make_rect_valid(r); + BRect clipped = fPainter->ClipRect(r); + if (clipped.IsValid()) { + fGraphicsCard->HideSoftwareCursor(clipped); fPainter->SetDrawState(d); - BRect touched = fPainter->DrawShape(opCount, opList, - ptCount, ptList, - filled); + BRect touched = filled ? fPainter->FillRoundRect(r, xrad, yrad) + : fPainter->StrokeRoundRect(r, xrad, yrad); fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); - - Unlock(); } + + Unlock(); } -// DrawTriangle + +void +DrawingEngine::DrawShape(const BRect& bounds, int32 opCount, + const uint32* opList, int32 ptCount, const BPoint* ptList, + const DrawState* d, bool filled) +{ + if (!Lock()) + return; + + fGraphicsCard->HideSoftwareCursor(); + + fPainter->SetDrawState(d); + BRect touched = fPainter->DrawShape(opCount, opList, + ptCount, ptList, + filled); + + fGraphicsCard->Invalidate(touched); + fGraphicsCard->ShowSoftwareCursor(); + + Unlock(); +} + + void DrawingEngine::DrawTriangle(BPoint* pts, const BRect& bounds, - const DrawState* d, bool filled) + const DrawState* d, bool filled) { if (Lock()) { BRect clipped(bounds); @@ -840,13 +873,13 @@ DrawingEngine::DrawTriangle(BPoint* pts, const BRect& bounds, clipped = fPainter->ClipRect(clipped); if (clipped.IsValid()) { fGraphicsCard->HideSoftwareCursor(clipped); - + fPainter->SetDrawState(d); if (filled) fPainter->FillTriangle(pts[0], pts[1], pts[2]); else fPainter->StrokeTriangle(pts[0], pts[1], pts[2]); - + fGraphicsCard->Invalidate(clipped); fGraphicsCard->ShowSoftwareCursor(); } @@ -892,9 +925,9 @@ DrawingEngine::StrokeLine(const BPoint &start, const BPoint &end, DrawState* con touched = fPainter->ClipRect(touched); if (touched.IsValid()) { fGraphicsCard->HideSoftwareCursor(touched); - + touched = fPainter->StrokeLine(start, end, context); - + fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); } @@ -905,13 +938,12 @@ DrawingEngine::StrokeLine(const BPoint &start, const BPoint &end, DrawState* con // StrokeLineArray void -DrawingEngine::StrokeLineArray(const int32 &numlines, - const LineArrayData *linedata, - const DrawState *d) +DrawingEngine::StrokeLineArray(int32 numLines, + const LineArrayData *linedata, const DrawState *d) { - if(!d || !linedata || numlines <= 0) + if (!d || !linedata || numLines <= 0) return; - + if (Lock()) { // figure out bounding box for line array const LineArrayData *data = (const LineArrayData *)&(linedata[0]); @@ -919,7 +951,8 @@ DrawingEngine::StrokeLineArray(const int32 &numlines, min_c(data->pt1.y, data->pt2.y), max_c(data->pt1.x, data->pt2.x), max_c(data->pt1.y, data->pt2.y)); - for (int32 i = 1; i < numlines; i++) { + + for (int32 i = 1; i < numLines; i++) { data = (const LineArrayData *)&(linedata[i]); BRect box(min_c(data->pt1.x, data->pt2.x), min_c(data->pt1.y, data->pt2.y), @@ -931,20 +964,20 @@ DrawingEngine::StrokeLineArray(const int32 &numlines, touched = fPainter->ClipRect(touched); if (touched.IsValid()) { fGraphicsCard->HideSoftwareCursor(touched); - + DrawState context; context.SetDrawingMode(B_OP_COPY); - + data = (const LineArrayData *)&(linedata[0]); context.SetHighColor(data->color); fPainter->StrokeLine(data->pt1, data->pt2, &context); - - for (int32 i = 1; i < numlines; i++) { + + for (int32 i = 1; i < numLines; i++) { data = (const LineArrayData *)&(linedata[i]); context.SetHighColor(data->color); fPainter->StrokeLine(data->pt1, data->pt2, &context); } - + fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); } @@ -1007,11 +1040,11 @@ DrawingEngine::DrawString(const char* string, int32 length, if (b.IsValid()) { //printf("bounding box '%s': %lld µs\n", string, system_time() - now); fGraphicsCard->HideSoftwareCursor(b); - + //now = system_time(); BRect touched = fPainter->DrawString(string, length, pt, delta); //printf("drawing string: %lld µs\n", system_time() - now); - + fGraphicsCard->Invalidate(touched); fGraphicsCard->ShowSoftwareCursor(); } @@ -1119,22 +1152,20 @@ DrawingEngine::DumpToBitmap() return NULL; } -// _CopyRect + BRect DrawingEngine::_CopyRect(BRect src, int32 xOffset, int32 yOffset) const { BRect dst; RenderingBuffer* buffer = fGraphicsCard->DrawingBuffer(); if (buffer) { - BRect clip(0, 0, buffer->Width() - 1, buffer->Height() - 1); dst = src; dst.OffsetBy(xOffset, yOffset); if (clip.Intersects(src) && clip.Intersects(dst)) { - - uint32 bpr = buffer->BytesPerRow(); + uint32 bytesPerRow = buffer->BytesPerRow(); uint8* bits = (uint8*)buffer->Bits(); // clip source rect @@ -1146,12 +1177,12 @@ DrawingEngine::_CopyRect(BRect src, int32 xOffset, int32 yOffset) const src = src & dst; // calc offset in buffer - bits += (int32)src.left * 4 + (int32)src.top * bpr; + bits += (int32)src.left * 4 + (int32)src.top * bytesPerRow; uint32 width = src.IntegerWidth() + 1; uint32 height = src.IntegerHeight() + 1; - _CopyRect(bits, width, height, bpr, xOffset, yOffset); + _CopyRect(bits, width, height, bytesPerRow, xOffset, yOffset); // offset dest again, because it is return value dst.OffsetBy(xOffset, yOffset); @@ -1160,10 +1191,10 @@ DrawingEngine::_CopyRect(BRect src, int32 xOffset, int32 yOffset) const return dst; } -// _CopyRect + void DrawingEngine::_CopyRect(uint8* src, uint32 width, uint32 height, - uint32 bpr, int32 xOffset, int32 yOffset) const + uint32 bytesPerRow, int32 xOffset, int32 yOffset) const { int32 xIncrement; int32 yIncrement; @@ -1179,14 +1210,14 @@ DrawingEngine::_CopyRect(uint8* src, uint32 width, uint32 height, if (yOffset > 0) { // copy from bottom to top - yIncrement = -bpr; - src += (height - 1) * bpr; + yIncrement = -bytesPerRow; + src += (height - 1) * bytesPerRow; } else { // copy from top to bottom - yIncrement = bpr; + yIncrement = bytesPerRow; } - uint8* dst = src + yOffset * bpr + xOffset * 4; + uint8* dst = src + yOffset * bytesPerRow + xOffset * 4; for (uint32 y = 0; y < height; y++) { uint32* srcHandle = (uint32*)src; diff --git a/src/servers/app/drawing/Painter/font_support/AGGTextRenderer.cpp b/src/servers/app/drawing/Painter/font_support/AGGTextRenderer.cpp index 70ce1af562..fcfc63d3d1 100644 --- a/src/servers/app/drawing/Painter/font_support/AGGTextRenderer.cpp +++ b/src/servers/app/drawing/Painter/font_support/AGGTextRenderer.cpp @@ -231,9 +231,9 @@ AGGTextRenderer::RenderString(const char* string, // by the x y location of the glyph along the base line, // it is therefor yet "untransformed". const agg::rect& r = glyph->bounds; - BRect glyphBounds(r.x1 + x, r.y1 + y - 1, r.x2 + x + 1, r.y2 + y); - // NOTE: "- 1"/"+ 1" fixes some weird problem with the bounding box - // might be a bug in AGG + BRect glyphBounds(r.x1 + x, r.y1 + y - 1, r.x2 + x + 1, r.y2 + y + 1); + // NOTE: "-1"/"+ 1" converts the glyph bounding box from pixel + // indices to pixel area coordinates // track bounding box if (glyphBounds.IsValid()) diff --git a/src/tests/servers/app/Jamfile b/src/tests/servers/app/Jamfile index b2cdac031d..d8a50d0a11 100644 --- a/src/tests/servers/app/Jamfile +++ b/src/tests/servers/app/Jamfile @@ -77,7 +77,6 @@ Server haiku_app_server : # Misc. Sources Decorator.cpp DebugInfoManager.cpp - SubWindowList.cpp PNGDump.cpp RAMLinkMsgReader.cpp MessageLooper.cpp @@ -108,13 +107,13 @@ Server haiku_app_server : VirtualScreen.cpp BitmapHWInterface.cpp DefaultDecorator.cpp - Layer.cpp OffscreenServerWindow.cpp OffscreenWindowLayer.cpp - RootLayer.cpp ServerPicture.cpp ServerScreen.cpp + ViewLayer.cpp WindowLayer.cpp + WindowList.cpp Workspace.cpp WorkspacesLayer.cpp