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 NULL; 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::RemoveAll() 215 { 216 for (int32 index = 0; index < fBitmapForWorkspaceList.CountItems();) { 217 BackgroundImageInfo *info = fBitmapForWorkspaceList.ItemAt(index); 218 if (info->fImageSet != fShowingImageSet) 219 index++; 220 else 221 fBitmapForWorkspaceList.RemoveItemAt(index); 222 } 223 } 224 225 226 void 227 BackgroundImage::Show(BView *view, int32 workspace) 228 { 229 fView = view; 230 231 BackgroundImageInfo *info = ImageInfoForWorkspace(workspace); 232 if (info) { 233 /*BPoseView *poseView = dynamic_cast<BPoseView *>(fView); 234 if (poseView) 235 poseView->SetEraseWidgetTextBackground(info->fEraseTextWidgetBackground);*/ 236 Show(info, fView); 237 } 238 } 239 240 241 void 242 BackgroundImage::Show(BackgroundImageInfo *info, BView *view) 243 { 244 BBitmap *bitmap = fBackgroundsView->GetImage(info->fImageIndex)->GetBitmap(); 245 246 if (!bitmap) 247 return; 248 249 BRect viewBounds(view->Bounds()); 250 251 display_mode mode; 252 BScreen().GetMode(&mode); 253 float x_ratio = viewBounds.Width() / mode.virtual_width; 254 float y_ratio = viewBounds.Height() / mode.virtual_height; 255 256 BRect bitmapBounds(bitmap->Bounds()); 257 BRect destinationBitmapBounds(bitmapBounds); 258 destinationBitmapBounds.right *= x_ratio; 259 destinationBitmapBounds.bottom *= y_ratio; 260 BPoint offset(info->fOffset); 261 offset.x *= x_ratio; 262 offset.y *= y_ratio; 263 264 uint32 tile = 0; 265 uint32 followFlags = B_FOLLOW_TOP | B_FOLLOW_LEFT; 266 267 // figure out the display mode and the destination bounds for the bitmap 268 switch (info->fMode) { 269 case kCentered: 270 if (fIsDesktop) { 271 destinationBitmapBounds.OffsetBy( 272 (viewBounds.Width() - destinationBitmapBounds.Width()) / 2, 273 (viewBounds.Height() - destinationBitmapBounds.Height()) / 2); 274 break; 275 } 276 // else fall thru 277 case kScaledToFit: 278 if (fIsDesktop) { 279 destinationBitmapBounds = viewBounds; 280 followFlags = B_FOLLOW_ALL; 281 break; 282 } 283 // else fall thru 284 case kAtOffset: 285 { 286 destinationBitmapBounds.OffsetTo(offset); 287 break; 288 } 289 case kTiled: 290 // Original Backgrounds Preferences center the tiled paper but the Tracker don't do that 291 //if (fIsDesktop) { 292 destinationBitmapBounds.OffsetBy( 293 (viewBounds.Width() - destinationBitmapBounds.Width()) / 2, 294 (viewBounds.Height() - destinationBitmapBounds.Height()) / 2); 295 //} 296 tile = B_TILE_BITMAP; 297 break; 298 } 299 300 // switch to the bitmap and force a redraw 301 view->SetViewBitmap(bitmap, bitmapBounds, destinationBitmapBounds, 302 followFlags, tile); 303 view->Invalidate(); 304 305 /*if(fShowingBitmap != info) { 306 if(fShowingBitmap) 307 fShowingBitmap->UnloadBitmap(fCacheMode); 308 fShowingBitmap = info; 309 }*/ 310 } 311 312 313 void 314 BackgroundImage::Remove() 315 { 316 if (fShowingBitmap) { 317 fView->ClearViewBitmap(); 318 fView->Invalidate(); 319 /*BPoseView *poseView = dynamic_cast<BPoseView *>(fView); 320 // make sure text widgets draw the default way, erasing their background 321 if (poseView) 322 poseView->SetEraseWidgetTextBackground(true);*/ 323 } 324 fShowingBitmap = NULL; 325 } 326 327 328 BackgroundImage::BackgroundImageInfo * 329 BackgroundImage::ImageInfoForWorkspace(int32 workspace) const 330 { 331 uint32 workspaceMask = 1; 332 333 for (; workspace; workspace--) 334 workspaceMask *= 2; 335 336 int32 count = fBitmapForWorkspaceList.CountItems(); 337 338 // do a simple lookup for the most likely candidate bitmap - 339 // pick the imageInfo that is only defined for this workspace over one 340 // that supports multiple workspaces 341 BackgroundImageInfo *result = NULL; 342 for (int32 index = 0; index < count; index++) { 343 BackgroundImageInfo *info = fBitmapForWorkspaceList.ItemAt(index); 344 if (info->fImageSet != fShowingImageSet) 345 continue; 346 347 if (fIsDesktop) { 348 if (info->fWorkspace == workspaceMask) 349 return info; 350 if (info->fWorkspace & workspaceMask) 351 result = info; 352 } else 353 return info; 354 } 355 356 return result; 357 } 358 359 360 void 361 BackgroundImage::WorkspaceActivated(BView *view, int32 workspace, bool state) 362 { 363 if (!fIsDesktop) { 364 // we only care for desktop bitmaps 365 return; 366 } 367 368 if (!state) { 369 // we only care comming into a new workspace, not leaving one 370 return; 371 } 372 373 BackgroundImageInfo *info = ImageInfoForWorkspace(workspace); 374 if (info != fShowingBitmap) { 375 if (info) 376 Show(info, view); 377 else { 378 /*if (BPoseView *poseView = dynamic_cast<BPoseView *>(view)) 379 poseView->SetEraseWidgetTextBackground(true);*/ 380 view->ClearViewBitmap(); 381 view->Invalidate(); 382 } 383 fShowingBitmap = info; 384 } 385 } 386 387 388 void 389 BackgroundImage::ScreenChanged(BRect, color_space) 390 { 391 if (!fIsDesktop || !fShowingBitmap) 392 return; 393 394 /*if (fShowingBitmap->fMode == kCentered) { 395 BRect viewBounds(fView->Bounds()); 396 BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds()); 397 BRect destinationBitmapBounds(bitmapBounds); 398 destinationBitmapBounds.OffsetBy( 399 (viewBounds.Width() - bitmapBounds.Width()) / 2, 400 (viewBounds.Height() - bitmapBounds.Height()) / 2); 401 402 fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds, destinationBitmapBounds, 403 B_FOLLOW_NONE, 0); 404 fView->Invalidate(); 405 }*/ 406 } 407 408 409 status_t 410 BackgroundImage::SetBackgroundImage(BNode *node) 411 { 412 status_t err; 413 BMessage container; 414 int32 count = fBitmapForWorkspaceList.CountItems(); 415 416 for (int32 index = 0; index < count; index++) { 417 BackgroundImageInfo *info = fBitmapForWorkspaceList.ItemAt(index); 418 if (fBackgroundsView->GetImage(info->fImageIndex) == NULL) 419 continue; 420 421 container.AddBool(kBackgroundImageInfoEraseText, 422 info->fEraseTextWidgetBackground); 423 container.AddString(kBackgroundImageInfoPath, 424 fBackgroundsView->GetImage(info->fImageIndex)->GetPath().Path()); 425 container.AddInt32(kBackgroundImageInfoWorkspaces, info->fWorkspace); 426 container.AddPoint(kBackgroundImageInfoOffset, info->fOffset); 427 container.AddInt32(kBackgroundImageInfoMode, info->fMode); 428 429 if (fIsDesktop) 430 container.AddInt32(kBackgroundImageInfoSet, info->fImageSet); 431 } 432 433 PRINT_OBJECT(container); 434 435 size_t flattenedSize = container.FlattenedSize(); 436 char* buffer = new (std::nothrow) char[flattenedSize]; 437 if (buffer == NULL) 438 return B_NO_MEMORY; 439 440 if ((err = container.Flatten(buffer, flattenedSize)) != B_OK) 441 return err; 442 443 ssize_t size = node->WriteAttr(kBackgroundImageInfo, B_MESSAGE_TYPE, 444 0, buffer, flattenedSize); 445 446 delete[] buffer; 447 448 if (size < B_OK) 449 return size; 450 if ((size_t)size != flattenedSize) 451 return B_ERROR; 452 453 return B_OK; 454 } 455 456 457 /*BackgroundImage * 458 BackgroundImage::Refresh(BackgroundImage *oldBackgroundImage, 459 const BNode *fromNode, bool desktop, BPoseView *poseView) 460 { 461 if (oldBackgroundImage) { 462 oldBackgroundImage->Remove(); 463 delete oldBackgroundImage; 464 } 465 466 BackgroundImage *result = GetBackgroundImage(fromNode, desktop); 467 if (result && poseView->ViewMode() != kListMode) 468 result->Show(poseView, current_workspace()); 469 return result; 470 } 471 472 473 void 474 BackgroundImage::ChangeImageSet(BPoseView *poseView) 475 { 476 if(fRandomChange) { 477 if(fImageSetCount > 1) { 478 uint32 oldShowingImageSet = fShowingImageSet; 479 while(oldShowingImageSet == fShowingImageSet) 480 fShowingImageSet = random()%fImageSetCount; 481 } else 482 fShowingImageSet = 0; 483 } else { 484 fShowingImageSet++; 485 if(fShowingImageSet > fImageSetCount - 1) 486 fShowingImageSet = 0; 487 } 488 489 this->Show(poseView, current_workspace()); 490 }*/ 491 492 493 // #pragma mark - 494 495 496 Image::Image(BPath path) 497 : 498 fBitmap(NULL), 499 fPath(path) 500 { 501 name = path.Leaf(); 502 } 503 504 505 Image::~Image() 506 { 507 delete fBitmap; 508 } 509 510 511 BBitmap* 512 Image::GetBitmap() 513 { 514 if (!fBitmap) 515 fBitmap = BTranslationUtils::GetBitmap(fPath.Path()); 516 517 return fBitmap; 518 } 519