|
Lines 16-21
Link Here
|
| 16 |
#include <QPointer> |
16 |
#include <QPointer> |
| 17 |
#include <QThread> |
17 |
#include <QThread> |
| 18 |
#include <QTimer> |
18 |
#include <QTimer> |
|
|
19 |
#include <QQueue> |
| 19 |
#include <QWaylandClientExtension> |
20 |
#include <QWaylandClientExtension> |
| 20 |
#include <QWindow> |
21 |
#include <QWindow> |
| 21 |
#include <QtWaylandClientVersion> |
22 |
#include <QtWaylandClientVersion> |
|
Lines 320-325
Link Here
|
| 320 |
|
321 |
|
| 321 |
Q_SIGNALS: |
322 |
Q_SIGNALS: |
| 322 |
void cancelled(); |
323 |
void cancelled(); |
|
|
324 |
void dataSendingCompleted(); |
| 323 |
|
325 |
|
| 324 |
protected: |
326 |
protected: |
| 325 |
void ext_data_control_source_v1_send(const QString &mime_type, int32_t fd) override; |
327 |
void ext_data_control_source_v1_send(const QString &mime_type, int32_t fd) override; |
|
Lines 394-399
Link Here
|
| 394 |
break; |
396 |
break; |
| 395 |
} |
397 |
} |
| 396 |
close(fd); |
398 |
close(fd); |
|
|
399 |
|
| 400 |
Q_EMIT dataSendingCompleted(); |
| 397 |
} |
401 |
} |
| 398 |
|
402 |
|
| 399 |
void DataControlSource::ext_data_control_source_v1_cancelled() |
403 |
void DataControlSource::ext_data_control_source_v1_cancelled() |
|
Lines 578-583
Link Here
|
| 578 |
wl_display *m_display = nullptr; |
582 |
wl_display *m_display = nullptr; |
| 579 |
}; |
583 |
}; |
| 580 |
|
584 |
|
|
|
585 |
class ClipboardProcessingQueue : public QObject |
| 586 |
{ |
| 587 |
Q_OBJECT |
| 588 |
public: |
| 589 |
explicit ClipboardProcessingQueue(WaylandClipboard &wclip, QObject *parent = nullptr); |
| 590 |
~ClipboardProcessingQueue(); |
| 591 |
|
| 592 |
void addMimeData(QMimeData *data); |
| 593 |
void stop(); |
| 594 |
|
| 595 |
private Q_SLOTS: |
| 596 |
void processNext(); |
| 597 |
|
| 598 |
private: |
| 599 |
QThread m_th; |
| 600 |
QMutex m_mtx; |
| 601 |
QQueue<QMimeData*> m_queue; |
| 602 |
WaylandClipboard &m_wclip; |
| 603 |
bool m_stopped = false; |
| 604 |
bool m_processing = false; |
| 605 |
QEventLoop *m_waitLoop = nullptr; |
| 606 |
}; |
| 607 |
|
| 608 |
ClipboardProcessingQueue::ClipboardProcessingQueue(WaylandClipboard &wclip, QObject *parent) |
| 609 |
: QObject(parent) |
| 610 |
, m_wclip(wclip) |
| 611 |
{ |
| 612 |
moveToThread(&m_th); |
| 613 |
m_th.start(); |
| 614 |
} |
| 615 |
|
| 616 |
ClipboardProcessingQueue::~ClipboardProcessingQueue() |
| 617 |
{ |
| 618 |
if (m_th.isRunning()) { |
| 619 |
m_th.quit(); |
| 620 |
m_th.wait(); |
| 621 |
} |
| 622 |
} |
| 623 |
|
| 624 |
void ClipboardProcessingQueue::addMimeData(QMimeData *data) |
| 625 |
{ |
| 626 |
QMutexLocker locker(&m_mtx); |
| 627 |
m_queue.enqueue(data); |
| 628 |
if (!m_processing) { |
| 629 |
QMetaObject::invokeMethod(this, "processNext", Qt::QueuedConnection); |
| 630 |
} |
| 631 |
} |
| 632 |
|
| 633 |
void ClipboardProcessingQueue::stop() |
| 634 |
{ |
| 635 |
QMutexLocker locker(&m_mtx); |
| 636 |
m_stopped = true; |
| 637 |
|
| 638 |
if (m_waitLoop && m_waitLoop->isRunning()) { |
| 639 |
QMetaObject::invokeMethod(this, [this]{ |
| 640 |
m_waitLoop->quit(); |
| 641 |
}, Qt::QueuedConnection); |
| 642 |
} |
| 643 |
} |
| 644 |
|
| 645 |
void ClipboardProcessingQueue::processNext() |
| 646 |
{ |
| 647 |
if (m_stopped) { |
| 648 |
return; |
| 649 |
} |
| 650 |
|
| 651 |
QMimeData *mime = nullptr; |
| 652 |
{ |
| 653 |
QMutexLocker locker(&m_mtx); |
| 654 |
if (m_queue.isEmpty() || m_processing) { |
| 655 |
return; |
| 656 |
} |
| 657 |
mime = m_queue.dequeue(); |
| 658 |
m_processing = true; |
| 659 |
} |
| 660 |
|
| 661 |
if (mime) { |
| 662 |
auto &device = m_wclip.m_device; |
| 663 |
auto &manager = m_wclip.m_manager; |
| 664 |
auto source = std::make_unique<DataControlSource>(manager->create_data_source(), mime); |
| 665 |
source->moveToThread(m_wclip.m_thread.get()); |
| 666 |
|
| 667 |
auto *sourcePtr = source.get(); |
| 668 |
device->setSelection(std::move(source)); |
| 669 |
|
| 670 |
QEventLoop loop; |
| 671 |
m_waitLoop = &loop; |
| 672 |
connect(sourcePtr, &DataControlSource::dataSendingCompleted, &loop, &QEventLoop::quit); |
| 673 |
connect(sourcePtr, &DataControlSource::cancelled, &loop, &QEventLoop::quit); |
| 674 |
QTimer::singleShot(5000, &loop, &QEventLoop::quit); |
| 675 |
loop.exec(); |
| 676 |
m_waitLoop = nullptr; |
| 677 |
} |
| 678 |
|
| 679 |
{ |
| 680 |
QMutexLocker locker(&m_mtx); |
| 681 |
m_processing = false; |
| 682 |
} |
| 683 |
|
| 684 |
QMetaObject::invokeMethod(this, "processNext", Qt::QueuedConnection); |
| 685 |
} |
| 686 |
|
| 581 |
WaylandClipboard::WaylandClipboard(QObject *parent) |
687 |
WaylandClipboard::WaylandClipboard(QObject *parent) |
| 582 |
: KSystemClipboard(parent) |
688 |
: KSystemClipboard(parent) |
| 583 |
, m_manager(new DataControlDeviceManager) |
689 |
, m_manager(new DataControlDeviceManager) |
|
Lines 623-631
Link Here
|
| 623 |
connect(m_device.get(), &DataControlDevice::primarySelectionChanged, this, [this]() { |
729 |
connect(m_device.get(), &DataControlDevice::primarySelectionChanged, this, [this]() { |
| 624 |
Q_EMIT changed(QClipboard::Selection); |
730 |
Q_EMIT changed(QClipboard::Selection); |
| 625 |
}); |
731 |
}); |
|
|
732 |
|
| 733 |
m_dataQueue.reset(new ClipboardProcessingQueue(*this)); |
| 626 |
m_thread->start(); |
734 |
m_thread->start(); |
| 627 |
|
735 |
|
| 628 |
} else { |
736 |
} else { |
|
|
737 |
m_dataQueue.reset(); |
| 629 |
m_device.reset(); |
738 |
m_device.reset(); |
| 630 |
m_thread->wait(); |
739 |
m_thread->wait(); |
| 631 |
m_thread.reset(); |
740 |
m_thread.reset(); |
|
Lines 637-642
Link Here
|
| 637 |
|
746 |
|
| 638 |
WaylandClipboard::~WaylandClipboard() |
747 |
WaylandClipboard::~WaylandClipboard() |
| 639 |
{ |
748 |
{ |
|
|
749 |
if (m_dataQueue) { |
| 750 |
m_dataQueue->stop(); |
| 751 |
} |
| 640 |
if (m_thread && m_thread->isRunning()) { |
752 |
if (m_thread && m_thread->isRunning()) { |
| 641 |
m_thread->syncQueue(); |
753 |
m_thread->syncQueue(); |
| 642 |
m_thread->wait(); |
754 |
m_thread->wait(); |
|
Lines 664-669
Link Here
|
| 664 |
return; |
776 |
return; |
| 665 |
} |
777 |
} |
| 666 |
|
778 |
|
|
|
779 |
// Use only for clipboard insertion and if mime data contains an image |
| 780 |
if (mode == QClipboard::Clipboard && mime->hasImage()) { |
| 781 |
m_dataQueue->addMimeData(mime); |
| 782 |
return; |
| 783 |
} |
| 784 |
|
| 667 |
auto source = std::make_unique<DataControlSource>(m_manager->create_data_source(), mime); |
785 |
auto source = std::make_unique<DataControlSource>(m_manager->create_data_source(), mime); |
| 668 |
source->moveToThread(m_thread.get()); |
786 |
source->moveToThread(m_thread.get()); |
| 669 |
if (mode == QClipboard::Clipboard) { |
787 |
if (mode == QClipboard::Clipboard) { |