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