mirror of
https://github.com/ckb-next/ckb-next.git
synced 2026-10-10 12:27:21 -04:00
gui: Fix crash when wayland display goes away
The WaylandUtils class had to be rewritten to not cache the seat or display as they can change. The crash is resolved with a hack that removes the registry proxy immediately after it's been used.
This commit is contained in:
@@ -52,13 +52,13 @@ public:
|
||||
};
|
||||
|
||||
WaylandIdleTimer::WaylandIdleTimer()
|
||||
: m_supported{WaylandUtils::hasInterface("ext_idle_notifier_v1")}
|
||||
: wl_utils(new WaylandUtils), m_supported(wl_utils->hasInterface("ext_idle_notifier_v1"))
|
||||
{
|
||||
if (m_supported) {
|
||||
auto seat = WaylandUtils::seat();
|
||||
m_notifier.reset(new WaylandIdleNotifier());
|
||||
#ifdef USE_WAYLAND_INPUT_IDLE_NOTIFY
|
||||
if (WaylandUtils::hasInterface("ext_idle_notifier_v1", 2)) {
|
||||
if (wl_utils->hasInterface("ext_idle_notifier_v1", 2)) {
|
||||
m_notification.reset(new WaylandIdleNotification(m_notifier->get_input_idle_notification(0, seat)));
|
||||
} else {
|
||||
m_notification.reset(new WaylandIdleNotification(m_notifier->get_idle_notification(0, seat)));
|
||||
@@ -88,4 +88,6 @@ bool WaylandIdleTimer::isSupported() const
|
||||
{
|
||||
return m_supported;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#ifdef USE_WAYLAND_IDLE_NOTIFY
|
||||
#include "idletimer.h"
|
||||
#include "waylandutils.h"
|
||||
|
||||
#include <QScopedPointer>
|
||||
|
||||
@@ -17,6 +18,7 @@ public:
|
||||
bool isSupported() const override;
|
||||
|
||||
private:
|
||||
QScopedPointer<WaylandUtils> wl_utils;
|
||||
bool m_supported;
|
||||
QScopedPointer<WaylandIdleNotifier> m_notifier;
|
||||
QScopedPointer<WaylandIdleNotification> m_notification;
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <QGuiApplication>
|
||||
|
||||
#ifdef USE_WAYLAND
|
||||
#include <QGuiApplication>
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 5 ,0)
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
@@ -11,17 +10,9 @@
|
||||
#include <wayland-client-protocol.h>
|
||||
#include <wayland-client.h>
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 3 ,0)
|
||||
#include <qapplicationstatic.h>
|
||||
#else
|
||||
#include <QGlobalStatic>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace WaylandUtils
|
||||
{
|
||||
|
||||
bool isWayland()
|
||||
bool WaylandUtils::isWayland()
|
||||
{
|
||||
if (qGuiApp->platformName() == "wayland") {
|
||||
return true;
|
||||
@@ -39,51 +30,29 @@ bool isWayland()
|
||||
}
|
||||
|
||||
#ifdef USE_WAYLAND
|
||||
struct RegistryData {
|
||||
QString interfaceName;
|
||||
quint32 version;
|
||||
};
|
||||
|
||||
class WaylandUtilsHelper {
|
||||
public:
|
||||
wl_display* m_display = nullptr;
|
||||
wl_registry* m_registry = nullptr;
|
||||
wl_seat *m_seat = nullptr;
|
||||
|
||||
QList<RegistryData> m_registerData;
|
||||
|
||||
WaylandUtilsHelper()
|
||||
WaylandUtils::WaylandUtils()
|
||||
{
|
||||
wl_display* m_display = nullptr;
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 5 ,0)
|
||||
QPlatformNativeInterface* nativeInterface = qGuiApp->platformNativeInterface();
|
||||
if (!nativeInterface) {
|
||||
if (!nativeInterface)
|
||||
return;
|
||||
}
|
||||
|
||||
m_display = static_cast<wl_display *>(nativeInterface->nativeResourceForIntegration("wl_display"));
|
||||
if (!m_display) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_seat = static_cast<wl_seat *>(nativeInterface->nativeResourceForIntegration("m_seat"));
|
||||
if (!m_seat) {
|
||||
m_display = nullptr;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
auto nativeInterface = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>();
|
||||
if (!nativeInterface) {
|
||||
if (!nativeInterface)
|
||||
return;
|
||||
}
|
||||
|
||||
m_display = nativeInterface->display();
|
||||
m_seat = nativeInterface->seat();
|
||||
#endif
|
||||
if (!m_display)
|
||||
return;
|
||||
|
||||
m_registry = wl_display_get_registry(m_display);
|
||||
if (!m_registry) {
|
||||
wl_registry* m_registry = wl_display_get_registry(m_display);
|
||||
if (!m_registry)
|
||||
return;
|
||||
}
|
||||
|
||||
auto global_handler = [](void* data_ptr, wl_registry*, uint32_t name, const char* interface, uint32_t version) {
|
||||
auto registerData = static_cast<QList<RegistryData>*>(data_ptr);
|
||||
@@ -101,34 +70,39 @@ public:
|
||||
|
||||
wl_display_dispatch(m_display);
|
||||
wl_display_roundtrip(m_display);
|
||||
|
||||
// HACK: Destroy the registry proxy to indirectly remove the listener
|
||||
// This way we avoid crashing when the display disappears/changes
|
||||
wl_proxy_destroy(reinterpret_cast<wl_proxy*>(m_registry));
|
||||
}
|
||||
};
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 3 ,0)
|
||||
Q_APPLICATION_STATIC(WaylandUtilsHelper, g_helper,)
|
||||
wl_seat* WaylandUtils::seat() {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 5 ,0)
|
||||
QPlatformNativeInterface* nativeInterface = qGuiApp->platformNativeInterface();
|
||||
if (!nativeInterface)
|
||||
return nullptr;
|
||||
|
||||
wl_seat* s = static_cast<wl_seat*>(nativeInterface->nativeResourceForIntegration("m_seat"));
|
||||
#else
|
||||
Q_GLOBAL_STATIC(WaylandUtilsHelper, g_helper)
|
||||
#endif
|
||||
auto nativeInterface = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>();
|
||||
if (!nativeInterface)
|
||||
return nullptr;
|
||||
|
||||
bool hasInterface(const QString &name, quint32 version)
|
||||
wl_seat* s = nativeInterface->seat();
|
||||
#endif
|
||||
return s;
|
||||
}
|
||||
|
||||
bool WaylandUtils::hasInterface(const QString &name, quint32 version)
|
||||
{
|
||||
auto it = std::find_if(g_helper->m_registerData.constBegin(), g_helper->m_registerData.constEnd(), [&name, &version](const RegistryData& data){
|
||||
auto it = std::find_if(m_registerData.constBegin(), m_registerData.constEnd(), [&name, &version](const RegistryData& data){
|
||||
const bool matched = data.interfaceName == name;
|
||||
if (version == 0) {
|
||||
return matched;
|
||||
}
|
||||
return matched && data.version == version;
|
||||
});
|
||||
return it != g_helper->m_registerData.constEnd();
|
||||
return it != m_registerData.constEnd();
|
||||
}
|
||||
|
||||
wl_display *display() {
|
||||
return g_helper->m_display;
|
||||
}
|
||||
|
||||
wl_seat *seat() {
|
||||
return g_helper->m_seat;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // WaylandUtils
|
||||
|
||||
@@ -6,20 +6,29 @@
|
||||
#ifdef USE_WAYLAND
|
||||
class wl_display;
|
||||
class wl_seat;
|
||||
#include <QList>
|
||||
#endif
|
||||
|
||||
namespace WaylandUtils
|
||||
class WaylandUtils
|
||||
{
|
||||
|
||||
bool isWayland();
|
||||
public:
|
||||
static bool isWayland();
|
||||
|
||||
#ifdef USE_WAYLAND
|
||||
WaylandUtils();
|
||||
static wl_seat* seat();
|
||||
|
||||
bool hasInterface(const QString& name, quint32 version = 0);
|
||||
|
||||
wl_display *display();
|
||||
wl_seat *seat();
|
||||
private:
|
||||
struct RegistryData {
|
||||
QString interfaceName;
|
||||
quint32 version;
|
||||
};
|
||||
QList<RegistryData> m_registerData;
|
||||
#endif
|
||||
|
||||
} // WaylandUtils
|
||||
}; // WaylandUtils
|
||||
|
||||
#endif // WAYLANDUTILS_HPP
|
||||
|
||||
Reference in New Issue
Block a user