xref: /haiku/src/apps/launchbox/MainWindow.cpp (revision e680a439bf54eb3f561c3fc8cefd299587e69368)
1 /*
2  * Copyright 2006 - 2011, Stephan Aßmus <superstippi@gmx.de>.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 #include "MainWindow.h"
7 
8 #include <stdio.h>
9 
10 #include <Directory.h>
11 #include <File.h>
12 #include <Alert.h>
13 #include <Application.h>
14 #include <Catalog.h>
15 #include <GroupLayout.h>
16 #include <Menu.h>
17 #include <MenuItem.h>
18 #include <Messenger.h>
19 #include <Path.h>
20 #include <Roster.h>
21 #include <Screen.h>
22 
23 #include "support.h"
24 
25 #include "App.h"
26 #include "LaunchButton.h"
27 #include "NamePanel.h"
28 #include "PadView.h"
29 
30 
31 #undef B_TRANSLATION_CONTEXT
32 #define B_TRANSLATION_CONTEXT "LaunchBox"
MainWindow(const char * name,BRect frame,bool addDefaultButtons)33 MainWindow::MainWindow(const char* name, BRect frame, bool addDefaultButtons)
34 	:
35 	BWindow(frame, name, B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
36 		B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE
37 		| B_WILL_ACCEPT_FIRST_CLICK | B_NO_WORKSPACE_ACTIVATION
38 		| B_AUTO_UPDATE_SIZE_LIMITS | B_SAME_POSITION_IN_ALL_WORKSPACES,
39 		B_ALL_WORKSPACES),
40 	fSettings(new BMessage('sett')),
41 	fPadView(new PadView("pad view")),
42 	fAutoRaise(false),
43 	fShowOnAllWorkspaces(true)
44 {
45 	bool buttonsAdded = false;
46 	if (load_settings(fSettings, "main_settings", "LaunchBox") >= B_OK)
47 		buttonsAdded = LoadSettings(fSettings);
48 	if (!buttonsAdded) {
49 		if (addDefaultButtons)
50 			_AddDefaultButtons();
51 		else
52 			_AddEmptyButtons();
53 	}
54 	SetLayout(new BGroupLayout(B_HORIZONTAL));
55 	AddChild(fPadView);
56 }
57 
58 
MainWindow(const char * name,BRect frame,BMessage * settings)59 MainWindow::MainWindow(const char* name, BRect frame, BMessage* settings)
60 	:
61 	BWindow(frame, name,
62 		B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
63 		B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE
64 		| B_WILL_ACCEPT_FIRST_CLICK | B_NO_WORKSPACE_ACTIVATION
65 		| B_AUTO_UPDATE_SIZE_LIMITS | B_SAME_POSITION_IN_ALL_WORKSPACES,
66 		B_ALL_WORKSPACES),
67 	fSettings(settings),
68 	fPadView(new PadView("pad view")),
69 	fAutoRaise(false),
70 	fShowOnAllWorkspaces(true)
71 {
72 	if (!LoadSettings(settings))
73 		_AddEmptyButtons();
74 
75 	SetLayout(new BGroupLayout(B_HORIZONTAL));
76 	AddChild(fPadView);
77 }
78 
79 
~MainWindow()80 MainWindow::~MainWindow()
81 {
82 	delete fSettings;
83 }
84 
85 
86 bool
QuitRequested()87 MainWindow::QuitRequested()
88 {
89 	int32 padWindowCount = 0;
90 	for (int32 i = 0; BWindow* window = be_app->WindowAt(i); i++) {
91 		if (dynamic_cast<MainWindow*>(window))
92 			padWindowCount++;
93 	}
94 	bool canClose = true;
95 
96 	if (padWindowCount == 1) {
97 		be_app->PostMessage(B_QUIT_REQUESTED);
98 		canClose = false;
99 	} else {
100 		BAlert* alert = new BAlert(B_TRANSLATE("last chance"),
101 			B_TRANSLATE("Really close this pad?\n"
102 							"(The pad will not be remembered.)"),
103 			B_TRANSLATE("Close"), B_TRANSLATE("Cancel"), NULL);
104 		alert->SetShortcut(1, B_ESCAPE);
105 		if (alert->Go() == 1)
106 			canClose = false;
107 	}
108 	return canClose;
109 }
110 
111 
112 void
MessageReceived(BMessage * message)113 MainWindow::MessageReceived(BMessage* message)
114 {
115 	switch (message->what) {
116 		case MSG_LAUNCH:
117 		{
118 			BView* pointer;
119 			if (message->FindPointer("be:source", (void**)&pointer) < B_OK)
120 				break;
121 			LaunchButton* button = dynamic_cast<LaunchButton*>(pointer);
122 			if (button == NULL)
123 				break;
124 			BString errorMessage;
125 			bool launchedByRef = false;
126 			if (button->Ref()) {
127 				BEntry entry(button->Ref(), true);
128 				if (entry.IsDirectory()) {
129 					// open in Tracker
130 					BMessenger messenger("application/x-vnd.Be-TRAK");
131 					if (messenger.IsValid()) {
132 						BMessage trackerMessage(B_REFS_RECEIVED);
133 						trackerMessage.AddRef("refs", button->Ref());
134 						status_t ret = messenger.SendMessage(&trackerMessage);
135 						if (ret < B_OK) {
136 							errorMessage = B_TRANSLATE("Failed to send "
137 							"'open folder' command to Tracker.\n\nError: ");
138 							errorMessage << strerror(ret);
139 						} else
140 							launchedByRef = true;
141 					} else
142 						errorMessage = ("Failed to open folder - is Tracker "
143 							"running?");
144 				} else {
145 					status_t ret = be_roster->Launch(button->Ref());
146 					if (ret < B_OK && ret != B_ALREADY_RUNNING) {
147 						BString errStr(B_TRANSLATE("Failed to launch '%1'.\n"
148 							"\nError:"));
149 						BPath path(button->Ref());
150 						if (path.InitCheck() >= B_OK)
151 							errStr.ReplaceFirst("%1", path.Path());
152 						else
153 							errStr.ReplaceFirst("%1", button->Ref()->name);
154 						errorMessage << errStr.String() << " ";
155 						errorMessage << strerror(ret);
156 					} else
157 						launchedByRef = true;
158 				}
159 			}
160 			if (!launchedByRef && button->AppSignature()) {
161 				status_t ret = be_roster->Launch(button->AppSignature());
162 				if (ret != B_OK && ret != B_ALREADY_RUNNING) {
163 					BString errStr(B_TRANSLATE("\n\nFailed to launch application "
164 						"with signature '%2'.\n\nError:"));
165 					errStr.ReplaceFirst("%2", button->AppSignature());
166 					errorMessage << errStr.String() << " ";
167 					errorMessage << strerror(ret);
168 				} else {
169 					// clear error message on success (might have been
170 					// filled when trying to launch by ref)
171 					errorMessage = "";
172 				}
173 			} else if (!launchedByRef) {
174 				errorMessage = B_TRANSLATE("Failed to launch 'something', "
175 					"error in Pad data.");
176 			}
177 			if (errorMessage.Length() > 0) {
178 				BAlert* alert = new BAlert("error", errorMessage.String(),
179 					B_TRANSLATE("Bummer"), NULL, NULL, B_WIDTH_FROM_WIDEST);
180 				alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
181 				alert->Go(NULL);
182 			}
183 			break;
184 		}
185 		case MSG_ADD_SLOT:
186 		{
187 			LaunchButton* button;
188 			if (message->FindPointer("be:source", (void**)&button) >= B_OK) {
189 				fPadView->AddButton(new LaunchButton("launch button",
190 					NULL, new BMessage(MSG_LAUNCH)), button);
191 			}
192 			break;
193 		}
194 		case MSG_CLEAR_SLOT:
195 		{
196 			LaunchButton* button;
197 			if (message->FindPointer("be:source", (void**)&button) >= B_OK)
198 				button->SetTo((entry_ref*)NULL);
199 			break;
200 		}
201 		case MSG_REMOVE_SLOT:
202 		{
203 			LaunchButton* button;
204 			if (message->FindPointer("be:source", (void**)&button) >= B_OK) {
205 				if (fPadView->RemoveButton(button))
206 					delete button;
207 			}
208 			break;
209 		}
210 		case MSG_SET_DESCRIPTION:
211 		{
212 			LaunchButton* button;
213 			if (message->FindPointer("be:source", (void**)&button) >= B_OK) {
214 				const char* name;
215 				if (message->FindString("name", &name) >= B_OK) {
216 					// message comes from a previous name panel
217 					button->SetDescription(name);
218 					BRect namePanelFrame;
219 					if (message->FindRect("frame", &namePanelFrame) == B_OK) {
220 						((App*)be_app)->SetNamePanelSize(
221 							namePanelFrame.Size());
222 					}
223 				} else {
224 					// message comes from pad view
225 					entry_ref* ref = button->Ref();
226 					if (ref) {
227 						BString helper(B_TRANSLATE("Description for '%3'"));
228 						helper.ReplaceFirst("%3", ref->name);
229 						// Place the name panel besides the pad, but give it
230 						// the user configured size.
231 						BPoint origin = B_ORIGIN;
232 						BSize size = ((App*)be_app)->NamePanelSize();
233 						NamePanel* panel = new NamePanel(helper.String(),
234 							button->Description(), this, this,
235 							new BMessage(*message), size);
236 						panel->Layout(true);
237 						size = panel->Frame().Size();
238 						BScreen screen(this);
239 						BPoint mousePos;
240 						uint32 buttons;
241 						fPadView->GetMouse(&mousePos, &buttons, false);
242 						fPadView->ConvertToScreen(&mousePos);
243 						if (fPadView->Orientation() == B_HORIZONTAL) {
244 							// Place above or below the pad
245 							origin.x = mousePos.x - size.width / 2;
246 							if (screen.Frame().bottom - Frame().bottom
247 									> size.height + 20) {
248 								origin.y = Frame().bottom + 10;
249 							} else {
250 								origin.y = Frame().top - 10 - size.height;
251 							}
252 						} else {
253 							// Place left or right of the pad
254 							origin.y = mousePos.y - size.height / 2;
255 							if (screen.Frame().right - Frame().right
256 									> size.width + 20) {
257 								origin.x = Frame().right + 10;
258 							} else {
259 								origin.x = Frame().left - 10 - size.width;
260 							}
261 						}
262 						panel->MoveTo(origin);
263 						panel->Show();
264 					}
265 				}
266 			}
267 			break;
268 		}
269 		case MSG_ADD_WINDOW:
270 		{
271 			BMessage settings('sett');
272 			SaveSettings(&settings);
273 			message->AddMessage("window", &settings);
274 			be_app->PostMessage(message);
275 			break;
276 		}
277 		case MSG_SHOW_BORDER:
278 			SetLook(B_TITLED_WINDOW_LOOK);
279 			break;
280 		case MSG_HIDE_BORDER:
281 			SetLook(B_BORDERED_WINDOW_LOOK);
282 			break;
283 		case MSG_TOGGLE_AUTORAISE:
284 			ToggleAutoRaise();
285 			break;
286 		case MSG_SHOW_ON_ALL_WORKSPACES:
287 			fShowOnAllWorkspaces = !fShowOnAllWorkspaces;
288 			if (fShowOnAllWorkspaces)
289 				SetWorkspaces(B_ALL_WORKSPACES);
290 			else
291 				SetWorkspaces(1L << current_workspace());
292 			break;
293 		case MSG_OPEN_CONTAINING_FOLDER:
294 		{
295 			LaunchButton* button;
296 			if (message->FindPointer("be:source", (void**)&button) == B_OK && button->Ref() != NULL) {
297 				entry_ref target = *button->Ref();
298 				BEntry openTarget(&target);
299 				BMessage openMsg(B_REFS_RECEIVED);
300 				BMessenger tracker("application/x-vnd.Be-TRAK");
301 				openTarget.GetParent(&openTarget);
302 				openTarget.GetRef(&target);
303 				openMsg.AddRef("refs",&target);
304 				tracker.SendMessage(&openMsg);
305 			}
306 		}
307 		break;
308 		case B_SIMPLE_DATA:
309 		case B_REFS_RECEIVED:
310 		case B_PASTE:
311 		case B_MODIFIERS_CHANGED:
312 			break;
313 		default:
314 			BWindow::MessageReceived(message);
315 			break;
316 	}
317 }
318 
319 
320 void
Show()321 MainWindow::Show()
322 {
323 	BWindow::Show();
324 	_GetLocation();
325 }
326 
327 
328 void
ScreenChanged(BRect frame,color_space format)329 MainWindow::ScreenChanged(BRect frame, color_space format)
330 {
331 	_AdjustLocation(Frame());
332 }
333 
334 
335 void
WorkspaceActivated(int32 workspace,bool active)336 MainWindow::WorkspaceActivated(int32 workspace, bool active)
337 {
338 	if (fShowOnAllWorkspaces) {
339 		if (!active)
340 			_GetLocation();
341 		else
342 			_AdjustLocation(Frame());
343 	}
344 }
345 
346 
347 void
FrameMoved(BPoint origin)348 MainWindow::FrameMoved(BPoint origin)
349 {
350 	if (IsActive()) {
351 		_GetLocation();
352 		_NotifySettingsChanged();
353 	}
354 }
355 
356 
357 void
FrameResized(float width,float height)358 MainWindow::FrameResized(float width, float height)
359 {
360 	if (IsActive()) {
361 		_GetLocation();
362 		_NotifySettingsChanged();
363 	}
364 	BWindow::FrameResized(width, height);
365 }
366 
367 
368 void
ToggleAutoRaise()369 MainWindow::ToggleAutoRaise()
370 {
371 	fAutoRaise = !fAutoRaise;
372 	if (fAutoRaise)
373 		fPadView->SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
374 	else
375 		fPadView->SetEventMask(0);
376 
377 	_NotifySettingsChanged();
378 }
379 
380 
381 bool
LoadSettings(const BMessage * message)382 MainWindow::LoadSettings(const BMessage* message)
383 {
384 	// restore window positioning
385 	BPoint point;
386 	bool useAdjust = false;
387 	if (message->FindPoint("window position", &point) == B_OK) {
388 		fScreenPosition = point;
389 		useAdjust = true;
390 	}
391 	float borderDist;
392 	if (message->FindFloat("border distance", &borderDist) == B_OK) {
393 		fBorderDist = borderDist;
394 	}
395 	// restore window frame
396 	BRect frame;
397 	if (message->FindRect("window frame", &frame) == B_OK) {
398 		if (useAdjust) {
399 			_AdjustLocation(frame);
400 		} else {
401 			make_sure_frame_is_on_screen(frame, this);
402 			MoveTo(frame.LeftTop());
403 			ResizeTo(frame.Width(), frame.Height());
404 		}
405 	}
406 
407 	// restore window look
408 	window_look look;
409 	if (message->FindInt32("window look", (int32*)&look) == B_OK)
410 		SetLook(look);
411 
412 	// restore orientation
413 	int32 orientation;
414 	if (message->FindInt32("orientation", &orientation) == B_OK)
415 		fPadView->SetOrientation((enum orientation)orientation);
416 
417 	// restore icon size
418 	int32 iconSize;
419 	if (message->FindInt32("icon size", &iconSize) == B_OK)
420 		fPadView->SetIconSize(iconSize);
421 
422 	// restore ignore double click
423 	bool ignoreDoubleClick;
424 	if (message->FindBool("ignore double click", &ignoreDoubleClick) == B_OK)
425 		fPadView->SetIgnoreDoubleClick(ignoreDoubleClick);
426 
427 	// restore buttons
428 	const char* path;
429 	bool buttonAdded = false;
430 	for (int32 i = 0; message->FindString("path", i, &path) >= B_OK; i++) {
431 		LaunchButton* button = new LaunchButton("launch button",
432 			NULL, new BMessage(MSG_LAUNCH));
433 		fPadView->AddButton(button);
434 		BString signature;
435 		if (message->FindString("signature", i, &signature) >= B_OK
436 			&& signature.CountChars() > 0)  {
437 			button->SetTo(signature.String(), true);
438 		}
439 
440 		BEntry entry(path, true);
441 		entry_ref ref;
442 		if (entry.Exists() && entry.GetRef(&ref) == B_OK)
443 			button->SetTo(&ref);
444 
445 		const char* text;
446 		if (message->FindString("description", i, &text) >= B_OK)
447 			button->SetDescription(text);
448 		buttonAdded = true;
449 	}
450 
451 	// restore auto raise setting
452 	bool autoRaise;
453 	if (message->FindBool("auto raise", &autoRaise) == B_OK && autoRaise)
454 		ToggleAutoRaise();
455 
456 	// store workspace setting
457 	bool showOnAllWorkspaces;
458 	if (message->FindBool("all workspaces", &showOnAllWorkspaces) == B_OK) {
459 		fShowOnAllWorkspaces = showOnAllWorkspaces;
460 		SetWorkspaces(showOnAllWorkspaces
461 			? B_ALL_WORKSPACES : 1L << current_workspace());
462 	}
463 	if (!fShowOnAllWorkspaces) {
464 		uint32 workspaces;
465 		if (message->FindInt32("workspaces", (int32*)&workspaces) == B_OK)
466 			SetWorkspaces(workspaces);
467 	}
468 
469 	return buttonAdded;
470 }
471 
472 
473 void
SaveSettings(BMessage * message)474 MainWindow::SaveSettings(BMessage* message)
475 {
476 	// make sure the positioning info is correct
477 	_GetLocation();
478 	// store window position
479 	if (message->ReplacePoint("window position", fScreenPosition) != B_OK)
480 		message->AddPoint("window position", fScreenPosition);
481 
482 	if (message->ReplaceFloat("border distance", fBorderDist) != B_OK)
483 		message->AddFloat("border distance", fBorderDist);
484 
485 	// store window frame and look
486 	if (message->ReplaceRect("window frame", Frame()) != B_OK)
487 		message->AddRect("window frame", Frame());
488 
489 	if (message->ReplaceInt32("window look", Look()) != B_OK)
490 		message->AddInt32("window look", Look());
491 
492 	// store orientation
493 	if (message->ReplaceInt32("orientation",
494 			(int32)fPadView->Orientation()) != B_OK)
495 		message->AddInt32("orientation", (int32)fPadView->Orientation());
496 
497 	// store icon size
498 	if (message->ReplaceInt32("icon size", fPadView->IconSize()) != B_OK)
499 		message->AddInt32("icon size", fPadView->IconSize());
500 
501 	// store ignore double click
502 	if (message->ReplaceBool("ignore double click",
503 			fPadView->IgnoreDoubleClick()) != B_OK) {
504 		message->AddBool("ignore double click", fPadView->IgnoreDoubleClick());
505 	}
506 
507 	// store buttons
508 	message->RemoveName("path");
509 	message->RemoveName("description");
510 	message->RemoveName("signature");
511 	for (int32 i = 0; LaunchButton* button = fPadView->ButtonAt(i); i++) {
512 		BPath path(button->Ref());
513 		if (path.InitCheck() >= B_OK)
514 			message->AddString("path", path.Path());
515 		else
516 			message->AddString("path", "");
517 		message->AddString("description", button->Description());
518 
519 		if (button->AppSignature())
520 			message->AddString("signature", button->AppSignature());
521 		else
522 			message->AddString("signature", "");
523 	}
524 
525 	// store auto raise setting
526 	if (message->ReplaceBool("auto raise", fAutoRaise) != B_OK)
527 		message->AddBool("auto raise", fAutoRaise);
528 
529 	// store workspace setting
530 	if (message->ReplaceBool("all workspaces", fShowOnAllWorkspaces) != B_OK)
531 		message->AddBool("all workspaces", fShowOnAllWorkspaces);
532 	if (message->ReplaceInt32("workspaces", Workspaces()) != B_OK)
533 		message->AddInt32("workspaces", Workspaces());
534 }
535 
536 
537 void
_GetLocation()538 MainWindow::_GetLocation()
539 {
540 	BRect frame = Frame();
541 	BPoint origin = frame.LeftTop();
542 	BPoint center(origin.x + frame.Width() / 2.0,
543 		origin.y + frame.Height() / 2.0);
544 	BScreen screen(this);
545 	BRect screenFrame = screen.Frame();
546 	fScreenPosition.x = center.x / screenFrame.Width();
547 	fScreenPosition.y = center.y / screenFrame.Height();
548 	if (fabs(0.5 - fScreenPosition.x) > fabs(0.5 - fScreenPosition.y)) {
549 		// nearest to left or right border
550 		if (fScreenPosition.x < 0.5)
551 			fBorderDist = frame.left - screenFrame.left;
552 		else
553 			fBorderDist = screenFrame.right - frame.right;
554 	} else {
555 		// nearest to top or bottom border
556 		if (fScreenPosition.y < 0.5)
557 			fBorderDist = frame.top - screenFrame.top;
558 		else
559 			fBorderDist = screenFrame.bottom - frame.bottom;
560 	}
561 }
562 
563 
564 void
_AdjustLocation(BRect frame)565 MainWindow::_AdjustLocation(BRect frame)
566 {
567 	BScreen screen(this);
568 	BRect screenFrame = screen.Frame();
569 	BPoint center(fScreenPosition.x * screenFrame.Width(),
570 		fScreenPosition.y * screenFrame.Height());
571 	BPoint frameCenter(frame.left + frame.Width() / 2.0,
572 		frame.top + frame.Height() / 2.0);
573 	frame.OffsetBy(center - frameCenter);
574 	// ignore border dist when distance too large
575 	if (fBorderDist < 10.0) {
576 		// see which border we mean depending on screen position
577 		BPoint offset(0.0, 0.0);
578 		if (fabs(0.5 - fScreenPosition.x) > fabs(0.5 - fScreenPosition.y)) {
579 			// left or right border
580 			if (fScreenPosition.x < 0.5)
581 				offset.x = (screenFrame.left + fBorderDist) - frame.left;
582 			else
583 				offset.x = (screenFrame.right - fBorderDist) - frame.right;
584 		} else {
585 			// top or bottom border
586 			if (fScreenPosition.y < 0.5)
587 				offset.y = (screenFrame.top + fBorderDist) - frame.top;
588 			else
589 				offset.y = (screenFrame.bottom - fBorderDist) - frame.bottom;
590 		}
591 		frame.OffsetBy(offset);
592 	}
593 
594 	make_sure_frame_is_on_screen(frame, this);
595 
596 	MoveTo(frame.LeftTop());
597 	ResizeTo(frame.Width(), frame.Height());
598 }
599 
600 
601 void
_AddDefaultButtons()602 MainWindow::_AddDefaultButtons()
603 {
604 	// Mail
605 	LaunchButton* button = new LaunchButton("launch button", NULL,
606 		new BMessage(MSG_LAUNCH));
607 	fPadView->AddButton(button);
608 	button->SetTo("application/x-vnd.Be-MAIL", true);
609 
610 	// StyledEdit
611 	button = new LaunchButton("launch button", NULL, new BMessage(MSG_LAUNCH));
612 	fPadView->AddButton(button);
613 	button->SetTo("application/x-vnd.Haiku-StyledEdit", true);
614 
615 	// ShowImage
616 	button = new LaunchButton("launch button", NULL, new BMessage(MSG_LAUNCH));
617 	fPadView->AddButton(button);
618 	button->SetTo("application/x-vnd.Haiku-ShowImage", true);
619 
620 	// MediaPlayer
621 	button = new LaunchButton("launch button", NULL, new BMessage(MSG_LAUNCH));
622 	fPadView->AddButton(button);
623 	button->SetTo("application/x-vnd.Haiku-MediaPlayer", true);
624 
625 	// DeskCalc
626 	button = new LaunchButton("launch button", NULL, new BMessage(MSG_LAUNCH));
627 	fPadView->AddButton(button);
628 	button->SetTo("application/x-vnd.Haiku-DeskCalc", true);
629 
630 	// Terminal
631 	button = new LaunchButton("launch button", NULL, new BMessage(MSG_LAUNCH));
632 	fPadView->AddButton(button);
633 	button->SetTo("application/x-vnd.Haiku-Terminal", true);
634 }
635 
636 
637 void
_AddEmptyButtons()638 MainWindow::_AddEmptyButtons()
639 {
640 	LaunchButton* button = new LaunchButton("launch button", NULL,
641 		new BMessage(MSG_LAUNCH));
642 	fPadView->AddButton(button);
643 
644 	button = new LaunchButton("launch button", NULL, new BMessage(MSG_LAUNCH));
645 	fPadView->AddButton(button);
646 
647 	button = new LaunchButton("launch button", NULL, new BMessage(MSG_LAUNCH));
648 	fPadView->AddButton(button);
649 }
650 
651 
652 void
_NotifySettingsChanged()653 MainWindow::_NotifySettingsChanged()
654 {
655 	be_app->PostMessage(MSG_SETTINGS_CHANGED);
656 }