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
37 #include "ExpandoMenuBar.h"
46 #include <ControlLook.h>
48 #include <MenuPrivate.h>
58 #include "BarMenuTitle.h"
60 #include "BarWindow.h"
61 #include "DeskbarMenu.h"
62 #include "DeskbarUtils.h"
63 #include "InlineScrollView.h"
64 #include "ResourceSet.h"
65 #include "ShowHideMenuItem.h"
66 #include "StatusView.h"
68 #include "TeamMenuItem.h"
69 #include "WindowMenu.h"
70 #include "WindowMenuItem.h"
73 const float kMinMenuItemWidth
= 50.0f
;
74 const float kSepItemWidth
= 5.0f
;
75 const float kIconPadding
= 8.0f
;
77 const uint32 kMinimizeTeam
= 'mntm';
78 const uint32 kBringTeamToFront
= 'bftm';
80 bool TExpandoMenuBar::sDoMonitor
= false;
81 thread_id
TExpandoMenuBar::sMonThread
= B_ERROR
;
82 BLocker
TExpandoMenuBar::sMonLocker("expando monitor");
84 typedef std::map
<BString
, TTeamMenuItem
*> TeamMenuItemMap
;
87 // #pragma mark - TExpandoMenuBar
90 TExpandoMenuBar::TExpandoMenuBar(TBarView
* barView
, bool vertical
)
92 BMenuBar(BRect(0, 0, 0, 0), "ExpandoMenuBar", B_FOLLOW_NONE
,
93 vertical
? B_ITEMS_IN_COLUMN
: B_ITEMS_IN_ROW
),
98 fDeskbarMenuWidth(kMinMenuItemWidth
),
99 fPreviousDragTargetItem(NULL
),
100 fLastMousedOverItem(NULL
),
101 fLastClickedItem(NULL
)
103 SetItemMargins(0.0f
, 0.0f
, 0.0f
, 0.0f
);
104 SetFont(be_plain_font
);
107 // top or bottom mode, add deskbar menu and sep for menubar tracking
109 const BBitmap
* logoBitmap
= AppResSet()->FindBitmap(B_MESSAGE_TYPE
,
111 if (logoBitmap
!= NULL
)
112 fDeskbarMenuWidth
= logoBitmap
->Bounds().Width() + 16;
117 TExpandoMenuBar::AllAttached()
119 BMenuBar::AllAttached();
126 TExpandoMenuBar::AttachedToWindow()
128 BMenuBar::AttachedToWindow();
130 fTeamList
.MakeEmpty();
133 StartMonitoringWindows();
138 TExpandoMenuBar::DetachedFromWindow()
140 BMenuBar::DetachedFromWindow();
142 StopMonitoringWindows();
144 BMessenger
self(this);
145 BMessage
message(kUnsubscribe
);
146 message
.AddMessenger("messenger", self
);
147 be_app
->PostMessage(&message
);
149 RemoveItems(0, CountItems(), true);
154 TExpandoMenuBar::MessageReceived(BMessage
* message
)
159 switch (message
->what
) {
160 case B_SOME_APP_LAUNCHED
:
163 message
->FindPointer("teams", (void**)&teams
);
165 BBitmap
* icon
= NULL
;
166 message
->FindPointer("icon", (void**)&icon
);
168 const char* signature
= NULL
;
169 message
->FindString("sig", &signature
);
172 message
->FindInt32("flags", ((int32
*) &flags
));
174 const char* name
= NULL
;
175 message
->FindString("name", &name
);
177 AddTeam(teams
, icon
, strdup(name
), strdup(signature
));
181 case B_MOUSE_WHEEL_CHANGED
:
184 message
->FindFloat("be:wheel_delta_y", &deltaY
);
188 TInlineScrollView
* scrollView
189 = dynamic_cast<TInlineScrollView
*>(Parent());
190 if (scrollView
== NULL
)
195 scrollView
->GetSteps(&smallStep
, &largeStep
);
197 // pressing the option/command/control key scrolls faster
198 if (modifiers() & (B_OPTION_KEY
| B_COMMAND_KEY
| B_CONTROL_KEY
))
203 scrollView
->ScrollBy(deltaY
);
208 AddTeam(message
->FindInt32("team"), message
->FindString("sig"));
214 message
->FindInt32("team", &team
);
216 RemoveTeam(team
, true);
220 case B_SOME_APP_QUIT
:
223 message
->FindInt32("team", &team
);
225 RemoveTeam(team
, false);
231 index
= message
->FindInt32("itemIndex");
232 item
= dynamic_cast<TTeamMenuItem
*>(ItemAt(index
));
236 TShowHideMenuItem::TeamShowHideCommon(B_MINIMIZE_WINDOW
,
238 item
->Menu()->ConvertToScreen(item
->Frame()),
243 case kBringTeamToFront
:
245 index
= message
->FindInt32("itemIndex");
246 item
= dynamic_cast<TTeamMenuItem
*>(ItemAt(index
));
250 TShowHideMenuItem::TeamShowHideCommon(B_BRING_TO_FRONT
,
251 item
->Teams(), item
->Menu()->ConvertToScreen(item
->Frame()),
257 BMenuBar::MessageReceived(message
);
264 TExpandoMenuBar::MouseDown(BPoint where
)
266 BMessage
* message
= Window()->CurrentMessage();
268 TTeamMenuItem
* item
= TeamItemAtPoint(where
, &menuItem
);
270 if (message
== NULL
|| item
== NULL
|| fBarView
->Dragging()) {
271 BMenuBar::MouseDown(where
);
276 message
->FindInt32("modifiers", &modifiers
);
278 // check for three finger salute, a.k.a. Vulcan Death Grip
279 if ((modifiers
& B_COMMAND_KEY
) != 0
280 && (modifiers
& B_CONTROL_KEY
) != 0
281 && (modifiers
& B_SHIFT_KEY
) != 0) {
282 const BList
* teams
= item
->Teams();
283 int32 teamCount
= teams
->CountItems();
285 for (int32 team
= 0; team
< teamCount
; team
++) {
286 teamID
= (addr_t
)teams
->ItemAt(team
);
288 RemoveTeam(teamID
, false);
289 // remove the team from display immediately
292 // absorb the message
295 // control click - show all/hide all shortcut
296 if ((modifiers
& B_CONTROL_KEY
) != 0) {
297 // show/hide item's teams
298 BMessage
showMessage((modifiers
& B_SHIFT_KEY
) != 0
299 ? kMinimizeTeam
: kBringTeamToFront
);
300 showMessage
.AddInt32("itemIndex", IndexOf(item
));
301 Window()->PostMessage(&showMessage
, this);
303 // absorb the message
306 // check if within expander bounds to expand window items
307 if (fVertical
&& static_cast<TBarApp
*>(be_app
)->Settings()->superExpando
308 && item
->ExpanderBounds().Contains(where
)) {
309 // start the animation here, finish on mouse up
310 fLastClickedItem
= item
;
311 MouseDownThread
<TExpandoMenuBar
>::TrackMouse(this,
312 &TExpandoMenuBar::_DoneTracking
, &TExpandoMenuBar::_Track
);
313 Invalidate(item
->ExpanderBounds());
315 // absorb the message
318 // double-click on an item brings the team to front
320 if (message
->FindInt32("clicks", &clicks
) == B_OK
&& clicks
> 1
321 && item
== menuItem
&& item
== fLastClickedItem
) {
322 be_roster
->ActivateApp((addr_t
)item
->Teams()->ItemAt(0));
323 // activate this team
325 // absorb the message
328 fLastClickedItem
= item
;
329 BMenuBar::MouseDown(where
);
334 TExpandoMenuBar::MouseMoved(BPoint where
, uint32 code
, const BMessage
* message
)
337 BMessage
* currentMessage
= Window()->CurrentMessage();
338 if (currentMessage
== NULL
339 || currentMessage
->FindInt32("buttons", &buttons
) != B_OK
) {
343 if (message
== NULL
) {
351 TTeamMenuItem
* item
= TeamItemAtPoint(where
, &menuItem
);
352 TWindowMenuItem
* windowMenuItem
353 = dynamic_cast<TWindowMenuItem
*>(menuItem
);
355 if (item
== NULL
|| menuItem
== NULL
) {
356 // item is NULL, remove the tooltip and break out
357 fLastMousedOverItem
= NULL
;
358 SetToolTip((const char*)NULL
);
362 if (menuItem
== fLastMousedOverItem
) {
363 // already set the tooltip for this item, break out
367 if (windowMenuItem
!= NULL
&& fBarView
->Vertical()
368 && fBarView
->ExpandoState() && item
->IsExpanded()) {
369 // expando mode window menu item
370 fLastMousedOverItem
= menuItem
;
371 if (strcasecmp(windowMenuItem
->TruncatedLabel(),
372 windowMenuItem
->Label()) > 0) {
373 // label is truncated, set tooltip
374 SetToolTip(windowMenuItem
->Label());
376 SetToolTip((const char*)NULL
);
381 if (!dynamic_cast<TBarApp
*>(be_app
)->Settings()->hideLabels
) {
382 // item has a visible label, set tool tip if truncated
383 fLastMousedOverItem
= menuItem
;
384 if (strcasecmp(item
->TruncatedLabel(), item
->Label()) > 0) {
385 // label is truncated, set tooltip
386 SetToolTip(item
->Label());
388 SetToolTip((const char*)NULL
);
393 SetToolTip(item
->Label());
394 // new item, set the tooltip to the item label
395 fLastMousedOverItem
= menuItem
;
396 // save the current menuitem for the next MouseMoved() call
401 BMenuBar::MouseMoved(where
, code
, message
);
410 // fPreviousDragTargetItem should always be NULL here anyways.
411 if (fPreviousDragTargetItem
!= NULL
)
414 fBarView
->CacheDragData(message
);
415 fPreviousDragTargetItem
= NULL
;
419 // NOTE: Should not be here, but for the sake of defensive
420 // programming... fall-through
426 if (fBarView
->Dragging()) {
427 TTeamMenuItem
* item
= NULL
;
428 int32 itemCount
= CountItems();
429 for (int32 i
= 0; i
< itemCount
; i
++) {
430 BMenuItem
* _item
= ItemAt(i
);
431 if (_item
->Frame().Contains(where
)) {
432 item
= dynamic_cast<TTeamMenuItem
*>(_item
);
436 if (item
== fPreviousDragTargetItem
)
438 if (fPreviousDragTargetItem
!= NULL
)
439 fPreviousDragTargetItem
->SetOverrideSelected(false);
441 item
->SetOverrideSelected(true);
442 fPreviousDragTargetItem
= item
;
450 TExpandoMenuBar::MouseUp(BPoint where
)
452 if (fBarView
->Dragging()) {
455 // absorb the message
458 BMenuBar::MouseUp(where
);
463 TExpandoMenuBar::BuildItems()
465 BMessenger
self(this);
466 TBarApp::Subscribe(self
, &fTeamList
);
468 int32 iconSize
= static_cast<TBarApp
*>(be_app
)->IconSize();
469 desk_settings
* settings
= static_cast<TBarApp
*>(be_app
)->Settings();
471 float itemWidth
= -1.0f
;
473 itemWidth
= Frame().Width();
474 SetMaxContentWidth(itemWidth
);
476 itemWidth
= iconSize
;
477 if (!settings
->hideLabels
)
478 itemWidth
+= gMinimumWindowWidth
- kMinimumIconSize
;
480 itemWidth
+= kIconPadding
* 2;
482 float itemHeight
= -1.0f
;
484 TeamMenuItemMap items
;
485 int32 itemCount
= CountItems();
486 BList
itemList(itemCount
);
487 for (int32 i
= 0; i
< itemCount
; i
++) {
488 BMenuItem
* menuItem
= RemoveItem((int32
)0);
489 itemList
.AddItem(menuItem
);
490 TTeamMenuItem
* item
= dynamic_cast<TTeamMenuItem
*>(menuItem
);
492 items
[BString(item
->Signature()).ToLower()] = item
;
495 if (settings
->sortRunningApps
)
496 fTeamList
.SortItems(TTeamMenu::CompareByName
);
498 int32 teamCount
= fTeamList
.CountItems();
499 for (int32 i
= 0; i
< teamCount
; i
++) {
500 BarTeamInfo
* barInfo
= (BarTeamInfo
*)fTeamList
.ItemAt(i
);
501 TeamMenuItemMap::const_iterator iter
502 = items
.find(BString(barInfo
->sig
).ToLower());
503 if (iter
== items
.end()) {
505 TTeamMenuItem
* item
= new TTeamMenuItem(barInfo
->teams
,
506 barInfo
->icon
, barInfo
->name
, barInfo
->sig
, itemWidth
,
509 if (settings
->trackerAlwaysFirst
510 && strcasecmp(barInfo
->sig
, kTrackerSignature
) == 0) {
515 if (fFirstBuild
&& fVertical
&& settings
->expandNewTeams
)
516 item
->ToggleExpandState(true);
518 // existing team, update info and add it
519 TTeamMenuItem
* item
= iter
->second
;
520 item
->SetIcon(barInfo
->icon
);
521 item
->SetOverrideWidth(itemWidth
);
522 item
->SetOverrideHeight(itemHeight
);
524 if (settings
->trackerAlwaysFirst
525 && strcasecmp(barInfo
->sig
, kTrackerSignature
) == 0) {
530 // add window items back
531 int32 index
= itemList
.IndexOf(item
);
532 TWindowMenuItem
* windowItem
;
533 TWindowMenu
* submenu
= dynamic_cast<TWindowMenu
*>(item
->Submenu());
534 bool hasWindowItems
= false;
535 while ((windowItem
= dynamic_cast<TWindowMenuItem
*>(
536 (BMenuItem
*)(itemList
.ItemAt(++index
)))) != NULL
) {
541 hasWindowItems
= submenu
!= NULL
;
545 // unexpand if turn off show team expander
546 if (fVertical
&& !settings
->superExpando
&& item
->IsExpanded())
547 item
->ToggleExpandState(false);
549 if (hasWindowItems
) {
550 // add (new) window items in submenu
551 submenu
->SetExpanded(false, 0);
552 submenu
->AttachedToWindow();
557 if (CountItems() == 0) {
558 // If we're empty, BMenuBar::AttachedToWindow() resizes us to some
559 // weird value - we just override it again
560 ResizeTo(itemWidth
, 0);
568 TExpandoMenuBar::InDeskbarMenu(BPoint loc
) const
570 TBarWindow
* window
= dynamic_cast<TBarWindow
*>(Window());
571 if (window
!= NULL
) {
572 if (TDeskbarMenu
* bemenu
= window
->DeskbarMenu()) {
573 bool inDeskbarMenu
= false;
574 if (bemenu
->LockLooper()) {
575 inDeskbarMenu
= bemenu
->Frame().Contains(loc
);
576 bemenu
->UnlockLooper();
578 return inDeskbarMenu
;
586 /*! Returns the team menu item that belongs to the item under the
588 If \a _item is given, it will return the exact menu item under
589 that point (which might be a window item when the expander is on).
592 TExpandoMenuBar::TeamItemAtPoint(BPoint point
, BMenuItem
** _item
)
594 TTeamMenuItem
* lastApp
= NULL
;
595 int32 count
= CountItems();
597 for (int32 i
= 0; i
< count
; i
++) {
598 BMenuItem
* item
= ItemAt(i
);
600 if (dynamic_cast<TTeamMenuItem
*>(item
) != NULL
)
601 lastApp
= (TTeamMenuItem
*)item
;
603 if (item
&& item
->Frame().Contains(point
)) {
621 TExpandoMenuBar::AddTeam(BList
* team
, BBitmap
* icon
, char* name
,
624 int32 iconSize
= static_cast<TBarApp
*>(be_app
)->IconSize();
625 desk_settings
* settings
= static_cast<TBarApp
*>(be_app
)->Settings();
627 float itemWidth
= -1.0f
;
629 itemWidth
= fBarView
->Bounds().Width();
631 itemWidth
= iconSize
;
632 if (!settings
->hideLabels
)
633 itemWidth
+= gMinimumWindowWidth
- kMinimumIconSize
;
635 itemWidth
+= kIconPadding
* 2;
637 float itemHeight
= -1.0f
;
639 TTeamMenuItem
* item
= new TTeamMenuItem(team
, icon
, name
, signature
,
640 itemWidth
, itemHeight
);
642 if (settings
->trackerAlwaysFirst
643 && strcasecmp(signature
, kTrackerSignature
) == 0) {
645 } else if (settings
->sortRunningApps
) {
646 TTeamMenuItem
* teamItem
= dynamic_cast<TTeamMenuItem
*>(ItemAt(0));
649 // if Tracker should always be the first item, we need to skip it
650 // when sorting in the current item
651 if (settings
->trackerAlwaysFirst
&& teamItem
!= NULL
652 && strcasecmp(teamItem
->Signature(), kTrackerSignature
) == 0) {
657 BLocale::Default()->GetCollator(&collator
);
660 int32 itemCount
= CountItems();
661 while (i
< itemCount
) {
662 teamItem
= dynamic_cast<TTeamMenuItem
*>(ItemAt(i
));
663 if (teamItem
!= NULL
&& collator
.Compare(teamItem
->Label(), name
)
670 // was the item added to the list yet?
676 if (fVertical
&& settings
->superExpando
&& settings
->expandNewTeams
)
677 item
->ToggleExpandState(false);
680 Window()->UpdateIfNeeded();
685 TExpandoMenuBar::AddTeam(team_id team
, const char* signature
)
687 int32 itemCount
= CountItems();
688 for (int32 i
= 0; i
< itemCount
; i
++) {
689 // Only add to team menu items
690 TTeamMenuItem
* item
= dynamic_cast<TTeamMenuItem
*>(ItemAt(i
));
691 if (item
!= NULL
&& strcasecmp(item
->Signature(), signature
) == 0
692 && !(item
->Teams()->HasItem((void*)(addr_t
)team
))) {
693 item
->Teams()->AddItem((void*)(addr_t
)team
);
701 TExpandoMenuBar::RemoveTeam(team_id team
, bool partial
)
703 TWindowMenuItem
* windowItem
= NULL
;
705 for (int32 i
= CountItems() - 1; i
>= 0; i
--) {
706 TTeamMenuItem
* item
= dynamic_cast<TTeamMenuItem
*>(ItemAt(i
));
707 if (item
!= NULL
&& item
->Teams()->HasItem((void*)(addr_t
)team
)) {
708 item
->Teams()->RemoveItem(team
);
712 BAutolock
locker(sMonLocker
);
713 // make the update thread wait
715 if (item
== fPreviousDragTargetItem
)
716 fPreviousDragTargetItem
= NULL
;
718 if (item
== fLastMousedOverItem
)
719 fLastMousedOverItem
= NULL
;
721 if (item
== fLastClickedItem
)
722 fLastClickedItem
= NULL
;
725 while ((windowItem
= dynamic_cast<TWindowMenuItem
*>(
726 ItemAt(i
))) != NULL
) {
727 // Also remove window items (if there are any)
729 if (windowItem
== fLastMousedOverItem
)
730 fLastMousedOverItem
= NULL
;
732 if (windowItem
== fLastClickedItem
)
733 fLastClickedItem
= NULL
;
738 Window()->UpdateIfNeeded();
746 TExpandoMenuBar::CheckItemSizes(int32 delta
)
748 if (fBarView
->Vertical())
751 bool drawLabels
= !static_cast<TBarApp
*>(be_app
)->Settings()->hideLabels
;
753 float maxWidth
= fBarView
->DragRegion()->Frame().left
754 - fDeskbarMenuWidth
- kSepItemWidth
;
755 int32 iconSize
= static_cast<TBarApp
*>(be_app
)->IconSize();
756 float iconOnlyWidth
= kIconPadding
+ iconSize
+ kIconPadding
;
757 float minItemWidth
= drawLabels
758 ? iconOnlyWidth
+ kMinMenuItemWidth
759 : iconOnlyWidth
- kIconPadding
;
760 float maxItemWidth
= drawLabels
761 ? gMinimumWindowWidth
+ iconSize
- kMinimumIconSize
763 float menuWidth
= maxItemWidth
* CountItems() + fDeskbarMenuWidth
767 float newWidth
= -1.0f
;
769 if (delta
>= 0 && menuWidth
> maxWidth
) {
772 newWidth
= floorf(maxWidth
/ CountItems());
773 } else if (delta
< 0 && fOverflow
) {
775 if (menuWidth
> maxWidth
)
776 newWidth
= floorf(maxWidth
/ CountItems());
778 newWidth
= maxItemWidth
;
782 if (newWidth
> maxItemWidth
)
783 newWidth
= maxItemWidth
;
784 else if (newWidth
< minItemWidth
)
785 newWidth
= minItemWidth
;
787 SetMaxContentWidth(newWidth
);
788 if (newWidth
== maxItemWidth
)
793 for (int32 index
= 0; ; index
++) {
794 TTeamMenuItem
* item
= (TTeamMenuItem
*)ItemAt(index
);
798 item
->SetOverrideWidth(newWidth
);
802 Window()->UpdateIfNeeded();
803 fBarView
->CheckForScrolling();
809 TExpandoMenuBar::MenuLayout() const
816 TExpandoMenuBar::SetMenuLayout(menu_layout layout
)
818 fVertical
= layout
== B_ITEMS_IN_COLUMN
;
819 BPrivate::MenuPrivate(this).SetLayout(layout
);
821 // when the menu layout changes, make sure to set the max width
826 TExpandoMenuBar::Draw(BRect updateRect
)
828 BMenu::Draw(updateRect
);
833 TExpandoMenuBar::DrawBackground(BRect updateRect
)
838 BRect
bounds(Bounds());
839 rgb_color menuColor
= ui_color(B_MENU_BACKGROUND_COLOR
);
840 rgb_color hilite
= tint_color(menuColor
, B_DARKEN_1_TINT
);
841 rgb_color vlight
= tint_color(menuColor
, B_LIGHTEN_2_TINT
);
843 int32 count
= CountItems() - 1;
845 bounds
.left
= ItemAt(count
)->Frame().right
+ 1;
849 if (be_control_look
!= NULL
) {
850 SetHighColor(tint_color(menuColor
, 1.22));
851 StrokeLine(bounds
.LeftTop(), bounds
.LeftBottom());
853 uint32 borders
= BControlLook::B_TOP_BORDER
854 | BControlLook::B_BOTTOM_BORDER
| BControlLook::B_RIGHT_BORDER
;
856 be_control_look
->DrawButtonBackground(this, bounds
, bounds
, menuColor
,
859 SetHighColor(vlight
);
860 StrokeLine(bounds
.LeftTop(), bounds
.RightTop());
861 StrokeLine(BPoint(bounds
.left
, bounds
.top
+ 1), bounds
.LeftBottom());
862 SetHighColor(hilite
);
863 StrokeLine(BPoint(bounds
.left
+ 1, bounds
.bottom
),
864 bounds
.RightBottom());
869 /*! Something to help determine if we are showing too many apps
870 need to add in scrolling functionality.
873 TExpandoMenuBar::CheckForSizeOverrun()
876 if (Window() == NULL
)
879 BRect screenFrame
= (BScreen(Window())).Frame();
880 return Window()->Frame().bottom
> screenFrame
.bottom
;
884 int32 count
= CountItems() - 1;
888 int32 iconSize
= static_cast<TBarApp
*>(be_app
)->IconSize();
889 float iconOnlyWidth
= kIconPadding
+ iconSize
+ kIconPadding
;
890 float minItemWidth
= !static_cast<TBarApp
*>(be_app
)->Settings()->hideLabels
891 ? iconOnlyWidth
+ kMinMenuItemWidth
892 : iconOnlyWidth
- kIconPadding
;
893 float menuWidth
= minItemWidth
* CountItems() + fDeskbarMenuWidth
895 float maxWidth
= fBarView
->DragRegion()->Frame().left
896 - fDeskbarMenuWidth
- kSepItemWidth
;
898 return menuWidth
> maxWidth
;
903 TExpandoMenuBar::SetMaxItemWidth()
906 SetMaxContentWidth(static_cast<TBarApp
*>(be_app
)->Settings()->width
);
908 // Make more room for the icon in horizontal mode
909 int32 iconSize
= static_cast<TBarApp
*>(be_app
)->IconSize();
910 SetMaxContentWidth(gMinimumWindowWidth
+ iconSize
917 TExpandoMenuBar::SizeWindow(int32 delta
)
919 // instead of resizing the window here and there in the
920 // code the resize method will be centered in one place
921 // thus, the same behavior (good or bad) will be used
922 // wherever window sizing is done
924 BRect screenFrame
= (BScreen(Window())).Frame();
925 fBarView
->SizeWindow(screenFrame
);
926 fBarView
->PositionWindow(screenFrame
);
927 fBarView
->CheckForScrolling();
929 CheckItemSizes(delta
);
934 TExpandoMenuBar::StartMonitoringWindows()
936 if (sMonThread
!= B_ERROR
)
940 sMonThread
= spawn_thread(monitor_team_windows
,
941 "Expando Window Watcher", B_LOW_PRIORITY
, this);
942 resume_thread(sMonThread
);
947 TExpandoMenuBar::StopMonitoringWindows()
949 if (sMonThread
== B_ERROR
)
954 wait_for_thread(sMonThread
, &returnCode
);
956 sMonThread
= B_ERROR
;
961 TExpandoMenuBar::monitor_team_windows(void* arg
)
963 TExpandoMenuBar
* teamMenu
= (TExpandoMenuBar
*)arg
;
965 while (teamMenu
->sDoMonitor
) {
968 if (teamMenu
->Window()->LockWithTimeout(50000) == B_OK
) {
969 int32 totalItems
= teamMenu
->CountItems();
971 // Set all WindowMenuItems to require an update.
972 TWindowMenuItem
* item
= NULL
;
973 for (int32 i
= 0; i
< totalItems
; i
++) {
974 if (!teamMenu
->SubmenuAt(i
)) {
975 item
= static_cast<TWindowMenuItem
*>(teamMenu
->ItemAt(i
));
976 item
->SetRequireUpdate(true);
980 // Perform SetTo() on all the items that still exist as well as add
982 bool itemModified
= false;
984 TTeamMenuItem
* teamItem
= NULL
;
986 for (int32 i
= 0; i
< totalItems
; i
++) {
987 if (teamMenu
->SubmenuAt(i
) == NULL
)
990 teamItem
= static_cast<TTeamMenuItem
*>(teamMenu
->ItemAt(i
));
991 if (teamItem
->IsExpanded()) {
992 int32 teamCount
= teamItem
->Teams()->CountItems();
993 for (int32 j
= 0; j
< teamCount
; j
++) {
994 // The following code is almost a copy/paste from
996 team_id theTeam
= (addr_t
)teamItem
->Teams()->ItemAt(j
);
998 int32
* tokens
= get_token_list(theTeam
, &count
);
1000 for (int32 k
= 0; k
< count
; k
++) {
1001 client_window_info
* wInfo
1002 = get_window_info(tokens
[k
]);
1006 BString
windowName(wInfo
->name
);
1008 BString
teamPrefix(teamItem
->Label());
1009 teamPrefix
.Append(": ");
1011 BString
teamSuffix(" - ");
1012 teamSuffix
.Append(teamItem
->Label());
1014 if (windowName
.StartsWith(teamPrefix
))
1015 windowName
.RemoveFirst(teamPrefix
);
1016 if (windowName
.EndsWith(teamSuffix
))
1017 windowName
.RemoveLast(teamSuffix
);
1019 if (TWindowMenu::WindowShouldBeListed(wInfo
)) {
1020 // Check if we have a matching window item...
1021 item
= teamItem
->ExpandedWindowItem(
1022 wInfo
->server_token
);
1024 item
->SetTo(windowName
,
1025 wInfo
->server_token
, wInfo
->is_mini
,
1026 ((1 << current_workspace())
1027 & wInfo
->workspaces
) != 0);
1029 if (strcasecmp(item
->Label(), windowName
) > 0)
1030 item
->SetLabel(windowName
);
1032 if (item
->Modified())
1033 itemModified
= true;
1034 } else if (teamItem
->IsExpanded()) {
1036 item
= new TWindowMenuItem(windowName
,
1037 wInfo
->server_token
, wInfo
->is_mini
,
1038 ((1 << current_workspace())
1039 & wInfo
->workspaces
) != 0, false);
1040 item
->SetExpanded(true);
1041 teamMenu
->AddItem(item
,
1042 TWindowMenuItem::InsertIndexFor(
1043 teamMenu
, i
+ 1, item
));
1054 // Remove any remaining items which require an update.
1055 for (int32 i
= 0; i
< totalItems
; i
++) {
1056 if (!teamMenu
->SubmenuAt(i
)) {
1057 item
= static_cast<TWindowMenuItem
*>(teamMenu
->ItemAt(i
));
1058 if (item
&& item
->RequiresUpdate()) {
1059 item
= static_cast<TWindowMenuItem
*>
1060 (teamMenu
->RemoveItem(i
));
1069 // If any of the WindowMenuItems changed state, we need to force a
1071 if (itemModified
|| resize
) {
1072 teamMenu
->Invalidate();
1074 teamMenu
->SizeWindow(1);
1077 teamMenu
->Window()->Unlock();
1080 sMonLocker
.Unlock();
1082 // sleep for a bit...
1090 TExpandoMenuBar::_FinishedDrag(bool invoke
)
1092 if (fPreviousDragTargetItem
!= NULL
) {
1094 fPreviousDragTargetItem
->Invoke();
1096 fPreviousDragTargetItem
->SetOverrideSelected(false);
1097 fPreviousDragTargetItem
= NULL
;
1100 if (!invoke
&& fBarView
->Dragging())
1101 fBarView
->DragStop(true);
1106 TExpandoMenuBar::_DoneTracking(BPoint where
)
1108 TTeamMenuItem
* lastItem
= dynamic_cast<TTeamMenuItem
*>(fLastClickedItem
);
1109 if (lastItem
== NULL
)
1112 if (!lastItem
->ExpanderBounds().Contains(where
))
1115 lastItem
->ToggleExpandState(true);
1116 lastItem
->SetArrowDirection(lastItem
->IsExpanded()
1117 ? BControlLook::B_DOWN_ARROW
1118 : BControlLook::B_RIGHT_ARROW
);
1120 Invalidate(lastItem
->ExpanderBounds());
1125 TExpandoMenuBar::_Track(BPoint where
, uint32
)
1127 TTeamMenuItem
* lastItem
= dynamic_cast<TTeamMenuItem
*>(fLastClickedItem
);
1128 if (lastItem
== NULL
)
1131 if (lastItem
->ExpanderBounds().Contains(where
))
1132 lastItem
->SetArrowDirection(BControlLook::B_RIGHT_DOWN_ARROW
);
1134 lastItem
->SetArrowDirection(lastItem
->IsExpanded()
1135 ? BControlLook::B_DOWN_ARROW
1136 : BControlLook::B_RIGHT_ARROW
);
1139 Invalidate(lastItem
->ExpanderBounds());