Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mRemoteNG/PuTTYNG.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'windows/utils/shinydialogbox.c')
-rw-r--r--windows/utils/shinydialogbox.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/windows/utils/shinydialogbox.c b/windows/utils/shinydialogbox.c
new file mode 100644
index 00000000..ab3201c1
--- /dev/null
+++ b/windows/utils/shinydialogbox.c
@@ -0,0 +1,111 @@
+/*
+ * PuTTY's own reimplementation of DialogBox() and EndDialog() which
+ * provide extra capabilities.
+ *
+ * Originally introduced in 2003 to work around a problem with our
+ * message loops, in which keystrokes pressed in the 'Change Settings'
+ * dialog in mid-session would _also_ be delivered to the main
+ * terminal window.
+ *
+ * But once we had our own wrapper it was convenient to put further
+ * things into it. In particular, this system allows you to provide a
+ * context pointer at setup time that's easy to retrieve from the
+ * window procedure.
+ */
+
+#include "putty.h"
+
+struct ShinyDialogBoxState {
+ bool ended;
+ int result;
+ ShinyDlgProc proc;
+ void *ctx;
+};
+
+/*
+ * For use in re-entrant calls to the dialog procedure from
+ * CreateDialog itself, temporarily store the state pointer that we
+ * won't store in the usual window-memory slot until later.
+ *
+ * I don't _intend_ that this system will need to be used in multiple
+ * threads at all, let alone concurrently, but just in case, declaring
+ * sdb_tempstate as thread-local will protect against that possibility.
+ */
+static THREADLOCAL struct ShinyDialogBoxState *sdb_tempstate;
+
+static inline struct ShinyDialogBoxState *ShinyDialogGetState(HWND hwnd)
+{
+ if (sdb_tempstate)
+ return sdb_tempstate;
+ return (struct ShinyDialogBoxState *)GetWindowLongPtr(
+ hwnd, DLGWINDOWEXTRA);
+}
+
+static INT_PTR CALLBACK ShinyRealDlgProc(HWND hwnd, UINT msg,
+ WPARAM wParam, LPARAM lParam)
+{
+ struct ShinyDialogBoxState *state = ShinyDialogGetState(hwnd);
+ return state->proc(hwnd, msg, wParam, lParam, state->ctx);
+}
+
+int ShinyDialogBox(HINSTANCE hinst, LPCTSTR tmpl, const char *winclass,
+ HWND hwndparent, ShinyDlgProc proc, void *ctx)
+{
+ /*
+ * Register the window class ourselves in such a way that we
+ * allocate an extra word of window memory to store the state
+ * pointer.
+ *
+ * It would be nice in principle to load the dialog template
+ * resource and dig the class name out of it. But DLGTEMPLATEEX is
+ * a nasty variable-layout structure not declared conveniently in
+ * a header file, so I think that's too much effort. Callers of
+ * this function will just have to provide the right window class
+ * name to match their template resource via the 'winclass'
+ * parameter.
+ */
+ WNDCLASS wc;
+ wc.style = CS_DBLCLKS | CS_SAVEBITS | CS_BYTEALIGNWINDOW;
+ wc.lpfnWndProc = DefDlgProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = DLGWINDOWEXTRA + sizeof(LONG_PTR);
+ wc.hInstance = hinst;
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH) (COLOR_BACKGROUND +1);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = winclass;
+ RegisterClass(&wc);
+
+ struct ShinyDialogBoxState state[1];
+ state->ended = false;
+ state->proc = proc;
+ state->ctx = ctx;
+
+ sdb_tempstate = state;
+ HWND hwnd = CreateDialog(hinst, tmpl, hwndparent, ShinyRealDlgProc);
+ SetWindowLongPtr(hwnd, DLGWINDOWEXTRA, (LONG_PTR)state);
+ sdb_tempstate = NULL;
+
+ MSG msg;
+ int gm;
+ while ((gm = GetMessage(&msg, NULL, 0, 0)) > 0) {
+ if (!state->ended && !IsDialogMessage(hwnd, &msg))
+ DispatchMessage(&msg);
+ if (state->ended)
+ break;
+ }
+
+ if (gm == 0)
+ PostQuitMessage(msg.wParam); /* We got a WM_QUIT, pass it on */
+
+ DestroyWindow(hwnd);
+ return state->result;
+}
+
+void ShinyEndDialog(HWND hwnd, int ret)
+{
+ struct ShinyDialogBoxState *state = ShinyDialogGetState(hwnd);
+ state->result = ret;
+ state->ended = true;
+}