Fix crash when dragging with touch without first having pointer focus
Also add drag-and-drop tests for both touch and mouse. Task-number: QTBUG-54756 Change-Id: Ibfff48b1f2377022a8624e28e9f638076187ddca Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
This commit is contained in:
parent
8184ff6bfb
commit
1e36cce9fe
@ -107,7 +107,10 @@ void QWaylandDataDevice::startDrag(QMimeData *mimeData, QWaylandWindow *icon)
|
|||||||
{
|
{
|
||||||
m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
|
m_dragSource.reset(new QWaylandDataSource(m_display->dndSelectionHandler(), mimeData));
|
||||||
connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
|
connect(m_dragSource.data(), &QWaylandDataSource::cancelled, this, &QWaylandDataDevice::dragSourceCancelled);
|
||||||
|
|
||||||
QWaylandWindow *origin = m_display->currentInputDevice()->pointerFocus();
|
QWaylandWindow *origin = m_display->currentInputDevice()->pointerFocus();
|
||||||
|
if (!origin)
|
||||||
|
origin = m_display->currentInputDevice()->touchFocus();
|
||||||
|
|
||||||
start_drag(m_dragSource->object(), origin->object(), icon->object(), m_display->currentInputDevice()->serial());
|
start_drag(m_dragSource->object(), origin->object(), icon->object(), m_display->currentInputDevice()->serial());
|
||||||
}
|
}
|
||||||
|
@ -150,6 +150,47 @@ void MockCompositor::sendTouchFrame(const QSharedPointer<MockSurface> &surface)
|
|||||||
processCommand(command);
|
processCommand(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MockCompositor::sendDataDeviceDataOffer(const QSharedPointer<MockSurface> &surface)
|
||||||
|
{
|
||||||
|
Command command = makeCommand(Impl::Compositor::sendDataDeviceDataOffer, m_compositor);
|
||||||
|
command.parameters << QVariant::fromValue(surface);
|
||||||
|
processCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MockCompositor::sendDataDeviceEnter(const QSharedPointer<MockSurface> &surface, const QPoint& position)
|
||||||
|
{
|
||||||
|
Command command = makeCommand(Impl::Compositor::sendDataDeviceEnter, m_compositor);
|
||||||
|
command.parameters << QVariant::fromValue(surface) << QVariant::fromValue(position);
|
||||||
|
processCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MockCompositor::sendDataDeviceMotion(const QPoint &position)
|
||||||
|
{
|
||||||
|
Command command = makeCommand(Impl::Compositor::sendDataDeviceMotion, m_compositor);
|
||||||
|
command.parameters << QVariant::fromValue(position);
|
||||||
|
processCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MockCompositor::sendDataDeviceDrop(const QSharedPointer<MockSurface> &surface)
|
||||||
|
{
|
||||||
|
Command command = makeCommand(Impl::Compositor::sendDataDeviceDrop, m_compositor);
|
||||||
|
command.parameters << QVariant::fromValue(surface);
|
||||||
|
processCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MockCompositor::sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface)
|
||||||
|
{
|
||||||
|
Command command = makeCommand(Impl::Compositor::sendDataDeviceLeave, m_compositor);
|
||||||
|
command.parameters << QVariant::fromValue(surface);
|
||||||
|
processCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MockCompositor::waitForStartDrag()
|
||||||
|
{
|
||||||
|
Command command = makeCommand(Impl::Compositor::waitForStartDrag, m_compositor);
|
||||||
|
processCommand(command);
|
||||||
|
}
|
||||||
|
|
||||||
QSharedPointer<MockSurface> MockCompositor::surface()
|
QSharedPointer<MockSurface> MockCompositor::surface()
|
||||||
{
|
{
|
||||||
QSharedPointer<MockSurface> result;
|
QSharedPointer<MockSurface> result;
|
||||||
@ -228,6 +269,7 @@ namespace Impl {
|
|||||||
|
|
||||||
Compositor::Compositor()
|
Compositor::Compositor()
|
||||||
: m_display(wl_display_create())
|
: m_display(wl_display_create())
|
||||||
|
, m_startDragSeen(false)
|
||||||
, m_time(0)
|
, m_time(0)
|
||||||
{
|
{
|
||||||
wl_list_init(&m_outputResources);
|
wl_list_init(&m_outputResources);
|
||||||
|
@ -85,6 +85,15 @@ public:
|
|||||||
static void sendTouchUp(void *data, const QList<QVariant> ¶meters);
|
static void sendTouchUp(void *data, const QList<QVariant> ¶meters);
|
||||||
static void sendTouchMotion(void *data, const QList<QVariant> ¶meters);
|
static void sendTouchMotion(void *data, const QList<QVariant> ¶meters);
|
||||||
static void sendTouchFrame(void *data, const QList<QVariant> ¶meters);
|
static void sendTouchFrame(void *data, const QList<QVariant> ¶meters);
|
||||||
|
static void sendDataDeviceDataOffer(void *data, const QList<QVariant> ¶meters);
|
||||||
|
static void sendDataDeviceEnter(void *data, const QList<QVariant> ¶meters);
|
||||||
|
static void sendDataDeviceMotion(void *data, const QList<QVariant> ¶meters);
|
||||||
|
static void sendDataDeviceDrop(void *data, const QList<QVariant> ¶meters);
|
||||||
|
static void sendDataDeviceLeave(void *data, const QList<QVariant> ¶meters);
|
||||||
|
static void waitForStartDrag(void *data, const QList<QVariant> ¶meters);
|
||||||
|
|
||||||
|
public:
|
||||||
|
bool m_startDragSeen;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void bindCompositor(wl_client *client, void *data, uint32_t version, uint32_t id);
|
static void bindCompositor(wl_client *client, void *data, uint32_t version, uint32_t id);
|
||||||
@ -156,6 +165,12 @@ public:
|
|||||||
void sendTouchMotion(const QSharedPointer<MockSurface> &surface, const QPoint &position, int id);
|
void sendTouchMotion(const QSharedPointer<MockSurface> &surface, const QPoint &position, int id);
|
||||||
void sendTouchUp(const QSharedPointer<MockSurface> &surface, int id);
|
void sendTouchUp(const QSharedPointer<MockSurface> &surface, int id);
|
||||||
void sendTouchFrame(const QSharedPointer<MockSurface> &surface);
|
void sendTouchFrame(const QSharedPointer<MockSurface> &surface);
|
||||||
|
void sendDataDeviceDataOffer(const QSharedPointer<MockSurface> &surface);
|
||||||
|
void sendDataDeviceEnter(const QSharedPointer<MockSurface> &surface, const QPoint &position);
|
||||||
|
void sendDataDeviceMotion(const QPoint &position);
|
||||||
|
void sendDataDeviceDrop(const QSharedPointer<MockSurface> &surface);
|
||||||
|
void sendDataDeviceLeave(const QSharedPointer<MockSurface> &surface);
|
||||||
|
void waitForStartDrag();
|
||||||
|
|
||||||
QSharedPointer<MockSurface> surface();
|
QSharedPointer<MockSurface> surface();
|
||||||
|
|
||||||
|
@ -144,6 +144,70 @@ void Compositor::sendTouchFrame(void *data, const QList<QVariant> ¶meters)
|
|||||||
compositor->m_touch->sendFrame(surface);
|
compositor->m_touch->sendFrame(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Compositor::sendDataDeviceDataOffer(void *data, const QList<QVariant> ¶meters)
|
||||||
|
{
|
||||||
|
Compositor *compositor = static_cast<Compositor *>(data);
|
||||||
|
Surface *surface = resolveSurface(parameters.first());
|
||||||
|
|
||||||
|
Q_ASSERT(compositor);
|
||||||
|
Q_ASSERT(surface);
|
||||||
|
|
||||||
|
compositor->m_data_device_manager->dataDevice()->sendDataOffer(surface->resource()->client());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compositor::sendDataDeviceEnter(void *data, const QList<QVariant> ¶meters)
|
||||||
|
{
|
||||||
|
Compositor *compositor = static_cast<Compositor *>(data);
|
||||||
|
Surface *surface = resolveSurface(parameters.first());
|
||||||
|
QPoint position = parameters.at(1).toPoint();
|
||||||
|
|
||||||
|
Q_ASSERT(compositor);
|
||||||
|
Q_ASSERT(surface);
|
||||||
|
|
||||||
|
compositor->m_data_device_manager->dataDevice()->sendEnter(surface, position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compositor::sendDataDeviceMotion(void *data, const QList<QVariant> ¶meters)
|
||||||
|
{
|
||||||
|
Compositor *compositor = static_cast<Compositor *>(data);
|
||||||
|
Q_ASSERT(compositor);
|
||||||
|
QPoint position = parameters.first().toPoint();
|
||||||
|
compositor->m_data_device_manager->dataDevice()->sendMotion(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compositor::sendDataDeviceDrop(void *data, const QList<QVariant> ¶meters)
|
||||||
|
{
|
||||||
|
Compositor *compositor = static_cast<Compositor *>(data);
|
||||||
|
Surface *surface = resolveSurface(parameters.first());
|
||||||
|
|
||||||
|
Q_ASSERT(compositor);
|
||||||
|
Q_ASSERT(surface);
|
||||||
|
|
||||||
|
compositor->m_data_device_manager->dataDevice()->sendDrop(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compositor::sendDataDeviceLeave(void *data, const QList<QVariant> ¶meters)
|
||||||
|
{
|
||||||
|
Compositor *compositor = static_cast<Compositor *>(data);
|
||||||
|
Surface *surface = resolveSurface(parameters.first());
|
||||||
|
|
||||||
|
Q_ASSERT(compositor);
|
||||||
|
Q_ASSERT(surface);
|
||||||
|
|
||||||
|
compositor->m_data_device_manager->dataDevice()->sendLeave(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compositor::waitForStartDrag(void *data, const QList<QVariant> ¶meters)
|
||||||
|
{
|
||||||
|
Compositor *compositor = static_cast<Compositor *>(data);
|
||||||
|
Q_ASSERT(compositor);
|
||||||
|
while (!compositor->m_startDragSeen) {
|
||||||
|
wl_display_flush_clients(compositor->m_display);
|
||||||
|
wl_event_loop_dispatch(compositor->m_loop, 100);
|
||||||
|
}
|
||||||
|
compositor->m_startDragSeen = false;
|
||||||
|
}
|
||||||
|
|
||||||
Seat::Seat(Compositor *compositor, struct ::wl_display *display)
|
Seat::Seat(Compositor *compositor, struct ::wl_display *display)
|
||||||
: wl_seat(display, 2)
|
: wl_seat(display, 2)
|
||||||
, m_compositor(compositor)
|
, m_compositor(compositor)
|
||||||
@ -312,18 +376,65 @@ void Touch::sendFrame(Surface *surface)
|
|||||||
wl_touch_send_frame(resource->handle);
|
wl_touch_send_frame(resource->handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataOffer::DataOffer()
|
||||||
|
: wl_data_offer()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
DataDevice::DataDevice(Compositor *compositor)
|
DataDevice::DataDevice(Compositor *compositor)
|
||||||
: wl_data_device()
|
: wl_data_device()
|
||||||
, m_compositor(compositor)
|
, m_compositor(compositor)
|
||||||
|
, m_dataOffer(nullptr)
|
||||||
|
, m_focus(nullptr)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataDevice::sendDataOffer(wl_client *client)
|
||||||
|
{
|
||||||
|
m_dataOffer = new QtWaylandServer::wl_data_offer(client, 0, 1);
|
||||||
|
Resource *resource = resourceMap().value(client);
|
||||||
|
send_data_offer(resource->handle, m_dataOffer->resource()->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataDevice::sendEnter(Surface *surface, const QPoint& position)
|
||||||
|
{
|
||||||
|
uint serial = m_compositor->nextSerial();
|
||||||
|
m_focus = surface;
|
||||||
|
Resource *resource = resourceMap().value(surface->resource()->client());
|
||||||
|
send_enter(resource->handle, serial, surface->resource()->handle, position.x(), position.y(), m_dataOffer->resource()->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataDevice::sendMotion(const QPoint &position)
|
||||||
|
{
|
||||||
|
uint32_t time = m_compositor->time();
|
||||||
|
Resource *resource = resourceMap().value(m_focus->resource()->client());
|
||||||
|
send_motion(resource->handle, time, position.x(), position.y());
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataDevice::sendDrop(Surface *surface)
|
||||||
|
{
|
||||||
|
Resource *resource = resourceMap().value(surface->resource()->client());
|
||||||
|
send_drop(resource->handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DataDevice::sendLeave(Surface *surface)
|
||||||
|
{
|
||||||
|
Resource *resource = resourceMap().value(surface->resource()->client());
|
||||||
|
send_leave(resource->handle);
|
||||||
|
}
|
||||||
|
|
||||||
DataDevice::~DataDevice()
|
DataDevice::~DataDevice()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataDevice::data_device_start_drag(QtWaylandServer::wl_data_device::Resource *resource, wl_resource *source, wl_resource *origin, wl_resource *icon, uint32_t serial)
|
||||||
|
{
|
||||||
|
m_compositor->m_startDragSeen = true;
|
||||||
|
}
|
||||||
|
|
||||||
DataDeviceManager::DataDeviceManager(Compositor *compositor, wl_display *display)
|
DataDeviceManager::DataDeviceManager(Compositor *compositor, wl_display *display)
|
||||||
: wl_data_device_manager(display, 1)
|
: wl_data_device_manager(display, 1)
|
||||||
, m_compositor(compositor)
|
, m_compositor(compositor)
|
||||||
@ -336,6 +447,11 @@ DataDeviceManager::~DataDeviceManager()
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DataDevice *DataDeviceManager::dataDevice() const
|
||||||
|
{
|
||||||
|
return m_data_device.data();
|
||||||
|
}
|
||||||
|
|
||||||
void DataDeviceManager::data_device_manager_get_data_device(Resource *resource, uint32_t id, struct ::wl_resource *seat)
|
void DataDeviceManager::data_device_manager_get_data_device(Resource *resource, uint32_t id, struct ::wl_resource *seat)
|
||||||
{
|
{
|
||||||
if (!m_data_device)
|
if (!m_data_device)
|
||||||
@ -343,4 +459,9 @@ void DataDeviceManager::data_device_manager_get_data_device(Resource *resource,
|
|||||||
m_data_device->add(resource->client(), id, 1);
|
m_data_device->add(resource->client(), id, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DataDeviceManager::data_device_manager_create_data_source(QtWaylandServer::wl_data_device_manager::Resource *resource, uint32_t id)
|
||||||
|
{
|
||||||
|
new QtWaylandServer::wl_data_source(resource->client(), id, 1);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -127,14 +127,30 @@ private:
|
|||||||
Compositor *m_compositor;
|
Compositor *m_compositor;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class DataOffer : public QtWaylandServer::wl_data_offer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DataOffer();
|
||||||
|
};
|
||||||
|
|
||||||
class DataDevice : public QtWaylandServer::wl_data_device
|
class DataDevice : public QtWaylandServer::wl_data_device
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DataDevice(Compositor *compositor);
|
DataDevice(Compositor *compositor);
|
||||||
|
void sendDataOffer(wl_client *client);
|
||||||
|
void sendEnter(Surface *surface, const QPoint &position);
|
||||||
|
void sendMotion(const QPoint &position);
|
||||||
|
void sendDrop(Surface *surface);
|
||||||
|
void sendLeave(Surface *surface);
|
||||||
~DataDevice();
|
~DataDevice();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void data_device_start_drag(Resource *resource, struct ::wl_resource *source, struct ::wl_resource *origin, struct ::wl_resource *icon, uint32_t serial) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Compositor *m_compositor;
|
Compositor *m_compositor;
|
||||||
|
QtWaylandServer::wl_data_offer *m_dataOffer;
|
||||||
|
Surface* m_focus;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DataDeviceManager : public QtWaylandServer::wl_data_device_manager
|
class DataDeviceManager : public QtWaylandServer::wl_data_device_manager
|
||||||
@ -142,9 +158,11 @@ class DataDeviceManager : public QtWaylandServer::wl_data_device_manager
|
|||||||
public:
|
public:
|
||||||
DataDeviceManager(Compositor *compositor, struct ::wl_display *display);
|
DataDeviceManager(Compositor *compositor, struct ::wl_display *display);
|
||||||
~DataDeviceManager();
|
~DataDeviceManager();
|
||||||
|
DataDevice *dataDevice() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void data_device_manager_get_data_device(Resource *resource, uint32_t id, struct ::wl_resource *seat) Q_DECL_OVERRIDE;
|
void data_device_manager_get_data_device(Resource *resource, uint32_t id, struct ::wl_resource *seat) Q_DECL_OVERRIDE;
|
||||||
|
void data_device_manager_create_data_source(Resource *resource, uint32_t id) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Compositor *m_compositor;
|
Compositor *m_compositor;
|
||||||
|
@ -36,6 +36,10 @@
|
|||||||
#include <QBackingStore>
|
#include <QBackingStore>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QScreen>
|
#include <QScreen>
|
||||||
|
#include <QWindow>
|
||||||
|
#include <QMimeData>
|
||||||
|
#include <QPixmap>
|
||||||
|
#include <QDrag>
|
||||||
|
|
||||||
#include <QtTest/QtTest>
|
#include <QtTest/QtTest>
|
||||||
|
|
||||||
@ -141,6 +145,8 @@ private slots:
|
|||||||
void createDestroyWindow();
|
void createDestroyWindow();
|
||||||
void events();
|
void events();
|
||||||
void backingStore();
|
void backingStore();
|
||||||
|
void touchDrag();
|
||||||
|
void mouseDrag();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MockCompositor *compositor;
|
MockCompositor *compositor;
|
||||||
@ -251,6 +257,86 @@ void tst_WaylandClient::backingStore()
|
|||||||
QTRY_VERIFY(surface->image.isNull());
|
QTRY_VERIFY(surface->image.isNull());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DndWindow : public QWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
DndWindow(QWindow *parent = 0)
|
||||||
|
: QWindow(parent)
|
||||||
|
, dragStarted(false)
|
||||||
|
{
|
||||||
|
QImage cursorImage(64,64,QImage::Format_ARGB32);
|
||||||
|
cursorImage.fill(Qt::blue);
|
||||||
|
m_dragIcon = QPixmap::fromImage(cursorImage);
|
||||||
|
}
|
||||||
|
~DndWindow(){}
|
||||||
|
bool dragStarted;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void mousePressEvent(QMouseEvent *event) Q_DECL_OVERRIDE
|
||||||
|
{
|
||||||
|
if (dragStarted)
|
||||||
|
return;
|
||||||
|
dragStarted = true;
|
||||||
|
|
||||||
|
QByteArray dataBytes;
|
||||||
|
QMimeData *mimeData = new QMimeData;
|
||||||
|
mimeData->setData("application/x-dnditemdata", dataBytes);
|
||||||
|
QDrag *drag = new QDrag(this);
|
||||||
|
drag->setMimeData(mimeData);
|
||||||
|
drag->setPixmap(m_dragIcon);
|
||||||
|
drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction);
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
QPixmap m_dragIcon;
|
||||||
|
};
|
||||||
|
|
||||||
|
void tst_WaylandClient::touchDrag()
|
||||||
|
{
|
||||||
|
DndWindow window;
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
QSharedPointer<MockSurface> surface;
|
||||||
|
QTRY_VERIFY(surface = compositor->surface());
|
||||||
|
|
||||||
|
compositor->setKeyboardFocus(surface);
|
||||||
|
QTRY_COMPARE(QGuiApplication::focusWindow(), &window);
|
||||||
|
|
||||||
|
const int id = 0;
|
||||||
|
compositor->sendTouchDown(surface, QPoint(10, 10), id);
|
||||||
|
compositor->sendTouchMotion(surface, QPoint(20, 20), id);
|
||||||
|
compositor->sendTouchFrame(surface);
|
||||||
|
compositor->waitForStartDrag();
|
||||||
|
compositor->sendDataDeviceDataOffer(surface);
|
||||||
|
compositor->sendDataDeviceEnter(surface, QPoint(20, 20));
|
||||||
|
compositor->sendDataDeviceMotion( QPoint(21, 21));
|
||||||
|
compositor->sendDataDeviceDrop(surface);
|
||||||
|
compositor->sendDataDeviceLeave(surface);
|
||||||
|
QTRY_VERIFY(window.dragStarted);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tst_WaylandClient::mouseDrag()
|
||||||
|
{
|
||||||
|
DndWindow window;
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
QSharedPointer<MockSurface> surface;
|
||||||
|
QTRY_VERIFY(surface = compositor->surface());
|
||||||
|
|
||||||
|
compositor->setKeyboardFocus(surface);
|
||||||
|
QTRY_COMPARE(QGuiApplication::focusWindow(), &window);
|
||||||
|
|
||||||
|
compositor->sendMousePress(surface, QPoint(10, 10));
|
||||||
|
compositor->sendDataDeviceDataOffer(surface);
|
||||||
|
compositor->sendDataDeviceEnter(surface, QPoint(20, 20));
|
||||||
|
compositor->sendDataDeviceMotion( QPoint(21, 21));
|
||||||
|
compositor->waitForStartDrag();
|
||||||
|
compositor->sendDataDeviceDrop(surface);
|
||||||
|
compositor->sendDataDeviceLeave(surface);
|
||||||
|
QTRY_VERIFY(window.dragStarted);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
setenv("XDG_RUNTIME_DIR", ".", 1);
|
setenv("XDG_RUNTIME_DIR", ".", 1);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user