Fix bug #24209 and add a global event scope

This adds a global event scope that an sdl_handler can register to in
order to receive all current events, regardless of the current
scope. Care should be taken to not be registerd in a local event
context and the global context at the same time as it will lead to the
event handler potentially being invoked twice.

This also adds the workaround needed for #24209 in the new event
handler in the video class.
This commit is contained in:
Andreas Löf 2016-01-01 15:50:54 +13:00
parent 6c0ecb6785
commit 544b61534c
4 changed files with 99 additions and 15 deletions

View file

@ -141,6 +141,10 @@ void context::set_focus(const sdl_handler* ptr)
//in that context. The current context is the one on the top of the stack
std::deque<context> event_contexts;
//add a global context for event handlers. Whichever object has joined this will always
//receive all events, regardless of the current context.
context global_context;
std::vector<pump_monitor*> pump_monitors;
} //end anon namespace
@ -185,7 +189,12 @@ event_context::~event_context()
sdl_handler::~sdl_handler()
{
leave();
if (has_joined_)
leave();
if (has_joined_global_)
leave_global();
#if !SDL_VERSION_ATLEAST(2, 0, 0)
SDL_EnableUNICODE(unicode_);
#endif
@ -227,6 +236,38 @@ void sdl_handler::leave()
has_joined_ = false;
}
void sdl_handler::join_global()
{
if(has_joined_global_) {
leave_global(); // should not be in multiple event contexts
}
//join self
global_context.add_handler(this);
has_joined_global_ = true;
//instruct members to join
sdl_handler_vector members = handler_members();
if(!members.empty()) {
for(sdl_handler_vector::iterator i = members.begin(); i != members.end(); ++i) {
(*i)->join_global();
}
}
}
void sdl_handler::leave_global()
{
sdl_handler_vector members = handler_members();
if(!members.empty()) {
for(sdl_handler_vector::iterator i = members.begin(); i != members.end(); ++i) {
(*i)->leave_global();
}
}
global_context.remove_handler(this);
has_joined_global_ = false;
}
void focus_handler(const sdl_handler* ptr)
{
if(event_contexts.empty() == false) {
@ -398,22 +439,14 @@ void pump()
case SDL_WINDOWEVENT_EXPOSED:
update_whole_screen();
if (display::get_singleton())
display::get_singleton()->redraw_everything();
break;
case SDL_WINDOWEVENT_RESIZED: {
case SDL_WINDOWEVENT_RESIZED:
info.resize_dimensions.first = event.window.data1;
info.resize_dimensions.second = event.window.data2;
break;
case SDL_WINDOWEVENT_MOVED:
case SDL_WINDOWEVENT_CLOSE:
break;
default:
if (display::get_singleton())
display::get_singleton()->redraw_everything();
}
}
break;
#else
case SDL_ACTIVEEVENT: {
@ -500,6 +533,11 @@ void pump()
}
}
const std::vector<sdl_handler*>& event_handlers = global_context.handlers;
for(size_t i1 = 0, i2 = event_handlers.size(); i1 != i2 && i1 < event_handlers.size(); ++i1) {
event_handlers[i1]->handle_event(event);
}
if(event_contexts.empty() == false) {
const std::vector<sdl_handler*>& event_handlers = event_contexts.back().handlers;
@ -510,6 +548,7 @@ void pump()
event_handlers[i1]->handle_event(event);
}
}
}
//inform the pump monitors that an events::pump() has occurred

View file

@ -55,6 +55,9 @@ public:
virtual void join(); /*joins the current event context*/
virtual void leave(); /*leave the event context*/
virtual void join_global(); /*join the global event context*/
virtual void leave_global(); /*leave the global event context*/
protected:
sdl_handler(const bool auto_join=true);
virtual ~sdl_handler();
@ -68,6 +71,7 @@ private:
int unicode_;
#endif
bool has_joined_;
bool has_joined_global_;
};
void focus_handler(const sdl_handler* ptr);

View file

@ -60,10 +60,7 @@ void resize_monitor::process(events::pump_info &info) {
}
}
#else
if(info.resize_dimensions.first > 0 &&
info.resize_dimensions.second > 0
&& display::get_singleton())
display::get_singleton()->redraw_everything();
UNUSED(info);
#endif
}
@ -355,6 +352,41 @@ void update_whole_screen()
{
update_all = true;
}
void CVideo::video_event_handler::handle_event(const SDL_Event &event)
{
#if SDL_VERSION_ATLEAST(2, 0, 0)
if (event.type == SDL_WINDOWEVENT) {
switch (event.window.event) {
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_RESTORED:
case SDL_WINDOWEVENT_SHOWN:
case SDL_WINDOWEVENT_EXPOSED:
if (display::get_singleton())
display::get_singleton()->redraw_everything();
break;
#if !SDL_VERSION_ATLEAST(2, 0, 4) && defined(_WIN32)
case SDL_WINDOWEVENT_FOCUS_GAINED:
if(SDL_GetWindowFlags(*window) & SDL_WINDOW_MAXIMIZED) {
SDL_RestoreWindow(*window);
SDL_MaximizeWindow(*window);
}
if(SDL_GetWindowFlags(*window) & SDL_WINDOW_FULLSCREEN_DESKTOP) {
SDL_RestoreWindow(*window);
SDL_SetWindowFullscreen(*window, SDL_WINDOW_FULLSCREEN_DESKTOP);
}
break;
#endif
}
}
#else
UNUSED(event);
#endif
}
CVideo::CVideo(FAKE_TYPES type) :
#ifdef SDL_GPU
shader_(),
@ -581,6 +613,7 @@ int CVideo::setMode( int x, int y, int bits_per_pixel, int flags )
// Note that x and y in this particular case refer to width and height of the window, not co-ordinates.
window = new sdl::twindow("", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, x, y, flags, SDL_RENDERER_SOFTWARE);
window->set_minimum_size(preferences::min_allowed_width(), preferences::min_allowed_height());
event_handler_.join_global();
} else {
if(fullScreen) {
window->full_screen();

View file

@ -218,6 +218,12 @@ class CVideo : private boost::noncopyable {
private:
class video_event_handler : public events::sdl_handler {
public:
virtual void handle_event(const SDL_Event &event);
video_event_handler() : sdl_handler(false) {}
};
void initSDL();
#ifdef SDL_GPU
void update_overlay(SDL_Rect *rect = NULL);
@ -233,6 +239,8 @@ private:
//if there is no display at all, but we 'fake' it for clients
bool fake_screen_;
video_event_handler event_handler_;
//variables for help strings
int help_string_;