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