From cb0c881b0298ef6c54e0cc57dc6f2ef46716c7aa Mon Sep 17 00:00:00 2001 From: Enrico Forestieri Date: Sun, 10 Jul 2016 19:31:32 +0200 Subject: [PATCH] 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 76cbdde85a..74d0ac8952 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 0e357a44de..f39c0ed67e 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 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 ], + [#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 46d3f809b7..c9c7b74b87 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 + #include + 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 65862079a3..ef945c9e8c 100644 --- a/src/frontends/qt4/GuiApplication.cpp +++ b/src/frontends/qt4/GuiApplication.cpp @@ -121,10 +121,14 @@ #ifdef Q_WS_X11 #include #include +#include #undef CursorShape #undef None #elif defined(QPA_XCB) #include +#ifdef HAVE_QT5_X11_EXTRAS +#include +#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(&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(&nev)); + xcb_flush(con); +#endif + return true; + } } break; } -- 2.39.2