Skip to content

Grouped Window List Window Association Enhancements#13828

Open
Twilight0 wants to merge 2 commits into
linuxmint:masterfrom
Twilight0:fix/gwl-grouping-heuristics
Open

Grouped Window List Window Association Enhancements#13828
Twilight0 wants to merge 2 commits into
linuxmint:masterfrom
Twilight0:fix/gwl-grouping-heuristics

Conversation

@Twilight0

Copy link
Copy Markdown

Problem

In Cinnamon, the Grouped Window List (GWL) applet relies on Cinnamon.WindowTracker to associate running windows with their corresponding launcher .desktop files. This association frequently fails for applications that:

  1. Do not define a StartupWMClass key in their .desktop files.
  2. Have casing discrepancies between their X11 WM_CLASS values and their .desktop file names (e.g. Brave-browser vs brave-browser.desktop or GitKraken vs GitKraken.desktop).
  3. Are launched via wrapper scripts or subprocess execution models (e.g. Electron apps, Java applications, or multi-process systems), which obscures the mapping process.

When this failure occurs, the window is classified as a transient or generic application. The GWL applet then spawns a duplicate, unpinned icon on the panel rather than nesting/grouping the window under its existing pinned launcher.

Additionally, a potential early-startup race condition existed in onWindowSkipTaskbarChanged where getCurrentWorkspace() could return null before workspaces were fully loaded, causing a fatal JS TypeError (TypeError: currentWorkspace is null) that broke subsequent applet event handling.

Changes Included

1. Pinned Launcher Fallback Matching (_matchWindowToPinnedApp)

Introduced a helper method _matchWindowToPinnedApp(metaWindow) that proactively queries the pinned favorites list to resolve window associations if the standard WindowTracker lookup fails or returns a transient app. It matches a window's WM_CLASS (both class name and instance name) and GTK application ID against:

  • Desktop file base names: Case-insensitively matches the base name of the pinned desktop launcher (e.g., gitkraken derived from GitKraken.desktop).
  • StartupWMClass Key: Retrieves the StartupWMClass key from the .desktop file metadata (using Gio.AppInfo APIs) and compares it case-insensitively.
  • Executable/Command Line: Extracts the executable name/command line specified in the .desktop entry's Exec field to match against the running process's window class.

2. TypeError Null-Check

Added a null-check check for currentWorkspace at the entry point of onWindowSkipTaskbarChanged in applet.js:

    onWindowSkipTaskbarChanged(display, metaWindow) {
        const currentWorkspace = this.getCurrentWorkspace();
        if (!currentWorkspace) {
            return;
        }
        // ...
    }

This safely prevents early-startup crashes when taskbar skip events are fired before the workspace array is fully initialized.

Rationale & Benefits

  • Zero-Configuration Grouping: Users no longer need to manually modify system-wide or user-space .desktop entries to add StartupWMClass keys or fix casing to prevent duplicate icons.
  • Electron & Wrapper Compatibility: Automatically corrects mapping for popular Electron-based applications (like GitKraken, Slack, VS Code, Discord) and standard applications with wrapper binaries.
  • Robust Shell Reliability: Eliminates a known startup-time JS crash, ensuring that window tracker callbacks are consistently registered and handled.

…licate panel icons

When Cinnamon's WindowTracker fails to associate a running window with a
`.desktop` launcher (due to missing `StartupWMClass` declarations, case
mismatches, or process wrappers common in Electron/wrapper apps), the
Grouped Window List (GWL) applet creates a new transient launcher on the
panel instead of nesting the app under the existing pinned launcher.

This change enhances `getAppFromWindow` by proactively checking the user's
pinned favorites array first. It checks for a match between the window's
WM_CLASS (both class and instance name) or GTK application ID, and the
pinned application properties:
1. Pinned launcher desktop file base name (case-insensitive)
2. Desktop file's `StartupWMClass` key
3. Pinned application command line/executable binary

Additionally, this fixes a potential early-startup TypeError crash
(`TypeError: currentWorkspace is null`) in `onWindowSkipTaskbarChanged` by
inserting a null-check check at the entry point.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant