Lots of dispatch refactoring

This commit is contained in:
Ilari Liusvaara 2013-07-07 13:54:56 +03:00
parent 95bbae153e
commit 8fe4f70d9a
25 changed files with 350 additions and 650 deletions

View file

@ -3,6 +3,7 @@
#include "core/keymapper.hpp"
#include "library/framebuffer.hpp"
#include "library/dispatch.hpp"
#include <cstdint>
#include <string>
@ -101,95 +102,6 @@ public:
* Destroy object.
*/
virtual ~information_dispatch() throw();
/**
* Window close event received (this is not emulator close!)
*
* The default handler does nothing.
*/
virtual void on_close();
/**
* Call all on_close() handlers.
*/
static void do_close() throw();
/**
* Sound mute/unmute status might have been changed.
*
* The default handler does nothing.
*
* Parameter unmuted: If true, the sound is now enabled. If false, the sound is now disabled.
*/
virtual void on_sound_unmute(bool unmuted);
/**
* Call all on_sound_unmute() handlers.
*/
static void do_sound_unmute(bool unmuted) throw();
/**
* Sound device might have been changed.
*
* The default handler does nothing.
*
* Parameter dev: The device name sound is now playing (if enabled) from.
*/
virtual void on_sound_change(std::pair<std::string, std::string> dev);
/**
* Call all on_sound_change() handlers.
*/
static void do_sound_change(std::pair<std::string, std::string> dev) throw();
/**
* Emulator mode might have been changed.
*
* The default handler does nothing.
*
* Parameter readonly: True if readonly mode is now active, false if now in readwrite mode.
*/
virtual void on_mode_change(bool readonly);
/**
* Call all on_mode_change() handlers.
*/
static void do_mode_change(bool readonly) throw();
/**
* Autohold on button might have been changed.
*
* The default handler does nothing.
*
* Parameter port: The port.
* Parameter controller: The controller
* Parameter ctrlnum: Physical control number (0-15).
* Parameter newstate: True if autohold is now active, false if autohold is now inactive.
*/
virtual void on_autohold_update(unsigned port, unsigned controller, unsigned ctrlnum, bool newstate);
/**
* Call all on_autohold_update() handlers.
*/
static void do_autohold_update(unsigned port, unsigned controller, unsigned ctrlnum, bool newstate) throw();
/**
* Autofire on button might have been changed.
*
* The default handler does nothing.
*
* Parameter port: The port.
* Parameter controller: The controller
* Parameter ctrlnum: Physical control number (0-15).
* Parameter duty: Duty cycle.
* Parameter cyclelen: Cycle length.
*/
virtual void on_autofire_update(unsigned port, unsigned controller, unsigned ctrlnum, unsigned duty,
unsigned cyclelen);
/**
* Call all on_autohold_update() handlers.
*/
static void do_autofire_update(unsigned port, unsigned controller, unsigned ctrlnum, unsigned duty,
unsigned cyclelen) throw();
/**
* Controller configuration may have been changed.
*
* The default handler does nothing.
*/
virtual void on_autohold_reconfigure();
/**
* Call all on_autohold_reconfigure() handlers.
*/
static void do_autohold_reconfigure() throw();
/**
* A frame has been received.
*
@ -318,38 +230,6 @@ public:
* Get name of target.
*/
const std::string& get_name() throw();
/**
* Render buffer needs to be (possibly) resized, so that graphics plugin can update the mappings.
*
* Default implementation does nothing.
*
* parameter scr: The render buffer object.
*/
virtual void on_set_screen(framebuffer<false>& scr);
/**
* Call on_set_screen on all objects.
*/
static void do_set_screen(framebuffer<false>& scr) throw();
/**
* Notify that new frame is available.
*
* Default implementation does nothing.
*/
virtual void on_screen_update();
/**
* Call on_screen_update() in all objects.
*/
static void do_screen_update() throw();
/**
* Notify that status buffer has been updated.
*
* Default implementation does nothing.
*/
virtual void on_status_update();
/**
* Call on_status_update() in all objects.
*/
static void do_status_update() throw();
/**
* Notify that some dumper has attached, deattached, popped into existence or disappeared.
*
@ -360,57 +240,6 @@ public:
* Call on_dumper_update on on all objects.
*/
static void do_dumper_update() throw();
/**
* Notify that core changed.
*
* Default implementation does nothing.
*/
virtual void on_core_change();
/**
* Call on_core_change on on all objects.
*/
static void do_core_change() throw();
/**
* Notify that there is a new core.
*
* Default implementation does nothing.
*/
virtual void on_new_core();
/**
* Call on_new_core on on all objects.
*/
static void do_new_core() throw();
/**
* Notify about changes to voice streams.
*
* Default implementation does nothing.
*/
virtual void on_voice_stream_change();
/**
* Call on_voice_stream_change on all objects.
*/
static void do_voice_stream_change() throw();
/**
* Notify about changes to subtitles.
*
* Default implementation does nothing.
*/
virtual void on_subtitle_change();
/**
* Call on_subtitle_change on all objects.
*/
static void do_subtitle_change() throw();
/**
* Notify about changes to VU levels.
*
* Default implementation does nothing.
*/
virtual void on_vu_change();
/**
* Call on_vu_change on all objects.
*/
static void do_vu_change() throw();
protected:
/**
* Call to indicate this target is interested in sound sample data.
@ -424,4 +253,22 @@ private:
bool notified_as_dumper;
};
void dispatch_set_error_streams(std::ostream* stream);
extern struct dispatcher<> notify_autohold_reconfigure;
extern struct dispatcher<unsigned, unsigned, unsigned, bool> notify_autohold_update;
extern struct dispatcher<unsigned, unsigned, unsigned, unsigned, unsigned> notify_autofire_update;
extern struct dispatcher<> notify_close;
extern struct dispatcher<framebuffer<false>&> notify_set_screen;
extern struct dispatcher<std::pair<std::string, std::string>> notify_sound_change;
extern struct dispatcher<> notify_screen_update;
extern struct dispatcher<> notify_status_update;
extern struct dispatcher<bool> notify_sound_unmute;
extern struct dispatcher<bool> notify_mode_change;
extern struct dispatcher<> notify_core_change;
extern struct dispatcher<> notify_new_core;
extern struct dispatcher<> notify_voice_stream_change;
extern struct dispatcher<> notify_vu_change;
extern struct dispatcher<> notify_subtitle_change;
#endif

View file

@ -0,0 +1,135 @@
#ifndef _library__dispatch__hpp__included__
#define _library__dispatch__hpp__included__
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <functional>
#include "threadtypes.hpp"
mutex_class& dispatch_global_init_lock();
template<typename... T> struct dispatcher;
template<typename... T> struct dispatch_target
{
dispatch_target()
{
src = NULL;
fn = dummy;
}
inline ~dispatch_target();
inline void set(dispatcher<T...>& d, std::function<void(T...)> _fn);
private:
static void dummy(T... args) {};
void set_source(dispatcher<T...>* d) { src = d; }
void call(T... args) { fn(args...); }
dispatcher<T...>* src;
std::function<void(T...)> fn;
friend class dispatcher<T...>;
};
template<typename... T> struct dispatcher
{
dispatcher(const char* _name)
{
init();
name = _name;
}
~dispatcher()
{
delete _targets;
delete lck;
lck = NULL;
}
void operator()(T... args)
{
init();
uint64_t k = 0;
typename std::map<uint64_t, dispatch_target<T...>*>::iterator i;
lck->lock();
i = targets().lower_bound(k);
while(i != targets().end()) {
k = i->first + 1;
dispatch_target<T...>* t = i->second;
lck->unlock();
try {
t->call(args...);
} catch(std::exception& e) {
(*errstrm) << name << ": Error in handler: " << e.what() << std::endl;
}
lck->lock();
i = targets().lower_bound(k);
}
lck->unlock();
}
void connect(dispatch_target<T...>& target)
{
init();
umutex_class h(*lck);
targets()[next_cbseq++] = &target;
target.set_source(this);
}
void disconnect(dispatch_target<T...>& target)
{
init();
if(!lck)
return;
umutex_class h(*lck);
for(auto i = targets().begin(); i != targets().end(); i++)
if(i->second == &target) {
targets().erase(i);
break;
}
target.set_source(NULL);
}
void errors_to(std::ostream* to)
{
errstrm = to ? to : &std::cerr;
}
private:
void init()
{
if(inited)
return;
umutex_class h(dispatch_global_init_lock());
if(inited)
return;
errstrm = &std::cerr;
next_cbseq = 0;
name = "(unknown)";
_targets = NULL;
lck = new mutex_class;
inited = true;
}
mutex_class* lck;
std::map<uint64_t, dispatch_target<T...>*>& targets()
{
if(!_targets) _targets = new std::map<uint64_t, dispatch_target<T...>*>;
return *_targets;
}
std::map<uint64_t, dispatch_target<T...>*>* _targets;
uint64_t next_cbseq;
std::ostream* errstrm;
const char* name;
bool inited;
dispatcher(const dispatcher<T...>&);
dispatcher<T...>& operator=(const dispatcher<T...>&);
};
template <typename... T> dispatch_target<T...>::~dispatch_target()
{
if(src)
src->disconnect(*this);
}
template <typename... T> void dispatch_target<T...>::set(dispatcher<T...>& d, std::function<void(T...)> _fn)
{
fn = _fn;
src = &d;
if(src)
src->connect(*this);
}
#endif

View file

@ -3,6 +3,7 @@
#include "platform/wxwidgets/window_status.hpp"
#include "platform/wxwidgets/menu_recent.hpp"
#include "library/dispatch.hpp"
#include <stack>
@ -65,6 +66,10 @@ private:
void* sounddev1;
void* sounddev2;
void* dmenu;
struct dispatch_target<> corechange;
struct dispatch_target<> newcore;
struct dispatch_target<bool> unmuted;
struct dispatch_target<bool> modechange;
};
#endif

View file

@ -525,7 +525,7 @@ void audioapi_vumeter::update_vu()
accumulator = 0;
samples = 0;
}
information_dispatch::do_vu_change();
notify_vu_change();
}
//VU values.

View file

@ -302,7 +302,7 @@ namespace
if(lua_callback_do_button(x.port, x.controller, x.bind.control1, nstate ? "hold" : "unhold"))
return;
controls.autohold2(x.port, x.controller, x.bind.control1, nstate);
information_dispatch::do_autohold_update(x.port, x.controller, x.bind.control1, nstate);
notify_autohold_update(x.port, x.controller, x.bind.control1, nstate);
} else if(mode == 2) {
//Framehold.
bool nstate = controls.framehold2(x.port, x.controller, x.bind.control1) ^ newstate;
@ -418,14 +418,14 @@ namespace
<< duty << " " << cyclelen).str().c_str()))
return;
controls.autofire2(z.port, z.controller, z.bind.control1, duty, cyclelen);
information_dispatch::do_autofire_update(z.port, z.controller, z.bind.control1, duty,
notify_autofire_update(z.port, z.controller, z.bind.control1, duty,
cyclelen);
} else if(mode == 0 || (mode == -1 && afire.first != 0)) {
//Turn off.
if(lua_callback_do_button(z.port, z.controller, z.bind.control1, "autofire"))
return;
controls.autofire2(z.port, z.controller, z.bind.control1, 0, 1);
information_dispatch::do_autofire_update(z.port, z.controller, z.bind.control1, 0, 1);
notify_autofire_update(z.port, z.controller, z.bind.control1, 0, 1);
}
}
@ -501,16 +501,14 @@ namespace
controls.do_macro(a, 2);
});
class new_core_snoop : public information_dispatch
class new_core_snoop
{
public:
new_core_snoop() : information_dispatch("controller-newcore")
new_core_snoop()
{
ncore.set(notify_new_core, []() { init_buttonmap(); });
}
void on_new_core()
{
init_buttonmap();
}
struct dispatch_target<> ncore;
} coresnoop;
}

View file

@ -63,7 +63,7 @@ void controller_state::analog(unsigned port, unsigned controller, unsigned contr
void controller_state::autohold2(unsigned port, unsigned controller, unsigned pbid, bool newstate) throw()
{
_autohold.axis3(port, controller, pbid, newstate ? 1 : 0);
information_dispatch::do_autohold_update(port, controller, pbid, newstate);
notify_autohold_update(port, controller, pbid, newstate);
}
bool controller_state::autohold2(unsigned port, unsigned controller, unsigned pbid) throw()
@ -190,7 +190,7 @@ void controller_state::set_ports(const port_type_set& ptype) throw(std::runtime_
_autohold = _autohold.blank_frame();
}
reread_active_buttons();
information_dispatch::do_autohold_reconfigure();
notify_autohold_reconfigure();
}
controller_frame controller_state::get_blank() throw()
@ -361,7 +361,7 @@ void controller_state::do_macro(const std::string& a, int mode) {
}
end:
update_movie_state();
information_dispatch::do_status_update();
notify_status_update();
}
std::set<std::string> controller_state::active_macro_set()

View file

@ -127,106 +127,6 @@ information_dispatch::~information_dispatch() throw()
}
}
void information_dispatch::on_close()
{
//Do nothing.
}
void information_dispatch::do_close() throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_close();
END_EH_BLOCK(i, "on_close");
}
}
void information_dispatch::on_sound_unmute(bool unmuted)
{
//Do nothing.
}
void information_dispatch::do_sound_unmute(bool unmuted) throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_sound_unmute(unmuted);
END_EH_BLOCK(i, "on_sound_unmute");
}
}
void information_dispatch::on_sound_change(std::pair<std::string, std::string> dev)
{
//Do nothing.
}
void information_dispatch::do_sound_change(std::pair<std::string,std::string> dev) throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_sound_change(dev);
END_EH_BLOCK(i, "on_sound_change");
}
}
void information_dispatch::on_mode_change(bool readonly)
{
//Do nothing.
}
void information_dispatch::do_mode_change(bool readonly) throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_mode_change(readonly);
END_EH_BLOCK(i, "on_mode_change");
}
}
void information_dispatch::on_autohold_update(unsigned port, unsigned controller, unsigned ctrlnum, bool newstate)
{
//Do nothing.
}
void information_dispatch::do_autohold_update(unsigned port, unsigned controller, unsigned ctrlnum, bool newstate) throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_autohold_update(port, controller, ctrlnum, newstate);
END_EH_BLOCK(i, "on_autohold_update");
}
}
void information_dispatch::on_autofire_update(unsigned port, unsigned controller, unsigned ctrlnum, unsigned duty,
unsigned cyclelen)
{
//Do nothing.
}
void information_dispatch::do_autofire_update(unsigned port, unsigned controller, unsigned ctrlnum, unsigned duty,
unsigned cyclelen) throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_autofire_update(port, controller, ctrlnum, duty, cyclelen);
END_EH_BLOCK(i, "on_autofire_update");
}
}
void information_dispatch::on_autohold_reconfigure()
{
//Do nothing.
}
void information_dispatch::do_autohold_reconfigure() throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_autohold_reconfigure();
END_EH_BLOCK(i, "on_autohold_reconfigure");
}
}
void information_dispatch::on_frame(struct framebuffer_raw& _frame, uint32_t fps_n, uint32_t fps_d)
{
//Do nothing.
@ -399,48 +299,6 @@ void information_dispatch::update_dumpers(bool nocalls) throw()
}
}
void information_dispatch::on_set_screen(framebuffer<false>& scr)
{
//Do nothing.
}
void information_dispatch::do_set_screen(framebuffer<false>& scr) throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_set_screen(scr);
END_EH_BLOCK(i, "on_set_screen");
}
}
void information_dispatch::on_screen_update()
{
//Do nothing.
}
void information_dispatch::do_screen_update() throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_screen_update();
END_EH_BLOCK(i, "on_screen_update");
}
}
void information_dispatch::on_status_update()
{
//Do nothing.
}
void information_dispatch::do_status_update() throw()
{
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_status_update();
END_EH_BLOCK(i, "on_status_update");
}
}
void information_dispatch::enable_send_sound() throw(std::bad_alloc)
{
dispatch_audio().push_back(this);
@ -462,82 +320,37 @@ void information_dispatch::do_dumper_update() throw()
}
}
void information_dispatch::on_core_change()
void dispatch_set_error_streams(std::ostream* stream)
{
//Do nothing.
notify_autofire_update.errors_to(stream);
notify_autohold_reconfigure.errors_to(stream);
notify_autohold_update.errors_to(stream);
notify_close.errors_to(stream);
notify_core_change.errors_to(stream);
notify_mode_change.errors_to(stream);
notify_new_core.errors_to(stream);
notify_screen_update.errors_to(stream);
notify_set_screen.errors_to(stream);
notify_sound_change.errors_to(stream);
notify_sound_unmute.errors_to(stream);
notify_status_update.errors_to(stream);
notify_subtitle_change.errors_to(stream);
notify_voice_stream_change.errors_to(stream);
notify_vu_change.errors_to(stream);
}
void information_dispatch::do_core_change() throw()
{
if(in_global_ctors())
return;
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_core_change();
END_EH_BLOCK(i, "on_core_change");
}
}
void information_dispatch::on_new_core()
{
//Do nothing.
}
void information_dispatch::do_new_core() throw()
{
if(in_global_ctors())
return;
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_new_core();
END_EH_BLOCK(i, "on_new_core");
}
}
void information_dispatch::on_voice_stream_change()
{
//Do nothing.
}
void information_dispatch::do_voice_stream_change() throw()
{
if(in_global_ctors())
return;
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_voice_stream_change();
END_EH_BLOCK(i, "on_voice_stream_change");
}
}
void information_dispatch::on_subtitle_change()
{
//Do nothing.
}
void information_dispatch::do_subtitle_change() throw()
{
if(in_global_ctors())
return;
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_subtitle_change();
END_EH_BLOCK(i, "on_subtitle_change");
}
}
void information_dispatch::on_vu_change()
{
//Do nothing.
}
void information_dispatch::do_vu_change() throw()
{
if(in_global_ctors())
return;
for(auto& i : dispatch()) {
START_EH_BLOCK
i->on_vu_change();
END_EH_BLOCK(i, "on_vu_change");
}
}
struct dispatcher<> notify_autohold_reconfigure("autohold_reconfigure");
struct dispatcher<unsigned, unsigned, unsigned, bool> notify_autohold_update("autohold_update");
struct dispatcher<unsigned, unsigned, unsigned, unsigned, unsigned> notify_autofire_update("autofire_update");
struct dispatcher<> notify_close("notify_close");
struct dispatcher<framebuffer<false>&> notify_set_screen("set_screen");
struct dispatcher<std::pair<std::string, std::string>> notify_sound_change("sound_change");
struct dispatcher<> notify_screen_update("screen_update");
struct dispatcher<> notify_status_update("status_update");
struct dispatcher<bool> notify_sound_unmute("sound_unmute");
struct dispatcher<bool> notify_mode_change("mode_change");
struct dispatcher<> notify_core_change("core_change");
struct dispatcher<> notify_new_core("new_core");
struct dispatcher<> notify_voice_stream_change("voice_stream_change");
struct dispatcher<> notify_vu_change("vu_change");
struct dispatcher<> notify_subtitle_change("subtitle_change");

View file

@ -190,7 +190,7 @@ void redraw_framebuffer(framebuffer_raw& todraw, bool no_lua, bool spontaneous)
ri.tgap = lrc.top_gap;
ri.bgap = lrc.bottom_gap;
buffering.end_write();
information_dispatch::do_screen_update();
notify_screen_update();
last_redraw_no_lua = no_lua;
}
@ -212,7 +212,7 @@ void render_framebuffer()
main_screen.set_origin(ri.lgap, ri.tgap);
main_screen.copy_from(ri.fbuf, ri.hscl, ri.vscl);
ri.rq.run(main_screen);
information_dispatch::do_set_screen(main_screen);
notify_set_screen(main_screen);
//We would want divide by 2, but we'll do it ourselves in order to do mouse.
keyboard_key* mouse_x = lsnes_kbd.try_lookup_key("mouse_x");
keyboard_key* mouse_y = lsnes_kbd.try_lookup_key("mouse_y");

View file

@ -1525,7 +1525,7 @@ out:
messages << "Can't add stream: " << e.what() << std::endl;
active_stream->put_ref();
}
information_dispatch::do_voice_stream_change();
notify_voice_stream_change();
} else
active_stream->put_ref();
active_stream = NULL;
@ -1800,7 +1800,7 @@ uint64_t voicesub_import_stream(uint64_t ts, const std::string& filename, extern
throw;
}
st->unlock(); //Not locked.
information_dispatch::do_voice_stream_change();
notify_voice_stream_change();
return id;
}
@ -1810,7 +1810,7 @@ void voicesub_delete_stream(uint64_t id)
if(!current_collection)
throw std::runtime_error("No collection loaded");
current_collection->delete_stream(id);
information_dispatch::do_voice_stream_change();
notify_voice_stream_change();
}
void voicesub_export_superstream(const std::string& filename)
@ -1834,7 +1834,7 @@ void voicesub_load_collection(const std::string& filename)
if(current_collection)
delete current_collection;
current_collection = newc;
information_dispatch::do_voice_stream_change();
notify_voice_stream_change();
}
void voicesub_unload_collection()
@ -1843,7 +1843,7 @@ void voicesub_unload_collection()
if(current_collection)
delete current_collection;
current_collection = NULL;
information_dispatch::do_voice_stream_change();
notify_voice_stream_change();
}
void voicesub_alter_timebase(uint64_t id, uint64_t ts)
@ -1852,7 +1852,7 @@ void voicesub_alter_timebase(uint64_t id, uint64_t ts)
if(!current_collection)
throw std::runtime_error("No collection loaded");
current_collection->alter_stream_timebase(id, ts);
information_dispatch::do_voice_stream_change();
notify_voice_stream_change();
}
float voicesub_get_gain(uint64_t id)
@ -1872,7 +1872,7 @@ void voicesub_set_gain(uint64_t id, float gain)
if(_gain < -32768 || _gain > 32767)
throw std::runtime_error("Gain out of range (+-128dB)");
current_collection->alter_stream_gain(id, _gain);
information_dispatch::do_voice_stream_change();
notify_voice_stream_change();
}
double voicesub_ts_seconds(uint64_t ts)

View file

@ -13,7 +13,7 @@ void handle_post_loadlibrary()
{
if(new_core_flag) {
new_core_flag = false;
information_dispatch::do_new_core();
notify_new_core();
}
}

View file

@ -245,9 +245,7 @@ controller_frame movie_logic::update_controls(bool subframe) throw(std::bad_allo
}
location_special = SPECIAL_FRAME_START;
update_movie_state();
}
information_dispatch::do_status_update();
platform::flush_command_queue();
controller_frame tmp = controls.get(movb.get_movie().get_current_frame());
our_rom->rtype->pre_emulate_frame(tmp); //Preset controls, the lua will override if needed.
@ -300,7 +298,7 @@ namespace
our_movie.romimg_sha256[i] = "";
our_movie.romxml_sha256[i] = "";
}
information_dispatch::do_core_change();
notify_core_change();
return true;
}
@ -351,7 +349,7 @@ namespace
return false;
}
messages << "Using core: " << our_rom->rtype->get_core_identifier() << std::endl;
information_dispatch::do_core_change();
notify_core_change();
return true;
}
@ -366,7 +364,6 @@ namespace
save_jukebox_pointer = 0;
}
update_movie_state();
information_dispatch::do_status_update();
}
};
}
@ -459,6 +456,7 @@ void update_movie_state()
c.display(pindex.first, pindex.second, buffer);
_status.set((stringfmt() << "P" << (i + 1)).str(), buffer);
}
notify_status_update();
}
uint64_t audio_irq_time;
@ -593,7 +591,6 @@ namespace
if(save_jukebox_pointer >= jukebox_size)
save_jukebox_pointer = 0;
update_movie_state();
information_dispatch::do_status_update();
});
function_ptr_command<> save_jukebox_next(lsnes_cmd, "cycle-jukebox-forward", "Cycle save jukebox forwards",
@ -608,7 +605,6 @@ namespace
if(save_jukebox_pointer >= jukebox_size)
save_jukebox_pointer = 0;
update_movie_state();
information_dispatch::do_status_update();
});
function_ptr_command<> load_jukebox(lsnes_cmd, "load-jukebox", "Load save from jukebox",
@ -778,19 +774,17 @@ namespace
"Syntax: set-rwmode\nSwitches to read/write mode\n",
[]() throw(std::bad_alloc, std::runtime_error) {
movb.get_movie().readonly_mode(false);
information_dispatch::do_mode_change(false);
notify_mode_change(false);
lua_callback_do_readwrite();
update_movie_state();
information_dispatch::do_status_update();
});
function_ptr_command<> set_romode(lsnes_cmd, "set-romode", "Switch to read-only mode",
"Syntax: set-romode\nSwitches to read-only mode\n",
[]() throw(std::bad_alloc, std::runtime_error) {
movb.get_movie().readonly_mode(true);
information_dispatch::do_mode_change(true);
notify_mode_change(true);
update_movie_state();
information_dispatch::do_status_update();
});
function_ptr_command<> toggle_rwmode(lsnes_cmd, "toggle-rwmode", "Toggle read/write mode",
@ -798,11 +792,10 @@ namespace
[]() throw(std::bad_alloc, std::runtime_error) {
bool c = movb.get_movie().readonly_mode();
movb.get_movie().readonly_mode(!c);
information_dispatch::do_mode_change(!c);
notify_mode_change(!c);
if(c)
lua_callback_do_readwrite();
update_movie_state();
information_dispatch::do_status_update();
});
function_ptr_command<> repaint(lsnes_cmd, "repaint", "Redraw the screen",
@ -966,7 +959,26 @@ namespace
class mywindowcallbacks : public information_dispatch
{
public:
mywindowcallbacks() : information_dispatch("mainloop-window-callbacks") {}
mywindowcallbacks() : information_dispatch("mainloop-window-callbacks")
{
closenotify.set(notify_close, [this]() {
if(on_quit_prompt) {
amode = ADVANCE_QUIT;
platform::set_paused(false);
platform::cancel_wait();
return;
}
on_quit_prompt = true;
try {
amode = ADVANCE_QUIT;
platform::set_paused(false);
platform::cancel_wait();
} catch(...) {
}
on_quit_prompt = false;
});
}
~mywindowcallbacks() throw() {}
void on_new_dumper(const std::string& n)
{
update_movie_state();
@ -975,23 +987,8 @@ namespace
{
update_movie_state();
}
void on_close() throw()
{
if(on_quit_prompt) {
amode = ADVANCE_QUIT;
platform::set_paused(false);
platform::cancel_wait();
return;
}
on_quit_prompt = true;
try {
amode = ADVANCE_QUIT;
platform::set_paused(false);
platform::cancel_wait();
} catch(...) {
}
on_quit_prompt = false;
}
private:
struct dispatch_target<> closenotify;
} mywcb;
//If there is a pending load, perform it. Return 1 on successful load, 0 if nothing to load, -1 on load
@ -1002,7 +999,7 @@ namespace
uint64_t t = get_utime();
std::vector<char> s;
lua_callback_do_unsafe_rewind(s, 0, 0, movb.get_movie(), unsafe_rewind_obj);
information_dispatch::do_mode_change(false);
notify_mode_change(false);
do_unsafe_rewind = false;
our_movie.is_savestate = true;
location_special = SPECIAL_SAVEPOINT;
@ -1058,7 +1055,6 @@ nothing_to_do:
if(!system_corrupt) {
location_special = SPECIAL_SAVEPOINT;
update_movie_state();
information_dispatch::do_status_update();
platform::flush_command_queue();
}
if(old_project != our_movie.projectid)
@ -1109,6 +1105,7 @@ void main_loop(struct loaded_rom& rom, struct moviefile& initial, bool load_has_
std::runtime_error)
{
//Basic initialization.
dispatch_set_error_streams(&messages.getstream());
emulation_thread = this_thread_id();
jukebox_size_listener jlistener;
voicethread_task();

View file

@ -413,7 +413,7 @@ void set_watchexpr_for(const std::string& w, const std::string& expr) throw(std:
}
if(p)
project_flush(p);
information_dispatch::do_status_update();
notify_status_update();
}
void do_watch_memory()

View file

@ -109,7 +109,6 @@ namespace
mprefix = pfx;
}
update_movie_state();
information_dispatch::do_status_update();
}
std::string get_mprefix_for_project(const std::string& prjid)
@ -324,7 +323,7 @@ void do_load_beginning(bool reload) throw(std::bad_alloc, std::runtime_error)
redraw_framebuffer(screen_corrupt, true);
throw;
}
information_dispatch::do_mode_change(movb.get_movie().readonly_mode());
notify_mode_change(movb.get_movie().readonly_mode());
our_movie.is_savestate = false;
our_movie.host_memory.clear();
if(reload)
@ -457,7 +456,7 @@ void do_load_state(struct moviefile& _movie, int lmode)
} else
redraw_framebuffer(our_rom->rtype->draw_cover());
}
information_dispatch::do_mode_change(movb.get_movie().readonly_mode());
notify_mode_change(movb.get_movie().readonly_mode());
if(our_rom->rtype)
messages << "ROM Type " << our_rom->rtype->get_hname() << " region " << our_rom->region->get_hname()
<< std::endl;

View file

@ -352,7 +352,7 @@ bool project_set(project_info* p, bool current)
if(active_project)
voicesub_unload_collection();
active_project = p;
information_dispatch::do_core_change();
notify_core_change();
return true;
}
@ -404,8 +404,7 @@ skip_rom_movie:
if(switched) {
do_flush_slotinfo();
update_movie_state();
information_dispatch::do_status_update();
information_dispatch::do_core_change();
notify_core_change();
}
return switched;
}

View file

@ -112,7 +112,7 @@ namespace
our_movie.subtitles.erase(key);
else
our_movie.subtitles[key] = s_unescape(text);
information_dispatch::do_subtitle_change();
notify_subtitle_change();
redraw_framebuffer();
});
@ -234,6 +234,6 @@ void set_subtitle_for(uint64_t f, uint64_t l, const std::string& x)
our_movie.subtitles.erase(key);
else
our_movie.subtitles[key] = s_unescape(x);
information_dispatch::do_subtitle_change();
notify_subtitle_change();
redraw_framebuffer();
}

View file

@ -152,7 +152,7 @@ void platform::sound_enable(bool enable) throw()
{
audioapi_driver_enable(enable);
sounds_enabled = enable;
information_dispatch::do_sound_unmute(enable);
notify_sound_unmute(enable);
}
void platform::set_sound_device(const std::string& pdev, const std::string& rdev) throw()
@ -170,8 +170,7 @@ void platform::set_sound_device(const std::string& pdev, const std::string& rdev
}
}
//After failed change, we don't know what is selected.
information_dispatch::do_sound_change(std::make_pair(audioapi_driver_get_device(true),
audioapi_driver_get_device(false)));
notify_sound_change(std::make_pair(audioapi_driver_get_device(true), audioapi_driver_get_device(false)));
}
bool platform::is_sound_enabled() throw()
@ -497,30 +496,19 @@ namespace
mutex_class _msgbuf_lock;
framebuffer<false>* our_screen;
struct painter_listener : public information_dispatch
struct painter_listener
{
painter_listener();
void on_set_screen(framebuffer<false>& scr);
void on_screen_update();
void on_status_update();
painter_listener()
{
screenupdate.set(notify_screen_update, []() { graphics_driver_notify_screen(); });
statusupdate.set(notify_status_update, []() { graphics_driver_notify_status(); });
setscreen.set(notify_set_screen, [](framebuffer<false>& scr) { our_screen = &scr; });
}
private:
struct dispatch_target<> screenupdate;
struct dispatch_target<> statusupdate;
struct dispatch_target<framebuffer<false>&> setscreen;
} x;
painter_listener::painter_listener() : information_dispatch("painter-listener") {}
void painter_listener::on_set_screen(framebuffer<false>& scr)
{
our_screen = &scr;
}
void painter_listener::on_screen_update()
{
graphics_driver_notify_screen();
}
void painter_listener::on_status_update()
{
graphics_driver_notify_status();
}
}
mutex_class& platform::msgbuf_lock() throw()

7
src/library/dispatch.cpp Normal file
View file

@ -0,0 +1,7 @@
#include "dispatch.hpp"
mutex_class& dispatch_global_init_lock()
{
static mutex_class m;
return m;
}

View file

@ -229,8 +229,7 @@ void wxeditor_authors::on_ok(wxCommandEvent& e)
//For save status to immediately update.
do_flush_slotinfo();
update_movie_state();
information_dispatch::do_status_update();
information_dispatch::do_core_change();
notify_core_change();
} else {
our_movie.gamename = gamename;
our_movie.authors = newauthors;

View file

@ -20,7 +20,7 @@
#include <wx/combobox.h>
#include <wx/statline.h>
class wxeditor_autohold : public wxDialog, public information_dispatch
class wxeditor_autohold : public wxDialog
{
public:
wxeditor_autohold(wxWindow* parent);
@ -28,11 +28,11 @@ public:
bool ShouldPreventAppExit() const;
void on_wclose(wxCloseEvent& e);
void on_checkbox(wxCommandEvent& e);
void on_autohold_update(unsigned port, unsigned controller, unsigned ctrlnum, bool newstate);
void on_autofire_update(unsigned port, unsigned controller, unsigned ctrlnum, unsigned duty,
unsigned cyclelen);
void on_autohold_reconfigure();
private:
struct dispatch_target<unsigned, unsigned, unsigned, bool> ahupdate;
struct dispatch_target<unsigned, unsigned, unsigned, unsigned, unsigned> afupdate;
struct dispatch_target<> ahreconfigure;
struct control_triple
{
unsigned port;
@ -71,8 +71,7 @@ namespace
wxeditor_autohold::~wxeditor_autohold() throw() {}
wxeditor_autohold::wxeditor_autohold(wxWindow* parent)
: wxDialog(parent, wxID_ANY, wxT("lsnes: Autohold/Autofire"), wxDefaultPosition, wxSize(-1, -1)),
information_dispatch("autohold-listener")
: wxDialog(parent, wxID_ANY, wxT("lsnes: Autohold/Autofire"), wxDefaultPosition, wxSize(-1, -1))
{
closing = false;
Centre();
@ -82,46 +81,42 @@ wxeditor_autohold::wxeditor_autohold(wxWindow* parent)
update_controls();
hsizer->SetSizeHints(this);
Fit();
}
void wxeditor_autohold::on_autohold_update(unsigned port, unsigned controller, unsigned ctrlnum, bool newstate)
{
runuifun([this, port, controller, ctrlnum, newstate]() {
for(auto i : this->autoholds) {
if(i.second.port != port) continue;
if(i.second.controller != controller) continue;
if(i.second.index != ctrlnum) continue;
i.second.check->SetValue(newstate);
}
ahupdate.set(notify_autohold_update, [this](unsigned port, unsigned controller, unsigned ctrlnum,
bool newstate) {
runuifun([this, port, controller, ctrlnum, newstate]() {
for(auto i : this->autoholds) {
if(i.second.port != port) continue;
if(i.second.controller != controller) continue;
if(i.second.index != ctrlnum) continue;
i.second.check->SetValue(newstate);
}
});
});
}
void wxeditor_autohold::on_autofire_update(unsigned port, unsigned controller, unsigned ctrlnum, unsigned duty,
unsigned cyclelen)
{
runuifun([this, port, controller, ctrlnum, duty]() {
for(auto i : this->autoholds) {
if(i.second.port != port) continue;
if(i.second.controller != controller) continue;
if(i.second.index != ctrlnum) continue;
i.second.afcheck->SetValue(duty != 0);
}
afupdate.set(notify_autofire_update, [this](unsigned port, unsigned controller, unsigned ctrlnum,
unsigned duty, unsigned cyclelen) {
runuifun([this, port, controller, ctrlnum, duty]() {
for(auto i : this->autoholds) {
if(i.second.port != port) continue;
if(i.second.controller != controller) continue;
if(i.second.index != ctrlnum) continue;
i.second.afcheck->SetValue(duty != 0);
}
});
});
}
void wxeditor_autohold::on_autohold_reconfigure()
{
runuifun([this]() {
try {
this->update_controls();
} catch(std::runtime_error& e) {
//Close the window.
bool wasc = closing;
closing = true;
autohold_open = NULL;
if(!wasc)
Destroy();
}
ahreconfigure.set(notify_autohold_reconfigure, [this]() {
runuifun([this]() {
try {
this->update_controls();
} catch(std::runtime_error& e) {
//Close the window.
bool wasc = closing;
closing = true;
autohold_open = NULL;
if(!wasc)
Destroy();
}
});
});
}

View file

@ -275,7 +275,7 @@ public:
scroll_bar* get_scroll();
void update();
private:
struct _moviepanel : public wxPanel, public information_dispatch
struct _moviepanel : public wxPanel
{
_moviepanel(wxeditor_movie* v);
~_moviepanel() throw();
@ -388,8 +388,7 @@ wxeditor_movie::_moviepanel::~_moviepanel() throw() {}
wxeditor_movie::~wxeditor_movie() throw() {}
wxeditor_movie::_moviepanel::_moviepanel(wxeditor_movie* v)
: wxPanel(v, wxID_ANY, wxDefaultPosition, wxSize(100, 100), wxWANTS_CHARS),
information_dispatch("movieeditor-listener")
: wxPanel(v, wxID_ANY, wxDefaultPosition, wxSize(100, 100), wxWANTS_CHARS)
{
m = v;
Connect(wxEVT_PAINT, wxPaintEventHandler(_moviepanel::on_paint), NULL, this);

View file

@ -37,20 +37,6 @@ public:
void on_wclose(wxCloseEvent& e);
void refresh();
private:
struct refresh_listener : public information_dispatch
{
refresh_listener(wxeditor_subtitles* v)
: information_dispatch("subtitle-editor-change-listener")
{
obj = v;
}
void on_subtitle_change()
{
wxeditor_subtitles* _obj = obj;
runuifun([_obj]() -> void { _obj->refresh(); });
}
wxeditor_subtitles* obj;
};
bool closing;
wxListBox* subs;
wxTextCtrl* subtext;
@ -59,7 +45,7 @@ private:
wxButton* _delete;
wxButton* close;
std::map<int, subdata> subtexts;
refresh_listener* rlistener;
struct dispatch_target<> subchange;
};
namespace
@ -205,13 +191,12 @@ wxeditor_subtitles::wxeditor_subtitles(wxWindow* parent)
pbutton_s->SetSizeHints(this);
top_s->SetSizeHints(this);
Fit();
rlistener = new refresh_listener(this);
subchange.set(notify_subtitle_change, [this]() { runuifun([this]() -> void { this->refresh(); }); });
refresh();
}
wxeditor_subtitles::~wxeditor_subtitles() throw()
{
delete rlistener;
}
bool wxeditor_subtitles::ShouldPreventAppExit() const

View file

@ -68,7 +68,7 @@ namespace
}
}
class wxeditor_tasinput : public wxDialog, public information_dispatch
class wxeditor_tasinput : public wxDialog
{
public:
wxeditor_tasinput(wxWindow* parent);
@ -76,10 +76,10 @@ public:
bool ShouldPreventAppExit() const;
void on_wclose(wxCloseEvent& e);
void on_control(wxCommandEvent& e);
void on_autohold_reconfigure();
void on_keyboard_up(wxKeyEvent& e);
void on_keyboard_down(wxKeyEvent& e);
private:
struct dispatch_target<> ahreconfigure;
struct xypanel;
struct control_triple
{
@ -239,8 +239,7 @@ void wxeditor_tasinput::xypanel::Destroy()
wxeditor_tasinput::~wxeditor_tasinput() throw() {}
wxeditor_tasinput::wxeditor_tasinput(wxWindow* parent)
: wxDialog(parent, wxID_ANY, wxT("lsnes: TAS input plugin"), wxDefaultPosition, wxSize(-1, -1)),
information_dispatch("tasinput-listener")
: wxDialog(parent, wxID_ANY, wxT("lsnes: TAS input plugin"), wxDefaultPosition, wxSize(-1, -1))
{
closing = false;
Centre();
@ -250,6 +249,22 @@ wxeditor_tasinput::wxeditor_tasinput(wxWindow* parent)
update_controls();
hsizer->SetSizeHints(this);
Fit();
ahreconfigure.set(notify_autohold_reconfigure, [this]() {
runuifun([this]() {
try {
this->update_controls();
} catch(std::runtime_error& e) {
//Close the window.
bool wasc = closing;
closing = true;
tasinput_open = NULL;
controls.tasinput_enable(false);
if(!wasc)
Destroy();
}
});
});
}
void wxeditor_tasinput::connect_keyboard_recursive(wxWindow* win)
@ -263,23 +278,6 @@ void wxeditor_tasinput::connect_keyboard_recursive(wxWindow* win)
}
}
void wxeditor_tasinput::on_autohold_reconfigure()
{
runuifun([this]() {
try {
this->update_controls();
} catch(std::runtime_error& e) {
//Close the window.
bool wasc = closing;
closing = true;
tasinput_open = NULL;
controls.tasinput_enable(false);
if(!wasc)
Destroy();
}
});
}
void wxeditor_tasinput::on_control(wxCommandEvent& e)
{
int id = e.GetId();

View file

@ -43,25 +43,6 @@ public:
void on_wclose(wxCloseEvent& e);
void refresh();
private:
struct refresh_listener : public information_dispatch
{
refresh_listener(wxeditor_voicesub* v)
: information_dispatch("voicesub-editor-change-listner")
{
obj = v;
}
void on_voice_stream_change()
{
wxeditor_voicesub* _obj = obj;
runuifun([_obj]() -> void { _obj->refresh(); });
}
void on_core_change()
{
wxeditor_voicesub* _obj = obj;
runuifun([_obj]() -> void { _obj->refresh(); });
}
wxeditor_voicesub* obj;
};
bool closing;
uint64_t get_id();
std::map<int, uint64_t> smap;
@ -79,8 +60,8 @@ private:
wxButton* unloadbutton;
wxButton* refreshbutton;
wxButton* closebutton;
refresh_listener* rlistener;
struct dispatch_target<> corechange;
struct dispatch_target<> vstreamchange;
};
wxeditor_voicesub::wxeditor_voicesub(wxWindow* parent)
@ -169,13 +150,13 @@ wxeditor_voicesub::wxeditor_voicesub(wxWindow* parent)
top_s->SetSizeHints(this);
Fit();
rlistener = new refresh_listener(this);
vstreamchange.set(notify_voice_stream_change, [this]() { runuifun([this]() -> void { this->refresh(); }); });
corechange.set(notify_core_change, [this]() { runuifun([this]() -> void { this->refresh(); }); });
refresh();
}
wxeditor_voicesub::~wxeditor_voicesub() throw()
{
delete rlistener;
}
void wxeditor_voicesub::on_select(wxCommandEvent& e)

View file

@ -496,39 +496,6 @@ namespace
set_speed_multiplier(target / 100);
}
class broadcast_listener : public information_dispatch
{
public:
broadcast_listener(wxwin_mainwindow* win);
void on_sound_unmute(bool unmute) throw();
void on_mode_change(bool readonly) throw();
void on_core_change();
void on_new_core();
private:
wxwin_mainwindow* mainw;
};
broadcast_listener::broadcast_listener(wxwin_mainwindow* win)
: information_dispatch("wxwidgets-broadcast-listener")
{
mainw = win;
}
void broadcast_listener::on_core_change()
{
signal_core_change();
}
void broadcast_listener::on_sound_unmute(bool unmute) throw()
{
runuifun([this, unmute]() { this->mainw->menu_check(wxID_AUDIO_ENABLED, unmute); });
}
void broadcast_listener::on_mode_change(bool readonly) throw()
{
runuifun([this, readonly]() { this->mainw->menu_check(wxID_READONLY_MODE, readonly); });
}
void update_preferences()
{
preferred_core.clear();
@ -542,15 +509,9 @@ namespace
std::string key2 = "type:" + i->get_iname();
if(core_selections.count(key2) && core_selections[key2] == val)
preferred_core[key2] = i;
}
}
void broadcast_listener::on_new_core()
{
update_preferences();
}
std::string movie_path()
{
return lsnes_vset["moviepath"].str();
@ -852,7 +813,6 @@ wxwin_mainwindow::wxwin_mainwindow()
: wxFrame(NULL, wxID_ANY, getname(), wxDefaultPosition, wxSize(-1, -1),
wxMINIMIZE_BOX | wxSYSTEM_MENU | wxCAPTION | wxCLIP_CHILDREN | wxCLOSE_BOX)
{
broadcast_listener* blistener = new broadcast_listener(this);
Centre();
mwindow = NULL;
toplevel = new wxFlexGridSizer(1, 2, 0, 0);
@ -981,6 +941,14 @@ wxwin_mainwindow::wxwin_mainwindow()
menu_start(wxT("Help"));
menu_entry(wxID_ABOUT, wxT("About..."));
corechange.set(notify_core_change, []() { signal_core_change(); });
newcore.set(notify_new_core, []() { update_preferences(); });
unmuted.set(notify_sound_unmute, [this](bool unmute) {
runuifun([this, unmute]() { this->menu_check(wxID_AUDIO_ENABLED, unmute); });
});
modechange.set(notify_mode_change, [this](bool readonly) {
runuifun([this, readonly]() { this->menu_check(wxID_READONLY_MODE, readonly); });
});
gpanel->SetDropTarget(new loadfile(this));
spanel->SetDropTarget(new loadfile(this));
}

View file

@ -193,27 +193,10 @@ private:
}
}
};
struct refresh_listener : public information_dispatch
{
refresh_listener(wxwin_vumeter* v)
: information_dispatch("voicesub-editor-change-listner")
{
obj = v;
}
void on_vu_change()
{
wxwin_vumeter* _obj = obj;
if(!obj->update_sent) {
obj->update_sent = true;
runuifun([_obj]() -> void { _obj->refresh(); });
}
}
wxwin_vumeter* obj;
};
volatile bool update_sent;
bool closing;
wxButton* closebutton;
refresh_listener* rlistener;
struct dispatch_target<> vulistener;
_vupanel* vupanel;
wxStaticText* rate;
wxSlider* gamevol;
@ -267,13 +250,17 @@ wxwin_vumeter::wxwin_vumeter(wxWindow* parent)
top_s->SetSizeHints(this);
Fit();
rlistener = new refresh_listener(this);
vulistener.set(notify_vu_change, [this]() {
if(!this->update_sent) {
this->update_sent = true;
runuifun([this]() -> void { this->refresh(); });
}
});
refresh();
}
wxwin_vumeter::~wxwin_vumeter() throw()
{
delete rlistener;
}
void wxwin_vumeter::on_game_change(wxScrollEvent& e)