[xwl] Fix coding style issues
parent
bb6d1153f7
commit
88c4c58072
|
@ -19,35 +19,37 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
*********************************************************************/
|
||||
#include "clipboard.h"
|
||||
|
||||
#include "xwayland.h"
|
||||
#include "databridge.h"
|
||||
#include "selection_source.h"
|
||||
#include "transfer.h"
|
||||
#include "xwayland.h"
|
||||
|
||||
#include "client.h"
|
||||
#include "wayland_server.h"
|
||||
#include "workspace.h"
|
||||
#include "client.h"
|
||||
|
||||
#include <KWayland/Client/connection_thread.h>
|
||||
#include <KWayland/Client/datadevice.h>
|
||||
#include <KWayland/Client/datasource.h>
|
||||
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
#include <KWayland/Server/datadevice_interface.h>
|
||||
#include <KWayland/Server/datasource_interface.h>
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
|
||||
#include <xcb/xcb_event.h>
|
||||
#include <xcb/xfixes.h>
|
||||
|
||||
#include <xwayland_logging.h>
|
||||
|
||||
namespace KWin {
|
||||
namespace Xwl {
|
||||
namespace KWin
|
||||
{
|
||||
namespace Xwl
|
||||
{
|
||||
|
||||
Clipboard::Clipboard(xcb_atom_t atom, QObject *parent)
|
||||
: Selection(atom, parent)
|
||||
{
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
|
||||
const uint32_t clipboardValues[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
|
||||
XCB_EVENT_MASK_PROPERTY_CHANGE };
|
||||
|
@ -135,53 +137,56 @@ void Clipboard::checkWlSource()
|
|||
|
||||
void Clipboard::doHandleXfixesNotify(xcb_xfixes_selection_notify_event_t *event)
|
||||
{
|
||||
createX11Source(NULL);
|
||||
createX11Source(nullptr);
|
||||
|
||||
const auto *ac = workspace()->activeClient();
|
||||
if (!qobject_cast<const KWin::Client *>(ac)) {
|
||||
const AbstractClient *client = workspace()->activeClient();
|
||||
if (!qobject_cast<const Client *>(client)) {
|
||||
// clipboard is only allowed to be acquired when Xwayland has focus
|
||||
// TODO: can we make this stronger (window id comparision)?
|
||||
return;
|
||||
}
|
||||
|
||||
createX11Source(event);
|
||||
auto *xSrc = x11Source();
|
||||
if (xSrc) {
|
||||
xSrc->getTargets();
|
||||
|
||||
if (X11Source *source = x11Source()) {
|
||||
source->getTargets();
|
||||
}
|
||||
}
|
||||
|
||||
void Clipboard::x11OffersChanged(const QVector<QString> &added, const QVector<QString> &removed)
|
||||
void Clipboard::x11OffersChanged(const QStringList &added, const QStringList &removed)
|
||||
{
|
||||
auto *xSrc = x11Source();
|
||||
if (!xSrc) {
|
||||
X11Source *source = x11Source();
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto offers = xSrc->offers();
|
||||
const bool hasOffers = offers.size() > 0;
|
||||
const Mimes offers = source->offers();
|
||||
|
||||
if (hasOffers) {
|
||||
if (!xSrc->dataSource() || !removed.isEmpty()) {
|
||||
if (!offers.isEmpty()) {
|
||||
if (!source->dataSource() || !removed.isEmpty()) {
|
||||
// create new Wl DataSource if there is none or when types
|
||||
// were removed (Wl Data Sources can only add types)
|
||||
auto *ddm = waylandServer()->internalDataDeviceManager();
|
||||
auto *ds = ddm->createDataSource(xSrc);
|
||||
KWayland::Client::DataDeviceManager *dataDeviceManager =
|
||||
waylandServer()->internalDataDeviceManager();
|
||||
KWayland::Client::DataSource *dataSource =
|
||||
dataDeviceManager->createDataSource(source);
|
||||
|
||||
// also offers directly the currently available types
|
||||
xSrc->setDataSource(ds);
|
||||
DataBridge::self()->dataDevice()->setSelection(0, ds);
|
||||
source->setDataSource(dataSource);
|
||||
DataBridge::self()->dataDevice()->setSelection(0, dataSource);
|
||||
waylandServer()->seat()->setSelection(DataBridge::self()->dataDeviceIface());
|
||||
} else if (auto *ds = xSrc->dataSource()) {
|
||||
for (const auto &mime : added) {
|
||||
ds->offer(mime);
|
||||
} else if (auto *dataSource = source->dataSource()) {
|
||||
for (const QString &mime : added) {
|
||||
dataSource->offer(mime);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
waylandServer()->seat()->setSelection(nullptr);
|
||||
}
|
||||
|
||||
waylandServer()->internalClientConection()->flush();
|
||||
waylandServer()->dispatch();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
|
|
@ -38,30 +38,33 @@ namespace Xwl
|
|||
/**
|
||||
* Represents the X clipboard, which is on Wayland side just called
|
||||
* @e selection.
|
||||
*/
|
||||
**/
|
||||
class Clipboard : public Selection
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Clipboard(xcb_atom_t atom, QObject *parent);
|
||||
|
||||
private:
|
||||
void doHandleXfixesNotify(xcb_xfixes_selection_notify_event_t *event) override;
|
||||
void x11OffersChanged(const QVector<QString> &added, const QVector<QString> &removed) override;
|
||||
void x11OffersChanged(const QStringList &added, const QStringList &removed) override;
|
||||
/**
|
||||
* React to Wl selection change.
|
||||
*/
|
||||
**/
|
||||
void wlSelectionChanged(KWayland::Server::DataDeviceInterface *ddi);
|
||||
/**
|
||||
* Check the current state of the selection and if a source needs
|
||||
* to be created or destroyed.
|
||||
*/
|
||||
**/
|
||||
void checkWlSource();
|
||||
|
||||
QMetaObject::Connection m_checkConnection;
|
||||
|
||||
Q_DISABLE_COPY(Clipboard)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
||||
#endif
|
||||
|
|
|
@ -18,29 +18,34 @@ You should have received a copy of the GNU General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*********************************************************************/
|
||||
#include "databridge.h"
|
||||
#include "xwayland.h"
|
||||
#include "selection.h"
|
||||
#include "clipboard.h"
|
||||
#include "dnd.h"
|
||||
#include "selection.h"
|
||||
#include "xwayland.h"
|
||||
|
||||
#include "abstract_client.h"
|
||||
#include "atoms.h"
|
||||
#include "wayland_server.h"
|
||||
#include "workspace.h"
|
||||
#include "abstract_client.h"
|
||||
|
||||
// KWayland
|
||||
#include <KWayland/Client/seat.h>
|
||||
#include <KWayland/Client/datadevicemanager.h>
|
||||
#include <KWayland/Client/seat.h>
|
||||
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
#include <KWayland/Server/datadevicemanager_interface.h>
|
||||
#include <KWayland/Server/datadevice_interface.h>
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
|
||||
namespace KWin {
|
||||
namespace Xwl {
|
||||
using namespace KWayland::Client;
|
||||
using namespace KWayland::Server;
|
||||
|
||||
namespace KWin
|
||||
{
|
||||
namespace Xwl
|
||||
{
|
||||
|
||||
static DataBridge *s_self = nullptr;
|
||||
DataBridge* DataBridge::self()
|
||||
|
||||
DataBridge *DataBridge::self()
|
||||
{
|
||||
return s_self;
|
||||
}
|
||||
|
@ -49,23 +54,29 @@ DataBridge::DataBridge(QObject *parent)
|
|||
: QObject(parent)
|
||||
{
|
||||
s_self = this;
|
||||
auto *ddm = waylandServer()->internalDataDeviceManager();
|
||||
auto *seat = waylandServer()->internalSeat();
|
||||
m_dd = ddm->getDataDevice(seat, this);
|
||||
|
||||
DataDeviceManager *dataDeviceManager = waylandServer()->internalDataDeviceManager();
|
||||
Seat *seat = waylandServer()->internalSeat();
|
||||
m_dataDevice = dataDeviceManager->getDataDevice(seat, this);
|
||||
waylandServer()->dispatch();
|
||||
|
||||
const auto *ddmi = waylandServer()->dataDeviceManager();
|
||||
const DataDeviceManagerInterface *dataDeviceManagerInterface =
|
||||
waylandServer()->dataDeviceManager();
|
||||
|
||||
auto *dc = new QMetaObject::Connection();
|
||||
*dc = connect(ddmi, &KWayland::Server::DataDeviceManagerInterface::dataDeviceCreated, this,
|
||||
[this, dc](KWayland::Server::DataDeviceInterface *ddi) {
|
||||
if (m_ddi || ddi->client() != waylandServer()->internalConnection()) {
|
||||
return;
|
||||
}
|
||||
QObject::disconnect(*dc);
|
||||
delete dc;
|
||||
m_ddi = ddi;
|
||||
init();
|
||||
}
|
||||
*dc = connect(dataDeviceManagerInterface, &DataDeviceManagerInterface::dataDeviceCreated, this,
|
||||
[this, dc](DataDeviceInterface *dataDeviceInterface) {
|
||||
if (m_dataDeviceInterface) {
|
||||
return;
|
||||
}
|
||||
if (dataDeviceInterface->client() != waylandServer()->internalConnection()) {
|
||||
return;
|
||||
}
|
||||
QObject::disconnect(*dc);
|
||||
delete dc;
|
||||
m_dataDeviceInterface = dataDeviceInterface;
|
||||
init();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -97,20 +108,22 @@ bool DataBridge::filterEvent(xcb_generic_event_t *event)
|
|||
|
||||
bool DataBridge::handleXfixesNotify(xcb_xfixes_selection_notify_event_t *event)
|
||||
{
|
||||
auto getSelection = [this](xcb_atom_t atom) -> Selection* {
|
||||
if (atom == atoms->clipboard) {
|
||||
return m_clipboard;
|
||||
}
|
||||
if (atom == atoms->xdnd_selection) {
|
||||
return m_dnd;
|
||||
}
|
||||
return nullptr;
|
||||
};
|
||||
auto *sel = getSelection(event->selection);
|
||||
return sel && sel->handleXfixesNotify(event);
|
||||
Selection *selection = nullptr;
|
||||
|
||||
if (event->selection == atoms->clipboard) {
|
||||
selection = m_clipboard;
|
||||
} else if (event->selection == atoms->xdnd_selection) {
|
||||
selection = m_dnd;
|
||||
}
|
||||
|
||||
if (!selection) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return selection->handleXfixesNotify(event);
|
||||
}
|
||||
|
||||
DragEventReply DataBridge::dragMoveFilter(Toplevel *target, QPoint pos)
|
||||
DragEventReply DataBridge::dragMoveFilter(Toplevel *target, const QPoint &pos)
|
||||
{
|
||||
if (!m_dnd) {
|
||||
return DragEventReply::Wayland;
|
||||
|
@ -118,5 +131,5 @@ DragEventReply DataBridge::dragMoveFilter(Toplevel *target, QPoint pos)
|
|||
return m_dnd->dragMoveFilter(target, pos);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
|
|
@ -27,11 +27,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
class xcb_xfixes_selection_notify_event_t;
|
||||
|
||||
namespace KWayland {
|
||||
namespace Client {
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class DataDevice;
|
||||
}
|
||||
namespace Server {
|
||||
namespace Server
|
||||
{
|
||||
class DataDeviceInterface;
|
||||
class SurfaceInterface;
|
||||
}
|
||||
|
@ -48,33 +51,34 @@ class Clipboard;
|
|||
class Dnd;
|
||||
enum class DragEventReply;
|
||||
|
||||
/*
|
||||
/**
|
||||
* Interface class for all data sharing in the context of X selections
|
||||
* and Wayland's internal mechanism.
|
||||
*
|
||||
* Exists only once per Xwayland session.
|
||||
*/
|
||||
**/
|
||||
class DataBridge : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static DataBridge* self();
|
||||
static DataBridge *self();
|
||||
|
||||
explicit DataBridge(QObject *parent = nullptr);
|
||||
~DataBridge();
|
||||
|
||||
bool filterEvent(xcb_generic_event_t *event);
|
||||
DragEventReply dragMoveFilter(Toplevel *target, QPoint pos);
|
||||
DragEventReply dragMoveFilter(Toplevel *target, const QPoint &pos);
|
||||
|
||||
KWayland::Client::DataDevice *dataDevice() const
|
||||
{
|
||||
return m_dd;
|
||||
return m_dataDevice;
|
||||
}
|
||||
KWayland::Server::DataDeviceInterface *dataDeviceIface() const
|
||||
{
|
||||
return m_ddi;
|
||||
return m_dataDeviceInterface;
|
||||
}
|
||||
Dnd* dnd() const
|
||||
Dnd *dnd() const
|
||||
{
|
||||
return m_dnd;
|
||||
}
|
||||
|
@ -88,11 +92,13 @@ private:
|
|||
Dnd *m_dnd = nullptr;
|
||||
|
||||
/* Internal data device interface */
|
||||
KWayland::Client::DataDevice *m_dd = nullptr;
|
||||
KWayland::Server::DataDeviceInterface *m_ddi = nullptr;
|
||||
KWayland::Client::DataDevice *m_dataDevice = nullptr;
|
||||
KWayland::Server::DataDeviceInterface *m_dataDeviceInterface = nullptr;
|
||||
|
||||
Q_DISABLE_COPY(DataBridge)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
||||
#endif
|
||||
|
|
44
xwl/dnd.cpp
44
xwl/dnd.cpp
|
@ -20,21 +20,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "dnd.h"
|
||||
|
||||
#include "databridge.h"
|
||||
#include "selection_source.h"
|
||||
#include "drag_wl.h"
|
||||
#include "drag_x.h"
|
||||
#include "selection_source.h"
|
||||
|
||||
#include "abstract_client.h"
|
||||
#include "atoms.h"
|
||||
#include "wayland_server.h"
|
||||
#include "workspace.h"
|
||||
#include "xwayland.h"
|
||||
#include "abstract_client.h"
|
||||
|
||||
#include <KWayland/Client/compositor.h>
|
||||
#include <KWayland/Client/surface.h>
|
||||
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
#include <KWayland/Server/compositor_interface.h>
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
|
||||
#include <QMouseEvent>
|
||||
|
||||
|
@ -55,7 +55,7 @@ uint32_t Dnd::version()
|
|||
Dnd::Dnd(xcb_atom_t atom, QObject *parent)
|
||||
: Selection(atom, parent)
|
||||
{
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
|
||||
const uint32_t dndValues[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
|
||||
XCB_EVENT_MASK_PROPERTY_CHANGE };
|
||||
|
@ -124,7 +124,7 @@ Dnd::Dnd(xcb_atom_t atom, QObject *parent)
|
|||
|
||||
void Dnd::doHandleXfixesNotify(xcb_xfixes_selection_notify_event_t *event)
|
||||
{
|
||||
if (qobject_cast<XToWlDrag*>(m_currentDrag)) {
|
||||
if (qobject_cast<XToWlDrag *>(m_currentDrag)) {
|
||||
// X drag is in progress, rogue X client took over the selection.
|
||||
return;
|
||||
}
|
||||
|
@ -134,7 +134,7 @@ void Dnd::doHandleXfixesNotify(xcb_xfixes_selection_notify_event_t *event)
|
|||
ownSelection(true);
|
||||
return;
|
||||
}
|
||||
createX11Source(NULL);
|
||||
createX11Source(nullptr);
|
||||
const auto *seat = waylandServer()->seat();
|
||||
auto *originSurface = seat->focusedPointerSurface();
|
||||
if (!originSurface) {
|
||||
|
@ -151,15 +151,15 @@ void Dnd::doHandleXfixesNotify(xcb_xfixes_selection_notify_event_t *event)
|
|||
return;
|
||||
}
|
||||
createX11Source(event);
|
||||
auto *xSrc = x11Source();
|
||||
if (!xSrc) {
|
||||
X11Source *source = x11Source();
|
||||
if (!source) {
|
||||
return;
|
||||
}
|
||||
DataBridge::self()->dataDeviceIface()->updateProxy(originSurface);
|
||||
m_currentDrag = new XToWlDrag(xSrc);
|
||||
m_currentDrag = new XToWlDrag(source);
|
||||
}
|
||||
|
||||
void Dnd::x11OffersChanged(const QVector<QString> &added, const QVector<QString> &removed)
|
||||
void Dnd::x11OffersChanged(const QStringList &added, const QStringList &removed)
|
||||
{
|
||||
Q_UNUSED(added);
|
||||
Q_UNUSED(removed);
|
||||
|
@ -168,7 +168,7 @@ void Dnd::x11OffersChanged(const QVector<QString> &added, const QVector<QString>
|
|||
|
||||
bool Dnd::handleClientMessage(xcb_client_message_event_t *event)
|
||||
{
|
||||
for (auto *drag : m_oldDrags) {
|
||||
for (Drag *drag : m_oldDrags) {
|
||||
if (drag->handleClientMessage(event)) {
|
||||
return true;
|
||||
}
|
||||
|
@ -179,9 +179,9 @@ bool Dnd::handleClientMessage(xcb_client_message_event_t *event)
|
|||
return false;
|
||||
}
|
||||
|
||||
DragEventReply Dnd::dragMoveFilter(Toplevel *target, QPoint pos)
|
||||
DragEventReply Dnd::dragMoveFilter(Toplevel *target, const QPoint &pos)
|
||||
{
|
||||
// this filter only is used when a drag is in process
|
||||
// This filter only is used when a drag is in process.
|
||||
Q_ASSERT(m_currentDrag);
|
||||
return m_currentDrag->moveFilter(target, pos);
|
||||
}
|
||||
|
@ -190,24 +190,26 @@ void Dnd::startDrag()
|
|||
{
|
||||
auto *ddi = waylandServer()->seat()->dragSource();
|
||||
if (ddi == DataBridge::self()->dataDeviceIface()) {
|
||||
// X to Wl drag, started by us, is in progress
|
||||
// X to Wl drag, started by us, is in progress.
|
||||
Q_ASSERT(m_currentDrag);
|
||||
return;
|
||||
}
|
||||
// there can only ever be one Wl native drag at the same time
|
||||
|
||||
// There can only ever be one Wl native drag at the same time.
|
||||
Q_ASSERT(!m_currentDrag);
|
||||
|
||||
// new Wl to X drag, init drag and Wl source
|
||||
// New Wl to X drag, init drag and Wl source.
|
||||
m_currentDrag = new WlToXDrag();
|
||||
auto *wls = new WlSource(this, ddi);
|
||||
wls->setDataSourceIface(ddi->dragSource());
|
||||
setWlSource(wls);
|
||||
auto source = new WlSource(this, ddi);
|
||||
source->setDataSourceIface(ddi->dragSource());
|
||||
setWlSource(source);
|
||||
ownSelection(true);
|
||||
}
|
||||
|
||||
void Dnd::endDrag()
|
||||
{
|
||||
Q_ASSERT(m_currentDrag);
|
||||
|
||||
if (m_currentDrag->end()) {
|
||||
delete m_currentDrag;
|
||||
} else {
|
||||
|
@ -223,5 +225,5 @@ void Dnd::clearOldDrag(Drag *drag)
|
|||
delete drag;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
|
15
xwl/dnd.h
15
xwl/dnd.h
|
@ -48,20 +48,21 @@ enum class DragEventReply;
|
|||
/**
|
||||
* Represents the drag and drop mechanism, on X side this is the XDND protocol.
|
||||
* For more information on XDND see: https://johnlindal.wixsite.com/xdnd
|
||||
*/
|
||||
**/
|
||||
class Dnd : public Selection
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Dnd(xcb_atom_t atom, QObject *parent);
|
||||
|
||||
static uint32_t version();
|
||||
|
||||
void doHandleXfixesNotify(xcb_xfixes_selection_notify_event_t *event) override;
|
||||
void x11OffersChanged(const QVector<QString> &added, const QVector<QString> &removed) override;
|
||||
void x11OffersChanged(const QStringList &added, const QStringList &removed) override;
|
||||
bool handleClientMessage(xcb_client_message_event_t *event) override;
|
||||
|
||||
DragEventReply dragMoveFilter(Toplevel *target, QPoint pos);
|
||||
DragEventReply dragMoveFilter(Toplevel *target, const QPoint &pos);
|
||||
|
||||
KWayland::Server::SurfaceInterface *surfaceIface() const {
|
||||
return m_surfaceIface;
|
||||
|
@ -78,13 +79,15 @@ private:
|
|||
|
||||
// active drag or null when no drag active
|
||||
Drag *m_currentDrag = nullptr;
|
||||
QVector<Drag*> m_oldDrags;
|
||||
QVector<Drag *> m_oldDrags;
|
||||
|
||||
KWayland::Client::Surface *m_surface;
|
||||
KWayland::Server::SurfaceInterface *m_surfaceIface = nullptr;
|
||||
|
||||
Q_DISABLE_COPY(Dnd)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
||||
#endif
|
||||
|
|
15
xwl/drag.cpp
15
xwl/drag.cpp
|
@ -26,6 +26,15 @@ namespace KWin
|
|||
namespace Xwl
|
||||
{
|
||||
|
||||
Drag::Drag(QObject *parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
}
|
||||
|
||||
Drag::~Drag()
|
||||
{
|
||||
}
|
||||
|
||||
void Drag::sendClientMessage(xcb_window_t target, xcb_atom_t type, xcb_client_message_data_t *data)
|
||||
{
|
||||
xcb_client_message_event_t event {
|
||||
|
@ -37,7 +46,7 @@ void Drag::sendClientMessage(xcb_window_t target, xcb_atom_t type, xcb_client_me
|
|||
*data, // data
|
||||
};
|
||||
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_send_event(xcbConn,
|
||||
0,
|
||||
target,
|
||||
|
@ -74,5 +83,5 @@ xcb_atom_t Drag::clientActionToAtom(DnDAction action)
|
|||
return XCB_ATOM_NONE;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
|
16
xwl/drag.h
16
xwl/drag.h
|
@ -38,26 +38,32 @@ using DnDAction = KWayland::Client::DataDeviceManager::DnDAction;
|
|||
|
||||
/**
|
||||
* An ongoing drag operation.
|
||||
*/
|
||||
**/
|
||||
class Drag : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit Drag(QObject *parent = nullptr);
|
||||
~Drag() override;
|
||||
|
||||
static void sendClientMessage(xcb_window_t target, xcb_atom_t type, xcb_client_message_data_t *data);
|
||||
static DnDAction atomToClientAction(xcb_atom_t atom);
|
||||
static xcb_atom_t clientActionToAtom(DnDAction action);
|
||||
|
||||
virtual ~Drag() = default;
|
||||
virtual bool handleClientMessage(xcb_client_message_event_t *event) = 0;
|
||||
virtual DragEventReply moveFilter(Toplevel *target, QPoint pos) = 0;
|
||||
virtual DragEventReply moveFilter(Toplevel *target, const QPoint &pos) = 0;
|
||||
|
||||
virtual bool end() = 0;
|
||||
|
||||
Q_SIGNALS:
|
||||
void finish(Drag *self);
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(Drag)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
||||
#endif
|
||||
|
|
|
@ -19,22 +19,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
*********************************************************************/
|
||||
#include "drag_wl.h"
|
||||
|
||||
#include "xwayland.h"
|
||||
#include "databridge.h"
|
||||
#include "dnd.h"
|
||||
#include "xwayland.h"
|
||||
|
||||
#include "atoms.h"
|
||||
#include "client.h"
|
||||
#include "wayland_server.h"
|
||||
#include "workspace.h"
|
||||
#include "client.h"
|
||||
|
||||
#include <KWayland/Client/datadevice.h>
|
||||
#include <KWayland/Client/datasource.h>
|
||||
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
#include <KWayland/Server/surface_interface.h>
|
||||
#include <KWayland/Server/datadevice_interface.h>
|
||||
#include <KWayland/Server/datasource_interface.h>
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
#include <KWayland/Server/surface_interface.h>
|
||||
|
||||
#include <QMouseEvent>
|
||||
#include <QTimer>
|
||||
|
@ -49,9 +49,9 @@ WlToXDrag::WlToXDrag()
|
|||
m_dsi = waylandServer()->seat()->dragSource()->dragSource();
|
||||
}
|
||||
|
||||
DragEventReply WlToXDrag::moveFilter(Toplevel *target, QPoint pos)
|
||||
DragEventReply WlToXDrag::moveFilter(Toplevel *target, const QPoint &pos)
|
||||
{
|
||||
AbstractClient *ac = qobject_cast<AbstractClient*>(target);
|
||||
AbstractClient *ac = qobject_cast<AbstractClient *>(target);
|
||||
auto *seat = waylandServer()->seat();
|
||||
if (m_visit && m_visit->target() == ac) {
|
||||
// no target change
|
||||
|
@ -64,7 +64,7 @@ DragEventReply WlToXDrag::moveFilter(Toplevel *target, QPoint pos)
|
|||
delete m_visit;
|
||||
m_visit = nullptr;
|
||||
}
|
||||
if (!qobject_cast<KWin::Client *>(ac)) {
|
||||
if (!qobject_cast<Client *>(ac)) {
|
||||
// no target or wayland native target,
|
||||
// handled by input code directly
|
||||
return DragEventReply::Wayland;
|
||||
|
@ -107,15 +107,15 @@ Xvisit::Xvisit(WlToXDrag *drag, AbstractClient *target)
|
|||
m_target(target)
|
||||
{
|
||||
// first check supported DND version
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_get_property_cookie_t cookie = xcb_get_property(xcbConn,
|
||||
0,
|
||||
m_target->window(),
|
||||
atoms->xdnd_aware,
|
||||
XCB_GET_PROPERTY_TYPE_ANY,
|
||||
0, 1);
|
||||
auto *reply = xcb_get_property_reply(xcbConn, cookie, NULL);
|
||||
if (reply == NULL) {
|
||||
auto *reply = xcb_get_property_reply(xcbConn, cookie, nullptr);
|
||||
if (!reply) {
|
||||
doFinish();
|
||||
return;
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ Xvisit::Xvisit(WlToXDrag *drag, AbstractClient *target)
|
|||
free(reply);
|
||||
return;
|
||||
}
|
||||
xcb_atom_t *value = static_cast<xcb_atom_t*>(xcb_get_property_value(reply));
|
||||
xcb_atom_t *value = static_cast<xcb_atom_t *>(xcb_get_property_value(reply));
|
||||
m_version = qMin(*value, Dnd::version());
|
||||
if (m_version < 1) {
|
||||
// minimal version we accept is 1
|
||||
|
@ -136,9 +136,9 @@ Xvisit::Xvisit(WlToXDrag *drag, AbstractClient *target)
|
|||
|
||||
const auto *dd = DataBridge::self()->dataDevice();
|
||||
// proxy drop
|
||||
m_enterCon = connect(dd, &KWayland::Client::DataDevice::dragEntered,
|
||||
m_enterConnection = connect(dd, &KWayland::Client::DataDevice::dragEntered,
|
||||
this, &Xvisit::receiveOffer);
|
||||
m_dropCon = connect(dd, &KWayland::Client::DataDevice::dropped,
|
||||
m_dropConnection = connect(dd, &KWayland::Client::DataDevice::dropped,
|
||||
this, &Xvisit::drop);
|
||||
}
|
||||
|
||||
|
@ -152,9 +152,9 @@ bool Xvisit::handleClientMessage(xcb_client_message_event_t *event)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool Xvisit::handleStatus(xcb_client_message_event_t *ev)
|
||||
bool Xvisit::handleStatus(xcb_client_message_event_t *event)
|
||||
{
|
||||
xcb_client_message_data_t *data = &ev->data;
|
||||
xcb_client_message_data_t *data = &event->data;
|
||||
if (data->data32[0] != m_target->window()) {
|
||||
// wrong target window
|
||||
return false;
|
||||
|
@ -186,9 +186,9 @@ bool Xvisit::handleStatus(xcb_client_message_event_t *ev)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool Xvisit::handleFinished(xcb_client_message_event_t *ev)
|
||||
bool Xvisit::handleFinished(xcb_client_message_event_t *event)
|
||||
{
|
||||
xcb_client_message_data_t *data = &ev->data;
|
||||
xcb_client_message_data_t *data = &event->data;
|
||||
|
||||
if (data->data32[0] != m_target->window()) {
|
||||
// different target window
|
||||
|
@ -264,7 +264,7 @@ void Xvisit::receiveOffer()
|
|||
Q_ASSERT(!m_dataOffer.isNull());
|
||||
|
||||
retrieveSupportedActions();
|
||||
m_actionCon = connect(m_dataOffer, &KWayland::Client::DataOffer::sourceDragAndDropActionsChanged,
|
||||
m_actionConnection = connect(m_dataOffer, &KWayland::Client::DataOffer::sourceDragAndDropActionsChanged,
|
||||
this, &Xvisit::retrieveSupportedActions);
|
||||
enter();
|
||||
}
|
||||
|
@ -277,7 +277,7 @@ void Xvisit::enter()
|
|||
sendPosition(waylandServer()->seat()->pointerPos());
|
||||
|
||||
// proxy future pointer position changes
|
||||
m_motionCon = connect(waylandServer()->seat(),
|
||||
m_motionConnection = connect(waylandServer()->seat(),
|
||||
&KWayland::Server::SeatInterface::pointerPosChanged,
|
||||
this, &Xvisit::sendPosition);
|
||||
}
|
||||
|
@ -431,16 +431,16 @@ void Xvisit::stopConnections()
|
|||
{
|
||||
// final outcome has been determined from Wayland side
|
||||
// no more updates needed
|
||||
disconnect(m_enterCon);
|
||||
m_enterCon = QMetaObject::Connection();
|
||||
disconnect(m_dropCon);
|
||||
m_dropCon = QMetaObject::Connection();
|
||||
disconnect(m_enterConnection);
|
||||
m_enterConnection = QMetaObject::Connection();
|
||||
disconnect(m_dropConnection);
|
||||
m_dropConnection = QMetaObject::Connection();
|
||||
|
||||
disconnect(m_motionCon);
|
||||
m_motionCon = QMetaObject::Connection();
|
||||
disconnect(m_actionCon);
|
||||
m_actionCon = QMetaObject::Connection();
|
||||
disconnect(m_motionConnection);
|
||||
m_motionConnection = QMetaObject::Connection();
|
||||
disconnect(m_actionConnection);
|
||||
m_actionConnection = QMetaObject::Connection();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
|
|
@ -58,10 +58,11 @@ using DnDActions = KWayland::Client::DataDeviceManager::DnDActions;
|
|||
class WlToXDrag : public Drag
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit WlToXDrag();
|
||||
|
||||
DragEventReply moveFilter(Toplevel *target, QPoint pos) override;
|
||||
DragEventReply moveFilter(Toplevel *target, const QPoint &pos) override;
|
||||
bool handleClientMessage(xcb_client_message_event_t *event) override;
|
||||
|
||||
bool end() override;
|
||||
|
@ -73,20 +74,23 @@ public:
|
|||
private:
|
||||
KWayland::Server::DataSourceInterface *m_dsi;
|
||||
Xvisit *m_visit = nullptr;
|
||||
|
||||
Q_DISABLE_COPY(WlToXDrag)
|
||||
};
|
||||
|
||||
// visit to an X window
|
||||
class Xvisit : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// TODO: handle ask action
|
||||
|
||||
Xvisit(WlToXDrag *drag, AbstractClient *target);
|
||||
|
||||
bool handleClientMessage(xcb_client_message_event_t *event);
|
||||
bool handleStatus(xcb_client_message_event_t *ev);
|
||||
bool handleFinished(xcb_client_message_event_t *ev);
|
||||
bool handleStatus(xcb_client_message_event_t *event);
|
||||
bool handleFinished(xcb_client_message_event_t *event);
|
||||
|
||||
void sendPosition(const QPointF &globalPos);
|
||||
void leave();
|
||||
|
@ -123,10 +127,10 @@ private:
|
|||
AbstractClient *m_target;
|
||||
uint32_t m_version = 0;
|
||||
|
||||
QMetaObject::Connection m_enterCon;
|
||||
QMetaObject::Connection m_motionCon;
|
||||
QMetaObject::Connection m_actionCon;
|
||||
QMetaObject::Connection m_dropCon;
|
||||
QMetaObject::Connection m_enterConnection;
|
||||
QMetaObject::Connection m_motionConnection;
|
||||
QMetaObject::Connection m_actionConnection;
|
||||
QMetaObject::Connection m_dropConnection;
|
||||
|
||||
struct {
|
||||
bool pending = false;
|
||||
|
@ -152,9 +156,11 @@ private:
|
|||
} m_state;
|
||||
|
||||
bool m_accepts = false;
|
||||
|
||||
Q_DISABLE_COPY(Xvisit)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
||||
#endif
|
||||
|
|
|
@ -39,8 +39,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <QMouseEvent>
|
||||
#include <QTimer>
|
||||
|
||||
namespace KWin {
|
||||
namespace Xwl {
|
||||
namespace KWin
|
||||
{
|
||||
namespace Xwl
|
||||
{
|
||||
|
||||
static QStringList atomToMimeTypes(xcb_atom_t atom)
|
||||
{
|
||||
|
@ -61,7 +63,7 @@ static QStringList atomToMimeTypes(xcb_atom_t atom)
|
|||
}
|
||||
|
||||
XToWlDrag::XToWlDrag(X11Source *source)
|
||||
: m_src(source)
|
||||
: m_source(source)
|
||||
{
|
||||
connect(DataBridge::self()->dnd(), &Dnd::transferFinished, this, [this](xcb_timestamp_t eventTime) {
|
||||
// we use this mechanism, because the finished call is not
|
||||
|
@ -80,7 +82,7 @@ XToWlDrag::XToWlDrag(X11Source *source)
|
|||
connect(source, &X11Source::transferReady, this, [this](xcb_atom_t target, qint32 fd) {
|
||||
Q_UNUSED(target);
|
||||
Q_UNUSED(fd);
|
||||
m_dataRequests << QPair<xcb_timestamp_t, bool>(m_src->timestamp(), false);
|
||||
m_dataRequests << QPair<xcb_timestamp_t, bool>(m_source->timestamp(), false);
|
||||
});
|
||||
auto *ddm = waylandServer()->internalDataDeviceManager();
|
||||
m_dataSource = ddm->createDataSource(this);
|
||||
|
@ -142,7 +144,7 @@ XToWlDrag::~XToWlDrag()
|
|||
m_dataSource = nullptr;
|
||||
}
|
||||
|
||||
DragEventReply XToWlDrag::moveFilter(Toplevel *target, QPoint pos)
|
||||
DragEventReply XToWlDrag::moveFilter(Toplevel *target, const QPoint &pos)
|
||||
{
|
||||
Q_UNUSED(pos);
|
||||
|
||||
|
@ -220,7 +222,7 @@ DnDAction XToWlDrag::selectedDragAndDropAction()
|
|||
|
||||
void XToWlDrag::setOffers(const Mimes &offers)
|
||||
{
|
||||
m_src->setOffers(offers);
|
||||
m_source->setOffers(offers);
|
||||
if (offers.isEmpty()) {
|
||||
// There are no offers, so just directly set the drag target,
|
||||
// no transfer possible anyways.
|
||||
|
@ -288,7 +290,7 @@ WlVisit::WlVisit(AbstractClient *target, XToWlDrag *drag)
|
|||
m_target(target),
|
||||
m_drag(drag)
|
||||
{
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
|
||||
m_window = xcb_generate_id(xcbConn);
|
||||
DataBridge::self()->dnd()->overwriteRequestorWindow(m_window);
|
||||
|
@ -325,7 +327,7 @@ WlVisit::WlVisit(AbstractClient *target, XToWlDrag *drag)
|
|||
|
||||
WlVisit::~WlVisit()
|
||||
{
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_destroy_window(xcbConn, m_window);
|
||||
xcb_flush(xcbConn);
|
||||
}
|
||||
|
@ -362,7 +364,7 @@ static bool hasMimeName(const Mimes &mimes, const QString &name)
|
|||
[name](const Mime &m) { return m.first == name; });
|
||||
}
|
||||
|
||||
bool WlVisit::handleEnter(xcb_client_message_event_t *ev)
|
||||
bool WlVisit::handleEnter(xcb_client_message_event_t *event)
|
||||
{
|
||||
if (m_entered) {
|
||||
// a drag already entered
|
||||
|
@ -370,7 +372,7 @@ bool WlVisit::handleEnter(xcb_client_message_event_t *ev)
|
|||
}
|
||||
m_entered = true;
|
||||
|
||||
xcb_client_message_data_t *data = &ev->data;
|
||||
xcb_client_message_data_t *data = &event->data;
|
||||
m_srcWindow = data->data32[0];
|
||||
m_version = data->data32[1] >> 24;
|
||||
|
||||
|
@ -398,7 +400,7 @@ bool WlVisit::handleEnter(xcb_client_message_event_t *ev)
|
|||
|
||||
void WlVisit::getMimesFromWinProperty(Mimes &offers)
|
||||
{
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
auto cookie = xcb_get_property(xcbConn,
|
||||
0,
|
||||
m_srcWindow,
|
||||
|
@ -416,10 +418,10 @@ void WlVisit::getMimesFromWinProperty(Mimes &offers)
|
|||
return;
|
||||
}
|
||||
|
||||
xcb_atom_t *mimeAtoms = static_cast<xcb_atom_t*>(xcb_get_property_value(reply));
|
||||
xcb_atom_t *mimeAtoms = static_cast<xcb_atom_t *>(xcb_get_property_value(reply));
|
||||
for (size_t i = 0; i < reply->value_len; ++i) {
|
||||
const auto mimeStrings = atomToMimeTypes(mimeAtoms[i]);
|
||||
for (const auto mime : mimeStrings ) {
|
||||
for (const auto mime : mimeStrings) {
|
||||
if (!hasMimeName(offers, mime)) {
|
||||
offers << Mime(mime, mimeAtoms[i]);
|
||||
}
|
||||
|
@ -428,9 +430,9 @@ void WlVisit::getMimesFromWinProperty(Mimes &offers)
|
|||
free(reply);
|
||||
}
|
||||
|
||||
bool WlVisit::handlePosition(xcb_client_message_event_t *ev)
|
||||
bool WlVisit::handlePosition(xcb_client_message_event_t *event)
|
||||
{
|
||||
xcb_client_message_data_t *data = &ev->data;
|
||||
xcb_client_message_data_t *data = &event->data;
|
||||
m_srcWindow = data->data32[0];
|
||||
|
||||
if (!m_target) {
|
||||
|
@ -466,11 +468,11 @@ bool WlVisit::handlePosition(xcb_client_message_event_t *ev)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool WlVisit::handleDrop(xcb_client_message_event_t *ev)
|
||||
bool WlVisit::handleDrop(xcb_client_message_event_t *event)
|
||||
{
|
||||
m_dropHandled = true;
|
||||
|
||||
xcb_client_message_data_t *data = &ev->data;
|
||||
xcb_client_message_data_t *data = &event->data;
|
||||
m_srcWindow = data->data32[0];
|
||||
const xcb_timestamp_t timestamp = data->data32[2];
|
||||
m_drag->x11Source()->setTimestamp(timestamp);
|
||||
|
@ -488,10 +490,10 @@ void WlVisit::doFinish()
|
|||
Q_EMIT finish(this);
|
||||
}
|
||||
|
||||
bool WlVisit::handleLeave(xcb_client_message_event_t *ev)
|
||||
bool WlVisit::handleLeave(xcb_client_message_event_t *event)
|
||||
{
|
||||
m_entered = false;
|
||||
xcb_client_message_data_t *data = &ev->data;
|
||||
xcb_client_message_data_t *data = &event->data;
|
||||
m_srcWindow = data->data32[0];
|
||||
doFinish();
|
||||
return true;
|
||||
|
@ -536,7 +538,7 @@ void WlVisit::unmapProxyWindow()
|
|||
if (!m_mapped) {
|
||||
return;
|
||||
}
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_unmap_window(xcbConn, m_window);
|
||||
workspace()->removeManualOverlay(m_window);
|
||||
workspace()->updateStackingOrder(true);
|
||||
|
@ -544,5 +546,5 @@ void WlVisit::unmapProxyWindow()
|
|||
m_mapped = false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
|
33
xwl/drag_x.h
33
xwl/drag_x.h
|
@ -31,8 +31,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <QPointer>
|
||||
#include <QVector>
|
||||
|
||||
namespace KWayland {
|
||||
namespace Client {
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class DataSource;
|
||||
}
|
||||
}
|
||||
|
@ -53,11 +55,12 @@ using Mimes = QVector<QPair<QString, xcb_atom_t> >;
|
|||
class XToWlDrag : public Drag
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit XToWlDrag(X11Source *source);
|
||||
~XToWlDrag() override;
|
||||
|
||||
DragEventReply moveFilter(Toplevel *target, QPoint pos) override;
|
||||
DragEventReply moveFilter(Toplevel *target, const QPoint &pos) override;
|
||||
bool handleClientMessage(xcb_client_message_event_t *event) override;
|
||||
|
||||
void setDragAndDropAction(DnDAction action);
|
||||
|
@ -66,8 +69,8 @@ public:
|
|||
bool end() override {
|
||||
return false;
|
||||
}
|
||||
X11Source* x11Source() const {
|
||||
return m_src;
|
||||
X11Source *x11Source() const {
|
||||
return m_source;
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -82,19 +85,22 @@ private:
|
|||
Mimes m_offers;
|
||||
Mimes m_offersPending;
|
||||
|
||||
X11Source *m_src;
|
||||
X11Source *m_source;
|
||||
QVector<QPair<xcb_timestamp_t, bool> > m_dataRequests;
|
||||
|
||||
WlVisit *m_visit = nullptr;
|
||||
QVector<WlVisit*> m_oldVisits;
|
||||
QVector<WlVisit *> m_oldVisits;
|
||||
|
||||
bool m_performed = false;
|
||||
DnDAction m_lastSelectedDragAndDropAction = DnDAction::None;
|
||||
|
||||
Q_DISABLE_COPY(XToWlDrag)
|
||||
};
|
||||
|
||||
class WlVisit : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WlVisit(AbstractClient *target, XToWlDrag *drag);
|
||||
~WlVisit();
|
||||
|
@ -124,10 +130,10 @@ Q_SIGNALS:
|
|||
void finish(WlVisit *self);
|
||||
|
||||
private:
|
||||
bool handleEnter(xcb_client_message_event_t *ev);
|
||||
bool handlePosition(xcb_client_message_event_t *ev);
|
||||
bool handleDrop(xcb_client_message_event_t *ev);
|
||||
bool handleLeave(xcb_client_message_event_t *ev);
|
||||
bool handleEnter(xcb_client_message_event_t *event);
|
||||
bool handlePosition(xcb_client_message_event_t *event);
|
||||
bool handleDrop(xcb_client_message_event_t *event);
|
||||
bool handleLeave(xcb_client_message_event_t *event);
|
||||
|
||||
void sendStatus();
|
||||
|
||||
|
@ -154,9 +160,10 @@ private:
|
|||
bool m_dropHandled = false;
|
||||
bool m_finished = false;
|
||||
|
||||
Q_DISABLE_COPY(WlVisit)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
||||
#endif
|
||||
|
|
|
@ -23,24 +23,28 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "transfer.h"
|
||||
|
||||
#include "atoms.h"
|
||||
#include "workspace.h"
|
||||
#include "client.h"
|
||||
#include "workspace.h"
|
||||
|
||||
#include <xcb/xcb_event.h>
|
||||
#include <xcb/xfixes.h>
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
namespace KWin {
|
||||
namespace Xwl {
|
||||
namespace KWin
|
||||
{
|
||||
namespace Xwl
|
||||
{
|
||||
|
||||
xcb_atom_t Selection::mimeTypeToAtom(const QString &mimeType)
|
||||
{
|
||||
if (mimeType == QLatin1String("text/plain;charset=utf-8")) {
|
||||
return atoms->utf8_string;
|
||||
} else if (mimeType == QLatin1String("text/plain")) {
|
||||
}
|
||||
if (mimeType == QLatin1String("text/plain")) {
|
||||
return atoms->text;
|
||||
} else if (mimeType == QLatin1String("text/x-uri")) {
|
||||
}
|
||||
if (mimeType == QLatin1String("text/x-uri")) {
|
||||
return atoms->uri_list;
|
||||
}
|
||||
return mimeTypeToAtomLiteral(mimeType);
|
||||
|
@ -53,15 +57,15 @@ xcb_atom_t Selection::mimeTypeToAtomLiteral(const QString &mimeType)
|
|||
|
||||
QString Selection::atomName(xcb_atom_t atom)
|
||||
{
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_get_atom_name_cookie_t nameCookie = xcb_get_atom_name(xcbConn, atom);
|
||||
xcb_get_atom_name_reply_t *nameReply = xcb_get_atom_name_reply(xcbConn, nameCookie, NULL);
|
||||
if (nameReply == NULL) {
|
||||
xcb_get_atom_name_reply_t *nameReply = xcb_get_atom_name_reply(xcbConn, nameCookie, nullptr);
|
||||
if (!nameReply) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
size_t len = xcb_get_atom_name_name_length(nameReply);
|
||||
QString name = QString::fromLatin1(xcb_get_atom_name_name(nameReply), len);
|
||||
const size_t length = xcb_get_atom_name_name_length(nameReply);
|
||||
QString name = QString::fromLatin1(xcb_get_atom_name_name(nameReply), length);
|
||||
free(nameReply);
|
||||
return name;
|
||||
}
|
||||
|
@ -83,10 +87,10 @@ QStringList Selection::atomToMimeTypes(xcb_atom_t atom)
|
|||
}
|
||||
|
||||
Selection::Selection(xcb_atom_t atom, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_atom(atom)
|
||||
: QObject(parent)
|
||||
, m_atom(atom)
|
||||
{
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
m_window = xcb_generate_id(kwinApp()->x11Connection());
|
||||
m_requestorWindow = m_window;
|
||||
xcb_flush(xcbConn);
|
||||
|
@ -105,11 +109,11 @@ bool Selection::handleXfixesNotify(xcb_xfixes_selection_notify_event_t *event)
|
|||
m_disownPending = false;
|
||||
return true;
|
||||
}
|
||||
if (event->owner == m_window && m_wlSrc) {
|
||||
if (event->owner == m_window && m_waylandSource) {
|
||||
// When we claim a selection we must use XCB_TIME_CURRENT,
|
||||
// grab the actual timestamp here to answer TIMESTAMP requests
|
||||
// correctly
|
||||
m_wlSrc->setTimestamp(event->timestamp);
|
||||
m_waylandSource->setTimestamp(event->timestamp);
|
||||
m_timestamp = event->timestamp;
|
||||
return true;
|
||||
}
|
||||
|
@ -123,22 +127,22 @@ bool Selection::filterEvent(xcb_generic_event_t *event)
|
|||
{
|
||||
switch (event->response_type & XCB_EVENT_RESPONSE_TYPE_MASK) {
|
||||
case XCB_SELECTION_NOTIFY:
|
||||
if (handleSelNotify(reinterpret_cast<xcb_selection_notify_event_t*>(event))) {
|
||||
if (handleSelectionNotify(reinterpret_cast<xcb_selection_notify_event_t *>(event))) {
|
||||
return true;
|
||||
}
|
||||
Q_FALLTHROUGH();
|
||||
case XCB_PROPERTY_NOTIFY:
|
||||
if (handlePropNotify(reinterpret_cast<xcb_property_notify_event_t*>(event))) {
|
||||
if (handlePropertyNotify(reinterpret_cast<xcb_property_notify_event_t *>(event))) {
|
||||
return true;
|
||||
}
|
||||
Q_FALLTHROUGH();
|
||||
case XCB_SELECTION_REQUEST:
|
||||
if (handleSelRequest(reinterpret_cast<xcb_selection_request_event_t*>(event))) {
|
||||
if (handleSelectionRequest(reinterpret_cast<xcb_selection_request_event_t *>(event))) {
|
||||
return true;
|
||||
}
|
||||
Q_FALLTHROUGH();
|
||||
case XCB_CLIENT_MESSAGE:
|
||||
if (handleClientMessage(reinterpret_cast<xcb_client_message_event_t*>(event))) {
|
||||
if (handleClientMessage(reinterpret_cast<xcb_client_message_event_t *>(event))) {
|
||||
return true;
|
||||
}
|
||||
Q_FALLTHROUGH();
|
||||
|
@ -147,7 +151,7 @@ bool Selection::filterEvent(xcb_generic_event_t *event)
|
|||
}
|
||||
}
|
||||
|
||||
void Selection::sendSelNotify(xcb_selection_request_event_t *event, bool success)
|
||||
void Selection::sendSelectionNotify(xcb_selection_request_event_t *event, bool success)
|
||||
{
|
||||
xcb_selection_notify_event_t notify;
|
||||
notify.response_type = XCB_SELECTION_NOTIFY;
|
||||
|
@ -156,9 +160,9 @@ void Selection::sendSelNotify(xcb_selection_request_event_t *event, bool success
|
|||
notify.requestor = event->requestor;
|
||||
notify.selection = event->selection;
|
||||
notify.target = event->target;
|
||||
notify.property = success ? event->property : (xcb_atom_t)XCB_ATOM_NONE;
|
||||
notify.property = success ? event->property : xcb_atom_t(XCB_ATOM_NONE);
|
||||
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_send_event(xcbConn,
|
||||
0,
|
||||
event->requestor,
|
||||
|
@ -169,7 +173,7 @@ void Selection::sendSelNotify(xcb_selection_request_event_t *event, bool success
|
|||
|
||||
void Selection::registerXfixes()
|
||||
{
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
const uint32_t mask = XCB_XFIXES_SELECTION_EVENT_MASK_SET_SELECTION_OWNER |
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_WINDOW_DESTROY |
|
||||
XCB_XFIXES_SELECTION_EVENT_MASK_SELECTION_CLIENT_CLOSE;
|
||||
|
@ -180,36 +184,36 @@ void Selection::registerXfixes()
|
|||
xcb_flush(xcbConn);
|
||||
}
|
||||
|
||||
void Selection::setWlSource(WlSource *src)
|
||||
void Selection::setWlSource(WlSource *source)
|
||||
{
|
||||
delete m_wlSrc;
|
||||
delete m_xSrc;
|
||||
m_wlSrc = nullptr;
|
||||
m_xSrc = nullptr;
|
||||
if (src) {
|
||||
m_wlSrc = src;
|
||||
connect(src, &WlSource::transferReady, this, &Selection::startTransferToX);
|
||||
delete m_waylandSource;
|
||||
delete m_xSource;
|
||||
m_waylandSource = nullptr;
|
||||
m_xSource = nullptr;
|
||||
if (source) {
|
||||
m_waylandSource = source;
|
||||
connect(source, &WlSource::transferReady, this, &Selection::startTransferToX);
|
||||
}
|
||||
}
|
||||
|
||||
void Selection::createX11Source(xcb_xfixes_selection_notify_event_t *event)
|
||||
{
|
||||
delete m_wlSrc;
|
||||
delete m_xSrc;
|
||||
m_wlSrc = nullptr;
|
||||
m_xSrc = nullptr;
|
||||
delete m_waylandSource;
|
||||
delete m_xSource;
|
||||
m_waylandSource = nullptr;
|
||||
m_xSource = nullptr;
|
||||
if (!event || event->owner == XCB_WINDOW_NONE) {
|
||||
return;
|
||||
}
|
||||
m_xSrc = new X11Source(this, event);
|
||||
m_xSource = new X11Source(this, event);
|
||||
|
||||
connect(m_xSrc, &X11Source::offersChanged, this, &Selection::x11OffersChanged);
|
||||
connect(m_xSrc, &X11Source::transferReady, this, &Selection::startTransferToWayland);
|
||||
connect(m_xSource, &X11Source::offersChanged, this, &Selection::x11OffersChanged);
|
||||
connect(m_xSource, &X11Source::transferReady, this, &Selection::startTransferToWayland);
|
||||
}
|
||||
|
||||
void Selection::ownSelection(bool own)
|
||||
{
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
if (own) {
|
||||
xcb_set_selection_owner(xcbConn,
|
||||
m_window,
|
||||
|
@ -227,16 +231,16 @@ void Selection::ownSelection(bool own)
|
|||
|
||||
void Selection::overwriteRequestorWindow(xcb_window_t window)
|
||||
{
|
||||
Q_ASSERT(m_xSrc);
|
||||
Q_ASSERT(m_xSource);
|
||||
if (window == XCB_WINDOW_NONE) {
|
||||
// reset
|
||||
window = m_window;
|
||||
}
|
||||
m_requestorWindow = window;
|
||||
m_xSrc->setRequestor(window);
|
||||
m_xSource->setRequestor(window);
|
||||
}
|
||||
|
||||
bool Selection::handleSelRequest(xcb_selection_request_event_t *event)
|
||||
bool Selection::handleSelectionRequest(xcb_selection_request_event_t *event)
|
||||
{
|
||||
if (event->selection != m_atom) {
|
||||
return false;
|
||||
|
@ -245,44 +249,44 @@ bool Selection::handleSelRequest(xcb_selection_request_event_t *event)
|
|||
if (qobject_cast<Client *>(workspace()->activeClient()) == nullptr) {
|
||||
// Receiving Wayland selection not allowed when no Xwayland surface active
|
||||
// filter the event, but don't act upon it
|
||||
sendSelNotify(event, false);
|
||||
sendSelectionNotify(event, false);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_window != event->owner || !m_wlSrc) {
|
||||
if (m_window != event->owner || !m_waylandSource) {
|
||||
if (event->time < m_timestamp) {
|
||||
// cancel earlier attempts at receiving a selection
|
||||
// TODO: is this for sure without problems?
|
||||
sendSelNotify(event, false);
|
||||
sendSelectionNotify(event, false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return m_wlSrc->handleSelRequest(event);
|
||||
return m_waylandSource->handleSelectionRequest(event);
|
||||
}
|
||||
|
||||
bool Selection::handleSelNotify(xcb_selection_notify_event_t *event)
|
||||
bool Selection::handleSelectionNotify(xcb_selection_notify_event_t *event)
|
||||
{
|
||||
if (m_xSrc && m_xSrc->handleSelNotify(event)) {
|
||||
if (m_xSource && m_xSource->handleSelectionNotify(event)) {
|
||||
return true;
|
||||
}
|
||||
for (auto *transfer : m_xToWlTransfers) {
|
||||
if (transfer->handleSelNotify(event)) {
|
||||
for (TransferXtoWl *transfer : m_xToWlTransfers) {
|
||||
if (transfer->handleSelectionNotify(event)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Selection::handlePropNotify(xcb_property_notify_event_t *event)
|
||||
bool Selection::handlePropertyNotify(xcb_property_notify_event_t *event)
|
||||
{
|
||||
for (auto *transfer : m_xToWlTransfers) {
|
||||
if (transfer->handlePropNotify(event)) {
|
||||
for (TransferXtoWl *transfer : m_xToWlTransfers) {
|
||||
if (transfer->handlePropertyNotify(event)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (auto *transfer : m_wlToXTransfers) {
|
||||
if (transfer->handlePropNotify(event)) {
|
||||
for (TransferWltoX *transfer : m_wlToXTransfers) {
|
||||
if (transfer->handlePropertyNotify(event)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -292,7 +296,7 @@ bool Selection::handlePropNotify(xcb_property_notify_event_t *event)
|
|||
void Selection::startTransferToWayland(xcb_atom_t target, qint32 fd)
|
||||
{
|
||||
// create new x to wl data transfer object
|
||||
auto *transfer = new TransferXtoWl(m_atom, target, fd, m_xSrc->timestamp(), m_requestorWindow, this);
|
||||
auto *transfer = new TransferXtoWl(m_atom, target, fd, m_xSource->timestamp(), m_requestorWindow, this);
|
||||
m_xToWlTransfers << transfer;
|
||||
|
||||
connect(transfer, &TransferXtoWl::finished, this, [this, transfer]() {
|
||||
|
@ -309,7 +313,7 @@ void Selection::startTransferToX(xcb_selection_request_event_t *event, qint32 fd
|
|||
// create new wl to x data transfer object
|
||||
auto *transfer = new TransferWltoX(m_atom, event, fd, this);
|
||||
|
||||
connect(transfer, &TransferWltoX::selNotify, this, &Selection::sendSelNotify);
|
||||
connect(transfer, &TransferWltoX::selectionNotify, this, &Selection::sendSelectionNotify);
|
||||
connect(transfer, &TransferWltoX::finished, this, [this, transfer]() {
|
||||
Q_EMIT transferFinished(transfer->timestamp());
|
||||
|
||||
|
@ -355,13 +359,13 @@ void Selection::endTimeoutTransfersTimer()
|
|||
|
||||
void Selection::timeoutTransfers()
|
||||
{
|
||||
for (auto *transfer : m_xToWlTransfers) {
|
||||
for (TransferXtoWl *transfer : m_xToWlTransfers) {
|
||||
transfer->timeout();
|
||||
}
|
||||
for (auto *transfer : m_wlToXTransfers) {
|
||||
for (TransferWltoX *transfer : m_wlToXTransfers) {
|
||||
transfer->timeout();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
|
|
@ -38,7 +38,7 @@ class TransferXtoWl;
|
|||
class WlSource;
|
||||
class X11Source;
|
||||
|
||||
/*
|
||||
/**
|
||||
* Base class representing generic X selections and their respective
|
||||
* Wayland counter-parts.
|
||||
*
|
||||
|
@ -52,16 +52,17 @@ class X11Source;
|
|||
* Independently of each other the class holds the currently active
|
||||
* source instance and active transfers relative to the represented
|
||||
* selection.
|
||||
*/
|
||||
**/
|
||||
class Selection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static xcb_atom_t mimeTypeToAtom(const QString &mimeType);
|
||||
static xcb_atom_t mimeTypeToAtomLiteral(const QString &mimeType);
|
||||
static QStringList atomToMimeTypes(xcb_atom_t atom);
|
||||
static QString atomName(xcb_atom_t atom);
|
||||
static void sendSelNotify(xcb_selection_request_event_t *event, bool success);
|
||||
static void sendSelectionNotify(xcb_selection_request_event_t *event, bool success);
|
||||
|
||||
// on selection owner changes by X clients (Xwl -> Wl)
|
||||
bool handleXfixesNotify(xcb_xfixes_selection_notify_event_t *event);
|
||||
|
@ -83,20 +84,20 @@ protected:
|
|||
void registerXfixes();
|
||||
|
||||
virtual void doHandleXfixesNotify(xcb_xfixes_selection_notify_event_t *event) = 0;
|
||||
virtual void x11OffersChanged(const QVector<QString> &added, const QVector<QString> &removed) = 0;
|
||||
virtual void x11OffersChanged(const QStringList &added, const QStringList &removed) = 0;
|
||||
|
||||
virtual bool handleClientMessage(xcb_client_message_event_t *event) {
|
||||
Q_UNUSED(event);
|
||||
return false;
|
||||
}
|
||||
// sets the current provider of the selection
|
||||
void setWlSource(WlSource *src);
|
||||
WlSource* wlSource() const {
|
||||
return m_wlSrc;
|
||||
void setWlSource(WlSource *source);
|
||||
WlSource *wlSource() const {
|
||||
return m_waylandSource;
|
||||
}
|
||||
void createX11Source(xcb_xfixes_selection_notify_event_t *event);
|
||||
X11Source* x11Source() const {
|
||||
return m_xSrc;
|
||||
X11Source *x11Source() const {
|
||||
return m_xSource;
|
||||
}
|
||||
// must be called in order to provide data from Wl to X
|
||||
void ownSelection(bool own);
|
||||
|
@ -105,9 +106,9 @@ protected:
|
|||
}
|
||||
|
||||
private:
|
||||
bool handleSelRequest(xcb_selection_request_event_t *event);
|
||||
bool handleSelNotify(xcb_selection_notify_event_t *event);
|
||||
bool handlePropNotify(xcb_property_notify_event_t *event);
|
||||
bool handleSelectionRequest(xcb_selection_request_event_t *event);
|
||||
bool handleSelectionNotify(xcb_selection_notify_event_t *event);
|
||||
bool handlePropertyNotify(xcb_property_notify_event_t *event);
|
||||
|
||||
void startTransferToWayland(xcb_atom_t target, qint32 fd);
|
||||
void startTransferToX(xcb_selection_request_event_t *event, qint32 fd);
|
||||
|
@ -124,18 +125,20 @@ private:
|
|||
|
||||
// Active source, if any. Only one of them at max can exist
|
||||
// at the same time.
|
||||
WlSource *m_wlSrc = nullptr;
|
||||
X11Source *m_xSrc = nullptr;
|
||||
WlSource *m_waylandSource = nullptr;
|
||||
X11Source *m_xSource = nullptr;
|
||||
|
||||
// active transfers
|
||||
QVector<TransferWltoX*> m_wlToXTransfers;
|
||||
QVector<TransferXtoWl*> m_xToWlTransfers;
|
||||
QVector<TransferWltoX *> m_wlToXTransfers;
|
||||
QVector<TransferXtoWl *> m_xToWlTransfers;
|
||||
QTimer *m_timeoutTransfers = nullptr;
|
||||
|
||||
bool m_disownPending = false;
|
||||
|
||||
Q_DISABLE_COPY(Selection)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
||||
#endif
|
||||
|
|
|
@ -29,27 +29,29 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <KWayland/Client/datadevice.h>
|
||||
#include <KWayland/Client/datasource.h>
|
||||
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
#include <KWayland/Server/datadevice_interface.h>
|
||||
#include <KWayland/Server/datasource_interface.h>
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include <xwayland_logging.h>
|
||||
|
||||
namespace KWin {
|
||||
namespace Xwl {
|
||||
namespace KWin
|
||||
{
|
||||
namespace Xwl
|
||||
{
|
||||
|
||||
SelectionSource::SelectionSource(Selection *sel)
|
||||
: QObject(sel),
|
||||
m_sel(sel),
|
||||
m_window(sel->window())
|
||||
SelectionSource::SelectionSource(Selection *selection)
|
||||
: QObject(selection)
|
||||
, m_selection(selection)
|
||||
, m_window(selection->window())
|
||||
{
|
||||
}
|
||||
|
||||
WlSource::WlSource(Selection *sel, KWayland::Server::DataDeviceInterface *ddi)
|
||||
: SelectionSource(sel),
|
||||
m_ddi(ddi)
|
||||
WlSource::WlSource(Selection *selection, KWayland::Server::DataDeviceInterface *ddi)
|
||||
: SelectionSource(selection)
|
||||
, m_ddi(ddi)
|
||||
{
|
||||
Q_ASSERT(ddi);
|
||||
}
|
||||
|
@ -62,7 +64,7 @@ void WlSource::setDataSourceIface(KWayland::Server::DataSourceInterface *dsi)
|
|||
for (const auto &mime : dsi->mimeTypes()) {
|
||||
m_offers << mime;
|
||||
}
|
||||
m_offerCon = connect(dsi,
|
||||
m_offerConnection = connect(dsi,
|
||||
&KWayland::Server::DataSourceInterface::mimeTypeOffered,
|
||||
this, &WlSource::receiveOffer);
|
||||
m_dsi = dsi;
|
||||
|
@ -73,23 +75,23 @@ void WlSource::receiveOffer(const QString &mime)
|
|||
m_offers << mime;
|
||||
}
|
||||
|
||||
void WlSource::sendSelNotify(xcb_selection_request_event_t *event, bool success)
|
||||
void WlSource::sendSelectionNotify(xcb_selection_request_event_t *event, bool success)
|
||||
{
|
||||
Selection::sendSelNotify(event, success);
|
||||
Selection::sendSelectionNotify(event, success);
|
||||
}
|
||||
|
||||
bool WlSource::handleSelRequest(xcb_selection_request_event_t *event)
|
||||
bool WlSource::handleSelectionRequest(xcb_selection_request_event_t *event)
|
||||
{
|
||||
if (event->target == atoms->targets) {
|
||||
sendTargets(event);
|
||||
} else if (event->target == atoms->timestamp) {
|
||||
sendTimestamp(event);
|
||||
} else if (event->target == atoms->delete_atom) {
|
||||
sendSelNotify(event, true);
|
||||
sendSelectionNotify(event, true);
|
||||
} else {
|
||||
// try to send mime data
|
||||
if (!checkStartTransfer(event)) {
|
||||
sendSelNotify(event, false);
|
||||
sendSelectionNotify(event, false);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -114,7 +116,7 @@ void WlSource::sendTargets(xcb_selection_request_event_t *event)
|
|||
event->property,
|
||||
XCB_ATOM_ATOM,
|
||||
32, cnt, targets.data());
|
||||
sendSelNotify(event, true);
|
||||
sendSelectionNotify(event, true);
|
||||
}
|
||||
|
||||
void WlSource::sendTimestamp(xcb_selection_request_event_t *event)
|
||||
|
@ -127,7 +129,7 @@ void WlSource::sendTimestamp(xcb_selection_request_event_t *event)
|
|||
XCB_ATOM_INTEGER,
|
||||
32, 1, &time);
|
||||
|
||||
sendSelNotify(event, true);
|
||||
sendSelectionNotify(event, true);
|
||||
}
|
||||
|
||||
bool WlSource::checkStartTransfer(xcb_selection_request_event_t *event)
|
||||
|
@ -172,16 +174,16 @@ bool WlSource::checkStartTransfer(xcb_selection_request_event_t *event)
|
|||
return true;
|
||||
}
|
||||
|
||||
X11Source::X11Source(Selection *sel, xcb_xfixes_selection_notify_event_t *event)
|
||||
: SelectionSource(sel),
|
||||
m_owner(event->owner)
|
||||
X11Source::X11Source(Selection *selection, xcb_xfixes_selection_notify_event_t *event)
|
||||
: SelectionSource(selection)
|
||||
, m_owner(event->owner)
|
||||
{
|
||||
setTimestamp(event->timestamp);
|
||||
}
|
||||
|
||||
void X11Source::getTargets()
|
||||
{
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
/* will lead to a selection request event for the new owner */
|
||||
xcb_convert_selection(xcbConn,
|
||||
window(),
|
||||
|
@ -197,7 +199,7 @@ using Mime = QPair<QString, xcb_atom_t>;
|
|||
void X11Source::handleTargets()
|
||||
{
|
||||
// receive targets
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_get_property_cookie_t cookie = xcb_get_property(xcbConn,
|
||||
1,
|
||||
window(),
|
||||
|
@ -206,8 +208,8 @@ void X11Source::handleTargets()
|
|||
0,
|
||||
4096
|
||||
);
|
||||
auto *reply = xcb_get_property_reply(xcbConn, cookie, NULL);
|
||||
if (reply == NULL) {
|
||||
auto *reply = xcb_get_property_reply(xcbConn, cookie, nullptr);
|
||||
if (!reply) {
|
||||
return;
|
||||
}
|
||||
if (reply->type != XCB_ATOM_ATOM) {
|
||||
|
@ -215,9 +217,11 @@ void X11Source::handleTargets()
|
|||
return;
|
||||
}
|
||||
|
||||
QStringList added;
|
||||
QStringList removed;
|
||||
|
||||
Mimes all;
|
||||
QVector<QString> add, rm;
|
||||
xcb_atom_t *value = static_cast<xcb_atom_t*>(xcb_get_property_value(reply));
|
||||
xcb_atom_t *value = static_cast<xcb_atom_t *>(xcb_get_property_value(reply));
|
||||
for (uint32_t i = 0; i < reply->value_len; i++) {
|
||||
if (value[i] == XCB_ATOM_NONE) {
|
||||
continue;
|
||||
|
@ -231,12 +235,14 @@ void X11Source::handleTargets()
|
|||
|
||||
|
||||
const auto mimeIt = std::find_if(m_offers.begin(), m_offers.end(),
|
||||
[value, i](const Mime &m)
|
||||
{ return m.second == value[i]; });
|
||||
[value, i](const Mime &mime) {
|
||||
return mime.second == value[i];
|
||||
}
|
||||
);
|
||||
|
||||
auto mimePair = Mime(mimeStrings[0], value[i]);
|
||||
if (mimeIt == m_offers.end()) {
|
||||
add << mimePair.first;
|
||||
added << mimePair.first;
|
||||
} else {
|
||||
m_offers.removeAll(mimePair);
|
||||
}
|
||||
|
@ -244,31 +250,32 @@ void X11Source::handleTargets()
|
|||
}
|
||||
// all left in m_offers are not in the updated targets
|
||||
for (const auto mimePair : m_offers) {
|
||||
rm << mimePair.first;
|
||||
removed << mimePair.first;
|
||||
}
|
||||
m_offers = all;
|
||||
|
||||
if (!add.isEmpty() || !rm.isEmpty()) {
|
||||
Q_EMIT offersChanged(add, rm);
|
||||
if (!added.isEmpty() || !removed.isEmpty()) {
|
||||
Q_EMIT offersChanged(added, removed);
|
||||
}
|
||||
|
||||
free(reply);
|
||||
}
|
||||
|
||||
void X11Source::setDataSource(KWayland::Client::DataSource *ds)
|
||||
void X11Source::setDataSource(KWayland::Client::DataSource *dataSource)
|
||||
{
|
||||
Q_ASSERT(ds);
|
||||
if (m_ds) {
|
||||
delete m_ds;
|
||||
Q_ASSERT(dataSource);
|
||||
if (m_dataSource) {
|
||||
delete m_dataSource;
|
||||
}
|
||||
m_ds = ds;
|
||||
|
||||
std::for_each(m_offers.begin(), m_offers.end(),
|
||||
[ds](const Mime &offer){
|
||||
ds->offer(offer.first);
|
||||
});
|
||||
connect(ds, &KWayland::Client::DataSource::sendDataRequested,
|
||||
this, &X11Source::startTransfer);
|
||||
m_dataSource = dataSource;
|
||||
|
||||
for (const Mime &offer : m_offers) {
|
||||
dataSource->offer(offer.first);
|
||||
}
|
||||
|
||||
connect(dataSource, &KWayland::Client::DataSource::sendDataRequested,
|
||||
this, &X11Source::startTransfer);
|
||||
}
|
||||
|
||||
void X11Source::setOffers(const Mimes &offers)
|
||||
|
@ -277,7 +284,7 @@ void X11Source::setOffers(const Mimes &offers)
|
|||
m_offers = offers;
|
||||
}
|
||||
|
||||
bool X11Source::handleSelNotify(xcb_selection_notify_event_t *event)
|
||||
bool X11Source::handleSelectionNotify(xcb_selection_notify_event_t *event)
|
||||
{
|
||||
if (event->requestor != window()) {
|
||||
return false;
|
||||
|
@ -299,8 +306,10 @@ bool X11Source::handleSelNotify(xcb_selection_notify_event_t *event)
|
|||
void X11Source::startTransfer(const QString &mimeName, qint32 fd)
|
||||
{
|
||||
const auto mimeIt = std::find_if(m_offers.begin(), m_offers.end(),
|
||||
[mimeName](const Mime &m)
|
||||
{ return m.first == mimeName; });
|
||||
[mimeName](const Mime &mime) {
|
||||
return mime.first == mimeName;
|
||||
}
|
||||
);
|
||||
if (mimeIt == m_offers.end()) {
|
||||
qCDebug(KWIN_XWL) << "Sending X11 clipboard to Wayland failed: unsupported MIME.";
|
||||
close(fd);
|
||||
|
@ -310,6 +319,5 @@ void X11Source::startTransfer(const QString &mimeName, qint32 fd)
|
|||
Q_EMIT transferReady((*mimeIt).second, fd);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
|
|
@ -51,12 +51,13 @@ class Selection;
|
|||
|
||||
/**
|
||||
* Base class representing a data source.
|
||||
*/
|
||||
**/
|
||||
class SelectionSource : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
SelectionSource(Selection *sel);
|
||||
SelectionSource(Selection *selection);
|
||||
|
||||
xcb_timestamp_t timestamp() const {
|
||||
return m_timestamp;
|
||||
|
@ -67,7 +68,7 @@ public:
|
|||
|
||||
protected:
|
||||
Selection *selection() const {
|
||||
return m_sel;
|
||||
return m_selection;
|
||||
}
|
||||
void setWindow(xcb_window_t window) {
|
||||
m_window = window;
|
||||
|
@ -78,26 +79,29 @@ protected:
|
|||
|
||||
private:
|
||||
xcb_timestamp_t m_timestamp = XCB_CURRENT_TIME;
|
||||
Selection *m_sel;
|
||||
Selection *m_selection;
|
||||
xcb_window_t m_window;
|
||||
|
||||
Q_DISABLE_COPY(SelectionSource)
|
||||
};
|
||||
|
||||
/**
|
||||
* Representing a Wayland native data source.
|
||||
*/
|
||||
**/
|
||||
class WlSource : public SelectionSource
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
WlSource(Selection *sel, KWayland::Server::DataDeviceInterface *ddi);
|
||||
WlSource(Selection *selection, KWayland::Server::DataDeviceInterface *ddi);
|
||||
void setDataSourceIface(KWayland::Server::DataSourceInterface *dsi);
|
||||
|
||||
bool handleSelRequest(xcb_selection_request_event_t *event);
|
||||
bool handleSelectionRequest(xcb_selection_request_event_t *event);
|
||||
void sendTargets(xcb_selection_request_event_t *event);
|
||||
void sendTimestamp(xcb_selection_request_event_t *event);
|
||||
|
||||
void receiveOffer(const QString &mime);
|
||||
void sendSelNotify(xcb_selection_request_event_t *event, bool success);
|
||||
void sendSelectionNotify(xcb_selection_request_event_t *event, bool success);
|
||||
|
||||
Q_SIGNALS:
|
||||
void transferReady(xcb_selection_request_event_t *event, qint32 fd);
|
||||
|
@ -109,29 +113,32 @@ private:
|
|||
KWayland::Server::DataSourceInterface *m_dsi = nullptr;
|
||||
|
||||
QVector<QString> m_offers;
|
||||
QMetaObject::Connection m_offerCon;
|
||||
QMetaObject::Connection m_offerConnection;
|
||||
|
||||
Q_DISABLE_COPY(WlSource)
|
||||
};
|
||||
|
||||
using Mimes = QVector<QPair<QString, xcb_atom_t> >;
|
||||
|
||||
/**
|
||||
* Representing an X data source.
|
||||
*/
|
||||
**/
|
||||
class X11Source : public SelectionSource
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
X11Source(Selection *sel, xcb_xfixes_selection_notify_event_t *event);
|
||||
X11Source(Selection *selection, xcb_xfixes_selection_notify_event_t *event);
|
||||
|
||||
/**
|
||||
* @param ds must exist.
|
||||
*
|
||||
* X11Source does not take ownership of it in general, but if the function
|
||||
* is called again, it will delete the previous data source.
|
||||
*/
|
||||
void setDataSource(KWayland::Client::DataSource *ds);
|
||||
KWayland::Client::DataSource* dataSource() const {
|
||||
return m_ds;
|
||||
**/
|
||||
void setDataSource(KWayland::Client::DataSource *dataSource);
|
||||
KWayland::Client::DataSource *dataSource() const {
|
||||
return m_dataSource;
|
||||
}
|
||||
void getTargets();
|
||||
|
||||
|
@ -140,14 +147,14 @@ public:
|
|||
}
|
||||
void setOffers(const Mimes &offers);
|
||||
|
||||
bool handleSelNotify(xcb_selection_notify_event_t *event);
|
||||
bool handleSelectionNotify(xcb_selection_notify_event_t *event);
|
||||
|
||||
void setRequestor(xcb_window_t window) {
|
||||
setWindow(window);
|
||||
}
|
||||
|
||||
Q_SIGNALS:
|
||||
void offersChanged(QVector<QString> added, QVector<QString> removed);
|
||||
void offersChanged(const QStringList &added, const QStringList &removed);
|
||||
void transferReady(xcb_atom_t target, qint32 fd);
|
||||
|
||||
private:
|
||||
|
@ -155,12 +162,14 @@ private:
|
|||
void startTransfer(const QString &mimeName, qint32 fd);
|
||||
|
||||
xcb_window_t m_owner;
|
||||
KWayland::Client::DataSource *m_ds = nullptr;
|
||||
KWayland::Client::DataSource *m_dataSource = nullptr;
|
||||
|
||||
Mimes m_offers;
|
||||
|
||||
Q_DISABLE_COPY(X11Source)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
||||
#endif
|
||||
|
|
137
xwl/transfer.cpp
137
xwl/transfer.cpp
|
@ -19,22 +19,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
*********************************************************************/
|
||||
#include "transfer.h"
|
||||
|
||||
#include "xwayland.h"
|
||||
#include "databridge.h"
|
||||
#include "xwayland.h"
|
||||
|
||||
#include "abstract_client.h"
|
||||
#include "atoms.h"
|
||||
#include "wayland_server.h"
|
||||
#include "workspace.h"
|
||||
#include "abstract_client.h"
|
||||
|
||||
#include <KWayland/Client/connection_thread.h>
|
||||
#include <KWayland/Client/datadevicemanager.h>
|
||||
#include <KWayland/Client/datadevice.h>
|
||||
#include <KWayland/Client/datasource.h>
|
||||
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
#include <KWayland/Server/datadevice_interface.h>
|
||||
#include <KWayland/Server/datasource_interface.h>
|
||||
#include <KWayland/Server/seat_interface.h>
|
||||
|
||||
#include <xcb/xcb_event.h>
|
||||
#include <xcb/xfixes.h>
|
||||
|
@ -44,31 +44,32 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#include <xwayland_logging.h>
|
||||
|
||||
namespace KWin {
|
||||
namespace Xwl {
|
||||
namespace KWin
|
||||
{
|
||||
namespace Xwl
|
||||
{
|
||||
|
||||
// in Bytes: equals 64KB
|
||||
static const uint32_t s_incrChunkSize = 63 * 1024;
|
||||
|
||||
Transfer::Transfer(xcb_atom_t selection, qint32 fd, xcb_timestamp_t timestamp, QObject *parent)
|
||||
: QObject(parent),
|
||||
m_atom(selection),
|
||||
m_fd(fd),
|
||||
m_timestamp(timestamp)
|
||||
: QObject(parent)
|
||||
, m_atom(selection)
|
||||
, m_fd(fd)
|
||||
, m_timestamp(timestamp)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void Transfer::createSocketNotifier(QSocketNotifier::Type type)
|
||||
{
|
||||
delete m_sn;
|
||||
m_sn = new QSocketNotifier(m_fd, type, this);
|
||||
delete m_notifier;
|
||||
m_notifier = new QSocketNotifier(m_fd, type, this);
|
||||
}
|
||||
|
||||
void Transfer::clearSocketNotifier()
|
||||
{
|
||||
delete m_sn;
|
||||
m_sn = nullptr;
|
||||
delete m_notifier;
|
||||
m_notifier = nullptr;
|
||||
}
|
||||
|
||||
void Transfer::timeout()
|
||||
|
@ -97,8 +98,8 @@ void Transfer::closeFd()
|
|||
|
||||
TransferWltoX::TransferWltoX(xcb_atom_t selection, xcb_selection_request_event_t *request,
|
||||
qint32 fd, QObject *parent)
|
||||
: Transfer(selection, fd, 0, parent),
|
||||
m_request(request)
|
||||
: Transfer(selection, fd, 0, parent)
|
||||
, m_request(request)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -121,7 +122,7 @@ void TransferWltoX::startTransferFromSource()
|
|||
|
||||
int TransferWltoX::flushSourceData()
|
||||
{
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
|
||||
xcb_change_property(xcbConn,
|
||||
XCB_PROP_MODE_REPLACE,
|
||||
|
@ -129,22 +130,22 @@ int TransferWltoX::flushSourceData()
|
|||
m_request->property,
|
||||
m_request->target,
|
||||
8,
|
||||
chunks.first().first.size(),
|
||||
chunks.first().first.data());
|
||||
m_chunks.first().first.size(),
|
||||
m_chunks.first().first.data());
|
||||
xcb_flush(xcbConn);
|
||||
|
||||
propertyIsSet = true;
|
||||
m_propertyIsSet = true;
|
||||
resetTimeout();
|
||||
|
||||
const auto rm = chunks.takeFirst();
|
||||
const auto rm = m_chunks.takeFirst();
|
||||
return rm.first.size();
|
||||
}
|
||||
|
||||
void TransferWltoX::startIncr()
|
||||
{
|
||||
Q_ASSERT(chunks.size() == 1);
|
||||
Q_ASSERT(m_chunks.size() == 1);
|
||||
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
|
||||
uint32_t mask[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
|
||||
xcb_change_window_attributes (xcbConn,
|
||||
|
@ -164,27 +165,27 @@ void TransferWltoX::startIncr()
|
|||
setIncr(true);
|
||||
// first data will be flushed after the property has been deleted
|
||||
// again by the requestor
|
||||
flushPropOnDelete = true;
|
||||
propertyIsSet = true;
|
||||
Q_EMIT selNotify(m_request, true);
|
||||
m_flushPropertyOnDelete = true;
|
||||
m_propertyIsSet = true;
|
||||
Q_EMIT selectionNotify(m_request, true);
|
||||
}
|
||||
|
||||
void TransferWltoX::readWlSource()
|
||||
{
|
||||
if (chunks.size() == 0 ||
|
||||
chunks.last().second == s_incrChunkSize) {
|
||||
if (m_chunks.size() == 0 ||
|
||||
m_chunks.last().second == s_incrChunkSize) {
|
||||
// append new chunk
|
||||
auto next = QPair<QByteArray, int>();
|
||||
next.first.resize(s_incrChunkSize);
|
||||
next.second = 0;
|
||||
chunks.append(next);
|
||||
m_chunks.append(next);
|
||||
}
|
||||
|
||||
const auto oldLen = chunks.last().second;
|
||||
const auto avail = s_incrChunkSize - chunks.last().second;
|
||||
const auto oldLen = m_chunks.last().second;
|
||||
const auto avail = s_incrChunkSize - m_chunks.last().second;
|
||||
Q_ASSERT(avail > 0);
|
||||
|
||||
ssize_t readLen = read(fd(), chunks.last().first.data() + oldLen, avail);
|
||||
ssize_t readLen = read(fd(), m_chunks.last().first.data() + oldLen, avail);
|
||||
if (readLen == -1) {
|
||||
qCWarning(KWIN_XWL) << "Error reading in Wl data.";
|
||||
|
||||
|
@ -192,16 +193,16 @@ void TransferWltoX::readWlSource()
|
|||
endTransfer();
|
||||
return;
|
||||
}
|
||||
chunks.last().second = oldLen + readLen;
|
||||
m_chunks.last().second = oldLen + readLen;
|
||||
|
||||
if (readLen == 0) {
|
||||
// at the fd end - complete transfer now
|
||||
chunks.last().first.resize(chunks.last().second);
|
||||
m_chunks.last().first.resize(m_chunks.last().second);
|
||||
|
||||
if (incr()) {
|
||||
// incremental transfer is to be completed now
|
||||
flushPropOnDelete = true;
|
||||
if (!propertyIsSet) {
|
||||
m_flushPropertyOnDelete = true;
|
||||
if (!m_propertyIsSet) {
|
||||
// flush if target's property is not set at the moment
|
||||
flushSourceData();
|
||||
}
|
||||
|
@ -210,14 +211,14 @@ void TransferWltoX::readWlSource()
|
|||
// non incremental transfer is to be completed now,
|
||||
// data can be transferred to X client via a single property set
|
||||
flushSourceData();
|
||||
Q_EMIT selNotify(m_request, true);
|
||||
Q_EMIT selectionNotify(m_request, true);
|
||||
endTransfer();
|
||||
}
|
||||
} else if (chunks.last().second == s_incrChunkSize) {
|
||||
} else if (m_chunks.last().second == s_incrChunkSize) {
|
||||
// first chunk full, but not yet at fd end -> go incremental
|
||||
if (incr()) {
|
||||
flushPropOnDelete = true;
|
||||
if (!propertyIsSet) {
|
||||
m_flushPropertyOnDelete = true;
|
||||
if (!m_propertyIsSet) {
|
||||
// flush if target's property is not set at the moment
|
||||
flushSourceData();
|
||||
}
|
||||
|
@ -229,30 +230,30 @@ void TransferWltoX::readWlSource()
|
|||
resetTimeout();
|
||||
}
|
||||
|
||||
bool TransferWltoX::handlePropNotify(xcb_property_notify_event_t *event)
|
||||
bool TransferWltoX::handlePropertyNotify(xcb_property_notify_event_t *event)
|
||||
{
|
||||
if (event->window == m_request->requestor) {
|
||||
if (event->state == XCB_PROPERTY_DELETE &&
|
||||
event->atom == m_request->property) {
|
||||
handlePropDelete();
|
||||
handlePropertyDelete();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void TransferWltoX::handlePropDelete()
|
||||
void TransferWltoX::handlePropertyDelete()
|
||||
{
|
||||
if (!incr()) {
|
||||
// non-incremental transfer: nothing to do
|
||||
return;
|
||||
}
|
||||
propertyIsSet = false;
|
||||
m_propertyIsSet = false;
|
||||
|
||||
if (flushPropOnDelete) {
|
||||
if (!socketNotifier() && chunks.isEmpty()) {
|
||||
if (m_flushPropertyOnDelete) {
|
||||
if (!socketNotifier() && m_chunks.isEmpty()) {
|
||||
// transfer complete
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
|
||||
uint32_t mask[] = {0};
|
||||
xcb_change_window_attributes (xcbConn,
|
||||
|
@ -266,7 +267,7 @@ void TransferWltoX::handlePropDelete()
|
|||
m_request->target,
|
||||
8, 0, NULL);
|
||||
xcb_flush(xcbConn);
|
||||
flushPropOnDelete = false;
|
||||
m_flushPropertyOnDelete = false;
|
||||
endTransfer();
|
||||
} else {
|
||||
flushSourceData();
|
||||
|
@ -280,7 +281,7 @@ TransferXtoWl::TransferXtoWl(xcb_atom_t selection, xcb_atom_t target, qint32 fd,
|
|||
: Transfer(selection, fd, timestamp, parent)
|
||||
{
|
||||
// create transfer window
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
m_window = xcb_generate_id(xcbConn);
|
||||
const uint32_t values[] = { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
|
||||
XCB_EVENT_MASK_PROPERTY_CHANGE };
|
||||
|
@ -307,7 +308,7 @@ TransferXtoWl::TransferXtoWl(xcb_atom_t selection, xcb_atom_t target, qint32 fd,
|
|||
|
||||
TransferXtoWl::~TransferXtoWl()
|
||||
{
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_destroy_window(xcbConn, m_window);
|
||||
xcb_flush(xcbConn);
|
||||
|
||||
|
@ -315,7 +316,7 @@ TransferXtoWl::~TransferXtoWl()
|
|||
m_receiver = nullptr;
|
||||
}
|
||||
|
||||
bool TransferXtoWl::handlePropNotify(xcb_property_notify_event_t *event)
|
||||
bool TransferXtoWl::handlePropertyNotify(xcb_property_notify_event_t *event)
|
||||
{
|
||||
if (event->window == m_window) {
|
||||
if (event->state == XCB_PROPERTY_NEW_VALUE &&
|
||||
|
@ -327,7 +328,7 @@ bool TransferXtoWl::handlePropNotify(xcb_property_notify_event_t *event)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool TransferXtoWl::handleSelNotify(xcb_selection_notify_event_t *event)
|
||||
bool TransferXtoWl::handleSelectionNotify(xcb_selection_notify_event_t *event)
|
||||
{
|
||||
if (event->requestor != m_window) {
|
||||
return false;
|
||||
|
@ -364,7 +365,7 @@ bool TransferXtoWl::handleSelNotify(xcb_selection_notify_event_t *event)
|
|||
|
||||
void TransferXtoWl::startTransfer()
|
||||
{
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
auto cookie = xcb_get_property(xcbConn,
|
||||
1,
|
||||
m_window,
|
||||
|
@ -402,7 +403,7 @@ void TransferXtoWl::getIncrChunk()
|
|||
// receive mechanism has not yet been setup
|
||||
return;
|
||||
}
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
|
||||
auto cookie = xcb_get_property(xcbConn,
|
||||
0,
|
||||
|
@ -412,8 +413,8 @@ void TransferXtoWl::getIncrChunk()
|
|||
0,
|
||||
0x1fffffff);
|
||||
|
||||
auto *reply = xcb_get_property_reply(xcbConn, cookie, NULL);
|
||||
if (reply == NULL) {
|
||||
auto *reply = xcb_get_property_reply(xcbConn, cookie, nullptr);
|
||||
if (!reply) {
|
||||
qCWarning(KWIN_XWL) << "Can't get selection property.";
|
||||
endTransfer();
|
||||
return;
|
||||
|
@ -443,11 +444,11 @@ void DataReceiver::transferFromProperty(xcb_get_property_reply_t *reply)
|
|||
m_propertyStart = 0;
|
||||
m_propertyReply = reply;
|
||||
|
||||
setData(static_cast<char*>(xcb_get_property_value(reply)),
|
||||
setData(static_cast<char *>(xcb_get_property_value(reply)),
|
||||
xcb_get_property_value_length(reply));
|
||||
}
|
||||
|
||||
void DataReceiver::setData(char *value, int length)
|
||||
void DataReceiver::setData(const char *value, int length)
|
||||
{
|
||||
// simply set data without copy
|
||||
m_data = QByteArray::fromRawData(value, length);
|
||||
|
@ -469,7 +470,7 @@ void DataReceiver::partRead(int length)
|
|||
}
|
||||
}
|
||||
|
||||
void NetscapeUrlReceiver::setData(char *value, int length)
|
||||
void NetscapeUrlReceiver::setData(const char *value, int length)
|
||||
{
|
||||
auto origData = QByteArray::fromRawData(value, length);
|
||||
|
||||
|
@ -507,14 +508,14 @@ void NetscapeUrlReceiver::setData(char *value, int length)
|
|||
setDataInternal(data);
|
||||
}
|
||||
|
||||
void MozUrlReceiver::setData(char *value, int length)
|
||||
void MozUrlReceiver::setData(const char *value, int length)
|
||||
{
|
||||
// represent as QByteArray (guaranteed '\0'-terminated)
|
||||
const auto origData = QByteArray::fromRawData(value, length);
|
||||
|
||||
// text/x-moz-url data is sent in utf-16 - copies the content
|
||||
// and converts it into 8 byte representation
|
||||
const auto byteData = QString::fromUtf16(reinterpret_cast<const char16_t*>(origData.data())).toLatin1();
|
||||
const auto byteData = QString::fromUtf16(reinterpret_cast<const char16_t *>(origData.data())).toLatin1();
|
||||
|
||||
if (byteData.indexOf('\n') == -1) {
|
||||
// there are no line breaks, not in text/x-moz-url format or empty,
|
||||
|
@ -566,7 +567,7 @@ void TransferXtoWl::dataSourceWrite()
|
|||
// property completely transferred
|
||||
if (incr()) {
|
||||
clearSocketNotifier();
|
||||
auto *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_connection_t *xcbConn = kwinApp()->x11Connection();
|
||||
xcb_delete_property(xcbConn,
|
||||
m_window,
|
||||
atoms->wl_selection);
|
||||
|
@ -579,15 +580,15 @@ void TransferXtoWl::dataSourceWrite()
|
|||
if (!socketNotifier()) {
|
||||
createSocketNotifier(QSocketNotifier::Write);
|
||||
connect(socketNotifier(), &QSocketNotifier::activated, this,
|
||||
[this](int socket) {
|
||||
Q_UNUSED(socket);
|
||||
dataSourceWrite();
|
||||
}
|
||||
[this](int socket) {
|
||||
Q_UNUSED(socket);
|
||||
dataSourceWrite();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
resetTimeout();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
|
|
@ -26,12 +26,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
|
||||
#include <xcb/xcb.h>
|
||||
|
||||
namespace KWayland {
|
||||
namespace Client {
|
||||
namespace KWayland
|
||||
{
|
||||
namespace Client
|
||||
{
|
||||
class DataDevice;
|
||||
class DataSource;
|
||||
}
|
||||
namespace Server {
|
||||
namespace Server
|
||||
{
|
||||
class DataDeviceInterface;
|
||||
}
|
||||
}
|
||||
|
@ -48,17 +51,18 @@ namespace Xwl
|
|||
* Lives for the duration of the transfer and must be cleaned up
|
||||
* externally afterwards. For that the owner should connect to the
|
||||
* @c finished() signal.
|
||||
*/
|
||||
**/
|
||||
class Transfer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Transfer(xcb_atom_t selection,
|
||||
qint32 fd,
|
||||
xcb_timestamp_t timestamp,
|
||||
QObject *parent = nullptr);
|
||||
|
||||
virtual bool handlePropNotify(xcb_property_notify_event_t *event) = 0;
|
||||
virtual bool handlePropertyNotify(xcb_property_notify_event_t *event) = 0;
|
||||
void timeout();
|
||||
xcb_timestamp_t timestamp() const {
|
||||
return m_timestamp;
|
||||
|
@ -88,8 +92,8 @@ protected:
|
|||
}
|
||||
void createSocketNotifier(QSocketNotifier::Type type);
|
||||
void clearSocketNotifier();
|
||||
QSocketNotifier* socketNotifier() const {
|
||||
return m_sn;
|
||||
QSocketNotifier *socketNotifier() const {
|
||||
return m_notifier;
|
||||
}
|
||||
private:
|
||||
void closeFd();
|
||||
|
@ -98,17 +102,20 @@ private:
|
|||
qint32 m_fd;
|
||||
xcb_timestamp_t m_timestamp = XCB_CURRENT_TIME;
|
||||
|
||||
QSocketNotifier *m_sn = nullptr;
|
||||
QSocketNotifier *m_notifier = nullptr;
|
||||
bool m_incr = false;
|
||||
bool m_timeout = false;
|
||||
|
||||
Q_DISABLE_COPY(Transfer)
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a transfer from a Wayland native source to an X window.
|
||||
*/
|
||||
**/
|
||||
class TransferWltoX : public Transfer
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TransferWltoX(xcb_atom_t selection,
|
||||
xcb_selection_request_event_t *request,
|
||||
|
@ -117,31 +124,33 @@ public:
|
|||
~TransferWltoX();
|
||||
|
||||
void startTransferFromSource();
|
||||
bool handlePropNotify(xcb_property_notify_event_t *event) override;
|
||||
bool handlePropertyNotify(xcb_property_notify_event_t *event) override;
|
||||
|
||||
Q_SIGNALS:
|
||||
void selNotify(xcb_selection_request_event_t *event, bool success);
|
||||
void selectionNotify(xcb_selection_request_event_t *event, bool success);
|
||||
|
||||
private:
|
||||
void startIncr();
|
||||
void readWlSource();
|
||||
int flushSourceData();
|
||||
void handlePropDelete();
|
||||
void handlePropertyDelete();
|
||||
|
||||
xcb_selection_request_event_t *m_request = nullptr;
|
||||
|
||||
/* contains all received data portioned in chunks
|
||||
* TODO: explain second QPair component
|
||||
*/
|
||||
QVector<QPair<QByteArray, int> > chunks;
|
||||
QVector<QPair<QByteArray, int> > m_chunks;
|
||||
|
||||
bool propertyIsSet = false;
|
||||
bool flushPropOnDelete = false;
|
||||
bool m_propertyIsSet = false;
|
||||
bool m_flushPropertyOnDelete = false;
|
||||
|
||||
Q_DISABLE_COPY(TransferWltoX)
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper class for X to Wl transfers
|
||||
*/
|
||||
* Helper class for X to Wl transfers.
|
||||
**/
|
||||
class DataReceiver
|
||||
{
|
||||
public:
|
||||
|
@ -150,7 +159,7 @@ public:
|
|||
void transferFromProperty(xcb_get_property_reply_t *reply);
|
||||
|
||||
|
||||
virtual void setData(char *value, int length);
|
||||
virtual void setData(const char *value, int length);
|
||||
QByteArray data() const;
|
||||
|
||||
void partRead(int length);
|
||||
|
@ -169,29 +178,30 @@ private:
|
|||
/**
|
||||
* Compatibility receiver for clients only
|
||||
* supporting the NETSCAPE_URL scheme (Firefox)
|
||||
*/
|
||||
**/
|
||||
class NetscapeUrlReceiver : public DataReceiver
|
||||
{
|
||||
public:
|
||||
void setData(char *value, int length) override;
|
||||
void setData(const char *value, int length) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Compatibility receiver for clients only
|
||||
* supporting the text/x-moz-url scheme (Chromium on own drags)
|
||||
*/
|
||||
**/
|
||||
class MozUrlReceiver : public DataReceiver
|
||||
{
|
||||
public:
|
||||
void setData(char *value, int length) override;
|
||||
void setData(const char *value, int length) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a transfer from an X window to a Wayland native client.
|
||||
*/
|
||||
**/
|
||||
class TransferXtoWl : public Transfer
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TransferXtoWl(xcb_atom_t selection,
|
||||
xcb_atom_t target,
|
||||
|
@ -200,8 +210,8 @@ public:
|
|||
QObject *parent = nullptr);
|
||||
~TransferXtoWl();
|
||||
|
||||
bool handleSelNotify(xcb_selection_notify_event_t *event);
|
||||
bool handlePropNotify(xcb_property_notify_event_t *event) override;
|
||||
bool handleSelectionNotify(xcb_selection_notify_event_t *event);
|
||||
bool handlePropertyNotify(xcb_property_notify_event_t *event) override;
|
||||
|
||||
private:
|
||||
void dataSourceWrite();
|
||||
|
@ -210,9 +220,11 @@ private:
|
|||
|
||||
xcb_window_t m_window;
|
||||
DataReceiver *m_receiver = nullptr;
|
||||
|
||||
Q_DISABLE_COPY(TransferXtoWl)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
||||
#endif
|
||||
|
|
|
@ -21,22 +21,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "xwayland.h"
|
||||
#include "databridge.h"
|
||||
|
||||
#include "wayland_server.h"
|
||||
#include "main_wayland.h"
|
||||
#include "utils.h"
|
||||
#include "wayland_server.h"
|
||||
#include "xcbutils.h"
|
||||
|
||||
#include <KLocalizedString>
|
||||
#include <KSelectionOwner>
|
||||
|
||||
#include "xcbutils.h"
|
||||
|
||||
#include <QAbstractEventDispatcher>
|
||||
#include <QtConcurrentRun>
|
||||
#include <QFile>
|
||||
#include <QFutureWatcher>
|
||||
#include <QProcess>
|
||||
#include <QSocketNotifier>
|
||||
#include <QThread>
|
||||
#include <QtConcurrentRun>
|
||||
|
||||
// system
|
||||
#ifdef HAVE_UNISTD_H
|
||||
|
@ -68,19 +67,21 @@ static void readDisplay(int pipe)
|
|||
close(pipe);
|
||||
}
|
||||
|
||||
namespace KWin {
|
||||
namespace KWin
|
||||
{
|
||||
namespace Xwl
|
||||
{
|
||||
|
||||
Xwayland *s_self = nullptr;
|
||||
Xwayland* Xwayland::self()
|
||||
|
||||
Xwayland *Xwayland::self()
|
||||
{
|
||||
return s_self;
|
||||
}
|
||||
|
||||
Xwayland::Xwayland(ApplicationWaylandAbstract *app, QObject *parent)
|
||||
: XwaylandInterface(parent),
|
||||
m_app(app)
|
||||
: XwaylandInterface(parent)
|
||||
, m_app(app)
|
||||
{
|
||||
s_self = this;
|
||||
}
|
||||
|
@ -211,7 +212,7 @@ void Xwayland::createX11Connection()
|
|||
void Xwayland::continueStartupWithX()
|
||||
{
|
||||
createX11Connection();
|
||||
auto *xcbConn = m_app->x11Connection();
|
||||
xcb_connection_t *xcbConn = m_app->x11Connection();
|
||||
if (!xcbConn) {
|
||||
// about to quit
|
||||
Q_EMIT criticalError(1);
|
||||
|
@ -268,7 +269,7 @@ void Xwayland::continueStartupWithX()
|
|||
Xcb::sync(); // Trigger possible errors, there's still a chance to abort
|
||||
}
|
||||
|
||||
DragEventReply Xwayland::dragMoveFilter(Toplevel *target, QPoint pos)
|
||||
DragEventReply Xwayland::dragMoveFilter(Toplevel *target, const QPoint &pos)
|
||||
{
|
||||
if (!m_dataBridge) {
|
||||
return DragEventReply::Wayland;
|
||||
|
@ -276,5 +277,5 @@ DragEventReply Xwayland::dragMoveFilter(Toplevel *target, QPoint pos)
|
|||
return m_dataBridge->dragMoveFilter(target, pos);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
|
|
@ -39,11 +39,12 @@ class DataBridge;
|
|||
class Xwayland : public XwaylandInterface
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static Xwayland* self();
|
||||
static Xwayland *self();
|
||||
|
||||
Xwayland(ApplicationWaylandAbstract *app, QObject *parent = nullptr);
|
||||
virtual ~Xwayland();
|
||||
~Xwayland() override;
|
||||
|
||||
void init();
|
||||
void prepareDestroy();
|
||||
|
@ -63,7 +64,7 @@ private:
|
|||
void createX11Connection();
|
||||
void continueStartupWithX();
|
||||
|
||||
DragEventReply dragMoveFilter(Toplevel *target, QPoint pos) override;
|
||||
DragEventReply dragMoveFilter(Toplevel *target, const QPoint &pos) override;
|
||||
|
||||
int m_xcbConnectionFd = -1;
|
||||
QProcess *m_xwaylandProcess = nullptr;
|
||||
|
@ -74,9 +75,11 @@ private:
|
|||
DataBridge *m_dataBridge = nullptr;
|
||||
|
||||
ApplicationWaylandAbstract *m_app;
|
||||
|
||||
Q_DISABLE_COPY(Xwayland)
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
} // namespace Xwl
|
||||
} // namespace KWin
|
||||
|
||||
#endif
|
||||
|
|
|
@ -40,4 +40,4 @@ XwaylandInterface::~XwaylandInterface()
|
|||
s_self = nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace KWin
|
||||
|
|
|
@ -39,25 +39,30 @@ enum class DragEventReply {
|
|||
// event should be handled as a Wayland native one
|
||||
Wayland,
|
||||
};
|
||||
}
|
||||
} // namespace Xwl
|
||||
|
||||
class KWIN_EXPORT XwaylandInterface : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static XwaylandInterface *self();
|
||||
|
||||
virtual Xwl::DragEventReply dragMoveFilter(Toplevel *target, QPoint pos) = 0;
|
||||
virtual Xwl::DragEventReply dragMoveFilter(Toplevel *target, const QPoint &pos) = 0;
|
||||
|
||||
protected:
|
||||
explicit XwaylandInterface(QObject *parent = nullptr);
|
||||
virtual ~XwaylandInterface();
|
||||
|
||||
private:
|
||||
Q_DISABLE_COPY(XwaylandInterface)
|
||||
};
|
||||
|
||||
inline XwaylandInterface *xwayland() {
|
||||
inline XwaylandInterface *xwayland()
|
||||
{
|
||||
return XwaylandInterface::self();
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace KWin
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue