--- /dev/null
+/*
+This file is part of libmspframework
+Copyright © 2006 Mikko Rasa, Mikkosoft Productions
+Distributed under the LGPL
+*/
+#include <signal.h>
+#include <iostream>
+#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