//winmain.h winmain services
#pragma once
namespace GE_{ namespace win{
//some important Global stores
inline HINSTANCE& hInst() {static HINSTANCE h=NULL; return h; }
inline HWND& hMainWnd() {static HWND h=NULL; return h; }
//Messageloop for WinMain,
// instatiate on stach, an call "run('mainwindow')"
class Messageloop
{
private:
static Messageloop*& _mainloop() { static Messageloop* m= NULL; return m;}
LRESULT lastresult;
public:
static Messageloop& get() { return *_mainloop(); }
public:
struct idle_event_type: public stdx1::event_source {} idle_event;
struct message_event_type:
public stdx1::event_source
{
MSG* pmsg;
};
message_event_type message_event;
bool is_idlemessage(UINT msg)
{
// These messages should NOT cause idle processing
switch(msg)
{
case WM_NCMOUSEMOVE:
case WM_MOUSEMOVE:
case WM_PAINT:
case 0x0118: // WM_SYSTIMER (caret blink) [WTL suggestion ...]
return false;
}
return true;
}
LRESULT result() { return lastresult; }
//declares and initialize a Messageloop
Messageloop(HINSTANCE _hInst)
{
if(!_mainloop()) _mainloop() = this;
if(!hInst()) hInst() = _hInst;
lastresult = 0;
}
//the loop body
bool body()
{
//the message loop body
MSG msg;
if(GetMessage(&msg, 0, 0,0) == -1)
return false; //invalid call
if(msg.message == WM_QUIT)
{
idle_event.fire(idle_event); //just if having pendings ...
return false;
}
message_event.pmsg = &msg;
if(message_event.fire(message_event))
return true; //message filtered from outside
TranslateMessage(&msg);
lastresult = DispatchMessage(&msg);
if(!PeekMessage(&msg, 0, 0,0, PM_NOREMOVE) && is_idlemessage(msg.message))
idle_event.fire(idle_event);
return true;
}
//a externally controllable loop
bool loopwhile(bool& b)
{
while(b && body()) {}
return b;
}
//an only internally controlled loop
void run(HWND _hwnd)
{
if(!hMainWnd() && _hwnd) hMainWnd() = _hwnd;
bool b = true;
loopwhile(b);
}
};
//a RefcountableValue with destroy policy
template<class H, class DeletePolicy, H nullval=NULL>
class RefcountableW32Handle: public stdx1::RefcountableValue<H,nullval>
{
protected:
virtual void on_lastrelease() { DeletePolicy(*this); }
};
//Resource ID UINT and STRING converter
class ResID
{
private:
LPCTSTR resID;
public:
ResID() { resID = 0; }
ResID(LPCTSTR _resID) { resID = _resID; }
ResID(UINT _resID) { resID = MAKEINTRESOURCE(_resID); }
operator LPCTSTR() const { return resID; }
};
//WNDCLASS registrations helpers
class _WndClassEx:
public stdx1::HandableRefcounter<stdx1::RefcountableValue<ATOM> >
{
private:
HINSTANCE hRegInstance;
virtual void on_lastrelease()
{
UnregisterClass((LPCTSTR)(ATOM)*this, hRegInstance);
STRACE(trc, 3, ("Unregistered class with ATOM %x\n", (ATOM)*this));
}
public:
void Register(
HINSTANCE hInst,
LPCTSTR clsName,
ResID resID,
int nBkgSysColorIdx=COLOR_WINDOW,
WNDPROC pfnDefWndProc= DefWindowProc,
DWORD dwStyle = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS
)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = dwStyle;
wc.lpfnWndProc = pfnDefWndProc;
wc.cbClsExtra = wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = (HICON)LoadImage(wc.hInstance, resID, IMAGE_ICON, 0,0, LR_DEFAULTSIZE);
wc.hIconSm = (HICON)LoadImage(wc.hInstance, resID, IMAGE_ICON, 16,16, LR_DEFAULTCOLOR);
wc.hCursor = LoadCursor(wc.hInstance, resID); if(!wc.hCursor) wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (nBkgSysColorIdx==-1)? NULL: GetSysColorBrush(nBkgSysColorIdx);
wc.lpszMenuName = NULL;
wc.lpszClassName = clsName;
_set(RegisterClassEx(&wc));
STRACE(trc,3,("Registering class %s, ATOM %x\n", clsName, (ATOM)*this));
hRegInstance = hInst;
}
void Register(
HINSTANCE hInst,
LPCTSTR clsName, //the name for the class (will autogenerate)
HICON HIcon = (HICON)-1, //IDI_APPLICATION
HCURSOR HCursor = (HCURSOR)-1, //IDC_CURSOR
int nBkgSysColorIdx = COLOR_WINDOW, // the background brush index: -1 means no backround
WNDPROC pfnDefWndProc = DefWindowProc,// the window procedure to subclass: DefWndProc , DefDialogProc etc...
DWORD dwStyle = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS //class style
)
{
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = dwStyle;
wc.lpfnWndProc = pfnDefWndProc;
wc.cbClsExtra = wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = (HIcon==(HICON)-1)? LoadIcon(NULL, IDI_APPLICATION): HIcon;
wc.hIconSm = NULL;
wc.hCursor = (HCursor==(HCURSOR)-1)? LoadCursor(NULL, IDC_ARROW): HCursor;
wc.hbrBackground = (nBkgSysColorIdx==-1)? NULL: GetSysColorBrush(nBkgSysColorIdx);
wc.lpszMenuName = NULL;
wc.lpszClassName = clsName;
_set(RegisterClassEx(&wc));
STRACE(trc,3,("Registering class %s, ATOM %x\n", clsName, (ATOM)*this));
hRegInstance = hInst;
}
operator LPCTSTR() const { return (LPCTSTR)(ATOM)*this; }
};
typedef stdx1::Handle<_WndClassEx> Wndclassex;
//provides delayed delete to a derived object.
// deletion takes place on the next idle event fired by the message loop
class delete_onidle:
public stdx1::event_handler<Messageloop::idle_event_type>
{
private:
bool bDelete;
protected:
delete_onidle() { bDelete = false; }
virtual ~delete_onidle() {}
virtual bool on_event(const Messageloop::idle_event_type& ie, stdx1::event_source::state* pState)
{
pState->do_next();
if(bDelete)
{
delete this;
}
return true;
}
public:
void post_delete()
{
bDelete = true;
Hook(Messageloop::get().idle_event);
}
};
}}