xref: /haiku/src/apps/deskbar/BarWindow.cpp (revision ff1ee776fe00c4b29992cd25ef94463302ba6a92)
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 "BarWindow.h"
38 
39 #include <stdio.h>
40 
41 #include <Application.h>
42 #include <AutoDeleter.h>
43 #include <Catalog.h>
44 #include <Directory.h>
45 #include <FindDirectory.h>
46 #include <Path.h>
47 #include <Debug.h>
48 #include <File.h>
49 #include <Locale.h>
50 #include <MenuItem.h>
51 #include <MessageFilter.h>
52 #include <MessagePrivate.h>
53 #include <Screen.h>
54 
55 #include <DeskbarPrivate.h>
56 #include <tracker_private.h>
57 
58 #include "BarApp.h"
59 #include "BarMenuBar.h"
60 #include "BarView.h"
61 #include "DeskbarUtils.h"
62 #include "DeskbarMenu.h"
63 #include "ExpandoMenuBar.h"
64 #include "StatusView.h"
65 
66 
67 #undef B_TRANSLATION_CONTEXT
68 #define B_TRANSLATION_CONTEXT "MainWindow"
69 
70 
71 // This is a bit of a hack to be able to call BMenuBar::StartMenuBar(), which
72 // is private. Don't do this at home!
73 class TStartableMenuBar : public BMenuBar {
74 public:
75 	TStartableMenuBar();
76 	void StartMenuBar(int32 menuIndex, bool sticky = true, bool showMenu = false,
77 		BRect* special_rect = NULL) { BMenuBar::StartMenuBar(menuIndex, sticky, showMenu,
78 			special_rect); }
79 };
80 
81 
82 TDeskbarMenu* TBarWindow::sDeskbarMenu = NULL;
83 
84 
85 TBarWindow::TBarWindow()
86 	:
87 	BWindow(BRect(-1000.0f, -1000.0f, -1000.0f, -1000.0f),
88 		B_TRANSLATE_SYSTEM_NAME("Deskbar"), B_BORDERED_WINDOW,
89 		B_WILL_ACCEPT_FIRST_CLICK | B_NOT_ZOOMABLE | B_NOT_CLOSABLE
90 			| B_NOT_MINIMIZABLE | B_NOT_MOVABLE | B_NOT_V_RESIZABLE
91 			| B_AVOID_FRONT | B_ASYNCHRONOUS_CONTROLS,
92 		B_ALL_WORKSPACES),
93 	fShowingMenu(false)
94 {
95 	desk_settings* settings = ((TBarApp*)be_app)->Settings();
96 	if (settings->alwaysOnTop)
97 		SetFeel(B_FLOATING_ALL_WINDOW_FEEL);
98 
99 	fBarView = new TBarView(Bounds(), settings->vertical, settings->left,
100 		settings->top, settings->state, settings->width);
101 	AddChild(fBarView);
102 
103 	RemoveShortcut('H', B_COMMAND_KEY | B_CONTROL_KEY);
104 	AddShortcut('F', B_COMMAND_KEY, new BMessage(kFindButton));
105 
106 	SetSizeLimits();
107 }
108 
109 
110 void
111 TBarWindow::MenusBeginning()
112 {
113 	BPath path;
114 	entry_ref ref;
115 	BEntry entry;
116 
117 	if (GetDeskbarSettingsDirectory(path) == B_OK
118 		&& path.Append(kDeskbarMenuEntriesFileName) == B_OK
119 		&& entry.SetTo(path.Path(), true) == B_OK
120 		&& entry.Exists()
121 		&& entry.GetRef(&ref) == B_OK) {
122 		sDeskbarMenu->SetNavDir(&ref);
123 	} else if (GetDeskbarDataDirectory(path) == B_OK
124 		&& path.Append(kDeskbarMenuEntriesFileName) == B_OK
125 		&& entry.SetTo(path.Path(), true) == B_OK
126 		&& entry.Exists()
127 		&& entry.GetRef(&ref) == B_OK) {
128 		sDeskbarMenu->SetNavDir(&ref);
129 	} else {
130 		//	this really should never happen
131 		TRESPASS();
132 		return;
133 	}
134 
135 	sDeskbarMenu->ResetTargets();
136 
137 	fShowingMenu = true;
138 	BWindow::MenusBeginning();
139 }
140 
141 
142 void
143 TBarWindow::MenusEnded()
144 {
145 	fShowingMenu = false;
146 	BWindow::MenusEnded();
147 
148 	if (sDeskbarMenu->LockLooper()) {
149 		sDeskbarMenu->ForceRebuild();
150 		sDeskbarMenu->UnlockLooper();
151 	}
152 }
153 
154 
155 void
156 TBarWindow::MessageReceived(BMessage* message)
157 {
158 	switch (message->what) {
159 		case kFindButton:
160 		{
161 			BMessenger tracker(kTrackerSignature);
162 			tracker.SendMessage(message);
163 			break;
164 		}
165 
166 		case kMsgLocation:
167 			GetLocation(message);
168 			break;
169 
170 		case kMsgSetLocation:
171 			SetLocation(message);
172 			break;
173 
174 		case kMsgIsExpanded:
175 			IsExpanded(message);
176 			break;
177 
178 		case kMsgExpand:
179 			Expand(message);
180 			break;
181 
182 		case kMsgGetItemInfo:
183 			ItemInfo(message);
184 			break;
185 
186 		case kMsgHasItem:
187 			ItemExists(message);
188 			break;
189 
190 		case kMsgCountItems:
191 			CountItems(message);
192 			break;
193 
194 		case kMsgMaxItemSize:
195 			MaxItemSize(message);
196 			break;
197 
198 		case kMsgAddAddOn:
199 		case kMsgAddView:
200 			AddItem(message);
201 			break;
202 
203 		case kMsgRemoveItem:
204 			RemoveItem(message);
205 			break;
206 
207 		case 'iloc':
208 			GetIconFrame(message);
209 			break;
210 
211 		default:
212 			BWindow::MessageReceived(message);
213 			break;
214 	}
215 }
216 
217 
218 void
219 TBarWindow::Minimize(bool minimize)
220 {
221 	// Don't allow the Deskbar to be minimized
222 	if (!minimize)
223 		BWindow::Minimize(false);
224 }
225 
226 
227 void
228 TBarWindow::FrameResized(float width, float height)
229 {
230 	if (!fBarView->Vertical())
231 		return BWindow::FrameResized(width, height);
232 
233 	bool setToHiddenSize = static_cast<TBarApp*>(be_app)->Settings()->autoHide
234 		&& fBarView->IsHidden() && !fBarView->DragRegion()->IsDragging();
235 	if (!setToHiddenSize) {
236 		// constrain within limits
237 		float newWidth;
238 		if (width < gMinimumWindowWidth)
239 			newWidth = gMinimumWindowWidth;
240 		else if (width > gMaximumWindowWidth)
241 			newWidth = gMaximumWindowWidth;
242 		else
243 			newWidth = width;
244 
245 		float oldWidth = static_cast<TBarApp*>(be_app)->Settings()->width;
246 
247 		// update width setting
248 		static_cast<TBarApp*>(be_app)->Settings()->width = newWidth;
249 
250 		if (oldWidth != newWidth) {
251 			fBarView->ResizeTo(width, fBarView->Bounds().Height());
252 			if (fBarView->Vertical() && fBarView->ExpandoState())
253 				fBarView->ExpandoMenuBar()->SetMaxContentWidth(width);
254 
255 			fBarView->UpdatePlacement();
256 		}
257 	}
258 }
259 
260 
261 void
262 TBarWindow::SaveSettings()
263 {
264 	fBarView->SaveSettings();
265 }
266 
267 
268 bool
269 TBarWindow::QuitRequested()
270 {
271 	be_app->PostMessage(B_QUIT_REQUESTED);
272 
273 	return BWindow::QuitRequested();
274 }
275 
276 
277 void
278 TBarWindow::WorkspaceActivated(int32 workspace, bool active)
279 {
280 	BWindow::WorkspaceActivated(workspace, active);
281 
282 	if (active && !(fBarView->ExpandoState() && fBarView->Vertical()))
283 		fBarView->UpdatePlacement();
284 	else {
285 		BRect screenFrame = (BScreen(fBarView->Window())).Frame();
286 		fBarView->SizeWindow(screenFrame);
287 		fBarView->PositionWindow(screenFrame);
288 		fBarView->Invalidate();
289 	}
290 }
291 
292 
293 void
294 TBarWindow::ScreenChanged(BRect size, color_space depth)
295 {
296 	BWindow::ScreenChanged(size, depth);
297 
298 	fBarView->UpdatePlacement();
299 	SetSizeLimits();
300 }
301 
302 
303 void
304 TBarWindow::SetDeskbarMenu(TDeskbarMenu* menu)
305 {
306 	sDeskbarMenu = menu;
307 }
308 
309 
310 TDeskbarMenu*
311 TBarWindow::DeskbarMenu()
312 {
313 	return sDeskbarMenu;
314 }
315 
316 
317 void
318 TBarWindow::ShowDeskbarMenu()
319 {
320 	TStartableMenuBar* menuBar = (TStartableMenuBar*)fBarView->BarMenuBar();
321 	if (menuBar == NULL)
322 		menuBar = (TStartableMenuBar*)KeyMenuBar();
323 
324 	if (menuBar == NULL)
325 		return;
326 
327 	menuBar->StartMenuBar(0, true, true, NULL);
328 }
329 
330 
331 void
332 TBarWindow::ShowTeamMenu()
333 {
334 	int32 index = 0;
335 	if (fBarView->BarMenuBar() == NULL)
336 		index = 2;
337 
338 	if (KeyMenuBar() == NULL)
339 		return;
340 
341 	((TStartableMenuBar*)KeyMenuBar())->StartMenuBar(index, true, true, NULL);
342 }
343 
344 
345 // determines the actual location of the window
346 
347 deskbar_location
348 TBarWindow::DeskbarLocation() const
349 {
350 	bool left = fBarView->Left();
351 	bool top = fBarView->Top();
352 
353 	if (fBarView->AcrossTop())
354 		return B_DESKBAR_TOP;
355 
356 	if (fBarView->AcrossBottom())
357 		return B_DESKBAR_BOTTOM;
358 
359 	if (left && top)
360 		return B_DESKBAR_LEFT_TOP;
361 
362 	if (!left && top)
363 		return B_DESKBAR_RIGHT_TOP;
364 
365 	if (left && !top)
366 		return B_DESKBAR_LEFT_BOTTOM;
367 
368 	return B_DESKBAR_RIGHT_BOTTOM;
369 }
370 
371 
372 void
373 TBarWindow::GetLocation(BMessage* message)
374 {
375 	BMessage reply('rply');
376 	reply.AddInt32("location", (int32)DeskbarLocation());
377 	reply.AddBool("expanded", fBarView->ExpandoState());
378 
379 	message->SendReply(&reply);
380 }
381 
382 
383 void
384 TBarWindow::SetDeskbarLocation(deskbar_location location, bool newExpandState)
385 {
386 	// left top and right top are the only two that
387 	// currently pay attention to expand, ignore for all others
388 
389 	bool left = false, top = true, vertical, expand;
390 
391 	switch (location) {
392 		case B_DESKBAR_TOP:
393 			left = true;
394 			top = true;
395 			vertical = false;
396 			expand = true;
397 			break;
398 
399 		case B_DESKBAR_BOTTOM:
400 			left = true;
401 			top = false;
402 			vertical = false;
403 			expand = true;
404 			break;
405 
406 		case B_DESKBAR_LEFT_TOP:
407 			left = true;
408 			top = true;
409 			vertical = true;
410 			expand = newExpandState;
411 			break;
412 
413 		case B_DESKBAR_RIGHT_TOP:
414 			left = false;
415 			top = true;
416 			vertical = true;
417 			expand = newExpandState;
418 			break;
419 
420 		case B_DESKBAR_LEFT_BOTTOM:
421 			left = true;
422 			top = false;
423 			vertical = true;
424 			expand = false;
425 			break;
426 
427 		case B_DESKBAR_RIGHT_BOTTOM:
428 			left = false;
429 			top = false;
430 			vertical = true;
431 			expand = false;
432 			break;
433 
434 		default:
435 			left = true;
436 			top = true;
437 			vertical = false;
438 			expand = true;
439 			break;
440 	}
441 
442 	fBarView->ChangeState(expand, vertical, left, top);
443 }
444 
445 
446 void
447 TBarWindow::SetLocation(BMessage* message)
448 {
449 	deskbar_location location;
450 	bool expand;
451 	if (message->FindInt32("location", (int32*)&location) == B_OK
452 		&& message->FindBool("expand", &expand) == B_OK)
453 		SetDeskbarLocation(location, expand);
454 }
455 
456 
457 void
458 TBarWindow::IsExpanded(BMessage* message)
459 {
460 	BMessage reply('rply');
461 	reply.AddBool("expanded", fBarView->ExpandoState());
462 	message->SendReply(&reply);
463 }
464 
465 
466 void
467 TBarWindow::Expand(BMessage* message)
468 {
469 	bool expand;
470 	if (message->FindBool("expand", &expand) == B_OK) {
471 		bool vertical = fBarView->Vertical();
472 		bool left = fBarView->Left();
473 		bool top = fBarView->Top();
474 		fBarView->ChangeState(expand, vertical, left, top);
475 	}
476 }
477 
478 
479 void
480 TBarWindow::ItemInfo(BMessage* message)
481 {
482 	BMessage replyMsg;
483 	const char* name;
484 	int32 id;
485 	DeskbarShelf shelf;
486 	if (message->FindInt32("id", &id) == B_OK) {
487 		if (fBarView->ItemInfo(id, &name, &shelf) == B_OK) {
488 			replyMsg.AddString("name", name);
489 #if SHELF_AWARE
490 			replyMsg.AddInt32("shelf", (int32)shelf);
491 #endif
492 		}
493 	} else if (message->FindString("name", &name) == B_OK) {
494 		if (fBarView->ItemInfo(name, &id, &shelf) == B_OK) {
495 			replyMsg.AddInt32("id", id);
496 #if SHELF_AWARE
497 			replyMsg.AddInt32("shelf", (int32)shelf);
498 #endif
499 		}
500 	}
501 
502 	message->SendReply(&replyMsg);
503 }
504 
505 
506 void
507 TBarWindow::ItemExists(BMessage* message)
508 {
509 	BMessage replyMsg;
510 	const char* name;
511 	int32 id;
512 	DeskbarShelf shelf;
513 
514 #if SHELF_AWARE
515 	if (message->FindInt32("shelf", (int32*)&shelf) != B_OK)
516 #endif
517 		shelf = B_DESKBAR_TRAY;
518 
519 	bool exists = false;
520 	if (message->FindInt32("id", &id) == B_OK)
521 		exists = fBarView->ItemExists(id, shelf);
522 	else if (message->FindString("name", &name) == B_OK)
523 		exists = fBarView->ItemExists(name, shelf);
524 
525 	replyMsg.AddBool("exists", exists);
526 	message->SendReply(&replyMsg);
527 }
528 
529 
530 void
531 TBarWindow::CountItems(BMessage* message)
532 {
533 	DeskbarShelf shelf;
534 
535 #if SHELF_AWARE
536 	if (message->FindInt32("shelf", (int32*)&shelf) != B_OK)
537 #endif
538 		shelf = B_DESKBAR_TRAY;
539 
540 	BMessage reply('rply');
541 	reply.AddInt32("count", fBarView->CountItems(shelf));
542 	message->SendReply(&reply);
543 }
544 
545 
546 void
547 TBarWindow::MaxItemSize(BMessage* message)
548 {
549 	DeskbarShelf shelf;
550 #if SHELF_AWARE
551 	if (message->FindInt32("shelf", (int32*)&shelf) != B_OK)
552 #endif
553 		shelf = B_DESKBAR_TRAY;
554 
555 	BSize size = fBarView->MaxItemSize(shelf);
556 
557 	BMessage reply('rply');
558 	reply.AddFloat("width", size.width);
559 	reply.AddFloat("height", size.height);
560 	message->SendReply(&reply);
561 }
562 
563 
564 void
565 TBarWindow::AddItem(BMessage* message)
566 {
567 	DeskbarShelf shelf = B_DESKBAR_TRAY;
568 	entry_ref ref;
569 	int32 id = 999;
570 	BMessage reply;
571 	status_t err = B_ERROR;
572 
573 	BMessage* archivedView = new BMessage();
574 	ObjectDeleter<BMessage> deleter(archivedView);
575 	if (message->FindMessage("view", archivedView) == B_OK) {
576 #if SHELF_AWARE
577 		message->FindInt32("shelf", &shelf);
578 #endif
579 		err = fBarView->AddItem(archivedView, shelf, &id);
580 		if (err == B_OK) {
581 			// Detach the deleter since AddReplicant is taking ownership
582 			// on success. This should be changed on server side.
583 			deleter.Detach();
584 		}
585 	} else if (message->FindRef("addon", &ref) == B_OK) {
586 		BEntry entry(&ref);
587 		err = entry.InitCheck();
588 		if (err == B_OK)
589 			err = fBarView->AddItem(&entry, shelf, &id);
590 	}
591 
592 	if (err == B_OK)
593 		reply.AddInt32("id", id);
594 	else
595 		reply.AddInt32("error", err);
596 
597 	message->SendReply(&reply);
598 }
599 
600 
601 void
602 TBarWindow::RemoveItem(BMessage* message)
603 {
604 	int32 id;
605 	const char* name;
606 
607 	// ids ought to be unique across all shelves, assuming, of course,
608 	// that sometime in the future there may be more than one
609 #if SHELF_AWARE
610 	if (message->FindInt32("shelf", (int32*)&shelf) == B_OK) {
611 		if (message->FindString("name", &name) == B_OK)
612 			fBarView->RemoveItem(name, shelf);
613 	} else {
614 #endif
615 		if (message->FindInt32("id", &id) == B_OK) {
616 			fBarView->RemoveItem(id);
617 		// remove the following two lines if and when the
618 		// shelf option returns
619 		} else if (message->FindString("name", &name) == B_OK)
620 			fBarView->RemoveItem(name, B_DESKBAR_TRAY);
621 
622 #if SHELF_AWARE
623 	}
624 #endif
625 }
626 
627 
628 void
629 TBarWindow::GetIconFrame(BMessage* message)
630 {
631 	BRect frame(0, 0, 0, 0);
632 
633 	const char* name;
634 	int32 id;
635 	if (message->FindInt32("id", &id) == B_OK)
636 		frame = fBarView->IconFrame(id);
637 	else if (message->FindString("name", &name) == B_OK)
638 		frame = fBarView->IconFrame(name);
639 
640 	BMessage reply('rply');
641 	reply.AddRect("frame", frame);
642 	message->SendReply(&reply);
643 }
644 
645 
646 bool
647 TBarWindow::IsShowingMenu() const
648 {
649 	return fShowingMenu;
650 }
651 
652 
653 void
654 TBarWindow::SetSizeLimits()
655 {
656 	BRect screenFrame = (BScreen(this)).Frame();
657 	bool setToHiddenSize = static_cast<TBarApp*>(be_app)->Settings()->autoHide
658 		&& fBarView->IsHidden() && !fBarView->DragRegion()->IsDragging();
659 
660 	if (setToHiddenSize) {
661 		if (fBarView->Vertical())
662 			BWindow::SetSizeLimits(0, kHiddenDimension, 0, kHiddenDimension);
663 		else {
664 			BWindow::SetSizeLimits(screenFrame.Width(), screenFrame.Width(),
665 				0, kHiddenDimension);
666 		}
667 	} else {
668 		if (fBarView->Vertical()) {
669 			BWindow::SetSizeLimits(gMinimumWindowWidth, gMaximumWindowWidth,
670 				kMenuBarHeight - 1, B_SIZE_UNLIMITED);
671 		} else {
672 			BWindow::SetSizeLimits(screenFrame.Width(), screenFrame.Width(),
673 				kMenuBarHeight - 1, kMaximumIconSize + 4);
674 		}
675 	}
676 }
677 
678 
679 bool
680 TBarWindow::_IsFocusMessage(BMessage* message)
681 {
682 	BMessage::Private messagePrivate(message);
683 	if (!messagePrivate.UsePreferredTarget())
684 		return false;
685 
686 	bool feedFocus;
687 	if (message->HasInt32("_token")
688 		&& (message->FindBool("_feed_focus", &feedFocus) != B_OK || !feedFocus))
689 		return false;
690 
691 	return true;
692 }
693