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