* Copyright (c) 2001-2020 Haiku, Inc. All right reserved.
* Distributed under the terms of the MIT license.
*
* Author:
* DarkWyrm <bpmagic@columbus.rr.com>
* Clemens Zeidler <haiku@clemens-zeidler.de>
* Joseph Groover <looncraz@satx.rr.com>
* John Scipione <jscipione@gmail.com>
*/
#include "DecorManager.h"
#include <Directory.h>
#include <Entry.h>
#include <File.h>
#include <FindDirectory.h>
#include <Message.h>
#include <Path.h>
#include <Rect.h>
#include <syslog.h>
#include "AppServer.h"
#include "Desktop.h"
#include "DesktopSettings.h"
#include "ServerConfig.h"
#include "SATDecorator.h"
#include "Window.h"
typedef float get_version(void);
typedef DecorAddOn* create_decor_addon(image_id id, const char* name);
DecorManager gDecorManager;
DecorAddOn::DecorAddOn(image_id id, const char* name)
:
fImageID(id),
fName(name)
{
}
DecorAddOn::~DecorAddOn()
{
}
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;
decorator = _AllocateDecorator(settings, rect, desktop);
desktop->UnlockSingleWindow();
if (!decorator)
return NULL;
decorator->UpdateColors(settings);
if (decorator->AddTab(settings, title, look, flags) == NULL) {
delete decorator;
return NULL;
}
decorator->SetDrawingEngine(engine);
return decorator;
}
WindowBehaviour*
DecorAddOn::AllocateWindowBehaviour(Window* window)
{
return new (std::nothrow)SATWindowBehaviour(window,
window->Desktop()->GetStackAndTile());
}
const DesktopListenerList&
DecorAddOn::GetDesktopListeners()
{
return fDesktopListeners;
}
Decorator*
DecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect,
Desktop* desktop)
{
return new (std::nothrow)SATDecorator(settings, rect, desktop);
}
DecorManager::DecorManager()
:
fDefaultDecor(-1, "Default"),
fCurrentDecor(&fDefaultDecor),
fPreviewDecor(NULL),
fPreviewWindow(NULL),
fCurrentDecorPath("Default")
{
_LoadSettingsFromDisk();
}
DecorManager::~DecorManager()
{
}
Decorator*
DecorManager::AllocateDecorator(Window* window)
{
if (!fCurrentDecor) {
debugger("DecorManager::AllocateDecorator has a NULL decorator");
return NULL;
}
if (window == fPreviewWindow) {
if (fPreviewDecor != NULL) {
return fPreviewDecor->AllocateDecorator(window->Desktop(),
window->GetDrawingEngine(), window->Frame(), window->Title(),
window->Look(), window->Flags());
} else {
fPreviewWindow = NULL;
}
}
return fCurrentDecor->AllocateDecorator(window->Desktop(),
window->GetDrawingEngine(), window->Frame(), window->Title(),
window->Look(), window->Flags());
}
WindowBehaviour*
DecorManager::AllocateWindowBehaviour(Window* window)
{
if (!fCurrentDecor) {
debugger("DecorManager::AllocateDecorator has a NULL decorator");
return NULL;
}
return fCurrentDecor->AllocateWindowBehaviour(window);
}
void
DecorManager::CleanupForWindow(Window* window)
{
if (fPreviewWindow == window && window != NULL){
fPreviewWindow = NULL;
if (fPreviewDecor != NULL)
unload_add_on(fPreviewDecor->ImageID());
fPreviewDecor = NULL;
}
}
status_t
DecorManager::PreviewDecorator(BString path, Window* window)
{
if (fPreviewWindow != NULL && fPreviewWindow != window){
Window* oldPreviewWindow = fPreviewWindow;
fPreviewWindow = NULL;
oldPreviewWindow->ReloadDecor();
}
if (window == NULL)
return B_BAD_VALUE;
status_t error = B_OK;
DecorAddOn* decorPtr = _LoadDecor(path, error);
if (decorPtr == NULL)
return error == B_OK ? B_ERROR : error;
BRegion border;
window->GetBorderRegion(&border);
DecorAddOn* oldDecor = fPreviewDecor;
fPreviewDecor = decorPtr;
fPreviewWindow = window;
fPreviewWindow->ReloadDecor();
BRegion newBorder;
window->GetBorderRegion(&newBorder);
border.Include(&newBorder);
window->Desktop()->RebuildAndRedrawAfterWindowChange(window, border);
if (oldDecor != NULL)
unload_add_on(oldDecor->ImageID());
return B_OK;
}
const DesktopListenerList&
DecorManager::GetDesktopListeners()
{
return fCurrentDecor->GetDesktopListeners();
}
BString
DecorManager::GetCurrentDecorator() const
{
return fCurrentDecorPath.String();
}
status_t
DecorManager::SetDecorator(BString path, Desktop* desktop)
{
status_t error = B_OK;
DecorAddOn* newDecor = _LoadDecor(path, error);
if (newDecor == NULL)
return error == B_OK ? B_ERROR : error;
DecorAddOn* oldDecor = fCurrentDecor;
BString oldPath = fCurrentDecorPath;
image_id oldImage = fCurrentDecor->ImageID();
fCurrentDecor = newDecor;
fCurrentDecorPath = path.String();
if (desktop->ReloadDecor(oldDecor)) {
unload_add_on(oldImage);
_SaveSettingsToDisk();
return B_OK;
}
syslog(LOG_WARNING,
"app_server:DecorManager:SetDecorator:\"%s\" *partly* failed\n",
fCurrentDecorPath.String());
fCurrentDecor = oldDecor;
fCurrentDecorPath = oldPath;
return B_ERROR;
}
DecorAddOn*
DecorManager::_LoadDecor(BString _path, status_t& error )
{
if (_path == "Default") {
error = B_OK;
return &fDefaultDecor;
}
BEntry entry(_path.String(), true);
if (!entry.Exists()) {
error = B_ENTRY_NOT_FOUND;
return NULL;
}
BPath path(&entry);
image_id image = load_add_on(path.Path());
if (image < 0) {
error = B_BAD_IMAGE_ID;
return NULL;
}
create_decor_addon* createFunc;
if (get_image_symbol(image, "instantiate_decor_addon", B_SYMBOL_TYPE_TEXT,
(void**)&createFunc) != B_OK) {
unload_add_on(image);
error = B_MISSING_SYMBOL;
return NULL;
}
char name[B_FILE_NAME_LENGTH];
entry.GetName(name);
DecorAddOn* newDecor = createFunc(image, name);
if (newDecor == NULL || newDecor->InitCheck() != B_OK) {
unload_add_on(image);
error = B_ERROR;
return NULL;
}
return newDecor;
}
static const char* kSettingsDir = "system/app_server";
static const char* kSettingsFile = "decorator_settings";
bool
DecorManager::_LoadSettingsFromDisk()
{
BPath path;
status_t error = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
if (error != B_OK)
return false;
path.Append(kSettingsDir);
path.Append(kSettingsFile);
BFile file(path.Path(), B_READ_ONLY);
if (file.InitCheck() != B_OK)
return false;
BMessage settings;
if (settings.Unflatten(&file) == B_OK) {
BString itemPath;
if (settings.FindString("decorator", &itemPath) == B_OK) {
status_t error = B_OK;
DecorAddOn* decor = _LoadDecor(itemPath, error);
if (decor != NULL) {
fCurrentDecor = decor;
fCurrentDecorPath = itemPath;
return true;
} else {
}
}
}
return false;
}
bool
DecorManager::_SaveSettingsToDisk()
{
BPath path;
status_t error = find_directory(B_USER_SETTINGS_DIRECTORY, &path, true);
if (error != B_OK)
return false;
path.Append(kSettingsDir);
if (create_directory(path.Path(), 777) != B_OK)
return false;
path.Append(kSettingsFile);
BFile file(path.Path(), B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE);
if (file.InitCheck() != B_OK)
return false;
BMessage settings;
if (settings.AddString("decorator", fCurrentDecorPath.String()) != B_OK)
return false;
if (settings.Flatten(&file) != B_OK)
return false;
return true;
}