]> git.tdb.fi Git - libs/core.git/blob - source/core/application.cpp
Store hInstance in Application class on win32
[libs/core.git] / source / core / application.cpp
1 /* $Id$
2
3 This file is part of libmspcore
4 Copyright © 2006 Mikko Rasa, Mikkosoft Productions
5 Distributed under the LGPL
6 */
7 #include <signal.h>
8 #include <iostream>
9 #include "../debug/backtrace.h"
10 #include "../debug/demangle.h"
11 #include "../time/units.h"
12 #include "../time/utils.h"
13 #include "application.h"
14 #include "except.h"
15
16 using namespace std;
17
18 namespace Msp {
19
20 /**
21 Constructs an instance of the registered application class and runs it.  If the
22 application throws a UsageError, the static usage() function is called.
23
24 This function can only be called once.  The global main() function provided by
25 the library normally does it automatically at program startup.
26 */
27 int Application::run(int argc, char **argv, void *data)
28 {
29         static bool called=false;
30         if(called)
31         {
32                 cerr<<"Trying to call Application::run_app twice!\n";
33                 return 125;
34         }
35         called=true;
36
37         if(!reg_app_)
38         {
39                 cerr<<"Trying to run with no application class registered!\n";
40                 return 126;
41         }
42
43         data_=data;
44
45         try
46         {
47                 try
48                 {
49                         app_=reg_app_->create_app(argc, argv);
50                 }
51                 catch(const UsageError &e)
52                 {
53                         reg_app_->usage(e.what(), argv[0], e.get_brief());
54                         return 1;
55                 }
56
57                 int result=app_->main();
58                 delete app_;
59                 return result;
60         }
61         catch(const exception &e)
62         {
63                 cerr<<"An uncaught exception occurred.\n";
64                 cerr<<"  type:   "<<Debug::demangle(typeid(e).name())<<'\n';
65                 cerr<<"  what(): "<<e.what()<<'\n';
66
67                 const Exception *exc=dynamic_cast<const Exception *>(&e);
68                 if(exc && !exc->get_backtrace().get_frames().empty())
69                 {
70                         cerr<<"  backtrace:\n";
71                         const Debug::Backtrace::FrameSeq &frames=exc->get_backtrace().get_frames();
72                         for(Debug::Backtrace::FrameSeq::const_iterator i=frames.begin(); i!=frames.end(); ++i)
73                         {
74                                 cerr<<"    "<<i->address;
75                                 if(!i->symbol.empty())
76                                         cerr<<" in "<<i->symbol;
77                                 cerr<<" from "<<i->file<<'\n';
78                         }
79                 }
80
81                 delete app_;
82                 return 124;
83         }
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   reason  Why the function was called
91 @param   argv0   The value of argv[0], to be used in the message
92 @param   brief   Whether to print a brief or long usage message
93 */
94 void Application::usage(const char *reason, const char *, bool)
95 {
96         if(reason)
97                 cerr<<"UsageError: "<<reason<<'\n';
98         cerr<<"The programmer was lazy and didn't write a usage() function for this application.\n";
99 }
100
101 Application::Application():
102         exit_code(0),
103         loop_mode_(TICK_SLEEP)
104 { }
105
106 /**
107 Default main loop.  Behavior depends on loop_mode_.  A custom main loop should
108 monitor the done member variable and return exit_code.
109 */
110 int Application::main()
111 {
112         if(loop_mode_==NONE)
113                 return 0;
114
115         done=false;
116         while(!done)
117         {
118                 if(loop_mode_==SLEEP)
119                 {
120                         sleep_sem_.wait();
121                         if(!done)
122                                 tick();
123                 }
124                 else if(loop_mode_==TICK_SLEEP)
125                 {
126                         tick();
127                         Time::sleep(Time::msec);
128                 }
129                 else if(loop_mode_==TICK_YIELD)
130                 {
131                         tick();
132 #ifdef WIN32
133                         Sleep(0);
134 #else
135                         sched_yield();
136 #endif
137                 }
138                 else if(loop_mode_==TICK_BUSY)
139                         tick();
140         }
141
142         return exit_code;
143 }
144
145 /**
146 Sets the specified signal to be delivered to the sighandler member function.
147 */
148 void Application::catch_signal(int s)
149 {
150         signal(s, &sighandler_);
151 }
152
153 /**
154 Changes the main loop mode.
155 */
156 void Application::set_loop_mode(LoopMode l)
157 {
158         LoopMode old_mode=loop_mode_;
159         loop_mode_=l;
160         if(old_mode==SLEEP)
161                 sleep_sem_.signal();
162 }
163
164 /**
165 Causes the tick() function to be executed once if loop mode is SLEEP.  Has no
166 effect with other loop modes.
167 */
168 void Application::induce_tick()
169 {
170         if(loop_mode_==SLEEP)
171                 sleep_sem_.signal();
172 }
173
174 /**
175 Causes the application to exit gracefully with the given exit code.
176 */
177 void Application::exit(int c)
178 {
179         done=true;
180         exit_code=c;
181         if(loop_mode_==SLEEP)
182                 sleep_sem_.signal();
183 }
184
185 /**
186 Static wrapper function to call a member function of the Application instance.
187 */
188 void Application::sighandler_(int s)
189 {
190         app_->sighandler(s);
191 }
192
193 Application::RegBase::RegBase()
194 {
195         if(reg_app_)
196         {
197                 cerr<<"Warning: registering the application twice\n";
198                 delete reg_app_;
199         }
200
201         reg_app_=this;
202 }
203
204 Application *Application::app_=0;
205 Application::RegBase *Application::reg_app_=0;
206 void *Application::data_=0;
207
208 } // namespace Msp