summaryrefslogtreecommitdiff
path: root/alf/alftoplevel.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'alf/alftoplevel.cpp')
-rw-r--r--alf/alftoplevel.cpp148
1 files changed, 143 insertions, 5 deletions
diff --git a/alf/alftoplevel.cpp b/alf/alftoplevel.cpp
index 161a738..b9f2e7b 100644
--- a/alf/alftoplevel.cpp
+++ b/alf/alftoplevel.cpp
@@ -3,8 +3,11 @@
#define ALF_TOPLEVEL_FLAG_MODALEND ((DWORD)1)
typedef struct {
+ HWND hwnd;
ALFToplevelVTable *vtbl;
void *closure;
+ ALFListHeader toplevelList;
+ ALFApplication *app;
DWORD flags;
LPARAM modalResult;
ALFLayout layout;
@@ -12,9 +15,17 @@ typedef struct {
HFONT hMessageFont;
} ALFToplevelPriv;
+struct tagALFApplication {
+ ALFListHeader toplevelList;
+ ALFToplevelPriv *activeToplevel;
+ BOOL (*pretranslatemessage)(void *,MSG *);
+ void *pretranslatemessage_closure;
+};
+
struct ALFToplevel_CreateParams{
ALFToplevelVTable *vtbl;
void *closure;
+ ALFApplication *app;
};
static TCHAR _alf_toplevelClass[28] = {0};
@@ -22,8 +33,8 @@ static TCHAR _alf_toplevelClass[28] = {0};
static void
ALF_InitializeToplevelPriv(HWND hwnd, ALFToplevelPriv *priv)
{
- (void)hwnd;
-
+ priv->hwnd = hwnd;
+ ALF_ListInit(&priv->toplevelList);
ALF_Layout_Init(&priv->layout);
priv->layout.bgcolor = ALF_COLOR_SYS(COLOR_BTNFACE);
}
@@ -34,6 +45,10 @@ ALF_DestroyToplevelPriv(ALFToplevelPriv *priv)
if (priv->vtbl && priv->vtbl->postdestroy)
priv->vtbl->postdestroy(priv->closure);
+ if (priv->app && priv->app->activeToplevel == priv)
+ priv->app->activeToplevel = NULL;
+
+ ALF_ListRemove(&priv->toplevelList);
ALF_Layout_Clear(&priv->layout);
if (priv->hMessageFont)
@@ -166,6 +181,11 @@ ALF_Toplevel_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
priv->vtbl = params->vtbl;
priv->closure = params->closure;
+ priv->app = params->app;
+
+ if (priv->app) {
+ ALF_ListInsert(&priv->app->toplevelList, &priv->toplevelList);
+ }
BOOL retval = TRUE;
if (priv->vtbl && priv->vtbl->initialize) {
@@ -195,6 +215,18 @@ ALF_Toplevel_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
return 0;
}
+ if (msg == WM_ACTIVATE) {
+ if (wparam) {
+ if (priv->app) {
+ priv->app->activeToplevel = priv;
+ }
+ } else {
+ if (priv->app && priv->app->activeToplevel == priv) {
+ priv->app->activeToplevel = NULL;
+ }
+ }
+ }
+
if (msg == WM_ERASEBKGND) {
return TRUE; // handled in WM_PAINT
}
@@ -350,6 +382,10 @@ ALF_Toplevel_DefWindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
}
}
+ if (msg == ALF_WM_GETAPPLICATION) {
+ return (LRESULT)priv->app;
+ }
+
LRESULT ret = 0;
if (ALF_Layout_HandleMessage(&priv->layout, hwnd, msg, wparam, lparam, &ret)) {
// if the layout was changed, our current size might be too small
@@ -397,7 +433,7 @@ ALF_UnregisterToplevelClass(void)
}
HWND
-ALF_CreateToplevelWindow(DWORD exstyle, DWORD style, HWND hwndOwner, ALFToplevelVTable *vtbl, void *closure)
+ALF_CreateToplevelWindow(DWORD exstyle, DWORD style, HWND hwndOwner, ALFApplication *app, ALFToplevelVTable *vtbl, void *closure)
{
#pragma pack(push, 1)
struct {
@@ -428,6 +464,7 @@ ALF_CreateToplevelWindow(DWORD exstyle, DWORD style, HWND hwndOwner, ALFToplevel
struct ALFToplevel_CreateParams params;
params.vtbl = vtbl;
params.closure = closure;
+ params.app = app;
return CreateDialogIndirectParam(ALF_HINSTANCE, &t.t, hwndOwner, ALF_Toplevel_DlgProc, (LPARAM)&params);
}
@@ -456,8 +493,8 @@ ALF_Toplevel_ShowModal(HWND toplevel)
while (!(priv->flags & ALF_TOPLEVEL_FLAG_MODALEND)) {
MSG msg;
if (GetMessage(&msg, NULL, 0, 0)) {
- // TODO: call app-level message filter
- if (!ALF_Toplevel_PreTranslateMessage(toplevel, &msg)) {
+ if (!(priv->app && ALF_Application_PreTranslateMessage(priv->app, &msg, toplevel))
+ && !ALF_Toplevel_PreTranslateMessage(toplevel, &msg)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
@@ -518,3 +555,104 @@ ALF_Toplevel_ResizePx(HWND win, int pxwidth, int pxheight)
SetWindowPos(win, NULL, 0, 0, pxwidth, pxheight, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
}
+
+ALFApplication *
+ALF_Toplevel_Application(HWND toplevel)
+{
+ return (ALFApplication *)SendMessage(toplevel, ALF_WM_GETAPPLICATION, 0, 0);
+}
+
+ALFApplication *
+ALF_CreateApplication(void)
+{
+ ALFApplication *app = ALF_New(ALFApplication, 1);
+ ALF_ListInit(&app->toplevelList);
+
+ return app;
+}
+
+void
+ALF_Application_ProcessMessages(ALFApplication *app)
+{
+ MSG msg;
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
+ if (msg.message == WM_QUIT) {
+ PostQuitMessage((int)msg.wParam);
+ return;
+ } else {
+ if (!ALF_Application_PreTranslateMessage(app, &msg, NULL)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+}
+
+void
+ALF_Application_Run(ALFApplication *app)
+{
+ while (!ALF_ListIsEmpty(&app->toplevelList)) {
+ MSG msg;
+ if (GetMessage(&msg, NULL, 0, 0)) {
+ if (!ALF_Application_PreTranslateMessage(app, &msg, NULL)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ } else {
+ PostQuitMessage((int)msg.wParam);
+ return;
+ }
+ }
+}
+
+BOOL
+ALF_Application_EnumToplevels(ALFApplication *app, WNDENUMPROC proc, LPARAM param)
+{
+ ALF_FOR_LIST(ALFToplevelPriv, toplevelList, &app->toplevelList, t) {
+ if (!proc(t->hwnd, param))
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+HWND
+ALF_Application_ActiveToplevel(ALFApplication *app)
+{
+ return app->activeToplevel->hwnd;
+}
+
+void
+ALF_Application_SetPreTranslateMessageHandler(ALFApplication *app, BOOL(*handler)(void *,MSG *), void *closure)
+{
+ app->pretranslatemessage = handler;
+ app->pretranslatemessage_closure = closure;
+}
+
+BOOL
+ALF_Application_PreTranslateMessage(ALFApplication *app, MSG *msg, HWND modalToplevel)
+{
+ return (app->pretranslatemessage && app->pretranslatemessage(app->pretranslatemessage_closure, msg))
+ || (app->activeToplevel && app->activeToplevel->hwnd != modalToplevel && ALF_Toplevel_PreTranslateMessage(app->activeToplevel->hwnd, msg));
+}
+
+// TODO: implement modal stuff
+/*void
+ALF_Application_DisableWindowsForModal(ALFApplication *app, HWND skip);
+
+void
+ALF_Application_ReenableWindowsForModal(ALFApplication *app, HWND skip);*/
+
+void
+ALF_DestroyApplication(ALFApplication *app)
+{
+ // don't use ALF_FOR_LIST here, since ALF_FOR_LIST can only handle destroying
+ // the current element. But the window might to anything in WM_DESTROY,
+ // including destroying various other windows.
+ while (!ALF_ListIsEmpty(&app->toplevelList)) {
+ HWND w = ALF_LIST_CONTAINER(ALFToplevelPriv, toplevelList, app->toplevelList.next)->hwnd;
+ DestroyWindow(w);
+ }
+
+ ALF_Free(app);
+}