1369b4ff1SClemens Zeidler/*
2369b4ff1SClemens Zeidler * Copyright 2001-2010, Haiku, Inc.
3369b4ff1SClemens Zeidler * Distributed under the terms of the MIT license.
4369b4ff1SClemens Zeidler *
5369b4ff1SClemens Zeidler * Authors:
6369b4ff1SClemens Zeidler *		DarkWyrm <bpmagic@columbus.rr.com>
7369b4ff1SClemens Zeidler *		Adi Oanca <adioanca@gmail.com>
8369b4ff1SClemens Zeidler *		Stephan A��mus <superstippi@gmx.de>
9369b4ff1SClemens Zeidler *		Axel D��rfler <axeld@pinc-software.de>
10369b4ff1SClemens Zeidler *		Brecht Machiels <brecht@mos6581.org>
11369b4ff1SClemens Zeidler *		Clemens Zeidler <haiku@clemens-zeidler.de>
1289d652d5SIngo Weinhold *		Ingo Weinhold <ingo_weinhold@gmx.de>
13369b4ff1SClemens Zeidler */
14369b4ff1SClemens Zeidler
15369b4ff1SClemens Zeidler
16177ecc46SClemens Zeidler#include "DefaultWindowBehaviour.h"
17177ecc46SClemens Zeidler
187cf89074SIngo Weinhold#include <math.h>
197cf89074SIngo Weinhold
2089d652d5SIngo Weinhold#include <WindowPrivate.h>
2189d652d5SIngo Weinhold
22427788e0SIngo Weinhold#include "ClickTarget.h"
23177ecc46SClemens Zeidler#include "Desktop.h"
24bb2e9b06SClemens Zeidler#include "DefaultDecorator.h"
25177ecc46SClemens Zeidler#include "DrawingEngine.h"
26177ecc46SClemens Zeidler#include "Window.h"
27177ecc46SClemens Zeidler
28177ecc46SClemens Zeidler
29177ecc46SClemens Zeidler//#define DEBUG_WINDOW_CLICK
30177ecc46SClemens Zeidler#ifdef DEBUG_WINDOW_CLICK
31177ecc46SClemens Zeidler#	define STRACE_CLICK(x) printf x
32177ecc46SClemens Zeidler#else
33177ecc46SClemens Zeidler#	define STRACE_CLICK(x) ;
34177ecc46SClemens Zeidler#endif
35177ecc46SClemens Zeidler
36177ecc46SClemens Zeidler
3789d652d5SIngo Weinhold// The span between mouse down
38f91f6b62SAxel Dörflerstatic const bigtime_t kWindowActivationTimeout = 500000LL;
39f91f6b62SAxel Dörfler
40f91f6b62SAxel Dörfler
4152cac2e7SIngo Weinhold// #pragma mark - State
4252cac2e7SIngo Weinhold
4352cac2e7SIngo Weinhold
4452cac2e7SIngo Weinholdstruct DefaultWindowBehaviour::State {
4552cac2e7SIngo Weinhold	State(DefaultWindowBehaviour& behavior)
4652cac2e7SIngo Weinhold		:
4752cac2e7SIngo Weinhold		fBehavior(behavior),
4852cac2e7SIngo Weinhold		fWindow(behavior.fWindow),
4952cac2e7SIngo Weinhold		fDesktop(behavior.fDesktop)
5052cac2e7SIngo Weinhold	{
5152cac2e7SIngo Weinhold	}
5252cac2e7SIngo Weinhold
5352cac2e7SIngo Weinhold	virtual ~State()
5452cac2e7SIngo Weinhold	{
5552cac2e7SIngo Weinhold	}
5652cac2e7SIngo Weinhold
5752cac2e7SIngo Weinhold	virtual void EnterState(State* previousState)
5852cac2e7SIngo Weinhold	{
5952cac2e7SIngo Weinhold	}
6052cac2e7SIngo Weinhold
61006f7485SIngo Weinhold	virtual void ExitState(State* nextState)
6252cac2e7SIngo Weinhold	{
63006f7485SIngo Weinhold	}
64006f7485SIngo Weinhold
65006f7485SIngo Weinhold	virtual bool MouseDown(BMessage* message, BPoint where, bool& _unhandled)
66006f7485SIngo Weinhold	{
67006f7485SIngo Weinhold		return true;
6852cac2e7SIngo Weinhold	}
6952cac2e7SIngo Weinhold
7052cac2e7SIngo Weinhold	virtual void MouseUp(BMessage* message, BPoint where)
7152cac2e7SIngo Weinhold	{
7252cac2e7SIngo Weinhold	}
7352cac2e7SIngo Weinhold
7452cac2e7SIngo Weinhold	virtual void MouseMoved(BMessage* message, BPoint where, bool isFake)
7552cac2e7SIngo Weinhold	{
7652cac2e7SIngo Weinhold	}
7752cac2e7SIngo Weinhold
78006f7485SIngo Weinhold	virtual void ModifiersChanged(BPoint where, int32 modifiers)
79006f7485SIngo Weinhold	{
80006f7485SIngo Weinhold	}
81006f7485SIngo Weinhold
8252cac2e7SIngo Weinholdprotected:
8352cac2e7SIngo Weinhold	DefaultWindowBehaviour&	fBehavior;
8452cac2e7SIngo Weinhold	Window*					fWindow;
8552cac2e7SIngo Weinhold	Desktop*				fDesktop;
8652cac2e7SIngo Weinhold};
8752cac2e7SIngo Weinhold
8852cac2e7SIngo Weinhold
8952cac2e7SIngo Weinhold// #pragma mark - MouseTrackingState
9052cac2e7SIngo Weinhold
9152cac2e7SIngo Weinhold
9252cac2e7SIngo Weinholdstruct DefaultWindowBehaviour::MouseTrackingState : State {
9352cac2e7SIngo Weinhold	MouseTrackingState(DefaultWindowBehaviour& behavior, BPoint where,
947cf89074SIngo Weinhold		bool windowActionOnMouseUp, bool minimizeCheckOnMouseUp,
957cf89074SIngo Weinhold		int32 mouseButton = B_PRIMARY_MOUSE_BUTTON)
9652cac2e7SIngo Weinhold		:
9752cac2e7SIngo Weinhold		State(behavior),
987cf89074SIngo Weinhold		fMouseButton(mouseButton),
990fd53296SIngo Weinhold		fWindowActionOnMouseUp(windowActionOnMouseUp),
10052cac2e7SIngo Weinhold		fMinimizeCheckOnMouseUp(minimizeCheckOnMouseUp),
10152cac2e7SIngo Weinhold		fLastMousePosition(where),
10252cac2e7SIngo Weinhold		fMouseMoveDistance(0),
10352cac2e7SIngo Weinhold		fLastMoveTime(system_time())
10452cac2e7SIngo Weinhold	{
10552cac2e7SIngo Weinhold	}
10652cac2e7SIngo Weinhold
10752cac2e7SIngo Weinhold	virtual void MouseUp(BMessage* message, BPoint where)
10852cac2e7SIngo Weinhold	{
1097cf89074SIngo Weinhold		// ignore, if it's not our mouse button
11052cac2e7SIngo Weinhold		int32 buttons = message->FindInt32("buttons");
1117cf89074SIngo Weinhold		if ((buttons & fMouseButton) != 0)
11252cac2e7SIngo Weinhold			return;
11352cac2e7SIngo Weinhold
11452cac2e7SIngo Weinhold		if (fMinimizeCheckOnMouseUp) {
11552cac2e7SIngo Weinhold			// If the modifiers haven't changed in the meantime and not too
11652cac2e7SIngo Weinhold			// much time has elapsed, we're supposed to minimize the window.
11752cac2e7SIngo Weinhold			fMinimizeCheckOnMouseUp = false;
11852cac2e7SIngo Weinhold			if (message->FindInt32("modifiers") == fBehavior.fLastModifiers
11952cac2e7SIngo Weinhold				&& (fWindow->Flags() & B_NOT_MINIMIZABLE) == 0
120427788e0SIngo Weinhold				&& system_time() - fLastMoveTime < kWindowActivationTimeout) {
12152cac2e7SIngo Weinhold				fWindow->ServerWindow()->NotifyMinimize(true);
12252cac2e7SIngo Weinhold			}
12352cac2e7SIngo Weinhold		}
12452cac2e7SIngo Weinhold
1250fd53296SIngo Weinhold		// Perform the window action in case the mouse was not moved.
1260fd53296SIngo Weinhold		if (fWindowActionOnMouseUp) {
1270fd53296SIngo Weinhold			// There is a time window for this feature, i.e. click and press
1280fd53296SIngo Weinhold			// too long, nothing will happen.
12952cac2e7SIngo Weinhold			if (system_time() - fLastMoveTime < kWindowActivationTimeout)
1300fd53296SIngo Weinhold				MouseUpWindowAction();
13152cac2e7SIngo Weinhold		}
13252cac2e7SIngo Weinhold
13352cac2e7SIngo Weinhold		fBehavior._NextState(NULL);
13452cac2e7SIngo Weinhold	}
13552cac2e7SIngo Weinhold
13652cac2e7SIngo Weinhold	virtual void MouseMoved(BMessage* message, BPoint where, bool isFake)
13752cac2e7SIngo Weinhold	{
13852cac2e7SIngo Weinhold		// Limit the rate at which "mouse moved" events are handled that move
13952cac2e7SIngo Weinhold		// or resize the window. At the moment this affects also tab sliding,
14052cac2e7SIngo Weinhold		// but 1/75 s is a pretty fine granularity anyway, so don't bother.
14152cac2e7SIngo Weinhold		bigtime_t now = system_time();
14252cac2e7SIngo Weinhold		if (now - fLastMoveTime < 13333) {
14352cac2e7SIngo Weinhold			// TODO: add a "timed event" to query for
14452cac2e7SIngo Weinhold			// the then current mouse position
14552cac2e7SIngo Weinhold			return;
14652cac2e7SIngo Weinhold		}
1470fd53296SIngo Weinhold		if (fWindowActionOnMouseUp || fMinimizeCheckOnMouseUp) {
14852cac2e7SIngo Weinhold			if (now - fLastMoveTime >= kWindowActivationTimeout) {
14952cac2e7SIngo Weinhold				// This click is too long already for window activation/
15052cac2e7SIngo Weinhold				// minimizing.
1510fd53296SIngo Weinhold				fWindowActionOnMouseUp = false;
15252cac2e7SIngo Weinhold				fMinimizeCheckOnMouseUp = false;
15352cac2e7SIngo Weinhold				fLastMoveTime = now;
15452cac2e7SIngo Weinhold			}
15552cac2e7SIngo Weinhold		} else
15652cac2e7SIngo Weinhold			fLastMoveTime = now;
15752cac2e7SIngo Weinhold
15852cac2e7SIngo Weinhold		BPoint delta = where - fLastMousePosition;
15952cac2e7SIngo Weinhold		// NOTE: "delta" is later used to change fLastMousePosition.
16052cac2e7SIngo Weinhold		// If for some reason no change should take effect, delta
16152cac2e7SIngo Weinhold		// is to be set to (0, 0) so that fLastMousePosition is not
16252cac2e7SIngo Weinhold		// adjusted. This way the relative mouse position to the
16352cac2e7SIngo Weinhold		// item being changed (border during resizing, tab during
16452cac2e7SIngo Weinhold		// sliding...) stays fixed when the mouse is moved so that
16552cac2e7SIngo Weinhold		// changes are taking effect again.
16652cac2e7SIngo Weinhold
16752cac2e7SIngo Weinhold		// If the window was moved enough, it doesn't come to
16852cac2e7SIngo Weinhold		// the front in FFM mode when the mouse is released.
1690fd53296SIngo Weinhold		if (fWindowActionOnMouseUp || fMinimizeCheckOnMouseUp) {
17052cac2e7SIngo Weinhold			fMouseMoveDistance += delta.x * delta.x + delta.y * delta.y;
17152cac2e7SIngo Weinhold			if (fMouseMoveDistance > 16.0f) {
1720fd53296SIngo Weinhold				fWindowActionOnMouseUp = false;
17352cac2e7SIngo Weinhold				fMinimizeCheckOnMouseUp = false;
17452cac2e7SIngo Weinhold			} else
17552cac2e7SIngo Weinhold				delta = B_ORIGIN;
17652cac2e7SIngo Weinhold		}
17752cac2e7SIngo Weinhold
17852cac2e7SIngo Weinhold		// perform the action (this also updates the delta)
17952cac2e7SIngo Weinhold		MouseMovedAction(delta, now);
18052cac2e7SIngo Weinhold
18152cac2e7SIngo Weinhold		// set the new mouse position
18252cac2e7SIngo Weinhold		fLastMousePosition += delta;
18352cac2e7SIngo Weinhold	}
18452cac2e7SIngo Weinhold
1850fd53296SIngo Weinhold	virtual void MouseMovedAction(BPoint& delta, bigtime_t now)
1860fd53296SIngo Weinhold	{
1870fd53296SIngo Weinhold	}
1880fd53296SIngo Weinhold
1890fd53296SIngo Weinhold	virtual void MouseUpWindowAction()
1900fd53296SIngo Weinhold	{
1910fd53296SIngo Weinhold		// default is window activation
1920fd53296SIngo Weinhold		fDesktop->ActivateWindow(fWindow);
1930fd53296SIngo Weinhold	}
19452cac2e7SIngo Weinhold
19552cac2e7SIngo Weinholdprotected:
1967cf89074SIngo Weinhold	int32				fMouseButton;
1970fd53296SIngo Weinhold	bool				fWindowActionOnMouseUp : 1;
19852cac2e7SIngo Weinhold	bool				fMinimizeCheckOnMouseUp : 1;
19952cac2e7SIngo Weinhold
20052cac2e7SIngo Weinhold	BPoint				fLastMousePosition;
20152cac2e7SIngo Weinhold	float				fMouseMoveDistance;
20252cac2e7SIngo Weinhold	bigtime_t			fLastMoveTime;
20352cac2e7SIngo Weinhold};
20452cac2e7SIngo Weinhold
20552cac2e7SIngo Weinhold
20652cac2e7SIngo Weinhold// #pragma mark - DragState
20752cac2e7SIngo Weinhold
20852cac2e7SIngo Weinhold
20952cac2e7SIngo Weinholdstruct DefaultWindowBehaviour::DragState : MouseTrackingState {
21052cac2e7SIngo Weinhold	DragState(DefaultWindowBehaviour& behavior, BPoint where,
21152cac2e7SIngo Weinhold		bool activateOnMouseUp, bool minimizeCheckOnMouseUp)
21252cac2e7SIngo Weinhold		:
21352cac2e7SIngo Weinhold		MouseTrackingState(behavior, where, activateOnMouseUp,
214b91ddd81SClemens Zeidler			minimizeCheckOnMouseUp)
21552cac2e7SIngo Weinhold	{
21652cac2e7SIngo Weinhold	}
21752cac2e7SIngo Weinhold
218006f7485SIngo Weinhold	virtual bool MouseDown(BMessage* message, BPoint where, bool& _unhandled)
21952cac2e7SIngo Weinhold	{
22052cac2e7SIngo Weinhold		// right-click while dragging shall bring the window to front
22152cac2e7SIngo Weinhold		int32 buttons = message->FindInt32("buttons");
22252cac2e7SIngo Weinhold		if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) {
22352cac2e7SIngo Weinhold			if (fWindow == fDesktop->BackWindow())
22452cac2e7SIngo Weinhold				fDesktop->ActivateWindow(fWindow);
22552cac2e7SIngo Weinhold			else
22652cac2e7SIngo Weinhold				fDesktop->SendWindowBehind(fWindow);
227006f7485SIngo Weinhold			return true;
22852cac2e7SIngo Weinhold		}
22952cac2e7SIngo Weinhold
230006f7485SIngo Weinhold		return MouseTrackingState::MouseDown(message, where, _unhandled);
23152cac2e7SIngo Weinhold	}
23252cac2e7SIngo Weinhold
23352cac2e7SIngo Weinhold	virtual void MouseMovedAction(BPoint& delta, bigtime_t now)
23452cac2e7SIngo Weinhold	{
2358f449285SJohn Scipione		if ((fWindow->Flags() & B_NOT_MOVABLE) == 0) {
23652cac2e7SIngo Weinhold			BPoint oldLeftTop = fWindow->Frame().LeftTop();
23752cac2e7SIngo Weinhold
238b91ddd81SClemens Zeidler			fBehavior.AlterDeltaForSnap(fWindow, delta, now);
23952cac2e7SIngo Weinhold			fDesktop->MoveWindowBy(fWindow, delta.x, delta.y);
24052cac2e7SIngo Weinhold
24152cac2e7SIngo Weinhold			// constrain delta to true change in position
24252cac2e7SIngo Weinhold			delta = fWindow->Frame().LeftTop() - oldLeftTop;
24352cac2e7SIngo Weinhold		} else
2444cf48a7aSJohn Scipione			delta = BPoint(0, 0);
24552cac2e7SIngo Weinhold	}
24652cac2e7SIngo Weinhold};
24752cac2e7SIngo Weinhold
24852cac2e7SIngo Weinhold
24952cac2e7SIngo Weinhold// #pragma mark - ResizeState
25052cac2e7SIngo Weinhold
25152cac2e7SIngo Weinhold
25252cac2e7SIngo Weinholdstruct DefaultWindowBehaviour::ResizeState : MouseTrackingState {
25352cac2e7SIngo Weinhold	ResizeState(DefaultWindowBehaviour& behavior, BPoint where,
25452cac2e7SIngo Weinhold		bool activateOnMouseUp)
25552cac2e7SIngo Weinhold		:
25652cac2e7SIngo Weinhold		MouseTrackingState(behavior, where, activateOnMouseUp, false)
25752cac2e7SIngo Weinhold	{
25852cac2e7SIngo Weinhold	}
25952cac2e7SIngo Weinhold
26052cac2e7SIngo Weinhold	virtual void MouseMovedAction(BPoint& delta, bigtime_t now)
26152cac2e7SIngo Weinhold	{
2628f449285SJohn Scipione		if ((fWindow->Flags() & B_NOT_RESIZABLE) == 0) {
2638f449285SJohn Scipione			if ((fWindow->Flags() & B_NOT_V_RESIZABLE) != 0)
2644cf48a7aSJohn Scipione				delta.y = 0;
2658f449285SJohn Scipione			if ((fWindow->Flags() & B_NOT_H_RESIZABLE) != 0)
2664cf48a7aSJohn Scipione				delta.x = 0;
26752cac2e7SIngo Weinhold
26852cac2e7SIngo Weinhold			BPoint oldRightBottom = fWindow->Frame().RightBottom();
26952cac2e7SIngo Weinhold
27052cac2e7SIngo Weinhold			fDesktop->ResizeWindowBy(fWindow, delta.x, delta.y);
27152cac2e7SIngo Weinhold
27252cac2e7SIngo Weinhold			// constrain delta to true change in size
27352cac2e7SIngo Weinhold			delta = fWindow->Frame().RightBottom() - oldRightBottom;
27452cac2e7SIngo Weinhold		} else
2754cf48a7aSJohn Scipione			delta = BPoint(0, 0);
27652cac2e7SIngo Weinhold	}
27752cac2e7SIngo Weinhold};
27852cac2e7SIngo Weinhold
27952cac2e7SIngo Weinhold
28052cac2e7SIngo Weinhold// #pragma mark - SlideTabState
28152cac2e7SIngo Weinhold
28252cac2e7SIngo Weinhold
28352cac2e7SIngo Weinholdstruct DefaultWindowBehaviour::SlideTabState : MouseTrackingState {
28452cac2e7SIngo Weinhold	SlideTabState(DefaultWindowBehaviour& behavior, BPoint where)
28552cac2e7SIngo Weinhold		:
28652cac2e7SIngo Weinhold		MouseTrackingState(behavior, where, false, false)
28752cac2e7SIngo Weinhold	{
28852cac2e7SIngo Weinhold	}
28952cac2e7SIngo Weinhold
290bb2e9b06SClemens Zeidler	virtual
291bb2e9b06SClemens Zeidler	~SlideTabState()
292bb2e9b06SClemens Zeidler	{
293bb2e9b06SClemens Zeidler		fDesktop->SetWindowTabLocation(fWindow, fWindow->TabLocation(), false);
294bb2e9b06SClemens Zeidler	}
295bb2e9b06SClemens Zeidler
29652cac2e7SIngo Weinhold	virtual void MouseMovedAction(BPoint& delta, bigtime_t now)
29752cac2e7SIngo Weinhold	{
298bb2e9b06SClemens Zeidler		float location = fWindow->TabLocation();
29952cac2e7SIngo Weinhold		// TODO: change to [0:1]
300bb2e9b06SClemens Zeidler		location += delta.x;
301bb2e9b06SClemens Zeidler		AdjustMultiTabLocation(location, true);
302bb2e9b06SClemens Zeidler		if (fDesktop->SetWindowTabLocation(fWindow, location, true))
3034cf48a7aSJohn Scipione			delta.y = 0;
30452cac2e7SIngo Weinhold		else
3054cf48a7aSJohn Scipione			delta = BPoint(0, 0);
30652cac2e7SIngo Weinhold	}
307bb2e9b06SClemens Zeidler
308bb2e9b06SClemens Zeidler	void AdjustMultiTabLocation(float location, bool isShifting)
309bb2e9b06SClemens Zeidler	{
310bb2e9b06SClemens Zeidler		::Decorator* decorator = fWindow->Decorator();
311bb2e9b06SClemens Zeidler		if (decorator == NULL || decorator->CountTabs() <= 1)
312bb2e9b06SClemens Zeidler			return;
313bb2e9b06SClemens Zeidler
314bb2e9b06SClemens Zeidler		// TODO does not work for none continuous shifts
315bb2e9b06SClemens Zeidler		int32 windowIndex = fWindow->PositionInStack();
316bb2e9b06SClemens Zeidler		DefaultDecorator::Tab*	movingTab = static_cast<DefaultDecorator::Tab*>(
317bb2e9b06SClemens Zeidler			decorator->TabAt(windowIndex));
318bb2e9b06SClemens Zeidler		int32 neighbourIndex = windowIndex;
319bb2e9b06SClemens Zeidler		if (movingTab->tabOffset > location)
320bb2e9b06SClemens Zeidler			neighbourIndex--;
321bb2e9b06SClemens Zeidler		else
322bb2e9b06SClemens Zeidler			neighbourIndex++;
323bb2e9b06SClemens Zeidler
324bb2e9b06SClemens Zeidler		DefaultDecorator::Tab* neighbourTab
325bb2e9b06SClemens Zeidler			= static_cast<DefaultDecorator::Tab*>(decorator->TabAt(
326bb2e9b06SClemens Zeidler				neighbourIndex));
327bb2e9b06SClemens Zeidler		if (neighbourTab == NULL)
328bb2e9b06SClemens Zeidler			return;
329bb2e9b06SClemens Zeidler
330bb2e9b06SClemens Zeidler		if (movingTab->tabOffset > location) {
3314cf48a7aSJohn Scipione			if (location > neighbourTab->tabOffset
3324cf48a7aSJohn Scipione					+ neighbourTab->tabRect.Width() / 2) {
333bb2e9b06SClemens Zeidler				return;
3348f449285SJohn Scipione			}
335bb2e9b06SClemens Zeidler		} else {
3364cf48a7aSJohn Scipione			if (location + movingTab->tabRect.Width() < neighbourTab->tabOffset
3374cf48a7aSJohn Scipione					+ neighbourTab->tabRect.Width() / 2) {
338bb2e9b06SClemens Zeidler				return;
3398f449285SJohn Scipione			}
340bb2e9b06SClemens Zeidler		}
3414cf48a7aSJohn Scipione
342bb2e9b06SClemens Zeidler		fWindow->MoveToStackPosition(neighbourIndex, isShifting);
343bb2e9b06SClemens Zeidler	}
34452cac2e7SIngo Weinhold};
34552cac2e7SIngo Weinhold
34652cac2e7SIngo Weinhold
3477cf89074SIngo Weinhold// #pragma mark - ResizeBorderState
3487cf89074SIngo Weinhold
3497cf89074SIngo Weinhold
3507cf89074SIngo Weinholdstruct DefaultWindowBehaviour::ResizeBorderState : MouseTrackingState {
351006f7485SIngo Weinhold	ResizeBorderState(DefaultWindowBehaviour& behavior, BPoint where,
352006f7485SIngo Weinhold		Decorator::Region region)
3537cf89074SIngo Weinhold		:
3547cf89074SIngo Weinhold		MouseTrackingState(behavior, where, true, false,
3557cf89074SIngo Weinhold			B_SECONDARY_MOUSE_BUTTON),
3567cf89074SIngo Weinhold		fHorizontal(NONE),
3577cf89074SIngo Weinhold		fVertical(NONE)
3587cf89074SIngo Weinhold	{
359006f7485SIngo Weinhold		switch (region) {
360006f7485SIngo Weinhold			case Decorator::REGION_TAB:
361006f7485SIngo Weinhold				// TODO: Handle like the border it is attached to (top/left)?
3627cf89074SIngo Weinhold				break;
363006f7485SIngo Weinhold			case Decorator::REGION_LEFT_BORDER:
364006f7485SIngo Weinhold				fHorizontal = LEFT;
365006f7485SIngo Weinhold				break;
366006f7485SIngo Weinhold			case Decorator::REGION_RIGHT_BORDER:
3677cf89074SIngo Weinhold				fHorizontal = RIGHT;
3687cf89074SIngo Weinhold				break;
369006f7485SIngo Weinhold			case Decorator::REGION_TOP_BORDER:
370006f7485SIngo Weinhold				fVertical = TOP;
3717cf89074SIngo Weinhold				break;
372006f7485SIngo Weinhold			case Decorator::REGION_BOTTOM_BORDER:
3737cf89074SIngo Weinhold				fVertical = BOTTOM;
3747cf89074SIngo Weinhold				break;
375006f7485SIngo Weinhold			case Decorator::REGION_LEFT_TOP_CORNER:
3767cf89074SIngo Weinhold				fHorizontal = LEFT;
377006f7485SIngo Weinhold				fVertical = TOP;
3787cf89074SIngo Weinhold				break;
379006f7485SIngo Weinhold			case Decorator::REGION_LEFT_BOTTOM_CORNER:
3807cf89074SIngo Weinhold				fHorizontal = LEFT;
381006f7485SIngo Weinhold				fVertical = BOTTOM;
3827cf89074SIngo Weinhold				break;
383006f7485SIngo Weinhold			case Decorator::REGION_RIGHT_TOP_CORNER:
384006f7485SIngo Weinhold				fHorizontal = RIGHT;
3857cf89074SIngo Weinhold				fVertical = TOP;
3867cf89074SIngo Weinhold				break;
387006f7485SIngo Weinhold			case Decorator::REGION_RIGHT_BOTTOM_CORNER:
3887cf89074SIngo Weinhold				fHorizontal = RIGHT;
389006f7485SIngo Weinhold				fVertical = BOTTOM;
390006f7485SIngo Weinhold				break;
391006f7485SIngo Weinhold			default:
3927cf89074SIngo Weinhold				break;
3937cf89074SIngo Weinhold		}
3947cf89074SIngo Weinhold	}
3957cf89074SIngo Weinhold
396006f7485SIngo Weinhold	ResizeBorderState(DefaultWindowBehaviour& behavior, BPoint where,
397006f7485SIngo Weinhold		int8 horizontal, int8 vertical)
398006f7485SIngo Weinhold		:
399006f7485SIngo Weinhold		MouseTrackingState(behavior, where, true, false,
400006f7485SIngo Weinhold			B_SECONDARY_MOUSE_BUTTON),
401006f7485SIngo Weinhold		fHorizontal(horizontal),
402006f7485SIngo Weinhold		fVertical(vertical)
403006f7485SIngo Weinhold	{
404006f7485SIngo Weinhold	}
405006f7485SIngo Weinhold
40697d62304SIngo Weinhold	virtual void EnterState(State* previousState)
40797d62304SIngo Weinhold	{
4088490a525SPhilippe Houdoin		if ((fWindow->Flags() & B_NOT_RESIZABLE) != 0)
4098490a525SPhilippe Houdoin			fHorizontal = fVertical = NONE;
4108490a525SPhilippe Houdoin		else {
4118490a525SPhilippe Houdoin			if ((fWindow->Flags() & B_NOT_H_RESIZABLE) != 0)
4128490a525SPhilippe Houdoin				fHorizontal = NONE;
4138490a525SPhilippe Houdoin
4148490a525SPhilippe Houdoin			if ((fWindow->Flags() & B_NOT_V_RESIZABLE) != 0)
4158490a525SPhilippe Houdoin				fVertical = NONE;
4168490a525SPhilippe Houdoin		}
41797d62304SIngo Weinhold		fBehavior._SetResizeCursor(fHorizontal, fVertical);
41897d62304SIngo Weinhold	}
41997d62304SIngo Weinhold
42097d62304SIngo Weinhold	virtual void ExitState(State* nextState)
42197d62304SIngo Weinhold	{
42297d62304SIngo Weinhold		fBehavior._ResetResizeCursor();
42397d62304SIngo Weinhold	}
42497d62304SIngo Weinhold
4257cf89074SIngo Weinhold	virtual void MouseMovedAction(BPoint& delta, bigtime_t now)
4267cf89074SIngo Weinhold	{
4278490a525SPhilippe Houdoin		if (fHorizontal == NONE)
4287cf89074SIngo Weinhold			delta.x = 0;
4298490a525SPhilippe Houdoin		if (fVertical == NONE)
4307cf89074SIngo Weinhold			delta.y = 0;
4317cf89074SIngo Weinhold
4327cf89074SIngo Weinhold		if (delta.x == 0 && delta.y == 0)
4337cf89074SIngo Weinhold			return;
4347cf89074SIngo Weinhold
4357cf89074SIngo Weinhold		// Resize first -- due to the window size limits this is not unlikely
4367cf89074SIngo Weinhold		// to turn out differently from what we request.
4377cf89074SIngo Weinhold		BPoint oldRightBottom = fWindow->Frame().RightBottom();
4387cf89074SIngo Weinhold
4397cf89074SIngo Weinhold		fDesktop->ResizeWindowBy(fWindow, delta.x * fHorizontal,
4407cf89074SIngo Weinhold			delta.y * fVertical);
4417cf89074SIngo Weinhold
4427cf89074SIngo Weinhold		// constrain delta to true change in size
4437cf89074SIngo Weinhold		delta = fWindow->Frame().RightBottom() - oldRightBottom;
4447cf89074SIngo Weinhold		delta.x *= fHorizontal;
4457cf89074SIngo Weinhold		delta.y *= fVertical;
4467cf89074SIngo Weinhold
4477cf89074SIngo Weinhold		// see, if we have to move, too
4487cf89074SIngo Weinhold		float moveX = fHorizontal == LEFT ? delta.x : 0;
4497cf89074SIngo Weinhold		float moveY = fVertical == TOP ? delta.y : 0;
4507cf89074SIngo Weinhold
4517cf89074SIngo Weinhold		if (moveX != 0 || moveY != 0)
4527cf89074SIngo Weinhold			fDesktop->MoveWindowBy(fWindow, moveX, moveY);
4537cf89074SIngo Weinhold	}
4547cf89074SIngo Weinhold
4557cf89074SIngo Weinhold	virtual void MouseUpWindowAction()
4567cf89074SIngo Weinhold	{
4577cf89074SIngo Weinhold		fDesktop->SendWindowBehind(fWindow);
4587cf89074SIngo Weinhold	}
4597cf89074SIngo Weinhold
4607cf89074SIngo Weinholdprivate:
4617cf89074SIngo Weinhold	int8	fHorizontal;
4627cf89074SIngo Weinhold	int8	fVertical;
4637cf89074SIngo Weinhold};
4647cf89074SIngo Weinhold
4657cf89074SIngo Weinhold
46652cac2e7SIngo Weinhold// #pragma mark - DecoratorButtonState
46752cac2e7SIngo Weinhold
46852cac2e7SIngo Weinhold
46952cac2e7SIngo Weinholdstruct DefaultWindowBehaviour::DecoratorButtonState : State {
470006f7485SIngo Weinhold	DecoratorButtonState(DefaultWindowBehaviour& behavior,
471bb2e9b06SClemens Zeidler		int32 tab, Decorator::Region button)
47252cac2e7SIngo Weinhold		:
47352cac2e7SIngo Weinhold		State(behavior),
474bb2e9b06SClemens Zeidler		fTab(tab),
47552cac2e7SIngo Weinhold		fButton(button)
47652cac2e7SIngo Weinhold	{
47752cac2e7SIngo Weinhold	}
47852cac2e7SIngo Weinhold
47952cac2e7SIngo Weinhold	virtual void EnterState(State* previousState)
48052cac2e7SIngo Weinhold	{
48152cac2e7SIngo Weinhold		_RedrawDecorator(NULL);
48252cac2e7SIngo Weinhold	}
48352cac2e7SIngo Weinhold
48452cac2e7SIngo Weinhold	virtual void MouseUp(BMessage* message, BPoint where)
48552cac2e7SIngo Weinhold	{
48652cac2e7SIngo Weinhold		// ignore, if it's not the primary mouse button
48752cac2e7SIngo Weinhold		int32 buttons = message->FindInt32("buttons");
48852cac2e7SIngo Weinhold		if ((buttons & B_PRIMARY_MOUSE_BUTTON) != 0)
48952cac2e7SIngo Weinhold			return;
49052cac2e7SIngo Weinhold
49152cac2e7SIngo Weinhold		// redraw the decorator
49252cac2e7SIngo Weinhold		if (Decorator* decorator = fWindow->Decorator()) {
49352cac2e7SIngo Weinhold			BRegion* visibleBorder = fWindow->RegionPool()->GetRegion();
49452cac2e7SIngo Weinhold			fWindow->GetBorderRegion(visibleBorder);
49552cac2e7SIngo Weinhold			visibleBorder->IntersectWith(&fWindow->VisibleRegion());
49652cac2e7SIngo Weinhold
49752cac2e7SIngo Weinhold			DrawingEngine* engine = decorator->GetDrawingEngine();
49852cac2e7SIngo Weinhold			engine->LockParallelAccess();
49952cac2e7SIngo Weinhold			engine->ConstrainClippingRegion(visibleBorder);
50052cac2e7SIngo Weinhold
501bb2e9b06SClemens Zeidler			int32 tab;
50252cac2e7SIngo Weinhold			switch (fButton) {
503006f7485SIngo Weinhold				case Decorator::REGION_CLOSE_BUTTON:
504bb2e9b06SClemens Zeidler					decorator->SetClose(fTab, false);
505bb2e9b06SClemens Zeidler					if (fBehavior._RegionFor(message, tab) == fButton)
50652cac2e7SIngo Weinhold						fWindow->ServerWindow()->NotifyQuitRequested();
50752cac2e7SIngo Weinhold					break;
50852cac2e7SIngo Weinhold
509006f7485SIngo Weinhold				case Decorator::REGION_ZOOM_BUTTON:
510bb2e9b06SClemens Zeidler					decorator->SetZoom(fTab, false);
511bb2e9b06SClemens Zeidler					if (fBehavior._RegionFor(message, tab) == fButton)
51252cac2e7SIngo Weinhold						fWindow->ServerWindow()->NotifyZoom();
51352cac2e7SIngo Weinhold					break;
51452cac2e7SIngo Weinhold
515006f7485SIngo Weinhold				case Decorator::REGION_MINIMIZE_BUTTON:
516bb2e9b06SClemens Zeidler					decorator->SetMinimize(fTab, false);
517bb2e9b06SClemens Zeidler					if (fBehavior._RegionFor(message, tab) == fButton)
51852cac2e7SIngo Weinhold						fWindow->ServerWindow()->NotifyMinimize(true);
51952cac2e7SIngo Weinhold					break;
52052cac2e7SIngo Weinhold
52152cac2e7SIngo Weinhold				default:
52252cac2e7SIngo Weinhold					break;
52352cac2e7SIngo Weinhold			}
52452cac2e7SIngo Weinhold
52552cac2e7SIngo Weinhold			engine->UnlockParallelAccess();
52652cac2e7SIngo Weinhold
52752cac2e7SIngo Weinhold			fWindow->RegionPool()->Recycle(visibleBorder);
52852cac2e7SIngo Weinhold		}
52952cac2e7SIngo Weinhold
53052cac2e7SIngo Weinhold		fBehavior._NextState(NULL);
53152cac2e7SIngo Weinhold	}
53252cac2e7SIngo Weinhold
53352cac2e7SIngo Weinhold	virtual void MouseMoved(BMessage* message, BPoint where, bool isFake)
53452cac2e7SIngo Weinhold	{
53552cac2e7SIngo Weinhold		_RedrawDecorator(message);
53652cac2e7SIngo Weinhold	}
53752cac2e7SIngo Weinhold
53852cac2e7SIngo Weinholdprivate:
53952cac2e7SIngo Weinhold	void _RedrawDecorator(const BMessage* message)
54052cac2e7SIngo Weinhold	{
54152cac2e7SIngo Weinhold		if (Decorator* decorator = fWindow->Decorator()) {
54252cac2e7SIngo Weinhold			BRegion* visibleBorder = fWindow->RegionPool()->GetRegion();
54352cac2e7SIngo Weinhold			fWindow->GetBorderRegion(visibleBorder);
54452cac2e7SIngo Weinhold			visibleBorder->IntersectWith(&fWindow->VisibleRegion());
54552cac2e7SIngo Weinhold
54652cac2e7SIngo Weinhold			DrawingEngine* engine = decorator->GetDrawingEngine();
54752cac2e7SIngo Weinhold			engine->LockParallelAccess();
54852cac2e7SIngo Weinhold			engine->ConstrainClippingRegion(visibleBorder);
54952cac2e7SIngo Weinhold
550bb2e9b06SClemens Zeidler			int32 tab;
551006f7485SIngo Weinhold			Decorator::Region hitRegion = message != NULL
552bb2e9b06SClemens Zeidler				? fBehavior._RegionFor(message, tab) : fButton;
55352cac2e7SIngo Weinhold
55452cac2e7SIngo Weinhold			switch (fButton) {
555006f7485SIngo Weinhold				case Decorator::REGION_CLOSE_BUTTON:
556bb2e9b06SClemens Zeidler					decorator->SetClose(fTab, hitRegion == fButton);
55752cac2e7SIngo Weinhold					break;
55852cac2e7SIngo Weinhold
559006f7485SIngo Weinhold				case Decorator::REGION_ZOOM_BUTTON:
560bb2e9b06SClemens Zeidler					decorator->SetZoom(fTab, hitRegion == fButton);
56152cac2e7SIngo Weinhold					break;
56252cac2e7SIngo Weinhold
563006f7485SIngo Weinhold				case Decorator::REGION_MINIMIZE_BUTTON:
564bb2e9b06SClemens Zeidler					decorator->SetMinimize(fTab, hitRegion == fButton);
56552cac2e7SIngo Weinhold					break;
56652cac2e7SIngo Weinhold
56752cac2e7SIngo Weinhold				default:
56852cac2e7SIngo Weinhold					break;
56952cac2e7SIngo Weinhold			}
57052cac2e7SIngo Weinhold
57152cac2e7SIngo Weinhold			engine->UnlockParallelAccess();
57252cac2e7SIngo Weinhold			fWindow->RegionPool()->Recycle(visibleBorder);
57352cac2e7SIngo Weinhold		}
57452cac2e7SIngo Weinhold	}
57552cac2e7SIngo Weinhold
57652cac2e7SIngo Weinholdprotected:
577bb2e9b06SClemens Zeidler	int32				fTab;
578006f7485SIngo Weinhold	Decorator::Region	fButton;
579006f7485SIngo Weinhold};
580006f7485SIngo Weinhold
581006f7485SIngo Weinhold
582006f7485SIngo Weinhold// #pragma mark - ManageWindowState
583006f7485SIngo Weinhold
584006f7485SIngo Weinhold
585006f7485SIngo Weinholdstruct DefaultWindowBehaviour::ManageWindowState : State {
586006f7485SIngo Weinhold	ManageWindowState(DefaultWindowBehaviour& behavior, BPoint where)
587006f7485SIngo Weinhold		:
588006f7485SIngo Weinhold		State(behavior),
589006f7485SIngo Weinhold		fLastMousePosition(where),
590006f7485SIngo Weinhold		fHorizontal(NONE),
591006f7485SIngo Weinhold		fVertical(NONE)
592006f7485SIngo Weinhold	{
593006f7485SIngo Weinhold	}
594006f7485SIngo Weinhold
595006f7485SIngo Weinhold	virtual void EnterState(State* previousState)
596006f7485SIngo Weinhold	{
597006f7485SIngo Weinhold		_UpdateBorders(fLastMousePosition);
598006f7485SIngo Weinhold	}
599006f7485SIngo Weinhold
600006f7485SIngo Weinhold	virtual void ExitState(State* nextState)
601006f7485SIngo Weinhold	{
602006f7485SIngo Weinhold		fBehavior._SetBorderHighlights(fHorizontal, fVertical, false);
603006f7485SIngo Weinhold	}
604006f7485SIngo Weinhold
605006f7485SIngo Weinhold	virtual bool MouseDown(BMessage* message, BPoint where, bool& _unhandled)
606006f7485SIngo Weinhold	{
607d5b6133bSJohn Scipione		// We're only interested if the secondary mouse button was pressed,
608d5b6133bSJohn Scipione		// otherwise let the caller handle the event.
609006f7485SIngo Weinhold		int32 buttons = message->FindInt32("buttons");
610006f7485SIngo Weinhold		if ((buttons & B_SECONDARY_MOUSE_BUTTON) == 0) {
611006f7485SIngo Weinhold			_unhandled = true;
612006f7485SIngo Weinhold			return true;
613006f7485SIngo Weinhold		}
614006f7485SIngo Weinhold
615006f7485SIngo Weinhold		fBehavior._NextState(new (std::nothrow) ResizeBorderState(fBehavior,
616006f7485SIngo Weinhold			where, fHorizontal, fVertical));
617006f7485SIngo Weinhold		return true;
618006f7485SIngo Weinhold	}
619006f7485SIngo Weinhold
620006f7485SIngo Weinhold	virtual void MouseMoved(BMessage* message, BPoint where, bool isFake)
621006f7485SIngo Weinhold	{
622006f7485SIngo Weinhold		// If the mouse is still over our window, update the borders. Otherwise
623006f7485SIngo Weinhold		// leave the state.
624006f7485SIngo Weinhold		if (fDesktop->WindowAt(where) == fWindow) {
625006f7485SIngo Weinhold			fLastMousePosition = where;
626006f7485SIngo Weinhold			_UpdateBorders(fLastMousePosition);
627006f7485SIngo Weinhold		} else
628006f7485SIngo Weinhold			fBehavior._NextState(NULL);
629006f7485SIngo Weinhold	}
630006f7485SIngo Weinhold
631006f7485SIngo Weinhold	virtual void ModifiersChanged(BPoint where, int32 modifiers)
632006f7485SIngo Weinhold	{
633006f7485SIngo Weinhold		if (!fBehavior._IsWindowModifier(modifiers))
634006f7485SIngo Weinhold			fBehavior._NextState(NULL);
635006f7485SIngo Weinhold	}
636006f7485SIngo Weinhold
637006f7485SIngo Weinholdprivate:
638006f7485SIngo Weinhold	void _UpdateBorders(BPoint where)
639006f7485SIngo Weinhold	{
6408490a525SPhilippe Houdoin		if ((fWindow->Flags() & B_NOT_RESIZABLE) != 0)
6418490a525SPhilippe Houdoin			return;
6428490a525SPhilippe Houdoin
643006f7485SIngo Weinhold		// Compute the window center relative location of where. We divide by
644006f7485SIngo Weinhold		// the width respective the height, so we compensate for the window's
645006f7485SIngo Weinhold		// aspect ratio.
646006f7485SIngo Weinhold		BRect frame(fWindow->Frame());
647006f7485SIngo Weinhold		if (frame.Width() + 1 == 0 || frame.Height() + 1 == 0)
648006f7485SIngo Weinhold			return;
649006f7485SIngo Weinhold
650006f7485SIngo Weinhold		float x = (where.x - (frame.left + frame.right) / 2)
651006f7485SIngo Weinhold			/ (frame.Width() + 1);
652006f7485SIngo Weinhold		float y = (where.y - (frame.top + frame.bottom) / 2)
653006f7485SIngo Weinhold			/ (frame.Height() + 1);
654006f7485SIngo Weinhold
6559f1aca35SIngo Weinhold		// compute the resize direction
6569f1aca35SIngo Weinhold		int8 horizontal;
6579f1aca35SIngo Weinhold		int8 vertical;
6589f1aca35SIngo Weinhold		_ComputeResizeDirection(x, y, horizontal, vertical);
659006f7485SIngo Weinhold
6608490a525SPhilippe Houdoin		if ((fWindow->Flags() & B_NOT_H_RESIZABLE) != 0)
6618490a525SPhilippe Houdoin			horizontal = NONE;
6628490a525SPhilippe Houdoin		if ((fWindow->Flags() & B_NOT_V_RESIZABLE) != 0)
6638490a525SPhilippe Houdoin			vertical = NONE;
6648490a525SPhilippe Houdoin
665006f7485SIngo Weinhold		// update the highlight, if necessary
666006f7485SIngo Weinhold		if (horizontal != fHorizontal || vertical != fVertical) {
667006f7485SIngo Weinhold			fBehavior._SetBorderHighlights(fHorizontal, fVertical, false);
668006f7485SIngo Weinhold			fHorizontal = horizontal;
669006f7485SIngo Weinhold			fVertical = vertical;
670006f7485SIngo Weinhold			fBehavior._SetBorderHighlights(fHorizontal, fVertical, true);
671006f7485SIngo Weinhold		}
672006f7485SIngo Weinhold	}
673006f7485SIngo Weinhold
674006f7485SIngo Weinholdprivate:
675006f7485SIngo Weinhold	BPoint	fLastMousePosition;
676006f7485SIngo Weinhold	int8	fHorizontal;
677006f7485SIngo Weinhold	int8	fVertical;
67852cac2e7SIngo Weinhold};
67952cac2e7SIngo Weinhold
68052cac2e7SIngo Weinhold
68152cac2e7SIngo Weinhold// #pragma mark - DefaultWindowBehaviour
68252cac2e7SIngo Weinhold
68352cac2e7SIngo Weinhold
68430c31ae2SClemens ZeidlerDefaultWindowBehaviour::DefaultWindowBehaviour(Window* window)
685177ecc46SClemens Zeidler	:
686177ecc46SClemens Zeidler	fWindow(window),
68752cac2e7SIngo Weinhold	fDesktop(window->Desktop()),
68852cac2e7SIngo Weinhold	fState(NULL),
689427788e0SIngo Weinhold	fLastModifiers(0)
690177ecc46SClemens Zeidler{
691177ecc46SClemens Zeidler}
692177ecc46SClemens Zeidler
693177ecc46SClemens Zeidler
694177ecc46SClemens ZeidlerDefaultWindowBehaviour::~DefaultWindowBehaviour()
695177ecc46SClemens Zeidler{
69652cac2e7SIngo Weinhold	delete fState;
697177ecc46SClemens Zeidler}
698177ecc46SClemens Zeidler
699177ecc46SClemens Zeidler
700177ecc46SClemens Zeidlerbool
701427788e0SIngo WeinholdDefaultWindowBehaviour::MouseDown(BMessage* message, BPoint where,
702427788e0SIngo Weinhold	int32 lastHitRegion, int32& clickCount, int32& _hitRegion)
703177ecc46SClemens Zeidler{
704427788e0SIngo Weinhold	fLastModifiers = message->FindInt32("modifiers");
7055116393fSIngo Weinhold	int32 buttons = message->FindInt32("buttons");
7065116393fSIngo Weinhold
70775504052SJohn Scipione	int32 numButtons;
70875504052SJohn Scipione	if (get_mouse_type(&numButtons) == B_OK) {
70975504052SJohn Scipione		switch (numButtons) {
71075504052SJohn Scipione			case 1:
71175504052SJohn Scipione				// 1 button mouse
71275504052SJohn Scipione				if ((fLastModifiers & B_CONTROL_KEY) != 0) {
71375504052SJohn Scipione					// emulate right click by holding control
71475504052SJohn Scipione					buttons = B_SECONDARY_MOUSE_BUTTON;
71575504052SJohn Scipione					message->ReplaceInt32("buttons", buttons);
71675504052SJohn Scipione				}
71775504052SJohn Scipione				break;
71875504052SJohn Scipione
71975504052SJohn Scipione			case 2:
72075504052SJohn Scipione				// TODO: 2 button mouse, pressing both buttons simultaneously
72175504052SJohn Scipione				// emulates middle click
72275504052SJohn Scipione
72375504052SJohn Scipione			default:
72475504052SJohn Scipione				break;
72575504052SJohn Scipione		}
72675504052SJohn Scipione	}
72775504052SJohn Scipione
72852cac2e7SIngo Weinhold	// if a state is active, let it do the job
729006f7485SIngo Weinhold	if (fState != NULL) {
730006f7485SIngo Weinhold		bool unhandled = false;
731006f7485SIngo Weinhold		bool result = fState->MouseDown(message, where, unhandled);
732006f7485SIngo Weinhold		if (!unhandled)
733006f7485SIngo Weinhold			return result;
734006f7485SIngo Weinhold	}
73552cac2e7SIngo Weinhold
736006f7485SIngo Weinhold	// No state active yet, or it wants us to handle the event -- determine the
737006f7485SIngo Weinhold	// click region and decide what to do.
73852cac2e7SIngo Weinhold
73952cac2e7SIngo Weinhold	Decorator* decorator = fWindow->Decorator();
74052cac2e7SIngo Weinhold
741006f7485SIngo Weinhold	Decorator::Region hitRegion = Decorator::REGION_NONE;
742bb2e9b06SClemens Zeidler	int32 tab = -1;
7430fd53296SIngo Weinhold	Action action = ACTION_NONE;
744177ecc46SClemens Zeidler
74552cac2e7SIngo Weinhold	bool inBorderRegion = false;
74652cac2e7SIngo Weinhold	if (decorator != NULL)
74752cac2e7SIngo Weinhold		inBorderRegion = decorator->GetFootprint().Contains(where);
74852cac2e7SIngo Weinhold
749427788e0SIngo Weinhold	bool windowModifier = _IsWindowModifier(fLastModifiers);
75052cac2e7SIngo Weinhold
751177ecc46SClemens Zeidler	if (windowModifier || inBorderRegion) {
75289d652d5SIngo Weinhold		// click on the window decorator or we have the window modifier keys
75389d652d5SIngo Weinhold		// held
75489d652d5SIngo Weinhold
75589d652d5SIngo Weinhold		// get the functional hit region
75689d652d5SIngo Weinhold		if (windowModifier) {
75789d652d5SIngo Weinhold			// click with window modifier keys -- let the whole window behave
75889d652d5SIngo Weinhold			// like the border
759006f7485SIngo Weinhold			hitRegion = Decorator::REGION_LEFT_BORDER;
76089d652d5SIngo Weinhold		} else {
76189d652d5SIngo Weinhold			// click on the decorator -- get the exact region
762bb2e9b06SClemens Zeidler			hitRegion = _RegionFor(message, tab);
76389d652d5SIngo Weinhold		}
764177ecc46SClemens Zeidler
76589d652d5SIngo Weinhold		// translate the region into an action
76689d652d5SIngo Weinhold		uint32 flags = fWindow->Flags();
76789d652d5SIngo Weinhold
7684e5bf973SIngo Weinhold		if ((buttons & B_PRIMARY_MOUSE_BUTTON) != 0) {
7694e5bf973SIngo Weinhold			// left mouse button
7704e5bf973SIngo Weinhold			switch (hitRegion) {
771bb2e9b06SClemens Zeidler				case Decorator::REGION_TAB: {
7724e5bf973SIngo Weinhold					// tab sliding in any case if either shift key is held down
7734e5bf973SIngo Weinhold					// except sliding up-down by moving mouse left-right would
7744e5bf973SIngo Weinhold					// look strange
775427788e0SIngo Weinhold					if ((fLastModifiers & B_SHIFT_KEY) != 0
7764e5bf973SIngo Weinhold						&& fWindow->Look() != kLeftTitledWindowLook) {
7774e5bf973SIngo Weinhold						action = ACTION_SLIDE_TAB;
7784e5bf973SIngo Weinhold						break;
7794e5bf973SIngo Weinhold					}
780006f7485SIngo Weinhold					action = ACTION_DRAG;
781006f7485SIngo Weinhold					break;
782bb2e9b06SClemens Zeidler				}
7834e5bf973SIngo Weinhold
784006f7485SIngo Weinhold				case Decorator::REGION_LEFT_BORDER:
785006f7485SIngo Weinhold				case Decorator::REGION_RIGHT_BORDER:
786006f7485SIngo Weinhold				case Decorator::REGION_TOP_BORDER:
787006f7485SIngo Weinhold				case Decorator::REGION_BOTTOM_BORDER:
7880fd53296SIngo Weinhold					action = ACTION_DRAG;
7894e5bf973SIngo Weinhold					break;
79089d652d5SIngo Weinhold
791006f7485SIngo Weinhold				case Decorator::REGION_CLOSE_BUTTON:
79289d652d5SIngo Weinhold					action = (flags & B_NOT_CLOSABLE) == 0
7930fd53296SIngo Weinhold						? ACTION_CLOSE : ACTION_DRAG;
7944e5bf973SIngo Weinhold					break;
79589d652d5SIngo Weinhold
796006f7485SIngo Weinhold				case Decorator::REGION_ZOOM_BUTTON:
79789d652d5SIngo Weinhold					action = (flags & B_NOT_ZOOMABLE) == 0
7980fd53296SIngo Weinhold						? ACTION_ZOOM : ACTION_DRAG;
7994e5bf973SIngo Weinhold					break;
80089d652d5SIngo Weinhold
801006f7485SIngo Weinhold				case Decorator::REGION_MINIMIZE_BUTTON:
80289d652d5SIngo Weinhold					action = (flags & B_NOT_MINIMIZABLE) == 0
8030fd53296SIngo Weinhold						? ACTION_MINIMIZE : ACTION_DRAG;
8044e5bf973SIngo Weinhold					break;
80589d652d5SIngo Weinhold
806006f7485SIngo Weinhold				case Decorator::REGION_LEFT_TOP_CORNER:
807006f7485SIngo Weinhold				case Decorator::REGION_LEFT_BOTTOM_CORNER:
808006f7485SIngo Weinhold				case Decorator::REGION_RIGHT_TOP_CORNER:
809006f7485SIngo Weinhold					// TODO: Handle correctly!
810006f7485SIngo Weinhold					action = ACTION_DRAG;
811006f7485SIngo Weinhold					break;
812006f7485SIngo Weinhold
813006f7485SIngo Weinhold				case Decorator::REGION_RIGHT_BOTTOM_CORNER:
81489d652d5SIngo Weinhold					action = (flags & B_NOT_RESIZABLE) == 0
8150fd53296SIngo Weinhold						? ACTION_RESIZE : ACTION_DRAG;
8164e5bf973SIngo Weinhold					break;
817006f7485SIngo Weinhold
818006f7485SIngo Weinhold				default:
819006f7485SIngo Weinhold					break;
8204e5bf973SIngo Weinhold			}
8214e5bf973SIngo Weinhold		} else if ((buttons & B_SECONDARY_MOUSE_BUTTON) != 0) {
8224e5bf973SIngo Weinhold			// right mouse button
8234e5bf973SIngo Weinhold			switch (hitRegion) {
824006f7485SIngo Weinhold				case Decorator::REGION_TAB:
825006f7485SIngo Weinhold				case Decorator::REGION_LEFT_BORDER:
826006f7485SIngo Weinhold				case Decorator::REGION_RIGHT_BORDER:
827006f7485SIngo Weinhold				case Decorator::REGION_TOP_BORDER:
828006f7485SIngo Weinhold				case Decorator::REGION_BOTTOM_BORDER:
829006f7485SIngo Weinhold				case Decorator::REGION_CLOSE_BUTTON:
830006f7485SIngo Weinhold				case Decorator::REGION_ZOOM_BUTTON:
831006f7485SIngo Weinhold				case Decorator::REGION_MINIMIZE_BUTTON:
832006f7485SIngo Weinhold				case Decorator::REGION_LEFT_TOP_CORNER:
833006f7485SIngo Weinhold				case Decorator::REGION_LEFT_BOTTOM_CORNER:
834006f7485SIngo Weinhold				case Decorator::REGION_RIGHT_TOP_CORNER:
835006f7485SIngo Weinhold				case Decorator::REGION_RIGHT_BOTTOM_CORNER:
836006f7485SIngo Weinhold					action = ACTION_RESIZE_BORDER;
8374e5bf973SIngo Weinhold					break;
8384e5bf973SIngo Weinhold
839006f7485SIngo Weinhold				default:
8404e5bf973SIngo Weinhold					break;
8414e5bf973SIngo Weinhold			}
842177ecc46SClemens Zeidler		}
843177ecc46SClemens Zeidler	}
844177ecc46SClemens Zeidler
845427788e0SIngo Weinhold	_hitRegion = (int32)hitRegion;
84698c0eab3SIngo Weinhold
8470fd53296SIngo Weinhold	if (action == ACTION_NONE) {
84889d652d5SIngo Weinhold		// No action -- if this is a click inside the window's contents,
84989d652d5SIngo Weinhold		// let it be forwarded to the window.
85089d652d5SIngo Weinhold		return inBorderRegion;
851f91f6b62SAxel Dörfler	}
852f91f6b62SAxel Dörfler
853427788e0SIngo Weinhold	// reset the click count, if the hit region differs from the previous one
854427788e0SIngo Weinhold	if (hitRegion != lastHitRegion)
855427788e0SIngo Weinhold		clickCount = 1;
856427788e0SIngo Weinhold
857177ecc46SClemens Zeidler	DesktopSettings desktopSettings(fDesktop);
858f91f6b62SAxel Dörfler	if (!desktopSettings.AcceptFirstClick()) {
859f91f6b62SAxel Dörfler		// Ignore clicks on decorator buttons if the
860f91f6b62SAxel Dörfler		// non-floating window doesn't have focus
861f91f6b62SAxel Dörfler		if (!fWindow->IsFocus() && !fWindow->IsFloating()
8620fd53296SIngo Weinhold			&& action != ACTION_RESIZE_BORDER
8630fd53296SIngo Weinhold			&& action != ACTION_RESIZE && action != ACTION_SLIDE_TAB)
8640fd53296SIngo Weinhold			action = ACTION_DRAG;
865f91f6b62SAxel Dörfler	}
866177ecc46SClemens Zeidler
86752cac2e7SIngo Weinhold	bool activateOnMouseUp = false;
8680fd53296SIngo Weinhold	if (action != ACTION_RESIZE_BORDER) {
86952cac2e7SIngo Weinhold		// activate window if in click to activate mode, else only focus it
87052cac2e7SIngo Weinhold		if (desktopSettings.MouseMode() == B_NORMAL_MOUSE) {
87152cac2e7SIngo Weinhold			fDesktop->ActivateWindow(fWindow);
87252cac2e7SIngo Weinhold		} else {
87352cac2e7SIngo Weinhold			fDesktop->SetFocusWindow(fWindow);
87452cac2e7SIngo Weinhold			activateOnMouseUp = true;
87552cac2e7SIngo Weinhold		}
87652cac2e7SIngo Weinhold	}
87752cac2e7SIngo Weinhold
87852cac2e7SIngo Weinhold	// switch to the new state
879f91f6b62SAxel Dörfler	switch (action) {
8800fd53296SIngo Weinhold		case ACTION_CLOSE:
8810fd53296SIngo Weinhold		case ACTION_ZOOM:
8820fd53296SIngo Weinhold		case ACTION_MINIMIZE:
88352cac2e7SIngo Weinhold			_NextState(
884bb2e9b06SClemens Zeidler				new (std::nothrow) DecoratorButtonState(*this, tab, hitRegion));
8850fd53296SIngo Weinhold			STRACE_CLICK(("===> ACTION_CLOSE/ZOOM/MINIMIZE\n"));
886f91f6b62SAxel Dörfler			break;
887f91f6b62SAxel Dörfler
8880fd53296SIngo Weinhold		case ACTION_DRAG:
88952cac2e7SIngo Weinhold			_NextState(new (std::nothrow) DragState(*this, where,
89052cac2e7SIngo Weinhold				activateOnMouseUp, clickCount == 2));
8910fd53296SIngo Weinhold			STRACE_CLICK(("===> ACTION_DRAG\n"));
892f91f6b62SAxel Dörfler			break;
893f91f6b62SAxel Dörfler
8940fd53296SIngo Weinhold		case ACTION_RESIZE:
89552cac2e7SIngo Weinhold			_NextState(new (std::nothrow) ResizeState(*this, where,
89652cac2e7SIngo Weinhold				activateOnMouseUp));
8970fd53296SIngo Weinhold			STRACE_CLICK(("===> ACTION_RESIZE\n"));
898f91f6b62SAxel Dörfler			break;
899f91f6b62SAxel Dörfler
9000fd53296SIngo Weinhold		case ACTION_SLIDE_TAB:
90152cac2e7SIngo Weinhold			_NextState(new (std::nothrow) SlideTabState(*this, where));
9020fd53296SIngo Weinhold			STRACE_CLICK(("===> ACTION_SLIDE_TAB\n"));
903f91f6b62SAxel Dörfler			break;
904f91f6b62SAxel Dörfler
9050fd53296SIngo Weinhold		case ACTION_RESIZE_BORDER:
906006f7485SIngo Weinhold			_NextState(new (std::nothrow) ResizeBorderState(*this, where,
907006f7485SIngo Weinhold				hitRegion));
9080fd53296SIngo Weinhold			STRACE_CLICK(("===> ACTION_RESIZE_BORDER\n"));
909f91f6b62SAxel Dörfler			break;
910177ecc46SClemens Zeidler
91152cac2e7SIngo Weinhold		default:
91252cac2e7SIngo Weinhold			break;
913f91f6b62SAxel Dörfler	}
914177ecc46SClemens Zeidler
915f91f6b62SAxel Dörfler	return true;
916177ecc46SClemens Zeidler}
917177ecc46SClemens Zeidler
918177ecc46SClemens Zeidler
919177ecc46SClemens Zeidlervoid
920177ecc46SClemens ZeidlerDefaultWindowBehaviour::MouseUp(BMessage* message, BPoint where)
921177ecc46SClemens Zeidler{
92252cac2e7SIngo Weinhold	if (fState != NULL)
92352cac2e7SIngo Weinhold		fState->MouseUp(message, where);
924177ecc46SClemens Zeidler}
925177ecc46SClemens Zeidler
926177ecc46SClemens Zeidler
927177ecc46SClemens Zeidlervoid
928006f7485SIngo WeinholdDefaultWindowBehaviour::MouseMoved(BMessage* message, BPoint where, bool isFake)
929177ecc46SClemens Zeidler{
930006f7485SIngo Weinhold	if (fState != NULL) {
93152cac2e7SIngo Weinhold		fState->MouseMoved(message, where, isFake);
932006f7485SIngo Weinhold	} else {
933006f7485SIngo Weinhold		// If the window modifiers are hold, enter the window management state.
934006f7485SIngo Weinhold		if (_IsWindowModifier(message->FindInt32("modifiers")))
935006f7485SIngo Weinhold			_NextState(new(std::nothrow) ManageWindowState(*this, where));
936006f7485SIngo Weinhold	}
9372ee2a8edSIngo Weinhold
9382ee2a8edSIngo Weinhold	// change focus in FFM mode
9392ee2a8edSIngo Weinhold	DesktopSettings desktopSettings(fDesktop);
9402ee2a8edSIngo Weinhold	if (desktopSettings.FocusFollowsMouse()
9418f449285SJohn Scipione		&& !fWindow->IsFocus() && (fWindow->Flags() & B_AVOID_FOCUS) == 0) {
9422ee2a8edSIngo Weinhold		// If the mouse move is a fake one, we set the focus to NULL, which
9432ee2a8edSIngo Weinhold		// will cause the window that had focus last to retrieve it again - this
9442ee2a8edSIngo Weinhold		// makes FFM much nicer to use with the keyboard.
9452ee2a8edSIngo Weinhold		fDesktop->SetFocusWindow(isFake ? NULL : fWindow);
9462ee2a8edSIngo Weinhold	}
947177ecc46SClemens Zeidler}
948177ecc46SClemens Zeidler
949177ecc46SClemens Zeidler
95076107eebSIngo Weinholdvoid
95176107eebSIngo WeinholdDefaultWindowBehaviour::ModifiersChanged(int32 modifiers)
95276107eebSIngo Weinhold{
953006f7485SIngo Weinhold	BPoint where;
954006f7485SIngo Weinhold	int32 buttons;
955006f7485SIngo Weinhold	fDesktop->GetLastMouseState(&where, &buttons);
956006f7485SIngo Weinhold
957006f7485SIngo Weinhold	if (fState != NULL) {
958006f7485SIngo Weinhold		fState->ModifiersChanged(where, modifiers);
959006f7485SIngo Weinhold	} else {
960006f7485SIngo Weinhold		// If the window modifiers are hold, enter the window management state.
961006f7485SIngo Weinhold		if (_IsWindowModifier(modifiers))
962006f7485SIngo Weinhold			_NextState(new(std::nothrow) ManageWindowState(*this, where));
963006f7485SIngo Weinhold	}
96476107eebSIngo Weinhold}
96576107eebSIngo Weinhold
96676107eebSIngo Weinhold
967b91ddd81SClemens Zeidlerbool
968b91ddd81SClemens ZeidlerDefaultWindowBehaviour::AlterDeltaForSnap(Window* window, BPoint& delta,
969b91ddd81SClemens Zeidler	bigtime_t now)
970b91ddd81SClemens Zeidler{
971b91ddd81SClemens Zeidler	return fMagneticBorder.AlterDeltaForSnap(window, delta, now);
972b91ddd81SClemens Zeidler}
973b91ddd81SClemens Zeidler
974b91ddd81SClemens Zeidler
975d45bbb64SAxel Dörflerbool
976d45bbb64SAxel DörflerDefaultWindowBehaviour::_IsWindowModifier(int32 modifiers) const
977177ecc46SClemens Zeidler{
978d45bbb64SAxel Dörfler	return (fWindow->Flags() & B_NO_SERVER_SIDE_WINDOW_MODIFIERS) == 0
979d45bbb64SAxel Dörfler		&& (modifiers & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY
980d45bbb64SAxel Dörfler				| B_SHIFT_KEY)) == (B_COMMAND_KEY | B_CONTROL_KEY);
981177ecc46SClemens Zeidler}
982177ecc46SClemens Zeidler
983177ecc46SClemens Zeidler
984006f7485SIngo WeinholdDecorator::Region
985bb2e9b06SClemens ZeidlerDefaultWindowBehaviour::_RegionFor(const BMessage* message, int32& tab) const
986177ecc46SClemens Zeidler{
98730c31ae2SClemens Zeidler	Decorator* decorator = fWindow->Decorator();
98830c31ae2SClemens Zeidler	if (decorator == NULL)
989006f7485SIngo Weinhold		return Decorator::REGION_NONE;
990177ecc46SClemens Zeidler
991177ecc46SClemens Zeidler	BPoint where;
992177ecc46SClemens Zeidler	if (message->FindPoint("where", &where) != B_OK)
993006f7485SIngo Weinhold		return Decorator::REGION_NONE;
99489d652d5SIngo Weinhold
995bb2e9b06SClemens Zeidler	return decorator->RegionAt(where, tab);
996006f7485SIngo Weinhold}
997177ecc46SClemens Zeidler
99889d652d5SIngo Weinhold
999006f7485SIngo Weinholdvoid
1000006f7485SIngo WeinholdDefaultWindowBehaviour::_SetBorderHighlights(int8 horizontal, int8 vertical,
1001006f7485SIngo Weinhold	bool active)
1002006f7485SIngo Weinhold{
1003006f7485SIngo Weinhold	if (Decorator* decorator = fWindow->Decorator()) {
1004006f7485SIngo Weinhold		uint8 highlight = active
1005006f7485SIngo Weinhold			? Decorator::HIGHLIGHT_RESIZE_BORDER
1006006f7485SIngo Weinhold			: Decorator::HIGHLIGHT_NONE;
1007006f7485SIngo Weinhold
1008006f7485SIngo Weinhold		// set the highlights for the borders
1009006f7485SIngo Weinhold		BRegion dirtyRegion;
1010006f7485SIngo Weinhold		switch (horizontal) {
1011006f7485SIngo Weinhold			case LEFT:
1012006f7485SIngo Weinhold				decorator->SetRegionHighlight(Decorator::REGION_LEFT_BORDER,
1013006f7485SIngo Weinhold					highlight, &dirtyRegion);
1014006f7485SIngo Weinhold				break;
1015006f7485SIngo Weinhold			case RIGHT:
1016006f7485SIngo Weinhold				decorator->SetRegionHighlight(
1017006f7485SIngo Weinhold					Decorator::REGION_RIGHT_BORDER, highlight,
1018006f7485SIngo Weinhold					&dirtyRegion);
1019006f7485SIngo Weinhold				break;
1020006f7485SIngo Weinhold		}
102189d652d5SIngo Weinhold
1022006f7485SIngo Weinhold		switch (vertical) {
1023006f7485SIngo Weinhold			case TOP:
1024006f7485SIngo Weinhold				decorator->SetRegionHighlight(Decorator::REGION_TOP_BORDER,
1025006f7485SIngo Weinhold					highlight, &dirtyRegion);
1026006f7485SIngo Weinhold				break;
1027006f7485SIngo Weinhold			case BOTTOM:
1028006f7485SIngo Weinhold				decorator->SetRegionHighlight(
1029006f7485SIngo Weinhold					Decorator::REGION_BOTTOM_BORDER, highlight,
1030006f7485SIngo Weinhold					&dirtyRegion);
1031006f7485SIngo Weinhold				break;
1032006f7485SIngo Weinhold		}
103389d652d5SIngo Weinhold
1034006f7485SIngo Weinhold		// set the highlights for the corners
1035006f7485SIngo Weinhold		if (horizontal != NONE && vertical != NONE) {
1036006f7485SIngo Weinhold			if (horizontal == LEFT) {
1037006f7485SIngo Weinhold				if (vertical == TOP) {
1038006f7485SIngo Weinhold					decorator->SetRegionHighlight(
1039006f7485SIngo Weinhold						Decorator::REGION_LEFT_TOP_CORNER, highlight,
1040006f7485SIngo Weinhold						&dirtyRegion);
1041006f7485SIngo Weinhold				} else {
1042006f7485SIngo Weinhold					decorator->SetRegionHighlight(
1043006f7485SIngo Weinhold						Decorator::REGION_LEFT_BOTTOM_CORNER, highlight,
1044006f7485SIngo Weinhold						&dirtyRegion);
1045006f7485SIngo Weinhold				}
1046006f7485SIngo Weinhold			} else {
1047006f7485SIngo Weinhold				if (vertical == TOP) {
1048006f7485SIngo Weinhold					decorator->SetRegionHighlight(
1049006f7485SIngo Weinhold						Decorator::REGION_RIGHT_TOP_CORNER, highlight,
1050006f7485SIngo Weinhold						&dirtyRegion);
1051006f7485SIngo Weinhold				} else {
1052006f7485SIngo Weinhold					decorator->SetRegionHighlight(
1053006f7485SIngo Weinhold						Decorator::REGION_RIGHT_BOTTOM_CORNER, highlight,
1054006f7485SIngo Weinhold						&dirtyRegion);
1055006f7485SIngo Weinhold				}
1056006f7485SIngo Weinhold			}
1057006f7485SIngo Weinhold		}
105889d652d5SIngo Weinhold
1059006f7485SIngo Weinhold		// invalidate the affected regions
1060dc2dd40cSClemens Zeidler		fWindow->ProcessDirtyRegion(dirtyRegion);
106189d652d5SIngo Weinhold	}
1062177ecc46SClemens Zeidler}
1063177ecc46SClemens Zeidler
1064177ecc46SClemens Zeidler
106597d62304SIngo WeinholdServerCursor*
106697d62304SIngo WeinholdDefaultWindowBehaviour::_ResizeCursorFor(int8 horizontal, int8 vertical)
106797d62304SIngo Weinhold{
106897d62304SIngo Weinhold	// get the cursor ID corresponding to the border/corner
106997d62304SIngo Weinhold	BCursorID cursorID = B_CURSOR_ID_SYSTEM_DEFAULT;
107097d62304SIngo Weinhold
107197d62304SIngo Weinhold	if (horizontal == LEFT) {
107297d62304SIngo Weinhold		if (vertical == TOP)
107397d62304SIngo Weinhold			cursorID = B_CURSOR_ID_RESIZE_NORTH_WEST;
107497d62304SIngo Weinhold		else if (vertical == BOTTOM)
107597d62304SIngo Weinhold			cursorID = B_CURSOR_ID_RESIZE_SOUTH_WEST;
107697d62304SIngo Weinhold		else
107797d62304SIngo Weinhold			cursorID = B_CURSOR_ID_RESIZE_WEST;
107897d62304SIngo Weinhold	} else if (horizontal == RIGHT) {
107997d62304SIngo Weinhold		if (vertical == TOP)
108097d62304SIngo Weinhold			cursorID = B_CURSOR_ID_RESIZE_NORTH_EAST;
108197d62304SIngo Weinhold		else if (vertical == BOTTOM)
108297d62304SIngo Weinhold			cursorID = B_CURSOR_ID_RESIZE_SOUTH_EAST;
108397d62304SIngo Weinhold		else
108497d62304SIngo Weinhold			cursorID = B_CURSOR_ID_RESIZE_EAST;
108597d62304SIngo Weinhold	} else {
108697d62304SIngo Weinhold		if (vertical == TOP)
108797d62304SIngo Weinhold			cursorID = B_CURSOR_ID_RESIZE_NORTH;
108897d62304SIngo Weinhold		else if (vertical == BOTTOM)
108997d62304SIngo Weinhold			cursorID = B_CURSOR_ID_RESIZE_SOUTH;
109097d62304SIngo Weinhold	}
109197d62304SIngo Weinhold
109297d62304SIngo Weinhold	return fDesktop->GetCursorManager().GetCursor(cursorID);
109397d62304SIngo Weinhold}
109497d62304SIngo Weinhold
109597d62304SIngo Weinhold
109697d62304SIngo Weinholdvoid
109797d62304SIngo WeinholdDefaultWindowBehaviour::_SetResizeCursor(int8 horizontal, int8 vertical)
109897d62304SIngo Weinhold{
109997d62304SIngo Weinhold	fDesktop->SetManagementCursor(_ResizeCursorFor(horizontal, vertical));
110097d62304SIngo Weinhold}
110197d62304SIngo Weinhold
110297d62304SIngo Weinhold
110397d62304SIngo Weinholdvoid
110497d62304SIngo WeinholdDefaultWindowBehaviour::_ResetResizeCursor()
110597d62304SIngo Weinhold{
110697d62304SIngo Weinhold	fDesktop->SetManagementCursor(NULL);
110797d62304SIngo Weinhold}
11089f1aca35SIngo Weinhold
11099f1aca35SIngo Weinhold
11109f1aca35SIngo Weinhold/*static*/ void
11119f1aca35SIngo WeinholdDefaultWindowBehaviour::_ComputeResizeDirection(float x, float y,
11129f1aca35SIngo Weinhold	int8& _horizontal, int8& _vertical)
11139f1aca35SIngo Weinhold{
11149f1aca35SIngo Weinhold	_horizontal = NONE;
11159f1aca35SIngo Weinhold	_vertical = NONE;
11169f1aca35SIngo Weinhold
11179f1aca35SIngo Weinhold	// compute the angle
11189f1aca35SIngo Weinhold	if (x == 0 && y == 0)
11199f1aca35SIngo Weinhold		return;
11209f1aca35SIngo Weinhold
11219f1aca35SIngo Weinhold	float angle = atan2f(y, x);
11229f1aca35SIngo Weinhold
11239f1aca35SIngo Weinhold	// rotate by 22.5 degree to align our sectors with 45 degree multiples
11249f1aca35SIngo Weinhold	angle += M_PI / 8;
11259f1aca35SIngo Weinhold
11269f1aca35SIngo Weinhold	// add 180 degree to the negative values, so we get a nice 0 to 360
11279f1aca35SIngo Weinhold	// degree range
11289f1aca35SIngo Weinhold	if (angle < 0)
11299f1aca35SIngo Weinhold		angle += M_PI * 2;
11309f1aca35SIngo Weinhold
11319f1aca35SIngo Weinhold	switch (int(angle / M_PI_4)) {
11329f1aca35SIngo Weinhold		case 0:
11339f1aca35SIngo Weinhold			_horizontal = RIGHT;
11349f1aca35SIngo Weinhold			break;
11359f1aca35SIngo Weinhold		case 1:
11369f1aca35SIngo Weinhold			_horizontal = RIGHT;
11379f1aca35SIngo Weinhold			_vertical = BOTTOM;
11389f1aca35SIngo Weinhold			break;
11399f1aca35SIngo Weinhold		case 2:
11409f1aca35SIngo Weinhold			_vertical = BOTTOM;
11419f1aca35SIngo Weinhold			break;
11429f1aca35SIngo Weinhold		case 3:
11439f1aca35SIngo Weinhold			_horizontal = LEFT;
11449f1aca35SIngo Weinhold			_vertical = BOTTOM;
11459f1aca35SIngo Weinhold			break;
11469f1aca35SIngo Weinhold		case 4:
11479f1aca35SIngo Weinhold			_horizontal = LEFT;
11489f1aca35SIngo Weinhold			break;
11499f1aca35SIngo Weinhold		case 5:
11509f1aca35SIngo Weinhold			_horizontal = LEFT;
11519f1aca35SIngo Weinhold			_vertical = TOP;
11529f1aca35SIngo Weinhold			break;
11539f1aca35SIngo Weinhold		case 6:
11549f1aca35SIngo Weinhold			_vertical = TOP;
11559f1aca35SIngo Weinhold			break;
11569f1aca35SIngo Weinhold		case 7:
11579f1aca35SIngo Weinhold		default:
11589f1aca35SIngo Weinhold			_horizontal = RIGHT;
11599f1aca35SIngo Weinhold			_vertical = TOP;
11609f1aca35SIngo Weinhold			break;
11619f1aca35SIngo Weinhold	}
11629f1aca35SIngo Weinhold}
11639f1aca35SIngo Weinhold
11649f1aca35SIngo Weinhold
11659f1aca35SIngo Weinholdvoid
11669f1aca35SIngo WeinholdDefaultWindowBehaviour::_NextState(State* state)
11679f1aca35SIngo Weinhold{
11689f1aca35SIngo Weinhold	// exit the old state
11699f1aca35SIngo Weinhold	if (fState != NULL)
11709f1aca35SIngo Weinhold		fState->ExitState(state);
11719f1aca35SIngo Weinhold
11729f1aca35SIngo Weinhold	// set and enter the new state
11739f1aca35SIngo Weinhold	State* oldState = fState;
11749f1aca35SIngo Weinhold	fState = state;
11759f1aca35SIngo Weinhold
11769f1aca35SIngo Weinhold	if (fState != NULL) {
11779f1aca35SIngo Weinhold		fState->EnterState(oldState);
11789f1aca35SIngo Weinhold		fDesktop->SetMouseEventWindow(fWindow);
11799f1aca35SIngo Weinhold	} else if (oldState != NULL) {
11809f1aca35SIngo Weinhold		// no state anymore -- reset the mouse event window, if it's still us
11819f1aca35SIngo Weinhold		if (fDesktop->MouseEventWindow() == fWindow)
11829f1aca35SIngo Weinhold			fDesktop->SetMouseEventWindow(NULL);
11839f1aca35SIngo Weinhold	}
11849f1aca35SIngo Weinhold
11859f1aca35SIngo Weinhold	delete oldState;
11869f1aca35SIngo Weinhold}
1187