1/* 2 * Copyright (c) 2001-2011, Haiku, Inc. 3 * Distributed under the terms of the MIT license. 4 * 5 * Author: 6 * DarkWyrm <bpmagic@columbus.rr.com> 7 * Clemens Zeidler <haiku@clemens-zeidler.de> 8 * Joseph Groover <looncraz@satx.rr.com> 9 */ 10 11#include "DecorManager.h" 12 13#include <Directory.h> 14#include <Entry.h> 15#include <File.h> 16#include <FindDirectory.h> 17#include <Message.h> 18#include <Path.h> 19#include <Rect.h> 20 21#include <syslog.h> 22 23#include "AppServer.h" 24#include "Desktop.h" 25#include "DesktopSettings.h" 26#include "ServerConfig.h" 27#include "SATDecorator.h" 28#include "Window.h" 29 30typedef float get_version(void); 31typedef DecorAddOn* create_decor_addon(image_id id, const char* name); 32 33// Globals 34DecorManager gDecorManager; 35 36 37DecorAddOn::DecorAddOn(image_id id, const char* name) 38 : 39 fImageID(id), 40 fName(name) 41{ 42} 43 44 45DecorAddOn::~DecorAddOn() 46{ 47} 48 49 50status_t 51DecorAddOn::InitCheck() const 52{ 53 return B_OK; 54} 55 56 57Decorator* 58DecorAddOn::AllocateDecorator(Desktop* desktop, DrawingEngine* engine, 59 BRect rect, const char* title, window_look look, uint32 flags) 60{ 61 if (!desktop->LockSingleWindow()) 62 return NULL; 63 64 DesktopSettings settings(desktop); 65 Decorator* decorator; 66 decorator = _AllocateDecorator(settings, rect); 67 desktop->UnlockSingleWindow(); 68 if (!decorator) 69 return NULL; 70 71 if (decorator->AddTab(settings, title, look, flags) == false) { 72 delete decorator; 73 return NULL; 74 } 75 76 decorator->SetDrawingEngine(engine); 77 return decorator; 78} 79 80 81WindowBehaviour* 82DecorAddOn::AllocateWindowBehaviour(Window* window) 83{ 84 return new (std::nothrow)SATWindowBehaviour(window, 85 window->Desktop()->GetStackAndTile()); 86} 87 88 89const DesktopListenerList& 90DecorAddOn::GetDesktopListeners() 91{ 92 return fDesktopListeners; 93} 94 95 96Decorator* 97DecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect) 98{ 99 return new (std::nothrow)SATDecorator(settings, rect); 100} 101 102 103// #pragma mark - 104 105 106DecorManager::DecorManager() 107 : 108 fDefaultDecor(-1, "Default"), 109 fCurrentDecor(&fDefaultDecor), 110 fPreviewDecor(NULL), 111 fPreviewWindow(NULL), 112 fCurrentDecorPath("Default") 113{ 114 _LoadSettingsFromDisk(); 115} 116 117 118DecorManager::~DecorManager() 119{ 120} 121 122 123Decorator* 124DecorManager::AllocateDecorator(Window* window) 125{ 126 // Create a new instance of the current decorator. 127 // Ownership is that of the caller 128 129 if (!fCurrentDecor) { 130 // We should *never* be here. If we do, it's a bug. 131 debugger("DecorManager::AllocateDecorator has a NULL decorator"); 132 return NULL; 133 } 134 135 // Are we previewing a specific decorator? 136 if (window == fPreviewWindow) { 137 if (fPreviewDecor != NULL) { 138 return fPreviewDecor->AllocateDecorator(window->Desktop(), 139 window->GetDrawingEngine(), window->Frame(), window->Title(), 140 window->Look(), window->Flags()); 141 } else { 142 fPreviewWindow = NULL; 143 } 144 } 145 146 return fCurrentDecor->AllocateDecorator(window->Desktop(), 147 window->GetDrawingEngine(), window->Frame(), window->Title(), 148 window->Look(), window->Flags()); 149} 150 151 152WindowBehaviour* 153DecorManager::AllocateWindowBehaviour(Window* window) 154{ 155 if (!fCurrentDecor) { 156 // We should *never* be here. If we do, it's a bug. 157 debugger("DecorManager::AllocateDecorator has a NULL decorator"); 158 return NULL; 159 } 160 161 return fCurrentDecor->AllocateWindowBehaviour(window); 162} 163 164 165void 166DecorManager::CleanupForWindow(Window* window) 167{ 168 // Given window is being deleted, do any cleanup needed 169 if (fPreviewWindow == window && window != NULL){ 170 fPreviewWindow = NULL; 171 172 if (fPreviewDecor != NULL) 173 unload_add_on(fPreviewDecor->ImageID()); 174 175 fPreviewDecor = NULL; 176 } 177} 178 179 180status_t 181DecorManager::PreviewDecorator(BString path, Window* window) 182{ 183 if (fPreviewWindow != NULL && fPreviewWindow != window){ 184 // Reset other window to current decorator - only one can preview 185 Window* oldPreviewWindow = fPreviewWindow; 186 fPreviewWindow = NULL; 187 oldPreviewWindow->ReloadDecor(); 188 } 189 190 if (window == NULL) 191 return B_BAD_VALUE; 192 193 // We have to jump some hoops because the window must be able to 194 // delete its decorator before we unload the add-on 195 status_t error = B_OK; 196 DecorAddOn* decorPtr = _LoadDecor(path, error); 197 if (decorPtr == NULL) 198 return error == B_OK ? B_ERROR : error; 199 200 BRegion border; 201 window->GetBorderRegion(&border); 202 203 DecorAddOn* oldDecor = fPreviewDecor; 204 fPreviewDecor = decorPtr; 205 fPreviewWindow = window; 206 // After this call, the window has deleted its decorator. 207 fPreviewWindow->ReloadDecor(); 208 209 BRegion newBorder; 210 window->GetBorderRegion(&newBorder); 211 212 border.Include(&newBorder); 213 window->Desktop()->RebuildAndRedrawAfterWindowChange(window, border); 214 215 if (oldDecor != NULL) 216 unload_add_on(oldDecor->ImageID()); 217 218 return B_OK; 219} 220 221 222const DesktopListenerList& 223DecorManager::GetDesktopListeners() 224{ 225 return fCurrentDecor->GetDesktopListeners(); 226} 227 228 229BString 230DecorManager::GetCurrentDecorator() const 231{ 232 return fCurrentDecorPath.String(); 233} 234 235 236status_t 237DecorManager::SetDecorator(BString path, Desktop* desktop) 238{ 239 status_t error = B_OK; 240 DecorAddOn* newDecor = _LoadDecor(path, error); 241 if (newDecor == NULL) 242 return error == B_OK ? B_ERROR : error; 243 244 DecorAddOn* oldDecor = fCurrentDecor; 245 246 BString oldPath = fCurrentDecorPath; 247 image_id oldImage = fCurrentDecor->ImageID(); 248 249 fCurrentDecor = newDecor; 250 fCurrentDecorPath = path.String(); 251 252 if (desktop->ReloadDecor(oldDecor)) { 253 // now safe to unload all old decorator data 254 // saves us from deleting oldDecor... 255 unload_add_on(oldImage); 256 _SaveSettingsToDisk(); 257 return B_OK; 258 } 259 260 // TODO: unloading the newDecor and its image 261 // problem is we don't know how many windows failed... or why they failed... 262 syslog(LOG_WARNING, 263 "app_server:DecorManager:SetDecorator:\"%s\" *partly* failed\n", 264 fCurrentDecorPath.String()); 265 266 fCurrentDecor = oldDecor; 267 fCurrentDecorPath = oldPath; 268 return B_ERROR; 269} 270 271 272DecorAddOn* 273DecorManager::_LoadDecor(BString _path, status_t& error ) 274{ 275 if (_path == "Default") { 276 error = B_OK; 277 return &fDefaultDecor; 278 } 279 280 BEntry entry(_path.String(), true); 281 if (!entry.Exists()) { 282 error = B_ENTRY_NOT_FOUND; 283 return NULL; 284 } 285 286 BPath path(&entry); 287 image_id image = load_add_on(path.Path()); 288 if (image < 0) { 289 error = B_BAD_IMAGE_ID; 290 return NULL; 291 } 292 293 create_decor_addon* createFunc; 294 if (get_image_symbol(image, "instantiate_decor_addon", B_SYMBOL_TYPE_TEXT, 295 (void**)&createFunc) != B_OK) { 296 unload_add_on(image); 297 error = B_MISSING_SYMBOL; 298 return NULL; 299 } 300 301 char name[B_FILE_NAME_LENGTH]; 302 entry.GetName(name); 303 DecorAddOn* newDecor = createFunc(image, name); 304 if (newDecor == NULL || newDecor->InitCheck() != B_OK) { 305 unload_add_on(image); 306 error = B_ERROR; 307 return NULL; 308 } 309 310 return newDecor; 311} 312 313 314static const char* kSettingsDir = "system/app_server"; 315static const char* kSettingsFile = "decorator_settings"; 316 317 318bool 319DecorManager::_LoadSettingsFromDisk() 320{ 321 // get the user settings directory 322 BPath path; 323 status_t error = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true); 324 if (error != B_OK) 325 return false; 326 327 path.Append(kSettingsDir); 328 path.Append(kSettingsFile); 329 BFile file(path.Path(), B_READ_ONLY); 330 if (file.InitCheck() != B_OK) 331 return false; 332 333 BMessage settings; 334 if (settings.Unflatten(&file) == B_OK) { 335 BString itemPath; 336 if (settings.FindString("decorator", &itemPath) == B_OK) { 337 status_t error = B_OK; 338 DecorAddOn* decor = _LoadDecor(itemPath, error); 339 if (decor != NULL) { 340 fCurrentDecor = decor; 341 return true; 342 } else { 343 //TODO: do something with the reported error 344 } 345 } 346 } 347 348 return false; 349} 350 351 352bool 353DecorManager::_SaveSettingsToDisk() 354{ 355 // get the user settings directory 356 BPath path; 357 status_t error = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true); 358 if (error != B_OK) 359 return false; 360 361 path.Append(kSettingsDir); 362 if (create_directory(path.Path(), 777) != B_OK) 363 return false; 364 365 path.Append(kSettingsFile); 366 BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); 367 if (file.InitCheck() != B_OK) 368 return false; 369 370 BMessage settings; 371 if (settings.AddString("decorator", fCurrentDecorPath.String()) != B_OK) 372 return false; 373 if (settings.Flatten(&file) != B_OK) 374 return false; 375 376 return true; 377} 378 379