diff --git a/src/servers/app/DecorManager.cpp b/src/servers/app/DecorManager.cpp index e2cc0486ea..10c621d2cb 100644 --- a/src/servers/app/DecorManager.cpp +++ b/src/servers/app/DecorManager.cpp @@ -21,87 +21,55 @@ #include "AppServer.h" #include "DefaultDecorator.h" +#include "DefaultWindowBehaviour.h" #include "Desktop.h" #include "DesktopSettings.h" #include "ServerConfig.h" #include "Window.h" typedef float get_version(void); -typedef Decorator* create_decorator(DesktopSettings& desktopSettings, BRect rect, - window_look look, uint32 flags); +typedef DecorAddOn* create_decor_addon(image_id id, const char* name); // Globals DecorManager gDecorManager; -// This is a class used only by the DecorManager to track all the decorators in memory -class DecorInfo { - public: - DecorInfo(image_id id, const char* name, - create_decorator* allocator = NULL); - ~DecorInfo(); - - status_t InitCheck() const; - - image_id ID() const { return fID; } - const char* Name() const { return fName.String(); } - - Decorator* Instantiate(Desktop* desktop, DrawingEngine* engine, - BRect rect, const char* title, - window_look look, uint32 flags); - - private: - image_id fID; - BString fName; - create_decorator* fAllocator; -}; - - -DecorInfo::DecorInfo(image_id id, const char* name, create_decorator* allocator) +DecorAddOn::DecorAddOn(image_id id, const char* name) : - fID(id), - fName(name), - fAllocator(allocator) + fImageID(id), + fName(name) { } -DecorInfo::~DecorInfo() +DecorAddOn::~DecorAddOn() { - // Do nothing. Normal programming practice would say that one should unload - // the object's associate image_id. However, there is some funkiness with - // the R5 kernel in which addons aren't unloaded when unload_add_on() is - // called -- perhaps it's lazy unloading or something. In any event, it - // causes crashes which are *extremely* hard to track down to this. - - // Considering the usage of DecorInfo and DecorManager, we can live with - // this because the app_server will not the DecorManager is freed only - // when the app_server quits. It's not pretty, but it gets the job done. + } -Decorator * -DecorInfo::Instantiate(Desktop* desktop, DrawingEngine* engine, BRect rect, - const char *title, window_look look, uint32 flags) +status_t +DecorAddOn::InitCheck() const +{ + return B_OK; +} + + +Decorator* +DecorAddOn::AllocateDecorator(Desktop* desktop, DrawingEngine* engine, + BRect rect, const char* title, window_look look, uint32 flags) { if (!desktop->LockSingleWindow()) return NULL; DesktopSettings settings(desktop); - Decorator *decorator; - - try { - if (fAllocator != NULL) - decorator = fAllocator(settings, rect, look, flags); - else - decorator = new DefaultDecorator(settings, rect, look, flags); - } catch (...) { - desktop->UnlockSingleWindow(); - return NULL; - } + Decorator* decorator; + decorator = _AllocateDecorator(settings, rect, look, flags); desktop->UnlockSingleWindow(); + if (!decorator) + return NULL; decorator->SetDrawingEngine(engine); decorator->SetTitle(title); @@ -109,17 +77,38 @@ DecorInfo::Instantiate(Desktop* desktop, DrawingEngine* engine, BRect rect, } +WindowBehaviour* +DecorAddOn::AllocateWindowBehaviour(Window* window) +{ + return new (std::nothrow)DefaultWindowBehaviour(window); +} + + +const DesktopListenerList& +DecorAddOn::GetDesktopListeners() +{ + return fDesktopListeners; +} + + +Decorator* +DecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect, + window_look look, uint32 flags) +{ + return new (std::nothrow)DefaultDecorator(settings, rect, look, flags); +} + + // #pragma mark - DecorManager::DecorManager() : - fDecorList(0), + fDefaultDecorAddOn(-1, "Default"), fCurrentDecor(NULL) { // Start with the default decorator - index is always 0 - DecorInfo *defaultDecor = new DecorInfo(-1, "Default", NULL); - fDecorList.AddItem(defaultDecor); + fDecorList.AddItem(&fDefaultDecorAddOn); // Add any on disk RescanDecorators(); @@ -127,7 +116,7 @@ DecorManager::DecorManager() _LoadSettingsFromDisk(); if (!fCurrentDecor) - fCurrentDecor = (DecorInfo*)fDecorList.ItemAt(0L); + fCurrentDecor = fDecorList.ItemAt(0L); } @@ -170,18 +159,25 @@ DecorManager::RescanDecorators() // to do so. If we *did* do anything with decorator versions, the // assignment would go here. - create_decorator* createFunc; + create_decor_addon* createFunc; // Get the instantiation function - status_t status = get_image_symbol(image, "instantiate_decorator", + status_t status = get_image_symbol(image, "instantiate_decor_addon", B_SYMBOL_TYPE_TEXT, (void**)&createFunc); if (status != B_OK) { unload_add_on(image); continue; } + DecorAddOn* addon = createFunc(image, ref.name); + // TODO: unload images until they are actually used! - fDecorList.AddItem(new DecorInfo(image, ref.name, createFunc)); + if (!addon || addon->InitCheck() != B_OK + || !fDecorList.AddItem(addon)) { + unload_add_on(image); + delete addon; + continue; + } } } @@ -199,11 +195,31 @@ DecorManager::AllocateDecorator(Desktop* desktop, DrawingEngine* engine, return NULL; } - return fCurrentDecor->Instantiate(desktop, engine, rect, title, + return fCurrentDecor->AllocateDecorator(desktop, engine, rect, title, look, flags); } +WindowBehaviour* +DecorManager::AllocateWindowBehaviour(Window* window) +{ + if (!fCurrentDecor) { + // We should *never* be here. If we do, it's a bug. + debugger("DecorManager::AllocateDecorator has a NULL decorator"); + return NULL; + } + + return fCurrentDecor->AllocateWindowBehaviour(window); +} + + +const DesktopListenerList& +DecorManager::GetDesktopListeners() +{ + return fCurrentDecor->GetDesktopListeners(); +} + + int32 DecorManager::CountDecorators() const { @@ -221,11 +237,11 @@ DecorManager::GetDecorator() const bool DecorManager::SetDecorator(int32 index, Desktop* desktop) { - DecorInfo* newDecInfo = (DecorInfo*)fDecorList.ItemAt(index); + DecorAddOn* newDecor = fDecorList.ItemAt(index); - if (newDecInfo) { - fCurrentDecor = newDecInfo; - desktop->ReloadAllDecorators(); + if (newDecor) { + fCurrentDecor = newDecor; + desktop->ReloadDecor(); _SaveSettingsToDisk(); return true; } @@ -248,9 +264,9 @@ DecorManager::SetR5Decorator(int32 value) return false; } - DecorInfo *newDecInfo = _FindDecor(string.String()); - if (newDecInfo) { - fCurrentDecor = newDecInfo; + DecorAddOn *newDecor = _FindDecor(string); + if (newDecor) { + fCurrentDecor = newDecor; return true; } @@ -258,40 +274,43 @@ DecorManager::SetR5Decorator(int32 value) } -const char * +BString DecorManager::GetDecoratorName(int32 index) { - DecorInfo *info = fDecorList.ItemAt(index); - if (info) - return info->Name(); + DecorAddOn *decor = fDecorList.ItemAt(index); + if (decor) + return decor->Name(); - return NULL; + return BString(""); } void DecorManager::_EmptyList() { - for (int32 i = 0; i < fDecorList.CountItems(); i++) { - delete fDecorList.ItemAt(i);; + for (int32 i = 1; i < fDecorList.CountItems(); i++) { + unload_add_on(fDecorList.ItemAt(i)->ImageID()); + delete fDecorList.ItemAt(i); } fDecorList.MakeEmpty(); - fCurrentDecor = NULL; + fDecorList.AddItem(&fDefaultDecorAddOn); + + fCurrentDecor = &fDefaultDecorAddOn; } -DecorInfo* -DecorManager::_FindDecor(const char *name) +DecorAddOn* +DecorManager::_FindDecor(BString name) { if (!name) return NULL; for (int32 i = 0; i < fDecorList.CountItems(); i++) { - DecorInfo* info = fDecorList.ItemAt(i); + DecorAddOn* decor = fDecorList.ItemAt(i); - if (strcmp(name, info->Name()) == 0) - return info; + if (decor->Name() == name) + return decor; } return NULL; @@ -321,7 +340,7 @@ DecorManager::_LoadSettingsFromDisk() if (settings.Unflatten(&file) == B_OK) { BString itemtext; if (settings.FindString("decorator", &itemtext) == B_OK) { - DecorInfo* decor = _FindDecor(itemtext.String()); + DecorAddOn* decor = _FindDecor(itemtext); if (decor) { fCurrentDecor = decor; return true; diff --git a/src/servers/app/DecorManager.h b/src/servers/app/DecorManager.h index cb5e262fd6..30fc3e051e 100644 --- a/src/servers/app/DecorManager.h +++ b/src/servers/app/DecorManager.h @@ -20,7 +20,46 @@ class DecorInfo; class Desktop; +class DesktopListener; class DrawingEngine; +class Window; +class WindowBehaviour; + + +typedef BObjectList DesktopListenerList; + + +class DecorAddOn +{ +public: + DecorAddOn(image_id id, const char* name); + virtual ~DecorAddOn(); + + virtual status_t InitCheck() const; + + image_id ImageID() const { return fImageID; } + BString Name() const { return fName; } + + Decorator* AllocateDecorator(Desktop* desktop, + DrawingEngine* engine, BRect rect, + const char* title, window_look look, + uint32 flags); + + virtual float Version() { return 1.0; } + virtual WindowBehaviour* AllocateWindowBehaviour(Window* window); + + virtual const DesktopListenerList& GetDesktopListeners(); + +protected: + virtual Decorator* _AllocateDecorator(DesktopSettings& settings, + BRect rect, window_look look, uint32 flags); + + DesktopListenerList fDesktopListeners; + +private: + image_id fImageID; + BString fName; +}; class DecorManager @@ -36,13 +75,15 @@ public: BRect rect, const char* title, window_look look, uint32 flags); + WindowBehaviour* AllocateWindowBehaviour(Window* window); + const DesktopListenerList& GetDesktopListeners(); int32 CountDecorators() const; int32 GetDecorator() const; bool SetDecorator(int32 index, Desktop* desktop); bool SetR5Decorator(int32 value); - const char* GetDecoratorName(int32 index); + BString GetDecoratorName(int32 index); // TODO: Implement this method once the rest of the necessary infrastructure // is in place @@ -50,13 +91,14 @@ public: private: void _EmptyList(); - DecorInfo* _FindDecor(const char *name); + DecorAddOn* _FindDecor(BString name); bool _LoadSettingsFromDisk(); bool _SaveSettingsToDisk(); - BObjectList fDecorList; - DecorInfo* fCurrentDecor; + BObjectList fDecorList; + DecorAddOn fDefaultDecorAddOn; + DecorAddOn* fCurrentDecor; }; extern DecorManager gDecorManager; diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index 394318f9f6..bdb141f586 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -36,6 +36,7 @@ #include #include "AppServer.h" +#include "DecorManager.h" #include "DesktopSettingsPrivate.h" #include "DrawingEngine.h" #include "HWInterface.h" @@ -1901,17 +1902,29 @@ Desktop::RedrawBackground() void -Desktop::ReloadAllDecorators() +Desktop::ReloadDecor() { AutoWriteLocker _(fWindowLock); + // TODO it is assumed all listeners are registered by one decor + // unregister old listeners + const DesktopListenerDLList& currentListeners = GetDesktopListenerList(); + for (DesktopListener* listener = currentListeners.First(); + listener != NULL; listener = currentListeners.GetNext(listener)) + UnregisterListener(listener); + // register new listeners + const DesktopListenerList& newListeners + = gDecorManager.GetDesktopListeners(); + for (int i = 0; i < newListeners.CountItems(); i++) + RegisterListener(newListeners.ItemAt(i)); + for (int32 i = 0; i < kMaxWorkspaces; i++) { for (Window* window = _Windows(i).LastWindow(); window; window = window->PreviousWindow(i)) { BRegion oldBorder; window->GetBorderRegion(&oldBorder); - window->ReloadDecorator(); + window->ReloadDecor(); BRegion border; window->GetBorderRegion(&border); diff --git a/src/servers/app/Desktop.h b/src/servers/app/Desktop.h index bef07e8196..e86a4af670 100644 --- a/src/servers/app/Desktop.h +++ b/src/servers/app/Desktop.h @@ -14,6 +14,14 @@ #define DESKTOP_H +#include +#include +#include +#include +#include +#include +#include + #include "CursorManager.h" #include "DesktopListener.h" #include "DesktopSettings.h" @@ -27,15 +35,6 @@ #include "Workspace.h" #include "WorkspacePrivate.h" -#include - -#include -#include -#include -#include -#include -#include - #define USE_MULTI_LOCKER 1 @@ -233,7 +232,7 @@ public: void Redraw(); void RedrawBackground(); - void ReloadAllDecorators(); + void ReloadDecor(); BRegion& BackgroundRegion() { return fBackgroundRegion; } diff --git a/src/servers/app/DesktopListener.cpp b/src/servers/app/DesktopListener.cpp index d40f5d91d1..ac32e9bf9e 100644 --- a/src/servers/app/DesktopListener.cpp +++ b/src/servers/app/DesktopListener.cpp @@ -37,6 +37,13 @@ DesktopObservable::UnregisterListener(DesktopListener* listener) } +const DesktopListenerDLList& +DesktopObservable::GetDesktopListenerList() +{ + return fDesktopListenerList; +} + + #define FOR_ALL_DESKTOP_LISTENER \ for (DesktopListener* listener = fDesktopListenerList.First(); \ listener != NULL; listener = fDesktopListenerList.GetNext(listener)) diff --git a/src/servers/app/DesktopListener.h b/src/servers/app/DesktopListener.h index dafc18f92f..55037a3454 100644 --- a/src/servers/app/DesktopListener.h +++ b/src/servers/app/DesktopListener.h @@ -55,7 +55,7 @@ class DesktopListener : public DoublyLinkedListLinkImpl }; -typedef DoublyLinkedList DesktopListenerList; +typedef DoublyLinkedList DesktopListenerDLList; class DesktopObservable @@ -65,6 +65,7 @@ class DesktopObservable void RegisterListener(DesktopListener* listener); void UnregisterListener(DesktopListener* listener); + const DesktopListenerDLList& GetDesktopListenerList(); void InvokeAddWindow(Window* window); void InvokeRemoveWindow(Window* window); @@ -104,10 +105,10 @@ class DesktopObservable bool& fInvoking; }; - DesktopListenerList fDesktopListenerList; + DesktopListenerDLList fDesktopListenerList; // prevent recursive invokes - bool fWeAreInvoking; + bool fWeAreInvoking; }; #endif diff --git a/src/servers/app/Window.cpp b/src/servers/app/Window.cpp index 46b81adc52..693337db4b 100644 --- a/src/servers/app/Window.cpp +++ b/src/servers/app/Window.cpp @@ -10,20 +10,18 @@ * Brecht Machiels * Clemens Zeidler */ - - #include "Window.h" #include "Decorator.h" #include "DecorManager.h" #include "Desktop.h" -#include "DefaultWindowBehaviour.h" #include "DrawingEngine.h" #include "HWInterface.h" #include "MessagePrivate.h" #include "PortLink.h" #include "ServerApp.h" #include "ServerWindow.h" +#include "WindowBehaviour.h" #include "Workspace.h" #include "WorkspacesView.h" @@ -135,7 +133,7 @@ Window::Window(const BRect& frame, const char *name, &fMaxWidth, &fMaxHeight); } } - fWindowBehaviour = new (std::nothrow)DefaultWindowBehaviour(this); + fWindowBehaviour = gDecorManager.AllocateWindowBehaviour(this); // do we need to change our size to let the decorator fit? // _ResizeBy() will adapt the frame for validity before resizing @@ -542,17 +540,35 @@ Window::PreviousWindow(int32 index) const } -void -Window::ReloadDecorator() +bool +Window::ReloadDecor() { + ::Decorator* decorator = NULL; + WindowBehaviour* windowBehaviour = NULL; + if (fLook != B_NO_BORDER_WINDOW_LOOK) { - delete fDecorator; // we need a new decorator - fDecorator = gDecorManager.AllocateDecorator(fDesktop, fDrawingEngine, + decorator = gDecorManager.AllocateDecorator(fDesktop, fDrawingEngine, Frame(), Title(), fLook, fFlags); + if (!decorator) + return false; if (IsFocus()) - fDecorator->SetFocus(true); + decorator->SetFocus(true); } + + windowBehaviour = gDecorManager.AllocateWindowBehaviour(this); + if (!windowBehaviour) { + delete decorator; + return false; + } + + delete fDecorator; + fDecorator = decorator; + + delete fWindowBehaviour; + fWindowBehaviour = windowBehaviour; + + return true; } diff --git a/src/servers/app/Window.h b/src/servers/app/Window.h index 5e4a91d3a0..f63c53b773 100644 --- a/src/servers/app/Window.h +++ b/src/servers/app/Window.h @@ -10,12 +10,10 @@ * Brecht Machiels * Clemens Zeidler */ - #ifndef WINDOW_H #define WINDOW_H -#include "Decorator.h" #include "RegionPool.h" #include "ServerWindow.h" #include "View.h" @@ -71,7 +69,7 @@ public: ::EventTarget& EventTarget() const { return fWindow->EventTarget(); } - void ReloadDecorator(); + bool ReloadDecor(); void SetScreen(const ::Screen* screen); const ::Screen* Screen() const;