xref: /haiku/src/apps/launchbox/MainWindow.cpp (revision 1b8f7f13a3dc70e0e903cb94248220b40b732204)
1 /*
2  * Copyright 2006, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  */
8 
9 #include "MainWindow.h"
10 
11 #include <stdio.h>
12 
13 #include <Alert.h>
14 #include <Application.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 "LaunchButton.h"
26 #include "NamePanel.h"
27 #include "PadView.h"
28 
29 // constructor
30 MainWindow::MainWindow(const char* name, BRect frame, bool addDefaultButtons)
31 	: BWindow(frame, name,
32 			  B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
33 			  B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE
34 			  | B_WILL_ACCEPT_FIRST_CLICK | B_NO_WORKSPACE_ACTIVATION
35 			  | B_AUTO_UPDATE_SIZE_LIMITS),
36 	  fSettings(new BMessage('sett')),
37 	  fPadView(new PadView("pad view")),
38 	  fLastID(0),
39 	  fNamePanelFrame(-1000.0, -1000.0, -800.0, -900.0),
40 	  fAutoRaise(false),
41 	  fShowOnAllWorkspaces(true)
42 {
43 	bool buttonsAdded = false;
44 	if (load_settings(fSettings, "main_settings", "LaunchBox") >= B_OK)
45 		buttonsAdded = LoadSettings(fSettings);
46 	if (!buttonsAdded) {
47 		if (addDefaultButtons)
48 			_AddDefaultButtons();
49 		else
50 			_AddEmptyButtons();
51 	}
52 
53 	SetLayout(new BGroupLayout(B_HORIZONTAL));
54 	AddChild(fPadView);
55 }
56 
57 // constructor
58 MainWindow::MainWindow(const char* name, BRect frame, BMessage* settings)
59 	: BWindow(frame, name,
60 			  B_TITLED_WINDOW_LOOK, B_NORMAL_WINDOW_FEEL,
61 			  B_ASYNCHRONOUS_CONTROLS | B_NOT_ZOOMABLE
62 			  | B_WILL_ACCEPT_FIRST_CLICK | B_NO_WORKSPACE_ACTIVATION
63 			  | B_AUTO_UPDATE_SIZE_LIMITS),
64 	  fSettings(settings),
65 	  fPadView(new PadView("pad view")),
66 	  fLastID(0),
67 	  fNamePanelFrame(-1000.0, -1000.0, -900.0, -900.0),
68 	  fAutoRaise(false),
69 	  fShowOnAllWorkspaces(true)
70 {
71 	if (!LoadSettings(settings))
72 		_AddEmptyButtons();
73 
74 	SetLayout(new BGroupLayout(B_HORIZONTAL));
75 	AddChild(fPadView);
76 }
77 
78 
79 // destructor
80 MainWindow::~MainWindow()
81 {
82 	delete fSettings;
83 }
84 
85 // QuitRequested
86 bool
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 	if (padWindowCount == 1) {
95 		be_app->PostMessage(B_QUIT_REQUESTED);
96 		return false;
97 	} else {
98 		BAlert* alert = new BAlert("last chance", "Really close this pad?\n"
99 												  "(The pad will not be remembered.)",
100 									"Close", "Cancel", NULL);
101 		if (alert->Go() == 1)
102 			return false;
103 	}
104 	return true;
105 }
106 
107 // MessageReceived
108 void
109 MainWindow::MessageReceived(BMessage* message)
110 {
111 	switch (message->what) {
112 		case MSG_LAUNCH: {
113 			BView* pointer;
114 			if (message->FindPointer("be:source", (void**)&pointer) >= B_OK) {
115 				if (LaunchButton* button = dynamic_cast<LaunchButton*>(pointer)) {
116 					if (button->AppSignature()) {
117 						be_roster->Launch(button->AppSignature());
118 					} else {
119 						BEntry entry(button->Ref(), true);
120 						if (entry.IsDirectory()) {
121 							// open in Tracker
122 							BMessenger messenger("application/x-vnd.Be-TRAK");
123 							if (messenger.IsValid()) {
124 								BMessage trackerMessage(B_REFS_RECEIVED);
125 								trackerMessage.AddRef("refs", button->Ref());
126 								messenger.SendMessage(&trackerMessage);
127 							}
128 						} else {
129 							status_t ret = be_roster->Launch(button->Ref());
130 							if (ret < B_OK)
131 								fprintf(stderr, "launching %s failed: %s\n",
132 										button->Ref()->name, strerror(ret));
133 						}
134 					}
135 				}
136 			}
137 			break;
138 		}
139 		case MSG_ADD_SLOT: {
140 			LaunchButton* button;
141 			if (message->FindPointer("be:source", (void**)&button) >= B_OK) {
142 				fPadView->AddButton(new LaunchButton("launch button", fLastID++, NULL,
143 													 new BMessage(MSG_LAUNCH)), button);
144 			}
145 			break;
146 		}
147 		case MSG_CLEAR_SLOT: {
148 			LaunchButton* button;
149 			if (message->FindPointer("be:source", (void**)&button) >= B_OK)
150 				button->SetTo((entry_ref*)NULL);
151 			break;
152 		}
153 		case MSG_REMOVE_SLOT: {
154 			LaunchButton* button;
155 			if (message->FindPointer("be:source", (void**)&button) >= B_OK) {
156 				if (fPadView->RemoveButton(button))
157 					delete button;
158 			}
159 			break;
160 		}
161 		case MSG_SET_DESCRIPTION: {
162 			LaunchButton* button;
163 			if (message->FindPointer("be:source", (void**)&button) >= B_OK) {
164 				const char* name;
165 				if (message->FindString("name", &name) >= B_OK) {
166 					// message comes from a previous name panel
167 					button->SetDescription(name);
168 					message->FindRect("frame", &fNamePanelFrame);
169 				} else {
170 					// message comes from pad view
171 					entry_ref* ref = button->Ref();
172 					if (ref) {
173 						BString helper("Description for '");
174 						helper << ref->name << "'";
175 //						BRect* frame = fNamePanelFrame.IsValid() ? &fNamePanelFrame : NULL;
176 						new NamePanel(helper.String(),
177 									  button->Description(),
178 									  this, this,
179 									  new BMessage(*message),
180 									  fNamePanelFrame);
181 					}
182 				}
183 			}
184 			break;
185 		}
186 		case MSG_ADD_WINDOW: {
187 			BMessage settings('sett');
188 			SaveSettings(&settings);
189 			message->AddMessage("window", &settings);
190 			be_app->PostMessage(message);
191 			break;
192 		}
193 		case MSG_SHOW_BORDER:
194 			SetLook(B_TITLED_WINDOW_LOOK);
195 			break;
196 		case MSG_HIDE_BORDER:
197 			SetLook(B_BORDERED_WINDOW_LOOK);
198 			break;
199 		case MSG_TOGGLE_AUTORAISE:
200 			ToggleAutoRaise();
201 			break;
202 		case MSG_SHOW_ON_ALL_WORKSPACES:
203 			fShowOnAllWorkspaces = !fShowOnAllWorkspaces;
204 			break;
205 		case B_SIMPLE_DATA:
206 		case B_REFS_RECEIVED:
207 		case B_PASTE:
208 		case B_MODIFIERS_CHANGED:
209 			break;
210 		case B_ABOUT_REQUESTED:
211 			be_app->PostMessage(message);
212 			break;
213 		default:
214 			BWindow::MessageReceived(message);
215 			break;
216 	}
217 }
218 
219 // Show
220 void
221 MainWindow::Show()
222 {
223 	BWindow::Show();
224 	_GetLocation();
225 }
226 
227 // ScreenChanged
228 void
229 MainWindow::ScreenChanged(BRect frame, color_space format)
230 {
231 	_AdjustLocation(Frame());
232 }
233 
234 // WorkspaceActivated
235 void
236 MainWindow::WorkspaceActivated(int32 workspace, bool active)
237 {
238 	if (fShowOnAllWorkspaces) {
239 		if (!active) {
240 			SetWorkspaces(1 << current_workspace());
241 			_AdjustLocation(Frame());
242 		} else
243 			_GetLocation();
244 	}
245 }
246 
247 // FrameMoved
248 void
249 MainWindow::FrameMoved(BPoint origin)
250 {
251 	if (IsActive())
252 		_GetLocation();
253 }
254 
255 // FrameResized
256 void
257 MainWindow::FrameResized(float width, float height)
258 {
259 	if (IsActive())
260 		_GetLocation();
261 	BWindow::FrameResized(width, height);
262 }
263 
264 // ToggleAutoRaise
265 void
266 MainWindow::ToggleAutoRaise()
267 {
268 	fAutoRaise = !fAutoRaise;
269 	if (fAutoRaise)
270 		fPadView->SetEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
271 	else
272 		fPadView->SetEventMask(0);
273 }
274 
275 // LoadSettings
276 bool
277 MainWindow::LoadSettings(const BMessage* message)
278 {
279 	// restore window positioning
280 	BPoint point;
281 	bool useAdjust = false;
282 	if (message->FindPoint("window position", &point) == B_OK) {
283 		fScreenPosition = point;
284 		useAdjust = true;
285 	}
286 	float borderDist;
287 	if (message->FindFloat("border distance", &borderDist) == B_OK) {
288 		fBorderDist = borderDist;
289 	}
290 	// restore window frame
291 	BRect frame;
292 	if (message->FindRect("window frame", &frame) == B_OK) {
293 		if (useAdjust) {
294 			_AdjustLocation(frame);
295 		} else {
296 			make_sure_frame_is_on_screen(frame, this);
297 			MoveTo(frame.LeftTop());
298 			ResizeTo(frame.Width(), frame.Height());
299 		}
300 	}
301 
302 	// restore name panel frame
303 	if (message->FindRect("name panel frame", &frame) == B_OK) {
304 		if (frame.IsValid()) {
305 			make_sure_frame_is_on_screen(frame, this);
306 			fNamePanelFrame = frame;
307 		}
308 	}
309 
310 	// restore window look
311 	window_look look;
312 	if (message->FindInt32("window look", (int32*)&look) == B_OK)
313 		SetLook(look);
314 
315 	// restore orientation
316 	int32 orientation;
317 	if (message->FindInt32("orientation", &orientation) == B_OK)
318 		fPadView->SetOrientation((enum orientation)orientation);
319 
320 	// restore buttons
321 	const char* path;
322 	bool buttonAdded = false;
323 	for (int32 i = 0; message->FindString("path", i, &path) >= B_OK; i++) {
324 		LaunchButton* button = new LaunchButton("launch button", fLastID++, NULL,
325 												new BMessage(MSG_LAUNCH));
326 		fPadView->AddButton(button);
327 		BString signature;
328 		if (message->FindString("signature", i, &signature) >= B_OK
329 			&& signature.CountChars() > 0)  {
330 			button->SetTo(signature.String(), true);
331 		} else {
332 			entry_ref ref;
333 			if (get_ref_for_path(path, &ref) >= B_OK)
334 				button->SetTo(&ref);
335 		}
336 		const char* text;
337 		if (message->FindString("description", i, &text) >= B_OK)
338 			button->SetDescription(text);
339 		buttonAdded = true;
340 	}
341 
342 	// restore auto raise setting
343 	bool autoRaise;
344 	if (message->FindBool("auto raise", &autoRaise) == B_OK && autoRaise)
345 		ToggleAutoRaise();
346 
347 	// store workspace setting
348 	bool showOnAllWorkspaces;
349 	if (message->FindBool("all workspaces", &showOnAllWorkspaces) == B_OK)
350 		fShowOnAllWorkspaces = showOnAllWorkspaces;
351 	if (!fShowOnAllWorkspaces) {
352 		uint32 workspaces;
353 		if (message->FindInt32("workspaces", (int32*)&workspaces) == B_OK)
354 			SetWorkspaces(workspaces);
355 	}
356 
357 	return buttonAdded;
358 }
359 
360 // SaveSettings
361 void
362 MainWindow::SaveSettings(BMessage* message)
363 {
364 	// make sure the positioning info is correct
365 	_GetLocation();
366 	// store window position
367 	if (message->ReplacePoint("window position", fScreenPosition) != B_OK)
368 		message->AddPoint("window position", fScreenPosition);
369 
370 	if (message->ReplaceFloat("border distance", fBorderDist) != B_OK)
371 		message->AddFloat("border distance", fBorderDist);
372 
373 	// store window frame
374 	if (message->ReplaceRect("window frame", Frame()) != B_OK)
375 		message->AddRect("window frame", Frame());
376 
377 	// store name panel frame
378 	if (message->ReplaceRect("name panel frame", fNamePanelFrame) != B_OK)
379 		message->AddRect("name panel frame", fNamePanelFrame);
380 
381 	if (message->ReplaceInt32("window look", Look()) != B_OK)
382 		message->AddInt32("window look", Look());
383 
384 	// store orientation
385 	if (message->ReplaceInt32("orientation",
386 			(int32)fPadView->Orientation()) != B_OK)
387 		message->AddInt32("orientation", (int32)fPadView->Orientation());
388 
389 	// store buttons
390 	message->RemoveName("path");
391 	message->RemoveName("description");
392 	message->RemoveName("signature");
393 	for (int32 i = 0; LaunchButton* button = fPadView->ButtonAt(i); i++) {
394 		BPath path(button->Ref());
395 		if (path.InitCheck() >= B_OK)
396 			message->AddString("path", path.Path());
397 		else
398 			message->AddString("path", "");
399 		message->AddString("description", button->Description());
400 
401 		if (button->AppSignature())
402 			message->AddString("signature", button->AppSignature());
403 		else
404 			message->AddString("signature", "");
405 	}
406 
407 	// store auto raise setting
408 	if (message->ReplaceBool("auto raise", fAutoRaise) != B_OK)
409 		message->AddBool("auto raise", fAutoRaise);
410 
411 	// store workspace setting
412 	if (message->ReplaceBool("all workspaces", fShowOnAllWorkspaces) != B_OK)
413 		message->AddBool("all workspaces", fShowOnAllWorkspaces);
414 	if (message->ReplaceInt32("workspaces", Workspaces()) != B_OK)
415 		message->AddInt32("workspaces", Workspaces());
416 }
417 
418 // _GetLocation
419 void
420 MainWindow::_GetLocation()
421 {
422 	BRect frame = Frame();
423 	BPoint origin = frame.LeftTop();
424 	BPoint center(origin.x + frame.Width() / 2.0, origin.y + frame.Height() / 2.0);
425 	BScreen screen(this);
426 	BRect screenFrame = screen.Frame();
427 	fScreenPosition.x = center.x / screenFrame.Width();
428 	fScreenPosition.y = center.y / screenFrame.Height();
429 	if (fabs(0.5 - fScreenPosition.x) > fabs(0.5 - fScreenPosition.y)) {
430 		// nearest to left or right border
431 		if (fScreenPosition.x < 0.5)
432 			fBorderDist = frame.left - screenFrame.left;
433 		else
434 			fBorderDist = screenFrame.right - frame.right;
435 	} else {
436 		// nearest to top or bottom border
437 		if (fScreenPosition.y < 0.5)
438 			fBorderDist = frame.top - screenFrame.top;
439 		else
440 			fBorderDist = screenFrame.bottom - frame.bottom;
441 	}
442 }
443 
444 // _AdjustLocation
445 void
446 MainWindow::_AdjustLocation(BRect frame)
447 {
448 	BScreen screen(this);
449 	BRect screenFrame = screen.Frame();
450 	BPoint center(fScreenPosition.x * screenFrame.Width(),
451 				  fScreenPosition.y * screenFrame.Height());
452 	BPoint frameCenter(frame.left + frame.Width() / 2.0,
453 					   frame.top + frame.Height() / 2.0);
454 	frame.OffsetBy(center - frameCenter);
455 	// ignore border dist when distance too large
456 	if (fBorderDist < 10.0) {
457 		// see which border we mean depending on screen position
458 		BPoint offset(0.0, 0.0);
459 		if (fabs(0.5 - fScreenPosition.x) > fabs(0.5 - fScreenPosition.y)) {
460 			// left or right border
461 			if (fScreenPosition.x < 0.5)
462 				offset.x = (screenFrame.left + fBorderDist) - frame.left;
463 			else
464 				offset.x = (screenFrame.right - fBorderDist) - frame.right;
465 		} else {
466 			// top or bottom border
467 			if (fScreenPosition.y < 0.5)
468 				offset.y = (screenFrame.top + fBorderDist) - frame.top;
469 			else
470 				offset.y = (screenFrame.bottom - fBorderDist) - frame.bottom;
471 		}
472 		frame.OffsetBy(offset);
473 	}
474 
475 	make_sure_frame_is_on_screen(frame, this);
476 
477 	MoveTo(frame.LeftTop());
478 	ResizeTo(frame.Width(), frame.Height());
479 }
480 
481 // _AddDefaultButtons
482 void
483 MainWindow::_AddDefaultButtons()
484 {
485 	// Mail
486 	LaunchButton* button = new LaunchButton("launch button", fLastID++, NULL,
487 		new BMessage(MSG_LAUNCH));
488 	fPadView->AddButton(button);
489 	button->SetTo("application/x-vnd.Be-MAIL", true);
490 
491 	// StyledEdit
492 	button = new LaunchButton("launch button", fLastID++, NULL,
493 		new BMessage(MSG_LAUNCH));
494 	fPadView->AddButton(button);
495 	button->SetTo("application/x-vnd.Haiku-StyledEdit", true);
496 
497 	// ShowImage
498 	button = new LaunchButton("launch button", fLastID++, NULL,
499 		new BMessage(MSG_LAUNCH));
500 	fPadView->AddButton(button);
501 	button->SetTo("application/x-vnd.Haiku-ShowImage", true);
502 
503 	// MediaPlayer
504 	button = new LaunchButton("launch button", fLastID++, NULL,
505 		new BMessage(MSG_LAUNCH));
506 	fPadView->AddButton(button);
507 	button->SetTo("application/x-vnd.Haiku-MediaPlayer", true);
508 
509 	// DeskCalc
510 	button = new LaunchButton("launch button", fLastID++, NULL,
511 		new BMessage(MSG_LAUNCH));
512 	fPadView->AddButton(button);
513 	button->SetTo("application/x-vnd.Haiku-DeskCalc", true);
514 
515 	// Terminal
516 	button = new LaunchButton("launch button", fLastID++, NULL,
517 		new BMessage(MSG_LAUNCH));
518 	fPadView->AddButton(button);
519 	button->SetTo("application/x-vnd.Haiku-Terminal", true);
520 }
521 
522 // _AddEmptyButtons
523 void
524 MainWindow::_AddEmptyButtons()
525 {
526 	LaunchButton* button = new LaunchButton("launch button", fLastID++, NULL,
527 		new BMessage(MSG_LAUNCH));
528 	fPadView->AddButton(button);
529 
530 	button = new LaunchButton("launch button", fLastID++, NULL,
531 		new BMessage(MSG_LAUNCH));
532 	fPadView->AddButton(button);
533 
534 	button = new LaunchButton("launch button", fLastID++, NULL,
535 		new BMessage(MSG_LAUNCH));
536 	fPadView->AddButton(button);
537 }
538 
539 
540