43 #define ERR_GEN LOG_STREAM(err, lg::general) 46 #define LOG_DP LOG_STREAM(info, log_display) 49 #define LOG_EV LOG_STREAM(info, log_event) 50 #define DBG_EV LOG_STREAM(debug, log_event) 54 struct invoked_function_data
56 explicit invoked_function_data(
const std::function<
void(
void)>& func)
63 const std::function<void(void)>&
f;
66 std::promise<void> finished;
77 finished.set_exception(std::current_exception());
94 staging_handlers.push_back(ptr);
99 if(handlers.cend() != std::find(handlers.cbegin(), handlers.cend(), ptr)) {
102 return staging_handlers.cend() != std::find(staging_handlers.cbegin(), staging_handlers.cend(), ptr);
107 static int depth = 0;
112 if(!handlers.empty() && handlers.back() == ptr) {
113 if(focused_handler != handlers.end() && *focused_handler == ptr) {
114 focused_handler = handlers.end();
121 if(i == handlers.end()) {
125 auto j = std::find(staging_handlers.begin(), staging_handlers.end(), ptr);
126 if(j != staging_handlers.end()) {
127 staging_handlers.erase(j);
134 if(i == focused_handler) {
135 focused_handler != handlers.begin() ? --focused_handler : ++focused_handler;
146 focused_handler = handlers.end();
152 void context::cycle_focus()
154 if(handlers.begin() == handlers.end()) {
161 if(last != handlers.begin()) {
165 if(current == handlers.end()) {
166 current = handlers.begin();
171 while(current != last) {
172 if(current != handlers.end() && (*current)->requires_event_focus()) {
173 focused_handler = current;
177 if(current == handlers.end()) {
178 current = handlers.begin();
188 if(i != handlers.end() && (*i)->requires_event_focus()) {
193 void context::add_staging_handlers()
195 std::copy(staging_handlers.begin(), staging_handlers.end(), std::back_inserter(handlers));
196 staging_handlers.clear();
202 if(
h->has_joined()) {
203 h->has_joined_ =
false;
206 if(
h->has_joined_global()) {
207 h->has_joined_global_ =
false;
221 pump_monitor::pump_monitor()
223 pump_monitors.push_back(
this);
226 pump_monitor::~pump_monitor()
228 pump_monitors.erase(
std::remove(pump_monitors.begin(), pump_monitors.end(),
this), pump_monitors.end());
233 event_contexts.emplace_back();
236 event_context::~event_context()
238 assert(event_contexts.empty() ==
false);
239 event_contexts.pop_back();
242 sdl_handler::sdl_handler(
const bool auto_join)
244 , has_joined_global_(false)
247 assert(!event_contexts.empty());
248 event_contexts.back().add_handler(
this);
258 assert(!event_contexts.empty());
259 event_contexts.front().add_handler(
this);
261 bool found_context =
false;
264 found_context =
true;
270 if (!found_context) {
271 throw std::logic_error(
"Copy-constructing a sdl_handler that has_joined_ but can't be found by searching contexts");
311 assert(&event_contexts.back() != &event_contexts.front());
313 join(event_contexts.back());
349 join(event_contexts.back());
356 if(members.empty()) {
357 assert(event_contexts.empty() ==
false);
360 for(
auto member : members) {
384 event_contexts.front().add_handler(
this);
389 member->join_global();
396 member->leave_global();
399 event_contexts.front().remove_handler(
this);
406 if(event_contexts.empty() ==
false) {
407 event_contexts.back().set_focus(ptr);
413 if(event_contexts.empty()) {
422 auto& handlers = event_contexts.back().handlers;
426 if(foc == handlers.end()) {
432 if(foc_hand == hand) {
437 for(
auto i = handlers.rbegin();
i != handlers.rend(); ++
i) {
445 handlers.splice(handlers.end(), handlers, foc);
447 return thief_hand == hand;
457 for(
auto&
context : event_contexts) {
459 handler->handle_window_event(event);
463 for(
auto global_handler : event_contexts.front().
handlers) {
464 global_handler->handle_window_event(event);
488 static int last_mouse_down = -1;
489 static int last_click_x = -1, last_click_y = -1;
491 SDL_Event temp_event;
493 int begin_ignoring = 0;
495 std::vector<SDL_Event>
events;
496 while(SDL_PollEvent(&temp_event)) {
498 static_cast<invoked_function_data*
>(temp_event.user.data1)->call();
504 if(!begin_ignoring && temp_event.type == SDL_WINDOWEVENT && (
505 temp_event.window.event == SDL_WINDOWEVENT_ENTER ||
506 temp_event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
508 begin_ignoring = poll_count;
509 }
else if(begin_ignoring > 0 &&
is_input(temp_event)) {
514 events.push_back(temp_event);
517 auto ev_it = events.begin();
518 for(
int i = 1;
i < begin_ignoring; ++
i) {
521 ev_it = events.erase(ev_it);
527 for(SDL_Event& event : events) {
529 c.add_staging_handlers();
532 #ifdef MOUSE_TOUCH_EMULATION 533 switch (event.type) {
535 case SDL_MOUSEMOTION:
536 if(event.motion.which != SDL_TOUCH_MOUSEID && event.motion.state == 0) {
540 if(event.motion.state & SDL_BUTTON(SDL_BUTTON_RIGHT))
546 SDL_Event touch_event;
547 touch_event.type = SDL_FINGERMOTION;
548 touch_event.tfinger.type = SDL_FINGERMOTION;
549 touch_event.tfinger.timestamp =
event.motion.timestamp;
550 touch_event.tfinger.touchId = 1;
551 touch_event.tfinger.fingerId = 1;
552 touch_event.tfinger.dx =
static_cast<float>(
event.motion.xrel) / c.x;
553 touch_event.tfinger.dy = static_cast<float>(event.motion.yrel) / c.y;
554 touch_event.tfinger.x =
static_cast<float>(
event.motion.x) / c.x;
555 touch_event.tfinger.y = static_cast<float>(event.motion.y) / c.y;
556 touch_event.tfinger.pressure = 1;
557 ::SDL_PushEvent(&touch_event);
559 event.motion.state = SDL_BUTTON(SDL_BUTTON_LEFT);
560 event.motion.which = SDL_TOUCH_MOUSEID;
563 case SDL_MOUSEBUTTONDOWN:
564 case SDL_MOUSEBUTTONUP:
565 if(event.button.button == SDL_BUTTON_RIGHT)
567 event.button.button = SDL_BUTTON_LEFT;
568 event.button.which = SDL_TOUCH_MOUSEID;
573 SDL_Event touch_event;
574 touch_event.type = (
event.type == SDL_MOUSEBUTTONDOWN) ? SDL_FINGERDOWN : SDL_FINGERUP;
575 touch_event.tfinger.type = touch_event.type;
576 touch_event.tfinger.timestamp =
event.button.timestamp;
577 touch_event.tfinger.touchId = 1;
578 touch_event.tfinger.fingerId = 1;
579 touch_event.tfinger.dx = 0;
580 touch_event.tfinger.dy = 0;
581 touch_event.tfinger.x =
static_cast<float>(
event.button.x) / c.x;
582 touch_event.tfinger.y = static_cast<float>(event.button.y) / c.y;
583 touch_event.tfinger.pressure = 1;
584 ::SDL_PushEvent(&touch_event);
594 case SDL_WINDOWEVENT:
595 switch(event.window.event) {
596 case SDL_WINDOWEVENT_ENTER:
597 case SDL_WINDOWEVENT_FOCUS_GAINED:
601 case SDL_WINDOWEVENT_LEAVE:
602 case SDL_WINDOWEVENT_FOCUS_LOST:
608 case SDL_WINDOWEVENT_SIZE_CHANGED:
609 LOG_DP <<
"events/SIZE_CHANGED " 610 <<
event.window.data1 <<
'x' <<
event.window.data2;
617 case SDL_WINDOWEVENT_RESIZED:
618 LOG_DP <<
"events/RESIZED " 619 <<
event.window.data1 <<
'x' <<
event.window.data2;
626 case SDL_WINDOWEVENT_EXPOSED:
627 LOG_DP <<
"events/EXPOSED";
631 case SDL_WINDOWEVENT_MAXIMIZED:
632 case SDL_WINDOWEVENT_RESTORED:
633 case SDL_WINDOWEVENT_SHOWN:
634 case SDL_WINDOWEVENT_MOVED:
644 case SDL_MOUSEMOTION: {
651 case SDL_MOUSEBUTTONDOWN: {
654 if(event.button.button == SDL_BUTTON_LEFT || event.button.which == SDL_TOUCH_MOUSEID) {
655 static const int DoubleClickTime = 500;
657 static const int DoubleClickMaxMove = 15;
659 static const int DoubleClickMaxMove = 3;
662 if(last_mouse_down >= 0 && info.
ticks() - last_mouse_down < DoubleClickTime
663 && std::abs(event.button.x - last_click_x) < DoubleClickMaxMove
664 && std::abs(event.button.y - last_click_y) < DoubleClickMaxMove
667 ::SDL_PushEvent(reinterpret_cast<SDL_Event*>(&user_event));
670 last_mouse_down = info.
ticks();
671 last_click_x =
event.button.x;
672 last_click_y =
event.button.y;
679 if(event.key.keysym.sym == SDLK_F4 &&
680 (event.key.keysym.mod == KMOD_RALT || event.key.keysym.mod == KMOD_LALT)
689 #if defined(_X11) && !defined(__APPLE__) 690 case SDL_SYSWMEVENT: {
698 case SDL_SYSWMEVENT: {
710 for(
auto global_handler : event_contexts.front().handlers) {
711 global_handler->handle_event(event);
714 if(event_contexts.empty() ==
false) {
717 size_t ec_index = event_contexts.size();
720 size_t h_size = h.size();
721 for(
auto it = h.begin(); it != h.end(); ++it) {
723 (*it)->handle_event(event);
725 if(event_contexts.size() != ec_index) {
726 LOG_EV <<
"ec size changed! bugging out";
729 if(h_size != h.size()) {
730 LOG_EV <<
"h size changed! bugging out";
738 for(
auto monitor : pump_monitors) {
739 monitor->process(info);
750 if(event_contexts.empty() ==
false) {
751 event_contexts.back().add_staging_handlers();
753 for(
auto handler : event_contexts.back().handlers) {
754 handler->process_event();
763 event.window.type = SDL_WINDOWEVENT;
764 event.window.event = SDL_WINDOWEVENT_RESIZED;
765 event.window.windowID = 0;
766 event.window.data1 = size.x;
767 event.window.data2 = size.y;
774 if(event_contexts.empty() ==
false) {
775 for(
auto handler : event_contexts.back().handlers) {
776 handler->process_tooltip_string(mousex, mousey);
783 if(!ticks_ && !(refresh_counter && ++*refresh_counter % refresh_rate)) {
784 ticks_ = ::SDL_GetTicks();
791 #define INPUT_MIN 0x300 792 #define INPUT_MAX 0x8FF 812 invoked_function_data fdata{
f};
818 sdl_event.user = sdl_userevent;
820 SDL_PushEvent(&sdl_event);
823 fdata.finished.get_future().wait();
void raise_resize_event()
void remove()
Removes a tip.
void discard_input()
Discards all input events.
std::vector< events::sdl_handler * > sdl_handler_vector
#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()
std::string get_unknown_exception_type()
Utility function for finding the type of thing caught with catch(...).
bool remove_handler(sdl_handler *ptr)
static void raise_window_event(const SDL_Event &event)
static lg::log_domain log_event("event")
virtual void join_same(sdl_handler *parent)
void call_in_main_thread(const std::function< void(void)> &f)
void invalidate_all()
Mark the entire screen as requiring redraw.
void update_buffers(bool autoupdate)
Update buffers to match current resolution and pixel scale settings.
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
void focus_handler(const sdl_handler *ptr)
void set_focus(bool focus)
static events::event_context * event_context
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
void sparkle()
Ensure that everything which needs to be drawn is drawn.
std::list< sdl_handler * > handler_list
void pump()
Process all events currently in the queue.
std::string id
Text to match against addon_info.tags()
#define DOUBLE_CLICK_EVENT
void raise_process_event()
static void quit_to_desktop()
static lg::log_domain log_display("display")
bool is_input(const SDL_Event &event)
Is the event an input event?
void handle_system_event(const SDL_Event &)
point game_canvas_size()
The size of the game canvas, in drawing coordinates / game pixels.
virtual std::vector< sdl_handler * > handler_members()
Type that can be thrown as an exception to quit to desktop.
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).
point window_size()
Returns the size of the window in display units / screen coordinates.
std::pair< int, int > resize_dimensions
static void handle_system_event(const SDL_Event &event)
Frees resources when a notification disappears, switches user to the wesnoth window if the notificati...
virtual void join_global()
void draw()
Trigger a draw cycle.
std::string::const_iterator iterator
void process_tooltip_strings(int mousex, int mousey)
Triggered by mouse-motion, sends the cursor position to all handlers to check whether a tooltip shoul...
bool has_handler(const sdl_handler *ptr) const
Returns true if ptr is found in either the handlers or staging_handlers lists.