1/* 2 * Copyright 2006-2009, Haiku, Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Author: 6 * DarkWyrm, bpmagic@columbus.rr.com 7 */ 8 9 10#include "ButtonBitmaps.h" 11#include "CDPlayer.h" 12#include "DrawButton.h" 13#include "DoubleShotDrawButton.h" 14#include "TwoStateDrawButton.h" 15 16#include <Alert.h> 17#include <Application.h> 18#include <Bitmap.h> 19#include <BitmapStream.h> 20#include <Box.h> 21#include <Button.h> 22#include <Catalog.h> 23#include <Debug.h> 24#include <Deskbar.h> 25#include <Dragger.h> 26#include <Entry.h> 27#include <MenuItem.h> 28#include <PopUpMenu.h> 29#include <Roster.h> 30#include <TranslatorFormats.h> 31#include <TranslatorRoster.h> 32#include <TranslationUtils.h> 33#include <Window.h> 34 35#include <stdlib.h> 36#include <string.h> 37 38#undef B_TRANSLATION_CONTEXT 39#define B_TRANSLATION_CONTEXT "CDPlayer" 40 41enum { 42 M_STOP = 'mstp', 43 M_PLAY, 44 M_NEXT_TRACK, 45 M_PREV_TRACK, 46 M_FFWD, 47 M_REWIND, 48 M_EJECT, 49 M_SAVE, 50 M_SHUFFLE, 51 M_REPEAT, 52 M_SET_VOLUME, 53 M_SET_CD_TITLE 54}; 55 56 57class CDPlayerWindow : public BWindow { 58 public: 59 CDPlayerWindow(); 60 bool QuitRequested(); 61}; 62 63 64inline void 65SetLabel(BStringView *label, const char *text) 66{ 67 if (strcmp(label->Text(), text) != 0) 68 label->SetText(text); 69} 70 71 72// #pragma mark - 73 74 75CDPlayer::CDPlayer(BRect frame, const char *name, uint32 resizeMask, 76 uint32 flags) 77 : BView(frame, name, resizeMask, flags | B_FRAME_EVENTS), 78 fCDQuery("freedb.freedb.org") 79{ 80 SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); 81 82 fVolume = 255; 83 84 BuildGUI(); 85 86 if (fCDDrive.CountDrives() < 1) { 87 BAlert *alert = new BAlert("CDPlayer", B_TRANSLATE( 88 "It appears that there are no CD" 89 " drives on your computer or there is no system software to " 90 "support one. Sorry."), B_TRANSLATE("OK")); 91 alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE); 92 alert->Go(); 93 } 94 95 fWindowState = fCDDrive.GetState(); 96 fVolumeSlider->SetValue(fCDDrive.GetVolume()); 97 if (fVolumeSlider->Value() <= 2) { 98 fCDDrive.SetVolume(255); 99 fVolumeSlider->SetValue(255); 100 } 101 _WatchCDState(); 102} 103 104 105CDPlayer::~CDPlayer() 106{ 107 fCDDrive.Stop(); 108} 109 110 111bool 112CDPlayer::InitCheck() 113{ 114 return fCDDrive.CountDrives() > 0; 115} 116 117 118void 119CDPlayer::BuildGUI() 120{ 121 fStopColor.red = 80; 122 fStopColor.green = 164; 123 fStopColor.blue = 80; 124 fStopColor.alpha = 255; 125 126 fPlayColor.red = 40; 127 fPlayColor.green = 230; 128 fPlayColor.blue = 40; 129 fPlayColor.alpha = 255; 130 131 BRect r(Bounds().InsetByCopy(10, 10)); 132 BBox *box = new BBox(r, "", B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP); 133 AddChild(box); 134 135 r = box->Bounds().InsetByCopy(10, 10); 136 r.bottom = 25; 137 138 float labelWidth, labelHeight; 139 fCDTitle = new BStringView(r, "CDTitle", B_TRANSLATE("CD drive is empty"), 140 B_FOLLOW_LEFT_RIGHT); 141 fCDTitle->GetPreferredSize(&labelWidth, &labelHeight); 142 fCDTitle->ResizeTo(r.Width(), labelHeight); 143 box->AddChild(fCDTitle); 144 145 r.bottom = r.top + labelHeight; 146 r.OffsetBy(0, r.Height() + 5); 147 148 fCurrentTrack = new BStringView(r, "TrackNumber", 149 "", B_FOLLOW_LEFT_RIGHT); 150 box->AddChild(fCurrentTrack); 151 152 r.OffsetBy(0, r.Height() + 5); 153 r.right = r.left + (r.Width() / 2); 154 fTrackTime = new BStringView(r, "TrackTime", 155 B_TRANSLATE("Track: 88:88 / 88:88"), B_FOLLOW_LEFT_RIGHT); 156 fTrackTime->ResizeToPreferred(); 157 fTrackTime->SetText(B_TRANSLATE("Track: --:-- / --:--")); 158 box->AddChild(fTrackTime); 159 160 r.OffsetTo(fTrackTime->Frame().right + 5, r.top); 161 fDiscTime = new BStringView(r, "DiscTime", 162 B_TRANSLATE("Disc: 88:88 / 88:88"), B_FOLLOW_RIGHT); 163 fDiscTime->ResizeToPreferred(); 164 fDiscTime->SetText(B_TRANSLATE("Disc: --:-- / --:--")); 165 box->AddChild(fDiscTime); 166 167 float maxWidth = max_c(fDiscTime->Frame().right, fCDTitle->Frame().right); 168 169 box->ResizeTo(maxWidth + 5, fDiscTime->Frame().bottom + 10); 170 171 fStop = new DrawButton(BRect(0, 0, 1, 1), "Stop", 172 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "stop_up"), 173 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "stop_down"), 174 new BMessage(M_STOP), B_FOLLOW_BOTTOM, B_WILL_DRAW); 175 fStop->ResizeToPreferred(); 176 fStop->MoveTo(10, box->Frame().bottom + 15); 177 fStop->SetDisabled(BTranslationUtils::GetBitmap(B_PNG_FORMAT, 178 "stop_disabled")); 179 AddChild(fStop); 180 float stopTop = fStop->Frame().top; 181 182 183 fPlay = new TwoStateDrawButton(BRect(0, 0, 1, 1), "Play", 184 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "play_up"), 185 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "play_down"), 186 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "play_up_on"), 187 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "play_down"), 188 new BMessage(M_PLAY), B_FOLLOW_NONE, B_WILL_DRAW); 189 190 fPlay->ResizeToPreferred(); 191 fPlay->MoveTo(fStop->Frame().right + 2, stopTop); 192 AddChild(fPlay); 193 194 fPrevTrack = new DrawButton(BRect(0, 0, 1, 1), "PrevTrack", 195 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "prev_up"), 196 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "prev_down"), 197 new BMessage(M_PREV_TRACK), 0, B_WILL_DRAW); 198 fPrevTrack->ResizeToPreferred(); 199 fPrevTrack->MoveTo(fPlay->Frame().right + 40, stopTop); 200 AddChild(fPrevTrack); 201 202 fNextTrack = new DrawButton(BRect(0, 0, 1, 1), "NextTrack", 203 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "next_up"), 204 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "next_down"), 205 new BMessage(M_NEXT_TRACK), 0, B_WILL_DRAW); 206 fNextTrack->ResizeToPreferred(); 207 fNextTrack->MoveTo(fPrevTrack->Frame().right + 1, stopTop); 208 AddChild(fNextTrack); 209 210 fRewind = new DoubleShotDrawButton(BRect(0, 0, 1, 1), "Rewind", 211 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "rew_up"), 212 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "rew_down"), 213 new BMessage(M_REWIND), 0, B_WILL_DRAW); 214 fRewind->ResizeToPreferred(); 215 fRewind->MoveTo(fNextTrack->Frame().right + 40, stopTop); 216 AddChild(fRewind); 217 218 fFastFwd = new DoubleShotDrawButton(BRect(0, 0, 1, 1), "FastFwd", 219 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "ffwd_up"), 220 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "ffwd_down"), 221 new BMessage(M_FFWD), 0, B_WILL_DRAW); 222 fFastFwd->ResizeToPreferred(); 223 fFastFwd->MoveTo(fRewind->Frame().right + 1, stopTop); 224 AddChild(fFastFwd); 225 226 r.left = 10; 227 r.right = fPlay->Frame().right; 228 r.top = fStop->Frame().bottom + 14; 229 r.bottom = r.top + 14; 230 fVolumeSlider = new VolumeSlider(r, "VolumeSlider", 231 0, 255, new BMessage(M_SET_VOLUME), this); 232 AddChild(fVolumeSlider); 233 234 fRepeat = new TwoStateDrawButton(BRect(0, 0, 1, 1), "Repeat", 235 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "repeat_up_off"), 236 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "repeat_down"), 237 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "repeat_up_on"), 238 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "repeat_down"), 239 new BMessage(M_REPEAT), B_FOLLOW_NONE, B_WILL_DRAW); 240 fRepeat->ResizeToPreferred(); 241 fRepeat->MoveTo(fPrevTrack->Frame().left, fVolumeSlider->Frame().top - 242 ((fRepeat->Frame().Height() - fVolumeSlider->Frame().Height()) / 2)); 243 AddChild(fRepeat); 244 245 fShuffle = new TwoStateDrawButton(BRect(0, 0, 1, 1), "Shuffle", 246 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "shuffle_up_off"), 247 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "shuffle_down"), 248 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "shuffle_up_on"), 249 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "shuffle_down"), 250 new BMessage(M_SHUFFLE), B_FOLLOW_NONE, B_WILL_DRAW); 251 fShuffle->ResizeToPreferred(); 252 fShuffle->MoveTo(fRepeat->Frame().right + 2, fRepeat->Frame().top); 253 AddChild(fShuffle); 254 255 fEject = new DrawButton(BRect(0, 0, 1, 1), "Eject", 256 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "eject_up"), 257 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "eject_down"), 258 new BMessage(M_EJECT), 0, B_WILL_DRAW); 259 fEject->ResizeToPreferred(); 260 fEject->MoveTo(fFastFwd->Frame().left, fShuffle->Frame().top); 261 AddChild(fEject); 262 263 ResizeTo(box->Frame().right + 10, fVolumeSlider->Frame().bottom + 10); 264} 265 266 267void 268CDPlayer::MessageReceived(BMessage *msg) 269{ 270 switch (msg->what) { 271 case M_SET_VOLUME: 272 fCDDrive.SetVolume(fVolumeSlider->Value()); 273 break; 274 275 case M_STOP: 276 if (fWindowState == kPaused) { 277 fPlay->SetBitmaps(0, BTranslationUtils::GetBitmap(B_PNG_FORMAT, 278 "play_up"), 279 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "play_down")); 280 fPlay->SetState(1); 281 } 282 fWindowState = kStopped; 283 fCDDrive.Stop(); 284 break; 285 286 case M_PLAY: 287 // If we are currently playing, then we will be showing 288 // the pause images and will want to switch back to the play images 289 if (fWindowState == kPlaying) { 290 fWindowState = kPaused; 291 fCDDrive.Pause(); 292 fPlay->SetBitmaps(0, BTranslationUtils::GetBitmap(B_PNG_FORMAT, 293 "paused_up"), 294 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "play_down")); 295 } else if (fWindowState == kPaused) { 296 fWindowState = kPlaying; 297 fCDDrive.Resume(); 298 fPlay->SetBitmaps(0, BTranslationUtils::GetBitmap(B_PNG_FORMAT, 299 "play_up"), 300 BTranslationUtils::GetBitmap(B_PNG_FORMAT, "play_down")); 301 } else { 302 fWindowState = kPlaying; 303 fCDDrive.Play(fPlayList.GetCurrentTrack()); 304 } 305 break; 306 307 case M_EJECT: 308 fCDDrive.Eject(); 309 break; 310 311 case M_NEXT_TRACK: 312 { 313 int16 next = fPlayList.GetNextTrack(); 314 if (next <= 0) { 315 // force a "wrap around" when possible. This makes it 316 // possible for the user to be able to, for example, jump 317 // back to the first track from the last one with 1 button push 318 next = fPlayList.GetFirstTrack(); 319 } 320 321 if (next > 0) { 322 CDState state = fCDDrive.GetState(); 323 if (state == kPlaying) { 324 while (!fCDDrive.Play(next)) { 325 next = fPlayList.GetNextTrack(); 326 if (next < 1) { 327 fWindowState = kStopped; 328 fCDDrive.Stop(); 329 fPlayList.Rewind(); 330 break; 331 } 332 } 333 } 334 else if (state == kPaused) { 335 fCDDrive.Play(next); 336 fCDDrive.Pause(); 337 } 338 else 339 fPlayList.SetCurrentTrack(next); 340 341 // Force an update for better responsiveness 342 _WatchCDState(); 343 } 344 break; 345 } 346 347 case M_PREV_TRACK: 348 { 349 int16 prev = fPlayList.GetPreviousTrack(); 350 if (prev <= 0) { 351 // force a "wrap around" when possible. This makes it 352 // possible for the user to be able to, for example, jump 353 // back to the first track from the last one with 1 button push 354 prev = fPlayList.GetLastTrack(); 355 } 356 357 if (prev > 0) { 358 CDState state = fCDDrive.GetState(); 359 if (state == kPlaying) { 360 while (!fCDDrive.Play(prev)) { 361 prev = fPlayList.GetPreviousTrack(); 362 if (prev < 1) { 363 fWindowState = kStopped; 364 fCDDrive.Stop(); 365 fPlayList.Rewind(); 366 break; 367 } 368 } 369 } else if (state == kPaused) { 370 fCDDrive.Play(prev); 371 fCDDrive.Pause(); 372 } else 373 fPlayList.SetCurrentTrack(prev); 374 375 // Force an update for better responsiveness 376 _WatchCDState(); 377 } 378 break; 379 } 380 381 case M_FFWD: 382 if (fFastFwd->Value() == B_CONTROL_ON) 383 fCDDrive.StartFastFwd(); 384 else 385 fCDDrive.StopFastFwd(); 386 break; 387 388 case M_REWIND: 389 if (fRewind->Value() == B_CONTROL_ON) 390 fCDDrive.StartRewind(); 391 else 392 fCDDrive.StopRewind(); 393 break; 394 395 case M_SHUFFLE: 396 if (fPlayList.IsShuffled()) { 397 int16 track = fPlayList.GetCurrentTrack(); 398 fPlayList.SetShuffle(false); 399 fPlayList.SetStartingTrack(track); 400 fPlayList.SetTrackCount(fCDDrive.CountTracks()); 401 fShuffle->SetState(0); 402 } else { 403 fPlayList.SetTrackCount(fCDDrive.CountTracks()); 404 fPlayList.SetShuffle(true); 405 fShuffle->SetState(1); 406 } 407 break; 408 409 case M_REPEAT: 410 if (fPlayList.IsLoop()) { 411 fPlayList.SetLoop(false); 412 fRepeat->SetState(0); 413 } else { 414 fPlayList.SetLoop(true); 415 fRepeat->SetState(1); 416 } 417 break; 418 419 default: 420 BView::MessageReceived(msg); 421 break; 422 423 } 424} 425 426 427void 428CDPlayer::AttachedToWindow() 429{ 430 fStop->SetTarget(this); 431 fPlay->SetTarget(this); 432 fNextTrack->SetTarget(this); 433 fPrevTrack->SetTarget(this); 434 fFastFwd->SetTarget(this); 435 fRewind->SetTarget(this); 436 fEject->SetTarget(this); 437 fShuffle->SetTarget(this); 438 fRepeat->SetTarget(this); 439} 440 441 442void 443CDPlayer::Pulse() 444{ 445 _WatchCDState(); 446} 447 448 449void 450CDPlayer::_WatchCDState() 451{ 452 // One watcher function to rule them all 453 454 // first, watch the one setting independent of having a CD: volume 455 uint8 driveVolume = fCDDrive.GetVolume(); 456 if (fVolume == driveVolume) { 457 fVolume = driveVolume; 458 fVolumeSlider->SetValue(fVolume); 459 } 460 461 // Second, establish whether or not we have a CD in the drive 462 CDState playState = fCDDrive.GetState(); 463 bool internalTrackChange = false; 464 465 if (playState == kNoCD) { 466 // Yes, we have no bananas! 467 468 // Do something only if there is a change in the app's play state 469 if (fWindowState != kNoCD) { 470 // We have just discovered that we have no bananas 471 fWindowState = kNoCD; 472 473 // Because we are changing play states, we will need to update 474 // the GUI 475 fCDData.SetDiscID(-1); 476 SetLabel(fCDTitle, B_TRANSLATE("CD drive is empty")); 477 478 SetLabel(fCurrentTrack, ""); 479 SetLabel(fTrackTime, B_TRANSLATE("Track: --:-- / --:--")); 480 SetLabel(fDiscTime, B_TRANSLATE("Disc: --:-- / --:--")); 481 fPlayList.SetTrackCount(0); 482 fPlayList.SetStartingTrack(1); 483 fPlayList.SetCurrentTrack(1); 484 485 if (fPlay->GetState() == 1) 486 fPlay->SetState(0); 487 } 488 489 return; 490 } 491 492 // Now otherwise handle the play state 493 if (playState == kStopped) { 494 if (fWindowState == kPlaying) { 495 internalTrackChange = true; 496 497 // This means that the drive finished playing the song, so get 498 // the next one from the list and play it 499 int16 next = fPlayList.GetNextTrack(); 500 if (next > 0) 501 fCDDrive.Play(next); 502 } 503 504 if (fPlay->GetState() == 1) 505 fPlay->SetState(0); 506 } else if (playState == kPlaying) { 507 if (fPlay->GetState() == 0) 508 fPlay->SetState(1); 509 } else if (playState == kPaused) 510 fPlay->SetState(0); 511 512 // If we got this far, then there must be a CD in the drive. The next order 513 // on the agenda is to find out which CD it is 514 int32 discId = fCDDrive.GetDiscID(); 515 bool updateTrackGui = false; 516 517 if (discId != fCDData.DiscID()) { 518 updateTrackGui = true; 519 520 // Apparently the disc has changed since we last looked. 521 if (fCDQuery.CurrentDiscID() != discId) 522 fCDQuery.SetToCD(fCDDrive.GetDrivePath()); 523 524 if (fCDQuery.Ready()) { 525 // Note that we only update the CD title for now. We still need a 526 // track number in order to update the display for the selected track 527 if (fCDQuery.GetData(&fCDData, 1000000)) { 528 BString display(fCDData.Artist()); 529 display << " - " << fCDData.Album(); 530 SetLabel(fCDTitle, display.String()); 531 } else 532 SetLabel(fCDTitle, B_TRANSLATE("Audio CD")); 533 } 534 } 535 536 // Now that we know which CD it is, update the track info 537 int16 driveCount = fCDDrive.CountTracks(); 538 int16 driveTrack = fCDDrive.GetTrack(); 539 540 int16 playlistTrack = fPlayList.GetCurrentTrack(); 541 int16 playlistCount = fPlayList.TrackCount(); 542 543 if (playState == kPlaying) { 544 if (playlistTrack != driveTrack) { 545 playlistTrack = driveTrack; 546 547 if (!internalTrackChange) { 548 // The main thing is that we need to make sure that the 549 // playlist and the drive's track stay in sync. The CD's 550 // track may have been changed by an outside source, so if 551 // the drive is playing, check for playlist sync. 552 fPlayList.SetTrackCount(driveCount); 553 fPlayList.SetCurrentTrack(driveTrack); 554 } 555 } 556 updateTrackGui = true; 557 } else { 558 if (playlistCount != driveCount) { 559 // This happens only when CDs are changed 560 if (driveCount < 0) { 561 // There is no CD in the drive. The playlist needs to have its 562 // track count set to 0 and it also needs to be rewound. 563 fPlayList.SetStartingTrack(1); 564 fPlayList.SetTrackCount(0); 565 playlistTrack = 1; 566 playlistCount = 0; 567 } else { 568 // Two possible cases here: playlist is empty or playlist has a 569 // different number of tracks. In either case, the playlist 570 // needs to be reinitialized to the current track data 571 fPlayList.SetStartingTrack(1); 572 fPlayList.SetTrackCount(driveCount); 573 playlistTrack = fPlayList.GetCurrentTrack(); 574 playlistCount = driveCount; 575 } 576 } else { 577 // update only with a track change 578 if (playlistTrack != driveTrack) 579 updateTrackGui = true; 580 } 581 } 582 583 if (updateTrackGui) { 584 BString currentTrackName(B_TRANSLATE("Track %whichTrack%: %trackAt%")); 585 586 if (playlistTrack >= 0) { 587 int16 whichTrack = playlistTrack; 588 589 if (whichTrack == 0) 590 whichTrack++; 591 592 BString stringTrack; 593 stringTrack << whichTrack; 594 595 BString stringTrackAt; 596 stringTrack << fCDData.TrackAt(whichTrack - 1); 597 598 currentTrackName.ReplaceFirst("%whichTrack%", stringTrack); 599 currentTrackName.ReplaceFirst("%trackAt%", stringTrackAt); 600 601 SetLabel(fCurrentTrack, currentTrackName.String()); 602 603 } else 604 SetLabel(fCurrentTrack, ""); 605 } 606 607 // Now update the time info 608 CDAudioTime trackTime; 609 CDAudioTime discTime; 610 CDAudioTime trackTotal; 611 CDAudioTime discTotal; 612 char timeString[1024]; 613 614 if (fCDDrive.GetTime(trackTime, discTime)) { 615 fCDDrive.GetTimeForDisc(discTotal); 616 sprintf(timeString, B_TRANSLATE("Disc: %ld:%.2ld / %ld:%.2ld"), 617 discTime.GetMinutes(), discTime.GetSeconds(), 618 discTotal.GetMinutes(), discTotal.GetSeconds()); 619 SetLabel(fDiscTime, timeString); 620 621 fCDDrive.GetTimeForTrack(playlistTrack, trackTotal); 622 sprintf(timeString, B_TRANSLATE("Track: %ld:%.2ld / %ld:%.2ld"), 623 trackTime.GetMinutes(), trackTime.GetSeconds(), 624 trackTotal.GetMinutes(), trackTotal.GetSeconds()); 625 SetLabel(fTrackTime, timeString); 626 } else { 627 SetLabel(fTrackTime, B_TRANSLATE("Track: --:-- / --:--")); 628 SetLabel(fDiscTime, B_TRANSLATE("Disc: --:-- / --:--")); 629 } 630} 631 632 633// #pragma mark - 634 635 636CDPlayerWindow::CDPlayerWindow() 637 : 638 BWindow(BRect (100, 100, 405, 280), B_TRANSLATE_SYSTEM_NAME("CDPlayer"), 639 B_TITLED_WINDOW, B_NOT_RESIZABLE | B_NOT_ZOOMABLE 640 | B_ASYNCHRONOUS_CONTROLS) 641{ 642} 643 644 645bool 646CDPlayerWindow::QuitRequested() 647{ 648 be_app->PostMessage(B_QUIT_REQUESTED); 649 return true; 650} 651 652 653// #pragma mark - 654 655 656CDPlayerApplication::CDPlayerApplication() 657 : BApplication("application/x-vnd.Haiku-CDPlayer") 658{ 659 BWindow *window = new CDPlayerWindow(); 660 CDPlayer *view = new CDPlayer(window->Bounds(), B_TRANSLATE("CD")); 661 if (view->InitCheck()) { 662 window->ResizeTo(view->Bounds().Width(), view->Bounds().Height()); 663 window->AddChild(view); 664 window->Show(); 665 } else 666 PostMessage(B_QUIT_REQUESTED); 667} 668 669 670int 671main(int, char **argv) 672{ 673 CDPlayerApplication app; 674 app.Run(); 675 676 return 0; 677} 678 679