]> git.tdb.fi Git - libs/core.git/blob - source/core/application.cpp
01bb558e279255fbb5f83676c61886966f9624b2
[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                         timespec ts={0,1000000};
129                         nanosleep(&ts, 0);
130 #endif
131                 }
132                 else
133                 {
134                         if(poller_)
135                                 poller_->poll(-1);
136                         else
137                         {
138 #ifdef WIN32
139                                 Sleep(1);
140 #else
141                                 timespec ts={1000,0};
142                                 nanosleep(&ts, 0);
143 #endif
144                         }
145                         if(tick_mode_!=NONE)
146                                 tick();
147                 }
148         }
149
150         return exit_code;
151 }
152
153 /**
154 Sets the specified signal to be delivered to the sighandler member function.
155 */
156 void Application::catch_signal(int s)
157 {
158         signal(s, &sighandler_);
159 }
160
161 void Application::set_tick_mode(TickMode t)
162 {
163         tick_mode_=t;
164 #ifndef WIN32 //XXX
165         pthread_kill(main_tid, SIGALRM);        
166 #endif
167 }
168
169 /**
170 Causes the application to exit gracefully with the given exit code.
171 */
172 void Application::exit(int c)
173 {
174         done=true;
175         exit_code=c;
176 #ifndef WIN32 //XXX
177         pthread_kill(main_tid, SIGALRM);        
178 #endif
179 }
180
181 void Application::sighandler_(int s)
182 {
183         app_->sighandler(s);
184 }
185
186 Application::RegBase::RegBase()
187 {
188         if(reg_app_)
189         {
190                 cerr<<"Warning: registering the application twice\n";
191                 delete reg_app_;
192         }
193
194         reg_app_=this;
195 }
196
197 Application *Application::app_=0;
198 Application::RegBase *Application::reg_app_=0;
199
200 } // namespace Msp