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
SATGroup::_SplitGroupIfNecessary(WindowArea* removedArea)
{
	// if there are windows stacked in the area we don't need to split
	if (!removedArea || removedArea->WindowList().CountItems() > 1)
		return;

	WindowAreaList neighbourWindows;

	_FillNeighbourList(neighbourWindows, removedArea);

	bool ownGroupProcessed = false;
	WindowAreaList newGroup;
	while (_FindConnectedGroup(neighbourWindows, removedArea, newGroup)) {
		STRACE_SAT("Connected group found; %i window(s)\n",
			(int)newGroup.CountItems());
		if (newGroup.CountItems() == 1
			&& newGroup.ItemAt(0)->WindowList().CountItems() == 1) {
			SATWindow* window = newGroup.ItemAt(0)->WindowList().ItemAt(0);
			RemoveWindow(window);
			_EnsureGroupIsOnScreen(window->GetGroup());
		} else if (ownGroupProcessed)
			_SpawnNewGroup(newGroup);
		else {
			_EnsureGroupIsOnScreen(this);
			ownGroupProcessed = true;
		}

		newGroup.MakeEmpty();
	}
}
Beispiel #3
0
SATGroup*
GroupIterator::NextGroup()
{
	SATGroup* group = NULL;
	do {
		Window* window = fCurrentWindow;
		if (window == NULL) {
			group = NULL;
			break;
		}
		fCurrentWindow = fCurrentWindow->PreviousWindow(
			fCurrentWindow->CurrentWorkspace());
		if (window->IsHidden()
			|| strcmp(window->Title(), "Deskbar") == 0
			|| strcmp(window->Title(), "Desktop") == 0) {
			continue;
		}

		SATWindow* satWindow = fStackAndTile->GetSATWindow(window);
		group = satWindow->GetGroup();
	} while (group == NULL || fCurrentGroup == group);

	fCurrentGroup = group;
	return fCurrentGroup;
}
Beispiel #4
0
void
StackAndTile::WindowLookChanged(Window* window, window_look look)
{
	SATWindow* satWindow = GetSATWindow(window);
	if (!satWindow)
		return;
	satWindow->WindowLookChanged(look);
}
Beispiel #5
0
bool
StackAndTile::SetDecoratorSettings(Window* window, const BMessage& settings)
{
	SATWindow* satWindow = GetSATWindow(window);
	if (!satWindow)
		return false;

	return satWindow->SetSettings(settings);
}
Beispiel #6
0
void
StackAndTile::GetDecoratorSettings(Window* window, BMessage& settings)
{
	SATWindow* satWindow = GetSATWindow(window);
	if (!satWindow)
		return;

	satWindow->GetSettings(settings);
}
void
WindowArea::DoGroupLayout()
{
	SATWindow* parentWindow = fWindowLayerOrder.ItemAt(0);
	if (parentWindow == NULL)
		return;

	BRect frame = parentWindow->CompleteWindowFrame();
	// Make it also work for solver which don't support negative variables
	frame.OffsetBy(kMakePositiveOffset, kMakePositiveOffset);

	// adjust window size soft constraints
	fWidthConstraint->SetRightSide(frame.Width());
	fHeightConstraint->SetRightSide(frame.Height());

	LinearSpec* linearSpec = fGroup->GetLinearSpec();
	Constraint* leftConstraint = linearSpec->AddConstraint(1.0, LeftVar(),
		kEQ, frame.left);
	Constraint* topConstraint = linearSpec->AddConstraint(1.0, TopVar(), kEQ,
		frame.top);

	// give soft constraints a high penalty
	fWidthConstraint->SetPenaltyNeg(kHighPenalty);
	fWidthConstraint->SetPenaltyPos(kHighPenalty);
	fHeightConstraint->SetPenaltyNeg(kHighPenalty);
	fHeightConstraint->SetPenaltyPos(kHighPenalty);

	// After we set the new parameter solve and apply the new layout.
	ResultType result;
	for (int32 tries = 0; tries < 15; tries++) {
		result = fGroup->GetLinearSpec()->Solve();
		if (result == kInfeasible) {
			debug_printf("can't solve constraints!\n");
			break;
		}
		if (result == kOptimal) {
			const WindowAreaList& areas = fGroup->GetAreaList();
			for (int32 i = 0; i < areas.CountItems(); i++) {
				WindowArea* area = areas.ItemAt(i);
				area->_MoveToSAT(parentWindow);
			}
			break;
		}
	}

	// set penalties back to normal
	fWidthConstraint->SetPenaltyNeg(kExtentPenalty);
	fWidthConstraint->SetPenaltyPos(kExtentPenalty);
	fHeightConstraint->SetPenaltyNeg(kExtentPenalty);
	fHeightConstraint->SetPenaltyPos(kExtentPenalty);

	linearSpec->RemoveConstraint(leftConstraint);
	linearSpec->RemoveConstraint(topConstraint);
}
Beispiel #8
0
void
StackAndTile::WindowMoved(Window* window)
{
	SATWindow* satWindow = GetSATWindow(window);
	if (satWindow == NULL)
		return;

	if (SATKeyPressed() && fCurrentSATWindow)
		satWindow->FindSnappingCandidates();
	else
		satWindow->DoGroupLayout();
}
Beispiel #9
0
SATWindow*
StackAndTile::FindSATWindow(uint64 id)
{
	for (SATWindowMap::const_iterator it = fSATWindowMap.begin();
		it != fSATWindowMap.end(); it++) {
		SATWindow* window = it->second;
		if (window->Id() == id)
			return window;
	}

	return NULL;
}
Beispiel #10
0
void
StackAndTile::SizeLimitsChanged(Window* window, int32 minWidth, int32 maxWidth,
	int32 minHeight, int32 maxHeight)
{
	SATWindow* satWindow = GetSATWindow(window);
	if (!satWindow)
		return;
	satWindow->SetOriginalSizeLimits(minWidth, maxWidth, minHeight, maxHeight);

	// trigger a relayout
	WindowMoved(window);
}
Beispiel #11
0
bool
StackAndTile::HandleMessage(Window* sender, BPrivate::LinkReceiver& link,
	BPrivate::LinkSender& reply)
{
	if (sender == NULL)
		return _HandleMessage(link, reply);

	SATWindow* satWindow = GetSATWindow(sender);
	if (!satWindow)
		return false;

	return satWindow->HandleMessage(satWindow, link, reply);
}
Beispiel #12
0
void
StackAndTile::WindowHidden(Window* window, bool fromMinimize)
{
	SATWindow* satWindow = GetSATWindow(window);
	if (satWindow == NULL)
		return;

	SATGroup* group = satWindow->GetGroup();
	if (group == NULL)
		return;

	if (fromMinimize == false && group->CountItems() > 1)
		group->RemoveWindow(satWindow, false);
}
Beispiel #13
0
void
StackAndTile::WindowFeelChanged(Window* window, window_feel feel)
{
	// check if it is still a compatible feel
	if (feel == B_NORMAL_WINDOW_FEEL)
		return;
	SATWindow* satWindow = GetSATWindow(window);
	if (satWindow == NULL)
		return;

	SATGroup* group = satWindow->GetGroup();
	if (group == NULL)
		return;

	if (group->CountItems() > 1)
		group->RemoveWindow(satWindow, false);
}
Beispiel #14
0
void
StackAndTile::MouseDown(Window* window, BMessage* message, const BPoint& where)
{
	SATWindow* satWindow = GetSATWindow(window);
	if (!satWindow || !satWindow->GetDecorator())
		return;

	// fCurrentSATWindow is not zero if e.g. the secondary and the primary
	// mouse button are pressed at the same time
	if ((message->FindInt32("buttons") & B_PRIMARY_MOUSE_BUTTON) == 0 ||
		fCurrentSATWindow != NULL)
		return;

	// we are only interested in single clicks
	if (message->FindInt32("clicks") == 2)
		return;

	int32 tab;
	switch (satWindow->GetDecorator()->RegionAt(where, tab)) {
		case Decorator::REGION_TAB:
		case Decorator::REGION_LEFT_BORDER:
		case Decorator::REGION_RIGHT_BORDER:
		case Decorator::REGION_TOP_BORDER:
		case Decorator::REGION_BOTTOM_BORDER:
		case Decorator::REGION_LEFT_TOP_CORNER:
		case Decorator::REGION_LEFT_BOTTOM_CORNER:
		case Decorator::REGION_RIGHT_TOP_CORNER:
		case Decorator::REGION_RIGHT_BOTTOM_CORNER:
			break;

		default:
			return;
	}

	ASSERT(fCurrentSATWindow == NULL);
	fCurrentSATWindow = satWindow;

	if (!SATKeyPressed())
		return;

	_StartSAT();
}
Beispiel #15
0
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;
}
Beispiel #16
0
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);
	}
}
Beispiel #17
0
bool
SATWindowBehaviour::AlterDeltaForSnap(Window* window, BPoint& delta,
	bigtime_t now)
{
	if (DefaultWindowBehaviour::AlterDeltaForSnap(window, delta, now) == true)
		return true;

	SATWindow* satWindow = fStackAndTile->GetSATWindow(window);
	if (satWindow == NULL)
		return false;
	SATGroup* group = satWindow->GetGroup();
	if (group == NULL)
		return false;

	BRect groupFrame = group->WindowAt(0)->CompleteWindowFrame();
	for (int32 i = 1; i < group->CountItems(); i++)
		groupFrame = groupFrame | group->WindowAt(i)->CompleteWindowFrame();

	return fMagneticBorder.AlterDeltaForSnap(window->Screen(),
		groupFrame, delta, now);
}
Beispiel #18
0
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);
	}
}
Beispiel #19
0
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);
	}
}
void
WindowArea::_UpdateConstraintValues()
{
	SATWindow* topWindow = TopWindow();
	if (topWindow == NULL)
		return;

	int32 minWidth, maxWidth;
	int32 minHeight, maxHeight;
	SATWindow* window = fWindowList.ItemAt(0);
	window->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight);
	for (int32 i = 1; i < fWindowList.CountItems(); i++) {
		window = fWindowList.ItemAt(i);
		// size limit constraints
		int32 minW, maxW;
		int32 minH, maxH;
		window->GetSizeLimits(&minW, &maxW, &minH, &maxH);
		if (minWidth < minW)
			minWidth = minW;
		if (minHeight < minH)
			minHeight = minH;
		if (maxWidth < maxW)
			maxWidth = maxW;
		if (maxHeight < maxH)
			maxHeight = maxH;
	}
	// the current solver don't like big values
	const int32 kMaxSolverValue = 5000;
	if (minWidth > kMaxSolverValue)
		minWidth = kMaxSolverValue;
	if (minHeight > kMaxSolverValue)
		minHeight = kMaxSolverValue;
	if (maxWidth > kMaxSolverValue)
		maxWidth = kMaxSolverValue;
	if (maxHeight > kMaxSolverValue)
		maxHeight = kMaxSolverValue;

	topWindow->AddDecorator(&minWidth, &maxWidth, &minHeight, &maxHeight);
	fMinWidthConstraint->SetRightSide(minWidth);
	fMinHeightConstraint->SetRightSide(minHeight);

	fMaxWidthConstraint->SetRightSide(maxWidth);
	fMaxHeightConstraint->SetRightSide(maxHeight);

	BRect frame = topWindow->CompleteWindowFrame();
	fWidthConstraint->SetRightSide(frame.Width());
	fHeightConstraint->SetRightSide(frame.Height());
}
Beispiel #21
0
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;
}
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();
}
status_t
SATGroup::RestoreGroup(const BMessage& archive, StackAndTile* sat)
{
	// create new group
	SATGroup* group = new (std::nothrow)SATGroup;
	if (!group)
		return B_NO_MEMORY;
	BReference<SATGroup> groupRef;
	groupRef.SetTo(group, true);

	int32 nHTabs, nVTabs;
	status_t status;
	status = archive.FindInt32("htab_count", &nHTabs);
	if (status != B_OK)
		return status;
	status = archive.FindInt32("vtab_count", &nVTabs);
	if (status != B_OK)
		return status;

	vector<BReference<Tab> > tempHTabs;
	for (int i = 0; i < nHTabs; i++) {
		BReference<Tab> tab = group->_AddHorizontalTab();
		if (!tab)
			return B_NO_MEMORY;
		tempHTabs.push_back(tab);
	}
	vector<BReference<Tab> > tempVTabs;
	for (int i = 0; i < nVTabs; i++) {
		BReference<Tab> tab = group->_AddVerticalTab();
		if (!tab)
			return B_NO_MEMORY;
		tempVTabs.push_back(tab);
	}

	BMessage areaArchive;
	for (int32 i = 0; archive.FindMessage("area", i, &areaArchive) == B_OK;
		i++) {
		uint32 leftTab, rightTab, topTab, bottomTab;
		if (areaArchive.FindInt32("left_tab", (int32*)&leftTab) != B_OK
			|| areaArchive.FindInt32("right_tab", (int32*)&rightTab) != B_OK
			|| areaArchive.FindInt32("top_tab", (int32*)&topTab) != B_OK
			|| areaArchive.FindInt32("bottom_tab", (int32*)&bottomTab) != B_OK)
			return B_ERROR;

		if (leftTab >= tempVTabs.size() || rightTab >= tempVTabs.size())
			return B_BAD_VALUE;
		if (topTab >= tempHTabs.size() || bottomTab >= tempHTabs.size())
			return B_BAD_VALUE;

		Tab* left = tempVTabs[leftTab];
		Tab* right = tempVTabs[rightTab];
		Tab* top = tempHTabs[topTab];
		Tab* bottom = tempHTabs[bottomTab];

		// adding windows to area
		uint64 windowId;
		SATWindow* prevWindow = NULL;
		for (int32 i = 0; areaArchive.FindInt64("window", i,
			(int64*)&windowId) == B_OK; i++) {
			SATWindow* window = sat->FindSATWindow(windowId);
			if (!window)
				continue;

			if (prevWindow == NULL) {
				if (!group->AddWindow(window, left, top, right, bottom))
					continue;
				prevWindow = window;
			} else {
				if (!prevWindow->StackWindow(window))
					continue;
				prevWindow = window;
			}
		}
	}
	return B_OK;
}
Beispiel #24
0
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;
}