Skip to content

WebView2 leaks GDI objects on GlazeWM workspace switch #264

@johnsideserf

Description

@johnsideserf

Description

WebView2 widget windows leak GDI objects every time a GlazeWM workspace switch occurs. Each switch leaks ~100-200 GDI objects per switch (with 2 widgets active). Over extended use with frequent workspace switching, this causes system-wide cursor stutter and UI lag as the process approaches the Windows per-process GDI limit (10,000).

Evidence

GDI object count was monitored using GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS) via a PowerShell script sampling every 30 seconds.

Baseline (no workspace switching)

GDI count stable at 30-36 for 30+ minutes:

00:36:11 | gdi=36
00:42:49 | gdi=36  (stable)

During workspace switching

Each GlazeWM workspace switch causes a GDI spike:

00:55:19 | gdi=1243
00:55:49 | gdi=1359  (+116, after switch)
00:56:49 | gdi=1468  (+109, after switch)
01:04:50 | gdi=1481  (stable between switches)
01:05:20 | gdi=1573  (+92, after switch)
01:06:50 | gdi=1802  (+218, after switch)
01:07:20 | gdi=1808  (stable after switch)

Key observations

  • Each workspace switch leaks ~100-200 GDI objects (with 2 widget windows)
  • GDI count never decreases — objects are never released
  • Ctrl+Alt+Delete (secure desktop switch) does NOT cause the leak — only GlazeWM workspace switches
  • Widgets are configured with visible_on_all_workspaces(true)

Instrumentation ruling out Zebar's Rust code

GDI counting instrumentation was added around three suspected code paths:

  1. icon_to_image() in systray-util (systray icon bitmap conversion)
  2. Systray::on_event() (systray event handler)
  3. Systray provider emission (PNG encoding + Tauri event emit)

Result: zero GDI delta logged across all three paths. The leak is entirely within the WebView2/Tauri window management layer, triggered by whatever window events GlazeWM sends during workspace switches.

Reproduction

  1. Run Zebar with 2+ widget windows and GlazeWM
  2. Monitor GDI objects: GetGuiResources(GetCurrentProcess(), GR_GDIOBJECTS)
  3. Switch GlazeWM workspaces repeatedly
  4. Observe GDI count climbing ~100-200 per switch

Environment

  • Windows 11
  • GlazeWM (latest)
  • Zebar with visible_on_all_workspaces: true widgets
  • WebView2 (via Tauri 2.x / WRY)

Possible causes

Since widgets use visible_on_all_workspaces(true), GlazeWM may still be sending window management messages (z-order changes, WM_WINDOWPOSCHANGED, etc.) to widget windows during workspace switches. WebView2 appears to allocate GDI resources (device contexts, bitmaps) in response to these messages without releasing the old ones.

Potential mitigation: GlazeWM could skip re-managing windows that have visible_on_all_workspaces set, or Tauri/WRY could be investigated for GDI cleanup during window position changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    Status

    📬 Needs triage

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions