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