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