Replace hardcoded window index w window-targeting

For a replicant, the target-window can now be selected by
either novelty, file-type, or an explicit index.
This commit is contained in:
Jaidyn Ann 2022-06-24 22:16:15 -05:00
parent 44eda8ab54
commit f67161ff12
4 changed files with 178 additions and 23 deletions

View File

@ -11,9 +11,15 @@
#include "Song.h" #include "Song.h"
MediaPlayer::MediaPlayer(int32 window) // This seems a fair amount of Pulse()-es to wait before spam-checking windows.
const int32 kTargetHops = 20;
MediaPlayer::MediaPlayer(int32 window, target followType)
{ {
fWindowIndex = window; fWindowIndex = window;
fWindowTarget = followType;
fWindowTargetHops = 0;
} }
@ -21,7 +27,9 @@ MediaPlayer::MediaPlayer(BMessage* data)
: :
BArchivable(data) BArchivable(data)
{ {
fWindowIndex = data->GetInt32("_window", 0); fWindowIndex = data->GetInt32("_window", -1);
fWindowTarget = (target)data->GetInt32("_windowtype", MP_BY_TYPE_AUDIO);
fWindowTargetHops = 0;
} }
@ -30,6 +38,7 @@ MediaPlayer::Archive(BMessage* data, bool deep) const
{ {
status_t status = BArchivable::Archive(data, deep); status_t status = BArchivable::Archive(data, deep);
data->AddInt32("_window", fWindowIndex); data->AddInt32("_window", fWindowIndex);
data->AddInt32("_windowtype", fWindowTarget);
data->AddString("class", "MediaPlayer"); data->AddString("class", "MediaPlayer");
data->AddString("add_on", APP_SIGNATURE); data->AddString("add_on", APP_SIGNATURE);
return status; return status;
@ -45,6 +54,16 @@ MediaPlayer::Instantiate(BMessage* data)
} }
bool
MediaPlayer::IsValid()
{
BString type;
BMessage send, reply;
_ScriptingCall("Suites", &send, &reply, MP_NO_TRACK, true);
return reply.FindString("suites", &type) == B_OK && type == "suite/vnd.Haiku-MediaPlayer";
}
bool bool
MediaPlayer::IsPlaying() MediaPlayer::IsPlaying()
{ {
@ -113,6 +132,33 @@ MediaPlayer::PlaylistItem(Song* song, int32 index, bool duration)
} }
int32
MediaPlayer::Window()
{
if (fWindowTarget == MP_BY_INDEX || fWindowTargetHops-- > 0)
return fWindowIndex;
fWindowTargetHops = kTargetHops;
for (int32 i = CountWindows() - 1; i >= 0; i--) {
MediaPlayer mp(i, MP_BY_INDEX);
if (mp.IsValid()) {
if (fWindowTarget == MP_BY_LATEST)
return i;
Song current;
BString type;
if (CurrentItem(&current, false)
&& BNode(current.Path().Path()).ReadAttrString("BEOS:TYPE", &type) == B_OK)
if ((type.StartsWith("audio") && fWindowTarget == MP_BY_TYPE_AUDIO)
|| (type.StartsWith("video") && fWindowTarget == MP_BY_TYPE_VIDEO))
return i;
}
}
return fWindowIndex;
}
int32 int32
MediaPlayer::SetWindow(int32 index) MediaPlayer::SetWindow(int32 index)
{ {
@ -127,7 +173,7 @@ int32
MediaPlayer::CountWindows() MediaPlayer::CountWindows()
{ {
BMessage send(B_COUNT_PROPERTIES), reply; BMessage send(B_COUNT_PROPERTIES), reply;
_ScriptingCall("Window", &send, &reply, MP_NO_TRACK); _ScriptingCall("Window", &send, &reply, MP_NO_TRACK, false);
int32 count; int32 count;
if (reply.FindInt32("result", &count) == B_OK) if (reply.FindInt32("result", &count) == B_OK)
@ -136,8 +182,23 @@ MediaPlayer::CountWindows()
} }
target
MediaPlayer::Target()
{
return fWindowTarget;
}
target
MediaPlayer::SetTarget(target target)
{
fWindowTargetHops = 0;
return fWindowTarget = target;
}
bool bool
MediaPlayer::_GetSong(Song* song, int32 trackIndex, bool durationRequired) MediaPlayer::_GetSong(Song* song, int32 trackIndex, bool durationReq)
{ {
BMessage send, reply; BMessage send, reply;
_ScriptingCall("URI", &send, &reply, trackIndex); _ScriptingCall("URI", &send, &reply, trackIndex);
@ -146,19 +207,25 @@ MediaPlayer::_GetSong(Song* song, int32 trackIndex, bool durationRequired)
return false; return false;
int64 duration = -1; int64 duration = -1;
if (durationRequired) { if (durationReq) {
_ScriptingCall("Duration", &send, &reply, trackIndex); _ScriptingCall("Duration", &send, &reply, trackIndex);
if (reply.FindInt64("result", &duration) != B_OK) if (reply.FindInt64("result", &duration) != B_OK)
return false; return false;
} }
if (trackIndex == MP_CURRENT_TRACK && fWindowTarget != MP_BY_INDEX
&& uriString != fLastItemPath) {
fLastItemPath.SetTo(uriString);
fWindowTargetHops = 0;
}
*song = Song(_UriToPath(uriString), duration); *song = Song(_UriToPath(uriString), duration);
return true; return true;
} }
void void
MediaPlayer::_ScriptingCall(const char* attribute, BMessage* send, BMessage* reply, int32 trackIndex) MediaPlayer::_ScriptingCall(const char* attribute, BMessage* send, BMessage* reply, int32 trackIndex,
bool window)
{ {
if (send->what == 0) if (send->what == 0)
send->what = B_GET_PROPERTY; send->what = B_GET_PROPERTY;
@ -169,9 +236,14 @@ MediaPlayer::_ScriptingCall(const char* attribute, BMessage* send, BMessage* rep
else if (trackIndex == MP_CURRENT_TRACK) else if (trackIndex == MP_CURRENT_TRACK)
send->AddSpecifier("CurrentTrack"); send->AddSpecifier("CurrentTrack");
send->AddSpecifier("Window", fWindowIndex); if (window)
send->AddSpecifier("Window", Window());
BMessenger("application/x-vnd.Haiku-MediaPlayer").SendMessage(send, reply); if (BMessenger("application/x-vnd.Haiku-MediaPlayer").SendMessage(send, reply) != B_OK)
return;
if (reply != NULL && reply->what == B_MESSAGE_NOT_UNDERSTOOD)
fWindowTargetHops = 0;
} }

View File

@ -19,17 +19,26 @@ enum {
}; };
enum target {
MP_BY_INDEX,
MP_BY_TYPE_AUDIO,
MP_BY_TYPE_VIDEO,
MP_BY_LATEST
};
class MediaPlayer : public BArchivable { class MediaPlayer : public BArchivable {
public: public:
MediaPlayer(int32 window = 0); MediaPlayer(int32 window = 0, target followType = MP_BY_TYPE_AUDIO);
MediaPlayer(BMessage* archive); MediaPlayer(BMessage* archive);
virtual status_t Archive(BMessage* data, bool deep = true) const; virtual status_t Archive(BMessage* data, bool deep = true) const;
static MediaPlayer* Instantiate(BMessage* data); static MediaPlayer* Instantiate(BMessage* data);
bool IsValid();
bool IsPlaying(); bool IsPlaying();
int64 Duration(); int64 Duration();
int64 Position(); int64 Position();
void SetPosition(int64 position); void SetPosition(int64 position);
float Volume(); float Volume();
@ -38,16 +47,25 @@ public:
bool CurrentItem(Song* song, bool duration = true); bool CurrentItem(Song* song, bool duration = true);
bool PlaylistItem(Song* song, int32 index, bool duration = true); bool PlaylistItem(Song* song, int32 index, bool duration = true);
int32 Window();
int32 SetWindow(int32 index); int32 SetWindow(int32 index);
int32 CountWindows(); int32 CountWindows();
target Target();
target SetTarget(target target);
private: private:
bool _GetSong(Song* song, int32 trackIndex, bool durationRequired = true); bool _GetSong(Song* song, int32 trackIndex, bool duration = true);
void _ScriptingCall(const char* attribute, BMessage* send, BMessage* reply, void _ScriptingCall(const char* attribute, BMessage* send, BMessage* reply,
int32 trackIndex = MP_NO_TRACK); int32 trackIndex = MP_NO_TRACK, bool window = true);
const char* _UriToPath(BString URI); const char* _UriToPath(BString URI);
int32 fWindowIndex; int32 fWindowIndex;
target fWindowTarget;
int32 fWindowTargetHops; // Amount of pulses to wait before re-checking windows
BString fLastItemPath;
}; };
#endif // MEDIAPLAYER_H #endif // MEDIAPLAYER_H

View File

@ -36,7 +36,7 @@ ReplicantView::ReplicantView(BRect frame, const char* name, uint32 draggerPlacem
fTransparentInactivity = false; fTransparentInactivity = false;
fTransparentDragger = false; fTransparentDragger = false;
fMediaPlayer = new MediaPlayer(0); fMediaPlayer = new MediaPlayer();
} }
@ -89,6 +89,25 @@ ReplicantView::MessageReceived(BMessage* msg)
{ {
switch (msg->what) switch (msg->what)
{ {
case REPL_WIN_BY_AUDIO:
fMediaPlayer->SetTarget(MP_BY_TYPE_AUDIO);
break;
case REPL_WIN_BY_VIDEO:
fMediaPlayer->SetTarget(MP_BY_TYPE_VIDEO);
break;
case REPL_WIN_BY_LATEST:
fMediaPlayer->SetTarget(MP_BY_LATEST);
break;
case REPL_WIN_BY_INDEX:
{
int32 index = 0;
if (msg->FindInt32("index", &index) == B_OK) {
fMediaPlayer->SetTarget(MP_BY_INDEX);
fMediaPlayer->SetWindow(index);
}
break;
}
case REPL_TRANSPARENTLY_INACTIVE: case REPL_TRANSPARENTLY_INACTIVE:
case REPL_TRANSPARENTLY_DRAG: { case REPL_TRANSPARENTLY_DRAG: {
if (msg->what == REPL_TRANSPARENTLY_INACTIVE) if (msg->what == REPL_TRANSPARENTLY_INACTIVE)
@ -136,7 +155,6 @@ ReplicantView::RightClickPopUp(BPopUpMenu* menu)
BMenu* hideMenu = new BMenu("Hide when inactive"); BMenu* hideMenu = new BMenu("Hide when inactive");
menu->AddItem(hideMenu); menu->AddItem(hideMenu);
BMenuItem* hideInactive = hideMenu->Superitem(); BMenuItem* hideInactive = hideMenu->Superitem();
hideInactive->SetMessage(new BMessage(REPL_TRANSPARENTLY_INACTIVE)); hideInactive->SetMessage(new BMessage(REPL_TRANSPARENTLY_INACTIVE));
hideInactive->SetMarked(fTransparentInactivity); hideInactive->SetMarked(fTransparentInactivity);
@ -148,12 +166,29 @@ ReplicantView::RightClickPopUp(BPopUpMenu* menu)
hideDragger->SetTarget(this); hideDragger->SetTarget(this);
hideMenu->AddItem(hideDragger); hideMenu->AddItem(hideDragger);
BMenu* windowMenu = new BMenu("Target window…");
menu->AddItem(windowMenu);
BMenu* indexMenu = _WindowIndexMenu();
indexMenu->SetTargetForItems(this);
windowMenu->AddItem(indexMenu);
BMenu* typeMenu = new BMenu("By type…");
windowMenu->AddItem(typeMenu);
BMenuItem* audioItem = new BMenuItem("Audio", new BMessage(REPL_WIN_BY_AUDIO));
BMenuItem* videoItem = new BMenuItem("Video", new BMessage(REPL_WIN_BY_VIDEO));
audioItem->SetMarked(fMediaPlayer->Target() == MP_BY_TYPE_AUDIO);
videoItem->SetMarked(fMediaPlayer->Target() == MP_BY_TYPE_VIDEO);
typeMenu->AddItem(audioItem);
typeMenu->AddItem(videoItem);
typeMenu->SetTargetForItems(this);
menu->AddSeparatorItem(); menu->AddSeparatorItem();
BString aboutLabel = "About %replicant" B_UTF8_ELLIPSIS; BString aboutLabel = "About %replicant" B_UTF8_ELLIPSIS;
aboutLabel.ReplaceAll("%replicant", Name()); aboutLabel.ReplaceAll("%replicant", Name());
BMenuItem* aboutItem = new BMenuItem(aboutLabel, new BMessage(B_ABOUT_REQUESTED)); BMenuItem* aboutItem = new BMenuItem(aboutLabel, new BMessage(B_ABOUT_REQUESTED));
aboutItem->SetTarget(this);
menu->AddItem(aboutItem); menu->AddItem(aboutItem);
if (fReplicated) { if (fReplicated) {
@ -182,3 +217,31 @@ ReplicantView::SetInactive(bool inactive)
Invalidate(); Invalidate();
} }
BMenu*
ReplicantView::_WindowIndexMenu()
{
BMenu* menu = new BMenu("By index…");
BMenuItem* latestItem = new BMenuItem("Latest", new BMessage(REPL_WIN_BY_LATEST));
latestItem->SetMarked(fMediaPlayer->Target() == MP_BY_LATEST);
menu->AddItem(latestItem);
int32 windowCount = fMediaPlayer->CountWindows();
for (int32 i = 0; i < windowCount; i++)
if (MediaPlayer(i, MP_BY_INDEX).IsValid()) {
BString label("");
label << i;
BMessage* msg = new BMessage(REPL_WIN_BY_INDEX);
msg->AddInt32("index", i);
BMenuItem* indexItem = new BMenuItem(label, msg);
indexItem->SetMarked(fMediaPlayer->Target() == MP_BY_INDEX
&& fMediaPlayer->Window() == i);
menu->AddItem(indexItem);
}
return menu;
}

View File

@ -8,19 +8,18 @@
#include <View.h> #include <View.h>
class BDragger; class BDragger;
class BMenu;
class BPopUpMenu; class BPopUpMenu;
class MediaPlayer; class MediaPlayer;
enum {
MP_AUDIO_WINDOW = 'mpaw',
MP_VIDEO_WINDOW = 'mpvw',
MP_NEWEST_WINDOW = 'mpnw'
};
enum { enum {
REPL_TRANSPARENTLY_INACTIVE = 'rtti', REPL_TRANSPARENTLY_INACTIVE = 'rtti',
REPL_TRANSPARENTLY_DRAG = 'rttd' REPL_TRANSPARENTLY_DRAG = 'rttd',
REPL_WIN_BY_INDEX = 'rwbi',
REPL_WIN_BY_LATEST = 'rwbl',
REPL_WIN_BY_AUDIO = 'rwba',
REPL_WIN_BY_VIDEO = 'rwbv'
}; };
@ -53,6 +52,9 @@ public:
// Set inactivity state, re-render accordingly // Set inactivity state, re-render accordingly
virtual void SetInactive(bool inactive); virtual void SetInactive(bool inactive);
private:
BMenu* _WindowIndexMenu();
protected: protected:
MediaPlayer* fMediaPlayer; MediaPlayer* fMediaPlayer;
BDragger* fDragger; BDragger* fDragger;