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->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);

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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;
}

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->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<std::string, SearchConstraints> >(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<Song>(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);

View File

@@ -38,7 +38,6 @@ void SelectedItemsAdder::Init()
{
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->SetTimeout(ncmpcpp_window_timeout);
w->CyclicScrolling(Config.use_cyclic_scrolling);
w->HighlightColor(Config.main_highlight_color);
w->SetItemDisplayer(Display::Generic);

View File

@@ -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);
// 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
#define _MPDPP_H
#ifdef WIN32
# include <winsock.h>
#else
# include <sys/select.h>
#endif
#include <vector>
#include <mpd/client.h>
@@ -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;

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->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<size_t> 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<size_t> 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<size_t> 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<size_t> 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;

View File

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

View File

@@ -32,7 +32,6 @@ Outputs *myOutputs = new Outputs;
void Outputs::Init()
{
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->HighlightColor(Config.main_highlight_color);
w->SetItemDisplayer(Display::Pairs);

View File

@@ -47,7 +47,6 @@ Menu< std::pair<std::string, MPD::Song::GetFunction> > *Playlist::SortDialog = 0
void Playlist::Init()
{
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->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<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->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->HighlightColor(Config.active_column_color);
Playlists->SetTimeout(ncmpcpp_window_timeout);
Playlists->CyclicScrolling(Config.use_cyclic_scrolling);
Playlists->SetItemDisplayer(Display::Generic);
Content = new Menu<Song>(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);

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->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);

View File

@@ -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);

View File

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

View File

@@ -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 &);

View File

@@ -68,14 +68,12 @@ void TagEditor::Init()
Albums = new Menu<string_pair>(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<string_pair>(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<std::string>(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<MPD::Song>(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<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->SetItemDisplayer(Display::Generic);
FParserDialog->AddOption("Get tags from filename");
@@ -130,15 +125,12 @@ void TagEditor::Init()
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->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;

View File

@@ -48,7 +48,6 @@ void TinyTagEditor::Init()
{
w = new Menu<Buffer>(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;

View File

@@ -21,6 +21,12 @@
#include <cstring>
#include <cstdlib>
#ifdef WIN32
# include <winsock.h>
#else
# include <sys/select.h>
#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))

View File

@@ -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<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
std::deque<std::wstring> *itsHistory;