Merge branch 'rr1-maint'

This commit is contained in:
Ilari Liusvaara 2012-04-19 12:47:30 +03:00
commit 96cd83d1b2
17 changed files with 776 additions and 220 deletions

View file

@ -1,6 +1,8 @@
#ifndef _settings__hpp__included__ #ifndef _settings__hpp__included__
#define _settings__hpp__included__ #define _settings__hpp__included__
#include "core/window.hpp"
#include <string> #include <string>
#include <set> #include <set>
#include <stdexcept> #include <stdexcept>
@ -106,8 +108,22 @@ public:
* Get set of all settings. * Get set of all settings.
*/ */
static std::set<std::string> get_settings_set() throw(std::bad_alloc); static std::set<std::string> get_settings_set() throw(std::bad_alloc);
/**
* Lock holder
*/
struct lock_holder
{
lock_holder(setting* t) { (targ = t)->mut->lock(); }
~lock_holder() { targ->mut->unlock(); }
private:
setting* targ;
};
friend struct lock_holder;
protected: protected:
std::string settingname; std::string settingname;
private:
static setting* get_by_name(const std::string& name);
mutex* mut;
}; };
/** /**

View file

@ -31,6 +31,10 @@ struct mutex
* Create a mutex. The returned mutex can be deleted using delete. * Create a mutex. The returned mutex can be deleted using delete.
*/ */
static mutex& aquire() throw(std::bad_alloc); static mutex& aquire() throw(std::bad_alloc);
/**
* Create a recursive mutex. The returned mutex can be deleted using delete.
*/
static mutex& aquire_rec() throw(std::bad_alloc);
/** /**
* Destroy a mutex. * Destroy a mutex.
*/ */
@ -535,6 +539,9 @@ struct platform
static bool pausing_allowed; static bool pausing_allowed;
static double global_volume; static double global_volume;
static volatile bool do_exit_dummy_event_loop;
static void dummy_event_loop() throw();
static void exit_dummy_event_loop() throw();
}; };
class modal_pause_holder class modal_pause_holder

View file

@ -27,6 +27,7 @@ void bring_app_foreground();
std::string pick_archive_member(wxWindow* parent, const std::string& filename) throw(std::bad_alloc); std::string pick_archive_member(wxWindow* parent, const std::string& filename) throw(std::bad_alloc);
void boot_emulator(loaded_rom& rom, moviefile& movie); void boot_emulator(loaded_rom& rom, moviefile& movie);
void handle_wx_keyboard(wxKeyEvent& e, bool polarity); void handle_wx_keyboard(wxKeyEvent& e, bool polarity);
std::string map_keycode_to_key(int kcode);
void initialize_wx_keyboard(); void initialize_wx_keyboard();
void signal_program_exit(); void signal_program_exit();
void signal_resize_needed(); void signal_resize_needed();

View file

@ -1,6 +1,7 @@
#include "core/command.hpp" #include "core/command.hpp"
#include "core/globalwrap.hpp" #include "core/globalwrap.hpp"
#include "core/misc.hpp" #include "core/misc.hpp"
#include "core/window.hpp"
#include "library/minmax.hpp" #include "library/minmax.hpp"
#include "library/string.hpp" #include "library/string.hpp"
#include "library/zip.hpp" #include "library/zip.hpp"
@ -14,6 +15,24 @@ namespace
std::set<std::string> command_stack; std::set<std::string> command_stack;
std::map<std::string, std::list<std::string>> aliases; std::map<std::string, std::list<std::string>> aliases;
//Return the recursive mutex.
mutex& cmlock()
{
static mutex& m = mutex::aquire_rec();
return m;
}
class cmlock_hold
{
public:
cmlock_hold() { cmlock().lock(); }
~cmlock_hold() { cmlock().unlock(); }
private:
cmlock_hold(const cmlock_hold& k);
cmlock_hold& operator=(const cmlock_hold& k);
};
function_ptr_command<arg_filename> run_script("run-script", "run file as a script", function_ptr_command<arg_filename> run_script("run-script", "run file as a script",
"Syntax: run-script <file>\nRuns file <file> just as it would have been entered in the command line\n", "Syntax: run-script <file>\nRuns file <file> just as it would have been entered in the command line\n",
[](arg_filename filename) throw(std::bad_alloc, std::runtime_error) { [](arg_filename filename) throw(std::bad_alloc, std::runtime_error) {
@ -34,6 +53,7 @@ namespace
function_ptr_command<> show_aliases("show-aliases", "show aliases", function_ptr_command<> show_aliases("show-aliases", "show aliases",
"Syntax: show-aliases\nShow expansions of all aliases\n", "Syntax: show-aliases\nShow expansions of all aliases\n",
[]() throw(std::bad_alloc, std::runtime_error) { []() throw(std::bad_alloc, std::runtime_error) {
cmlock_hold lck;
for(auto i : aliases) for(auto i : aliases)
for(auto j : i.second) for(auto j : i.second)
messages << "alias " << i.first << " " << j << std::endl; messages << "alias " << i.first << " " << j << std::endl;
@ -45,6 +65,7 @@ namespace
auto r = regex("([^ \t]+)[ \t]*", t, "This command only takes one argument"); auto r = regex("([^ \t]+)[ \t]*", t, "This command only takes one argument");
if(!command::valid_alias_name(r[1])) if(!command::valid_alias_name(r[1]))
throw std::runtime_error("Illegal alias name"); throw std::runtime_error("Illegal alias name");
cmlock_hold lck;
aliases[r[1]].clear(); aliases[r[1]].clear();
messages << "Command '" << r[1] << "' unaliased" << std::endl; messages << "Command '" << r[1] << "' unaliased" << std::endl;
}); });
@ -56,6 +77,7 @@ namespace
auto r = regex("([^ \t]+)[ \t]+([^ \t].*)", t, "Alias name and command needed"); auto r = regex("([^ \t]+)[ \t]+([^ \t].*)", t, "Alias name and command needed");
if(!command::valid_alias_name(r[1])) if(!command::valid_alias_name(r[1]))
throw std::runtime_error("Illegal alias name"); throw std::runtime_error("Illegal alias name");
cmlock_hold lck;
aliases[r[1]].push_back(r[2]); aliases[r[1]].push_back(r[2]);
messages << "Command '" << r[1] << "' aliased to '" << r[2] << "'" << std::endl; messages << "Command '" << r[1] << "' aliased to '" << r[2] << "'" << std::endl;
}); });
@ -63,6 +85,7 @@ namespace
command::command(const std::string& cmd) throw(std::bad_alloc) command::command(const std::string& cmd) throw(std::bad_alloc)
{ {
cmlock_hold lck;
if(commands().count(cmd)) if(commands().count(cmd))
std::cerr << "WARNING: Command collision for " << cmd << "!" << std::endl; std::cerr << "WARNING: Command collision for " << cmd << "!" << std::endl;
commands()[commandname = cmd] = this; commands()[commandname = cmd] = this;
@ -70,6 +93,7 @@ command::command(const std::string& cmd) throw(std::bad_alloc)
command::~command() throw() command::~command() throw()
{ {
cmlock_hold lck;
commands().erase(commandname); commands().erase(commandname);
} }
@ -79,12 +103,14 @@ void command::invokeC(const std::string& cmd) throw()
std::string cmd2 = strip_CR(cmd); std::string cmd2 = strip_CR(cmd);
if(cmd2 == "?") { if(cmd2 == "?") {
//The special ? command. //The special ? command.
cmlock_hold lck;
for(auto i : commands()) for(auto i : commands())
messages << i.first << ": " << i.second->get_short_help() << std::endl; messages << i.first << ": " << i.second->get_short_help() << std::endl;
return; return;
} }
if(firstchar(cmd2) == '?') { if(firstchar(cmd2) == '?') {
//?command. //?command.
cmlock_hold lck;
std::string rcmd = cmd2.substr(1, min(cmd2.find_first_of(" \t"), cmd2.length())); std::string rcmd = cmd2.substr(1, min(cmd2.find_first_of(" \t"), cmd2.length()));
if(firstchar(rcmd) != '*') { if(firstchar(rcmd) != '*') {
//This may be an alias. //This may be an alias.
@ -109,21 +135,33 @@ void command::invokeC(const std::string& cmd) throw()
may_be_alias_expanded = false; may_be_alias_expanded = false;
cmd2 = cmd2.substr(1); cmd2 = cmd2.substr(1);
} }
if(may_be_alias_expanded && aliases.count(cmd2)) { //Now this gets painful as command handlers must not be invoked with lock held.
for(auto i : aliases[cmd2]) if(may_be_alias_expanded) {
std::list<std::string> aexp;
{
cmlock_hold lck;
if(!aliases.count(cmd))
goto not_alias;
aexp = aliases[cmd2];
}
for(auto i : aexp)
invokeC(i); invokeC(i);
return; return;
} }
not_alias:
try { try {
size_t split = cmd2.find_first_of(" \t"); size_t split = cmd2.find_first_of(" \t");
std::string rcmd = cmd2.substr(0, min(split, cmd2.length())); std::string rcmd = cmd2.substr(0, min(split, cmd2.length()));
std::string args = cmd2.substr(min(cmd2.find_first_not_of(" \t", split), cmd2.length())); std::string args = cmd2.substr(min(cmd2.find_first_not_of(" \t", split), cmd2.length()));
command* cmdh = NULL; command* cmdh = NULL;
if(!commands().count(rcmd)) { {
messages << "Unknown command '" << rcmd << "'" << std::endl; cmlock_hold lck;
return; if(!commands().count(rcmd)) {
messages << "Unknown command '" << rcmd << "'" << std::endl;
return;
}
cmdh = commands()[rcmd];
} }
cmdh = commands()[rcmd];
if(command_stack.count(cmd2)) if(command_stack.count(cmd2))
throw std::runtime_error("Recursive command invocation"); throw std::runtime_error("Recursive command invocation");
command_stack.insert(cmd2); command_stack.insert(cmd2);
@ -154,6 +192,7 @@ std::string command::get_long_help() throw(std::bad_alloc)
std::set<std::string> command::get_aliases() throw(std::bad_alloc) std::set<std::string> command::get_aliases() throw(std::bad_alloc)
{ {
cmlock_hold lck;
std::set<std::string> r; std::set<std::string> r;
for(auto i : aliases) for(auto i : aliases)
r.insert(i.first); r.insert(i.first);
@ -162,6 +201,7 @@ std::set<std::string> command::get_aliases() throw(std::bad_alloc)
std::string command::get_alias_for(const std::string& aname) throw(std::bad_alloc) std::string command::get_alias_for(const std::string& aname) throw(std::bad_alloc)
{ {
cmlock_hold lck;
if(!valid_alias_name(aname)) if(!valid_alias_name(aname))
return ""; return "";
if(aliases.count(aname)) { if(aliases.count(aname)) {
@ -175,6 +215,7 @@ std::string command::get_alias_for(const std::string& aname) throw(std::bad_allo
void command::set_alias_for(const std::string& aname, const std::string& avalue) throw(std::bad_alloc) void command::set_alias_for(const std::string& aname, const std::string& avalue) throw(std::bad_alloc)
{ {
cmlock_hold lck;
if(!valid_alias_name(aname)) if(!valid_alias_name(aname))
return; return;
std::list<std::string> newlist; std::list<std::string> newlist;

View file

@ -110,6 +110,27 @@ namespace
} }
} }
std::pair<bool, double> read() throw()
{
lock_holder lck(this);
return std::make_pair(target_infinite, target_fps);
}
void set_nominal_framerate(double fps)
{
lock_holder(this);
nominal_rate = fps;
if(target_nominal) {
target_fps = nominal_rate;
target_infinite = false;
}
}
double get_framerate()
{
lock_holder(this);
return 100.0 * get_realized_fps() / nominal_rate;
}
} targetfps; } targetfps;
bool turboed = false; bool turboed = false;
@ -151,16 +172,12 @@ void unfreeze_time(uint64_t curtime)
void set_nominal_framerate(double fps) throw() void set_nominal_framerate(double fps) throw()
{ {
nominal_rate = fps; targetfps.set_nominal_framerate(fps);
if(target_nominal) {
target_fps = nominal_rate;
target_infinite = false;
}
} }
double get_framerate() throw() double get_framerate() throw()
{ {
return 100.0 * get_realized_fps() / nominal_rate; return targetfps.get_framerate();
} }
void ack_frame_tick(uint64_t usec) throw() void ack_frame_tick(uint64_t usec) throw()
@ -171,22 +188,22 @@ void ack_frame_tick(uint64_t usec) throw()
uint64_t to_wait_frame(uint64_t usec) throw() uint64_t to_wait_frame(uint64_t usec) throw()
{ {
if(!frame_number || target_infinite || turboed) auto target = targetfps.read();
if(!frame_number || target.first || turboed)
return 0; return 0;
uint64_t lintime = get_time(usec, true); uint64_t lintime = get_time(usec, true);
uint64_t frame_lasted = lintime - frame_start_times[0]; uint64_t frame_lasted = lintime - frame_start_times[0];
uint64_t frame_should_last = 1000000 / (target_fps * nominal_rate / 100); uint64_t frame_should_last = 1000000 / (target.second * nominal_rate / 100);
if(frame_lasted >= frame_should_last) if(frame_lasted >= frame_should_last)
return 0; //We are late. return 0; //We are late.
uint64_t history_frames = min(frame_number, static_cast<uint64_t>(HISTORY_FRAMES)); uint64_t history_frames = min(frame_number, static_cast<uint64_t>(HISTORY_FRAMES));
uint64_t history_lasted = lintime - frame_start_times[history_frames - 1]; uint64_t history_lasted = lintime - frame_start_times[history_frames - 1];
uint64_t history_should_last = history_frames * 1000000 / (target_fps * nominal_rate / 100); uint64_t history_should_last = history_frames * 1000000 / (target.second * nominal_rate / 100);
if(history_lasted >= history_should_last) if(history_lasted >= history_should_last)
return 0; return 0;
return min(history_should_last - history_lasted, frame_should_last - frame_lasted); return min(history_should_last - history_lasted, frame_should_last - frame_lasted);
} }
uint64_t get_utime() uint64_t get_utime()
{ {
struct timeval tv; struct timeval tv;

View file

@ -78,6 +78,23 @@ namespace
globalwrap<std::map<std::string, std::string>> modifier_linkages; globalwrap<std::map<std::string, std::string>> modifier_linkages;
globalwrap<std::map<std::string, keygroup*>> keygroups; globalwrap<std::map<std::string, keygroup*>> keygroups;
//Return the recursive mutex.
mutex& kmlock()
{
static mutex& m = mutex::aquire_rec();
return m;
}
class kmlock_hold
{
public:
kmlock_hold() { kmlock().lock(); }
~kmlock_hold() { kmlock().unlock(); }
private:
kmlock_hold(const kmlock_hold& k);
kmlock_hold& operator=(const kmlock_hold& k);
};
//Returns orig if not linked. //Returns orig if not linked.
const modifier* get_linked_modifier(const modifier* orig) const modifier* get_linked_modifier(const modifier* orig)
{ {
@ -90,23 +107,27 @@ namespace
modifier::modifier(const std::string& name) throw(std::bad_alloc) modifier::modifier(const std::string& name) throw(std::bad_alloc)
{ {
kmlock_hold lck;
known_modifiers()[modname = name] = this; known_modifiers()[modname = name] = this;
} }
modifier::modifier(const std::string& name, const std::string& linkgroup) throw(std::bad_alloc) modifier::modifier(const std::string& name, const std::string& linkgroup) throw(std::bad_alloc)
{ {
kmlock_hold lck;
known_modifiers()[modname = name] = this; known_modifiers()[modname = name] = this;
modifier_linkages()[name] = linkgroup; modifier_linkages()[name] = linkgroup;
} }
modifier::~modifier() throw() modifier::~modifier() throw()
{ {
kmlock_hold lck;
known_modifiers().erase(modname); known_modifiers().erase(modname);
modifier_linkages().erase(modname); modifier_linkages().erase(modname);
} }
std::set<std::string> modifier::get_set() throw(std::bad_alloc) std::set<std::string> modifier::get_set() throw(std::bad_alloc)
{ {
kmlock_hold lck;
std::set<std::string> r; std::set<std::string> r;
for(auto i : known_modifiers()) for(auto i : known_modifiers())
r.insert(i.first); r.insert(i.first);
@ -115,6 +136,7 @@ std::set<std::string> modifier::get_set() throw(std::bad_alloc)
modifier& modifier::lookup(const std::string& name) throw(std::bad_alloc, std::runtime_error) modifier& modifier::lookup(const std::string& name) throw(std::bad_alloc, std::runtime_error)
{ {
kmlock_hold lck;
if(!known_modifiers().count(name)) { if(!known_modifiers().count(name)) {
std::ostringstream x; std::ostringstream x;
x << "Invalid modifier '" << name << "'"; x << "Invalid modifier '" << name << "'";
@ -125,11 +147,13 @@ modifier& modifier::lookup(const std::string& name) throw(std::bad_alloc, std::r
std::string modifier::name() const throw(std::bad_alloc) std::string modifier::name() const throw(std::bad_alloc)
{ {
kmlock_hold lck;
return modname; return modname;
} }
std::string modifier::linked_name() const throw(std::bad_alloc) std::string modifier::linked_name() const throw(std::bad_alloc)
{ {
kmlock_hold lck;
const modifier* p = get_linked_modifier(this); const modifier* p = get_linked_modifier(this);
if(p == this) if(p == this)
return ""; return "";
@ -139,18 +163,21 @@ std::string modifier::linked_name() const throw(std::bad_alloc)
void modifier_set::add(const modifier& mod, bool really) throw(std::bad_alloc) void modifier_set::add(const modifier& mod, bool really) throw(std::bad_alloc)
{ {
kmlock_hold lck;
if(really) if(really)
set.insert(&mod); set.insert(&mod);
} }
void modifier_set::remove(const modifier& mod, bool really) throw(std::bad_alloc) void modifier_set::remove(const modifier& mod, bool really) throw(std::bad_alloc)
{ {
kmlock_hold lck;
if(really) if(really)
set.erase(&mod); set.erase(&mod);
} }
modifier_set modifier_set::construct(const std::string& _modifiers) throw(std::bad_alloc, std::runtime_error) modifier_set modifier_set::construct(const std::string& _modifiers) throw(std::bad_alloc, std::runtime_error)
{ {
kmlock_hold lck;
modifier_set set; modifier_set set;
std::string modifiers = _modifiers; std::string modifiers = _modifiers;
while(modifiers != "") { while(modifiers != "") {
@ -169,6 +196,7 @@ modifier_set modifier_set::construct(const std::string& _modifiers) throw(std::b
bool modifier_set::valid(const modifier_set& set, const modifier_set& mask) throw(std::bad_alloc) bool modifier_set::valid(const modifier_set& set, const modifier_set& mask) throw(std::bad_alloc)
{ {
kmlock_hold lck;
//No element can be together with its linkage group. //No element can be together with its linkage group.
for(auto i : set.set) { for(auto i : set.set) {
const modifier* j = get_linked_modifier(i); const modifier* j = get_linked_modifier(i);
@ -191,6 +219,7 @@ bool modifier_set::valid(const modifier_set& set, const modifier_set& mask) thro
bool modifier_set::operator==(const modifier_set& m) const throw() bool modifier_set::operator==(const modifier_set& m) const throw()
{ {
kmlock_hold lck;
for(auto i : set) for(auto i : set)
if(!m.set.count(i)) if(!m.set.count(i))
return false; return false;
@ -202,6 +231,7 @@ bool modifier_set::operator==(const modifier_set& m) const throw()
std::ostream& operator<<(std::ostream& os, const modifier_set& m) std::ostream& operator<<(std::ostream& os, const modifier_set& m)
{ {
kmlock_hold lck;
os << "<modset:"; os << "<modset:";
for(auto i : m.set) for(auto i : m.set)
os << i->name() << " "; os << i->name() << " ";
@ -212,6 +242,7 @@ std::ostream& operator<<(std::ostream& os, const modifier_set& m)
bool modifier_set::triggers(const modifier_set& set, const modifier_set& trigger, const modifier_set& mask) bool modifier_set::triggers(const modifier_set& set, const modifier_set& trigger, const modifier_set& mask)
throw(std::bad_alloc) throw(std::bad_alloc)
{ {
kmlock_hold lck;
for(auto i : mask.set) { for(auto i : mask.set) {
bool ok = false; bool ok = false;
//OK iff at least one of: //OK iff at least one of:
@ -254,16 +285,19 @@ bool modifier_set::triggers(const modifier_set& set, const modifier_set& trigger
std::string keygroup::name() throw(std::bad_alloc) std::string keygroup::name() throw(std::bad_alloc)
{ {
kmlock_hold lck;
return keyname; return keyname;
} }
const std::string& keygroup::get_class() const std::string& keygroup::get_class()
{ {
kmlock_hold lck;
return clazz; return clazz;
} }
struct keygroup::parameters keygroup::get_parameters() struct keygroup::parameters keygroup::get_parameters()
{ {
kmlock_hold lck;
parameters p; parameters p;
p.ktype = ktype; p.ktype = ktype;
p.cal_left = cal_left; p.cal_left = cal_left;
@ -276,6 +310,7 @@ struct keygroup::parameters keygroup::get_parameters()
std::map<std::string, struct keygroup::parameters> keygroup::get_all_parameters() std::map<std::string, struct keygroup::parameters> keygroup::get_all_parameters()
{ {
kmlock_hold lck;
std::map<std::string, struct parameters> ret; std::map<std::string, struct parameters> ret;
for(auto i : keygroups()) for(auto i : keygroups())
ret[i.first] = i.second->get_parameters(); ret[i.first] = i.second->get_parameters();
@ -284,6 +319,7 @@ std::map<std::string, struct keygroup::parameters> keygroup::get_all_parameters(
keygroup::keygroup(const std::string& name, const std::string& _clazz, enum type t) throw(std::bad_alloc) keygroup::keygroup(const std::string& name, const std::string& _clazz, enum type t) throw(std::bad_alloc)
{ {
kmlock_hold lck;
keygroups()[keyname = name] = this; keygroups()[keyname = name] = this;
clazz = _clazz; clazz = _clazz;
ktype = t; ktype = t;
@ -298,11 +334,13 @@ keygroup::keygroup(const std::string& name, const std::string& _clazz, enum type
keygroup::~keygroup() throw() keygroup::~keygroup() throw()
{ {
kmlock_hold lck;
keygroups().erase(keyname); keygroups().erase(keyname);
} }
void keygroup::change_type(enum type t) throw() void keygroup::change_type(enum type t) throw()
{ {
kmlock_hold lck;
ktype = t; ktype = t;
state = 0; state = 0;
if(requests_hook) if(requests_hook)
@ -311,6 +349,7 @@ void keygroup::change_type(enum type t) throw()
void keygroup::request_hook_callback(bool state) void keygroup::request_hook_callback(bool state)
{ {
kmlock_hold lck;
requests_hook = state; requests_hook = state;
} }
@ -318,6 +357,7 @@ void keygroup::request_hook_callback(bool state)
std::pair<keygroup*, unsigned> keygroup::lookup(const std::string& name) throw(std::bad_alloc, std::pair<keygroup*, unsigned> keygroup::lookup(const std::string& name) throw(std::bad_alloc,
std::runtime_error) std::runtime_error)
{ {
kmlock_hold lck;
if(keygroups().count(name)) if(keygroups().count(name))
return std::make_pair(keygroups()[name], 0); return std::make_pair(keygroups()[name], 0);
std::string prefix = name; std::string prefix = name;
@ -344,6 +384,7 @@ std::pair<keygroup*, unsigned> keygroup::lookup(const std::string& name) throw(s
void keygroup::change_calibration(short left, short center, short right, double tolerance) void keygroup::change_calibration(short left, short center, short right, double tolerance)
{ {
kmlock_hold lck;
cal_left = left; cal_left = left;
cal_center = center; cal_center = center;
cal_right = right; cal_right = right;
@ -354,6 +395,7 @@ void keygroup::change_calibration(short left, short center, short right, double
double keygroup::compensate(short value) double keygroup::compensate(short value)
{ {
kmlock_hold lck;
if(ktype == KT_HAT || ktype == KT_KEY || ktype == KT_DISABLED || ktype == KT_MOUSE) if(ktype == KT_HAT || ktype == KT_KEY || ktype == KT_DISABLED || ktype == KT_MOUSE)
return value; //These can't be calibrated. return value; //These can't be calibrated.
if(value <= cal_left) if(value <= cal_left)
@ -370,6 +412,7 @@ double keygroup::compensate(short value)
double keygroup::compensate2(double value) double keygroup::compensate2(double value)
{ {
kmlock_hold lck;
switch(ktype) { switch(ktype) {
case KT_DISABLED: case KT_DISABLED:
case KT_MOUSE: case KT_MOUSE:
@ -398,6 +441,7 @@ double keygroup::compensate2(double value)
void keygroup::set_position(short pos, const modifier_set& modifiers) throw() void keygroup::set_position(short pos, const modifier_set& modifiers) throw()
{ {
kmlock_hold lck;
last_rawval = pos; last_rawval = pos;
if(requests_hook) if(requests_hook)
lua_callback_keyhook(keyname, get_parameters()); lua_callback_keyhook(keyname, get_parameters());
@ -461,26 +505,32 @@ void keygroup::set_position(short pos, const modifier_set& modifiers) throw()
void keygroup::run_listeners(const modifier_set& modifiers, unsigned subkey, bool polarity, bool really, double x) void keygroup::run_listeners(const modifier_set& modifiers, unsigned subkey, bool polarity, bool really, double x)
{ {
if(!really) std::string name;
return; modifier_set _modifiers = modifiers;
std::string name = keyname; {
if(ktype == KT_AXIS_PAIR && subkey == 0) if(!really)
name = name + "+"; return;
if(ktype == KT_AXIS_PAIR && subkey == 1) kmlock_hold lck;
name = name + "-"; name = keyname;
if(ktype == KT_HAT && subkey == 0) if(ktype == KT_AXIS_PAIR && subkey == 0)
name = name + "n"; name = name + "+";
if(ktype == KT_HAT && subkey == 1) if(ktype == KT_AXIS_PAIR && subkey == 1)
name = name + "e"; name = name + "-";
if(ktype == KT_HAT && subkey == 2) if(ktype == KT_HAT && subkey == 0)
name = name + "s"; name = name + "n";
if(ktype == KT_HAT && subkey == 3) if(ktype == KT_HAT && subkey == 1)
name = name + "w"; name = name + "e";
information_dispatch::do_key_event(modifiers, *this, subkey, polarity, name); if(ktype == KT_HAT && subkey == 2)
name = name + "s";
if(ktype == KT_HAT && subkey == 3)
name = name + "w";
}
information_dispatch::do_key_event(_modifiers, *this, subkey, polarity, name);
} }
keygroup* keygroup::lookup_by_name(const std::string& name) throw() keygroup* keygroup::lookup_by_name(const std::string& name) throw()
{ {
kmlock_hold lck;
if(keygroups().count(name)) if(keygroups().count(name))
return keygroups()[name]; return keygroups()[name];
else else
@ -489,6 +539,7 @@ keygroup* keygroup::lookup_by_name(const std::string& name) throw()
std::set<std::string> keygroup::get_axis_set() throw(std::bad_alloc) std::set<std::string> keygroup::get_axis_set() throw(std::bad_alloc)
{ {
kmlock_hold lck;
std::set<std::string> r; std::set<std::string> r;
for(auto i : keygroups()) { for(auto i : keygroups()) {
keygroup::parameters p = i.second->get_parameters(); keygroup::parameters p = i.second->get_parameters();
@ -514,6 +565,7 @@ std::set<std::string> keygroup::get_axis_set() throw(std::bad_alloc)
std::set<std::string> keygroup::get_keys() throw(std::bad_alloc) std::set<std::string> keygroup::get_keys() throw(std::bad_alloc)
{ {
kmlock_hold lck;
std::set<std::string> r; std::set<std::string> r;
for(auto i : keygroups()) { for(auto i : keygroups()) {
switch(i.second->ktype) { switch(i.second->ktype) {
@ -546,12 +598,12 @@ std::set<std::string> keygroup::get_keys() throw(std::bad_alloc)
signed keygroup::get_value() signed keygroup::get_value()
{ {
kmlock_hold lck;
return state; return state;
} }
namespace namespace
{ {
function_ptr_command<const std::string&> set_axis("set-axis", "Set mode of Joystick axis", function_ptr_command<const std::string&> set_axis("set-axis", "Set mode of Joystick axis",
"Syntax: set-axis <axis> <options>...\nKnown options: disabled, axis, axis-inverse, pressure0-\n" "Syntax: set-axis <axis> <options>...\nKnown options: disabled, axis, axis-inverse, pressure0-\n"
"pressure0+, pressure-0, pressure-+, pressure+0, pressure+-\nminus=<val>, zero=<val>, plus=<val>\n" "pressure0+, pressure-0, pressure-+, pressure+0, pressure+-\nminus=<val>, zero=<val>, plus=<val>\n"
@ -721,6 +773,7 @@ namespace
std::map<triple, keybind_data*>& keybindings() std::map<triple, keybind_data*>& keybindings()
{ {
kmlock_hold lck;
static std::map<triple, keybind_data*> x; static std::map<triple, keybind_data*> x;
return x; return x;
} }
@ -729,35 +782,42 @@ namespace
void keymapper::bind(std::string mod, std::string modmask, std::string keyname, std::string command) void keymapper::bind(std::string mod, std::string modmask, std::string keyname, std::string command)
throw(std::bad_alloc, std::runtime_error) throw(std::bad_alloc, std::runtime_error)
{ {
triple k(mod, modmask, keyname); {
modifier_set _mod = modifier_set::construct(mod); kmlock_hold lck;
modifier_set _modmask = modifier_set::construct(modmask); triple k(mod, modmask, keyname);
if(!modifier_set::valid(_mod, _modmask)) modifier_set _mod = modifier_set::construct(mod);
throw std::runtime_error("Invalid modifiers"); modifier_set _modmask = modifier_set::construct(modmask);
auto g = keygroup::lookup(keyname); if(!modifier_set::valid(_mod, _modmask))
if(!keybindings().count(k)) { throw std::runtime_error("Invalid modifiers");
keybindings()[k] = new keybind_data; auto g = keygroup::lookup(keyname);
keybindings()[k]->mod = _mod; if(!keybindings().count(k)) {
keybindings()[k]->modmask = _modmask; keybindings()[k] = new keybind_data;
keybindings()[k]->group = g.first; keybindings()[k]->mod = _mod;
keybindings()[k]->subkey = g.second; keybindings()[k]->modmask = _modmask;
keybindings()[k]->group = g.first;
keybindings()[k]->subkey = g.second;
}
keybindings()[k]->command = command;
} }
keybindings()[k]->command = command;
inverse_key::notify_update(mod + "/" + modmask + "|" + keyname, command); inverse_key::notify_update(mod + "/" + modmask + "|" + keyname, command);
} }
void keymapper::unbind(std::string mod, std::string modmask, std::string keyname) throw(std::bad_alloc, void keymapper::unbind(std::string mod, std::string modmask, std::string keyname) throw(std::bad_alloc,
std::runtime_error) std::runtime_error)
{ {
triple k(mod, modmask, keyname); {
if(!keybindings().count(k)) kmlock_hold lck;
throw std::runtime_error("Key is not bound"); triple k(mod, modmask, keyname);
delete keybindings()[k]; if(!keybindings().count(k))
keybindings().erase(k); throw std::runtime_error("Key is not bound");
delete keybindings()[k];
keybindings().erase(k);
}
inverse_key::notify_update(mod + "/" + modmask + "|" + keyname, ""); inverse_key::notify_update(mod + "/" + modmask + "|" + keyname, "");
} }
void keymapper::dumpbindings() throw(std::bad_alloc) void keymapper::dumpbindings() throw(std::bad_alloc)
{ {
kmlock_hold lck;
for(auto i : keybindings()) { for(auto i : keybindings()) {
messages << "bind-key "; messages << "bind-key ";
if(i.first.a != "" || i.first.b != "") if(i.first.a != "" || i.first.b != "")
@ -768,6 +828,7 @@ void keymapper::dumpbindings() throw(std::bad_alloc)
std::set<std::string> keymapper::get_bindings() throw(std::bad_alloc) std::set<std::string> keymapper::get_bindings() throw(std::bad_alloc)
{ {
kmlock_hold lck;
std::set<std::string> r; std::set<std::string> r;
for(auto i : keybindings()) for(auto i : keybindings())
r.insert(i.first.a + "/" + i.first.b + "|" + i.first.c); r.insert(i.first.a + "/" + i.first.b + "|" + i.first.c);
@ -776,6 +837,7 @@ std::set<std::string> keymapper::get_bindings() throw(std::bad_alloc)
std::string keymapper::get_command_for(const std::string& keyspec) throw(std::bad_alloc) std::string keymapper::get_command_for(const std::string& keyspec) throw(std::bad_alloc)
{ {
kmlock_hold lck;
triple k("", "", ""); triple k("", "", "");
try { try {
k = parse_to_triple(keyspec); k = parse_to_triple(keyspec);
@ -800,6 +862,7 @@ void keymapper::bind_for(const std::string& keyspec, const std::string& cmd) thr
inverse_key::inverse_key(const std::string& command, const std::string& name) throw(std::bad_alloc) inverse_key::inverse_key(const std::string& command, const std::string& name) throw(std::bad_alloc)
{ {
kmlock_hold lck;
cmd = command; cmd = command;
oname = name; oname = name;
ikeys().insert(this); ikeys().insert(this);
@ -813,44 +876,52 @@ inverse_key::inverse_key(const std::string& command, const std::string& name) th
inverse_key::~inverse_key() inverse_key::~inverse_key()
{ {
kmlock_hold lck;
ikeys().erase(this); ikeys().erase(this);
forkey().erase(cmd); forkey().erase(cmd);
} }
std::set<inverse_key*> inverse_key::get_ikeys() throw(std::bad_alloc) std::set<inverse_key*> inverse_key::get_ikeys() throw(std::bad_alloc)
{ {
kmlock_hold lck;
return ikeys(); return ikeys();
} }
std::string inverse_key::getname() throw(std::bad_alloc) std::string inverse_key::getname() throw(std::bad_alloc)
{ {
kmlock_hold lck;
return oname; return oname;
} }
inverse_key* inverse_key::get_for(const std::string& command) throw(std::bad_alloc) inverse_key* inverse_key::get_for(const std::string& command) throw(std::bad_alloc)
{ {
kmlock_hold lck;
return forkey().count(command) ? forkey()[command] : NULL; return forkey().count(command) ? forkey()[command] : NULL;
} }
std::set<inverse_key*>& inverse_key::ikeys() std::set<inverse_key*>& inverse_key::ikeys()
{ {
kmlock_hold lck;
static std::set<inverse_key*> x; static std::set<inverse_key*> x;
return x; return x;
} }
std::map<std::string, inverse_key*>& inverse_key::forkey() std::map<std::string, inverse_key*>& inverse_key::forkey()
{ {
kmlock_hold lck;
static std::map<std::string, inverse_key*> x; static std::map<std::string, inverse_key*> x;
return x; return x;
} }
std::string inverse_key::get(bool primary) throw(std::bad_alloc) std::string inverse_key::get(bool primary) throw(std::bad_alloc)
{ {
kmlock_hold lck;
return primary ? primary_spec : secondary_spec; return primary ? primary_spec : secondary_spec;
} }
void inverse_key::clear(bool primary) throw(std::bad_alloc) void inverse_key::clear(bool primary) throw(std::bad_alloc)
{ {
kmlock_hold lck;
if(primary) { if(primary) {
if(primary_spec != "") if(primary_spec != "")
keymapper::bind_for(primary_spec, ""); keymapper::bind_for(primary_spec, "");
@ -870,6 +941,7 @@ void inverse_key::clear(bool primary) throw(std::bad_alloc)
void inverse_key::set(std::string keyspec, bool primary) throw(std::bad_alloc) void inverse_key::set(std::string keyspec, bool primary) throw(std::bad_alloc)
{ {
kmlock_hold lck;
if(keyspec == "") { if(keyspec == "") {
clear(primary); clear(primary);
return; return;
@ -891,6 +963,7 @@ void inverse_key::set(std::string keyspec, bool primary) throw(std::bad_alloc)
void inverse_key::addkey(const std::string& keyspec) void inverse_key::addkey(const std::string& keyspec)
{ {
kmlock_hold lck;
if(primary_spec == "" || primary_spec == keyspec) if(primary_spec == "" || primary_spec == keyspec)
primary_spec = keyspec; primary_spec = keyspec;
else if(secondary_spec == "") else if(secondary_spec == "")
@ -899,6 +972,7 @@ void inverse_key::addkey(const std::string& keyspec)
void inverse_key::notify_update(const std::string& keyspec, const std::string& command) void inverse_key::notify_update(const std::string& keyspec, const std::string& command)
{ {
kmlock_hold lck;
for(auto k : ikeys()) { for(auto k : ikeys()) {
bool u = false; bool u = false;
if(k->primary_spec == keyspec || k->secondary_spec == keyspec) { if(k->primary_spec == keyspec || k->secondary_spec == keyspec) {

View file

@ -81,6 +81,7 @@ namespace
} }
operator std::string() throw() operator std::string() throw()
{ {
lock_holder lck(this);
if(_set) if(_set)
return prefix + "-"; return prefix + "-";
else else

View file

@ -50,24 +50,55 @@ namespace
messages << i << ": " << setting::get(i) << std::endl; messages << i << ": " << setting::get(i) << std::endl;
} }
}); });
//Return the mutex.
mutex& stlock()
{
static mutex& m = mutex::aquire();
return m;
}
class stlock_hold
{
public:
stlock_hold() { stlock().lock(); }
~stlock_hold() { stlock().unlock(); }
private:
stlock_hold(const stlock_hold& k);
stlock_hold& operator=(const stlock_hold& k);
};
} }
setting::setting(const std::string& name) throw(std::bad_alloc) setting::setting(const std::string& name) throw(std::bad_alloc)
{ {
stlock_hold lck;
mut = &mutex::aquire();
settings()[settingname = name] = this; settings()[settingname = name] = this;
} }
setting::~setting() throw() setting::~setting() throw()
{ {
stlock_hold lck;
delete mut;
settings().erase(settingname); settings().erase(settingname);
} }
setting* setting::get_by_name(const std::string& name)
{
stlock_hold lck;
if(!settings().count(name))
throw std::runtime_error("No such setting '" + name + "'");
return settings()[name];
}
void setting::set(const std::string& _setting, const std::string& value) throw(std::bad_alloc, std::runtime_error) void setting::set(const std::string& _setting, const std::string& value) throw(std::bad_alloc, std::runtime_error)
{ {
if(!settings().count(_setting)) setting* tochange = get_by_name(_setting);
throw std::runtime_error("No such setting '" + _setting + "'");
try { try {
settings()[_setting]->set(value); {
lock_holder lck(tochange);
tochange->set(value);
}
information_dispatch::do_setting_change(_setting, value); information_dispatch::do_setting_change(_setting, value);
} catch(std::bad_alloc& e) { } catch(std::bad_alloc& e) {
throw; throw;
@ -83,10 +114,12 @@ bool setting::blank(bool really) throw(std::bad_alloc, std::runtime_error)
bool setting::blankable(const std::string& _setting) throw(std::bad_alloc, std::runtime_error) bool setting::blankable(const std::string& _setting) throw(std::bad_alloc, std::runtime_error)
{ {
if(!settings().count(_setting)) setting* tochange = get_by_name(_setting);
throw std::runtime_error("No such setting '" + _setting + "'");
try { try {
return settings()[_setting]->blank(false); {
lock_holder lck(tochange);
return tochange->blank(false);
}
} catch(...) { } catch(...) {
return false; return false;
} }
@ -94,11 +127,13 @@ bool setting::blankable(const std::string& _setting) throw(std::bad_alloc, std::
void setting::blank(const std::string& _setting) throw(std::bad_alloc, std::runtime_error) void setting::blank(const std::string& _setting) throw(std::bad_alloc, std::runtime_error)
{ {
if(!settings().count(_setting)) setting* tochange = get_by_name(_setting);
throw std::runtime_error("No such setting '" + _setting + "'");
try { try {
if(!settings()[_setting]->blank(true)) {
throw std::runtime_error("This setting can't be cleared"); lock_holder lck(tochange);
if(!tochange->blank(true))
throw std::runtime_error("This setting can't be cleared");
}
information_dispatch::do_setting_clear(_setting); information_dispatch::do_setting_clear(_setting);
} catch(std::bad_alloc& e) { } catch(std::bad_alloc& e) {
throw; throw;
@ -109,16 +144,20 @@ void setting::blank(const std::string& _setting) throw(std::bad_alloc, std::runt
std::string setting::get(const std::string& _setting) throw(std::bad_alloc, std::runtime_error) std::string setting::get(const std::string& _setting) throw(std::bad_alloc, std::runtime_error)
{ {
if(!settings().count(_setting)) setting* tochange = get_by_name(_setting);
throw std::runtime_error("No such setting '" + _setting + "'"); {
return settings()[_setting]->get(); lock_holder lck(tochange);
return tochange->get();
}
} }
bool setting::is_set(const std::string& _setting) throw(std::bad_alloc, std::runtime_error) bool setting::is_set(const std::string& _setting) throw(std::bad_alloc, std::runtime_error)
{ {
if(!settings().count(_setting)) setting* tochange = get_by_name(_setting);
throw std::runtime_error("No such setting '" + _setting + "'"); {
return settings()[_setting]->is_set(); lock_holder lck(tochange);
return tochange->is_set();
}
} }
std::set<std::string> setting::get_settings_set() throw(std::bad_alloc) std::set<std::string> setting::get_settings_set() throw(std::bad_alloc)
@ -164,6 +203,7 @@ std::string numeric_setting::get() throw(std::bad_alloc)
numeric_setting::operator int32_t() throw() numeric_setting::operator int32_t() throw()
{ {
lock_holder lck(this);
return value; return value;
} }
@ -202,6 +242,7 @@ std::string boolean_setting::get() throw(std::bad_alloc)
boolean_setting::operator bool() throw() boolean_setting::operator bool() throw()
{ {
lock_holder lck(this);
return value; return value;
} }
@ -244,5 +285,6 @@ std::string path_setting::get() throw(std::bad_alloc)
path_setting::operator std::string() path_setting::operator std::string()
{ {
lock_holder lck(this);
return path; return path;
} }

View file

@ -13,6 +13,8 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <deque> #include <deque>
#include <sys/time.h>
#include <unistd.h>
#include <boost/iostreams/categories.hpp> #include <boost/iostreams/categories.hpp>
#include <boost/iostreams/copy.hpp> #include <boost/iostreams/copy.hpp>
#include <boost/iostreams/stream.hpp> #include <boost/iostreams/stream.hpp>
@ -118,6 +120,7 @@ keypress::keypress(modifier_set mod, keygroup& _key, keygroup& _key2, short _val
value = _value; value = _value;
} }
volatile bool platform::do_exit_dummy_event_loop = false;
namespace namespace
{ {
@ -298,6 +301,7 @@ bool platform::is_sound_enabled() throw()
void platform::init() void platform::init()
{ {
do_exit_dummy_event_loop = false;
msgbuf.register_handler(msg_callback_obj); msgbuf.register_handler(msg_callback_obj);
system_log.open("lsnes.log", std::ios_base::out | std::ios_base::app); system_log.open("lsnes.log", std::ios_base::out | std::ios_base::app);
time_t curtime = time(NULL); time_t curtime = time(NULL);
@ -449,6 +453,24 @@ namespace
#define MAXWAIT 100000ULL #define MAXWAIT 100000ULL
void platform::dummy_event_loop() throw()
{
init_threading();
while(!do_exit_dummy_event_loop) {
mutex::holder h(*queue_lock);
internal_run_queues(true);
queue_condition->wait(MAXWAIT);
}
}
void platform::exit_dummy_event_loop() throw()
{
init_threading();
do_exit_dummy_event_loop = true;
mutex::holder h(*queue_lock);
queue_condition->signal();
usleep(200000);
}
void platform::flush_command_queue() throw() void platform::flush_command_queue() throw()
{ {

View file

@ -24,6 +24,11 @@ mutex& mutex::aquire() throw(std::bad_alloc)
return *new dummy_mutex(); return *new dummy_mutex();
} }
mutex& mutex::aquire_rec() throw(std::bad_alloc)
{
return *new dummy_mutex();
}
struct dummy_condition : public condition struct dummy_condition : public condition
{ {
dummy_condition(mutex& m); dummy_condition(mutex& m);

View file

@ -208,9 +208,6 @@ namespace
unsigned long axes[(ABS_MAX + div) / div] = {0}; unsigned long axes[(ABS_MAX + div) / div] = {0};
unsigned long evtypes[(EV_MAX + div) / div] = {0}; unsigned long evtypes[(EV_MAX + div) / div] = {0};
char namebuffer[256]; char namebuffer[256];
unsigned button_count = 0;
unsigned axis_count = 0;
unsigned hat_count = 0;
if(ioctl(fd, EVIOCGBIT(0, sizeof(evtypes)), evtypes) < 0) { if(ioctl(fd, EVIOCGBIT(0, sizeof(evtypes)), evtypes) < 0) {
int merrno = errno; int merrno = errno;
messages << "Error probing joystick (evmap; " << filename << "): " << strerror(merrno) messages << "Error probing joystick (evmap; " << filename << "): " << strerror(merrno)
@ -240,13 +237,10 @@ namespace
return false; return false;
} }
joystick_create(fd, namebuffer); joystick_create(fd, namebuffer);
for(unsigned i = 0; i <= KEY_MAX; i++) { for(unsigned i = 0; i <= KEY_MAX; i++)
if(keys[i / div] & (1ULL << (i % div))) { if(keys[i / div] & (1ULL << (i % div)))
joystick_new_button(fd, i, get_button_name(i)); joystick_new_button(fd, i, get_button_name(i));
button_count++; for(unsigned i = 0; i <= ABS_MAX; i++)
}
}
for(unsigned i = 0; i <= ABS_MAX; i++) {
if(axes[i / div] & (1ULL << (i % div))) { if(axes[i / div] & (1ULL << (i % div))) {
if(i < ABS_HAT0X || i > ABS_HAT3Y) { if(i < ABS_HAT0X || i > ABS_HAT3Y) {
int32_t V[5]; int32_t V[5];
@ -258,13 +252,9 @@ namespace
} }
joystick_new_axis(fd, i, V[1], V[2], get_axis_name(i), joystick_new_axis(fd, i, V[1], V[2], get_axis_name(i),
(V[1] < 0) ? keygroup::KT_AXIS_PAIR : keygroup::KT_PRESSURE_MP); (V[1] < 0) ? keygroup::KT_AXIS_PAIR : keygroup::KT_PRESSURE_MP);
axis_count++; } else if(i % 2 == 0)
} else if(i % 2 == 0) {
joystick_new_hat(fd, i, i + 1, 1, get_axis_name(i), get_axis_name(i + 1)); joystick_new_hat(fd, i, i + 1, 1, get_axis_name(i), get_axis_name(i + 1));
hat_count++;
}
} }
}
joystick_message(fd); joystick_message(fd);
return true; return true;
} }

View file

@ -13,6 +13,18 @@ struct sdl_mutex : public mutex
SDL_mutex* m; SDL_mutex* m;
}; };
struct sdl_rec_mutex : public mutex
{
sdl_rec_mutex() throw(std::bad_alloc);
~sdl_rec_mutex() throw();
void lock() throw();
void unlock() throw();
SDL_mutex* m;
volatile bool locked;
uint32_t owner;
uint32_t count;
};
sdl_mutex::sdl_mutex() throw(std::bad_alloc) sdl_mutex::sdl_mutex() throw(std::bad_alloc)
{ {
m = SDL_CreateMutex(); m = SDL_CreateMutex();
@ -25,6 +37,21 @@ sdl_mutex::~sdl_mutex() throw()
SDL_DestroyMutex(m); SDL_DestroyMutex(m);
} }
sdl_rec_mutex::sdl_rec_mutex() throw(std::bad_alloc)
{
m = SDL_CreateMutex();
if(!m)
throw std::bad_alloc();
locked = false;
owner = 0;
count = 0;
}
sdl_rec_mutex::~sdl_rec_mutex() throw()
{
SDL_DestroyMutex(m);
}
void sdl_mutex::lock() throw() void sdl_mutex::lock() throw()
{ {
SDL_mutexP(m); SDL_mutexP(m);
@ -35,11 +62,42 @@ void sdl_mutex::unlock() throw()
SDL_mutexV(m); SDL_mutexV(m);
} }
void sdl_rec_mutex::lock() throw()
{
uint32_t our_id = SDL_ThreadID();
if(locked && owner == our_id) {
//Owned by us, increment lock count.
++count;
return;
}
SDL_mutexP(m);
locked = true;
owner = our_id;
count = 1;
}
void sdl_rec_mutex::unlock() throw()
{
uint32_t our_id = SDL_ThreadID();
if(!locked || owner != our_id)
std::cerr << "Warning: Trying to unlock recursive lock locked by another thread!" << std::endl;
if(!--count) {
locked = false;
owner = 0;
SDL_mutexV(m);
}
}
mutex& mutex::aquire() throw(std::bad_alloc) mutex& mutex::aquire() throw(std::bad_alloc)
{ {
return *new sdl_mutex; return *new sdl_mutex;
} }
mutex& mutex::aquire_rec() throw(std::bad_alloc)
{
return *new sdl_rec_mutex;
}
struct sdl_condition : public condition struct sdl_condition : public condition
{ {
sdl_condition(mutex& m) throw(std::bad_alloc); sdl_condition(mutex& m) throw(std::bad_alloc);

View file

@ -283,6 +283,17 @@ namespace
} }
} }
std::string map_keycode_to_key(int kcode)
{
key_entry* k = keys;
while(k->name) {
if(k->keynum == kcode)
return k->name;
k++;
}
return "";
}
void handle_wx_keyboard(wxKeyEvent& e, bool polarity) void handle_wx_keyboard(wxKeyEvent& e, bool polarity)
{ {
int mods = e.GetModifiers(); int mods = e.GetModifiers();

View file

@ -29,6 +29,7 @@
#include <wx/event.h> #include <wx/event.h>
#include <wx/control.h> #include <wx/control.h>
#include <wx/combobox.h> #include <wx/combobox.h>
#include <wx/cmdline.h>
#define UISERV_RESIZED 9991 #define UISERV_RESIZED 9991
#define UISERV_UIFUN 9992 #define UISERV_UIFUN 9992
@ -232,6 +233,13 @@ end:
std::ofstream lsave(get_config_path() + "/" + our_rom_name + ".ls"); std::ofstream lsave(get_config_path() + "/" + our_rom_name + ".ls");
lsave << last_save; lsave << last_save;
} }
void* eloop_helper(void* x)
{
platform::dummy_event_loop();
return NULL;
}
} }
wxString towxstring(const std::string& str) throw(std::bad_alloc) wxString towxstring(const std::string& str) throw(std::bad_alloc)
@ -287,18 +295,53 @@ void graphics_plugin::quit() throw()
{ {
} }
static const wxCmdLineEntryDesc dummy_descriptor_table[] = {
{ wxCMD_LINE_PARAM, NULL, NULL, NULL, wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL |
wxCMD_LINE_PARAM_MULTIPLE },
{ wxCMD_LINE_NONE }
};
class lsnes_app : public wxApp class lsnes_app : public wxApp
{ {
public: public:
lsnes_app();
virtual bool OnInit(); virtual bool OnInit();
virtual int OnExit(); virtual int OnExit();
virtual void OnInitCmdLine(wxCmdLineParser& parser);
virtual bool OnCmdLineParsed(wxCmdLineParser& parser);
private:
bool settings_mode;
}; };
IMPLEMENT_APP(lsnes_app) IMPLEMENT_APP(lsnes_app)
lsnes_app::lsnes_app()
{
settings_mode = false;
}
void lsnes_app::OnInitCmdLine(wxCmdLineParser& parser)
{
parser.SetDesc(dummy_descriptor_table);
parser.SetSwitchChars(wxT(""));
}
bool lsnes_app::OnCmdLineParsed(wxCmdLineParser& parser)
{
std::vector<std::string> cmdline;
for(size_t i = 0; i< parser.GetParamCount(); i++)
cmdline.push_back(tostdstring(parser.GetParam(i)));
for(auto i: cmdline) {
if(i == "--settings")
settings_mode = true;
}
}
bool lsnes_app::OnInit() bool lsnes_app::OnInit()
{ {
wxApp::OnInit();
reached_main(); reached_main();
set_random_seed(); set_random_seed();
bring_app_foreground(); bring_app_foreground();
@ -309,7 +352,6 @@ bool lsnes_app::OnInit()
ui_thread = &thread_id::me(); ui_thread = &thread_id::me();
platform::init(); platform::init();
init_lua();
messages << "BSNES version: " << emucore_get_version() << std::endl; messages << "BSNES version: " << emucore_get_version() << std::endl;
messages << "lsnes version: lsnes rr" << lsnes_version << std::endl; messages << "lsnes version: lsnes rr" << lsnes_version << std::endl;
@ -323,6 +365,21 @@ bool lsnes_app::OnInit()
command::invokeC("run-script " + cfgpath + "/lsneswxw.rc"); command::invokeC("run-script " + cfgpath + "/lsneswxw.rc");
messages << "--- End running lsnesrc --- " << std::endl; messages << "--- End running lsnesrc --- " << std::endl;
if(settings_mode) {
//We got to boot this up quite a bit to get the joystick driver working.
//In practicular, we need joystick thread and emulator thread in pause.
joystick_thread_handle = &thread::create(joystick_thread, NULL);
thread* dummy_loop = &thread::create(eloop_helper, NULL);
wxsetingsdialog_display(NULL);
platform::exit_dummy_event_loop();
joystick_plugin::signal();
joystick_thread_handle->join();
dummy_loop->join();
save_configuration();
return false;
}
init_lua();
joystick_thread_handle = &thread::create(joystick_thread, NULL); joystick_thread_handle = &thread::create(joystick_thread, NULL);
msg_window = new wxwin_messages(); msg_window = new wxwin_messages();
@ -335,12 +392,14 @@ bool lsnes_app::OnInit()
int lsnes_app::OnExit() int lsnes_app::OnExit()
{ {
if(settings_mode)
return 0;
//NULL these so no further messages will be sent. //NULL these so no further messages will be sent.
msg_window = NULL; msg_window = NULL;
main_window = NULL; main_window = NULL;
save_configuration();
information_dispatch::do_dump_end(); information_dispatch::do_dump_end();
rrdata::close(); rrdata::close();
save_configuration();
joystick_plugin::signal(); joystick_plugin::signal();
joystick_thread_handle->join(); joystick_thread_handle->join();
platform::quit(); platform::quit();

View file

@ -210,9 +210,9 @@ namespace
{ {
std::string v = (stringfmt() << target).str(); std::string v = (stringfmt() << target).str();
if(target < 0) if(target < 0)
runemufn([]() { setting::set("targetfps", "infinite"); }); setting::set("targetfps", "infinite");
else else
runemufn([v]() { setting::set("targetfps", v); }); setting::set("targetfps", v);
} }
class controller_autohold_menu : public wxMenu class controller_autohold_menu : public wxMenu
@ -452,9 +452,7 @@ namespace
std::string movie_path() std::string movie_path()
{ {
std::string x; return setting::get("moviepath");
runemufn([&x]() { x = setting::get("moviepath"); });
return x;
} }
} }
@ -962,13 +960,14 @@ void wxwin_mainwindow::handle_menu_click_cancelable(wxCommandEvent& e)
return; return;
} }
case wxID_SET_SPEED: { case wxID_SET_SPEED: {
std::string value;
bool bad = false; bool bad = false;
runemufn([&value]() { value = setting::is_set("targetfps") ? setting::get("targetfps") : ""; }); std::string value = setting::is_set("targetfps") ? setting::get("targetfps") : "";
value = pick_text(this, "Set speed", "Enter percentage speed (or \"infinite\"):", value); value = pick_text(this, "Set speed", "Enter percentage speed (or \"infinite\"):", value);
runemufn([&bad, &value]() { try { setting::set("targetfps", value); } catch(...) { bad = true; } }); try {
if(bad) setting::set("targetfps", value);
} catch(...) {
wxMessageBox(wxT("Invalid speed"), _T("Error"), wxICON_EXCLAMATION | wxOK, this); wxMessageBox(wxT("Invalid speed"), _T("Error"), wxICON_EXCLAMATION | wxOK, this);
}
return; return;
} }
case wxID_SET_VOLUME: { case wxID_SET_VOLUME: {

View file

@ -46,6 +46,154 @@ const char* scalealgo_choices[] = {"Fast Bilinear", "Bilinear", "Bicubic", "Expe
namespace namespace
{ {
class wxdialog_pressbutton;
volatile bool keygrab_active = false;
std::string pkey;
wxdialog_pressbutton* presser = NULL;
void report_grab_key(const std::string& name);
class keygrabber : public information_dispatch
{
public:
keygrabber() : information_dispatch("wxwdigets-key-grabber") { keygrab_active = false; }
void on_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey,
bool polarity, const std::string& name)
{
if(!keygrab_active)
return;
if(polarity)
pkey = name;
else {
if(pkey == name) {
keygrab_active = false;
runuifun([pkey]() { report_grab_key(pkey); });
} else
pkey = "";
}
}
} keygrabber;
class wxdialog_pressbutton : public wxDialog
{
public:
wxdialog_pressbutton(wxWindow* parent, const std::string& title);
std::string getkey() { return key; }
void on_mouse(wxMouseEvent& e);
void on_keyboard_up(wxKeyEvent& e);
void on_keyboard_down(wxKeyEvent& e);
void dismiss_with(const std::string& k);
private:
bool handle_mousebtn(wxMouseEvent& e, bool(wxMouseEvent::*down)()const, bool(wxMouseEvent::*up)()const,
const std::string& k, int flag);
std::string key;
int mouseflag;
int lastkbdkey;
};
void report_grab_key(const std::string& name)
{
presser->dismiss_with(name);
}
int vert_padding = 40;
int horiz_padding = 60;
wxdialog_pressbutton::wxdialog_pressbutton(wxWindow* parent, const std::string& title)
: wxDialog(parent, wxID_ANY, towxstring(title), wxDefaultPosition, wxSize(-1, -1))
{
wxStaticText* t;
wxBoxSizer* s2 = new wxBoxSizer(wxVERTICAL);
wxPanel* p = new wxPanel(this, wxID_ANY);
s2->Add(p, 1, wxGROW);
lastkbdkey = -1;
mouseflag = 0;
Centre();
wxFlexGridSizer* s = new wxFlexGridSizer(3, 3, 0, 0);
p->SetSizer(s);
SetSizer(s2);
s->Add(horiz_padding, vert_padding);
s->Add(0, 0);
s->Add(0, 0);
s->Add(0, 0);
s->Add(t = new wxStaticText(p, wxID_ANY, wxT("Press the key to assign")), 1, wxGROW);
s->Add(0, 0);
s->Add(0, 0);
s->Add(0, 0);
s->Add(horiz_padding, vert_padding);
p->SetFocus();
p->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(wxdialog_pressbutton::on_keyboard_down), NULL, this);
p->Connect(wxEVT_KEY_UP, wxKeyEventHandler(wxdialog_pressbutton::on_keyboard_up), NULL, this);
p->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxdialog_pressbutton::on_mouse), NULL, this);
p->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxdialog_pressbutton::on_mouse), NULL, this);
p->Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(wxdialog_pressbutton::on_mouse), NULL, this);
p->Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(wxdialog_pressbutton::on_mouse), NULL, this);
p->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(wxdialog_pressbutton::on_mouse), NULL, this);
p->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(wxdialog_pressbutton::on_mouse), NULL, this);
t->Connect(wxEVT_KEY_DOWN, wxKeyEventHandler(wxdialog_pressbutton::on_keyboard_down), NULL, this);
t->Connect(wxEVT_KEY_UP, wxKeyEventHandler(wxdialog_pressbutton::on_keyboard_up), NULL, this);
t->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(wxdialog_pressbutton::on_mouse), NULL, this);
t->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(wxdialog_pressbutton::on_mouse), NULL, this);
t->Connect(wxEVT_MIDDLE_DOWN, wxMouseEventHandler(wxdialog_pressbutton::on_mouse), NULL, this);
t->Connect(wxEVT_MIDDLE_UP, wxMouseEventHandler(wxdialog_pressbutton::on_mouse), NULL, this);
t->Connect(wxEVT_RIGHT_DOWN, wxMouseEventHandler(wxdialog_pressbutton::on_mouse), NULL, this);
t->Connect(wxEVT_RIGHT_UP, wxMouseEventHandler(wxdialog_pressbutton::on_mouse), NULL, this);
presser = this;
keygrab_active = true;
s->SetSizeHints(this);
Fit();
}
bool wxdialog_pressbutton::handle_mousebtn(wxMouseEvent& e, bool(wxMouseEvent::*down)()const,
bool(wxMouseEvent::*up)()const, const std::string& k, int flag)
{
if((e.*down)())
mouseflag = flag;
if((e.*up)()) {
if(mouseflag == flag) {
dismiss_with(k);
return true;
} else
mouseflag = 0;
}
return false;
}
void wxdialog_pressbutton::on_mouse(wxMouseEvent& e)
{
handle_mousebtn(e, &wxMouseEvent::LeftDown, &wxMouseEvent::LeftUp, "mouse_left", 1);
handle_mousebtn(e, &wxMouseEvent::MiddleDown, &wxMouseEvent::MiddleUp, "mouse_center", 2);
handle_mousebtn(e, &wxMouseEvent::RightDown, &wxMouseEvent::RightUp, "mouse_right", 3);
}
void wxdialog_pressbutton::on_keyboard_down(wxKeyEvent& e)
{
lastkbdkey = e.GetKeyCode();
mouseflag = 0;
}
void wxdialog_pressbutton::on_keyboard_up(wxKeyEvent& e)
{
int kcode = e.GetKeyCode();
if(lastkbdkey == kcode) {
dismiss_with(map_keycode_to_key(kcode));
} else {
lastkbdkey = -1;
mouseflag = 0;
}
}
void wxdialog_pressbutton::dismiss_with(const std::string& k)
{
if(k == "")
return;
if(key == "") {
keygrab_active = false;
key = k;
EndModal(wxID_OK);
}
}
struct keyentry_mod_data struct keyentry_mod_data
{ {
wxCheckBox* pressed; wxCheckBox* pressed;
@ -62,6 +210,7 @@ namespace
void on_ok(wxCommandEvent& e); void on_ok(wxCommandEvent& e);
void on_cancel(wxCommandEvent& e); void on_cancel(wxCommandEvent& e);
void on_clear(wxCommandEvent& e); void on_clear(wxCommandEvent& e);
void on_pressbutton(wxCommandEvent& e);
void on_classchange(wxCommandEvent& e); void on_classchange(wxCommandEvent& e);
std::string getkey(); std::string getkey();
private: private:
@ -73,11 +222,13 @@ namespace
void set_class(const std::string& _class); void set_class(const std::string& _class);
std::map<std::string, keyentry_mod_data> modifiers; std::map<std::string, keyentry_mod_data> modifiers;
std::map<std::string, std::set<std::string>> classes; std::map<std::string, std::set<std::string>> classes;
std::string wtitle;
std::string currentclass; std::string currentclass;
wxFlexGridSizer* top_s; wxFlexGridSizer* top_s;
wxFlexGridSizer* t_s; wxFlexGridSizer* t_s;
wxComboBox* mainclass; wxComboBox* mainclass;
wxComboBox* mainkey; wxComboBox* mainkey;
wxButton* press;
wxButton* ok; wxButton* ok;
wxButton* cancel; wxButton* cancel;
wxButton* clear; wxButton* clear;
@ -92,19 +243,19 @@ namespace
wxString emptystring; wxString emptystring;
std::set<std::string> mods, keys; std::set<std::string> mods, keys;
wtitle = title;
cleared = false; cleared = false;
runemufn([&mods, &keys, &classes, &classeslist]() { std::set<std::string> x;
std::set<std::string> x; mods = modifier::get_set();
mods = modifier::get_set(); keys = keygroup::get_keys();
keys = keygroup::get_keys(); for(auto i : keys) {
for(auto i : keys) { std::string kclass = keygroup::lookup(i).first->get_class();
std::string kclass = keygroup::lookup(i).first->get_class(); if(!x.count(kclass))
if(!x.count(kclass)) classeslist.push_back(towxstring(kclass));
classeslist.push_back(towxstring(kclass)); x.insert(kclass);
x.insert(kclass); classes[kclass].insert(i);
classes[kclass].insert(i); }
}
});
Centre(); Centre();
top_s = new wxFlexGridSizer(2, 1, 0, 0); top_s = new wxFlexGridSizer(2, 1, 0, 0);
@ -135,6 +286,9 @@ namespace
top_s->Add(t_s); top_s->Add(t_s);
wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL); wxBoxSizer* pbutton_s = new wxBoxSizer(wxHORIZONTAL);
pbutton_s->Add(press = new wxButton(this, wxID_OK, wxT("Prompt key")), 0, wxGROW);
press->Connect(wxEVT_COMMAND_BUTTON_CLICKED,
wxCommandEventHandler(wxdialog_keyentry::on_pressbutton), NULL, this);
if(clearable) if(clearable)
pbutton_s->Add(clear = new wxButton(this, wxID_OK, wxT("Clear")), 0, wxGROW); pbutton_s->Add(clear = new wxButton(this, wxID_OK, wxT("Clear")), 0, wxGROW);
pbutton_s->Add(ok = new wxButton(this, wxID_OK, wxT("OK")), 0, wxGROW); pbutton_s->Add(ok = new wxButton(this, wxID_OK, wxT("OK")), 0, wxGROW);
@ -222,9 +376,11 @@ namespace
for(auto i : classes) for(auto i : classes)
if(i.second.count(key)) if(i.second.count(key))
_class = i.first; _class = i.first;
set_class(_class); if(_class != "") {
mainclass->SetValue(towxstring(_class)); set_class(_class);
mainkey->SetValue(towxstring(key)); mainclass->SetValue(towxstring(_class));
mainkey->SetValue(towxstring(key));
}
t_s->Layout(); t_s->Layout();
top_s->Layout(); top_s->Layout();
Fit(); Fit();
@ -281,6 +437,23 @@ namespace
} }
} }
void wxdialog_keyentry::on_pressbutton(wxCommandEvent& e)
{
wxdialog_pressbutton* p = new wxdialog_pressbutton(this, wtitle);
p->ShowModal();
std::string key = p->getkey();
p->Destroy();
std::string _class;
for(auto i : classes)
if(i.second.count(key))
_class = i.first;
if(_class == "")
return;
set_class(_class);
mainclass->SetValue(towxstring(_class));
mainkey->SetValue(towxstring(key));
}
void wxdialog_keyentry::on_ok(wxCommandEvent& e) void wxdialog_keyentry::on_ok(wxCommandEvent& e)
{ {
EndModal(wxID_OK); EndModal(wxID_OK);
@ -384,11 +557,9 @@ wxeditor_esettings_joystick_aconfig::wxeditor_esettings_joystick_aconfig(wxWindo
aname = _aname; aname = _aname;
keygroup::parameters params; keygroup::parameters params;
runemufn([aname, &params]() { auto k = keygroup::lookup_by_name(aname);
auto k = keygroup::lookup_by_name(aname); if(k)
if(k) params = k->get_parameters();
params = k->get_parameters();
});
switch(params.ktype) { switch(params.ktype) {
case keygroup::KT_DISABLED: didx = 0; break; case keygroup::KT_DISABLED: didx = 0; break;
@ -456,12 +627,10 @@ void wxeditor_esettings_joystick_aconfig::on_ok(wxCommandEvent& e)
double ntol; double ntol;
keygroup* k; keygroup* k;
runemufn([&k, aname, &_ctype]() { k = keygroup::lookup_by_name(aname);
k = keygroup::lookup_by_name(aname); if(k)
if(k) _ctype = k->get_parameters().ktype;
_ctype = k->get_parameters().ktype; else {
});
if(!k) {
//Axis gone away? //Axis gone away?
EndModal(wxID_OK); EndModal(wxID_OK);
return; return;
@ -502,11 +671,9 @@ void wxeditor_esettings_joystick_aconfig::on_ok(wxCommandEvent& e)
return; return;
} }
runemufn([&k, _ctype, _ntype, nlow, nmid, nhi, ntol]() { if(_ctype != _ntype)
if(_ctype != _ntype) k->change_type(_ntype);
k->change_type(_ntype); k->change_calibration(nlow, nmid, nhi, ntol);
k->change_calibration(nlow, nmid, nhi, ntol);
});
EndModal(wxID_OK); EndModal(wxID_OK);
} }
@ -534,7 +701,8 @@ namespace
{ {
std::string formattype(keygroup::type t) std::string formattype(keygroup::type t)
{ {
if(t == keygroup::KT_AXIS_PAIR) return AMODE_AXIS_PAIR; if(t == keygroup::KT_DISABLED) return AMODE_DISABLED;
else if(t == keygroup::KT_AXIS_PAIR) return AMODE_AXIS_PAIR;
else if(t == keygroup::KT_AXIS_PAIR_INVERSE) return AMODE_AXIS_PAIR_INVERSE; else if(t == keygroup::KT_AXIS_PAIR_INVERSE) return AMODE_AXIS_PAIR_INVERSE;
else if(t == keygroup::KT_PRESSURE_0M) return AMODE_PRESSURE_0M; else if(t == keygroup::KT_PRESSURE_0M) return AMODE_PRESSURE_0M;
else if(t == keygroup::KT_PRESSURE_0P) return AMODE_PRESSURE_0P; else if(t == keygroup::KT_PRESSURE_0P) return AMODE_PRESSURE_0P;
@ -591,14 +759,12 @@ void wxeditor_esettings_joystick::refresh()
{ {
//Collect the new settings. //Collect the new settings.
std::map<std::string, keygroup::parameters> x; std::map<std::string, keygroup::parameters> x;
runemufn([&x]() { auto axisnames = keygroup::get_axis_set();
auto axisnames = keygroup::get_axis_set(); for(auto i : axisnames) {
for(auto i : axisnames) { keygroup* k = keygroup::lookup_by_name(i);
keygroup* k = keygroup::lookup_by_name(i); if(k)
if(k) x[i] = k->get_parameters();
x[i] = k->get_parameters(); }
}
});
unsigned jcount = 0; unsigned jcount = 0;
for(auto i : x) { for(auto i : x) {
@ -709,8 +875,7 @@ void wxeditor_esettings_paths::on_configure(wxCommandEvent& e)
name = SLOTPATH; name = SLOTPATH;
else else
return; return;
std::string val; std::string val = setting::get(name);
runemufn([&val, name]() { val = setting::get(name); });
try { try {
if(e.GetId() == wxID_HIGHEST + 4) if(e.GetId() == wxID_HIGHEST + 4)
val = pick_text(this, "Change number of slots", "Enter number of slots:", val); val = pick_text(this, "Change number of slots", "Enter number of slots:", val);
@ -721,22 +886,22 @@ void wxeditor_esettings_paths::on_configure(wxCommandEvent& e)
return; return;
} }
std::string err; std::string err;
runemufn([val, name, &err]() { try { setting::set(name, val); } catch(std::exception& e) { err = e.what(); }}); try {
if(err != "") setting::set(name, val);
} catch(std::exception& e) {
wxMessageBox(wxT("Invalid value"), wxT("Can't change value"), wxICON_EXCLAMATION | wxOK); wxMessageBox(wxT("Invalid value"), wxT("Can't change value"), wxICON_EXCLAMATION | wxOK);
}
refresh(); refresh();
} }
void wxeditor_esettings_paths::refresh() void wxeditor_esettings_paths::refresh()
{ {
std::string rpath, fpath, spath, nslot, lpath; std::string rpath, fpath, spath, nslot, lpath;
runemufn([&rpath, &fpath, &spath, &nslot, &lpath]() { fpath = setting::get(FIRMWAREPATH);
fpath = setting::get(FIRMWAREPATH); rpath = setting::get(ROMPATH);
rpath = setting::get(ROMPATH); spath = setting::get(MOVIEPATH);
spath = setting::get(MOVIEPATH); nslot = setting::get(SAVESLOTS);
nslot = setting::get(SAVESLOTS); lpath = setting::get(SLOTPATH);
lpath = setting::get(SLOTPATH);
});
rompath->SetLabel(towxstring(rpath)); rompath->SetLabel(towxstring(rpath));
firmpath->SetLabel(towxstring(fpath)); firmpath->SetLabel(towxstring(fpath));
savepath->SetLabel(towxstring(spath)); savepath->SetLabel(towxstring(spath));
@ -929,11 +1094,10 @@ void wxeditor_esettings_aliases::on_add(wxCommandEvent& e)
show_message_ok(this, "Error", "Not a valid alias name: " + name, wxICON_EXCLAMATION); show_message_ok(this, "Error", "Not a valid alias name: " + name, wxICON_EXCLAMATION);
throw canceled_exception(); throw canceled_exception();
} }
std::string old_alias_value; std::string old_alias_value = command::get_alias_for(name);
runemufn([name, &old_alias_value]() { old_alias_value = command::get_alias_for(name); });
std::string newcmd = pick_text(this, "Edit alias", "Enter new commands for '" + name + "':", std::string newcmd = pick_text(this, "Edit alias", "Enter new commands for '" + name + "':",
old_alias_value, true); old_alias_value, true);
runemufn([name, newcmd]() { command::set_alias_for(name, newcmd); }); command::set_alias_for(name, newcmd);
} catch(...) { } catch(...) {
} }
refresh(); refresh();
@ -947,11 +1111,10 @@ void wxeditor_esettings_aliases::on_edit(wxCommandEvent& e)
return; return;
} }
try { try {
std::string old_alias_value; std::string old_alias_value = command::get_alias_for(name);
runemufn([name, &old_alias_value]() { old_alias_value = command::get_alias_for(name); });
std::string newcmd = pick_text(this, "Edit alias", "Enter new commands for '" + name + "':", std::string newcmd = pick_text(this, "Edit alias", "Enter new commands for '" + name + "':",
old_alias_value, true); old_alias_value, true);
runemufn([name, newcmd]() { command::set_alias_for(name, newcmd); }); command::set_alias_for(name, newcmd);
} catch(...) { } catch(...) {
} }
refresh(); refresh();
@ -964,7 +1127,7 @@ void wxeditor_esettings_aliases::on_delete(wxCommandEvent& e)
refresh(); refresh();
return; return;
} }
runemufn([name]() { command::set_alias_for(name, ""); }); command::set_alias_for(name, "");
refresh(); refresh();
} }
@ -973,7 +1136,7 @@ void wxeditor_esettings_aliases::refresh()
int n = select->GetSelection(); int n = select->GetSelection();
std::set<std::string> bind; std::set<std::string> bind;
std::vector<wxString> choices; std::vector<wxString> choices;
runemufn([&bind]() { bind = command::get_aliases(); }); bind = command::get_aliases();
for(auto i : bind) { for(auto i : bind) {
numbers[choices.size()] = i; numbers[choices.size()] = i;
choices.push_back(towxstring(i)); choices.push_back(towxstring(i));
@ -1007,6 +1170,7 @@ public:
void on_primary(wxCommandEvent& e); void on_primary(wxCommandEvent& e);
void on_secondary(wxCommandEvent& e); void on_secondary(wxCommandEvent& e);
void on_change(wxCommandEvent& e); void on_change(wxCommandEvent& e);
void kill_internal_data();
private: private:
std::map<std::string, wxTreeItemId> items; std::map<std::string, wxTreeItemId> items;
std::map<std::string, inverse_key*> realitems; std::map<std::string, inverse_key*> realitems;
@ -1060,6 +1224,14 @@ wxeditor_esettings_hotkeys::~wxeditor_esettings_hotkeys()
{ {
} }
void wxeditor_esettings_hotkeys::kill_internal_data()
{
items.clear();
realitems.clear();
leafname.clear();
true_root = wxTreeItemId();
}
void wxeditor_esettings_hotkeys::on_primary(wxCommandEvent& e) void wxeditor_esettings_hotkeys::on_primary(wxCommandEvent& e)
{ {
std::string name = selected(); std::string name = selected();
@ -1068,13 +1240,12 @@ void wxeditor_esettings_hotkeys::on_primary(wxCommandEvent& e)
return; return;
} }
try { try {
std::string key;
inverse_key* ik = realitems[name]; inverse_key* ik = realitems[name];
if(!ik) { if(!ik) {
refresh(); refresh();
return; return;
} }
runemufn([&key, ik]() { key = ik->get(true); }); std::string key = ik->get(true);
wxdialog_keyentry* d = new wxdialog_keyentry(this, "Specify key for " + name, key, true); wxdialog_keyentry* d = new wxdialog_keyentry(this, "Specify key for " + name, key, true);
if(d->ShowModal() == wxID_CANCEL) { if(d->ShowModal() == wxID_CANCEL) {
d->Destroy(); d->Destroy();
@ -1083,9 +1254,9 @@ void wxeditor_esettings_hotkeys::on_primary(wxCommandEvent& e)
key = d->getkey(); key = d->getkey();
d->Destroy(); d->Destroy();
if(key != "") if(key != "")
runemufn([key, ik]() { ik->set(key, true); }); ik->set(key, true);
else else
runemufn([key, ik]() { ik->clear(true); }); ik->clear(true);
refresh(); refresh();
} catch(...) { } catch(...) {
refresh(); refresh();
@ -1100,13 +1271,12 @@ void wxeditor_esettings_hotkeys::on_secondary(wxCommandEvent& e)
return; return;
} }
try { try {
std::string key;
inverse_key* ik = realitems[name]; inverse_key* ik = realitems[name];
if(!ik) { if(!ik) {
refresh(); refresh();
return; return;
} }
runemufn([&key, ik]() { key = ik->get(false); }); std::string key = ik->get(false);
wxdialog_keyentry* d = new wxdialog_keyentry(this, "Specify key for " + name, key, true); wxdialog_keyentry* d = new wxdialog_keyentry(this, "Specify key for " + name, key, true);
if(d->ShowModal() == wxID_CANCEL) { if(d->ShowModal() == wxID_CANCEL) {
d->Destroy(); d->Destroy();
@ -1115,9 +1285,9 @@ void wxeditor_esettings_hotkeys::on_secondary(wxCommandEvent& e)
key = d->getkey(); key = d->getkey();
d->Destroy(); d->Destroy();
if(key != "") if(key != "")
runemufn([key, ik]() { ik->set(key, false); }); ik->set(key, false);
else else
runemufn([key, ik]() { ik->clear(false); }); ik->clear(false);
refresh(); refresh();
} catch(...) { } catch(...) {
refresh(); refresh();
@ -1129,13 +1299,11 @@ void wxeditor_esettings_hotkeys::refresh()
std::set<std::string> closure_additional; std::set<std::string> closure_additional;
std::map<std::string, inverse_key*> keyorder; std::map<std::string, inverse_key*> keyorder;
std::map<inverse_key*, std::pair<std::string, std::string>> data; std::map<inverse_key*, std::pair<std::string, std::string>> data;
runemufn([&data, &keyorder]() { auto x = inverse_key::get_ikeys();
auto x = inverse_key::get_ikeys(); for(auto y : x) {
for(auto y : x) { keyorder[y->getname()] = y;
keyorder[y->getname()] = y; data[y] = std::make_pair(y->get(true), y->get(false));
data[y] = std::make_pair(y->get(true), y->get(false)); }
}
});
//Close keyorder with respect to parents. //Close keyorder with respect to parents.
for(auto i : keyorder) { for(auto i : keyorder) {
std::string tmp = i.first; std::string tmp = i.first;
@ -1282,22 +1450,15 @@ void wxeditor_esettings_bindings::on_add(wxCommandEvent& e)
d->Destroy(); d->Destroy();
std::string newcommand = pick_text(this, "New binding", "Enter command for binding:", ""); std::string newcommand = pick_text(this, "New binding", "Enter command for binding:", "");
bool fault = false; try {
std::string faulttext; keymapper::bind_for(name, newcommand);
runemufn([&fault, &faulttext, name, newcommand]() { } catch(std::exception& e) {
try { wxMessageBox(wxT("Error"), towxstring(std::string("Can't bind key: ") + e.what()),
keymapper::bind_for(name, newcommand); wxICON_EXCLAMATION);
} catch(std::exception& e) { }
fault = true;
faulttext = e.what();
}
});
if(fault)
wxMessageBox(wxT("Error"), towxstring("Can't bind key: " + faulttext), wxICON_EXCLAMATION);
refresh();
} catch(...) { } catch(...) {
refresh();
} }
refresh();
} }
void wxeditor_esettings_bindings::on_edit(wxCommandEvent& e) void wxeditor_esettings_bindings::on_edit(wxCommandEvent& e)
@ -1308,26 +1469,18 @@ void wxeditor_esettings_bindings::on_edit(wxCommandEvent& e)
return; return;
} }
try { try {
std::string old_command_value; std::string old_command_value = keymapper::get_command_for(name);
runemufn([&old_command_value, name]() { old_command_value = keymapper::get_command_for(name); });
std::string newcommand = pick_text(this, "Edit binding", "Enter new command for binding:", std::string newcommand = pick_text(this, "Edit binding", "Enter new command for binding:",
old_command_value); old_command_value);
bool fault = false; try {
std::string faulttext; keymapper::bind_for(name, newcommand);
runemufn([&fault, &faulttext, name, newcommand]() { } catch(std::exception& e) {
try { wxMessageBox(wxT("Error"), towxstring(std::string("Can't bind key: ") + e.what()),
keymapper::bind_for(name, newcommand); wxICON_EXCLAMATION);
} catch(std::exception& e) { }
fault = true;
faulttext = e.what();
}
});
if(fault)
wxMessageBox(wxT("Error"), towxstring("Can't bind key: " + faulttext), wxICON_EXCLAMATION);
refresh();
} catch(...) { } catch(...) {
refresh();
} }
refresh();
} }
void wxeditor_esettings_bindings::on_delete(wxCommandEvent& e) void wxeditor_esettings_bindings::on_delete(wxCommandEvent& e)
@ -1337,7 +1490,7 @@ void wxeditor_esettings_bindings::on_delete(wxCommandEvent& e)
refresh(); refresh();
return; return;
} }
runemufn([name]() { try { keymapper::bind_for(name, ""); } catch(...) {} }); try { keymapper::bind_for(name, ""); } catch(...) {}
refresh(); refresh();
} }
@ -1346,11 +1499,9 @@ void wxeditor_esettings_bindings::refresh()
int n = select->GetSelection(); int n = select->GetSelection();
std::map<std::string, std::string> bind; std::map<std::string, std::string> bind;
std::vector<wxString> choices; std::vector<wxString> choices;
runemufn([&bind]() { std::set<std::string> a = keymapper::get_bindings();
std::set<std::string> a = keymapper::get_bindings(); for(auto i : a)
for(auto i : a) bind[i] = keymapper::get_command_for(i);
bind[i] = keymapper::get_command_for(i);
});
for(auto i : bind) { for(auto i : bind) {
numbers[choices.size()] = i.first; numbers[choices.size()] = i.first;
choices.push_back(towxstring(i.first + " (" + i.second + ")")); choices.push_back(towxstring(i.first + " (" + i.second + ")"));
@ -1439,17 +1590,17 @@ void wxeditor_esettings_advanced::on_change(wxCommandEvent& e)
return; return;
std::string value; std::string value;
std::string err; std::string err;
runemufn([name, &value]() { value = setting::get(name); }); value = setting::get(name);
try { try {
value = pick_text(this, "Set value to", "Set " + name + " to value:", value); value = pick_text(this, "Set value to", "Set " + name + " to value:", value);
} catch(...) { } catch(...) {
return; return;
} }
runemufn([name, value, &err]() { try {
try { setting::set(name, value); } catch(std::exception& e) { err = e.what(); } setting::set(name, value);
}); } catch(std::exception& e) {
if(err != "")
wxMessageBox(towxstring(err), wxT("Error setting value"), wxICON_EXCLAMATION | wxOK); wxMessageBox(towxstring(err), wxT("Error setting value"), wxICON_EXCLAMATION | wxOK);
}
} }
void wxeditor_esettings_advanced::on_selchange(wxCommandEvent& e) void wxeditor_esettings_advanced::on_selchange(wxCommandEvent& e)
@ -1466,9 +1617,11 @@ void wxeditor_esettings_advanced::on_clear(wxCommandEvent& e)
if(name == "") if(name == "")
return; return;
bool err = false; bool err = false;
runemufn([name, &err]() { try { setting::blank(name); } catch(...) { err = true; }}); try {
if(err) setting::blank(name);
} catch(...) {
wxMessageBox(wxT("This setting can't be cleared"), wxT("Error"), wxICON_EXCLAMATION | wxOK); wxMessageBox(wxT("This setting can't be cleared"), wxT("Error"), wxICON_EXCLAMATION | wxOK);
}
} }
void wxeditor_esettings_advanced::on_setting_change(const std::string& setting, const std::string& value) void wxeditor_esettings_advanced::on_setting_change(const std::string& setting, const std::string& value)
@ -1489,16 +1642,14 @@ void wxeditor_esettings_advanced::on_setting_clear(const std::string& setting)
void wxeditor_esettings_advanced::refresh() void wxeditor_esettings_advanced::refresh()
{ {
runemufn([&settings, &values, &blankables]() { settings = setting::get_settings_set();
settings = setting::get_settings_set(); blankables.clear();
blankables.clear(); for(auto i : settings) {
for(auto i : settings) { if(setting::is_set(i))
if(setting::is_set(i)) values[i] = setting::get(i);
values[i] = setting::get(i); if(setting::blankable(i))
if(setting::blankable(i)) blankables.insert(i);
blankables.insert(i); }
}
});
_refresh(); _refresh();
} }
@ -1537,11 +1688,15 @@ private:
wxWindow* joystick_window; wxWindow* joystick_window;
wxNotebook* tabset; wxNotebook* tabset;
wxButton* closebutton; wxButton* closebutton;
wxeditor_esettings_hotkeys* hotkeytab;
}; };
wxeditor_esettings::wxeditor_esettings(wxWindow* parent) wxeditor_esettings::wxeditor_esettings(wxWindow* parent)
: wxDialog(parent, wxID_ANY, wxT("lsnes: Configure emulator"), wxDefaultPosition, wxSize(-1, -1)) : wxDialog(parent, wxID_ANY, wxT("lsnes: Configure emulator"), wxDefaultPosition, wxSize(-1, -1))
{ {
//Grab keys to prevent the joystick driver from running who knows what commands.
keygrabber.grab_keys();
Centre(); Centre();
wxSizer* top_s = new wxBoxSizer(wxVERTICAL); wxSizer* top_s = new wxBoxSizer(wxVERTICAL);
SetSizer(top_s); SetSizer(top_s);
@ -1550,7 +1705,7 @@ wxeditor_esettings::wxeditor_esettings(wxWindow* parent)
tabset->AddPage(new wxeditor_esettings_joystick(tabset), wxT("Joysticks")); tabset->AddPage(new wxeditor_esettings_joystick(tabset), wxT("Joysticks"));
tabset->AddPage(new wxeditor_esettings_paths(tabset), wxT("Paths")); tabset->AddPage(new wxeditor_esettings_paths(tabset), wxT("Paths"));
tabset->AddPage(new wxeditor_esettings_screen(tabset), wxT("Scaling")); tabset->AddPage(new wxeditor_esettings_screen(tabset), wxT("Scaling"));
tabset->AddPage(new wxeditor_esettings_hotkeys(tabset), wxT("Hotkeys")); tabset->AddPage(hotkeytab = new wxeditor_esettings_hotkeys(tabset), wxT("Hotkeys"));
tabset->AddPage(new wxeditor_esettings_aliases(tabset), wxT("Aliases")); tabset->AddPage(new wxeditor_esettings_aliases(tabset), wxT("Aliases"));
tabset->AddPage(new wxeditor_esettings_bindings(tabset), wxT("Bindings")); tabset->AddPage(new wxeditor_esettings_bindings(tabset), wxT("Bindings"));
tabset->AddPage(new wxeditor_esettings_advanced(tabset), wxT("Advanced")); tabset->AddPage(new wxeditor_esettings_advanced(tabset), wxT("Advanced"));
@ -1578,6 +1733,8 @@ bool wxeditor_esettings::ShouldPreventAppExit() const
void wxeditor_esettings::on_close(wxCommandEvent& e) void wxeditor_esettings::on_close(wxCommandEvent& e)
{ {
hotkeytab->kill_internal_data();
keygrabber.ungrab_keys();
EndModal(wxID_OK); EndModal(wxID_OK);
} }

View file

@ -11,6 +11,18 @@ struct wxw_mutex : public mutex
wxMutex* m; wxMutex* m;
}; };
struct wxw_rec_mutex : public mutex
{
wxw_rec_mutex() throw(std::bad_alloc);
~wxw_rec_mutex() throw();
void lock() throw();
void unlock() throw();
wxMutex* m;
volatile bool locked;
uint32_t owner;
uint32_t count;
};
wxw_mutex::wxw_mutex() throw(std::bad_alloc) wxw_mutex::wxw_mutex() throw(std::bad_alloc)
{ {
m = new wxMutex(); m = new wxMutex();
@ -31,11 +43,55 @@ void wxw_mutex::unlock() throw()
m->Unlock(); m->Unlock();
} }
wxw_rec_mutex::wxw_rec_mutex() throw(std::bad_alloc)
{
m = new wxMutex();
locked = false;
owner = 0;
count = 0;
}
wxw_rec_mutex::~wxw_rec_mutex() throw()
{
delete m;
}
void wxw_rec_mutex::lock() throw()
{
uint32_t our_id = wxThread::GetCurrentId();
if(locked && owner == our_id) {
//Owned by us, increment lock count.
++count;
return;
}
m->Lock();
locked = true;
owner = our_id;
count = 1;
}
void wxw_rec_mutex::unlock() throw()
{
uint32_t our_id = wxThread::GetCurrentId();
if(!locked || owner != our_id)
std::cerr << "Warning: Trying to unlock recursive lock locked by another thread!" << std::endl;
if(!--count) {
locked = false;
owner = 0;
m->Unlock();
}
}
mutex& mutex::aquire() throw(std::bad_alloc) mutex& mutex::aquire() throw(std::bad_alloc)
{ {
return *new wxw_mutex; return *new wxw_mutex;
} }
mutex& mutex::aquire_rec() throw(std::bad_alloc)
{
return *new wxw_rec_mutex;
}
struct wxw_condition : public condition struct wxw_condition : public condition
{ {
wxw_condition(mutex& m) throw(std::bad_alloc); wxw_condition(mutex& m) throw(std::bad_alloc);