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 continue; 104 } 105 } else 106 break; 107 108 if (be_control_look != NULL && isDesktop) { 109 be_control_look->SetBackgroundInfo(container); 110 } 111 112 container.FindInt32(kBackgroundImageInfoWorkspaces, index, 113 (int32*)&workspaces); 114 container.FindInt32(kBackgroundImageInfoMode, index, (int32*)&mode); 115 container.FindBool(kBackgroundImageInfoTextOutline, index, 116 &textWidgetLabelOutline); 117 container.FindPoint(kBackgroundImageInfoOffset, index, &offset); 118 119 BackgroundImage::BackgroundImageInfo* imageInfo = new 120 BackgroundImage::BackgroundImageInfo(workspaces, bitmap, mode, 121 offset, textWidgetLabelOutline); 122 123 if (backgroundImage == NULL) 124 backgroundImage = new BackgroundImage(node, isDesktop); 125 126 backgroundImage->Add(imageInfo); 127 } 128 129 return backgroundImage; 130 } 131 132 133 BackgroundImage::BackgroundImageInfo::BackgroundImageInfo(uint32 workspaces, 134 BBitmap* bitmap, Mode mode, BPoint offset, bool textWidgetOutline) 135 : 136 fWorkspace(workspaces), 137 fBitmap(bitmap), 138 fMode(mode), 139 fOffset(offset), 140 fTextWidgetOutline(textWidgetOutline) 141 { 142 } 143 144 145 BackgroundImage::BackgroundImageInfo::~BackgroundImageInfo() 146 { 147 delete fBitmap; 148 } 149 150 151 BackgroundImage::BackgroundImage(const BNode* node, bool desktop) 152 : 153 fIsDesktop(desktop), 154 fDefinedByNode(*node), 155 fView(NULL), 156 fShowingBitmap(NULL), 157 fBitmapForWorkspaceList(1, true) 158 { 159 } 160 161 162 BackgroundImage::~BackgroundImage() 163 { 164 } 165 166 167 void 168 BackgroundImage::Add(BackgroundImageInfo* info) 169 { 170 fBitmapForWorkspaceList.AddItem(info); 171 } 172 173 174 void 175 BackgroundImage::Show(BView* view, int32 workspace) 176 { 177 fView = view; 178 179 BackgroundImageInfo* info = ImageInfoForWorkspace(workspace); 180 if (info) { 181 BPoseView* poseView = dynamic_cast<BPoseView*>(fView); 182 if (poseView) 183 poseView->SetWidgetTextOutline(info->fTextWidgetOutline); 184 Show(info, fView); 185 } 186 } 187 188 189 void 190 BackgroundImage::Show(BackgroundImageInfo* info, BView* view) 191 { 192 BPoseView* poseView = dynamic_cast<BPoseView*>(view); 193 if (poseView) 194 poseView->SetWidgetTextOutline(info->fTextWidgetOutline); 195 196 if (info->fBitmap == NULL) { 197 view->ClearViewBitmap(); 198 view->Invalidate(); 199 fShowingBitmap = info; 200 return; 201 } 202 BRect viewBounds(view->Bounds()); 203 BRect bitmapBounds(info->fBitmap->Bounds()); 204 BRect destinationBitmapBounds(bitmapBounds); 205 206 uint32 options = 0; 207 uint32 followFlags = B_FOLLOW_TOP | B_FOLLOW_LEFT; 208 209 // figure out the display mode and the destination bounds for the bitmap 210 switch (info->fMode) { 211 case kCentered: 212 if (fIsDesktop) { 213 destinationBitmapBounds.OffsetBy( 214 (viewBounds.Width() - bitmapBounds.Width()) / 2, 215 (viewBounds.Height() - bitmapBounds.Height()) / 2); 216 break; 217 } 218 // else fall thru 219 case kScaledToFit: 220 if (fIsDesktop) { 221 if (BRectRatio(destinationBitmapBounds) 222 >= BRectRatio(viewBounds)) { 223 float overlap = BRectHorizontalOverlap(viewBounds, 224 destinationBitmapBounds); 225 destinationBitmapBounds.Set(-overlap, 0, 226 viewBounds.Width() + overlap, viewBounds.Height()); 227 } else { 228 float overlap = BRectVerticalOverlap(viewBounds, 229 destinationBitmapBounds); 230 destinationBitmapBounds.Set(0, -overlap, 231 viewBounds.Width(), viewBounds.Height() + overlap); 232 } 233 followFlags = B_FOLLOW_ALL; 234 options |= B_FILTER_BITMAP_BILINEAR; 235 break; 236 } 237 // else fall thru 238 case kAtOffset: 239 destinationBitmapBounds.OffsetTo(info->fOffset); 240 break; 241 242 case kTiled: 243 if (fIsDesktop) { 244 destinationBitmapBounds.OffsetBy( 245 (viewBounds.Width() - bitmapBounds.Width()) / 2, 246 (viewBounds.Height() - bitmapBounds.Height()) / 2); 247 } 248 options |= B_TILE_BITMAP; 249 break; 250 } 251 252 // switch to the bitmap and force a redraw 253 view->SetViewBitmap(info->fBitmap, bitmapBounds, destinationBitmapBounds, 254 followFlags, options); 255 view->Invalidate(); 256 fShowingBitmap = info; 257 } 258 259 260 float 261 BackgroundImage::BRectRatio(BRect rect) 262 { 263 return rect.Width() / rect.Height(); 264 } 265 266 267 float 268 BackgroundImage::BRectHorizontalOverlap(BRect hostRect, BRect resizedRect) 269 { 270 return ((hostRect.Height() / resizedRect.Height() * resizedRect.Width()) 271 - hostRect.Width()) / 2; 272 } 273 274 275 float 276 BackgroundImage::BRectVerticalOverlap(BRect hostRect, BRect resizedRect) 277 { 278 return ((hostRect.Width() / resizedRect.Width() * resizedRect.Height()) 279 - hostRect.Height()) / 2; 280 } 281 282 283 void 284 BackgroundImage::Remove() 285 { 286 if (fShowingBitmap != NULL) { 287 fView->ClearViewBitmap(); 288 fView->Invalidate(); 289 BPoseView* poseView = dynamic_cast<BPoseView*>(fView); 290 // make sure text widgets draw the default way, erasing 291 // their background 292 if (poseView != NULL) 293 poseView->SetWidgetTextOutline(true); 294 } 295 296 fShowingBitmap = NULL; 297 } 298 299 300 BackgroundImage::BackgroundImageInfo* 301 BackgroundImage::ImageInfoForWorkspace(int32 workspace) const 302 { 303 uint32 workspaceMask = 1; 304 305 for ( ; workspace; workspace--) 306 workspaceMask *= 2; 307 308 int32 count = fBitmapForWorkspaceList.CountItems(); 309 310 // do a simple lookup for the most likely candidate bitmap - 311 // pick the imageInfo that is only defined for this workspace over one 312 // that supports multiple workspaces 313 BackgroundImageInfo* result = NULL; 314 for (int32 index = 0; index < count; index++) { 315 BackgroundImageInfo* info = fBitmapForWorkspaceList.ItemAt(index); 316 if (info->fWorkspace == workspaceMask) 317 return info; 318 319 if (info->fWorkspace & workspaceMask) 320 result = info; 321 } 322 323 return result; 324 } 325 326 327 void 328 BackgroundImage::WorkspaceActivated(BView* view, int32 workspace, bool state) 329 { 330 if (!fIsDesktop) { 331 // we only care for desktop bitmaps 332 return; 333 } 334 335 if (!state) { 336 // we only care comming into a new workspace, not leaving one 337 return; 338 } 339 340 BackgroundImageInfo* info = ImageInfoForWorkspace(workspace); 341 if (info != fShowingBitmap) { 342 if (info != NULL) 343 Show(info, view); 344 else { 345 BPoseView* poseView = dynamic_cast<BPoseView*>(view); 346 if (poseView != NULL) 347 poseView->SetWidgetTextOutline(true); 348 349 view->ClearViewBitmap(); 350 view->Invalidate(); 351 } 352 353 fShowingBitmap = info; 354 } 355 } 356 357 358 void 359 BackgroundImage::ScreenChanged(BRect, color_space) 360 { 361 if (!fIsDesktop || fShowingBitmap == NULL) 362 return; 363 364 if (fShowingBitmap->fMode == kCentered) { 365 BRect viewBounds(fView->Bounds()); 366 BRect bitmapBounds(fShowingBitmap->fBitmap->Bounds()); 367 BRect destinationBitmapBounds(bitmapBounds); 368 destinationBitmapBounds.OffsetBy( 369 (viewBounds.Width() - bitmapBounds.Width()) / 2, 370 (viewBounds.Height() - bitmapBounds.Height()) / 2); 371 372 fView->SetViewBitmap(fShowingBitmap->fBitmap, bitmapBounds, 373 destinationBitmapBounds, B_FOLLOW_NONE, 0); 374 fView->Invalidate(); 375 } 376 } 377 378 379 BackgroundImage* 380 BackgroundImage::Refresh(BackgroundImage* oldBackgroundImage, 381 const BNode* fromNode, bool desktop, BPoseView* poseView) 382 { 383 if (oldBackgroundImage != NULL) { 384 oldBackgroundImage->Remove(); 385 delete oldBackgroundImage; 386 } 387 388 BackgroundImage* backgroundImage = GetBackgroundImage(fromNode, desktop); 389 if (backgroundImage != NULL && poseView->ViewMode() != kListMode) 390 backgroundImage->Show(poseView, current_workspace()); 391 392 return backgroundImage; 393 } 394