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"
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;
fWindowTarget = followType;
fWindowTargetHops = 0;
}
@ -21,7 +27,9 @@ MediaPlayer::MediaPlayer(BMessage* 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);
data->AddInt32("_window", fWindowIndex);
data->AddInt32("_windowtype", fWindowTarget);
data->AddString("class", "MediaPlayer");
data->AddString("add_on", APP_SIGNATURE);
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
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
MediaPlayer::SetWindow(int32 index)
{
@ -127,7 +173,7 @@ int32
MediaPlayer::CountWindows()
{
BMessage send(B_COUNT_PROPERTIES), reply;
_ScriptingCall("Window", &send, &reply, MP_NO_TRACK);
_ScriptingCall("Window", &send, &reply, MP_NO_TRACK, false);
int32 count;
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
MediaPlayer::_GetSong(Song* song, int32 trackIndex, bool durationRequired)
MediaPlayer::_GetSong(Song* song, int32 trackIndex, bool durationReq)
{
BMessage send, reply;
_ScriptingCall("URI", &send, &reply, trackIndex);
@ -146,19 +207,25 @@ MediaPlayer::_GetSong(Song* song, int32 trackIndex, bool durationRequired)
return false;
int64 duration = -1;
if (durationRequired) {
if (durationReq) {
_ScriptingCall("Duration", &send, &reply, trackIndex);
if (reply.FindInt64("result", &duration) != B_OK)
return false;
}
if (trackIndex == MP_CURRENT_TRACK && fWindowTarget != MP_BY_INDEX
&& uriString != fLastItemPath) {
fLastItemPath.SetTo(uriString);
fWindowTargetHops = 0;
}
*song = Song(_UriToPath(uriString), duration);
return true;
}
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)
send->what = B_GET_PROPERTY;
@ -169,9 +236,14 @@ MediaPlayer::_ScriptingCall(const char* attribute, BMessage* send, BMessage* rep
else if (trackIndex == MP_CURRENT_TRACK)
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 {
public:
MediaPlayer(int32 window = 0);
MediaPlayer(int32 window = 0, target followType = MP_BY_TYPE_AUDIO);
MediaPlayer(BMessage* archive);
virtual status_t Archive(BMessage* data, bool deep = true) const;
static MediaPlayer* Instantiate(BMessage* data);
bool IsValid();
bool IsPlaying();
int64 Duration();
int64 Duration();
int64 Position();
void SetPosition(int64 position);
float Volume();
@ -38,16 +47,25 @@ public:
bool CurrentItem(Song* song, bool duration = true);
bool PlaylistItem(Song* song, int32 index, bool duration = true);
int32 Window();
int32 SetWindow(int32 index);
int32 CountWindows();
target Target();
target SetTarget(target target);
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,
int32 trackIndex = MP_NO_TRACK);
int32 trackIndex = MP_NO_TRACK, bool window = true);
const char* _UriToPath(BString URI);
int32 fWindowIndex;
target fWindowTarget;
int32 fWindowTargetHops; // Amount of pulses to wait before re-checking windows
BString fLastItemPath;
};
#endif // MEDIAPLAYER_H

View File

@ -36,7 +36,7 @@ ReplicantView::ReplicantView(BRect frame, const char* name, uint32 draggerPlacem
fTransparentInactivity = false;
fTransparentDragger = false;
fMediaPlayer = new MediaPlayer(0);
fMediaPlayer = new MediaPlayer();
}
@ -71,7 +71,7 @@ ReplicantView::Archive(BMessage* data, bool deep) const
data->AddString("class", "ReplicantView");
data->AddString("add_on", APP_SIGNATURE);
return status;
return status;
}
@ -89,6 +89,25 @@ ReplicantView::MessageReceived(BMessage* msg)
{
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_DRAG: {
if (msg->what == REPL_TRANSPARENTLY_INACTIVE)
@ -136,7 +155,6 @@ ReplicantView::RightClickPopUp(BPopUpMenu* menu)
BMenu* hideMenu = new BMenu("Hide when inactive");
menu->AddItem(hideMenu);
BMenuItem* hideInactive = hideMenu->Superitem();
hideInactive->SetMessage(new BMessage(REPL_TRANSPARENTLY_INACTIVE));
hideInactive->SetMarked(fTransparentInactivity);
@ -148,12 +166,29 @@ ReplicantView::RightClickPopUp(BPopUpMenu* menu)
hideDragger->SetTarget(this);
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();
BString aboutLabel = "About %replicant" B_UTF8_ELLIPSIS;
aboutLabel.ReplaceAll("%replicant", Name());
BMenuItem* aboutItem = new BMenuItem(aboutLabel, new BMessage(B_ABOUT_REQUESTED));
aboutItem->SetTarget(this);
menu->AddItem(aboutItem);
if (fReplicated) {
@ -182,3 +217,31 @@ ReplicantView::SetInactive(bool inactive)
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>
class BDragger;
class BMenu;
class BPopUpMenu;
class MediaPlayer;
enum {
MP_AUDIO_WINDOW = 'mpaw',
MP_VIDEO_WINDOW = 'mpvw',
MP_NEWEST_WINDOW = 'mpnw'
};
enum {
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
virtual void SetInactive(bool inactive);
private:
BMenu* _WindowIndexMenu();
protected:
MediaPlayer* fMediaPlayer;
BDragger* fDragger;