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