events.cpp

Go to the documentation of this file.
00001 /* $Id: events.cpp 23842 2008-02-16 08:47:16Z mordante $ */
00002 /*
00003    Copyright (C) 2003 - 2008 by David White <dave@whitevine.net>
00004    Part of the Battle for Wesnoth Project http://www.wesnoth.org/
00005 
00006    This program is free software; you can redistribute it and/or modify
00007    it under the terms of the GNU General Public License version 2
00008    or at your option any later version.
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY.
00011 
00012    See the COPYING file for more details.
00013 */
00014 
00015 #include "global.hpp"
00016 
00017 #include "clipboard.hpp"
00018 #include "cursor.hpp"
00019 #include "events.hpp"
00020 #include "log.hpp"
00021 #include "preferences_display.hpp"
00022 #include "sound.hpp"
00023 #include "video.hpp"
00024 
00025 #include "SDL.h"
00026 
00027 #include <algorithm>
00028 #include <cassert>
00029 #include <deque>
00030 #include <utility>
00031 #include <vector>
00032 
00033 #define ERR_GEN LOG_STREAM(err, general)
00034 #define INFO_GEN LOG_STREAM(info, general)
00035 
00036 unsigned input_blocker::instance_count = 0; //static initialization
00037 
00038 namespace events
00039 {
00040 
00041 void raise_help_string_event(int mousex, int mousey);
00042 
00043 namespace {
00044 
00045 struct context
00046 {
00047     context() : focused_handler(-1) {}
00048     void add_handler(handler* ptr);
00049     bool remove_handler(handler* ptr);
00050     int cycle_focus();
00051     void set_focus(const handler* ptr);
00052 
00053     std::vector<handler*> handlers;
00054     int focused_handler;
00055 
00056     void delete_handler_index(size_t handler);
00057 };
00058 
00059 void context::add_handler(handler* ptr)
00060 {
00061     handlers.push_back(ptr);
00062 }
00063 
00064 void context::delete_handler_index(size_t handler)
00065 {
00066     if(focused_handler == static_cast<int>(handler)) {
00067         focused_handler = -1;
00068     } else if(focused_handler > static_cast<int>(handler)) {
00069         --focused_handler;
00070     }
00071 
00072     handlers.erase(handlers.begin()+handler);
00073 }
00074 
00075 bool context::remove_handler(handler* ptr)
00076 {
00077     if(handlers.empty()) {
00078         return false;
00079     }
00080 
00081     static int depth = 0;
00082     ++depth;
00083 
00084     //the handler is most likely on the back of the events array,
00085     //so look there first, otherwise do a complete search.
00086     if(handlers.back() == ptr) {
00087         delete_handler_index(handlers.size()-1);
00088     } else {
00089         const std::vector<handler*>::iterator i = std::find(handlers.begin(),handlers.end(),ptr);
00090         if(i != handlers.end()) {
00091             delete_handler_index(i - handlers.begin());
00092         } else {
00093             return false;
00094         }
00095     }
00096 
00097     --depth;
00098 
00099     if(depth == 0) {
00100         cycle_focus();
00101     } else {
00102         focused_handler = -1;
00103     }
00104 
00105     return true;
00106 }
00107 
00108 int context::cycle_focus()
00109 {
00110     int index = focused_handler+1;
00111     for(size_t i = 0; i != handlers.size(); ++i) {
00112         if(size_t(index) == handlers.size()) {
00113             index = 0;
00114         }
00115 
00116         if(handlers[size_t(index)]->requires_event_focus()) {
00117             focused_handler = index;
00118             break;
00119         }
00120     }
00121 
00122     return focused_handler;
00123 }
00124 
00125 void context::set_focus(const handler* ptr)
00126 {
00127     const std::vector<handler*>::const_iterator i = std::find(handlers.begin(),handlers.end(),ptr);
00128     if(i != handlers.end() && (**i).requires_event_focus()) {
00129         focused_handler = int(i - handlers.begin());
00130     }
00131 }
00132 
00133 //this object stores all the event handlers. It is a stack of event 'contexts'.
00134 //a new event context is created when e.g. a modal dialog is opened, and then
00135 //closed when that dialog is closed. Each context contains a list of the handlers
00136 //in that context. The current context is the one on the top of the stack
00137 std::deque<context> event_contexts;
00138 
00139 std::vector<pump_monitor*> pump_monitors;
00140 
00141 } //end anon namespace
00142 
00143 pump_monitor::pump_monitor() {
00144     pump_monitors.push_back(this);
00145 }
00146 
00147 pump_monitor::~pump_monitor() {
00148     pump_monitors.erase(
00149         std::remove(pump_monitors.begin(), pump_monitors.end(), this),
00150         pump_monitors.end());
00151 }
00152 
00153 event_context::event_context()
00154 {
00155     event_contexts.push_back(context());
00156 }
00157 
00158 event_context::~event_context()
00159 {
00160     assert(event_contexts.empty() == false);
00161     event_contexts.pop_back();
00162 }
00163 
00164 handler::handler(const bool auto_join) : unicode_(SDL_EnableUNICODE(1)), has_joined_(false)
00165 {
00166     SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY,SDL_DEFAULT_REPEAT_INTERVAL);
00167     if(auto_join) {
00168         event_contexts.back().add_handler(this);
00169         has_joined_ = true;
00170     }
00171 }
00172 
00173 handler::~handler()
00174 {
00175     leave();
00176     SDL_EnableUNICODE(unicode_);
00177 }
00178 
00179 void handler::join()
00180 {
00181     if(has_joined_) {
00182         leave(); // should not be in multiple event contexts
00183     }
00184     //join self
00185     event_contexts.back().add_handler(this);
00186     has_joined_ = true;
00187 
00188     //instruct members to join
00189     handler_vector members = handler_members();
00190     if(!members.empty()) {
00191         for(handler_vector::iterator i = members.begin(); i != members.end(); i++) {
00192             (*i)->join();
00193         }
00194     }
00195 }
00196 
00197 void handler::leave()
00198 {
00199     handler_vector members = handler_members();
00200     if(!members.empty()) {
00201         for(handler_vector::iterator i = members.begin(); i != members.end(); i++) {
00202             (*i)->leave();
00203         }
00204     } else {
00205         assert(event_contexts.empty() == false);
00206     }
00207     for(std::deque<context>::reverse_iterator i = event_contexts.rbegin(); i != event_contexts.rend(); ++i) {
00208         if(i->remove_handler(this)) {
00209             break;
00210         }
00211     }
00212     has_joined_ = false;
00213 }
00214 
00215 void focus_handler(const handler* ptr)
00216 {
00217     if(event_contexts.empty() == false) {
00218         event_contexts.back().set_focus(ptr);
00219     }
00220 }
00221 
00222 bool has_focus(const handler* hand, const SDL_Event* event)
00223 {
00224     if(event_contexts.empty()) {
00225         return true;
00226     }
00227 
00228     if(hand->requires_event_focus(event) == false) {
00229         return true;
00230     }
00231 
00232     const int foc_i = event_contexts.back().focused_handler;
00233 
00234     //if no-one has focus at the moment, this handler obviously wants
00235     //focus, so give it to it.
00236     if(foc_i == -1) {
00237         focus_handler(hand);
00238         return true;
00239     }
00240 
00241     handler *const foc_hand = event_contexts.back().handlers[foc_i];
00242     if(foc_hand == hand){
00243         return true;
00244     } else if(!foc_hand->requires_event_focus(event)) {
00245         //if the currently focused handler doesn't need focus for this event
00246         //allow the most recent interested handler to take care of it
00247         int back_i = event_contexts.back().handlers.size() - 1;
00248         for(int i=back_i; i>=0; --i) {
00249             handler *const thief_hand = event_contexts.back().handlers[i];
00250             if(i != foc_i && thief_hand->requires_event_focus(event)) {
00251                 //steal focus
00252                 focus_handler(thief_hand);
00253                 if(foc_i < back_i) {
00254                     //position the previously focused handler to allow stealing back
00255                     event_contexts.back().delete_handler_index(foc_i);
00256                     event_contexts.back().add_handler(foc_hand);
00257                 }
00258                 return thief_hand == hand;
00259             }
00260         }
00261     }
00262     return false;
00263 }
00264 
00265 void pump()
00266 {
00267     SDL_PumpEvents();
00268 
00269     pump_info info;
00270 
00271     //used to keep track of double click events
00272     static int last_mouse_down = -1;
00273     static int last_click_x = -1, last_click_y = -1;
00274 
00275     SDL_Event temp_event;
00276     int poll_count = 0;
00277     int begin_ignoring = 0;
00278     std::vector< SDL_Event > events;
00279     while(SDL_PollEvent(&temp_event)) {
00280         ++poll_count;
00281         if(!begin_ignoring && temp_event.type == SDL_ACTIVEEVENT) {
00282             begin_ignoring = poll_count;
00283         } else if(begin_ignoring > 0 && SDL_EVENTMASK(temp_event.type)&INPUT_MASK) {
00284             //ignore user input events that occurred after the window was activated
00285             continue;
00286         }
00287         events.push_back(temp_event);
00288     }
00289     std::vector<SDL_Event>::iterator ev_it = events.begin();
00290     for(int i=1; i < begin_ignoring; ++i){
00291         if(SDL_EVENTMASK(ev_it->type)&INPUT_MASK) {
00292             //ignore user input events that occurred before the window was activated
00293             ev_it = events.erase(ev_it);
00294         } else {
00295             ++ev_it;
00296         }
00297     }
00298     std::vector<SDL_Event>::iterator ev_end = events.end();
00299     for(ev_it = events.begin(); ev_it != ev_end; ++ev_it){
00300         SDL_Event &event = *ev_it;
00301         switch(event.type) {
00302 
00303             case SDL_ACTIVEEVENT: {
00304                 SDL_ActiveEvent& ae = reinterpret_cast<SDL_ActiveEvent&>(event);
00305                 if((ae.state & SDL_APPMOUSEFOCUS) != 0 || (ae.state & SDL_APPINPUTFOCUS) != 0) {
00306                     cursor::set_focus(ae.gain != 0);
00307                 }
00308                 break;
00309             }
00310 
00311             //if the window must be redrawn, update the entire screen
00312             case SDL_VIDEOEXPOSE: {
00313                 update_whole_screen();
00314                 break;
00315             }
00316 
00317             case SDL_VIDEORESIZE: {
00318                 const SDL_ResizeEvent* const resize = reinterpret_cast<SDL_ResizeEvent*>(&event);
00319                 info.resize_dimensions.first = resize->w;
00320                 info.resize_dimensions.second = resize->h;
00321                 break;
00322             }
00323 
00324             case SDL_MOUSEMOTION: {
00325                 //always make sure a cursor is displayed if the
00326                 //mouse moves or if the user clicks
00327                 cursor::set_focus(true);
00328                 raise_help_string_event(event.motion.x,event.motion.y);
00329                 break;
00330             }
00331 
00332             case SDL_MOUSEBUTTONDOWN: {
00333                 //always make sure a cursor is displayed if the
00334                 //mouse moves or if the user clicks
00335                 cursor::set_focus(true);
00336                 if(event.button.button == SDL_BUTTON_LEFT) {
00337                     static const int DoubleClickTime = 500;
00338                     static const int DoubleClickMaxMove = 3;
00339                     if(last_mouse_down >= 0 && info.ticks() - last_mouse_down < DoubleClickTime &&
00340                        abs(event.button.x - last_click_x) < DoubleClickMaxMove &&
00341                        abs(event.button.y - last_click_y) < DoubleClickMaxMove) {
00342                         SDL_UserEvent user_event;
00343                         user_event.type = DOUBLE_CLICK_EVENT;
00344                         user_event.code = 0;
00345                         user_event.data1 = reinterpret_cast<void*>(event.button.x);
00346                         user_event.data2 = reinterpret_cast<void*>(event.button.y);
00347                         ::SDL_PushEvent(reinterpret_cast<SDL_Event*>(&user_event));
00348                     }
00349                     last_mouse_down = info.ticks();
00350                     last_click_x = event.button.x;
00351                     last_click_y = event.button.y;
00352                 }
00353                 break;
00354             }
00355 
00356 #if defined(_X11) && !defined(__APPLE__)
00357             case SDL_SYSWMEVENT: {
00358                 //clipboard support for X11
00359                 handle_system_event(event);
00360                 break;
00361             }
00362 #endif
00363 
00364             case SDL_QUIT: {
00365                 throw CVideo::quit();
00366             }
00367         }
00368 
00369         if(event_contexts.empty() == false) {
00370 
00371             const std::vector<handler*>& event_handlers = event_contexts.back().handlers;
00372 
00373             //events may cause more event handlers to be added and/or removed,
00374             //so we must use indexes instead of iterators here.
00375             for(size_t i1 = 0, i2 = event_handlers.size(); i1 != i2 && i1 < event_handlers.size(); ++i1) {
00376                 event_handlers[i1]->handle_event(event);
00377             }
00378         }
00379     }
00380 
00381     //inform the pump monitors that an events::pump() has occurred
00382     for(size_t i1 = 0, i2 = pump_monitors.size(); i1 != i2 && i1 < pump_monitors.size(); ++i1) {
00383         pump_monitors[i1]->process(info);
00384     }
00385 }
00386 
00387 void raise_process_event()
00388 {
00389     if(event_contexts.empty() == false) {
00390 
00391         const std::vector<handler*>& event_handlers = event_contexts.back().handlers;
00392 
00393         //events may cause more event handlers to be added and/or removed,
00394         //so we must use indexes instead of iterators here.
00395         for(size_t i1 = 0, i2 = event_handlers.size(); i1 != i2 && i1 < event_handlers.size(); ++i1) {
00396             event_handlers[i1]->process_event();
00397         }
00398     }
00399 }
00400 
00401 void raise_draw_event()
00402 {
00403     if(event_contexts.empty() == false) {
00404 
00405         const std::vector<handler*>& event_handlers = event_contexts.back().handlers;
00406 
00407         //events may cause more event handlers to be added and/or removed,
00408         //so we must use indexes instead of iterators here.
00409         for(size_t i1 = 0, i2 = event_handlers.size(); i1 != i2 && i1 < event_handlers.size(); ++i1) {
00410             event_handlers[i1]->draw();
00411         }
00412     }
00413 }
00414 
00415 void raise_volatile_draw_event()
00416 {
00417     if(event_contexts.empty() == false) {
00418 
00419         const std::vector<handler*>& event_handlers = event_contexts.back().handlers;
00420 
00421         //events may cause more event handlers to be added and/or removed,
00422         //so we must use indexes instead of iterators here.
00423         for(size_t i1 = 0, i2 = event_handlers.size(); i1 != i2 && i1 < event_handlers.size(); ++i1) {
00424             event_handlers[i1]->volatile_draw();
00425         }
00426     }
00427 }
00428 
00429 void raise_volatile_undraw_event()
00430 {
00431     if(event_contexts.empty() == false) {
00432 
00433         const std::vector<handler*>& event_handlers = event_contexts.back().handlers;
00434 
00435         //events may cause more event handlers to be added and/or removed,
00436         //so we must use indexes instead of iterators here.
00437         for(size_t i1 = 0, i2 = event_handlers.size(); i1 != i2 && i1 < event_handlers.size(); ++i1) {
00438             event_handlers[i1]->volatile_undraw();
00439         }
00440     }
00441 }
00442 
00443 void raise_help_string_event(int mousex, int mousey)
00444 {
00445     if(event_contexts.empty() == false) {
00446 
00447         const std::vector<handler*>& event_handlers = event_contexts.back().handlers;
00448 
00449         for(size_t i1 = 0, i2 = event_handlers.size(); i1 != i2 && i1 < event_handlers.size(); ++i1) {
00450             event_handlers[i1]->process_help_string(mousex,mousey);
00451         }
00452     }
00453 }
00454 
00455 int discard(Uint32 event_mask)
00456 {
00457     int discard_count = 0;
00458     SDL_Event temp_event;
00459     std::vector< SDL_Event > keepers;
00460     SDL_Delay(10);
00461     while(SDL_PollEvent(&temp_event) > 0) {
00462         if((SDL_EVENTMASK(temp_event.type) & event_mask) == 0) {
00463             keepers.push_back( temp_event );
00464         } else {
00465             ++discard_count;
00466         }
00467     }
00468 
00469     //FIXME: there is a chance new events are added before kept events are replaced
00470     for (unsigned int i=0; i < keepers.size(); ++i)
00471     {
00472         if(SDL_PushEvent(&keepers[i]) != 0) {
00473             ERR_GEN << "failed to return an event to the queue.";
00474         }
00475     }
00476 
00477     return discard_count;
00478 }
00479 
00480 int pump_info::ticks(unsigned *refresh_counter, unsigned refresh_rate) {
00481     if(!ticks_ && !(refresh_counter && ++*refresh_counter % refresh_rate)) {
00482         ticks_ = ::SDL_GetTicks();
00483     }
00484     return ticks_;
00485 }
00486 
00487 } //end events namespace
00488 
00489 input_blocker::input_blocker()
00490 {
00491     SDL_EventState(SDL_KEYDOWN, SDL_IGNORE);
00492     SDL_EventState(SDL_KEYUP, SDL_IGNORE);
00493     SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_IGNORE);
00494     SDL_EventState(SDL_MOUSEBUTTONUP, SDL_IGNORE);
00495     SDL_EventState(SDL_JOYBUTTONDOWN, SDL_IGNORE);
00496     SDL_EventState(SDL_JOYBUTTONUP, SDL_IGNORE);
00497     instance_count++;
00498 }
00499 
00500 input_blocker::~input_blocker()
00501 {
00502     instance_count--;
00503     if(instance_count == 0) {
00504         events::discard(INPUT_MASK);
00505         SDL_EventState(SDL_KEYDOWN, SDL_ENABLE);
00506         SDL_EventState(SDL_KEYUP, SDL_ENABLE);
00507         SDL_EventState(SDL_MOUSEBUTTONDOWN, SDL_ENABLE);
00508         SDL_EventState(SDL_MOUSEBUTTONUP, SDL_ENABLE);
00509         SDL_EventState(SDL_JOYBUTTONDOWN, SDL_ENABLE);
00510         SDL_EventState(SDL_JOYBUTTONUP, SDL_ENABLE);
00511     }
00512 }

Generated by doxygen 1.5.5 on 23 May 2008 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs