2 * Copyright 2006 - 2011, Stephan Aßmus <superstippi@gmx.de>.
3 * All rights reserved. Distributed under the terms of the MIT License.
6 #include "MainWindow.h"
11 #include <Application.h>
13 #include <GroupLayout.h>
16 #include <Messenger.h>
24 #include "LaunchButton.h"
25 #include "NamePanel.h"
29 #undef B_TRANSLATION_CONTEXT
30 #define B_TRANSLATION_CONTEXT "LaunchBox"
31 MainWindow::MainWindow(const char* name
, BRect frame
, bool addDefaultButtons
)
33 BWindow(frame
, name
, B_TITLED_WINDOW_LOOK
, B_NORMAL_WINDOW_FEEL
,
34 B_ASYNCHRONOUS_CONTROLS
| B_NOT_ZOOMABLE
35 | B_WILL_ACCEPT_FIRST_CLICK
| B_NO_WORKSPACE_ACTIVATION
36 | B_AUTO_UPDATE_SIZE_LIMITS
| B_SAME_POSITION_IN_ALL_WORKSPACES
,
38 fSettings(new BMessage('sett')),
39 fPadView(new PadView("pad view")),
41 fShowOnAllWorkspaces(true)
43 bool buttonsAdded
= false;
44 if (load_settings(fSettings
, "main_settings", "LaunchBox") >= B_OK
)
45 buttonsAdded
= LoadSettings(fSettings
);
47 if (addDefaultButtons
)
53 SetLayout(new BGroupLayout(B_HORIZONTAL
));
58 MainWindow::MainWindow(const char* name
, BRect frame
, BMessage
* settings
)
61 B_TITLED_WINDOW_LOOK
, B_NORMAL_WINDOW_FEEL
,
62 B_ASYNCHRONOUS_CONTROLS
| B_NOT_ZOOMABLE
63 | B_WILL_ACCEPT_FIRST_CLICK
| B_NO_WORKSPACE_ACTIVATION
64 | B_AUTO_UPDATE_SIZE_LIMITS
| B_SAME_POSITION_IN_ALL_WORKSPACES
,
67 fPadView(new PadView("pad view")),
69 fShowOnAllWorkspaces(true)
71 if (!LoadSettings(settings
))
74 SetLayout(new BGroupLayout(B_HORIZONTAL
));
79 MainWindow::~MainWindow()
86 MainWindow::QuitRequested()
88 int32 padWindowCount
= 0;
89 for (int32 i
= 0; BWindow
* window
= be_app
->WindowAt(i
); i
++) {
90 if (dynamic_cast<MainWindow
*>(window
))
95 if (padWindowCount
== 1) {
96 be_app
->PostMessage(B_QUIT_REQUESTED
);
99 BAlert
* alert
= new BAlert(B_TRANSLATE("last chance"),
100 B_TRANSLATE("Really close this pad?\n"
101 "(The pad will not be remembered.)"),
102 B_TRANSLATE("Close"), B_TRANSLATE("Cancel"), NULL
);
103 alert
->SetShortcut(1, B_ESCAPE
);
104 if (alert
->Go() == 1)
112 MainWindow::MessageReceived(BMessage
* message
)
114 switch (message
->what
) {
118 if (message
->FindPointer("be:source", (void**)&pointer
) < B_OK
)
120 LaunchButton
* button
= dynamic_cast<LaunchButton
*>(pointer
);
123 BString errorMessage
;
124 bool launchedByRef
= false;
126 BEntry
entry(button
->Ref(), true);
127 if (entry
.IsDirectory()) {
129 BMessenger
messenger("application/x-vnd.Be-TRAK");
130 if (messenger
.IsValid()) {
131 BMessage
trackerMessage(B_REFS_RECEIVED
);
132 trackerMessage
.AddRef("refs", button
->Ref());
133 status_t ret
= messenger
.SendMessage(&trackerMessage
);
135 errorMessage
= B_TRANSLATE("Failed to send "
136 "'open folder' command to Tracker.\n\nError: ");
137 errorMessage
<< strerror(ret
);
139 launchedByRef
= true;
141 errorMessage
= ("Failed to open folder - is Tracker "
144 status_t ret
= be_roster
->Launch(button
->Ref());
145 if (ret
< B_OK
&& ret
!= B_ALREADY_RUNNING
) {
146 BString
errStr(B_TRANSLATE("Failed to launch '%1'.\n"
148 BPath
path(button
->Ref());
149 if (path
.InitCheck() >= B_OK
)
150 errStr
.ReplaceFirst("%1", path
.Path());
152 errStr
.ReplaceFirst("%1", button
->Ref()->name
);
153 errorMessage
<< errStr
.String() << " ";
154 errorMessage
<< strerror(ret
);
156 launchedByRef
= true;
159 if (!launchedByRef
&& button
->AppSignature()) {
160 status_t ret
= be_roster
->Launch(button
->AppSignature());
161 if (ret
!= B_OK
&& ret
!= B_ALREADY_RUNNING
) {
162 BString
errStr(B_TRANSLATE("\n\nFailed to launch application "
163 "with signature '%2'.\n\nError:"));
164 errStr
.ReplaceFirst("%2", button
->AppSignature());
165 errorMessage
<< errStr
.String() << " ";
166 errorMessage
<< strerror(ret
);
168 // clear error message on success (might have been
169 // filled when trying to launch by ref)
172 } else if (!launchedByRef
) {
173 errorMessage
= B_TRANSLATE("Failed to launch 'something', "
174 "error in Pad data.");
176 if (errorMessage
.Length() > 0) {
177 BAlert
* alert
= new BAlert("error", errorMessage
.String(),
178 B_TRANSLATE("Bummer"), NULL
, NULL
, B_WIDTH_FROM_WIDEST
);
179 alert
->SetFlags(alert
->Flags() | B_CLOSE_ON_ESCAPE
);
186 LaunchButton
* button
;
187 if (message
->FindPointer("be:source", (void**)&button
) >= B_OK
) {
188 fPadView
->AddButton(new LaunchButton("launch button",
189 NULL
, new BMessage(MSG_LAUNCH
)), button
);
195 LaunchButton
* button
;
196 if (message
->FindPointer("be:source", (void**)&button
) >= B_OK
)
197 button
->SetTo((entry_ref
*)NULL
);
200 case MSG_REMOVE_SLOT
:
202 LaunchButton
* button
;
203 if (message
->FindPointer("be:source", (void**)&button
) >= B_OK
) {
204 if (fPadView
->RemoveButton(button
))
209 case MSG_SET_DESCRIPTION
:
211 LaunchButton
* button
;
212 if (message
->FindPointer("be:source", (void**)&button
) >= B_OK
) {
214 if (message
->FindString("name", &name
) >= B_OK
) {
215 // message comes from a previous name panel
216 button
->SetDescription(name
);
217 BRect namePanelFrame
;
218 if (message
->FindRect("frame", &namePanelFrame
) == B_OK
) {
219 ((App
*)be_app
)->SetNamePanelSize(
220 namePanelFrame
.Size());
223 // message comes from pad view
224 entry_ref
* ref
= button
->Ref();
226 BString
helper(B_TRANSLATE("Description for '%3'"));
227 helper
.ReplaceFirst("%3", ref
->name
);
228 // Place the name panel besides the pad, but give it
229 // the user configured size.
230 BPoint origin
= B_ORIGIN
;
231 BSize size
= ((App
*)be_app
)->NamePanelSize();
232 NamePanel
* panel
= new NamePanel(helper
.String(),
233 button
->Description(), this, this,
234 new BMessage(*message
), size
);
236 size
= panel
->Frame().Size();
237 BScreen
screen(this);
240 fPadView
->GetMouse(&mousePos
, &buttons
, false);
241 fPadView
->ConvertToScreen(&mousePos
);
242 if (fPadView
->Orientation() == B_HORIZONTAL
) {
243 // Place above or below the pad
244 origin
.x
= mousePos
.x
- size
.width
/ 2;
245 if (screen
.Frame().bottom
- Frame().bottom
246 > size
.height
+ 20) {
247 origin
.y
= Frame().bottom
+ 10;
249 origin
.y
= Frame().top
- 10 - size
.height
;
252 // Place left or right of the pad
253 origin
.y
= mousePos
.y
- size
.height
/ 2;
254 if (screen
.Frame().right
- Frame().right
256 origin
.x
= Frame().right
+ 10;
258 origin
.x
= Frame().left
- 10 - size
.width
;
261 panel
->MoveTo(origin
);
270 BMessage
settings('sett');
271 SaveSettings(&settings
);
272 message
->AddMessage("window", &settings
);
273 be_app
->PostMessage(message
);
276 case MSG_SHOW_BORDER
:
277 SetLook(B_TITLED_WINDOW_LOOK
);
279 case MSG_HIDE_BORDER
:
280 SetLook(B_BORDERED_WINDOW_LOOK
);
282 case MSG_TOGGLE_AUTORAISE
:
285 case MSG_SHOW_ON_ALL_WORKSPACES
:
286 fShowOnAllWorkspaces
= !fShowOnAllWorkspaces
;
287 if (fShowOnAllWorkspaces
)
288 SetWorkspaces(B_ALL_WORKSPACES
);
290 SetWorkspaces(1L << current_workspace());
292 case MSG_OPEN_CONTAINING_FOLDER
:
294 LaunchButton
* button
;
295 if (message
->FindPointer("be:source", (void**)&button
) == B_OK
&& button
->Ref() != NULL
) {
296 entry_ref target
= *button
->Ref();
297 BEntry
openTarget(&target
);
298 BMessage
openMsg(B_REFS_RECEIVED
);
299 BMessenger
tracker("application/x-vnd.Be-TRAK");
300 openTarget
.GetParent(&openTarget
);
301 openTarget
.GetRef(&target
);
302 openMsg
.AddRef("refs",&target
);
303 tracker
.SendMessage(&openMsg
);
308 case B_REFS_RECEIVED
:
310 case B_MODIFIERS_CHANGED
:
313 BWindow::MessageReceived(message
);
328 MainWindow::ScreenChanged(BRect frame
, color_space format
)
330 _AdjustLocation(Frame());
335 MainWindow::WorkspaceActivated(int32 workspace
, bool active
)
337 if (fShowOnAllWorkspaces
) {
341 _AdjustLocation(Frame());
347 MainWindow::FrameMoved(BPoint origin
)
351 _NotifySettingsChanged();
357 MainWindow::FrameResized(float width
, float height
)
361 _NotifySettingsChanged();
363 BWindow::FrameResized(width
, height
);
368 MainWindow::ToggleAutoRaise()
370 fAutoRaise
= !fAutoRaise
;
372 fPadView
->SetEventMask(B_POINTER_EVENTS
, B_NO_POINTER_HISTORY
);
374 fPadView
->SetEventMask(0);
376 _NotifySettingsChanged();
381 MainWindow::LoadSettings(const BMessage
* message
)
383 // restore window positioning
385 bool useAdjust
= false;
386 if (message
->FindPoint("window position", &point
) == B_OK
) {
387 fScreenPosition
= point
;
391 if (message
->FindFloat("border distance", &borderDist
) == B_OK
) {
392 fBorderDist
= borderDist
;
394 // restore window frame
396 if (message
->FindRect("window frame", &frame
) == B_OK
) {
398 _AdjustLocation(frame
);
400 make_sure_frame_is_on_screen(frame
, this);
401 MoveTo(frame
.LeftTop());
402 ResizeTo(frame
.Width(), frame
.Height());
406 // restore window look
408 if (message
->FindInt32("window look", (int32
*)&look
) == B_OK
)
411 // restore orientation
413 if (message
->FindInt32("orientation", &orientation
) == B_OK
)
414 fPadView
->SetOrientation((enum orientation
)orientation
);
418 if (message
->FindInt32("icon size", &iconSize
) == B_OK
)
419 fPadView
->SetIconSize(iconSize
);
421 // restore ignore double click
422 bool ignoreDoubleClick
;
423 if (message
->FindBool("ignore double click", &ignoreDoubleClick
) == B_OK
)
424 fPadView
->SetIgnoreDoubleClick(ignoreDoubleClick
);
428 bool buttonAdded
= false;
429 for (int32 i
= 0; message
->FindString("path", i
, &path
) >= B_OK
; i
++) {
430 LaunchButton
* button
= new LaunchButton("launch button",
431 NULL
, new BMessage(MSG_LAUNCH
));
432 fPadView
->AddButton(button
);
434 if (message
->FindString("signature", i
, &signature
) >= B_OK
435 && signature
.CountChars() > 0) {
436 button
->SetTo(signature
.String(), true);
439 BEntry
entry(path
, true);
441 if (entry
.Exists() && entry
.GetRef(&ref
) == B_OK
)
445 if (message
->FindString("description", i
, &text
) >= B_OK
)
446 button
->SetDescription(text
);
450 // restore auto raise setting
452 if (message
->FindBool("auto raise", &autoRaise
) == B_OK
&& autoRaise
)
455 // store workspace setting
456 bool showOnAllWorkspaces
;
457 if (message
->FindBool("all workspaces", &showOnAllWorkspaces
) == B_OK
) {
458 fShowOnAllWorkspaces
= showOnAllWorkspaces
;
459 SetWorkspaces(showOnAllWorkspaces
460 ? B_ALL_WORKSPACES
: 1L << current_workspace());
462 if (!fShowOnAllWorkspaces
) {
464 if (message
->FindInt32("workspaces", (int32
*)&workspaces
) == B_OK
)
465 SetWorkspaces(workspaces
);
473 MainWindow::SaveSettings(BMessage
* message
)
475 // make sure the positioning info is correct
477 // store window position
478 if (message
->ReplacePoint("window position", fScreenPosition
) != B_OK
)
479 message
->AddPoint("window position", fScreenPosition
);
481 if (message
->ReplaceFloat("border distance", fBorderDist
) != B_OK
)
482 message
->AddFloat("border distance", fBorderDist
);
484 // store window frame and look
485 if (message
->ReplaceRect("window frame", Frame()) != B_OK
)
486 message
->AddRect("window frame", Frame());
488 if (message
->ReplaceInt32("window look", Look()) != B_OK
)
489 message
->AddInt32("window look", Look());
492 if (message
->ReplaceInt32("orientation",
493 (int32
)fPadView
->Orientation()) != B_OK
)
494 message
->AddInt32("orientation", (int32
)fPadView
->Orientation());
497 if (message
->ReplaceInt32("icon size", fPadView
->IconSize()) != B_OK
)
498 message
->AddInt32("icon size", fPadView
->IconSize());
500 // store ignore double click
501 if (message
->ReplaceBool("ignore double click",
502 fPadView
->IgnoreDoubleClick()) != B_OK
) {
503 message
->AddBool("ignore double click", fPadView
->IgnoreDoubleClick());
507 message
->RemoveName("path");
508 message
->RemoveName("description");
509 message
->RemoveName("signature");
510 for (int32 i
= 0; LaunchButton
* button
= fPadView
->ButtonAt(i
); i
++) {
511 BPath
path(button
->Ref());
512 if (path
.InitCheck() >= B_OK
)
513 message
->AddString("path", path
.Path());
515 message
->AddString("path", "");
516 message
->AddString("description", button
->Description());
518 if (button
->AppSignature())
519 message
->AddString("signature", button
->AppSignature());
521 message
->AddString("signature", "");
524 // store auto raise setting
525 if (message
->ReplaceBool("auto raise", fAutoRaise
) != B_OK
)
526 message
->AddBool("auto raise", fAutoRaise
);
528 // store workspace setting
529 if (message
->ReplaceBool("all workspaces", fShowOnAllWorkspaces
) != B_OK
)
530 message
->AddBool("all workspaces", fShowOnAllWorkspaces
);
531 if (message
->ReplaceInt32("workspaces", Workspaces()) != B_OK
)
532 message
->AddInt32("workspaces", Workspaces());
537 MainWindow::_GetLocation()
539 BRect frame
= Frame();
540 BPoint origin
= frame
.LeftTop();
541 BPoint
center(origin
.x
+ frame
.Width() / 2.0,
542 origin
.y
+ frame
.Height() / 2.0);
543 BScreen
screen(this);
544 BRect screenFrame
= screen
.Frame();
545 fScreenPosition
.x
= center
.x
/ screenFrame
.Width();
546 fScreenPosition
.y
= center
.y
/ screenFrame
.Height();
547 if (fabs(0.5 - fScreenPosition
.x
) > fabs(0.5 - fScreenPosition
.y
)) {
548 // nearest to left or right border
549 if (fScreenPosition
.x
< 0.5)
550 fBorderDist
= frame
.left
- screenFrame
.left
;
552 fBorderDist
= screenFrame
.right
- frame
.right
;
554 // nearest to top or bottom border
555 if (fScreenPosition
.y
< 0.5)
556 fBorderDist
= frame
.top
- screenFrame
.top
;
558 fBorderDist
= screenFrame
.bottom
- frame
.bottom
;
564 MainWindow::_AdjustLocation(BRect frame
)
566 BScreen
screen(this);
567 BRect screenFrame
= screen
.Frame();
568 BPoint
center(fScreenPosition
.x
* screenFrame
.Width(),
569 fScreenPosition
.y
* screenFrame
.Height());
570 BPoint
frameCenter(frame
.left
+ frame
.Width() / 2.0,
571 frame
.top
+ frame
.Height() / 2.0);
572 frame
.OffsetBy(center
- frameCenter
);
573 // ignore border dist when distance too large
574 if (fBorderDist
< 10.0) {
575 // see which border we mean depending on screen position
576 BPoint
offset(0.0, 0.0);
577 if (fabs(0.5 - fScreenPosition
.x
) > fabs(0.5 - fScreenPosition
.y
)) {
578 // left or right border
579 if (fScreenPosition
.x
< 0.5)
580 offset
.x
= (screenFrame
.left
+ fBorderDist
) - frame
.left
;
582 offset
.x
= (screenFrame
.right
- fBorderDist
) - frame
.right
;
584 // top or bottom border
585 if (fScreenPosition
.y
< 0.5)
586 offset
.y
= (screenFrame
.top
+ fBorderDist
) - frame
.top
;
588 offset
.y
= (screenFrame
.bottom
- fBorderDist
) - frame
.bottom
;
590 frame
.OffsetBy(offset
);
593 make_sure_frame_is_on_screen(frame
, this);
595 MoveTo(frame
.LeftTop());
596 ResizeTo(frame
.Width(), frame
.Height());
601 MainWindow::_AddDefaultButtons()
604 LaunchButton
* button
= new LaunchButton("launch button", NULL
,
605 new BMessage(MSG_LAUNCH
));
606 fPadView
->AddButton(button
);
607 button
->SetTo("application/x-vnd.Be-MAIL", true);
610 button
= new LaunchButton("launch button", NULL
, new BMessage(MSG_LAUNCH
));
611 fPadView
->AddButton(button
);
612 button
->SetTo("application/x-vnd.Haiku-StyledEdit", true);
615 button
= new LaunchButton("launch button", NULL
, new BMessage(MSG_LAUNCH
));
616 fPadView
->AddButton(button
);
617 button
->SetTo("application/x-vnd.Haiku-ShowImage", true);
620 button
= new LaunchButton("launch button", NULL
, new BMessage(MSG_LAUNCH
));
621 fPadView
->AddButton(button
);
622 button
->SetTo("application/x-vnd.Haiku-MediaPlayer", true);
625 button
= new LaunchButton("launch button", NULL
, new BMessage(MSG_LAUNCH
));
626 fPadView
->AddButton(button
);
627 button
->SetTo("application/x-vnd.Haiku-DeskCalc", true);
630 button
= new LaunchButton("launch button", NULL
, new BMessage(MSG_LAUNCH
));
631 fPadView
->AddButton(button
);
632 button
->SetTo("application/x-vnd.Haiku-Terminal", true);
637 MainWindow::_AddEmptyButtons()
639 LaunchButton
* button
= new LaunchButton("launch button", NULL
,
640 new BMessage(MSG_LAUNCH
));
641 fPadView
->AddButton(button
);
643 button
= new LaunchButton("launch button", NULL
, new BMessage(MSG_LAUNCH
));
644 fPadView
->AddButton(button
);
646 button
= new LaunchButton("launch button", NULL
, new BMessage(MSG_LAUNCH
));
647 fPadView
->AddButton(button
);
652 MainWindow::_NotifySettingsChanged()
654 be_app
->PostMessage(MSG_SETTINGS_CHANGED
);