1 /***************************************************************************
2 * Copyright (C) 2008-2014 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 ***************************************************************************/
26 #include <boost/locale.hpp>
37 #include "configuration.h"
46 #include "statusbar.h"
47 #include "visualizer.h"
49 #include "utility/conversion.h"
53 std::ofstream errorlog
;
54 std::streambuf
*cerr_buffer
;
55 bool run_resize_screen
= false;
58 void sighandler(int sig
)
62 Statusbar::print("SIGPIPE (broken pipe signal) received");
64 else if (sig
== SIGWINCH
)
66 run_resize_screen
= true;
68 # if defined(__sun) && defined(__SVR4)
69 // in solaris it is needed to reinstall the handler each time it's executed
70 signal(sig
, sighandler
);
71 # endif // __sun && __SVR4
77 // restore old cerr buffer
78 std::cerr
.rdbuf(cerr_buffer
);
81 # ifndef USE_PDCURSES // destroying screen somehow crashes pdcurses
83 # endif // USE_PDCURSES
88 int main(int argc
, char **argv
)
90 using Global::myScreen
;
91 using Global::myLockedScreen
;
92 using Global::myInactiveScreen
;
94 using Global::wHeader
;
95 using Global::wFooter
;
97 using Global::VolumeState
;
100 std::srand(std::time(0));
101 std::setlocale(LC_ALL
, "");
102 std::locale::global(Charset::internalLocale());
104 if (!configure(argc
, argv
))
107 // always execute these commands, even if ncmpcpp use exit function
110 // redirect std::cerr output to ~/.ncmpcpp/error.log file
111 errorlog
.open((Config
.ncmpcpp_directory
+ "error.log").c_str(), std::ios::app
);
112 cerr_buffer
= std::cerr
.rdbuf();
113 std::cerr
.rdbuf(errorlog
.rdbuf());
115 NC::initScreen("ncmpcpp ver. " VERSION
, Config
.colors_enabled
);
117 Actions::OriginalStatusbarVisibility
= Config
.statusbar_visibility
;
119 // for column separators
120 attron(COLOR_PAIR(int(Config
.main_color
)));
122 if (Config
.design
== Design::Alternative
)
123 Config
.statusbar_visibility
= 0;
125 Actions::setWindowsDimensions();
126 Actions::validateScreenSize();
127 Actions::initializeScreens();
129 wHeader
= new NC::Window(0, 0, COLS
, Actions::HeaderHeight
, "", Config
.header_color
, NC::Border::None
);
130 if (Config
.header_visibility
|| Config
.design
== Design::Alternative
)
133 wFooter
= new NC::Window(0, Actions::FooterStartY
, COLS
, Actions::FooterHeight
, "", Config
.statusbar_color
, NC::Border::None
);
134 wFooter
->setTimeout(500);
135 wFooter
->setGetStringHelper(Statusbar::Helpers::getString
);
137 // initialize global timer
138 Timer
= boost::posix_time::microsec_clock::local_time();
140 // initialize playlist
141 myPlaylist
->switchTo();
144 Key
input(0, Key::Standard
);
145 auto past
= boost::posix_time::from_time_t(0);
149 if (Config
.mouse_support
)
150 mousemask(ALL_MOUSE_EVENTS
, 0);
153 signal(SIGPIPE
, sighandler
);
154 signal(SIGWINCH
, sighandler
);
157 while (!Actions::ExitMainLoop
)
161 if (!Mpd
.Connected())
163 wFooter
->clearFDCallbacksList();
167 if (Mpd
.Version() < 16)
170 throw MPD::ClientError(MPD_ERROR_STATE
, "MPD < 0.16.0 is not supported", false);
172 wFooter
->addFDCallback(Mpd
.GetFD(), Statusbar::Helpers::mpd
);
173 Status::update(-1); // we need info about new connection
175 if (Config
.jump_to_now_playing_song_at_start
)
177 int curr_pos
= myPlaylist
->currentSongPosition();
179 myPlaylist
->main().highlight(curr_pos
);
182 // go to startup screen
183 if (Config
.startup_screen_type
!= myScreen
->type())
184 toScreen(Config
.startup_screen_type
)->switchTo();
186 myBrowser
->fetchSupportedExtensions();
187 # ifdef ENABLE_OUTPUTS
188 myOutputs
->FetchList();
189 # endif // ENABLE_OUTPUTS
190 # ifdef ENABLE_VISUALIZER
191 myVisualizer
->ResetFD();
192 if (myScreen
== myVisualizer
)
193 myVisualizer
->SetFD();
194 myVisualizer
->FindOutputID();
195 # endif // ENABLE_VISUALIZER
197 Statusbar::printf("Connected to %1%", Mpd
.GetHostname());
199 catch (MPD::ClientError
&e
)
201 Status::handleClientError(e
);
207 if (run_resize_screen
)
209 Actions::resizeScreen(true);
210 run_resize_screen
= false;
214 if ((myScreen
== myPlaylist
|| myScreen
== myBrowser
|| myScreen
== myLyrics
)
215 && (Timer
- past
> boost::posix_time::milliseconds(500))
222 if (input
!= Key::noOp
)
223 myScreen
->refreshWindow();
224 input
= Key::read(*wFooter
);
226 if (input
== Key::noOp
)
231 auto k
= Bindings
.get(input
);
232 std::any_of(k
.first
, k
.second
, boost::bind(&Binding::execute
, _1
));
234 catch (ConversionError
&e
)
236 Statusbar::printf("Couldn't convert value \"%1%\" to target type", e
.value());
238 catch (OutOfBounds
&e
)
240 Statusbar::printf("Error: %1%", e
.errorMessage());
243 if (myScreen
== myPlaylist
)
244 myPlaylist
->EnableHighlighting();
246 # ifdef ENABLE_VISUALIZER
247 // visualizer sets timeout to 40ms, but since only it needs such small
248 // value, we should restore default one after switching to another screen.
249 if (wFooter
->getTimeout() < 500
250 && !(myScreen
== myVisualizer
|| myLockedScreen
== myVisualizer
|| myInactiveScreen
== myVisualizer
)
252 wFooter
->setTimeout(500);
253 # endif // ENABLE_VISUALIZER
255 catch (MPD::ClientError
&e
)
257 Status::handleClientError(e
);
259 catch (MPD::ServerError
&e
)
261 Status::handleServerError(e
);