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