From a321593ed1797774923354f0fd3e2432d9bbd83c Mon Sep 17 00:00:00 2001 From: Igor Kushnir Date: Sat, 5 Nov 2022 18:05:11 +0200 Subject: [PATCH 1/2] Linux-specific: check correct X11 window ID translateLine->internalWinId() always equals 0. When the show/hide main window hotkey is triggered right after GoldenDict starts to system tray, `wh` equals MainWindow::internalWinId(). A few more experiments confirm that XGetInputFocus()'s output parameter `focus_return` is an ID of a top-level window, not of an embedded widget child. --- mainwindow.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mainwindow.cc b/mainwindow.cc index b41d6f57..f3bbff3d 100644 --- a/mainwindow.cc +++ b/mainwindow.cc @@ -3076,11 +3076,12 @@ void MainWindow::toggleMainWindow( bool onlyShow ) ftsDlg->show(); focusTranslateLine(); + #ifdef X11_MAIN_WINDOW_FOCUS_WORKAROUNDS Window wh = 0; int rev = 0; XGetInputFocus( QX11Info::display(), &wh, &rev ); - if( wh != translateLine->internalWinId() && !byIconClick ) + if( wh != internalWinId() && !byIconClick ) { QPoint const pointRelativeToRoot = mapToGlobal( QPoint( 0, 0 ) ); XEvent event; From 5f96f1f26ee2389b29d8059a74f3e0e61a52c6c2 Mon Sep 17 00:00:00 2001 From: Igor Kushnir Date: Sat, 5 Nov 2022 18:21:28 +0200 Subject: [PATCH 2/2] Linux-specific: don't force X11 focus unnecessarily Focus is already transferred to GoldenDict in toggleMainWindow() only the first time the main window is shown. At all subsequent requests to show the main window, focus has to be forced with the workaround. Checking focus asynchronously allows to resort to the workaround less often. Under Xfce: the timeout of 0 ms is almost always sufficient in the Qt 5 version, but is never enough in the Qt 4 version. The timeout of 4 ms is always sufficient in both versions. Under KDE Plasma: the timeout of 0 ms is rarely sufficient in the Qt 5 version. Unfortunately, with any timeout other than 0 ms, the Qt 5 version does not always get focus, which would be a serious regression, so no other timeout can be used. The Qt 4 version does not always get focus both with and without the timeout. --- mainwindow.cc | 60 +++++++++++++++++++++++++++++---------------------- mainwindow.hh | 4 ++++ 2 files changed, 38 insertions(+), 26 deletions(-) diff --git a/mainwindow.cc b/mainwindow.cc index f3bbff3d..a11c83c2 100644 --- a/mainwindow.cc +++ b/mainwindow.cc @@ -3078,36 +3078,44 @@ void MainWindow::toggleMainWindow( bool onlyShow ) focusTranslateLine(); #ifdef X11_MAIN_WINDOW_FOCUS_WORKAROUNDS - Window wh = 0; - int rev = 0; - XGetInputFocus( QX11Info::display(), &wh, &rev ); - if( wh != internalWinId() && !byIconClick ) - { - QPoint const pointRelativeToRoot = mapToGlobal( QPoint( 0, 0 ) ); - XEvent event; - memset( &event, 0, sizeof( event) ); - event.type = ButtonPress; - event.xbutton.x = 0; - event.xbutton.y = 0; - event.xbutton.x_root = pointRelativeToRoot.x(); - event.xbutton.y_root = pointRelativeToRoot.y(); - event.xbutton.window = internalWinId(); - event.xbutton.root = QX11Info::appRootWindow( QX11Info::appScreen() ); - event.xbutton.state = Button1Mask; - event.xbutton.button = Button1; - event.xbutton.same_screen = true; - event.xbutton.time = CurrentTime; - - XSendEvent( QX11Info::display(), internalWinId(), true, 0xfff, &event ); - XFlush( QX11Info::display() ); - event.type = ButtonRelease; - XSendEvent( QX11Info::display(), internalWinId(), true, 0xfff, &event ); - XFlush( QX11Info::display() ); - } + if( !byIconClick ) + QTimer::singleShot( 0, this, SLOT( forceX11Focus() ) ); #endif } } +#ifdef X11_MAIN_WINDOW_FOCUS_WORKAROUNDS +void MainWindow::forceX11Focus() +{ + Window wh = 0; + int rev = 0; + XGetInputFocus( QX11Info::display(), &wh, &rev ); + if( wh != internalWinId() ) + { + QPoint const pointRelativeToRoot = mapToGlobal( QPoint( 0, 0 ) ); + XEvent event; + memset( &event, 0, sizeof( event) ); + event.type = ButtonPress; + event.xbutton.x = 0; + event.xbutton.y = 0; + event.xbutton.x_root = pointRelativeToRoot.x(); + event.xbutton.y_root = pointRelativeToRoot.y(); + event.xbutton.window = internalWinId(); + event.xbutton.root = QX11Info::appRootWindow( QX11Info::appScreen() ); + event.xbutton.state = Button1Mask; + event.xbutton.button = Button1; + event.xbutton.same_screen = true; + event.xbutton.time = CurrentTime; + + XSendEvent( QX11Info::display(), internalWinId(), true, 0xfff, &event ); + XFlush( QX11Info::display() ); + event.type = ButtonRelease; + XSendEvent( QX11Info::display(), internalWinId(), true, 0xfff, &event ); + XFlush( QX11Info::display() ); + } +} +#endif + void MainWindow::installHotKeys() { hotkeyWrapper.reset(); // Remove the old one diff --git a/mainwindow.hh b/mainwindow.hh index b98cc85b..2fa3cd05 100644 --- a/mainwindow.hh +++ b/mainwindow.hh @@ -280,6 +280,10 @@ private: private slots: +#ifdef X11_MAIN_WINDOW_FOCUS_WORKAROUNDS + void forceX11Focus(); +#endif + void hotKeyActivated( int ); /// If new release checks are on, santizies the next check time and starts