6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered
30 trademarks of Be Incorporated in the United States and other countries. Other
31 brand product names are registered trademarks or trademarks of their respective
52 #include <WindowInfo.h>
55 #include "ResourceSet.h"
56 #include "WindowMenuItem.h"
58 #include "tracker_private.h"
60 #define _ALLOW_STICKY_ 0
61 // allows you to press 's' to keep the switcher window on screen
64 static const color_space kIconFormat
= B_RGBA32
;
70 TTeamGroup(BList
* teams
, uint32 flags
, char* name
,
71 const char* signature
);
72 virtual ~TTeamGroup();
74 void Draw(BView
* view
, BRect bounds
, bool main
);
76 BList
* TeamList() const
78 const char* Name() const
80 const char* Signature() const
81 { return fSignature
; }
84 const BBitmap
* SmallIcon() const
85 { return fSmallIcon
; }
86 const BBitmap
* LargeIcon() const
87 { return fLargeIcon
; }
92 char fSignature
[B_MIME_TYPE_LENGTH
];
98 class TSwitcherWindow
: public BWindow
{
100 TSwitcherWindow(BRect frame
,
101 TSwitchManager
* manager
);
102 virtual ~TSwitcherWindow();
104 virtual bool QuitRequested();
105 virtual void MessageReceived(BMessage
* message
);
108 virtual void WindowActivated(bool state
);
110 void DoKey(uint32 key
, uint32 modifiers
);
111 TIconView
* IconView();
112 TWindowView
* WindowView();
115 void Update(int32 previous
, int32 current
,
116 int32 prevSlot
, int32 currentSlot
,
119 void Redraw(int32 index
);
122 TSwitchManager
* fManager
;
123 TIconView
* fIconView
;
125 TWindowView
* fWindowView
;
127 bool fSkipKeyRepeats
;
130 class TWindowView
: public BView
{
132 TWindowView(BRect frame
, TSwitchManager
* manager
,
133 TSwitcherWindow
* switcher
);
135 void UpdateGroup(int32 groupIndex
, int32 windowIndex
);
137 virtual void AttachedToWindow();
138 virtual void Draw(BRect update
);
139 virtual void Pulse();
140 virtual void GetPreferredSize(float* w
, float* h
);
141 void ScrollTo(float x
, float y
)
143 ScrollTo(BPoint(x
, y
));
145 virtual void ScrollTo(BPoint where
);
147 void ShowIndex(int32 windex
);
148 BRect
FrameOf(int32 index
) const;
153 TSwitcherWindow
* fSwitcher
;
154 TSwitchManager
* fManager
;
157 class TIconView
: public BView
{
159 TIconView(BRect frame
, TSwitchManager
* manager
,
160 TSwitcherWindow
* switcher
);
161 virtual ~TIconView();
166 virtual void KeyDown(const char* bytes
, int32 numBytes
);
167 virtual void Pulse();
168 virtual void MouseDown(BPoint point
);
169 virtual void Draw(BRect updateRect
);
171 void ScrollTo(float x
, float y
)
173 ScrollTo(BPoint(x
, y
));
175 virtual void ScrollTo(BPoint where
);
176 void Update(int32 previous
, int32 current
,
177 int32 previousSlot
, int32 currentSlot
,
179 void DrawTeams(BRect update
);
180 int32
SlotOf(int32
) const;
181 BRect
FrameOf(int32
) const;
182 int32
ItemAtPoint(BPoint
) const;
183 int32
IndexAt(int32 slot
) const;
184 void CenterOn(int32 index
);
187 void CacheIcons(TTeamGroup
* group
);
188 void AnimateIcon(BBitmap
* startIcon
, BBitmap
* endIcon
);
191 TSwitcherWindow
* fSwitcher
;
192 TSwitchManager
* fManager
;
195 BBitmap
* fCurrentSmall
;
196 BBitmap
* fCurrentLarge
;
199 class TBox
: public BBox
{
201 TBox(BRect bounds
, TSwitchManager
* manager
,
202 TSwitcherWindow
* window
, TIconView
* iconView
);
204 virtual void Draw(BRect update
);
205 virtual void AllAttached();
206 virtual void DrawIconScrollers(bool force
);
207 virtual void DrawWindowScrollers(bool force
);
208 virtual void MouseDown(BPoint where
);
211 TSwitchManager
* fManager
;
212 TSwitcherWindow
* fWindow
;
213 TIconView
* fIconView
;
222 const int32 kHorizontalMargin
= 11;
223 const int32 kVerticalMargin
= 10;
225 // SLOT_SIZE must be divisible by 4. That's because of the scrolling
226 // animation. If this needs to change then look at TIconView::Update()
228 const int32 kSlotSize
= 36;
229 const int32 kScrollStep
= kSlotSize
/ 2;
230 const int32 kNumSlots
= 7;
231 const int32 kCenterSlot
= 3;
233 const int32 kWindowScrollSteps
= 3;
240 LowBitIndex(uint32 value
)
248 while (result
< 32 && (value
& bitMask
) == 0) {
250 bitMask
= bitMask
<< 1;
257 IsVisibleInCurrentWorkspace(const window_info
* windowInfo
)
259 // The window list is always ordered from the top front visible window
260 // (the first on the list), going down through all the other visible
261 // windows, then all hidden or non-workspace visible windows at the end.
262 // layer > 2 : normal visible window
263 // layer == 2 : reserved for the desktop window (visible also)
264 // layer < 2 : hidden (0) and non workspace visible window (1)
265 return windowInfo
->layer
> 2;
274 get_key_info(&keyInfo
);
275 return (keyInfo
.key_states
[key
>> 3] & (1 << ((7 - key
) & 7))) != 0;
280 IsWindowOK(const window_info
* windowInfo
)
282 // is_mini (true means that the window is minimized).
283 // if not, then show_hide >= 1 means that the window is hidden.
284 // If the window is both minimized and hidden, then you get :
285 // TWindow->is_mini = false;
286 // TWindow->was_mini = true;
287 // TWindow->show_hide >= 1;
289 if (windowInfo
->feel
!= _STD_W_TYPE_
)
292 if (windowInfo
->is_mini
)
295 return windowInfo
->show_hide_level
<= 0;
300 SmartStrcmp(const char* s1
, const char* s2
)
302 if (strcasecmp(s1
, s2
) == 0)
305 // if the strings on differ in spaces or underscores they still match
307 if ((*s1
== ' ') || (*s1
== '_')) {
311 if ((*s2
== ' ') || (*s2
== '_')) {
323 // if one of the strings ended before the other
324 // TODO: could process trailing spaces and underscores
337 TTeamGroup::TTeamGroup()
345 fSignature
[0] = '\0';
349 TTeamGroup::TTeamGroup(BList
* teams
, uint32 flags
, char* name
,
350 const char* signature
)
358 strlcpy(fSignature
, signature
, sizeof(fSignature
));
360 fSmallIcon
= new BBitmap(BRect(0, 0, 15, 15), kIconFormat
);
361 fLargeIcon
= new BBitmap(BRect(0, 0, 31, 31), kIconFormat
);
364 if (be_roster
->GetAppInfo(signature
, &appInfo
) == B_OK
) {
365 BNode
node(&(appInfo
.ref
));
366 if (node
.InitCheck() == B_OK
) {
367 BNodeInfo
nodeInfo(&node
);
368 if (nodeInfo
.InitCheck() == B_OK
) {
369 nodeInfo
.GetTrackerIcon(fSmallIcon
, B_MINI_ICON
);
370 nodeInfo
.GetTrackerIcon(fLargeIcon
, B_LARGE_ICON
);
377 TTeamGroup::~TTeamGroup()
387 TTeamGroup::Draw(BView
* view
, BRect bounds
, bool main
)
391 rect
= fLargeIcon
->Bounds();
392 rect
.OffsetTo(bounds
.LeftTop());
394 view
->DrawBitmap(fLargeIcon
, rect
);
396 rect
= fSmallIcon
->Bounds();
397 rect
.OffsetTo(bounds
.LeftTop());
398 rect
.OffsetBy(10, 10);
399 view
->DrawBitmap(fSmallIcon
, rect
);
407 TSwitchManager::TSwitchManager(BPoint point
)
408 : BHandler("SwitchManager"),
409 fMainMonitor(create_sem(1, "main_monitor")),
413 fQuickSwitchIndex(-1),
414 fQuickSwitchWindow(-1),
420 BRect
rect(point
.x
, point
.y
,
421 point
.x
+ (kSlotSize
* kNumSlots
) - 1 + (2 * kHorizontalMargin
),
423 fWindow
= new TSwitcherWindow(rect
, this);
424 fWindow
->AddHandler(this);
430 TBarApp::Subscribe(BMessenger(this), &tmpList
);
432 for (int32 i
= 0; ; i
++) {
433 BarTeamInfo
* barTeamInfo
= (BarTeamInfo
*)tmpList
.ItemAt(i
);
437 TTeamGroup
* tinfo
= new TTeamGroup(barTeamInfo
->teams
,
438 barTeamInfo
->flags
, barTeamInfo
->name
, barTeamInfo
->sig
);
439 fGroupList
.AddItem(tinfo
);
441 barTeamInfo
->teams
= NULL
;
442 barTeamInfo
->name
= NULL
;
450 TSwitchManager::~TSwitchManager()
452 for (int32 i
= fGroupList
.CountItems() - 1; i
>= 0; i
--) {
453 TTeamGroup
* teamInfo
= static_cast<TTeamGroup
*>(fGroupList
.ItemAt(i
));
460 TSwitchManager::MessageReceived(BMessage
* message
)
462 switch (message
->what
) {
463 case B_SOME_APP_QUIT
:
465 // This is only sent when last team of a matching set quits
469 message
->FindInt32("team", &teamID
);
471 while ((tinfo
= (TTeamGroup
*)fGroupList
.ItemAt(i
)) != NULL
) {
472 if (tinfo
->TeamList()->HasItem((void*)(addr_t
)teamID
)) {
473 fGroupList
.RemoveItem(i
);
476 if (i
<= fCurrentIndex
) {
488 case B_SOME_APP_LAUNCHED
:
494 const char* signature
;
496 if (message
->FindPointer("teams", (void**)&teams
) != B_OK
)
499 if (message
->FindPointer("icon", (void**)&smallIcon
) != B_OK
) {
506 if (message
->FindString("sig", &signature
) != B_OK
) {
511 if (message
->FindInt32("flags", (int32
*)&flags
) != B_OK
) {
516 if (message
->FindString("name", &name
) != B_OK
) {
521 TTeamGroup
* tinfo
= new TTeamGroup(teams
, flags
, strdup(name
),
524 fGroupList
.AddItem(tinfo
);
525 fWindow
->Redraw(fGroupList
.CountItems() - 1);
532 const char* signature
= message
->FindString("sig");
533 team_id team
= message
->FindInt32("team");
534 int32 count
= fGroupList
.CountItems();
536 for (int32 i
= 0; i
< count
; i
++) {
537 TTeamGroup
* tinfo
= (TTeamGroup
*)fGroupList
.ItemAt(i
);
538 if (strcasecmp(tinfo
->Signature(), signature
) == 0) {
539 if (!(tinfo
->TeamList()->HasItem((void*)(addr_t
)team
)))
540 tinfo
->TeamList()->AddItem((void*)(addr_t
)team
);
549 team_id team
= message
->FindInt32("team");
550 int32 count
= fGroupList
.CountItems();
552 for (int32 i
= 0; i
< count
; i
++) {
553 TTeamGroup
* tinfo
= (TTeamGroup
*)fGroupList
.ItemAt(i
);
554 if (tinfo
->TeamList()->HasItem((void*)(addr_t
)team
)) {
555 tinfo
->TeamList()->RemoveItem((void*)(addr_t
)team
);
564 // The first TASK message calls MainEntry. Subsequent ones
567 message
->FindInt64("when", (int64
*)&time
);
569 // The fSkipUntil stuff can be removed once the new input_server
570 // starts differentiating initial key_downs from KeyDowns generated
571 // by auto-repeat. Until then the fSkipUntil stuff helps, but it
573 if (time
< fSkipUntil
)
576 status_t status
= acquire_sem_etc(fMainMonitor
, 1, B_TIMEOUT
, 0);
577 if (status
!= B_OK
) {
578 if (!fWindow
->IsHidden() && !fBlock
) {
579 // Want to skip TASK msgs posted before the window
580 // was made visible. Better UI feel if we do this.
581 if (time
> fSkipUntil
) {
582 uint32 modifiers
= 0;
583 message
->FindInt32("modifiers", (int32
*)&modifiers
);
585 message
->FindInt32("key", &key
);
587 Process((modifiers
& B_SHIFT_KEY
) == 0, key
== 0x11);
603 TSwitchManager::_SortApps()
607 if (BPrivate::get_application_order(current_workspace(), &teams
, &count
)
612 if (!groups
.AddList(&fGroupList
)) {
617 fGroupList
.MakeEmpty();
619 for (int32 i
= 0; i
< count
; i
++) {
621 TTeamGroup
* info
= NULL
;
622 for (int32 j
= 0; (info
= (TTeamGroup
*)groups
.ItemAt(j
)) != NULL
; j
++) {
623 if (info
->TeamList()->HasItem((void*)(addr_t
)teams
[i
])) {
624 groups
.RemoveItem(j
);
630 fGroupList
.AddItem(info
);
633 fGroupList
.AddList(&groups
);
634 // add the remaining entries
640 TSwitchManager::MainEntry(BMessage
* message
)
642 bigtime_t now
= system_time();
643 bigtime_t timeout
= now
+ 180000;
644 // The above delay has a good "feel" found by trial and error
647 be_roster
->GetActiveAppInfo(&appInfo
);
649 bool resetQuickSwitch
= false;
651 if (now
> fLastSwitch
+ 400000) {
653 resetQuickSwitch
= true;
659 fCurrentIndex
= FindTeam(appInfo
.team
, &index
) != NULL
? index
: 0;
661 if (resetQuickSwitch
) {
662 fQuickSwitchIndex
= fCurrentIndex
;
663 fQuickSwitchWindow
= fCurrentWindow
;
667 message
->FindInt32("key", (int32
*)&key
);
669 uint32 modifierKeys
= 0;
670 while (system_time() < timeout
) {
671 modifierKeys
= modifiers();
672 if (!IsKeyDown(key
)) {
673 QuickSwitch(message
);
676 if ((modifierKeys
& B_CONTROL_KEY
) == 0) {
677 QuickSwitch(message
);
681 // Must be a multiple of the delay used above
684 Process((modifierKeys
& B_SHIFT_KEY
) == 0, key
== 0x11);
689 TSwitchManager::Stop(bool do_action
, uint32
)
693 ActivateApp(true, true);
695 release_sem(fMainMonitor
);
700 TSwitchManager::FindTeam(team_id teamID
, int32
* index
)
704 while ((info
= (TTeamGroup
*)fGroupList
.ItemAt(i
)) != NULL
) {
705 if (info
->TeamList()->HasItem((void*)(addr_t
)teamID
)) {
717 TSwitchManager::Process(bool forward
, bool byWindow
)
720 if (fWindow
->Lock()) {
721 hidden
= fWindow
->IsHidden();
725 // If hidden we need to get things started by switching to correct app
727 SwitchToApp(fCurrentIndex
, fCurrentIndex
, forward
);
728 CycleWindow(forward
, true);
730 CycleApp(forward
, false);
733 // more auto keyrepeat code
734 // Because of key repeats we don't want to respond to any extraneous
735 // 'TASK' messages until the window is completely shown. So block here.
736 // the WindowActivated hook function will unblock.
739 if (fWindow
->Lock()) {
740 BRect screenFrame
= BScreen().Frame();
741 BRect windowFrame
= fWindow
->Frame();
743 if (!screenFrame
.Contains(windowFrame
)) {
745 BPoint
point((screenFrame
.left
+ screenFrame
.right
) / 2,
746 (screenFrame
.top
+ screenFrame
.bottom
) / 2);
748 point
.x
-= (windowFrame
.Width() / 2);
749 point
.y
-= (windowFrame
.Height() / 2);
750 fWindow
->MoveTo(point
);
761 TSwitchManager::QuickSwitch(BMessage
* message
)
763 uint32 modifiers
= 0;
764 message
->FindInt32("modifiers", (int32
*)&modifiers
);
766 message
->FindInt32("key", &key
);
769 if (message
->FindInt32("team", &team
) == B_OK
) {
770 bool forward
= (modifiers
& B_SHIFT_KEY
) == 0;
773 // TODO: add the same switch logic we have for apps!
774 SwitchWindow(team
, forward
, true);
776 if (fQuickSwitchIndex
>= 0) {
777 // Switch to the first app inbetween to make it always the next
778 // app to switch to after the quick switch.
779 int32 current
= fCurrentIndex
;
780 SwitchToApp(current
, fQuickSwitchIndex
, false);
781 ActivateApp(false, false);
783 fCurrentIndex
= current
;
786 CycleApp(forward
, true);
790 release_sem(fMainMonitor
);
795 TSwitchManager::CycleWindow(bool forward
, bool wrap
)
797 int32 max
= CountWindows(fCurrentIndex
);
798 int32 prev
= fCurrentWindow
;
799 int32 next
= fCurrentWindow
;
816 fCurrentWindow
= next
;
818 if (fCurrentWindow
!= prev
)
819 fWindow
->WindowView()->ShowIndex(fCurrentWindow
);
824 TSwitchManager::CycleApp(bool forward
, bool activateNow
)
826 int32 startIndex
= fCurrentIndex
;
828 if (_FindNextValidApp(forward
)) {
829 // if we're here then we found a good one
830 SwitchToApp(startIndex
, fCurrentIndex
, forward
);
835 ActivateApp(false, false);
841 TSwitchManager::_FindNextValidApp(bool forward
)
843 if (fGroupList
.IsEmpty())
846 int32 max
= fGroupList
.CountItems();
849 if (fCurrentIndex
>= max
)
853 if (fCurrentIndex
< 0)
854 fCurrentIndex
= max
- 1;
862 TSwitchManager::SwitchToApp(int32 previousIndex
, int32 newIndex
, bool forward
)
864 int32 previousSlot
= fCurrentSlot
;
866 fCurrentIndex
= newIndex
;
867 fCurrentSlot
= fWindow
->SlotOf(fCurrentIndex
);
870 fWindow
->Update(previousIndex
, fCurrentIndex
, previousSlot
, fCurrentSlot
,
876 TSwitchManager::ActivateApp(bool forceShow
, bool allowWorkspaceSwitch
)
878 // Let's get the info about the selected window. If it doesn't exist
879 // anymore then get info about first window. If that doesn't exist then
881 client_window_info
* windowInfo
= WindowInfo(fCurrentIndex
, fCurrentWindow
);
882 if (windowInfo
== NULL
) {
883 windowInfo
= WindowInfo(fCurrentIndex
, 0);
884 if (windowInfo
== NULL
)
888 int32 currentWorkspace
= current_workspace();
889 TTeamGroup
* teamGroup
= (TTeamGroup
*)fGroupList
.ItemAt(fCurrentIndex
);
891 // Let's handle the easy case first: There's only 1 team in the group
892 if (teamGroup
->TeamList()->CountItems() == 1) {
894 if (forceShow
&& (fCurrentWindow
!= 0 || windowInfo
->is_mini
)) {
895 do_window_action(windowInfo
->server_token
, B_BRING_TO_FRONT
,
896 BRect(0, 0, 0, 0), false);
899 if (!forceShow
&& windowInfo
->is_mini
) {
900 // we aren't unhiding minimized windows, so we can't do
903 } else if (!allowWorkspaceSwitch
904 && (windowInfo
->workspaces
& (1 << currentWorkspace
)) == 0) {
905 // we're not supposed to switch workspaces so abort.
909 be_roster
->ActivateApp((addr_t
)teamGroup
->TeamList()->ItemAt(0));
917 // Now the trickier case. We're trying to Bring to the Front a group
918 // of teams. The current window (defined by fCurrentWindow) will define
919 // which workspace we're going to. Then, once that is determined we
920 // want to bring to the front every window of the group of teams that
921 // lives in that workspace.
923 if ((windowInfo
->workspaces
& (1 << currentWorkspace
)) == 0) {
924 if (!allowWorkspaceSwitch
) {
925 // If the first window in the list isn't in current workspace,
926 // then none are. So we can't switch to this app.
931 int32 destWorkspace
= LowBitIndex(windowInfo
->workspaces
);
932 // now switch to that workspace
933 activate_workspace(destWorkspace
);
936 if (!forceShow
&& windowInfo
->is_mini
) {
937 // If the first window in the list is hidden then no windows in
938 // this group are visible. So we can't switch to this app.
945 int32
* tokens
= get_token_list(-1, &tokenCount
);
946 if (tokens
== NULL
) {
950 // weird error, so don't try to recover
953 BList windowsToActivate
;
955 // Now we go through all the windows in the current workspace list in order.
956 // As we hit member teams we build the "activate" list.
957 for (int32 i
= 0; i
< tokenCount
; i
++) {
958 client_window_info
* matchWindowInfo
= get_window_info(tokens
[i
]);
959 if (!matchWindowInfo
) {
960 // That window probably closed. Just go to the next one.
963 if (!IsVisibleInCurrentWorkspace(matchWindowInfo
)) {
964 // first non-visible in workspace window means we're done.
965 free(matchWindowInfo
);
968 if (matchWindowInfo
->server_token
!= windowInfo
->server_token
969 && teamGroup
->TeamList()->HasItem((void*)(addr_t
)matchWindowInfo
->team
))
970 windowsToActivate
.AddItem((void*)(addr_t
)matchWindowInfo
->server_token
);
972 free(matchWindowInfo
);
977 // Want to go through the list backwards to keep windows in same relative
979 int32 i
= windowsToActivate
.CountItems() - 1;
980 for (; i
>= 0; i
--) {
981 int32 wid
= (addr_t
)windowsToActivate
.ItemAt(i
);
982 do_window_action(wid
, B_BRING_TO_FRONT
, BRect(0, 0, 0, 0), false);
985 // now bring the select window on top of everything.
987 do_window_action(windowInfo
->server_token
, B_BRING_TO_FRONT
,
988 BRect(0, 0, 0, 0), false);
996 \brief quit all teams in this group
999 TSwitchManager::QuitApp()
1001 // we should not be trying to quit an app if we have an empty list
1002 if (fGroupList
.IsEmpty())
1005 TTeamGroup
* teamGroup
= (TTeamGroup
*)fGroupList
.ItemAt(fCurrentIndex
);
1006 if (fCurrentIndex
== fGroupList
.CountItems() - 1) {
1007 // if we're in the last slot already (the last usable team group)
1008 // switch to previous app in the list so that we don't jump to
1009 // the start of the list (try to keep the same position when
1010 // the apps at the current index go away)
1011 CycleApp(false, false);
1014 // send the quit request to all teams in this group
1015 for (int32 i
= teamGroup
->TeamList()->CountItems() - 1; i
>= 0; i
--) {
1016 team_id team
= (addr_t
)teamGroup
->TeamList()->ItemAt(i
);
1018 if (be_roster
->GetRunningAppInfo(team
, &info
) == B_OK
) {
1019 if (strcasecmp(info
.signature
, kTrackerSignature
) == 0) {
1020 // Tracker can't be quit this way
1024 BMessenger
messenger(NULL
, team
);
1025 messenger
.SendMessage(B_QUIT_REQUESTED
);
1032 \brief hide all teams in this group
1035 TSwitchManager::HideApp()
1037 // we should not be trying to hide an app if we have an empty list
1038 if (fGroupList
.IsEmpty())
1041 TTeamGroup
* teamGroup
= (TTeamGroup
*)fGroupList
.ItemAt(fCurrentIndex
);
1043 for (int32 i
= teamGroup
->TeamList()->CountItems() - 1; i
>= 0; i
--) {
1044 team_id team
= (addr_t
)teamGroup
->TeamList()->ItemAt(i
);
1046 if (be_roster
->GetRunningAppInfo(team
, &info
) == B_OK
)
1047 do_minimize_team(BRect(), team
, false);
1053 TSwitchManager::WindowInfo(int32 groupIndex
, int32 windowIndex
)
1055 TTeamGroup
* teamGroup
= (TTeamGroup
*)fGroupList
.ItemAt(groupIndex
);
1056 if (teamGroup
== NULL
)
1060 int32
* tokens
= get_token_list(-1, &tokenCount
);
1066 // Want to find the "windowIndex'th" window in window order that belongs
1067 // the the specified group (groupIndex). Since multiple teams can belong to
1068 // the same group (multiple-launch apps) we get the list of _every_
1069 // window and go from there.
1071 client_window_info
* result
= NULL
;
1072 for (int32 i
= 0; i
< tokenCount
; i
++) {
1073 client_window_info
* windowInfo
= get_window_info(tokens
[i
]);
1075 // skip hidden/special windows
1076 if (IsWindowOK(windowInfo
)
1077 && (teamGroup
->TeamList()->HasItem((void*)(addr_t
)windowInfo
->team
))) {
1078 // this window belongs to the team!
1079 if (matches
== windowIndex
) {
1081 result
= windowInfo
;
1088 // else - that window probably closed. Just go to the next one.
1098 TSwitchManager::CountWindows(int32 groupIndex
, bool )
1100 TTeamGroup
* teamGroup
= (TTeamGroup
*)fGroupList
.ItemAt(groupIndex
);
1106 for (int32 i
= 0; ; i
++) {
1107 team_id teamID
= (addr_t
)teamGroup
->TeamList()->ItemAt(i
);
1112 int32
* tokens
= get_token_list(teamID
, &count
);
1116 for (int32 i
= 0; i
< count
; i
++) {
1117 window_info
*windowInfo
= get_window_info(tokens
[i
]);
1119 if (IsWindowOK(windowInfo
))
1132 TSwitchManager::ActivateWindow(int32 windowID
)
1135 windowID
= fWindowID
;
1137 do_window_action(windowID
, B_BRING_TO_FRONT
, BRect(0, 0, 0, 0), false);
1142 TSwitchManager::SwitchWindow(team_id team
, bool, bool activate
)
1144 // Find the _last_ window in the current workspace that belongs
1145 // to the group. This is the window to activate.
1148 TTeamGroup
* teamGroup
= FindTeam(team
, &index
);
1150 // cycle through the windows in the active application
1152 int32
* tokens
= get_token_list(-1, &count
);
1156 for (int32 i
= count
- 1; i
>= 0; i
--) {
1157 client_window_info
* windowInfo
= get_window_info(tokens
[i
]);
1158 if (windowInfo
&& IsVisibleInCurrentWorkspace(windowInfo
)
1159 && teamGroup
->TeamList()->HasItem((void*)(addr_t
)windowInfo
->team
)) {
1160 fWindowID
= windowInfo
->server_token
;
1162 ActivateWindow(windowInfo
->server_token
);
1174 TSwitchManager::Unblock()
1177 fSkipUntil
= system_time();
1182 TSwitchManager::CurrentIndex()
1184 return fCurrentIndex
;
1189 TSwitchManager::CurrentWindow()
1191 return fCurrentWindow
;
1196 TSwitchManager::CurrentSlot()
1198 return fCurrentSlot
;
1203 TSwitchManager::GroupList()
1212 TBox::TBox(BRect bounds
, TSwitchManager
* manager
, TSwitcherWindow
* window
,
1213 TIconView
* iconView
)
1215 BBox(bounds
, "top", B_FOLLOW_ALL
, B_WILL_DRAW
, B_NO_BORDER
),
1218 fIconView(iconView
),
1219 fLeftScroller(false),
1220 fRightScroller(false),
1222 fDownScroller(false)
1230 BRect
centerRect(kCenterSlot
* kSlotSize
, 0,
1231 (kCenterSlot
+ 1) * kSlotSize
- 1, kSlotSize
- 1);
1232 BRect frame
= fIconView
->Frame();
1234 // scroll the centerRect to correct location
1235 centerRect
.OffsetBy(frame
.left
, frame
.top
);
1237 // switch to local coords
1238 fIconView
->ConvertToParent(¢erRect
);
1240 fCenter
= centerRect
;
1245 TBox::MouseDown(BPoint where
)
1247 if (!fLeftScroller
&& !fRightScroller
&& !fUpScroller
&& !fDownScroller
)
1250 BRect frame
= fIconView
->Frame();
1251 BRect bounds
= Bounds();
1253 if (fLeftScroller
) {
1254 BRect
lhit(0, frame
.top
, frame
.left
, frame
.bottom
);
1255 if (lhit
.Contains(where
)) {
1256 // Want to scroll by NUMSLOTS - 1 slots
1257 int32 previousIndex
= fManager
->CurrentIndex();
1258 int32 previousSlot
= fManager
->CurrentSlot();
1259 int32 newSlot
= previousSlot
- (kNumSlots
- 1);
1263 int32 newIndex
= fIconView
->IndexAt(newSlot
);
1264 fManager
->SwitchToApp(previousIndex
, newIndex
, false);
1268 if (fRightScroller
) {
1269 BRect
rhit(frame
.right
, frame
.top
, bounds
.right
, frame
.bottom
);
1270 if (rhit
.Contains(where
)) {
1271 // Want to scroll by NUMSLOTS - 1 slots
1272 int32 previousIndex
= fManager
->CurrentIndex();
1273 int32 previousSlot
= fManager
->CurrentSlot();
1274 int32 newSlot
= previousSlot
+ (kNumSlots
- 1);
1275 int32 newIndex
= fIconView
->IndexAt(newSlot
);
1278 // don't have a page full to scroll
1279 newIndex
= fManager
->GroupList()->CountItems() - 1;
1281 fManager
->SwitchToApp(previousIndex
, newIndex
, true);
1285 frame
= fWindow
->WindowView()->Frame();
1287 BRect
hit1(frame
.left
- 10, frame
.top
, frame
.left
,
1288 (frame
.top
+ frame
.bottom
) / 2);
1289 BRect
hit2(frame
.right
, frame
.top
, frame
.right
+ 10,
1290 (frame
.top
+ frame
.bottom
) / 2);
1291 if (hit1
.Contains(where
) || hit2
.Contains(where
)) {
1292 // Want to scroll up 1 window
1293 fManager
->CycleWindow(false, false);
1297 if (fDownScroller
) {
1298 BRect
hit1(frame
.left
- 10, (frame
.top
+ frame
.bottom
) / 2,
1299 frame
.left
, frame
.bottom
);
1300 BRect
hit2(frame
.right
, (frame
.top
+ frame
.bottom
) / 2,
1301 frame
.right
+ 10, frame
.bottom
);
1302 if (hit1
.Contains(where
) || hit2
.Contains(where
)) {
1303 // Want to scroll down 1 window
1304 fManager
->CycleWindow(true, false);
1311 TBox::Draw(BRect update
)
1313 static const int32 kChildInset
= 7;
1314 static const int32 kWedge
= 6;
1318 // The fancy border around the icon view
1320 BRect bounds
= Bounds();
1321 float height
= fIconView
->Bounds().Height();
1322 float center
= (bounds
.right
+ bounds
.left
) / 2;
1324 BRect
box(3, 3, bounds
.right
- 3, 3 + height
+ kChildInset
* 2);
1325 rgb_color panelColor
= ui_color(B_PANEL_BACKGROUND_COLOR
);
1326 rgb_color white
= {255, 255, 255, 255};
1327 rgb_color standardGray
= panelColor
;
1328 rgb_color veryDarkGray
= {128, 128, 128, 255};
1329 rgb_color darkGray
= tint_color(panelColor
, B_DARKEN_1_TINT
);
1331 if (panelColor
.Brightness() < 100) {
1332 standardGray
= tint_color(panelColor
, 0.8);
1333 darkGray
= tint_color(panelColor
, 0.85);
1334 white
= make_color(200, 200, 200, 255);
1335 veryDarkGray
= make_color(0, 0, 0, 255);
1338 // Fill the area with dark gray
1339 SetHighColor(darkGray
);
1343 box
.InsetBy(-1, -1);
1347 // The main frame around the icon view
1348 AddLine(box
.LeftTop(), BPoint(center
- kWedge
, box
.top
), veryDarkGray
);
1349 AddLine(BPoint(center
+ kWedge
, box
.top
), box
.RightTop(), veryDarkGray
);
1351 AddLine(box
.LeftBottom(), BPoint(center
- kWedge
, box
.bottom
),
1353 AddLine(BPoint(center
+ kWedge
, box
.bottom
), box
.RightBottom(),
1355 AddLine(box
.LeftBottom() + BPoint(1, 1),
1356 BPoint(center
- kWedge
, box
.bottom
+ 1), white
);
1357 AddLine(BPoint(center
+ kWedge
, box
.bottom
) + BPoint(0, 1),
1358 box
.RightBottom() + BPoint(1, 1), white
);
1360 AddLine(box
.LeftTop(), box
.LeftBottom(), veryDarkGray
);
1361 AddLine(box
.RightTop(), box
.RightBottom(), veryDarkGray
);
1362 AddLine(box
.RightTop() + BPoint(1, 1), box
.RightBottom() + BPoint(1, 1),
1365 // downward pointing area at top of frame
1366 BPoint
point(center
- kWedge
, box
.top
);
1367 AddLine(point
, point
+ BPoint(kWedge
, kWedge
), veryDarkGray
);
1368 AddLine(point
+ BPoint(kWedge
, kWedge
), BPoint(center
+ kWedge
, point
.y
),
1371 AddLine(point
+ BPoint(1, 0), point
+ BPoint(1, 0)
1372 + BPoint(kWedge
- 1, kWedge
- 1), white
);
1374 AddLine(point
+ BPoint(2, -1) + BPoint(kWedge
- 1, kWedge
- 1),
1375 BPoint(center
+ kWedge
- 1, point
.y
), darkGray
);
1377 BPoint topPoint
= point
;
1379 // upward pointing area at bottom of frame
1380 point
.y
= box
.bottom
;
1381 point
.x
= center
- kWedge
;
1382 AddLine(point
, point
+ BPoint(kWedge
, -kWedge
), veryDarkGray
);
1383 AddLine(point
+ BPoint(kWedge
, -kWedge
),
1384 BPoint(center
+ kWedge
, point
.y
), veryDarkGray
);
1386 AddLine(point
+ BPoint(1, 0),
1387 point
+ BPoint(1, 0) + BPoint(kWedge
- 1, -(kWedge
- 1)), white
);
1389 AddLine(point
+ BPoint(2 , 1) + BPoint(kWedge
- 1, -(kWedge
- 1)),
1390 BPoint(center
+ kWedge
- 1, point
.y
), darkGray
);
1392 BPoint bottomPoint
= point
;
1396 // fill the downward pointing arrow area
1397 SetHighColor(standardGray
);
1398 FillTriangle(topPoint
+ BPoint(2, 0),
1399 topPoint
+ BPoint(2, 0) + BPoint(kWedge
- 2, kWedge
- 2),
1400 BPoint(center
+ kWedge
- 2, topPoint
.y
));
1402 // fill the upward pointing arrow area
1403 SetHighColor(standardGray
);
1404 FillTriangle(bottomPoint
+ BPoint(2, 0),
1405 bottomPoint
+ BPoint(2, 0) + BPoint(kWedge
- 2, -(kWedge
- 2)),
1406 BPoint(center
+ kWedge
- 2, bottomPoint
.y
));
1408 DrawIconScrollers(false);
1409 DrawWindowScrollers(false);
1415 TBox::DrawIconScrollers(bool force
)
1417 rgb_color panelColor
= ui_color(B_PANEL_BACKGROUND_COLOR
);
1418 rgb_color backgroundColor
;
1421 if (panelColor
.Brightness() > 100) {
1422 backgroundColor
= tint_color(panelColor
, B_DARKEN_1_TINT
);
1423 dark
= tint_color(backgroundColor
, B_DARKEN_3_TINT
);
1425 backgroundColor
= tint_color(panelColor
, 0.85);
1426 dark
= tint_color(panelColor
, B_LIGHTEN_1_TINT
);
1429 bool updateLeft
= false;
1430 bool updateRight
= false;
1432 BRect rect
= fIconView
->Bounds();
1433 if (rect
.left
> (kSlotSize
* kCenterSlot
)) {
1435 fLeftScroller
= true;
1437 fLeftScroller
= false;
1442 int32 maxIndex
= fManager
->GroupList()->CountItems() - 1;
1443 // last_frame is in fIconView coordinate space
1444 BRect lastFrame
= fIconView
->FrameOf(maxIndex
);
1446 if (lastFrame
.right
> rect
.right
) {
1448 fRightScroller
= true;
1450 fRightScroller
= false;
1456 SetDrawingMode(B_OP_COPY
);
1458 rect
= fIconView
->Frame();
1460 BPoint pt1
, pt2
, pt3
;
1461 pt1
.x
= rect
.left
- 5;
1462 pt1
.y
= floorf((rect
.bottom
+ rect
.top
) / 2);
1463 pt2
.x
= pt3
.x
= pt1
.x
+ 3;
1467 if (fLeftScroller
) {
1469 FillTriangle(pt1
, pt2
, pt3
);
1471 SetHighColor(backgroundColor
);
1472 FillRect(BRect(pt1
.x
, pt2
.y
, pt3
.x
, pt3
.y
));
1476 BPoint pt1
, pt2
, pt3
;
1477 pt1
.x
= rect
.right
+ 4;
1478 pt1
.y
= rintf((rect
.bottom
+ rect
.top
) / 2);
1479 pt2
.x
= pt3
.x
= pt1
.x
- 4;
1483 if (fRightScroller
) {
1485 FillTriangle(pt1
, pt2
, pt3
);
1487 SetHighColor(backgroundColor
);
1488 FillRect(BRect(pt3
.x
, pt2
.y
, pt1
.x
, pt3
.y
));
1497 TBox::DrawWindowScrollers(bool force
)
1499 rgb_color panelColor
= ui_color(B_PANEL_BACKGROUND_COLOR
);
1500 rgb_color backgroundColor
;
1503 if (panelColor
.Brightness() > 100) {
1504 backgroundColor
= tint_color(panelColor
, B_DARKEN_1_TINT
);
1505 dark
= tint_color(backgroundColor
, B_DARKEN_2_TINT
);
1507 backgroundColor
= panelColor
;
1508 dark
= tint_color(panelColor
, B_LIGHTEN_2_TINT
);
1511 bool updateUp
= false;
1512 bool updateDown
= false;
1514 BRect rect
= fWindow
->WindowView()->Bounds();
1515 if (rect
.top
!= 0) {
1519 fUpScroller
= false;
1524 int32 groupIndex
= fManager
->CurrentIndex();
1525 int32 maxIndex
= fManager
->CountWindows(groupIndex
) - 1;
1527 BRect
lastFrame(0, 0, 0, 0);
1529 lastFrame
= fWindow
->WindowView()->FrameOf(maxIndex
);
1531 if (maxIndex
>= 0 && lastFrame
.bottom
> rect
.bottom
) {
1533 fDownScroller
= true;
1535 fDownScroller
= false;
1541 SetDrawingMode(B_OP_COPY
);
1543 rect
= fWindow
->WindowView()->Frame();
1544 rect
.InsetBy(-3, 0);
1548 BPoint pt1
, pt2
, pt3
;
1549 pt1
.x
= rect
.left
- 6;
1550 pt1
.y
= rect
.top
+ 3;
1551 pt2
.y
= pt3
.y
= pt1
.y
+ 4;
1554 FillTriangle(pt1
, pt2
, pt3
);
1556 pt1
.x
+= rect
.Width() + 12;
1557 pt2
.x
+= rect
.Width() + 12;
1558 pt3
.x
+= rect
.Width() + 12;
1559 FillTriangle(pt1
, pt2
, pt3
);
1561 FillRect(BRect(rect
.left
- 10, rect
.top
+ 3, rect
.left
- 2,
1562 rect
.top
+ 7), B_SOLID_LOW
);
1563 FillRect(BRect(rect
.right
+ 2, rect
.top
+ 3, rect
.right
+ 10,
1564 rect
.top
+ 7), B_SOLID_LOW
);
1568 if (fDownScroller
) {
1570 BPoint pt1
, pt2
, pt3
;
1571 pt1
.x
= rect
.left
- 6;
1572 pt1
.y
= rect
.bottom
- 3;
1573 pt2
.y
= pt3
.y
= pt1
.y
- 4;
1576 FillTriangle(pt1
, pt2
, pt3
);
1578 pt1
.x
+= rect
.Width() + 12;
1579 pt2
.x
+= rect
.Width() + 12;
1580 pt3
.x
+= rect
.Width() + 12;
1581 FillTriangle(pt1
, pt2
, pt3
);
1583 FillRect(BRect(rect
.left
- 10, rect
.bottom
- 7, rect
.left
- 2,
1584 rect
.bottom
- 3), B_SOLID_LOW
);
1585 FillRect(BRect(rect
.right
+ 2, rect
.bottom
- 7, rect
.right
+ 10,
1586 rect
.bottom
- 3), B_SOLID_LOW
);
1598 TSwitcherWindow::TSwitcherWindow(BRect frame
, TSwitchManager
* manager
)
1600 BWindow(frame
, "Twitcher", B_MODAL_WINDOW_LOOK
, B_MODAL_ALL_WINDOW_FEEL
,
1601 B_NOT_MINIMIZABLE
| B_NOT_ZOOMABLE
| B_NOT_RESIZABLE
, B_ALL_WORKSPACES
),
1606 rect
.OffsetTo(B_ORIGIN
);
1607 rect
.InsetBy(kHorizontalMargin
, 0);
1608 rect
.top
= kVerticalMargin
;
1609 rect
.bottom
= rect
.top
+ kSlotSize
- 1;
1611 fIconView
= new TIconView(rect
, manager
, this);
1613 rect
.top
= rect
.bottom
+ (kVerticalMargin
* 1 + 4);
1616 fWindowView
= new TWindowView(rect
, manager
, this);
1617 fWindowView
->ResizeToPreferred();
1619 fTopView
= new TBox(Bounds(), fManager
, this, fIconView
);
1621 fTopView
->SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
1622 fTopView
->SetLowUIColor(B_PANEL_BACKGROUND_COLOR
);
1623 fTopView
->SetHighUIColor(B_PANEL_TEXT_COLOR
);
1626 fTopView
->AddChild(fIconView
);
1627 fTopView
->AddChild(fWindowView
);
1629 if (be_plain_font
->Size() != 12) {
1630 float sizeDelta
= be_plain_font
->Size() - 12;
1631 ResizeBy(0, sizeDelta
);
1636 TSwitcherWindow::~TSwitcherWindow()
1642 TSwitcherWindow::MessageReceived(BMessage
* message
)
1644 switch (message
->what
) {
1645 case B_UNMAPPED_KEY_DOWN
:
1649 if (message
->FindInt32("be:key_repeat", &repeats
) == B_OK
1650 && (fSkipKeyRepeats
|| (repeats
% 6) != 0))
1653 // The first actual key press let's us listening to repeated keys
1654 fSkipKeyRepeats
= false;
1658 message
->FindInt32("raw_char", 0, (int32
*)&rawChar
);
1659 message
->FindInt32("modifiers", 0, (int32
*)&modifiers
);
1660 DoKey(rawChar
, modifiers
);
1665 BWindow::MessageReceived(message
);
1671 TSwitcherWindow::Redraw(int32 index
)
1673 BRect frame
= fIconView
->FrameOf(index
);
1674 frame
.right
= fIconView
->Bounds().right
;
1675 fIconView
->Invalidate(frame
);
1680 TSwitcherWindow::DoKey(uint32 key
, uint32 modifiers
)
1682 bool forward
= ((modifiers
& B_SHIFT_KEY
) == 0);
1686 fManager
->CycleApp(true, false);
1691 fManager
->CycleApp(false, false);
1695 fManager
->CycleWindow(false, false);
1699 fManager
->CycleWindow(true, false);
1703 fManager
->CycleApp(forward
, false);
1707 fManager
->Stop(false, 0);
1712 fManager
->Stop(true, modifiers
);
1717 fManager
->QuitApp();
1722 fManager
->HideApp();
1729 SetLook(B_TITLED_WINDOW_LOOK
);
1730 fHairTrigger
= false;
1732 SetLook(B_MODAL_WINDOW_LOOK
);
1733 fHairTrigger
= true;
1742 TSwitcherWindow::QuitRequested()
1744 ((TBarApp
*)be_app
)->Settings()->switcherLoc
= Frame().LeftTop();
1745 fManager
->Stop(false, 0);
1751 TSwitcherWindow::WindowActivated(bool state
)
1754 fManager
->Unblock();
1759 TSwitcherWindow::Update(int32 prev
, int32 current
, int32 previousSlot
,
1760 int32 currentSlot
, bool forward
)
1763 fIconView
->Update(prev
, current
, previousSlot
, currentSlot
, forward
);
1765 fIconView
->CenterOn(current
);
1767 fWindowView
->UpdateGroup(current
, 0);
1772 TSwitcherWindow::Hide()
1774 fIconView
->Hiding();
1781 TSwitcherWindow::Show()
1783 fHairTrigger
= true;
1784 fSkipKeyRepeats
= true;
1785 fIconView
->Showing();
1786 SetPulseRate(100000);
1787 SetLook(B_MODAL_WINDOW_LOOK
);
1793 TSwitcherWindow::TopView()
1800 TSwitcherWindow::HairTrigger()
1802 return fHairTrigger
;
1807 TSwitcherWindow::SlotOf(int32 i
)
1809 return fIconView
->SlotOf(i
);
1814 TSwitcherWindow::IconView()
1821 TSwitcherWindow::WindowView()
1830 TIconView::TIconView(BRect frame
, TSwitchManager
* manager
,
1831 TSwitcherWindow
* switcherWindow
)
1832 : BView(frame
, "main_view", B_FOLLOW_NONE
,
1833 B_WILL_DRAW
| B_PULSE_NEEDED
),
1834 fAutoScrolling(false),
1835 fSwitcher(switcherWindow
),
1838 BRect
rect(0, 0, kSlotSize
- 1, kSlotSize
- 1);
1840 fOffView
= new BView(rect
, "off_view", B_FOLLOW_NONE
, B_WILL_DRAW
);
1841 fOffBitmap
= new BBitmap(rect
, B_RGB32
, true);
1842 fOffBitmap
->AddChild(fOffView
);
1844 fCurrentSmall
= new BBitmap(BRect(0, 0, 15, 15), kIconFormat
);
1845 fCurrentLarge
= new BBitmap(BRect(0, 0, 31, 31), kIconFormat
);
1849 TIconView::~TIconView()
1851 delete fCurrentSmall
;
1852 delete fCurrentLarge
;
1858 TIconView::KeyDown(const char* /*bytes*/, int32
/*numBytes*/)
1864 TIconView::CacheIcons(TTeamGroup
* teamGroup
)
1866 const BBitmap
* bitmap
= teamGroup
->SmallIcon();
1868 fCurrentSmall
->SetBits(bitmap
->Bits(), bitmap
->BitsLength(), 0,
1869 bitmap
->ColorSpace());
1871 bitmap
= teamGroup
->LargeIcon();
1873 fCurrentLarge
->SetBits(bitmap
->Bits(), bitmap
->BitsLength(), 0,
1874 bitmap
->ColorSpace());
1879 TIconView::AnimateIcon(BBitmap
* startIcon
, BBitmap
* endIcon
)
1881 BRect
centerRect(kCenterSlot
* kSlotSize
, 0,
1882 (kCenterSlot
+ 1) * kSlotSize
- 1, kSlotSize
- 1);
1883 BRect startIconBounds
= startIcon
->Bounds();
1884 BRect bounds
= Bounds();
1885 float width
= startIconBounds
.Width();
1886 int32 amount
= (width
< 20) ? -2 : 2;
1888 // center the starting icon inside of centerRect
1889 float off
= (centerRect
.Width() - width
) / 2;
1890 startIconBounds
.OffsetTo(BPoint(off
, off
));
1892 // scroll the centerRect to correct location
1893 centerRect
.OffsetBy(bounds
.left
, 0);
1895 BRect destRect
= fOffBitmap
->Bounds();
1896 // scroll to the centerRect location
1897 destRect
.OffsetTo(centerRect
.left
, 0);
1898 // center the destRect inside of centerRect.
1899 off
= (centerRect
.Width() - destRect
.Width()) / 2;
1900 destRect
.OffsetBy(BPoint(off
, off
));
1903 rgb_color backgroundColor
= ui_color(B_PANEL_BACKGROUND_COLOR
);
1904 if (backgroundColor
.Brightness() > 100)
1905 fOffView
->SetHighColor(tint_color(backgroundColor
, B_DARKEN_1_TINT
));
1907 fOffView
->SetHighColor(tint_color(backgroundColor
, 0.85));
1909 for (int i
= 0; i
< 2; i
++) {
1910 startIconBounds
.InsetBy(amount
, amount
);
1912 fOffView
->SetDrawingMode(B_OP_COPY
);
1913 fOffView
->FillRect(fOffView
->Bounds());
1914 fOffView
->SetDrawingMode(B_OP_ALPHA
);
1915 fOffView
->DrawBitmap(startIcon
, startIconBounds
);
1917 DrawBitmap(fOffBitmap
, destRect
);
1919 for (int i
= 0; i
< 2; i
++) {
1920 startIconBounds
.InsetBy(amount
, amount
);
1922 fOffView
->SetDrawingMode(B_OP_COPY
);
1923 fOffView
->FillRect(fOffView
->Bounds());
1924 fOffView
->SetDrawingMode(B_OP_ALPHA
);
1925 fOffView
->DrawBitmap(endIcon
, startIconBounds
);
1927 DrawBitmap(fOffBitmap
, destRect
);
1930 fOffBitmap
->Unlock();
1935 TIconView::Update(int32
, int32 current
, int32 previousSlot
, int32 currentSlot
,
1938 // Animate the shrinking of the currently centered icon.
1939 AnimateIcon(fCurrentLarge
, fCurrentSmall
);
1941 int32 nslots
= abs(previousSlot
- currentSlot
);
1942 int32 stepSize
= kScrollStep
;
1944 if (forward
&& (currentSlot
< previousSlot
)) {
1945 // we were at the end of the list and we just moved to the start
1947 if (previousSlot
- currentSlot
> 4)
1949 } else if (!forward
&& (currentSlot
> previousSlot
)) {
1950 // we're are moving backwards and we just hit start of list and
1951 // we wrapped to the end.
1953 if (currentSlot
- previousSlot
> 4)
1957 int32 scrollValue
= forward
? stepSize
: -stepSize
;
1960 fAutoScrolling
= true;
1961 while (total
< (nslots
* kSlotSize
)) {
1962 ScrollBy(scrollValue
, 0);
1965 Window()->UpdateIfNeeded();
1967 fAutoScrolling
= false;
1969 TTeamGroup
* teamGroup
= (TTeamGroup
*)fManager
->GroupList()->ItemAt(current
);
1971 CacheIcons(teamGroup
);
1973 // Animate the expansion of the currently centered icon
1974 AnimateIcon(fCurrentSmall
, fCurrentLarge
);
1979 TIconView::CenterOn(int32 index
)
1981 BRect rect
= FrameOf(index
);
1982 ScrollTo(rect
.left
- (kCenterSlot
* kSlotSize
), 0);
1987 TIconView::ItemAtPoint(BPoint point
) const
1989 return IndexAt((int32
)(point
.x
/ kSlotSize
) - kCenterSlot
);
1994 TIconView::ScrollTo(BPoint where
)
1996 BView::ScrollTo(where
);
1997 fSwitcher
->TopView()->DrawIconScrollers(true);
2002 TIconView::IndexAt(int32 slot
) const
2004 if (slot
< 0 || slot
>= fManager
->GroupList()->CountItems())
2012 TIconView::SlotOf(int32 index
) const
2014 BRect rect
= FrameOf(index
);
2016 return (int32
)(rect
.left
/ kSlotSize
) - kCenterSlot
;
2021 TIconView::FrameOf(int32 index
) const
2023 int32 visible
= index
+ kCenterSlot
;
2024 // first few slots in view are empty
2026 return BRect(visible
* kSlotSize
, 0, (visible
+ 1) * kSlotSize
- 1,
2032 TIconView::DrawTeams(BRect update
)
2034 float tint
= B_NO_TINT
;
2035 rgb_color panelColor
= ui_color(B_PANEL_BACKGROUND_COLOR
);
2037 if (panelColor
.Brightness() < 100)
2040 tint
= B_DARKEN_1_TINT
;
2042 SetHighUIColor(B_PANEL_BACKGROUND_COLOR
, tint
);
2043 SetLowUIColor(ViewUIColor(), tint
);
2046 int32 mainIndex
= fManager
->CurrentIndex();
2047 BList
* list
= fManager
->GroupList();
2048 int32 count
= list
->CountItems();
2050 BRect
rect(kCenterSlot
* kSlotSize
, 0,
2051 (kCenterSlot
+ 1) * kSlotSize
- 1, kSlotSize
- 1);
2053 for (int32 i
= 0; i
< count
; i
++) {
2054 TTeamGroup
* teamGroup
= (TTeamGroup
*)list
->ItemAt(i
);
2055 if (rect
.Intersects(update
) && teamGroup
) {
2056 SetDrawingMode(B_OP_ALPHA
);
2057 SetBlendingMode(B_PIXEL_ALPHA
, B_ALPHA_OVERLAY
);
2059 teamGroup
->Draw(this, rect
, !fAutoScrolling
&& (i
== mainIndex
));
2062 CacheIcons(teamGroup
);
2064 SetDrawingMode(B_OP_COPY
);
2066 rect
.OffsetBy(kSlotSize
, 0);
2072 TIconView::Draw(BRect update
)
2079 TIconView::MouseDown(BPoint where
)
2081 int32 index
= ItemAtPoint(where
);
2083 int32 previousIndex
= fManager
->CurrentIndex();
2084 int32 previousSlot
= fManager
->CurrentSlot();
2085 int32 currentSlot
= SlotOf(index
);
2086 fManager
->SwitchToApp(previousIndex
, index
, (currentSlot
2095 uint32 modifiersKeys
= modifiers();
2096 if (fSwitcher
->HairTrigger() && (modifiersKeys
& B_CONTROL_KEY
) == 0) {
2097 fManager
->Stop(true, modifiersKeys
);
2101 if (!fSwitcher
->HairTrigger()) {
2104 GetMouse(&point
, &buttons
);
2106 point
= ConvertToScreen(point
);
2107 if (!Window()->Frame().Contains(point
))
2108 fManager
->Stop(false, 0);
2115 TIconView::Showing()
2130 TWindowView::TWindowView(BRect rect
, TSwitchManager
* manager
,
2131 TSwitcherWindow
* window
)
2132 : BView(rect
, "wlist_view", B_FOLLOW_NONE
, B_WILL_DRAW
| B_PULSE_NEEDED
),
2138 SetFont(be_plain_font
);
2143 TWindowView::AttachedToWindow()
2145 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
2150 TWindowView::ScrollTo(BPoint where
)
2152 BView::ScrollTo(where
);
2153 fSwitcher
->TopView()->DrawWindowScrollers(true);
2158 TWindowView::FrameOf(int32 index
) const
2160 return BRect(0, index
* fItemHeight
, 100, ((index
+ 1) * fItemHeight
) - 1);
2165 TWindowView::GetPreferredSize(float* _width
, float* _height
)
2168 be_plain_font
->GetHeight(&fh
);
2169 fItemHeight
= (int32
) fh
.ascent
+ fh
.descent
;
2171 // top & bottom margin
2172 fItemHeight
= fItemHeight
+ 3 + 3;
2174 // want fItemHeight to be divisible by kWindowScrollSteps.
2175 fItemHeight
= ((((int)fItemHeight
) + kWindowScrollSteps
)
2176 / kWindowScrollSteps
) * kWindowScrollSteps
;
2178 *_height
= fItemHeight
;
2180 // leave width alone
2181 *_width
= Bounds().Width();
2186 TWindowView::ShowIndex(int32 newIndex
)
2188 // convert index to scroll location
2189 BPoint
point(0, newIndex
* fItemHeight
);
2190 BRect bounds
= Bounds();
2192 int32 groupIndex
= fManager
->CurrentIndex();
2193 TTeamGroup
* teamGroup
2194 = (TTeamGroup
*)fManager
->GroupList()->ItemAt(groupIndex
);
2195 if (teamGroup
== NULL
)
2198 window_info
* windowInfo
= fManager
->WindowInfo(groupIndex
, newIndex
);
2199 if (windowInfo
== NULL
)
2202 fCurrentToken
= windowInfo
->server_token
;
2205 if (bounds
.top
== point
.y
)
2208 int32 oldIndex
= (int32
) (bounds
.top
/ fItemHeight
);
2210 int32 stepSize
= (int32
) (fItemHeight
/ kWindowScrollSteps
);
2211 int32 scrollValue
= (newIndex
> oldIndex
) ? stepSize
: -stepSize
;
2213 int32 nslots
= abs(newIndex
- oldIndex
);
2215 while (total
< (nslots
* (int32
)fItemHeight
)) {
2216 ScrollBy(0, scrollValue
);
2219 Window()->UpdateIfNeeded();
2225 TWindowView::Draw(BRect update
)
2227 int32 groupIndex
= fManager
->CurrentIndex();
2228 TTeamGroup
* teamGroup
2229 = (TTeamGroup
*)fManager
->GroupList()->ItemAt(groupIndex
);
2231 if (teamGroup
== NULL
)
2234 BRect bounds
= Bounds();
2235 int32 windowIndex
= (int32
) (bounds
.top
/ fItemHeight
);
2236 BRect windowRect
= bounds
;
2238 windowRect
.top
= windowIndex
* fItemHeight
;
2239 windowRect
.bottom
= (windowIndex
+ 1) * fItemHeight
- 1;
2241 for (int32 i
= 0; i
< 3; i
++) {
2242 if (!update
.Intersects(windowRect
)) {
2244 windowRect
.OffsetBy(0, fItemHeight
);
2248 // is window in current workspace?
2251 bool minimized
= false;
2254 client_window_info
* windowInfo
2255 = fManager
->WindowInfo(groupIndex
, windowIndex
);
2256 if (windowInfo
!= NULL
) {
2257 if (SmartStrcmp(windowInfo
->name
, teamGroup
->Name()) != 0)
2258 title
<< teamGroup
->Name() << ": " << windowInfo
->name
;
2260 title
= teamGroup
->Name();
2262 int32 currentWorkspace
= current_workspace();
2263 if ((windowInfo
->workspaces
& (1 << currentWorkspace
)) == 0)
2266 minimized
= windowInfo
->is_mini
;
2269 title
= teamGroup
->Name();
2271 if (!title
.Length())
2274 float stringWidth
= StringWidth(title
.String());
2275 float maxWidth
= bounds
.Width() - (14 + 5);
2277 if (stringWidth
> maxWidth
) {
2278 // window title is too long, need to truncate
2279 TruncateString(&title
, B_TRUNCATE_MIDDLE
, maxWidth
);
2280 stringWidth
= maxWidth
;
2283 BPoint
point((bounds
.Width() - (stringWidth
+ 14 + 5)) / 2,
2284 windowRect
.bottom
- 4);
2285 BPoint
p(point
.x
, (windowRect
.top
+ windowRect
.bottom
) / 2);
2286 SetDrawingMode(B_OP_OVER
);
2287 const BBitmap
* bitmap
= AppResSet()->FindBitmap(B_MESSAGE_TYPE
,
2288 minimized
? R_WindowHiddenIcon
: R_WindowShownIcon
);
2289 p
.y
-= (bitmap
->Bounds().bottom
- bitmap
->Bounds().top
) / 2;
2290 DrawBitmap(bitmap
, p
);
2293 rgb_color color
= ui_color(B_PANEL_BACKGROUND_COLOR
);
2294 if (color
.Brightness() > 100)
2295 SetHighColor(tint_color(color
, B_DARKEN_4_TINT
));
2297 SetHighColor(tint_color(color
, B_LIGHTEN_1_TINT
));
2301 StrokeLine(p
+ BPoint(2, 2), p
+ BPoint(2, 2));
2302 StrokeLine(p
+ BPoint(4, 2), p
+ BPoint(6, 2));
2304 StrokeLine(p
+ BPoint(0, 5), p
+ BPoint(0, 5));
2305 StrokeLine(p
+ BPoint(2, 5), p
+ BPoint(6, 5));
2307 StrokeLine(p
+ BPoint(1, 8), p
+ BPoint(1, 8));
2308 StrokeLine(p
+ BPoint(3, 8), p
+ BPoint(6, 8));
2314 SetHighUIColor(B_PANEL_TEXT_COLOR
);
2315 DrawString(title
.String());
2316 SetDrawingMode(B_OP_COPY
);
2319 windowRect
.OffsetBy(0, fItemHeight
);
2325 TWindowView::UpdateGroup(int32
, int32 windowIndex
)
2327 ScrollTo(0, windowIndex
* fItemHeight
);
2328 Invalidate(Bounds());
2333 TWindowView::Pulse()
2335 // If selected window went away then reset to first window
2336 window_info
*windowInfo
= get_window_info(fCurrentToken
);
2337 if (windowInfo
== NULL
) {