/
dd_init.cpp
218 lines (186 loc) · 6.74 KB
/
dd_init.cpp
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
/**
* @file dd_init.cpp
* Application entrypoint. @ingroup base
*
* @authors Copyright © 2012 Jaakko Keränen <jaakko.keranen@iki.fi>
* @authors Copyright © 2012 Daniel Swanson <danij@dengine.net>
*
* @par License
* GPL: http://www.gnu.org/licenses/gpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details. You should have received a copy of the GNU
* General Public License along with this program; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA</small>
*/
/**
* @page mainFlow Engine Control Flow
*
* The main Qt application instance is de::App, which is a slightly modified
* version of the normal QApplication: it catches stray exceptions and forces a
* clean shutdown of the application.
*
* LegacyCore is a thin wrapper around de::App that manages the event loop in a
* way that is compatible with the legacy C implementation. The LegacyCore
* instance is created in the main() function and is globally available
* throughout the libdeng implementation as de2LegacyCore.
*
* The application's event loop is started as soon as the main window has been
* created (but not shown yet). After the window appears with a fully
* functional OpenGL drawing surface, the rest of the engine initialization is
* completed. This is done via a callback in the Canvas class that gets called
* when the window actually appears on screen (with empty contents).
*
* While the event loop is running, it periodically calls the loop callback
* function that has been set via LegacyCore. Initially it is used for showing
* the main window while the loop is already running
* (continueInitWithEventLoopRunning()) after which it switches to the engine's
* main loop callback (DD_GameLoopCallback()).
*
* During startup the engine goes through a series of busy tasks. While a busy
* task is running, the event loop started in LegacyCore is blocked. However,
* BusyTask starts another loop that continues to handle events received by the
* application, including making calls to the loop callback function. Busy mode
* uses its own loop callback function that monitors the progress of the busy
* worker and keeps updating the busy mode progress indicator on screen. After
* busy mode ends, the main loop callback is restored.
*
* The rate at which the main loop calls the loop callback can be configured
* via LegacyCore.
*/
#include <QApplication>
#include <QAction>
#include <QMenuBar>
#include <QNetworkProxyFactory>
#include <QDebug>
#include <stdlib.h>
#include <de/App>
#include <de/Log>
#include <de/Error>
#include <de/c_wrapper.h>
#include <de/garbage.h>
#include "de_platform.h"
#include "dd_loop.h"
#include "con_main.h"
#include "ui/window.h"
#include "ui/displaymode.h"
#include "updater.h"
#include "sys_system.h"
extern "C" {
/// @todo Refactor this away.
uint mainWindowIdx; // Main window index.
boolean DD_Init(void);
#if WIN32
# include "dd_winit.h"
#elif UNIX
# include "dd_uinit.h"
#endif
/**
* libdeng2 application core.
*/
static LegacyCore* de2LegacyCore;
}
static void continueInitWithEventLoopRunning(void)
{
// This function only needs to be called once, so clear the callback.
LegacyCore_SetLoopFunc(0);
// Show the main window. This causes initialization to finish (in busy mode)
// as the canvas is visible and ready for initialization.
Window_Show(Window_Main(), true);
}
static void handleLegacyCoreTerminate(const char* msg)
{
Con_Error("Application terminated due to exception:\n%s\n", msg);
}
/**
* Application entry point.
*/
int main(int argc, char** argv)
{
#ifdef Q_WS_X11
// Autodetect non-graphical mode on X11.
bool useGUI = (getenv("DISPLAY") != 0);
#else
bool useGUI = true;
#endif
// Are we running in novideo mode?
for(int i = 1; i < argc; ++i)
{
if(!stricmp(argv[i], "-novideo") || !stricmp(argv[i], "-dedicated"))
{
// Console mode.
useGUI = false;
}
}
QMenuBar* menuBar = 0;
// Application core.
de::App dengApp(argc, argv, useGUI? de::App::GUIEnabled : de::App::GUIDisabled);
try
{
// Override the system locale (affects number/time formatting).
QLocale::setDefault(QLocale("en_US.UTF-8"));
// Use the host system's proxy configuration.
QNetworkProxyFactory::setUseSystemConfiguration(true);
// Metadata.
QApplication::setOrganizationDomain("dengine.net");
QApplication::setOrganizationName("Deng Team");
QApplication::setApplicationName("Doomsday Engine");
QApplication::setApplicationVersion(DOOMSDAY_VERSION_BASE);
// C interface to the app.
de2LegacyCore = LegacyCore_New(&dengApp);
LegacyCore_SetTerminateFunc(handleLegacyCoreTerminate);
if(useGUI)
{
// Config needs DisplayMode, so let's initialize it before the configuration.
DisplayMode_Init();
/**
* @todo DisplayMode should be moved under de::App's ownership, so
* this is handled automatically.
*/
}
dengApp.initSubsystems();
Libdeng_Init();
if(useGUI)
{
// Check for updates automatically.
Updater_Init();
#ifdef MACOSX
// Set up the application-wide menu.
menuBar = new QMenuBar;
QMenu* gameMenu = menuBar->addMenu("&Game");
QAction* checkForUpdates = gameMenu->addAction("Check For &Updates...", Updater_Instance(),
SLOT(checkNowShowingProgress()));
checkForUpdates->setMenuRole(QAction::ApplicationSpecificRole);
#endif
}
// Initialize.
#if WIN32
if(!DD_Win32_Init()) return 1;
#elif UNIX
if(!DD_Unix_Init()) return 1;
#endif
// Create the main window.
char title[256];
DD_ComposeMainWindowTitle(title);
Window_New(novideo? WT_CONSOLE : WT_NORMAL, title);
LegacyCore_SetLoopFunc(continueInitWithEventLoopRunning);
}
catch(const de::Error& er)
{
qFatal("App init failed: %s", er.asText().toLatin1().constData());
}
// Run the main loop.
int result = DD_GameLoop();
// Cleanup.
Sys_Shutdown();
DD_Shutdown();
LegacyCore_Delete(de2LegacyCore);
delete menuBar;
return result;
}