1 /*
2 Open Tracker License
3
4 Terms and Conditions
5
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
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:
14
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.
17
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.
24
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.
28
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
32 holders.
33 All rights reserved.
34 */
35
36
37 #include "BarView.h"
38
39 #include <AppFileInfo.h>
40 #include <Bitmap.h>
41 #include <ControlLook.h>
42 #include <Debug.h>
43 #include <Directory.h>
44 #include <LocaleRoster.h>
45 #include <NodeInfo.h>
46 #include <Roster.h>
47 #include <Screen.h>
48 #include <String.h>
49
50 #include "icons.h"
51 #include "BarApp.h"
52 #include "BarMenuBar.h"
53 #include "BarWindow.h"
54 #include "DeskbarMenu.h"
55 #include "DeskbarUtils.h"
56 #include "ExpandoMenuBar.h"
57 #include "FSUtils.h"
58 #include "InlineScrollView.h"
59 #include "ResourceSet.h"
60 #include "StatusView.h"
61 #include "TeamMenuItem.h"
62
63
64 const int32 kDefaultRecentDocCount = 10;
65 const int32 kDefaultRecentAppCount = 10;
66
67 const int32 kMenuTrackMargin = 20;
68 const float kMinTeamItemHeight = 20.0f;
69 const float kScrollerDimension = 12.0f;
70
71 const uint32 kUpdateOrientation = 'UpOr';
72
73
74 class BarViewMessageFilter : public BMessageFilter
75 {
76 public:
77 BarViewMessageFilter(TBarView* barView);
78 virtual ~BarViewMessageFilter();
79
80 virtual filter_result Filter(BMessage* message, BHandler** target);
81
82 private:
83 TBarView* fBarView;
84 };
85
86
BarViewMessageFilter(TBarView * barView)87 BarViewMessageFilter::BarViewMessageFilter(TBarView* barView)
88 :
89 BMessageFilter(B_ANY_DELIVERY, B_ANY_SOURCE),
90 fBarView(barView)
91 {
92 }
93
94
~BarViewMessageFilter()95 BarViewMessageFilter::~BarViewMessageFilter()
96 {
97 }
98
99
100 filter_result
Filter(BMessage * message,BHandler ** target)101 BarViewMessageFilter::Filter(BMessage* message, BHandler** target)
102 {
103 if (message->what == B_MOUSE_DOWN || message->what == B_MOUSE_MOVED) {
104 BPoint where = message->FindPoint("be:view_where");
105 uint32 transit = message->FindInt32("be:transit");
106 BMessage* dragMessage = NULL;
107 if (message->HasMessage("be:drag_message")) {
108 dragMessage = new BMessage();
109 message->FindMessage("be:drag_message", dragMessage);
110 }
111
112 switch (message->what) {
113 case B_MOUSE_DOWN:
114 fBarView->MouseDown(where);
115 break;
116
117 case B_MOUSE_MOVED:
118 fBarView->MouseMoved(where, transit, dragMessage);
119 break;
120 }
121
122 delete dragMessage;
123 }
124
125 return B_DISPATCH_MESSAGE;
126 }
127
128
129 // #pragma mark - TBarView
130
131
TBarView(BRect frame,bool vertical,bool left,bool top,int32 state,float)132 TBarView::TBarView(BRect frame, bool vertical, bool left, bool top,
133 int32 state, float)
134 :
135 BView(frame, "BarView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW),
136 fBarApp(static_cast<TBarApp*>(be_app)),
137 fBarWindow(NULL),
138 fInlineScrollView(NULL),
139 fBarMenuBar(NULL),
140 fExpandoMenuBar(NULL),
141 fTrayLocation(1),
142 fIsRaised(false),
143 fMouseDownOutside(false),
144 fVertical(vertical),
145 fTop(top),
146 fLeft(left),
147 fState(state),
148 fRefsRcvdOnly(true),
149 fDragMessage(NULL),
150 fCachedTypesList(NULL),
151 fMaxRecentDocs(kDefaultRecentDocCount),
152 fMaxRecentApps(kDefaultRecentAppCount),
153 fLastDragItem(NULL),
154 fMouseFilter(NULL),
155 fTabHeight(kMenuBarHeight)
156 {
157 // get window tab height
158 BWindow* tmpWindow = new(std::nothrow) BWindow(BRect(), NULL,
159 B_TITLED_WINDOW, 0);
160 if (tmpWindow != NULL) {
161 BMessage settings;
162 if (tmpWindow->GetDecoratorSettings(&settings) == B_OK) {
163 BRect tabRect;
164 if (settings.FindRect("tab frame", &tabRect) == B_OK)
165 fTabHeight = tabRect.Height();
166 }
167 delete tmpWindow;
168 }
169
170 // determine the initial Be menu size
171 // (will be updated later)
172 BRect menuFrame(frame);
173 if (fVertical)
174 menuFrame.bottom = menuFrame.top + fTabHeight - 1;
175 else
176 menuFrame.bottom = menuFrame.top + TeamMenuItemHeight();
177
178 // create and add the Be menu
179 fBarMenuBar = new TBarMenuBar(menuFrame, "BarMenuBar", this);
180 AddChild(fBarMenuBar);
181
182 // create the status tray
183 fReplicantTray = new TReplicantTray(this);
184
185 // create the resize control
186 fResizeControl = new TResizeControl(this);
187
188 // create the drag region and add the resize control
189 // and replicant tray to it
190 fDragRegion = new TDragRegion(this, fReplicantTray);
191 fDragRegion->AddChild(fResizeControl);
192 fDragRegion->AddChild(fReplicantTray);
193
194 // Add the drag region
195 if (fTrayLocation != 0)
196 AddChild(fDragRegion);
197
198 // create and add the expando menu bar
199 fExpandoMenuBar = new TExpandoMenuBar(
200 fVertical ? B_ITEMS_IN_COLUMN : B_ITEMS_IN_ROW, this);
201 fInlineScrollView = new TInlineScrollView(fExpandoMenuBar,
202 fVertical ? B_VERTICAL : B_HORIZONTAL);
203 AddChild(fInlineScrollView);
204
205 // hide the expando menu bar in mini-mode
206 if (state == kMiniState)
207 fInlineScrollView->Hide();
208
209 // if auto-hide is on and we're not already hidden, hide ourself
210 if (fBarApp->Settings()->autoHide && !IsHidden())
211 Hide();
212 }
213
214
~TBarView()215 TBarView::~TBarView()
216 {
217 delete fDragMessage;
218 delete fCachedTypesList;
219 delete fBarMenuBar;
220 }
221
222
223 void
AttachedToWindow()224 TBarView::AttachedToWindow()
225 {
226 BView::AttachedToWindow();
227
228 fBarWindow = dynamic_cast<TBarWindow*>(Window());
229
230 SetViewUIColor(B_MENU_BACKGROUND_COLOR);
231 SetFont(be_plain_font);
232
233 fMouseFilter = new BarViewMessageFilter(this);
234 Window()->AddCommonFilter(fMouseFilter);
235
236 fTrackingHookData.fTrackingHook = MenuTrackingHook;
237 fTrackingHookData.fTarget = BMessenger(this);
238 fTrackingHookData.fDragMessage = new BMessage(B_REFS_RECEIVED);
239
240 if (!fVertical)
241 UpdatePlacement(); // update MenuBarHeight
242 }
243
244
245 void
DetachedFromWindow()246 TBarView::DetachedFromWindow()
247 {
248 Window()->RemoveCommonFilter(fMouseFilter);
249 delete fMouseFilter;
250 fMouseFilter = NULL;
251 delete fTrackingHookData.fDragMessage;
252 fTrackingHookData.fDragMessage = NULL;
253 }
254
255
256 void
Draw(BRect)257 TBarView::Draw(BRect)
258 {
259 BRect bounds(Bounds());
260
261 rgb_color hilite = tint_color(ViewColor(), B_DARKEN_1_TINT);
262
263 SetHighColor(hilite);
264 if (AcrossTop())
265 StrokeLine(bounds.LeftBottom(), bounds.RightBottom());
266 else if (AcrossBottom())
267 StrokeLine(bounds.LeftTop(), bounds.RightTop());
268
269 if (fVertical && fState == kExpandoState) {
270 SetHighColor(hilite);
271 BRect frame(fExpandoMenuBar->Frame());
272 StrokeLine(BPoint(frame.left, frame.top - 1),
273 BPoint(frame.right, frame.top -1));
274 }
275 }
276
277
278 void
MessageReceived(BMessage * message)279 TBarView::MessageReceived(BMessage* message)
280 {
281 switch (message->what) {
282 case B_LOCALE_CHANGED:
283 case kRealignReplicants:
284 case kShowHideTime:
285 case kShowSeconds:
286 case kShowDayOfWeek:
287 case kShowTimeZone:
288 case kGetClockSettings:
289 fReplicantTray->MessageReceived(message);
290 break;
291
292 case B_REFS_RECEIVED:
293 // received when an item is selected during DnD
294 // message is targeted here from Be menu
295 HandleDeskbarMenu(message);
296 break;
297
298 case B_ARCHIVED_OBJECT:
299 {
300 // this message has been retargeted to here
301 // instead of directly to the replicant tray
302 // so that I can follow the common pathway
303 // for adding icons to the tray
304 int32 id;
305 if (AddItem(message, B_DESKBAR_TRAY, &id) == B_OK)
306 Looper()->DetachCurrentMessage();
307 break;
308 }
309
310 case kUpdateOrientation:
311 {
312 _ChangeState(message);
313 break;
314 }
315
316 default:
317 BView::MessageReceived(message);
318 }
319 }
320
321
322 void
MouseDown(BPoint where)323 TBarView::MouseDown(BPoint where)
324 {
325 // exit if menu or calendar is showing
326 if (fBarWindow == NULL || fBarWindow->IsShowingMenu()
327 || fReplicantTray->fTime->IsShowingCalendar()) {
328 return BView::MouseDown(where);
329 }
330
331 // where is relative to status tray while mouse is over it so pull
332 // the screen point out of the message instead
333 BMessage* currentMessage = Window()->CurrentMessage();
334 if (currentMessage == NULL)
335 return BView::MouseDown(where);
336
337 desk_settings* settings = fBarApp->Settings();
338 bool alwaysOnTop = settings->alwaysOnTop;
339 bool autoRaise = settings->autoRaise;
340 bool autoHide = settings->autoHide;
341
342 BPoint whereScreen = currentMessage->GetPoint("screen_where",
343 ConvertToScreen(where));
344 fMouseDownOutside = !Window()->Frame().Contains(whereScreen);
345
346 if (fMouseDownOutside) {
347 // lower Deskbar
348 if (!alwaysOnTop && autoRaise && fIsRaised)
349 RaiseDeskbar(false);
350
351 // hide Deskbar
352 if (autoHide && !IsHidden())
353 HideDeskbar(true);
354 } else {
355 // Activate Deskbar on click only if not in auto-raise mode and not
356 // in always-on-top mode. In auto-raise mode click activates through
357 // foreground windows, which we don't want. We don't ever want to
358 // activate Deskbar in always-on-top mode because Deskbar is
359 // already on top and we don't want to change the active window.
360 if (!autoRaise && !alwaysOnTop)
361 Window()->Activate(true);
362
363 if ((modifiers() & (B_CONTROL_KEY | B_COMMAND_KEY | B_OPTION_KEY
364 | B_SHIFT_KEY)) == (B_CONTROL_KEY | B_COMMAND_KEY)) {
365 // The window key was pressed - enter dragging code
366 fDragRegion->MouseDown(fDragRegion->DragRegion().LeftTop());
367 return BView::MouseDown(where);
368 }
369 }
370
371 BView::MouseDown(where);
372 }
373
374
375 void
MouseMoved(BPoint where,uint32 transit,const BMessage * dragMessage)376 TBarView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
377 {
378 if (fDragRegion->IsDragging())
379 return fDragRegion->MouseMoved(where, transit, dragMessage);
380 else if (fResizeControl->IsResizing())
381 return BView::MouseMoved(where, transit, dragMessage);
382
383 desk_settings* settings = fBarApp->Settings();
384 bool alwaysOnTop = settings->alwaysOnTop;
385 bool autoRaise = settings->autoRaise;
386 bool autoHide = settings->autoHide;
387
388 // exit if both auto-raise and auto-hide are off
389 if (!autoRaise && !autoHide) {
390 // turn off mouse tracking
391 SetEventMask(0);
392
393 return BView::MouseMoved(where, transit, dragMessage);
394 } else if (EventMask() != B_POINTER_EVENTS) {
395 // track mouse outside view
396 SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
397 }
398
399 // exit if menu or calendar is showing
400 if (fBarWindow == NULL || fBarWindow->IsShowingMenu()
401 || fReplicantTray->fTime->IsShowingCalendar()) {
402 return BView::MouseMoved(where, transit, dragMessage);
403 }
404
405 // where is relative to status tray while mouse is over it so pull
406 // the screen point out of the message instead
407 BMessage* currentMessage = Window()->CurrentMessage();
408 if (currentMessage == NULL)
409 return BView::MouseMoved(where, transit, dragMessage);
410
411 BPoint whereScreen = currentMessage->GetPoint("screen_where",
412 ConvertToScreen(where));
413 BRect screenFrame = (BScreen(Window())).Frame();
414 bool onScreenEdge = whereScreen.x == screenFrame.left
415 || whereScreen.x == screenFrame.right
416 || whereScreen.y == screenFrame.top
417 || whereScreen.y == screenFrame.bottom;
418
419 // Auto-Raise and Auto-Hide
420 if (!Window()->Frame().Contains(whereScreen)) {
421 // lower Deskbar
422 if (!alwaysOnTop && autoRaise && fIsRaised && !fMouseDownOutside)
423 RaiseDeskbar(false);
424
425 // check if cursor to bar distance is below threshold
426 BRect preventHideArea = Window()->Frame().InsetByCopy(
427 -kMaxPreventHidingDist, -kMaxPreventHidingDist);
428 if (!preventHideArea.Contains(whereScreen)
429 && autoHide && !IsHidden()) {
430 // hide Deskbar
431 HideDeskbar(true);
432 }
433 } else if (onScreenEdge) {
434 // cursor is on a screen edge within the window frame
435
436 // raise Deskbar
437 if (!alwaysOnTop && autoRaise && !fIsRaised && !fMouseDownOutside)
438 RaiseDeskbar(true);
439
440 // show Deskbar
441 if (autoHide && IsHidden())
442 HideDeskbar(false);
443 }
444
445 BView::MouseMoved(where, transit, dragMessage);
446 }
447
448
449 void
MouseUp(BPoint where)450 TBarView::MouseUp(BPoint where)
451 {
452 fMouseDownOutside = false;
453
454 BView::MouseUp(where);
455 }
456
457
458 void
PlaceDeskbarMenu()459 TBarView::PlaceDeskbarMenu()
460 {
461 float width = 0;
462 float height = 0;
463
464 // Calculate the size of the deskbar menu
465 BRect menuFrame(Bounds());
466 if (fVertical) {
467 width = static_cast<TBarApp*>(be_app)->Settings()->width;
468 height = fTabHeight;
469 } else {
470 // horizontal
471 if (fState == kMiniState) {
472 width = gMinimumWindowWidth;
473 height = std::max(fTabHeight,
474 kGutter + fReplicantTray->MaxReplicantHeight() + kGutter);
475 } else {
476 width = gMinimumWindowWidth / 2
477 + be_control_look->ComposeSpacing(kIconPadding);
478 height = std::max(TeamMenuItemHeight(),
479 kGutter + fReplicantTray->MaxReplicantHeight() + kGutter);
480 }
481 }
482 menuFrame.bottom = menuFrame.top + height;
483
484 if (fBarMenuBar == NULL) {
485 // create the Be menu
486 fBarMenuBar = new TBarMenuBar(menuFrame, "BarMenuBar", this);
487 AddChild(fBarMenuBar);
488 } else
489 fBarMenuBar->SmartResize(-1, -1);
490
491 if (fState == kMiniState) {
492 // vertical or horizontal mini
493 fBarMenuBar->RemoveSeperatorItem();
494 fBarMenuBar->AddTeamMenu();
495 } else if (fVertical) {
496 fBarMenuBar->RemoveSeperatorItem();
497 fBarMenuBar->RemoveTeamMenu();
498 } else {
499 fBarMenuBar->RemoveTeamMenu();
500 fBarMenuBar->AddSeparatorItem();
501 }
502
503 fBarMenuBar->SmartResize(width, height);
504 fBarMenuBar->MoveTo(B_ORIGIN);
505 }
506
507
508 void
PlaceTray(bool vertSwap,bool leftSwap)509 TBarView::PlaceTray(bool vertSwap, bool leftSwap)
510 {
511 BPoint statusLoc;
512 if (fTrayLocation == 0) {
513 // no replicant tray mode, not used
514 if (!fReplicantTray->IsHidden())
515 fReplicantTray->Hide();
516 return;
517 } else if (fReplicantTray->IsHidden())
518 fReplicantTray->Show();
519
520 fReplicantTray->RealignReplicants();
521 fDragRegion->ResizeToPreferred();
522 // also resizes replicant tray
523
524 if (fVertical) {
525 if (fResizeControl->IsHidden())
526 fResizeControl->Show();
527
528 if (fLeft) {
529 // move replicant tray past dragger width on left
530 // also down 1px so it won't cover the border
531 fReplicantTray->MoveTo(gDragWidth + kGutter, kGutter);
532
533 // shrink width by same amount
534 fReplicantTray->ResizeBy(-(gDragWidth + kGutter), 0);
535 } else {
536 // move replicant tray down 1px so it won't cover the border
537 fReplicantTray->MoveTo(0, kGutter);
538 }
539
540 statusLoc.x = 0;
541 statusLoc.y = fBarMenuBar->Frame().bottom + 1;
542 } else {
543 // horizontal
544 if (fState == kMiniState) {
545 // horizontal mini
546 statusLoc.x = fLeft ? fBarMenuBar->Frame().right + 1 : 0;
547 statusLoc.y = 0;
548
549 // move past dragger and top border
550 // and make room for the top and bottom borders
551 fReplicantTray->MoveTo(fLeft ? gDragWidth : 0, kGutter);
552 fReplicantTray->ResizeBy(0, -4);
553 } else {
554 // move tray right and down to not cover border, resize by same
555 fReplicantTray->MoveTo(2, 0);
556 fReplicantTray->ResizeBy(-2, 0);
557 BRect screenFrame = (BScreen(Window())).Frame();
558 statusLoc.x = screenFrame.right - fDragRegion->Bounds().Width();
559 statusLoc.y = 0;
560 }
561 }
562
563 fDragRegion->MoveTo(statusLoc);
564
565 // make room for top and bottom border
566 fResizeControl->ResizeTo(gDragWidth, fDragRegion->Bounds().Height() - 2);
567
568 if (fVertical) {
569 // move resize control into place based on width setting
570 fResizeControl->MoveTo(
571 fLeft ? fBarApp->Settings()->width - gDragWidth : 0, 1);
572 if (fResizeControl->IsHidden())
573 fResizeControl->Show();
574 } else {
575 // hide resize control
576 if (!fResizeControl->IsHidden())
577 fResizeControl->Hide();
578 }
579
580 fDragRegion->Invalidate();
581 }
582
583
584 void
PlaceApplicationBar()585 TBarView::PlaceApplicationBar()
586 {
587 BRect screenFrame = (BScreen(Window())).Frame();
588 if (fState == kMiniState) {
589 if (!fInlineScrollView->IsHidden())
590 fInlineScrollView->Hide();
591
592 SizeWindow(screenFrame);
593 PositionWindow(screenFrame);
594 Window()->UpdateIfNeeded();
595 if (!fVertical) {
596 // move the menu bar into place after the window has been resized
597 // based on replicant tray
598 fBarMenuBar->MoveTo(fLeft ? 0 : fDragRegion->Bounds().right + 1,
599 0);
600 }
601 Invalidate();
602 return;
603 }
604
605 if (fInlineScrollView->IsHidden())
606 fInlineScrollView->Show();
607
608 BRect expandoFrame(0, 0, 0, 0);
609 if (fVertical) {
610 // left or right
611 expandoFrame.left = fDragRegion->Frame().left;
612 expandoFrame.top = fTrayLocation != 0 ? fDragRegion->Frame().bottom + 1
613 : fBarMenuBar->Frame().bottom + 1;
614 expandoFrame.right = fBarApp->Settings()->width;
615 expandoFrame.bottom = fState == kFullState ? screenFrame.bottom
616 : Frame().bottom;
617 } else {
618 // top or bottom
619 expandoFrame.top = 0;
620 expandoFrame.bottom = TeamMenuItemHeight();
621 expandoFrame.left = screenFrame.left + fBarMenuBar->Frame().Width();
622 expandoFrame.right = screenFrame.right - fDragRegion->Frame().Width() - 1;
623 }
624
625 fInlineScrollView->DetachScrollers();
626 fInlineScrollView->MoveTo(expandoFrame.LeftTop());
627 fInlineScrollView->ResizeTo(expandoFrame.Width(), fVertical
628 ? screenFrame.bottom - expandoFrame.top : expandoFrame.bottom);
629 fExpandoMenuBar->ResizeTo(expandoFrame.Width(), expandoFrame.Height());
630 fExpandoMenuBar->MoveTo(0, 0);
631 fExpandoMenuBar->BuildItems();
632 fExpandoMenuBar->SizeWindow(0);
633 }
634
635
636 void
GetPreferredWindowSize(BRect screenFrame,float * width,float * height)637 TBarView::GetPreferredWindowSize(BRect screenFrame, float* width,
638 float* height)
639 {
640 float windowHeight = 0;
641 float windowWidth = 0;
642 bool setToHiddenSize = fBarApp->Settings()->autoHide && IsHidden()
643 && !fDragRegion->IsDragging();
644
645 if (setToHiddenSize) {
646 windowHeight = kHiddenDimension;
647
648 if (fState == kExpandoState && !fVertical) {
649 // top or bottom, full
650 windowWidth = screenFrame.Width();
651 } else
652 windowWidth = kHiddenDimension;
653 } else if (fVertical) {
654 if (fState == kFullState) {
655 // full state has minimum screen window height
656 windowHeight = std::max(screenFrame.bottom, windowHeight);
657 } else {
658 // mini or expando
659 if (fTrayLocation != 0)
660 windowHeight = fDragRegion->Frame().bottom;
661 else
662 windowHeight = fBarMenuBar->Frame().bottom;
663
664 if (fState == kExpandoState && fExpandoMenuBar != NULL) {
665 // top left or right
666 windowHeight += fExpandoMenuBar->Bounds().Height();
667 // use Height() here, not bottom so view can be scrolled
668 }
669 }
670
671 windowWidth = fBarApp->Settings()->width;
672 } else {
673 // horizontal
674 if (fState == kMiniState) {
675 // four corners horizontal
676 windowHeight = fBarMenuBar->Frame().Height();
677 windowWidth = fDragRegion->Frame().Width()
678 + fBarMenuBar->Frame().Width() + 1;
679 } else {
680 // horizontal top or bottom
681 windowHeight = std::max(TeamMenuItemHeight(),
682 kGutter + fReplicantTray->MaxReplicantHeight() + kGutter);
683 windowWidth = screenFrame.Width();
684 }
685 }
686
687 *width = windowWidth;
688 *height = windowHeight;
689 }
690
691
692 void
SizeWindow(BRect screenFrame)693 TBarView::SizeWindow(BRect screenFrame)
694 {
695 float windowWidth;
696 float windowHeight;
697 GetPreferredWindowSize(screenFrame, &windowWidth, &windowHeight);
698 Window()->ResizeTo(windowWidth, windowHeight);
699 ResizeTo(windowWidth, windowHeight);
700 }
701
702
703 void
PositionWindow(BRect screenFrame)704 TBarView::PositionWindow(BRect screenFrame)
705 {
706 float windowWidth;
707 float windowHeight;
708 GetPreferredWindowSize(screenFrame, &windowWidth, &windowHeight);
709
710 BPoint moveLoc(0, 0);
711 // right, expanded, mini, or full
712 if (!fLeft && (fVertical || fState == kMiniState))
713 moveLoc.x = screenFrame.right - windowWidth;
714
715 // bottom, full
716 if (!fTop)
717 moveLoc.y = screenFrame.bottom - windowHeight;
718
719 Window()->MoveTo(moveLoc);
720 }
721
722
723 void
CheckForScrolling()724 TBarView::CheckForScrolling()
725 {
726 if (fInlineScrollView == NULL && fExpandoMenuBar == NULL)
727 return;
728
729 if (fExpandoMenuBar->CheckForSizeOverrun())
730 fInlineScrollView->AttachScrollers();
731 else
732 fInlineScrollView->DetachScrollers();
733 }
734
735
736 void
SaveSettings()737 TBarView::SaveSettings()
738 {
739 desk_settings* settings = fBarApp->Settings();
740
741 settings->vertical = fVertical;
742 settings->left = fLeft;
743 settings->top = fTop;
744 settings->state = fState;
745
746 fReplicantTray->SaveTimeSettings();
747 }
748
749
750 void
UpdatePlacement()751 TBarView::UpdatePlacement()
752 {
753 ChangeState(fState, fVertical, fLeft, fTop);
754 }
755
756
757 void
ChangeState(int32 state,bool vertical,bool left,bool top,bool async)758 TBarView::ChangeState(int32 state, bool vertical, bool left, bool top,
759 bool async)
760 {
761 BMessage message(kUpdateOrientation);
762 message.AddInt32("state", state);
763 message.AddBool("vertical", vertical);
764 message.AddBool("left", left);
765 message.AddBool("top", top);
766
767 if (async)
768 BMessenger(this).SendMessage(&message);
769 else
770 _ChangeState(&message);
771 }
772
773
774 void
_ChangeState(BMessage * message)775 TBarView::_ChangeState(BMessage* message)
776 {
777 int32 state = message->FindInt32("state");
778 bool vertical = message->FindBool("vertical");
779 bool left = message->FindBool("left");
780 bool top = message->FindBool("top");
781
782 bool vertSwap = (fVertical != vertical);
783 bool leftSwap = (fLeft != left);
784 bool stateChanged = (fState != state);
785
786 fState = state;
787 fVertical = vertical;
788 fLeft = left;
789 fTop = top;
790
791 if (stateChanged || vertSwap) {
792 be_app->PostMessage(kStateChanged);
793 // Send a message to the preferences window to let it know to
794 // enable or disable preference items.
795
796 TBarWindow* barWindow = dynamic_cast<TBarWindow*>(Window());
797 if (barWindow != NULL)
798 barWindow->SetSizeLimits();
799
800 if (vertSwap && fExpandoMenuBar != NULL) {
801 if (fVertical) {
802 fInlineScrollView->SetOrientation(B_VERTICAL);
803 fExpandoMenuBar->SetMenuLayout(B_ITEMS_IN_COLUMN);
804 fExpandoMenuBar->StartMonitoringWindows();
805 } else {
806 fInlineScrollView->SetOrientation(B_HORIZONTAL);
807 fExpandoMenuBar->SetMenuLayout(B_ITEMS_IN_ROW);
808 fExpandoMenuBar->StopMonitoringWindows();
809 }
810 }
811 }
812
813 PlaceDeskbarMenu();
814 PlaceTray(vertSwap, leftSwap);
815 PlaceApplicationBar();
816 }
817
818
819 void
RaiseDeskbar(bool raise)820 TBarView::RaiseDeskbar(bool raise)
821 {
822 fIsRaised = raise;
823
824 // raise or lower Deskbar without changing the active window
825 if (raise) {
826 Window()->SetFeel(B_FLOATING_ALL_WINDOW_FEEL);
827 Window()->SetFeel(B_NORMAL_WINDOW_FEEL);
828 } else
829 Window()->SendBehind(Window());
830 }
831
832
833 void
HideDeskbar(bool hide)834 TBarView::HideDeskbar(bool hide)
835 {
836 BRect screenFrame = (BScreen(Window())).Frame();
837
838 if (hide) {
839 Hide();
840 if (fBarWindow != NULL)
841 fBarWindow->SetSizeLimits();
842
843 PositionWindow(screenFrame);
844 SizeWindow(screenFrame);
845 } else {
846 Show();
847 if (fBarWindow != NULL)
848 fBarWindow->SetSizeLimits();
849
850 SizeWindow(screenFrame);
851 PositionWindow(screenFrame);
852 }
853 }
854
855
856 // #pragma mark - Drag and Drop
857
858
859 void
CacheDragData(const BMessage * incoming)860 TBarView::CacheDragData(const BMessage* incoming)
861 {
862 if (!incoming)
863 return;
864
865 if (Dragging() && SpringLoadedFolderCompareMessages(incoming, fDragMessage))
866 return;
867
868 // disposes then fills cached drag message and
869 // mimetypes list
870 SpringLoadedFolderCacheDragData(incoming, &fDragMessage, &fCachedTypesList);
871 }
872
873
874 static void
init_tracking_hook(BMenuItem * item,bool (* hookFunction)(BMenu *,void *),void * state)875 init_tracking_hook(BMenuItem* item,
876 bool (*hookFunction)(BMenu*, void*), void* state)
877 {
878 if (!item)
879 return;
880
881 BMenu* windowMenu = item->Submenu();
882 if (windowMenu) {
883 // have a menu, set the tracking hook
884 windowMenu->SetTrackingHook(hookFunction, state);
885 }
886 }
887
888
889 status_t
DragStart()890 TBarView::DragStart()
891 {
892 if (!Dragging())
893 return B_OK;
894
895 BPoint loc;
896 uint32 buttons;
897 GetMouse(&loc, &buttons);
898
899 if (fExpandoMenuBar != NULL && fExpandoMenuBar->Frame().Contains(loc)) {
900 ConvertToScreen(&loc);
901 BPoint expandoLocation = fExpandoMenuBar->ConvertFromScreen(loc);
902 TTeamMenuItem* item = fExpandoMenuBar->TeamItemAtPoint(expandoLocation);
903
904 if (fLastDragItem)
905 init_tracking_hook(fLastDragItem, NULL, NULL);
906
907 if (item != NULL) {
908 if (item == fLastDragItem)
909 return B_OK;
910
911 fLastDragItem = item;
912 }
913 }
914
915 return B_OK;
916 }
917
918
919 bool
MenuTrackingHook(BMenu * menu,void * castToThis)920 TBarView::MenuTrackingHook(BMenu* menu, void* castToThis)
921 {
922 // return true if the menu should go away
923 TrackingHookData* data = static_cast<TrackingHookData*>(castToThis);
924 if (!data)
925 return false;
926
927 TBarView* barView = dynamic_cast<TBarView*>(data->fTarget.Target(NULL));
928 if (!barView || !menu->LockLooper())
929 return false;
930
931 uint32 buttons;
932 BPoint location;
933 menu->GetMouse(&location, &buttons);
934
935 bool endMenu = true;
936 BRect frame(menu->Bounds());
937 frame.InsetBy(-kMenuTrackMargin, -kMenuTrackMargin);
938
939 if (frame.Contains(location)) {
940 // if current loc is still in the menu
941 // keep tracking
942 endMenu = false;
943 } else {
944 // see if the mouse is in the team/deskbar menu item
945 menu->ConvertToScreen(&location);
946 if (barView->LockLooper()) {
947 TExpandoMenuBar* expandoMenuBar = barView->ExpandoMenuBar();
948 TBarWindow* barWindow
949 = dynamic_cast<TBarWindow*>(barView->Window());
950 TDeskbarMenu* deskbarMenu = barWindow->DeskbarMenu();
951
952 if (deskbarMenu && deskbarMenu->LockLooper()) {
953 deskbarMenu->ConvertFromScreen(&location);
954 if (deskbarMenu->Frame().Contains(location))
955 endMenu = false;
956
957 deskbarMenu->UnlockLooper();
958 }
959
960 if (endMenu && expandoMenuBar) {
961 expandoMenuBar->ConvertFromScreen(&location);
962 BMenuItem* item = expandoMenuBar->TeamItemAtPoint(location);
963 if (item)
964 endMenu = false;
965 }
966 barView->UnlockLooper();
967 }
968 }
969
970 menu->UnlockLooper();
971
972 return endMenu;
973 }
974
975
976 // used by WindowMenu and TeamMenu to
977 // set the tracking hook for dragging
978 TrackingHookData*
GetTrackingHookData()979 TBarView::GetTrackingHookData()
980 {
981 // all tracking hook data is
982 // preset in AttachedToWindow
983 // data should never change
984 return &fTrackingHookData;
985 }
986
987
988 void
DragStop(bool full)989 TBarView::DragStop(bool full)
990 {
991 if (!Dragging())
992 return;
993
994 if (fExpandoMenuBar != NULL) {
995 if (fLastDragItem != NULL) {
996 init_tracking_hook(fLastDragItem, NULL, NULL);
997 fLastDragItem = NULL;
998 }
999 }
1000
1001 if (full) {
1002 delete fDragMessage;
1003 fDragMessage = NULL;
1004
1005 delete fCachedTypesList;
1006 fCachedTypesList = NULL;
1007 }
1008 }
1009
1010
1011 bool
AppCanHandleTypes(const char * signature)1012 TBarView::AppCanHandleTypes(const char* signature)
1013 {
1014 // used for filtering apps/teams in the ExpandoMenuBar and TeamMenu
1015
1016 if (modifiers() & B_CONTROL_KEY) {
1017 // control key forces acceptance, just like drag&drop on icons
1018 return true;
1019 }
1020
1021 if (!signature || strlen(signature) == 0
1022 || !fCachedTypesList || fCachedTypesList->CountItems() == 0)
1023 return false;
1024
1025 if (strcasecmp(signature, kTrackerSignature) == 0) {
1026 // tracker should support all types
1027 // and should pass them on to the appropriate application
1028 return true;
1029 }
1030
1031 entry_ref hintref;
1032 BMimeType appmime(signature);
1033 if (appmime.GetAppHint(&hintref) != B_OK)
1034 return false;
1035
1036 // an app was found, now see if it supports any of
1037 // the refs in the message
1038 BFile file(&hintref, O_RDONLY);
1039 BAppFileInfo fileinfo(&file);
1040
1041 // scan the cached mimetype list and see if this app
1042 // supports anything in the list
1043 // only one item needs to match in the list of refs
1044
1045 int32 count = fCachedTypesList->CountItems();
1046 for (int32 i = 0 ; i < count ; i++) {
1047 if (fileinfo.IsSupportedType(fCachedTypesList->ItemAt(i)->String()))
1048 return true;
1049 }
1050
1051 return false;
1052 }
1053
1054
1055 void
SetDragOverride(bool on)1056 TBarView::SetDragOverride(bool on)
1057 {
1058 fRefsRcvdOnly = on;
1059 }
1060
1061
1062 bool
DragOverride()1063 TBarView::DragOverride()
1064 {
1065 return fRefsRcvdOnly;
1066 }
1067
1068
1069 status_t
SendDragMessage(const char * signature,entry_ref * ref)1070 TBarView::SendDragMessage(const char* signature, entry_ref* ref)
1071 {
1072 status_t err = B_ERROR;
1073 if (fDragMessage != NULL) {
1074 if (fRefsRcvdOnly) {
1075 // current message sent to apps is only B_REFS_RECEIVED
1076 fDragMessage->what = B_REFS_RECEIVED;
1077 }
1078
1079 BRoster roster;
1080 if (signature != NULL && *signature != '\0'
1081 && roster.IsRunning(signature)) {
1082 BMessenger messenger(signature);
1083 // drag message is still owned by DB, copy is sent
1084 // can toss it after send
1085 err = messenger.SendMessage(fDragMessage);
1086 } else if (ref != NULL) {
1087 FSLaunchItem((const entry_ref*)ref, (const BMessage*)fDragMessage,
1088 true, true);
1089 } else if (signature != NULL && *signature != '\0')
1090 roster.Launch(signature, fDragMessage);
1091 }
1092
1093 return err;
1094 }
1095
1096
1097 bool
InvokeItem(const char * signature)1098 TBarView::InvokeItem(const char* signature)
1099 {
1100 // sent from TeamMenuItem
1101 if (Dragging() && AppCanHandleTypes(signature)) {
1102 SendDragMessage(signature);
1103 // invoking okay to toss memory
1104 DragStop(true);
1105 return true;
1106 }
1107
1108 return false;
1109 }
1110
1111
1112 void
HandleDeskbarMenu(BMessage * messagewithdestination)1113 TBarView::HandleDeskbarMenu(BMessage* messagewithdestination)
1114 {
1115 if (!Dragging())
1116 return;
1117
1118 // in mini-mode
1119 if (fVertical && fState != kExpandoState) {
1120 // if drop is in the team menu, bail
1121 if (fBarMenuBar->CountItems() >= 2) {
1122 uint32 buttons;
1123 BPoint location;
1124 GetMouse(&location, &buttons);
1125 if (fBarMenuBar->ItemAt(1)->Frame().Contains(location))
1126 return;
1127 }
1128 }
1129
1130 if (messagewithdestination) {
1131 entry_ref ref;
1132 if (messagewithdestination->FindRef("refs", &ref) == B_OK) {
1133 BEntry entry(&ref, true);
1134 if (entry.IsDirectory()) {
1135 // if the ref received (should only be 1) is a directory
1136 // then add the drag refs to the directory
1137 AddRefsToDeskbarMenu(DragMessage(), &ref);
1138 } else
1139 SendDragMessage(NULL, &ref);
1140 }
1141 } else {
1142 // adds drag refs to top level in deskbar menu
1143 AddRefsToDeskbarMenu(DragMessage(), NULL);
1144 }
1145
1146 // clean up drag message and types list
1147 DragStop(true);
1148 }
1149
1150
1151 // #pragma mark - Add-ons
1152
1153
1154 // shelf is ignored for now,
1155 // it exists in anticipation of having other 'shelves' for
1156 // storing items
1157
1158 status_t
ItemInfo(int32 id,const char ** name,DeskbarShelf * shelf)1159 TBarView::ItemInfo(int32 id, const char** name, DeskbarShelf* shelf)
1160 {
1161 *shelf = B_DESKBAR_TRAY;
1162 return fReplicantTray->ItemInfo(id, name);
1163 }
1164
1165
1166 status_t
ItemInfo(const char * name,int32 * id,DeskbarShelf * shelf)1167 TBarView::ItemInfo(const char* name, int32* id, DeskbarShelf* shelf)
1168 {
1169 *shelf = B_DESKBAR_TRAY;
1170 return fReplicantTray->ItemInfo(name, id);
1171 }
1172
1173
1174 bool
ItemExists(int32 id,DeskbarShelf)1175 TBarView::ItemExists(int32 id, DeskbarShelf)
1176 {
1177 return fReplicantTray->IconExists(id);
1178 }
1179
1180
1181 bool
ItemExists(const char * name,DeskbarShelf)1182 TBarView::ItemExists(const char* name, DeskbarShelf)
1183 {
1184 return fReplicantTray->IconExists(name);
1185 }
1186
1187
1188 int32
CountItems(DeskbarShelf)1189 TBarView::CountItems(DeskbarShelf)
1190 {
1191 return fReplicantTray->ReplicantCount();
1192 }
1193
1194
1195 BSize
MaxItemSize(DeskbarShelf shelf)1196 TBarView::MaxItemSize(DeskbarShelf shelf)
1197 {
1198 return BSize(fReplicantTray->MaxReplicantWidth(),
1199 fReplicantTray->MaxReplicantHeight());
1200 }
1201
1202
1203 status_t
AddItem(BMessage * item,DeskbarShelf,int32 * id)1204 TBarView::AddItem(BMessage* item, DeskbarShelf, int32* id)
1205 {
1206 return fReplicantTray->AddIcon(item, id);
1207 }
1208
1209
1210 status_t
AddItem(BEntry * entry,DeskbarShelf,int32 * id)1211 TBarView::AddItem(BEntry* entry, DeskbarShelf, int32* id)
1212 {
1213 return fReplicantTray->LoadAddOn(entry, id);
1214 }
1215
1216
1217 void
RemoveItem(int32 id)1218 TBarView::RemoveItem(int32 id)
1219 {
1220 fReplicantTray->RemoveIcon(id);
1221 }
1222
1223
1224 void
RemoveItem(const char * name,DeskbarShelf)1225 TBarView::RemoveItem(const char* name, DeskbarShelf)
1226 {
1227 fReplicantTray->RemoveIcon(name);
1228 }
1229
1230
1231 BRect
OffsetIconFrame(BRect rect) const1232 TBarView::OffsetIconFrame(BRect rect) const
1233 {
1234 BRect frame(Frame());
1235
1236 frame.left += fDragRegion->Frame().left + fReplicantTray->Frame().left
1237 + rect.left;
1238 frame.top += fDragRegion->Frame().top + fReplicantTray->Frame().top
1239 + rect.top;
1240
1241 frame.right = frame.left + rect.Width();
1242 frame.bottom = frame.top + rect.Height();
1243
1244 return frame;
1245 }
1246
1247
1248 BRect
IconFrame(int32 id) const1249 TBarView::IconFrame(int32 id) const
1250 {
1251 return OffsetIconFrame(fReplicantTray->IconFrame(id));
1252 }
1253
1254
1255 BRect
IconFrame(const char * name) const1256 TBarView::IconFrame(const char* name) const
1257 {
1258 return OffsetIconFrame(fReplicantTray->IconFrame(name));
1259 }
1260
1261
1262 float
TeamMenuItemHeight() const1263 TBarView::TeamMenuItemHeight() const
1264 {
1265 const int32 iconSize = fBarApp->TeamIconSize();
1266 const float iconPadding = be_control_look->ComposeSpacing(kIconPadding);
1267 float iconOnlyHeight = iconSize + iconPadding / 2;
1268 const int32 large = be_control_look->ComposeIconSize(B_LARGE_ICON)
1269 .IntegerWidth() + 1;
1270
1271 font_height fontHeight;
1272 if (fExpandoMenuBar != NULL)
1273 fExpandoMenuBar->GetFontHeight(&fontHeight);
1274 else
1275 GetFontHeight(&fontHeight);
1276
1277 float labelHeight = fontHeight.ascent + fontHeight.descent;
1278 labelHeight = labelHeight < kMinTeamItemHeight ? kMinTeamItemHeight
1279 : ceilf(labelHeight * 1.1f);
1280
1281 if (fBarApp->Settings()->hideLabels && iconSize > B_MINI_ICON) {
1282 // height is determined based solely on icon size
1283 return iconOnlyHeight;
1284 } else if (!fVertical || (fVertical && iconSize <= large)) {
1285 // horizontal or vertical with label on same row as icon:
1286 // height based on icon size or font size, whichever is bigger
1287 return std::max(iconOnlyHeight, labelHeight);
1288 } else if (fVertical && iconSize > large) {
1289 // vertical with label below icon: height based on icon and label
1290 return ceilf(iconOnlyHeight + labelHeight);
1291 } else {
1292 // height is determined based solely on label height
1293 return labelHeight;
1294 }
1295 }
1296