void WindowArea::_MoveToSAT(SATWindow* triggerWindow) { SATWindow* topWindow = TopWindow(); // if there is no window in the group we are done if (topWindow == NULL) return; BRect frameSAT(LeftVar()->Value() - kMakePositiveOffset, TopVar()->Value() - kMakePositiveOffset, RightVar()->Value() - kMakePositiveOffset, BottomVar()->Value() - kMakePositiveOffset); topWindow->AdjustSizeLimits(frameSAT); BRect frame = topWindow->CompleteWindowFrame(); float deltaToX = round(frameSAT.left - frame.left); float deltaToY = round(frameSAT.top - frame.top); frame.OffsetBy(deltaToX, deltaToY); float deltaByX = round(frameSAT.right - frame.right); float deltaByY = round(frameSAT.bottom - frame.bottom); int32 workspace = triggerWindow->GetWindow()->CurrentWorkspace(); Desktop* desktop = triggerWindow->GetWindow()->Desktop(); desktop->MoveWindowBy(topWindow->GetWindow(), deltaToX, deltaToY, workspace); // Update frame to the new position desktop->ResizeWindowBy(topWindow->GetWindow(), deltaByX, deltaByY); UpdateSizeConstaints(frameSAT); }
void StackAndTile::WindowMinimized(Window* window, bool minimize) { SATWindow* satWindow = GetSATWindow(window); if (satWindow == NULL) return; SATGroup* group = satWindow->GetGroup(); if (group == NULL) return; Desktop* desktop = satWindow->GetWindow()->Desktop(); if (desktop == NULL) return; for (int i = 0; i < group->CountItems(); i++) { SATWindow* listWindow = group->WindowAt(i); if (listWindow != satWindow) listWindow->GetWindow()->ServerWindow()->NotifyMinimize(minimize); } }
void StackAndTile::WindowWorkspacesChanged(Window* window, uint32 workspaces) { SATWindow* satWindow = GetSATWindow(window); if (satWindow == NULL) return; SATGroup* group = satWindow->GetGroup(); if (group == NULL) return; Desktop* desktop = satWindow->GetWindow()->Desktop(); if (desktop == NULL) return; const WindowAreaList& areaList = group->GetAreaList(); for (int32 i = 0; i < areaList.CountItems(); i++) { WindowArea* area = areaList.ItemAt(i); if (area->WindowList().HasItem(satWindow)) continue; SATWindow* topWindow = area->TopWindow(); desktop->SetWindowWorkspaces(topWindow->GetWindow(), workspaces); } }
void StackAndTile::WindowSentBehind(Window* window, Window* behindOf) { SATWindow* satWindow = GetSATWindow(window); if (satWindow == NULL) return; SATGroup* group = satWindow->GetGroup(); if (group == NULL) return; Desktop* desktop = satWindow->GetWindow()->Desktop(); if (desktop == NULL) return; const WindowAreaList& areaList = group->GetAreaList(); for (int32 i = 0; i < areaList.CountItems(); i++) { WindowArea* area = areaList.ItemAt(i); SATWindow* topWindow = area->TopWindow(); if (topWindow == NULL || topWindow == satWindow) continue; desktop->SendWindowBehind(topWindow->GetWindow(), behindOf); } }
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 StackAndTile::KeyPressed(uint32 what, int32 key, int32 modifiers) { if (what == B_MODIFIERS_CHANGED || (what == B_UNMAPPED_KEY_DOWN && key == kRightOptionKey) || (what == B_UNMAPPED_KEY_UP && key == kRightOptionKey)) { // switch to and from stacking and snapping mode bool wasPressed = fSATKeyPressed; fSATKeyPressed = (what == B_MODIFIERS_CHANGED && (modifiers & kModifiers) == B_OPTION_KEY) || (what == B_UNMAPPED_KEY_DOWN && key == kRightOptionKey); if (wasPressed && !fSATKeyPressed) _StopSAT(); if (!wasPressed && fSATKeyPressed) _StartSAT(); } if (!SATKeyPressed() || what != B_KEY_DOWN) return false; SATWindow* frontWindow = GetSATWindow(fDesktop->FocusWindow()); SATGroup* currentGroup = _GetSATGroup(frontWindow); switch (key) { case kLeftArrowKey: case kRightArrowKey: case kTabKey: { // go to previous or next window tab in current window group if (currentGroup == NULL) return false; int32 groupSize = currentGroup->CountItems(); if (groupSize <= 1) return false; for (int32 i = 0; i < groupSize; i++) { SATWindow* targetWindow = currentGroup->WindowAt(i); if (targetWindow == frontWindow) { if (key == kLeftArrowKey || (key == kTabKey && (modifiers & B_SHIFT_KEY) != 0)) { // Go to previous window tab (wrap around) int32 previousIndex = i > 0 ? i - 1 : groupSize - 1; targetWindow = currentGroup->WindowAt(previousIndex); } else { // Go to next window tab (wrap around) int32 nextIndex = i < groupSize - 1 ? i + 1 : 0; targetWindow = currentGroup->WindowAt(nextIndex); } _ActivateWindow(targetWindow); return true; } } break; } case kUpArrowKey: case kPageUpKey: { // go to previous window group GroupIterator groups(this, fDesktop); groups.SetCurrentGroup(currentGroup); SATGroup* backmostGroup = NULL; while (true) { SATGroup* group = groups.NextGroup(); if (group == NULL || group == currentGroup) break; else if (group->CountItems() < 1) continue; if (currentGroup == NULL) { SATWindow* activeWindow = group->ActiveWindow(); if (activeWindow != NULL) _ActivateWindow(activeWindow); else _ActivateWindow(group->WindowAt(0)); return true; } backmostGroup = group; } if (backmostGroup != NULL && backmostGroup != currentGroup) { SATWindow* activeWindow = backmostGroup->ActiveWindow(); if (activeWindow != NULL) _ActivateWindow(activeWindow); else _ActivateWindow(backmostGroup->WindowAt(0)); return true; } break; } case kDownArrowKey: case kPageDownKey: { // go to next window group GroupIterator groups(this, fDesktop); groups.SetCurrentGroup(currentGroup); while (true) { SATGroup* group = groups.NextGroup(); if (group == NULL || group == currentGroup) break; else if (group->CountItems() < 1) continue; SATWindow* activeWindow = group->ActiveWindow(); if (activeWindow != NULL) _ActivateWindow(activeWindow); else _ActivateWindow(group->WindowAt(0)); if (currentGroup != NULL && frontWindow != NULL) { Window* window = frontWindow->GetWindow(); fDesktop->SendWindowBehind(window); WindowSentBehind(window, NULL); } return true; } break; } } return false; }
void SATGroup::_EnsureGroupIsOnScreen(SATGroup* group) { STRACE_SAT("SATGroup::_EnsureGroupIsOnScreen\n"); if (!group) return; if (group->CountItems() < 1) return; SATWindow* window = group->WindowAt(0); Desktop* desktop = window->GetWindow()->Desktop(); if (!desktop) return; const float kBigDistance = 1E+10; float minLeftDistance = kBigDistance; BRect leftRect; float minTopDistance = kBigDistance; BRect topRect; float minRightDistance = kBigDistance; BRect rightRect; float minBottomDistance = kBigDistance; BRect bottomRect; BRect screen = window->GetWindow()->Screen()->Frame(); BRect reducedScreen = screen; reducedScreen.InsetBy(kMinOverlap, kMinOverlap); for (int i = 0; i < group->CountItems(); i++) { SATWindow* window = group->WindowAt(i); BRect frame = window->CompleteWindowFrame(); if (reducedScreen.Intersects(frame)) return; if (frame.right < screen.left + kMinOverlap) { float dist = fabs(screen.left - frame.right); if (dist < minLeftDistance) { minLeftDistance = dist; leftRect = frame; } else if (dist == minLeftDistance) leftRect = leftRect | frame; } if (frame.top > screen.bottom - kMinOverlap) { float dist = fabs(frame.top - screen.bottom); if (dist < minBottomDistance) { minBottomDistance = dist; bottomRect = frame; } else if (dist == minBottomDistance) bottomRect = bottomRect | frame; } if (frame.left > screen.right - kMinOverlap) { float dist = fabs(frame.left - screen.right); if (dist < minRightDistance) { minRightDistance = dist; rightRect = frame; } else if (dist == minRightDistance) rightRect = rightRect | frame; } if (frame.bottom < screen.top + kMinOverlap) { float dist = fabs(frame.bottom - screen.top); if (dist < minTopDistance) { minTopDistance = dist; topRect = frame; } else if (dist == minTopDistance) topRect = topRect | frame; } } BPoint offset; if (minLeftDistance < kBigDistance) { offset.x = screen.left - leftRect.right + kMoveToScreen; _CallculateYOffset(offset, leftRect, screen); } else if (minTopDistance < kBigDistance) { offset.y = screen.top - topRect.bottom + kMoveToScreen; _CallculateXOffset(offset, topRect, screen); } else if (minRightDistance < kBigDistance) { offset.x = screen.right - rightRect.left - kMoveToScreen; _CallculateYOffset(offset, rightRect, screen); } else if (minBottomDistance < kBigDistance) { offset.y = screen.bottom - bottomRect.top - kMoveToScreen; _CallculateXOffset(offset, bottomRect, screen); } if (offset.x == 0. && offset.y == 0.) return; STRACE_SAT("move group back to screen: offset x: %f offset y: %f\n", offset.x, offset.y); desktop->MoveWindowBy(window->GetWindow(), offset.x, offset.y); window->DoGroupLayout(); }
bool StackingEventHandler::HandleMessage(SATWindow* sender, BPrivate::LinkReceiver& link, BPrivate::LinkSender& reply) { Desktop* desktop = sender->GetDesktop(); StackAndTile* stackAndTile = sender->GetStackAndTile(); int32 what; link.Read<int32>(&what); switch (what) { case kAddWindowToStack: { port_id port; int32 token; team_id team; link.Read<port_id>(&port); link.Read<int32>(&token); link.Read<team_id>(&team); int32 position; if (link.Read<int32>(&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; 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_id>(&port); link.Read<int32>(&token); if (link.Read<team_id>(&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<int32>(&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<port_id>(window->ClientLooperPort()); reply.Attach<int32>(window->ClientToken()); reply.Attach<team_id>(window->ClientTeam()); reply.Flush(); break; } case kCountWindowsOnStack: { WindowArea* area = sender->GetWindowArea(); if (!area) return false; reply.StartMessage(B_OK); reply.Attach<int32>(area->WindowList().CountItems()); reply.Flush(); break; } case kWindowOnStackAt: { int32 position; if (link.Read<int32>(&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<port_id>(window->ClientLooperPort()); reply.Attach<int32>(window->ClientToken()); reply.Attach<team_id>(window->ClientTeam()); reply.Flush(); break; } case kStackHasWindow: { port_id port; int32 token; team_id team; link.Read<port_id>(&port); link.Read<int32>(&token); if (link.Read<team_id>(&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<bool>(area->WindowList().HasItem(candidate)); reply.Flush(); break; } default: return false; } return true; }