The Battle for Wesnoth  1.15.0-dev
events.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
3  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "events.hpp"
16 #include "cursor.hpp"
17 #include "desktop/clipboard.hpp"
18 #include "log.hpp"
19 #include "quit_confirmation.hpp"
20 #include "video.hpp"
21 #include "sdl/userevent.hpp"
22 
23 #if defined _WIN32
25 #endif
26 
27 #include <algorithm>
28 #include <atomic>
29 #include <cassert>
30 #include <deque>
31 #include <iterator>
32 #include <utility>
33 #include <vector>
34 #include <thread>
35 
36 #include <SDL.h>
37 
38 #include <boost/range/adaptor/reversed.hpp>
39 
40 #define ERR_GEN LOG_STREAM(err, lg::general)
41 
42 namespace
43 {
44 struct invoked_function_data
45 {
46  explicit invoked_function_data(const std::function<void(void)>& func)
47  : f(func)
48  , finished(false)
49  , thrown_exception()
50  {
51  }
52 
53  /** The actual function to call. */
54  const std::function<void(void)>& f;
55 
56  /** Whether execution in the main thread is complete. */
57  std::atomic_bool finished;
58 
59  /** Stores any exception thrown during the execution of @ref f. */
60  std::exception_ptr thrown_exception;
61 
62  void call()
63  {
64  try {
65  f();
66  } catch(const CVideo::quit&) {
67  // Handle this exception in the main thread.
68  throw;
69  } catch(...) {
70  thrown_exception = std::current_exception();
71  }
72 
73  finished = true;
74  }
75 };
76 }
77 
78 namespace events
79 {
80 void context::add_handler(sdl_handler* ptr)
81 {
82  /* Add new handlers to the staging list initially.
83  * This ensures that if an event handler adds more handlers, the new handlers
84  * won't be called for the event that caused them to be added.
85  */
86  staging_handlers.push_back(ptr);
87 }
88 
89 bool context::remove_handler(sdl_handler* ptr)
90 {
91  static int depth = 0;
92  ++depth;
93 
94  // The handler is most likely on the back of the events list,
95  // so look there first, otherwise do a complete search.
96  if(!handlers.empty() && handlers.back() == ptr) {
97  if(focused_handler != handlers.end() && *focused_handler == ptr) {
98  focused_handler = handlers.end();
99  }
100 
101  handlers.pop_back();
102  } else {
103  const handler_list::iterator i = std::find(handlers.begin(), handlers.end(), ptr);
104 
105  if(i == handlers.end()) {
106  --depth;
107 
108  // The handler may be in the staging area. Search it from there.
109  auto j = std::find(staging_handlers.begin(), staging_handlers.end(), ptr);
110  if(j != staging_handlers.end()) {
111  staging_handlers.erase(j);
112  return true;
113  } else {
114  return false;
115  }
116  }
117 
118  if(i == focused_handler) {
119  focused_handler != handlers.begin() ? --focused_handler : ++focused_handler;
120  }
121 
122  handlers.erase(i);
123  }
124 
125  --depth;
126 
127  if(depth == 0) {
128  cycle_focus();
129  } else {
130  focused_handler = handlers.end();
131  }
132 
133  return true;
134 }
135 
136 void context::cycle_focus()
137 {
138  if(handlers.begin() == handlers.end()) {
139  return;
140  }
141 
142  handler_list::iterator current = focused_handler;
143  handler_list::iterator last = focused_handler;
144 
145  if(last != handlers.begin()) {
146  --last;
147  }
148 
149  if(current == handlers.end()) {
150  current = handlers.begin();
151  } else {
152  ++current;
153  }
154 
155  while(current != last) {
156  if(current != handlers.end() && (*current)->requires_event_focus()) {
157  focused_handler = current;
158  break;
159  }
160 
161  if(current == handlers.end()) {
162  current = handlers.begin();
163  } else {
164  ++current;
165  }
166  }
167 }
168 
170 {
171  const handler_list::iterator i = std::find(handlers.begin(), handlers.end(), ptr);
172  if(i != handlers.end() && (*i)->requires_event_focus()) {
173  focused_handler = i;
174  }
175 }
176 
177 void context::add_staging_handlers()
178 {
179  std::copy(staging_handlers.begin(), staging_handlers.end(), std::back_inserter(handlers));
180  staging_handlers.clear();
181 }
182 
183 context::~context()
184 {
185  for(sdl_handler* h : handlers) {
186  if(h->has_joined()) {
187  h->has_joined_ = false;
188  }
189 
190  if(h->has_joined_global()) {
191  h->has_joined_global_ = false;
192  }
193  }
194 }
195 
196 // This object stores all the event handlers. It is a stack of event 'contexts'.
197 // a new event context is created when e.g. a modal dialog is opened, and then
198 // closed when that dialog is closed. Each context contains a list of the handlers
199 // in that context. The current context is the one on the top of the stack.
200 // The global context must always be in the first position.
201 std::deque<context> event_contexts;
202 
203 std::vector<pump_monitor*> pump_monitors;
204 
205 pump_monitor::pump_monitor()
206 {
207  pump_monitors.push_back(this);
208 }
209 
210 pump_monitor::~pump_monitor()
211 {
212  pump_monitors.erase(std::remove(pump_monitors.begin(), pump_monitors.end(), this), pump_monitors.end());
213 }
214 
216 {
217  event_contexts.emplace_back();
218 }
219 
220 event_context::~event_context()
221 {
222  assert(event_contexts.empty() == false);
223  event_contexts.pop_back();
224 }
225 
226 sdl_handler::sdl_handler(const bool auto_join)
227  : has_joined_(false)
228  , has_joined_global_(false)
229 {
230  if(auto_join) {
231  assert(!event_contexts.empty());
232  event_contexts.back().add_handler(this);
233  has_joined_ = true;
234  }
235 }
236 
238 {
239  if(has_joined_) {
240  leave();
241  }
242 
243  if(has_joined_global_) {
244  leave_global();
245  }
246 }
247 
249 {
250  // this assert will fire if someone will inadvertently try to join
251  // an event context but might end up in the global context instead.
252  assert(&event_contexts.back() != &event_contexts.front());
253 
254  join(event_contexts.back());
255 }
256 
258 {
259  if(has_joined_global_) {
260  leave_global();
261  }
262 
263  if(has_joined_) {
264  leave(); // should not be in multiple event contexts
265  }
266 
267  // join self
268  c.add_handler(this);
269  has_joined_ = true;
270 
271  // instruct members to join
272  for(auto member : handler_members()) {
273  member->join(c);
274  }
275 }
276 
278 {
279  if(has_joined_) {
280  leave(); // should not be in multiple event contexts
281  }
282 
283  for(auto& context : boost::adaptors::reverse(event_contexts)) {
284  handler_list& handlers = context.handlers;
285  if(std::find(handlers.begin(), handlers.end(), parent) != handlers.end()) {
286  join(context);
287  return;
288  }
289  }
290 
291  join(event_contexts.back());
292 }
293 
295 {
297 
298  if(members.empty()) {
299  assert(event_contexts.empty() == false);
300  }
301 
302  for(auto member : members) {
303  member->leave();
304  }
305 
306  for(auto& context : boost::adaptors::reverse(event_contexts)) {
307  if(context.remove_handler(this)) {
308  break;
309  }
310  }
311 
312  has_joined_ = false;
313 }
314 
316 {
317  if(has_joined_) {
318  leave();
319  }
320 
321  if(has_joined_global_) {
322  leave_global(); // Should not be in multiple event contexts
323  }
324 
325  // Join self
326  event_contexts.front().add_handler(this);
327  has_joined_global_ = true;
328 
329  // Instruct members to join
330  for(auto member : handler_members()) {
331  member->join_global();
332  }
333 }
334 
336 {
337  for(auto member : handler_members()) {
338  member->leave_global();
339  }
340 
341  event_contexts.front().remove_handler(this);
342 
343  has_joined_global_ = false;
344 }
345 
346 void focus_handler(const sdl_handler* ptr)
347 {
348  if(event_contexts.empty() == false) {
349  event_contexts.back().set_focus(ptr);
350  }
351 }
352 
353 bool has_focus(const sdl_handler* hand, const SDL_Event* event)
354 {
355  if(event_contexts.empty()) {
356  return true;
357  }
358 
359  if(hand->requires_event_focus(event) == false) {
360  return true;
361  }
362 
363  const handler_list::iterator foc = event_contexts.back().focused_handler;
364  auto& handlers = event_contexts.back().handlers;
365 
366  // If no-one has focus at the moment, this handler obviously wants
367  // focus, so give it to it.
368  if(foc == handlers.end()) {
369  focus_handler(hand);
370  return true;
371  }
372 
373  sdl_handler* const foc_hand = *foc;
374  if(foc_hand == hand) {
375  return true;
376  } else if(!foc_hand->requires_event_focus(event)) {
377  // If the currently focused handler doesn't need focus for this event
378  // allow the most recent interested handler to take care of it
379  for(auto i = handlers.rbegin(); i != handlers.rend(); ++i) {
380  sdl_handler* const thief_hand = *i;
381 
382  if(thief_hand != foc_hand && thief_hand->requires_event_focus(event)) {
383  // Steal focus
384  focus_handler(thief_hand);
385 
386  // Position the previously focused handler to allow stealing back
387  handlers.splice(handlers.end(), handlers, foc);
388 
389  return thief_hand == hand;
390  }
391  }
392  }
393 
394  return false;
395 }
396 
397 const uint32_t resize_timeout = 100;
400 
401 static bool remove_on_resize(const SDL_Event& a)
402 {
403  if(a.type == DRAW_EVENT || a.type == DRAW_ALL_EVENT) {
404  return true;
405  }
406 
407  if(a.type == SHOW_HELPTIP_EVENT) {
408  return true;
409  }
410 
411  if((a.type == SDL_WINDOWEVENT) && (
412  a.window.event == SDL_WINDOWEVENT_RESIZED ||
413  a.window.event == SDL_WINDOWEVENT_SIZE_CHANGED ||
414  a.window.event == SDL_WINDOWEVENT_EXPOSED)
415  ) {
416  return true;
417  }
418 
419  return false;
420 }
421 
422 // TODO: I'm uncertain if this is always safe to call at static init; maybe set in main() instead?
423 static const std::thread::id main_thread = std::this_thread::get_id();
424 
425 void pump()
426 {
427  if(std::this_thread::get_id() != main_thread) {
428  // Can only call this on the main thread!
429  return;
430  }
431 
432  peek_for_resize();
433  pump_info info;
434 
435  // Used to keep track of double click events
436  static int last_mouse_down = -1;
437  static int last_click_x = -1, last_click_y = -1;
438 
439  SDL_Event temp_event;
440  int poll_count = 0;
441  int begin_ignoring = 0;
442 
443  std::vector<SDL_Event> events;
444  while(SDL_PollEvent(&temp_event)) {
445  if(temp_event.type == INVOKE_FUNCTION_EVENT) {
446  static_cast<invoked_function_data*>(temp_event.user.data1)->call();
447  continue;
448  }
449 
450  ++poll_count;
451  peek_for_resize();
452 
453  if(!begin_ignoring && temp_event.type == SDL_WINDOWEVENT && (
454  temp_event.window.event == SDL_WINDOWEVENT_ENTER ||
455  temp_event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
456  ) {
457  begin_ignoring = poll_count;
458  } else if(begin_ignoring > 0 && is_input(temp_event)) {
459  // ignore user input events that occurred after the window was activated
460  continue;
461  }
462 
463  events.push_back(temp_event);
464  }
465 
466  auto ev_it = events.begin();
467  for(int i = 1; i < begin_ignoring; ++i) {
468  if(is_input(*ev_it)) {
469  // ignore user input events that occurred before the window was activated
470  ev_it = events.erase(ev_it);
471  } else {
472  ++ev_it;
473  }
474  }
475 
476  bool resize_found = false;
477  for(const SDL_Event& event : boost::adaptors::reverse(events)) {
478  if(event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_RESIZED) {
479  resize_found = true;
480  last_resize_event = event;
481  last_resize_event_used = false;
482 
483  // Since we're working backwards, the first resize event found is the last in the list.
484  break;
485  }
486  }
487 
488  // remove all inputs, draw events and only keep the last of the resize events
489  // This will turn horrible after ~38 days when the uint32_t wraps.
490  if(resize_found || SDL_GetTicks() <= last_resize_event.window.timestamp + resize_timeout) {
491  events.erase(std::remove_if(events.begin(), events.end(), remove_on_resize), events.end());
492  } else if(SDL_GetTicks() > last_resize_event.window.timestamp + resize_timeout && !last_resize_event_used) {
493  events.insert(events.begin(), last_resize_event);
494  last_resize_event_used = true;
495  }
496 
497  // Move all draw events to the end of the queue
498  auto first_draw_event = std::stable_partition(events.begin(), events.end(),
499  [](const SDL_Event& e) { return e.type != DRAW_EVENT; }
500  );
501 
502  if(first_draw_event != events.end()) {
503  // Remove all draw events except one
504  events.erase(first_draw_event + 1, events.end());
505  }
506 
507  for(SDL_Event& event : events) {
508  for(context& c : event_contexts) {
509  c.add_staging_handlers();
510  }
511 
512 #ifdef MOUSE_TOUCH_EMULATION
513  switch (event.type) {
514  // TODO: Implement SDL_MULTIGESTURE. Some day.
515  case SDL_MOUSEMOTION:
516  if(event.motion.which != SDL_TOUCH_MOUSEID && event.motion.state == 0) {
517  return;
518  }
519 
520  if(event.motion.state & SDL_BUTTON(SDL_BUTTON_RIGHT))
521  {
522  SDL_Rect r = CVideo::get_singleton().screen_area();
523 
524  // TODO: Check if SDL_FINGERMOTION is actually signaled for COMPLETE motions (I doubt, but tbs)
525  SDL_Event touch_event;
526  touch_event.type = SDL_FINGERMOTION;
527  touch_event.tfinger.type = SDL_FINGERMOTION;
528  touch_event.tfinger.timestamp = event.motion.timestamp;
529  touch_event.tfinger.touchId = 1;
530  touch_event.tfinger.fingerId = 1;
531  touch_event.tfinger.dx = static_cast<float>(event.motion.xrel) / r.w;
532  touch_event.tfinger.dy = static_cast<float>(event.motion.yrel) / r.h;
533  touch_event.tfinger.x = static_cast<float>(event.motion.x) / r.w;
534  touch_event.tfinger.y = static_cast<float>(event.motion.y) / r.h;
535  touch_event.tfinger.pressure = 1;
536  ::SDL_PushEvent(&touch_event);
537 
538  event.motion.state = SDL_BUTTON(SDL_BUTTON_LEFT);
539  event.motion.which = SDL_TOUCH_MOUSEID;
540  }
541  break;
542  case SDL_MOUSEBUTTONDOWN:
543  case SDL_MOUSEBUTTONUP:
544  if(event.button.button == SDL_BUTTON_RIGHT)
545  {
546  event.button.button = SDL_BUTTON_LEFT;
547  event.button.which = SDL_TOUCH_MOUSEID;
548 
549  SDL_Rect r = CVideo::get_singleton().screen_area();
550  SDL_Event touch_event;
551  touch_event.type = (event.type == SDL_MOUSEBUTTONDOWN) ? SDL_FINGERDOWN : SDL_FINGERUP;
552  touch_event.tfinger.type = touch_event.type;
553  touch_event.tfinger.timestamp = event.button.timestamp;
554  touch_event.tfinger.touchId = 1;
555  touch_event.tfinger.fingerId = 1;
556  touch_event.tfinger.dx = 0;
557  touch_event.tfinger.dy = 0;
558  touch_event.tfinger.x = static_cast<float>(event.button.x) / r.w;
559  touch_event.tfinger.y = static_cast<float>(event.button.y) / r.h;
560  touch_event.tfinger.pressure = 1;
561  ::SDL_PushEvent(&touch_event);
562 
563  }
564  break;
565  default:
566  break;
567  }
568 #endif
569 
570  switch(event.type) {
571  case SDL_WINDOWEVENT:
572  switch(event.window.event) {
573  case SDL_WINDOWEVENT_ENTER:
574  case SDL_WINDOWEVENT_FOCUS_GAINED:
576  break;
577 
578  case SDL_WINDOWEVENT_LEAVE:
579  case SDL_WINDOWEVENT_FOCUS_LOST:
581  break;
582 
583  case SDL_WINDOWEVENT_RESIZED:
584  info.resize_dimensions.first = event.window.data1;
585  info.resize_dimensions.second = event.window.data2;
586  break;
587  }
588 
589  // make sure this runs in it's own scope.
590  {
591  flip_locker flip_lock(CVideo::get_singleton());
592  for(auto& context : event_contexts) {
593  for(auto handler : context.handlers) {
594  handler->handle_window_event(event);
595  }
596  }
597 
598  for(auto global_handler : event_contexts.front().handlers) {
599  global_handler->handle_window_event(event);
600  }
601  }
602 
603  // This event was just distributed, don't re-distribute.
604  continue;
605 
606  case SDL_MOUSEMOTION: {
607  // Always make sure a cursor is displayed if the mouse moves or if the user clicks
608  cursor::set_focus(true);
609  raise_help_string_event(event.motion.x, event.motion.y);
610  break;
611  }
612 
613  case SDL_MOUSEBUTTONDOWN: {
614  // Always make sure a cursor is displayed if the mouse moves or if the user clicks
615  cursor::set_focus(true);
616  if(event.button.button == SDL_BUTTON_LEFT || event.button.which == SDL_TOUCH_MOUSEID) {
617  static const int DoubleClickTime = 500;
618 #ifdef __IPHONEOS__
619  static const int DoubleClickMaxMove = 15;
620 #else
621  static const int DoubleClickMaxMove = 3;
622 #endif
623 
624  if(last_mouse_down >= 0 && info.ticks() - last_mouse_down < DoubleClickTime
625  && std::abs(event.button.x - last_click_x) < DoubleClickMaxMove
626  && std::abs(event.button.y - last_click_y) < DoubleClickMaxMove
627  ) {
628  sdl::UserEvent user_event(DOUBLE_CLICK_EVENT, event.button.which, event.button.x, event.button.y);
629  ::SDL_PushEvent(reinterpret_cast<SDL_Event*>(&user_event));
630  }
631 
632  last_mouse_down = info.ticks();
633  last_click_x = event.button.x;
634  last_click_y = event.button.y;
635  }
636  break;
637  }
638 
639  case DRAW_ALL_EVENT: {
640  flip_locker flip_lock(CVideo::get_singleton());
641 
642  /* Iterate backwards as the most recent things will be at the top */
643  // FIXME? ^ that isn't happening here.
644  for(auto& context : event_contexts) {
645  for(auto handler : context.handlers) {
646  handler->handle_event(event);
647  }
648  }
649 
650  continue; // do not do further handling here
651  }
652 
653 #ifndef __APPLE__
654  case SDL_KEYDOWN: {
655  if(event.key.keysym.sym == SDLK_F4 &&
656  (event.key.keysym.mod == KMOD_RALT || event.key.keysym.mod == KMOD_LALT)
657  ) {
659  continue; // this event is already handled
660  }
661  break;
662  }
663 #endif
664 
665 #if defined(_X11) && !defined(__APPLE__)
666  case SDL_SYSWMEVENT: {
667  // clipboard support for X11
669  break;
670  }
671 #endif
672 
673 #if defined _WIN32
674  case SDL_SYSWMEVENT: {
676  break;
677  }
678 #endif
679 
680  case SDL_QUIT: {
682  continue; // this event is already handled.
683  }
684  }
685 
686  for(auto global_handler : event_contexts.front().handlers) {
687  global_handler->handle_event(event);
688  }
689 
690  if(event_contexts.empty() == false) {
691  for(auto handler : event_contexts.back().handlers) {
692  handler->handle_event(event);
693  }
694  }
695  }
696 
697  // Inform the pump monitors that an events::pump() has occurred
698  for(auto monitor : pump_monitors) {
699  monitor->process(info);
700  }
701 }
702 
704 {
705  if(event_contexts.empty() == false) {
706  event_contexts.back().add_staging_handlers();
707 
708  for(auto handler : event_contexts.back().handlers) {
709  handler->process_event();
710  }
711  }
712 }
713 
715 {
716  SDL_Event event;
717  event.window.type = SDL_WINDOWEVENT;
718  event.window.event = SDL_WINDOWEVENT_RESIZED;
719  event.window.windowID = 0; // We don't check this anyway... I think...
720  event.window.data1 = CVideo::get_singleton().get_width();
721  event.window.data2 = CVideo::get_singleton().get_height();
722 
723  SDL_PushEvent(&event);
724 }
725 
727 {
728  if(event_contexts.empty() == false) {
729  event_contexts.back().add_staging_handlers();
730 
731  // Events may cause more event handlers to be added and/or removed,
732  // so we must use indexes instead of iterators here.
733  for(auto handler : event_contexts.back().handlers) {
734  handler->draw();
735  }
736  }
737 }
738 
740 {
741  for(auto& context : event_contexts) {
742  for(auto handler : context.handlers) {
743  handler->draw();
744  }
745  }
746 }
747 
749 {
750  if(event_contexts.empty() == false) {
751  for(auto handler : event_contexts.back().handlers) {
752  handler->volatile_draw();
753  }
754  }
755 }
756 
758 {
759  for(auto& context : event_contexts) {
760  for(auto handler : context.handlers) {
761  handler->volatile_draw();
762  }
763  }
764 }
765 
767 {
768  if(event_contexts.empty() == false) {
769  for(auto handler : event_contexts.back().handlers) {
770  handler->volatile_undraw();
771  }
772  }
773 }
774 
775 void raise_help_string_event(int mousex, int mousey)
776 {
777  if(event_contexts.empty() == false) {
778  for(auto handler : event_contexts.back().handlers) {
779  handler->process_help_string(mousex, mousey);
780  handler->process_tooltip_string(mousex, mousey);
781  }
782  }
783 }
784 
785 int pump_info::ticks(unsigned* refresh_counter, unsigned refresh_rate)
786 {
787  if(!ticks_ && !(refresh_counter && ++*refresh_counter % refresh_rate)) {
788  ticks_ = ::SDL_GetTicks();
789  }
790 
791  return ticks_;
792 }
793 
794 /* The constants for the minimum and maximum are picked from the headers. */
795 #define INPUT_MIN 0x300
796 #define INPUT_MAX 0x8FF
797 
798 bool is_input(const SDL_Event& event)
799 {
800  return event.type >= INPUT_MIN && event.type <= INPUT_MAX;
801 }
802 
804 {
805  SDL_FlushEvents(INPUT_MIN, INPUT_MAX);
806 }
807 
809 {
810  SDL_Event events[100];
811  int num = SDL_PeepEvents(events, 100, SDL_PEEKEVENT, SDL_WINDOWEVENT, SDL_WINDOWEVENT);
812  for(int i = 0; i < num; ++i) {
813  if(events[i].type == SDL_WINDOWEVENT && events[i].window.event == SDL_WINDOWEVENT_RESIZED) {
815  }
816  }
817 }
818 
819 void call_in_main_thread(const std::function<void(void)>& f)
820 {
821  if(std::this_thread::get_id() == main_thread) {
822  // nothing special to do if called from the main thread.
823  f();
824  return;
825  }
826 
827  invoked_function_data fdata{f};
828 
829  SDL_Event sdl_event;
830  sdl::UserEvent sdl_userevent(INVOKE_FUNCTION_EVENT, &fdata);
831 
832  sdl_event.type = INVOKE_FUNCTION_EVENT;
833  sdl_event.user = sdl_userevent;
834 
835  SDL_PushEvent(&sdl_event);
836 
837  while(!fdata.finished) {
838  SDL_Delay(10);
839  }
840 
841  if(fdata.thrown_exception) {
842  std::rethrow_exception(fdata.thrown_exception);
843  }
844 }
845 
846 } // end events namespace
void raise_resize_event()
Definition: events.cpp:714
void raise_volatile_undraw_event()
Definition: events.cpp:766
void remove()
Removes a tip.
Definition: tooltip.cpp:189
void discard_input()
Discards all input events.
Definition: events.cpp:803
std::vector< events::sdl_handler * > sdl_handler_vector
Definition: events.hpp:176
bool last_resize_event_used
Definition: events.cpp:399
#define INVOKE_FUNCTION_EVENT
Definition: events.hpp:30
static const std::thread::id main_thread
Definition: events.cpp:423
logger & info()
Definition: log.cpp:90
#define a
int ticks(unsigned *refresh_counter=nullptr, unsigned refresh_rate=1)
Definition: events.cpp:785
void add_handler(sdl_handler *ptr)
Definition: events.cpp:80
#define DRAW_EVENT
Definition: events.hpp:26
virtual void leave_global()
Definition: events.cpp:335
Type that can be thrown as an exception to quit to desktop.
Definition: video.hpp:228
static CVideo & get_singleton()
Definition: video.hpp:43
#define h
bool remove_handler(sdl_handler *ptr)
Definition: events.cpp:89
-file util.hpp
virtual void join_same(sdl_handler *parent)
Definition: events.cpp:277
void call_in_main_thread(const std::function< void(void)> &f)
Definition: events.cpp:819
void raise_draw_all_event()
Definition: events.cpp:739
static bool remove_on_resize(const SDL_Event &a)
Definition: events.cpp:401
void focus_handler(const sdl_handler *ptr)
Definition: events.cpp:346
void set_focus(bool focus)
Definition: cursor.cpp:218
static events::event_context * event_context
Definition: handler.cpp:63
void raise_volatile_draw_all_event()
Definition: events.cpp:757
virtual bool requires_event_focus(const SDL_Event *=nullptr) const
Definition: events.hpp:83
#define INPUT_MAX
Definition: events.cpp:796
virtual void join()
Definition: events.cpp:248
std::list< sdl_handler * > handler_list
Definition: events.hpp:35
int get_width(bool as_pixels=true) const
Returns the window renderer width in pixels or screen coordinates.
Definition: video.cpp:320
void peek_for_resize()
Definition: events.cpp:808
const uint32_t resize_timeout
Definition: events.cpp:397
void raise_draw_event()
Definition: events.cpp:726
void pump()
Definition: events.cpp:425
#define DRAW_ALL_EVENT
Definition: events.hpp:29
virtual ~sdl_handler()
Definition: events.cpp:237
#define DOUBLE_CLICK_EVENT
Definition: events.hpp:23
void raise_process_event()
Definition: events.cpp:703
static void quit_to_desktop()
std::size_t i
Definition: function.cpp:933
#define SHOW_HELPTIP_EVENT
Definition: events.hpp:28
bool is_input(const SDL_Event &event)
Is the event an input event?
Definition: events.cpp:798
void raise_help_string_event(int mousex, int mousey)
Definition: events.cpp:775
void handle_system_event(const SDL_Event &)
Definition: clipboard.cpp:52
void raise_volatile_draw_event()
Definition: events.cpp:748
virtual std::vector< sdl_handler * > handler_members()
Definition: events.hpp:101
int get_height(bool as_pixels=true) const
Returns the window renderer height in pixels or in screen coordinates.
Definition: video.cpp:325
std::deque< context > event_contexts
Definition: events.cpp:201
Handling of system events.
Definition: manager.hpp:41
std::vector< pump_monitor * > pump_monitors
Definition: events.cpp:203
#define f
bool find(E event, F functor)
Tests whether an event handler is available.
bool has_focus(const sdl_handler *hand, const SDL_Event *event)
Definition: events.cpp:353
Standard logging facilities (interface).
std::pair< int, int > resize_dimensions
Definition: events.hpp:140
#define e
SDL_Event last_resize_event
Definition: events.cpp:398
void update_framebuffer()
Updates and ensures the framebuffer surface is valid.
Definition: video.cpp:200
static void reverse(lua_State *L, StkId from, StkId to)
Definition: lapi.cpp:193
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 leave()
Definition: events.cpp:294
handler_list handlers
Definition: events.hpp:59
mock_char c
SDL_Rect screen_area(bool as_pixels=true) const
Returns the current window renderer area, either in pixels or screen coordinates. ...
Definition: video.cpp:299
virtual void join_global()
Definition: events.cpp:315
std::string::const_iterator iterator
Definition: tokenizer.hpp:24
HOTKEY_COMMAND get_id(const std::string &command)
returns get_hotkey_command(command).id
#define INPUT_MIN
Definition: events.cpp:795