]> git.tdb.fi Git - libs/core.git/blob - source/application.cpp
22c8d2688310685fb2aaeb4e30857256bcc7c062
[libs/core.git] / source / 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         pthread_kill(main_tid, SIGALRM);        
23         return slot;
24 }
25
26 EventManager::Event &Application::create_event()
27 {
28         if(!ev_mgr_)
29                 ev_mgr_=new EventManager(*this);
30
31         return ev_mgr_->create_event();
32 }
33
34 Application::~Application()
35 {
36         if(poller_)
37                 delete poller_;
38         if(ev_mgr_)
39                 delete ev_mgr_;
40 }
41
42 /**
43 Constructs an instance of the registered application class and runs it.  If the
44 application throws a UsageError, the static usage() function is called.
45
46 This function can only be called once.  The global main() function provided by
47 the library normally does it automatically at program startup.
48 */
49 int Application::run(int argc, char **argv)
50 {
51         static bool called=false;
52         if(called)
53         {
54                 cerr<<"Trying to call Application::run_app twice!\n";
55                 return 125;
56         }
57         called=true;
58
59         if(!reg_app_)
60         {
61                 cerr<<"Trying to run with no application class registered!\n";
62                 return 126;
63         }
64
65         signal(SIGALRM, &sigalrm_);
66         
67         try
68         {
69                 app_=reg_app_->create_app(argc, argv);
70         }
71         catch(const UsageError &e)
72         {
73                 reg_app_->usage(argv[0], e.get_brief());
74                 return 1;
75         }
76
77         int result=app_->main();
78         delete app_;
79         return result;
80 }
81
82 /**
83 Prints a message describing the usage of the application.  The default version
84 will blame the programmer for being lazy.
85
86 @param   argv0  The value of argv[0], to be used in the message
87 @param   brief  Whether to print a brief or long usage message
88 */
89 void Application::usage(const char *, bool)
90 {
91         cerr<<"The programmer was lazy and didn't write a usage() function for this application.\n";
92 }
93
94 /**
95 Default main loop.  Calls tick() periodically if do_ticks is true, otherwise
96 just sleeps.  A custom main loop should monitor the done member variable and
97 return exit_code.
98 */
99 int Application::main()
100 {
101         done=false;
102         while(!done)
103         {
104                 if(tick_mode_==IDLE)
105                 {
106                         if(poller_)
107                                 poller_->poll(0);
108                         tick();
109                         sched_yield();
110                 }
111                 else
112                 {
113                         if(poller_)
114                                 poller_->poll(-1);
115                         else
116                         {
117 #ifdef WIN32
118                                 Sleep(1);
119 #else
120                                 timespec ts={1000,0};
121                                 nanosleep(&ts, 0);
122 #endif
123                         }
124                         if(tick_mode_!=NONE)
125                                 tick();
126                 }
127         }
128
129         return exit_code;
130 }
131
132 /**
133 Sets the specified signal to be delivered to the sighandler member function.
134 */
135 void Application::catch_signal(int s)
136 {
137         signal(s, &sighandler_);
138 }
139
140 void Application::set_tick_mode(TickMode t)
141 {
142         tick_mode_=t;
143         pthread_kill(main_tid, SIGALRM);        
144 }
145
146 /**
147 Causes the application to exit gracefully with the given exit code.
148 */
149 void Application::exit(int c)
150 {
151         done=true;
152         exit_code=c;
153         pthread_kill(main_tid, SIGALRM);        
154 }
155
156 void Application::sighandler_(int s)
157 {
158         app_->sighandler(s);
159 }
160
161 Application::RegBase::RegBase()
162 {
163         if(reg_app_)
164         {
165                 cerr<<"Warning: registering the application twice\n";
166                 delete reg_app_;
167         }
168
169         reg_app_=this;
170 }
171
172 Application *Application::app_=0;
173 Application::RegBase *Application::reg_app_=0;
174
175 } // namespace Msp