1 /* 2 * MainWin.cpp - Media Player for the Haiku Operating System 3 * 4 * Copyright (C) 2006 Marcus Overhagen <marcus@overhagen.de> 5 * Copyright (C) 2007-2009 Stephan Aßmus <superstippi@gmx.de> (GPL->MIT ok) 6 * Copyright (C) 2007-2009 Fredrik Modéen <[FirstName]@[LastName].se> (MIT ok) 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * version 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 20 * USA. 21 * 22 */ 23 24 #include "MainWin.h" 25 26 #include <math.h> 27 #include <stdio.h> 28 #include <string.h> 29 30 #include <Alert.h> 31 #include <Application.h> 32 #include <Autolock.h> 33 #include <Debug.h> 34 #include <Menu.h> 35 #include <MenuBar.h> 36 #include <MenuItem.h> 37 #include <Messenger.h> 38 #include <PopUpMenu.h> 39 #include <RecentItems.h> 40 #include <Roster.h> 41 #include <Screen.h> 42 #include <String.h> 43 #include <View.h> 44 45 #include "AudioProducer.h" 46 #include "ControllerObserver.h" 47 #include "MainApp.h" 48 #include "PeakView.h" 49 #include "PlaylistItem.h" 50 #include "PlaylistObserver.h" 51 #include "PlaylistWindow.h" 52 #include "Settings.h" 53 54 #define NAME "MediaPlayer" 55 #define MIN_WIDTH 250 56 57 58 // XXX TODO: why is lround not defined? 59 #define lround(a) ((int)(0.99999 + (a))) 60 61 enum { 62 M_DUMMY = 0x100, 63 M_FILE_OPEN = 0x1000, 64 M_FILE_NEWPLAYER, 65 M_FILE_INFO, 66 M_FILE_PLAYLIST, 67 M_FILE_CLOSE, 68 M_FILE_QUIT, 69 M_VIEW_50, 70 M_VIEW_100, 71 M_VIEW_200, 72 M_VIEW_300, 73 M_VIEW_400, 74 M_TOGGLE_FULLSCREEN, 75 M_TOGGLE_NO_BORDER, 76 M_TOGGLE_NO_MENU, 77 M_TOGGLE_NO_CONTROLS, 78 M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS, 79 M_TOGGLE_ALWAYS_ON_TOP, 80 M_TOGGLE_KEEP_ASPECT_RATIO, 81 M_VOLUME_UP, 82 M_VOLUME_DOWN, 83 M_SKIP_NEXT, 84 M_SKIP_PREV, 85 M_ASPECT_100000_1, 86 M_ASPECT_106666_1, 87 M_ASPECT_109091_1, 88 M_ASPECT_141176_1, 89 M_ASPECT_720_576, 90 M_ASPECT_704_576, 91 M_ASPECT_544_576, 92 M_SELECT_AUDIO_TRACK = 0x00000800, 93 M_SELECT_AUDIO_TRACK_END = 0x00000fff, 94 M_SELECT_VIDEO_TRACK = 0x00010000, 95 M_SELECT_VIDEO_TRACK_END = 0x000fffff, 96 97 M_SET_PLAYLIST_POSITION, 98 99 M_FILE_DELETE 100 }; 101 102 //#define printf(a...) 103 104 105 MainWin::MainWin() 106 : BWindow(BRect(100,100,400,300), NAME, B_TITLED_WINDOW, 107 B_ASYNCHRONOUS_CONTROLS /* | B_WILL_ACCEPT_FIRST_CLICK */), 108 fInfoWin(NULL), 109 fPlaylistWindow(NULL), 110 fHasFile(false), 111 fHasVideo(false), 112 fHasAudio(false), 113 fPlaylist(new Playlist), 114 fPlaylistObserver(new PlaylistObserver(this)), 115 fController(new Controller), 116 fControllerObserver(new ControllerObserver(this, 117 OBSERVE_FILE_CHANGES | OBSERVE_TRACK_CHANGES 118 | OBSERVE_PLAYBACK_STATE_CHANGES | OBSERVE_POSITION_CHANGES 119 | OBSERVE_VOLUME_CHANGES)), 120 fIsFullscreen(false), 121 fKeepAspectRatio(true), 122 fAlwaysOnTop(false), 123 fNoMenu(false), 124 fNoBorder(false), 125 fNoControls(false), 126 fSourceWidth(-1), 127 fSourceHeight(-1), 128 fWidthScale(1.0), 129 fHeightScale(1.0), 130 fMouseDownTracking(false), 131 fGlobalSettingsListener(this) 132 { 133 static int pos = 0; 134 MoveBy(pos * 25, pos * 25); 135 pos = (pos + 1) % 15; 136 137 BRect rect = Bounds(); 138 139 // background 140 fBackground = new BView(rect, "background", B_FOLLOW_ALL, 141 B_WILL_DRAW | B_FULL_UPDATE_ON_RESIZE); 142 fBackground->SetViewColor(0,0,0); 143 AddChild(fBackground); 144 145 // menu 146 fMenuBar = new BMenuBar(fBackground->Bounds(), "menu"); 147 _CreateMenu(); 148 fBackground->AddChild(fMenuBar); 149 fMenuBar->SetResizingMode(B_FOLLOW_NONE); 150 fMenuBar->ResizeToPreferred(); 151 fMenuBarWidth = (int)fMenuBar->Frame().Width() + 1; 152 fMenuBarHeight = (int)fMenuBar->Frame().Height() + 1; 153 154 // video view 155 rect = BRect(0, fMenuBarHeight, fBackground->Bounds().right, 156 fMenuBarHeight + 10); 157 fVideoView = new VideoView(rect, "video display", B_FOLLOW_NONE); 158 fBackground->AddChild(fVideoView); 159 160 // controls 161 rect = BRect(0, fMenuBarHeight + 11, fBackground->Bounds().right, 162 fBackground->Bounds().bottom); 163 fControls = new ControllerView(rect, fController, fPlaylist); 164 fBackground->AddChild(fControls); 165 fControls->ResizeToPreferred(); 166 fControlsHeight = (int)fControls->Frame().Height() + 1; 167 fControlsWidth = (int)fControls->Frame().Width() + 1; 168 fControls->SetResizingMode(B_FOLLOW_BOTTOM | B_FOLLOW_LEFT_RIGHT); 169 // fControls->MoveTo(0, fBackground->Bounds().bottom - fControlsHeight + 1); 170 171 // fVideoView->ResizeTo(fBackground->Bounds().Width(), 172 // fBackground->Bounds().Height() - fMenuBarHeight - fControlsHeight); 173 174 fPlaylist->AddListener(fPlaylistObserver); 175 fController->SetVideoView(fVideoView); 176 fController->AddListener(fControllerObserver); 177 PeakView* peakView = fControls->GetPeakView(); 178 peakView->SetPeakNotificationWhat(MSG_PEAK_NOTIFICATION); 179 fController->SetPeakListener(peakView); 180 181 // printf("fMenuBarHeight %d\n", fMenuBarHeight); 182 // printf("fControlsHeight %d\n", fControlsHeight); 183 // printf("fControlsWidth %d\n", fControlsWidth); 184 185 _SetupWindow(); 186 187 // setup the playlist window now, we need to have it 188 // running for the undo/redo playlist editing 189 fPlaylistWindow = new PlaylistWindow(BRect(150, 150, 500, 600), fPlaylist, 190 fController); 191 fPlaylistWindow->Hide(); 192 fPlaylistWindow->Show(); 193 // this makes sure the window thread is running without 194 // showing the window just yet 195 196 Settings::Default()->AddListener(&fGlobalSettingsListener); 197 _AdoptGlobalSettings(); 198 199 AddShortcut('z', B_COMMAND_KEY, new BMessage(B_UNDO)); 200 AddShortcut('y', B_COMMAND_KEY, new BMessage(B_UNDO)); 201 AddShortcut('z', B_COMMAND_KEY | B_SHIFT_KEY, new BMessage(B_REDO)); 202 AddShortcut('y', B_COMMAND_KEY | B_SHIFT_KEY, new BMessage(B_REDO)); 203 204 Show(); 205 } 206 207 208 MainWin::~MainWin() 209 { 210 // printf("MainWin::~MainWin\n"); 211 212 Settings::Default()->RemoveListener(&fGlobalSettingsListener); 213 fPlaylist->RemoveListener(fPlaylistObserver); 214 fController->RemoveListener(fControllerObserver); 215 fController->SetPeakListener(NULL); 216 217 // give the views a chance to detach from any notifiers 218 // before we delete them 219 fBackground->RemoveSelf(); 220 delete fBackground; 221 222 if (fInfoWin && fInfoWin->Lock()) 223 fInfoWin->Quit(); 224 225 if (fPlaylistWindow && fPlaylistWindow->Lock()) 226 fPlaylistWindow->Quit(); 227 228 delete fPlaylist; 229 230 // quit the Controller looper thread 231 thread_id controllerThread = fController->Thread(); 232 fController->PostMessage(B_QUIT_REQUESTED); 233 status_t exitValue; 234 wait_for_thread(controllerThread, &exitValue); 235 } 236 237 238 // #pragma mark - 239 240 241 void 242 MainWin::FrameResized(float newWidth, float newHeight) 243 { 244 if (newWidth != Bounds().Width() || newHeight != Bounds().Height()) { 245 debugger("size wrong\n"); 246 } 247 248 bool noMenu = fNoMenu || fIsFullscreen; 249 bool noControls = fNoControls || fIsFullscreen; 250 251 // printf("FrameResized enter: newWidth %.0f, newHeight %.0f\n", 252 // newWidth, newHeight); 253 254 int maxVideoWidth = int(newWidth) + 1; 255 int maxVideoHeight = int(newHeight) + 1 256 - (noMenu ? 0 : fMenuBarHeight) 257 - (noControls ? 0 : fControlsHeight); 258 259 ASSERT(maxVideoHeight >= 0); 260 261 int y = 0; 262 263 if (noMenu) { 264 if (!fMenuBar->IsHidden()) 265 fMenuBar->Hide(); 266 } else { 267 // fMenuBar->MoveTo(0, y); 268 fMenuBar->ResizeTo(newWidth, fMenuBarHeight - 1); 269 if (fMenuBar->IsHidden()) 270 fMenuBar->Show(); 271 y += fMenuBarHeight; 272 } 273 274 if (maxVideoHeight == 0) { 275 bool hidden = fVideoView->IsHidden(); 276 // printf(" video view hidden: %d\n", hidden); 277 if (!hidden) 278 fVideoView->Hide(); 279 } else { 280 _ResizeVideoView(0, y, maxVideoWidth, maxVideoHeight); 281 if (fVideoView->IsHidden()) 282 fVideoView->Show(); 283 y += maxVideoHeight; 284 } 285 286 if (noControls) { 287 if (!fControls->IsHidden()) 288 fControls->Hide(); 289 } else { 290 fControls->MoveTo(0, y); 291 fControls->ResizeTo(newWidth, fControlsHeight - 1); 292 if (fControls->IsHidden()) 293 fControls->Show(); 294 // y += fControlsHeight; 295 } 296 297 // printf("FrameResized leave\n"); 298 } 299 300 301 void 302 MainWin::Zoom(BPoint rec_position, float rec_width, float rec_height) 303 { 304 PostMessage(M_TOGGLE_FULLSCREEN); 305 } 306 307 308 void 309 MainWin::DispatchMessage(BMessage *msg, BHandler *handler) 310 { 311 if ((msg->what == B_MOUSE_DOWN) 312 && (handler == fBackground || handler == fVideoView 313 || handler == fControls)) 314 _MouseDown(msg, dynamic_cast<BView*>(handler)); 315 316 if ((msg->what == B_MOUSE_MOVED) 317 && (handler == fBackground || handler == fVideoView 318 || handler == fControls)) 319 _MouseMoved(msg, dynamic_cast<BView*>(handler)); 320 321 if ((msg->what == B_MOUSE_UP) 322 && (handler == fBackground || handler == fVideoView)) 323 _MouseUp(msg); 324 325 if ((msg->what == B_KEY_DOWN) 326 && (handler == fBackground || handler == fVideoView)) { 327 328 // special case for PrintScreen key 329 if (msg->FindInt32("key") == B_PRINT_KEY) { 330 fVideoView->OverlayScreenshotPrepare(); 331 BWindow::DispatchMessage(msg, handler); 332 fVideoView->OverlayScreenshotCleanup(); 333 return; 334 } 335 336 // every other key gets dispatched to our _KeyDown first 337 if (_KeyDown(msg) == B_OK) { 338 // it got handled, don't pass it on 339 return; 340 } 341 } 342 343 BWindow::DispatchMessage(msg, handler); 344 } 345 346 347 void 348 MainWin::MessageReceived(BMessage *msg) 349 { 350 // msg->PrintToStream(); 351 switch (msg->what) { 352 case B_REFS_RECEIVED: 353 printf("MainWin::MessageReceived: B_REFS_RECEIVED\n"); 354 _RefsReceived(msg); 355 break; 356 case B_SIMPLE_DATA: 357 printf("MainWin::MessageReceived: B_SIMPLE_DATA\n"); 358 if (msg->HasRef("refs")) { 359 // add to recent documents as it's not done with drag-n-drop 360 entry_ref ref; 361 for (int32 i = 0; msg->FindRef("refs", i, &ref) == B_OK; i++) { 362 be_roster->AddToRecentDocuments(&ref, kAppSig); 363 } 364 _RefsReceived(msg); 365 } 366 break; 367 368 case B_UNDO: 369 case B_REDO: 370 fPlaylistWindow->PostMessage(msg); 371 break; 372 373 case M_MEDIA_SERVER_STARTED: 374 printf("TODO: implement M_MEDIA_SERVER_STARTED\n"); 375 // fController->... 376 break; 377 378 case M_MEDIA_SERVER_QUIT: 379 printf("TODO: implement M_MEDIA_SERVER_QUIT\n"); 380 // fController->... 381 break; 382 383 // PlaylistObserver messages 384 case MSG_PLAYLIST_ITEM_ADDED: 385 { 386 PlaylistItem* item; 387 int32 index; 388 if (msg->FindPointer("item", (void**)&item) == B_OK 389 && msg->FindInt32("index", &index) == B_OK) { 390 _AddPlaylistItem(item, index); 391 } 392 break; 393 } 394 case MSG_PLAYLIST_ITEM_REMOVED: 395 { 396 int32 index; 397 if (msg->FindInt32("index", &index) == B_OK) 398 _RemovePlaylistItem(index); 399 break; 400 } 401 case MSG_PLAYLIST_CURRENT_ITEM_CHANGED: 402 { 403 BAutolock _(fPlaylist); 404 405 int32 index; 406 if (msg->FindInt32("index", &index) < B_OK 407 || index != fPlaylist->CurrentItemIndex()) 408 break; 409 PlaylistItemRef item(fPlaylist->ItemAt(index)); 410 if (item.Get() != NULL) { 411 printf("open playlist item: %s\n", item->Name().String()); 412 OpenPlaylistItem(item); 413 _MarkPlaylistItem(index); 414 } 415 break; 416 } 417 418 // ControllerObserver messages 419 case MSG_CONTROLLER_FILE_FINISHED: 420 { 421 BAutolock _(fPlaylist); 422 423 bool hadNext = fPlaylist->SetCurrentItemIndex( 424 fPlaylist->CurrentItemIndex() + 1); 425 if (!hadNext) { 426 if (fHasVideo) { 427 if (fCloseWhenDonePlayingMovie) 428 PostMessage(B_QUIT_REQUESTED); 429 } else { 430 if (fCloseWhenDonePlayingSound) 431 PostMessage(B_QUIT_REQUESTED); 432 } 433 } 434 break; 435 } 436 case MSG_CONTROLLER_FILE_CHANGED: 437 // TODO: move all other GUI changes as a reaction to this 438 // notification 439 // _UpdatePlaylistMenu(); 440 break; 441 case MSG_CONTROLLER_VIDEO_TRACK_CHANGED: 442 { 443 int32 index; 444 if (msg->FindInt32("index", &index) == B_OK) { 445 BMenuItem* item = fVideoTrackMenu->ItemAt(index); 446 if (item) 447 item->SetMarked(true); 448 } 449 break; 450 } 451 case MSG_CONTROLLER_AUDIO_TRACK_CHANGED: 452 { 453 int32 index; 454 if (msg->FindInt32("index", &index) == B_OK) { 455 BMenuItem* item = fAudioTrackMenu->ItemAt(index); 456 if (item) 457 item->SetMarked(true); 458 } 459 break; 460 } 461 case MSG_CONTROLLER_PLAYBACK_STATE_CHANGED: 462 { 463 uint32 state; 464 if (msg->FindInt32("state", (int32*)&state) == B_OK) 465 fControls->SetPlaybackState(state); 466 break; 467 } 468 case MSG_CONTROLLER_POSITION_CHANGED: 469 { 470 float position; 471 if (msg->FindFloat("position", &position) == B_OK) 472 fControls->SetPosition(position); 473 break; 474 } 475 case MSG_CONTROLLER_VOLUME_CHANGED: 476 { 477 float volume; 478 if (msg->FindFloat("volume", &volume) == B_OK) 479 fControls->SetVolume(volume); 480 break; 481 } 482 case MSG_CONTROLLER_MUTED_CHANGED: 483 { 484 bool muted; 485 if (msg->FindBool("muted", &muted) == B_OK) 486 fControls->SetMuted(muted); 487 break; 488 } 489 490 // menu item messages 491 case M_FILE_NEWPLAYER: 492 gMainApp->NewWindow(); 493 break; 494 case M_FILE_OPEN: 495 { 496 BMessenger target(this); 497 BMessage result(B_REFS_RECEIVED); 498 BMessage appMessage(M_SHOW_OPEN_PANEL); 499 appMessage.AddMessenger("target", target); 500 appMessage.AddMessage("message", &result); 501 appMessage.AddString("title", "Open Clips"); 502 appMessage.AddString("label", "Open"); 503 be_app->PostMessage(&appMessage); 504 break; 505 } 506 case M_FILE_INFO: 507 ShowFileInfo(); 508 break; 509 case M_FILE_PLAYLIST: 510 ShowPlaylistWindow(); 511 break; 512 case B_ABOUT_REQUESTED: 513 { 514 BAlert *alert; 515 alert = new BAlert("about", NAME"\n\n Written by Marcus Overhagen " 516 ", Stephan Aßmus and Frederik Modéen", "Thanks"); 517 if (fAlwaysOnTop) { 518 _ToggleAlwaysOnTop(); 519 alert->Go(NULL); // Asynchronous mode 520 _ToggleAlwaysOnTop(); 521 } else { 522 alert->Go(NULL); // Asynchronous mode 523 } 524 break; 525 } 526 case M_FILE_CLOSE: 527 PostMessage(B_QUIT_REQUESTED); 528 break; 529 case M_FILE_QUIT: 530 be_app->PostMessage(B_QUIT_REQUESTED); 531 break; 532 533 case M_TOGGLE_FULLSCREEN: 534 _ToggleFullscreen(); 535 break; 536 537 case M_TOGGLE_NO_MENU: 538 _ToggleNoMenu(); 539 break; 540 541 case M_TOGGLE_NO_CONTROLS: 542 _ToggleNoControls(); 543 break; 544 545 case M_TOGGLE_NO_BORDER: 546 _ToggleNoBorder(); 547 break; 548 549 case M_TOGGLE_ALWAYS_ON_TOP: 550 _ToggleAlwaysOnTop(); 551 break; 552 553 case M_TOGGLE_KEEP_ASPECT_RATIO: 554 _ToggleKeepAspectRatio(); 555 break; 556 557 case M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS: 558 _ToggleNoBorderNoMenu(); 559 break; 560 561 case M_VIEW_50: 562 if (!fHasVideo) 563 break; 564 if (fIsFullscreen) 565 _ToggleFullscreen(); 566 _ResizeWindow(50); 567 break; 568 569 case M_VIEW_100: 570 if (!fHasVideo) 571 break; 572 if (fIsFullscreen) 573 _ToggleFullscreen(); 574 _ResizeWindow(100); 575 break; 576 577 case M_VIEW_200: 578 if (!fHasVideo) 579 break; 580 if (fIsFullscreen) 581 _ToggleFullscreen(); 582 _ResizeWindow(200); 583 break; 584 585 case M_VIEW_300: 586 if (!fHasVideo) 587 break; 588 if (fIsFullscreen) 589 _ToggleFullscreen(); 590 _ResizeWindow(300); 591 break; 592 593 case M_VIEW_400: 594 if (!fHasVideo) 595 break; 596 if (fIsFullscreen) 597 _ToggleFullscreen(); 598 _ResizeWindow(400); 599 break; 600 /* 601 case B_ACQUIRE_OVERLAY_LOCK: 602 printf("B_ACQUIRE_OVERLAY_LOCK\n"); 603 fVideoView->OverlayLockAcquire(); 604 break; 605 606 case B_RELEASE_OVERLAY_LOCK: 607 printf("B_RELEASE_OVERLAY_LOCK\n"); 608 fVideoView->OverlayLockRelease(); 609 break; 610 */ 611 case B_MOUSE_WHEEL_CHANGED: 612 { 613 float dx = msg->FindFloat("be:wheel_delta_x"); 614 float dy = msg->FindFloat("be:wheel_delta_y"); 615 bool inv = modifiers() & B_COMMAND_KEY; 616 if (dx > 0.1) PostMessage(inv ? M_VOLUME_DOWN : M_SKIP_PREV); 617 if (dx < -0.1) PostMessage(inv ? M_VOLUME_UP : M_SKIP_NEXT); 618 if (dy > 0.1) PostMessage(inv ? M_SKIP_PREV : M_VOLUME_DOWN); 619 if (dy < -0.1) PostMessage(inv ? M_SKIP_NEXT : M_VOLUME_UP); 620 break; 621 } 622 623 case M_SKIP_NEXT: 624 fControls->SkipForward(); 625 break; 626 627 case M_SKIP_PREV: 628 fControls->SkipBackward(); 629 break; 630 631 case M_VOLUME_UP: 632 fController->VolumeUp(); 633 break; 634 635 case M_VOLUME_DOWN: 636 fController->VolumeDown(); 637 break; 638 639 case M_ASPECT_100000_1: 640 VideoFormatChange(fSourceWidth, fSourceHeight, 1.0, 1.0); 641 break; 642 643 case M_ASPECT_106666_1: 644 VideoFormatChange(fSourceWidth, fSourceHeight, 1.06666, 1.0); 645 break; 646 647 case M_ASPECT_109091_1: 648 VideoFormatChange(fSourceWidth, fSourceHeight, 1.09091, 1.0); 649 break; 650 651 case M_ASPECT_141176_1: 652 VideoFormatChange(fSourceWidth, fSourceHeight, 1.41176, 1.0); 653 break; 654 655 case M_ASPECT_720_576: 656 VideoFormatChange(720, 576, 1.06666, 1.0); 657 break; 658 659 case M_ASPECT_704_576: 660 VideoFormatChange(704, 576, 1.09091, 1.0); 661 break; 662 663 case M_ASPECT_544_576: 664 VideoFormatChange(544, 576, 1.41176, 1.0); 665 break; 666 667 /* 668 default: 669 if (msg->what >= M_SELECT_CHANNEL 670 && msg->what <= M_SELECT_CHANNEL_END) { 671 SelectChannel(msg->what - M_SELECT_CHANNEL); 672 break; 673 } 674 if (msg->what >= M_SELECT_INTERFACE 675 && msg->what <= M_SELECT_INTERFACE_END) { 676 SelectInterface(msg->what - M_SELECT_INTERFACE - 1); 677 break; 678 } 679 */ 680 case M_SET_PLAYLIST_POSITION: 681 { 682 BAutolock _(fPlaylist); 683 684 int32 index; 685 if (msg->FindInt32("index", &index) == B_OK) 686 fPlaylist->SetCurrentItemIndex(index); 687 break; 688 } 689 690 case MSG_OBJECT_CHANGED: 691 // received from fGlobalSettingsListener 692 // TODO: find out which object, if we ever watch more than 693 // the global settings instance... 694 _AdoptGlobalSettings(); 695 break; 696 697 default: 698 // let BWindow handle the rest 699 BWindow::MessageReceived(msg); 700 } 701 } 702 703 704 void 705 MainWin::WindowActivated(bool active) 706 { 707 if (active) { 708 BScreen screen(this); 709 BRect screenFrame = screen.Frame(); 710 BRect frame = Frame(); 711 float diffX = 0.0; 712 float diffY = 0.0; 713 714 // If the frame is off the edge of the screen at all 715 // we will move it so all the window is on the screen. 716 if (frame.right > screenFrame.right) 717 // Move left 718 diffX = screenFrame.right - frame.right; 719 if (frame.bottom > screenFrame.bottom) 720 // Move up 721 diffY = screenFrame.bottom - frame.bottom; 722 if (frame.left < screenFrame.left) 723 // Move right 724 diffX = screenFrame.left - frame.left; 725 if (frame.top < screenFrame.top) 726 // Move down 727 diffY = screenFrame.top - frame.top; 728 729 MoveBy(diffX, diffY); 730 } 731 732 fController->PlayerActivated(active); 733 } 734 735 736 bool 737 MainWin::QuitRequested() 738 { 739 be_app->PostMessage(M_PLAYER_QUIT); 740 return true; 741 } 742 743 744 // #pragma mark - 745 746 747 void 748 MainWin::OpenPlaylistItem(const PlaylistItemRef& item) 749 { 750 printf("MainWin::OpenPlaylistItem\n"); 751 752 status_t err = fController->SetTo(item); 753 if (err != B_OK) { 754 BAutolock _(fPlaylist); 755 if (fPlaylist->CountItems() == 1) { 756 // display error if this is the only file we're supposed to play 757 BString message; 758 message << "The file '"; 759 message << item->Name(); 760 message << "' could not be opened.\n\n"; 761 762 if (err == B_MEDIA_NO_HANDLER) { 763 // give a more detailed message for the most likely of all 764 // errors 765 message << "There is no decoder installed to handle the " 766 "file format, or the decoder has trouble with the specific " 767 "version of the format."; 768 } else { 769 message << "Error: " << strerror(err); 770 } 771 (new BAlert("error", message.String(), "OK"))->Go(); 772 } else { 773 // just go to the next file and don't bother user 774 fPlaylist->SetCurrentItemIndex(fPlaylist->CurrentItemIndex() + 1); 775 } 776 fHasFile = false; 777 fHasVideo = false; 778 fHasAudio = false; 779 SetTitle(NAME); 780 } else { 781 fHasFile = true; 782 fHasVideo = fController->VideoTrackCount() != 0; 783 fHasAudio = fController->AudioTrackCount() != 0; 784 SetTitle(item->Name().String()); 785 } 786 _SetupWindow(); 787 } 788 789 790 void 791 MainWin::ShowFileInfo() 792 { 793 if (!fInfoWin) 794 fInfoWin = new InfoWin(Frame().LeftTop(), fController); 795 796 if (fInfoWin->Lock()) { 797 if (fInfoWin->IsHidden()) 798 fInfoWin->Show(); 799 else 800 fInfoWin->Activate(); 801 fInfoWin->Unlock(); 802 } 803 } 804 805 806 void 807 MainWin::ShowPlaylistWindow() 808 { 809 if (fPlaylistWindow->Lock()) { 810 // make sure the window shows on the same workspace as ourself 811 uint32 workspaces = Workspaces(); 812 if (fPlaylistWindow->Workspaces() != workspaces) 813 fPlaylistWindow->SetWorkspaces(workspaces); 814 815 // show or activate 816 if (fPlaylistWindow->IsHidden()) 817 fPlaylistWindow->Show(); 818 else 819 fPlaylistWindow->Activate(); 820 821 fPlaylistWindow->Unlock(); 822 } 823 } 824 825 826 void 827 MainWin::VideoFormatChange(int width, int height, float width_scale, 828 float height_scale) 829 { 830 // called when video format or aspect ratio changes 831 832 printf("VideoFormatChange enter: width %d, height %d, width_scale %.6f, " 833 "height_scale %.6f\n", width, height, width_scale, height_scale); 834 835 if (width_scale < 1.0 && height_scale >= 1.0) { 836 width_scale = 1.0 / width_scale; 837 height_scale = 1.0 / height_scale; 838 printf("inverting! new values: width_scale %.6f, height_scale %.6f\n", 839 width_scale, height_scale); 840 } 841 842 fSourceWidth = width; 843 fSourceHeight = height; 844 fWidthScale = width_scale; 845 fHeightScale = height_scale; 846 847 FrameResized(Bounds().Width(), Bounds().Height()); 848 849 printf("VideoFormatChange leave\n"); 850 } 851 852 853 // #pragma mark - 854 855 856 void 857 MainWin::_RefsReceived(BMessage* msg) 858 { 859 // the playlist ist replaced by dropped files 860 // or the dropped files are appended to the end 861 // of the existing playlist if <shift> is pressed 862 BAutolock _(fPlaylist); 863 int32 appendIndex = modifiers() & B_SHIFT_KEY ? 864 fPlaylist->CountItems() : -1; 865 msg->AddInt32("append_index", appendIndex); 866 867 // forward the message to the playlist window, 868 // so that undo/redo is used for modifying the playlist 869 fPlaylistWindow->PostMessage(msg); 870 } 871 872 873 void 874 MainWin::_SetupWindow() 875 { 876 // printf("MainWin::_SetupWindow\n"); 877 // Populate the track menus 878 _SetupTrackMenus(); 879 // Enable both if a file was loaded 880 fAudioTrackMenu->SetEnabled(fHasFile); 881 fVideoTrackMenu->SetEnabled(fHasFile); 882 883 fVideoMenu->SetEnabled(fHasVideo); 884 fAudioMenu->SetEnabled(fHasAudio); 885 // fDebugMenu->SetEnabled(fHasVideo); 886 int previousSourceWidth = fSourceWidth; 887 int previousSourceHeight = fSourceHeight; 888 if (fHasVideo) { 889 fController->GetSize(&fSourceWidth, &fSourceHeight); 890 fWidthScale = 1.0; 891 fHeightScale = 1.0; 892 // TODO: implement aspect ratio 893 } else { 894 fSourceWidth = 0; 895 fSourceHeight = 0; 896 fWidthScale = 1.0; 897 fHeightScale = 1.0; 898 } 899 _UpdateControlsEnabledStatus(); 900 901 // adopt the size and window layout if necessary 902 if (!fIsFullscreen && (previousSourceWidth != fSourceWidth 903 || previousSourceHeight != fSourceHeight)) { 904 _ResizeWindow(100); 905 } 906 907 fVideoView->MakeFocus(); 908 } 909 910 911 void 912 MainWin::_CreateMenu() 913 { 914 fFileMenu = new BMenu(NAME); 915 fPlaylistMenu = new BMenu("Playlist"B_UTF8_ELLIPSIS); 916 fAudioMenu = new BMenu("Audio"); 917 fVideoMenu = new BMenu("Video"); 918 fSettingsMenu = new BMenu("Settings"); 919 fAudioTrackMenu = new BMenu("Track"); 920 fVideoTrackMenu = new BMenu("Track"); 921 // fDebugMenu = new BMenu("Debug"); 922 923 fMenuBar->AddItem(fFileMenu); 924 fMenuBar->AddItem(fAudioMenu); 925 fMenuBar->AddItem(fVideoMenu); 926 fMenuBar->AddItem(fSettingsMenu); 927 // fMenuBar->AddItem(fDebugMenu); 928 929 fFileMenu->AddItem(new BMenuItem("New Player"B_UTF8_ELLIPSIS, 930 new BMessage(M_FILE_NEWPLAYER), 'N')); 931 fFileMenu->AddSeparatorItem(); 932 933 // fFileMenu->AddItem(new BMenuItem("Open File"B_UTF8_ELLIPSIS, 934 // new BMessage(M_FILE_OPEN), 'O')); 935 // Add recent files 936 BRecentFilesList recentFiles(10, false, NULL, kAppSig); 937 BMenuItem *item = new BMenuItem(recentFiles.NewFileListMenu( 938 "Open File"B_UTF8_ELLIPSIS, new BMessage(B_REFS_RECEIVED), 939 NULL, this, 10, false, NULL, 0, kAppSig), new BMessage(M_FILE_OPEN)); 940 item->SetShortcut('O', 0); 941 fFileMenu->AddItem(item); 942 943 fFileMenu->AddItem(new BMenuItem("File Info"B_UTF8_ELLIPSIS, 944 new BMessage(M_FILE_INFO), 'I')); 945 fFileMenu->AddItem(fPlaylistMenu); 946 fPlaylistMenu->Superitem()->SetShortcut('P', B_COMMAND_KEY); 947 fPlaylistMenu->Superitem()->SetMessage(new BMessage(M_FILE_PLAYLIST)); 948 949 fFileMenu->AddSeparatorItem(); 950 fFileMenu->AddItem(new BMenuItem("About " NAME B_UTF8_ELLIPSIS, 951 new BMessage(B_ABOUT_REQUESTED))); 952 fFileMenu->AddSeparatorItem(); 953 fFileMenu->AddItem(new BMenuItem("Close", new BMessage(M_FILE_CLOSE), 'W')); 954 fFileMenu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q')); 955 956 fPlaylistMenu->SetRadioMode(true); 957 958 fAudioMenu->AddItem(fAudioTrackMenu); 959 960 fVideoMenu->AddItem(fVideoTrackMenu); 961 fVideoMenu->AddSeparatorItem(); 962 fVideoMenu->AddItem(new BMenuItem("50% scale", 963 new BMessage(M_VIEW_50), '0')); 964 fVideoMenu->AddItem(new BMenuItem("100% scale", 965 new BMessage(M_VIEW_100), '1')); 966 fVideoMenu->AddItem(new BMenuItem("200% scale", 967 new BMessage(M_VIEW_200), '2')); 968 fVideoMenu->AddItem(new BMenuItem("300% scale", 969 new BMessage(M_VIEW_300), '3')); 970 fVideoMenu->AddItem(new BMenuItem("400% scale", 971 new BMessage(M_VIEW_400), '4')); 972 fVideoMenu->AddSeparatorItem(); 973 fVideoMenu->AddItem(new BMenuItem("Full Screen", 974 new BMessage(M_TOGGLE_FULLSCREEN), 'F')); 975 fVideoMenu->AddItem(new BMenuItem("Keep Aspect Ratio", 976 new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K')); 977 978 fSettingsMenu->AddItem(new BMenuItem("No Menu", 979 new BMessage(M_TOGGLE_NO_MENU), 'M')); 980 fSettingsMenu->AddItem(new BMenuItem("No Border", 981 new BMessage(M_TOGGLE_NO_BORDER), 'B')); 982 fSettingsMenu->AddItem(new BMenuItem("No Controls", 983 new BMessage(M_TOGGLE_NO_CONTROLS), 'C')); 984 fSettingsMenu->AddItem(new BMenuItem("Always on Top", 985 new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T')); 986 fSettingsMenu->AddSeparatorItem(); 987 item = new BMenuItem("Settings"B_UTF8_ELLIPSIS, 988 new BMessage(M_SETTINGS), 'S'); 989 fSettingsMenu->AddItem(item); 990 item->SetTarget(be_app); 991 992 // fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", 993 // new BMessage(M_ASPECT_100000_1))); 994 // fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", 995 // new BMessage(M_ASPECT_106666_1))); 996 // fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", 997 // new BMessage(M_ASPECT_109091_1))); 998 // fDebugMenu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", 999 // new BMessage(M_ASPECT_141176_1))); 1000 // fDebugMenu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", 1001 // new BMessage(M_ASPECT_720_576))); 1002 // fDebugMenu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", 1003 // new BMessage(M_ASPECT_704_576))); 1004 // fDebugMenu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", 1005 // new BMessage(M_ASPECT_544_576))); 1006 1007 fAudioTrackMenu->SetRadioMode(true); 1008 fVideoTrackMenu->SetRadioMode(true); 1009 } 1010 1011 1012 void 1013 MainWin::_SetupTrackMenus() 1014 { 1015 fAudioTrackMenu->RemoveItems(0, fAudioTrackMenu->CountItems(), true); 1016 fVideoTrackMenu->RemoveItems(0, fVideoTrackMenu->CountItems(), true); 1017 1018 char s[100]; 1019 1020 int count = fController->AudioTrackCount(); 1021 int current = fController->CurrentAudioTrack(); 1022 for (int i = 0; i < count; i++) { 1023 sprintf(s, "Track %d", i + 1); 1024 BMenuItem* item = new BMenuItem(s, 1025 new BMessage(M_SELECT_AUDIO_TRACK + i)); 1026 item->SetMarked(i == current); 1027 fAudioTrackMenu->AddItem(item); 1028 } 1029 if (!count) { 1030 fAudioTrackMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY))); 1031 fAudioTrackMenu->ItemAt(0)->SetMarked(true); 1032 } 1033 1034 1035 count = fController->VideoTrackCount(); 1036 current = fController->CurrentVideoTrack(); 1037 for (int i = 0; i < count; i++) { 1038 sprintf(s, "Track %d", i + 1); 1039 BMenuItem* item = new BMenuItem(s, 1040 new BMessage(M_SELECT_VIDEO_TRACK + i)); 1041 item->SetMarked(i == current); 1042 fVideoTrackMenu->AddItem(item); 1043 } 1044 if (!count) { 1045 fVideoTrackMenu->AddItem(new BMenuItem("none", new BMessage(M_DUMMY))); 1046 fVideoTrackMenu->ItemAt(0)->SetMarked(true); 1047 } 1048 } 1049 1050 1051 void 1052 MainWin::_SetWindowSizeLimits() 1053 { 1054 int minWidth = fNoControls ? MIN_WIDTH : fControlsWidth; 1055 if (!fNoMenu) 1056 minWidth = max_c(minWidth, fMenuBarWidth); 1057 int minHeight = (fNoMenu ? 0 : fMenuBarHeight) 1058 + (fNoControls ? 0 : fControlsHeight); 1059 1060 SetSizeLimits(minWidth - 1, 32000, minHeight - 1, fHasVideo ? 1061 32000 : minHeight - 1); 1062 } 1063 1064 1065 void 1066 MainWin::_ResizeWindow(int percent) 1067 { 1068 // Get required window size 1069 int videoWidth = lround(fSourceWidth * fWidthScale); 1070 int videoHeight = lround(fSourceHeight * fHeightScale); 1071 1072 videoWidth = (videoWidth * percent) / 100; 1073 videoHeight = (videoHeight * percent) / 100; 1074 1075 // Calculate and set the initial window size 1076 int width = max_c(fControlsWidth, videoWidth); 1077 int height = (fNoControls ? 0 : fControlsHeight) + videoHeight; 1078 if (!fNoMenu) { 1079 width = max_c(width, fMenuBarWidth); 1080 height += fMenuBarHeight; 1081 } 1082 _SetWindowSizeLimits(); 1083 ResizeTo(width - 1, height - 1); 1084 } 1085 1086 1087 void 1088 MainWin::_ResizeVideoView(int x, int y, int width, int height) 1089 { 1090 printf("_ResizeVideoView: %d,%d, width %d, height %d\n", x, y, 1091 width, height); 1092 1093 if (fKeepAspectRatio) { 1094 // Keep aspect ratio, place video view inside 1095 // the background area (may create black bars). 1096 float scaledWidth = fSourceWidth * fWidthScale; 1097 float scaledHeight = fSourceHeight * fHeightScale; 1098 float factor = min_c(width / scaledWidth, height / scaledHeight); 1099 int renderWidth = lround(scaledWidth * factor); 1100 int renderHeight = lround(scaledHeight * factor); 1101 if (renderWidth > width) 1102 renderWidth = width; 1103 if (renderHeight > height) 1104 renderHeight = height; 1105 1106 int xOffset = x + (width - renderWidth) / 2; 1107 int yOffset = y + (height - renderHeight) / 2; 1108 1109 fVideoView->MoveTo(xOffset, yOffset); 1110 fVideoView->ResizeTo(renderWidth - 1, renderHeight - 1); 1111 1112 } else { 1113 fVideoView->MoveTo(x, y); 1114 fVideoView->ResizeTo(width - 1, height - 1); 1115 } 1116 } 1117 1118 1119 // #pragma mark - 1120 1121 1122 void 1123 MainWin::_MouseDown(BMessage *msg, BView* originalHandler) 1124 { 1125 BPoint screen_where; 1126 uint32 buttons = msg->FindInt32("buttons"); 1127 1128 // On Zeta, only "screen_where" is relyable, "where" and "be:view_where" 1129 // seem to be broken 1130 if (B_OK != msg->FindPoint("screen_where", &screen_where)) { 1131 // Workaround for BeOS R5, it has no "screen_where" 1132 if (!originalHandler || msg->FindPoint("where", &screen_where) < B_OK) 1133 return; 1134 originalHandler->ConvertToScreen(&screen_where); 1135 } 1136 1137 // msg->PrintToStream(); 1138 1139 // if (1 == msg->FindInt32("buttons") && msg->FindInt32("clicks") == 1) { 1140 1141 if (1 == buttons && msg->FindInt32("clicks") % 2 == 0) { 1142 BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1, 1143 screen_where.y + 1); 1144 if (r.Contains(fMouseDownMousePos)) { 1145 PostMessage(M_TOGGLE_FULLSCREEN); 1146 return; 1147 } 1148 } 1149 1150 if (2 == buttons && msg->FindInt32("clicks") % 2 == 0) { 1151 BRect r(screen_where.x - 1, screen_where.y - 1, screen_where.x + 1, 1152 screen_where.y + 1); 1153 if (r.Contains(fMouseDownMousePos)) { 1154 PostMessage(M_TOGGLE_NO_BORDER_NO_MENU_NO_CONTROLS); 1155 return; 1156 } 1157 } 1158 1159 /* 1160 // very broken in Zeta: 1161 fMouseDownMousePos = fVideoView->ConvertToScreen( 1162 msg->FindPoint("where")); 1163 */ 1164 fMouseDownMousePos = screen_where; 1165 fMouseDownWindowPos = Frame().LeftTop(); 1166 1167 if (buttons == 1 && !fIsFullscreen) { 1168 // start mouse tracking 1169 fVideoView->SetMouseEventMask(B_POINTER_EVENTS | B_NO_POINTER_HISTORY 1170 /* | B_LOCK_WINDOW_FOCUS */); 1171 fMouseDownTracking = true; 1172 } 1173 1174 // pop up a context menu if right mouse button is down for 200 ms 1175 1176 if ((buttons & 2) == 0) 1177 return; 1178 bigtime_t start = system_time(); 1179 bigtime_t delay = 200000; 1180 BPoint location; 1181 do { 1182 fVideoView->GetMouse(&location, &buttons); 1183 if ((buttons & 2) == 0) 1184 break; 1185 snooze(1000); 1186 } while (system_time() - start < delay); 1187 1188 if (buttons & 2) 1189 _ShowContextMenu(screen_where); 1190 } 1191 1192 1193 void 1194 MainWin::_MouseMoved(BMessage *msg, BView* originalHandler) 1195 { 1196 // msg->PrintToStream(); 1197 1198 BPoint mousePos; 1199 uint32 buttons = msg->FindInt32("buttons"); 1200 1201 if (1 == buttons && fMouseDownTracking && !fIsFullscreen) { 1202 /* 1203 // very broken in Zeta: 1204 BPoint mousePos = msg->FindPoint("where"); 1205 printf("view where: %.0f, %.0f => ", mousePos.x, mousePos.y); 1206 fVideoView->ConvertToScreen(&mousePos); 1207 */ 1208 // On Zeta, only "screen_where" is relyable, "where" 1209 // and "be:view_where" seem to be broken 1210 if (B_OK != msg->FindPoint("screen_where", &mousePos)) { 1211 // Workaround for BeOS R5, it has no "screen_where" 1212 if (!originalHandler || msg->FindPoint("where", &mousePos) < B_OK) 1213 return; 1214 originalHandler->ConvertToScreen(&mousePos); 1215 } 1216 // printf("screen where: %.0f, %.0f => ", mousePos.x, mousePos.y); 1217 float delta_x = mousePos.x - fMouseDownMousePos.x; 1218 float delta_y = mousePos.y - fMouseDownMousePos.y; 1219 float x = fMouseDownWindowPos.x + delta_x; 1220 float y = fMouseDownWindowPos.y + delta_y; 1221 // printf("move window to %.0f, %.0f\n", x, y); 1222 MoveTo(x, y); 1223 } 1224 } 1225 1226 1227 void 1228 MainWin::_MouseUp(BMessage *msg) 1229 { 1230 // msg->PrintToStream(); 1231 fMouseDownTracking = false; 1232 } 1233 1234 1235 void 1236 MainWin::_ShowContextMenu(const BPoint &screen_point) 1237 { 1238 printf("Show context menu\n"); 1239 BPopUpMenu *menu = new BPopUpMenu("context menu", false, false); 1240 BMenuItem *item; 1241 menu->AddItem(item = new BMenuItem("Full Screen", 1242 new BMessage(M_TOGGLE_FULLSCREEN), 'F')); 1243 item->SetMarked(fIsFullscreen); 1244 item->SetEnabled(fHasVideo); 1245 menu->AddItem(item = new BMenuItem("Keep Aspect Ratio", 1246 new BMessage(M_TOGGLE_KEEP_ASPECT_RATIO), 'K')); 1247 item->SetMarked(fKeepAspectRatio); 1248 item->SetEnabled(fHasVideo); 1249 1250 menu->AddSeparatorItem(); 1251 menu->AddItem(item = new BMenuItem("No Menu", 1252 new BMessage(M_TOGGLE_NO_MENU), 'M')); 1253 item->SetMarked(fNoMenu); 1254 menu->AddItem(item = new BMenuItem("No Border", 1255 new BMessage(M_TOGGLE_NO_BORDER), 'B')); 1256 item->SetMarked(fNoBorder); 1257 menu->AddItem(item = new BMenuItem("Always on Top", 1258 new BMessage(M_TOGGLE_ALWAYS_ON_TOP), 'T')); 1259 item->SetMarked(fAlwaysOnTop); 1260 1261 menu->AddSeparatorItem(); 1262 menu->AddItem(new BMenuItem("About " NAME B_UTF8_ELLIPSIS, 1263 new BMessage(B_ABOUT_REQUESTED))); 1264 menu->AddSeparatorItem(); 1265 menu->AddItem(new BMenuItem("Quit", new BMessage(M_FILE_QUIT), 'Q')); 1266 1267 menu->AddSeparatorItem(); 1268 menu->AddItem(new BMenuItem("pixel aspect ratio 1.00000:1", 1269 new BMessage(M_ASPECT_100000_1))); 1270 menu->AddItem(new BMenuItem("pixel aspect ratio 1.06666:1", 1271 new BMessage(M_ASPECT_106666_1))); 1272 menu->AddItem(new BMenuItem("pixel aspect ratio 1.09091:1", 1273 new BMessage(M_ASPECT_109091_1))); 1274 menu->AddItem(new BMenuItem("pixel aspect ratio 1.41176:1", 1275 new BMessage(M_ASPECT_141176_1))); 1276 menu->AddItem(new BMenuItem("force 720 x 576, display aspect 4:3", 1277 new BMessage(M_ASPECT_720_576))); 1278 menu->AddItem(new BMenuItem("force 704 x 576, display aspect 4:3", 1279 new BMessage(M_ASPECT_704_576))); 1280 menu->AddItem(new BMenuItem("force 544 x 576, display aspect 4:3", 1281 new BMessage(M_ASPECT_544_576))); 1282 1283 menu->SetTargetForItems(this); 1284 BRect r(screen_point.x - 5, screen_point.y - 5, screen_point.x + 5, 1285 screen_point.y + 5); 1286 menu->Go(screen_point, true, true, r, true); 1287 } 1288 1289 1290 /* Trap keys that are about to be send to background or renderer view. 1291 * Return B_OK if it shouldn't be passed to the view 1292 */ 1293 status_t 1294 MainWin::_KeyDown(BMessage *msg) 1295 { 1296 // msg->PrintToStream(); 1297 1298 uint32 key = msg->FindInt32("key"); 1299 uint32 raw_char = msg->FindInt32("raw_char"); 1300 uint32 modifier = msg->FindInt32("modifiers"); 1301 1302 printf("key 0x%lx, raw_char 0x%lx, modifiers 0x%lx\n", key, raw_char, 1303 modifier); 1304 1305 switch (raw_char) { 1306 case B_SPACE: 1307 fController->TogglePlaying(); 1308 return B_OK; 1309 1310 case B_ESCAPE: 1311 if (fIsFullscreen) { 1312 PostMessage(M_TOGGLE_FULLSCREEN); 1313 return B_OK; 1314 } else 1315 break; 1316 1317 case B_ENTER: // Enter / Return 1318 if (modifier & B_COMMAND_KEY) { 1319 PostMessage(M_TOGGLE_FULLSCREEN); 1320 return B_OK; 1321 } else 1322 break; 1323 1324 case B_TAB: 1325 if ((modifier & (B_COMMAND_KEY | B_CONTROL_KEY | B_OPTION_KEY 1326 | B_MENU_KEY)) == 0) { 1327 PostMessage(M_TOGGLE_FULLSCREEN); 1328 return B_OK; 1329 } else 1330 break; 1331 1332 case B_UP_ARROW: 1333 if (modifier & B_COMMAND_KEY) { 1334 PostMessage(M_SKIP_NEXT); 1335 } else { 1336 PostMessage(M_VOLUME_UP); 1337 } 1338 return B_OK; 1339 1340 case B_DOWN_ARROW: 1341 if (modifier & B_COMMAND_KEY) { 1342 PostMessage(M_SKIP_PREV); 1343 } else { 1344 PostMessage(M_VOLUME_DOWN); 1345 } 1346 return B_OK; 1347 1348 case B_RIGHT_ARROW: 1349 if (modifier & B_COMMAND_KEY) { 1350 PostMessage(M_VOLUME_UP); 1351 } else { 1352 PostMessage(M_SKIP_NEXT); 1353 } 1354 return B_OK; 1355 1356 case B_LEFT_ARROW: 1357 if (modifier & B_COMMAND_KEY) { 1358 PostMessage(M_VOLUME_DOWN); 1359 } else { 1360 PostMessage(M_SKIP_PREV); 1361 } 1362 return B_OK; 1363 1364 case B_PAGE_UP: 1365 PostMessage(M_SKIP_NEXT); 1366 return B_OK; 1367 1368 case B_PAGE_DOWN: 1369 PostMessage(M_SKIP_PREV); 1370 return B_OK; 1371 } 1372 1373 switch (key) { 1374 case 0x3a: // numeric keypad + 1375 if ((modifier & B_COMMAND_KEY) == 0) { 1376 PostMessage(M_VOLUME_UP); 1377 return B_OK; 1378 } else { 1379 break; 1380 } 1381 1382 case 0x25: // numeric keypad - 1383 if ((modifier & B_COMMAND_KEY) == 0) { 1384 PostMessage(M_VOLUME_DOWN); 1385 return B_OK; 1386 } else { 1387 break; 1388 } 1389 1390 case 0x38: // numeric keypad up arrow 1391 PostMessage(M_VOLUME_UP); 1392 return B_OK; 1393 1394 case 0x59: // numeric keypad down arrow 1395 PostMessage(M_VOLUME_DOWN); 1396 return B_OK; 1397 1398 case 0x39: // numeric keypad page up 1399 case 0x4a: // numeric keypad right arrow 1400 PostMessage(M_SKIP_NEXT); 1401 return B_OK; 1402 1403 case 0x5a: // numeric keypad page down 1404 case 0x48: // numeric keypad left arrow 1405 PostMessage(M_SKIP_PREV); 1406 return B_OK; 1407 1408 case 0x34: //delete button 1409 case 0x3e: //d for delete 1410 case 0x2b: //t for Trash 1411 if (modifiers() & B_COMMAND_KEY) { 1412 BAutolock _(fPlaylist); 1413 BMessage removeMessage(M_PLAYLIST_REMOVE_AND_PUT_INTO_TRASH); 1414 removeMessage.AddInt32("playlist index", 1415 fPlaylist->CurrentItemIndex()); 1416 fPlaylistWindow->PostMessage(&removeMessage); 1417 return B_OK; 1418 } 1419 break; 1420 } 1421 1422 return B_ERROR; 1423 } 1424 1425 1426 // #pragma mark - 1427 1428 1429 void 1430 MainWin::_ToggleNoBorderNoMenu() 1431 { 1432 if (!fNoMenu && !fNoBorder && !fNoControls) { 1433 PostMessage(M_TOGGLE_NO_MENU); 1434 PostMessage(M_TOGGLE_NO_BORDER); 1435 PostMessage(M_TOGGLE_NO_CONTROLS); 1436 } else { 1437 if (!fNoMenu) 1438 PostMessage(M_TOGGLE_NO_MENU); 1439 if (!fNoBorder) 1440 PostMessage(M_TOGGLE_NO_BORDER); 1441 if (!fNoControls) 1442 PostMessage(M_TOGGLE_NO_CONTROLS); 1443 } 1444 } 1445 1446 1447 void 1448 MainWin::_ToggleFullscreen() 1449 { 1450 printf("_ToggleFullscreen enter\n"); 1451 1452 if (!fHasVideo) { 1453 printf("_ToggleFullscreen - ignoring, as we don't have a video\n"); 1454 return; 1455 } 1456 1457 fIsFullscreen = !fIsFullscreen; 1458 1459 if (fIsFullscreen) { 1460 // switch to fullscreen 1461 1462 fSavedFrame = Frame(); 1463 printf("saving current frame: %d %d %d %d\n", int(fSavedFrame.left), 1464 int(fSavedFrame.top), int(fSavedFrame.right), 1465 int(fSavedFrame.bottom)); 1466 BScreen screen(this); 1467 BRect rect(screen.Frame()); 1468 1469 Hide(); 1470 MoveTo(rect.left, rect.top); 1471 ResizeTo(rect.Width(), rect.Height()); 1472 Show(); 1473 1474 } else { 1475 // switch back from full screen mode 1476 1477 Hide(); 1478 MoveTo(fSavedFrame.left, fSavedFrame.top); 1479 ResizeTo(fSavedFrame.Width(), fSavedFrame.Height()); 1480 Show(); 1481 } 1482 1483 fVideoView->SetFullscreen(fIsFullscreen); 1484 1485 _MarkSettingsItem(M_TOGGLE_FULLSCREEN, fIsFullscreen); 1486 1487 printf("_ToggleFullscreen leave\n"); 1488 } 1489 1490 void 1491 MainWin::_ToggleNoControls() 1492 { 1493 printf("_ToggleNoControls enter\n"); 1494 1495 if (fIsFullscreen) { 1496 // fullscreen is always without menu 1497 printf("_ToggleNoControls leave, doing nothing, we are fullscreen\n"); 1498 return; 1499 } 1500 1501 fNoControls = !fNoControls; 1502 _SetWindowSizeLimits(); 1503 1504 if (fNoControls) { 1505 ResizeBy(0, - fControlsHeight); 1506 } else { 1507 ResizeBy(0, fControlsHeight); 1508 } 1509 1510 _MarkSettingsItem(M_TOGGLE_NO_CONTROLS, fNoControls); 1511 1512 printf("_ToggleNoControls leave\n"); 1513 } 1514 1515 void 1516 MainWin::_ToggleNoMenu() 1517 { 1518 printf("_ToggleNoMenu enter\n"); 1519 1520 if (fIsFullscreen) { 1521 // fullscreen is always without menu 1522 printf("_ToggleNoMenu leave, doing nothing, we are fullscreen\n"); 1523 return; 1524 } 1525 1526 fNoMenu = !fNoMenu; 1527 _SetWindowSizeLimits(); 1528 1529 if (fNoMenu) { 1530 MoveBy(0, fMenuBarHeight); 1531 ResizeBy(0, - fMenuBarHeight); 1532 } else { 1533 MoveBy(0, - fMenuBarHeight); 1534 ResizeBy(0, fMenuBarHeight); 1535 } 1536 1537 _MarkSettingsItem(M_TOGGLE_NO_MENU, fNoMenu); 1538 1539 printf("_ToggleNoMenu leave\n"); 1540 } 1541 1542 1543 void 1544 MainWin::_ToggleNoBorder() 1545 { 1546 fNoBorder = !fNoBorder; 1547 SetLook(fNoBorder ? B_BORDERED_WINDOW_LOOK : B_TITLED_WINDOW_LOOK); 1548 1549 _MarkSettingsItem(M_TOGGLE_NO_BORDER, fNoBorder); 1550 } 1551 1552 1553 void 1554 MainWin::_ToggleAlwaysOnTop() 1555 { 1556 fAlwaysOnTop = !fAlwaysOnTop; 1557 SetFeel(fAlwaysOnTop ? B_FLOATING_ALL_WINDOW_FEEL : B_NORMAL_WINDOW_FEEL); 1558 1559 _MarkSettingsItem(M_TOGGLE_ALWAYS_ON_TOP, fAlwaysOnTop); 1560 } 1561 1562 1563 void 1564 MainWin::_ToggleKeepAspectRatio() 1565 { 1566 fKeepAspectRatio = !fKeepAspectRatio; 1567 FrameResized(Bounds().Width(), Bounds().Height()); 1568 1569 _MarkSettingsItem(M_TOGGLE_KEEP_ASPECT_RATIO, fKeepAspectRatio); 1570 } 1571 1572 1573 // #pragma mark - 1574 1575 1576 void 1577 MainWin::_UpdateControlsEnabledStatus() 1578 { 1579 uint32 enabledButtons = 0; 1580 if (fHasVideo || fHasAudio) { 1581 enabledButtons |= PLAYBACK_ENABLED | SEEK_ENABLED 1582 | SEEK_BACK_ENABLED | SEEK_FORWARD_ENABLED; 1583 } 1584 if (fHasAudio) 1585 enabledButtons |= VOLUME_ENABLED; 1586 1587 BAutolock _(fPlaylist); 1588 bool canSkipPrevious, canSkipNext; 1589 fPlaylist->GetSkipInfo(&canSkipPrevious, &canSkipNext); 1590 if (canSkipPrevious) 1591 enabledButtons |= SKIP_BACK_ENABLED; 1592 if (canSkipNext) 1593 enabledButtons |= SKIP_FORWARD_ENABLED; 1594 1595 fControls->SetEnabled(enabledButtons); 1596 } 1597 1598 1599 void 1600 MainWin::_UpdatePlaylistMenu() 1601 { 1602 if (!fPlaylist->Lock()) 1603 return; 1604 1605 fPlaylistMenu->RemoveItems(0, fPlaylistMenu->CountItems(), true); 1606 1607 int32 count = fPlaylist->CountItems(); 1608 for (int32 i = 0; i < count; i++) { 1609 PlaylistItem* item = fPlaylist->ItemAtFast(i); 1610 _AddPlaylistItem(item, i); 1611 } 1612 fPlaylistMenu->SetTargetForItems(this); 1613 1614 _MarkPlaylistItem(fPlaylist->CurrentItemIndex()); 1615 1616 fPlaylist->Unlock(); 1617 } 1618 1619 1620 void 1621 MainWin::_AddPlaylistItem(PlaylistItem* item, int32 index) 1622 { 1623 BMessage* message = new BMessage(M_SET_PLAYLIST_POSITION); 1624 message->AddInt32("index", index); 1625 BMenuItem* menuItem = new BMenuItem(item->Name().String(), message); 1626 fPlaylistMenu->AddItem(menuItem, index); 1627 } 1628 1629 1630 void 1631 MainWin::_RemovePlaylistItem(int32 index) 1632 { 1633 delete fPlaylistMenu->RemoveItem(index); 1634 } 1635 1636 1637 void 1638 MainWin::_MarkPlaylistItem(int32 index) 1639 { 1640 if (BMenuItem* item = fPlaylistMenu->ItemAt(index)) { 1641 item->SetMarked(true); 1642 // ... and in case the menu is currently on screen: 1643 if (fPlaylistMenu->LockLooper()) { 1644 fPlaylistMenu->Invalidate(); 1645 fPlaylistMenu->UnlockLooper(); 1646 } 1647 } 1648 } 1649 1650 1651 void 1652 MainWin::_MarkSettingsItem(uint32 command, bool mark) 1653 { 1654 if (BMenuItem* item = fSettingsMenu->FindItem(command)) 1655 item->SetMarked(mark); 1656 } 1657 1658 1659 void 1660 MainWin::_AdoptGlobalSettings() 1661 { 1662 mpSettings settings = Settings::CurrentSettings(); 1663 // thread safe 1664 1665 fCloseWhenDonePlayingMovie = settings.closeWhenDonePlayingMovie; 1666 fCloseWhenDonePlayingSound = settings.closeWhenDonePlayingSound; 1667 } 1668 1669 1670