Browse Source

feat: include resize edge with will-resize event (#29199)

* feat: emit resize edge with will-resize event

fix: wparam type

fix: private member usage on mac

docs: will-resize event edge option

refactor: 'info' -> 'details' for better type gen

* Update docs/api/browser-window.md

Co-authored-by: Samuel Attard <[email protected]>

* Update docs/api/browser-window.md

Co-authored-by: Samuel Attard <[email protected]>
Samuel Maddock 3 years ago
parent
commit
f9d2a7077e

+ 9 - 0
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.

+ 8 - 1
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;
   }
 }

+ 1 - 0
shell/browser/api/electron_api_base_window.h

@@ -62,6 +62,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
   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;

+ 2 - 1
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,

+ 2 - 0
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();

+ 3 - 1
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() {}

+ 28 - 1
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<RECT*>(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<RECT*>(l_param));
         return true;  // Tells Windows that the Sizing is handled.

+ 6 - 0
shell/browser/ui/cocoa/electron_ns_window_delegate.h

@@ -8,6 +8,7 @@
 #include <Quartz/Quartz.h>
 
 #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<bool> resizingHorizontally_;
 }
 - (id)initWithShell:(electron::NativeWindowMac*)shell;
 @end

+ 12 - 0
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())

+ 26 - 0
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<v8::Value> Converter<display::Display>::ToV8(
   return dict.GetHandle();
 }
 
+v8::Local<v8::Value> Converter<gfx::ResizeEdge>::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

+ 7 - 0
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> {
                      display::Display* out);
 };
 
+template <>
+struct Converter<gfx::ResizeEdge> {
+  static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
+                                   const gfx::ResizeEdge& val);
+};
+
 }  // namespace gin
 
 #endif  // SHELL_COMMON_GIN_CONVERTERS_GFX_CONVERTER_H_