Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions src/main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -243,16 +243,20 @@ void processCommandLine( QCoreApplication * app, GDOptions * result )
int main( int argc, char ** argv )
{
#if defined( WITH_X11 )
// GoldenDict use lots of X11 functions and it currently cannot work
// natively on Wayland. This workaround will force GoldenDict to use
// XWayland.

if ( qEnvironmentVariableIsEmpty( "GOLDENDICT_FORCE_WAYLAND" ) && !Utils::isWayland() ) {
char * xdg_envc = getenv( "XDG_SESSION_TYPE" );
QString xdg_session = xdg_envc ? QString::fromLatin1( xdg_envc ) : QString();
if ( !QString::compare( xdg_session, QString( "wayland" ), Qt::CaseInsensitive ) ) {
// Platform selection: Higher priority to user intention
// 1. Respect QT_QPA_PLATFORM if already set.
// 2. GOLDENDICT_FORCE_XCB forces Xcb (fallback mode).
// 3. GOLDENDICT_FORCE_WAYLAND forces native Wayland.
// 4. By default, we let Qt decide (usually native Wayland on Wayland sessions).
// This improves HiDPI support but might affect some X11-specific features.

if ( qEnvironmentVariableIsEmpty( "QT_QPA_PLATFORM" ) ) {
if ( qEnvironmentVariableIsSet( "GOLDENDICT_FORCE_XCB" ) ) {
setenv( "QT_QPA_PLATFORM", "xcb", 1 );
}
else if ( qEnvironmentVariableIsSet( "GOLDENDICT_FORCE_WAYLAND" ) ) {
setenv( "QT_QPA_PLATFORM", "wayland", 1 );
}
}
#endif

Expand Down
2 changes: 1 addition & 1 deletion src/ui/mainwindow.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2987,7 +2987,7 @@ void MainWindow::toggleMainWindow( bool ensureShow )
void MainWindow::installHotKeys()
{
#if defined( WITH_X11 )
if ( !qEnvironmentVariableIsEmpty( "GOLDENDICT_FORCE_WAYLAND" ) || Utils::isWayland() ) {
if ( QGuiApplication::platformName() != "xcb" ) {
return;
}
#endif
Expand Down
24 changes: 14 additions & 10 deletions src/ui/scanpopup.cc
Original file line number Diff line number Diff line change
Expand Up @@ -341,18 +341,20 @@ ScanPopup::ScanPopup( QWidget * parent,
#endif

#ifdef WITH_X11
scanFlag = new ScanFlag( this );
if ( QGuiApplication::platformName() == "xcb" ) {
scanFlag = new ScanFlag( this );

connect( scanFlag, &ScanFlag::requestScanPopup, this, [ this ] {
translateWordFromSelection();
} );
connect( scanFlag, &ScanFlag::requestScanPopup, this, [ this ] {
translateWordFromSelection();
} );

// Use delay show to prevent popup from showing up while selection is still in progress
// Only certain software has this problem (e.g. Chrome)
selectionDelayTimer.setSingleShot( true );
selectionDelayTimer.setInterval( cfg.preferences.selectionChangeDelayTimer );
// Use delay show to prevent popup from showing up while selection is still in progress
// Only certain software has this problem (e.g. Chrome)
selectionDelayTimer.setSingleShot( true );
selectionDelayTimer.setInterval( cfg.preferences.selectionChangeDelayTimer );

connect( &selectionDelayTimer, &QTimer::timeout, this, &ScanPopup::translateWordFromSelection );
connect( &selectionDelayTimer, &QTimer::timeout, this, &ScanPopup::translateWordFromSelection );
}
#endif

applyZoomFactor();
Expand Down Expand Up @@ -447,7 +449,9 @@ void ScanPopup::refresh()

connect( groupList, &GroupComboBox::currentIndexChanged, this, &ScanPopup::currentGroupChanged );
#ifdef WITH_X11
selectionDelayTimer.setInterval( cfg.preferences.selectionChangeDelayTimer );
if ( scanFlag ) {
selectionDelayTimer.setInterval( cfg.preferences.selectionChangeDelayTimer );
}
#endif
}

Expand Down
2 changes: 1 addition & 1 deletion src/ui/scanpopup.hh
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ private:
QFont wordListDefaultFont, translateLineDefaultFont, groupListDefaultFont;

#ifdef WITH_X11
ScanFlag * scanFlag;
ScanFlag * scanFlag = nullptr;
#endif

bool mouseEnteredOnce = false;
Expand Down
57 changes: 47 additions & 10 deletions website/docs/topic_wayland.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,53 @@
Environment variable `GOLDENDICT_FORCE_WAYLAND` can be used to force GD to run in Wayland mode, like `env GOLDENDICT_FORCE_WAYLAND=1 goldendict`.
# Wayland Support and Configuration

!!! danger "Don't use unless you know!"
This flag only guarantees GD to run in wayland mode and won't crash, but nothing more.
GoldenDict-ng supports running both natively on **Wayland** and via **XWayland (X11)**.

Enable this will break popup, global hotkeys and probably other things.
Since version 25.12.0, the application defaults to native Wayland on Wayland sessions to provide the best HiDPI and fractional scaling experience. However, due to Wayland's security design, certain features like global hotkeys and screen-grabbing popups may require switching back to X11 mode.

## Current reality
## Mode Selection Hardware

!!! note "Help wanted"
Need help to redesign popup for wayland.
The display mode is determined by environment variables at startup. You can specify your preference using the following flags:

Popup is implemented with `querying mouse cursor's position` and `setting a window's absolute global position`.
Wayland does not support both by design and philosophy.
| Mode | Environment Variable | Best For |
| :--- | :--- | :--- |
| **Native Wayland** (Default) | (None) or `GOLDENDICT_FORCE_WAYLAND=1` | HiDPI screens, smooth scaling, security. |
| **XWayland (X11)** | `GOLDENDICT_FORCE_XCB=1` | Global hotkeys, advanced ScanPopup (ScanFlag). |

Wayland does not support registering global hotkeys until very recently, but a reasonable wayland desktop environment should provide some way to bind keys to commands globally.
### How to Switch

#### 1. Native Wayland (Default)
By default, the app will try to run as a native Wayland client. If you want to force it explicitly:
```bash
env GOLDENDICT_FORCE_WAYLAND=1 goldendict
```

#### 2. XWayland / X11 Mode (Recommended for Hotkeys)
If you need global hotkeys (`Ctrl+C+C` etc.) or the "Scan Flag" feature to work across windows, run the app in X11 mode:
```bash
env GOLDENDICT_FORCE_XCB=1 goldendict
```

### Flatpak Configuration
If you are using the Flatpak version, you can use **Flatseal** or the command line to set these variables:
```bash
# Force X11 mode for Flatpak
flatpak override --env=GOLDENDICT_FORCE_XCB=1 io.github.xiaoyifang.goldendict_ng
```

---

## Technical Comparison

| Feature | Native Wayland | XWayland (X11) |
| :--- | :---: | :---: |
| **HiDPI / Sharp Text** | ⭐ Excellent | ⚠️ May be blurry |
| **Global Hotkeys** | ❌ Not Supported | ✅ Fully Supported |
| **Scan Flag (Small Flag)** | ❌ Disabled | ✅ Enabled |
| **Window Positioning** | ⚠️ Limited by compositor | ✅ Precise |
| **Input Method (IME)** | ✅ Supported (Qt 6) | ✅ Supported |

!!! danger "Global Hotkeys on Wayland"
Native Wayland does not allow applications to listen to keyboard events globally. If you rely on `Ctrl+C+C` to trigger lookups from other apps, you **must** use X11 mode (`GOLDENDICT_FORCE_XCB=1`).

!!! tip "Workaround for Wayland Hotkeys"
Users on KDE or GNOME can manually bind a custom system shortcut to a command that sends a word to GoldenDict, for example: `goldendict "selection"`.
Loading