events.cpp

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

Generated by doxygen 1.7.1 on Thu May 24 2012 01:02:36 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs