diff --git a/headers/private/interface/DecorInfo.h b/headers/private/interface/DecorInfo.h new file mode 100644 index 0000000000..d66eb74735 --- /dev/null +++ b/headers/private/interface/DecorInfo.h @@ -0,0 +1,129 @@ +/* + * Public domain source code. + * + * Author: + * Joseph "looncraz" Groover + */ + + +#ifndef DECOR_INFO_H +#define DECOR_INFO_H + + +#include +#include +#include +#include +#include + + +// NOTE: DecorInfo itself is not thread-safe +class DecorInfo { +public: + DecorInfo(); + DecorInfo(const BString& path); + DecorInfo(const entry_ref& ref); + ~DecorInfo(); + + status_t SetTo(const entry_ref& ref); + status_t SetTo(BString path); + status_t InitCheck() const; + void Unset(); + + bool IsDefault() const; + + BString Path() const; + // Returns "Default" for the default decorator + + const entry_ref* Ref() const; + // Returns NULL if virtual (default) or InitCheck() != B_OK + // The ref returned may NOT be the same as the one given to + // SetTo or the constructor - we may have traversed a Symlink! + + BString Name() const; + BString ShortcutName() const; + + BString Authors() const; + BString ShortDescription() const; + BString LongDescription() const; + BString LicenseURL() const; + BString LicenseName() const; + BString SupportURL() const; + + float Version() const; + time_t ModificationTime() const; + + bool CheckForChanges(bool &deleted); + +private: + void _Init(bool is_update = false); + +private: + entry_ref fRef; + + BString fPath; + BString fName; + BString fAuthors; + BString fShortDescription; + BString fLongDescription; + BString fLicenseURL; + BString fLicenseName; + BString fSupportURL; + + float fVersion; + + time_t fModificationTime; + + status_t fInitStatus; +}; + + +class DecorInfoUtility{ +public: + DecorInfoUtility(bool scanNow = true); + // NOTE: When scanNow is passed false, + // scanning will be performed lazily, such + // as in CountDecorators() and other + // methods. + + ~DecorInfoUtility(); + + status_t ScanDecorators(); + // Can also be used to rescan for changes. + // Warning: potentially destructive as we + // will remove all DecorInfo objects which + // no longer have a file system cousin. + // TODO: Would a call-back mechanism be + // worthwhile here? + + int32 CountDecorators(); + + DecorInfo* DecoratorAt(int32); + + DecorInfo* FindDecorator(const BString& string); + // Checks for ref.name, path, fName, and + // "Default," an empty-string returns the + // current decorator NULL on match failure + + DecorInfo* CurrentDecorator(); + DecorInfo* DefaultDecorator(); + + bool IsCurrentDecorator(DecorInfo*); + + status_t SetDecorator(DecorInfo*); + status_t SetDecorator(int32); + + status_t Preview(DecorInfo* decor, BWindow* window); + +private: + DecorInfo* _FindDecor(const BString& path); + +private: + BObjectList fList; + BLocker fLock; + bool fHasScanned; + +}; + + +#endif diff --git a/src/add-ons/decorators/BeDecorator/BeDecorator.cpp b/src/add-ons/decorators/BeDecorator/BeDecorator.cpp index bf7907ef10..2c39148c80 100644 --- a/src/add-ons/decorators/BeDecorator/BeDecorator.cpp +++ b/src/add-ons/decorators/BeDecorator/BeDecorator.cpp @@ -93,13 +93,6 @@ BeDecorAddOn::BeDecorAddOn(image_id id, const char* name) } -float -BeDecorAddOn::Version() -{ - return 1.00; -} - - Decorator* BeDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect, window_look look, uint32 flags) diff --git a/src/add-ons/decorators/BeDecorator/BeDecorator.h b/src/add-ons/decorators/BeDecorator/BeDecorator.h index a6bb80d67d..34ad4b0208 100644 --- a/src/add-ons/decorators/BeDecorator/BeDecorator.h +++ b/src/add-ons/decorators/BeDecorator/BeDecorator.h @@ -24,8 +24,6 @@ class BeDecorAddOn : public DecorAddOn { public: BeDecorAddOn(image_id id, const char* name); - float Version(); - protected: virtual Decorator* _AllocateDecorator(DesktopSettings& settings, BRect rect, window_look look, uint32 flags); diff --git a/src/add-ons/decorators/BeDecorator/Jamfile b/src/add-ons/decorators/BeDecorator/Jamfile index 6a1dc0f343..2cea3d0db7 100644 --- a/src/add-ons/decorators/BeDecorator/Jamfile +++ b/src/add-ons/decorators/BeDecorator/Jamfile @@ -7,7 +7,10 @@ UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter ] ; UsePrivateHeaders app shared interface graphics ; UseLibraryHeaders agg ; +AddResources ClassicBe : resources.rdef ; + Addon ClassicBe : BeDecorator.cpp : be app_server $(TARGET_LIBSTDC++) $(TARGET_LIBSUPC++) + : resources.rdef ; diff --git a/src/add-ons/decorators/BeDecorator/resources.rdef b/src/add-ons/decorators/BeDecorator/resources.rdef new file mode 100644 index 0000000000..6174acddd4 --- /dev/null +++ b/src/add-ons/decorators/BeDecorator/resources.rdef @@ -0,0 +1,10 @@ +resource("be:decor:info") message('deco') { + "name" = "Classic BeOS", + "authors" = "DarkWyrm, Stephan Aßmus, Clemens Zeidler", + "short_descr" = "Basic appearance of the classic BeOS.", + "long_descr" = "", + "lic_url" = "", + "lic_name" = "MIT", + "support_url" = "http://www.haiku-os.org/", + float "version" = 1.0 +}; diff --git a/src/add-ons/decorators/MacDecorator/Jamfile b/src/add-ons/decorators/MacDecorator/Jamfile index 7671ab5f75..f6eaccedb7 100644 --- a/src/add-ons/decorators/MacDecorator/Jamfile +++ b/src/add-ons/decorators/MacDecorator/Jamfile @@ -7,6 +7,8 @@ UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter ] ; UsePrivateHeaders app shared interface graphics ; UseLibraryHeaders agg ; +AddResources MacDecorator : resources.rdef ; + Addon MacDecorator : MacDecorator.cpp : be app_server $(TARGET_LIBSTDC++) diff --git a/src/add-ons/decorators/MacDecorator/MacDecorator.cpp b/src/add-ons/decorators/MacDecorator/MacDecorator.cpp index df94420733..5f8d362fd5 100644 --- a/src/add-ons/decorators/MacDecorator/MacDecorator.cpp +++ b/src/add-ons/decorators/MacDecorator/MacDecorator.cpp @@ -38,13 +38,6 @@ MacDecorAddOn::MacDecorAddOn(image_id id, const char* name) } -float -MacDecorAddOn::Version() -{ - return 1.00; -} - - Decorator* MacDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect, window_look look, uint32 flags) diff --git a/src/add-ons/decorators/MacDecorator/MacDecorator.h b/src/add-ons/decorators/MacDecorator/MacDecorator.h index e1aa512f9b..634e61a79a 100644 --- a/src/add-ons/decorators/MacDecorator/MacDecorator.h +++ b/src/add-ons/decorators/MacDecorator/MacDecorator.h @@ -14,8 +14,6 @@ class MacDecorAddOn : public DecorAddOn { public: MacDecorAddOn(image_id id, const char* name); - float Version(); - protected: virtual Decorator* _AllocateDecorator(DesktopSettings& settings, BRect rect, window_look look, uint32 flags); diff --git a/src/add-ons/decorators/MacDecorator/resources.rdef b/src/add-ons/decorators/MacDecorator/resources.rdef new file mode 100644 index 0000000000..d10ae684dc --- /dev/null +++ b/src/add-ons/decorators/MacDecorator/resources.rdef @@ -0,0 +1,10 @@ +resource("be:decor:info") message('deco') { + "name" = "MacOS 9", + "authors" = "", + "short_descr" = "MacOS 9", + "long_descr" = "", + "lic_url" = "", + "lic_name" = "MIT", + "support_url" = "http://www.haiku-os.org/", + float "version" = 1.0 +}; diff --git a/src/add-ons/decorators/SATDecorator/Jamfile b/src/add-ons/decorators/SATDecorator/Jamfile index 94f39b7cf8..1f07f3ecc4 100644 --- a/src/add-ons/decorators/SATDecorator/Jamfile +++ b/src/add-ons/decorators/SATDecorator/Jamfile @@ -8,6 +8,8 @@ UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing ] ; UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter ] ; UseFreeTypeHeaders ; +AddResources SATDecorator : resources.rdef ; + Addon SATDecorator : SATDecorator.cpp SATGroup.cpp diff --git a/src/add-ons/decorators/SATDecorator/SATDecorator.cpp b/src/add-ons/decorators/SATDecorator/SATDecorator.cpp index e9bcce9fa2..c31d73911e 100644 --- a/src/add-ons/decorators/SATDecorator/SATDecorator.cpp +++ b/src/add-ons/decorators/SATDecorator/SATDecorator.cpp @@ -66,13 +66,6 @@ SATDecorAddOn::InitCheck() const } -float -SATDecorAddOn::Version() -{ - return 0.1; -} - - Decorator* SATDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect, window_look look, uint32 flags) diff --git a/src/add-ons/decorators/SATDecorator/SATDecorator.h b/src/add-ons/decorators/SATDecorator/SATDecorator.h index 3eb9c5d011..e722625df9 100644 --- a/src/add-ons/decorators/SATDecorator/SATDecorator.h +++ b/src/add-ons/decorators/SATDecorator/SATDecorator.h @@ -19,7 +19,6 @@ public: SATDecorAddOn(image_id id, const char* name); virtual status_t InitCheck() const; - float Version(); protected: virtual Decorator* _AllocateDecorator(DesktopSettings& settings, diff --git a/src/add-ons/decorators/SATDecorator/resources.rdef b/src/add-ons/decorators/SATDecorator/resources.rdef new file mode 100644 index 0000000000..3ceacd091c --- /dev/null +++ b/src/add-ons/decorators/SATDecorator/resources.rdef @@ -0,0 +1,11 @@ +resource("be:decor:info") message('deco') { + "name" = "Stack and Tile", + "authors" = "Clemens Zeidler, Ingo Weinhold", + "short_descr" = "Default look with ability to stack & tile windows.", + "long_descr" = "Group windows together and take advantage of those" + " tabs!\n\nTODO: instructions", + "lic_url" = "", + "lic_name" = "MIT", + "support_url" = "http://www.haiku-os.org/", + float "version" = 1.0 +}; diff --git a/src/add-ons/decorators/WinDecorator/Jamfile b/src/add-ons/decorators/WinDecorator/Jamfile index fa945b98d3..49acf41505 100644 --- a/src/add-ons/decorators/WinDecorator/Jamfile +++ b/src/add-ons/decorators/WinDecorator/Jamfile @@ -7,6 +7,8 @@ UseHeaders [ FDirName $(HAIKU_TOP) src servers app drawing Painter ] ; UsePrivateHeaders app shared interface graphics ; UseLibraryHeaders agg ; +AddResources WinDecorator : resources.rdef ; + Addon WinDecorator : WinDecorator.cpp : be app_server $(TARGET_LIBSTDC++) diff --git a/src/add-ons/decorators/WinDecorator/WinDecorator.cpp b/src/add-ons/decorators/WinDecorator/WinDecorator.cpp index fc7971ed59..836841979b 100644 --- a/src/add-ons/decorators/WinDecorator/WinDecorator.cpp +++ b/src/add-ons/decorators/WinDecorator/WinDecorator.cpp @@ -37,13 +37,6 @@ WinDecorAddOn::WinDecorAddOn(image_id id, const char* name) } -float -WinDecorAddOn::Version() -{ - return 1.00; -} - - Decorator* WinDecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect, window_look look, uint32 flags) diff --git a/src/add-ons/decorators/WinDecorator/WinDecorator.h b/src/add-ons/decorators/WinDecorator/WinDecorator.h index eddd59d154..aec2b0f6b1 100644 --- a/src/add-ons/decorators/WinDecorator/WinDecorator.h +++ b/src/add-ons/decorators/WinDecorator/WinDecorator.h @@ -14,7 +14,6 @@ class WinDecorAddOn : public DecorAddOn { public: WinDecorAddOn(image_id id, const char* name); - float Version(); protected: virtual Decorator* _AllocateDecorator(DesktopSettings& settings, diff --git a/src/add-ons/decorators/WinDecorator/resources.rdef b/src/add-ons/decorators/WinDecorator/resources.rdef new file mode 100644 index 0000000000..06e3be2036 --- /dev/null +++ b/src/add-ons/decorators/WinDecorator/resources.rdef @@ -0,0 +1,10 @@ +resource("be:decor:info") message('deco') { + "name" = "Windows 95", + "authors" = "", + "short_descr" = "Windows 95", + "long_descr" = "", + "lic_url" = "", + "lic_name" = "MIT", + "support_url" = "http://www.haiku-os.org/", + float "version" = 1.0 +}; diff --git a/src/bin/Jamfile b/src/bin/Jamfile index e41b9b5e57..3769a6b2ba 100644 --- a/src/bin/Jamfile +++ b/src/bin/Jamfile @@ -102,7 +102,6 @@ StdBinCommands play.cpp quit.cpp roster.cpp - setdecor.cpp setversion.cpp trash.cpp version.cpp @@ -123,6 +122,7 @@ StdBinCommands hey.cpp reindex.cpp resattr.cpp + setdecor.cpp settype.cpp spybmessage.cpp urlwrapper.cpp diff --git a/src/bin/setdecor.cpp b/src/bin/setdecor.cpp index 9bc80e03ab..273b787c18 100644 --- a/src/bin/setdecor.cpp +++ b/src/bin/setdecor.cpp @@ -1,4 +1,5 @@ /* + * Copyright 2011, Joseph "looncraz" Groover, looncraz@satx.rr.com * Copyright 2007, François Revol, revol@free.fr. * Distributed under the terms of the MIT license. */ @@ -7,87 +8,224 @@ #include #include +#include #include #include +#include +#include -class BBitmap; +#include -namespace BPrivate { -int32 count_decorators(void); -int32 get_decorator(void); -status_t get_decorator_name(const int32 &index, BString &name); -status_t get_decorator_preview(const int32 &index, BBitmap *bitmap); -status_t set_decorator(const int32 &index); + +void +print_decor_info_header() +{ + printf(" Name License\t Description\n"); + printf("----------------------------------------------------\n"); } -using namespace BPrivate; -int main(int argc, char **argv) +void +print_decor_summary(DecorInfo* decor, bool isCurrent) +{ + if (isCurrent) + printf("*"); + + printf("%-12s\t%-8s %-30s\n", decor->Name().String(), + decor->LicenseName().String(), decor->ShortDescription().String()); +} + + +void +print_decor_shortcut(DecorInfo* decor, bool isCurrent) +{ + if (isCurrent) + printf("*"); + + printf("%-12s\t%-12s\n", decor->ShortcutName().String(), + decor->Name().String()); +} + + +void +print_decor_info_verbose(DecorInfo* decor, bool isCurrent) +{ + printf("Name:\t\t%s\n", decor->Name().String()); + printf("Version:\t%f\n", decor->Version()); + printf("Author(s):\t%s\n", decor->Authors().String()); + printf("Description:\t%s\n", decor->ShortDescription().String()); + printf("License:\t%s (%s)\n", decor->LicenseName().String(), + decor->LicenseURL().String()); + printf("Support URL:\t%s\n", decor->SupportURL().String()); + printf("%s\n", isCurrent ? "Currently in use." : "Currently not in use."); +} + + +int +main(int argc, char** argv) { - status_t err; if (argc < 2) { printf("usage: %s [-l|-c|decorname]\n", argv[0]); printf("\t-l: list available decors\n"); + printf("\t-s: list shortcut names for available decors\n"); printf("\t-c: give current decor name\n"); + printf("\t-i: detailed information about decor\n"); + printf("\t-p: see preview window\n"); return 1; } + + // combine remaining args into one string: + BString decoratorName; + for (int i = 2; i < argc; ++i) + decoratorName << argv[i] << " "; + decoratorName.RemoveLast(" "); + BApplication app("application/x-vnd.Haiku-setdecor"); + + DecorInfoUtility* util = new DecorInfoUtility(); + DecorInfo* decor = NULL; + + if (util == NULL) { + fprintf(stderr, "error instantiating DecoratorInfoUtility (out of" + " memory?)\n"); + return 1; + } + // we want the list if (!strcmp(argv[1], "-l")) { - int32 i, count; - count = count_decorators(); - if (count < 0) { - fprintf(stderr, "error counting decorators: %s\n", strerror(count)); - return 1; - } - for (i = 0; i < count; i++) { - BString name; - err = get_decorator_name(i, name); - if (err < 0) - continue; - printf("%s\n", name.String()); + // Print default decorator: + print_decor_info_header(); + int32 count = util->CountDecorators(); + for (int32 i = 0; i < count; ++i) { + decor = util->DecoratorAt(i); + if (decor == NULL) { + fprintf(stderr, "error NULL entry @ %li / %li - BUG BUG BUG\n", + i, count); + // return 2 to track DecorInfoUtility errors + return 2; + } + print_decor_summary(decor, util->IsCurrentDecorator(decor)); } + return 0; } - // we want the current one + + // we want the current decorator if (!strcmp(argv[1], "-c")) { - int32 i; - BString name; - i = get_decorator(); - if (i < 0) { - fprintf(stderr, "error getting current decorator: %s\n", strerror(i)); - return 1; + decor = util->CurrentDecorator(); + + if (decor == NULL) { + fprintf(stderr, "Unable to determine current decorator, sorry! - " + "BUG BUG BUG\n"); + return 2; } - err = get_decorator_name(i, name); - if (err < 0) { - fprintf(stderr, "error getting name of decorator: %s\n", strerror(err)); - return 1; - } - printf("%s\n", name.String()); + + print_decor_info_header(); + print_decor_summary(decor, true); return 0; } + + + if (!strcmp(argv[1], "-s")) { + + printf(" Shortcut Name\n"); + printf("------------------------------------\n"); + + int32 count = util->CountDecorators(); + for (int32 i = 0; i < count; ++i) { + decor = util->DecoratorAt(i); + if (decor == NULL) { + fprintf(stderr, "error NULL entry @ %li / %li - BUG BUG BUG\n", + i, count); + // return 2 to track DecorInfoUtility errors + return 2; + } + print_decor_shortcut(decor, util->IsCurrentDecorator(decor)); + } + + return 0; + } + + // we want detailed information for a specific decorator ( by name or path ) + if (!strcmp(argv[1], "-i")) { + if (argc < 3) { + fprintf(stderr, "not enough arguments\n"); + return 1; + } + + decor = util->FindDecorator(decoratorName.String()); + + if (decor == NULL) { + fprintf(stderr, "Can't find decor named \"%s\", try again\n", + decoratorName.String()); + return 1; + } + + print_decor_info_verbose(decor, util->IsCurrentDecorator(decor)); + return 0; + } + + + if (!strcmp(argv[1], "-p")) { + if (argc < 3) { + fprintf(stderr, "not enough arguments\n"); + return 1; + } + + decor = util->FindDecorator(decoratorName.String()); + + if (decor == NULL) { + fprintf(stderr, "Can't find decor named \"%s\", try again\n", + decoratorName.String()); + return 1; + } + + printf("Preparing preview...\n"); + + BWindow* previewWindow = new BWindow(BRect(150, 150, 390, 490), + decor->Name().String(), B_TITLED_WINDOW, B_NOT_ZOOMABLE + | B_QUIT_ON_WINDOW_CLOSE | B_NOT_RESIZABLE ); + + previewWindow->AddChild(new BView(previewWindow->Bounds(), "", + B_FOLLOW_ALL, 0)); + + if (util->Preview(decor, previewWindow) != B_OK) { + fprintf(stderr, "Unable to preview decorator, sorry!\n"); + // TODO: more detailed error... + return 1; + } + + previewWindow->Show(); + + app.Run(); + return 0; + } + // we want to change it - int32 i, count; - count = count_decorators(); - if (count < 0) { - fprintf(stderr, "error counting decorators: %s\n", strerror(count)); + decoratorName = ""; + for (int i = 1; i < argc; ++i) + decoratorName << argv[i] << " "; + decoratorName.RemoveLast(" "); + + decor = util->FindDecorator(decoratorName.String()); + + if (decor == NULL) { + fprintf(stderr, "no such decorator \"%s\"\n", decoratorName.String()); return 1; } - for (i = 0; i < count; i++) { - BString name; - err = get_decorator_name(i, name); - if (err < 0) - continue; - if (name == argv[1]) { - err = set_decorator(i); - if (err < 0) { - fprintf(stderr, "error setting decorator: %s\n", strerror(err)); - return 1; - } - return 0; - } + + if (util->IsCurrentDecorator(decor)) { + printf("\"%s\" is already the current decorator\n", + decor->Name().String()); + return 0; } - fprintf(stderr, "can't find decorator \"%s\"\n", argv[1]); - return 1; + + printf("Setting %s as the current decorator...\n", decor->Name().String()); + if (util->SetDecorator(decor) != B_OK ) { + fprintf(stderr, "Unable to set decorator, sorry\n\n"); + return 1; // todo more detailed error... + } + + return 0; } diff --git a/src/kits/interface/DecorInfo.cpp b/src/kits/interface/DecorInfo.cpp new file mode 100644 index 0000000000..abec0f34c3 --- /dev/null +++ b/src/kits/interface/DecorInfo.cpp @@ -0,0 +1,594 @@ +/* + * Public domain source code. + * + * Author: + * Joseph "looncraz" Groover + */ + + +#include + +#include +#include + +#include +#include +#include +#include +#include + + +DecorInfo::DecorInfo() + : + fVersion(0), + fModificationTime(0), + fInitStatus(B_NO_INIT) +{ +} + + +DecorInfo::DecorInfo(const BString& path) + : + fPath(path), + fVersion(0), + fModificationTime(0), + fInitStatus(B_NO_INIT) +{ + BEntry entry(path.String(), true); + entry.GetRef(&fRef); + + _Init(); +} + + +DecorInfo::DecorInfo(const entry_ref& ref) + : + fRef(ref), + fVersion(0), + fModificationTime(0), + fInitStatus(B_NO_INIT) +{ + BPath path(&ref); + fPath = path.Path(); + + _Init(); +} + + +DecorInfo::~DecorInfo() +{ +} + + +status_t +DecorInfo::SetTo(const entry_ref& ref) +{ + Unset(); + + BPath path(&ref); + fPath = path.Path(); + path.Unset(); + + fRef = ref; + _Init(); + + return InitCheck(); +} + + +status_t +DecorInfo::SetTo(BString path) +{ + entry_ref ref; + BEntry entry(path.String(), true); + entry.GetRef(&ref); + entry.Unset(); + return SetTo(ref); +} + + +status_t +DecorInfo::InitCheck() const +{ + return fInitStatus; +} + + +void +DecorInfo::Unset() +{ + fRef = entry_ref(); + fPath = ""; + fName = ""; + fAuthors = ""; + fShortDescription = ""; + fLicenseURL = ""; + fLicenseName = ""; + fSupportURL = ""; + fVersion = 0; + fModificationTime = 0; + fInitStatus = B_NO_INIT; +} + + +bool +DecorInfo::IsDefault() const +{ + return fInitStatus == B_OK && fPath == "Default"; +} + + +BString +DecorInfo::Path() const +{ + return fPath.String(); +} + + +const entry_ref* +DecorInfo::Ref() const +{ + if (InitCheck() != B_OK || IsDefault()) + return NULL; + return &fRef; +} + + +BString +DecorInfo::Name() const +{ + return fName; +} + + +BString +DecorInfo::ShortcutName() const +{ + if (Ref()) + return fRef.name; + return Name(); +} + + +BString +DecorInfo::Authors() const +{ + return fAuthors; +} + + +BString +DecorInfo::ShortDescription() const +{ + return fShortDescription; +} + + +BString +DecorInfo::LongDescription() const +{ + return fLongDescription; +} + + +BString +DecorInfo::LicenseURL() const +{ + return fLicenseURL; +} + + +BString +DecorInfo::LicenseName() const +{ + return fLicenseName; +} + + +BString +DecorInfo::SupportURL() const +{ + return fSupportURL; +} + + +float +DecorInfo::Version() const +{ + return fVersion; +} + + +time_t +DecorInfo::ModificationTime() const +{ + return fModificationTime; +} + + +bool +DecorInfo::CheckForChanges(bool& deleted) +{ + if (InitCheck() != B_OK) + return false; + + BEntry entry(&fRef); + + if (entry.InitCheck() != B_OK) + return false; + + if (!entry.Exists()) { + deleted = true; + return true; + } + + time_t modtime = 0; + if (entry.GetModificationTime(&modtime) != B_OK) { + fprintf(stderr, "DecorInfo::CheckForChanges()\tERROR: " + "BEntry:GetModificationTime() failed\n"); + return false; + } + + if (fModificationTime != modtime) { + _Init(true); + return true; + } + + return false; +} + + +void +DecorInfo::_Init(bool isUpdate) +{ + if (!isUpdate && InitCheck() != B_NO_INIT) { + // TODO: remove after validation + fprintf(stderr, "DecorInfo::_Init()\tImproper init state\n"); + return; + } + + BEntry entry; + + if (fPath == "Default") { + if (isUpdate){ + // should never happen + fprintf(stderr, "DecorInfo::_Init(true)\tBUG BUG updating default" + "decorator!?!?!\n"); + return; + } + + fName = "Default"; + fAuthors = "DarkWyrm, Stephan Aßmus, Clemens Zeidler, Ingo Weinhold"; + fShortDescription = "Default Haiku window decorator."; + fLongDescription = fShortDescription; + fLicenseURL = "http://"; + fLicenseName = "MIT"; + fSupportURL = "http://www.haiku-os.org/"; + fVersion = 0.5; + fInitStatus = B_OK; + + // The following is to get the modification time of the app_server + // and, thusly, the Default decorator... + // If you can make it more simple, please do! + BPath path; + find_directory(B_BEOS_SERVERS_DIRECTORY, &path); + path.Append("app_server"); + entry.SetTo(path.Path(), true); + if (!entry.Exists()) { + fprintf(stderr, "Server MIA the world has become its slave! " + "Call the CIA!\n"); + return; + } + + entry.GetModificationTime(&fModificationTime); + entry.Unset(); + return; + } + + // Is a file system object... + + entry.SetTo(&fRef, true); // follow link + if (entry.InitCheck() != B_OK) { + fInitStatus = entry.InitCheck(); + return; + } + + if (!entry.Exists()) { + if (isUpdate) { + fprintf(stderr, "DecorInfo::_Init()\tERROR: decorator deleted" + " after CheckForChanges() found it!\n"); + fprintf(stderr, "DecorInfo::_Init()\tERROR: DecorInfo will " + "Unset\n"); + Unset(); + } + return; + } + + // update fRef to match file system object + entry.GetRef(&fRef); + entry.GetModificationTime(&fModificationTime); + + BResources resources(&fRef); + if (resources.InitCheck() != B_OK) { + fprintf(stderr, "DecorInfo::_Init()\t BResource InitCheck() failure\n"); + return; + } + + size_t infoSize = 0; + const void* infoData = resources.LoadResource(B_MESSAGE_TYPE, + "be:decor:info", &infoSize); + BMessage infoMessage; + + if (infoData == NULL || infoSize == 0 + || infoMessage.Unflatten((const char*)infoData) != B_OK) { + fprintf(stderr, "DecorInfo::_init()\tNo extended information found for" + " \"%s\"\n", fRef.name); + } else { + infoMessage.FindString("name", &fName); + infoMessage.FindString("authors", &fAuthors); + infoMessage.FindString("short_descr", &fShortDescription); + infoMessage.FindString("long_descr", &fLongDescription); + infoMessage.FindString("lic_url", &fLicenseURL); + infoMessage.FindString("lic_name", &fLicenseName); + infoMessage.FindString("support_url", &fSupportURL); + infoMessage.FindFloat ("version", &fVersion); + } + + resources.Unset(); + fInitStatus = B_OK; + fName = fRef.name; +} + + +// #pragma mark - DecorInfoUtility + + +namespace BPrivate { + // kits/interface/InterfaceDefs.cpp + bool get_decorator(BString&); + status_t set_decorator(const BString&); + status_t preview_decorator(const BString&, BWindow*); +}; + +using namespace BPrivate; + + +DecorInfoUtility::DecorInfoUtility(bool scanNow) + : + fHasScanned(false) +{ + // get default decorator from app_server + DecorInfo* info = new(std::nothrow) DecorInfo("Default"); + if (info == NULL || info->InitCheck() != B_OK) { + delete info; + fprintf(stderr, "DecorInfoUtility::constructor\tdefault decorator's " + "DecorInfo failed InitCheck()\n"); + return; + } + + fList.AddItem(info); + + if (scanNow) + ScanDecorators(); +} + + +DecorInfoUtility::~DecorInfoUtility() +{ + BAutolock _(fLock); + for (int i = fList.CountItems() - 1; i >= 0; --i) + delete fList.ItemAt(i); +} + + +status_t +DecorInfoUtility::ScanDecorators() +{ + BPath decorPath; + status_t ret = find_directory(B_USER_ADDONS_DIRECTORY, &decorPath); + if (ret != B_OK) + return ret; + ret = decorPath.Append("decorators"); + if (ret != B_OK) + return ret; + + BDirectory dir(decorPath.Path()); + ret = dir.InitCheck(); + if (ret != B_OK) { + fprintf(stderr, "DecorInfoUtility::ScanDecorators:\tERROR: " + "DECORATORS_DIR not found!\n"); + return ret; + } + + BAutolock _(fLock); + // First, run through our list and DecorInfos CheckForChanges() + + if (fHasScanned) { + for (int i = fList.CountItems() - 1; i > 0; --i) { + DecorInfo* decorInfo = fList.ItemAt(i); + + bool deleted = false; + decorInfo->CheckForChanges(deleted); + + if (deleted) { + fList.RemoveItem(decorInfo); + delete decorInfo; + } + } + } + + BPath path; + entry_ref ref; + // Now, look at file system, skip the entries for which we already have + // a DecorInfo in the list. + while (dir.GetNextRef(&ref) == B_OK) { + path.SetTo(decorPath.Path()); + path.Append(ref.name); + if (_FindDecor(path.Path()) != NULL) + continue; + + DecorInfo* decorInfo = new(std::nothrow) DecorInfo(ref); + if (decorInfo == NULL || decorInfo->InitCheck() != B_OK) { + fprintf(stderr, "DecorInfoUtility::ScanDecorators()\tInitCheck() " + "failure on decorator, skipping\n"); + delete decorInfo; + continue; + } + + fList.AddItem(decorInfo); + } + + fHasScanned = true; + + return B_OK; +} + + +int32 +DecorInfoUtility::CountDecorators() +{ + BAutolock _(fLock); + if (!fHasScanned) + ScanDecorators(); + + return fList.CountItems(); +} + + +DecorInfo* +DecorInfoUtility::DecoratorAt(int32 index) +{ + BAutolock _(fLock); + return fList.ItemAt(index); +} + + +DecorInfo* +DecorInfoUtility::FindDecorator(const BString& string) +{ + if (string.Length() == 0) + return CurrentDecorator(); + + if (string.ICompare("default") == 0) + return DefaultDecorator(); + + BAutolock _(fLock); + if (!fHasScanned) + ScanDecorators(); + + // search by path + DecorInfo* decor = _FindDecor(string); + if (decor != NULL) + return decor; + + // search by cached name + for (int i = 1; i < fList.CountItems(); ++i) { + decor = fList.ItemAt(i); + if (string.ICompare(decor->Name()) == 0) + return decor; + } + + return NULL; +} + + +DecorInfo* +DecorInfoUtility::CurrentDecorator() +{ + BAutolock _(fLock); + if (!fHasScanned) + ScanDecorators(); + + BString name; + get_decorator(name); + return FindDecorator(name); +} + + +DecorInfo* +DecorInfoUtility::DefaultDecorator() +{ + BAutolock _(fLock); + return fList.ItemAt(0); +} + + +bool +DecorInfoUtility::IsCurrentDecorator(DecorInfo* decor) +{ + BAutolock _(fLock); + if (decor == NULL) + return false; + return decor->Path() == CurrentDecorator()->Path(); +} + + +status_t +DecorInfoUtility::SetDecorator(DecorInfo* decor) +{ + if (decor == NULL) + return B_BAD_VALUE; + + BAutolock _(fLock); + if (decor->IsDefault()) + return set_decorator("Default"); + + return set_decorator(decor->Path()); +} + + +status_t +DecorInfoUtility::SetDecorator(int32 index) +{ + BAutolock _(fLock); + if (!fHasScanned) + return B_ERROR; + + DecorInfo* decor = DecoratorAt(index); + if (decor == NULL) + return B_BAD_INDEX; + + return SetDecorator(decor); +} + + +status_t +DecorInfoUtility::Preview(DecorInfo* decor, BWindow* window) +{ + if (decor == NULL) + return B_BAD_VALUE; + + return preview_decorator(decor->Path(), window); +} + + +// #pargma mark - private + + +DecorInfo* +DecorInfoUtility::_FindDecor(const BString& pathString) +{ + // find decor by path and path alone! + if (!fLock.IsLocked()) { + fprintf(stderr, "DecorInfoUtility::_find_decor()\tfailure to lock! - " + "BUG BUG BUG\n"); + return NULL; + } + + if (pathString == "Default") + return fList.ItemAt(0); + + for (int i = 1; i < fList.CountItems(); ++i) { + DecorInfo* decor = fList.ItemAt(i); + // Find the DecoratorInfo either by its true current location or by + // what we still think the location is (before we had a chance to + // update). NOTE: This will only catch the case when the user moved the + // folder in which the add-on file lives. It will not work when the user + // moves the add-on file itself or renames it. + BPath path(decor->Ref()); + if (path.Path() == pathString || decor->Path() == pathString) + return decor; + } + + return NULL; +} diff --git a/src/kits/interface/InterfaceDefs.cpp b/src/kits/interface/InterfaceDefs.cpp index 9b8f8db00a..ed61c2f5e5 100644 --- a/src/kits/interface/InterfaceDefs.cpp +++ b/src/kits/interface/InterfaceDefs.cpp @@ -32,10 +32,12 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -1185,129 +1187,66 @@ _fini_interface_kit_() } -// #pragma mark - - - -/*! \brief private function used by Deskbar to set window decor - Note, we don't have to be compatible here, and could just change - the Deskbar not to use this anymore - \param theme The theme to choose - - - \c 0: BeOS - - \c 1: AmigaOS - - \c 2: Win95 - - \c 3: MacOS -*/ -void -__set_window_decor(int32 theme) -{ - BPrivate::AppServerLink link; - link.StartMessage(AS_R5_SET_DECORATOR); - link.Attach(theme); - link.Flush(); -} - namespace BPrivate { -/*! \brief queries the server for the number of available decorators - \return the number of available decorators +/*! \brief queries the server for the current decorator + \param ref entry_ref into which to store current decorator's location + \return boolean true/false */ -int32 -count_decorators(void) -{ - BPrivate::AppServerLink link; - link.StartMessage(AS_COUNT_DECORATORS); - - int32 code; - int32 count = -1; - if (link.FlushWithReply(code) == B_OK && code == B_OK) - link.Read(&count); - - return count; -} - - -/*! \brief queries the server for the index of the current decorators - \return the current decorator's index - - If for some bizarre reason this function fails, it returns -1 -*/ -int32 -get_decorator(void) +bool +get_decorator(BString& path) { BPrivate::AppServerLink link; link.StartMessage(AS_GET_DECORATOR); int32 code; - int32 index = -1; - if (link.FlushWithReply(code) == B_OK && code == B_OK) - link.Read(&index); + if (link.FlushWithReply(code) != B_OK || code != B_OK) + return false; - return index; -} - - -/*! \brief queries the server for the name of the decorator with a certain index - \param index The index of the decorator to get the name for - \param name BString to receive the name of the decorator - \return B_OK if successful, B_ERROR if not -*/ -status_t -get_decorator_name(const int32 &index, BString &name) -{ - BPrivate::AppServerLink link; - link.StartMessage(AS_GET_DECORATOR_NAME); - link.Attach(index); - - int32 code; - if (link.FlushWithReply(code) == B_OK && code == B_OK) { - char *string; - if (link.ReadString(&string) == B_OK) { - name = string; - free(string); - return B_OK; - } - } - - return B_ERROR; -} - - -/*! \brief asks the server to draw a decorator preview into a BBitmap - \param index The index of the decorator to get the name for - \param bitmap BBitmap to receive the preview - \return B_OK if successful, B_ERROR if not. - - This is currently unimplemented. -*/ -status_t -get_decorator_preview(const int32 &index, BBitmap *bitmap) -{ - // TODO: implement get_decorator_preview - return B_ERROR; + return link.ReadString(path) == B_OK; } /*! \brief Private function which sets the window decorator for the system. - \param index Index of the decorator to set + \param entry_ref to the decorator to set - If the index is invalid, this function and the server do nothing + Will return detailed error status via status_t */ status_t -set_decorator(const int32 &index) +set_decorator(const BString& path) { - if (index < 0) - return B_BAD_VALUE; - BPrivate::AppServerLink link; link.StartMessage(AS_SET_DECORATOR); - link.Attach(index); + + link.AttachString(path.String()); link.Flush(); - return B_OK; + status_t error = B_OK; + link.Read(&error); + + return error; +} + + +/*! \brief sets a window to preview a given decorator + \param path path to any given decorator add-on + \param window pointer to BWindow which will show decorator + + Piggy-backs on BWindow::SetDecoratorSettings(...) +*/ +status_t +preview_decorator(const BString& path, BWindow* window) +{ + if (window == NULL) + return B_ERROR; + + BMessage msg('prVu'); + msg.AddString("preview", path.String()); + + return window->SetDecoratorSettings(msg); } diff --git a/src/kits/interface/Jamfile b/src/kits/interface/Jamfile index 4545803557..911473a440 100644 --- a/src/kits/interface/Jamfile +++ b/src/kits/interface/Jamfile @@ -49,6 +49,7 @@ MergeObject interface_kit.o : ColorTools.cpp Control.cpp ControlLook.cpp + DecorInfo.cpp Deskbar.cpp Dragger.cpp Font.cpp diff --git a/src/preferences/appearance/APRView.cpp b/src/preferences/appearance/APRView.cpp index 2b3f54606e..bbe2863814 100644 --- a/src/preferences/appearance/APRView.cpp +++ b/src/preferences/appearance/APRView.cpp @@ -20,8 +20,11 @@ #include #include +#include + #include + #include "APRWindow.h" #include "defs.h" #include "ColorWell.h" @@ -35,39 +38,33 @@ #define COLOR_DROPPED 'cldp' #define DECORATOR_CHANGED 'dcch' -namespace BPrivate -{ - int32 count_decorators(void); - status_t set_decorator(const int32 &index); - int32 get_decorator(void); - status_t get_decorator_name(const int32 &index, BString &name); - status_t get_decorator_preview(const int32 &index, BBitmap *bitmap); -} -APRView::APRView(const char *name, uint32 flags) - : BView(name, flags), +APRView::APRView(const char* name, uint32 flags) + : + BView(name, flags), fDefaultSet(ColorSet::DefaultColorSet()), - fDecorMenu(NULL) + fDecorMenu(NULL), + fDecorUtil(new DecorInfoUtility(false)) { SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); #if 0 fDecorMenu = new BMenu("Window Style"); - int32 decorCount = BPrivate::count_decorators(); + int32 decorCount = fDecorUtil->CountDecorators(); + DecorInfo* decor = NULL; if (decorCount > 1) { for (int32 i = 0; i < decorCount; i++) { - BString name; - BPrivate::get_decorator_name(i, name); - if (name.CountChars() < 1) + decor = fDecorUtil->GetDecorator(i); + if (!decor) continue; - fDecorMenu->AddItem(new BMenuItem(name.String(), + fDecorMenu->AddItem(new BMenuItem(decor->Name().String(), new BMessage(DECORATOR_CHANGED))); } - BMenuField *field = new BMenuField("Window Style", fDecorMenu); + BMenuField* field = new BMenuField("Window Style", fDecorMenu); // TODO: use this menu field. } - BMenuItem *marked = fDecorMenu->ItemAt(BPrivate::get_decorator()); + BMenuItem* marked = fDecorMenu->ItemAt(fDecorUtil->IndexOfCurrentDecorator()); if (marked) marked->SetMarked(true); else { @@ -156,7 +153,7 @@ APRView::MessageReceived(BMessage *msg) int32 index = fDecorMenu->IndexOf(fDecorMenu->FindMarked()); #ifdef HAIKU_TARGET_PLATFORM_HAIKU if (index >= 0) - BPrivate::set_decorator(index); + fDecorUtil->SetDecorator(index); #endif break; } @@ -207,7 +204,7 @@ APRView::MessageReceived(BMessage *msg) if (item) { item->SetMarked(true); #ifdef HAIKU_TARGET_PLATFORM_HAIKU - BPrivate::set_decorator(fDecorMenu->IndexOf(item)); + fDecorUtil->SetDecorator(fDecorMenu->IndexOf(item)); #endif } } diff --git a/src/preferences/appearance/APRView.h b/src/preferences/appearance/APRView.h index fbc75ee6f6..e51ed2db1f 100644 --- a/src/preferences/appearance/APRView.h +++ b/src/preferences/appearance/APRView.h @@ -28,6 +28,7 @@ #include "ColorSet.h" class ColorWell; +class DecorInfoUtility; class APRWindow; class APRView : public BView @@ -62,6 +63,7 @@ protected: ColorSet fDefaultSet; BMenu *fDecorMenu; + DecorInfoUtility*fDecorUtil; }; #endif diff --git a/src/servers/app/DecorManager.cpp b/src/servers/app/DecorManager.cpp index 10c621d2cb..9b53e060e0 100644 --- a/src/servers/app/DecorManager.cpp +++ b/src/servers/app/DecorManager.cpp @@ -1,10 +1,11 @@ /* - * Copyright (c) 2001-2010, Haiku, Inc. + * Copyright (c) 2001-2011, Haiku, Inc. * Distributed under the terms of the MIT license. * * Author: * DarkWyrm * Clemens Zeidler + * Joseph Groover */ #include "DecorManager.h" @@ -44,7 +45,6 @@ DecorAddOn::DecorAddOn(image_id id, const char* name) DecorAddOn::~DecorAddOn() { - } @@ -70,6 +70,7 @@ DecorAddOn::AllocateDecorator(Desktop* desktop, DrawingEngine* engine, if (!decorator) return NULL; + decorator->SetDrawingEngine(engine); decorator->SetTitle(title); @@ -104,87 +105,23 @@ DecorAddOn::_AllocateDecorator(DesktopSettings& settings, BRect rect, DecorManager::DecorManager() : - fDefaultDecorAddOn(-1, "Default"), - fCurrentDecor(NULL) + fDefaultDecor(-1, "Default"), + fCurrentDecor(&fDefaultDecor), + fPreviewDecor(NULL), + fPreviewWindow(NULL), + fCurrentDecorPath("Default") { - // Start with the default decorator - index is always 0 - fDecorList.AddItem(&fDefaultDecorAddOn); - - // Add any on disk - RescanDecorators(); - _LoadSettingsFromDisk(); - - if (!fCurrentDecor) - fCurrentDecor = fDecorList.ItemAt(0L); } DecorManager::~DecorManager() { - _EmptyList(); } -void -DecorManager::RescanDecorators() -{ - BDirectory dir(DECORATORS_DIR); - - if (dir.InitCheck() != B_OK) - return; - - entry_ref ref; - while (dir.GetNextRef(&ref) == B_OK) { - BPath path; - path.SetTo(DECORATORS_DIR); - path.Append(ref.name); - - // Because this function is used for both initialization and for keeping - // the list up to date, check for existence in the list. Note that we - // do not check to see if a decorator has been removed. This is for - // stability. If there is a decorator in memory already whose file has - // been deleted, it is still available until the next boot, at which point - // it will obviously not be loaded. - - if (_FindDecor(ref.name)) - continue; - - image_id image = load_add_on(path.Path()); - if (image < 0) - continue; - - // As of now, we do nothing with decorator versions, but the possibility - // exists that the API will change even though I cannot forsee any reason - // to do so. If we *did* do anything with decorator versions, the - // assignment would go here. - - create_decor_addon* createFunc; - - // Get the instantiation function - 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! - if (!addon || addon->InitCheck() != B_OK - || !fDecorList.AddItem(addon)) { - unload_add_on(image); - delete addon; - continue; - } - } -} - - -Decorator * -DecorManager::AllocateDecorator(Desktop* desktop, DrawingEngine* engine, - BRect rect, const char* title, window_look look, uint32 flags) +Decorator* +DecorManager::AllocateDecorator(Window* window) { // Create a new instance of the current decorator. // Ownership is that of the caller @@ -195,8 +132,20 @@ DecorManager::AllocateDecorator(Desktop* desktop, DrawingEngine* engine, return NULL; } - return fCurrentDecor->AllocateDecorator(desktop, engine, rect, title, - look, flags); + // Are we previewing a specific decorator? + 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()); } @@ -213,6 +162,63 @@ DecorManager::AllocateWindowBehaviour(Window* window) } +void +DecorManager::CleanupForWindow(Window* window) +{ + // Given window is being deleted, do any cleanup needed + 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){ + // Reset other window to current decorator - only one can preview + Window* oldPreviewWindow = fPreviewWindow; + fPreviewWindow = NULL; + oldPreviewWindow->ReloadDecor(); + } + + if (window == NULL) + return B_BAD_VALUE; + + // We have to jump some hoops because the window must be able to + // delete its decorator before we unload the add-on + 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; + // After this call, the window has deleted its decorator. + 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() { @@ -220,100 +226,87 @@ DecorManager::GetDesktopListeners() } -int32 -DecorManager::CountDecorators() const -{ - return fDecorList.CountItems(); -} - - -int32 -DecorManager::GetDecorator() const -{ - return fDecorList.IndexOf(fCurrentDecor); -} - - -bool -DecorManager::SetDecorator(int32 index, Desktop* desktop) -{ - DecorAddOn* newDecor = fDecorList.ItemAt(index); - - if (newDecor) { - fCurrentDecor = newDecor; - desktop->ReloadDecor(); - _SaveSettingsToDisk(); - return true; - } - - return false; -} - - -bool -DecorManager::SetR5Decorator(int32 value) -{ - BString string; - - switch (value) { - case 0: string = "BeOS"; break; - case 1: string = "AmigaOS"; break; - case 2: string = "Windows"; break; - case 3: string = "MacOS"; break; - default: - return false; - } - - DecorAddOn *newDecor = _FindDecor(string); - if (newDecor) { - fCurrentDecor = newDecor; - return true; - } - - return false; -} - - BString -DecorManager::GetDecoratorName(int32 index) +DecorManager::GetCurrentDecorator() const { - DecorAddOn *decor = fDecorList.ItemAt(index); - if (decor) - return decor->Name(); - - return BString(""); + return fCurrentDecorPath.String(); } -void -DecorManager::_EmptyList() +status_t +DecorManager::SetDecorator(BString path, Desktop* desktop) { - for (int32 i = 1; i < fDecorList.CountItems(); i++) { - unload_add_on(fDecorList.ItemAt(i)->ImageID()); - delete fDecorList.ItemAt(i); + 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()) { + // now safe to unload all old decorator data + // saves us from deleting oldDecor... + unload_add_on(oldImage); + _SaveSettingsToDisk(); + return B_OK; } - fDecorList.MakeEmpty(); - fDecorList.AddItem(&fDefaultDecorAddOn); + // TODO: unloading the newDecor and its image + // problem is we don't know how many windows failed... or why they failed... + syslog(LOG_WARNING, + "app_server:DecorManager:SetDecorator:\"%s\" *partly* failed\n", + fCurrentDecorPath.String()); - fCurrentDecor = &fDefaultDecorAddOn; + fCurrentDecor = oldDecor; + fCurrentDecorPath = oldPath; + return B_ERROR; } DecorAddOn* -DecorManager::_FindDecor(BString name) +DecorManager::_LoadDecor(BString _path, status_t& error ) { - if (!name) - return NULL; - - for (int32 i = 0; i < fDecorList.CountItems(); i++) { - DecorAddOn* decor = fDecorList.ItemAt(i); - - if (decor->Name() == name) - return decor; + if (_path == "Default") { + error = B_OK; + return &fDefaultDecor; } - return NULL; + 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; } @@ -338,12 +331,15 @@ DecorManager::_LoadSettingsFromDisk() BMessage settings; if (settings.Unflatten(&file) == B_OK) { - BString itemtext; - if (settings.FindString("decorator", &itemtext) == B_OK) { - DecorAddOn* decor = _FindDecor(itemtext); - if (decor) { + BString itemPath; + if (settings.FindString("decorator", &itemPath) == B_OK) { + status_t error = B_OK; + DecorAddOn* decor = _LoadDecor(itemPath, error); + if (decor != NULL) { fCurrentDecor = decor; return true; + } else { + //TODO: do something with the reported error } } } @@ -371,7 +367,7 @@ DecorManager::_SaveSettingsToDisk() return false; BMessage settings; - if (settings.AddString("decorator", fCurrentDecor->Name()) != B_OK) + if (settings.AddString("decorator", fCurrentDecorPath.String()) != B_OK) return false; if (settings.Flatten(&file) != B_OK) return false; diff --git a/src/servers/app/DecorManager.h b/src/servers/app/DecorManager.h index 15dc6c1e4a..92feeb084d 100644 --- a/src/servers/app/DecorManager.h +++ b/src/servers/app/DecorManager.h @@ -14,10 +14,11 @@ #include #include #include +#include +#include #include "Decorator.h" -class DecorInfo; class Desktop; class DesktopListener; class DrawingEngine; @@ -28,6 +29,9 @@ class WindowBehaviour; typedef BObjectList DesktopListenerList; +// special name to test for use of non-fs-tied default decorator +// this just keeps things clean and simple is all + class DecorAddOn { public: DecorAddOn(image_id id, const char* name); @@ -35,68 +39,57 @@ public: virtual status_t InitCheck() const; - image_id ImageID() const { return fImageID; } - BString Name() const { return fName; } + image_id ImageID() const { return fImageID; } - Decorator* AllocateDecorator(Desktop* desktop, + 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 WindowBehaviour* AllocateWindowBehaviour(Window* window); - virtual const DesktopListenerList& GetDesktopListeners(); + virtual const DesktopListenerList& GetDesktopListeners(); protected: virtual Decorator* _AllocateDecorator(DesktopSettings& settings, BRect rect, window_look look, uint32 flags); - DesktopListenerList fDesktopListeners; + DesktopListenerList fDesktopListeners; private: - image_id fImageID; - BString fName; + image_id fImageID; + BString fName; }; -class DecorManager -{ +class DecorManager { public: - DecorManager(); - ~DecorManager(); + DecorManager(); + ~DecorManager(); - void RescanDecorators(); + Decorator* AllocateDecorator(Window *window); + WindowBehaviour* AllocateWindowBehaviour(Window *window); + void CleanupForWindow(Window *window); - Decorator* AllocateDecorator(Desktop* desktop, - DrawingEngine* engine, - BRect rect, - const char* title, window_look look, - uint32 flags); - WindowBehaviour* AllocateWindowBehaviour(Window* window); - const DesktopListenerList& GetDesktopListeners(); + status_t PreviewDecorator(BString path, Window *window); - int32 CountDecorators() const; + const DesktopListenerList& GetDesktopListeners(); - int32 GetDecorator() const; - bool SetDecorator(int32 index, Desktop* desktop); - bool SetR5Decorator(int32 value); - BString GetDecoratorName(int32 index); - - // TODO: Implement this method once the rest of the necessary infrastructure - // is in place - //status_t GetPreview(int32 index, ServerBitmap *bitmap); + BString GetCurrentDecorator() const; + status_t SetDecorator(BString path, Desktop *desktop); private: - void _EmptyList(); - DecorAddOn* _FindDecor(BString name); + DecorAddOn* _LoadDecor(BString path, status_t &error); + bool _LoadSettingsFromDisk(); + bool _SaveSettingsToDisk(); - bool _LoadSettingsFromDisk(); - bool _SaveSettingsToDisk(); +private: + DecorAddOn fDefaultDecor; + DecorAddOn* fCurrentDecor; + DecorAddOn* fPreviewDecor; - BObjectList fDecorList; - DecorAddOn fDefaultDecorAddOn; - DecorAddOn* fCurrentDecor; + Window* fPreviewWindow; + BString fCurrentDecorPath; }; extern DecorManager gDecorManager; diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index ac05af8549..d6a5d28d22 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -17,7 +17,6 @@ #include "Desktop.h" - #include #include #include @@ -2044,11 +2043,13 @@ Desktop::RedrawBackground() } -void +bool Desktop::ReloadDecor() { AutoWriteLocker _(fWindowLock); + bool returnValue = true; + // TODO it is assumed all listeners are registered by one decor // unregister old listeners const DesktopListenerDLList& currentListeners = GetDesktopListenerList(); @@ -2058,16 +2059,19 @@ Desktop::ReloadDecor() for (Window* window = fAllWindows.FirstWindow(); window != NULL; window = window->NextWindow(kAllWindowList)) { - BRegion oldBorder; - window->GetBorderRegion(&oldBorder); + BRegion oldBorder; + window->GetBorderRegion(&oldBorder); - window->ReloadDecor(); + if (!window->ReloadDecor()) { + // prevent unloading previous add-on + returnValue = false; + } - BRegion border; - window->GetBorderRegion(&border); + BRegion border; + window->GetBorderRegion(&border); - border.Include(&oldBorder); - RebuildAndRedrawAfterWindowChange(window, border); + border.Include(&oldBorder); + RebuildAndRedrawAfterWindowChange(window, border); } // register new listeners @@ -2075,6 +2079,8 @@ Desktop::ReloadDecor() = gDecorManager.GetDesktopListeners(); for (int i = 0; i < newListeners.CountItems(); i++) RegisterListener(newListeners.ItemAt(i)); + + return returnValue; } diff --git a/src/servers/app/Desktop.h b/src/servers/app/Desktop.h index e5f4d887c3..388c3f4b1f 100644 --- a/src/servers/app/Desktop.h +++ b/src/servers/app/Desktop.h @@ -221,7 +221,7 @@ public: void Redraw(); void RedrawBackground(); - void ReloadDecor(); + bool ReloadDecor(); BRegion& BackgroundRegion() { return fBackgroundRegion; } diff --git a/src/servers/app/ProfileMessageSupport.cpp b/src/servers/app/ProfileMessageSupport.cpp index 3a6192ff4f..5472f040e5 100644 --- a/src/servers/app/ProfileMessageSupport.cpp +++ b/src/servers/app/ProfileMessageSupport.cpp @@ -162,10 +162,6 @@ string_for_message_code(uint32 code, BString& string) CODE(AS_SET_UI_COLOR); CODE(AS_SET_DECORATOR); CODE(AS_GET_DECORATOR); - case AS_R5_SET_DECORATOR: - string = "AS_R5_SET_DECORATOR"; break; - CODE(AS_COUNT_DECORATORS); - CODE(AS_GET_DECORATOR_NAME); CODE(AS_SET_WORKSPACE_LAYOUT); CODE(AS_GET_WORKSPACE_LAYOUT); diff --git a/src/servers/app/ServerApp.cpp b/src/servers/app/ServerApp.cpp index 65724f31da..c5dce90daa 100644 --- a/src/servers/app/ServerApp.cpp +++ b/src/servers/app/ServerApp.cpp @@ -648,68 +648,29 @@ ServerApp::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link) case AS_SET_DECORATOR: { // Attached Data: - // int32 the index of the decorator to use + // path to decorator add-on - int32 index; - link.Read(&index); - if (gDecorManager.SetDecorator(index, fDesktop)) - fDesktop->BroadcastToAllApps(AS_UPDATE_DECORATOR); - break; - } + BString path; + link.ReadString(path); - case AS_COUNT_DECORATORS: - { - fLink.StartMessage(B_OK); - fLink.Attach(gDecorManager.CountDecorators()); + status_t error = gDecorManager.SetDecorator(path, fDesktop); + + fLink.Attach(error); fLink.Flush(); + + if (error == B_OK) + fDesktop->BroadcastToAllApps(AS_UPDATE_DECORATOR); break; } case AS_GET_DECORATOR: { fLink.StartMessage(B_OK); - fLink.Attach(gDecorManager.GetDecorator()); + fLink.AttachString(gDecorManager.GetCurrentDecorator().String()); fLink.Flush(); break; } - case AS_GET_DECORATOR_NAME: - { - int32 index; - link.Read(&index); - - BString str(gDecorManager.GetDecoratorName(index)); - if (str.CountChars() > 0) { - fLink.StartMessage(B_OK); - fLink.AttachString(str.String()); - } else - fLink.StartMessage(B_ERROR); - - fLink.Flush(); - break; - } - - case AS_R5_SET_DECORATOR: - { - // Sort of supports Tracker's nifty Easter Egg. It was easy to do - // and it's kind of neat, so why not? - - // Attached Data: - // int32 value of the decorator to use - // 0: BeOS - // 1: Amiga - // 2: Windows - // 3: MacOS - - int32 decindex = 0; - link.Read(&decindex); - - if (gDecorManager.SetR5Decorator(decindex)) - fDesktop->BroadcastToAllApps(AS_UPDATE_DECORATOR); - - break; - } - case AS_CREATE_BITMAP: { STRACE(("ServerApp %s: Received BBitmap creation request\n", diff --git a/src/servers/app/Window.cpp b/src/servers/app/Window.cpp index 40b3639ce1..dd57406573 100644 --- a/src/servers/app/Window.cpp +++ b/src/servers/app/Window.cpp @@ -129,8 +129,7 @@ Window::Window(const BRect& frame, const char *name, SetFlags(flags, NULL); if (fLook != B_NO_BORDER_WINDOW_LOOK) { - fDecorator = gDecorManager.AllocateDecorator(fDesktop, fDrawingEngine, - frame, name, fLook, fFlags); + fDecorator = gDecorManager.AllocateDecorator(this); if (fDecorator) { fDecorator->GetSizeLimits(&fMinWidth, &fMinHeight, &fMaxWidth, &fMaxHeight); @@ -172,8 +171,9 @@ Window::~Window() delete fWindowBehaviour; delete fDecorator; - delete fDrawingEngine; + + gDecorManager.CleanupForWindow(this); } @@ -549,18 +549,18 @@ Window::ReloadDecor() ::Decorator* decorator = NULL; WindowBehaviour* windowBehaviour = NULL; + if (fLook != B_NO_BORDER_WINDOW_LOOK) { // we need a new decorator - decorator = gDecorManager.AllocateDecorator(fDesktop, fDrawingEngine, - Frame(), Title(), fLook, fFlags); - if (!decorator) + decorator = gDecorManager.AllocateDecorator(this); + if (decorator == NULL) return false; if (IsFocus()) decorator->SetFocus(true); } windowBehaviour = gDecorManager.AllocateWindowBehaviour(this); - if (!windowBehaviour) { + if (windowBehaviour == NULL) { delete decorator; return false; } @@ -1108,6 +1108,14 @@ Window::TabLocation() const bool Window::SetDecoratorSettings(const BMessage& settings, BRegion& dirty) { + if (settings.what == 'prVu') { + // 'prVu' == preview a decorator! + BString path; + if (settings.FindString("preview", &path) == B_OK) + return gDecorManager.PreviewDecorator(path, this) == B_OK; + return false; + } + if (fDecorator) return fDecorator->SetSettings(settings, &dirty); return false; @@ -1142,8 +1150,7 @@ Window::SetLook(window_look look, BRegion* updateRegion) { if (fDecorator == NULL && look != B_NO_BORDER_WINDOW_LOOK) { // we need a new decorator - fDecorator = gDecorManager.AllocateDecorator(fDesktop, fDrawingEngine, - Frame(), Title(), fLook, fFlags); + fDecorator = gDecorManager.AllocateDecorator(this); if (IsFocus()) fDecorator->SetFocus(true); } diff --git a/src/servers/app/Window.h b/src/servers/app/Window.h index 7b62336c04..749ba086a4 100644 --- a/src/servers/app/Window.h +++ b/src/servers/app/Window.h @@ -375,6 +375,8 @@ protected: int32 fMaxHeight; int32 fWorkspacesViewCount; + + friend class DecorManager; }; #endif // WINDOW_H