X-Git-Url: http://git.tdb.fi/?p=libs%2Fcore.git;a=blobdiff_plain;f=source%2Fapplication.cpp;fp=source%2Fapplication.cpp;h=765b0670d3ecee5ccaad9228b02306769022e0d7;hp=0000000000000000000000000000000000000000;hb=1013e3c216cdf8e0ecc0f3b1e8314989b5333818;hpb=5780f0826f057f99593de46a583be7c098efaf90 diff --git a/source/application.cpp b/source/application.cpp new file mode 100644 index 0000000..765b067 --- /dev/null +++ b/source/application.cpp @@ -0,0 +1,171 @@ +/* +This file is part of libmspframework +Copyright © 2006 Mikko Rasa, Mikkosoft Productions +Distributed under the LGPL +*/ +#include +#include +#include "application.h" +#include "error.h" + +using namespace std; + +namespace Msp { + +Poller::Slot &Application::add_pollable(Pollable *obj, short events) +{ + if(!poller_) + poller_=new Poller; + + Poller::Slot &slot=poller_->add_pollable(obj, events); + // Interrupt a possible poll in progress + pthread_kill(main_tid, SIGALRM); + return slot; +} + +EventManager::Event &Application::create_event() +{ + if(!ev_mgr_) + ev_mgr_=new EventManager(*this); + + return ev_mgr_->create_event(); +} + +Application::~Application() +{ + if(poller_) + delete poller_; + if(ev_mgr_) + delete ev_mgr_; +} + +/** +Constructs an instance of the registered application class and runs it. If the +application throws a UsageError, the static usage() function is called. + +This function can only be called once. The global main() function provided by +the library normally does it automatically at program startup. +*/ +int Application::run(int argc, char **argv) +{ + static bool called=false; + if(called) + { + cerr<<"Trying to call Application::run_app twice!\n"; + return 125; + } + called=true; + + if(!reg_app_) + { + cerr<<"Trying to run with no application class registered!\n"; + return 126; + } + + signal(SIGALRM, &sigalrm_); + + try + { + app_=reg_app_->create_app(argc, argv); + } + catch(const UsageError &e) + { + reg_app_->usage(argv[0], e.get_brief()); + return 1; + } + + int result=app_->main(); + delete app_; + return result; +} + +/** +Prints a message describing the usage of the application. The default version +will blame the programmer for being lazy. + +@param argv0 The value of argv[0], to be used in the message +@param brief Whether to print a brief or long usage message +*/ +void Application::usage(const char *, bool) +{ + cerr<<"The programmer was lazy and didn't write a usage() function for this application.\n"; +} + +/** +Default main loop. Calls tick() periodically if do_ticks is true, otherwise +just sleeps. A custom main loop should monitor the done member variable and +return exit_code. +*/ +int Application::main() +{ + done=false; + while(!done) + { + if(tick_mode_==IDLE) + { + if(poller_) + poller_->poll(0); + tick(); + sched_yield(); + } + else + { + if(poller_) + poller_->poll(-1); + else + { + timespec ts={1000,0}; + nanosleep(&ts, 0); + } + if(tick_mode_!=NONE) + tick(); + } + } + + return exit_code; +} + +/** +Sets the specified signal to be delivered to the sighandler member function. +*/ +void Application::catch_signal(int s) +{ + signal(s, &sighandler_); +} + +void Application::set_tick_mode(TickMode t) +{ + tick_mode_=t; + pthread_kill(main_tid, SIGALRM); +} + +/** +Causes the application to exit gracefully with the given exit code. +*/ +void Application::exit(int c) +{ + done=true; + exit_code=c; + pthread_kill(main_tid, SIGALRM); +} + +void Application::sighandler_(int s) +{ + app_->sighandler(s); +} + +Application::RegBase::RegBase() +{ + if(reg_app_) + { + cerr<<"Warning: registering the application twice\n"; + delete reg_app_; + } + + reg_app_=this; +} + +Application *Application::app_=0; +Application::RegBase *Application::reg_app_=0; + +} // namespace Msp