| 1 |
// Written in the D programming language. |
|---|
| 2 |
/* MinWin Application structure |
|---|
| 3 |
* |
|---|
| 4 |
* An Application encapsulates the global state provided by |
|---|
| 5 |
* the OS when starting the application and it manages the event queue. |
|---|
| 6 |
* |
|---|
| 7 |
* Written by Ben Hinkle and released to the public domain, as |
|---|
| 8 |
* explained at http://creativecommons.org/licenses/publicdomain |
|---|
| 9 |
* Report comments and bugs at dsource: http://www.dsource.org/projects/minwin |
|---|
| 10 |
*/ |
|---|
| 11 |
|
|---|
| 12 |
module minwin.app; |
|---|
| 13 |
|
|---|
| 14 |
private { |
|---|
| 15 |
import minwin.logging; |
|---|
| 16 |
import minwin.multidg; |
|---|
| 17 |
import minwin.event; |
|---|
| 18 |
import std.string; |
|---|
| 19 |
} |
|---|
| 20 |
|
|---|
| 21 |
version(MinWin32) { |
|---|
| 22 |
private import minwin.mswindows; |
|---|
| 23 |
} |
|---|
| 24 |
|
|---|
| 25 |
extern (C) void gc_init(); |
|---|
| 26 |
extern (C) void gc_term(); |
|---|
| 27 |
extern (C) void _minit(); |
|---|
| 28 |
extern (C) void _moduleCtor(); |
|---|
| 29 |
extern (C) void _moduleUnitTests(); |
|---|
| 30 |
extern (C) int MinWinMain(Application* app); |
|---|
| 31 |
|
|---|
| 32 |
const int NO_ID = -1; |
|---|
| 33 |
class MinWinException : Exception { |
|---|
| 34 |
int id = NO_ID; |
|---|
| 35 |
this(char[] msg) { |
|---|
| 36 |
super(msg); |
|---|
| 37 |
} |
|---|
| 38 |
this(char[] msg, int id) { |
|---|
| 39 |
this.id = id; |
|---|
| 40 |
if (id == NO_ID) |
|---|
| 41 |
super(msg); |
|---|
| 42 |
else |
|---|
| 43 |
super(format("%s (error code %x)",msg,id)); |
|---|
| 44 |
} |
|---|
| 45 |
} |
|---|
| 46 |
|
|---|
| 47 |
// Assert a condition is true and if not throw an exception. |
|---|
| 48 |
void sysAssert(bool passed, char[] msg, int id = 0) { |
|---|
| 49 |
if (!passed) { |
|---|
| 50 |
version (MinWin32) { |
|---|
| 51 |
if (GetVersion() < 0x80_00_00_00 || id != 0) { |
|---|
| 52 |
throw new MinWinException(msg,id); |
|---|
| 53 |
} else { |
|---|
| 54 |
throw new MinWinException(msg,GetLastError()); |
|---|
| 55 |
} |
|---|
| 56 |
} else { |
|---|
| 57 |
throw new MinWinException(msg,id); |
|---|
| 58 |
} |
|---|
| 59 |
} |
|---|
| 60 |
} |
|---|
| 61 |
|
|---|
| 62 |
Application gApp; |
|---|
| 63 |
|
|---|
| 64 |
version (MinWin32) { |
|---|
| 65 |
|
|---|
| 66 |
extern (Windows) |
|---|
| 67 |
void MinWinIdleProc(HWND hWnd, uint msg, uint id, DWORD time) { |
|---|
| 68 |
gApp.idleDelegate(); |
|---|
| 69 |
} |
|---|
| 70 |
|
|---|
| 71 |
struct Application { |
|---|
| 72 |
|
|---|
| 73 |
char[] rsrc(char[] id, char[] group = "strings") { |
|---|
| 74 |
wchar[] wres; |
|---|
| 75 |
char[] cres; |
|---|
| 76 |
if (useWfuncs) |
|---|
| 77 |
wres.length = 64; |
|---|
| 78 |
else |
|---|
| 79 |
cres.length = 64; |
|---|
| 80 |
int len; |
|---|
| 81 |
for (;;) { |
|---|
| 82 |
if (useWfuncs) { |
|---|
| 83 |
len = cast(int)LoadStringW(gApp.hInstance,toUTF16z(id),wres.ptr,wres.length); |
|---|
| 84 |
if (len < wres.length) break; |
|---|
| 85 |
else wres.length = 2*wres.length; |
|---|
| 86 |
} |
|---|
| 87 |
else { |
|---|
| 88 |
len = cast(int)LoadStringA(gApp.hInstance,toMBSz(id),cres.ptr,cres.length); |
|---|
| 89 |
if (len < cres.length) break; |
|---|
| 90 |
else cres.length = 2*cres.length; |
|---|
| 91 |
} |
|---|
| 92 |
} |
|---|
| 93 |
if (useWfuncs) |
|---|
| 94 |
return toUTF8(wres[0..len]); |
|---|
| 95 |
else { |
|---|
| 96 |
return fromMBSz(cres[0..len].ptr); |
|---|
| 97 |
} |
|---|
| 98 |
} |
|---|
| 99 |
|
|---|
| 100 |
char[][] cmdLineArgs(){ |
|---|
| 101 |
// TODO: parse cmd line args |
|---|
| 102 |
return parsedCmdLineArgs; |
|---|
| 103 |
} |
|---|
| 104 |
|
|---|
| 105 |
MultiDelegate!() idleDelegate; |
|---|
| 106 |
|
|---|
| 107 |
private uint fTimerID; |
|---|
| 108 |
private uint fIdleTime; |
|---|
| 109 |
uint idleTime() { |
|---|
| 110 |
return fIdleTime; |
|---|
| 111 |
} |
|---|
| 112 |
void idleTime(uint t) { // time 0 means stop |
|---|
| 113 |
fIdleTime = t; |
|---|
| 114 |
if (fTimerID) { |
|---|
| 115 |
BOOL ok = KillTimer(null,fTimerID); |
|---|
| 116 |
sysAssert(ok != false, "Failed to kill existing timer"); |
|---|
| 117 |
} |
|---|
| 118 |
if (t) { |
|---|
| 119 |
fTimerID = SetTimer(null,0,t,&MinWinIdleProc); |
|---|
| 120 |
sysAssert(fTimerID != 0, "Failed to set timer"); |
|---|
| 121 |
} |
|---|
| 122 |
} |
|---|
| 123 |
|
|---|
| 124 |
int enterEventLoop() { |
|---|
| 125 |
while (nextEvent(&event)) { |
|---|
| 126 |
// TODO: check IsDialogMessage |
|---|
| 127 |
dispatchEvent(&event); |
|---|
| 128 |
} |
|---|
| 129 |
return 1; |
|---|
| 130 |
} |
|---|
| 131 |
|
|---|
| 132 |
void exitEventLoop() { |
|---|
| 133 |
PostQuitMessage(0); |
|---|
| 134 |
} |
|---|
| 135 |
|
|---|
| 136 |
HINSTANCE hInstance; |
|---|
| 137 |
HINSTANCE hPrevInstance; |
|---|
| 138 |
LPSTR lpCmdLine; |
|---|
| 139 |
char[][] parsedCmdLineArgs; |
|---|
| 140 |
int nCmdShow; |
|---|
| 141 |
Event event; |
|---|
| 142 |
} |
|---|
| 143 |
|
|---|
| 144 |
extern (Windows) |
|---|
| 145 |
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { |
|---|
| 146 |
/*{ |
|---|
| 147 |
INITCOMMONCONTROLSEX icc; |
|---|
| 148 |
icc.dwSize = INITCOMMONCONTROLSEX.sizeof; |
|---|
| 149 |
icc.dwICC = ICC_WIN95_CLASSES; |
|---|
| 150 |
InitCommonControlsEx(&icc); |
|---|
| 151 |
}*/ |
|---|
| 152 |
|
|---|
| 153 |
int result; |
|---|
| 154 |
gc_init(); // initialize garbage collector |
|---|
| 155 |
_minit(); // initialize module constructor table |
|---|
| 156 |
|
|---|
| 157 |
try |
|---|
| 158 |
{ |
|---|
| 159 |
_moduleCtor(); // call module constructors |
|---|
| 160 |
_moduleUnitTests(); // run unit tests (optional) |
|---|
| 161 |
|
|---|
| 162 |
gApp.hInstance = hInstance; |
|---|
| 163 |
gApp.hPrevInstance = hPrevInstance; |
|---|
| 164 |
gApp.nCmdShow = nCmdShow; |
|---|
| 165 |
version (LOG) log.writefln("about to enter MinWinMain"); |
|---|
| 166 |
result = MinWinMain(&gApp); |
|---|
| 167 |
version (LOG) log.writefln("done with MinWinMain"); |
|---|
| 168 |
} |
|---|
| 169 |
|
|---|
| 170 |
catch (Object o) // catch any uncaught exceptions |
|---|
| 171 |
{ |
|---|
| 172 |
MessageBoxX(null, o.toString(), "Error",MB_OK | MB_ICONEXCLAMATION); |
|---|
| 173 |
result = 0; // failed |
|---|
| 174 |
} |
|---|
| 175 |
version(LOG) log.close(); |
|---|
| 176 |
if (gApp.fTimerID) { |
|---|
| 177 |
BOOL ok = KillTimer(null,gApp.fTimerID); |
|---|
| 178 |
sysAssert(ok != false, "Failed to kill existing timer at exit"); |
|---|
| 179 |
} |
|---|
| 180 |
gc_term(); // run finalizers; terminate garbage collector |
|---|
| 181 |
return result; |
|---|
| 182 |
} |
|---|
| 183 |
|
|---|
| 184 |
} else version (GTK) { |
|---|
| 185 |
|
|---|
| 186 |
private { |
|---|
| 187 |
import minwin.gtk; |
|---|
| 188 |
import std.string; |
|---|
| 189 |
import std.file; |
|---|
| 190 |
} |
|---|
| 191 |
|
|---|
| 192 |
extern (C) |
|---|
| 193 |
gboolean MinWinIdleProc(gpointer data) { |
|---|
| 194 |
gApp.idleDelegate(); |
|---|
| 195 |
return true; |
|---|
| 196 |
} |
|---|
| 197 |
|
|---|
| 198 |
struct Application { |
|---|
| 199 |
|
|---|
| 200 |
char[][] cmdLineArgs; |
|---|
| 201 |
|
|---|
| 202 |
char[] rsrc(char[] id, char[] group = "strings") { |
|---|
| 203 |
// TODO |
|---|
| 204 |
return ""; |
|---|
| 205 |
} |
|---|
| 206 |
|
|---|
| 207 |
char[] resourcePath; |
|---|
| 208 |
|
|---|
| 209 |
int enterEventLoop() { |
|---|
| 210 |
gtk_main(); |
|---|
| 211 |
return 1; |
|---|
| 212 |
} |
|---|
| 213 |
|
|---|
| 214 |
void exitEventLoop() { |
|---|
| 215 |
gtk_main_quit(); |
|---|
| 216 |
} |
|---|
| 217 |
|
|---|
| 218 |
MultiDelegate!() idleDelegate; |
|---|
| 219 |
uint fIdleTime; |
|---|
| 220 |
uint idleTime() { |
|---|
| 221 |
return fIdleTime; |
|---|
| 222 |
} |
|---|
| 223 |
|
|---|
| 224 |
guint fTimerID; |
|---|
| 225 |
|
|---|
| 226 |
static |
|---|
| 227 |
void idleTime(uint t) { |
|---|
| 228 |
gApp.fIdleTime = t; |
|---|
| 229 |
if (gApp.fTimerID) |
|---|
| 230 |
g_source_remove(gApp.fTimerID); |
|---|
| 231 |
if (t) |
|---|
| 232 |
gApp.fTimerID = g_timeout_add(t,&MinWinIdleProc,null); |
|---|
| 233 |
} |
|---|
| 234 |
} |
|---|
| 235 |
|
|---|
| 236 |
int main(char[][] args) { |
|---|
| 237 |
gApp.cmdLineArgs = args; |
|---|
| 238 |
|
|---|
| 239 |
char*[] argv; |
|---|
| 240 |
argv.length = args.length; |
|---|
| 241 |
foreach (int n, char[] str; args) { |
|---|
| 242 |
argv[n] = toStringz(str); |
|---|
| 243 |
} |
|---|
| 244 |
int argc = args.length; |
|---|
| 245 |
char**argvp = argv.ptr; |
|---|
| 246 |
gtk_init(&argc,&argvp); |
|---|
| 247 |
|
|---|
| 248 |
int res = MinWinMain(&gApp); |
|---|
| 249 |
version(LOG) log.close(); |
|---|
| 250 |
return res; |
|---|
| 251 |
} |
|---|
| 252 |
} |
|---|