mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
fix: glitchy rendering and maximize behavior with different GTK themes (#50644)
fix: glitchy rendering and maximize behavior with different GTK themes (#50550) * fix glitchy rendering with different gtk themes especially when maximizing * use actual insets, not restored insets Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Mitchell Cohen <mitch.cohen@me.com>
This commit is contained in:
@@ -163,7 +163,7 @@ int ClientFrameViewLinux::ResizingBorderHitTest(const gfx::Point& point) {
|
||||
gfx::Rect ClientFrameViewLinux::GetBoundsForClientView() const {
|
||||
gfx::Rect client_bounds = bounds();
|
||||
if (!frame_->IsFullscreen()) {
|
||||
client_bounds.Inset(RestoredFrameBorderInsets());
|
||||
client_bounds.Inset(linux_frame_layout_->FrameBorderInsets(false));
|
||||
client_bounds.Inset(
|
||||
gfx::Insets::TLBR(GetTitlebarBounds().height(), 0, 0, 0));
|
||||
}
|
||||
@@ -236,6 +236,21 @@ void ClientFrameViewLinux::Layout(PassKey) {
|
||||
}
|
||||
|
||||
void ClientFrameViewLinux::OnPaint(gfx::Canvas* canvas) {
|
||||
if (frame_->IsFullscreen()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (frame_->IsMaximized()) {
|
||||
// Some GTK themes (Breeze) still render shadow/border assets when
|
||||
// maximized, and we don't need a border when maximized anyway. Chromium
|
||||
// switches on this too: OpaqueBrowserFrameView::PaintMaximizedFrameBorder.
|
||||
PaintMaximizedFrameBorder(canvas);
|
||||
} else {
|
||||
PaintRestoredFrameBorder(canvas);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientFrameViewLinux::PaintRestoredFrameBorder(gfx::Canvas* canvas) {
|
||||
if (auto* frame_provider = linux_frame_layout_->GetFrameProvider()) {
|
||||
frame_provider->PaintWindowFrame(
|
||||
canvas, GetLocalBounds(), GetTitlebarBounds().bottom(),
|
||||
@@ -243,6 +258,18 @@ void ClientFrameViewLinux::OnPaint(gfx::Canvas* canvas) {
|
||||
}
|
||||
}
|
||||
|
||||
void ClientFrameViewLinux::PaintMaximizedFrameBorder(gfx::Canvas* canvas) {
|
||||
ui::NativeTheme::FrameTopAreaExtraParams frame_top_area;
|
||||
frame_top_area.use_custom_frame = true;
|
||||
frame_top_area.is_active = ShouldPaintAsActive();
|
||||
frame_top_area.default_background_color = SK_ColorTRANSPARENT;
|
||||
ui::NativeTheme::ExtraParams params(frame_top_area);
|
||||
GetNativeTheme()->Paint(
|
||||
canvas->sk_canvas(), GetColorProvider(), ui::NativeTheme::kFrameTopArea,
|
||||
ui::NativeTheme::kNormal,
|
||||
gfx::Rect(0, 0, width(), GetTitlebarBounds().bottom()), params);
|
||||
}
|
||||
|
||||
void ClientFrameViewLinux::PaintAsActiveChanged() {
|
||||
UpdateThemeValues();
|
||||
}
|
||||
@@ -251,23 +278,15 @@ void ClientFrameViewLinux::UpdateThemeValues() {
|
||||
gtk::GtkCssContext window_context =
|
||||
gtk::AppendCssNodeToStyleContext({}, "window.background.csd");
|
||||
gtk::GtkCssContext headerbar_context = gtk::AppendCssNodeToStyleContext(
|
||||
{}, "headerbar.default-decoration.titlebar");
|
||||
window_context, "headerbar.default-decoration.titlebar");
|
||||
gtk::GtkCssContext title_context =
|
||||
gtk::AppendCssNodeToStyleContext(headerbar_context, "label.title");
|
||||
gtk::GtkCssContext button_context = gtk::AppendCssNodeToStyleContext(
|
||||
headerbar_context, "button.image-button");
|
||||
|
||||
gtk_style_context_set_parent(headerbar_context, window_context);
|
||||
gtk_style_context_set_parent(title_context, headerbar_context);
|
||||
gtk_style_context_set_parent(button_context, headerbar_context);
|
||||
|
||||
// ShouldPaintAsActive asks the widget, so assume active if the widget is not
|
||||
// set yet.
|
||||
if (GetWidget() != nullptr && !ShouldPaintAsActive()) {
|
||||
gtk_style_context_set_state(window_context, GTK_STATE_FLAG_BACKDROP);
|
||||
gtk_style_context_set_state(headerbar_context, GTK_STATE_FLAG_BACKDROP);
|
||||
gtk_style_context_set_state(title_context, GTK_STATE_FLAG_BACKDROP);
|
||||
gtk_style_context_set_state(button_context, GTK_STATE_FLAG_BACKDROP);
|
||||
}
|
||||
|
||||
theme_values_.window_border_radius =
|
||||
@@ -281,10 +300,6 @@ void ClientFrameViewLinux::UpdateThemeValues() {
|
||||
theme_values_.title_color = gtk::GtkStyleContextGetColor(title_context);
|
||||
theme_values_.title_padding = gtk::GtkStyleContextGetPadding(title_context);
|
||||
|
||||
gtk::GtkStyleContextGet(button_context, "min-height",
|
||||
&theme_values_.button_min_size, nullptr);
|
||||
theme_values_.button_padding = gtk::GtkStyleContextGetPadding(button_context);
|
||||
|
||||
title_->SetEnabledColor(theme_values_.title_color);
|
||||
|
||||
InvalidateLayout();
|
||||
@@ -299,8 +314,9 @@ ClientFrameViewLinux::GetButtonTypeToSkip() const {
|
||||
}
|
||||
|
||||
void ClientFrameViewLinux::UpdateButtonImages() {
|
||||
nav_button_provider_->RedrawImages(theme_values_.button_min_size,
|
||||
frame_->IsMaximized(),
|
||||
int top_area_height = theme_values_.titlebar_min_height +
|
||||
theme_values_.titlebar_padding.height();
|
||||
nav_button_provider_->RedrawImages(top_area_height, frame_->IsMaximized(),
|
||||
ShouldPaintAsActive());
|
||||
|
||||
ui::NavButtonProvider::FrameButtonDisplayType skip_type =
|
||||
@@ -368,7 +384,14 @@ void ClientFrameViewLinux::LayoutButtonsOnSide(
|
||||
|
||||
button->button->SetVisible(true);
|
||||
|
||||
int button_width = theme_values_.button_min_size;
|
||||
// CSS min-size/height/width is not enough to determine the actual size of
|
||||
// the buttons, so we sample the rendered image. See Chromium's
|
||||
// BrowserFrameViewLinuxNative::MaybeUpdateCachedFrameButtonImages.
|
||||
int button_width =
|
||||
nav_button_provider_
|
||||
->GetImage(button->type,
|
||||
ui::NavButtonProvider::ButtonState::kNormal)
|
||||
.width();
|
||||
int next_button_offset =
|
||||
button_width + nav_button_provider_->GetInterNavButtonSpacing();
|
||||
|
||||
@@ -404,7 +427,7 @@ gfx::Rect ClientFrameViewLinux::GetTitlebarBounds() const {
|
||||
std::max(font_height, theme_values_.titlebar_min_height) +
|
||||
GetTitlebarContentInsets().height();
|
||||
|
||||
gfx::Insets decoration_insets = RestoredFrameBorderInsets();
|
||||
gfx::Insets decoration_insets = linux_frame_layout_->FrameBorderInsets(false);
|
||||
|
||||
// We add the inset height here, so the .Inset() that follows won't reduce it
|
||||
// to be too small.
|
||||
|
||||
@@ -91,12 +91,11 @@ class ClientFrameViewLinux : public FramelessView,
|
||||
|
||||
SkColor title_color;
|
||||
gfx::Insets title_padding;
|
||||
|
||||
int button_min_size;
|
||||
gfx::Insets button_padding;
|
||||
};
|
||||
|
||||
void PaintAsActiveChanged();
|
||||
void PaintRestoredFrameBorder(gfx::Canvas* canvas);
|
||||
void PaintMaximizedFrameBorder(gfx::Canvas* canvas);
|
||||
|
||||
void UpdateThemeValues();
|
||||
|
||||
|
||||
@@ -83,6 +83,12 @@ gfx::Insets LinuxFrameLayout::RestoredFrameBorderInsets() const {
|
||||
return gfx::Insets();
|
||||
}
|
||||
|
||||
gfx::Insets LinuxFrameLayout::FrameBorderInsets(bool restored) const {
|
||||
return !restored && (window_->IsMaximized() || window_->IsFullscreen())
|
||||
? gfx::Insets()
|
||||
: RestoredFrameBorderInsets();
|
||||
}
|
||||
|
||||
gfx::Insets LinuxFrameLayout::GetInputInsets() const {
|
||||
return gfx::Insets(kResizeInsideBoundsSize);
|
||||
}
|
||||
@@ -106,7 +112,7 @@ void LinuxFrameLayout::set_tiled(bool tiled) {
|
||||
|
||||
gfx::Rect LinuxFrameLayout::GetWindowBounds() const {
|
||||
gfx::Rect bounds = window_->widget()->GetWindowBoundsInScreen();
|
||||
bounds.Inset(RestoredFrameBorderInsets());
|
||||
bounds.Inset(FrameBorderInsets(false));
|
||||
return bounds;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,6 +44,9 @@ class LinuxFrameLayout {
|
||||
CSDStyle csd_style);
|
||||
|
||||
// Insets from the transparent widget border to the opaque part of the window.
|
||||
// Returns empty insets when maximized or fullscreen unless |restored| is
|
||||
// true. Matches Chromium's OpaqueBrowserFrameViewLayout::FrameBorderInsets.
|
||||
gfx::Insets FrameBorderInsets(bool restored) const;
|
||||
virtual gfx::Insets RestoredFrameBorderInsets() const;
|
||||
// Insets for parts of the surface that should be counted for user input.
|
||||
virtual gfx::Insets GetInputInsets() const;
|
||||
|
||||
@@ -204,7 +204,7 @@ void OpaqueFrameView::OnPaint(gfx::Canvas* canvas) {
|
||||
return;
|
||||
|
||||
const bool active = ShouldPaintAsActive();
|
||||
const gfx::Insets border = RestoredFrameBorderInsets();
|
||||
const gfx::Insets border = FrameBorderInsets(false);
|
||||
const bool showing_shadow = linux_frame_layout_->IsShowingShadow();
|
||||
gfx::RectF bounds_dip(GetLocalBounds());
|
||||
if (showing_shadow) {
|
||||
@@ -341,9 +341,7 @@ views::Button* OpaqueFrameView::CreateButton(
|
||||
}
|
||||
|
||||
gfx::Insets OpaqueFrameView::FrameBorderInsets(bool restored) const {
|
||||
return !restored && IsFrameCondensed()
|
||||
? gfx::Insets()
|
||||
: linux_frame_layout_->RestoredFrameBorderInsets();
|
||||
return linux_frame_layout_->FrameBorderInsets(restored);
|
||||
}
|
||||
|
||||
int OpaqueFrameView::FrameTopBorderThickness(bool restored) const {
|
||||
|
||||
Reference in New Issue
Block a user