Move files around a lot
[lsnes.git] / src / core / window.cpp
blob231e6992072a608dd9ea1285305757df4b5cf14a
1 #include "core/command.hpp"
2 #include "core/misc.hpp"
3 #include "core/window.hpp"
5 #include <fstream>
6 #include <boost/iostreams/categories.hpp>
7 #include <boost/iostreams/copy.hpp>
8 #include <boost/iostreams/stream.hpp>
9 #include <boost/iostreams/stream_buffer.hpp>
10 #include <boost/iostreams/filter/symmetric.hpp>
11 #include <boost/iostreams/filter/zlib.hpp>
12 #include <boost/iostreams/filtering_stream.hpp>
13 #include <boost/iostreams/device/back_inserter.hpp>
15 #define MAXMESSAGES 5000
16 #define INIT_WIN_SIZE 6
19 namespace
21 function_ptr_command<> identify_key("show-plugins", "Show plugins in use",
22 "Syntax: show-plugins\nShows plugins in use.\n",
23 []() throw(std::bad_alloc, std::runtime_error) {
24 window::message(std::string("Graphics:\t") + graphics_plugin_name);
25 window::message(std::string("Sound:\t") + sound_plugin_name);
26 window::message(std::string("Joystick:\t") + joystick_plugin_name);
27 });
29 function_ptr_command<const std::string&> enable_sound("enable-sound", "Enable/Disable sound",
30 "Syntax: enable-sound <on/off>\nEnable or disable sound.\n",
31 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
32 std::string s = args;
33 if(s == "on" || s == "true" || s == "1" || s == "enable" || s == "enabled") {
34 if(!window::sound_initialized())
35 throw std::runtime_error("Sound failed to initialize and is disabled");
36 window::sound_enable(true);
37 } else if(s == "off" || s == "false" || s == "0" || s == "disable" || s == "disabled") {
38 if(window::sound_initialized())
39 window::sound_enable(false);
40 } else
41 throw std::runtime_error("Bad sound setting");
42 });
44 function_ptr_command<const std::string&> set_sound_device("set-sound-device", "Set sound device",
45 "Syntax: set-sound-device <id>\nSet sound device to <id>.\n",
46 [](const std::string& args) throw(std::bad_alloc, std::runtime_error) {
47 if(!window::sound_initialized())
48 throw std::runtime_error("Sound failed to initialize and is disabled");
49 window::set_sound_device(args);
50 });
52 function_ptr_command<> get_sound_devices("show-sound-devices", "Show sound devices",
53 "Syntax: show-sound-devices\nShow listing of available sound devices\n",
54 []() throw(std::bad_alloc, std::runtime_error) {
55 if(!window::sound_initialized())
56 throw std::runtime_error("Sound failed to initialize and is disabled");
57 auto r = window::get_sound_devices();
58 auto s = window::get_current_sound_device();
59 std::string dname = "unknown";
60 if(r.count(s))
61 dname = r[s];
62 window::out() << "Detected " << r.size() << " sound output devices."
63 << std::endl;
64 for(auto i : r)
65 window::out() << "Audio device " << i.first << ": " << i.second << std::endl;
66 window::out() << "Currently using device " << window::get_current_sound_device() << " ("
67 << dname << ")" << std::endl;
68 });
70 function_ptr_command<> get_sound_status("show-sound-status", "Show sound status",
71 "Syntax: show-sound-status\nShow current sound status\n",
72 []() throw(std::bad_alloc, std::runtime_error) {
73 window::out() << "Sound plugin: " << sound_plugin_name << std::endl;
74 if(!window::sound_initialized())
75 window::out() << "Sound initialization failed, sound disabled" << std::endl;
76 else {
77 auto r = window::get_sound_devices();
78 auto s = window::get_current_sound_device();
79 std::string dname = "unknown";
80 if(r.count(s))
81 dname = r[s];
82 window::out() << "Current sound device " << s << " (" << dname << ")" << std::endl;
84 });
86 std::map<std::string, std::string> emustatus;
88 class window_output
90 public:
91 typedef char char_type;
92 typedef boost::iostreams::sink_tag category;
93 window_output(window* win)
97 void close()
101 std::streamsize write(const char* s, std::streamsize n)
103 size_t oldsize = stream.size();
104 stream.resize(oldsize + n);
105 memcpy(&stream[oldsize], s, n);
106 while(true) {
107 size_t lf = stream.size();
108 for(size_t i = 0; i < stream.size(); i++)
109 if(stream[i] == '\n') {
110 lf = i;
111 break;
113 if(lf == stream.size())
114 break;
115 std::string foo(stream.begin(), stream.begin() + lf);
116 window::message(foo);
117 if(lf + 1 < stream.size())
118 memmove(&stream[0], &stream[lf + 1], stream.size() - lf - 1);
119 stream.resize(stream.size() - lf - 1);
121 return n;
123 protected:
124 std::vector<char> stream;
127 class msgcallback : public messagebuffer::update_handler
129 public:
130 ~msgcallback() throw() {};
131 void messagebuffer_update() throw(std::bad_alloc, std::runtime_error)
133 window::notify_message();
135 } msg_callback_obj;
137 std::ofstream system_log;
138 window_callback* wcb = NULL;
139 uint32_t vc_xoffset;
140 uint32_t vc_yoffset;
141 uint32_t vc_hscl = 1;
142 uint32_t vc_vscl = 1;
143 bool sounds_enabled = true;
146 std::map<std::string, std::string>& window::get_emustatus() throw()
148 return emustatus;
151 void window::sound_enable(bool enable) throw()
153 _sound_enable(enable);
154 sounds_enabled = enable;
155 window_callback::do_sound_unmute(enable);
158 void window::set_sound_device(const std::string& dev) throw()
160 try {
161 _set_sound_device(dev);
162 } catch(std::exception& e) {
163 out() << "Error changing sound device: " << e.what() << std::endl;
165 try {
166 //After failed change, we don't know what is selected.
167 window_callback::do_sound_change(get_current_sound_device());
168 } catch(...) {
172 bool window::is_sound_enabled() throw()
174 return sounds_enabled;
178 void window::init()
180 msgbuf.register_handler(msg_callback_obj);
181 system_log.open("lsnes.log", std::ios_base::out | std::ios_base::app);
182 time_t curtime = __real_time(NULL);
183 struct tm* tm = localtime(&curtime);
184 char buffer[1024];
185 strftime(buffer, 1023, "%Y-%m-%d %H:%M:%S %Z", tm);
186 system_log << "-----------------------------------------------------------------------" << std::endl;
187 system_log << "lsnes started at " << buffer << std::endl;
188 system_log << "-----------------------------------------------------------------------" << std::endl;
189 graphics_init();
190 sound_init();
191 joystick_init();
194 void window::quit()
196 joystick_quit();
197 sound_quit();
198 graphics_quit();
199 msgbuf.unregister_handler(msg_callback_obj);
200 time_t curtime = __real_time(NULL);
201 struct tm* tm = localtime(&curtime);
202 char buffer[1024];
203 strftime(buffer, 1023, "%Y-%m-%d %H:%M:%S %Z", tm);
204 system_log << "-----------------------------------------------------------------------" << std::endl;
205 system_log << "lsnes shutting down at " << buffer << std::endl;
206 system_log << "-----------------------------------------------------------------------" << std::endl;
207 system_log.close();
210 std::ostream& window::out() throw(std::bad_alloc)
212 static std::ostream* cached = NULL;
213 window* win = NULL;
214 if(!cached)
215 cached = new boost::iostreams::stream<window_output>(win);
216 return *cached;
219 void window::set_window_compensation(uint32_t xoffset, uint32_t yoffset, uint32_t hscl, uint32_t vscl)
221 vc_xoffset = xoffset;
222 vc_yoffset = yoffset;
223 vc_hscl = hscl;
224 vc_vscl = vscl;
227 messagebuffer window::msgbuf(MAXMESSAGES, INIT_WIN_SIZE);
230 void window::message(const std::string& msg) throw(std::bad_alloc)
232 std::string msg2 = msg;
233 while(msg2 != "") {
234 size_t s = msg2.find_first_of("\n");
235 std::string forlog;
236 if(s >= msg2.length()) {
237 msgbuf.add_message(forlog = msg2);
238 if(system_log)
239 system_log << forlog << std::endl;
240 break;
241 } else {
242 msgbuf.add_message(forlog = msg2.substr(0, s));
243 if(system_log)
244 system_log << forlog << std::endl;
245 msg2 = msg2.substr(s + 1);
250 void window::fatal_error() throw()
252 time_t curtime = __real_time(NULL);
253 struct tm* tm = localtime(&curtime);
254 char buffer[1024];
255 strftime(buffer, 1023, "%Y-%m-%d %H:%M:%S %Z", tm);
256 system_log << "-----------------------------------------------------------------------" << std::endl;
257 system_log << "lsnes paniced at " << buffer << std::endl;
258 system_log << "-----------------------------------------------------------------------" << std::endl;
259 system_log.close();
260 fatal_error2();
261 exit(1);
264 namespace
266 static std::set<window_callback*>& wcbs()
268 static std::set<window_callback*> s;
269 return s;
273 window_callback::window_callback() throw()
275 wcbs().insert(this);
278 window_callback::~window_callback() throw()
280 wcbs().erase(this);
283 void window_callback::on_close() throw()
287 void window_callback::on_click(int32_t x, int32_t y, uint32_t buttonmask) throw()
291 void window_callback::on_sound_unmute(bool unmute) throw()
295 void window_callback::on_mode_change(bool readonly) throw()
299 void window_callback::on_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate)
303 void window_callback::on_autohold_reconfigure()
307 void window_callback::on_sound_change(const std::string& dev) throw()
311 void window_callback::do_close() throw()
313 for(auto i : wcbs())
314 i->on_close();
317 void window_callback::do_click(int32_t x, int32_t y, uint32_t buttonmask) throw()
319 x = (x - vc_xoffset) / vc_hscl;
320 y = (y - vc_yoffset) / vc_vscl;
321 for(auto i : wcbs())
322 i->on_click(x, y, buttonmask);
325 void window_callback::do_sound_unmute(bool unmute) throw()
327 for(auto i : wcbs())
328 i->on_sound_unmute(unmute);
331 void window_callback::do_sound_change(const std::string& dev) throw()
333 for(auto i : wcbs())
334 i->on_sound_change(dev);
337 void window_callback::do_mode_change(bool readonly) throw()
339 for(auto i : wcbs())
340 i->on_mode_change(readonly);
343 void window_callback::do_autohold_update(unsigned pid, unsigned ctrlnum, bool newstate)
345 for(auto i : wcbs())
346 i->on_autohold_update(pid, ctrlnum, newstate);
349 void window_callback::do_autohold_reconfigure()
351 for(auto i : wcbs())
352 i->on_autohold_reconfigure();
355 void window_callback::do_setting_change(const std::string& _setting, const std::string& value)
357 for(auto i : wcbs())
358 i->on_setting_change(_setting, value);
361 void window_callback::do_setting_clear(const std::string& _setting)
363 for(auto i : wcbs())
364 i->on_setting_clear(_setting);
367 void window_callback::on_setting_change(const std::string& setting, const std::string& value)
371 void window_callback::on_setting_clear(const std::string& setting)