diff --git a/config.cc b/config.cc index 7ab0c80a..1c77a8c5 100644 --- a/config.cc +++ b/config.cc @@ -128,6 +128,18 @@ bool InternalPlayerBackend::isQtmultimedia() const #endif } +ScanPopupWindowFlags spwfFromInt( int id ) +{ + if( id == SPWF_Popup ) + return SPWF_Popup; + if( id == SPWF_Tool ) + return SPWF_Tool; + + if( id != SPWF_default ) + gdWarning( "Invalid ScanPopup unpinned window flags: %d\n", id ); + return SPWF_default; +} + Preferences::Preferences(): newTabsOpenAfterCurrentOne( false ), newTabsOpenInBackground( true ), @@ -158,6 +170,8 @@ Preferences::Preferences(): scanPopupUseUIAutomation( true ), scanPopupUseIAccessibleEx( true ), scanPopupUseGDMessage( true ), + scanPopupUnpinnedWindowFlags( SPWF_default ), + scanPopupUnpinnedBypassWMHint( false ), scanToMainWindow( false ), #ifdef HAVE_X11 showScanFlag( false ), @@ -812,6 +826,8 @@ Class load() throw( exError ) c.preferences.scanPopupUseUIAutomation = ( preferences.namedItem( "scanPopupUseUIAutomation" ).toElement().text() == "1" ); c.preferences.scanPopupUseIAccessibleEx = ( preferences.namedItem( "scanPopupUseIAccessibleEx" ).toElement().text() == "1" ); c.preferences.scanPopupUseGDMessage = ( preferences.namedItem( "scanPopupUseGDMessage" ).toElement().text() == "1" ); + c.preferences.scanPopupUnpinnedWindowFlags = spwfFromInt( preferences.namedItem( "scanPopupUnpinnedWindowFlags" ).toElement().text().toInt() ); + c.preferences.scanPopupUnpinnedBypassWMHint = ( preferences.namedItem( "scanPopupUnpinnedBypassWMHint" ).toElement().text() == "1" ); c.preferences.pronounceOnLoadMain = ( preferences.namedItem( "pronounceOnLoadMain" ).toElement().text() == "1" ); c.preferences.pronounceOnLoadPopup = ( preferences.namedItem( "pronounceOnLoadPopup" ).toElement().text() == "1" ); @@ -1702,6 +1718,14 @@ void save( Class const & c ) throw( exError ) opt.appendChild( dd.createTextNode( c.preferences.scanPopupUseGDMessage ? "1":"0" ) ); preferences.appendChild( opt ); + opt = dd.createElement( "scanPopupUnpinnedWindowFlags" ); + opt.appendChild( dd.createTextNode( QString::number( c.preferences.scanPopupUnpinnedWindowFlags ) ) ); + preferences.appendChild( opt ); + + opt = dd.createElement( "scanPopupUnpinnedBypassWMHint" ); + opt.appendChild( dd.createTextNode( c.preferences.scanPopupUnpinnedBypassWMHint ? "1":"0" ) ); + preferences.appendChild( opt ); + opt = dd.createElement( "pronounceOnLoadMain" ); opt.appendChild( dd.createTextNode( c.preferences.pronounceOnLoadMain ? "1" : "0" ) ); preferences.appendChild( opt ); diff --git a/config.hh b/config.hh index be1e3249..62979142 100644 --- a/config.hh +++ b/config.hh @@ -225,6 +225,23 @@ private: QString name; }; +#if defined( HAVE_X11 ) && QT_VERSION >= QT_VERSION_CHECK( 5, 0, 0 ) + // The ScanPopup window flags customization code has been tested + // only in X11 desktop environments and window managers. + // None of the window flags configurations I have tried works perfectly well + // in XFCE with Qt4. Let us enable customization code for Qt5 exclusively to + // avoid regressions with Qt4. + #define ENABLE_SPWF_CUSTOMIZATION +#endif + +enum ScanPopupWindowFlags +{ + SPWF_default = 0, + SPWF_Popup, + SPWF_Tool +}; +ScanPopupWindowFlags spwfFromInt( int id ); + /// Various user preferences struct Preferences { @@ -263,6 +280,8 @@ struct Preferences bool scanPopupUseUIAutomation; bool scanPopupUseIAccessibleEx; bool scanPopupUseGDMessage; + ScanPopupWindowFlags scanPopupUnpinnedWindowFlags; + bool scanPopupUnpinnedBypassWMHint; bool scanToMainWindow; #ifdef HAVE_X11 bool showScanFlag; diff --git a/preferences.cc b/preferences.cc index ee82614c..57aa0752 100644 --- a/preferences.cc +++ b/preferences.cc @@ -191,6 +191,8 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ): ui.scanPopupUseUIAutomation->setChecked( p.scanPopupUseUIAutomation ); ui.scanPopupUseIAccessibleEx->setChecked( p.scanPopupUseIAccessibleEx ); ui.scanPopupUseGDMessage->setChecked( p.scanPopupUseGDMessage ); + ui.scanPopupUnpinnedWindowFlags->setCurrentIndex( p.scanPopupUnpinnedWindowFlags ); + ui.scanPopupUnpinnedBypassWMHint->setChecked( p.scanPopupUnpinnedBypassWMHint ); ui.storeHistory->setChecked( p.storeHistory ); ui.historyMaxSizeField->setValue( p.maxStringsInHistory ); @@ -232,6 +234,10 @@ Preferences::Preferences( QWidget * parent, Config::Class & cfg_ ): // ui.tabWidget->removeTab( 5 ); #endif +#ifndef ENABLE_SPWF_CUSTOMIZATION + ui.groupBox_ScanPopupWindowFlags->hide(); +#endif + #ifdef HAVE_X11 ui.showScanFlag->setChecked( p.showScanFlag); #else @@ -395,6 +401,8 @@ Config::Preferences Preferences::getPreferences() p.scanPopupUseUIAutomation = ui.scanPopupUseUIAutomation->isChecked(); p.scanPopupUseIAccessibleEx = ui.scanPopupUseIAccessibleEx->isChecked(); p.scanPopupUseGDMessage = ui.scanPopupUseGDMessage->isChecked(); + p.scanPopupUnpinnedWindowFlags = Config::spwfFromInt( ui.scanPopupUnpinnedWindowFlags->currentIndex() ); + p.scanPopupUnpinnedBypassWMHint = ui.scanPopupUnpinnedBypassWMHint->isChecked(); p.storeHistory = ui.storeHistory->isChecked(); p.maxStringsInHistory = ui.historyMaxSizeField->text().toUInt(); @@ -543,6 +551,11 @@ void Preferences::showScanFlagToggled( bool b ) ui.enableScanPopupModifiers->setChecked( false ); } +void Preferences::on_scanPopupUnpinnedWindowFlags_currentIndexChanged( int index ) +{ + ui.scanPopupUnpinnedBypassWMHint->setEnabled( Config::spwfFromInt( index ) != Config::SPWF_default ); +} + void Preferences::wholeAltClicked( bool b ) { if ( b ) diff --git a/preferences.hh b/preferences.hh index c25b4caa..b9fcfccc 100644 --- a/preferences.hh +++ b/preferences.hh @@ -34,6 +34,7 @@ private slots: void enableScanPopupToggled( bool ); void enableScanPopupModifiersToggled( bool ); void showScanFlagToggled( bool b ); + void on_scanPopupUnpinnedWindowFlags_currentIndexChanged( int index ); void wholeAltClicked( bool ); void wholeCtrlClicked( bool ); diff --git a/preferences.ui b/preferences.ui index 3e47d6fe..f7c7dcac 100644 --- a/preferences.ui +++ b/preferences.ui @@ -1370,50 +1370,124 @@ download page. - - - ScanPopup extra technologies - - - - - - Try to use IAccessibleEx technology to retrieve word under cursor. + + + + + ScanPopup extra technologies + + + + + + Try to use IAccessibleEx technology to retrieve word under cursor. This technology works only with some programs that support it (for example Internet Explorer 9). It is not needed to select this option if you don't use such programs. - - - Use &IAccessibleEx - - - - - - - Try to use UI Automation technology to retrieve word under cursor. + + + Use &IAccessibleEx + + + + + + + Try to use UI Automation technology to retrieve word under cursor. This technology works only with some programs that support it. It is not needed to select this option if you don't use such programs. - - - Use &UIAutomation - - - - - - - Try to use special GoldenDict message to retrieve word under cursor. + + + Use &UIAutomation + + + + + + + Try to use special GoldenDict message to retrieve word under cursor. This technology works only with some programs that support it. It is not needed to select this option if you don't use such programs. - - - Use &GoldenDict message - - - - - + + + Use &GoldenDict message + + + + + + + + + + ScanPopup unpinned window flags + + + + + + Experiment with non-default flags if the unpinned scan popup window misbehaves + + + + <default> + + + + + Popup + + + + + Tool + + + + + + + + false + + + This hint can be combined with non-default window flags + + + Bypass window manager hint + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + diff --git a/scanpopup.cc b/scanpopup.cc index b602d120..951b93e9 100644 --- a/scanpopup.cc +++ b/scanpopup.cc @@ -24,7 +24,7 @@ using std::wstring; /// We use different window flags under Windows and X11 due to slight differences /// in their behavior on those platforms. -static Qt::WindowFlags popupWindowFlags = +static const Qt::WindowFlags defaultUnpinnedWindowFlags = #if defined (Q_OS_WIN) || ( defined (Q_OS_MAC) && QT_VERSION < QT_VERSION_CHECK( 5, 3, 0 ) ) Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint @@ -177,7 +177,7 @@ ScanPopup::ScanPopup( QWidget * parent, else { dictionaryBar.setMovable( false ); - setWindowFlags( popupWindowFlags ); + setWindowFlags( unpinnedWindowFlags() ); } connect( &configEvents, SIGNAL( mutedDictionariesChanged() ), @@ -387,6 +387,27 @@ void ScanPopup::applyWordsZoomLevel() ui.groupList->parentWidget()->layout()->activate(); } +Qt::WindowFlags ScanPopup::unpinnedWindowFlags() const +{ +#ifdef ENABLE_SPWF_CUSTOMIZATION + const Config::ScanPopupWindowFlags spwf = cfg.preferences.scanPopupUnpinnedWindowFlags; + Qt::WindowFlags result; + if( spwf == Config::SPWF_Popup ) + result = Qt::Popup; + else + if( spwf == Config::SPWF_Tool ) + result = Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint; + else + return defaultUnpinnedWindowFlags; // Ignore BypassWMHint option. + + if( cfg.preferences.scanPopupUnpinnedBypassWMHint ) + result |= Qt::X11BypassWindowManagerHint; + return result; +#else + return defaultUnpinnedWindowFlags; +#endif +} + void ScanPopup::translateWordFromClipboard() { return translateWordFromClipboard(QClipboard::Clipboard); @@ -584,6 +605,14 @@ void ScanPopup::engagePopup( bool forcePopup, bool giveFocus ) show(); +#ifdef ENABLE_SPWF_CUSTOMIZATION + // Ensure that the window always has focus on X11 with Qt::Tool flag. + // This also often prevents the window from disappearing prematurely with Qt::Popup flag, + // especially when combined with Qt::X11BypassWindowManagerHint flag. + if ( !ui.pinButton->isChecked() ) + giveFocus = true; +#endif + if ( giveFocus ) { activateWindow(); @@ -608,6 +637,15 @@ void ScanPopup::engagePopup( bool forcePopup, bool giveFocus ) activateWindow(); raise(); } +#ifdef ENABLE_SPWF_CUSTOMIZATION + else + if ( ( windowFlags() & Qt::Tool ) == Qt::Tool ) + { + // Ensure that the window with Qt::Tool flag always has focus on X11. + activateWindow(); + raise(); + } +#endif if ( ui.pinButton->isChecked() ) setWindowTitle( tr( "%1 - %2" ).arg( elideInputWord(), "GoldenDict" ) ); @@ -906,7 +944,7 @@ void ScanPopup::requestWindowFocus() // One of the rare, actually working workarounds for requesting a user keyboard focus on X11, // works for Qt::Popup windows, exactly like our Scan Popup (in unpinned state). // Modern window managers actively resist to automatically focus pop-up windows. -#ifdef HAVE_X11 +#if defined HAVE_X11 && QT_VERSION < QT_VERSION_CHECK( 5, 0, 0 ) if ( !ui.pinButton->isChecked() ) { QMenu m( this ); @@ -973,7 +1011,7 @@ void ScanPopup::pinButtonClicked( bool checked ) { ui.onTopButton->setVisible( false ); dictionaryBar.setMovable( false ); - setWindowFlags( popupWindowFlags ); + setWindowFlags( unpinnedWindowFlags() ); mouseEnteredOnce = true; } diff --git a/scanpopup.hh b/scanpopup.hh index db0af231..9de1263c 100644 --- a/scanpopup.hh +++ b/scanpopup.hh @@ -108,6 +108,8 @@ public slots: private: + Qt::WindowFlags unpinnedWindowFlags() const; + // Translates the word from the clipboard or the clipboard selection void translateWordFromClipboard(QClipboard::Mode m);