599 lines
15 KiB
C++
599 lines
15 KiB
C++
|
#include "lsnes.hpp"
|
||
|
#include "core/command.hpp"
|
||
|
#include "core/dispatch.hpp"
|
||
|
#include "core/framebuffer.hpp"
|
||
|
#include "core/framerate.hpp"
|
||
|
#include "core/window.hpp"
|
||
|
#include "plat-sdl/platform.hpp"
|
||
|
|
||
|
screen_model screenmod;
|
||
|
|
||
|
#define USERCODE_TIMER 0
|
||
|
#define USERCODE_PAINT 1
|
||
|
|
||
|
#define SPECIALMODE_NORMAL 0
|
||
|
#define SPECIALMODE_COMMAND 1
|
||
|
#define SPECIALMODE_IDENTIFY 2
|
||
|
#define SPECIALMODE_MODAL 3
|
||
|
|
||
|
#ifdef SDL_NO_JOYSTICK
|
||
|
unsigned translate_sdl_joystick(SDL_Event& e, keypress& k1)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
namespace
|
||
|
{
|
||
|
//Dirty flags for various displays.
|
||
|
volatile bool messages_dirty = false;
|
||
|
volatile bool status_dirty = false;
|
||
|
volatile bool screen_dirty = false;
|
||
|
volatile bool fullscreen_console = false;
|
||
|
bool fullscreen_console_active = false;
|
||
|
//If true, repaint request is in flight. Protected by ui_mutex.
|
||
|
volatile bool repaint_in_flight = false;
|
||
|
//If true, timer event has occured.
|
||
|
volatile bool timer_triggered = false;
|
||
|
//If true, modal dialog is to be displayed. Pull low to ack the dialog. Protected by ui_mutex.
|
||
|
volatile bool modal_dialog_active = false;
|
||
|
//If modal_dialog_active is true, this is the text for the dialog box. Protected by ui_mutex.
|
||
|
std::string modal_dialog_text;
|
||
|
//If true, the modal dialog is confirmation dialog. Pull low if confirmation dialog is canceled. Protected
|
||
|
//by ui_mutex.
|
||
|
volatile bool modal_dialog_confirm = true;
|
||
|
//Set if emulator panics.
|
||
|
volatile bool paniced = false;
|
||
|
//Set when user dismisses panic prompt (emulator can exit).
|
||
|
volatile bool panic_ack = false;
|
||
|
//Set after SIGALRM handler has got installed.
|
||
|
bool sigalrm_handler_installed = false;
|
||
|
//Special mode.
|
||
|
unsigned special_mode;
|
||
|
volatile bool identify_requested;
|
||
|
volatile bool emulator_thread_exited = false;
|
||
|
//The command line modal to use.
|
||
|
commandline_model cmdline;
|
||
|
//Mutex protecting various variables and associated mutex for waking the emulator thread from some blocking
|
||
|
//operations.
|
||
|
mutex* ui_mutex;
|
||
|
condition* ui_condition;
|
||
|
//Set to true when SDL has been initialized.
|
||
|
bool sdl_init = false;
|
||
|
//Thread ID of UI thread (for identifying it).
|
||
|
thread_id* ui_thread;
|
||
|
//Timer for implementing stuff like autorepeat.
|
||
|
SDL_TimerID timer_id;
|
||
|
//Timer IRQ counter. Used by identify key stuff.
|
||
|
volatile unsigned timer_irq_counter;
|
||
|
|
||
|
void sigalrm_handler(int s)
|
||
|
{
|
||
|
_exit(1);
|
||
|
}
|
||
|
|
||
|
void send_sdl_userevent(int code)
|
||
|
{
|
||
|
SDL_Event e;
|
||
|
e.type = SDL_USEREVENT;
|
||
|
e.user.code = USERCODE_PAINT;
|
||
|
e.user.data1 = NULL;
|
||
|
e.user.data2 = NULL;
|
||
|
ui_mutex->lock();
|
||
|
//SDL_PushEvent(&e);
|
||
|
ui_mutex->unlock();
|
||
|
}
|
||
|
|
||
|
Uint32 timer_cb(Uint32 interval, void* param)
|
||
|
{
|
||
|
//send_sdl_userevent(USERCODE_TIMER);
|
||
|
timer_triggered = true;
|
||
|
timer_irq_counter = timer_irq_counter + 1;
|
||
|
return interval;
|
||
|
}
|
||
|
|
||
|
void arm_sigalrm()
|
||
|
{
|
||
|
#ifdef SIGALRM
|
||
|
if(!sigalrm_handler_installed)
|
||
|
signal(SIGALRM, sigalrm_handler);
|
||
|
sigalrm_handler_installed = true;
|
||
|
//alarm(15);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
void ui_panic()
|
||
|
{
|
||
|
//Be very careful what you use here, as program state can be really unpredictable!
|
||
|
try {
|
||
|
platform::message("PANIC: Cannot continue, press ESC or close window to exit.");
|
||
|
screenmod.repaint_full();
|
||
|
screenmod.flip();
|
||
|
} catch(...) {
|
||
|
//Just crash.
|
||
|
panic_ack = true;
|
||
|
return;
|
||
|
}
|
||
|
while(true) {
|
||
|
SDL_Event e;
|
||
|
if(SDL_WaitEvent(&e)) {
|
||
|
if(e.type == SDL_QUIT)
|
||
|
break;
|
||
|
if(e.type == SDL_ACTIVEEVENT) {
|
||
|
screenmod.repaint_full();
|
||
|
screenmod.flip();
|
||
|
}
|
||
|
if(e.type == SDL_KEYUP && e.key.keysym.sym == SDLK_ESCAPE)
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
panic_ack = true;
|
||
|
}
|
||
|
|
||
|
void wake_ui()
|
||
|
{
|
||
|
mutex::holder h(*ui_mutex);
|
||
|
if(!repaint_in_flight) {
|
||
|
//Wake the UI.
|
||
|
repaint_in_flight = true;
|
||
|
//send_sdl_userevent(USERCODE_PAINT);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function_ptr_command<> identify_key("identify-key", "Identify a key",
|
||
|
"Syntax: identify-key\nIdentifies a (pseudo-)key.\n",
|
||
|
[]() throw(std::bad_alloc, std::runtime_error) {
|
||
|
identify_requested = true;
|
||
|
wake_ui();
|
||
|
});
|
||
|
|
||
|
function_ptr_command<> scroll_up("scroll-up", "Scroll messages a page up",
|
||
|
"Syntax: scroll-up\nScrolls message console backward one page.\n",
|
||
|
[]() throw(std::bad_alloc, std::runtime_error) {
|
||
|
mutex::holder h(platform::msgbuf_lock());
|
||
|
platform::msgbuf.scroll_up_page();
|
||
|
});
|
||
|
|
||
|
function_ptr_command<> scroll_fullup("scroll-fullup", "Scroll messages to beginning",
|
||
|
"Syntax: scroll-fullup\nScrolls message console to its beginning.\n",
|
||
|
[]() throw(std::bad_alloc, std::runtime_error) {
|
||
|
mutex::holder h(platform::msgbuf_lock());
|
||
|
platform::msgbuf.scroll_beginning();
|
||
|
});
|
||
|
|
||
|
function_ptr_command<> scroll_fulldown("scroll-fulldown", "Scroll messages to end",
|
||
|
"Syntax: scroll-fulldown\nScrolls message console to its end.\n",
|
||
|
[]() throw(std::bad_alloc, std::runtime_error) {
|
||
|
mutex::holder h(platform::msgbuf_lock());
|
||
|
platform::msgbuf.scroll_end();
|
||
|
});
|
||
|
|
||
|
function_ptr_command<> scrolldown("scroll-down", "Scroll messages a page down",
|
||
|
"Syntax: scroll-up\nScrolls message console forward one page.\n",
|
||
|
[]() throw(std::bad_alloc, std::runtime_error) {
|
||
|
mutex::holder h(platform::msgbuf_lock());
|
||
|
platform::msgbuf.scroll_down_page();
|
||
|
});
|
||
|
|
||
|
function_ptr_command<> toggle_console("toggle-console", "Toggle console between small and full window",
|
||
|
"Syntax: toggle-console\nToggles console between small and large.\n",
|
||
|
[]() throw(std::bad_alloc, std::runtime_error) {
|
||
|
fullscreen_console = !fullscreen_console;
|
||
|
wake_ui();
|
||
|
});
|
||
|
|
||
|
class keygrabber : public information_dispatch
|
||
|
{
|
||
|
public:
|
||
|
keygrabber() : information_dispatch("sdl-key-grabber") { idmode = false; }
|
||
|
void enter_id_mode()
|
||
|
{
|
||
|
keys = "";
|
||
|
idmode = true;
|
||
|
}
|
||
|
bool got_id()
|
||
|
{
|
||
|
return keys != "";
|
||
|
}
|
||
|
std::string get_id()
|
||
|
{
|
||
|
return keys;
|
||
|
}
|
||
|
void leave_id_mode()
|
||
|
{
|
||
|
keys = "";
|
||
|
idmode = false;
|
||
|
}
|
||
|
void on_key_event(const modifier_set& modifiers, keygroup& keygroup, unsigned subkey,
|
||
|
bool polarity, const std::string& name)
|
||
|
{
|
||
|
if(idmode && !polarity) {
|
||
|
keys = keys + "key: " + name + "\n";
|
||
|
}
|
||
|
}
|
||
|
bool idmode;
|
||
|
std::string keys;
|
||
|
} keygrabber;
|
||
|
|
||
|
void emu_ungrab_keys(void* dummy)
|
||
|
{
|
||
|
keygrabber.ungrab_keys();
|
||
|
keygrabber.leave_id_mode();
|
||
|
}
|
||
|
|
||
|
void emu_grab_keys_identify(void* dummy)
|
||
|
{
|
||
|
keygrabber.enter_id_mode();
|
||
|
keygrabber.grab_keys();
|
||
|
}
|
||
|
|
||
|
void emu_grab_keys_nonid(void* dummy)
|
||
|
{
|
||
|
keygrabber.leave_id_mode();
|
||
|
keygrabber.grab_keys();
|
||
|
}
|
||
|
|
||
|
void emu_handle_quit_signal(void* dummy)
|
||
|
{
|
||
|
information_dispatch::do_close();
|
||
|
}
|
||
|
|
||
|
void emu_handle_identify(void* dummy)
|
||
|
{
|
||
|
if(keygrabber.got_id()) {
|
||
|
std::string k = keygrabber.get_id();
|
||
|
keygrabber.leave_id_mode();
|
||
|
platform::modal_message(k, false);
|
||
|
}
|
||
|
//Exiting the modal mode undoes key grab and modal pause.
|
||
|
}
|
||
|
|
||
|
//Grab keys, setting or unsetting id mode.
|
||
|
void ui_grab_keys(bool idmode)
|
||
|
{
|
||
|
if(idmode)
|
||
|
platform::queue(emu_grab_keys_identify, NULL, true);
|
||
|
else
|
||
|
platform::queue(emu_grab_keys_nonid, NULL, true);
|
||
|
}
|
||
|
|
||
|
//Grab keys, unset id mode, special.
|
||
|
void ui_grab_keys_special()
|
||
|
{
|
||
|
keygrabber.leave_id_mode();
|
||
|
keygrabber.grab_keys();
|
||
|
}
|
||
|
|
||
|
//Ungrab keys.
|
||
|
void ui_ungrab_keys(bool direct = false)
|
||
|
{
|
||
|
if(direct) {
|
||
|
keygrabber.ungrab_keys();
|
||
|
keygrabber.leave_id_mode();
|
||
|
} else
|
||
|
platform::queue(emu_ungrab_keys, NULL, true);
|
||
|
}
|
||
|
|
||
|
//Handle identify timer interrupt.
|
||
|
void ui_handle_identify()
|
||
|
{
|
||
|
//This call has to be asynchronous.
|
||
|
platform::queue(emu_handle_identify, NULL, false);
|
||
|
}
|
||
|
|
||
|
//Handle QUIT in normal state.
|
||
|
void ui_handle_quit_signal()
|
||
|
{
|
||
|
platform::queue(emu_handle_quit_signal, NULL, false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void notify_emulator_exit()
|
||
|
{
|
||
|
emulator_thread_exited = true;
|
||
|
wake_ui();
|
||
|
}
|
||
|
|
||
|
void ui_loop()
|
||
|
{
|
||
|
uint32_t mouse_state = 0;
|
||
|
uint32_t k;
|
||
|
uint64_t kts;
|
||
|
std::string cmd;
|
||
|
bool modal_dialog_was_active = false;
|
||
|
while(!emulator_thread_exited) {
|
||
|
bool commandline_updated = false;
|
||
|
SDL_Event e;
|
||
|
SDLKey kbdkey;
|
||
|
bool iskbd = false;
|
||
|
bool polarity;
|
||
|
bool full = false;
|
||
|
memset(&e, 0, sizeof(e));
|
||
|
{
|
||
|
ui_mutex->lock();
|
||
|
if(!repaint_in_flight && !timer_triggered && !SDL_PollEvent(&e)) {
|
||
|
ui_mutex->unlock();
|
||
|
usleep(5000);
|
||
|
continue;
|
||
|
}
|
||
|
ui_mutex->unlock();
|
||
|
}
|
||
|
if(e.type == SDL_KEYUP) {
|
||
|
iskbd = true;
|
||
|
polarity = false;
|
||
|
kbdkey = e.key.keysym.sym;
|
||
|
//std::cerr << "Keyup symbol " << kbdkey << "(held=" << (get_utime() - kts) << "us)" << std::endl;
|
||
|
} else if(e.type == SDL_KEYDOWN) {
|
||
|
iskbd = true;
|
||
|
polarity = true;
|
||
|
kbdkey = e.key.keysym.sym;
|
||
|
//std::cerr << "Keydown symbol " << kbdkey << std::endl;
|
||
|
kts = get_utime();
|
||
|
}
|
||
|
if(e.type == SDL_VIDEOEXPOSE || e.type == SDL_ACTIVEEVENT)
|
||
|
full = true;
|
||
|
//Handle panics.
|
||
|
if(paniced) {
|
||
|
ui_panic();
|
||
|
while(true);
|
||
|
}
|
||
|
if(e.type == SDL_MOUSEBUTTONDOWN) {
|
||
|
int i;
|
||
|
switch(e.button.button) {
|
||
|
case SDL_BUTTON_LEFT:
|
||
|
mouse_state |= 1;
|
||
|
break;
|
||
|
case SDL_BUTTON_MIDDLE:
|
||
|
mouse_state |= 2;
|
||
|
break;
|
||
|
case SDL_BUTTON_RIGHT:
|
||
|
mouse_state |= 4;
|
||
|
break;
|
||
|
};
|
||
|
send_mouse_click(e.button.x, e.button.y, mouse_state);
|
||
|
}
|
||
|
if(e.type == SDL_MOUSEBUTTONUP) {
|
||
|
switch(e.button.button) {
|
||
|
case SDL_BUTTON_LEFT:
|
||
|
mouse_state &= ~1;
|
||
|
break;
|
||
|
case SDL_BUTTON_MIDDLE:
|
||
|
mouse_state &= ~2;
|
||
|
break;
|
||
|
case SDL_BUTTON_RIGHT:
|
||
|
mouse_state &= ~4;
|
||
|
break;
|
||
|
};
|
||
|
send_mouse_click(e.button.x, e.button.y, mouse_state);
|
||
|
}
|
||
|
//Handle entering identify mode.
|
||
|
if(identify_requested) {
|
||
|
identify_requested = false;
|
||
|
special_mode = SPECIALMODE_IDENTIFY;
|
||
|
ui_grab_keys(true);
|
||
|
platform::message("Press key to identify...");
|
||
|
}
|
||
|
//Handle entering modal dialog.
|
||
|
if(!modal_dialog_was_active && modal_dialog_active) {
|
||
|
screenmod.set_modal(modal_dialog_text, modal_dialog_confirm);
|
||
|
special_mode = SPECIALMODE_MODAL;
|
||
|
modal_dialog_was_active = true;
|
||
|
ui_grab_keys_special();
|
||
|
}
|
||
|
//Handle special modes.
|
||
|
switch(special_mode) {
|
||
|
case SPECIALMODE_NORMAL:
|
||
|
//Enable command line if needed.
|
||
|
if(iskbd && kbdkey == SDLK_ESCAPE) {
|
||
|
if(!cmdline.enabled() && !polarity) {
|
||
|
cmdline.enable();
|
||
|
commandline_updated = true;
|
||
|
special_mode = SPECIALMODE_COMMAND;
|
||
|
platform::set_modal_pause(true);
|
||
|
ui_grab_keys(false);
|
||
|
//std::cerr << "Entered commandline mode." << std::endl;
|
||
|
}
|
||
|
continue;
|
||
|
}
|
||
|
break;
|
||
|
case SPECIALMODE_COMMAND:
|
||
|
if(timer_triggered || (e.type == SDL_USEREVENT && e.user.code == USERCODE_TIMER)) {
|
||
|
cmdline.tick();
|
||
|
timer_triggered = false;
|
||
|
}
|
||
|
cmd = cmdline.key(get_command_edit_operation(e, true));
|
||
|
if(cmd != "") {
|
||
|
//std::cerr << "To execute: '" << cmd << "'" << std::endl;
|
||
|
platform::queue(cmd);
|
||
|
}
|
||
|
commandline_updated = true;
|
||
|
if(!cmdline.enabled()) {
|
||
|
//std::cerr << "Exited commandline mode." << std::endl;
|
||
|
//Exiting commandline mode.
|
||
|
special_mode = SPECIALMODE_NORMAL;
|
||
|
platform::set_modal_pause(false);
|
||
|
ui_ungrab_keys();
|
||
|
}
|
||
|
break;
|
||
|
case SPECIALMODE_IDENTIFY:
|
||
|
if(timer_triggered || (e.type == SDL_USEREVENT && e.user.code == USERCODE_TIMER)) {
|
||
|
ui_handle_identify();
|
||
|
timer_triggered = false;
|
||
|
}
|
||
|
break;
|
||
|
case SPECIALMODE_MODAL:
|
||
|
if((iskbd && !polarity && kbdkey == SDLK_ESCAPE) || e.type == SDL_QUIT) {
|
||
|
//Negative response.
|
||
|
modal_dialog_confirm = false;
|
||
|
modal_dialog_active = false;
|
||
|
screenmod.clear_modal();
|
||
|
special_mode = SPECIALMODE_NORMAL;
|
||
|
//We NAK the command in case modal dialog was somehow entered with command active.
|
||
|
cmdline.key(SPECIAL_NAK);
|
||
|
ui_ungrab_keys(true);
|
||
|
platform::set_modal_pause(false);
|
||
|
modal_dialog_was_active = false;
|
||
|
mutex::holder h(*ui_mutex);
|
||
|
ui_condition->signal();
|
||
|
}
|
||
|
if(iskbd && !polarity && (kbdkey == SDLK_RETURN || kbdkey == SDLK_KP_ENTER)) {
|
||
|
//Positive response.
|
||
|
modal_dialog_active = false;
|
||
|
screenmod.clear_modal();
|
||
|
modal_dialog_was_active = false;
|
||
|
special_mode = SPECIALMODE_NORMAL;
|
||
|
//We NAK the command in case modal dialog was somehow entered with command active.
|
||
|
cmdline.key(SPECIAL_NAK);
|
||
|
platform::set_modal_pause(false);
|
||
|
ui_ungrab_keys(true);
|
||
|
mutex::holder h(*ui_mutex);
|
||
|
ui_condition->signal();
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
timer_triggered = false;
|
||
|
if(e.type == SDL_QUIT)
|
||
|
ui_handle_quit_signal();
|
||
|
//Yes, normal key handling is done even if in commandline or other modal mode.
|
||
|
keypress k;
|
||
|
if(translate_sdl_key(e, k)) {
|
||
|
platform::queue(k);
|
||
|
}
|
||
|
if(translate_sdl_joystick(e, k)) {
|
||
|
platform::queue(k);
|
||
|
}
|
||
|
//Handle repaints.
|
||
|
bool status = false;
|
||
|
bool screen = false;
|
||
|
bool pmessages = false;
|
||
|
bool new_fsc = false;
|
||
|
bool toggle_fsc = false;
|
||
|
{
|
||
|
mutex::holder h(*ui_mutex);
|
||
|
pmessages = messages_dirty;
|
||
|
status = status_dirty;
|
||
|
screen = screen_dirty;
|
||
|
new_fsc = fullscreen_console;
|
||
|
messages_dirty = false;
|
||
|
screen_dirty = false;
|
||
|
status_dirty = false;
|
||
|
if(new_fsc != fullscreen_console_active)
|
||
|
toggle_fsc = true;
|
||
|
else
|
||
|
toggle_fsc = false;
|
||
|
repaint_in_flight = false;
|
||
|
}
|
||
|
//If screen is dirty (irrespective if full repaint would be done), render the screeen.
|
||
|
if(screen)
|
||
|
render_framebuffer();
|
||
|
bool any = status || pmessages || screen || commandline_updated || toggle_fsc || full;
|
||
|
if(special_mode == SPECIALMODE_MODAL || full) {
|
||
|
//FIXME: Use less intensive paint for SPECIALMODE_MODAL.
|
||
|
screenmod.repaint_full();
|
||
|
any = true;
|
||
|
} else {
|
||
|
if(status) {
|
||
|
screenmod.repaint_status();
|
||
|
}
|
||
|
if(pmessages) {
|
||
|
screenmod.repaint_messages();
|
||
|
}
|
||
|
if(screen) {
|
||
|
screenmod.repaint_screen();
|
||
|
}
|
||
|
if(commandline_updated) {
|
||
|
screenmod.repaint_commandline();
|
||
|
}
|
||
|
if(toggle_fsc) {
|
||
|
screenmod.set_fullscreen_console(new_fsc);
|
||
|
fullscreen_console_active = new_fsc;
|
||
|
}
|
||
|
}
|
||
|
if(any)
|
||
|
screenmod.flip();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void graphics_plugin::init() throw()
|
||
|
{
|
||
|
if(!ui_mutex)
|
||
|
ui_mutex = &mutex::aquire();
|
||
|
if(!ui_condition)
|
||
|
ui_condition = &condition::aquire(*ui_mutex);
|
||
|
screenmod.set_command_line(&cmdline);
|
||
|
arm_sigalrm();
|
||
|
ui_thread = &thread_id::me();
|
||
|
init_sdl_keys();
|
||
|
if(!sdl_init) {
|
||
|
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_TIMER);
|
||
|
SDL_EnableUNICODE(true);
|
||
|
sdl_init = true;
|
||
|
timer_id = SDL_AddTimer(30, timer_cb, NULL);
|
||
|
}
|
||
|
//Doing full repaint will open the window.
|
||
|
screenmod.repaint_full();
|
||
|
std::string windowname = "lsnes rr" + lsnes_version + "[" + bsnes_core_version + "]";
|
||
|
SDL_WM_SetCaption(windowname.c_str(), "lsnes");
|
||
|
}
|
||
|
|
||
|
void graphics_plugin::quit() throw()
|
||
|
{
|
||
|
if(sdl_init) {
|
||
|
SDL_Quit();
|
||
|
sdl_init = false;
|
||
|
SDL_RemoveTimer(timer_id);
|
||
|
}
|
||
|
deinit_sdl_keys();
|
||
|
}
|
||
|
|
||
|
void graphics_plugin::notify_message() throw()
|
||
|
{
|
||
|
messages_dirty = true;
|
||
|
wake_ui();
|
||
|
}
|
||
|
|
||
|
void graphics_plugin::notify_status() throw()
|
||
|
{
|
||
|
status_dirty = true;
|
||
|
wake_ui();
|
||
|
}
|
||
|
|
||
|
void graphics_plugin::notify_screen() throw()
|
||
|
{
|
||
|
screen_dirty = true;
|
||
|
wake_ui();
|
||
|
}
|
||
|
|
||
|
bool graphics_plugin::modal_message(const std::string& text, bool confirm) throw()
|
||
|
{
|
||
|
bool answer = false;
|
||
|
try {
|
||
|
//Make the UI thread do the prompting.
|
||
|
mutex::holder h(*ui_mutex);
|
||
|
modal_dialog_active = true;
|
||
|
modal_dialog_text = text;
|
||
|
modal_dialog_confirm = confirm;
|
||
|
while(modal_dialog_active)
|
||
|
ui_condition->wait(100000);
|
||
|
answer = modal_dialog_confirm;
|
||
|
} catch(std::bad_alloc& e) {
|
||
|
OOM_panic();
|
||
|
}
|
||
|
return answer;
|
||
|
}
|
||
|
|
||
|
void graphics_plugin::fatal_error() throw()
|
||
|
{
|
||
|
//Fun... This can be called from any thread.
|
||
|
if(ui_thread->is_me()) {
|
||
|
ui_panic();
|
||
|
} else {
|
||
|
paniced = true;
|
||
|
wake_ui();
|
||
|
//Busywait as program state may be very unpredictable.
|
||
|
while(!panic_ack);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
const char* graphics_plugin::name = "SDL graphics plugin";
|