commit cb0c881b0298ef6c54e0cc57dc6f2ef46716c7aa
Author: Enrico Forestieri <for...@lyx.org>
Date:   Sun Jul 10 19:31:32 2016 +0200

    Fix paste of selection to (unfocused) external applications
    
    With both Qt4 and Qt5, when using a click-to-focus policy, the first
    attempt to paste a selection by middle mouse in an external application
    which has no focus may fail. It is not clear why this succeeds for some
    applications and fails for others, but refreshing the timestamp of the
    selection request cures the issue. The cmake part is by Kornel.
    
    See also this thread:
    http://thread.gmane.org/gmane.editors.lyx.devel/162491
---
 CMakeLists.txt                          |    5 ---
 config/qt4.m4                           |   27 +++++++++++++++--
 development/cmake/ConfigureChecks.cmake |   27 +++++++++++++++++-
 src/frontends/qt4/GuiApplication.cpp    |   47 +++++++++++++++++++++++++++++-
 4 files changed, 94 insertions(+), 12 deletions(-)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 76cbdde..74d0ac8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -925,11 +925,6 @@ endif()
 include(${LYX_CMAKE_DIR}/ConfigureChecks.cmake)
 configure_file(${LYX_CMAKE_DIR}/configCompiler.h.cmake 
${TOP_BINARY_DIR}/configCompiler.h)
 
-set(QPA_XCB)
-if(Qt5X11Extras_FOUND AND QT_USES_X11)
-  # QPA_XCB is only valid if QT5+X11
-  set(QPA_XCB 1)
-endif()
 configure_file(${LYX_CMAKE_DIR}/config.h.cmake ${TOP_BINARY_DIR}/config.h)
 
 if(QTVERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+).*")
diff --git a/config/qt4.m4 b/config/qt4.m4
index 0e357a4..f39c0ed 100644
--- a/config/qt4.m4
+++ b/config/qt4.m4
@@ -172,18 +172,30 @@ AC_DEFUN([QT_DO_IT_ALL],
        [AC_MSG_ERROR([LyX requires at least version $1 of Qt. Only version 
$QTLIB_VERSION has been found.])
        ])
 
+       save_CPPFLAGS=$CPPFLAGS
+       AC_MSG_CHECKING([whether Qt uses the X Window system])
+       CPPFLAGS="$save_CPPFLAGS $QT_CORE_INCLUDES"
        if test x$USE_QT5 = xyes ; then
-         save_CPPFLAGS=$CPPFLAGS
-         AC_MSG_CHECKING([whether Qt uses the X Window system])
-         CPPFLAGS="$save_CPPFLAGS $QT_CORE_INCLUDES"
          AC_EGREP_CPP(xcb,
            [#include <qconfig.h>
            QT_QPA_DEFAULT_PLATFORM_NAME],
            [AC_MSG_RESULT(yes)
             AC_DEFINE(QPA_XCB, 1, [Define if Qt uses the X Window System])],
            [AC_MSG_RESULT(no)])
-         CPPFLAGS=$save_CPPFLAGS
+       else
+         AC_PREPROC_IFELSE([AC_LANG_SOURCE([
+           [#include <qglobal.h>],
+           [#ifndef Q_WS_X11],
+           [#error Fail],
+           [#endif]])],
+           qt_use_x11=yes,
+           qt_use_x11=no)
+         AC_MSG_RESULT($qt_use_x11)
+         if test "x$qt_use_x11" = "xyes"; then
+           QT_LIB="$QT_LIB -lX11"
+         fi
        fi
+       CPPFLAGS=$save_CPPFLAGS
 
        QT_FIND_TOOL([QT_MOC], [moc])
        QT_FIND_TOOL([QT_UIC], [uic])
@@ -209,6 +221,13 @@ AC_DEFUN([QT_DO_PKG_CONFIG],
        if test "x$USE_QT5" != "xno" ; then
                qt_corelibs="Qt5Core"
                qt_guilibs="Qt5Core Qt5Concurrent Qt5Gui Qt5Svg Qt5Widgets"
+               lyx_use_x11extras=false
+               PKG_CHECK_EXISTS(Qt5X11Extras, [lyx_use_x11extras=true], [])
+               if $lyx_use_x11extras; then
+                       qt_guilibs="$qt_guilibs Qt5X11Extras xcb"
+                       AC_DEFINE(HAVE_QT5_X11_EXTRAS, 1,
+                               [Define if you have the Qt5X11Extras module])
+               fi
                lyx_use_winextras=false
                PKG_CHECK_EXISTS(Qt5WinExtras, [lyx_use_winextras=true], [])
                if $lyx_use_winextras; then
diff --git a/development/cmake/ConfigureChecks.cmake 
b/development/cmake/ConfigureChecks.cmake
index 46d3f80..c9c7b74 100644
--- a/development/cmake/ConfigureChecks.cmake
+++ b/development/cmake/ConfigureChecks.cmake
@@ -12,6 +12,7 @@ include(CheckFunctionExists)
 include(CheckLibraryExists)
 include(CheckTypeSize)
 include(CheckCXXSourceCompiles)
+include(CheckCXXSourceRuns)
 include(MacroBoolTo01)
 include(TestBigEndian)
 
@@ -197,7 +198,30 @@ else()
   endif()
 endif()
 
+set(QPA_XCB)
+set(HAVE_QT5_X11_EXTRAS)
 if(LYX_USE_QT MATCHES "QT5")
+
+  set(CMAKE_REQUIRED_INCLUDES ${Qt5Core_INCLUDE_DIRS})
+  set(CMAKE_REQUIRED_FLAGS)
+  #message(STATUS "Qt5Core_INCLUDE_DIRS = ${Qt5Core_INCLUDE_DIRS}")
+  check_cxx_source_runs(
+    "
+    #include <QtCore/qconfig.h>
+    #include <string>
+    using namespace std;
+    string a(QT_QPA_DEFAULT_PLATFORM_NAME);
+    int main(int argc, char **argv)
+    {
+      if (a.compare(\"xcb\") == 0)
+       return(0);
+      else
+       return 1;
+    }
+    "
+    QT_USES_X11)
+  set(QPA_XCB ${QT_USES_X11})
+
   if (Qt5X11Extras_FOUND)
     get_target_property(_x11extra_prop Qt5::X11Extras IMPORTED_CONFIGURATIONS)
     get_target_property(_x11extra_link_libraries Qt5::X11Extras 
IMPORTED_LOCATION_${_x11extra_prop})
@@ -215,7 +239,8 @@ if(LYX_USE_QT MATCHES "QT5")
               bool isX11 = QX11Info::isPlatformX11();
             }
             "
-    QT_USES_X11)
+      QT_HAS_X11_EXTRAS)
+    set(HAVE_QT5_X11_EXTRAS ${QT_HAS_X11_EXTRAS})
   endif()
   if (Qt5WinExtras_FOUND)
     get_target_property(_winextra_prop Qt5::WinExtras IMPORTED_CONFIGURATIONS)
diff --git a/src/frontends/qt4/GuiApplication.cpp 
b/src/frontends/qt4/GuiApplication.cpp
index 6586207..ef945c9 100644
--- a/src/frontends/qt4/GuiApplication.cpp
+++ b/src/frontends/qt4/GuiApplication.cpp
@@ -121,10 +121,14 @@
 #ifdef Q_WS_X11
 #include <X11/Xatom.h>
 #include <X11/Xlib.h>
+#include <QX11Info>
 #undef CursorShape
 #undef None
 #elif defined(QPA_XCB)
 #include <xcb/xcb.h>
+#ifdef HAVE_QT5_X11_EXTRAS
+#include <QtX11Extras/QX11Info>
+#endif
 #endif
 
 #if (QT_VERSION < 0x050000) || (QT_VERSION >= 0x050400)
@@ -3130,8 +3134,26 @@ bool GuiApplication::x11EventFilter(XEvent * xev)
                BufferView * bv = current_view_->currentBufferView();
                if (bv) {
                        docstring const sel = bv->requestSelection();
-                       if (!sel.empty())
+                       if (!sel.empty()) {
                                d->selection_.put(sel);
+                               // Refresh the selection request timestamp.
+                               // We have to do this by ourselves as Qt seems
+                               // not doing that, maybe because of our
+                               // "persistent selection" implementation
+                               // (see comments in GuiSelection.cpp).
+                               XSelectionEvent nev;
+                               nev.type = SelectionNotify;
+                               nev.display = xev->xselectionrequest.display;
+                               nev.requestor = 
xev->xselectionrequest.requestor;
+                               nev.selection = 
xev->xselectionrequest.selection;
+                               nev.target = xev->xselectionrequest.target;
+                               nev.property = 0L; // None
+                               nev.time = CurrentTime;
+                               XSendEvent(QX11Info::display(),
+                                       nev.requestor, False, 0,
+                                       reinterpret_cast<XEvent *>(&nev));
+                               return true;
+                       }
                }
                break;
        }
@@ -3166,8 +3188,29 @@ bool GuiApplication::nativeEventFilter(const QByteArray 
& eventType,
                BufferView * bv = current_view_->currentBufferView();
                if (bv) {
                        docstring const sel = bv->requestSelection();
-                       if (!sel.empty())
+                       if (!sel.empty()) {
                                d->selection_.put(sel);
+#ifdef HAVE_QT5_X11_EXTRAS
+                               // Refresh the selection request timestamp.
+                               // We have to do this by ourselves as Qt seems
+                               // not doing that, maybe because of our
+                               // "persistent selection" implementation
+                               // (see comments in GuiSelection.cpp).
+                               xcb_selection_notify_event_t nev;
+                               nev.response_type = XCB_SELECTION_NOTIFY;
+                               nev.requestor = srev->requestor;
+                               nev.selection = srev->selection;
+                               nev.target = srev->target;
+                               nev.property = XCB_NONE;
+                               nev.time = XCB_CURRENT_TIME;
+                               xcb_connection_t * con = QX11Info::connection();
+                               xcb_send_event(con, 0, srev->requestor,
+                                       XCB_EVENT_MASK_NO_EVENT,
+                                       reinterpret_cast<char const *>(&nev));
+                               xcb_flush(con);
+#endif
+                               return true;
+                       }
                }
                break;
        }

Reply via email to