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