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