Implement xdg-toplevel-drag
This commit is contained in:
parent
01a1aaf99e
commit
b336691b3e
13 changed files with 477 additions and 22 deletions
|
@ -29,6 +29,7 @@
|
|||
#include "pointer_input.h"
|
||||
#include "tablet_input.h"
|
||||
#include "touch_input.h"
|
||||
#include "wayland/xdgtopleveldrag_v1_interface.h"
|
||||
#include "x11window.h"
|
||||
#if KWIN_BUILD_TABBOX
|
||||
#include "tabbox/tabbox.h"
|
||||
|
@ -72,6 +73,7 @@
|
|||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
#include "osd.h"
|
||||
#include "wayland/xdgshell_interface.h"
|
||||
#include <cmath>
|
||||
|
||||
using namespace std::literals;
|
||||
|
@ -2383,6 +2385,15 @@ public:
|
|||
m_raiseTimer.setSingleShot(true);
|
||||
m_raiseTimer.setInterval(250);
|
||||
connect(&m_raiseTimer, &QTimer::timeout, this, &DragAndDropInputFilter::raiseDragTarget);
|
||||
|
||||
connect(waylandServer()->seat(), &KWaylandServer::SeatInterface::dragEnded, this, [this] {
|
||||
if (!m_currentToplevelDragWindow) {
|
||||
return;
|
||||
}
|
||||
m_currentToplevelDragWindow->setKeepAbove(m_wasKeepAbove);
|
||||
workspace()->takeActivity(m_currentToplevelDragWindow, Workspace::ActivityFlag::ActivityFocus | Workspace::ActivityFlag::ActivityRaise);
|
||||
m_currentToplevelDragWindow = nullptr;
|
||||
});
|
||||
}
|
||||
|
||||
bool pointerEvent(MouseEvent *event, quint32 nativeButton) override
|
||||
|
@ -2398,6 +2409,11 @@ public:
|
|||
switch (event->type()) {
|
||||
case QEvent::MouseMove: {
|
||||
const auto pos = input()->globalPointer();
|
||||
|
||||
if (seat->xdgTopleveldrag()) {
|
||||
dragToplevel(pos, seat->xdgTopleveldrag());
|
||||
}
|
||||
|
||||
seat->notifyPointerMotion(pos);
|
||||
|
||||
Window *dragTarget = pickDragTarget(pos);
|
||||
|
@ -2499,6 +2515,11 @@ public:
|
|||
if (m_touchId != id) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (seat->xdgTopleveldrag()) {
|
||||
dragToplevel(pos, seat->xdgTopleveldrag());
|
||||
}
|
||||
|
||||
seat->setTimestamp(time);
|
||||
seat->notifyTouchMotion(id, pos);
|
||||
|
||||
|
@ -2573,6 +2594,9 @@ private:
|
|||
do {
|
||||
--it;
|
||||
Window *window = (*it);
|
||||
if (auto toplevelDrag = waylandServer()->seat()->xdgTopleveldrag(); toplevelDrag && toplevelDrag->toplevel() && toplevelDrag->toplevel()->surface() == window->surface()) {
|
||||
continue;
|
||||
}
|
||||
if (window->isDeleted()) {
|
||||
continue;
|
||||
}
|
||||
|
@ -2592,10 +2616,33 @@ private:
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void dragToplevel(const QPointF &pos, const KWaylandServer::XdgToplevelDragV1Interface *toplevelDrag)
|
||||
{
|
||||
|
||||
auto window = toplevelDrag->toplevel() ? waylandServer()->findWindow(toplevelDrag->toplevel()->surface()) : nullptr;
|
||||
|
||||
if (m_currentToplevelDragWindow != window) {
|
||||
if (m_currentToplevelDragWindow) {
|
||||
m_currentToplevelDragWindow->setKeepAbove(m_wasKeepAbove);
|
||||
}
|
||||
m_currentToplevelDragWindow = window;
|
||||
if (window) {
|
||||
m_wasKeepAbove = window->keepAbove();
|
||||
window->setKeepAbove(true);
|
||||
}
|
||||
}
|
||||
|
||||
if (window) {
|
||||
window->move(pos - toplevelDrag->offset());
|
||||
}
|
||||
}
|
||||
|
||||
qint32 m_touchId = -1;
|
||||
QPointF m_lastPos = QPointF(-1, -1);
|
||||
QPointer<Window> m_dragTarget;
|
||||
QTimer m_raiseTimer;
|
||||
QPointer<Window> m_currentToplevelDragWindow = nullptr;
|
||||
bool m_wasKeepAbove = false;
|
||||
};
|
||||
|
||||
KWIN_SINGLETON_FACTORY(InputRedirection)
|
||||
|
|
|
@ -217,6 +217,11 @@ ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml
|
|||
BASENAME cursor-shape-v1
|
||||
)
|
||||
|
||||
ecm_add_qtwayland_server_protocol_kde(WaylandProtocols_xml
|
||||
PROTOCOL protocols/xdg-toplevel-drag-v1.xml
|
||||
BASENAME xdg-toplevel-drag-v1
|
||||
)
|
||||
|
||||
target_sources(kwin PRIVATE
|
||||
abstract_data_source.cpp
|
||||
abstract_drop_handler.cpp
|
||||
|
@ -292,6 +297,7 @@ target_sources(kwin PRIVATE
|
|||
xdgforeign_v2_interface.cpp
|
||||
xdgoutput_v1_interface.cpp
|
||||
xdgshell_interface.cpp
|
||||
xdgtopleveldrag_v1_interface.cpp
|
||||
xwaylandkeyboardgrab_v1_interface.cpp
|
||||
xwaylandshell_v1_interface.cpp
|
||||
)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
#include "datadevice_interface.h"
|
||||
#include "datadevice_interface_p.h"
|
||||
#include "datadevicemanager_interface.h"
|
||||
|
@ -127,6 +128,11 @@ void DataDeviceInterfacePrivate::data_device_set_selection(Resource *resource, w
|
|||
return;
|
||||
}
|
||||
|
||||
if (dataSource && dataSource->xdgToplevelDrag()) {
|
||||
wl_resource_post_error(resource->handle, QtWaylandServer::wl_data_source::error_invalid_source, "Data source is for drag and drop");
|
||||
return;
|
||||
}
|
||||
|
||||
if (selection == dataSource) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -202,7 +202,6 @@ void DataOfferInterface::dndAction(DataDeviceManagerInterface::DnDAction action)
|
|||
}
|
||||
d->send_action(wlAction);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "moc_dataoffer_interface.cpp"
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "datasource_interface.h"
|
||||
#include "clientconnection.h"
|
||||
#include "datadevicemanager_interface.h"
|
||||
#include "datasource_interface_p.h"
|
||||
#include "utils.h"
|
||||
// Qt
|
||||
#include <QStringList>
|
||||
|
@ -17,27 +18,6 @@
|
|||
|
||||
namespace KWaylandServer
|
||||
{
|
||||
class DataSourceInterfacePrivate : public QtWaylandServer::wl_data_source
|
||||
{
|
||||
public:
|
||||
DataSourceInterfacePrivate(DataSourceInterface *_q, ::wl_resource *resource);
|
||||
|
||||
DataSourceInterface *q;
|
||||
QStringList mimeTypes;
|
||||
DataDeviceManagerInterface::DnDActions supportedDnDActions = DataDeviceManagerInterface::DnDAction::None;
|
||||
DataDeviceManagerInterface::DnDAction selectedDndAction = DataDeviceManagerInterface::DnDAction::None;
|
||||
bool isAccepted = false;
|
||||
|
||||
protected:
|
||||
void data_source_destroy_resource(Resource *resource) override;
|
||||
void data_source_offer(Resource *resource, const QString &mime_type) override;
|
||||
void data_source_destroy(Resource *resource) override;
|
||||
void data_source_set_actions(Resource *resource, uint32_t dnd_actions) override;
|
||||
|
||||
private:
|
||||
void offer(const QString &mimeType);
|
||||
};
|
||||
|
||||
DataSourceInterfacePrivate::DataSourceInterfacePrivate(DataSourceInterface *_q, ::wl_resource *resource)
|
||||
: QtWaylandServer::wl_data_source(resource)
|
||||
, q(_q)
|
||||
|
@ -92,6 +72,11 @@ void DataSourceInterfacePrivate::data_source_set_actions(Resource *resource, uin
|
|||
}
|
||||
}
|
||||
|
||||
DataSourceInterfacePrivate *DataSourceInterfacePrivate::get(DataSourceInterface *dataSource)
|
||||
{
|
||||
return dataSource->d.get();
|
||||
}
|
||||
|
||||
DataSourceInterface::DataSourceInterface(wl_resource *resource)
|
||||
: d(new DataSourceInterfacePrivate(this, resource))
|
||||
{
|
||||
|
@ -144,6 +129,7 @@ DataDeviceManagerInterface::DnDAction DataSourceInterface::selectedDndAction() c
|
|||
|
||||
void DataSourceInterface::dropPerformed()
|
||||
{
|
||||
d->dropPerformed = true;
|
||||
if (d->resource()->version() < WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION) {
|
||||
return;
|
||||
}
|
||||
|
@ -158,6 +144,11 @@ void DataSourceInterface::dndFinished()
|
|||
d->send_dnd_finished();
|
||||
}
|
||||
|
||||
bool DataSourceInterface::isDropPerformed() const
|
||||
{
|
||||
return d->dropPerformed;
|
||||
}
|
||||
|
||||
void DataSourceInterface::dndAction(DataDeviceManagerInterface::DnDAction action)
|
||||
{
|
||||
d->selectedDndAction = action;
|
||||
|
@ -178,6 +169,7 @@ void DataSourceInterface::dndAction(DataDeviceManagerInterface::DnDAction action
|
|||
|
||||
void DataSourceInterface::dndCancelled()
|
||||
{
|
||||
d->isCanceled = true;
|
||||
// for v3 or less, cancel should not be called after a failed drag operation
|
||||
if (wl_resource_get_version(resource()) < 3) {
|
||||
return;
|
||||
|
@ -185,6 +177,11 @@ void DataSourceInterface::dndCancelled()
|
|||
d->send_cancelled();
|
||||
}
|
||||
|
||||
bool DataSourceInterface::isDndCancelled() const
|
||||
{
|
||||
return d->isCanceled;
|
||||
}
|
||||
|
||||
wl_resource *DataSourceInterface::resource() const
|
||||
{
|
||||
return d->resource()->handle;
|
||||
|
@ -205,6 +202,11 @@ void DataSourceInterface::setAccepted(bool accepted)
|
|||
d->isAccepted = accepted;
|
||||
}
|
||||
|
||||
XdgToplevelDragV1Interface *DataSourceInterface::xdgToplevelDrag() const
|
||||
{
|
||||
return d->xdgToplevelDrag;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#include "moc_datasource_interface.cpp"
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
namespace KWaylandServer
|
||||
{
|
||||
class DataSourceInterfacePrivate;
|
||||
class XdgToplevelDragV1Interface;
|
||||
|
||||
/**
|
||||
* @brief Represents the Resource for the wl_data_source interface.
|
||||
|
@ -42,6 +43,9 @@ public:
|
|||
void dndAction(DataDeviceManagerInterface::DnDAction action) override;
|
||||
void dndCancelled() override;
|
||||
|
||||
bool isDndCancelled() const;
|
||||
bool isDropPerformed() const;
|
||||
|
||||
wl_resource *resource() const;
|
||||
|
||||
wl_client *client() const override;
|
||||
|
@ -49,8 +53,11 @@ public:
|
|||
bool isAccepted() const override;
|
||||
void setAccepted(bool accepted);
|
||||
|
||||
XdgToplevelDragV1Interface *xdgToplevelDrag() const;
|
||||
|
||||
private:
|
||||
friend class DataDeviceManagerInterfacePrivate;
|
||||
friend class DataSourceInterfacePrivate;
|
||||
explicit DataSourceInterface(wl_resource *resource);
|
||||
|
||||
std::unique_ptr<DataSourceInterfacePrivate> d;
|
||||
|
|
44
src/wayland/datasource_interface_p.h
Normal file
44
src/wayland/datasource_interface_p.h
Normal file
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
SPDX-FileCopyrightText: 2020 David Edmundson <davidedmundson@kde.org>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <qwayland-server-wayland.h>
|
||||
|
||||
#include "datadevicemanager_interface.h"
|
||||
|
||||
namespace KWaylandServer
|
||||
{
|
||||
class DataSourceInterface;
|
||||
class XdgToplevelDragV1Interface;
|
||||
|
||||
class DataSourceInterfacePrivate : public QtWaylandServer::wl_data_source
|
||||
{
|
||||
public:
|
||||
DataSourceInterfacePrivate(DataSourceInterface *_q, ::wl_resource *resource);
|
||||
|
||||
static DataSourceInterfacePrivate *get(DataSourceInterface *dataSource);
|
||||
|
||||
DataSourceInterface *q;
|
||||
QStringList mimeTypes;
|
||||
DataDeviceManagerInterface::DnDActions supportedDnDActions = DataDeviceManagerInterface::DnDAction::None;
|
||||
DataDeviceManagerInterface::DnDAction selectedDndAction = DataDeviceManagerInterface::DnDAction::None;
|
||||
bool isAccepted = false;
|
||||
bool dropPerformed = false;
|
||||
bool isCanceled = false;
|
||||
XdgToplevelDragV1Interface *xdgToplevelDrag = nullptr;
|
||||
|
||||
protected:
|
||||
void data_source_destroy_resource(Resource *resource) override;
|
||||
void data_source_offer(Resource *resource, const QString &mime_type) override;
|
||||
void data_source_destroy(Resource *resource) override;
|
||||
void data_source_set_actions(Resource *resource, uint32_t dnd_actions) override;
|
||||
|
||||
private:
|
||||
void offer(const QString &mimeType);
|
||||
};
|
||||
}
|
139
src/wayland/protocols/xdg-toplevel-drag-v1.xml
Normal file
139
src/wayland/protocols/xdg-toplevel-drag-v1.xml
Normal file
|
@ -0,0 +1,139 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<protocol name="xdg_toplevel_drag_v1">
|
||||
|
||||
<copyright>
|
||||
Copyright 2023 David Redondo <kde@david-redondo.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice (including the next
|
||||
paragraph) shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
</copyright>
|
||||
|
||||
<interface name="xdg_toplevel_drag_manager_v1" version="1">
|
||||
<description summary="Move a window during a drag">
|
||||
This protocol enhances normal drag and drop with the ability to move a
|
||||
window at the same time. This allows having detachable parts of a window
|
||||
that when dragged out of it become a new window and can be dragged over
|
||||
an existing window to be reattached.
|
||||
|
||||
A typical workflow would be when the user starts dragging on top of a
|
||||
detachable part of a window, the client would create a wl_data_source and
|
||||
a xdg_toplevel_drag_v1 object and start the drag as normal via
|
||||
wl_data_device.start_drag. Once the client determines that the detachable
|
||||
window contents should be detached from the originating window, it creates
|
||||
a new xdg_toplevel with these contents and issues a
|
||||
xdg_toplevel_drag_v1.attach request. From now on the new window is moved
|
||||
by the compositor during the drag as if the client called
|
||||
xdg_toplevel.move.
|
||||
|
||||
Dragging an existing window is similar. The client creates a
|
||||
xdg_toplevel_drag_v1 object and attaches the existing toplevel before
|
||||
starting the drag.
|
||||
|
||||
Clients use the existing drag and drop mechanism to detect when a window
|
||||
can be docked or undocked. If the client wants to snap a window into a
|
||||
parent window it should delete or unmap the dragged top-level. If the
|
||||
contents should be detached again it attaches a new toplevel as described
|
||||
above. If a drag operation is cancelled, clients should revert to the
|
||||
previous state, deleting any newly created windows as appropriate.
|
||||
When a drag operation ends the dragged toplevel window's final position is
|
||||
determined as if a xdg_toplevel_move operation ended.
|
||||
|
||||
Warning! The protocol described in this file is currently in the testing
|
||||
phase. Backward compatible changes may be added together with the
|
||||
corresponding interface version bump. Backward incompatible changes can
|
||||
only be done by creating a new major version of the extension.
|
||||
</description>
|
||||
|
||||
<request name="get_xdg_toplevel_drag">
|
||||
<description summary="get an xdg_toplevel_drag for a wl_data_source">
|
||||
Create an xdg_toplevel_drag for a drag and drop operation that is going
|
||||
to be started with data_source.
|
||||
|
||||
This request can only be made on sources used in drag-and-drop, so it
|
||||
must be performed before wl_data_device.start_drag. Attempting to use
|
||||
the source other than for drag-and-drop such as in
|
||||
wl_data_device.set_selection will raise an invalid_source error.
|
||||
|
||||
Destroying data_source while a toplevel is attached to the
|
||||
xdg_toplevel_drag is undefined.
|
||||
</description>
|
||||
|
||||
<arg name="id" type="new_id" interface="xdg_toplevel_drag_v1"/>
|
||||
<arg name="data_source" type="object" interface="wl_data_source"/>
|
||||
</request>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy the xdg_toplevel_drag_manager_v1 object">
|
||||
Destroy this xdg_toplevel_drag_manager_v1 object. Other objects,
|
||||
including xdg_toplevel_drag_v1 objects created by this factory, are not
|
||||
affected by this request.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="invalid_source" value="0"
|
||||
summary="data_source already used for toplevel drag"/>
|
||||
</enum>
|
||||
</interface>
|
||||
|
||||
<interface name="xdg_toplevel_drag_v1" version="1">
|
||||
<description summary="Object representing a toplevel move during a drag">
|
||||
</description>
|
||||
|
||||
<request name="attach">
|
||||
<description summary="Move a toplevel with the drag operation">
|
||||
Request that the window will be moved with the cursor during the drag
|
||||
operation. The offset describes how the toplevel will be positioned
|
||||
relative to the cursor hotspot in surface local coordinates. The
|
||||
attached window does not participate in the selection of the drag
|
||||
target.
|
||||
|
||||
If the toplevel is unmapped while it is attached, it is automatically
|
||||
detached from the drag. In this case this request has to be called again
|
||||
if the window should be attached after it is remapped.
|
||||
|
||||
This request can be called multiple times but issuing it while a
|
||||
toplevel with an active role is attached raises a toplevel_attached
|
||||
error.
|
||||
</description>
|
||||
|
||||
<arg name="toplevel" type="object" interface="xdg_toplevel"/>
|
||||
<arg name="x_offset" type="int" summary="dragged surface x offset"/>
|
||||
<arg name="y_offset" type="int" summary="dragged surface y offset"/>
|
||||
</request>
|
||||
|
||||
<request name="destroy" type="destructor">
|
||||
<description summary="destroy an xdg_toplevel_drag_v1 object">
|
||||
Destroy this xdg_toplevel_drag_v1 object. This request must only be
|
||||
called after the underlying wl_data_source drag has ended, as indicated
|
||||
by the dnd_drop_performed or cancelled events. In any other case an
|
||||
ongoing_drag error is raised.
|
||||
</description>
|
||||
</request>
|
||||
|
||||
<enum name="error">
|
||||
<entry name="toplevel_attached" value="0"
|
||||
summary="valid toplevel already attached"/>
|
||||
<entry name="ongoing_drag" value="1"
|
||||
summary="drag has not ended" />
|
||||
</enum>
|
||||
|
||||
</interface>
|
||||
</protocol>
|
||||
|
|
@ -31,6 +31,7 @@
|
|||
#include "touch_interface_p.h"
|
||||
#include "utils.h"
|
||||
#include "utils/common.h"
|
||||
#include "xdgtopleveldrag_v1_interface.h"
|
||||
|
||||
#include <linux/input.h>
|
||||
|
||||
|
@ -273,6 +274,7 @@ void SeatInterfacePrivate::endDrag()
|
|||
|
||||
AbstractDropHandler *dragTargetDevice = drag.target.data();
|
||||
AbstractDataSource *dragSource = drag.source;
|
||||
|
||||
if (dragSource) {
|
||||
// TODO: Also check the current drag-and-drop action.
|
||||
if (dragTargetDevice && dragSource->isAccepted()) {
|
||||
|
@ -1214,6 +1216,14 @@ AbstractDataSource *SeatInterface::dragSource() const
|
|||
return d->drag.source;
|
||||
}
|
||||
|
||||
XdgToplevelDragV1Interface *SeatInterface::xdgTopleveldrag() const
|
||||
{
|
||||
if (auto source = qobject_cast<DataSourceInterface *>(d->drag.source)) {
|
||||
return source->xdgToplevelDrag();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void SeatInterface::setFocusedTextInputSurface(SurfaceInterface *surface)
|
||||
{
|
||||
const quint32 serial = d->display->nextSerial();
|
||||
|
|
|
@ -30,6 +30,7 @@ class TextInputV1Interface;
|
|||
class TextInputV2Interface;
|
||||
class TextInputV3Interface;
|
||||
class TouchInterface;
|
||||
class XdgToplevelDragV1Interface;
|
||||
|
||||
/**
|
||||
* Describes the source types for axis events. This indicates to the
|
||||
|
@ -182,6 +183,11 @@ public:
|
|||
* @see isDrag
|
||||
*/
|
||||
KWaylandServer::AbstractDataSource *dragSource() const;
|
||||
/**
|
||||
* @returns the toplevel drag if the current drag is a toplevel drag
|
||||
*/
|
||||
KWaylandServer::XdgToplevelDragV1Interface *xdgTopleveldrag() const;
|
||||
|
||||
/**
|
||||
* Sets the current drag target to @p surface.
|
||||
*
|
||||
|
|
131
src/wayland/xdgtopleveldrag_v1_interface.cpp
Normal file
131
src/wayland/xdgtopleveldrag_v1_interface.cpp
Normal file
|
@ -0,0 +1,131 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2023 David Redondo <kde@david-redondo.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
#include "xdgtopleveldrag_v1_interface.h"
|
||||
|
||||
#include <qwayland-server-xdg-toplevel-drag-v1.h>
|
||||
|
||||
#include "dataoffer_interface.h"
|
||||
#include "datasource_interface.h"
|
||||
#include "datasource_interface_p.h"
|
||||
#include "xdgshell_interface.h"
|
||||
|
||||
#include "display.h"
|
||||
#include "surface_interface.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <QPointer>
|
||||
|
||||
#include <memory>
|
||||
|
||||
namespace KWaylandServer
|
||||
{
|
||||
constexpr int version = 1;
|
||||
|
||||
class XdgToplevelDragV1InterfacePrivate : public QtWaylandServer::xdg_toplevel_drag_v1
|
||||
{
|
||||
public:
|
||||
XdgToplevelDragV1InterfacePrivate(wl_resource *resource, XdgToplevelDragV1Interface *q)
|
||||
: xdg_toplevel_drag_v1(resource)
|
||||
, q(q)
|
||||
{
|
||||
}
|
||||
XdgToplevelDragV1Interface *q;
|
||||
QPointer<DataSourceInterface> dataSource;
|
||||
QPointer<XdgToplevelInterface> toplevel;
|
||||
QPoint pos;
|
||||
|
||||
private:
|
||||
void xdg_toplevel_drag_v1_attach(Resource *resource, wl_resource *toplevelResource, int32_t x_offset, int32_t y_offset) override
|
||||
{
|
||||
if (toplevel) {
|
||||
wl_resource_post_error(resource->handle, error_toplevel_attached, "Valid toplevel already attached");
|
||||
return;
|
||||
}
|
||||
toplevel = XdgToplevelInterface::get(toplevelResource);
|
||||
QObject::connect(toplevel, &XdgToplevelInterface::resetOccurred, q, [this] {
|
||||
toplevel = nullptr;
|
||||
});
|
||||
pos = QPoint(x_offset, y_offset);
|
||||
Q_EMIT q->toplevelChanged();
|
||||
}
|
||||
|
||||
void xdg_toplevel_drag_v1_destroy_resource(Resource *resource) override
|
||||
{
|
||||
delete q;
|
||||
}
|
||||
void xdg_toplevel_drag_v1_destroy(Resource *resource) override
|
||||
{
|
||||
if (!dataSource || dataSource->isDndCancelled() || dataSource->isDropPerformed()) {
|
||||
wl_resource_destroy(resource->handle);
|
||||
return;
|
||||
}
|
||||
wl_resource_post_error(resource->handle, error_ongoing_drag, "Drag has not ended");
|
||||
}
|
||||
};
|
||||
|
||||
XdgToplevelDragV1Interface::XdgToplevelDragV1Interface(wl_resource *resource, DataSourceInterface *dataSource)
|
||||
: d(std::make_unique<XdgToplevelDragV1InterfacePrivate>(resource, this))
|
||||
{
|
||||
d->dataSource = dataSource;
|
||||
DataSourceInterfacePrivate::get(dataSource)->xdgToplevelDrag = this;
|
||||
}
|
||||
|
||||
XdgToplevelDragV1Interface::~XdgToplevelDragV1Interface()
|
||||
{
|
||||
if (d->dataSource) {
|
||||
DataSourceInterfacePrivate::get(d->dataSource)->xdgToplevelDrag = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
XdgToplevelInterface *XdgToplevelDragV1Interface::toplevel() const
|
||||
{
|
||||
return d->toplevel;
|
||||
}
|
||||
|
||||
QPoint XdgToplevelDragV1Interface::offset() const
|
||||
{
|
||||
return d->pos;
|
||||
}
|
||||
|
||||
class XdgToplevelDragManagerV1InterfacePrivate : public QtWaylandServer::xdg_toplevel_drag_manager_v1
|
||||
{
|
||||
public:
|
||||
XdgToplevelDragManagerV1InterfacePrivate(XdgToplevelDragManagerV1Interface *q, Display *display)
|
||||
: xdg_toplevel_drag_manager_v1(*display, version)
|
||||
, q(q)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void xdg_toplevel_drag_manager_v1_destroy(Resource *resource) override
|
||||
{
|
||||
wl_resource_destroy(resource->handle);
|
||||
}
|
||||
|
||||
void xdg_toplevel_drag_manager_v1_get_xdg_toplevel_drag(Resource *resource, uint32_t id, wl_resource *data_source) override
|
||||
{
|
||||
auto dataSource = DataSourceInterface::get(data_source);
|
||||
|
||||
wl_resource *xdg_toplevel_drag = wl_resource_create(resource->client(), &xdg_toplevel_drag_v1_interface, resource->version(), id);
|
||||
if (!xdg_toplevel_drag) {
|
||||
wl_resource_post_no_memory(resource->handle);
|
||||
return;
|
||||
}
|
||||
new XdgToplevelDragV1Interface(xdg_toplevel_drag, dataSource);
|
||||
}
|
||||
|
||||
XdgToplevelDragManagerV1Interface *q;
|
||||
};
|
||||
|
||||
XdgToplevelDragManagerV1Interface::XdgToplevelDragManagerV1Interface(KWaylandServer::Display *display, QObject *parent)
|
||||
: QObject(parent)
|
||||
, d(std::make_unique<XdgToplevelDragManagerV1InterfacePrivate>(this, display))
|
||||
{
|
||||
}
|
||||
|
||||
XdgToplevelDragManagerV1Interface::~XdgToplevelDragManagerV1Interface() = default;
|
||||
}
|
56
src/wayland/xdgtopleveldrag_v1_interface.h
Normal file
56
src/wayland/xdgtopleveldrag_v1_interface.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2023 David Redondo <kde@david-redondo.de>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "datadevice_interface.h"
|
||||
|
||||
struct wl_resource;
|
||||
|
||||
namespace KWaylandServer
|
||||
{
|
||||
|
||||
class DataOfferInterface;
|
||||
class DataSourceInterface;
|
||||
class Display;
|
||||
class XdgToplevelDragV1InterfacePrivate;
|
||||
class XdgToplevelDragManagerV1InterfacePrivate;
|
||||
class XdgToplevelInterface;
|
||||
|
||||
class XdgToplevelDragV1Interface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
~XdgToplevelDragV1Interface() override;
|
||||
|
||||
DataSourceInterface *dataSource();
|
||||
XdgToplevelInterface *toplevel() const;
|
||||
QPoint offset() const;
|
||||
|
||||
Q_SIGNALS:
|
||||
void toplevelChanged();
|
||||
|
||||
private:
|
||||
XdgToplevelDragV1Interface(wl_resource *resource, DataSourceInterface *dataSource);
|
||||
std::unique_ptr<XdgToplevelDragV1InterfacePrivate> d;
|
||||
friend class XdgToplevelDragManagerV1InterfacePrivate;
|
||||
};
|
||||
|
||||
class XdgToplevelDragManagerV1Interface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
XdgToplevelDragManagerV1Interface(Display *display, QObject *parent = nullptr);
|
||||
~XdgToplevelDragManagerV1Interface() override;
|
||||
|
||||
private:
|
||||
std::unique_ptr<XdgToplevelDragManagerV1InterfacePrivate> d;
|
||||
};
|
||||
}
|
|
@ -65,6 +65,7 @@
|
|||
#include "wayland/xdgforeign_v2_interface.h"
|
||||
#include "wayland/xdgoutput_v1_interface.h"
|
||||
#include "wayland/xdgshell_interface.h"
|
||||
#include "wayland/xdgtopleveldrag_v1_interface.h"
|
||||
#include "wayland/xwaylandkeyboardgrab_v1_interface.h"
|
||||
#include "wayland/xwaylandshell_v1_interface.h"
|
||||
#include "workspace.h"
|
||||
|
@ -513,6 +514,7 @@ bool WaylandServer::init(InitializationFlags flags)
|
|||
|
||||
m_contentTypeManager = new KWaylandServer::ContentTypeManagerV1Interface(m_display, m_display);
|
||||
m_tearingControlInterface = new KWaylandServer::TearingControlManagerV1Interface(m_display, m_display);
|
||||
new XdgToplevelDragManagerV1Interface(m_display, this);
|
||||
|
||||
auto screenEdgeManager = new KWaylandServer::ScreenEdgeManagerV1Interface(m_display, m_display);
|
||||
connect(screenEdgeManager, &KWaylandServer::ScreenEdgeManagerV1Interface::edgeRequested, this, [this](KWaylandServer::AutoHideScreenEdgeV1Interface *edge) {
|
||||
|
|
Loading…
Reference in a new issue