1/* 2Open Tracker License 3 4Terms and Conditions 5 6Copyright (c) 1991-2000, Be Incorporated. All rights reserved. 7 8Permission is hereby granted, free of charge, to any person obtaining a copy of 9this software and associated documentation files (the "Software"), to deal in 10the Software without restriction, including without limitation the rights to 11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 12of the Software, and to permit persons to whom the Software is furnished to do 13so, subject to the following conditions: 14 15The above copyright notice and this permission notice applies to all licensees 16and shall be included in all copies or substantial portions of the Software. 17 18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY, 20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION 23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 25Except as contained in this notice, the name of Be Incorporated shall not be 26used in advertising or otherwise to promote the sale, use or other dealings in 27this Software without prior written authorization from Be Incorporated. 28 29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks 30of Be Incorporated in the United States and other countries. Other brand product 31names are registered trademarks or trademarks of their respective holders. 32All rights reserved. 33*/ 34 35// Classes used for setting up and managing background images 36 37 38#include <Bitmap.h> 39#include <ControlLook.h> 40#include <Node.h> 41#include <TranslationKit.h> 42#include <View.h> 43#include <Window.h> 44 45#include <fs_attr.h> 46 47#include "BackgroundImage.h" 48 49#include "Background.h" 50#include "Commands.h" 51#include "PoseView.h" 52 53 54namespace BPrivate { 55 56const char* kBackgroundImageInfo = B_BACKGROUND_INFO; 57const char* kBackgroundImageInfoOffset = B_BACKGROUND_ORIGIN; 58const char* kBackgroundImageInfoTextOutline = B_BACKGROUND_TEXT_OUTLINE; 59const char* kBackgroundImageInfoMode = B_BACKGROUND_MODE; 60const char* kBackgroundImageInfoWorkspaces = B_BACKGROUND_WORKSPACES; 61const char* kBackgroundImageInfoPath = B_BACKGROUND_IMAGE; 62 63} // namespace BPrivate 64 65 66// #pragma mark - BackgroundImage 67 68 69BackgroundImage* 70BackgroundImage::GetBackgroundImage(const BNode* node, bool isDesktop) 71{ 72 attr_info info; 73 if (node->GetAttrInfo(kBackgroundImageInfo, &info) != B_OK) 74 return NULL; 75 76 BMessage container; 77 char* buffer = new char[info.size]; 78 79 status_t error = node->ReadAttr(kBackgroundImageInfo, info.type, 0, 80 buffer, (size_t)info.size); 81 if (error == info.size) 82 error = container.Unflatten(buffer); 83 84 delete[] buffer; 85 86 if (error != B_OK) 87 return NULL; 88 89 BackgroundImage* backgroundImage = NULL; 90 for (int32 index = 0; ; index++) { 91 const char* path; 92 uint32 workspaces = B_ALL_WORKSPACES; 93 Mode mode = kTiled; 94 bool textWidgetLabelOutline = false; 95 BPoint offset; 96 BBitmap* bitmap = NULL; 97 98 if (container.FindString(kBackgroundImageInfoPath, index, &path) 99 == B_OK) { 100 bitmap = BTranslationUtils::GetBitmap(path); 101 if (!bitmap) 102 PRINT(("failed to load background bitmap from path\n")); 103 } else 104 break; 105 106 if (isDesktop) 107 be_control_look->SetBackgroundInfo(container); 108 109 container.FindInt32(kBackgroundImageInfoWorkspaces, index, 110 (int32*)&workspaces); 111 container.FindInt32(kBackgroundImageInfoMode, index, (int32*)&mode); 112 container.FindBool(kBackgroundImageInfoTextOutline, index, 113 &textWidgetLabelOutline); 114 container.FindPoint(kBackgroundImageInfoOffset, index, &offset); 115 116 BackgroundImage::BackgroundImageInfo* imageInfo = new 117 BackgroundImage::BackgroundImageInfo(workspaces, bitmap, mode, 118 offset, textWidgetLabelOutline); 119 120 if (backgroundImage == NULL) 121 backgroundImage = new BackgroundImage(node, isDesktop); 122 123 backgroundImage->Add(imageInfo); 124 } 125 126 return backgroundImage; 127} 128 129 130BackgroundImage::BackgroundImageInfo::BackgroundImageInfo(uint32 workspaces, 131 BBitmap* bitmap, Mode mode, BPoint offset, bool textWidgetOutline) 132 : 133 fWorkspace(workspaces), 134 fBitmap(bitmap), 135 fMode(mode), 136 fOffset(offset), 137 fTextWidgetOutline(textWidgetOutline) 138{ 139} 140 141 142BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo() 143{ 144 delete fBitmap; 145} 146 147 148BackgroundImage::BackgroundImage(const BNode* node, bool desktop) 149 : 150 fIsDesktop(desktop), 151 fDefinedByNode(*node), 152 fView(NULL), 153 fShowingBitmap(NULL), 154 fBitmapForWorkspaceList(1, true) 155{ 156} 157 158 159BackgroundImage::~BackgroundImage() 160{ 161} 162 163 164void 165BackgroundImage::Add(BackgroundImageInfo* info) 166{ 167 fBitmapForWorkspaceList.AddItem(info); 168} 169 170 171void 172BackgroundImage::Show(BView* view, int32 workspace) 173{ 174 fView = view; 175 176 BackgroundImageInfo* info = ImageInfoForWorkspace(workspace); 177 if (info) { 178 BPoseView* poseView = dynamic_cast<BPoseView*>(fView); 179 if (poseView != NULL) 180 poseView->SetWidgetTextOutline(info->fTextWidgetOutline); 181 182 Show(info, fView); 183 } 184} 185 186 187void 188BackgroundImage::Show(BackgroundImageInfo* info, BView* view) 189{ 190 BPoseView* poseView = dynamic_cast<BPoseView*>(view); 191 if (poseView != NULL) 192 poseView->SetWidgetTextOutline(info->fTextWidgetOutline); 193 194 if (info->fBitmap == NULL) { 195 view->ClearViewBitmap(); 196 view->Invalidate(); 197 fShowingBitmap = info; 198 return; 199 } 200 BRect viewBounds(view->Bounds()); 201 BRect bitmapBounds(info->fBitmap->Bounds()); 202 BRect destinationBitmapBounds(bitmapBounds); 203 204 uint32 options = 0; 205 uint32 followFlags = B_FOLLOW_TOP | B_FOLLOW_LEFT; 206 207 // figure out the display mode and the destination bounds for the bitmap 208 switch (info->fMode) { 209 case kCentered: 210 if (fIsDesktop) { 211 destinationBitmapBounds.OffsetBy( 212 (viewBounds.Width() - bitmapBounds.Width()) / 2, 213 (viewBounds.Height() - bitmapBounds.Height()) / 2); 214 break; 215 } 216 // else fall thru 217 case kScaledToFit: 218 if (fIsDesktop) { 219 if (BRectRatio(destinationBitmapBounds) 220 >= BRectRatio(viewBounds)) { 221 float overlap = BRectHorizontalOverlap(viewBounds, 222 destinationBitmapBounds); 223 destinationBitmapBounds.Set(-overlap, 0, 224 viewBounds.Width() + overlap, viewBounds.Height()); 225 } else { 226 float overlap = BRectVerticalOverlap(viewBounds, 227 destinationBitmapBounds); 228 destinationBitmapBounds.Set(0, -overlap, 229 viewBounds.Width(), viewBounds.Height() + overlap); 230 } 231 followFlags = B_FOLLOW_ALL; 232 options |= B_FILTER_BITMAP_BILINEAR; 233 break; 234 } 235 // else fall thru 236 case kAtOffset: 237 destinationBitmapBounds.OffsetTo(info->fOffset); 238 break; 239 240 case kTiled: 241 if (fIsDesktop) { 242 destinationBitmapBounds.OffsetBy( 243 (viewBounds.Width() - bitmapBounds.Width()) / 2, 244 (viewBounds.Height() - bitmapBounds.Height()) / 2); 245 } 246 options |= B_TILE_BITMAP; 247 break; 248 } 249 250 // switch to the bitmap and force a redraw 251 view->SetViewBitmap(info->fBitmap, bitmapBounds, destinationBitmapBounds, 252 followFlags, options); 253 view->Invalidate(); 254 fShowingBitmap = info; 255} 256 257 258float 259BackgroundImage::BRectRatio(BRect rect) 260{ 261 return rect.Width() / rect.Height(); 262} 263 264 265float 266BackgroundImage::BRectHorizontalOverlap(BRect hostRect, BRect resizedRect) 267{ 268 return ((hostRect.Height() / resizedRect.Height() * resizedRect.Width()) 269 - hostRect.Width()) / 2; 270} 271 272 273float 274BackgroundImage::BRectVerticalOverlap(BRect hostRect, BRect resizedRect) 275{ 276 return ((hostRect.Width() / resizedRect.Width() * resizedRect.Height()) 277 - hostRect.Height()) / 2; 278} 279 280 281void 282BackgroundImage::Remove() 283{ 284 if (fShowingBitmap != NULL) { 285 fView->ClearViewBitmap(); 286 fView->Invalidate(); 287 BPoseView* poseView = dynamic_cast<BPoseView*>(fView); 288 // make sure text widgets draw the default way, erasing 289 // their background 290 if (poseView != NULL) 291 poseView->SetWidgetTextOutline(true); 292 } 293 294 fShowingBitmap = NULL; 295} 296 297 298BackgroundImage::BackgroundImageInfo* 299BackgroundImage::ImageInfoForWorkspace(int32 workspace) const 300{ 301 uint32 workspaceMask = 1; 302 303 for ( ; workspace; workspace--) 304 workspaceMask *= 2; 305 306 int32 count = fBitmapForWorkspaceList.CountItems(); 307 308 // do a simple lookup for the most likely candidate bitmap - 309 // pick the imageInfo that is only defined for this workspace over one 310 // that supports multiple workspaces 311 BackgroundImageInfo* result = NULL; 312 for (int32 index = 0; index < count; index++) { 313 BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index); 314 if (info->fWorkspace == workspaceMask) 315 return info; 316 317 if (info->fWorkspace & workspaceMask) 318 result = info; 319 } 320 321 return result; 322} 323 324 325void 326BackgroundImage::WorkspaceActivated(BView* view, int32 workspace, bool state) 327{ 328 if (!fIsDesktop) { 329 // we only care for desktop bitmaps 330 return; 331 } 332 333 if (!state) { 334 // we only care comming into a new workspace, not leaving one 335 return; 336 } 337 338 BackgroundImageInfo* info = ImageInfoForWorkspace(workspace); 339 if (info != fShowingBitmap) { 340 if (info != NULL) 341 Show(info, view); 342 else { 343 BPoseView* poseView = dynamic_cast<BPoseView*>(view); 344 if (poseView != NULL) 345 poseView->SetWidgetTextOutline(true); 346 347 view->ClearViewBitmap(); 348 view->Invalidate(); 349 } 350 351 fShowingBitmap = info; 352 } 353} 354 355 356void 357BackgroundImage::ScreenChanged(BRect, color_space) 358{ 359 if (!fIsDesktop || fShowingBitmap == NULL) 360 return; 361 362 if (fShowingBitmap->fMode == kCentered) { 363 BRect viewBounds(fView->Bounds()); 364 BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds()); 365 BRect destinationBitmapBounds(bitmapBounds); 366 destinationBitmapBounds.OffsetBy( 367 (viewBounds.Width() - bitmapBounds.Width()) / 2, 368 (viewBounds.Height() - bitmapBounds.Height()) / 2); 369 370 fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds, 371 destinationBitmapBounds, B_FOLLOW_NONE, 0); 372 fView->Invalidate(); 373 } 374} 375 376 377BackgroundImage* 378BackgroundImage::Refresh(BackgroundImage* oldBackgroundImage, 379 const BNode* fromNode, bool desktop, BPoseView* poseView) 380{ 381 if (oldBackgroundImage != NULL) { 382 oldBackgroundImage->Remove(); 383 delete oldBackgroundImage; 384 } 385 386 BackgroundImage* backgroundImage = GetBackgroundImage(fromNode, desktop); 387 if (backgroundImage != NULL && poseView->ViewMode() != kListMode) 388 backgroundImage->Show(poseView, current_workspace()); 389 390 return backgroundImage; 391} 392