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