]> git.tdb.fi Git - libs/core.git/blob - source/application.cpp
765b0670d3ecee5ccaad9228b02306769022e0d7
[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                                 timespec ts={1000,0};
118                                 nanosleep(&ts, 0);
119                         }
120                         if(tick_mode_!=NONE)
121                                 tick();
122                 }
123         }
124
125         return exit_code;
126 }
127
128 /**
129 Sets the specified signal to be delivered to the sighandler member function.
130 */
131 void Application::catch_signal(int s)
132 {
133         signal(s, &sighandler_);
134 }
135
136 void Application::set_tick_mode(TickMode t)
137 {
138         tick_mode_=t;
139         pthread_kill(main_tid, SIGALRM);        
140 }
141
142 /**
143 Causes the application to exit gracefully with the given exit code.
144 */
145 void Application::exit(int c)
146 {
147         done=true;
148         exit_code=c;
149         pthread_kill(main_tid, SIGALRM);        
150 }
151
152 void Application::sighandler_(int s)
153 {
154         app_->sighandler(s);
155 }
156
157 Application::RegBase::RegBase()
158 {
159         if(reg_app_)
160         {
161                 cerr<<"Warning: registering the application twice\n";
162                 delete reg_app_;
163         }
164
165         reg_app_=this;
166 }
167
168 Application *Application::app_=0;
169 Application::RegBase *Application::reg_app_=0;
170
171 } // namespace Msp