1b960e451SClemens Zeidler/*
2b960e451SClemens Zeidler * Copyright 2010, Haiku.
3b960e451SClemens Zeidler * Distributed under the terms of the MIT License.
4b960e451SClemens Zeidler *
5b960e451SClemens Zeidler * Authors:
6b960e451SClemens Zeidler *		Clemens Zeidler <haiku@clemens-zeidler.de>
7b960e451SClemens Zeidler */
8b960e451SClemens Zeidler
9b960e451SClemens Zeidler#include "Stacking.h"
10b960e451SClemens Zeidler
11b960e451SClemens Zeidler#include <Debug.h>
12b960e451SClemens Zeidler
1319f43b9fSClemens Zeidler#include "StackAndTilePrivate.h"
1419f43b9fSClemens Zeidler
156a0ed7daSClemens Zeidler#include "Desktop.h"
16b960e451SClemens Zeidler#include "SATWindow.h"
17b960e451SClemens Zeidler#include "Window.h"
18b960e451SClemens Zeidler
19b960e451SClemens Zeidler
2001d68c97SClemens Zeidler//#define DEBUG_STACKING
21b960e451SClemens Zeidler
22b960e451SClemens Zeidler#ifdef DEBUG_STACKING
23b960e451SClemens Zeidler#	define STRACE_STACKING(x...) debug_printf("SAT Stacking: "x)
24b960e451SClemens Zeidler#else
25b960e451SClemens Zeidler#	define STRACE_STACKING(x...) ;
26b960e451SClemens Zeidler#endif
27b960e451SClemens Zeidler
28b960e451SClemens Zeidler
2919f43b9fSClemens Zeidlerusing namespace BPrivate;
3019f43b9fSClemens Zeidler
3119f43b9fSClemens Zeidler
3219f43b9fSClemens Zeidlerbool
3319f43b9fSClemens ZeidlerStackingEventHandler::HandleMessage(SATWindow* sender,
349ff327deSClemens Zeidler	BPrivate::LinkReceiver& link, BPrivate::LinkSender& reply)
3519f43b9fSClemens Zeidler{
3619f43b9fSClemens Zeidler	Desktop* desktop = sender->GetDesktop();
3719f43b9fSClemens Zeidler	StackAndTile* stackAndTile = sender->GetStackAndTile();
3819f43b9fSClemens Zeidler
3919f43b9fSClemens Zeidler	int32 what;
4019f43b9fSClemens Zeidler	link.Read<int32>(&what);
4119f43b9fSClemens Zeidler
4219f43b9fSClemens Zeidler	switch (what) {
4319f43b9fSClemens Zeidler		case kAddWindowToStack:
4419f43b9fSClemens Zeidler		{
4519f43b9fSClemens Zeidler			port_id port;
4619f43b9fSClemens Zeidler			int32 token;
4719f43b9fSClemens Zeidler			team_id team;
4819f43b9fSClemens Zeidler			link.Read<port_id>(&port);
4919f43b9fSClemens Zeidler			link.Read<int32>(&token);
5019f43b9fSClemens Zeidler			link.Read<team_id>(&team);
5119f43b9fSClemens Zeidler			int32 position;
5219f43b9fSClemens Zeidler			if (link.Read<int32>(&position) != B_OK)
5319f43b9fSClemens Zeidler				return false;
5419f43b9fSClemens Zeidler
5519f43b9fSClemens Zeidler			WindowArea* area = sender->GetWindowArea();
5619f43b9fSClemens Zeidler			if (!area)
5719f43b9fSClemens Zeidler				return false;
5819f43b9fSClemens Zeidler			if (position < 0)
5919f43b9fSClemens Zeidler				position = area->WindowList().CountItems() - 1;
6019f43b9fSClemens Zeidler
6119f43b9fSClemens Zeidler			SATWindow* parent = area->WindowList().ItemAt(position);
6219f43b9fSClemens Zeidler			Window* window = desktop->WindowForClientLooperPort(port);
6319f43b9fSClemens Zeidler			if (!parent || !window) {
649ff327deSClemens Zeidler				reply.StartMessage(B_BAD_VALUE);
659ff327deSClemens Zeidler				reply.Flush();
6619f43b9fSClemens Zeidler				break;
6719f43b9fSClemens Zeidler			}
6819f43b9fSClemens Zeidler
6919f43b9fSClemens Zeidler			SATWindow* candidate = stackAndTile->GetSATWindow(window);
7019f43b9fSClemens Zeidler			if (!candidate)
7119f43b9fSClemens Zeidler				return false;
7219f43b9fSClemens Zeidler			if (!parent->StackWindow(candidate))
7319f43b9fSClemens Zeidler				return false;
7419f43b9fSClemens Zeidler
759ff327deSClemens Zeidler			reply.StartMessage(B_OK);
769ff327deSClemens Zeidler			reply.Flush();
7719f43b9fSClemens Zeidler			break;
7819f43b9fSClemens Zeidler		}
7919f43b9fSClemens Zeidler		case kRemoveWindowFromStack:
8019f43b9fSClemens Zeidler		{
8119f43b9fSClemens Zeidler			port_id port;
8219f43b9fSClemens Zeidler			int32 token;
8319f43b9fSClemens Zeidler			team_id team;
8419f43b9fSClemens Zeidler			link.Read<port_id>(&port);
8519f43b9fSClemens Zeidler			link.Read<int32>(&token);
8619f43b9fSClemens Zeidler			if (link.Read<team_id>(&team) != B_OK)
8719f43b9fSClemens Zeidler				return false;
8819f43b9fSClemens Zeidler
8919f43b9fSClemens Zeidler			SATGroup* group = sender->GetGroup();
9019f43b9fSClemens Zeidler			if (!group)
9119f43b9fSClemens Zeidler				return false;
9219f43b9fSClemens Zeidler
9319f43b9fSClemens Zeidler			Window* window = desktop->WindowForClientLooperPort(port);
9419f43b9fSClemens Zeidler			if (!window) {
959ff327deSClemens Zeidler				reply.StartMessage(B_BAD_VALUE);
969ff327deSClemens Zeidler				reply.Flush();
9719f43b9fSClemens Zeidler				break;
9819f43b9fSClemens Zeidler			}
9919f43b9fSClemens Zeidler			SATWindow* candidate = stackAndTile->GetSATWindow(window);
10019f43b9fSClemens Zeidler			if (!candidate)
10119f43b9fSClemens Zeidler				return false;
102f149f7aaSClemens Zeidler			if (!group->RemoveWindow(candidate, false))
10319f43b9fSClemens Zeidler				return false;
10419f43b9fSClemens Zeidler			break;
10519f43b9fSClemens Zeidler		}
10619f43b9fSClemens Zeidler		case kRemoveWindowFromStackAt:
10719f43b9fSClemens Zeidler		{
10819f43b9fSClemens Zeidler			int32 position;
10919f43b9fSClemens Zeidler			if (link.Read<int32>(&position) != B_OK)
11019f43b9fSClemens Zeidler				return false;
11119f43b9fSClemens Zeidler			SATGroup* group = sender->GetGroup();
11219f43b9fSClemens Zeidler			WindowArea* area = sender->GetWindowArea();
11319f43b9fSClemens Zeidler			if (!area || !group)
11419f43b9fSClemens Zeidler				return false;
11519f43b9fSClemens Zeidler			SATWindow* removeWindow = area->WindowList().ItemAt(position);
11619f43b9fSClemens Zeidler			if (!removeWindow) {
1179ff327deSClemens Zeidler				reply.StartMessage(B_BAD_VALUE);
1189ff327deSClemens Zeidler				reply.Flush();
11919f43b9fSClemens Zeidler				break;
12019f43b9fSClemens Zeidler			}
12119f43b9fSClemens Zeidler
122f149f7aaSClemens Zeidler			if (!group->RemoveWindow(removeWindow, false))
12319f43b9fSClemens Zeidler				return false;
12419f43b9fSClemens Zeidler
12519f43b9fSClemens Zeidler			ServerWindow* window = removeWindow->GetWindow()->ServerWindow();
1269ff327deSClemens Zeidler			reply.StartMessage(B_OK);
1279ff327deSClemens Zeidler			reply.Attach<port_id>(window->ClientLooperPort());
1289ff327deSClemens Zeidler			reply.Attach<int32>(window->ClientToken());
1299ff327deSClemens Zeidler			reply.Attach<team_id>(window->ClientTeam());
1309ff327deSClemens Zeidler			reply.Flush();
13119f43b9fSClemens Zeidler			break;
13219f43b9fSClemens Zeidler		}
13319f43b9fSClemens Zeidler		case kCountWindowsOnStack:
13419f43b9fSClemens Zeidler		{
13519f43b9fSClemens Zeidler			WindowArea* area = sender->GetWindowArea();
13619f43b9fSClemens Zeidler			if (!area)
13719f43b9fSClemens Zeidler				return false;
1389ff327deSClemens Zeidler			reply.StartMessage(B_OK);
1399ff327deSClemens Zeidler			reply.Attach<int32>(area->WindowList().CountItems());
1409ff327deSClemens Zeidler			reply.Flush();
14119f43b9fSClemens Zeidler			break;
14219f43b9fSClemens Zeidler		}
14319f43b9fSClemens Zeidler		case kWindowOnStackAt:
14419f43b9fSClemens Zeidler		{
14519f43b9fSClemens Zeidler			int32 position;
14619f43b9fSClemens Zeidler			if (link.Read<int32>(&position) != B_OK)
14719f43b9fSClemens Zeidler				return false;
14819f43b9fSClemens Zeidler			WindowArea* area = sender->GetWindowArea();
14919f43b9fSClemens Zeidler			if (!area)
15019f43b9fSClemens Zeidler				return false;
15119f43b9fSClemens Zeidler			SATWindow* satWindow = area->WindowList().ItemAt(position);
15219f43b9fSClemens Zeidler			if (!satWindow) {
1539ff327deSClemens Zeidler				reply.StartMessage(B_BAD_VALUE);
1549ff327deSClemens Zeidler				reply.Flush();
15519f43b9fSClemens Zeidler				break;
15619f43b9fSClemens Zeidler			}
15719f43b9fSClemens Zeidler
15819f43b9fSClemens Zeidler			ServerWindow* window = satWindow->GetWindow()->ServerWindow();
1599ff327deSClemens Zeidler			reply.StartMessage(B_OK);
1609ff327deSClemens Zeidler			reply.Attach<port_id>(window->ClientLooperPort());
1619ff327deSClemens Zeidler			reply.Attach<int32>(window->ClientToken());
1629ff327deSClemens Zeidler			reply.Attach<team_id>(window->ClientTeam());
1639ff327deSClemens Zeidler			reply.Flush();
16419f43b9fSClemens Zeidler			break;
16519f43b9fSClemens Zeidler		}
16619f43b9fSClemens Zeidler		case kStackHasWindow:
16719f43b9fSClemens Zeidler		{
16819f43b9fSClemens Zeidler			port_id port;
16919f43b9fSClemens Zeidler			int32 token;
17019f43b9fSClemens Zeidler			team_id team;
17119f43b9fSClemens Zeidler			link.Read<port_id>(&port);
17219f43b9fSClemens Zeidler			link.Read<int32>(&token);
17319f43b9fSClemens Zeidler			if (link.Read<team_id>(&team) != B_OK)
17419f43b9fSClemens Zeidler				return false;
17519f43b9fSClemens Zeidler
17619f43b9fSClemens Zeidler			Window* window = desktop->WindowForClientLooperPort(port);
17719f43b9fSClemens Zeidler			if (!window) {
1789ff327deSClemens Zeidler				reply.StartMessage(B_BAD_VALUE);
1799ff327deSClemens Zeidler				reply.Flush();
18019f43b9fSClemens Zeidler				break;
18119f43b9fSClemens Zeidler			}
18219f43b9fSClemens Zeidler			SATWindow* candidate = stackAndTile->GetSATWindow(window);
18319f43b9fSClemens Zeidler			if (!candidate)
18419f43b9fSClemens Zeidler				return false;
18519f43b9fSClemens Zeidler
18619f43b9fSClemens Zeidler			WindowArea* area = sender->GetWindowArea();
18719f43b9fSClemens Zeidler			if (!area)
18819f43b9fSClemens Zeidler				return false;
1899ff327deSClemens Zeidler			reply.StartMessage(B_OK);
1909ff327deSClemens Zeidler			reply.Attach<bool>(area->WindowList().HasItem(candidate));
1919ff327deSClemens Zeidler			reply.Flush();
19219f43b9fSClemens Zeidler			break;
19319f43b9fSClemens Zeidler		}
19419f43b9fSClemens Zeidler		default:
19519f43b9fSClemens Zeidler			return false;
19619f43b9fSClemens Zeidler	}
19719f43b9fSClemens Zeidler	return true;
19819f43b9fSClemens Zeidler}
19919f43b9fSClemens Zeidler
20019f43b9fSClemens Zeidler
201b960e451SClemens ZeidlerSATStacking::SATStacking(SATWindow* window)
202b960e451SClemens Zeidler	:
203b960e451SClemens Zeidler	fSATWindow(window),
204007179caSClemens Zeidler	fStackingParent(NULL)
205b960e451SClemens Zeidler{
206df4074fbSAugustin Cavalier
207b960e451SClemens Zeidler}
208b960e451SClemens Zeidler
209b960e451SClemens Zeidler
210b960e451SClemens ZeidlerSATStacking::~SATStacking()
211b960e451SClemens Zeidler{
212df4074fbSAugustin Cavalier
213b960e451SClemens Zeidler}
214b960e451SClemens Zeidler
215b960e451SClemens Zeidler
216b960e451SClemens Zeidlerbool
217b960e451SClemens ZeidlerSATStacking::FindSnappingCandidates(SATGroup* group)
218b960e451SClemens Zeidler{
219b960e451SClemens Zeidler	_ClearSearchResult();
220b960e451SClemens Zeidler
221b960e451SClemens Zeidler	Window* window = fSATWindow->GetWindow();
222007179caSClemens Zeidler	if (!window->Decorator())
223007179caSClemens Zeidler		return false;
224007179caSClemens Zeidler
225007179caSClemens Zeidler	BPoint mousePosition;
226007179caSClemens Zeidler	int32 buttons;
227007179caSClemens Zeidler	fSATWindow->GetDesktop()->GetLastMouseState(&mousePosition, &buttons);
228bdfe478eSClemens Zeidler	if (!window->Decorator()->TitleBarRect().Contains(mousePosition))
22907a8c146SClemens Zeidler		return false;
23007a8c146SClemens Zeidler
231007179caSClemens Zeidler	// use the upper edge of the candidate window to find the parent window
232bdfe478eSClemens Zeidler	mousePosition.y = window->Decorator()->TitleBarRect().top;
233b960e451SClemens Zeidler
234b960e451SClemens Zeidler	for (int i = 0; i < group->CountItems(); i++) {
235b960e451SClemens Zeidler		SATWindow* satWindow = group->WindowAt(i);
236007179caSClemens Zeidler		// search for stacking parent
237e0bc3d9eSClemens Zeidler		Window* parentWindow = satWindow->GetWindow();
238e0bc3d9eSClemens Zeidler		if (parentWindow == window || parentWindow->Decorator() == NULL)
239007179caSClemens Zeidler			continue;
240e0bc3d9eSClemens Zeidler		if (_IsStackableWindow(parentWindow) == false
2417c5525e8SClemens Zeidler			|| _IsStackableWindow(window) == false)
2427c5525e8SClemens Zeidler			continue;
243e0bc3d9eSClemens Zeidler		Decorator::Tab* tab = parentWindow->Decorator()->TabAt(
244e0bc3d9eSClemens Zeidler			parentWindow->PositionInStack());
245bdfe478eSClemens Zeidler		if (tab == NULL)
246bdfe478eSClemens Zeidler			continue;
247bdfe478eSClemens Zeidler		if (tab->tabRect.Contains(mousePosition)) {
248007179caSClemens Zeidler			// remember window as the parent for stacking
249007179caSClemens Zeidler			fStackingParent = satWindow;
250b960e451SClemens Zeidler			_HighlightWindows(true);
251b960e451SClemens Zeidler			return true;
252b960e451SClemens Zeidler		}
253b960e451SClemens Zeidler	}
254b960e451SClemens Zeidler
255b960e451SClemens Zeidler	return false;
256b960e451SClemens Zeidler}
257b960e451SClemens Zeidler
258b960e451SClemens Zeidler
259b960e451SClemens Zeidlerbool
260b960e451SClemens ZeidlerSATStacking::JoinCandidates()
261b960e451SClemens Zeidler{
262007179caSClemens Zeidler	if (!fStackingParent)
263b960e451SClemens Zeidler		return false;
264b960e451SClemens Zeidler
265007179caSClemens Zeidler	bool result = fStackingParent->StackWindow(fSATWindow);
266b960e451SClemens Zeidler
267b960e451SClemens Zeidler	_ClearSearchResult();
26819f43b9fSClemens Zeidler	return result;
269b960e451SClemens Zeidler}
270b960e451SClemens Zeidler
271b960e451SClemens Zeidler
272b960e451SClemens Zeidlervoid
273b960e451SClemens ZeidlerSATStacking::RemovedFromArea(WindowArea* area)
274b960e451SClemens Zeidler{
275b960e451SClemens Zeidler	const SATWindowList& list = area->WindowList();
276bdfe478eSClemens Zeidler	if (list.CountItems() > 0)
277b960e451SClemens Zeidler		list.ItemAt(0)->DoGroupLayout();
278b960e451SClemens Zeidler}
279b960e451SClemens Zeidler
280b960e451SClemens Zeidler
2817c5525e8SClemens Zeidlervoid
2827c5525e8SClemens ZeidlerSATStacking::WindowLookChanged(window_look look)
2837c5525e8SClemens Zeidler{
2847c5525e8SClemens Zeidler	Window* window = fSATWindow->GetWindow();
2857c5525e8SClemens Zeidler	WindowStack* stack = window->GetWindowStack();
2867c5525e8SClemens Zeidler	if (stack == NULL)
2877c5525e8SClemens Zeidler		return;
2887c5525e8SClemens Zeidler	SATGroup* group = fSATWindow->GetGroup();
2897c5525e8SClemens Zeidler	if (group == NULL)
2907c5525e8SClemens Zeidler		return;
2917c5525e8SClemens Zeidler	if (stack->CountWindows() > 1 && _IsStackableWindow(window) == false)
2927c5525e8SClemens Zeidler		group->RemoveWindow(fSATWindow);
2937c5525e8SClemens Zeidler}
2947c5525e8SClemens Zeidler
2957c5525e8SClemens Zeidler
2967c5525e8SClemens Zeidlerbool
2977c5525e8SClemens ZeidlerSATStacking::_IsStackableWindow(Window* window)
2987c5525e8SClemens Zeidler{
2997c5525e8SClemens Zeidler	if (window->Look() == B_DOCUMENT_WINDOW_LOOK)
3007c5525e8SClemens Zeidler		return true;
3017c5525e8SClemens Zeidler	if (window->Look() == B_TITLED_WINDOW_LOOK)
3027c5525e8SClemens Zeidler		return true;
3037c5525e8SClemens Zeidler	return false;
3047c5525e8SClemens Zeidler}
3057c5525e8SClemens Zeidler
3067c5525e8SClemens Zeidler
307b960e451SClemens Zeidlervoid
308b960e451SClemens ZeidlerSATStacking::_ClearSearchResult()
309b960e451SClemens Zeidler{
310007179caSClemens Zeidler	if (!fStackingParent)
311b960e451SClemens Zeidler		return;
312b960e451SClemens Zeidler
313b960e451SClemens Zeidler	_HighlightWindows(false);
314007179caSClemens Zeidler	fStackingParent = NULL;
315b960e451SClemens Zeidler}
316b960e451SClemens Zeidler
317b960e451SClemens Zeidler
318b960e451SClemens Zeidlervoid
319b960e451SClemens ZeidlerSATStacking::_HighlightWindows(bool highlight)
320b960e451SClemens Zeidler{
321b960e451SClemens Zeidler	Desktop* desktop = fSATWindow->GetWindow()->Desktop();
322b960e451SClemens Zeidler	if (!desktop)
323b960e451SClemens Zeidler		return;
324007179caSClemens Zeidler	fStackingParent->HighlightTab(highlight);
325b960e451SClemens Zeidler	fSATWindow->HighlightTab(highlight);
326b960e451SClemens Zeidler}
327