Refactor message handling

Refactor message handling so that message buffering and window handling
are in the main window code, leaving only message window rendering to
the platform code.
This commit is contained in:
Ilari Liusvaara 2011-11-01 14:58:27 +02:00
parent 2f20963264
commit 829cd4a2d0
6 changed files with 548 additions and 108 deletions

213
generic/messagebuffer.cpp Normal file
View file

@ -0,0 +1,213 @@
#include "messagebuffer.hpp"
messagebuffer::update_handler::~update_handler() throw()
{
}
messagebuffer::messagebuffer(size_t maxmessages, size_t windowsize) throw(std::bad_alloc, std::logic_error)
{
if(windowsize > maxmessages)
throw std::logic_error("Invalid window size");
if(maxmessages == 0)
throw std::logic_error("Invalid max message count");
first_present_message = 0;
next_message_number = 0;
window_start = 0;
max_messages = maxmessages;
window_size = windowsize;
scroll_frozen = false;
updates_frozen = false;
window_start_at_freeze = 0;
window_size_at_freeze = 0;
next_message_number_at_freeze = 0;
}
void messagebuffer::add_message(const std::string& msg) throw(std::bad_alloc, std::runtime_error)
{
messages[next_message_number++] = msg;
//If too many messages, erase one.
if(messages.size() > max_messages)
messages.erase(first_present_message++);
//Force scrolling if message in window got erased.
if(window_start < first_present_message) {
window_start = first_present_message;
send_notifications();
}
//Autoscrolling at the end.
if(!scroll_frozen && window_start + window_size + 1 == next_message_number) {
window_start++;
send_notifications();
}
}
const std::string& messagebuffer::get_message(size_t msgnum) throw(std::bad_alloc, std::logic_error)
{
if(!messages.count(msgnum))
throw std::logic_error("Invalid message number");
return messages[msgnum];
}
size_t messagebuffer::get_msg_first() throw()
{
return first_present_message;
}
size_t messagebuffer::get_msg_count() throw()
{
return next_message_number - first_present_message;
}
size_t messagebuffer::get_visible_first() throw()
{
return window_start;
}
size_t messagebuffer::get_visible_count() throw()
{
if(window_start + window_size > next_message_number)
return next_message_number - window_start;
else
return window_size;
}
bool messagebuffer::is_more_messages() throw()
{
return (window_start + window_size < next_message_number);
}
void messagebuffer::freeze_scrolling() throw()
{
scroll_frozen = true;
}
void messagebuffer::unfreeze_scrolling() throw()
{
scroll_frozen = false;
}
void messagebuffer::freeze_updates() throw()
{
updates_frozen = true;
window_size_at_freeze = window_size;
window_start_at_freeze = window_start;
next_message_number_at_freeze = next_message_number;
}
bool messagebuffer::unfreeze_updates() throw()
{
updates_frozen = false;
if(window_start_at_freeze < first_present_message)
return true;
uint64_t messages_visible_at_freeze;
uint64_t messages_visible_now;
if(window_start_at_freeze + window_size_at_freeze >= next_message_number_at_freeze)
messages_visible_at_freeze = next_message_number_at_freeze - window_start_at_freeze;
else
messages_visible_at_freeze = window_size_at_freeze;
messages_visible_now = get_visible_count();
if(messages_visible_now != messages_visible_at_freeze)
return true;
if(window_start_at_freeze != window_start)
return true;
return false;
}
void messagebuffer::scroll_beginning() throw(std::bad_alloc, std::runtime_error)
{
if(window_start == first_present_message)
return;
window_start = first_present_message;
send_notifications();
}
void messagebuffer::scroll_up_page() throw(std::bad_alloc, std::runtime_error)
{
if(window_start == first_present_message)
return;
if(window_start < first_present_message + window_size)
window_start = first_present_message;
else
window_start -= window_size;
send_notifications();
}
void messagebuffer::scroll_up_line() throw(std::bad_alloc, std::runtime_error)
{
if(window_start == first_present_message)
return;
window_start--;
send_notifications();
}
void messagebuffer::scroll_down_line() throw(std::bad_alloc, std::runtime_error)
{
if(window_start + window_size >= next_message_number)
return;
window_start++;
send_notifications();
}
void messagebuffer::scroll_down_page() throw(std::bad_alloc, std::runtime_error)
{
if(window_start + window_size >= next_message_number)
return;
window_start += window_size;
if(window_start + window_size >= next_message_number)
window_start = next_message_number - window_size;
send_notifications();
}
void messagebuffer::scroll_end() throw(std::bad_alloc, std::runtime_error)
{
if(first_present_message + window_size > next_message_number)
return;
window_start = next_message_number - window_size;
send_notifications();
}
void messagebuffer::register_handler(messagebuffer::update_handler& handler) throw(std::bad_alloc)
{
handlers.insert(&handler);
}
void messagebuffer::unregister_handler(messagebuffer::update_handler& handler) throw()
{
handlers.erase(&handler);
}
void messagebuffer::set_max_window_size(size_t windowsize) throw(std::bad_alloc, std::logic_error)
{
if(windowsize > max_messages)
throw std::logic_error("Invalid window size");
if(window_size > windowsize) {
//Shrink window.
size_t shrinkage = window_size - windowsize;
bool autoscrolling = !scroll_frozen && (window_start + window_size >= next_message_number);
if(autoscrolling && window_start + windowsize < next_message_number)
window_start = next_message_number - windowsize;
window_size = windowsize;
send_notifications();
} else if(window_size < windowsize) {
//Enlarge window.
size_t enlargement = windowsize - window_size;
if(first_present_message + windowsize >= next_message_number)
window_start = first_present_message;
else if(window_start + windowsize >= next_message_number)
window_start = next_message_number - windowsize;
window_size = windowsize;
send_notifications();
}
}
size_t messagebuffer::get_max_window_size() throw()
{
return window_size;
}
void messagebuffer::send_notifications()
{
if(updates_frozen)
return;
for(auto i : handlers)
i->messagebuffer_update();
}

207
generic/messagebuffer.hpp Normal file
View file

@ -0,0 +1,207 @@
#ifndef _messagebuffer__hpp__included__
#define _messagebuffer__hpp__included__
#include <stdexcept>
#include <map>
#include <set>
#include <cstdint>
#include <string>
class messagebuffer
{
public:
/**
* Update handler.
*/
class update_handler
{
public:
/**
* Destructor.
*/
virtual ~update_handler() throw();
/**
* Handle update.
*/
virtual void messagebuffer_update() throw(std::bad_alloc, std::runtime_error) = 0;
};
/**
* Create new message buffer with specified maximum message count.
*
* Parameter maxmessages: The maximum number of messages.
* Parameter windowsize: The initial window size.
* Throws std::bad_alloc: Not enough memory.
* Throws std::logic_error: Windowsize is greater than maxmessages or maxmessages is zero.
*/
messagebuffer(size_t maxmessages, size_t windowsize) throw(std::bad_alloc, std::logic_error);
/**
* Add a new message to the buffer.
*
* Parameter msg: The new message to add.
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void add_message(const std::string& msg) throw(std::bad_alloc, std::runtime_error);
/**
* Read a message.
*
* Parameter msgnum: Number of message to read.
* Returns: The read message.
* Throws std::bad_alloc: Not enough memory.
* Throws std::logic_error: Invalid message number.
*/
const std::string& get_message(size_t msgnum) throw(std::bad_alloc, std::logic_error);
/**
* Get the number of first message present.
*
* Returns: The number of first message present.
*/
size_t get_msg_first() throw();
/**
* Get the number of messages present.
*
* Returns: The number of messages present.
*/
size_t get_msg_count() throw();
/**
* Get the number of first message visible.
*
* Returns: The number of first message visible.
*/
size_t get_visible_first() throw();
/**
* Get the number of messages visible.
*
* Returns: The number of messages visible.
*/
size_t get_visible_count() throw();
/**
* Is there more messages after the current window?
*
* Returns: True if there is, false if not.
*/
bool is_more_messages() throw();
/**
* Freeze scrolling
*/
void freeze_scrolling() throw();
/**
* Unfreeze scrolling
*/
void unfreeze_scrolling() throw();
/**
* Freeze updates
*/
void freeze_updates() throw();
/**
* Unfreeze updates
*
* Returns: True if update is needed.
*/
bool unfreeze_updates() throw();
/**
* Scroll to beginning.
*
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void scroll_beginning() throw(std::bad_alloc, std::runtime_error);
/**
* Scroll up one page.
*
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void scroll_up_page() throw(std::bad_alloc, std::runtime_error);
/**
* Scroll up one line.
*
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void scroll_up_line() throw(std::bad_alloc, std::runtime_error);
/**
* Scroll down one line.
*
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void scroll_down_line() throw(std::bad_alloc, std::runtime_error);
/**
* Scroll down one page.
*
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void scroll_down_page() throw(std::bad_alloc, std::runtime_error);
/**
* Scroll to beginning.
*
* Throws std::bad_alloc: Not enough memory.
* Throws std::runtime_error: Thrown through from update handler.
*/
void scroll_end() throw(std::bad_alloc, std::runtime_error);
/**
* Register an update handler.
*
* Parameter handler: The new handler.
* Throws std::bad_alloc: Not enough memory.
*/
void register_handler(update_handler& handler) throw(std::bad_alloc);
/**
* Unregister an update handler.
*
* Parameter handler: The handler to remove.
* Throws std::bad_alloc: Not enough memory.
*/
void unregister_handler(update_handler& handler) throw();
/**
* Change the window size.
*
* Parameter windowsize: The new window size.
* Throws std::bad_alloc: Not enough memory.
* Throws std::logic_error: Windowsize is greater than maxmessages or maxmessages is zero.
*/
void set_max_window_size(size_t windowsize) throw(std::bad_alloc, std::logic_error);
/**
* Read the window size.
*/
size_t get_max_window_size() throw();
private:
void send_notifications();
std::map<uint64_t, std::string> messages;
uint64_t first_present_message;
uint64_t next_message_number;
uint64_t window_start;
size_t max_messages;
size_t window_size;
bool scroll_frozen;
bool updates_frozen;
uint64_t window_start_at_freeze;
uint64_t window_size_at_freeze;
uint64_t next_message_number_at_freeze;
std::set<update_handler*> handlers;
};
#endif

View file

@ -1,5 +1,7 @@
#include "window.hpp" #include "window.hpp"
#include "command.hpp" #include "command.hpp"
#include "misc.hpp"
#include <fstream>
#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>
@ -9,6 +11,10 @@
#include <boost/iostreams/filtering_stream.hpp> #include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/device/back_inserter.hpp> #include <boost/iostreams/device/back_inserter.hpp>
#define MAXMESSAGES 5000
#define INIT_WIN_SIZE 6
namespace namespace
{ {
function_ptr_command<> identify_key("show-plugins", "Show plugins in use", function_ptr_command<> identify_key("show-plugins", "Show plugins in use",
@ -117,6 +123,17 @@ namespace
std::vector<char> stream; std::vector<char> stream;
}; };
class msgcallback : public messagebuffer::update_handler
{
public:
~msgcallback() throw() {};
void messagebuffer_update() throw(std::bad_alloc, std::runtime_error)
{
window::notify_message();
}
} msg_callback_obj;
std::ofstream system_log;
window_callback* wcb = NULL; window_callback* wcb = NULL;
uint32_t vc_xoffset; uint32_t vc_xoffset;
uint32_t vc_yoffset; uint32_t vc_yoffset;
@ -131,6 +148,15 @@ std::map<std::string, std::string>& window::get_emustatus() throw()
void window::init() void window::init()
{ {
msgbuf.register_handler(msg_callback_obj);
system_log.open("lsnes.log", std::ios_base::out | std::ios_base::app);
time_t curtime = __real_time(NULL);
struct tm* tm = localtime(&curtime);
char buffer[1024];
strftime(buffer, 1023, "%Y-%m-%d %H:%M:%S %Z", tm);
system_log << "-----------------------------------------------------------------------" << std::endl;
system_log << "lsnes started at " << buffer << std::endl;
system_log << "-----------------------------------------------------------------------" << std::endl;
graphics_init(); graphics_init();
sound_init(); sound_init();
joystick_init(); joystick_init();
@ -141,6 +167,15 @@ void window::quit()
joystick_quit(); joystick_quit();
sound_quit(); sound_quit();
graphics_quit(); graphics_quit();
msgbuf.unregister_handler(msg_callback_obj);
time_t curtime = __real_time(NULL);
struct tm* tm = localtime(&curtime);
char buffer[1024];
strftime(buffer, 1023, "%Y-%m-%d %H:%M:%S %Z", tm);
system_log << "-----------------------------------------------------------------------" << std::endl;
system_log << "lsnes shutting down at " << buffer << std::endl;
system_log << "-----------------------------------------------------------------------" << std::endl;
system_log.close();
} }
std::ostream& window::out() throw(std::bad_alloc) std::ostream& window::out() throw(std::bad_alloc)
@ -160,6 +195,43 @@ void window::set_window_compensation(uint32_t xoffset, uint32_t yoffset, uint32_
vc_vscl = vscl; vc_vscl = vscl;
} }
messagebuffer window::msgbuf(MAXMESSAGES, INIT_WIN_SIZE);
void window::message(const std::string& msg) throw(std::bad_alloc)
{
std::string msg2 = msg;
while(msg2 != "") {
size_t s = msg2.find_first_of("\n");
std::string forlog;
if(s >= msg2.length()) {
msgbuf.add_message(forlog = msg2);
if(system_log)
system_log << forlog << std::endl;
break;
} else {
msgbuf.add_message(forlog = msg2.substr(0, s));
if(system_log)
system_log << forlog << std::endl;
msg2 = msg2.substr(s + 1);
}
}
}
void window::fatal_error() throw()
{
time_t curtime = __real_time(NULL);
struct tm* tm = localtime(&curtime);
char buffer[1024];
strftime(buffer, 1023, "%Y-%m-%d %H:%M:%S %Z", tm);
system_log << "-----------------------------------------------------------------------" << std::endl;
system_log << "lsnes paniced at " << buffer << std::endl;
system_log << "-----------------------------------------------------------------------" << std::endl;
system_log.close();
fatal_error2();
exit(1);
}
window_callback::~window_callback() throw() window_callback::~window_callback() throw()
{ {
} }

View file

@ -2,6 +2,7 @@
#define _window__hpp__included__ #define _window__hpp__included__
#include "render.hpp" #include "render.hpp"
#include "messagebuffer.hpp"
#include <string> #include <string>
#include <map> #include <map>
#include <list> #include <list>
@ -113,17 +114,38 @@ public:
*/ */
static void set_window_compensation(uint32_t xoffset, uint32_t yoffset, uint32_t hscl, uint32_t vscl); static void set_window_compensation(uint32_t xoffset, uint32_t yoffset, uint32_t hscl, uint32_t vscl);
/******************************** GRAPHICS PLUGIN **********************************/ /**
* Message buffer.
*
* Implemented by the generic window code.
*/
static messagebuffer msgbuf;
/** /**
* Adds a messages to mesage queue to be shown. * Adds a messages to mesage queue to be shown.
* *
* Needs to be implemented by the graphics plugin. * Implemented by the generic window code.
* *
* parameter msg: The messages to add (split by '\n'). * parameter msg: The messages to add (split by '\n').
* throws std::bad_alloc: Not enough memory. * throws std::bad_alloc: Not enough memory.
*/ */
static void message(const std::string& msg) throw(std::bad_alloc); 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();
/******************************** GRAPHICS PLUGIN **********************************/
/**
* Notification when messages get updated.
*
* Needs to be implemented by the graphics plugin.
*/
static void notify_message() throw(std::bad_alloc, std::runtime_error);
/** /**
* Displays a modal message, not returning until the message is acknowledged. Keybindings are not available, but * Displays a modal message, not returning until the message is acknowledged. Keybindings are not available, but
* should quit be generated somehow, modal message will be closed and command callback triggered. * should quit be generated somehow, modal message will be closed and command callback triggered.
@ -138,11 +160,11 @@ public:
static bool modal_message(const std::string& msg, bool confirm = false) throw(std::bad_alloc); static bool modal_message(const std::string& msg, bool confirm = false) throw(std::bad_alloc);
/** /**
* Displays fatal error message, quitting after the user acks it. * Displays fatal error message, quitting after the user acks it (called by fatal_error()).
* *
* Needs to be implemented by the graphics plugin. * Needs to be implemented by the graphics plugin.
*/ */
static void fatal_error() throw(); static void fatal_error2() throw();
/** /**
* Processes inputs. If in non-modal mode (normal mode without pause), this returns quickly. Otherwise it waits * Processes inputs. If in non-modal mode (normal mode without pause), this returns quickly. Otherwise it waits
@ -268,6 +290,7 @@ private:
window& operator==(const window&); window& operator==(const window&);
}; };
/** /**
* Names of plugins. * Names of plugins.
*/ */

View file

@ -14,10 +14,9 @@
#include <fstream> #include <fstream>
#include <cassert> #include <cassert>
#define WATCHDOG_TIMEOUT 15
#define MAXMESSAGES 6
#define MSGHISTORY 1000
#define MAXHISTORY 1000 #define MAXHISTORY 1000
#define MAXMESSAGES 6
#define WATCHDOG_TIMEOUT 15
#include <SDL.h> #include <SDL.h>
#include <string> #include <string>
@ -471,12 +470,7 @@ namespace
unsigned old_screen_w; unsigned old_screen_w;
unsigned old_screen_h; unsigned old_screen_h;
unsigned state; unsigned state;
std::map<uint64_t, std::string> messagebuffer;
uint64_t messagebuffer_next_seq;
uint64_t messagebuffer_first_seq;
uint64_t messagebuffer_first_show;
bool console_mode; bool console_mode;
uint32_t maxmessages;
std::list<std::string> commandhistory; std::list<std::string> commandhistory;
std::list<std::string>::iterator commandhistory_itr; std::list<std::string>::iterator commandhistory_itr;
screen* current_screen; screen* current_screen;
@ -986,14 +980,6 @@ void graphics_init()
alarm(WATCHDOG_TIMEOUT); alarm(WATCHDOG_TIMEOUT);
#endif #endif
init_keys(); init_keys();
system_log.open("lsnes.log", std::ios_base::out | std::ios_base::app);
time_t curtime = __real_time(NULL);
struct tm* tm = localtime(&curtime);
char buffer[1024];
strftime(buffer, 1023, "%Y-%m-%d %H:%M:%S %Z", tm);
system_log << "-----------------------------------------------------------------------" << std::endl;
system_log << "lsnes started at " << buffer << std::endl;
system_log << "-----------------------------------------------------------------------" << std::endl;
if(!sdl_init) { if(!sdl_init) {
SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_TIMER); SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_JOYSTICK | SDL_INIT_TIMER);
SDL_EnableUNICODE(true); SDL_EnableUNICODE(true);
@ -1009,11 +995,7 @@ void graphics_init()
old_screen_w = 0; old_screen_w = 0;
modal_return_flag = false; modal_return_flag = false;
delayed_close_flag = false; delayed_close_flag = false;
messagebuffer_next_seq = 0;
messagebuffer_first_seq = 0;
messagebuffer_first_show = 0;
console_mode = false; console_mode = false;
maxmessages = MAXMESSAGES;
window::notify_screen_update(); window::notify_screen_update();
std::string windowname = "lsnes-" + lsnes_version + "[" + bsnes_core_version + "]"; std::string windowname = "lsnes-" + lsnes_version + "[" + bsnes_core_version + "]";
@ -1024,14 +1006,6 @@ void graphics_init()
void graphics_quit() void graphics_quit()
{ {
time_t curtime = time(NULL);
struct tm* tm = localtime(&curtime);
char buffer[1024];
strftime(buffer, 1023, "%Y-%m-%d %H:%M:%S %Z", tm);
system_log << "-----------------------------------------------------------------------" << std::endl;
system_log << "lsnes shutting down at " << buffer << std::endl;
system_log << "-----------------------------------------------------------------------" << std::endl;
system_log.close();
if(sdl_init) { if(sdl_init) {
SDL_RemoveTimer(tid); SDL_RemoveTimer(tid);
SDL_Quit(); SDL_Quit();
@ -1055,38 +1029,8 @@ bool window::modal_message(const std::string& msg, bool confirm) throw(std::bad_
return ret; return ret;
} }
void window::message(const std::string& msg) throw(std::bad_alloc) void window::notify_message() throw(std::bad_alloc, std::runtime_error)
{ {
std::string msg2 = msg;
bool locked_mode = (messagebuffer_next_seq - messagebuffer_first_show <= maxmessages) ;
while(msg2 != "") {
size_t s = msg2.find_first_of("\n");
std::string forlog;
if(s >= msg2.length()) {
if(SDL_initialized) {
messagebuffer[messagebuffer_next_seq++] = (forlog = msg2);
system_log << forlog << std::endl;
} else
std::cerr << msg2 << std::endl;
break;
} else {
if(SDL_initialized) {
messagebuffer[messagebuffer_next_seq++] = (forlog = msg2.substr(0, s));
system_log << forlog << std::endl;
} else
std::cerr << msg2.substr(0, s) << std::endl;
msg2 = msg2.substr(s + 1);
}
}
if(locked_mode && messagebuffer_first_show + maxmessages < messagebuffer_next_seq)
messagebuffer_first_show = messagebuffer_next_seq - maxmessages;
while(messagebuffer.size() > MSGHISTORY) {
messagebuffer.erase(messagebuffer_first_seq++);
if(messagebuffer_first_show < messagebuffer_first_seq)
messagebuffer_first_show = messagebuffer_first_seq;
}
notify_screen_update(); notify_screen_update();
} }
@ -1219,17 +1163,19 @@ namespace
message_y = screensize.second + 16; message_y = screensize.second + 16;
else else
message_y = 6; message_y = 6;
size_t maxmessages = window::msgbuf.get_max_window_size();
size_t msgnum = window::msgbuf.get_visible_first();
size_t visible = window::msgbuf.get_visible_count();
for(size_t j = 0; j < maxmessages; j++) for(size_t j = 0; j < maxmessages; j++)
try { try {
std::ostringstream o; std::ostringstream o;
if(messagebuffer_first_show + j < messagebuffer_next_seq) if(j < visible)
o << (messagebuffer_first_show + j + 1) << ": " o << (msgnum + j + 1) << ": " << window::msgbuf.get_message(msgnum + j);
<< messagebuffer[messagebuffer_first_show + j];
draw_string(reinterpret_cast<uint8_t*>(swsurf->pixels), swsurf->pitch, o.str(), 6, draw_string(reinterpret_cast<uint8_t*>(swsurf->pixels), swsurf->pitch, o.str(), 6,
message_y + 16 * j, windowsize.first - 12); message_y + 16 * j, windowsize.first - 12);
} catch(...) { } catch(...) {
} }
if(messagebuffer_next_seq - messagebuffer_first_show > maxmessages) if(window::msgbuf.is_more_messages())
try { try {
draw_string(reinterpret_cast<uint8_t*>(swsurf->pixels), swsurf->pitch, "--More--", draw_string(reinterpret_cast<uint8_t*>(swsurf->pixels), swsurf->pitch, "--More--",
windowsize.first - 76, message_y + 16 * maxmessages - 16, 64); windowsize.first - 76, message_y + 16 * maxmessages - 16, 64);
@ -1357,41 +1303,25 @@ namespace
function_ptr_command<> scroll_up("scroll-up", "Scroll messages a page up", function_ptr_command<> scroll_up("scroll-up", "Scroll messages a page up",
"Syntax: scroll-up\nScrolls message console backward one page.\n", "Syntax: scroll-up\nScrolls message console backward one page.\n",
[]() throw(std::bad_alloc, std::runtime_error) { []() throw(std::bad_alloc, std::runtime_error) {
if(messagebuffer_first_show > maxmessages) window::msgbuf.scroll_up_page();
messagebuffer_first_show -= maxmessages;
else
messagebuffer_first_show = 0;
if(messagebuffer_first_show < messagebuffer_first_seq)
messagebuffer_first_show = messagebuffer_first_seq;
window::notify_screen_update();
}); });
function_ptr_command<> scroll_fullup("scroll-fullup", "Scroll messages to beginning", function_ptr_command<> scroll_fullup("scroll-fullup", "Scroll messages to beginning",
"Syntax: scroll-fullup\nScrolls message console to its beginning.\n", "Syntax: scroll-fullup\nScrolls message console to its beginning.\n",
[]() throw(std::bad_alloc, std::runtime_error) { []() throw(std::bad_alloc, std::runtime_error) {
messagebuffer_first_show = messagebuffer_first_seq; window::msgbuf.scroll_beginning();
window::notify_screen_update();
}); });
function_ptr_command<> scroll_fulldown("scroll-fulldown", "Scroll messages to end", function_ptr_command<> scroll_fulldown("scroll-fulldown", "Scroll messages to end",
"Syntax: scroll-fulldown\nScrolls message console to its end.\n", "Syntax: scroll-fulldown\nScrolls message console to its end.\n",
[]() throw(std::bad_alloc, std::runtime_error) { []() throw(std::bad_alloc, std::runtime_error) {
if(messagebuffer_next_seq < maxmessages) window::msgbuf.scroll_end();
messagebuffer_first_show = 0;
else
messagebuffer_first_show = messagebuffer_next_seq - maxmessages;
window::notify_screen_update();
}); });
function_ptr_command<> scrolldown("scroll-down", "Scroll messages a page down", function_ptr_command<> scrolldown("scroll-down", "Scroll messages a page down",
"Syntax: scroll-up\nScrolls message console forward one page.\n", "Syntax: scroll-up\nScrolls message console forward one page.\n",
[]() throw(std::bad_alloc, std::runtime_error) { []() throw(std::bad_alloc, std::runtime_error) {
messagebuffer_first_show += maxmessages; window::msgbuf.scroll_down_page();
if(messagebuffer_next_seq < maxmessages)
messagebuffer_first_show = 0;
else if(messagebuffer_next_seq < messagebuffer_first_show + maxmessages)
messagebuffer_first_show = messagebuffer_next_seq - maxmessages;
window::notify_screen_update();
}); });
function_ptr_command<> toggle_console("toggle-console", "Toggle console between small and full window", function_ptr_command<> toggle_console("toggle-console", "Toggle console between small and full window",
@ -1399,13 +1329,9 @@ namespace
[]() throw(std::bad_alloc, std::runtime_error) { []() throw(std::bad_alloc, std::runtime_error) {
console_mode = !console_mode; console_mode = !console_mode;
if(console_mode) if(console_mode)
maxmessages = hwsurf ? (hwsurf->h - 38) / 16 : 36; window::msgbuf.set_max_window_size(hwsurf ? (hwsurf->h - 38) / 16 : 36);
else else
maxmessages = MAXMESSAGES; window::msgbuf.set_max_window_size(MAXMESSAGES);
if(messagebuffer_next_seq < maxmessages)
messagebuffer_first_show = 0;
else
messagebuffer_first_show = messagebuffer_next_seq - maxmessages;
window::notify_screen_update(true); window::notify_screen_update(true);
}); });
} }
@ -1430,7 +1356,7 @@ void window::wait_usec(uint64_t usec) throw(std::bad_alloc)
wait_canceled = false; wait_canceled = false;
} }
void window::fatal_error() throw() void window::fatal_error2() throw()
{ {
try { try {
message("PANIC: Cannot continue, press ESC or close window to exit."); message("PANIC: Cannot continue, press ESC or close window to exit.");
@ -1440,14 +1366,6 @@ void window::fatal_error() throw()
//Just crash. //Just crash.
exit(1); exit(1);
} }
time_t curtime = time(NULL);
struct tm* tm = localtime(&curtime);
char buffer[1024];
strftime(buffer, 1023, "%Y-%m-%d %H:%M:%S %Z", tm);
system_log << "-----------------------------------------------------------------------" << std::endl;
system_log << "lsnes paniced at " << buffer << std::endl;
system_log << "-----------------------------------------------------------------------" << std::endl;
system_log.close();
while(true) { while(true) {
SDL_Event e; SDL_Event e;
if(SDL_WaitEvent(&e)) { if(SDL_WaitEvent(&e)) {

View file

@ -2,6 +2,11 @@
#include <cstdlib> #include <cstdlib>
#include <iostream> #include <iostream>
namespace
{
uint64_t next_message_to_print = 0;
}
void graphics_init() {} void graphics_init() {}
void graphics_quit() {} void graphics_quit() {}
void window::poll_inputs() throw(std::bad_alloc) {} void window::poll_inputs() throw(std::bad_alloc) {}
@ -17,18 +22,20 @@ bool window::modal_message(const std::string& msg, bool confirm) throw(std::bad_
return confirm; return confirm;
} }
void window::fatal_error() throw() void window::fatal_error2() throw()
{ {
std::cerr << "Exiting on fatal error." << std::endl; std::cerr << "Exiting on fatal error." << std::endl;
exit(1); exit(1);
} }
void window::message(const std::string& msg) throw(std::bad_alloc) void window::notify_message() throw(std::bad_alloc, std::runtime_error)
{ {
if(msg[msg.length() - 1] == '\n') while(msgbuf.get_msg_first() + msgbuf.get_msg_count() > next_message_to_print) {
std::cout << msg; if(msgbuf.get_msg_first() > next_message_to_print)
else next_message_to_print = msgbuf.get_msg_first();
std::cout << msg << std::endl; else
std::cout << msgbuf.get_message(next_message_to_print++) << std::endl;
}
} }
const char* graphics_plugin_name = "Dummy graphics plugin"; const char* graphics_plugin_name = "Dummy graphics plugin";