* Implemented moving windows around via the Workspaces app. However, you

can't move them to another workspace, and you currently don't see a
  window moving that is not in the current workspace. (this fixes bug #135)
* Desktop::SetWindowBehind() didn't update the WorkspacesLayer.
* Changed Desktop::MoveWindowBy() to be able to move window on any workspace.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16776 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-03-13 22:05:49 +00:00
parent 604390bbb5
commit 14fe11cfae
7 changed files with 286 additions and 36 deletions

View File

@ -1205,7 +1205,7 @@ Desktop::SendWindowBehind(WindowLayer* window, WindowLayer* behindOf)
_UpdateFronts();
SetFocusWindow(FrontWindow());
//_WindowsChanged();
_WindowChanged(window);
UnlockAllWindows();
}
@ -1282,6 +1282,9 @@ Desktop::HideWindow(WindowLayer* window)
SetFocusWindow(FrontWindow());
}
if (fWorkspacesLayer != NULL)
fWorkspacesLayer->WindowRemoved(window);
if (dynamic_cast<WorkspacesLayer*>(window->TopLayer()) != NULL)
fWorkspacesLayer = NULL;
@ -1340,13 +1343,26 @@ Desktop::_HideWindow(WindowLayer* window)
void
Desktop::MoveWindowBy(WindowLayer* window, float x, float y)
Desktop::MoveWindowBy(WindowLayer* window, float x, float y, int32 workspace)
{
if (!LockAllWindows())
return;
if (!window->IsVisible()) {
window->MoveBy(x, y);
if (workspace == -1)
workspace = fCurrentWorkspace;
if (!window->IsVisible() || workspace != fCurrentWorkspace) {
if (workspace != fCurrentWorkspace) {
// move the window on another workspace - this doesn't change it's
// current position
if (window->Anchor(workspace).position == kInvalidWindowPosition)
window->Anchor(workspace).position = window->Frame().LeftTop();
window->Anchor(workspace).position += BPoint(x, y);
_WindowChanged(window);
} else
window->MoveBy(x, y);
UnlockAllWindows();
return;
}

View File

@ -106,7 +106,8 @@ class Desktop : public MessageLooper, public ScreenOwner {
void ShowWindow(WindowLayer* window);
void HideWindow(WindowLayer* window);
void MoveWindowBy(WindowLayer* window, float x, float y);
void MoveWindowBy(WindowLayer* window, float x, float y,
int32 workspace = -1);
void ResizeWindowBy(WindowLayer* window, float x, float y);
void SetWindowWorkspaces(WindowLayer* window,

View File

@ -980,6 +980,27 @@ ViewLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
}
void
ViewLayer::MouseDown(BMessage* message, BPoint where)
{
// empty hook methods
}
void
ViewLayer::MouseUp(BMessage* message, BPoint where)
{
// empty hook methods
}
void
ViewLayer::MouseMoved(BMessage* message, BPoint where)
{
// empty hook methods
}
// #pragma mark -

View File

@ -165,6 +165,10 @@ class ViewLayer {
BRegion* windowContentClipping,
bool deep = false);
virtual void MouseDown(BMessage* message, BPoint where);
virtual void MouseUp(BMessage* message, BPoint where);
virtual void MouseMoved(BMessage* message, BPoint where);
void SetHidden(bool hidden);
bool IsHidden() const;

View File

@ -837,22 +837,18 @@ WindowLayer::MouseDown(BMessage* message, BPoint where, int32* _viewToken)
// fill out view token for the view under the mouse
*_viewToken = view->Token();
// TODO: that's not really a clean solution - maybe move that
// functionality back into the ViewLayer class
if (WorkspacesLayer* layer = dynamic_cast<WorkspacesLayer*>(view))
layer->MouseDown(message, where);
view->MouseDown(message, where);
}
}
}
void
WindowLayer::MouseUp(BMessage* msg, BPoint where, int32* _viewToken)
WindowLayer::MouseUp(BMessage* message, BPoint where, int32* _viewToken)
{
bool invalidate = false;
if (fDecorator) {
click_type action = _ActionFor(msg);
click_type action = _ActionFor(message);
// redraw decorator
BRegion visibleBorder;
@ -893,13 +889,15 @@ WindowLayer::MouseUp(BMessage* msg, BPoint where, int32* _viewToken)
fIsResizing = false;
fIsSlidingTab = false;
if (ViewLayer* view = ViewAt(where))
if (ViewLayer* view = ViewAt(where)) {
*_viewToken = view->Token();
view->MouseUp(message, where);
}
}
void
WindowLayer::MouseMoved(BMessage *msg, BPoint where, int32* _viewToken,
WindowLayer::MouseMoved(BMessage *message, BPoint where, int32* _viewToken,
bool isLatestMouseMoved)
{
ViewLayer* view = ViewAt(where);
@ -931,11 +929,11 @@ WindowLayer::MouseMoved(BMessage *msg, BPoint where, int32* _viewToken,
fDrawingEngine->ConstrainClippingRegion(&visibleBorder);
if (fIsZooming) {
fDecorator->SetZoom(_ActionFor(msg) == DEC_ZOOM);
fDecorator->SetZoom(_ActionFor(message) == DEC_ZOOM);
} else if (fIsClosing) {
fDecorator->SetClose(_ActionFor(msg) == DEC_CLOSE);
fDecorator->SetClose(_ActionFor(message) == DEC_CLOSE);
} else if (fIsMinimizing) {
fDecorator->SetMinimize(_ActionFor(msg) == DEC_MINIMIZE);
fDecorator->SetMinimize(_ActionFor(message) == DEC_MINIMIZE);
}
fDrawingEngine->Unlock();
@ -990,6 +988,8 @@ WindowLayer::MouseMoved(BMessage *msg, BPoint where, int32* _viewToken,
// mouse cursor
if (view != NULL) {
view->MouseMoved(message, where);
// TODO: there is more for real cursor support, ie. if a window is closed,
// new app cursor shouldn't override view cursor, ...
ServerWindow()->App()->SetCurrentCursor(view->Cursor());

View File

@ -1,5 +1,5 @@
/*
* Copyright 2005, Haiku Inc.
* Copyright 2005-2006, Haiku Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -21,8 +21,11 @@
WorkspacesLayer::WorkspacesLayer(BRect frame, const char* name,
int32 token, uint32 resizeMode, uint32 flags)
: ViewLayer(frame, name, token, resizeMode, flags)
int32 token, uint32 resizeMode, uint32 flags)
: ViewLayer(frame, name, token, resizeMode, flags),
fSelectedWindow(NULL),
fSelectedWorkspace(-1),
fHasMoved(false)
{
fDrawState->SetLowColor(RGBColor(255, 255, 255));
fDrawState->SetHighColor(RGBColor(0, 0, 0));
@ -50,6 +53,28 @@ WorkspacesLayer::_GetGrid(int32& columns, int32& rows)
}
/*!
\brief Returns the frame of the screen for the specified workspace.
*/
BRect
WorkspacesLayer::_ScreenFrame(int32 i)
{
// TODO: we don't need the current screen frame, but the one
// from the workspace!
uint16 width, height;
uint32 colorSpace;
float frequency;
Window()->Desktop()->ScreenAt(0)->GetMode(width, height,
colorSpace, frequency);
return BRect(0, 0, width - 1, height - 1);
}
/*!
\brief Returns the frame of the specified workspace within the
workspaces layer.
*/
BRect
WorkspacesLayer::_WorkspaceAt(int32 i)
{
@ -76,6 +101,30 @@ WorkspacesLayer::_WorkspaceAt(int32 i)
}
/*!
\brief Returns the workspace frame and index of the workspace
under \a where.
If, for some reason, there is no workspace located under \where,
an empty rectangle is returned, and \a index is set to -1.
*/
BRect
WorkspacesLayer::_WorkspaceAt(BPoint where, int32& index)
{
int32 columns, rows;
_GetGrid(columns, rows);
for (index = columns * rows; index-- > 0;) {
BRect workspaceFrame = _WorkspaceAt(index);
if (workspaceFrame.Contains(where))
return workspaceFrame;
}
return BRect();
}
BRect
WorkspacesLayer::_WindowFrame(const BRect& workspaceFrame,
const BRect& screenFrame, const BRect& windowFrame,
@ -115,6 +164,8 @@ WorkspacesLayer::_DrawWindow(DrawingEngine* drawingEngine, const BRect& workspac
tabFrame = _WindowFrame(workspaceFrame, screenFrame,
tabFrame, tabFrame.LeftTop() - offset);
if (!workspaceFrame.Intersects(frame) && !workspaceFrame.Intersects(tabFrame))
return;
// ToDo: let decorator do this!
RGBColor yellow;
@ -202,12 +253,7 @@ WorkspacesLayer::_DrawWorkspace(DrawingEngine* drawingEngine,
// ToDo: would be nice to get the real update region here
uint16 width, height;
uint32 colorSpace;
float frequency;
Window()->Desktop()->ScreenAt(0)->GetMode(width, height,
colorSpace, frequency);
BRect screenFrame(0, 0, width - 1, height - 1);
BRect screenFrame = _ScreenFrame(index);
BRegion workspaceRegion(rect);
backgroundRegion.IntersectWith(&workspaceRegion);
@ -295,19 +341,161 @@ WorkspacesLayer::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
void
WorkspacesLayer::MouseDown(BMessage* message, BPoint where)
{
int32 columns, rows;
_GetGrid(columns, rows);
// reset tracking variables
fSelectedWorkspace = -1;
fSelectedWindow = NULL;
fHasMoved = false;
for (int32 i = columns * rows; i-- > 0;) {
BRect rect = _WorkspaceAt(i);
// check if the correct mouse button is pressed
int32 buttons;
if (message->FindInt32("buttons", &buttons) != B_OK
|| (buttons & B_PRIMARY_MOUSE_BUTTON) == 0)
return;
if (rect.Contains(where)) {
Window()->Desktop()->SetWorkspace(i);
break;
int32 index;
BRect workspaceFrame = _WorkspaceAt(where, index);
if (index < 0)
return;
Workspace workspace(*Window()->Desktop(), index);
workspaceFrame.InsetBy(1, 1);
BRect screenFrame = _ScreenFrame(index);
WindowLayer* window;
BPoint leftTop;
while (workspace.GetNextWindow(window, leftTop) == B_OK) {
BRect frame = _WindowFrame(workspaceFrame, screenFrame, window->Frame(),
leftTop);
if (frame.Contains(where) && window->Feel() != kDesktopWindowFeel)
fSelectedWindow = window;
}
// Some special functionality (clicked with modifiers)
int32 modifiers;
if (fSelectedWindow != NULL
&& message->FindInt32("modifiers", &modifiers) == B_OK) {
if ((modifiers & B_CONTROL_KEY) != 0) {
// Activate window if clicked with the control key pressed,
// minimize it if control+shift - this mirrors Deskbar
// shortcuts (when pressing a team menu item).
if ((modifiers & B_SHIFT_KEY) != 0)
fSelectedWindow->ServerWindow()->NotifyMinimize(true);
else
Window()->Desktop()->ActivateWindow(fSelectedWindow);
fSelectedWindow = NULL;
} else if ((modifiers & B_OPTION_KEY) != 0) {
// Also, send window to back if clicked with the option
// key pressed.
Window()->Desktop()->SendWindowBehind(fSelectedWindow);
fSelectedWindow = NULL;
}
}
//ViewLayer::MouseDown(message, where, _viewToken);
// If this window is movable, we keep it selected
if (fSelectedWindow != NULL && (fSelectedWindow->Flags() & B_NOT_MOVABLE) != 0)
fSelectedWindow = NULL;
fSelectedWorkspace = index;
fLastMousePosition = where;
}
void
WorkspacesLayer::MouseUp(BMessage* message, BPoint where)
{
if (!fHasMoved && fSelectedWorkspace >= 0)
Window()->Desktop()->SetWorkspace(fSelectedWorkspace);
fSelectedWindow = NULL;
}
void
WorkspacesLayer::MouseMoved(BMessage* message, BPoint where)
{
if (fSelectedWindow == NULL)
return;
// check if the correct mouse button is pressed
int32 buttons;
if (message->FindInt32("buttons", &buttons) != B_OK
|| (buttons & B_PRIMARY_MOUSE_BUTTON) == 0)
return;
BPoint delta = where - fLastMousePosition;
if (delta.x == 0 && delta.y == 0)
return;
Window()->Desktop()->SetMouseEventWindow(Window());
// don't let us off the mouse
int32 index;
BRect workspaceFrame = _WorkspaceAt(where, index);
workspaceFrame.InsetBy(1, 1);
if (index != fSelectedWorkspace) {
return;
// TODO: the code below doesn't work yet...
#if 0
if (!fSelectedWindow->InWorkspace(index) && fSelectedWindow->IsNormal()) {
// move window to this new workspace
uint32 newWorkspaces = fSelectedWindow->Workspaces()
& ~(1UL << fSelectedWorkspace) | (1UL << index);
Window()->Desktop()->SetWindowWorkspaces(fSelectedWindow,
newWorkspaces);
// move window to the correct location on this new workspace
// (preserve offset to window relative to the mouse)
BRect screenFrame = _ScreenFrame(index);
BPoint leftTop = fSelectedWindow->Anchor(fSelectedWorkspace).position;
BRect windowFrame = _WindowFrame(workspaceFrame, screenFrame,
fSelectedWindow->Frame(), leftTop);
BPoint delta = fLastMousePosition - windowFrame.LeftTop();
delta.x = rintf(delta.x * screenFrame.Width() / workspaceFrame.Width());
delta.y = rintf(delta.y * screenFrame.Height() / workspaceFrame.Height());
printf("delta: %g, %g\n", delta.x, delta.y);
// normalize position
// TODO: take the actual grid position into account!!!
float left = leftTop.x + delta.x;
if (delta.x < 0)
left += screenFrame.Width();
else if (screenFrame.Width() + delta.x > 0)
left -= screenFrame.Width();
float top = leftTop.y + delta.y;
if (delta.y < 0)
top += screenFrame.Height();
else if (delta.y > 0)
top -= screenFrame.Height();
printf("new absolute position: %g, %g\n", left, top);
leftTop = fSelectedWindow->Anchor(index).position;
if (leftTop == kInvalidWindowPosition)
leftTop = fSelectedWindow->Anchor(fSelectedWorkspace).position;
Window()->Desktop()->MoveWindowBy(fSelectedWindow, left - leftTop.x,
top - leftTop.y, index);
}
fSelectedWorkspace = index;
#endif
}
BRect screenFrame = _ScreenFrame(index);
float deltaX = rintf(delta.x * screenFrame.Width() / workspaceFrame.Width());
float deltaY = rintf(delta.y * screenFrame.Height() / workspaceFrame.Height());
fHasMoved = true;
Window()->Desktop()->MoveWindowBy(fSelectedWindow, deltaX, deltaY);
fLastMousePosition += delta;
}
@ -319,3 +507,11 @@ WorkspacesLayer::WindowChanged(WindowLayer* window)
Window()->MarkContentDirty(region);
}
void
WorkspacesLayer::WindowRemoved(WindowLayer* window)
{
if (fSelectedWindow == window)
fSelectedWindow = NULL;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2005, Haiku Inc.
* Copyright 2005-2006, Haiku Inc.
* Distributed under the terms of the MIT License.
*
* Authors:
@ -24,13 +24,19 @@ class WorkspacesLayer : public ViewLayer {
BRegion* effectiveClipping,
BRegion* windowContentClipping,
bool deep = false);
virtual void MouseDown(BMessage* message, BPoint where);
virtual void MouseUp(BMessage* message, BPoint where);
virtual void MouseMoved(BMessage* message, BPoint where);
void WindowChanged(WindowLayer* window);
void WindowRemoved(WindowLayer* window);
private:
void _GetGrid(int32& columns, int32& rows);
BRect _WorkspaceAt(int32 i);
BRect _ScreenFrame(int32 index);
BRect _WorkspaceAt(int32 index);
BRect _WorkspaceAt(BPoint where, int32& index);
BRect _WindowFrame(const BRect& workspaceFrame,
const BRect& screenFrame, const BRect& windowFrame,
BPoint windowPosition);
@ -43,6 +49,12 @@ class WorkspacesLayer : public ViewLayer {
int32 index);
void _DarkenColor(RGBColor& color) const;
private:
WindowLayer* fSelectedWindow;
int32 fSelectedWorkspace;
bool fHasMoved;
BPoint fLastMousePosition;
};
#endif // WORKSPACES_LAYER_H