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