application.cpp

Go to the documentation of this file.
00001 /*
00002   libwt - Vassilis Virvilis Toolkit - a widget library
00003   Copyright (C) 2006 Vassilis Virvilis <vasvir2@fastmail.fm>
00004  
00005   This library is free software; you can redistribute it and/or
00006   modify it under the terms of the GNU Lesser General Public
00007   License as published by the Free Software Foundation; either
00008   version 2.1 of the License, or (at your option) any later version.
00009   
00010   This library is distributed in the hope that it will be useful,
00011   but WITHOUT ANY WARRANTY; without even the implied warranty of
00012   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013   Lesser General Public License for more details.
00014   
00015   You should have received a copy of the GNU Lesser General Public
00016   License along with this library; if not, write to the
00017   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00018   Boston, MA  02111-1307, SA.
00019 */
00020 
00021 // for Fatal constructor
00022 #include <iostream>
00023 
00024 #include <wt/application.h>
00025 #include <wt/trace.h>
00026 #include <wt/rootwindow.h>
00027 #include <wt/color.h>
00028 #include <wt/font.h>
00029 #include <wt/audio.h>
00030 
00031 #include "sdlevent.h"
00032 #include "sdltimer.h"
00033 #include "sdlinput.h"
00034 #include "sdlmisc.h"
00035 
00036 #include <wt/event.h>
00037 
00038 namespace Wt {
00039 
00040 Application::EventQueueItem::EventQueueItem(Object *receiver, Event *event)
00041         : receiver(receiver), event(event) {}
00042 
00043 bool Application::EventQueueItem::operator==(const EventQueueItem& other) const {
00044     return (other.receiver == receiver && other.event->type() == event->type());
00045 }
00046 
00047 const char * Application::Exception::what() const throw() {
00048     return SDL_GetError();
00049 }
00050 
00051 Application::Application(int argc, char **argv)
00052         : Object(0, "Application::anon"),
00053         Singleton<Application>(this),
00054         exitcode_(0),
00055         running_(true),
00056         width_(Display::defaultWidth),
00057         height_(Display::defaultHeight),
00058 depth_(Display::defaultDepth) {
00059     parseArgs(argc, argv);
00060     Uint32 sdl_flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE | SDL_INIT_TIMER;
00061 
00062 #if !defined( __WIN32__ ) && !defined( __CYGWIN32__ )
00063 
00064     sdl_flags |= SDL_INIT_EVENTTHREAD;
00065 #endif
00066 
00067     /* Initialize SDL step by step*/
00068     trace("app") << "trying to initialize SDLvideo ... " << std::endl;
00069     if ( SDL_Init(sdl_flags) < 0 ) {
00070         Error("Cannot initialize SDL\n");
00071         throw Exception();
00072     }
00073 
00074     //init SDLEventHandler
00075     SDLEvent::init();
00076     //init SDLInput
00077     SDLInput::init();
00078     //init SDLTimers
00079     SDLTimer::init();
00080     // initialize audio handling
00081     Audio::init();
00082     // initialize font handling
00083     Font::init();
00084     // initialize rootwindow
00085     new RootWindow(width_, height_, depth_);
00086 
00087     //parseArgs(argc, argv, other_flags);
00088 
00089     trace("app", "Enabling SDL Unicode support\n");
00090     SDL_EnableUNICODE(1);
00091 
00092     SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
00093 }
00094 
00095 std::list<std::string>& Application::argv() {
00096     return argv_;
00097 }
00098 
00099 void Application::parseArgs(int argc, char** argv) {
00100     enum {
00101         TRACE, XSYNC, WT_WIDTH, WT_HEIGHT, WT_DEPTH, WT_HELP, HELP
00102     };
00103 
00104     class Option {
00105     public:
00106         Option(const std::string& name, const std::string& help)
00107                 : name(name),
00108         help(help) {}
00109         std::string name;
00110         std::string help;
00111     };
00112 
00113     Option options[] = {
00114                            Option("--wt-trace=", "enables tracing for a comma separated list of subsystems"),
00115                            Option("--wt-xsync", "enables X sync to help debugging"),
00116                            Option("--wt-width=", "the preffered width of the application"),
00117                            Option("--wt-height=", "the preffered height of the application"),
00118                            Option("--wt-depth=", "the preffered color depth of the application"),
00119                            Option("--wt-help", "display this help and quits"),
00120                            Option("--help", "display this help and quits")
00121                        };
00122 
00123     const int numopts = sizeof(options) / sizeof(options[0]);
00124 
00125     for (int i = 0; i < argc; i++) {
00126         std::string s = argv[i];
00127         if (s.find(options[TRACE].name) == 0) {
00128             std::string rest = std::string(s, options[TRACE].name.length());
00129             do {
00130                 //look for comma
00131                 std::string channel;
00132                 int comma_index = rest.find(",");
00133                 if (comma_index > 0) {
00134                     channel = std::string(rest, 0, comma_index);
00135                     rest = std::string(rest, comma_index + 1);
00136                     enableTrace(channel);
00137                 } else if (comma_index < 0) {
00138                     channel = std::string(rest, 0);
00139                     rest = "";
00140                     enableTrace(channel);
00141                 } else {
00142                     // == 0
00143                     rest = std::string(rest, comma_index + 1);
00144                 }
00145             } while(rest.length());
00146         } else if (s.find(options[XSYNC].name) == 0) {
00147             trace("app", "Enabling X-sync for debugging\n");
00148             SDL::enableDebug();
00149         } else if (s.find(options[WT_WIDTH].name) == 0) {
00150             width_ = boost::lexical_cast<int>(std::string(s, options[WT_WIDTH].name.length()));
00151         } else if (s.find(options[WT_HEIGHT].name) == 0) {
00152             height_ = boost::lexical_cast<int>(std::string(s, options[WT_HEIGHT].name.length()));
00153         } else if (s.find(options[WT_DEPTH].name) == 0) {
00154             depth_ = boost::lexical_cast<int>(std::string(s, options[WT_DEPTH].name.length()));
00155         } else if (s.find(options[WT_HELP].name) == 0 ||
00156                    s.find(options[HELP].name) == 0) {
00157             std::cout << "Standard wt options are:\n";
00158             for (int j = 0; j < numopts; j++) {
00159                 std::cout << "\t" << options[j].name <<
00160                 "\t" << options[j].help << std::endl;
00161             }
00162             quit();
00163         } else {
00164             argv_.push_back(s);
00165         }
00166     }
00167 }
00168 
00169 Application::~Application() {
00170     trace("app") << "In application destructor" << std::endl;
00171 
00172     aboutToQuit.emit();
00173 
00174     trace("app") << "Doing video shutdown" << std::endl;
00175 
00176     delete RootWindow::instance();
00177 
00178     trace("app") << "Quitting SDL" << std::endl;
00179 
00180     Font::quit();
00181     Audio::quit();
00182     SDLTimer::quit();
00183     SDLInput::quit();
00184     SDLEvent::quit();
00185     // shut down video (to kill the window) before shutting down
00186     // audio, since audio shutdown takes _so_ long
00187     SDL_QuitSubSystem(SDL_INIT_VIDEO);
00188     SDL_Quit();
00189 }
00190 
00191 Widget *Application::mainWidget() {
00192     return static_cast<Widget *>(RootWindow::instance());
00193 }
00194 
00195 void Application::sendPostedEvents() {
00196     Application *app = existingInstance();
00197     if (!app)
00198         return;
00199     EventQueueList& queue = app->queue;
00200     while (!queue.empty()) {
00201         const EventQueueItem item = queue.front();
00202         Object *receiver = item.receiver;
00203         Event *e = item.event;
00204         queue.pop_front();
00205         trace("event") << "Handling " << e << std::endl;
00206         sendEvent(receiver, *e);
00207         delete e;
00208     }
00209 }
00210 
00211 void Application::processEvents(Condition* cond) {
00212     condition_stack.push(cond);
00213     while (!(*cond)()) {
00214         if (queue.empty())
00215             SDLEvent::wait();
00216         sendPostedEvents();
00217     }
00218     condition_stack.pop();
00219 }
00220 
00221 class SingleShot : public Application::Condition {
00222 public:
00223     SingleShot()
00224             : count_(0) {}
00225 
00226     virtual bool operator()() {
00227         if (count_)
00228             return true;
00229 
00230         count_++;
00231 
00232         return false;
00233     }
00234 
00235 private:
00236     int count_;
00237 };
00238 
00239 void Application::processEvent() {
00240     SingleShot c;
00241     processEvents(&c);
00242 }
00243 
00244 class TimerBlock : public Application::Condition {
00245 public:
00246     TimerBlock(int ms)
00247             : ms(ms) {
00248         time.start();
00249     }
00250 
00251     virtual bool operator()() {
00252         return (time.elapsed() > ms);
00253     }
00254 
00255 private:
00256     Time time;
00257     int ms;
00258 };
00259 
00260 void Application::processEvents(int ms) {
00261     TimerBlock t(ms);
00262     processEvents(&t);
00263 }
00264 
00265 class VarBlock : public Application::Condition {
00266 public:
00267     VarBlock(const bool& var)
00268             : var(var) {}
00269 
00270     virtual bool operator()() {
00271         return !var;
00272     }
00273 
00274 private:
00275     const bool& var;
00276 };
00277 
00278 void Application::processEvents(const bool& var) {
00279     VarBlock v(var);
00280     processEvents(&v);
00281 }
00282 
00283 /// process all events so far until the end of the application
00284 int Application::exec() {
00285     processEvents(running_);
00286     sendPostedEvents();
00287     return exitcode_;
00288 }
00289 
00290 void Application::exit(int exitcode) {
00291     Application *app = existingInstance();
00292     if (!app)
00293         return;
00294     trace("app") << "Application: was requested to exit." << std::endl;
00295     app->running_ = false;
00296     app->exitcode_ = exitcode;
00297 }
00298 
00299 void Application::quit() {
00300     Application::exit(0);
00301 }
00302 
00303 bool Application::event(Event *e) {
00304     return filterEvent(e);
00305 }
00306 
00307 bool Application::notify(Object *receiver, Event *event) {
00308     if (this->event(event))
00309         return true;
00310     const int type = event->type();
00311     Widget *w = dynamic_cast<Widget *>(receiver);
00312     if (w) {
00313         const bool input_event = (type == Event::MouseButtonPress) ||
00314                                  (type == Event::MouseButtonRelease) ||
00315                                  (type == Event::MouseButtonDblClick) ||
00316                                  (type == Event::MouseMove) ||
00317                                  (type == Event::KeyPress) ||
00318                                  (type == Event::KeyRelease) ||
00319                                  (type == Event::Wheel);
00320 
00321         if (input_event && !w->enabled) {
00322             return false;
00323         }
00324         return receiver->event(event);
00325     }
00326 
00327     return receiver->event(event);
00328 }
00329 
00330 bool Application::sendEvent(Object *receiver, Event& event) {
00331     Application *app = existingInstance();
00332     if (app)
00333         return app->notify(receiver, &event);
00334     else if (receiver)
00335         return receiver->event(&event);
00336     return 0;
00337 }
00338 
00339 void Application::postEvent(Object *receiver, Event *event) {
00340     Application *app = existingInstance();
00341     if (!app) {
00342         sendEvent(receiver, *event);
00343         delete event;
00344         return;
00345     }
00346     EventQueueList& queue = app->queue;
00347     EventQueueItem new_item(receiver, event);
00348     int type = event->type();
00349 
00350     trace("event") << "Posting " << event
00351     << " for " << receiver << std::endl;
00352 
00353     // obvious optimization: eliminate unnedded/unprocessed/overwritten events
00354     // let only the last one suvive for move, size, layouthint
00355     // aggregate paint
00356     // also eliminate child events when they are followed by destruction
00357     switch (type) {
00358     case Event::ChildRemoved: {
00359             Object *dead_obj = (static_cast<ChildEvent *>(event))->child();
00360             for (EventQueueList::iterator I(queue.begin()),
00361                     E(queue.end()); I != E;) {
00362                 const EventQueueItem& item = *I;
00363                 if ((item.receiver == new_item.receiver &&
00364                         item.event->type() == Event::ChildInserted) ||
00365                         item.receiver == dead_obj) {
00366                     trace("event") << "Eliminating " << item.event <<
00367                     " for " << static_cast<void *>(item.receiver) << std::endl;
00368                     delete item.event;
00369                     I = queue.erase(I);
00370                 } else {
00371                     ++I;
00372                 }
00373             }
00374             // we are not going to deliver this sucker
00375             if (!receiver) {
00376                 delete event;
00377                 return;
00378             }
00379         }
00380         break;
00381     case Event::Paint: {
00382             Region region;
00383 
00384             for (EventQueueList::iterator I(queue.begin()),
00385                     E(queue.end()); I != E;) {
00386                 const EventQueueItem& item = *I;
00387                 if(item == new_item) {
00388                     PaintEvent *paint_e;
00389                     if (region.isEmpty()) {
00390                         paint_e = static_cast<PaintEvent *>(new_item.event);
00391                         region = paint_e->region();
00392                     }
00393                     // aggregate paint events
00394                     paint_e = static_cast<PaintEvent *>(item.event);
00395                     trace("event") << "Before Aggregation: " << region;
00396                     region |= paint_e->region();
00397                     trace("event") << "Aggregate: " << paint_e->region();
00398                     trace("event") << "After Aggregation: " << region;
00399                     trace("event") << "Eliminating "
00400                     << item.event << " " << static_cast<void *>(item.event)
00401                     << " for " << receiver << std::endl;
00402                     delete item.event;
00403                     I = queue.erase(I);
00404                 } else {
00405                     ++I;
00406                 }
00407             }
00408 
00409             if (!region.isEmpty()) {
00410                 bool erased = static_cast<PaintEvent *>(new_item.event)->erased();
00411                 delete new_item.event;
00412                 // clip to parent if exists
00413                 Widget *w = static_cast<Widget *>(new_item.receiver);
00414                 Widget *wp = static_cast<Widget *>(w->parent());
00415                 if (wp) {
00416                     Widget::update(wp, w->mapToParent(region));
00417                 }
00418                 new_item.event = new PaintEvent(region, erased);
00419             }
00420 
00421         }
00422         break;
00423     case Event::Resize:
00424     case Event::Move:
00425     case Event::LayoutHint:
00426         for (EventQueueList::iterator I(queue.begin()),
00427                 E(queue.end()); I != E;) {
00428             const EventQueueItem& item = *I;
00429             if(item == new_item) {
00430                 trace("event") << "Eliminating " << item.event << " for " << receiver << std::endl;
00431                 delete item.event;
00432                 I = queue.erase(I);
00433             } else {
00434                 ++I;
00435             }
00436         }
00437         break;
00438     default:
00439         break;
00440     }
00441 
00442     queue.push_back(new_item);
00443 }
00444 
00445 } // namespace Wt

Generated Fri Jul 28 19:22:59 2006.
Copyright © 1998-2003 by the respective authors.

This document is licensed under the terms of the GNU Free Documentation License and may be freely distributed under the conditions given by this license.