Add a progress dialog during Connect()

- The dialog supports retry and cancel and shows
  a progress marquee

Signed-off-by: Selva Nair <selva.nair@gmail.com
pull/529/head
Selva Nair 2022-08-06 18:05:43 -04:00
parent e64b18074f
commit ed0ceeb95b
3 changed files with 132 additions and 15 deletions

View File

@ -50,6 +50,8 @@ struct OpenVPNConnection
#define ISDISCONNECTED(c) (ConnectionState(c) == state_disconnected)
#define ISONHOLD(c) (ConnectionState(c) == state_onhold)
extern DWORD status_menu_id;
/* Methods in IConnectableCredentialProviderCredential that we need to define */
/* IUnknown */
@ -528,6 +530,64 @@ NotifyEvents(OpenVPNConnection *oc, const wchar_t *status)
}
}
static HRESULT WINAPI
ProgressCallback(HWND hwnd, UINT msg, WPARAM wParam, UNUSED LPARAM lParam, LONG_PTR ref_data)
{
assert(ref_data);
OpenVPNConnection *oc = (OpenVPNConnection *) ref_data;
connection_t *c = oc->c;
IQueryContinueWithStatus *qc = oc->qc;
assert(qc);
HRESULT hr = S_FALSE;
WCHAR status[256] = L"";
if (msg == TDN_BUTTON_CLICKED && wParam == IDCANCEL)
{
dmsg(L"wParam=IDCANCEL -- returning S_OK");
hr = S_OK; /* this will cause the progress dialog to close */
}
else if (ISCONNECTED(c) || ISDISCONNECTED(c) || (qc->lpVtbl->QueryContinue(qc) != S_OK))
{
/* this will trigger IDCANCEL */
PostMessageW(hwnd, WM_CLOSE, 0, 0);
dmsg(L"profile = %ls, closing progress dialog", oc->display_name);
hr = S_OK;
}
else if (ISONHOLD(c)) /* Try to connect again */
{
ConnectHelper(c);
}
else if (!ISCONNECTED(c) && msg == TDN_BUTTON_CLICKED && wParam == status_menu_id)
{
dmsg(L"wParam = status_menu_id -- showing status window");
ShowStatusWindow(c, TRUE);
}
else if (!ISCONNECTED(c) && msg == TDN_BUTTON_CLICKED && wParam == IDRETRY)
{
dmsg(L"wParam = IDRETRY -- closing progress dialog for restart");
hr = S_OK;
}
if (msg == TDN_CREATED)
{
dmsg(L"starting progress bar marquee");
PostMessageW(hwnd, TDM_SET_PROGRESS_BAR_MARQUEE, 1, 0);
}
if (msg == TDN_TIMER)
{
GetConnectionStatusText(c, status, _countof(status));
NotifyEvents(oc, status);
SendMessageW(hwnd, TDM_UPDATE_ELEMENT_TEXT, TDE_CONTENT, (LPARAM) status);
dmsg(L"Connection status <%ls>", status);
}
return hr;
}
static HRESULT WINAPI
Connect(ICCPC *this, IQueryContinueWithStatus *qc)
{
@ -538,33 +598,41 @@ Connect(ICCPC *this, IQueryContinueWithStatus *qc)
oc->qc = qc;
NotifyEvents(oc, L"");
oc->connect_cancelled = FALSE;
SetActiveProfile(oc->c);
again:
oc->connect_cancelled = FALSE;
SetActiveProfile(oc->c); /* This enables UI dialogs to be shown for c */
ConnectHelper(oc->c);
Sleep(100);
while (!ISCONNECTED(oc->c) && !ISDISCONNECTED(oc->c))
/* if not immediately connected, show a progress dialog with
* service state changes and retry/cancel options. Progress dialog
* returns on error, cancel or when connected.
*/
if (!ISCONNECTED(oc->c) && !ISDISCONNECTED(oc->c))
{
ShowStatusWindow(oc->c, TRUE);
GetConnectionStatusText(oc->c, status, _countof(status));
NotifyEvents(oc, status);
if (qc->lpVtbl->QueryContinue(qc) != S_OK)
dmsg(L"Runninng progress dialog");
int res = RunProgressDialog(oc->c, ProgressCallback, (LONG_PTR) oc);
dmsg(L"Out of progress dialog with res = %d", res);
if (res == IDRETRY && !ISCONNECTED(oc->c))
{
wcsncpy_s(status, _countof(status), L"Current State: Retrying", _TRUNCATE);
NotifyEvents(oc, status);
DisconnectHelper(oc->c);
goto again;
}
else if (res == IDCANCEL && !ISCONNECTED(oc->c) && !ISDISCONNECTED(oc->c))
{
/* user wants to cancel */
wcsncpy_s(status, _countof(status), L"Current State: Cancelling", _TRUNCATE);
NotifyEvents(oc, status);
oc->connect_cancelled = TRUE;
DisconnectHelper(oc->c);
break;
oc->connect_cancelled = TRUE;
}
else if (ISONHOLD(oc->c))
{
ConnectHelper(oc->c);
}
Sleep(100);
}
GetConnectionStatusText(oc->c, status, _countof(status));

View File

@ -39,6 +39,7 @@
#include "openvpn-gui-res.h"
#include "localization.h"
#include "misc.h"
#include "tray.h"
/* Global options structure */
options_t o;
@ -47,6 +48,7 @@ int state_connected = connected, state_disconnected = disconnected,
state_onhold = onhold;
static connection_t *active_profile;
DWORD status_menu_id = IDM_STATUSMENU;
/* Override management handlers that generate user dialogs
* and pass them on only for currently active profile.
@ -477,3 +479,41 @@ SetActiveProfile(connection_t *c)
{
active_profile = c;
}
int
RunProgressDialog(connection_t *c, PFTASKDIALOGCALLBACK cb_fn, LONG_PTR cb_data)
{
dmsg(L"Entry with profile = <%ls>", c->config_name);
const TASKDIALOG_FLAGS flags = TDF_SHOW_MARQUEE_PROGRESS_BAR|TDF_CALLBACK_TIMER|TDF_USE_HICON_MAIN;
wchar_t main_text[256];
wchar_t details_btn_text[256];
_sntprintf_0(main_text, L"%ls %ls", LoadLocalizedString(IDS_MENU_CONNECT), c->config_name);
LoadLocalizedStringBuf(details_btn_text, _countof(main_text), IDS_MENU_STATUS);
const TASKDIALOG_BUTTON extra_buttons[] = {
{status_menu_id, details_btn_text},
};
const TASKDIALOGCONFIG taskcfg = {
.cbSize = sizeof(taskcfg),
.hwndParent = o.hWnd,
.hInstance = o.hInstance,
.dwFlags = flags,
.hMainIcon = LoadLocalizedIcon(ID_ICO_APP),
.cButtons = _countof(extra_buttons),
.pButtons = extra_buttons,
.dwCommonButtons = TDCBF_CANCEL_BUTTON|TDCBF_RETRY_BUTTON,
.pszWindowTitle = L""PACKAGE_NAME" PLAP",
.pszMainInstruction = main_text,
.pszContent = L"Starting", /* replaced on create */
.pfCallback = cb_fn,
.lpCallbackData = cb_data,
};
int button_clicked = 0;
dmsg(L"calling taskdialogindirect");
TaskDialogIndirect(&taskcfg, &button_clicked, NULL, NULL);
return button_clicked;
}

View File

@ -107,6 +107,15 @@ void DisconnectHelper(connection_t *c);
*/
void SetActiveProfile(connection_t *c);
/**
* A helper function to run a dialog showing progress of a connection process.
*
* @param c Connection to monitor
* @param cb_fn A callback function that is called back every 200 msec
* @param cb_data Data passed to the callback function
*/
int RunProgressDialog(connection_t *c, PFTASKDIALOGCALLBACK cb_fn, LONG_PTR cb_data);
#ifdef __cplusplus
}
#endif