diff --git a/src/apps/cdplayer/CDButton.cpp b/src/apps/cdplayer/CDButton.cpp new file mode 100644 index 0000000000..126b7222b1 --- /dev/null +++ b/src/apps/cdplayer/CDButton.cpp @@ -0,0 +1,451 @@ +// Copyright 1992-1999, Be Incorporated, All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +// +// send comments/suggestions/feedback to pavel@be.com +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "CDButton.h" +#include "DrawButton.h" +#include + +enum +{ + M_STOP='mstp', + M_PLAY, + M_NEXT_TRACK, + M_PREV_TRACK, + M_FFWD, + M_REWIND, + M_EJECT, + M_SAVE, + M_SHUFFLE, + M_REPEAT, + M_SET_VOLUME, + M_SET_CD_TITLE +}; + +CDButton::CDButton(BRect frame, const char *name, uint32 resizeMask, uint32 flags) + : BView(frame, name, resizeMask, flags) +{ + SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + engine = new CDEngine(CDEngine::FindCDPlayerDevice()); + + BuildGUI(); + + fCDState = engine->PlayStateWatcher()->GetState(); + + if(fCDState == kNoCD) + { + fStop->SetEnabled(false); + fPlay->SetEnabled(false); + fNextTrack->SetEnabled(false); + fPrevTrack->SetEnabled(false); + fFastFwd->SetEnabled(false); + fRewind->SetEnabled(false); + fSave->SetEnabled(false); + } +} + +CDButton::~CDButton() +{ + delete engine; +} + +void CDButton::BuildGUI(void) +{ + fCDTitle = new BTextControl( BRect(5,5,230,30), "CDTitle","","",new BMessage(M_SET_CD_TITLE)); + AddChild(fCDTitle); + fCDTitle->SetDivider(0); + fCDTitle->TextView()->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); + + BBox *box = new BBox(BRect(0,0,75,20),"TrackBox"); + box->MoveTo(fCDTitle->Frame().right + 15, 5); + AddChild(box); + + BView *view = new BView( box->Bounds().InsetByCopy(2,2), "view",B_FOLLOW_NONE,B_WILL_DRAW); + view->SetViewColor(0,0,0); + box->AddChild(view); + + fTrackNumber = new BStringView( view->Bounds(),"TrackNumber","Track: --"); + view->AddChild(fTrackNumber); + fTrackNumber->SetAlignment(B_ALIGN_CENTER); + fTrackNumber->SetHighColor(0,255,0); + fTrackNumber->SetFont(be_bold_font); + + fVolume = new BSlider( BRect(0,0,75,30), "VolumeSlider", "Volume", new BMessage(M_SET_VOLUME),0,100); + fVolume->MoveTo(5, Bounds().bottom - 10 - fVolume->Frame().Height()); + AddChild(fVolume); + fVolume->SetEnabled(false); + + fStop = new DrawButton( BRect(0,0,1,1), "Stop", BTranslationUtils::GetBitmap('PNG ',"stop_up"), + BTranslationUtils::GetBitmap('PNG ',"stop_down"), new BMessage(M_STOP), + B_FOLLOW_BOTTOM, B_WILL_DRAW); + fStop->ResizeToPreferred(); + fStop->MoveTo(fVolume->Frame().right + 10, Bounds().bottom - 5 - fStop->Frame().Height()); + fStop->SetDisabled(BTranslationUtils::GetBitmap('PNG ',"stop_disabled")); + AddChild(fStop); + + // TODO: Play is a special button. Implement as two-state buttons + fPlay = new DrawButton( BRect(0,0,1,1), "Play", BTranslationUtils::GetBitmap('PNG ',"play_up"), + BTranslationUtils::GetBitmap('PNG ',"play_down"), new BMessage(M_PLAY), + B_FOLLOW_BOTTOM, B_WILL_DRAW); + fPlay->ResizeToPreferred(); + fPlay->MoveTo(fStop->Frame().right + 2, Bounds().bottom - 5 - fPlay->Frame().Height()); + fPlay->SetDisabled(BTranslationUtils::GetBitmap('PNG ',"play_disabled")); + AddChild(fPlay); + + fPrevTrack = new DrawButton( BRect(0,0,1,1), "PrevTrack", BTranslationUtils::GetBitmap('PNG ',"prev_up"), + BTranslationUtils::GetBitmap('PNG ',"prev_down"), new BMessage(M_PREV_TRACK), + B_FOLLOW_BOTTOM, B_WILL_DRAW); + fPrevTrack->ResizeToPreferred(); + fPrevTrack->MoveTo(fPlay->Frame().right + 10, Bounds().bottom - 5 - fPrevTrack->Frame().Height()); + fPrevTrack->SetDisabled(BTranslationUtils::GetBitmap('PNG ',"prev_disabled")); + AddChild(fPrevTrack); + + fNextTrack = new DrawButton( BRect(0,0,1,1), "NextTrack", BTranslationUtils::GetBitmap('PNG ',"next_up"), + BTranslationUtils::GetBitmap('PNG ',"next_down"), new BMessage(M_NEXT_TRACK), + B_FOLLOW_BOTTOM, B_WILL_DRAW); + fNextTrack->ResizeToPreferred(); + fNextTrack->MoveTo(fPrevTrack->Frame().right + 2, Bounds().bottom - 5 - fNextTrack->Frame().Height()); + fNextTrack->SetDisabled(BTranslationUtils::GetBitmap('PNG ',"next_disabled")); + AddChild(fNextTrack); + + // TODO: Fast Forward and Rewind are special buttons. Implement as two-state buttons + fRewind = new DrawButton( BRect(0,0,1,1), "Rewind", BTranslationUtils::GetBitmap('PNG ',"rew_up"), + BTranslationUtils::GetBitmap('PNG ',"rew_down"), new BMessage(M_PREV_TRACK), + B_FOLLOW_BOTTOM, B_WILL_DRAW); + fRewind->ResizeToPreferred(); + fRewind->MoveTo(fNextTrack->Frame().right + 10, Bounds().bottom - 5 - fRewind->Frame().Height()); + fRewind->SetDisabled(BTranslationUtils::GetBitmap('PNG ',"rew_disabled")); + AddChild(fRewind); + + fFastFwd = new DrawButton( BRect(0,0,1,1), "FastFwd", BTranslationUtils::GetBitmap('PNG ',"ffwd_up"), + BTranslationUtils::GetBitmap('PNG ',"ffwd_down"), new BMessage(M_NEXT_TRACK), + B_FOLLOW_BOTTOM, B_WILL_DRAW); + fFastFwd->ResizeToPreferred(); + fFastFwd->MoveTo(fRewind->Frame().right + 2, Bounds().bottom - 5 - fFastFwd->Frame().Height()); + fFastFwd->SetDisabled(BTranslationUtils::GetBitmap('PNG ',"ffwd_disabled")); + AddChild(fFastFwd); + + fEject = new DrawButton( BRect(0,0,1,1), "Eject", BTranslationUtils::GetBitmap('PNG ',"eject_up"), + BTranslationUtils::GetBitmap('PNG ',"eject_down"), new BMessage(M_EJECT), + B_FOLLOW_BOTTOM, B_WILL_DRAW); + fEject->ResizeToPreferred(); + fEject->MoveTo(fFastFwd->Frame().right + 20, Bounds().bottom - 5 - fEject->Frame().Height()); + fEject->SetDisabled(BTranslationUtils::GetBitmap('PNG ',"eject_disabled")); + AddChild(fEject); + + fSave = new DrawButton( BRect(0,0,1,1), "Save", BTranslationUtils::GetBitmap('PNG ',"save_up"), + BTranslationUtils::GetBitmap('PNG ',"save_down"), new BMessage(M_SAVE), + B_FOLLOW_BOTTOM, B_WILL_DRAW); + fSave->ResizeToPreferred(); + fSave->MoveTo(fEject->Frame().right + 20, Bounds().bottom - 5 - fSave->Frame().Height()); + fSave->SetDisabled(BTranslationUtils::GetBitmap('PNG ',"save_disabled")); + AddChild(fSave); + fSave->SetEnabled(false); + + // TODO: Shuffle and Repeat are special buttons. Implement as two-state buttons + fShuffle = new DrawButton( BRect(0,0,1,1), "Shuffle", BTranslationUtils::GetBitmap('PNG ',"shuffle_up"), + BTranslationUtils::GetBitmap('PNG ',"shuffle_down"), new BMessage(M_SHUFFLE), + B_FOLLOW_BOTTOM, B_WILL_DRAW); + fShuffle->ResizeToPreferred(); + fShuffle->MoveTo(fSave->Frame().right + 2, Bounds().bottom - 5 - fShuffle->Frame().Height()); + fShuffle->SetDisabled(BTranslationUtils::GetBitmap('PNG ',"shuffle_disabled")); + AddChild(fShuffle); + fShuffle->SetEnabled(false); + + fRepeat = new DrawButton( BRect(0,0,1,1), "Repeat", BTranslationUtils::GetBitmap('PNG ',"repeat_up"), + BTranslationUtils::GetBitmap('PNG ',"repeat_down"), new BMessage(M_REPEAT), + B_FOLLOW_BOTTOM, B_WILL_DRAW); + fRepeat->ResizeToPreferred(); + fRepeat->MoveTo(fShuffle->Frame().right + 2, Bounds().bottom - 5 - fRepeat->Frame().Height()); + fRepeat->SetDisabled(BTranslationUtils::GetBitmap('PNG ',"repeat_disabled")); + AddChild(fRepeat); + fRepeat->SetEnabled(false); +} + + +void +CDButton::MessageReceived(BMessage *message) +{ + switch (message->what) + { + case M_SET_VOLUME: + { + // TODO: Implement + break; + } + case M_STOP: + { + engine->Stop(); + break; + } + case M_PLAY: + { + engine->PlayOrPause(); + break; + } + case M_NEXT_TRACK: + { + engine->SkipOneForward(); + break; + } + case M_PREV_TRACK: + { + engine->SkipOneBackward(); + break; + } + case M_FFWD: + { + // TODO: Implement + break; + } + case M_REWIND: + { + // TODO: Implement + break; + } + case M_EJECT: + { + engine->Eject(); + break; + } + case M_SAVE: + { + // TODO: Implement + break; + } + case M_SHUFFLE: + { + // TODO: Implement + break; + } + case M_REPEAT: + { + // TODO: Implement + break; + } + default: + { + + if (!Observer::HandleObservingMessages(message)) + { + // just support observing messages + BView::MessageReceived(message); + break; + } + } + } +} + +void +CDButton::NoticeChange(Notifier *notifier) +{ +// debugger(""); + + PlayState *ps; + TrackState *trs; + TimeState *tms; + CDContentWatcher *ccw; + + ps = dynamic_cast(notifier); + trs = dynamic_cast(notifier); + tms = dynamic_cast(notifier); + ccw = dynamic_cast(notifier); + + if(ps) + { + switch(ps->GetState()) + { + case kNoCD: + { + if(fStop->IsEnabled()) + { + fStop->SetEnabled(false); + fPlay->SetEnabled(false); + fNextTrack->SetEnabled(false); + fPrevTrack->SetEnabled(false); + fFastFwd->SetEnabled(false); + fRewind->SetEnabled(false); + fSave->SetEnabled(false); + } + break; + } + case kStopped: + { + if(!fStop->IsEnabled()) + { + fStop->SetEnabled(true); + fPlay->SetEnabled(true); + fNextTrack->SetEnabled(true); + fPrevTrack->SetEnabled(true); + fFastFwd->SetEnabled(true); + fRewind->SetEnabled(true); + fSave->SetEnabled(true); + } + break; + } + case kPaused: + { + // TODO: Set play button to Pause + if(!fStop->IsEnabled()) + { + fStop->SetEnabled(true); + fPlay->SetEnabled(true); + fNextTrack->SetEnabled(true); + fPrevTrack->SetEnabled(true); + fFastFwd->SetEnabled(true); + fRewind->SetEnabled(true); + fSave->SetEnabled(true); + } + UpdateTrackInfo(); + break; + } + case kPlaying: + { + if(!fStop->IsEnabled()) + { + fStop->SetEnabled(true); + fPlay->SetEnabled(true); + fNextTrack->SetEnabled(true); + fPrevTrack->SetEnabled(true); + fFastFwd->SetEnabled(true); + fRewind->SetEnabled(true); + fSave->SetEnabled(true); + } + UpdateTrackInfo(); + break; + } + case kSkipping: + { + if(!fStop->IsEnabled()) + { + fStop->SetEnabled(true); + fPlay->SetEnabled(true); + fNextTrack->SetEnabled(true); + fPrevTrack->SetEnabled(true); + fFastFwd->SetEnabled(true); + fRewind->SetEnabled(true); + fSave->SetEnabled(true); + } + break; + } + default: + { + break; + } + } + } + else + if(trs) + { + UpdateTrackInfo(); + // TODO: Update track count indicator + } + else + if(tms) + { + } + else + if(ccw) + { + } +} + +void +CDButton::UpdateTrackInfo(void) +{ + + fCurrentTrack=engine->TrackStateWatcher()->GetTrack(); + fTrackCount=engine->TrackStateWatcher()->GetNumTracks(); + + if(fCurrentTrack < 1) + { + char string[255]; + sprintf(string,"Track: %ld",fCurrentTrack); + fTrackNumber->SetText(string); + } + else + fTrackNumber->SetText("Track: --"); +} + +void +CDButton::AttachedToWindow() +{ + // start observing + engine->AttachedToLooper(Window()); + StartObserving(engine->TrackStateWatcher()); + StartObserving(engine->PlayStateWatcher()); + + fVolume->SetTarget(this); + fStop->SetTarget(this); + fPlay->SetTarget(this); + fNextTrack->SetTarget(this); + fPrevTrack->SetTarget(this); + fFastFwd->SetTarget(this); + fRewind->SetTarget(this); + fEject->SetTarget(this); + fSave->SetTarget(this); + fShuffle->SetTarget(this); + fRepeat->SetTarget(this); +} + +void +CDButton::Pulse() +{ + engine->DoPulse(); +} + +class CDButtonWindow : public BWindow +{ +public: + CDButtonWindow(void); + bool QuitRequested(void); +}; + +CDButtonWindow::CDButtonWindow(void) + : BWindow(BRect (100, 100, 610, 400), "CD Player", B_TITLED_WINDOW, 0) +{ +} + +bool CDButtonWindow::QuitRequested(void) +{ + be_app->PostMessage(B_QUIT_REQUESTED); + return true; +} + +CDButtonApplication::CDButtonApplication() + : BApplication("application/x-vnd.Be-CDPlayer") +{ + BWindow *window = new CDButtonWindow(); + + BView *button = new CDButton(window->Bounds(), "CD"); + window->AddChild(button); + window->Show(); +} + + +int +main(int, char **argv) +{ + (new CDButtonApplication())->Run(); + + return 0; +} diff --git a/src/apps/cdplayer/CDButton.h b/src/apps/cdplayer/CDButton.h new file mode 100644 index 0000000000..04cec69163 --- /dev/null +++ b/src/apps/cdplayer/CDButton.h @@ -0,0 +1,72 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ +// This defines the replicant button + +#ifndef __CD_BUTTON__ +#define __CD_BUTTON__ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Observer.h" +#include "CDEngine.h" + +class DrawButton; + +class CDButton : public BView, private Observer +{ +public: + CDButton(BRect frame, const char *name, uint32 resizeMask = B_FOLLOW_ALL, + uint32 flags = B_WILL_DRAW | B_NAVIGABLE | B_PULSE_NEEDED); + + virtual ~CDButton(); + + void BuildGUI(void); + + // misc BView overrides + virtual void AttachedToWindow(); + + virtual void Pulse(); + + virtual void MessageReceived(BMessage *); + + // observing overrides + virtual BHandler *RecipientHandler() const + { return (BHandler *)this; } + + virtual void NoticeChange(Notifier *); + +private: + void UpdateTrackInfo(void); + + CDEngine *engine; + + DrawButton *fStop, *fPlay, *fNextTrack, *fPrevTrack; + DrawButton *fFastFwd, *fRewind, *fEject, *fSave, *fShuffle, *fRepeat; + + BSlider *fVolume; + + BTextControl *fCDTitle; + BStringView *fTrackNumber; + + CDState fCDState; + int32 fTrackCount, fCurrentTrack; +}; + + +class CDButtonApplication : public BApplication +{ +public: + CDButtonApplication(); +}; + + +#endif \ No newline at end of file diff --git a/src/apps/cdplayer/CDDBSupport.cpp b/src/apps/cdplayer/CDDBSupport.cpp new file mode 100644 index 0000000000..e227ca2839 --- /dev/null +++ b/src/apps/cdplayer/CDDBSupport.cpp @@ -0,0 +1,583 @@ +// Copyright 1992-2000, Be Incorporated, All Rights Reserved. +// This file may be used under the terms of the Be Sample Code License. +// +// send comments/suggestions/feedback to pavel@be.com +// + +#include "CDDBSupport.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + + +// #pragma mark - +// some glue + +template +void +InitCheck(InitCheckable *item) +{ + if (!item) + throw B_ERROR; + status_t error = item->InitCheck(); + if (error != B_OK) + throw error; +} + +inline void +ThrowOnError(status_t error) +{ + if (error != B_OK) + throw error; +} + +inline void +ThrowIfNotSize(ssize_t size) +{ + if (size < 0) + throw (status_t)size; +} + + +// #pragma mark - + +CDDBQuery::CDDBQuery(const char *server, int32 port, bool log) + : log(log), + serverName(server), + port(port), + connected(false), + discID(-1), + state(kInitial) +{ +} + +void +CDDBQuery::SetToSite(const char *server, int32 port) +{ + Disconnect(); + serverName = server; + port = port; + state = kInitial; +} + +void +CDDBQuery::SetToCD(const scsi_toc *toc) +{ + if (state == kInitial) { + GetDiscID(toc, discID, numTracks, discLength, frameOffsetString, discIDStr); + } else { + int32 tmpDiscID; + int32 tmpDiscLength; + int32 tmpNumTracks; + BString tmpFrameOffsetString; + BString tmpDiscIDStr; + + GetDiscID(toc, tmpDiscID, tmpNumTracks, tmpDiscLength, tmpFrameOffsetString, + tmpDiscIDStr); + + if (discID == tmpDiscID && discLength == tmpDiscLength && numTracks == tmpNumTracks + && frameOffsetString == frameOffsetString) + return; + + discID = tmpDiscID; + discLength = tmpDiscLength; + numTracks = tmpNumTracks; + frameOffsetString = tmpFrameOffsetString; + discIDStr = tmpDiscIDStr; + } + + // ToDo: + // add interrupting here + + result = B_OK; + state = kReading; + thread = spawn_thread(&CDDBQuery::LookupBinder, "CDDBLookup", B_NORMAL_PRIORITY, this); + if (thread >= 0) + resume_thread(thread); + else { + state = kError; + result = thread; + } +} + +const int kTerminatingSignal = SIGINT; // SIGCONT; + +static void +DoNothing(int) +{ +} + +int32 +CDDBQuery::LookupBinder(void *castToThis) +{ + CDDBQuery *query = (CDDBQuery *)castToThis; + + BFile file; + entry_ref ref; + bool newFile = false; + + try { + signal(kTerminatingSignal, DoNothing); + + if (!query->FindOrCreateContentFileForDisk(&file, &ref, query->discID)) { + // new content file, read it in from the server + Connector connection(query); + query->ReadFromServer(&file); + file.Seek(0, SEEK_SET); + newFile = true; + } + query->ParseResult(&file); + + query->state = kDone; + query->thread = -1; + query->result = B_OK; + + if (newFile) { + BString newTitle(query->title); + int32 length = newTitle.Length(); + for (int32 index = 0; index < length; index++) { + if (newTitle[index] == '/' || newTitle[index] == ':') + newTitle[index] = '-'; + } + + file.Sync(); + BEntry entry(&ref); + entry.Rename(newTitle.String(), false); + } + + } catch (status_t error) { + query->state = kError; + query->result = error; + + // the cached file is messed up, remove it + BEntry entry(&ref); + BPath path; + entry.GetPath(&path); + printf("removing bad CD content file %s\n", path.Path()); + entry.Remove(); + } + return 0; +} + + +const char * +CDDBQuery::GetToken(const char *stream, BString &result) +{ + result = ""; + while (*stream && *stream <= ' ') + stream++; + while (*stream && *stream > ' ') + result += *stream++; + + return stream; +} + + +void +CDDBQuery::GetSites(bool (*eachFunc)(const char *site, int port, const char *latitude, + const char *longitude, const char *description, void *state), void *passThru) +{ + // ToDo: + // add interrupting here + + Connector connection(this); + BString tmp; + + tmp = "sites\n"; + if (log) + printf(">%s", tmp.String()); + + ThrowIfNotSize( socket.Send(tmp.String(), tmp.Length()) ); + ReadLine(tmp); + + if (tmp.FindFirst("210") == -1) + throw (status_t)B_ERROR; + + for (;;) { + BString site; + int32 sitePort; + BString latitude; + BString longitude; + BString description; + + ReadLine(tmp); + if (tmp == ".") + break; + const char *scanner = tmp.String(); + + scanner = GetToken(scanner, site); + BString portString; + scanner = GetToken(scanner, portString); + sitePort = atoi(portString.String()); + scanner = GetToken(scanner, latitude); + scanner = GetToken(scanner, longitude); + description = scanner; + + if (eachFunc(site.String(), sitePort, latitude.String(), longitude.String(), + description.String(), passThru)) + break; + } +} + +bool +CDDBQuery::GetTitles(BString *resultingTitle, vector *tracks, bigtime_t timeout) +{ + bigtime_t deadline = system_time() + timeout; + while (state == kReading) { + snooze(50000); + if (system_time() > deadline) + break; + } + if (state != kDone) + return false; + + if (resultingTitle) + *resultingTitle = title; + + if (tracks) + *tracks = trackNames; + return true; +} + +static int32 +cddb_sum(int n) +{ + char buf[12]; + int32 ret = 0; + + sprintf(buf, "%u", n); + for (const char *p = buf; *p != '\0'; p++) + ret += (*p - '0'); + return ret; +} + +struct ConvertedToc { + int32 min; + int32 sec; + int32 frame; +}; + +int32 +CDDBQuery::GetDiscID(const scsi_toc *toc) +{ + int32 tmpDiscID; + int32 tmpDiscLength; + int32 tmpNumTracks; + BString tmpFrameOffsetString; + BString tmpDiscIDStr; + + GetDiscID(toc, tmpDiscID, tmpNumTracks, tmpDiscLength, tmpFrameOffsetString, + tmpDiscIDStr); + + return tmpDiscID; +} + +void +CDDBQuery::GetDiscID(const scsi_toc *toc, int32 &id, int32 &numTracks, + int32 &length, BString &frameOffsetsString, BString &discIDString) +{ + ConvertedToc tocData[100]; + + // figure out the disc ID + for (int index = 0; index < 100; index++) { + tocData[index].min = toc->toc_data[9 + 8*index]; + tocData[index].sec = toc->toc_data[10 + 8*index]; + tocData[index].frame = toc->toc_data[11 + 8*index]; + } + numTracks = toc->toc_data[3] - toc->toc_data[2] + 1; + + int32 sum1 = 0; + int32 sum2 = 0; + for (int index = 0; index < numTracks; index++) { + sum1 += cddb_sum((tocData[index].min * 60) + tocData[index].sec); + // the following is probably running over too far + sum2 += (tocData[index + 1].min * 60 + tocData[index + 1].sec) - + (tocData[index].min * 60 + tocData[index].sec); + } + id = ((sum1 % 0xff) << 24) + (sum2 << 8) + numTracks; + discIDString = ""; + + sprintf(discIDString.LockBuffer(10), "%08lx", id); + discIDString.UnlockBuffer(); + + // compute the total length of the CD. + length = tocData[numTracks].min * 60 + tocData[numTracks].sec; + + for (int index = 0; index < numTracks; index++) + frameOffsetsString << tocData[index].min * 4500 + tocData[index].sec * 75 + + tocData[index].frame << ' '; +} + +void +CDDBQuery::ReadFromServer(BDataIO *stream) +{ + // Format the query + BString query; + query << "cddb query " << discIDStr << ' ' << numTracks << ' ' + // Add frame offsets + << frameOffsetString << ' ' + // Finish it off with the total CD length. + << discLength << '\n'; + + if (log) + printf(">%s", query.String()); + + // Send it off. + ThrowIfNotSize( socket.Send(query.String(), query.Length()) ); + + BString tmp; + ReadLine(tmp); + if (tmp.FindFirst("200") != 0) + return; + + BString category; + GetToken(tmp.String() + 3, category); + if (!category.Length()) + category = "misc"; + + query = ""; + query << "cddb read " << category << ' ' << discIDStr << '\n' ; + ThrowIfNotSize( socket.Send(query.String(), query.Length()) ); + + for (;;) { + BString tmp; + ReadLine(tmp); + tmp += '\n'; + ThrowIfNotSize( stream->Write(tmp.String(), tmp.Length()) ); + if (tmp == "." || tmp == ".\n") + break; + } + state = kDone; +} + +void +CDDBQuery::ParseResult(BDataIO *source) +{ + title = ""; + trackNames.clear(); + for (;;) { + BString tmp; + ReadLine(source, tmp); + if (tmp == ".") + break; + + if (tmp == "") + throw (status_t)B_ERROR; + + if (tmp.FindFirst("DTITLE=") == 0) + title = tmp.String() + sizeof("DTITLE"); + else if (tmp.FindFirst("TTITLE") == 0) { + int32 afterIndex = tmp.FindFirst('='); + if (afterIndex > 0) { + BString trackName(tmp.String() + afterIndex + 1); + trackNames.push_back(trackName); + } + } + } + state = kDone; +} + + +void +CDDBQuery::Connect() +{ + BNetAddress address(serverName.String(), port); + InitCheck(&address); + + ThrowOnError( socket.Connect(address) ); + connected = true; + + BString tmp; + ReadLine(tmp); + IdentifySelf(); +} + +bool +CDDBQuery::IsConnected() const +{ + return connected; +} + +void +CDDBQuery::Disconnect() +{ + socket.Close(); + connected = false; +} + +void +CDDBQuery::ReadLine(BString &buffer) +{ + buffer = ""; + char ch; + for (;;) { + if (socket.Receive(&ch, 1) <= 0) + break; + if (ch >= ' ') + buffer += ch; + if (ch == '\n') + break; + } + if (log) + printf("<%s\n", buffer.String()); +} + +void +CDDBQuery::ReadLine(BDataIO *stream, BString &buffer) +{ + // this is super-lame, should use better buffering + // ToDo: + // redo using LockBuffer, growing the buffer by 2k and reading into it + + buffer = ""; + char ch; + for (;;) { + ssize_t result = stream->Read(&ch, 1); + + if (result < 0) + // read error + throw (status_t)result; + if (result == 0) + break; + if (ch >= ' ') + buffer += ch; + if (ch == '\n') + break; + } +} + + +void +CDDBQuery::IdentifySelf() +{ + char username[256]; + if (!getusername(username,256)) + strcpy(username, "unknown"); + + char hostname[MAXHOSTNAMELEN + 1]; + if (gethostname(hostname, MAXHOSTNAMELEN) == -1) + strcpy(hostname, "unknown"); + + BString tmp; + tmp << "cddb hello " << username << " " << hostname << " CDButton v1.0\n"; + + if (log) + printf(">%s", tmp.String()); + ThrowIfNotSize( socket.Send(tmp.String(), tmp.Length()) ); + + ReadLine(tmp); +} + +bool +CDDBQuery::FindOrCreateContentFileForDisk(BFile *file, entry_ref *fileRef, int32 discID) +{ + BString predicate; + predicate << "cddb:discID == " << discID; + entry_ref ref; + + BVolumeRoster roster; + BVolume volume; + roster.Rewind(); + while (roster.GetNextVolume(&volume) == B_OK) { + if (volume.IsReadOnly() || !volume.IsPersistent() + || !volume.KnowsAttr() || !volume.KnowsQuery()) + continue; + + // make sure the volume we are looking at is indexed right + fs_create_index(volume.Device(), "cddb:discID", B_INT32_TYPE, 0); + + BQuery query; + query.SetVolume(&volume); + query.SetPredicate(predicate.String()); + if (query.Fetch() != B_OK) + continue; + + while (query.GetNextRef(&ref) == B_OK) { + // we have one already, return + file->SetTo(&ref, O_RDONLY); + *fileRef = ref; + return true; + } + } + + BPath path; + ThrowOnError( find_directory(B_USER_SETTINGS_DIRECTORY, &path, true) ); + path.Append("CDContentFiles"); + ThrowOnError( create_directory(path.Path(), 0755) ); + + BDirectory dir(path.Path()); + BString name("CDContent"); + for (int32 index = 0; ;index++) { + if (dir.CreateFile(name.String(), file, true) != B_FILE_EXISTS) { + BEntry entry(&dir, name.String()); + entry.GetRef(fileRef); + file->WriteAttr("cddb:discID", B_INT32_TYPE, 0, &discID, sizeof(int32)); + break; + } + name = "CDContent"; + name << index; + } + return false; +} + +#if 0 + +bool +PrintSite(const char *site, int port, const char *latitude, + const char *longitude, const char *description, void *) +{ + printf("server:%s port:%d latitude:%s longitude:%s description: %s\n", + site, port, latitude, longitude, description); + return false; +} + +int +main() +{ + try { + CDDBQuery query("us.cddb.com", 888, true); + // query.GetSites(&PrintSite, NULL); + + int32 device = CDEngine::FindCDPlayerDevice(); + if (!device) { + printf("no device %s\n", strerror(device)); + return 0; + } + CDEngine engine(device); + scsi_toc toc; + engine.GetToc(&toc); + + query.SetToCD(&toc); + + BString title; + vector trackTitles; + query.GetTitles(title, trackTitles, 10000000); + + printf("CD Title:%s\n", title.String()); + int32 index = 0; + for (vector::iterator iterator = trackTitles.begin(); + iterator != trackTitles.end(); index++, iterator++) + printf("%d: %s\n", index, (*iterator).String()); + + } catch(status_t error) { + printf("error %s\n", strerror(error)); + } + return 0; +} + +#endif \ No newline at end of file diff --git a/src/apps/cdplayer/CDDBSupport.h b/src/apps/cdplayer/CDDBSupport.h new file mode 100644 index 0000000000..bbbfc7169f --- /dev/null +++ b/src/apps/cdplayer/CDDBSupport.h @@ -0,0 +1,107 @@ +#ifndef __CDDBSUPPORT__ +#define __CDDBSUPPORT__ + +#include +#include +#include +#include + + +// based on Jukebox by Chip Paul + +class CDDBQuery { +public: + CDDBQuery(const char *server, int32 port = 888, bool log = false); + void SetToSite(const char *server, int32 port); + void GetSites(bool (*)(const char *site, int port, const char *latitude, + const char *longitude, const char *description, void *state), void *); + + void SetToCD(const scsi_toc *); + bool GetTitles(BString *title, vector *tracks, bigtime_t timeout); + // title or tracks may be NULL if you are only interrested in one, not the other + + bool Ready() const + { return state == kDone; } + + int32 CurrentDiscID() const + { return discID; } + + static int32 GetDiscID(const scsi_toc *); + +private: + + static void GetDiscID(const scsi_toc *, int32 &id, int32 &numTracks, int32 &length, + BString &tmpFrameOffsetString, BString &discIDString); + + void Connect(); + void Disconnect(); + bool IsConnected() const; + + static int32 LookupBinder(void *); + + class Connector { + public: + Connector(CDDBQuery *client) + : client(client), + wasConnected(client->IsConnected()) + { + if (!wasConnected) + client->Connect(); + } + + ~Connector() + { + if (!wasConnected) + client->Disconnect(); + } + + private: + CDDBQuery *client; + bool wasConnected; + }; + + bool FindOrCreateContentFileForDisk(BFile *file, entry_ref *ref, int32 discID); + + void ReadFromServer(BDataIO *); + void ParseResult(BDataIO *); + + void ReadLine(BString &); + static void ReadLine(BDataIO *, BString &); + void IdentifySelf(); + + const char *GetToken(const char *, BString &); + + bool log; + + // connection description + BString serverName; + BNetEndpoint socket; + int32 port; + bool connected; + + // disc identification + int32 discID; + int32 discLength; + int32 numTracks; + BString frameOffsetString; + BString discIDStr; + + // cached retrieved data + enum State { + kInitial, + kReading, + kDone, + kInterrupting, + kError + }; + + thread_id thread; + State state; + BString title; + vector trackNames; + status_t result; + + friend class Connector; +}; + +#endif diff --git a/src/apps/cdplayer/CDEngine.cpp b/src/apps/cdplayer/CDEngine.cpp new file mode 100644 index 0000000000..7c5fd34f87 --- /dev/null +++ b/src/apps/cdplayer/CDEngine.cpp @@ -0,0 +1,607 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "CDEngine.h" + +PeriodicWatcher::PeriodicWatcher(int devicefd) + : Notifier(), + devicefd(devicefd) +{ +} + + +PeriodicWatcher::PeriodicWatcher(BMessage *) + : devicefd(-1) +{ + // not implemented yet + PRINT(("under construction")); +} + +BHandler * +PeriodicWatcher::RecipientHandler() const +{ + return engine; +} + +void +PeriodicWatcher::DoPulse() +{ + // control the period here + if (UpdateState()) + Notify(); +} + +void +PeriodicWatcher::UpdateNow() +{ + UpdateState(); +} + + +PlayState::PlayState(int devicefd) + : PeriodicWatcher(devicefd), + oldState(kNoCD) +{ +} + +bool +PlayState::UpdateState() +{ + // check the current CD play state and force a notification to + // be sent if it changed from last time + scsi_position pos; + status_t media_status = B_DEV_NO_MEDIA; + ioctl(devicefd, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status)); + if (media_status != B_NO_ERROR) + return CurrentState(kNoCD); + + status_t result = ioctl(devicefd, B_SCSI_GET_POSITION, &pos); + + if (result != B_NO_ERROR) + return CurrentState(kNoCD); + else if ((!pos.position[1]) || (pos.position[1] >= 0x13) || + ((pos.position[1] == 0x12) && (!pos.position[6]))) + return CurrentState(kStopped); + else if (pos.position[1] == 0x11) + return CurrentState(kPlaying); + else + return CurrentState(kPaused); +} + +CDState +PlayState::GetState() const +{ + return oldState; +} + +bool +PlayState::CurrentState(CDState newState) +{ + if (newState != oldState) { + oldState = newState; + return true; + } + return false; +} + +TrackState::TrackState(int devicefd) + : PeriodicWatcher(devicefd), + currentTrack(0) +{ +} + +int32 +TrackState::GetTrack() const +{ + return currentTrack; +} + +bool +TrackState::UpdateState() +{ + // check the current CD track number and force a notification to + // be sent if it changed from last time + scsi_position pos; + + status_t media_status = B_DEV_NO_MEDIA; + ioctl(devicefd, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status)); + if (media_status != B_NO_ERROR) + return CurrentState(-1); + + status_t result = ioctl(devicefd, B_SCSI_GET_POSITION, &pos); + + if (result != B_NO_ERROR) + return CurrentState(-1); + + if (!pos.position[1] || pos.position[1] >= 0x13 + || (pos.position[1] == 0x12 && !pos.position[6])) + return CurrentState(0); + else + return CurrentState(pos.position[6]); +} + +int32 +TrackState::GetNumTracks() const +{ + // get the number of tracks on the current CD + + scsi_toc toc; + + status_t result = ioctl(devicefd, B_SCSI_GET_TOC, &toc); + + if (result != B_NO_ERROR) + return 0; + + return toc.toc_data[3]; +} + +bool +TrackState::CurrentState(int32 track) +{ + if (track != currentTrack) { + currentTrack = track; + return true; + } + return false; +} + +bool +TimeState::UpdateState() +{ + // check the current CD time and force a notification to + // be sent if it changed from last time + // currently only supports global time + scsi_position pos; + + status_t media_status = B_DEV_NO_MEDIA; + ioctl(devicefd, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status)); + if (media_status != B_NO_ERROR) + return CurrentState(-1, -1); + + status_t result = ioctl(devicefd, B_SCSI_GET_POSITION, &pos); + + if (result != B_NO_ERROR) + return CurrentState(-1, -1); + else if ((!pos.position[1]) || (pos.position[1] >= 0x13) || + ((pos.position[1] == 0x12) && (!pos.position[6]))) + return CurrentState(0, 0); + else + return CurrentState(pos.position[9], pos.position[10]); +} + +bool +TimeState::CurrentState(int32 minutes, int32 seconds) +{ + if (minutes == oldMinutes && seconds == oldSeconds) + return false; + oldMinutes = minutes; + oldSeconds = seconds; + return true; +} + +void +TimeState::GetTime(int32 &minutes, int32 &seconds) const +{ + minutes = oldMinutes; + seconds = oldSeconds; +} + + +CDContentWatcher::CDContentWatcher(int devicefd) + : PeriodicWatcher(devicefd), + cddbQuery("us.cddb.com", 888, true), + discID(-1), + wasReady(false) +{ +} + +CDContentWatcher::CDContentWatcher(BMessage *message) + : PeriodicWatcher(message), + cddbQuery("us.cddb.com", 888, true), + discID(-1), + wasReady(false) +{ +} + +bool +CDContentWatcher::GetContent(BString *title, vector *tracks) +{ + return cddbQuery.GetTitles(title, tracks, 1000000); +} + +bool +CDContentWatcher::UpdateState() +{ + bool newReady = false; + bool newDiscID = -1; + if (engine->PlayStateWatcher()->GetState() != kNoCD) { + scsi_toc toc; + ioctl(devicefd, B_SCSI_GET_TOC, &toc); + newDiscID = cddbQuery.GetDiscID(&toc); + if (discID != newDiscID) + cddbQuery.SetToCD(&toc); + } + + bool result = newReady != cddbQuery.Ready() && newDiscID != discID; + newReady = cddbQuery.Ready(); + newDiscID = discID; + + return result; +} + +CDEngine::CDEngine(int devicefd) + : BHandler("CDEngine"), + devicefd(devicefd), + playState(devicefd), + trackState(devicefd), + timeState(devicefd), + volumeState(devicefd), + contentWatcher(devicefd) +{ +} + +CDEngine::CDEngine(BMessage *message) + : BHandler(message), + devicefd(-1), + playState(message), + trackState(message), + timeState(message), + volumeState(message), + contentWatcher(devicefd) +{ +} + +CDEngine::~CDEngine() +{ + if(devicefd >= 0) + close(devicefd); +} + +void +CDEngine::AttachedToLooper(BLooper *looper) +{ + looper->AddHandler(this); + playState.AttachedToLooper(this); + trackState.AttachedToLooper(this); + timeState.AttachedToLooper(this); + volumeState.AttachedToLooper(this); + contentWatcher.AttachedToLooper(this); +} + +void +CDEngine::PlayOrPause() +{ + // if paused, or stopped, plays, if playing, pauses + playState.UpdateNow(); + switch (playState.GetState()) { + case kNoCD: + Play(); + return; + case kStopped: + Play(); + break; + case kPaused: + PlayContinue(); + break; + case kPlaying: + Pause(); + break; + default: + break; + } +} + +void +CDEngine::Pause() +{ + // pause the CD + status_t result = ioctl(devicefd, B_SCSI_PAUSE_AUDIO); + if (result != B_NO_ERROR) { + PRINT(("error %s pausing\n", strerror(errno))); + return; + } +} + +void +CDEngine::Play() +{ + // play the CD + if (playState.GetState() == kNoCD) { + // no CD available, bail out + ioctl(devicefd, B_LOAD_MEDIA, 0, 0); + return; + } + + scsi_play_track track; + + track.start_track = 1; + track.start_index = 1; + track.end_track = 99; + track.end_index = 1; + + status_t result = ioctl(devicefd, B_SCSI_PLAY_TRACK, &track); + if (result != B_NO_ERROR) { + PRINT(("error %s playing track\n", strerror(errno))); + return; + } +} + +void +CDEngine::PlayContinue() +{ + // continue after a pause + status_t result = ioctl(devicefd, B_SCSI_RESUME_AUDIO); + if (result != B_NO_ERROR) { + PRINT(("error %s resuming\n", strerror(errno))); + return; + } +} + +void +CDEngine::Stop() +{ + // stop a playing CD + status_t result = ioctl(devicefd, B_SCSI_STOP_AUDIO); + if (result != B_NO_ERROR) { + PRINT(("error %s stoping\n", strerror(errno))); + return; + } +} + +void +CDEngine::Eject() +{ + // eject or load a CD + status_t media_status = B_DEV_NO_MEDIA; + + // get the status first + ioctl(devicefd, B_GET_MEDIA_STATUS, &media_status, sizeof(media_status)); + + // if door open, load the media, else eject the CD + status_t result = ioctl(devicefd, + media_status == B_DEV_DOOR_OPEN ? B_LOAD_MEDIA : B_EJECT_DEVICE); + + if (result != B_NO_ERROR) { + PRINT(("error %s ejecting\n", strerror(errno))); + return; + } +} + +void +CDEngine::SkipOneForward() +{ + // skip forward by one track + CDState state = playState.GetState(); + + if (state == kNoCD) + return; + + bool wasPaused = state == kPaused + || state == kStopped; + + SelectTrack(trackState.GetTrack() + 1); + if (wasPaused) + // make sure we don't start playing if we were paused before + Pause(); +} + +void +CDEngine::SkipOneBackward() +{ + // skip backward by one track + CDState state = playState.GetState(); + + if (state == kNoCD) + return; + + bool wasPaused = state == kPaused + || state == kStopped; + + int32 track = trackState.GetTrack(); + + if (track > 1) + track--; + + SelectTrack(track); + + if (wasPaused) + // make sure we don't start playing if we were paused before + Pause(); +} + +void +CDEngine::StartSkippingBackward() +{ + // start skipping + CDState state = playState.GetState(); + + if (state == kNoCD) + return; + + scsi_scan scan; + scan.direction = -1; + scan.speed = 1; + status_t result = ioctl(devicefd, B_SCSI_SCAN, &scan); + if (result != B_NO_ERROR) { + PRINT(("error %s skipping backward\n", strerror(errno))); + return; + } +} + +void +CDEngine::StartSkippingForward() +{ + // start skipping + CDState state = playState.GetState(); + + if (state == kNoCD) + return; + + scsi_scan scan; + scan.direction = 1; + scan.speed = 1; + status_t result = ioctl(devicefd, B_SCSI_SCAN, &scan); + if (result != B_NO_ERROR) { + PRINT(("error %s skipping forward\n", strerror(errno))); + return; + } +} + +void +CDEngine::StopSkipping() +{ + // stop skipping + CDState state = playState.GetState(); + + if (state == kNoCD) + return; + + scsi_scan scan; + scan.direction = 0; + scan.speed = 1; + status_t result = ioctl(devicefd, B_SCSI_SCAN, &scan); + if (result != B_NO_ERROR) { + PRINT(("error %s in stop skipping\n", strerror(errno))); + return; + } + + result = ioctl(devicefd, B_SCSI_RESUME_AUDIO); + if (result != B_NO_ERROR) { + PRINT(("error %s resuming\n", strerror(errno))); + return; + } + +} + +void +CDEngine::SelectTrack(int32 trackNumber) +{ + // go to a selected track + if (playState.GetState() == kNoCD) + return; + + scsi_play_track track; + + track.start_track = trackNumber; + track.start_index = 1; + track.end_track = 99; + track.end_index = 1; + + status_t result = ioctl(devicefd, B_SCSI_PLAY_TRACK, &track); + if (result != B_NO_ERROR) { + PRINT(("error %s playing track\n", strerror(errno))); + return; + } +} + +const bigtime_t kPulseRate = 500000; + +void +CDEngine::DoPulse() +{ + // this is the CDEngine's hearbeat; Since it is a Notifier, it checks if + // any values changed since the last hearbeat and sends notices to observers + + bigtime_t time = system_time(); + if (time > lastPulse && time < lastPulse + kPulseRate) + return; + + // every pulse rate have all the different state watchers check the + // curent state and send notifications if anything changed + + lastPulse = time; + + playState.DoPulse(); + trackState.DoPulse(); + timeState.DoPulse(); + volumeState.DoPulse(); + contentWatcher.DoPulse(); +} + +void +CDEngine::MessageReceived(BMessage *message) +{ + if (message->what == 'slTk') { + // handle message from menu selection + int32 track; + if (message->FindInt32("track", &track) == B_OK) + SelectTrack(track); + + } else + // handle observing + if (!Notifier::HandleObservingMessages(message) + && !CDEngineFunctorFactory::DispatchIfFunctionObject(message)) + BHandler::MessageReceived(message); +} + + +static int +try_dir(const char *directory) +{ + BDirectory dir; + dir.SetTo(directory); + if(dir.InitCheck() != B_NO_ERROR) { + return false; + } + dir.Rewind(); + BEntry entry; + while(dir.GetNextEntry(&entry) >= 0) { + BPath path; + const char *name; + entry_ref e; + + if(entry.GetPath(&path) != B_NO_ERROR) + continue; + name = path.Path(); + + if(entry.GetRef(&e) != B_NO_ERROR) + continue; + + if(entry.IsDirectory()) { + if(strcmp(e.name, "floppy") == 0) + continue; // ignore floppy (it is not silent) + int devfd = try_dir(name); + if(devfd >= 0) + return devfd; + } + else { + int devfd; + device_geometry g; + + if(strcmp(e.name, "raw") != 0) + continue; // ignore partitions + + devfd = open(name, O_RDONLY); + if(devfd < 0) + continue; + + if(ioctl(devfd, B_GET_GEOMETRY, &g, sizeof(g)) >= 0) { + if(g.device_type == B_CD) + { + return devfd; + } + } + close(devfd); + } + } + return B_ERROR; +} + +int +CDEngine::FindCDPlayerDevice() +{ + return try_dir("/dev/disk"); +} + diff --git a/src/apps/cdplayer/CDEngine.h b/src/apps/cdplayer/CDEngine.h new file mode 100644 index 0000000000..28ef3838fe --- /dev/null +++ b/src/apps/cdplayer/CDEngine.h @@ -0,0 +1,226 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +// This defines an engine that tracks the state of the CD player +// and supports the CD player control and status calls + +#ifndef __CD_ENGINE__ +#define __CD_ENGINE__ + +#include +#include +#include + +#include + +#include "Observer.h" +#include "FunctionObjectMessage.h" +#include "CDDBSupport.h" + +class CDEngine; +class PeriodicWatcher : public Notifier { +// watcher sits somewhere were it can get pulses and makes sure +// notices get sent if state changes +public: + PeriodicWatcher(int devicefd); + PeriodicWatcher(BMessage *); + + virtual ~PeriodicWatcher() {} + + void DoPulse(); + void UpdateNow(); + + void AttachedToLooper(CDEngine *engine) + { this->engine = engine; } + + virtual BHandler *RecipientHandler() const; + +protected: + virtual bool UpdateState() = 0; + + int devicefd; + CDEngine *engine; +}; + +enum CDState { + kNoCD=0, + kStopped, + kPaused, + kPlaying, + kSkipping +}; + +class PlayState : public PeriodicWatcher { + // this watcher sends notices to observers that are interrested + // about play state changes +public: + PlayState(int devicefd); + PlayState(BMessage *message) + : PeriodicWatcher(message) + {} + + CDState GetState() const; + +private: + bool UpdateState(); + bool CurrentState(CDState); + CDState oldState; +}; + +class TrackState : public PeriodicWatcher { + // this watcher sends notices to observers that are interrested + // about changes in the current track +public: + TrackState(int devicefd); + TrackState(BMessage *message) + : PeriodicWatcher(message) + {} + + int32 GetTrack() const; + int32 GetNumTracks() const; + +private: + bool UpdateState(); + bool CurrentState(int32); + int32 currentTrack; +}; + +class TimeState : public PeriodicWatcher { + // this watcher sends notices to observers that are interrested + // about changes in the current time +public: + TimeState(int devicefd) + : PeriodicWatcher(devicefd) + { } + TimeState(BMessage *message) + : PeriodicWatcher(message) + {} + + void GetTime(int32 &minutes, int32 &seconds) const; + +private: + bool UpdateState(); + bool CurrentState(int32 minutes, int32 seconds); + int32 oldMinutes; + int32 oldSeconds; +}; + +class CDContentWatcher : public PeriodicWatcher { +public: + CDContentWatcher(int devicefd); + CDContentWatcher(BMessage *message); + + bool GetContent(BString *title, vector *tracks); + +private: + bool UpdateState(); + + CDDBQuery cddbQuery; + int32 discID; + bool wasReady; +}; + +class VolumeState : public PeriodicWatcher { + // this watcher sends notices to observers that are interrested + // about changes in the current volume + // currently not used yet +public: + VolumeState(int devicefd) + : PeriodicWatcher(devicefd) + { } + VolumeState(BMessage *message) + : PeriodicWatcher(message) + {} + + bool UpdateState() { return true; } + virtual void DoPulse() {} + int32 GetVolume() const; +}; + +class CDEngine : public BHandler { + // The CD engine defines all the different CD control calls; also, + // it hosts the different state watchers and helps them send notices + // to observers about the CD state changes +public: + CDEngine(int devicefd); + CDEngine(BMessage *); + + virtual ~CDEngine(); + + // observing supprt + virtual void MessageReceived(BMessage *); + void AttachedToLooper(BLooper *); + void DoPulse(); + + // control calls + void PlayOrPause(); + void PlayContinue(); + void Play(); + void Pause(); + void Stop(); + void Eject(); + void SkipOneForward(); + void SkipOneBackward(); + void StartSkippingBackward(); + void StartSkippingForward(); + void StopSkipping(); + void SelectTrack(int32); + + + TrackState *TrackStateWatcher() + { return &trackState; } + // to find the current Track, you may call the GetTrack function + // TrackState defines + + PlayState *PlayStateWatcher() + { return &playState; } + // to find the current play state, you may call the GetState function + // PlayState defines + + TimeState *TimeStateWatcher() + { return &timeState; } + // to find the current location on the CD, you may call the GetTime function + // TimeState defines + + CDContentWatcher *ContentWatcher() + { return &contentWatcher; } + + static int FindCDPlayerDevice(); + +private: + int devicefd; + + PlayState playState; + TrackState trackState; + TimeState timeState; + VolumeState volumeState; + CDContentWatcher contentWatcher; + + bigtime_t lastPulse; +}; + + +// some function object glue +class CDEngineFunctorFactory : public FunctorFactoryCommon { +public: + static BMessage *NewFunctorMessage(void (CDEngine::*func)(), + CDEngine *target) + { + PlainMemberFunctionObject tmp(func, target); + return NewMessage(&tmp); + } + + static BMessage *NewFunctorMessage(void (CDEngine::*func)(ulong), + CDEngine *target, ulong param) + { + SingleParamMemberFunctionObject tmp(func, target, param); + return NewMessage(&tmp); + } +}; + + +#endif \ No newline at end of file diff --git a/src/apps/cdplayer/CDPlayer.cpp b/src/apps/cdplayer/CDPlayer.cpp deleted file mode 100644 index f94ce6c608..0000000000 --- a/src/apps/cdplayer/CDPlayer.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - -CDPlayer - -Author: Sikosis - -(C)2004 Haiku - http://haiku-os.org/ - -*/ - -// Includes ------------------------------------------------------------------------------------------ // -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "CDPlayer.h" -#include "CDPlayerWindows.h" -#include "CDPlayerViews.h" -#include "CDPlayerConstants.h" -// Constants ---------------------------------------------------------------------------------------- // - -const char *APP_SIGNATURE = "application/x-vnd.Haiku.CDPlayer"; // Application Signature and Title - -// -------------------------------------------------------------------------------------------------- // - -CDPlayerWindow *ptrCDPlayerWindow; - -// CDPlayer - Constructor -CDPlayer::CDPlayer() : BApplication (APP_SIGNATURE) -{ - // Default Window Size - Position doesn't matter as we centre the form to the current screen size - BRect screenFrame = (BScreen(B_MAIN_SCREEN_ID).Frame()); - - float FormTopDefault = 0; - float FormLeftDefault = 0; - float FormWidthDefault = 500; - float FormHeightDefault = 100; - BRect CDPlayerWindowRect(FormTopDefault,FormLeftDefault,FormLeftDefault+FormWidthDefault,FormTopDefault+FormHeightDefault); - - ptrCDPlayerWindow = new CDPlayerWindow(CDPlayerWindowRect); -} -// ------------------------------------------------------------------------------------------------- // - -// CDPlayer::MessageReceived -- handles incoming messages -void CDPlayer::MessageReceived (BMessage *message) -{ - switch(message->what) - { - default: - BApplication::MessageReceived(message); // pass it along ... - break; - } -} -// ------------------------------------------------------------------------------------------------- // - -// CDPlayer Main -int main(void) -{ - CDPlayer theApp; - theApp.Run(); - return 0; -} -// end --------------------------------------------------------------------------------------------- // - diff --git a/src/apps/cdplayer/CDPlayer.h b/src/apps/cdplayer/CDPlayer.h deleted file mode 100644 index 93b7f5ca0f..0000000000 --- a/src/apps/cdplayer/CDPlayer.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - -CDPlayer Header - -Author: Sikosis - -(C)2004 Haiku - http://haiku-os.org/ - -*/ - -#ifndef __CDPLAYER_H__ -#define __CDPLAYER_H__ - -extern const char *APP_SIGNATURE; - -class CDPlayer : public BApplication -{ - public: - CDPlayer(); - virtual void MessageReceived(BMessage *message); - private: - -}; - -#endif diff --git a/src/apps/cdplayer/CDPlayer.rdef b/src/apps/cdplayer/CDPlayer.rdef index b621c6e733..e6476c71c7 100644 --- a/src/apps/cdplayer/CDPlayer.rdef +++ b/src/apps/cdplayer/CDPlayer.rdef @@ -1,8 +1,32 @@ -resource(1, "BEOS:FILE_TYPES") message; +resource(1, "BEOS:APP_FLAGS") #'APPF' $"00000000"; -resource(101, "BEOS:L:STD_ICON") #'ICON' array -{ +resource(1, "BEOS:APP_VERSION") #'APPV' array { + $"00000000000000000100000001000000000000004344506C6179657200000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000426173696320434420506C61" + $"79657220666F72204861696B7500000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000000000000000000000000000000000000000000000000000" + $"0000000000000000" +}; + +resource(101, "BEOS:L:STD_ICON") #'ICON' array { $"FFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" $"FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" $"FFFFFFFFFFFFFFFFFFFF00F90000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" @@ -37,8 +61,7 @@ resource(101, "BEOS:L:STD_ICON") #'ICON' array $"FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000E0F0FFFFFFFFFFFFFFFFFFFFFFFFF" }; -resource(101, "BEOS:M:STD_ICON") #'MICN' array -{ +resource(101, "BEOS:M:STD_ICON") #'MICN' array { $"FFFFFFFF000000FFFFFFFFFFFFFFFFFF" $"FFFFFFFFFF005D0000FFFFFFFFFFFFFF" $"FFFFFFFFFFFF007D7D0000FFFFFFFFFF" @@ -59,30 +82,387 @@ resource(101, "BEOS:M:STD_ICON") #'MICN' array resource(1, "BEOS:APP_SIG") #'MIMS' "application/x-vnd.Haiku.CDPlayer"; -resource(1, "BEOS:APP_VERSION") #'APPV' array -{ - $"00000000000000000100000001000000000000004344506C6179657200000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000426173696320434420506C61" - $"79657220666F72204861696B7500000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000000000000000000000000000000000000000000000000000" - $"0000000000000000" +resource(1, "BEOS:FILE_TYPES") message; + +resource(1, "play_up") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C770000009549444154789C8591BB11C5200C04578C4A" + $"51AD8E5FE0F22076074E79013F83E5E112E058A10324030492A4243901920122" + $"448980E484C502351504104DCD0B8059E77A45AC151DAC32AD6343A60ED62695" + $"EA88AF1EA84BAF7B367E613979B4335B9DE10DA765D065ED657C547D4AF2B521" + $"8E53E1DE40230F94DB396FA5ABE1706E66B369F93AC7E9A69BFD17F3F1B7CAE1" + $"6F3CF407D134242111EC44A10000000049454E44AE426082" }; -resource(1, "BEOS:APP_FLAGS") #'APPF' $"00000000"; +resource(2, "play_down") #'PNG ' array { + $"89504E470D0A1A0A0000000D49484452000000230000001308060000001AA3B4" + $"F40000008D49444154789CCDD6C10904210C40D13F8B4DD84E4AB00E2BB038CB" + $"B18DEC6109CC6D5123E69F151E6AC0075002A4AA24805AEB55486B0DE0870128" + $"A55CC3589FDB8077D3181141444E58D64FE6046AFB9A3C516E6FC603E5FE8077" + $"50A1A629FD5F3257EF7D79AF1B6607616D633C10D632C613614D634E20AC50D3" + $"140AF3003AC6B8ED20E74C520DF1D103E00B489821B04B2C9C09000000004945" + $"4E44AE426082" +}; + +resource(3, "play_disabled") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C770000009B49444154789C8591BB15C4200C04473C95" + $"7265509FE30BAE249571C4EEC0290ECCC760F9B109B08CD0029201946411C909" + $"900C6832A2FC01C9098B00812AC975A2A97A01306B5CAB88A5A281451FBD46AB" + $"C8D0C1EAA4500DF1D50235E97E8CC6374C27F77666B3D3BDEED40C3AADBD8CB7" + $"AA5749DE17C4F653381650CF03D7ED9CB7D2D9703837B3D9B07C9CE374D3C5FE" + $"8379F95B65F3376E3A010B1C24319A2F2A100000000049454E44AE426082" +}; + +resource(4, "stop_up") #'PNG ' array { + $"89504E470D0A1A0A0000000D49484452000000230000001308060000001AA3B4" + $"F40000006E49444154789CEDD6310E80300840D18FE9517AD69EB27B6FD01507" + $"63D481585D60E0CF0C2F0C04515525402242011863B8425A6B00070660CEE986" + $"39DBBC01F7CAFBC8B35AEBD25CEFFD3326D46612639518ABC45825C6EAF305FE" + $"7359570BB599509802D73FE19D00213E3D801DE2CC137C9B1F7C290000000049" + $"454E44AE426082" +}; + +resource(5, "stop_down") #'PNG ' array { + $"89504E470D0A1A0A0000000D49484452000000230000001308060000001AA3B4" + $"F40000007649444154789CEDD6B10DC0200C00C1276209D66104E6600286631C" + $"D6708A285252A0401ABBF0D72E4E2E2C074030908810016AADAA90D61AC08501" + $"28A5A861EE0E6DC0B3F83DF22EE7BC34D77BDFC698DA8C636639669663663966" + $"D6F605FE73595733B519539800C81843DB414A892862E2D103E004602A1406AE" + $"0663330000000049454E44AE426082" +}; + +resource(6, "stop_disabled") #'PNG ' array { + $"89504E470D0A1A0A0000000D49484452000000230000001308060000001AA3B4" + $"F40000006F49444154789CEDD6310E80300840D18FE9B17ABE9EAC77E90DBAE2" + $"608C3A10AB0B0CFC99E1858120AAAA0448442800630C57486B0DE0C000CC39DD" + $"30679B37E05E791F79D67B5F9AABB57EC684DA4C62AC12639518ABC4587DBEC0" + $"7F2EEB6AA136130A53E0FA27BC1320C4A707B0036170119C944D95F600000000" + $"49454E44AE426082" +}; + +resource(7, "next_up") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C770000009649444154789C858E3B1684300C03C73C1F" + $"C567A5DE628FA7D4DC80365B04F221B0A84AEC9125CB000BC952B29C00CB0002" + $"9900CB8950814E1504304F00217020A89C004C0717E574AF38CE45C469EC12A2" + $"454D4666D54255BEEDE3E0B334F71817EDA24F21AD922E8CEAC6DB5F57D7B32C" + $"6F2FC4FA75D85FA0D699525BC74B0FCCC83D3327F79FD144F9B49FE5B7842ECC" + $"7AEBEDF50309A3288D19DE43630000000049454E44AE426082" +}; + +resource(8, "next_down") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C770000009649444154789C858ECB1583400C03C73C37" + $"410769232E813AA880E2544EDA2007F6C3624874F27AC792E090900C417B2313" + $"608810C044D2EE0208810341E30460D5EF7DB62EAB621711F5F0941075B839B4" + $"3D1749B2751917AFA91B8F71D1C2F094DF2BE9C2F45EDEDFBA5EB53EA9B4B13E" + $"952FDA6687E50FD43B73D45699F4C08CDC3353B9DF8C12E5E93FCB6F8991353E" + $"B7B727CD5FEB601F32B3AD1E6C0000000049454E44AE426082" +}; + +resource(9, "next_disabled") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C770000009A49444154789C858EBB1584300C04473C95" + $"4219AA8FF8822B4965E0980E487D01FE1B8E8D646B56BB120194E086C4004804" + $"3438263B2031E006B09025310F1A00DC4001A77006207BE2D6EB74AB359D73F7" + $"6C6C12BC464D46669542457A9CFDC767A987FB38F7EA9AF26B251B182B1BAD6F" + $"1B5DCF9278BC10DB57E17C816A67AEDA96267B607AEE99C9DC7FC6264AA7FD2C" + $"BD256C60B65B6FAB1F14962A7DEE40835F0000000049454E44AE426082" +}; + +resource(10, "prev_up") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C770000009649444154789C858FB911C3300C04171A94" + $"825A153B707960AC0E94D201FF67CC8B38C4DEE12011E022480812032011C0C1" + $"C5018901F30401584500D100600E9A6789F3CE515246D945C9334BC6CCD720F6" + $"4656D54255FABCE3C7A7D52F11BA44EAB22257F2E5279FD85CDE611767497C0E" + $"C4FD55780F50BB02B0DCC0182A0F4C99FFCBD91333E35B6EDEB5E3749ACEAFC4" + $"DCDB0EBD7E98BA296A78A62B700000000049454E44AE426082" +}; + +resource(11, "prev_down") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C770000009949444154789C858FC115C3200C43BF792C" + $"910DBA463D42E6C804194EE3748DF41008E0D04627B064498613423204D71F99" + $"0043B80012004E87230BC005F9E212A06EA3BA8C789F240EEEC53455B2854C16" + $"EDE019B6ADE3E0D5D52FF6F91697637CADA4DBA49CD8B6D4C91211F7D2C6F6AB" + $"7CC1BE64581F44ED0AC04B0367A83C682AFFCF67AE881A4D75316BA6CB818D2F" + $"00E333EDD061F902FBC91FF2833D9C250000000049454E44AE426082" +}; + +resource(12, "prev_disabled") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C770000009C49444154789C858FB911C3300C04171A94" + $"E232509F62072E096598B13A504A07FC9FB12EE2F0F68083440025B821310012" + $"010D8EC917901870033800F0820088060037D0EC25CEBA84E529A35EC9C4C13D" + $"05335F07B10FB2AA16AAD2EB1E3FDEAD7E19AFCB3A9DD7974AB6FCE4135BCA3A" + $"ECE05912AF07E2FC28DC0F50BB02F0DCC0192A0F4CF1FFCDD91333635B6EDEB5" + $"E37472E75762CE6D875E3FEE602ABACC9639B80000000049454E44AE426082" +}; + +resource(13, "ffwd_up") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C770000009F49444154789C858F3B16843008452F1E96" + $"92B55A4F31CB7BD6EEC0365324928F8EBE8243E0022F9601C8802C6F80650081" + $"4C80E52D09800580140860BE01A5AF4289051012982A97CAEA5EC9EB3695D02E" + $"941B257033C8556128E4FB31163ECBB4393E94CE003E1A50B3541CAA31F1AE95" + $"EEDD4D3DC8F2FE42AC5F87E3050ACFA430D0B29979E006E6EC9E996E1905D55D" + $"F3B13F6723F39700679D4B17FD00CCDC346454415F090000000049454E44AE42" + $"6082" +}; + +resource(14, "ffwd_down") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C770000009F49444154789C858FCB15C3300804073F35" + $"E10ED24628C175B88214B7E5A40DE720097DE2441CF46019C1021132D40A9009" + $"30E459DE0070BAB892001790C0C1111B2024B03AEFD98F2E522AD3949FB6A1EC" + $"C88B6E3EDAC53AEC3C46E1B14D93E320AF0FA4D1809AA56C438D89BA285DDDFD" + $"6A7EBE4C1BE7E286D79EE05840E1190F032D9B993FDCC0D46ECD74CB28A86E5B" + $"1AFB7336323F0930DEB334C7FE0115B3282C4AE639D10000000049454E44AE42" + $"6082" +}; + +resource(15, "ffwd_disabled") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C77000000A849444154789C858FBB15844008452F1E4A" + $"B10CEA33DE601BD85E28C389EDC0740CC6F9EAEA0B38C05CE08D4400E5072631" + $"0012010D8EC90A480C6E004C007846004403E006283838C604186620EBC9CD69" + $"75AB59CF6D9642BD906EA4C0CD2057154345BAED7DE3330D9BCB873C07D0DE80" + $"554BC9A155A6D467A7A99BA90749DC5E88E5ABB0BF40C5335E0CD46C641EB88E" + $"C9AF39B35BC60AD55CD3FE7DCC7AE62F01CA32B62E3A00C80630E7BA72D89A00" + $"00000049454E44AE426082" +}; + +resource(16, "rew_up") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C77000000A149444154789C8590311684200C447F7839" + $"4ACE6ABD85C71B6B6F60CB160882ACEB14BCBCF09319B00C40066479032C0308" + $"64022C6F10021200444500F3ADF484439466022101A6938BB2BA57785BA77254" + $"876847B51F0799D50235F97E8C8D4FEAE703C0273BBFDB9328D150DF29CF93AE" + $"A911AB5EFF64797F2196D5E17881AAFBA96819AEAA67E2473532CFC4C5A8DD6A" + $"E2FA3C4FDC98B9FBDCAE7296C9FFAE2FF13F3064D77552650000000049454E44" + $"AE426082" +}; + +resource(17, "rew_down") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C77000000AA49444154789C8592BB0DC3300C441F052D" + $"E12675D60847F01C9E20C3DD24A95C780DA7D0CFB26C9885209147DE2320A821" + $"43ED01320186C0058454F1D6C11E53878B582B0184045899F7398ECEA958C729" + $"1DC5C18F2E178DB6F31CB6CC7DE29DF1F3F8171007BB78B62790D01A4600D27A" + $"52EB6AB2B52ED2F10CD0C6F2B0C3778A303F888A7B0EAFA80EFCD6B3C62F6EBD" + $"E65ED134AA550DBA23CF9DAE67A6FB771919631BFC4F31FD01075828D428AF1D" + $"AC0000000049454E44AE426082" +}; + +resource(18, "rew_disabled") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C77000000AA49444154789C8590B911C3300C04171A94" + $"A232509F62076EC0BDB00C3156074AE9007C45CBBA00830197B8232501281F30" + $"49119004680C98EC80A408C180050042460044A3CF0C85E0C3050C3340F6CCAD" + $"BEBAD7AA759D79290EA196623F5E64560D54A5C7390E5E397EB75E273BBDDAB3" + $"E0D1BC94893FCFACDD1AB1E2F54F928E07627B2B9C0F5071CF0A3543EB7A26FC" + $"E846E69E688CD5539BB83ECF1D3766EE3EB7EB946DF2BFEA0B7B823033032405" + $"7B0000000049454E44AE426082" +}; + +resource(19, "eject_up") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C770000008E49444154789C8D913116C4200805071F47" + $"E1ACA953ECF1629D1B6C6B0A233ED164F737CA6704542900892C394BC9801440" + $"339000AA490BA12100A22D59B3E6BB239E70F09679D26CA851CB58B0DEE503B9" + $"F4FC8EC6DEFBC5765D7D80E7FE7AAF4774ACBB1A9185A49C6F6960FB28846BD8" + $"54739AB00FFFC8184C509A91094A0B2442FFFC980ED1FA9994ED679D0B07B91C" + $"F1A3B1DDDF0000000049454E44AE426082" +}; + +resource(20, "eject_down") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C770000009049444154789C8591D111C3200C431F9C97" + $"C8065DA31E217364820CE771B246FA110E834DAEFA010B5916000F0CB382B58A" + $"62400570B292704BEFA800DA7736770CD60DDF7EA83A793C361AA801E5CE5C16" + $"1DFB4C7C7C5E1CE7F000EFF3A5AD16197556A26411BA702C728F383781700D8D" + $"EF98137AF8578D4212D52C49A2BA9044D1E2C71264AAD29500285CFF6CB61FF3" + $"3B15C0D5E713DD0000000049454E44AE426082" +}; + +resource(21, "eject_disabled") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C770000009149444154789C8D91BB11C4200C051746A5" + $"5C19D4E7D8C195A43688DD81532E309F41C2F6BD04F4B44802420110B22642C9" + $"402880642002D5A485D01080202D7965B5EF923DD1C1AA4F4FAA4E35AE326AAC" + $"67F581BAE43867631FFD6CBBA131C07D7FA96BB28E0E572CB25028C7531AD8BE" + $"02E61AEA6ABA09C7F0B78C8283A2471C14178885FEF93199A2F53309DB6B9D1F" + $"5A8523B87099497F0000000049454E44AE426082" +}; + +resource(22, "save_up") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C77000000AD49444154789CA5D0316EC4300C04C0A1E0" + $"2AAF70A1EFE51BA953DCF32440A9EE07AE0E500ACB675C622306C2462477B15C" + $"6D7448AA5A1395E84835D428885E650A13348F418198AA8126F4CECAFBB2750F" + $"9B0A322890935F358DB7615EDB03D6413D0DED52F7E579B0C0E7AA943B7A3ED1" + $"DE0CF49F9B68078EC6E254A78CCF9F79BE1F030B6FE0E336B16CEBBCBB0A6507" + $"AE24748533BD4C7181A3C1DCE67FDD2A7904397B492BFAFB5F32B76F1913323C" + $"2181DF6C0000000049454E44AE426082" +}; + +resource(23, "save_down") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C77000000A549444154789CA590CB11C3200C449F189A" + $"F08D63DA3025B80E5790E2E44E32E492369403E0908013CF642FE8B3B3BB0200" + $"049D371C6C1428A6A2794504050790120DCC2BCDD60CC003776A75A3AA00B168" + $"03B3A3832F6F02422E072CB17ED693D6653754804B568A06583CD0AE01EC7322" + $"6990A80C0E75B41C3F0E2DACDF4FE03A79586A175FA964971DBAF738C3F16F9D" + $"9CE09000420A7F79692C1F1968CF4278FC92999E50C526E88C462E9A00000000" + $"49454E44AE426082" +}; + +resource(24, "save_disabled") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C77000000B649444154789CA5D0BB6DC4301004D04781" + $"A5B80C06EC84DD5C7C811B50270A18BA043370741D5C74802E10751F5B020478" + $"13EE67767638618641D3DA4023CC18DAA8856F84B9A9242264B70E81109B3E1D" + $"500A0BEEC79ADDA4CE820A127C0CFE44EC6FC6B4A41BA88D78087A525DAE8F83" + $"09CE0B532D2875877B15507E77C6BCA1A837767952FFFC9EE6CBEE6C89D367E4" + $"BA56F5A96A7CA53DE2D0114C7CABC6031819A63CFDEB56AADDC8C99B5BD16973" + $"F7EB25BF0326ED2E5BFED7474F0000000049454E44AE426082" +}; + +resource(25, "repeat_up") #'PNG ' array { + $"89504E470D0A1A0A0000000D49484452000000230000001308030000015A7A74" + $"5000000012504C5445FFFFFF000000E6E6E6DCDCDC6C6C6C008300BB001C5100" + $"0000096F464673000000000000000000DA2AB6CE000000097048597300000FA0" + $"00000FA001A06A8C770000007E49444154789CAD8F510EC0200843ADD5FB5F79" + $"90AA1B62B264593FB6525E104A9148D0BFE4ACCDA9244CAB6D662026A80976A8" + $"E9FDA39B16F31723448A21C2D49885A49255C930AC59A24334A8C31204889F93" + $"6DC5B6BDEEC961E77A96E1320DE98CE7D3E8DDCE1283CC605562B6AD9F10FF66" + $"4ED01DE5BBB29C696FC205B240065004A187160000000049454E44AE426082" +}; + +resource(26, "repeat_down") #'PNG ' array { + $"89504E470D0A1A0A0000000D49484452000000230000001308030000015A7A74" + $"5000000012504C5445000000FFFFFF6C6C6CE6E6E6BEBEBE0083004C8424AC00" + $"0000096F464673000000000000000000DA2AB6CE000000097048597300000FA0" + $"00000FA001A06A8C770000007C49444154789CAD90510EC0200843CBACF7BFF2" + $"40D40D313159D60F85478320E022413BF5EEB991963632CB4631245E04AB7851" + $"B58F4688714584E86240F3B9DE4B92907591A15951E28B78A30A2508267E26CB" + $"886579DDC866E6EBA022698DF041B5EA5AEE41F66066EE59A67E9BF8B767677A" + $"50DE2BCB3CE524B9012C9D0763558616CC0000000049454E44AE426082" +}; + +resource(27, "repeat_up_on") #'PNG ' array { + $"89504E470D0A1A0A0000000D49484452000000230000001308030000015A7A74" + $"5000000012504C5445FFFFFF000000E6E6E66C6C6CDCDCDC00FF00911226CA00" + $"0000096F464673000000000000000000DA2AB6CE000000097048597300000FA0" + $"00000FA001A06A8C770000007B49444154789CAD8FDB0EC0200843AD96FFFFE5" + $"6110276262B2AC0F0AE5844B292612EC2FE9B9469612AA59D660202A58111458" + $"B1D78F9187F02F5A88148305D7E885A49255C9D0ACA963875823813A08103F3B" + $"DB8A6D9BDE9DC3CEF5A28674C63A1A227A9631C80C6666CCB6F50AF16FE604BD" + $"56BE2BAB33ED263C9CF907A6D61A86EF0000000049454E44AE426082" +}; + +resource(28, "repeat_down_on") #'PNG ' array { + $"89504E470D0A1A0A0000000D49484452000000230000001308030000015A7A74" + $"5000000012504C5445000000FFFFFF6C6C6CE6E6E6BEBEBE00FF00CF0E125600" + $"0000096F464673000000000000000000DA2AB6CE000000097048597300000FA0" + $"00000FA001A06A8C770000007C49444154789CAD90510EC0200843CBACF7BFF2" + $"40D40D313159D60F85478320E022413BF5EEB991963632CB4631245E04AB7851" + $"B58F4688714584E86240F3B9DE4B92907591A15951E28B78A30A2508267E26CB" + $"886579DDC866E6EBA022698DF041B5EA5AEE41F66066EE59A67E9BF8B767677A" + $"50DE2BCB3CE524B9012C9D0763558616CC0000000049454E44AE426082" +}; + +resource(29, "repeat_disabled") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C77000000B749444154789C8D90BD15C3200C843FF254" + $"658E8CA13A63A574ED22D3B8D618A18D37704B0AC008E2FCA841EF743A4E1712" + $"8010310D290221011281134048D100AD634C330520483400BD111E05BB9CA8D5" + $"BAB20BA6E57134C0401D5FF781E4E1080FB51B6A7BEBD6E9EB2C59482D0B2D10" + $"9E4BAF38779E86133E2392459D45F9E2B5795E8F071B9C0198EE02FD194E76B3" + $"85ABE6846AAC1D57B31DA5A4E828B5D54AE2E8AEF7FA97D3F218FC789D83843C" + $"244C3FFF7A014CCF345764741A860000000049454E44AE426082" +}; + +resource(30, "shuffle_up") #'PNG ' array { + $"89504E470D0A1A0A0000000D49484452000000230000001308030000015A7A74" + $"5000000012504C5445FFFFFF000000E6E6E66C6C6CDCDCDC0083001298103000" + $"0000096F464673000000000000000000DA2AB6CE000000097048597300000FA0" + $"00000FA001A06A8C770000008E49444154789C85925B16802008449DC4FD6F39" + $"E46581E57C100EF720786A4D452C8F715E26113803C05F4758B0228DC8088D21" + $"E19E5EA4DEAD5842CDEE8012D22559DABFA8555DE9BE9E9C81EC5061D4818C02" + $"1B881D9845E1F86131A5CF66E6EBA08EBCC67BA73178AD7F46063B3132E064E0" + $"3BC9EBFBABEB91EC2EAD58D9330DD830FE2B44D8311F77F5937003992A073AE8" + $"E0FDC50000000049454E44AE426082" +}; + +resource(31, "shuffle_down") #'PNG ' array { + $"89504E470D0A1A0A0000000D49484452000000230000001308030000015A7A74" + $"5000000012504C5445000000FFFFFF6C6C6CE6E6E6BEBEBE0083004C8424AC00" + $"0000096F464673000000000000000000DA2AB6CE000000097048597300000FA0" + $"00000FA001A06A8C770000008749444154789C85925B168020084487C4FD6F39" + $"792847B09C0F8E0CD7800A30F1D08C2B0F5312F3B19021F222F775621248B9DD" + $"DB846A298518430FD9528A8A50F5A47E2D391DD9E1C29803D8C63A86DC825BBC" + $"9C9904539E7398F9B9A8515E63DFA9F7B1D63FA383DD181D509878D9B00FCE91" + $"B2F7B28A97E7C9020E8CFF0A114ECC47AF7613BD278906D3979AD3BB00000000" + $"49454E44AE426082" +}; + +resource(32, "shuffle_up_on") #'PNG ' array { + $"89504E470D0A1A0A0000000D49484452000000230000001308030000015A7A74" + $"5000000012504C5445FFFFFF000000E6E6E66C6C6CDCDCDC00FF00911226CA00" + $"0000096F464673000000000000000000DA2AB6CE000000097048597300000FA0" + $"00000FA001A06A8C770000008E49444154789C85925B16802008449DC4FD6F39" + $"E46581E57C100EF720786A4D452C8F715E26113803C05F4758B0228DC8088D21" + $"E19E5EA4DEAD5842CDEE8012D22559DABFA8555DE9BE9E9C81EC5061D4818C02" + $"1B881D9845E1F86131A5CF66E6EBA08EBCC67BA73178AD7F46063B3132E064E0" + $"3BC9EBFBABEB91EC2EAD58D9330DD830FE2B44D8311F77F5937003992A073AE8" + $"E0FDC50000000049454E44AE426082" +}; + +resource(33, "shuffle_down_on") #'PNG ' array { + $"89504E470D0A1A0A0000000D49484452000000230000001308030000015A7A74" + $"5000000012504C5445000000FFFFFF6C6C6CE6E6E6BEBEBE00FF00CF0E125600" + $"0000096F464673000000000000000000DA2AB6CE000000097048597300000FA0" + $"00000FA001A06A8C770000008749444154789C85925B168020084487C4FD6F39" + $"792847B09C0F8E0CD7800A30F1D08C2B0F5312F3B19021F222F775621248B9DD" + $"DB846A298518430FD9528A8A50F5A47E2D391DD9E1C29803D8C63A86DC825BBC" + $"9C9904539E7398F9B9A8515E63DFA9F7B1D63FA383DD181D509878D9B00FCE91" + $"B2F7B28A97E7C9020E8CFF0A114ECC47AF7613BD278906D3979AD3BB00000000" + $"49454E44AE426082" +}; + +resource(34, "shuffle_disabled") #'PNG ' array { + $"89504E470D0A1A0A0000000D494844520000002300000013080000000148CFDB" + $"BE000000096F464673000000000000000000DA2AB6CE00000009704859730000" + $"0FA000000FA001A06A8C77000000C449444154789C7D91B115C2301043BFFD3C" + $"0A63A8661B56A0A4A66001D648AD31480B1BA43585ED042721AA2C9DDE597717" + $"324062042200210369E6218F0058213F4156B50084548A5C09AFAA9DA2B131FC" + $"68AD4B83758AF410440CD8002E8FB431ED610E34237DA6FEBFFBAAD300E13DF5" + $"DA7D9D091218614018998885D112262217E29667D3792FF3677F9819B74782E9" + $"6FD903676D36D4A3A63CF4D43922D86DFF06B743148A8B07C958AA2AA2D13A7D" + $"BF43999EEF781065CBB29703877C394C0D3CBE855E4A1104D8C6E70000000049" + $"454E44AE426082" +}; diff --git a/src/apps/cdplayer/CDPlayerConstants.h b/src/apps/cdplayer/CDPlayerConstants.h deleted file mode 100644 index 1c57592e93..0000000000 --- a/src/apps/cdplayer/CDPlayerConstants.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - -CDPlayer Constants - -Author: Sikosis - -(C)2004 Haiku - http://haiku-os.org/ - -*/ - -#ifndef __CDPLAYERCONSTANTS_H__ -#define __CDPLAYERCONSTANTS_H__ - -// Pointers to BWindows -extern CDPlayerWindow* ptrCDPlayerWindow; - -// Product Name and Properties -const char projtitle[]="CDPlayer"; -const char projversion[]="v0.1"; -const char projauthor[]="Sikosis"; - -#endif diff --git a/src/apps/cdplayer/CDPlayerView.cpp b/src/apps/cdplayer/CDPlayerView.cpp deleted file mode 100644 index 3a63209b7e..0000000000 --- a/src/apps/cdplayer/CDPlayerView.cpp +++ /dev/null @@ -1,35 +0,0 @@ -/* - -CDPlayer View - -Author: Sikosis - -(C)2004 Haiku - http://haiku-os.org/ - -*/ - -// Includes ------------------------------------------------------------------------------------------ // -#include -#include -#include -#include -#include -#include - -#include "CDPlayerWindows.h" -#include "CDPlayerViews.h" -// -------------------------------------------------------------------------------------------------- // - -// CDPlayerView - Constructor -CDPlayerView::CDPlayerView (BRect frame) : BView (frame, "CDPlayerView", B_FOLLOW_ALL_SIDES, B_WILL_DRAW ) -{ - SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); -} -// ------------------------------------------------------------------------------------------------- // - -void CDPlayerView::Draw(BRect /*updateRect*/) -{ - BRect r; - r = Bounds(); -} -// ------------------------------------------------------------------------------------------------- // diff --git a/src/apps/cdplayer/CDPlayerViews.h b/src/apps/cdplayer/CDPlayerViews.h deleted file mode 100644 index 504229d503..0000000000 --- a/src/apps/cdplayer/CDPlayerViews.h +++ /dev/null @@ -1,24 +0,0 @@ -/* - -CDPlayer Views Header - -Author: Sikosis - -(C)2004 Haiku - http://haiku-os.org/ - -*/ - -#ifndef __CDPlayerVIEWS_H__ -#define __CDPlayerVIEWS_H__ - -#include "CDPlayer.h" -#include "CDPlayerWindows.h" - -class CDPlayerView : public BView -{ - public: - CDPlayerView(BRect frame); - virtual void Draw(BRect updateRect); -}; - -#endif diff --git a/src/apps/cdplayer/CDPlayerWindow.cpp b/src/apps/cdplayer/CDPlayerWindow.cpp deleted file mode 100644 index f11f42533a..0000000000 --- a/src/apps/cdplayer/CDPlayerWindow.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/* - -CDPlayerWindow - -Author: Sikosis - -(C)2004 Haiku - http://haiku-os.org/ - -*/ - -// Includes ------------------------------------------------------------------------------------------ // -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "CDPlayer.h" -#include "CDPlayerWindows.h" -#include "CDPlayerViews.h" -// -------------------------------------------------------------------------------------------------- // - -// CenterWindowOnScreen -- Centers the BWindow to the Current Screen -static void CenterWindowOnScreen(BWindow* w) -{ - BRect screenFrame = (BScreen(B_MAIN_SCREEN_ID).Frame()); BPoint pt; - pt.x = screenFrame.Width()/2 - w->Bounds().Width()/2; - pt.y = screenFrame.Height()/2 - w->Bounds().Height()/2; - - if (screenFrame.Contains(pt)) - w->MoveTo(pt); -} -// -------------------------------------------------------------------------------------------------- // - -// CDPlayerWindow - Constructor -CDPlayerWindow::CDPlayerWindow(BRect frame) : BWindow (frame, "CD Player", B_TITLED_WINDOW, B_NORMAL_WINDOW_FEEL , 0) -{ - InitWindow(); - CenterWindowOnScreen(this); - - // Load User Settings - BPath path; - find_directory(B_USER_SETTINGS_DIRECTORY,&path); - path.Append("CDPlayer_Settings",true); - BFile file(path.Path(),B_READ_ONLY); - BMessage msg; - msg.Unflatten(&file); - LoadSettings (&msg); - - Show(); -} -// -------------------------------------------------------------------------------------------------- // - - -// CDPlayerWindow - Destructor -CDPlayerWindow::~CDPlayerWindow() -{ - //exit(0); - this is bad i seem to remember someone telling me ... -} -// -------------------------------------------------------------------------------------------------- // - - -// CDPlayerWindow::InitWindow -- Initialization Commands here -void CDPlayerWindow::InitWindow(void) -{ - BRect r; - r = Bounds(); // the whole view - - // Create the Views - AddChild(ptrCDPlayerView = new CDPlayerView(r)); -} -// -------------------------------------------------------------------------------------------------- // - - -// CDPlayerWindow::QuitRequested -- Post a message to the app to quit -bool CDPlayerWindow::QuitRequested() -{ - SaveSettings(); - be_app->PostMessage(B_QUIT_REQUESTED); - return true; -} -// -------------------------------------------------------------------------------------------------- // - - -// CDPlayerWindow::LoadSettings -- Loads your current settings -void CDPlayerWindow::LoadSettings(BMessage *msg) -{ - BRect frame; - - if (B_OK == msg->FindRect("windowframe",&frame)) { - MoveTo(frame.left,frame.top); - ResizeTo(frame.right-frame.left,frame.bottom-frame.top); - } -} -// -------------------------------------------------------------------------------------------------- // - - -// CDPlayerWindow::SaveSettings -- Saves the Users settings -void CDPlayerWindow::SaveSettings(void) -{ - BMessage msg; - msg.AddRect("windowframe",Frame()); - - BPath path; - status_t result = find_directory(B_USER_SETTINGS_DIRECTORY,&path); - if (result == B_OK) { - path.Append("CDPlayer_Settings",true); - BFile file(path.Path(),B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE); - msg.Flatten(&file); - } -} -// -------------------------------------------------------------------------------------------------- // - - -// CDPlayerWindow::MessageReceived -- receives messages -void CDPlayerWindow::MessageReceived (BMessage *message) -{ - switch(message->what) - { - default: - BWindow::MessageReceived(message); - break; - } -} -// -------------------------------------------------------------------------------------------------- // - diff --git a/src/apps/cdplayer/CDPlayerWindows.h b/src/apps/cdplayer/CDPlayerWindows.h deleted file mode 100644 index 20d8456fad..0000000000 --- a/src/apps/cdplayer/CDPlayerWindows.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - -CDPlayer Windows Header - -Author: Sikosis - -(C)2004 Haiku - http://haiku-os.org/ - -*/ - -#ifndef __CDPLAYERWINDOWS_H__ -#define __CDPLAYERWINDOWS_H__ - -#include "CDPlayer.h" -#include "CDPlayerViews.h" - -class CDPlayerView; - -class CDPlayerWindow : public BWindow -{ - public: - CDPlayerWindow(BRect frame); - ~CDPlayerWindow(); - virtual bool QuitRequested(); - virtual void MessageReceived(BMessage *message); - private: - void InitWindow(void); - - void LoadSettings(BMessage *msg); - void SaveSettings(void); - CDPlayerView* ptrCDPlayerView; -}; - -#endif diff --git a/src/apps/cdplayer/DrawButton.cpp b/src/apps/cdplayer/DrawButton.cpp new file mode 100644 index 0000000000..db51f8692f --- /dev/null +++ b/src/apps/cdplayer/DrawButton.cpp @@ -0,0 +1,69 @@ +#include "DrawButton.h" + +DrawButton::DrawButton(BRect frame, const char *name, BBitmap *up, BBitmap *down, + BMessage *msg, int32 resize, int32 flags) + : BButton(frame, name, "", msg, resize, flags) +{ + fUp=up; + fDown=down; + fDisabled=NULL; +} + +DrawButton::~DrawButton(void) +{ +} + +void DrawButton::SetBitmaps(BBitmap *up, BBitmap *down) +{ + delete fUp; + delete fDown; + + fUp=up; + fDown=down; +} + +void DrawButton::SetDisabled(BBitmap *disabled) +{ + delete fDisabled; + + fDisabled=disabled; +} + +void DrawButton::Draw(BRect update) +{ + if(!IsEnabled()) + { + if(fDisabled) + DrawBitmap(fDisabled, BPoint(0,0)); + else + StrokeRect(Bounds()); + return; + } + + if(Value() == B_CONTROL_ON) + { + if(fDown) + DrawBitmap(fDown, BPoint(0,0)); + else + StrokeRect(Bounds()); + } + else + { + if(fUp) + DrawBitmap(fUp, BPoint(0,0)); + else + StrokeRect(Bounds()); + } +} + +void DrawButton::ResizeToPreferred(void) +{ + if(fUp) + ResizeTo(fUp->Bounds().Width(),fUp->Bounds().Height()); + else + if(fDown) + ResizeTo(fDown->Bounds().Width(),fDown->Bounds().Height()); + else + if(fDisabled) + ResizeTo(fDisabled->Bounds().Width(),fDisabled->Bounds().Height()); +} diff --git a/src/apps/cdplayer/DrawButton.h b/src/apps/cdplayer/DrawButton.h new file mode 100644 index 0000000000..af907b91af --- /dev/null +++ b/src/apps/cdplayer/DrawButton.h @@ -0,0 +1,31 @@ +#ifndef _DRAW_BUTTON_H +#define _DRAW_BUTTON_H + +#include +#include +#include +#include +#include +#include + + +class DrawButton : public BButton +{ +public: + DrawButton(BRect frame, const char *name, BBitmap *up, BBitmap *down, + BMessage *msg, int32 resize, int32 flags); + ~DrawButton(void); + + void Draw(BRect update); + + void SetBitmaps(BBitmap *up, BBitmap *down); + void ResizeToPreferred(void); + void SetDisabled(BBitmap *disabled); + +private: + + BBitmap *fUp, *fDown, *fDisabled; + +}; + +#endif \ No newline at end of file diff --git a/src/apps/cdplayer/FunctionObjectMessage.cpp b/src/apps/cdplayer/FunctionObjectMessage.cpp new file mode 100644 index 0000000000..446b879f0e --- /dev/null +++ b/src/apps/cdplayer/FunctionObjectMessage.cpp @@ -0,0 +1,50 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +// This defines code for sending funciton objects in messages + +#ifndef _BE_H +#include +#endif + +#include "FunctionObjectMessage.h" + + +BMessage * +FunctorFactoryCommon::NewMessage(const FunctionObject *functor) +{ + BMessage *result = new BMessage('fCmG'); + ASSERT(result); + + long error = result->AddData("functor", B_RAW_TYPE, + functor, functor->Size()); + + if (error != B_NO_ERROR) { + delete result; + result = NULL; + } + + return result; +} + +bool +FunctorFactoryCommon::DispatchIfFunctionObject(BMessage *message) +{ + if (message->what != 'fCmG') + return false; + + // find the functor + long size; + FunctionObject *functor; + status_t error = message->FindData("functor", B_RAW_TYPE, (const void**)&functor, &size); + if (error != B_NO_ERROR) + return false; + + ASSERT(functor); + // functor found, call it + (*functor)(); + return true; +} + diff --git a/src/apps/cdplayer/FunctionObjectMessage.h b/src/apps/cdplayer/FunctionObjectMessage.h new file mode 100644 index 0000000000..0674435177 --- /dev/null +++ b/src/apps/cdplayer/FunctionObjectMessage.h @@ -0,0 +1,73 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +// This defines some function object glue code + +// See the Be Newsletter article about using Function Objects in the Be messaging +// model for more information + +#ifndef __FUNCTION_OBJECT_MESSAGE__ +#define __FUNCTION_OBJECT_MESSAGE__ + +#ifndef _BE_H +#include +#include +#endif + +class FunctionObject { +public: + virtual void operator()() = 0; + virtual ~FunctionObject() {} + virtual ulong Size() const = 0; +}; + +template +class PlainMemberFunctionObject : public FunctionObject { +public: + PlainMemberFunctionObject(FT callThis, T *onThis) + : function(callThis), + target(onThis) + { + } + virtual ~PlainMemberFunctionObject() {} + + virtual void operator()() + { (target->*function)(); } + + virtual ulong Size() const { return sizeof(*this); } +private: + FT function; + T *target; +}; + +template +class SingleParamMemberFunctionObject : public FunctionObject { +public: + SingleParamMemberFunctionObject(FT callThis, T *onThis, P withThis) + : function(callThis), + target(onThis), + parameter(withThis) + { + } + virtual ~SingleParamMemberFunctionObject() {} + + virtual void operator()() + { (target->*function)(parameter); } + + virtual ulong Size() const { return sizeof(*this); } +private: + FT function; + T *target; + P parameter; +}; + +class FunctorFactoryCommon { +public: + static bool DispatchIfFunctionObject(BMessage *); +protected: + static BMessage *NewMessage(const FunctionObject *); +}; + +#endif \ No newline at end of file diff --git a/src/apps/cdplayer/Jamfile b/src/apps/cdplayer/Jamfile index 792e1b8c3d..aa21aa5959 100644 --- a/src/apps/cdplayer/Jamfile +++ b/src/apps/cdplayer/Jamfile @@ -1,5 +1,13 @@ SubDir OBOS_TOP src apps cdplayer ; AddResources CDPlayer : CDPlayer.rdef ; -App CDPlayer : CDPlayer.cpp CDPlayerWindow.cpp CDPlayerView.cpp ; -LinkSharedOSLibs CDPlayer : be ; +App CDPlayer : + CDButton.cpp + CDDBSupport.cpp + CDEngine.cpp + DrawButton.cpp + FunctionObjectMessage.cpp + Observer.cpp + TypedList.cpp + ; +LinkSharedOSLibs CDPlayer : be net netapi translation ; diff --git a/src/apps/cdplayer/LICENSE b/src/apps/cdplayer/LICENSE new file mode 100644 index 0000000000..86a4268fa9 --- /dev/null +++ b/src/apps/cdplayer/LICENSE @@ -0,0 +1,31 @@ +---------------------- +Be Sample Code License +---------------------- + +Copyright 1991-1999, Be Incorporated. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions, and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/apps/cdplayer/Observer.cpp b/src/apps/cdplayer/Observer.cpp new file mode 100644 index 0000000000..631012b895 --- /dev/null +++ b/src/apps/cdplayer/Observer.cpp @@ -0,0 +1,180 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +// This defines the Observer and Notifier classes + +#include +#include +#include +#include "Observer.h" + +Observer::Observer(Notifier *target) + : observedList(4, true) +{ + if (target) + StartObserving(target); +} + +Observer::~Observer() +{ + StopObserving(); + // tell everyone to stop sending us notices +} + +void +Observer::StartObserving(Notifier *target) +{ + ASSERT(target->RecipientHandler()); + ASSERT(RecipientHandler()->Looper()); + + // send a message to the notifier to start sending us notices + if (target->RecipientHandler()->Looper()) { + BMessage *message = new BMessage(kStartObserving); + message->AddPointer("observer", this); + message->AddPointer("observed", target); + + // send the message to the looper associated with the + // notifier + target->RecipientHandler()->Looper()->PostMessage(message, + target->RecipientHandler()); + NotifierListEntry *entry = new NotifierListEntry; + + entry->observed = target; + entry->handler = target->RecipientHandler(); + entry->looper = target->RecipientHandler()->Looper(); + + observedList.AddItem(entry); + } +} + +void +Observer::SendStopObserving(NotifierListEntry *target) +{ + // send a message to the notifier to start sending us notices + if (target->looper) { + BMessage *message = new BMessage(kEndObserving); + message->AddPointer("observer", this); + message->AddPointer("observed", target->observed); + target->looper->PostMessage(message, target->handler); + } +} + +NotifierListEntry * +StopObservingOne(NotifierListEntry *observed, void *castToObserver) +{ + ((Observer *)castToObserver)->SendStopObserving(observed); + return 0; +} + +void +Observer::StopObserving() +{ + // send a message to all the notifiers to start sending us notices + observedList.EachElement(StopObservingOne, this); + observedList.MakeEmpty(); +} + +bool +Observer::HandleObservingMessages(const BMessage *message) +{ + switch (message->what) { + case kNoticeChange: + { + // look for notice messages from notifiers + Notifier *observed = NULL; + Observer *observer = NULL; + message->FindPointer("observed", (void**)&observed); + message->FindPointer("observer", (void**)&observer); + ASSERT(observed); + ASSERT(observer); + if (!observed || !observer) + return false; + + ASSERT(dynamic_cast(observer)); + + // this is a notice for us, call the NoticeChange function + observer->NoticeChange(observed); + return true; + } + default: + return false; + } +} + +static ObserverListEntry * +NotifyOne(ObserverListEntry *observer, void *castToObserved) +{ + if (observer->looper) { + BMessage *message = new BMessage(kNoticeChange); + message->AddPointer("observed", castToObserved); + message->AddPointer("observer", observer->observer); + observer->looper->PostMessage(message, observer->handler); + } + return 0; +} + +void +Notifier::Notify() +{ + // send notices to all the observers + observerList.EachElement(NotifyOne, this); +} + +static ObserverListEntry * +FindItemWithObserver(ObserverListEntry *item, void *castToObserver) +{ + if (item->observer == castToObserver) + return item; + return 0; +} + +void +Notifier::AddObserver(Observer *observer) +{ + ObserverListEntry *item = new ObserverListEntry; + item->observer = observer; + item->handler = observer->RecipientHandler(); + item->looper = observer->RecipientHandler()->Looper(); + ASSERT(item->looper); + observerList.AddUnique(item); +} + +void +Notifier::RemoveObserver(Observer *observer) +{ + ObserverListEntry *item = observerList.EachElement( + FindItemWithObserver, observer); + + observerList.RemoveItem(item); + delete item; +} + +bool +Notifier::HandleObservingMessages(const BMessage *message) +{ + switch (message->what) { + case kStartObserving: + case kEndObserving: + { + // handle messages about stopping and starting observing + Observer *observer = 0; + Notifier *observed = 0; + message->FindPointer("observer", (void**)&observer); + message->FindPointer("observed", (void**)&observed); + ASSERT(observer); + ASSERT(observed); + if (!observer || !observed) + return false; + + if (message->what == kStartObserving) + observed->AddObserver(observer); + else + observed->RemoveObserver(observer); + return true; + } + default: + return false; + } +} diff --git a/src/apps/cdplayer/Observer.h b/src/apps/cdplayer/Observer.h new file mode 100644 index 0000000000..d17c0c6a62 --- /dev/null +++ b/src/apps/cdplayer/Observer.h @@ -0,0 +1,98 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +// This defines the Observer and Notifier classes + +// The idea of observing is make it easier to support a client-server +// setup where a client want's to react to changes in the server state, +// for instance a view displaying a track number needs to change whenever +// a track changes. Normally this is done by the client periodically checking +// the server from within a Pulse call or a simillar mechanism. With Observer +// and Notifier, the Observer (client) starts observing a Notifier (server) +// and then just sits back and wait to get a notice, whenever the Notifier +// changes. + +#ifndef __OBSERVER__ +#define __OBSERVER__ + +#include "TypedList.h" +#include + +const uint32 kNoticeChange = 'notc'; +const uint32 kStartObserving = 'stob'; +const uint32 kEndObserving = 'edob'; + +class Notifier; + +class NotifierListEntry { +public: + Notifier *observed; + BHandler *handler; + BLooper *looper; +}; + +class Observer { +public: + Observer(Notifier *target = NULL); + virtual ~Observer(); + + void StartObserving(Notifier *); + // start observing a speficied notifier + void StopObserving(Notifier *); + // stop observing a speficied notifier + void StopObserving(); + // stop observing all the observed notifiers + + virtual void NoticeChange(Notifier *) = 0; + // override this to get your job done, your class will get called + // whenever the Notifier changes + + static bool HandleObservingMessages(const BMessage *message); + // call this from subclasses MessageReceived + virtual BHandler *RecipientHandler() const = 0; + // hook this up to return subclasses looper +private: + void SendStopObserving(NotifierListEntry *); + + // keep a list of all the observed notifiers + TypedList observedList; + +friend NotifierListEntry *StopObservingOne(NotifierListEntry *, void *); +}; + +class ObserverListEntry { +public: + Observer *observer; + BHandler *handler; + BLooper *looper; +}; + +class Notifier { +public: + Notifier() + {} + virtual ~Notifier() + {} + + virtual void Notify(); + // call this when the notifier object changes to send notices + // to all the observers + + static bool HandleObservingMessages(const BMessage *message); + // call this from subclasses MessageReceived + virtual BHandler *RecipientHandler() const = 0; + // hook this up to return subclasses looper + + // keep a list of all the observers so that we can send them notices + void AddObserver(Observer *); + void RemoveObserver(Observer *); + +private: + TypedList observerList; + +friend class Observer; +}; + +#endif \ No newline at end of file diff --git a/src/apps/cdplayer/TypedList.cpp b/src/apps/cdplayer/TypedList.cpp new file mode 100644 index 0000000000..56ce164be0 --- /dev/null +++ b/src/apps/cdplayer/TypedList.cpp @@ -0,0 +1,87 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +// TypedList is a type-safe template version of BList + +#include +#include "TypedList.h" + +void * +_PointerList::EachElement(GenericEachFunction func, void *passThru) +{ + // iterates through all elements, calling func on each + // if each function returns a nonzero value, terminates early + void *result = NULL; + int32 numElements = CountItems(); + + for (int32 index = 0; index < numElements; index++) + if ((result = func(ItemAtFast(index), passThru)) != NULL) + break; + + return result; +} + +_PointerList::_PointerList(const _PointerList &list) + : BList(list), + owning(list.owning) +{ +} + +_PointerList::_PointerList(int32 itemsPerBlock = 20, bool owningList) + : BList(itemsPerBlock), + owning(owningList) +{ +} + +_PointerList::~_PointerList() +{ +} + +bool +_PointerList::Owning() const +{ + return owning; +} + +bool +_PointerList::AddUnique(void *newItem) +{ + if (IndexOf(newItem) >= 0) + return false; + + return AddItem(newItem); +} + +struct OneMatchParams { + void *matchThis; + _PointerList::GenericCompareFunction matchFunction; +}; + + +static void * +MatchOne(void *item, void *castToParams) +{ + OneMatchParams *params = (OneMatchParams *)castToParams; + if (params->matchFunction(item, params->matchThis) == 0) + // got a match, terminate search + return item; + + return 0; +} + +bool +_PointerList::AddUnique(void *newItem, GenericCompareFunction function) +{ + OneMatchParams params; + params.matchThis = newItem; + params.matchFunction = function; + + if (EachElement(MatchOne, ¶ms)) + // already in list + return false; + + return AddItem(newItem); +} + diff --git a/src/apps/cdplayer/TypedList.h b/src/apps/cdplayer/TypedList.h new file mode 100644 index 0000000000..de10d87506 --- /dev/null +++ b/src/apps/cdplayer/TypedList.h @@ -0,0 +1,326 @@ +/* + Copyright 1999, Be Incorporated. All Rights Reserved. + This file may be used under the terms of the Be Sample Code License. +*/ + +// TypedList is a garden-variety of a type-safe template version of BList + +#ifndef __LIST_TEMPLATE__ +#define __LIST_TEMPLATE__ + +#ifndef _BE_H +#include +#endif + +#include + +class _PointerList : public BList { +public: + _PointerList(const _PointerList &list); + _PointerList(int32 itemsPerBlock = 20, bool owning = false); + virtual ~_PointerList(); + + typedef void *(* GenericEachFunction)(void *, void *); + typedef int (* GenericCompareFunction)(const void *, const void *); + void *EachElement(GenericEachFunction, void *); + + bool AddUnique(void *); + // return true if item added or already in the list + bool AddUnique(void *, GenericCompareFunction); + + bool Owning() const; +private: + const bool owning; +}; + +// TypedList - +// to be used as a list of pointers to objects; this class should contain +// pretty much no code, just stubs that do proper type conversion +// it uses BetterEachBList for all of it's functionality and provides a +// typed interface +template +class TypedList : public _PointerList { +public: + TypedList(int32 itemsPerBlock = 20, bool owning = false); + TypedList(const TypedList&); + virtual ~TypedList(); + + TypedList &operator=(const TypedList &); + + // iteration and sorting + typedef T (* EachFunction)(T, void *); + typedef const T (* ConstEachFunction)(const T, void *); + typedef int (* CompareFunction)(const T *, const T *); + + // adding and removing + bool AddItem(T); + bool AddItem(T, int32); + bool AddList(TypedList *); + bool AddList(TypedList *, int32); + bool AddUnique(T); + bool AddUnique(T, CompareFunction); + + bool RemoveItem(T); + T RemoveItem(int32); + T RemoveItemAt(int32); + // same as RemoveItem(int32), RemoveItem does not work when T is a scalar + + void MakeEmpty(); + + // item access + T ItemAt(int32) const; + T ItemAtFast(int32) const; + // does not do an index range check + + T FirstItem() const; + T LastItem() const; + + T Items() const; + + // misc. getters + int32 IndexOf(const T) const; + bool HasItem(const T) const; + bool IsEmpty() const; + int32 CountItems() const; + + + T EachElement(EachFunction, void *); + const T EachElement(ConstEachFunction, void *) const; + // Do for each are obsoleted by this list, possibly add + // them for convenience + void SortItems(CompareFunction); + bool ReplaceItem(int32 index, T item); + bool SwapItems(int32 a, int32 b); + bool MoveItem(int32 from, int32 to); + +private: + friend class ParseArray; +}; + +template +TypedList::TypedList(int32 itemsPerBlock, bool owning) + : _PointerList(itemsPerBlock, owning) +{ +} + +template +TypedList::TypedList(const TypedList &list) + : _PointerList(list) +{ + ASSERT(!list.Owning()); + // copying owned lists does not work yet +} + +template +TypedList::~TypedList() +{ + if (Owning()) + // have to nuke elements first + MakeEmpty(); +} + +template +TypedList & +TypedList::operator=(const TypedList &from) +{ + ASSERT(!from.Owning()); + // copying owned lists does not work yet + + return (TypedList &)BList::operator=(from); +} + +template +bool +TypedList::AddItem(T item) +{ + return _PointerList::AddItem(item); +} + +template +bool +TypedList::AddItem(T item, int32 atIndex) +{ + return _PointerList::AddItem(item, atIndex); +} + +template +bool +TypedList::AddList(TypedList *newItems) +{ + return _PointerList::AddList(newItems); +} + +template +bool +TypedList::AddList(TypedList *newItems, int32 atIndex) +{ + return _PointerList::AddList(newItems, atIndex); +} + +template +bool +TypedList::AddUnique(T item) +{ + return _PointerList::AddUnique(item); +} + +template +bool +TypedList::AddUnique(T item, CompareFunction function) +{ + return _PointerList::AddUnique(item, (GenericCompareFunction)function); +} + + +template +bool +TypedList::RemoveItem(T item) +{ + bool result = _PointerList::RemoveItem(item); + + if (result && Owning()) { + delete item; + } + + return result; +} + +template +T +TypedList::RemoveItem(int32 index) +{ + return (T)_PointerList::RemoveItem(index); +} + +template +T +TypedList::RemoveItemAt(int32 index) +{ + return (T)_PointerList::RemoveItem(index); +} + +template +T +TypedList::ItemAt(int32 index) const +{ + return (T)_PointerList::ItemAt(index); +} + +template +T +TypedList::ItemAtFast(int32 index) const +{ + return (T)_PointerList::ItemAtFast(index); +} + +template +int32 +TypedList::IndexOf(const T item) const +{ + return _PointerList::IndexOf(item); +} + +template +T +TypedList::FirstItem() const +{ + return (T)_PointerList::FirstItem(); +} + +template +T +TypedList::LastItem() const +{ + return (T)_PointerList::LastItem(); +} + +template +bool +TypedList::HasItem(const T item) const +{ + return _PointerList::HasItem(item); +} + +template +bool +TypedList::IsEmpty() const +{ + return _PointerList::IsEmpty(); +} + +template +int32 +TypedList::CountItems() const +{ + return _PointerList::CountItems(); +} + +template +void +TypedList::MakeEmpty() +{ + if (Owning()) { + int32 numElements = CountItems(); + + for (int32 count = 0; count < numElements; count++) + // this is probably not the most efficient, but + // is relatively indepenent of BList implementation + // details + RemoveItem(LastItem()); + } + _PointerList::MakeEmpty(); +} + +template +T +TypedList::EachElement(EachFunction func, void *params) +{ + return (T)_PointerList::EachElement((GenericEachFunction)func, params); +} + + +template +const T +TypedList::EachElement(ConstEachFunction func, void *params) const +{ + return (const T) + const_cast *>(this)->_PointerList::EachElement( + (GenericEachFunction)func, params); +} + + +template +T +TypedList::Items() const +{ + return (T)_PointerList::Items(); +} + +template +void +TypedList::SortItems(CompareFunction function) +{ + ASSERT(sizeof(T) == sizeof(void *)); + _PointerList::SortItems((GenericCompareFunction)function); +} + +template +bool TypedList::ReplaceItem(int32 index, T item) +{ + return _PointerList::ReplaceItem(index, (void *)item); +} + +template +bool TypedList::SwapItems(int32 a, int32 b) +{ + return _PointerList::SwapItems(a, b); +} + +template +bool TypedList::MoveItem(int32 from, int32 to) +{ + return _PointerList::MoveItem(from, to); +} + + +#endif