/* * Copyright 2010, Haiku. * Distributed under the terms of the MIT License. * * Authors: * Clemens Zeidler */ #include "Stacking.h" #include #include "StackAndTilePrivate.h" #include "Desktop.h" #include "SATWindow.h" #include "Window.h" //#define DEBUG_STACKING #ifdef DEBUG_STACKING # define STRACE_STACKING(x...) debug_printf("SAT Stacking: "x) #else # define STRACE_STACKING(x...) ; #endif using namespace BPrivate; bool StackingEventHandler::HandleMessage(SATWindow* sender, BPrivate::LinkReceiver& link, BPrivate::LinkSender& reply) { Desktop* desktop = sender->GetDesktop(); StackAndTile* stackAndTile = sender->GetStackAndTile(); int32 what; link.Read(&what); switch (what) { case kAddWindowToStack: { port_id port; int32 token; team_id team; link.Read(&port); link.Read(&token); link.Read(&team); int32 position; if (link.Read(&position) != B_OK) return false; WindowArea* area = sender->GetWindowArea(); if (!area) return false; if (position < 0) position = area->WindowList().CountItems() - 1; SATWindow* parent = area->WindowList().ItemAt(position); Window* window = desktop->WindowForClientLooperPort(port); if (!parent || !window) { reply.StartMessage(B_BAD_VALUE); reply.Flush(); break; } SATWindow* candidate = stackAndTile->GetSATWindow(window); if (!candidate) return false; // Is that window already part of the stack? if (area->WindowList().HasItem(candidate)) { reply.StartMessage(B_MISMATCHED_VALUES); reply.Flush(); break; } if (!parent->StackWindow(candidate)) return false; reply.StartMessage(B_OK); reply.Flush(); break; } case kRemoveWindowFromStack: { port_id port; int32 token; team_id team; link.Read(&port); link.Read(&token); if (link.Read(&team) != B_OK) return false; SATGroup* group = sender->GetGroup(); if (!group) return false; Window* window = desktop->WindowForClientLooperPort(port); if (!window) { reply.StartMessage(B_BAD_VALUE); reply.Flush(); break; } SATWindow* candidate = stackAndTile->GetSATWindow(window); if (!candidate) return false; if (!group->RemoveWindow(candidate, false)) return false; break; } case kRemoveWindowFromStackAt: { int32 position; if (link.Read(&position) != B_OK) return false; SATGroup* group = sender->GetGroup(); WindowArea* area = sender->GetWindowArea(); if (!area || !group) return false; SATWindow* removeWindow = area->WindowList().ItemAt(position); if (!removeWindow) { reply.StartMessage(B_BAD_VALUE); reply.Flush(); break; } if (!group->RemoveWindow(removeWindow, false)) return false; ServerWindow* window = removeWindow->GetWindow()->ServerWindow(); reply.StartMessage(B_OK); reply.Attach(window->ClientLooperPort()); reply.Attach(window->ClientToken()); reply.Attach(window->ClientTeam()); reply.Flush(); break; } case kCountWindowsOnStack: { WindowArea* area = sender->GetWindowArea(); if (!area) return false; reply.StartMessage(B_OK); reply.Attach(area->WindowList().CountItems()); reply.Flush(); break; } case kWindowOnStackAt: { int32 position; if (link.Read(&position) != B_OK) return false; WindowArea* area = sender->GetWindowArea(); if (!area) return false; SATWindow* satWindow = area->WindowList().ItemAt(position); if (!satWindow) { reply.StartMessage(B_BAD_VALUE); reply.Flush(); break; } ServerWindow* window = satWindow->GetWindow()->ServerWindow(); reply.StartMessage(B_OK); reply.Attach(window->ClientLooperPort()); reply.Attach(window->ClientToken()); reply.Attach(window->ClientTeam()); reply.Flush(); break; } case kStackHasWindow: { port_id port; int32 token; team_id team; link.Read(&port); link.Read(&token); if (link.Read(&team) != B_OK) return false; Window* window = desktop->WindowForClientLooperPort(port); if (!window) { reply.StartMessage(B_BAD_VALUE); reply.Flush(); break; } SATWindow* candidate = stackAndTile->GetSATWindow(window); if (!candidate) return false; WindowArea* area = sender->GetWindowArea(); if (!area) return false; reply.StartMessage(B_OK); reply.Attach(area->WindowList().HasItem(candidate)); reply.Flush(); break; } default: return false; } return true; } SATStacking::SATStacking(SATWindow* window) : fSATWindow(window), fStackingParent(NULL) { } SATStacking::~SATStacking() { } bool SATStacking::FindSnappingCandidates(SATGroup* group) { _ClearSearchResult(); Window* window = fSATWindow->GetWindow(); if (!window->Decorator()) return false; BPoint mousePosition; int32 buttons; fSATWindow->GetDesktop()->GetLastMouseState(&mousePosition, &buttons); if (!window->Decorator()->TitleBarRect().Contains(mousePosition)) return false; // use the upper edge of the candidate window to find the parent window mousePosition.y = window->Decorator()->TitleBarRect().top; for (int i = 0; i < group->CountItems(); i++) { SATWindow* satWindow = group->WindowAt(i); // search for stacking parent Window* parentWindow = satWindow->GetWindow(); if (parentWindow == window || parentWindow->Decorator() == NULL) continue; if (_IsStackableWindow(parentWindow) == false || _IsStackableWindow(window) == false) continue; Decorator::Tab* tab = parentWindow->Decorator()->TabAt( parentWindow->PositionInStack()); if (tab == NULL) continue; if (tab->tabRect.Contains(mousePosition)) { // remember window as the parent for stacking fStackingParent = satWindow; _HighlightWindows(true); return true; } } return false; } bool SATStacking::JoinCandidates() { if (!fStackingParent) return false; bool result = fStackingParent->StackWindow(fSATWindow); _ClearSearchResult(); return result; } void SATStacking::RemovedFromArea(WindowArea* area) { const SATWindowList& list = area->WindowList(); if (list.CountItems() > 0) list.ItemAt(0)->DoGroupLayout(); } void SATStacking::WindowLookChanged(window_look look) { Window* window = fSATWindow->GetWindow(); WindowStack* stack = window->GetWindowStack(); if (stack == NULL) return; SATGroup* group = fSATWindow->GetGroup(); if (group == NULL) return; if (stack->CountWindows() > 1 && _IsStackableWindow(window) == false) group->RemoveWindow(fSATWindow); } bool SATStacking::_IsStackableWindow(Window* window) { if (window->Look() == B_DOCUMENT_WINDOW_LOOK) return true; if (window->Look() == B_TITLED_WINDOW_LOOK) return true; return false; } void SATStacking::_ClearSearchResult() { if (!fStackingParent) return; _HighlightWindows(false); fStackingParent = NULL; } void SATStacking::_HighlightWindows(bool highlight) { Desktop* desktop = fSATWindow->GetWindow()->Desktop(); if (!desktop) return; fStackingParent->HighlightTab(highlight); fSATWindow->HighlightTab(highlight); }