1/* 2Open Tracker License 3 4Terms and Conditions 5 6Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8Permission is hereby granted, free of charge, to any person obtaining a copy of 9this software and associated documentation files (the "Software"), to deal in 10the Software without restriction, including without limitation the rights to 11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12of the Software, and to permit persons to whom the Software is furnished to do 13so, subject to the following conditions: 14 15The above copyright notice and this permission notice applies to all licensees 16and shall be included in all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25Except as contained in this notice, the name of Be Incorporated shall not be 26used in advertising or otherwise to promote the sale, use or other dealings in 27this Software without prior written authorization from Be Incorporated. 28 29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30of Be Incorporated in the United States and other countries. Other brand product 31names are registered trademarks or trademarks of their respective holders. 32All 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 59const char* kBackgroundImageInfo = "be:bgndimginfo"; 60const char* kBackgroundImageInfoOffset = "be:bgndimginfooffset"; 61// const char* kBackgroundImageInfoTextOutline = "be:bgndimginfotextoutline"; 62const 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... 66const char* kBackgroundImageInfoMode = "be:bgndimginfomode"; 67const char* kBackgroundImageInfoWorkspaces = "be:bgndimginfoworkspaces"; 68const char* kBackgroundImageInfoPath = "be:bgndimginfopath"; 69const char* kBackgroundImageInfoSet = "be:bgndimginfoset"; 70const char* kBackgroundImageInfoCacheMode = "be:bgndimginfocachemode"; 71const char* kBackgroundImageSetPeriod = "be:bgndimgsetperiod"; 72const char* kBackgroundImageRandomChange = "be:bgndimgrandomchange"; 73const char* kBackgroundImageCacheMode = "be:bgndimgcachemode"; 74 75 76BackgroundImage* 77BackgroundImage::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 173BackgroundImage::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 188BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo() 189{ 190} 191 192 193// #pragma mark - 194 195 196BackgroundImage::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 214BackgroundImage::~BackgroundImage() 215{ 216} 217 218 219void 220BackgroundImage::Add(BackgroundImageInfo* info) 221{ 222 fBitmapForWorkspaceList.AddItem(info); 223} 224 225 226void 227BackgroundImage::Remove(BackgroundImageInfo* info) 228{ 229 fBitmapForWorkspaceList.RemoveItem(info); 230} 231 232 233void 234BackgroundImage::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 246void 247BackgroundImage::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 262void 263BackgroundImage::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 tile = 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 break; 316 } 317 // else fall thru 318 case kAtOffset: 319 { 320 destinationBitmapBounds.OffsetTo(offset); 321 break; 322 } 323 case kTiled: 324 // Original Backgrounds Preferences center the tiled paper 325 // but Tracker doesn't do that 326 //if (fIsDesktop) { 327 destinationBitmapBounds.OffsetBy( 328 (viewBounds.Width() - destinationBitmapBounds.Width()) / 2, 329 (viewBounds.Height() - destinationBitmapBounds.Height()) / 2); 330 //} 331 tile = B_TILE_BITMAP; 332 break; 333 } 334 335 // switch to the bitmap and force a redraw 336 view->SetViewBitmap(bitmap, bitmapBounds, destinationBitmapBounds, 337 followFlags, tile); 338 view->Invalidate(); 339 340 /*if (fShowingBitmap != info) { 341 if (fShowingBitmap) 342 fShowingBitmap->UnloadBitmap(fCacheMode); 343 fShowingBitmap = info; 344 }*/ 345} 346 347 348float 349BackgroundImage::BRectRatio(BRect rect) 350{ 351 return rect.Width() / rect.Height(); 352} 353 354 355float 356BackgroundImage::BRectHorizontalOverlap(BRect hostRect, BRect resizedRect) 357{ 358 return ((hostRect.Height() / resizedRect.Height() * resizedRect.Width()) 359 - hostRect.Width()) / 2; 360} 361 362 363float 364BackgroundImage::BRectVerticalOverlap(BRect hostRect, BRect resizedRect) 365{ 366 return ((hostRect.Width() / resizedRect.Width() * resizedRect.Height()) 367 - hostRect.Height()) / 2; 368} 369 370 371void 372BackgroundImage::Remove() 373{ 374 if (fShowingBitmap) { 375 fView->ClearViewBitmap(); 376 fView->Invalidate(); 377 /*BPoseView* poseView = dynamic_cast<BPoseView*>(fView); 378 // make sure text widgets draw the default way, erasing their background 379 if (poseView) 380 poseView->SetEraseWidgetTextBackground(true);*/ 381 } 382 fShowingBitmap = NULL; 383} 384 385 386BackgroundImage::BackgroundImageInfo* 387BackgroundImage::ImageInfoForWorkspace(int32 workspace) const 388{ 389 uint32 workspaceMask = 1; 390 391 for (; workspace; workspace--) 392 workspaceMask *= 2; 393 394 int32 count = fBitmapForWorkspaceList.CountItems(); 395 396 // do a simple lookup for the most likely candidate bitmap - 397 // pick the imageInfo that is only defined for this workspace over one 398 // that supports multiple workspaces 399 BackgroundImageInfo* result = NULL; 400 for (int32 index = 0; index < count; index++) { 401 BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index); 402 if (info->fImageSet != fShowingImageSet) 403 continue; 404 405 if (fIsDesktop) { 406 if (info->fWorkspace == workspaceMask) 407 return info; 408 409 if (info->fWorkspace & workspaceMask) 410 result = info; 411 } else 412 return info; 413 } 414 return result; 415} 416 417 418void 419BackgroundImage::WorkspaceActivated(BView* view, int32 workspace, bool state) 420{ 421 if (!fIsDesktop) { 422 // we only care for desktop bitmaps 423 return; 424 } 425 426 if (!state) { 427 // we only care comming into a new workspace, not leaving one 428 return; 429 } 430 431 BackgroundImageInfo* info = ImageInfoForWorkspace(workspace); 432 if (info != fShowingBitmap) { 433 if (info) 434 Show(info, view); 435 else { 436 /*if (BPoseView* poseView = dynamic_cast<BPoseView*>(view)) 437 poseView->SetEraseWidgetTextBackground(true);*/ 438 view->ClearViewBitmap(); 439 view->Invalidate(); 440 } 441 fShowingBitmap = info; 442 } 443} 444 445 446void 447BackgroundImage::ScreenChanged(BRect, color_space) 448{ 449 if (!fIsDesktop || !fShowingBitmap) 450 return; 451 452 /*if (fShowingBitmap->fMode == kCentered) { 453 BRect viewBounds(fView->Bounds()); 454 BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds()); 455 BRect destinationBitmapBounds(bitmapBounds); 456 destinationBitmapBounds.OffsetBy( 457 (viewBounds.Width() - bitmapBounds.Width()) / 2, 458 (viewBounds.Height() - bitmapBounds.Height()) / 2); 459 460 fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds, 461 destinationBitmapBounds, B_FOLLOW_NONE, 0); 462 fView->Invalidate(); 463 }*/ 464} 465 466 467status_t 468BackgroundImage::SetBackgroundImage(BNode* node) 469{ 470 status_t err; 471 BMessage container; 472 int32 count = fBitmapForWorkspaceList.CountItems(); 473 474 for (int32 index = 0; index < count; index++) { 475 BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index); 476 477 container.AddBool(kBackgroundImageInfoTextOutline, 478 info->fTextWidgetLabelOutline); 479 if (fBackgroundsView->GetImage(info->fImageIndex) != NULL) { 480 container.AddString(kBackgroundImageInfoPath, 481 fBackgroundsView 482 ->GetImage(info->fImageIndex)->GetPath().Path()); 483 } else 484 container.AddString(kBackgroundImageInfoPath, ""); 485 486 container.AddInt32(kBackgroundImageInfoWorkspaces, info->fWorkspace); 487 container.AddPoint(kBackgroundImageInfoOffset, info->fOffset); 488 container.AddInt32(kBackgroundImageInfoMode, info->fMode); 489 490 if (fIsDesktop) 491 container.AddInt32(kBackgroundImageInfoSet, info->fImageSet); 492 } 493 494 PRINT_OBJECT(container); 495 496 size_t flattenedSize = container.FlattenedSize(); 497 char* buffer = new(std::nothrow) char[flattenedSize]; 498 if (buffer == NULL) 499 return B_NO_MEMORY; 500 501 if ((err = container.Flatten(buffer, flattenedSize)) != B_OK) { 502 delete[] buffer; 503 return err; 504 } 505 506 ssize_t size = node->WriteAttr(kBackgroundImageInfo, B_MESSAGE_TYPE, 507 0, buffer, flattenedSize); 508 509 delete[] buffer; 510 511 if (size < B_OK) 512 return size; 513 if ((size_t)size != flattenedSize) 514 return B_ERROR; 515 516 return B_OK; 517} 518 519 520/*BackgroundImage* 521BackgroundImage::Refresh(BackgroundImage* oldBackgroundImage, 522 const BNode* fromNode, bool desktop, BPoseView* poseView) 523{ 524 if (oldBackgroundImage) { 525 oldBackgroundImage->Remove(); 526 delete oldBackgroundImage; 527 } 528 529 BackgroundImage* result = GetBackgroundImage(fromNode, desktop); 530 if (result && poseView->ViewMode() != kListMode) 531 result->Show(poseView, current_workspace()); 532 return result; 533} 534 535 536void 537BackgroundImage::ChangeImageSet(BPoseView* poseView) 538{ 539 if (fRandomChange) { 540 if (fImageSetCount > 1) { 541 uint32 oldShowingImageSet = fShowingImageSet; 542 while (oldShowingImageSet == fShowingImageSet) 543 fShowingImageSet = random()%fImageSetCount; 544 } else 545 fShowingImageSet = 0; 546 } else { 547 fShowingImageSet++; 548 if (fShowingImageSet > fImageSetCount - 1) 549 fShowingImageSet = 0; 550 } 551 552 this->Show(poseView, current_workspace()); 553}*/ 554 555 556// #pragma mark - 557 558 559Image::Image(BPath path) 560 : 561 fBitmap(NULL), 562 fPath(path) 563{ 564 const int32 kMaxNameChars = 40; 565 fName = path.Leaf(); 566 int extra = fName.CountChars() - kMaxNameChars; 567 if (extra > 0) { 568 BString extension; 569 int offset = fName.FindLast('.'); 570 if (offset > 0) 571 fName.CopyInto(extension, ++offset, -1); 572 fName.TruncateChars(kMaxNameChars) << B_UTF8_ELLIPSIS << extension; 573 } 574} 575 576 577Image::~Image() 578{ 579 delete fBitmap; 580} 581 582 583BBitmap* 584Image::GetBitmap() 585{ 586 if (!fBitmap) 587 fBitmap = BTranslationUtils::GetBitmap(fPath.Path()); 588 589 return fBitmap; 590} 591 592