vfs: check userland buffers before reading them.
[haiku.git] / src / preferences / backgrounds / BackgroundImage.cpp
blobe0a8a4449cdeaa575a53a60201b485d405f733d8
1 /*
2 Open Tracker License
4 Terms and Conditions
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
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:
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.
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.
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.
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.
35 // Classes used for setting up and managing background images
38 #include "BackgroundImage.h"
40 #include <new>
41 #include <stdlib.h>
43 #include <Bitmap.h>
44 #include <Debug.h>
45 #include <fs_attr.h>
46 #include <Node.h>
47 #include <TranslationKit.h>
48 #include <View.h>
49 #include <Window.h>
50 #include <Message.h>
51 #include <Entry.h>
52 #include <Path.h>
53 #include <Screen.h>
54 #include <String.h>
56 #include "BackgroundsView.h"
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";
76 BackgroundImage*
77 BackgroundImage::GetBackgroundImage(const BNode* node, bool isDesktop,
78 BackgroundsView* view)
80 BackgroundImage* result = new BackgroundImage(node, isDesktop, view);
81 attr_info info;
82 if (node->GetAttrInfo(kBackgroundImageInfo, &info) != B_OK)
83 return result;
85 BMessage container;
86 char* buffer = new char [info.size];
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);
93 delete [] buffer;
95 if (error != B_OK)
96 return result;
98 PRINT_OBJECT(container);
100 uint32 imageSetPeriod = 0;
101 uint32 globalCacheMode = 0;
102 bool randomChange = false;
103 uint32 maxImageSet = 0;
105 if (isDesktop) {
106 container.FindInt32(kBackgroundImageSetPeriod, (int32*)&imageSetPeriod);
107 container.FindInt32(kBackgroundImageCacheMode,
108 (int32*)&globalCacheMode);
109 container.FindBool(kBackgroundImageRandomChange, &randomChange);
112 for (int32 index = 0; ; index++) {
113 const char* path;
114 uint32 workspaces = B_ALL_WORKSPACES;
115 Mode mode = kTiled;
116 bool textWidgetLabelOutline = false;
117 BPoint offset;
118 uint32 imageSet = 0;
119 uint32 cacheMode = 0;
120 int32 imageIndex = -1;
122 if (container.FindString(kBackgroundImageInfoPath, index, &path)
123 == B_OK) {
124 if (strcmp(path, "")) {
125 BPath bpath(path);
126 imageIndex = view->AddImage(bpath);
127 if (imageIndex < 0) {
128 imageIndex = -imageIndex - 1;
131 } else
132 break;
134 container.FindInt32(kBackgroundImageInfoWorkspaces, index,
135 (int32*)&workspaces);
136 container.FindInt32(kBackgroundImageInfoMode, index, (int32*)&mode);
137 container.FindBool(kBackgroundImageInfoTextOutline, index,
138 &textWidgetLabelOutline);
139 container.FindPoint(kBackgroundImageInfoOffset, index, &offset);
141 if (isDesktop) {
142 container.FindInt32(kBackgroundImageInfoSet, index,
143 (int32*)&imageSet);
144 container.FindInt32(kBackgroundImageInfoCacheMode, index,
145 (int32*)&cacheMode);
148 BackgroundImage::BackgroundImageInfo* imageInfo = new
149 BackgroundImage::BackgroundImageInfo(workspaces, imageIndex,
150 mode, offset, textWidgetLabelOutline, imageSet, cacheMode);
152 // imageInfo->UnloadBitmap(globalCacheMode);
154 if (imageSet > maxImageSet)
155 maxImageSet = imageSet;
157 result->Add(imageInfo);
160 if (result) {
161 result->fImageSetCount = maxImageSet + 1;
162 result->fRandomChange = randomChange;
163 result->fImageSetPeriod = imageSetPeriod;
164 result->fCacheMode = globalCacheMode;
165 if (result->fImageSetCount > 1)
166 result->fShowingImageSet = random() % result->fImageSetCount;
169 return result;
173 BackgroundImage::BackgroundImageInfo::BackgroundImageInfo(uint32 workspaces,
174 int32 imageIndex, Mode mode, BPoint offset, bool textWidgetLabelOutline,
175 uint32 imageSet, uint32 cacheMode)
177 fWorkspace(workspaces),
178 fImageIndex(imageIndex),
179 fMode(mode),
180 fOffset(offset),
181 fTextWidgetLabelOutline(textWidgetLabelOutline),
182 fImageSet(imageSet),
183 fCacheMode(cacheMode)
188 BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo()
193 // #pragma mark -
196 BackgroundImage::BackgroundImage(const BNode* node, bool desktop,
197 BackgroundsView* view)
199 fIsDesktop(desktop),
200 fDefinedByNode(*node),
201 fView(NULL),
202 fBackgroundsView(view),
203 fShowingBitmap(NULL),
204 fBitmapForWorkspaceList(1, true),
205 fImageSetPeriod(0),
206 fShowingImageSet(0),
207 fImageSetCount(0),
208 fCacheMode(0),
209 fRandomChange(false)
214 BackgroundImage::~BackgroundImage()
219 void
220 BackgroundImage::Add(BackgroundImageInfo* info)
222 fBitmapForWorkspaceList.AddItem(info);
226 void
227 BackgroundImage::Remove(BackgroundImageInfo* info)
229 fBitmapForWorkspaceList.RemoveItem(info);
233 void
234 BackgroundImage::RemoveAll()
236 for (int32 index = 0; index < fBitmapForWorkspaceList.CountItems();) {
237 BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index);
238 if (info->fImageSet != fShowingImageSet)
239 index++;
240 else
241 fBitmapForWorkspaceList.RemoveItemAt(index);
246 void
247 BackgroundImage::Show(BView* view, int32 workspace)
249 fView = view;
251 BackgroundImageInfo* info = ImageInfoForWorkspace(workspace);
252 if (info) {
253 /*BPoseView* poseView = dynamic_cast<BPoseView*>(fView);
254 if (poseView)
255 poseView
256 ->SetEraseWidgetTextBackground(info->fTextWidgetLabelOutline);*/
257 Show(info, fView);
262 void
263 BackgroundImage::Show(BackgroundImageInfo* info, BView* view)
265 BBitmap* bitmap
266 = fBackgroundsView->GetImage(info->fImageIndex)->GetBitmap();
268 if (!bitmap)
269 return;
271 BRect viewBounds(view->Bounds());
273 display_mode mode;
274 BScreen().GetMode(&mode);
275 float x_ratio = viewBounds.Width() / mode.virtual_width;
276 float y_ratio = viewBounds.Height() / mode.virtual_height;
278 BRect bitmapBounds(bitmap->Bounds());
279 BRect destinationBitmapBounds(bitmapBounds);
280 destinationBitmapBounds.right *= x_ratio;
281 destinationBitmapBounds.bottom *= y_ratio;
282 BPoint offset(info->fOffset);
283 offset.x *= x_ratio;
284 offset.y *= y_ratio;
286 uint32 options = 0;
287 uint32 followFlags = B_FOLLOW_TOP | B_FOLLOW_LEFT;
289 // figure out the display mode and the destination bounds for the bitmap
290 switch (info->fMode) {
291 case kCentered:
292 if (fIsDesktop) {
293 destinationBitmapBounds.OffsetBy(
294 (viewBounds.Width() - destinationBitmapBounds.Width()) / 2,
295 (viewBounds.Height() - destinationBitmapBounds.Height())
296 / 2);
297 break;
299 // else fall thru
300 case kScaledToFit:
301 if (fIsDesktop) {
302 if (BRectRatio(destinationBitmapBounds)
303 >= BRectRatio(viewBounds)) {
304 float overlap = BRectHorizontalOverlap(viewBounds,
305 destinationBitmapBounds);
306 destinationBitmapBounds.Set(-overlap, 0,
307 viewBounds.Width() + overlap, viewBounds.Height());
308 } else {
309 float overlap = BRectVerticalOverlap(viewBounds,
310 destinationBitmapBounds);
311 destinationBitmapBounds.Set(0, -overlap,
312 viewBounds.Width(), viewBounds.Height() + overlap);
314 followFlags = B_FOLLOW_ALL;
315 options |= B_FILTER_BITMAP_BILINEAR;
316 break;
318 // else fall thru
319 case kAtOffset:
321 destinationBitmapBounds.OffsetTo(offset);
322 break;
324 case kTiled:
325 // Original Backgrounds Preferences center the tiled paper
326 // but Tracker doesn't do that
327 //if (fIsDesktop) {
328 destinationBitmapBounds.OffsetBy(
329 (viewBounds.Width() - destinationBitmapBounds.Width()) / 2,
330 (viewBounds.Height() - destinationBitmapBounds.Height()) / 2);
332 options |= B_TILE_BITMAP;
333 break;
336 // switch to the bitmap and force a redraw
337 view->SetViewBitmap(bitmap, bitmapBounds, destinationBitmapBounds,
338 followFlags, options);
339 view->Invalidate();
341 /*if (fShowingBitmap != info) {
342 if (fShowingBitmap)
343 fShowingBitmap->UnloadBitmap(fCacheMode);
344 fShowingBitmap = info;
349 float
350 BackgroundImage::BRectRatio(BRect rect)
352 return rect.Width() / rect.Height();
356 float
357 BackgroundImage::BRectHorizontalOverlap(BRect hostRect, BRect resizedRect)
359 return ((hostRect.Height() / resizedRect.Height() * resizedRect.Width())
360 - hostRect.Width()) / 2;
364 float
365 BackgroundImage::BRectVerticalOverlap(BRect hostRect, BRect resizedRect)
367 return ((hostRect.Width() / resizedRect.Width() * resizedRect.Height())
368 - hostRect.Height()) / 2;
372 void
373 BackgroundImage::Remove()
375 if (fShowingBitmap) {
376 fView->ClearViewBitmap();
377 fView->Invalidate();
378 /*BPoseView* poseView = dynamic_cast<BPoseView*>(fView);
379 // make sure text widgets draw the default way, erasing their background
380 if (poseView)
381 poseView->SetEraseWidgetTextBackground(true);*/
383 fShowingBitmap = NULL;
387 BackgroundImage::BackgroundImageInfo*
388 BackgroundImage::ImageInfoForWorkspace(int32 workspace) const
390 uint32 workspaceMask = 1;
392 for (; workspace; workspace--)
393 workspaceMask *= 2;
395 int32 count = fBitmapForWorkspaceList.CountItems();
397 // do a simple lookup for the most likely candidate bitmap -
398 // pick the imageInfo that is only defined for this workspace over one
399 // that supports multiple workspaces
400 BackgroundImageInfo* result = NULL;
401 for (int32 index = 0; index < count; index++) {
402 BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index);
403 if (info->fImageSet != fShowingImageSet)
404 continue;
406 if (fIsDesktop) {
407 if (info->fWorkspace == workspaceMask)
408 return info;
410 if (info->fWorkspace & workspaceMask)
411 result = info;
412 } else
413 return info;
415 return result;
419 void
420 BackgroundImage::WorkspaceActivated(BView* view, int32 workspace, bool state)
422 if (!fIsDesktop) {
423 // we only care for desktop bitmaps
424 return;
427 if (!state) {
428 // we only care comming into a new workspace, not leaving one
429 return;
432 BackgroundImageInfo* info = ImageInfoForWorkspace(workspace);
433 if (info != fShowingBitmap) {
434 if (info)
435 Show(info, view);
436 else {
437 /*if (BPoseView* poseView = dynamic_cast<BPoseView*>(view))
438 poseView->SetEraseWidgetTextBackground(true);*/
439 view->ClearViewBitmap();
440 view->Invalidate();
442 fShowingBitmap = info;
447 void
448 BackgroundImage::ScreenChanged(BRect, color_space)
450 if (!fIsDesktop || !fShowingBitmap)
451 return;
453 /*if (fShowingBitmap->fMode == kCentered) {
454 BRect viewBounds(fView->Bounds());
455 BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds());
456 BRect destinationBitmapBounds(bitmapBounds);
457 destinationBitmapBounds.OffsetBy(
458 (viewBounds.Width() - bitmapBounds.Width()) / 2,
459 (viewBounds.Height() - bitmapBounds.Height()) / 2);
461 fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds,
462 destinationBitmapBounds, B_FOLLOW_NONE, 0);
463 fView->Invalidate();
468 status_t
469 BackgroundImage::SetBackgroundImage(BNode* node)
471 status_t err;
472 BMessage container;
473 int32 count = fBitmapForWorkspaceList.CountItems();
475 for (int32 index = 0; index < count; index++) {
476 BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index);
478 container.AddBool(kBackgroundImageInfoTextOutline,
479 info->fTextWidgetLabelOutline);
480 if (fBackgroundsView->GetImage(info->fImageIndex) != NULL) {
481 container.AddString(kBackgroundImageInfoPath,
482 fBackgroundsView
483 ->GetImage(info->fImageIndex)->GetPath().Path());
484 } else
485 container.AddString(kBackgroundImageInfoPath, "");
487 container.AddInt32(kBackgroundImageInfoWorkspaces, info->fWorkspace);
488 container.AddPoint(kBackgroundImageInfoOffset, info->fOffset);
489 container.AddInt32(kBackgroundImageInfoMode, info->fMode);
491 if (fIsDesktop)
492 container.AddInt32(kBackgroundImageInfoSet, info->fImageSet);
495 PRINT_OBJECT(container);
497 ssize_t flattenedSize = container.FlattenedSize();
498 if (flattenedSize < B_OK)
499 return flattenedSize;
501 char* buffer = new(std::nothrow) char[flattenedSize];
502 if (buffer == NULL)
503 return B_NO_MEMORY;
505 if ((err = container.Flatten(buffer, flattenedSize)) != B_OK) {
506 delete[] buffer;
507 return err;
510 ssize_t size = node->WriteAttr(kBackgroundImageInfo, B_MESSAGE_TYPE,
511 0, buffer, flattenedSize);
513 delete[] buffer;
515 if (size < B_OK)
516 return size;
517 if (size != flattenedSize)
518 return B_ERROR;
520 return B_OK;
524 /*BackgroundImage*
525 BackgroundImage::Refresh(BackgroundImage* oldBackgroundImage,
526 const BNode* fromNode, bool desktop, BPoseView* poseView)
528 if (oldBackgroundImage) {
529 oldBackgroundImage->Remove();
530 delete oldBackgroundImage;
533 BackgroundImage* result = GetBackgroundImage(fromNode, desktop);
534 if (result && poseView->ViewMode() != kListMode)
535 result->Show(poseView, current_workspace());
536 return result;
540 void
541 BackgroundImage::ChangeImageSet(BPoseView* poseView)
543 if (fRandomChange) {
544 if (fImageSetCount > 1) {
545 uint32 oldShowingImageSet = fShowingImageSet;
546 while (oldShowingImageSet == fShowingImageSet)
547 fShowingImageSet = random()%fImageSetCount;
548 } else
549 fShowingImageSet = 0;
550 } else {
551 fShowingImageSet++;
552 if (fShowingImageSet > fImageSetCount - 1)
553 fShowingImageSet = 0;
556 this->Show(poseView, current_workspace());
560 // #pragma mark -
563 Image::Image(BPath path)
565 fBitmap(NULL),
566 fPath(path)
568 const int32 kMaxNameChars = 40;
569 fName = path.Leaf();
570 int extra = fName.CountChars() - kMaxNameChars;
571 if (extra > 0) {
572 BString extension;
573 int offset = fName.FindLast('.');
574 if (offset > 0)
575 fName.CopyInto(extension, ++offset, -1);
576 fName.TruncateChars(kMaxNameChars) << B_UTF8_ELLIPSIS << extension;
581 Image::~Image()
583 delete fBitmap;
587 BBitmap*
588 Image::GetBitmap()
590 if (!fBitmap)
591 fBitmap = BTranslationUtils::GetBitmap(fPath.Path());
593 return fBitmap;