mirror of
https://github.com/electron/electron.git
synced 2026-03-19 03:02:02 -04:00
Compare commits
5 Commits
nikwen/ext
...
dispositio
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2be495f70e | ||
|
|
11f28ac3ac | ||
|
|
5ec589a1de | ||
|
|
4fe3752fae | ||
|
|
c8dd0b99ee |
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"plugins": [
|
||||
["remark-lint-code-block-style", "fenced"],
|
||||
["remark-lint-fenced-code-flag"]
|
||||
]
|
||||
}
|
||||
@@ -245,6 +245,10 @@ static_library("chrome") {
|
||||
"//chrome/browser/ui/views/dark_mode_manager_linux.cc",
|
||||
"//chrome/browser/ui/views/dark_mode_manager_linux.h",
|
||||
]
|
||||
sources += [
|
||||
"//chrome/browser/ui/views/frame/browser_frame_view_paint_utils_linux.cc",
|
||||
"//chrome/browser/ui/views/frame/browser_frame_view_paint_utils_linux.h",
|
||||
]
|
||||
public_deps += [ "//components/dbus" ]
|
||||
}
|
||||
|
||||
|
||||
@@ -226,7 +226,8 @@ Returns:
|
||||
Only defined when the window is being created by a form that set
|
||||
`target=_blank`.
|
||||
* `disposition` string - Can be `default`, `foreground-tab`,
|
||||
`background-tab`, `new-window` or `other`.
|
||||
`background-tab`, `new-window` or `other`. Corresponds to the manner an associated link was clicked. See Chromium's
|
||||
[WindowOpenDisposition](https://source.chromium.org/chromium/chromium/src/+/main:ui/base/window_open_disposition.h).
|
||||
|
||||
Emitted _after_ successful creation of a window via `window.open` in the renderer.
|
||||
Not emitted if the creation of the window is canceled from
|
||||
@@ -1450,7 +1451,8 @@ Ignore application menu shortcuts while this web contents is focused.
|
||||
* `frameName` string - Name of the window provided in `window.open()`
|
||||
* `features` string - Comma separated list of window features provided to `window.open()`.
|
||||
* `disposition` string - Can be `default`, `foreground-tab`, `background-tab`,
|
||||
`new-window` or `other`.
|
||||
`new-window` or `other`. Corresponds to the manner an associated link was clicked. See Chromium's
|
||||
[WindowOpenDisposition](https://source.chromium.org/chromium/chromium/src/+/main:ui/base/window_open_disposition.h).
|
||||
* `referrer` [Referrer](structures/referrer.md) - The referrer that will be
|
||||
passed to the new window. May or may not result in the `Referer` header being
|
||||
sent, depending on the referrer policy.
|
||||
|
||||
@@ -39,7 +39,7 @@ etc.
|
||||
|
||||
## Documentation
|
||||
|
||||
* Write [remark](https://github.com/remarkjs/remark) markdown style.
|
||||
* Write prose according to our [documentation style guide](./style-guide.md).
|
||||
|
||||
You can run `npm run lint:docs` to ensure that your documentation changes are
|
||||
formatted correctly.
|
||||
|
||||
@@ -45,8 +45,6 @@
|
||||
"null-loader": "^4.0.1",
|
||||
"pre-flight": "^2.0.0",
|
||||
"process": "^0.11.10",
|
||||
"remark-cli": "^12.0.1",
|
||||
"remark-preset-lint-markdown-style-guide": "^6.0.1",
|
||||
"semver": "^7.6.3",
|
||||
"stream-json": "^1.9.1",
|
||||
"tap-xunit": "^2.4.1",
|
||||
@@ -73,7 +71,7 @@
|
||||
"lint:objc": "node ./script/lint.js --objc",
|
||||
"lint:py": "node ./script/lint.js --py",
|
||||
"lint:gn": "node ./script/lint.js --gn",
|
||||
"lint:docs": "remark docs -qf && npm run lint:js-in-markdown && npm run create-typescript-definitions && npm run lint:ts-check-js-in-markdown && npm run lint:docs-fiddles && npm run lint:docs-relative-links && npm run lint:markdown && npm run lint:api-history",
|
||||
"lint:docs": "npm run lint:js-in-markdown && npm run create-typescript-definitions && npm run lint:ts-check-js-in-markdown && npm run lint:docs-fiddles && npm run lint:docs-relative-links && npm run lint:markdown && npm run lint:api-history",
|
||||
"lint:docs-fiddles": "standard \"docs/fiddles/**/*.js\"",
|
||||
"lint:docs-relative-links": "lint-roller-markdown-links --resource-root . --root docs \"**/*.md\"",
|
||||
"lint:markdown": "node ./script/lint.js --md",
|
||||
|
||||
@@ -8,10 +8,10 @@ electron objects that extend gin::Wrappable and gets
|
||||
allocated on the cpp heap
|
||||
|
||||
diff --git a/gin/public/wrappable_pointer_tags.h b/gin/public/wrappable_pointer_tags.h
|
||||
index c29e8554933994ff56ccea394af34e17c4e9fc2c..42512541b36ceb353483a29eca2c858b9628854b 100644
|
||||
index c29e8554933994ff56ccea394af34e17c4e9fc2c..6befb717f83d93d97033c240aa281e0bcb94e69c 100644
|
||||
--- a/gin/public/wrappable_pointer_tags.h
|
||||
+++ b/gin/public/wrappable_pointer_tags.h
|
||||
@@ -76,7 +76,19 @@ enum WrappablePointerTag : uint16_t {
|
||||
@@ -76,7 +76,20 @@ enum WrappablePointerTag : uint16_t {
|
||||
kTextInputControllerBindings, // content::TextInputControllerBindings
|
||||
kWebAXObjectProxy, // content::WebAXObjectProxy
|
||||
kWrappedExceptionHandler, // extensions::WrappedExceptionHandler
|
||||
@@ -27,6 +27,7 @@ index c29e8554933994ff56ccea394af34e17c4e9fc2c..42512541b36ceb353483a29eca2c858b
|
||||
+ kElectronReplyChannel, // gin_helper::internal::ReplyChannel
|
||||
+ kElectronScreen, // electron::api::Screen
|
||||
+ kElectronSession, // electron::api::Session
|
||||
+ kElectronTray, // electron::api::Tray
|
||||
+ kElectronWebRequest, // electron::api::WebRequest
|
||||
+ kLastPointerTag = kElectronWebRequest,
|
||||
};
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include "shell/common/gin_helper/error_thrower.h"
|
||||
#include "shell/common/gin_helper/handle.h"
|
||||
#include "shell/common/node_includes.h"
|
||||
#include "v8/include/cppgc/allocation.h"
|
||||
#include "v8/include/v8-cppgc.h"
|
||||
|
||||
namespace gin {
|
||||
|
||||
@@ -48,12 +50,13 @@ struct Converter<electron::TrayIcon::IconType> {
|
||||
|
||||
namespace electron::api {
|
||||
|
||||
gin::DeprecatedWrapperInfo Tray::kWrapperInfo = {gin::kEmbedderNativeGin};
|
||||
const gin::WrapperInfo Tray::kWrapperInfo = {{gin::kEmbedderNativeGin},
|
||||
gin::kElectronTray};
|
||||
|
||||
Tray::Tray(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> image,
|
||||
std::optional<base::Uuid> guid)
|
||||
: guid_(guid), tray_icon_(TrayIcon::Create(guid)) {
|
||||
: guid_{guid}, tray_icon_{TrayIcon::Create(guid)} {
|
||||
SetImage(isolate, image);
|
||||
tray_icon_->AddObserver(this);
|
||||
if (guid.has_value())
|
||||
@@ -63,10 +66,10 @@ Tray::Tray(v8::Isolate* isolate,
|
||||
Tray::~Tray() = default;
|
||||
|
||||
// static
|
||||
gin_helper::Handle<Tray> Tray::New(gin_helper::ErrorThrower thrower,
|
||||
v8::Local<v8::Value> image,
|
||||
std::optional<base::Uuid> guid,
|
||||
gin::Arguments* args) {
|
||||
Tray* Tray::New(gin_helper::ErrorThrower thrower,
|
||||
v8::Local<v8::Value> image,
|
||||
std::optional<base::Uuid> guid,
|
||||
gin::Arguments* args) {
|
||||
if (!Browser::Get()->is_ready()) {
|
||||
thrower.ThrowError("Cannot create Tray before app is ready");
|
||||
return {};
|
||||
@@ -80,17 +83,17 @@ gin_helper::Handle<Tray> Tray::New(gin_helper::ErrorThrower thrower,
|
||||
// Error thrown by us will be dropped when entering V8.
|
||||
// Make sure to abort early and propagate the error to JS.
|
||||
// Refs https://chromium-review.googlesource.com/c/v8/v8/+/5050065
|
||||
v8::TryCatch try_catch(args->isolate());
|
||||
auto* tray = new Tray(args->isolate(), image, guid);
|
||||
v8::Isolate* isolate = args->isolate();
|
||||
v8::TryCatch try_catch{isolate};
|
||||
Tray* tray = cppgc::MakeGarbageCollected<Tray>(
|
||||
isolate->GetCppHeap()->GetAllocationHandle(), isolate, image, guid);
|
||||
if (try_catch.HasCaught()) {
|
||||
delete tray;
|
||||
tray->keep_alive_.Clear();
|
||||
try_catch.ReThrow();
|
||||
return {};
|
||||
}
|
||||
|
||||
auto handle = gin_helper::CreateHandle(args->isolate(), tray);
|
||||
handle->Pin(args->isolate());
|
||||
return handle;
|
||||
return tray;
|
||||
}
|
||||
|
||||
void Tray::OnClicked(const gfx::Rect& bounds,
|
||||
@@ -186,9 +189,9 @@ void Tray::OnDragEnded() {
|
||||
}
|
||||
|
||||
void Tray::Destroy() {
|
||||
Unpin();
|
||||
menu_.Reset();
|
||||
menu_.Clear();
|
||||
tray_icon_.reset();
|
||||
keep_alive_.Clear();
|
||||
}
|
||||
|
||||
bool Tray::IsDestroyed() {
|
||||
@@ -374,12 +377,13 @@ void Tray::SetContextMenu(gin_helper::ErrorThrower thrower,
|
||||
v8::Local<v8::Value> arg) {
|
||||
if (!CheckAlive())
|
||||
return;
|
||||
gin_helper::Handle<Menu> menu;
|
||||
|
||||
if (arg->IsNull()) {
|
||||
menu_.Reset();
|
||||
menu_.Clear();
|
||||
tray_icon_->SetContextMenu(nullptr);
|
||||
} else if (gin::ConvertFromV8(thrower.isolate(), arg, &menu)) {
|
||||
menu_.Reset(thrower.isolate(), menu.ToV8());
|
||||
} else if (Menu* menu = nullptr;
|
||||
gin::ConvertFromV8(thrower.isolate(), arg, &menu)) {
|
||||
menu_ = menu;
|
||||
tray_icon_->SetContextMenu(menu->model());
|
||||
} else {
|
||||
thrower.ThrowTypeError("Must pass Menu or null");
|
||||
@@ -437,12 +441,17 @@ void Tray::FillObjectTemplate(v8::Isolate* isolate,
|
||||
.Build();
|
||||
}
|
||||
|
||||
const char* Tray::GetTypeName() {
|
||||
return GetClassName();
|
||||
void Tray::Trace(cppgc::Visitor* visitor) const {
|
||||
gin::Wrappable<Tray>::Trace(visitor);
|
||||
visitor->Trace(menu_);
|
||||
}
|
||||
|
||||
void Tray::WillBeDestroyed() {
|
||||
ClearWeak();
|
||||
const gin::WrapperInfo* Tray::wrapper_info() const {
|
||||
return &kWrapperInfo;
|
||||
}
|
||||
|
||||
const char* Tray::GetHumanReadableName() const {
|
||||
return "Electron / Tray";
|
||||
}
|
||||
|
||||
} // namespace electron::api
|
||||
@@ -457,7 +466,7 @@ void Initialize(v8::Local<v8::Object> exports,
|
||||
void* priv) {
|
||||
v8::Isolate* const isolate = electron::JavascriptEnvironment::GetIsolate();
|
||||
gin::Dictionary dict{isolate, exports};
|
||||
dict.Set("Tray", Tray::GetConstructor(isolate, context));
|
||||
dict.Set("Tray", Tray::GetConstructor(isolate, context, &Tray::kWrapperInfo));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
@@ -10,14 +10,13 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gin/wrappable.h"
|
||||
#include "shell/browser/event_emitter_mixin.h"
|
||||
#include "shell/browser/ui/tray_icon.h"
|
||||
#include "shell/browser/ui/tray_icon_observer.h"
|
||||
#include "shell/common/gin_converters/guid_converter.h"
|
||||
#include "shell/common/gin_helper/cleaned_up_at_exit.h"
|
||||
#include "shell/common/gin_helper/constructible.h"
|
||||
#include "shell/common/gin_helper/pinnable.h"
|
||||
#include "shell/common/gin_helper/wrappable.h"
|
||||
#include "shell/common/gin_helper/self_keep_alive.h"
|
||||
|
||||
namespace gfx {
|
||||
class Image;
|
||||
@@ -27,47 +26,43 @@ class Image;
|
||||
namespace gin_helper {
|
||||
class Dictionary;
|
||||
class ErrorThrower;
|
||||
template <typename T>
|
||||
class Handle;
|
||||
} // namespace gin_helper
|
||||
|
||||
namespace electron::api {
|
||||
|
||||
class Menu;
|
||||
|
||||
class Tray final : public gin_helper::DeprecatedWrappable<Tray>,
|
||||
class Tray final : public gin::Wrappable<Tray>,
|
||||
public gin_helper::EventEmitterMixin<Tray>,
|
||||
public gin_helper::Constructible<Tray>,
|
||||
public gin_helper::CleanedUpAtExit,
|
||||
public gin_helper::Pinnable<Tray>,
|
||||
private TrayIconObserver {
|
||||
public:
|
||||
// gin_helper::Constructible
|
||||
static gin_helper::Handle<Tray> New(gin_helper::ErrorThrower thrower,
|
||||
v8::Local<v8::Value> image,
|
||||
std::optional<base::Uuid> guid,
|
||||
gin::Arguments* args);
|
||||
static Tray* New(gin_helper::ErrorThrower thrower,
|
||||
v8::Local<v8::Value> image,
|
||||
std::optional<base::Uuid> guid,
|
||||
gin::Arguments* args);
|
||||
|
||||
static void FillObjectTemplate(v8::Isolate*, v8::Local<v8::ObjectTemplate>);
|
||||
static const char* GetClassName() { return "Tray"; }
|
||||
|
||||
// gin_helper::Wrappable
|
||||
static gin::DeprecatedWrapperInfo kWrapperInfo;
|
||||
const char* GetTypeName() override;
|
||||
// gin::Wrappable
|
||||
static const gin::WrapperInfo kWrapperInfo;
|
||||
void Trace(cppgc::Visitor*) const override;
|
||||
const gin::WrapperInfo* wrapper_info() const override;
|
||||
const char* GetHumanReadableName() const override;
|
||||
|
||||
// gin_helper::CleanedUpAtExit
|
||||
void WillBeDestroyed() override;
|
||||
// Make public for cppgc::MakeGarbageCollected.
|
||||
Tray(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> image,
|
||||
std::optional<base::Uuid> guid);
|
||||
~Tray() override;
|
||||
|
||||
// disable copy
|
||||
Tray(const Tray&) = delete;
|
||||
Tray& operator=(const Tray&) = delete;
|
||||
|
||||
private:
|
||||
Tray(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> image,
|
||||
std::optional<base::Uuid> guid);
|
||||
~Tray() override;
|
||||
|
||||
// TrayIconObserver:
|
||||
void OnClicked(const gfx::Rect& bounds,
|
||||
const gfx::Point& location,
|
||||
@@ -115,9 +110,10 @@ class Tray final : public gin_helper::DeprecatedWrappable<Tray>,
|
||||
|
||||
bool CheckAlive();
|
||||
|
||||
v8::Global<v8::Value> menu_;
|
||||
cppgc::Member<Menu> menu_;
|
||||
std::optional<base::Uuid> guid_;
|
||||
std::unique_ptr<TrayIcon> tray_icon_;
|
||||
gin_helper::SelfKeepAlive<Tray> keep_alive_{this};
|
||||
};
|
||||
|
||||
} // namespace electron::api
|
||||
|
||||
@@ -172,6 +172,12 @@ class NativeWindowMac : public NativeWindow,
|
||||
void NotifyWindowDidFailToEnterFullScreen();
|
||||
void NotifyWindowWillLeaveFullScreen();
|
||||
|
||||
// Hide/show traffic light buttons around miniaturize/deminiaturize to
|
||||
// prevent them from flashing at the default position during the restore
|
||||
// animation when a custom trafficLightPosition is configured.
|
||||
void HideTrafficLights();
|
||||
void RestoreTrafficLights();
|
||||
|
||||
// Cleanup observers when window is getting closed. Note that the destructor
|
||||
// can be called much later after window gets closed, so we should not do
|
||||
// cleanup in destructor.
|
||||
|
||||
@@ -1535,6 +1535,18 @@ void NativeWindowMac::RedrawTrafficLights() {
|
||||
[buttons_proxy_ redraw];
|
||||
}
|
||||
|
||||
void NativeWindowMac::HideTrafficLights() {
|
||||
if (buttons_proxy_)
|
||||
[buttons_proxy_ setVisible:NO];
|
||||
}
|
||||
|
||||
void NativeWindowMac::RestoreTrafficLights() {
|
||||
if (buttons_proxy_ && window_button_visibility_.value_or(true)) {
|
||||
[buttons_proxy_ redraw];
|
||||
[buttons_proxy_ setVisible:YES];
|
||||
}
|
||||
}
|
||||
|
||||
// In simpleFullScreen mode, update the frame for new bounds.
|
||||
void NativeWindowMac::UpdateFrame() {
|
||||
NSWindow* window = GetNativeWindow().GetNativeNSWindow();
|
||||
|
||||
@@ -256,6 +256,10 @@ using TitleBarStyle = electron::NativeWindowMac::TitleBarStyle;
|
||||
shell_->SetWindowLevel(NSNormalWindowLevel);
|
||||
shell_->UpdateWindowOriginalFrame();
|
||||
shell_->DetachChildren();
|
||||
// Hide the traffic light buttons container before miniaturize so that
|
||||
// when the window is restored, macOS does not render the buttons at
|
||||
// their default position during the deminiaturize animation.
|
||||
shell_->HideTrafficLights();
|
||||
}
|
||||
|
||||
- (void)windowDidMiniaturize:(NSNotification*)notification {
|
||||
@@ -273,6 +277,10 @@ using TitleBarStyle = electron::NativeWindowMac::TitleBarStyle;
|
||||
shell_->set_wants_to_be_visible(true);
|
||||
shell_->AttachChildren();
|
||||
shell_->SetWindowLevel(level_);
|
||||
// Reposition traffic light buttons and make them visible again.
|
||||
// They were hidden in windowWillMiniaturize to prevent a flash at
|
||||
// the default (0,0) position during the restore animation.
|
||||
shell_->RestoreTrafficLights();
|
||||
shell_->NotifyWindowRestore();
|
||||
}
|
||||
|
||||
|
||||
@@ -243,8 +243,8 @@ void ElectronDesktopWindowTreeHostLinux::UpdateFrameHints() {
|
||||
// The opaque region is a list of rectangles that contain only fully
|
||||
// opaque pixels of the window. We need to convert the clipping
|
||||
// rounded-rect into this format.
|
||||
SkRRect rrect = layout->GetRoundedWindowContentBounds();
|
||||
gfx::RectF rectf(layout->GetWindowContentBounds());
|
||||
SkRRect rrect = layout->GetRoundedWindowBounds();
|
||||
gfx::RectF rectf(layout->GetWindowBounds());
|
||||
rectf.Scale(scale);
|
||||
// It is acceptable to omit some pixels that are opaque, but the region
|
||||
// must not include any translucent pixels. Therefore, we must
|
||||
|
||||
@@ -112,7 +112,7 @@ ClientFrameViewLinux::~ClientFrameViewLinux() {
|
||||
void ClientFrameViewLinux::Init(NativeWindowViews* window,
|
||||
views::Widget* frame) {
|
||||
FramelessView::Init(window, frame);
|
||||
linux_frame_layout_ = std::make_unique<LinuxCSDFrameLayout>(window);
|
||||
linux_frame_layout_ = std::make_unique<LinuxCSDNativeFrameLayout>(window);
|
||||
|
||||
// Unretained() is safe because the subscription is saved into an instance
|
||||
// member and thus will be cancelled upon the instance's destruction.
|
||||
@@ -156,7 +156,8 @@ void ClientFrameViewLinux::OnWindowButtonOrderingChange() {
|
||||
}
|
||||
|
||||
int ClientFrameViewLinux::ResizingBorderHitTest(const gfx::Point& point) {
|
||||
return ResizingBorderHitTestImpl(point, RestoredFrameBorderInsets());
|
||||
return ResizingBorderHitTestImpl(
|
||||
point, linux_frame_layout_->GetResizeBorderInsets());
|
||||
}
|
||||
|
||||
gfx::Rect ClientFrameViewLinux::GetBoundsForClientView() const {
|
||||
@@ -235,8 +236,11 @@ void ClientFrameViewLinux::Layout(PassKey) {
|
||||
}
|
||||
|
||||
void ClientFrameViewLinux::OnPaint(gfx::Canvas* canvas) {
|
||||
linux_frame_layout_->PaintWindowFrame(
|
||||
canvas, GetLocalBounds(), GetTitlebarBounds(), ShouldPaintAsActive());
|
||||
if (auto* frame_provider = linux_frame_layout_->GetFrameProvider()) {
|
||||
frame_provider->PaintWindowFrame(
|
||||
canvas, GetLocalBounds(), GetTitlebarBounds().bottom(),
|
||||
ShouldPaintAsActive(), linux_frame_layout_->GetInputInsets());
|
||||
}
|
||||
}
|
||||
|
||||
void ClientFrameViewLinux::PaintAsActiveChanged() {
|
||||
@@ -267,7 +271,7 @@ void ClientFrameViewLinux::UpdateThemeValues() {
|
||||
}
|
||||
|
||||
theme_values_.window_border_radius =
|
||||
linux_frame_layout_->GetFrameProvider()->GetTopCornerRadiusDip();
|
||||
linux_frame_layout_->GetTopCornerRadiusDip();
|
||||
|
||||
gtk::GtkStyleContextGet(headerbar_context, "min-height",
|
||||
&theme_values_.titlebar_min_height, nullptr);
|
||||
|
||||
@@ -112,7 +112,7 @@ class ClientFrameViewLinux : public FramelessView,
|
||||
gfx::Insets GetTitlebarContentInsets() const;
|
||||
gfx::Rect GetTitlebarContentBounds() const;
|
||||
|
||||
std::unique_ptr<LinuxFrameLayout> linux_frame_layout_;
|
||||
std::unique_ptr<LinuxCSDNativeFrameLayout> linux_frame_layout_;
|
||||
|
||||
raw_ptr<ui::NativeTheme> theme_;
|
||||
ThemeValues theme_values_;
|
||||
|
||||
@@ -4,14 +4,20 @@
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "shell/browser/ui/views/linux_frame_layout.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "base/i18n/rtl.h"
|
||||
#include "chrome/browser/ui/views/frame/browser_frame_view_paint_utils_linux.h" // nogncheck
|
||||
#include "shell/browser/linux/x11_util.h"
|
||||
#include "shell/browser/native_window_views.h"
|
||||
#include "shell/browser/ui/electron_desktop_window_tree_host_linux.h"
|
||||
#include "ui/gfx/canvas.h"
|
||||
#include "third_party/skia/include/core/SkRRect.h"
|
||||
#include "ui/gfx/geometry/insets.h"
|
||||
#include "ui/gfx/geometry/skia_conversions.h"
|
||||
#include "ui/linux/linux_ui.h"
|
||||
#include "ui/native_theme/native_theme.h"
|
||||
#include "ui/linux/window_frame_provider.h"
|
||||
#include "ui/views/layout/layout_provider.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
|
||||
namespace electron {
|
||||
@@ -21,151 +27,174 @@ namespace {
|
||||
constexpr int kResizeBorder = 10;
|
||||
// This should match FramelessView's inside resize band.
|
||||
constexpr int kResizeInsideBoundsSize = 5;
|
||||
// These should match Chromium's restored frame edge thickness.
|
||||
constexpr gfx::Insets kDefaultCustomFrameBorder = gfx::Insets::TLBR(2, 1, 1, 1);
|
||||
|
||||
bool CheckClientFrameShadowSupport(NativeWindowViews* window) {
|
||||
auto* tree_host = static_cast<ElectronDesktopWindowTreeHostLinux*>(
|
||||
ElectronDesktopWindowTreeHostLinux::GetHostForWidget(
|
||||
window->GetAcceleratedWidget()));
|
||||
return tree_host && tree_host->SupportsClientFrameShadow();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
std::unique_ptr<LinuxFrameLayout> LinuxFrameLayout::Create(
|
||||
NativeWindowViews* window,
|
||||
bool wants_shadow) {
|
||||
bool wants_shadow,
|
||||
CSDStyle csd_style) {
|
||||
if (x11_util::IsX11() || window->IsTranslucent() || !wants_shadow) {
|
||||
return std::make_unique<LinuxUndecoratedFrameLayout>(window);
|
||||
return std::make_unique<LinuxFrameLayout>(window);
|
||||
} else if (csd_style == CSDStyle::kCustom) {
|
||||
return std::make_unique<LinuxCSDCustomFrameLayout>(window);
|
||||
} else {
|
||||
return std::make_unique<LinuxCSDFrameLayout>(window);
|
||||
return std::make_unique<LinuxCSDNativeFrameLayout>(window);
|
||||
}
|
||||
}
|
||||
|
||||
LinuxCSDFrameLayout::LinuxCSDFrameLayout(NativeWindowViews* window)
|
||||
: window_(window) {
|
||||
host_supports_client_frame_shadow_ = SupportsClientFrameShadow();
|
||||
gfx::Insets LinuxFrameLayout::GetResizeBorderInsets() const {
|
||||
gfx::Insets insets = RestoredFrameBorderInsets();
|
||||
return insets.IsEmpty() ? GetInputInsets() : insets;
|
||||
}
|
||||
|
||||
bool LinuxCSDFrameLayout::tiled() const {
|
||||
return tiled_;
|
||||
}
|
||||
|
||||
void LinuxCSDFrameLayout::set_tiled(bool tiled) {
|
||||
tiled_ = tiled;
|
||||
}
|
||||
|
||||
gfx::Insets LinuxCSDFrameLayout::RestoredFrameBorderInsets() const {
|
||||
gfx::Insets insets = GetFrameProvider()->GetFrameThicknessDip();
|
||||
const gfx::Insets input = GetInputInsets();
|
||||
|
||||
auto expand_if_visible = [](int side_thickness, int min_band) {
|
||||
return side_thickness > 0 ? std::max(side_thickness, min_band) : 0;
|
||||
};
|
||||
|
||||
gfx::Insets merged;
|
||||
merged.set_top(expand_if_visible(insets.top(), input.top()));
|
||||
merged.set_left(expand_if_visible(insets.left(), input.left()));
|
||||
merged.set_bottom(expand_if_visible(insets.bottom(), input.bottom()));
|
||||
merged.set_right(expand_if_visible(insets.right(), input.right()));
|
||||
|
||||
return base::i18n::IsRTL() ? gfx::Insets::TLBR(merged.top(), merged.right(),
|
||||
merged.bottom(), merged.left())
|
||||
: merged;
|
||||
}
|
||||
|
||||
gfx::Insets LinuxCSDFrameLayout::GetInputInsets() const {
|
||||
bool showing_shadow = host_supports_client_frame_shadow_ &&
|
||||
!window_->IsMaximized() && !window_->IsFullscreen();
|
||||
return gfx::Insets(showing_shadow ? kResizeBorder : 0);
|
||||
}
|
||||
|
||||
bool LinuxCSDFrameLayout::SupportsClientFrameShadow() const {
|
||||
auto* tree_host = static_cast<ElectronDesktopWindowTreeHostLinux*>(
|
||||
ElectronDesktopWindowTreeHostLinux::GetHostForWidget(
|
||||
window_->GetAcceleratedWidget()));
|
||||
return tree_host->SupportsClientFrameShadow();
|
||||
}
|
||||
|
||||
void LinuxCSDFrameLayout::PaintWindowFrame(gfx::Canvas* canvas,
|
||||
gfx::Rect local_bounds,
|
||||
gfx::Rect titlebar_bounds,
|
||||
bool active) {
|
||||
GetFrameProvider()->PaintWindowFrame(
|
||||
canvas, local_bounds, titlebar_bounds.bottom(), active, GetInputInsets());
|
||||
}
|
||||
|
||||
gfx::Rect LinuxCSDFrameLayout::GetWindowContentBounds() const {
|
||||
gfx::Rect content_bounds = window_->widget()->GetWindowBoundsInScreen();
|
||||
content_bounds.Inset(RestoredFrameBorderInsets());
|
||||
return content_bounds;
|
||||
}
|
||||
|
||||
SkRRect LinuxCSDFrameLayout::GetRoundedWindowContentBounds() const {
|
||||
SkRect rect = gfx::RectToSkRect(GetWindowContentBounds());
|
||||
SkRRect LinuxFrameLayout::GetRoundedWindowBounds() const {
|
||||
SkRect rect = gfx::RectToSkRect(GetWindowBounds());
|
||||
SkRRect rrect;
|
||||
|
||||
if (!window_->IsMaximized()) {
|
||||
float radius = GetFrameProvider()->GetTopCornerRadiusDip();
|
||||
float radius = GetTopCornerRadiusDip();
|
||||
if (radius > 0) {
|
||||
SkPoint round_point{radius, radius};
|
||||
SkPoint radii[] = {round_point, round_point, {}, {}};
|
||||
rrect.setRectRadii(rect, radii);
|
||||
} else {
|
||||
rrect.setRect(rect);
|
||||
}
|
||||
|
||||
return rrect;
|
||||
}
|
||||
|
||||
int LinuxCSDFrameLayout::GetTranslucentTopAreaHeight() const {
|
||||
// Base implementation is suitable for X11/views without shadows
|
||||
LinuxFrameLayout::LinuxFrameLayout(NativeWindowViews* window)
|
||||
: window_(window) {
|
||||
host_supports_client_frame_shadow_ = false;
|
||||
}
|
||||
|
||||
LinuxFrameLayout::~LinuxFrameLayout() = default;
|
||||
|
||||
gfx::Insets LinuxFrameLayout::RestoredFrameBorderInsets() const {
|
||||
return gfx::Insets();
|
||||
}
|
||||
|
||||
gfx::Insets LinuxFrameLayout::GetInputInsets() const {
|
||||
return gfx::Insets(kResizeInsideBoundsSize);
|
||||
}
|
||||
|
||||
bool LinuxFrameLayout::IsShowingShadow() const {
|
||||
return host_supports_client_frame_shadow_ && !window_->IsMaximized() &&
|
||||
!window_->IsFullscreen();
|
||||
}
|
||||
|
||||
bool LinuxFrameLayout::SupportsClientFrameShadow() const {
|
||||
return host_supports_client_frame_shadow_;
|
||||
}
|
||||
|
||||
bool LinuxFrameLayout::tiled() const {
|
||||
return tiled_;
|
||||
}
|
||||
|
||||
void LinuxFrameLayout::set_tiled(bool tiled) {
|
||||
tiled_ = tiled;
|
||||
}
|
||||
|
||||
gfx::Rect LinuxFrameLayout::GetWindowBounds() const {
|
||||
gfx::Rect bounds = window_->widget()->GetWindowBoundsInScreen();
|
||||
bounds.Inset(RestoredFrameBorderInsets());
|
||||
return bounds;
|
||||
}
|
||||
|
||||
float LinuxFrameLayout::GetTopCornerRadiusDip() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ui::WindowFrameProvider* LinuxCSDFrameLayout::GetFrameProvider() const {
|
||||
int LinuxFrameLayout::GetTranslucentTopAreaHeight() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
gfx::Insets LinuxFrameLayout::NormalizeBorderInsets(
|
||||
const gfx::Insets& frame_insets,
|
||||
const gfx::Insets& input_insets) const {
|
||||
auto expand_if_visible = [](int side_thickness, int min_band) {
|
||||
return side_thickness > 0 ? std::max(side_thickness, min_band) : 0;
|
||||
};
|
||||
|
||||
// Ensure hit testing for resize targets works
|
||||
// even if borders/shadows are absent on some edges.
|
||||
gfx::Insets merged;
|
||||
merged.set_top(expand_if_visible(frame_insets.top(), input_insets.top()));
|
||||
merged.set_left(expand_if_visible(frame_insets.left(), input_insets.left()));
|
||||
merged.set_bottom(
|
||||
expand_if_visible(frame_insets.bottom(), input_insets.bottom()));
|
||||
merged.set_right(
|
||||
expand_if_visible(frame_insets.right(), input_insets.right()));
|
||||
|
||||
return base::i18n::IsRTL() ? gfx::Insets::TLBR(merged.top(), merged.right(),
|
||||
merged.bottom(), merged.left())
|
||||
: merged;
|
||||
}
|
||||
|
||||
// Used for a native-like frame with a FrameProvider
|
||||
LinuxCSDNativeFrameLayout::LinuxCSDNativeFrameLayout(NativeWindowViews* window)
|
||||
: LinuxFrameLayout(window) {
|
||||
host_supports_client_frame_shadow_ = CheckClientFrameShadowSupport(window);
|
||||
}
|
||||
|
||||
LinuxCSDNativeFrameLayout::~LinuxCSDNativeFrameLayout() = default;
|
||||
|
||||
gfx::Insets LinuxCSDNativeFrameLayout::RestoredFrameBorderInsets() const {
|
||||
const gfx::Insets input_insets = GetInputInsets();
|
||||
const gfx::Insets frame_insets = GetFrameProvider()->GetFrameThicknessDip();
|
||||
return NormalizeBorderInsets(frame_insets, input_insets);
|
||||
}
|
||||
|
||||
gfx::Insets LinuxCSDNativeFrameLayout::GetInputInsets() const {
|
||||
return gfx::Insets(IsShowingShadow() ? kResizeBorder : 0);
|
||||
}
|
||||
|
||||
float LinuxCSDNativeFrameLayout::GetTopCornerRadiusDip() const {
|
||||
return window_->IsMaximized() ? 0
|
||||
: GetFrameProvider()->GetTopCornerRadiusDip();
|
||||
}
|
||||
|
||||
ui::WindowFrameProvider* LinuxCSDNativeFrameLayout::GetFrameProvider() const {
|
||||
return ui::LinuxUiTheme::GetForProfile(nullptr)->GetWindowFrameProvider(
|
||||
!host_supports_client_frame_shadow_, tiled(), window_->IsMaximized());
|
||||
}
|
||||
|
||||
LinuxUndecoratedFrameLayout::LinuxUndecoratedFrameLayout(
|
||||
NativeWindowViews* window)
|
||||
: window_(window) {}
|
||||
|
||||
gfx::Insets LinuxUndecoratedFrameLayout::RestoredFrameBorderInsets() const {
|
||||
return gfx::Insets();
|
||||
// Used for Chromium-like custom CSD
|
||||
LinuxCSDCustomFrameLayout::LinuxCSDCustomFrameLayout(NativeWindowViews* window)
|
||||
: LinuxFrameLayout(window) {
|
||||
host_supports_client_frame_shadow_ = CheckClientFrameShadowSupport(window);
|
||||
}
|
||||
|
||||
gfx::Insets LinuxUndecoratedFrameLayout::GetInputInsets() const {
|
||||
return gfx::Insets(kResizeInsideBoundsSize);
|
||||
LinuxCSDCustomFrameLayout::~LinuxCSDCustomFrameLayout() = default;
|
||||
|
||||
gfx::Insets LinuxCSDCustomFrameLayout::RestoredFrameBorderInsets() const {
|
||||
const gfx::Insets input_insets = GetInputInsets();
|
||||
const bool showing_shadow = IsShowingShadow();
|
||||
const auto shadow_values = (showing_shadow && !tiled())
|
||||
? GetFrameShadowValuesLinux(/*active=*/true)
|
||||
: gfx::ShadowValues();
|
||||
const gfx::Insets frame_insets = GetRestoredFrameBorderInsetsLinux(
|
||||
showing_shadow, kDefaultCustomFrameBorder, shadow_values, input_insets);
|
||||
return NormalizeBorderInsets(frame_insets, input_insets);
|
||||
}
|
||||
|
||||
bool LinuxUndecoratedFrameLayout::SupportsClientFrameShadow() const {
|
||||
return false;
|
||||
gfx::Insets LinuxCSDCustomFrameLayout::GetInputInsets() const {
|
||||
return gfx::Insets(IsShowingShadow() ? kResizeBorder : 0);
|
||||
}
|
||||
|
||||
bool LinuxUndecoratedFrameLayout::tiled() const {
|
||||
return tiled_;
|
||||
}
|
||||
|
||||
void LinuxUndecoratedFrameLayout::set_tiled(bool tiled) {
|
||||
tiled_ = tiled;
|
||||
}
|
||||
|
||||
void LinuxUndecoratedFrameLayout::PaintWindowFrame(gfx::Canvas* canvas,
|
||||
gfx::Rect local_bounds,
|
||||
gfx::Rect titlebar_bounds,
|
||||
bool active) {
|
||||
// No-op
|
||||
}
|
||||
|
||||
gfx::Rect LinuxUndecoratedFrameLayout::GetWindowContentBounds() const {
|
||||
// With no transparent insets, widget bounds and logical bounds match.
|
||||
return window_->widget()->GetWindowBoundsInScreen();
|
||||
}
|
||||
|
||||
SkRRect LinuxUndecoratedFrameLayout::GetRoundedWindowContentBounds() const {
|
||||
SkRRect rrect;
|
||||
rrect.setRect(gfx::RectToSkRect(GetWindowContentBounds()));
|
||||
return rrect;
|
||||
}
|
||||
|
||||
int LinuxUndecoratedFrameLayout::GetTranslucentTopAreaHeight() const {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ui::WindowFrameProvider* LinuxUndecoratedFrameLayout::GetFrameProvider() const {
|
||||
return nullptr;
|
||||
gfx::ShadowValues GetFrameShadowValuesLinux(bool active) {
|
||||
const int elevation = views::LayoutProvider::Get()->GetShadowElevationMetric(
|
||||
active ? views::Emphasis::kMaximum : views::Emphasis::kMedium);
|
||||
return gfx::ShadowValue::MakeMdShadowValues(elevation);
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -8,110 +8,96 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "base/i18n/rtl.h"
|
||||
#include "shell/browser/linux/x11_util.h"
|
||||
#include "shell/browser/native_window_views.h"
|
||||
#include "shell/browser/ui/electron_desktop_window_tree_host_linux.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "third_party/skia/include/core/SkRRect.h"
|
||||
#include "ui/base/ozone_buildflags.h"
|
||||
#include "ui/gfx/canvas.h"
|
||||
#include "ui/gfx/geometry/insets.h"
|
||||
#include "ui/linux/linux_ui.h"
|
||||
#include "ui/gfx/shadow_value.h"
|
||||
#include "ui/linux/window_frame_provider.h"
|
||||
|
||||
namespace gfx {
|
||||
class Insets;
|
||||
class Rect;
|
||||
} // namespace gfx
|
||||
|
||||
namespace electron {
|
||||
|
||||
class NativeWindowViews;
|
||||
|
||||
// Shared helper for CSD layout and frame painting on Linux (shadows, resize
|
||||
// regions, titlebars, etc.). Also helps views determine insets and perform
|
||||
// bounds conversions between widget and logical coordinates.
|
||||
// Shared helper for CSD layout on Linux (shadows, resize regions, titlebars,
|
||||
// etc.). Also helps views determine insets and perform bounds conversions
|
||||
// between widget and logical coordinates.
|
||||
//
|
||||
// The base class is concrete and suitable as-is for the undecorated case (X11,
|
||||
// translucent windows, or windows without shadows). CSD subclasses override
|
||||
// the methods that differ.
|
||||
class LinuxFrameLayout {
|
||||
public:
|
||||
virtual ~LinuxFrameLayout() = default;
|
||||
enum class CSDStyle {
|
||||
kNativeFrame,
|
||||
kCustom,
|
||||
};
|
||||
|
||||
explicit LinuxFrameLayout(NativeWindowViews* window);
|
||||
virtual ~LinuxFrameLayout();
|
||||
|
||||
static std::unique_ptr<LinuxFrameLayout> Create(NativeWindowViews* window,
|
||||
bool wants_shadow);
|
||||
bool wants_shadow,
|
||||
CSDStyle csd_style);
|
||||
|
||||
// Insets from the transparent widget border to the opaque part of the window
|
||||
virtual gfx::Insets RestoredFrameBorderInsets() const = 0;
|
||||
// Insets for parts of the surface that should be counted for user input
|
||||
virtual gfx::Insets GetInputInsets() const = 0;
|
||||
// Insets from the transparent widget border to the opaque part of the window.
|
||||
virtual gfx::Insets RestoredFrameBorderInsets() const;
|
||||
// Insets for parts of the surface that should be counted for user input.
|
||||
virtual gfx::Insets GetInputInsets() const;
|
||||
// Insets to use for non-client resize hit-testing.
|
||||
gfx::Insets GetResizeBorderInsets() const;
|
||||
|
||||
virtual bool SupportsClientFrameShadow() const = 0;
|
||||
bool IsShowingShadow() const;
|
||||
bool SupportsClientFrameShadow() const;
|
||||
|
||||
virtual bool tiled() const = 0;
|
||||
virtual void set_tiled(bool tiled) = 0;
|
||||
bool tiled() const;
|
||||
void set_tiled(bool tiled);
|
||||
|
||||
virtual void PaintWindowFrame(gfx::Canvas* canvas,
|
||||
gfx::Rect local_bounds,
|
||||
gfx::Rect titlebar_bounds,
|
||||
bool active) = 0;
|
||||
// The logical bounds of the window interior.
|
||||
gfx::Rect GetWindowBounds() const;
|
||||
// The logical window bounds as a rounded rect with corner radii applied.
|
||||
SkRRect GetRoundedWindowBounds() const;
|
||||
// The corner radius of the top corners of the window, in DIPs.
|
||||
virtual float GetTopCornerRadiusDip() const;
|
||||
|
||||
// The logical bounds of the window
|
||||
virtual gfx::Rect GetWindowContentBounds() const = 0;
|
||||
// The logical bounds as a rounded rect with corner radii applied
|
||||
virtual SkRRect GetRoundedWindowContentBounds() const = 0;
|
||||
int GetTranslucentTopAreaHeight() const;
|
||||
|
||||
virtual int GetTranslucentTopAreaHeight() const = 0;
|
||||
protected:
|
||||
gfx::Insets NormalizeBorderInsets(const gfx::Insets& frame_insets,
|
||||
const gfx::Insets& input_insets) const;
|
||||
|
||||
virtual ui::WindowFrameProvider* GetFrameProvider() const = 0;
|
||||
};
|
||||
|
||||
// Client-side decoration (CSD) Linux frame layout implementation.
|
||||
class LinuxCSDFrameLayout : public LinuxFrameLayout {
|
||||
public:
|
||||
explicit LinuxCSDFrameLayout(NativeWindowViews* window);
|
||||
~LinuxCSDFrameLayout() override = default;
|
||||
|
||||
gfx::Insets RestoredFrameBorderInsets() const override;
|
||||
gfx::Insets GetInputInsets() const override;
|
||||
bool SupportsClientFrameShadow() const override;
|
||||
bool tiled() const override;
|
||||
void set_tiled(bool tiled) override;
|
||||
void PaintWindowFrame(gfx::Canvas* canvas,
|
||||
gfx::Rect local_bounds,
|
||||
gfx::Rect titlebar_bounds,
|
||||
bool active) override;
|
||||
gfx::Rect GetWindowContentBounds() const override;
|
||||
SkRRect GetRoundedWindowContentBounds() const override;
|
||||
int GetTranslucentTopAreaHeight() const override;
|
||||
ui::WindowFrameProvider* GetFrameProvider() const override;
|
||||
|
||||
private:
|
||||
raw_ptr<NativeWindowViews> window_;
|
||||
bool tiled_ = false;
|
||||
bool host_supports_client_frame_shadow_ = false;
|
||||
};
|
||||
|
||||
// No-decoration Linux frame layout implementation.
|
||||
//
|
||||
// Intended for cases where we do not allocate a transparent inset area around
|
||||
// the window (e.g. X11 / server-side decorations, or when insets are disabled).
|
||||
// All inset math returns 0 and frame painting is skipped.
|
||||
class LinuxUndecoratedFrameLayout : public LinuxFrameLayout {
|
||||
// CSD strategy that uses the GTK window frame provider for metrics.
|
||||
class LinuxCSDNativeFrameLayout : public LinuxFrameLayout {
|
||||
public:
|
||||
explicit LinuxUndecoratedFrameLayout(NativeWindowViews* window);
|
||||
~LinuxUndecoratedFrameLayout() override = default;
|
||||
explicit LinuxCSDNativeFrameLayout(NativeWindowViews* window);
|
||||
~LinuxCSDNativeFrameLayout() override;
|
||||
|
||||
gfx::Insets RestoredFrameBorderInsets() const override;
|
||||
gfx::Insets GetInputInsets() const override;
|
||||
bool SupportsClientFrameShadow() const override;
|
||||
bool tiled() const override;
|
||||
void set_tiled(bool tiled) override;
|
||||
void PaintWindowFrame(gfx::Canvas* canvas,
|
||||
gfx::Rect local_bounds,
|
||||
gfx::Rect titlebar_bounds,
|
||||
bool active) override;
|
||||
gfx::Rect GetWindowContentBounds() const override;
|
||||
SkRRect GetRoundedWindowContentBounds() const override;
|
||||
int GetTranslucentTopAreaHeight() const override;
|
||||
ui::WindowFrameProvider* GetFrameProvider() const override;
|
||||
|
||||
private:
|
||||
raw_ptr<NativeWindowViews> window_;
|
||||
bool tiled_ = false;
|
||||
float GetTopCornerRadiusDip() const override;
|
||||
ui::WindowFrameProvider* GetFrameProvider() const;
|
||||
};
|
||||
|
||||
// CSD strategy that uses custom metrics, similar to those used in Chromium.
|
||||
class LinuxCSDCustomFrameLayout : public LinuxFrameLayout {
|
||||
public:
|
||||
explicit LinuxCSDCustomFrameLayout(NativeWindowViews* window);
|
||||
~LinuxCSDCustomFrameLayout() override;
|
||||
|
||||
gfx::Insets RestoredFrameBorderInsets() const override;
|
||||
gfx::Insets GetInputInsets() const override;
|
||||
};
|
||||
|
||||
gfx::ShadowValues GetFrameShadowValuesLinux(bool active);
|
||||
|
||||
} // namespace electron
|
||||
|
||||
#endif // ELECTRON_SHELL_BROWSER_UI_VIEWS_LINUX_FRAME_LAYOUT_H_
|
||||
|
||||
@@ -5,22 +5,24 @@
|
||||
#include "shell/browser/ui/views/opaque_frame_view.h"
|
||||
|
||||
#include "base/containers/adapters.h"
|
||||
#include "base/i18n/rtl.h"
|
||||
#include "chrome/browser/ui/views/frame/browser_frame_view_paint_utils_linux.h" // nogncheck
|
||||
#include "chrome/browser/ui/views/frame/opaque_browser_frame_view_layout.h" // nogncheck
|
||||
#include "chrome/grit/generated_resources.h"
|
||||
#include "components/strings/grit/components_strings.h"
|
||||
#include "shell/browser/native_window_views.h"
|
||||
#include "shell/browser/ui/views/caption_button_placeholder_container.h"
|
||||
#include "third_party/skia/include/core/SkRRect.h"
|
||||
#include "ui/base/hit_test.h"
|
||||
#include "ui/base/l10n/l10n_util.h"
|
||||
#include "ui/base/metadata/metadata_impl_macros.h"
|
||||
#include "ui/compositor/layer.h"
|
||||
#include "ui/gfx/font_list.h"
|
||||
#include "ui/linux/linux_ui.h"
|
||||
#include "ui/gfx/geometry/insets_f.h"
|
||||
#include "ui/gfx/geometry/skia_conversions.h"
|
||||
#include "ui/views/accessibility/view_accessibility.h"
|
||||
#include "ui/views/background.h"
|
||||
#include "ui/views/widget/widget.h"
|
||||
#include "ui/views/widget/widget_delegate.h"
|
||||
#include "ui/views/window/frame_background.h"
|
||||
#include "ui/views/window/frame_caption_button.h"
|
||||
#include "ui/views/window/vector_icons/vector_icons.h"
|
||||
|
||||
@@ -55,12 +57,14 @@ const int kCaptionButtonBottomPadding = 3;
|
||||
// The content edge images have a shadow built into them.
|
||||
const int OpaqueFrameView::kContentEdgeShadowThickness = 2;
|
||||
|
||||
OpaqueFrameView::OpaqueFrameView() = default;
|
||||
OpaqueFrameView::OpaqueFrameView()
|
||||
: frame_background_(std::make_unique<views::FrameBackground>()) {}
|
||||
OpaqueFrameView::~OpaqueFrameView() = default;
|
||||
|
||||
void OpaqueFrameView::Init(NativeWindowViews* window, views::Widget* frame) {
|
||||
FramelessView::Init(window, frame);
|
||||
linux_frame_layout_ = LinuxFrameLayout::Create(window, window->HasShadow());
|
||||
linux_frame_layout_ = LinuxFrameLayout::Create(
|
||||
window, window->HasShadow(), LinuxFrameLayout::CSDStyle::kCustom);
|
||||
|
||||
// Unretained() is safe because the subscription is saved into an instance
|
||||
// member and thus will be cancelled upon the instance's destruction.
|
||||
@@ -98,9 +102,8 @@ void OpaqueFrameView::Init(NativeWindowViews* window, views::Widget* frame) {
|
||||
}
|
||||
|
||||
int OpaqueFrameView::ResizingBorderHitTest(const gfx::Point& point) {
|
||||
auto insets = RestoredFrameBorderInsets();
|
||||
return ResizingBorderHitTestImpl(
|
||||
point, insets.IsEmpty() ? linux_frame_layout_->GetInputInsets() : insets);
|
||||
point, linux_frame_layout_->GetResizeBorderInsets());
|
||||
}
|
||||
|
||||
void OpaqueFrameView::InvalidateCaptionButtons() {
|
||||
@@ -200,14 +203,31 @@ void OpaqueFrameView::OnPaint(gfx::Canvas* canvas) {
|
||||
if (frame()->IsFullscreen())
|
||||
return;
|
||||
|
||||
// Titlebar height must be at least the frame border insets to avoid
|
||||
// a negative height calculation in the GTK frame provider. We add 1 to
|
||||
// ensure it's always positive even when insets are 0.
|
||||
int top_area_height = RestoredFrameBorderInsets().top() + 1;
|
||||
const bool active = ShouldPaintAsActive();
|
||||
const gfx::Insets border = RestoredFrameBorderInsets();
|
||||
const bool showing_shadow = linux_frame_layout_->IsShowingShadow();
|
||||
gfx::RectF bounds_dip(GetLocalBounds());
|
||||
if (showing_shadow) {
|
||||
bounds_dip.Inset(gfx::InsetsF(border));
|
||||
}
|
||||
|
||||
linux_frame_layout_->PaintWindowFrame(
|
||||
canvas, GetLocalBounds(), gfx::Rect(0, 0, width(), top_area_height),
|
||||
ShouldPaintAsActive());
|
||||
// TODO: support roundedCorners.
|
||||
float radius_dip = 0;
|
||||
SkVector radii[4]{{radius_dip, radius_dip}, {radius_dip, radius_dip}, {}, {}};
|
||||
SkRRect clip;
|
||||
clip.setRectRadii(gfx::RectFToSkRect(bounds_dip), radii);
|
||||
|
||||
frame_background_->set_frame_color(GetFrameColor());
|
||||
frame_background_->set_use_custom_frame(true);
|
||||
frame_background_->set_is_active(active);
|
||||
frame_background_->set_top_area_height(GetTopAreaHeight());
|
||||
|
||||
const bool draw_shadow = showing_shadow && !linux_frame_layout_->tiled();
|
||||
auto shadow_values =
|
||||
draw_shadow ? GetFrameShadowValuesLinux(active) : gfx::ShadowValues();
|
||||
::PaintRestoredFrameBorderLinux(*canvas, *this, frame_background_.get(), clip,
|
||||
showing_shadow, active, border, shadow_values,
|
||||
linux_frame_layout_->tiled());
|
||||
|
||||
if (!window()->IsWindowControlsOverlayEnabled())
|
||||
return;
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
|
||||
class CaptionButtonPlaceholderContainer;
|
||||
|
||||
namespace views {
|
||||
class FrameBackground;
|
||||
}
|
||||
|
||||
namespace electron {
|
||||
|
||||
class NativeWindowViews;
|
||||
@@ -166,6 +170,7 @@ class OpaqueFrameView : public FramelessView {
|
||||
bool is_leading_button) const;
|
||||
|
||||
std::unique_ptr<LinuxFrameLayout> linux_frame_layout_;
|
||||
std::unique_ptr<views::FrameBackground> frame_background_;
|
||||
|
||||
// Window controls.
|
||||
raw_ptr<views::Button> minimize_button_;
|
||||
|
||||
Reference in New Issue
Block a user