1bef1ed93SStephan Aßmus
2bef1ed93SStephan Aßmus#include <new>
3bef1ed93SStephan Aßmus#include <stdio.h>
4bef1ed93SStephan Aßmus
5bef1ed93SStephan Aßmus#include <Message.h>
6bef1ed93SStephan Aßmus#include <MessageQueue.h>
7bef1ed93SStephan Aßmus
8ff89d51eSStephan Aßmus#include "ClientLooper.h"
9bef1ed93SStephan Aßmus#include "Desktop.h"
10bef1ed93SStephan Aßmus#include "DrawingEngine.h"
11bef1ed93SStephan Aßmus
12bef1ed93SStephan Aßmus#include "WindowLayer.h"
13bef1ed93SStephan Aßmus
144dd89c69SStephan Aßmus// if the background clearing is delayed until
154dd89c69SStephan Aßmus// the client draws the view, we have less flickering
164dd89c69SStephan Aßmus// when contents have to be redrawn because of resizing
174dd89c69SStephan Aßmus// a window or because the client invalidates parts.
184dd89c69SStephan Aßmus// when redrawing something that has been exposed from underneath
194dd89c69SStephan Aßmus// other windows, the other window will be seen longer at
204dd89c69SStephan Aßmus// its previous position though if the exposed parts are not
214dd89c69SStephan Aßmus// cleared right away. maybe there ought to be a flag in
224dd89c69SStephan Aßmus// the update session, which tells us the cause of the update
234dd89c69SStephan Aßmus#define DELAYED_BACKGROUND_CLEARING 1
24bef1ed93SStephan Aßmus
25727653f7SStephan Aßmus// IMPORTANT: nested ReadLockClipping()s are not supported (by MultiLocker)
26727653f7SStephan Aßmus
27727653f7SStephan Aßmus
28bef1ed93SStephan Aßmus// constructor
29bef1ed93SStephan AßmusWindowLayer::WindowLayer(BRect frame, const char* name,
30bef1ed93SStephan Aßmus						 DrawingEngine* drawingEngine, Desktop* desktop)
314dd89c69SStephan Aßmus	: BLooper(name, B_DISPLAY_PRIORITY),
32bef1ed93SStephan Aßmus	  fFrame(frame),
337f705589SStephan Aßmus
34bef1ed93SStephan Aßmus	  fVisibleRegion(),
357f705589SStephan Aßmus	  fVisibleContentRegion(),
367fd1af6fSStephan Aßmus	  fVisibleContentRegionValid(false),
37c63a78aaSStephan Aßmus	  fDirtyRegion(),
38bef1ed93SStephan Aßmus
390b78f37eSStephan Aßmus	  fBorderRegion(),
400b78f37eSStephan Aßmus	  fBorderRegionValid(false),
410b78f37eSStephan Aßmus	  fContentRegion(),
420b78f37eSStephan Aßmus	  fContentRegionValid(false),
437f705589SStephan Aßmus	  fEffectiveDrawingRegion(),
447f705589SStephan Aßmus	  fEffectiveDrawingRegionValid(false),
450b78f37eSStephan Aßmus
460b78f37eSStephan Aßmus	  fFocus(false),
47bef1ed93SStephan Aßmus
48bef1ed93SStephan Aßmus	  fTopLayer(NULL),
49bef1ed93SStephan Aßmus
5012aa597dSAdi Oanca// TODO: windows must start hidden!
5112aa597dSAdi Oanca	  fHidden(false),
5212aa597dSAdi Oanca	  // windows start hidden
5312aa597dSAdi Oanca//	  fHidden(true),
5412aa597dSAdi Oanca
55bef1ed93SStephan Aßmus	  fDrawingEngine(drawingEngine),
56ff89d51eSStephan Aßmus	  fDesktop(desktop),
57ff89d51eSStephan Aßmus
58ff89d51eSStephan Aßmus	  fTokenViewMap(64),
59ff89d51eSStephan Aßmus
60ff89d51eSStephan Aßmus	  fClient(new ClientLooper(name, this)),
617fd1af6fSStephan Aßmus	  fCurrentUpdateSession(),
627fd1af6fSStephan Aßmus	  fPendingUpdateSession(),
63ff89d51eSStephan Aßmus	  fUpdateRequested(false),
64ff89d51eSStephan Aßmus	  fInUpdate(false)
65bef1ed93SStephan Aßmus{
66bef1ed93SStephan Aßmus	// the top layer is special, it has a coordinate system
67bef1ed93SStephan Aßmus	// as if it was attached directly to the desktop, therefor,
68bef1ed93SStephan Aßmus	// the coordinate conversion through the layer tree works
69bef1ed93SStephan Aßmus	// as expected, since the top layer has no "parent" but has
70bef1ed93SStephan Aßmus	// fFrame as if it had
71bef1ed93SStephan Aßmus	fTopLayer = new(nothrow) ViewLayer(fFrame, "top view", B_FOLLOW_ALL, 0,
72bef1ed93SStephan Aßmus									   (rgb_color){ 255, 255, 255, 255 });
73748533bbSStephan Aßmus	fTopLayer->AttachedToWindow(this);
74ff89d51eSStephan Aßmus
75ff89d51eSStephan Aßmus	fClient->Run();
76bef1ed93SStephan Aßmus}
77bef1ed93SStephan Aßmus
78bef1ed93SStephan Aßmus// destructor
79bef1ed93SStephan AßmusWindowLayer::~WindowLayer()
80bef1ed93SStephan Aßmus{
81bef1ed93SStephan Aßmus	delete fTopLayer;
82bef1ed93SStephan Aßmus}
83bef1ed93SStephan Aßmus
84bef1ed93SStephan Aßmus// MessageReceived
85bef1ed93SStephan Aßmusvoid
86bef1ed93SStephan AßmusWindowLayer::MessageReceived(BMessage* message)
87bef1ed93SStephan Aßmus{
88bef1ed93SStephan Aßmus	switch (message->what) {
89bef1ed93SStephan Aßmus		case MSG_REDRAW: {
90312345bcSStephan Aßmus			// there is only one MSG_REDRAW in the queue at anytime
91312345bcSStephan Aßmus			if (fDesktop->ReadLockClipping()) {
92312345bcSStephan Aßmus
93bef1ed93SStephan Aßmus				_DrawBorder();
94748533bbSStephan Aßmus				_TriggerContentRedraw();
95ff89d51eSStephan Aßmus
96c63a78aaSStephan Aßmus				// reset the dirty region, since
97c63a78aaSStephan Aßmus				// we're fully clean. If the desktop
98c63a78aaSStephan Aßmus				// thread wanted to mark something
99c63a78aaSStephan Aßmus				// dirty in the mean time, it was
100c63a78aaSStephan Aßmus				// blocking on the global region lock to
101c63a78aaSStephan Aßmus				// get write access, since we held the
102c63a78aaSStephan Aßmus				// read lock for the whole time.
103c63a78aaSStephan Aßmus				fDirtyRegion.MakeEmpty();
104c63a78aaSStephan Aßmus
105bef1ed93SStephan Aßmus				fDesktop->ReadUnlockClipping();
106bef1ed93SStephan Aßmus			} else {
107bef1ed93SStephan Aßmus//printf("%s MSG_REDRAW -> pending redraws\n", Name());
108bef1ed93SStephan Aßmus			}
109bef1ed93SStephan Aßmus			break;
110bef1ed93SStephan Aßmus		}
111ff89d51eSStephan Aßmus		case MSG_BEGIN_UPDATE:
112ff89d51eSStephan Aßmus			_BeginUpdate();
113ff89d51eSStephan Aßmus			break;
114ff89d51eSStephan Aßmus		case MSG_END_UPDATE:
115ff89d51eSStephan Aßmus			_EndUpdate();
116ff89d51eSStephan Aßmus			break;
117ff89d51eSStephan Aßmus		case MSG_DRAWING_COMMAND: {
118ff89d51eSStephan Aßmus			int32 token;
119ff89d51eSStephan Aßmus			if (message->FindInt32("token", &token) >= B_OK)
120ff89d51eSStephan Aßmus				_DrawClient(token);
121ff89d51eSStephan Aßmus			break;
122ff89d51eSStephan Aßmus		}
123727653f7SStephan Aßmus		case MSG_DRAW_POLYGON: {
124727653f7SStephan Aßmus			int32 token;
125727653f7SStephan Aßmus			BPoint polygon[4];
126727653f7SStephan Aßmus			if (message->FindInt32("token", &token) >= B_OK &&
127727653f7SStephan Aßmus				message->FindPoint("point", 0, &polygon[0]) >= B_OK &&
128727653f7SStephan Aßmus				message->FindPoint("point", 1, &polygon[1]) >= B_OK &&
129727653f7SStephan Aßmus				message->FindPoint("point", 2, &polygon[2]) >= B_OK &&
130727653f7SStephan Aßmus				message->FindPoint("point", 3, &polygon[3]) >= B_OK) {
131727653f7SStephan Aßmus
132727653f7SStephan Aßmus				_DrawClientPolygon(token, polygon);
133727653f7SStephan Aßmus			}
134727653f7SStephan Aßmus			break;
135727653f7SStephan Aßmus
136727653f7SStephan Aßmus		}
137727653f7SStephan Aßmus
138727653f7SStephan Aßmus		case MSG_INVALIDATE_VIEW: {
139727653f7SStephan Aßmus			int32 token;
140727653f7SStephan Aßmus			if (message->FindInt32("token", &token) >= B_OK)
141727653f7SStephan Aßmus				InvalidateView(token);
142727653f7SStephan Aßmus			break;
143727653f7SStephan Aßmus		}
1448c8275c2SStephan Aßmus
1458c8275c2SStephan Aßmus		case MSG_SHOW:
1468c8275c2SStephan Aßmus			if (IsHidden()) {
1478c8275c2SStephan Aßmus				fDesktop->ShowWindow(this);
1488c8275c2SStephan Aßmus			}
1498c8275c2SStephan Aßmus			break;
150bef1ed93SStephan Aßmus		default:
151bef1ed93SStephan Aßmus			BLooper::MessageReceived(message);
152bef1ed93SStephan Aßmus			break;
153bef1ed93SStephan Aßmus	}
154bef1ed93SStephan Aßmus}
155bef1ed93SStephan Aßmus
156a825e403SStephan Aßmus// QuitRequested
157a825e403SStephan Aßmusbool
158a825e403SStephan AßmusWindowLayer::QuitRequested()
159a825e403SStephan Aßmus{
160a825e403SStephan Aßmus	if (fDesktop && fDesktop->LockClipping()) {
161a825e403SStephan Aßmus		fDesktop->WindowDied(this);
162a825e403SStephan Aßmus
163a825e403SStephan Aßmus		fClient->Lock();
164a825e403SStephan Aßmus		fClient->Quit();
165a825e403SStephan Aßmus
166a825e403SStephan Aßmus		fDesktop->UnlockClipping();
167a825e403SStephan Aßmus	}
168a825e403SStephan Aßmus	return true;
169a825e403SStephan Aßmus}
170a825e403SStephan Aßmus
171bef1ed93SStephan Aßmus// SetClipping
172bef1ed93SStephan Aßmusvoid
173bef1ed93SStephan AßmusWindowLayer::SetClipping(BRegion* stillAvailableOnScreen)
174bef1ed93SStephan Aßmus{
1757f705589SStephan Aßmus	// this function is only called from the Desktop thread
1767f705589SStephan Aßmus
177bef1ed93SStephan Aßmus	// start from full region (as if the window was fully visible)
178bef1ed93SStephan Aßmus	GetFullRegion(&fVisibleRegion);
179bef1ed93SStephan Aßmus	// clip to region still available on screen
180bef1ed93SStephan Aßmus	fVisibleRegion.IntersectWith(stillAvailableOnScreen);
1817f705589SStephan Aßmus
1827fd1af6fSStephan Aßmus	fVisibleContentRegionValid = false;
1837f705589SStephan Aßmus	fEffectiveDrawingRegionValid = false;
184bef1ed93SStephan Aßmus}
185bef1ed93SStephan Aßmus
186bef1ed93SStephan Aßmus// GetFullRegion
187bef1ed93SStephan Aßmusvoid
188bef1ed93SStephan AßmusWindowLayer::GetFullRegion(BRegion* region) const
189bef1ed93SStephan Aßmus{
190bef1ed93SStephan Aßmus	// start from the frame, extend to include decorator border
191bef1ed93SStephan Aßmus	region->Set(BRect(fFrame.left - 4, fFrame.top - 4,
192bef1ed93SStephan Aßmus					  fFrame.right + 4, fFrame.bottom + 4));
193bef1ed93SStephan Aßmus	// add the title tab
194bef1ed93SStephan Aßmus	region->Include(BRect(fFrame.left - 4, fFrame.top - 20,
195e76d86d5SStephan Aßmus						  ceilf((fFrame.left + fFrame.right) / 2), fFrame.top - 5));
196bef1ed93SStephan Aßmus}
197bef1ed93SStephan Aßmus
198bef1ed93SStephan Aßmus// GetBorderRegion
199bef1ed93SStephan Aßmusvoid
2007f705589SStephan AßmusWindowLayer::GetBorderRegion(BRegion* region)
201bef1ed93SStephan Aßmus{
2027f705589SStephan Aßmus	if (!fBorderRegionValid) {
203d0e89d53SStephan Aßmus		fBorderRegion.Set(BRect(fFrame.left - 4, fFrame.top - 20,
204e76d86d5SStephan Aßmus							  	ceilf((fFrame.left + fFrame.right) / 2), fFrame.top - 5));
205d0e89d53SStephan Aßmus		fBorderRegion.Include(BRect(fFrame.left - 4, fFrame.top - 4,
206d0e89d53SStephan Aßmus									fFrame.right + 4, fFrame.top - 1));
207d0e89d53SStephan Aßmus		fBorderRegion.Include(BRect(fFrame.left - 4, fFrame.top,
208d0e89d53SStephan Aßmus									fFrame.left - 1, fFrame.bottom));
209d0e89d53SStephan Aßmus		fBorderRegion.Include(BRect(fFrame.right + 1, fFrame.top,
210d0e89d53SStephan Aßmus									fFrame.right + 4, fFrame.bottom - 11));
211d0e89d53SStephan Aßmus		fBorderRegion.Include(BRect(fFrame.left - 4, fFrame.bottom + 1,
212d0e89d53SStephan Aßmus									fFrame.right - 11, fFrame.bottom + 4));
213d0e89d53SStephan Aßmus		fBorderRegion.Include(BRect(fFrame.right - 10, fFrame.bottom - 10,
214d0e89d53SStephan Aßmus									fFrame.right + 4, fFrame.bottom + 4));
2157f705589SStephan Aßmus		fBorderRegionValid = true;
2160b78f37eSStephan Aßmus	}
2170b78f37eSStephan Aßmus
2187f705589SStephan Aßmus	*region = fBorderRegion;
219bef1ed93SStephan Aßmus}
220bef1ed93SStephan Aßmus
2210b78f37eSStephan Aßmus// GetContentRegion
2220b78f37eSStephan Aßmusvoid
2237f705589SStephan AßmusWindowLayer::GetContentRegion(BRegion* region)
2240b78f37eSStephan Aßmus{
2257f705589SStephan Aßmus	if (!fContentRegionValid) {
2261ba9992dSStephan Aßmus		_UpdateContentRegion();
2277f705589SStephan Aßmus	}
2280b78f37eSStephan Aßmus
2297f705589SStephan Aßmus	*region = fContentRegion;
2300b78f37eSStephan Aßmus}
2310b78f37eSStephan Aßmus
2327fd1af6fSStephan Aßmus// VisibleContentRegion
2337fd1af6fSStephan AßmusBRegion&
2347fd1af6fSStephan AßmusWindowLayer::VisibleContentRegion()
2357fd1af6fSStephan Aßmus{
2367fd1af6fSStephan Aßmus	// regions expected to be locked
2377fd1af6fSStephan Aßmus	if (!fVisibleContentRegionValid) {
2387fd1af6fSStephan Aßmus		GetContentRegion(&fVisibleContentRegion);
2397fd1af6fSStephan Aßmus		fVisibleContentRegion.IntersectWith(&fVisibleRegion);
2407fd1af6fSStephan Aßmus	}
2417fd1af6fSStephan Aßmus	return fVisibleContentRegion;
2427fd1af6fSStephan Aßmus}
2437fd1af6fSStephan Aßmus
2440b78f37eSStephan Aßmus// SetFocus
2450b78f37eSStephan Aßmusvoid
2460b78f37eSStephan AßmusWindowLayer::SetFocus(bool focus)
2470b78f37eSStephan Aßmus{
2484dd89c69SStephan Aßmus	// executed from Desktop thread
249312345bcSStephan Aßmus	// it holds the clipping write lock,
250312345bcSStephan Aßmus	// so the window thread cannot be
251312345bcSStephan Aßmus	// accessing fFocus
2524dd89c69SStephan Aßmus
253312345bcSStephan Aßmus	BRegion dirty(fBorderRegion);
254312345bcSStephan Aßmus	dirty.IntersectWith(&fVisibleRegion);
255312345bcSStephan Aßmus	fDesktop->MarkDirty(&dirty);
2560b78f37eSStephan Aßmus
257312345bcSStephan Aßmus	fFocus = focus;
2580b78f37eSStephan Aßmus}
2590b78f37eSStephan Aßmus
260bef1ed93SStephan Aßmus// MoveBy
261bef1ed93SStephan Aßmusvoid
262bef1ed93SStephan AßmusWindowLayer::MoveBy(int32 x, int32 y)
263bef1ed93SStephan Aßmus{
2647f705589SStephan Aßmus	// this function is only called from the desktop thread
2657f705589SStephan Aßmus
266bef1ed93SStephan Aßmus	if (x == 0 && y == 0)
267bef1ed93SStephan Aßmus		return;
268bef1ed93SStephan Aßmus
269bef1ed93SStephan Aßmus	fFrame.OffsetBy(x, y);
270bef1ed93SStephan Aßmus
271c63a78aaSStephan Aßmus	// take along the dirty region which have not
272c63a78aaSStephan Aßmus	// processed yet
273c63a78aaSStephan Aßmus	fDirtyRegion.OffsetBy(x, y);
274c63a78aaSStephan Aßmus
2750b78f37eSStephan Aßmus	if (fBorderRegionValid)
2760b78f37eSStephan Aßmus		fBorderRegion.OffsetBy(x, y);
2770b78f37eSStephan Aßmus	if (fContentRegionValid)
2780b78f37eSStephan Aßmus		fContentRegion.OffsetBy(x, y);
2790b78f37eSStephan Aßmus
2807fd1af6fSStephan Aßmus	if (fCurrentUpdateSession.IsUsed())
2817fd1af6fSStephan Aßmus		fCurrentUpdateSession.MoveBy(x, y);
2827fd1af6fSStephan Aßmus	if (fPendingUpdateSession.IsUsed())
2837fd1af6fSStephan Aßmus		fPendingUpdateSession.MoveBy(x, y);
284ff89d51eSStephan Aßmus
2857f705589SStephan Aßmus	fEffectiveDrawingRegionValid = false;
2867f705589SStephan Aßmus
2877f705589SStephan Aßmus	fTopLayer->MoveBy(x, y, NULL);
288bef1ed93SStephan Aßmus
2897f705589SStephan Aßmus	// the desktop will take care of dirty regions
290bef1ed93SStephan Aßmus}
291bef1ed93SStephan Aßmus
292bef1ed93SStephan Aßmus// ResizeBy
293bef1ed93SStephan Aßmusvoid
294bef1ed93SStephan AßmusWindowLayer::ResizeBy(int32 x, int32 y, BRegion* dirtyRegion)
295bef1ed93SStephan Aßmus{
2964dd89c69SStephan Aßmus	// this function is only called from the desktop thread
2974dd89c69SStephan Aßmus
298bef1ed93SStephan Aßmus	if (x == 0 && y == 0)
299bef1ed93SStephan Aßmus		return;
300bef1ed93SStephan Aßmus
301bef1ed93SStephan Aßmus	fFrame.right += x;
302bef1ed93SStephan Aßmus	fFrame.bottom += y;
303bef1ed93SStephan Aßmus
3047f705589SStephan Aßmus	// put the previous border region into the dirty region as well
3057f705589SStephan Aßmus	// to handle the part that was overlapping a layer
3067f705589SStephan Aßmus	dirtyRegion->Include(&fBorderRegion);
3077f705589SStephan Aßmus
3080b78f37eSStephan Aßmus	fBorderRegionValid = false;
3090b78f37eSStephan Aßmus	fContentRegionValid = false;
3107f705589SStephan Aßmus	fEffectiveDrawingRegionValid = false;
3110b78f37eSStephan Aßmus
312bef1ed93SStephan Aßmus	// the border is dirty, put it into
313bef1ed93SStephan Aßmus	// dirtyRegion for a start
3147f705589SStephan Aßmus	BRegion newBorderRegion;
3157f705589SStephan Aßmus	GetBorderRegion(&newBorderRegion);
3167f705589SStephan Aßmus	dirtyRegion->Include(&newBorderRegion);
3170b78f37eSStephan Aßmus
318bef1ed93SStephan Aßmus	fTopLayer->ResizeBy(x, y, dirtyRegion);
319bef1ed93SStephan Aßmus}
320bef1ed93SStephan Aßmus
3217943e1a8SStephan Aßmus// ScrollViewBy
3227943e1a8SStephan Aßmusvoid
3237943e1a8SStephan AßmusWindowLayer::ScrollViewBy(ViewLayer* view, int32 dx, int32 dy)
3247943e1a8SStephan Aßmus{
3257943e1a8SStephan Aßmus	// this can be executed from any thread, but if the
3267943e1a8SStephan Aßmus	// desktop thread is executing this, it should have
3277943e1a8SStephan Aßmus	// the write lock, otherwise it is not prevented
3287943e1a8SStephan Aßmus	// from executing this at the same time as the window
3297943e1a8SStephan Aßmus	// is doing something else here!
3307943e1a8SStephan Aßmus
3310bbd104aSStephan Aßmus	if (!view || view == fTopLayer || (dx == 0 && dy == 0))
3327943e1a8SStephan Aßmus		return;
3337943e1a8SStephan Aßmus
3347943e1a8SStephan Aßmus	if (fDesktop && fDesktop->ReadLockClipping()) {
3357943e1a8SStephan Aßmus
3367943e1a8SStephan Aßmus		BRegion dirty;
3377943e1a8SStephan Aßmus		view->ScrollBy(dx, dy, &dirty);
3387943e1a8SStephan Aßmus
3397943e1a8SStephan Aßmus		_MarkContentDirty(&dirty);
3407943e1a8SStephan Aßmus
3417943e1a8SStephan Aßmus		fDesktop->ReadUnlockClipping();
3427943e1a8SStephan Aßmus	}
3437943e1a8SStephan Aßmus}
3447943e1a8SStephan Aßmus
345bef1ed93SStephan Aßmus// AddChild
346bef1ed93SStephan Aßmusvoid
347bef1ed93SStephan AßmusWindowLayer::AddChild(ViewLayer* layer)
348bef1ed93SStephan Aßmus{
349bef1ed93SStephan Aßmus	fTopLayer->AddChild(layer);
350bef1ed93SStephan Aßmus
351ff89d51eSStephan Aßmus	// inform client about the view
352ff89d51eSStephan Aßmus	// (just a part of the simulation)
353ff89d51eSStephan Aßmus	fTokenViewMap.MakeEmpty();
354ff89d51eSStephan Aßmus	fTopLayer->CollectTokensForChildren(&fTokenViewMap);
355ff89d51eSStephan Aßmus	BMessage message(MSG_VIEWS_ADDED);
356ff89d51eSStephan Aßmus	message.AddInt32("count", fTokenViewMap.CountItems());
357ff89d51eSStephan Aßmus	fClient->PostMessage(&message);
358ff89d51eSStephan Aßmus
359bef1ed93SStephan Aßmus	// TODO: trigger redraw for dirty regions
360bef1ed93SStephan Aßmus}
361bef1ed93SStephan Aßmus
3627943e1a8SStephan Aßmus// ViewAt
3637943e1a8SStephan AßmusViewLayer*
3647943e1a8SStephan AßmusWindowLayer::ViewAt(const BPoint& where)
3657943e1a8SStephan Aßmus{
3667943e1a8SStephan Aßmus	if (!fContentRegionValid)
3677943e1a8SStephan Aßmus		_UpdateContentRegion();
3687943e1a8SStephan Aßmus
3697943e1a8SStephan Aßmus	return fTopLayer->ViewAt(where, &fContentRegion);
3707943e1a8SStephan Aßmus}
3717943e1a8SStephan Aßmus
3727943e1a8SStephan Aßmus// SetHidden
37312aa597dSAdi Oancavoid
3748c8275c2SStephan AßmusWindowLayer::SetHidden(bool hidden)
37512aa597dSAdi Oanca{
3767943e1a8SStephan Aßmus	// the desktop takes care of dirty regions
3778c8275c2SStephan Aßmus	if (fHidden != hidden) {
3788c8275c2SStephan Aßmus		fHidden = hidden;
37912aa597dSAdi Oanca
3808c8275c2SStephan Aßmus		fTopLayer->SetHidden(hidden);
38112aa597dSAdi Oanca
3828c8275c2SStephan Aßmus		// this is only for simulation purposes:
3838c8275c2SStephan Aßmus		if (fHidden)
3848c8275c2SStephan Aßmus			fClient->PostMessage(MSG_WINDOW_HIDDEN);
38512aa597dSAdi Oanca
3868c8275c2SStephan Aßmus		// TODO: anything else?
3878c8275c2SStephan Aßmus	}
38812aa597dSAdi Oanca}
38912aa597dSAdi Oanca
390c63a78aaSStephan Aßmus// ProcessDirtyRegion
391c63a78aaSStephan Aßmusvoid
392c63a78aaSStephan AßmusWindowLayer::ProcessDirtyRegion(BRegion* region)
393c63a78aaSStephan Aßmus{
3947e68917fSStephan Aßmus	// if this is exectuted in the desktop thread,
3957e68917fSStephan Aßmus	// it means that the window thread currently
3967e68917fSStephan Aßmus	// blocks to get the read lock, if it is
3977e68917fSStephan Aßmus	// executed from the window thread, it should
3987e68917fSStephan Aßmus	// have the read lock and the desktop thread
3997e68917fSStephan Aßmus	// is blocking to get the write lock. IAW, this
4007e68917fSStephan Aßmus	// is only executed in one thread.
401c63a78aaSStephan Aßmus	if (fDirtyRegion.CountRects() == 0) {
402c63a78aaSStephan Aßmus		// the window needs to be informed
4037e68917fSStephan Aßmus		// when the dirty region was empty.
4047e68917fSStephan Aßmus		// NOTE: when the window thread has processed
4057e68917fSStephan Aßmus		// the dirty region in MessageReceived(),
4067e68917fSStephan Aßmus		// it will make the region empty again,
4077e68917fSStephan Aßmus		// when it is empty here, we need to send
4087e68917fSStephan Aßmus		// the message to initiate the next update round.
4097e68917fSStephan Aßmus		// Until the message is processed in the window
4107e68917fSStephan Aßmus		// thread, the desktop thread can add parts to
4117e68917fSStephan Aßmus		// the region as it likes.
412c63a78aaSStephan Aßmus		PostMessage(MSG_REDRAW, this);
413c63a78aaSStephan Aßmus	}
414c63a78aaSStephan Aßmus	// this is executed from the desktop thread
415c63a78aaSStephan Aßmus	fDirtyRegion.Include(region);
416c63a78aaSStephan Aßmus}
417c63a78aaSStephan Aßmus
418bef1ed93SStephan Aßmus// MarkDirty
419bef1ed93SStephan Aßmusvoid
420bef1ed93SStephan AßmusWindowLayer::MarkDirty(BRegion* regionOnScreen)
421bef1ed93SStephan Aßmus{
4227e68917fSStephan Aßmus	// for marking any part of the desktop dirty
4237e68917fSStephan Aßmus	// this will get write access to the global
4247e68917fSStephan Aßmus	// region lock, and result in ProcessDirtyRegion()
4257e68917fSStephan Aßmus	// to be called for any windows affected
4260b78f37eSStephan Aßmus	if (fDesktop)
4270b78f37eSStephan Aßmus		fDesktop->MarkDirty(regionOnScreen);
428bef1ed93SStephan Aßmus}
429bef1ed93SStephan Aßmus
430987aa5e4SStephan Aßmus// MarkContentDirty
4317f705589SStephan Aßmusvoid
4327f705589SStephan AßmusWindowLayer::MarkContentDirty(BRegion* regionOnScreen)
4337f705589SStephan Aßmus{
4341ba9992dSStephan Aßmus	// for triggering MSG_REDRAW
4357e68917fSStephan Aßmus	// since this won't affect other windows, read locking
4367e68917fSStephan Aßmus	// is sufficient. If there was no dirty region before,
4377e68917fSStephan Aßmus	// an update message is triggered
4381ba9992dSStephan Aßmus	if (fDesktop && fDesktop->ReadLockClipping()) {
4397f705589SStephan Aßmus
4407fd1af6fSStephan Aßmus		regionOnScreen->IntersectWith(&VisibleContentRegion());
4411ba9992dSStephan Aßmus		ProcessDirtyRegion(regionOnScreen);
4427f705589SStephan Aßmus
4431ba9992dSStephan Aßmus		fDesktop->ReadUnlockClipping();
4441ba9992dSStephan Aßmus	}
4457f705589SStephan Aßmus}
446748533bbSStephan Aßmus
447727653f7SStephan Aßmus// InvalidateView
448727653f7SStephan Aßmusvoid
449727653f7SStephan AßmusWindowLayer::InvalidateView(int32 token)
450727653f7SStephan Aßmus{
451727653f7SStephan Aßmus	if (fDesktop && fDesktop->ReadLockClipping()) {
452727653f7SStephan Aßmus
453727653f7SStephan Aßmus		ViewLayer* layer = (ViewLayer*)fTokenViewMap.ItemAt(token);
454727653f7SStephan Aßmus		if (!layer || !layer->IsVisible()) {
455727653f7SStephan Aßmus			fDesktop->ReadUnlockClipping();
456727653f7SStephan Aßmus			return;
457727653f7SStephan Aßmus		}
458727653f7SStephan Aßmus		if (!fContentRegionValid)
459727653f7SStephan Aßmus			_UpdateContentRegion();
460727653f7SStephan Aßmus
461727653f7SStephan Aßmus		_MarkContentDirty(&layer->ScreenClipping(&fContentRegion));
462727653f7SStephan Aßmus
463727653f7SStephan Aßmus		fDesktop->ReadUnlockClipping();
464727653f7SStephan Aßmus	}
465727653f7SStephan Aßmus}
466727653f7SStephan Aßmus
4674dd89c69SStephan Aßmus//# pragma mark -
468748533bbSStephan Aßmus
469748533bbSStephan Aßmus// CopyContents
470748533bbSStephan Aßmusvoid
471748533bbSStephan AßmusWindowLayer::CopyContents(BRegion* region, int32 xOffset, int32 yOffset)
472ff89d51eSStephan Aßmus{
473748533bbSStephan Aßmus	// this function takes care of invalidating parts that could not be copied
474748533bbSStephan Aßmus
4751ba9992dSStephan Aßmus	if (fDesktop->ReadLockClipping()) {
476748533bbSStephan Aßmus
477748533bbSStephan Aßmus		BRegion newDirty(*region);
478748533bbSStephan Aßmus
4794dd89c69SStephan Aßmus		// clip the region to the visible contents at the
4807fd1af6fSStephan Aßmus		// source and destination location (not that VisibleContentRegion()
4817fd1af6fSStephan Aßmus		// is used once to make sure it is valid, then fVisibleContentRegion
4827fd1af6fSStephan Aßmus		// is used directly)
4837fd1af6fSStephan Aßmus		region->IntersectWith(&VisibleContentRegion());
4844dd89c69SStephan Aßmus		if (region->CountRects() > 0) {
4854dd89c69SStephan Aßmus			region->OffsetBy(xOffset, yOffset);
4864dd89c69SStephan Aßmus			region->IntersectWith(&fVisibleContentRegion);
4874dd89c69SStephan Aßmus			if (region->CountRects() > 0) {
4884dd89c69SStephan Aßmus				// if the region still contains any rects
4894dd89c69SStephan Aßmus				// offset to source location again
4904dd89c69SStephan Aßmus				region->OffsetBy(-xOffset, -yOffset);
4914dd89c69SStephan Aßmus				// the part which we can copy is not dirty
4924dd89c69SStephan Aßmus				newDirty.Exclude(region);
4934dd89c69SStephan Aßmus
4944dd89c69SStephan Aßmus				if (fDrawingEngine->Lock()) {
4954dd89c69SStephan Aßmus					fDrawingEngine->CopyRegion(region, xOffset, yOffset);
4964dd89c69SStephan Aßmus					fDrawingEngine->Unlock();
4974dd89c69SStephan Aßmus				}
498748533bbSStephan Aßmus
4994dd89c69SStephan Aßmus				// move along the already dirty regions that are common
5004dd89c69SStephan Aßmus				// with the region that we could copy
501c63a78aaSStephan Aßmus				_ShiftPartOfRegion(&fDirtyRegion, region, xOffset, yOffset);
5027fd1af6fSStephan Aßmus				if (fCurrentUpdateSession.IsUsed())
5037fd1af6fSStephan Aßmus					_ShiftPartOfRegion(&fCurrentUpdateSession.DirtyRegion(), region, xOffset, yOffset);
5047fd1af6fSStephan Aßmus				if (fPendingUpdateSession.IsUsed())
5057fd1af6fSStephan Aßmus					_ShiftPartOfRegion(&fPendingUpdateSession.DirtyRegion(), region, xOffset, yOffset);
5064dd89c69SStephan Aßmus
5074dd89c69SStephan Aßmus			}
508748533bbSStephan Aßmus		}
5094dd89c69SStephan Aßmus		// what is left visible from the original region
5104dd89c69SStephan Aßmus		// at the destination after the region which could be
5114dd89c69SStephan Aßmus		// copied has been excluded, is considered dirty
5127e68917fSStephan Aßmus		// NOTE: it may look like dirty regions are not moved
5137e68917fSStephan Aßmus		// if no region could be copied, but that's alright,
5147e68917fSStephan Aßmus		// since these parts will now be in newDirty anyways
5157e68917fSStephan Aßmus		// (with the right offset)
516748533bbSStephan Aßmus		newDirty.OffsetBy(xOffset, yOffset);
517748533bbSStephan Aßmus		newDirty.IntersectWith(&fVisibleContentRegion);
5184dd89c69SStephan Aßmus		if (newDirty.CountRects() > 0)
5191ba9992dSStephan Aßmus			ProcessDirtyRegion(&newDirty);
520748533bbSStephan Aßmus
5211ba9992dSStephan Aßmus		fDesktop->ReadUnlockClipping();
522ff89d51eSStephan Aßmus	}
523ff89d51eSStephan Aßmus}
524748533bbSStephan Aßmus
525c63a78aaSStephan Aßmus// #pragma mark -
526bef1ed93SStephan Aßmus
527748533bbSStephan Aßmus// _ShiftPartOfRegion
528bef1ed93SStephan Aßmusvoid
529748533bbSStephan AßmusWindowLayer::_ShiftPartOfRegion(BRegion* region, BRegion* regionToShift,
530748533bbSStephan Aßmus								int32 xOffset, int32 yOffset)
531bef1ed93SStephan Aßmus{
5324dd89c69SStephan Aßmus	BRegion common(*regionToShift);
5334dd89c69SStephan Aßmus	// see if there is a common part at all
5344dd89c69SStephan Aßmus	common.IntersectWith(region);
5354dd89c69SStephan Aßmus	if (common.CountRects() > 0) {
5364dd89c69SStephan Aßmus		// cut the common part from the region,
5374dd89c69SStephan Aßmus		// offset that to destination and include again
5384dd89c69SStephan Aßmus		region->Exclude(&common);
5394dd89c69SStephan Aßmus		common.OffsetBy(xOffset, yOffset);
5404dd89c69SStephan Aßmus		region->Include(&common);
5414dd89c69SStephan Aßmus	}
542748533bbSStephan Aßmus}
543bef1ed93SStephan Aßmus
544748533bbSStephan Aßmus// _TriggerContentRedraw
545748533bbSStephan Aßmusvoid
546748533bbSStephan AßmusWindowLayer::_TriggerContentRedraw()
547748533bbSStephan Aßmus{
548748533bbSStephan Aßmus//printf("%s - DrawContents()\n", Name());
5497fd1af6fSStephan Aßmus	BRegion dirtyContentRegion(VisibleContentRegion());
550c63a78aaSStephan Aßmus	dirtyContentRegion.IntersectWith(&fDirtyRegion);
5517f705589SStephan Aßmus
5524dd89c69SStephan Aßmus	if (dirtyContentRegion.CountRects() > 0) {
553f5552ed0SStephan Aßmus
554f5552ed0SStephan Aßmus#if SHOW_WINDOW_CONTENT_DIRTY_REGION
555987aa5e4SStephan Aßmusif (fDrawingEngine->Lock()) {
5564dd89c69SStephan AßmusfDrawingEngine->SetHighColor(0, 0, 255);
5574dd89c69SStephan AßmusfDrawingEngine->FillRegion(&dirtyContentRegion);
5584dd89c69SStephan AßmusfDrawingEngine->MarkDirty(&dirtyContentRegion);
5594dd89c69SStephan AßmusfDrawingEngine->Unlock();
5604dd89c69SStephan Aßmussnooze(100000);
561987aa5e4SStephan Aßmus}
562f5552ed0SStephan Aßmus#endif
5634dd89c69SStephan Aßmus		// send UPDATE message to the client
5644dd89c69SStephan Aßmus		_MarkContentDirty(&dirtyContentRegion);
565987aa5e4SStephan Aßmus
5661ba9992dSStephan Aßmus		if (!fContentRegionValid)
5671ba9992dSStephan Aßmus			_UpdateContentRegion();
5681ba9992dSStephan Aßmus
5694dd89c69SStephan Aßmus#if DELAYED_BACKGROUND_CLEARING
5704dd89c69SStephan Aßmus		fTopLayer->Draw(fDrawingEngine, &dirtyContentRegion,
5711ba9992dSStephan Aßmus						&fContentRegion, false);
5724dd89c69SStephan Aßmus#else
5734dd89c69SStephan Aßmus		fTopLayer->Draw(fDrawingEngine, &dirtyContentRegion,
5741ba9992dSStephan Aßmus						&fContentRegion, true);
5754dd89c69SStephan Aßmus#endif
576bef1ed93SStephan Aßmus	}
577