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 destinationBitmapBounds = viewBounds; 303 followFlags = B_FOLLOW_ALL; 304 break; 305 } 306 // else fall thru 307 case kAtOffset: 308 { 309 destinationBitmapBounds.OffsetTo(offset); 310 break; 311 } 312 case kTiled: 313 // Original Backgrounds Preferences center the tiled paper 314 // but Tracker doesn't do that 315 //if (fIsDesktop) { 316 destinationBitmapBounds.OffsetBy( 317 (viewBounds.Width() - destinationBitmapBounds.Width()) / 2, 318 (viewBounds.Height() - destinationBitmapBounds.Height()) / 2); 319 //} 320 tile = B_TILE_BITMAP; 321 break; 322 } 323 324 // switch to the bitmap and force a redraw 325 view->SetViewBitmap(bitmap, bitmapBounds, destinationBitmapBounds, 326 followFlags, tile); 327 view->Invalidate(); 328 329 /*if (fShowingBitmap != info) { 330 if (fShowingBitmap) 331 fShowingBitmap->UnloadBitmap(fCacheMode); 332 fShowingBitmap = info; 333 }*/ 334 } 335 336 337 void 338 BackgroundImage::Remove() 339 { 340 if (fShowingBitmap) { 341 fView->ClearViewBitmap(); 342 fView->Invalidate(); 343 /*BPoseView* poseView = dynamic_cast<BPoseView*>(fView); 344 // make sure text widgets draw the default way, erasing their background 345 if (poseView) 346 poseView->SetEraseWidgetTextBackground(true);*/ 347 } 348 fShowingBitmap = NULL; 349 } 350 351 352 BackgroundImage::BackgroundImageInfo* 353 BackgroundImage::ImageInfoForWorkspace(int32 workspace) const 354 { 355 uint32 workspaceMask = 1; 356 357 for (; workspace; workspace--) 358 workspaceMask *= 2; 359 360 int32 count = fBitmapForWorkspaceList.CountItems(); 361 362 // do a simple lookup for the most likely candidate bitmap - 363 // pick the imageInfo that is only defined for this workspace over one 364 // that supports multiple workspaces 365 BackgroundImageInfo* result = NULL; 366 for (int32 index = 0; index < count; index++) { 367 BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index); 368 if (info->fImageSet != fShowingImageSet) 369 continue; 370 371 if (fIsDesktop) { 372 if (info->fWorkspace == workspaceMask) 373 return info; 374 375 if (info->fWorkspace & workspaceMask) 376 result = info; 377 } else 378 return info; 379 } 380 return result; 381 } 382 383 384 void 385 BackgroundImage::WorkspaceActivated(BView* view, int32 workspace, bool state) 386 { 387 if (!fIsDesktop) { 388 // we only care for desktop bitmaps 389 return; 390 } 391 392 if (!state) { 393 // we only care comming into a new workspace, not leaving one 394 return; 395 } 396 397 BackgroundImageInfo* info = ImageInfoForWorkspace(workspace); 398 if (info != fShowingBitmap) { 399 if (info) 400 Show(info, view); 401 else { 402 /*if (BPoseView* poseView = dynamic_cast<BPoseView*>(view)) 403 poseView->SetEraseWidgetTextBackground(true);*/ 404 view->ClearViewBitmap(); 405 view->Invalidate(); 406 } 407 fShowingBitmap = info; 408 } 409 } 410 411 412 void 413 BackgroundImage::ScreenChanged(BRect, color_space) 414 { 415 if (!fIsDesktop || !fShowingBitmap) 416 return; 417 418 /*if (fShowingBitmap->fMode == kCentered) { 419 BRect viewBounds(fView->Bounds()); 420 BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds()); 421 BRect destinationBitmapBounds(bitmapBounds); 422 destinationBitmapBounds.OffsetBy( 423 (viewBounds.Width() - bitmapBounds.Width()) / 2, 424 (viewBounds.Height() - bitmapBounds.Height()) / 2); 425 426 fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds, 427 destinationBitmapBounds, B_FOLLOW_NONE, 0); 428 fView->Invalidate(); 429 }*/ 430 } 431 432 433 status_t 434 BackgroundImage::SetBackgroundImage(BNode* node) 435 { 436 status_t err; 437 BMessage container; 438 int32 count = fBitmapForWorkspaceList.CountItems(); 439 440 for (int32 index = 0; index < count; index++) { 441 BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index); 442 443 container.AddBool(kBackgroundImageInfoTextOutline, 444 info->fTextWidgetLabelOutline); 445 if (fBackgroundsView->GetImage(info->fImageIndex) != NULL) { 446 container.AddString(kBackgroundImageInfoPath, 447 fBackgroundsView 448 ->GetImage(info->fImageIndex)->GetPath().Path()); 449 } else 450 container.AddString(kBackgroundImageInfoPath, ""); 451 452 container.AddInt32(kBackgroundImageInfoWorkspaces, info->fWorkspace); 453 container.AddPoint(kBackgroundImageInfoOffset, info->fOffset); 454 container.AddInt32(kBackgroundImageInfoMode, info->fMode); 455 456 if (fIsDesktop) 457 container.AddInt32(kBackgroundImageInfoSet, info->fImageSet); 458 } 459 460 PRINT_OBJECT(container); 461 462 size_t flattenedSize = container.FlattenedSize(); 463 char* buffer = new(std::nothrow) char[flattenedSize]; 464 if (buffer == NULL) 465 return B_NO_MEMORY; 466 467 if ((err = container.Flatten(buffer, flattenedSize)) != B_OK) { 468 delete[] buffer; 469 return err; 470 } 471 472 ssize_t size = node->WriteAttr(kBackgroundImageInfo, B_MESSAGE_TYPE, 473 0, buffer, flattenedSize); 474 475 delete[] buffer; 476 477 if (size < B_OK) 478 return size; 479 if ((size_t)size != flattenedSize) 480 return B_ERROR; 481 482 return B_OK; 483 } 484 485 486 /*BackgroundImage* 487 BackgroundImage::Refresh(BackgroundImage* oldBackgroundImage, 488 const BNode* fromNode, bool desktop, BPoseView* poseView) 489 { 490 if (oldBackgroundImage) { 491 oldBackgroundImage->Remove(); 492 delete oldBackgroundImage; 493 } 494 495 BackgroundImage* result = GetBackgroundImage(fromNode, desktop); 496 if (result && poseView->ViewMode() != kListMode) 497 result->Show(poseView, current_workspace()); 498 return result; 499 } 500 501 502 void 503 BackgroundImage::ChangeImageSet(BPoseView* poseView) 504 { 505 if (fRandomChange) { 506 if (fImageSetCount > 1) { 507 uint32 oldShowingImageSet = fShowingImageSet; 508 while (oldShowingImageSet == fShowingImageSet) 509 fShowingImageSet = random()%fImageSetCount; 510 } else 511 fShowingImageSet = 0; 512 } else { 513 fShowingImageSet++; 514 if (fShowingImageSet > fImageSetCount - 1) 515 fShowingImageSet = 0; 516 } 517 518 this->Show(poseView, current_workspace()); 519 }*/ 520 521 522 // #pragma mark - 523 524 525 Image::Image(BPath path) 526 : 527 fBitmap(NULL), 528 fPath(path) 529 { 530 name = path.Leaf(); 531 } 532 533 534 Image::~Image() 535 { 536 delete fBitmap; 537 } 538 539 540 BBitmap* 541 Image::GetBitmap() 542 { 543 if (!fBitmap) 544 fBitmap = BTranslationUtils::GetBitmap(fPath.Path()); 545 546 return fBitmap; 547 } 548 549