diff --git a/src/browser.cpp b/src/browser.cpp index 08637288..989f4dee 100644 --- a/src/browser.cpp +++ b/src/browser.cpp @@ -53,7 +53,6 @@ void Browser::Init() { w = new Menu(0, MainStartY, COLS, MainHeight, Config.columns_in_browser ? Display::Columns() : "", Config.main_color, brNone); w->HighlightColor(Config.main_highlight_color); - w->SetTimeout(ncmpcpp_window_timeout); w->CyclicScrolling(Config.use_cyclic_scrolling); w->SetSelectPrefix(&Config.selected_item_prefix); w->SetSelectSuffix(&Config.selected_item_suffix); diff --git a/src/clock.cpp b/src/clock.cpp index cf620a43..528ebdd0 100644 --- a/src/clock.cpp +++ b/src/clock.cpp @@ -52,7 +52,6 @@ void Clock::Init() 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->SetTimeout(ncmpcpp_window_timeout); isInitialized = 1; } diff --git a/src/help.cpp b/src/help.cpp index 31be68bf..64813a8f 100644 --- a/src/help.cpp +++ b/src/help.cpp @@ -32,7 +32,6 @@ Help *myHelp = new Help; void Help::Init() { w = new Scrollpad(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone); - w->SetTimeout(ncmpcpp_window_timeout); GetKeybindings(); w->Flush(); isInitialized = 1; diff --git a/src/info.cpp b/src/info.cpp index b0a47918..0c435c26 100644 --- a/src/info.cpp +++ b/src/info.cpp @@ -73,7 +73,6 @@ const Info::Metadata Info::Tags[] = void Info::Init() { w = new Scrollpad(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone); - w->SetTimeout(ncmpcpp_window_timeout); isInitialized = 1; } diff --git a/src/lyrics.cpp b/src/lyrics.cpp index dfe983f1..cfb300bc 100644 --- a/src/lyrics.cpp +++ b/src/lyrics.cpp @@ -69,7 +69,6 @@ Lyrics *myLyrics = new Lyrics; void Lyrics::Init() { w = new Scrollpad(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone); - w->SetTimeout(ncmpcpp_window_timeout); isInitialized = 1; } diff --git a/src/media_library.cpp b/src/media_library.cpp index e9a8cfce..14e053f1 100644 --- a/src/media_library.cpp +++ b/src/media_library.cpp @@ -52,20 +52,17 @@ void MediaLibrary::Init() Artists = new Menu(0, MainStartY, itsLeftColWidth, MainHeight, IntoStr(Config.media_lib_primary_tag) + "s", Config.main_color, brNone); Artists->HighlightColor(Config.active_column_color); - Artists->SetTimeout(ncmpcpp_window_timeout); Artists->CyclicScrolling(Config.use_cyclic_scrolling); Artists->SetItemDisplayer(Display::Generic); Albums = new Menu< std::pair >(itsMiddleColStartX, MainStartY, itsMiddleColWidth, MainHeight, "Albums", Config.main_color, brNone); Albums->HighlightColor(Config.main_highlight_color); - Albums->SetTimeout(ncmpcpp_window_timeout); Albums->CyclicScrolling(Config.use_cyclic_scrolling); Albums->SetItemDisplayer(Display::Pairs); Albums->SetGetStringFunction(StringPairToString); Songs = new Menu(itsRightColStartX, MainStartY, itsRightColWidth, MainHeight, "Songs", Config.main_color, brNone); Songs->HighlightColor(Config.main_highlight_color); - Songs->SetTimeout(ncmpcpp_window_timeout); Songs->CyclicScrolling(Config.use_cyclic_scrolling); Songs->SetSelectPrefix(&Config.selected_item_prefix); Songs->SetSelectSuffix(&Config.selected_item_suffix); diff --git a/src/misc.cpp b/src/misc.cpp index 80f7f974..fbe4c7e9 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -38,7 +38,6 @@ void SelectedItemsAdder::Init() { SetDimensions(); w = new Menu((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->HighlightColor(Config.main_highlight_color); w->SetItemDisplayer(Display::Generic); diff --git a/src/mpdpp.cpp b/src/mpdpp.cpp index fe091d5b..7ed7818a 100644 --- a/src/mpdpp.cpp +++ b/src/mpdpp.cpp @@ -151,14 +151,14 @@ void Connection::GoIdle() isIdle = 1; } -mpd_idle Connection::GoBusy() +int Connection::GoBusy() { if (isIdle && mpd_send_noidle(itsConnection)) { isIdle = 0; return mpd_recv_idle(itsConnection, 1); } - return mpd_idle(0); + return 0; } void Connection::UpdateStatus() @@ -166,13 +166,14 @@ void Connection::UpdateStatus() if (!itsConnection) return; + int idle_mask = 0; if (isIdle) { - FD_ZERO(&itsPoll); - FD_SET(itsFD, &itsPoll); - timeval timeout = { 0, 0 }; - if (select(itsFD+1, &itsPoll, 0, 0, &timeout) == 1) - GoBusy(); + if (hasData) + { + idle_mask = GoBusy(); + hasData = 0; + } else { // count local elapsed time as we don't receive @@ -217,14 +218,6 @@ void Connection::UpdateStatus() { // sync local elapsed time counter with mpd 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]); } else @@ -274,7 +267,12 @@ void Connection::UpdateStatus() itsChanges.StatusFlags = itsChanges.Repeat || itsChanges.Random || itsChanges.Single || itsChanges.Consume || itsChanges.Crossfade || itsChanges.DBUpdating; } 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(); } } diff --git a/src/mpdpp.h b/src/mpdpp.h index fc587590..9b72b67a 100644 --- a/src/mpdpp.h +++ b/src/mpdpp.h @@ -21,12 +21,6 @@ #ifndef _MPDPP_H #define _MPDPP_H -#ifdef WIN32 -# include -#else -# include -#endif - #include #include @@ -98,7 +92,10 @@ namespace MPD int GetPort() { return itsPort; } float Version() const; + bool SupportsIdle() const { return supportsIdle; } + void OrderDataFetching() { hasData = 1; } + int GetFD() const { return itsFD; } void SetHostname(const std::string &); void SetPort(int port) { itsPort = port; } @@ -213,7 +210,7 @@ namespace MPD private: void GoIdle(); - mpd_idle GoBusy(); + int GoBusy(); int CheckForErrors(); @@ -224,10 +221,10 @@ namespace MPD int itsErrorCode; size_t itsMaxPlaylistLength; - fd_set itsPoll; int itsFD; bool isIdle; bool supportsIdle; + bool hasData; std::string itsHost; int itsPort; diff --git a/src/ncmpcpp.cpp b/src/ncmpcpp.cpp index 0801a0ea..a9a8faf8 100644 --- a/src/ncmpcpp.cpp +++ b/src/ncmpcpp.cpp @@ -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->SetTimeout(ncmpcpp_window_timeout); wFooter->SetGetStringHelper(StatusbarGetStringHelper); + wFooter->AddFDCallback(Mpd.GetFD(), StatusbarMPDCallback); wFooter->CreateHistory(); myPlaylist->SwitchTo(); @@ -201,10 +202,13 @@ int main(int argc, char *argv[]) { if (!Mpd.Connected()) { + if (!wFooter->FDCallbacksListEmpty()) + wFooter->ClearFDCallbacksList(); ShowMessage("Attempting to reconnect..."); if (Mpd.Connect()) { ShowMessage("Connected to %s!", Mpd.GetHostname().c_str()); + wFooter->AddFDCallback(Mpd.GetFD(), StatusbarMPDCallback); MessagesAllowed = 0; UpdateStatusImmediately = 1; # ifdef ENABLE_OUTPUTS @@ -289,7 +293,7 @@ int main(int argc, char *argv[]) myScreen->Update(); if (input != ERR) myScreen->RefreshWindow(); - myScreen->ReadKey(input); + wFooter->ReadKey(input); if (input == ERR) continue; @@ -567,7 +571,7 @@ int main(int argc, char *argv[]) else { Playlist::BlockNowPlayingUpdate = 1; - myPlaylist->Items->SetTimeout(50); + wFooter->SetTimeout(50); int del_counter = 0; while (!myPlaylist->Items->Empty() && Keypressed(input, Key.Delete)) { @@ -581,11 +585,11 @@ int main(int argc, char *argv[]) Mpd.DeleteID(myPlaylist->CurrentSong()->GetID()); myPlaylist->Items->DeleteOption(id); myPlaylist->Items->Refresh(); - myPlaylist->Items->ReadKey(input); + wFooter->ReadKey(input); ++del_counter; } myPlaylist->FixPositions(myPlaylist->Items->Choice()); - myPlaylist->Items->SetTimeout(ncmpcpp_window_timeout); + wFooter->SetTimeout(ncmpcpp_window_timeout); Playlist::BlockNowPlayingUpdate = 0; } } @@ -703,7 +707,7 @@ int main(int argc, char *argv[]) } else { - myPlaylistEditor->Content->SetTimeout(50); + wFooter->SetTimeout(50); locale_to_utf(myPlaylistEditor->Playlists->Current()); 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()); myPlaylistEditor->Content->DeleteOption(myPlaylistEditor->Content->Choice()); myPlaylistEditor->Content->Refresh(); - myPlaylistEditor->Content->ReadKey(input); + wFooter->ReadKey(input); } 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()) { CHECK_PLAYLIST_FOR_FILTERING; - myPlaylist->Items->SetTimeout(50); + wFooter->SetTimeout(50); if (myPlaylist->Items->hasSelected()) { std::vector list; @@ -848,7 +852,7 @@ int main(int argc, char *argv[]) } myPlaylist->Items->Highlight(list[(list.size()-1)/2]); myPlaylist->Items->Refresh(); - myPlaylist->Items->ReadKey(input); + wFooter->ReadKey(input); } Playlist::BlockNowPlayingUpdate = 0; Mpd.StartCommandsList(); @@ -876,17 +880,17 @@ int main(int argc, char *argv[]) myPlaylist->Items->Swap(to, to+1); myPlaylist->Items->Scroll(wUp); myPlaylist->Items->Refresh(); - myPlaylist->Items->ReadKey(input); + wFooter->ReadKey(input); } Mpd.Move(from, to); Playlist::BlockNowPlayingUpdate = 0; UpdateStatusImmediately = 1; } - myPlaylist->Items->SetTimeout(ncmpcpp_window_timeout); + wFooter->SetTimeout(ncmpcpp_window_timeout); } else if (myScreen->ActiveWindow() == myPlaylistEditor->Content && !myPlaylistEditor->Content->Empty()) { - myPlaylistEditor->Content->SetTimeout(50); + wFooter->SetTimeout(50); if (myPlaylistEditor->Content->hasSelected()) { std::vector list; @@ -905,7 +909,7 @@ int main(int argc, char *argv[]) } myPlaylistEditor->Content->Highlight(list[(list.size()-1)/2]); myPlaylistEditor->Content->Refresh(); - myPlaylistEditor->Content->ReadKey(input); + wFooter->ReadKey(input); } Mpd.StartCommandsList(); 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->Scroll(wUp); myPlaylistEditor->Content->Refresh(); - myPlaylistEditor->Content->ReadKey(input); + wFooter->ReadKey(input); } if (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)) @@ -940,7 +944,7 @@ int main(int argc, char *argv[]) else if (myScreen == myPlaylist && !myPlaylist->Items->Empty()) { CHECK_PLAYLIST_FOR_FILTERING; - myPlaylist->Items->SetTimeout(50); + wFooter->SetTimeout(50); if (myPlaylist->Items->hasSelected()) { std::vector list; @@ -974,7 +978,7 @@ int main(int argc, char *argv[]) } myPlaylist->Items->Highlight(list[(list.size()-1)/2]); myPlaylist->Items->Refresh(); - myPlaylist->Items->ReadKey(input); + wFooter->ReadKey(input); } Playlist::BlockNowPlayingUpdate = 0; Mpd.StartCommandsList(); @@ -1002,18 +1006,18 @@ int main(int argc, char *argv[]) myPlaylist->Items->Swap(to, to-1); myPlaylist->Items->Scroll(wDown); myPlaylist->Items->Refresh(); - myPlaylist->Items->ReadKey(input); + wFooter->ReadKey(input); } Mpd.Move(from, to); Playlist::BlockNowPlayingUpdate = 0; UpdateStatusImmediately = 1; } - myPlaylist->Items->SetTimeout(ncmpcpp_window_timeout); + wFooter->SetTimeout(ncmpcpp_window_timeout); } else if (myScreen->ActiveWindow() == myPlaylistEditor->Content && !myPlaylistEditor->Content->Empty()) { - myPlaylistEditor->Content->SetTimeout(50); + wFooter->SetTimeout(50); if (myPlaylistEditor->Content->hasSelected()) { std::vector list; @@ -1032,7 +1036,7 @@ int main(int argc, char *argv[]) } myPlaylistEditor->Content->Highlight(list[(list.size()-1)/2]); myPlaylistEditor->Content->Refresh(); - myPlaylistEditor->Content->ReadKey(input); + wFooter->ReadKey(input); } Mpd.StartCommandsList(); 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->Scroll(wDown); myPlaylistEditor->Content->Refresh(); - myPlaylistEditor->Content->ReadKey(input); + wFooter->ReadKey(input); } if (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) @@ -1148,7 +1152,7 @@ int main(int argc, char *argv[]) { TraceMpdStatus(); myPlaylist->UpdateTimer(); - myPlaylist->Items->ReadKey(input); + wFooter->ReadKey(input); int howmuch = Config.incremental_seeking ? (myPlaylist->Timer()-t)/2+Config.seek_time : Config.seek_time; diff --git a/src/ncmpcpp.h b/src/ncmpcpp.h index affd75f0..8c928ab7 100644 --- a/src/ncmpcpp.h +++ b/src/ncmpcpp.h @@ -37,7 +37,7 @@ using namespace NCurses; typedef std::pair string_pair; -const int ncmpcpp_window_timeout = 100; +const int ncmpcpp_window_timeout = 500; #endif diff --git a/src/outputs.cpp b/src/outputs.cpp index eca0246f..bef53feb 100644 --- a/src/outputs.cpp +++ b/src/outputs.cpp @@ -32,7 +32,6 @@ Outputs *myOutputs = new Outputs; void Outputs::Init() { w = new Menu(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone); - w->SetTimeout(ncmpcpp_window_timeout); w->CyclicScrolling(Config.use_cyclic_scrolling); w->HighlightColor(Config.main_highlight_color); w->SetItemDisplayer(Display::Pairs); diff --git a/src/playlist.cpp b/src/playlist.cpp index 06bf16df..367ac9c5 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -47,7 +47,6 @@ Menu< std::pair > *Playlist::SortDialog = 0 void Playlist::Init() { Items = new Menu(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->HighlightColor(Config.main_highlight_color); Items->SetSelectPrefix(&Config.selected_item_prefix); @@ -62,7 +61,6 @@ void Playlist::Init() SortDialogHeight = std::min(int(MainHeight), 18); SortDialog = new Menu< std::pair >((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->SetItemDisplayer(Display::Pairs); diff --git a/src/playlist_editor.cpp b/src/playlist_editor.cpp index f7325601..581b4757 100644 --- a/src/playlist_editor.cpp +++ b/src/playlist_editor.cpp @@ -47,13 +47,11 @@ void PlaylistEditor::Init() Playlists = new Menu(0, MainStartY, LeftColumnWidth, MainHeight, "Playlists", Config.main_color, brNone); Playlists->HighlightColor(Config.active_column_color); - Playlists->SetTimeout(ncmpcpp_window_timeout); Playlists->CyclicScrolling(Config.use_cyclic_scrolling); Playlists->SetItemDisplayer(Display::Generic); Content = new Menu(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, "Playlist's content", Config.main_color, brNone); Content->HighlightColor(Config.main_highlight_color); - Content->SetTimeout(ncmpcpp_window_timeout); Content->CyclicScrolling(Config.use_cyclic_scrolling); Content->SetSelectPrefix(&Config.selected_item_prefix); Content->SetSelectSuffix(&Config.selected_item_suffix); diff --git a/src/search_engine.cpp b/src/search_engine.cpp index 2b79c1b4..9f534f7f 100644 --- a/src/search_engine.cpp +++ b/src/search_engine.cpp @@ -61,7 +61,6 @@ void SearchEngine::Init() { w = new Menu< std::pair >(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone); w->HighlightColor(Config.main_highlight_color); - w->SetTimeout(ncmpcpp_window_timeout); w->CyclicScrolling(Config.use_cyclic_scrolling); w->SetItemDisplayer(Display::SearchEngine); w->SetSelectPrefix(&Config.selected_item_prefix); diff --git a/src/server_info.cpp b/src/server_info.cpp index cf5e51d9..f4818402 100644 --- a/src/server_info.cpp +++ b/src/server_info.cpp @@ -34,7 +34,6 @@ void ServerInfo::Init() { SetDimensions(); 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.GetTagTypes(itsTagTypes); diff --git a/src/status.cpp b/src/status.cpp index 788ea1d7..dfbd7861 100644 --- a/src/status.cpp +++ b/src/status.cpp @@ -63,6 +63,11 @@ void WindowTitle(const std::string &status) } #endif // !USE_PDCURSES +void StatusbarMPDCallback() +{ + Mpd.OrderDataFetching(); +} + void StatusbarGetStringHelper(const std::wstring &) { TraceMpdStatus(); diff --git a/src/status.h b/src/status.h index acf3ea5c..681aa79a 100644 --- a/src/status.h +++ b/src/status.h @@ -44,6 +44,7 @@ Window &Statusbar(); void DrawProgressbar(unsigned elapsed, unsigned time); void ShowMessage(const char *, ...) GNUC_PRINTF(1, 2); +void StatusbarMPDCallback(); void StatusbarGetStringHelper(const std::wstring &); void StatusbarApplyFilterImmediately(const std::wstring &); diff --git a/src/tag_editor.cpp b/src/tag_editor.cpp index 0ab6c251..34e7a302 100644 --- a/src/tag_editor.cpp +++ b/src/tag_editor.cpp @@ -68,14 +68,12 @@ void TagEditor::Init() Albums = new Menu(0, MainStartY, LeftColumnWidth, MainHeight, "Albums", Config.main_color, brNone); Albums->HighlightColor(Config.active_column_color); - Albums->SetTimeout(ncmpcpp_window_timeout); Albums->CyclicScrolling(Config.use_cyclic_scrolling); Albums->SetItemDisplayer(Display::Pairs); Albums->SetGetStringFunction(StringPairToString); Dirs = new Menu(0, MainStartY, LeftColumnWidth, MainHeight, "Directories", Config.main_color, brNone); Dirs->HighlightColor(Config.active_column_color); - Dirs->SetTimeout(ncmpcpp_window_timeout); Dirs->CyclicScrolling(Config.use_cyclic_scrolling); Dirs->SetItemDisplayer(Display::Pairs); Dirs->SetGetStringFunction(StringPairToString); @@ -84,7 +82,6 @@ void TagEditor::Init() TagTypes = new Menu(MiddleColumnStartX, MainStartY, MiddleColumnWidth, MainHeight, "Tag types", Config.main_color, brNone); TagTypes->HighlightColor(Config.main_highlight_color); - TagTypes->SetTimeout(ncmpcpp_window_timeout); TagTypes->CyclicScrolling(Config.use_cyclic_scrolling); TagTypes->SetItemDisplayer(Display::Generic); @@ -111,7 +108,6 @@ void TagEditor::Init() Tags = new Menu(RightColumnStartX, MainStartY, RightColumnWidth, MainHeight, "Tags", Config.main_color, brNone); Tags->HighlightColor(Config.main_highlight_color); - Tags->SetTimeout(ncmpcpp_window_timeout); Tags->CyclicScrolling(Config.use_cyclic_scrolling); Tags->SetSelectPrefix(&Config.selected_item_prefix); Tags->SetSelectSuffix(&Config.selected_item_suffix); @@ -121,7 +117,6 @@ void TagEditor::Init() Tags->SetGetStringFunctionUserData(TagTypes); FParserDialog = new Menu((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->SetItemDisplayer(Display::Generic); FParserDialog->AddOption("Get tags from filename"); @@ -130,15 +125,12 @@ void TagEditor::Init() FParserDialog->AddOption("Cancel"); FParser = new Menu((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->SetItemDisplayer(Display::Generic); 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->SetTimeout(ncmpcpp_window_timeout); w = LeftColumn; isInitialized = 1; diff --git a/src/tiny_tag_editor.cpp b/src/tiny_tag_editor.cpp index 9fc4031b..41feaaed 100644 --- a/src/tiny_tag_editor.cpp +++ b/src/tiny_tag_editor.cpp @@ -48,7 +48,6 @@ void TinyTagEditor::Init() { w = new Menu(0, MainStartY, COLS, MainHeight, "", Config.main_color, brNone); w->HighlightColor(Config.main_highlight_color); - w->SetTimeout(ncmpcpp_window_timeout); w->CyclicScrolling(Config.use_cyclic_scrolling); w->SetItemDisplayer(Display::Generic); isInitialized = 1; diff --git a/src/window.cpp b/src/window.cpp index 23963988..8fd0beaa 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -21,6 +21,12 @@ #include #include +#ifdef WIN32 +# include +#else +# include +#endif + #include "error.h" #include "window.h" @@ -352,9 +358,63 @@ void Window::SetTimeout(int 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 { + // 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); +# endif } 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); 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 if ((input < 10 || (input > 10 && input != 21 && input < 32)) diff --git a/src/window.h b/src/window.h index 90c20c00..59ecd014 100644 --- a/src/window.h +++ b/src/window.h @@ -343,6 +343,23 @@ namespace NCurses /// 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 /// @param read_key variable for read key to be written into it /// @@ -553,6 +570,12 @@ namespace NCurses /// stack of colors std::stack 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 > FDCallbacks; + FDCallbacks itsFDs; + /// pointer to container used as history std::deque *itsHistory;