wasm: disable spinbox context menu if not ASYNCIFY to avoid deadlock
Using exec will lock the application if asyncify is not used Fixes: QTBUG-120925 Change-Id: Ic8b3acc402f3ecbfb07fd8cb80013e02e2421402 Reviewed-by: Morten Johan Sørvig <morten.sorvig@qt.io>
This commit is contained in:
parent
183a775f80
commit
00ce86a908
@ -2,6 +2,9 @@
|
|||||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||||
|
|
||||||
#include <qplatformdefs.h>
|
#include <qplatformdefs.h>
|
||||||
|
#ifdef Q_OS_WASM
|
||||||
|
# include <private/qstdweb_p.h>
|
||||||
|
#endif
|
||||||
#include <private/qabstractspinbox_p.h>
|
#include <private/qabstractspinbox_p.h>
|
||||||
#include <private/qapplication_p.h>
|
#include <private/qapplication_p.h>
|
||||||
#if QT_CONFIG(datetimeparser)
|
#if QT_CONFIG(datetimeparser)
|
||||||
@ -1281,6 +1284,12 @@ void QAbstractSpinBox::timerEvent(QTimerEvent *event)
|
|||||||
#if QT_CONFIG(contextmenu)
|
#if QT_CONFIG(contextmenu)
|
||||||
void QAbstractSpinBox::contextMenuEvent(QContextMenuEvent *event)
|
void QAbstractSpinBox::contextMenuEvent(QContextMenuEvent *event)
|
||||||
{
|
{
|
||||||
|
#ifdef Q_OS_WASM
|
||||||
|
if (!qstdweb::haveAsyncify()) {
|
||||||
|
qDebug() << " Skipping context menu for spinbox since asyncify is off";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
Q_D(QAbstractSpinBox);
|
Q_D(QAbstractSpinBox);
|
||||||
|
|
||||||
QPointer<QMenu> menu = d->edit->createStandardContextMenu();
|
QPointer<QMenu> menu = d->edit->createStandardContextMenu();
|
||||||
|
@ -81,6 +81,35 @@ class WidgetTestCase(unittest.TestCase):
|
|||||||
|
|
||||||
clearWidgets(self._driver)
|
clearWidgets(self._driver)
|
||||||
|
|
||||||
|
#Looks weird, no asserts, the test is that
|
||||||
|
#the test itself finishes
|
||||||
|
def test_showContextMenu_doesNotDeadlock(self):
|
||||||
|
screen = Screen(self._driver, ScreenPosition.FIXED,
|
||||||
|
x=0, y=0, width=600, height=1200)
|
||||||
|
|
||||||
|
w0 = Widget(self._driver, "w0")
|
||||||
|
w0.show()
|
||||||
|
w0.showContextMenu()
|
||||||
|
|
||||||
|
w1 = Widget(self._driver, "w1")
|
||||||
|
w1.setNoFocusShow()
|
||||||
|
w1.show()
|
||||||
|
w1.showContextMenu()
|
||||||
|
|
||||||
|
w2 = Widget(self._driver, "w2")
|
||||||
|
w2.show()
|
||||||
|
w2.showContextMenu()
|
||||||
|
|
||||||
|
w3 = Widget(self._driver, "w3")
|
||||||
|
w3.setNoFocusShow()
|
||||||
|
w3.show()
|
||||||
|
w3.showContextMenu()
|
||||||
|
|
||||||
|
w3.activate();
|
||||||
|
w3.showContextMenu()
|
||||||
|
|
||||||
|
clearWidgets(self._driver)
|
||||||
|
|
||||||
def test_window_resizing(self):
|
def test_window_resizing(self):
|
||||||
screen = Screen(self._driver, ScreenPosition.FIXED,
|
screen = Screen(self._driver, ScreenPosition.FIXED,
|
||||||
x=0, y=0, width=600, height=600)
|
x=0, y=0, width=600, height=600)
|
||||||
@ -686,6 +715,12 @@ class Widget:
|
|||||||
information = call_instance_function(self.driver, 'windowInformation')
|
information = call_instance_function(self.driver, 'windowInformation')
|
||||||
return next(filter(lambda e: e['title'] == "Dialog", information))
|
return next(filter(lambda e: e['title'] == "Dialog", information))
|
||||||
|
|
||||||
|
def showContextMenu(self):
|
||||||
|
self.driver.execute_script(
|
||||||
|
f'''
|
||||||
|
instance.showContextMenuWidget('{self.name}');
|
||||||
|
'''
|
||||||
|
)
|
||||||
|
|
||||||
class Window:
|
class Window:
|
||||||
def __init__(self, parent=None, rect=None, title=None, element=None, visible=True, opengl=0):
|
def __init__(self, parent=None, rect=None, title=None, element=None, visible=True, opengl=0):
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include <QFileSystemModel>
|
#include <QFileSystemModel>
|
||||||
#include <QScrollArea>
|
#include <QScrollArea>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
#include <QSpinBox>
|
||||||
|
|
||||||
#include <QOpenGLWindow>
|
#include <QOpenGLWindow>
|
||||||
#include <QOpenGLFunctions>
|
#include <QOpenGLFunctions>
|
||||||
@ -33,6 +34,34 @@
|
|||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
// Our dialog to test two things
|
||||||
|
// 1) Focus logic
|
||||||
|
// 2) spinbox context menu
|
||||||
|
class TestWidget : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
};
|
||||||
|
|
||||||
|
// We override to be able to test that the contextMenu
|
||||||
|
// calls popup and not exec. Calling exec locks the
|
||||||
|
// test.
|
||||||
|
class TestSpinBox : public QSpinBox
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
TestSpinBox(QWidget *parent = nullptr) : QSpinBox(parent) { }
|
||||||
|
|
||||||
|
void ShowContextMenu()
|
||||||
|
{
|
||||||
|
QContextMenuEvent event(QContextMenuEvent::Reason::Mouse, QPoint(0, geometry().bottom()),
|
||||||
|
mapToGlobal(QPoint(0, geometry().bottom())), Qt::NoModifier);
|
||||||
|
|
||||||
|
contextMenuEvent(&event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Baseclass for our windows, openglwindow and raster window
|
||||||
class TestWindowBase
|
class TestWindowBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -45,11 +74,6 @@ public:
|
|||||||
virtual void opengl_color_at_0_0(int *r, int *g, int *b) = 0;
|
virtual void opengl_color_at_0_0(int *r, int *g, int *b) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TestWidget : public QDialog
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
};
|
|
||||||
|
|
||||||
class TestWindow : public QRasterWindow, public TestWindowBase
|
class TestWindow : public QRasterWindow, public TestWindowBase
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -363,9 +387,8 @@ public:
|
|||||||
static WidgetStorage *getInstance()
|
static WidgetStorage *getInstance()
|
||||||
{
|
{
|
||||||
if (!s_instance)
|
if (!s_instance)
|
||||||
{
|
|
||||||
s_instance = new WidgetStorage();
|
s_instance = new WidgetStorage();
|
||||||
}
|
|
||||||
return s_instance;
|
return s_instance;
|
||||||
}
|
}
|
||||||
static void clearInstance()
|
static void clearInstance()
|
||||||
@ -382,10 +405,10 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
QLineEdit *findEdit(const std::string &name)
|
TestSpinBox *findSpinBox(const std::string &name)
|
||||||
{
|
{
|
||||||
auto it = m_lineEdits.find(name);
|
auto it = m_spinBoxes.find(name);
|
||||||
if (it != m_lineEdits.end())
|
if (it != m_spinBoxes.end())
|
||||||
return it->second;
|
return it->second;
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -393,34 +416,37 @@ public:
|
|||||||
void make(const std::string &name)
|
void make(const std::string &name)
|
||||||
{
|
{
|
||||||
auto widget = std::make_shared<TestWidget>();
|
auto widget = std::make_shared<TestWidget>();
|
||||||
|
|
||||||
widget->setWindowTitle("Dialog");
|
widget->setWindowTitle("Dialog");
|
||||||
auto *lineEdit = new QLineEdit(widget.get());
|
auto *spinBox = new TestSpinBox(widget.get());
|
||||||
|
|
||||||
widget->setMinimumSize(200, 200);
|
widget->setMinimumSize(200, 200);
|
||||||
widget->setMaximumSize(200, 200);
|
widget->setMaximumSize(200, 200);
|
||||||
widget->setGeometry(0, m_widgetY, 200, 200);
|
widget->setGeometry(0, m_widgetY, 200, 200);
|
||||||
m_widgetY += 200;
|
m_widgetY += 200;
|
||||||
|
|
||||||
lineEdit->setText("Hello world");
|
|
||||||
|
|
||||||
m_widgets[name] = widget;
|
m_widgets[name] = widget;
|
||||||
m_lineEdits[name] = lineEdit;
|
m_spinBoxes[name] = spinBox;
|
||||||
|
}
|
||||||
|
void showContextMenu(const std::string &name)
|
||||||
|
{
|
||||||
|
TestSpinBox *spinBox = findSpinBox(name);
|
||||||
|
if (spinBox)
|
||||||
|
spinBox->ShowContextMenu();
|
||||||
}
|
}
|
||||||
void makeNative(const std::string &name)
|
void makeNative(const std::string &name)
|
||||||
{
|
{
|
||||||
auto widget = std::make_shared<TestWidget>();
|
auto widget = std::make_shared<TestWidget>();
|
||||||
widget->setWindowTitle("Dialog");
|
widget->setWindowTitle("Dialog");
|
||||||
auto *lineEdit = new QLineEdit();
|
auto *spinBox = new TestSpinBox(widget.get());
|
||||||
|
|
||||||
widget->setMinimumSize(200, 200);
|
widget->setMinimumSize(200, 200);
|
||||||
widget->setMaximumSize(200, 200);
|
widget->setMaximumSize(200, 200);
|
||||||
widget->setGeometry(0, m_widgetY, 200, 200);
|
widget->setGeometry(0, m_widgetY, 200, 200);
|
||||||
m_widgetY += 200;
|
m_widgetY += 200;
|
||||||
|
|
||||||
lineEdit->setText("Hello world");
|
|
||||||
|
|
||||||
m_widgets[name] = widget;
|
m_widgets[name] = widget;
|
||||||
m_lineEdits[name] = lineEdit;
|
m_spinBoxes[name] = spinBox;
|
||||||
|
|
||||||
QFileSystemModel *model = new QFileSystemModel;
|
QFileSystemModel *model = new QFileSystemModel;
|
||||||
model->setRootPath(QDir::currentPath());
|
model->setRootPath(QDir::currentPath());
|
||||||
@ -430,22 +456,22 @@ public:
|
|||||||
auto *treeView = new QTreeView(scrollArea);
|
auto *treeView = new QTreeView(scrollArea);
|
||||||
treeView->setModel(model);
|
treeView->setModel(model);
|
||||||
|
|
||||||
layout->addWidget(lineEdit);
|
layout->addWidget(spinBox);
|
||||||
layout->addWidget(scrollArea);
|
layout->addWidget(scrollArea);
|
||||||
|
|
||||||
treeView->setAttribute(Qt::WA_NativeWindow);
|
treeView->setAttribute(Qt::WA_NativeWindow);
|
||||||
scrollArea->setAttribute(Qt::WA_NativeWindow);
|
scrollArea->setAttribute(Qt::WA_NativeWindow);
|
||||||
lineEdit->setAttribute(Qt::WA_NativeWindow);
|
spinBox->setAttribute(Qt::WA_NativeWindow);
|
||||||
widget->setAttribute(Qt::WA_NativeWindow);
|
widget->setAttribute(Qt::WA_NativeWindow);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
using TestWidgetPtr = std::shared_ptr<TestWidget>;
|
using TestWidgetPtr = std::shared_ptr<TestWidget>;
|
||||||
|
|
||||||
static WidgetStorage * s_instance;
|
static WidgetStorage *s_instance;
|
||||||
std::map<std::string, TestWidgetPtr> m_widgets;
|
std::map<std::string, TestWidgetPtr> m_widgets;
|
||||||
std::map<std::string, QLineEdit *> m_lineEdits;
|
std::map<std::string, TestSpinBox *> m_spinBoxes;
|
||||||
int m_widgetY = 0;
|
int m_widgetY = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
WidgetStorage *WidgetStorage::s_instance = nullptr;
|
WidgetStorage *WidgetStorage::s_instance = nullptr;
|
||||||
@ -540,11 +566,17 @@ void createWidget(const std::string &name)
|
|||||||
WidgetStorage::getInstance()->make(name);
|
WidgetStorage::getInstance()->make(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void createNativeWidget(const std::string &name)
|
void createNativeWidget(const std::string &name)
|
||||||
{
|
{
|
||||||
WidgetStorage::getInstance()->makeNative(name);
|
WidgetStorage::getInstance()->makeNative(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void showContextMenuWidget(const std::string &name)
|
||||||
|
{
|
||||||
|
WidgetStorage::getInstance()->showContextMenu(name);
|
||||||
|
}
|
||||||
|
|
||||||
void setWidgetNoFocusShow(const std::string &name)
|
void setWidgetNoFocusShow(const std::string &name)
|
||||||
{
|
{
|
||||||
auto w = WidgetStorage::getInstance()->findWidget(name);
|
auto w = WidgetStorage::getInstance()->findWidget(name);
|
||||||
@ -562,9 +594,9 @@ void showWidget(const std::string &name)
|
|||||||
void hasWidgetFocus(const std::string &name)
|
void hasWidgetFocus(const std::string &name)
|
||||||
{
|
{
|
||||||
bool focus = false;
|
bool focus = false;
|
||||||
auto le = WidgetStorage::getInstance()->findEdit(name);
|
auto spinBox = WidgetStorage::getInstance()->findSpinBox(name);
|
||||||
if (le)
|
if (spinBox)
|
||||||
focus = le->hasFocus();
|
focus = spinBox->hasFocus();
|
||||||
|
|
||||||
emscripten::val::global("window").call<void>("hasWidgetFocusCallback",
|
emscripten::val::global("window").call<void>("hasWidgetFocusCallback",
|
||||||
emscripten::val(focus));
|
emscripten::val(focus));
|
||||||
@ -681,12 +713,17 @@ bool closeWindow(const std::string &title)
|
|||||||
|
|
||||||
std::string colorToJs(int r, int g, int b)
|
std::string colorToJs(int r, int g, int b)
|
||||||
{
|
{
|
||||||
return
|
return "[{"
|
||||||
"[{"
|
" r: "
|
||||||
" r: " + std::to_string(r) + ","
|
+ std::to_string(r)
|
||||||
" g: " + std::to_string(g) + ","
|
+ ","
|
||||||
" b: " + std::to_string(b) + ""
|
" g: "
|
||||||
"}]";
|
+ std::to_string(g)
|
||||||
|
+ ","
|
||||||
|
" b: "
|
||||||
|
+ std::to_string(b)
|
||||||
|
+ ""
|
||||||
|
"}]";
|
||||||
}
|
}
|
||||||
|
|
||||||
void getOpenGLColorAt_0_0(const std::string &windowTitle)
|
void getOpenGLColorAt_0_0(const std::string &windowTitle)
|
||||||
@ -721,6 +758,7 @@ EMSCRIPTEN_BINDINGS(qwasmwindow)
|
|||||||
|
|
||||||
emscripten::function("createWidget", &createWidget);
|
emscripten::function("createWidget", &createWidget);
|
||||||
emscripten::function("createNativeWidget", &createNativeWidget);
|
emscripten::function("createNativeWidget", &createNativeWidget);
|
||||||
|
emscripten::function("showContextMenuWidget", &showContextMenuWidget);
|
||||||
emscripten::function("setWidgetNoFocusShow", &setWidgetNoFocusShow);
|
emscripten::function("setWidgetNoFocusShow", &setWidgetNoFocusShow);
|
||||||
emscripten::function("showWidget", &showWidget);
|
emscripten::function("showWidget", &showWidget);
|
||||||
emscripten::function("activateWidget", &activateWidget);
|
emscripten::function("activateWidget", &activateWidget);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user