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