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
This commit is contained in:
Enrico Forestieri 2016-07-10 19:31:32 +02:00
parent 65173b26d5
commit cb0c881b02
4 changed files with 94 additions and 12 deletions

View File

@ -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]+).*")

View File

@ -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

View File

@ -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)

View File

@ -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;
}