1#include "SnowView.h"
2
3#include <stdio.h>
4#include <stdlib.h>
5#include <string.h>
6#include <math.h>
7
8#include <Alert.h>
9#include <Catalog.h>
10#include <Debug.h>
11#include <Message.h>
12#include <MessageRunner.h>
13#include <MessageFilter.h>
14#include <OS.h>
15#include <Region.h>
16#include <Screen.h>
17
18#include "Flakes.h"
19
20
21#define FORWARD_TO_PARENT
22#undef B_TRANSLATION_CONTEXT
23#define B_TRANSLATION_CONTEXT "BSnow"
24
25
26SnowView::SnowView()
27	:
28	BView(BRect(SNOW_VIEW_RECT), "BSnow", B_FOLLOW_NONE,
29	B_WILL_DRAW | B_PULSE_NEEDED)
30{
31	fAttached = false;
32	fMsgRunner = NULL;
33	fCachedParent = NULL;
34	fFallenBmp = NULL;
35	fFallenView = NULL;
36	fFallenReg = NULL;
37	fInvalidator = -1;
38	fShowClickMe = false;
39	for (int i = 0; i < WORKSPACES_COUNT; i++)
40		fFlakes[i] = NULL;
41	for (int i = 0; i < NUM_PATTERNS; i++)
42		fFlakeBitmaps[i] = NULL;
43	BRect r(Frame());
44	r.left = r.right - 7;
45	r.top = r.bottom - 7;
46	fDragger = new BDragger(r, this);
47	AddChild(fDragger);
48	SetHighColor(255,255,255);
49}
50
51#ifdef DEBUG
52filter_result msgfilter(BMessage *message, BHandler **target, BMessageFilter *filter)
53{
54	switch (message->what) {
55	case B_MOUSE_DOWN:
56	case B_MOUSE_UP:
57	case B_MOUSE_MOVED:
58	case '_EVP':
59	case '_UPD':
60	case '_PUL':
61	case 'NTCH':
62	case 'NMDN':
63		break;
64	default:
65		printf("For: %p: %s\n", *target, (*target)->Name());
66		message->PrintToStream();
67	}
68	return B_DISPATCH_MESSAGE;
69}
70#endif
71
72SnowView::SnowView(BMessage *archive)
73 : BView(archive)
74{
75	system_info si;
76	PRINT(("SnowView()\n"));
77#ifdef DEBUG
78	archive->PrintToStream();
79#endif
80	fDragger = NULL;
81	fAttached = false;
82	fMsgRunner = NULL;
83	fFallenBmp = NULL;
84	fFallenView = NULL;
85	fFallenReg = NULL;
86	fCachedParent = NULL;
87	fShowClickMe = false;
88	SetFlags(Flags() & ~B_PULSE_NEEDED); /* it's only used when in the app */
89	get_system_info(&si);
90	fNumFlakes = ((int32)(si.cpu_clock_speed/1000000)) * si.cpu_count / 3; //;
91	printf("BSnow: using %ld flakes\n", fNumFlakes);
92	for (int i = 0; i < WORKSPACES_COUNT; i++) {
93		fFlakes[i] = new flake[fNumFlakes];
94		memset(fFlakes[i], 0, fNumFlakes * sizeof(flake));
95	}
96	for (int i = 0; i < NUM_PATTERNS; i++) {
97		fFlakeBitmaps[i] = new BBitmap(BRect(0,0,7,7), B_CMAP8);
98		fFlakeBitmaps[i]->SetBits(gFlakeBits[i], 8*8, 0, B_CMAP8);
99	}
100	fCurrentWorkspace = 0;
101	SetHighColor(255,255,255);
102	SetDrawingMode(B_OP_OVER);
103}
104
105SnowView::~SnowView()
106{
107	for (int i = 0; i < WORKSPACES_COUNT; i++)
108		if (fFlakes[i])
109			delete [] fFlakes[i];
110	if (fFallenBmp)
111		delete fFallenBmp; /* the view goes away with it */
112}
113
114BArchivable *SnowView::Instantiate(BMessage *data)
115{
116	return new SnowView(data);
117}
118
119status_t SnowView::Archive(BMessage *data, bool deep) const
120{
121	status_t err;
122	err = BView::Archive(data, deep);
123	if (err < B_OK)
124		return err;
125	data->AddString("add_on", APP_SIG);
126	return B_OK;
127}
128
129void SnowView::AttachedToWindow()
130{
131	BView *p;
132	rgb_color col;
133	fAttached = true;
134/*	if (!fMsgRunner)
135		fMsgRunner = new BMessageRunner(BMessenger(this),
136					new BMessage(MSG_PULSE_ME),
137					INTERVAL);
138*/
139	p = Parent();
140	if (p)
141		col = B_TRANSPARENT_32_BIT;//Parent()->ViewColor();
142	else
143		col = ui_color(B_PANEL_BACKGROUND_COLOR);
144	SetViewColor(col);
145//	BScreen bs;
146//	fCachedWsWidth = bs.Frame().IntegerWidth();
147//	fCachedWsHeight = bs.Frame().IntegerHeight();
148	fDragger = dynamic_cast<BDragger *>(FindView("_dragger_"));
149	if (fDragger && p) {
150		fCachedParent = p;
151		fCachedWsWidth = p->Frame().IntegerWidth();
152		fCachedWsHeight = p->Frame().IntegerHeight();
153		fDragger->SetViewColor(col);
154		if (fDragger->InShelf()) {
155			p->SetFlags(p->Flags() | B_DRAW_ON_CHILDREN);
156#ifdef B_BEOS_VERSION_DANO
157			p->SetDoubleBuffering(p->DoubleBuffering() | B_UPDATE_EXPOSED);
158#endif
159			ResizeTo(p->Bounds().Width(), p->Bounds().Height());
160			MoveTo(0,0);
161			fDragger->MoveTo(p->Bounds().Width()-7, p->Bounds().Height()-7);
162		}
163		BRect fallenRect(p->Bounds());
164		fallenRect.top = fallenRect.bottom - FALLEN_HEIGHT;
165		fFallenBmp = new BBitmap(fallenRect, B_BITMAP_ACCEPTS_VIEWS, B_CMAP8);
166		memset(fFallenBmp->Bits(), B_TRANSPARENT_MAGIC_CMAP8, (size_t)(fallenRect.Height()*fFallenBmp->BytesPerRow()));
167		fFallenView = new BView(fallenRect, "offscreen fallen snow", B_FOLLOW_NONE, 0);
168		fFallenBmp->AddChild(fFallenView);
169		fFallenReg = new BRegion;
170		fInvalidator = spawn_thread(SnowMakerThread, INVALIDATOR_THREAD_NAME, B_LOW_PRIORITY, (void *)this);
171		resume_thread(fInvalidator);
172		printf("BSnow: OK: ws = %" B_PRId32 " x %" B_PRId32 "\n", fCachedWsWidth, fCachedWsHeight);
173#ifdef DEBUG
174		Window()->AddCommonFilter(new BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE, msgfilter));
175#endif
176	}
177}
178
179void SnowView::DetachedFromWindow()
180{
181	fAttached = false;
182/*
183	if (Parent()) {
184		Parent()->Invalidate(Parent()->Bounds());
185	}
186*/
187	if (fMsgRunner)
188		delete fMsgRunner;
189	fMsgRunner = NULL;
190	status_t err;
191	fCachedParent = NULL;
192	if (fInvalidator > B_OK)
193		wait_for_thread(fInvalidator, &err);
194	fInvalidator = -1;
195	if (fFallenReg)
196		delete fFallenReg;
197}
198
199void SnowView::MessageReceived(BMessage *msg)
200{
201	BAlert *info;
202	//msg->PrintToStream();
203	switch (msg->what) {
204	case MSG_PULSE_ME:
205		if (Parent()) {
206			Calc();
207			InvalFlakes();
208		}
209		break;
210	case B_ABOUT_REQUESTED:
211		info = new BAlert("BSnow info",
212			"BSnow, just in case you don't have real one...\n"
213			"" B_UTF8_COPYRIGHT " 2003, Fran��ois Revol.",
214			"Where is Santa ??");
215		info->SetFeel(B_NORMAL_WINDOW_FEEL);
216		info->SetLook(B_FLOATING_WINDOW_LOOK);
217		info->SetFlags(info->Flags()|B_NOT_ZOOMABLE|B_CLOSE_ON_ESCAPE);
218		info->Go(NULL);
219		break;
220	default:
221//#ifdef FORWARD_TO_PARENT
222/*
223		if (fAttached && Parent())
224			Parent()->MessageReceived(msg);
225		else
226*/
227//#endif
228			BView::MessageReceived(msg);
229	}
230}
231
232void SnowView::Draw(BRect ur)
233{
234	int i;
235	if (!fCachedParent) {
236		if (!fShowClickMe) { /* show "drag me" */
237			SetLowColor(ViewColor());
238			SetHighColor(0,0,0);
239			SetFontSize(12);
240			DrawString(B_TRANSLATE("Drag me on your desktop"B_UTF8_ELLIPSIS),
241				BPoint(15,25));
242			BPoint arrowHead(Bounds().RightBottom() + BPoint(-10,-10));
243			StrokeLine(arrowHead, arrowHead - BPoint(7,0));
244			StrokeLine(arrowHead, arrowHead - BPoint(0,7));
245			StrokeLine(arrowHead, arrowHead - BPoint(12,12));
246			return;
247		} else {
248			SetLowColor(ViewColor());
249			SetHighColor(0,0,0);
250			SetFontSize(12);
251			DrawString(B_TRANSLATE("Click me to remove BSnow"B_UTF8_ELLIPSIS),
252				BPoint(15,25));
253			return;
254		}
255	}
256	//printf("Draw()\n");
257	uint32 cw = fCurrentWorkspace;
258	if (fFlakes[cw] == NULL)
259		return;
260	/* draw the snow already fallen */
261//	BRect fallenRect(Bounds());
262//	fallenRect.top = fallenRect.bottom - FALLEN_HEIGHT;
263//	if (ur.Intersects(fallenRect)) {
264		//if (fFallenBmp->Lock()) {
265		//	DrawBitmap(fFallenBmp, fallenRect);
266		//	fFallenBmp->Unlock();
267		//}
268		int32 cnt = fFallenReg->CountRects();
269//		drawing_mode oldmode = DrawingMode();
270//		SetDrawingMode(B_OP_ADD);
271
272		for (i=0; i<cnt; i++) {
273			BRect r = fFallenReg->RectAt(i);
274//			SetHighColor(245, 245, 245, 200);
275//			FillRect(r);
276//			SetHighColor(255, 255, 255, 255);
277//			r.InsetBy(1,1);
278			FillRect(r);
279		}
280//		SetDrawingMode(oldmode);
281//	}
282	/* draw our flakes */
283	for (i=0; i<fNumFlakes; i++) {
284		int pat;
285		if (!ur.Contains(BRect(fFlakes[cw][i].pos-BPoint(4,4), fFlakes[cw][i].pos+BPoint(4,4))))
286			continue;
287		if (fFlakes[cw][i].weight == 0)
288			continue;
289		pat = (fFlakes[cw][i].weight>3)?1:0;
290		//FillRect(BRect(fFlakes[cw][i].pos-BPoint(PAT_HOTSPOT),fFlakes[cw][i].pos-BPoint(PAT_HOTSPOT)+BPoint(7,7)), gFlakePatterns[pat]);
291/*
292		StrokeLine(fFlakes[cw][i].pos+BPoint(-1,-1),
293				fFlakes[cw][i].pos+BPoint(1,1));
294		StrokeLine(fFlakes[cw][i].pos+BPoint(-1,1),
295				fFlakes[cw][i].pos+BPoint(1,-1));
296*/
297		DrawBitmap(fFlakeBitmaps[pat], fFlakes[cw][i].pos-BPoint(PAT_HOTSPOT));
298	}
299}
300
301void SnowView::Pulse()
302{
303	if (fShowClickMe)
304		return; /* done */
305	if (fCachedParent)
306		return; /* we are in Tracker! */
307	BMessenger msgr("application/x-vnd.Be-TRAK");
308	BMessage msg(B_GET_PROPERTY), reply;
309	msg.AddSpecifier("Frame");
310	msg.AddSpecifier("View", "BSnow");
311	msg.AddSpecifier("Window", 1); /* 0 is Twitcher */
312	if (msgr.SendMessage(&msg, &reply) == B_OK && reply.what == B_REPLY) {
313		//reply.PrintToStream();
314		Invalidate(Bounds());
315		fShowClickMe = true;
316	}
317}
318
319void SnowView::Calc()
320{
321	int i;
322	uint32 cw = fCurrentWorkspace;
323
324	/* check if the parent changed size */
325	BRect pFrame = fCachedParent->Frame();
326	if (fCachedWsWidth != pFrame.Width() || fCachedWsHeight != pFrame.Height()) {
327		fCachedWsWidth = pFrame.IntegerWidth();
328		fCachedWsHeight = pFrame.IntegerHeight();
329		printf("BSnow: Parent resized to %" B_PRId32 " %" B_PRId32 "\n", fCachedWsWidth, fCachedWsHeight);
330		fFallenReg->MakeEmpty(); /* remove all the fallen snow */
331		ResizeTo(pFrame.IntegerWidth(), pFrame.IntegerHeight());
332		fDragger->MoveTo(pFrame.IntegerWidth()-7, pFrame.IntegerHeight()-7);
333	}
334
335	/* make new flakes */
336	for (i=0; i<fNumFlakes; i++) {
337		if (fFlakes[cw][i].weight == 0) {
338			fFlakes[cw][i].weight = ((float)(rand() % WEIGHT_SPAN)) / WEIGHT_GRAN;
339			fFlakes[cw][i].weight = MAX(fFlakes[cw][i].weight, 0.5);
340			fFlakes[cw][i].pos.y = rand() % 5 - 2;
341			fFlakes[cw][i].pos.x = (rand()%(fCachedWsWidth+2*fCachedWsHeight))-fCachedWsHeight;
342			if (fFlakes[cw][i].pos.x < -10) {
343				fFlakes[cw][i].pos.y = -fFlakes[cw][i].pos.x;
344				if (fWind > 0)
345					fFlakes[cw][i].pos.x = 0;
346				else
347					fFlakes[cw][i].pos.x = fCachedWsWidth;
348			}
349			if (fFlakes[cw][i].pos.x > fCachedWsWidth+10) {
350				fFlakes[cw][i].pos.y = fFlakes[cw][i].pos.x - fCachedWsWidth;
351				if (fWind > 0)
352					fFlakes[cw][i].pos.x = 0;
353				else
354					fFlakes[cw][i].pos.x = fCachedWsWidth;
355			}
356		}
357	}
358
359	/* like a candle in the wind... */
360	if (fWindDuration < system_time()) {
361		fWindDuration = system_time() + ((((bigtime_t)rand())*1000) % WIND_MAX_DURATION);
362		fWind = (rand() % WIND_SPAN) - WIND_SPAN/2;
363		printf("BSnow: wind change: %f\n", fWind);
364	}
365
366
367//	if (fFallenView->LockLooperWithTimeout(5000)) {
368//	if (fFallenBmp) {
369//		uint8 *fallenBits = (uint8 *)fFallenBmp->Bits();
370
371		BRegion desktopReg;
372		GetClippingRegion(&desktopReg);
373
374		/* let's add some gravity and wind */
375		for (i=0; i<fNumFlakes; i++) {
376			float yinc;
377			if (fFlakes[cw][i].weight == 0)
378				continue;
379			fFlakes[cw][i].opos = fFlakes[cw][i].pos;
380
381			yinc = fFlakes[cw][i].weight - (rand() % 3);
382			yinc = MAX(yinc, 0.5);
383			fFlakes[cw][i].pos.y += yinc;
384
385//			if (fFlakes[cw][i].pos.y > (fCachedWsHeight-FALLEN_HEIGHT)) {
386
387			bool fallen = false;
388			bool keepfalling = false;
389
390			/* fallen on the flour */
391			if (fFlakes[cw][i].pos.y > fCachedWsHeight-2)
392				fallen = true;
393			/* fallon on another fallen flake */
394			else if (fFallenReg->Intersects(BRect(fFlakes[cw][i].pos - BPoint(0,1),
395											fFlakes[cw][i].pos + BPoint(0,1)))) {
396				/* don't accumulate too much */
397				if ((fFlakes[cw][i].pos.y > fCachedWsHeight-30) ||
398									!desktopReg.Intersects(
399									BRect(fFlakes[cw][i].pos + BPoint(0,6),
400									fFlakes[cw][i].pos + BPoint(0,10))))
401					fallen = true;
402			/* fallen on a window */
403			} else if (!desktopReg.Intersects(
404							BRect(fFlakes[cw][i].pos + BPoint(-1,-1-2),
405							fFlakes[cw][i].pos + BPoint(1,1-1))) &&
406					desktopReg.Intersects(
407							BRect(fFlakes[cw][i].pos + BPoint(-1,-1-3),
408							fFlakes[cw][i].pos + BPoint(1,1-3)))) {
409				//printf("fallen3 @ %f %f\n", fFlakes[cw][i].pos.x, fFlakes[cw][i].pos.y);
410				fFlakes[cw][i].pos = fFlakes[cw][i].opos;
411				fallen = true;
412				keepfalling = true; /* but keep one falling */
413			}
414
415/*			else if (fallenBits[ (long)(fFlakes[cw][i].pos.y
416					 * fFallenBmp->BytesPerRow()
417					 + fFlakes[cw][i].pos.y
418					 - (fCachedWsHeight-FALLEN_HEIGHT)) ] != B_TRANSPARENT_MAGIC_CMAP8) {
419				fallen = true;
420			}*/
421
422//			if (fallen) {
423//				int pat = (fFlakes[cw][i].weight>3)?1:0;
424//				if (fFlakes[cw][i].pos.y > fCachedWsHeight-1)
425//					fFlakes[cw][i].pos.y = fCachedWsHeight-(rand()%4);
426				//fFallenView->DrawBitmap(fFlakeBitmaps[pat], fFlakes[cw][i].pos-BPoint(PAT_HOTSPOT));
427//				fallenBits[ (long)(fFlakes[cw][i].pos.y * fFallenBmp->BytesPerRow()
428//					+ fFlakes[cw][i].pos.y-(fCachedWsHeight-FALLEN_HEIGHT)) ] = 0x56;
429//				printf("fallen @ %f, %f\n", fFlakes[cw][i].pos.x, fFlakes[cw][i].pos.y);
430//			}
431			if (fallen) {
432				if (!keepfalling)
433					fFlakes[cw][i].weight = 0;
434				fFallenReg->Include(BRect(fFlakes[cw][i].pos - BPoint(2,0),
435										fFlakes[cw][i].pos + BPoint(2,2)));
436				if (keepfalling) {
437					fFlakes[cw][i].pos += BPoint(0,10);
438					/* except if under the desktop */
439					if (fFlakes[cw][i].pos.y > fCachedWsHeight-1)
440						fFlakes[cw][i].weight = 0;
441				}
442			}
443
444			/* cleanup, when a window hides the snow */
445			fFallenReg->IntersectWith(&desktopReg);
446
447			/* cleanup, when a window is moved */
448			/* seems to lockup Tracker */
449/*
450			int32 cnt = fFallenReg->CountRects();
451			for (i=0; i<cnt; i++) {
452				BRect r = fFallenReg->RectAt(i);
453				if (desktopReg.Intersects(r.OffsetByCopy(0,15))) {
454					fFallenReg->Exclude(r);
455					cnt--;
456				}
457			}
458*/
459			/* add the effect of the wind */
460			fFlakes[cw][i].pos.x += fWind + (rand() % 6 - 3);
461			if ((fFlakes[cw][i].pos.x > fCachedWsWidth+50)||(fFlakes[cw][i].pos.x < -50))
462				fFlakes[cw][i].weight = 0;
463		}
464//		fFallenView->UnlockLooper();
465//	}
466#if 0
467	for (i=0; i<10; i++)
468		printf("f[%d] = {%f, %f}, {%f, %f}, %d\n", i,
469			fFlakes[cw][i].opos.x, fFlakes[cw][i].opos.y,
470			fFlakes[cw][i].pos.x, fFlakes[cw][i].pos.y,
471			fFlakes[cw][i].weight);
472#endif
473}
474
475void SnowView::InvalFlakes()
476{
477	int i;
478	BView *p = Parent();
479	if (!p)
480		return;
481	//printf("InvalFlakes()\n");
482	uint32 cw = fCurrentWorkspace;
483
484	for (i=0; i<fNumFlakes; i++) {
485		if (fFlakes[cw][i].weight)
486			Invalidate(BRect(fFlakes[cw][i].opos-BPoint(PAT_HOTSPOT), fFlakes[cw][i].opos-BPoint(PAT_HOTSPOT)+BPoint(7,7)));
487	}
488}
489
490void SnowView::MouseDown(BPoint where)
491{
492#ifdef FORWARD_TO_PARENT
493	if (fAttached && Parent())
494		Parent()->MouseDown(where);
495#endif
496}
497
498void SnowView::MouseUp(BPoint where)
499{
500#ifdef FORWARD_TO_PARENT
501	if (fAttached && Parent())
502		Parent()->MouseUp(where);
503#endif
504	if (fCachedParent)
505		return; /* we are *inside* the Tracker,
506				 * don't even try talking to ourselve
507				 * with the window locked
508				 */
509	BMessenger msgr("application/x-vnd.Be-TRAK");
510	BMessage msg(B_DELETE_PROPERTY), reply;
511	msg.AddSpecifier("Replicant", "BSnow");
512	msg.AddSpecifier("Shelf");
513	msg.AddSpecifier("View", "PoseView");
514	msg.AddSpecifier("Window", 1); /* 0 is Tracker Status */
515	if ((msgr.SendMessage(&msg, &reply) == B_OK) &&
516				(reply.what == B_NO_REPLY || reply.what == B_REPLY)) {
517		//reply.PrintToStream();
518		fShowClickMe = false;
519		Invalidate(Bounds());
520	}
521	/*
522	BMessage: what = JAHA (0x4a414841, or 1245792321)
523    entry          index, type='LONG', c=1, size= 4, data[0]: 0x2 (2, '')
524    entry           when, type='LLNG', c=1, size= 8, data[0]: 0xf6a1b09ac (66204666284, '')
525    entry         source, type='PNTR', c=1, size= 4,
526    entry      be:sender, type='MSNG', c=1, size=24,
527    */
528}
529
530void SnowView::MouseMoved(BPoint where, uint32 code, const BMessage *a_message)
531{
532#ifdef FORWARD_TO_PARENT
533	if (fAttached && Parent())
534		Parent()->MouseMoved(where, code, a_message);
535#endif
536}
537
538void SnowView::KeyDown(const char *bytes, int32 numBytes)
539{
540#ifdef FORWARD_TO_PARENT
541	if (fAttached && Parent())
542		Parent()->KeyDown(bytes, numBytes);
543#endif
544}
545
546void SnowView::KeyUp(const char *bytes, int32 numBytes)
547{
548#ifdef FORWARD_TO_PARENT
549	if (fAttached && Parent())
550		Parent()->KeyUp(bytes, numBytes);
551#endif
552}
553
554#define PORTION_GRAN 20
555
556int32 SnowView::SnowMakerThread(void *p_this)
557{
558	SnowView *_this = (SnowView *)p_this;
559	BView *p = _this->Parent();
560	BRect portion(0,0,(_this->fCachedWsWidth/PORTION_GRAN)-1, (_this->fCachedWsHeight/PORTION_GRAN)-1);
561	int nf = _this->fNumFlakes;
562	BRegion reg(BRect(-1,-1,-1,-1));
563	while (p && _this->fAttached) {
564		snooze(INTERVAL/(10*(nf?nf:1)));
565		int32 cw = _this->fCurrentWorkspace;
566		bool drawThisOne = false;
567//printf("processing flake %d...\n", current);
568		//for (; (current%(fNumFlakes/4); current++)
569		if (reg.Intersects(portion)) {
570			for (int i = 0; !drawThisOne && i < nf; i++) {
571				/* if we find at least one flake in this rect, draw it */
572				if ((_this->fFlakes[cw][i].weight) && (
573					portion.Intersects(BRect(_this->fFlakes[cw][i].opos - BPoint(4,4), _this->fFlakes[cw][i].opos + BPoint(4,4))) ||
574					portion.Intersects(BRect(_this->fFlakes[cw][i].pos - BPoint(4,4), _this->fFlakes[cw][i].pos + BPoint(4,4))))) {
575						drawThisOne = true;
576				}
577			}
578		}
579		//if (!drawThisOne)
580			//printf("!Invalidate(%f, %f, %f, %f)\n", portion.left, portion.top, portion.right, portion.bottom);
581		/* avoid deadlock on exit */
582		if (drawThisOne && (_this->LockLooperWithTimeout(2000) == B_OK)) {
583//			printf("Invalidate(%f, %f, %f, %f)\n", portion.left, portion.top, portion.right, portion.bottom);
584			p->Invalidate(portion);
585			_this->UnlockLooper();
586		}
587		portion.OffsetBy(_this->fCachedWsWidth/PORTION_GRAN, 0);
588		if (portion.left >= _this->fCachedWsWidth) { /* right wrap */
589			//printf("rigth wrap to %ld\n", _this->fCachedWsWidth);
590			portion.OffsetTo(0, portion.top+(_this->fCachedWsHeight/PORTION_GRAN));
591		}
592		if (portion.top >= _this->fCachedWsHeight) {
593			portion.OffsetTo(0,0);
594			/* avoid deadlock on exit */
595			if (_this->LockLooperWithTimeout(5000) == B_OK) {
596//printf("calculating flakes...\n");
597				_this->Calc();
598//printf("done calculating flakes.\n");
599				_this->GetClippingRegion(&reg);
600				//printf("Region:\n");
601				//reg.PrintToStream();
602				_this->UnlockLooper();
603			}
604		}
605	}
606#if 0
607	BView *p = _this->Parent();
608	while (p && _this->fAttached) {
609		snooze(INTERVAL/_this->fNumFlakes);
610//printf("processing flake %d...\n", current);
611		//for (; (current%(fNumFlakes/4); current++)
612		/* avoid deadlock on exit */
613		if (_this->LockLooperWithTimeout(2000) == B_OK) {
614			if (_this->fFlakes[_this->fCurrentWorkspace][current].weight) {
615				p->Invalidate(BRect(_this->fFlakes[_this->fCurrentWorkspace][current].opos - BPoint(4,4),
616									_this->fFlakes[_this->fCurrentWorkspace][current].opos + BPoint(4,4)));
617				p->Invalidate(BRect(_this->fFlakes[_this->fCurrentWorkspace][current].pos - BPoint(4,4),
618									_this->fFlakes[_this->fCurrentWorkspace][current].pos + BPoint(4,4)));
619			}
620			_this->UnlockLooper();
621			current++;
622			current %= _this->fNumFlakes;
623			if (!current) {
624				/* avoid deadlock on exit */
625				if (_this->LockLooperWithTimeout(2000) == B_OK) {
626printf("calculating flakes...\n");
627					_this->Calc();
628printf("done calculating flakes.\n");
629					_this->UnlockLooper();
630				}
631			}
632		}
633	}
634#endif
635	return B_OK;
636}
637