From dc7322cc4a08b64e72bf19e3b48502db682a65f6 Mon Sep 17 00:00:00 2001 From: Weslly Date: Mon, 20 Nov 2017 01:38:48 -0200 Subject: [PATCH 1/3] Improve macOS pasteboard handling --- src/CMakeLists.txt | 2 + src/core/MacPasteboard.cpp | 94 ++++++++++++++++++++++++++++++++++++++ src/core/MacPasteboard.h | 37 +++++++++++++++ src/gui/Clipboard.cpp | 11 +++++ 4 files changed, 144 insertions(+) create mode 100644 src/core/MacPasteboard.cpp create mode 100644 src/core/MacPasteboard.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 092a2102d..24742edef 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -155,6 +155,8 @@ if(APPLE) set(keepassx_SOURCES ${keepassx_SOURCES} core/ScreenLockListenerMac.h core/ScreenLockListenerMac.cpp + core/MacPasteboard.h + core/MacPasteboard.cpp ) endif() if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux") diff --git a/src/core/MacPasteboard.cpp b/src/core/MacPasteboard.cpp new file mode 100644 index 000000000..98dc6f7ab --- /dev/null +++ b/src/core/MacPasteboard.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "MacPasteboard.h" + +QString MacPasteboard::convertorName() { return QLatin1String("MacPasteboard"); } + +QString MacPasteboard::flavorFor(const QString& mimetype) { + if (mimetype == QLatin1String("text/plain")) { + return QLatin1String("public.utf8-plain-text"); + } else if (mimetype == QLatin1String("application/x-nspasteboard-concealed-type")) { + return QLatin1String("org.nspasteboard.ConcealedType"); + } + + int i = mimetype.indexOf(QLatin1String("charset=")); + + if (i >= 0) { + QString cs(mimetype.mid(i + 8).toLower()); + i = cs.indexOf(QLatin1Char(';')); + + if (i >= 0) { + cs = cs.left(i); + } + + if (cs == QLatin1String("system")) { + return QLatin1String("public.utf8-plain-text"); + } else if (cs == QLatin1String("iso-10646-ucs-2") || + cs == QLatin1String("utf16")) { + return QLatin1String("public.utf16-plain-text"); + } + } + return QString(); +} + +QString MacPasteboard::mimeFor(QString flavor) { + if (flavor == QLatin1String("public.utf8-plain-text")) + return QLatin1String("text/plain"); + if (flavor == QLatin1String("org.nspasteboard.ConcealedType")) + return QLatin1String("application/x-nspasteboard-concealed-type"); + if (flavor == QLatin1String("public.utf16-plain-text")) + return QLatin1String("text/plain;charset=utf16"); + return QString(); +} + +bool MacPasteboard::canConvert(const QString& mimetype, QString flavor) { + Q_UNUSED(mimetype); + Q_UNUSED(flavor); + return true; +} + +QVariant MacPasteboard::convertToMime(const QString& mimetype, QList data, QString flavor) { + if (data.count() > 1) + qWarning("QMime::convertToMime: Cannot handle multiple member data"); + const QByteArray& firstData = data.first(); + QVariant ret; + if (flavor == QLatin1String("public.utf8-plain-text")) { + ret = QString::fromUtf8(firstData); + } else if (flavor == QLatin1String("org.nspasteboard.ConcealedType")) { + ret = QString::fromUtf8(firstData); + } else if (flavor == QLatin1String("public.utf16-plain-text")) { + ret = QTextCodec::codecForName("UTF-16")->toUnicode(firstData); + } else { + qWarning("QMime::convertToMime: unhandled mimetype: %s", + qPrintable(mimetype)); + } + return ret; +} + +QList MacPasteboard::convertFromMime(const QString&, QVariant data, QString flavor) { + QList ret; + QString string = data.toString(); + if (flavor == QLatin1String("public.utf8-plain-text")) + ret.append(string.toUtf8()); + else if (flavor == QLatin1String("org.nspasteboard.ConcealedType")) + ret.append(string.toUtf8()); + else if (flavor == QLatin1String("public.utf16-plain-text")) + ret.append(QTextCodec::codecForName("UTF-16")->fromUnicode(string)); + return ret; +} + diff --git a/src/core/MacPasteboard.h b/src/core/MacPasteboard.h new file mode 100644 index 000000000..15e99616c --- /dev/null +++ b/src/core/MacPasteboard.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2017 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_MACPASTEBOARD_H +#define KEEPASSXC_MACPASTEBOARD_H + +#include +#include + +class MacPasteboard : public QMacPasteboardMime +{ +public: + explicit MacPasteboard() : QMacPasteboardMime(MIME_ALL) {} + + QString convertorName(); + bool canConvert(const QString &mime, QString flav); + QString mimeFor(QString flav); + QString flavorFor(const QString &mime); + QVariant convertToMime(const QString &mime, QList data, QString flav); + QList convertFromMime(const QString &mime, QVariant data, QString flav); +}; + +#endif // KEEPASSXC_MACPASTEBOARD_H diff --git a/src/gui/Clipboard.cpp b/src/gui/Clipboard.cpp index bf4db8ff5..a62385728 100644 --- a/src/gui/Clipboard.cpp +++ b/src/gui/Clipboard.cpp @@ -22,6 +22,9 @@ #include #include "core/Config.h" +#ifdef Q_OS_MAC +#include "core/MacPasteboard.h" +#endif Clipboard* Clipboard::m_instance(nullptr); @@ -38,10 +41,18 @@ void Clipboard::setText(const QString& text) { QClipboard* clipboard = QApplication::clipboard(); +#ifdef Q_OS_MAC + new MacPasteboard; + QMimeData* mime = new QMimeData; + mime->setText(text); + mime->setData("application/x-nspasteboard-concealed-type", text.toUtf8()); + clipboard->setMimeData(mime, QClipboard::Clipboard); +#else clipboard->setText(text, QClipboard::Clipboard); if (clipboard->supportsSelection()) { clipboard->setText(text, QClipboard::Selection); } +#endif if (config()->get("security/clearclipboard").toBool()) { int timeout = config()->get("security/clearclipboardtimeout").toInt(); From 806248ebd4a2ab68c159029ea94597c731c72414 Mon Sep 17 00:00:00 2001 From: Weslly Date: Mon, 20 Nov 2017 16:50:56 -0200 Subject: [PATCH 2/3] Review fixes --- src/core/MacPasteboard.h | 12 ++++++------ src/gui/Clipboard.cpp | 17 +++++++++++++---- src/gui/Clipboard.h | 7 +++++++ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/core/MacPasteboard.h b/src/core/MacPasteboard.h index 15e99616c..8461cbc5d 100644 --- a/src/core/MacPasteboard.h +++ b/src/core/MacPasteboard.h @@ -26,12 +26,12 @@ class MacPasteboard : public QMacPasteboardMime public: explicit MacPasteboard() : QMacPasteboardMime(MIME_ALL) {} - QString convertorName(); - bool canConvert(const QString &mime, QString flav); - QString mimeFor(QString flav); - QString flavorFor(const QString &mime); - QVariant convertToMime(const QString &mime, QList data, QString flav); - QList convertFromMime(const QString &mime, QVariant data, QString flav); + QString convertorName() override; + bool canConvert(const QString &mime, QString flav) override; + QString mimeFor(QString flav) override; + QString flavorFor(const QString &mime) override; + QVariant convertToMime(const QString &mime, QList data, QString flav) override; + QList convertFromMime(const QString &mime, QVariant data, QString flav) override; }; #endif // KEEPASSXC_MACPASTEBOARD_H diff --git a/src/gui/Clipboard.cpp b/src/gui/Clipboard.cpp index a62385728..a35f59b19 100644 --- a/src/gui/Clipboard.cpp +++ b/src/gui/Clipboard.cpp @@ -22,9 +22,6 @@ #include #include "core/Config.h" -#ifdef Q_OS_MAC -#include "core/MacPasteboard.h" -#endif Clipboard* Clipboard::m_instance(nullptr); @@ -33,16 +30,28 @@ Clipboard::Clipboard(QObject* parent) , m_timer(new QTimer(this)) { m_timer->setSingleShot(true); +#ifdef Q_OS_MAC + m_pasteboard = new MacPasteboard; +#endif + connect(m_timer, SIGNAL(timeout()), SLOT(clearClipboard())); connect(qApp, SIGNAL(aboutToQuit()), SLOT(clearCopiedText())); } +Clipboard::~Clipboard() +{ +#ifdef Q_OS_MAC + if (m_pasteboard) { + delete m_pasteboard; + } +#endif +} + void Clipboard::setText(const QString& text) { QClipboard* clipboard = QApplication::clipboard(); #ifdef Q_OS_MAC - new MacPasteboard; QMimeData* mime = new QMimeData; mime->setText(text); mime->setData("application/x-nspasteboard-concealed-type", text.toUtf8()); diff --git a/src/gui/Clipboard.h b/src/gui/Clipboard.h index e0a16d26d..68f4e0485 100644 --- a/src/gui/Clipboard.h +++ b/src/gui/Clipboard.h @@ -19,6 +19,9 @@ #define KEEPASSX_CLIPBOARD_H #include +#ifdef Q_OS_MAC +#include "core/MacPasteboard.h" +#endif class QTimer; @@ -28,6 +31,7 @@ class Clipboard : public QObject public: void setText(const QString& text); + ~Clipboard(); static Clipboard* instance(); @@ -43,6 +47,9 @@ private: static Clipboard* m_instance; QTimer* m_timer; +#ifdef Q_OS_MAC + MacPasteboard* m_pasteboard; +#endif QString m_lastCopied; }; From afe48da4b182e71b204d33c5f9a8f8d43cffc074 Mon Sep 17 00:00:00 2001 From: Weslly Date: Mon, 20 Nov 2017 17:25:27 -0200 Subject: [PATCH 3/3] Change MacPasteboard init object to QScopedPointer --- src/gui/Clipboard.cpp | 16 +++------------- src/gui/Clipboard.h | 3 +-- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/gui/Clipboard.cpp b/src/gui/Clipboard.cpp index a35f59b19..78bad2731 100644 --- a/src/gui/Clipboard.cpp +++ b/src/gui/Clipboard.cpp @@ -28,25 +28,15 @@ Clipboard* Clipboard::m_instance(nullptr); Clipboard::Clipboard(QObject* parent) : QObject(parent) , m_timer(new QTimer(this)) +#ifdef Q_OS_MAC + , m_pasteboard(new MacPasteboard) +#endif { m_timer->setSingleShot(true); -#ifdef Q_OS_MAC - m_pasteboard = new MacPasteboard; -#endif - connect(m_timer, SIGNAL(timeout()), SLOT(clearClipboard())); connect(qApp, SIGNAL(aboutToQuit()), SLOT(clearCopiedText())); } -Clipboard::~Clipboard() -{ -#ifdef Q_OS_MAC - if (m_pasteboard) { - delete m_pasteboard; - } -#endif -} - void Clipboard::setText(const QString& text) { QClipboard* clipboard = QApplication::clipboard(); diff --git a/src/gui/Clipboard.h b/src/gui/Clipboard.h index 68f4e0485..6f8ff9ace 100644 --- a/src/gui/Clipboard.h +++ b/src/gui/Clipboard.h @@ -31,7 +31,6 @@ class Clipboard : public QObject public: void setText(const QString& text); - ~Clipboard(); static Clipboard* instance(); @@ -48,7 +47,7 @@ private: QTimer* m_timer; #ifdef Q_OS_MAC - MacPasteboard* m_pasteboard; + QScopedPointer m_pasteboard; #endif QString m_lastCopied; };