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