poll both stdin and mpd using one select()

this allows for immediate reading mpd events
This commit is contained in:
Andrzej Rybczak
2009-10-25 20:44:07 +01:00
parent 08f4459b54
commit dd04406ee5
22 changed files with 138 additions and 75 deletions

View File

@@ -53,7 +53,6 @@ void Browser::Init()
{ {
w = new Menu<Item>(0, MainStartY, COLS, MainHeight, Config.columns_in_browser ? Display::Columns() : "", Config.main_color, brNone); w = new Menu<Item>(0, MainStartY, COLS, MainHeight, Config.columns_in_browser ? Display::Columns() : "", Config.main_color, brNone);
w->HighlightColor(Config.main_highlight_color); w->HighlightColor(Config.main_highlight_color);
w->SetTimeout(ncmpcpp_window_timeout);
w->CyclicScrolling(Config.use_cyclic_scrolling); w->CyclicScrolling(Config.use_cyclic_scrolling);
w->SetSelectPrefix(&Config.selected_item_prefix); w->SetSelectPrefix(&Config.selected_item_prefix);
w->SetSelectSuffix(&Config.selected_item_suffix); w->SetSelectSuffix(&Config.selected_item_suffix);

View File

@@ -52,7 +52,6 @@ void Clock::Init()
Width = Config.clock_display_seconds ? 60 : 40; Width = Config.clock_display_seconds ? 60 : 40;
w = new Window((COLS-Width)/2, (MainHeight-Height)/2+MainStartY, Width, Height-1, "", Config.main_color, Border(Config.main_color)); w = new Window((COLS-Width)/2, (MainHeight-Height)/2+MainStartY, Width, Height-1, "", Config.main_color, Border(Config.main_color));
w->SetTimeout(ncmpcpp_window_timeout);
isInitialized = 1; isInitialized = 1;
} }

View File

@@ -32,7 +32,6 @@ Help *myHelp = new Help;
void Help::Init() void Help::Init()
{ {
w = new Scrollpad(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone); w = new Scrollpad(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone);
w->SetTimeout(ncmpcpp_window_timeout);
GetKeybindings(); GetKeybindings();
w->Flush(); w->Flush();
isInitialized = 1; isInitialized = 1;

View File

@@ -73,7 +73,6 @@ const Info::Metadata Info::Tags[] =
void Info::Init() void Info::Init()
{ {
w = new Scrollpad(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone); w = new Scrollpad(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone);
w->SetTimeout(ncmpcpp_window_timeout);
isInitialized = 1; isInitialized = 1;
} }

View File

@@ -69,7 +69,6 @@ Lyrics *myLyrics = new Lyrics;
void Lyrics::Init() void Lyrics::Init()
{ {
w = new Scrollpad(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone); w = new Scrollpad(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone);
w->SetTimeout(ncmpcpp_window_timeout);
isInitialized = 1; isInitialized = 1;
} }

View File

@@ -52,20 +52,17 @@ void MediaLibrary::Init()
Artists = new Menu<std::string>(0, MainStartY, itsLeftColWidth, MainHeight, IntoStr(Config.media_lib_primary_tag) + "s", Config.main_color, brNone); Artists = new Menu<std::string>(0, MainStartY, itsLeftColWidth, MainHeight, IntoStr(Config.media_lib_primary_tag) + "s", Config.main_color, brNone);
Artists->HighlightColor(Config.active_column_color); Artists->HighlightColor(Config.active_column_color);
Artists->SetTimeout(ncmpcpp_window_timeout);
Artists->CyclicScrolling(Config.use_cyclic_scrolling); Artists->CyclicScrolling(Config.use_cyclic_scrolling);
Artists->SetItemDisplayer(Display::Generic); Artists->SetItemDisplayer(Display::Generic);
Albums = new Menu< std::pair<std::string, SearchConstraints> >(itsMiddleColStartX, MainStartY, itsMiddleColWidth, MainHeight, "Albums", Config.main_color, brNone); Albums = new Menu< std::pair<std::string, SearchConstraints> >(itsMiddleColStartX, MainStartY, itsMiddleColWidth, MainHeight, "Albums", Config.main_color, brNone);
Albums->HighlightColor(Config.main_highlight_color); Albums->HighlightColor(Config.main_highlight_color);
Albums->SetTimeout(ncmpcpp_window_timeout);
Albums->CyclicScrolling(Config.use_cyclic_scrolling); Albums->CyclicScrolling(Config.use_cyclic_scrolling);
Albums->SetItemDisplayer(Display::Pairs); Albums->SetItemDisplayer(Display::Pairs);
Albums->SetGetStringFunction(StringPairToString); Albums->SetGetStringFunction(StringPairToString);
Songs = new Menu<Song>(itsRightColStartX, MainStartY, itsRightColWidth, MainHeight, "Songs", Config.main_color, brNone); Songs = new Menu<Song>(itsRightColStartX, MainStartY, itsRightColWidth, MainHeight, "Songs", Config.main_color, brNone);
Songs->HighlightColor(Config.main_highlight_color); Songs->HighlightColor(Config.main_highlight_color);
Songs->SetTimeout(ncmpcpp_window_timeout);
Songs->CyclicScrolling(Config.use_cyclic_scrolling); Songs->CyclicScrolling(Config.use_cyclic_scrolling);
Songs->SetSelectPrefix(&Config.selected_item_prefix); Songs->SetSelectPrefix(&Config.selected_item_prefix);
Songs->SetSelectSuffix(&Config.selected_item_suffix); Songs->SetSelectSuffix(&Config.selected_item_suffix);

View File

@@ -38,7 +38,6 @@ void SelectedItemsAdder::Init()
{ {
SetDimensions(); SetDimensions();
w = new Menu<std::string>((COLS-itsWidth)/2, (MainHeight-itsHeight)/2+MainStartY, itsWidth, itsHeight, "Add selected items to...", Config.main_color, Config.window_border); w = new Menu<std::string>((COLS-itsWidth)/2, (MainHeight-itsHeight)/2+MainStartY, itsWidth, itsHeight, "Add selected items to...", Config.main_color, Config.window_border);
w->SetTimeout(ncmpcpp_window_timeout);
w->CyclicScrolling(Config.use_cyclic_scrolling); w->CyclicScrolling(Config.use_cyclic_scrolling);
w->HighlightColor(Config.main_highlight_color); w->HighlightColor(Config.main_highlight_color);
w->SetItemDisplayer(Display::Generic); w->SetItemDisplayer(Display::Generic);

View File

@@ -151,14 +151,14 @@ void Connection::GoIdle()
isIdle = 1; isIdle = 1;
} }
mpd_idle Connection::GoBusy() int Connection::GoBusy()
{ {
if (isIdle && mpd_send_noidle(itsConnection)) if (isIdle && mpd_send_noidle(itsConnection))
{ {
isIdle = 0; isIdle = 0;
return mpd_recv_idle(itsConnection, 1); return mpd_recv_idle(itsConnection, 1);
} }
return mpd_idle(0); return 0;
} }
void Connection::UpdateStatus() void Connection::UpdateStatus()
@@ -166,13 +166,14 @@ void Connection::UpdateStatus()
if (!itsConnection) if (!itsConnection)
return; return;
int idle_mask = 0;
if (isIdle) if (isIdle)
{ {
FD_ZERO(&itsPoll); if (hasData)
FD_SET(itsFD, &itsPoll); {
timeval timeout = { 0, 0 }; idle_mask = GoBusy();
if (select(itsFD+1, &itsPoll, 0, 0, &timeout) == 1) hasData = 0;
GoBusy(); }
else else
{ {
// count local elapsed time as we don't receive // count local elapsed time as we don't receive
@@ -217,14 +218,6 @@ void Connection::UpdateStatus()
{ {
// sync local elapsed time counter with mpd // sync local elapsed time counter with mpd
itsElapsed = mpd_status_get_elapsed_time(itsCurrentStatus); itsElapsed = mpd_status_get_elapsed_time(itsCurrentStatus);
// little hack as it seems mpd doesn't always return elapsed
// time equal to 0 even if song has changed, it sometimes
// returns the last second, so we need to bypass it by zeroing
// it in this case.
// NOTICE: it seems polling with select() instead of poll()
// fixes this, but that can just be more randomness.
//if (itsElapsed == mpd_status_get_total_time(itsCurrentStatus))
// itsElapsed = 0;
time(&itsElapsedTimer[0]); time(&itsElapsedTimer[0]);
} }
else else
@@ -274,7 +267,12 @@ void Connection::UpdateStatus()
itsChanges.StatusFlags = itsChanges.Repeat || itsChanges.Random || itsChanges.Single || itsChanges.Consume || itsChanges.Crossfade || itsChanges.DBUpdating; itsChanges.StatusFlags = itsChanges.Repeat || itsChanges.Random || itsChanges.Single || itsChanges.Consume || itsChanges.Crossfade || itsChanges.DBUpdating;
} }
itsUpdater(this, itsChanges, itsErrorHandlerUserdata); itsUpdater(this, itsChanges, itsErrorHandlerUserdata);
GoIdle(); // below conditionals are a hack to workaround mpd bug 2608/2612
// by fetching another status with correct values after a while
if (!((idle_mask & MPD_IDLE_PLAYER) && !itsChanges.PlayerState))
GoIdle();
else if (supportsIdle && !isIdle)
OrderDataFetching();
} }
} }

View File

@@ -21,12 +21,6 @@
#ifndef _MPDPP_H #ifndef _MPDPP_H
#define _MPDPP_H #define _MPDPP_H
#ifdef WIN32
# include <winsock.h>
#else
# include <sys/select.h>
#endif
#include <vector> #include <vector>
#include <mpd/client.h> #include <mpd/client.h>
@@ -98,7 +92,10 @@ namespace MPD
int GetPort() { return itsPort; } int GetPort() { return itsPort; }
float Version() const; float Version() const;
bool SupportsIdle() const { return supportsIdle; } bool SupportsIdle() const { return supportsIdle; }
void OrderDataFetching() { hasData = 1; }
int GetFD() const { return itsFD; }
void SetHostname(const std::string &); void SetHostname(const std::string &);
void SetPort(int port) { itsPort = port; } void SetPort(int port) { itsPort = port; }
@@ -213,7 +210,7 @@ namespace MPD
private: private:
void GoIdle(); void GoIdle();
mpd_idle GoBusy(); int GoBusy();
int CheckForErrors(); int CheckForErrors();
@@ -224,10 +221,10 @@ namespace MPD
int itsErrorCode; int itsErrorCode;
size_t itsMaxPlaylistLength; size_t itsMaxPlaylistLength;
fd_set itsPoll;
int itsFD; int itsFD;
bool isIdle; bool isIdle;
bool supportsIdle; bool supportsIdle;
bool hasData;
std::string itsHost; std::string itsHost;
int itsPort; int itsPort;

View File

@@ -159,6 +159,7 @@ int main(int argc, char *argv[])
wFooter = new Window(0, footer_start_y, COLS, footer_height, "", Config.statusbar_color, brNone); wFooter = new Window(0, footer_start_y, COLS, footer_height, "", Config.statusbar_color, brNone);
wFooter->SetTimeout(ncmpcpp_window_timeout); wFooter->SetTimeout(ncmpcpp_window_timeout);
wFooter->SetGetStringHelper(StatusbarGetStringHelper); wFooter->SetGetStringHelper(StatusbarGetStringHelper);
wFooter->AddFDCallback(Mpd.GetFD(), StatusbarMPDCallback);
wFooter->CreateHistory(); wFooter->CreateHistory();
myPlaylist->SwitchTo(); myPlaylist->SwitchTo();
@@ -201,10 +202,13 @@ int main(int argc, char *argv[])
{ {
if (!Mpd.Connected()) if (!Mpd.Connected())
{ {
if (!wFooter->FDCallbacksListEmpty())
wFooter->ClearFDCallbacksList();
ShowMessage("Attempting to reconnect..."); ShowMessage("Attempting to reconnect...");
if (Mpd.Connect()) if (Mpd.Connect())
{ {
ShowMessage("Connected to %s!", Mpd.GetHostname().c_str()); ShowMessage("Connected to %s!", Mpd.GetHostname().c_str());
wFooter->AddFDCallback(Mpd.GetFD(), StatusbarMPDCallback);
MessagesAllowed = 0; MessagesAllowed = 0;
UpdateStatusImmediately = 1; UpdateStatusImmediately = 1;
# ifdef ENABLE_OUTPUTS # ifdef ENABLE_OUTPUTS
@@ -289,7 +293,7 @@ int main(int argc, char *argv[])
myScreen->Update(); myScreen->Update();
if (input != ERR) if (input != ERR)
myScreen->RefreshWindow(); myScreen->RefreshWindow();
myScreen->ReadKey(input); wFooter->ReadKey(input);
if (input == ERR) if (input == ERR)
continue; continue;
@@ -567,7 +571,7 @@ int main(int argc, char *argv[])
else else
{ {
Playlist::BlockNowPlayingUpdate = 1; Playlist::BlockNowPlayingUpdate = 1;
myPlaylist->Items->SetTimeout(50); wFooter->SetTimeout(50);
int del_counter = 0; int del_counter = 0;
while (!myPlaylist->Items->Empty() && Keypressed(input, Key.Delete)) while (!myPlaylist->Items->Empty() && Keypressed(input, Key.Delete))
{ {
@@ -581,11 +585,11 @@ int main(int argc, char *argv[])
Mpd.DeleteID(myPlaylist->CurrentSong()->GetID()); Mpd.DeleteID(myPlaylist->CurrentSong()->GetID());
myPlaylist->Items->DeleteOption(id); myPlaylist->Items->DeleteOption(id);
myPlaylist->Items->Refresh(); myPlaylist->Items->Refresh();
myPlaylist->Items->ReadKey(input); wFooter->ReadKey(input);
++del_counter; ++del_counter;
} }
myPlaylist->FixPositions(myPlaylist->Items->Choice()); myPlaylist->FixPositions(myPlaylist->Items->Choice());
myPlaylist->Items->SetTimeout(ncmpcpp_window_timeout); wFooter->SetTimeout(ncmpcpp_window_timeout);
Playlist::BlockNowPlayingUpdate = 0; Playlist::BlockNowPlayingUpdate = 0;
} }
} }
@@ -703,7 +707,7 @@ int main(int argc, char *argv[])
} }
else else
{ {
myPlaylistEditor->Content->SetTimeout(50); wFooter->SetTimeout(50);
locale_to_utf(myPlaylistEditor->Playlists->Current()); locale_to_utf(myPlaylistEditor->Playlists->Current());
while (!myPlaylistEditor->Content->Empty() && Keypressed(input, Key.Delete)) while (!myPlaylistEditor->Content->Empty() && Keypressed(input, Key.Delete))
{ {
@@ -712,10 +716,10 @@ int main(int argc, char *argv[])
Mpd.Delete(myPlaylistEditor->Playlists->Current(), myPlaylistEditor->Content->Choice()); Mpd.Delete(myPlaylistEditor->Playlists->Current(), myPlaylistEditor->Content->Choice());
myPlaylistEditor->Content->DeleteOption(myPlaylistEditor->Content->Choice()); myPlaylistEditor->Content->DeleteOption(myPlaylistEditor->Content->Choice());
myPlaylistEditor->Content->Refresh(); myPlaylistEditor->Content->Refresh();
myPlaylistEditor->Content->ReadKey(input); wFooter->ReadKey(input);
} }
utf_to_locale(myPlaylistEditor->Playlists->Current()); utf_to_locale(myPlaylistEditor->Playlists->Current());
myPlaylistEditor->Content->SetTimeout(ncmpcpp_window_timeout); wFooter->SetTimeout(ncmpcpp_window_timeout);
} }
} }
} }
@@ -808,7 +812,7 @@ int main(int argc, char *argv[])
else if (myScreen == myPlaylist && !myPlaylist->Items->Empty()) else if (myScreen == myPlaylist && !myPlaylist->Items->Empty())
{ {
CHECK_PLAYLIST_FOR_FILTERING; CHECK_PLAYLIST_FOR_FILTERING;
myPlaylist->Items->SetTimeout(50); wFooter->SetTimeout(50);
if (myPlaylist->Items->hasSelected()) if (myPlaylist->Items->hasSelected())
{ {
std::vector<size_t> list; std::vector<size_t> list;
@@ -848,7 +852,7 @@ int main(int argc, char *argv[])
} }
myPlaylist->Items->Highlight(list[(list.size()-1)/2]); myPlaylist->Items->Highlight(list[(list.size()-1)/2]);
myPlaylist->Items->Refresh(); myPlaylist->Items->Refresh();
myPlaylist->Items->ReadKey(input); wFooter->ReadKey(input);
} }
Playlist::BlockNowPlayingUpdate = 0; Playlist::BlockNowPlayingUpdate = 0;
Mpd.StartCommandsList(); Mpd.StartCommandsList();
@@ -876,17 +880,17 @@ int main(int argc, char *argv[])
myPlaylist->Items->Swap(to, to+1); myPlaylist->Items->Swap(to, to+1);
myPlaylist->Items->Scroll(wUp); myPlaylist->Items->Scroll(wUp);
myPlaylist->Items->Refresh(); myPlaylist->Items->Refresh();
myPlaylist->Items->ReadKey(input); wFooter->ReadKey(input);
} }
Mpd.Move(from, to); Mpd.Move(from, to);
Playlist::BlockNowPlayingUpdate = 0; Playlist::BlockNowPlayingUpdate = 0;
UpdateStatusImmediately = 1; UpdateStatusImmediately = 1;
} }
myPlaylist->Items->SetTimeout(ncmpcpp_window_timeout); wFooter->SetTimeout(ncmpcpp_window_timeout);
} }
else if (myScreen->ActiveWindow() == myPlaylistEditor->Content && !myPlaylistEditor->Content->Empty()) else if (myScreen->ActiveWindow() == myPlaylistEditor->Content && !myPlaylistEditor->Content->Empty())
{ {
myPlaylistEditor->Content->SetTimeout(50); wFooter->SetTimeout(50);
if (myPlaylistEditor->Content->hasSelected()) if (myPlaylistEditor->Content->hasSelected())
{ {
std::vector<size_t> list; std::vector<size_t> list;
@@ -905,7 +909,7 @@ int main(int argc, char *argv[])
} }
myPlaylistEditor->Content->Highlight(list[(list.size()-1)/2]); myPlaylistEditor->Content->Highlight(list[(list.size()-1)/2]);
myPlaylistEditor->Content->Refresh(); myPlaylistEditor->Content->Refresh();
myPlaylistEditor->Content->ReadKey(input); wFooter->ReadKey(input);
} }
Mpd.StartCommandsList(); Mpd.StartCommandsList();
for (size_t i = 0; i < list.size(); ++i) for (size_t i = 0; i < list.size(); ++i)
@@ -925,12 +929,12 @@ int main(int argc, char *argv[])
myPlaylistEditor->Content->Swap(to, to+1); myPlaylistEditor->Content->Swap(to, to+1);
myPlaylistEditor->Content->Scroll(wUp); myPlaylistEditor->Content->Scroll(wUp);
myPlaylistEditor->Content->Refresh(); myPlaylistEditor->Content->Refresh();
myPlaylistEditor->Content->ReadKey(input); wFooter->ReadKey(input);
} }
if (from != to) if (from != to)
Mpd.Move(myPlaylistEditor->Playlists->Current(), from, to); Mpd.Move(myPlaylistEditor->Playlists->Current(), from, to);
} }
myPlaylistEditor->Content->SetTimeout(ncmpcpp_window_timeout); wFooter->SetTimeout(ncmpcpp_window_timeout);
} }
} }
else if (Keypressed(input, Key.MvSongDown)) else if (Keypressed(input, Key.MvSongDown))
@@ -940,7 +944,7 @@ int main(int argc, char *argv[])
else if (myScreen == myPlaylist && !myPlaylist->Items->Empty()) else if (myScreen == myPlaylist && !myPlaylist->Items->Empty())
{ {
CHECK_PLAYLIST_FOR_FILTERING; CHECK_PLAYLIST_FOR_FILTERING;
myPlaylist->Items->SetTimeout(50); wFooter->SetTimeout(50);
if (myPlaylist->Items->hasSelected()) if (myPlaylist->Items->hasSelected())
{ {
std::vector<size_t> list; std::vector<size_t> list;
@@ -974,7 +978,7 @@ int main(int argc, char *argv[])
} }
myPlaylist->Items->Highlight(list[(list.size()-1)/2]); myPlaylist->Items->Highlight(list[(list.size()-1)/2]);
myPlaylist->Items->Refresh(); myPlaylist->Items->Refresh();
myPlaylist->Items->ReadKey(input); wFooter->ReadKey(input);
} }
Playlist::BlockNowPlayingUpdate = 0; Playlist::BlockNowPlayingUpdate = 0;
Mpd.StartCommandsList(); Mpd.StartCommandsList();
@@ -1002,18 +1006,18 @@ int main(int argc, char *argv[])
myPlaylist->Items->Swap(to, to-1); myPlaylist->Items->Swap(to, to-1);
myPlaylist->Items->Scroll(wDown); myPlaylist->Items->Scroll(wDown);
myPlaylist->Items->Refresh(); myPlaylist->Items->Refresh();
myPlaylist->Items->ReadKey(input); wFooter->ReadKey(input);
} }
Mpd.Move(from, to); Mpd.Move(from, to);
Playlist::BlockNowPlayingUpdate = 0; Playlist::BlockNowPlayingUpdate = 0;
UpdateStatusImmediately = 1; UpdateStatusImmediately = 1;
} }
myPlaylist->Items->SetTimeout(ncmpcpp_window_timeout); wFooter->SetTimeout(ncmpcpp_window_timeout);
} }
else if (myScreen->ActiveWindow() == myPlaylistEditor->Content && !myPlaylistEditor->Content->Empty()) else if (myScreen->ActiveWindow() == myPlaylistEditor->Content && !myPlaylistEditor->Content->Empty())
{ {
myPlaylistEditor->Content->SetTimeout(50); wFooter->SetTimeout(50);
if (myPlaylistEditor->Content->hasSelected()) if (myPlaylistEditor->Content->hasSelected())
{ {
std::vector<size_t> list; std::vector<size_t> list;
@@ -1032,7 +1036,7 @@ int main(int argc, char *argv[])
} }
myPlaylistEditor->Content->Highlight(list[(list.size()-1)/2]); myPlaylistEditor->Content->Highlight(list[(list.size()-1)/2]);
myPlaylistEditor->Content->Refresh(); myPlaylistEditor->Content->Refresh();
myPlaylistEditor->Content->ReadKey(input); wFooter->ReadKey(input);
} }
Mpd.StartCommandsList(); Mpd.StartCommandsList();
for (int i = list.size()-1; i >= 0; --i) for (int i = list.size()-1; i >= 0; --i)
@@ -1052,12 +1056,12 @@ int main(int argc, char *argv[])
myPlaylistEditor->Content->Swap(to, to-1); myPlaylistEditor->Content->Swap(to, to-1);
myPlaylistEditor->Content->Scroll(wDown); myPlaylistEditor->Content->Scroll(wDown);
myPlaylistEditor->Content->Refresh(); myPlaylistEditor->Content->Refresh();
myPlaylistEditor->Content->ReadKey(input); wFooter->ReadKey(input);
} }
if (from != to) if (from != to)
Mpd.Move(myPlaylistEditor->Playlists->Current(), from, to); Mpd.Move(myPlaylistEditor->Playlists->Current(), from, to);
} }
myPlaylistEditor->Content->SetTimeout(ncmpcpp_window_timeout); wFooter->SetTimeout(ncmpcpp_window_timeout);
} }
} }
else if (Keypressed(input, Key.MoveTo) && myScreen == myPlaylist) else if (Keypressed(input, Key.MoveTo) && myScreen == myPlaylist)
@@ -1148,7 +1152,7 @@ int main(int argc, char *argv[])
{ {
TraceMpdStatus(); TraceMpdStatus();
myPlaylist->UpdateTimer(); myPlaylist->UpdateTimer();
myPlaylist->Items->ReadKey(input); wFooter->ReadKey(input);
int howmuch = Config.incremental_seeking ? (myPlaylist->Timer()-t)/2+Config.seek_time : Config.seek_time; int howmuch = Config.incremental_seeking ? (myPlaylist->Timer()-t)/2+Config.seek_time : Config.seek_time;

View File

@@ -37,7 +37,7 @@ using namespace NCurses;
typedef std::pair<std::string, std::string> string_pair; typedef std::pair<std::string, std::string> string_pair;
const int ncmpcpp_window_timeout = 100; const int ncmpcpp_window_timeout = 500;
#endif #endif

View File

@@ -32,7 +32,6 @@ Outputs *myOutputs = new Outputs;
void Outputs::Init() void Outputs::Init()
{ {
w = new Menu<MPD::Output>(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone); w = new Menu<MPD::Output>(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone);
w->SetTimeout(ncmpcpp_window_timeout);
w->CyclicScrolling(Config.use_cyclic_scrolling); w->CyclicScrolling(Config.use_cyclic_scrolling);
w->HighlightColor(Config.main_highlight_color); w->HighlightColor(Config.main_highlight_color);
w->SetItemDisplayer(Display::Pairs); w->SetItemDisplayer(Display::Pairs);

View File

@@ -47,7 +47,6 @@ Menu< std::pair<std::string, MPD::Song::GetFunction> > *Playlist::SortDialog = 0
void Playlist::Init() void Playlist::Init()
{ {
Items = new Menu<MPD::Song>(0, MainStartY, COLS, MainHeight, Config.columns_in_playlist ? Display::Columns() : "", Config.main_color, brNone); Items = new Menu<MPD::Song>(0, MainStartY, COLS, MainHeight, Config.columns_in_playlist ? Display::Columns() : "", Config.main_color, brNone);
Items->SetTimeout(ncmpcpp_window_timeout);
Items->CyclicScrolling(Config.use_cyclic_scrolling); Items->CyclicScrolling(Config.use_cyclic_scrolling);
Items->HighlightColor(Config.main_highlight_color); Items->HighlightColor(Config.main_highlight_color);
Items->SetSelectPrefix(&Config.selected_item_prefix); Items->SetSelectPrefix(&Config.selected_item_prefix);
@@ -62,7 +61,6 @@ void Playlist::Init()
SortDialogHeight = std::min(int(MainHeight), 18); SortDialogHeight = std::min(int(MainHeight), 18);
SortDialog = new Menu< std::pair<std::string, MPD::Song::GetFunction> >((COLS-SortDialogWidth)/2, (MainHeight-SortDialogHeight)/2+MainStartY, SortDialogWidth, SortDialogHeight, "Sort songs by...", Config.main_color, Config.window_border); SortDialog = new Menu< std::pair<std::string, MPD::Song::GetFunction> >((COLS-SortDialogWidth)/2, (MainHeight-SortDialogHeight)/2+MainStartY, SortDialogWidth, SortDialogHeight, "Sort songs by...", Config.main_color, Config.window_border);
SortDialog->SetTimeout(ncmpcpp_window_timeout);
SortDialog->CyclicScrolling(Config.use_cyclic_scrolling); SortDialog->CyclicScrolling(Config.use_cyclic_scrolling);
SortDialog->SetItemDisplayer(Display::Pairs); SortDialog->SetItemDisplayer(Display::Pairs);

View File

@@ -47,13 +47,11 @@ void PlaylistEditor::Init()
Playlists = new Menu<std::string>(0, MainStartY, LeftColumnWidth, MainHeight, "Playlists", Config.main_color, brNone); Playlists = new Menu<std::string>(0, MainStartY, LeftColumnWidth, MainHeight, "Playlists", Config.main_color, brNone);
Playlists->HighlightColor(Config.active_column_color); Playlists->HighlightColor(Config.active_column_color);
Playlists->SetTimeout(ncmpcpp_window_timeout);
Playlists->CyclicScrolling(Config.use_cyclic_scrolling); Playlists->CyclicScrolling(Config.use_cyclic_scrolling);
Playlists->SetItemDisplayer(Display::Generic); Playlists->SetItemDisplayer(Display::Generic);
Content = new Menu<Song>(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, "Playlist's content", Config.main_color, brNone); Content = new Menu<Song>(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, "Playlist's content", Config.main_color, brNone);
Content->HighlightColor(Config.main_highlight_color); Content->HighlightColor(Config.main_highlight_color);
Content->SetTimeout(ncmpcpp_window_timeout);
Content->CyclicScrolling(Config.use_cyclic_scrolling); Content->CyclicScrolling(Config.use_cyclic_scrolling);
Content->SetSelectPrefix(&Config.selected_item_prefix); Content->SetSelectPrefix(&Config.selected_item_prefix);
Content->SetSelectSuffix(&Config.selected_item_suffix); Content->SetSelectSuffix(&Config.selected_item_suffix);

View File

@@ -61,7 +61,6 @@ void SearchEngine::Init()
{ {
w = new Menu< std::pair<Buffer *, Song *> >(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone); w = new Menu< std::pair<Buffer *, Song *> >(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone);
w->HighlightColor(Config.main_highlight_color); w->HighlightColor(Config.main_highlight_color);
w->SetTimeout(ncmpcpp_window_timeout);
w->CyclicScrolling(Config.use_cyclic_scrolling); w->CyclicScrolling(Config.use_cyclic_scrolling);
w->SetItemDisplayer(Display::SearchEngine); w->SetItemDisplayer(Display::SearchEngine);
w->SetSelectPrefix(&Config.selected_item_prefix); w->SetSelectPrefix(&Config.selected_item_prefix);

View File

@@ -34,7 +34,6 @@ void ServerInfo::Init()
{ {
SetDimensions(); SetDimensions();
w = new Scrollpad((COLS-itsWidth)/2, (MainHeight-itsHeight)/2+MainStartY, itsWidth, itsHeight, "MPD server info", Config.main_color, Config.window_border); w = new Scrollpad((COLS-itsWidth)/2, (MainHeight-itsHeight)/2+MainStartY, itsWidth, itsHeight, "MPD server info", Config.main_color, Config.window_border);
w->SetTimeout(ncmpcpp_window_timeout);
Mpd.GetURLHandlers(itsURLHandlers); Mpd.GetURLHandlers(itsURLHandlers);
Mpd.GetTagTypes(itsTagTypes); Mpd.GetTagTypes(itsTagTypes);

View File

@@ -63,6 +63,11 @@ void WindowTitle(const std::string &status)
} }
#endif // !USE_PDCURSES #endif // !USE_PDCURSES
void StatusbarMPDCallback()
{
Mpd.OrderDataFetching();
}
void StatusbarGetStringHelper(const std::wstring &) void StatusbarGetStringHelper(const std::wstring &)
{ {
TraceMpdStatus(); TraceMpdStatus();

View File

@@ -44,6 +44,7 @@ Window &Statusbar();
void DrawProgressbar(unsigned elapsed, unsigned time); void DrawProgressbar(unsigned elapsed, unsigned time);
void ShowMessage(const char *, ...) GNUC_PRINTF(1, 2); void ShowMessage(const char *, ...) GNUC_PRINTF(1, 2);
void StatusbarMPDCallback();
void StatusbarGetStringHelper(const std::wstring &); void StatusbarGetStringHelper(const std::wstring &);
void StatusbarApplyFilterImmediately(const std::wstring &); void StatusbarApplyFilterImmediately(const std::wstring &);

View File

@@ -68,14 +68,12 @@ void TagEditor::Init()
Albums = new Menu<string_pair>(0, MainStartY, LeftColumnWidth, MainHeight, "Albums", Config.main_color, brNone); Albums = new Menu<string_pair>(0, MainStartY, LeftColumnWidth, MainHeight, "Albums", Config.main_color, brNone);
Albums->HighlightColor(Config.active_column_color); Albums->HighlightColor(Config.active_column_color);
Albums->SetTimeout(ncmpcpp_window_timeout);
Albums->CyclicScrolling(Config.use_cyclic_scrolling); Albums->CyclicScrolling(Config.use_cyclic_scrolling);
Albums->SetItemDisplayer(Display::Pairs); Albums->SetItemDisplayer(Display::Pairs);
Albums->SetGetStringFunction(StringPairToString); Albums->SetGetStringFunction(StringPairToString);
Dirs = new Menu<string_pair>(0, MainStartY, LeftColumnWidth, MainHeight, "Directories", Config.main_color, brNone); Dirs = new Menu<string_pair>(0, MainStartY, LeftColumnWidth, MainHeight, "Directories", Config.main_color, brNone);
Dirs->HighlightColor(Config.active_column_color); Dirs->HighlightColor(Config.active_column_color);
Dirs->SetTimeout(ncmpcpp_window_timeout);
Dirs->CyclicScrolling(Config.use_cyclic_scrolling); Dirs->CyclicScrolling(Config.use_cyclic_scrolling);
Dirs->SetItemDisplayer(Display::Pairs); Dirs->SetItemDisplayer(Display::Pairs);
Dirs->SetGetStringFunction(StringPairToString); Dirs->SetGetStringFunction(StringPairToString);
@@ -84,7 +82,6 @@ void TagEditor::Init()
TagTypes = new Menu<std::string>(MiddleColumnStartX, MainStartY, MiddleColumnWidth, MainHeight, "Tag types", Config.main_color, brNone); TagTypes = new Menu<std::string>(MiddleColumnStartX, MainStartY, MiddleColumnWidth, MainHeight, "Tag types", Config.main_color, brNone);
TagTypes->HighlightColor(Config.main_highlight_color); TagTypes->HighlightColor(Config.main_highlight_color);
TagTypes->SetTimeout(ncmpcpp_window_timeout);
TagTypes->CyclicScrolling(Config.use_cyclic_scrolling); TagTypes->CyclicScrolling(Config.use_cyclic_scrolling);
TagTypes->SetItemDisplayer(Display::Generic); TagTypes->SetItemDisplayer(Display::Generic);
@@ -111,7 +108,6 @@ void TagEditor::Init()
Tags = new Menu<MPD::Song>(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, "Tags", Config.main_color, brNone); Tags = new Menu<MPD::Song>(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, "Tags", Config.main_color, brNone);
Tags->HighlightColor(Config.main_highlight_color); Tags->HighlightColor(Config.main_highlight_color);
Tags->SetTimeout(ncmpcpp_window_timeout);
Tags->CyclicScrolling(Config.use_cyclic_scrolling); Tags->CyclicScrolling(Config.use_cyclic_scrolling);
Tags->SetSelectPrefix(&Config.selected_item_prefix); Tags->SetSelectPrefix(&Config.selected_item_prefix);
Tags->SetSelectSuffix(&Config.selected_item_suffix); Tags->SetSelectSuffix(&Config.selected_item_suffix);
@@ -121,7 +117,6 @@ void TagEditor::Init()
Tags->SetGetStringFunctionUserData(TagTypes); Tags->SetGetStringFunctionUserData(TagTypes);
FParserDialog = new Menu<std::string>((COLS-FParserDialogWidth)/2, (MainHeight-FParserDialogHeight)/2+MainStartY, FParserDialogWidth, FParserDialogHeight, "", Config.main_color, Config.window_border); FParserDialog = new Menu<std::string>((COLS-FParserDialogWidth)/2, (MainHeight-FParserDialogHeight)/2+MainStartY, FParserDialogWidth, FParserDialogHeight, "", Config.main_color, Config.window_border);
FParserDialog->SetTimeout(ncmpcpp_window_timeout);
FParserDialog->CyclicScrolling(Config.use_cyclic_scrolling); FParserDialog->CyclicScrolling(Config.use_cyclic_scrolling);
FParserDialog->SetItemDisplayer(Display::Generic); FParserDialog->SetItemDisplayer(Display::Generic);
FParserDialog->AddOption("Get tags from filename"); FParserDialog->AddOption("Get tags from filename");
@@ -130,15 +125,12 @@ void TagEditor::Init()
FParserDialog->AddOption("Cancel"); FParserDialog->AddOption("Cancel");
FParser = new Menu<std::string>((COLS-FParserWidth)/2, (MainHeight-FParserHeight)/2+MainStartY, FParserWidthOne, FParserHeight, "_", Config.main_color, Config.active_window_border); FParser = new Menu<std::string>((COLS-FParserWidth)/2, (MainHeight-FParserHeight)/2+MainStartY, FParserWidthOne, FParserHeight, "_", Config.main_color, Config.active_window_border);
FParser->SetTimeout(ncmpcpp_window_timeout);
FParser->CyclicScrolling(Config.use_cyclic_scrolling); FParser->CyclicScrolling(Config.use_cyclic_scrolling);
FParser->SetItemDisplayer(Display::Generic); FParser->SetItemDisplayer(Display::Generic);
FParserLegend = new Scrollpad((COLS-FParserWidth)/2+FParserWidthOne, (MainHeight-FParserHeight)/2+MainStartY, FParserWidthTwo, FParserHeight, "Legend", Config.main_color, Config.window_border); FParserLegend = new Scrollpad((COLS-FParserWidth)/2+FParserWidthOne, (MainHeight-FParserHeight)/2+MainStartY, FParserWidthTwo, FParserHeight, "Legend", Config.main_color, Config.window_border);
FParserLegend->SetTimeout(ncmpcpp_window_timeout);
FParserPreview = new Scrollpad((COLS-FParserWidth)/2+FParserWidthOne, (MainHeight-FParserHeight)/2+MainStartY, FParserWidthTwo, FParserHeight, "Preview", Config.main_color, Config.window_border); FParserPreview = new Scrollpad((COLS-FParserWidth)/2+FParserWidthOne, (MainHeight-FParserHeight)/2+MainStartY, FParserWidthTwo, FParserHeight, "Preview", Config.main_color, Config.window_border);
FParserPreview->SetTimeout(ncmpcpp_window_timeout);
w = LeftColumn; w = LeftColumn;
isInitialized = 1; isInitialized = 1;

View File

@@ -48,7 +48,6 @@ void TinyTagEditor::Init()
{ {
w = new Menu<Buffer>(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone); w = new Menu<Buffer>(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone);
w->HighlightColor(Config.main_highlight_color); w->HighlightColor(Config.main_highlight_color);
w->SetTimeout(ncmpcpp_window_timeout);
w->CyclicScrolling(Config.use_cyclic_scrolling); w->CyclicScrolling(Config.use_cyclic_scrolling);
w->SetItemDisplayer(Display::Generic); w->SetItemDisplayer(Display::Generic);
isInitialized = 1; isInitialized = 1;

View File

@@ -21,6 +21,12 @@
#include <cstring> #include <cstring>
#include <cstdlib> #include <cstdlib>
#ifdef WIN32
# include <winsock.h>
#else
# include <sys/select.h>
#endif
#include "error.h" #include "error.h"
#include "window.h" #include "window.h"
@@ -352,9 +358,63 @@ void Window::SetTimeout(int timeout)
wtimeout(itsWindow, timeout); wtimeout(itsWindow, timeout);
} }
void Window::AddFDCallback(int fd, void (*callback)())
{
itsFDs.push_back(std::make_pair(fd, callback));
}
void Window::ClearFDCallbacksList()
{
itsFDs.clear();
}
bool Window::FDCallbacksListEmpty() const
{
return itsFDs.empty();
}
void Window::ReadKey(int &read_key) const void Window::ReadKey(int &read_key) const
{ {
// in pdcurses polling stdin doesn't work, so we can't poll
// both stdin and other file descriptors in one select. the
// workaround is to set the timeout of select to 0, poll
// other file descriptors and then wait for stdin input with
// the given timeout. unfortunately, this results in delays
// since ncmpcpp doesn't see that data arrived while waiting
// for input from stdin, but it seems there is no better option.
fd_set fdset;
FD_ZERO(&fdset);
# if !defined(USE_PDCURSES)
FD_SET(STDIN_FILENO, &fdset);
timeval timeout = { itsWindowTimeout/1000, (itsWindowTimeout%1000)*1000 };
# else
timeval timeout = { 0, 0 };
# endif
int fd_max = STDIN_FILENO;
for (FDCallbacks::const_iterator it = itsFDs.begin(); it != itsFDs.end(); ++it)
{
if (it->first > fd_max)
fd_max = it->first;
FD_SET(it->first, &fdset);
}
if (select(fd_max+1, &fdset, 0, 0, &timeout) > 0)
{
# if !defined(USE_PDCURSES)
read_key = FD_ISSET(STDIN_FILENO, &fdset) ? wgetch(itsWindow) : ERR;
# endif // !USE_PDCURSES
for (FDCallbacks::const_iterator it = itsFDs.begin(); it != itsFDs.end(); ++it)
if (FD_ISSET(it->first, &fdset))
it->second();
}
# if !defined(USE_PDCURSES)
else
read_key = ERR;
# else
read_key = wgetch(itsWindow); read_key = wgetch(itsWindow);
# endif
} }
void Window::ReadKey() const void Window::ReadKey() const
@@ -437,7 +497,7 @@ std::string Window::GetString(const std::string &base, size_t length, size_t wid
wmove(itsWindow, y, x); wmove(itsWindow, y, x);
prefresh(itsWindow, 0, 0, itsStartY, itsStartX, itsStartY+itsHeight-1, itsStartX+itsWidth-1); prefresh(itsWindow, 0, 0, itsStartY, itsStartX, itsStartY+itsHeight-1, itsStartX+itsWidth-1);
input = wgetch(itsWindow); ReadKey(input);
// these key codes are special and should be ignored // these key codes are special and should be ignored
if ((input < 10 || (input > 10 && input != 21 && input < 32)) if ((input < 10 || (input > 10 && input != 21 && input < 32))

View File

@@ -343,6 +343,23 @@ namespace NCurses
/// ///
virtual void Clear(bool refresh = 1); virtual void Clear(bool refresh = 1);
/// Adds given file descriptor to the list that will be polled in
/// ReadKey() along with stdin and callback that will be invoked
/// when there is data waiting for reading in it
/// @param fd file descriptor
/// @param callback callback
///
void AddFDCallback(int fd, void (*callback)());
/// Clears list of file descriptors and their callbacks
///
void ClearFDCallbacksList();
/// Checks if list of file descriptors is empty
/// @return true if list is empty, false otherwise
///
bool FDCallbacksListEmpty() const;
/// Reads key from standard input and writes it into read_key variable /// Reads key from standard input and writes it into read_key variable
/// @param read_key variable for read key to be written into it /// @param read_key variable for read key to be written into it
/// ///
@@ -553,6 +570,12 @@ namespace NCurses
/// stack of colors /// stack of colors
std::stack<Colors> itsColors; std::stack<Colors> itsColors;
/// containter used for additional file descriptors that have
/// to be polled in ReadKey() and correspondent callbacks that
/// are invoked if there is data available in them
typedef std::vector< std::pair<int, void (*)()> > FDCallbacks;
FDCallbacks itsFDs;
/// pointer to container used as history /// pointer to container used as history
std::deque<std::wstring> *itsHistory; std::deque<std::wstring> *itsHistory;