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