diff --git a/x11-misc/copyq/copyq-9.1.0-r1.ebuild b/x11-misc/copyq/copyq-9.1.0-r1.ebuild new file mode 100644 index 000000000000..1f329cbc2b3d --- /dev/null +++ b/x11-misc/copyq/copyq-9.1.0-r1.ebuild @@ -0,0 +1,104 @@ +# Copyright 1999-2025 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +EAPI=8 + +inherit cmake optfeature virtualx xdg + +DESCRIPTION="Clipboard manager with advanced features" +HOMEPAGE="https://hluk.github.io/CopyQ/ https://github.com/hluk/CopyQ/" +SRC_URI="https://github.com/hluk/${PN}/archive/v${PV}.tar.gz -> ${P}.tar.gz" +S="${WORKDIR}/CopyQ-${PV}" + +LICENSE="GPL-3+" +SLOT="0" +KEYWORDS="~amd64 ~arm64 ~x86 ~amd64-linux ~x86-linux" +IUSE="notification test X" + +RESTRICT="!test? ( test )" + +RDEPEND=" + dev-libs/wayland + dev-qt/qtbase:6[gui,network,widgets,xml(+)] + dev-qt/qtdeclarative:6 + dev-qt/qtsvg:6 + dev-qt/qtwayland:6 + X? ( + dev-qt/qtbase:6=[X] + x11-libs/libX11 + x11-libs/libXfixes + x11-libs/libXtst + ) + notification? ( + kde-frameworks/knotifications:6 + kde-frameworks/kstatusnotifieritem:6 + ) +" +DEPEND="${RDEPEND} + X? ( x11-base/xorg-proto ) +" +BDEPEND=" + kde-frameworks/extra-cmake-modules:0 + dev-qt/qttools:6[linguist] + dev-util/wayland-scanner + test? ( + app-crypt/gnupg + x11-wm/openbox + ) +" + +PATCHES=( + # used in tests + "${FILESDIR}/${PN}-7.1.0-support-plugin-dir-envvar-r1.patch" + # + "${FILESDIR}/${PN}-9.1.0-qt-6.9.patch" +) + +src_configure() { + local mycmakeargs=( + -DWITH_QT6=ON + -DPLUGIN_INSTALL_PREFIX="${EPREFIX}/usr/$(get_libdir)/${PN}/plugins" + -DWITH_NATIVE_NOTIFICATIONS=$(usex notification) + -DWITH_TESTS=$(usex test) + -DWITH_X11=$(usex X) + ) + + cmake_src_configure +} + +my_src_test() { + # Don't rerun tests and more logs + local -x COPYQ_TESTS_RERUN_FAILED=0 + local -x COPYQ_LOG_LEVEL=DEBUG + + # Skip test that require network + local -x COPYQ_TESTS_NO_NETWORK=1 + + # Less noise from trying the wayland plugin + local -x QT_QPA_PLATFORM=xcb + + # Make sure copyq doesn't use system installed plugins which may be incompatible. + local -x COPYQ_PLUGIN_DIR="${BUILD_DIR}/plugins" + + # In case the users current system confuses the notification integration + unset KDE_FULL_SESSION XDG_CURRENT_DESKTOP + + mkdir "${HOME}"/.gnupg || die + + ebegin "Starting Openbox" + openbox & # upstream uses Openbox and it doesn't fail like IceWM + sleep 5 + eend 0 + + "${BUILD_DIR}"/copyq tests +} + +src_test() { + # local -x QT_QPA_PLATFORM=offscreen # TODO: make it work + virtx my_src_test +} + +pkg_postinst() { + xdg_pkg_postinst + optfeature "encryption support" app-crypt/gnupg +} diff --git a/x11-misc/copyq/files/copyq-9.1.0-qt-6.9.patch b/x11-misc/copyq/files/copyq-9.1.0-qt-6.9.patch new file mode 100644 index 000000000000..d1753a93bad9 --- /dev/null +++ b/x11-misc/copyq/files/copyq-9.1.0-qt-6.9.patch @@ -0,0 +1,413 @@ +https://github.com/hluk/CopyQ/commit/f08c0d46a239362c5d3525ef9c3ba943bb00f734 +https://bugs.gentoo.org/958277#c5 + +commit 7f1de919d2f6c3a84041d8f8afeff02a17290e16 +Author: Lukas Holecek +Date: Mon Apr 7 11:50:05 2025 +0200 + + Fix QChar construction for Qt 6.9 + +diff --git a/plugins/itemencrypted/itemencrypted.cpp b/plugins/itemencrypted/itemencrypted.cpp +index 666dedde..73f47017 100644 +--- a/plugins/itemencrypted/itemencrypted.cpp ++++ b/plugins/itemencrypted/itemencrypted.cpp +@@ -13,6 +13,7 @@ + #include "common/textdata.h" + #include "gui/icons.h" + #include "gui/iconwidget.h" ++#include "gui/fromiconid.h" + #include "item/serialize.h" + + #ifdef HAS_TESTS +@@ -859,7 +860,7 @@ QVector ItemEncryptedLoader::commands() const + Command c; + c.internalId = QStringLiteral("copyq_encrypted_encrypt"); + c.name = ItemEncryptedLoader::tr("Encrypt (needs GnuPG)"); +- c.icon = QString(QChar(IconLock)); ++ c.icon = fromIconId(IconLock); + c.input = "!OUTPUT"; + c.output = mimeEncryptedData; + c.inMenu = true; +@@ -870,7 +871,7 @@ QVector ItemEncryptedLoader::commands() const + c = Command(); + c.internalId = QStringLiteral("copyq_encrypted_decrypt"); + c.name = ItemEncryptedLoader::tr("Decrypt"); +- c.icon = QString(QChar(IconUnlock)); ++ c.icon = fromIconId(IconUnlock); + c.input = mimeEncryptedData; + c.output = mimeItems; + c.inMenu = true; +@@ -881,7 +882,7 @@ QVector ItemEncryptedLoader::commands() const + c = Command(); + c.internalId = QStringLiteral("copyq_encrypted_decrypt_and_copy"); + c.name = ItemEncryptedLoader::tr("Decrypt and Copy"); +- c.icon = QString(QChar(IconUnlockKeyhole)); ++ c.icon = fromIconId(IconUnlockKeyhole); + c.input = mimeEncryptedData; + c.inMenu = true; + c.cmd = "copyq: plugins.itemencrypted.copyEncryptedItems()"; +@@ -891,7 +892,7 @@ QVector ItemEncryptedLoader::commands() const + c = Command(); + c.internalId = QStringLiteral("copyq_encrypted_decrypt_and_paste"); + c.name = ItemEncryptedLoader::tr("Decrypt and Paste"); +- c.icon = QString(QChar(IconUnlockKeyhole)); ++ c.icon = fromIconId(IconUnlockKeyhole); + c.input = mimeEncryptedData; + c.inMenu = true; + c.cmd = "copyq: plugins.itemencrypted.pasteEncryptedItems()"; +diff --git a/plugins/itemfakevim/fakevim/fakevimhandler.cpp b/plugins/itemfakevim/fakevim/fakevimhandler.cpp +index c28d2504..4205b1cc 100644 +--- a/plugins/itemfakevim/fakevim/fakevimhandler.cpp ++++ b/plugins/itemfakevim/fakevim/fakevimhandler.cpp +@@ -1033,7 +1033,7 @@ QString quoteUnprintable(const QString &ba) + else if (cc == '\n') + res += ""; + else +- res += QString("\\x%1").arg(c.unicode(), 2, 16, QLatin1Char('0')); ++ res += QString("\\x%1").arg(cc, 2, 16, QLatin1Char('0')); + } + return res; + } +diff --git a/plugins/itempinned/itempinned.cpp b/plugins/itempinned/itempinned.cpp +index eb2518d1..19098149 100644 +--- a/plugins/itempinned/itempinned.cpp ++++ b/plugins/itempinned/itempinned.cpp +@@ -5,6 +5,7 @@ + #include "common/command.h" + #include "common/contenttype.h" + #include "common/display.h" ++#include "gui/fromiconid.h" + + #ifdef HAS_TESTS + # include "tests/itempinnedtests.h" +@@ -32,7 +33,7 @@ bool isPinned(const QModelIndex &index) + Command dummyPinCommand() + { + Command c; +- c.icon = QString(QChar(IconThumbtack)); ++ c.icon = fromIconId(IconThumbtack); + c.inMenu = true; + return c; + } +diff --git a/plugins/itemsync/itemsync.cpp b/plugins/itemsync/itemsync.cpp +index 8d3466d7..77c73bea 100644 +--- a/plugins/itemsync/itemsync.cpp ++++ b/plugins/itemsync/itemsync.cpp +@@ -15,6 +15,7 @@ + #include "gui/icons.h" + #include "gui/iconfont.h" + #include "gui/iconwidget.h" ++#include "gui/fromiconid.h" + #include "item/itemfilter.h" + + #ifdef HAS_TESTS +@@ -100,7 +101,7 @@ void writeConfiguration(QIODevice *file, const QStringList &savedFiles) + + QString iconFromId(int id) + { +- return id != -1 ? QString(QChar(id)) : QString(); ++ return id != -1 ? fromIconId(id) : QString(); + } + + QPushButton *createBrowseButton() +diff --git a/plugins/itemtags/itemtags.cpp b/plugins/itemtags/itemtags.cpp +index fe2a2f4c..d86dd908 100644 +--- a/plugins/itemtags/itemtags.cpp ++++ b/plugins/itemtags/itemtags.cpp +@@ -10,6 +10,7 @@ + #include "common/textdata.h" + #include "gui/iconfont.h" + #include "gui/iconselectbutton.h" ++#include "gui/fromiconid.h" + #include "gui/pixelratio.h" + #include "item/itemfilter.h" + +@@ -153,7 +154,7 @@ QString removeTagText() + Command dummyTagCommand() + { + Command c; +- c.icon = QString(QChar(IconTag)); ++ c.icon = fromIconId(IconTag); + c.inMenu = true; + return c; + } +diff --git a/src/common/globalshortcutcommands.cpp b/src/common/globalshortcutcommands.cpp +index 4bb8b756..d0b7eeeb 100644 +--- a/src/common/globalshortcutcommands.cpp ++++ b/src/common/globalshortcutcommands.cpp +@@ -3,6 +3,7 @@ + #include "globalshortcutcommands.h" + + #include "common/command.h" ++#include "gui/fromiconid.h" + + #include + #include +@@ -50,7 +51,7 @@ Command createGlobalShortcut(const QString &name, const QString &script, IconId + c.internalId = internalId; + c.name = name; + c.cmd = "copyq: " + script; +- c.icon = QString(QChar(icon)); ++ c.icon = fromIconId(icon); + c.isGlobalShortcut = true; + return c; + } +diff --git a/src/common/predefinedcommands.cpp b/src/common/predefinedcommands.cpp +index 236755aa..08ab0ffb 100644 +--- a/src/common/predefinedcommands.cpp ++++ b/src/common/predefinedcommands.cpp +@@ -8,6 +8,7 @@ + #include "common/shortcuts.h" + #include "common/textdata.h" + #include "gui/icons.h" ++#include "gui/fromiconid.h" + #include "platform/platformnativeinterface.h" + + #include +@@ -38,14 +39,14 @@ QVector predefinedCommands() + commands.prepend(Command()); + c = &commands.first(); + c->name = AddCommandDialog::tr("New command"); +- c->icon = QString(QChar(IconFile)); ++ c->icon = fromIconId(IconFile); + c->input = c->output = QString(); + c->wait = c->automatic = c->remove = false; + c->sep = QLatin1String("\\n"); + + c = newCommand(&commands); + c->name = AddCommandDialog::tr("Ignore items with no or single character"); +- c->icon = QString(QChar(IconCircleExclamation)); ++ c->icon = fromIconId(IconCircleExclamation); + c->cmd = R"(function hasEmptyOrSingleCharText() { + if (dataFormats().includes(mimeText)) { + var text = str(data(mimeText)); +@@ -83,7 +84,7 @@ synchronizeToSelection = function() { + c = newCommand(&commands); + c->name = AddCommandDialog::tr("Open in &Browser"); + c->re = reURL; +- c->icon = QString(QChar(IconGlobe)); ++ c->icon = fromIconId(IconGlobe); + c->cmd = QStringLiteral("copyq open %1"); + c->hideWindow = true; + c->inMenu = true; +@@ -91,7 +92,7 @@ synchronizeToSelection = function() { + c = newCommand(&commands); + c->name = AddCommandDialog::tr("Paste as Plain Text"); + c->input = mimeText; +- c->icon = QString(QChar(IconPaste)); ++ c->icon = fromIconId(IconPaste); + c->cmd = QStringLiteral("copyq:") + pasteAsPlainTextScript("input()"); + c->hideWindow = true; + c->inMenu = true; +@@ -99,7 +100,7 @@ synchronizeToSelection = function() { + c = newCommand(&commands); + c->name = AddCommandDialog::tr("Autoplay videos"); + c->re = QRegularExpression("^http://.*\\.(mp4|avi|mkv|wmv|flv|ogv)$"); +- c->icon = QString(QChar(IconCirclePlay)); ++ c->icon = fromIconId(IconCirclePlay); + c->cmd = QStringLiteral("copyq open %1"); + c->automatic = true; + c->hideWindow = true; +@@ -108,13 +109,13 @@ synchronizeToSelection = function() { + c = newCommand(&commands); + c->name = AddCommandDialog::tr("Copy URL (web address) to other tab"); + c->re = reURL; +- c->icon = QString(QChar(IconCopy)); ++ c->icon = fromIconId(IconCopy); + c->tab = QStringLiteral("&web"); + c->automatic = true; + + c = newCommand(&commands); + c->name = AddCommandDialog::tr("Create thumbnail (needs ImageMagick)"); +- c->icon = QString(QChar(IconImage)); ++ c->icon = fromIconId(IconImage); + c->cmd = QStringLiteral("convert - -resize 92x92 png:-"); + c->input = QStringLiteral("image/png"); + c->output = QStringLiteral("image/png"); +@@ -123,7 +124,7 @@ synchronizeToSelection = function() { + c = newCommand(&commands); + c->name = AddCommandDialog::tr("Create QR Code from URL (needs qrencode)"); + c->re = reURL; +- c->icon = QString(QChar(IconQrcode)); ++ c->icon = fromIconId(IconQrcode); + c->cmd = QStringLiteral("qrencode -o - -t PNG -s 6"); + c->input = mimeText; + c->output = QStringLiteral("image/png"); +@@ -134,7 +135,7 @@ synchronizeToSelection = function() { + c = newCommand(&commands); + c->name = AddCommandDialog::tr("Add to %1 tab", "%1 is quoted Tasks tab name") + .arg(todoTabQuoted); +- c->icon = QString(QChar(IconShare)); ++ c->icon = fromIconId(IconShare); + c->tab = todoTab; + c->input = mimeText; + c->inMenu = true; +@@ -142,7 +143,7 @@ synchronizeToSelection = function() { + c = newCommand(&commands); + c->name = AddCommandDialog::tr("Move to %1 tab", "%1 is quoted Tasks tab name") + .arg(todoTabQuoted); +- c->icon = QString(QChar(IconShare)); ++ c->icon = fromIconId(IconShare); + c->tab = todoTab; + c->remove = true; + c->inMenu = true; +@@ -150,7 +151,7 @@ synchronizeToSelection = function() { + c = newCommand(&commands); + c->name = AddCommandDialog::tr("Ignore copied files"); + c->re = reNotURL; +- c->icon = QString(QChar(IconCircleExclamation)); ++ c->icon = fromIconId(IconCircleExclamation); + c->input = mimeUriList; + c->remove = true; + c->automatic = true; +@@ -159,7 +160,7 @@ synchronizeToSelection = function() { + c = newCommand(&commands); + c->name = AddCommandDialog::tr("Ignore *\"Password\"* window"); + c->wndre = QRegularExpression(AddCommandDialog::tr("Password")); +- c->icon = QString(QChar(IconAsterisk)); ++ c->icon = fromIconId(IconAsterisk); + c->remove = true; + c->automatic = true; + c->cmd = QStringLiteral("copyq ignore"); +@@ -167,14 +168,14 @@ synchronizeToSelection = function() { + + c = newCommand(&commands); + c->name = AddCommandDialog::tr("Move to Trash"); +- c->icon = QString(QChar(IconTrash)); ++ c->icon = fromIconId(IconTrash); + c->inMenu = true; + c->tab = AddCommandDialog::tr("(trash)"); + c->remove = true; + + c = newCommand(&commands); + c->name = AddCommandDialog::tr("Clear Current Tab"); +- c->icon = QString(QChar(IconBroom)); ++ c->icon = fromIconId(IconBroom); + c->inMenu = true; + c->cmd = QStringLiteral("copyq: ItemSelection(selectedTab()).selectRemovable().removeAll()"); + c->matchCmd = QStringLiteral("copyq: tab(selectedTab()); if (size() == 0) fail()"); +diff --git a/src/gui/commanddialog.cpp b/src/gui/commanddialog.cpp +index 2ac1355e..86dd29b1 100644 +--- a/src/gui/commanddialog.cpp ++++ b/src/gui/commanddialog.cpp +@@ -13,6 +13,7 @@ + #include "gui/commandwidget.h" + #include "gui/iconfactory.h" + #include "gui/icons.h" ++#include "gui/fromiconid.h" + #include "platform/platformclipboard.h" + #include "platform/platformnativeinterface.h" + +@@ -48,7 +49,7 @@ QIcon getCommandIcon(const QString &iconString, int commandType) + : commandType & CommandType::Menu ? QColor(100,220,255) + : QColor(255,100,100); + +- return iconFromFile(iconString, QString(QChar(icon)), color); ++ return iconFromFile(iconString, fromIconId(icon), color); + } + + bool hasCommandsToPaste(const QString &text) +diff --git a/src/gui/fromiconid.h b/src/gui/fromiconid.h +new file mode 100644 +index 00000000..e00104b2 +--- /dev/null ++++ b/src/gui/fromiconid.h +@@ -0,0 +1,9 @@ ++// SPDX-License-Identifier: GPL-3.0-or-later ++#pragma once ++ ++#include ++#include ++ ++inline QString fromIconId(int id) { ++ return QString(QChar(id)); ++} +diff --git a/src/gui/iconfactory.cpp b/src/gui/iconfactory.cpp +index b0cfcf3b..df28a4f4 100644 +--- a/src/gui/iconfactory.cpp ++++ b/src/gui/iconfactory.cpp +@@ -3,8 +3,8 @@ + #include "iconfactory.h" + + #include "gui/fix_icon_id.h" +-#include "gui/icons.h" + #include "gui/iconfont.h" ++#include "gui/fromiconid.h" + #include "gui/pixelratio.h" + + #include +@@ -265,7 +265,7 @@ QPixmap drawFontIcon(ushort id, int w, int h, const QColor &color) + + // Center the icon to whole pixels so it stays sharp. + const auto flags = Qt::AlignTop | Qt::AlignLeft; +- const auto iconText = QString(QChar(id)); ++ const auto iconText = fromIconId(id); + auto boundingRect = painter.boundingRect(0, 0, w, h, flags, iconText); + const auto x = w - boundingRect.width(); + // If icon is wider, assume that a tag will be rendered and align image to the right. +diff --git a/src/gui/iconselectbutton.cpp b/src/gui/iconselectbutton.cpp +index e26eaeff..4fc8c0fb 100644 +--- a/src/gui/iconselectbutton.cpp ++++ b/src/gui/iconselectbutton.cpp +@@ -7,7 +7,7 @@ + #include "gui/fix_icon_id.h" + #include "gui/iconfont.h" + #include "gui/iconselectdialog.h" +-#include "gui/icons.h" ++#include "gui/fromiconid.h" + + #include + #include +@@ -40,7 +40,7 @@ void IconSelectButton::setCurrentIcon(const QString &iconString) + if ( iconString.size() == 1 ) { + const QChar c = iconString[0]; + const ushort id = fixIconId( c.unicode() ); +- m_currentIcon = QString(QChar(id)); ++ m_currentIcon = fromIconId(id); + setFont(iconFont()); + setText(m_currentIcon); + } else if ( !iconString.isEmpty() ) { +diff --git a/src/gui/notificationbasic.cpp b/src/gui/notificationbasic.cpp +index ed688f39..13a98528 100644 +--- a/src/gui/notificationbasic.cpp ++++ b/src/gui/notificationbasic.cpp +@@ -8,7 +8,7 @@ + #include "common/textdata.h" + #include "common/timer.h" + #include "gui/iconfactory.h" +-#include "gui/icons.h" ++#include "gui/fromiconid.h" + #include "gui/pixelratio.h" + + #include +@@ -230,7 +230,7 @@ void NotificationBasicWidget::setIcon(const QString &icon) + + void NotificationBasicWidget::setIcon(ushort icon) + { +- m_icon = QString(QChar(icon)); ++ m_icon = fromIconId(icon); + } + + void NotificationBasicWidget::setInterval(int msec) +diff --git a/src/scriptable/scriptable.cpp b/src/scriptable/scriptable.cpp +index 8893140c..7d5fd294 100644 +--- a/src/scriptable/scriptable.cpp ++++ b/src/scriptable/scriptable.cpp +@@ -14,6 +14,7 @@ + #include "common/textdata.h" + #include "gui/clipboardspy.h" + #include "gui/icons.h" ++#include "gui/fromiconid.h" + #include "item/itemfactory.h" + #include "item/serialize.h" + #include "platform/platformclipboard.h" +@@ -2912,7 +2913,7 @@ void Scriptable::showExceptionMessage(const QString &message) + QtPrivate::QHashCombine hash; + const auto id = hash(hash(0, title), message); + const auto notificationId = QString::number(id); +- m_proxy->showMessage(title, message, QString(QChar(IconCircleExclamation)), 8000, notificationId); ++ m_proxy->showMessage(title, message, fromIconId(IconCircleExclamation), 8000, notificationId); + } + + QVector Scriptable::getRows() const +