From c7c8b6f632b1b3abff10fa6d5dec7ffdc031ef91 Mon Sep 17 00:00:00 2001 From: Igor Kushnir Date: Wed, 2 Nov 2022 16:27:03 +0200 Subject: [PATCH 1/6] git clone URL in README: git:// => https:// scheme MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An attempt to clone the git:// URL fails on my Manjaro GNU/Linux system and produces the following output: $ git clone git://github.com/goldendict/goldendict.git Cloning into 'goldendict'... fatal: unable to connect to github.com: github.com[0: 140.82.121.4]: errno=Connection timed out 128✗ The GitHub UI offers the replacement https:// URL when the green Code button in the GoldenDict repository is clicked. Fixes #1561. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9c7712fc..5b8f01af 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ This code has been run and tested on Windows XP/Vista/7, Ubuntu Linux, Mac OS X. First, clone this repository, e.g.: - git clone git://github.com/goldendict/goldendict.git + git clone https://github.com/goldendict/goldendict.git And then invoke `qmake-qt4` and `make`: From 9330c89e4b0f39328e4b5fc2c0ee63fcfeeb249b Mon Sep 17 00:00:00 2001 From: Igor Kushnir Date: Sat, 29 Oct 2022 10:05:26 +0300 Subject: [PATCH 2/6] Don't attempt to translate empty or whitespace-only text Silently ignore empty or whitespace-only translation requests. It should be clear to most users why GoldenDict ignores them. The translated word ends up as the "word" URL query item value, which is trimmed in ArticleNetworkAccessManager::getResource(). So the added trimming in MainWindow::translateInputFinished() should be fine. When a trimmed translated word was empty, InputPhrase::isValid() returned false, ArticleNetworkAccessManager::getResource() returned a null pointer and ArticleNetworkAccessManager::createRequest() fell back to QNetworkAccessManager::createRequest(), which: * failed silently in the Qt 4 version; * displayed the Protocol "gdlookup" is unknown Failed to load URL gdlookup://localhost?word= &group=4. QtNetwork Error 301 error page in the Qt 5 version. Fixes #1179. --- mainwindow.cc | 5 ++++- scanpopup.cc | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/mainwindow.cc b/mainwindow.cc index fdea2925..680a6466 100644 --- a/mainwindow.cc +++ b/mainwindow.cc @@ -2343,7 +2343,10 @@ void MainWindow::updateSuggestionList( QString const & newValue ) void MainWindow::translateInputFinished( bool checkModifiers ) { - QString word = Folding::unescapeWildcardSymbols( translateLine->text() ); + QString word = translateLine->text().trimmed(); + if( word.isEmpty() ) + return; + word = Folding::unescapeWildcardSymbols( word ); respondToTranslationRequest( Config::InputPhrase( word, translateBoxSuffix ), checkModifiers ); } diff --git a/scanpopup.cc b/scanpopup.cc index 4de1ca95..764c5eb3 100644 --- a/scanpopup.cc +++ b/scanpopup.cc @@ -805,7 +805,10 @@ void ScanPopup::updateSuggestionList( QString const & text ) void ScanPopup::translateInputFinished() { - inputPhrase.phrase = Folding::unescapeWildcardSymbols( ui.translateBox->translateLine()->text().trimmed() ); + QString const word = ui.translateBox->translateLine()->text().trimmed(); + if( word.isEmpty() ) + return; + inputPhrase.phrase = Folding::unescapeWildcardSymbols( word ); inputPhrase.punctuationSuffix = translateBoxSuffix; showTranslationFor( inputPhrase ); } From cf84f57632cd314fd4e1600ec0297ad054a598c0 Mon Sep 17 00:00:00 2001 From: Igor Kushnir Date: Sat, 29 Oct 2022 13:32:17 +0300 Subject: [PATCH 3/6] Don't append duplicates to openedInspectors There is no benefit in storing the same pointer multiple times in openedInspectors. This occurred when an article inspector window was closed then shown again. When the tab corresponding to the duplicated article inspector pointer was closed, ArticleInspector::beforeClosed() erased only one pointer from openedInspectors. This left dangling duplicate pointer(s) in the list and eventually caused a crash when another inspector's showEvent() accessed a dangling pointer at openedInspectors.front(). --- articleinspector.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/articleinspector.cc b/articleinspector.cc index 7ab091a7..2d1c2006 100644 --- a/articleinspector.cc +++ b/articleinspector.cc @@ -47,7 +47,8 @@ void ArticleInspector::showEvent( QShowEvent * event ) setGeometry( p->geometry() ); } - openedInspectors.push_back( this ); + if( std::find( openedInspectors.begin(), openedInspectors.end(), this ) == openedInspectors.end() ) + openedInspectors.push_back( this ); QWebInspector::showEvent( event ); } From 307fe2ba16e7ae052ec338206236f3e0cdcdada2 Mon Sep 17 00:00:00 2001 From: Igor Kushnir Date: Wed, 2 Nov 2022 20:12:42 +0200 Subject: [PATCH 4/6] Download and open an image double-clicked in scan popup Now double-clicking an image has the same effect in the main window and in the scan popup. This consistency in no way prevents or hinders using the popup window as designed (for fast lookup in a small group of dictionaries), because a user is unlikely to double-click an image accidentally. Without this commit, when "Double-click translates the word clicked" option is on, double-clicking an image in the scan popup translates currently selected text if the selection is not empty. Fixes #1279. --- articleview.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/articleview.cc b/articleview.cc index 5d48d196..58f51abb 100644 --- a/articleview.cc +++ b/articleview.cc @@ -2320,7 +2320,7 @@ void ArticleView::doubleClicked( QPoint pos ) QWebHitTestResult r = ui.definition->page()->mainFrame()->hitTestContent( pos ); QWebElement el = r.element(); QUrl imageUrl; - if( !popupView && el.tagName().compare( "img", Qt::CaseInsensitive ) == 0 ) + if( el.tagName().compare( "img", Qt::CaseInsensitive ) == 0 ) { // Double click on image; download it and transfer to external program From 6dc74a7c7b1fc082ac1df4ff355ec1d8927c90a3 Mon Sep 17 00:00:00 2001 From: Igor Kushnir Date: Thu, 3 Nov 2022 16:58:44 +0200 Subject: [PATCH 5/6] Assign correct values to XButtonEvent::[xy]_root The signature is: QPoint QWidget::mapToGlobal(const QPoint &) const; --- mainwindow.cc | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/mainwindow.cc b/mainwindow.cc index 680a6466..53b14ffd 100644 --- a/mainwindow.cc +++ b/mainwindow.cc @@ -3050,15 +3050,14 @@ void MainWindow::toggleMainWindow( bool onlyShow ) XGetInputFocus( QX11Info::display(), &wh, &rev ); if( wh != translateLine->internalWinId() && !byIconClick ) { - QPoint p( 1, 1 ); - mapToGlobal( p ); + QPoint const pointRelativeToRoot = mapToGlobal( QPoint( 1, 1 ) ); XEvent event; memset( &event, 0, sizeof( event) ); event.type = ButtonPress; event.xbutton.x = 1; event.xbutton.y = 1; - event.xbutton.x_root = p.x(); - event.xbutton.y_root = p.y(); + 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; From a27a29aca31c8a294a89f7229b2a5811ff119bc8 Mon Sep 17 00:00:00 2001 From: Igor Kushnir Date: Thu, 3 Nov 2022 15:09:44 +0200 Subject: [PATCH 6/6] Linux-specific: don't open File menu after showing main window Unfortunately the X11 focus workaround that opens the File menu cannot be simply removed. Without this workaround, when KDE Plasma's Focus stealing prevention level is set to Low (which is the default) or higher, launching a second GoldenDict instance doesn't give focus to the already running instance unless that instance's main window is currently hidden into system tray or minimized. A workaround of hiding then showing the main window makes the window flicker. Suggesting GoldenDict users to set the focus stealing prevention level to None is not right, because this setting is global and affects all applications. Emulate a left mouse button click at position (0, 0) instead of (1, 1) in order to waste 1 rather than 2 pixels to the left of the menu bar. Introduce a new macro X11_MAIN_WINDOW_FOCUS_WORKAROUNDS to link the X11 focus workaround to the File menu workaround introduced in this commit. This simplifies disabling all related workarounds at once. When the focus workaround is replaced with a proper solution, the developer won't forget to remove all obsolete workarounds if they are linked together. Fixes #781. --- mainwindow.cc | 50 +++++++++++++++++++++++++++++++++++++++++++------- mainwindow.hh | 8 +++++++- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/mainwindow.cc b/mainwindow.cc index 53b14ffd..b41d6f57 100644 --- a/mainwindow.cc +++ b/mainwindow.cc @@ -63,7 +63,7 @@ #endif -#ifdef HAVE_X11 +#ifdef X11_MAIN_WINDOW_FOCUS_WORKAROUNDS #include #include #include @@ -76,6 +76,26 @@ using std::wstring; using std::map; using std::pair; +namespace { + +#ifdef X11_MAIN_WINDOW_FOCUS_WORKAROUNDS +class MinimumSizeWidget: public QWidget +{ + Q_OBJECT +public: + explicit MinimumSizeWidget( QWidget * parent ): + QWidget( parent ) + { + setSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ); + } + + virtual QSize sizeHint() const + { return QSize( 1, 1 ); } +}; +#endif + +} // unnamed namespace + #ifndef QT_NO_OPENSSL class InitSSLRunnable : public QRunnable @@ -853,6 +873,18 @@ MainWindow::MainWindow( Config::Class & cfg_ ): connect( &newReleaseCheckTimer, SIGNAL( timeout() ), this, SLOT( checkForNewRelease() ) ); +#ifdef X11_MAIN_WINDOW_FOCUS_WORKAROUNDS + // The X11 focus workaround in toggleMainWindow() emulates a left mouse button + // click on the top-left pixel of the main GoldenDict window. This hack steals + // focus from other applications reliably, but it also performs this click at + // the position that belongs to the File menu in the default KDE Plasma style, + // because the menu bar has no left margin there. + // Insert a minimum-size widget, which ignores mouse clicks, to the left of the + // menu bar to work around opening of the File menu each time the main window + // is shown (e.g. via a hotkey or when another GoldenDict instance is launched). + menuBar()->setCornerWidget( new MinimumSizeWidget( this ), Qt::TopLeftCorner ); +#endif + if ( cfg.preferences.hideMenubar ) { toggleMenuBarTriggered( false ); @@ -2945,7 +2977,7 @@ void MainWindow::showTranslationFor( QString const & inWord, ignoreDiacritics ); } -#ifdef HAVE_X11 +#ifdef X11_MAIN_WINDOW_FOCUS_WORKAROUNDS void MainWindow::toggleMainWindow( bool onlyShow, bool byIconClick ) #else void MainWindow::toggleMainWindow( bool onlyShow ) @@ -3044,18 +3076,18 @@ void MainWindow::toggleMainWindow( bool onlyShow ) ftsDlg->show(); focusTranslateLine(); -#ifdef HAVE_X11 +#ifdef X11_MAIN_WINDOW_FOCUS_WORKAROUNDS Window wh = 0; int rev = 0; XGetInputFocus( QX11Info::display(), &wh, &rev ); if( wh != translateLine->internalWinId() && !byIconClick ) { - QPoint const pointRelativeToRoot = mapToGlobal( QPoint( 1, 1 ) ); + QPoint const pointRelativeToRoot = mapToGlobal( QPoint( 0, 0 ) ); XEvent event; memset( &event, 0, sizeof( event) ); event.type = ButtonPress; - event.xbutton.x = 1; - event.xbutton.y = 1; + event.xbutton.x = 0; + event.xbutton.y = 0; event.xbutton.x_root = pointRelativeToRoot.x(); event.xbutton.y_root = pointRelativeToRoot.y(); event.xbutton.window = internalWinId(); @@ -3275,7 +3307,7 @@ void MainWindow::trayIconActivated( QSystemTrayIcon::ActivationReason r ) switch(r) { case QSystemTrayIcon::Trigger: // Left click toggles the visibility of main window -#ifdef HAVE_X11 +#ifdef X11_MAIN_WINDOW_FOCUS_WORKAROUNDS toggleMainWindow( false, true ); #else toggleMainWindow(); @@ -4933,3 +4965,7 @@ bool MainWindow::isGoldenDictWindow( HWND hwnd ) } #endif + +#ifdef X11_MAIN_WINDOW_FOCUS_WORKAROUNDS +#include "mainwindow.moc" +#endif diff --git a/mainwindow.hh b/mainwindow.hh index 87cd959d..b98cc85b 100644 --- a/mainwindow.hh +++ b/mainwindow.hh @@ -36,6 +36,12 @@ #include #endif +#ifdef HAVE_X11 + // TODO: implement startup notification support and remove these workarounds + // (see investigation comments on #781). + #define X11_MAIN_WINDOW_FOCUS_WORKAROUNDS +#endif + using std::string; using std::vector; @@ -230,7 +236,7 @@ private: /// Brings the main window to front if it's not currently, or hides it /// otherwise. The hiding part is omitted if onlyShow is true. -#ifdef HAVE_X11 +#ifdef X11_MAIN_WINDOW_FOCUS_WORKAROUNDS void toggleMainWindow( bool onlyShow = false, bool byIconClick = false ); #else void toggleMainWindow( bool onlyShow = false );