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