diff --git a/headers/os/app/Application.h b/headers/os/app/Application.h index a9263efd7d..105073e6c0 100644 --- a/headers/os/app/Application.h +++ b/headers/os/app/Application.h @@ -29,6 +29,10 @@ namespace BPrivate { } +void restore_window_geometry(BWindow* window, const BMessage* windowGeometry); +void save_window_geometry(const BWindow* window, BMessage* windowGeometry); + + class BApplication : public BLooper { public: BApplication(const char* signature); @@ -91,6 +95,12 @@ public: class Private; +protected: + // Session Manager + bool HasBeenRestored(); + virtual status_t RestoreState(const BMessage* state); + virtual status_t SaveState(BMessage* state) const; + private: typedef BLooper _inherited; @@ -145,8 +155,9 @@ private: BMessageRunner* fPulseRunner; status_t fInitError; void* fServerReadOnlyMemory; - uint32 _reserved[12]; + uint32 _reserved[11]; + uint32 fHasBeenRestored; bool fReadyToRunCalled; }; diff --git a/headers/private/app/ApplicationPrivate.h b/headers/private/app/ApplicationPrivate.h index bfd6a56d95..bea2498ae8 100644 --- a/headers/private/app/ApplicationPrivate.h +++ b/headers/private/app/ApplicationPrivate.h @@ -14,6 +14,10 @@ struct server_read_only_memory; +const uint32 kRestoreStateMsg = '_RSM'; +const uint32 kSaveStateMsg = '_SSM'; + + class BApplication::Private { public: static inline BPrivate::PortLink *ServerLink() diff --git a/src/kits/app/Application.cpp b/src/kits/app/Application.cpp index dc40511c97..350b82d902 100644 --- a/src/kits/app/Application.cpp +++ b/src/kits/app/Application.cpp @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include @@ -48,6 +50,46 @@ using namespace BPrivate; +void +restore_window_geometry(BWindow* window, const BMessage* windowGeometry) +{ + BRect frame; + status_t status = windowGeometry->FindRect("frame", &frame); + if (status == B_OK) { + // make sure window is on the screen + BScreen screen; + BRect screenFrame = screen.Frame(); + if (screenFrame.right < frame.left || screenFrame.bottom < frame.top) + frame.OffsetBy(-frame.top, -frame.left); + + window->MoveTo(frame.LeftTop()); + window->ResizeTo(frame.Width(), frame.Height()); + } + + uint32 workspaces; + status = windowGeometry->FindInt32("workspaces", (int32*)&workspaces); + if (status == B_OK) + window->SetWorkspaces(workspaces); + + BMessage decoratroSettings; + status = windowGeometry->FindMessage("decorator_settings", + &decoratroSettings); + if (status == B_OK) + window->SetDecoratorSettings(decoratroSettings); +} + + +void +save_window_geometry(const BWindow* window, BMessage* windowGeometry) +{ + windowGeometry->AddRect("frame", window->Frame()); + windowGeometry->AddInt32("workspaces", window->Workspaces()); + BMessage decoratroSettings; + if (window->GetDecoratorSettings(&decoratroSettings) == B_OK) + windowGeometry->AddMessage("decorator_settings", &decoratroSettings); +} + + BApplication *be_app = NULL; BMessenger be_app_messenger; @@ -274,6 +316,7 @@ BApplication::_InitData(const char *signature, bool initGUI, status_t *_error) fServerAllocator = NULL; fInitialWorkspace = 0; //fDraggedMessage = NULL; + fHasBeenRestored = 0; fReadyToRunCalled = false; // initially, there is no pulse @@ -572,6 +615,8 @@ BApplication::ReadyToRun() // supposed to be implemented by subclasses } +#include "ApplicationPrivate.h" + void BApplication::MessageReceived(BMessage *message) @@ -597,6 +642,19 @@ BApplication::MessageReceived(BMessage *message) be_roster->ActivateApp(Team()); break; + case kRestoreStateMsg: + if (RestoreState(message) == B_OK) + fHasBeenRestored = 1; + break; + + case kSaveStateMsg: + { + BMessage state; + if (SaveState(&state) == B_OK) + message->SendReply(&state); + break; + } + default: BLooper::MessageReceived(message); break; @@ -1028,6 +1086,56 @@ BApplication::Perform(perform_code d, void *arg) } +bool +BApplication::HasBeenRestored() +{ + return fHasBeenRestored != 0; +} + + +status_t +BApplication::RestoreState(const BMessage* state) +{ + int32 i = 0; + while (true) { + BMessage windowState; + if (state->FindMessage("window", i, &windowState) != B_OK) + break; + i++; + + BString title; + if (windowState.FindString("title", &title) != B_OK) + continue; + + for (int i = 0; i < CountWindows(); i++) { + BWindow* window = WindowAt(i); + if (title != window->Title()) + continue; + restore_window_geometry(window, &windowState); + } + } + + return B_OK; +} + + +status_t +BApplication::SaveState(BMessage* state) const +{ + // just store all window positions + for (int i = 0; i < CountWindows(); i++) { + BWindow* window = WindowAt(i); + + BMessage windowState; + save_window_geometry(window, &windowState); + windowState.AddString("title", window->Title()); + state->AddMessage("window", &windowState); + } + + return B_OK; +} + + void BApplication::_ReservedApplication1() {} void BApplication::_ReservedApplication2() {} void BApplication::_ReservedApplication3() {}