diff --git a/atom/browser/api/atom_api_browser_window.cc b/atom/browser/api/atom_api_browser_window.cc index c1fc97476de1..08e953539a98 100644 --- a/atom/browser/api/atom_api_browser_window.cc +++ b/atom/browser/api/atom_api_browser_window.cc @@ -9,7 +9,10 @@ #include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/browser.h" #include "atom/browser/native_window.h" +#include "atom/browser/unresponsive_suppressor.h" #include "atom/browser/web_contents_preferences.h" +#include "atom/browser/window_list.h" +#include "atom/common/api/api_messages.h" #include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/gfx_converter.h" @@ -20,11 +23,14 @@ #include "atom/common/options_switches.h" #include "base/command_line.h" #include "base/threading/thread_task_runner_handle.h" +#include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" #include "content/public/common/content_switches.h" #include "native_mate/constructor.h" #include "native_mate/dictionary.h" #include "ui/gfx/geometry/rect.h" +#include "ui/gl/gpu_switching_manager.h" #if defined(TOOLKIT_VIEWS) #include "atom/browser/native_window_views.h" @@ -77,7 +83,8 @@ v8::Local ToBuffer(v8::Isolate* isolate, void* val, int size) { BrowserWindow::BrowserWindow(v8::Isolate* isolate, v8::Local wrapper, - const mate::Dictionary& options) { + const mate::Dictionary& options) + : weak_factory_(this) { mate::Handle web_contents; // Use options.webPreferences in WebContents. @@ -129,6 +136,8 @@ void BrowserWindow::Init(v8::Isolate* isolate, mate::Handle web_contents) { web_contents_.Reset(isolate, web_contents.ToV8()); api_web_contents_ = web_contents.get(); + api_web_contents_->AddObserver(this); + Observe(api_web_contents_->web_contents()); // Keep a copy of the options for later use. mate::Dictionary(isolate, web_contents->GetWrapper()).Set( @@ -147,6 +156,10 @@ void BrowserWindow::Init(v8::Isolate* isolate, web_contents->SetOwnerWindow(window_.get()); window_->set_is_offscreen_dummy(api_web_contents_->IsOffScreen()); + // Tell the content module to initialize renderer widget with transparent + // mode. + ui::GpuSwitchingManager::SetTransparent(window_->transparent()); + #if defined(TOOLKIT_VIEWS) // Sets the window icon. mate::Handle icon; @@ -164,22 +177,107 @@ void BrowserWindow::Init(v8::Isolate* isolate, // window's JS wrapper gets initialized. if (!parent.IsEmpty()) parent->child_windows_.Set(isolate, ID(), wrapper); + + auto* host = web_contents->web_contents()->GetRenderViewHost(); + if (host) + host->GetWidget()->AddInputEventObserver(this); } BrowserWindow::~BrowserWindow() { if (!window_->IsClosed()) - window_->CloseContents(nullptr); + window_->CloseImmediately(); + + api_web_contents_->RemoveObserver(this); // Destroy the native window in next tick because the native code might be // iterating all windows. base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, window_.release()); } -void BrowserWindow::WillCloseWindow(bool* prevent_default) { - *prevent_default = Emit("close"); +void BrowserWindow::OnInputEvent(const blink::WebInputEvent& event) { + switch (event.GetType()) { + case blink::WebInputEvent::kGestureScrollBegin: + case blink::WebInputEvent::kGestureScrollUpdate: + case blink::WebInputEvent::kGestureScrollEnd: + Emit("scroll-touch-edge"); + break; + default: + break; + } } -void BrowserWindow::WillDestroyNativeObject() { +void BrowserWindow::RenderViewHostChanged(content::RenderViewHost* old_host, + content::RenderViewHost* new_host) { + if (old_host) + old_host->GetWidget()->RemoveInputEventObserver(this); + if (new_host) + new_host->GetWidget()->AddInputEventObserver(this); +} + +void BrowserWindow::RenderViewCreated( + content::RenderViewHost* render_view_host) { + if (!window_->transparent()) + return; + + content::RenderWidgetHostImpl* impl = content::RenderWidgetHostImpl::FromID( + render_view_host->GetProcess()->GetID(), + render_view_host->GetRoutingID()); + if (impl) + impl->SetBackgroundOpaque(false); +} + +void BrowserWindow::DidFirstVisuallyNonEmptyPaint() { + if (window_->IsVisible()) + return; + + // When there is a non-empty first paint, resize the RenderWidget to force + // Chromium to draw. + const auto view = web_contents()->GetRenderWidgetHostView(); + view->Show(); + view->SetSize(window_->GetContentSize()); + + // Emit the ReadyToShow event in next tick in case of pending drawing work. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind([](base::WeakPtr self) { + if (self) + self->Emit("ready-to-show"); + }, GetWeakPtr())); +} + +void BrowserWindow::BeforeUnloadDialogCancelled() { + WindowList::WindowCloseCancelled(window_.get()); + // Cancel unresponsive event when window close is cancelled. + window_unresponsive_closure_.Cancel(); +} + +void BrowserWindow::OnRendererUnresponsive(content::RenderWidgetHost*) { + // Schedule the unresponsive shortly later, since we may receive the + // responsive event soon. This could happen after the whole application had + // blocked for a while. + // Also notice that when closing this event would be ignored because we have + // explicitly started a close timeout counter. This is on purpose because we + // don't want the unresponsive event to be sent too early when user is closing + // the window. + ScheduleUnresponsiveEvent(50); +} + +bool BrowserWindow::OnMessageReceived(const IPC::Message& message, + content::RenderFrameHost* rfh) { + bool handled = true; + IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BrowserWindow, message, rfh) + IPC_MESSAGE_HANDLER(AtomFrameHostMsg_UpdateDraggableRegions, + UpdateDraggableRegions) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + return handled; +} + +void BrowserWindow::OnCloseContents() { + if (!web_contents()) + return; + Observe(nullptr); + // Close all child windows before closing current window. v8::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); @@ -188,6 +286,48 @@ void BrowserWindow::WillDestroyNativeObject() { if (mate::ConvertFromV8(isolate(), value, &child) && !child.IsEmpty()) child->window_->CloseImmediately(); } + + // When the web contents is gone, close the window immediately, but the + // memory will not be freed until you call delete. + // In this way, it would be safe to manage windows via smart pointers. If you + // want to free memory when the window is closed, you can do deleting by + // overriding the OnWindowClosed method in the observer. + window_->CloseImmediately(); + + // Do not sent "unresponsive" event after window is closed. + window_unresponsive_closure_.Cancel(); +} + +void BrowserWindow::OnRendererResponsive() { + window_unresponsive_closure_.Cancel(); + Emit("responsive"); +} + +void BrowserWindow::WillCloseWindow(bool* prevent_default) { + *prevent_default = Emit("close"); +} + +void BrowserWindow::OnCloseButtonClicked(bool* prevent_default) { + // When user tries to close the window by clicking the close button, we do + // not close the window immediately, instead we try to close the web page + // first, and when the web page is closed the window will also be closed. + *prevent_default = true; + + // Assume the window is not responding if it doesn't cancel the close and is + // not closed in 5s, in this way we can quickly show the unresponsive + // dialog when the window is busy executing some script withouth waiting for + // the unresponsive timeout. + if (window_unresponsive_closure_.IsCancelled()) + ScheduleUnresponsiveEvent(5000); + + if (!web_contents()) + // Already closed by renderer + return; + + if (web_contents()->NeedToFireBeforeUnload()) + web_contents()->DispatchBeforeUnload(); + else + web_contents()->Close(); } void BrowserWindow::OnWindowClosed() { @@ -231,10 +371,6 @@ void BrowserWindow::OnWindowHide() { Emit("hide"); } -void BrowserWindow::OnReadyToShow() { - Emit("ready-to-show"); -} - void BrowserWindow::OnWindowMaximize() { Emit("maximize"); } @@ -279,10 +415,6 @@ void BrowserWindow::OnWindowScrollTouchEnd() { Emit("scroll-touch-end"); } -void BrowserWindow::OnWindowScrollTouchEdge() { - Emit("scroll-touch-edge"); -} - void BrowserWindow::OnWindowSwipe(const std::string& direction) { Emit("swipe", direction); } @@ -303,14 +435,6 @@ void BrowserWindow::OnWindowLeaveHtmlFullScreen() { Emit("leave-html-full-screen"); } -void BrowserWindow::OnRendererUnresponsive() { - Emit("unresponsive"); -} - -void BrowserWindow::OnRendererResponsive() { - Emit("responsive"); -} - void BrowserWindow::OnExecuteWindowsCommand(const std::string& command_name) { Emit("app-command", command_name); } @@ -1008,6 +1132,32 @@ void BrowserWindow::RemoveFromParentChildWindows() { parent->child_windows_.Remove(ID()); } +void BrowserWindow::UpdateDraggableRegions( + content::RenderFrameHost* rfh, + const std::vector& regions) { + window_->UpdateDraggableRegions(regions); +} + +void BrowserWindow::ScheduleUnresponsiveEvent(int ms) { + if (!window_unresponsive_closure_.IsCancelled()) + return; + + window_unresponsive_closure_.Reset( + base::Bind(&BrowserWindow::NotifyWindowUnresponsive, GetWeakPtr())); + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, + window_unresponsive_closure_.callback(), + base::TimeDelta::FromMilliseconds(ms)); +} + +void BrowserWindow::NotifyWindowUnresponsive() { + window_unresponsive_closure_.Cancel(); + if (!window_->IsClosed() && window_->IsEnabled() && + !IsUnresponsiveEventSuppressed()) { + Emit("unresponsive"); + } +} + // static void BrowserWindow::BuildPrototype(v8::Isolate* isolate, v8::Local prototype) { diff --git a/atom/browser/api/atom_api_browser_window.h b/atom/browser/api/atom_api_browser_window.h index 50d77a24928e..65f3a10f7ad9 100644 --- a/atom/browser/api/atom_api_browser_window.h +++ b/atom/browser/api/atom_api_browser_window.h @@ -10,14 +10,15 @@ #include #include -#include "atom/browser/api/trackable_object.h" +#include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/native_window.h" #include "atom/browser/native_window_observer.h" #include "atom/common/api/atom_api_native_image.h" #include "atom/common/key_weak_map.h" -#include "native_mate/handle.h" +#include "base/cancelable_callback.h" +#include "base/memory/weak_ptr.h" +#include "content/public/browser/render_widget_host.h" #include "native_mate/persistent_dictionary.h" -#include "ui/gfx/image/image.h" class GURL; @@ -36,9 +37,10 @@ class NativeWindow; namespace api { -class WebContents; - class BrowserWindow : public mate::TrackableObject, + public content::RenderWidgetHost::InputEventObserver, + public content::WebContentsObserver, + public ExtendedWebContentsObserver, public NativeWindowObserver { public: static mate::WrappableBase* New(mate::Arguments* args); @@ -60,16 +62,32 @@ class BrowserWindow : public mate::TrackableObject, const mate::Dictionary& options); ~BrowserWindow() override; + // content::RenderWidgetHost::InputEventObserver: + void OnInputEvent(const blink::WebInputEvent& event) override; + + // content::WebContentsObserver: + void RenderViewHostChanged(content::RenderViewHost* old_host, + content::RenderViewHost* new_host) override; + void RenderViewCreated(content::RenderViewHost* render_view_host) override; + void DidFirstVisuallyNonEmptyPaint() override; + void BeforeUnloadDialogCancelled() override; + void OnRendererUnresponsive(content::RenderWidgetHost*) override; + bool OnMessageReceived(const IPC::Message& message, + content::RenderFrameHost* rfh) override; + + // ExtendedWebContentsObserver: + void OnCloseContents() override; + void OnRendererResponsive() override; + // NativeWindowObserver: void WillCloseWindow(bool* prevent_default) override; - void WillDestroyNativeObject() override; + void OnCloseButtonClicked(bool* prevent_default) override; void OnWindowClosed() override; void OnWindowEndSession() override; void OnWindowBlur() override; void OnWindowFocus() override; void OnWindowShow() override; void OnWindowHide() override; - void OnReadyToShow() override; void OnWindowMaximize() override; void OnWindowUnmaximize() override; void OnWindowMinimize() override; @@ -79,7 +97,6 @@ class BrowserWindow : public mate::TrackableObject, void OnWindowMoved() override; void OnWindowScrollTouchBegin() override; void OnWindowScrollTouchEnd() override; - void OnWindowScrollTouchEdge() override; void OnWindowSwipe(const std::string& direction) override; void OnWindowSheetBegin() override; void OnWindowSheetEnd() override; @@ -87,8 +104,6 @@ class BrowserWindow : public mate::TrackableObject, void OnWindowLeaveFullScreen() override; void OnWindowEnterHtmlFullScreen() override; void OnWindowLeaveHtmlFullScreen() override; - void OnRendererUnresponsive() override; - void OnRendererResponsive() override; void OnExecuteWindowsCommand(const std::string& command_name) override; void OnTouchBarItemResult(const std::string& item_id, const base::DictionaryValue& details) override; @@ -98,11 +113,16 @@ class BrowserWindow : public mate::TrackableObject, void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) override; #endif + base::WeakPtr GetWeakPtr() { + return weak_factory_.GetWeakPtr(); + } + private: void Init(v8::Isolate* isolate, v8::Local wrapper, const mate::Dictionary& options, mate::Handle web_contents); + // APIs for NativeWindow. void Close(); void Focus(); @@ -235,11 +255,26 @@ class BrowserWindow : public mate::TrackableObject, // Remove this window from parent window's |child_windows_|. void RemoveFromParentChildWindows(); + // Called when the window needs to update its draggable region. + void UpdateDraggableRegions( + content::RenderFrameHost* rfh, + const std::vector& regions); + + // Schedule a notification unresponsive event. + void ScheduleUnresponsiveEvent(int ms); + + // Dispatch unresponsive event to observers. + void NotifyWindowUnresponsive(); + #if defined(OS_WIN) typedef std::map MessageCallbackMap; MessageCallbackMap messages_callback_map_; #endif + // Closure that would be called when window is unresponsive when closing, + // it should be cancelled when we can prove that the window is responsive. + base::CancelableClosure window_unresponsive_closure_; + v8::Global browser_view_; v8::Global web_contents_; v8::Global menu_; @@ -250,6 +285,8 @@ class BrowserWindow : public mate::TrackableObject, std::unique_ptr window_; + base::WeakPtrFactory weak_factory_; + DISALLOW_COPY_AND_ASSIGN(BrowserWindow); }; diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index f44bb96ad0c5..86851826bb4a 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -89,6 +89,11 @@ #include "ui/aura/window.h" #endif +#if defined(OS_LINUX) || defined(OS_WIN) +#include "content/public/common/renderer_preferences.h" +#include "ui/gfx/font_render_params.h" +#endif + #include "atom/common/node_includes.h" namespace { @@ -412,6 +417,19 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate, managed_web_contents()->GetView()->SetDelegate(this); +#if defined(OS_LINUX) || defined(OS_WIN) + // Update font settings. + auto* prefs = web_contents->GetMutableRendererPrefs(); + CR_DEFINE_STATIC_LOCAL(const gfx::FontRenderParams, params, + (gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr))); + prefs->should_antialias_text = params.antialiasing; + prefs->use_subpixel_positioning = params.subpixel_positioning; + prefs->hinting = params.hinting; + prefs->use_autohinter = params.autohinter; + prefs->use_bitmaps = params.use_bitmaps; + prefs->subpixel_rendering = params.subpixel_rendering; +#endif + // Save the preferences in C++. new WebContentsPreferences(web_contents, options); @@ -446,6 +464,8 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate, WebContents::~WebContents() { // The destroy() is called. if (managed_web_contents()) { + managed_web_contents()->GetView()->SetDelegate(nullptr); + // For webview we need to tell content module to do some cleanup work before // destroying it. if (type_ == WEB_VIEW) @@ -457,7 +477,8 @@ WebContents::~WebContents() { DestroyWebContents(false /* async */); } else { if (type_ == BROWSER_WINDOW && owner_window()) { - owner_window()->CloseContents(nullptr); + for (ExtendedWebContentsObserver& observer : observers_) + observer.OnCloseContents(); } else { DestroyWebContents(true /* async */); } @@ -565,9 +586,10 @@ void WebContents::MoveContents(content::WebContents* source, void WebContents::CloseContents(content::WebContents* source) { Emit("close"); - - if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window()) - owner_window()->CloseContents(source); + if (managed_web_contents()) + managed_web_contents()->GetView()->SetDelegate(nullptr); + for (ExtendedWebContentsObserver& observer : observers_) + observer.OnCloseContents(); } void WebContents::ActivateContents(content::WebContents* source) { @@ -636,14 +658,12 @@ void WebContents::RendererUnresponsive( content::WebContents* source, const content::WebContentsUnresponsiveState& unresponsive_state) { Emit("unresponsive"); - if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window()) - owner_window()->RendererUnresponsive(source); } void WebContents::RendererResponsive(content::WebContents* source) { Emit("responsive"); - if ((type_ == BROWSER_WINDOW || type_ == OFF_SCREEN) && owner_window()) - owner_window()->RendererResponsive(source); + for (ExtendedWebContentsObserver& observer : observers_) + observer.OnRendererResponsive(); } bool WebContents::HandleContextMenu(const content::ContextMenuParams& params) { diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 16f23210557c..5d0f9ea3df06 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -13,6 +13,7 @@ #include "atom/browser/api/trackable_object.h" #include "atom/browser/common_web_contents_delegate.h" #include "atom/browser/ui/autofill_popup.h" +#include "base/observer_list.h" #include "content/common/cursors/webcursor.h" #include "content/public/browser/keyboard_event_processing_result.h" #include "content/public/browser/web_contents.h" @@ -49,6 +50,15 @@ class WebViewGuestDelegate; namespace api { +// Certain events are only in WebContentsDelegate, provide our own Observer to +// dispatch those events. +class ExtendedWebContentsObserver { + public: + virtual void OnCloseContents() {} + virtual void OnRendererResponsive() {} +}; + +// Wrapper around the content::WebContents. class WebContents : public mate::TrackableObject, public CommonWebContentsDelegate, public content::WebContentsObserver { @@ -231,6 +241,13 @@ class WebContents : public mate::TrackableObject, WebContentsZoomController* GetZoomController() { return zoom_controller_; } + void AddObserver(ExtendedWebContentsObserver* obs) { + observers_.AddObserver(obs); + } + void RemoveObserver(ExtendedWebContentsObserver* obs) { + observers_.RemoveObserver(obs); + } + protected: WebContents(v8::Isolate* isolate, content::WebContents* web_contents, @@ -421,6 +438,9 @@ class WebContents : public mate::TrackableObject, // Whether to enable devtools. bool enable_devtools_; + // Observers of this WebContents. + base::ObserverList observers_; + DISALLOW_COPY_AND_ASSIGN(WebContents); }; diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 34778fb64347..a96b65424a90 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -11,9 +11,8 @@ #include "atom/browser/atom_browser_context.h" #include "atom/browser/atom_browser_main_parts.h" #include "atom/browser/browser.h" -#include "atom/browser/unresponsive_suppressor.h" #include "atom/browser/window_list.h" -#include "atom/common/api/api_messages.h" +#include "atom/common/draggable_region.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/options_switches.h" #include "base/files/file_util.h" @@ -24,7 +23,6 @@ #include "brightray/browser/inspectable_web_contents.h" #include "brightray/browser/inspectable_web_contents_view.h" #include "components/prefs/pref_service.h" -#include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/plugin_service.h" #include "content/public/browser/render_process_host.h" @@ -40,12 +38,6 @@ #include "ui/gfx/geometry/rect.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size_conversions.h" -#include "ui/gl/gpu_switching_manager.h" - -#if defined(OS_LINUX) || defined(OS_WIN) -#include "content/public/common/renderer_preferences.h" -#include "ui/gfx/font_render_params.h" -#endif DEFINE_WEB_CONTENTS_USER_DATA_KEY(atom::NativeWindowRelay); @@ -75,24 +67,6 @@ NativeWindow::NativeWindow( if (parent) options.Get("modal", &is_modal_); -#if defined(OS_LINUX) || defined(OS_WIN) - auto* prefs = web_contents()->GetMutableRendererPrefs(); - - // Update font settings. - CR_DEFINE_STATIC_LOCAL(const gfx::FontRenderParams, params, - (gfx::GetFontRenderParams(gfx::FontRenderParamsQuery(), nullptr))); - prefs->should_antialias_text = params.antialiasing; - prefs->use_subpixel_positioning = params.subpixel_positioning; - prefs->hinting = params.hinting; - prefs->use_autohinter = params.autohinter; - prefs->use_bitmaps = params.use_bitmaps; - prefs->subpixel_rendering = params.subpixel_rendering; -#endif - - // Tell the content module to initialize renderer widget with transparent - // mode. - ui::GpuSwitchingManager::SetTransparent(transparent_); - WindowList::AddWindow(this); } @@ -427,7 +401,8 @@ void NativeWindow::PreviewFile(const std::string& path, void NativeWindow::CloseFilePreview() { } -void NativeWindow::RequestToClosePage() { +void NativeWindow::NotifyWindowCloseButtonClicked() { + // First ask the observers whether we want to close. bool prevent_default = false; for (NativeWindowObserver& observer : observers_) observer.WillCloseWindow(&prevent_default); @@ -436,60 +411,13 @@ void NativeWindow::RequestToClosePage() { return; } - // Assume the window is not responding if it doesn't cancel the close and is - // not closed in 5s, in this way we can quickly show the unresponsive - // dialog when the window is busy executing some script withouth waiting for - // the unresponsive timeout. - if (window_unresposive_closure_.IsCancelled()) - ScheduleUnresponsiveEvent(5000); - - if (!web_contents()) - // Already closed by renderer - return; - - if (web_contents()->NeedToFireBeforeUnload()) - web_contents()->DispatchBeforeUnload(); - else - web_contents()->Close(); -} - -void NativeWindow::CloseContents(content::WebContents* source) { - if (!inspectable_web_contents_) - return; - - inspectable_web_contents_->GetView()->SetDelegate(nullptr); - inspectable_web_contents_ = nullptr; - Observe(nullptr); - + // Then ask the observers how should we close the window. for (NativeWindowObserver& observer : observers_) - observer.WillDestroyNativeObject(); + observer.OnCloseButtonClicked(&prevent_default); + if (prevent_default) + return; - // When the web contents is gone, close the window immediately, but the - // memory will not be freed until you call delete. - // In this way, it would be safe to manage windows via smart pointers. If you - // want to free memory when the window is closed, you can do deleting by - // overriding the OnWindowClosed method in the observer. CloseImmediately(); - - // Do not sent "unresponsive" event after window is closed. - window_unresposive_closure_.Cancel(); -} - -void NativeWindow::RendererUnresponsive(content::WebContents* source) { - // Schedule the unresponsive shortly later, since we may receive the - // responsive event soon. This could happen after the whole application had - // blocked for a while. - // Also notice that when closing this event would be ignored because we have - // explicitly started a close timeout counter. This is on purpose because we - // don't want the unresponsive event to be sent too early when user is closing - // the window. - ScheduleUnresponsiveEvent(50); -} - -void NativeWindow::RendererResponsive(content::WebContents* source) { - window_unresposive_closure_.Cancel(); - for (NativeWindowObserver& observer : observers_) - observer.OnRendererResponsive(); } void NativeWindow::NotifyWindowClosed() { @@ -578,11 +506,6 @@ void NativeWindow::NotifyWindowScrollTouchEnd() { observer.OnWindowScrollTouchEnd(); } -void NativeWindow::NotifyWindowScrollTouchEdge() { - for (NativeWindowObserver& observer : observers_) - observer.OnWindowScrollTouchEdge(); -} - void NativeWindow::NotifyWindowSwipe(const std::string& direction) { for (NativeWindowObserver& observer : observers_) observer.OnWindowSwipe(direction); @@ -653,87 +576,4 @@ std::unique_ptr NativeWindow::DraggableRegionsToSkRegion( return sk_region; } -void NativeWindow::RenderViewCreated( - content::RenderViewHost* render_view_host) { - if (!transparent_) - return; - - content::RenderWidgetHostImpl* impl = content::RenderWidgetHostImpl::FromID( - render_view_host->GetProcess()->GetID(), - render_view_host->GetRoutingID()); - if (impl) - impl->SetBackgroundOpaque(false); -} - -void NativeWindow::BeforeUnloadDialogCancelled() { - WindowList::WindowCloseCancelled(this); - - // Cancel unresponsive event when window close is cancelled. - window_unresposive_closure_.Cancel(); -} - -void NativeWindow::DidFirstVisuallyNonEmptyPaint() { - if (IsVisible()) - return; - - // When there is a non-empty first paint, resize the RenderWidget to force - // Chromium to draw. - const auto view = web_contents()->GetRenderWidgetHostView(); - view->Show(); - view->SetSize(GetContentSize()); - - // Emit the ReadyToShow event in next tick in case of pending drawing work. - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, - base::Bind(&NativeWindow::NotifyReadyToShow, GetWeakPtr())); -} - -bool NativeWindow::OnMessageReceived(const IPC::Message& message, - content::RenderFrameHost* rfh) { - bool handled = true; - IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(NativeWindow, message, rfh) - IPC_MESSAGE_HANDLER(AtomFrameHostMsg_UpdateDraggableRegions, - UpdateDraggableRegions) - IPC_MESSAGE_UNHANDLED(handled = false) - IPC_END_MESSAGE_MAP() - - return handled; -} - -void NativeWindow::UpdateDraggableRegions( - content::RenderFrameHost* rfh, - const std::vector& regions) { - // Draggable region is not supported for non-frameless window. - if (has_frame_) - return; - draggable_region_ = DraggableRegionsToSkRegion(regions); -} - -void NativeWindow::ScheduleUnresponsiveEvent(int ms) { - if (!window_unresposive_closure_.IsCancelled()) - return; - - window_unresposive_closure_.Reset( - base::Bind(&NativeWindow::NotifyWindowUnresponsive, - weak_factory_.GetWeakPtr())); - base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( - FROM_HERE, - window_unresposive_closure_.callback(), - base::TimeDelta::FromMilliseconds(ms)); -} - -void NativeWindow::NotifyWindowUnresponsive() { - window_unresposive_closure_.Cancel(); - - if (!is_closed_ && !IsUnresponsiveEventSuppressed() && IsEnabled()) { - for (NativeWindowObserver& observer : observers_) - observer.OnRendererUnresponsive(); - } -} - -void NativeWindow::NotifyReadyToShow() { - for (NativeWindowObserver& observer : observers_) - observer.OnReadyToShow(); -} - } // namespace atom diff --git a/atom/browser/native_window.h b/atom/browser/native_window.h index d1cfa7cc3529..5661f6237d17 100644 --- a/atom/browser/native_window.h +++ b/atom/browser/native_window.h @@ -13,7 +13,6 @@ #include "atom/browser/native_window_observer.h" #include "atom/browser/ui/accelerator_util.h" #include "atom/browser/ui/atom_menu_model.h" -#include "base/cancelable_callback.h" #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "base/supports_user_data.h" @@ -216,17 +215,21 @@ class NativeWindow : public base::SupportsUserData, const std::string& display_name); virtual void CloseFilePreview(); + // Converts between content bounds and window bounds. + virtual gfx::Rect ContentBoundsToWindowBounds( + const gfx::Rect& bounds) const = 0; + virtual gfx::Rect WindowBoundsToContentBounds( + const gfx::Rect& bounds) const = 0; + + // Called when the window needs to update its draggable region. + virtual void UpdateDraggableRegions( + const std::vector& regions) = 0; + base::WeakPtr GetWeakPtr() { return weak_factory_.GetWeakPtr(); } - // Requests the WebContents to close, can be cancelled by the page. - virtual void RequestToClosePage(); - // Methods called by the WebContents. - virtual void CloseContents(content::WebContents* source); - virtual void RendererUnresponsive(content::WebContents* source); - virtual void RendererResponsive(content::WebContents* source); virtual void HandleKeyboardEvent( content::WebContents*, const content::NativeWebKeyboardEvent& event) {} @@ -240,6 +243,7 @@ class NativeWindow : public base::SupportsUserData, // Public API used by platform-dependent delegates and observers to send UI // related notifications. + void NotifyWindowCloseButtonClicked(); void NotifyWindowClosed(); void NotifyWindowEndSession(); void NotifyWindowBlur(); @@ -255,7 +259,6 @@ class NativeWindow : public base::SupportsUserData, void NotifyWindowMoved(); void NotifyWindowScrollTouchBegin(); void NotifyWindowScrollTouchEnd(); - void NotifyWindowScrollTouchEdge(); void NotifyWindowSwipe(const std::string& direction); void NotifyWindowSheetBegin(); void NotifyWindowSheetEnd(); @@ -287,7 +290,6 @@ class NativeWindow : public base::SupportsUserData, void set_has_frame(bool has_frame) { has_frame_ = has_frame; } bool transparent() const { return transparent_; } - SkRegion* draggable_region() const { return draggable_region_.get(); } bool enable_larger_than_screen() const { return enable_larger_than_screen_; } void set_is_offscreen_dummy(bool is_dummy) { is_osr_dummy_ = is_dummy; } @@ -306,44 +308,13 @@ class NativeWindow : public base::SupportsUserData, std::unique_ptr DraggableRegionsToSkRegion( const std::vector& regions); - // Converts between content bounds and window bounds. - virtual gfx::Rect ContentBoundsToWindowBounds( - const gfx::Rect& bounds) const = 0; - virtual gfx::Rect WindowBoundsToContentBounds( - const gfx::Rect& bounds) const = 0; - - // Called when the window needs to update its draggable region. - virtual void UpdateDraggableRegions( - content::RenderFrameHost* rfh, - const std::vector& regions); - - // content::WebContentsObserver: - void RenderViewCreated(content::RenderViewHost* render_view_host) override; - void BeforeUnloadDialogCancelled() override; - void DidFirstVisuallyNonEmptyPaint() override; - bool OnMessageReceived(const IPC::Message& message, - content::RenderFrameHost* rfh) override; - private: - // Schedule a notification unresponsive event. - void ScheduleUnresponsiveEvent(int ms); - - // Dispatch unresponsive event to observers. - void NotifyWindowUnresponsive(); - - // Dispatch ReadyToShow event to observers. - void NotifyReadyToShow(); - // Whether window has standard frame. bool has_frame_; // Whether window is transparent. bool transparent_; - // For custom drag, the whole window is non-draggable and the draggable region - // has to been explicitly provided. - std::unique_ptr draggable_region_; // used in custom drag. - // Minimum and maximum size, stored as content size. extensions::SizeConstraints size_constraints_; @@ -353,10 +324,6 @@ class NativeWindow : public base::SupportsUserData, // The windows has been closed. bool is_closed_; - // Closure that would be called when window is unresponsive when closing, - // it should be cancelled when we can prove that the window is responsive. - base::CancelableClosure window_unresposive_closure_; - // Used to display sheets at the appropriate horizontal and vertical offsets // on macOS. double sheet_offset_x_; diff --git a/atom/browser/native_window_mac.h b/atom/browser/native_window_mac.h index 60d8fc23f59a..a54e24b4668c 100644 --- a/atom/browser/native_window_mac.h +++ b/atom/browser/native_window_mac.h @@ -12,7 +12,6 @@ #include "atom/browser/native_window.h" #include "base/mac/scoped_nsobject.h" -#include "content/public/browser/render_widget_host.h" @class AtomNSWindow; @class AtomNSWindowDelegate; @@ -20,8 +19,7 @@ namespace atom { -class NativeWindowMac : public NativeWindow, - public content::RenderWidgetHost::InputEventObserver { +class NativeWindowMac : public NativeWindow { public: NativeWindowMac(brightray::InspectableWebContents* inspectable_web_contents, const mate::Dictionary& options, @@ -119,17 +117,10 @@ class NativeWindowMac : public NativeWindow, void RefreshTouchBarItem(const std::string& item_id) override; void SetEscapeTouchBarItem(const mate::PersistentDictionary& item) override; - // content::RenderWidgetHost::InputEventObserver: - void OnInputEvent(const blink::WebInputEvent& event) override; - - // content::WebContentsObserver: - void RenderViewHostChanged(content::RenderViewHost* old_host, - content::RenderViewHost* new_host) override; - - // Refresh the DraggableRegion views. - void UpdateDraggableRegionViews() { - UpdateDraggableRegionViews(draggable_regions_); - } + gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const; + gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const; + void UpdateDraggableRegions( + const std::vector& regions) override; // Set the attribute of NSWindow while work around a bug of zoom button. void SetStyleMask(bool on, NSUInteger flag); @@ -144,10 +135,11 @@ class NativeWindowMac : public NativeWindow, TitleBarStyle title_bar_style() const { return title_bar_style_; } bool zoom_to_page_width() const { return zoom_to_page_width_; } - bool fullscreen_window_title() const { return fullscreen_window_title_; } - bool simple_fullscreen() const { return always_simple_fullscreen_; } + const std::vector& draggable_regions() const { + return draggable_regions_; + } protected: // Return a vector of non-draggable regions that fill a window of size @@ -156,26 +148,12 @@ class NativeWindowMac : public NativeWindow, const std::vector& regions, int width, int height); private: - // NativeWindow: - gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const; - gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const; - void UpdateDraggableRegions( - content::RenderFrameHost* rfh, - const std::vector& regions) override; - void InternalSetParentWindow(NativeWindow* parent, bool attach); void ShowWindowButton(NSWindowButton button); void InstallView(); void UninstallView(); - // Install the drag view, which will cover the whole window and decides - // whether we can drag. - void UpdateDraggableRegionViews(const std::vector& regions); - - void RegisterInputEventObserver(content::RenderViewHost* host); - void UnregisterInputEventObserver(content::RenderViewHost* host); - void SetRenderWidgetHostOpaque(bool opaque); base::scoped_nsobject window_; diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index ad1713e40124..72dd45728f15 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -296,7 +296,7 @@ bool ScopedDisableResize::disable_resize_ = false; } - (void)windowDidResize:(NSNotification*)notification { - shell_->UpdateDraggableRegionViews(); + shell_->UpdateDraggableRegions(shell_->draggable_regions()); shell_->NotifyWindowResize(); } @@ -415,10 +415,7 @@ bool ScopedDisableResize::disable_resize_ = false; } - (BOOL)windowShouldClose:(id)window { - // When user tries to close the window by clicking the close button, we do - // not close the window immediately, instead we try to close the web page - // first, and when the web page is closed the window will also be closed. - shell_->RequestToClosePage(); + shell_->NotifyWindowCloseButtonClicked(); return NO; } @@ -1041,9 +1038,6 @@ NativeWindowMac::NativeWindowMac( // Set maximizable state last to ensure zoom button does not get reset // by calls to other APIs. SetMaximizable(maximizable); - - RegisterInputEventObserver( - web_contents->GetWebContents()->GetRenderViewHost()); } NativeWindowMac::~NativeWindowMac() { @@ -1789,42 +1783,6 @@ void NativeWindowMac::SetEscapeTouchBarItem(const mate::PersistentDictionary& it [window_ setEscapeTouchBarItem:item]; } -void NativeWindowMac::OnInputEvent(const blink::WebInputEvent& event) { - switch (event.GetType()) { - case blink::WebInputEvent::kGestureScrollBegin: - case blink::WebInputEvent::kGestureScrollUpdate: - case blink::WebInputEvent::kGestureScrollEnd: - this->NotifyWindowScrollTouchEdge(); - break; - default: - break; - } -} - -void NativeWindowMac::RenderViewHostChanged( - content::RenderViewHost* old_host, - content::RenderViewHost* new_host) { - UnregisterInputEventObserver(old_host); - RegisterInputEventObserver(new_host); -} - -std::vector NativeWindowMac::CalculateNonDraggableRegions( - const std::vector& regions, int width, int height) { - std::vector result; - if (regions.empty()) { - result.push_back(gfx::Rect(0, 0, width, height)); - } else { - std::unique_ptr draggable(DraggableRegionsToSkRegion(regions)); - std::unique_ptr non_draggable(new SkRegion); - non_draggable->op(0, 0, width, height, SkRegion::kUnion_Op); - non_draggable->op(*draggable, SkRegion::kDifference_Op); - for (SkRegion::Iterator it(*non_draggable); !it.done(); it.next()) { - result.push_back(gfx::SkIRectToRect(it.rect())); - } - } - return result; -} - gfx::Rect NativeWindowMac::ContentBoundsToWindowBounds( const gfx::Rect& bounds) const { if (has_frame()) { @@ -1852,11 +1810,77 @@ gfx::Rect NativeWindowMac::WindowBoundsToContentBounds( } void NativeWindowMac::UpdateDraggableRegions( - content::RenderFrameHost* rfh, const std::vector& regions) { - NativeWindow::UpdateDraggableRegions(rfh, regions); + if (has_frame()) + return; + + // All ControlRegionViews should be added as children of the WebContentsView, + // because WebContentsView will be removed and re-added when entering and + // leaving fullscreen mode. + NSView* webView = web_contents()->GetNativeView(); + NSInteger webViewWidth = NSWidth([webView bounds]); + NSInteger webViewHeight = NSHeight([webView bounds]); + + if ([webView respondsToSelector:@selector(setMouseDownCanMoveWindow:)]) { + [webView setMouseDownCanMoveWindow:YES]; + } + + // Remove all ControlRegionViews that are added last time. + // Note that [webView subviews] returns the view's mutable internal array and + // it should be copied to avoid mutating the original array while enumerating + // it. + base::scoped_nsobject subviews([[webView subviews] copy]); + for (NSView* subview in subviews.get()) + if ([subview isKindOfClass:[ControlRegionView class]]) + [subview removeFromSuperview]; + + // Draggable regions is implemented by having the whole web view draggable + // (mouseDownCanMoveWindow) and overlaying regions that are not draggable. draggable_regions_ = regions; - UpdateDraggableRegionViews(regions); + std::vector system_drag_exclude_areas = + CalculateNonDraggableRegions(regions, webViewWidth, webViewHeight); + + if (browser_view_) + browser_view_->UpdateDraggableRegions(system_drag_exclude_areas); + + // Create and add a ControlRegionView for each region that needs to be + // excluded from the dragging. + for (std::vector::const_iterator iter = + system_drag_exclude_areas.begin(); + iter != system_drag_exclude_areas.end(); + ++iter) { + base::scoped_nsobject controlRegion( + [[ControlRegionView alloc] initWithFrame:NSZeroRect]); + [controlRegion setFrame:NSMakeRect(iter->x(), + webViewHeight - iter->bottom(), + iter->width(), + iter->height())]; + [webView addSubview:controlRegion]; + } + + // AppKit will not update its cache of mouseDownCanMoveWindow unless something + // changes. Previously we tried adding an NSView and removing it, but for some + // reason it required reposting the mouse-down event, and didn't always work. + // Calling the below seems to be an effective solution. + [window_ setMovableByWindowBackground:NO]; + [window_ setMovableByWindowBackground:YES]; +} + +std::vector NativeWindowMac::CalculateNonDraggableRegions( + const std::vector& regions, int width, int height) { + std::vector result; + if (regions.empty()) { + result.push_back(gfx::Rect(0, 0, width, height)); + } else { + std::unique_ptr draggable(DraggableRegionsToSkRegion(regions)); + std::unique_ptr non_draggable(new SkRegion); + non_draggable->op(0, 0, width, height, SkRegion::kUnion_Op); + non_draggable->op(*draggable, SkRegion::kDifference_Op); + for (SkRegion::Iterator it(*non_draggable); !it.done(); it.next()) { + result.push_back(gfx::SkIRectToRect(it.rect())); + } + } + return result; } void NativeWindowMac::InternalSetParentWindow(NativeWindow* parent, bool attach) { @@ -1944,63 +1968,6 @@ void NativeWindowMac::UninstallView() { [view removeFromSuperview]; } -void NativeWindowMac::UpdateDraggableRegionViews( - const std::vector& regions) { - if (has_frame()) - return; - - // All ControlRegionViews should be added as children of the WebContentsView, - // because WebContentsView will be removed and re-added when entering and - // leaving fullscreen mode. - NSView* webView = web_contents()->GetNativeView(); - NSInteger webViewWidth = NSWidth([webView bounds]); - NSInteger webViewHeight = NSHeight([webView bounds]); - - if ([webView respondsToSelector:@selector(setMouseDownCanMoveWindow:)]) { - [webView setMouseDownCanMoveWindow:YES]; - } - - // Remove all ControlRegionViews that are added last time. - // Note that [webView subviews] returns the view's mutable internal array and - // it should be copied to avoid mutating the original array while enumerating - // it. - base::scoped_nsobject subviews([[webView subviews] copy]); - for (NSView* subview in subviews.get()) - if ([subview isKindOfClass:[ControlRegionView class]]) - [subview removeFromSuperview]; - - // Draggable regions is implemented by having the whole web view draggable - // (mouseDownCanMoveWindow) and overlaying regions that are not draggable. - std::vector system_drag_exclude_areas = - CalculateNonDraggableRegions(regions, webViewWidth, webViewHeight); - - if (browser_view_) { - browser_view_->UpdateDraggableRegions(system_drag_exclude_areas); - } - - // Create and add a ControlRegionView for each region that needs to be - // excluded from the dragging. - for (std::vector::const_iterator iter = - system_drag_exclude_areas.begin(); - iter != system_drag_exclude_areas.end(); - ++iter) { - base::scoped_nsobject controlRegion( - [[ControlRegionView alloc] initWithFrame:NSZeroRect]); - [controlRegion setFrame:NSMakeRect(iter->x(), - webViewHeight - iter->bottom(), - iter->width(), - iter->height())]; - [webView addSubview:controlRegion]; - } - - // AppKit will not update its cache of mouseDownCanMoveWindow unless something - // changes. Previously we tried adding an NSView and removing it, but for some - // reason it required reposting the mouse-down event, and didn't always work. - // Calling the below seems to be an effective solution. - [window_ setMovableByWindowBackground:NO]; - [window_ setMovableByWindowBackground:YES]; -} - void NativeWindowMac::SetStyleMask(bool on, NSUInteger flag) { // Changing the styleMask of a frameless windows causes it to change size so // we explicitly disable resizing while setting it. @@ -2027,18 +1994,6 @@ void NativeWindowMac::SetCollectionBehavior(bool on, NSUInteger flag) { SetMaximizable(was_maximizable); } -void NativeWindowMac::RegisterInputEventObserver( - content::RenderViewHost* host) { - if (host) - host->GetWidget()->AddInputEventObserver(this); -} - -void NativeWindowMac::UnregisterInputEventObserver( - content::RenderViewHost* host) { - if (host) - host->GetWidget()->RemoveInputEventObserver(this); -} - // static NativeWindow* NativeWindow::Create( brightray::InspectableWebContents* inspectable_web_contents, diff --git a/atom/browser/native_window_observer.h b/atom/browser/native_window_observer.h index 9aad030aa324..27f5cb92f8a3 100644 --- a/atom/browser/native_window_observer.h +++ b/atom/browser/native_window_observer.h @@ -34,8 +34,8 @@ class NativeWindowObserver { // Called when the window is gonna closed. virtual void WillCloseWindow(bool* prevent_default) {} - // Called before the native window object is going to be destroyed. - virtual void WillDestroyNativeObject() {} + // Called when closed button is clicked. + virtual void OnCloseButtonClicked(bool* prevent_default) {} // Called when the window is closed. virtual void OnWindowClosed() {} @@ -55,9 +55,6 @@ class NativeWindowObserver { // Called when window is hidden. virtual void OnWindowHide() {} - // Called when window is ready to show. - virtual void OnReadyToShow() {} - // Called when window state changed. virtual void OnWindowMaximize() {} virtual void OnWindowUnmaximize() {} @@ -68,7 +65,6 @@ class NativeWindowObserver { virtual void OnWindowMoved() {} virtual void OnWindowScrollTouchBegin() {} virtual void OnWindowScrollTouchEnd() {} - virtual void OnWindowScrollTouchEdge() {} virtual void OnWindowSwipe(const std::string& direction) {} virtual void OnWindowSheetBegin() {} virtual void OnWindowSheetEnd() {} @@ -85,12 +81,6 @@ class NativeWindowObserver { virtual void OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) {} #endif - // Called when renderer is hung. - virtual void OnRendererUnresponsive() {} - - // Called when renderer recovers. - virtual void OnRendererResponsive() {} - // Called on Windows when App Commands arrive (WM_APPCOMMAND) virtual void OnExecuteWindowsCommand(const std::string& command_name) {} }; diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 008109970ec8..895f1b07f79a 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -124,7 +124,8 @@ class NativeWindowClientView : public views::ClientView { virtual ~NativeWindowClientView() {} bool CanClose() override { - static_cast(contents_view())->RequestToClosePage(); + static_cast(contents_view())-> + NotifyWindowCloseButtonClicked(); return false; } @@ -1072,6 +1073,63 @@ gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() const { return GetNativeWindow()->GetHost()->GetAcceleratedWidget(); } +gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds( + const gfx::Rect& bounds) const { + if (!has_frame()) + return bounds; + + gfx::Rect window_bounds(bounds); +#if defined(OS_WIN) + HWND hwnd = GetAcceleratedWidget(); + gfx::Rect dpi_bounds = display::win::ScreenWin::DIPToScreenRect(hwnd, bounds); + window_bounds = display::win::ScreenWin::ScreenToDIPRect( + hwnd, + window_->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds)); +#endif + + if (menu_bar_ && menu_bar_visible_) { + window_bounds.set_y(window_bounds.y() - kMenuBarHeight); + window_bounds.set_height(window_bounds.height() + kMenuBarHeight); + } + return window_bounds; +} + +gfx::Rect NativeWindowViews::WindowBoundsToContentBounds( + const gfx::Rect& bounds) const { + if (!has_frame()) + return bounds; + + gfx::Rect content_bounds(bounds); +#if defined(OS_WIN) + HWND hwnd = GetAcceleratedWidget(); + content_bounds.set_size( + display::win::ScreenWin::DIPToScreenSize(hwnd, content_bounds.size())); + RECT rect; + SetRectEmpty(&rect); + DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); + DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE); + AdjustWindowRectEx(&rect, style, FALSE, ex_style); + content_bounds.set_width(content_bounds.width() - (rect.right - rect.left)); + content_bounds.set_height(content_bounds.height() - (rect.bottom - rect.top)); + content_bounds.set_size( + display::win::ScreenWin::ScreenToDIPSize(hwnd, content_bounds.size())); +#endif + + if (menu_bar_ && menu_bar_visible_) { + content_bounds.set_y(content_bounds.y() + kMenuBarHeight); + content_bounds.set_height(content_bounds.height() - kMenuBarHeight); + } + return content_bounds; +} + +void NativeWindowViews::UpdateDraggableRegions( + const std::vector& regions) { + // Draggable region is not supported for non-frameless window. + if (has_frame()) + return; + draggable_region_ = DraggableRegionsToSkRegion(regions); +} + #if defined(OS_WIN) void NativeWindowViews::SetIcon(HICON window_icon, HICON app_icon) { // We are responsible for storing the images. @@ -1270,55 +1328,6 @@ void NativeWindowViews::OnWidgetMove() { NotifyWindowMove(); } -gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds( - const gfx::Rect& bounds) const { - if (!has_frame()) - return bounds; - - gfx::Rect window_bounds(bounds); -#if defined(OS_WIN) - HWND hwnd = GetAcceleratedWidget(); - gfx::Rect dpi_bounds = display::win::ScreenWin::DIPToScreenRect(hwnd, bounds); - window_bounds = display::win::ScreenWin::ScreenToDIPRect( - hwnd, - window_->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds)); -#endif - - if (menu_bar_ && menu_bar_visible_) { - window_bounds.set_y(window_bounds.y() - kMenuBarHeight); - window_bounds.set_height(window_bounds.height() + kMenuBarHeight); - } - return window_bounds; -} - -gfx::Rect NativeWindowViews::WindowBoundsToContentBounds( - const gfx::Rect& bounds) const { - if (!has_frame()) - return bounds; - - gfx::Rect content_bounds(bounds); -#if defined(OS_WIN) - HWND hwnd = GetAcceleratedWidget(); - content_bounds.set_size( - display::win::ScreenWin::DIPToScreenSize(hwnd, content_bounds.size())); - RECT rect; - SetRectEmpty(&rect); - DWORD style = ::GetWindowLong(hwnd, GWL_STYLE); - DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE); - AdjustWindowRectEx(&rect, style, FALSE, ex_style); - content_bounds.set_width(content_bounds.width() - (rect.right - rect.left)); - content_bounds.set_height(content_bounds.height() - (rect.bottom - rect.top)); - content_bounds.set_size( - display::win::ScreenWin::ScreenToDIPSize(hwnd, content_bounds.size())); -#endif - - if (menu_bar_ && menu_bar_visible_) { - content_bounds.set_y(content_bounds.y() + kMenuBarHeight); - content_bounds.set_height(content_bounds.height() - kMenuBarHeight); - } - return content_bounds; -} - void NativeWindowViews::HandleKeyboardEvent( content::WebContents*, const content::NativeWebKeyboardEvent& event) { diff --git a/atom/browser/native_window_views.h b/atom/browser/native_window_views.h index 2d24b50deffb..73e91a92277a 100644 --- a/atom/browser/native_window_views.h +++ b/atom/browser/native_window_views.h @@ -126,6 +126,11 @@ class NativeWindowViews : public NativeWindow, gfx::AcceleratedWidget GetAcceleratedWidget() const override; + gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const override; + gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override; + void UpdateDraggableRegions( + const std::vector& regions) override; + #if defined(OS_WIN) void SetIcon(HICON small_icon, HICON app_icon); #elif defined(USE_X11) @@ -135,6 +140,7 @@ class NativeWindowViews : public NativeWindow, void SetEnabled(bool enable) override; views::Widget* widget() const { return window_.get(); } + SkRegion* draggable_region() const { return draggable_region_.get(); } #if defined(OS_WIN) TaskbarHost& taskbar_host() { return taskbar_host_; } @@ -183,8 +189,6 @@ class NativeWindowViews : public NativeWindow, #endif // NativeWindow: - gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const override; - gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override; void HandleKeyboardEvent( content::WebContents*, const content::NativeWebKeyboardEvent& event) override; @@ -289,6 +293,10 @@ class NativeWindowViews : public NativeWindow, // Map from accelerator to menu item's command id. accelerator_util::AcceleratorTable accelerator_table_; + // For custom drag, the whole window is non-draggable and the draggable region + // has to been explicitly provided. + std::unique_ptr draggable_region_; // used in custom drag. + // How many times the Disable has been called. int disable_count_; diff --git a/atom/browser/window_list.cc b/atom/browser/window_list.cc index 2ab0b24cf50b..baef11f65611 100644 --- a/atom/browser/window_list.cc +++ b/atom/browser/window_list.cc @@ -93,7 +93,7 @@ void WindowList::CloseAllWindows() { void WindowList::DestroyAllWindows() { WindowVector windows = GetInstance()->windows_; for (const auto& window : windows) - window->CloseContents(nullptr); // e.g. Destroy() + window->CloseImmediately(); // e.g. Destroy() } WindowList::WindowList() {