summaryrefslogtreecommitdiff
path: root/test/source
diff options
context:
space:
mode:
authorColomban Wendling <cwendling@hypra.fr>2023-01-31 11:25:28 +0100
committerMichael Weghorn <m.weghorn@posteo.de>2023-03-03 10:57:11 +0000
commit655f6164e38c2f675beb5272fc6a9780f4767429 (patch)
tree583afce5ac496e805e4af0e00eac292ae3da32f1 /test/source
parent1791b26d75bd50971fe58627c6554f1711890817 (diff)
test: Run user dialog callback in idle time
On e.g. Windows we need to let the dialogs fully finish starting up before we can properly interact with them, and especially close them again. We notice new dialogs with the WindowActivate event, but this will happen before the dialog is fully set up internally, leading to failures on Windows. In practice, the WindowActivate event might be dispatched before the dialog setup function finishes, leading to an intermediate state at WindowActivate time. Work around this by running the user code in an idle timer in response to the WindowActivate event, so that the setup code can return before the callback is dispatched. Based on findings by Michael Weghorn, thanks! Change-Id: Ieecee09d84144570fe1943ca12dc1db6d9f64524 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146378 Tested-by: Jenkins Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
Diffstat (limited to 'test/source')
-rw-r--r--test/source/a11y/accessibletestbase.cxx43
1 files changed, 32 insertions, 11 deletions
diff --git a/test/source/a11y/accessibletestbase.cxx b/test/source/a11y/accessibletestbase.cxx
index 579d4ba2bfd4..bcfdcc89db1d 100644
--- a/test/source/a11y/accessibletestbase.cxx
+++ b/test/source/a11y/accessibletestbase.cxx
@@ -27,6 +27,7 @@
#include <com/sun/star/uno/RuntimeException.hpp>
#include <com/sun/star/util/XCloseable.hpp>
+#include <vcl/idle.hxx>
#include <vcl/scheduler.hxx>
#include <vcl/svapp.hxx>
#include <vcl/window.hxx>
@@ -393,6 +394,9 @@ test::AccessibleTestBase::awaitDialog(const std::u16string_view name,
std::function<void(Dialog&)> mCallback;
bool mbAutoClose;
Timer maTimeoutTimer;
+ Idle maIdleHandler;
+
+ std::unique_ptr<Dialog> mxDialog;
public:
virtual ~ListenerHelper()
@@ -400,6 +404,7 @@ test::AccessibleTestBase::awaitDialog(const std::u16string_view name,
Application::SetDialogCancelMode(miPreviousDialogCancelMode);
Application::RemoveEventListener(mLink);
maTimeoutTimer.Stop();
+ maIdleHandler.Stop();
}
ListenerHelper(const std::u16string_view& name, std::function<void(Dialog&)> callback,
@@ -409,6 +414,7 @@ test::AccessibleTestBase::awaitDialog(const std::u16string_view name,
, mCallback(callback)
, mbAutoClose(bAutoClose)
, maTimeoutTimer("workaround timer if we don't catch WindowActivate")
+ , maIdleHandler("runs user callback in idle time")
{
mLink = LINK(this, ListenerHelper, eventListener);
Application::AddEventListener(mLink);
@@ -417,6 +423,9 @@ test::AccessibleTestBase::awaitDialog(const std::u16string_view name,
maTimeoutTimer.SetTimeout(60000);
maTimeoutTimer.Start();
+ maIdleHandler.SetInvokeHandler(LINK(this, ListenerHelper, idleHandler));
+ maIdleHandler.SetPriority(TaskPriority::DEFAULT_IDLE);
+
miPreviousDialogCancelMode = Application::GetDialogCancelMode();
Application::SetDialogCancelMode(DialogCancelMode::Off);
}
@@ -458,42 +467,54 @@ test::AccessibleTestBase::awaitDialog(const std::u16string_view name,
if (!pWin->IsDialog())
return;
- mbWaitingForDialog = false;
-
// remove ourselves, we don't want to run again
Application::RemoveEventListener(mLink);
+
+ mxDialog = std::make_unique<Dialog>(pWin, true);
+
+ maIdleHandler.Start();
+ }
+
+ // mimic IMPL_LINK inline
+ static void LinkStubidleHandler(void* instance, Timer* idle)
+ {
+ static_cast<ListenerHelper*>(instance)->idleHandler(idle);
+ }
+
+ void idleHandler(Timer*)
+ {
+ mbWaitingForDialog = false;
+
maTimeoutTimer.ClearInvokeHandler();
maTimeoutTimer.Stop();
- /* bind the dialog before checking its name so auto-close can kick in if anything
- * fails/throws */
- Dialog dialog(pWin, true);
-
/* The popping up dialog ought to be the right one, or something's fishy and
* we're bound to failure (e.g. waiting on a dialog that either will never come, or
* that will not run after the current one -- deadlock style) */
- if (msName != pWin->GetText())
+ if (msName != mxDialog->getWindow()->GetText())
{
mpException = std::make_exception_ptr(css::uno::RuntimeException(
- "Unexpected dialog '" + pWin->GetText() + "' opened instead of the expected '"
- + msName + "'"));
+ "Unexpected dialog '" + mxDialog->getWindow()->GetText()
+ + "' opened instead of the expected '" + msName + "'"));
}
else
{
std::cout << "found dialog, calling user callback" << std::endl;
// set the real requested auto close now we're just calling the user callback
- dialog.setAutoClose(mbAutoClose);
+ mxDialog->setAutoClose(mbAutoClose);
try
{
- mCallback(dialog);
+ mCallback(*mxDialog);
}
catch (...)
{
mpException = std::current_exception();
}
}
+
+ mxDialog.reset();
}
public: