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* 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 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 188 BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo() 189 { 190 } 191 192 193 // #pragma mark - 194 195 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 214 BackgroundImage::~BackgroundImage() 215 { 216 } 217 218 219 void 220 BackgroundImage::Add(BackgroundImageInfo* info) 221 { 222 fBitmapForWorkspaceList.AddItem(info); 223 } 224 225 226 void 227 BackgroundImage::Remove(BackgroundImageInfo* info) 228 { 229 fBitmapForWorkspaceList.RemoveItem(info); 230 } 231 232 233 void 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 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 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 350 BackgroundImage::BRectRatio(BRect rect) 351 { 352 return rect.Width() / rect.Height(); 353 } 354 355 356 float 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 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 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* 388 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 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 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 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 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 581 Image::~Image() 582 { 583 delete fBitmap; 584 } 585 586 587 BBitmap* 588 Image::GetBitmap() 589 { 590 if (!fBitmap) 591 fBitmap = BTranslationUtils::GetBitmap(fPath.Path()); 592 593 return fBitmap; 594 } 595 596