]> git.tdb.fi Git - libs/core.git/blobdiff - source/application.cpp
Add files
[libs/core.git] / source / application.cpp
diff --git a/source/application.cpp b/source/application.cpp
new file mode 100644 (file)
index 0000000..765b067
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+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