From af3c2b3d77bc07350a8e56de4860b835ed2ed1f4 Mon Sep 17 00:00:00 2001 From: stefan Date: Sun, 23 Aug 2026 16:39:50 +0700 Subject: [PATCH 1/3] feat(linux): allow the GTK application ID to be set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ID was always org.wails.. It is the app ID a Wayland compositor sees, and a desktop entry is found by matching it, so a window's icon and its grouping both hang off it — and Flatpak and Snap require it to be a domain the publisher controls, which org.wails cannot be. An app packaged for either had no way to be identified correctly. LinuxOptions.ApplicationID sets it. GTK refuses an invalid ID, so it is checked with g_application_id_is_valid first and the old default used instead: an application that fails to construct has no window to report the problem in. --- v3/pkg/application/application_linux.go | 9 ++++++++- v3/pkg/application/application_options.go | 10 ++++++++++ v3/pkg/application/linux_cgo.go | 18 ++++++++++++++---- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/v3/pkg/application/application_linux.go b/v3/pkg/application/application_linux.go index 6ecd09c03f4..15adb80a41f 100644 --- a/v3/pkg/application/application_linux.go +++ b/v3/pkg/application/application_linux.go @@ -233,9 +233,16 @@ func (a *linuxApp) unregisterWindow(window windowPointer) { func newPlatformApp(parent *App) *linuxApp { name := sanitizeAppName(parent.options.Name) + application := pointer(nil) + if id := parent.options.Linux.ApplicationID; id != "" { + application = appNewWithID(id) + } + if application == nil { + application = appNew(name) + } app := &linuxApp{ parent: parent, - application: appNew(name), + application: application, activated: make(chan struct{}), windowMap: map[windowPointer]uint{}, } diff --git a/v3/pkg/application/application_options.go b/v3/pkg/application/application_options.go index 560436a36d8..e13637e2b27 100644 --- a/v3/pkg/application/application_options.go +++ b/v3/pkg/application/application_options.go @@ -329,6 +329,16 @@ type LinuxOptions struct { // //[see the docs]: https://docs.gtk.org/glib/func.set_prgname.html ProgramName string + + // ApplicationID overrides the GTK application ID, which defaults to + // org.wails.. + // + // It is the app ID a Wayland compositor sees, and a desktop entry is found + // by matching it, so a window's icon and its grouping both hang off it. + // Flatpak and Snap go further and require the ID to be a domain the + // publisher controls, which the default cannot be. Must be a valid GTK + // application ID; an invalid one is ignored in favour of the default. + ApplicationID string } /********* iOS Options *********/ diff --git a/v3/pkg/application/linux_cgo.go b/v3/pkg/application/linux_cgo.go index e4751c88262..5e6919c5de7 100644 --- a/v3/pkg/application/linux_cgo.go +++ b/v3/pkg/application/linux_cgo.go @@ -144,12 +144,22 @@ func appName() string { } func appNew(name string) pointer { + return appNewWithID(fmt.Sprintf("org.wails.%s", name)) +} + +// appNewWithID creates the GtkApplication under an explicit ID. GTK refuses an +// invalid one, so it is checked first and the caller's default used instead — +// an application that fails to construct has no window to report the problem +// in. +func appNewWithID(appID string) pointer { C.install_signal_handlers() - appId := fmt.Sprintf("org.wails.%s", name) - nameC := C.CString(appId) - defer C.free(unsafe.Pointer(nameC)) - return pointer(C.gtk_application_new(nameC, C.APPLICATION_DEFAULT_FLAGS)) + idC := C.CString(appID) + defer C.free(unsafe.Pointer(idC)) + if C.g_application_id_is_valid(idC) == 0 { + return nil + } + return pointer(C.gtk_application_new(idC, C.APPLICATION_DEFAULT_FLAGS)) } func setProgramName(prgName string) { From d24007c607dd9d907d45f3415c76fd0d7f851cf7 Mon Sep 17 00:00:00 2001 From: stefan Date: Mon, 24 Aug 2026 00:15:44 +0700 Subject: [PATCH 2/3] docs: changelog entry --- v3/UNRELEASED_CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/v3/UNRELEASED_CHANGELOG.md b/v3/UNRELEASED_CHANGELOG.md index 33638e7fc86..8350b32f340 100644 --- a/v3/UNRELEASED_CHANGELOG.md +++ b/v3/UNRELEASED_CHANGELOG.md @@ -17,6 +17,7 @@ After processing, the content will be moved to the main changelog and this file ## Added +- Add `LinuxOptions.ApplicationID` to override the GTK application ID, which Flatpak and Snap require to be a domain the publisher controls ## Changed From 12c1f26c9da20288fcad07894fedadee6d60dffc Mon Sep 17 00:00:00 2001 From: stefan Date: Mon, 24 Aug 2026 00:54:01 +0700 Subject: [PATCH 3/3] fix(linux): keep the generated application ID within GTK's length limit A GApplication ID is capped at 255 characters. The default ID is built from the app name, so a long enough name produced one GTK refuses, and the application came back nil with nothing left to fall back to. The name is bounded to what the prefix leaves room for. --- v3/UNRELEASED_CHANGELOG.md | 2 +- v3/pkg/application/linux_cgo.go | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/v3/UNRELEASED_CHANGELOG.md b/v3/UNRELEASED_CHANGELOG.md index 8350b32f340..303e7c354fc 100644 --- a/v3/UNRELEASED_CHANGELOG.md +++ b/v3/UNRELEASED_CHANGELOG.md @@ -17,7 +17,7 @@ After processing, the content will be moved to the main changelog and this file ## Added -- Add `LinuxOptions.ApplicationID` to override the GTK application ID, which Flatpak and Snap require to be a domain the publisher controls +- Add `LinuxOptions.ApplicationID` to override the GTK application ID, which Flatpak and Snap require to be a domain the publisher controls (#6020) ## Changed diff --git a/v3/pkg/application/linux_cgo.go b/v3/pkg/application/linux_cgo.go index 5e6919c5de7..67d3d96ce18 100644 --- a/v3/pkg/application/linux_cgo.go +++ b/v3/pkg/application/linux_cgo.go @@ -144,6 +144,13 @@ func appName() string { } func appNew(name string) pointer { + // A GApplication ID is capped at 255 characters and the prefix takes ten, + // so a long enough app name would otherwise build an ID GTK refuses, + // leaving no application at all. + const maxNameLength = 245 + if len(name) > maxNameLength { + name = name[:maxNameLength] + } return appNewWithID(fmt.Sprintf("org.wails.%s", name)) }