xref: /haiku/src/preferences/backgrounds/BackgroundImage.cpp (revision be3db2942c0e8dda63cdd226ec3c99309d3eab0c)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 
35 //  Classes used for setting up and managing background images
36 //
37 
38 #include <Bitmap.h>
39 #include <Node.h>
40 #include <TranslationKit.h>
41 #include <View.h>
42 #include <Window.h>
43 #include <Message.h>
44 #include <Entry.h>
45 #include <Path.h>
46 #include <Screen.h>
47 #include <String.h>
48 
49 #include <fs_attr.h>
50 #include <stdlib.h>
51 
52 #include "BackgroundImage.h"
53 #include "BackgroundsView.h"
54 
55 #include <new>
56 
57 
58 const char *kBackgroundImageInfo 			= "be:bgndimginfo";
59 const char *kBackgroundImageInfoOffset 		= "be:bgndimginfooffset";
60 const char *kBackgroundImageInfoEraseText	= "be:bgndimginfoerasetext";
61 const char *kBackgroundImageInfoMode 		= "be:bgndimginfomode";
62 const char *kBackgroundImageInfoWorkspaces 	= "be:bgndimginfoworkspaces";
63 const char *kBackgroundImageInfoPath 		= "be:bgndimginfopath";
64 const char *kBackgroundImageInfoSet 		= "be:bgndimginfoset";
65 const char *kBackgroundImageInfoCacheMode	= "be:bgndimginfocachemode";
66 const char *kBackgroundImageSetPeriod		= "be:bgndimgsetperiod";
67 const char *kBackgroundImageRandomChange	= "be:bgndimgrandomchange";
68 const char *kBackgroundImageCacheMode		= "be:bgndimgcachemode";
69 
70 
71 BackgroundImage *
72 BackgroundImage::GetBackgroundImage(const BNode *node, bool isDesktop,
73 	BackgroundsView* view)
74 {
75 	BackgroundImage *result = new BackgroundImage(node, isDesktop, view);
76 	attr_info info;
77 	if (node->GetAttrInfo(kBackgroundImageInfo, &info) != B_OK)
78 		return result;
79 
80 	BMessage container;
81 	char *buffer = new char [info.size];
82 
83 	status_t error = node->ReadAttr(kBackgroundImageInfo, info.type, 0, buffer,
84 		(size_t)info.size);
85 	if (error == info.size)
86 		error = container.Unflatten(buffer);
87 
88 	delete [] buffer;
89 
90 	if (error != B_OK)
91 		return result;
92 
93 	PRINT_OBJECT(container);
94 
95 	uint32 imageSetPeriod = 0;
96 	uint32 globalCacheMode = 0;
97 	bool randomChange = false;
98 	uint32 maxImageSet = 0;
99 
100 	if (isDesktop) {
101 		container.FindInt32(kBackgroundImageSetPeriod, (int32 *)&imageSetPeriod);
102 		container.FindInt32(kBackgroundImageCacheMode, (int32 *)&globalCacheMode);
103 		container.FindBool(kBackgroundImageRandomChange, &randomChange);
104 	}
105 
106 	for (int32 index = 0; ; index++) {
107 		const char *path;
108 		uint32 workspaces = B_ALL_WORKSPACES;
109 		Mode mode = kTiled;
110 		bool eraseTextWidgetBackground = true;
111 		BPoint offset;
112 		uint32 imageSet = 0;
113 		uint32 cacheMode = 0;
114 		if (container.FindString(kBackgroundImageInfoPath, index, &path) != B_OK)
115 			break;
116 
117 		BPath bpath(path);
118 		int32 imageIndex = view->AddImage(bpath);
119 		if (imageIndex < 0)
120 			imageIndex = -imageIndex - 1;
121 
122 		container.FindInt32(kBackgroundImageInfoWorkspaces, index,
123 			(int32 *)&workspaces);
124 		container.FindInt32(kBackgroundImageInfoMode, index, (int32 *)&mode);
125 		container.FindBool(kBackgroundImageInfoEraseText, index,
126 			&eraseTextWidgetBackground);
127 		container.FindPoint(kBackgroundImageInfoOffset, index, &offset);
128 
129 		if (isDesktop) {
130 			container.FindInt32(kBackgroundImageInfoSet, index,
131 				(int32 *)&imageSet);
132 			container.FindInt32(kBackgroundImageInfoCacheMode, index,
133 				(int32 *)&cacheMode);
134 		}
135 
136 		BackgroundImage::BackgroundImageInfo *imageInfo = new
137 			BackgroundImage::BackgroundImageInfo(workspaces, imageIndex,
138 				mode, offset, eraseTextWidgetBackground, imageSet, cacheMode);
139 
140 		//imageInfo->UnloadBitmap(globalCacheMode);
141 
142 		if (imageSet > maxImageSet)
143 			maxImageSet = imageSet;
144 
145 		result->Add(imageInfo);
146 	}
147 
148 	if (result) {
149 		result->fImageSetCount = maxImageSet + 1;
150 		result->fRandomChange = randomChange;
151 		result->fImageSetPeriod = imageSetPeriod;
152 		result->fCacheMode = globalCacheMode;
153 		if (result->fImageSetCount > 1)
154 			result->fShowingImageSet = random()%result->fImageSetCount;
155 	}
156 
157 	return result;
158 }
159 
160 
161 BackgroundImage::BackgroundImageInfo::BackgroundImageInfo(uint32 workspaces,
162 	int32 imageIndex, Mode mode, BPoint offset, bool eraseTextWidget,
163 	uint32 imageSet, uint32 cacheMode)
164 	:
165 	fWorkspace(workspaces),
166 	fImageIndex(imageIndex),
167 	fMode(mode),
168 	fOffset(offset),
169 	fEraseTextWidgetBackground(eraseTextWidget),
170 	fImageSet(imageSet),
171 	fCacheMode(cacheMode)
172 {
173 }
174 
175 
176 BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo()
177 {
178 }
179 
180 
181 //	#pragma mark -
182 
183 
184 BackgroundImage::BackgroundImage(const BNode *node, bool desktop, BackgroundsView* view)
185 	:
186 	fIsDesktop(desktop),
187 	fDefinedByNode(*node),
188 	fView(NULL),
189 	fBackgroundsView(view),
190 	fShowingBitmap(NULL),
191 	fBitmapForWorkspaceList(1, true),
192 	fImageSetPeriod(0),
193 	fShowingImageSet(0),
194 	fImageSetCount(0),
195 	fCacheMode(0),
196 	fRandomChange(false)
197 {
198 }
199 
200 
201 BackgroundImage::~BackgroundImage()
202 {
203 }
204 
205 
206 void
207 BackgroundImage::Add(BackgroundImageInfo *info)
208 {
209 	fBitmapForWorkspaceList.AddItem(info);
210 }
211 
212 
213 void
214 BackgroundImage::Remove(BackgroundImageInfo *info)
215 {
216 	fBitmapForWorkspaceList.RemoveItem(info);
217 }
218 
219 
220 void
221 BackgroundImage::RemoveAll()
222 {
223 	for (int32 index = 0; index < fBitmapForWorkspaceList.CountItems();) {
224 		BackgroundImageInfo *info = fBitmapForWorkspaceList.ItemAt(index);
225 		if (info->fImageSet != fShowingImageSet)
226 			index++;
227 		else
228 			fBitmapForWorkspaceList.RemoveItemAt(index);
229 	}
230 }
231 
232 
233 void
234 BackgroundImage::Show(BView *view, int32 workspace)
235 {
236 	fView = view;
237 
238 	BackgroundImageInfo *info = ImageInfoForWorkspace(workspace);
239 	if (info) {
240 		/*BPoseView *poseView = dynamic_cast<BPoseView *>(fView);
241 		if (poseView)
242 			poseView->SetEraseWidgetTextBackground(info->fEraseTextWidgetBackground);*/
243 		Show(info, fView);
244 	}
245 }
246 
247 
248 void
249 BackgroundImage::Show(BackgroundImageInfo *info, BView *view)
250 {
251 	BBitmap *bitmap = fBackgroundsView->GetImage(info->fImageIndex)->GetBitmap();
252 
253 	if (!bitmap)
254 		return;
255 
256 	BRect viewBounds(view->Bounds());
257 
258 	display_mode mode;
259 	BScreen().GetMode(&mode);
260 	float x_ratio = viewBounds.Width() / mode.virtual_width;
261 	float y_ratio = viewBounds.Height() / mode.virtual_height;
262 
263 	BRect bitmapBounds(bitmap->Bounds());
264 	BRect destinationBitmapBounds(bitmapBounds);
265 	destinationBitmapBounds.right *= x_ratio;
266 	destinationBitmapBounds.bottom *= y_ratio;
267 	BPoint offset(info->fOffset);
268 	offset.x *= x_ratio;
269 	offset.y *= y_ratio;
270 
271 	uint32 tile = 0;
272 	uint32 followFlags = B_FOLLOW_TOP | B_FOLLOW_LEFT;
273 
274 	// figure out the display mode and the destination bounds for the bitmap
275 	switch (info->fMode) {
276 		case kCentered:
277 			if (fIsDesktop) {
278 				destinationBitmapBounds.OffsetBy(
279 					(viewBounds.Width() - destinationBitmapBounds.Width()) / 2,
280 					(viewBounds.Height() - destinationBitmapBounds.Height()) / 2);
281 				break;
282 			}
283 			// else fall thru
284 		case kScaledToFit:
285 			if (fIsDesktop) {
286 				destinationBitmapBounds = viewBounds;
287 				followFlags = B_FOLLOW_ALL;
288 				break;
289 			}
290 			// else fall thru
291 		case kAtOffset:
292 			{
293 				destinationBitmapBounds.OffsetTo(offset);
294 				break;
295 			}
296 		case kTiled:
297 			// Original Backgrounds Preferences center the tiled paper but the Tracker don't do that
298 			//if (fIsDesktop) {
299 				destinationBitmapBounds.OffsetBy(
300 					(viewBounds.Width() - destinationBitmapBounds.Width()) / 2,
301 					(viewBounds.Height() - destinationBitmapBounds.Height()) / 2);
302 			//}
303 			tile = B_TILE_BITMAP;
304 			break;
305 	}
306 
307 	// switch to the bitmap and force a redraw
308 	view->SetViewBitmap(bitmap, bitmapBounds, destinationBitmapBounds,
309 		followFlags, tile);
310 	view->Invalidate();
311 
312 	/*if(fShowingBitmap != info) {
313 		if(fShowingBitmap)
314 			fShowingBitmap->UnloadBitmap(fCacheMode);
315 		fShowingBitmap = info;
316 	}*/
317 }
318 
319 
320 void
321 BackgroundImage::Remove()
322 {
323 	if (fShowingBitmap) {
324 		fView->ClearViewBitmap();
325 		fView->Invalidate();
326 		/*BPoseView *poseView = dynamic_cast<BPoseView *>(fView);
327 		// make sure text widgets draw the default way, erasing their background
328 		if (poseView)
329 			poseView->SetEraseWidgetTextBackground(true);*/
330 	}
331 	fShowingBitmap = NULL;
332 }
333 
334 
335 BackgroundImage::BackgroundImageInfo *
336 BackgroundImage::ImageInfoForWorkspace(int32 workspace) const
337 {
338 	uint32 workspaceMask = 1;
339 
340 	for (; workspace; workspace--)
341 		workspaceMask *= 2;
342 
343 	int32 count = fBitmapForWorkspaceList.CountItems();
344 
345 	// do a simple lookup for the most likely candidate bitmap -
346 	// pick the imageInfo that is only defined for this workspace over one
347 	// that supports multiple workspaces
348 	BackgroundImageInfo *result = NULL;
349 	for (int32 index = 0; index < count; index++) {
350 		BackgroundImageInfo *info = fBitmapForWorkspaceList.ItemAt(index);
351 		if (info->fImageSet != fShowingImageSet)
352 			continue;
353 
354 		if (fIsDesktop) {
355 			if (info->fWorkspace == workspaceMask)
356 				return info;
357 			if (info->fWorkspace & workspaceMask)
358 				result = info;
359 		} else
360 			return info;
361 	}
362 
363 	return result;
364 }
365 
366 
367 void
368 BackgroundImage::WorkspaceActivated(BView *view, int32 workspace, bool state)
369 {
370 	if (!fIsDesktop) {
371 		// we only care for desktop bitmaps
372 		return;
373 	}
374 
375 	if (!state) {
376 		// we only care comming into a new workspace, not leaving one
377 		return;
378 	}
379 
380 	BackgroundImageInfo *info = ImageInfoForWorkspace(workspace);
381 	if (info != fShowingBitmap) {
382 		if (info)
383 			Show(info, view);
384 		else {
385 			/*if (BPoseView *poseView = dynamic_cast<BPoseView *>(view))
386 				poseView->SetEraseWidgetTextBackground(true);*/
387 			view->ClearViewBitmap();
388 			view->Invalidate();
389 		}
390 		fShowingBitmap = info;
391 	}
392 }
393 
394 
395 void
396 BackgroundImage::ScreenChanged(BRect, color_space)
397 {
398 	if (!fIsDesktop || !fShowingBitmap)
399 		return;
400 
401 	/*if (fShowingBitmap->fMode == kCentered) {
402 		BRect viewBounds(fView->Bounds());
403 		BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds());
404 		BRect destinationBitmapBounds(bitmapBounds);
405 		destinationBitmapBounds.OffsetBy(
406 			(viewBounds.Width() - bitmapBounds.Width()) / 2,
407 			(viewBounds.Height() - bitmapBounds.Height()) / 2);
408 
409 		fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds, destinationBitmapBounds,
410 			B_FOLLOW_NONE, 0);
411 		fView->Invalidate();
412 	}*/
413 }
414 
415 
416 status_t
417 BackgroundImage::SetBackgroundImage(BNode *node)
418 {
419 	status_t err;
420 	BMessage container;
421 	int32 count = fBitmapForWorkspaceList.CountItems();
422 
423 	for (int32 index = 0; index < count; index++) {
424 		BackgroundImageInfo *info = fBitmapForWorkspaceList.ItemAt(index);
425 		if (fBackgroundsView->GetImage(info->fImageIndex) == NULL)
426 			continue;
427 
428 		container.AddBool(kBackgroundImageInfoEraseText,
429 			info->fEraseTextWidgetBackground);
430 		container.AddString(kBackgroundImageInfoPath,
431 			fBackgroundsView->GetImage(info->fImageIndex)->GetPath().Path());
432 		container.AddInt32(kBackgroundImageInfoWorkspaces, info->fWorkspace);
433 		container.AddPoint(kBackgroundImageInfoOffset, info->fOffset);
434 		container.AddInt32(kBackgroundImageInfoMode, info->fMode);
435 
436 		if (fIsDesktop)
437 			container.AddInt32(kBackgroundImageInfoSet, info->fImageSet);
438 	}
439 
440 	PRINT_OBJECT(container);
441 
442 	size_t flattenedSize = container.FlattenedSize();
443 	char* buffer = new (std::nothrow) char[flattenedSize];
444 	if (buffer == NULL)
445 		return B_NO_MEMORY;
446 
447 	if ((err = container.Flatten(buffer, flattenedSize)) != B_OK)
448 		return err;
449 
450 	ssize_t size = node->WriteAttr(kBackgroundImageInfo, B_MESSAGE_TYPE,
451 		0, buffer, flattenedSize);
452 
453 	delete[] buffer;
454 
455 	if (size < B_OK)
456 		return size;
457 	if ((size_t)size != flattenedSize)
458 		return B_ERROR;
459 
460 	return B_OK;
461 }
462 
463 
464 /*BackgroundImage *
465 BackgroundImage::Refresh(BackgroundImage *oldBackgroundImage,
466 	const BNode *fromNode, bool desktop, BPoseView *poseView)
467 {
468 	if (oldBackgroundImage) {
469 		oldBackgroundImage->Remove();
470 		delete oldBackgroundImage;
471 	}
472 
473 	BackgroundImage *result = GetBackgroundImage(fromNode, desktop);
474 	if (result && poseView->ViewMode() != kListMode)
475 		result->Show(poseView, current_workspace());
476 	return result;
477 }
478 
479 
480 void
481 BackgroundImage::ChangeImageSet(BPoseView *poseView)
482 {
483 	if(fRandomChange) {
484 		if(fImageSetCount > 1) {
485 			uint32 oldShowingImageSet = fShowingImageSet;
486 			while(oldShowingImageSet == fShowingImageSet)
487 				fShowingImageSet = random()%fImageSetCount;
488 		} else
489 			fShowingImageSet = 0;
490 	} else {
491 		fShowingImageSet++;
492 		if(fShowingImageSet > fImageSetCount - 1)
493 			fShowingImageSet = 0;
494 	}
495 
496 	this->Show(poseView, current_workspace());
497 }*/
498 
499 
500 //	#pragma mark -
501 
502 
503 Image::Image(BPath path)
504 	:
505 	fBitmap(NULL),
506 	fPath(path)
507 {
508 	name = path.Leaf();
509 }
510 
511 
512 Image::~Image()
513 {
514 	delete fBitmap;
515 }
516 
517 
518 BBitmap*
519 Image::GetBitmap()
520 {
521 	if (!fBitmap)
522 		fBitmap = BTranslationUtils::GetBitmap(fPath.Path());
523 
524 	return fBitmap;
525 }
526