xref: /haiku/src/add-ons/screen_savers/icons/IconsSaver.cpp (revision a127b88ecbfab58f64944c98aa47722a18e363b2)
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 
33 static const int32 kMaxConcurrentIcons = 15;
34 static const int32 kMinIconWidthPercentage = 5;
35 	// percentage of the screen width
36 static const int32 kMaxIconWidthPercentage = 20;
37 	// same here
38 static const int32 kMinIconCount = 20;
39 static const int32 kMaxIconCount = 384;
40 
41 
42 const rgb_color kBackgroundColor = ui_color(B_DESKTOP_COLOR);
43 
44 
45 BScreenSaver* instantiate_screen_saver(BMessage* msg, image_id image)
46 {
47 	return new IconsSaver(msg, image);
48 }
49 
50 
51 //	#pragma mark - IconsSaver
52 
53 
54 IconsSaver::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 
66 IconsSaver::~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 
76 status_t
77 IconsSaver::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 
122 void
123 IconsSaver::StopSaver()
124 {
125 	delete[] fIcons;
126 	fIcons = NULL;
127 	delete fBackBitmap;
128 	fBackBitmap = NULL;
129 }
130 
131 
132 void
133 IconsSaver::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 
182 void
183 IconsSaver::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 
193 void
194 IconsSaver::_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