40 #define ERR_GEN LOG_STREAM(err, lg::general) 44 struct invoked_function_data
46 explicit invoked_function_data(
const std::function<
void(
void)>& func)
53 const std::function<void(void)>&
f;
56 std::promise<void> finished;
66 finished.set_exception(std::current_exception());
83 staging_handlers.push_back(ptr);
88 if(handlers.cend() != std::find(handlers.cbegin(), handlers.cend(), ptr)) {
91 return staging_handlers.cend() != std::find(staging_handlers.cbegin(), staging_handlers.cend(), ptr);
101 if(!handlers.empty() && handlers.back() == ptr) {
102 if(focused_handler != handlers.end() && *focused_handler == ptr) {
103 focused_handler = handlers.end();
110 if(i == handlers.end()) {
114 auto j = std::find(staging_handlers.begin(), staging_handlers.end(), ptr);
115 if(j != staging_handlers.end()) {
116 staging_handlers.erase(j);
123 if(i == focused_handler) {
124 focused_handler != handlers.begin() ? --focused_handler : ++focused_handler;
135 focused_handler = handlers.end();
141 void context::cycle_focus()
143 if(handlers.begin() == handlers.end()) {
150 if(last != handlers.begin()) {
154 if(current == handlers.end()) {
155 current = handlers.begin();
160 while(current != last) {
161 if(current != handlers.end() && (*current)->requires_event_focus()) {
162 focused_handler = current;
166 if(current == handlers.end()) {
167 current = handlers.begin();
177 if(i != handlers.end() && (*i)->requires_event_focus()) {
182 void context::add_staging_handlers()
184 std::copy(staging_handlers.begin(), staging_handlers.end(), std::back_inserter(handlers));
185 staging_handlers.clear();
191 if(
h->has_joined()) {
192 h->has_joined_ =
false;
195 if(
h->has_joined_global()) {
196 h->has_joined_global_ =
false;
210 pump_monitor::pump_monitor()
212 pump_monitors.push_back(
this);
215 pump_monitor::~pump_monitor()
217 pump_monitors.erase(
std::remove(pump_monitors.begin(), pump_monitors.end(),
this), pump_monitors.end());
222 event_contexts.emplace_back();
225 event_context::~event_context()
227 assert(event_contexts.empty() ==
false);
228 event_contexts.pop_back();
231 sdl_handler::sdl_handler(
const bool auto_join)
233 , has_joined_global_(false)
236 assert(!event_contexts.empty());
237 event_contexts.back().add_handler(
this);
247 assert(!event_contexts.empty());
248 event_contexts.front().add_handler(
this);
250 bool found_context =
false;
253 found_context =
true;
259 if (!found_context) {
260 throw std::logic_error(
"Copy-constructing a sdl_handler that has_joined_ but can't be found by searching contexts");
300 assert(&event_contexts.back() != &event_contexts.front());
302 join(event_contexts.back());
338 join(event_contexts.back());
345 if(members.empty()) {
346 assert(event_contexts.empty() ==
false);
349 for(
auto member : members) {
373 event_contexts.front().add_handler(
this);
378 member->join_global();
385 member->leave_global();
388 event_contexts.front().remove_handler(
this);
395 if(event_contexts.empty() ==
false) {
396 event_contexts.back().set_focus(ptr);
402 if(event_contexts.empty()) {
411 auto& handlers = event_contexts.back().handlers;
415 if(foc == handlers.end()) {
421 if(foc_hand == hand) {
426 for(
auto i = handlers.rbegin();
i != handlers.rend(); ++
i) {
434 handlers.splice(handlers.end(), handlers, foc);
436 return thief_hand == hand;
458 if((a.type == SDL_WINDOWEVENT) && (
459 a.window.event == SDL_WINDOWEVENT_RESIZED ||
460 a.window.event == SDL_WINDOWEVENT_SIZE_CHANGED ||
461 a.window.event == SDL_WINDOWEVENT_EXPOSED)
483 static int last_mouse_down = -1;
484 static int last_click_x = -1, last_click_y = -1;
486 SDL_Event temp_event;
488 int begin_ignoring = 0;
490 std::vector<SDL_Event>
events;
491 while(SDL_PollEvent(&temp_event)) {
493 static_cast<invoked_function_data*
>(temp_event.user.data1)->call();
500 if(!begin_ignoring && temp_event.type == SDL_WINDOWEVENT && (
501 temp_event.window.event == SDL_WINDOWEVENT_ENTER ||
502 temp_event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
504 begin_ignoring = poll_count;
505 }
else if(begin_ignoring > 0 &&
is_input(temp_event)) {
510 events.push_back(temp_event);
513 auto ev_it = events.begin();
514 for(
int i = 1;
i < begin_ignoring; ++
i) {
517 ev_it = events.erase(ev_it);
523 bool resize_found =
false;
525 if(event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) {
527 last_resize_event = event;
528 last_resize_event_used =
false;
537 if(resize_found || SDL_GetTicks() <= last_resize_event.window.timestamp + resize_timeout) {
538 events.erase(std::remove_if(events.begin(), events.end(),
remove_on_resize), events.end());
539 }
else if(SDL_GetTicks() > last_resize_event.window.timestamp + resize_timeout && !
last_resize_event_used) {
541 last_resize_event_used =
true;
545 auto first_draw_event = std::stable_partition(events.begin(), events.end(),
549 if(first_draw_event != events.end()) {
551 events.erase(first_draw_event + 1, events.end());
554 for(SDL_Event& event : events) {
556 c.add_staging_handlers();
559 #ifdef MOUSE_TOUCH_EMULATION 560 switch (event.type) {
562 case SDL_MOUSEMOTION:
563 if(event.motion.which != SDL_TOUCH_MOUSEID && event.motion.state == 0) {
567 if(event.motion.state & SDL_BUTTON(SDL_BUTTON_RIGHT))
572 SDL_Event touch_event;
573 touch_event.type = SDL_FINGERMOTION;
574 touch_event.tfinger.type = SDL_FINGERMOTION;
575 touch_event.tfinger.timestamp =
event.motion.timestamp;
576 touch_event.tfinger.touchId = 1;
577 touch_event.tfinger.fingerId = 1;
578 touch_event.tfinger.dx =
static_cast<float>(
event.motion.xrel) / r.w;
579 touch_event.tfinger.dy = static_cast<float>(event.motion.yrel) / r.h;
580 touch_event.tfinger.x =
static_cast<float>(
event.motion.x) / r.w;
581 touch_event.tfinger.y = static_cast<float>(event.motion.y) / r.h;
582 touch_event.tfinger.pressure = 1;
583 ::SDL_PushEvent(&touch_event);
585 event.motion.state = SDL_BUTTON(SDL_BUTTON_LEFT);
586 event.motion.which = SDL_TOUCH_MOUSEID;
589 case SDL_MOUSEBUTTONDOWN:
590 case SDL_MOUSEBUTTONUP:
591 if(event.button.button == SDL_BUTTON_RIGHT)
593 event.button.button = SDL_BUTTON_LEFT;
594 event.button.which = SDL_TOUCH_MOUSEID;
597 SDL_Event touch_event;
598 touch_event.type = (
event.type == SDL_MOUSEBUTTONDOWN) ? SDL_FINGERDOWN : SDL_FINGERUP;
599 touch_event.tfinger.type = touch_event.type;
600 touch_event.tfinger.timestamp =
event.button.timestamp;
601 touch_event.tfinger.touchId = 1;
602 touch_event.tfinger.fingerId = 1;
603 touch_event.tfinger.dx = 0;
604 touch_event.tfinger.dy = 0;
605 touch_event.tfinger.x =
static_cast<float>(
event.button.x) / r.w;
606 touch_event.tfinger.y = static_cast<float>(event.button.y) / r.h;
607 touch_event.tfinger.pressure = 1;
608 ::SDL_PushEvent(&touch_event);
618 case SDL_WINDOWEVENT:
619 switch(event.window.event) {
620 case SDL_WINDOWEVENT_ENTER:
621 case SDL_WINDOWEVENT_FOCUS_GAINED:
625 case SDL_WINDOWEVENT_LEAVE:
626 case SDL_WINDOWEVENT_FOCUS_LOST:
630 case SDL_WINDOWEVENT_RESIZED:
639 for(
auto&
context : event_contexts) {
641 handler->handle_window_event(event);
645 for(
auto global_handler : event_contexts.front().
handlers) {
646 global_handler->handle_window_event(event);
653 case SDL_MOUSEMOTION: {
660 case SDL_MOUSEBUTTONDOWN: {
663 if(event.button.button == SDL_BUTTON_LEFT || event.button.which == SDL_TOUCH_MOUSEID) {
664 static const int DoubleClickTime = 500;
666 static const int DoubleClickMaxMove = 15;
668 static const int DoubleClickMaxMove = 3;
671 if(last_mouse_down >= 0 && info.
ticks() - last_mouse_down < DoubleClickTime
672 && std::abs(event.button.x - last_click_x) < DoubleClickMaxMove
673 && std::abs(event.button.y - last_click_y) < DoubleClickMaxMove
676 ::SDL_PushEvent(reinterpret_cast<SDL_Event*>(&user_event));
679 last_mouse_down = info.
ticks();
680 last_click_x =
event.button.x;
681 last_click_y =
event.button.y;
691 for(
auto&
context : event_contexts) {
693 handler->handle_event(event);
702 if(event.key.keysym.sym == SDLK_F4 &&
703 (event.key.keysym.mod == KMOD_RALT || event.key.keysym.mod == KMOD_LALT)
712 #if defined(_X11) && !defined(__APPLE__) 713 case SDL_SYSWMEVENT: {
721 case SDL_SYSWMEVENT: {
733 for(
auto global_handler : event_contexts.front().handlers) {
734 global_handler->handle_event(event);
737 if(event_contexts.empty() ==
false) {
738 for(
auto handler : event_contexts.back().handlers) {
739 handler->handle_event(event);
745 for(
auto monitor : pump_monitors) {
746 monitor->process(info);
752 if(event_contexts.empty() ==
false) {
753 event_contexts.back().add_staging_handlers();
755 for(
auto handler : event_contexts.back().handlers) {
756 handler->process_event();
764 event.window.type = SDL_WINDOWEVENT;
765 event.window.event = SDL_WINDOWEVENT_RESIZED;
766 event.window.windowID = 0;
770 SDL_PushEvent(&event);
775 if(event_contexts.empty() ==
false) {
776 event_contexts.back().add_staging_handlers();
780 for(
auto handler : event_contexts.back().handlers) {
788 for(
auto&
context : event_contexts) {
797 if(event_contexts.empty() ==
false) {
798 for(
auto handler : event_contexts.back().handlers) {
799 handler->volatile_draw();
806 for(
auto&
context : event_contexts) {
808 handler->volatile_draw();
815 if(event_contexts.empty() ==
false) {
816 for(
auto handler : event_contexts.back().handlers) {
817 handler->volatile_undraw();
824 if(event_contexts.empty() ==
false) {
825 for(
auto handler : event_contexts.back().handlers) {
826 handler->process_help_string(mousex, mousey);
827 handler->process_tooltip_string(mousex, mousey);
834 if(!ticks_ && !(refresh_counter && ++*refresh_counter % refresh_rate)) {
835 ticks_ = ::SDL_GetTicks();
842 #define INPUT_MIN 0x300 843 #define INPUT_MAX 0x8FF 858 int num = SDL_PeepEvents(events, 100, SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT);
859 for(
int i = 0;
i < num; ++
i) {
860 if(events[
i].
type == SDL_WINDOWEVENT && events[
i].window.event == SDL_WINDOWEVENT_RESIZED) {
874 invoked_function_data fdata{
f};
880 sdl_event.user = sdl_userevent;
882 SDL_PushEvent(&sdl_event);
885 fdata.finished.get_future().wait();
void raise_resize_event()
void raise_volatile_undraw_event()
void remove()
Removes a tip.
void discard_input()
Discards all input events.
std::vector< events::sdl_handler * > sdl_handler_vector
bool last_resize_event_used
#define INVOKE_FUNCTION_EVENT
static const std::thread::id main_thread
int ticks(unsigned *refresh_counter=nullptr, unsigned refresh_rate=1)
auto reversed_view(T &container)
void add_handler(sdl_handler *ptr)
virtual void leave_global()
Type that can be thrown as an exception to quit to desktop.
static CVideo & get_singleton()
bool remove_handler(sdl_handler *ptr)
virtual void join_same(sdl_handler *parent)
void call_in_main_thread(const std::function< void(void)> &f)
void raise_draw_all_event()
static bool remove_on_resize(const SDL_Event &a)
void focus_handler(const sdl_handler *ptr)
void set_focus(bool focus)
static events::event_context * event_context
void raise_volatile_draw_all_event()
sdl_handler & operator=(sdl_handler &&)=delete
Moving would require two instances' context membership to be handled, it's simpler to delete these an...
virtual bool requires_event_focus(const SDL_Event *=nullptr) const
sdl_handler(sdl_handler &&)=delete
int get_width(bool as_pixels=true) const
Returns the window renderer width in pixels or screen coordinates.
const uint32_t resize_timeout
#define DOUBLE_CLICK_EVENT
void raise_process_event()
static void quit_to_desktop()
#define SHOW_HELPTIP_EVENT
bool is_input(const SDL_Event &event)
Is the event an input event?
void raise_help_string_event(int mousex, int mousey)
void handle_system_event(const SDL_Event &)
void raise_volatile_draw_event()
virtual std::vector< sdl_handler * > handler_members()
int get_height(bool as_pixels=true) const
Returns the window renderer height in pixels or in screen coordinates.
std::deque< context > event_contexts
Handling of system events.
std::vector< pump_monitor * > pump_monitors
bool has_focus(const sdl_handler *hand, const SDL_Event *event)
Standard logging facilities (interface).
std::pair< int, int > resize_dimensions
SDL_Event last_resize_event
void update_framebuffer()
Updates and ensures the framebuffer surface is valid.
static void handle_system_event(const SDL_Event &event)
Frees resources when a notification disappears, switches user to the wesnoth window if the notificati...
SDL_Rect screen_area(bool as_pixels=true) const
Returns the current window renderer area, either in pixels or screen coordinates. ...
virtual void join_global()
std::string::const_iterator iterator
HOTKEY_COMMAND get_id(const std::string &command)
returns get_hotkey_command(command).id
bool has_handler(const sdl_handler *ptr) const
Returns true if ptr is found in either the handlers or staging_handlers lists.