1/*
2 * Copyright 2009 Vincent Duvert, vincent.duvert@free.fr
3 * Copyright 2014 Haiku, Inc. All rights reserved.
4 *
5 * Distributed under the terms of the MIT License.
6 *
7 * Authors:
8 *		Vincent Duvert, vincent.duvert@free.fr
9 *		John Scipione, jscipione@gmail.com
10 */
11
12
13#include "IconsSaver.h"
14
15#include <stdlib.h>
16
17#include <Bitmap.h>
18#include <Catalog.h>
19#include <DefaultSettingsView.h>
20#include <MimeType.h>
21
22#include "IconDisplay.h"
23#include "VectorIcon.h"
24
25
26#undef B_TRANSLATION_CONTEXT
27#define B_TRANSLATION_CONTEXT "Screensaver Icons"
28
29
30#define RAND_BETWEEN(a, b) ((rand() % ((b) - (a) + 1) + (a)))
31
32
33static const int32 kMaxConcurrentIcons = 15;
34static const int32 kMinIconWidthPercentage = 5;
35	// percentage of the screen width
36static const int32 kMaxIconWidthPercentage = 20;
37	// same here
38static const int32 kMinIconCount = 20;
39static const int32 kMaxIconCount = 384;
40
41
42const rgb_color kBackgroundColor = ui_color(B_DESKTOP_COLOR);
43
44
45BScreenSaver* instantiate_screen_saver(BMessage* msg, image_id image)
46{
47	return new IconsSaver(msg, image);
48}
49
50
51//	#pragma mark - IconsSaver
52
53
54IconsSaver::IconsSaver(BMessage* archive, image_id image)
55	:
56	BScreenSaver(archive, image),
57	fIcons(NULL),
58	fBackBitmap(NULL),
59	fBackView(NULL),
60	fMinSize(0),
61	fMaxSize(0)
62{
63}
64
65
66IconsSaver::~IconsSaver()
67{
68	vector_icon* icon;
69	while ((icon = fVectorIcons.RemoveItemAt((int32)0)) != NULL) {
70		delete[] icon->data;
71		free(icon);
72	}
73}
74
75
76status_t
77IconsSaver::StartSaver(BView* view, bool /*preview*/)
78{
79	if (fVectorIcons.CountItems() < kMinIconCount)
80		_GetVectorIcons();
81
82	srand(system_time() % INT_MAX);
83
84	BRect screenRect(0, 0, view->Frame().Width(), view->Frame().Height());
85	fBackBitmap = new BBitmap(screenRect, B_RGBA32, true);
86	if (!fBackBitmap->IsValid())
87		return B_NO_MEMORY;
88
89	fBackView = new BView(screenRect, "back view", 0, 0);
90	if (fBackView == NULL)
91		return B_NO_MEMORY;
92
93	fBackView->SetViewColor(kBackgroundColor);
94	fBackView->SetHighColor(kBackgroundColor);
95
96	fBackBitmap->AddChild(fBackView);
97	if (fBackBitmap->Lock()) {
98		fBackView->FillRect(fBackView->Frame());
99		fBackView->SetDrawingMode(B_OP_ALPHA);
100		fBackView->SetBlendingMode(B_CONSTANT_ALPHA, B_ALPHA_OVERLAY);
101		fBackView->Sync();
102		fBackBitmap->Unlock();
103	}
104
105	fIcons = new IconDisplay[kMaxConcurrentIcons];
106
107	fMaxSize = (screenRect.IntegerWidth() * kMaxIconWidthPercentage) / 100;
108	fMinSize = (screenRect.IntegerWidth() * kMinIconWidthPercentage) / 100;
109	if (fMaxSize > 255)
110		fMaxSize = 255;
111
112	if (fMaxSize > screenRect.IntegerHeight())
113		fMaxSize = screenRect.IntegerHeight();
114
115	if (fMinSize > fMaxSize)
116		fMinSize = fMaxSize;
117
118	return B_OK;
119}
120
121
122void
123IconsSaver::StopSaver()
124{
125	delete[] fIcons;
126	fIcons = NULL;
127	delete fBackBitmap;
128	fBackBitmap = NULL;
129}
130
131
132void
133IconsSaver::Draw(BView* view, int32 frame)
134{
135	static int32 previousFrame = 0;
136
137	// update drawing
138	if (fBackBitmap->Lock()) {
139		for (uint8 i = 0 ; i < kMaxConcurrentIcons ; i++)
140			fIcons[i].ClearOn(fBackView);
141
142		int32 delta = frame - previousFrame;
143		for (uint8 i = 0 ; i < kMaxConcurrentIcons ; i++)
144			fIcons[i].DrawOn(fBackView, delta);
145
146		fBackView->Sync();
147		fBackBitmap->Unlock();
148	}
149
150	// sync the view with the back buffer
151	view->DrawBitmap(fBackBitmap);
152	previousFrame = frame;
153
154	if (fVectorIcons.CountItems() < kMinIconCount)
155		return;
156
157	// restart one icon
158	for (uint8 i = 0 ; i < kMaxConcurrentIcons ; i++) {
159		if (!fIcons[i].IsRunning()) {
160			uint16 size = RAND_BETWEEN(fMinSize, fMaxSize);
161			uint16 maxX = view->Frame().IntegerWidth() - size;
162			uint16 maxY = view->Frame().IntegerHeight() - size;
163
164			BRect iconFrame(0, 0, size, size);
165			iconFrame.OffsetTo(RAND_BETWEEN(0, maxX), RAND_BETWEEN(0, maxY));
166
167			// Check that the icon doesn't overlap with others
168			for (uint8 j = 0 ; j < kMaxConcurrentIcons ; j++) {
169				if (fIcons[j].IsRunning() &&
170					iconFrame.Intersects(fIcons[j].GetFrame()))
171					return;
172			}
173
174			int32 index = RAND_BETWEEN(0, fVectorIcons.CountItems() - 1);
175			fIcons[i].Run(fVectorIcons.ItemAt(index), iconFrame);
176			return;
177		}
178	}
179}
180
181
182void
183IconsSaver::StartConfig(BView* view)
184{
185	BPrivate::BuildDefaultSettingsView(view, "Icons",
186		B_TRANSLATE("by Vincent Duvert"));
187}
188
189
190//	#pragma mark - IconsSaver private methods
191
192
193void
194IconsSaver::_GetVectorIcons()
195{
196	// Load vector icons from the MIME type database
197	BMessage types;
198	if (BMimeType::GetInstalledTypes(&types) != B_OK)
199		return;
200
201	const char* type;
202	for (int32 i = 0; types.FindString("types", i, &type) == B_OK; i++) {
203		BMimeType mimeType(type);
204		if (mimeType.InitCheck() != B_OK)
205			continue;
206
207		uint8* data;
208		size_t size;
209
210		if (mimeType.GetIcon(&data, &size) != B_OK) {
211			// didn't find an icon
212			continue;
213		}
214
215		vector_icon* icon = (vector_icon*)malloc(sizeof(vector_icon));
216		if (icon == NULL) {
217			// ran out of memory, delete the icon data
218			delete[] data;
219			continue;
220		}
221
222		icon->data = data;
223		icon->size = size;
224
225		// found a vector icon, add it to the list
226		fVectorIcons.AddItem(icon);
227		if (fVectorIcons.CountItems() >= kMaxIconCount) {
228			// this is enough to choose from, stop eating memory...
229			return;
230		}
231	}
232}
233