mirror of
https://github.com/ckb-next/ckb-next.git
synced 2026-10-10 12:27:21 -04:00
Add Wayland interfaces query function
With Qt 6.5 and later, we have QNativeInterface::QWaylandApplication for low level Wayland access. For older Qt, QPlatformNativeInterface is required. QPlatformNativeInterface is a private class from Qt::GuiPrivate, which isn't idea. But it was how KDE did it in the past. FindWayland.cmake and FindWaylandProtocols.cmake are modifed version of KDE's ECM, with unused bits removed.
This commit is contained in:
@@ -107,6 +107,7 @@ if (LINUX)
|
||||
cmake_dependent_option(WITH_MVIZ "Build with music visualizer." ON "WITH_ANIMATIONS;WITH_GUI" OFF)
|
||||
cmake_dependent_option(USE_XCB "Build with features that require XCB." ON "WITH_GUI" OFF)
|
||||
cmake_dependent_option(USE_DBUS_MENU "Build with DBus support for the tray." ON "WITH_GUI" OFF)
|
||||
cmake_dependent_option(USE_WAYLAND "Build with features that require Wayland." ON "WITH_GUI" OFF)
|
||||
option(USE_PORTAUDIO "Use portaudio for music visualizer." OFF)
|
||||
else ()
|
||||
cmake_dependent_option(WITH_MVIZ "Build with music visualizer." OFF "WITH_ANIMATIONS;WITH_GUI" OFF)
|
||||
|
||||
@@ -0,0 +1,208 @@
|
||||
# SPDX-FileCopyrightText: 2014 Alex Merry <[email protected]>
|
||||
# SPDX-FileCopyrightText: 2014 Martin Gräßlin <[email protected]>
|
||||
# SPDX-FileCopyrightText: 2025 Trần Nam Tuấn <[email protected]>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
FindWayland
|
||||
-----------
|
||||
|
||||
Try to find Wayland.
|
||||
|
||||
This is a component-based find module, which makes use of the COMPONENTS
|
||||
and OPTIONAL_COMPONENTS arguments to find_module. The following components
|
||||
are available::
|
||||
|
||||
Client Server Cursor Egl
|
||||
|
||||
If no components are specified, this module will act as though all components
|
||||
were passed to OPTIONAL_COMPONENTS.
|
||||
|
||||
This module will define the following variables, independently of the
|
||||
components searched for or found:
|
||||
|
||||
``Wayland_FOUND``
|
||||
TRUE if (the requested version of) Wayland is available
|
||||
``Wayland_VERSION``
|
||||
Found Wayland version
|
||||
``Wayland_TARGETS``
|
||||
A list of all targets imported by this module (note that there may be more
|
||||
than the components that were requested)
|
||||
``Wayland_LIBRARIES``
|
||||
This can be passed to target_link_libraries() instead of the imported
|
||||
targets
|
||||
``Wayland_INCLUDE_DIRS``
|
||||
This should be passed to target_include_directories() if the targets are
|
||||
not used for linking
|
||||
``Wayland_DEFINITIONS``
|
||||
This should be passed to target_compile_options() if the targets are not
|
||||
used for linking
|
||||
``Wayland_DATADIR``
|
||||
The core wayland protocols data directory
|
||||
|
||||
For each searched-for components, ``Wayland_<component>_FOUND`` will be set to
|
||||
TRUE if the corresponding Wayland library was found, and FALSE otherwise. If
|
||||
``Wayland_<component>_FOUND`` is TRUE, the imported target
|
||||
``Wayland::<component>`` will be defined. This module will also attempt to
|
||||
determine ``Wayland_*_VERSION`` variables for each imported target, although
|
||||
``Wayland_VERSION`` should normally be sufficient.
|
||||
|
||||
In general we recommend using the imported targets, as they are easier to use
|
||||
and provide more control. Bear in mind, however, that if any target is in the
|
||||
link interface of an exported library, it must be made available by the
|
||||
package config file.
|
||||
#]=======================================================================]
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
set(Wayland_known_components
|
||||
Client
|
||||
Server
|
||||
Cursor
|
||||
Egl
|
||||
)
|
||||
|
||||
foreach(_comp ${Wayland_known_components})
|
||||
string(TOLOWER "${_comp}" _lc_comp)
|
||||
set(Wayland_${_comp}_component_deps)
|
||||
set(Wayland_${_comp}_pkg_config "wayland-${_lc_comp}")
|
||||
set(Wayland_${_comp}_lib "wayland-${_lc_comp}")
|
||||
set(Wayland_${_comp}_header "wayland-${_lc_comp}.h")
|
||||
endforeach()
|
||||
set(Wayland_Egl_component_deps Client)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
foreach(_comp ${Wayland_known_components})
|
||||
# Handling components dependencies
|
||||
foreach(_dep ${Wayland_${_comp}_component_deps})
|
||||
list(APPEND _dep_vars "Wayland_${_dep}_FOUND")
|
||||
list(APPEND _dep_targets "Wayland::${_dep}")
|
||||
endforeach()
|
||||
|
||||
pkg_check_modules(PKG_Wayland_${_comp} QUIET ${Wayland_${_comp}_pkg_config})
|
||||
|
||||
find_path(Wayland_${_comp}_INCLUDE_DIR
|
||||
NAMES ${Wayland_${_comp}_header}
|
||||
HINTS ${PKG_Wayland_${_comp}_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
find_library(Wayland_${_comp}_LIBRARY
|
||||
NAMES ${Wayland_${_comp}_lib}
|
||||
HINTS ${PKG_Wayland_${_comp}_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
set(Wayland_${_comp}_VERSION "${PKG_Wayland_${_comp}_VERSION}")
|
||||
if(NOT Wayland_VERSION)
|
||||
set(Wayland_VERSION ${Wayland_${_comp}_VERSION})
|
||||
endif()
|
||||
|
||||
set(FPHSA_NAME_MISMATCHED 1)
|
||||
find_package_handle_standard_args(Wayland_${_comp}
|
||||
FOUND_VAR
|
||||
Wayland_${_comp}_FOUND
|
||||
REQUIRED_VARS
|
||||
Wayland_${_comp}_LIBRARY
|
||||
Wayland_${_comp}_INCLUDE_DIR
|
||||
${_dep_vars}
|
||||
VERSION_VAR
|
||||
Wayland_${_comp}_VERSION
|
||||
)
|
||||
unset(FPHSA_NAME_MISMATCHED)
|
||||
|
||||
mark_as_advanced(
|
||||
Wayland_${_comp}_LIBRARY
|
||||
Wayland_${_comp}_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if(Wayland_${_comp}_FOUND)
|
||||
list(APPEND Wayland_LIBRARIES
|
||||
"${Wayland_${_comp}_LIBRARY}")
|
||||
list(APPEND Wayland_INCLUDE_DIRS
|
||||
"${Wayland_${_comp}_INCLUDE_DIR}")
|
||||
set(Wayland_DEFINITIONS
|
||||
${Wayland_DEFINITIONS}
|
||||
${PKG_Wayland_${_comp}_DEFINITIONS})
|
||||
if(NOT TARGET Wayland::${_comp})
|
||||
add_library(Wayland::${_comp} UNKNOWN IMPORTED)
|
||||
set_target_properties(Wayland::${_comp} PROPERTIES
|
||||
IMPORTED_LOCATION "${Wayland_${_comp}_LIBRARY}"
|
||||
INTERFACE_COMPILE_OPTIONS "${PKG_Wayland_${_comp}_DEFINITIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${Wayland_${_comp}_INCLUDE_DIR}"
|
||||
INTERFACE_LINK_LIBRARIES "${_dep_targets}"
|
||||
)
|
||||
endif()
|
||||
list(APPEND Wayland_TARGETS
|
||||
"Wayland::${_comp}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
if(Wayland_LIBRARIES)
|
||||
list(REMOVE_DUPLICATES Wayland_LIBRARIES)
|
||||
endif()
|
||||
|
||||
if(Wayland_INCLUDE_DIRS)
|
||||
list(REMOVE_DUPLICATES Wayland_INCLUDE_DIRS)
|
||||
endif()
|
||||
|
||||
if(Wayland_DEFINITIONS)
|
||||
list(REMOVE_DUPLICATES Wayland_DEFINITIONS)
|
||||
endif()
|
||||
|
||||
if(Wayland_TARGETS)
|
||||
list(REMOVE_DUPLICATES Wayland_TARGETS)
|
||||
endif()
|
||||
|
||||
# If pkg-config didn't provide us with version information,
|
||||
# try to extract it from wayland-version.h
|
||||
# (Note that the version from wayland-egl.pc will probably be
|
||||
# the Mesa version, rather than the Wayland version, but that
|
||||
# version will be ignored as we always find wayland-client.pc
|
||||
# first).
|
||||
if(NOT Wayland_VERSION)
|
||||
find_file(Wayland_VERSION_HEADER
|
||||
NAMES wayland-version.h
|
||||
HINTS ${Wayland_INCLUDE_DIRS}
|
||||
)
|
||||
mark_as_advanced(Wayland_VERSION_HEADER)
|
||||
if(Wayland_VERSION_HEADER)
|
||||
file(READ ${Wayland_VERSION_HEADER} _wayland_version_header_contents)
|
||||
string(REGEX REPLACE
|
||||
"^.*[ \t]+WAYLAND_VERSION[ \t]+\"([0-9.]*)\".*$"
|
||||
"\\1"
|
||||
Wayland_VERSION
|
||||
"${_wayland_version_header_contents}"
|
||||
)
|
||||
unset(_wayland_version_header_contents)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
find_package_handle_standard_args(Wayland
|
||||
FOUND_VAR
|
||||
Wayland_FOUND
|
||||
REQUIRED_VARS
|
||||
Wayland_LIBRARIES
|
||||
VERSION_VAR
|
||||
Wayland_VERSION
|
||||
HANDLE_COMPONENTS
|
||||
)
|
||||
|
||||
pkg_get_variable(Wayland_DATADIR wayland-scanner pkgdatadir)
|
||||
if (CMAKE_CROSSCOMPILING AND (NOT EXISTS "${Wayland_DATADIR}/wayland.xml"))
|
||||
# PKG_CONFIG_SYSROOT_DIR only applies to -I and -L flags, so pkg-config
|
||||
# does not prepend CMAKE_SYSROOT when cross-compiling unless you pass
|
||||
# --define-prefix explicitly. Therefore we have to manually do prepend
|
||||
# it here when cross-compiling.
|
||||
# See https://gitlab.kitware.com/cmake/cmake/-/issues/16647#note_844761
|
||||
set(Wayland_DATADIR ${CMAKE_SYSROOT}${Wayland_DATADIR})
|
||||
endif()
|
||||
if (NOT EXISTS "${Wayland_DATADIR}/wayland.xml")
|
||||
message(WARNING "Could not find wayland.xml in ${Wayland_DATADIR}")
|
||||
endif()
|
||||
|
||||
include(FeatureSummary)
|
||||
set_package_properties(Wayland PROPERTIES
|
||||
URL "https://wayland.freedesktop.org/"
|
||||
DESCRIPTION "C library implementation of the Wayland protocol: a protocol for a compositor to talk to its clients"
|
||||
)
|
||||
@@ -0,0 +1,38 @@
|
||||
# SPDX-FileCopyrightText: 2019 Vlad Zahorodnii <[email protected]>
|
||||
#
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
#[=======================================================================[.rst:
|
||||
FindWaylandProtocols
|
||||
--------------------
|
||||
|
||||
Try to find wayland-protocols on a Unix system.
|
||||
|
||||
This will define the following variables:
|
||||
|
||||
``WaylandProtocols_FOUND``
|
||||
True if (the requested version of) wayland-protocols is available
|
||||
``WaylandProtocols_VERSION``
|
||||
The version of wayland-protocols
|
||||
``WaylandProtocols_DATADIR``
|
||||
The wayland protocols data directory
|
||||
#]=======================================================================]
|
||||
|
||||
find_package(PkgConfig QUIET)
|
||||
pkg_check_modules(PKG_wayland_protocols QUIET wayland-protocols)
|
||||
|
||||
set(WaylandProtocols_VERSION ${PKG_wayland_protocols_VERSION})
|
||||
pkg_get_variable(WaylandProtocols_DATADIR wayland-protocols pkgdatadir)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(WaylandProtocols
|
||||
FOUND_VAR WaylandProtocols_FOUND
|
||||
REQUIRED_VARS WaylandProtocols_DATADIR
|
||||
VERSION_VAR WaylandProtocols_VERSION
|
||||
)
|
||||
|
||||
include(FeatureSummary)
|
||||
set_package_properties(WaylandProtocols PROPERTIES
|
||||
DESCRIPTION "Specifications of extended Wayland protocols"
|
||||
URL "https://wayland.freedesktop.org/"
|
||||
)
|
||||
@@ -411,6 +411,30 @@ elseif (LINUX)
|
||||
wayland/waylandutils.cpp
|
||||
wayland/waylandutils.h
|
||||
)
|
||||
|
||||
if (USE_WAYLAND)
|
||||
find_package(Wayland COMPONENTS Client REQUIRED)
|
||||
|
||||
target_compile_definitions(
|
||||
ckb-next
|
||||
PRIVATE
|
||||
USE_WAYLAND
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
ckb-next
|
||||
PRIVATE
|
||||
Wayland::Client
|
||||
)
|
||||
|
||||
if (Qt6_VERSION VERSION_LESS "6.5.0")
|
||||
target_link_libraries(
|
||||
ckb-next
|
||||
PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::GuiPrivate # For QPlatformNativeInterface. Qt 6.5 and later has QNativeInterface::QWaylandApplication.
|
||||
)
|
||||
endif ()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (MAC_LEGACY)
|
||||
|
||||
@@ -2,6 +2,22 @@
|
||||
|
||||
#include <QGuiApplication>
|
||||
|
||||
#ifdef USE_WAYLAND
|
||||
#include <QGuiApplication>
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 5 ,0)
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
#endif
|
||||
|
||||
#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
|
||||
{
|
||||
|
||||
@@ -22,4 +38,93 @@ bool isWayland()
|
||||
return false;
|
||||
}
|
||||
|
||||
#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()
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 5 ,0)
|
||||
QPlatformNativeInterface *nativeInterface = qGuiApp->platformNativeInterface();
|
||||
if (!nativeInterface) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_display = static_cast<wl_display *>(nativeInterface->nativeResourceForIntegration("wl_display"));
|
||||
if (!m_display) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_seat = static_cast<m_seat *>(nativeInterface->nativeResourceForIntegration("m_seat"));
|
||||
if (!m_seat) {
|
||||
m_display = nullptr;
|
||||
return;
|
||||
}
|
||||
#else
|
||||
auto nativeInterface = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>();
|
||||
if (!nativeInterface) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_display = nativeInterface->display();
|
||||
m_seat = nativeInterface->seat();
|
||||
#endif
|
||||
|
||||
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);
|
||||
registerData->append({QString::fromLatin1(interface), version});
|
||||
};
|
||||
|
||||
auto global_remover_handler = [](void*, wl_registry*, uint32_t) { };
|
||||
|
||||
wl_registry_listener registry_listener = {
|
||||
global_handler,
|
||||
global_remover_handler
|
||||
};
|
||||
|
||||
wl_registry_add_listener(m_registry, ®istry_listener, &m_registerData);
|
||||
|
||||
wl_display_dispatch(m_display);
|
||||
wl_display_roundtrip(m_display);
|
||||
}
|
||||
};
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 3 ,0)
|
||||
Q_APPLICATION_STATIC(WaylandUtilsHelper, g_helper,)
|
||||
#else
|
||||
Q_GLOBAL_STATIC(WaylandUtilsHelper, g_helper)
|
||||
#endif
|
||||
|
||||
bool 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){
|
||||
return data.interfaceName == name && data.version == version;
|
||||
});
|
||||
return it != g_helper->m_registerData.constEnd();
|
||||
}
|
||||
|
||||
wl_display *display() {
|
||||
return g_helper->m_display;
|
||||
}
|
||||
|
||||
wl_seat *seat() {
|
||||
return g_helper->m_seat;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // WaylandUtils
|
||||
|
||||
@@ -3,11 +3,23 @@
|
||||
|
||||
#include <QString>
|
||||
|
||||
#ifdef USE_WAYLAND
|
||||
class wl_display;
|
||||
class wl_seat;
|
||||
#endif
|
||||
|
||||
namespace WaylandUtils
|
||||
{
|
||||
|
||||
bool isWayland();
|
||||
|
||||
#ifdef USE_WAYLAND
|
||||
bool hasInterface(const QString &name, quint32 version);
|
||||
|
||||
wl_display *display();
|
||||
wl_seat *seat();
|
||||
#endif
|
||||
|
||||
} // WaylandUtils
|
||||
|
||||
#endif // WAYLANDUTILS_HPP
|
||||
|
||||
Reference in New Issue
Block a user