1 #include "core/dispatch.hpp"
2 #include "core/globalwrap.hpp"
3 #include "core/misc.hpp"
9 #define START_EH_BLOCK try {
10 #define END_EH_BLOCK(obj, call) } catch(std::bad_alloc& e) { \
12 } catch(std::exception& e) { \
13 messages << "[dumper " << obj->get_name() << "] Warning: " call ": " << e.what() \
16 messages << "[dumper " << obj->get_name() << "] Warning: " call ": Error code #" << code \
20 gameinfo_struct::gameinfo_struct() throw(std::bad_alloc
)
26 std::string
gameinfo_struct::get_readable_time(unsigned digits
) const throw(std::bad_alloc
)
28 double bias
= 0.5 * pow(10, -static_cast<int>(digits
));
29 double len
= length
+ bias
;
30 std::ostringstream str
;
32 double hours
= floor(len
/ 3600);
36 double minutes
= floor(len
/ 60);
38 double seconds
= floor(len
);
40 str
<< std::setw(2) << std::setfill('0') << minutes
<< ":" << seconds
;
45 str
<< '0' + static_cast<int>(len
);
51 size_t gameinfo_struct::get_author_count() const throw()
53 return authors
.size();
56 std::string
gameinfo_struct::get_author_short(size_t idx
) const throw(std::bad_alloc
)
58 if(idx
>= authors
.size())
60 const std::pair
<std::string
, std::string
>& x
= authors
[idx
];
67 uint64_t gameinfo_struct::get_rerecords() const throw()
70 uint64_t max
= 0xFFFFFFFFFFFFFFFFULL
;
71 for(size_t i
= 0; i
< rerecords
.length(); i
++) {
73 //No risk of overflow.
74 v
= v
* 10 + static_cast<unsigned>(rerecords
[i
] - '0');
75 else if(v
== max
/ 10) {
78 if(v
+ static_cast<unsigned>(rerecords
[i
] - '0') < v
)
80 v
= v
+ static_cast<unsigned>(rerecords
[i
] - '0');
90 globalwrap
<std::list
<information_dispatch
*>> dispatch
;
91 globalwrap
<std::list
<information_dispatch
*>> dispatch_audio
;
92 uint32_t srate_n
= 32000;
94 struct gameinfo_struct sgi
;
95 information_dispatch
* exclusive_key
= NULL
;
96 int32_t vc_xoffset
= 0;
97 int32_t vc_yoffset
= 0;
100 bool recursive
= false;
103 information_dispatch::information_dispatch(const std::string
& name
) throw(std::bad_alloc
)
106 dispatch().push_back(this);
107 known_if_dumper
= false;
108 marked_as_dumper
= false;
109 notified_as_dumper
= false;
110 grabbing_keys
= false;
113 information_dispatch::~information_dispatch() throw()
115 for(auto i
= dispatch().begin(); i
!= dispatch().end(); ++i
) {
121 for(auto i
= dispatch_audio().begin(); i
!= dispatch_audio().end(); ++i
) {
123 dispatch_audio().erase(i
);
127 if(notified_as_dumper
)
128 for(auto& i
: dispatch()) {
130 i
->on_destroy_dumper(target_name
);
131 END_EH_BLOCK(i
, "on_destroy_dumper");
135 void information_dispatch::on_close()
140 void information_dispatch::do_close() throw()
142 for(auto& i
: dispatch()) {
145 END_EH_BLOCK(i
, "on_close");
149 void information_dispatch::on_sound_unmute(bool unmuted
)
154 void information_dispatch::do_sound_unmute(bool unmuted
) throw()
156 for(auto& i
: dispatch()) {
158 i
->on_sound_unmute(unmuted
);
159 END_EH_BLOCK(i
, "on_sound_unmute");
163 void information_dispatch::on_sound_change(const std::string
& dev
)
168 void information_dispatch::do_sound_change(const std::string
& dev
) throw()
170 for(auto& i
: dispatch()) {
172 i
->on_sound_change(dev
);
173 END_EH_BLOCK(i
, "on_sound_change");
177 void information_dispatch::on_mode_change(bool readonly
)
182 void information_dispatch::do_mode_change(bool readonly
) throw()
184 for(auto& i
: dispatch()) {
186 i
->on_mode_change(readonly
);
187 END_EH_BLOCK(i
, "on_mode_change");
191 void information_dispatch::on_autohold_update(unsigned pid
, unsigned ctrlnum
, bool newstate
)
196 void information_dispatch::do_autohold_update(unsigned pid
, unsigned ctrlnum
, bool newstate
) throw()
198 for(auto& i
: dispatch()) {
200 i
->on_autohold_update(pid
, ctrlnum
, newstate
);
201 END_EH_BLOCK(i
, "on_autohold_update");
205 void information_dispatch::on_autohold_reconfigure()
210 void information_dispatch::do_autohold_reconfigure() throw()
212 for(auto& i
: dispatch()) {
214 i
->on_autohold_reconfigure();
215 END_EH_BLOCK(i
, "on_autohold_reconfigure");
219 void information_dispatch::on_setting_change(const std::string
& setting
, const std::string
& value
)
224 void information_dispatch::do_setting_change(const std::string
& setting
, const std::string
& value
) throw()
226 for(auto& i
: dispatch()) {
228 i
->on_setting_change(setting
, value
);
229 END_EH_BLOCK(i
, "on_setting_change");
233 void information_dispatch::on_setting_clear(const std::string
& setting
)
238 void information_dispatch::do_setting_clear(const std::string
& setting
) throw()
240 for(auto& i
: dispatch()) {
242 i
->on_setting_clear(setting
);
243 END_EH_BLOCK(i
, "on_setting_clear");
248 void information_dispatch::on_raw_frame(const uint32_t* raw
, bool hires
, bool interlaced
, bool overscan
,
254 void information_dispatch::do_raw_frame(const uint32_t* raw
, bool hires
, bool interlaced
, bool overscan
,
255 unsigned region
) throw()
258 for(auto& i
: dispatch()) {
260 i
->on_raw_frame(raw
, hires
, interlaced
, overscan
, region
);
261 END_EH_BLOCK(i
, "on_raw_frame");
265 void information_dispatch::on_frame(struct framebuffer_raw
& _frame
, uint32_t fps_n
, uint32_t fps_d
)
270 void information_dispatch::do_frame(struct framebuffer_raw
& _frame
, uint32_t fps_n
, uint32_t fps_d
) throw()
273 for(auto& i
: dispatch()) {
275 i
->on_frame(_frame
, fps_n
, fps_d
);
276 END_EH_BLOCK(i
, "on_frame");
280 void information_dispatch::on_sample(short l
, short r
)
285 void information_dispatch::do_sample(short l
, short r
) throw()
288 for(auto& i
: dispatch_audio()) {
291 END_EH_BLOCK(i
, "on_sample");
295 void information_dispatch::on_dump_end()
300 void information_dispatch::do_dump_end() throw()
303 for(auto& i
: dispatch()) {
306 END_EH_BLOCK(i
, "on_dump_end");
310 void information_dispatch::on_sound_rate(uint32_t rate_n
, uint32_t rate_d
)
312 if(!known_if_dumper
) {
313 marked_as_dumper
= get_dumper_flag();
314 known_if_dumper
= true;
316 if(marked_as_dumper
) {
317 messages
<< "[dumper " << get_name() << "] Warning: Sound sample rate changing not supported!"
322 void information_dispatch::do_sound_rate(uint32_t rate_n
, uint32_t rate_d
) throw()
325 uint32_t g
= gcd(rate_n
, rate_d
);
328 if(rate_n
== srate_n
&& rate_d
== srate_d
)
332 for(auto& i
: dispatch()) {
334 i
->on_sound_rate(rate_n
, rate_d
);
335 END_EH_BLOCK(i
, "on_sound_rate");
339 std::pair
<uint32_t, uint32_t> information_dispatch::get_sound_rate() throw()
341 return std::make_pair(srate_n
, srate_d
);
344 void information_dispatch::on_gameinfo(const struct gameinfo_struct
& gi
)
349 void information_dispatch::do_gameinfo(const struct gameinfo_struct
& gi
) throw()
357 for(auto& i
: dispatch()) {
360 END_EH_BLOCK(i
, "on_gameinfo");
364 const struct gameinfo_struct
& information_dispatch::get_gameinfo() throw()
369 bool information_dispatch::get_dumper_flag() throw()
374 void information_dispatch::on_new_dumper(const std::string
& dumper
)
379 void information_dispatch::on_destroy_dumper(const std::string
& dumper
)
384 unsigned information_dispatch::get_dumper_count() throw()
386 update_dumpers(true);
388 for(auto& i
: dispatch())
389 if(i
->marked_as_dumper
)
399 std::set
<std::string
> information_dispatch::get_dumpers() throw(std::bad_alloc
)
402 std::set
<std::string
> r
;
404 for(auto& i
: dispatch())
405 if(i
->notified_as_dumper
)
406 r
.insert(i
->get_name());
413 void information_dispatch::on_key_event(const modifier_set
& modifiers
, keygroup
& keygroup
, unsigned subkey
,
414 bool polarity
, const std::string
& name
)
419 void information_dispatch::do_key_event(const modifier_set
& modifiers
, keygroup
& keygroup
, unsigned subkey
,
420 bool polarity
, const std::string
& name
) throw()
424 exclusive_key
->on_key_event(modifiers
, keygroup
, subkey
, polarity
, name
);
425 END_EH_BLOCK(exclusive_key
, "on_key_event");
428 for(auto& i
: dispatch()) {
430 i
->on_key_event(modifiers
, keygroup
, subkey
, polarity
, name
);
431 END_EH_BLOCK(i
, "on_key_event");
435 void information_dispatch::grab_keys() throw()
439 exclusive_key
= this;
440 grabbing_keys
= true;
443 void information_dispatch::ungrab_keys() throw()
447 exclusive_key
= NULL
;
448 grabbing_keys
= false;
449 for(auto& i
: dispatch())
450 if(i
->grabbing_keys
) {
456 const std::string
& information_dispatch::get_name() throw()
461 void information_dispatch::update_dumpers(bool nocalls
) throw()
463 for(auto& i
: dispatch()) {
464 if(!i
->known_if_dumper
) {
465 i
->marked_as_dumper
= i
->get_dumper_flag();
466 i
->known_if_dumper
= true;
468 if(i
->marked_as_dumper
&& !i
->notified_as_dumper
&& !nocalls
) {
469 for(auto& j
: dispatch()) {
471 j
->on_new_dumper(i
->target_name
);
472 END_EH_BLOCK(j
, "on_new_dumper");
474 i
->notified_as_dumper
= true;
479 void information_dispatch::on_set_screen(framebuffer
<false>& scr
)
484 void information_dispatch::do_set_screen(framebuffer
<false>& scr
) throw()
486 for(auto& i
: dispatch()) {
488 i
->on_set_screen(scr
);
489 END_EH_BLOCK(i
, "on_set_screen");
493 void information_dispatch::on_screen_update()
498 void information_dispatch::do_screen_update() throw()
500 for(auto& i
: dispatch()) {
502 i
->on_screen_update();
503 END_EH_BLOCK(i
, "on_screen_update");
507 void information_dispatch::on_status_update()
512 void information_dispatch::do_status_update() throw()
514 for(auto& i
: dispatch()) {
516 i
->on_status_update();
517 END_EH_BLOCK(i
, "on_status_update");
521 void information_dispatch::enable_send_sound() throw(std::bad_alloc
)
523 dispatch_audio().push_back(this);
526 void information_dispatch::on_dumper_update()
531 void information_dispatch::do_dumper_update() throw()
533 if(in_global_ctors())
535 for(auto& i
: dispatch()) {
537 i
->on_dumper_update();
538 END_EH_BLOCK(i
, "on_dumper_update");
542 void information_dispatch::on_voice_stream_change()
547 void information_dispatch::do_voice_stream_change() throw()
549 if(in_global_ctors())
551 for(auto& i
: dispatch()) {
553 i
->on_voice_stream_change();
554 END_EH_BLOCK(i
, "on_voice_stream_change");