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 "BackgroundImage.h"
39
40 #include <new>
41 #include <stdlib.h>
42
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>
55
56 #include "BackgroundsView.h"
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*
GetBackgroundImage(const BNode * node,bool isDesktop,BackgroundsView * view)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,
108 (int32*)&globalCacheMode);
109 container.FindBool(kBackgroundImageRandomChange, &randomChange);
110 }
111
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;
121
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;
129 }
130 }
131 } else
132 break;
133
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);
140
141 if (isDesktop) {
142 container.FindInt32(kBackgroundImageInfoSet, index,
143 (int32*)&imageSet);
144 container.FindInt32(kBackgroundImageInfoCacheMode, index,
145 (int32*)&cacheMode);
146 }
147
148 BackgroundImage::BackgroundImageInfo* imageInfo = new
149 BackgroundImage::BackgroundImageInfo(workspaces, imageIndex,
150 mode, offset, textWidgetLabelOutline, imageSet, cacheMode);
151
152 // imageInfo->UnloadBitmap(globalCacheMode);
153
154 if (imageSet > maxImageSet)
155 maxImageSet = imageSet;
156
157 result->Add(imageInfo);
158 }
159
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;
167 }
168
169 return result;
170 }
171
172
BackgroundImageInfo(uint32 workspaces,int32 imageIndex,Mode mode,BPoint offset,bool textWidgetLabelOutline,uint32 imageSet,uint32 cacheMode)173 BackgroundImage::BackgroundImageInfo::BackgroundImageInfo(uint32 workspaces,
174 int32 imageIndex, Mode mode, BPoint offset, bool textWidgetLabelOutline,
175 uint32 imageSet, uint32 cacheMode)
176 :
177 fWorkspace(workspaces),
178 fImageIndex(imageIndex),
179 fMode(mode),
180 fOffset(offset),
181 fTextWidgetLabelOutline(textWidgetLabelOutline),
182 fImageSet(imageSet),
183 fCacheMode(cacheMode)
184 {
185 }
186
187
~BackgroundImageInfo()188 BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo()
189 {
190 }
191
192
193 // #pragma mark -
194
195
BackgroundImage(const BNode * node,bool desktop,BackgroundsView * view)196 BackgroundImage::BackgroundImage(const BNode* node, bool desktop,
197 BackgroundsView* view)
198 :
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)
210 {
211 }
212
213
~BackgroundImage()214 BackgroundImage::~BackgroundImage()
215 {
216 }
217
218
219 void
Add(BackgroundImageInfo * info)220 BackgroundImage::Add(BackgroundImageInfo* info)
221 {
222 fBitmapForWorkspaceList.AddItem(info);
223 }
224
225
226 void
Remove(BackgroundImageInfo * info)227 BackgroundImage::Remove(BackgroundImageInfo* info)
228 {
229 fBitmapForWorkspaceList.RemoveItem(info);
230 }
231
232
233 void
RemoveAll()234 BackgroundImage::RemoveAll()
235 {
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);
242 }
243 }
244
245
246 void
Show(BView * view,int32 workspace)247 BackgroundImage::Show(BView* view, int32 workspace)
248 {
249 fView = view;
250
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);
258 }
259 }
260
261
262 void
Show(BackgroundImageInfo * info,BView * view)263 BackgroundImage::Show(BackgroundImageInfo* info, BView* view)
264 {
265 BBitmap* bitmap
266 = fBackgroundsView->GetImage(info->fImageIndex)->GetBitmap();
267
268 if (!bitmap)
269 return;
270
271 BRect viewBounds(view->Bounds());
272
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;
277
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;
285
286 uint32 options = 0;
287 uint32 followFlags = B_FOLLOW_TOP | B_FOLLOW_LEFT;
288
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;
298 }
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);
313 }
314 followFlags = B_FOLLOW_ALL;
315 options |= B_FILTER_BITMAP_BILINEAR;
316 break;
317 }
318 // else fall thru
319 case kAtOffset:
320 {
321 destinationBitmapBounds.OffsetTo(offset);
322 break;
323 }
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);
331 //}
332 options |= B_TILE_BITMAP;
333 break;
334 }
335
336 // switch to the bitmap and force a redraw
337 view->SetViewBitmap(bitmap, bitmapBounds, destinationBitmapBounds,
338 followFlags, options);
339 view->Invalidate();
340
341 /*if (fShowingBitmap != info) {
342 if (fShowingBitmap)
343 fShowingBitmap->UnloadBitmap(fCacheMode);
344 fShowingBitmap = info;
345 }*/
346 }
347
348
349 float
BRectRatio(BRect rect)350 BackgroundImage::BRectRatio(BRect rect)
351 {
352 return rect.Width() / rect.Height();
353 }
354
355
356 float
BRectHorizontalOverlap(BRect hostRect,BRect resizedRect)357 BackgroundImage::BRectHorizontalOverlap(BRect hostRect, BRect resizedRect)
358 {
359 return ((hostRect.Height() / resizedRect.Height() * resizedRect.Width())
360 - hostRect.Width()) / 2;
361 }
362
363
364 float
BRectVerticalOverlap(BRect hostRect,BRect resizedRect)365 BackgroundImage::BRectVerticalOverlap(BRect hostRect, BRect resizedRect)
366 {
367 return ((hostRect.Width() / resizedRect.Width() * resizedRect.Height())
368 - hostRect.Height()) / 2;
369 }
370
371
372 void
Remove()373 BackgroundImage::Remove()
374 {
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);*/
382 }
383 fShowingBitmap = NULL;
384 }
385
386
387 BackgroundImage::BackgroundImageInfo*
ImageInfoForWorkspace(int32 workspace) const388 BackgroundImage::ImageInfoForWorkspace(int32 workspace) const
389 {
390 uint32 workspaceMask = 1;
391
392 for (; workspace; workspace--)
393 workspaceMask *= 2;
394
395 int32 count = fBitmapForWorkspaceList.CountItems();
396
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;
405
406 if (fIsDesktop) {
407 if (info->fWorkspace == workspaceMask)
408 return info;
409
410 if (info->fWorkspace & workspaceMask)
411 result = info;
412 } else
413 return info;
414 }
415 return result;
416 }
417
418
419 void
WorkspaceActivated(BView * view,int32 workspace,bool state)420 BackgroundImage::WorkspaceActivated(BView* view, int32 workspace, bool state)
421 {
422 if (!fIsDesktop) {
423 // we only care for desktop bitmaps
424 return;
425 }
426
427 if (!state) {
428 // we only care comming into a new workspace, not leaving one
429 return;
430 }
431
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();
441 }
442 fShowingBitmap = info;
443 }
444 }
445
446
447 void
ScreenChanged(BRect,color_space)448 BackgroundImage::ScreenChanged(BRect, color_space)
449 {
450 if (!fIsDesktop || !fShowingBitmap)
451 return;
452
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);
460
461 fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds,
462 destinationBitmapBounds, B_FOLLOW_NONE, 0);
463 fView->Invalidate();
464 }*/
465 }
466
467
468 status_t
SetBackgroundImage(BNode * node)469 BackgroundImage::SetBackgroundImage(BNode* node)
470 {
471 status_t err;
472 BMessage container;
473 int32 count = fBitmapForWorkspaceList.CountItems();
474
475 for (int32 index = 0; index < count; index++) {
476 BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index);
477
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, "");
486
487 container.AddInt32(kBackgroundImageInfoWorkspaces, info->fWorkspace);
488 container.AddPoint(kBackgroundImageInfoOffset, info->fOffset);
489 container.AddInt32(kBackgroundImageInfoMode, info->fMode);
490
491 if (fIsDesktop)
492 container.AddInt32(kBackgroundImageInfoSet, info->fImageSet);
493 }
494
495 PRINT_OBJECT(container);
496
497 ssize_t flattenedSize = container.FlattenedSize();
498 if (flattenedSize < B_OK)
499 return flattenedSize;
500
501 char* buffer = new(std::nothrow) char[flattenedSize];
502 if (buffer == NULL)
503 return B_NO_MEMORY;
504
505 if ((err = container.Flatten(buffer, flattenedSize)) != B_OK) {
506 delete[] buffer;
507 return err;
508 }
509
510 ssize_t size = node->WriteAttr(kBackgroundImageInfo, B_MESSAGE_TYPE,
511 0, buffer, flattenedSize);
512
513 delete[] buffer;
514
515 if (size < B_OK)
516 return size;
517 if (size != flattenedSize)
518 return B_ERROR;
519
520 return B_OK;
521 }
522
523
524 /*BackgroundImage*
525 BackgroundImage::Refresh(BackgroundImage* oldBackgroundImage,
526 const BNode* fromNode, bool desktop, BPoseView* poseView)
527 {
528 if (oldBackgroundImage) {
529 oldBackgroundImage->Remove();
530 delete oldBackgroundImage;
531 }
532
533 BackgroundImage* result = GetBackgroundImage(fromNode, desktop);
534 if (result && poseView->ViewMode() != kListMode)
535 result->Show(poseView, current_workspace());
536 return result;
537 }
538
539
540 void
541 BackgroundImage::ChangeImageSet(BPoseView* poseView)
542 {
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;
554 }
555
556 this->Show(poseView, current_workspace());
557 }*/
558
559
560 // #pragma mark -
561
562
Image(BPath path)563 Image::Image(BPath path)
564 :
565 fBitmap(NULL),
566 fPath(path)
567 {
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;
577 }
578 }
579
580
~Image()581 Image::~Image()
582 {
583 delete fBitmap;
584 }
585
586
587 BBitmap*
GetBitmap()588 Image::GetBitmap()
589 {
590 if (!fBitmap)
591 fBitmap = BTranslationUtils::GetBitmap(fPath.Path());
592
593 return fBitmap;
594 }
595
596