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