From 8f7f770b05a9f33219ceb3fe8e72ebf8a93b7308 Mon Sep 17 00:00:00 2001 From: Tobiichi-Origuchi Date: Thu, 5 Nov 2026 13:43:14 +0800 Subject: [PATCH] fix(linux): clear stale shadow input region when restoring title bar --- src/platform/linux/window_linux.cpp | 18 ++++++++++++++++-- src/platform/linux/window_shadow_linux.h | 2 ++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/platform/linux/window_linux.cpp b/src/platform/linux/window_linux.cpp index a4bc3bc5..efab1f5c 100644 --- a/src/platform/linux/window_linux.cpp +++ b/src/platform/linux/window_linux.cpp @@ -40,6 +40,7 @@ static const char* kMouseInputPolicyKey = "NativeAPIMouseInputPolicy"; struct MouseInputPolicy { bool ignored = false; bool forward = false; + bool shadow_rectangle = false; guint source = 0; GtkWidget* widget = nullptr; // The owner, or nullptr for a bare GdkWindow. GdkWindow* surface = nullptr; @@ -239,6 +240,17 @@ static void ApplyMouseInputPolicy(GtkWidget* widget, GdkWindow* surface, else gdk_window_input_shape_combine_region(surface, region, 0, 0); if (empty) cairo_region_destroy(empty); } + +static void ClearShadowInput(GtkWidget* widget) { + auto* surface = gtk_widget_get_window(widget); + auto* policy = GetMouseInputPolicy(widget, surface, false); + // Ownership survives surface recreation; explicit input/visual shapes stay intact. + if (!policy || !policy->shadow_rectangle) return; + cairo_region_destroy(policy->region); + policy->region = nullptr; + policy->shadow_rectangle = false; + ApplyMouseInputPolicy(widget, surface, *policy); +} static const char* kTitleBarStyleKey = "NativeAPITitleBarStyle"; static const char* kFocusableKey = "NativeAPIFocusable"; static const char* kNonActivatingKey = "NativeAPINonActivating"; @@ -2678,12 +2690,14 @@ static cairo_region_t* RasterizeShape(GtkWidget* widget, GdkWindow* window, return region; } -static void ApplyInputRegion(GtkWidget* widget, GdkWindow* window, cairo_region_t* region) { +static void ApplyInputRegion(GtkWidget* widget, GdkWindow* window, cairo_region_t* region, + bool shadow_rectangle = false) { // GTK intersects its CSD input region with the explicit widget region. Register // ours with GTK as well as GDK so a later allocation cannot overwrite it. auto* policy = GetMouseInputPolicy(widget, window, true); if (policy->region) cairo_region_destroy(policy->region); policy->region = region ? cairo_region_copy(region) : nullptr; + policy->shadow_rectangle = shadow_rectangle; ApplyMouseInputPolicy(widget, window, *policy); g_object_set_data(G_OBJECT(window), kInputShapeKey, region ? GINT_TO_POINTER(1) : nullptr); gdk_window_invalidate_rect(window, nullptr, TRUE); @@ -2703,7 +2717,7 @@ static void RefreshShadowInput(GtkWidget* widget) { rectangle.AddPoint({double(width), double(height)}); rectangle.AddPoint({0, double(height)}); } auto* region = RasterizeShape(widget, window, explicit_polygon ? shadow->polygon : rectangle); - ApplyInputRegion(widget, window, region); + ApplyInputRegion(widget, window, region, !explicit_polygon); cairo_region_destroy(region); g_object_set_data(G_OBJECT(window), kInputShapeKey, explicit_polygon ? GINT_TO_POINTER(1) : nullptr); } diff --git a/src/platform/linux/window_shadow_linux.h b/src/platform/linux/window_shadow_linux.h index c8a67fde..ebea2357 100644 --- a/src/platform/linux/window_shadow_linux.h +++ b/src/platform/linux/window_shadow_linux.h @@ -7,6 +7,7 @@ namespace nativeapi { static void RefreshShadowInput(GtkWidget* widget); +static void ClearShadowInput(GtkWidget* widget); } namespace nativeapi::linux_shadow { @@ -271,6 +272,7 @@ inline void Remove(GtkWidget* widget) { const int width = child ? gtk_widget_get_allocated_width(child) : 0; const int height = child ? gtk_widget_get_allocated_height(child) : 0; g_signal_handlers_disconnect_by_data(widget, state); + ClearShadowInput(widget); gtk_style_context_remove_class(gtk_widget_get_style_context(widget), kGutterStyleClass); if (state->overlay && child == state->overlay) { auto* content = gtk_bin_get_child(GTK_BIN(state->overlay));