xref: /haiku/src/preferences/backgrounds/BackgroundImage.cpp (revision 893988af824e65e49e55f517b157db8386e8002b)
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 <Debug.h>
40 #include <Node.h>
41 #include <TranslationKit.h>
42 #include <View.h>
43 #include <Window.h>
44 #include <Message.h>
45 #include <Entry.h>
46 #include <Path.h>
47 #include <Screen.h>
48 #include <String.h>
49 
50 #include <fs_attr.h>
51 #include <stdlib.h>
52 
53 #include "BackgroundImage.h"
54 #include "BackgroundsView.h"
55 
56 #include <new>
57 
58 
59 const char *kBackgroundImageInfo 			= "be:bgndimginfo";
60 const char *kBackgroundImageInfoOffset 		= "be:bgndimginfooffset";
61 //const char *kBackgroundImageInfoTextOutline	= "be:bgndimginfotextoutline";
62 const char *kBackgroundImageInfoTextOutline	= "be:bgndimginfoerasetext";
63 // NOTE: the attribute keeps the old name for backwards compatibility,
64 // just in case some users spend time configuring a few windows with
65 // this feature on or off...
66 const char *kBackgroundImageInfoMode 		= "be:bgndimginfomode";
67 const char *kBackgroundImageInfoWorkspaces 	= "be:bgndimginfoworkspaces";
68 const char *kBackgroundImageInfoPath 		= "be:bgndimginfopath";
69 const char *kBackgroundImageInfoSet 		= "be:bgndimginfoset";
70 const char *kBackgroundImageInfoCacheMode	= "be:bgndimginfocachemode";
71 const char *kBackgroundImageSetPeriod		= "be:bgndimgsetperiod";
72 const char *kBackgroundImageRandomChange	= "be:bgndimgrandomchange";
73 const char *kBackgroundImageCacheMode		= "be:bgndimgcachemode";
74 
75 
76 BackgroundImage *
77 BackgroundImage::GetBackgroundImage(const BNode *node, bool isDesktop,
78 	BackgroundsView* view)
79 {
80 	BackgroundImage *result = new BackgroundImage(node, isDesktop, view);
81 	attr_info info;
82 	if (node->GetAttrInfo(kBackgroundImageInfo, &info) != B_OK)
83 		return result;
84 
85 	BMessage container;
86 	char *buffer = new char [info.size];
87 
88 	status_t error = node->ReadAttr(kBackgroundImageInfo, info.type, 0, buffer,
89 		(size_t)info.size);
90 	if (error == info.size)
91 		error = container.Unflatten(buffer);
92 
93 	delete [] buffer;
94 
95 	if (error != B_OK)
96 		return result;
97 
98 	PRINT_OBJECT(container);
99 
100 	uint32 imageSetPeriod = 0;
101 	uint32 globalCacheMode = 0;
102 	bool randomChange = false;
103 	uint32 maxImageSet = 0;
104 
105 	if (isDesktop) {
106 		container.FindInt32(kBackgroundImageSetPeriod, (int32 *)&imageSetPeriod);
107 		container.FindInt32(kBackgroundImageCacheMode, (int32 *)&globalCacheMode);
108 		container.FindBool(kBackgroundImageRandomChange, &randomChange);
109 	}
110 
111 	for (int32 index = 0; ; index++) {
112 		const char *path;
113 		uint32 workspaces = B_ALL_WORKSPACES;
114 		Mode mode = kTiled;
115 		bool textWidgetLabelOutline = false;
116 		BPoint offset;
117 		uint32 imageSet = 0;
118 		uint32 cacheMode = 0;
119 		int32 imageIndex = -1;
120 
121 		if (container.FindString(kBackgroundImageInfoPath, index, &path) == B_OK) {
122 			if (strcmp(path, "")) {
123 				BPath bpath(path);
124 				imageIndex = view->AddImage(bpath);
125 				if (imageIndex < 0) {
126 					imageIndex = -imageIndex - 1;
127 				}
128 			}
129 		} else
130 			break;
131 
132 		container.FindInt32(kBackgroundImageInfoWorkspaces, index,
133 			(int32 *)&workspaces);
134 		container.FindInt32(kBackgroundImageInfoMode, index, (int32 *)&mode);
135 		container.FindBool(kBackgroundImageInfoTextOutline, index,
136 			&textWidgetLabelOutline);
137 		container.FindPoint(kBackgroundImageInfoOffset, index, &offset);
138 
139 		if (isDesktop) {
140 			container.FindInt32(kBackgroundImageInfoSet, index,
141 				(int32 *)&imageSet);
142 			container.FindInt32(kBackgroundImageInfoCacheMode, index,
143 				(int32 *)&cacheMode);
144 		}
145 
146 		BackgroundImage::BackgroundImageInfo *imageInfo = new
147 			BackgroundImage::BackgroundImageInfo(workspaces, imageIndex,
148 				mode, offset, textWidgetLabelOutline, imageSet, cacheMode);
149 
150 		//imageInfo->UnloadBitmap(globalCacheMode);
151 
152 		if (imageSet > maxImageSet)
153 			maxImageSet = imageSet;
154 
155 		result->Add(imageInfo);
156 	}
157 
158 	if (result) {
159 		result->fImageSetCount = maxImageSet + 1;
160 		result->fRandomChange = randomChange;
161 		result->fImageSetPeriod = imageSetPeriod;
162 		result->fCacheMode = globalCacheMode;
163 		if (result->fImageSetCount > 1)
164 			result->fShowingImageSet = random() % result->fImageSetCount;
165 	}
166 
167 	return result;
168 }
169 
170 
171 BackgroundImage::BackgroundImageInfo::BackgroundImageInfo(uint32 workspaces,
172 	int32 imageIndex, Mode mode, BPoint offset, bool textWidgetLabelOutline,
173 	uint32 imageSet, uint32 cacheMode)
174 	:
175 	fWorkspace(workspaces),
176 	fImageIndex(imageIndex),
177 	fMode(mode),
178 	fOffset(offset),
179 	fTextWidgetLabelOutline(textWidgetLabelOutline),
180 	fImageSet(imageSet),
181 	fCacheMode(cacheMode)
182 {
183 }
184 
185 
186 BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo()
187 {
188 }
189 
190 
191 //	#pragma mark -
192 
193 
194 BackgroundImage::BackgroundImage(const BNode *node, bool desktop, BackgroundsView* view)
195 	:
196 	fIsDesktop(desktop),
197 	fDefinedByNode(*node),
198 	fView(NULL),
199 	fBackgroundsView(view),
200 	fShowingBitmap(NULL),
201 	fBitmapForWorkspaceList(1, true),
202 	fImageSetPeriod(0),
203 	fShowingImageSet(0),
204 	fImageSetCount(0),
205 	fCacheMode(0),
206 	fRandomChange(false)
207 {
208 }
209 
210 
211 BackgroundImage::~BackgroundImage()
212 {
213 }
214 
215 
216 void
217 BackgroundImage::Add(BackgroundImageInfo *info)
218 {
219 	fBitmapForWorkspaceList.AddItem(info);
220 }
221 
222 
223 void
224 BackgroundImage::Remove(BackgroundImageInfo *info)
225 {
226 	fBitmapForWorkspaceList.RemoveItem(info);
227 }
228 
229 
230 void
231 BackgroundImage::RemoveAll()
232 {
233 	for (int32 index = 0; index < fBitmapForWorkspaceList.CountItems();) {
234 		BackgroundImageInfo *info = fBitmapForWorkspaceList.ItemAt(index);
235 		if (info->fImageSet != fShowingImageSet)
236 			index++;
237 		else
238 			fBitmapForWorkspaceList.RemoveItemAt(index);
239 	}
240 }
241 
242 
243 void
244 BackgroundImage::Show(BView *view, int32 workspace)
245 {
246 	fView = view;
247 
248 	BackgroundImageInfo *info = ImageInfoForWorkspace(workspace);
249 	if (info) {
250 		/*BPoseView *poseView = dynamic_cast<BPoseView *>(fView);
251 		if (poseView)
252 			poseView->SetEraseWidgetTextBackground(info->fTextWidgetLabelOutline);*/
253 		Show(info, fView);
254 	}
255 }
256 
257 
258 void
259 BackgroundImage::Show(BackgroundImageInfo *info, BView *view)
260 {
261 	BBitmap *bitmap = fBackgroundsView->GetImage(info->fImageIndex)->GetBitmap();
262 
263 	if (!bitmap)
264 		return;
265 
266 	BRect viewBounds(view->Bounds());
267 
268 	display_mode mode;
269 	BScreen().GetMode(&mode);
270 	float x_ratio = viewBounds.Width() / mode.virtual_width;
271 	float y_ratio = viewBounds.Height() / mode.virtual_height;
272 
273 	BRect bitmapBounds(bitmap->Bounds());
274 	BRect destinationBitmapBounds(bitmapBounds);
275 	destinationBitmapBounds.right *= x_ratio;
276 	destinationBitmapBounds.bottom *= y_ratio;
277 	BPoint offset(info->fOffset);
278 	offset.x *= x_ratio;
279 	offset.y *= y_ratio;
280 
281 	uint32 tile = 0;
282 	uint32 followFlags = B_FOLLOW_TOP | B_FOLLOW_LEFT;
283 
284 	// figure out the display mode and the destination bounds for the bitmap
285 	switch (info->fMode) {
286 		case kCentered:
287 			if (fIsDesktop) {
288 				destinationBitmapBounds.OffsetBy(
289 					(viewBounds.Width() - destinationBitmapBounds.Width()) / 2,
290 					(viewBounds.Height() - destinationBitmapBounds.Height()) / 2);
291 				break;
292 			}
293 			// else fall thru
294 		case kScaledToFit:
295 			if (fIsDesktop) {
296 				destinationBitmapBounds = viewBounds;
297 				followFlags = B_FOLLOW_ALL;
298 				break;
299 			}
300 			// else fall thru
301 		case kAtOffset:
302 		{
303 			destinationBitmapBounds.OffsetTo(offset);
304 			break;
305 		}
306 		case kTiled:
307 			// Original Backgrounds Preferences center the tiled paper but the Tracker don't do that
308 			//if (fIsDesktop) {
309 			destinationBitmapBounds.OffsetBy(
310 				(viewBounds.Width() - destinationBitmapBounds.Width()) / 2,
311 				(viewBounds.Height() - destinationBitmapBounds.Height()) / 2);
312 			//}
313 			tile = B_TILE_BITMAP;
314 			break;
315 	}
316 
317 	// switch to the bitmap and force a redraw
318 	view->SetViewBitmap(bitmap, bitmapBounds, destinationBitmapBounds,
319 		followFlags, tile);
320 	view->Invalidate();
321 
322 	/*if (fShowingBitmap != info) {
323 		if (fShowingBitmap)
324 			fShowingBitmap->UnloadBitmap(fCacheMode);
325 		fShowingBitmap = info;
326 	}*/
327 }
328 
329 
330 void
331 BackgroundImage::Remove()
332 {
333 	if (fShowingBitmap) {
334 		fView->ClearViewBitmap();
335 		fView->Invalidate();
336 		/*BPoseView *poseView = dynamic_cast<BPoseView *>(fView);
337 		// make sure text widgets draw the default way, erasing their background
338 		if (poseView)
339 			poseView->SetEraseWidgetTextBackground(true);*/
340 	}
341 	fShowingBitmap = NULL;
342 }
343 
344 
345 BackgroundImage::BackgroundImageInfo *
346 BackgroundImage::ImageInfoForWorkspace(int32 workspace) const
347 {
348 	uint32 workspaceMask = 1;
349 
350 	for (; workspace; workspace--)
351 		workspaceMask *= 2;
352 
353 	int32 count = fBitmapForWorkspaceList.CountItems();
354 
355 	// do a simple lookup for the most likely candidate bitmap -
356 	// pick the imageInfo that is only defined for this workspace over one
357 	// that supports multiple workspaces
358 	BackgroundImageInfo *result = NULL;
359 	for (int32 index = 0; index < count; index++) {
360 		BackgroundImageInfo *info = fBitmapForWorkspaceList.ItemAt(index);
361 		if (info->fImageSet != fShowingImageSet)
362 			continue;
363 
364 		if (fIsDesktop) {
365 			if (info->fWorkspace == workspaceMask)
366 				return info;
367 
368 			if (info->fWorkspace & workspaceMask)
369 				result = info;
370 		} else
371 			return info;
372 	}
373 	return result;
374 }
375 
376 
377 void
378 BackgroundImage::WorkspaceActivated(BView *view, int32 workspace, bool state)
379 {
380 	if (!fIsDesktop) {
381 		// we only care for desktop bitmaps
382 		return;
383 	}
384 
385 	if (!state) {
386 		// we only care comming into a new workspace, not leaving one
387 		return;
388 	}
389 
390 	BackgroundImageInfo *info = ImageInfoForWorkspace(workspace);
391 	if (info != fShowingBitmap) {
392 		if (info)
393 			Show(info, view);
394 		else {
395 			/*if (BPoseView *poseView = dynamic_cast<BPoseView *>(view))
396 				poseView->SetEraseWidgetTextBackground(true);*/
397 			view->ClearViewBitmap();
398 			view->Invalidate();
399 		}
400 		fShowingBitmap = info;
401 	}
402 }
403 
404 
405 void
406 BackgroundImage::ScreenChanged(BRect, color_space)
407 {
408 	if (!fIsDesktop || !fShowingBitmap)
409 		return;
410 
411 	/*if (fShowingBitmap->fMode == kCentered) {
412 		BRect viewBounds(fView->Bounds());
413 		BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds());
414 		BRect destinationBitmapBounds(bitmapBounds);
415 		destinationBitmapBounds.OffsetBy(
416 			(viewBounds.Width() - bitmapBounds.Width()) / 2,
417 			(viewBounds.Height() - bitmapBounds.Height()) / 2);
418 
419 		fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds, destinationBitmapBounds,
420 			B_FOLLOW_NONE, 0);
421 		fView->Invalidate();
422 	}*/
423 }
424 
425 
426 status_t
427 BackgroundImage::SetBackgroundImage(BNode *node)
428 {
429 	status_t err;
430 	BMessage container;
431 	int32 count = fBitmapForWorkspaceList.CountItems();
432 
433 	for (int32 index = 0; index < count; index++) {
434 		BackgroundImageInfo *info = fBitmapForWorkspaceList.ItemAt(index);
435 
436 		container.AddBool(kBackgroundImageInfoTextOutline,
437 			info->fTextWidgetLabelOutline);
438 		if (fBackgroundsView->GetImage(info->fImageIndex) != NULL) {
439 			container.AddString(kBackgroundImageInfoPath,
440 				fBackgroundsView->GetImage(info->fImageIndex)->GetPath().Path());
441 		} else
442 			container.AddString(kBackgroundImageInfoPath, "");
443 
444 		container.AddInt32(kBackgroundImageInfoWorkspaces, info->fWorkspace);
445 		container.AddPoint(kBackgroundImageInfoOffset, info->fOffset);
446 		container.AddInt32(kBackgroundImageInfoMode, info->fMode);
447 
448 		if (fIsDesktop)
449 			container.AddInt32(kBackgroundImageInfoSet, info->fImageSet);
450 	}
451 
452 	PRINT_OBJECT(container);
453 
454 	size_t flattenedSize = container.FlattenedSize();
455 	char* buffer = new(std::nothrow) char[flattenedSize];
456 	if (buffer == NULL)
457 		return B_NO_MEMORY;
458 
459 	if ((err = container.Flatten(buffer, flattenedSize)) != B_OK)
460 		return err;
461 
462 	ssize_t size = node->WriteAttr(kBackgroundImageInfo, B_MESSAGE_TYPE,
463 		0, buffer, flattenedSize);
464 
465 	delete[] buffer;
466 
467 	if (size < B_OK)
468 		return size;
469 	if ((size_t)size != flattenedSize)
470 		return B_ERROR;
471 
472 	return B_OK;
473 }
474 
475 
476 /*BackgroundImage *
477 BackgroundImage::Refresh(BackgroundImage *oldBackgroundImage,
478 	const BNode *fromNode, bool desktop, BPoseView *poseView)
479 {
480 	if (oldBackgroundImage) {
481 		oldBackgroundImage->Remove();
482 		delete oldBackgroundImage;
483 	}
484 
485 	BackgroundImage *result = GetBackgroundImage(fromNode, desktop);
486 	if (result && poseView->ViewMode() != kListMode)
487 		result->Show(poseView, current_workspace());
488 	return result;
489 }
490 
491 
492 void
493 BackgroundImage::ChangeImageSet(BPoseView *poseView)
494 {
495 	if (fRandomChange) {
496 		if (fImageSetCount > 1) {
497 			uint32 oldShowingImageSet = fShowingImageSet;
498 			while(oldShowingImageSet == fShowingImageSet)
499 				fShowingImageSet = random()%fImageSetCount;
500 		} else
501 			fShowingImageSet = 0;
502 	} else {
503 		fShowingImageSet++;
504 		if (fShowingImageSet > fImageSetCount - 1)
505 			fShowingImageSet = 0;
506 	}
507 
508 	this->Show(poseView, current_workspace());
509 }*/
510 
511 
512 //	#pragma mark -
513 
514 
515 Image::Image(BPath path)
516 	:
517 	fBitmap(NULL),
518 	fPath(path)
519 {
520 	name = path.Leaf();
521 }
522 
523 
524 Image::~Image()
525 {
526 	delete fBitmap;
527 }
528 
529 
530 BBitmap*
531 Image::GetBitmap()
532 {
533 	if (!fBitmap)
534 		fBitmap = BTranslationUtils::GetBitmap(fPath.Path());
535 
536 	return fBitmap;
537 }
538