xref: /haiku/src/servers/app/stackandtile/Stacking.cpp (revision cbe0a0c436162d78cc3f92a305b64918c839d079)
1 /*
2  * Copyright 2010, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Clemens Zeidler <haiku@clemens-zeidler.de>
7  */
8 
9 #include "Stacking.h"
10 
11 #include <Debug.h>
12 
13 #include "StackAndTilePrivate.h"
14 
15 #include "Desktop.h"
16 #include "SATWindow.h"
17 #include "Window.h"
18 
19 
20 //#define DEBUG_STACKING
21 
22 #ifdef DEBUG_STACKING
23 #	define STRACE_STACKING(x...) debug_printf("SAT Stacking: "x)
24 #else
25 #	define STRACE_STACKING(x...) ;
26 #endif
27 
28 
29 using namespace BPrivate;
30 
31 
32 bool
33 StackingEventHandler::HandleMessage(SATWindow* sender,
34 	BPrivate::LinkReceiver& link, BPrivate::LinkSender& reply)
35 {
36 	Desktop* desktop = sender->GetDesktop();
37 	StackAndTile* stackAndTile = sender->GetStackAndTile();
38 
39 	int32 what;
40 	link.Read<int32>(&what);
41 
42 	switch (what) {
43 		case kAddWindowToStack:
44 		{
45 			port_id port;
46 			int32 token;
47 			team_id team;
48 			link.Read<port_id>(&port);
49 			link.Read<int32>(&token);
50 			link.Read<team_id>(&team);
51 			int32 position;
52 			if (link.Read<int32>(&position) != B_OK)
53 				return false;
54 
55 			WindowArea* area = sender->GetWindowArea();
56 			if (!area)
57 				return false;
58 			if (position < 0)
59 				position = area->WindowList().CountItems() - 1;
60 
61 			SATWindow* parent = area->WindowList().ItemAt(position);
62 			Window* window = desktop->WindowForClientLooperPort(port);
63 			if (!parent || !window) {
64 				reply.StartMessage(B_BAD_VALUE);
65 				reply.Flush();
66 				break;
67 			}
68 
69 			SATWindow* candidate = stackAndTile->GetSATWindow(window);
70 			if (!candidate)
71 				return false;
72 			if (!parent->StackWindow(candidate))
73 				return false;
74 
75 			reply.StartMessage(B_OK);
76 			reply.Flush();
77 			break;
78 		}
79 		case kRemoveWindowFromStack:
80 		{
81 			port_id port;
82 			int32 token;
83 			team_id team;
84 			link.Read<port_id>(&port);
85 			link.Read<int32>(&token);
86 			if (link.Read<team_id>(&team) != B_OK)
87 				return false;
88 
89 			SATGroup* group = sender->GetGroup();
90 			if (!group)
91 				return false;
92 
93 			Window* window = desktop->WindowForClientLooperPort(port);
94 			if (!window) {
95 				reply.StartMessage(B_BAD_VALUE);
96 				reply.Flush();
97 				break;
98 			}
99 			SATWindow* candidate = stackAndTile->GetSATWindow(window);
100 			if (!candidate)
101 				return false;
102 			if (!group->RemoveWindow(candidate, false))
103 				return false;
104 			break;
105 		}
106 		case kRemoveWindowFromStackAt:
107 		{
108 			int32 position;
109 			if (link.Read<int32>(&position) != B_OK)
110 				return false;
111 			SATGroup* group = sender->GetGroup();
112 			WindowArea* area = sender->GetWindowArea();
113 			if (!area || !group)
114 				return false;
115 			SATWindow* removeWindow = area->WindowList().ItemAt(position);
116 			if (!removeWindow) {
117 				reply.StartMessage(B_BAD_VALUE);
118 				reply.Flush();
119 				break;
120 			}
121 
122 			if (!group->RemoveWindow(removeWindow, false))
123 				return false;
124 
125 			ServerWindow* window = removeWindow->GetWindow()->ServerWindow();
126 			reply.StartMessage(B_OK);
127 			reply.Attach<port_id>(window->ClientLooperPort());
128 			reply.Attach<int32>(window->ClientToken());
129 			reply.Attach<team_id>(window->ClientTeam());
130 			reply.Flush();
131 			break;
132 		}
133 		case kCountWindowsOnStack:
134 		{
135 			WindowArea* area = sender->GetWindowArea();
136 			if (!area)
137 				return false;
138 			reply.StartMessage(B_OK);
139 			reply.Attach<int32>(area->WindowList().CountItems());
140 			reply.Flush();
141 			break;
142 		}
143 		case kWindowOnStackAt:
144 		{
145 			int32 position;
146 			if (link.Read<int32>(&position) != B_OK)
147 				return false;
148 			WindowArea* area = sender->GetWindowArea();
149 			if (!area)
150 				return false;
151 			SATWindow* satWindow = area->WindowList().ItemAt(position);
152 			if (!satWindow) {
153 				reply.StartMessage(B_BAD_VALUE);
154 				reply.Flush();
155 				break;
156 			}
157 
158 			ServerWindow* window = satWindow->GetWindow()->ServerWindow();
159 			reply.StartMessage(B_OK);
160 			reply.Attach<port_id>(window->ClientLooperPort());
161 			reply.Attach<int32>(window->ClientToken());
162 			reply.Attach<team_id>(window->ClientTeam());
163 			reply.Flush();
164 			break;
165 		}
166 		case kStackHasWindow:
167 		{
168 			port_id port;
169 			int32 token;
170 			team_id team;
171 			link.Read<port_id>(&port);
172 			link.Read<int32>(&token);
173 			if (link.Read<team_id>(&team) != B_OK)
174 				return false;
175 
176 			Window* window = desktop->WindowForClientLooperPort(port);
177 			if (!window) {
178 				reply.StartMessage(B_BAD_VALUE);
179 				reply.Flush();
180 				break;
181 			}
182 			SATWindow* candidate = stackAndTile->GetSATWindow(window);
183 			if (!candidate)
184 				return false;
185 
186 			WindowArea* area = sender->GetWindowArea();
187 			if (!area)
188 				return false;
189 			reply.StartMessage(B_OK);
190 			reply.Attach<bool>(area->WindowList().HasItem(candidate));
191 			reply.Flush();
192 			break;
193 		}
194 		default:
195 			return false;
196 	}
197 	return true;
198 }
199 
200 
201 SATStacking::SATStacking(SATWindow* window)
202 	:
203 	fSATWindow(window),
204 	fStackingParent(NULL)
205 {
206 
207 }
208 
209 
210 SATStacking::~SATStacking()
211 {
212 
213 }
214 
215 
216 bool
217 SATStacking::FindSnappingCandidates(SATGroup* group)
218 {
219 	_ClearSearchResult();
220 
221 	Window* window = fSATWindow->GetWindow();
222 	if (!window->Decorator())
223 		return false;
224 
225 	BPoint mousePosition;
226 	int32 buttons;
227 	fSATWindow->GetDesktop()->GetLastMouseState(&mousePosition, &buttons);
228 	if (!window->Decorator()->TitleBarRect().Contains(mousePosition))
229 		return false;
230 
231 	// use the upper edge of the candidate window to find the parent window
232 	mousePosition.y = window->Decorator()->TitleBarRect().top;
233 
234 	for (int i = 0; i < group->CountItems(); i++) {
235 		SATWindow* satWindow = group->WindowAt(i);
236 		// search for stacking parent
237 		Window* parentWindow = satWindow->GetWindow();
238 		if (parentWindow == window || parentWindow->Decorator() == NULL)
239 			continue;
240 		if (_IsStackableWindow(parentWindow) == false
241 			|| _IsStackableWindow(window) == false)
242 			continue;
243 		Decorator::Tab* tab = parentWindow->Decorator()->TabAt(
244 			parentWindow->PositionInStack());
245 		if (tab == NULL)
246 			continue;
247 		if (tab->tabRect.Contains(mousePosition)) {
248 			// remember window as the parent for stacking
249 			fStackingParent = satWindow;
250 			_HighlightWindows(true);
251 			return true;
252 		}
253 	}
254 
255 	return false;
256 }
257 
258 
259 bool
260 SATStacking::JoinCandidates()
261 {
262 	if (!fStackingParent)
263 		return false;
264 
265 	bool result = fStackingParent->StackWindow(fSATWindow);
266 
267 	_ClearSearchResult();
268 	return result;
269 }
270 
271 
272 void
273 SATStacking::RemovedFromArea(WindowArea* area)
274 {
275 	const SATWindowList& list = area->WindowList();
276 	if (list.CountItems() > 0)
277 		list.ItemAt(0)->DoGroupLayout();
278 }
279 
280 
281 void
282 SATStacking::WindowLookChanged(window_look look)
283 {
284 	Window* window = fSATWindow->GetWindow();
285 	WindowStack* stack = window->GetWindowStack();
286 	if (stack == NULL)
287 		return;
288 	SATGroup* group = fSATWindow->GetGroup();
289 	if (group == NULL)
290 		return;
291 	if (stack->CountWindows() > 1 && _IsStackableWindow(window) == false)
292 		group->RemoveWindow(fSATWindow);
293 }
294 
295 
296 bool
297 SATStacking::_IsStackableWindow(Window* window)
298 {
299 	if (window->Look() == B_DOCUMENT_WINDOW_LOOK)
300 		return true;
301 	if (window->Look() == B_TITLED_WINDOW_LOOK)
302 		return true;
303 	return false;
304 }
305 
306 
307 void
308 SATStacking::_ClearSearchResult()
309 {
310 	if (!fStackingParent)
311 		return;
312 
313 	_HighlightWindows(false);
314 	fStackingParent = NULL;
315 }
316 
317 
318 void
319 SATStacking::_HighlightWindows(bool highlight)
320 {
321 	Desktop* desktop = fSATWindow->GetWindow()->Desktop();
322 	if (!desktop)
323 		return;
324 	fStackingParent->HighlightTab(highlight);
325 	fSATWindow->HighlightTab(highlight);
326 }
327