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