xref: /haiku/src/apps/deskbar/BarView.cpp (revision 4466b89c65970de4c7236ac87faa2bee4589f413)
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 #include <Debug.h>
37 
38 #include "BarView.h"
39 
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 
44 #include <AppFileInfo.h>
45 #include <Bitmap.h>
46 #include <Directory.h>
47 #include <NodeInfo.h>
48 #include <Roster.h>
49 #include <Screen.h>
50 #include <String.h>
51 
52 #include "icons.h"
53 #include "BarApp.h"
54 #include "BarMenuBar.h"
55 #include "BarWindow.h"
56 #include "BeMenu.h"
57 #include "DeskBarUtils.h"
58 #include "ExpandoMenuBar.h"
59 #include "FSUtils.h"
60 #include "ResourceSet.h"
61 #include "StatusView.h"
62 #include "TeamMenuItem.h"
63 
64 
65 const int32 kDefaultRecentDocCount = 10;
66 const int32 kDefaultRecentFolderCount = 10;
67 const int32 kDefaultRecentAppCount = 10;
68 
69 const int32 kMenuTrackMargin = 20;
70 
71 
72 TBarView::TBarView(BRect frame, bool vertical, bool left, bool top,
73 		bool showInterval, uint32 state, float, bool showTime)
74 	: BView(frame, "BarView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW),
75 	fBarMenuBar(NULL),
76 	fExpando(NULL),
77 	fTrayLocation(1),
78 	fShowInterval(showInterval),
79 	fShowClock(showTime),
80 	fVertical(vertical),
81 	fTop(top),
82 	fLeft(left),
83 	fState(static_cast<int32>(state)),
84 	fRefsRcvdOnly(true),
85 	fDragMessage(NULL),
86 	fCachedTypesList(NULL),
87 	fMaxRecentDocs(kDefaultRecentDocCount),
88 	fMaxRecentApps(kDefaultRecentAppCount),
89 	fLastDragItem(NULL)
90 {
91 	fReplicantTray = new TReplicantTray(this, fVertical);
92 	fDragRegion = new TDragRegion(this, fReplicantTray);
93 	fDragRegion->AddChild(fReplicantTray);
94 	if (fTrayLocation != 0)
95 		AddChild(fDragRegion);
96 }
97 
98 
99 TBarView::~TBarView()
100 {
101 	delete fDragMessage;
102 	delete fCachedTypesList;
103 
104 	RemoveExpandedItems();
105 }
106 
107 
108 void
109 TBarView::AttachedToWindow()
110 {
111 	BView::AttachedToWindow();
112 
113 	SetViewColor(ui_color(B_MENU_BACKGROUND_COLOR));
114 	SetFont(be_plain_font);
115 
116 	UpdateEventMask();
117 	UpdatePlacement();
118 
119 	fTrackingHookData.fTrackingHook = MenuTrackingHook;
120 	fTrackingHookData.fTarget = BMessenger(this);
121 	fTrackingHookData.fDragMessage = new BMessage(B_REFS_RECEIVED);
122 }
123 
124 
125 void
126 TBarView::DetachedFromWindow()
127 {
128 	delete fTrackingHookData.fDragMessage;
129 	fTrackingHookData.fDragMessage = NULL;
130 }
131 
132 
133 void
134 TBarView::Draw(BRect)
135 {
136 	BRect bounds(Bounds());
137 
138 	rgb_color hilite = tint_color(ViewColor(), B_DARKEN_1_TINT);
139 	rgb_color light = tint_color(ViewColor(), B_LIGHTEN_2_TINT);
140 
141 	SetHighColor(hilite);
142 	if (AcrossTop())
143 		StrokeLine(bounds.LeftBottom(), bounds.RightBottom());
144 	else if (AcrossBottom())
145 		StrokeLine(bounds.LeftTop(), bounds.RightTop());
146 
147 	if (Vertical() && Expando()) {
148 		SetHighColor(hilite);
149 		BRect frame(fExpando->Frame());
150 		StrokeLine(BPoint(frame.left, frame.top - 1),
151 			BPoint(frame.right, frame.top -1));
152 	}
153 }
154 
155 
156 void
157 TBarView::MessageReceived(BMessage* message)
158 {
159 	switch (message->what) {
160 		case B_REFS_RECEIVED:
161 			// received when an item is selected during DnD
162 			// message is targeted here from Be menu
163 			HandleBeMenu(message);
164 			break;
165 
166 		case B_ARCHIVED_OBJECT:
167 		{
168 			// this message has been retargeted to here
169 			// instead of directly to the replicant tray
170 			// so that I can follow the common pathway
171 			// for adding icons to the tray
172 			int32 id;
173 			AddItem(new BMessage(*message), B_DESKBAR_TRAY, &id);
174 			break;
175 		}
176 
177 		default:
178 			BView::MessageReceived(message);
179 	}
180 }
181 
182 
183 void
184 TBarView::MouseMoved(BPoint where, uint32 transit, const BMessage* dragMessage)
185 {
186 	if (Window() == NULL || EventMask() == 0)
187 		return;
188 
189 	desk_settings* settings = ((TBarApp*)be_app)->Settings();
190 	bool alwaysOnTop = settings->alwaysOnTop;
191 	bool autoRaise = settings->autoRaise;
192 	bool autoHide = settings->autoHide;
193 
194 	if (!autoRaise && !autoHide)
195 		return;
196 
197 	if (DragRegion()->IsDragging())
198 		return;
199 
200 	bool isTopMost = Window()->Feel() == B_FLOATING_ALL_WINDOW_FEEL;
201 
202 	// Auto-Raise
203 	where = ConvertToScreen(where);
204 	BScreen screen(Window());
205 	BRect screenFrame = screen.Frame();
206 	if ((where.x == screenFrame.left || where.x == screenFrame.right
207 			|| where.y == screenFrame.top || where.y == screenFrame.bottom)
208 		&& Window()->Frame().Contains(where)) {
209 		// cursor is on a screen edge within the window frame
210 
211 		if (!alwaysOnTop && autoRaise && !isTopMost)
212 			RaiseDeskbar(true);
213 
214 		if (autoHide && IsHidden())
215 			HideDeskbar(false);
216 	} else {
217 		// cursor is not on screen edge
218 		BRect preventHideArea = Window()->Frame().InsetByCopy(
219 			-kMaxPreventHidingDist, -kMaxPreventHidingDist);
220 
221 		if (preventHideArea.Contains(where))
222 			return;
223 
224 		// cursor to bar distance above threshold
225 		if (!alwaysOnTop && autoRaise && isTopMost)
226 			RaiseDeskbar(false);
227 
228 		if (autoHide && !IsHidden())
229 			HideDeskbar(true);
230 	}
231 }
232 
233 
234 void
235 TBarView::MouseDown(BPoint where)
236 {
237 	where = ConvertToScreen(where);
238 
239 	if (Window()->Frame().Contains(where)) {
240 		Window()->Activate();
241 
242 		if ((modifiers() & (B_CONTROL_KEY | B_COMMAND_KEY | B_OPTION_KEY
243 					| B_SHIFT_KEY)) == (B_CONTROL_KEY | B_COMMAND_KEY)) {
244 			// The window key was pressed - enter dragging code
245 			DragRegion()->MouseDown(
246 				DragRegion()->DragRegion().LeftTop());
247 			return;
248 		}
249 	} else {
250 		// hide deskbar if required
251 		desk_settings* settings = ((TBarApp*)be_app)->Settings();
252 		bool alwaysOnTop = settings->alwaysOnTop;
253 		bool autoRaise = settings->autoRaise;
254 		bool autoHide = settings->autoHide;
255 		bool isTopMost = Window()->Feel() == B_FLOATING_ALL_WINDOW_FEEL;
256 
257 		if (!alwaysOnTop && autoRaise && isTopMost)
258 			RaiseDeskbar(false);
259 
260 		if (autoHide && !IsHidden())
261 			HideDeskbar(true);
262 	}
263 }
264 
265 
266 void
267 TBarView::PlaceBeMenu()
268 {
269 	// top or bottom, full
270 	if (!fVertical && fBarMenuBar) {
271 		fBarMenuBar->RemoveSelf();
272 		delete fBarMenuBar;
273 		fBarMenuBar = NULL;
274 	}
275 
276 	// top or bottom expando mode has Be menu built in for tracking
277 	// only for vertical mini or expanded
278 	// mini mode will have team menu added as part of BarMenuBar
279 	if (fVertical && !fBarMenuBar) {
280 		//	create the Be menu
281 		BRect mbarFrame(Bounds());
282 		mbarFrame.bottom = mbarFrame.top + kMenuBarHeight;
283 		fBarMenuBar = new TBarMenuBar(this, mbarFrame, "BarMenuBar");
284 		AddChild(fBarMenuBar);
285 	}
286 
287 	// if there isn't a bemenu at this point,
288 	// DB should be in top/bottom mode, else error
289 	if (!fBarMenuBar)
290 		return;
291 
292 	float width = sMinimumWindowWidth;
293 	BPoint loc(B_ORIGIN);
294 	BRect menuFrame(fBarMenuBar->Frame());
295 	if (fState == kFullState) {
296 		fBarMenuBar->RemoveTeamMenu();
297 		width = 8 + 16 + 8;
298 		loc = Bounds().LeftTop();
299 	} else if (fState == kExpandoState) {
300 		// shows apps below tray
301 		fBarMenuBar->RemoveTeamMenu();
302 		if (fVertical)
303 			width += 1;
304 		else
305 			width = floorf(width) / 2;
306 		loc = Bounds().LeftTop();
307 	} else {
308 		// mini mode, BeMenu next to team menu
309 		fBarMenuBar->AddTeamMenu();
310 	}
311 
312 	fBarMenuBar->SmartResize(width, menuFrame.Height());
313 	fBarMenuBar->MoveTo(loc);
314 }
315 
316 
317 void
318 TBarView::PlaceTray(bool, bool, BRect screenFrame)
319 {
320 	BPoint statusLoc;
321 	if (fState == kFullState) {
322 		fDragRegion->ResizeTo(fBarMenuBar->Frame().Width(), kMenuBarHeight);
323 		statusLoc.y = fBarMenuBar->Frame().bottom + 1;
324 		statusLoc.x = 0;
325 		fDragRegion->MoveTo(statusLoc);
326 
327 		if (!fReplicantTray->IsHidden())
328 			fReplicantTray->Hide();
329 
330 		return;
331 	}
332 
333 	if (fReplicantTray->IsHidden())
334 		fReplicantTray->Show();
335 
336 	if (fTrayLocation != 0) {
337 		fReplicantTray->SetMultiRow(fVertical);
338 		fReplicantTray->RealignReplicants();
339 		fDragRegion->ResizeToPreferred();
340 
341 		if (fVertical) {
342 			statusLoc.y = fBarMenuBar->Frame().bottom + 1;
343 			statusLoc.x = 0;
344 			if (Left() && Vertical())
345 				fReplicantTray->MoveTo(5, 2);
346 			else
347 				fReplicantTray->MoveTo(2, 2);
348 		} else {
349 			statusLoc.x = screenFrame.right - fDragRegion->Bounds().Width();
350 			statusLoc.y = -1;
351 		}
352 
353 		fDragRegion->MoveTo(statusLoc);
354 	}
355 }
356 
357 
358 void
359 TBarView::PlaceApplicationBar(BRect screenFrame)
360 {
361 	if (fExpando != NULL) {
362 		fExpando->RemoveSelf();
363 		delete fExpando;
364 		fExpando = NULL;
365 	}
366 	if (fState == kMiniState)
367 		return;
368 
369 	BRect expandoFrame(0, 0, 0, 0);
370 	if (fVertical) {
371 		// top left/right
372 		if (fTrayLocation != 0)
373 			expandoFrame.top = fDragRegion->Frame().bottom + 1;
374 		else
375 			expandoFrame.top = fBarMenuBar->Frame().bottom + 1;
376 
377 		expandoFrame.bottom = expandoFrame.top + 1;
378 		if (fState == kFullState)
379 			expandoFrame.right = fBarMenuBar->Frame().Width();
380 		else
381 			expandoFrame.right = sMinimumWindowWidth;
382 	} else {
383 		// top or bottom
384 		expandoFrame.top = 0;
385 		expandoFrame.bottom = kHModeHeight;
386 		if (fTrayLocation != 0)
387 			expandoFrame.right = fDragRegion->Frame().left - 1;
388 		else
389 			expandoFrame.right = screenFrame.Width();
390 	}
391 
392 	fExpando = new TExpandoMenuBar(this, expandoFrame, "ExpandoMenuBar",
393 		fVertical, fState != kFullState);
394 	AddChild(fExpando);
395 }
396 
397 
398 void
399 TBarView::GetPreferredWindowSize(BRect screenFrame, float* width, float* height)
400 {
401 	float windowHeight = 0;
402 	float windowWidth = sMinimumWindowWidth;
403 	bool calcHiddenSize = ((TBarApp*)be_app)->Settings()->autoHide
404 		&& IsHidden() && !DragRegion()->IsDragging();
405 
406 	if (!calcHiddenSize) {
407 		if (fState == kFullState) {
408 			windowHeight = screenFrame.bottom;
409 			windowWidth = fBarMenuBar->Frame().Width();
410 		} else if (fState == kExpandoState) {
411 			if (fVertical) {
412 				// top left or right
413 				windowHeight = fExpando->Frame().bottom;
414 			} else {
415 				// top or bottom, full
416 				fExpando->CheckItemSizes(0);
417 				windowHeight = kHModeHeight;
418 				windowWidth = screenFrame.Width();
419 			}
420 		} else {
421 			// four corners
422 			if (fTrayLocation != 0)
423 				windowHeight = fDragRegion->Frame().bottom;
424 			else
425 				windowHeight = fBarMenuBar->Frame().bottom;
426 		}
427 	} else {
428 		windowHeight = kHModeHiddenHeight;
429 
430 		if (fState == kExpandoState && !fVertical) {
431 			// top or bottom, full
432 			fExpando->CheckItemSizes(0);
433 			windowWidth = screenFrame.Width();
434 		} else
435 			windowWidth = kHModeHiddenHeight;
436 	}
437 
438 	*width = windowWidth;
439 	*height = windowHeight;
440 }
441 
442 
443 void
444 TBarView::SizeWindow(BRect screenFrame)
445 {
446 	float windowWidth, windowHeight;
447 	GetPreferredWindowSize(screenFrame, &windowWidth, &windowHeight);
448 	Window()->ResizeTo(windowWidth, windowHeight);
449 	if (fExpando)
450 		fExpando->CheckForSizeOverrun();
451 }
452 
453 
454 void
455 TBarView::PositionWindow(BRect screenFrame)
456 {
457 	float windowWidth, windowHeight;
458 	GetPreferredWindowSize(screenFrame, &windowWidth, &windowHeight);
459 
460 	BPoint moveLoc(0, 0);
461 	// right, expanded
462 	if (!fLeft && fVertical) {
463 		if (fState == kFullState)
464 			moveLoc.x = screenFrame.right - fBarMenuBar->Frame().Width();
465 		else
466 			moveLoc.x = screenFrame.right - windowWidth;
467 	}
468 
469 	// bottom, full or corners
470 	if (!fTop)
471 		moveLoc.y = screenFrame.bottom - windowHeight;
472 
473 	Window()->MoveTo(moveLoc);
474 }
475 
476 
477 void
478 TBarView::SaveSettings()
479 {
480 	desk_settings* settings = ((TBarApp*)be_app)->Settings();
481 
482 	settings->vertical = Vertical();
483 	settings->left = Left();
484 	settings->top = Top();
485 	settings->ampmMode = MilTime();
486 	settings->state = (uint32)State();
487 	settings->width = 0;
488 	settings->showTime = ShowingClock();
489 
490 	fReplicantTray->RememberClockSettings();
491 }
492 
493 
494 void
495 TBarView::UpdateEventMask()
496 {
497 	if (((TBarApp*)be_app)->Settings()->autoRaise
498 		|| ((TBarApp*)be_app)->Settings()->autoHide)
499 		SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
500 	else
501 		SetEventMask(0);
502 }
503 
504 
505 void
506 TBarView::UpdatePlacement()
507 {
508 	ChangeState(fState, fVertical, fLeft, fTop);
509 }
510 
511 
512 void
513 TBarView::ChangeState(int32 state, bool vertical, bool left, bool top)
514 {
515 	bool vertSwap = (fVertical != vertical);
516 	bool leftSwap = (fLeft != left);
517 	bool stateChanged = (fState != state);
518 
519 	fState = state;
520 	fVertical = vertical;
521 	fLeft = left;
522 	fTop = top;
523 
524 	// Send a message to the preferences window to let it know to enable
525 	// or disable preference items
526 	if (stateChanged || vertSwap)
527 		be_app->PostMessage(kStateChanged);
528 
529 	BRect screenFrame = (BScreen(Window())).Frame();
530 
531 	PlaceBeMenu();
532 	PlaceTray(vertSwap, leftSwap, screenFrame);
533 
534 	// Keep track of which apps are expanded
535 	SaveExpandedItems();
536 
537 	PlaceApplicationBar(screenFrame);
538 	SizeWindow(screenFrame);
539 	PositionWindow(screenFrame);
540 	Window()->UpdateIfNeeded();
541 
542 	// Re-expand apps
543 	ExpandItems();
544 	Invalidate();
545 }
546 
547 
548 void
549 TBarView::SaveExpandedItems()
550 {
551 	if (fExpando == NULL || fExpando->CountItems() <= 0)
552 		return;
553 
554 	// Get a list of the signatures of expanded apps. Can't use
555 	// team_id because there can be more than one team per application
556 	for (int32 i = 0; i < fExpando->CountItems(); i++) {
557 		TTeamMenuItem* teamItem
558 			= dynamic_cast<TTeamMenuItem*>(fExpando->ItemAt(i));
559 
560 		if (teamItem != NULL && teamItem->IsExpanded())
561 			AddExpandedItem(teamItem->Signature());
562 	}
563 }
564 
565 
566 void
567 TBarView::RemoveExpandedItems()
568 {
569 	while (!fExpandedItems.IsEmpty())
570 		delete static_cast<BString*>(fExpandedItems.RemoveItem((int32)0));
571 	fExpandedItems.MakeEmpty();
572 }
573 
574 
575 void
576 TBarView::ExpandItems()
577 {
578 	if (fExpando == NULL || !fVertical || !Expando()
579 		|| !static_cast<TBarApp*>(be_app)->Settings()->superExpando
580 		|| fExpandedItems.CountItems() <= 0)
581 		return;
582 
583 	// Start at the 'bottom' of the list working up.
584 	// Prevents being thrown off by expanding items.
585 	for (int32 i = fExpando->CountItems() - 1; i >= 0; i--) {
586 		TTeamMenuItem* teamItem
587 			= dynamic_cast<TTeamMenuItem*>(fExpando->ItemAt(i));
588 
589 		if (teamItem != NULL) {
590 			// Start at the 'bottom' of the fExpandedItems list working up
591 			// matching the order of the fExpando list in the outer loop.
592 			for (int32 j = fExpandedItems.CountItems() - 1; j >= 0; j--) {
593 				BString* itemSig =
594 					static_cast<BString*>(fExpandedItems.ItemAt(j));
595 
596 				if (itemSig->Compare(teamItem->Signature()) == 0) {
597 					// Found it, expand the item and delete signature from
598 					// the list so that we don't consider it for later items.
599 					teamItem->ToggleExpandState(false);
600 					fExpandedItems.RemoveItem(j);
601 					delete itemSig;
602 					break;
603 				}
604 			}
605 		}
606 	}
607 
608 	// Clean up the expanded items list
609 	RemoveExpandedItems();
610 
611 	fExpando->SizeWindow();
612 }
613 
614 
615 void
616 TBarView::AddExpandedItem(const char* signature)
617 {
618 	bool shouldAdd = true;
619 
620 	for (int32 i = 0; i < fExpandedItems.CountItems(); i++) {
621 		BString *itemSig = static_cast<BString*>(fExpandedItems.ItemAt(i));
622 		if (itemSig->Compare(signature) == 0) {
623 			// already in the list, don't add the signature
624 			shouldAdd = false;
625 			break;
626 		}
627 	}
628 
629 	if (shouldAdd)
630 		fExpandedItems.AddItem(static_cast<void*>(new BString(signature)));
631 }
632 
633 
634 void
635 TBarView::RaiseDeskbar(bool raise)
636 {
637 	if (raise)
638 		Window()->SetFeel(B_FLOATING_ALL_WINDOW_FEEL);
639 	else
640 		Window()->SetFeel(B_NORMAL_WINDOW_FEEL);
641 }
642 
643 
644 void
645 TBarView::HideDeskbar(bool hide)
646 {
647 	BScreen screen(Window());
648 	BRect screenFrame = screen.Frame();
649 
650 	if (hide) {
651 		Hide();
652 		PositionWindow(screenFrame);
653 		SizeWindow(screenFrame);
654 	} else {
655 		Show();
656 		SizeWindow(screenFrame);
657 		PositionWindow(screenFrame);
658 	}
659 }
660 
661 
662 // window placement functions
663 
664 bool
665 TBarView::Vertical() const
666 {
667 	return fVertical;
668 }
669 
670 
671 bool
672 TBarView::Left() const
673 {
674 	return fLeft;
675 }
676 
677 
678 bool
679 TBarView::AcrossTop() const
680 {
681 	return fTop && !fVertical;
682 }
683 
684 
685 bool
686 TBarView::AcrossBottom() const
687 {
688 	return !fTop && !fVertical;
689 }
690 
691 
692 bool
693 TBarView::Expando() const
694 {
695 	return fState == kExpandoState;
696 }
697 
698 
699 bool
700 TBarView::Top() const
701 {
702 	return fTop;
703 }
704 
705 
706 int32
707 TBarView::State() const
708 {
709 	return fState;
710 }
711 
712 
713 // optional functionality functions
714 
715 bool
716 TBarView::MilTime() const
717 {
718 	return fShowInterval;
719 }
720 
721 
722 void
723 TBarView::ShowClock(bool on)
724 {
725 	fShowClock = on;
726 }
727 
728 
729 bool
730 TBarView::ShowingClock() const
731 {
732 	return fShowClock;
733 }
734 
735 
736 //	#pragma mark - Drag and Drop
737 
738 
739 void
740 TBarView::CacheDragData(const BMessage* incoming)
741 {
742 	if (!incoming)
743 		return;
744 
745 	if (Dragging() && SpringLoadedFolderCompareMessages(incoming, fDragMessage))
746 		return;
747 
748 	// disposes then fills cached drag message and
749 	// mimetypes list
750 	SpringLoadedFolderCacheDragData(incoming, &fDragMessage, &fCachedTypesList);
751 }
752 
753 
754 static void
755 init_tracking_hook(BMenuItem* item,
756 	bool (*hookFunction)(BMenu*, void*), void* state)
757 {
758 	if (!item)
759 		return;
760 
761 	BMenu* windowMenu = item->Submenu();
762 	if (windowMenu) {
763 		// have a menu, set the tracking hook
764 		windowMenu->SetTrackingHook(hookFunction, state);
765 	}
766 }
767 
768 
769 status_t
770 TBarView::DragStart()
771 {
772 	if (!Dragging())
773 		return B_OK;
774 
775 	BPoint loc;
776 	uint32 buttons;
777 	GetMouse(&loc, &buttons);
778 
779 	if (fExpando && fExpando->Frame().Contains(loc)) {
780 		ConvertToScreen(&loc);
781 		BPoint expandoLocation = fExpando->ConvertFromScreen(loc);
782 		TTeamMenuItem* item = fExpando->TeamItemAtPoint(expandoLocation);
783 
784 		if (fLastDragItem)
785 			init_tracking_hook(fLastDragItem, NULL, NULL);
786 
787 		if (item) {
788 			if (item == fLastDragItem)
789 				return B_OK;
790 
791 			fLastDragItem = item;
792 		}
793 	}
794 
795 	return B_OK;
796 }
797 
798 
799 bool
800 TBarView::MenuTrackingHook(BMenu* menu, void* castToThis)
801 {
802 	// return true if the menu should go away
803 	TrackingHookData* data = static_cast<TrackingHookData*>(castToThis);
804 	if (!data)
805 		return false;
806 
807 	TBarView* barview = dynamic_cast<TBarView*>(data->fTarget.Target(NULL));
808 	if (!barview || !menu->LockLooper())
809 		return false;
810 
811 	uint32 buttons;
812 	BPoint location;
813 	menu->GetMouse(&location, &buttons);
814 
815 	bool endMenu = true;
816 	BRect frame(menu->Bounds());
817 	frame.InsetBy(-kMenuTrackMargin, -kMenuTrackMargin);
818 
819 	if (frame.Contains(location)) {
820 		// if current loc is still in the menu
821 		// keep tracking
822 		endMenu = false;
823 	} else {
824 		// see if the mouse is in the team/be menu item
825 		menu->ConvertToScreen(&location);
826 		if (barview->LockLooper()) {
827 			TExpandoMenuBar* expando = barview->ExpandoMenuBar();
828 			TBeMenu* bemenu
829 				= (dynamic_cast<TBarWindow*>(barview->Window()))->BeMenu();
830 
831 			if (bemenu && bemenu->LockLooper()) {
832 				bemenu->ConvertFromScreen(&location);
833 				if (bemenu->Frame().Contains(location))
834 					endMenu = false;
835 
836 				bemenu->UnlockLooper();
837 			}
838 
839 			if (endMenu && expando) {
840 				expando->ConvertFromScreen(&location);
841 				BMenuItem* item = expando->TeamItemAtPoint(location);
842 				if (item)
843 					endMenu = false;
844 			}
845 			barview->UnlockLooper();
846 		}
847 	}
848 
849 	menu->UnlockLooper();
850 	return endMenu;
851 }
852 
853 
854 // used by WindowMenu and TeamMenu to
855 // set the tracking hook for dragging
856 TrackingHookData*
857 TBarView::GetTrackingHookData()
858 {
859 	// all tracking hook data is
860 	// preset in AttachedToWindow
861 	// data should never change
862 	return &fTrackingHookData;
863 }
864 
865 
866 void
867 TBarView::DragStop(bool full)
868 {
869 	if (!Dragging())
870 		return;
871 
872 	if (fExpando) {
873 		if (fLastDragItem) {
874 			init_tracking_hook(fLastDragItem, NULL, NULL);
875 			fLastDragItem = NULL;
876 		}
877 	}
878 
879 	if (full) {
880 		delete fDragMessage;
881 		fDragMessage = NULL;
882 
883 		delete fCachedTypesList;
884 		fCachedTypesList = NULL;
885 	}
886 }
887 
888 
889 bool
890 TBarView::AppCanHandleTypes(const char* signature)
891 {
892 	// used for filtering apps/teams in the ExpandoMenuBar and TeamMenu
893 
894 	if (modifiers() & B_CONTROL_KEY) {
895 		// control key forces acceptance, just like drag&drop on icons
896 		return true;
897 	}
898 
899 	if (!signature || strlen(signature) == 0
900 		|| !fCachedTypesList || fCachedTypesList->CountItems() == 0)
901 		return false;
902 
903 	if (strcmp(signature, kTrackerSignature) == 0) {
904 		// tracker should support all types
905 		// and should pass them on to the appropriate application
906 		return true;
907 	}
908 
909 	entry_ref hintref;
910 	BMimeType appmime(signature);
911 	if (appmime.GetAppHint(&hintref) != B_OK)
912 		return false;
913 
914 	// an app was found, now see if it supports any of
915 	// the refs in the message
916 	BFile file(&hintref, O_RDONLY);
917 	BAppFileInfo fileinfo(&file);
918 
919 	// scan the cached mimetype list and see if this app
920 	// supports anything in the list
921 	// only one item needs to match in the list of refs
922 
923 	int32 count = fCachedTypesList->CountItems();
924 	for (int32 i = 0 ; i < count ; i++) {
925 		if (fileinfo.IsSupportedType(fCachedTypesList->ItemAt(i)->String()))
926 			return true;
927 	}
928 
929 	return false;
930 }
931 
932 
933 void
934 TBarView::SetDragOverride(bool on)
935 {
936 	fRefsRcvdOnly = on;
937 }
938 
939 
940 bool
941 TBarView::DragOverride()
942 {
943 	return fRefsRcvdOnly;
944 }
945 
946 
947 status_t
948 TBarView::SendDragMessage(const char* signature, entry_ref* ref)
949 {
950 	status_t err = B_ERROR;
951 	if (fDragMessage) {
952 		if (fRefsRcvdOnly) {
953 			// current message sent to apps is only B_REFS_RECEIVED
954 			fDragMessage->what = B_REFS_RECEIVED;
955 		}
956 
957 		BRoster roster;
958 		if (signature && strlen(signature) > 0 && roster.IsRunning(signature)) {
959 			BMessenger mess(signature);
960 			// drag message is still owned by DB, copy is sent
961 			// can toss it after send
962 			err = mess.SendMessage(fDragMessage);
963 		} else if (ref) {
964 			FSLaunchItem((const entry_ref*)ref, (const BMessage*)fDragMessage,
965 				true, true);
966 		} else if (signature && strlen(signature) > 0) {
967 			roster.Launch(signature, fDragMessage);
968 		}
969 	}
970 	return err;
971 }
972 
973 
974 bool
975 TBarView::InvokeItem(const char* signature)
976 {
977 	// sent from TeamMenuItem
978 	if (Dragging() && AppCanHandleTypes(signature)) {
979 		SendDragMessage(signature);
980 		// invoking okay to toss memory
981 		DragStop(true);
982 		return true;
983 	}
984 
985 	return false;
986 }
987 
988 
989 void
990 TBarView::HandleBeMenu(BMessage* messagewithdestination)
991 {
992 	if (!Dragging())
993 		return;
994 
995 	// in mini-mode
996 	if (Vertical() && !Expando()) {
997 		// if drop is in the team menu, bail
998 		if (fBarMenuBar->CountItems() >= 2) {
999 			uint32 buttons;
1000 			BPoint location;
1001 			GetMouse(&location, &buttons);
1002 			if (fBarMenuBar->ItemAt(1)->Frame().Contains(location))
1003 				return;
1004 		}
1005 	}
1006 
1007 	if (messagewithdestination) {
1008 		entry_ref ref;
1009 		if (messagewithdestination->FindRef("refs", &ref) == B_OK) {
1010 			BEntry entry(&ref, true);
1011 			if (entry.IsDirectory()) {
1012 				// if the ref received (should only be 1) is a directory
1013 				// then add the drag refs to the directory
1014 				AddRefsToBeMenu(DragMessage(), &ref);
1015 			} else
1016 				SendDragMessage(NULL, &ref);
1017 		}
1018 	} else {
1019 		// adds drag refs to top level in be menu
1020 		AddRefsToBeMenu(DragMessage(), NULL);
1021 	}
1022 
1023 	// clean up drag message and types list
1024 	DragStop(true);
1025 }
1026 
1027 
1028 //	#pragma mark - Add-ons
1029 
1030 
1031 // shelf is ignored for now,
1032 // it exists in anticipation of having other 'shelves' for
1033 // storing items
1034 
1035 status_t
1036 TBarView::ItemInfo(int32 id, const char** name, DeskbarShelf* shelf)
1037 {
1038 	*shelf = B_DESKBAR_TRAY;
1039 	return fReplicantTray->ItemInfo(id, name);
1040 }
1041 
1042 
1043 status_t
1044 TBarView::ItemInfo(const char* name, int32* id, DeskbarShelf* shelf)
1045 {
1046 	*shelf = B_DESKBAR_TRAY;
1047 	return fReplicantTray->ItemInfo(name, id);
1048 }
1049 
1050 
1051 bool
1052 TBarView::ItemExists(int32 id, DeskbarShelf)
1053 {
1054 	return fReplicantTray->IconExists(id);
1055 }
1056 
1057 
1058 bool
1059 TBarView::ItemExists(const char* name, DeskbarShelf)
1060 {
1061 	return fReplicantTray->IconExists(name);
1062 }
1063 
1064 
1065 int32
1066 TBarView::CountItems(DeskbarShelf)
1067 {
1068 	return fReplicantTray->IconCount();
1069 }
1070 
1071 
1072 status_t
1073 TBarView::AddItem(BMessage* item, DeskbarShelf, int32* id)
1074 {
1075 	return fReplicantTray->AddIcon(item, id);
1076 }
1077 
1078 
1079 status_t
1080 TBarView::AddItem(BEntry* entry, DeskbarShelf, int32* id)
1081 {
1082 	return fReplicantTray->LoadAddOn(entry, id);
1083 }
1084 
1085 
1086 void
1087 TBarView::RemoveItem(int32 id)
1088 {
1089 	fReplicantTray->RemoveIcon(id);
1090 }
1091 
1092 
1093 void
1094 TBarView::RemoveItem(const char* name, DeskbarShelf)
1095 {
1096 	fReplicantTray->RemoveIcon(name);
1097 }
1098 
1099 
1100 BRect
1101 TBarView::OffsetIconFrame(BRect rect) const
1102 {
1103 	BRect frame(Frame());
1104 	frame.left += fDragRegion->Frame().left + fReplicantTray->Frame().left
1105 		+ rect.left;
1106 	frame.top += fDragRegion->Frame().top + fReplicantTray->Frame().top
1107 		+ rect.top;
1108 
1109 	frame.right = frame.left + rect.Width();
1110 	frame.bottom = frame.top + rect.Height();
1111 
1112 	return frame;
1113 }
1114 
1115 
1116 BRect
1117 TBarView::IconFrame(int32 id) const
1118 {
1119 	return OffsetIconFrame(fReplicantTray->IconFrame(id));
1120 }
1121 
1122 
1123 BRect
1124 TBarView::IconFrame(const char* name) const
1125 {
1126 	return OffsetIconFrame(fReplicantTray->IconFrame(name));
1127 }
1128 
1129