]> git.tdb.fi Git - libs/core.git/blob - source/core/application.cpp
a9aa88ea55bdee578d81238d614120a962be2173
[libs/core.git] / source / core / application.cpp
1 /*
2 This file is part of libmspframework
3 Copyright © 2006 Mikko Rasa, Mikkosoft Productions
4 Distributed under the LGPL
5 */
6 #include <signal.h>
7 #include <iostream>
8 #include "application.h"
9 #include "error.h"
10
11 using namespace std;
12
13 namespace Msp {
14
15 Poller::Slot &Application::add_pollable(Pollable *obj, short events)
16 {
17         if(!poller_)
18                 poller_=new Poller;
19         
20         Poller::Slot &slot=poller_->add_pollable(obj, events);
21         // Interrupt a possible poll in progress
22 #ifndef WIN32  //XXX
23         pthread_kill(main_tid, SIGALRM);
24 #endif
25         return slot;
26 }
27
28 EventManager::Event &Application::create_event()
29 {
30         if(!ev_mgr_)
31                 ev_mgr_=new EventManager(*this);
32
33         return ev_mgr_->create_event();
34 }
35
36 Application::~Application()
37 {
38         if(poller_)
39                 delete poller_;
40         if(ev_mgr_)
41                 delete ev_mgr_;
42 }
43
44 /**
45 Constructs an instance of the registered application class and runs it.  If the
46 application throws a UsageError, the static usage() function is called.
47
48 This function can only be called once.  The global main() function provided by
49 the library normally does it automatically at program startup.
50 */
51 int Application::run(int argc, char **argv)
52 {
53         static bool called=false;
54         if(called)
55         {
56                 cerr<<"Trying to call Application::run_app twice!\n";
57                 return 125;
58         }
59         called=true;
60
61         if(!reg_app_)
62         {
63                 cerr<<"Trying to run with no application class registered!\n";
64                 return 126;
65         }
66
67 #ifndef WIN32 //XXX
68         signal(SIGALRM, &sigalrm_);
69 #endif
70         
71         try
72         {
73                 app_=reg_app_->create_app(argc, argv);
74         }
75         catch(const UsageError &e)
76         {
77                 reg_app_->usage(argv[0], e.get_brief());
78                 return 1;
79         }
80
81         int result=app_->main();
82         delete app_;
83         return result;
84 }
85
86 /**
87 Prints a message describing the usage of the application.  The default version
88 will blame the programmer for being lazy.
89
90 @param   argv0  The value of argv[0], to be used in the message
91 @param   brief  Whether to print a brief or long usage message
92 */
93 void Application::usage(const char *, bool)
94 {
95         cerr<<"The programmer was lazy and didn't write a usage() function for this application.\n";
96 }
97
98 Application::Application():
99         exit_code(0),
100         tick_mode_(IDLE),
101         poller_(0),
102         ev_mgr_(0)
103 #ifndef WIN32
104         //XXX Figure out how to get the current thread on win32
105         ,main_tid(pthread_self())
106 #endif
107 { }
108
109 /**
110 Default main loop.  Calls tick() periodically if do_ticks is true, otherwise
111 just sleeps.  A custom main loop should monitor the done member variable and
112 return exit_code.
113 */
114 int Application::main()
115 {
116         done=false;
117         while(!done)
118         {
119                 if(tick_mode_==IDLE)
120                 {
121                         if(poller_)
122                                 poller_->poll(0);
123                         tick();
124 #ifdef WIN32
125                         Sleep(0);
126 #else
127                         sched_yield();
128 #endif
129                 }
130                 else
131                 {
132                         if(poller_)
133                                 poller_->poll(-1);
134                         else
135                         {
136 #ifdef WIN32
137                                 Sleep(1);
138 #else
139                                 timespec ts={1000,0};
140                                 nanosleep(&ts, 0);
141 #endif
142                         }
143                         if(tick_mode_!=NONE)
144                                 tick();
145                 }
146         }
147
148         return exit_code;
149 }
150
151 /**
152 Sets the specified signal to be delivered to the sighandler member function.
153 */
154 void Application::catch_signal(int s)
155 {
156         signal(s, &sighandler_);
157 }
158
159 void Application::set_tick_mode(TickMode t)
160 {
161         tick_mode_=t;
162 #ifndef WIN32 //XXX
163         pthread_kill(main_tid, SIGALRM);        
164 #endif
165 }
166
167 /**
168 Causes the application to exit gracefully with the given exit code.
169 */
170 void Application::exit(int c)
171 {
172         done=true;
173         exit_code=c;
174 #ifndef WIN32 //XXX
175         pthread_kill(main_tid, SIGALRM);        
176 #endif
177 }
178
179 void Application::sighandler_(int s)
180 {
181         app_->sighandler(s);
182 }
183
184 Application::RegBase::RegBase()
185 {
186         if(reg_app_)
187         {
188                 cerr<<"Warning: registering the application twice\n";
189                 delete reg_app_;
190         }
191
192         reg_app_=this;
193 }
194
195 Application *Application::app_=0;
196 Application::RegBase *Application::reg_app_=0;
197
198 } // namespace Msp