1 #include "core/command.hpp"
2 #include "core/misc.hpp"
3 #include "core/window.hpp"
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
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
);
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
) {
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);
41 throw std::runtime_error("Bad sound setting");
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
);
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";
62 window::out() << "Detected " << r
.size() << " sound output devices."
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
;
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
;
77 auto r
= window::get_sound_devices();
78 auto s
= window::get_current_sound_device();
79 std::string dname
= "unknown";
82 window::out() << "Current sound device " << s
<< " (" << dname
<< ")" << std::endl
;
86 std::map
<std::string
, std::string
> emustatus
;
91 typedef char char_type
;
92 typedef boost::iostreams::sink_tag category
;
93 window_output(window
* win
)
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
);
107 size_t lf
= stream
.size();
108 for(size_t i
= 0; i
< stream
.size(); i
++)
109 if(stream
[i
] == '\n') {
113 if(lf
== stream
.size())
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);
124 std::vector
<char> stream
;
127 class msgcallback
: public messagebuffer::update_handler
130 ~msgcallback() throw() {};
131 void messagebuffer_update() throw(std::bad_alloc
, std::runtime_error
)
133 window::notify_message();
137 std::ofstream system_log
;
138 window_callback
* wcb
= NULL
;
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()
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()
161 _set_sound_device(dev
);
162 } catch(std::exception
& e
) {
163 out() << "Error changing sound device: " << e
.what() << std::endl
;
166 //After failed change, we don't know what is selected.
167 window_callback::do_sound_change(get_current_sound_device());
172 bool window::is_sound_enabled() throw()
174 return sounds_enabled
;
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
);
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
;
199 msgbuf
.unregister_handler(msg_callback_obj
);
200 time_t curtime
= __real_time(NULL
);
201 struct tm
* tm
= localtime(&curtime
);
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
;
210 std::ostream
& window::out() throw(std::bad_alloc
)
212 static std::ostream
* cached
= NULL
;
215 cached
= new boost::iostreams::stream
<window_output
>(win
);
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
;
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
;
234 size_t s
= msg2
.find_first_of("\n");
236 if(s
>= msg2
.length()) {
237 msgbuf
.add_message(forlog
= msg2
);
239 system_log
<< forlog
<< std::endl
;
242 msgbuf
.add_message(forlog
= msg2
.substr(0, s
));
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
);
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
;
266 static std::set
<window_callback
*>& wcbs()
268 static std::set
<window_callback
*> s
;
273 window_callback::window_callback() throw()
278 window_callback::~window_callback() throw()
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()
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
;
322 i
->on_click(x
, y
, buttonmask
);
325 void window_callback::do_sound_unmute(bool unmute
) throw()
328 i
->on_sound_unmute(unmute
);
331 void window_callback::do_sound_change(const std::string
& dev
) throw()
334 i
->on_sound_change(dev
);
337 void window_callback::do_mode_change(bool readonly
) throw()
340 i
->on_mode_change(readonly
);
343 void window_callback::do_autohold_update(unsigned pid
, unsigned ctrlnum
, bool newstate
)
346 i
->on_autohold_update(pid
, ctrlnum
, newstate
);
349 void window_callback::do_autohold_reconfigure()
352 i
->on_autohold_reconfigure();
355 void window_callback::do_setting_change(const std::string
& _setting
, const std::string
& value
)
358 i
->on_setting_change(_setting
, value
);
361 void window_callback::do_setting_clear(const std::string
& _setting
)
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
)