Web lists-archives.com

Re: KDE (or X?) clipboard goes stupid




On Monday April 01 2019 13:53:18 Jerome Yuzyk wrote:

>Both X and KDE clipboards are messed again, after 57 days of uptime. Ctrl-X 
>will cut, but Ctrl-V pastes whatever was left by the last non-KDE Ctrl-V (like 
>from Chrome). The X clipboard is not filled by highlighting either. This 
>happens to the main KDE apps I use: KMail, Konqueror, Konsole, and KAlarm. It 
>does not happen to non-KDE apps like SeaMonkey or Chrome. It's damned annoying 
>and ongoing for years.

Now that's interesting: I'm seeing exactly the same thing when I run Qt5 apps under X11 on Mac. I've always written that off to something non-standard in XQuartz in combination with the fact that the xcb QPA is not officially supported on Mac. 

However, I find that I don't need to restart my entire X11 session, just restarting the affected Qt applications is enough.

I've never seen it under Linux before. I'm attaching a little patch I apply to Qt (5.9), in case you can build Qt yourself.  It doesn't solve anything but it helps to get some information about the error when the issue triggers. If you get comparable error output it would be good to file a bug report.

>From what I recall, Qt uses a hidden window that is opened just once that will act as the owner of clipboard content, so that that content can be removed when you quit the application. Something goes wrong at that level, causing our issue.

I've never really seen the point for making clipboard wiping-on-exit the default and GTk applications clearly have a different more robust way to do this :(

>Does anyone have any idea how to "reset" KDE's clipboard management without 
>logging in/out?

If indeed you have the same issue (and restarting affected applications fixes things) then it's not a KDE problem. BTW, the Plasma-devel ML may be a more appropriate place to discuss this, for the feature that's involved here, but also because there will be devs there who may actually understand the details of Qt's clipboard management.

R.
diff --git a/qtbase/src/plugins/platforms/xcb/qxcbclipboard.cpp b/qtbase/src/plugins/platforms/xcb/qxcbclipboard.cpp
index 01b3bca0d2b75752d4d2fdc1019e9b196778b870..cb9cd819fc807619b15cb04325c848289f66e6ab 100644
--- a/qtbase/src/plugins/platforms/xcb/qxcbclipboard.cpp
+++ b/qtbase/src/plugins/platforms/xcb/qxcbclipboard.cpp
@@ -52,6 +52,11 @@
 #include <xcb/xcb_icccm.h>
 #undef class
 
+#if QT_CONFIG(xcb_xlib)
+#include <X11/Xlib.h>
+#include <X11/Xlib-xcb.h>
+#endif
+
 QT_BEGIN_NAMESPACE
 
 #ifndef QT_NO_CLIPBOARD
@@ -292,8 +297,21 @@ QXcbClipboard::QXcbClipboard(QXcbConnection *c)
         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;
-        Q_XCB_CALL(xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, XCB_ATOM_PRIMARY, mask));
+        xcb_void_cookie_t cookie;
+        cookie = Q_XCB_CALL(xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, XCB_ATOM_PRIMARY, mask));
+        xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie);
+        if (error) {
+            qWarning() << "X11 error in xcb_xfixes_select_selection_input(..primary..)" << error->error_code << "opcode" << error->major_code << ":" << error->minor_code;
+            connection()->handleXcbError(error);
+            free(error);
+        }
         Q_XCB_CALL(xcb_xfixes_select_selection_input_checked(xcb_connection(), m_owner, atom(QXcbAtom::CLIPBOARD), mask));
+        error = xcb_request_check(xcb_connection(), cookie);
+        if (error) {
+            qWarning() << "X11 error in xcb_xfixes_select_selection_input(..clipboard..)" << error->error_code << "opcode" << error->major_code << ":" << error->minor_code;
+            connection()->handleXcbError(error);
+            free(error);
+        }
     }
 }
 
@@ -419,13 +437,40 @@ void QXcbClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
         m_timestamp[mode] = connection()->time();
     }
 
-    xcb_set_selection_owner(xcb_connection(), newOwner, modeAtom, connection()->time());
+    xcb_void_cookie_t cookie = xcb_set_selection_owner(xcb_connection(), newOwner, modeAtom, connection()->time());
+    xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie);
 
-    if (getSelectionOwner(modeAtom) != newOwner) {
+    if (getSelectionOwner(modeAtom) != newOwner || error) {
         qWarning("QXcbClipboard::setMimeData: Cannot set X11 selection owner");
+        qWarning() << "\tclipboard mode=" << mode << "connection=" << xcb_connection() << "time=" << connection()->time()
+            << "newOwner=" << newOwner << "effective owner:" << getSelectionOwner(modeAtom);
+        if (error) {
+            qWarning() << "\tX11 error" << error->error_code << "opcode" << error->major_code << ":" << error->minor_code;
+            connection()->handleXcbError(error);
+            free(error);
+        }
+        // adapted from QXcbClipboard::handleXFixesSelectionRequest(), in
+        // hope a full reset will clear the issue.
+        if (mode <= QClipboard::Selection) {
+            qWarning() << "\tattempting again after resetting the X clipboard";
+            m_xClipboard[mode].reset(new QXcbClipboardMime(mode, this));
+            cookie = xcb_set_selection_owner(xcb_connection(), newOwner, modeAtom, connection()->time());
+        }
+#if QT_CONFIG(xcb_xlib)
+        if (getSelectionOwner(modeAtom) != newOwner && data && data->hasText()) {
+            const QByteArray text(data->text().toLocal8Bit());
+            if (text.size()) {
+                qWarning() << "\tfallback: storing on X11 cutbuffer 0";
+                XStoreBuffer(DISPLAY_FROM_XCB(connection()), text.constData(), text.size(), 0);
+            }
+        }
+#endif
     }
 
-    emitChanged(mode);
+    // only emit the change if we set the owner successfully
+    if (getSelectionOwner(modeAtom) == newOwner) {
+        emitChanged(mode);
+    }
 }
 
 bool QXcbClipboard::supportsMode(QClipboard::Mode mode) const