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