tauri-apps/tauri

[bug] broken IPC in multi window app on Linux

Ynng opened this issue · 9 comments

Ynng commented

Describe the bug

In a multi-window Tauri app on Linux, only the first window ever created can receive events and have its listen callbacks triggered. All subsequent windows do not receive any events.

In this video, the same Tauri app runs on Windows on the left and Linux on the right.

Every window ran listen("reply", (event) => {alert(event.payload})}).
When the button is pressed, a Rust Tauri command is invoked, which emits the reply event.

On Windows, the app behaves correctly and every window receives the reply event.

On Linux, only the first window ever receives any events.

Screencast.from.2024-09-27.23-42-14.mp4

Reproduction

The example shown in the video: https://github.com/Ynng/tauri-listen-test

Or:

  • Clone the tauri repo on an Ubuntu 24 machine
  • Run cargo run --example multiwindow
  • Try to send a message to the second/third window

Expected behavior

All windows should receive events that are "emitted to all targets".

Full tauri info output

[✔] Environment
    - OS: Fedora 40.0.0 x86_64 (X64)
    ✔ webkit2gtk-4.1: 2.44.3
    ✔ rsvg2: 2.57.1
    ✔ rustc: 1.80.1 (3f5fd8dd4 2024-08-06)
    ✔ cargo: 1.80.1 (376290515 2024-07-16)
    ✔ rustup: 1.27.1 (54dd3d00f 2024-04-24)
    ✔ Rust toolchain: stable-x86_64-unknown-linux-gnu (environment override by RUSTUP_TOOLCHAIN)
    - node: 21.7.2
    - pnpm: 9.7.1
    - npm: 10.5.0

[-] Packages
    - tauri 🦀: 2.0.0-rc.11
    - tauri-build 🦀: 2.0.0-rc.13
    - wry 🦀: 0.44.1
    - tao 🦀: 0.30.2
    - tauri-cli 🦀: 2.0.0-rc.10

[-] Plugins
    - tauri-plugin-shell 🦀: 2.0.0-rc.0

[-] App
    - build-type: bundle
    - CSP: unset
    - frontendDist: ../dist
    - devUrl: http://localhost:1420/

Stack trace

No response

Additional context

Undoing #11043 fixes this problem, but re-introduces #10981

Ynng commented

It appears that this bug was introduced in tauri version 2.0.0-rc.16.

I tested with tauri pinned to version =2.0.0-rc.15 and tauri-utils pinned to version =2.0.0-rc.12, and the bug does not occur

Ynng commented

My guess is #11043 might be related

Ynng commented

The problem still exists on Tauri 2.0.0 stable

I just ran into this today too.

One other thing I noticed is that the injected window in the #[command] is always the main window, too.

For example, this prints main on Linux, when it prints settings on macOS

#[tauri::command]
async fn cmd_update_settings(settings: Settings, w: WebviewWindow) -> Result<Settings, String> {
    println!("UPDATE SETTINGS {}", w.label());
    update_settings(&w, settings)
        .await
        .map_err(|e| e.to_string())
}

Perhaps the same root cause, but it seems like data-tauri-drag-region="true" is also broken in additional windows on Linux

Ynng commented

Manually reverting the changes made in #11043 solved the problem, but re-introduced #10981.

Ynng commented

I just ran into this today too.

One other thing I noticed is that the injected window in the #[command] is always the main window, too.

For example, this prints main on Linux, when it prints settings on macOS

#[tauri::command]
async fn cmd_update_settings(settings: Settings, w: WebviewWindow) -> Result<Settings, String> {
    println!("UPDATE SETTINGS {}", w.label());
    update_settings(&w, settings)
        .await
        .map_err(|e| e.to_string())
}

I'm fairly certain this is the cause of the "event listening issue" I described.
The listen command is getting the wrong webview object.

Ynng commented

I think I figured out the problem:

for (scheme, protocol) in uri_scheme_protocols {
// on Linux the custom protocols are associated with the web context
// and you cannot register a scheme more than once
if cfg!(any(
target_os = "linux",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
)) {
if web_context.registered_custom_protocols.contains(&scheme) {
continue;
}
web_context
.registered_custom_protocols
.insert(scheme.clone());
}
webview_builder =
webview_builder.with_asynchronous_custom_protocol(scheme, move |request, responder| {
protocol(
request,
Box::new(move |response| responder.respond(response)),
)
});
}

As documented, on Linux, custom protocols are associated with the web context and thus we can't register a scheme more than once.

However, every webview want its own tauri, ipc and asset handlers.

On Linux, only the first window's handlers are registered.
Secondary windows' handlers are simply ignored.

Ynng commented

Some ideas for potential fix:

On the short term, we can:
Use separate web context (revert #11043) and accept desyned local storage (reopen #10981) for now.

To completely fix the problem,
we need to include the window label in InvokeRequest and update the ipc handler to route requests based on that.