1 /***************************************************************************
2 * Copyright (C) 2008-2012 by Andrzej Rybczak *
3 * electricityispower@gmail.com *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. *
19 ***************************************************************************/
43 #include "statusbar.h"
44 #include "visualizer.h"
49 std::ofstream errorlog
;
50 std::streambuf
*cerr_buffer
;
53 void sighandler(int signal
)
55 if (signal
== SIGPIPE
)
57 Statusbar::msg("SIGPIPE (broken pipe signal) received");
59 else if (signal
== SIGWINCH
)
61 Action::ResizeScreen(true);
68 // restore old cerr buffer
69 std::cerr
.rdbuf(cerr_buffer
);
72 # ifndef USE_PDCURSES // destroying screen somehow crashes pdcurses
74 # endif // USE_PDCURSES
79 int main(int argc
, char **argv
)
81 using Global::myScreen
;
82 using Global::myOldScreen
;
83 using Global::myPrevScreen
;
84 using Global::myLockedScreen
;
85 using Global::myInactiveScreen
;
87 using Global::wHeader
;
88 using Global::wFooter
;
90 using Global::ShowMessages
;
91 using Global::VolumeState
;
95 setlocale(LC_ALL
, "");
96 std::locale::global(std::locale(""));
98 Config
.CheckForCommandLineConfigFilePath(argv
, argc
);
100 Config
.SetDefaults();
102 Config
.GenerateColumns();
104 if (!Bindings
.read(Config
.ncmpcpp_directory
+ "bindings"))
106 Bindings
.generateDefaults();
108 if (getenv("MPD_HOST"))
109 Mpd
.SetHostname(getenv("MPD_HOST"));
110 if (getenv("MPD_PORT"))
111 Mpd
.SetPort(atoi(getenv("MPD_PORT")));
113 if (Config
.mpd_host
!= "localhost")
114 Mpd
.SetHostname(Config
.mpd_host
);
115 if (Config
.mpd_port
!= 6600)
116 Mpd
.SetPort(Config
.mpd_port
);
118 Mpd
.SetTimeout(Config
.mpd_connection_timeout
);
119 Mpd
.SetIdleEnabled(Config
.enable_idle_notifications
);
122 ParseArgv(argc
, argv
);
124 if (!Action::ConnectToMPD())
127 if (Mpd
.Version() < 16)
129 std::cout
<< "MPD < 0.16.0 is not supported, please upgrade.\n";
133 CreateDir(Config
.ncmpcpp_directory
);
135 // always execute these commands, even if ncmpcpp use exit function
138 // redirect std::cerr output to ~/.ncmpcpp/error.log file
139 errorlog
.open((Config
.ncmpcpp_directory
+ "error.log").c_str(), std::ios::app
);
140 cerr_buffer
= std::cerr
.rdbuf();
141 std::cerr
.rdbuf(errorlog
.rdbuf());
143 NC::initScreen("ncmpcpp ver. " VERSION
, Config
.colors_enabled
);
145 Action::OriginalStatusbarVisibility
= Config
.statusbar_visibility
;
147 if (!Config
.titles_visibility
)
148 wattron(stdscr
, COLOR_PAIR(Config
.main_color
));
150 if (Config
.new_design
)
151 Config
.statusbar_visibility
= 0;
153 Action::SetWindowsDimensions();
154 Action::ValidateScreenSize();
156 wHeader
= new NC::Window(0, 0, COLS
, Action::HeaderHeight
, "", Config
.header_color
, NC::brNone
);
157 if (Config
.header_visibility
|| Config
.new_design
)
160 wFooter
= new NC::Window(0, Action::FooterStartY
, COLS
, Action::FooterHeight
, "", Config
.statusbar_color
, NC::brNone
);
161 wFooter
->setTimeout(500);
162 wFooter
->setGetStringHelper(Statusbar::Helpers::getString
);
163 if (Mpd
.SupportsIdle())
164 wFooter
->addFDCallback(Mpd
.GetFD(), Statusbar::Helpers::mpd
);
165 wFooter
->createHistory();
167 // initialize screens to browser as default previous screen
168 myScreen
= myBrowser
;
169 myPrevScreen
= myBrowser
;
170 myOldScreen
= myBrowser
;
172 // initialize global timer
173 gettimeofday(&Timer
, 0);
176 myPlaylist
->SwitchTo();
177 myPlaylist
->UpdateTimer();
179 // go to startup screen
180 if (Config
.startup_screen
!= myScreen
)
181 Config
.startup_screen
->SwitchTo();
183 Mpd
.SetStatusUpdater(Status::update
, 0);
184 Mpd
.SetErrorHandler(Status::handleError
, 0);
187 Key
input(0, Key::Standard
);
188 timeval past
= { 0, 0 };
189 // local variables end
192 signal(SIGPIPE
, sighandler
);
193 signal(SIGWINCH
, sighandler
);
197 if (Config
.mouse_support
)
198 mousemask(ALL_MOUSE_EVENTS
, 0);
200 Mpd
.OrderDataFetching();
201 if (Config
.jump_to_now_playing_song_at_start
)
204 int curr_pos
= Mpd
.GetCurrentSongPos();
206 myPlaylist
->Items
->highlight(curr_pos
);
209 while (!Action::ExitMainLoop
)
211 if (!Mpd
.Connected())
213 if (!wFooter
->FDCallbacksListEmpty())
214 wFooter
->clearFDCallbacksList();
215 Statusbar::msg("Attempting to reconnect...");
218 Statusbar::msg("Connected to %s", Mpd
.GetHostname().c_str());
219 if (Mpd
.SupportsIdle())
221 wFooter
->addFDCallback(Mpd
.GetFD(), Statusbar::Helpers::mpd
);
222 Mpd
.OrderDataFetching(); // we need info about new connection
224 ShowMessages
= false;
225 # ifdef ENABLE_VISUALIZER
226 myVisualizer
->ResetFD();
227 if (myScreen
== myVisualizer
)
228 myVisualizer
->SetFD();
229 myVisualizer
->FindOutputID();
230 # endif // ENABLE_VISUALIZER
239 if (((Timer
.tv_sec
== past
.tv_sec
&& Timer
.tv_usec
>= past
.tv_usec
+500000) || Timer
.tv_sec
> past
.tv_sec
)
240 && (myScreen
== myPlaylist
|| myScreen
== myBrowser
|| myScreen
== myLyrics
)
249 if (input
!= Key::noOp
)
250 myScreen
->RefreshWindow();
251 input
= Key::read(*wFooter
);
253 if (input
== Key::noOp
)
256 auto k
= Bindings
.get(input
);
257 for (; k
.first
!= k
.second
; ++k
.first
)
259 Binding
&b
= k
.first
->second
;
262 if (b
.action()->Execute())
267 auto chain
= b
.chain();
268 for (auto it
= chain
->begin(); it
!= chain
->end(); ++it
)
269 if (!(*it
)->Execute())
275 if (myScreen
== myPlaylist
)
276 myPlaylist
->EnableHighlighting();
278 # ifdef ENABLE_VISUALIZER
279 // visualizer sets timeout to 40ms, but since only it needs such small
280 // value, we should restore defalt one after switching to another screen.
281 if (wFooter
->getTimeout() < 500
282 && !(myScreen
== myVisualizer
|| myLockedScreen
== myVisualizer
|| myInactiveScreen
== myVisualizer
)
284 wFooter
->setTimeout(500);
285 # endif // ENABLE_VISUALIZER