diff --git a/src/servers/app/Jamfile b/src/servers/app/Jamfile index 3aee492ca6..7bbd4fc197 100644 --- a/src/servers/app/Jamfile +++ b/src/servers/app/Jamfile @@ -97,6 +97,7 @@ Server app_server : ServerScreen.cpp WinBorder.cpp Workspace.cpp + WorkspacesLayer.cpp ; # link libraries for app_server and libappserver.so diff --git a/src/servers/app/Layer.cpp b/src/servers/app/Layer.cpp index eafebdb5e3..5d3e0e19c1 100644 --- a/src/servers/app/Layer.cpp +++ b/src/servers/app/Layer.cpp @@ -1494,6 +1494,11 @@ return; fParent->Redraw(fRootLayer->fRedrawReg, this); + // redraw workspaces layer + if (dynamic_cast(this) != NULL && fRootLayer->WorkspacesLayer() != NULL) { + fRootLayer->GoRedraw(fRootLayer->WorkspacesLayer(), fRootLayer->WorkspacesLayer()->fVisible); + } + SendViewCoordUpdateMsg(); EmptyGlobals(); @@ -1523,9 +1528,13 @@ return; fDriver->CopyRegionList(&fRootLayer->fCopyRegList, &fRootLayer->fCopyList, fRootLayer->fCopyRegList.CountItems(), &fFullVisible); - fParent->Redraw(fRootLayer->fRedrawReg, this); + // redraw workspaces layer + if (dynamic_cast(this) != NULL && fRootLayer->WorkspacesLayer() != NULL) { + fRootLayer->GoRedraw(fRootLayer->WorkspacesLayer(), fRootLayer->WorkspacesLayer()->fVisible); + } + SendViewCoordUpdateMsg(); EmptyGlobals(); diff --git a/src/servers/app/RootLayer.cpp b/src/servers/app/RootLayer.cpp index 060701e300..e5ca708798 100644 --- a/src/servers/app/RootLayer.cpp +++ b/src/servers/app/RootLayer.cpp @@ -48,6 +48,7 @@ #include "ServerWindow.h" #include "WinBorder.h" #include "Workspace.h" +#include "WorkspacesLayer.h" #include "RootLayer.h" @@ -105,6 +106,7 @@ RootLayer::RootLayer(const char *name, int32 workspaceCount, fActiveWksIndex(0), fWsCount(0), fWorkspace(new Workspace*[kMaxWorkspaceCount]), + fWorkspacesLayer(NULL), fWinBorderListLength(64), fWinBorderList2((WinBorder**)malloc(fWinBorderListLength * sizeof(WinBorder*))), @@ -696,6 +698,7 @@ bool RootLayer::SetActiveWorkspace(int32 index) for (int32 i = 0; i < ptrCount; i++) { if (ptrWin[i]->Workspaces() & (0x00000001UL << index)) { fWorkspace[index]->AddWinBorder(ptrWin[i]); + if (!ptrWin[i]->IsHidden()) fWorkspace[index]->ShowWinBorder(ptrWin[i]); } @@ -782,6 +785,9 @@ bool RootLayer::SetActiveWorkspace(int32 index) fHaveWinBorderList = true; get_workspace_windows(); + if (WorkspacesLayer() != NULL) + GoRedraw(WorkspacesLayer(), WorkspacesLayer()->fVisible); + // send the workspace changed message for the new workspace { BMessage activatedMsg(B_WORKSPACE_ACTIVATED); @@ -1980,8 +1986,12 @@ RootLayer::show_winBorder(WinBorder *winBorder) invalid = fWorkspace[i]->ShowWinBorder(winBorder); } - if (fActiveWksIndex == i) + if (fActiveWksIndex == i) { invalidate = invalid; + + if (dynamic_cast(winBorder->TopChild()) != NULL) + SetWorkspacesLayer(winBorder->TopChild()); + } } if (invalidate) @@ -2004,8 +2014,12 @@ void RootLayer::hide_winBorder(WinBorder *winBorder) if (fWorkspace[i] && fWorkspace[i]->HasWinBorder(winBorder)) invalid = fWorkspace[i]->HideWinBorder(winBorder); - if (fActiveWksIndex == i) + if (fActiveWksIndex == i) { invalidate = invalid; + + if (dynamic_cast(winBorder->TopChild()) != NULL) + SetWorkspacesLayer(NULL); + } } if (invalidate) @@ -2070,11 +2084,19 @@ bool RootLayer::get_workspace_windows() fWinBorderList = (WinBorder**)realloc(fWinBorderList, fWinBorderListLength); ActiveWorkspace()->GetWinBorderList((void**)fWinBorderList, &bufferSize); } - - fWinBorderCount = bufferSize; + fWinBorderCount = bufferSize; fWinBorderIndex = 0; + // activate any workspaces layer in the current list + + SetWorkspacesLayer(NULL); + + for (int32 i = 0; i < fWinBorderCount; i++) { + if (dynamic_cast(fWinBorderList[i]->TopChild()) != NULL) + SetWorkspacesLayer(fWinBorderList[i]->TopChild()); + } + // to determine if there was a change in window hierarchy if (exCount != fWinBorderCount || memcmp(fWinBorderList, fWinBorderList2, fWinBorderCount) != 0) aChange = true; diff --git a/src/servers/app/RootLayer.h b/src/servers/app/RootLayer.h index c027136b9e..b9630b3252 100644 --- a/src/servers/app/RootLayer.h +++ b/src/servers/app/RootLayer.h @@ -49,7 +49,7 @@ namespace BPrivate { }; #ifndef DISPLAY_HAIKU_LOGO -#define DISPLAY_HAIKU_LOGO 1 +# define DISPLAY_HAIKU_LOGO 1 #endif #if DISPLAY_HAIKU_LOGO @@ -106,6 +106,9 @@ public: void ReadWorkspaceData(const char *path); void SaveWorkspaceData(const char *path); + + void SetWorkspacesLayer(Layer* layer) { fWorkspacesLayer = layer; } + Layer* WorkspacesLayer() const { return fWorkspacesLayer; } void SetScreens(Screen *screen[], int32 rows, int32 columns); Screen** Screens(void); @@ -212,6 +215,7 @@ friend class Desktop; int32 fActiveWksIndex; int32 fWsCount; Workspace** fWorkspace; + Layer* fWorkspacesLayer; int32 fWinBorderListLength; WinBorder** fWinBorderList2; diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 4f4f2f2c3e..7b271d17cf 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -38,6 +38,7 @@ #include "Utils.h" #include "WinBorder.h" #include "Workspace.h" +#include "WorkspacesLayer.h" #include "ServerWindow.h" @@ -372,8 +373,17 @@ ServerWindow::CreateLayerTree(BPrivate::LinkReceiver &link, Layer **_parent) STRACE(("ServerWindow(%s)::CreateLayerTree()-> layer %s, token %ld\n", fTitle, name, token)); - Layer *newLayer = new Layer(frame, name, token, resizeMask, + Layer *newLayer; + + if (link.Code() == AS_LAYER_CREATE_ROOT + && (fWinBorder->WindowFlags() & 0x00008000) != 0) { + // this is a workspaces window! + newLayer = new WorkspacesLayer(frame, name, token, resizeMask, flags, gDesktop->GetDisplayDriver()); + } else { + newLayer = new Layer(frame, name, token, resizeMask, + flags, gDesktop->GetDisplayDriver()); + } free(name); diff --git a/src/servers/app/WorkspacesLayer.cpp b/src/servers/app/WorkspacesLayer.cpp new file mode 100644 index 0000000000..6f8b06ee31 --- /dev/null +++ b/src/servers/app/WorkspacesLayer.cpp @@ -0,0 +1,204 @@ +/* + * Copyright 2005, Haiku Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ + + +#include "WorkspacesLayer.h" +#include "Workspace.h" +#include "RootLayer.h" +#include "DisplayDriver.h" +#include "AppServer.h" +#include "WinBorder.h" + +#include + + +WorkspacesLayer::WorkspacesLayer(BRect frame, const char* name, + int32 token, uint32 resizeMode, uint32 flags, DisplayDriver* driver) + : Layer(frame, name, token, resizeMode, flags, driver) +{ +} + + +WorkspacesLayer::~WorkspacesLayer() +{ +} + + +void +WorkspacesLayer::_GetGrid(int32& columns, int32& rows) +{ + int32 count = GetRootLayer()->WorkspaceCount(); + + rows = 1; + for (int32 i = 2; i < count; i++) { + if (count % i == 0) + rows = i; + } + + columns = count / rows; +} + + +BRect +WorkspacesLayer::_WorkspaceAt(int32 i) +{ + int32 columns, rows; + _GetGrid(columns, rows); + + int32 width = fFrame.IntegerWidth() / columns; + int32 height = fFrame.IntegerHeight() / rows; + + int32 column = i % columns; + int32 row = i / columns; + + BRect rect(column * width, row * height, (column + 1) * width, (row + 1) * height); + + // make sure there is no gap anywhere + if (column == columns - 1) + rect.right = fFrame.right; + if (row == rows - 1) + rect.bottom = fFrame.bottom; + + rect.OffsetBy(ConvertToTop(BPoint(0, 0))); + return rect; +} + + +BRect +WorkspacesLayer::_WindowFrame(const BRect& workspaceFrame, + const BRect& screenFrame, const BRect& windowFrame) +{ + BRect frame = windowFrame; + + float factor = workspaceFrame.Width() / screenFrame.Width(); + frame.left *= factor; + frame.right *= factor; + + factor = workspaceFrame.Height() / screenFrame.Height(); + frame.top *= factor; + frame.bottom *= factor; + + frame.OffsetBy(workspaceFrame.LeftTop()); + return frame; +} + + +void +WorkspacesLayer::_DrawWindow(const BRect& workspaceFrame, + const BRect& screenFrame, WinBorder* window) +{ + BRect frame = _WindowFrame(workspaceFrame, screenFrame, window->Frame()); + BRect tabFrame = _WindowFrame(workspaceFrame, screenFrame, + window->GetDecorator()->GetTabRect()); + + // ToDo: let decorator do this! + RGBColor yellow = window->GetDecorator()->GetColors().window_tab; + + fDriver->StrokeLine(BPoint(tabFrame.left, frame.top - 1), + BPoint(tabFrame.right, frame.top - 1), yellow); + + RGBColor gray(180, 180, 180); + fDriver->StrokeRect(frame, gray); + + RGBColor white(255, 255, 255); + frame.InsetBy(1, 1); + fDriver->FillRect(frame, white); +} + + +void +WorkspacesLayer::_DrawWorkspace(int32 index) +{ + BRect rect = _WorkspaceAt(index); + + Workspace* workspace = GetRootLayer()->WorkspaceAt(index); + if (workspace == GetRootLayer()->ActiveWorkspace()) { + // draw active frame + RGBColor black(0, 0, 0); + fDriver->StrokeRect(rect, black); + } + + // draw background + + rect.InsetBy(1, 1); + RGBColor color; + + // ToDo: fix me - workspaces must always exist, not only on first visit! + if (workspace != NULL) + color = workspace->BGColor(); + else + color.SetColor(51, 102, 152); + + fDriver->FillRect(rect, color); + + if (workspace == NULL) + return; + + // draw windows + + WinBorder* windows[256]; + int32 count = 256; + if (!workspace->GetWinBorderList((void **)&windows, &count)) + return; + + uint16 width, height; + uint32 colorSpace; + float frequency; + gDesktop->ScreenAt(0)->GetMode(width, height, colorSpace, frequency); + + BRect screenFrame(0, 0, width - 1, height - 1); + + for (int32 i = count; i-- > 0;) { + _DrawWindow(rect, screenFrame, windows[i]); + } +} + + +void +WorkspacesLayer::Draw(const BRect& updateRect) +{ + // ToDo: either draw into an off-screen bitmap, or turn off flickering... + + int32 columns, rows; + _GetGrid(columns, rows); + + // draw grid + // horizontal lines + + BRect frame = fFrame; + frame.OffsetBy(ConvertToTop(BPoint(0, 0))); + + fDriver->StrokeLine(BPoint(frame.left, frame.top), + BPoint(frame.right, frame.top), ViewColor()); + + for (int32 row = 0; row < rows; row++) { + BRect rect = _WorkspaceAt(row * columns); + fDriver->StrokeLine(BPoint(frame.left, rect.bottom), + BPoint(frame.right, rect.bottom), ViewColor()); + } + + // vertical lines + + fDriver->StrokeLine(BPoint(frame.left, frame.top), + BPoint(frame.left, frame.bottom), ViewColor()); + + for (int32 column = 0; column < columns; column++) { + BRect rect = _WorkspaceAt(column); + fDriver->StrokeLine(BPoint(rect.right, frame.top), + BPoint(rect.right, frame.bottom), ViewColor()); + } + + // draw workspaces + + int32 count = GetRootLayer()->WorkspaceCount(); + + for (int32 i = 0; i < count; i++) { + _DrawWorkspace(i); + } +} + diff --git a/src/servers/app/WorkspacesLayer.h b/src/servers/app/WorkspacesLayer.h new file mode 100644 index 0000000000..d5e5dcd73b --- /dev/null +++ b/src/servers/app/WorkspacesLayer.h @@ -0,0 +1,36 @@ +/* + * Copyright 2005, Haiku Inc. + * Distributed under the terms of the MIT License. + * + * Authors: + * Axel Dörfler, axeld@pinc-software.de + */ +#ifndef WORKSPACES_LAYER_H +#define WORKSPACES_LAYER_H + + +#include "Layer.h" + +class WinBorder; + + +class WorkspacesLayer : public Layer { + public: + WorkspacesLayer(BRect frame, const char* name, int32 token, + uint32 resize, uint32 flags, DisplayDriver* driver); + virtual ~WorkspacesLayer(); + + virtual void Draw(const BRect& updateRect); + + private: + void _GetGrid(int32& columns, int32& rows); + BRect _WorkspaceAt(int32 i); + BRect _WindowFrame(const BRect& workspaceFrame, + const BRect& screenFrame, const BRect& windowFrame); + + void _DrawWindow(const BRect& workspaceFrame, + const BRect& screenFrame, WinBorder* window); + void _DrawWorkspace(int32 index); +}; + +#endif // WORKSPACES_LAYER_H