124a146d4SAxel Dörfler/*
269f9a367SAxel Dörfler * Copyright 2005-2009, Haiku Inc.
324a146d4SAxel Dörfler * Distributed under the terms of the MIT License.
424a146d4SAxel Dörfler *
524a146d4SAxel Dörfler * Authors:
624a146d4SAxel Dörfler *		Axel D��rfler, axeld@pinc-software.de
76ed89418SStephan Aßmus *		Stephan A��mus <superstippi@gmx.de>
824a146d4SAxel Dörfler */
924a146d4SAxel Dörfler
1024a146d4SAxel Dörfler
11953d895eSAxel Dörfler#include "WorkspacesView.h"
1224a146d4SAxel Dörfler
136ed89418SStephan Aßmus#include "AppServer.h"
14bd06a41cSClemens Zeidler#include "Decorator.h"
15e83820edSAxel Dörfler#include "Desktop.h"
166ed89418SStephan Aßmus#include "DrawingEngine.h"
17bd06a41cSClemens Zeidler#include "DrawState.h"
1830d17caaSJohn Scipione#include "InterfaceDefs.h"
1990c518c2SStephan Aßmus#include "ServerApp.h"
20953d895eSAxel Dörfler#include "Window.h"
216ed89418SStephan Aßmus#include "Workspace.h"
226ed89418SStephan Aßmus
23e83820edSAxel Dörfler#include <WindowPrivate.h>
24e83820edSAxel Dörfler
2524a146d4SAxel Dörfler
26953d895eSAxel DörflerWorkspacesView::WorkspacesView(BRect frame, BPoint scrollingOffset,
27903936bcSAxel Dörfler		const char* name, int32 token, uint32 resizeMode, uint32 flags)
285ce91949SAxel Dörfler	:
295ce91949SAxel Dörfler	View(frame, scrollingOffset, name, token, resizeMode, flags),
3014fe11cfSAxel Dörfler	fSelectedWindow(NULL),
3114fe11cfSAxel Dörfler	fSelectedWorkspace(-1),
3214fe11cfSAxel Dörfler	fHasMoved(false)
3324a146d4SAxel Dörfler{
34f7e1df75SStephan Aßmus	fDrawState->SetLowColor((rgb_color){ 255, 255, 255, 255 });
35f7e1df75SStephan Aßmus	fDrawState->SetHighColor((rgb_color){ 0, 0, 0, 255 });
3624a146d4SAxel Dörfler}
3724a146d4SAxel Dörfler
3824a146d4SAxel Dörfler
39953d895eSAxel DörflerWorkspacesView::~WorkspacesView()
4024a146d4SAxel Dörfler{
412c184b20SAxel Dörfler}
422c184b20SAxel Dörfler
432c184b20SAxel Dörfler
442c184b20SAxel Dörflervoid
45953d895eSAxel DörflerWorkspacesView::AttachedToWindow(::Window* window)
462c184b20SAxel Dörfler{
47953d895eSAxel Dörfler	View::AttachedToWindow(window);
482c184b20SAxel Dörfler
492c184b20SAxel Dörfler	window->AddWorkspacesView();
502c184b20SAxel Dörfler	window->Desktop()->AddWorkspacesView(this);
512c184b20SAxel Dörfler}
522c184b20SAxel Dörfler
532c184b20SAxel Dörfler
542c184b20SAxel Dörflervoid
55953d895eSAxel DörflerWorkspacesView::DetachedFromWindow()
562c184b20SAxel Dörfler{
572c184b20SAxel Dörfler	fWindow->Desktop()->RemoveWorkspacesView(this);
582c184b20SAxel Dörfler	fWindow->RemoveWorkspacesView();
592c184b20SAxel Dörfler
60953d895eSAxel Dörfler	View::DetachedFromWindow();
6124a146d4SAxel Dörfler}
6224a146d4SAxel Dörfler
6324a146d4SAxel Dörfler
6424a146d4SAxel Dörflervoid
65953d895eSAxel DörflerWorkspacesView::_GetGrid(int32& columns, int32& rows)
6624a146d4SAxel Dörfler{
67a631158aSAxel Dörfler	DesktopSettings settings(Window()->Desktop());
6874e8df0eSAxel Dörfler
6969f9a367SAxel Dörfler	columns = settings.WorkspacesColumns();
7069f9a367SAxel Dörfler	rows = settings.WorkspacesRows();
7124a146d4SAxel Dörfler}
7224a146d4SAxel Dörfler
7324a146d4SAxel Dörfler
7469f9a367SAxel Dörfler/*!	\brief Returns the frame of the screen for the specified workspace.
7514fe11cfSAxel Dörfler*/
7614fe11cfSAxel DörflerBRect
77953d895eSAxel DörflerWorkspacesView::_ScreenFrame(int32 i)
7814fe11cfSAxel Dörfler{
7927c43a2dSRene Gollent	return Window()->Desktop()->WorkspaceFrame(i);
8014fe11cfSAxel Dörfler}
8114fe11cfSAxel Dörfler
8214fe11cfSAxel Dörfler
8369f9a367SAxel Dörfler/*!	\brief Returns the frame of the specified workspace within the
84437b1927SAxel Dörfler		workspaces view.
8514fe11cfSAxel Dörfler*/
8624a146d4SAxel DörflerBRect
87953d895eSAxel DörflerWorkspacesView::_WorkspaceAt(int32 i)
8824a146d4SAxel Dörfler{
8924a146d4SAxel Dörfler	int32 columns, rows;
9024a146d4SAxel Dörfler	_GetGrid(columns, rows);
9124a146d4SAxel Dörfler
92f9bbab88SAxel Dörfler	BRect frame = Bounds();
936f2a446eSJulian Harnath	LocalToScreenTransform().Apply(&frame);
94f9bbab88SAxel Dörfler
95f9bbab88SAxel Dörfler	int32 width = frame.IntegerWidth() / columns;
96f9bbab88SAxel Dörfler	int32 height = frame.IntegerHeight() / rows;
9724a146d4SAxel Dörfler
9824a146d4SAxel Dörfler	int32 column = i % columns;
9924a146d4SAxel Dörfler	int32 row = i / columns;
10024a146d4SAxel Dörfler
101f9bbab88SAxel Dörfler	BRect rect(column * width, row * height, (column + 1) * width,
102f9bbab88SAxel Dörfler		(row + 1) * height);
10324a146d4SAxel Dörfler
104f9bbab88SAxel Dörfler	rect.OffsetBy(frame.LeftTop());
10552d2c710SAxel Dörfler
10624a146d4SAxel Dörfler	// make sure there is no gap anywhere
10724a146d4SAxel Dörfler	if (column == columns - 1)
108f9bbab88SAxel Dörfler		rect.right = frame.right;
10924a146d4SAxel Dörfler	if (row == rows - 1)
110f9bbab88SAxel Dörfler		rect.bottom = frame.bottom;
11124a146d4SAxel Dörfler
11224a146d4SAxel Dörfler	return rect;
11324a146d4SAxel Dörfler}
11424a146d4SAxel Dörfler
11524a146d4SAxel Dörfler
11669f9a367SAxel Dörfler/*!	\brief Returns the workspace frame and index of the workspace
11714fe11cfSAxel Dörfler		under \a where.
11814fe11cfSAxel Dörfler
11914fe11cfSAxel Dörfler	If, for some reason, there is no workspace located under \where,
12014fe11cfSAxel Dörfler	an empty rectangle is returned, and \a index is set to -1.
12114fe11cfSAxel Dörfler*/
12214fe11cfSAxel DörflerBRect
123953d895eSAxel DörflerWorkspacesView::_WorkspaceAt(BPoint where, int32& index)
12414fe11cfSAxel Dörfler{
12514fe11cfSAxel Dörfler	int32 columns, rows;
12614fe11cfSAxel Dörfler	_GetGrid(columns, rows);
12714fe11cfSAxel Dörfler
12814fe11cfSAxel Dörfler	for (index = columns * rows; index-- > 0;) {
12914fe11cfSAxel Dörfler		BRect workspaceFrame = _WorkspaceAt(index);
13014fe11cfSAxel Dörfler
13114fe11cfSAxel Dörfler		if (workspaceFrame.Contains(where))
13214fe11cfSAxel Dörfler			return workspaceFrame;
13314fe11cfSAxel Dörfler	}
13414fe11cfSAxel Dörfler
13514fe11cfSAxel Dörfler	return BRect();
13614fe11cfSAxel Dörfler}
13714fe11cfSAxel Dörfler
13814fe11cfSAxel Dörfler
13924a146d4SAxel DörflerBRect
140953d895eSAxel DörflerWorkspacesView::_WindowFrame(const BRect& workspaceFrame,
14185d512edSPhilippe Houdoin	const BRect& screenFrame, const BRect& windowFrame,
14285d512edSPhilippe Houdoin	BPoint windowPosition)
14324a146d4SAxel Dörfler{
14424a146d4SAxel Dörfler	BRect frame = windowFrame;
1455ca8477eSAxel Dörfler	frame.OffsetTo(windowPosition);
14624a146d4SAxel Dörfler
147f7d80088SStephan Aßmus	// scale down the rect
14824a146d4SAxel Dörfler	float factor = workspaceFrame.Width() / screenFrame.Width();
149f7d80088SStephan Aßmus	frame.left = frame.left * factor;
150f7d80088SStephan Aßmus	frame.right = frame.right * factor;
15124a146d4SAxel Dörfler
15224a146d4SAxel Dörfler	factor = workspaceFrame.Height() / screenFrame.Height();
153f7d80088SStephan Aßmus	frame.top = frame.top * factor;
154f7d80088SStephan Aßmus	frame.bottom = frame.bottom * factor;
155f7d80088SStephan Aßmus
156f7d80088SStephan Aßmus	// offset by the workspace fame position
157f7d80088SStephan Aßmus	// and snap to integer coordinates without distorting the size too much
158f7d80088SStephan Aßmus	frame.OffsetTo(rintf(frame.left + workspaceFrame.left),
159f7d80088SStephan Aßmus		rintf(frame.top + workspaceFrame.top));
160f7d80088SStephan Aßmus	frame.right = rintf(frame.right);
161f7d80088SStephan Aßmus	frame.bottom = rintf(frame.bottom);
16224a146d4SAxel Dörfler
16324a146d4SAxel Dörfler	return frame;
16424a146d4SAxel Dörfler}
16524a146d4SAxel Dörfler
16624a146d4SAxel Dörfler
16724a146d4SAxel Dörflervoid
168953d895eSAxel DörflerWorkspacesView::_DrawWindow(DrawingEngine* drawingEngine,
169953d895eSAxel Dörfler	const BRect& workspaceFrame, const BRect& screenFrame, ::Window* window,
170eafed2f6SJohn Scipione	BPoint windowPosition, BRegion& backgroundRegion, bool workspaceActive)
17124a146d4SAxel Dörfler{
17252d2c710SAxel Dörfler	if (window->Feel() == kDesktopWindowFeel || window->IsHidden())
17331828430SAxel Dörfler		return;
17431828430SAxel Dörfler
1755ca8477eSAxel Dörfler	BPoint offset = window->Frame().LeftTop() - windowPosition;
1765ca8477eSAxel Dörfler	BRect frame = _WindowFrame(workspaceFrame, screenFrame, window->Frame(),
1775ca8477eSAxel Dörfler		windowPosition);
1787938b115SStefano Ceccherini	Decorator *decorator = window->Decorator();
1797938b115SStefano Ceccherini	BRect tabFrame(0, 0, 0, 0);
1807938b115SStefano Ceccherini	if (decorator != NULL)
181bb2e9b06SClemens Zeidler		tabFrame = decorator->TitleBarRect();
1827938b115SStefano Ceccherini
1835ca8477eSAxel Dörfler	tabFrame = _WindowFrame(workspaceFrame, screenFrame,
1845ca8477eSAxel Dörfler		tabFrame, tabFrame.LeftTop() - offset);
185f7d80088SStephan Aßmus	if (!workspaceFrame.Intersects(frame)
186f7d80088SStephan Aßmus		&& !workspaceFrame.Intersects(tabFrame))
18714fe11cfSAxel Dörfler		return;
18824a146d4SAxel Dörfler
189568b1f0bSRyan Leavengood	rgb_color activeTabColor = (rgb_color){ 255, 203, 0, 255 };
190568b1f0bSRyan Leavengood	rgb_color inactiveTabColor = (rgb_color){ 232, 232, 232, 255 };
191568b1f0bSRyan Leavengood	rgb_color navColor = (rgb_color){ 0, 0, 229, 255 };
192eafed2f6SJohn Scipione	rgb_color activeFrameColor = (rgb_color){ 180, 180, 180, 255 };
193eafed2f6SJohn Scipione	rgb_color inactiveFrameColor = (rgb_color){ 180, 180, 180, 255 };
194568b1f0bSRyan Leavengood	if (decorator != NULL) {
195568b1f0bSRyan Leavengood		activeTabColor = decorator->UIColor(B_WINDOW_TAB_COLOR);
196568b1f0bSRyan Leavengood		inactiveTabColor = decorator->UIColor(B_WINDOW_INACTIVE_TAB_COLOR);
197568b1f0bSRyan Leavengood		navColor = decorator->UIColor(B_NAVIGATION_BASE_COLOR);
198eafed2f6SJohn Scipione		activeFrameColor = decorator->UIColor(B_WINDOW_BORDER_COLOR);
199eafed2f6SJohn Scipione		inactiveFrameColor = decorator->UIColor(B_WINDOW_INACTIVE_BORDER_COLOR);
200568b1f0bSRyan Leavengood	}
201eafed2f6SJohn Scipione
202f7e1df75SStephan Aßmus	rgb_color white = (rgb_color){ 255, 255, 255, 255 };
20305988bd3SStephan Aßmus
204568b1f0bSRyan Leavengood	rgb_color tabColor = inactiveTabColor;
205eafed2f6SJohn Scipione	rgb_color frameColor = inactiveFrameColor;
206eafed2f6SJohn Scipione	if (window->IsFocus()) {
207568b1f0bSRyan Leavengood		tabColor = activeTabColor;
208eafed2f6SJohn Scipione		frameColor = activeFrameColor;
209eafed2f6SJohn Scipione	}
210568b1f0bSRyan Leavengood
211eafed2f6SJohn Scipione	if (!workspaceActive) {
212568b1f0bSRyan Leavengood		_DarkenColor(tabColor);
213acfa924cSAxel Dörfler		_DarkenColor(frameColor);
21405988bd3SStephan Aßmus		_DarkenColor(white);
21505988bd3SStephan Aßmus	}
21624a146d4SAxel Dörfler
217585d44f2SRyan Leavengood	if (tabFrame.Height() > 0 && tabFrame.Width() > 0) {
218585d44f2SRyan Leavengood		float width = tabFrame.Width();
219585d44f2SRyan Leavengood		if (tabFrame.left < frame.left) {
220585d44f2SRyan Leavengood			// Shift the tab right
221585d44f2SRyan Leavengood			tabFrame.left = frame.left;
222585d44f2SRyan Leavengood			tabFrame.right = tabFrame.left + width;
223585d44f2SRyan Leavengood		}
224585d44f2SRyan Leavengood		if (tabFrame.right > frame.right) {
225585d44f2SRyan Leavengood			// Shift the tab left
226585d44f2SRyan Leavengood			tabFrame.right = frame.right;
227585d44f2SRyan Leavengood			tabFrame.left = tabFrame.right - width;
228585d44f2SRyan Leavengood		}
229585d44f2SRyan Leavengood
230b9d90cb1SRyan Leavengood		if (tabFrame.bottom >= tabFrame.top) {
231585d44f2SRyan Leavengood			// Shift the tab up
232585d44f2SRyan Leavengood			float tabHeight = tabFrame.Height();
233585d44f2SRyan Leavengood			tabFrame.bottom = frame.top - 1;
234585d44f2SRyan Leavengood			tabFrame.top = tabFrame.bottom - tabHeight;
235585d44f2SRyan Leavengood		}
236585d44f2SRyan Leavengood
237585d44f2SRyan Leavengood		tabFrame = tabFrame & workspaceFrame;
238585d44f2SRyan Leavengood
239585d44f2SRyan Leavengood		if (decorator != NULL && tabFrame.IsValid()) {
240585d44f2SRyan Leavengood			drawingEngine->FillRect(tabFrame, tabColor);
241585d44f2SRyan Leavengood			backgroundRegion.Exclude(tabFrame);
242585d44f2SRyan Leavengood		}
24337b502f2SAxel Dörfler	}
24424a146d4SAxel Dörfler
245acfa924cSAxel Dörfler	drawingEngine->StrokeRect(frame, frameColor);
24624a146d4SAxel Dörfler
247f7d80088SStephan Aßmus	BRect fillFrame = frame.InsetByCopy(1, 1) & workspaceFrame;
24837b502f2SAxel Dörfler	frame = frame & workspaceFrame;
249f7d80088SStephan Aßmus	if (!frame.IsValid())
250f7d80088SStephan Aßmus		return;
251f7d80088SStephan Aßmus
252f7d80088SStephan Aßmus	// fill the window itself
253f7d80088SStephan Aßmus	drawingEngine->FillRect(fillFrame, white);
254649e929cSAxel Dörfler
255649e929cSAxel Dörfler	// draw title
256649e929cSAxel Dörfler
257f7d80088SStephan Aßmus	// TODO: the mini-window functionality should probably be moved into the
258f7d80088SStephan Aßmus	// Window class, so that it has only to be recalculated on demand. With
259f7d80088SStephan Aßmus	// double buffered windows, this would also open up the door to have a
260f7d80088SStephan Aßmus	// more detailed preview.
261252f4767SRyan Leavengood	BString title(window->Title());
262649e929cSAxel Dörfler
263f7d80088SStephan Aßmus	const ServerFont& font = fDrawState->Font();
264f7d80088SStephan Aßmus
265f7d80088SStephan Aßmus	font.TruncateString(&title, B_TRUNCATE_END, fillFrame.Width() - 4);
266f7d80088SStephan Aßmus	font_height fontHeight;
267f7d80088SStephan Aßmus	font.GetHeight(fontHeight);
268f7d80088SStephan Aßmus	float height = ceilf(fontHeight.ascent) + ceilf(fontHeight.descent);
269f7d80088SStephan Aßmus	if (title.Length() > 0 && height < frame.Height() - 2) {
270f7d80088SStephan Aßmus		rgb_color textColor = tint_color(white, B_DARKEN_4_TINT);
271f7d80088SStephan Aßmus		drawingEngine->SetHighColor(textColor);
272f7d80088SStephan Aßmus		drawingEngine->SetLowColor(white);
273649e929cSAxel Dörfler
274f7d80088SStephan Aßmus		float width = font.StringWidth(title.String(), title.Length());
275f7d80088SStephan Aßmus
276f7d80088SStephan Aßmus		BPoint textOffset;
277f7d80088SStephan Aßmus		textOffset.x = rintf(frame.left + (frame.Width() - width) / 2);
278f7d80088SStephan Aßmus		textOffset.y = rintf(frame.top + (frame.Height() - height) / 2
279f7d80088SStephan Aßmus			+ fontHeight.ascent);
280f7d80088SStephan Aßmus		drawingEngine->DrawString(title.String(), title.Length(), textOffset);
281f7d80088SStephan Aßmus	}
282f7d80088SStephan Aßmus
283f7d80088SStephan Aßmus	// prevent the next window down from drawing over this window
284f7d80088SStephan Aßmus	backgroundRegion.Exclude(frame);
28524a146d4SAxel Dörfler}
28624a146d4SAxel Dörfler
28724a146d4SAxel Dörfler
28824a146d4SAxel Dörflervoid
289953d895eSAxel DörflerWorkspacesView::_DrawWorkspace(DrawingEngine* drawingEngine,
290a7e20143SAxel Dörfler	BRegion& redraw, int32 index)
29124a146d4SAxel Dörfler{
29224a146d4SAxel Dörfler	BRect rect = _WorkspaceAt(index);
29324a146d4SAxel Dörfler
294a0e9f8e2SStephan Aßmus	Workspace workspace(*Window()->Desktop(), index, true);
295eafed2f6SJohn Scipione	bool workspaceActive = workspace.IsCurrent();
296eafed2f6SJohn Scipione	if (workspaceActive) {
29724a146d4SAxel Dörfler		// draw active frame
298f7e1df75SStephan Aßmus		rgb_color black = (rgb_color){ 0, 0, 0, 255 };
299e83820edSAxel Dörfler		drawingEngine->StrokeRect(rect, black);
300acfa924cSAxel Dörfler	} else if (index == fSelectedWorkspace) {
301f7e1df75SStephan Aßmus		rgb_color gray = (rgb_color){ 80, 80, 80, 255 };
302acfa924cSAxel Dörfler		drawingEngine->StrokeRect(rect, gray);
30324a146d4SAxel Dörfler	}
30424a146d4SAxel Dörfler
30524a146d4SAxel Dörfler	rect.InsetBy(1, 1);
30624a146d4SAxel Dörfler
307f7e1df75SStephan Aßmus	rgb_color color = workspace.Color();
308eafed2f6SJohn Scipione	if (!workspaceActive)
30905988bd3SStephan Aßmus		_DarkenColor(color);
31005988bd3SStephan Aßmus
31124a146d4SAxel Dörfler	// draw windows
31224a146d4SAxel Dörfler
313a7e20143SAxel Dörfler	BRegion backgroundRegion = redraw;
3142c8cfe2dSAdi Oanca
3154e59d9c7SAxel Dörfler	// TODO: would be nice to get the real update region here
31624a146d4SAxel Dörfler
31714fe11cfSAxel Dörfler	BRect screenFrame = _ScreenFrame(index);
31824a146d4SAxel Dörfler
3195ca8477eSAxel Dörfler	BRegion workspaceRegion(rect);
3205ca8477eSAxel Dörfler	backgroundRegion.IntersectWith(&workspaceRegion);
321e83820edSAxel Dörfler	drawingEngine->ConstrainClippingRegion(&backgroundRegion);
32224a146d4SAxel Dörfler
323f7d80088SStephan Aßmus	ServerFont font = fDrawState->Font();
32490c518c2SStephan Aßmus	font.SetSize(fWindow->ServerWindow()->App()->PlainFont().Size());
32590c518c2SStephan Aßmus	float reducedSize = ceilf(max_c(8.0f,
32690c518c2SStephan Aßmus		min_c(Frame().Height(), Frame().Width()) / 15));
32790c518c2SStephan Aßmus	if (font.Size() > reducedSize)
32890c518c2SStephan Aßmus		font.SetSize(reducedSize);
329f7d80088SStephan Aßmus	fDrawState->SetFont(font);
330f7d80088SStephan Aßmus	drawingEngine->SetFont(font);
331f7d80088SStephan Aßmus
33291d64539SAxel Dörfler	// We draw from top down and cut the window out of the clipping region
33391d64539SAxel Dörfler	// which reduces the flickering
334953d895eSAxel Dörfler	::Window* window;
3355ca8477eSAxel Dörfler	BPoint leftTop;
33691d64539SAxel Dörfler	while (workspace.GetPreviousWindow(window, leftTop) == B_OK) {
337e83820edSAxel Dörfler		_DrawWindow(drawingEngine, rect, screenFrame, window,
338eafed2f6SJohn Scipione			leftTop, backgroundRegion, workspaceActive);
33924a146d4SAxel Dörfler	}
3405712a788SAxel Dörfler
3415ca8477eSAxel Dörfler	// draw background
342e83820edSAxel Dörfler	drawingEngine->FillRect(rect, color);
3434a9bbc7dSAdi Oanca
344a7e20143SAxel Dörfler	drawingEngine->ConstrainClippingRegion(&redraw);
34524a146d4SAxel Dörfler}
34624a146d4SAxel Dörfler
34724a146d4SAxel Dörfler
34805988bd3SStephan Aßmusvoid
349953d895eSAxel DörflerWorkspacesView::_DarkenColor(rgb_color& color) const
35005988bd3SStephan Aßmus{
351f7e1df75SStephan Aßmus	color = tint_color(color, B_DARKEN_2_TINT);
35205988bd3SStephan Aßmus}
35305988bd3SStephan Aßmus
35405988bd3SStephan Aßmus
355acfa924cSAxel Dörflervoid
356953d895eSAxel DörflerWorkspacesView::_Invalidate() const
357acfa924cSAxel Dörfler{
358f9bbab88SAxel Dörfler	BRect frame = Bounds();
3596f2a446eSJulian Harnath	LocalToScreenTransform().Apply(&frame);
360f9bbab88SAxel Dörfler
361f9bbab88SAxel Dörfler	BRegion region(frame);
362acfa924cSAxel Dörfler	Window()->MarkContentDirty(region);
363acfa924cSAxel Dörfler}
364acfa924cSAxel Dörfler
365acfa924cSAxel Dörfler
36624a146d4SAxel Dörflervoid
367953d895eSAxel DörflerWorkspacesView::Draw(DrawingEngine* drawingEngine, BRegion* effectiveClipping,
368e83820edSAxel Dörfler	BRegion* windowContentClipping, bool deep)
36924a146d4SAxel Dörfler{
370a7e20143SAxel Dörfler	// we can only draw within our own area
371f0c3c996SMichael Lotz	BRegion redraw(ScreenAndUserClipping(windowContentClipping));
372a7e20143SAxel Dörfler	// add the current clipping
373a7e20143SAxel Dörfler	redraw.IntersectWith(effectiveClipping);
374a7e20143SAxel Dörfler
37524a146d4SAxel Dörfler	int32 columns, rows;
37624a146d4SAxel Dörfler	_GetGrid(columns, rows);
37724a146d4SAxel Dörfler
37824a146d4SAxel Dörfler	// draw grid
379a1d0e588SAxel Dörfler
380a1d0e588SAxel Dörfler	// make sure the grid around the active workspace is not drawn
381a1d0e588SAxel Dörfler	// to reduce flicker
382a1d0e588SAxel Dörfler	BRect activeRect = _WorkspaceAt(Window()->Desktop()->CurrentWorkspace());
383a7e20143SAxel Dörfler	BRegion gridRegion(redraw);
384a1d0e588SAxel Dörfler	gridRegion.Exclude(activeRect);
385e83820edSAxel Dörfler	drawingEngine->ConstrainClippingRegion(&gridRegion);
38624a146d4SAxel Dörfler
387f9bbab88SAxel Dörfler	BRect frame = Bounds();
3886f2a446eSJulian Harnath	LocalToScreenTransform().Apply(&frame);
38924a146d4SAxel Dörfler
390a1d0e588SAxel Dörfler	// horizontal lines
391a1d0e588SAxel Dörfler
392e83820edSAxel Dörfler	drawingEngine->StrokeLine(BPoint(frame.left, frame.top),
39324a146d4SAxel Dörfler		BPoint(frame.right, frame.top), ViewColor());
39424a146d4SAxel Dörfler
39524a146d4SAxel Dörfler	for (int32 row = 0; row < rows; row++) {
39624a146d4SAxel Dörfler		BRect rect = _WorkspaceAt(row * columns);
397e83820edSAxel Dörfler		drawingEngine->StrokeLine(BPoint(frame.left, rect.bottom),
39824a146d4SAxel Dörfler			BPoint(frame.right, rect.bottom), ViewColor());
39924a146d4SAxel Dörfler	}
40024a146d4SAxel Dörfler
40124a146d4SAxel Dörfler	// vertical lines
40224a146d4SAxel Dörfler
403e83820edSAxel Dörfler	drawingEngine->StrokeLine(BPoint(frame.left, frame.top),
40424a146d4SAxel Dörfler		BPoint(frame.left, frame.bottom), ViewColor());
40524a146d4SAxel Dörfler
40624a146d4SAxel Dörfler	for (int32 column = 0; column < columns; column++) {
40724a146d4SAxel Dörfler		BRect rect = _WorkspaceAt(column);
408e83820edSAxel Dörfler		drawingEngine->StrokeLine(BPoint(rect.right, frame.top),
40924a146d4SAxel Dörfler			BPoint(rect.right, frame.bottom), ViewColor());
41024a146d4SAxel Dörfler	}
41124a146d4SAxel Dörfler
412a7e20143SAxel Dörfler	drawingEngine->ConstrainClippingRegion(&redraw);
413a1d0e588SAxel Dörfler
41424a146d4SAxel Dörfler	// draw workspaces
41524a146d4SAxel Dörfler
4165ca8477eSAxel Dörfler	for (int32 i = rows * columns; i-- > 0;) {
417a7e20143SAxel Dörfler		_DrawWorkspace(drawingEngine, redraw, i);
418a631158aSAxel Dörfler	}
419f871c6f7SRene Gollent	fWindow->ServerWindow()->ResyncDrawState();
4205ca8477eSAxel Dörfler}
42124a146d4SAxel Dörfler
4225ca8477eSAxel Dörfler
4235ca8477eSAxel Dörflervoid
424953d895eSAxel DörflerWorkspacesView::MouseDown(BMessage* message, BPoint where)
4255ca8477eSAxel Dörfler{
42614fe11cfSAxel Dörfler	// reset tracking variables
42714fe11cfSAxel Dörfler	fSelectedWorkspace = -1;
42814fe11cfSAxel Dörfler	fSelectedWindow = NULL;
42914fe11cfSAxel Dörfler	fHasMoved = false;
43014fe11cfSAxel Dörfler
43114fe11cfSAxel Dörfler	// check if the correct mouse button is pressed
43214fe11cfSAxel Dörfler	int32 buttons;
43314fe11cfSAxel Dörfler	if (message->FindInt32("buttons", &buttons) != B_OK
43414fe11cfSAxel Dörfler		|| (buttons & B_PRIMARY_MOUSE_BUTTON) == 0)
43514fe11cfSAxel Dörfler		return;
4365ca8477eSAxel Dörfler
43714fe11cfSAxel Dörfler	int32 index;
43814fe11cfSAxel Dörfler	BRect workspaceFrame = _WorkspaceAt(where, index);
43914fe11cfSAxel Dörfler	if (index < 0)
44014fe11cfSAxel Dörfler		return;
4415ca8477eSAxel Dörfler
44214fe11cfSAxel Dörfler	Workspace workspace(*Window()->Desktop(), index);
44314fe11cfSAxel Dörfler	workspaceFrame.InsetBy(1, 1);
44414fe11cfSAxel Dörfler
44514fe11cfSAxel Dörfler	BRect screenFrame = _ScreenFrame(index);
44614fe11cfSAxel Dörfler
447953d895eSAxel Dörfler	::Window* window;
44888962660SAxel Dörfler	BRect windowFrame;
44914fe11cfSAxel Dörfler	BPoint leftTop;
45091d64539SAxel Dörfler	while (workspace.GetPreviousWindow(window, leftTop) == B_OK) {
451b0841df4SRyan Leavengood		if (window->IsMinimized() || window->IsHidden())
452b0841df4SRyan Leavengood			continue;
453b0841df4SRyan Leavengood
45414fe11cfSAxel Dörfler		BRect frame = _WindowFrame(workspaceFrame, screenFrame, window->Frame(),
45514fe11cfSAxel Dörfler			leftTop);
4562815b65bSAxel Dörfler		if (frame.Contains(where) && window->Feel() != kDesktopWindowFeel
4572815b65bSAxel Dörfler			&& window->Feel() != kWindowScreenFeel) {
45814fe11cfSAxel Dörfler			fSelectedWindow = window;
45988962660SAxel Dörfler			windowFrame = frame;
46091d64539SAxel Dörfler			break;
46188962660SAxel Dörfler		}
46214fe11cfSAxel Dörfler	}
46314fe11cfSAxel Dörfler
46414fe11cfSAxel Dörfler	// Some special functionality (clicked with modifiers)
46514fe11cfSAxel Dörfler
46614fe11cfSAxel Dörfler	int32 modifiers;
46714fe11cfSAxel Dörfler	if (fSelectedWindow != NULL
46814fe11cfSAxel Dörfler		&& message->FindInt32("modifiers", &modifiers) == B_OK) {
46914fe11cfSAxel Dörfler		if ((modifiers & B_CONTROL_KEY) != 0) {
47014fe11cfSAxel Dörfler			// Activate window if clicked with the control key pressed,
47114fe11cfSAxel Dörfler			// minimize it if control+shift - this mirrors Deskbar
47214fe11cfSAxel Dörfler			// shortcuts (when pressing a team menu item).
47314fe11cfSAxel Dörfler			if ((modifiers & B_SHIFT_KEY) != 0)
47414fe11cfSAxel Dörfler				fSelectedWindow->ServerWindow()->NotifyMinimize(true);
47514fe11cfSAxel Dörfler			else
47614fe11cfSAxel Dörfler				Window()->Desktop()->ActivateWindow(fSelectedWindow);
47714fe11cfSAxel Dörfler			fSelectedWindow = NULL;
47814fe11cfSAxel Dörfler		} else if ((modifiers & B_OPTION_KEY) != 0) {
47914fe11cfSAxel Dörfler			// Also, send window to back if clicked with the option
48014fe11cfSAxel Dörfler			// key pressed.
48114fe11cfSAxel Dörfler			Window()->Desktop()->SendWindowBehind(fSelectedWindow);
48214fe11cfSAxel Dörfler			fSelectedWindow = NULL;
4835ca8477eSAxel Dörfler		}
48424a146d4SAxel Dörfler	}
4855ca8477eSAxel Dörfler
48614fe11cfSAxel Dörfler	// If this window is movable, we keep it selected
4871e5e237dSAxel Dörfler	// (we prevent our own window from being moved, too)
48814fe11cfSAxel Dörfler
48963d557f0SMichael Lotz	if ((fSelectedWindow != NULL
49063d557f0SMichael Lotz			&& (fSelectedWindow->Flags() & B_NOT_MOVABLE) != 0)
491acfa924cSAxel Dörfler		|| fSelectedWindow == Window()) {
49214fe11cfSAxel Dörfler		fSelectedWindow = NULL;
493acfa924cSAxel Dörfler	}
49414fe11cfSAxel Dörfler
49588962660SAxel Dörfler	fLeftTopOffset = where - windowFrame.LeftTop();
49614fe11cfSAxel Dörfler	fSelectedWorkspace = index;
4973add2e79SAxel Dörfler	fClickPoint = where;
498acfa924cSAxel Dörfler
499acfa924cSAxel Dörfler	if (index >= 0)
500acfa924cSAxel Dörfler		_Invalidate();
50114fe11cfSAxel Dörfler}
50214fe11cfSAxel Dörfler
50314fe11cfSAxel Dörfler
50414fe11cfSAxel Dörflervoid
505953d895eSAxel DörflerWorkspacesView::MouseUp(BMessage* message, BPoint where)
50614fe11cfSAxel Dörfler{
50788962660SAxel Dörfler	if (!fHasMoved && fSelectedWorkspace >= 0) {
50888962660SAxel Dörfler		int32 index;
50988962660SAxel Dörfler		_WorkspaceAt(where, index);
51088962660SAxel Dörfler		if (index >= 0)
511dd84f111SAxel Dörfler			Window()->Desktop()->SetWorkspaceAsync(index);
51288962660SAxel Dörfler	}
51314fe11cfSAxel Dörfler
514acfa924cSAxel Dörfler	if (fSelectedWindow != NULL) {
515acfa924cSAxel Dörfler		// We need to hide the selection frame again
516acfa924cSAxel Dörfler		_Invalidate();
517acfa924cSAxel Dörfler	}
518acfa924cSAxel Dörfler
51914fe11cfSAxel Dörfler	fSelectedWindow = NULL;
520acfa924cSAxel Dörfler	fSelectedWorkspace = -1;
52114fe11cfSAxel Dörfler}
52214fe11cfSAxel Dörfler
52314fe11cfSAxel Dörfler
52414fe11cfSAxel Dörflervoid
525953d895eSAxel DörflerWorkspacesView::MouseMoved(BMessage* message, BPoint where)
52614fe11cfSAxel Dörfler{
527acfa924cSAxel Dörfler	if (fSelectedWindow == NULL && fSelectedWorkspace < 0)
52814fe11cfSAxel Dörfler		return;
52914fe11cfSAxel Dörfler
53014fe11cfSAxel Dörfler	// check if the correct mouse button is pressed
53114fe11cfSAxel Dörfler	int32 buttons;
53214fe11cfSAxel Dörfler	if (message->FindInt32("buttons", &buttons) != B_OK
53314fe11cfSAxel Dörfler		|| (buttons & B_PRIMARY_MOUSE_BUTTON) == 0)
53414fe11cfSAxel Dörfler		return;
53514fe11cfSAxel Dörfler
53688962660SAxel Dörfler	if (!fHasMoved) {
53788962660SAxel Dörfler		Window()->Desktop()->SetMouseEventWindow(Window());
53888962660SAxel Dörfler			// don't let us off the mouse
53988962660SAxel Dörfler	}
54014fe11cfSAxel Dörfler
54114fe11cfSAxel Dörfler	int32 index;
54214fe11cfSAxel Dörfler	BRect workspaceFrame = _WorkspaceAt(where, index);
543acfa924cSAxel Dörfler
544acfa924cSAxel Dörfler	if (fSelectedWindow == NULL) {
545acfa924cSAxel Dörfler		if (fSelectedWorkspace >= 0 && fSelectedWorkspace != index) {
546acfa924cSAxel Dörfler			fSelectedWorkspace = index;
547acfa924cSAxel Dörfler			_Invalidate();
548acfa924cSAxel Dörfler		}
549acfa924cSAxel Dörfler		return;
550acfa924cSAxel Dörfler	}
551acfa924cSAxel Dörfler
55214fe11cfSAxel Dörfler	workspaceFrame.InsetBy(1, 1);
55314fe11cfSAxel Dörfler
55414fe11cfSAxel Dörfler	if (index != fSelectedWorkspace) {
5557e9f5d25SAxel Dörfler		if (fSelectedWindow->IsNormal() && !fSelectedWindow->InWorkspace(index)) {
55614fe11cfSAxel Dörfler			// move window to this new workspace
55763d557f0SMichael Lotz			uint32 newWorkspaces = (fSelectedWindow->Workspaces()
55863d557f0SMichael Lotz				& ~(1UL << fSelectedWorkspace)) | (1UL << index);
55914fe11cfSAxel Dörfler
56014fe11cfSAxel Dörfler			Window()->Desktop()->SetWindowWorkspaces(fSelectedWindow,
56114fe11cfSAxel Dörfler				newWorkspaces);
56214fe11cfSAxel Dörfler		}
56314fe11cfSAxel Dörfler		fSelectedWorkspace = index;
56414fe11cfSAxel Dörfler	}
56514fe11cfSAxel Dörfler
56614fe11cfSAxel Dörfler	BRect screenFrame = _ScreenFrame(index);
56788962660SAxel Dörfler	float left = rintf((where.x - workspaceFrame.left - fLeftTopOffset.x)
56888962660SAxel Dörfler		* screenFrame.Width() / workspaceFrame.Width());
56988962660SAxel Dörfler	float top = rintf((where.y - workspaceFrame.top - fLeftTopOffset.y)
57088962660SAxel Dörfler		* screenFrame.Height() / workspaceFrame.Height());
57114fe11cfSAxel Dörfler
57288962660SAxel Dörfler	BPoint leftTop;
57388962660SAxel Dörfler	if (fSelectedWorkspace == Window()->Desktop()->CurrentWorkspace())
57488962660SAxel Dörfler		leftTop = fSelectedWindow->Frame().LeftTop();
57588962660SAxel Dörfler	else {
576dd169d9eSAxel Dörfler		if (fSelectedWindow->Anchor(fSelectedWorkspace).position
577dd169d9eSAxel Dörfler				== kInvalidWindowPosition) {
578dd169d9eSAxel Dörfler			fSelectedWindow->Anchor(fSelectedWorkspace).position
579dd169d9eSAxel Dörfler				= fSelectedWindow->Frame().LeftTop();
580dd169d9eSAxel Dörfler		}
58188962660SAxel Dörfler		leftTop = fSelectedWindow->Anchor(fSelectedWorkspace).position;
58288962660SAxel Dörfler	}
58388962660SAxel Dörfler
584dd169d9eSAxel Dörfler	// Don't treat every little mouse move as a window move - this would
585dd169d9eSAxel Dörfler	// make it too hard to activate a workspace.
58649cc2c3bSAxel Dörfler	float diff = max_c(fabs(fClickPoint.x - where.x),
587dd169d9eSAxel Dörfler		fabs(fClickPoint.y - where.y));
588dd169d9eSAxel Dörfler	if (!fHasMoved && diff > 2)
5893add2e79SAxel Dörfler		fHasMoved = true;
59014fe11cfSAxel Dörfler
5913add2e79SAxel Dörfler	if (fHasMoved) {
5923add2e79SAxel Dörfler		Window()->Desktop()->MoveWindowBy(fSelectedWindow, left - leftTop.x,
5933add2e79SAxel Dörfler			top - leftTop.y, fSelectedWorkspace);
5943add2e79SAxel Dörfler	}
59524a146d4SAxel Dörfler}
59624a146d4SAxel Dörfler
5975ca8477eSAxel Dörfler
59852d2c710SAxel Dörflervoid
599953d895eSAxel DörflerWorkspacesView::WindowChanged(::Window* window)
60052d2c710SAxel Dörfler{
60152d2c710SAxel Dörfler	// TODO: be smarter about this!
602acfa924cSAxel Dörfler	_Invalidate();
60352d2c710SAxel Dörfler}
60452d2c710SAxel Dörfler
60514fe11cfSAxel Dörfler
60614fe11cfSAxel Dörflervoid
607953d895eSAxel DörflerWorkspacesView::WindowRemoved(::Window* window)
60814fe11cfSAxel Dörfler{
60914fe11cfSAxel Dörfler	if (fSelectedWindow == window)
61014fe11cfSAxel Dörfler		fSelectedWindow = NULL;
61114fe11cfSAxel Dörfler}
61214fe11cfSAxel Dörfler