diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 3dd9de0c2de..1e5fe42d81d 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -523,11 +523,20 @@ Returns: * `event` Event * `newBounds` [Rectangle](structures/rectangle.md) - Size the window is being resized to. +* `details` Object + * `edge` (String) - The edge of the window being dragged for resizing. Can be `bottom`, `left`, `right`, `top-left`, `top-right`, `bottom-left` or `bottom-right`. Emitted before the window is resized. Calling `event.preventDefault()` will prevent the window from being resized. Note that this is only emitted when the window is being resized manually. Resizing the window with `setBounds`/`setSize` will not emit this event. +The possible values and behaviors of the `edge` option are platform dependent. Possible values are: + +* On Windows, possible values are `bottom`, `top`, `left`, `right`, `top-left`, `top-right`, `bottom-left`, `bottom-right`. +* On macOS, possible values are `bottom` and `right`. + * The value `bottom` is used to denote vertical resizing. + * The value `right` is used to denote horizontal resizing. + #### Event: 'resize' Emitted after the window has been resized. diff --git a/shell/browser/api/electron_api_base_window.cc b/shell/browser/api/electron_api_base_window.cc index ba551776aec..0f02b782a22 100644 --- a/shell/browser/api/electron_api_base_window.cc +++ b/shell/browser/api/electron_api_base_window.cc @@ -206,8 +206,15 @@ void BaseWindow::OnWindowRestore() { } void BaseWindow::OnWindowWillResize(const gfx::Rect& new_bounds, + const gfx::ResizeEdge& edge, bool* prevent_default) { - if (Emit("will-resize", new_bounds)) { + v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); + v8::Locker locker(isolate); + v8::HandleScope handle_scope(isolate); + gin_helper::Dictionary info = gin::Dictionary::CreateEmpty(isolate); + info.Set("edge", edge); + + if (Emit("will-resize", new_bounds, info)) { *prevent_default = true; } } diff --git a/shell/browser/api/electron_api_base_window.h b/shell/browser/api/electron_api_base_window.h index d0f2f44df16..d302ed8ea02 100644 --- a/shell/browser/api/electron_api_base_window.h +++ b/shell/browser/api/electron_api_base_window.h @@ -62,6 +62,7 @@ class BaseWindow : public gin_helper::TrackableObject, void OnWindowMinimize() override; void OnWindowRestore() override; void OnWindowWillResize(const gfx::Rect& new_bounds, + const gfx::ResizeEdge& edge, bool* prevent_default) override; void OnWindowResize() override; void OnWindowResized() override; diff --git a/shell/browser/native_window.cc b/shell/browser/native_window.cc index 4441e27f3eb..47346d3d13b 100644 --- a/shell/browser/native_window.cc +++ b/shell/browser/native_window.cc @@ -480,9 +480,10 @@ void NativeWindow::NotifyWindowRestore() { } void NativeWindow::NotifyWindowWillResize(const gfx::Rect& new_bounds, + const gfx::ResizeEdge& edge, bool* prevent_default) { for (NativeWindowObserver& observer : observers_) - observer.OnWindowWillResize(new_bounds, prevent_default); + observer.OnWindowWillResize(new_bounds, edge, prevent_default); } void NativeWindow::NotifyWindowWillMove(const gfx::Rect& new_bounds, diff --git a/shell/browser/native_window.h b/shell/browser/native_window.h index 5da40a30eec..5ee191b2018 100644 --- a/shell/browser/native_window.h +++ b/shell/browser/native_window.h @@ -32,6 +32,7 @@ class Image; class Point; class Rect; class RectF; +enum class ResizeEdge; class Size; } // namespace gfx @@ -275,6 +276,7 @@ class NativeWindow : public base::SupportsUserData, void NotifyWindowRestore(); void NotifyWindowMove(); void NotifyWindowWillResize(const gfx::Rect& new_bounds, + const gfx::ResizeEdge& edge, bool* prevent_default); void NotifyWindowResize(); void NotifyWindowResized(); diff --git a/shell/browser/native_window_observer.h b/shell/browser/native_window_observer.h index 4d81276b5fb..4f33570de4b 100644 --- a/shell/browser/native_window_observer.h +++ b/shell/browser/native_window_observer.h @@ -18,7 +18,8 @@ namespace gfx { class Rect; -} +enum class ResizeEdge; +} // namespace gfx namespace electron { @@ -71,6 +72,7 @@ class NativeWindowObserver : public base::CheckedObserver { virtual void OnWindowMinimize() {} virtual void OnWindowRestore() {} virtual void OnWindowWillResize(const gfx::Rect& new_bounds, + const gfx::ResizeEdge& edge, bool* prevent_default) {} virtual void OnWindowResize() {} virtual void OnWindowResized() {} diff --git a/shell/browser/native_window_views_win.cc b/shell/browser/native_window_views_win.cc index 13e369c716c..86668156172 100644 --- a/shell/browser/native_window_views_win.cc +++ b/shell/browser/native_window_views_win.cc @@ -14,6 +14,7 @@ #include "ui/display/display.h" #include "ui/display/win/screen_win.h" #include "ui/gfx/geometry/insets.h" +#include "ui/gfx/geometry/resize_utils.h" #include "ui/views/widget/native_widget_private.h" // Must be included after other Windows headers. @@ -137,6 +138,31 @@ const char* AppCommandToString(int command_id) { } } +// Copied from ui/views/win/hwnd_message_handler.cc +gfx::ResizeEdge GetWindowResizeEdge(WPARAM param) { + switch (param) { + case WMSZ_BOTTOM: + return gfx::ResizeEdge::kBottom; + case WMSZ_TOP: + return gfx::ResizeEdge::kTop; + case WMSZ_LEFT: + return gfx::ResizeEdge::kLeft; + case WMSZ_RIGHT: + return gfx::ResizeEdge::kRight; + case WMSZ_TOPLEFT: + return gfx::ResizeEdge::kTopLeft; + case WMSZ_TOPRIGHT: + return gfx::ResizeEdge::kTopRight; + case WMSZ_BOTTOMLEFT: + return gfx::ResizeEdge::kBottomLeft; + case WMSZ_BOTTOMRIGHT: + return gfx::ResizeEdge::kBottomRight; + default: + NOTREACHED(); + return gfx::ResizeEdge::kBottomRight; + } +} + bool IsScreenReaderActive() { UINT screenReader = 0; SystemParametersInfo(SPI_GETSCREENREADER, 0, &screenReader, 0); @@ -263,7 +289,8 @@ bool NativeWindowViews::PreHandleMSG(UINT message, gfx::Rect bounds = gfx::Rect(*reinterpret_cast(l_param)); HWND hwnd = GetAcceleratedWidget(); gfx::Rect dpi_bounds = ScreenToDIPRect(hwnd, bounds); - NotifyWindowWillResize(dpi_bounds, &prevent_default); + NotifyWindowWillResize(dpi_bounds, GetWindowResizeEdge(w_param), + &prevent_default); if (prevent_default) { ::GetWindowRect(hwnd, reinterpret_cast(l_param)); return true; // Tells Windows that the Sizing is handled. diff --git a/shell/browser/ui/cocoa/electron_ns_window_delegate.h b/shell/browser/ui/cocoa/electron_ns_window_delegate.h index c5db7fbb27f..dca6e9a08fb 100644 --- a/shell/browser/ui/cocoa/electron_ns_window_delegate.h +++ b/shell/browser/ui/cocoa/electron_ns_window_delegate.h @@ -8,6 +8,7 @@ #include #include "components/remote_cocoa/app_shim/views_nswindow_delegate.h" +#include "third_party/abseil-cpp/absl/types/optional.h" namespace electron { class NativeWindowMac; @@ -20,6 +21,11 @@ class NativeWindowMac; bool is_zooming_; int level_; bool is_resizable_; + + // Only valid during a live resize. + // Used to keep track of whether a resize is happening horizontally or + // vertically, even if physically the user is resizing in both directions. + absl::optional resizingHorizontally_; } - (id)initWithShell:(electron::NativeWindowMac*)shell; @end diff --git a/shell/browser/ui/cocoa/electron_ns_window_delegate.mm b/shell/browser/ui/cocoa/electron_ns_window_delegate.mm index e2821f09a94..9cc74a8b961 100644 --- a/shell/browser/ui/cocoa/electron_ns_window_delegate.mm +++ b/shell/browser/ui/cocoa/electron_ns_window_delegate.mm @@ -12,6 +12,7 @@ #include "shell/browser/native_window_mac.h" #include "shell/browser/ui/cocoa/electron_preview_item.h" #include "shell/browser/ui/cocoa/electron_touch_bar.h" +#include "ui/gfx/geometry/resize_utils.h" #include "ui/gfx/mac/coordinate_conversion.h" #include "ui/views/cocoa/native_widget_mac_ns_window_host.h" #include "ui/views/widget/native_widget_mac.h" @@ -140,11 +141,21 @@ using FullScreenTransitionState = extraHeightPlusFrame); } + if (!resizingHorizontally_) { + NSWindow* window = shell_->GetNativeWindow().GetNativeNSWindow(); + const auto widthDelta = frameSize.width - [window frame].size.width; + const auto heightDelta = frameSize.height - [window frame].size.height; + resizingHorizontally_ = std::abs(widthDelta) > std::abs(heightDelta); + } + { bool prevent_default = false; NSRect new_bounds = NSMakeRect(sender.frame.origin.x, sender.frame.origin.y, newSize.width, newSize.height); shell_->NotifyWindowWillResize(gfx::ScreenRectFromNSRect(new_bounds), + *resizingHorizontally_ + ? gfx::ResizeEdge::kRight + : gfx::ResizeEdge::kBottom, &prevent_default); if (prevent_default) { return sender.frame.size; @@ -204,6 +215,7 @@ using FullScreenTransitionState = } - (void)windowDidEndLiveResize:(NSNotification*)notification { + resizingHorizontally_.reset(); shell_->NotifyWindowResized(); if (is_zooming_) { if (shell_->IsMaximized()) diff --git a/shell/common/gin_converters/gfx_converter.cc b/shell/common/gin_converters/gfx_converter.cc index 3a9ffc9ed53..23c7d873893 100644 --- a/shell/common/gin_converters/gfx_converter.cc +++ b/shell/common/gin_converters/gfx_converter.cc @@ -10,6 +10,7 @@ #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point_f.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gfx/geometry/resize_utils.h" #include "ui/gfx/geometry/size.h" namespace gin { @@ -160,4 +161,29 @@ v8::Local Converter::ToV8( return dict.GetHandle(); } +v8::Local Converter::ToV8( + v8::Isolate* isolate, + const gfx::ResizeEdge& val) { + switch (val) { + case gfx::ResizeEdge::kRight: + return StringToV8(isolate, "right"); + case gfx::ResizeEdge::kBottom: + return StringToV8(isolate, "bottom"); + case gfx::ResizeEdge::kTop: + return StringToV8(isolate, "top"); + case gfx::ResizeEdge::kLeft: + return StringToV8(isolate, "left"); + case gfx::ResizeEdge::kTopLeft: + return StringToV8(isolate, "top-left"); + case gfx::ResizeEdge::kTopRight: + return StringToV8(isolate, "top-right"); + case gfx::ResizeEdge::kBottomLeft: + return StringToV8(isolate, "bottom-left"); + case gfx::ResizeEdge::kBottomRight: + return StringToV8(isolate, "bottom-right"); + default: + return StringToV8(isolate, "unknown"); + } +} + } // namespace gin diff --git a/shell/common/gin_converters/gfx_converter.h b/shell/common/gin_converters/gfx_converter.h index beb425f682f..6c46a98af41 100644 --- a/shell/common/gin_converters/gfx_converter.h +++ b/shell/common/gin_converters/gfx_converter.h @@ -16,6 +16,7 @@ class Point; class PointF; class Size; class Rect; +enum class ResizeEdge; } // namespace gfx namespace gin { @@ -62,6 +63,12 @@ struct Converter { display::Display* out); }; +template <> +struct Converter { + static v8::Local ToV8(v8::Isolate* isolate, + const gfx::ResizeEdge& val); +}; + } // namespace gin #endif // SHELL_COMMON_GIN_CONVERTERS_GFX_CONVERTER_H_