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