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