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 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 348 float 349 BackgroundImage::BRectRatio(BRect rect) 350 { 351 return rect.Width() / rect.Height(); 352 } 353 354 355 float 356 BackgroundImage::BRectHorizontalOverlap(BRect hostRect, BRect resizedRect) 357 { 358 return ((hostRect.Height() / resizedRect.Height() * resizedRect.Width()) 359 - hostRect.Width()) / 2; 360 } 361 362 363 float 364 BackgroundImage::BRectVerticalOverlap(BRect hostRect, BRect resizedRect) 365 { 366 return ((hostRect.Width() / resizedRect.Width() * resizedRect.Height()) 367 - hostRect.Height()) / 2; 368 } 369 370 371 void 372 BackgroundImage::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 386 BackgroundImage::BackgroundImageInfo* 387 BackgroundImage::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 418 void 419 BackgroundImage::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 446 void 447 BackgroundImage::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 467 status_t 468 BackgroundImage::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* 521 BackgroundImage::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 536 void 537 BackgroundImage::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 559 Image::Image(BPath path) 560 : 561 fBitmap(NULL), 562 fPath(path) 563 { 564 name = path.Leaf(); 565 } 566 567 568 Image::~Image() 569 { 570 delete fBitmap; 571 } 572 573 574 BBitmap* 575 Image::GetBitmap() 576 { 577 if (!fBitmap) 578 fBitmap = BTranslationUtils::GetBitmap(fPath.Path()); 579 580 return fBitmap; 581 } 582 583