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