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