diff --git a/src/tests/servers/app/newerClipping/ClientLooper.cpp b/src/tests/servers/app/newerClipping/ClientLooper.cpp index eb6e2356e0..7cba05937c 100644 --- a/src/tests/servers/app/newerClipping/ClientLooper.cpp +++ b/src/tests/servers/app/newerClipping/ClientLooper.cpp @@ -1,8 +1,13 @@ +#include #include +#include #include #include +#include +#include +#include #include #include "WindowLayer.h" @@ -11,6 +16,71 @@ #define SLOW_DRAWING 0 +#define SPEED 2.0 + +// random_number_between +static float +random_number_between(float v1, float v2) +{ + if (v1 < v2) + return v1 + fmod(rand() / 1000.0, (v2 - v1)); + else if (v2 < v1) + return v2 + fmod(rand() / 1000.0, (v1 - v2)); + return v1; +} + +// init_polygon +static void +init_polygon(const BRect& b, point* polygon) +{ + polygon[0].x = b.left; + polygon[0].y = b.top; + polygon[0].direction_x = random_number_between(-SPEED, SPEED); + polygon[0].direction_y = random_number_between(-SPEED, SPEED); + polygon[1].x = b.right; + polygon[1].y = b.top; + polygon[1].direction_x = random_number_between(-SPEED, SPEED); + polygon[1].direction_y = random_number_between(-SPEED, SPEED); + polygon[2].x = b.right; + polygon[2].y = b.bottom; + polygon[2].direction_x = random_number_between(-SPEED, SPEED); + polygon[2].direction_y = random_number_between(-SPEED, SPEED); + polygon[3].x = b.left; + polygon[3].y = b.bottom; + polygon[3].direction_x = random_number_between(-SPEED, SPEED); + polygon[3].direction_y = random_number_between(-SPEED, SPEED); +} + +// morph +static inline void +morph(double* value, double* direction, double min, double max) +{ + *value += *direction; + if (*value < min) { + *value = min; + *direction = -*direction; + } else if (*value > max) { + *value = max; + *direction = -*direction; + } +} + +// morph_polygon +static inline void +morph_polygon(const BRect& b, point* polygon) +{ + morph(&polygon[0].x, &polygon[0].direction_x, b.left, b.right); + morph(&polygon[1].x, &polygon[1].direction_x, b.left, b.right); + morph(&polygon[2].x, &polygon[2].direction_x, b.left, b.right); + morph(&polygon[3].x, &polygon[3].direction_x, b.left, b.right); + morph(&polygon[0].y, &polygon[0].direction_y, b.top, b.bottom); + morph(&polygon[1].y, &polygon[1].direction_y, b.top, b.bottom); + morph(&polygon[2].y, &polygon[2].direction_y, b.top, b.bottom); + morph(&polygon[3].y, &polygon[3].direction_y, b.top, b.bottom); +} + + + // constructor ClientLooper::ClientLooper(const char* name, WindowLayer* serverWindow) : BLooper("", B_DISPLAY_PRIORITY), @@ -20,11 +90,17 @@ ClientLooper::ClientLooper(const char* name, WindowLayer* serverWindow) BString clientName(name); clientName << " client"; SetName(clientName.String()); + + BMessenger messenger(this); + fTicker = new BMessageRunner(messenger, new BMessage(MSG_TICK), 40000); + + init_polygon(BRect(0, 0, 100, 100), fPolygon); } // destructor ClientLooper::~ClientLooper() { + delete fTicker; } // MessageReceived @@ -40,9 +116,13 @@ ClientLooper::MessageReceived(BMessage* message) // the client is slow // snooze(40000L); // send the command to redraw a view - BMessage command(MSG_DRAWING_COMMAND); - command.AddInt32("token", i); - fServerWindow->PostMessage(&command); + if (i == 5) { + _DrawAnimatedLayer(i); + } else { + BMessage command(MSG_DRAWING_COMMAND); + command.AddInt32("token", i); + fServerWindow->PostMessage(&command); + } } fServerWindow->PostMessage(MSG_END_UPDATE); @@ -69,8 +149,33 @@ ClientLooper::MessageReceived(BMessage* message) fServerWindow->PostMessage(MSG_SHOW); break; + case MSG_TICK: { + BMessage invalidate(MSG_INVALIDATE_VIEW); + invalidate.AddInt32("token", 5); + fServerWindow->PostMessage(&invalidate); + + morph_polygon(BRect(0, 0, 100, 100), fPolygon); + break; + } + default: BLooper::MessageReceived(message); break; } } + +// _DrawAnimatedLayer +void +ClientLooper::_DrawAnimatedLayer(int32 token) +{ + BMessage message(MSG_DRAW_POLYGON); + message.AddInt32("token", token); + + message.AddPoint("point", BPoint(fPolygon[0].x, fPolygon[0].y)); + message.AddPoint("point", BPoint(fPolygon[1].x, fPolygon[1].y)); + message.AddPoint("point", BPoint(fPolygon[2].x, fPolygon[2].y)); + message.AddPoint("point", BPoint(fPolygon[3].x, fPolygon[3].y)); + + fServerWindow->PostMessage(&message); +} + diff --git a/src/tests/servers/app/newerClipping/ClientLooper.h b/src/tests/servers/app/newerClipping/ClientLooper.h index 425ee851c4..6d16477313 100644 --- a/src/tests/servers/app/newerClipping/ClientLooper.h +++ b/src/tests/servers/app/newerClipping/ClientLooper.h @@ -12,6 +12,15 @@ enum { MSG_VIEWS_REMOVED = 'vwrm', MSG_WINDOW_HIDDEN = 'whdn', + + MSG_TICK = 'tick', +}; + +struct point { + double x; + double y; + double direction_x; + double direction_y; }; class ClientLooper : public BLooper { @@ -25,6 +34,13 @@ class ClientLooper : public BLooper { private: WindowLayer* fServerWindow; int32 fViewCount; + + BMessageRunner* fTicker; + + + void _DrawAnimatedLayer(int32 token); + + point fPolygon[4]; }; #endif // CLIENT_LOOPER_H diff --git a/src/tests/servers/app/newerClipping/WindowLayer.cpp b/src/tests/servers/app/newerClipping/WindowLayer.cpp index 8c03dd2b4c..5c4ac7d414 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.cpp +++ b/src/tests/servers/app/newerClipping/WindowLayer.cpp @@ -22,6 +22,9 @@ // the update session, which tells us the cause of the update #define DELAYED_BACKGROUND_CLEARING 1 +// IMPORTANT: nested ReadLockClipping()s are not supported (by MultiLocker) + + // constructor WindowLayer::WindowLayer(BRect frame, const char* name, DrawingEngine* drawingEngine, Desktop* desktop) @@ -75,6 +78,9 @@ WindowLayer::WindowLayer(BRect frame, const char* name, // destructor WindowLayer::~WindowLayer() { + fClient->Lock(); + fClient->Quit(); + delete fTopLayer; } @@ -117,6 +123,27 @@ WindowLayer::MessageReceived(BMessage* message) _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()) { @@ -386,6 +413,26 @@ WindowLayer::MarkContentDirty(BRegion* regionOnScreen) } } +// InvalidateView +void +WindowLayer::InvalidateView(int32 token) +{ + if (fDesktop && fDesktop->ReadLockClipping()) { + + ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token); + if (!layer || !layer->IsVisible()) { + fDesktop->ReadUnlockClipping(); + return; + } + if (!fContentRegionValid) + _UpdateContentRegion(); + + _MarkContentDirty(&layer->ScreenClipping(&fContentRegion)); + + fDesktop->ReadUnlockClipping(); + } +} + //# pragma mark - // CopyContents @@ -507,12 +554,14 @@ WindowLayer::_DrawClient(int32 token) // We have to be sure that the clipping is up to date. // If true readlocking would work correctly, this would // not be an issue - ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token); - if (!layer || !layer->IsVisible()) - return; - if (fDesktop->ReadLockClipping()) { + ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token); + if (!layer || !layer->IsVisible()) { + fDesktop->ReadUnlockClipping(); + return; + } + if (!fEffectiveDrawingRegionValid) { fEffectiveDrawingRegion = VisibleContentRegion(); if (fInUpdate) { @@ -551,6 +600,68 @@ WindowLayer::_DrawClient(int32 token) } } +// _DrawClientPolygon +void +WindowLayer::_DrawClientPolygon(int32 token, BPoint polygon[4]) +{ + if (fDesktop->ReadLockClipping()) { + + ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token); + if (!layer || !layer->IsVisible()) { + fDesktop->ReadUnlockClipping(); + return; + } + + if (!fEffectiveDrawingRegionValid) { + fEffectiveDrawingRegion = VisibleContentRegion(); + if (fInUpdate) { + // enforce the dirty region of the update session + fEffectiveDrawingRegion.IntersectWith(&fCurrentUpdateSession.DirtyRegion()); + } else { + printf("%s - _DrawClient(token: %ld) - not in update\n", Name(), token); + } + fEffectiveDrawingRegionValid = true; + } + + BRegion effectiveClipping(fEffectiveDrawingRegion); + if (!fContentRegionValid) + _UpdateContentRegion(); + effectiveClipping.IntersectWith(&layer->ScreenClipping(&fContentRegion)); + + if (effectiveClipping.CountRects() > 0) { +#if DELAYED_BACKGROUND_CLEARING + layer->Draw(fDrawingEngine, &effectiveClipping, + &fContentRegion, false); +#endif + + if (fDrawingEngine->Lock()) { + + fDrawingEngine->PushState(); + fDrawingEngine->ConstrainClippingRegion(&effectiveClipping); + fDrawingEngine->SetPenSize(3); +// fDrawingEngine->SetDrawingMode(B_OP_BLEND); + layer->ConvertToTop(&polygon[0]); + layer->ConvertToTop(&polygon[1]); + layer->ConvertToTop(&polygon[2]); + layer->ConvertToTop(&polygon[3]); + fDrawingEngine->BeginLineArray(4); + fDrawingEngine->AddLine(polygon[0], polygon[1], layer->ViewColor()); + fDrawingEngine->AddLine(polygon[1], polygon[2], layer->ViewColor()); + fDrawingEngine->AddLine(polygon[2], polygon[3], layer->ViewColor()); + fDrawingEngine->AddLine(polygon[3], polygon[0], layer->ViewColor()); + fDrawingEngine->EndLineArray(); + + fDrawingEngine->PopState(); + fDrawingEngine->MarkDirty(&effectiveClipping); + fDrawingEngine->Unlock(); + } + } + + fDesktop->ReadUnlockClipping(); + } +} + + // _DrawBorder void WindowLayer::_DrawBorder() diff --git a/src/tests/servers/app/newerClipping/WindowLayer.h b/src/tests/servers/app/newerClipping/WindowLayer.h index 8943a033f0..15e78af13d 100644 --- a/src/tests/servers/app/newerClipping/WindowLayer.h +++ b/src/tests/servers/app/newerClipping/WindowLayer.h @@ -14,14 +14,17 @@ class Desktop; class DrawingEngine; enum { - MSG_REDRAW = 'rdrw', + MSG_REDRAW = 'rdrw', // client messages - MSG_BEGIN_UPDATE = 'bgud', - MSG_END_UPDATE = 'edud', - MSG_DRAWING_COMMAND = 'draw', + MSG_BEGIN_UPDATE = 'bgud', + MSG_END_UPDATE = 'edud', + MSG_DRAWING_COMMAND = 'draw', - MSG_SHOW = 'show', + MSG_SHOW = 'show', + + MSG_INVALIDATE_VIEW = 'invl', + MSG_DRAW_POLYGON = 'drwp', }; class UpdateSession { @@ -82,6 +85,7 @@ class WindowLayer : public BLooper { void MarkDirty(BRegion* regionOnScreen); void MarkContentDirty(BRegion* regionOnScreen); + void InvalidateView(int32 token); void ProcessDirtyRegion(BRegion* region); @@ -98,6 +102,7 @@ class WindowLayer : public BLooper { // different types of drawing void _TriggerContentRedraw(); void _DrawClient(int32 token); + void _DrawClientPolygon(int32 token, BPoint polygon[4]); void _DrawBorder(); // handling update sessions diff --git a/src/tests/servers/app/newerClipping/main.cpp b/src/tests/servers/app/newerClipping/main.cpp index cb6221bbc2..8f2b3f0f1e 100644 --- a/src/tests/servers/app/newerClipping/main.cpp +++ b/src/tests/servers/app/newerClipping/main.cpp @@ -220,6 +220,8 @@ Window::Test() int main(int argc, const char* argv[]) { + srand((long int)system_time()); + App app; app.Run(); return 0;