244 lines
6.3 KiB
D
244 lines
6.3 KiB
D
/* MinWin Application structure
|
|
*
|
|
* An Application encapsulates the global state provided by
|
|
* the OS when starting the application and it manages the event queue.
|
|
*
|
|
* Written by Ben Hinkle and released to the public domain, as
|
|
* explained at http://creativecommons.org/licenses/publicdomain
|
|
* Report comments and bugs at dsource: http://www.dsource.org/projects/minwin
|
|
*/
|
|
|
|
module minwin.app;
|
|
|
|
private {
|
|
import minwin.logging;
|
|
import minwin.multidg;
|
|
import minwin.event;
|
|
import std.string;
|
|
}
|
|
|
|
version(MinWin32) {
|
|
private import minwin.mswindows;
|
|
}
|
|
|
|
extern (C) void gc_init();
|
|
extern (C) void gc_term();
|
|
extern (C) void _minit();
|
|
extern (C) void _moduleCtor();
|
|
extern (C) void _moduleUnitTests();
|
|
extern (C) int MinWinMain(Application* app);
|
|
|
|
const int NO_ID = -1;
|
|
class MinWinException : Exception {
|
|
int id = NO_ID;
|
|
this(char[] msg) {
|
|
super(msg);
|
|
}
|
|
this(char[] msg, int id) {
|
|
this.id = id;
|
|
if (id == NO_ID)
|
|
super(msg);
|
|
else
|
|
super(format("%s (error code %x)",msg,id));
|
|
}
|
|
}
|
|
|
|
// Assert a condition is true and if not throw an exception.
|
|
void sysAssert(bool passed, char[] msg, int id = 0) {
|
|
if (!passed) {
|
|
version (MinWin32) {
|
|
if (GetVersion() < 0x80_00_00_00 || id != 0) {
|
|
throw new MinWinException(msg,id);
|
|
} else {
|
|
throw new MinWinException(msg,GetLastError());
|
|
}
|
|
} else {
|
|
throw new MinWinException(msg,id);
|
|
}
|
|
}
|
|
}
|
|
|
|
Application gApp;
|
|
|
|
version (MinWin32) {
|
|
|
|
extern (Windows)
|
|
void MinWinIdleProc(HWND hWnd, uint msg, uint id, DWORD time) {
|
|
gApp.idleDelegate();
|
|
}
|
|
|
|
struct Application {
|
|
|
|
char[] rsrc(char[] id, char[] group = "strings") {
|
|
wchar[] wres;
|
|
char[] cres;
|
|
if (useWfuncs)
|
|
wres.length = 64;
|
|
else
|
|
cres.length = 64;
|
|
int len;
|
|
for (;;) {
|
|
if (useWfuncs) {
|
|
len = cast(int)LoadStringW(gApp.hInstance,toUTF16z(id),wres.ptr,wres.length);
|
|
if (len < wres.length) break;
|
|
else wres.length = 2*wres.length;
|
|
}
|
|
else {
|
|
len = cast(int)LoadStringA(gApp.hInstance,toMBSz(id),cres.ptr,cres.length);
|
|
if (len < cres.length) break;
|
|
else cres.length = 2*cres.length;
|
|
}
|
|
}
|
|
if (useWfuncs)
|
|
return toUTF8(wres[0..len]);
|
|
else {
|
|
return fromMBSz(cres[0..len].ptr);
|
|
}
|
|
}
|
|
|
|
char[][] cmdLineArgs(){
|
|
// TODO: parse cmd line args
|
|
return parsedCmdLineArgs;
|
|
}
|
|
|
|
MultiDelegate!() idleDelegate;
|
|
|
|
private uint fTimerID;
|
|
private uint fIdleTime;
|
|
uint idleTime() {
|
|
return fIdleTime;
|
|
}
|
|
void idleTime(uint t) { // time 0 means stop
|
|
fIdleTime = t;
|
|
if (fTimerID) {
|
|
BOOL ok = KillTimer(null,fTimerID);
|
|
sysAssert(ok != false, "Failed to kill existing timer");
|
|
}
|
|
if (t) {
|
|
fTimerID = SetTimer(null,0,t,&MinWinIdleProc);
|
|
sysAssert(fTimerID != 0, "Failed to set timer");
|
|
}
|
|
}
|
|
|
|
int enterEventLoop() {
|
|
while (nextEvent(&event)) {
|
|
// TODO: check IsDialogMessage
|
|
dispatchEvent(&event);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
void exitEventLoop() {
|
|
PostQuitMessage(0);
|
|
}
|
|
|
|
HINSTANCE hInstance;
|
|
HINSTANCE hPrevInstance;
|
|
LPSTR lpCmdLine;
|
|
char[][] parsedCmdLineArgs;
|
|
int nCmdShow;
|
|
Event event;
|
|
}
|
|
|
|
extern (Windows)
|
|
int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
|
int result;
|
|
gc_init(); // initialize garbage collector
|
|
_minit(); // initialize module constructor table
|
|
|
|
try
|
|
{
|
|
_moduleCtor(); // call module constructors
|
|
_moduleUnitTests(); // run unit tests (optional)
|
|
|
|
gApp.hInstance = hInstance;
|
|
gApp.hPrevInstance = hPrevInstance;
|
|
gApp.nCmdShow = nCmdShow;
|
|
version (LOG) log.writefln("about to enter MinWinMain");
|
|
result = MinWinMain(&gApp);
|
|
version (LOG) log.writefln("done with MinWinMain");
|
|
}
|
|
|
|
catch (Object o) // catch any uncaught exceptions
|
|
{
|
|
MessageBoxX(null, o.toString(), "Error",MB_OK | MB_ICONEXCLAMATION);
|
|
result = 0; // failed
|
|
}
|
|
version(LOG) log.close();
|
|
if (gApp.fTimerID) {
|
|
BOOL ok = KillTimer(null,gApp.fTimerID);
|
|
sysAssert(ok != false, "Failed to kill existing timer at exit");
|
|
}
|
|
gc_term(); // run finalizers; terminate garbage collector
|
|
return result;
|
|
}
|
|
|
|
} else version (GTK) {
|
|
|
|
private {
|
|
import minwin.gtk;
|
|
import std.string;
|
|
import std.file;
|
|
}
|
|
|
|
extern (C)
|
|
gboolean MinWinIdleProc(gpointer data) {
|
|
gApp.idleDelegate();
|
|
return true;
|
|
}
|
|
|
|
struct Application {
|
|
|
|
char[][] cmdLineArgs;
|
|
|
|
char[] rsrc(char[] id, char[] group = "strings") {
|
|
// TODO
|
|
return "";
|
|
}
|
|
|
|
char[] resourcePath;
|
|
|
|
int enterEventLoop() {
|
|
gtk_main();
|
|
return 1;
|
|
}
|
|
|
|
void exitEventLoop() {
|
|
gtk_main_quit();
|
|
}
|
|
|
|
MultiDelegate!() idleDelegate;
|
|
uint fIdleTime;
|
|
uint idleTime() {
|
|
return fIdleTime;
|
|
}
|
|
|
|
guint fTimerID;
|
|
|
|
static
|
|
void idleTime(uint t) {
|
|
gApp.fIdleTime = t;
|
|
if (gApp.fTimerID)
|
|
g_source_remove(gApp.fTimerID);
|
|
if (t)
|
|
gApp.fTimerID = g_timeout_add(t,&MinWinIdleProc,null);
|
|
}
|
|
}
|
|
|
|
int main(char[][] args) {
|
|
gApp.cmdLineArgs = args;
|
|
|
|
char*[] argv;
|
|
argv.length = args.length;
|
|
foreach (int n, char[] str; args) {
|
|
argv[n] = toStringz(str);
|
|
}
|
|
int argc = args.length;
|
|
char**argvp = argv.ptr;
|
|
gtk_init(&argc,&argvp);
|
|
|
|
int res = MinWinMain(&gApp);
|
|
version(LOG) log.close();
|
|
return res;
|
|
}
|
|
}
|