/
imodule.h
340 lines (295 loc) · 10.1 KB
/
imodule.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
#pragma once
#include <memory>
#include <functional>
#include <cassert>
#include <sigc++/trackable.h>
#include <sigc++/signal.h>
#include <mutex>
#include <string>
#include <set>
#include <vector>
/**
* \defgroup module Module system
*/
/** greebo: These registry keys can be used application-wide during runtime
* to retrieve the various paths.
*/
namespace
{
const char* const RKEY_APP_PATH = "user/paths/appPath";
const char* const RKEY_HOME_PATH = "user/paths/homePath";
const char* const RKEY_SETTINGS_PATH = "user/paths/settingsPath";
const char* const RKEY_BITMAPS_PATH = "user/paths/bitmapsPath";
const char* const RKEY_ENGINE_PATH = "user/paths/enginePath";
const char* const RKEY_MAP_PATH = "user/paths/mapPath";
const char* const RKEY_PREFAB_PATH = "user/paths/prefabPath";
}
// A function taking an error title and an error message string, invoked in debug builds
// for things like ASSERT_MESSAGE and ERROR_MESSAGE
typedef std::function<void (const std::string&, const std::string&)> ErrorHandlingFunction;
/**
* Provider for various information that may be required by modules during
* initialisation.
*
* \ingroup module
*/
class ApplicationContext
{
public:
/**
* \brief
* Argument list type.
*/
typedef std::vector<std::string> ArgumentList;
/**
* Destructor
*/
virtual ~ApplicationContext() {}
/**
* Return the application path of the current Radiant instance.
*/
virtual std::string getApplicationPath() const = 0;
/**
* Return the toplevel path contaning runtime data files, such as the GL
* programs or UI descriptor files. On Windows this is the same as the
* application path, on Linux it is determined at compile-time but probably
* something like /usr/share/darkradiant.
*/
virtual std::string getRuntimeDataPath() const = 0;
/**
* Return the settings path of the current Radiant instance.
*/
virtual std::string getSettingsPath() const = 0;
/**
* Return the settings path of the current Radiant instance.
*/
virtual std::string getBitmapsPath() const = 0;
/**
* \brief
* Return the list of command line arguments.
*/
virtual const ArgumentList& getCmdLineArgs() const = 0;
/**
* Return the reference to the application's output/error streams.
*/
virtual std::ostream& getOutputStream() const = 0;
virtual std::ostream& getErrorStream() const = 0;
virtual std::ostream& getWarningStream() const = 0;
// Provides a single mutex object which should be locked by client code
// before writing to the any of the above streams.
virtual std::mutex& getStreamLock() const = 0;
/**
* Sets up the paths and stores them into the registry.
*/
virtual void savePathsToRegistry() const = 0;
/**
* Retrieve a function pointer which can handle assertions and runtime errors
*/
virtual const ErrorHandlingFunction& getErrorHandlingFunction() const = 0;
};
/**
* Set of strings for module dependencies.
*/
typedef std::set<std::string> StringSet;
/**
* Interface class for modules. Each RegisterableModule can return its name and
* its set of dependencies.
*
* Note that this interface does NOT concern itself with the type (interface)
* of each individual module; it is up to the GlobalBlah() accessor function
* associated with each module to perform the required downcast to the known
* type.
*
* All RegisterableModules implement sigc::trackable, since they will often want
* to connect themselves to another module's signal(s).
*
* \ingroup module
*/
class RegisterableModule: public sigc::trackable
{
public:
/**
* Destructor
*/
virtual ~RegisterableModule() {}
/**
* Return the name of this module. This must be globally unique across all
* modules; the modulesystem will throw a logic_error if two modules attempt
* to register themselves with the same name.
*/
virtual const std::string& getName() const = 0;
/**
* Return the set of dependencies for this module. The return value is a
* set of strings, each containing the unique name (as returned by
* getName()) of a module which must be initialised before this one.
*/
virtual const StringSet& getDependencies() const = 0;
/**
* Instruct this module to initialise itself. A RegisterableModule must NOT
* invoke any calls to other modules in its constructor, since at the point
* of construction the other modules will not have been initialised. Once
* all of the dependencies are processed by the ModuleRegistry, each module
* will have its initialiseModule() method called at the appropriate point.
*
* The ModuleRegistry guarantees that any modules named in the set of
* dependencies returned by getDependencies() will be initialised and ready
* for use at the time this method is invoked. Attempting to access a module
* which was NOT listed as a dependency is undefined.
*
* @param ctx
* The ApplicationContext of the running Radiant application.
*/
virtual void initialiseModule(const ApplicationContext& ctx) = 0;
/**
* Optional shutdown routine. Allows the module to de-register itself,
* shutdown windows, save stuff into the Registry and so on.
*
* All the modules are getting called one by one, all other modules
* are available until the last shutdownModule() call was invoked.
*/
virtual void shutdownModule() {
// Empty default implementation
}
};
/**
* Shared pointer typdef.
*/
typedef std::shared_ptr<RegisterableModule> RegisterableModulePtr;
/**
* A ModuleObserver can be attached/detached to certain modules (like the
* MaterialManager or the OpenGLRendersystem) to get notified about
* realise() or unrealise() events.
* (Might be replaced by the sigc signal framework eventually)
*/
class ModuleObserver
{
public:
virtual ~ModuleObserver() {}
virtual void unrealise() = 0;
virtual void realise() = 0;
};
/**
* Interface for the module registry. This is the owner and manager of all
* RegisterableModules defined in DLLs and the main binary.
*
* For obvious reasons, the ModuleRegistry itself is not a module, but a static
* object owned by the main binary and returned through a globally-accessible
* method.
*
* \ingroup module
*/
class IModuleRegistry {
public:
/**
* Destructor
*/
virtual ~IModuleRegistry() {}
/**
* Register a RegisterableModule. The name and dependencies are retrieved
* through the appropriate RegisterableModule interface methods.
*
* This method does not cause the RegisterableModule to be initialised.
*/
virtual void registerModule(const RegisterableModulePtr& module) = 0;
/**
* Initialise all of the modules previously registered with
* registerModule() in the order required by their dependencies. This method
* is invoked once, at application startup, with any subsequent attempts
* to invoke this method throwing a logic_error.
*/
virtual void initialiseModules() = 0;
/**
* All the RegisterableModule::shutdownModule() routines are getting
* called one by one. No modules are actually destroyed during the
* iteration is ongoing, so each module is guaranteed to exist.
*
* After the last shutdownModule() call has been invoked, the modules
* can be safely unloaded/destroyed.
*/
virtual void shutdownModules() = 0;
/**
* Retrieve the module associated with the provided unique name. If the
* named module is not found, an empty RegisterableModulePtr is returned
* (this allows modules to be optional).
*
* Note that the return value of this function is RegisterableModulePtr,
* which in itself is useless to application code. It is up to the accessor
* functions defined in each module interface (e.g. GlobalEntityCreator())
* to downcast the pointer to the appropriate type.
*/
virtual RegisterableModulePtr getModule(const std::string& name) const = 0;
/**
* Returns TRUE if the named module exists in the records.
*/
virtual bool moduleExists(const std::string& name) const = 0;
/**
* This retrieves a reference to the information structure ApplicationContext,
* which holds the AppPath, SettingsPath and references to the application
* streams. The latter can be used by modules to initialise their
* rMessage/globalErrorStreams().
*/
virtual const ApplicationContext& getApplicationContext() const = 0;
/**
* Invoked when all modules have been initialised.
*/
virtual sigc::signal<void> signal_allModulesInitialised() const = 0;
/**
* Invoked when all modules have been shut down (i.e. after shutdownModule()).
*/
virtual sigc::signal<void> signal_allModulesUninitialised() const = 0;
};
namespace module {
/**
* \namespace module
* Types and functions implementing the module registry system.
*
* \ingroup module
*/
/** greebo: This is a container holding a reference to the registry.
* The getRegistry() symbol above is not exported to the
* modules in Win32 compiles. That's why this structure
* has to be initialised in the RegisterModule() routine.
*
* As soon as it's initialised, the module can access the ModuleRegistry
* with the routine GlobalModuleRegistry() below.
*/
class RegistryReference {
IModuleRegistry* _registry;
public:
RegistryReference() :
_registry(NULL)
{}
inline void setRegistry(IModuleRegistry& registry) {
_registry = ®istry;
}
inline IModuleRegistry& getRegistry() {
assert(_registry); // must not be NULL
return *_registry;
}
static RegistryReference& Instance() {
static RegistryReference _registryRef;
return _registryRef;
}
};
/**
* Global accessor method for the ModuleRegistry.
*/
inline IModuleRegistry& GlobalModuleRegistry() {
return RegistryReference::Instance().getRegistry();
}
}
// Platform-specific definition which needs to be defined both
// in the plugins and the main binary.
#if defined(WIN32)
#if defined(_MSC_VER)
// In VC++ we use this to export symbols instead of using .def files
// Note: don't use __stdcall since this is adding stack bytes to the function name
#define DARKRADIANT_DLLEXPORT __declspec(dllexport)
#else
#define DARKRADIANT_DLLEXPORT
#endif
#elif defined(__APPLE__)
#define DARKRADIANT_DLLEXPORT __attribute__((visibility("default")))
#else
#define DARKRADIANT_DLLEXPORT
#endif