lsnes/include/core/window.hpp
Ilari Liusvaara 996cecd164 Add warning about calling synchronous queue in callback to UI
This combo seems to trigger lots of deadlocks, so print warnings about
it so instances of this can be found.
2012-01-15 20:47:57 +02:00

561 lines
12 KiB
C++

#ifndef _window__hpp__included__
#define _window__hpp__included__
#include "core/keymapper.hpp"
#include "core/messagebuffer.hpp"
#include "core/render.hpp"
#include "core/status.hpp"
#include <string>
#include <map>
#include <list>
#include <stdexcept>
class emulator_status;
/**
* Mutex.
*/
struct mutex
{
/**
* Hold mutex RAII-style.
*/
struct holder
{
holder(mutex& m) throw();
~holder() throw();
private:
mutex& mut;
};
/**
* Create a mutex. The returned mutex can be deleted using delete.
*/
static mutex& aquire() throw(std::bad_alloc);
/**
* Destroy a mutex.
*/
virtual ~mutex() throw();
/**
* Lock a mutex.
*/
virtual void lock() throw() = 0;
/**
* Lock a mutex.
*/
virtual void unlock() throw() = 0;
protected:
mutex() throw();
};
/**
* Condition variable.
*/
struct condition
{
/**
* Create a condition variable. The returned condition can be freed using delete.
*/
static condition& aquire(mutex& m) throw(std::bad_alloc);
/**
* Destroy a condition.
*/
virtual ~condition() throw();
/**
* Return associated mutex.
*/
mutex& associated() throw();
/**
* Wait for condition. The associate mutex must be locked.
*/
virtual bool wait(uint64_t max_usec) throw() = 0;
/**
* Signal a condition. The associated mutex should be locked.
*/
virtual void signal() throw() = 0;
protected:
condition(mutex& m);
mutex& assoc;
};
/**
* Thread ID.
*/
struct thread_id
{
/**
* Return thread id for this thread. Can be freed with delete.
*/
static thread_id& me() throw(std::bad_alloc);
/**
* Destructor.
*/
virtual ~thread_id() throw();
/**
* Is this thread me?
*/
virtual bool is_me() throw() = 0;
protected:
thread_id() throw();
};
/**
* Thread.
*/
struct thread
{
/**
* Create a thread, jumping to specified starting point.
*/
static thread& create(void* (*entrypoint)(void* arg), void* arg) throw(std::bad_alloc, std::runtime_error);
/**
* Destroy a thread, first joining it (if not already joined).
*/
virtual ~thread() throw();
/**
* Is this thread still alive?
*/
bool is_alive() throw();
/**
* Join a thread.
*/
void* join() throw();
protected:
thread() throw();
/**
* Notify that this thread has quit.
*/
void notify_quit(void* retval) throw();
/**
* Join a thread.
*/
virtual void _join() throw() = 0;
private:
bool alive;
bool joined;
void* returns;
};
/**
* Information about keypress.
*/
struct keypress
{
/**
* Create null keypress (no modifiers, NULL key and released).
*/
keypress();
/**
* Create new keypress.
*/
keypress(modifier_set mod, keygroup& _key, short _value);
/**
* Create new keypress (two keys).
*/
keypress(modifier_set mod, keygroup& _key, keygroup& _key2, short _value);
/**
* Modifier set.
*/
modifier_set modifiers;
/**
* The actual key (first)
*/
keygroup* key1;
/**
* The actual key (second)
*/
keygroup* key2;
/**
* Value for the press
*/
short value;
};
/**
* Functions implemented by the graphics plugin.
*
* Unless explicitly noted otherwise, all the methods are to be called from emulation thread if that exists, otherwise
* from the main thread.
*/
struct graphics_plugin
{
/**
* Graphics initialization function.
*
* - The first initialization function to be called by platform::init().
*/
static void init() throw();
/**
* Graphics quit function.
*
* - The last quit function to be called by platform::quit().
*/
static void quit() throw();
/**
* Notification when messages get updated.
*/
static void notify_message() throw();
/**
* Notification when status gets updated.
*/
static void notify_status() throw();
/**
* Notification when main screen gets updated.
*/
static void notify_screen() throw();
/**
* Show modal message dialog.
*
* Parameter text: The text for dialog.
* Parameter confirm: If true, display confirmation dialog, if false, display notification dialog.
* Returns: True if confirmation dialog was confirmed, otherwise false.
*/
static bool modal_message(const std::string& text, bool confirm = false) throw();
/**
* Displays fatal error message.
*
* - After this routine returns, the program will quit.
* - The call can occur in any thread.
*/
static void fatal_error() throw();
/**
* Identification for graphics plugin.
*/
static const char* name;
};
/**
* Functions implemented by the sound plugin.
*
* Unless explicitly noted otherwise, all the methods are to be called from emulation thread if that exists, otherwise
* from the main thread.
*/
struct sound_plugin
{
/**
* Sound initialization function.
*
* - The second initialization function to be called by window_init().
*/
static void init() throw();
/**
* Sound quit function.
*
* - The second last quit function to be called by window_quit().
*/
static void quit() throw();
/**
* Enable or disable sound.
*
* parameter enable: Enable sounds if true, otherwise disable sounds.
*/
static void enable(bool enable) throw();
/**
* Input audio sample (at specified rate).
*
* parameter left: Left sample.
* parameter right: Right sample.
*/
static void sample(uint16_t left, uint16_t right) throw();
/**
* Has the sound system been successfully initialized?
*
* Returns: True if sound system has successfully initialized, false otherwise.
*/
static bool initialized();
/**
* Set sound device.
*
* - If new sound device is invalid, the sound device is not changed.
*
* Parameter dev: The new sound device.
*/
static void set_device(const std::string& dev) throw(std::bad_alloc, std::runtime_error);
/**
* Get current sound device.
*
* Returns: The current sound device.
*/
static std::string get_device() throw(std::bad_alloc);
/**
* Get available sound devices.
*
* Returns: The map of devices. Keyed by name of the device, values are human-readable names for devices.
*/
static std::map<std::string, std::string> get_devices() throw(std::bad_alloc);
/**
* Identification for sound plugin.
*/
static const char* name;
};
/**
* Functions implemented by the sound plugin.
*
* Unless explicitly noted otherwise, all the methods are to be called from emulation thread if that exists, otherwise
* from the main thread.
*/
struct joystick_plugin
{
/**
* Joystick initialization function.
*
* - The third initialization function to be called by window_init().
* - The call occurs in the main thread.
* - Implemented by the joystick plugin.
*/
static void init() throw();
/**
* Joystick quit function.
*
* - The third last quit function to be called by window_quit().
* - The call occurs in the main thread.
* - Implemented by the joystick plugin.
*/
static void quit() throw();
/**
* This thread becomes the joystick polling thread.
*
* - Called in joystick polling thread.
*/
static void thread_fn() throw();
/**
* Signal the joystick thread to quit.
*/
static void signal() throw();
/**
* Identification for joystick plugin.
*/
static const char* name;
};
/**
* Platform-specific-related functions.
*/
struct platform
{
/**
* Initialize the system.
*/
static void init();
/**
* Shut down the system.
*/
static void quit();
/**
* Get output stream printing into message queue.
*
* Note that lines printed there should be terminated by '\n'.
*
* Implemented by the generic window code.
*
* returns: The output stream.
* throws std::bad_alloc: Not enough memory.
*/
static std::ostream& out() throw(std::bad_alloc);
/**
* Get emulator status area
*
* returns: Emulator status area.
*/
static emulator_status& get_emustatus() throw();
/**
* Message buffer.
*/
static messagebuffer msgbuf;
/**
* Get message buffer lock.
*/
static mutex& msgbuf_lock() throw();
/**
* Set palette used on screen.
*/
static void screen_set_palette(unsigned rshift, unsigned gshift, unsigned bshift) throw();
/**
* Adds a messages to mesage queue to be shown.
*
* Implemented by the generic window code.
*
* parameter msg: The messages to add (split by '\n').
* throws std::bad_alloc: Not enough memory.
*/
static void message(const std::string& msg) throw(std::bad_alloc);
/**
* Displays fatal error message, quitting after the user acks it (called by fatal_error()).
*
* Needs to be implemented by the graphics plugin.
*/
static void fatal_error() throw();
/**
* Enable or disable sound.
*
* Implemented by the generic window code.
*
* parameter enable: Enable sounds if true, otherwise disable sounds.
*/
static void sound_enable(bool enable) throw();
/**
* Are sounds enabled?
*/
static bool is_sound_enabled() throw();
/**
* Is sound system initialized?
*/
static bool sound_initialized() throw()
{
return sound_plugin::initialized();
}
/**
* Set sound device.
*/
static void set_sound_device(const std::string& dev) throw();
/**
* Get sound device.
*/
static std::string get_sound_device() throw(std::bad_alloc)
{
return sound_plugin::get_device();
}
/**
* Get list of sound devices.
*/
static std::map<std::string, std::string> get_sound_devices() throw(std::bad_alloc)
{
return sound_plugin::get_devices();
}
/**
* Show modal message dialog.
*
* Parameter text: The text for dialog.
* Parameter confirm: If true, display confirmation dialog, if false, display notification dialog.
* Returns: True, if confirmation dialog was confirmed, otherwise false.
*/
static bool modal_message(const std::string& text, bool confirm = false) throw()
{
return graphics_plugin::modal_message(text, confirm);
}
/**
* Process command and keypress queues.
*
* - If emulating normally, this routine returns fast.
* - If emulator is in pause mode, this routine will block until emulator has left pause mode.
* - If emulator is in some special mode, this routine can block until said mode is left.
*/
static void flush_command_queue() throw();
/**
* Enable/Disable pause mode.
*
* - This function doesn't actually block. For actual paused blocking, use flush_command_queue().
*
* Parameter enable: Enable pause mode if true, disable pause mode if false.
*/
static void set_paused(bool enable) throw();
/**
* Wait specified number of milliseconds before returning.
*
* - The command and keypresses queues are processed while waiting.
*
* Parameter usec: The number of microseconds to wait.
*/
static void wait(uint64_t usec) throw();
/**
* Cause call to wait() to return immediately.
*/
static void cancel_wait() throw();
/**
* Notify received message.
*/
static void notify_message() throw()
{
graphics_plugin::notify_message();
}
/**
* Notify changed status.
*/
static void notify_status() throw()
{
graphics_plugin::notify_status();
}
/**
* Notify changed screen.
*/
static void notify_screen() throw()
{
graphics_plugin::notify_screen();
}
/**
* Input audio sample (at specified rate).
*
* parameter left: Left sample.
* parameter right: Right sample.
*/
static void audio_sample(uint16_t left, uint16_t right) throw()
{
sound_plugin::sample(left, right);
}
/**
* Set modal pause mode.
*
* - Modal pause works like ordinary pause, except it uses a separate flag.
*
* Parameter enable: If true, enable modal pause, else disable it.
*/
static void set_modal_pause(bool enable) throw();
/**
* Queue keypress.
*
* - Can be called from any thread.
*
* Parameter k: The keypress to queue.
*/
static void queue(const keypress& k) throw(std::bad_alloc);
/**
* Queue command.
*
* - Can be called from any thread.
*
* Parameter c: The command to queue.
*/
static void queue(const std::string& c) throw(std::bad_alloc);
/**
* Queue function to be called in emulation thread.
*
* - Can be called from any thread (exception: Synchronous mode can not be used from emulation nor main threads).
*
* Parameter f: The function to execute.
* Parameter arg: Argument to pass to the function.
* Parameter sync: If true, execute function call synchronously, else asynchronously.
*/
static void queue(void (*f)(void* arg), void* arg, bool sync) throw(std::bad_alloc);
/**
* Run all queues.
*/
static void run_queues() throw();
};
/**
* Send a mouse click.
*
* Call from UI thread.
*/
void send_mouse_click(long x, long y, uint32_t buttons);
template<typename T>
void functor_call_helper(void* args)
{
(*reinterpret_cast<T*>(args))();
}
template<typename T>
void runemufn(T fn)
{
platform::queue(functor_call_helper<T>, &fn, true);
}
/**
* If set, queueing synchronous function produces a warning.
*/
extern volatile bool queue_synchronous_fn_warning;
#endif