00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #define GETTEXT_DOMAIN "wesnoth-lib"
00017
00018 #include "gui/auxiliary/event/handler.hpp"
00019
00020 #include "clipboard.hpp"
00021 #include "foreach.hpp"
00022 #include "gui/auxiliary/event/dispatcher.hpp"
00023 #include "gui/auxiliary/timer.hpp"
00024 #include "gui/auxiliary/log.hpp"
00025 #include "gui/widgets/helper.hpp"
00026 #include "gui/widgets/widget.hpp"
00027 #include "gui/widgets/window.hpp"
00028 #include "hotkeys.hpp"
00029 #include "video.hpp"
00030
00031 #include <cassert>
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054 namespace gui2 {
00055
00056 namespace event {
00057
00058
00059 class thandler;
00060 static thandler* handler = NULL;
00061 static events::event_context* event_context = NULL;
00062
00063 #ifdef MAIN_EVENT_HANDLER
00064 static unsigned draw_interval = 0;
00065 static unsigned event_poll_interval = 0;
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076 static Uint32 timer_sdl_draw_event(Uint32, void*)
00077 {
00078
00079
00080 SDL_Event event;
00081 SDL_UserEvent data;
00082
00083 data.type = DRAW_EVENT;
00084 data.code = 0;
00085 data.data1 = NULL;
00086 data.data2 = NULL;
00087
00088 event.type = DRAW_EVENT;
00089 event.user = data;
00090
00091 SDL_PushEvent(&event);
00092 return draw_interval;
00093 }
00094
00095
00096
00097
00098
00099
00100
00101
00102 static Uint32 timer_sdl_poll_events(Uint32, void*)
00103 {
00104 try {
00105 events::pump();
00106 } catch(CVideo::quit&) {
00107 return 0;
00108 }
00109 return event_poll_interval;
00110 }
00111 #endif
00112
00113
00114
00115
00116
00117
00118
00119
00120 class thandler
00121 : public events::handler
00122 {
00123 friend bool gui2::is_in_dialog();
00124 public:
00125 thandler();
00126
00127 ~thandler();
00128
00129
00130 void handle_event(const SDL_Event& event);
00131
00132
00133
00134
00135
00136
00137 void connect(tdispatcher* dispatcher);
00138
00139
00140
00141
00142
00143
00144 void disconnect(tdispatcher* dispatcher);
00145
00146
00147 tdispatcher* mouse_focus;
00148
00149 private:
00150
00151
00152
00153
00154
00155
00156
00157 void activate();
00158
00159
00160
00161
00162 void draw(const bool force);
00163
00164
00165
00166
00167
00168
00169 void video_resize(const tpoint& new_size);
00170
00171
00172
00173
00174
00175
00176
00177 void mouse(const tevent event, const tpoint& position);
00178
00179
00180
00181
00182
00183
00184
00185
00186 void mouse_button_up(const tpoint& position, const Uint8 button);
00187
00188
00189
00190
00191
00192
00193
00194
00195 void mouse_button_down(const tpoint& position, const Uint8 button);
00196
00197
00198
00199
00200
00201
00202
00203 tdispatcher* keyboard_dispatcher();
00204
00205
00206
00207
00208
00209
00210 void hat_motion(const SDL_JoyHatEvent& event);
00211
00212
00213
00214
00215
00216
00217
00218 void button_down(const SDL_JoyButtonEvent& event);
00219
00220
00221
00222
00223
00224
00225
00226 void key_down(const SDL_KeyboardEvent& event);
00227
00228
00229
00230
00231
00232
00233
00234
00235 bool hotkey_pressed(const hotkey::hotkey_item& key);
00236
00237
00238
00239
00240
00241
00242
00243
00244 void key_down(const SDLKey key
00245 , const SDLMod modifier
00246 , const Uint16 unicode);
00247
00248
00249
00250
00251
00252
00253
00254
00255 void keyboard(const tevent event);
00256
00257
00258
00259
00260
00261
00262
00263
00264 std::vector<tdispatcher*> dispatchers_;
00265
00266
00267
00268
00269
00270
00271 tdispatcher* keyboard_focus_;
00272 friend void capture_keyboard(tdispatcher*);
00273 };
00274
00275 thandler::thandler()
00276 : events::handler(false)
00277 , mouse_focus(NULL)
00278 , dispatchers_()
00279 , keyboard_focus_(NULL)
00280 {
00281 if(SDL_WasInit(SDL_INIT_TIMER) == 0) {
00282 if(SDL_InitSubSystem(SDL_INIT_TIMER) == -1) {
00283 assert(false);
00284 }
00285 }
00286
00287
00288 #ifdef ENABLE
00289 join();
00290 #endif
00291 }
00292
00293 thandler::~thandler()
00294 {
00295 #ifdef ENABLE
00296 leave();
00297 #endif
00298 }
00299
00300 void thandler::handle_event(const SDL_Event& event)
00301 {
00302
00303 if(dispatchers_.empty()) {
00304 return;
00305 }
00306
00307 switch(event.type) {
00308 case SDL_MOUSEMOTION:
00309 mouse(SDL_MOUSE_MOTION, tpoint(event.motion.x, event.motion.y));
00310 break;
00311
00312 case SDL_MOUSEBUTTONDOWN:
00313 mouse_button_down(tpoint(event.button.x, event.button.y)
00314 , event.button.button);
00315 break;
00316
00317 case SDL_MOUSEBUTTONUP:
00318 mouse_button_up(tpoint(event.button.x, event.button.y)
00319 , event.button.button);
00320 break;
00321
00322 case SHOW_HELPTIP_EVENT:
00323 mouse(SHOW_HELPTIP, get_mouse_position());
00324 break;
00325
00326 case HOVER_REMOVE_POPUP_EVENT:
00327
00328 break;
00329
00330 case DRAW_EVENT:
00331 draw(false);
00332 break;
00333
00334 case TIMER_EVENT:
00335 execute_timer(reinterpret_cast<long>(event.user.data1));
00336 break;
00337
00338 case CLOSE_WINDOW_EVENT:
00339 {
00340
00341 DBG_GUI_E << "Firing " << CLOSE_WINDOW << ".\n";
00342
00343 twindow* window = twindow::window_instance(event.user.code);
00344 if(window) {
00345 window->set_retval(twindow::AUTO_CLOSE);
00346 }
00347 }
00348 break;
00349
00350 case SDL_JOYBUTTONDOWN:
00351 button_down(event.jbutton);
00352 break;
00353
00354 case SDL_JOYBUTTONUP:
00355 break;
00356
00357 case SDL_JOYAXISMOTION:
00358 break;
00359
00360 case SDL_JOYHATMOTION:
00361 hat_motion(event.jhat);
00362 break;
00363
00364 case SDL_KEYDOWN:
00365 key_down(event.key);
00366 break;
00367
00368 case SDL_VIDEOEXPOSE:
00369 draw(true);
00370 break;
00371
00372 case SDL_VIDEORESIZE:
00373 video_resize(tpoint(event.resize.w, event.resize.h));
00374 break;
00375
00376 #if defined(_X11) && !defined(__APPLE__)
00377 case SDL_SYSWMEVENT: {
00378 DBG_GUI_E << "Event: System event.\n";
00379
00380 handle_system_event(event);
00381 break;
00382 }
00383 #endif
00384
00385 case SDL_ACTIVEEVENT:
00386 activate();
00387 break;
00388
00389
00390 case SDL_KEYUP:
00391 case DOUBLE_CLICK_EVENT:
00392 break;
00393
00394 default:
00395 WRN_GUI_E << "Unhandled event "
00396 << static_cast<Uint32>(event.type) << ".\n";
00397 break;
00398 }
00399 }
00400
00401 void thandler::connect(tdispatcher* dispatcher)
00402 {
00403 assert(std::find(dispatchers_.begin(), dispatchers_.end(), dispatcher)
00404 == dispatchers_.end());
00405
00406 if(dispatchers_.empty()) {
00407 event_context = new events::event_context();
00408 join();
00409 }
00410
00411 dispatchers_.push_back(dispatcher);
00412 }
00413
00414 void thandler::disconnect(tdispatcher* dispatcher)
00415 {
00416
00417 std::vector<tdispatcher*>::iterator itor =
00418 std::find(dispatchers_.begin(), dispatchers_.end(), dispatcher);
00419 assert(itor != dispatchers_.end());
00420
00421
00422 dispatchers_.erase(itor);
00423
00424 if(dispatcher == mouse_focus) {
00425 mouse_focus = NULL;
00426 }
00427 if(dispatcher == keyboard_focus_) {
00428 keyboard_focus_ = NULL;
00429 }
00430
00431
00432 foreach(tdispatcher* dispatcher, dispatchers_) {
00433 dynamic_cast<twidget&>(*dispatcher).set_dirty();
00434 }
00435
00436 activate();
00437
00438
00439 assert(std::find(dispatchers_.begin(), dispatchers_.end(), dispatcher)
00440 == dispatchers_.end());
00441
00442 if(dispatchers_.empty()) {
00443 leave();
00444 delete event_context;
00445 event_context = NULL;
00446 }
00447 }
00448
00449 void thandler::activate()
00450 {
00451 foreach(tdispatcher* dispatcher, dispatchers_) {
00452 dispatcher->fire(SDL_ACTIVATE
00453 , dynamic_cast<twidget&>(*dispatcher)
00454 , NULL);
00455 }
00456 }
00457
00458 void thandler::draw(const bool force)
00459 {
00460
00461
00462
00463
00464
00465
00466
00467
00468 bool first = !force;
00469
00470
00471
00472
00473
00474
00475 foreach(tdispatcher* dispatcher, dispatchers_) {
00476 if(!first) {
00477
00478
00479
00480
00481
00482
00483 dynamic_cast<twidget&>(*dispatcher).set_dirty();
00484 } else {
00485 first = false;
00486 }
00487
00488 dispatcher->fire(DRAW, dynamic_cast<twidget&>(*dispatcher));
00489 }
00490
00491 if(!dispatchers_.empty()) {
00492 CVideo& video = dynamic_cast<twindow&>(*dispatchers_.back()).video();
00493
00494 surface frame_buffer = video.getSurface();
00495
00496 cursor::draw(frame_buffer);
00497 video.flip();
00498 cursor::undraw(frame_buffer);
00499 }
00500 }
00501
00502 void thandler::video_resize(const tpoint& new_size)
00503 {
00504 DBG_GUI_E << "Firing: " << SDL_VIDEO_RESIZE << ".\n";
00505
00506 foreach(tdispatcher* dispatcher, dispatchers_) {
00507 dispatcher->fire(SDL_VIDEO_RESIZE
00508 , dynamic_cast<twidget&>(*dispatcher)
00509 , new_size);
00510 }
00511 }
00512
00513 void thandler::mouse(const tevent event, const tpoint& position)
00514 {
00515 DBG_GUI_E << "Firing: " << event << ".\n";
00516
00517 if(mouse_focus) {
00518 mouse_focus->fire(event
00519 , dynamic_cast<twidget&>(*mouse_focus)
00520 , position);
00521 } else {
00522
00523 for(std::vector<tdispatcher*>::reverse_iterator ritor =
00524 dispatchers_.rbegin(); ritor != dispatchers_.rend(); ++ritor) {
00525
00526 if((**ritor).get_mouse_behaviour() == tdispatcher::all) {
00527 (**ritor).fire(event
00528 , dynamic_cast<twidget&>(**ritor)
00529 , position);
00530 break;
00531 }
00532 if((**ritor).get_mouse_behaviour() == tdispatcher::none) {
00533 continue;
00534 }
00535 if((**ritor).is_at(position)) {
00536 (**ritor).fire(event
00537 , dynamic_cast<twidget&>(**ritor)
00538 , position);
00539 break;
00540 }
00541 }
00542 }
00543 }
00544
00545 void thandler::mouse_button_up(const tpoint& position, const Uint8 button)
00546 {
00547 switch(button) {
00548 case SDL_BUTTON_LEFT :
00549 mouse(SDL_LEFT_BUTTON_UP, position);
00550 break;
00551 case SDL_BUTTON_MIDDLE :
00552 mouse(SDL_MIDDLE_BUTTON_UP, position);
00553 break;
00554 case SDL_BUTTON_RIGHT :
00555 mouse(SDL_RIGHT_BUTTON_UP, position);
00556 break;
00557
00558 case SDL_BUTTON_WHEELLEFT :
00559 mouse(SDL_WHEEL_LEFT, get_mouse_position());
00560 break;
00561 case SDL_BUTTON_WHEELRIGHT :
00562 mouse(SDL_WHEEL_RIGHT, get_mouse_position());
00563 break;
00564 case SDL_BUTTON_WHEELUP :
00565 mouse(SDL_WHEEL_UP, get_mouse_position());
00566 break;
00567 case SDL_BUTTON_WHEELDOWN :
00568 mouse(SDL_WHEEL_DOWN, get_mouse_position());
00569 break;
00570
00571 default:
00572 WRN_GUI_E << "Unhandled 'mouse button up' event for button "
00573 << static_cast<Uint32>(button) << ".\n";
00574 break;
00575 }
00576 }
00577
00578 void thandler::mouse_button_down(const tpoint& position, const Uint8 button)
00579 {
00580
00581
00582
00583 if(button == SDL_BUTTON_WHEELUP
00584 || button == SDL_BUTTON_WHEELDOWN
00585 || button == SDL_BUTTON_WHEELLEFT
00586 || button == SDL_BUTTON_WHEELRIGHT) {
00587
00588 return;
00589 }
00590
00591 switch(button) {
00592 case SDL_BUTTON_LEFT :
00593 mouse(SDL_LEFT_BUTTON_DOWN, position);
00594 break;
00595 case SDL_BUTTON_MIDDLE :
00596 mouse(SDL_MIDDLE_BUTTON_DOWN, position);
00597 break;
00598 case SDL_BUTTON_RIGHT :
00599 mouse(SDL_RIGHT_BUTTON_DOWN, position);
00600 break;
00601 default:
00602 WRN_GUI_E << "Unhandled 'mouse button down' event for button "
00603 << static_cast<Uint32>(button) << ".\n";
00604 break;
00605 }
00606 }
00607
00608 tdispatcher* thandler::keyboard_dispatcher()
00609 {
00610 if(keyboard_focus_) {
00611 return keyboard_focus_;
00612 }
00613
00614 for(std::vector<tdispatcher*>::reverse_iterator ritor =
00615 dispatchers_.rbegin(); ritor != dispatchers_.rend(); ++ritor) {
00616
00617 if((**ritor).get_want_keyboard_input()) {
00618 return *ritor;
00619 }
00620 }
00621
00622 return NULL;
00623 }
00624
00625 void thandler::hat_motion(const SDL_JoyHatEvent& event)
00626 {
00627 const hotkey::hotkey_item& hk = hotkey::get_hotkey(event);
00628 bool done = false;
00629 if(!hk.null()) {
00630 done = hotkey_pressed(hk);
00631 }
00632 if(!done) {
00633
00634 }
00635 }
00636
00637 void thandler::button_down(const SDL_JoyButtonEvent& event)
00638 {
00639 const hotkey::hotkey_item& hk = hotkey::get_hotkey(event);
00640 bool done = false;
00641 if(!hk.null()) {
00642 done = hotkey_pressed(hk);
00643 }
00644 if(!done) {
00645
00646 }
00647 }
00648
00649 void thandler::key_down(const SDL_KeyboardEvent& event)
00650 {
00651 const hotkey::hotkey_item& hk = hotkey::get_hotkey(event);
00652 bool done = false;
00653 if(!hk.null()) {
00654 done = hotkey_pressed(hk);
00655 }
00656 if(!done) {
00657 key_down(event.keysym.sym, event.keysym.mod, event.keysym.unicode);
00658 }
00659 }
00660
00661 bool thandler::hotkey_pressed(const hotkey::hotkey_item& key)
00662 {
00663 tdispatcher* dispatcher = keyboard_dispatcher();
00664
00665 if(!dispatcher) {
00666 return false;
00667 }
00668
00669 return dispatcher->execute_hotkey(key.get_id());
00670 }
00671
00672 void thandler::key_down(const SDLKey key
00673 , const SDLMod modifier
00674 , const Uint16 unicode)
00675 {
00676 DBG_GUI_E << "Firing: " << SDL_KEY_DOWN << ".\n";
00677
00678 if(tdispatcher* dispatcher = keyboard_dispatcher()) {
00679 dispatcher->fire(SDL_KEY_DOWN
00680 , dynamic_cast<twidget&>(*dispatcher)
00681 , key
00682 , modifier
00683 , unicode);
00684 }
00685 }
00686
00687 void thandler::keyboard(const tevent event)
00688 {
00689 DBG_GUI_E << "Firing: " << event << ".\n";
00690
00691 if(tdispatcher* dispatcher = keyboard_dispatcher()) {
00692 dispatcher->fire(event, dynamic_cast<twidget&>(*dispatcher));
00693 }
00694 }
00695
00696
00697
00698 tmanager::tmanager()
00699 {
00700 handler = new thandler();
00701
00702 #ifdef MAIN_EVENT_HANDLER
00703 draw_interval = 30;
00704 SDL_AddTimer(draw_interval, timer_sdl_draw_event, NULL);
00705
00706 event_poll_interval = 10;
00707 SDL_AddTimer(event_poll_interval, timer_sdl_poll_events, NULL);
00708 #endif
00709 }
00710
00711 tmanager::~tmanager()
00712 {
00713 delete handler;
00714 handler = NULL;
00715
00716 #ifdef MAIN_EVENT_HANDLER
00717 draw_interval = 0;
00718 event_poll_interval = 0;
00719 #endif
00720 }
00721
00722
00723
00724 void connect_dispatcher(tdispatcher* dispatcher)
00725 {
00726 assert(handler);
00727 assert(dispatcher);
00728 handler->connect(dispatcher);
00729 }
00730
00731 void disconnect_dispatcher(tdispatcher* dispatcher)
00732 {
00733 assert(handler);
00734 assert(dispatcher);
00735 handler->disconnect(dispatcher);
00736 }
00737
00738 void init_mouse_location()
00739 {
00740 tpoint mouse = get_mouse_position();
00741
00742 SDL_Event event;
00743 event.type = SDL_MOUSEMOTION;
00744 event.motion.type = SDL_MOUSEMOTION;
00745 event.motion.x = mouse.x;
00746 event.motion.y = mouse.y;
00747
00748 SDL_PushEvent(&event);
00749 }
00750
00751 void capture_mouse(tdispatcher* dispatcher)
00752 {
00753 assert(handler);
00754 assert(dispatcher);
00755 handler->mouse_focus = dispatcher;
00756 }
00757
00758 void release_mouse(tdispatcher* dispatcher)
00759 {
00760 assert(handler);
00761 assert(dispatcher);
00762 if(handler->mouse_focus == dispatcher) {
00763 handler->mouse_focus = NULL;
00764 }
00765 }
00766
00767 void capture_keyboard(tdispatcher* dispatcher)
00768 {
00769 assert(handler);
00770 assert(dispatcher);
00771 assert(dispatcher->get_want_keyboard_input());
00772
00773 handler->keyboard_focus_ = dispatcher;
00774 }
00775
00776 std::ostream& operator<<(std::ostream& stream, const tevent event)
00777 {
00778 switch(event) {
00779 case DRAW : stream << "draw"; break;
00780 case CLOSE_WINDOW : stream << "close window"; break;
00781 case SDL_VIDEO_RESIZE : stream << "SDL video resize"; break;
00782 case SDL_MOUSE_MOTION : stream << "SDL mouse motion"; break;
00783 case MOUSE_ENTER : stream << "mouse enter"; break;
00784 case MOUSE_LEAVE : stream << "mouse leave"; break;
00785 case MOUSE_MOTION : stream << "mouse motion"; break;
00786 case SDL_LEFT_BUTTON_DOWN : stream << "SDL left button down"; break;
00787 case SDL_LEFT_BUTTON_UP : stream << "SDL left button up"; break;
00788 case LEFT_BUTTON_DOWN : stream << "left button down"; break;
00789 case LEFT_BUTTON_UP : stream << "left button up"; break;
00790 case LEFT_BUTTON_CLICK : stream << "left button click"; break;
00791 case LEFT_BUTTON_DOUBLE_CLICK
00792 : stream << "left button double click";
00793 break;
00794 case SDL_MIDDLE_BUTTON_DOWN : stream << "SDL middle button down"; break;
00795 case SDL_MIDDLE_BUTTON_UP : stream << "SDL middle button up"; break;
00796 case MIDDLE_BUTTON_DOWN : stream << "middle button down"; break;
00797 case MIDDLE_BUTTON_UP : stream << "middle button up"; break;
00798 case MIDDLE_BUTTON_CLICK : stream << "middle button click"; break;
00799 case MIDDLE_BUTTON_DOUBLE_CLICK
00800 : stream << "middle button double click";
00801 break;
00802 case SDL_RIGHT_BUTTON_DOWN : stream << "SDL right button down"; break;
00803 case SDL_RIGHT_BUTTON_UP : stream << "SDL right button up"; break;
00804 case RIGHT_BUTTON_DOWN : stream << "right button down"; break;
00805 case RIGHT_BUTTON_UP : stream << "right button up"; break;
00806 case RIGHT_BUTTON_CLICK : stream << "right button click"; break;
00807 case RIGHT_BUTTON_DOUBLE_CLICK
00808 : stream << "right button double click";
00809 break;
00810 case SDL_WHEEL_LEFT : stream << "SDL wheel left"; break;
00811 case SDL_WHEEL_RIGHT : stream << "SDL wheel right"; break;
00812 case SDL_WHEEL_UP : stream << "SDL wheel up"; break;
00813 case SDL_WHEEL_DOWN : stream << "SDL wheel down"; break;
00814 case SDL_KEY_DOWN : stream << "SDL key down"; break;
00815
00816 case NOTIFY_REMOVAL : stream << "notify removal"; break;
00817 case NOTIFY_MODIFIED : stream << "notify modified"; break;
00818 case RECEIVE_KEYBOARD_FOCUS : stream << "receive keyboard focus"; break;
00819 case LOSE_KEYBOARD_FOCUS : stream << "lose keyboard focus"; break;
00820 case SHOW_TOOLTIP : stream << "show tooltip"; break;
00821 case NOTIFY_REMOVE_TOOLTIP : stream << "notify remove tooltip"; break;
00822 case SDL_ACTIVATE : stream << "SDL activate"; break;
00823 case MESSAGE_SHOW_TOOLTIP : stream << "message show tooltip"; break;
00824 case SHOW_HELPTIP : stream << "show helptip"; break;
00825 case MESSAGE_SHOW_HELPTIP : stream << "message show helptip"; break;
00826 case REQUEST_PLACEMENT : stream << "request placement"; break;
00827 }
00828
00829 return stream;
00830 }
00831
00832 }
00833
00834 bool is_in_dialog()
00835 {
00836 return event::handler && !event::handler->dispatchers_.empty();
00837 }
00838
00839 }
00840