usb_ecm: Use the current configuration instead of a fixed one.
[haiku.git] / src / servers / app / stackandtile / StackAndTile.cpp
blob5fd7896a3a345280183f7d6531354707a268a035
1 /*
2 * Copyright 2010-2014 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * John Scipione, jscipione@gmail.com
7 * Clemens Zeidler, haiku@clemens-zeidler.de
8 */
11 #include "StackAndTile.h"
13 #include <Debug.h>
15 #include "StackAndTilePrivate.h"
17 #include "Desktop.h"
18 #include "SATWindow.h"
19 #include "Tiling.h"
20 #include "Window.h"
23 static const int32 kRightOptionKey = 0x67;
24 static const int32 kTabKey = 0x26;
25 static const int32 kPageUpKey = 0x21;
26 static const int32 kPageDownKey = 0x36;
27 static const int32 kLeftArrowKey = 0x61;
28 static const int32 kUpArrowKey = 0x57;
29 static const int32 kRightArrowKey = 0x63;
30 static const int32 kDownArrowKey = 0x62;
32 static const int32 kModifiers = B_SHIFT_KEY | B_COMMAND_KEY
33 | B_CONTROL_KEY | B_OPTION_KEY | B_MENU_KEY;
36 using namespace std;
39 // #pragma mark - StackAndTile
42 StackAndTile::StackAndTile()
44 fDesktop(NULL),
45 fSATKeyPressed(false),
46 fCurrentSATWindow(NULL)
52 StackAndTile::~StackAndTile()
58 int32
59 StackAndTile::Identifier()
61 return BPrivate::kMagicSATIdentifier;
65 void
66 StackAndTile::ListenerRegistered(Desktop* desktop)
68 fDesktop = desktop;
70 WindowList& windows = desktop->AllWindows();
71 for (Window *window = windows.FirstWindow(); window != NULL;
72 window = window->NextWindow(kAllWindowList))
73 WindowAdded(window);
77 void
78 StackAndTile::ListenerUnregistered()
80 for (SATWindowMap::iterator it = fSATWindowMap.begin();
81 it != fSATWindowMap.end(); it++) {
82 SATWindow* satWindow = it->second;
83 delete satWindow;
85 fSATWindowMap.clear();
89 bool
90 StackAndTile::HandleMessage(Window* sender, BPrivate::LinkReceiver& link,
91 BPrivate::LinkSender& reply)
93 if (sender == NULL)
94 return _HandleMessage(link, reply);
96 SATWindow* satWindow = GetSATWindow(sender);
97 if (!satWindow)
98 return false;
100 return satWindow->HandleMessage(satWindow, link, reply);
104 void
105 StackAndTile::WindowAdded(Window* window)
107 SATWindow* satWindow = new (std::nothrow)SATWindow(this, window);
108 if (!satWindow)
109 return;
111 ASSERT(fSATWindowMap.find(window) == fSATWindowMap.end());
112 fSATWindowMap[window] = satWindow;
116 void
117 StackAndTile::WindowRemoved(Window* window)
119 STRACE_SAT("StackAndTile::WindowRemoved %s\n", window->Title());
121 SATWindowMap::iterator it = fSATWindowMap.find(window);
122 if (it == fSATWindowMap.end())
123 return;
125 SATWindow* satWindow = it->second;
126 // delete SATWindow
127 delete satWindow;
128 fSATWindowMap.erase(it);
132 bool
133 StackAndTile::KeyPressed(uint32 what, int32 key, int32 modifiers)
135 if (what == B_MODIFIERS_CHANGED
136 || (what == B_UNMAPPED_KEY_DOWN && key == kRightOptionKey)
137 || (what == B_UNMAPPED_KEY_UP && key == kRightOptionKey)) {
138 // switch to and from stacking and snapping mode
139 bool wasPressed = fSATKeyPressed;
140 fSATKeyPressed = (what == B_MODIFIERS_CHANGED
141 && (modifiers & kModifiers) == B_OPTION_KEY)
142 || (what == B_UNMAPPED_KEY_DOWN && key == kRightOptionKey);
143 if (wasPressed && !fSATKeyPressed)
144 _StopSAT();
145 if (!wasPressed && fSATKeyPressed)
146 _StartSAT();
149 if (!SATKeyPressed() || what != B_KEY_DOWN)
150 return false;
152 SATWindow* frontWindow = GetSATWindow(fDesktop->FocusWindow());
153 SATGroup* currentGroup = _GetSATGroup(frontWindow);
155 switch (key) {
156 case kLeftArrowKey:
157 case kRightArrowKey:
158 case kTabKey:
160 // go to previous or next window tab in current window group
161 if (currentGroup == NULL)
162 return false;
164 int32 groupSize = currentGroup->CountItems();
165 if (groupSize <= 1)
166 return false;
168 for (int32 i = 0; i < groupSize; i++) {
169 SATWindow* targetWindow = currentGroup->WindowAt(i);
170 if (targetWindow == frontWindow) {
171 if (key == kLeftArrowKey
172 || (key == kTabKey && (modifiers & B_SHIFT_KEY) != 0)) {
173 // Go to previous window tab (wrap around)
174 int32 previousIndex = i > 0 ? i - 1 : groupSize - 1;
175 targetWindow = currentGroup->WindowAt(previousIndex);
176 } else {
177 // Go to next window tab (wrap around)
178 int32 nextIndex = i < groupSize - 1 ? i + 1 : 0;
179 targetWindow = currentGroup->WindowAt(nextIndex);
182 _ActivateWindow(targetWindow);
183 return true;
186 break;
189 case kUpArrowKey:
190 case kPageUpKey:
192 // go to previous window group
193 GroupIterator groups(this, fDesktop);
194 groups.SetCurrentGroup(currentGroup);
195 SATGroup* backmostGroup = NULL;
197 while (true) {
198 SATGroup* group = groups.NextGroup();
199 if (group == NULL || group == currentGroup)
200 break;
201 else if (group->CountItems() < 1)
202 continue;
204 if (currentGroup == NULL) {
205 SATWindow* activeWindow = group->ActiveWindow();
206 if (activeWindow != NULL)
207 _ActivateWindow(activeWindow);
208 else
209 _ActivateWindow(group->WindowAt(0));
211 return true;
213 backmostGroup = group;
215 if (backmostGroup != NULL && backmostGroup != currentGroup) {
216 SATWindow* activeWindow = backmostGroup->ActiveWindow();
217 if (activeWindow != NULL)
218 _ActivateWindow(activeWindow);
219 else
220 _ActivateWindow(backmostGroup->WindowAt(0));
222 return true;
225 break;
228 case kDownArrowKey:
229 case kPageDownKey:
231 // go to next window group
232 GroupIterator groups(this, fDesktop);
233 groups.SetCurrentGroup(currentGroup);
235 while (true) {
236 SATGroup* group = groups.NextGroup();
237 if (group == NULL || group == currentGroup)
238 break;
239 else if (group->CountItems() < 1)
240 continue;
242 SATWindow* activeWindow = group->ActiveWindow();
243 if (activeWindow != NULL)
244 _ActivateWindow(activeWindow);
245 else
246 _ActivateWindow(group->WindowAt(0));
248 if (currentGroup != NULL && frontWindow != NULL) {
249 Window* window = frontWindow->GetWindow();
250 fDesktop->SendWindowBehind(window);
251 WindowSentBehind(window, NULL);
253 return true;
255 break;
259 return false;
263 void
264 StackAndTile::MouseDown(Window* window, BMessage* message, const BPoint& where)
266 SATWindow* satWindow = GetSATWindow(window);
267 if (!satWindow || !satWindow->GetDecorator())
268 return;
270 // fCurrentSATWindow is not zero if e.g. the secondary and the primary
271 // mouse button are pressed at the same time
272 if ((message->FindInt32("buttons") & B_PRIMARY_MOUSE_BUTTON) == 0 ||
273 fCurrentSATWindow != NULL)
274 return;
276 // we are only interested in single clicks
277 if (message->FindInt32("clicks") == 2)
278 return;
280 int32 tab;
281 switch (satWindow->GetDecorator()->RegionAt(where, tab)) {
282 case Decorator::REGION_TAB:
283 case Decorator::REGION_LEFT_BORDER:
284 case Decorator::REGION_RIGHT_BORDER:
285 case Decorator::REGION_TOP_BORDER:
286 case Decorator::REGION_BOTTOM_BORDER:
287 case Decorator::REGION_LEFT_TOP_CORNER:
288 case Decorator::REGION_LEFT_BOTTOM_CORNER:
289 case Decorator::REGION_RIGHT_TOP_CORNER:
290 case Decorator::REGION_RIGHT_BOTTOM_CORNER:
291 break;
293 default:
294 return;
297 ASSERT(fCurrentSATWindow == NULL);
298 fCurrentSATWindow = satWindow;
300 if (!SATKeyPressed())
301 return;
303 _StartSAT();
307 void
308 StackAndTile::MouseUp(Window* window, BMessage* message, const BPoint& where)
310 if (fSATKeyPressed)
311 _StopSAT();
313 fCurrentSATWindow = NULL;
317 void
318 StackAndTile::WindowMoved(Window* window)
320 SATWindow* satWindow = GetSATWindow(window);
321 if (satWindow == NULL)
322 return;
324 if (SATKeyPressed() && fCurrentSATWindow)
325 satWindow->FindSnappingCandidates();
326 else
327 satWindow->DoGroupLayout();
331 void
332 StackAndTile::WindowResized(Window* window)
334 SATWindow* satWindow = GetSATWindow(window);
335 if (satWindow == NULL)
336 return;
337 satWindow->Resized();
339 if (SATKeyPressed() && fCurrentSATWindow)
340 satWindow->FindSnappingCandidates();
341 else
342 satWindow->DoGroupLayout();
346 void
347 StackAndTile::WindowActivated(Window* window)
349 SATWindow* satWindow = GetSATWindow(window);
350 if (satWindow == NULL)
351 return;
353 _ActivateWindow(satWindow);
357 void
358 StackAndTile::WindowSentBehind(Window* window, Window* behindOf)
360 SATWindow* satWindow = GetSATWindow(window);
361 if (satWindow == NULL)
362 return;
364 SATGroup* group = satWindow->GetGroup();
365 if (group == NULL)
366 return;
368 Desktop* desktop = satWindow->GetWindow()->Desktop();
369 if (desktop == NULL)
370 return;
372 const WindowAreaList& areaList = group->GetAreaList();
373 for (int32 i = 0; i < areaList.CountItems(); i++) {
374 WindowArea* area = areaList.ItemAt(i);
375 SATWindow* topWindow = area->TopWindow();
376 if (topWindow == NULL || topWindow == satWindow)
377 continue;
378 desktop->SendWindowBehind(topWindow->GetWindow(), behindOf);
383 void
384 StackAndTile::WindowWorkspacesChanged(Window* window, uint32 workspaces)
386 SATWindow* satWindow = GetSATWindow(window);
387 if (satWindow == NULL)
388 return;
390 SATGroup* group = satWindow->GetGroup();
391 if (group == NULL)
392 return;
394 Desktop* desktop = satWindow->GetWindow()->Desktop();
395 if (desktop == NULL)
396 return;
398 const WindowAreaList& areaList = group->GetAreaList();
399 for (int32 i = 0; i < areaList.CountItems(); i++) {
400 WindowArea* area = areaList.ItemAt(i);
401 if (area->WindowList().HasItem(satWindow))
402 continue;
403 SATWindow* topWindow = area->TopWindow();
404 desktop->SetWindowWorkspaces(topWindow->GetWindow(), workspaces);
409 void
410 StackAndTile::WindowHidden(Window* window, bool fromMinimize)
412 SATWindow* satWindow = GetSATWindow(window);
413 if (satWindow == NULL)
414 return;
416 SATGroup* group = satWindow->GetGroup();
417 if (group == NULL)
418 return;
420 if (fromMinimize == false && group->CountItems() > 1)
421 group->RemoveWindow(satWindow, false);
425 void
426 StackAndTile::WindowMinimized(Window* window, bool minimize)
428 SATWindow* satWindow = GetSATWindow(window);
429 if (satWindow == NULL)
430 return;
432 SATGroup* group = satWindow->GetGroup();
433 if (group == NULL)
434 return;
436 Desktop* desktop = satWindow->GetWindow()->Desktop();
437 if (desktop == NULL)
438 return;
440 for (int i = 0; i < group->CountItems(); i++) {
441 SATWindow* listWindow = group->WindowAt(i);
442 if (listWindow != satWindow)
443 listWindow->GetWindow()->ServerWindow()->NotifyMinimize(minimize);
448 void
449 StackAndTile::WindowTabLocationChanged(Window* window, float location,
450 bool isShifting)
456 void
457 StackAndTile::SizeLimitsChanged(Window* window, int32 minWidth, int32 maxWidth,
458 int32 minHeight, int32 maxHeight)
460 SATWindow* satWindow = GetSATWindow(window);
461 if (!satWindow)
462 return;
463 satWindow->SetOriginalSizeLimits(minWidth, maxWidth, minHeight, maxHeight);
465 // trigger a relayout
466 WindowMoved(window);
470 void
471 StackAndTile::WindowLookChanged(Window* window, window_look look)
473 SATWindow* satWindow = GetSATWindow(window);
474 if (!satWindow)
475 return;
476 satWindow->WindowLookChanged(look);
480 void
481 StackAndTile::WindowFeelChanged(Window* window, window_feel feel)
483 // check if it is still a compatible feel
484 if (feel == B_NORMAL_WINDOW_FEEL)
485 return;
486 SATWindow* satWindow = GetSATWindow(window);
487 if (satWindow == NULL)
488 return;
490 SATGroup* group = satWindow->GetGroup();
491 if (group == NULL)
492 return;
494 if (group->CountItems() > 1)
495 group->RemoveWindow(satWindow, false);
499 bool
500 StackAndTile::SetDecoratorSettings(Window* window, const BMessage& settings)
502 SATWindow* satWindow = GetSATWindow(window);
503 if (!satWindow)
504 return false;
506 return satWindow->SetSettings(settings);
510 void
511 StackAndTile::GetDecoratorSettings(Window* window, BMessage& settings)
513 SATWindow* satWindow = GetSATWindow(window);
514 if (!satWindow)
515 return;
517 satWindow->GetSettings(settings);
521 SATWindow*
522 StackAndTile::GetSATWindow(Window* window)
524 if (window == NULL)
525 return NULL;
527 SATWindowMap::const_iterator it = fSATWindowMap.find(
528 window);
529 if (it != fSATWindowMap.end())
530 return it->second;
532 // TODO fix race condition with WindowAdded this method is called before
533 // WindowAdded and a SATWindow is created twice!
534 return NULL;
536 // If we don't know this window, memory allocation might has been failed
537 // previously. Try to add the window now.
538 SATWindow* satWindow = new (std::nothrow)SATWindow(this, window);
539 if (satWindow)
540 fSATWindowMap[window] = satWindow;
542 return satWindow;
546 SATWindow*
547 StackAndTile::FindSATWindow(uint64 id)
549 for (SATWindowMap::const_iterator it = fSATWindowMap.begin();
550 it != fSATWindowMap.end(); it++) {
551 SATWindow* window = it->second;
552 if (window->Id() == id)
553 return window;
556 return NULL;
560 // #pragma mark - StackAndTile private methods
563 void
564 StackAndTile::_StartSAT()
566 STRACE_SAT("StackAndTile::_StartSAT()\n");
567 if (!fCurrentSATWindow)
568 return;
570 // Remove window from the group.
571 SATGroup* group = fCurrentSATWindow->GetGroup();
572 if (group == NULL)
573 return;
575 group->RemoveWindow(fCurrentSATWindow, false);
576 // Bring window to the front. (in focus follow mouse this is not
577 // automatically the case)
578 _ActivateWindow(fCurrentSATWindow);
580 fCurrentSATWindow->FindSnappingCandidates();
584 void
585 StackAndTile::_StopSAT()
587 STRACE_SAT("StackAndTile::_StopSAT()\n");
588 if (!fCurrentSATWindow)
589 return;
590 if (fCurrentSATWindow->JoinCandidates())
591 _ActivateWindow(fCurrentSATWindow);
595 void
596 StackAndTile::_ActivateWindow(SATWindow* satWindow)
598 if (satWindow == NULL)
599 return;
601 SATGroup* group = satWindow->GetGroup();
602 if (group == NULL)
603 return;
605 Desktop* desktop = satWindow->GetWindow()->Desktop();
606 if (desktop == NULL)
607 return;
609 WindowArea* area = satWindow->GetWindowArea();
610 if (area == NULL)
611 return;
613 area->MoveToTopLayer(satWindow);
615 // save the active window of the current group
616 SATWindow* frontWindow = GetSATWindow(fDesktop->FocusWindow());
617 SATGroup* currentGroup = _GetSATGroup(frontWindow);
618 if (currentGroup != NULL && currentGroup != group && frontWindow != NULL)
619 currentGroup->SetActiveWindow(frontWindow);
620 else
621 group->SetActiveWindow(satWindow);
623 const WindowAreaList& areas = group->GetAreaList();
624 int32 areasCount = areas.CountItems();
625 for (int32 i = 0; i < areasCount; i++) {
626 WindowArea* currentArea = areas.ItemAt(i);
627 if (currentArea == area)
628 continue;
630 desktop->ActivateWindow(currentArea->TopWindow()->GetWindow());
633 desktop->ActivateWindow(satWindow->GetWindow());
637 bool
638 StackAndTile::_HandleMessage(BPrivate::LinkReceiver& link,
639 BPrivate::LinkSender& reply)
641 int32 what;
642 link.Read<int32>(&what);
644 switch (what) {
645 case BPrivate::kSaveAllGroups:
647 BMessage allGroupsArchive;
648 GroupIterator groups(this, fDesktop);
649 while (true) {
650 SATGroup* group = groups.NextGroup();
651 if (group == NULL)
652 break;
653 if (group->CountItems() <= 1)
654 continue;
655 BMessage groupArchive;
656 if (group->ArchiveGroup(groupArchive) != B_OK)
657 continue;
658 allGroupsArchive.AddMessage("group", &groupArchive);
660 int32 size = allGroupsArchive.FlattenedSize();
661 char buffer[size];
662 if (allGroupsArchive.Flatten(buffer, size) == B_OK) {
663 reply.StartMessage(B_OK);
664 reply.Attach<int32>(size);
665 reply.Attach(buffer, size);
666 } else
667 reply.StartMessage(B_ERROR);
668 reply.Flush();
669 break;
672 case BPrivate::kRestoreGroup:
674 int32 size;
675 if (link.Read<int32>(&size) == B_OK) {
676 char buffer[size];
677 BMessage group;
678 if (link.Read(buffer, size) == B_OK
679 && group.Unflatten(buffer) == B_OK) {
680 status_t status = SATGroup::RestoreGroup(group, this);
681 reply.StartMessage(status);
682 reply.Flush();
685 break;
688 default:
689 return false;
692 return true;
696 SATGroup*
697 StackAndTile::_GetSATGroup(SATWindow* window)
699 if (window == NULL)
700 return NULL;
702 SATGroup* group = window->GetGroup();
703 if (group == NULL)
704 return NULL;
706 if (group->CountItems() < 1)
707 return NULL;
709 return group;
713 // #pragma mark - GroupIterator
716 GroupIterator::GroupIterator(StackAndTile* sat, Desktop* desktop)
718 fStackAndTile(sat),
719 fDesktop(desktop),
720 fCurrentGroup(NULL)
722 RewindToFront();
726 void
727 GroupIterator::RewindToFront()
729 fCurrentWindow = fDesktop->CurrentWindows().LastWindow();
733 SATGroup*
734 GroupIterator::NextGroup()
736 SATGroup* group = NULL;
737 do {
738 Window* window = fCurrentWindow;
739 if (window == NULL) {
740 group = NULL;
741 break;
743 fCurrentWindow = fCurrentWindow->PreviousWindow(
744 fCurrentWindow->CurrentWorkspace());
745 if (window->IsHidden()
746 || strcmp(window->Title(), "Deskbar") == 0
747 || strcmp(window->Title(), "Desktop") == 0) {
748 continue;
751 SATWindow* satWindow = fStackAndTile->GetSATWindow(window);
752 group = satWindow->GetGroup();
753 } while (group == NULL || fCurrentGroup == group);
755 fCurrentGroup = group;
756 return fCurrentGroup;
760 // #pragma mark - WindowIterator
763 WindowIterator::WindowIterator(SATGroup* group, bool reverseLayerOrder)
765 fGroup(group),
766 fReverseLayerOrder(reverseLayerOrder)
768 if (fReverseLayerOrder)
769 _ReverseRewind();
770 else
771 Rewind();
775 void
776 WindowIterator::Rewind()
778 fAreaIndex = 0;
779 fWindowIndex = 0;
780 fCurrentArea = fGroup->GetAreaList().ItemAt(fAreaIndex);
784 SATWindow*
785 WindowIterator::NextWindow()
787 if (fReverseLayerOrder)
788 return _ReverseNextWindow();
790 if (fWindowIndex == fCurrentArea->LayerOrder().CountItems()) {
791 fAreaIndex++;
792 fWindowIndex = 0;
793 fCurrentArea = fGroup->GetAreaList().ItemAt(fAreaIndex);
794 if (!fCurrentArea)
795 return NULL;
797 SATWindow* window = fCurrentArea->LayerOrder().ItemAt(fWindowIndex);
798 fWindowIndex++;
799 return window;
803 // #pragma mark - WindowIterator private methods
806 SATWindow*
807 WindowIterator::_ReverseNextWindow()
809 if (fWindowIndex < 0) {
810 fAreaIndex++;
811 fCurrentArea = fGroup->GetAreaList().ItemAt(fAreaIndex);
812 if (!fCurrentArea)
813 return NULL;
814 fWindowIndex = fCurrentArea->LayerOrder().CountItems() - 1;
816 SATWindow* window = fCurrentArea->LayerOrder().ItemAt(fWindowIndex);
817 fWindowIndex--;
818 return window;
822 void
823 WindowIterator::_ReverseRewind()
825 Rewind();
826 if (fCurrentArea)
827 fWindowIndex = fCurrentArea->LayerOrder().CountItems() - 1;