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 <Bitmap.h> 39 #include <Debug.h> 40 #include <Node.h> 41 #include <TranslationKit.h> 42 #include <View.h> 43 #include <Window.h> 44 #include <Message.h> 45 #include <Entry.h> 46 #include <Path.h> 47 #include <Screen.h> 48 #include <String.h> 49 50 #include <fs_attr.h> 51 #include <stdlib.h> 52 53 #include "BackgroundImage.h" 54 #include "BackgroundsView.h" 55 56 #include <new> 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, (int32 *)&globalCacheMode); 108 container.FindBool(kBackgroundImageRandomChange, &randomChange); 109 } 110 111 for (int32 index = 0; ; index++) { 112 const char *path; 113 uint32 workspaces = B_ALL_WORKSPACES; 114 Mode mode = kTiled; 115 bool textWidgetLabelOutline = false; 116 BPoint offset; 117 uint32 imageSet = 0; 118 uint32 cacheMode = 0; 119 int32 imageIndex = -1; 120 121 if (container.FindString(kBackgroundImageInfoPath, index, &path) == B_OK) { 122 if (strcmp(path, "")) { 123 BPath bpath(path); 124 imageIndex = view->AddImage(bpath); 125 if (imageIndex < 0) { 126 imageIndex = -imageIndex - 1; 127 } 128 } 129 } else 130 break; 131 132 container.FindInt32(kBackgroundImageInfoWorkspaces, index, 133 (int32 *)&workspaces); 134 container.FindInt32(kBackgroundImageInfoMode, index, (int32 *)&mode); 135 container.FindBool(kBackgroundImageInfoTextOutline, index, 136 &textWidgetLabelOutline); 137 container.FindPoint(kBackgroundImageInfoOffset, index, &offset); 138 139 if (isDesktop) { 140 container.FindInt32(kBackgroundImageInfoSet, index, 141 (int32 *)&imageSet); 142 container.FindInt32(kBackgroundImageInfoCacheMode, index, 143 (int32 *)&cacheMode); 144 } 145 146 BackgroundImage::BackgroundImageInfo *imageInfo = new 147 BackgroundImage::BackgroundImageInfo(workspaces, imageIndex, 148 mode, offset, textWidgetLabelOutline, imageSet, cacheMode); 149 150 //imageInfo->UnloadBitmap(globalCacheMode); 151 152 if (imageSet > maxImageSet) 153 maxImageSet = imageSet; 154 155 result->Add(imageInfo); 156 } 157 158 if (result) { 159 result->fImageSetCount = maxImageSet + 1; 160 result->fRandomChange = randomChange; 161 result->fImageSetPeriod = imageSetPeriod; 162 result->fCacheMode = globalCacheMode; 163 if (result->fImageSetCount > 1) 164 result->fShowingImageSet = random() % result->fImageSetCount; 165 } 166 167 return result; 168 } 169 170 171 BackgroundImage::BackgroundImageInfo::BackgroundImageInfo(uint32 workspaces, 172 int32 imageIndex, Mode mode, BPoint offset, bool textWidgetLabelOutline, 173 uint32 imageSet, uint32 cacheMode) 174 : 175 fWorkspace(workspaces), 176 fImageIndex(imageIndex), 177 fMode(mode), 178 fOffset(offset), 179 fTextWidgetLabelOutline(textWidgetLabelOutline), 180 fImageSet(imageSet), 181 fCacheMode(cacheMode) 182 { 183 } 184 185 186 BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo() 187 { 188 } 189 190 191 // #pragma mark - 192 193 194 BackgroundImage::BackgroundImage(const BNode *node, bool desktop, BackgroundsView* view) 195 : 196 fIsDesktop(desktop), 197 fDefinedByNode(*node), 198 fView(NULL), 199 fBackgroundsView(view), 200 fShowingBitmap(NULL), 201 fBitmapForWorkspaceList(1, true), 202 fImageSetPeriod(0), 203 fShowingImageSet(0), 204 fImageSetCount(0), 205 fCacheMode(0), 206 fRandomChange(false) 207 { 208 } 209 210 211 BackgroundImage::~BackgroundImage() 212 { 213 } 214 215 216 void 217 BackgroundImage::Add(BackgroundImageInfo *info) 218 { 219 fBitmapForWorkspaceList.AddItem(info); 220 } 221 222 223 void 224 BackgroundImage::Remove(BackgroundImageInfo *info) 225 { 226 fBitmapForWorkspaceList.RemoveItem(info); 227 } 228 229 230 void 231 BackgroundImage::RemoveAll() 232 { 233 for (int32 index = 0; index < fBitmapForWorkspaceList.CountItems();) { 234 BackgroundImageInfo *info = fBitmapForWorkspaceList.ItemAt(index); 235 if (info->fImageSet != fShowingImageSet) 236 index++; 237 else 238 fBitmapForWorkspaceList.RemoveItemAt(index); 239 } 240 } 241 242 243 void 244 BackgroundImage::Show(BView *view, int32 workspace) 245 { 246 fView = view; 247 248 BackgroundImageInfo *info = ImageInfoForWorkspace(workspace); 249 if (info) { 250 /*BPoseView *poseView = dynamic_cast<BPoseView *>(fView); 251 if (poseView) 252 poseView->SetEraseWidgetTextBackground(info->fTextWidgetLabelOutline);*/ 253 Show(info, fView); 254 } 255 } 256 257 258 void 259 BackgroundImage::Show(BackgroundImageInfo *info, BView *view) 260 { 261 BBitmap *bitmap = fBackgroundsView->GetImage(info->fImageIndex)->GetBitmap(); 262 263 if (!bitmap) 264 return; 265 266 BRect viewBounds(view->Bounds()); 267 268 display_mode mode; 269 BScreen().GetMode(&mode); 270 float x_ratio = viewBounds.Width() / mode.virtual_width; 271 float y_ratio = viewBounds.Height() / mode.virtual_height; 272 273 BRect bitmapBounds(bitmap->Bounds()); 274 BRect destinationBitmapBounds(bitmapBounds); 275 destinationBitmapBounds.right *= x_ratio; 276 destinationBitmapBounds.bottom *= y_ratio; 277 BPoint offset(info->fOffset); 278 offset.x *= x_ratio; 279 offset.y *= y_ratio; 280 281 uint32 tile = 0; 282 uint32 followFlags = B_FOLLOW_TOP | B_FOLLOW_LEFT; 283 284 // figure out the display mode and the destination bounds for the bitmap 285 switch (info->fMode) { 286 case kCentered: 287 if (fIsDesktop) { 288 destinationBitmapBounds.OffsetBy( 289 (viewBounds.Width() - destinationBitmapBounds.Width()) / 2, 290 (viewBounds.Height() - destinationBitmapBounds.Height()) / 2); 291 break; 292 } 293 // else fall thru 294 case kScaledToFit: 295 if (fIsDesktop) { 296 destinationBitmapBounds = viewBounds; 297 followFlags = B_FOLLOW_ALL; 298 break; 299 } 300 // else fall thru 301 case kAtOffset: 302 { 303 destinationBitmapBounds.OffsetTo(offset); 304 break; 305 } 306 case kTiled: 307 // Original Backgrounds Preferences center the tiled paper but the Tracker don't do that 308 //if (fIsDesktop) { 309 destinationBitmapBounds.OffsetBy( 310 (viewBounds.Width() - destinationBitmapBounds.Width()) / 2, 311 (viewBounds.Height() - destinationBitmapBounds.Height()) / 2); 312 //} 313 tile = B_TILE_BITMAP; 314 break; 315 } 316 317 // switch to the bitmap and force a redraw 318 view->SetViewBitmap(bitmap, bitmapBounds, destinationBitmapBounds, 319 followFlags, tile); 320 view->Invalidate(); 321 322 /*if (fShowingBitmap != info) { 323 if (fShowingBitmap) 324 fShowingBitmap->UnloadBitmap(fCacheMode); 325 fShowingBitmap = info; 326 }*/ 327 } 328 329 330 void 331 BackgroundImage::Remove() 332 { 333 if (fShowingBitmap) { 334 fView->ClearViewBitmap(); 335 fView->Invalidate(); 336 /*BPoseView *poseView = dynamic_cast<BPoseView *>(fView); 337 // make sure text widgets draw the default way, erasing their background 338 if (poseView) 339 poseView->SetEraseWidgetTextBackground(true);*/ 340 } 341 fShowingBitmap = NULL; 342 } 343 344 345 BackgroundImage::BackgroundImageInfo * 346 BackgroundImage::ImageInfoForWorkspace(int32 workspace) const 347 { 348 uint32 workspaceMask = 1; 349 350 for (; workspace; workspace--) 351 workspaceMask *= 2; 352 353 int32 count = fBitmapForWorkspaceList.CountItems(); 354 355 // do a simple lookup for the most likely candidate bitmap - 356 // pick the imageInfo that is only defined for this workspace over one 357 // that supports multiple workspaces 358 BackgroundImageInfo *result = NULL; 359 for (int32 index = 0; index < count; index++) { 360 BackgroundImageInfo *info = fBitmapForWorkspaceList.ItemAt(index); 361 if (info->fImageSet != fShowingImageSet) 362 continue; 363 364 if (fIsDesktop) { 365 if (info->fWorkspace == workspaceMask) 366 return info; 367 368 if (info->fWorkspace & workspaceMask) 369 result = info; 370 } else 371 return info; 372 } 373 return result; 374 } 375 376 377 void 378 BackgroundImage::WorkspaceActivated(BView *view, int32 workspace, bool state) 379 { 380 if (!fIsDesktop) { 381 // we only care for desktop bitmaps 382 return; 383 } 384 385 if (!state) { 386 // we only care comming into a new workspace, not leaving one 387 return; 388 } 389 390 BackgroundImageInfo *info = ImageInfoForWorkspace(workspace); 391 if (info != fShowingBitmap) { 392 if (info) 393 Show(info, view); 394 else { 395 /*if (BPoseView *poseView = dynamic_cast<BPoseView *>(view)) 396 poseView->SetEraseWidgetTextBackground(true);*/ 397 view->ClearViewBitmap(); 398 view->Invalidate(); 399 } 400 fShowingBitmap = info; 401 } 402 } 403 404 405 void 406 BackgroundImage::ScreenChanged(BRect, color_space) 407 { 408 if (!fIsDesktop || !fShowingBitmap) 409 return; 410 411 /*if (fShowingBitmap->fMode == kCentered) { 412 BRect viewBounds(fView->Bounds()); 413 BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds()); 414 BRect destinationBitmapBounds(bitmapBounds); 415 destinationBitmapBounds.OffsetBy( 416 (viewBounds.Width() - bitmapBounds.Width()) / 2, 417 (viewBounds.Height() - bitmapBounds.Height()) / 2); 418 419 fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds, destinationBitmapBounds, 420 B_FOLLOW_NONE, 0); 421 fView->Invalidate(); 422 }*/ 423 } 424 425 426 status_t 427 BackgroundImage::SetBackgroundImage(BNode *node) 428 { 429 status_t err; 430 BMessage container; 431 int32 count = fBitmapForWorkspaceList.CountItems(); 432 433 for (int32 index = 0; index < count; index++) { 434 BackgroundImageInfo *info = fBitmapForWorkspaceList.ItemAt(index); 435 436 container.AddBool(kBackgroundImageInfoTextOutline, 437 info->fTextWidgetLabelOutline); 438 if (fBackgroundsView->GetImage(info->fImageIndex) != NULL) { 439 container.AddString(kBackgroundImageInfoPath, 440 fBackgroundsView->GetImage(info->fImageIndex)->GetPath().Path()); 441 } else 442 container.AddString(kBackgroundImageInfoPath, ""); 443 444 container.AddInt32(kBackgroundImageInfoWorkspaces, info->fWorkspace); 445 container.AddPoint(kBackgroundImageInfoOffset, info->fOffset); 446 container.AddInt32(kBackgroundImageInfoMode, info->fMode); 447 448 if (fIsDesktop) 449 container.AddInt32(kBackgroundImageInfoSet, info->fImageSet); 450 } 451 452 PRINT_OBJECT(container); 453 454 size_t flattenedSize = container.FlattenedSize(); 455 char* buffer = new(std::nothrow) char[flattenedSize]; 456 if (buffer == NULL) 457 return B_NO_MEMORY; 458 459 if ((err = container.Flatten(buffer, flattenedSize)) != B_OK) 460 return err; 461 462 ssize_t size = node->WriteAttr(kBackgroundImageInfo, B_MESSAGE_TYPE, 463 0, buffer, flattenedSize); 464 465 delete[] buffer; 466 467 if (size < B_OK) 468 return size; 469 if ((size_t)size != flattenedSize) 470 return B_ERROR; 471 472 return B_OK; 473 } 474 475 476 /*BackgroundImage * 477 BackgroundImage::Refresh(BackgroundImage *oldBackgroundImage, 478 const BNode *fromNode, bool desktop, BPoseView *poseView) 479 { 480 if (oldBackgroundImage) { 481 oldBackgroundImage->Remove(); 482 delete oldBackgroundImage; 483 } 484 485 BackgroundImage *result = GetBackgroundImage(fromNode, desktop); 486 if (result && poseView->ViewMode() != kListMode) 487 result->Show(poseView, current_workspace()); 488 return result; 489 } 490 491 492 void 493 BackgroundImage::ChangeImageSet(BPoseView *poseView) 494 { 495 if (fRandomChange) { 496 if (fImageSetCount > 1) { 497 uint32 oldShowingImageSet = fShowingImageSet; 498 while(oldShowingImageSet == fShowingImageSet) 499 fShowingImageSet = random()%fImageSetCount; 500 } else 501 fShowingImageSet = 0; 502 } else { 503 fShowingImageSet++; 504 if (fShowingImageSet > fImageSetCount - 1) 505 fShowingImageSet = 0; 506 } 507 508 this->Show(poseView, current_workspace()); 509 }*/ 510 511 512 // #pragma mark - 513 514 515 Image::Image(BPath path) 516 : 517 fBitmap(NULL), 518 fPath(path) 519 { 520 name = path.Leaf(); 521 } 522 523 524 Image::~Image() 525 { 526 delete fBitmap; 527 } 528 529 530 BBitmap* 531 Image::GetBitmap() 532 { 533 if (!fBitmap) 534 fBitmap = BTranslationUtils::GetBitmap(fPath.Path()); 535 536 return fBitmap; 537 } 538