Advance Wayland and KDE package bring-up
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
@@ -0,0 +1 @@
|
||||
EXCLUDE typedefs
|
||||
@@ -0,0 +1,52 @@
|
||||
add_subdirectory(client)
|
||||
|
||||
add_subdirectory(tools)
|
||||
|
||||
ecm_qt_install_logging_categories(
|
||||
EXPORT KWAYLAND
|
||||
FILE kwayland.categories
|
||||
DESTINATION ${KDE_INSTALL_LOGGINGCATEGORIESDIR}
|
||||
)
|
||||
|
||||
|
||||
if(BUILD_QCH)
|
||||
macro(_make_absolute var_name base_path)
|
||||
set(_result)
|
||||
foreach(_path ${${var_name}})
|
||||
if(IS_ABSOLUTE "${_path}")
|
||||
list(APPEND _result "${_path}")
|
||||
else()
|
||||
list(APPEND _result "${base_path}/${_path}")
|
||||
endif()
|
||||
endforeach()
|
||||
set(${var_name} ${_result})
|
||||
endmacro()
|
||||
|
||||
_make_absolute(KWaylandClient_APIDOX_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/client")
|
||||
|
||||
ecm_add_qch(
|
||||
KWayland_QCH
|
||||
NAME KWayland
|
||||
BASE_NAME KWayland
|
||||
VERSION ${PROJECT_VERSION}
|
||||
ORG_DOMAIN org.kde
|
||||
SOURCES # using only public headers, to cover only public API
|
||||
${KWaylandClient_APIDOX_SRCS}
|
||||
MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md"
|
||||
LINK_QCHS
|
||||
Qt6Gui_QCH
|
||||
INCLUDE_DIRS
|
||||
${KWaylandClient_APIDOX_BUILD_INCLUDE_DIRS}
|
||||
BLANK_MACROS
|
||||
KWAYLANDCLIENT_EXPORT
|
||||
KWAYLANDCLIENT_DEPRECATED
|
||||
KWAYLANDCLIENT_DEPRECATED_EXPORT
|
||||
"KWAYLANDCLIENT_DEPRECATED_VERSION(x, y, t)"
|
||||
"KWAYLANDCLIENT_DEPRECATED_VERSION_BELATED(x, y, xt, yt, t)"
|
||||
"KWAYLANDCLIENT_ENUMERATOR_DEPRECATED_VERSION(x, y, t)"
|
||||
"KWAYLANDCLIENT_ENUMERATOR_DEPRECATED_VERSION_BELATED(x, y, xt, yt, t)"
|
||||
TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
|
||||
QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
|
||||
COMPONENT Devel
|
||||
)
|
||||
endif()
|
||||
@@ -0,0 +1,303 @@
|
||||
remove_definitions(-DQT_NO_CAST_FROM_BYTEARRAY)
|
||||
remove_definitions(-DQT_NO_CAST_FROM_ASCII)
|
||||
remove_definitions(-DQT_NO_CAST_TO_ASCII)
|
||||
remove_definitions(-DQT_NO_KEYWORDS)
|
||||
|
||||
# needed to access QPA
|
||||
include_directories(SYSTEM ${Qt6Gui_PRIVATE_INCLUDE_DIRS})
|
||||
|
||||
set(CLIENT_LIB_SRCS
|
||||
appmenu.cpp
|
||||
buffer.cpp
|
||||
blur.cpp
|
||||
compositor.cpp
|
||||
connection_thread.cpp
|
||||
contrast.cpp
|
||||
slide.cpp
|
||||
event_queue.cpp
|
||||
datadevice.cpp
|
||||
datadevicemanager.cpp
|
||||
dataoffer.cpp
|
||||
datasource.cpp
|
||||
dpms.cpp
|
||||
fakeinput.cpp
|
||||
idleinhibit.cpp
|
||||
keyboard.cpp
|
||||
output.cpp
|
||||
pointer.cpp
|
||||
pointerconstraints.cpp
|
||||
pointergestures.cpp
|
||||
plasmashell.cpp
|
||||
plasmavirtualdesktop.cpp
|
||||
plasmawindowmanagement.cpp
|
||||
plasmawindowmodel.cpp
|
||||
region.cpp
|
||||
registry.cpp
|
||||
relativepointer.cpp
|
||||
seat.cpp
|
||||
shadow.cpp
|
||||
shell.cpp
|
||||
shm_pool.cpp
|
||||
subcompositor.cpp
|
||||
subsurface.cpp
|
||||
surface.cpp
|
||||
touch.cpp
|
||||
textinput.cpp
|
||||
textinput_v0.cpp
|
||||
textinput_v2.cpp
|
||||
xdgdecoration.cpp
|
||||
xdgshell.cpp
|
||||
xdgforeign_v2.cpp
|
||||
xdgforeign.cpp
|
||||
xdgshell_v5.cpp
|
||||
xdgshell_v6.cpp
|
||||
xdgshell_stable.cpp
|
||||
xdgoutput.cpp
|
||||
../compat/wayland-xdg-shell-v5-protocol.c
|
||||
)
|
||||
|
||||
ecm_qt_declare_logging_category(CLIENT_LIB_SRCS
|
||||
HEADER logging.h
|
||||
IDENTIFIER KWAYLAND_CLIENT
|
||||
CATEGORY_NAME kde.plasma.wayland.client
|
||||
OLD_CATEGORY_NAMES kwayland-client kf.wayland.client
|
||||
DEFAULT_SEVERITY Critical
|
||||
DESCRIPTION "KWayland Client Library"
|
||||
EXPORT KWAYLAND
|
||||
)
|
||||
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/plasma-shell.xml
|
||||
BASENAME plasma-shell
|
||||
PRIVATE_CODE
|
||||
)
|
||||
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/plasma-virtual-desktop.xml
|
||||
BASENAME plasma-virtual-desktop
|
||||
PRIVATE_CODE
|
||||
)
|
||||
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/plasma-window-management.xml
|
||||
BASENAME plasma-window-management
|
||||
PRIVATE_CODE
|
||||
)
|
||||
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/fake-input.xml
|
||||
BASENAME fake-input
|
||||
PRIVATE_CODE
|
||||
)
|
||||
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/shadow.xml
|
||||
BASENAME shadow
|
||||
PRIVATE_CODE
|
||||
)
|
||||
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/blur.xml
|
||||
BASENAME blur
|
||||
PRIVATE_CODE
|
||||
)
|
||||
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/contrast.xml
|
||||
BASENAME contrast
|
||||
PRIVATE_CODE
|
||||
)
|
||||
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/slide.xml
|
||||
BASENAME slide
|
||||
PRIVATE_CODE
|
||||
)
|
||||
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/dpms.xml
|
||||
BASENAME dpms
|
||||
PRIVATE_CODE
|
||||
)
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/text-input.xml
|
||||
BASENAME text-input-v0
|
||||
PRIVATE_CODE
|
||||
)
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/text-input-unstable-v2.xml
|
||||
BASENAME text-input-v2
|
||||
PRIVATE_CODE
|
||||
)
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/unstable/xdg-shell/xdg-shell-unstable-v6.xml
|
||||
BASENAME xdg-shell-v6
|
||||
PRIVATE_CODE
|
||||
)
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/unstable/relative-pointer/relative-pointer-unstable-v1.xml
|
||||
BASENAME relativepointer-unstable-v1
|
||||
PRIVATE_CODE
|
||||
)
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml
|
||||
BASENAME pointer-gestures-unstable-v1
|
||||
PRIVATE_CODE
|
||||
)
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml
|
||||
BASENAME pointer-constraints-unstable-v1
|
||||
PRIVATE_CODE
|
||||
)
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/unstable/xdg-foreign/xdg-foreign-unstable-v2.xml
|
||||
BASENAME xdg-foreign-unstable-v2
|
||||
PRIVATE_CODE
|
||||
)
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml
|
||||
BASENAME idle-inhibit-unstable-v1
|
||||
PRIVATE_CODE
|
||||
)
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${PLASMA_WAYLAND_PROTOCOLS_DIR}/appmenu.xml
|
||||
BASENAME appmenu
|
||||
PRIVATE_CODE
|
||||
)
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/unstable/xdg-output/xdg-output-unstable-v1.xml
|
||||
BASENAME xdg-output-unstable-v1
|
||||
PRIVATE_CODE
|
||||
)
|
||||
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/stable/xdg-shell/xdg-shell.xml
|
||||
BASENAME xdg-shell
|
||||
PRIVATE_CODE
|
||||
)
|
||||
|
||||
ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS
|
||||
PROTOCOL ${WaylandProtocols_DATADIR}/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
|
||||
BASENAME xdg-decoration-unstable-v1
|
||||
PRIVATE_CODE
|
||||
)
|
||||
|
||||
set(CLIENT_GENERATED_FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-plasma-shell-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-plasma-shell-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-plasma-window-management-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-fake-input-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-shadow-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-blur-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-contrast-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-slide-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-dpms-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-text-input-v0-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-text-input-v2-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-shell-v6-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-relativepointer-unstable-v1-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-pointer-gestures-unstable-v1-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-pointer-constraints-unstable-v1-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-foreign-unstable-v2-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-idle-inhibit-unstable-v1-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-output-unstable-v1-client-protocol.h
|
||||
${CMAKE_CURRENT_BINARY_DIR}/wayland-xdg-decoration-unstable-v1-client-protocol.h
|
||||
)
|
||||
|
||||
set_source_files_properties(${CLIENT_GENERATED_FILES} PROPERTIES SKIP_AUTOMOC ON)
|
||||
|
||||
set_source_files_properties(${CLIENT_LIB_SRCS} PROPERTIES
|
||||
COMPILE_FLAGS -DQT_NO_KEYWORDS)
|
||||
|
||||
add_library(KWaylandClient ${CLIENT_LIB_SRCS} surface_p.cpp)
|
||||
add_library(Plasma::KWaylandClient ALIAS KWaylandClient)
|
||||
|
||||
ecm_generate_export_header(KWaylandClient
|
||||
BASE_NAME
|
||||
KWaylandClient
|
||||
EXPORT_FILE_NAME
|
||||
KWayland/Client/kwaylandclient_export.h
|
||||
VERSION ${PROJECT_VERSION}
|
||||
USE_VERSION_HEADER
|
||||
VERSION_BASE_NAME KWayland
|
||||
DEPRECATED_BASE_VERSION 0
|
||||
DEPRECATION_VERSIONS
|
||||
EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT}
|
||||
)
|
||||
|
||||
if (HAVE_MEMFD)
|
||||
target_compile_definitions(KWaylandClient PRIVATE -DHAVE_MEMFD=1)
|
||||
else()
|
||||
target_compile_definitions(KWaylandClient PRIVATE -DHAVE_MEMFD=0)
|
||||
endif()
|
||||
|
||||
target_include_directories(KWaylandClient
|
||||
INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR}/KWayland>"
|
||||
)
|
||||
|
||||
target_link_libraries(KWaylandClient
|
||||
PUBLIC Qt6::Gui
|
||||
PRIVATE Wayland::Client
|
||||
Qt6::Concurrent
|
||||
Qt6::GuiPrivate
|
||||
Qt6::WaylandClientPrivate
|
||||
)
|
||||
|
||||
set_target_properties(KWaylandClient PROPERTIES VERSION ${KWAYLAND_VERSION}
|
||||
SOVERSION ${KWAYLAND_SOVERSION}
|
||||
)
|
||||
|
||||
install(TARGETS KWaylandClient EXPORT KWaylandTargets ${KF_INSTALL_TARGETS_DEFAULT_ARGS})
|
||||
|
||||
set(CLIENT_LIB_HEADERS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/KWayland/Client/kwaylandclient_export.h
|
||||
appmenu.h
|
||||
blur.h
|
||||
buffer.h
|
||||
compositor.h
|
||||
connection_thread.h
|
||||
contrast.h
|
||||
event_queue.h
|
||||
datadevice.h
|
||||
datadevicemanager.h
|
||||
dataoffer.h
|
||||
datasource.h
|
||||
dpms.h
|
||||
fakeinput.h
|
||||
idleinhibit.h
|
||||
keyboard.h
|
||||
output.h
|
||||
pointer.h
|
||||
pointerconstraints.h
|
||||
plasmashell.h
|
||||
plasmavirtualdesktop.h
|
||||
plasmawindowmanagement.h
|
||||
plasmawindowmodel.h
|
||||
pointergestures.h
|
||||
region.h
|
||||
registry.h
|
||||
relativepointer.h
|
||||
seat.h
|
||||
shadow.h
|
||||
shell.h
|
||||
shm_pool.h
|
||||
slide.h
|
||||
subcompositor.h
|
||||
subsurface.h
|
||||
surface.h
|
||||
touch.h
|
||||
textinput.h
|
||||
xdgdecoration.h
|
||||
xdgshell.h
|
||||
xdgforeign.h
|
||||
xdgoutput.h
|
||||
)
|
||||
|
||||
install(FILES
|
||||
${CLIENT_LIB_HEADERS}
|
||||
DESTINATION ${KDE_INSTALL_INCLUDEDIR}/KWayland/KWayland/Client COMPONENT Devel
|
||||
)
|
||||
|
||||
# make available to ecm_add_qch in parent folder
|
||||
set(KWaylandClient_APIDOX_SRCS ${CLIENT_LIB_HEADERS} PARENT_SCOPE)
|
||||
set(KWaylandClient_APIDOX_BUILD_INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} PARENT_SCOPE)
|
||||
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2017 David Edmundson <kde@davidedmundson.co.uk>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "appmenu.h"
|
||||
#include "event_queue.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <wayland-appmenu-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class AppMenuManager::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
void setup(org_kde_kwin_appmenu_manager *arg);
|
||||
|
||||
WaylandPointer<org_kde_kwin_appmenu_manager, org_kde_kwin_appmenu_manager_destroy> appmenumanager;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
AppMenuManager::AppMenuManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
void AppMenuManager::Private::setup(org_kde_kwin_appmenu_manager *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!appmenumanager);
|
||||
appmenumanager.setup(arg);
|
||||
}
|
||||
|
||||
AppMenuManager::~AppMenuManager()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void AppMenuManager::setup(org_kde_kwin_appmenu_manager *appmenumanager)
|
||||
{
|
||||
d->setup(appmenumanager);
|
||||
}
|
||||
|
||||
void AppMenuManager::release()
|
||||
{
|
||||
d->appmenumanager.release();
|
||||
}
|
||||
|
||||
void AppMenuManager::destroy()
|
||||
{
|
||||
d->appmenumanager.destroy();
|
||||
}
|
||||
|
||||
AppMenuManager::operator org_kde_kwin_appmenu_manager *()
|
||||
{
|
||||
return d->appmenumanager;
|
||||
}
|
||||
|
||||
AppMenuManager::operator org_kde_kwin_appmenu_manager *() const
|
||||
{
|
||||
return d->appmenumanager;
|
||||
}
|
||||
|
||||
bool AppMenuManager::isValid() const
|
||||
{
|
||||
return d->appmenumanager.isValid();
|
||||
}
|
||||
|
||||
void AppMenuManager::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *AppMenuManager::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
AppMenu *AppMenuManager::create(Surface *surface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
auto p = new AppMenu(parent);
|
||||
auto w = org_kde_kwin_appmenu_manager_create(d->appmenumanager, *surface);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
p->setup(w);
|
||||
return p;
|
||||
}
|
||||
|
||||
class AppMenu::Private
|
||||
{
|
||||
public:
|
||||
void setup(org_kde_kwin_appmenu *arg);
|
||||
|
||||
WaylandPointer<org_kde_kwin_appmenu, org_kde_kwin_appmenu_release> appmenu;
|
||||
};
|
||||
|
||||
AppMenu::AppMenu(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
void AppMenu::Private::setup(org_kde_kwin_appmenu *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!appmenu);
|
||||
appmenu.setup(arg);
|
||||
}
|
||||
|
||||
AppMenu::~AppMenu()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void AppMenu::setup(org_kde_kwin_appmenu *appmenu)
|
||||
{
|
||||
d->setup(appmenu);
|
||||
}
|
||||
|
||||
void AppMenu::release()
|
||||
{
|
||||
d->appmenu.release();
|
||||
}
|
||||
|
||||
void AppMenu::destroy()
|
||||
{
|
||||
d->appmenu.destroy();
|
||||
}
|
||||
|
||||
AppMenu::operator org_kde_kwin_appmenu *()
|
||||
{
|
||||
return d->appmenu;
|
||||
}
|
||||
|
||||
AppMenu::operator org_kde_kwin_appmenu *() const
|
||||
{
|
||||
return d->appmenu;
|
||||
}
|
||||
|
||||
bool AppMenu::isValid() const
|
||||
{
|
||||
return d->appmenu.isValid();
|
||||
}
|
||||
|
||||
void AppMenu::setAddress(const QString &serviceName, const QString &objectPath)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
org_kde_kwin_appmenu_set_address(d->appmenu, serviceName.toLatin1(), objectPath.toLatin1());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_appmenu.cpp"
|
||||
@@ -0,0 +1,186 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2017 David Edmundson <kde@davidedmundson.co.uk>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_APPMENU_H
|
||||
#define KWAYLAND_CLIENT_APPMENU_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct org_kde_kwin_appmenu_manager;
|
||||
struct org_kde_kwin_appmenu;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Surface;
|
||||
class AppMenu;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the org_kde_kwin_appmenu_manager interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the org_kde_kwin_appmenu_manager interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the AppMenuManager interface:
|
||||
* @code
|
||||
* AppMenuManager *c = registry->createAppMenuManager(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the AppMenuManager and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* AppMenuManager *c = new AppMenuManager;
|
||||
* c->setup(registry->bindAppMenuManager(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The AppMenuManager can be used as a drop-in replacement for any org_kde_kwin_appmenu_manager
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
* @since 5.42
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT AppMenuManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new AppMenuManager.
|
||||
* Note: after constructing the AppMenuManager it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use AppMenuManager prefer using
|
||||
* Registry::createAppMenuManager.
|
||||
**/
|
||||
explicit AppMenuManager(QObject *parent = nullptr);
|
||||
~AppMenuManager() override;
|
||||
|
||||
/**
|
||||
* Setup this AppMenuManager to manage the @p appmenumanager.
|
||||
* When using Registry::createAppMenuManager there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_kwin_appmenu_manager *appmenumanager);
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_kwin_appmenu_manager.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the org_kde_kwin_appmenu_manager interface.
|
||||
* After the interface has been released the AppMenuManager instance is no
|
||||
* longer valid and can be setup with another org_kde_kwin_appmenu_manager interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this AppMenuManager.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_kwin_appmenu_manager interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, appmenumanager, &AppMenuManager::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating objects with this AppMenuManager.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating objects with this AppMenuManager.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
AppMenu *create(Surface *surface, QObject *parent = nullptr);
|
||||
|
||||
operator org_kde_kwin_appmenu_manager *();
|
||||
operator org_kde_kwin_appmenu_manager *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the AppMenuManager got created by
|
||||
* Registry::createAppMenuManager
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 5.42
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT AppMenu : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~AppMenu() override;
|
||||
|
||||
/**
|
||||
* Setup this Appmenu to manage the @p appmenu.
|
||||
* When using AppMenuManager::createAppmenu there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_kwin_appmenu *appmenu);
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_kwin_appmenu.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the org_kde_kwin_appmenu interface.
|
||||
* After the interface has been released the Appmenu instance is no
|
||||
* longer valid and can be setup with another org_kde_kwin_appmenu interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this Appmenu.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_kwin_appmenu interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, appmenu, &Appmenu::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the appmenu address. The DBus object should be registered before making this call
|
||||
* Strings should be valid DBus formatted names, in latin1.
|
||||
*/
|
||||
void setAddress(const QString &serviceName, const QString &objectPath);
|
||||
|
||||
operator org_kde_kwin_appmenu *();
|
||||
operator org_kde_kwin_appmenu *() const;
|
||||
|
||||
private:
|
||||
friend class AppMenuManager;
|
||||
explicit AppMenu(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "blur.h"
|
||||
#include "event_queue.h"
|
||||
#include "region.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <wayland-blur-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN BlurManager::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
WaylandPointer<org_kde_kwin_blur_manager, org_kde_kwin_blur_manager_destroy> manager;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
BlurManager::BlurManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
BlurManager::~BlurManager()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void BlurManager::release()
|
||||
{
|
||||
d->manager.release();
|
||||
}
|
||||
|
||||
void BlurManager::destroy()
|
||||
{
|
||||
d->manager.destroy();
|
||||
}
|
||||
|
||||
bool BlurManager::isValid() const
|
||||
{
|
||||
return d->manager.isValid();
|
||||
}
|
||||
|
||||
void BlurManager::setup(org_kde_kwin_blur_manager *manager)
|
||||
{
|
||||
Q_ASSERT(manager);
|
||||
Q_ASSERT(!d->manager);
|
||||
d->manager.setup(manager);
|
||||
}
|
||||
|
||||
void BlurManager::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *BlurManager::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
Blur *BlurManager::createBlur(Surface *surface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Blur *s = new Blur(parent);
|
||||
auto w = org_kde_kwin_blur_manager_create(d->manager, *surface);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
s->setup(w);
|
||||
return s;
|
||||
}
|
||||
|
||||
void BlurManager::removeBlur(Surface *surface)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
org_kde_kwin_blur_manager_unset(d->manager, *surface);
|
||||
}
|
||||
|
||||
BlurManager::operator org_kde_kwin_blur_manager *()
|
||||
{
|
||||
return d->manager;
|
||||
}
|
||||
|
||||
BlurManager::operator org_kde_kwin_blur_manager *() const
|
||||
{
|
||||
return d->manager;
|
||||
}
|
||||
|
||||
class Blur::Private
|
||||
{
|
||||
public:
|
||||
WaylandPointer<org_kde_kwin_blur, org_kde_kwin_blur_release> blur;
|
||||
};
|
||||
|
||||
Blur::Blur(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
Blur::~Blur()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void Blur::release()
|
||||
{
|
||||
d->blur.release();
|
||||
}
|
||||
|
||||
void Blur::setup(org_kde_kwin_blur *blur)
|
||||
{
|
||||
Q_ASSERT(blur);
|
||||
Q_ASSERT(!d->blur);
|
||||
d->blur.setup(blur);
|
||||
}
|
||||
|
||||
void Blur::destroy()
|
||||
{
|
||||
d->blur.destroy();
|
||||
}
|
||||
|
||||
bool Blur::isValid() const
|
||||
{
|
||||
return d->blur.isValid();
|
||||
}
|
||||
|
||||
void Blur::commit()
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
org_kde_kwin_blur_commit(d->blur);
|
||||
}
|
||||
|
||||
void Blur::setRegion(Region *region)
|
||||
{
|
||||
org_kde_kwin_blur_set_region(d->blur, *region);
|
||||
}
|
||||
|
||||
Blur::operator org_kde_kwin_blur *()
|
||||
{
|
||||
return d->blur;
|
||||
}
|
||||
|
||||
Blur::operator org_kde_kwin_blur *() const
|
||||
{
|
||||
return d->blur;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_blur.cpp"
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_BLUR_H
|
||||
#define KWAYLAND_BLUR_H
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QPoint>
|
||||
#include <QSize>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_buffer;
|
||||
struct wl_region;
|
||||
struct org_kde_kwin_blur;
|
||||
struct org_kde_kwin_blur_manager;
|
||||
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Blur;
|
||||
class Surface;
|
||||
class Region;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
class KWAYLANDCLIENT_EXPORT BlurManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new BlurManager.
|
||||
* Note: after constructing the BlurManager it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use BlurManager prefer using
|
||||
* Registry::createBlurManager.
|
||||
**/
|
||||
explicit BlurManager(QObject *parent = nullptr);
|
||||
~BlurManager() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_kwin_blur_manager.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this BlurManager to manage the @p compositor.
|
||||
* When using Registry::createBlurManager there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_kwin_blur_manager *compositor);
|
||||
/**
|
||||
* Releases the org_kde_kwin_blur_manager interface.
|
||||
* After the interface has been released the BlurManager instance is no
|
||||
* longer valid and can be setup with another org_kde_kwin_blur_manager interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this BlurManager.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_kwin_blur_manager interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, compositor, &BlurManager::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating a Blur.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating a Blur.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Creates and setup a new Blur with @p parent.
|
||||
* @param parent The parent to pass to the Blur.
|
||||
* @returns The new created Blur
|
||||
**/
|
||||
Blur *createBlur(Surface *surface, QObject *parent = nullptr);
|
||||
void removeBlur(Surface *surface);
|
||||
|
||||
operator org_kde_kwin_blur_manager *();
|
||||
operator org_kde_kwin_blur_manager *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the BlurManager got created by
|
||||
* Registry::createBlurManager
|
||||
*
|
||||
* @since 5.5
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Wrapper for the org_kde_kwin_blur interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the org_kde_kwin_blur interface.
|
||||
* To create a Blur call BlurManager::createBlur.
|
||||
*
|
||||
* The main purpose of this class is to setup the next frame which
|
||||
* should be rendered. Therefore it provides methods to add damage
|
||||
* and to attach a new Buffer and to finalize the frame by calling
|
||||
* commit.
|
||||
*
|
||||
* @see BlurManager
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Blur : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~Blur() override;
|
||||
|
||||
/**
|
||||
* Setup this Blur to manage the @p blur.
|
||||
* When using BlurManager::createBlur there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_kwin_blur *blur);
|
||||
/**
|
||||
* Releases the org_kde_kwin_blur interface.
|
||||
* After the interface has been released the Blur instance is no
|
||||
* longer valid and can be setup with another org_kde_kwin_blur interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this Blur.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_kwin_blur interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* Blur gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_kwin_blur.
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
void commit();
|
||||
|
||||
/**
|
||||
* Sets the area of the window that will have a blurred
|
||||
* background.
|
||||
* The region will have to be created with
|
||||
* Compositor::createRegion(QRegion)
|
||||
*/
|
||||
void setRegion(Region *region);
|
||||
|
||||
operator org_kde_kwin_blur *();
|
||||
operator org_kde_kwin_blur *() const;
|
||||
|
||||
private:
|
||||
friend class BlurManager;
|
||||
explicit Blur(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "buffer.h"
|
||||
#include "buffer_p.h"
|
||||
#include "shm_pool.h"
|
||||
// system
|
||||
#include <string.h>
|
||||
// wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
#ifndef K_DOXYGEN
|
||||
const struct wl_buffer_listener Buffer::Private::s_listener = {Buffer::Private::releasedCallback};
|
||||
#endif
|
||||
|
||||
Buffer::Private::Private(Buffer *q, ShmPool *parent, wl_buffer *nativeBuffer, const QSize &size, int32_t stride, size_t offset, Format format)
|
||||
: shm(parent)
|
||||
, nativeBuffer(nativeBuffer)
|
||||
, released(false)
|
||||
, size(size)
|
||||
, stride(stride)
|
||||
, offset(offset)
|
||||
, used(false)
|
||||
, format(format)
|
||||
, q(q)
|
||||
{
|
||||
wl_buffer_add_listener(nativeBuffer, &s_listener, this);
|
||||
}
|
||||
|
||||
Buffer::Private::~Private()
|
||||
{
|
||||
nativeBuffer.release();
|
||||
}
|
||||
|
||||
void Buffer::Private::destroy()
|
||||
{
|
||||
nativeBuffer.destroy();
|
||||
}
|
||||
|
||||
void Buffer::Private::releasedCallback(void *data, wl_buffer *buffer)
|
||||
{
|
||||
auto b = reinterpret_cast<Buffer::Private *>(data);
|
||||
Q_ASSERT(b->nativeBuffer == buffer);
|
||||
b->q->setReleased(true);
|
||||
}
|
||||
|
||||
Buffer::Buffer(ShmPool *parent, wl_buffer *buffer, const QSize &size, int32_t stride, size_t offset, Format format)
|
||||
: d(new Private(this, parent, buffer, size, stride, offset, format))
|
||||
{
|
||||
}
|
||||
|
||||
Buffer::~Buffer() = default;
|
||||
|
||||
void Buffer::copy(const void *src)
|
||||
{
|
||||
memcpy(address(), src, d->size.height() * d->stride);
|
||||
}
|
||||
|
||||
uchar *Buffer::address()
|
||||
{
|
||||
return reinterpret_cast<uchar *>(d->shm->poolAddress()) + d->offset;
|
||||
}
|
||||
|
||||
wl_buffer *Buffer::buffer() const
|
||||
{
|
||||
return d->nativeBuffer;
|
||||
}
|
||||
|
||||
Buffer::operator wl_buffer *()
|
||||
{
|
||||
return d->nativeBuffer;
|
||||
}
|
||||
|
||||
Buffer::operator wl_buffer *() const
|
||||
{
|
||||
return d->nativeBuffer;
|
||||
}
|
||||
|
||||
bool Buffer::isReleased() const
|
||||
{
|
||||
return d->released;
|
||||
}
|
||||
|
||||
void Buffer::setReleased(bool released)
|
||||
{
|
||||
d->released = released;
|
||||
}
|
||||
|
||||
QSize Buffer::size() const
|
||||
{
|
||||
return d->size;
|
||||
}
|
||||
|
||||
int32_t Buffer::stride() const
|
||||
{
|
||||
return d->stride;
|
||||
}
|
||||
|
||||
bool Buffer::isUsed() const
|
||||
{
|
||||
return d->used;
|
||||
}
|
||||
|
||||
void Buffer::setUsed(bool used)
|
||||
{
|
||||
d->used = used;
|
||||
}
|
||||
|
||||
Buffer::Format Buffer::format() const
|
||||
{
|
||||
return d->format;
|
||||
}
|
||||
|
||||
quint32 Buffer::getId(wl_buffer *b)
|
||||
{
|
||||
return wl_proxy_get_id(reinterpret_cast<wl_proxy *>(b));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_BUFFER_H
|
||||
#define WAYLAND_BUFFER_H
|
||||
|
||||
#include <QScopedPointer>
|
||||
#include <QSize>
|
||||
#include <QWeakPointer>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_buffer;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class ShmPool;
|
||||
|
||||
/**
|
||||
* @short Wrapper class for wl_buffer interface.
|
||||
*
|
||||
* The Buffer is provided by ShmPool and is owned by ShmPool.
|
||||
*
|
||||
* @see ShmPool
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Buffer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* All image formats supported by the implementation.
|
||||
**/
|
||||
enum class Format {
|
||||
ARGB32, ///< 32-bit ARGB format, can be used for QImage::Format_ARGB32 and QImage::Format_ARGB32_Premultiplied
|
||||
RGB32, ///< 32-bit RGB format, can be used for QImage::Format_RGB32
|
||||
};
|
||||
|
||||
~Buffer();
|
||||
/**
|
||||
* Copies the data from @p src into the Buffer.
|
||||
**/
|
||||
void copy(const void *src);
|
||||
/**
|
||||
* Sets the Buffer as @p released.
|
||||
* This is automatically invoked when the Wayland server sends the release event.
|
||||
* @param released Whether the Buffer got released by the Wayland server.
|
||||
* @see isReleased
|
||||
**/
|
||||
void setReleased(bool released);
|
||||
/**
|
||||
* Sets whether the Buffer is used.
|
||||
* If the Buffer may not be reused when it gets released, the user of a Buffer should
|
||||
* mark the Buffer as used. This is needed for example when the memory is shared with
|
||||
* a QImage. As soon as the Buffer can be reused again one should call this method with
|
||||
* @c false again.
|
||||
*
|
||||
* By default a Buffer is not used.
|
||||
*
|
||||
* @param used Whether the Buffer should be marked as used.
|
||||
* @see isUsed
|
||||
**/
|
||||
void setUsed(bool used);
|
||||
|
||||
wl_buffer *buffer() const;
|
||||
/**
|
||||
* @returns The size of this Buffer.
|
||||
**/
|
||||
QSize size() const;
|
||||
/**
|
||||
* @returns The stride (bytes per line) of this Buffer.
|
||||
**/
|
||||
int32_t stride() const;
|
||||
/**
|
||||
* @returns @c true if the Wayland server doesn't need the Buffer anymore.
|
||||
**/
|
||||
bool isReleased() const;
|
||||
/**
|
||||
* @returns @c true if the Buffer's user is still needing the Buffer.
|
||||
**/
|
||||
bool isUsed() const;
|
||||
/**
|
||||
* @returns the memory address of this Buffer.
|
||||
**/
|
||||
uchar *address();
|
||||
/**
|
||||
* @returns The image format used by this Buffer.
|
||||
**/
|
||||
Format format() const;
|
||||
|
||||
operator wl_buffer *();
|
||||
operator wl_buffer *() const;
|
||||
|
||||
typedef QWeakPointer<Buffer> Ptr;
|
||||
|
||||
/**
|
||||
* Helper method to get the id for a provided native buffer.
|
||||
* @since 5.3
|
||||
**/
|
||||
static quint32 getId(wl_buffer *b);
|
||||
|
||||
private:
|
||||
friend class ShmPool;
|
||||
explicit Buffer(ShmPool *parent, wl_buffer *buffer, const QSize &size, int32_t stride, size_t offset, Format format);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_BUFFER_P_H
|
||||
#define WAYLAND_BUFFER_P_H
|
||||
#include "buffer.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN Buffer::Private
|
||||
{
|
||||
public:
|
||||
Private(Buffer *q, ShmPool *parent, wl_buffer *nativeBuffer, const QSize &size, int32_t stride, size_t offset, Format format);
|
||||
~Private();
|
||||
void destroy();
|
||||
|
||||
ShmPool *shm;
|
||||
WaylandPointer<wl_buffer, wl_buffer_destroy> nativeBuffer;
|
||||
bool released;
|
||||
QSize size;
|
||||
int32_t stride;
|
||||
size_t offset;
|
||||
bool used;
|
||||
Format format;
|
||||
|
||||
private:
|
||||
Buffer *q;
|
||||
static const struct wl_buffer_listener s_listener;
|
||||
static void releasedCallback(void *data, wl_buffer *wl_buffer);
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "compositor.h"
|
||||
#include "event_queue.h"
|
||||
#include "region.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Qt
|
||||
#include <QGuiApplication>
|
||||
#include <QRegion>
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN Compositor::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
WaylandPointer<wl_compositor, wl_compositor_destroy> compositor;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
Compositor::Compositor(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
Compositor::~Compositor()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
Compositor *Compositor::fromApplication(QObject *parent)
|
||||
{
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native) {
|
||||
return nullptr;
|
||||
}
|
||||
wl_compositor *compositor = reinterpret_cast<wl_compositor *>(native->nativeResourceForIntegration(QByteArrayLiteral("compositor")));
|
||||
if (!compositor) {
|
||||
return nullptr;
|
||||
}
|
||||
Compositor *c = new Compositor(parent);
|
||||
c->d->compositor.setup(compositor, true);
|
||||
return c;
|
||||
}
|
||||
|
||||
void Compositor::setup(wl_compositor *compositor)
|
||||
{
|
||||
Q_ASSERT(compositor);
|
||||
Q_ASSERT(!d->compositor);
|
||||
d->compositor.setup(compositor);
|
||||
}
|
||||
|
||||
void Compositor::release()
|
||||
{
|
||||
d->compositor.release();
|
||||
}
|
||||
|
||||
void Compositor::destroy()
|
||||
{
|
||||
d->compositor.destroy();
|
||||
}
|
||||
|
||||
void Compositor::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *Compositor::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
Surface *Compositor::createSurface(QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Surface *s = new Surface(parent);
|
||||
auto w = wl_compositor_create_surface(d->compositor);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
s->setup(w);
|
||||
return s;
|
||||
}
|
||||
|
||||
Region *Compositor::createRegion(QObject *parent)
|
||||
{
|
||||
return createRegion(QRegion(), parent);
|
||||
}
|
||||
|
||||
Region *Compositor::createRegion(const QRegion ®ion, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Region *r = new Region(region, parent);
|
||||
auto w = wl_compositor_create_region(d->compositor);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
r->setup(w);
|
||||
return r;
|
||||
}
|
||||
|
||||
std::unique_ptr<Region> Compositor::createRegion(const QRegion ®ion)
|
||||
{
|
||||
return std::unique_ptr<Region>(createRegion(region, nullptr));
|
||||
}
|
||||
|
||||
Compositor::operator wl_compositor *()
|
||||
{
|
||||
return d->compositor;
|
||||
}
|
||||
|
||||
Compositor::operator wl_compositor *() const
|
||||
{
|
||||
return d->compositor;
|
||||
}
|
||||
|
||||
bool Compositor::isValid() const
|
||||
{
|
||||
return d->compositor.isValid();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_compositor.cpp"
|
||||
@@ -0,0 +1,180 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_COMPOSITOR_H
|
||||
#define WAYLAND_COMPOSITOR_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_compositor;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Region;
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the wl_compositor interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the wl_compositor interface.
|
||||
* It's main purpose is to create a Surface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the Compositor interface:
|
||||
* @code
|
||||
* Compositor *c = registry->createCompositor(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the Compositor and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* Compositor *c = new Compositor;
|
||||
* c->setup(registry->bindCompositor(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The Compositor can be used as a drop-in replacement for any wl_compositor
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Compositor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new Compositor.
|
||||
* Note: after constructing the Compositor it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use Compositor prefer using
|
||||
* Registry::createCompositor.
|
||||
**/
|
||||
explicit Compositor(QObject *parent = nullptr);
|
||||
~Compositor() override;
|
||||
|
||||
/**
|
||||
* Creates a Compositor for the used QGuiApplication.
|
||||
* This is an integration feature for QtWayland. On non-wayland platforms this method returns
|
||||
* @c nullptr.
|
||||
*
|
||||
* The returned Compositor will be fully setup, which means it manages a wl_compositor.
|
||||
* When the created Compositor gets destroyed the managed wl_compositor won't be disconnected
|
||||
* as that's managed by Qt.
|
||||
* @since 5.4
|
||||
**/
|
||||
static Compositor *fromApplication(QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a wl_compositor.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this Compositor to manage the @p compositor.
|
||||
* When using Registry::createCompositor there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_compositor *compositor);
|
||||
/**
|
||||
* Releases the wl_compositor interface.
|
||||
* After the interface has been released the Compositor instance is no
|
||||
* longer valid and can be setup with another wl_compositor interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this Compositor.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_compositor interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, compositor, &Compositor::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating a Surface.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating a Surface.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Creates and setup a new Surface with @p parent.
|
||||
* @param parent The parent to pass to the Surface.
|
||||
* @returns The new created Surface
|
||||
**/
|
||||
Surface *createSurface(QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Creates and setup a new Region with @p parent.
|
||||
* @param parent The parent to pass to the Region.
|
||||
* @returns The new created Region
|
||||
**/
|
||||
Region *createRegion(QObject *parent = nullptr);
|
||||
/**
|
||||
* Creates and setup a new Region with @p parent.
|
||||
*
|
||||
* The @p region is directly added to the created Region.
|
||||
* @param parent The parent to pass to the Region.
|
||||
* @param region The region to install on the newly created Region
|
||||
* @returns The new created Region
|
||||
**/
|
||||
Region *createRegion(const QRegion ®ion, QObject *parent);
|
||||
/**
|
||||
* Creates and setup a new Region with @p region installed.
|
||||
*
|
||||
* This overloaded convenience method is intended to be used in the
|
||||
* case that the Region is only needed to setup e.g. input region on
|
||||
* a Surface and is afterwards no longer needed. Setting the input
|
||||
* region has copy semantics and the Region can be destroyed afterwards.
|
||||
* This allows to simplify setting the input region to:
|
||||
*
|
||||
* @code
|
||||
* Surface *s = compositor->createSurface();
|
||||
* s->setInputRegion(compositor->createRegion(QRegion(0, 0, 10, 10)).get());
|
||||
* @endcode
|
||||
*
|
||||
* @param region The region to install on the newly created Region
|
||||
* @returns The new created Region
|
||||
**/
|
||||
std::unique_ptr<Region> createRegion(const QRegion ®ion);
|
||||
|
||||
operator wl_compositor *();
|
||||
operator wl_compositor *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the Compositor got created by
|
||||
* Registry::createCompositor
|
||||
*
|
||||
* @since 5.5
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,318 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "connection_thread.h"
|
||||
#include "logging.h"
|
||||
// Qt
|
||||
#include <QAbstractEventDispatcher>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QGuiApplication>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
#include <QSocketNotifier>
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
// Wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
#include <poll.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN ConnectionThread::Private
|
||||
{
|
||||
public:
|
||||
Private(ConnectionThread *q);
|
||||
~Private();
|
||||
void doInitConnection();
|
||||
void setupSocketNotifier();
|
||||
void setupSocketFileWatcher();
|
||||
void dispatchEvents();
|
||||
|
||||
wl_display *display = nullptr;
|
||||
int fd = -1;
|
||||
QString socketName;
|
||||
QDir runtimeDir;
|
||||
QScopedPointer<QSocketNotifier> socketNotifier;
|
||||
QScopedPointer<QFileSystemWatcher> socketWatcher;
|
||||
bool serverDied = false;
|
||||
bool foreign = false;
|
||||
QMetaObject::Connection eventDispatcherConnection;
|
||||
int error = 0;
|
||||
static QList<ConnectionThread *> connections;
|
||||
static QRecursiveMutex mutex;
|
||||
|
||||
private:
|
||||
ConnectionThread *q;
|
||||
};
|
||||
|
||||
QList<ConnectionThread *> ConnectionThread::Private::connections = QList<ConnectionThread *>{};
|
||||
QRecursiveMutex ConnectionThread::Private::mutex;
|
||||
|
||||
ConnectionThread::Private::Private(ConnectionThread *q)
|
||||
: socketName(QString::fromUtf8(qgetenv("WAYLAND_DISPLAY")))
|
||||
, runtimeDir(QString::fromUtf8(qgetenv("XDG_RUNTIME_DIR")))
|
||||
, q(q)
|
||||
{
|
||||
if (socketName.isEmpty()) {
|
||||
socketName = QStringLiteral("wayland-0");
|
||||
}
|
||||
{
|
||||
QMutexLocker lock(&mutex);
|
||||
connections << q;
|
||||
}
|
||||
}
|
||||
|
||||
ConnectionThread::Private::~Private()
|
||||
{
|
||||
{
|
||||
QMutexLocker lock(&mutex);
|
||||
connections.removeOne(q);
|
||||
}
|
||||
if (display && !foreign) {
|
||||
wl_display_flush(display);
|
||||
wl_display_disconnect(display);
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectionThread::Private::doInitConnection()
|
||||
{
|
||||
if (fd != -1) {
|
||||
display = wl_display_connect_to_fd(fd);
|
||||
} else {
|
||||
display = wl_display_connect(socketName.toUtf8().constData());
|
||||
}
|
||||
if (!display) {
|
||||
qCWarning(KWAYLAND_CLIENT) << "Failed connecting to Wayland display";
|
||||
Q_EMIT q->failed();
|
||||
return;
|
||||
}
|
||||
if (fd != -1) {
|
||||
qCDebug(KWAYLAND_CLIENT) << "Connected to Wayland server over file descriptor:" << fd;
|
||||
} else {
|
||||
qCDebug(KWAYLAND_CLIENT) << "Connected to Wayland server at:" << socketName;
|
||||
}
|
||||
|
||||
// setup socket notifier
|
||||
setupSocketNotifier();
|
||||
setupSocketFileWatcher();
|
||||
Q_EMIT q->connected();
|
||||
}
|
||||
|
||||
void ConnectionThread::Private::setupSocketNotifier()
|
||||
{
|
||||
const int fd = wl_display_get_fd(display);
|
||||
socketNotifier.reset(new QSocketNotifier(fd, QSocketNotifier::Read));
|
||||
QObject::connect(socketNotifier.data(), &QSocketNotifier::activated, q, [this]() {
|
||||
dispatchEvents();
|
||||
});
|
||||
}
|
||||
|
||||
void ConnectionThread::Private::dispatchEvents()
|
||||
{
|
||||
if (!display) {
|
||||
return;
|
||||
}
|
||||
// first dispatch any pending events on the default queue
|
||||
while (wl_display_prepare_read(display) != 0) {
|
||||
wl_display_dispatch_pending(display);
|
||||
}
|
||||
wl_display_flush(display);
|
||||
// then check if there are any new events waiting to be read
|
||||
struct pollfd pfd;
|
||||
pfd.fd = wl_display_get_fd(display);
|
||||
pfd.events = POLLIN;
|
||||
int ret = poll(&pfd, 1, 0);
|
||||
if (ret > 0) {
|
||||
// if yes, read them now
|
||||
wl_display_read_events(display);
|
||||
} else {
|
||||
wl_display_cancel_read(display);
|
||||
}
|
||||
|
||||
// finally, dispatch the default queue and all frame queues
|
||||
if (wl_display_dispatch_pending(display) == -1) {
|
||||
error = wl_display_get_error(display);
|
||||
if (error != 0) {
|
||||
if (display) {
|
||||
free(display);
|
||||
display = nullptr;
|
||||
}
|
||||
Q_EMIT q->errorOccurred();
|
||||
return;
|
||||
}
|
||||
}
|
||||
Q_EMIT q->eventsRead();
|
||||
}
|
||||
|
||||
void ConnectionThread::Private::setupSocketFileWatcher()
|
||||
{
|
||||
if (!runtimeDir.exists() || fd != -1) {
|
||||
return;
|
||||
}
|
||||
socketWatcher.reset(new QFileSystemWatcher);
|
||||
socketWatcher->addPath(runtimeDir.absoluteFilePath(socketName));
|
||||
QObject::connect(socketWatcher.data(), &QFileSystemWatcher::fileChanged, q, [this](const QString &file) {
|
||||
if (QFile::exists(file) || serverDied) {
|
||||
return;
|
||||
}
|
||||
qCWarning(KWAYLAND_CLIENT) << "Connection to server went away";
|
||||
serverDied = true;
|
||||
if (display) {
|
||||
free(display);
|
||||
display = nullptr;
|
||||
}
|
||||
socketNotifier.reset();
|
||||
|
||||
// need a new filesystem watcher
|
||||
socketWatcher.reset(new QFileSystemWatcher);
|
||||
socketWatcher->addPath(runtimeDir.absolutePath());
|
||||
QObject::connect(socketWatcher.data(), &QFileSystemWatcher::directoryChanged, q, [this]() {
|
||||
if (!serverDied) {
|
||||
return;
|
||||
}
|
||||
if (runtimeDir.exists(socketName)) {
|
||||
qCDebug(KWAYLAND_CLIENT) << "Socket reappeared";
|
||||
socketWatcher.reset();
|
||||
serverDied = false;
|
||||
error = 0;
|
||||
q->initConnection();
|
||||
}
|
||||
});
|
||||
Q_EMIT q->connectionDied();
|
||||
});
|
||||
}
|
||||
|
||||
ConnectionThread::ConnectionThread(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
d->eventDispatcherConnection = connect(
|
||||
QCoreApplication::eventDispatcher(),
|
||||
&QAbstractEventDispatcher::aboutToBlock,
|
||||
this,
|
||||
[this] {
|
||||
if (d->display) {
|
||||
wl_display_flush(d->display);
|
||||
}
|
||||
},
|
||||
Qt::DirectConnection);
|
||||
}
|
||||
|
||||
ConnectionThread::ConnectionThread(wl_display *display, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
d->display = display;
|
||||
d->foreign = true;
|
||||
}
|
||||
|
||||
ConnectionThread::~ConnectionThread()
|
||||
{
|
||||
disconnect(d->eventDispatcherConnection);
|
||||
}
|
||||
|
||||
ConnectionThread *ConnectionThread::fromApplication(QObject *parent)
|
||||
{
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native) {
|
||||
return nullptr;
|
||||
}
|
||||
wl_display *display = reinterpret_cast<wl_display *>(native->nativeResourceForIntegration(QByteArrayLiteral("wl_display")));
|
||||
if (!display) {
|
||||
return nullptr;
|
||||
}
|
||||
ConnectionThread *ct = new ConnectionThread(display, parent);
|
||||
connect(native, &QObject::destroyed, ct, &ConnectionThread::connectionDied);
|
||||
return ct;
|
||||
}
|
||||
|
||||
void ConnectionThread::initConnection()
|
||||
{
|
||||
QMetaObject::invokeMethod(this, &ConnectionThread::doInitConnection, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void ConnectionThread::doInitConnection()
|
||||
{
|
||||
d->doInitConnection();
|
||||
}
|
||||
|
||||
void ConnectionThread::setSocketName(const QString &socketName)
|
||||
{
|
||||
if (d->display) {
|
||||
// already initialized
|
||||
return;
|
||||
}
|
||||
d->socketName = socketName;
|
||||
}
|
||||
|
||||
void ConnectionThread::setSocketFd(int fd)
|
||||
{
|
||||
if (d->display) {
|
||||
// already initialized
|
||||
return;
|
||||
}
|
||||
d->fd = fd;
|
||||
}
|
||||
|
||||
wl_display *ConnectionThread::display()
|
||||
{
|
||||
return d->display;
|
||||
}
|
||||
|
||||
QString ConnectionThread::socketName() const
|
||||
{
|
||||
return d->socketName;
|
||||
}
|
||||
|
||||
void ConnectionThread::flush()
|
||||
{
|
||||
if (!d->display) {
|
||||
return;
|
||||
}
|
||||
wl_display_flush(d->display);
|
||||
}
|
||||
|
||||
void ConnectionThread::roundtrip()
|
||||
{
|
||||
if (!d->display) {
|
||||
return;
|
||||
}
|
||||
if (d->foreign) {
|
||||
// try to perform roundtrip through the QPA plugin if it's supported
|
||||
if (QPlatformNativeInterface *native = qApp->platformNativeInterface()) {
|
||||
// in case the platform provides a dedicated roundtrip function use that install of wl_display_roundtrip
|
||||
QFunctionPointer roundtripFunction = native->platformFunction(QByteArrayLiteral("roundtrip"));
|
||||
if (roundtripFunction) {
|
||||
roundtripFunction();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
wl_display_roundtrip(d->display);
|
||||
}
|
||||
|
||||
bool ConnectionThread::hasError() const
|
||||
{
|
||||
return d->error != 0;
|
||||
}
|
||||
|
||||
int ConnectionThread::errorCode() const
|
||||
{
|
||||
return d->error;
|
||||
}
|
||||
|
||||
QList<ConnectionThread *> ConnectionThread::connections()
|
||||
{
|
||||
return Private::connections;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_connection_thread.cpp"
|
||||
@@ -0,0 +1,261 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_CONNECTION_THREAD_H
|
||||
#define WAYLAND_CONNECTION_THREAD_H
|
||||
|
||||
#include <QList>
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_display;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
/**
|
||||
* @short KWayland Client.
|
||||
*
|
||||
* This namespace groups all classes related to the Client module.
|
||||
*
|
||||
* The main entry point into the KWayland::Client API is the ConnectionThread class.
|
||||
* It allows to create a Wayland client connection either in a native way or wrap a
|
||||
* connection created by the QtWayland QPA plugin.
|
||||
*
|
||||
* KWayland::Client provides one the one hand a low-level API to interact with the
|
||||
* Wayland API, on the other hand an easy to use convenience API. Each class directly
|
||||
* relates to a low-level Wayland type and allows direct casting into the type.
|
||||
*
|
||||
* On the convenience side KWayland::Client allows easy creation of objects, signals
|
||||
* emitted for Wayland events and easy conversion from Qt to Wayland types.
|
||||
*
|
||||
* Once one has a ConnectionThread created, it's possible to setup a Registry to
|
||||
* get a listing of all registered globals. For each global the Registry provides a convenience
|
||||
* method to create the resource.
|
||||
*
|
||||
* @see ConnectionThread
|
||||
* @see Registry
|
||||
**/
|
||||
namespace Client
|
||||
{
|
||||
/**
|
||||
* @short Creates and manages the connection to a Wayland server.
|
||||
*
|
||||
* The purpose of this class is to create the connection to a Wayland server
|
||||
* and to manage it. As the name suggests it's intended to move instances of
|
||||
* this class into a dedicated thread. This also means that this class doesn't
|
||||
* inherit QThread. In order to use it in a threaded way one needs to create a
|
||||
* QThread and move the object there:
|
||||
*
|
||||
* @code
|
||||
* ConnectionThread *connection = new ConnectionThread;
|
||||
* QThread *thread = new QThread;
|
||||
* connection->moveToThread(thread);
|
||||
* thread->start();
|
||||
* @endcode
|
||||
*
|
||||
* To finalize the initialization of the connection one needs to call @link ::initConnection @endlink.
|
||||
* This starts an asynchronous connection initialization. In case the initialization
|
||||
* succeeds the signal @link ::connected @endlink will be emitted, otherwise @link ::failed @endlink will
|
||||
* be emitted:
|
||||
*
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connected, [connection] {
|
||||
* qDebug() << "Successfully connected to Wayland server at socket:" << connection->socketName();
|
||||
* });
|
||||
* connect(connection, &ConnectionThread::failed, [connection] {
|
||||
* qDebug() << "Failed to connect to Wayland server at socket:" << connection->socketName();
|
||||
* });
|
||||
* connection->initConnection();
|
||||
* @endcode
|
||||
*
|
||||
* This class is also responsible for dispatching events. Whenever new data is available on
|
||||
* the Wayland socket, it will be dispatched and the signal @link ::eventsRead @endlink is emitted.
|
||||
* This allows further event queues in other threads to also dispatch their events.
|
||||
*
|
||||
* Furthermore this class flushes the Wayland connection whenever the QAbstractEventDispatcher
|
||||
* is about to block.
|
||||
*
|
||||
* To disconnect the connection to the Wayland server one should delete the instance of this
|
||||
* class and quit the dedicated thread:
|
||||
*
|
||||
* @code
|
||||
* connection->deleteLater();
|
||||
* thread->quit();
|
||||
* thread->wait();
|
||||
* @endcode
|
||||
*
|
||||
* In addition the ConnectionThread provides integration with QtWayland QPA plugin. For that
|
||||
* it provides a static factory method:
|
||||
*
|
||||
* @code
|
||||
* auto connection = ConnectionThread::fromApplication();
|
||||
* @endcode
|
||||
*
|
||||
* The semantics of the ConnectionThread are slightly changed if it's integrated with QtWayland.
|
||||
* The ConnectionThread does not hold the connection, does not emit connected or released signals
|
||||
* (one can safely assume that the connection is valid when integrating with the Qt application),
|
||||
* does not dispatch events. Given that the use case of the ConnectionThread is rather limited to
|
||||
* a convenient API around wl_display to allow easily setup an own Registry in a QtWayland powered
|
||||
* application. Also moving the ConnectionThread to a different thread is not necessarily recommended
|
||||
* in that case as QtWayland holds it's connection in an own thread anyway.
|
||||
*
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT ConnectionThread : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ConnectionThread(QObject *parent = nullptr);
|
||||
~ConnectionThread() override;
|
||||
|
||||
/**
|
||||
* Creates a ConnectionThread for the used QGuiApplication.
|
||||
* This is an integration feature for QtWayland. On non-wayland platforms this method returns
|
||||
* @c nullptr.
|
||||
*
|
||||
* The returned ConnectionThread will be fully setup, which means it manages a wl_display.
|
||||
* There is no need to initConnection and the connected or failed signals won't be emitted.
|
||||
* When the created ConnectionThread gets destroyed the managed wl_display won't be disconnected
|
||||
* as that's managed by Qt.
|
||||
*
|
||||
* The returned ConnectionThread is not able to detect (protocol) error. The signal
|
||||
* {@link errorOccurred} won't be emitted, {@link hasError} will return @c false, even if the
|
||||
* actual connection held by QtWayland is on error. The behavior of QtWayland is to exit the
|
||||
* application on error.
|
||||
*
|
||||
* @since 5.4
|
||||
**/
|
||||
static ConnectionThread *fromApplication(QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* The display this ConnectionThread is connected to.
|
||||
* As long as there is no connection this method returns @c null.
|
||||
* @see initConnection
|
||||
**/
|
||||
wl_display *display();
|
||||
/**
|
||||
* @returns the name of the socket it connects to.
|
||||
**/
|
||||
QString socketName() const;
|
||||
/**
|
||||
* Sets the @p socketName to connect to.
|
||||
* Only applies if called before calling initConnection.
|
||||
* The default socket name is derived from environment variable WAYLAND_DISPLAY
|
||||
* and if not set is hard coded to "wayland-0".
|
||||
*
|
||||
* The socket name will be ignored if a file descriptor has been set through @link setSocketFd @endlink.
|
||||
*
|
||||
* @see setSocketFd
|
||||
**/
|
||||
void setSocketName(const QString &socketName);
|
||||
/**
|
||||
* Sets the socket @p fd to connect to.
|
||||
* Only applies if called before calling initConnection.
|
||||
* If this method is invoked, the connection will be created on the file descriptor
|
||||
* and not on the socket name passed through @link setSocketName @endlink or through the
|
||||
* default environment variable WAYLAND_DISPLAY.
|
||||
* @see setSocketName
|
||||
**/
|
||||
void setSocketFd(int fd);
|
||||
|
||||
/**
|
||||
* Trigger a blocking roundtrip to the Wayland server. Ensures that all events are processed
|
||||
* before returning to the event loop.
|
||||
*
|
||||
* @since 5.4
|
||||
**/
|
||||
void roundtrip();
|
||||
|
||||
/**
|
||||
* @returns whether the Wayland connection experienced an error
|
||||
* @see errorCode
|
||||
* @see errorOccurred
|
||||
* @since 5.23
|
||||
**/
|
||||
bool hasError() const;
|
||||
|
||||
/**
|
||||
* @returns the error code of the last occurred error or @c 0 if the connection doesn't have an error
|
||||
* @see hasError
|
||||
* @see errorOccurred
|
||||
* @since 5.23
|
||||
**/
|
||||
int errorCode() const;
|
||||
|
||||
/**
|
||||
* @returns all connections created in this application
|
||||
* @since 5.37
|
||||
**/
|
||||
static QList<ConnectionThread *> connections();
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Initializes the connection in an asynchronous way.
|
||||
* In case the connection gets established the signal @link ::connected @endlink will be
|
||||
* emitted, on failure the signal @link ::failed @endlink will be emitted.
|
||||
*
|
||||
* @see connected
|
||||
* @see failed
|
||||
**/
|
||||
void initConnection();
|
||||
|
||||
/**
|
||||
* Explicitly flush the Wayland display.
|
||||
* @since 5.3
|
||||
**/
|
||||
void flush();
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted once a connection to a Wayland server is established.
|
||||
* Normally emitted after invoking initConnection(), but might also be
|
||||
* emitted after re-connecting to another server.
|
||||
**/
|
||||
void connected();
|
||||
/**
|
||||
* Emitted if connecting to a Wayland server failed.
|
||||
**/
|
||||
void failed();
|
||||
/**
|
||||
* Emitted whenever new events are ready to be read.
|
||||
**/
|
||||
void eventsRead();
|
||||
/**
|
||||
* Emitted if the Wayland server connection dies.
|
||||
* If the socket reappears, it is tried to reconnect.
|
||||
**/
|
||||
void connectionDied();
|
||||
/**
|
||||
* The Wayland connection experienced a fatal error.
|
||||
* The ConnectionThread is no longer valid, no requests may be sent.
|
||||
* This has the same effects as {@link connectionDied}.
|
||||
*
|
||||
* @see hasError
|
||||
* @see errorCode
|
||||
* @since 5.23
|
||||
**/
|
||||
void errorOccurred();
|
||||
|
||||
protected:
|
||||
/*
|
||||
* Creates a connection thread from an existing wl_display object
|
||||
* @see ConnectionThread::fromApplication
|
||||
*/
|
||||
explicit ConnectionThread(wl_display *display, QObject *parent);
|
||||
|
||||
private Q_SLOTS:
|
||||
/**
|
||||
* @internal
|
||||
**/
|
||||
void doInitConnection();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "contrast.h"
|
||||
#include "event_queue.h"
|
||||
#include "region.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <wayland-contrast-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN ContrastManager::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
WaylandPointer<org_kde_kwin_contrast_manager, org_kde_kwin_contrast_manager_destroy> manager;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
ContrastManager::ContrastManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
ContrastManager::~ContrastManager()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void ContrastManager::release()
|
||||
{
|
||||
d->manager.release();
|
||||
}
|
||||
|
||||
void ContrastManager::destroy()
|
||||
{
|
||||
d->manager.destroy();
|
||||
}
|
||||
|
||||
bool ContrastManager::isValid() const
|
||||
{
|
||||
return d->manager.isValid();
|
||||
}
|
||||
|
||||
void ContrastManager::setup(org_kde_kwin_contrast_manager *manager)
|
||||
{
|
||||
Q_ASSERT(manager);
|
||||
Q_ASSERT(!d->manager);
|
||||
d->manager.setup(manager);
|
||||
}
|
||||
|
||||
void ContrastManager::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *ContrastManager::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
Contrast *ContrastManager::createContrast(Surface *surface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Contrast *s = new Contrast(parent);
|
||||
auto w = org_kde_kwin_contrast_manager_create(d->manager, *surface);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
s->setup(w);
|
||||
return s;
|
||||
}
|
||||
|
||||
void ContrastManager::removeContrast(Surface *surface)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
org_kde_kwin_contrast_manager_unset(d->manager, *surface);
|
||||
}
|
||||
|
||||
ContrastManager::operator org_kde_kwin_contrast_manager *()
|
||||
{
|
||||
return d->manager;
|
||||
}
|
||||
|
||||
ContrastManager::operator org_kde_kwin_contrast_manager *() const
|
||||
{
|
||||
return d->manager;
|
||||
}
|
||||
|
||||
class Contrast::Private
|
||||
{
|
||||
public:
|
||||
WaylandPointer<org_kde_kwin_contrast, org_kde_kwin_contrast_release> contrast;
|
||||
};
|
||||
|
||||
Contrast::Contrast(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
Contrast::~Contrast()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void Contrast::release()
|
||||
{
|
||||
d->contrast.release();
|
||||
}
|
||||
|
||||
void Contrast::setup(org_kde_kwin_contrast *contrast)
|
||||
{
|
||||
Q_ASSERT(contrast);
|
||||
Q_ASSERT(!d->contrast);
|
||||
d->contrast.setup(contrast);
|
||||
}
|
||||
|
||||
void Contrast::destroy()
|
||||
{
|
||||
d->contrast.destroy();
|
||||
}
|
||||
|
||||
bool Contrast::isValid() const
|
||||
{
|
||||
return d->contrast.isValid();
|
||||
}
|
||||
|
||||
void Contrast::commit()
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
org_kde_kwin_contrast_commit(d->contrast);
|
||||
}
|
||||
|
||||
void Contrast::setRegion(Region *region)
|
||||
{
|
||||
org_kde_kwin_contrast_set_region(d->contrast, *region);
|
||||
}
|
||||
|
||||
void Contrast::setContrast(qreal contrast)
|
||||
{
|
||||
org_kde_kwin_contrast_set_contrast(d->contrast, wl_fixed_from_double(contrast));
|
||||
}
|
||||
|
||||
void Contrast::setIntensity(qreal intensity)
|
||||
{
|
||||
org_kde_kwin_contrast_set_intensity(d->contrast, wl_fixed_from_double(intensity));
|
||||
}
|
||||
|
||||
void Contrast::setSaturation(qreal saturation)
|
||||
{
|
||||
org_kde_kwin_contrast_set_saturation(d->contrast, wl_fixed_from_double(saturation));
|
||||
}
|
||||
|
||||
void Contrast::setFrost(QColor frost)
|
||||
{
|
||||
if (org_kde_kwin_contrast_get_version(d->contrast) < ORG_KDE_KWIN_CONTRAST_SET_FROST_SINCE_VERSION) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (frost.isValid()) {
|
||||
org_kde_kwin_contrast_set_frost(d->contrast, frost.red(), frost.green(), frost.blue(), frost.alpha());
|
||||
} else {
|
||||
org_kde_kwin_contrast_unset_frost(d->contrast);
|
||||
}
|
||||
}
|
||||
|
||||
Contrast::operator org_kde_kwin_contrast *()
|
||||
{
|
||||
return d->contrast;
|
||||
}
|
||||
|
||||
Contrast::operator org_kde_kwin_contrast *() const
|
||||
{
|
||||
return d->contrast;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_contrast.cpp"
|
||||
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
SPDX-FileCopyrightText: 2015 Marco Martin <mart@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CONTRAST_H
|
||||
#define KWAYLAND_CONTRAST_H
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include <QObject>
|
||||
#include <QPoint>
|
||||
#include <QSize>
|
||||
#include <QColor>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct org_kde_kwin_contrast;
|
||||
struct org_kde_kwin_contrast_manager;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Contrast;
|
||||
class Surface;
|
||||
class Region;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
class KWAYLANDCLIENT_EXPORT ContrastManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new ContrastManager.
|
||||
* Note: after constructing the ContrastManager it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use ContrastManager prefer using
|
||||
* Registry::createContrastManager.
|
||||
**/
|
||||
explicit ContrastManager(QObject *parent = nullptr);
|
||||
~ContrastManager() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_kwin_contrast_manager.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this ContrastManager to manage the @p contrastManager.
|
||||
* When using Registry::createContrastManager there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_kwin_contrast_manager *contrastManager);
|
||||
/**
|
||||
* Releases the org_kde_kwin_contrast_manager interface.
|
||||
* After the interface has been released the ContrastManager instance is no
|
||||
* longer valid and can be setup with another org_kde_kwin_contrast_manager interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this ContrastManager.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_kwin_contrast_manager interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, contrastManager, &ContrastManager::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating a Contrast.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating a Contrast.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Creates and setup a new Contrast with @p parent.
|
||||
* @param parent The parent to pass to the Contrast.
|
||||
* @returns The new created Contrast
|
||||
**/
|
||||
Contrast *createContrast(Surface *surface, QObject *parent = nullptr);
|
||||
void removeContrast(Surface *surface);
|
||||
|
||||
operator org_kde_kwin_contrast_manager *();
|
||||
operator org_kde_kwin_contrast_manager *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the ContrastManager got created by
|
||||
* Registry::createContrastManager
|
||||
*
|
||||
* @since 5.5
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Wrapper for the org_kde_kwin_contrast interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the org_kde_kwin_contrast interface.
|
||||
* To create a Contrast call ContrastManager::createContrast.
|
||||
*
|
||||
* The main purpose of this class is to setup the next frame which
|
||||
* should be rendered. Therefore it provides methods to add damage
|
||||
* and to attach a new Buffer and to finalize the frame by calling
|
||||
* commit.
|
||||
*
|
||||
* @see ContrastManager
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Contrast : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~Contrast() override;
|
||||
|
||||
/**
|
||||
* Setup this Contrast to manage the @p contrast.
|
||||
* When using ContrastManager::createContrast there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_kwin_contrast *contrast);
|
||||
/**
|
||||
* Releases the org_kde_kwin_contrast interface.
|
||||
* After the interface has been released the Contrast instance is no
|
||||
* longer valid and can be setup with another org_kde_kwin_contrast interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this Contrast.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_kwin_contrast interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* Contrast gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_kwin_contrast.
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
void commit();
|
||||
|
||||
/**
|
||||
* Sets the area of the window that will have a contrasted
|
||||
* background.
|
||||
* The region will have to be created with
|
||||
* Compositor::createRegion(QRegion)
|
||||
*/
|
||||
void setRegion(Region *region);
|
||||
void setContrast(qreal contrast);
|
||||
void setIntensity(qreal intensity);
|
||||
void setSaturation(qreal saturation);
|
||||
|
||||
void setFrost(QColor frost);
|
||||
|
||||
operator org_kde_kwin_contrast *();
|
||||
operator org_kde_kwin_contrast *() const;
|
||||
|
||||
private:
|
||||
friend class ContrastManager;
|
||||
explicit Contrast(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "datadevice.h"
|
||||
#include "datasource.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Qt
|
||||
#include <QPointer>
|
||||
// Wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN DataDevice::Private
|
||||
{
|
||||
public:
|
||||
explicit Private(DataDevice *q);
|
||||
void setup(wl_data_device *d);
|
||||
|
||||
WaylandPointer<wl_data_device, wl_data_device_release> device;
|
||||
QScopedPointer<DataOffer> selectionOffer;
|
||||
struct Drag {
|
||||
QPointer<DataOffer> offer;
|
||||
QPointer<Surface> surface;
|
||||
};
|
||||
Drag drag;
|
||||
|
||||
private:
|
||||
void dataOffer(wl_data_offer *id);
|
||||
void selection(wl_data_offer *id);
|
||||
void dragEnter(quint32 serial, const QPointer<Surface> &surface, const QPointF &relativeToSurface, wl_data_offer *dataOffer);
|
||||
void dragLeft();
|
||||
static void dataOfferCallback(void *data, wl_data_device *dataDevice, wl_data_offer *id);
|
||||
static void enterCallback(void *data, wl_data_device *dataDevice, uint32_t serial, wl_surface *surface, wl_fixed_t x, wl_fixed_t y, wl_data_offer *id);
|
||||
static void leaveCallback(void *data, wl_data_device *dataDevice);
|
||||
static void motionCallback(void *data, wl_data_device *dataDevice, uint32_t time, wl_fixed_t x, wl_fixed_t y);
|
||||
static void dropCallback(void *data, wl_data_device *dataDevice);
|
||||
static void selectionCallback(void *data, wl_data_device *dataDevice, wl_data_offer *id);
|
||||
|
||||
static const struct wl_data_device_listener s_listener;
|
||||
|
||||
DataDevice *q;
|
||||
DataOffer *lastOffer = nullptr;
|
||||
};
|
||||
|
||||
const wl_data_device_listener DataDevice::Private::s_listener =
|
||||
{dataOfferCallback, enterCallback, leaveCallback, motionCallback, dropCallback, selectionCallback};
|
||||
|
||||
void DataDevice::Private::dataOfferCallback(void *data, wl_data_device *dataDevice, wl_data_offer *id)
|
||||
{
|
||||
auto d = reinterpret_cast<Private *>(data);
|
||||
Q_ASSERT(d->device == dataDevice);
|
||||
d->dataOffer(id);
|
||||
}
|
||||
|
||||
void DataDevice::Private::dataOffer(wl_data_offer *id)
|
||||
{
|
||||
Q_ASSERT(!lastOffer);
|
||||
lastOffer = new DataOffer(q, id);
|
||||
Q_ASSERT(lastOffer->isValid());
|
||||
}
|
||||
|
||||
void DataDevice::Private::enterCallback(void *data,
|
||||
wl_data_device *dataDevice,
|
||||
uint32_t serial,
|
||||
wl_surface *surface,
|
||||
wl_fixed_t x,
|
||||
wl_fixed_t y,
|
||||
wl_data_offer *id)
|
||||
{
|
||||
auto d = reinterpret_cast<Private *>(data);
|
||||
Q_ASSERT(d->device == dataDevice);
|
||||
d->dragEnter(serial, QPointer<Surface>(Surface::get(surface)), QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), id);
|
||||
}
|
||||
|
||||
void DataDevice::Private::dragEnter(quint32 serial, const QPointer<Surface> &surface, const QPointF &relativeToSurface, wl_data_offer *dataOffer)
|
||||
{
|
||||
drag.surface = surface;
|
||||
Q_ASSERT(*lastOffer == dataOffer);
|
||||
drag.offer = lastOffer;
|
||||
lastOffer = nullptr;
|
||||
Q_EMIT q->dragEntered(serial, relativeToSurface);
|
||||
}
|
||||
|
||||
void DataDevice::Private::leaveCallback(void *data, wl_data_device *dataDevice)
|
||||
{
|
||||
auto d = reinterpret_cast<Private *>(data);
|
||||
Q_ASSERT(d->device == dataDevice);
|
||||
d->dragLeft();
|
||||
}
|
||||
|
||||
void DataDevice::Private::dragLeft()
|
||||
{
|
||||
if (drag.offer) {
|
||||
delete drag.offer;
|
||||
}
|
||||
drag = Drag();
|
||||
Q_EMIT q->dragLeft();
|
||||
}
|
||||
|
||||
void DataDevice::Private::motionCallback(void *data, wl_data_device *dataDevice, uint32_t time, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
auto d = reinterpret_cast<Private *>(data);
|
||||
Q_ASSERT(d->device == dataDevice);
|
||||
Q_EMIT d->q->dragMotion(QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), time);
|
||||
}
|
||||
|
||||
void DataDevice::Private::dropCallback(void *data, wl_data_device *dataDevice)
|
||||
{
|
||||
auto d = reinterpret_cast<Private *>(data);
|
||||
Q_ASSERT(d->device == dataDevice);
|
||||
Q_EMIT d->q->dropped();
|
||||
}
|
||||
|
||||
void DataDevice::Private::selectionCallback(void *data, wl_data_device *dataDevice, wl_data_offer *id)
|
||||
{
|
||||
auto d = reinterpret_cast<Private *>(data);
|
||||
Q_ASSERT(d->device == dataDevice);
|
||||
d->selection(id);
|
||||
}
|
||||
|
||||
void DataDevice::Private::selection(wl_data_offer *id)
|
||||
{
|
||||
if (!id) {
|
||||
selectionOffer.reset();
|
||||
Q_EMIT q->selectionCleared();
|
||||
return;
|
||||
}
|
||||
Q_ASSERT(*lastOffer == id);
|
||||
selectionOffer.reset(lastOffer);
|
||||
lastOffer = nullptr;
|
||||
Q_EMIT q->selectionOffered(selectionOffer.data());
|
||||
}
|
||||
|
||||
DataDevice::Private::Private(DataDevice *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void DataDevice::Private::setup(wl_data_device *d)
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
Q_ASSERT(!device.isValid());
|
||||
device.setup(d);
|
||||
wl_data_device_add_listener(device, &s_listener, this);
|
||||
}
|
||||
|
||||
DataDevice::DataDevice(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
DataDevice::~DataDevice()
|
||||
{
|
||||
if (d->drag.offer) {
|
||||
delete d->drag.offer;
|
||||
}
|
||||
release();
|
||||
}
|
||||
|
||||
void DataDevice::destroy()
|
||||
{
|
||||
d->device.destroy();
|
||||
}
|
||||
|
||||
void DataDevice::release()
|
||||
{
|
||||
d->device.release();
|
||||
}
|
||||
|
||||
bool DataDevice::isValid() const
|
||||
{
|
||||
return d->device.isValid();
|
||||
}
|
||||
|
||||
void DataDevice::setup(wl_data_device *dataDevice)
|
||||
{
|
||||
d->setup(dataDevice);
|
||||
}
|
||||
|
||||
void DataDevice::startDragInternally(quint32 serial, Surface *origin, Surface *icon)
|
||||
{
|
||||
startDrag(serial, nullptr, origin, icon);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
static wl_data_source *dataSource(const DataSource *source)
|
||||
{
|
||||
if (!source) {
|
||||
return nullptr;
|
||||
}
|
||||
return *source;
|
||||
}
|
||||
}
|
||||
|
||||
void DataDevice::startDrag(quint32 serial, DataSource *source, Surface *origin, Surface *icon)
|
||||
{
|
||||
wl_data_device_start_drag(d->device, dataSource(source), *origin, icon ? (wl_surface *)*icon : nullptr, serial);
|
||||
}
|
||||
|
||||
void DataDevice::setSelection(quint32 serial, DataSource *source)
|
||||
{
|
||||
wl_data_device_set_selection(d->device, dataSource(source), serial);
|
||||
}
|
||||
|
||||
void DataDevice::clearSelection(quint32 serial)
|
||||
{
|
||||
setSelection(serial);
|
||||
}
|
||||
|
||||
DataOffer *DataDevice::offeredSelection() const
|
||||
{
|
||||
return d->selectionOffer.data();
|
||||
}
|
||||
|
||||
QPointer<Surface> DataDevice::dragSurface() const
|
||||
{
|
||||
return d->drag.surface;
|
||||
}
|
||||
|
||||
DataOffer *DataDevice::dragOffer() const
|
||||
{
|
||||
return d->drag.offer;
|
||||
}
|
||||
|
||||
DataDevice::operator wl_data_device *()
|
||||
{
|
||||
return d->device;
|
||||
}
|
||||
|
||||
DataDevice::operator wl_data_device *() const
|
||||
{
|
||||
return d->device;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_datadevice.cpp"
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_DATADEVICE_H
|
||||
#define WAYLAND_DATADEVICE_H
|
||||
|
||||
#include "dataoffer.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_data_device;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class DataSource;
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
* @short DataDevice allows clients to share data by copy-and-paste and drag-and-drop.
|
||||
*
|
||||
* This class is a convenient wrapper for the wl_data_device interface.
|
||||
* To create a DataDevice call DataDeviceManager::getDataDevice.
|
||||
*
|
||||
* @see DataDeviceManager
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT DataDevice : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DataDevice(QObject *parent = nullptr);
|
||||
~DataDevice() override;
|
||||
|
||||
/**
|
||||
* Setup this DataDevice to manage the @p dataDevice.
|
||||
* When using DataDeviceManager::createDataDevice there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_data_device *dataDevice);
|
||||
/**
|
||||
* Releases the wl_data_device interface.
|
||||
* After the interface has been released the DataDevice instance is no
|
||||
* longer valid and can be setup with another wl_data_device interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this DataDevice.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_data_device interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* DataDevice gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* @returns @c true if managing a wl_data_device.
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
void startDrag(quint32 serial, DataSource *source, Surface *origin, Surface *icon = nullptr);
|
||||
void startDragInternally(quint32 serial, Surface *origin, Surface *icon = nullptr);
|
||||
|
||||
void setSelection(quint32 serial, DataSource *source = nullptr);
|
||||
void clearSelection(quint32 serial);
|
||||
|
||||
DataOffer *offeredSelection() const;
|
||||
|
||||
/**
|
||||
* @returns the currently focused surface during drag'n'drop on this DataDevice.
|
||||
* @since 5.22
|
||||
**/
|
||||
QPointer<Surface> dragSurface() const;
|
||||
/**
|
||||
* @returns the DataOffer during a drag'n'drop operation.
|
||||
* @since 5.22
|
||||
**/
|
||||
DataOffer *dragOffer() const;
|
||||
|
||||
operator wl_data_device *();
|
||||
operator wl_data_device *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void selectionOffered(KWayland::Client::DataOffer *);
|
||||
void selectionCleared();
|
||||
/**
|
||||
* Notification that a drag'n'drop operation entered a Surface on this DataDevice.
|
||||
*
|
||||
* @param serial The serial for this enter
|
||||
* @param relativeToSurface Coordinates relative to the upper-left corner of the Surface.
|
||||
* @see dragSurface
|
||||
* @see dragOffer
|
||||
* @see dragLeft
|
||||
* @see dragMotion
|
||||
* @since 5.22
|
||||
**/
|
||||
void dragEntered(quint32 serial, const QPointF &relativeToSurface);
|
||||
/**
|
||||
* Notification that the drag'n'drop operation left the Surface on this DataDevice.
|
||||
*
|
||||
* The leave notification is sent before the enter notification for the new focus.
|
||||
* @see dragEnter
|
||||
* @since 5.22
|
||||
**/
|
||||
void dragLeft();
|
||||
/**
|
||||
* Notification of drag motion events on the current drag surface.
|
||||
*
|
||||
* @param relativeToSurface Coordinates relative to the upper-left corner of the entered Surface.
|
||||
* @param time timestamp with millisecond granularity
|
||||
* @see dragEntered
|
||||
* @since 5.22
|
||||
**/
|
||||
void dragMotion(const QPointF &relativeToSurface, quint32 time);
|
||||
/**
|
||||
* Emitted when the implicit grab is removed and the drag'n'drop operation ended on this
|
||||
* DataDevice.
|
||||
*
|
||||
* The client can now start a data transfer on the DataOffer.
|
||||
* @see dragEntered
|
||||
* @see dragOffer
|
||||
* @since 5.22
|
||||
**/
|
||||
void dropped();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "datadevicemanager.h"
|
||||
#include "datadevice.h"
|
||||
#include "datasource.h"
|
||||
#include "event_queue.h"
|
||||
#include "seat.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN DataDeviceManager::Private
|
||||
{
|
||||
public:
|
||||
WaylandPointer<wl_data_device_manager, wl_data_device_manager_destroy> manager;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
DataDeviceManager::DataDeviceManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
DataDeviceManager::~DataDeviceManager()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void DataDeviceManager::release()
|
||||
{
|
||||
d->manager.release();
|
||||
}
|
||||
|
||||
void DataDeviceManager::destroy()
|
||||
{
|
||||
d->manager.destroy();
|
||||
}
|
||||
|
||||
bool DataDeviceManager::isValid() const
|
||||
{
|
||||
return d->manager.isValid();
|
||||
}
|
||||
|
||||
void DataDeviceManager::setup(wl_data_device_manager *manager)
|
||||
{
|
||||
Q_ASSERT(manager);
|
||||
Q_ASSERT(!d->manager.isValid());
|
||||
d->manager.setup(manager);
|
||||
}
|
||||
|
||||
EventQueue *DataDeviceManager::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
void DataDeviceManager::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
DataSource *DataDeviceManager::createDataSource(QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
DataSource *s = new DataSource(parent);
|
||||
auto w = wl_data_device_manager_create_data_source(d->manager);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
s->setup(w);
|
||||
return s;
|
||||
}
|
||||
|
||||
DataDevice *DataDeviceManager::getDataDevice(Seat *seat, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Q_ASSERT(seat);
|
||||
DataDevice *device = new DataDevice(parent);
|
||||
auto w = wl_data_device_manager_get_data_device(d->manager, *seat);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
device->setup(w);
|
||||
return device;
|
||||
}
|
||||
|
||||
DataDeviceManager::operator wl_data_device_manager *() const
|
||||
{
|
||||
return d->manager;
|
||||
}
|
||||
|
||||
DataDeviceManager::operator wl_data_device_manager *()
|
||||
{
|
||||
return d->manager;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_datadevicemanager.cpp"
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_DATA_DEVICE_MANAGER_H
|
||||
#define WAYLAND_DATA_DEVICE_MANAGER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_data_device_manager;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class DataDevice;
|
||||
class DataSource;
|
||||
class Seat;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the wl_data_device_manager interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the wl_data_device_manager interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the DataDeviceManager interface:
|
||||
* @code
|
||||
* DataDeviceManager *m = registry->createDataDeviceManager(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the DataDeviceManager and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* DataDeviceManager *m = new DataDeviceManager;
|
||||
* m->setup(registry->bindDataDeviceManager(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The DataDeviceManager can be used as a drop-in replacement for any wl_data_device_manager
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT DataDeviceManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Drag and Drop actions supported by DataSource and DataOffer.
|
||||
* @since 5.42
|
||||
**/
|
||||
enum class DnDAction {
|
||||
None = 0,
|
||||
Copy = 1 << 0,
|
||||
Move = 1 << 1,
|
||||
Ask = 1 << 2,
|
||||
};
|
||||
Q_DECLARE_FLAGS(DnDActions, DnDAction)
|
||||
|
||||
/**
|
||||
* Creates a new Compositor.
|
||||
* Note: after constructing the Compositor it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use Compositor prefer using
|
||||
* Registry::createCompositor.
|
||||
**/
|
||||
explicit DataDeviceManager(QObject *parent = nullptr);
|
||||
~DataDeviceManager() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a wl_data_device_manager.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this DataDeviceManager to manage the @p manager.
|
||||
* When using Registry::createDataDeviceManager there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_data_device_manager *manager);
|
||||
/**
|
||||
* Releases the wl_data_device_manager interface.
|
||||
* After the interface has been released the DataDeviceManager instance is no
|
||||
* longer valid and can be setup with another wl_data_device_manager interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this DataDeviceManager.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_data_device_manager interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* DataDeviceManager gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating a DataSource.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating a DataSource.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
DataSource *createDataSource(QObject *parent = nullptr);
|
||||
|
||||
DataDevice *getDataDevice(Seat *seat, QObject *parent = nullptr);
|
||||
|
||||
operator wl_data_device_manager *();
|
||||
operator wl_data_device_manager *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the Compositor got created by
|
||||
* Registry::createDataDeviceManager
|
||||
*
|
||||
* @since 5.5
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(DataDeviceManager::DnDActions)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,234 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "dataoffer.h"
|
||||
#include "datadevice.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Qt
|
||||
#include <QMimeDatabase>
|
||||
#include <QMimeType>
|
||||
// Wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN DataOffer::Private
|
||||
{
|
||||
public:
|
||||
Private(wl_data_offer *offer, DataOffer *q);
|
||||
WaylandPointer<wl_data_offer, wl_data_offer_destroy> dataOffer;
|
||||
QList<QMimeType> mimeTypes;
|
||||
DataDeviceManager::DnDActions sourceActions = DataDeviceManager::DnDAction::None;
|
||||
DataDeviceManager::DnDAction selectedAction = DataDeviceManager::DnDAction::None;
|
||||
|
||||
private:
|
||||
void offer(const QString &mimeType);
|
||||
void setAction(DataDeviceManager::DnDAction action);
|
||||
static void offerCallback(void *data, wl_data_offer *dataOffer, const char *mimeType);
|
||||
static void sourceActionsCallback(void *data, wl_data_offer *wl_data_offer, uint32_t source_actions);
|
||||
static void actionCallback(void *data, wl_data_offer *wl_data_offer, uint32_t dnd_action);
|
||||
DataOffer *q;
|
||||
|
||||
static const struct wl_data_offer_listener s_listener;
|
||||
};
|
||||
|
||||
#ifndef K_DOXYGEN
|
||||
const struct wl_data_offer_listener DataOffer::Private::s_listener = {offerCallback, sourceActionsCallback, actionCallback};
|
||||
#endif
|
||||
|
||||
DataOffer::Private::Private(wl_data_offer *offer, DataOffer *q)
|
||||
: q(q)
|
||||
{
|
||||
dataOffer.setup(offer);
|
||||
wl_data_offer_add_listener(offer, &s_listener, this);
|
||||
}
|
||||
|
||||
void DataOffer::Private::offerCallback(void *data, wl_data_offer *dataOffer, const char *mimeType)
|
||||
{
|
||||
auto d = reinterpret_cast<Private *>(data);
|
||||
Q_ASSERT(d->dataOffer == dataOffer);
|
||||
d->offer(QString::fromUtf8(mimeType));
|
||||
}
|
||||
|
||||
void DataOffer::Private::offer(const QString &mimeType)
|
||||
{
|
||||
QMimeDatabase db;
|
||||
const auto &m = db.mimeTypeForName(mimeType);
|
||||
if (m.isValid()) {
|
||||
mimeTypes << m;
|
||||
Q_EMIT q->mimeTypeOffered(m.name());
|
||||
}
|
||||
}
|
||||
|
||||
void DataOffer::Private::sourceActionsCallback(void *data, wl_data_offer *wl_data_offer, uint32_t source_actions)
|
||||
{
|
||||
Q_UNUSED(wl_data_offer)
|
||||
DataDeviceManager::DnDActions actions;
|
||||
if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) {
|
||||
actions |= DataDeviceManager::DnDAction::Copy;
|
||||
}
|
||||
if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE) {
|
||||
actions |= DataDeviceManager::DnDAction::Move;
|
||||
}
|
||||
if (source_actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK) {
|
||||
actions |= DataDeviceManager::DnDAction::Ask;
|
||||
}
|
||||
auto d = reinterpret_cast<Private *>(data);
|
||||
if (d->sourceActions != actions) {
|
||||
d->sourceActions = actions;
|
||||
Q_EMIT d->q->sourceDragAndDropActionsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void DataOffer::Private::actionCallback(void *data, wl_data_offer *wl_data_offer, uint32_t dnd_action)
|
||||
{
|
||||
Q_UNUSED(wl_data_offer)
|
||||
auto d = reinterpret_cast<Private *>(data);
|
||||
switch (dnd_action) {
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY:
|
||||
d->setAction(DataDeviceManager::DnDAction::Copy);
|
||||
break;
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE:
|
||||
d->setAction(DataDeviceManager::DnDAction::Move);
|
||||
break;
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
|
||||
d->setAction(DataDeviceManager::DnDAction::Ask);
|
||||
break;
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
|
||||
d->setAction(DataDeviceManager::DnDAction::None);
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void DataOffer::Private::setAction(DataDeviceManager::DnDAction action)
|
||||
{
|
||||
if (action == selectedAction) {
|
||||
return;
|
||||
}
|
||||
selectedAction = action;
|
||||
Q_EMIT q->selectedDragAndDropActionChanged();
|
||||
}
|
||||
|
||||
DataOffer::DataOffer(DataDevice *parent, wl_data_offer *dataOffer)
|
||||
: QObject(parent)
|
||||
, d(new Private(dataOffer, this))
|
||||
{
|
||||
}
|
||||
|
||||
DataOffer::~DataOffer()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void DataOffer::release()
|
||||
{
|
||||
d->dataOffer.release();
|
||||
}
|
||||
|
||||
void DataOffer::destroy()
|
||||
{
|
||||
d->dataOffer.destroy();
|
||||
}
|
||||
|
||||
bool DataOffer::isValid() const
|
||||
{
|
||||
return d->dataOffer.isValid();
|
||||
}
|
||||
|
||||
QList<QMimeType> DataOffer::offeredMimeTypes() const
|
||||
{
|
||||
return d->mimeTypes;
|
||||
}
|
||||
|
||||
void DataOffer::accept(const QMimeType &mimeType, quint32 serial)
|
||||
{
|
||||
accept(mimeType.name(), serial);
|
||||
}
|
||||
|
||||
void DataOffer::accept(const QString &mimeType, quint32 serial)
|
||||
{
|
||||
wl_data_offer_accept(d->dataOffer, serial, mimeType.toUtf8().constData());
|
||||
}
|
||||
|
||||
void DataOffer::receive(const QMimeType &mimeType, qint32 fd)
|
||||
{
|
||||
receive(mimeType.name(), fd);
|
||||
}
|
||||
|
||||
void DataOffer::receive(const QString &mimeType, qint32 fd)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
wl_data_offer_receive(d->dataOffer, mimeType.toUtf8().constData(), fd);
|
||||
}
|
||||
|
||||
DataOffer::operator wl_data_offer *()
|
||||
{
|
||||
return d->dataOffer;
|
||||
}
|
||||
|
||||
DataOffer::operator wl_data_offer *() const
|
||||
{
|
||||
return d->dataOffer;
|
||||
}
|
||||
|
||||
void DataOffer::dragAndDropFinished()
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
if (wl_proxy_get_version(d->dataOffer) < WL_DATA_OFFER_FINISH_SINCE_VERSION) {
|
||||
return;
|
||||
}
|
||||
wl_data_offer_finish(d->dataOffer);
|
||||
}
|
||||
|
||||
DataDeviceManager::DnDActions DataOffer::sourceDragAndDropActions() const
|
||||
{
|
||||
return d->sourceActions;
|
||||
}
|
||||
|
||||
void DataOffer::setDragAndDropActions(DataDeviceManager::DnDActions supported, DataDeviceManager::DnDAction preferred)
|
||||
{
|
||||
if (wl_proxy_get_version(d->dataOffer) < WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION) {
|
||||
return;
|
||||
}
|
||||
auto toWayland = [](DataDeviceManager::DnDAction action) {
|
||||
switch (action) {
|
||||
case DataDeviceManager::DnDAction::Copy:
|
||||
return WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
||||
case DataDeviceManager::DnDAction::Move:
|
||||
return WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
|
||||
case DataDeviceManager::DnDAction::Ask:
|
||||
return WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
|
||||
case DataDeviceManager::DnDAction::None:
|
||||
return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
};
|
||||
uint32_t wlSupported = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
|
||||
if (supported.testFlag(DataDeviceManager::DnDAction::Copy)) {
|
||||
wlSupported |= toWayland(DataDeviceManager::DnDAction::Copy);
|
||||
}
|
||||
if (supported.testFlag(DataDeviceManager::DnDAction::Move)) {
|
||||
wlSupported |= toWayland(DataDeviceManager::DnDAction::Move);
|
||||
}
|
||||
if (supported.testFlag(DataDeviceManager::DnDAction::Ask)) {
|
||||
wlSupported |= toWayland(DataDeviceManager::DnDAction::Ask);
|
||||
}
|
||||
wl_data_offer_set_actions(d->dataOffer, wlSupported, toWayland(preferred));
|
||||
}
|
||||
|
||||
DataDeviceManager::DnDAction DataOffer::selectedDragAndDropAction() const
|
||||
{
|
||||
return d->selectedAction;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_dataoffer.cpp"
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_DATAOFFER_H
|
||||
#define WAYLAND_DATAOFFER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
#include "datadevicemanager.h"
|
||||
|
||||
struct wl_data_offer;
|
||||
|
||||
class QMimeType;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class DataDevice;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the wl_data_offer interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the wl_data_offer interface.
|
||||
* The DataOffer gets created by DataDevice.
|
||||
*
|
||||
* @see DataOfferManager
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT DataOffer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~DataOffer() override;
|
||||
|
||||
/**
|
||||
* Releases the wl_data_offer interface.
|
||||
* After the interface has been released the DataOffer instance is no
|
||||
* longer valid and can be setup with another wl_data_offer interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this DataOffer.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_data_offer interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* DataOffer gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* @returns @c true if managing a wl_data_offer.
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
QList<QMimeType> offeredMimeTypes() const;
|
||||
|
||||
/**
|
||||
* Indicates that the client can accept data of the given @a mimeType.
|
||||
* The @a serial parameter specifies the serial number of the corresponding
|
||||
* dragEntered() event.
|
||||
*
|
||||
* @see DataDevice::dragEntered
|
||||
*/
|
||||
void accept(const QMimeType &mimeType, quint32 serial);
|
||||
/**
|
||||
* Indicates that the client can accept data of the given @a mimeType.
|
||||
* The @a serial parameter specifies the serial number of the corresponding
|
||||
* dragEntered() event.
|
||||
*
|
||||
* @see DataDevice::dragEntered
|
||||
*/
|
||||
void accept(const QString &mimeType, quint32 serial);
|
||||
|
||||
void receive(const QMimeType &mimeType, qint32 fd);
|
||||
void receive(const QString &mimeType, qint32 fd);
|
||||
|
||||
/**
|
||||
* Notifies the compositor that the drag destination successfully
|
||||
* finished the drag-and-drop operation.
|
||||
*
|
||||
* After this operation it is only allowed to release the DataOffer.
|
||||
*
|
||||
* @since 5.42
|
||||
**/
|
||||
void dragAndDropFinished();
|
||||
|
||||
/**
|
||||
* The actions offered by the DataSource.
|
||||
* @since 5.42
|
||||
* @see sourceDragAndDropActionsChanged
|
||||
**/
|
||||
DataDeviceManager::DnDActions sourceDragAndDropActions() const;
|
||||
|
||||
/**
|
||||
* Sets the @p supported and @p preferred Drag and Drop actions.
|
||||
* @since 5.42
|
||||
**/
|
||||
void setDragAndDropActions(DataDeviceManager::DnDActions supported, DataDeviceManager::DnDAction preferred);
|
||||
|
||||
/**
|
||||
* The currently selected drag and drop action by the compositor.
|
||||
* @see selectedDragAndDropActionChanged
|
||||
* @since 5.42
|
||||
**/
|
||||
DataDeviceManager::DnDAction selectedDragAndDropAction() const;
|
||||
|
||||
operator wl_data_offer *();
|
||||
operator wl_data_offer *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void mimeTypeOffered(const QString &);
|
||||
/**
|
||||
* Emitted whenever the @link{sourceDragAndDropActions} changed, e.g. on enter or when
|
||||
* the DataSource changes the supported actions.
|
||||
* @see sourceDragAndDropActions
|
||||
* @since 5.42
|
||||
**/
|
||||
void sourceDragAndDropActionsChanged();
|
||||
/**
|
||||
* Emitted whenever the selected drag and drop action changes.
|
||||
* @see selectedDragAndDropAction
|
||||
* @since 5.42
|
||||
**/
|
||||
void selectedDragAndDropActionChanged();
|
||||
|
||||
private:
|
||||
friend class DataDevice;
|
||||
explicit DataOffer(DataDevice *parent, wl_data_offer *dataOffer);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWayland::Client::DataOffer *)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "datasource.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Qt
|
||||
#include <QMimeType>
|
||||
// Wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN DataSource::Private
|
||||
{
|
||||
public:
|
||||
explicit Private(DataSource *q);
|
||||
void setup(wl_data_source *s);
|
||||
|
||||
WaylandPointer<wl_data_source, wl_data_source_destroy> source;
|
||||
DataDeviceManager::DnDAction selectedAction = DataDeviceManager::DnDAction::None;
|
||||
|
||||
private:
|
||||
void setAction(DataDeviceManager::DnDAction action);
|
||||
static void targetCallback(void *data, wl_data_source *dataSource, const char *mimeType);
|
||||
static void sendCallback(void *data, wl_data_source *dataSource, const char *mimeType, int32_t fd);
|
||||
static void cancelledCallback(void *data, wl_data_source *dataSource);
|
||||
static void dndDropPerformedCallback(void *data, wl_data_source *wl_data_source);
|
||||
static void dndFinishedCallback(void *data, wl_data_source *wl_data_source);
|
||||
static void actionCallback(void *data, wl_data_source *wl_data_source, uint32_t dnd_action);
|
||||
|
||||
static const struct wl_data_source_listener s_listener;
|
||||
|
||||
DataSource *q;
|
||||
};
|
||||
|
||||
const wl_data_source_listener DataSource::Private::s_listener =
|
||||
{targetCallback, sendCallback, cancelledCallback, dndDropPerformedCallback, dndFinishedCallback, actionCallback};
|
||||
|
||||
DataSource::Private::Private(DataSource *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void DataSource::Private::targetCallback(void *data, wl_data_source *dataSource, const char *mimeType)
|
||||
{
|
||||
auto d = reinterpret_cast<DataSource::Private *>(data);
|
||||
Q_ASSERT(d->source == dataSource);
|
||||
Q_EMIT d->q->targetAccepts(QString::fromUtf8(mimeType));
|
||||
}
|
||||
|
||||
void DataSource::Private::sendCallback(void *data, wl_data_source *dataSource, const char *mimeType, int32_t fd)
|
||||
{
|
||||
auto d = reinterpret_cast<DataSource::Private *>(data);
|
||||
Q_ASSERT(d->source == dataSource);
|
||||
Q_EMIT d->q->sendDataRequested(QString::fromUtf8(mimeType), fd);
|
||||
}
|
||||
|
||||
void DataSource::Private::cancelledCallback(void *data, wl_data_source *dataSource)
|
||||
{
|
||||
auto d = reinterpret_cast<DataSource::Private *>(data);
|
||||
Q_ASSERT(d->source == dataSource);
|
||||
Q_EMIT d->q->cancelled();
|
||||
}
|
||||
|
||||
void DataSource::Private::dndDropPerformedCallback(void *data, wl_data_source *wl_data_source)
|
||||
{
|
||||
Q_UNUSED(wl_data_source)
|
||||
auto d = reinterpret_cast<DataSource::Private *>(data);
|
||||
Q_EMIT d->q->dragAndDropPerformed();
|
||||
}
|
||||
|
||||
void DataSource::Private::dndFinishedCallback(void *data, wl_data_source *wl_data_source)
|
||||
{
|
||||
Q_UNUSED(wl_data_source)
|
||||
auto d = reinterpret_cast<DataSource::Private *>(data);
|
||||
Q_EMIT d->q->dragAndDropFinished();
|
||||
}
|
||||
|
||||
void DataSource::Private::actionCallback(void *data, wl_data_source *wl_data_source, uint32_t dnd_action)
|
||||
{
|
||||
Q_UNUSED(wl_data_source)
|
||||
auto d = reinterpret_cast<Private *>(data);
|
||||
switch (dnd_action) {
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY:
|
||||
d->setAction(DataDeviceManager::DnDAction::Copy);
|
||||
break;
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE:
|
||||
d->setAction(DataDeviceManager::DnDAction::Move);
|
||||
break;
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
|
||||
d->setAction(DataDeviceManager::DnDAction::Ask);
|
||||
break;
|
||||
case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
|
||||
d->setAction(DataDeviceManager::DnDAction::None);
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void DataSource::Private::setAction(DataDeviceManager::DnDAction action)
|
||||
{
|
||||
if (action == selectedAction) {
|
||||
return;
|
||||
}
|
||||
selectedAction = action;
|
||||
Q_EMIT q->selectedDragAndDropActionChanged();
|
||||
}
|
||||
|
||||
void DataSource::Private::setup(wl_data_source *s)
|
||||
{
|
||||
Q_ASSERT(!source.isValid());
|
||||
Q_ASSERT(s);
|
||||
source.setup(s);
|
||||
wl_data_source_add_listener(s, &s_listener, this);
|
||||
}
|
||||
|
||||
DataSource::DataSource(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
DataSource::~DataSource()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void DataSource::release()
|
||||
{
|
||||
d->source.release();
|
||||
}
|
||||
|
||||
void DataSource::destroy()
|
||||
{
|
||||
d->source.destroy();
|
||||
}
|
||||
|
||||
bool DataSource::isValid() const
|
||||
{
|
||||
return d->source.isValid();
|
||||
}
|
||||
|
||||
void DataSource::setup(wl_data_source *dataSource)
|
||||
{
|
||||
d->setup(dataSource);
|
||||
}
|
||||
|
||||
void DataSource::offer(const QString &mimeType)
|
||||
{
|
||||
wl_data_source_offer(d->source, mimeType.toUtf8().constData());
|
||||
}
|
||||
|
||||
void DataSource::offer(const QMimeType &mimeType)
|
||||
{
|
||||
if (!mimeType.isValid()) {
|
||||
return;
|
||||
}
|
||||
offer(mimeType.name());
|
||||
}
|
||||
|
||||
DataSource::operator wl_data_source *() const
|
||||
{
|
||||
return d->source;
|
||||
}
|
||||
|
||||
DataSource::operator wl_data_source *()
|
||||
{
|
||||
return d->source;
|
||||
}
|
||||
|
||||
void DataSource::setDragAndDropActions(DataDeviceManager::DnDActions actions)
|
||||
{
|
||||
uint32_t wlActions = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
|
||||
if (actions.testFlag(DataDeviceManager::DnDAction::Copy)) {
|
||||
wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
||||
}
|
||||
if (actions.testFlag(DataDeviceManager::DnDAction::Move)) {
|
||||
wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
|
||||
}
|
||||
if (actions.testFlag(DataDeviceManager::DnDAction::Ask)) {
|
||||
wlActions |= WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
|
||||
}
|
||||
wl_data_source_set_actions(d->source, wlActions);
|
||||
}
|
||||
|
||||
DataDeviceManager::DnDAction DataSource::selectedDragAndDropAction() const
|
||||
{
|
||||
return d->selectedAction;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_datasource.cpp"
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_DATASOURCE_H
|
||||
#define WAYLAND_DATASOURCE_H
|
||||
|
||||
#include "buffer.h"
|
||||
#include "datadevicemanager.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_data_source;
|
||||
class QMimeType;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
/**
|
||||
* @short Wrapper for the wl_data_source interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the wl_data_source interface.
|
||||
* To create a DataSource call DataDeviceManager::createDataSource.
|
||||
*
|
||||
* @see DataDeviceManager
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT DataSource : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit DataSource(QObject *parent = nullptr);
|
||||
~DataSource() override;
|
||||
|
||||
/**
|
||||
* Setup this DataSource to manage the @p dataSource.
|
||||
* When using DataDeviceManager::createDataSource there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_data_source *dataSource);
|
||||
/**
|
||||
* Releases the wl_data_source interface.
|
||||
* After the interface has been released the DataSource instance is no
|
||||
* longer valid and can be setup with another wl_data_source interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this DataSource.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_data_source interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* DataSource gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* @returns @c true if managing a wl_data_source.
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
void offer(const QString &mimeType);
|
||||
void offer(const QMimeType &mimeType);
|
||||
|
||||
/**
|
||||
* Sets the actions that the source side client supports for this
|
||||
* operation.
|
||||
*
|
||||
* This request must be made once only, and can only be made on sources
|
||||
* used in drag-and-drop, so it must be performed before
|
||||
* @link{DataDevice::startDrag}. Attempting to use the source other than
|
||||
* for drag-and-drop will raise a protocol error.
|
||||
* @since 5.42
|
||||
**/
|
||||
void setDragAndDropActions(DataDeviceManager::DnDActions actions);
|
||||
|
||||
/**
|
||||
* The currently selected drag and drop action by the compositor.
|
||||
* @see selectedDragAndDropActionChanged
|
||||
* @since 5.42
|
||||
**/
|
||||
DataDeviceManager::DnDAction selectedDragAndDropAction() const;
|
||||
|
||||
operator wl_data_source *();
|
||||
operator wl_data_source *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted when a target accepts pointer_focus or motion events. If
|
||||
* a target does not accept any of the offered types, @p mimeType is empty.
|
||||
**/
|
||||
void targetAccepts(const QString &mimeType);
|
||||
/**
|
||||
* Request for data from the client. Send the data as the
|
||||
* specified @p mimeType over the passed file descriptor @p fd, then close
|
||||
* it.
|
||||
**/
|
||||
void sendDataRequested(const QString &mimeType, qint32 fd);
|
||||
/**
|
||||
* This DataSource has been replaced by another DataSource.
|
||||
* The client should clean up and destroy this DataSource.
|
||||
**/
|
||||
void cancelled();
|
||||
|
||||
/**
|
||||
* The drag-and-drop operation physically finished.
|
||||
*
|
||||
* The user performed the drop action. This signal does not
|
||||
* indicate acceptance, @link{cancelled} may still be
|
||||
* emitted afterwards if the drop destination does not accept any
|
||||
* mime type.
|
||||
*
|
||||
* However, this signal might not be received if the
|
||||
* compositor cancelled the drag-and-drop operation before this
|
||||
* signal could happen.
|
||||
*
|
||||
* Note that the DataSource may still be used in the future and
|
||||
* should not be destroyed here.
|
||||
* @since 5.42
|
||||
**/
|
||||
void dragAndDropPerformed();
|
||||
|
||||
/**
|
||||
* The drag-and-drop operation concluded.
|
||||
*
|
||||
* The drop destination finished interoperating with this DataSource,
|
||||
* so the client is now free to destroy this DataSource.
|
||||
*
|
||||
* If the action used to perform the operation was "move", the
|
||||
* source can now delete the transferred data.
|
||||
* @since 5.42
|
||||
*/
|
||||
void dragAndDropFinished();
|
||||
|
||||
/**
|
||||
* Emitted whenever the selected drag and drop action changes.
|
||||
* @see selectedDragAndDropAction
|
||||
* @since 5.42
|
||||
**/
|
||||
void selectedDragAndDropActionChanged();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "dpms.h"
|
||||
#include "event_queue.h"
|
||||
#include "output.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <wayland-client-protocol.h>
|
||||
#include <wayland-dpms-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN DpmsManager::Private
|
||||
{
|
||||
public:
|
||||
WaylandPointer<org_kde_kwin_dpms_manager, org_kde_kwin_dpms_manager_destroy> manager;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
DpmsManager::DpmsManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
DpmsManager::~DpmsManager()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void DpmsManager::release()
|
||||
{
|
||||
d->manager.release();
|
||||
}
|
||||
|
||||
void DpmsManager::destroy()
|
||||
{
|
||||
d->manager.destroy();
|
||||
}
|
||||
|
||||
bool DpmsManager::isValid() const
|
||||
{
|
||||
return d->manager.isValid();
|
||||
}
|
||||
|
||||
void DpmsManager::setup(org_kde_kwin_dpms_manager *manager)
|
||||
{
|
||||
Q_ASSERT(manager);
|
||||
Q_ASSERT(!d->manager.isValid());
|
||||
d->manager.setup(manager);
|
||||
}
|
||||
|
||||
EventQueue *DpmsManager::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
void DpmsManager::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
Dpms *DpmsManager::getDpms(Output *output, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Q_ASSERT(output);
|
||||
Dpms *dpms = new Dpms(output, parent);
|
||||
auto w = org_kde_kwin_dpms_manager_get(d->manager, *output);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
dpms->setup(w);
|
||||
return dpms;
|
||||
}
|
||||
|
||||
DpmsManager::operator org_kde_kwin_dpms_manager *() const
|
||||
{
|
||||
return d->manager;
|
||||
}
|
||||
|
||||
DpmsManager::operator org_kde_kwin_dpms_manager *()
|
||||
{
|
||||
return d->manager;
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN Dpms::Private
|
||||
{
|
||||
public:
|
||||
explicit Private(const QPointer<Output> &output, Dpms *q);
|
||||
void setup(org_kde_kwin_dpms *d);
|
||||
|
||||
WaylandPointer<org_kde_kwin_dpms, org_kde_kwin_dpms_release> dpms;
|
||||
struct Data {
|
||||
bool supported = false;
|
||||
Mode mode = Mode::On;
|
||||
bool supportedChanged = false;
|
||||
bool modeChanged = false;
|
||||
};
|
||||
Data current;
|
||||
Data pending;
|
||||
QPointer<Output> output;
|
||||
|
||||
private:
|
||||
static void supportedCallback(void *data, org_kde_kwin_dpms *org_kde_kwin_dpms, uint32_t supported);
|
||||
static void modeCallback(void *data, org_kde_kwin_dpms *org_kde_kwin_dpms, uint32_t mode);
|
||||
static void doneCallback(void *data, org_kde_kwin_dpms *org_kde_kwin_dpms);
|
||||
static const struct org_kde_kwin_dpms_listener s_listener;
|
||||
|
||||
Dpms *q;
|
||||
};
|
||||
|
||||
#ifndef K_DOXYGEN
|
||||
const org_kde_kwin_dpms_listener Dpms::Private::s_listener = {supportedCallback, modeCallback, doneCallback};
|
||||
#endif
|
||||
|
||||
void Dpms::Private::supportedCallback(void *data, org_kde_kwin_dpms *org_kde_kwin_dpms, uint32_t supported)
|
||||
{
|
||||
Q_UNUSED(org_kde_kwin_dpms)
|
||||
Private *p = reinterpret_cast<Private *>(data);
|
||||
p->pending.supported = supported == 0 ? false : true;
|
||||
p->pending.supportedChanged = true;
|
||||
}
|
||||
|
||||
void Dpms::Private::modeCallback(void *data, org_kde_kwin_dpms *org_kde_kwin_dpms, uint32_t mode)
|
||||
{
|
||||
Q_UNUSED(org_kde_kwin_dpms)
|
||||
Mode m;
|
||||
switch (mode) {
|
||||
case ORG_KDE_KWIN_DPMS_MODE_ON:
|
||||
m = Mode::On;
|
||||
break;
|
||||
case ORG_KDE_KWIN_DPMS_MODE_STANDBY:
|
||||
m = Mode::Standby;
|
||||
break;
|
||||
case ORG_KDE_KWIN_DPMS_MODE_SUSPEND:
|
||||
m = Mode::Suspend;
|
||||
break;
|
||||
case ORG_KDE_KWIN_DPMS_MODE_OFF:
|
||||
m = Mode::Off;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
Private *p = reinterpret_cast<Private *>(data);
|
||||
p->pending.mode = m;
|
||||
p->pending.modeChanged = true;
|
||||
}
|
||||
|
||||
void Dpms::Private::doneCallback(void *data, org_kde_kwin_dpms *org_kde_kwin_dpms)
|
||||
{
|
||||
Q_UNUSED(org_kde_kwin_dpms)
|
||||
Private *p = reinterpret_cast<Private *>(data);
|
||||
const bool supportedChanged = p->pending.supportedChanged && p->pending.supported != p->current.supported;
|
||||
const bool modeChanged = p->pending.modeChanged && p->pending.mode != p->current.mode;
|
||||
if (supportedChanged) {
|
||||
p->current.supported = p->pending.supported;
|
||||
Q_EMIT p->q->supportedChanged();
|
||||
}
|
||||
if (modeChanged) {
|
||||
p->current.mode = p->pending.mode;
|
||||
Q_EMIT p->q->modeChanged();
|
||||
}
|
||||
p->pending = Data();
|
||||
}
|
||||
|
||||
Dpms::Private::Private(const QPointer<Output> &output, Dpms *q)
|
||||
: output(output)
|
||||
, q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void Dpms::Private::setup(org_kde_kwin_dpms *d)
|
||||
{
|
||||
Q_ASSERT(d);
|
||||
Q_ASSERT(!dpms.isValid());
|
||||
dpms.setup(d);
|
||||
org_kde_kwin_dpms_add_listener(dpms, &s_listener, this);
|
||||
}
|
||||
|
||||
Dpms::Dpms(const QPointer<Output> &o, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(o, this))
|
||||
{
|
||||
}
|
||||
|
||||
Dpms::~Dpms()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void Dpms::destroy()
|
||||
{
|
||||
d->dpms.destroy();
|
||||
}
|
||||
|
||||
void Dpms::release()
|
||||
{
|
||||
d->dpms.release();
|
||||
}
|
||||
|
||||
bool Dpms::isValid() const
|
||||
{
|
||||
return d->dpms.isValid();
|
||||
}
|
||||
|
||||
void Dpms::setup(org_kde_kwin_dpms *dpms)
|
||||
{
|
||||
d->setup(dpms);
|
||||
}
|
||||
|
||||
bool Dpms::isSupported() const
|
||||
{
|
||||
return d->current.supported;
|
||||
}
|
||||
|
||||
Dpms::Mode Dpms::mode() const
|
||||
{
|
||||
return d->current.mode;
|
||||
}
|
||||
|
||||
void Dpms::requestMode(Dpms::Mode mode)
|
||||
{
|
||||
uint32_t wlMode;
|
||||
switch (mode) {
|
||||
case Mode::On:
|
||||
wlMode = ORG_KDE_KWIN_DPMS_MODE_ON;
|
||||
break;
|
||||
case Mode::Standby:
|
||||
wlMode = ORG_KDE_KWIN_DPMS_MODE_STANDBY;
|
||||
break;
|
||||
case Mode::Suspend:
|
||||
wlMode = ORG_KDE_KWIN_DPMS_MODE_SUSPEND;
|
||||
break;
|
||||
case Mode::Off:
|
||||
wlMode = ORG_KDE_KWIN_DPMS_MODE_OFF;
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
org_kde_kwin_dpms_set(d->dpms, wlMode);
|
||||
}
|
||||
|
||||
QPointer<Output> Dpms::output() const
|
||||
{
|
||||
return d->output;
|
||||
}
|
||||
|
||||
Dpms::operator org_kde_kwin_dpms *()
|
||||
{
|
||||
return d->dpms;
|
||||
}
|
||||
|
||||
Dpms::operator org_kde_kwin_dpms *() const
|
||||
{
|
||||
return d->dpms;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_dpms.cpp"
|
||||
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_DPMS_H
|
||||
#define KWAYLAND_CLIENT_DPMS_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct org_kde_kwin_dpms;
|
||||
struct org_kde_kwin_dpms_manager;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Dpms;
|
||||
class Output;
|
||||
|
||||
/**
|
||||
* @short This class is a factory for Dpms instances.
|
||||
*
|
||||
* It is a convenience wrapper for the org_kde_kwin_dpms_manager interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the DpmsManager interface:
|
||||
* @code
|
||||
* DpmsManager *m = registry->createDpmsManager(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the DpmsManager and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* DpmsManager *m = new DpmsManager;
|
||||
* m->setup(registry->bindDpmsManager(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The DpmsManager can be used as a drop-in replacement for any org_kde_kwin_dpms_manager
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry, Dpms
|
||||
* @since 5.5
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT DpmsManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new DpmsManager.
|
||||
* Note: after constructing the DpmsManager it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use DpmsManager prefer using
|
||||
* Registry::createDpmsManager.
|
||||
**/
|
||||
explicit DpmsManager(QObject *parent = nullptr);
|
||||
~DpmsManager() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_kwin_dpms_manager.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this DpmsManager to manage the @p manager.
|
||||
* When using Registry::createDpmsManager there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_kwin_dpms_manager *manager);
|
||||
/**
|
||||
* Releases the org_kde_kwin_dpms_manager interface.
|
||||
* After the interface has been released the DpmsManager instance is no
|
||||
* longer valid and can be setup with another org_kde_kwin_dpms_manager interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this DpmsManager.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_kwin_dpms_manager interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* DPMS gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating a Dpms.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating a Dpms.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
Dpms *getDpms(Output *output, QObject *parent = nullptr);
|
||||
|
||||
operator org_kde_kwin_dpms_manager *();
|
||||
operator org_kde_kwin_dpms_manager *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the DpmsManager got created by
|
||||
* Registry::createDpmsManager
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Power management for monitors.
|
||||
*
|
||||
* Display Power Management Signaling allows power management for monitors.
|
||||
* This class is a convenient wrapper for the org_kde_kwin_dpms interface.
|
||||
* To create a Dpms call DpmsManager::getDpms.
|
||||
*
|
||||
* @see DpmsManager
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Dpms : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~Dpms() override;
|
||||
|
||||
enum class Mode {
|
||||
On,
|
||||
Standby,
|
||||
Suspend,
|
||||
Off,
|
||||
};
|
||||
|
||||
/**
|
||||
* Setup this Dpms to manage the @p dpms.
|
||||
* When using DpmsManager::createDpms there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_kwin_dpms *dpms);
|
||||
/**
|
||||
* Releases the org_kde_kwin_dpms interface.
|
||||
* After the interface has been released the Dpms instance is no
|
||||
* longer valid and can be setup with another org_kde_kwin_dpms interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this Dpms.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_kwin_dpms interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, source, &Dpms::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_kwin_dpms.
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* @returns the Output for which this Dpms got created
|
||||
**/
|
||||
QPointer<Output> output() const;
|
||||
|
||||
/**
|
||||
* Whether Dpms is supported for the Output.
|
||||
* Initially set to @c false.
|
||||
* @returns whether Dpms is supported for the Output.
|
||||
* @see supportedChanged
|
||||
**/
|
||||
bool isSupported() const;
|
||||
/**
|
||||
* The current Dpms mode.
|
||||
* Initially set to @c Mode::On.
|
||||
* @returns the current Dpms mode of the Output
|
||||
* @see modeChanged
|
||||
**/
|
||||
Mode mode() const;
|
||||
|
||||
/**
|
||||
* Request to change the Output into Dpms @p mode.
|
||||
* The Wayland compositor is not obliged to honor the request.
|
||||
* If the mode changes the client is notified and @link modeChanged @endlink gets emitted.
|
||||
* @param mode The requested Dpms mode.
|
||||
**/
|
||||
void requestMode(Mode mode);
|
||||
|
||||
operator org_kde_kwin_dpms *();
|
||||
operator org_kde_kwin_dpms *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted if the supported state on the Output changes.
|
||||
* @see isSupported
|
||||
**/
|
||||
void supportedChanged();
|
||||
/**
|
||||
* Emitted if the Dpms mode on the Output changes.
|
||||
* @see mode
|
||||
**/
|
||||
void modeChanged();
|
||||
|
||||
private:
|
||||
friend class DpmsManager;
|
||||
explicit Dpms(const QPointer<Output> &o, QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWayland::Client::Dpms::Mode)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "event_queue.h"
|
||||
#include "connection_thread.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <wayland-client.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN EventQueue::Private
|
||||
{
|
||||
public:
|
||||
wl_display *display = nullptr;
|
||||
WaylandPointer<wl_event_queue, wl_event_queue_destroy> queue;
|
||||
};
|
||||
|
||||
EventQueue::EventQueue(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
EventQueue::~EventQueue()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void EventQueue::release()
|
||||
{
|
||||
d->queue.release();
|
||||
d->display = nullptr;
|
||||
}
|
||||
|
||||
void EventQueue::destroy()
|
||||
{
|
||||
d->queue.destroy();
|
||||
d->display = nullptr;
|
||||
}
|
||||
|
||||
bool EventQueue::isValid()
|
||||
{
|
||||
return d->queue.isValid();
|
||||
}
|
||||
|
||||
void EventQueue::setup(wl_display *display)
|
||||
{
|
||||
Q_ASSERT(display);
|
||||
Q_ASSERT(!d->display);
|
||||
Q_ASSERT(!d->queue);
|
||||
d->display = display;
|
||||
d->queue.setup(wl_display_create_queue(display));
|
||||
}
|
||||
|
||||
void EventQueue::setup(ConnectionThread *connection)
|
||||
{
|
||||
setup(connection->display());
|
||||
connect(connection, &ConnectionThread::eventsRead, this, &EventQueue::dispatch, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
void EventQueue::dispatch()
|
||||
{
|
||||
if (!d->display || !d->queue) {
|
||||
return;
|
||||
}
|
||||
wl_display_dispatch_queue_pending(d->display, d->queue);
|
||||
wl_display_flush(d->display);
|
||||
}
|
||||
|
||||
void EventQueue::addProxy(wl_proxy *proxy)
|
||||
{
|
||||
Q_ASSERT(d->queue);
|
||||
wl_proxy_set_queue(proxy, d->queue);
|
||||
}
|
||||
|
||||
EventQueue::operator wl_event_queue *() const
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
EventQueue::operator wl_event_queue *()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_event_queue.cpp"
|
||||
@@ -0,0 +1,147 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_EVENT_QUEUE_H
|
||||
#define WAYLAND_EVENT_QUEUE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_display;
|
||||
struct wl_proxy;
|
||||
struct wl_event_queue;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class ConnectionThread;
|
||||
|
||||
/**
|
||||
* @short Wrapper class for wl_event_queue interface.
|
||||
*
|
||||
* The EventQueue is needed if a different thread is used for the connection.
|
||||
* If the interface wrappers are held in a different thread than the connection thread
|
||||
* an EventQueue is needed for the thread which holds the interface wrappers. A common
|
||||
* example is a dedicated connection thread while the interface wrappers are created
|
||||
* in the main thread.
|
||||
*
|
||||
* All interface wrappers are set up to support the EventQueue in the most convenient
|
||||
* way. The EventQueue needs only to be passed to the Registry. The EventQueue will then
|
||||
* be passed to all created wrappers through the tree.
|
||||
*
|
||||
* @code
|
||||
* ConnectionThread connection;
|
||||
* EventQueue queue;
|
||||
* Registry registry;
|
||||
*
|
||||
* connect(&connection, &ConnectionThread::connected, this, [&] {
|
||||
* queue.setup(&connection);
|
||||
* registry.setEventQueue(&queue);
|
||||
* registry.setup(&connection);
|
||||
* registry.create();
|
||||
* });
|
||||
*
|
||||
* connection.initConnection();
|
||||
* @endcode
|
||||
*
|
||||
* The EventQueue can be used as a drop-in replacement for any wl_event_queue
|
||||
* pointer as it provides matching cast operators.
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT EventQueue : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit EventQueue(QObject *parent = nullptr);
|
||||
~EventQueue() override;
|
||||
|
||||
/**
|
||||
* Creates the event queue for the @p display.
|
||||
*
|
||||
* Note: this will not automatically setup the dispatcher.
|
||||
* When using this method one needs to ensure that dispatch
|
||||
* gets invoked whenever new events need to be dispatched.
|
||||
* @see dispatch
|
||||
**/
|
||||
void setup(wl_display *display);
|
||||
/**
|
||||
* Creates the event queue for the @p connection.
|
||||
*
|
||||
* This method also connects the eventsRead signal of the ConnectionThread
|
||||
* to the dispatch method. Events will be automatically dispatched without
|
||||
* the need to call dispatch manually.
|
||||
* @see dispatch
|
||||
**/
|
||||
void setup(ConnectionThread *connection);
|
||||
|
||||
/**
|
||||
* @returns @c true if EventQueue is setup.
|
||||
**/
|
||||
bool isValid();
|
||||
/**
|
||||
* Releases the wl_event_queue interface.
|
||||
* After the interface has been released the EventQueue instance is no
|
||||
* longer valid and can be setup with another wl_event_queue interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this EventQueue.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_event_queue interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Adds the @p proxy to the EventQueue.
|
||||
**/
|
||||
void addProxy(wl_proxy *proxy);
|
||||
/**
|
||||
* Adds the @p proxy of type wl_interface (e.g. wl_compositor) to the EventQueue.
|
||||
**/
|
||||
template<typename wl_interface>
|
||||
void addProxy(wl_interface *proxy);
|
||||
/**
|
||||
* Adds the @p proxy wrapper class of type T referencing the wl_interface to the EventQueue.
|
||||
**/
|
||||
template<typename wl_interface, typename T>
|
||||
void addProxy(T *proxy);
|
||||
|
||||
operator wl_event_queue *();
|
||||
operator wl_event_queue *() const;
|
||||
|
||||
public Q_SLOTS:
|
||||
/**
|
||||
* Dispatches all pending events on the EventQueue.
|
||||
**/
|
||||
void dispatch();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
template<typename wl_interface>
|
||||
inline void EventQueue::addProxy(wl_interface *proxy)
|
||||
{
|
||||
addProxy(reinterpret_cast<wl_proxy *>(proxy));
|
||||
}
|
||||
|
||||
template<typename wl_interface, typename T>
|
||||
inline void EventQueue::addProxy(T *proxy)
|
||||
{
|
||||
addProxy(reinterpret_cast<wl_proxy *>((wl_interface *)*(proxy)));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "fakeinput.h"
|
||||
#include "event_queue.h"
|
||||
#include "seat.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
#include <QPointF>
|
||||
#include <QSizeF>
|
||||
|
||||
#if __has_include(<linux/input-event-codes.h>)
|
||||
#include <linux/input-event-codes.h>
|
||||
#elif __has_include(<linux/input.h>)
|
||||
#include <linux/input.h>
|
||||
#else
|
||||
#define BTN_LEFT 0x110
|
||||
#define BTN_RIGHT 0x111
|
||||
#define BTN_MIDDLE 0x112
|
||||
#endif
|
||||
|
||||
#include <wayland-fake-input-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN FakeInput::Private
|
||||
{
|
||||
public:
|
||||
WaylandPointer<org_kde_kwin_fake_input, org_kde_kwin_fake_input_destroy> manager;
|
||||
EventQueue *queue = nullptr;
|
||||
|
||||
void sendPointerButtonState(Qt::MouseButton button, quint32 state);
|
||||
};
|
||||
|
||||
FakeInput::FakeInput(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
FakeInput::~FakeInput()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void FakeInput::release()
|
||||
{
|
||||
d->manager.release();
|
||||
}
|
||||
|
||||
void FakeInput::destroy()
|
||||
{
|
||||
d->manager.destroy();
|
||||
}
|
||||
|
||||
bool FakeInput::isValid() const
|
||||
{
|
||||
return d->manager.isValid();
|
||||
}
|
||||
|
||||
void FakeInput::setup(org_kde_kwin_fake_input *manager)
|
||||
{
|
||||
Q_ASSERT(manager);
|
||||
Q_ASSERT(!d->manager.isValid());
|
||||
d->manager.setup(manager);
|
||||
}
|
||||
|
||||
EventQueue *FakeInput::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
void FakeInput::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
void FakeInput::authenticate(const QString &applicationName, const QString &reason)
|
||||
{
|
||||
Q_ASSERT(d->manager.isValid());
|
||||
org_kde_kwin_fake_input_authenticate(d->manager, applicationName.toUtf8().constData(), reason.toUtf8().constData());
|
||||
}
|
||||
|
||||
void FakeInput::requestPointerMove(const QSizeF &delta)
|
||||
{
|
||||
Q_ASSERT(d->manager.isValid());
|
||||
org_kde_kwin_fake_input_pointer_motion(d->manager, wl_fixed_from_double(delta.width()), wl_fixed_from_double(delta.height()));
|
||||
}
|
||||
|
||||
void FakeInput::requestPointerMoveAbsolute(const QPointF &pos)
|
||||
{
|
||||
Q_ASSERT(d->manager.isValid());
|
||||
if (wl_proxy_get_version(d->manager) < ORG_KDE_KWIN_FAKE_INPUT_POINTER_MOTION_ABSOLUTE_SINCE_VERSION) {
|
||||
return;
|
||||
}
|
||||
|
||||
org_kde_kwin_fake_input_pointer_motion_absolute(d->manager, wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()));
|
||||
}
|
||||
|
||||
void FakeInput::Private::sendPointerButtonState(Qt::MouseButton button, quint32 state)
|
||||
{
|
||||
Q_ASSERT(manager.isValid());
|
||||
uint32_t b = 0;
|
||||
switch (button) {
|
||||
case Qt::LeftButton:
|
||||
b = BTN_LEFT;
|
||||
break;
|
||||
case Qt::RightButton:
|
||||
b = BTN_RIGHT;
|
||||
break;
|
||||
case Qt::MiddleButton:
|
||||
b = BTN_MIDDLE;
|
||||
break;
|
||||
default:
|
||||
// TODO: more buttons, check implementation in QtWayland
|
||||
// unsupported button
|
||||
return;
|
||||
}
|
||||
org_kde_kwin_fake_input_button(manager, b, state);
|
||||
}
|
||||
|
||||
void FakeInput::requestPointerButtonPress(Qt::MouseButton button)
|
||||
{
|
||||
d->sendPointerButtonState(button, WL_POINTER_BUTTON_STATE_PRESSED);
|
||||
}
|
||||
|
||||
void FakeInput::requestPointerButtonPress(quint32 linuxButton)
|
||||
{
|
||||
Q_ASSERT(d->manager.isValid());
|
||||
org_kde_kwin_fake_input_button(d->manager, linuxButton, WL_POINTER_BUTTON_STATE_PRESSED);
|
||||
}
|
||||
|
||||
void FakeInput::requestPointerButtonRelease(Qt::MouseButton button)
|
||||
{
|
||||
d->sendPointerButtonState(button, WL_POINTER_BUTTON_STATE_RELEASED);
|
||||
}
|
||||
|
||||
void FakeInput::requestPointerButtonRelease(quint32 linuxButton)
|
||||
{
|
||||
Q_ASSERT(d->manager.isValid());
|
||||
org_kde_kwin_fake_input_button(d->manager, linuxButton, WL_POINTER_BUTTON_STATE_RELEASED);
|
||||
}
|
||||
|
||||
void FakeInput::requestPointerButtonClick(Qt::MouseButton button)
|
||||
{
|
||||
requestPointerButtonPress(button);
|
||||
requestPointerButtonRelease(button);
|
||||
}
|
||||
|
||||
void FakeInput::requestPointerButtonClick(quint32 linuxButton)
|
||||
{
|
||||
requestPointerButtonPress(linuxButton);
|
||||
requestPointerButtonRelease(linuxButton);
|
||||
}
|
||||
|
||||
void FakeInput::requestPointerAxis(Qt::Orientation axis, qreal delta)
|
||||
{
|
||||
Q_ASSERT(d->manager.isValid());
|
||||
uint32_t a;
|
||||
switch (axis) {
|
||||
case Qt::Horizontal:
|
||||
a = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
|
||||
break;
|
||||
case Qt::Vertical:
|
||||
a = WL_POINTER_AXIS_VERTICAL_SCROLL;
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
org_kde_kwin_fake_input_axis(d->manager, a, wl_fixed_from_double(delta));
|
||||
}
|
||||
|
||||
void FakeInput::requestTouchDown(quint32 id, const QPointF &pos)
|
||||
{
|
||||
Q_ASSERT(d->manager.isValid());
|
||||
org_kde_kwin_fake_input_touch_down(d->manager, id, wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()));
|
||||
}
|
||||
|
||||
void FakeInput::requestTouchMotion(quint32 id, const QPointF &pos)
|
||||
{
|
||||
Q_ASSERT(d->manager.isValid());
|
||||
org_kde_kwin_fake_input_touch_motion(d->manager, id, wl_fixed_from_double(pos.x()), wl_fixed_from_double(pos.y()));
|
||||
}
|
||||
|
||||
void FakeInput::requestTouchUp(quint32 id)
|
||||
{
|
||||
Q_ASSERT(d->manager.isValid());
|
||||
org_kde_kwin_fake_input_touch_up(d->manager, id);
|
||||
}
|
||||
|
||||
void FakeInput::requestTouchCancel()
|
||||
{
|
||||
Q_ASSERT(d->manager.isValid());
|
||||
org_kde_kwin_fake_input_touch_cancel(d->manager);
|
||||
}
|
||||
|
||||
void FakeInput::requestTouchFrame()
|
||||
{
|
||||
Q_ASSERT(d->manager.isValid());
|
||||
org_kde_kwin_fake_input_touch_frame(d->manager);
|
||||
}
|
||||
|
||||
void FakeInput::requestKeyboardKeyPress(quint32 linuxKey)
|
||||
{
|
||||
Q_ASSERT(d->manager.isValid());
|
||||
if (wl_proxy_get_version(d->manager) < ORG_KDE_KWIN_FAKE_INPUT_KEYBOARD_KEY_SINCE_VERSION) {
|
||||
return;
|
||||
}
|
||||
|
||||
org_kde_kwin_fake_input_keyboard_key(d->manager, linuxKey, WL_KEYBOARD_KEY_STATE_PRESSED);
|
||||
}
|
||||
|
||||
void FakeInput::requestKeyboardKeyRelease(quint32 linuxKey)
|
||||
{
|
||||
Q_ASSERT(d->manager.isValid());
|
||||
if (wl_proxy_get_version(d->manager) < ORG_KDE_KWIN_FAKE_INPUT_KEYBOARD_KEY_SINCE_VERSION) {
|
||||
return;
|
||||
}
|
||||
|
||||
org_kde_kwin_fake_input_keyboard_key(d->manager, linuxKey, WL_KEYBOARD_KEY_STATE_RELEASED);
|
||||
}
|
||||
|
||||
FakeInput::operator org_kde_kwin_fake_input *() const
|
||||
{
|
||||
return d->manager;
|
||||
}
|
||||
|
||||
FakeInput::operator org_kde_kwin_fake_input *()
|
||||
{
|
||||
return d->manager;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_fakeinput.cpp"
|
||||
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_FAKEINPUT_H
|
||||
#define KWAYLAND_FAKEINPUT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct org_kde_kwin_fake_input;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the org_kde_kwin_fake_input interface.
|
||||
*
|
||||
* FakeInput allows to fake input events into the Wayland server. This is a privileged
|
||||
* Wayland interface and the Wayland server is allowed to ignore all events.
|
||||
*
|
||||
* This class provides a convenient wrapper for the org_kde_kwin_fake_input interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the FakeInput interface:
|
||||
* @code
|
||||
* FakeInput *m = registry->createFakeInput(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the FakeInput and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* FakeInput *m = new FakeInput;
|
||||
* m->setup(registry->bindFakeInput(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The FakeInput can be used as a drop-in replacement for any org_kde_kwin_fake_input
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT FakeInput : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new FakeInput.
|
||||
* Note: after constructing the FakeInput it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use FakeInput prefer using
|
||||
* Registry::createFakeInput.
|
||||
**/
|
||||
explicit FakeInput(QObject *parent = nullptr);
|
||||
~FakeInput() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_kwin_fake_input.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this FakeInput to manage the @p manager.
|
||||
* When using Registry::createFakeInput there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_kwin_fake_input *manager);
|
||||
/**
|
||||
* Releases the org_kde_kwin_fake_input interface.
|
||||
* After the interface has been released the FakeInput instance is no
|
||||
* longer valid and can be setup with another org_kde_kwin_fake_input interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this FakeInput.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_kwin_fake_input interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* FakeInput gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for bound proxies.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for bound proxies.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Authenticate with the Wayland server in order to request sending fake input events.
|
||||
* The Wayland server might ignore all requests without a prior authentication.
|
||||
*
|
||||
* The Wayland server might use the provided @p applicationName and @p reason to ask
|
||||
* the user whether this request should get authenticated.
|
||||
*
|
||||
* There is no way for the client to figure out whether the authentication was granted
|
||||
* or denied. The client should assume that it wasn't granted.
|
||||
*
|
||||
* @param applicationName A human readable description of the application
|
||||
* @param reason A human readable explanation why this application wants to send fake requests
|
||||
**/
|
||||
void authenticate(const QString &applicationName, const QString &reason);
|
||||
/**
|
||||
* Request a relative pointer motion of @p delta pixels.
|
||||
**/
|
||||
void requestPointerMove(const QSizeF &delta);
|
||||
/**
|
||||
* Request an absolute pointer motion to @p pos position.
|
||||
*
|
||||
* @since 5.54
|
||||
**/
|
||||
void requestPointerMoveAbsolute(const QPointF &pos);
|
||||
/**
|
||||
* Convenience overload.
|
||||
* @see requestPointerButtonPress(quint32)
|
||||
**/
|
||||
void requestPointerButtonPress(Qt::MouseButton button);
|
||||
/**
|
||||
* Request a pointer button press.
|
||||
* @param linuxButton The button code as defined in linux/input-event-codes.h
|
||||
**/
|
||||
void requestPointerButtonPress(quint32 linuxButton);
|
||||
/**
|
||||
* Convenience overload.
|
||||
* @see requestPointerButtonRelease(quint32)
|
||||
**/
|
||||
void requestPointerButtonRelease(Qt::MouseButton button);
|
||||
/**
|
||||
* Request a pointer button release.
|
||||
* @param linuxButton The button code as defined in linux/input-event-codes.h
|
||||
**/
|
||||
void requestPointerButtonRelease(quint32 linuxButton);
|
||||
/**
|
||||
* Convenience overload.
|
||||
* @see requestPointerButtonClick(quint32)
|
||||
**/
|
||||
void requestPointerButtonClick(Qt::MouseButton button);
|
||||
/**
|
||||
* Requests a pointer button click, that is a press directly followed by a release.
|
||||
* @param linuxButton The button code as defined in linux/input-event-codes.h
|
||||
**/
|
||||
void requestPointerButtonClick(quint32 linuxButton);
|
||||
/**
|
||||
* Request a scroll of the pointer @p axis with @p delta.
|
||||
**/
|
||||
void requestPointerAxis(Qt::Orientation axis, qreal delta);
|
||||
/**
|
||||
* Request a touch down at @p pos in global coordinates.
|
||||
*
|
||||
* If this is the first touch down it starts a touch sequence.
|
||||
* @param id The id to identify the touch point
|
||||
* @param pos The global position of the touch point
|
||||
* @see requestTouchMotion
|
||||
* @see requestTouchUp
|
||||
* @since 5.23
|
||||
**/
|
||||
void requestTouchDown(quint32 id, const QPointF &pos);
|
||||
/**
|
||||
* Request a move of the touch point identified by @p id to new global @p pos.
|
||||
* @param id The id to identify the touch point
|
||||
* @param pos The global position of the touch point
|
||||
* @see requestTouchDown
|
||||
* @since 5.23
|
||||
**/
|
||||
void requestTouchMotion(quint32 id, const QPointF &pos);
|
||||
/**
|
||||
* Requests a touch up of the touch point identified by @p id.
|
||||
* @param id The id to identify the touch point
|
||||
* @since 5.23
|
||||
**/
|
||||
void requestTouchUp(quint32 id);
|
||||
/**
|
||||
* Requests to cancel the current touch event sequence.
|
||||
* @since 5.23
|
||||
**/
|
||||
void requestTouchCancel();
|
||||
/**
|
||||
* Requests a touch frame. This allows to manipulate multiple touch points in one
|
||||
* event and notify that the set of touch events for the current frame are finished.
|
||||
* @since 5.23
|
||||
**/
|
||||
void requestTouchFrame();
|
||||
|
||||
/**
|
||||
* Request a keyboard key press.
|
||||
* @param linuxButton The button code as defined in linux/input-event-codes.h
|
||||
*
|
||||
* @since 5.63
|
||||
**/
|
||||
void requestKeyboardKeyPress(quint32 linuxKey);
|
||||
/**
|
||||
* Request a keyboard button release.
|
||||
* @param linuxButton The button code as defined in linux/input-event-codes.h
|
||||
*
|
||||
* @since 5.63
|
||||
**/
|
||||
void requestKeyboardKeyRelease(quint32 linuxKey);
|
||||
|
||||
operator org_kde_kwin_fake_input *();
|
||||
operator org_kde_kwin_fake_input *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the Compositor got created by
|
||||
* Registry::createFakeInput
|
||||
*
|
||||
* @since 5.5
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,157 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2017 Martin Flöser <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "idleinhibit.h"
|
||||
#include "event_queue.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <wayland-idle-inhibit-unstable-v1-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN IdleInhibitManager::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
void setup(zwp_idle_inhibit_manager_v1 *arg);
|
||||
|
||||
WaylandPointer<zwp_idle_inhibit_manager_v1, zwp_idle_inhibit_manager_v1_destroy> idleinhibitmanager;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
IdleInhibitManager::IdleInhibitManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
void IdleInhibitManager::Private::setup(zwp_idle_inhibit_manager_v1 *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!idleinhibitmanager);
|
||||
idleinhibitmanager.setup(arg);
|
||||
}
|
||||
|
||||
IdleInhibitManager::~IdleInhibitManager()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void IdleInhibitManager::setup(zwp_idle_inhibit_manager_v1 *idleinhibitmanager)
|
||||
{
|
||||
d->setup(idleinhibitmanager);
|
||||
}
|
||||
|
||||
void IdleInhibitManager::release()
|
||||
{
|
||||
d->idleinhibitmanager.release();
|
||||
}
|
||||
|
||||
void IdleInhibitManager::destroy()
|
||||
{
|
||||
d->idleinhibitmanager.destroy();
|
||||
}
|
||||
|
||||
IdleInhibitManager::operator zwp_idle_inhibit_manager_v1 *()
|
||||
{
|
||||
return d->idleinhibitmanager;
|
||||
}
|
||||
|
||||
IdleInhibitManager::operator zwp_idle_inhibit_manager_v1 *() const
|
||||
{
|
||||
return d->idleinhibitmanager;
|
||||
}
|
||||
|
||||
bool IdleInhibitManager::isValid() const
|
||||
{
|
||||
return d->idleinhibitmanager.isValid();
|
||||
}
|
||||
|
||||
void IdleInhibitManager::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *IdleInhibitManager::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
IdleInhibitor *IdleInhibitManager::createInhibitor(Surface *surface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
auto p = new IdleInhibitor(parent);
|
||||
auto w = zwp_idle_inhibit_manager_v1_create_inhibitor(d->idleinhibitmanager, *surface);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
p->setup(w);
|
||||
return p;
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN IdleInhibitor::Private
|
||||
{
|
||||
public:
|
||||
void setup(zwp_idle_inhibitor_v1 *arg);
|
||||
|
||||
WaylandPointer<zwp_idle_inhibitor_v1, zwp_idle_inhibitor_v1_destroy> idleinhibitor;
|
||||
};
|
||||
|
||||
IdleInhibitor::IdleInhibitor(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
void IdleInhibitor::Private::setup(zwp_idle_inhibitor_v1 *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!idleinhibitor);
|
||||
idleinhibitor.setup(arg);
|
||||
}
|
||||
|
||||
IdleInhibitor::~IdleInhibitor()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void IdleInhibitor::setup(zwp_idle_inhibitor_v1 *idleinhibitor)
|
||||
{
|
||||
d->setup(idleinhibitor);
|
||||
}
|
||||
|
||||
void IdleInhibitor::release()
|
||||
{
|
||||
d->idleinhibitor.release();
|
||||
}
|
||||
|
||||
void IdleInhibitor::destroy()
|
||||
{
|
||||
d->idleinhibitor.destroy();
|
||||
}
|
||||
|
||||
IdleInhibitor::operator zwp_idle_inhibitor_v1 *()
|
||||
{
|
||||
return d->idleinhibitor;
|
||||
}
|
||||
|
||||
IdleInhibitor::operator zwp_idle_inhibitor_v1 *() const
|
||||
{
|
||||
return d->idleinhibitor;
|
||||
}
|
||||
|
||||
bool IdleInhibitor::isValid() const
|
||||
{
|
||||
return d->idleinhibitor.isValid();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_idleinhibit.cpp"
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2017 Martin Flöser <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_IDLEINHIBIT_H
|
||||
#define KWAYLAND_CLIENT_IDLEINHIBIT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct zwp_idle_inhibit_manager_v1;
|
||||
struct zwp_idle_inhibitor_v1;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Surface;
|
||||
class IdleInhibitor;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the zwp_idle_inhibit_manager_v1 interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the zwp_idle_inhibit_manager_v1 interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the IdleInhibitManager interface:
|
||||
* @code
|
||||
* IdleInhibitManager *c = registry->createIdleInhibitManager(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the IdleInhibitManager and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* IdleInhibitManager *c = new IdleInhibitManager;
|
||||
* c->setup(registry->bindIdleInhibitManager(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The IdleInhibitManager can be used as a drop-in replacement for any zwp_idle_inhibit_manager_v1
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
* @since 5.41
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT IdleInhibitManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new IdleInhibitManager.
|
||||
* Note: after constructing the IdleInhibitManager it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use IdleInhibitManager prefer using
|
||||
* Registry::createIdleInhibitManager.
|
||||
**/
|
||||
explicit IdleInhibitManager(QObject *parent = nullptr);
|
||||
~IdleInhibitManager() override;
|
||||
|
||||
/**
|
||||
* Setup this IdleInhibitManager to manage the @p idleinhibitmanager.
|
||||
* When using Registry::createIdleInhibitManager there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zwp_idle_inhibit_manager_v1 *idleinhibitmanager);
|
||||
/**
|
||||
* @returns @c true if managing a zwp_idle_inhibit_manager_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zwp_idle_inhibit_manager_v1 interface.
|
||||
* After the interface has been released the IdleInhibitManager instance is no
|
||||
* longer valid and can be setup with another zwp_idle_inhibit_manager_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this IdleInhibitManager.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zwp_idle_inhibit_manager_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, idleinhibitmanager, &IdleInhibitManager::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating objects with this IdleInhibitManager.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating objects with this IdleInhibitManager.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Creates an IdleInhibitor for the given @p surface.
|
||||
* While the IdleInhibitor exists the @p surface is marked to inhibit idle.
|
||||
* @param surface The Surface which should have idle inhibited
|
||||
* @param parent The parent object for the IdleInhibitor
|
||||
* @returns The created IdleInhibitor
|
||||
**/
|
||||
IdleInhibitor *createInhibitor(Surface *surface, QObject *parent = nullptr);
|
||||
|
||||
operator zwp_idle_inhibit_manager_v1 *();
|
||||
operator zwp_idle_inhibit_manager_v1 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the IdleInhibitManager got created by
|
||||
* Registry::createIdleInhibitManager
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* An IdleInhibitor prevents the Output that the associated Surface is visible on from being
|
||||
* set to a state where it is not visually usable due to lack of user interaction
|
||||
* (e.g. blanked, dimmed, locked, set to power save, etc.) Any screensaver processes are
|
||||
* also blocked from displaying.
|
||||
*
|
||||
* If the Surface is destroyed, unmapped, becomes occluded, loses visibility, or otherwise
|
||||
* becomes not visually relevant for the user, the IdleInhibitor will not be honored by
|
||||
* the compositor; if the Surface subsequently regains visibility the inhibitor takes effect
|
||||
* once again.
|
||||
* Likewise, the IdleInhibitor isn't honored if the system was already idled at the time the
|
||||
* IdleInhibitor was established, although if the system later de-idles and re-idles the
|
||||
* IdleInhibitor will take effect.
|
||||
*
|
||||
* @see IdleInhibitManager
|
||||
* @see Surface
|
||||
* @since 5.41
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT IdleInhibitor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~IdleInhibitor() override;
|
||||
|
||||
/**
|
||||
* Setup this IdleInhibitor to manage the @p idleinhibitor.
|
||||
* When using IdleInhibitManager::createIdleInhibitor there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zwp_idle_inhibitor_v1 *idleinhibitor);
|
||||
/**
|
||||
* @returns @c true if managing a zwp_idle_inhibitor_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zwp_idle_inhibitor_v1 interface.
|
||||
* After the interface has been released the IdleInhibitor instance is no
|
||||
* longer valid and can be setup with another zwp_idle_inhibitor_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this IdleInhibitor.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zwp_idle_inhibitor_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, idleinhibitor, &IdleInhibitor::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
operator zwp_idle_inhibitor_v1 *();
|
||||
operator zwp_idle_inhibitor_v1 *() const;
|
||||
|
||||
private:
|
||||
friend class IdleInhibitManager;
|
||||
explicit IdleInhibitor(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "keyboard.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
#include <QPointer>
|
||||
// wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN Keyboard::Private
|
||||
{
|
||||
public:
|
||||
Private(Keyboard *q);
|
||||
void setup(wl_keyboard *k);
|
||||
|
||||
WaylandPointer<wl_keyboard, wl_keyboard_release> keyboard;
|
||||
QPointer<Surface> enteredSurface;
|
||||
QList<quint32> enteredKeys;
|
||||
|
||||
struct {
|
||||
qint32 charactersPerSecond = 0;
|
||||
qint32 delay = 0;
|
||||
} repeatInfo;
|
||||
|
||||
private:
|
||||
void enter(uint32_t serial, wl_surface *surface, wl_array *keys);
|
||||
void leave(uint32_t serial);
|
||||
static void keymapCallback(void *data, wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size);
|
||||
static void enterCallback(void *data, wl_keyboard *keyboard, uint32_t serial, wl_surface *surface, wl_array *keys);
|
||||
static void leaveCallback(void *data, wl_keyboard *keyboard, uint32_t serial, wl_surface *surface);
|
||||
static void keyCallback(void *data, wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state);
|
||||
static void
|
||||
modifiersCallback(void *data, wl_keyboard *keyboard, uint32_t serial, uint32_t modsDepressed, uint32_t modsLatched, uint32_t modsLocked, uint32_t group);
|
||||
static void repeatInfoCallback(void *data, wl_keyboard *keyboard, int32_t charactersPerSecond, int32_t delay);
|
||||
Keyboard *q;
|
||||
static const wl_keyboard_listener s_listener;
|
||||
};
|
||||
|
||||
Keyboard::Private::Private(Keyboard *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void Keyboard::Private::setup(wl_keyboard *k)
|
||||
{
|
||||
Q_ASSERT(k);
|
||||
Q_ASSERT(!keyboard);
|
||||
keyboard.setup(k);
|
||||
wl_keyboard_add_listener(keyboard, &s_listener, this);
|
||||
}
|
||||
|
||||
const wl_keyboard_listener Keyboard::Private::s_listener = {keymapCallback, enterCallback, leaveCallback, keyCallback, modifiersCallback, repeatInfoCallback};
|
||||
|
||||
Keyboard::Keyboard(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
Keyboard::~Keyboard()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void Keyboard::release()
|
||||
{
|
||||
d->keyboard.release();
|
||||
}
|
||||
|
||||
void Keyboard::destroy()
|
||||
{
|
||||
d->keyboard.destroy();
|
||||
}
|
||||
|
||||
void Keyboard::setup(wl_keyboard *keyboard)
|
||||
{
|
||||
d->setup(keyboard);
|
||||
}
|
||||
|
||||
void Keyboard::Private::enterCallback(void *data, wl_keyboard *keyboard, uint32_t serial, wl_surface *surface, wl_array *keys)
|
||||
{
|
||||
auto k = reinterpret_cast<Private *>(data);
|
||||
Q_ASSERT(k->keyboard == keyboard);
|
||||
k->enter(serial, surface, keys);
|
||||
}
|
||||
|
||||
void Keyboard::Private::enter(uint32_t serial, wl_surface *surface, wl_array *keys)
|
||||
{
|
||||
enteredSurface = Surface::get(surface);
|
||||
|
||||
enteredKeys.clear();
|
||||
for (const uint32_t &key : std::span(static_cast<uint32_t *>(keys->data), keys->size / sizeof(uint32_t))) {
|
||||
enteredKeys.append(key);
|
||||
}
|
||||
|
||||
Q_EMIT q->entered(serial);
|
||||
}
|
||||
|
||||
void Keyboard::Private::leaveCallback(void *data, wl_keyboard *keyboard, uint32_t serial, wl_surface *surface)
|
||||
{
|
||||
Q_UNUSED(surface)
|
||||
auto k = reinterpret_cast<Private *>(data);
|
||||
Q_ASSERT(k->keyboard == keyboard);
|
||||
k->leave(serial);
|
||||
}
|
||||
|
||||
void Keyboard::Private::leave(uint32_t serial)
|
||||
{
|
||||
enteredSurface.clear();
|
||||
Q_EMIT q->left(serial);
|
||||
}
|
||||
|
||||
void Keyboard::Private::keyCallback(void *data, wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
|
||||
{
|
||||
Q_UNUSED(serial)
|
||||
auto k = reinterpret_cast<Keyboard::Private *>(data);
|
||||
Q_ASSERT(k->keyboard == keyboard);
|
||||
auto toState = [state] {
|
||||
if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
|
||||
return KeyState::Released;
|
||||
} else {
|
||||
return KeyState::Pressed;
|
||||
}
|
||||
};
|
||||
Q_EMIT k->q->keyChanged(key, toState(), time);
|
||||
}
|
||||
|
||||
void Keyboard::Private::keymapCallback(void *data, wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size)
|
||||
{
|
||||
auto k = reinterpret_cast<Keyboard::Private *>(data);
|
||||
Q_ASSERT(k->keyboard == keyboard);
|
||||
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT k->q->keymapChanged(fd, size);
|
||||
}
|
||||
|
||||
void Keyboard::Private::modifiersCallback(void *data,
|
||||
wl_keyboard *keyboard,
|
||||
uint32_t serial,
|
||||
uint32_t modsDepressed,
|
||||
uint32_t modsLatched,
|
||||
uint32_t modsLocked,
|
||||
uint32_t group)
|
||||
{
|
||||
Q_UNUSED(serial)
|
||||
auto k = reinterpret_cast<Keyboard::Private *>(data);
|
||||
Q_ASSERT(k->keyboard == keyboard);
|
||||
Q_EMIT k->q->modifiersChanged(modsDepressed, modsLatched, modsLocked, group);
|
||||
}
|
||||
|
||||
void Keyboard::Private::repeatInfoCallback(void *data, wl_keyboard *keyboard, int32_t charactersPerSecond, int32_t delay)
|
||||
{
|
||||
auto k = reinterpret_cast<Keyboard::Private *>(data);
|
||||
Q_ASSERT(k->keyboard == keyboard);
|
||||
k->repeatInfo.charactersPerSecond = qMax(charactersPerSecond, 0);
|
||||
k->repeatInfo.delay = qMax(delay, 0);
|
||||
Q_EMIT k->q->keyRepeatChanged();
|
||||
}
|
||||
|
||||
Surface *Keyboard::enteredSurface()
|
||||
{
|
||||
return d->enteredSurface.data();
|
||||
}
|
||||
|
||||
Surface *Keyboard::enteredSurface() const
|
||||
{
|
||||
return d->enteredSurface.data();
|
||||
}
|
||||
|
||||
QList<quint32> Keyboard::enteredKeys() const
|
||||
{
|
||||
return d->enteredKeys;
|
||||
}
|
||||
|
||||
bool Keyboard::isValid() const
|
||||
{
|
||||
return d->keyboard.isValid();
|
||||
}
|
||||
|
||||
bool Keyboard::isKeyRepeatEnabled() const
|
||||
{
|
||||
return d->repeatInfo.charactersPerSecond > 0;
|
||||
}
|
||||
|
||||
qint32 Keyboard::keyRepeatDelay() const
|
||||
{
|
||||
return d->repeatInfo.delay;
|
||||
}
|
||||
|
||||
qint32 Keyboard::keyRepeatRate() const
|
||||
{
|
||||
return d->repeatInfo.charactersPerSecond;
|
||||
}
|
||||
|
||||
Keyboard::operator wl_keyboard *()
|
||||
{
|
||||
return d->keyboard;
|
||||
}
|
||||
|
||||
Keyboard::operator wl_keyboard *() const
|
||||
{
|
||||
return d->keyboard;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_keyboard.cpp"
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_KEYBOARD_H
|
||||
#define WAYLAND_KEYBOARD_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_keyboard;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the wl_keyboard interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the wl_keyboard interface.
|
||||
*
|
||||
* To create an instance use Seat::createKeyboard.
|
||||
*
|
||||
* @see Seat
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Keyboard : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class KeyState {
|
||||
Released,
|
||||
Pressed,
|
||||
};
|
||||
explicit Keyboard(QObject *parent = nullptr);
|
||||
~Keyboard() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a wl_keyboard.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this Keyboard to manage the @p keyboard.
|
||||
* When using Seat::createKeyboard there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_keyboard *keyboard);
|
||||
/**
|
||||
* Releases the wl_keyboard interface.
|
||||
* After the interface has been released the Keyboard instance is no
|
||||
* longer valid and can be setup with another wl_keyboard interface.
|
||||
*
|
||||
* This method is automatically invoked when the Seat which created this
|
||||
* Keyboard gets released.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this Keyboard.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_keyboard interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Seat which created this
|
||||
* Keyboard gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* @returns The Surface the Keyboard is on, may be @c null.
|
||||
**/
|
||||
Surface *enteredSurface() const;
|
||||
/**
|
||||
* @overload
|
||||
**/
|
||||
Surface *enteredSurface();
|
||||
|
||||
/**
|
||||
* @returns The keys that were reported in the enter event.
|
||||
**/
|
||||
QList<quint32> enteredKeys() const;
|
||||
|
||||
/**
|
||||
* @returns Whether key repeat is enabled on this keyboard
|
||||
* @see keyRepeatRate
|
||||
* @see keyRepeatDelay
|
||||
* @see keyRepeatChanged
|
||||
* @since 5.5
|
||||
**/
|
||||
bool isKeyRepeatEnabled() const;
|
||||
/**
|
||||
* @returns the key repeat rate in characters per second.
|
||||
* @see isKeyRepeatEnabled
|
||||
* @see keyRepeatDelay
|
||||
* @see keyRepeatChanged
|
||||
* @since 5.5
|
||||
**/
|
||||
qint32 keyRepeatRate() const;
|
||||
/**
|
||||
* @returns the delay in millisecond for key repeat after a press.
|
||||
* @see isKeyRepeatEnabled
|
||||
* @see keyRepeatRate
|
||||
* @see keyRepeatChanged
|
||||
* @since 5.5
|
||||
**/
|
||||
qint32 keyRepeatDelay() const;
|
||||
|
||||
operator wl_keyboard *();
|
||||
operator wl_keyboard *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Notification that this seat's Keyboard is focused on a certain surface.
|
||||
*
|
||||
* @param serial The serial for this enter
|
||||
**/
|
||||
void entered(quint32 serial);
|
||||
/**
|
||||
* Notification that this seat's Keyboard is no longer focused on a certain surface.
|
||||
*
|
||||
* The leave notification is sent before the enter notification for the new focus.
|
||||
*
|
||||
* @param serial The serial of this enter
|
||||
**/
|
||||
void left(quint32 serial);
|
||||
/**
|
||||
* This signal provides a file descriptor to the client which can
|
||||
* be memory-mapped to provide a keyboard mapping description.
|
||||
*
|
||||
* The signal is only emitted if the keymap format is libxkbcommon compatible.
|
||||
*
|
||||
* @param fd file descriptor of the keymap
|
||||
* @param size The size of the keymap
|
||||
**/
|
||||
void keymapChanged(int fd, quint32 size);
|
||||
/**
|
||||
* A key was pressed or released.
|
||||
* The time argument is a timestamp with millisecond granularity, with an undefined base.
|
||||
* @param key The key which was pressed
|
||||
* @param state Whether the key got @c Released or @c Pressed
|
||||
* @param time The timestamp
|
||||
**/
|
||||
void keyChanged(quint32 key, KWayland::Client::Keyboard::KeyState state, quint32 time);
|
||||
/**
|
||||
* Notifies clients that the modifier and/or group state has changed,
|
||||
* and it should update its local state.
|
||||
**/
|
||||
void modifiersChanged(quint32 depressed, quint32 latched, quint32 locked, quint32 group);
|
||||
/**
|
||||
* Emitted whenever information on key repeat changed.
|
||||
* @see isKeyRepeatEnabled
|
||||
* @see keyRepeatRate
|
||||
* @see keyRepeatDelay
|
||||
* @since 5.5
|
||||
**/
|
||||
void keyRepeatChanged();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWayland::Client::Keyboard::KeyState)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,427 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "output.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Qt
|
||||
#include <QList>
|
||||
#include <QPoint>
|
||||
#include <QRect>
|
||||
// wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
namespace
|
||||
{
|
||||
typedef QList<Output::Mode> Modes;
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN Output::Private
|
||||
{
|
||||
public:
|
||||
Private(Output *q);
|
||||
~Private();
|
||||
void setup(wl_output *o);
|
||||
|
||||
WaylandPointer<wl_output, wl_output_release> output;
|
||||
EventQueue *queue = nullptr;
|
||||
QSize physicalSize;
|
||||
QPoint globalPosition;
|
||||
QString manufacturer;
|
||||
QString model;
|
||||
int scale = 1;
|
||||
SubPixel subPixel = SubPixel::Unknown;
|
||||
Transform transform = Transform::Normal;
|
||||
Modes modes;
|
||||
std::optional<Mode> currentMode;
|
||||
QString name;
|
||||
QString description;
|
||||
|
||||
static Output *get(wl_output *o);
|
||||
|
||||
private:
|
||||
static void geometryCallback(void *data,
|
||||
wl_output *output,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t physicalWidth,
|
||||
int32_t physicalHeight,
|
||||
int32_t subPixel,
|
||||
const char *make,
|
||||
const char *model,
|
||||
int32_t transform);
|
||||
static void modeCallback(void *data, wl_output *output, uint32_t flags, int32_t width, int32_t height, int32_t refresh);
|
||||
static void doneCallback(void *data, wl_output *output);
|
||||
static void scaleCallback(void *data, wl_output *output, int32_t scale);
|
||||
static void nameCallback(void *data, struct wl_output *wl_output, const char *name);
|
||||
static void descriptionCallback(void *data, struct wl_output *wl_output, const char *description);
|
||||
void setPhysicalSize(const QSize &size);
|
||||
void setGlobalPosition(const QPoint &pos);
|
||||
void setManufacturer(const QString &manufacturer);
|
||||
void setModel(const QString &model);
|
||||
void setScale(int scale);
|
||||
void setSubPixel(SubPixel subPixel);
|
||||
void setTransform(Transform transform);
|
||||
void addMode(uint32_t flags, int32_t width, int32_t height, int32_t refresh);
|
||||
|
||||
Output *q;
|
||||
static struct wl_output_listener s_outputListener;
|
||||
|
||||
static QList<Private *> s_allOutputs;
|
||||
};
|
||||
|
||||
QList<Output::Private *> Output::Private::s_allOutputs;
|
||||
|
||||
Output::Private::Private(Output *q)
|
||||
: q(q)
|
||||
{
|
||||
s_allOutputs << this;
|
||||
}
|
||||
|
||||
Output::Private::~Private()
|
||||
{
|
||||
s_allOutputs.removeOne(this);
|
||||
}
|
||||
|
||||
Output *Output::Private::get(wl_output *o)
|
||||
{
|
||||
auto it = std::find_if(s_allOutputs.constBegin(), s_allOutputs.constEnd(), [o](Private *p) {
|
||||
const wl_output *reference = p->output;
|
||||
return reference == o;
|
||||
});
|
||||
if (it != s_allOutputs.constEnd()) {
|
||||
return (*it)->q;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Output::Private::setup(wl_output *o)
|
||||
{
|
||||
Q_ASSERT(o);
|
||||
Q_ASSERT(!output);
|
||||
output.setup(o);
|
||||
wl_output_add_listener(output, &s_outputListener, this);
|
||||
}
|
||||
|
||||
bool Output::Mode::operator==(const Output::Mode &m) const
|
||||
{
|
||||
return size == m.size && refreshRate == m.refreshRate && flags == m.flags && output == m.output;
|
||||
}
|
||||
|
||||
Output::Output(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
Output::~Output()
|
||||
{
|
||||
d->output.release();
|
||||
}
|
||||
|
||||
wl_output_listener Output::Private::s_outputListener = {
|
||||
geometryCallback, modeCallback, doneCallback, scaleCallback,
|
||||
#ifdef WL_OUTPUT_NAME_SINCE_VERSION
|
||||
nameCallback,
|
||||
#endif
|
||||
#ifdef WL_OUTPUT_DESCRIPTION_SINCE_VERSION
|
||||
descriptionCallback,
|
||||
#endif
|
||||
};
|
||||
|
||||
void Output::Private::geometryCallback(void *data,
|
||||
wl_output *output,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t physicalWidth,
|
||||
int32_t physicalHeight,
|
||||
int32_t subPixel,
|
||||
const char *make,
|
||||
const char *model,
|
||||
int32_t transform)
|
||||
{
|
||||
Q_UNUSED(transform)
|
||||
auto o = reinterpret_cast<Output::Private *>(data);
|
||||
Q_ASSERT(o->output == output);
|
||||
o->setGlobalPosition(QPoint(x, y));
|
||||
o->setManufacturer(make);
|
||||
o->setModel(model);
|
||||
o->setPhysicalSize(QSize(physicalWidth, physicalHeight));
|
||||
auto toSubPixel = [subPixel]() {
|
||||
switch (subPixel) {
|
||||
case WL_OUTPUT_SUBPIXEL_NONE:
|
||||
return SubPixel::None;
|
||||
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
|
||||
return SubPixel::HorizontalRGB;
|
||||
case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
|
||||
return SubPixel::HorizontalBGR;
|
||||
case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
|
||||
return SubPixel::VerticalRGB;
|
||||
case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
|
||||
return SubPixel::VerticalBGR;
|
||||
case WL_OUTPUT_SUBPIXEL_UNKNOWN:
|
||||
default:
|
||||
return SubPixel::Unknown;
|
||||
}
|
||||
};
|
||||
o->setSubPixel(toSubPixel());
|
||||
auto toTransform = [transform]() {
|
||||
switch (transform) {
|
||||
case WL_OUTPUT_TRANSFORM_90:
|
||||
return Transform::Rotated90;
|
||||
case WL_OUTPUT_TRANSFORM_180:
|
||||
return Transform::Rotated180;
|
||||
case WL_OUTPUT_TRANSFORM_270:
|
||||
return Transform::Rotated270;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED:
|
||||
return Transform::Flipped;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
|
||||
return Transform::Flipped90;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
|
||||
return Transform::Flipped180;
|
||||
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
|
||||
return Transform::Flipped270;
|
||||
case WL_OUTPUT_TRANSFORM_NORMAL:
|
||||
default:
|
||||
return Transform::Normal;
|
||||
}
|
||||
};
|
||||
o->setTransform(toTransform());
|
||||
}
|
||||
|
||||
void Output::Private::modeCallback(void *data, wl_output *output, uint32_t flags, int32_t width, int32_t height, int32_t refresh)
|
||||
{
|
||||
auto o = reinterpret_cast<Output::Private *>(data);
|
||||
Q_ASSERT(o->output == output);
|
||||
o->addMode(flags, width, height, refresh);
|
||||
}
|
||||
|
||||
void Output::Private::addMode(uint32_t flags, int32_t width, int32_t height, int32_t refresh)
|
||||
{
|
||||
Mode mode;
|
||||
mode.output = QPointer<Output>(q);
|
||||
mode.refreshRate = refresh;
|
||||
mode.size = QSize(width, height);
|
||||
if (flags & WL_OUTPUT_MODE_CURRENT) {
|
||||
mode.flags |= Mode::Flag::Current;
|
||||
}
|
||||
if (flags & WL_OUTPUT_MODE_PREFERRED) {
|
||||
mode.flags |= Mode::Flag::Preferred;
|
||||
}
|
||||
auto currentIt = modes.insert(modes.end(), mode);
|
||||
bool existing = false;
|
||||
if (flags & WL_OUTPUT_MODE_CURRENT) {
|
||||
auto it = modes.begin();
|
||||
while (it != currentIt) {
|
||||
auto &m = (*it);
|
||||
if (m.flags.testFlag(Mode::Flag::Current)) {
|
||||
m.flags &= ~Mode::Flags(Mode::Flag::Current);
|
||||
Q_EMIT q->modeChanged(m);
|
||||
}
|
||||
if (m.refreshRate == mode.refreshRate && m.size == mode.size) {
|
||||
it = modes.erase(it);
|
||||
existing = true;
|
||||
} else {
|
||||
it++;
|
||||
}
|
||||
}
|
||||
currentMode = *currentIt;
|
||||
}
|
||||
if (existing) {
|
||||
Q_EMIT q->modeChanged(mode);
|
||||
} else {
|
||||
Q_EMIT q->modeAdded(mode);
|
||||
}
|
||||
}
|
||||
|
||||
void Output::Private::scaleCallback(void *data, wl_output *output, int32_t scale)
|
||||
{
|
||||
auto o = reinterpret_cast<Output::Private *>(data);
|
||||
Q_ASSERT(o->output == output);
|
||||
o->setScale(scale);
|
||||
}
|
||||
|
||||
void Output::Private::nameCallback(void *data, struct wl_output *wl_output, const char *name)
|
||||
{
|
||||
auto o = reinterpret_cast<Output::Private *>(data);
|
||||
Q_ASSERT(o->output == wl_output);
|
||||
o->name = QString::fromUtf8(name);
|
||||
}
|
||||
|
||||
void Output::Private::descriptionCallback(void *data, struct wl_output *wl_output, const char *description)
|
||||
{
|
||||
auto o = reinterpret_cast<Output::Private *>(data);
|
||||
Q_ASSERT(o->output == wl_output);
|
||||
o->description = QString::fromUtf8(description);
|
||||
}
|
||||
|
||||
void Output::Private::doneCallback(void *data, wl_output *output)
|
||||
{
|
||||
auto o = reinterpret_cast<Output::Private *>(data);
|
||||
Q_ASSERT(o->output == output);
|
||||
Q_EMIT o->q->changed();
|
||||
}
|
||||
|
||||
void Output::setup(wl_output *output)
|
||||
{
|
||||
d->setup(output);
|
||||
}
|
||||
|
||||
EventQueue *Output::eventQueue() const
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
void Output::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
void Output::Private::setGlobalPosition(const QPoint &pos)
|
||||
{
|
||||
globalPosition = pos;
|
||||
}
|
||||
|
||||
void Output::Private::setManufacturer(const QString &m)
|
||||
{
|
||||
manufacturer = m;
|
||||
}
|
||||
|
||||
void Output::Private::setModel(const QString &m)
|
||||
{
|
||||
model = m;
|
||||
}
|
||||
|
||||
void Output::Private::setPhysicalSize(const QSize &size)
|
||||
{
|
||||
physicalSize = size;
|
||||
}
|
||||
|
||||
void Output::Private::setScale(int s)
|
||||
{
|
||||
scale = s;
|
||||
}
|
||||
|
||||
QRect Output::geometry() const
|
||||
{
|
||||
if (!d->currentMode) {
|
||||
return QRect();
|
||||
}
|
||||
return QRect(d->globalPosition, pixelSize());
|
||||
}
|
||||
|
||||
void Output::Private::setSubPixel(Output::SubPixel s)
|
||||
{
|
||||
subPixel = s;
|
||||
}
|
||||
|
||||
void Output::Private::setTransform(Output::Transform t)
|
||||
{
|
||||
transform = t;
|
||||
}
|
||||
|
||||
QPoint Output::globalPosition() const
|
||||
{
|
||||
return d->globalPosition;
|
||||
}
|
||||
|
||||
QString Output::manufacturer() const
|
||||
{
|
||||
return d->manufacturer;
|
||||
}
|
||||
|
||||
QString Output::model() const
|
||||
{
|
||||
return d->model;
|
||||
}
|
||||
|
||||
wl_output *Output::output()
|
||||
{
|
||||
return d->output;
|
||||
}
|
||||
|
||||
QSize Output::physicalSize() const
|
||||
{
|
||||
return d->physicalSize;
|
||||
}
|
||||
|
||||
QSize Output::pixelSize() const
|
||||
{
|
||||
if (!d->currentMode) {
|
||||
return QSize();
|
||||
}
|
||||
return (*d->currentMode).size;
|
||||
}
|
||||
|
||||
int Output::refreshRate() const
|
||||
{
|
||||
if (!d->currentMode) {
|
||||
return 0;
|
||||
}
|
||||
return (*d->currentMode).refreshRate;
|
||||
}
|
||||
|
||||
int Output::scale() const
|
||||
{
|
||||
return d->scale;
|
||||
}
|
||||
|
||||
bool Output::isValid() const
|
||||
{
|
||||
return d->output.isValid();
|
||||
}
|
||||
|
||||
Output::SubPixel Output::subPixel() const
|
||||
{
|
||||
return d->subPixel;
|
||||
}
|
||||
|
||||
Output::Transform Output::transform() const
|
||||
{
|
||||
return d->transform;
|
||||
}
|
||||
|
||||
QList<Output::Mode> Output::modes() const
|
||||
{
|
||||
return d->modes;
|
||||
}
|
||||
|
||||
QString Output::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
QString Output::description() const
|
||||
{
|
||||
return d->description;
|
||||
}
|
||||
|
||||
Output::operator wl_output *()
|
||||
{
|
||||
return d->output;
|
||||
}
|
||||
|
||||
Output::operator wl_output *() const
|
||||
{
|
||||
return d->output;
|
||||
}
|
||||
|
||||
Output *Output::get(wl_output *o)
|
||||
{
|
||||
return Private::get(o);
|
||||
}
|
||||
|
||||
void Output::destroy()
|
||||
{
|
||||
d->output.destroy();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_output.cpp"
|
||||
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_OUTPUT_H
|
||||
#define WAYLAND_OUTPUT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
#include <QSize>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_output;
|
||||
class QPoint;
|
||||
class QRect;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the wl_output interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the wl_output interface.
|
||||
* Its main purpose is to hold the information about one Output.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create an Output interface:
|
||||
* @code
|
||||
* Output *c = registry->createOutput(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the Output and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* Output *c = new Output;
|
||||
* c->setup(registry->bindOutput(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The Output can be used as a drop-in replacement for any wl_output
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* Please note that all properties of Output are not valid until the
|
||||
* changed signal has been emitted. The wayland server is pushing the
|
||||
* information in an async way to the Output instance. By emitting changed
|
||||
* the Output indicates that all relevant information is available.
|
||||
*
|
||||
* @see Registry
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Output : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class SubPixel {
|
||||
Unknown,
|
||||
None,
|
||||
HorizontalRGB,
|
||||
HorizontalBGR,
|
||||
VerticalRGB,
|
||||
VerticalBGR,
|
||||
};
|
||||
enum class Transform {
|
||||
Normal,
|
||||
Rotated90,
|
||||
Rotated180,
|
||||
Rotated270,
|
||||
Flipped,
|
||||
Flipped90,
|
||||
Flipped180,
|
||||
Flipped270,
|
||||
};
|
||||
struct Mode {
|
||||
enum class Flag {
|
||||
None = 0,
|
||||
Current = 1 << 0,
|
||||
Preferred = 1 << 1,
|
||||
};
|
||||
Q_DECLARE_FLAGS(Flags, Flag)
|
||||
/**
|
||||
* The size of this Mode in pixel space.
|
||||
**/
|
||||
QSize size;
|
||||
/**
|
||||
* The refresh rate in mHz of this Mode.
|
||||
**/
|
||||
int refreshRate = 0;
|
||||
/**
|
||||
* The flags of this Mode, that is whether it's the
|
||||
* Current and/or Preferred Mode of the Output.
|
||||
**/
|
||||
Flags flags = Flag::None;
|
||||
/**
|
||||
* The Output to which this Mode belongs.
|
||||
**/
|
||||
QPointer<Output> output;
|
||||
|
||||
bool operator==(const Mode &m) const;
|
||||
};
|
||||
explicit Output(QObject *parent = nullptr);
|
||||
~Output() override;
|
||||
|
||||
/**
|
||||
* Setup this Compositor to manage the @p output.
|
||||
* When using Registry::createOutput there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_output *output);
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a wl_output.
|
||||
**/
|
||||
bool isValid() const;
|
||||
operator wl_output *();
|
||||
operator wl_output *() const;
|
||||
wl_output *output();
|
||||
/**
|
||||
* Size in millimeters.
|
||||
**/
|
||||
QSize physicalSize() const;
|
||||
/**
|
||||
* Position within the global compositor space.
|
||||
**/
|
||||
QPoint globalPosition() const;
|
||||
/**
|
||||
* Textual description of the manufacturer.
|
||||
**/
|
||||
QString manufacturer() const;
|
||||
/**
|
||||
* Textual description of the model.
|
||||
**/
|
||||
QString model() const;
|
||||
/**
|
||||
* Size in the current mode.
|
||||
**/
|
||||
QSize pixelSize() const;
|
||||
/**
|
||||
* The geometry of this Output in pixels.
|
||||
* Convenient for QRect(globalPosition(), pixelSize()).
|
||||
* @see globalPosition
|
||||
* @see pixelSize
|
||||
**/
|
||||
QRect geometry() const;
|
||||
/**
|
||||
* Refresh rate in mHz of the current mode.
|
||||
**/
|
||||
int refreshRate() const;
|
||||
/**
|
||||
* Scaling factor of this output.
|
||||
*
|
||||
* A scale larger than 1 means that the compositor will automatically scale surface buffers
|
||||
* by this amount when rendering. This is used for very high resolution displays where
|
||||
* applications rendering at the native resolution would be too small to be legible.
|
||||
**/
|
||||
int scale() const;
|
||||
/**
|
||||
* Subpixel orientation of this Output.
|
||||
**/
|
||||
SubPixel subPixel() const;
|
||||
/**
|
||||
* Transform that maps framebuffer to Output.
|
||||
*
|
||||
* The purpose is mainly to allow clients render accordingly and tell the compositor,
|
||||
* so that for fullscreen surfaces, the compositor will still be able to scan out
|
||||
* directly from client surfaces.
|
||||
**/
|
||||
Transform transform() const;
|
||||
|
||||
/**
|
||||
* @returns The Modes of this Output.
|
||||
**/
|
||||
QList<Mode> modes() const;
|
||||
|
||||
/**
|
||||
* Returns the name of the output.
|
||||
**/
|
||||
QString name() const;
|
||||
|
||||
/**
|
||||
* Returns the human readable description of the output.
|
||||
**/
|
||||
QString description() const;
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for bound proxies.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for bound proxies.
|
||||
**/
|
||||
EventQueue *eventQueue() const;
|
||||
|
||||
/**
|
||||
* @returns The Output for the @p native wl_output. @c null if there is no Output for it.
|
||||
* @since 5.27
|
||||
**/
|
||||
static Output *get(wl_output *native);
|
||||
|
||||
/**
|
||||
* Destroys the data hold by this Output.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid any more, it's not
|
||||
* possible to call release any more as that calls into the Wayland
|
||||
* connection and the call would fail.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* Output gets destroyed.
|
||||
*
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted whenever at least one of the data changed.
|
||||
**/
|
||||
void changed();
|
||||
/**
|
||||
* Emitted whenever a new Mode is added.
|
||||
* This normally only happens during the initial promoting of modes.
|
||||
* Afterwards only modeChanged should be emitted.
|
||||
* @param mode The newly added Mode.
|
||||
* @see modeChanged
|
||||
**/
|
||||
void modeAdded(const KWayland::Client::Output::Mode &mode);
|
||||
/**
|
||||
* Emitted whenever a Mode changes.
|
||||
* This normally means that the @c Mode::Flag::Current is added or removed.
|
||||
* @param mode The changed Mode
|
||||
**/
|
||||
void modeChanged(const KWayland::Client::Output::Mode &mode);
|
||||
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the Compositor got created by
|
||||
* Registry::createOutput
|
||||
*
|
||||
* @since 5.5
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(Output::Mode::Flags)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWayland::Client::Output *)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::Output::SubPixel)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::Output::Transform)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::Output::Mode)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,352 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "plasmashell.h"
|
||||
#include "event_queue.h"
|
||||
#include "output.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Wayland
|
||||
#include <wayland-plasma-shell-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN PlasmaShell::Private
|
||||
{
|
||||
public:
|
||||
WaylandPointer<org_kde_plasma_shell, org_kde_plasma_shell_destroy> shell;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
class Q_DECL_HIDDEN PlasmaShellSurface::Private
|
||||
{
|
||||
public:
|
||||
Private(PlasmaShellSurface *q);
|
||||
~Private();
|
||||
void setup(org_kde_plasma_surface *surface);
|
||||
|
||||
WaylandPointer<org_kde_plasma_surface, org_kde_plasma_surface_destroy> surface;
|
||||
QSize size;
|
||||
QPointer<Surface> parentSurface;
|
||||
PlasmaShellSurface::Role role;
|
||||
|
||||
static PlasmaShellSurface *get(Surface *surface);
|
||||
|
||||
private:
|
||||
static void autoHidingPanelHiddenCallback(void *data, org_kde_plasma_surface *org_kde_plasma_surface);
|
||||
static void autoHidingPanelShownCallback(void *data, org_kde_plasma_surface *org_kde_plasma_surface);
|
||||
|
||||
PlasmaShellSurface *q;
|
||||
static QList<Private *> s_surfaces;
|
||||
static const org_kde_plasma_surface_listener s_listener;
|
||||
};
|
||||
|
||||
QList<PlasmaShellSurface::Private *> PlasmaShellSurface::Private::s_surfaces;
|
||||
|
||||
PlasmaShell::PlasmaShell(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
PlasmaShell::~PlasmaShell()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void PlasmaShell::destroy()
|
||||
{
|
||||
if (!d->shell) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT interfaceAboutToBeDestroyed();
|
||||
d->shell.destroy();
|
||||
}
|
||||
|
||||
void PlasmaShell::release()
|
||||
{
|
||||
if (!d->shell) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT interfaceAboutToBeReleased();
|
||||
d->shell.release();
|
||||
}
|
||||
|
||||
void PlasmaShell::setup(org_kde_plasma_shell *shell)
|
||||
{
|
||||
Q_ASSERT(!d->shell);
|
||||
Q_ASSERT(shell);
|
||||
d->shell.setup(shell);
|
||||
}
|
||||
|
||||
void PlasmaShell::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *PlasmaShell::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
PlasmaShellSurface *PlasmaShell::createSurface(wl_surface *surface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
auto kwS = Surface::get(surface);
|
||||
if (kwS) {
|
||||
if (auto s = PlasmaShellSurface::Private::get(kwS)) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
PlasmaShellSurface *s = new PlasmaShellSurface(parent);
|
||||
connect(this, &PlasmaShell::interfaceAboutToBeReleased, s, &PlasmaShellSurface::release);
|
||||
connect(this, &PlasmaShell::interfaceAboutToBeDestroyed, s, &PlasmaShellSurface::destroy);
|
||||
auto w = org_kde_plasma_shell_get_surface(d->shell, surface);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
s->setup(w);
|
||||
s->d->parentSurface = QPointer<Surface>(kwS);
|
||||
return s;
|
||||
}
|
||||
|
||||
PlasmaShellSurface *PlasmaShell::createSurface(Surface *surface, QObject *parent)
|
||||
{
|
||||
return createSurface(*surface, parent);
|
||||
}
|
||||
|
||||
bool PlasmaShell::isValid() const
|
||||
{
|
||||
return d->shell.isValid();
|
||||
}
|
||||
|
||||
PlasmaShell::operator org_kde_plasma_shell *()
|
||||
{
|
||||
return d->shell;
|
||||
}
|
||||
|
||||
PlasmaShell::operator org_kde_plasma_shell *() const
|
||||
{
|
||||
return d->shell;
|
||||
}
|
||||
|
||||
PlasmaShellSurface::Private::Private(PlasmaShellSurface *q)
|
||||
: role(PlasmaShellSurface::Role::Normal)
|
||||
, q(q)
|
||||
{
|
||||
s_surfaces << this;
|
||||
}
|
||||
|
||||
PlasmaShellSurface::Private::~Private()
|
||||
{
|
||||
s_surfaces.removeAll(this);
|
||||
}
|
||||
|
||||
PlasmaShellSurface *PlasmaShellSurface::Private::get(Surface *surface)
|
||||
{
|
||||
if (!surface) {
|
||||
return nullptr;
|
||||
}
|
||||
for (auto it = s_surfaces.constBegin(); it != s_surfaces.constEnd(); ++it) {
|
||||
if ((*it)->parentSurface == surface) {
|
||||
return (*it)->q;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::Private::setup(org_kde_plasma_surface *s)
|
||||
{
|
||||
Q_ASSERT(s);
|
||||
Q_ASSERT(!surface);
|
||||
surface.setup(s);
|
||||
org_kde_plasma_surface_add_listener(surface, &s_listener, this);
|
||||
}
|
||||
|
||||
const org_kde_plasma_surface_listener PlasmaShellSurface::Private::s_listener = {autoHidingPanelHiddenCallback, autoHidingPanelShownCallback};
|
||||
|
||||
void PlasmaShellSurface::Private::autoHidingPanelHiddenCallback(void *data, org_kde_plasma_surface *org_kde_plasma_surface)
|
||||
{
|
||||
auto p = reinterpret_cast<PlasmaShellSurface::Private *>(data);
|
||||
Q_ASSERT(p->surface == org_kde_plasma_surface);
|
||||
Q_EMIT p->q->autoHidePanelHidden();
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::Private::autoHidingPanelShownCallback(void *data, org_kde_plasma_surface *org_kde_plasma_surface)
|
||||
{
|
||||
auto p = reinterpret_cast<PlasmaShellSurface::Private *>(data);
|
||||
Q_ASSERT(p->surface == org_kde_plasma_surface);
|
||||
Q_EMIT p->q->autoHidePanelShown();
|
||||
}
|
||||
|
||||
PlasmaShellSurface::PlasmaShellSurface(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
PlasmaShellSurface::~PlasmaShellSurface()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::release()
|
||||
{
|
||||
d->surface.release();
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::destroy()
|
||||
{
|
||||
d->surface.destroy();
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::setup(org_kde_plasma_surface *surface)
|
||||
{
|
||||
d->setup(surface);
|
||||
}
|
||||
|
||||
PlasmaShellSurface *PlasmaShellSurface::get(Surface *surface)
|
||||
{
|
||||
if (auto s = PlasmaShellSurface::Private::get(surface)) {
|
||||
return s;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool PlasmaShellSurface::isValid() const
|
||||
{
|
||||
return d->surface.isValid();
|
||||
}
|
||||
|
||||
PlasmaShellSurface::operator org_kde_plasma_surface *()
|
||||
{
|
||||
return d->surface;
|
||||
}
|
||||
|
||||
PlasmaShellSurface::operator org_kde_plasma_surface *() const
|
||||
{
|
||||
return d->surface;
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::setPosition(const QPoint &point)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
org_kde_plasma_surface_set_position(d->surface, point.x(), point.y());
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::openUnderCursor()
|
||||
{
|
||||
org_kde_plasma_surface_open_under_cursor(d->surface);
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::setRole(PlasmaShellSurface::Role role)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
uint32_t wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_NORMAL;
|
||||
switch (role) {
|
||||
case Role::Normal:
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_NORMAL;
|
||||
break;
|
||||
case Role::Desktop:
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_DESKTOP;
|
||||
break;
|
||||
case Role::Panel:
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_PANEL;
|
||||
break;
|
||||
case Role::OnScreenDisplay:
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_ONSCREENDISPLAY;
|
||||
break;
|
||||
case Role::Notification:
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_NOTIFICATION;
|
||||
break;
|
||||
case Role::ToolTip:
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_TOOLTIP;
|
||||
break;
|
||||
case Role::CriticalNotification:
|
||||
if (wl_proxy_get_version(d->surface) < ORG_KDE_PLASMA_SURFACE_ROLE_CRITICALNOTIFICATION_SINCE_VERSION) {
|
||||
// Fall back to generic notification type if not supported
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_NOTIFICATION;
|
||||
} else {
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_CRITICALNOTIFICATION;
|
||||
}
|
||||
break;
|
||||
case Role::AppletPopup:
|
||||
if (wl_proxy_get_version(d->surface) < ORG_KDE_PLASMA_SURFACE_ROLE_APPLETPOPUP_SINCE_VERSION) {
|
||||
// dock is what applet popups were before
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_PANEL;
|
||||
setPanelBehavior(PanelBehavior::WindowsGoBelow);
|
||||
} else {
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_ROLE_APPLETPOPUP;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
org_kde_plasma_surface_set_role(d->surface, wlRole);
|
||||
d->role = role;
|
||||
}
|
||||
|
||||
PlasmaShellSurface::Role PlasmaShellSurface::role() const
|
||||
{
|
||||
return d->role;
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::setPanelBehavior(PlasmaShellSurface::PanelBehavior behavior)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
uint32_t wlRole = ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_ALWAYS_VISIBLE;
|
||||
switch (behavior) {
|
||||
case PanelBehavior::AlwaysVisible:
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_ALWAYS_VISIBLE;
|
||||
break;
|
||||
case PanelBehavior::AutoHide:
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_AUTO_HIDE;
|
||||
break;
|
||||
case PanelBehavior::WindowsCanCover:
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_WINDOWS_CAN_COVER;
|
||||
break;
|
||||
case PanelBehavior::WindowsGoBelow:
|
||||
wlRole = ORG_KDE_PLASMA_SURFACE_PANEL_BEHAVIOR_WINDOWS_GO_BELOW;
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
org_kde_plasma_surface_set_panel_behavior(d->surface, wlRole);
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::setSkipTaskbar(bool skip)
|
||||
{
|
||||
org_kde_plasma_surface_set_skip_taskbar(d->surface, skip);
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::setSkipSwitcher(bool skip)
|
||||
{
|
||||
org_kde_plasma_surface_set_skip_switcher(d->surface, skip);
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::requestHideAutoHidingPanel()
|
||||
{
|
||||
org_kde_plasma_surface_panel_auto_hide_hide(d->surface);
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::requestShowAutoHidingPanel()
|
||||
{
|
||||
org_kde_plasma_surface_panel_auto_hide_show(d->surface);
|
||||
}
|
||||
|
||||
void PlasmaShellSurface::setPanelTakesFocus(bool takesFocus)
|
||||
{
|
||||
org_kde_plasma_surface_set_panel_takes_focus(d->surface, takesFocus);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_plasmashell.cpp"
|
||||
@@ -0,0 +1,364 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_PLASMASHELL_H
|
||||
#define WAYLAND_PLASMASHELL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QSize>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_surface;
|
||||
struct org_kde_plasma_shell;
|
||||
struct org_kde_plasma_surface;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Surface;
|
||||
class PlasmaShellSurface;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the org_kde_plasma_shell interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the org_kde_plasma_shell interface.
|
||||
* It's main purpose is to create a PlasmaShellSurface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the Shell interface:
|
||||
* @code
|
||||
* PlasmaShell *s = registry->createPlasmaShell(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the PlasmaShell and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* PlasmaShell *s = new PlasmaShell;
|
||||
* s->setup(registry->bindPlasmaShell(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The PlasmaShell can be used as a drop-in replacement for any org_kde_plasma_shell
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
* @see PlasmaShellSurface
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT PlasmaShell : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PlasmaShell(QObject *parent = nullptr);
|
||||
~PlasmaShell() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_plasma_shell.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the org_kde_plasma_shell interface.
|
||||
* After the interface has been released the PlasmaShell instance is no
|
||||
* longer valid and can be setup with another org_kde_plasma_shell interface.
|
||||
*
|
||||
* Right before the interface is released the signal interfaceAboutToBeReleased is emitted.
|
||||
* @see interfaceAboutToBeReleased
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this PlasmaShell.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. Once the connection becomes invalid, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_plasma_shell interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* PlasmaShell gets destroyed.
|
||||
*
|
||||
* Right before the data is destroyed, the signal interfaceAboutToBeDestroyed is emitted.
|
||||
*
|
||||
* @see release
|
||||
* @see interfaceAboutToBeDestroyed
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* Setup this Shell to manage the @p shell.
|
||||
* When using Registry::createShell there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_plasma_shell *shell);
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating a Surface.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating a Surface.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Creates a PlasmaShellSurface for the given @p surface and sets it up.
|
||||
*
|
||||
* If a PlasmaShellSurface for the given @p surface has already been created
|
||||
* a pointer to the existing one is returned instead of creating a new surface.
|
||||
*
|
||||
* @param surface The native surface to create the PlasmaShellSurface for
|
||||
* @param parent The parent to use for the PlasmaShellSurface
|
||||
* @returns created PlasmaShellSurface
|
||||
**/
|
||||
PlasmaShellSurface *createSurface(wl_surface *surface, QObject *parent = nullptr);
|
||||
/**
|
||||
* Creates a PlasmaShellSurface for the given @p surface and sets it up.
|
||||
*
|
||||
* If a PlasmaShellSurface for the given @p surface has already been created
|
||||
* a pointer to the existing one is returned instead of creating a new surface.
|
||||
*
|
||||
* @param surface The Surface to create the PlasmaShellSurface for
|
||||
* @param parent The parent to use for the PlasmaShellSurface
|
||||
* @returns created PlasmaShellSurface
|
||||
**/
|
||||
PlasmaShellSurface *createSurface(Surface *surface, QObject *parent = nullptr);
|
||||
|
||||
operator org_kde_plasma_shell *();
|
||||
operator org_kde_plasma_shell *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* This signal is emitted right before the interface is released.
|
||||
**/
|
||||
void interfaceAboutToBeReleased();
|
||||
/**
|
||||
* This signal is emitted right before the data is destroyed.
|
||||
**/
|
||||
void interfaceAboutToBeDestroyed();
|
||||
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the Compositor got created by
|
||||
* Registry::createPlasmaShell
|
||||
*
|
||||
* @since 5.5
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Wrapper for the org_kde_plasma_surface interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the org_kde_plasma_surface interface.
|
||||
*
|
||||
* To create an instance use PlasmaShell::createSurface.
|
||||
*
|
||||
* A PlasmaShellSurface is a privileged Surface which can add further hints to the
|
||||
* Wayland server about it's position and the usage role. The Wayland server is allowed
|
||||
* to ignore all requests.
|
||||
*
|
||||
* Even if a PlasmaShellSurface is created for a Surface a normal ShellSurface (or similar)
|
||||
* needs to be created to have the Surface mapped as a window by the Wayland server.
|
||||
*
|
||||
* @see PlasmaShell
|
||||
* @see Surface
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT PlasmaShellSurface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PlasmaShellSurface(QObject *parent);
|
||||
~PlasmaShellSurface() override;
|
||||
|
||||
/**
|
||||
* Releases the org_kde_plasma_surface interface.
|
||||
* After the interface has been released the PlasmaShellSurface instance is no
|
||||
* longer valid and can be setup with another org_kde_plasma_surface interface.
|
||||
*
|
||||
* This method is automatically invoked when the PlasmaShell which created this
|
||||
* PlasmaShellSurface gets released.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this PlasmaShellSurface.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_plasma_surface interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the PlasmaShell which created this
|
||||
* PlasmaShellSurface gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* Setup this PlasmaShellSurface to manage the @p surface.
|
||||
* There is normally no need to call this method as it's invoked by
|
||||
* PlasmaShell::createSurface.
|
||||
**/
|
||||
void setup(org_kde_plasma_surface *surface);
|
||||
|
||||
/**
|
||||
* @returns the PlasmaShellSurface * associated with surface,
|
||||
* if any, nullptr if not found.
|
||||
* @since 5.6
|
||||
*/
|
||||
static PlasmaShellSurface *get(Surface *surf);
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_plasma_surface.
|
||||
**/
|
||||
bool isValid() const;
|
||||
operator org_kde_plasma_surface *();
|
||||
operator org_kde_plasma_surface *() const;
|
||||
|
||||
/**
|
||||
* Describes possible roles this PlasmaShellSurface can have.
|
||||
* The role can be used by the Wayland server to e.g. change the stacking order accordingly.
|
||||
**/
|
||||
enum class Role {
|
||||
Normal, ///< A normal Surface
|
||||
Desktop, ///< The Surface represents a desktop, normally stacked below all other surfaces
|
||||
Panel, ///< The Surface represents a panel (dock), normally stacked above normal surfaces
|
||||
OnScreenDisplay, ///< The Surface represents an on screen display, like a volume changed notification
|
||||
Notification, ///< The Surface represents a notification @since 5.24
|
||||
ToolTip, ///< The Surface represents a tooltip @since 5.24
|
||||
CriticalNotification, ///< The Surface represents a critical notification, like battery is running out @since 5.58
|
||||
AppletPopup, ///< The Surface used for applets
|
||||
};
|
||||
/**
|
||||
* Changes the requested Role to @p role.
|
||||
* @see role
|
||||
**/
|
||||
void setRole(Role role);
|
||||
/**
|
||||
* @returns The requested Role, default value is @c Role::Normal.
|
||||
* @see setRole
|
||||
**/
|
||||
Role role() const;
|
||||
/**
|
||||
* Requests to position this PlasmaShellSurface at @p point in global coordinates.
|
||||
**/
|
||||
void setPosition(const QPoint &point);
|
||||
|
||||
/**
|
||||
* Request that the initial position of this surface will be under the cursor
|
||||
*
|
||||
* Has to be called before attaching any buffer to the corresponding surface.
|
||||
* @since 5.94
|
||||
**/
|
||||
void openUnderCursor();
|
||||
|
||||
/**
|
||||
* Describes how a PlasmaShellSurface with role @c Role::Panel should behave.
|
||||
* @see Role
|
||||
**/
|
||||
enum class PanelBehavior {
|
||||
AlwaysVisible,
|
||||
AutoHide,
|
||||
WindowsCanCover,
|
||||
WindowsGoBelow,
|
||||
};
|
||||
/**
|
||||
* Sets the PanelBehavior for a PlasmaShellSurface with Role @c Role::Panel
|
||||
* @see setRole
|
||||
**/
|
||||
void setPanelBehavior(PanelBehavior behavior);
|
||||
|
||||
/**
|
||||
* Setting this bit to the window, will make it say it prefers
|
||||
* to not be listed in the taskbar. Taskbar implementations
|
||||
* may or may not follow this hint.
|
||||
* @since 5.5
|
||||
*/
|
||||
void setSkipTaskbar(bool skip);
|
||||
|
||||
/**
|
||||
* Setting this bit on a window will indicate it does not prefer
|
||||
* to be included in a window switcher.
|
||||
* @since 5.47
|
||||
*/
|
||||
void setSkipSwitcher(bool skip);
|
||||
|
||||
/**
|
||||
* Requests to hide a surface with Role Panel and PanelBahvior AutoHide.
|
||||
*
|
||||
* Once the compositor has hidden the panel the signal {@link autoHidePanelHidden} gets
|
||||
* emitted. Once it is shown again the signal {@link autoHidePanelShown} gets emitted.
|
||||
*
|
||||
* To show the surface again from client side use {@link requestShowAutoHidingPanel}.
|
||||
*
|
||||
* @see autoHidePanelHidden
|
||||
* @see autoHidePanelShown
|
||||
* @see requestShowAutoHidingPanel
|
||||
* @since 5.28
|
||||
**/
|
||||
void requestHideAutoHidingPanel();
|
||||
|
||||
/**
|
||||
* Requests to show a surface with Role Panel and PanelBahvior AutoHide.
|
||||
*
|
||||
* This request allows the client to show a surface which it previously
|
||||
* requested to be hidden with {@link requestHideAutoHidingPanel}.
|
||||
*
|
||||
* @see autoHidePanelHidden
|
||||
* @see autoHidePanelShown
|
||||
* @see requestHideAutoHidingPanel
|
||||
* @since 5.28
|
||||
**/
|
||||
void requestShowAutoHidingPanel();
|
||||
|
||||
/**
|
||||
* Set whether a PlasmaShellSurface should get focus or not.
|
||||
*
|
||||
* By default some roles do not take focus. With this request the compositor
|
||||
* can be instructed to also pass focus.
|
||||
*
|
||||
* @param takesFocus Set to @c true if the surface should gain focus.
|
||||
* @since 5.28
|
||||
**/
|
||||
// KF6 TODO rename to make it generic
|
||||
void setPanelTakesFocus(bool takesFocus);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted when the compositor hid an auto hiding panel.
|
||||
* @see requestHideAutoHidingPanel
|
||||
* @see autoHidePanelShown
|
||||
* @see requestShowAutoHidingPanel
|
||||
* @since 5.28
|
||||
**/
|
||||
void autoHidePanelHidden();
|
||||
|
||||
/**
|
||||
* Emitted when the compositor showed an auto hiding panel.
|
||||
* @see requestHideAutoHidingPanel
|
||||
* @see autoHidePanelHidden
|
||||
* @see requestShowAutoHidingPanel
|
||||
* @since 5.28
|
||||
**/
|
||||
void autoHidePanelShown();
|
||||
|
||||
private:
|
||||
friend class PlasmaShell;
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWayland::Client::PlasmaShellSurface::Role)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::PlasmaShellSurface::PanelBehavior)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2018 Marco Martin <notmart@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "plasmavirtualdesktop.h"
|
||||
#include "event_queue.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QMap>
|
||||
|
||||
#include <wayland-plasma-virtual-desktop-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN PlasmaVirtualDesktopManagement::Private
|
||||
{
|
||||
public:
|
||||
Private(PlasmaVirtualDesktopManagement *q);
|
||||
|
||||
void setup(org_kde_plasma_virtual_desktop_management *arg);
|
||||
|
||||
WaylandPointer<org_kde_plasma_virtual_desktop_management, org_kde_plasma_virtual_desktop_management_destroy> plasmavirtualdesktopmanagement;
|
||||
EventQueue *queue = nullptr;
|
||||
|
||||
quint32 rows = 1;
|
||||
QList<PlasmaVirtualDesktop *> desktops;
|
||||
|
||||
inline QList<PlasmaVirtualDesktop *>::const_iterator constFindDesktop(const QString &id);
|
||||
inline QList<PlasmaVirtualDesktop *>::iterator findDesktop(const QString &id);
|
||||
|
||||
private:
|
||||
static void
|
||||
createdCallback(void *data, org_kde_plasma_virtual_desktop_management *org_kde_plasma_virtual_desktop_management, const char *id, uint32_t position);
|
||||
static void removedCallback(void *data, org_kde_plasma_virtual_desktop_management *org_kde_plasma_virtual_desktop_management, const char *id);
|
||||
static void rowsCallback(void *data, org_kde_plasma_virtual_desktop_management *org_kde_plasma_virtual_desktop_management, uint32_t rows);
|
||||
static void doneCallback(void *data, org_kde_plasma_virtual_desktop_management *org_kde_plasma_virtual_desktop_management);
|
||||
|
||||
PlasmaVirtualDesktopManagement *q;
|
||||
|
||||
static const org_kde_plasma_virtual_desktop_management_listener s_listener;
|
||||
};
|
||||
|
||||
class Q_DECL_HIDDEN PlasmaVirtualDesktop::Private
|
||||
{
|
||||
public:
|
||||
Private(PlasmaVirtualDesktop *q);
|
||||
|
||||
void setup(org_kde_plasma_virtual_desktop *arg);
|
||||
|
||||
WaylandPointer<org_kde_plasma_virtual_desktop, org_kde_plasma_virtual_desktop_destroy> plasmavirtualdesktop;
|
||||
|
||||
QString id;
|
||||
QString name;
|
||||
bool active = false;
|
||||
|
||||
private:
|
||||
PlasmaVirtualDesktop *q;
|
||||
|
||||
private:
|
||||
static void idCallback(void *data, org_kde_plasma_virtual_desktop *org_kde_plasma_virtual_desktop, const char *id);
|
||||
static void nameCallback(void *data, org_kde_plasma_virtual_desktop *org_kde_plasma_virtual_desktop, const char *name);
|
||||
|
||||
static void activatedCallback(void *data, org_kde_plasma_virtual_desktop *org_kde_plasma_virtual_desktop);
|
||||
static void deactivatedCallback(void *data, org_kde_plasma_virtual_desktop *org_kde_plasma_virtual_desktop);
|
||||
static void doneCallback(void *data, org_kde_plasma_virtual_desktop *org_kde_plasma_virtual_desktop);
|
||||
static void removedCallback(void *data, org_kde_plasma_virtual_desktop *org_kde_plasma_virtual_desktop);
|
||||
|
||||
static const org_kde_plasma_virtual_desktop_listener s_listener;
|
||||
};
|
||||
|
||||
inline QList<PlasmaVirtualDesktop *>::const_iterator PlasmaVirtualDesktopManagement::Private::constFindDesktop(const QString &id)
|
||||
{
|
||||
return std::find_if(desktops.constBegin(), desktops.constEnd(), [id](const PlasmaVirtualDesktop *desk) {
|
||||
return desk->id() == id;
|
||||
});
|
||||
}
|
||||
|
||||
inline QList<PlasmaVirtualDesktop *>::iterator PlasmaVirtualDesktopManagement::Private::findDesktop(const QString &id)
|
||||
{
|
||||
return std::find_if(desktops.begin(), desktops.end(), [id](const PlasmaVirtualDesktop *desk) {
|
||||
return desk->id() == id;
|
||||
});
|
||||
}
|
||||
|
||||
const org_kde_plasma_virtual_desktop_management_listener PlasmaVirtualDesktopManagement::Private::s_listener = {createdCallback,
|
||||
removedCallback,
|
||||
doneCallback,
|
||||
rowsCallback};
|
||||
|
||||
void PlasmaVirtualDesktopManagement::Private::createdCallback(void *data,
|
||||
org_kde_plasma_virtual_desktop_management *org_kde_plasma_virtual_desktop_management,
|
||||
const char *id,
|
||||
uint32_t position)
|
||||
{
|
||||
auto p = reinterpret_cast<PlasmaVirtualDesktopManagement::Private *>(data);
|
||||
Q_ASSERT(p->plasmavirtualdesktopmanagement == org_kde_plasma_virtual_desktop_management);
|
||||
const QString stringId = QString::fromUtf8(id);
|
||||
PlasmaVirtualDesktop *vd = p->q->getVirtualDesktop(stringId);
|
||||
Q_ASSERT(vd);
|
||||
|
||||
p->desktops.insert(position, vd);
|
||||
// TODO: emit a lot of desktopMoved?
|
||||
|
||||
Q_EMIT p->q->desktopCreated(stringId, position);
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktopManagement::Private::removedCallback(void *data,
|
||||
org_kde_plasma_virtual_desktop_management *org_kde_plasma_virtual_desktop_management,
|
||||
const char *id)
|
||||
{
|
||||
auto p = reinterpret_cast<PlasmaVirtualDesktopManagement::Private *>(data);
|
||||
Q_ASSERT(p->plasmavirtualdesktopmanagement == org_kde_plasma_virtual_desktop_management);
|
||||
const QString stringId = QString::fromUtf8(id);
|
||||
PlasmaVirtualDesktop *vd = p->q->getVirtualDesktop(stringId);
|
||||
// TODO: emit a lot of desktopMoved?
|
||||
Q_ASSERT(vd);
|
||||
auto i = p->findDesktop(stringId);
|
||||
p->desktops.erase(i);
|
||||
vd->release();
|
||||
vd->destroy();
|
||||
vd->deleteLater();
|
||||
Q_EMIT p->q->desktopRemoved(stringId);
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktopManagement::Private::rowsCallback(void *data,
|
||||
org_kde_plasma_virtual_desktop_management *org_kde_plasma_virtual_desktop_management,
|
||||
uint32_t rows)
|
||||
{
|
||||
auto p = reinterpret_cast<PlasmaVirtualDesktopManagement::Private *>(data);
|
||||
Q_ASSERT(p->plasmavirtualdesktopmanagement == org_kde_plasma_virtual_desktop_management);
|
||||
if (rows == 0) {
|
||||
return;
|
||||
}
|
||||
p->rows = rows;
|
||||
Q_EMIT p->q->rowsChanged(rows);
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktopManagement::Private::doneCallback(void *data, org_kde_plasma_virtual_desktop_management *org_kde_plasma_virtual_desktop_management)
|
||||
{
|
||||
auto p = reinterpret_cast<PlasmaVirtualDesktopManagement::Private *>(data);
|
||||
Q_ASSERT(p->plasmavirtualdesktopmanagement == org_kde_plasma_virtual_desktop_management);
|
||||
Q_EMIT p->q->done();
|
||||
}
|
||||
|
||||
PlasmaVirtualDesktopManagement::PlasmaVirtualDesktopManagement(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
PlasmaVirtualDesktopManagement::Private::Private(PlasmaVirtualDesktopManagement *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktopManagement::Private::setup(org_kde_plasma_virtual_desktop_management *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!plasmavirtualdesktopmanagement);
|
||||
plasmavirtualdesktopmanagement.setup(arg);
|
||||
org_kde_plasma_virtual_desktop_management_add_listener(plasmavirtualdesktopmanagement, &s_listener, this);
|
||||
}
|
||||
|
||||
PlasmaVirtualDesktopManagement::~PlasmaVirtualDesktopManagement()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktopManagement::setup(org_kde_plasma_virtual_desktop_management *plasmavirtualdesktopmanagement)
|
||||
{
|
||||
d->setup(plasmavirtualdesktopmanagement);
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktopManagement::release()
|
||||
{
|
||||
d->plasmavirtualdesktopmanagement.release();
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktopManagement::destroy()
|
||||
{
|
||||
d->plasmavirtualdesktopmanagement.destroy();
|
||||
}
|
||||
|
||||
PlasmaVirtualDesktopManagement::operator org_kde_plasma_virtual_desktop_management *()
|
||||
{
|
||||
return d->plasmavirtualdesktopmanagement;
|
||||
}
|
||||
|
||||
PlasmaVirtualDesktopManagement::operator org_kde_plasma_virtual_desktop_management *() const
|
||||
{
|
||||
return d->plasmavirtualdesktopmanagement;
|
||||
}
|
||||
|
||||
bool PlasmaVirtualDesktopManagement::isValid() const
|
||||
{
|
||||
return d->plasmavirtualdesktopmanagement.isValid();
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktopManagement::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *PlasmaVirtualDesktopManagement::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
PlasmaVirtualDesktop *PlasmaVirtualDesktopManagement::getVirtualDesktop(const QString &id)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
|
||||
if (id.isEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto i = d->constFindDesktop(id);
|
||||
if (i != d->desktops.constEnd()) {
|
||||
return *i;
|
||||
}
|
||||
|
||||
auto w = org_kde_plasma_virtual_desktop_management_get_virtual_desktop(d->plasmavirtualdesktopmanagement, id.toUtf8());
|
||||
|
||||
if (!w) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
|
||||
auto desktop = new PlasmaVirtualDesktop(this);
|
||||
desktop->setup(w);
|
||||
desktop->d->id = id;
|
||||
|
||||
return desktop;
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktopManagement::requestRemoveVirtualDesktop(const QString &id)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
|
||||
org_kde_plasma_virtual_desktop_management_request_remove_virtual_desktop(d->plasmavirtualdesktopmanagement, id.toUtf8());
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktopManagement::requestCreateVirtualDesktop(const QString &name, quint32 position)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
|
||||
org_kde_plasma_virtual_desktop_management_request_create_virtual_desktop(d->plasmavirtualdesktopmanagement, name.toUtf8(), position);
|
||||
}
|
||||
|
||||
QList<PlasmaVirtualDesktop *> PlasmaVirtualDesktopManagement::desktops() const
|
||||
{
|
||||
return d->desktops;
|
||||
}
|
||||
|
||||
quint32 PlasmaVirtualDesktopManagement::rows() const
|
||||
{
|
||||
return d->rows;
|
||||
}
|
||||
|
||||
const org_kde_plasma_virtual_desktop_listener PlasmaVirtualDesktop::Private::s_listener =
|
||||
{idCallback, nameCallback, activatedCallback, deactivatedCallback, doneCallback, removedCallback};
|
||||
|
||||
void PlasmaVirtualDesktop::Private::idCallback(void *data, org_kde_plasma_virtual_desktop *org_kde_plasma_virtual_desktop, const char *id)
|
||||
{
|
||||
auto p = reinterpret_cast<PlasmaVirtualDesktop::Private *>(data);
|
||||
Q_ASSERT(p->plasmavirtualdesktop == org_kde_plasma_virtual_desktop);
|
||||
p->id = QString::fromUtf8(id);
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktop::Private::nameCallback(void *data, org_kde_plasma_virtual_desktop *org_kde_plasma_virtual_desktop, const char *name)
|
||||
{
|
||||
auto p = reinterpret_cast<PlasmaVirtualDesktop::Private *>(data);
|
||||
Q_ASSERT(p->plasmavirtualdesktop == org_kde_plasma_virtual_desktop);
|
||||
p->name = QString::fromUtf8(name);
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktop::Private::activatedCallback(void *data, org_kde_plasma_virtual_desktop *org_kde_plasma_virtual_desktop)
|
||||
{
|
||||
auto p = reinterpret_cast<PlasmaVirtualDesktop::Private *>(data);
|
||||
Q_ASSERT(p->plasmavirtualdesktop == org_kde_plasma_virtual_desktop);
|
||||
p->active = true;
|
||||
Q_EMIT p->q->activated();
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktop::Private::deactivatedCallback(void *data, org_kde_plasma_virtual_desktop *org_kde_plasma_virtual_desktop)
|
||||
{
|
||||
auto p = reinterpret_cast<PlasmaVirtualDesktop::Private *>(data);
|
||||
Q_ASSERT(p->plasmavirtualdesktop == org_kde_plasma_virtual_desktop);
|
||||
p->active = false;
|
||||
Q_EMIT p->q->deactivated();
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktop::Private::doneCallback(void *data, org_kde_plasma_virtual_desktop *org_kde_plasma_virtual_desktop)
|
||||
{
|
||||
auto p = reinterpret_cast<PlasmaVirtualDesktop::Private *>(data);
|
||||
Q_ASSERT(p->plasmavirtualdesktop == org_kde_plasma_virtual_desktop);
|
||||
Q_EMIT p->q->done();
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktop::Private::removedCallback(void *data, org_kde_plasma_virtual_desktop *org_kde_plasma_virtual_desktop)
|
||||
{
|
||||
auto p = reinterpret_cast<PlasmaVirtualDesktop::Private *>(data);
|
||||
Q_ASSERT(p->plasmavirtualdesktop == org_kde_plasma_virtual_desktop);
|
||||
Q_EMIT p->q->removed();
|
||||
}
|
||||
|
||||
PlasmaVirtualDesktop::Private::Private(PlasmaVirtualDesktop *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
PlasmaVirtualDesktop::PlasmaVirtualDesktop(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktop::Private::setup(org_kde_plasma_virtual_desktop *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!plasmavirtualdesktop);
|
||||
plasmavirtualdesktop.setup(arg);
|
||||
org_kde_plasma_virtual_desktop_add_listener(plasmavirtualdesktop, &s_listener, this);
|
||||
}
|
||||
|
||||
PlasmaVirtualDesktop::~PlasmaVirtualDesktop()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktop::setup(org_kde_plasma_virtual_desktop *plasmavirtualdesktop)
|
||||
{
|
||||
d->setup(plasmavirtualdesktop);
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktop::release()
|
||||
{
|
||||
d->plasmavirtualdesktop.release();
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktop::destroy()
|
||||
{
|
||||
d->plasmavirtualdesktop.destroy();
|
||||
}
|
||||
|
||||
PlasmaVirtualDesktop::operator org_kde_plasma_virtual_desktop *()
|
||||
{
|
||||
return d->plasmavirtualdesktop;
|
||||
}
|
||||
|
||||
PlasmaVirtualDesktop::operator org_kde_plasma_virtual_desktop *() const
|
||||
{
|
||||
return d->plasmavirtualdesktop;
|
||||
}
|
||||
|
||||
bool PlasmaVirtualDesktop::isValid() const
|
||||
{
|
||||
return d->plasmavirtualdesktop.isValid();
|
||||
}
|
||||
|
||||
void PlasmaVirtualDesktop::requestActivate()
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
org_kde_plasma_virtual_desktop_request_activate(d->plasmavirtualdesktop);
|
||||
}
|
||||
|
||||
QString PlasmaVirtualDesktop::id() const
|
||||
{
|
||||
return d->id;
|
||||
}
|
||||
|
||||
QString PlasmaVirtualDesktop::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
bool PlasmaVirtualDesktop::isActive() const
|
||||
{
|
||||
return d->active;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_plasmavirtualdesktop.cpp"
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2018 Marco Martin <notmart@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_PLASMAVIRTUALDESKTOP_H
|
||||
#define KWAYLAND_CLIENT_PLASMAVIRTUALDESKTOP_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct org_kde_plasma_virtual_desktop_management;
|
||||
struct org_kde_plasma_virtual_desktop;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class PlasmaVirtualDesktop;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the org_kde_plasma_virtual_desktop_management interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the org_kde_plasma_virtual_desktop_management interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the PlasmaVirtualDesktopManagement interface:
|
||||
* @code
|
||||
* PlasmaVirtualDesktopManagement *c = registry->createPlasmaVirtualDesktopManagement(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the PlasmaVirtualDesktopManagement and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* PlasmaVirtualDesktopManagement *c = new PlasmaVirtualDesktopManagement;
|
||||
* c->setup(registry->bindPlasmaVirtualDesktopManagement(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The PlasmaVirtualDesktopManagement can be used as a drop-in replacement for any org_kde_plasma_virtual_desktop_management
|
||||
* pointer as it provides matching cast operators.
|
||||
* @since 5.52
|
||||
*
|
||||
* @see Registry
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT PlasmaVirtualDesktopManagement : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new PlasmaVirtualDesktopManagement.
|
||||
* Note: after constructing the PlasmaVirtualDesktopManagement it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use PlasmaVirtualDesktopManagement prefer using
|
||||
* Registry::createPlasmaVirtualDesktopManagement.
|
||||
**/
|
||||
explicit PlasmaVirtualDesktopManagement(QObject *parent = nullptr);
|
||||
~PlasmaVirtualDesktopManagement() override;
|
||||
|
||||
/**
|
||||
* Setup this PlasmaVirtualDesktopManagement to manage the @p plasmavirtualdesktopmanagement.
|
||||
* When using Registry::createPlasmaVirtualDesktopManagement there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_plasma_virtual_desktop_management *plasmavirtualdesktopmanagement);
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_plasma_virtual_desktop_management.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the org_kde_plasma_virtual_desktop_management interface.
|
||||
* After the interface has been released the PlasmaVirtualDesktopManagement instance is no
|
||||
* longer valid and can be setup with another org_kde_plasma_virtual_desktop_management interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this PlasmaVirtualDesktopManagement.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_plasma_virtual_desktop_management interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, plasmavirtualdesktopmanagement, &PlasmaVirtualDesktopManagement::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating objects with this PlasmaVirtualDesktopManagement.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
|
||||
/**
|
||||
* @returns The event queue to use for creating objects with this PlasmaVirtualDesktopManagement.
|
||||
* The object is owned by the manager and the caller should not delete it.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* @returns the PlasmaVirtualDesktop representing the desktop id.
|
||||
* The PlasmaVirtualDesktop instance is guaranteed to be unique for each id.
|
||||
*/
|
||||
PlasmaVirtualDesktop *getVirtualDesktop(const QString &id);
|
||||
|
||||
/**
|
||||
* Requests for the desktop identified by id to be removed.
|
||||
* The server may or may not acconsent to the request.
|
||||
*/
|
||||
void requestRemoveVirtualDesktop(const QString &id);
|
||||
|
||||
/**
|
||||
* Ask the server to create a new virtual desktop, and position it at a specified position.
|
||||
* If the position is zero or less, it will be positioned at the beginning,
|
||||
* if the cosition is the count or more, it will be positioned at the end.
|
||||
* @param name The name we want for the desktop
|
||||
* @param position The position for the desktop to be created
|
||||
*/
|
||||
void requestCreateVirtualDesktop(const QString &name, quint32 position = std::numeric_limits<uint32_t>::max());
|
||||
|
||||
/**
|
||||
* @returns All the existent virtual desktops
|
||||
*/
|
||||
QList<PlasmaVirtualDesktop *> desktops() const;
|
||||
|
||||
/**
|
||||
* @returns How many rows the virtual desktops should be laid out into
|
||||
* @since 5.55
|
||||
*/
|
||||
quint32 rows() const;
|
||||
|
||||
operator org_kde_plasma_virtual_desktop_management *();
|
||||
operator org_kde_plasma_virtual_desktop_management *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void removed();
|
||||
|
||||
/**
|
||||
* Emitted when a new desktop has been added
|
||||
*/
|
||||
void desktopCreated(const QString &id, quint32 position);
|
||||
|
||||
/**
|
||||
* Emitted when a desktop has been removed
|
||||
*/
|
||||
void desktopRemoved(const QString &id);
|
||||
|
||||
/**
|
||||
* Emitted when the number of rows of virtual desktops has been changed by the server
|
||||
* @since 5.55
|
||||
*/
|
||||
void rowsChanged(quint32 rows);
|
||||
|
||||
/**
|
||||
* This event is sent after all other properties has been
|
||||
* sent after binding to the desktop manager object and after any
|
||||
* other property changes done after that. This allows
|
||||
* changes to the org_kde_plasma_virtual_desktop_management properties
|
||||
* to be seen as atomic, even if they happen via multiple events.
|
||||
*/
|
||||
void done();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
class KWAYLANDCLIENT_EXPORT PlasmaVirtualDesktop : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~PlasmaVirtualDesktop() override;
|
||||
|
||||
/**
|
||||
* Setup this PlasmaVirtualDesktop to manage the @p plasmavirtualdesktop.
|
||||
* When using PlasmaVirtualDesktopManagement::createPlasmaVirtualDesktop there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_plasma_virtual_desktop *plasmavirtualdesktop);
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_plasma_virtual_desktop.
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* Releases the org_kde_plasma_virtual_desktop interface.
|
||||
* After the interface has been released the PlasmaVirtualDesktop instance is no
|
||||
* longer valid and can be setup with another org_kde_plasma_virtual_desktop interface.
|
||||
**/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* Destroys the data held by this PlasmaVirtualDesktop.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_plasma_virtual_desktop interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, plasmavirtualdesktop, &PlasmaVirtualDesktop::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Requests this desktop to be activated.
|
||||
* The server may or may not decide to consent to the request.
|
||||
*/
|
||||
void requestActivate();
|
||||
|
||||
/**
|
||||
* @returns The unique id of this desktop. The format of the id is decided by the compositor
|
||||
*/
|
||||
QString id() const;
|
||||
|
||||
/**
|
||||
* @returns User readable name for the desktop.
|
||||
*/
|
||||
QString name() const;
|
||||
|
||||
/**
|
||||
* @returns True if the desktop is the active one.
|
||||
* when this property changes, activated or deactivated will be emitted.
|
||||
* @see activated
|
||||
* @see deactivated
|
||||
*/
|
||||
bool isActive() const;
|
||||
|
||||
operator org_kde_plasma_virtual_desktop *();
|
||||
operator org_kde_plasma_virtual_desktop *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* TODO: activeChanged(bool)?
|
||||
* Emitted when this desktop has been activated by the server
|
||||
*/
|
||||
void activated();
|
||||
|
||||
/**
|
||||
* Emitted when this desktop has been activated by the server
|
||||
*/
|
||||
void deactivated();
|
||||
|
||||
/**
|
||||
* This event is sent after all other properties has been
|
||||
* sent after binding to the desktop manager object and after any
|
||||
* other property changes done after that. This allows
|
||||
* changes to the org_kde_plasma_virtual_desktop properties
|
||||
* to be seen as atomic, even if they happen via multiple events.
|
||||
*/
|
||||
void done();
|
||||
|
||||
/**
|
||||
* This virtual desktop has just been removed by the server:
|
||||
* This object itself is about to be deleted. All windows will
|
||||
* lose the association to this desktop.
|
||||
*/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
friend class PlasmaVirtualDesktopManagement;
|
||||
explicit PlasmaVirtualDesktop(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,902 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_PLASMAWINDOWMANAGEMENT_H
|
||||
#define WAYLAND_PLASMAWINDOWMANAGEMENT_H
|
||||
|
||||
#include <QIcon>
|
||||
#include <QObject>
|
||||
#include <QSize>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct org_kde_plasma_activation_feedback;
|
||||
struct org_kde_plasma_activation;
|
||||
struct org_kde_plasma_window_management;
|
||||
struct org_kde_plasma_window;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Output;
|
||||
class PlasmaActivationFeedback;
|
||||
class PlasmaWindow;
|
||||
class PlasmaWindowModel;
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the org_kde_plasma_window_management interface.
|
||||
*
|
||||
* PlasmaWindowManagement is a privileged interface. A Wayland compositor is allowed to ignore
|
||||
* any requests. The PlasmaWindowManagement allows to get information about the overall windowing
|
||||
* system. It allows to see which windows are currently available and thus is the base to implement
|
||||
* e.g. a task manager.
|
||||
*
|
||||
* This class provides a convenient wrapper for the org_kde_plasma_window_management interface.
|
||||
* It's main purpose is to create a PlasmaWindowManagementSurface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the Shell interface:
|
||||
* @code
|
||||
* PlasmaWindowManagement *s = registry->createPlasmaWindowManagement(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the PlasmaWindowManagement and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* PlasmaWindowManagement *s = new PlasmaWindowManagement;
|
||||
* s->setup(registry->bindPlasmaWindowManagement(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The PlasmaWindowManagement can be used as a drop-in replacement for any org_kde_plasma_window_management
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
* @see PlasmaWindowManagementSurface
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT PlasmaWindowManagement : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit PlasmaWindowManagement(QObject *parent = nullptr);
|
||||
~PlasmaWindowManagement() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_plasma_window_management.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the org_kde_plasma_window_management interface.
|
||||
* After the interface has been released the PlasmaWindowManagement instance is no
|
||||
* longer valid and can be setup with another org_kde_plasma_window_management interface.
|
||||
*
|
||||
* Right before the interface is released the signal interfaceAboutToBeReleased is emitted.
|
||||
* @see interfaceAboutToBeReleased
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this PlasmaWindowManagement.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. Once the connection becomes invalid, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_plasma_window_management interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* PlasmaWindowManagement gets destroyed.
|
||||
*
|
||||
* Right before the data is destroyed, the signal interfaceAboutToBeDestroyed is emitted.
|
||||
*
|
||||
* @see release
|
||||
* @see interfaceAboutToBeDestroyed
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* Setup this Shell to manage the @p shell.
|
||||
* When using Registry::createShell there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_plasma_window_management *shell);
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating a Surface.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating a Surface.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
operator org_kde_plasma_window_management *();
|
||||
operator org_kde_plasma_window_management *() const;
|
||||
|
||||
/**
|
||||
* Whether the system is currently showing the desktop.
|
||||
* This means that the system focuses on the desktop and hides other windows.
|
||||
* @see setShowingDesktop
|
||||
* @see showDesktop
|
||||
* @see hideDesktop
|
||||
* @see showingDesktopChanged
|
||||
**/
|
||||
bool isShowingDesktop() const;
|
||||
/**
|
||||
* Requests to change the showing desktop state to @p show.
|
||||
* @see isShowingDesktop
|
||||
* @see showDesktop
|
||||
* @see hideDesktop
|
||||
**/
|
||||
void setShowingDesktop(bool show);
|
||||
/**
|
||||
* Same as calling setShowingDesktop with @c true.
|
||||
* @see setShowingDesktop
|
||||
**/
|
||||
void showDesktop();
|
||||
/**
|
||||
* Same as calling setShowingDesktop with @c false.
|
||||
* @see setShowingDesktop
|
||||
**/
|
||||
void hideDesktop();
|
||||
|
||||
/**
|
||||
* @returns All windows currently known to the PlasmaWindowManagement
|
||||
* @see windowCreated
|
||||
**/
|
||||
QList<PlasmaWindow *> windows() const;
|
||||
/**
|
||||
* @returns The currently active PlasmaWindow, the PlasmaWindow which
|
||||
* returns @c true in {@link PlasmaWindow::isActive} or @c nullptr in case
|
||||
* there is no active window.
|
||||
**/
|
||||
PlasmaWindow *activeWindow() const;
|
||||
/**
|
||||
* Factory method to create a PlasmaWindowModel.
|
||||
* @returns a new created PlasmaWindowModel
|
||||
**/
|
||||
PlasmaWindowModel *createWindowModel();
|
||||
|
||||
/**
|
||||
* @returns windows stacking order
|
||||
*
|
||||
* @since 5.73
|
||||
*/
|
||||
QList<QByteArray> stackingOrderUuids() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* This signal is emitted right before the interface is released.
|
||||
**/
|
||||
void interfaceAboutToBeReleased();
|
||||
/**
|
||||
* This signal is emitted right before the data is destroyed.
|
||||
**/
|
||||
void interfaceAboutToBeDestroyed();
|
||||
/**
|
||||
* The showing desktop state changed.
|
||||
* @see isShowingDesktop
|
||||
**/
|
||||
void showingDesktopChanged(bool);
|
||||
|
||||
/**
|
||||
* A new @p window got created.
|
||||
* @see windows
|
||||
**/
|
||||
void windowCreated(KWayland::Client::PlasmaWindow *window);
|
||||
/**
|
||||
* The active window changed.
|
||||
* @see activeWindow
|
||||
**/
|
||||
void activeWindowChanged();
|
||||
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the Compositor got created by
|
||||
* Registry::createPlasmaWindowManagement
|
||||
*
|
||||
* @since 5.5
|
||||
**/
|
||||
void removed();
|
||||
|
||||
/**
|
||||
* The stacking order uuids changed
|
||||
* @since 5.73
|
||||
**/
|
||||
void stackingOrderUuidsChanged();
|
||||
|
||||
public:
|
||||
class Private;
|
||||
|
||||
private:
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Wrapper for the org_kde_plasma_window interface.
|
||||
*
|
||||
* A PlasmaWindow gets created by the PlasmaWindowManagement and announced through
|
||||
* the {@link PlasmaWindowManagement::windowCreated} signal. The PlasmaWindow encapsulates
|
||||
* state about a window managed by the Wayland server and allows to request state changes.
|
||||
*
|
||||
* The PlasmaWindow will be automatically deleted when the PlasmaWindow gets unmapped.
|
||||
*
|
||||
* This class is a convenient wrapper for the org_kde_plasma_window interface.
|
||||
* The PlasmaWindow gets created by PlasmaWindowManagement.
|
||||
*
|
||||
* @see PlasmaWindowManager
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT PlasmaWindow : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~PlasmaWindow() override;
|
||||
|
||||
/**
|
||||
* Releases the org_kde_plasma_window interface.
|
||||
* After the interface has been released the PlasmaWindow instance is no
|
||||
* longer valid and can be setup with another org_kde_plasma_window interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this PlasmaWindow.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_plasma_window interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, source, &PlasmaWindow::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_plasma_window.
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
operator org_kde_plasma_window *();
|
||||
operator org_kde_plasma_window *() const;
|
||||
|
||||
/**
|
||||
* @returns the window title.
|
||||
* @see titleChanged
|
||||
**/
|
||||
QString title() const;
|
||||
/**
|
||||
* @returns the application id which should reflect the name of a desktop file.
|
||||
* @see appIdChanged
|
||||
**/
|
||||
QString appId() const;
|
||||
/**
|
||||
* @returns Whether the window is currently the active Window.
|
||||
* @see activeChanged
|
||||
**/
|
||||
bool isActive() const;
|
||||
/**
|
||||
* @returns Whether the window is fullscreen
|
||||
* @see fullscreenChanged
|
||||
**/
|
||||
bool isFullscreen() const;
|
||||
/**
|
||||
* @returns Whether the window is kept above other windows.
|
||||
* @see keepAboveChanged
|
||||
**/
|
||||
bool isKeepAbove() const;
|
||||
/**
|
||||
* @returns Whether the window is kept below other window
|
||||
* @see keepBelowChanged
|
||||
**/
|
||||
bool isKeepBelow() const;
|
||||
/**
|
||||
* @returns Whether the window is currently minimized
|
||||
* @see minimizedChanged
|
||||
**/
|
||||
bool isMinimized() const;
|
||||
/**
|
||||
* @returns Whether the window is maximized.
|
||||
* @see maximizedChanged
|
||||
**/
|
||||
bool isMaximized() const;
|
||||
/**
|
||||
* @returns Whether the window is shown on all desktops.
|
||||
* @see virtualDesktop
|
||||
* @see onAllDesktopsChanged
|
||||
**/
|
||||
bool isOnAllDesktops() const;
|
||||
/**
|
||||
* @returns Whether the window is demanding attention.
|
||||
* @see demandsAttentionChanged
|
||||
**/
|
||||
bool isDemandingAttention() const;
|
||||
/**
|
||||
* @returns Whether the window can be closed.
|
||||
* @see closeableChanged
|
||||
**/
|
||||
bool isCloseable() const;
|
||||
/**
|
||||
* @returns Whether the window can be maximized.
|
||||
* @see maximizeableChanged
|
||||
**/
|
||||
bool isMaximizeable() const;
|
||||
/**
|
||||
* @returns Whether the window can be minimized.
|
||||
* @see minimizeableChanged
|
||||
**/
|
||||
bool isMinimizeable() const;
|
||||
/**
|
||||
* @returns Whether the window can be set to fullscreen.
|
||||
* @see fullscreenableChanged
|
||||
**/
|
||||
bool isFullscreenable() const;
|
||||
/**
|
||||
* @returns Whether the window should be ignored by a task bar.
|
||||
* @see skipTaskbarChanged
|
||||
**/
|
||||
bool skipTaskbar() const;
|
||||
/**
|
||||
* @returns Whether the window should be ignored by a switcher.
|
||||
* @see skipSwitcherChanged
|
||||
**/
|
||||
bool skipSwitcher() const;
|
||||
/**
|
||||
* @returns The icon of the window.
|
||||
* @see iconChanged
|
||||
**/
|
||||
QIcon icon() const;
|
||||
/**
|
||||
* @returns Whether the window can be set to the shaded state.
|
||||
* @see isShaded
|
||||
* @see shadeableChanged
|
||||
* @since 5.22
|
||||
*/
|
||||
bool isShadeable() const;
|
||||
/**
|
||||
* @returns Whether the window is shaded, that is reduced to the window decoration
|
||||
* @see shadedChanged
|
||||
* @since 5.22
|
||||
*/
|
||||
bool isShaded() const;
|
||||
/**
|
||||
* @returns Whether the window can be moved.
|
||||
* @see movableChanged
|
||||
* @since 5.22
|
||||
*/
|
||||
bool isMovable() const;
|
||||
/**
|
||||
* @returns Whether the window can be resized.
|
||||
* @see resizableChanged
|
||||
* @since 5.22
|
||||
*/
|
||||
bool isResizable() const;
|
||||
/**
|
||||
* @returns Whether the virtual desktop can be changed.
|
||||
* @see virtualDesktopChangeableChanged
|
||||
* @since 5.22
|
||||
*/
|
||||
bool isVirtualDesktopChangeable() const;
|
||||
/**
|
||||
* @returns The process id this window belongs to.
|
||||
* or 0 if unset
|
||||
* @since 5.35
|
||||
*/
|
||||
quint32 pid() const;
|
||||
/**
|
||||
* @returns The X11 resource name for this window.
|
||||
* This is only set for X11 windows.
|
||||
* @since 5.94
|
||||
*/
|
||||
QString resourceName() const;
|
||||
|
||||
/**
|
||||
* Requests to activate the window.
|
||||
**/
|
||||
void requestActivate();
|
||||
/**
|
||||
* Requests to close the window.
|
||||
**/
|
||||
void requestClose();
|
||||
/**
|
||||
* Requests to start an interactive window move operation.
|
||||
* @since 5.22
|
||||
*/
|
||||
void requestMove();
|
||||
/**
|
||||
* Requests to start an interactive resize operation.
|
||||
* @since 5.22
|
||||
*/
|
||||
void requestResize();
|
||||
|
||||
/**
|
||||
* Requests the window at this model row index have its keep above state toggled.
|
||||
* @since 5.35
|
||||
*/
|
||||
void requestToggleKeepAbove();
|
||||
|
||||
/**
|
||||
* Requests the window at this model row index have its keep below state toggled.
|
||||
* @since 5.35
|
||||
*/
|
||||
void requestToggleKeepBelow();
|
||||
|
||||
/**
|
||||
* Requests the window at this model row index have its minimized state toggled.
|
||||
*/
|
||||
void requestToggleMinimized();
|
||||
|
||||
/**
|
||||
* Requests the window at this model row index have its maximized state toggled.
|
||||
*/
|
||||
void requestToggleMaximized();
|
||||
|
||||
/**
|
||||
* Requests the window at this model row index have its fullscreen state toggled.
|
||||
* @since 6.0
|
||||
*/
|
||||
void requestToggleFullscreen();
|
||||
|
||||
/**
|
||||
* Sets the geometry of the taskbar entry for this window
|
||||
* relative to a panel in particular
|
||||
* @since 5.5
|
||||
*/
|
||||
void setMinimizedGeometry(Surface *panel, const QRect &geom);
|
||||
|
||||
/**
|
||||
* Remove the task geometry information for a particular panel
|
||||
* @since 5.5
|
||||
*/
|
||||
void unsetMinimizedGeometry(Surface *panel);
|
||||
|
||||
/**
|
||||
* Requests the window at this model row index have its shaded state toggled.
|
||||
* @since 5.22
|
||||
*/
|
||||
void requestToggleShaded();
|
||||
|
||||
/**
|
||||
* A unique identifier for the window
|
||||
*
|
||||
* @see QUuid
|
||||
* @since 5.73
|
||||
*/
|
||||
QByteArray uuid() const;
|
||||
|
||||
/**
|
||||
* The parent window of this PlasmaWindow.
|
||||
*
|
||||
* If there is a parent window, this window is a transient window for the
|
||||
* parent window. If this method returns a null PlasmaWindow it means this
|
||||
* window is a top level window and is not a transient window.
|
||||
*
|
||||
* @see parentWindowChanged
|
||||
* @since 5.24
|
||||
**/
|
||||
QPointer<PlasmaWindow> parentWindow() const;
|
||||
|
||||
/**
|
||||
* @returns The window geometry in absolute coordinates.
|
||||
* @see geometryChanged
|
||||
* @since 5.25
|
||||
**/
|
||||
QRect geometry() const;
|
||||
|
||||
/**
|
||||
* Ask the server to make the window enter a virtual desktop.
|
||||
* The server may or may not consent.
|
||||
* A window can enter more than one virtual desktop.
|
||||
*
|
||||
* @since 5.52
|
||||
*/
|
||||
void requestEnterVirtualDesktop(const QString &id);
|
||||
|
||||
/**
|
||||
* Make the window enter a new virtual desktop. If the server consents the request,
|
||||
* it will create a new virtual desktop and assign the window to it.
|
||||
* @since 5.52
|
||||
*/
|
||||
void requestEnterNewVirtualDesktop();
|
||||
|
||||
/**
|
||||
* Ask the server to make the window the window exit a virtual desktop.
|
||||
* The server may or may not consent.
|
||||
* If it exits all desktops it will be considered on all of them.
|
||||
*
|
||||
* @since 5.52
|
||||
*/
|
||||
void requestLeaveVirtualDesktop(const QString &id);
|
||||
|
||||
/**
|
||||
* Return all the virtual desktop ids this window is associated to.
|
||||
* When a desktop gets deleted, it will be automatically removed from this list.
|
||||
* If this list is empty, assume it's on all desktops.
|
||||
*
|
||||
* @since 5.52
|
||||
*/
|
||||
QStringList plasmaVirtualDesktops() const;
|
||||
|
||||
/**
|
||||
* Ask the server to make the window enter an activity.
|
||||
* The server may or may not consent.
|
||||
* A window can enter more than one activity.
|
||||
*
|
||||
* @since 5.81
|
||||
*/
|
||||
void requestEnterActivity(const QString &id);
|
||||
|
||||
/**
|
||||
* Ask the server to make the window exit an activity.
|
||||
* The server may or may not consent.
|
||||
* If it exits all activities it will be considered on all of them.
|
||||
*
|
||||
* @since 5.81
|
||||
*/
|
||||
void requestLeaveActivity(const QString &id);
|
||||
|
||||
/**
|
||||
* Return all the activity ids this window is associated to.
|
||||
* When an activity gets deleted, it will be automatically removed from this list.
|
||||
* If this list is empty, assume it's on all activities.
|
||||
*
|
||||
* @since 5.81
|
||||
*/
|
||||
QStringList plasmaActivities() const;
|
||||
|
||||
/**
|
||||
* Return the D-BUS service name for a window's
|
||||
* application menu.
|
||||
*
|
||||
* @since 5.69
|
||||
*/
|
||||
QString applicationMenuServiceName() const;
|
||||
/**
|
||||
* Return the D-BUS object path to a windows's
|
||||
* application menu.
|
||||
*
|
||||
* @since 5.69
|
||||
*/
|
||||
QString applicationMenuObjectPath() const;
|
||||
|
||||
/**
|
||||
* Sends the current window to @p output
|
||||
*
|
||||
* @since 5.86
|
||||
*/
|
||||
void sendToOutput(KWayland::Client::Output *output) const;
|
||||
|
||||
/**
|
||||
* @returns The client geometry (i.e. without window borders) in absolute coordinates.
|
||||
* @see clientGeometryChanged
|
||||
* @since 6.2
|
||||
**/
|
||||
QRect clientGeometry() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The window title changed.
|
||||
* @see title
|
||||
**/
|
||||
void titleChanged();
|
||||
/**
|
||||
* The application id changed.
|
||||
* @see appId
|
||||
**/
|
||||
void appIdChanged();
|
||||
/**
|
||||
* The window became active or inactive.
|
||||
* @see isActive
|
||||
**/
|
||||
void activeChanged();
|
||||
/**
|
||||
* The fullscreen state changed.
|
||||
* @see isFullscreen
|
||||
**/
|
||||
void fullscreenChanged();
|
||||
/**
|
||||
* The keep above state changed.
|
||||
* @see isKeepAbove
|
||||
**/
|
||||
void keepAboveChanged();
|
||||
/**
|
||||
* The keep below state changed.
|
||||
* @see isKeepBelow
|
||||
**/
|
||||
void keepBelowChanged();
|
||||
/**
|
||||
* The minimized state changed.
|
||||
* @see isMinimized
|
||||
**/
|
||||
void minimizedChanged();
|
||||
/**
|
||||
* The maximized state changed.
|
||||
* @see isMaximized
|
||||
**/
|
||||
void maximizedChanged();
|
||||
/**
|
||||
* The on all desktops state changed.
|
||||
* @see isOnAllDesktops
|
||||
**/
|
||||
void onAllDesktopsChanged();
|
||||
/**
|
||||
* The demands attention state changed.
|
||||
* @see isDemandingAttention
|
||||
**/
|
||||
void demandsAttentionChanged();
|
||||
/**
|
||||
* The closeable state changed.
|
||||
* @see isCloseable
|
||||
**/
|
||||
void closeableChanged();
|
||||
/**
|
||||
* The minimizeable state changed.
|
||||
* @see isMinimizeable
|
||||
**/
|
||||
void minimizeableChanged();
|
||||
/**
|
||||
* The maximizeable state changed.
|
||||
* @see isMaximizeable
|
||||
**/
|
||||
void maximizeableChanged();
|
||||
/**
|
||||
* The fullscreenable state changed.
|
||||
* @see isFullscreenable
|
||||
**/
|
||||
void fullscreenableChanged();
|
||||
/**
|
||||
* The skip taskbar state changed.
|
||||
* @see skipTaskbar
|
||||
**/
|
||||
void skipTaskbarChanged();
|
||||
/**
|
||||
* The skip switcher state changed.
|
||||
* @see skipSwitcher
|
||||
**/
|
||||
void skipSwitcherChanged();
|
||||
/**
|
||||
* The window icon changed.
|
||||
* @see icon
|
||||
**/
|
||||
void iconChanged();
|
||||
/**
|
||||
* The shadeable state changed.
|
||||
* @see isShadeable
|
||||
* @since 5.22
|
||||
*/
|
||||
void shadeableChanged();
|
||||
/**
|
||||
* The shaded state changed.
|
||||
* @see isShaded
|
||||
* @since 5.22
|
||||
*/
|
||||
void shadedChanged();
|
||||
/**
|
||||
* The movable state changed.
|
||||
* @see isMovable
|
||||
* @since 5.22
|
||||
*/
|
||||
void movableChanged();
|
||||
/**
|
||||
* The resizable state changed.
|
||||
* @see isResizable
|
||||
* @since 5.22
|
||||
*/
|
||||
void resizableChanged();
|
||||
/**
|
||||
* The virtual desktop changeable state changed.
|
||||
* @see virtualDesktopChangeable
|
||||
* @since 5.22
|
||||
*/
|
||||
void virtualDesktopChangeableChanged();
|
||||
/**
|
||||
* The window got unmapped and is no longer available to the Wayland server.
|
||||
* This instance will be automatically deleted and one should connect to this
|
||||
* signal to perform cleanup.
|
||||
**/
|
||||
void unmapped();
|
||||
/**
|
||||
* This signal is emitted whenever the parent window changes.
|
||||
* @see parentWindow
|
||||
* @since 5.24
|
||||
**/
|
||||
void parentWindowChanged();
|
||||
/**
|
||||
* This signal is emitted whenever the window geometry changes.
|
||||
* @see geometry
|
||||
* @since 5.25
|
||||
**/
|
||||
void geometryChanged();
|
||||
|
||||
/**
|
||||
* This signal is emitted whenever the resource name changes.
|
||||
* @see resourceName
|
||||
* @since 5.94
|
||||
**/
|
||||
void resourceNameChanged();
|
||||
|
||||
/**
|
||||
* This signal is emitted when the window has entered a new virtual desktop.
|
||||
* The window can be on more than one desktop, or none: then is considered on all of them.
|
||||
* @since 5.46
|
||||
*/
|
||||
void plasmaVirtualDesktopEntered(const QString &id);
|
||||
|
||||
/**
|
||||
* This signal is emitted when the window left a virtual desktop.
|
||||
* If the window leaves all desktops, it can be considered on all.
|
||||
*
|
||||
* @since 5.46
|
||||
*/
|
||||
void plasmaVirtualDesktopLeft(const QString &id);
|
||||
|
||||
/**
|
||||
* This signal is emitted when the window has entered an activity.
|
||||
* The window can be on more than one activity, or none: then is considered on all of them.
|
||||
* @since 5.81
|
||||
*/
|
||||
void plasmaActivityEntered(const QString &id);
|
||||
|
||||
/**
|
||||
* This signal is emitted when the window left an activity.
|
||||
* If the window leaves all activities, it can be considered on all.
|
||||
*
|
||||
* @since 5.81
|
||||
*/
|
||||
void plasmaActivityLeft(const QString &id);
|
||||
|
||||
/**
|
||||
* This signal is emitted when either the D-BUS service name or
|
||||
* object path for the window's application menu changes.
|
||||
*
|
||||
* @since 5.69
|
||||
**/
|
||||
void applicationMenuChanged();
|
||||
|
||||
/**
|
||||
* This signal is emitted whenever the client geometry changes.
|
||||
* @see clientGeometry
|
||||
* @since 6.2
|
||||
**/
|
||||
void clientGeometryChanged();
|
||||
|
||||
private:
|
||||
friend class PlasmaWindowManagement;
|
||||
explicit PlasmaWindow(PlasmaWindowManagement *parent, org_kde_plasma_window *activation, quint32 internalId, const char *uuid);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @since 5.86
|
||||
*/
|
||||
class KWAYLANDCLIENT_EXPORT PlasmaActivation : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~PlasmaActivation() override;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Informs about which application this activation is representing
|
||||
*
|
||||
* The @p appId can be used to infer how to decorate this activation.
|
||||
*/
|
||||
void applicationId(const QString &appId);
|
||||
|
||||
/**
|
||||
* Notifies that the activation is done with.
|
||||
*
|
||||
* It might happen either because it's over or because it timed out.
|
||||
*/
|
||||
void finished();
|
||||
|
||||
private:
|
||||
friend class PlasmaActivationFeedback;
|
||||
explicit PlasmaActivation(PlasmaActivationFeedback *parent, org_kde_plasma_activation *activation);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @since 5.86
|
||||
*/
|
||||
class KWAYLANDCLIENT_EXPORT PlasmaActivationFeedback : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PlasmaActivationFeedback(QObject *parent = nullptr);
|
||||
~PlasmaActivationFeedback() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_plasma_activation_feedback.
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* Releases the org_kde_plasma_activation_feedback interface.
|
||||
* After the interface has been released the PlasmaActivationFeedback instance is no
|
||||
* longer valid and can be setup with another org_kde_plasma_activation_feedback interface.
|
||||
*
|
||||
* Right before the interface is released the signal interfaceAboutToBeReleased is emitted.
|
||||
* @see interfaceAboutToBeReleased
|
||||
**/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* Destroys the data held by this PlasmaActivationFeedback.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. Once the connection becomes invalid, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_plasma_activation_feedback interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* PlasmaActivationFeedback gets destroyed.
|
||||
*
|
||||
* Right before the data is destroyed, the signal interfaceAboutToBeDestroyed is emitted.
|
||||
*
|
||||
* @see release
|
||||
* @see interfaceAboutToBeDestroyed
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Setup this PlasmaActivationFeedback to manage the @p manager.
|
||||
* When using Registry::createPlasmaActivationFeedback there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_plasma_activation_feedback *manager);
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating a PlasmaActivationFeedback.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
|
||||
/**
|
||||
* @returns The event queue to use for creating a PlasmaActivationFeedback.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
operator org_kde_plasma_activation_feedback *();
|
||||
operator org_kde_plasma_activation_feedback *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* This signal is emitted right before the interface is released.
|
||||
**/
|
||||
void interfaceAboutToBeReleased();
|
||||
|
||||
/**
|
||||
* This signal is emitted right before the data is destroyed.
|
||||
**/
|
||||
void interfaceAboutToBeDestroyed();
|
||||
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the Compositor got created by
|
||||
* Registry::createPlasmaActivationFeedback
|
||||
**/
|
||||
void removed();
|
||||
|
||||
void activation(KWayland::Client::PlasmaActivation *activation);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWayland::Client::PlasmaWindow *)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "plasmawindowmodel.h"
|
||||
#include "plasmawindowmanagement.h"
|
||||
|
||||
#include <QMetaEnum>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN PlasmaWindowModel::Private
|
||||
{
|
||||
public:
|
||||
Private(PlasmaWindowModel *q);
|
||||
QList<PlasmaWindow *> windows;
|
||||
PlasmaWindow *window = nullptr;
|
||||
|
||||
void addWindow(PlasmaWindow *window);
|
||||
void dataChanged(PlasmaWindow *window, int role);
|
||||
|
||||
private:
|
||||
PlasmaWindowModel *q;
|
||||
};
|
||||
|
||||
PlasmaWindowModel::Private::Private(PlasmaWindowModel *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void PlasmaWindowModel::Private::addWindow(PlasmaWindow *window)
|
||||
{
|
||||
if (windows.indexOf(window) != -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int count = windows.count();
|
||||
q->beginInsertRows(QModelIndex(), count, count);
|
||||
windows.append(window);
|
||||
q->endInsertRows();
|
||||
|
||||
auto removeWindow = [window, this] {
|
||||
const int row = windows.indexOf(window);
|
||||
if (row != -1) {
|
||||
q->beginRemoveRows(QModelIndex(), row, row);
|
||||
windows.removeAt(row);
|
||||
q->endRemoveRows();
|
||||
}
|
||||
};
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::unmapped, q, removeWindow);
|
||||
QObject::connect(window, &QObject::destroyed, q, removeWindow);
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::titleChanged, q, [window, this] {
|
||||
this->dataChanged(window, Qt::DisplayRole);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::iconChanged, q, [window, this] {
|
||||
this->dataChanged(window, Qt::DecorationRole);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::appIdChanged, q, [window, this] {
|
||||
this->dataChanged(window, PlasmaWindowModel::AppId);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::activeChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsActive);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::fullscreenableChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsFullscreenable);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::fullscreenChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsFullscreen);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::maximizeableChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsMaximizable);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::maximizedChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsMaximized);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::minimizeableChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsMinimizable);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::minimizedChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsMinimized);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::keepAboveChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsKeepAbove);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::keepBelowChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsKeepBelow);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::onAllDesktopsChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsOnAllDesktops);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::demandsAttentionChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsDemandingAttention);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::skipTaskbarChanged, q, [window, this] {
|
||||
this->dataChanged(window, SkipTaskbar);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::skipSwitcherChanged, q, [window, this] {
|
||||
this->dataChanged(window, SkipSwitcher);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::shadeableChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsShadeable);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::shadedChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsShaded);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::movableChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsMovable);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::resizableChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsResizable);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::virtualDesktopChangeableChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsVirtualDesktopChangeable);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::closeableChanged, q, [window, this] {
|
||||
this->dataChanged(window, IsCloseable);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::geometryChanged, q, [window, this] {
|
||||
this->dataChanged(window, Geometry);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::plasmaVirtualDesktopEntered, q, [window, this] {
|
||||
this->dataChanged(window, VirtualDesktops);
|
||||
});
|
||||
|
||||
QObject::connect(window, &PlasmaWindow::plasmaVirtualDesktopLeft, q, [window, this] {
|
||||
this->dataChanged(window, VirtualDesktops);
|
||||
});
|
||||
}
|
||||
|
||||
void PlasmaWindowModel::Private::dataChanged(PlasmaWindow *window, int role)
|
||||
{
|
||||
QModelIndex idx = q->index(windows.indexOf(window));
|
||||
Q_EMIT q->dataChanged(idx, idx, QList<int>() << role);
|
||||
}
|
||||
|
||||
PlasmaWindowModel::PlasmaWindowModel(PlasmaWindowManagement *parent)
|
||||
: QAbstractListModel(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
connect(parent, &PlasmaWindowManagement::interfaceAboutToBeReleased, this, [this] {
|
||||
beginResetModel();
|
||||
d->windows.clear();
|
||||
endResetModel();
|
||||
});
|
||||
|
||||
connect(parent, &PlasmaWindowManagement::windowCreated, this, [this](PlasmaWindow *window) {
|
||||
d->addWindow(window);
|
||||
});
|
||||
|
||||
for (auto it = parent->windows().constBegin(); it != parent->windows().constEnd(); ++it) {
|
||||
d->addWindow(*it);
|
||||
}
|
||||
}
|
||||
|
||||
PlasmaWindowModel::~PlasmaWindowModel()
|
||||
{
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> PlasmaWindowModel::roleNames() const
|
||||
{
|
||||
QHash<int, QByteArray> roles;
|
||||
|
||||
roles.insert(Qt::DisplayRole, "display");
|
||||
roles.insert(Qt::DecorationRole, "decoration");
|
||||
|
||||
QMetaEnum e = metaObject()->enumerator(metaObject()->indexOfEnumerator("AdditionalRoles"));
|
||||
|
||||
for (int i = 0; i < e.keyCount(); ++i) {
|
||||
roles.insert(e.value(i), e.key(i));
|
||||
}
|
||||
|
||||
return roles;
|
||||
}
|
||||
|
||||
QVariant PlasmaWindowModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid() || index.row() >= d->windows.count()) {
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
const PlasmaWindow *window = d->windows.at(index.row());
|
||||
|
||||
if (role == Qt::DisplayRole) {
|
||||
return window->title();
|
||||
} else if (role == Qt::DecorationRole) {
|
||||
return window->icon();
|
||||
} else if (role == AppId) {
|
||||
return window->appId();
|
||||
} else if (role == Pid) {
|
||||
return window->pid();
|
||||
} else if (role == IsActive) {
|
||||
return window->isActive();
|
||||
} else if (role == IsFullscreenable) {
|
||||
return window->isFullscreenable();
|
||||
} else if (role == IsFullscreen) {
|
||||
return window->isFullscreen();
|
||||
} else if (role == IsMaximizable) {
|
||||
return window->isMaximizeable();
|
||||
} else if (role == IsMaximized) {
|
||||
return window->isMaximized();
|
||||
} else if (role == IsMinimizable) {
|
||||
return window->isMinimizeable();
|
||||
} else if (role == IsMinimized) {
|
||||
return window->isMinimized();
|
||||
} else if (role == IsKeepAbove) {
|
||||
return window->isKeepAbove();
|
||||
} else if (role == IsKeepBelow) {
|
||||
return window->isKeepBelow();
|
||||
} else if (role == IsOnAllDesktops) {
|
||||
return window->isOnAllDesktops();
|
||||
} else if (role == IsDemandingAttention) {
|
||||
return window->isDemandingAttention();
|
||||
} else if (role == SkipTaskbar) {
|
||||
return window->skipTaskbar();
|
||||
} else if (role == SkipSwitcher) {
|
||||
return window->skipSwitcher();
|
||||
} else if (role == IsShadeable) {
|
||||
return window->isShadeable();
|
||||
} else if (role == IsShaded) {
|
||||
return window->isShaded();
|
||||
} else if (role == IsMovable) {
|
||||
return window->isMovable();
|
||||
} else if (role == IsResizable) {
|
||||
return window->isResizable();
|
||||
} else if (role == IsVirtualDesktopChangeable) {
|
||||
return window->isVirtualDesktopChangeable();
|
||||
} else if (role == IsCloseable) {
|
||||
return window->isCloseable();
|
||||
} else if (role == Geometry) {
|
||||
return window->geometry();
|
||||
} else if (role == VirtualDesktops) {
|
||||
return window->plasmaVirtualDesktops();
|
||||
} else if (role == Uuid) {
|
||||
return window->uuid();
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
QMap<int, QVariant> PlasmaWindowModel::itemData(const QModelIndex &index) const
|
||||
{
|
||||
QMap<int, QVariant> ret = QAbstractItemModel::itemData(index);
|
||||
for (int role = AppId; role < LastRole; ++role) {
|
||||
ret.insert(role, data(index, role));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int PlasmaWindowModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : d->windows.count();
|
||||
}
|
||||
|
||||
QModelIndex PlasmaWindowModel::index(int row, int column, const QModelIndex &parent) const
|
||||
{
|
||||
return hasIndex(row, column, parent) ? createIndex(row, column, d->windows.at(row)) : QModelIndex();
|
||||
}
|
||||
|
||||
Q_INVOKABLE void PlasmaWindowModel::requestActivate(int row)
|
||||
{
|
||||
if (row >= 0 && row < d->windows.count()) {
|
||||
d->windows.at(row)->requestActivate();
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void PlasmaWindowModel::requestClose(int row)
|
||||
{
|
||||
if (row >= 0 && row < d->windows.count()) {
|
||||
d->windows.at(row)->requestClose();
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void PlasmaWindowModel::requestMove(int row)
|
||||
{
|
||||
if (row >= 0 && row < d->windows.count()) {
|
||||
d->windows.at(row)->requestMove();
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void PlasmaWindowModel::requestResize(int row)
|
||||
{
|
||||
if (row >= 0 && row < d->windows.count()) {
|
||||
d->windows.at(row)->requestResize();
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void PlasmaWindowModel::requestEnterVirtualDesktop(int row, const QString &id)
|
||||
{
|
||||
if (row >= 0 && row < d->windows.count()) {
|
||||
d->windows.at(row)->requestEnterVirtualDesktop(id);
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void PlasmaWindowModel::requestToggleKeepAbove(int row)
|
||||
{
|
||||
if (row >= 0 && row < d->windows.count()) {
|
||||
d->windows.at(row)->requestToggleKeepAbove();
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void PlasmaWindowModel::requestToggleKeepBelow(int row)
|
||||
{
|
||||
if (row >= 0 && row < d->windows.count()) {
|
||||
d->windows.at(row)->requestToggleKeepBelow();
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void PlasmaWindowModel::requestToggleMinimized(int row)
|
||||
{
|
||||
if (row >= 0 && row < d->windows.count()) {
|
||||
d->windows.at(row)->requestToggleMinimized();
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void PlasmaWindowModel::requestToggleMaximized(int row)
|
||||
{
|
||||
if (row >= 0 && row < d->windows.count()) {
|
||||
d->windows.at(row)->requestToggleMaximized();
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void PlasmaWindowModel::requestToggleFullscreen(int row)
|
||||
{
|
||||
if (row >= 0 && row < d->windows.count()) {
|
||||
d->windows.at(row)->requestToggleFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void PlasmaWindowModel::setMinimizedGeometry(int row, Surface *panel, const QRect &geom)
|
||||
{
|
||||
if (row >= 0 && row < d->windows.count()) {
|
||||
d->windows.at(row)->setMinimizedGeometry(panel, geom);
|
||||
}
|
||||
}
|
||||
|
||||
Q_INVOKABLE void PlasmaWindowModel::requestToggleShaded(int row)
|
||||
{
|
||||
if (row >= 0 && row < d->windows.count()) {
|
||||
d->windows.at(row)->requestToggleShaded();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_plasmawindowmodel.cpp"
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Eike Hein <hein.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_PLASMAWINDOWMODEL_H
|
||||
#define WAYLAND_PLASMAWINDOWMODEL_H
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class PlasmaWindowManagement;
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
* @short Exposes the window list and window state as a Qt item model.
|
||||
*
|
||||
* This class is a QAbstractListModel implementation that exposes information
|
||||
* from a PlasmaWindowManagement instance passed as parent and enables convenient
|
||||
* calls to PlasmaWindow methods through a model row index.
|
||||
*
|
||||
* The model is destroyed when the PlasmaWindowManagement parent is.
|
||||
*
|
||||
* The model resets when the PlasmaWindowManagement parent signals that its
|
||||
* interface is about to be destroyed.
|
||||
*
|
||||
* To use this class you can create an instance yourself, or preferably use the
|
||||
* convenience method in PlasmaWindowManagement:
|
||||
* @code
|
||||
* PlasmaWindowModel *model = wm->createWindowModel();
|
||||
* @endcode
|
||||
*
|
||||
* @see PlasmaWindowManagement
|
||||
* @see PlasmaWindow
|
||||
**/
|
||||
|
||||
class KWAYLANDCLIENT_EXPORT PlasmaWindowModel : public QAbstractListModel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum AdditionalRoles {
|
||||
AppId = Qt::UserRole + 1,
|
||||
IsActive,
|
||||
IsFullscreenable,
|
||||
IsFullscreen,
|
||||
IsMaximizable,
|
||||
IsMaximized,
|
||||
IsMinimizable,
|
||||
IsMinimized,
|
||||
IsKeepAbove,
|
||||
IsKeepBelow,
|
||||
IsOnAllDesktops,
|
||||
IsDemandingAttention,
|
||||
SkipTaskbar,
|
||||
/**
|
||||
* @since 5.22
|
||||
*/
|
||||
IsShadeable,
|
||||
/**
|
||||
* @since 5.22
|
||||
*/
|
||||
IsShaded,
|
||||
/**
|
||||
* @since 5.22
|
||||
*/
|
||||
IsMovable,
|
||||
/**
|
||||
* @since 5.22
|
||||
*/
|
||||
IsResizable,
|
||||
/**
|
||||
* @since 5.22
|
||||
*/
|
||||
IsVirtualDesktopChangeable,
|
||||
/**
|
||||
* @since 5.22
|
||||
*/
|
||||
IsCloseable,
|
||||
/**
|
||||
* @since 5.25
|
||||
*/
|
||||
Geometry,
|
||||
/**
|
||||
* @since 5.35
|
||||
*/
|
||||
Pid,
|
||||
/**
|
||||
* @since 5.47
|
||||
*/
|
||||
SkipSwitcher,
|
||||
/**
|
||||
* @since 5.53
|
||||
*/
|
||||
VirtualDesktops,
|
||||
/**
|
||||
* @since 5.73
|
||||
*/
|
||||
Uuid,
|
||||
LastRole,
|
||||
};
|
||||
Q_ENUM(AdditionalRoles)
|
||||
|
||||
explicit PlasmaWindowModel(PlasmaWindowManagement *parent);
|
||||
~PlasmaWindowModel() override;
|
||||
|
||||
QHash<int, QByteArray> roleNames() const override;
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
/**
|
||||
* Returns an index with internalPointer() pointing to a PlasmaWindow instance.
|
||||
**/
|
||||
QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
QMap<int, QVariant> itemData(const QModelIndex &index) const override;
|
||||
|
||||
/**
|
||||
* Request the window at this model row index be activated.
|
||||
**/
|
||||
Q_INVOKABLE void requestActivate(int row);
|
||||
|
||||
/**
|
||||
* Request the window at this model row index be closed.
|
||||
**/
|
||||
Q_INVOKABLE void requestClose(int row);
|
||||
|
||||
/**
|
||||
* Request an interactive move for the window at this model row index.
|
||||
* @since 5.22
|
||||
**/
|
||||
Q_INVOKABLE void requestMove(int row);
|
||||
|
||||
/**
|
||||
* Request an interactive resize for the window at this model row index.
|
||||
* @since 5.22
|
||||
**/
|
||||
Q_INVOKABLE void requestResize(int row);
|
||||
|
||||
/**
|
||||
* Request the window at the model index @p row to be moved to the virtual desktop @p id.
|
||||
*
|
||||
* @since 5.90
|
||||
**/
|
||||
Q_INVOKABLE void requestEnterVirtualDesktop(int row, const QString &id);
|
||||
|
||||
/**
|
||||
* Requests the window at this model row index have its keep above state toggled.
|
||||
* @since 5.35
|
||||
*/
|
||||
Q_INVOKABLE void requestToggleKeepAbove(int row);
|
||||
|
||||
/**
|
||||
* Requests the window at this model row index have its keep above state toggled.
|
||||
* @since 5.35
|
||||
*/
|
||||
Q_INVOKABLE void requestToggleKeepBelow(int row);
|
||||
|
||||
/**
|
||||
* Requests the window at this model row index have its minimized state toggled.
|
||||
*/
|
||||
Q_INVOKABLE void requestToggleMinimized(int row);
|
||||
|
||||
/**
|
||||
* Requests the window at this model row index have its maximized state toggled.
|
||||
*/
|
||||
Q_INVOKABLE void requestToggleMaximized(int row);
|
||||
|
||||
/**
|
||||
* Requests the window at this model row index have its fullscreen state toggled.
|
||||
* @since 6.0
|
||||
*/
|
||||
Q_INVOKABLE void requestToggleFullscreen(int row);
|
||||
|
||||
/**
|
||||
* Sets the geometry of the taskbar entry for the window at the model row
|
||||
* relative to a panel in particular. QRectF, intended for use from QML
|
||||
* @since 5.5
|
||||
*/
|
||||
Q_INVOKABLE void setMinimizedGeometry(int row, Surface *panel, const QRect &geom);
|
||||
|
||||
/**
|
||||
* Requests the window at this model row index have its shaded state toggled.
|
||||
* @since 5.22
|
||||
*/
|
||||
Q_INVOKABLE void requestToggleShaded(int row);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "pointer.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Qt
|
||||
#include <QPointF>
|
||||
#include <QPointer>
|
||||
// wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
static Pointer::Axis wlAxisToPointerAxis(uint32_t axis)
|
||||
{
|
||||
switch (axis) {
|
||||
case WL_POINTER_AXIS_VERTICAL_SCROLL:
|
||||
return Pointer::Axis::Vertical;
|
||||
case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
|
||||
return Pointer::Axis::Horizontal;
|
||||
}
|
||||
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN Pointer::Private
|
||||
{
|
||||
public:
|
||||
Private(Pointer *q);
|
||||
void setup(wl_pointer *p);
|
||||
|
||||
WaylandPointer<wl_pointer, wl_pointer_release> pointer;
|
||||
QPointer<Surface> enteredSurface;
|
||||
quint32 enteredSerial = 0;
|
||||
|
||||
private:
|
||||
void enter(uint32_t serial, wl_surface *surface, const QPointF &relativeToSurface);
|
||||
void leave(uint32_t serial);
|
||||
static void enterCallback(void *data, wl_pointer *pointer, uint32_t serial, wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy);
|
||||
static void leaveCallback(void *data, wl_pointer *pointer, uint32_t serial, wl_surface *surface);
|
||||
static void motionCallback(void *data, wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy);
|
||||
static void buttonCallback(void *data, wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state);
|
||||
static void axisCallback(void *data, wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value);
|
||||
static void frameCallback(void *data, wl_pointer *pointer);
|
||||
static void axisSourceCallback(void *data, wl_pointer *pointer, uint32_t axis_source);
|
||||
static void axisStopCallback(void *data, wl_pointer *pointer, uint32_t time, uint32_t axis);
|
||||
static void axisDiscreteCallback(void *data, wl_pointer *pointer, uint32_t axis, int32_t discrete);
|
||||
|
||||
Pointer *q;
|
||||
static const wl_pointer_listener s_listener;
|
||||
};
|
||||
|
||||
Pointer::Private::Private(Pointer *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void Pointer::Private::setup(wl_pointer *p)
|
||||
{
|
||||
Q_ASSERT(p);
|
||||
Q_ASSERT(!pointer);
|
||||
pointer.setup(p);
|
||||
wl_pointer_add_listener(pointer, &s_listener, this);
|
||||
}
|
||||
|
||||
const wl_pointer_listener Pointer::Private::s_listener =
|
||||
{enterCallback, leaveCallback, motionCallback, buttonCallback, axisCallback, frameCallback, axisSourceCallback, axisStopCallback, axisDiscreteCallback};
|
||||
|
||||
Pointer::Pointer(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
Pointer::~Pointer()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void Pointer::release()
|
||||
{
|
||||
d->pointer.release();
|
||||
}
|
||||
|
||||
void Pointer::destroy()
|
||||
{
|
||||
d->pointer.destroy();
|
||||
}
|
||||
|
||||
void Pointer::setup(wl_pointer *pointer)
|
||||
{
|
||||
d->setup(pointer);
|
||||
}
|
||||
|
||||
void Pointer::Private::enterCallback(void *data, wl_pointer *pointer, uint32_t serial, wl_surface *surface, wl_fixed_t sx, wl_fixed_t sy)
|
||||
{
|
||||
auto p = reinterpret_cast<Pointer::Private *>(data);
|
||||
Q_ASSERT(p->pointer == pointer);
|
||||
p->enter(serial, surface, QPointF(wl_fixed_to_double(sx), wl_fixed_to_double(sy)));
|
||||
}
|
||||
|
||||
void Pointer::Private::enter(uint32_t serial, wl_surface *surface, const QPointF &relativeToSurface)
|
||||
{
|
||||
enteredSurface = QPointer<Surface>(Surface::get(surface));
|
||||
enteredSerial = serial;
|
||||
Q_EMIT q->entered(serial, relativeToSurface);
|
||||
}
|
||||
|
||||
void Pointer::Private::leaveCallback(void *data, wl_pointer *pointer, uint32_t serial, wl_surface *surface)
|
||||
{
|
||||
auto p = reinterpret_cast<Pointer::Private *>(data);
|
||||
Q_ASSERT(p->pointer == pointer);
|
||||
Q_UNUSED(surface)
|
||||
p->leave(serial);
|
||||
}
|
||||
|
||||
void Pointer::Private::leave(uint32_t serial)
|
||||
{
|
||||
enteredSurface.clear();
|
||||
Q_EMIT q->left(serial);
|
||||
}
|
||||
|
||||
void Pointer::Private::motionCallback(void *data, wl_pointer *pointer, uint32_t time, wl_fixed_t sx, wl_fixed_t sy)
|
||||
{
|
||||
auto p = reinterpret_cast<Pointer::Private *>(data);
|
||||
Q_ASSERT(p->pointer == pointer);
|
||||
Q_EMIT p->q->motion(QPointF(wl_fixed_to_double(sx), wl_fixed_to_double(sy)), time);
|
||||
}
|
||||
|
||||
void Pointer::Private::buttonCallback(void *data, wl_pointer *pointer, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
|
||||
{
|
||||
auto p = reinterpret_cast<Pointer::Private *>(data);
|
||||
Q_ASSERT(p->pointer == pointer);
|
||||
auto toState = [state] {
|
||||
if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
|
||||
return ButtonState::Released;
|
||||
} else {
|
||||
return ButtonState::Pressed;
|
||||
}
|
||||
};
|
||||
Q_EMIT p->q->buttonStateChanged(serial, time, button, toState());
|
||||
}
|
||||
|
||||
void Pointer::Private::axisCallback(void *data, wl_pointer *pointer, uint32_t time, uint32_t axis, wl_fixed_t value)
|
||||
{
|
||||
auto p = reinterpret_cast<Pointer::Private *>(data);
|
||||
Q_ASSERT(p->pointer == pointer);
|
||||
Q_EMIT p->q->axisChanged(time, wlAxisToPointerAxis(axis), wl_fixed_to_double(value));
|
||||
}
|
||||
|
||||
void Pointer::Private::frameCallback(void *data, wl_pointer *pointer)
|
||||
{
|
||||
auto p = reinterpret_cast<Pointer::Private *>(data);
|
||||
Q_ASSERT(p->pointer == pointer);
|
||||
Q_EMIT p->q->frame();
|
||||
}
|
||||
|
||||
void Pointer::Private::axisSourceCallback(void *data, wl_pointer *pointer, uint32_t axis_source)
|
||||
{
|
||||
auto p = reinterpret_cast<Pointer::Private *>(data);
|
||||
Q_ASSERT(p->pointer == pointer);
|
||||
AxisSource source;
|
||||
switch (axis_source) {
|
||||
case WL_POINTER_AXIS_SOURCE_WHEEL:
|
||||
source = AxisSource::Wheel;
|
||||
break;
|
||||
case WL_POINTER_AXIS_SOURCE_FINGER:
|
||||
source = AxisSource::Finger;
|
||||
break;
|
||||
case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
|
||||
source = AxisSource::Continuous;
|
||||
break;
|
||||
case WL_POINTER_AXIS_SOURCE_WHEEL_TILT:
|
||||
source = AxisSource::WheelTilt;
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
Q_EMIT p->q->axisSourceChanged(source);
|
||||
}
|
||||
|
||||
void Pointer::Private::axisStopCallback(void *data, wl_pointer *pointer, uint32_t time, uint32_t axis)
|
||||
{
|
||||
auto p = reinterpret_cast<Pointer::Private *>(data);
|
||||
Q_ASSERT(p->pointer == pointer);
|
||||
Q_EMIT p->q->axisStopped(time, wlAxisToPointerAxis(axis));
|
||||
}
|
||||
|
||||
void Pointer::Private::axisDiscreteCallback(void *data, wl_pointer *pointer, uint32_t axis, int32_t discrete)
|
||||
{
|
||||
auto p = reinterpret_cast<Pointer::Private *>(data);
|
||||
Q_ASSERT(p->pointer == pointer);
|
||||
Q_EMIT p->q->axisDiscreteChanged(wlAxisToPointerAxis(axis), discrete);
|
||||
}
|
||||
|
||||
void Pointer::setCursor(Surface *surface, const QPoint &hotspot)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
wl_surface *s = nullptr;
|
||||
if (surface) {
|
||||
s = *surface;
|
||||
}
|
||||
wl_pointer_set_cursor(d->pointer, d->enteredSerial, s, hotspot.x(), hotspot.y());
|
||||
}
|
||||
|
||||
void Pointer::hideCursor()
|
||||
{
|
||||
setCursor(nullptr);
|
||||
}
|
||||
|
||||
Surface *Pointer::enteredSurface()
|
||||
{
|
||||
return d->enteredSurface.data();
|
||||
}
|
||||
|
||||
Surface *Pointer::enteredSurface() const
|
||||
{
|
||||
return d->enteredSurface.data();
|
||||
}
|
||||
|
||||
bool Pointer::isValid() const
|
||||
{
|
||||
return d->pointer.isValid();
|
||||
}
|
||||
|
||||
Pointer::operator wl_pointer *() const
|
||||
{
|
||||
return d->pointer;
|
||||
}
|
||||
|
||||
Pointer::operator wl_pointer *()
|
||||
{
|
||||
return d->pointer;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_pointer.cpp"
|
||||
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_POINTER_H
|
||||
#define WAYLAND_POINTER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QPoint>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_pointer;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the wl_pointer interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the wl_pointer interface.
|
||||
*
|
||||
* To create an instance use Seat::createPointer.
|
||||
*
|
||||
* @see Seat
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Pointer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class ButtonState {
|
||||
Released,
|
||||
Pressed,
|
||||
};
|
||||
enum class Axis {
|
||||
Vertical,
|
||||
Horizontal,
|
||||
};
|
||||
enum class AxisSource {
|
||||
Wheel,
|
||||
Finger,
|
||||
Continuous,
|
||||
WheelTilt,
|
||||
};
|
||||
explicit Pointer(QObject *parent = nullptr);
|
||||
~Pointer() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a wl_pointer.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this Pointer to manage the @p pointer.
|
||||
* When using Seat::createPointer there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_pointer *pointer);
|
||||
/**
|
||||
* Releases the wl_pointer interface.
|
||||
* After the interface has been released the Pointer instance is no
|
||||
* longer valid and can be setup with another wl_pointer interface.
|
||||
*
|
||||
* This method is automatically invoked when the Seat which created this
|
||||
* Pointer gets released.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this Pointer.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_pointer interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Seat which created this
|
||||
* Pointer gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the cursor image for this Pointer.
|
||||
*
|
||||
* This has only an effect if a Surface of the same client is focused.
|
||||
*
|
||||
* @param surface The Surface pointing to the image data, if @c null the cursor will be hidden
|
||||
* @param hotspot The hotspot of the cursor image
|
||||
* @see hideCursor
|
||||
* @since 5.3
|
||||
**/
|
||||
void setCursor(Surface *surface, const QPoint &hotspot = QPoint());
|
||||
/**
|
||||
* Hides the cursor. Same as calling setCursor with @c null for surface.
|
||||
* @see setCursor
|
||||
* @since 5.3
|
||||
**/
|
||||
void hideCursor();
|
||||
|
||||
/**
|
||||
* @returns The Surface the Pointer is on, may be @c null.
|
||||
**/
|
||||
Surface *enteredSurface() const;
|
||||
/**
|
||||
* @overload
|
||||
**/
|
||||
Surface *enteredSurface();
|
||||
|
||||
operator wl_pointer *();
|
||||
operator wl_pointer *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Notification that this seat's pointer is focused on a certain surface.
|
||||
*
|
||||
* When an seat's focus enters a surface, the pointer image is undefined
|
||||
* and a client should respond to this event by setting an appropriate pointer
|
||||
* image with the set_cursor request.
|
||||
*
|
||||
* @param serial The serial for this enter
|
||||
* @param relativeToSurface Coordinates relative to the upper-left corner of the Surface.
|
||||
**/
|
||||
void entered(quint32 serial, const QPointF &relativeToSurface);
|
||||
/**
|
||||
* Notification that this seat's pointer is no longer focused on a certain surface.
|
||||
*
|
||||
* The leave notification is sent before the enter notification for the new focus.
|
||||
*
|
||||
* @param serial The serial of this leave event
|
||||
**/
|
||||
void left(quint32 serial);
|
||||
/**
|
||||
* Notification of pointer location change.
|
||||
*
|
||||
* @param relativeToSurface Coordinates relative to the upper-left corner of the entered Surface.
|
||||
* @param time timestamp with millisecond granularity
|
||||
**/
|
||||
void motion(const QPointF &relativeToSurface, quint32 time);
|
||||
/**
|
||||
* Mouse button click and release notifications.
|
||||
*
|
||||
* The location of the click is given by the last motion or enter event.
|
||||
*
|
||||
* @param serial The serial of this button state change
|
||||
* @param time timestamp with millisecond granularity, with an undefined base.
|
||||
* @param button The button which got changed
|
||||
* @param state @c Released or @c Pressed
|
||||
**/
|
||||
void buttonStateChanged(quint32 serial, quint32 time, quint32 button, KWayland::Client::Pointer::ButtonState state);
|
||||
/**
|
||||
* Scroll and other axis notifications.
|
||||
*
|
||||
* @param time timestamp with millisecond granularity
|
||||
* @param axis @c Vertical or @c Horizontal
|
||||
* @param delta
|
||||
**/
|
||||
void axisChanged(quint32 time, KWayland::Client::Pointer::Axis axis, qreal delta);
|
||||
/**
|
||||
* Indicates the source of scroll and other axes.
|
||||
*
|
||||
* @since 5.59
|
||||
**/
|
||||
void axisSourceChanged(KWayland::Client::Pointer::AxisSource source);
|
||||
/**
|
||||
* Discrete step information for scroll and other axes.
|
||||
*
|
||||
* @since 5.59
|
||||
**/
|
||||
void axisDiscreteChanged(KWayland::Client::Pointer::Axis axis, qint32 discreteDelta);
|
||||
/**
|
||||
* Stop notification for scroll and other axes.
|
||||
*
|
||||
* @since 5.59
|
||||
**/
|
||||
void axisStopped(quint32 time, KWayland::Client::Pointer::Axis axis);
|
||||
|
||||
/**
|
||||
* Indicates the end of a set of events that logically belong together.
|
||||
* A client is expected to accumulate the data in all events within the
|
||||
* frame before proceeding.
|
||||
* @since 5.45
|
||||
**/
|
||||
void frame();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWayland::Client::Pointer::ButtonState)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::Pointer::Axis)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::Pointer::AxisSource)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,351 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "pointerconstraints.h"
|
||||
#include "event_queue.h"
|
||||
#include "pointer.h"
|
||||
#include "region.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <wayland-pointer-constraints-unstable-v1-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN PointerConstraints::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
void setup(zwp_pointer_constraints_v1 *arg);
|
||||
|
||||
WaylandPointer<zwp_pointer_constraints_v1, zwp_pointer_constraints_v1_destroy> pointerconstraints;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
PointerConstraints::PointerConstraints(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
void PointerConstraints::Private::setup(zwp_pointer_constraints_v1 *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!pointerconstraints);
|
||||
pointerconstraints.setup(arg);
|
||||
}
|
||||
|
||||
PointerConstraints::~PointerConstraints()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void PointerConstraints::setup(zwp_pointer_constraints_v1 *pointerconstraints)
|
||||
{
|
||||
d->setup(pointerconstraints);
|
||||
}
|
||||
|
||||
void PointerConstraints::release()
|
||||
{
|
||||
d->pointerconstraints.release();
|
||||
}
|
||||
|
||||
void PointerConstraints::destroy()
|
||||
{
|
||||
d->pointerconstraints.destroy();
|
||||
}
|
||||
|
||||
PointerConstraints::operator zwp_pointer_constraints_v1 *()
|
||||
{
|
||||
return d->pointerconstraints;
|
||||
}
|
||||
|
||||
PointerConstraints::operator zwp_pointer_constraints_v1 *() const
|
||||
{
|
||||
return d->pointerconstraints;
|
||||
}
|
||||
|
||||
bool PointerConstraints::isValid() const
|
||||
{
|
||||
return d->pointerconstraints.isValid();
|
||||
}
|
||||
|
||||
void PointerConstraints::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *PointerConstraints::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
LockedPointer *PointerConstraints::lockPointer(Surface *surface, Pointer *pointer, Region *region, LifeTime lifetime, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
auto p = new LockedPointer(parent);
|
||||
zwp_pointer_constraints_v1_lifetime lf;
|
||||
switch (lifetime) {
|
||||
case LifeTime::OneShot:
|
||||
lf = ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT;
|
||||
break;
|
||||
case LifeTime::Persistent:
|
||||
lf = ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT;
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
wl_region *wr = nullptr;
|
||||
if (region) {
|
||||
wr = *region;
|
||||
}
|
||||
auto w = zwp_pointer_constraints_v1_lock_pointer(d->pointerconstraints, *surface, *pointer, wr, lf);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
p->setup(w);
|
||||
return p;
|
||||
}
|
||||
|
||||
ConfinedPointer *PointerConstraints::confinePointer(Surface *surface, Pointer *pointer, Region *region, LifeTime lifetime, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
auto p = new ConfinedPointer(parent);
|
||||
zwp_pointer_constraints_v1_lifetime lf;
|
||||
switch (lifetime) {
|
||||
case LifeTime::OneShot:
|
||||
lf = ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_ONESHOT;
|
||||
break;
|
||||
case LifeTime::Persistent:
|
||||
lf = ZWP_POINTER_CONSTRAINTS_V1_LIFETIME_PERSISTENT;
|
||||
break;
|
||||
default:
|
||||
Q_UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
wl_region *wr = nullptr;
|
||||
if (region) {
|
||||
wr = *region;
|
||||
}
|
||||
auto w = zwp_pointer_constraints_v1_confine_pointer(d->pointerconstraints, *surface, *pointer, wr, lf);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
p->setup(w);
|
||||
return p;
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN LockedPointer::Private
|
||||
{
|
||||
public:
|
||||
Private(LockedPointer *q);
|
||||
|
||||
void setup(zwp_locked_pointer_v1 *arg);
|
||||
|
||||
WaylandPointer<zwp_locked_pointer_v1, zwp_locked_pointer_v1_destroy> lockedpointer;
|
||||
|
||||
private:
|
||||
LockedPointer *q;
|
||||
|
||||
private:
|
||||
static void lockedCallback(void *data, zwp_locked_pointer_v1 *zwp_locked_pointer_v1);
|
||||
static void unlockedCallback(void *data, zwp_locked_pointer_v1 *zwp_locked_pointer_v1);
|
||||
|
||||
static const zwp_locked_pointer_v1_listener s_listener;
|
||||
};
|
||||
|
||||
const zwp_locked_pointer_v1_listener LockedPointer::Private::s_listener = {lockedCallback, unlockedCallback};
|
||||
|
||||
void LockedPointer::Private::lockedCallback(void *data, zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
|
||||
{
|
||||
auto p = reinterpret_cast<LockedPointer::Private *>(data);
|
||||
Q_ASSERT(p->lockedpointer == zwp_locked_pointer_v1);
|
||||
Q_EMIT p->q->locked();
|
||||
}
|
||||
|
||||
void LockedPointer::Private::unlockedCallback(void *data, zwp_locked_pointer_v1 *zwp_locked_pointer_v1)
|
||||
{
|
||||
auto p = reinterpret_cast<LockedPointer::Private *>(data);
|
||||
Q_ASSERT(p->lockedpointer == zwp_locked_pointer_v1);
|
||||
Q_EMIT p->q->unlocked();
|
||||
}
|
||||
|
||||
LockedPointer::Private::Private(LockedPointer *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
LockedPointer::LockedPointer(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
void LockedPointer::Private::setup(zwp_locked_pointer_v1 *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!lockedpointer);
|
||||
lockedpointer.setup(arg);
|
||||
zwp_locked_pointer_v1_add_listener(lockedpointer, &s_listener, this);
|
||||
}
|
||||
|
||||
LockedPointer::~LockedPointer()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void LockedPointer::setup(zwp_locked_pointer_v1 *lockedpointer)
|
||||
{
|
||||
d->setup(lockedpointer);
|
||||
}
|
||||
|
||||
void LockedPointer::release()
|
||||
{
|
||||
d->lockedpointer.release();
|
||||
}
|
||||
|
||||
void LockedPointer::destroy()
|
||||
{
|
||||
d->lockedpointer.destroy();
|
||||
}
|
||||
|
||||
LockedPointer::operator zwp_locked_pointer_v1 *()
|
||||
{
|
||||
return d->lockedpointer;
|
||||
}
|
||||
|
||||
LockedPointer::operator zwp_locked_pointer_v1 *() const
|
||||
{
|
||||
return d->lockedpointer;
|
||||
}
|
||||
|
||||
bool LockedPointer::isValid() const
|
||||
{
|
||||
return d->lockedpointer.isValid();
|
||||
}
|
||||
|
||||
void LockedPointer::setCursorPositionHint(const QPointF &surfaceLocal)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
zwp_locked_pointer_v1_set_cursor_position_hint(d->lockedpointer, wl_fixed_from_double(surfaceLocal.x()), wl_fixed_from_double(surfaceLocal.y()));
|
||||
}
|
||||
|
||||
void LockedPointer::setRegion(Region *region)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
wl_region *wr = nullptr;
|
||||
if (region) {
|
||||
wr = *region;
|
||||
}
|
||||
zwp_locked_pointer_v1_set_region(d->lockedpointer, wr);
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN ConfinedPointer::Private
|
||||
{
|
||||
public:
|
||||
Private(ConfinedPointer *q);
|
||||
|
||||
void setup(zwp_confined_pointer_v1 *arg);
|
||||
|
||||
WaylandPointer<zwp_confined_pointer_v1, zwp_confined_pointer_v1_destroy> confinedpointer;
|
||||
|
||||
private:
|
||||
ConfinedPointer *q;
|
||||
|
||||
private:
|
||||
static void confinedCallback(void *data, zwp_confined_pointer_v1 *zwp_confined_pointer_v1);
|
||||
static void unconfinedCallback(void *data, zwp_confined_pointer_v1 *zwp_confined_pointer_v1);
|
||||
|
||||
static const zwp_confined_pointer_v1_listener s_listener;
|
||||
};
|
||||
|
||||
const zwp_confined_pointer_v1_listener ConfinedPointer::Private::s_listener = {confinedCallback, unconfinedCallback};
|
||||
|
||||
void ConfinedPointer::Private::confinedCallback(void *data, zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
|
||||
{
|
||||
auto p = reinterpret_cast<ConfinedPointer::Private *>(data);
|
||||
Q_ASSERT(p->confinedpointer == zwp_confined_pointer_v1);
|
||||
Q_EMIT p->q->confined();
|
||||
}
|
||||
|
||||
void ConfinedPointer::Private::unconfinedCallback(void *data, zwp_confined_pointer_v1 *zwp_confined_pointer_v1)
|
||||
{
|
||||
auto p = reinterpret_cast<ConfinedPointer::Private *>(data);
|
||||
Q_ASSERT(p->confinedpointer == zwp_confined_pointer_v1);
|
||||
Q_EMIT p->q->unconfined();
|
||||
}
|
||||
|
||||
ConfinedPointer::Private::Private(ConfinedPointer *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
ConfinedPointer::ConfinedPointer(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
void ConfinedPointer::Private::setup(zwp_confined_pointer_v1 *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!confinedpointer);
|
||||
confinedpointer.setup(arg);
|
||||
zwp_confined_pointer_v1_add_listener(confinedpointer, &s_listener, this);
|
||||
}
|
||||
|
||||
ConfinedPointer::~ConfinedPointer()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void ConfinedPointer::setup(zwp_confined_pointer_v1 *confinedpointer)
|
||||
{
|
||||
d->setup(confinedpointer);
|
||||
}
|
||||
|
||||
void ConfinedPointer::release()
|
||||
{
|
||||
d->confinedpointer.release();
|
||||
}
|
||||
|
||||
void ConfinedPointer::destroy()
|
||||
{
|
||||
d->confinedpointer.destroy();
|
||||
}
|
||||
|
||||
ConfinedPointer::operator zwp_confined_pointer_v1 *()
|
||||
{
|
||||
return d->confinedpointer;
|
||||
}
|
||||
|
||||
ConfinedPointer::operator zwp_confined_pointer_v1 *() const
|
||||
{
|
||||
return d->confinedpointer;
|
||||
}
|
||||
|
||||
bool ConfinedPointer::isValid() const
|
||||
{
|
||||
return d->confinedpointer.isValid();
|
||||
}
|
||||
|
||||
void ConfinedPointer::setRegion(Region *region)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
wl_region *wr = nullptr;
|
||||
if (region) {
|
||||
wr = *region;
|
||||
}
|
||||
zwp_confined_pointer_v1_set_region(d->confinedpointer, wr);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_pointerconstraints.cpp"
|
||||
@@ -0,0 +1,455 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_POINTERCONSTRAINTS_H
|
||||
#define KWAYLAND_CLIENT_POINTERCONSTRAINTS_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct zwp_pointer_constraints_v1;
|
||||
struct zwp_locked_pointer_v1;
|
||||
struct zwp_confined_pointer_v1;
|
||||
|
||||
class QPointF;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class LockedPointer;
|
||||
class Surface;
|
||||
class Region;
|
||||
class ConfinedPointer;
|
||||
class Pointer;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the zwp_pointer_constraints_v1 interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the zwp_pointer_constraints_v1 interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the PointerConstraints interface:
|
||||
* @code
|
||||
* PointerConstraints *c = registry->createPointerConstraints(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the PointerConstraints and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* PointerConstraints *c = new PointerConstraints;
|
||||
* c->setup(registry->bindPointerConstraints(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The PointerConstraints can be used as a drop-in replacement for any zwp_pointer_constraints_v1
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
* @since 5.29
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT PointerConstraints : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new PointerConstraints.
|
||||
* Note: after constructing the PointerConstraints it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use PointerConstraints prefer using
|
||||
* Registry::createPointerConstraints.
|
||||
**/
|
||||
explicit PointerConstraints(QObject *parent = nullptr);
|
||||
~PointerConstraints() override;
|
||||
|
||||
/**
|
||||
* Setup this PointerConstraints to manage the @p pointerconstraints.
|
||||
* When using Registry::createPointerConstraints there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zwp_pointer_constraints_v1 *pointerconstraints);
|
||||
/**
|
||||
* @returns @c true if managing a zwp_pointer_constraints_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zwp_pointer_constraints_v1 interface.
|
||||
* After the interface has been released the PointerConstraints instance is no
|
||||
* longer valid and can be setup with another zwp_pointer_constraints_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this PointerConstraints.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zwp_pointer_constraints_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, pointerconstraints, &PointerConstraints::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating objects with this PointerConstraints.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating objects with this PointerConstraints.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* These values represent different lifetime semantics. They are passed
|
||||
* as arguments to the factory requests to specify how the constraint
|
||||
* lifetimes should be managed.
|
||||
* @see lockPointer
|
||||
* @see confinePointer
|
||||
**/
|
||||
enum class LifeTime {
|
||||
/**
|
||||
* A OneShot pointer constraint will never reactivate once it has been
|
||||
* deactivated.
|
||||
**/
|
||||
OneShot,
|
||||
/**
|
||||
* A persistent pointer constraint may again reactivate once it has
|
||||
* been deactivated.
|
||||
**/
|
||||
Persistent,
|
||||
};
|
||||
|
||||
/**
|
||||
* This factory method creates a LockedPointer.
|
||||
*
|
||||
* A LockedPointer lets the client request to disable movements of
|
||||
* the virtual pointer (i.e. the cursor), effectively locking the pointer
|
||||
* to a position.
|
||||
*
|
||||
* Creating a LockedPointer does not lock the pointer immediately; in the
|
||||
* future, when the compositor deems implementation-specific constraints
|
||||
* are satisfied, the pointer lock will be activated and the compositor
|
||||
* sends a locked event, reported by {@link LockedPointer::locked}.
|
||||
*
|
||||
* The protocol provides no guarantee that the constraints are ever
|
||||
* satisfied, and does not require the compositor to send an error if the
|
||||
* constraints cannot ever be satisfied. It is thus possible to request a
|
||||
* lock that will never activate.
|
||||
*
|
||||
* There may not be another pointer constraint of any kind requested or
|
||||
* active on the @p surface for any of the Pointer objects of the Seat of
|
||||
* the passed @p pointer when requesting a lock. If there is, an error will be
|
||||
* raised.
|
||||
*
|
||||
* The intersection of the @p region passed with this request and the input
|
||||
* region of the @p surface is used to determine where the pointer must be
|
||||
* in order for the lock to activate. It is up to the compositor whether to
|
||||
* warp the pointer or require some kind of user interaction for the lock
|
||||
* to activate. If the @p region is null the surface input region is used.
|
||||
*
|
||||
* A Surface may receive pointer focus without the lock being activated.
|
||||
*
|
||||
* Note that while a pointer is locked, the Pointer objects of the
|
||||
* corresponding seat will not emit any {@link Pointer::motion} signals, but
|
||||
* relative motion events will still be emitted via {@link RelativePointer::relativeMotion}.
|
||||
* Pointer axis and button events are unaffected.
|
||||
*
|
||||
* @param surface The Surface which should be constrained in pointer motion
|
||||
* @param pointer The Pointer object for which this LockedPointer should be created
|
||||
* @param region Region where to lock the pointer, if @c null the input region of the Surface is used
|
||||
* @param lifetime Whether the LockedPointer becomes invalid on unlocked
|
||||
* @param parent The parent object for the LockedPointer
|
||||
* @returns The factored LockedPointer
|
||||
**/
|
||||
LockedPointer *lockPointer(Surface *surface, Pointer *pointer, Region *region, LifeTime lifetime, QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* This factory method creates a ConfinedPointer.
|
||||
*
|
||||
* A ConfinedPointer lets the client request to confine the
|
||||
* pointer cursor to a given @p region. Creating a ConfinedPointer
|
||||
* does not take effect immediately; in the future, when the compositor
|
||||
* deems implementation-specific constraints are satisfied, the pointer
|
||||
* confinement will be activated and the compositor sends a confined event,
|
||||
* which is reported through the {@link ConfinedPointer::confined} signal.
|
||||
*
|
||||
* The intersection of the @p region passed and the input region of the
|
||||
* @p surface is used to determine where the pointer must be
|
||||
* in order for the confinement to activate. It is up to the compositor
|
||||
* whether to warp the pointer or require some kind of user interaction for
|
||||
* the confinement to activate. If the @p region is @c null the @p surface input
|
||||
* region is used.
|
||||
*
|
||||
* @param surface The Surface which should be constrained in pointer motion
|
||||
* @param pointer The Pointer object for which this LockedPointer should be created
|
||||
* @param region Region where to confine the pointer, if @c null the input region of the Surface is used
|
||||
* @param lifetime Whether the ConfinedPointer becomes invalid on unconfined
|
||||
* @param parent The parent object for the ConfinedPointer
|
||||
* @returns The factored ConfinedPointer
|
||||
**/
|
||||
ConfinedPointer *confinePointer(Surface *surface, Pointer *pointer, Region *region, LifeTime lifetime, QObject *parent = nullptr);
|
||||
|
||||
operator zwp_pointer_constraints_v1 *();
|
||||
operator zwp_pointer_constraints_v1 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the PointerConstraints got created by
|
||||
* Registry::createPointerConstraints
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Wrapper for the zwp_locked_pointer_v1 interface.
|
||||
*
|
||||
* The LockedPointer represents a locked pointer state.
|
||||
*
|
||||
* While the lock of this object is active, the Pointer objects of the
|
||||
* associated seat will not emit any {@link Pointer::motion} events.
|
||||
*
|
||||
* This object will send the signal locked when the lock is activated.
|
||||
* Whenever the lock is activated, it is guaranteed that the locked surface
|
||||
* will already have received pointer focus and that the pointer will be
|
||||
* within the region passed to the request creating this object.
|
||||
*
|
||||
* To unlock the pointer, delete the object.
|
||||
*
|
||||
* If the compositor decides to unlock the pointer the unlocked signal is
|
||||
* emitted.
|
||||
*
|
||||
* When unlocking, the compositor may warp the cursor position to the set
|
||||
* cursor position hint. If it does, it will not result in any relative
|
||||
* motion events emitted via {@link RelativePointer::relativeMotion}.
|
||||
*
|
||||
* If the Surface the lock was requested on is destroyed and the lock is not
|
||||
* yet activated, the LockedPointer object is now defunct and must be
|
||||
* deleted.
|
||||
*
|
||||
* @see PointerConstraints::lockedPointer
|
||||
* @since 5.29
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT LockedPointer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~LockedPointer() override;
|
||||
|
||||
/**
|
||||
* Setup this LockedPointer to manage the @p lockedpointer.
|
||||
* When using PointerConstraints::createLockedPointer there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zwp_locked_pointer_v1 *lockedpointer);
|
||||
/**
|
||||
* @returns @c true if managing a zwp_locked_pointer_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zwp_locked_pointer_v1 interface.
|
||||
* After the interface has been released the LockedPointer instance is no
|
||||
* longer valid and can be setup with another zwp_locked_pointer_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this LockedPointer.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zwp_locked_pointer_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, lockedpointer, &LockedPointer::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Set the cursor position hint relative to the top left corner of the Surface.
|
||||
*
|
||||
* If the client is drawing its own cursor, it should update the position
|
||||
* hint to the position of its own cursor. A compositor may use this
|
||||
* information to warp the pointer upon unlock in order to avoid pointer
|
||||
* jumps.
|
||||
*
|
||||
* The cursor position hint is double buffered. The new hint will only take
|
||||
* effect when the associated surface gets it pending state applied.
|
||||
* See {@link Surface::commit} for details.
|
||||
*
|
||||
* @param surfaceLocal The new position hint in surface local coordinates
|
||||
* @see Surface::commit
|
||||
**/
|
||||
void setCursorPositionHint(const QPointF &surfaceLocal);
|
||||
|
||||
/**
|
||||
* Set a new region used to lock the pointer.
|
||||
*
|
||||
* The new lock region is double-buffered. The new lock region will
|
||||
* only take effect when the associated Surface gets its pending state
|
||||
* applied. See {@link Surface::commit} for details.
|
||||
*
|
||||
* @param region The new lock region.
|
||||
* @see Surface::commit
|
||||
* @see PointerConstraints::lockPointer
|
||||
**/
|
||||
void setRegion(Region *region);
|
||||
|
||||
operator zwp_locked_pointer_v1 *();
|
||||
operator zwp_locked_pointer_v1 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Notification that the pointer lock of the seat's pointer is activated.
|
||||
* @see unlocked
|
||||
**/
|
||||
void locked();
|
||||
|
||||
/**
|
||||
* Notification that the pointer lock of the seat's pointer is no longer
|
||||
* active. If this is a oneshot pointer lock (see
|
||||
* wp_pointer_constraints.lifetime) this object is now defunct and should
|
||||
* be destroyed. If this is a persistent pointer lock (see
|
||||
* wp_pointer_constraints.lifetime) this pointer lock may again
|
||||
* reactivate in the future.
|
||||
* @see locked
|
||||
**/
|
||||
void unlocked();
|
||||
|
||||
private:
|
||||
friend class PointerConstraints;
|
||||
explicit LockedPointer(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Wrapper for zwp_confined_pointer_v1 protocol
|
||||
* The confine pointer interface represents a confined pointer state.
|
||||
*
|
||||
* This object will send the signal 'confined' when the confinement is
|
||||
* activated. Whenever the confinement is activated, it is guaranteed that
|
||||
* the surface the pointer is confined to will already have received pointer
|
||||
* focus and that the pointer will be within the region passed to the request
|
||||
* creating this object. It is up to the compositor to decide whether this
|
||||
* requires some user interaction and if the pointer will warp to within the
|
||||
* passed region if outside.
|
||||
*
|
||||
* To unconfine the pointer, delete the object.
|
||||
*
|
||||
* If the compositor decides to unconfine the pointer the unconfined signal is
|
||||
* emitted. The ConfinedPointer object is at this point defunct and should
|
||||
* be deleted.
|
||||
* @see PointerConstraints::confinePointer
|
||||
* @since 5.29
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT ConfinedPointer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~ConfinedPointer() override;
|
||||
|
||||
/**
|
||||
* Setup this ConfinedPointer to manage the @p confinedpointer.
|
||||
* When using PointerConstraints::createConfinedPointer there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zwp_confined_pointer_v1 *confinedpointer);
|
||||
/**
|
||||
* @returns @c true if managing a zwp_confined_pointer_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zwp_confined_pointer_v1 interface.
|
||||
* After the interface has been released the ConfinedPointer instance is no
|
||||
* longer valid and can be setup with another zwp_confined_pointer_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this ConfinedPointer.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zwp_confined_pointer_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* PointerConstraints gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Set a new region used to confine the pointer.
|
||||
*
|
||||
* The new confine region is double-buffered. The new confine region will
|
||||
* only take effect when the associated Surface gets its pending state
|
||||
* applied. See {@link Surface::commit} for details.
|
||||
*
|
||||
* If the confinement is active when the new confinement region is applied
|
||||
* and the pointer ends up outside of newly applied region, the pointer may
|
||||
* warped to a position within the new confinement region. If warped, a
|
||||
* {@link Pointer::motion} signal will be emitted, but no
|
||||
* {@link RelativePointer::relativeMotion} signal.
|
||||
*
|
||||
* The compositor may also, instead of using the new region, unconfine the
|
||||
* pointer.
|
||||
*
|
||||
* @param region The new confine region.
|
||||
* @see Surface::commit
|
||||
* @see PointerConstraints::confinePointer
|
||||
**/
|
||||
void setRegion(Region *region);
|
||||
|
||||
operator zwp_confined_pointer_v1 *();
|
||||
operator zwp_confined_pointer_v1 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Notification that the pointer confinement of the seat's pointer is activated.
|
||||
* @see unconfined
|
||||
**/
|
||||
void confined();
|
||||
|
||||
/**
|
||||
* Notification that the pointer confinement of the seat's pointer is no
|
||||
* longer active. If this is a oneshot pointer confinement (see
|
||||
* wp_pointer_constraints.lifetime) this object is now defunct and should
|
||||
* be destroyed. If this is a persistent pointer confinement (see
|
||||
* wp_pointer_constraints.lifetime) this pointer confinement may again
|
||||
* reactivate in the future.
|
||||
* @see confined
|
||||
**/
|
||||
void unconfined();
|
||||
|
||||
private:
|
||||
friend class PointerConstraints;
|
||||
explicit ConfinedPointer(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,379 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "pointergestures.h"
|
||||
#include "event_queue.h"
|
||||
#include "pointer.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <wayland-pointer-gestures-unstable-v1-client-protocol.h>
|
||||
|
||||
#include <QSizeF>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN PointerGestures::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
WaylandPointer<zwp_pointer_gestures_v1, zwp_pointer_gestures_v1_destroy> pointergestures;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
PointerGestures::PointerGestures(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
PointerGestures::~PointerGestures()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void PointerGestures::setup(zwp_pointer_gestures_v1 *pointergestures)
|
||||
{
|
||||
Q_ASSERT(pointergestures);
|
||||
Q_ASSERT(!d->pointergestures);
|
||||
d->pointergestures.setup(pointergestures);
|
||||
}
|
||||
|
||||
void PointerGestures::release()
|
||||
{
|
||||
d->pointergestures.release();
|
||||
}
|
||||
|
||||
void PointerGestures::destroy()
|
||||
{
|
||||
d->pointergestures.destroy();
|
||||
}
|
||||
|
||||
PointerGestures::operator zwp_pointer_gestures_v1 *()
|
||||
{
|
||||
return d->pointergestures;
|
||||
}
|
||||
|
||||
PointerGestures::operator zwp_pointer_gestures_v1 *() const
|
||||
{
|
||||
return d->pointergestures;
|
||||
}
|
||||
|
||||
bool PointerGestures::isValid() const
|
||||
{
|
||||
return d->pointergestures.isValid();
|
||||
}
|
||||
|
||||
void PointerGestures::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *PointerGestures::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
PointerSwipeGesture *PointerGestures::createSwipeGesture(Pointer *pointer, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
PointerSwipeGesture *p = new PointerSwipeGesture(parent);
|
||||
auto w = zwp_pointer_gestures_v1_get_swipe_gesture(d->pointergestures, *pointer);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
p->setup(w);
|
||||
return p;
|
||||
}
|
||||
|
||||
PointerPinchGesture *PointerGestures::createPinchGesture(Pointer *pointer, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
PointerPinchGesture *p = new PointerPinchGesture(parent);
|
||||
auto w = zwp_pointer_gestures_v1_get_pinch_gesture(d->pointergestures, *pointer);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
p->setup(w);
|
||||
return p;
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN PointerSwipeGesture::Private
|
||||
{
|
||||
public:
|
||||
Private(PointerSwipeGesture *q);
|
||||
|
||||
void setup(zwp_pointer_gesture_swipe_v1 *pg);
|
||||
|
||||
WaylandPointer<zwp_pointer_gesture_swipe_v1, zwp_pointer_gesture_swipe_v1_destroy> pointerswipegesture;
|
||||
quint32 fingerCount = 0;
|
||||
QPointer<Surface> surface;
|
||||
|
||||
private:
|
||||
static void beginCallback(void *data,
|
||||
zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
wl_surface *surface,
|
||||
uint32_t fingers);
|
||||
static void updateCallback(void *data, zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1, uint32_t time, wl_fixed_t dx, wl_fixed_t dy);
|
||||
static void endCallback(void *data, zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1, uint32_t serial, uint32_t time, int32_t cancelled);
|
||||
|
||||
PointerSwipeGesture *q;
|
||||
static const zwp_pointer_gesture_swipe_v1_listener s_listener;
|
||||
};
|
||||
|
||||
const zwp_pointer_gesture_swipe_v1_listener PointerSwipeGesture::Private::s_listener = {beginCallback, updateCallback, endCallback};
|
||||
|
||||
void PointerSwipeGesture::Private::beginCallback(void *data,
|
||||
zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
wl_surface *surface,
|
||||
uint32_t fingers)
|
||||
{
|
||||
auto p = reinterpret_cast<PointerSwipeGesture::Private *>(data);
|
||||
Q_ASSERT(p->pointerswipegesture == zwp_pointer_gesture_swipe_v1);
|
||||
p->fingerCount = fingers;
|
||||
p->surface = QPointer<Surface>(Surface::get(surface));
|
||||
Q_EMIT p->q->started(serial, time);
|
||||
}
|
||||
|
||||
void PointerSwipeGesture::Private::updateCallback(void *data,
|
||||
zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1,
|
||||
uint32_t time,
|
||||
wl_fixed_t dx,
|
||||
wl_fixed_t dy)
|
||||
{
|
||||
auto p = reinterpret_cast<PointerSwipeGesture::Private *>(data);
|
||||
Q_ASSERT(p->pointerswipegesture == zwp_pointer_gesture_swipe_v1);
|
||||
Q_EMIT p->q->updated(QSizeF(wl_fixed_to_double(dx), wl_fixed_to_double(dy)), time);
|
||||
}
|
||||
|
||||
void PointerSwipeGesture::Private::endCallback(void *data,
|
||||
zwp_pointer_gesture_swipe_v1 *zwp_pointer_gesture_swipe_v1,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
int32_t cancelled)
|
||||
{
|
||||
auto p = reinterpret_cast<PointerSwipeGesture::Private *>(data);
|
||||
Q_ASSERT(p->pointerswipegesture == zwp_pointer_gesture_swipe_v1);
|
||||
if (cancelled) {
|
||||
Q_EMIT p->q->cancelled(serial, time);
|
||||
} else {
|
||||
Q_EMIT p->q->ended(serial, time);
|
||||
}
|
||||
p->fingerCount = 0;
|
||||
p->surface.clear();
|
||||
}
|
||||
|
||||
PointerSwipeGesture::Private::Private(PointerSwipeGesture *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
PointerSwipeGesture::PointerSwipeGesture(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
PointerSwipeGesture::~PointerSwipeGesture()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
quint32 PointerSwipeGesture::fingerCount() const
|
||||
{
|
||||
return d->fingerCount;
|
||||
}
|
||||
|
||||
QPointer<Surface> PointerSwipeGesture::surface() const
|
||||
{
|
||||
return d->surface;
|
||||
}
|
||||
|
||||
void PointerSwipeGesture::Private::setup(zwp_pointer_gesture_swipe_v1 *pg)
|
||||
{
|
||||
Q_ASSERT(pg);
|
||||
Q_ASSERT(!pointerswipegesture);
|
||||
pointerswipegesture.setup(pg);
|
||||
zwp_pointer_gesture_swipe_v1_add_listener(pointerswipegesture, &s_listener, this);
|
||||
}
|
||||
|
||||
void PointerSwipeGesture::setup(zwp_pointer_gesture_swipe_v1 *pointerswipegesture)
|
||||
{
|
||||
d->setup(pointerswipegesture);
|
||||
}
|
||||
|
||||
void PointerSwipeGesture::release()
|
||||
{
|
||||
d->pointerswipegesture.release();
|
||||
}
|
||||
|
||||
void PointerSwipeGesture::destroy()
|
||||
{
|
||||
d->pointerswipegesture.destroy();
|
||||
}
|
||||
|
||||
PointerSwipeGesture::operator zwp_pointer_gesture_swipe_v1 *()
|
||||
{
|
||||
return d->pointerswipegesture;
|
||||
}
|
||||
|
||||
PointerSwipeGesture::operator zwp_pointer_gesture_swipe_v1 *() const
|
||||
{
|
||||
return d->pointerswipegesture;
|
||||
}
|
||||
|
||||
bool PointerSwipeGesture::isValid() const
|
||||
{
|
||||
return d->pointerswipegesture.isValid();
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN PointerPinchGesture::Private
|
||||
{
|
||||
public:
|
||||
Private(PointerPinchGesture *q);
|
||||
|
||||
void setup(zwp_pointer_gesture_pinch_v1 *pg);
|
||||
|
||||
WaylandPointer<zwp_pointer_gesture_pinch_v1, zwp_pointer_gesture_pinch_v1_destroy> pointerpinchgesture;
|
||||
quint32 fingerCount = 0;
|
||||
QPointer<Surface> surface;
|
||||
|
||||
private:
|
||||
static void beginCallback(void *data,
|
||||
zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
wl_surface *surface,
|
||||
uint32_t fingers);
|
||||
static void updateCallback(void *data,
|
||||
zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1,
|
||||
uint32_t time,
|
||||
wl_fixed_t dx,
|
||||
wl_fixed_t dy,
|
||||
wl_fixed_t scale,
|
||||
wl_fixed_t rotation);
|
||||
static void endCallback(void *data, zwp_pointer_gesture_pinch_v1 *zwp_pointer_gesture_pinch_v1, uint32_t serial, uint32_t time, int32_t cancelled);
|
||||
|
||||
PointerPinchGesture *q;
|
||||
static const zwp_pointer_gesture_pinch_v1_listener s_listener;
|
||||
};
|
||||
|
||||
const zwp_pointer_gesture_pinch_v1_listener PointerPinchGesture::Private::s_listener = {beginCallback, updateCallback, endCallback};
|
||||
|
||||
void PointerPinchGesture::Private::beginCallback(void *data,
|
||||
zwp_pointer_gesture_pinch_v1 *pg,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
wl_surface *surface,
|
||||
uint32_t fingers)
|
||||
{
|
||||
auto p = reinterpret_cast<PointerPinchGesture::Private *>(data);
|
||||
Q_ASSERT(p->pointerpinchgesture == pg);
|
||||
p->fingerCount = fingers;
|
||||
p->surface = QPointer<Surface>(Surface::get(surface));
|
||||
Q_EMIT p->q->started(serial, time);
|
||||
}
|
||||
|
||||
void PointerPinchGesture::Private::updateCallback(void *data,
|
||||
zwp_pointer_gesture_pinch_v1 *pg,
|
||||
uint32_t time,
|
||||
wl_fixed_t dx,
|
||||
wl_fixed_t dy,
|
||||
wl_fixed_t scale,
|
||||
wl_fixed_t rotation)
|
||||
{
|
||||
auto p = reinterpret_cast<PointerPinchGesture::Private *>(data);
|
||||
Q_ASSERT(p->pointerpinchgesture == pg);
|
||||
Q_EMIT p->q->updated(QSizeF(wl_fixed_to_double(dx), wl_fixed_to_double(dy)), wl_fixed_to_double(scale), wl_fixed_to_double(rotation), time);
|
||||
}
|
||||
|
||||
void PointerPinchGesture::Private::endCallback(void *data, zwp_pointer_gesture_pinch_v1 *pg, uint32_t serial, uint32_t time, int32_t cancelled)
|
||||
{
|
||||
auto p = reinterpret_cast<PointerPinchGesture::Private *>(data);
|
||||
Q_ASSERT(p->pointerpinchgesture == pg);
|
||||
if (cancelled) {
|
||||
Q_EMIT p->q->cancelled(serial, time);
|
||||
} else {
|
||||
Q_EMIT p->q->ended(serial, time);
|
||||
}
|
||||
p->fingerCount = 0;
|
||||
p->surface.clear();
|
||||
}
|
||||
|
||||
PointerPinchGesture::Private::Private(PointerPinchGesture *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
PointerPinchGesture::PointerPinchGesture(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
PointerPinchGesture::~PointerPinchGesture()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void PointerPinchGesture::Private::setup(zwp_pointer_gesture_pinch_v1 *pg)
|
||||
{
|
||||
Q_ASSERT(pg);
|
||||
Q_ASSERT(!pointerpinchgesture);
|
||||
pointerpinchgesture.setup(pg);
|
||||
zwp_pointer_gesture_pinch_v1_add_listener(pointerpinchgesture, &s_listener, this);
|
||||
}
|
||||
|
||||
void PointerPinchGesture::setup(zwp_pointer_gesture_pinch_v1 *pointerpinchgesture)
|
||||
{
|
||||
d->setup(pointerpinchgesture);
|
||||
}
|
||||
|
||||
void PointerPinchGesture::release()
|
||||
{
|
||||
d->pointerpinchgesture.release();
|
||||
}
|
||||
|
||||
void PointerPinchGesture::destroy()
|
||||
{
|
||||
d->pointerpinchgesture.destroy();
|
||||
}
|
||||
|
||||
PointerPinchGesture::operator zwp_pointer_gesture_pinch_v1 *()
|
||||
{
|
||||
return d->pointerpinchgesture;
|
||||
}
|
||||
|
||||
PointerPinchGesture::operator zwp_pointer_gesture_pinch_v1 *() const
|
||||
{
|
||||
return d->pointerpinchgesture;
|
||||
}
|
||||
|
||||
bool PointerPinchGesture::isValid() const
|
||||
{
|
||||
return d->pointerpinchgesture.isValid();
|
||||
}
|
||||
|
||||
quint32 PointerPinchGesture::fingerCount() const
|
||||
{
|
||||
return d->fingerCount;
|
||||
}
|
||||
|
||||
QPointer<Surface> PointerPinchGesture::surface() const
|
||||
{
|
||||
return d->surface;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_pointergestures.cpp"
|
||||
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_POINTERGESTURES_H
|
||||
#define KWAYLAND_CLIENT_POINTERGESTURES_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct zwp_pointer_gestures_v1;
|
||||
struct zwp_pointer_gesture_swipe_v1;
|
||||
struct zwp_pointer_gesture_pinch_v1;
|
||||
|
||||
class QSizeF;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class PointerPinchGesture;
|
||||
class Pointer;
|
||||
class Surface;
|
||||
class PointerSwipeGesture;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the zwp_pointer_gestures_v1 interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the zwp_pointer_gestures_v1 interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the PointerGestures interface:
|
||||
* @code
|
||||
* PointerGestures *c = registry->createPointerGestures(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the PointerGestures and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* PointerGestures *c = new PointerGestures;
|
||||
* c->setup(registry->bindPointerGestures(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The PointerGestures can be used as a drop-in replacement for any zwp_pointer_gestures_v1
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
* @see PointerSwipeGesture
|
||||
* @see PointerPinchGesture
|
||||
* @since 5.29
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT PointerGestures : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new PointerGestures.
|
||||
* Note: after constructing the PointerGestures it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use PointerGestures prefer using
|
||||
* Registry::createPointerGestures.
|
||||
**/
|
||||
explicit PointerGestures(QObject *parent = nullptr);
|
||||
~PointerGestures() override;
|
||||
|
||||
/**
|
||||
* Setup this PointerGestures to manage the @p pointergestures.
|
||||
* When using Registry::createPointerGestures there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zwp_pointer_gestures_v1 *pointergestures);
|
||||
/**
|
||||
* @returns @c true if managing a zwp_pointer_gestures_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zwp_pointer_gestures_v1 interface.
|
||||
* After the interface has been released the PointerGestures instance is no
|
||||
* longer valid and can be setup with another zwp_pointer_gestures_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this PointerGestures.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zwp_pointer_gestures_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* PointerGestures gets destroyed.
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating objects with this PointerGestures.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating objects with this PointerGestures.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Creates a PointerSwipeGesture for the given @p pointer with the @p parent.
|
||||
**/
|
||||
PointerSwipeGesture *createSwipeGesture(Pointer *pointer, QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Creates a PointerPinchGesture for the given @p pointer with the @p parent.
|
||||
**/
|
||||
PointerPinchGesture *createPinchGesture(Pointer *pointer, QObject *parent = nullptr);
|
||||
|
||||
operator zwp_pointer_gestures_v1 *();
|
||||
operator zwp_pointer_gestures_v1 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the PointerGestures got created by
|
||||
* Registry::createPointerGestures
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class is a wrapper for the zwp_pointer_gesture_swipe_v1 protocol.
|
||||
*
|
||||
* A PointerSwipeGesture object notifies a client about a multi-finger swipe
|
||||
* gesture detected on an indirect input device such as a touchpad.
|
||||
* The gesture is usually initiated by multiple fingers moving in the
|
||||
* same direction but once initiated the direction may change.
|
||||
* The precise conditions of when such a gesture is detected are
|
||||
* implementation-dependent.
|
||||
*
|
||||
* A gesture consists of three stages: begin, update (optional) and end.
|
||||
* There cannot be multiple simultaneous pinch or swipe gestures on the
|
||||
* same pointer/seat, how compositors prevent these situations is
|
||||
* implementation-dependent.
|
||||
*
|
||||
* A gesture may be cancelled by the compositor or the hardware.
|
||||
* Clients should not consider performing permanent or irreversible
|
||||
* actions until the end of a gesture has been received.
|
||||
*
|
||||
* @see PointerGestures
|
||||
* @see PointerPinchGesture
|
||||
* @since 5.29
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT PointerSwipeGesture : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~PointerSwipeGesture() override;
|
||||
|
||||
/**
|
||||
* Setup this PointerSwipeGesture to manage the @p pointerswipegesture.
|
||||
* When using PointerGestures::createPointerSwipeGesture there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zwp_pointer_gesture_swipe_v1 *pointerswipegesture);
|
||||
/**
|
||||
* @returns @c true if managing a zwp_pointer_gesture_swipe_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zwp_pointer_gesture_swipe_v1 interface.
|
||||
* After the interface has been released the PointerSwipeGesture instance is no
|
||||
* longer valid and can be setup with another zwp_pointer_gesture_swipe_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this PointerSwipeGesture.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zwp_pointer_gesture_swipe_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, pointerswipegesture, &PointerSwipeGesture::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* The number of fingers taking part in this gesture.
|
||||
* If no gesture is in progress @c 0 is returned.
|
||||
**/
|
||||
quint32 fingerCount() const;
|
||||
|
||||
/**
|
||||
* The Surface on which this gesture is performed.
|
||||
* If no gesture is in progress the returned pointer is null.
|
||||
**/
|
||||
QPointer<Surface> surface() const;
|
||||
|
||||
operator zwp_pointer_gesture_swipe_v1 *();
|
||||
operator zwp_pointer_gesture_swipe_v1 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* A gesture got started.
|
||||
* @param serial Unique serial for this start gesture event.
|
||||
* @param time Timestamp in milliseconds granularity
|
||||
* @see updated
|
||||
* @see ended
|
||||
* @see cancelled
|
||||
**/
|
||||
void started(quint32 serial, quint32 time);
|
||||
|
||||
/**
|
||||
* A gesture got updated.
|
||||
* @param delta relative coordinates of the logical center of the gesture compared to the previous event
|
||||
* @param time Timestamp in milliseconds granularity
|
||||
* @see started
|
||||
* @see ended
|
||||
* @see cancelled
|
||||
**/
|
||||
void updated(const QSizeF &delta, quint32 time);
|
||||
|
||||
/**
|
||||
* A gesture ended.
|
||||
*
|
||||
* @param serial Unique serial for this end gesture event.
|
||||
* @param time Timestamp in milliseconds granularity
|
||||
* @see started
|
||||
* @see updated
|
||||
* @see cancelled
|
||||
**/
|
||||
void ended(quint32 serial, quint32 time);
|
||||
|
||||
/**
|
||||
* A gesture got cancelled by the Wayland compositor.
|
||||
*
|
||||
* @param serial Unique serial for this cancel gesture event.
|
||||
* @param time Timestamp in milliseconds granularity
|
||||
* @see started
|
||||
* @see updated
|
||||
* @see ended
|
||||
**/
|
||||
void cancelled(quint32 serial, quint32 time);
|
||||
|
||||
private:
|
||||
friend class PointerGestures;
|
||||
explicit PointerSwipeGesture(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class is a wrapper for the zwp_pointer_gesture_pinch_v1 protocol.
|
||||
*
|
||||
* A PointerPinchGesture object notifies a client about a multi-finger pinch
|
||||
* gesture detected on an indirect input device such as a touchpad.
|
||||
* The gesture is usually initiated by multiple fingers moving towards
|
||||
* each other or away from each other, or by two or more fingers rotating
|
||||
* around a logical center of gravity. The precise conditions of when
|
||||
* such a gesture is detected are implementation-dependent.
|
||||
*
|
||||
* A gesture consists of three stages: begin, update (optional) and end.
|
||||
* There cannot be multiple simultaneous pinch or swipe gestures on the
|
||||
* same pointer/seat, how compositors prevent these situations is
|
||||
* implementation-dependent.
|
||||
*
|
||||
* A gesture may be cancelled by the compositor or the hardware.
|
||||
* Clients should not consider performing permanent or irreversible
|
||||
* actions until the end of a gesture has been received.
|
||||
*
|
||||
* @see PointerGestures
|
||||
* @see PointerSwipeGesture
|
||||
* @since 5.29
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT PointerPinchGesture : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~PointerPinchGesture() override;
|
||||
|
||||
/**
|
||||
* Setup this PointerPinchGesture to manage the @p pointerpinchgesture.
|
||||
* When using PointerGestures::createPointerPinchGesture there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zwp_pointer_gesture_pinch_v1 *pointerpinchgesture);
|
||||
/**
|
||||
* @returns @c true if managing a zwp_pointer_gesture_pinch_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zwp_pointer_gesture_pinch_v1 interface.
|
||||
* After the interface has been released the PointerPinchGesture instance is no
|
||||
* longer valid and can be setup with another zwp_pointer_gesture_pinch_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this PointerPinchGesture.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zwp_pointer_gesture_pinch_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, pointerpinchgesture, &PointerPinchGesture::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* The number of fingers taking part in this gesture.
|
||||
* If no gesture is in progress @c 0 is returned.
|
||||
**/
|
||||
quint32 fingerCount() const;
|
||||
|
||||
/**
|
||||
* The Surface on which this gesture is performed.
|
||||
* If no gesture is in progress the returned pointer is null.
|
||||
**/
|
||||
QPointer<Surface> surface() const;
|
||||
|
||||
operator zwp_pointer_gesture_pinch_v1 *();
|
||||
operator zwp_pointer_gesture_pinch_v1 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* A gesture got started.
|
||||
* @param serial Unique serial for this start gesture event.
|
||||
* @param time Timestamp in milliseconds granularity
|
||||
* @see updated
|
||||
* @see ended
|
||||
* @see cancelled
|
||||
**/
|
||||
void started(quint32 serial, quint32 time);
|
||||
|
||||
/**
|
||||
* A gesture got updated.
|
||||
* @param delta relative coordinates of the logical center of the gesture compared to the previous event
|
||||
* @param scale an absolute scale compared to the start
|
||||
* @param rotation relative angle in degrees clockwise compared to the previous start or update event.
|
||||
* @param time Timestamp in milliseconds granularity
|
||||
* @see started
|
||||
* @see ended
|
||||
* @see cancelled
|
||||
**/
|
||||
void updated(const QSizeF &delta, qreal scale, qreal rotation, quint32 time);
|
||||
|
||||
/**
|
||||
* A gesture ended.
|
||||
*
|
||||
* @param serial Unique serial for this end gesture event.
|
||||
* @param time Timestamp in milliseconds granularity
|
||||
* @see started
|
||||
* @see updated
|
||||
* @see cancelled
|
||||
**/
|
||||
void ended(quint32 serial, quint32 time);
|
||||
|
||||
/**
|
||||
* A gesture got cancelled by the Wayland compositor.
|
||||
*
|
||||
* @param serial Unique serial for this cancel gesture event.
|
||||
* @param time Timestamp in milliseconds granularity
|
||||
* @see started
|
||||
* @see updated
|
||||
* @see ended
|
||||
**/
|
||||
void cancelled(quint32 serial, quint32 time);
|
||||
|
||||
private:
|
||||
friend class PointerGestures;
|
||||
explicit PointerPinchGesture(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "region.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Qt
|
||||
#include <QList>
|
||||
#include <QRegion>
|
||||
// Wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN Region::Private
|
||||
{
|
||||
public:
|
||||
Private(const QRegion ®ion);
|
||||
void installRegion(const QRect &rect);
|
||||
void installRegion(const QRegion ®ion);
|
||||
void uninstallRegion(const QRect &rect);
|
||||
void uninstallRegion(const QRegion ®ion);
|
||||
|
||||
WaylandPointer<wl_region, wl_region_destroy> region;
|
||||
QRegion qtRegion;
|
||||
};
|
||||
|
||||
Region::Private::Private(const QRegion ®ion)
|
||||
: qtRegion(region)
|
||||
{
|
||||
}
|
||||
|
||||
void Region::Private::installRegion(const QRect &rect)
|
||||
{
|
||||
if (!region.isValid()) {
|
||||
return;
|
||||
}
|
||||
wl_region_add(region, rect.x(), rect.y(), rect.width(), rect.height());
|
||||
}
|
||||
|
||||
void Region::Private::installRegion(const QRegion ®ion)
|
||||
{
|
||||
for (const QRect &rect : region) {
|
||||
installRegion(rect);
|
||||
}
|
||||
}
|
||||
|
||||
void Region::Private::uninstallRegion(const QRect &rect)
|
||||
{
|
||||
if (!region.isValid()) {
|
||||
return;
|
||||
}
|
||||
wl_region_subtract(region, rect.x(), rect.y(), rect.width(), rect.height());
|
||||
}
|
||||
|
||||
void Region::Private::uninstallRegion(const QRegion ®ion)
|
||||
{
|
||||
for (const QRect &rect : region) {
|
||||
uninstallRegion(rect);
|
||||
}
|
||||
}
|
||||
|
||||
Region::Region(const QRegion ®ion, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(region))
|
||||
{
|
||||
}
|
||||
|
||||
Region::~Region()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void Region::release()
|
||||
{
|
||||
d->region.release();
|
||||
}
|
||||
|
||||
void Region::destroy()
|
||||
{
|
||||
d->region.destroy();
|
||||
}
|
||||
|
||||
void Region::setup(wl_region *region)
|
||||
{
|
||||
Q_ASSERT(region);
|
||||
d->region.setup(region);
|
||||
d->installRegion(d->qtRegion);
|
||||
}
|
||||
|
||||
bool Region::isValid() const
|
||||
{
|
||||
return d->region.isValid();
|
||||
}
|
||||
|
||||
void Region::add(const QRect &rect)
|
||||
{
|
||||
d->qtRegion = d->qtRegion.united(rect);
|
||||
d->installRegion(rect);
|
||||
}
|
||||
|
||||
void Region::add(const QRegion ®ion)
|
||||
{
|
||||
d->qtRegion = d->qtRegion.united(region);
|
||||
d->installRegion(region);
|
||||
}
|
||||
|
||||
void Region::subtract(const QRect &rect)
|
||||
{
|
||||
d->qtRegion = d->qtRegion.subtracted(rect);
|
||||
d->uninstallRegion(rect);
|
||||
}
|
||||
|
||||
void Region::subtract(const QRegion ®ion)
|
||||
{
|
||||
d->qtRegion = d->qtRegion.subtracted(region);
|
||||
d->uninstallRegion(region);
|
||||
}
|
||||
|
||||
QRegion Region::region() const
|
||||
{
|
||||
return d->qtRegion;
|
||||
}
|
||||
|
||||
Region::operator wl_region *() const
|
||||
{
|
||||
return d->region;
|
||||
}
|
||||
|
||||
Region::operator wl_region *()
|
||||
{
|
||||
return d->region;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_region.cpp"
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_REGION_H
|
||||
#define WAYLAND_REGION_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_region;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
/**
|
||||
* @short Wrapper for the wl_region interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the wl_region interface.
|
||||
* To create a Region call Compositor::createRegion.
|
||||
*
|
||||
* The main purpose of this class is to provide regions which can be
|
||||
* used to e.g. set the input region on a Surface.
|
||||
*
|
||||
* @see Compositor
|
||||
* @see Surface
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Region : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Region(const QRegion ®ion, QObject *parent = nullptr);
|
||||
~Region() override;
|
||||
|
||||
/**
|
||||
* Setup this Surface to manage the @p region.
|
||||
* When using Compositor::createRegion there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_region *region);
|
||||
/**
|
||||
* Releases the wl_region interface.
|
||||
* After the interface has been released the Region instance is no
|
||||
* longer valid and can be setup with another wl_region interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this Region.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_region interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, region, &Region::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* @returns @c true if managing a wl_region.
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* Adds the @p rect to this Region.
|
||||
**/
|
||||
void add(const QRect &rect);
|
||||
/**
|
||||
* Adds the @p region to this Rregion.
|
||||
**/
|
||||
void add(const QRegion ®ion);
|
||||
/**
|
||||
* Subtracts @p rect from this Region.
|
||||
**/
|
||||
void subtract(const QRect &rect);
|
||||
/**
|
||||
* Subtracts @p region from this Region.
|
||||
**/
|
||||
void subtract(const QRegion ®ion);
|
||||
|
||||
/**
|
||||
* The geometry of this Region.
|
||||
**/
|
||||
QRegion region() const;
|
||||
|
||||
operator wl_region *();
|
||||
operator wl_region *() const;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,815 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
SPDX-FileCopyrightText: 2018 David Edmundson <davidedmundson@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "registry.h"
|
||||
#include "appmenu.h"
|
||||
#include "blur.h"
|
||||
#include "compositor.h"
|
||||
#include "connection_thread.h"
|
||||
#include "contrast.h"
|
||||
#include "datadevicemanager.h"
|
||||
#include "dpms.h"
|
||||
#include "event_queue.h"
|
||||
#include "fakeinput.h"
|
||||
#include "idleinhibit.h"
|
||||
#include "logging.h"
|
||||
#include "output.h"
|
||||
#include "plasmashell.h"
|
||||
#include "plasmavirtualdesktop.h"
|
||||
#include "plasmawindowmanagement.h"
|
||||
#include "pointerconstraints.h"
|
||||
#include "pointergestures.h"
|
||||
#include "relativepointer.h"
|
||||
#include "seat.h"
|
||||
#include "shadow.h"
|
||||
#include "shell.h"
|
||||
#include "shm_pool.h"
|
||||
#include "slide.h"
|
||||
#include "subcompositor.h"
|
||||
#include "textinput_p.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
#include "xdgdecoration.h"
|
||||
#include "xdgforeign_v2.h"
|
||||
#include "xdgoutput.h"
|
||||
#include "xdgshell.h"
|
||||
#include "xdgshell_p.h"
|
||||
// Qt
|
||||
#include <QDebug>
|
||||
// wayland
|
||||
#include "../compat/wayland-xdg-shell-v5-client-protocol.h"
|
||||
#include <wayland-appmenu-client-protocol.h>
|
||||
#include <wayland-blur-client-protocol.h>
|
||||
#include <wayland-client-protocol.h>
|
||||
#include <wayland-contrast-client-protocol.h>
|
||||
#include <wayland-dpms-client-protocol.h>
|
||||
#include <wayland-fake-input-client-protocol.h>
|
||||
#include <wayland-idle-inhibit-unstable-v1-client-protocol.h>
|
||||
#include <wayland-plasma-shell-client-protocol.h>
|
||||
#include <wayland-plasma-virtual-desktop-client-protocol.h>
|
||||
#include <wayland-plasma-window-management-client-protocol.h>
|
||||
#include <wayland-pointer-constraints-unstable-v1-client-protocol.h>
|
||||
#include <wayland-pointer-gestures-unstable-v1-client-protocol.h>
|
||||
#include <wayland-relativepointer-unstable-v1-client-protocol.h>
|
||||
#include <wayland-shadow-client-protocol.h>
|
||||
#include <wayland-slide-client-protocol.h>
|
||||
#include <wayland-text-input-v0-client-protocol.h>
|
||||
#include <wayland-text-input-v2-client-protocol.h>
|
||||
#include <wayland-xdg-decoration-unstable-v1-client-protocol.h>
|
||||
#include <wayland-xdg-foreign-unstable-v2-client-protocol.h>
|
||||
#include <wayland-xdg-output-unstable-v1-client-protocol.h>
|
||||
#include <wayland-xdg-shell-client-protocol.h>
|
||||
#include <wayland-xdg-shell-v6-client-protocol.h>
|
||||
|
||||
/*****
|
||||
* How to add another interface:
|
||||
* * define a new enum value in Registry::Interface
|
||||
* * define the bind<InterfaceName> method
|
||||
* * define the create<InterfaceName> method
|
||||
* * define the <interfaceName>Announced signal
|
||||
* * define the <interfaceName>Removed signal
|
||||
* * add a block to s_interfaces
|
||||
* * add the BIND macro for the new bind<InterfaceName>
|
||||
* * add the CREATE macro for the new create<InterfaceName>
|
||||
* * extend registry unit test to verify that it works
|
||||
****/
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct SuppertedInterfaceData {
|
||||
quint32 maxVersion;
|
||||
QByteArray name;
|
||||
const wl_interface *interface;
|
||||
void (Registry::*announcedSignal)(quint32, quint32);
|
||||
void (Registry::*removedSignal)(quint32);
|
||||
};
|
||||
// clang-format off
|
||||
static const QMap<Registry::Interface, SuppertedInterfaceData> s_interfaces = {
|
||||
{Registry::Interface::Compositor, {
|
||||
4,
|
||||
QByteArrayLiteral("wl_compositor"),
|
||||
&wl_compositor_interface,
|
||||
&Registry::compositorAnnounced,
|
||||
&Registry::compositorRemoved
|
||||
}},
|
||||
{Registry::Interface::DataDeviceManager, {
|
||||
3,
|
||||
QByteArrayLiteral("wl_data_device_manager"),
|
||||
&wl_data_device_manager_interface,
|
||||
&Registry::dataDeviceManagerAnnounced,
|
||||
&Registry::dataDeviceManagerRemoved
|
||||
}},
|
||||
{Registry::Interface::Output, {
|
||||
4,
|
||||
QByteArrayLiteral("wl_output"),
|
||||
&wl_output_interface,
|
||||
&Registry::outputAnnounced,
|
||||
&Registry::outputRemoved
|
||||
}},
|
||||
{Registry::Interface::Shm, {
|
||||
1,
|
||||
QByteArrayLiteral("wl_shm"),
|
||||
&wl_shm_interface,
|
||||
&Registry::shmAnnounced,
|
||||
&Registry::shmRemoved
|
||||
}},
|
||||
{Registry::Interface::Seat, {
|
||||
5,
|
||||
QByteArrayLiteral("wl_seat"),
|
||||
&wl_seat_interface,
|
||||
&Registry::seatAnnounced,
|
||||
&Registry::seatRemoved
|
||||
}},
|
||||
{Registry::Interface::Shell, {
|
||||
1,
|
||||
QByteArrayLiteral("wl_shell"),
|
||||
&wl_shell_interface,
|
||||
&Registry::shellAnnounced,
|
||||
&Registry::shellRemoved
|
||||
}},
|
||||
{Registry::Interface::SubCompositor, {
|
||||
1,
|
||||
QByteArrayLiteral("wl_subcompositor"),
|
||||
&wl_subcompositor_interface,
|
||||
&Registry::subCompositorAnnounced,
|
||||
&Registry::subCompositorRemoved
|
||||
}},
|
||||
{Registry::Interface::PlasmaShell, {
|
||||
8,
|
||||
QByteArrayLiteral("org_kde_plasma_shell"),
|
||||
&org_kde_plasma_shell_interface,
|
||||
&Registry::plasmaShellAnnounced,
|
||||
&Registry::plasmaShellRemoved
|
||||
}},
|
||||
{Registry::Interface::PlasmaVirtualDesktopManagement, {
|
||||
2,
|
||||
QByteArrayLiteral("org_kde_plasma_virtual_desktop_management"),
|
||||
&org_kde_plasma_virtual_desktop_management_interface,
|
||||
&Registry::plasmaVirtualDesktopManagementAnnounced,
|
||||
&Registry::plasmaVirtualDesktopManagementRemoved
|
||||
}},
|
||||
{Registry::Interface::PlasmaWindowManagement, {
|
||||
18,
|
||||
QByteArrayLiteral("org_kde_plasma_window_management"),
|
||||
&org_kde_plasma_window_management_interface,
|
||||
&Registry::plasmaWindowManagementAnnounced,
|
||||
&Registry::plasmaWindowManagementRemoved
|
||||
}},
|
||||
{Registry::Interface::FakeInput, {
|
||||
4,
|
||||
QByteArrayLiteral("org_kde_kwin_fake_input"),
|
||||
&org_kde_kwin_fake_input_interface,
|
||||
&Registry::fakeInputAnnounced,
|
||||
&Registry::fakeInputRemoved
|
||||
}},
|
||||
{Registry::Interface::Shadow, {
|
||||
2,
|
||||
QByteArrayLiteral("org_kde_kwin_shadow_manager"),
|
||||
&org_kde_kwin_shadow_manager_interface,
|
||||
&Registry::shadowAnnounced,
|
||||
&Registry::shadowRemoved
|
||||
}},
|
||||
{Registry::Interface::Blur, {
|
||||
1,
|
||||
QByteArrayLiteral("org_kde_kwin_blur_manager"),
|
||||
&org_kde_kwin_blur_manager_interface,
|
||||
&Registry::blurAnnounced,
|
||||
&Registry::blurRemoved
|
||||
}},
|
||||
{Registry::Interface::Contrast, {
|
||||
2,
|
||||
QByteArrayLiteral("org_kde_kwin_contrast_manager"),
|
||||
&org_kde_kwin_contrast_manager_interface,
|
||||
&Registry::contrastAnnounced,
|
||||
&Registry::contrastRemoved
|
||||
}},
|
||||
{Registry::Interface::Slide, {
|
||||
1,
|
||||
QByteArrayLiteral("org_kde_kwin_slide_manager"),
|
||||
&org_kde_kwin_slide_manager_interface,
|
||||
&Registry::slideAnnounced,
|
||||
&Registry::slideRemoved
|
||||
}},
|
||||
{Registry::Interface::Dpms, {
|
||||
1,
|
||||
QByteArrayLiteral("org_kde_kwin_dpms_manager"),
|
||||
&org_kde_kwin_dpms_manager_interface,
|
||||
&Registry::dpmsAnnounced,
|
||||
&Registry::dpmsRemoved
|
||||
}},
|
||||
{Registry::Interface::TextInputManagerUnstableV0, {
|
||||
1,
|
||||
QByteArrayLiteral("wl_text_input_manager"),
|
||||
&wl_text_input_manager_interface,
|
||||
&Registry::textInputManagerUnstableV0Announced,
|
||||
&Registry::textInputManagerUnstableV0Removed
|
||||
}},
|
||||
{Registry::Interface::TextInputManagerUnstableV2, {
|
||||
1,
|
||||
QByteArrayLiteral("zwp_text_input_manager_v2"),
|
||||
&zwp_text_input_manager_v2_interface,
|
||||
&Registry::textInputManagerUnstableV2Announced,
|
||||
&Registry::textInputManagerUnstableV2Removed
|
||||
}},
|
||||
{Registry::Interface::XdgShellUnstableV5, {
|
||||
1,
|
||||
QByteArrayLiteral("xdg_shell"),
|
||||
&zxdg_shell_v5_interface,
|
||||
&Registry::xdgShellUnstableV5Announced,
|
||||
&Registry::xdgShellUnstableV5Removed
|
||||
}},
|
||||
{Registry::Interface::RelativePointerManagerUnstableV1, {
|
||||
1,
|
||||
QByteArrayLiteral("zwp_relative_pointer_manager_v1"),
|
||||
&zwp_relative_pointer_manager_v1_interface,
|
||||
&Registry::relativePointerManagerUnstableV1Announced,
|
||||
&Registry::relativePointerManagerUnstableV1Removed
|
||||
}},
|
||||
{Registry::Interface::PointerGesturesUnstableV1, {
|
||||
1,
|
||||
QByteArrayLiteral("zwp_pointer_gestures_v1"),
|
||||
&zwp_pointer_gestures_v1_interface,
|
||||
&Registry::pointerGesturesUnstableV1Announced,
|
||||
&Registry::pointerGesturesUnstableV1Removed
|
||||
}},
|
||||
{Registry::Interface::PointerConstraintsUnstableV1, {
|
||||
1,
|
||||
QByteArrayLiteral("zwp_pointer_constraints_v1"),
|
||||
&zwp_pointer_constraints_v1_interface,
|
||||
&Registry::pointerConstraintsUnstableV1Announced,
|
||||
&Registry::pointerConstraintsUnstableV1Removed
|
||||
}},
|
||||
{Registry::Interface::XdgExporterUnstableV2, {
|
||||
1,
|
||||
QByteArrayLiteral("zxdg_exporter_v2"),
|
||||
&zxdg_exporter_v2_interface,
|
||||
&Registry::exporterUnstableV2Announced,
|
||||
&Registry::exporterUnstableV2Removed
|
||||
}},
|
||||
{Registry::Interface::XdgImporterUnstableV2, {
|
||||
1,
|
||||
QByteArrayLiteral("zxdg_importer_v2"),
|
||||
&zxdg_importer_v2_interface,
|
||||
&Registry::importerUnstableV2Announced,
|
||||
&Registry::importerUnstableV2Removed
|
||||
}},
|
||||
{Registry::Interface::XdgShellUnstableV6, {
|
||||
1,
|
||||
QByteArrayLiteral("zxdg_shell_v6"),
|
||||
&zxdg_shell_v6_interface,
|
||||
&Registry::xdgShellUnstableV6Announced,
|
||||
&Registry::xdgShellUnstableV6Removed
|
||||
}},
|
||||
{Registry::Interface::IdleInhibitManagerUnstableV1, {
|
||||
1,
|
||||
QByteArrayLiteral("zwp_idle_inhibit_manager_v1"),
|
||||
&zwp_idle_inhibit_manager_v1_interface,
|
||||
&Registry::idleInhibitManagerUnstableV1Announced,
|
||||
&Registry::idleInhibitManagerUnstableV1Removed
|
||||
}},
|
||||
{Registry::Interface::AppMenu, {
|
||||
1,
|
||||
QByteArrayLiteral("org_kde_kwin_appmenu_manager"),
|
||||
&org_kde_kwin_appmenu_manager_interface,
|
||||
&Registry::appMenuAnnounced,
|
||||
&Registry::appMenuRemoved
|
||||
}},
|
||||
{Registry::Interface::XdgOutputUnstableV1, {
|
||||
2,
|
||||
QByteArrayLiteral("zxdg_output_manager_v1"),
|
||||
&zxdg_output_manager_v1_interface,
|
||||
&Registry::xdgOutputAnnounced,
|
||||
&Registry::xdgOutputRemoved
|
||||
}},
|
||||
{Registry::Interface::XdgShellStable, {
|
||||
1,
|
||||
QByteArrayLiteral("xdg_wm_base"),
|
||||
&xdg_wm_base_interface,
|
||||
&Registry::xdgShellStableAnnounced,
|
||||
&Registry::xdgShellStableRemoved
|
||||
}},
|
||||
{Registry::Interface::XdgDecorationUnstableV1, {
|
||||
1,
|
||||
QByteArrayLiteral("zxdg_decoration_manager_v1"),
|
||||
&zxdg_decoration_manager_v1_interface,
|
||||
&Registry::xdgDecorationAnnounced,
|
||||
&Registry::xdgDecorationRemoved
|
||||
}},
|
||||
{Registry::Interface::PlasmaActivationFeedback, {
|
||||
1,
|
||||
QByteArrayLiteral("org_kde_plasma_activation_feedback"),
|
||||
&org_kde_plasma_activation_feedback_interface,
|
||||
&Registry::plasmaActivationFeedbackAnnounced,
|
||||
&Registry::plasmaActivationFeedbackRemoved
|
||||
}},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
static quint32 maxVersion(const Registry::Interface &interface)
|
||||
{
|
||||
auto it = s_interfaces.find(interface);
|
||||
if (it != s_interfaces.end()) {
|
||||
return it.value().maxVersion;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN Registry::Private
|
||||
{
|
||||
public:
|
||||
Private(Registry *q);
|
||||
void setup();
|
||||
bool hasInterface(Interface interface) const;
|
||||
AnnouncedInterface interface(Interface interface) const;
|
||||
QList<AnnouncedInterface> interfaces(Interface interface) const;
|
||||
Interface interfaceForName(quint32 name) const;
|
||||
template<typename T>
|
||||
T *bind(Interface interface, uint32_t name, uint32_t version) const;
|
||||
template<class T, typename WL>
|
||||
T *create(quint32 name, quint32 version, QObject *parent, WL *(Registry::*bindMethod)(uint32_t, uint32_t) const);
|
||||
|
||||
WaylandPointer<wl_registry, wl_registry_destroy> registry;
|
||||
static const struct wl_callback_listener s_callbackListener;
|
||||
WaylandPointer<wl_callback, wl_callback_destroy> callback;
|
||||
EventQueue *queue = nullptr;
|
||||
|
||||
private:
|
||||
void handleAnnounce(uint32_t name, const char *interface, uint32_t version);
|
||||
void handleRemove(uint32_t name);
|
||||
void handleGlobalSync();
|
||||
static void globalAnnounce(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version);
|
||||
static void globalRemove(void *data, struct wl_registry *registry, uint32_t name);
|
||||
static void globalSync(void *data, struct wl_callback *callback, uint32_t serial);
|
||||
|
||||
Registry *q;
|
||||
struct InterfaceData {
|
||||
Interface interface;
|
||||
uint32_t name;
|
||||
uint32_t version;
|
||||
};
|
||||
QList<InterfaceData> m_interfaces;
|
||||
static const struct wl_registry_listener s_registryListener;
|
||||
};
|
||||
|
||||
Registry::Private::Private(Registry *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void Registry::Private::setup()
|
||||
{
|
||||
wl_registry_add_listener(registry, &s_registryListener, this);
|
||||
wl_callback_add_listener(callback, &s_callbackListener, this);
|
||||
}
|
||||
|
||||
Registry::Registry(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
Registry::~Registry()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void Registry::release()
|
||||
{
|
||||
d->registry.release();
|
||||
d->callback.release();
|
||||
}
|
||||
|
||||
void Registry::destroy()
|
||||
{
|
||||
Q_EMIT registryDestroyed();
|
||||
d->registry.destroy();
|
||||
d->callback.destroy();
|
||||
}
|
||||
|
||||
void Registry::create(wl_display *display)
|
||||
{
|
||||
Q_ASSERT(display);
|
||||
Q_ASSERT(!isValid());
|
||||
d->registry.setup(wl_display_get_registry(display));
|
||||
d->callback.setup(wl_display_sync(display));
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(d->registry);
|
||||
d->queue->addProxy(d->callback);
|
||||
}
|
||||
}
|
||||
|
||||
void Registry::create(ConnectionThread *connection)
|
||||
{
|
||||
create(connection->display());
|
||||
connect(connection, &ConnectionThread::connectionDied, this, &Registry::destroy);
|
||||
}
|
||||
|
||||
void Registry::setup()
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
d->setup();
|
||||
}
|
||||
|
||||
void Registry::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
if (!queue) {
|
||||
return;
|
||||
}
|
||||
if (d->registry) {
|
||||
d->queue->addProxy(d->registry);
|
||||
}
|
||||
if (d->callback) {
|
||||
d->queue->addProxy(d->callback);
|
||||
}
|
||||
}
|
||||
|
||||
EventQueue *Registry::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
#ifndef K_DOXYGEN
|
||||
const struct wl_registry_listener Registry::Private::s_registryListener = {globalAnnounce, globalRemove};
|
||||
|
||||
const struct wl_callback_listener Registry::Private::s_callbackListener = {globalSync};
|
||||
#endif
|
||||
|
||||
void Registry::Private::globalAnnounce(void *data, wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
|
||||
{
|
||||
auto r = reinterpret_cast<Registry::Private *>(data);
|
||||
Q_ASSERT(registry == r->registry);
|
||||
r->handleAnnounce(name, interface, version);
|
||||
}
|
||||
|
||||
void Registry::Private::globalRemove(void *data, wl_registry *registry, uint32_t name)
|
||||
{
|
||||
auto r = reinterpret_cast<Registry::Private *>(data);
|
||||
Q_ASSERT(registry == r->registry);
|
||||
r->handleRemove(name);
|
||||
}
|
||||
|
||||
void Registry::Private::globalSync(void *data, wl_callback *callback, uint32_t serial)
|
||||
{
|
||||
Q_UNUSED(serial)
|
||||
auto r = reinterpret_cast<Registry::Private *>(data);
|
||||
Q_ASSERT(r->callback == callback);
|
||||
r->handleGlobalSync();
|
||||
r->callback.release();
|
||||
}
|
||||
|
||||
void Registry::Private::handleGlobalSync()
|
||||
{
|
||||
Q_EMIT q->interfacesAnnounced();
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
static Registry::Interface nameToInterface(const char *interface)
|
||||
{
|
||||
for (auto it = s_interfaces.constBegin(); it != s_interfaces.constEnd(); ++it) {
|
||||
if (qstrcmp(interface, it.value().name) == 0) {
|
||||
return it.key();
|
||||
}
|
||||
}
|
||||
return Registry::Interface::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
void Registry::Private::handleAnnounce(uint32_t name, const char *interface, uint32_t version)
|
||||
{
|
||||
Interface i = nameToInterface(interface);
|
||||
if (i == Interface::Unknown) {
|
||||
qCDebug(KWAYLAND_CLIENT) << "Unknown interface announced: " << interface << "/" << name << "/" << version;
|
||||
} else {
|
||||
qCDebug(KWAYLAND_CLIENT) << "Wayland Interface: " << interface << "/" << name << "/" << version;
|
||||
m_interfaces.append({i, name, version});
|
||||
auto it = s_interfaces.constFind(i);
|
||||
if (it != s_interfaces.end()) {
|
||||
Q_EMIT(q->*it.value().announcedSignal)(name, version);
|
||||
}
|
||||
}
|
||||
Q_EMIT q->interfaceAnnounced(QByteArray(interface), name, version);
|
||||
}
|
||||
|
||||
void Registry::Private::handleRemove(uint32_t name)
|
||||
{
|
||||
auto it = std::find_if(m_interfaces.begin(), m_interfaces.end(), [name](const InterfaceData &data) {
|
||||
return data.name == name;
|
||||
});
|
||||
if (it != m_interfaces.end()) {
|
||||
InterfaceData data = *(it);
|
||||
m_interfaces.erase(it);
|
||||
auto sit = s_interfaces.find(data.interface);
|
||||
if (sit != s_interfaces.end()) {
|
||||
Q_EMIT(q->*sit.value().removedSignal)(data.name);
|
||||
}
|
||||
}
|
||||
Q_EMIT q->interfaceRemoved(name);
|
||||
}
|
||||
|
||||
bool Registry::Private::hasInterface(Registry::Interface interface) const
|
||||
{
|
||||
auto it = std::find_if(m_interfaces.constBegin(), m_interfaces.constEnd(), [interface](const InterfaceData &data) {
|
||||
return data.interface == interface;
|
||||
});
|
||||
return it != m_interfaces.constEnd();
|
||||
}
|
||||
|
||||
QList<Registry::AnnouncedInterface> Registry::Private::interfaces(Interface interface) const
|
||||
{
|
||||
QList<Registry::AnnouncedInterface> retVal;
|
||||
for (auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) {
|
||||
const auto &data = *it;
|
||||
if (data.interface == interface) {
|
||||
retVal << AnnouncedInterface{data.name, data.version};
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
Registry::AnnouncedInterface Registry::Private::interface(Interface interface) const
|
||||
{
|
||||
const auto all = interfaces(interface);
|
||||
if (!all.isEmpty()) {
|
||||
return all.last();
|
||||
}
|
||||
return AnnouncedInterface{0, 0};
|
||||
}
|
||||
|
||||
Registry::Interface Registry::Private::interfaceForName(quint32 name) const
|
||||
{
|
||||
auto it = std::find_if(m_interfaces.constBegin(), m_interfaces.constEnd(), [name](const InterfaceData &data) {
|
||||
return data.name == name;
|
||||
});
|
||||
if (it == m_interfaces.constEnd()) {
|
||||
return Interface::Unknown;
|
||||
}
|
||||
return (*it).interface;
|
||||
}
|
||||
|
||||
bool Registry::hasInterface(Registry::Interface interface) const
|
||||
{
|
||||
return d->hasInterface(interface);
|
||||
}
|
||||
|
||||
QList<Registry::AnnouncedInterface> Registry::interfaces(Interface interface) const
|
||||
{
|
||||
return d->interfaces(interface);
|
||||
}
|
||||
|
||||
Registry::AnnouncedInterface Registry::interface(Interface interface) const
|
||||
{
|
||||
return d->interface(interface);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
#define BIND2(__NAME__, __INAME__, __WL__) \
|
||||
__WL__ *Registry::bind##__NAME__(uint32_t name, uint32_t version) const \
|
||||
{ \
|
||||
return d->bind<__WL__>(Interface::__INAME__, name, qMin(maxVersion(Interface::__INAME__), version)); \
|
||||
}
|
||||
|
||||
#define BIND(__NAME__, __WL__) BIND2(__NAME__, __NAME__, __WL__)
|
||||
// clang-format on
|
||||
|
||||
BIND(Compositor, wl_compositor)
|
||||
BIND(Output, wl_output)
|
||||
BIND(Seat, wl_seat)
|
||||
BIND(Shell, wl_shell)
|
||||
BIND(Shm, wl_shm)
|
||||
BIND(SubCompositor, wl_subcompositor)
|
||||
BIND(DataDeviceManager, wl_data_device_manager)
|
||||
BIND(PlasmaShell, org_kde_plasma_shell)
|
||||
BIND(PlasmaActivationFeedback, org_kde_plasma_activation_feedback)
|
||||
BIND(PlasmaVirtualDesktopManagement, org_kde_plasma_virtual_desktop_management)
|
||||
BIND(PlasmaWindowManagement, org_kde_plasma_window_management)
|
||||
BIND(FakeInput, org_kde_kwin_fake_input)
|
||||
BIND(TextInputManagerUnstableV0, wl_text_input_manager)
|
||||
BIND(TextInputManagerUnstableV2, zwp_text_input_manager_v2)
|
||||
BIND(XdgShellUnstableV5, xdg_shell)
|
||||
BIND(XdgShellUnstableV6, zxdg_shell_v6)
|
||||
BIND(XdgShellStable, xdg_wm_base)
|
||||
BIND(RelativePointerManagerUnstableV1, zwp_relative_pointer_manager_v1)
|
||||
BIND(PointerGesturesUnstableV1, zwp_pointer_gestures_v1)
|
||||
BIND(PointerConstraintsUnstableV1, zwp_pointer_constraints_v1)
|
||||
BIND(XdgExporterUnstableV2, zxdg_exporter_v2)
|
||||
BIND(XdgImporterUnstableV2, zxdg_importer_v2)
|
||||
BIND(IdleInhibitManagerUnstableV1, zwp_idle_inhibit_manager_v1)
|
||||
BIND2(ShadowManager, Shadow, org_kde_kwin_shadow_manager)
|
||||
BIND2(BlurManager, Blur, org_kde_kwin_blur_manager)
|
||||
BIND2(ContrastManager, Contrast, org_kde_kwin_contrast_manager)
|
||||
BIND2(SlideManager, Slide, org_kde_kwin_slide_manager)
|
||||
BIND2(DpmsManager, Dpms, org_kde_kwin_dpms_manager)
|
||||
BIND2(AppMenuManager, AppMenu, org_kde_kwin_appmenu_manager)
|
||||
BIND(XdgOutputUnstableV1, zxdg_output_manager_v1)
|
||||
BIND(XdgDecorationUnstableV1, zxdg_decoration_manager_v1)
|
||||
|
||||
#undef BIND
|
||||
#undef BIND2
|
||||
|
||||
template<class T, typename WL>
|
||||
T *Registry::Private::create(quint32 name, quint32 version, QObject *parent, WL *(Registry::*bindMethod)(uint32_t, uint32_t) const)
|
||||
{
|
||||
T *t = new T(parent);
|
||||
t->setEventQueue(queue);
|
||||
t->setup((q->*bindMethod)(name, version));
|
||||
QObject::connect(q, &Registry::interfaceRemoved, t, [t, name](quint32 removed) {
|
||||
if (name == removed) {
|
||||
Q_EMIT t->removed();
|
||||
}
|
||||
});
|
||||
QObject::connect(q, &Registry::registryDestroyed, t, &T::destroy);
|
||||
return t;
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
#define CREATE2(__NAME__, __BINDNAME__) \
|
||||
__NAME__ *Registry::create##__NAME__(quint32 name, quint32 version, QObject *parent) \
|
||||
{ \
|
||||
return d->create<__NAME__>(name, version, parent, &Registry::bind##__BINDNAME__); \
|
||||
}
|
||||
|
||||
#define CREATE(__NAME__) CREATE2(__NAME__, __NAME__)
|
||||
// clang-format on
|
||||
|
||||
CREATE(Compositor)
|
||||
CREATE(Seat)
|
||||
CREATE(Shell)
|
||||
CREATE(SubCompositor)
|
||||
CREATE(Output)
|
||||
CREATE(DataDeviceManager)
|
||||
CREATE(PlasmaShell)
|
||||
CREATE(PlasmaActivationFeedback)
|
||||
CREATE(PlasmaVirtualDesktopManagement)
|
||||
CREATE(PlasmaWindowManagement)
|
||||
CREATE(FakeInput)
|
||||
CREATE(ShadowManager)
|
||||
CREATE(BlurManager)
|
||||
CREATE(ContrastManager)
|
||||
CREATE(SlideManager)
|
||||
CREATE(DpmsManager)
|
||||
CREATE2(ShmPool, Shm)
|
||||
CREATE(AppMenuManager)
|
||||
|
||||
#undef CREATE
|
||||
#undef CREATE2
|
||||
|
||||
XdgExporter *Registry::createXdgExporter(quint32 name, quint32 version, QObject *parent)
|
||||
{
|
||||
// only V1 supported for now
|
||||
return d->create<XdgExporterUnstableV2>(name, version, parent, &Registry::bindXdgExporterUnstableV2);
|
||||
}
|
||||
|
||||
XdgImporter *Registry::createXdgImporter(quint32 name, quint32 version, QObject *parent)
|
||||
{
|
||||
// only V1 supported for now
|
||||
return d->create<XdgImporterUnstableV2>(name, version, parent, &Registry::bindXdgImporterUnstableV2);
|
||||
}
|
||||
|
||||
TextInputManager *Registry::createTextInputManager(quint32 name, quint32 version, QObject *parent)
|
||||
{
|
||||
switch (d->interfaceForName(name)) {
|
||||
case Interface::TextInputManagerUnstableV0:
|
||||
return d->create<TextInputManagerUnstableV0>(name, version, parent, &Registry::bindTextInputManagerUnstableV0);
|
||||
case Interface::TextInputManagerUnstableV2:
|
||||
return d->create<TextInputManagerUnstableV2>(name, version, parent, &Registry::bindTextInputManagerUnstableV2);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
XdgShell *Registry::createXdgShell(quint32 name, quint32 version, QObject *parent)
|
||||
{
|
||||
switch (d->interfaceForName(name)) {
|
||||
case Interface::XdgShellUnstableV5:
|
||||
return d->create<XdgShellUnstableV5>(name, version, parent, &Registry::bindXdgShellUnstableV5);
|
||||
case Interface::XdgShellUnstableV6:
|
||||
return d->create<XdgShellUnstableV6>(name, version, parent, &Registry::bindXdgShellUnstableV6);
|
||||
case Interface::XdgShellStable:
|
||||
return d->create<XdgShellStable>(name, version, parent, &Registry::bindXdgShellStable);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
RelativePointerManager *Registry::createRelativePointerManager(quint32 name, quint32 version, QObject *parent)
|
||||
{
|
||||
switch (d->interfaceForName(name)) {
|
||||
case Interface::RelativePointerManagerUnstableV1:
|
||||
return d->create<RelativePointerManager>(name, version, parent, &Registry::bindRelativePointerManagerUnstableV1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PointerGestures *Registry::createPointerGestures(quint32 name, quint32 version, QObject *parent)
|
||||
{
|
||||
switch (d->interfaceForName(name)) {
|
||||
case Interface::PointerGesturesUnstableV1:
|
||||
return d->create<PointerGestures>(name, version, parent, &Registry::bindPointerGesturesUnstableV1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
PointerConstraints *Registry::createPointerConstraints(quint32 name, quint32 version, QObject *parent)
|
||||
{
|
||||
switch (d->interfaceForName(name)) {
|
||||
case Interface::PointerConstraintsUnstableV1:
|
||||
return d->create<PointerConstraints>(name, version, parent, &Registry::bindPointerConstraintsUnstableV1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
IdleInhibitManager *Registry::createIdleInhibitManager(quint32 name, quint32 version, QObject *parent)
|
||||
{
|
||||
switch (d->interfaceForName(name)) {
|
||||
case Interface::IdleInhibitManagerUnstableV1:
|
||||
return d->create<IdleInhibitManager>(name, version, parent, &Registry::bindIdleInhibitManagerUnstableV1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
XdgOutputManager *Registry::createXdgOutputManager(quint32 name, quint32 version, QObject *parent)
|
||||
{
|
||||
switch (d->interfaceForName(name)) {
|
||||
case Interface::XdgOutputUnstableV1:
|
||||
return d->create<XdgOutputManager>(name, version, parent, &Registry::bindXdgOutputUnstableV1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
XdgDecorationManager *Registry::createXdgDecorationManager(quint32 name, quint32 version, QObject *parent)
|
||||
{
|
||||
switch (d->interfaceForName(name)) {
|
||||
case Interface::XdgDecorationUnstableV1:
|
||||
return d->create<XdgDecorationManager>(name, version, parent, &Registry::bindXdgDecorationUnstableV1);
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
static const wl_interface *wlInterface(Registry::Interface interface)
|
||||
{
|
||||
auto it = s_interfaces.find(interface);
|
||||
if (it != s_interfaces.end()) {
|
||||
return it.value().interface;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
T *Registry::Private::bind(Registry::Interface interface, uint32_t name, uint32_t version) const
|
||||
{
|
||||
auto it = std::find_if(m_interfaces.constBegin(), m_interfaces.constEnd(), [=](const InterfaceData &data) {
|
||||
return data.interface == interface && data.name == name && data.version >= version;
|
||||
});
|
||||
if (it == m_interfaces.constEnd()) {
|
||||
qCDebug(KWAYLAND_CLIENT) << "Don't have interface " << int(interface) << "with name " << name << "and minimum version" << version;
|
||||
return nullptr;
|
||||
}
|
||||
auto t = reinterpret_cast<T *>(wl_registry_bind(registry, name, wlInterface(interface), version));
|
||||
if (queue) {
|
||||
queue->addProxy(t);
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
bool Registry::isValid() const
|
||||
{
|
||||
return d->registry.isValid();
|
||||
}
|
||||
|
||||
wl_registry *Registry::registry()
|
||||
{
|
||||
return d->registry;
|
||||
}
|
||||
|
||||
Registry::operator wl_registry *() const
|
||||
{
|
||||
return d->registry;
|
||||
}
|
||||
|
||||
Registry::operator wl_registry *()
|
||||
{
|
||||
return d->registry;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_registry.cpp"
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "relativepointer.h"
|
||||
#include "event_queue.h"
|
||||
#include "pointer.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
#include <QSizeF>
|
||||
#include <wayland-relativepointer-unstable-v1-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN RelativePointerManager::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
WaylandPointer<zwp_relative_pointer_manager_v1, zwp_relative_pointer_manager_v1_destroy> relativepointermanagerunstablev1;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
RelativePointerManager::RelativePointerManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
RelativePointerManager::~RelativePointerManager()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void RelativePointerManager::setup(zwp_relative_pointer_manager_v1 *relativepointermanagerunstablev1)
|
||||
{
|
||||
Q_ASSERT(relativepointermanagerunstablev1);
|
||||
Q_ASSERT(!d->relativepointermanagerunstablev1);
|
||||
d->relativepointermanagerunstablev1.setup(relativepointermanagerunstablev1);
|
||||
}
|
||||
|
||||
void RelativePointerManager::release()
|
||||
{
|
||||
d->relativepointermanagerunstablev1.release();
|
||||
}
|
||||
|
||||
void RelativePointerManager::destroy()
|
||||
{
|
||||
d->relativepointermanagerunstablev1.destroy();
|
||||
}
|
||||
|
||||
void RelativePointerManager::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *RelativePointerManager::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
RelativePointerManager::operator zwp_relative_pointer_manager_v1 *()
|
||||
{
|
||||
return d->relativepointermanagerunstablev1;
|
||||
}
|
||||
|
||||
RelativePointerManager::operator zwp_relative_pointer_manager_v1 *() const
|
||||
{
|
||||
return d->relativepointermanagerunstablev1;
|
||||
}
|
||||
|
||||
bool RelativePointerManager::isValid() const
|
||||
{
|
||||
return d->relativepointermanagerunstablev1.isValid();
|
||||
}
|
||||
|
||||
RelativePointer *RelativePointerManager::createRelativePointer(Pointer *pointer, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
RelativePointer *p = new RelativePointer(parent);
|
||||
auto w = zwp_relative_pointer_manager_v1_get_relative_pointer(d->relativepointermanagerunstablev1, *pointer);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
p->setup(w);
|
||||
return p;
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN RelativePointer::Private
|
||||
{
|
||||
public:
|
||||
Private(RelativePointer *q);
|
||||
|
||||
void setup(zwp_relative_pointer_v1 *relativepointerunstablev1);
|
||||
|
||||
WaylandPointer<zwp_relative_pointer_v1, zwp_relative_pointer_v1_destroy> relativepointerunstablev1;
|
||||
|
||||
private:
|
||||
static void relativeMotionCallback(void *data,
|
||||
zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
|
||||
uint32_t utime_hi,
|
||||
uint32_t utime_lo,
|
||||
wl_fixed_t dx,
|
||||
wl_fixed_t dy,
|
||||
wl_fixed_t dx_unaccel,
|
||||
wl_fixed_t dy_unaccel);
|
||||
|
||||
RelativePointer *q;
|
||||
|
||||
static const zwp_relative_pointer_v1_listener s_listener;
|
||||
};
|
||||
|
||||
RelativePointer::Private::Private(RelativePointer *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
const zwp_relative_pointer_v1_listener RelativePointer::Private::s_listener = {relativeMotionCallback};
|
||||
|
||||
void RelativePointer::Private::relativeMotionCallback(void *data,
|
||||
zwp_relative_pointer_v1 *zwp_relative_pointer_v1,
|
||||
uint32_t utime_hi,
|
||||
uint32_t utime_lo,
|
||||
wl_fixed_t dx,
|
||||
wl_fixed_t dy,
|
||||
wl_fixed_t dx_unaccel,
|
||||
wl_fixed_t dy_unaccel)
|
||||
{
|
||||
auto p = reinterpret_cast<RelativePointer::Private *>(data);
|
||||
Q_ASSERT(p->relativepointerunstablev1 == zwp_relative_pointer_v1);
|
||||
const QSizeF delta(wl_fixed_to_double(dx), wl_fixed_to_double(dy));
|
||||
const QSizeF deltaNonAccel(wl_fixed_to_double(dx_unaccel), wl_fixed_to_double(dy_unaccel));
|
||||
const quint64 timestamp = quint64(utime_lo) | (quint64(utime_hi) << 32);
|
||||
Q_EMIT p->q->relativeMotion(delta, deltaNonAccel, timestamp);
|
||||
}
|
||||
|
||||
void RelativePointer::Private::setup(zwp_relative_pointer_v1 *v1)
|
||||
{
|
||||
Q_ASSERT(v1);
|
||||
Q_ASSERT(!relativepointerunstablev1);
|
||||
relativepointerunstablev1.setup(v1);
|
||||
zwp_relative_pointer_v1_add_listener(relativepointerunstablev1, &s_listener, this);
|
||||
}
|
||||
|
||||
RelativePointer::RelativePointer(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
RelativePointer::~RelativePointer()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void RelativePointer::setup(zwp_relative_pointer_v1 *relativepointerunstablev1)
|
||||
{
|
||||
d->setup(relativepointerunstablev1);
|
||||
}
|
||||
|
||||
void RelativePointer::release()
|
||||
{
|
||||
d->relativepointerunstablev1.release();
|
||||
}
|
||||
|
||||
void RelativePointer::destroy()
|
||||
{
|
||||
d->relativepointerunstablev1.destroy();
|
||||
}
|
||||
|
||||
RelativePointer::operator zwp_relative_pointer_v1 *()
|
||||
{
|
||||
return d->relativepointerunstablev1;
|
||||
}
|
||||
|
||||
RelativePointer::operator zwp_relative_pointer_v1 *() const
|
||||
{
|
||||
return d->relativepointerunstablev1;
|
||||
}
|
||||
|
||||
bool RelativePointer::isValid() const
|
||||
{
|
||||
return d->relativepointerunstablev1.isValid();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_relativepointer.cpp"
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_RELATIVEPOINTER_H
|
||||
#define KWAYLAND_CLIENT_RELATIVEPOINTER_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct zwp_relative_pointer_manager_v1;
|
||||
struct zwp_relative_pointer_v1;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Pointer;
|
||||
class RelativePointer;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the zwp_relative_pointer_manager_v1 interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the zwp_relative_pointer_manager_v1 interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the RelativePointerManager interface:
|
||||
* @code
|
||||
* RelativePointerManager *c = registry->createRelativePointerManagerUnstableV1(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the RelativePointerManager and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* RelativePointerManager *c = new RelativePointerManager;
|
||||
* c->setup(registry->RelativePointerManager(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The RelativePointerManager can be used as a drop-in replacement for any zwp_relative_pointer_manager_v1
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
* @since 5.28
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT RelativePointerManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new RelativePointerManager.
|
||||
* Note: after constructing the RelativePointerManager it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use RelativePointerManager prefer using
|
||||
* Registry::createRelativePointerManagerUnstableV1.
|
||||
**/
|
||||
explicit RelativePointerManager(QObject *parent = nullptr);
|
||||
~RelativePointerManager() override;
|
||||
|
||||
/**
|
||||
* Setup this RelativePointerManagerUnstableV1 to manage the @p relativepointermanagerunstablev1.
|
||||
* When using Registry::createRelativePointerManagerUnstableV1 there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zwp_relative_pointer_manager_v1 *relativepointermanagerunstablev1);
|
||||
/**
|
||||
* @returns @c true if managing a zwp_relative_pointer_manager_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zwp_relative_pointer_manager_v1 interface.
|
||||
* After the interface has been released the RelativePointerManagerUnstableV1 instance is no
|
||||
* longer valid and can be setup with another zwp_relative_pointer_manager_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this RelativePointerManagerUnstableV1.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zwp_relative_pointer_manager_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, relativepointermanagerunstablev1, &RelativePointerManagerUnstableV1::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating objects with this RelativePointerManagerUnstableV1.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating objects with this RelativePointerManagerUnstableV1.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Creates a RelativePointer for the given @p pointer.
|
||||
**/
|
||||
RelativePointer *createRelativePointer(Pointer *pointer, QObject *parent = nullptr);
|
||||
|
||||
operator zwp_relative_pointer_manager_v1 *();
|
||||
operator zwp_relative_pointer_manager_v1 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the RelativePointerManagerUnstableV1 got created by
|
||||
* Registry::createRelativePointerManagerUnstableV1
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Wrapper for the zwp_relative_pointer_v1 interface.
|
||||
*
|
||||
* The RelativePointer is an extension to the Pointer used for emitting
|
||||
* relative pointer events. It shares the same focus as Pointer of the same Seat
|
||||
* and will only emit events when it has focus.
|
||||
*
|
||||
* @since 5.28
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT RelativePointer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~RelativePointer() override;
|
||||
|
||||
/**
|
||||
* Setup this RelativePointerUnstableV1 to manage the @p relativepointerunstablev1.
|
||||
* When using RelativePointerManagerUnstableV1::createRelativePointerUnstableV1 there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zwp_relative_pointer_v1 *relativepointerunstablev1);
|
||||
/**
|
||||
* @returns @c true if managing a zwp_relative_pointer_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zwp_relative_pointer_v1 interface.
|
||||
* After the interface has been released the RelativePointerUnstableV1 instance is no
|
||||
* longer valid and can be setup with another zwp_relative_pointer_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this RelativePointerUnstableV1.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zwp_relative_pointer_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* RelativePointer gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
operator zwp_relative_pointer_v1 *();
|
||||
operator zwp_relative_pointer_v1 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* A relative motion event.
|
||||
*
|
||||
* A relative motion is in the same dimension as regular motion events,
|
||||
* except they do not represent an absolute position. For example,
|
||||
* moving a pointer from (x, y) to (x', y') would have the equivalent
|
||||
* relative motion (x' - x, y' - y). If a pointer motion caused the
|
||||
* absolute pointer position to be clipped by for example the edge of the
|
||||
* monitor, the relative motion is unaffected by the clipping and will
|
||||
* represent the unclipped motion.
|
||||
*
|
||||
* This signal also contains non-accelerated motion deltas (@p deltaNonAccelerated).
|
||||
* The non-accelerated delta is, when applicable, the regular pointer motion
|
||||
* delta as it was before having applied motion acceleration and other
|
||||
* transformations such as normalization.
|
||||
*
|
||||
* Note that the non-accelerated delta does not represent 'raw' events as
|
||||
* they were read from some device. Pointer motion acceleration is device-
|
||||
* and configuration-specific and non-accelerated deltas and accelerated
|
||||
* deltas may have the same value on some devices.
|
||||
*
|
||||
* Relative motions are not coupled to Pointer motion events,
|
||||
* and can be sent in combination with such events, but also independently. There may
|
||||
* also be scenarios where Pointer motion is sent, but there is no
|
||||
* relative motion. The order of an absolute and relative motion event
|
||||
* originating from the same physical motion is not guaranteed.
|
||||
*
|
||||
* @param delta Motion vector
|
||||
* @param deltaNonAccelerated non-accelerated motion vector
|
||||
* @param microseconds timestamp with microseconds granularity
|
||||
**/
|
||||
void relativeMotion(const QSizeF &delta, const QSizeF &deltaNonAccelerated, quint64 timestamp);
|
||||
|
||||
private:
|
||||
friend class RelativePointerManager;
|
||||
explicit RelativePointer(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "seat.h"
|
||||
#include "event_queue.h"
|
||||
#include "keyboard.h"
|
||||
#include "pointer.h"
|
||||
#include "touch.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN Seat::Private
|
||||
{
|
||||
public:
|
||||
Private(Seat *q);
|
||||
void resetSeat();
|
||||
void setup(wl_seat *seat);
|
||||
|
||||
WaylandPointer<wl_seat, wl_seat_destroy> seat;
|
||||
EventQueue *queue = nullptr;
|
||||
bool capabilityKeyboard = false;
|
||||
bool capabilityPointer = false;
|
||||
bool capabilityTouch = false;
|
||||
QString name;
|
||||
|
||||
private:
|
||||
void setHasKeyboard(bool has);
|
||||
void setHasPointer(bool has);
|
||||
void setHasTouch(bool has);
|
||||
void capabilitiesChanged(uint32_t capabilities);
|
||||
void setName(const QString &name);
|
||||
static void capabilitiesCallback(void *data, wl_seat *seat, uint32_t capabilities);
|
||||
static void nameCallback(void *data, wl_seat *wl_seat, const char *name);
|
||||
|
||||
Seat *q;
|
||||
static const wl_seat_listener s_listener;
|
||||
};
|
||||
|
||||
Seat::Private::Private(Seat *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void Seat::Private::setup(wl_seat *s)
|
||||
{
|
||||
Q_ASSERT(s);
|
||||
Q_ASSERT(!seat);
|
||||
seat.setup(s);
|
||||
wl_seat_add_listener(seat, &s_listener, this);
|
||||
}
|
||||
|
||||
const wl_seat_listener Seat::Private::s_listener = {capabilitiesCallback, nameCallback};
|
||||
|
||||
Seat::Seat(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
Seat::~Seat()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void Seat::release()
|
||||
{
|
||||
if (!d->seat) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT interfaceAboutToBeReleased();
|
||||
d->seat.release();
|
||||
d->resetSeat();
|
||||
}
|
||||
|
||||
void Seat::destroy()
|
||||
{
|
||||
if (!d->seat) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT interfaceAboutToBeDestroyed();
|
||||
d->seat.destroy();
|
||||
d->resetSeat();
|
||||
}
|
||||
|
||||
void Seat::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *Seat::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
void Seat::Private::resetSeat()
|
||||
{
|
||||
setHasKeyboard(false);
|
||||
setHasPointer(false);
|
||||
setHasTouch(false);
|
||||
setName(QString());
|
||||
}
|
||||
|
||||
void Seat::Private::setHasKeyboard(bool has)
|
||||
{
|
||||
if (capabilityKeyboard == has) {
|
||||
return;
|
||||
}
|
||||
capabilityKeyboard = has;
|
||||
Q_EMIT q->hasKeyboardChanged(capabilityKeyboard);
|
||||
}
|
||||
|
||||
void Seat::Private::setHasPointer(bool has)
|
||||
{
|
||||
if (capabilityPointer == has) {
|
||||
return;
|
||||
}
|
||||
capabilityPointer = has;
|
||||
Q_EMIT q->hasPointerChanged(capabilityPointer);
|
||||
}
|
||||
|
||||
void Seat::Private::setHasTouch(bool has)
|
||||
{
|
||||
if (capabilityTouch == has) {
|
||||
return;
|
||||
}
|
||||
capabilityTouch = has;
|
||||
Q_EMIT q->hasTouchChanged(capabilityTouch);
|
||||
}
|
||||
|
||||
void Seat::setup(wl_seat *seat)
|
||||
{
|
||||
d->setup(seat);
|
||||
}
|
||||
|
||||
void Seat::Private::capabilitiesCallback(void *data, wl_seat *seat, uint32_t capabilities)
|
||||
{
|
||||
auto s = reinterpret_cast<Seat::Private *>(data);
|
||||
Q_ASSERT(s->seat == seat);
|
||||
s->capabilitiesChanged(capabilities);
|
||||
}
|
||||
|
||||
void Seat::Private::nameCallback(void *data, wl_seat *seat, const char *name)
|
||||
{
|
||||
auto s = reinterpret_cast<Seat::Private *>(data);
|
||||
Q_ASSERT(s->seat == seat);
|
||||
s->setName(QString::fromUtf8(name));
|
||||
}
|
||||
|
||||
void Seat::Private::capabilitiesChanged(uint32_t capabilities)
|
||||
{
|
||||
setHasKeyboard(capabilities & WL_SEAT_CAPABILITY_KEYBOARD);
|
||||
setHasPointer(capabilities & WL_SEAT_CAPABILITY_POINTER);
|
||||
setHasTouch(capabilities & WL_SEAT_CAPABILITY_TOUCH);
|
||||
}
|
||||
|
||||
Keyboard *Seat::createKeyboard(QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Q_ASSERT(d->capabilityKeyboard);
|
||||
Keyboard *k = new Keyboard(parent);
|
||||
connect(this, &Seat::interfaceAboutToBeReleased, k, &Keyboard::release);
|
||||
connect(this, &Seat::interfaceAboutToBeDestroyed, k, &Keyboard::destroy);
|
||||
auto w = wl_seat_get_keyboard(d->seat);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
k->setup(w);
|
||||
return k;
|
||||
}
|
||||
|
||||
Pointer *Seat::createPointer(QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Q_ASSERT(d->capabilityPointer);
|
||||
Pointer *p = new Pointer(parent);
|
||||
connect(this, &Seat::interfaceAboutToBeReleased, p, &Pointer::release);
|
||||
connect(this, &Seat::interfaceAboutToBeDestroyed, p, &Pointer::destroy);
|
||||
auto w = wl_seat_get_pointer(d->seat);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
p->setup(w);
|
||||
return p;
|
||||
}
|
||||
|
||||
Touch *Seat::createTouch(QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Q_ASSERT(d->capabilityTouch);
|
||||
Touch *t = new Touch(parent);
|
||||
connect(this, &Seat::interfaceAboutToBeReleased, t, &Touch::release);
|
||||
connect(this, &Seat::interfaceAboutToBeDestroyed, t, &Touch::destroy);
|
||||
auto w = wl_seat_get_touch(d->seat);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
t->setup(w);
|
||||
return t;
|
||||
}
|
||||
|
||||
void Seat::Private::setName(const QString &n)
|
||||
{
|
||||
if (name == n) {
|
||||
return;
|
||||
}
|
||||
name = n;
|
||||
Q_EMIT q->nameChanged(name);
|
||||
}
|
||||
|
||||
bool Seat::isValid() const
|
||||
{
|
||||
return d->seat.isValid();
|
||||
}
|
||||
|
||||
bool Seat::hasKeyboard() const
|
||||
{
|
||||
return d->capabilityKeyboard;
|
||||
}
|
||||
|
||||
bool Seat::hasPointer() const
|
||||
{
|
||||
return d->capabilityPointer;
|
||||
}
|
||||
|
||||
bool Seat::hasTouch() const
|
||||
{
|
||||
return d->capabilityTouch;
|
||||
}
|
||||
|
||||
QString Seat::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
Seat::operator wl_seat *()
|
||||
{
|
||||
return d->seat;
|
||||
}
|
||||
|
||||
Seat::operator wl_seat *() const
|
||||
{
|
||||
return d->seat;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_seat.cpp"
|
||||
@@ -0,0 +1,191 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_SEAT_H
|
||||
#define WAYLAND_SEAT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_seat;
|
||||
struct wl_touch;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Keyboard;
|
||||
class Pointer;
|
||||
class Touch;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the wl_seat interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the wl_seat interface.
|
||||
* It's main purpose is to provide the interfaces for Keyboard, Pointer and Touch.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the Seat interface:
|
||||
* @code
|
||||
* Seat *s = registry->createSeat(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the Seat and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* Seat *s = new Seat;
|
||||
* s->setup(registry->bindSeat(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The Seat can be used as a drop-in replacement for any wl_seat
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
* @see Keyboard
|
||||
* @see Pointer
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Seat : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
/**
|
||||
* The seat has pointer devices. Default value is @c false.
|
||||
**/
|
||||
Q_PROPERTY(bool keyboard READ hasKeyboard NOTIFY hasKeyboardChanged)
|
||||
/**
|
||||
* The seat has pointer devices. Default value is @c false.
|
||||
**/
|
||||
Q_PROPERTY(bool pointer READ hasPointer NOTIFY hasPointerChanged)
|
||||
/**
|
||||
* The seat has touch devices. Default value is @c false.
|
||||
**/
|
||||
Q_PROPERTY(bool touch READ hasTouch NOTIFY hasTouchChanged)
|
||||
/**
|
||||
* In a multiseat configuration this can be used by the client to help identify
|
||||
* which physical devices the seat represents.
|
||||
* Based on the seat configuration used by the compositor.
|
||||
**/
|
||||
Q_PROPERTY(QString name READ name NOTIFY nameChanged)
|
||||
public:
|
||||
explicit Seat(QObject *parent = nullptr);
|
||||
~Seat() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a wl_seat.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this Seat to manage the @p seat.
|
||||
* When using Registry::createSeat there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_seat *seat);
|
||||
/**
|
||||
* Releases the wl_seat interface.
|
||||
* After the interface has been released the Seat instance is no
|
||||
* longer valid and can be setup with another wl_seat interface.
|
||||
*
|
||||
* Right before the interface is released the signal interfaceAboutToBeReleased is emitted.
|
||||
* @see interfaceAboutToBeReleased
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this Seat.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_shell interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* Seat gets destroyed.
|
||||
*
|
||||
* Right before the data is destroyed the signal interfaceAboutToBeDestroyed is emitted.
|
||||
*
|
||||
* @see release
|
||||
* @see interfaceAboutToBeDestroyed
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating Keyboard, Pointer and Touch.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating Keyboard, Pointer and Touch.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
bool hasKeyboard() const;
|
||||
bool hasPointer() const;
|
||||
bool hasTouch() const;
|
||||
QString name() const;
|
||||
operator wl_seat *();
|
||||
operator wl_seat *() const;
|
||||
|
||||
/**
|
||||
* Creates a Keyboard.
|
||||
*
|
||||
* This method may only be called if the Seat has a keyboard.
|
||||
*
|
||||
* @param parent The parent to pass to the created Keyboard.
|
||||
* @returns The created Keyboard.
|
||||
**/
|
||||
Keyboard *createKeyboard(QObject *parent = nullptr);
|
||||
/**
|
||||
* Creates a Pointer.
|
||||
*
|
||||
* This method may only be called if the Seat has a pointer.
|
||||
*
|
||||
* @param parent The parent to pass to the created Pointer.
|
||||
* @returns The created Pointer.
|
||||
**/
|
||||
Pointer *createPointer(QObject *parent = nullptr);
|
||||
/**
|
||||
* Creates a Touch.
|
||||
*
|
||||
* This method may only be called if the Seat has touch support.
|
||||
*
|
||||
* @param parent The parent to pass to the created Touch.
|
||||
* @returns The created Touch.
|
||||
**/
|
||||
Touch *createTouch(QObject *parent = nullptr);
|
||||
|
||||
Q_SIGNALS:
|
||||
void hasKeyboardChanged(bool);
|
||||
void hasPointerChanged(bool);
|
||||
void hasTouchChanged(bool);
|
||||
void nameChanged(const QString &name);
|
||||
|
||||
/**
|
||||
* This signal is emitted right before the interface is going to be released.
|
||||
**/
|
||||
void interfaceAboutToBeReleased();
|
||||
/**
|
||||
* This signal is emitted right before the data is going to be destroyed.
|
||||
**/
|
||||
void interfaceAboutToBeDestroyed();
|
||||
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the Compositor got created by
|
||||
* Registry::createSeat
|
||||
*
|
||||
* @since 5.5
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "shadow.h"
|
||||
#include "event_queue.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <QMarginsF>
|
||||
|
||||
#include <wayland-shadow-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN ShadowManager::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
WaylandPointer<org_kde_kwin_shadow_manager, org_kde_kwin_shadow_manager_destroy> manager;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
ShadowManager::ShadowManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
ShadowManager::~ShadowManager()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void ShadowManager::release()
|
||||
{
|
||||
d->manager.release();
|
||||
}
|
||||
|
||||
void ShadowManager::destroy()
|
||||
{
|
||||
d->manager.destroy();
|
||||
}
|
||||
|
||||
bool ShadowManager::isValid() const
|
||||
{
|
||||
return d->manager.isValid();
|
||||
}
|
||||
|
||||
void ShadowManager::setup(org_kde_kwin_shadow_manager *manager)
|
||||
{
|
||||
Q_ASSERT(manager);
|
||||
Q_ASSERT(!d->manager);
|
||||
d->manager.setup(manager);
|
||||
}
|
||||
|
||||
void ShadowManager::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *ShadowManager::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
Shadow *ShadowManager::createShadow(Surface *surface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Shadow *s = new Shadow(parent);
|
||||
auto w = org_kde_kwin_shadow_manager_create(d->manager, *surface);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
s->setup(w);
|
||||
return s;
|
||||
}
|
||||
|
||||
void ShadowManager::removeShadow(Surface *surface)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
org_kde_kwin_shadow_manager_unset(d->manager, *surface);
|
||||
}
|
||||
|
||||
ShadowManager::operator org_kde_kwin_shadow_manager *()
|
||||
{
|
||||
return d->manager;
|
||||
}
|
||||
|
||||
ShadowManager::operator org_kde_kwin_shadow_manager *() const
|
||||
{
|
||||
return d->manager;
|
||||
}
|
||||
|
||||
class Shadow::Private
|
||||
{
|
||||
public:
|
||||
WaylandPointer<org_kde_kwin_shadow, org_kde_kwin_shadow_destroy> shadow;
|
||||
};
|
||||
|
||||
Shadow::Shadow(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
Shadow::~Shadow()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void Shadow::release()
|
||||
{
|
||||
d->shadow.release();
|
||||
}
|
||||
|
||||
void Shadow::setup(org_kde_kwin_shadow *shadow)
|
||||
{
|
||||
Q_ASSERT(shadow);
|
||||
Q_ASSERT(!d->shadow);
|
||||
d->shadow.setup(shadow);
|
||||
}
|
||||
|
||||
void Shadow::destroy()
|
||||
{
|
||||
d->shadow.destroy();
|
||||
}
|
||||
|
||||
bool Shadow::isValid() const
|
||||
{
|
||||
return d->shadow.isValid();
|
||||
}
|
||||
|
||||
void Shadow::setOffsets(const QMarginsF &margins)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
org_kde_kwin_shadow_set_left_offset(d->shadow, wl_fixed_from_double(margins.left()));
|
||||
org_kde_kwin_shadow_set_top_offset(d->shadow, wl_fixed_from_double(margins.top()));
|
||||
org_kde_kwin_shadow_set_right_offset(d->shadow, wl_fixed_from_double(margins.right()));
|
||||
org_kde_kwin_shadow_set_bottom_offset(d->shadow, wl_fixed_from_double(margins.bottom()));
|
||||
}
|
||||
|
||||
void Shadow::commit()
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
org_kde_kwin_shadow_commit(d->shadow);
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
#ifndef K_DOXYGEN
|
||||
#define attach( __PART__, __WAYLAND_PART__ ) \
|
||||
void Shadow::attach##__PART__(wl_buffer *buffer) \
|
||||
{ \
|
||||
Q_ASSERT(isValid()); \
|
||||
org_kde_kwin_shadow_attach_##__WAYLAND_PART__(d->shadow, buffer); \
|
||||
} \
|
||||
void Shadow::attach##__PART__(Buffer *buffer) \
|
||||
{ \
|
||||
if (!buffer) {\
|
||||
return;\
|
||||
}\
|
||||
attach##__PART__(buffer->buffer()); \
|
||||
} \
|
||||
void Shadow::attach##__PART__(Buffer::Ptr buffer) \
|
||||
{ \
|
||||
attach##__PART__(buffer.toStrongRef().data()); \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
attach(Left, left) attach(TopLeft, top_left) attach(Top, top) attach(TopRight, top_right) attach(Right, right) attach(BottomRight, bottom_right)
|
||||
attach(Bottom, bottom) attach(BottomLeft, bottom_left)
|
||||
|
||||
#undef attach
|
||||
#endif
|
||||
|
||||
Shadow::operator org_kde_kwin_shadow *()
|
||||
{
|
||||
return d->shadow;
|
||||
}
|
||||
|
||||
Shadow::operator org_kde_kwin_shadow *() const
|
||||
{
|
||||
return d->shadow;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_shadow.cpp"
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_SHADOW_H
|
||||
#define KWAYLAND_SHADOW_H
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QPoint>
|
||||
#include <QSize>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_buffer;
|
||||
struct org_kde_kwin_shadow;
|
||||
struct org_kde_kwin_shadow_manager;
|
||||
|
||||
class QMarginsF;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Shadow;
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the org_kde_kwin_shadow_manager interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the org_kde_kwin_shadow_manager interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the ShadowManager interface:
|
||||
* @code
|
||||
* ShadowManager *s = registry->createShadowManager(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the ShadowManager and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* ShadowManager *s = new ShadowManager;
|
||||
* s->setup(registry->bindShadowManager(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The ShadowManager can be used as a drop-in replacement for any org_kde_kwin_shadow_manager
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
* @since 5.4
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT ShadowManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new ShadowManager.
|
||||
* Note: after constructing the ShadowManager it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use ShadowManager prefer using
|
||||
* Registry::createShadowManager.
|
||||
**/
|
||||
explicit ShadowManager(QObject *parent = nullptr);
|
||||
~ShadowManager() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_kwin_shadow_manager.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this ShadowManager to manage the @p compositor.
|
||||
* When using Registry::createShadowManager there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_kwin_shadow_manager *compositor);
|
||||
/**
|
||||
* Releases the org_kde_kwin_shadow_manager interface.
|
||||
* After the interface has been released the ShadowManager instance is no
|
||||
* longer valid and can be setup with another org_kde_kwin_shadow_manager interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this ShadowManager.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_kwin_shadow_manager interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* Shadow gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating a Shadow.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating a Shadow.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Creates and setup a new Shadow with @p parent.
|
||||
* @param parent The parent to pass to the Shadow.
|
||||
* @returns The new created Shadow
|
||||
**/
|
||||
Shadow *createShadow(Surface *surface, QObject *parent = nullptr);
|
||||
void removeShadow(Surface *surface);
|
||||
|
||||
operator org_kde_kwin_shadow_manager *();
|
||||
operator org_kde_kwin_shadow_manager *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the Compositor got created by
|
||||
* Registry::createShadowManager
|
||||
*
|
||||
* @since 5.5
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Wrapper for the org_kde_kwin_shadow interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the org_kde_kwin_shadow interface.
|
||||
* To create a Shadow call Compositor::createShadow.
|
||||
*
|
||||
* The main purpose of this class is to setup the next frame which
|
||||
* should be rendered. Therefore it provides methods to add damage
|
||||
* and to attach a new Buffer and to finalize the frame by calling
|
||||
* commit.
|
||||
*
|
||||
* @see Compositor
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Shadow : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~Shadow() override;
|
||||
|
||||
/**
|
||||
* Setup this Shadow to manage the @p shadow.
|
||||
* When using Compositor::createSurface there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_kwin_shadow *shadow);
|
||||
/**
|
||||
* Releases the org_kde_kwin_shadow interface.
|
||||
* After the interface has been released the Shadow instance is no
|
||||
* longer valid and can be setup with another org_kde_kwin_shadow interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this Shadow.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_kwin_shadow interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, shadow, &Shadow::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_kwin_shadow.
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
void commit();
|
||||
void attachLeft(wl_buffer *buffer);
|
||||
void attachLeft(Buffer *buffer);
|
||||
void attachLeft(Buffer::Ptr buffer);
|
||||
void attachTopLeft(wl_buffer *buffer);
|
||||
void attachTopLeft(Buffer *buffer);
|
||||
void attachTopLeft(Buffer::Ptr buffer);
|
||||
void attachTop(wl_buffer *buffer);
|
||||
void attachTop(Buffer *buffer);
|
||||
void attachTop(Buffer::Ptr buffer);
|
||||
void attachTopRight(wl_buffer *buffer);
|
||||
void attachTopRight(Buffer *buffer);
|
||||
void attachTopRight(Buffer::Ptr buffer);
|
||||
void attachRight(wl_buffer *buffer);
|
||||
void attachRight(Buffer *buffer);
|
||||
void attachRight(Buffer::Ptr buffer);
|
||||
void attachBottomRight(wl_buffer *buffer);
|
||||
void attachBottomRight(Buffer *buffer);
|
||||
void attachBottomRight(Buffer::Ptr buffer);
|
||||
void attachBottom(wl_buffer *buffer);
|
||||
void attachBottom(Buffer *buffer);
|
||||
void attachBottom(Buffer::Ptr buffer);
|
||||
void attachBottomLeft(wl_buffer *buffer);
|
||||
void attachBottomLeft(Buffer *buffer);
|
||||
void attachBottomLeft(Buffer::Ptr buffer);
|
||||
void setOffsets(const QMarginsF &margins);
|
||||
|
||||
operator org_kde_kwin_shadow *();
|
||||
operator org_kde_kwin_shadow *() const;
|
||||
|
||||
private:
|
||||
friend class ShadowManager;
|
||||
explicit Shadow(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,377 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "shell.h"
|
||||
#include "event_queue.h"
|
||||
#include "output.h"
|
||||
#include "seat.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Qt
|
||||
#include <QGuiApplication>
|
||||
#include <QList>
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
// Wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN Shell::Private
|
||||
{
|
||||
public:
|
||||
WaylandPointer<wl_shell, wl_shell_destroy> shell;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
Shell::Shell(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
Shell::~Shell()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void Shell::destroy()
|
||||
{
|
||||
if (!d->shell) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT interfaceAboutToBeDestroyed();
|
||||
d->shell.destroy();
|
||||
}
|
||||
|
||||
void Shell::release()
|
||||
{
|
||||
if (!d->shell) {
|
||||
return;
|
||||
}
|
||||
Q_EMIT interfaceAboutToBeReleased();
|
||||
d->shell.release();
|
||||
}
|
||||
|
||||
void Shell::setup(wl_shell *shell)
|
||||
{
|
||||
Q_ASSERT(!d->shell);
|
||||
Q_ASSERT(shell);
|
||||
d->shell.setup(shell);
|
||||
}
|
||||
|
||||
void Shell::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *Shell::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
ShellSurface *Shell::createSurface(wl_surface *surface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
ShellSurface *s = new ShellSurface(parent);
|
||||
connect(this, &Shell::interfaceAboutToBeReleased, s, &ShellSurface::release);
|
||||
connect(this, &Shell::interfaceAboutToBeDestroyed, s, &ShellSurface::destroy);
|
||||
auto w = wl_shell_get_shell_surface(d->shell, surface);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
s->setup(w);
|
||||
return s;
|
||||
}
|
||||
|
||||
ShellSurface *Shell::createSurface(Surface *surface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(surface);
|
||||
return createSurface(*surface, parent);
|
||||
}
|
||||
|
||||
bool Shell::isValid() const
|
||||
{
|
||||
return d->shell.isValid();
|
||||
}
|
||||
|
||||
Shell::operator wl_shell *()
|
||||
{
|
||||
return d->shell;
|
||||
}
|
||||
|
||||
Shell::operator wl_shell *() const
|
||||
{
|
||||
return d->shell;
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN ShellSurface::Private
|
||||
{
|
||||
public:
|
||||
Private(ShellSurface *q);
|
||||
void setup(wl_shell_surface *surface);
|
||||
|
||||
WaylandPointer<wl_shell_surface, wl_shell_surface_destroy> surface;
|
||||
QSize size;
|
||||
static QList<ShellSurface *> s_surfaces;
|
||||
|
||||
private:
|
||||
void ping(uint32_t serial);
|
||||
static void pingCallback(void *data, struct wl_shell_surface *shellSurface, uint32_t serial);
|
||||
static void configureCallback(void *data, struct wl_shell_surface *shellSurface, uint32_t edges, int32_t width, int32_t height);
|
||||
static void popupDoneCallback(void *data, struct wl_shell_surface *shellSurface);
|
||||
|
||||
ShellSurface *q;
|
||||
static const struct wl_shell_surface_listener s_listener;
|
||||
};
|
||||
|
||||
QList<ShellSurface *> ShellSurface::Private::s_surfaces = QList<ShellSurface *>();
|
||||
|
||||
ShellSurface::Private::Private(ShellSurface *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void ShellSurface::Private::setup(wl_shell_surface *s)
|
||||
{
|
||||
Q_ASSERT(s);
|
||||
Q_ASSERT(!surface);
|
||||
surface.setup(s);
|
||||
wl_shell_surface_add_listener(surface, &s_listener, this);
|
||||
}
|
||||
|
||||
ShellSurface *ShellSurface::fromWindow(QWindow *window)
|
||||
{
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native) {
|
||||
return nullptr;
|
||||
}
|
||||
window->create();
|
||||
wl_shell_surface *s = reinterpret_cast<wl_shell_surface *>(native->nativeResourceForWindow(QByteArrayLiteral("wl_shell_surface"), window));
|
||||
if (!s) {
|
||||
return nullptr;
|
||||
}
|
||||
if (auto surface = get(s)) {
|
||||
return surface;
|
||||
}
|
||||
ShellSurface *surface = new ShellSurface(window);
|
||||
surface->d->surface.setup(s, true);
|
||||
return surface;
|
||||
}
|
||||
|
||||
ShellSurface *ShellSurface::fromQtWinId(WId wid)
|
||||
{
|
||||
QWindow *window = nullptr;
|
||||
|
||||
for (auto win : qApp->allWindows()) {
|
||||
if (win->winId() == wid) {
|
||||
window = win;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
return fromWindow(window);
|
||||
}
|
||||
|
||||
ShellSurface *ShellSurface::get(wl_shell_surface *native)
|
||||
{
|
||||
auto it = std::find_if(Private::s_surfaces.constBegin(), Private::s_surfaces.constEnd(), [native](ShellSurface *s) {
|
||||
return s->d->surface == native;
|
||||
});
|
||||
if (it != Private::s_surfaces.constEnd()) {
|
||||
return *(it);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ShellSurface::ShellSurface(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
Private::s_surfaces << this;
|
||||
}
|
||||
|
||||
ShellSurface::~ShellSurface()
|
||||
{
|
||||
Private::s_surfaces.removeOne(this);
|
||||
release();
|
||||
}
|
||||
|
||||
void ShellSurface::release()
|
||||
{
|
||||
d->surface.release();
|
||||
}
|
||||
|
||||
void ShellSurface::destroy()
|
||||
{
|
||||
d->surface.destroy();
|
||||
}
|
||||
|
||||
#ifndef K_DOXYGEN
|
||||
const struct wl_shell_surface_listener ShellSurface::Private::s_listener = {pingCallback, configureCallback, popupDoneCallback};
|
||||
#endif
|
||||
|
||||
void ShellSurface::Private::configureCallback(void *data, wl_shell_surface *shellSurface, uint32_t edges, int32_t width, int32_t height)
|
||||
{
|
||||
Q_UNUSED(edges)
|
||||
auto s = reinterpret_cast<ShellSurface::Private *>(data);
|
||||
Q_ASSERT(s->surface == shellSurface);
|
||||
s->q->setSize(QSize(width, height));
|
||||
}
|
||||
|
||||
void ShellSurface::Private::pingCallback(void *data, wl_shell_surface *shellSurface, uint32_t serial)
|
||||
{
|
||||
auto s = reinterpret_cast<ShellSurface::Private *>(data);
|
||||
Q_ASSERT(s->surface == shellSurface);
|
||||
s->ping(serial);
|
||||
}
|
||||
|
||||
void ShellSurface::Private::popupDoneCallback(void *data, wl_shell_surface *shellSurface)
|
||||
{
|
||||
auto s = reinterpret_cast<ShellSurface::Private *>(data);
|
||||
Q_ASSERT(s->surface == shellSurface);
|
||||
Q_EMIT s->q->popupDone();
|
||||
}
|
||||
|
||||
void ShellSurface::setup(wl_shell_surface *surface)
|
||||
{
|
||||
d->setup(surface);
|
||||
}
|
||||
|
||||
void ShellSurface::Private::ping(uint32_t serial)
|
||||
{
|
||||
wl_shell_surface_pong(surface, serial);
|
||||
Q_EMIT q->pinged();
|
||||
}
|
||||
|
||||
void ShellSurface::setSize(const QSize &size)
|
||||
{
|
||||
if (d->size == size) {
|
||||
return;
|
||||
}
|
||||
d->size = size;
|
||||
Q_EMIT sizeChanged(size);
|
||||
}
|
||||
|
||||
void ShellSurface::setFullscreen(Output *output)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
wl_shell_surface_set_fullscreen(d->surface, WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT, 0, output ? output->output() : nullptr);
|
||||
}
|
||||
|
||||
void ShellSurface::setMaximized(Output *output)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
wl_shell_surface_set_maximized(d->surface, output ? output->output() : nullptr);
|
||||
}
|
||||
|
||||
void ShellSurface::setToplevel()
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
wl_shell_surface_set_toplevel(d->surface);
|
||||
}
|
||||
|
||||
void ShellSurface::setTransient(Surface *parent, const QPoint &offset, TransientFlags flags)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
uint32_t wlFlags = 0;
|
||||
if (flags.testFlag(TransientFlag::NoFocus)) {
|
||||
wlFlags |= WL_SHELL_SURFACE_TRANSIENT_INACTIVE;
|
||||
}
|
||||
wl_shell_surface_set_transient(d->surface, *parent, offset.x(), offset.y(), wlFlags);
|
||||
}
|
||||
|
||||
void ShellSurface::setTransientPopup(Surface *parent, Seat *grabbedSeat, quint32 grabSerial, const QPoint &offset, TransientFlags flags)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Q_ASSERT(parent);
|
||||
Q_ASSERT(grabbedSeat);
|
||||
uint32_t wlFlags = 0;
|
||||
if (flags.testFlag(TransientFlag::NoFocus)) {
|
||||
wlFlags |= WL_SHELL_SURFACE_TRANSIENT_INACTIVE;
|
||||
}
|
||||
wl_shell_surface_set_popup(d->surface, *grabbedSeat, grabSerial, *parent, offset.x(), offset.y(), wlFlags);
|
||||
}
|
||||
|
||||
void ShellSurface::requestMove(Seat *seat, quint32 serial)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Q_ASSERT(seat);
|
||||
|
||||
wl_shell_surface_move(d->surface, *seat, serial);
|
||||
}
|
||||
|
||||
void ShellSurface::requestResize(Seat *seat, quint32 serial, Qt::Edges edges)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Q_ASSERT(seat);
|
||||
|
||||
uint wlEdge = WL_SHELL_SURFACE_RESIZE_NONE;
|
||||
if (edges.testFlag(Qt::TopEdge)) {
|
||||
if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::TopEdge)) {
|
||||
wlEdge = WL_SHELL_SURFACE_RESIZE_TOP_LEFT;
|
||||
} else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::TopEdge)) {
|
||||
wlEdge = WL_SHELL_SURFACE_RESIZE_TOP_RIGHT;
|
||||
} else if ((edges & ~Qt::TopEdge) == Qt::Edges()) {
|
||||
wlEdge = WL_SHELL_SURFACE_RESIZE_TOP;
|
||||
}
|
||||
} else if (edges.testFlag(Qt::BottomEdge)) {
|
||||
if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::BottomEdge)) {
|
||||
wlEdge = WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT;
|
||||
} else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::BottomEdge)) {
|
||||
wlEdge = WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT;
|
||||
} else if ((edges & ~Qt::BottomEdge) == Qt::Edges()) {
|
||||
wlEdge = WL_SHELL_SURFACE_RESIZE_BOTTOM;
|
||||
}
|
||||
} else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::Edges())) {
|
||||
wlEdge = WL_SHELL_SURFACE_RESIZE_RIGHT;
|
||||
} else if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::Edges())) {
|
||||
wlEdge = WL_SHELL_SURFACE_RESIZE_LEFT;
|
||||
}
|
||||
|
||||
wl_shell_surface_resize(d->surface, *seat, serial, wlEdge);
|
||||
}
|
||||
|
||||
void ShellSurface::setTitle(const QString &title)
|
||||
{
|
||||
wl_shell_surface_set_title(d->surface, title.toUtf8().constData());
|
||||
}
|
||||
|
||||
void ShellSurface::setWindowClass(const QByteArray &windowClass)
|
||||
{
|
||||
wl_shell_surface_set_class(d->surface, windowClass.constData());
|
||||
}
|
||||
|
||||
QSize ShellSurface::size() const
|
||||
{
|
||||
return d->size;
|
||||
}
|
||||
|
||||
bool ShellSurface::isValid() const
|
||||
{
|
||||
return d->surface.isValid();
|
||||
}
|
||||
|
||||
ShellSurface::operator wl_shell_surface *()
|
||||
{
|
||||
return d->surface;
|
||||
}
|
||||
|
||||
ShellSurface::operator wl_shell_surface *() const
|
||||
{
|
||||
return d->surface;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_shell.cpp"
|
||||
@@ -0,0 +1,359 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_SHELL_H
|
||||
#define WAYLAND_SHELL_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QPoint>
|
||||
#include <QSize>
|
||||
#include <QWindow>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_surface;
|
||||
struct wl_shell;
|
||||
struct wl_shell_surface;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class ShellSurface;
|
||||
class Output;
|
||||
class Seat;
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the wl_shell interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the wl_shell interface.
|
||||
* It's main purpose is to create a ShellSurface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the Shell interface:
|
||||
* @code
|
||||
* Shell *s = registry->createShell(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the Shell and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* Shell *s = new Shell;
|
||||
* s->setup(registry->bindShell(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The Shell can be used as a drop-in replacement for any wl_shell
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
* @see ShellSurface
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Shell : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Shell(QObject *parent = nullptr);
|
||||
~Shell() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a wl_shell.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the wl_shell interface.
|
||||
* After the interface has been released the Shell instance is no
|
||||
* longer valid and can be setup with another wl_shell interface.
|
||||
*
|
||||
* Right before the interface is released the signal interfaceAboutToBeReleased is emitted.
|
||||
* @see interfaceAboutToBeReleased
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this Shell.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. Once the connection becomes invalid, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_shell interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, shell, &Shell::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* Right before the data is destroyed, the signal interfaceAboutToBeDestroyed is emitted.
|
||||
*
|
||||
* @see release
|
||||
* @see interfaceAboutToBeDestroyed
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* Setup this Shell to manage the @p shell.
|
||||
* When using Registry::createShell there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_shell *shell);
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating a Surface.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating a Surface.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Creates a ShellSurface for the given @p surface and sets it up.
|
||||
*
|
||||
* @param surface The native surface to create the ShellSurface for
|
||||
* @param parent The parent to use for the ShellSurface
|
||||
* @returns created ShellSurface
|
||||
**/
|
||||
ShellSurface *createSurface(wl_surface *surface, QObject *parent = nullptr);
|
||||
/**
|
||||
* Creates a ShellSurface for the given @p surface and sets it up.
|
||||
*
|
||||
* @param surface The Surface to create the ShellSurface for
|
||||
* @param parent The parent to use for the ShellSurface
|
||||
* @returns created ShellSurface
|
||||
**/
|
||||
ShellSurface *createSurface(Surface *surface, QObject *parent = nullptr);
|
||||
|
||||
operator wl_shell *();
|
||||
operator wl_shell *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* This signal is emitted right before the interface is released.
|
||||
**/
|
||||
void interfaceAboutToBeReleased();
|
||||
/**
|
||||
* This signal is emitted right before the data is destroyed.
|
||||
**/
|
||||
void interfaceAboutToBeDestroyed();
|
||||
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the Compositor got created by
|
||||
* Registry::createShell
|
||||
*
|
||||
* @since 5.5
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Wrapper for the wl_shell_surface interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the wl_shell_surface interface.
|
||||
*
|
||||
* To create an instance use Shell::createSurface.
|
||||
*
|
||||
* @see Shell
|
||||
* @see Surface
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT ShellSurface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
/**
|
||||
* The size of the ShellSurface.
|
||||
**/
|
||||
Q_PROPERTY(QSize size READ size WRITE setSize NOTIFY sizeChanged)
|
||||
public:
|
||||
explicit ShellSurface(QObject *parent);
|
||||
~ShellSurface() override;
|
||||
|
||||
/**
|
||||
* Releases the wl_shell_surface interface.
|
||||
* After the interface has been released the ShellSurface instance is no
|
||||
* longer valid and can be setup with another wl_shell_surface interface.
|
||||
*
|
||||
* This method is automatically invoked when the Shell which created this
|
||||
* ShellSurface gets released.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this ShellSurface.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_shell_surface interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Shell which created this
|
||||
* ShellSurface gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* Setup this ShellSurface to manage the @p surface.
|
||||
* There is normally no need to call this method as it's invoked by
|
||||
* Shell::createSurface.
|
||||
**/
|
||||
void setup(wl_shell_surface *surface);
|
||||
QSize size() const;
|
||||
void setSize(const QSize &size);
|
||||
|
||||
/**
|
||||
* Sets the ShellSurface fullscreen on @p output.
|
||||
**/
|
||||
void setFullscreen(Output *output = nullptr);
|
||||
void setMaximized(Output *output = nullptr);
|
||||
void setToplevel();
|
||||
/**
|
||||
* Flags which can be passed to a transient surface.
|
||||
* @see setTransient
|
||||
* @since 5.5
|
||||
**/
|
||||
enum class TransientFlag {
|
||||
Default = 0x0, ///< Default: transient surface accepts keyboard focus
|
||||
NoFocus = 0x1, ///< Transient surface does not accept keyboard focus
|
||||
};
|
||||
Q_DECLARE_FLAGS(TransientFlags, TransientFlag)
|
||||
/**
|
||||
* Sets this Surface as a transient for @p parent.
|
||||
*
|
||||
* @param parent The parent Surface of this surface
|
||||
* @param offset The offset of this Surface in the parent coordinate system
|
||||
* @param flags The flags for the transient
|
||||
* @since 5.5
|
||||
**/
|
||||
void setTransient(Surface *parent, const QPoint &offset = QPoint(), TransientFlags flags = TransientFlag::Default);
|
||||
|
||||
/**
|
||||
* Sets this Surface as a popup transient for @p parent.
|
||||
*
|
||||
* A popup is a transient with an added pointer grab on the @p grabbedSeat.
|
||||
*
|
||||
* The popup grab can be created if the client has an implicit grab (e.g. button press)
|
||||
* on the @p grabbedSeat. It needs to pass the @p grabSerial indicating the implicit grab
|
||||
* to the request for setting the surface. The implicit grab is turned into a popup grab
|
||||
* which will persist after the implicit grab ends. The popup grab ends when the ShellSurface
|
||||
* gets destroyed or when the compositor breaks the grab through the {@link popupDone} signal.
|
||||
*
|
||||
* @param parent The parent Surface of this ShellSurface
|
||||
* @param grabbedSeat The Seat on which an implicit grab exists
|
||||
* @param grabSerial The serial of the implicit grab
|
||||
* @param offset The offset of this Surface in the parent coordinate system
|
||||
* @param flags The flags for the transient
|
||||
* @since 5.33
|
||||
**/
|
||||
void
|
||||
setTransientPopup(Surface *parent, Seat *grabbedSeat, quint32 grabSerial, const QPoint &offset = QPoint(), TransientFlags flags = TransientFlag::Default);
|
||||
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* Requests a move on the given @p seat after the pointer button press with the given @p serial.
|
||||
*
|
||||
* @param seat The seat on which to move the window
|
||||
* @param serial The serial of the pointer button press which should trigger the move
|
||||
* @since 5.5
|
||||
**/
|
||||
void requestMove(Seat *seat, quint32 serial);
|
||||
|
||||
/**
|
||||
* Requests a resize on the given @p seat after the pointer button press with the given @p serial.
|
||||
*
|
||||
* @param seat The seat on which to resize the window
|
||||
* @param serial The serial of the pointer button press which should trigger the resize
|
||||
* @param edges A hint for the compositor to set e.g. an appropriate cursor image
|
||||
* @since 5.5
|
||||
**/
|
||||
void requestResize(Seat *seat, quint32 serial, Qt::Edges edges);
|
||||
|
||||
/**
|
||||
* Sets a short title for the surface.
|
||||
*
|
||||
* This string may be used to identify the surface in a task bar, window list, or other user
|
||||
* interface elements provided by the compositor.
|
||||
*
|
||||
* @since 5.55
|
||||
**/
|
||||
void setTitle(const QString &title);
|
||||
|
||||
/**
|
||||
* Sets a window class for the surface.
|
||||
*
|
||||
* The surface class identifies the general class of applications to which the surface belongs.
|
||||
* A common convention is to use the file name (or the full path if it is a non-standard location)
|
||||
* of the application's .desktop file as the class.
|
||||
*
|
||||
* @since 5.55
|
||||
**/
|
||||
void setWindowClass(const QByteArray &windowClass);
|
||||
|
||||
/**
|
||||
* Creates a ShellSurface for the given @p window.
|
||||
* This is an integration feature for QtWayland. On non-wayland platforms this method returns
|
||||
* @c nullptr as well as for not created QWindows.
|
||||
*
|
||||
* The returned ShellSurface will be fully setup, but won't be released. It gets automatically
|
||||
* destroyed together with the @p window.
|
||||
* @since 5.28
|
||||
**/
|
||||
static ShellSurface *fromWindow(QWindow *window);
|
||||
|
||||
/**
|
||||
* Creates a ShellSurface for the given @p winId.
|
||||
* This is an integration feature for QtWayland. On non-wayland platforms this method returns
|
||||
* @c nullptr as well as for not created QWindows.
|
||||
*
|
||||
* The returned ShellSurface will be fully setup, but won't be released. It gets automatically
|
||||
* destroyed together with the QWindow corresponding
|
||||
* the @p wid.
|
||||
* @since 5.28
|
||||
**/
|
||||
static ShellSurface *fromQtWinId(WId wid);
|
||||
|
||||
/**
|
||||
* @returns The Surface referencing the @p native wl_surface or @c null if there is no such Surface.
|
||||
* @since 5.28
|
||||
**/
|
||||
static ShellSurface *get(wl_shell_surface *native);
|
||||
|
||||
operator wl_shell_surface *();
|
||||
operator wl_shell_surface *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Signal is emitted when the ShellSurface received a ping request.
|
||||
* The ShellSurface automatically responds to the ping.
|
||||
**/
|
||||
void pinged();
|
||||
void sizeChanged(const QSize &);
|
||||
|
||||
/**
|
||||
* The popupDone signal is sent out when a popup grab is broken, that is,
|
||||
* when the user clicks a surface that doesn't belong to the client owning
|
||||
* the popup surface.
|
||||
* @see setTransientPopup
|
||||
* @since 5.33
|
||||
**/
|
||||
void popupDone();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWayland::Client::ShellSurface::TransientFlag)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::ShellSurface::TransientFlags)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,301 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2013 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "shm_pool.h"
|
||||
#include "buffer_p.h"
|
||||
#include "event_queue.h"
|
||||
#include "logging.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Qt
|
||||
#include <QDebug>
|
||||
#include <QImage>
|
||||
// system
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
// wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN ShmPool::Private
|
||||
{
|
||||
public:
|
||||
Private(ShmPool *q);
|
||||
bool createPool();
|
||||
bool resizePool(int32_t newSize);
|
||||
QList<QSharedPointer<Buffer>>::iterator getBuffer(const QSize &size, int32_t stride, Buffer::Format format);
|
||||
WaylandPointer<wl_shm, wl_shm_destroy> shm;
|
||||
WaylandPointer<wl_shm_pool, wl_shm_pool_destroy> pool;
|
||||
void *poolData = nullptr;
|
||||
int fd = -1;
|
||||
int32_t size = 1024;
|
||||
bool valid = false;
|
||||
int offset = 0;
|
||||
QList<QSharedPointer<Buffer>> buffers;
|
||||
EventQueue *queue = nullptr;
|
||||
|
||||
private:
|
||||
ShmPool *q;
|
||||
};
|
||||
|
||||
ShmPool::Private::Private(ShmPool *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
ShmPool::ShmPool(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
ShmPool::~ShmPool()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void ShmPool::release()
|
||||
{
|
||||
d->buffers.clear();
|
||||
if (d->poolData) {
|
||||
munmap(d->poolData, d->size);
|
||||
d->poolData = nullptr;
|
||||
}
|
||||
if (d->fd != -1) {
|
||||
close(d->fd);
|
||||
d->fd = -1;
|
||||
}
|
||||
d->pool.release();
|
||||
d->shm.release();
|
||||
d->valid = false;
|
||||
d->offset = 0;
|
||||
}
|
||||
|
||||
void ShmPool::destroy()
|
||||
{
|
||||
for (auto b : d->buffers) {
|
||||
b->d->destroy();
|
||||
}
|
||||
d->buffers.clear();
|
||||
if (d->poolData) {
|
||||
munmap(d->poolData, d->size);
|
||||
d->poolData = nullptr;
|
||||
}
|
||||
if (d->fd != -1) {
|
||||
close(d->fd);
|
||||
d->fd = -1;
|
||||
}
|
||||
d->pool.destroy();
|
||||
d->shm.destroy();
|
||||
d->valid = false;
|
||||
d->offset = 0;
|
||||
}
|
||||
|
||||
void ShmPool::setup(wl_shm *shm)
|
||||
{
|
||||
Q_ASSERT(shm);
|
||||
Q_ASSERT(!d->shm);
|
||||
d->shm.setup(shm);
|
||||
d->valid = d->createPool();
|
||||
}
|
||||
|
||||
void ShmPool::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *ShmPool::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
bool ShmPool::Private::createPool()
|
||||
{
|
||||
#if HAVE_MEMFD
|
||||
fd = memfd_create("kwayland-shared", MFD_CLOEXEC | MFD_ALLOW_SEALING);
|
||||
if (fd >= 0) {
|
||||
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
char templateName[] = "/tmp/kwayland-shared-XXXXXX";
|
||||
fd = mkstemp(templateName);
|
||||
if (fd >= 0) {
|
||||
unlink(templateName);
|
||||
|
||||
int flags = fcntl(fd, F_GETFD);
|
||||
if (flags == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (fd == -1) {
|
||||
qCDebug(KWAYLAND_CLIENT) << "Could not open temporary file for Shm pool";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ftruncate(fd, size) < 0) {
|
||||
qCDebug(KWAYLAND_CLIENT) << "Could not set size for Shm pool file";
|
||||
return false;
|
||||
}
|
||||
poolData = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
pool.setup(wl_shm_create_pool(shm, fd, size));
|
||||
|
||||
if (poolData == MAP_FAILED || !pool) {
|
||||
qCDebug(KWAYLAND_CLIENT) << "Creating Shm pool failed";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShmPool::Private::resizePool(int32_t newSize)
|
||||
{
|
||||
if (ftruncate(fd, newSize) < 0) {
|
||||
qCDebug(KWAYLAND_CLIENT) << "Could not set new size for Shm pool file";
|
||||
return false;
|
||||
}
|
||||
wl_shm_pool_resize(pool, newSize);
|
||||
munmap(poolData, size);
|
||||
poolData = mmap(nullptr, newSize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
|
||||
size = newSize;
|
||||
if (poolData == MAP_FAILED) {
|
||||
qCDebug(KWAYLAND_CLIENT) << "Resizing Shm pool failed";
|
||||
return false;
|
||||
}
|
||||
Q_EMIT q->poolResized();
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
static Buffer::Format toBufferFormat(const QImage &image)
|
||||
{
|
||||
switch (image.format()) {
|
||||
case QImage::Format_ARGB32_Premultiplied:
|
||||
return Buffer::Format::ARGB32;
|
||||
case QImage::Format_RGB32:
|
||||
return Buffer::Format::RGB32;
|
||||
case QImage::Format_ARGB32:
|
||||
qCWarning(KWAYLAND_CLIENT) << "Unsupported image format: " << image.format() << ". expect slow performance. Use QImage::Format_ARGB32_Premultiplied";
|
||||
return Buffer::Format::ARGB32;
|
||||
default:
|
||||
qCWarning(KWAYLAND_CLIENT) << "Unsupported image format: " << image.format() << ". expect slow performance.";
|
||||
return Buffer::Format::ARGB32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Buffer::Ptr ShmPool::createBuffer(const QImage &image)
|
||||
{
|
||||
if (image.isNull() || !d->valid) {
|
||||
return QWeakPointer<Buffer>();
|
||||
}
|
||||
auto format = toBufferFormat(image);
|
||||
auto it = d->getBuffer(image.size(), image.bytesPerLine(), format);
|
||||
if (it == d->buffers.end()) {
|
||||
return QWeakPointer<Buffer>();
|
||||
}
|
||||
if (format == Buffer::Format::ARGB32 && image.format() != QImage::Format_ARGB32_Premultiplied) {
|
||||
auto imageCopy = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
|
||||
(*it)->copy(imageCopy.bits());
|
||||
} else {
|
||||
(*it)->copy(image.bits());
|
||||
}
|
||||
return QWeakPointer<Buffer>(*it);
|
||||
}
|
||||
|
||||
Buffer::Ptr ShmPool::createBuffer(const QSize &size, int32_t stride, const void *src, Buffer::Format format)
|
||||
{
|
||||
if (size.isEmpty() || !d->valid) {
|
||||
return QWeakPointer<Buffer>();
|
||||
}
|
||||
auto it = d->getBuffer(size, stride, format);
|
||||
if (it == d->buffers.end()) {
|
||||
return QWeakPointer<Buffer>();
|
||||
}
|
||||
(*it)->copy(src);
|
||||
return QWeakPointer<Buffer>(*it);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
static wl_shm_format toWaylandFormat(Buffer::Format format)
|
||||
{
|
||||
switch (format) {
|
||||
case Buffer::Format::ARGB32:
|
||||
return WL_SHM_FORMAT_ARGB8888;
|
||||
case Buffer::Format::RGB32:
|
||||
return WL_SHM_FORMAT_XRGB8888;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
Buffer::Ptr ShmPool::getBuffer(const QSize &size, int32_t stride, Buffer::Format format)
|
||||
{
|
||||
auto it = d->getBuffer(size, stride, format);
|
||||
if (it == d->buffers.end()) {
|
||||
return QWeakPointer<Buffer>();
|
||||
}
|
||||
return QWeakPointer<Buffer>(*it);
|
||||
}
|
||||
|
||||
QList<QSharedPointer<Buffer>>::iterator ShmPool::Private::getBuffer(const QSize &s, int32_t stride, Buffer::Format format)
|
||||
{
|
||||
for (auto it = buffers.begin(); it != buffers.end(); ++it) {
|
||||
auto buffer = *it;
|
||||
if (!buffer->isReleased() || buffer->isUsed()) {
|
||||
continue;
|
||||
}
|
||||
if (buffer->size() != s || buffer->stride() != stride || buffer->format() != format) {
|
||||
continue;
|
||||
}
|
||||
buffer->setReleased(false);
|
||||
return it;
|
||||
}
|
||||
const int32_t byteCount = s.height() * stride;
|
||||
if (offset + byteCount > size) {
|
||||
if (!resizePool(size + byteCount)) {
|
||||
return buffers.end();
|
||||
}
|
||||
}
|
||||
// we don't have a buffer which we could reuse - need to create a new one
|
||||
wl_buffer *native = wl_shm_pool_create_buffer(pool, offset, s.width(), s.height(), stride, toWaylandFormat(format));
|
||||
if (!native) {
|
||||
return buffers.end();
|
||||
}
|
||||
if (queue) {
|
||||
queue->addProxy(native);
|
||||
}
|
||||
Buffer *buffer = new Buffer(q, native, s, stride, offset, format);
|
||||
offset += byteCount;
|
||||
auto it = buffers.insert(buffers.end(), QSharedPointer<Buffer>(buffer));
|
||||
return it;
|
||||
}
|
||||
|
||||
bool ShmPool::isValid() const
|
||||
{
|
||||
return d->valid;
|
||||
}
|
||||
|
||||
void *ShmPool::poolAddress() const
|
||||
{
|
||||
return d->poolData;
|
||||
}
|
||||
|
||||
wl_shm *ShmPool::shm()
|
||||
{
|
||||
return d->shm;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_shm_pool.cpp"
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_SHM_POOL_H
|
||||
#define WAYLAND_SHM_POOL_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
#include "buffer.h"
|
||||
|
||||
class QImage;
|
||||
class QSize;
|
||||
|
||||
struct wl_shm;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
|
||||
/**
|
||||
* @short Wrapper class for wl_shm interface.
|
||||
*
|
||||
* This class holds a shared memory pool together with the Wayland server.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create a ShmPool instance:
|
||||
* @code
|
||||
* ShmPool *s = registry->createShmPool(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the ShmPool and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* ShmPool *s = new ShmPool;
|
||||
* s->setup(registry->bindShm(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The ShmPool holds a memory-mapped file from which it provides Buffers.
|
||||
* All Buffers are held by the ShmPool and can be reused. Whenever a Buffer
|
||||
* is requested the ShmPool tries to reuse an existing Buffer. A Buffer can
|
||||
* be reused if the following conditions hold
|
||||
* @li it's no longer marked as used
|
||||
* @li the server released the buffer
|
||||
* @li the size matches
|
||||
* @li the stride matches
|
||||
* @li the format matches
|
||||
*
|
||||
* The ownership of a Buffer stays with ShmPool. The ShmPool might destroy the
|
||||
* Buffer at any given time. Because of that ShmPool only provides QWeakPointer
|
||||
* for Buffers. Users should always check whether the pointer is still valid and
|
||||
* only promote to a QSharedPointer for a short time, e.g. to set new data.
|
||||
*
|
||||
* The ShmPool can provide Buffers for different purposes. One can create a Buffer
|
||||
* from an existing QImage. This will use a Buffer with same size, stride and image
|
||||
* format as the QImage and <b>copy</b> the content of the QImage into the Buffer.
|
||||
* The memory is <b>not</b> shared:
|
||||
* @code
|
||||
* QImage image(24, 24, QImage::Format_ARG32);
|
||||
* image.fill(Qt::transparent);
|
||||
* Buffer::Ptr buffer = s->createBuffer(image);
|
||||
* @endcode
|
||||
*
|
||||
* It is also possible to create a Buffer and copy the content from a generic location.
|
||||
* Like above this doesn't share the content but copies it:
|
||||
* @code
|
||||
* QImage image(24, 24, QImage::Format_ARG32);
|
||||
* image.fill(Qt::transparent);
|
||||
* Buffer::Ptr buffer = s->createBuffer(image.size(), image.bytesPerLine(), image.constBits());
|
||||
* @endcode
|
||||
*
|
||||
* Last but not least it is possible to get a Buffer without copying content directly to it.
|
||||
* This means an empty area is just reserved and can be used to e.g. share the memory with a
|
||||
* QImage:
|
||||
* @code
|
||||
* const QSize size = QSize(24, 24);
|
||||
* const int stride = size.width() * 4;
|
||||
* Buffer::Ptr buffer = s->getBuffer(size, stride, Buffer::Format::RGB32);
|
||||
* if (!buffer) {
|
||||
* qDebug() << "Didn't get a valid Buffer";
|
||||
* return;
|
||||
* }
|
||||
* QImage image(buffer.toStrongRef()->address(), size.width(), size.height(), stride, QImage::Format_RGB32);
|
||||
* image.fill(Qt::black);
|
||||
* @endcode
|
||||
*
|
||||
* A Buffer can be attached to a Surface:
|
||||
* @code
|
||||
* Compositor *c = registry.createCompositor(name, version);
|
||||
* Surface *s = c->createSurface();
|
||||
* s->attachBuffer(buffer);
|
||||
* s->damage(QRect(QPoint(0, 0), size));
|
||||
* @endcode
|
||||
*
|
||||
* Once a Buffer is attached to a Surface and the Surface is committed, it might be released
|
||||
* by the Wayland server and thus is free to be reused again. If the client code wants to
|
||||
* continue using the Buffer it must call Buffer::setUsed on it. This is important if the memory
|
||||
* is shared for example with a QImage as the memory buffer for a QImage must remain valid
|
||||
* throughout the life time of the QImage:
|
||||
* @code
|
||||
* buffer.toStrongRef()->setUsed(true);
|
||||
* @endcode
|
||||
*
|
||||
* This is also important for the case that the shared memory pool needs to be resized.
|
||||
* The ShmPool will automatically resize if it cannot provide a new Buffer. During the resize
|
||||
* all existing Buffers are unmapped and any shared objects must be recreated. The ShmPool emits
|
||||
* the signal poolResized() after the pool got resized.
|
||||
*
|
||||
* @see Buffer
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT ShmPool : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ShmPool(QObject *parent = nullptr);
|
||||
~ShmPool() override;
|
||||
/**
|
||||
* @returns @c true if the ShmPool references a wl_shm interface and the shared memory pool
|
||||
* is setup.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this ShmPool to manage the @p shm.
|
||||
* This also creates the shared memory pool.
|
||||
* When using Registry::createShmPool there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_shm *shm);
|
||||
/**
|
||||
* Releases the wl_shm interface.
|
||||
* After the interface has been released the ShmPool instance is no
|
||||
* longer valid and can be setup with another wl_shm interface.
|
||||
*
|
||||
* This also destroys the shared memory pool and all Buffers are destroyed.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this ShmPool.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_shm interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* All Buffers are destroyed!
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* ShmPool gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating a Buffer.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating a Buffer.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Provides a Buffer with:
|
||||
* @li same size as @p image
|
||||
* @li same stride as @p image
|
||||
* @li same format as @p image
|
||||
*
|
||||
* If the ShmPool fails to provide such a Buffer a @c null Buffer::Ptr is returned.
|
||||
* The content of the @p image is <b>copied</b> into the buffer. The @p image and
|
||||
* returned Buffer do <b>not</b> share memory.
|
||||
*
|
||||
* @param image The image which should be copied into the Buffer
|
||||
* @return Buffer with copied content of @p image in success case, a @c null Buffer::Ptr otherwise
|
||||
* @see getBuffer
|
||||
**/
|
||||
Buffer::Ptr createBuffer(const QImage &image);
|
||||
/**
|
||||
* Provides a Buffer with @p size, @p stride and @p format.
|
||||
*
|
||||
* If the ShmPool fails to provide such a Buffer a @c null Buffer::Ptr is returned.
|
||||
* A memory copy is performed from @p src into the Buffer. The Buffer does <b>not</b> share
|
||||
* memory with @p src.
|
||||
*
|
||||
* @param size The requested size for the Buffer
|
||||
* @param stride The requested stride for the Buffer
|
||||
* @param src The source memory location to copy from
|
||||
* @param format The requested format for the Buffer
|
||||
* @return Buffer with copied content of @p src in success case, a @c null Buffer::Ptr otherwise
|
||||
* @see getBuffer
|
||||
**/
|
||||
Buffer::Ptr createBuffer(const QSize &size, int32_t stride, const void *src, Buffer::Format format = Buffer::Format::ARGB32);
|
||||
void *poolAddress() const;
|
||||
/**
|
||||
* Provides a Buffer with @p size, @p stride and @p format.
|
||||
*
|
||||
* If the ShmPool fails to provide such a Buffer a @c null Buffer::Ptr is returned.
|
||||
* Unlike with createBuffer there is no memory copy performed. This provides a bare Buffer
|
||||
* to be used by the user.
|
||||
*
|
||||
* @param size The requested size for the Buffer
|
||||
* @param stride The requested stride for the Buffer
|
||||
* @param format The requested format for the Buffer
|
||||
* @return Buffer as requested in success case, a @c null Buffer::Ptr otherwise.
|
||||
* @see createBuffer
|
||||
**/
|
||||
Buffer::Ptr getBuffer(const QSize &size, int32_t stride, Buffer::Format format = Buffer::Format::ARGB32);
|
||||
wl_shm *shm();
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* This signal is emitted whenever the shared memory pool gets resized.
|
||||
* Any used Buffer must be remapped.
|
||||
**/
|
||||
void poolResized();
|
||||
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the Compositor got created by
|
||||
* Registry::createShmPool
|
||||
*
|
||||
* @since 5.5
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "slide.h"
|
||||
#include "event_queue.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <wayland-slide-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN SlideManager::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
WaylandPointer<org_kde_kwin_slide_manager, org_kde_kwin_slide_manager_destroy> slidemanager;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
SlideManager::SlideManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
SlideManager::~SlideManager()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void SlideManager::setup(org_kde_kwin_slide_manager *slidemanager)
|
||||
{
|
||||
Q_ASSERT(slidemanager);
|
||||
Q_ASSERT(!d->slidemanager);
|
||||
d->slidemanager.setup(slidemanager);
|
||||
}
|
||||
|
||||
void SlideManager::release()
|
||||
{
|
||||
d->slidemanager.release();
|
||||
}
|
||||
|
||||
void SlideManager::destroy()
|
||||
{
|
||||
d->slidemanager.destroy();
|
||||
}
|
||||
|
||||
void SlideManager::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *SlideManager::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
SlideManager::operator org_kde_kwin_slide_manager *()
|
||||
{
|
||||
return d->slidemanager;
|
||||
}
|
||||
|
||||
SlideManager::operator org_kde_kwin_slide_manager *() const
|
||||
{
|
||||
return d->slidemanager;
|
||||
}
|
||||
|
||||
bool SlideManager::isValid() const
|
||||
{
|
||||
return d->slidemanager.isValid();
|
||||
}
|
||||
|
||||
Slide *SlideManager::createSlide(Surface *surface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
Slide *s = new Slide(parent);
|
||||
auto w = org_kde_kwin_slide_manager_create(d->slidemanager, *surface);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
s->setup(w);
|
||||
return s;
|
||||
}
|
||||
|
||||
void SlideManager::removeSlide(Surface *surface)
|
||||
{
|
||||
org_kde_kwin_slide_manager_unset(d->slidemanager, *surface);
|
||||
}
|
||||
|
||||
class Slide::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
WaylandPointer<org_kde_kwin_slide, org_kde_kwin_slide_release> slide;
|
||||
};
|
||||
|
||||
Slide::Slide(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
Slide::~Slide()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void Slide::setup(org_kde_kwin_slide *slide)
|
||||
{
|
||||
Q_ASSERT(slide);
|
||||
Q_ASSERT(!d->slide);
|
||||
d->slide.setup(slide);
|
||||
}
|
||||
|
||||
void Slide::release()
|
||||
{
|
||||
d->slide.release();
|
||||
}
|
||||
|
||||
void Slide::destroy()
|
||||
{
|
||||
d->slide.destroy();
|
||||
}
|
||||
|
||||
Slide::operator org_kde_kwin_slide *()
|
||||
{
|
||||
return d->slide;
|
||||
}
|
||||
|
||||
Slide::operator org_kde_kwin_slide *() const
|
||||
{
|
||||
return d->slide;
|
||||
}
|
||||
|
||||
bool Slide::isValid() const
|
||||
{
|
||||
return d->slide.isValid();
|
||||
}
|
||||
|
||||
void Slide::commit()
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
org_kde_kwin_slide_commit(d->slide);
|
||||
}
|
||||
|
||||
void Slide::setLocation(Slide::Location location)
|
||||
{
|
||||
org_kde_kwin_slide_set_location(d->slide, location);
|
||||
}
|
||||
|
||||
void Slide::setOffset(qint32 offset)
|
||||
{
|
||||
org_kde_kwin_slide_set_offset(d->slide, offset);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_slide.cpp"
|
||||
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Marco Martin <notmart@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_SLIDE_H
|
||||
#define KWAYLAND_CLIENT_SLIDE_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct org_kde_kwin_slide_manager;
|
||||
struct org_kde_kwin_slide;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Slide;
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the org_kde_kwin_slide_manager interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the org_kde_kwin_slide_manager interface.
|
||||
*
|
||||
* Ask the compositor to move the surface from a location
|
||||
* to another with a slide animation.
|
||||
*
|
||||
* The from argument provides a clue about where the slide
|
||||
* animation begins, offset is the distance from screen
|
||||
* edge to begin the animation.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the SlideManager interface:
|
||||
* @code
|
||||
* SlideManager *c = registry->createSlideManager(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the SlideManager and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* SlideManager *c = new SlideManager;
|
||||
* c->setup(registry->bindSlideManager(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The SlideManager can be used as a drop-in replacement for any org_kde_kwin_slide_manager
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT SlideManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new SlideManager.
|
||||
* Note: after constructing the SlideManager it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use SlideManager prefer using
|
||||
* Registry::createSlideManager.
|
||||
**/
|
||||
explicit SlideManager(QObject *parent = nullptr);
|
||||
~SlideManager() override;
|
||||
|
||||
/**
|
||||
* Setup this SlideManager to manage the @p slidemanager.
|
||||
* When using Registry::createSlideManager there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_kwin_slide_manager *slidemanager);
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_kwin_slide_manager.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the org_kde_kwin_slide_manager interface.
|
||||
* After the interface has been released the SlideManager instance is no
|
||||
* longer valid and can be setup with another org_kde_kwin_slide_manager interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this SlideManager.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_kwin_slide_manager interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* SlideManager gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating objects with this SlideManager.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating objects with this SlideManager.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
Slide *createSlide(Surface *surface, QObject *parent = nullptr);
|
||||
|
||||
void removeSlide(Surface *surface);
|
||||
|
||||
operator org_kde_kwin_slide_manager *();
|
||||
operator org_kde_kwin_slide_manager *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the SlideManager got created by
|
||||
* Registry::createSlideManager
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
class KWAYLANDCLIENT_EXPORT Slide : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Location {
|
||||
Left = 0, /**< Slide from the left edge of the screen */
|
||||
Top, /**< Slide from the top edge of the screen */
|
||||
Right, /**< Slide from the bottom edge of the screen */
|
||||
Bottom, /**< Slide from the bottom edge of the screen */
|
||||
};
|
||||
|
||||
~Slide() override;
|
||||
|
||||
/**
|
||||
* Setup this Slide to manage the @p slide.
|
||||
* When using SlideManager::createSlide there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(org_kde_kwin_slide *slide);
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a org_kde_kwin_slide.
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* Releases the org_kde_kwin_slide interface.
|
||||
* After the interface has been released the Slide instance is no
|
||||
* longer valid and can be setup with another org_kde_kwin_slide interface.
|
||||
**/
|
||||
void release();
|
||||
|
||||
/**
|
||||
* Destroys the data held by this Slide.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new org_kde_kwin_slide interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, slide, &Slide::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
void commit();
|
||||
|
||||
/**
|
||||
* Set the location of the screen to slide the window from
|
||||
*/
|
||||
void setLocation(Slide::Location location);
|
||||
|
||||
/**
|
||||
* Set the offset from the screen edge
|
||||
* to make the window slide from
|
||||
*/
|
||||
void setOffset(qint32 offset);
|
||||
|
||||
operator org_kde_kwin_slide *();
|
||||
operator org_kde_kwin_slide *() const;
|
||||
|
||||
private:
|
||||
friend class SlideManager;
|
||||
explicit Slide(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "subcompositor.h"
|
||||
#include "event_queue.h"
|
||||
#include "subsurface.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN SubCompositor::Private
|
||||
{
|
||||
public:
|
||||
WaylandPointer<wl_subcompositor, wl_subcompositor_destroy> subCompositor;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
SubCompositor::SubCompositor(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
SubCompositor::~SubCompositor()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void SubCompositor::release()
|
||||
{
|
||||
d->subCompositor.release();
|
||||
}
|
||||
|
||||
void SubCompositor::destroy()
|
||||
{
|
||||
d->subCompositor.destroy();
|
||||
}
|
||||
|
||||
void SubCompositor::setup(wl_subcompositor *subcompositor)
|
||||
{
|
||||
Q_ASSERT(subcompositor);
|
||||
Q_ASSERT(!d->subCompositor.isValid());
|
||||
d->subCompositor.setup(subcompositor);
|
||||
}
|
||||
|
||||
SubSurface *SubCompositor::createSubSurface(QPointer<Surface> surface, QPointer<Surface> parentSurface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
SubSurface *s = new SubSurface(surface, parentSurface, parent);
|
||||
auto w = wl_subcompositor_get_subsurface(d->subCompositor, *surface, *parentSurface);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
s->setup(w);
|
||||
return s;
|
||||
}
|
||||
|
||||
bool SubCompositor::isValid() const
|
||||
{
|
||||
return d->subCompositor.isValid();
|
||||
}
|
||||
|
||||
SubCompositor::operator wl_subcompositor *()
|
||||
{
|
||||
return d->subCompositor;
|
||||
}
|
||||
|
||||
SubCompositor::operator wl_subcompositor *() const
|
||||
{
|
||||
return d->subCompositor;
|
||||
}
|
||||
|
||||
EventQueue *SubCompositor::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
void SubCompositor::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_subcompositor.cpp"
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_SUBCOMPOSITOR_H
|
||||
#define WAYLAND_SUBCOMPOSITOR_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_subcompositor;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class SubSurface;
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the wl_subcompositor interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the wl_subcompositor interface.
|
||||
* The main purpose of this class is to create SubSurfaces.
|
||||
*
|
||||
* To create an instance use Registry::createSubCompositor.
|
||||
*
|
||||
* @see Registry
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT SubCompositor : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SubCompositor(QObject *parent = nullptr);
|
||||
~SubCompositor() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a wl_subcompositor.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this SubCompositor to manage the @p subcompositor.
|
||||
* When using Registry::createSubCompositor there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_subcompositor *subcompositor);
|
||||
/**
|
||||
* Releases the wl_subcompositor interface.
|
||||
* After the interface has been released the SubCompositor instance is no
|
||||
* longer valid and can be setup with another wl_subcompositor interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this SubCompositor.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_subcompositor interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating a SubSurface.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating a SubSurface.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Creates and setup a new SubSurface with @p parent.
|
||||
* @param parent The parent to pass to the Surface.
|
||||
* @returns The new created Surface
|
||||
**/
|
||||
SubSurface *createSubSurface(QPointer<Surface> surface, QPointer<Surface> parentSurface, QObject *parent = nullptr);
|
||||
|
||||
operator wl_subcompositor *();
|
||||
operator wl_subcompositor *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the Compositor got created by
|
||||
* Registry::createSubCompositor
|
||||
*
|
||||
* @since 5.5
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "subsurface.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN SubSurface::Private
|
||||
{
|
||||
public:
|
||||
Private(QPointer<Surface> surface, QPointer<Surface> parentSurface, SubSurface *q);
|
||||
void setup(wl_subsurface *subsurface);
|
||||
|
||||
WaylandPointer<wl_subsurface, wl_subsurface_destroy> subSurface;
|
||||
QPointer<Surface> surface;
|
||||
QPointer<Surface> parentSurface;
|
||||
Mode mode = Mode::Synchronized;
|
||||
QPoint pos = QPoint(0, 0);
|
||||
|
||||
static SubSurface *cast(wl_subsurface *native);
|
||||
|
||||
private:
|
||||
SubSurface *q;
|
||||
};
|
||||
|
||||
SubSurface::Private::Private(QPointer<Surface> surface, QPointer<Surface> parentSurface, SubSurface *q)
|
||||
: surface(surface)
|
||||
, parentSurface(parentSurface)
|
||||
, q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void SubSurface::Private::setup(wl_subsurface *subsurface)
|
||||
{
|
||||
Q_ASSERT(subsurface);
|
||||
Q_ASSERT(!subSurface.isValid());
|
||||
subSurface.setup(subsurface);
|
||||
wl_subsurface_set_user_data(subsurface, this);
|
||||
}
|
||||
|
||||
SubSurface *SubSurface::Private::cast(wl_subsurface *native)
|
||||
{
|
||||
return reinterpret_cast<Private *>(wl_subsurface_get_user_data(native))->q;
|
||||
}
|
||||
|
||||
SubSurface::SubSurface(QPointer<Surface> surface, QPointer<Surface> parentSurface, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(surface, parentSurface, this))
|
||||
{
|
||||
}
|
||||
|
||||
SubSurface::~SubSurface()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void SubSurface::setup(wl_subsurface *subsurface)
|
||||
{
|
||||
d->setup(subsurface);
|
||||
}
|
||||
|
||||
void SubSurface::destroy()
|
||||
{
|
||||
d->subSurface.destroy();
|
||||
}
|
||||
|
||||
void SubSurface::release()
|
||||
{
|
||||
d->subSurface.release();
|
||||
}
|
||||
|
||||
bool SubSurface::isValid() const
|
||||
{
|
||||
return d->subSurface.isValid();
|
||||
}
|
||||
|
||||
QPointer<Surface> SubSurface::surface() const
|
||||
{
|
||||
return d->surface;
|
||||
}
|
||||
|
||||
QPointer<Surface> SubSurface::parentSurface() const
|
||||
{
|
||||
return d->parentSurface;
|
||||
}
|
||||
|
||||
void SubSurface::setMode(SubSurface::Mode mode)
|
||||
{
|
||||
if (mode == d->mode) {
|
||||
return;
|
||||
}
|
||||
d->mode = mode;
|
||||
switch (d->mode) {
|
||||
case Mode::Synchronized:
|
||||
wl_subsurface_set_sync(d->subSurface);
|
||||
break;
|
||||
case Mode::Desynchronized:
|
||||
wl_subsurface_set_desync(d->subSurface);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SubSurface::Mode SubSurface::mode() const
|
||||
{
|
||||
return d->mode;
|
||||
}
|
||||
|
||||
void SubSurface::setPosition(const QPoint &pos)
|
||||
{
|
||||
if (pos == d->pos) {
|
||||
return;
|
||||
}
|
||||
d->pos = pos;
|
||||
wl_subsurface_set_position(d->subSurface, pos.x(), pos.y());
|
||||
}
|
||||
|
||||
QPoint SubSurface::position() const
|
||||
{
|
||||
return d->pos;
|
||||
}
|
||||
|
||||
void SubSurface::raise()
|
||||
{
|
||||
placeAbove(d->parentSurface);
|
||||
}
|
||||
|
||||
void SubSurface::placeAbove(QPointer<SubSurface> sibling)
|
||||
{
|
||||
if (sibling.isNull()) {
|
||||
return;
|
||||
}
|
||||
placeAbove(sibling->surface());
|
||||
}
|
||||
|
||||
void SubSurface::placeAbove(QPointer<Surface> sibling)
|
||||
{
|
||||
if (sibling.isNull()) {
|
||||
return;
|
||||
}
|
||||
wl_subsurface_place_above(d->subSurface, *sibling);
|
||||
}
|
||||
|
||||
void SubSurface::lower()
|
||||
{
|
||||
placeBelow(d->parentSurface);
|
||||
}
|
||||
|
||||
void SubSurface::placeBelow(QPointer<Surface> sibling)
|
||||
{
|
||||
if (sibling.isNull()) {
|
||||
return;
|
||||
}
|
||||
wl_subsurface_place_below(d->subSurface, *sibling);
|
||||
}
|
||||
|
||||
void SubSurface::placeBelow(QPointer<SubSurface> sibling)
|
||||
{
|
||||
if (sibling.isNull()) {
|
||||
return;
|
||||
}
|
||||
placeBelow(sibling->surface());
|
||||
}
|
||||
|
||||
QPointer<SubSurface> SubSurface::get(wl_subsurface *native)
|
||||
{
|
||||
return QPointer<SubSurface>(Private::cast(native));
|
||||
}
|
||||
|
||||
SubSurface::operator wl_subsurface *() const
|
||||
{
|
||||
return d->subSurface;
|
||||
}
|
||||
|
||||
SubSurface::operator wl_subsurface *()
|
||||
{
|
||||
return d->subSurface;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_subsurface.cpp"
|
||||
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_SUBSURFACE_H
|
||||
#define WAYLAND_SUBSURFACE_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_subsurface;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Surface;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the wl_subsurface interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the wl_subsurface interface.
|
||||
* To create a SubSurface call SubCompositor::createSubSurface.
|
||||
*
|
||||
* A SubSurface is bound to a Surface and has a parent Surface.
|
||||
* A SubSurface can only be created for a Surface not already used in onther way,
|
||||
* e.g. as a ShellSurface.
|
||||
*
|
||||
* The SubSurface has a position in local coordinates to the parent Surface.
|
||||
* Please note that changing the position is a double buffered state and is only
|
||||
* applied once the parent surface is committed. The same applies for manipulating
|
||||
* the stacking order of the SubSurface's siblings.
|
||||
*
|
||||
* @see SubCompositor
|
||||
* @see Surface
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT SubSurface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit SubSurface(QPointer<Surface> surface, QPointer<Surface> parentSurface, QObject *parent = nullptr);
|
||||
~SubSurface() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a wl_subsurface.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this SubSurface to manage the @p subsurface.
|
||||
* When using SubCompositor::createSubSurface there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_subsurface *subsurface);
|
||||
/**
|
||||
* Releases the wl_subsurface interface.
|
||||
* After the interface has been released the SubSurface instance is no
|
||||
* longer valid and can be setup with another wl_subsurface interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this SubSurface.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_subsurface interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Operation Mode on how the Surface's commit should behave.
|
||||
**/
|
||||
enum class Mode {
|
||||
Synchronized,
|
||||
Desynchronized,
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the operation mode to @p mode.
|
||||
* Initially a SubSurface is in Synchronized Mode.
|
||||
**/
|
||||
void setMode(Mode mode);
|
||||
Mode mode() const;
|
||||
|
||||
/**
|
||||
* Sets the position in relative coordinates to the parent surface to @p pos.
|
||||
*
|
||||
* The change is only applied after the parent Surface got committed.
|
||||
**/
|
||||
void setPosition(const QPoint &pos);
|
||||
QPoint position() const;
|
||||
|
||||
/**
|
||||
* Raises this SubSurface above all siblings.
|
||||
* This is the same as calling placeAbove with the parent surface
|
||||
* as argument.
|
||||
*
|
||||
* The change is only applied after the parent surface got committed.
|
||||
* @see placeAbove
|
||||
**/
|
||||
void raise();
|
||||
/**
|
||||
* Places the SubSurface above the @p sibling.
|
||||
*
|
||||
* The change is only applied after the parent surface got committed.
|
||||
* @param sibling The SubSurface on top of which this SubSurface should be placed
|
||||
**/
|
||||
void placeAbove(QPointer<SubSurface> sibling);
|
||||
/**
|
||||
* Places the SubSurface above the @p referenceSurface.
|
||||
*
|
||||
* In case @p referenceSurface is the parent surface this SubSurface is
|
||||
* raised to the top of the stacking order. Otherwise it is put directly
|
||||
* above the @p referenceSurface in the stacking order.
|
||||
*
|
||||
* The change is only applied after the parent surface got committed.
|
||||
* @param referenceSurface Either a sibling or parent Surface
|
||||
**/
|
||||
void placeAbove(QPointer<Surface> referenceSurface);
|
||||
|
||||
/**
|
||||
* Lowers this SubSurface below all siblings.
|
||||
* This is the same as calling placeBelow with the parent surface
|
||||
* as argument.
|
||||
*
|
||||
* The change is only applied after the parent surface got committed.
|
||||
* @see placeBelow
|
||||
**/
|
||||
void lower();
|
||||
/**
|
||||
* Places the SubSurface below the @p sibling.
|
||||
*
|
||||
* The change is only applied after the parent surface got committed.
|
||||
* @param sibling The SubSurface under which the SubSurface should be put
|
||||
**/
|
||||
void placeBelow(QPointer<SubSurface> sibling);
|
||||
/**
|
||||
* Places the SubSurface below the @p referenceSurface.
|
||||
*
|
||||
* In case @p referenceSurface is the parent surface this SubSurface is
|
||||
* lowered to the bottom of the stacking order. Otherwise it is put directly
|
||||
* below the @p referenceSurface in the stacking order.
|
||||
*
|
||||
* The change is only applied after the parent surface got committed.
|
||||
* @param referenceSurface Either a sibling or parent Surface
|
||||
**/
|
||||
void placeBelow(QPointer<Surface> referenceSurface);
|
||||
|
||||
/**
|
||||
* @returns The Surface for which this SubSurface got created.
|
||||
**/
|
||||
QPointer<Surface> surface() const;
|
||||
/**
|
||||
* @returns The parent Surface of this SubSurface.
|
||||
**/
|
||||
QPointer<Surface> parentSurface() const;
|
||||
|
||||
static QPointer<SubSurface> get(wl_subsurface *native);
|
||||
|
||||
operator wl_subsurface *();
|
||||
operator wl_subsurface *() const;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,273 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "surface.h"
|
||||
#include "output.h"
|
||||
#include "region.h"
|
||||
#include "surface_p.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QList>
|
||||
#include <QRegion>
|
||||
// Wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
|
||||
QList<Surface *> Surface::Private::s_surfaces = QList<Surface *>();
|
||||
|
||||
Surface::Private::Private(Surface *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
Surface::Surface(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
Private::s_surfaces << this;
|
||||
}
|
||||
|
||||
Surface::~Surface()
|
||||
{
|
||||
Private::s_surfaces.removeAll(this);
|
||||
release();
|
||||
}
|
||||
|
||||
|
||||
void Surface::release()
|
||||
{
|
||||
d->surface.release();
|
||||
}
|
||||
|
||||
void Surface::destroy()
|
||||
{
|
||||
d->surface.destroy();
|
||||
}
|
||||
|
||||
void Surface::setup(wl_surface *surface)
|
||||
{
|
||||
d->setup(surface);
|
||||
}
|
||||
|
||||
void Surface::Private::setup(wl_surface *s)
|
||||
{
|
||||
Q_ASSERT(s);
|
||||
Q_ASSERT(!surface);
|
||||
surface.setup(s);
|
||||
wl_surface_add_listener(s, &s_surfaceListener, this);
|
||||
}
|
||||
|
||||
void Surface::Private::frameCallback(void *data, wl_callback *callback, uint32_t time)
|
||||
{
|
||||
Q_UNUSED(time)
|
||||
auto s = reinterpret_cast<Surface::Private *>(data);
|
||||
if (callback) {
|
||||
wl_callback_destroy(callback);
|
||||
}
|
||||
s->handleFrameCallback();
|
||||
}
|
||||
|
||||
void Surface::Private::handleFrameCallback()
|
||||
{
|
||||
frameCallbackInstalled = false;
|
||||
Q_EMIT q->frameRendered();
|
||||
}
|
||||
|
||||
#ifndef K_DOXYGEN
|
||||
const struct wl_callback_listener Surface::Private::s_listener = {frameCallback};
|
||||
|
||||
const struct wl_surface_listener Surface::Private::s_surfaceListener = {enterCallback, leaveCallback};
|
||||
#endif
|
||||
|
||||
void Surface::Private::removeOutput(Output *o)
|
||||
{
|
||||
if (o && outputs.removeOne(o)) {
|
||||
Q_EMIT q->outputLeft(o);
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::Private::enterCallback(void *data, wl_surface *surface, wl_output *output)
|
||||
{
|
||||
Q_UNUSED(surface);
|
||||
auto s = reinterpret_cast<Surface::Private *>(data);
|
||||
Output *o = Output::get(output);
|
||||
if (!o) {
|
||||
return;
|
||||
}
|
||||
s->outputs << o;
|
||||
QObject::connect(o, &Output::removed, s->q, [s, o]() {
|
||||
s->removeOutput(o);
|
||||
});
|
||||
Q_EMIT s->q->outputEntered(o);
|
||||
}
|
||||
|
||||
void Surface::Private::leaveCallback(void *data, wl_surface *surface, wl_output *output)
|
||||
{
|
||||
Q_UNUSED(surface);
|
||||
auto s = reinterpret_cast<Surface::Private *>(data);
|
||||
s->removeOutput(Output::get(output));
|
||||
}
|
||||
|
||||
void Surface::Private::setupFrameCallback()
|
||||
{
|
||||
Q_ASSERT(!frameCallbackInstalled);
|
||||
wl_callback *callback = wl_surface_frame(surface);
|
||||
wl_callback_add_listener(callback, &s_listener, this);
|
||||
frameCallbackInstalled = true;
|
||||
}
|
||||
|
||||
void Surface::setupFrameCallback()
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
d->setupFrameCallback();
|
||||
}
|
||||
|
||||
void Surface::commit(Surface::CommitFlag flag)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
if (flag == CommitFlag::FrameCallback) {
|
||||
setupFrameCallback();
|
||||
}
|
||||
wl_surface_commit(d->surface);
|
||||
}
|
||||
|
||||
void Surface::damage(const QRegion ®ion)
|
||||
{
|
||||
for (const QRect &rect : region) {
|
||||
damage(rect);
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::damage(const QRect &rect)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
wl_surface_damage(d->surface, rect.x(), rect.y(), rect.width(), rect.height());
|
||||
}
|
||||
|
||||
void Surface::damageBuffer(const QRegion ®ion)
|
||||
{
|
||||
for (const QRect &r : region) {
|
||||
damageBuffer(r);
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::damageBuffer(const QRect &rect)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
wl_surface_damage_buffer(d->surface, rect.x(), rect.y(), rect.width(), rect.height());
|
||||
}
|
||||
|
||||
void Surface::attachBuffer(wl_buffer *buffer, const QPoint &offset)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
wl_surface_attach(d->surface, buffer, offset.x(), offset.y());
|
||||
}
|
||||
|
||||
void Surface::attachBuffer(Buffer *buffer, const QPoint &offset)
|
||||
{
|
||||
attachBuffer(buffer ? buffer->buffer() : nullptr, offset);
|
||||
}
|
||||
|
||||
void Surface::attachBuffer(Buffer::Ptr buffer, const QPoint &offset)
|
||||
{
|
||||
attachBuffer(buffer.toStrongRef().data(), offset);
|
||||
}
|
||||
|
||||
void Surface::setInputRegion(const Region *region)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
if (region) {
|
||||
wl_surface_set_input_region(d->surface, *region);
|
||||
} else {
|
||||
wl_surface_set_input_region(d->surface, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::setOpaqueRegion(const Region *region)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
if (region) {
|
||||
wl_surface_set_opaque_region(d->surface, *region);
|
||||
} else {
|
||||
wl_surface_set_opaque_region(d->surface, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Surface::setSize(const QSize &size)
|
||||
{
|
||||
if (d->size == size) {
|
||||
return;
|
||||
}
|
||||
d->size = size;
|
||||
Q_EMIT sizeChanged(d->size);
|
||||
}
|
||||
|
||||
Surface *Surface::get(wl_surface *native)
|
||||
{
|
||||
auto it = std::find_if(Private::s_surfaces.constBegin(), Private::s_surfaces.constEnd(), [native](Surface *s) {
|
||||
return s->d->surface == native;
|
||||
});
|
||||
if (it != Private::s_surfaces.constEnd()) {
|
||||
return *(it);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const QList<Surface *> &Surface::all()
|
||||
{
|
||||
return Private::s_surfaces;
|
||||
}
|
||||
|
||||
bool Surface::isValid() const
|
||||
{
|
||||
return d->surface.isValid();
|
||||
}
|
||||
|
||||
QSize Surface::size() const
|
||||
{
|
||||
return d->size;
|
||||
}
|
||||
|
||||
Surface::operator wl_surface *()
|
||||
{
|
||||
return d->surface;
|
||||
}
|
||||
|
||||
Surface::operator wl_surface *() const
|
||||
{
|
||||
return d->surface;
|
||||
}
|
||||
|
||||
quint32 Surface::id() const
|
||||
{
|
||||
wl_surface *s = *this;
|
||||
return wl_proxy_get_id(reinterpret_cast<wl_proxy *>(s));
|
||||
}
|
||||
|
||||
qint32 Surface::scale() const
|
||||
{
|
||||
return d->scale;
|
||||
}
|
||||
|
||||
void Surface::setScale(qint32 scale)
|
||||
{
|
||||
d->scale = scale;
|
||||
wl_surface_set_buffer_scale(d->surface, scale);
|
||||
}
|
||||
|
||||
QList<Output *> Surface::outputs() const
|
||||
{
|
||||
return d->outputs;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_surface.cpp"
|
||||
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_SURFACE_H
|
||||
#define WAYLAND_SURFACE_H
|
||||
|
||||
#include "buffer.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QPoint>
|
||||
#include <QSize>
|
||||
#include <QWindow>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_buffer;
|
||||
struct wl_surface;
|
||||
|
||||
class QWindow;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Output;
|
||||
class Region;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the wl_surface interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the wl_surface interface.
|
||||
* To create a Surface call Compositor::createSurface.
|
||||
*
|
||||
* The main purpose of this class is to setup the next frame which
|
||||
* should be rendered. Therefore it provides methods to add damage
|
||||
* and to attach a new Buffer and to finalize the frame by calling
|
||||
* commit.
|
||||
*
|
||||
* @see Compositor
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Surface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Surface(QObject *parent = nullptr);
|
||||
~Surface() override;
|
||||
|
||||
/**
|
||||
* Creates a Surface for the given @p window.
|
||||
* This is an integration feature for QtWayland. On non-wayland platforms this method returns
|
||||
* @c nullptr as well as for not created QWindows.
|
||||
*
|
||||
* The returned Surface will be fully setup, but won't be released. It gets automatically
|
||||
* destroyed together with the @p window or when the internal wl_surface get destroyed.
|
||||
* QtWayland may destroy wl_surface when hiding the window, you should always call
|
||||
* this function instead of holding the returned pointer.
|
||||
* @since 5.4
|
||||
**/
|
||||
static Surface *fromWindow(QWindow *window);
|
||||
|
||||
/**
|
||||
* Creates a Surface for the given @p winId.
|
||||
* This is an integration feature for QtWayland. On non-wayland platforms this method returns
|
||||
* @c nullptr as well as for not created QWindows.
|
||||
*
|
||||
* The returned Surface will be fully setup, but won't be released. It gets automatically
|
||||
* destroyed together with the QWindow or the wl_surface corresponding.
|
||||
* the @p wid.
|
||||
* @since 5.5
|
||||
* @see fromWindow
|
||||
**/
|
||||
static Surface *fromQtWinId(WId wid);
|
||||
|
||||
/**
|
||||
* Setup this Surface to manage the @p surface.
|
||||
* When using Compositor::createSurface there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_surface *surface);
|
||||
/**
|
||||
* Releases the wl_surface interface.
|
||||
* After the interface has been released the Surface instance is no
|
||||
* longer valid and can be setup with another wl_surface interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this Surface.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_surface interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* Surface gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* @returns @c true if managing a wl_surface.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Registers a frame rendered callback.
|
||||
* This registers a callback in the Wayland server to be notified once the
|
||||
* next frame for this Surface has been rendered. The Surface will emit the
|
||||
* signal frameRendered after receiving the callback from the server.
|
||||
*
|
||||
* Instead of using this method one should prefer using the CommitFlag::FrameCallback
|
||||
* in commit. This method is intended for cases when the Surface is going to
|
||||
* be committed on other ways, e.g. through the OpenGL/EGL stack.
|
||||
*
|
||||
* @see frameRendered
|
||||
* @see commit
|
||||
**/
|
||||
void setupFrameCallback();
|
||||
/**
|
||||
* Flags to be added to commit.
|
||||
* @li None: no flag
|
||||
* @li FrameCallback: register a frame rendered callback
|
||||
*
|
||||
* Instead of setting the FrameCallback flag one can also call
|
||||
* setupFrameCallback. If one uses setupFrameCallback one may not
|
||||
* use the FrameCallback flag when committing the Surface.
|
||||
*
|
||||
* @see commit
|
||||
* @see setupFrameCallback
|
||||
**/
|
||||
enum class CommitFlag {
|
||||
None,
|
||||
FrameCallback,
|
||||
};
|
||||
void commit(CommitFlag flag = CommitFlag::FrameCallback);
|
||||
/**
|
||||
* Mark @p rect as damaged for the next frame.
|
||||
* @see damageBuffer
|
||||
**/
|
||||
void damage(const QRect &rect);
|
||||
/**
|
||||
* Mark @p region as damaged for the next frame.
|
||||
* @see damageBuffer
|
||||
**/
|
||||
void damage(const QRegion ®ion);
|
||||
/**
|
||||
* Mark @p rect in buffer coordinates as damaged for the next frame.
|
||||
* @see damage
|
||||
* @since 5.59
|
||||
**/
|
||||
void damageBuffer(const QRect &rect);
|
||||
/**
|
||||
* Mark @p region in buffer coordinates as damaged for the next frame.
|
||||
* @see damage
|
||||
* @since 5.59
|
||||
**/
|
||||
void damageBuffer(const QRegion ®ion);
|
||||
/**
|
||||
* Attaches the @p buffer to this Surface for the next frame.
|
||||
* @param buffer The buffer to attach to this Surface
|
||||
* @param offset Position of the new upper-left corner in relation to previous frame
|
||||
**/
|
||||
void attachBuffer(wl_buffer *buffer, const QPoint &offset = QPoint());
|
||||
/**
|
||||
* Overloaded method for convenience.
|
||||
**/
|
||||
void attachBuffer(Buffer *buffer, const QPoint &offset = QPoint());
|
||||
/**
|
||||
* Overloaded method for convenience.
|
||||
**/
|
||||
void attachBuffer(Buffer::Ptr buffer, const QPoint &offset = QPoint());
|
||||
/**
|
||||
* Sets the input region to @p region.
|
||||
*
|
||||
* This is a double buffered state and will be applied with the next Surface
|
||||
* commit. Initially the Surface is set up to an infinite input region.
|
||||
* By passing @c null as the input region, it gets reset to an infinite input
|
||||
* region.
|
||||
*
|
||||
* Note: the Region is being copied and can be destroyed directly after passing
|
||||
* to this method.
|
||||
*
|
||||
* @param region The new input region or an infinite region if @c null
|
||||
* @see commit
|
||||
**/
|
||||
void setInputRegion(const Region *region = nullptr);
|
||||
/**
|
||||
* Sets the opaque region to @p region.
|
||||
*
|
||||
* This is a double buffered state and will be applied with the next Surface
|
||||
* commit. Initially the Surface is set up to an empty opaque region.
|
||||
* By passing @c null as the opaque region, it gets reset to an empty opaque
|
||||
* region.
|
||||
*
|
||||
* Note: the Region is being copied and can be destroyed directly after passing
|
||||
* to this method.
|
||||
*
|
||||
* @param region The new opaque region or an empty region if @c null
|
||||
* @see commit
|
||||
**/
|
||||
void setOpaqueRegion(const Region *region = nullptr);
|
||||
void setSize(const QSize &size);
|
||||
QSize size() const;
|
||||
|
||||
/**
|
||||
* The purpose of this method is to allow to supply higher resolution buffer data for use
|
||||
* on high resolution outputs. It's intended that the same buffer scale as the scale of the
|
||||
* output that the surface is displayed on is used.
|
||||
* This means the compositor can avoid scaling when rendering the surface on that output.
|
||||
*
|
||||
* Note that if @p scale is larger than 1 you have to attach a buffer that is larger
|
||||
* (by a factor of scale in each dimension) than the desired surface size.
|
||||
*
|
||||
* The default scale factor is 1.
|
||||
*
|
||||
* The state is only applied with the next commit.
|
||||
*
|
||||
* @see scale
|
||||
* @see commit
|
||||
* @since 5.22
|
||||
**/
|
||||
void setScale(qint32 scale);
|
||||
/**
|
||||
* @returns The current scale factor, if not explicitly set it's @c 1.
|
||||
* @see setScale
|
||||
* @since 5.22
|
||||
**/
|
||||
qint32 scale() const;
|
||||
|
||||
operator wl_surface *();
|
||||
operator wl_surface *() const;
|
||||
|
||||
/**
|
||||
* @returns the id of the referenced wl_proxy.
|
||||
* @since 5.4
|
||||
**/
|
||||
quint32 id() const;
|
||||
|
||||
/**
|
||||
* @returns All Outputs the Surface is on, may be none.
|
||||
* @see outputEntered
|
||||
* @see outputLeft
|
||||
* @since 5.27
|
||||
**/
|
||||
QList<Output *> outputs() const;
|
||||
|
||||
/**
|
||||
* All Surfaces which are currently created.
|
||||
* TODO: KF6 return QList<Surface*> instead of const-ref
|
||||
**/
|
||||
static const QList<Surface *> &all(); // krazy:exclude=constref
|
||||
/**
|
||||
* @returns The Surface referencing the @p native wl_surface or @c null if there is no such Surface.
|
||||
**/
|
||||
static Surface *get(wl_surface *native);
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted when the server indicates that the last committed frame has been rendered.
|
||||
* The signal will only be emitted if a callback has been registered by either calling
|
||||
* setupFrameCallback or calling commit with the CommitFlag::FrameCallback.
|
||||
* @see setupFrameCallback
|
||||
* @see commit
|
||||
**/
|
||||
void frameRendered();
|
||||
void sizeChanged(const QSize &);
|
||||
|
||||
/**
|
||||
* Emitted whenever a change in the Surface (e.g. creation, movement, resize) results in
|
||||
* a part of the Surface being within the scanout region of the Output @p o.
|
||||
*
|
||||
* @param o The Output the Surface intersects with
|
||||
* @see outputLeft
|
||||
* @see outputs
|
||||
* @since 5.27
|
||||
**/
|
||||
void outputEntered(KWayland::Client::Output *o);
|
||||
|
||||
/**
|
||||
* Emitted whenever a change in the Surface (e.g. creation, movement, resize, unmapping)
|
||||
* results in the Surface no longer being within the scanout region of the Output @p o.
|
||||
*
|
||||
* @param o The Output the Surface no longer intersects with
|
||||
* @see outputEntered
|
||||
* @see outputs
|
||||
* @since 5.27
|
||||
**/
|
||||
void outputLeft(KWayland::Client::Output *o);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
#include "surface_p.h"
|
||||
#include "surface.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <private/qwaylandwindow_p.h>
|
||||
#include <qpa/qplatformnativeinterface.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
|
||||
// The file split from surface.cpp because QtWaylandClient private headers require to unset QT_NO_KEYWORDS.
|
||||
Surface *Surface::fromWindow(QWindow *window)
|
||||
{
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
QPlatformNativeInterface *native = qApp->platformNativeInterface();
|
||||
if (!native) {
|
||||
return nullptr;
|
||||
}
|
||||
window->create();
|
||||
wl_surface *s = reinterpret_cast<wl_surface *>(native->nativeResourceForWindow(QByteArrayLiteral("surface"), window));
|
||||
if (!s) {
|
||||
return nullptr;
|
||||
}
|
||||
if (auto surface = get(s)) {
|
||||
return surface;
|
||||
}
|
||||
Surface *surface = new Surface(window);
|
||||
surface->d->surface.setup(s, true);
|
||||
|
||||
auto waylandWindow = dynamic_cast<QtWaylandClient::QWaylandWindow *>(window->handle());
|
||||
if (waylandWindow) {
|
||||
connect(waylandWindow, &QtWaylandClient::QWaylandWindow::wlSurfaceDestroyed, surface, &QObject::deleteLater);
|
||||
}
|
||||
return surface;
|
||||
}
|
||||
|
||||
Surface *Surface::fromQtWinId(WId wid)
|
||||
{
|
||||
QWindow *window = nullptr;
|
||||
|
||||
for (auto win : qApp->allWindows()) {
|
||||
if (win->winId() == wid) {
|
||||
window = win;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!window) {
|
||||
return nullptr;
|
||||
}
|
||||
return fromWindow(window);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_SURFACE_P_H
|
||||
#define WAYLAND_SURFACE_P_H
|
||||
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN Surface::Private
|
||||
{
|
||||
public:
|
||||
Private(Surface *q);
|
||||
void setupFrameCallback();
|
||||
|
||||
WaylandPointer<wl_surface, wl_surface_destroy> surface;
|
||||
bool frameCallbackInstalled = false;
|
||||
QSize size;
|
||||
bool foreign = false;
|
||||
qint32 scale = 1;
|
||||
QList<Output *> outputs;
|
||||
|
||||
void setup(wl_surface *s);
|
||||
|
||||
static QList<Surface *> s_surfaces;
|
||||
|
||||
private:
|
||||
void handleFrameCallback();
|
||||
static void frameCallback(void *data, wl_callback *callback, uint32_t time);
|
||||
static void enterCallback(void *data, wl_surface *wl_surface, wl_output *output);
|
||||
static void leaveCallback(void *data, wl_surface *wl_surface, wl_output *output);
|
||||
void removeOutput(Output *o);
|
||||
|
||||
Surface *q;
|
||||
static const wl_callback_listener s_listener;
|
||||
static const wl_surface_listener s_surfaceListener;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,216 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "textinput_p.h"
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
TextInput::Private::Private(Seat *seat)
|
||||
: seat(seat)
|
||||
{
|
||||
currentCommit.deleteSurrounding.afterLength = 0;
|
||||
currentCommit.deleteSurrounding.beforeLength = 0;
|
||||
pendingCommit.deleteSurrounding.afterLength = 0;
|
||||
pendingCommit.deleteSurrounding.beforeLength = 0;
|
||||
}
|
||||
|
||||
TextInput::TextInput(Private *p, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(p)
|
||||
{
|
||||
}
|
||||
|
||||
TextInput::~TextInput() = default;
|
||||
|
||||
void TextInput::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *TextInput::eventQueue() const
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
bool TextInput::isValid() const
|
||||
{
|
||||
return d->isValid();
|
||||
}
|
||||
|
||||
Surface *TextInput::enteredSurface() const
|
||||
{
|
||||
return d->enteredSurface;
|
||||
}
|
||||
|
||||
bool TextInput::isInputPanelVisible() const
|
||||
{
|
||||
return d->inputPanelVisible;
|
||||
}
|
||||
|
||||
void TextInput::enable(Surface *surface)
|
||||
{
|
||||
d->enable(surface);
|
||||
}
|
||||
|
||||
void TextInput::disable(Surface *surface)
|
||||
{
|
||||
d->disable(surface);
|
||||
}
|
||||
|
||||
void TextInput::showInputPanel()
|
||||
{
|
||||
d->showInputPanel();
|
||||
}
|
||||
|
||||
void TextInput::hideInputPanel()
|
||||
{
|
||||
d->hideInputPanel();
|
||||
}
|
||||
|
||||
void TextInput::reset()
|
||||
{
|
||||
d->reset();
|
||||
}
|
||||
|
||||
void TextInput::setSurroundingText(const QString &text, quint32 cursor, quint32 anchor)
|
||||
{
|
||||
d->setSurroundingText(text, cursor, anchor);
|
||||
}
|
||||
|
||||
void TextInput::setContentType(ContentHints hint, ContentPurpose purpose)
|
||||
{
|
||||
d->setContentType(hint, purpose);
|
||||
}
|
||||
|
||||
void TextInput::setCursorRectangle(const QRect &rect)
|
||||
{
|
||||
d->setCursorRectangle(rect);
|
||||
}
|
||||
|
||||
void TextInput::setPreferredLanguage(const QString &language)
|
||||
{
|
||||
d->setPreferredLanguage(language);
|
||||
}
|
||||
|
||||
Qt::LayoutDirection TextInput::textDirection() const
|
||||
{
|
||||
return d->textDirection;
|
||||
}
|
||||
|
||||
QByteArray TextInput::language() const
|
||||
{
|
||||
return d->language;
|
||||
}
|
||||
|
||||
qint32 TextInput::composingTextCursorPosition() const
|
||||
{
|
||||
return d->currentPreEdit.cursor;
|
||||
}
|
||||
|
||||
QByteArray TextInput::composingText() const
|
||||
{
|
||||
return d->currentPreEdit.text;
|
||||
}
|
||||
|
||||
QByteArray TextInput::composingFallbackText() const
|
||||
{
|
||||
return d->currentPreEdit.commitText;
|
||||
}
|
||||
|
||||
qint32 TextInput::anchorPosition() const
|
||||
{
|
||||
return d->currentCommit.anchor;
|
||||
}
|
||||
|
||||
qint32 TextInput::cursorPosition() const
|
||||
{
|
||||
return d->currentCommit.cursor;
|
||||
}
|
||||
|
||||
TextInput::DeleteSurroundingText TextInput::deleteSurroundingText() const
|
||||
{
|
||||
return d->currentCommit.deleteSurrounding;
|
||||
}
|
||||
|
||||
QByteArray TextInput::commitText() const
|
||||
{
|
||||
return d->currentCommit.text;
|
||||
}
|
||||
|
||||
TextInputManager::TextInputManager(Private *p, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(p)
|
||||
{
|
||||
}
|
||||
|
||||
TextInputManager::~TextInputManager() = default;
|
||||
|
||||
void TextInputManager::setup(wl_text_input_manager *textinputmanagerunstablev0)
|
||||
{
|
||||
d->setupV0(textinputmanagerunstablev0);
|
||||
}
|
||||
|
||||
void TextInputManager::setup(zwp_text_input_manager_v2 *textinputmanagerunstablev2)
|
||||
{
|
||||
d->setupV2(textinputmanagerunstablev2);
|
||||
}
|
||||
|
||||
void TextInputManager::release()
|
||||
{
|
||||
d->release();
|
||||
}
|
||||
|
||||
void TextInputManager::destroy()
|
||||
{
|
||||
d->destroy();
|
||||
}
|
||||
|
||||
void TextInputManager::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *TextInputManager::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
TextInputManager::operator wl_text_input_manager *()
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
TextInputManager::operator wl_text_input_manager *() const
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
TextInputManager::operator zwp_text_input_manager_v2 *()
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
TextInputManager::operator zwp_text_input_manager_v2 *() const
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
bool TextInputManager::isValid() const
|
||||
{
|
||||
return d->isValid();
|
||||
}
|
||||
|
||||
TextInput *TextInputManager::createTextInput(Seat *seat, QObject *parent)
|
||||
{
|
||||
return d->createTextInput(seat, parent);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_textinput.cpp"
|
||||
#include "moc_textinput_p.cpp"
|
||||
@@ -0,0 +1,519 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_TEXTINPUT_H
|
||||
#define KWAYLAND_CLIENT_TEXTINPUT_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_text_input;
|
||||
struct wl_text_input_manager;
|
||||
struct zwp_text_input_manager_v2;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Surface;
|
||||
class Seat;
|
||||
|
||||
/**
|
||||
* @brief TextInput represents a Wayland interface for text input.
|
||||
*
|
||||
* The TextInput allows to have text composed by the Compositor and be sent to
|
||||
* the client.
|
||||
*
|
||||
* Depending on the interface the TextInputManager got created for this class
|
||||
* encapsulates one of the following interfaces:
|
||||
* @li wl_text_input
|
||||
* @li zwp_text_input_v2
|
||||
*
|
||||
* @since 5.23
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT TextInput : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~TextInput() override;
|
||||
/**
|
||||
* @returns @c true if managing a resource.
|
||||
**/
|
||||
bool isValid() const;
|
||||
|
||||
/**
|
||||
* @returns The Surface which has the text input focus on this TextInput.
|
||||
* @see entered
|
||||
* @see left
|
||||
**/
|
||||
Surface *enteredSurface() const;
|
||||
|
||||
void setEventQueue(EventQueue *queue);
|
||||
EventQueue *eventQueue() const;
|
||||
|
||||
/**
|
||||
* @returns whether the input panel (virtual keyboard) is currently visible on the screen
|
||||
* @see inputPanelStateChanged
|
||||
**/
|
||||
bool isInputPanelVisible() const;
|
||||
|
||||
/**
|
||||
* Enable text input in a @p surface (usually when a text entry inside of it has focus).
|
||||
*
|
||||
* This can be called before or after a surface gets text (or keyboard) focus via the
|
||||
* enter event. Text input to a surface is only active when it has the current
|
||||
* text (or keyboard) focus and is enabled.
|
||||
* @see deactivate
|
||||
**/
|
||||
void enable(Surface *surface);
|
||||
|
||||
/**
|
||||
* Disable text input in a @p surface (typically when there is no focus on any
|
||||
* text entry inside the surface).
|
||||
* @see enable
|
||||
**/
|
||||
void disable(Surface *surface);
|
||||
|
||||
/**
|
||||
* Requests input panels (virtual keyboard) to show.
|
||||
* @see hideInputPanel
|
||||
**/
|
||||
void showInputPanel();
|
||||
|
||||
/**
|
||||
* Requests input panels (virtual keyboard) to hide.
|
||||
* @see showInputPanel
|
||||
**/
|
||||
void hideInputPanel();
|
||||
|
||||
/**
|
||||
* Should be called by an editor widget when the input state should be
|
||||
* reset, for example after the text was changed outside of the normal
|
||||
* input method flow.
|
||||
**/
|
||||
void reset();
|
||||
|
||||
/**
|
||||
* Sets the plain surrounding text around the input position.
|
||||
*
|
||||
* @param text The text surrounding the cursor position
|
||||
* @param cursor Index in the text describing the cursor position
|
||||
* @param anchor Index of the selection anchor, if no selection same as cursor
|
||||
**/
|
||||
void setSurroundingText(const QString &text, quint32 cursor, quint32 anchor);
|
||||
|
||||
/**
|
||||
* The possible states for a keyEvent.
|
||||
* @see keyEvent
|
||||
**/
|
||||
enum class KeyState {
|
||||
Pressed,
|
||||
Released,
|
||||
};
|
||||
|
||||
/**
|
||||
* ContentHint allows to modify the behavior of the text input.
|
||||
**/
|
||||
enum class ContentHint : uint32_t {
|
||||
/**
|
||||
* no special behaviour
|
||||
*/
|
||||
None = 0,
|
||||
/**
|
||||
* suggest word completions
|
||||
*/
|
||||
AutoCompletion = 1 << 0,
|
||||
/**
|
||||
* suggest word corrections
|
||||
*/
|
||||
AutoCorrection = 1 << 1,
|
||||
/**
|
||||
* switch to uppercase letters at the start of a sentence
|
||||
*/
|
||||
AutoCapitalization = 1 << 2,
|
||||
/**
|
||||
* prefer lowercase letters
|
||||
*/
|
||||
LowerCase = 1 << 3,
|
||||
/**
|
||||
* prefer uppercase letters
|
||||
*/
|
||||
UpperCase = 1 << 4,
|
||||
/**
|
||||
* prefer casing for titles and headings (can be language dependent)
|
||||
*/
|
||||
TitleCase = 1 << 5,
|
||||
/**
|
||||
* characters should be hidden
|
||||
*/
|
||||
HiddenText = 1 << 6,
|
||||
/**
|
||||
* typed text should not be stored
|
||||
*/
|
||||
SensitiveData = 1 << 7,
|
||||
/**
|
||||
* just latin characters should be entered
|
||||
*/
|
||||
Latin = 1 << 8,
|
||||
/**
|
||||
* the text input is multi line
|
||||
*/
|
||||
MultiLine = 1 << 9,
|
||||
};
|
||||
Q_DECLARE_FLAGS(ContentHints, ContentHint)
|
||||
|
||||
/**
|
||||
* The ContentPurpose allows to specify the primary purpose of a text input.
|
||||
*
|
||||
* This allows an input method to show special purpose input panels with
|
||||
* extra characters or to disallow some characters.
|
||||
*/
|
||||
enum class ContentPurpose : uint32_t {
|
||||
/**
|
||||
* default input, allowing all characters
|
||||
*/
|
||||
Normal,
|
||||
/**
|
||||
* allow only alphabetic characters
|
||||
**/
|
||||
Alpha,
|
||||
/**
|
||||
* allow only digits
|
||||
*/
|
||||
Digits,
|
||||
/**
|
||||
* input a number (including decimal separator and sign)
|
||||
*/
|
||||
Number,
|
||||
/**
|
||||
* input a phone number
|
||||
*/
|
||||
Phone,
|
||||
/**
|
||||
* input an URL
|
||||
*/
|
||||
Url,
|
||||
/**
|
||||
* input an email address
|
||||
**/
|
||||
Email,
|
||||
/**
|
||||
* input a name of a person
|
||||
*/
|
||||
Name,
|
||||
/**
|
||||
* input a password
|
||||
*/
|
||||
Password,
|
||||
/**
|
||||
* input a date
|
||||
*/
|
||||
Date,
|
||||
/**
|
||||
* input a time
|
||||
*/
|
||||
Time,
|
||||
/**
|
||||
* input a date and time
|
||||
*/
|
||||
DateTime,
|
||||
/**
|
||||
* input for a terminal
|
||||
*/
|
||||
Terminal,
|
||||
};
|
||||
/**
|
||||
* Sets the content @p purpose and content @p hints.
|
||||
* While the @p purpose is the basic purpose of an input field, the @p hints flags allow
|
||||
* to modify some of the behavior.
|
||||
**/
|
||||
void setContentType(ContentHints hints, ContentPurpose purpose);
|
||||
|
||||
/**
|
||||
* Sets the cursor outline @p rect in surface local coordinates.
|
||||
*
|
||||
* Allows the compositor to e.g. put a window with word suggestions
|
||||
* near the cursor.
|
||||
**/
|
||||
void setCursorRectangle(const QRect &rect);
|
||||
|
||||
/**
|
||||
* Sets a specific @p language.
|
||||
*
|
||||
* This allows for example a virtual keyboard to show a language specific layout.
|
||||
* The @p language argument is a RFC-3066 format language tag.
|
||||
**/
|
||||
void setPreferredLanguage(const QString &language);
|
||||
|
||||
/**
|
||||
* The text direction of input text.
|
||||
*
|
||||
* It is mainly needed for showing input cursor on correct side of the
|
||||
* editor when there is no input yet done and making sure neutral
|
||||
* direction text is laid out properly.
|
||||
* @see textDirectionChnaged
|
||||
**/
|
||||
Qt::LayoutDirection textDirection() const;
|
||||
|
||||
/**
|
||||
* The language of the input text.
|
||||
*
|
||||
* As long as the server has not emitted the language, the code will be empty.
|
||||
*
|
||||
* @returns a RFC-3066 format language tag in utf-8.
|
||||
* @see languageChanged
|
||||
**/
|
||||
QByteArray language() const;
|
||||
|
||||
/**
|
||||
* The cursor position inside the {@link composingText} (as byte offset) relative
|
||||
* to the start of the {@link composingText}.
|
||||
* If index is a negative number no cursor is shown.
|
||||
* @see composingText
|
||||
* @see composingTextChanged
|
||||
**/
|
||||
qint32 composingTextCursorPosition() const;
|
||||
|
||||
/**
|
||||
* The currently being composed text around the {@link composingTextCursorPosition}.
|
||||
* @see composingTextCursorPosition
|
||||
* @see composingTextChanged
|
||||
**/
|
||||
QByteArray composingText() const;
|
||||
|
||||
/**
|
||||
* The fallback text can be used to replace the {@link composingText} in some cases
|
||||
* (for example when losing focus).
|
||||
*
|
||||
* @see composingText
|
||||
* @see composingTextChanged
|
||||
**/
|
||||
QByteArray composingFallbackText() const;
|
||||
|
||||
/**
|
||||
* The commit text to be inserted.
|
||||
*
|
||||
* The commit text might be empty if only text should be deleted or the cursor be moved.
|
||||
* @see cursorPosition
|
||||
* @see anchorPosition
|
||||
* @see deleteSurroundingText
|
||||
* @see committed
|
||||
**/
|
||||
QByteArray commitText() const;
|
||||
|
||||
/**
|
||||
* The cursor position in bytes at which the {@link commitText} should be inserted.
|
||||
* @see committed
|
||||
**/
|
||||
qint32 cursorPosition() const;
|
||||
|
||||
/**
|
||||
* The text between anchorPosition and {@link cursorPosition} should be selected.
|
||||
* @see cursorPosition
|
||||
* @see committed
|
||||
**/
|
||||
qint32 anchorPosition() const;
|
||||
|
||||
/**
|
||||
* Holds the length before and after the cursor position to be deleted.
|
||||
**/
|
||||
struct DeleteSurroundingText {
|
||||
quint32 beforeLength;
|
||||
quint32 afterLength;
|
||||
};
|
||||
/**
|
||||
* @returns The length in bytes which should be deleted around the cursor position
|
||||
* @see committed
|
||||
**/
|
||||
DeleteSurroundingText deleteSurroundingText() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted whenever a Surface is focused on this TextInput.
|
||||
* @see enteredSurface
|
||||
* @see left
|
||||
**/
|
||||
void entered();
|
||||
/**
|
||||
* Emitted whenever a Surface loses the focus on this TextInput.
|
||||
* @see enteredSurface
|
||||
* @see entered
|
||||
**/
|
||||
void left();
|
||||
/**
|
||||
* Emitted whenever the state of the input panel (virtual keyboard changes).
|
||||
* @see isInputPanelVisible
|
||||
**/
|
||||
void inputPanelStateChanged();
|
||||
/**
|
||||
* Emitted whenever the text direction changes.
|
||||
* @see textDirection
|
||||
**/
|
||||
void textDirectionChanged();
|
||||
/**
|
||||
* Emitted whenever the language changes.
|
||||
* @see language
|
||||
**/
|
||||
void languageChanged();
|
||||
|
||||
/**
|
||||
* Emitted when a key event was sent.
|
||||
* Key events are not used for normal text input operations, but for specific key symbols
|
||||
* which are not composable through text.
|
||||
*
|
||||
* @param xkbKeySym The XKB key symbol, not a key code
|
||||
* @param state Whether the event represents a press or release event
|
||||
* @param modifiers The hold modifiers on this event
|
||||
* @param time Timestamp of this event
|
||||
**/
|
||||
void keyEvent(quint32 xkbKeySym, KWayland::Client::TextInput::KeyState state, Qt::KeyboardModifiers modifiers, quint32 time);
|
||||
|
||||
/**
|
||||
* Emitted whenever the composing text and related states changed.
|
||||
* @see composingText
|
||||
* @see composingTextCursorPosition
|
||||
* @see composingFallbackText
|
||||
**/
|
||||
void composingTextChanged();
|
||||
|
||||
/**
|
||||
* Emitted when the currently composing text got committed.
|
||||
* The {@link commitText} should get inserted at the {@link cursorPosition} and
|
||||
* the text around {@link deleteSurroundingText} should be deleted.
|
||||
*
|
||||
* @see commitText
|
||||
* @see cursorPosition
|
||||
* @see anchorPosition
|
||||
* @see deleteSurroundingText
|
||||
**/
|
||||
void committed();
|
||||
|
||||
protected:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
explicit TextInput(Private *p, QObject *parent = nullptr);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Manager class for the TextInputManager interfaces.
|
||||
*
|
||||
* The TextInputManager supports multiple interfaces:
|
||||
* @li wl_text_input_manager
|
||||
* @li zwp_text_input_manager_v2
|
||||
*
|
||||
* Due to that it is different to other manager classes. It can only be created through
|
||||
* the corresponding factory method in Registry. A manual setup is not directly possible.
|
||||
*
|
||||
* The only task of a TextInputManager is to create TextInput for a given Seat.
|
||||
*
|
||||
* @since 5.23
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT TextInputManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~TextInputManager() override;
|
||||
|
||||
/**
|
||||
* Setup this TextInputManager to manage the @p textinputmanagerunstablev0.
|
||||
* When using Registry::createTextInputManager there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_text_input_manager *textinputmanagerunstablev0);
|
||||
/**
|
||||
* Setup this TextInputManager to manage the @p textinputmanagerunstablev0.
|
||||
* When using Registry::createTextInputManager there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zwp_text_input_manager_v2 *textinputmanagerunstablev2);
|
||||
/**
|
||||
* @returns @c true if managing a resource.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the interface.
|
||||
* After the interface has been released the TextInputManager instance is no
|
||||
* longer valid and can be setup with another interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this TextInputManager.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* TextInput gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating objects with this TextInputManager.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating objects with this TextInputManager.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Creates a TextInput for the @p seat.
|
||||
*
|
||||
* @param seat The Seat to create the TextInput for
|
||||
* @param parent The parent to use for the TextInput
|
||||
**/
|
||||
TextInput *createTextInput(Seat *seat, QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* @returns @c null if not for a wl_text_input_manager
|
||||
**/
|
||||
operator wl_text_input_manager *();
|
||||
/**
|
||||
* @returns @c null if not for a wl_text_input_manager
|
||||
**/
|
||||
operator wl_text_input_manager *() const;
|
||||
/**
|
||||
* @returns @c null if not for a zwp_text_input_manager_v2
|
||||
**/
|
||||
operator zwp_text_input_manager_v2 *();
|
||||
/**
|
||||
* @returns @c null if not for a zwp_text_input_manager_v2
|
||||
**/
|
||||
operator zwp_text_input_manager_v2 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the TextInputManager got created by
|
||||
* Registry::createTextInputManager
|
||||
**/
|
||||
void removed();
|
||||
|
||||
protected:
|
||||
class Private;
|
||||
explicit TextInputManager(Private *p, QObject *parent = nullptr);
|
||||
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(TextInput::ContentHints)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWayland::Client::TextInput::KeyState)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::TextInput::ContentHint)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::TextInput::ContentPurpose)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::TextInput::ContentHints)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_TEXTINPUT_P_H
|
||||
#define KWAYLAND_CLIENT_TEXTINPUT_P_H
|
||||
#include "textinput.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
struct wl_text_input;
|
||||
struct wl_text_input_manager;
|
||||
struct zwp_text_input_v2;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class TextInputUnstableV0;
|
||||
class Surface;
|
||||
class Seat;
|
||||
|
||||
class TextInputManagerUnstableV0 : public TextInputManager
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new TextInputManagerUnstableV0.
|
||||
* Note: after constructing the TextInputManagerUnstableV0 it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use TextInputManagerUnstableV0 prefer using
|
||||
* Registry::createTextInputManagerUnstableV0.
|
||||
**/
|
||||
explicit TextInputManagerUnstableV0(QObject *parent = nullptr);
|
||||
~TextInputManagerUnstableV0() override;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *d_func() const;
|
||||
};
|
||||
|
||||
class TextInputManagerUnstableV2 : public TextInputManager
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new TextInputManagerUnstableV0.
|
||||
* Note: after constructing the TextInputManagerUnstableV0 it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use TextInputManagerUnstableV0 prefer using
|
||||
* Registry::createTextInputManagerUnstableV0.
|
||||
**/
|
||||
explicit TextInputManagerUnstableV2(QObject *parent = nullptr);
|
||||
~TextInputManagerUnstableV2() override;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
class Q_DECL_HIDDEN TextInputManager::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
virtual ~Private() = default;
|
||||
|
||||
virtual void release() = 0;
|
||||
virtual void destroy() = 0;
|
||||
virtual bool isValid() = 0;
|
||||
virtual void setupV0(wl_text_input_manager *textinputmanagerunstablev0)
|
||||
{
|
||||
Q_UNUSED(textinputmanagerunstablev0)
|
||||
}
|
||||
virtual void setupV2(zwp_text_input_manager_v2 *textinputmanagerunstablev2)
|
||||
{
|
||||
Q_UNUSED(textinputmanagerunstablev2)
|
||||
}
|
||||
virtual TextInput *createTextInput(Seat *seat, QObject *parent = nullptr) = 0;
|
||||
virtual operator wl_text_input_manager *()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator wl_text_input_manager *() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator zwp_text_input_manager_v2 *()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator zwp_text_input_manager_v2 *() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
class Q_DECL_HIDDEN TextInput::Private
|
||||
{
|
||||
public:
|
||||
Private(Seat *seat);
|
||||
virtual ~Private() = default;
|
||||
|
||||
virtual bool isValid() const = 0;
|
||||
virtual void enable(Surface *surface) = 0;
|
||||
virtual void disable(Surface *surface) = 0;
|
||||
virtual void showInputPanel() = 0;
|
||||
virtual void hideInputPanel() = 0;
|
||||
virtual void setCursorRectangle(const QRect &rect) = 0;
|
||||
virtual void setPreferredLanguage(const QString &lang) = 0;
|
||||
virtual void setSurroundingText(const QString &text, quint32 cursor, quint32 anchor) = 0;
|
||||
virtual void reset() = 0;
|
||||
virtual void setContentType(ContentHints hint, ContentPurpose purpose) = 0;
|
||||
|
||||
EventQueue *queue = nullptr;
|
||||
Seat *seat;
|
||||
Surface *enteredSurface = nullptr;
|
||||
quint32 latestSerial = 0;
|
||||
bool inputPanelVisible = false;
|
||||
Qt::LayoutDirection textDirection = Qt::LayoutDirectionAuto;
|
||||
QByteArray language;
|
||||
|
||||
struct PreEdit {
|
||||
QByteArray text;
|
||||
QByteArray commitText;
|
||||
qint32 cursor = 0;
|
||||
bool cursorSet = false;
|
||||
};
|
||||
PreEdit currentPreEdit;
|
||||
PreEdit pendingPreEdit;
|
||||
|
||||
struct Commit {
|
||||
QByteArray text;
|
||||
qint32 cursor = 0;
|
||||
qint32 anchor = 0;
|
||||
DeleteSurroundingText deleteSurrounding;
|
||||
};
|
||||
Commit currentCommit;
|
||||
Commit pendingCommit;
|
||||
};
|
||||
|
||||
class TextInputUnstableV0 : public TextInput
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TextInputUnstableV0(Seat *seat, QObject *parent = nullptr);
|
||||
~TextInputUnstableV0() override;
|
||||
|
||||
/**
|
||||
* Setup this TextInputUnstableV0 to manage the @p textinputunstablev0.
|
||||
* When using TextInputManagerUnstableV0::createTextInputUnstableV0 there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_text_input *textinputunstablev0);
|
||||
/**
|
||||
* Releases the wl_text_input interface.
|
||||
* After the interface has been released the TextInputUnstableV0 instance is no
|
||||
* longer valid and can be setup with another wl_text_input interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this TextInputUnstableV0.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_text_input interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, textinputunstablev0, &TextInputUnstableV0::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
operator wl_text_input *();
|
||||
operator wl_text_input *() const;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *d_func() const;
|
||||
};
|
||||
|
||||
class TextInputUnstableV2 : public TextInput
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TextInputUnstableV2(Seat *seat, QObject *parent = nullptr);
|
||||
~TextInputUnstableV2() override;
|
||||
|
||||
/**
|
||||
* Setup this TextInputUnstableV2 to manage the @p textinputunstablev2.
|
||||
* When using TextInputManagerUnstableV2::createTextInputUnstableV2 there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zwp_text_input_v2 *textinputunstablev2);
|
||||
/**
|
||||
* Releases the zwp_text_input_v2 interface.
|
||||
* After the interface has been released the TextInputUnstableV2 instance is no
|
||||
* longer valid and can be setup with another zwp_text_input_v2 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this TextInputUnstableV2.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zwp_text_input_v2 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, textinputunstablev2, &TextInputUnstableV2::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
operator zwp_text_input_v2 *();
|
||||
operator zwp_text_input_v2 *() const;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
Private *d_func() const;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,496 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "event_queue.h"
|
||||
#include "seat.h"
|
||||
#include "surface.h"
|
||||
#include "textinput_p.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <wayland-text-input-v0-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class TextInputUnstableV0::Private : public TextInput::Private
|
||||
{
|
||||
public:
|
||||
Private(TextInputUnstableV0 *q, Seat *seat);
|
||||
|
||||
void setup(wl_text_input *textinputmanagerunstablev0);
|
||||
|
||||
bool isValid() const override;
|
||||
void enable(Surface *surface) override;
|
||||
void disable(Surface *surface) override;
|
||||
void showInputPanel() override;
|
||||
void hideInputPanel() override;
|
||||
void setCursorRectangle(const QRect &rect) override;
|
||||
void setPreferredLanguage(const QString &lang) override;
|
||||
void setSurroundingText(const QString &text, quint32 cursor, quint32 anchor) override;
|
||||
void reset() override;
|
||||
void setContentType(ContentHints hint, ContentPurpose purpose) override;
|
||||
|
||||
WaylandPointer<wl_text_input, wl_text_input_destroy> textinputunstablev0;
|
||||
|
||||
private:
|
||||
static void enterCallaback(void *data, wl_text_input *wl_text_input, wl_surface *surface);
|
||||
static void leaveCallback(void *data, wl_text_input *wl_text_input);
|
||||
static void modifiersMapCallback(void *data, wl_text_input *wl_text_input, wl_array *map);
|
||||
static void inputPanelStateCallback(void *data, wl_text_input *wl_text_input, uint32_t state);
|
||||
static void preeditStringCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, const char *text, const char *commit);
|
||||
static void preeditStylingCallback(void *data, wl_text_input *wl_text_input, uint32_t index, uint32_t length, uint32_t style);
|
||||
static void preeditCursorCallback(void *data, wl_text_input *wl_text_input, int32_t index);
|
||||
static void commitStringCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, const char *text);
|
||||
static void cursorPositionCallback(void *data, wl_text_input *wl_text_input, int32_t index, int32_t anchor);
|
||||
static void deleteSurroundingTextCallback(void *data, wl_text_input *wl_text_input, int32_t index, uint32_t length);
|
||||
static void keysymCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers);
|
||||
static void languageCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, const char *language);
|
||||
static void textDirectionCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, uint32_t direction);
|
||||
|
||||
TextInputUnstableV0 *q;
|
||||
|
||||
static const wl_text_input_listener s_listener;
|
||||
};
|
||||
|
||||
const wl_text_input_listener TextInputUnstableV0::Private::s_listener = {enterCallaback,
|
||||
leaveCallback,
|
||||
modifiersMapCallback,
|
||||
inputPanelStateCallback,
|
||||
preeditStringCallback,
|
||||
preeditStylingCallback,
|
||||
preeditCursorCallback,
|
||||
commitStringCallback,
|
||||
cursorPositionCallback,
|
||||
deleteSurroundingTextCallback,
|
||||
keysymCallback,
|
||||
languageCallback,
|
||||
textDirectionCallback};
|
||||
|
||||
void TextInputUnstableV0::Private::enterCallaback(void *data, wl_text_input *wl_text_input, wl_surface *surface)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev0 == wl_text_input);
|
||||
t->enteredSurface = Surface::get(surface);
|
||||
Q_EMIT t->q->entered();
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::leaveCallback(void *data, wl_text_input *wl_text_input)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev0 == wl_text_input);
|
||||
t->enteredSurface = nullptr;
|
||||
Q_EMIT t->q->left();
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::modifiersMapCallback(void *data, wl_text_input *wl_text_input, wl_array *map)
|
||||
{
|
||||
Q_UNUSED(map)
|
||||
auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev0 == wl_text_input);
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::inputPanelStateCallback(void *data, wl_text_input *wl_text_input, uint32_t state)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev0 == wl_text_input);
|
||||
if (t->inputPanelVisible != state) {
|
||||
t->inputPanelVisible = state;
|
||||
Q_EMIT t->q->inputPanelStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::preeditStringCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, const char *text, const char *commit)
|
||||
{
|
||||
Q_UNUSED(serial)
|
||||
auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev0 == wl_text_input);
|
||||
t->pendingPreEdit.commitText = QByteArray(commit);
|
||||
t->pendingPreEdit.text = QByteArray(text);
|
||||
if (!t->pendingPreEdit.cursorSet) {
|
||||
t->pendingPreEdit.cursor = t->pendingPreEdit.text.length();
|
||||
}
|
||||
t->currentPreEdit = t->pendingPreEdit;
|
||||
t->pendingPreEdit = TextInput::Private::PreEdit();
|
||||
Q_EMIT t->q->composingTextChanged();
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::preeditStylingCallback(void *data, wl_text_input *wl_text_input, uint32_t index, uint32_t length, uint32_t style)
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
Q_UNUSED(length)
|
||||
Q_UNUSED(style)
|
||||
// TODO: implement
|
||||
auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev0 == wl_text_input);
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::preeditCursorCallback(void *data, wl_text_input *wl_text_input, int32_t index)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev0 == wl_text_input);
|
||||
t->pendingPreEdit.cursor = index;
|
||||
t->pendingPreEdit.cursorSet = true;
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::commitStringCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, const char *text)
|
||||
{
|
||||
Q_UNUSED(serial)
|
||||
auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev0 == wl_text_input);
|
||||
t->pendingCommit.text = QByteArray(text);
|
||||
t->currentCommit = t->pendingCommit;
|
||||
// TODO: what are the proper values it should be set to?
|
||||
t->pendingCommit = TextInput::Private::Commit();
|
||||
t->pendingCommit.deleteSurrounding.beforeLength = 0;
|
||||
t->pendingCommit.deleteSurrounding.afterLength = 0;
|
||||
Q_EMIT t->q->committed();
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::cursorPositionCallback(void *data, wl_text_input *wl_text_input, int32_t index, int32_t anchor)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev0 == wl_text_input);
|
||||
t->pendingCommit.cursor = index;
|
||||
t->pendingCommit.anchor = anchor;
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::deleteSurroundingTextCallback(void *data, wl_text_input *wl_text_input, int32_t index, uint32_t length)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev0 == wl_text_input);
|
||||
t->pendingCommit.deleteSurrounding.beforeLength = qAbs(index);
|
||||
t->pendingCommit.deleteSurrounding.afterLength = length - t->pendingCommit.deleteSurrounding.beforeLength;
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::keysymCallback(void *data,
|
||||
wl_text_input *wl_text_input,
|
||||
uint32_t serial,
|
||||
uint32_t time,
|
||||
uint32_t sym,
|
||||
uint32_t wlState,
|
||||
uint32_t modifiers)
|
||||
{
|
||||
Q_UNUSED(serial)
|
||||
// TODO: add support for modifiers
|
||||
Q_UNUSED(modifiers)
|
||||
auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev0 == wl_text_input);
|
||||
TextInput::KeyState state;
|
||||
switch (wlState) {
|
||||
case WL_KEYBOARD_KEY_STATE_RELEASED:
|
||||
state = TextInput::KeyState::Released;
|
||||
break;
|
||||
case WL_KEYBOARD_KEY_STATE_PRESSED:
|
||||
state = TextInput::KeyState::Pressed;
|
||||
break;
|
||||
default:
|
||||
// invalid
|
||||
return;
|
||||
}
|
||||
Q_EMIT t->q->keyEvent(sym, state, Qt::KeyboardModifiers(), time);
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::languageCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, const char *language)
|
||||
{
|
||||
Q_UNUSED(serial)
|
||||
auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev0 == wl_text_input);
|
||||
if (qstrcmp(t->language, language) != 0) {
|
||||
t->language = QByteArray(language);
|
||||
Q_EMIT t->q->languageChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::textDirectionCallback(void *data, wl_text_input *wl_text_input, uint32_t serial, uint32_t wlDirection)
|
||||
{
|
||||
Q_UNUSED(serial)
|
||||
auto t = reinterpret_cast<TextInputUnstableV0::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev0 == wl_text_input);
|
||||
Qt::LayoutDirection direction;
|
||||
switch (wlDirection) {
|
||||
case WL_TEXT_INPUT_TEXT_DIRECTION_LTR:
|
||||
direction = Qt::LeftToRight;
|
||||
break;
|
||||
case WL_TEXT_INPUT_TEXT_DIRECTION_RTL:
|
||||
direction = Qt::RightToLeft;
|
||||
break;
|
||||
case WL_TEXT_INPUT_TEXT_DIRECTION_AUTO:
|
||||
direction = Qt::LayoutDirectionAuto;
|
||||
break;
|
||||
default:
|
||||
// invalid
|
||||
return;
|
||||
}
|
||||
if (direction != t->textDirection) {
|
||||
t->textDirection = direction;
|
||||
Q_EMIT t->q->textDirectionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
TextInputUnstableV0::Private::Private(TextInputUnstableV0 *q, Seat *seat)
|
||||
: TextInput::Private(seat)
|
||||
, q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::setup(wl_text_input *ti)
|
||||
{
|
||||
Q_ASSERT(ti);
|
||||
Q_ASSERT(!textinputunstablev0);
|
||||
textinputunstablev0.setup(ti);
|
||||
wl_text_input_add_listener(ti, &s_listener, this);
|
||||
}
|
||||
|
||||
bool TextInputUnstableV0::Private::isValid() const
|
||||
{
|
||||
return textinputunstablev0.isValid();
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::enable(Surface *surface)
|
||||
{
|
||||
wl_text_input_activate(textinputunstablev0, *seat, *surface);
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::disable(Surface *surface)
|
||||
{
|
||||
Q_UNUSED(surface)
|
||||
wl_text_input_deactivate(textinputunstablev0, *seat);
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::showInputPanel()
|
||||
{
|
||||
wl_text_input_show_input_panel(textinputunstablev0);
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::hideInputPanel()
|
||||
{
|
||||
wl_text_input_hide_input_panel(textinputunstablev0);
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::setCursorRectangle(const QRect &rect)
|
||||
{
|
||||
wl_text_input_set_cursor_rectangle(textinputunstablev0, rect.x(), rect.y(), rect.width(), rect.height());
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::setPreferredLanguage(const QString &lang)
|
||||
{
|
||||
wl_text_input_set_preferred_language(textinputunstablev0, lang.toUtf8().constData());
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::setSurroundingText(const QString &text, quint32 cursor, quint32 anchor)
|
||||
{
|
||||
const QStringView strView(text);
|
||||
|
||||
wl_text_input_set_surrounding_text(textinputunstablev0,
|
||||
text.toUtf8().constData(),
|
||||
strView.left(cursor).toUtf8().length(),
|
||||
strView.left(anchor).toUtf8().length());
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::reset()
|
||||
{
|
||||
wl_text_input_reset(textinputunstablev0);
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::Private::setContentType(ContentHints hints, ContentPurpose purpose)
|
||||
{
|
||||
uint32_t wlHints = 0;
|
||||
uint32_t wlPurpose = 0;
|
||||
if (hints.testFlag(ContentHint::AutoCompletion)) {
|
||||
wlHints |= WL_TEXT_INPUT_CONTENT_HINT_AUTO_COMPLETION;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::AutoCorrection)) {
|
||||
wlHints |= WL_TEXT_INPUT_CONTENT_HINT_AUTO_CORRECTION;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::AutoCapitalization)) {
|
||||
wlHints |= WL_TEXT_INPUT_CONTENT_HINT_AUTO_CAPITALIZATION;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::LowerCase)) {
|
||||
wlHints |= WL_TEXT_INPUT_CONTENT_HINT_LOWERCASE;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::UpperCase)) {
|
||||
wlHints |= WL_TEXT_INPUT_CONTENT_HINT_UPPERCASE;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::TitleCase)) {
|
||||
wlHints |= WL_TEXT_INPUT_CONTENT_HINT_TITLECASE;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::HiddenText)) {
|
||||
wlHints |= WL_TEXT_INPUT_CONTENT_HINT_HIDDEN_TEXT;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::SensitiveData)) {
|
||||
wlHints |= WL_TEXT_INPUT_CONTENT_HINT_SENSITIVE_DATA;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::Latin)) {
|
||||
wlHints |= WL_TEXT_INPUT_CONTENT_HINT_LATIN;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::MultiLine)) {
|
||||
wlHints |= WL_TEXT_INPUT_CONTENT_HINT_MULTILINE;
|
||||
}
|
||||
switch (purpose) {
|
||||
case ContentPurpose::Normal:
|
||||
wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NORMAL;
|
||||
break;
|
||||
case ContentPurpose::Alpha:
|
||||
wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_ALPHA;
|
||||
break;
|
||||
case ContentPurpose::Digits:
|
||||
wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DIGITS;
|
||||
break;
|
||||
case ContentPurpose::Number:
|
||||
wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NUMBER;
|
||||
break;
|
||||
case ContentPurpose::Phone:
|
||||
wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_PHONE;
|
||||
break;
|
||||
case ContentPurpose::Url:
|
||||
wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_URL;
|
||||
break;
|
||||
case ContentPurpose::Email:
|
||||
wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_EMAIL;
|
||||
break;
|
||||
case ContentPurpose::Name:
|
||||
wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_NAME;
|
||||
break;
|
||||
case ContentPurpose::Password:
|
||||
wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_PASSWORD;
|
||||
break;
|
||||
case ContentPurpose::Date:
|
||||
wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DATE;
|
||||
break;
|
||||
case ContentPurpose::Time:
|
||||
wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_TIME;
|
||||
break;
|
||||
case ContentPurpose::DateTime:
|
||||
wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_DATETIME;
|
||||
break;
|
||||
case ContentPurpose::Terminal:
|
||||
wlPurpose = WL_TEXT_INPUT_CONTENT_PURPOSE_TERMINAL;
|
||||
break;
|
||||
}
|
||||
wl_text_input_set_content_type(textinputunstablev0, wlHints, wlPurpose);
|
||||
}
|
||||
|
||||
TextInputUnstableV0::TextInputUnstableV0(Seat *seat, QObject *parent)
|
||||
: TextInput(new Private(this, seat), parent)
|
||||
{
|
||||
}
|
||||
|
||||
TextInputUnstableV0::~TextInputUnstableV0()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
TextInputUnstableV0::Private *TextInputUnstableV0::d_func() const
|
||||
{
|
||||
return reinterpret_cast<Private *>(d.data());
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::setup(wl_text_input *textinputunstablev0)
|
||||
{
|
||||
Q_D();
|
||||
d->setup(textinputunstablev0);
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::release()
|
||||
{
|
||||
Q_D();
|
||||
d->textinputunstablev0.release();
|
||||
}
|
||||
|
||||
void TextInputUnstableV0::destroy()
|
||||
{
|
||||
Q_D();
|
||||
d->textinputunstablev0.destroy();
|
||||
}
|
||||
|
||||
TextInputUnstableV0::operator wl_text_input *()
|
||||
{
|
||||
Q_D();
|
||||
return d->textinputunstablev0;
|
||||
}
|
||||
|
||||
TextInputUnstableV0::operator wl_text_input *() const
|
||||
{
|
||||
Q_D();
|
||||
return d->textinputunstablev0;
|
||||
}
|
||||
|
||||
class TextInputManagerUnstableV0::Private : public TextInputManager::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() override;
|
||||
void setupV0(wl_text_input_manager *ti) override;
|
||||
TextInput *createTextInput(Seat *seat, QObject *parent = nullptr) override;
|
||||
using TextInputManager::Private::operator zwp_text_input_manager_v2 *; // overriding only one overload results in a compiler warning. This tells GCC we're
|
||||
// doing it deliberately
|
||||
operator wl_text_input_manager *() override
|
||||
{
|
||||
return textinputmanagerunstablev0;
|
||||
}
|
||||
operator wl_text_input_manager *() const override
|
||||
{
|
||||
return textinputmanagerunstablev0;
|
||||
}
|
||||
|
||||
WaylandPointer<wl_text_input_manager, wl_text_input_manager_destroy> textinputmanagerunstablev0;
|
||||
};
|
||||
|
||||
void TextInputManagerUnstableV0::Private::release()
|
||||
{
|
||||
textinputmanagerunstablev0.release();
|
||||
}
|
||||
|
||||
void TextInputManagerUnstableV0::Private::destroy()
|
||||
{
|
||||
textinputmanagerunstablev0.destroy();
|
||||
}
|
||||
|
||||
bool TextInputManagerUnstableV0::Private::isValid()
|
||||
{
|
||||
return textinputmanagerunstablev0.isValid();
|
||||
}
|
||||
|
||||
TextInputManagerUnstableV0::TextInputManagerUnstableV0(QObject *parent)
|
||||
: TextInputManager(new Private, parent)
|
||||
{
|
||||
}
|
||||
|
||||
TextInputManagerUnstableV0::Private *TextInputManagerUnstableV0::d_func() const
|
||||
{
|
||||
return reinterpret_cast<Private *>(d.data());
|
||||
}
|
||||
|
||||
TextInputManagerUnstableV0::~TextInputManagerUnstableV0()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void TextInputManagerUnstableV0::Private::setupV0(wl_text_input_manager *ti)
|
||||
{
|
||||
Q_ASSERT(ti);
|
||||
Q_ASSERT(!textinputmanagerunstablev0);
|
||||
textinputmanagerunstablev0.setup(ti);
|
||||
}
|
||||
|
||||
TextInput *TextInputManagerUnstableV0::Private::createTextInput(Seat *seat, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
TextInputUnstableV0 *t = new TextInputUnstableV0(seat, parent);
|
||||
auto w = wl_text_input_manager_create_text_input(textinputmanagerunstablev0);
|
||||
if (queue) {
|
||||
queue->addProxy(w);
|
||||
}
|
||||
t->setup(w);
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,522 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "event_queue.h"
|
||||
#include "seat.h"
|
||||
#include "surface.h"
|
||||
#include "textinput_p.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <wayland-text-input-v2-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class TextInputUnstableV2::Private : public TextInput::Private
|
||||
{
|
||||
public:
|
||||
Private(TextInputUnstableV2 *q, Seat *seat);
|
||||
|
||||
void setup(zwp_text_input_v2 *textinputmanagerunstablev0);
|
||||
|
||||
bool isValid() const override;
|
||||
void enable(Surface *surface) override;
|
||||
void disable(Surface *surface) override;
|
||||
void showInputPanel() override;
|
||||
void hideInputPanel() override;
|
||||
void setCursorRectangle(const QRect &rect) override;
|
||||
void setPreferredLanguage(const QString &lang) override;
|
||||
void setSurroundingText(const QString &text, quint32 cursor, quint32 anchor) override;
|
||||
void reset() override;
|
||||
void setContentType(ContentHints hint, ContentPurpose purpose) override;
|
||||
|
||||
WaylandPointer<zwp_text_input_v2, zwp_text_input_v2_destroy> textinputunstablev2;
|
||||
|
||||
private:
|
||||
static void enterCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t serial, wl_surface *surface);
|
||||
static void leaveCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t serial, wl_surface *surface);
|
||||
static void inputPanelStateCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t state, int32_t x, int32_t y, int32_t width, int32_t height);
|
||||
static void preeditStringCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, const char *text, const char *commit);
|
||||
static void preeditStylingCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t index, uint32_t length, uint32_t style);
|
||||
static void preeditCursorCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, int32_t index);
|
||||
static void commitStringCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, const char *text);
|
||||
static void cursorPositionCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, int32_t index, int32_t anchor);
|
||||
static void deleteSurroundingTextCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t before_length, uint32_t after_length);
|
||||
static void modifiersMapCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, wl_array *map);
|
||||
static void keysymCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t time, uint32_t sym, uint32_t state, uint32_t modifiers);
|
||||
static void languageCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, const char *language);
|
||||
static void textDirectionCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t direction);
|
||||
static void configureSurroundingTextCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, int32_t before_cursor, int32_t after_cursor);
|
||||
static void inputMethodChangedCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t serial, uint32_t flags);
|
||||
|
||||
TextInputUnstableV2 *q;
|
||||
|
||||
static const zwp_text_input_v2_listener s_listener;
|
||||
};
|
||||
|
||||
const zwp_text_input_v2_listener TextInputUnstableV2::Private::s_listener = {enterCallback,
|
||||
leaveCallback,
|
||||
inputPanelStateCallback,
|
||||
preeditStringCallback,
|
||||
preeditStylingCallback,
|
||||
preeditCursorCallback,
|
||||
commitStringCallback,
|
||||
cursorPositionCallback,
|
||||
deleteSurroundingTextCallback,
|
||||
modifiersMapCallback,
|
||||
keysymCallback,
|
||||
languageCallback,
|
||||
textDirectionCallback,
|
||||
configureSurroundingTextCallback,
|
||||
inputMethodChangedCallback};
|
||||
|
||||
void TextInputUnstableV2::Private::enterCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t serial, wl_surface *surface)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
t->latestSerial = serial;
|
||||
t->enteredSurface = Surface::get(surface);
|
||||
Q_EMIT t->q->entered();
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::leaveCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t serial, wl_surface *surface)
|
||||
{
|
||||
Q_UNUSED(surface)
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
t->enteredSurface = nullptr;
|
||||
t->latestSerial = serial;
|
||||
Q_EMIT t->q->left();
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::inputPanelStateCallback(void *data,
|
||||
zwp_text_input_v2 *zwp_text_input_v2,
|
||||
uint32_t state,
|
||||
int32_t x,
|
||||
int32_t y,
|
||||
int32_t width,
|
||||
int32_t height)
|
||||
{
|
||||
Q_UNUSED(x)
|
||||
Q_UNUSED(y)
|
||||
Q_UNUSED(width)
|
||||
Q_UNUSED(height)
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
// TODO: add rect
|
||||
if (t->inputPanelVisible != state) {
|
||||
t->inputPanelVisible = state;
|
||||
Q_EMIT t->q->inputPanelStateChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::preeditStringCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, const char *text, const char *commit)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
t->pendingPreEdit.commitText = QByteArray(commit);
|
||||
t->pendingPreEdit.text = QByteArray(text);
|
||||
if (!t->pendingPreEdit.cursorSet) {
|
||||
t->pendingPreEdit.cursor = t->pendingPreEdit.text.length();
|
||||
}
|
||||
t->currentPreEdit = t->pendingPreEdit;
|
||||
t->pendingPreEdit = TextInput::Private::PreEdit();
|
||||
Q_EMIT t->q->composingTextChanged();
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::preeditStylingCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t index, uint32_t length, uint32_t style)
|
||||
{
|
||||
Q_UNUSED(index)
|
||||
Q_UNUSED(length)
|
||||
Q_UNUSED(style)
|
||||
// TODO: implement
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::preeditCursorCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, int32_t index)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
t->pendingPreEdit.cursor = index;
|
||||
t->pendingPreEdit.cursorSet = true;
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::commitStringCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, const char *text)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
t->pendingCommit.text = QByteArray(text);
|
||||
t->currentCommit = t->pendingCommit;
|
||||
// TODO: what are the proper values it should be set to?
|
||||
t->pendingCommit = TextInput::Private::Commit();
|
||||
t->pendingCommit.deleteSurrounding.beforeLength = 0;
|
||||
t->pendingCommit.deleteSurrounding.afterLength = 0;
|
||||
Q_EMIT t->q->committed();
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::cursorPositionCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, int32_t index, int32_t anchor)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
t->pendingCommit.cursor = index;
|
||||
t->pendingCommit.anchor = anchor;
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::deleteSurroundingTextCallback(void *data,
|
||||
zwp_text_input_v2 *zwp_text_input_v2,
|
||||
uint32_t before_length,
|
||||
uint32_t after_length)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
t->pendingCommit.deleteSurrounding.beforeLength = before_length;
|
||||
t->pendingCommit.deleteSurrounding.afterLength = after_length;
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::modifiersMapCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, wl_array *map)
|
||||
{
|
||||
// TODO: implement
|
||||
Q_UNUSED(map)
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::keysymCallback(void *data,
|
||||
zwp_text_input_v2 *zwp_text_input_v2,
|
||||
uint32_t time,
|
||||
uint32_t sym,
|
||||
uint32_t wlState,
|
||||
uint32_t modifiers)
|
||||
{
|
||||
// TODO: add support for modifiers
|
||||
Q_UNUSED(modifiers)
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
TextInput::KeyState state;
|
||||
switch (wlState) {
|
||||
case WL_KEYBOARD_KEY_STATE_RELEASED:
|
||||
state = TextInput::KeyState::Released;
|
||||
break;
|
||||
case WL_KEYBOARD_KEY_STATE_PRESSED:
|
||||
state = TextInput::KeyState::Pressed;
|
||||
break;
|
||||
default:
|
||||
// invalid
|
||||
return;
|
||||
}
|
||||
Q_EMIT t->q->keyEvent(sym, state, Qt::KeyboardModifiers(), time);
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::languageCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, const char *language)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
if (qstrcmp(t->language, language) != 0) {
|
||||
t->language = QByteArray(language);
|
||||
Q_EMIT t->q->languageChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::textDirectionCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t wlDirection)
|
||||
{
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
Qt::LayoutDirection direction;
|
||||
switch (wlDirection) {
|
||||
case ZWP_TEXT_INPUT_V2_TEXT_DIRECTION_LTR:
|
||||
direction = Qt::LeftToRight;
|
||||
break;
|
||||
case ZWP_TEXT_INPUT_V2_TEXT_DIRECTION_RTL:
|
||||
direction = Qt::RightToLeft;
|
||||
break;
|
||||
case ZWP_TEXT_INPUT_V2_TEXT_DIRECTION_AUTO:
|
||||
direction = Qt::LayoutDirectionAuto;
|
||||
break;
|
||||
default:
|
||||
// invalid
|
||||
return;
|
||||
}
|
||||
if (direction != t->textDirection) {
|
||||
t->textDirection = direction;
|
||||
Q_EMIT t->q->textDirectionChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::configureSurroundingTextCallback(void *data,
|
||||
zwp_text_input_v2 *zwp_text_input_v2,
|
||||
int32_t before_cursor,
|
||||
int32_t after_cursor)
|
||||
{
|
||||
// TODO: implement
|
||||
Q_UNUSED(before_cursor)
|
||||
Q_UNUSED(after_cursor)
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::inputMethodChangedCallback(void *data, zwp_text_input_v2 *zwp_text_input_v2, uint32_t serial, uint32_t flags)
|
||||
{
|
||||
Q_UNUSED(serial)
|
||||
Q_UNUSED(flags)
|
||||
// TODO: implement
|
||||
auto t = reinterpret_cast<TextInputUnstableV2::Private *>(data);
|
||||
Q_ASSERT(t->textinputunstablev2 == zwp_text_input_v2);
|
||||
}
|
||||
|
||||
TextInputUnstableV2::Private::Private(TextInputUnstableV2 *q, Seat *seat)
|
||||
: TextInput::Private(seat)
|
||||
, q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::setup(zwp_text_input_v2 *ti)
|
||||
{
|
||||
Q_ASSERT(ti);
|
||||
Q_ASSERT(!textinputunstablev2);
|
||||
textinputunstablev2.setup(ti);
|
||||
zwp_text_input_v2_add_listener(ti, &s_listener, this);
|
||||
}
|
||||
|
||||
bool TextInputUnstableV2::Private::isValid() const
|
||||
{
|
||||
return textinputunstablev2.isValid();
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::enable(Surface *surface)
|
||||
{
|
||||
zwp_text_input_v2_enable(textinputunstablev2, *surface);
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::disable(Surface *surface)
|
||||
{
|
||||
zwp_text_input_v2_disable(textinputunstablev2, *surface);
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::showInputPanel()
|
||||
{
|
||||
zwp_text_input_v2_show_input_panel(textinputunstablev2);
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::hideInputPanel()
|
||||
{
|
||||
zwp_text_input_v2_hide_input_panel(textinputunstablev2);
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::setCursorRectangle(const QRect &rect)
|
||||
{
|
||||
zwp_text_input_v2_set_cursor_rectangle(textinputunstablev2, rect.x(), rect.y(), rect.width(), rect.height());
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::setPreferredLanguage(const QString &lang)
|
||||
{
|
||||
zwp_text_input_v2_set_preferred_language(textinputunstablev2, lang.toUtf8().constData());
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::setSurroundingText(const QString &text, quint32 cursor, quint32 anchor)
|
||||
{
|
||||
const QStringView strView(text);
|
||||
|
||||
zwp_text_input_v2_set_surrounding_text(textinputunstablev2,
|
||||
text.toUtf8().constData(),
|
||||
strView.left(cursor).toUtf8().length(),
|
||||
strView.left(anchor).toUtf8().length());
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::reset()
|
||||
{
|
||||
zwp_text_input_v2_update_state(textinputunstablev2, latestSerial, ZWP_TEXT_INPUT_V2_UPDATE_STATE_RESET);
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::Private::setContentType(ContentHints hints, ContentPurpose purpose)
|
||||
{
|
||||
uint32_t wlHints = 0;
|
||||
uint32_t wlPurpose = 0;
|
||||
if (hints.testFlag(ContentHint::AutoCompletion)) {
|
||||
wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_COMPLETION;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::AutoCorrection)) {
|
||||
wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CORRECTION;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::AutoCapitalization)) {
|
||||
wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_AUTO_CAPITALIZATION;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::LowerCase)) {
|
||||
wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LOWERCASE;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::UpperCase)) {
|
||||
wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_UPPERCASE;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::TitleCase)) {
|
||||
wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_TITLECASE;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::HiddenText)) {
|
||||
wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_HIDDEN_TEXT;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::SensitiveData)) {
|
||||
wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_SENSITIVE_DATA;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::Latin)) {
|
||||
wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_LATIN;
|
||||
}
|
||||
if (hints.testFlag(ContentHint::MultiLine)) {
|
||||
wlHints |= ZWP_TEXT_INPUT_V2_CONTENT_HINT_MULTILINE;
|
||||
}
|
||||
switch (purpose) {
|
||||
case ContentPurpose::Normal:
|
||||
wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NORMAL;
|
||||
break;
|
||||
case ContentPurpose::Alpha:
|
||||
wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_ALPHA;
|
||||
break;
|
||||
case ContentPurpose::Digits:
|
||||
wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DIGITS;
|
||||
break;
|
||||
case ContentPurpose::Number:
|
||||
wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NUMBER;
|
||||
break;
|
||||
case ContentPurpose::Phone:
|
||||
wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_PHONE;
|
||||
break;
|
||||
case ContentPurpose::Url:
|
||||
wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_URL;
|
||||
break;
|
||||
case ContentPurpose::Email:
|
||||
wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_EMAIL;
|
||||
break;
|
||||
case ContentPurpose::Name:
|
||||
wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_NAME;
|
||||
break;
|
||||
case ContentPurpose::Password:
|
||||
wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_PASSWORD;
|
||||
break;
|
||||
case ContentPurpose::Date:
|
||||
wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATE;
|
||||
break;
|
||||
case ContentPurpose::Time:
|
||||
wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_TIME;
|
||||
break;
|
||||
case ContentPurpose::DateTime:
|
||||
wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_DATETIME;
|
||||
break;
|
||||
case ContentPurpose::Terminal:
|
||||
wlPurpose = ZWP_TEXT_INPUT_V2_CONTENT_PURPOSE_TERMINAL;
|
||||
break;
|
||||
}
|
||||
zwp_text_input_v2_set_content_type(textinputunstablev2, wlHints, wlPurpose);
|
||||
}
|
||||
|
||||
TextInputUnstableV2::TextInputUnstableV2(Seat *seat, QObject *parent)
|
||||
: TextInput(new Private(this, seat), parent)
|
||||
{
|
||||
}
|
||||
|
||||
TextInputUnstableV2::~TextInputUnstableV2()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
TextInputUnstableV2::Private *TextInputUnstableV2::d_func() const
|
||||
{
|
||||
return reinterpret_cast<Private *>(d.data());
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::setup(zwp_text_input_v2 *textinputunstablev2)
|
||||
{
|
||||
Q_D();
|
||||
d->setup(textinputunstablev2);
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::release()
|
||||
{
|
||||
Q_D();
|
||||
d->textinputunstablev2.release();
|
||||
}
|
||||
|
||||
void TextInputUnstableV2::destroy()
|
||||
{
|
||||
Q_D();
|
||||
d->textinputunstablev2.destroy();
|
||||
}
|
||||
|
||||
TextInputUnstableV2::operator zwp_text_input_v2 *()
|
||||
{
|
||||
Q_D();
|
||||
return d->textinputunstablev2;
|
||||
}
|
||||
|
||||
TextInputUnstableV2::operator zwp_text_input_v2 *() const
|
||||
{
|
||||
Q_D();
|
||||
return d->textinputunstablev2;
|
||||
}
|
||||
|
||||
class TextInputManagerUnstableV2::Private : public TextInputManager::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() override;
|
||||
void setupV2(zwp_text_input_manager_v2 *ti) override;
|
||||
TextInput *createTextInput(Seat *seat, QObject *parent = nullptr) override;
|
||||
using TextInputManager::Private::operator wl_text_input_manager *;
|
||||
operator zwp_text_input_manager_v2 *() override
|
||||
{
|
||||
return textinputmanagerunstablev2;
|
||||
}
|
||||
operator zwp_text_input_manager_v2 *() const override
|
||||
{
|
||||
return textinputmanagerunstablev2;
|
||||
}
|
||||
|
||||
WaylandPointer<zwp_text_input_manager_v2, zwp_text_input_manager_v2_destroy> textinputmanagerunstablev2;
|
||||
};
|
||||
|
||||
void TextInputManagerUnstableV2::Private::release()
|
||||
{
|
||||
textinputmanagerunstablev2.release();
|
||||
}
|
||||
|
||||
void TextInputManagerUnstableV2::Private::destroy()
|
||||
{
|
||||
textinputmanagerunstablev2.destroy();
|
||||
}
|
||||
|
||||
bool TextInputManagerUnstableV2::Private::isValid()
|
||||
{
|
||||
return textinputmanagerunstablev2.isValid();
|
||||
}
|
||||
|
||||
TextInputManagerUnstableV2::TextInputManagerUnstableV2(QObject *parent)
|
||||
: TextInputManager(new Private, parent)
|
||||
{
|
||||
}
|
||||
|
||||
TextInputManagerUnstableV2::~TextInputManagerUnstableV2() = default;
|
||||
|
||||
void TextInputManagerUnstableV2::Private::setupV2(zwp_text_input_manager_v2 *ti)
|
||||
{
|
||||
Q_ASSERT(ti);
|
||||
Q_ASSERT(!textinputmanagerunstablev2);
|
||||
textinputmanagerunstablev2.setup(ti);
|
||||
}
|
||||
|
||||
TextInput *TextInputManagerUnstableV2::Private::createTextInput(Seat *seat, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
TextInputUnstableV2 *t = new TextInputUnstableV2(seat, parent);
|
||||
auto w = zwp_text_input_manager_v2_get_text_input(textinputmanagerunstablev2, *seat);
|
||||
if (queue) {
|
||||
queue->addProxy(w);
|
||||
}
|
||||
t->setup(w);
|
||||
return t;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,277 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "touch.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
// Qt
|
||||
#include <QList>
|
||||
#include <QPointF>
|
||||
#include <QPointer>
|
||||
// wayland
|
||||
#include <wayland-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN Touch::Private
|
||||
{
|
||||
public:
|
||||
Private(Touch *q);
|
||||
void setup(wl_touch *t);
|
||||
WaylandPointer<wl_touch, wl_touch_release> touch;
|
||||
bool active = false;
|
||||
QList<TouchPoint *> sequence;
|
||||
TouchPoint *getActivePoint(qint32 id) const;
|
||||
|
||||
private:
|
||||
static void downCallback(void *data, wl_touch *touch, uint32_t serial, uint32_t time, wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y);
|
||||
static void upCallback(void *data, wl_touch *touch, uint32_t serial, uint32_t time, int32_t id);
|
||||
static void motionCallback(void *data, wl_touch *touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y);
|
||||
static void frameCallback(void *data, wl_touch *touch);
|
||||
static void cancelCallback(void *data, wl_touch *touch);
|
||||
void down(quint32 serial, quint32 time, qint32 id, const QPointF &position, const QPointer<Surface> &surface);
|
||||
void up(quint32 serial, quint32 time, qint32 id);
|
||||
void motion(quint32 time, qint32 id, const QPointF &position);
|
||||
|
||||
Touch *q;
|
||||
static const wl_touch_listener s_listener;
|
||||
};
|
||||
|
||||
class TouchPoint::Private
|
||||
{
|
||||
public:
|
||||
qint32 id = 0;
|
||||
quint32 downSerial = 0;
|
||||
quint32 upSerial = 0;
|
||||
QPointer<Surface> surface;
|
||||
QList<QPointF> positions;
|
||||
QList<quint32> timestamps;
|
||||
bool down = true;
|
||||
};
|
||||
|
||||
TouchPoint::TouchPoint()
|
||||
: d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
TouchPoint::~TouchPoint() = default;
|
||||
|
||||
QPointF TouchPoint::position() const
|
||||
{
|
||||
if (d->positions.isEmpty()) {
|
||||
return QPointF();
|
||||
}
|
||||
return d->positions.last();
|
||||
}
|
||||
|
||||
QList<QPointF> TouchPoint::positions() const
|
||||
{
|
||||
return d->positions;
|
||||
}
|
||||
|
||||
quint32 TouchPoint::downSerial() const
|
||||
{
|
||||
return d->downSerial;
|
||||
}
|
||||
|
||||
quint32 TouchPoint::upSerial() const
|
||||
{
|
||||
return d->upSerial;
|
||||
}
|
||||
|
||||
QPointer<Surface> TouchPoint::surface() const
|
||||
{
|
||||
return d->surface;
|
||||
}
|
||||
|
||||
quint32 TouchPoint::time() const
|
||||
{
|
||||
if (d->timestamps.isEmpty()) {
|
||||
return 0;
|
||||
}
|
||||
return d->timestamps.last();
|
||||
}
|
||||
|
||||
QList<quint32> TouchPoint::timestamps() const
|
||||
{
|
||||
return d->timestamps;
|
||||
}
|
||||
|
||||
bool TouchPoint::isDown() const
|
||||
{
|
||||
return d->down;
|
||||
}
|
||||
|
||||
qint32 TouchPoint::id() const
|
||||
{
|
||||
return d->id;
|
||||
}
|
||||
|
||||
Touch::Private::Private(Touch *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
void Touch::Private::setup(wl_touch *t)
|
||||
{
|
||||
Q_ASSERT(t);
|
||||
Q_ASSERT(!touch);
|
||||
touch.setup(t);
|
||||
wl_touch_add_listener(touch, &s_listener, this);
|
||||
}
|
||||
|
||||
const wl_touch_listener Touch::Private::s_listener = {downCallback, upCallback, motionCallback, frameCallback, cancelCallback};
|
||||
|
||||
void Touch::Private::downCallback(void *data, wl_touch *touch, uint32_t serial, uint32_t time, wl_surface *surface, int32_t id, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
auto t = reinterpret_cast<Touch::Private *>(data);
|
||||
Q_ASSERT(t->touch == touch);
|
||||
t->down(serial, time, id, QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)), QPointer<Surface>(Surface::get(surface)));
|
||||
}
|
||||
|
||||
void Touch::Private::down(quint32 serial, quint32 time, qint32 id, const QPointF &position, const QPointer<Surface> &surface)
|
||||
{
|
||||
TouchPoint *p = new TouchPoint;
|
||||
p->d->downSerial = serial;
|
||||
p->d->surface = surface;
|
||||
p->d->id = id;
|
||||
p->d->positions << position;
|
||||
p->d->timestamps << time;
|
||||
if (active) {
|
||||
sequence << p;
|
||||
Q_EMIT q->pointAdded(p);
|
||||
} else {
|
||||
qDeleteAll(sequence);
|
||||
sequence.clear();
|
||||
sequence << p;
|
||||
active = true;
|
||||
Q_EMIT q->sequenceStarted(p);
|
||||
}
|
||||
}
|
||||
|
||||
TouchPoint *Touch::Private::getActivePoint(qint32 id) const
|
||||
{
|
||||
auto it = std::find_if(sequence.constBegin(), sequence.constEnd(), [id](TouchPoint *p) {
|
||||
return p->id() == id && p->isDown();
|
||||
});
|
||||
if (it == sequence.constEnd()) {
|
||||
return nullptr;
|
||||
}
|
||||
return *it;
|
||||
}
|
||||
|
||||
void Touch::Private::upCallback(void *data, wl_touch *touch, uint32_t serial, uint32_t time, int32_t id)
|
||||
{
|
||||
auto t = reinterpret_cast<Touch::Private *>(data);
|
||||
Q_ASSERT(t->touch == touch);
|
||||
t->up(serial, time, id);
|
||||
}
|
||||
|
||||
void Touch::Private::up(quint32 serial, quint32 time, qint32 id)
|
||||
{
|
||||
TouchPoint *p = getActivePoint(id);
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
p->d->timestamps << time;
|
||||
p->d->upSerial = serial;
|
||||
p->d->down = false;
|
||||
Q_EMIT q->pointRemoved(p);
|
||||
// check whether the sequence ended
|
||||
for (auto it = sequence.constBegin(); it != sequence.constEnd(); ++it) {
|
||||
if ((*it)->isDown()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
// no touch point is down
|
||||
active = false;
|
||||
Q_EMIT q->sequenceEnded();
|
||||
}
|
||||
|
||||
void Touch::Private::motionCallback(void *data, wl_touch *touch, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y)
|
||||
{
|
||||
auto t = reinterpret_cast<Touch::Private *>(data);
|
||||
Q_ASSERT(t->touch == touch);
|
||||
t->motion(time, id, QPointF(wl_fixed_to_double(x), wl_fixed_to_double(y)));
|
||||
}
|
||||
|
||||
void Touch::Private::motion(quint32 time, qint32 id, const QPointF &position)
|
||||
{
|
||||
TouchPoint *p = getActivePoint(id);
|
||||
if (!p) {
|
||||
return;
|
||||
}
|
||||
p->d->positions << position;
|
||||
p->d->timestamps << time;
|
||||
Q_EMIT q->pointMoved(p);
|
||||
}
|
||||
|
||||
void Touch::Private::frameCallback(void *data, wl_touch *touch)
|
||||
{
|
||||
auto t = reinterpret_cast<Touch::Private *>(data);
|
||||
Q_ASSERT(t->touch == touch);
|
||||
Q_EMIT t->q->frameEnded();
|
||||
}
|
||||
|
||||
void Touch::Private::cancelCallback(void *data, wl_touch *touch)
|
||||
{
|
||||
auto t = reinterpret_cast<Touch::Private *>(data);
|
||||
Q_ASSERT(t->touch == touch);
|
||||
t->active = false;
|
||||
Q_EMIT t->q->sequenceCanceled();
|
||||
}
|
||||
|
||||
Touch::Touch(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
Touch::~Touch()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void Touch::destroy()
|
||||
{
|
||||
d->touch.destroy();
|
||||
}
|
||||
|
||||
void Touch::release()
|
||||
{
|
||||
d->touch.release();
|
||||
}
|
||||
|
||||
void Touch::setup(wl_touch *touch)
|
||||
{
|
||||
d->setup(touch);
|
||||
}
|
||||
|
||||
bool Touch::isValid() const
|
||||
{
|
||||
return d->touch.isValid();
|
||||
}
|
||||
|
||||
Touch::operator wl_touch *() const
|
||||
{
|
||||
return d->touch;
|
||||
}
|
||||
|
||||
Touch::operator wl_touch *()
|
||||
{
|
||||
return d->touch;
|
||||
}
|
||||
|
||||
QList<TouchPoint *> Touch::sequence() const
|
||||
{
|
||||
return d->sequence;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_touch.cpp"
|
||||
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_TOUCH_H
|
||||
#define WAYLAND_TOUCH_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QPoint>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct wl_touch;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Surface;
|
||||
class Touch;
|
||||
|
||||
/**
|
||||
* TODO
|
||||
*/
|
||||
class KWAYLANDCLIENT_EXPORT TouchPoint
|
||||
{
|
||||
public:
|
||||
virtual ~TouchPoint();
|
||||
|
||||
/**
|
||||
* Unique in the scope of all TouchPoints currently being down.
|
||||
* As soon as the TouchPoint is now longer down another TouchPoint
|
||||
* might get assigned the id.
|
||||
**/
|
||||
qint32 id() const;
|
||||
/**
|
||||
* The serial when the down event happened.
|
||||
**/
|
||||
quint32 downSerial() const;
|
||||
/**
|
||||
* The serial when the up event happened.
|
||||
**/
|
||||
quint32 upSerial() const;
|
||||
/**
|
||||
* Most recent timestamp
|
||||
**/
|
||||
quint32 time() const;
|
||||
/**
|
||||
* All timestamps, references the positions.
|
||||
* That is each position has a timestamp.
|
||||
**/
|
||||
QList<quint32> timestamps() const;
|
||||
/**
|
||||
* Most recent position
|
||||
**/
|
||||
QPointF position() const;
|
||||
/**
|
||||
* All positions this TouchPoint had, updated with each move.
|
||||
**/
|
||||
QList<QPointF> positions() const;
|
||||
/**
|
||||
* The Surface this TouchPoint happened on.
|
||||
**/
|
||||
QPointer<Surface> surface() const;
|
||||
/**
|
||||
* @c true if currently down, @c false otherwise.
|
||||
**/
|
||||
bool isDown() const;
|
||||
|
||||
private:
|
||||
friend class Touch;
|
||||
explicit TouchPoint();
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Wrapper for the wl_touch interface.
|
||||
*
|
||||
* This class is a convenient wrapper for the wl_touch interface.
|
||||
*
|
||||
* To create an instance use Seat::createTouch.
|
||||
*
|
||||
* @see Seat
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT Touch : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Touch(QObject *parent = nullptr);
|
||||
~Touch() override;
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a wl_pointer.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Setup this Touch to manage the @p touch.
|
||||
* When using Seat::createTouch there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(wl_touch *touch);
|
||||
/**
|
||||
* Releases the wl_touch interface.
|
||||
* After the interface has been released the Touch instance is no
|
||||
* longer valid and can be setup with another wl_touch interface.
|
||||
*
|
||||
* This method is automatically invoked when the Seat which created this
|
||||
* Touch gets released.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this Touch.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new wl_touch interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Seat which created this
|
||||
* Touch gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* The TouchPoints of the latest touch event sequence.
|
||||
* Only valid till the next touch event sequence is started
|
||||
**/
|
||||
QList<TouchPoint *> sequence() const;
|
||||
|
||||
operator wl_touch *();
|
||||
operator wl_touch *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* A new touch sequence is started. The previous sequence is discarded.
|
||||
* @param startPoint The first point which started the sequence
|
||||
**/
|
||||
void sequenceStarted(KWayland::Client::TouchPoint *startPoint);
|
||||
/**
|
||||
* Sent if the compositor decides the touch stream is a global
|
||||
* gesture.
|
||||
**/
|
||||
void sequenceCanceled();
|
||||
/**
|
||||
* Emitted once all touch points are no longer down.
|
||||
**/
|
||||
void sequenceEnded();
|
||||
/**
|
||||
* Indicates the end of a contact point list.
|
||||
**/
|
||||
void frameEnded();
|
||||
/**
|
||||
* TouchPoint @p point got added to the sequence.
|
||||
**/
|
||||
void pointAdded(KWayland::Client::TouchPoint *point);
|
||||
/**
|
||||
* TouchPoint @p point is no longer down.
|
||||
* A new TouchPoint might reuse the Id of the @p point.
|
||||
**/
|
||||
void pointRemoved(KWayland::Client::TouchPoint *point);
|
||||
/**
|
||||
* TouchPoint @p point moved.
|
||||
**/
|
||||
void pointMoved(KWayland::Client::TouchPoint *point);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWayland::Client::TouchPoint *)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef WAYLAND_POINTER_P_H
|
||||
#define WAYLAND_POINTER_P_H
|
||||
|
||||
struct wl_proxy;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
template<typename Pointer, void (*deleter)(Pointer *)>
|
||||
class WaylandPointer
|
||||
{
|
||||
public:
|
||||
WaylandPointer() = default;
|
||||
WaylandPointer(Pointer *p)
|
||||
: m_pointer(p)
|
||||
{
|
||||
}
|
||||
WaylandPointer(const WaylandPointer &other) = delete;
|
||||
virtual ~WaylandPointer()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void setup(Pointer *pointer, bool foreign = false)
|
||||
{
|
||||
Q_ASSERT(pointer);
|
||||
Q_ASSERT(!m_pointer);
|
||||
m_pointer = pointer;
|
||||
m_foreign = foreign;
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
if (!m_pointer) {
|
||||
return;
|
||||
}
|
||||
if (!m_foreign) {
|
||||
deleter(m_pointer);
|
||||
}
|
||||
m_pointer = nullptr;
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if (!m_pointer) {
|
||||
return;
|
||||
}
|
||||
if (!m_foreign) {
|
||||
free(m_pointer);
|
||||
}
|
||||
m_pointer = nullptr;
|
||||
}
|
||||
|
||||
bool isValid() const
|
||||
{
|
||||
return m_pointer != nullptr;
|
||||
}
|
||||
|
||||
operator Pointer *()
|
||||
{
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
operator Pointer *() const
|
||||
{
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
operator wl_proxy *()
|
||||
{
|
||||
return reinterpret_cast<wl_proxy *>(m_pointer);
|
||||
}
|
||||
|
||||
Pointer *operator->()
|
||||
{
|
||||
return m_pointer;
|
||||
}
|
||||
|
||||
operator bool()
|
||||
{
|
||||
return isValid();
|
||||
}
|
||||
|
||||
operator bool() const
|
||||
{
|
||||
return isValid();
|
||||
}
|
||||
|
||||
private:
|
||||
Pointer *m_pointer = nullptr;
|
||||
bool m_foreign = false;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2018 David Edmundson <kde@davidedmundson.co.uk>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "xdgdecoration.h"
|
||||
|
||||
#include "event_queue.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
#include "xdgshell.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include "wayland-xdg-decoration-unstable-v1-client-protocol.h"
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN XdgDecorationManager::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
void setup(zxdg_decoration_manager_v1 *arg);
|
||||
|
||||
WaylandPointer<zxdg_decoration_manager_v1, zxdg_decoration_manager_v1_destroy> xdgdecorationmanager;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
XdgDecorationManager::XdgDecorationManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgDecorationManager::Private::setup(zxdg_decoration_manager_v1 *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!xdgdecorationmanager);
|
||||
xdgdecorationmanager.setup(arg);
|
||||
}
|
||||
|
||||
XdgDecorationManager::~XdgDecorationManager()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void XdgDecorationManager::setup(zxdg_decoration_manager_v1 *xdgdecorationmanager)
|
||||
{
|
||||
d->setup(xdgdecorationmanager);
|
||||
}
|
||||
|
||||
void XdgDecorationManager::release()
|
||||
{
|
||||
d->xdgdecorationmanager.release();
|
||||
}
|
||||
|
||||
void XdgDecorationManager::destroy()
|
||||
{
|
||||
d->xdgdecorationmanager.destroy();
|
||||
}
|
||||
|
||||
XdgDecorationManager::operator zxdg_decoration_manager_v1 *()
|
||||
{
|
||||
return d->xdgdecorationmanager;
|
||||
}
|
||||
|
||||
XdgDecorationManager::operator zxdg_decoration_manager_v1 *() const
|
||||
{
|
||||
return d->xdgdecorationmanager;
|
||||
}
|
||||
|
||||
bool XdgDecorationManager::isValid() const
|
||||
{
|
||||
return d->xdgdecorationmanager.isValid();
|
||||
}
|
||||
|
||||
void XdgDecorationManager::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *XdgDecorationManager::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
XdgDecoration *XdgDecorationManager::getToplevelDecoration(XdgShellSurface *toplevel, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
xdg_toplevel *toplevel_resource = *toplevel;
|
||||
if (!toplevel_resource) { // i.e using XDGShellV5
|
||||
qWarning() << "Trying to create an XdgDecoration without an XDGShell stable toplevel object";
|
||||
return nullptr;
|
||||
}
|
||||
auto p = new XdgDecoration(parent);
|
||||
auto w = zxdg_decoration_manager_v1_get_toplevel_decoration(d->xdgdecorationmanager, toplevel_resource);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
p->setup(w);
|
||||
return p;
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN XdgDecoration::Private
|
||||
{
|
||||
public:
|
||||
Private(XdgDecoration *q);
|
||||
|
||||
void setup(zxdg_toplevel_decoration_v1 *arg);
|
||||
|
||||
WaylandPointer<zxdg_toplevel_decoration_v1, zxdg_toplevel_decoration_v1_destroy> xdgdecoration;
|
||||
|
||||
XdgDecoration::Mode m_mode = XdgDecoration::Mode::ClientSide;
|
||||
|
||||
private:
|
||||
XdgDecoration *q;
|
||||
|
||||
private:
|
||||
static void configureCallback(void *data, zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t mode);
|
||||
|
||||
static const zxdg_toplevel_decoration_v1_listener s_listener;
|
||||
};
|
||||
|
||||
const zxdg_toplevel_decoration_v1_listener XdgDecoration::Private::s_listener = {configureCallback};
|
||||
|
||||
void XdgDecoration::Private::configureCallback(void *data, zxdg_toplevel_decoration_v1 *zxdg_toplevel_decoration_v1, uint32_t m)
|
||||
{
|
||||
auto p = reinterpret_cast<XdgDecoration::Private *>(data);
|
||||
Q_ASSERT(p->xdgdecoration == zxdg_toplevel_decoration_v1);
|
||||
switch (m) {
|
||||
case ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE:
|
||||
p->m_mode = XdgDecoration::Mode::ClientSide;
|
||||
break;
|
||||
case ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE:
|
||||
p->m_mode = XdgDecoration::Mode::ServerSide;
|
||||
break;
|
||||
}
|
||||
Q_EMIT p->q->modeChanged(p->m_mode);
|
||||
}
|
||||
|
||||
XdgDecoration::Private::Private(XdgDecoration *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
XdgDecoration::XdgDecoration(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
void XdgDecoration::Private::setup(zxdg_toplevel_decoration_v1 *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!xdgdecoration);
|
||||
xdgdecoration.setup(arg);
|
||||
zxdg_toplevel_decoration_v1_add_listener(xdgdecoration, &s_listener, this);
|
||||
}
|
||||
|
||||
XdgDecoration::~XdgDecoration()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void XdgDecoration::setup(zxdg_toplevel_decoration_v1 *xdgdecoration)
|
||||
{
|
||||
d->setup(xdgdecoration);
|
||||
}
|
||||
|
||||
void XdgDecoration::release()
|
||||
{
|
||||
d->xdgdecoration.release();
|
||||
}
|
||||
|
||||
void XdgDecoration::destroy()
|
||||
{
|
||||
d->xdgdecoration.destroy();
|
||||
}
|
||||
|
||||
XdgDecoration::operator zxdg_toplevel_decoration_v1 *()
|
||||
{
|
||||
return d->xdgdecoration;
|
||||
}
|
||||
|
||||
XdgDecoration::operator zxdg_toplevel_decoration_v1 *() const
|
||||
{
|
||||
return d->xdgdecoration;
|
||||
}
|
||||
|
||||
bool XdgDecoration::isValid() const
|
||||
{
|
||||
return d->xdgdecoration.isValid();
|
||||
}
|
||||
|
||||
void XdgDecoration::setMode(XdgDecoration::Mode mode)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
uint32_t mode_raw;
|
||||
switch (mode) {
|
||||
case XdgDecoration::Mode::ClientSide:
|
||||
mode_raw = ZXDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE;
|
||||
break;
|
||||
default:
|
||||
mode_raw = ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE;
|
||||
break;
|
||||
}
|
||||
zxdg_toplevel_decoration_v1_set_mode(d->xdgdecoration, mode_raw);
|
||||
}
|
||||
|
||||
void XdgDecoration::unsetMode()
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
zxdg_toplevel_decoration_v1_unset_mode(d->xdgdecoration);
|
||||
}
|
||||
|
||||
XdgDecoration::Mode XdgDecoration::mode() const
|
||||
{
|
||||
return d->m_mode;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_xdgdecoration.cpp"
|
||||
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2018 David Edmundson <kde@davidedmundson.co.uk>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_XDG_DECORATION_UNSTABLE_V1_H
|
||||
#define KWAYLAND_CLIENT_XDG_DECORATION_UNSTABLE_V1_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct zxdg_decoration_manager_v1;
|
||||
struct zxdg_toplevel_decoration_v1;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class XdgDecoration;
|
||||
class XdgShellSurface;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the zxdg_decoration_manager_v1 interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the zxdg_decoration_manager_v1 interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the XdgDecorationManager interface:
|
||||
* @code
|
||||
* XdgDecorationManager *c = registry->createXdgDecorationManager(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the XdgDecorationManager and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* XdgDecorationManager *c = new XdgDecorationManager;
|
||||
* c->setup(registry->bindXdgDecorationManager(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The XdgDecorationManager can be used as a drop-in replacement for any zxdg_decoration_manager_v1
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* If you use the QtWayland QPA you do not need to use this class.
|
||||
*
|
||||
* @see Registry
|
||||
* @since 5.54
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT XdgDecorationManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new XdgDecorationManager.
|
||||
* Note: after constructing the XdgDecorationManager it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use XdgDecorationManager prefer using
|
||||
* Registry::createXdgDecorationManager.
|
||||
**/
|
||||
explicit XdgDecorationManager(QObject *parent = nullptr);
|
||||
~XdgDecorationManager() override;
|
||||
|
||||
/**
|
||||
* Setup this XdgDecorationManager to manage the @p xdgdecorationmanager.
|
||||
* When using Registry::createXdgDecorationManager there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zxdg_decoration_manager_v1 *xdgdecorationmanager);
|
||||
/**
|
||||
* @returns @c true if managing a zxdg_decoration_manager_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zxdg_decoration_manager_v1 interface.
|
||||
* After the interface has been released the XdgDecorationManager instance is no
|
||||
* longer valid and can be setup with another zxdg_decoration_manager_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this XdgDecorationManager.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zxdg_decoration_manager_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, xdgdecorationmanager, &XdgDecorationManager::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating objects with this XdgDecorationManager.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating objects with this XdgDecorationManager.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
XdgDecoration *getToplevelDecoration(XdgShellSurface *toplevel, QObject *parent = nullptr);
|
||||
|
||||
operator zxdg_decoration_manager_v1 *();
|
||||
operator zxdg_decoration_manager_v1 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the XdgDecorationManager got created by
|
||||
* Registry::createXdgDecorationManager
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
class KWAYLANDCLIENT_EXPORT XdgDecoration : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum class Mode {
|
||||
ClientSide,
|
||||
ServerSide,
|
||||
};
|
||||
|
||||
Q_ENUM(Mode)
|
||||
|
||||
~XdgDecoration() override;
|
||||
|
||||
/**
|
||||
* Setup this XdgDecoration to manage the @p xdgdecoration.
|
||||
* When using XdgDecorationManager::createXdgDecoration there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zxdg_toplevel_decoration_v1 *xdgdecoration);
|
||||
/**
|
||||
* @returns @c true if managing a zxdg_toplevel_decoration_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zxdg_toplevel_decoration_v1 interface.
|
||||
* After the interface has been released the XdgDecoration instance is no
|
||||
* longer valid and can be setup with another zxdg_toplevel_decoration_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this XdgDecoration.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zxdg_toplevel_decoration_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, xdgdecoration, &XdgDecoration::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* @brief Request that the server puts us in a given mode. The compositor will respond with a modeChange
|
||||
* The compositor may ignore this request.
|
||||
*/
|
||||
void setMode(Mode mode);
|
||||
|
||||
/**
|
||||
* @brief Unset our requested mode. The compositor can then configure this surface with the default mode
|
||||
*/
|
||||
void unsetMode();
|
||||
|
||||
/**
|
||||
* The mode configured by the server.
|
||||
*/
|
||||
Mode mode() const;
|
||||
|
||||
operator zxdg_toplevel_decoration_v1 *();
|
||||
operator zxdg_toplevel_decoration_v1 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void modeChanged(KWayland::Client::XdgDecoration::Mode mode);
|
||||
|
||||
private:
|
||||
friend class XdgDecorationManager;
|
||||
explicit XdgDecoration(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2017 Marco Martin <notmart@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "xdgforeign.h"
|
||||
#include "event_queue.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
#include "xdgforeign_p.h"
|
||||
|
||||
#include <wayland-xdg-foreign-unstable-v2-client-protocol.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
XdgExporter::Private::Private()
|
||||
{
|
||||
}
|
||||
|
||||
XdgExporter::Private::~Private()
|
||||
{
|
||||
}
|
||||
|
||||
XdgExporter::XdgExporter(Private *p, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(p)
|
||||
{
|
||||
}
|
||||
|
||||
XdgExporter::~XdgExporter()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void XdgExporter::setup(zxdg_exporter_v2 *exporter)
|
||||
{
|
||||
d->setupV2(exporter);
|
||||
}
|
||||
|
||||
void XdgExporter::release()
|
||||
{
|
||||
d->release();
|
||||
}
|
||||
|
||||
void XdgExporter::destroy()
|
||||
{
|
||||
d->destroy();
|
||||
}
|
||||
|
||||
XdgExporter::operator zxdg_exporter_v2 *()
|
||||
{
|
||||
return d->exporterV2();
|
||||
}
|
||||
|
||||
XdgExporter::operator zxdg_exporter_v2 *() const
|
||||
{
|
||||
return d->exporterV2();
|
||||
}
|
||||
|
||||
bool XdgExporter::isValid() const
|
||||
{
|
||||
return d->isValid();
|
||||
}
|
||||
|
||||
void XdgExporter::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *XdgExporter::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
XdgExported *XdgExporter::exportTopLevel(Surface *surface, QObject *parent)
|
||||
{
|
||||
return d->exportTopLevelV2(surface, parent);
|
||||
}
|
||||
|
||||
XdgImporter::Private::Private()
|
||||
{
|
||||
}
|
||||
|
||||
XdgImporter::Private::~Private()
|
||||
{
|
||||
}
|
||||
|
||||
XdgImporter::XdgImporter(Private *p, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(p)
|
||||
{
|
||||
}
|
||||
|
||||
XdgImporter::~XdgImporter()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void XdgImporter::setup(zxdg_importer_v2 *importer)
|
||||
{
|
||||
d->setupV2(importer);
|
||||
}
|
||||
|
||||
void XdgImporter::release()
|
||||
{
|
||||
d->release();
|
||||
}
|
||||
|
||||
void XdgImporter::destroy()
|
||||
{
|
||||
d->destroy();
|
||||
}
|
||||
|
||||
XdgImporter::operator zxdg_importer_v2 *()
|
||||
{
|
||||
return d->importerV2();
|
||||
}
|
||||
|
||||
XdgImporter::operator zxdg_importer_v2 *() const
|
||||
{
|
||||
return d->importerV2();
|
||||
}
|
||||
|
||||
bool XdgImporter::isValid() const
|
||||
{
|
||||
return d->isValid();
|
||||
}
|
||||
|
||||
void XdgImporter::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *XdgImporter::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
XdgImported *XdgImporter::importTopLevel(const QString &handle, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
return d->importTopLevelV2(handle, parent);
|
||||
}
|
||||
|
||||
XdgExported::XdgExported(Private *p, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(p)
|
||||
{
|
||||
}
|
||||
|
||||
XdgExported::Private::Private(XdgExported *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
XdgExported::Private::~Private()
|
||||
{
|
||||
}
|
||||
|
||||
XdgExported::~XdgExported()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void XdgExported::setup(zxdg_exported_v2 *exported)
|
||||
{
|
||||
d->setupV2(exported);
|
||||
}
|
||||
|
||||
void XdgExported::release()
|
||||
{
|
||||
d->release();
|
||||
}
|
||||
|
||||
void XdgExported::destroy()
|
||||
{
|
||||
d->destroy();
|
||||
}
|
||||
|
||||
QString XdgExported::handle() const
|
||||
{
|
||||
return d->handle;
|
||||
}
|
||||
|
||||
XdgExported::operator zxdg_exported_v2 *()
|
||||
{
|
||||
return d->exportedV2();
|
||||
}
|
||||
|
||||
XdgExported::operator zxdg_exported_v2 *() const
|
||||
{
|
||||
return d->exportedV2();
|
||||
}
|
||||
|
||||
bool XdgExported::isValid() const
|
||||
{
|
||||
return d->isValid();
|
||||
}
|
||||
|
||||
XdgImported::Private::Private(XdgImported *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
XdgImported::Private::~Private()
|
||||
{
|
||||
}
|
||||
|
||||
XdgImported::XdgImported(Private *p, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(p)
|
||||
{
|
||||
}
|
||||
|
||||
XdgImported::~XdgImported()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void XdgImported::setup(zxdg_imported_v2 *imported)
|
||||
{
|
||||
d->setupV2(imported);
|
||||
}
|
||||
|
||||
void XdgImported::release()
|
||||
{
|
||||
d->release();
|
||||
}
|
||||
|
||||
void XdgImported::destroy()
|
||||
{
|
||||
d->destroy();
|
||||
}
|
||||
|
||||
XdgImported::operator zxdg_imported_v2 *()
|
||||
{
|
||||
return d->importedV2();
|
||||
}
|
||||
|
||||
XdgImported::operator zxdg_imported_v2 *() const
|
||||
{
|
||||
return d->importedV2();
|
||||
}
|
||||
|
||||
bool XdgImported::isValid() const
|
||||
{
|
||||
return d->isValid();
|
||||
}
|
||||
|
||||
void XdgImported::setParentOf(Surface *surface)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
d->setParentOf(surface);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_xdgforeign.cpp"
|
||||
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2017 Marco Martin <notmart@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_XDGFOREIGN_H
|
||||
#define KWAYLAND_CLIENT_XDGFOREIGN_H
|
||||
|
||||
#include "surface.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct zxdg_exporter_v2;
|
||||
struct zxdg_importer_v2;
|
||||
struct zxdg_exported_v2;
|
||||
struct zxdg_imported_v2;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Surface;
|
||||
class XdgExported;
|
||||
class XdgImported;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the zxdg_exporter_v2 interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the zxdg_exporter_v2 interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the XdgExporter interface:
|
||||
* @code
|
||||
* *c = registry->create(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the XdgExporter and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* *c = new ;
|
||||
* c->setup(registry->bind(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The XdgExporter can be used as a drop-in replacement for any zxdg_exporter_v2
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT XdgExporter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgExporter() override;
|
||||
|
||||
/**
|
||||
* Setup this XdgExporter to manage the @p .
|
||||
* When using Registry::create there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zxdg_exporter_v2 *);
|
||||
/**
|
||||
* @returns @c true if managing a zxdg_exporter_v2.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zxdg_exporter_v2 interface.
|
||||
* After the interface has been released the XdgExporter instance is no
|
||||
* longer valid and can be setup with another zxdg_exporter_v2 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this .
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zxdg_exporter_v2 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, , &::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating objects with this .
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating objects with this .
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* The export request exports the passed surface so that it can later be
|
||||
* imported via XdgImporter::importTopLevel.
|
||||
* A surface may be exported multiple times, and each exported handle may
|
||||
* be used to create an XdgImported multiple times.
|
||||
* @param surface the surface which we want to export an handle.
|
||||
* @param parent the parent in the QObject's hierarchy of the new XdgExported
|
||||
*/
|
||||
XdgExported *exportTopLevel(Surface *surface, QObject *parent = nullptr);
|
||||
|
||||
operator zxdg_exporter_v2 *();
|
||||
operator zxdg_exporter_v2 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the XdgExporter got created by
|
||||
* Registry::create
|
||||
**/
|
||||
void removed();
|
||||
|
||||
protected:
|
||||
class Private;
|
||||
explicit XdgExporter(Private *p, QObject *parent = nullptr);
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Wrapper for the zxdg_importer_v2 interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the zxdg_importer_v2 interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the XdgImporter interface:
|
||||
* @code
|
||||
* *c = registry->create(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the XdgImporter and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* *c = new ;
|
||||
* c->setup(registry->bind(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The XdgImporter can be used as a drop-in replacement for any zxdg_importer_v2
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT XdgImporter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgImporter() override;
|
||||
|
||||
/**
|
||||
* Setup this XdgImporter to manage the @p .
|
||||
* When using Registry::create there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zxdg_importer_v2 *);
|
||||
/**
|
||||
* @returns @c true if managing a zxdg_importer_v2.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zxdg_importer_v2 interface.
|
||||
* After the interface has been released the XdgImporter instance is no
|
||||
* longer valid and can be setup with another zxdg_importer_v2 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this .
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zxdg_importer_v2 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, , &::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating objects with this .
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating objects with this .
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Imports a surface from any client given a handle
|
||||
* retrieved by exporting said surface using XdgExporter::exportTopLevel.
|
||||
* When called, a new XdgImported object will be created.
|
||||
* This new object represents the imported surface, and the importing
|
||||
* client can manipulate its relationship using it.
|
||||
*
|
||||
* @param handle the unique handle that represent an exported toplevel surface.
|
||||
* it has to have been generated by the XdgExporter by either this
|
||||
* or some other process (which would have communicated the handle
|
||||
* in some way, such as command line or a DBus call)
|
||||
* @param parent the parent in the QObject's hierarchy of the new XdgImported
|
||||
*/
|
||||
XdgImported *importTopLevel(const QString &handle, QObject *parent = nullptr);
|
||||
|
||||
operator zxdg_importer_v2 *();
|
||||
operator zxdg_importer_v2 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the XdgImporter got created by
|
||||
* Registry::create
|
||||
**/
|
||||
void removed();
|
||||
|
||||
protected:
|
||||
class Private;
|
||||
explicit XdgImporter(Private *p, QObject *parent = nullptr);
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
class KWAYLANDCLIENT_EXPORT XdgExported : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgExported() override;
|
||||
|
||||
/**
|
||||
* Setup this XdgExported to manage the @p .
|
||||
* When using ::create there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zxdg_exported_v2 *);
|
||||
/**
|
||||
* @returns @c true if managing a zxdg_exported_v2.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zxdg_exported_v2 interface.
|
||||
* After the interface has been released the XdgExported instance is no
|
||||
* longer valid and can be setup with another zxdg_exported_v2 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this .
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zxdg_exported_v2 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, , &::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* @returns The unique handle corresponding tho this exported surface.
|
||||
* Any process can import this toplevel surface provided they know this
|
||||
* unique string.
|
||||
*/
|
||||
QString handle() const;
|
||||
|
||||
operator zxdg_exported_v2 *();
|
||||
operator zxdg_exported_v2 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted when the exported window is fully initialized.
|
||||
* the handle will be valid at this point
|
||||
**/
|
||||
void done();
|
||||
|
||||
protected:
|
||||
friend class XdgExporter;
|
||||
class Private;
|
||||
explicit XdgExported(Private *p, QObject *parent = nullptr);
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
class KWAYLANDCLIENT_EXPORT XdgImported : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgImported() override;
|
||||
|
||||
/**
|
||||
* Setup this XdgImported to manage the @p .
|
||||
* When using ::create there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zxdg_imported_v2 *);
|
||||
/**
|
||||
* @returns @c true if managing a zxdg_imported_v2.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zxdg_imported_v2 interface.
|
||||
* After the interface has been released the XdgImported instance is no
|
||||
* longer valid and can be setup with another zxdg_imported_v2 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this .
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zxdg_imported_v2 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, , &::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Set the imported surface as the parent of some surface of the client.
|
||||
* The passed surface must be a toplevel xdg_surface.
|
||||
* Calling this function sets up a surface to surface relation with the same
|
||||
* stacking and positioning semantics as XdgShellSurface::setTransientFor
|
||||
*
|
||||
* @param surface the child surface, which must belong to this process.
|
||||
*/
|
||||
void setParentOf(Surface *surface);
|
||||
|
||||
operator zxdg_imported_v2 *();
|
||||
operator zxdg_imported_v2 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted when the imported surface is not valid anymore,
|
||||
* for instance because it's no longer exported on the other end
|
||||
*/
|
||||
void importedDestroyed();
|
||||
|
||||
protected:
|
||||
friend class XdgImporter;
|
||||
class Private;
|
||||
explicit XdgImported(Private *p, QObject *parent = nullptr);
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2017 Marco Martin <notmart@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_XDGFOREIGN_P_H
|
||||
#define KWAYLAND_CLIENT_XDGFOREIGN_P_H
|
||||
|
||||
#include "xdgforeign.h"
|
||||
#include <QObject>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
|
||||
class Q_DECL_HIDDEN XdgExporter::Private
|
||||
{
|
||||
public:
|
||||
Private();
|
||||
virtual ~Private();
|
||||
|
||||
virtual XdgExported *exportTopLevelV2(Surface *surface, QObject *parent) = 0;
|
||||
|
||||
virtual void setupV2(zxdg_exporter_v2 *arg) = 0;
|
||||
virtual zxdg_exporter_v2 *exporterV2() = 0;
|
||||
|
||||
virtual void release() = 0;
|
||||
virtual void destroy() = 0;
|
||||
virtual bool isValid() = 0;
|
||||
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
class Q_DECL_HIDDEN XdgImporter::Private
|
||||
{
|
||||
public:
|
||||
Private();
|
||||
virtual ~Private();
|
||||
|
||||
virtual XdgImported *importTopLevelV2(const QString &handle, QObject *parent) = 0;
|
||||
|
||||
virtual void setupV2(zxdg_importer_v2 *arg) = 0;
|
||||
virtual zxdg_importer_v2 *importerV2() = 0;
|
||||
|
||||
virtual void release() = 0;
|
||||
virtual void destroy() = 0;
|
||||
virtual bool isValid() = 0;
|
||||
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
class Q_DECL_HIDDEN XdgExported::Private
|
||||
{
|
||||
public:
|
||||
Private(XdgExported *q);
|
||||
virtual ~Private();
|
||||
|
||||
virtual void setupV2(zxdg_exported_v2 *) = 0;
|
||||
virtual zxdg_exported_v2 *exportedV2() = 0;
|
||||
|
||||
virtual void release() = 0;
|
||||
virtual void destroy() = 0;
|
||||
virtual bool isValid() = 0;
|
||||
|
||||
QString handle;
|
||||
|
||||
protected:
|
||||
XdgExported *q;
|
||||
};
|
||||
|
||||
class Q_DECL_HIDDEN XdgImported::Private
|
||||
{
|
||||
public:
|
||||
Private(XdgImported *q);
|
||||
virtual ~Private();
|
||||
|
||||
virtual void setupV2(zxdg_imported_v2 *) = 0;
|
||||
virtual zxdg_imported_v2 *importedV2() = 0;
|
||||
|
||||
virtual void setParentOf(Surface *surface) = 0;
|
||||
virtual void release() = 0;
|
||||
virtual void destroy() = 0;
|
||||
virtual bool isValid() = 0;
|
||||
|
||||
protected:
|
||||
XdgImported *q;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,314 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2017 Marco Martin <notmart@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "xdgforeign_v2.h"
|
||||
#include "event_queue.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
#include "xdgforeign_p.h"
|
||||
|
||||
#include <wayland-xdg-foreign-unstable-v2-client-protocol.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN XdgExporterUnstableV2::Private : public XdgExporter::Private
|
||||
{
|
||||
public:
|
||||
Private();
|
||||
|
||||
XdgExported *exportTopLevelV2(Surface *surface, QObject *parent) override;
|
||||
void setupV2(zxdg_exporter_v2 *arg) override;
|
||||
zxdg_exporter_v2 *exporterV2() override;
|
||||
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() override;
|
||||
|
||||
WaylandPointer<zxdg_exporter_v2, zxdg_exporter_v2_destroy> exporter;
|
||||
};
|
||||
|
||||
XdgExporterUnstableV2::Private::Private()
|
||||
: XdgExporter::Private()
|
||||
{
|
||||
}
|
||||
|
||||
zxdg_exporter_v2 *XdgExporterUnstableV2::Private::exporterV2()
|
||||
{
|
||||
return exporter;
|
||||
}
|
||||
|
||||
void XdgExporterUnstableV2::Private::release()
|
||||
{
|
||||
exporter.release();
|
||||
}
|
||||
|
||||
void XdgExporterUnstableV2::Private::destroy()
|
||||
{
|
||||
exporter.destroy();
|
||||
}
|
||||
|
||||
bool XdgExporterUnstableV2::Private::isValid()
|
||||
{
|
||||
return exporter.isValid();
|
||||
}
|
||||
|
||||
XdgExported *XdgExporterUnstableV2::Private::exportTopLevelV2(Surface *surface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
auto p = new XdgExportedUnstableV2(parent);
|
||||
auto w = zxdg_exporter_v2_export_toplevel(exporter, *surface);
|
||||
if (queue) {
|
||||
queue->addProxy(w);
|
||||
}
|
||||
p->setup(w);
|
||||
return p;
|
||||
}
|
||||
|
||||
XdgExporterUnstableV2::XdgExporterUnstableV2(QObject *parent)
|
||||
: XdgExporter(new Private, parent)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgExporterUnstableV2::Private::setupV2(zxdg_exporter_v2 *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!exporter);
|
||||
exporter.setup(arg);
|
||||
}
|
||||
|
||||
XdgExporterUnstableV2::~XdgExporterUnstableV2()
|
||||
{
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN XdgImporterUnstableV2::Private : public XdgImporter::Private
|
||||
{
|
||||
public:
|
||||
Private();
|
||||
|
||||
XdgImported *importTopLevelV2(const QString &handle, QObject *parent) override;
|
||||
void setupV2(zxdg_importer_v2 *arg) override;
|
||||
zxdg_importer_v2 *importerV2() override;
|
||||
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() override;
|
||||
|
||||
WaylandPointer<zxdg_importer_v2, zxdg_importer_v2_destroy> importer;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
XdgImporterUnstableV2::Private::Private()
|
||||
: XdgImporter::Private()
|
||||
{
|
||||
}
|
||||
|
||||
zxdg_importer_v2 *XdgImporterUnstableV2::Private::importerV2()
|
||||
{
|
||||
return importer;
|
||||
}
|
||||
|
||||
void XdgImporterUnstableV2::Private::release()
|
||||
{
|
||||
importer.release();
|
||||
}
|
||||
|
||||
void XdgImporterUnstableV2::Private::destroy()
|
||||
{
|
||||
importer.destroy();
|
||||
}
|
||||
|
||||
bool XdgImporterUnstableV2::Private::isValid()
|
||||
{
|
||||
return importer.isValid();
|
||||
}
|
||||
|
||||
XdgImported *XdgImporterUnstableV2::Private::importTopLevelV2(const QString &handle, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
auto p = new XdgImportedUnstableV2(parent);
|
||||
auto w = zxdg_importer_v2_import_toplevel(importer, handle.toUtf8());
|
||||
if (queue) {
|
||||
queue->addProxy(w);
|
||||
}
|
||||
p->setup(w);
|
||||
return p;
|
||||
}
|
||||
|
||||
XdgImporterUnstableV2::XdgImporterUnstableV2(QObject *parent)
|
||||
: XdgImporter(new Private, parent)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgImporterUnstableV2::Private::setupV2(zxdg_importer_v2 *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!importer);
|
||||
importer.setup(arg);
|
||||
}
|
||||
|
||||
XdgImporterUnstableV2::~XdgImporterUnstableV2()
|
||||
{
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN XdgExportedUnstableV2::Private : public XdgExported::Private
|
||||
{
|
||||
public:
|
||||
Private(XdgExportedUnstableV2 *q);
|
||||
|
||||
void setupV2(zxdg_exported_v2 *arg) override;
|
||||
zxdg_exported_v2 *exportedV2() override;
|
||||
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() override;
|
||||
|
||||
WaylandPointer<zxdg_exported_v2, zxdg_exported_v2_destroy> exported;
|
||||
|
||||
private:
|
||||
static void handleCallback(void *data, zxdg_exported_v2 *zxdg_exported_v2, const char *handle);
|
||||
|
||||
static const zxdg_exported_v2_listener s_listener;
|
||||
};
|
||||
|
||||
zxdg_exported_v2 *XdgExportedUnstableV2::Private::exportedV2()
|
||||
{
|
||||
return exported;
|
||||
}
|
||||
|
||||
void XdgExportedUnstableV2::Private::release()
|
||||
{
|
||||
exported.release();
|
||||
}
|
||||
|
||||
void XdgExportedUnstableV2::Private::destroy()
|
||||
{
|
||||
exported.destroy();
|
||||
}
|
||||
|
||||
bool XdgExportedUnstableV2::Private::isValid()
|
||||
{
|
||||
return exported.isValid();
|
||||
}
|
||||
|
||||
const zxdg_exported_v2_listener XdgExportedUnstableV2::Private::s_listener = {handleCallback};
|
||||
|
||||
void XdgExportedUnstableV2::Private::handleCallback(void *data, zxdg_exported_v2 *zxdg_exported_v2, const char *handle)
|
||||
{
|
||||
auto p = reinterpret_cast<XdgExportedUnstableV2::Private *>(data);
|
||||
Q_ASSERT(p->exported == zxdg_exported_v2);
|
||||
|
||||
p->handle = handle;
|
||||
Q_EMIT p->q->done();
|
||||
}
|
||||
|
||||
XdgExportedUnstableV2::XdgExportedUnstableV2(QObject *parent)
|
||||
: XdgExported(new Private(this), parent)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgExportedUnstableV2::Private::setupV2(zxdg_exported_v2 *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!exported);
|
||||
exported.setup(arg);
|
||||
zxdg_exported_v2_add_listener(exported, &s_listener, this);
|
||||
}
|
||||
|
||||
XdgExportedUnstableV2::Private::Private(XdgExportedUnstableV2 *q)
|
||||
: XdgExported::Private::Private(q)
|
||||
{
|
||||
}
|
||||
|
||||
XdgExportedUnstableV2::~XdgExportedUnstableV2()
|
||||
{
|
||||
}
|
||||
|
||||
class Q_DECL_HIDDEN XdgImportedUnstableV2::Private : public XdgImported::Private
|
||||
{
|
||||
public:
|
||||
Private(XdgImportedUnstableV2 *q);
|
||||
|
||||
void setupV2(zxdg_imported_v2 *arg) override;
|
||||
zxdg_imported_v2 *importedV2() override;
|
||||
|
||||
void setParentOf(Surface *surface) override;
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() override;
|
||||
|
||||
WaylandPointer<zxdg_imported_v2, zxdg_imported_v2_destroy> imported;
|
||||
|
||||
private:
|
||||
static void destroyedCallback(void *data, zxdg_imported_v2 *zxdg_imported_v2);
|
||||
|
||||
static const zxdg_imported_v2_listener s_listener;
|
||||
};
|
||||
|
||||
XdgImportedUnstableV2::Private::Private(XdgImportedUnstableV2 *q)
|
||||
: XdgImported::Private::Private(q)
|
||||
{
|
||||
}
|
||||
|
||||
zxdg_imported_v2 *XdgImportedUnstableV2::Private::importedV2()
|
||||
{
|
||||
return imported;
|
||||
}
|
||||
|
||||
void XdgImportedUnstableV2::Private::release()
|
||||
{
|
||||
imported.release();
|
||||
}
|
||||
|
||||
void XdgImportedUnstableV2::Private::destroy()
|
||||
{
|
||||
imported.destroy();
|
||||
}
|
||||
|
||||
bool XdgImportedUnstableV2::Private::isValid()
|
||||
{
|
||||
return imported.isValid();
|
||||
}
|
||||
|
||||
void XdgImportedUnstableV2::Private::setParentOf(Surface *surface)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
zxdg_imported_v2_set_parent_of(imported, *surface);
|
||||
}
|
||||
|
||||
const zxdg_imported_v2_listener XdgImportedUnstableV2::Private::s_listener = {destroyedCallback};
|
||||
|
||||
void XdgImportedUnstableV2::Private::destroyedCallback(void *data, zxdg_imported_v2 *zxdg_imported_v2)
|
||||
{
|
||||
auto p = reinterpret_cast<XdgImportedUnstableV2::Private *>(data);
|
||||
Q_ASSERT(p->imported == zxdg_imported_v2);
|
||||
|
||||
p->q->release();
|
||||
Q_EMIT p->q->importedDestroyed();
|
||||
}
|
||||
|
||||
XdgImportedUnstableV2::XdgImportedUnstableV2(QObject *parent)
|
||||
: XdgImported(new Private(this), parent)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgImportedUnstableV2::Private::setupV2(zxdg_imported_v2 *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!imported);
|
||||
imported.setup(arg);
|
||||
zxdg_imported_v2_add_listener(imported, &s_listener, this);
|
||||
}
|
||||
|
||||
XdgImportedUnstableV2::~XdgImportedUnstableV2()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_xdgforeign_v2.cpp"
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2017 Marco Martin <notmart@gmail.com>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_XDGFOREIGN_V2_H
|
||||
#define KWAYLAND_CLIENT_XDGFOREIGN_V2_H
|
||||
|
||||
#include "surface.h"
|
||||
#include "xdgforeign.h"
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct zxdg_exporter_v2;
|
||||
struct zxdg_importer_v2;
|
||||
struct zxdg_exported_v2;
|
||||
struct zxdg_imported_v2;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class XdgExportedUnstableV2;
|
||||
class XdgImportedUnstableV2;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the zxdg_exporter_v2 interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the zxdg_exporter_v2 interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the interface:
|
||||
* @code
|
||||
* *c = registry->create(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* *c = new ;
|
||||
* c->setup(registry->bind(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The can be used as a drop-in replacement for any zxdg_exporter_v2
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
**/
|
||||
class Q_DECL_HIDDEN XdgExporterUnstableV2 : public XdgExporter
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new .
|
||||
* Note: after constructing the it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use prefer using
|
||||
* Registry::create.
|
||||
**/
|
||||
explicit XdgExporterUnstableV2(QObject *parent = nullptr);
|
||||
~XdgExporterUnstableV2() override;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Wrapper for the zxdg_importer_v2 interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the zxdg_importer_v2 interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the interface:
|
||||
* @code
|
||||
* *c = registry->create(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* *c = new ;
|
||||
* c->setup(registry->bind(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The can be used as a drop-in replacement for any zxdg_importer_v2
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
**/
|
||||
class Q_DECL_HIDDEN XdgImporterUnstableV2 : public XdgImporter
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new .
|
||||
* Note: after constructing the it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use prefer using
|
||||
* Registry::create.
|
||||
**/
|
||||
explicit XdgImporterUnstableV2(QObject *parent = nullptr);
|
||||
~XdgImporterUnstableV2() override;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
};
|
||||
|
||||
class Q_DECL_HIDDEN XdgExportedUnstableV2 : public XdgExported
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgExportedUnstableV2() override;
|
||||
|
||||
private:
|
||||
friend class XdgExporterUnstableV2;
|
||||
explicit XdgExportedUnstableV2(QObject *parent = nullptr);
|
||||
class Private;
|
||||
};
|
||||
|
||||
class Q_DECL_HIDDEN XdgImportedUnstableV2 : public XdgImported
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgImportedUnstableV2() override;
|
||||
|
||||
private:
|
||||
friend class XdgImporterUnstableV2;
|
||||
explicit XdgImportedUnstableV2(QObject *parent = nullptr);
|
||||
class Private;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2018 David Edmundson <kde@davidedmundson.co.uk>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "xdgoutput.h"
|
||||
#include "event_queue.h"
|
||||
#include "output.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
|
||||
#include <wayland-client-protocol.h>
|
||||
#include <wayland-xdg-output-unstable-v1-client-protocol.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class XdgOutputManager::Private
|
||||
{
|
||||
public:
|
||||
Private() = default;
|
||||
|
||||
void setup(zxdg_output_manager_v1 *arg);
|
||||
|
||||
WaylandPointer<zxdg_output_manager_v1, zxdg_output_manager_v1_destroy> xdgoutputmanager;
|
||||
EventQueue *queue = nullptr;
|
||||
};
|
||||
|
||||
XdgOutputManager::XdgOutputManager(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgOutputManager::Private::setup(zxdg_output_manager_v1 *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!xdgoutputmanager);
|
||||
xdgoutputmanager.setup(arg);
|
||||
}
|
||||
|
||||
XdgOutputManager::~XdgOutputManager()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void XdgOutputManager::setup(zxdg_output_manager_v1 *xdgoutputmanager)
|
||||
{
|
||||
d->setup(xdgoutputmanager);
|
||||
}
|
||||
|
||||
void XdgOutputManager::release()
|
||||
{
|
||||
d->xdgoutputmanager.release();
|
||||
}
|
||||
|
||||
void XdgOutputManager::destroy()
|
||||
{
|
||||
d->xdgoutputmanager.destroy();
|
||||
}
|
||||
|
||||
XdgOutputManager::operator zxdg_output_manager_v1 *()
|
||||
{
|
||||
return d->xdgoutputmanager;
|
||||
}
|
||||
|
||||
XdgOutputManager::operator zxdg_output_manager_v1 *() const
|
||||
{
|
||||
return d->xdgoutputmanager;
|
||||
}
|
||||
|
||||
bool XdgOutputManager::isValid() const
|
||||
{
|
||||
return d->xdgoutputmanager.isValid();
|
||||
}
|
||||
|
||||
void XdgOutputManager::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *XdgOutputManager::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
XdgOutput *XdgOutputManager::getXdgOutput(Output *output, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
auto p = new XdgOutput(parent);
|
||||
auto w = zxdg_output_manager_v1_get_xdg_output(d->xdgoutputmanager, *output);
|
||||
if (d->queue) {
|
||||
d->queue->addProxy(w);
|
||||
}
|
||||
p->setup(w);
|
||||
return p;
|
||||
}
|
||||
|
||||
struct XdgOutputBuffer {
|
||||
QPoint logicalPosition;
|
||||
QSize logicalSize;
|
||||
QString name;
|
||||
QString description;
|
||||
};
|
||||
|
||||
class XdgOutput::Private
|
||||
{
|
||||
public:
|
||||
Private(XdgOutput *q);
|
||||
|
||||
void setup(zxdg_output_v1 *arg);
|
||||
|
||||
WaylandPointer<zxdg_output_v1, zxdg_output_v1_destroy> xdgoutput;
|
||||
|
||||
XdgOutputBuffer current;
|
||||
XdgOutputBuffer pending;
|
||||
|
||||
private:
|
||||
XdgOutput *q;
|
||||
|
||||
private:
|
||||
static void logical_positionCallback(void *data, zxdg_output_v1 *zxdg_output_v1, int32_t x, int32_t y);
|
||||
static void logical_sizeCallback(void *data, zxdg_output_v1 *zxdg_output_v1, int32_t width, int32_t height);
|
||||
static void doneCallback(void *data, zxdg_output_v1 *zxdg_output_v1);
|
||||
static void nameCallback(void *data, zxdg_output_v1 *zxdg_output_v1, const char *name);
|
||||
static void descriptionCallback(void *data, zxdg_output_v1 *zxdg_output_v1, const char *description);
|
||||
|
||||
static const zxdg_output_v1_listener s_listener;
|
||||
};
|
||||
|
||||
const zxdg_output_v1_listener XdgOutput::Private::s_listener = {logical_positionCallback,
|
||||
logical_sizeCallback,
|
||||
doneCallback,
|
||||
nameCallback,
|
||||
descriptionCallback};
|
||||
|
||||
void XdgOutput::Private::logical_positionCallback(void *data, zxdg_output_v1 *zxdg_output_v1, int32_t x, int32_t y)
|
||||
{
|
||||
auto p = reinterpret_cast<XdgOutput::Private *>(data);
|
||||
Q_ASSERT(p->xdgoutput == zxdg_output_v1);
|
||||
p->pending.logicalPosition = QPoint(x, y);
|
||||
}
|
||||
|
||||
void XdgOutput::Private::logical_sizeCallback(void *data, zxdg_output_v1 *zxdg_output_v1, int32_t width, int32_t height)
|
||||
{
|
||||
auto p = reinterpret_cast<XdgOutput::Private *>(data);
|
||||
Q_ASSERT(p->xdgoutput == zxdg_output_v1);
|
||||
p->pending.logicalSize = QSize(width, height);
|
||||
}
|
||||
|
||||
void XdgOutput::Private::nameCallback(void *data, zxdg_output_v1 *zxdg_output_v1, const char *name)
|
||||
{
|
||||
auto p = reinterpret_cast<XdgOutput::Private *>(data);
|
||||
Q_ASSERT(p->xdgoutput == zxdg_output_v1);
|
||||
p->pending.name = name;
|
||||
}
|
||||
|
||||
void XdgOutput::Private::descriptionCallback(void *data, zxdg_output_v1 *zxdg_output_v1, const char *description)
|
||||
{
|
||||
auto p = reinterpret_cast<XdgOutput::Private *>(data);
|
||||
Q_ASSERT(p->xdgoutput == zxdg_output_v1);
|
||||
p->pending.description = description;
|
||||
}
|
||||
|
||||
void XdgOutput::Private::doneCallback(void *data, zxdg_output_v1 *zxdg_output_v1)
|
||||
{
|
||||
auto p = reinterpret_cast<XdgOutput::Private *>(data);
|
||||
Q_ASSERT(p->xdgoutput == zxdg_output_v1);
|
||||
std::swap(p->current, p->pending);
|
||||
|
||||
Q_EMIT p->q->changed();
|
||||
}
|
||||
|
||||
XdgOutput::Private::Private(XdgOutput *qptr)
|
||||
: q(qptr)
|
||||
{
|
||||
}
|
||||
|
||||
XdgOutput::XdgOutput(QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(new Private(this))
|
||||
{
|
||||
}
|
||||
|
||||
void XdgOutput::Private::setup(zxdg_output_v1 *arg)
|
||||
{
|
||||
Q_ASSERT(arg);
|
||||
Q_ASSERT(!xdgoutput);
|
||||
xdgoutput.setup(arg);
|
||||
zxdg_output_v1_add_listener(xdgoutput, &s_listener, this);
|
||||
}
|
||||
|
||||
XdgOutput::~XdgOutput()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void XdgOutput::setup(zxdg_output_v1 *xdgoutput)
|
||||
{
|
||||
d->setup(xdgoutput);
|
||||
}
|
||||
|
||||
void XdgOutput::release()
|
||||
{
|
||||
d->xdgoutput.release();
|
||||
}
|
||||
|
||||
void XdgOutput::destroy()
|
||||
{
|
||||
d->xdgoutput.destroy();
|
||||
}
|
||||
|
||||
QSize XdgOutput::logicalSize() const
|
||||
{
|
||||
return d->current.logicalSize;
|
||||
}
|
||||
|
||||
QPoint XdgOutput::logicalPosition() const
|
||||
{
|
||||
return d->current.logicalPosition;
|
||||
}
|
||||
|
||||
QString XdgOutput::name() const
|
||||
{
|
||||
return d->current.name;
|
||||
}
|
||||
|
||||
QString XdgOutput::description() const
|
||||
{
|
||||
return d->current.description;
|
||||
}
|
||||
|
||||
XdgOutput::operator zxdg_output_v1 *()
|
||||
{
|
||||
return d->xdgoutput;
|
||||
}
|
||||
|
||||
XdgOutput::operator zxdg_output_v1 *() const
|
||||
{
|
||||
return d->xdgoutput;
|
||||
}
|
||||
|
||||
bool XdgOutput::isValid() const
|
||||
{
|
||||
return d->xdgoutput.isValid();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_xdgoutput.cpp"
|
||||
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2018 David Edmundson <kde@davidedmundson.co.uk>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_XDGOUTPUT_H
|
||||
#define KWAYLAND_CLIENT_XDGOUTPUT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QPoint>
|
||||
#include <QSize>
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
|
||||
struct zxdg_output_manager_v1;
|
||||
struct zxdg_output_v1;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class XdgOutput;
|
||||
class Output;
|
||||
|
||||
/**
|
||||
* @short Wrapper for the zxdg_output_manager_v1 interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the zxdg_output_manager_v1 interface.
|
||||
*
|
||||
* This provides the logical size of the output. This is useful in case it doesn't match the
|
||||
* pixelSize / outputScale.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the XdgOutputManager interface:
|
||||
* @code
|
||||
* XdgOutputManager *c = registry->createXdgOutputManager(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the XdgOutputManager and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* XdgOutputManager *c = new XdgOutputManager;
|
||||
* c->setup(registry->bindXdgOutputManager(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The XdgOutputManager can be used as a drop-in replacement for any zxdg_output_manager_v1
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @since 5.47
|
||||
*
|
||||
* @see Registry
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT XdgOutputManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* Creates a new XdgOutputManager.
|
||||
* Note: after constructing the XdgOutputManager it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use XdgOutputManager prefer using
|
||||
* Registry::createXdgOutputManager.
|
||||
**/
|
||||
explicit XdgOutputManager(QObject *parent = nullptr);
|
||||
~XdgOutputManager() override;
|
||||
|
||||
/**
|
||||
* Setup this XdgOutputManager to manage the @p xdgoutputmanager.
|
||||
* When using Registry::createXdgOutputManager there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zxdg_output_manager_v1 *xdgoutputmanager);
|
||||
/**
|
||||
* @returns @c true if managing a zxdg_output_manager_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zxdg_output_manager_v1 interface.
|
||||
* After the interface has been released the XdgOutputManager instance is no
|
||||
* longer valid and can be setup with another zxdg_output_manager_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this XdgOutputManager.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zxdg_output_manager_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, xdgoutputmanager, &XdgOutputManager::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating objects with this XdgOutputManager.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating objects with this XdgOutputManager.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
XdgOutput *getXdgOutput(Output *output, QObject *parent = nullptr);
|
||||
|
||||
operator zxdg_output_manager_v1 *();
|
||||
operator zxdg_output_manager_v1 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the XdgOutputManager got created by
|
||||
* Registry::createXdgOutputManager
|
||||
**/
|
||||
void removed();
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* @short Wrapper for the zxdg_output_v1 interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the zxdg_output_v1 interface.
|
||||
*
|
||||
* The XdgOutputManager can be used as a drop-in replacement for any zxdg_output_v1
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* This protocol provides a potentially more correct size and position of the screen
|
||||
* than Output with respect to scaling.
|
||||
*
|
||||
* @see Registry
|
||||
**/
|
||||
|
||||
class KWAYLANDCLIENT_EXPORT XdgOutput : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgOutput() override;
|
||||
|
||||
/**
|
||||
* Setup this XdgOutput to manage the @p xdgoutput.
|
||||
* When using XdgOutputManager::createXdgOutput there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zxdg_output_v1 *xdgoutput);
|
||||
/**
|
||||
* @returns @c true if managing a zxdg_output_v1.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the zxdg_output_v1 interface.
|
||||
* After the interface has been released the XdgOutput instance is no
|
||||
* longer valid and can be setup with another zxdg_output_v1 interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this XdgOutput.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new zxdg_output_v1 interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, xdgoutput, &XdgOutput::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
operator zxdg_output_v1 *();
|
||||
operator zxdg_output_v1 *() const;
|
||||
|
||||
/**
|
||||
* The top left position of the output in compositor coordinates
|
||||
*/
|
||||
QPoint logicalPosition() const;
|
||||
|
||||
/**
|
||||
* The size of the output in compositor coordinates
|
||||
* (i.e pixel size / output scale)
|
||||
*/
|
||||
QSize logicalSize() const;
|
||||
|
||||
/**
|
||||
* A consistent unique name for this monitor
|
||||
* @since 5.XDGOUTPUT
|
||||
*/
|
||||
QString name() const;
|
||||
|
||||
/**
|
||||
* A longer human readable description
|
||||
* @since 5.XDGOUTPUT
|
||||
*/
|
||||
QString description() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* Emitted when any of the attributes have changed
|
||||
*/
|
||||
void changed();
|
||||
|
||||
private:
|
||||
friend class XdgOutputManager;
|
||||
explicit XdgOutput(QObject *parent = nullptr);
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,500 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "../compat/wayland-xdg-shell-v5-client-protocol.h"
|
||||
#include "event_queue.h"
|
||||
#include "output.h"
|
||||
#include "seat.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
#include "xdgshell_p.h"
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
XdgShell::Private::~Private() = default;
|
||||
|
||||
XdgShell::XdgShell(Private *p, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(p)
|
||||
{
|
||||
}
|
||||
|
||||
XdgShell::~XdgShell()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void XdgShell::setup(xdg_shell *xdgshellv5)
|
||||
{
|
||||
d->setupV5(xdgshellv5);
|
||||
}
|
||||
|
||||
void XdgShell::setup(zxdg_shell_v6 *xdgshellv6)
|
||||
{
|
||||
d->setupV6(xdgshellv6);
|
||||
}
|
||||
|
||||
void XdgShell::setup(xdg_wm_base *xdg_wm_base)
|
||||
{
|
||||
d->setup(xdg_wm_base);
|
||||
}
|
||||
|
||||
void XdgShell::release()
|
||||
{
|
||||
d->release();
|
||||
}
|
||||
|
||||
void XdgShell::destroy()
|
||||
{
|
||||
d->destroy();
|
||||
}
|
||||
|
||||
void XdgShell::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *XdgShell::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
XdgShell::operator xdg_shell *()
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShell::operator xdg_shell *() const
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShell::operator zxdg_shell_v6 *()
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShell::operator zxdg_shell_v6 *() const
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShell::operator xdg_wm_base *()
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShell::operator xdg_wm_base *() const
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
bool XdgShell::isValid() const
|
||||
{
|
||||
return d->isValid();
|
||||
}
|
||||
|
||||
XdgShellSurface *XdgShell::createSurface(Surface *surface, QObject *parent)
|
||||
{
|
||||
return d->getXdgSurface(surface, parent);
|
||||
}
|
||||
|
||||
XdgShellPopup *XdgShell::createPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent)
|
||||
{
|
||||
return d->getXdgPopup(surface, parentSurface, seat, serial, parentPos, parent);
|
||||
}
|
||||
|
||||
XdgShellPopup *XdgShell::createPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent)
|
||||
{
|
||||
return d->getXdgPopup(surface, parentSurface, positioner, parent);
|
||||
}
|
||||
|
||||
XdgShellPopup *XdgShell::createPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent)
|
||||
{
|
||||
return d->getXdgPopup(surface, parentSurface, positioner, parent);
|
||||
}
|
||||
|
||||
XdgShellSurface::Private::Private(XdgShellSurface *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
XdgShellSurface::Private::~Private() = default;
|
||||
|
||||
XdgShellSurface::XdgShellSurface(Private *p, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(p)
|
||||
{
|
||||
}
|
||||
|
||||
XdgShellSurface::~XdgShellSurface()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void XdgShellSurface::setup(xdg_surface *xdgsurfacev5)
|
||||
{
|
||||
d->setupV5(xdgsurfacev5);
|
||||
}
|
||||
|
||||
void XdgShellSurface::setup(zxdg_surface_v6 *xdgsurfacev6, zxdg_toplevel_v6 *xdgtoplevelv6)
|
||||
{
|
||||
d->setupV6(xdgsurfacev6, xdgtoplevelv6);
|
||||
}
|
||||
|
||||
void XdgShellSurface::setup(xdg_surface *xdgsurface, xdg_toplevel *xdgtoplevel)
|
||||
{
|
||||
d->setup(xdgsurface, xdgtoplevel);
|
||||
}
|
||||
|
||||
void XdgShellSurface::release()
|
||||
{
|
||||
d->release();
|
||||
}
|
||||
|
||||
void XdgShellSurface::destroy()
|
||||
{
|
||||
d->destroy();
|
||||
}
|
||||
|
||||
void XdgShellSurface::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *XdgShellSurface::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
XdgShellSurface::operator xdg_surface *()
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellSurface::operator xdg_surface *() const
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellSurface::operator xdg_toplevel *()
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellSurface::operator xdg_toplevel *() const
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellSurface::operator zxdg_surface_v6 *()
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellSurface::operator zxdg_surface_v6 *() const
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellSurface::operator zxdg_toplevel_v6 *()
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellSurface::operator zxdg_toplevel_v6 *() const
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
bool XdgShellSurface::isValid() const
|
||||
{
|
||||
return d->isValid();
|
||||
}
|
||||
|
||||
void XdgShellSurface::setTransientFor(XdgShellSurface *parent)
|
||||
{
|
||||
d->setTransientFor(parent);
|
||||
}
|
||||
|
||||
void XdgShellSurface::setTitle(const QString &title)
|
||||
{
|
||||
d->setTitle(title);
|
||||
}
|
||||
|
||||
void XdgShellSurface::setAppId(const QByteArray &appId)
|
||||
{
|
||||
d->setAppId(appId);
|
||||
}
|
||||
|
||||
void XdgShellSurface::requestShowWindowMenu(Seat *seat, quint32 serial, const QPoint &pos)
|
||||
{
|
||||
d->showWindowMenu(seat, serial, pos.x(), pos.y());
|
||||
}
|
||||
|
||||
void XdgShellSurface::requestMove(Seat *seat, quint32 serial)
|
||||
{
|
||||
d->move(seat, serial);
|
||||
}
|
||||
|
||||
void XdgShellSurface::requestResize(Seat *seat, quint32 serial, Qt::Edges edges)
|
||||
{
|
||||
d->resize(seat, serial, edges);
|
||||
}
|
||||
|
||||
void XdgShellSurface::ackConfigure(quint32 serial)
|
||||
{
|
||||
d->ackConfigure(serial);
|
||||
}
|
||||
|
||||
void XdgShellSurface::setMaximized(bool set)
|
||||
{
|
||||
if (set) {
|
||||
d->setMaximized();
|
||||
} else {
|
||||
d->unsetMaximized();
|
||||
}
|
||||
}
|
||||
|
||||
void XdgShellSurface::setFullscreen(bool set, Output *output)
|
||||
{
|
||||
if (set) {
|
||||
d->setFullscreen(output);
|
||||
} else {
|
||||
d->unsetFullscreen();
|
||||
}
|
||||
}
|
||||
|
||||
void XdgShellSurface::setMaxSize(const QSize &size)
|
||||
{
|
||||
d->setMaxSize(size);
|
||||
}
|
||||
|
||||
void XdgShellSurface::setMinSize(const QSize &size)
|
||||
{
|
||||
d->setMinSize(size);
|
||||
}
|
||||
|
||||
void XdgShellSurface::setWindowGeometry(const QRect &windowGeometry)
|
||||
{
|
||||
d->setWindowGeometry(windowGeometry);
|
||||
}
|
||||
|
||||
void XdgShellSurface::requestMinimize()
|
||||
{
|
||||
d->setMinimized();
|
||||
}
|
||||
|
||||
void XdgShellSurface::setSize(const QSize &size)
|
||||
{
|
||||
if (d->size == size) {
|
||||
return;
|
||||
}
|
||||
d->size = size;
|
||||
Q_EMIT sizeChanged(size);
|
||||
}
|
||||
|
||||
QSize XdgShellSurface::size() const
|
||||
{
|
||||
return d->size;
|
||||
}
|
||||
|
||||
XdgShellPopup::Private::~Private() = default;
|
||||
|
||||
XdgShellPopup::Private::Private(XdgShellPopup *q)
|
||||
: q(q)
|
||||
{
|
||||
}
|
||||
|
||||
XdgShellPopup::XdgShellPopup(Private *p, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(p)
|
||||
{
|
||||
}
|
||||
|
||||
XdgShellPopup::~XdgShellPopup()
|
||||
{
|
||||
release();
|
||||
}
|
||||
|
||||
void XdgShellPopup::setup(xdg_popup *xdgpopupv5)
|
||||
{
|
||||
d->setupV5(xdgpopupv5);
|
||||
}
|
||||
|
||||
void XdgShellPopup::setup(zxdg_surface_v6 *xdgsurfacev6, zxdg_popup_v6 *xdgpopupv6)
|
||||
{
|
||||
d->setupV6(xdgsurfacev6, xdgpopupv6);
|
||||
}
|
||||
|
||||
void XdgShellPopup::setup(xdg_surface *surface, xdg_popup *popup)
|
||||
{
|
||||
d->setup(surface, popup);
|
||||
}
|
||||
|
||||
void XdgShellPopup::release()
|
||||
{
|
||||
d->release();
|
||||
}
|
||||
|
||||
void XdgShellPopup::destroy()
|
||||
{
|
||||
d->destroy();
|
||||
}
|
||||
|
||||
void XdgShellPopup::setEventQueue(EventQueue *queue)
|
||||
{
|
||||
d->queue = queue;
|
||||
}
|
||||
|
||||
EventQueue *XdgShellPopup::eventQueue()
|
||||
{
|
||||
return d->queue;
|
||||
}
|
||||
|
||||
void XdgShellPopup::requestGrab(KWayland::Client::Seat *seat, quint32 serial)
|
||||
{
|
||||
d->requestGrab(seat, serial);
|
||||
}
|
||||
|
||||
void XdgShellPopup::ackConfigure(quint32 serial)
|
||||
{
|
||||
d->ackConfigure(serial);
|
||||
}
|
||||
|
||||
void XdgShellPopup::setWindowGeometry(const QRect &windowGeometry)
|
||||
{
|
||||
d->setWindowGeometry(windowGeometry);
|
||||
}
|
||||
|
||||
XdgShellPopup::operator xdg_surface *()
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellPopup::operator xdg_surface *() const
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellPopup::operator xdg_popup *()
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellPopup::operator xdg_popup *() const
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellPopup::operator zxdg_surface_v6 *()
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellPopup::operator zxdg_surface_v6 *() const
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellPopup::operator zxdg_popup_v6 *()
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
XdgShellPopup::operator zxdg_popup_v6 *() const
|
||||
{
|
||||
return *(d.data());
|
||||
}
|
||||
|
||||
bool XdgShellPopup::isValid() const
|
||||
{
|
||||
return d->isValid();
|
||||
}
|
||||
|
||||
XdgPositioner::XdgPositioner(const QSize &initialSize, const QRect &anchor)
|
||||
: d(new Private)
|
||||
{
|
||||
d->initialSize = initialSize;
|
||||
d->anchorRect = anchor;
|
||||
}
|
||||
|
||||
XdgPositioner::XdgPositioner(const XdgPositioner &other)
|
||||
: d(new Private)
|
||||
{
|
||||
*d = *other.d;
|
||||
}
|
||||
|
||||
XdgPositioner::~XdgPositioner()
|
||||
{
|
||||
}
|
||||
|
||||
void XdgPositioner::setInitialSize(const QSize &size)
|
||||
{
|
||||
d->initialSize = size;
|
||||
}
|
||||
|
||||
QSize XdgPositioner::initialSize() const
|
||||
{
|
||||
return d->initialSize;
|
||||
}
|
||||
|
||||
void XdgPositioner::setAnchorRect(const QRect &anchor)
|
||||
{
|
||||
d->anchorRect = anchor;
|
||||
}
|
||||
|
||||
QRect XdgPositioner::anchorRect() const
|
||||
{
|
||||
return d->anchorRect;
|
||||
}
|
||||
|
||||
void XdgPositioner::setAnchorEdge(Qt::Edges edge)
|
||||
{
|
||||
d->anchorEdge = edge;
|
||||
}
|
||||
|
||||
Qt::Edges XdgPositioner::anchorEdge() const
|
||||
{
|
||||
return d->anchorEdge;
|
||||
}
|
||||
|
||||
void XdgPositioner::setAnchorOffset(const QPoint &offset)
|
||||
{
|
||||
d->anchorOffset = offset;
|
||||
}
|
||||
|
||||
QPoint XdgPositioner::anchorOffset() const
|
||||
{
|
||||
return d->anchorOffset;
|
||||
}
|
||||
|
||||
void XdgPositioner::setGravity(Qt::Edges edge)
|
||||
{
|
||||
d->gravity = edge;
|
||||
}
|
||||
|
||||
Qt::Edges XdgPositioner::gravity() const
|
||||
{
|
||||
return d->gravity;
|
||||
}
|
||||
|
||||
void XdgPositioner::setConstraints(Constraints constraints)
|
||||
{
|
||||
d->constraints = constraints;
|
||||
}
|
||||
|
||||
XdgPositioner::Constraints XdgPositioner::constraints() const
|
||||
{
|
||||
return d->constraints;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#include "moc_xdgshell.cpp"
|
||||
#include "moc_xdgshell_p.cpp"
|
||||
@@ -0,0 +1,690 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_XDG_SHELL_H
|
||||
#define KWAYLAND_CLIENT_XDG_SHELL_H
|
||||
|
||||
#include "KWayland/Client/kwaylandclient_export.h"
|
||||
#include <QObject>
|
||||
#include <QRect>
|
||||
#include <QSize>
|
||||
|
||||
// This is a mix of structs for both xdgshell unstable v5 AND xdg wm base stable
|
||||
struct xdg_wm_base;
|
||||
struct xdg_shell;
|
||||
struct xdg_surface;
|
||||
struct xdg_popup;
|
||||
struct xdg_toplevel;
|
||||
|
||||
struct zxdg_shell_v6;
|
||||
struct zxdg_toplevel_v6;
|
||||
struct zxdg_surface_v6;
|
||||
struct zxdg_popup_v6;
|
||||
struct zxdg_position_v6;
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class EventQueue;
|
||||
class Output;
|
||||
class Surface;
|
||||
class Seat;
|
||||
class XdgShellPopup;
|
||||
class XdgShellSurface;
|
||||
|
||||
/**
|
||||
* Builder class describing how a popup should be positioned
|
||||
* when created
|
||||
*
|
||||
* @since 5.39
|
||||
*/
|
||||
class KWAYLANDCLIENT_EXPORT XdgPositioner
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Flags describing how a popup should be reposition if constrained
|
||||
*/
|
||||
enum class Constraint {
|
||||
/*
|
||||
* Slide the popup on the X axis until there is room
|
||||
*/
|
||||
SlideX = 1 << 0,
|
||||
/*
|
||||
* Slide the popup on the Y axis until there is room
|
||||
*/
|
||||
SlideY = 1 << 1,
|
||||
/*
|
||||
* Invert the anchor and gravity on the X axis
|
||||
*/
|
||||
FlipX = 1 << 2,
|
||||
/*
|
||||
* Invert the anchor and gravity on the Y axis
|
||||
*/
|
||||
FlipY = 1 << 3,
|
||||
/*
|
||||
* Resize the popup in the X axis
|
||||
*/
|
||||
ResizeX = 1 << 4,
|
||||
/*
|
||||
* Resize the popup in the Y axis
|
||||
*/
|
||||
ResizeY = 1 << 5,
|
||||
};
|
||||
|
||||
Q_DECLARE_FLAGS(Constraints, Constraint)
|
||||
|
||||
XdgPositioner(const QSize &initialSize = QSize(), const QRect &anchor = QRect());
|
||||
XdgPositioner(const XdgPositioner &other);
|
||||
~XdgPositioner();
|
||||
|
||||
/**
|
||||
* Which edge of the anchor should the popup be positioned around
|
||||
*/
|
||||
// KF6 TODO use a better data type (enum of 8 options) rather than flags which allow invalid values
|
||||
Qt::Edges anchorEdge() const;
|
||||
void setAnchorEdge(Qt::Edges edge);
|
||||
|
||||
/**
|
||||
* Specifies in what direction the popup should be positioned around the anchor
|
||||
* i.e if the gravity is "bottom", then then the top of top of the popup will be at the anchor edge
|
||||
* if the gravity is top, then the bottom of the popup will be at the anchor edge
|
||||
*
|
||||
*/
|
||||
// KF6 TODO use a better data type (enum of 8 options) rather than flags which allow invalid values
|
||||
Qt::Edges gravity() const;
|
||||
void setGravity(Qt::Edges edge);
|
||||
|
||||
/**
|
||||
* The area this popup should be positioned around
|
||||
*/
|
||||
QRect anchorRect() const;
|
||||
void setAnchorRect(const QRect &anchor);
|
||||
|
||||
/**
|
||||
* The size of the surface that is to be positioned.
|
||||
*/
|
||||
QSize initialSize() const;
|
||||
void setInitialSize(const QSize &size);
|
||||
|
||||
/**
|
||||
* Specifies how the compositor should position the popup if it does not fit in the requested position
|
||||
*/
|
||||
Constraints constraints() const;
|
||||
void setConstraints(Constraints constraints);
|
||||
|
||||
/**
|
||||
* An additional offset that should be applied from the anchor.
|
||||
*/
|
||||
QPoint anchorOffset() const;
|
||||
void setAnchorOffset(const QPoint &offset);
|
||||
|
||||
private:
|
||||
class Private;
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(XdgPositioner::Constraints)
|
||||
|
||||
/**
|
||||
* @short Wrapper for the xdg_shell interface.
|
||||
*
|
||||
* This class provides a convenient wrapper for the xdg_shell interface.
|
||||
*
|
||||
* To use this class one needs to interact with the Registry. There are two
|
||||
* possible ways to create the XdgShell interface:
|
||||
* @code
|
||||
* XdgShell *c = registry->createXdgShell(name, version);
|
||||
* @endcode
|
||||
*
|
||||
* This creates the XdgShell and sets it up directly. As an alternative this
|
||||
* can also be done in a more low level way:
|
||||
* @code
|
||||
* XdgShell *c = new XdgShell;
|
||||
* c->setup(registry->bindXdgShell(name, version));
|
||||
* @endcode
|
||||
*
|
||||
* The XdgShell can be used as a drop-in replacement for any xdg_shell
|
||||
* pointer as it provides matching cast operators.
|
||||
*
|
||||
* @see Registry
|
||||
* @since 5.25
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT XdgShell : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgShell() override;
|
||||
|
||||
/**
|
||||
* Setup this XdgShell to manage the @p xdgshellv5.
|
||||
* When using Registry::createXdgShell there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(xdg_shell *xdgshellv5);
|
||||
|
||||
/**
|
||||
* Setup this XdgShell to manage the @p xdgshellv6.
|
||||
* When using Registry::createXdgShell there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zxdg_shell_v6 *xdgshellv6);
|
||||
|
||||
/**
|
||||
* Setup this XdgShell to manage the @p xdg_wm_base.
|
||||
* When using Registry::createXdgShell there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(xdg_wm_base *xdg_wm_base);
|
||||
/**
|
||||
* @returns @c true if managing a xdg_shell.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the xdg_shell interface.
|
||||
* After the interface has been released the XdgShell instance is no
|
||||
* longer valid and can be setup with another xdg_shell interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this XdgShell.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new xdg_shell interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* This method is automatically invoked when the Registry which created this
|
||||
* XdgShell gets destroyed.
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
|
||||
/**
|
||||
* Sets the @p queue to use for creating objects with this XdgShell.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for creating objects with this XdgShell.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Creates a new XdgShellSurface for the given @p surface.
|
||||
**/
|
||||
XdgShellSurface *createSurface(Surface *surface, QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Creates a new XdgShellPopup for the given @p surface on top of @p parentSurface.
|
||||
* This method is only valid for Xdgv5
|
||||
**/
|
||||
XdgShellPopup *createPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Creates a new XdgShellPopup for the given @p surface on top of @p parentSurface with the given @p positioner.
|
||||
* This method is only valid for Xdgv6 onwards.
|
||||
* @since 5.39
|
||||
**/
|
||||
XdgShellPopup *createPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent = nullptr);
|
||||
|
||||
/**
|
||||
* Creates a new XdgShellPopup for the given @p surface on top of @p parentSurface with the given @p positioner.
|
||||
* @since 5.39
|
||||
**/
|
||||
XdgShellPopup *createPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent = nullptr);
|
||||
|
||||
operator xdg_wm_base *();
|
||||
operator xdg_wm_base *() const;
|
||||
operator xdg_shell *();
|
||||
operator xdg_shell *() const;
|
||||
operator zxdg_shell_v6 *();
|
||||
operator zxdg_shell_v6 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The corresponding global for this interface on the Registry got removed.
|
||||
*
|
||||
* This signal gets only emitted if the XdgShell got created by
|
||||
* Registry::createXdgShell
|
||||
**/
|
||||
void removed();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Creates a new XdgShell.
|
||||
* Note: after constructing the XdgShell it is not yet valid and one needs
|
||||
* to call setup. In order to get a ready to use XdgShell prefer using
|
||||
* Registry::createXdgShell.
|
||||
**/
|
||||
class Private;
|
||||
explicit XdgShell(Private *p, QObject *parent = nullptr);
|
||||
|
||||
private:
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* @since 5.25
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT XdgShellSurface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgShellSurface() override;
|
||||
/**
|
||||
* States the Surface can be in
|
||||
**/
|
||||
enum class State {
|
||||
/**
|
||||
* The Surface is maximized.
|
||||
**/
|
||||
Maximized = 1 << 0,
|
||||
/**
|
||||
* The Surface is fullscreen.
|
||||
**/
|
||||
Fullscreen = 1 << 1,
|
||||
/**
|
||||
* The Surface is currently being resized by the Compositor.
|
||||
**/
|
||||
Resizing = 1 << 2,
|
||||
/**
|
||||
* The Surface is considered active. Does not imply keyboard focus.
|
||||
**/
|
||||
Activated = 1 << 3
|
||||
};
|
||||
Q_DECLARE_FLAGS(States, State)
|
||||
|
||||
/**
|
||||
* Setup this XdgShellSurface to manage the @p xdgsurfacev5.
|
||||
* When using XdgShell::createXdgShellSurface there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(xdg_surface *xdgsurfacev5);
|
||||
|
||||
/**
|
||||
* Setup this XdgShellSurface to manage the @p toplevel on the relevant @p xdgsurfacev6
|
||||
* When using XdgShell::createXdgShellSurface there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(zxdg_surface_v6 *xdgsurfacev6, zxdg_toplevel_v6 *toplevel);
|
||||
|
||||
/**
|
||||
* Setup this XdgShellSurface to manage the @p toplevel on the relevant @p xdgsurface
|
||||
* When using XdgShell::createXdgShellSurface there is no need to call this
|
||||
* method.
|
||||
**/
|
||||
void setup(xdg_surface *xdgsurface, xdg_toplevel *toplevel);
|
||||
|
||||
/**
|
||||
* @returns @c true if managing a xdg_surface.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the xdg_surface interface.
|
||||
* After the interface has been released the XdgShellSurface instance is no
|
||||
* longer valid and can be setup with another xdg_surface interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this XdgShellSurface.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new xdg_surface interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, xdgsurfacev5, &XdgShellSurface::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* Sets the @p queue to use for bound proxies.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for bound proxies.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* The currently configured size.
|
||||
* @see sizeChanged
|
||||
* @see setSize
|
||||
**/
|
||||
QSize size() const;
|
||||
|
||||
/**
|
||||
* Sets the size for the XdgShellSurface to @p size.
|
||||
* This is mostly an internal information. The actual size of the XdgShellSurface is
|
||||
* determined by the size of the Buffer attached to the XdgShellSurface's Surface.
|
||||
*
|
||||
* @param size The new size to be used for the XdgShellSurface
|
||||
* @see size
|
||||
* @see sizeChanged
|
||||
**/
|
||||
void setSize(const QSize &size);
|
||||
|
||||
/**
|
||||
* Set this XdgShellSurface as transient for @p parent.
|
||||
**/
|
||||
void setTransientFor(XdgShellSurface *parent);
|
||||
|
||||
/**
|
||||
* Sets the window title of this XdgShellSurface to @p title.
|
||||
**/
|
||||
void setTitle(const QString &title);
|
||||
|
||||
/**
|
||||
* Set an application identifier for the surface.
|
||||
**/
|
||||
void setAppId(const QByteArray &appId);
|
||||
|
||||
/**
|
||||
* Requests to show the window menu at @p pos in surface coordinates.
|
||||
**/
|
||||
void requestShowWindowMenu(Seat *seat, quint32 serial, const QPoint &pos);
|
||||
|
||||
/**
|
||||
* Requests a move on the given @p seat after the pointer button press with the given @p serial.
|
||||
*
|
||||
* @param seat The seat on which to move the window
|
||||
* @param serial The serial of the pointer button press which should trigger the move
|
||||
**/
|
||||
void requestMove(Seat *seat, quint32 serial);
|
||||
|
||||
/**
|
||||
* Requests a resize on the given @p seat after the pointer button press with the given @p serial.
|
||||
*
|
||||
* @param seat The seat on which to resize the window
|
||||
* @param serial The serial of the pointer button press which should trigger the resize
|
||||
* @param edges A hint for the compositor to set e.g. an appropriate cursor image
|
||||
**/
|
||||
void requestResize(Seat *seat, quint32 serial, Qt::Edges edges);
|
||||
|
||||
/**
|
||||
* When a configure event is received, if a client commits the
|
||||
* Surface in response to the configure event, then the client
|
||||
* must make an ackConfigure request sometime before the commit
|
||||
* request, passing along the @p serial of the configure event.
|
||||
* @see configureRequested
|
||||
**/
|
||||
void ackConfigure(quint32 serial);
|
||||
|
||||
/**
|
||||
* Request to set this XdgShellSurface to be maximized if @p set is @c true.
|
||||
* If @p set is @c false it requests to unset the maximized state - if set.
|
||||
*
|
||||
* @param set Whether the XdgShellSurface should be maximized
|
||||
**/
|
||||
void setMaximized(bool set);
|
||||
|
||||
/**
|
||||
* Request to set this XdgShellSurface as fullscreen on @p output.
|
||||
* If @p set is @c true the Surface should be set to fullscreen, otherwise restore
|
||||
* from fullscreen state.
|
||||
*
|
||||
* @param set Whether the Surface should be fullscreen or not
|
||||
* @param output Optional output as hint to the compositor where the Surface should be put
|
||||
**/
|
||||
void setFullscreen(bool set, Output *output = nullptr);
|
||||
|
||||
/**
|
||||
* Request to the compositor to minimize this XdgShellSurface.
|
||||
**/
|
||||
void requestMinimize();
|
||||
|
||||
/**
|
||||
* Set this surface to have a given maximum size
|
||||
* @since 5.39
|
||||
*/
|
||||
void setMaxSize(const QSize &size);
|
||||
|
||||
/**
|
||||
* Set this surface to have a given minimum size
|
||||
* @since 5.39
|
||||
*/
|
||||
void setMinSize(const QSize &size);
|
||||
|
||||
/**
|
||||
* Sets the position of the window contents within the buffer
|
||||
* @since 5.59
|
||||
*/
|
||||
void setWindowGeometry(const QRect &windowGeometry);
|
||||
|
||||
operator xdg_surface *();
|
||||
operator xdg_surface *() const;
|
||||
operator xdg_toplevel *();
|
||||
operator xdg_toplevel *() const;
|
||||
operator zxdg_surface_v6 *();
|
||||
operator zxdg_surface_v6 *() const;
|
||||
operator zxdg_toplevel_v6 *();
|
||||
operator zxdg_toplevel_v6 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* The compositor requested to close this window.
|
||||
**/
|
||||
void closeRequested();
|
||||
/**
|
||||
* The compositor sent a configure with the new @p size and the @p states.
|
||||
* Before the next commit of the surface the @p serial needs to be passed to ackConfigure.
|
||||
**/
|
||||
void configureRequested(const QSize &size, KWayland::Client::XdgShellSurface::States states, quint32 serial);
|
||||
|
||||
/**
|
||||
* Emitted whenever the size of the XdgShellSurface changes by e.g. receiving a configure request.
|
||||
*
|
||||
* @see configureRequested
|
||||
* @see size
|
||||
* @see setSize
|
||||
**/
|
||||
void sizeChanged(const QSize &);
|
||||
|
||||
protected:
|
||||
class Private;
|
||||
explicit XdgShellSurface(Private *p, QObject *parent = nullptr);
|
||||
|
||||
private:
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(XdgShellSurface::States)
|
||||
|
||||
/**
|
||||
* A XdgShellPopup is a short-lived, temporary surface that can be
|
||||
* used to implement menus. It takes an explicit grab on the surface
|
||||
* that will be dismissed when the user dismisses the popup. This can
|
||||
* be done by the user clicking outside the surface, using the keyboard,
|
||||
* or even locking the screen through closing the lid or a timeout.
|
||||
* @since 5.25
|
||||
**/
|
||||
class KWAYLANDCLIENT_EXPORT XdgShellPopup : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgShellPopup() override;
|
||||
|
||||
/**
|
||||
* Setup this XdgShellPopup to manage the @p xdgpopupv5.
|
||||
* When using XdgShell::createXdgShellPopup there is no need to call this
|
||||
* method.
|
||||
*
|
||||
* @deprecated Since 5.49. This was for XDGShellV5, this is now deprecated
|
||||
**/
|
||||
// KWAYLANDCLIENT_DEPRECATED_VERSION(5, 49, "Use XDGShell version >5") // TODO KF6 remove internal usage
|
||||
void setup(xdg_popup *xdgpopupv5);
|
||||
|
||||
/**
|
||||
* Setup this XdgShellPopup to manage the @p xdgpopupv6 on associated @p xdgsurfacev6
|
||||
* When using XdgShell::createXdgShellPopup there is no need to call this
|
||||
* method.
|
||||
* @since 5.39
|
||||
**/
|
||||
void setup(zxdg_surface_v6 *xdgsurfacev6, zxdg_popup_v6 *xdgpopup6);
|
||||
|
||||
/**
|
||||
* Setup this XdgShellPopup to manage the @p xdgpopupv on associated @p xdgsurface
|
||||
* When using XdgShell::createXdgShellPopup there is no need to call this
|
||||
* method.
|
||||
* @since 5.XDGSTABLE
|
||||
**/
|
||||
void setup(xdg_surface *xdgsurface, xdg_popup *xdgpopup);
|
||||
|
||||
/**
|
||||
* @returns @c true if managing an xdg_popup.
|
||||
**/
|
||||
bool isValid() const;
|
||||
/**
|
||||
* Releases the xdg_popup interface.
|
||||
* After the interface has been released the XdgShellPopup instance is no
|
||||
* longer valid and can be setup with another xdg_popup interface.
|
||||
**/
|
||||
void release();
|
||||
/**
|
||||
* Destroys the data held by this XdgShellPopup.
|
||||
* This method is supposed to be used when the connection to the Wayland
|
||||
* server goes away. If the connection is not valid anymore, it's not
|
||||
* possible to call release anymore as that calls into the Wayland
|
||||
* connection and the call would fail. This method cleans up the data, so
|
||||
* that the instance can be deleted or set up to a new xdg_popup interface
|
||||
* once there is a new connection available.
|
||||
*
|
||||
* It is suggested to connect this method to ConnectionThread::connectionDied:
|
||||
* @code
|
||||
* connect(connection, &ConnectionThread::connectionDied, xdgpopupv5, &XdgShellPopup::destroy);
|
||||
* @endcode
|
||||
*
|
||||
* @see release
|
||||
**/
|
||||
void destroy();
|
||||
/**
|
||||
* Sets the @p queue to use for bound proxies.
|
||||
**/
|
||||
void setEventQueue(EventQueue *queue);
|
||||
/**
|
||||
* @returns The event queue to use for bound proxies.
|
||||
**/
|
||||
EventQueue *eventQueue();
|
||||
|
||||
/**
|
||||
* Requests a grab on this popup
|
||||
* @since 5.39
|
||||
*/
|
||||
void requestGrab(Seat *seat, quint32 serial);
|
||||
|
||||
/**
|
||||
* When a configure event is received, if a client commits the
|
||||
* Surface in response to the configure event, then the client
|
||||
* must make an ackConfigure request sometime before the commit
|
||||
* request, passing along the @p serial of the configure event.
|
||||
* @see configureRequested
|
||||
* @since 5.56
|
||||
**/
|
||||
void ackConfigure(quint32 serial);
|
||||
|
||||
/**
|
||||
* Sets the position of the window contents within the buffer
|
||||
* @since 5.59
|
||||
*/
|
||||
void setWindowGeometry(const QRect &windowGeometry);
|
||||
|
||||
operator xdg_surface *();
|
||||
operator xdg_surface *() const;
|
||||
operator xdg_popup *();
|
||||
operator xdg_popup *() const;
|
||||
operator zxdg_surface_v6 *();
|
||||
operator zxdg_surface_v6 *() const;
|
||||
operator zxdg_popup_v6 *();
|
||||
operator zxdg_popup_v6 *() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
/**
|
||||
* This signal is emitted when a XdgShellPopup is dismissed by the
|
||||
* compositor. The user should delete this instance at this point.
|
||||
**/
|
||||
void popupDone();
|
||||
|
||||
/**
|
||||
* Emitted when the server has configured the popup with the final location of @p relativePosition
|
||||
* This is emitted for V6 surfaces only
|
||||
* @since 5.39
|
||||
**/
|
||||
void configureRequested(const QRect &relativePosition, quint32 serial);
|
||||
|
||||
protected:
|
||||
class Private;
|
||||
explicit XdgShellPopup(Private *p, QObject *parent = nullptr);
|
||||
|
||||
private:
|
||||
QScopedPointer<Private> d;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper class for xdg_wm_base interface.
|
||||
*
|
||||
* @since 5.101
|
||||
*/
|
||||
class KWAYLANDCLIENT_EXPORT XdgShellStable : public XdgShell
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit XdgShellStable(QObject *parent = nullptr);
|
||||
~XdgShellStable() override;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper class for xdg_toplevel interface.
|
||||
*
|
||||
* @since 5.101
|
||||
*/
|
||||
class KWAYLANDCLIENT_EXPORT XdgTopLevelStable : public XdgShellSurface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit XdgTopLevelStable(QObject *parent = nullptr);
|
||||
~XdgTopLevelStable() override;
|
||||
|
||||
private:
|
||||
friend class XdgShellStable;
|
||||
class Private;
|
||||
};
|
||||
|
||||
/**
|
||||
* Wrapper class for xdg_popup interface.
|
||||
*
|
||||
* @since 5.101
|
||||
*/
|
||||
class KWAYLANDCLIENT_EXPORT XdgShellPopupStable : public XdgShellPopup
|
||||
{
|
||||
public:
|
||||
explicit XdgShellPopupStable(QObject *parent = nullptr);
|
||||
~XdgShellPopupStable() override;
|
||||
|
||||
private:
|
||||
friend class XdgShellStable;
|
||||
class Private;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(KWayland::Client::XdgPositioner)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::XdgShellSurface::State)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::XdgShellSurface::States)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::XdgPositioner::Constraint)
|
||||
Q_DECLARE_METATYPE(KWayland::Client::XdgPositioner::Constraints)
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,345 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#ifndef KWAYLAND_CLIENT_XDGSHELL_P_H
|
||||
#define KWAYLAND_CLIENT_XDGSHELL_P_H
|
||||
#include "xdgshell.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QRect>
|
||||
#include <QSize>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class Q_DECL_HIDDEN XdgShell::Private
|
||||
{
|
||||
public:
|
||||
virtual ~Private();
|
||||
virtual void setupV5(xdg_shell *xdgshellv5)
|
||||
{
|
||||
Q_UNUSED(xdgshellv5)
|
||||
}
|
||||
virtual void setupV6(zxdg_shell_v6 *xdgshellv6)
|
||||
{
|
||||
Q_UNUSED(xdgshellv6)
|
||||
}
|
||||
virtual void setup(xdg_wm_base *xdgshell)
|
||||
{
|
||||
Q_UNUSED(xdgshell);
|
||||
}
|
||||
virtual void release() = 0;
|
||||
virtual void destroy() = 0;
|
||||
virtual bool isValid() const = 0;
|
||||
virtual operator xdg_shell *()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator xdg_shell *() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator zxdg_shell_v6 *()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator zxdg_shell_v6 *() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator xdg_wm_base *()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator xdg_wm_base *() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual XdgShellSurface *getXdgSurface(Surface *surface, QObject *parent) = 0;
|
||||
|
||||
virtual XdgShellPopup *getXdgPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent)
|
||||
{
|
||||
Q_UNUSED(surface)
|
||||
Q_UNUSED(parentSurface)
|
||||
Q_UNUSED(seat)
|
||||
Q_UNUSED(serial)
|
||||
Q_UNUSED(parentPos)
|
||||
Q_UNUSED(parent)
|
||||
Q_ASSERT(false);
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
virtual XdgShellPopup *getXdgPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent)
|
||||
{
|
||||
Q_UNUSED(surface)
|
||||
Q_UNUSED(parentSurface)
|
||||
Q_UNUSED(positioner)
|
||||
Q_UNUSED(parent)
|
||||
Q_ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual XdgShellPopup *getXdgPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent)
|
||||
{
|
||||
Q_UNUSED(surface)
|
||||
Q_UNUSED(parentSurface)
|
||||
Q_UNUSED(positioner)
|
||||
Q_UNUSED(parent)
|
||||
Q_ASSERT(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EventQueue *queue = nullptr;
|
||||
|
||||
protected:
|
||||
Private() = default;
|
||||
};
|
||||
|
||||
class XdgShellUnstableV5 : public XdgShell
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit XdgShellUnstableV5(QObject *parent = nullptr);
|
||||
~XdgShellUnstableV5() override;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
};
|
||||
|
||||
class XdgShellUnstableV6 : public XdgShell
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit XdgShellUnstableV6(QObject *parent = nullptr);
|
||||
~XdgShellUnstableV6() override;
|
||||
|
||||
private:
|
||||
class Private;
|
||||
};
|
||||
|
||||
class XdgShellSurfaceUnstableV5 : public XdgShellSurface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgShellSurfaceUnstableV5() override;
|
||||
|
||||
private:
|
||||
explicit XdgShellSurfaceUnstableV5(QObject *parent = nullptr);
|
||||
friend class XdgShellUnstableV5;
|
||||
class Private;
|
||||
};
|
||||
|
||||
class XdgTopLevelUnstableV6 : public XdgShellSurface
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgTopLevelUnstableV6() override;
|
||||
|
||||
private:
|
||||
explicit XdgTopLevelUnstableV6(QObject *parent = nullptr);
|
||||
friend class XdgShellUnstableV6;
|
||||
class Private;
|
||||
};
|
||||
|
||||
class Q_DECL_HIDDEN XdgShellSurface::Private
|
||||
{
|
||||
public:
|
||||
virtual ~Private();
|
||||
EventQueue *queue = nullptr;
|
||||
QSize size;
|
||||
|
||||
virtual void setupV5(xdg_surface *surface)
|
||||
{
|
||||
Q_UNUSED(surface)
|
||||
}
|
||||
virtual void setupV6(zxdg_surface_v6 *surface, zxdg_toplevel_v6 *toplevel)
|
||||
{
|
||||
Q_UNUSED(toplevel)
|
||||
Q_UNUSED(surface)
|
||||
}
|
||||
virtual void setup(xdg_surface *surface, xdg_toplevel *toplevel)
|
||||
{
|
||||
Q_UNUSED(surface)
|
||||
Q_UNUSED(toplevel)
|
||||
}
|
||||
virtual void release() = 0;
|
||||
virtual void destroy() = 0;
|
||||
virtual bool isValid() const = 0;
|
||||
virtual operator xdg_surface *()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator xdg_surface *() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator xdg_toplevel *()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator xdg_toplevel *() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator zxdg_surface_v6 *()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator zxdg_surface_v6 *() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator zxdg_toplevel_v6 *()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator zxdg_toplevel_v6 *() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void setTransientFor(XdgShellSurface *parent) = 0;
|
||||
virtual void setTitle(const QString &title) = 0;
|
||||
virtual void setAppId(const QByteArray &appId) = 0;
|
||||
virtual void showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) = 0;
|
||||
virtual void move(Seat *seat, quint32 serial) = 0;
|
||||
virtual void resize(Seat *seat, quint32 serial, Qt::Edges edges) = 0;
|
||||
virtual void ackConfigure(quint32 serial) = 0;
|
||||
virtual void setMaximized() = 0;
|
||||
virtual void unsetMaximized() = 0;
|
||||
virtual void setFullscreen(Output *output) = 0;
|
||||
virtual void unsetFullscreen() = 0;
|
||||
virtual void setMinimized() = 0;
|
||||
virtual void setMaxSize(const QSize &size) = 0;
|
||||
virtual void setMinSize(const QSize &size) = 0;
|
||||
virtual void setWindowGeometry(const QRect &windowGeometry)
|
||||
{
|
||||
Q_UNUSED(windowGeometry);
|
||||
}
|
||||
|
||||
protected:
|
||||
Private(XdgShellSurface *q);
|
||||
|
||||
XdgShellSurface *q;
|
||||
};
|
||||
|
||||
class Q_DECL_HIDDEN XdgShellPopup::Private
|
||||
{
|
||||
public:
|
||||
Private(XdgShellPopup *q);
|
||||
virtual ~Private();
|
||||
|
||||
EventQueue *queue = nullptr;
|
||||
|
||||
virtual void setupV5(xdg_popup *p)
|
||||
{
|
||||
Q_UNUSED(p)
|
||||
}
|
||||
virtual void setupV6(zxdg_surface_v6 *s, zxdg_popup_v6 *p)
|
||||
{
|
||||
Q_UNUSED(s)
|
||||
Q_UNUSED(p)
|
||||
}
|
||||
virtual void setup(xdg_surface *s, xdg_popup *p)
|
||||
{
|
||||
Q_UNUSED(s)
|
||||
Q_UNUSED(p)
|
||||
}
|
||||
virtual void release() = 0;
|
||||
virtual void destroy() = 0;
|
||||
virtual bool isValid() const = 0;
|
||||
virtual void requestGrab(Seat *seat, quint32 serial)
|
||||
{
|
||||
Q_UNUSED(seat);
|
||||
Q_UNUSED(serial);
|
||||
};
|
||||
virtual void ackConfigure(quint32 serial)
|
||||
{
|
||||
Q_UNUSED(serial);
|
||||
}
|
||||
|
||||
virtual void setWindowGeometry(const QRect &windowGeometry)
|
||||
{
|
||||
Q_UNUSED(windowGeometry);
|
||||
}
|
||||
|
||||
virtual operator xdg_surface *()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator xdg_surface *() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator xdg_popup *()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator xdg_popup *() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator zxdg_surface_v6 *()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator zxdg_surface_v6 *() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator zxdg_popup_v6 *()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
virtual operator zxdg_popup_v6 *() const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
XdgShellPopup *q;
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
class XdgPositioner::Private
|
||||
{
|
||||
public:
|
||||
QSize initialSize;
|
||||
QRect anchorRect;
|
||||
Qt::Edges gravity;
|
||||
Qt::Edges anchorEdge;
|
||||
XdgPositioner::Constraints constraints;
|
||||
QPoint anchorOffset;
|
||||
};
|
||||
|
||||
class XdgShellPopupUnstableV5 : public XdgShellPopup
|
||||
{
|
||||
public:
|
||||
~XdgShellPopupUnstableV5() override;
|
||||
|
||||
private:
|
||||
explicit XdgShellPopupUnstableV5(QObject *parent = nullptr);
|
||||
friend class XdgShellUnstableV5;
|
||||
class Private;
|
||||
};
|
||||
|
||||
class XdgShellPopupUnstableV6 : public XdgShellPopup
|
||||
{
|
||||
public:
|
||||
~XdgShellPopupUnstableV6() override;
|
||||
|
||||
private:
|
||||
explicit XdgShellPopupUnstableV6(QObject *parent = nullptr);
|
||||
friend class XdgShellUnstableV6;
|
||||
class Private;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,610 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2017 David Edmundson <davidedmundson@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "event_queue.h"
|
||||
#include "output.h"
|
||||
#include "seat.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
#include "xdgshell_p.h"
|
||||
#include <wayland-xdg-shell-client-protocol.h>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class XdgShellStable::Private : public XdgShell::Private
|
||||
{
|
||||
public:
|
||||
void setup(xdg_wm_base *shell) override;
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() const override;
|
||||
XdgShellSurface *getXdgSurface(Surface *surface, QObject *parent) override;
|
||||
|
||||
XdgShellPopup *getXdgPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent) override;
|
||||
XdgShellPopup *getXdgPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent) override;
|
||||
|
||||
using XdgShell::Private::operator xdg_shell *;
|
||||
using XdgShell::Private::operator zxdg_shell_v6 *;
|
||||
operator xdg_wm_base *() override
|
||||
{
|
||||
return xdg_shell_base;
|
||||
}
|
||||
operator xdg_wm_base *() const override
|
||||
{
|
||||
return xdg_shell_base;
|
||||
}
|
||||
|
||||
private:
|
||||
XdgShellPopup *internalGetXdgPopup(Surface *surface, xdg_surface *parentSurface, const XdgPositioner &positioner, QObject *parent);
|
||||
static void pingCallback(void *data, struct xdg_wm_base *shell, uint32_t serial);
|
||||
|
||||
WaylandPointer<xdg_wm_base, xdg_wm_base_destroy> xdg_shell_base;
|
||||
static const struct xdg_wm_base_listener s_shellListener;
|
||||
};
|
||||
|
||||
const struct xdg_wm_base_listener XdgShellStable::Private::s_shellListener = {
|
||||
pingCallback,
|
||||
};
|
||||
|
||||
void XdgShellStable::Private::pingCallback(void *data, struct xdg_wm_base *shell, uint32_t serial)
|
||||
{
|
||||
Q_UNUSED(data)
|
||||
xdg_wm_base_pong(shell, serial);
|
||||
}
|
||||
|
||||
void XdgShellStable::Private::setup(xdg_wm_base *shell)
|
||||
{
|
||||
Q_ASSERT(shell);
|
||||
Q_ASSERT(!xdg_shell_base);
|
||||
xdg_shell_base.setup(shell);
|
||||
xdg_wm_base_add_listener(shell, &s_shellListener, this);
|
||||
}
|
||||
|
||||
void XdgShellStable::Private::release()
|
||||
{
|
||||
xdg_shell_base.release();
|
||||
}
|
||||
|
||||
void XdgShellStable::Private::destroy()
|
||||
{
|
||||
xdg_shell_base.destroy();
|
||||
}
|
||||
|
||||
bool XdgShellStable::Private::isValid() const
|
||||
{
|
||||
return xdg_shell_base.isValid();
|
||||
}
|
||||
|
||||
XdgShellSurface *XdgShellStable::Private::getXdgSurface(Surface *surface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
auto ss = xdg_wm_base_get_xdg_surface(xdg_shell_base, *surface);
|
||||
|
||||
if (!ss) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto s = new XdgTopLevelStable(parent);
|
||||
auto toplevel = xdg_surface_get_toplevel(ss);
|
||||
if (queue) {
|
||||
queue->addProxy(ss);
|
||||
queue->addProxy(toplevel);
|
||||
}
|
||||
s->setup(ss, toplevel);
|
||||
return s;
|
||||
}
|
||||
|
||||
XdgShellPopup *XdgShellStable::Private::getXdgPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent)
|
||||
{
|
||||
return internalGetXdgPopup(surface, *parentSurface, positioner, parent);
|
||||
}
|
||||
|
||||
XdgShellPopup *XdgShellStable::Private::getXdgPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent)
|
||||
{
|
||||
return internalGetXdgPopup(surface, *parentSurface, positioner, parent);
|
||||
}
|
||||
|
||||
XdgShellPopup *XdgShellStable::Private::internalGetXdgPopup(Surface *surface, xdg_surface *parentSurface, const XdgPositioner &positioner, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
auto ss = xdg_wm_base_get_xdg_surface(xdg_shell_base, *surface);
|
||||
if (!ss) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto p = xdg_wm_base_create_positioner(xdg_shell_base);
|
||||
|
||||
auto anchorRect = positioner.anchorRect();
|
||||
xdg_positioner_set_anchor_rect(p, anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height());
|
||||
|
||||
QSize initialSize = positioner.initialSize();
|
||||
xdg_positioner_set_size(p, initialSize.width(), initialSize.height());
|
||||
|
||||
QPoint anchorOffset = positioner.anchorOffset();
|
||||
if (!anchorOffset.isNull()) {
|
||||
xdg_positioner_set_offset(p, anchorOffset.x(), anchorOffset.y());
|
||||
}
|
||||
|
||||
uint32_t anchor = XDG_POSITIONER_ANCHOR_NONE;
|
||||
if (positioner.anchorEdge().testFlag(Qt::TopEdge)) {
|
||||
if (positioner.anchorEdge().testFlag(Qt::LeftEdge) && ((positioner.anchorEdge() & ~Qt::LeftEdge) == Qt::TopEdge)) {
|
||||
anchor = XDG_POSITIONER_ANCHOR_TOP_LEFT;
|
||||
} else if (positioner.anchorEdge().testFlag(Qt::RightEdge) && ((positioner.anchorEdge() & ~Qt::RightEdge) == Qt::TopEdge)) {
|
||||
anchor = XDG_POSITIONER_ANCHOR_TOP_RIGHT;
|
||||
} else if ((positioner.anchorEdge() & ~Qt::TopEdge) == Qt::Edges()) {
|
||||
anchor = XDG_POSITIONER_ANCHOR_TOP;
|
||||
}
|
||||
} else if (positioner.anchorEdge().testFlag(Qt::BottomEdge)) {
|
||||
if (positioner.anchorEdge().testFlag(Qt::LeftEdge) && ((positioner.anchorEdge() & ~Qt::LeftEdge) == Qt::BottomEdge)) {
|
||||
anchor = XDG_POSITIONER_ANCHOR_BOTTOM_LEFT;
|
||||
} else if (positioner.anchorEdge().testFlag(Qt::RightEdge) && ((positioner.anchorEdge() & ~Qt::RightEdge) == Qt::BottomEdge)) {
|
||||
anchor = XDG_POSITIONER_ANCHOR_BOTTOM_RIGHT;
|
||||
} else if ((positioner.anchorEdge() & ~Qt::BottomEdge) == Qt::Edges()) {
|
||||
anchor = XDG_POSITIONER_ANCHOR_BOTTOM;
|
||||
}
|
||||
} else if (positioner.anchorEdge().testFlag(Qt::RightEdge) && ((positioner.anchorEdge() & ~Qt::RightEdge) == Qt::Edges())) {
|
||||
anchor = XDG_POSITIONER_ANCHOR_RIGHT;
|
||||
} else if (positioner.anchorEdge().testFlag(Qt::LeftEdge) && ((positioner.anchorEdge() & ~Qt::LeftEdge) == Qt::Edges())) {
|
||||
anchor = XDG_POSITIONER_ANCHOR_LEFT;
|
||||
}
|
||||
if (anchor != 0) {
|
||||
xdg_positioner_set_anchor(p, anchor);
|
||||
}
|
||||
|
||||
uint32_t gravity = XDG_POSITIONER_GRAVITY_NONE;
|
||||
if (positioner.gravity().testFlag(Qt::TopEdge)) {
|
||||
if (positioner.gravity().testFlag(Qt::LeftEdge) && ((positioner.gravity() & ~Qt::LeftEdge) == Qt::TopEdge)) {
|
||||
gravity = XDG_POSITIONER_GRAVITY_TOP_LEFT;
|
||||
} else if (positioner.gravity().testFlag(Qt::RightEdge) && ((positioner.gravity() & ~Qt::RightEdge) == Qt::TopEdge)) {
|
||||
gravity = XDG_POSITIONER_GRAVITY_TOP_RIGHT;
|
||||
} else if ((positioner.gravity() & ~Qt::TopEdge) == Qt::Edges()) {
|
||||
gravity = XDG_POSITIONER_GRAVITY_TOP;
|
||||
}
|
||||
} else if (positioner.gravity().testFlag(Qt::BottomEdge)) {
|
||||
if (positioner.gravity().testFlag(Qt::LeftEdge) && ((positioner.gravity() & ~Qt::LeftEdge) == Qt::BottomEdge)) {
|
||||
gravity = XDG_POSITIONER_GRAVITY_BOTTOM_LEFT;
|
||||
} else if (positioner.gravity().testFlag(Qt::RightEdge) && ((positioner.gravity() & ~Qt::RightEdge) == Qt::BottomEdge)) {
|
||||
gravity = XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT;
|
||||
} else if ((positioner.gravity() & ~Qt::BottomEdge) == Qt::Edges()) {
|
||||
gravity = XDG_POSITIONER_GRAVITY_BOTTOM;
|
||||
}
|
||||
} else if (positioner.gravity().testFlag(Qt::RightEdge) && ((positioner.gravity() & ~Qt::RightEdge) == Qt::Edges())) {
|
||||
gravity = XDG_POSITIONER_GRAVITY_RIGHT;
|
||||
} else if (positioner.gravity().testFlag(Qt::LeftEdge) && ((positioner.gravity() & ~Qt::LeftEdge) == Qt::Edges())) {
|
||||
gravity = XDG_POSITIONER_GRAVITY_LEFT;
|
||||
}
|
||||
if (gravity != 0) {
|
||||
xdg_positioner_set_gravity(p, gravity);
|
||||
}
|
||||
|
||||
uint32_t constraint = XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_NONE;
|
||||
if (positioner.constraints().testFlag(XdgPositioner::Constraint::SlideX)) {
|
||||
constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X;
|
||||
}
|
||||
if (positioner.constraints().testFlag(XdgPositioner::Constraint::SlideY)) {
|
||||
constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
|
||||
}
|
||||
if (positioner.constraints().testFlag(XdgPositioner::Constraint::FlipX)) {
|
||||
constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_X;
|
||||
}
|
||||
if (positioner.constraints().testFlag(XdgPositioner::Constraint::FlipY)) {
|
||||
constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y;
|
||||
}
|
||||
if (positioner.constraints().testFlag(XdgPositioner::Constraint::ResizeX)) {
|
||||
constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_X;
|
||||
}
|
||||
if (positioner.constraints().testFlag(XdgPositioner::Constraint::ResizeY)) {
|
||||
constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
|
||||
}
|
||||
if (constraint != 0) {
|
||||
xdg_positioner_set_constraint_adjustment(p, constraint);
|
||||
}
|
||||
|
||||
XdgShellPopup *s = new XdgShellPopupStable(parent);
|
||||
auto popup = xdg_surface_get_popup(ss, parentSurface, p);
|
||||
if (queue) {
|
||||
// deliberately not adding the positioner because the positioner has no events sent to it
|
||||
queue->addProxy(ss);
|
||||
queue->addProxy(popup);
|
||||
}
|
||||
s->setup(ss, popup);
|
||||
|
||||
xdg_positioner_destroy(p);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
XdgShellStable::XdgShellStable(QObject *parent)
|
||||
: XdgShell(new Private, parent)
|
||||
{
|
||||
}
|
||||
|
||||
XdgShellStable::~XdgShellStable() = default;
|
||||
|
||||
// A top level wraps both xdg_surface and xdg_top_level into the public API XdgShelllSurface
|
||||
class XdgTopLevelStable::Private : public XdgShellSurface::Private
|
||||
{
|
||||
public:
|
||||
Private(XdgShellSurface *q);
|
||||
WaylandPointer<xdg_toplevel, xdg_toplevel_destroy> xdgtoplevel;
|
||||
WaylandPointer<xdg_surface, xdg_surface_destroy> xdgsurface;
|
||||
|
||||
void setup(xdg_surface *surface, xdg_toplevel *toplevel) override;
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() const override;
|
||||
|
||||
using XdgShellSurface::Private::operator zxdg_toplevel_v6 *;
|
||||
using XdgShellSurface::Private::operator zxdg_surface_v6 *;
|
||||
operator xdg_surface *() override
|
||||
{
|
||||
return xdgsurface;
|
||||
}
|
||||
operator xdg_surface *() const override
|
||||
{
|
||||
return xdgsurface;
|
||||
}
|
||||
operator xdg_toplevel *() override
|
||||
{
|
||||
return xdgtoplevel;
|
||||
}
|
||||
operator xdg_toplevel *() const override
|
||||
{
|
||||
return xdgtoplevel;
|
||||
}
|
||||
|
||||
void setTransientFor(XdgShellSurface *parent) override;
|
||||
void setTitle(const QString &title) override;
|
||||
void setAppId(const QByteArray &appId) override;
|
||||
void showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) override;
|
||||
void move(Seat *seat, quint32 serial) override;
|
||||
void resize(Seat *seat, quint32 serial, Qt::Edges edges) override;
|
||||
void ackConfigure(quint32 serial) override;
|
||||
void setMaximized() override;
|
||||
void unsetMaximized() override;
|
||||
void setFullscreen(Output *output) override;
|
||||
void unsetFullscreen() override;
|
||||
void setMinimized() override;
|
||||
void setMaxSize(const QSize &size) override;
|
||||
void setMinSize(const QSize &size) override;
|
||||
void setWindowGeometry(const QRect &windowGeometry) override;
|
||||
|
||||
private:
|
||||
QSize pendingSize;
|
||||
States pendingState;
|
||||
|
||||
static void configureCallback(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *state);
|
||||
static void closeCallback(void *data, xdg_toplevel *xdg_toplevel);
|
||||
static void surfaceConfigureCallback(void *data, xdg_surface *xdg_surface, uint32_t serial);
|
||||
|
||||
static const struct xdg_toplevel_listener s_toplevelListener;
|
||||
static const struct xdg_surface_listener s_surfaceListener;
|
||||
};
|
||||
|
||||
const struct xdg_toplevel_listener XdgTopLevelStable::Private::s_toplevelListener = {configureCallback, closeCallback};
|
||||
|
||||
const struct xdg_surface_listener XdgTopLevelStable::Private::s_surfaceListener = {surfaceConfigureCallback};
|
||||
|
||||
void XdgTopLevelStable::Private::surfaceConfigureCallback(void *data, struct xdg_surface *surface, uint32_t serial)
|
||||
{
|
||||
Q_UNUSED(surface)
|
||||
auto s = static_cast<Private *>(data);
|
||||
s->q->configureRequested(s->pendingSize, s->pendingState, serial);
|
||||
if (!s->pendingSize.isNull()) {
|
||||
s->q->setSize(s->pendingSize);
|
||||
s->pendingSize = QSize();
|
||||
}
|
||||
s->pendingState = {};
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::configureCallback(void *data, struct xdg_toplevel *xdg_toplevel, int32_t width, int32_t height, struct wl_array *state)
|
||||
{
|
||||
Q_UNUSED(xdg_toplevel)
|
||||
auto s = static_cast<Private *>(data);
|
||||
States states;
|
||||
|
||||
uint32_t *statePtr = static_cast<uint32_t *>(state->data);
|
||||
for (size_t i = 0; i < state->size / sizeof(uint32_t); i++) {
|
||||
switch (statePtr[i]) {
|
||||
case XDG_TOPLEVEL_STATE_MAXIMIZED:
|
||||
states = states | XdgShellSurface::State::Maximized;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_FULLSCREEN:
|
||||
states = states | XdgShellSurface::State::Fullscreen;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_RESIZING:
|
||||
states = states | XdgShellSurface::State::Resizing;
|
||||
break;
|
||||
case XDG_TOPLEVEL_STATE_ACTIVATED:
|
||||
states = states | XdgShellSurface::State::Activated;
|
||||
break;
|
||||
}
|
||||
}
|
||||
s->pendingSize = QSize(width, height);
|
||||
s->pendingState = states;
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::closeCallback(void *data, xdg_toplevel *xdg_toplevel)
|
||||
{
|
||||
auto s = static_cast<XdgTopLevelStable::Private *>(data);
|
||||
Q_ASSERT(s->xdgtoplevel == xdg_toplevel);
|
||||
Q_EMIT s->q->closeRequested();
|
||||
}
|
||||
|
||||
XdgTopLevelStable::Private::Private(XdgShellSurface *q)
|
||||
: XdgShellSurface::Private(q)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::setup(xdg_surface *surface, xdg_toplevel *topLevel)
|
||||
{
|
||||
Q_ASSERT(surface);
|
||||
Q_ASSERT(!xdgtoplevel);
|
||||
xdgsurface.setup(surface);
|
||||
xdgtoplevel.setup(topLevel);
|
||||
xdg_surface_add_listener(xdgsurface, &s_surfaceListener, this);
|
||||
xdg_toplevel_add_listener(xdgtoplevel, &s_toplevelListener, this);
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::release()
|
||||
{
|
||||
xdgtoplevel.release();
|
||||
xdgsurface.release();
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::destroy()
|
||||
{
|
||||
xdgtoplevel.destroy();
|
||||
xdgsurface.destroy();
|
||||
}
|
||||
|
||||
bool XdgTopLevelStable::Private::isValid() const
|
||||
{
|
||||
return xdgtoplevel.isValid() && xdgsurface.isValid();
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::setTransientFor(XdgShellSurface *parent)
|
||||
{
|
||||
xdg_toplevel *parentSurface = nullptr;
|
||||
if (parent) {
|
||||
parentSurface = *parent;
|
||||
}
|
||||
xdg_toplevel_set_parent(xdgtoplevel, parentSurface);
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::setTitle(const QString &title)
|
||||
{
|
||||
xdg_toplevel_set_title(xdgtoplevel, title.toUtf8().constData());
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::setAppId(const QByteArray &appId)
|
||||
{
|
||||
xdg_toplevel_set_app_id(xdgtoplevel, appId.constData());
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y)
|
||||
{
|
||||
xdg_toplevel_show_window_menu(xdgtoplevel, *seat, serial, x, y);
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::move(Seat *seat, quint32 serial)
|
||||
{
|
||||
xdg_toplevel_move(xdgtoplevel, *seat, serial);
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::resize(Seat *seat, quint32 serial, Qt::Edges edges)
|
||||
{
|
||||
uint wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_NONE;
|
||||
if (edges.testFlag(Qt::TopEdge)) {
|
||||
if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::TopEdge)) {
|
||||
wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_LEFT;
|
||||
} else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::TopEdge)) {
|
||||
wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_TOP_RIGHT;
|
||||
} else if ((edges & ~Qt::TopEdge) == Qt::Edges()) {
|
||||
wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_TOP;
|
||||
}
|
||||
} else if (edges.testFlag(Qt::BottomEdge)) {
|
||||
if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::BottomEdge)) {
|
||||
wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_LEFT;
|
||||
} else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::BottomEdge)) {
|
||||
wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM_RIGHT;
|
||||
} else if ((edges & ~Qt::BottomEdge) == Qt::Edges()) {
|
||||
wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_BOTTOM;
|
||||
}
|
||||
} else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::Edges())) {
|
||||
wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_RIGHT;
|
||||
} else if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::Edges())) {
|
||||
wlEdge = XDG_TOPLEVEL_RESIZE_EDGE_LEFT;
|
||||
}
|
||||
xdg_toplevel_resize(xdgtoplevel, *seat, serial, wlEdge);
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::ackConfigure(quint32 serial)
|
||||
{
|
||||
xdg_surface_ack_configure(xdgsurface, serial);
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::setMaximized()
|
||||
{
|
||||
xdg_toplevel_set_maximized(xdgtoplevel);
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::unsetMaximized()
|
||||
{
|
||||
xdg_toplevel_unset_maximized(xdgtoplevel);
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::setFullscreen(Output *output)
|
||||
{
|
||||
wl_output *o = nullptr;
|
||||
if (output) {
|
||||
o = *output;
|
||||
}
|
||||
xdg_toplevel_set_fullscreen(xdgtoplevel, o);
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::unsetFullscreen()
|
||||
{
|
||||
xdg_toplevel_unset_fullscreen(xdgtoplevel);
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::setMinimized()
|
||||
{
|
||||
xdg_toplevel_set_minimized(xdgtoplevel);
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::setMaxSize(const QSize &size)
|
||||
{
|
||||
xdg_toplevel_set_max_size(xdgtoplevel, size.width(), size.height());
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::setMinSize(const QSize &size)
|
||||
{
|
||||
xdg_toplevel_set_min_size(xdgtoplevel, size.width(), size.height());
|
||||
}
|
||||
|
||||
void XdgTopLevelStable::Private::setWindowGeometry(const QRect &windowGeometry)
|
||||
{
|
||||
xdg_surface_set_window_geometry(xdgsurface, windowGeometry.x(), windowGeometry.y(), windowGeometry.width(), windowGeometry.height());
|
||||
}
|
||||
|
||||
XdgTopLevelStable::XdgTopLevelStable(QObject *parent)
|
||||
: XdgShellSurface(new Private(this), parent)
|
||||
{
|
||||
}
|
||||
|
||||
XdgTopLevelStable::~XdgTopLevelStable() = default;
|
||||
|
||||
class XdgShellPopupStable::Private : public XdgShellPopup::Private
|
||||
{
|
||||
public:
|
||||
Private(XdgShellPopup *q);
|
||||
|
||||
void setup(xdg_surface *s, xdg_popup *p) override;
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() const override;
|
||||
void requestGrab(Seat *seat, quint32 serial) override;
|
||||
void ackConfigure(quint32 serial) override;
|
||||
void setWindowGeometry(const QRect &windowGeometry) override;
|
||||
|
||||
using XdgShellPopup::Private::operator zxdg_popup_v6 *;
|
||||
using XdgShellPopup::Private::operator zxdg_surface_v6 *;
|
||||
operator xdg_surface *() override
|
||||
{
|
||||
return xdgsurface;
|
||||
}
|
||||
operator xdg_surface *() const override
|
||||
{
|
||||
return xdgsurface;
|
||||
}
|
||||
operator xdg_popup *() override
|
||||
{
|
||||
return xdgpopup;
|
||||
}
|
||||
operator xdg_popup *() const override
|
||||
{
|
||||
return xdgpopup;
|
||||
}
|
||||
WaylandPointer<xdg_surface, xdg_surface_destroy> xdgsurface;
|
||||
WaylandPointer<xdg_popup, xdg_popup_destroy> xdgpopup;
|
||||
|
||||
QRect pendingRect;
|
||||
|
||||
private:
|
||||
static void configureCallback(void *data, xdg_popup *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height);
|
||||
static void popupDoneCallback(void *data, xdg_popup *xdg_popup);
|
||||
static void surfaceConfigureCallback(void *data, xdg_surface *xdg_surface, uint32_t serial);
|
||||
|
||||
static const struct xdg_popup_listener s_popupListener;
|
||||
static const struct xdg_surface_listener s_surfaceListener;
|
||||
};
|
||||
|
||||
const struct xdg_popup_listener XdgShellPopupStable::Private::s_popupListener = {configureCallback, popupDoneCallback};
|
||||
|
||||
const struct xdg_surface_listener XdgShellPopupStable::Private::s_surfaceListener = {
|
||||
surfaceConfigureCallback,
|
||||
};
|
||||
|
||||
void XdgShellPopupStable::Private::configureCallback(void *data, xdg_popup *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height)
|
||||
{
|
||||
Q_UNUSED(xdg_popup)
|
||||
auto s = static_cast<Private *>(data);
|
||||
s->pendingRect = QRect(x, y, width, height);
|
||||
}
|
||||
|
||||
void XdgShellPopupStable::Private::surfaceConfigureCallback(void *data, struct xdg_surface *surface, uint32_t serial)
|
||||
{
|
||||
Q_UNUSED(surface)
|
||||
auto s = static_cast<Private *>(data);
|
||||
s->q->configureRequested(s->pendingRect, serial);
|
||||
s->pendingRect = QRect();
|
||||
}
|
||||
|
||||
void XdgShellPopupStable::Private::popupDoneCallback(void *data, xdg_popup *xdg_popup)
|
||||
{
|
||||
auto s = static_cast<XdgShellPopupStable::Private *>(data);
|
||||
Q_ASSERT(s->xdgpopup == xdg_popup);
|
||||
Q_EMIT s->q->popupDone();
|
||||
}
|
||||
|
||||
XdgShellPopupStable::Private::Private(XdgShellPopup *q)
|
||||
: XdgShellPopup::Private(q)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgShellPopupStable::Private::setup(xdg_surface *s, xdg_popup *p)
|
||||
{
|
||||
Q_ASSERT(p);
|
||||
Q_ASSERT(!xdgsurface);
|
||||
Q_ASSERT(!xdgpopup);
|
||||
|
||||
xdgsurface.setup(s);
|
||||
xdgpopup.setup(p);
|
||||
xdg_surface_add_listener(xdgsurface, &s_surfaceListener, this);
|
||||
xdg_popup_add_listener(xdgpopup, &s_popupListener, this);
|
||||
}
|
||||
|
||||
void XdgShellPopupStable::Private::release()
|
||||
{
|
||||
xdgpopup.release();
|
||||
}
|
||||
|
||||
void XdgShellPopupStable::Private::destroy()
|
||||
{
|
||||
xdgpopup.destroy();
|
||||
}
|
||||
|
||||
bool XdgShellPopupStable::Private::isValid() const
|
||||
{
|
||||
return xdgpopup.isValid();
|
||||
}
|
||||
|
||||
void XdgShellPopupStable::Private::requestGrab(Seat *seat, quint32 serial)
|
||||
{
|
||||
xdg_popup_grab(xdgpopup, *seat, serial);
|
||||
}
|
||||
|
||||
void XdgShellPopupStable::Private::ackConfigure(quint32 serial)
|
||||
{
|
||||
xdg_surface_ack_configure(xdgsurface, serial);
|
||||
}
|
||||
|
||||
void XdgShellPopupStable::Private::setWindowGeometry(const QRect &windowGeometry)
|
||||
{
|
||||
xdg_surface_set_window_geometry(xdgsurface, windowGeometry.x(), windowGeometry.y(), windowGeometry.width(), windowGeometry.height());
|
||||
}
|
||||
|
||||
XdgShellPopupStable::XdgShellPopupStable(QObject *parent)
|
||||
: XdgShellPopup(new Private(this), parent)
|
||||
{
|
||||
}
|
||||
|
||||
XdgShellPopupStable::~XdgShellPopupStable() = default;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,410 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "../compat/wayland-xdg-shell-v5-client-protocol.h"
|
||||
#include "event_queue.h"
|
||||
#include "output.h"
|
||||
#include "seat.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
#include "xdgshell_p.h"
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class XdgShellUnstableV5::Private : public XdgShell::Private
|
||||
{
|
||||
public:
|
||||
void setupV5(xdg_shell *shell) override;
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() const override;
|
||||
XdgShellSurface *getXdgSurface(Surface *surface, QObject *parent) override;
|
||||
XdgShellPopup *getXdgPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent) override;
|
||||
|
||||
using XdgShell::Private::operator xdg_wm_base *;
|
||||
using XdgShell::Private::operator zxdg_shell_v6 *;
|
||||
operator xdg_shell *() override
|
||||
{
|
||||
return xdgshellv5;
|
||||
}
|
||||
operator xdg_shell *() const override
|
||||
{
|
||||
return xdgshellv5;
|
||||
}
|
||||
|
||||
static void pingCallback(void *data, struct xdg_shell *shell, uint32_t serial);
|
||||
|
||||
WaylandPointer<xdg_shell, zxdg_shell_v5_destroy> xdgshellv5;
|
||||
static const struct zxdg_shell_v5_listener s_shellListener;
|
||||
};
|
||||
|
||||
const struct zxdg_shell_v5_listener XdgShellUnstableV5::Private::s_shellListener = {
|
||||
pingCallback,
|
||||
};
|
||||
|
||||
void XdgShellUnstableV5::Private::pingCallback(void *data, struct xdg_shell *shell, uint32_t serial)
|
||||
{
|
||||
Q_UNUSED(data);
|
||||
zxdg_shell_v5_pong(shell, serial);
|
||||
}
|
||||
|
||||
void XdgShellUnstableV5::Private::setupV5(xdg_shell *shell)
|
||||
{
|
||||
Q_ASSERT(shell);
|
||||
Q_ASSERT(!xdgshellv5);
|
||||
xdgshellv5.setup(shell);
|
||||
zxdg_shell_v5_use_unstable_version(xdgshellv5, 5);
|
||||
zxdg_shell_v5_add_listener(shell, &s_shellListener, this);
|
||||
}
|
||||
|
||||
void XdgShellUnstableV5::Private::release()
|
||||
{
|
||||
xdgshellv5.release();
|
||||
}
|
||||
|
||||
void XdgShellUnstableV5::Private::destroy()
|
||||
{
|
||||
xdgshellv5.destroy();
|
||||
}
|
||||
|
||||
bool XdgShellUnstableV5::Private::isValid() const
|
||||
{
|
||||
return xdgshellv5.isValid();
|
||||
}
|
||||
|
||||
XdgShellSurface *XdgShellUnstableV5::Private::getXdgSurface(Surface *surface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
XdgShellSurface *s = new XdgShellSurfaceUnstableV5(parent);
|
||||
auto w = zxdg_shell_v5_get_xdg_surface(xdgshellv5, *surface);
|
||||
if (queue) {
|
||||
queue->addProxy(w);
|
||||
}
|
||||
s->setup(w);
|
||||
return s;
|
||||
}
|
||||
|
||||
XdgShellPopup *
|
||||
XdgShellUnstableV5::Private::getXdgPopup(Surface *surface, Surface *parentSurface, Seat *seat, quint32 serial, const QPoint &parentPos, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
XdgShellPopup *s = new XdgShellPopupUnstableV5(parent);
|
||||
auto w = zxdg_shell_v5_get_xdg_popup(xdgshellv5, *surface, *parentSurface, *seat, serial, parentPos.x(), parentPos.y());
|
||||
if (queue) {
|
||||
queue->addProxy(w);
|
||||
}
|
||||
s->setup(w);
|
||||
return s;
|
||||
}
|
||||
|
||||
XdgShellUnstableV5::XdgShellUnstableV5(QObject *parent)
|
||||
: XdgShell(new Private, parent)
|
||||
{
|
||||
}
|
||||
|
||||
XdgShellUnstableV5::~XdgShellUnstableV5() = default;
|
||||
|
||||
class XdgShellSurfaceUnstableV5::Private : public XdgShellSurface::Private
|
||||
{
|
||||
public:
|
||||
Private(XdgShellSurface *q);
|
||||
WaylandPointer<xdg_surface, zxdg_surface_v5_destroy> xdgsurfacev5;
|
||||
|
||||
void setupV5(xdg_surface *surface) override;
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() const override;
|
||||
|
||||
using XdgShellSurface::Private::operator zxdg_surface_v6 *;
|
||||
using XdgShellSurface::Private::operator zxdg_toplevel_v6 *;
|
||||
using XdgShellSurface::Private::operator xdg_toplevel *;
|
||||
operator xdg_surface *() override
|
||||
{
|
||||
return xdgsurfacev5;
|
||||
}
|
||||
operator xdg_surface *() const override
|
||||
{
|
||||
return xdgsurfacev5;
|
||||
}
|
||||
|
||||
void setTransientFor(XdgShellSurface *parent) override;
|
||||
void setTitle(const QString &title) override;
|
||||
void setAppId(const QByteArray &appId) override;
|
||||
void showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) override;
|
||||
void move(Seat *seat, quint32 serial) override;
|
||||
void resize(Seat *seat, quint32 serial, Qt::Edges edges) override;
|
||||
void ackConfigure(quint32 serial) override;
|
||||
void setMaximized() override;
|
||||
void unsetMaximized() override;
|
||||
void setFullscreen(Output *output) override;
|
||||
void unsetFullscreen() override;
|
||||
void setMinimized() override;
|
||||
void setMaxSize(const QSize &size) override;
|
||||
void setMinSize(const QSize &size) override;
|
||||
|
||||
private:
|
||||
static void configureCallback(void *data, xdg_surface *xdg_surface, int32_t width, int32_t height, wl_array *states, uint32_t serial);
|
||||
static void closeCallback(void *data, xdg_surface *xdg_surface);
|
||||
|
||||
static const struct zxdg_surface_v5_listener s_listener;
|
||||
};
|
||||
|
||||
const struct zxdg_surface_v5_listener XdgShellSurfaceUnstableV5::Private::s_listener = {configureCallback, closeCallback};
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::configureCallback(void *data,
|
||||
xdg_surface *xdg_surface,
|
||||
int32_t width,
|
||||
int32_t height,
|
||||
wl_array *wlStates,
|
||||
uint32_t serial)
|
||||
{
|
||||
auto s = reinterpret_cast<XdgShellSurfaceUnstableV5::Private *>(data);
|
||||
Q_ASSERT(s->xdgsurfacev5 == xdg_surface);
|
||||
uint32_t *state = reinterpret_cast<uint32_t *>(wlStates->data);
|
||||
size_t numStates = wlStates->size / sizeof(uint32_t);
|
||||
States states;
|
||||
for (size_t i = 0; i < numStates; i++) {
|
||||
switch (state[i]) {
|
||||
case ZXDG_SURFACE_V5_STATE_MAXIMIZED:
|
||||
states = states | XdgShellSurface::State::Maximized;
|
||||
break;
|
||||
case ZXDG_SURFACE_V5_STATE_FULLSCREEN:
|
||||
states = states | XdgShellSurface::State::Fullscreen;
|
||||
break;
|
||||
case ZXDG_SURFACE_V5_STATE_RESIZING:
|
||||
states = states | XdgShellSurface::State::Resizing;
|
||||
break;
|
||||
case ZXDG_SURFACE_V5_STATE_ACTIVATED:
|
||||
states = states | XdgShellSurface::State::Activated;
|
||||
break;
|
||||
}
|
||||
}
|
||||
const QSize size = QSize(width, height);
|
||||
Q_EMIT s->q->configureRequested(size, states, serial);
|
||||
if (!size.isNull()) {
|
||||
s->q->setSize(size);
|
||||
}
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::closeCallback(void *data, xdg_surface *xdg_surface)
|
||||
{
|
||||
auto s = reinterpret_cast<XdgShellSurfaceUnstableV5::Private *>(data);
|
||||
Q_ASSERT(s->xdgsurfacev5 == xdg_surface);
|
||||
Q_EMIT s->q->closeRequested();
|
||||
}
|
||||
|
||||
XdgShellSurfaceUnstableV5::Private::Private(XdgShellSurface *q)
|
||||
: XdgShellSurface::Private(q)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::setupV5(xdg_surface *surface)
|
||||
{
|
||||
Q_ASSERT(surface);
|
||||
Q_ASSERT(!xdgsurfacev5);
|
||||
xdgsurfacev5.setup(surface);
|
||||
zxdg_surface_v5_add_listener(xdgsurfacev5, &s_listener, this);
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::release()
|
||||
{
|
||||
xdgsurfacev5.release();
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::destroy()
|
||||
{
|
||||
xdgsurfacev5.destroy();
|
||||
}
|
||||
|
||||
bool XdgShellSurfaceUnstableV5::Private::isValid() const
|
||||
{
|
||||
return xdgsurfacev5.isValid();
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::setTransientFor(XdgShellSurface *parent)
|
||||
{
|
||||
xdg_surface *parentSurface = nullptr;
|
||||
if (parent) {
|
||||
parentSurface = *parent;
|
||||
}
|
||||
zxdg_surface_v5_set_parent(xdgsurfacev5, parentSurface);
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::setTitle(const QString &title)
|
||||
{
|
||||
zxdg_surface_v5_set_title(xdgsurfacev5, title.toUtf8().constData());
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::setAppId(const QByteArray &appId)
|
||||
{
|
||||
zxdg_surface_v5_set_app_id(xdgsurfacev5, appId.constData());
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y)
|
||||
{
|
||||
zxdg_surface_v5_show_window_menu(xdgsurfacev5, *seat, serial, x, y);
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::move(Seat *seat, quint32 serial)
|
||||
{
|
||||
zxdg_surface_v5_move(xdgsurfacev5, *seat, serial);
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::resize(Seat *seat, quint32 serial, Qt::Edges edges)
|
||||
{
|
||||
uint wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_NONE;
|
||||
if (edges.testFlag(Qt::TopEdge)) {
|
||||
if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::TopEdge)) {
|
||||
wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_TOP_LEFT;
|
||||
} else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::TopEdge)) {
|
||||
wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_TOP_RIGHT;
|
||||
} else if ((edges & ~Qt::TopEdge) == Qt::Edges()) {
|
||||
wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_TOP;
|
||||
}
|
||||
} else if (edges.testFlag(Qt::BottomEdge)) {
|
||||
if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::BottomEdge)) {
|
||||
wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_BOTTOM_LEFT;
|
||||
} else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::BottomEdge)) {
|
||||
wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_BOTTOM_RIGHT;
|
||||
} else if ((edges & ~Qt::BottomEdge) == Qt::Edges()) {
|
||||
wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_BOTTOM;
|
||||
}
|
||||
} else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::Edges())) {
|
||||
wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_RIGHT;
|
||||
} else if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::Edges())) {
|
||||
wlEdge = ZXDG_SURFACE_V5_RESIZE_EDGE_LEFT;
|
||||
}
|
||||
zxdg_surface_v5_resize(xdgsurfacev5, *seat, serial, wlEdge);
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::ackConfigure(quint32 serial)
|
||||
{
|
||||
zxdg_surface_v5_ack_configure(xdgsurfacev5, serial);
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::setMaximized()
|
||||
{
|
||||
zxdg_surface_v5_set_maximized(xdgsurfacev5);
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::unsetMaximized()
|
||||
{
|
||||
zxdg_surface_v5_unset_maximized(xdgsurfacev5);
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::setFullscreen(Output *output)
|
||||
{
|
||||
wl_output *o = nullptr;
|
||||
if (output) {
|
||||
o = *output;
|
||||
}
|
||||
zxdg_surface_v5_set_fullscreen(xdgsurfacev5, o);
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::unsetFullscreen()
|
||||
{
|
||||
zxdg_surface_v5_unset_fullscreen(xdgsurfacev5);
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::setMinimized()
|
||||
{
|
||||
zxdg_surface_v5_set_minimized(xdgsurfacev5);
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::setMaxSize(const QSize &size)
|
||||
{
|
||||
Q_UNUSED(size)
|
||||
// TODO: notify an error?
|
||||
}
|
||||
|
||||
void XdgShellSurfaceUnstableV5::Private::setMinSize(const QSize &size)
|
||||
{
|
||||
Q_UNUSED(size)
|
||||
// TODO: notify an error?
|
||||
}
|
||||
|
||||
XdgShellSurfaceUnstableV5::XdgShellSurfaceUnstableV5(QObject *parent)
|
||||
: XdgShellSurface(new Private(this), parent)
|
||||
{
|
||||
}
|
||||
|
||||
XdgShellSurfaceUnstableV5::~XdgShellSurfaceUnstableV5() = default;
|
||||
|
||||
class XdgShellPopupUnstableV5::Private : public XdgShellPopup::Private
|
||||
{
|
||||
public:
|
||||
Private(XdgShellPopup *q);
|
||||
|
||||
void setupV5(xdg_popup *p) override;
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() const override;
|
||||
|
||||
using XdgShellPopup::Private::operator xdg_surface *;
|
||||
using XdgShellPopup::Private::operator zxdg_popup_v6 *;
|
||||
using XdgShellPopup::Private::operator zxdg_surface_v6 *;
|
||||
operator xdg_popup *() override
|
||||
{
|
||||
return xdgpopupv5;
|
||||
}
|
||||
operator xdg_popup *() const override
|
||||
{
|
||||
return xdgpopupv5;
|
||||
}
|
||||
WaylandPointer<xdg_popup, zxdg_popup_v5_destroy> xdgpopupv5;
|
||||
|
||||
private:
|
||||
static void popupDoneCallback(void *data, xdg_popup *xdg_popup);
|
||||
static const struct zxdg_popup_v5_listener s_listener;
|
||||
};
|
||||
|
||||
const struct zxdg_popup_v5_listener XdgShellPopupUnstableV5::Private::s_listener = {popupDoneCallback};
|
||||
|
||||
void XdgShellPopupUnstableV5::Private::popupDoneCallback(void *data, xdg_popup *xdg_popup)
|
||||
{
|
||||
auto s = reinterpret_cast<XdgShellPopupUnstableV5::Private *>(data);
|
||||
Q_ASSERT(s->xdgpopupv5 == xdg_popup);
|
||||
Q_EMIT s->q->popupDone();
|
||||
}
|
||||
|
||||
XdgShellPopupUnstableV5::Private::Private(XdgShellPopup *q)
|
||||
: XdgShellPopup::Private(q)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgShellPopupUnstableV5::Private::setupV5(xdg_popup *p)
|
||||
{
|
||||
Q_ASSERT(p);
|
||||
Q_ASSERT(!xdgpopupv5);
|
||||
xdgpopupv5.setup(p);
|
||||
zxdg_popup_v5_add_listener(xdgpopupv5, &s_listener, this);
|
||||
}
|
||||
|
||||
void XdgShellPopupUnstableV5::Private::release()
|
||||
{
|
||||
xdgpopupv5.release();
|
||||
}
|
||||
|
||||
void XdgShellPopupUnstableV5::Private::destroy()
|
||||
{
|
||||
xdgpopupv5.destroy();
|
||||
}
|
||||
|
||||
bool XdgShellPopupUnstableV5::Private::isValid() const
|
||||
{
|
||||
return xdgpopupv5.isValid();
|
||||
}
|
||||
|
||||
XdgShellPopupUnstableV5::XdgShellPopupUnstableV5(QObject *parent)
|
||||
: XdgShellPopup(new Private(this), parent)
|
||||
{
|
||||
}
|
||||
|
||||
XdgShellPopupUnstableV5::~XdgShellPopupUnstableV5() = default;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,584 @@
|
||||
/*
|
||||
SPDX-FileCopyrightText: 2017 David Edmundson <davidedmundson@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
#include "event_queue.h"
|
||||
#include "output.h"
|
||||
#include "seat.h"
|
||||
#include "surface.h"
|
||||
#include "wayland_pointer_p.h"
|
||||
#include "xdgshell_p.h"
|
||||
#include <wayland-xdg-shell-v6-client-protocol.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class XdgShellUnstableV6::Private : public XdgShell::Private
|
||||
{
|
||||
public:
|
||||
void setupV6(zxdg_shell_v6 *shell) override;
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() const override;
|
||||
XdgShellSurface *getXdgSurface(Surface *surface, QObject *parent) override;
|
||||
|
||||
XdgShellPopup *getXdgPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent) override;
|
||||
XdgShellPopup *getXdgPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent) override;
|
||||
|
||||
using XdgShell::Private::operator xdg_wm_base *;
|
||||
using XdgShell::Private::operator xdg_shell *;
|
||||
operator zxdg_shell_v6 *() override
|
||||
{
|
||||
return xdgshellv6;
|
||||
}
|
||||
operator zxdg_shell_v6 *() const override
|
||||
{
|
||||
return xdgshellv6;
|
||||
}
|
||||
|
||||
private:
|
||||
XdgShellPopup *internalGetXdgPopup(Surface *surface, zxdg_surface_v6 *parentSurface, const XdgPositioner &positioner, QObject *parent);
|
||||
static void pingCallback(void *data, struct zxdg_shell_v6 *shell, uint32_t serial);
|
||||
|
||||
WaylandPointer<zxdg_shell_v6, zxdg_shell_v6_destroy> xdgshellv6;
|
||||
static const struct zxdg_shell_v6_listener s_shellListener;
|
||||
};
|
||||
|
||||
const struct zxdg_shell_v6_listener XdgShellUnstableV6::Private::s_shellListener = {
|
||||
pingCallback,
|
||||
};
|
||||
|
||||
void XdgShellUnstableV6::Private::pingCallback(void *data, struct zxdg_shell_v6 *shell, uint32_t serial)
|
||||
{
|
||||
Q_UNUSED(data)
|
||||
zxdg_shell_v6_pong(shell, serial);
|
||||
}
|
||||
|
||||
void XdgShellUnstableV6::Private::setupV6(zxdg_shell_v6 *shell)
|
||||
{
|
||||
Q_ASSERT(shell);
|
||||
Q_ASSERT(!xdgshellv6);
|
||||
xdgshellv6.setup(shell);
|
||||
zxdg_shell_v6_add_listener(shell, &s_shellListener, this);
|
||||
}
|
||||
|
||||
void XdgShellUnstableV6::Private::release()
|
||||
{
|
||||
xdgshellv6.release();
|
||||
}
|
||||
|
||||
void XdgShellUnstableV6::Private::destroy()
|
||||
{
|
||||
xdgshellv6.destroy();
|
||||
}
|
||||
|
||||
bool XdgShellUnstableV6::Private::isValid() const
|
||||
{
|
||||
return xdgshellv6.isValid();
|
||||
}
|
||||
|
||||
XdgShellSurface *XdgShellUnstableV6::Private::getXdgSurface(Surface *surface, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
auto ss = zxdg_shell_v6_get_xdg_surface(xdgshellv6, *surface);
|
||||
|
||||
if (!ss) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto s = new XdgTopLevelUnstableV6(parent);
|
||||
auto toplevel = zxdg_surface_v6_get_toplevel(ss);
|
||||
if (queue) {
|
||||
queue->addProxy(ss);
|
||||
queue->addProxy(toplevel);
|
||||
}
|
||||
s->setup(ss, toplevel);
|
||||
return s;
|
||||
}
|
||||
|
||||
XdgShellPopup *XdgShellUnstableV6::Private::getXdgPopup(Surface *surface, XdgShellSurface *parentSurface, const XdgPositioner &positioner, QObject *parent)
|
||||
{
|
||||
return internalGetXdgPopup(surface, *parentSurface, positioner, parent);
|
||||
}
|
||||
|
||||
XdgShellPopup *XdgShellUnstableV6::Private::getXdgPopup(Surface *surface, XdgShellPopup *parentSurface, const XdgPositioner &positioner, QObject *parent)
|
||||
{
|
||||
return internalGetXdgPopup(surface, *parentSurface, positioner, parent);
|
||||
}
|
||||
|
||||
XdgShellPopup *
|
||||
XdgShellUnstableV6::Private::internalGetXdgPopup(Surface *surface, zxdg_surface_v6 *parentSurface, const XdgPositioner &positioner, QObject *parent)
|
||||
{
|
||||
Q_ASSERT(isValid());
|
||||
auto ss = zxdg_shell_v6_get_xdg_surface(xdgshellv6, *surface);
|
||||
if (!ss) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto p = zxdg_shell_v6_create_positioner(xdgshellv6);
|
||||
|
||||
auto anchorRect = positioner.anchorRect();
|
||||
zxdg_positioner_v6_set_anchor_rect(p, anchorRect.x(), anchorRect.y(), anchorRect.width(), anchorRect.height());
|
||||
|
||||
QSize initialSize = positioner.initialSize();
|
||||
zxdg_positioner_v6_set_size(p, initialSize.width(), initialSize.height());
|
||||
|
||||
QPoint anchorOffset = positioner.anchorOffset();
|
||||
if (!anchorOffset.isNull()) {
|
||||
zxdg_positioner_v6_set_offset(p, anchorOffset.x(), anchorOffset.y());
|
||||
}
|
||||
|
||||
uint32_t anchor = 0;
|
||||
if (positioner.anchorEdge().testFlag(Qt::LeftEdge)) {
|
||||
anchor |= ZXDG_POSITIONER_V6_ANCHOR_LEFT;
|
||||
}
|
||||
if (positioner.anchorEdge().testFlag(Qt::TopEdge)) {
|
||||
anchor |= ZXDG_POSITIONER_V6_ANCHOR_TOP;
|
||||
}
|
||||
if (positioner.anchorEdge().testFlag(Qt::RightEdge)) {
|
||||
anchor |= ZXDG_POSITIONER_V6_ANCHOR_RIGHT;
|
||||
}
|
||||
if (positioner.anchorEdge().testFlag(Qt::BottomEdge)) {
|
||||
anchor |= ZXDG_POSITIONER_V6_ANCHOR_BOTTOM;
|
||||
}
|
||||
if (anchor != 0) {
|
||||
zxdg_positioner_v6_set_anchor(p, anchor);
|
||||
}
|
||||
|
||||
uint32_t gravity = 0;
|
||||
if (positioner.gravity().testFlag(Qt::LeftEdge)) {
|
||||
gravity |= ZXDG_POSITIONER_V6_GRAVITY_LEFT;
|
||||
}
|
||||
if (positioner.gravity().testFlag(Qt::TopEdge)) {
|
||||
gravity |= ZXDG_POSITIONER_V6_GRAVITY_TOP;
|
||||
}
|
||||
if (positioner.gravity().testFlag(Qt::RightEdge)) {
|
||||
gravity |= ZXDG_POSITIONER_V6_GRAVITY_RIGHT;
|
||||
}
|
||||
if (positioner.gravity().testFlag(Qt::BottomEdge)) {
|
||||
gravity |= ZXDG_POSITIONER_V6_GRAVITY_BOTTOM;
|
||||
}
|
||||
if (gravity != 0) {
|
||||
zxdg_positioner_v6_set_gravity(p, gravity);
|
||||
}
|
||||
|
||||
uint32_t constraint = 0;
|
||||
|
||||
if (positioner.constraints().testFlag(XdgPositioner::Constraint::SlideX)) {
|
||||
constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_X;
|
||||
}
|
||||
if (positioner.constraints().testFlag(XdgPositioner::Constraint::SlideY)) {
|
||||
constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_SLIDE_Y;
|
||||
}
|
||||
if (positioner.constraints().testFlag(XdgPositioner::Constraint::FlipX)) {
|
||||
constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_X;
|
||||
}
|
||||
if (positioner.constraints().testFlag(XdgPositioner::Constraint::FlipY)) {
|
||||
constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_FLIP_Y;
|
||||
}
|
||||
if (positioner.constraints().testFlag(XdgPositioner::Constraint::ResizeX)) {
|
||||
constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_X;
|
||||
}
|
||||
if (positioner.constraints().testFlag(XdgPositioner::Constraint::ResizeY)) {
|
||||
constraint |= ZXDG_POSITIONER_V6_CONSTRAINT_ADJUSTMENT_RESIZE_Y;
|
||||
}
|
||||
if (constraint != 0) {
|
||||
zxdg_positioner_v6_set_constraint_adjustment(p, constraint);
|
||||
}
|
||||
|
||||
XdgShellPopup *s = new XdgShellPopupUnstableV6(parent);
|
||||
auto popup = zxdg_surface_v6_get_popup(ss, parentSurface, p);
|
||||
if (queue) {
|
||||
// deliberately not adding the positioner because the positioner has no events sent to it
|
||||
queue->addProxy(ss);
|
||||
queue->addProxy(popup);
|
||||
}
|
||||
s->setup(ss, popup);
|
||||
|
||||
zxdg_positioner_v6_destroy(p);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
XdgShellUnstableV6::XdgShellUnstableV6(QObject *parent)
|
||||
: XdgShell(new Private, parent)
|
||||
{
|
||||
}
|
||||
|
||||
XdgShellUnstableV6::~XdgShellUnstableV6() = default;
|
||||
|
||||
// A top level wraps both xdg_surface_v6 and xdg_top_level into the public API XdgShelllSurface
|
||||
class XdgTopLevelUnstableV6::Private : public XdgShellSurface::Private
|
||||
{
|
||||
public:
|
||||
Private(XdgShellSurface *q);
|
||||
WaylandPointer<zxdg_toplevel_v6, zxdg_toplevel_v6_destroy> xdgtoplevelv6;
|
||||
WaylandPointer<zxdg_surface_v6, zxdg_surface_v6_destroy> xdgsurfacev6;
|
||||
|
||||
void setupV6(zxdg_surface_v6 *surface, zxdg_toplevel_v6 *toplevel) override;
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() const override;
|
||||
|
||||
using XdgShellSurface::Private::operator xdg_surface *;
|
||||
using XdgShellSurface::Private::operator xdg_toplevel *;
|
||||
operator zxdg_surface_v6 *() override
|
||||
{
|
||||
return xdgsurfacev6;
|
||||
}
|
||||
operator zxdg_surface_v6 *() const override
|
||||
{
|
||||
return xdgsurfacev6;
|
||||
}
|
||||
operator zxdg_toplevel_v6 *() override
|
||||
{
|
||||
return xdgtoplevelv6;
|
||||
}
|
||||
operator zxdg_toplevel_v6 *() const override
|
||||
{
|
||||
return xdgtoplevelv6;
|
||||
}
|
||||
|
||||
void setTransientFor(XdgShellSurface *parent) override;
|
||||
void setTitle(const QString &title) override;
|
||||
void setAppId(const QByteArray &appId) override;
|
||||
void showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y) override;
|
||||
void move(Seat *seat, quint32 serial) override;
|
||||
void resize(Seat *seat, quint32 serial, Qt::Edges edges) override;
|
||||
void ackConfigure(quint32 serial) override;
|
||||
void setMaximized() override;
|
||||
void unsetMaximized() override;
|
||||
void setFullscreen(Output *output) override;
|
||||
void unsetFullscreen() override;
|
||||
void setMinimized() override;
|
||||
void setMaxSize(const QSize &size) override;
|
||||
void setMinSize(const QSize &size) override;
|
||||
|
||||
private:
|
||||
QSize pendingSize;
|
||||
States pendingState;
|
||||
|
||||
static void configureCallback(void *data, struct zxdg_toplevel_v6 *xdg_toplevel, int32_t width, int32_t height, struct wl_array *state);
|
||||
static void closeCallback(void *data, zxdg_toplevel_v6 *xdg_toplevel);
|
||||
static void surfaceConfigureCallback(void *data, zxdg_surface_v6 *xdg_surface, uint32_t serial);
|
||||
|
||||
static const struct zxdg_toplevel_v6_listener s_toplevelListener;
|
||||
static const struct zxdg_surface_v6_listener s_surfaceListener;
|
||||
};
|
||||
|
||||
const struct zxdg_toplevel_v6_listener XdgTopLevelUnstableV6::Private::s_toplevelListener = {configureCallback, closeCallback};
|
||||
|
||||
const struct zxdg_surface_v6_listener XdgTopLevelUnstableV6::Private::s_surfaceListener = {surfaceConfigureCallback};
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::surfaceConfigureCallback(void *data, struct zxdg_surface_v6 *surface, uint32_t serial)
|
||||
{
|
||||
Q_UNUSED(surface)
|
||||
auto s = reinterpret_cast<Private *>(data);
|
||||
s->q->configureRequested(s->pendingSize, s->pendingState, serial);
|
||||
if (!s->pendingSize.isNull()) {
|
||||
s->q->setSize(s->pendingSize);
|
||||
s->pendingSize = QSize();
|
||||
}
|
||||
s->pendingState = {};
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::configureCallback(void *data, struct zxdg_toplevel_v6 *xdg_toplevel, int32_t width, int32_t height, struct wl_array *state)
|
||||
{
|
||||
Q_UNUSED(xdg_toplevel)
|
||||
auto s = reinterpret_cast<Private *>(data);
|
||||
States states;
|
||||
|
||||
uint32_t *statePtr = reinterpret_cast<uint32_t *>(state->data);
|
||||
for (size_t i = 0; i < state->size / sizeof(uint32_t); i++) {
|
||||
switch (statePtr[i]) {
|
||||
case ZXDG_TOPLEVEL_V6_STATE_MAXIMIZED:
|
||||
states = states | XdgShellSurface::State::Maximized;
|
||||
break;
|
||||
case ZXDG_TOPLEVEL_V6_STATE_FULLSCREEN:
|
||||
states = states | XdgShellSurface::State::Fullscreen;
|
||||
break;
|
||||
case ZXDG_TOPLEVEL_V6_STATE_RESIZING:
|
||||
states = states | XdgShellSurface::State::Resizing;
|
||||
break;
|
||||
case ZXDG_TOPLEVEL_V6_STATE_ACTIVATED:
|
||||
states = states | XdgShellSurface::State::Activated;
|
||||
break;
|
||||
}
|
||||
}
|
||||
s->pendingSize = QSize(width, height);
|
||||
s->pendingState = states;
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::closeCallback(void *data, zxdg_toplevel_v6 *xdg_toplevel)
|
||||
{
|
||||
auto s = reinterpret_cast<XdgTopLevelUnstableV6::Private *>(data);
|
||||
Q_ASSERT(s->xdgtoplevelv6 == xdg_toplevel);
|
||||
Q_EMIT s->q->closeRequested();
|
||||
}
|
||||
|
||||
XdgTopLevelUnstableV6::Private::Private(XdgShellSurface *q)
|
||||
: XdgShellSurface::Private(q)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::setupV6(zxdg_surface_v6 *surface, zxdg_toplevel_v6 *topLevel)
|
||||
{
|
||||
Q_ASSERT(surface);
|
||||
Q_ASSERT(!xdgtoplevelv6);
|
||||
xdgsurfacev6.setup(surface);
|
||||
xdgtoplevelv6.setup(topLevel);
|
||||
zxdg_surface_v6_add_listener(xdgsurfacev6, &s_surfaceListener, this);
|
||||
zxdg_toplevel_v6_add_listener(xdgtoplevelv6, &s_toplevelListener, this);
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::release()
|
||||
{
|
||||
xdgtoplevelv6.release();
|
||||
xdgsurfacev6.release();
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::destroy()
|
||||
{
|
||||
xdgtoplevelv6.destroy();
|
||||
xdgsurfacev6.destroy();
|
||||
}
|
||||
|
||||
bool XdgTopLevelUnstableV6::Private::isValid() const
|
||||
{
|
||||
return xdgtoplevelv6.isValid() && xdgsurfacev6.isValid();
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::setTransientFor(XdgShellSurface *parent)
|
||||
{
|
||||
zxdg_toplevel_v6 *parentSurface = nullptr;
|
||||
if (parent) {
|
||||
parentSurface = *parent;
|
||||
}
|
||||
zxdg_toplevel_v6_set_parent(xdgtoplevelv6, parentSurface);
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::setTitle(const QString &title)
|
||||
{
|
||||
zxdg_toplevel_v6_set_title(xdgtoplevelv6, title.toUtf8().constData());
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::setAppId(const QByteArray &appId)
|
||||
{
|
||||
zxdg_toplevel_v6_set_app_id(xdgtoplevelv6, appId.constData());
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::showWindowMenu(Seat *seat, quint32 serial, qint32 x, qint32 y)
|
||||
{
|
||||
zxdg_toplevel_v6_show_window_menu(xdgtoplevelv6, *seat, serial, x, y);
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::move(Seat *seat, quint32 serial)
|
||||
{
|
||||
zxdg_toplevel_v6_move(xdgtoplevelv6, *seat, serial);
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::resize(Seat *seat, quint32 serial, Qt::Edges edges)
|
||||
{
|
||||
uint wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_NONE;
|
||||
if (edges.testFlag(Qt::TopEdge)) {
|
||||
if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::TopEdge)) {
|
||||
wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_LEFT;
|
||||
} else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::TopEdge)) {
|
||||
wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP_RIGHT;
|
||||
} else if ((edges & ~Qt::TopEdge) == Qt::Edges()) {
|
||||
wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_TOP;
|
||||
}
|
||||
} else if (edges.testFlag(Qt::BottomEdge)) {
|
||||
if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::BottomEdge)) {
|
||||
wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_LEFT;
|
||||
} else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::BottomEdge)) {
|
||||
wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM_RIGHT;
|
||||
} else if ((edges & ~Qt::BottomEdge) == Qt::Edges()) {
|
||||
wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_BOTTOM;
|
||||
}
|
||||
} else if (edges.testFlag(Qt::RightEdge) && ((edges & ~Qt::RightEdge) == Qt::Edges())) {
|
||||
wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_RIGHT;
|
||||
} else if (edges.testFlag(Qt::LeftEdge) && ((edges & ~Qt::LeftEdge) == Qt::Edges())) {
|
||||
wlEdge = ZXDG_TOPLEVEL_V6_RESIZE_EDGE_LEFT;
|
||||
}
|
||||
zxdg_toplevel_v6_resize(xdgtoplevelv6, *seat, serial, wlEdge);
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::ackConfigure(quint32 serial)
|
||||
{
|
||||
zxdg_surface_v6_ack_configure(xdgsurfacev6, serial);
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::setMaximized()
|
||||
{
|
||||
zxdg_toplevel_v6_set_maximized(xdgtoplevelv6);
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::unsetMaximized()
|
||||
{
|
||||
zxdg_toplevel_v6_unset_maximized(xdgtoplevelv6);
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::setFullscreen(Output *output)
|
||||
{
|
||||
wl_output *o = nullptr;
|
||||
if (output) {
|
||||
o = *output;
|
||||
}
|
||||
zxdg_toplevel_v6_set_fullscreen(xdgtoplevelv6, o);
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::unsetFullscreen()
|
||||
{
|
||||
zxdg_toplevel_v6_unset_fullscreen(xdgtoplevelv6);
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::setMinimized()
|
||||
{
|
||||
zxdg_toplevel_v6_set_minimized(xdgtoplevelv6);
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::setMaxSize(const QSize &size)
|
||||
{
|
||||
zxdg_toplevel_v6_set_max_size(xdgtoplevelv6, size.width(), size.height());
|
||||
}
|
||||
|
||||
void XdgTopLevelUnstableV6::Private::setMinSize(const QSize &size)
|
||||
{
|
||||
zxdg_toplevel_v6_set_min_size(xdgtoplevelv6, size.width(), size.height());
|
||||
}
|
||||
|
||||
XdgTopLevelUnstableV6::XdgTopLevelUnstableV6(QObject *parent)
|
||||
: XdgShellSurface(new Private(this), parent)
|
||||
{
|
||||
}
|
||||
|
||||
XdgTopLevelUnstableV6::~XdgTopLevelUnstableV6() = default;
|
||||
|
||||
class XdgShellPopupUnstableV6::Private : public XdgShellPopup::Private
|
||||
{
|
||||
public:
|
||||
Private(XdgShellPopup *q);
|
||||
|
||||
void setupV6(zxdg_surface_v6 *s, zxdg_popup_v6 *p) override;
|
||||
void release() override;
|
||||
void destroy() override;
|
||||
bool isValid() const override;
|
||||
void requestGrab(Seat *seat, quint32 serial) override;
|
||||
void ackConfigure(quint32 serial) override;
|
||||
|
||||
using XdgShellPopup::Private::operator xdg_popup *;
|
||||
using XdgShellPopup::Private::operator xdg_surface *;
|
||||
operator zxdg_surface_v6 *() override
|
||||
{
|
||||
return xdgsurfacev6;
|
||||
}
|
||||
operator zxdg_surface_v6 *() const override
|
||||
{
|
||||
return xdgsurfacev6;
|
||||
}
|
||||
operator zxdg_popup_v6 *() override
|
||||
{
|
||||
return xdgpopupv6;
|
||||
}
|
||||
operator zxdg_popup_v6 *() const override
|
||||
{
|
||||
return xdgpopupv6;
|
||||
}
|
||||
WaylandPointer<zxdg_surface_v6, zxdg_surface_v6_destroy> xdgsurfacev6;
|
||||
WaylandPointer<zxdg_popup_v6, zxdg_popup_v6_destroy> xdgpopupv6;
|
||||
|
||||
QRect pendingRect;
|
||||
|
||||
private:
|
||||
static void configureCallback(void *data, zxdg_popup_v6 *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height);
|
||||
static void popupDoneCallback(void *data, zxdg_popup_v6 *xdg_popup);
|
||||
static void surfaceConfigureCallback(void *data, zxdg_surface_v6 *xdg_surface, uint32_t serial);
|
||||
|
||||
static const struct zxdg_popup_v6_listener s_popupListener;
|
||||
static const struct zxdg_surface_v6_listener s_surfaceListener;
|
||||
};
|
||||
|
||||
const struct zxdg_popup_v6_listener XdgShellPopupUnstableV6::Private::s_popupListener = {configureCallback, popupDoneCallback};
|
||||
|
||||
const struct zxdg_surface_v6_listener XdgShellPopupUnstableV6::Private::s_surfaceListener = {
|
||||
surfaceConfigureCallback,
|
||||
};
|
||||
|
||||
void XdgShellPopupUnstableV6::Private::configureCallback(void *data, zxdg_popup_v6 *xdg_popup, int32_t x, int32_t y, int32_t width, int32_t height)
|
||||
{
|
||||
Q_UNUSED(xdg_popup);
|
||||
auto s = reinterpret_cast<Private *>(data);
|
||||
s->pendingRect = QRect(x, y, width, height);
|
||||
}
|
||||
|
||||
void XdgShellPopupUnstableV6::Private::surfaceConfigureCallback(void *data, struct zxdg_surface_v6 *surface, uint32_t serial)
|
||||
{
|
||||
Q_UNUSED(surface);
|
||||
auto s = reinterpret_cast<Private *>(data);
|
||||
s->q->configureRequested(s->pendingRect, serial);
|
||||
s->pendingRect = QRect();
|
||||
}
|
||||
|
||||
void XdgShellPopupUnstableV6::Private::popupDoneCallback(void *data, zxdg_popup_v6 *xdg_popup)
|
||||
{
|
||||
auto s = reinterpret_cast<XdgShellPopupUnstableV6::Private *>(data);
|
||||
Q_ASSERT(s->xdgpopupv6 == xdg_popup);
|
||||
Q_EMIT s->q->popupDone();
|
||||
}
|
||||
|
||||
XdgShellPopupUnstableV6::Private::Private(XdgShellPopup *q)
|
||||
: XdgShellPopup::Private(q)
|
||||
{
|
||||
}
|
||||
|
||||
void XdgShellPopupUnstableV6::Private::setupV6(zxdg_surface_v6 *s, zxdg_popup_v6 *p)
|
||||
{
|
||||
Q_ASSERT(p);
|
||||
Q_ASSERT(!xdgsurfacev6);
|
||||
Q_ASSERT(!xdgpopupv6);
|
||||
|
||||
xdgsurfacev6.setup(s);
|
||||
xdgpopupv6.setup(p);
|
||||
zxdg_surface_v6_add_listener(xdgsurfacev6, &s_surfaceListener, this);
|
||||
zxdg_popup_v6_add_listener(xdgpopupv6, &s_popupListener, this);
|
||||
}
|
||||
|
||||
void XdgShellPopupUnstableV6::Private::release()
|
||||
{
|
||||
xdgpopupv6.release();
|
||||
}
|
||||
|
||||
void XdgShellPopupUnstableV6::Private::destroy()
|
||||
{
|
||||
xdgpopupv6.destroy();
|
||||
}
|
||||
|
||||
bool XdgShellPopupUnstableV6::Private::isValid() const
|
||||
{
|
||||
return xdgpopupv6.isValid();
|
||||
}
|
||||
|
||||
void XdgShellPopupUnstableV6::Private::requestGrab(Seat *seat, quint32 serial)
|
||||
{
|
||||
zxdg_popup_v6_grab(xdgpopupv6, *seat, serial);
|
||||
}
|
||||
|
||||
void XdgShellPopupUnstableV6::Private::ackConfigure(quint32 serial)
|
||||
{
|
||||
zxdg_surface_v6_ack_configure(xdgsurfacev6, serial);
|
||||
}
|
||||
|
||||
XdgShellPopupUnstableV6::XdgShellPopupUnstableV6(QObject *parent)
|
||||
: XdgShellPopup(new Private(this), parent)
|
||||
{
|
||||
}
|
||||
|
||||
XdgShellPopupUnstableV6::~XdgShellPopupUnstableV6() = default;
|
||||
|
||||
}
|
||||
}
|
||||
+1045
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
* This file is *NOT* autogenerated.
|
||||
* It contains XDGShellV5 with method names modified to be not clashing with XDG stable
|
||||
* Strings inside the sent protocol remain the same
|
||||
*/
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2008-2013 Kristian Høgsberg
|
||||
* SPDX-FileCopyrightText: 2013 Rafael Antognolli
|
||||
* SPDX-FileCopyrightText: 2013 Jasper St. Pierre
|
||||
* SPDX-FileCopyrightText: 2010-2013 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*/
|
||||
|
||||
#include "wayland-util.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
extern const struct wl_interface wl_output_interface;
|
||||
extern const struct wl_interface wl_seat_interface;
|
||||
extern const struct wl_interface wl_surface_interface;
|
||||
extern const struct wl_interface zxdg_popup_v5_interface;
|
||||
extern const struct wl_interface zxdg_surface_v5_interface;
|
||||
|
||||
static const struct wl_interface *types[] = {
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&zxdg_surface_v5_interface,
|
||||
&wl_surface_interface,
|
||||
&zxdg_popup_v5_interface,
|
||||
&wl_surface_interface,
|
||||
&wl_surface_interface,
|
||||
&wl_seat_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&zxdg_surface_v5_interface,
|
||||
&wl_seat_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_seat_interface,
|
||||
NULL,
|
||||
&wl_seat_interface,
|
||||
NULL,
|
||||
NULL,
|
||||
&wl_output_interface,
|
||||
};
|
||||
|
||||
static const struct wl_message zxdg_shell_v5_requests[] = {
|
||||
{"destroy", "", types + 0},
|
||||
{"use_unstable_version", "i", types + 0},
|
||||
{"get_xdg_surface", "no", types + 4},
|
||||
{"get_xdg_popup", "nooouii", types + 6},
|
||||
{"pong", "u", types + 0},
|
||||
};
|
||||
|
||||
static const struct wl_message zxdg_shell_v5_events[] = {
|
||||
{"ping", "u", types + 0},
|
||||
};
|
||||
|
||||
WL_EXPORT const struct wl_interface zxdg_shell_v5_interface = {
|
||||
"xdg_shell",
|
||||
1,
|
||||
5,
|
||||
zxdg_shell_v5_requests,
|
||||
1,
|
||||
zxdg_shell_v5_events,
|
||||
};
|
||||
|
||||
static const struct wl_message zxdg_surface_v5_requests[] = {
|
||||
{"destroy", "", types + 0},
|
||||
{"set_parent", "?o", types + 13},
|
||||
{"set_title", "s", types + 0},
|
||||
{"set_app_id", "s", types + 0},
|
||||
{"show_window_menu", "ouii", types + 14},
|
||||
{"move", "ou", types + 18},
|
||||
{"resize", "ouu", types + 20},
|
||||
{"ack_configure", "u", types + 0},
|
||||
{"set_window_geometry", "iiii", types + 0},
|
||||
{"set_maximized", "", types + 0},
|
||||
{"unset_maximized", "", types + 0},
|
||||
{"set_fullscreen", "?o", types + 23},
|
||||
{"unset_fullscreen", "", types + 0},
|
||||
{"set_minimized", "", types + 0},
|
||||
};
|
||||
|
||||
static const struct wl_message zxdg_surface_v5_events[] = {
|
||||
{"configure", "iiau", types + 0},
|
||||
{"close", "", types + 0},
|
||||
};
|
||||
|
||||
WL_EXPORT const struct wl_interface zxdg_surface_v5_interface = {
|
||||
"xdg_surface",
|
||||
1,
|
||||
14,
|
||||
zxdg_surface_v5_requests,
|
||||
2,
|
||||
zxdg_surface_v5_events,
|
||||
};
|
||||
|
||||
static const struct wl_message zxdg_popup_v5_requests[] = {
|
||||
{"destroy", "", types + 0},
|
||||
};
|
||||
|
||||
static const struct wl_message zxdg_popup_v5_events[] = {
|
||||
{"popup_done", "", types + 0},
|
||||
};
|
||||
|
||||
WL_EXPORT const struct wl_interface zxdg_popup_v5_interface = {
|
||||
"xdg_popup",
|
||||
1,
|
||||
1,
|
||||
zxdg_popup_v5_requests,
|
||||
1,
|
||||
zxdg_popup_v5_events,
|
||||
};
|
||||
+844
@@ -0,0 +1,844 @@
|
||||
/*
|
||||
* This file is *NOT* autogenerated.
|
||||
* It contains XDGShellV5 with method names modified to be not clashing with XDG stable
|
||||
* Strings inside the sent protocol remain the same
|
||||
*/
|
||||
#ifndef ZXDG_SHELL_V5_UNSTABLE_V5_SERVER_PROTOCOL_H
|
||||
#define ZXDG_SHELL_V5_UNSTABLE_V5_SERVER_PROTOCOL_H
|
||||
|
||||
#include "wayland-server.h"
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct wl_client;
|
||||
struct wl_resource;
|
||||
|
||||
/**
|
||||
* @page page_zxdg_shell_v5_unstable_v5 The zxdg_shell_v5_unstable_v5 protocol
|
||||
* @section page_ifaces_zxdg_shell_v5_unstable_v5 Interfaces
|
||||
* - @subpage page_iface_xdg_shell - create desktop-style surfaces
|
||||
* - @subpage page_iface_xdg_surface - A desktop window
|
||||
* - @subpage page_iface_xdg_popup - short-lived, popup surfaces for menus
|
||||
* @section page_copyright_zxdg_shell_v5_unstable_v5 Copyright
|
||||
* <pre>
|
||||
*
|
||||
* SPDX-FileCopyrightText: 2008-2013 Kristian Høgsberg
|
||||
* SPDX-FileCopyrightText: 2013 Rafael Antognolli
|
||||
* SPDX-FileCopyrightText: 2013 Jasper St. Pierre
|
||||
* SPDX-FileCopyrightText: 2010-2013 Intel Corporation
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
* </pre>
|
||||
*/
|
||||
struct wl_output;
|
||||
struct wl_seat;
|
||||
struct wl_surface;
|
||||
struct zxdg_popup_v5;
|
||||
struct zxdg_shell_v5;
|
||||
struct zxdg_surface_v5;
|
||||
|
||||
/**
|
||||
* @page page_iface_zxdg_shell xdg_v5_shell
|
||||
* @section page_iface_zxdg_shell_v5_desc Description
|
||||
*
|
||||
* zxdg_shell allows clients to turn a wl_v5_surface into a "real window"
|
||||
* which can be dragged, resized, stacked, and moved around by the
|
||||
* user. Everything about this interface is suited towards traditional
|
||||
* desktop environments.
|
||||
* @section page_iface_zxdg_shell_v5_api API
|
||||
* See @ref iface_xdg_shell.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zxdg_shell The xdg_v5_shell interface
|
||||
*
|
||||
* zxdg_shell allows clients to turn a wl_v5_surface into a "real window"
|
||||
* which can be dragged, resized, stacked, and moved around by the
|
||||
* user. Everything about this interface is suited towards traditional
|
||||
* desktop environments.
|
||||
*/
|
||||
extern const struct wl_interface zxdg_shell_v5_interface;
|
||||
/**
|
||||
* @page page_iface_zxdg_surface xdg_v5_surface
|
||||
* @section page_iface_zxdg_surface_v5_desc Description
|
||||
*
|
||||
* An interface that may be implemented by a wl_surface, for
|
||||
* implementations that provide a desktop-style user interface.
|
||||
*
|
||||
* It provides requests to treat surfaces like windows, allowing to set
|
||||
* properties like maximized, fullscreen, minimized, and to move and resize
|
||||
* them, and associate metadata like title and app id.
|
||||
*
|
||||
* The client must call wl_surface.commit on the corresponding wl_surface
|
||||
* for the xdg_surface state to take effect. Prior to committing the new
|
||||
* state, it can set up initial configuration, such as maximizing or setting
|
||||
* a window geometry.
|
||||
*
|
||||
* Even without attaching a buffer the compositor must respond to initial
|
||||
* committed configuration, for instance sending a configure event with
|
||||
* expected window geometry if the client maximized its surface during
|
||||
* initialization.
|
||||
*
|
||||
* For a surface to be mapped by the compositor the client must have
|
||||
* committed both an xdg_surface state and a buffer.
|
||||
* @section page_iface_zxdg_surface_v5_api API
|
||||
* See @ref iface_xdg_surface.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zxdg_surface The xdg_v5_surface interface
|
||||
*
|
||||
* An interface that may be implemented by a wl_surface, for
|
||||
* implementations that provide a desktop-style user interface.
|
||||
*
|
||||
* It provides requests to treat surfaces like windows, allowing to set
|
||||
* properties like maximized, fullscreen, minimized, and to move and resize
|
||||
* them, and associate metadata like title and app id.
|
||||
*
|
||||
* The client must call wl_surface.commit on the corresponding wl_surface
|
||||
* for the xdg_surface state to take effect. Prior to committing the new
|
||||
* state, it can set up initial configuration, such as maximizing or setting
|
||||
* a window geometry.
|
||||
*
|
||||
* Even without attaching a buffer the compositor must respond to initial
|
||||
* committed configuration, for instance sending a configure event with
|
||||
* expected window geometry if the client maximized its surface during
|
||||
* initialization.
|
||||
*
|
||||
* For a surface to be mapped by the compositor the client must have
|
||||
* committed both an xdg_surface state and a buffer.
|
||||
*/
|
||||
extern const struct wl_interface zxdg_surface_v5_interface;
|
||||
/**
|
||||
* @page page_iface_zxdg_popup xdg_v5_popup
|
||||
* @section page_iface_zxdg_popup_v5_desc Description
|
||||
*
|
||||
* A popup surface is a short-lived, temporary surface that can be
|
||||
* used to implement menus. It takes an explicit grab on the surface
|
||||
* that will be dismissed when the user dismisses the popup. This can
|
||||
* be done by the user clicking outside the surface, using the keyboard,
|
||||
* or even locking the screen through closing the lid or a timeout.
|
||||
*
|
||||
* When the popup is dismissed, a popup_done event will be sent out,
|
||||
* and at the same time the surface will be unmapped. The xdg_popup
|
||||
* object is now inert and cannot be reactivated, so clients should
|
||||
* destroy it. Explicitly destroying the xdg_popup object will also
|
||||
* dismiss the popup and unmap the surface.
|
||||
*
|
||||
* Clients will receive events for all their surfaces during this
|
||||
* grab (which is an "owner-events" grab in X11 parlance). This is
|
||||
* done so that users can navigate through submenus and other
|
||||
* "nested" popup windows without having to dismiss the topmost
|
||||
* popup.
|
||||
*
|
||||
* Clients that want to dismiss the popup when another surface of
|
||||
* their own is clicked should dismiss the popup using the destroy
|
||||
* request.
|
||||
*
|
||||
* The parent surface must have either an zxdg_surface or xdg_v5_popup
|
||||
* role.
|
||||
*
|
||||
* Specifying an xdg_popup for the parent means that the popups are
|
||||
* nested, with this popup now being the topmost popup. Nested
|
||||
* popups must be destroyed in the reverse order they were created
|
||||
* in, e.g. the only popup you are allowed to destroy at all times
|
||||
* is the topmost one.
|
||||
*
|
||||
* If there is an existing popup when creating a new popup, the
|
||||
* parent must be the current topmost popup.
|
||||
*
|
||||
* A parent surface must be mapped before the new popup is mapped.
|
||||
*
|
||||
* When compositors choose to dismiss a popup, they will likely
|
||||
* dismiss every nested popup as well. When a compositor dismisses
|
||||
* popups, it will follow the same dismissing order as required
|
||||
* from the client.
|
||||
*
|
||||
* The x and y arguments passed when creating the popup object specify
|
||||
* where the top left of the popup should be placed, relative to the
|
||||
* local surface coordinates of the parent surface. See
|
||||
* zxdg_shell.get_v5_xdg_popup.
|
||||
*
|
||||
* The client must call wl_surface.commit on the corresponding wl_surface
|
||||
* for the xdg_popup state to take effect.
|
||||
*
|
||||
* For a surface to be mapped by the compositor the client must have
|
||||
* committed both the xdg_popup state and a buffer.
|
||||
* @section page_iface_zxdg_popup_v5_api API
|
||||
* See @ref iface_xdg_popup.
|
||||
*/
|
||||
/**
|
||||
* @defgroup iface_zxdg_popup The xdg_v5_popup interface
|
||||
*
|
||||
* A popup surface is a short-lived, temporary surface that can be
|
||||
* used to implement menus. It takes an explicit grab on the surface
|
||||
* that will be dismissed when the user dismisses the popup. This can
|
||||
* be done by the user clicking outside the surface, using the keyboard,
|
||||
* or even locking the screen through closing the lid or a timeout.
|
||||
*
|
||||
* When the popup is dismissed, a popup_done event will be sent out,
|
||||
* and at the same time the surface will be unmapped. The xdg_popup
|
||||
* object is now inert and cannot be reactivated, so clients should
|
||||
* destroy it. Explicitly destroying the xdg_popup object will also
|
||||
* dismiss the popup and unmap the surface.
|
||||
*
|
||||
* Clients will receive events for all their surfaces during this
|
||||
* grab (which is an "owner-events" grab in X11 parlance). This is
|
||||
* done so that users can navigate through submenus and other
|
||||
* "nested" popup windows without having to dismiss the topmost
|
||||
* popup.
|
||||
*
|
||||
* Clients that want to dismiss the popup when another surface of
|
||||
* their own is clicked should dismiss the popup using the destroy
|
||||
* request.
|
||||
*
|
||||
* The parent surface must have either an zxdg_surface or xdg_v5_popup
|
||||
* role.
|
||||
*
|
||||
* Specifying an xdg_popup for the parent means that the popups are
|
||||
* nested, with this popup now being the topmost popup. Nested
|
||||
* popups must be destroyed in the reverse order they were created
|
||||
* in, e.g. the only popup you are allowed to destroy at all times
|
||||
* is the topmost one.
|
||||
*
|
||||
* If there is an existing popup when creating a new popup, the
|
||||
* parent must be the current topmost popup.
|
||||
*
|
||||
* A parent surface must be mapped before the new popup is mapped.
|
||||
*
|
||||
* When compositors choose to dismiss a popup, they will likely
|
||||
* dismiss every nested popup as well. When a compositor dismisses
|
||||
* popups, it will follow the same dismissing order as required
|
||||
* from the client.
|
||||
*
|
||||
* The x and y arguments passed when creating the popup object specify
|
||||
* where the top left of the popup should be placed, relative to the
|
||||
* local surface coordinates of the parent surface. See
|
||||
* zxdg_shell.get_v5_xdg_popup.
|
||||
*
|
||||
* The client must call wl_surface.commit on the corresponding wl_surface
|
||||
* for the xdg_popup state to take effect.
|
||||
*
|
||||
* For a surface to be mapped by the compositor the client must have
|
||||
* committed both the xdg_popup state and a buffer.
|
||||
*/
|
||||
extern const struct wl_interface zxdg_popup_v5_interface;
|
||||
|
||||
#ifndef ZXDG_SHELL_V5_VERSION_ENUM
|
||||
#define ZXDG_SHELL_V5_VERSION_ENUM
|
||||
/**
|
||||
* @ingroup iface_xdg_shell
|
||||
* latest protocol version
|
||||
*
|
||||
* The 'current' member of this enum gives the version of the
|
||||
* protocol. Implementations can compare this to the version
|
||||
* they implement using static_assert to ensure the protocol and
|
||||
* implementation versions match.
|
||||
*/
|
||||
enum zxdg_shell_v5_version {
|
||||
/**
|
||||
* Always the latest version
|
||||
*/
|
||||
ZXDG_SHELL_V5_VERSION_CURRENT = 5,
|
||||
};
|
||||
#endif /* ZXDG_SHELL_V5_VERSION_ENUM */
|
||||
|
||||
#ifndef ZXDG_SHELL_V5_ERROR_ENUM
|
||||
#define ZXDG_SHELL_V5_ERROR_ENUM
|
||||
enum zxdg_shell_v5_error {
|
||||
/**
|
||||
* given wl_surface has another role
|
||||
*/
|
||||
ZXDG_SHELL_V5_ERROR_ROLE = 0,
|
||||
/**
|
||||
* xdg_shell was destroyed before children
|
||||
*/
|
||||
ZXDG_SHELL_V5_ERROR_DEFUNCT_SURFACES = 1,
|
||||
/**
|
||||
* the client tried to map or destroy a non-topmost popup
|
||||
*/
|
||||
ZXDG_SHELL_V5_ERROR_NOT_THE_TOPMOST_POPUP = 2,
|
||||
/**
|
||||
* the client specified an invalid popup parent surface
|
||||
*/
|
||||
ZXDG_SHELL_V5_ERROR_INVALID_POPUP_PARENT = 3,
|
||||
};
|
||||
#endif /* ZXDG_SHELL_V5_ERROR_ENUM */
|
||||
|
||||
/**
|
||||
* @ingroup iface_xdg_shell
|
||||
* @struct zxdg_shell_v5_interface
|
||||
*/
|
||||
struct zxdg_shell_v5_interface {
|
||||
/**
|
||||
* destroy xdg_shell
|
||||
*
|
||||
* Destroy this xdg_shell object.
|
||||
*
|
||||
* Destroying a bound xdg_shell object while there are surfaces
|
||||
* still alive created by this xdg_shell object instance is illegal
|
||||
* and will result in a protocol error.
|
||||
*/
|
||||
void (*destroy)(struct wl_client *client, struct wl_resource *resource);
|
||||
/**
|
||||
* enable use of this unstable version
|
||||
*
|
||||
* Negotiate the unstable version of the interface. This
|
||||
* mechanism is in place to ensure client and server agree on the
|
||||
* unstable versions of the protocol that they speak or exit
|
||||
* cleanly if they don't agree. This request will go away once the
|
||||
* xdg-shell protocol is stable.
|
||||
*/
|
||||
void (*use_unstable_version)(struct wl_client *client, struct wl_resource *resource, int32_t version);
|
||||
/**
|
||||
* create a shell surface from a surface
|
||||
*
|
||||
* This creates an xdg_surface for the given surface and gives it
|
||||
* the zxdg_surface role. A wl_v5_surface can only be given an
|
||||
* zxdg_surface role once. If get_v5_xdg_surface is called with a
|
||||
* wl_surface that already has an active xdg_surface associated
|
||||
* with it, or if it had any other role, an error is raised.
|
||||
*
|
||||
* See the documentation of xdg_surface for more details about what
|
||||
* an xdg_surface is and how it is used.
|
||||
*/
|
||||
void (*get_zxdg_surface)(struct wl_client *client, struct wl_resource *resource, uint32_t id, struct wl_resource *surface);
|
||||
/**
|
||||
* create a popup for a surface
|
||||
*
|
||||
* This creates an xdg_popup for the given surface and gives it
|
||||
* the zxdg_popup role. A wl_v5_surface can only be given an xdg_popup
|
||||
* role once. If get_zxdg_popup is called with a wl_v5_surface that
|
||||
* already has an active xdg_popup associated with it, or if it had
|
||||
* any other role, an error is raised.
|
||||
*
|
||||
* This request must be used in response to some sort of user
|
||||
* action like a button press, key press, or touch down event.
|
||||
*
|
||||
* See the documentation of xdg_popup for more details about what
|
||||
* an xdg_popup is and how it is used.
|
||||
* @param seat the wl_seat of the user event
|
||||
* @param serial the serial of the user event
|
||||
*/
|
||||
void (*get_zxdg_popup)(struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t id,
|
||||
struct wl_resource *surface,
|
||||
struct wl_resource *parent,
|
||||
struct wl_resource *seat,
|
||||
uint32_t serial,
|
||||
int32_t x,
|
||||
int32_t y);
|
||||
/**
|
||||
* respond to a ping event
|
||||
*
|
||||
* A client must respond to a ping event with a pong request or
|
||||
* the client may be deemed unresponsive.
|
||||
* @param serial serial of the ping event
|
||||
*/
|
||||
void (*pong)(struct wl_client *client, struct wl_resource *resource, uint32_t serial);
|
||||
};
|
||||
|
||||
#define ZXDG_SHELL_V5_PING 0
|
||||
|
||||
/**
|
||||
* @ingroup iface_xdg_shell
|
||||
*/
|
||||
#define ZXDG_SHELL_V5_PING_SINCE_VERSION 1
|
||||
|
||||
/**
|
||||
* @ingroup iface_xdg_shell
|
||||
*/
|
||||
#define ZXDG_SHELL_V5_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_shell
|
||||
*/
|
||||
#define ZXDG_SHELL_V5_USE_UNSTABLE_VERSION_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_shell
|
||||
*/
|
||||
#define ZXDG_SHELL_V5_GET_ZXDG_SURFACE_V5_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_shell
|
||||
*/
|
||||
#define ZXDG_SHELL_V5_GET_ZXDG_POPUP_v5_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_shell
|
||||
*/
|
||||
#define ZXDG_SHELL_V5_PONG_SINCE_VERSION 1
|
||||
|
||||
/**
|
||||
* @ingroup iface_xdg_shell
|
||||
* Sends an ping event to the client owning the resource.
|
||||
* @param resource_ The client's resource
|
||||
* @param serial pass this to the pong request
|
||||
*/
|
||||
static inline void zxdg_shell_v5_send_ping(struct wl_resource *resource_, uint32_t serial)
|
||||
{
|
||||
wl_resource_post_event(resource_, ZXDG_SHELL_V5_PING, serial);
|
||||
}
|
||||
|
||||
#ifndef ZXDG_SURFACE_V5_RESIZE_EDGE_ENUM
|
||||
#define ZXDG_SURFACE_V5_RESIZE_EDGE_ENUM
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
* edge values for resizing
|
||||
*
|
||||
* These values are used to indicate which edge of a surface
|
||||
* is being dragged in a resize operation.
|
||||
*/
|
||||
enum zxdg_surface_v5_resize_edge {
|
||||
ZXDG_SURFACE_V5_RESIZE_EDGE_NONE = 0,
|
||||
ZXDG_SURFACE_V5_RESIZE_EDGE_TOP = 1,
|
||||
ZXDG_SURFACE_V5_RESIZE_EDGE_BOTTOM = 2,
|
||||
ZXDG_SURFACE_V5_RESIZE_EDGE_LEFT = 4,
|
||||
ZXDG_SURFACE_V5_RESIZE_EDGE_TOP_LEFT = 5,
|
||||
ZXDG_SURFACE_V5_RESIZE_EDGE_BOTTOM_LEFT = 6,
|
||||
ZXDG_SURFACE_V5_RESIZE_EDGE_RIGHT = 8,
|
||||
ZXDG_SURFACE_V5_RESIZE_EDGE_TOP_RIGHT = 9,
|
||||
ZXDG_SURFACE_V5_RESIZE_EDGE_BOTTOM_RIGHT = 10,
|
||||
};
|
||||
#endif /* ZXDG_SURFACE_V5_RESIZE_EDGE_ENUM */
|
||||
|
||||
#ifndef ZXDG_SURFACE_V5_STATE_ENUM
|
||||
#define ZXDG_SURFACE_V5_STATE_ENUM
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
* the surface is now activated
|
||||
*
|
||||
* Client window decorations should be painted as if the window is
|
||||
* active. Do not assume this means that the window actually has
|
||||
* keyboard or pointer focus.
|
||||
*/
|
||||
enum zxdg_surface_v5_state {
|
||||
/**
|
||||
* the surface is maximized
|
||||
*/
|
||||
ZXDG_SURFACE_V5_STATE_MAXIMIZED = 1,
|
||||
/**
|
||||
* the surface is fullscreen
|
||||
*/
|
||||
ZXDG_SURFACE_V5_STATE_FULLSCREEN = 2,
|
||||
/**
|
||||
* the surface is being resized
|
||||
*/
|
||||
ZXDG_SURFACE_V5_STATE_RESIZING = 3,
|
||||
/**
|
||||
* the surface is now activated
|
||||
*/
|
||||
ZXDG_SURFACE_V5_STATE_ACTIVATED = 4,
|
||||
};
|
||||
#endif /* ZXDG_SURFACE_V5_STATE_ENUM */
|
||||
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
* @struct zxdg_surface_v5_interface
|
||||
*/
|
||||
struct zxdg_surface_v5_interface {
|
||||
/**
|
||||
* Destroy the xdg_surface
|
||||
*
|
||||
* Unmap and destroy the window. The window will be effectively
|
||||
* hidden from the user's point of view, and all state like
|
||||
* maximization, fullscreen, and so on, will be lost.
|
||||
*/
|
||||
void (*destroy)(struct wl_client *client, struct wl_resource *resource);
|
||||
/**
|
||||
* set the parent of this surface
|
||||
*
|
||||
* Set the "parent" of this surface. This window should be
|
||||
* stacked above a parent. The parent surface must be mapped as
|
||||
* long as this surface is mapped.
|
||||
*
|
||||
* Parent windows should be set on dialogs, toolboxes, or other
|
||||
* "auxiliary" surfaces, so that the parent is raised when the
|
||||
* dialog is raised.
|
||||
*/
|
||||
void (*set_parent)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *parent);
|
||||
/**
|
||||
* set surface title
|
||||
*
|
||||
* Set a short title for the surface.
|
||||
*
|
||||
* This string may be used to identify the surface in a task bar,
|
||||
* window list, or other user interface elements provided by the
|
||||
* compositor.
|
||||
*
|
||||
* The string must be encoded in UTF-8.
|
||||
*/
|
||||
void (*set_title)(struct wl_client *client, struct wl_resource *resource, const char *title);
|
||||
/**
|
||||
* set application ID
|
||||
*
|
||||
* Set an application identifier for the surface.
|
||||
*
|
||||
* The app ID identifies the general class of applications to which
|
||||
* the surface belongs. The compositor can use this to group
|
||||
* multiple surfaces together, or to determine how to launch a new
|
||||
* application.
|
||||
*
|
||||
* For D-Bus activatable applications, the app ID is used as the
|
||||
* D-Bus service name.
|
||||
*
|
||||
* The compositor shell will try to group application surfaces
|
||||
* together by their app ID. As a best practice, it is suggested to
|
||||
* select app ID's that match the basename of the application's
|
||||
* .desktop file. For example, "org.freedesktop.FooViewer" where
|
||||
* the .desktop file is "org.freedesktop.FooViewer.desktop".
|
||||
*
|
||||
* See the desktop-entry specification [0] for more details on
|
||||
* application identifiers and how they relate to well-known D-Bus
|
||||
* names and .desktop files.
|
||||
*
|
||||
* [0] http://standards.freedesktop.org/desktop-entry-spec/
|
||||
*/
|
||||
void (*set_app_id)(struct wl_client *client, struct wl_resource *resource, const char *app_id);
|
||||
/**
|
||||
* show the window menu
|
||||
*
|
||||
* Clients implementing client-side decorations might want to
|
||||
* show a context menu when right-clicking on the decorations,
|
||||
* giving the user a menu that they can use to maximize or minimize
|
||||
* the window.
|
||||
*
|
||||
* This request asks the compositor to pop up such a window menu at
|
||||
* the given position, relative to the local surface coordinates of
|
||||
* the parent surface. There are no guarantees as to what menu
|
||||
* items the window menu contains.
|
||||
*
|
||||
* This request must be used in response to some sort of user
|
||||
* action like a button press, key press, or touch down event.
|
||||
* @param seat the wl_seat of the user event
|
||||
* @param serial the serial of the user event
|
||||
* @param x the x position to pop up the window menu at
|
||||
* @param y the y position to pop up the window menu at
|
||||
*/
|
||||
void (*show_window_menu)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, int32_t x, int32_t y);
|
||||
/**
|
||||
* start an interactive move
|
||||
*
|
||||
* Start an interactive, user-driven move of the surface.
|
||||
*
|
||||
* This request must be used in response to some sort of user
|
||||
* action like a button press, key press, or touch down event. The
|
||||
* passed serial is used to determine the type of interactive move
|
||||
* (touch, pointer, etc).
|
||||
*
|
||||
* The server may ignore move requests depending on the state of
|
||||
* the surface (e.g. fullscreen or maximized), or if the passed
|
||||
* serial is no longer valid.
|
||||
*
|
||||
* If triggered, the surface will lose the focus of the device
|
||||
* (wl_pointer, wl_touch, etc) used for the move. It is up to the
|
||||
* compositor to visually indicate that the move is taking place,
|
||||
* such as updating a pointer cursor, during the move. There is no
|
||||
* guarantee that the device focus will return when the move is
|
||||
* completed.
|
||||
* @param seat the wl_seat of the user event
|
||||
* @param serial the serial of the user event
|
||||
*/
|
||||
void (*move)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial);
|
||||
/**
|
||||
* start an interactive resize
|
||||
*
|
||||
* Start a user-driven, interactive resize of the surface.
|
||||
*
|
||||
* This request must be used in response to some sort of user
|
||||
* action like a button press, key press, or touch down event. The
|
||||
* passed serial is used to determine the type of interactive
|
||||
* resize (touch, pointer, etc).
|
||||
*
|
||||
* The server may ignore resize requests depending on the state of
|
||||
* the surface (e.g. fullscreen or maximized).
|
||||
*
|
||||
* If triggered, the client will receive configure events with the
|
||||
* "resize" state enum value and the expected sizes. See the
|
||||
* "resize" enum value for more details about what is required. The
|
||||
* client must also acknowledge configure events using
|
||||
* "ack_configure". After the resize is completed, the client will
|
||||
* receive another "configure" event without the resize state.
|
||||
*
|
||||
* If triggered, the surface also will lose the focus of the device
|
||||
* (wl_pointer, wl_touch, etc) used for the resize. It is up to the
|
||||
* compositor to visually indicate that the resize is taking place,
|
||||
* such as updating a pointer cursor, during the resize. There is
|
||||
* no guarantee that the device focus will return when the resize
|
||||
* is completed.
|
||||
*
|
||||
* The edges parameter specifies how the surface should be resized,
|
||||
* and is one of the values of the resize_edge enum. The compositor
|
||||
* may use this information to update the surface position for
|
||||
* example when dragging the top left corner. The compositor may
|
||||
* also use this information to adapt its behavior, e.g. choose an
|
||||
* appropriate cursor image.
|
||||
* @param seat the wl_seat of the user event
|
||||
* @param serial the serial of the user event
|
||||
* @param edges which edge or corner is being dragged
|
||||
*/
|
||||
void (*resize)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat, uint32_t serial, uint32_t edges);
|
||||
/**
|
||||
* ack a configure event
|
||||
*
|
||||
* When a configure event is received, if a client commits the
|
||||
* surface in response to the configure event, then the client must
|
||||
* make an ack_configure request sometime before the commit
|
||||
* request, passing along the serial of the configure event.
|
||||
*
|
||||
* For instance, the compositor might use this information to move
|
||||
* a surface to the top left only when the client has drawn itself
|
||||
* for the maximized or fullscreen state.
|
||||
*
|
||||
* If the client receives multiple configure events before it can
|
||||
* respond to one, it only has to ack the last configure event.
|
||||
*
|
||||
* A client is not required to commit immediately after sending an
|
||||
* ack_configure request - it may even ack_configure several times
|
||||
* before its next surface commit.
|
||||
*
|
||||
* The compositor expects that the most recently received
|
||||
* ack_configure request at the time of a commit indicates which
|
||||
* configure event the client is responding to.
|
||||
* @param serial the serial from the configure event
|
||||
*/
|
||||
void (*ack_configure)(struct wl_client *client, struct wl_resource *resource, uint32_t serial);
|
||||
/**
|
||||
* set the new window geometry
|
||||
*
|
||||
* The window geometry of a window is its "visible bounds" from
|
||||
* the user's perspective. Client-side decorations often have
|
||||
* invisible portions like drop-shadows which should be ignored for
|
||||
* the purposes of aligning, placing and constraining windows.
|
||||
*
|
||||
* The window geometry is double buffered, and will be applied at
|
||||
* the time wl_surface.commit of the corresponding wl_surface is
|
||||
* called.
|
||||
*
|
||||
* Once the window geometry of the surface is set once, it is not
|
||||
* possible to unset it, and it will remain the same until
|
||||
* set_window_geometry is called again, even if a new subsurface or
|
||||
* buffer is attached.
|
||||
*
|
||||
* If never set, the value is the full bounds of the surface,
|
||||
* including any subsurfaces. This updates dynamically on every
|
||||
* commit. This unset mode is meant for extremely simple clients.
|
||||
*
|
||||
* If responding to a configure event, the window geometry in here
|
||||
* must respect the sizing negotiations specified by the states in
|
||||
* the configure event.
|
||||
*
|
||||
* The arguments are given in the surface local coordinate space of
|
||||
* the wl_surface associated with this xdg_surface.
|
||||
*
|
||||
* The width and height must be greater than zero.
|
||||
*/
|
||||
void (*set_window_geometry)(struct wl_client *client, struct wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height);
|
||||
/**
|
||||
* maximize the window
|
||||
*
|
||||
* Maximize the surface.
|
||||
*
|
||||
* After requesting that the surface should be maximized, the
|
||||
* compositor will respond by emitting a configure event with the
|
||||
* "maximized" state and the required window geometry. The client
|
||||
* should then update its content, drawing it in a maximized state,
|
||||
* i.e. without shadow or other decoration outside of the window
|
||||
* geometry. The client must also acknowledge the configure when
|
||||
* committing the new content (see ack_configure).
|
||||
*
|
||||
* It is up to the compositor to decide how and where to maximize
|
||||
* the surface, for example which output and what region of the
|
||||
* screen should be used.
|
||||
*
|
||||
* If the surface was already maximized, the compositor will still
|
||||
* emit a configure event with the "maximized" state.
|
||||
*/
|
||||
void (*set_maximized)(struct wl_client *client, struct wl_resource *resource);
|
||||
/**
|
||||
* unmaximize the window
|
||||
*
|
||||
* Unmaximize the surface.
|
||||
*
|
||||
* After requesting that the surface should be unmaximized, the
|
||||
* compositor will respond by emitting a configure event without
|
||||
* the "maximized" state. If available, the compositor will include
|
||||
* the window geometry dimensions the window had prior to being
|
||||
* maximized in the configure request. The client must then update
|
||||
* its content, drawing it in a regular state, i.e. potentially
|
||||
* with shadow, etc. The client must also acknowledge the configure
|
||||
* when committing the new content (see ack_configure).
|
||||
*
|
||||
* It is up to the compositor to position the surface after it was
|
||||
* unmaximized; usually the position the surface had before
|
||||
* maximizing, if applicable.
|
||||
*
|
||||
* If the surface was already not maximized, the compositor will
|
||||
* still emit a configure event without the "maximized" state.
|
||||
*/
|
||||
void (*unset_maximized)(struct wl_client *client, struct wl_resource *resource);
|
||||
/**
|
||||
* set the window as fullscreen on a monitor
|
||||
*
|
||||
* Make the surface fullscreen.
|
||||
*
|
||||
* You can specify an output that you would prefer to be
|
||||
* fullscreen. If this value is NULL, it's up to the compositor to
|
||||
* choose which display will be used to map this surface.
|
||||
*
|
||||
* If the surface doesn't cover the whole output, the compositor
|
||||
* will position the surface in the center of the output and
|
||||
* compensate with black borders filling the rest of the output.
|
||||
*/
|
||||
void (*set_fullscreen)(struct wl_client *client, struct wl_resource *resource, struct wl_resource *output);
|
||||
/**
|
||||
*/
|
||||
void (*unset_fullscreen)(struct wl_client *client, struct wl_resource *resource);
|
||||
/**
|
||||
* set the window as minimized
|
||||
*
|
||||
* Request that the compositor minimize your surface. There is no
|
||||
* way to know if the surface is currently minimized, nor is there
|
||||
* any way to unset minimization on this surface.
|
||||
*
|
||||
* If you are looking to throttle redrawing when minimized, please
|
||||
* instead use the wl_surface.frame event for this, as this will
|
||||
* also work with live previews on windows in Alt-Tab, Expose or
|
||||
* similar compositor features.
|
||||
*/
|
||||
void (*set_minimized)(struct wl_client *client, struct wl_resource *resource);
|
||||
};
|
||||
|
||||
#define ZXDG_SURFACE_V5_CONFIGURE 0
|
||||
#define ZXDG_SURFACE_V5_CLOSE 1
|
||||
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_CONFIGURE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_CLOSE_SINCE_VERSION 1
|
||||
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_DESTROY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_SET_PARENT_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_SET_TITLE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_SET_APP_ID_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_SHOW_WINDOW_MENU_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_MOVE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_RESIZE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_ACK_CONFIGURE_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_SET_WINDOW_GEOMETRY_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_SET_MAXIMIZED_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_UNSET_MAXIMIZED_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_SET_FULLSCREEN_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_UNSET_FULLSCREEN_SINCE_VERSION 1
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
*/
|
||||
#define ZXDG_SURFACE_V5_SET_MINIMIZED_SINCE_VERSION 1
|
||||
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
* Sends an configure event to the client owning the resource.
|
||||
* @param resource_ The client's resource
|
||||
*/
|
||||
static inline void zxdg_surface_v5_send_configure(struct wl_resource *resource_, int32_t width, int32_t height, struct wl_array *states, uint32_t serial)
|
||||
{
|
||||
wl_resource_post_event(resource_, ZXDG_SURFACE_V5_CONFIGURE, width, height, states, serial);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_xdg_surface
|
||||
* Sends an close event to the client owning the resource.
|
||||
* @param resource_ The client's resource
|
||||
*/
|
||||
static inline void zxdg_surface_v5_send_close(struct wl_resource *resource_)
|
||||
{
|
||||
wl_resource_post_event(resource_, ZXDG_SURFACE_V5_CLOSE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @ingroup iface_xdg_popup
|
||||
* @struct zxdg_popup_v5_interface
|
||||
*/
|
||||
struct zxdg_popup_v5_interface {
|
||||
/**
|
||||
* remove xdg_popup interface
|
||||
*
|
||||
* This destroys the popup. Explicitly destroying the xdg_popup
|
||||
* object will also dismiss the popup, and unmap the surface.
|
||||
*
|
||||
* If this xdg_popup is not the "topmost" popup, a protocol error
|
||||
* will be sent.
|
||||
*/
|
||||
void (*destroy)(struct wl_client *client, struct wl_resource *resource);
|
||||
};
|
||||
|
||||
#define ZXDG_POPUP_v5_POPUP_DONE 0
|
||||
|
||||
/**
|
||||
* @ingroup iface_xdg_popup
|
||||
*/
|
||||
#define ZXDG_POPUP_v5_POPUP_DONE_SINCE_VERSION 1
|
||||
|
||||
/**
|
||||
* @ingroup iface_xdg_popup
|
||||
*/
|
||||
#define ZXDG_POPUP_v5_DESTROY_SINCE_VERSION 1
|
||||
|
||||
/**
|
||||
* @ingroup iface_xdg_popup
|
||||
* Sends an popup_done event to the client owning the resource.
|
||||
* @param resource_ The client's resource
|
||||
*/
|
||||
static inline void zxdg_popup_v5_send_popup_done(struct wl_resource *resource_)
|
||||
{
|
||||
wl_resource_post_event(resource_, ZXDG_POPUP_v5_POPUP_DONE);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user