From 5bc59a624c5d1758ff87e06545e33df79f7935bf Mon Sep 17 00:00:00 2001 From: msizanoen1 <55322658+msizanoen1@users.noreply.github.com> Date: Wed, 3 Aug 2022 15:51:52 +0700 Subject: [PATCH] fix: Wayland general CSD fixes (#34955) * fix: broken wayland window decorations due to botched chromium update The `GetTitlebarBounds().height()` is obviously intended to be placed in the `top` parameter, which used to be the second one before upstream removed multi-parameter `gfx::Rect::Inset`, but it's the first parameter for `gfx::Insets::TLBR`, which was intended to replace the removed `Inset` function. However, whoever updated Chromium kept the parameter unchanged, causing the title bar height to be passed to the `left` parameter, causing the window title bar to be unclickable. * fix: wayland window top bar buttons unclickable Use NonClientFrameView::TargetForRect for the ClientFrameViewLinux implementation because the default inherited from FramelessView blocks any non-HTCLIENT events. * fix: add maximized parameter to LinuxUI::GetWindowFrameProvider * fix: pass frame_->IsMaximized() to GetWindowFrameProvider This ensures that the toolkit renders the window decorations in maximized mode while the window is maximized to ensure that there is no empty space around the window. --- patches/chromium/.patches | 1 + ...er_to_linuxui_getwindowframeprovider.patch | 176 ++++++++++++++++++ .../ui/views/client_frame_view_linux.cc | 12 +- .../ui/views/client_frame_view_linux.h | 3 + 4 files changed, 190 insertions(+), 2 deletions(-) create mode 100644 patches/chromium/add_maximized_parameter_to_linuxui_getwindowframeprovider.patch diff --git a/patches/chromium/.patches b/patches/chromium/.patches index 4a5fe02140ea0..7cc9b8c2de314 100644 --- a/patches/chromium/.patches +++ b/patches/chromium/.patches @@ -114,3 +114,4 @@ disable_freezing_flags_after_init_in_node.patch short-circuit_permissions_checks_in_mediastreamdevicescontroller.patch chore_add_electron_deps_to_gitignores.patch chore_allow_chromium_to_handle_synthetic_mouse_events_for_touch.patch +add_maximized_parameter_to_linuxui_getwindowframeprovider.patch diff --git a/patches/chromium/add_maximized_parameter_to_linuxui_getwindowframeprovider.patch b/patches/chromium/add_maximized_parameter_to_linuxui_getwindowframeprovider.patch new file mode 100644 index 0000000000000..a7d6873b9ed49 --- /dev/null +++ b/patches/chromium/add_maximized_parameter_to_linuxui_getwindowframeprovider.patch @@ -0,0 +1,176 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: msizanoen1 +Date: Tue, 19 Jul 2022 05:11:06 +0200 +Subject: Add maximized parameter to LinuxUI::GetWindowFrameProvider + +This allows ClientFrameViewLinux to instruct the toolkit to draw the window +decorations in maximized mode where needed, preventing empty space caused +by decoration shadows and rounded titlebars around the window while maximized. + +diff --git a/ui/gtk/gtk_ui.cc b/ui/gtk/gtk_ui.cc +index 50c01fb42bc1a7350fae4773f1b549355c6cdc25..ab49a67e3b20cd240f532cfbf868533bb1f293d8 100644 +--- a/ui/gtk/gtk_ui.cc ++++ b/ui/gtk/gtk_ui.cc +@@ -511,13 +511,15 @@ std::unique_ptr GtkUi::CreateNavButtonProvider() { + return nullptr; + } + +-ui::WindowFrameProvider* GtkUi::GetWindowFrameProvider(bool solid_frame) { ++ui::WindowFrameProvider* GtkUi::GetWindowFrameProvider(bool solid_frame, bool maximized) { + if (!GtkCheckVersion(3, 14)) + return nullptr; + auto& provider = +- solid_frame ? solid_frame_provider_ : transparent_frame_provider_; ++ maximized ++ ? (solid_frame ? solid_maximized_frame_provider_ : transparent_maximized_frame_provider_) ++ : (solid_frame ? solid_frame_provider_ : transparent_frame_provider_); + if (!provider) +- provider = std::make_unique(solid_frame); ++ provider = std::make_unique(solid_frame, maximized); + return provider.get(); + } + +diff --git a/ui/gtk/gtk_ui.h b/ui/gtk/gtk_ui.h +index 5206acf475346f50e0f31b7432d9b93afc3a8ad0..9f2b3cca2337b4528f9451c2fdec7c67021c949f 100644 +--- a/ui/gtk/gtk_ui.h ++++ b/ui/gtk/gtk_ui.h +@@ -93,7 +93,7 @@ class GtkUi : public ui::LinuxUi { + bool PreferDarkTheme() const override; + bool AnimationsEnabled() const override; + std::unique_ptr CreateNavButtonProvider() override; +- ui::WindowFrameProvider* GetWindowFrameProvider(bool solid_frame) override; ++ ui::WindowFrameProvider* GetWindowFrameProvider(bool solid_frame, bool maximized) override; + base::flat_map GetKeyboardLayoutMap() override; + std::string GetCursorThemeName() override; + int GetCursorThemeSize() override; +@@ -197,6 +197,8 @@ class GtkUi : public ui::LinuxUi { + // while Chrome is running. + std::unique_ptr solid_frame_provider_; + std::unique_ptr transparent_frame_provider_; ++ std::unique_ptr solid_maximized_frame_provider_; ++ std::unique_ptr transparent_maximized_frame_provider_; + }; + + } // namespace gtk +diff --git a/ui/gtk/window_frame_provider_gtk.cc b/ui/gtk/window_frame_provider_gtk.cc +index e4dbdad327eb77994ffd7f068c67336a19897915..d3ae0636455489a7c7443df85cb769952c98aca2 100644 +--- a/ui/gtk/window_frame_provider_gtk.cc ++++ b/ui/gtk/window_frame_provider_gtk.cc +@@ -38,16 +38,18 @@ std::string GetThemeName() { + return theme_string; + } + +-GtkCssContext WindowContext(bool solid_frame, bool focused) { ++GtkCssContext WindowContext(bool solid_frame, bool maximized, bool focused) { + std::string selector = "#window.background."; + selector += solid_frame ? "solid-csd" : "csd"; ++ if (maximized) ++ selector += ".maximized"; + if (!focused) + selector += ":inactive"; + return AppendCssNodeToStyleContext({}, selector); + } + +-GtkCssContext DecorationContext(bool solid_frame, bool focused) { +- auto context = WindowContext(solid_frame, focused); ++GtkCssContext DecorationContext(bool solid_frame, bool maximized, bool focused) { ++ auto context = WindowContext(solid_frame, maximized, focused); + // GTK4 renders the decoration directly on the window. + if (!GtkCheckVersion(4)) + context = AppendCssNodeToStyleContext(context, "#decoration"); +@@ -64,8 +66,8 @@ GtkCssContext DecorationContext(bool solid_frame, bool focused) { + return context; + } + +-GtkCssContext HeaderContext(bool solid_frame, bool focused) { +- auto context = WindowContext(solid_frame, focused); ++GtkCssContext HeaderContext(bool solid_frame, bool maximized, bool focused) { ++ auto context = WindowContext(solid_frame, maximized, focused); + context = + AppendCssNodeToStyleContext(context, "#headerbar.header-bar.titlebar"); + if (!focused) +@@ -110,8 +112,8 @@ int ComputeTopCornerRadius() { + // need to experimentally determine the corner radius by rendering a sample. + // Additionally, in GTK4, the headerbar corners get clipped by the window + // rather than the headerbar having its own rounded corners. +- auto context = GtkCheckVersion(4) ? DecorationContext(false, false) +- : HeaderContext(false, false); ++ auto context = GtkCheckVersion(4) ? DecorationContext(false, false, false) ++ : HeaderContext(false, false, false); + ApplyCssToContext(context, R"(window, headerbar { + background-image: none; + background-color: black; +@@ -169,8 +171,8 @@ void WindowFrameProviderGtk::Asset::CloneFrom( + unfocused_bitmap = src.unfocused_bitmap; + } + +-WindowFrameProviderGtk::WindowFrameProviderGtk(bool solid_frame) +- : solid_frame_(solid_frame) {} ++WindowFrameProviderGtk::WindowFrameProviderGtk(bool solid_frame, bool maximized) ++ : solid_frame_(solid_frame), maximized_(maximized) {} + + WindowFrameProviderGtk::~WindowFrameProviderGtk() = default; + +@@ -264,7 +266,7 @@ void WindowFrameProviderGtk::PaintWindowFrame(gfx::Canvas* canvas, + top_area_height_dip * scale - asset.frame_thickness_px.top(); + + auto header = PaintHeaderbar({client_bounds_px.width(), top_area_height_px}, +- HeaderContext(solid_frame_, focused), scale); ++ HeaderContext(solid_frame_, maximized_, focused), scale); + image = gfx::ImageSkia::CreateFrom1xBitmap(header); + // In GTK4, the headerbar gets clipped by the window. + if (GtkCheckVersion(4)) { +@@ -296,7 +298,7 @@ void WindowFrameProviderGtk::MaybeUpdateBitmaps(float scale) { + + gfx::Rect frame_bounds_dip(kMaxFrameSizeDip, kMaxFrameSizeDip, + 2 * kMaxFrameSizeDip, 2 * kMaxFrameSizeDip); +- auto focused_context = DecorationContext(solid_frame_, true); ++ auto focused_context = DecorationContext(solid_frame_, maximized_, true); + frame_bounds_dip.Inset(-GtkStyleContextGetPadding(focused_context)); + frame_bounds_dip.Inset(-GtkStyleContextGetBorder(focused_context)); + gfx::Size bitmap_size(BitmapSizePx(asset), BitmapSizePx(asset)); +@@ -304,7 +306,7 @@ void WindowFrameProviderGtk::MaybeUpdateBitmaps(float scale) { + PaintBitmap(bitmap_size, frame_bounds_dip, focused_context, scale); + asset.unfocused_bitmap = + PaintBitmap(bitmap_size, frame_bounds_dip, +- DecorationContext(solid_frame_, false), scale); ++ DecorationContext(solid_frame_, maximized_, false), scale); + + // In GTK4, there's no way to obtain the frame thickness from CSS values + // directly, so we must determine it experimentally based on the drawn +diff --git a/ui/gtk/window_frame_provider_gtk.h b/ui/gtk/window_frame_provider_gtk.h +index da0f7c33a260f8d98a73c126def30944589001df..a2999a6dcea30a9e468f974301b3a4f03dcb8aeb 100644 +--- a/ui/gtk/window_frame_provider_gtk.h ++++ b/ui/gtk/window_frame_provider_gtk.h +@@ -14,7 +14,7 @@ namespace gtk { + + class WindowFrameProviderGtk : public ui::WindowFrameProvider { + public: +- explicit WindowFrameProviderGtk(bool solid_frame); ++ explicit WindowFrameProviderGtk(bool solid_frame, bool maximized); + + WindowFrameProviderGtk(const WindowFrameProviderGtk&) = delete; + WindowFrameProviderGtk& operator=(const WindowFrameProviderGtk&) = delete; +@@ -69,6 +69,9 @@ class WindowFrameProviderGtk : public ui::WindowFrameProvider { + + // Cached bitmaps and metrics. The scale is rounded to percent. + base::flat_map assets_; ++ ++ // Whether to draw the window decorations as maximized. ++ bool maximized_; + }; + + } // namespace gtk +diff --git a/ui/linux/linux_ui.h b/ui/linux/linux_ui.h +index 0cd8a0e101de186e11ead65526c7f0abc60c6577..7db580ce04a407877ca4108ec087120cdb9ce2ad 100644 +--- a/ui/linux/linux_ui.h ++++ b/ui/linux/linux_ui.h +@@ -176,7 +176,7 @@ class COMPONENT_EXPORT(LINUX_UI) LinuxUi + // if transparency is unsupported and the frame should be rendered opaque. + // The returned object is not owned by the caller and will remain alive until + // the process ends. +- virtual WindowFrameProvider* GetWindowFrameProvider(bool solid_frame) = 0; ++ virtual WindowFrameProvider* GetWindowFrameProvider(bool solid_frame, bool maximized) = 0; + + // Returns a map of KeyboardEvent code to KeyboardEvent key values. + virtual base::flat_map GetKeyboardLayoutMap() = 0; diff --git a/shell/browser/ui/views/client_frame_view_linux.cc b/shell/browser/ui/views/client_frame_view_linux.cc index 011764e864f96..97905462a45b9 100644 --- a/shell/browser/ui/views/client_frame_view_linux.cc +++ b/shell/browser/ui/views/client_frame_view_linux.cc @@ -131,7 +131,7 @@ void ClientFrameViewLinux::Init(NativeWindowViews* window, host_supports_client_frame_shadow_ = tree_host->SupportsClientFrameShadow(); frame_provider_ = ui::LinuxUi::instance()->GetWindowFrameProvider( - !host_supports_client_frame_shadow_); + !host_supports_client_frame_shadow_, frame_->IsMaximized()); UpdateWindowTitle(); @@ -202,7 +202,7 @@ gfx::Rect ClientFrameViewLinux::GetBoundsForClientView() const { if (!frame_->IsFullscreen()) { client_bounds.Inset(GetBorderDecorationInsets()); client_bounds.Inset( - gfx::Insets::TLBR(0, GetTitlebarBounds().height(), 0, 0)); + gfx::Insets::TLBR(GetTitlebarBounds().height(), 0, 0, 0)); } return client_bounds; } @@ -274,6 +274,9 @@ void ClientFrameViewLinux::Layout() { return; } + frame_provider_ = ui::LinuxUi::instance()->GetWindowFrameProvider( + !host_supports_client_frame_shadow_, frame_->IsMaximized()); + UpdateButtonImages(); LayoutButtons(); @@ -485,4 +488,9 @@ gfx::Size ClientFrameViewLinux::SizeWithDecorations(gfx::Size size) const { return size; } +views::View* ClientFrameViewLinux::TargetForRect(views::View* root, + const gfx::Rect& rect) { + return views::NonClientFrameView::TargetForRect(root, rect); +} + } // namespace electron diff --git a/shell/browser/ui/views/client_frame_view_linux.h b/shell/browser/ui/views/client_frame_view_linux.h index c76512465e023..cd0acf7b8af07 100644 --- a/shell/browser/ui/views/client_frame_view_linux.h +++ b/shell/browser/ui/views/client_frame_view_linux.h @@ -67,6 +67,9 @@ class ClientFrameViewLinux : public FramelessView, void OnPaint(gfx::Canvas* canvas) override; const char* GetClassName() const override; + // Overriden from views::ViewTargeterDelegate + views::View* TargetForRect(views::View* root, const gfx::Rect& rect) override; + private: static constexpr int kNavButtonCount = 4;