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