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 <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 54 namespace BPrivate { 55 56 const char* kBackgroundImageInfo = B_BACKGROUND_INFO; 57 const char* kBackgroundImageInfoOffset = B_BACKGROUND_ORIGIN; 58 const char* kBackgroundImageInfoTextOutline = B_BACKGROUND_TEXT_OUTLINE; 59 const char* kBackgroundImageInfoMode = B_BACKGROUND_MODE; 60 const char* kBackgroundImageInfoWorkspaces = B_BACKGROUND_WORKSPACES; 61 const char* kBackgroundImageInfoPath = B_BACKGROUND_IMAGE; 62 63 } // namespace BPrivate 64 65 66 // #pragma mark - BackgroundImage 67 68 69 BackgroundImage* 70 BackgroundImage::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 130 BackgroundImage::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 142 BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo() 143 { 144 delete fBitmap; 145 } 146 147 148 BackgroundImage::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 159 BackgroundImage::~BackgroundImage() 160 { 161 } 162 163 164 void 165 BackgroundImage::Add(BackgroundImageInfo* info) 166 { 167 fBitmapForWorkspaceList.AddItem(info); 168 } 169 170 171 void 172 BackgroundImage::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 187 void 188 BackgroundImage::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 258 float 259 BackgroundImage::BRectRatio(BRect rect) 260 { 261 return rect.Width() / rect.Height(); 262 } 263 264 265 float 266 BackgroundImage::BRectHorizontalOverlap(BRect hostRect, BRect resizedRect) 267 { 268 return ((hostRect.Height() / resizedRect.Height() * resizedRect.Width()) 269 - hostRect.Width()) / 2; 270 } 271 272 273 float 274 BackgroundImage::BRectVerticalOverlap(BRect hostRect, BRect resizedRect) 275 { 276 return ((hostRect.Width() / resizedRect.Width() * resizedRect.Height()) 277 - hostRect.Height()) / 2; 278 } 279 280 281 void 282 BackgroundImage::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 298 BackgroundImage::BackgroundImageInfo* 299 BackgroundImage::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 325 void 326 BackgroundImage::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 356 void 357 BackgroundImage::ScreenChanged(BRect, color_space) 358 { 359 if (!fIsDesktop || fShowingBitmap == NULL || fShowingBitmap->fBitmap == 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 377 BackgroundImage* 378 BackgroundImage::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