xref: /haiku/src/apps/deskbar/BarView.cpp (revision cb29eafe2586fdb2d7685afa69fdab5d88a8b576)
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 			TBarWindow* window = dynamic_cast<TBarWindow*>(Window());
737 			if (window != NULL)
738 				window->SetSizeLimits();
739 
740 			fReplicantTray->fTime->SetOrientation(fVertical);
741 			if (fExpandoMenuBar != NULL) {
742 				if (fVertical) {
743 					fInlineScrollView->SetOrientation(B_VERTICAL);
744 					fExpandoMenuBar->SetMenuLayout(B_ITEMS_IN_COLUMN);
745 					fExpandoMenuBar->StartMonitoringWindows();
746 				} else {
747 					fInlineScrollView->SetOrientation(B_HORIZONTAL);
748 					fExpandoMenuBar->SetMenuLayout(B_ITEMS_IN_ROW);
749 					fExpandoMenuBar->StopMonitoringWindows();
750 				}
751 			}
752 		}
753 	}
754 
755 	PlaceDeskbarMenu();
756 	PlaceTray(vertSwap, leftSwap);
757 	PlaceApplicationBar();
758 }
759 
760 
761 void
762 TBarView::RaiseDeskbar(bool raise)
763 {
764 	if (raise)
765 		Window()->SetFeel(B_FLOATING_ALL_WINDOW_FEEL);
766 	else
767 		Window()->SetFeel(B_NORMAL_WINDOW_FEEL);
768 }
769 
770 
771 void
772 TBarView::HideDeskbar(bool hide)
773 {
774 	BRect screenFrame = (BScreen(Window())).Frame();
775 
776 	if (hide) {
777 		Hide();
778 		PositionWindow(screenFrame);
779 		SizeWindow(screenFrame);
780 	} else {
781 		Show();
782 		SizeWindow(screenFrame);
783 		PositionWindow(screenFrame);
784 	}
785 }
786 
787 
788 //	#pragma mark - Drag and Drop
789 
790 
791 void
792 TBarView::CacheDragData(const BMessage* incoming)
793 {
794 	if (!incoming)
795 		return;
796 
797 	if (Dragging() && SpringLoadedFolderCompareMessages(incoming, fDragMessage))
798 		return;
799 
800 	// disposes then fills cached drag message and
801 	// mimetypes list
802 	SpringLoadedFolderCacheDragData(incoming, &fDragMessage, &fCachedTypesList);
803 }
804 
805 
806 static void
807 init_tracking_hook(BMenuItem* item,
808 	bool (*hookFunction)(BMenu*, void*), void* state)
809 {
810 	if (!item)
811 		return;
812 
813 	BMenu* windowMenu = item->Submenu();
814 	if (windowMenu) {
815 		// have a menu, set the tracking hook
816 		windowMenu->SetTrackingHook(hookFunction, state);
817 	}
818 }
819 
820 
821 status_t
822 TBarView::DragStart()
823 {
824 	if (!Dragging())
825 		return B_OK;
826 
827 	BPoint loc;
828 	uint32 buttons;
829 	GetMouse(&loc, &buttons);
830 
831 	if (fExpandoMenuBar != NULL && fExpandoMenuBar->Frame().Contains(loc)) {
832 		ConvertToScreen(&loc);
833 		BPoint expandoLocation = fExpandoMenuBar->ConvertFromScreen(loc);
834 		TTeamMenuItem* item = fExpandoMenuBar->TeamItemAtPoint(expandoLocation);
835 
836 		if (fLastDragItem)
837 			init_tracking_hook(fLastDragItem, NULL, NULL);
838 
839 		if (item != NULL) {
840 			if (item == fLastDragItem)
841 				return B_OK;
842 
843 			fLastDragItem = item;
844 		}
845 	}
846 
847 	return B_OK;
848 }
849 
850 
851 bool
852 TBarView::MenuTrackingHook(BMenu* menu, void* castToThis)
853 {
854 	// return true if the menu should go away
855 	TrackingHookData* data = static_cast<TrackingHookData*>(castToThis);
856 	if (!data)
857 		return false;
858 
859 	TBarView* barview = dynamic_cast<TBarView*>(data->fTarget.Target(NULL));
860 	if (!barview || !menu->LockLooper())
861 		return false;
862 
863 	uint32 buttons;
864 	BPoint location;
865 	menu->GetMouse(&location, &buttons);
866 
867 	bool endMenu = true;
868 	BRect frame(menu->Bounds());
869 	frame.InsetBy(-kMenuTrackMargin, -kMenuTrackMargin);
870 
871 	if (frame.Contains(location)) {
872 		// if current loc is still in the menu
873 		// keep tracking
874 		endMenu = false;
875 	} else {
876 		// see if the mouse is in the team/deskbar menu item
877 		menu->ConvertToScreen(&location);
878 		if (barview->LockLooper()) {
879 			TExpandoMenuBar* expando = barview->ExpandoMenuBar();
880 			TDeskbarMenu* bemenu
881 				= (dynamic_cast<TBarWindow*>(barview->Window()))->DeskbarMenu();
882 
883 			if (bemenu && bemenu->LockLooper()) {
884 				bemenu->ConvertFromScreen(&location);
885 				if (bemenu->Frame().Contains(location))
886 					endMenu = false;
887 
888 				bemenu->UnlockLooper();
889 			}
890 
891 			if (endMenu && expando) {
892 				expando->ConvertFromScreen(&location);
893 				BMenuItem* item = expando->TeamItemAtPoint(location);
894 				if (item)
895 					endMenu = false;
896 			}
897 			barview->UnlockLooper();
898 		}
899 	}
900 
901 	menu->UnlockLooper();
902 	return endMenu;
903 }
904 
905 
906 // used by WindowMenu and TeamMenu to
907 // set the tracking hook for dragging
908 TrackingHookData*
909 TBarView::GetTrackingHookData()
910 {
911 	// all tracking hook data is
912 	// preset in AttachedToWindow
913 	// data should never change
914 	return &fTrackingHookData;
915 }
916 
917 
918 void
919 TBarView::DragStop(bool full)
920 {
921 	if (!Dragging())
922 		return;
923 
924 	if (fExpandoMenuBar != NULL) {
925 		if (fLastDragItem != NULL) {
926 			init_tracking_hook(fLastDragItem, NULL, NULL);
927 			fLastDragItem = NULL;
928 		}
929 	}
930 
931 	if (full) {
932 		delete fDragMessage;
933 		fDragMessage = NULL;
934 
935 		delete fCachedTypesList;
936 		fCachedTypesList = NULL;
937 	}
938 }
939 
940 
941 bool
942 TBarView::AppCanHandleTypes(const char* signature)
943 {
944 	// used for filtering apps/teams in the ExpandoMenuBar and TeamMenu
945 
946 	if (modifiers() & B_CONTROL_KEY) {
947 		// control key forces acceptance, just like drag&drop on icons
948 		return true;
949 	}
950 
951 	if (!signature || strlen(signature) == 0
952 		|| !fCachedTypesList || fCachedTypesList->CountItems() == 0)
953 		return false;
954 
955 	if (strcasecmp(signature, kTrackerSignature) == 0) {
956 		// tracker should support all types
957 		// and should pass them on to the appropriate application
958 		return true;
959 	}
960 
961 	entry_ref hintref;
962 	BMimeType appmime(signature);
963 	if (appmime.GetAppHint(&hintref) != B_OK)
964 		return false;
965 
966 	// an app was found, now see if it supports any of
967 	// the refs in the message
968 	BFile file(&hintref, O_RDONLY);
969 	BAppFileInfo fileinfo(&file);
970 
971 	// scan the cached mimetype list and see if this app
972 	// supports anything in the list
973 	// only one item needs to match in the list of refs
974 
975 	int32 count = fCachedTypesList->CountItems();
976 	for (int32 i = 0 ; i < count ; i++) {
977 		if (fileinfo.IsSupportedType(fCachedTypesList->ItemAt(i)->String()))
978 			return true;
979 	}
980 
981 	return false;
982 }
983 
984 
985 void
986 TBarView::SetDragOverride(bool on)
987 {
988 	fRefsRcvdOnly = on;
989 }
990 
991 
992 bool
993 TBarView::DragOverride()
994 {
995 	return fRefsRcvdOnly;
996 }
997 
998 
999 status_t
1000 TBarView::SendDragMessage(const char* signature, entry_ref* ref)
1001 {
1002 	status_t err = B_ERROR;
1003 	if (fDragMessage != NULL) {
1004 		if (fRefsRcvdOnly) {
1005 			// current message sent to apps is only B_REFS_RECEIVED
1006 			fDragMessage->what = B_REFS_RECEIVED;
1007 		}
1008 
1009 		BRoster roster;
1010 		if (signature != NULL && *signature != '\0'
1011 			&& roster.IsRunning(signature)) {
1012 			BMessenger messenger(signature);
1013 			// drag message is still owned by DB, copy is sent
1014 			// can toss it after send
1015 			err = messenger.SendMessage(fDragMessage);
1016 		} else if (ref != NULL) {
1017 			FSLaunchItem((const entry_ref*)ref, (const BMessage*)fDragMessage,
1018 				true, true);
1019 		} else if (signature != NULL && *signature != '\0')
1020 			roster.Launch(signature, fDragMessage);
1021 	}
1022 
1023 	return err;
1024 }
1025 
1026 
1027 bool
1028 TBarView::InvokeItem(const char* signature)
1029 {
1030 	// sent from TeamMenuItem
1031 	if (Dragging() && AppCanHandleTypes(signature)) {
1032 		SendDragMessage(signature);
1033 		// invoking okay to toss memory
1034 		DragStop(true);
1035 		return true;
1036 	}
1037 
1038 	return false;
1039 }
1040 
1041 
1042 void
1043 TBarView::HandleDeskbarMenu(BMessage* messagewithdestination)
1044 {
1045 	if (!Dragging())
1046 		return;
1047 
1048 	// in mini-mode
1049 	if (fVertical && fState != kExpandoState) {
1050 		// if drop is in the team menu, bail
1051 		if (fBarMenuBar->CountItems() >= 2) {
1052 			uint32 buttons;
1053 			BPoint location;
1054 			GetMouse(&location, &buttons);
1055 			if (fBarMenuBar->ItemAt(1)->Frame().Contains(location))
1056 				return;
1057 		}
1058 	}
1059 
1060 	if (messagewithdestination) {
1061 		entry_ref ref;
1062 		if (messagewithdestination->FindRef("refs", &ref) == B_OK) {
1063 			BEntry entry(&ref, true);
1064 			if (entry.IsDirectory()) {
1065 				// if the ref received (should only be 1) is a directory
1066 				// then add the drag refs to the directory
1067 				AddRefsToDeskbarMenu(DragMessage(), &ref);
1068 			} else
1069 				SendDragMessage(NULL, &ref);
1070 		}
1071 	} else {
1072 		// adds drag refs to top level in deskbar menu
1073 		AddRefsToDeskbarMenu(DragMessage(), NULL);
1074 	}
1075 
1076 	// clean up drag message and types list
1077 	DragStop(true);
1078 }
1079 
1080 
1081 //	#pragma mark - Add-ons
1082 
1083 
1084 // shelf is ignored for now,
1085 // it exists in anticipation of having other 'shelves' for
1086 // storing items
1087 
1088 status_t
1089 TBarView::ItemInfo(int32 id, const char** name, DeskbarShelf* shelf)
1090 {
1091 	*shelf = B_DESKBAR_TRAY;
1092 	return fReplicantTray->ItemInfo(id, name);
1093 }
1094 
1095 
1096 status_t
1097 TBarView::ItemInfo(const char* name, int32* id, DeskbarShelf* shelf)
1098 {
1099 	*shelf = B_DESKBAR_TRAY;
1100 	return fReplicantTray->ItemInfo(name, id);
1101 }
1102 
1103 
1104 bool
1105 TBarView::ItemExists(int32 id, DeskbarShelf)
1106 {
1107 	return fReplicantTray->IconExists(id);
1108 }
1109 
1110 
1111 bool
1112 TBarView::ItemExists(const char* name, DeskbarShelf)
1113 {
1114 	return fReplicantTray->IconExists(name);
1115 }
1116 
1117 
1118 int32
1119 TBarView::CountItems(DeskbarShelf)
1120 {
1121 	return fReplicantTray->ReplicantCount();
1122 }
1123 
1124 
1125 BSize
1126 TBarView::MaxItemSize(DeskbarShelf shelf)
1127 {
1128 	return BSize(fReplicantTray->MaxReplicantWidth(),
1129 		fReplicantTray->MaxReplicantHeight());
1130 }
1131 
1132 
1133 status_t
1134 TBarView::AddItem(BMessage* item, DeskbarShelf, int32* id)
1135 {
1136 	return fReplicantTray->AddIcon(item, id);
1137 }
1138 
1139 
1140 status_t
1141 TBarView::AddItem(BEntry* entry, DeskbarShelf, int32* id)
1142 {
1143 	return fReplicantTray->LoadAddOn(entry, id);
1144 }
1145 
1146 
1147 void
1148 TBarView::RemoveItem(int32 id)
1149 {
1150 	fReplicantTray->RemoveIcon(id);
1151 }
1152 
1153 
1154 void
1155 TBarView::RemoveItem(const char* name, DeskbarShelf)
1156 {
1157 	fReplicantTray->RemoveIcon(name);
1158 }
1159 
1160 
1161 BRect
1162 TBarView::OffsetIconFrame(BRect rect) const
1163 {
1164 	BRect frame(Frame());
1165 
1166 	frame.left += fDragRegion->Frame().left + fReplicantTray->Frame().left
1167 		+ rect.left;
1168 	frame.top += fDragRegion->Frame().top + fReplicantTray->Frame().top
1169 		+ rect.top;
1170 
1171 	frame.right = frame.left + rect.Width();
1172 	frame.bottom = frame.top + rect.Height();
1173 
1174 	return frame;
1175 }
1176 
1177 
1178 BRect
1179 TBarView::IconFrame(int32 id) const
1180 {
1181 	return OffsetIconFrame(fReplicantTray->IconFrame(id));
1182 }
1183 
1184 
1185 BRect
1186 TBarView::IconFrame(const char* name) const
1187 {
1188 	return OffsetIconFrame(fReplicantTray->IconFrame(name));
1189 }
1190