Merge pull request #6140 from electron/parent
Add support for child windows
This commit is contained in:
commit
3428874907
16 changed files with 532 additions and 28 deletions
|
@ -95,9 +95,16 @@ Window::Window(v8::Isolate* isolate, const mate::Dictionary& options) {
|
||||||
mate::Dictionary(isolate, web_contents->GetWrapper()).Set(
|
mate::Dictionary(isolate, web_contents->GetWrapper()).Set(
|
||||||
"browserWindowOptions", options);
|
"browserWindowOptions", options);
|
||||||
|
|
||||||
|
// The parent window.
|
||||||
|
mate::Handle<Window> parent;
|
||||||
|
if (options.Get("parent", &parent))
|
||||||
|
parent_window_.Reset(isolate, parent.ToV8());
|
||||||
|
|
||||||
// Creates BrowserWindow.
|
// Creates BrowserWindow.
|
||||||
window_.reset(NativeWindow::Create(web_contents->managed_web_contents(),
|
window_.reset(NativeWindow::Create(
|
||||||
options));
|
web_contents->managed_web_contents(),
|
||||||
|
options,
|
||||||
|
parent.IsEmpty() ? nullptr : parent->window_.get()));
|
||||||
web_contents->SetOwnerWindow(window_.get());
|
web_contents->SetOwnerWindow(window_.get());
|
||||||
window_->InitFromOptions(options);
|
window_->InitFromOptions(options);
|
||||||
window_->AddObserver(this);
|
window_->AddObserver(this);
|
||||||
|
@ -120,10 +127,32 @@ Window::~Window() {
|
||||||
base::MessageLoop::current()->DeleteSoon(FROM_HERE, window_.release());
|
base::MessageLoop::current()->DeleteSoon(FROM_HERE, window_.release());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::AfterInit(v8::Isolate* isolate) {
|
||||||
|
mate::TrackableObject<Window>::AfterInit(isolate);
|
||||||
|
|
||||||
|
// We can only append this window to parent window's child windows after this
|
||||||
|
// window's JS wrapper gets initialized.
|
||||||
|
mate::Handle<Window> parent;
|
||||||
|
if (!parent_window_.IsEmpty() &&
|
||||||
|
mate::ConvertFromV8(isolate, GetParentWindow(), &parent))
|
||||||
|
parent->child_windows_.Set(isolate, ID(), GetWrapper());
|
||||||
|
}
|
||||||
|
|
||||||
void Window::WillCloseWindow(bool* prevent_default) {
|
void Window::WillCloseWindow(bool* prevent_default) {
|
||||||
*prevent_default = Emit("close");
|
*prevent_default = Emit("close");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::WillDestoryNativeObject() {
|
||||||
|
// Close all child windows before closing current window.
|
||||||
|
v8::Locker locker(isolate());
|
||||||
|
v8::HandleScope handle_scope(isolate());
|
||||||
|
for (v8::Local<v8::Value> value : child_windows_.Values(isolate())) {
|
||||||
|
mate::Handle<Window> child;
|
||||||
|
if (mate::ConvertFromV8(isolate(), value, &child))
|
||||||
|
child->window_->CloseImmediately();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Window::OnWindowClosed() {
|
void Window::OnWindowClosed() {
|
||||||
api_web_contents_->DestroyWebContents();
|
api_web_contents_->DestroyWebContents();
|
||||||
|
|
||||||
|
@ -136,6 +165,8 @@ void Window::OnWindowClosed() {
|
||||||
|
|
||||||
Emit("closed");
|
Emit("closed");
|
||||||
|
|
||||||
|
RemoveFromParentChildWindows();
|
||||||
|
|
||||||
// Destroy the native class when window is closed.
|
// Destroy the native class when window is closed.
|
||||||
base::MessageLoop::current()->PostTask(FROM_HERE, GetDestroyClosure());
|
base::MessageLoop::current()->PostTask(FROM_HERE, GetDestroyClosure());
|
||||||
}
|
}
|
||||||
|
@ -280,6 +311,10 @@ void Window::Show() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::ShowInactive() {
|
void Window::ShowInactive() {
|
||||||
|
// This method doesn't make sense for modal window..
|
||||||
|
if (IsModal())
|
||||||
|
return;
|
||||||
|
|
||||||
window_->ShowInactive();
|
window_->ShowInactive();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,6 +326,10 @@ bool Window::IsVisible() {
|
||||||
return window_->IsVisible();
|
return window_->IsVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Window::IsEnabled() {
|
||||||
|
return window_->IsEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
void Window::Maximize() {
|
void Window::Maximize() {
|
||||||
window_->Maximize();
|
window_->Maximize();
|
||||||
}
|
}
|
||||||
|
@ -650,6 +689,42 @@ void Window::SetAspectRatio(double aspect_ratio, mate::Arguments* args) {
|
||||||
window_->SetAspectRatio(aspect_ratio, extra_size);
|
window_->SetAspectRatio(aspect_ratio, extra_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::SetParentWindow(v8::Local<v8::Value> value,
|
||||||
|
mate::Arguments* args) {
|
||||||
|
if (IsModal()) {
|
||||||
|
args->ThrowError("Can not be called for modal window");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
mate::Handle<Window> parent;
|
||||||
|
if (value->IsNull()) {
|
||||||
|
RemoveFromParentChildWindows();
|
||||||
|
parent_window_.Reset();
|
||||||
|
window_->SetParentWindow(nullptr);
|
||||||
|
} else if (mate::ConvertFromV8(isolate(), value, &parent)) {
|
||||||
|
parent_window_.Reset(isolate(), value);
|
||||||
|
window_->SetParentWindow(parent->window_.get());
|
||||||
|
parent->child_windows_.Set(isolate(), ID(), GetWrapper());
|
||||||
|
} else {
|
||||||
|
args->ThrowError("Must pass BrowserWindow instance or null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v8::Local<v8::Value> Window::GetParentWindow() const {
|
||||||
|
if (parent_window_.IsEmpty())
|
||||||
|
return v8::Null(isolate());
|
||||||
|
else
|
||||||
|
return v8::Local<v8::Value>::New(isolate(), parent_window_);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<v8::Local<v8::Object>> Window::GetChildWindows() const {
|
||||||
|
return child_windows_.Values(isolate());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Window::IsModal() const {
|
||||||
|
return window_->is_modal();
|
||||||
|
}
|
||||||
|
|
||||||
v8::Local<v8::Value> Window::GetNativeWindowHandle() {
|
v8::Local<v8::Value> Window::GetNativeWindowHandle() {
|
||||||
gfx::AcceleratedWidget handle = window_->GetAcceleratedWidget();
|
gfx::AcceleratedWidget handle = window_->GetAcceleratedWidget();
|
||||||
return ToBuffer(
|
return ToBuffer(
|
||||||
|
@ -675,6 +750,17 @@ v8::Local<v8::Value> Window::WebContents(v8::Isolate* isolate) {
|
||||||
return v8::Local<v8::Value>::New(isolate, web_contents_);
|
return v8::Local<v8::Value>::New(isolate, web_contents_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::RemoveFromParentChildWindows() {
|
||||||
|
if (parent_window_.IsEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
mate::Handle<Window> parent;
|
||||||
|
if (!mate::ConvertFromV8(isolate(), GetParentWindow(), &parent))
|
||||||
|
return;
|
||||||
|
|
||||||
|
parent->child_windows_.Remove(ID());
|
||||||
|
}
|
||||||
|
|
||||||
// static
|
// static
|
||||||
void Window::BuildPrototype(v8::Isolate* isolate,
|
void Window::BuildPrototype(v8::Isolate* isolate,
|
||||||
v8::Local<v8::ObjectTemplate> prototype) {
|
v8::Local<v8::ObjectTemplate> prototype) {
|
||||||
|
@ -688,6 +774,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("showInactive", &Window::ShowInactive)
|
.SetMethod("showInactive", &Window::ShowInactive)
|
||||||
.SetMethod("hide", &Window::Hide)
|
.SetMethod("hide", &Window::Hide)
|
||||||
.SetMethod("isVisible", &Window::IsVisible)
|
.SetMethod("isVisible", &Window::IsVisible)
|
||||||
|
.SetMethod("isEnabled", &Window::IsEnabled)
|
||||||
.SetMethod("maximize", &Window::Maximize)
|
.SetMethod("maximize", &Window::Maximize)
|
||||||
.SetMethod("unmaximize", &Window::Unmaximize)
|
.SetMethod("unmaximize", &Window::Unmaximize)
|
||||||
.SetMethod("isMaximized", &Window::IsMaximized)
|
.SetMethod("isMaximized", &Window::IsMaximized)
|
||||||
|
@ -697,6 +784,12 @@ void Window::BuildPrototype(v8::Isolate* isolate,
|
||||||
.SetMethod("setFullScreen", &Window::SetFullScreen)
|
.SetMethod("setFullScreen", &Window::SetFullScreen)
|
||||||
.SetMethod("isFullScreen", &Window::IsFullscreen)
|
.SetMethod("isFullScreen", &Window::IsFullscreen)
|
||||||
.SetMethod("setAspectRatio", &Window::SetAspectRatio)
|
.SetMethod("setAspectRatio", &Window::SetAspectRatio)
|
||||||
|
#if !defined(OS_WIN)
|
||||||
|
.SetMethod("setParentWindow", &Window::SetParentWindow)
|
||||||
|
#endif
|
||||||
|
.SetMethod("getParentWindow", &Window::GetParentWindow)
|
||||||
|
.SetMethod("getChildWindows", &Window::GetChildWindows)
|
||||||
|
.SetMethod("isModal", &Window::IsModal)
|
||||||
.SetMethod("getNativeWindowHandle", &Window::GetNativeWindowHandle)
|
.SetMethod("getNativeWindowHandle", &Window::GetNativeWindowHandle)
|
||||||
.SetMethod("getBounds", &Window::GetBounds)
|
.SetMethod("getBounds", &Window::GetBounds)
|
||||||
.SetMethod("setBounds", &Window::SetBounds)
|
.SetMethod("setBounds", &Window::SetBounds)
|
||||||
|
|
|
@ -6,15 +6,16 @@
|
||||||
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
|
#define ATOM_BROWSER_API_ATOM_API_WINDOW_H_
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "base/memory/scoped_ptr.h"
|
|
||||||
#include "ui/gfx/image/image.h"
|
#include "ui/gfx/image/image.h"
|
||||||
#include "atom/browser/api/trackable_object.h"
|
#include "atom/browser/api/trackable_object.h"
|
||||||
#include "atom/browser/native_window.h"
|
#include "atom/browser/native_window.h"
|
||||||
#include "atom/browser/native_window_observer.h"
|
#include "atom/browser/native_window_observer.h"
|
||||||
#include "atom/common/api/atom_api_native_image.h"
|
#include "atom/common/api/atom_api_native_image.h"
|
||||||
|
#include "atom/common/key_weak_map.h"
|
||||||
#include "native_mate/handle.h"
|
#include "native_mate/handle.h"
|
||||||
|
|
||||||
class GURL;
|
class GURL;
|
||||||
|
@ -54,8 +55,12 @@ class Window : public mate::TrackableObject<Window>,
|
||||||
Window(v8::Isolate* isolate, const mate::Dictionary& options);
|
Window(v8::Isolate* isolate, const mate::Dictionary& options);
|
||||||
~Window() override;
|
~Window() override;
|
||||||
|
|
||||||
|
// TrackableObject:
|
||||||
|
void AfterInit(v8::Isolate* isolate) override;
|
||||||
|
|
||||||
// NativeWindowObserver:
|
// NativeWindowObserver:
|
||||||
void WillCloseWindow(bool* prevent_default) override;
|
void WillCloseWindow(bool* prevent_default) override;
|
||||||
|
void WillDestoryNativeObject() override;
|
||||||
void OnWindowClosed() override;
|
void OnWindowClosed() override;
|
||||||
void OnWindowBlur() override;
|
void OnWindowBlur() override;
|
||||||
void OnWindowFocus() override;
|
void OnWindowFocus() override;
|
||||||
|
@ -94,6 +99,7 @@ class Window : public mate::TrackableObject<Window>,
|
||||||
void ShowInactive();
|
void ShowInactive();
|
||||||
void Hide();
|
void Hide();
|
||||||
bool IsVisible();
|
bool IsVisible();
|
||||||
|
bool IsEnabled();
|
||||||
void Maximize();
|
void Maximize();
|
||||||
void Unmaximize();
|
void Unmaximize();
|
||||||
bool IsMaximized();
|
bool IsMaximized();
|
||||||
|
@ -159,6 +165,10 @@ class Window : public mate::TrackableObject<Window>,
|
||||||
void SetMenuBarVisibility(bool visible);
|
void SetMenuBarVisibility(bool visible);
|
||||||
bool IsMenuBarVisible();
|
bool IsMenuBarVisible();
|
||||||
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
|
void SetAspectRatio(double aspect_ratio, mate::Arguments* args);
|
||||||
|
void SetParentWindow(v8::Local<v8::Value> value, mate::Arguments* args);
|
||||||
|
v8::Local<v8::Value> GetParentWindow() const;
|
||||||
|
std::vector<v8::Local<v8::Object>> GetChildWindows() const;
|
||||||
|
bool IsModal() const;
|
||||||
v8::Local<v8::Value> GetNativeWindowHandle();
|
v8::Local<v8::Value> GetNativeWindowHandle();
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
|
@ -181,6 +191,9 @@ class Window : public mate::TrackableObject<Window>,
|
||||||
int32_t ID() const;
|
int32_t ID() const;
|
||||||
v8::Local<v8::Value> WebContents(v8::Isolate* isolate);
|
v8::Local<v8::Value> WebContents(v8::Isolate* isolate);
|
||||||
|
|
||||||
|
// Remove this window from parent window's |child_windows_|.
|
||||||
|
void RemoveFromParentChildWindows();
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
typedef std::map<UINT, MessageCallback> MessageCallbackMap;
|
typedef std::map<UINT, MessageCallback> MessageCallbackMap;
|
||||||
MessageCallbackMap messages_callback_map_;
|
MessageCallbackMap messages_callback_map_;
|
||||||
|
@ -188,6 +201,8 @@ class Window : public mate::TrackableObject<Window>,
|
||||||
|
|
||||||
v8::Global<v8::Value> web_contents_;
|
v8::Global<v8::Value> web_contents_;
|
||||||
v8::Global<v8::Value> menu_;
|
v8::Global<v8::Value> menu_;
|
||||||
|
v8::Global<v8::Value> parent_window_;
|
||||||
|
KeyWeakMap<int> child_windows_;
|
||||||
|
|
||||||
api::WebContents* api_web_contents_;
|
api::WebContents* api_web_contents_;
|
||||||
|
|
||||||
|
|
|
@ -46,7 +46,8 @@ namespace atom {
|
||||||
|
|
||||||
NativeWindow::NativeWindow(
|
NativeWindow::NativeWindow(
|
||||||
brightray::InspectableWebContents* inspectable_web_contents,
|
brightray::InspectableWebContents* inspectable_web_contents,
|
||||||
const mate::Dictionary& options)
|
const mate::Dictionary& options,
|
||||||
|
NativeWindow* parent)
|
||||||
: content::WebContentsObserver(inspectable_web_contents->GetWebContents()),
|
: content::WebContentsObserver(inspectable_web_contents->GetWebContents()),
|
||||||
has_frame_(true),
|
has_frame_(true),
|
||||||
transparent_(false),
|
transparent_(false),
|
||||||
|
@ -56,12 +57,17 @@ NativeWindow::NativeWindow(
|
||||||
sheet_offset_x_(0.0),
|
sheet_offset_x_(0.0),
|
||||||
sheet_offset_y_(0.0),
|
sheet_offset_y_(0.0),
|
||||||
aspect_ratio_(0.0),
|
aspect_ratio_(0.0),
|
||||||
|
parent_(parent),
|
||||||
|
is_modal_(false),
|
||||||
inspectable_web_contents_(inspectable_web_contents),
|
inspectable_web_contents_(inspectable_web_contents),
|
||||||
weak_factory_(this) {
|
weak_factory_(this) {
|
||||||
options.Get(options::kFrame, &has_frame_);
|
options.Get(options::kFrame, &has_frame_);
|
||||||
options.Get(options::kTransparent, &transparent_);
|
options.Get(options::kTransparent, &transparent_);
|
||||||
options.Get(options::kEnableLargerThanScreen, &enable_larger_than_screen_);
|
options.Get(options::kEnableLargerThanScreen, &enable_larger_than_screen_);
|
||||||
|
|
||||||
|
if (parent)
|
||||||
|
options.Get("modal", &is_modal_);
|
||||||
|
|
||||||
// Tell the content module to initialize renderer widget with transparent
|
// Tell the content module to initialize renderer widget with transparent
|
||||||
// mode.
|
// mode.
|
||||||
ui::GpuSwitchingManager::SetTransparent(transparent_);
|
ui::GpuSwitchingManager::SetTransparent(transparent_);
|
||||||
|
@ -292,6 +298,10 @@ bool NativeWindow::HasModalDialog() {
|
||||||
return has_dialog_attached_;
|
return has_dialog_attached_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NativeWindow::SetParentWindow(NativeWindow* parent) {
|
||||||
|
parent_ = parent;
|
||||||
|
}
|
||||||
|
|
||||||
void NativeWindow::FocusOnWebView() {
|
void NativeWindow::FocusOnWebView() {
|
||||||
web_contents()->GetRenderViewHost()->GetWidget()->Focus();
|
web_contents()->GetRenderViewHost()->GetWidget()->Focus();
|
||||||
}
|
}
|
||||||
|
@ -397,6 +407,9 @@ void NativeWindow::CloseContents(content::WebContents* source) {
|
||||||
inspectable_web_contents_ = nullptr;
|
inspectable_web_contents_ = nullptr;
|
||||||
Observe(nullptr);
|
Observe(nullptr);
|
||||||
|
|
||||||
|
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
|
||||||
|
WillDestoryNativeObject());
|
||||||
|
|
||||||
// When the web contents is gone, close the window immediately, but the
|
// When the web contents is gone, close the window immediately, but the
|
||||||
// memory will not be freed until you call delete.
|
// memory will not be freed until you call delete.
|
||||||
// In this way, it would be safe to manage windows via smart pointers. If you
|
// In this way, it would be safe to manage windows via smart pointers. If you
|
||||||
|
@ -611,7 +624,7 @@ void NativeWindow::ScheduleUnresponsiveEvent(int ms) {
|
||||||
void NativeWindow::NotifyWindowUnresponsive() {
|
void NativeWindow::NotifyWindowUnresponsive() {
|
||||||
window_unresposive_closure_.Cancel();
|
window_unresposive_closure_.Cancel();
|
||||||
|
|
||||||
if (!is_closed_ && !HasModalDialog())
|
if (!is_closed_ && !HasModalDialog() && IsEnabled())
|
||||||
FOR_EACH_OBSERVER(NativeWindowObserver,
|
FOR_EACH_OBSERVER(NativeWindowObserver,
|
||||||
observers_,
|
observers_,
|
||||||
OnRendererUnresponsive());
|
OnRendererUnresponsive());
|
||||||
|
|
|
@ -81,7 +81,8 @@ class NativeWindow : public base::SupportsUserData,
|
||||||
// managing the window's live.
|
// managing the window's live.
|
||||||
static NativeWindow* Create(
|
static NativeWindow* Create(
|
||||||
brightray::InspectableWebContents* inspectable_web_contents,
|
brightray::InspectableWebContents* inspectable_web_contents,
|
||||||
const mate::Dictionary& options);
|
const mate::Dictionary& options,
|
||||||
|
NativeWindow* parent = nullptr);
|
||||||
|
|
||||||
// Find a window from its WebContents
|
// Find a window from its WebContents
|
||||||
static NativeWindow* FromWebContents(content::WebContents* web_contents);
|
static NativeWindow* FromWebContents(content::WebContents* web_contents);
|
||||||
|
@ -97,6 +98,7 @@ class NativeWindow : public base::SupportsUserData,
|
||||||
virtual void ShowInactive() = 0;
|
virtual void ShowInactive() = 0;
|
||||||
virtual void Hide() = 0;
|
virtual void Hide() = 0;
|
||||||
virtual bool IsVisible() = 0;
|
virtual bool IsVisible() = 0;
|
||||||
|
virtual bool IsEnabled() = 0;
|
||||||
virtual void Maximize() = 0;
|
virtual void Maximize() = 0;
|
||||||
virtual void Unmaximize() = 0;
|
virtual void Unmaximize() = 0;
|
||||||
virtual bool IsMaximized() = 0;
|
virtual bool IsMaximized() = 0;
|
||||||
|
@ -158,6 +160,7 @@ class NativeWindow : public base::SupportsUserData,
|
||||||
virtual void SetFocusable(bool focusable);
|
virtual void SetFocusable(bool focusable);
|
||||||
virtual void SetMenu(ui::MenuModel* menu);
|
virtual void SetMenu(ui::MenuModel* menu);
|
||||||
virtual bool HasModalDialog();
|
virtual bool HasModalDialog();
|
||||||
|
virtual void SetParentWindow(NativeWindow* parent);
|
||||||
virtual gfx::NativeWindow GetNativeWindow() = 0;
|
virtual gfx::NativeWindow GetNativeWindow() = 0;
|
||||||
virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0;
|
virtual gfx::AcceleratedWidget GetAcceleratedWidget() = 0;
|
||||||
|
|
||||||
|
@ -255,9 +258,13 @@ class NativeWindow : public base::SupportsUserData,
|
||||||
has_dialog_attached_ = has_dialog_attached;
|
has_dialog_attached_ = has_dialog_attached;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NativeWindow* parent() const { return parent_; }
|
||||||
|
bool is_modal() const { return is_modal_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
NativeWindow(brightray::InspectableWebContents* inspectable_web_contents,
|
NativeWindow(brightray::InspectableWebContents* inspectable_web_contents,
|
||||||
const mate::Dictionary& options);
|
const mate::Dictionary& options,
|
||||||
|
NativeWindow* parent);
|
||||||
|
|
||||||
// Convert draggable regions in raw format to SkRegion format. Caller is
|
// Convert draggable regions in raw format to SkRegion format. Caller is
|
||||||
// responsible for deleting the returned SkRegion instance.
|
// responsible for deleting the returned SkRegion instance.
|
||||||
|
@ -329,6 +336,12 @@ class NativeWindow : public base::SupportsUserData,
|
||||||
double aspect_ratio_;
|
double aspect_ratio_;
|
||||||
gfx::Size aspect_ratio_extraSize_;
|
gfx::Size aspect_ratio_extraSize_;
|
||||||
|
|
||||||
|
// The parent window, it is guaranteed to be valid during this window's life.
|
||||||
|
NativeWindow* parent_;
|
||||||
|
|
||||||
|
// Is this a modal window.
|
||||||
|
bool is_modal_;
|
||||||
|
|
||||||
// The page this window is viewing.
|
// The page this window is viewing.
|
||||||
brightray::InspectableWebContents* inspectable_web_contents_;
|
brightray::InspectableWebContents* inspectable_web_contents_;
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,8 @@ namespace atom {
|
||||||
class NativeWindowMac : public NativeWindow {
|
class NativeWindowMac : public NativeWindow {
|
||||||
public:
|
public:
|
||||||
NativeWindowMac(brightray::InspectableWebContents* inspectable_web_contents,
|
NativeWindowMac(brightray::InspectableWebContents* inspectable_web_contents,
|
||||||
const mate::Dictionary& options);
|
const mate::Dictionary& options,
|
||||||
|
NativeWindow* parent);
|
||||||
~NativeWindowMac() override;
|
~NativeWindowMac() override;
|
||||||
|
|
||||||
// NativeWindow:
|
// NativeWindow:
|
||||||
|
@ -34,6 +35,7 @@ class NativeWindowMac : public NativeWindow {
|
||||||
void ShowInactive() override;
|
void ShowInactive() override;
|
||||||
void Hide() override;
|
void Hide() override;
|
||||||
bool IsVisible() override;
|
bool IsVisible() override;
|
||||||
|
bool IsEnabled() override;
|
||||||
void Maximize() override;
|
void Maximize() override;
|
||||||
void Unmaximize() override;
|
void Unmaximize() override;
|
||||||
bool IsMaximized() override;
|
bool IsMaximized() override;
|
||||||
|
@ -78,6 +80,7 @@ class NativeWindowMac : public NativeWindow {
|
||||||
bool IsDocumentEdited() override;
|
bool IsDocumentEdited() override;
|
||||||
void SetIgnoreMouseEvents(bool ignore) override;
|
void SetIgnoreMouseEvents(bool ignore) override;
|
||||||
bool HasModalDialog() override;
|
bool HasModalDialog() override;
|
||||||
|
void SetParentWindow(NativeWindow* parent) override;
|
||||||
gfx::NativeWindow GetNativeWindow() override;
|
gfx::NativeWindow GetNativeWindow() override;
|
||||||
gfx::AcceleratedWidget GetAcceleratedWidget() override;
|
gfx::AcceleratedWidget GetAcceleratedWidget() override;
|
||||||
void SetProgressBar(double progress) override;
|
void SetProgressBar(double progress) override;
|
||||||
|
@ -144,9 +147,6 @@ class NativeWindowMac : public NativeWindow {
|
||||||
// The "titleBarStyle" option.
|
// The "titleBarStyle" option.
|
||||||
TitleBarStyle title_bar_style_;
|
TitleBarStyle title_bar_style_;
|
||||||
|
|
||||||
// Whether to hide the native toolbar under fullscreen mode.
|
|
||||||
bool should_hide_native_toolbar_in_fullscreen_;
|
|
||||||
|
|
||||||
DISALLOW_COPY_AND_ASSIGN(NativeWindowMac);
|
DISALLOW_COPY_AND_ASSIGN(NativeWindowMac);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -429,8 +429,9 @@ namespace atom {
|
||||||
|
|
||||||
NativeWindowMac::NativeWindowMac(
|
NativeWindowMac::NativeWindowMac(
|
||||||
brightray::InspectableWebContents* web_contents,
|
brightray::InspectableWebContents* web_contents,
|
||||||
const mate::Dictionary& options)
|
const mate::Dictionary& options,
|
||||||
: NativeWindow(web_contents, options),
|
NativeWindow* parent)
|
||||||
|
: NativeWindow(web_contents, options, parent),
|
||||||
is_kiosk_(false),
|
is_kiosk_(false),
|
||||||
attention_request_id_(0),
|
attention_request_id_(0),
|
||||||
title_bar_style_(NORMAL) {
|
title_bar_style_(NORMAL) {
|
||||||
|
@ -501,6 +502,11 @@ NativeWindowMac::NativeWindowMac(
|
||||||
window_delegate_.reset([[AtomNSWindowDelegate alloc] initWithShell:this]);
|
window_delegate_.reset([[AtomNSWindowDelegate alloc] initWithShell:this]);
|
||||||
[window_ setDelegate:window_delegate_];
|
[window_ setDelegate:window_delegate_];
|
||||||
|
|
||||||
|
// Only use native parent window for non-modal windows.
|
||||||
|
if (parent && !is_modal()) {
|
||||||
|
SetParentWindow(parent);
|
||||||
|
}
|
||||||
|
|
||||||
if (transparent()) {
|
if (transparent()) {
|
||||||
// Setting the background color to clear will also hide the shadow.
|
// Setting the background color to clear will also hide the shadow.
|
||||||
[window_ setBackgroundColor:[NSColor clearColor]];
|
[window_ setBackgroundColor:[NSColor clearColor]];
|
||||||
|
@ -595,6 +601,12 @@ NativeWindowMac::~NativeWindowMac() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeWindowMac::Close() {
|
void NativeWindowMac::Close() {
|
||||||
|
// When this is a sheet showing, performClose won't work.
|
||||||
|
if (is_modal() && parent() && IsVisible()) {
|
||||||
|
CloseImmediately();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (!IsClosable()) {
|
if (!IsClosable()) {
|
||||||
WindowList::WindowCloseCancelled(this);
|
WindowList::WindowCloseCancelled(this);
|
||||||
return;
|
return;
|
||||||
|
@ -624,6 +636,12 @@ bool NativeWindowMac::IsFocused() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeWindowMac::Show() {
|
void NativeWindowMac::Show() {
|
||||||
|
if (is_modal() && parent()) {
|
||||||
|
[parent()->GetNativeWindow() beginSheet:window_
|
||||||
|
completionHandler:^(NSModalResponse) {}];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// This method is supposed to put focus on window, however if the app does not
|
// This method is supposed to put focus on window, however if the app does not
|
||||||
// have focus then "makeKeyAndOrderFront" will only show the window.
|
// have focus then "makeKeyAndOrderFront" will only show the window.
|
||||||
[NSApp activateIgnoringOtherApps:YES];
|
[NSApp activateIgnoringOtherApps:YES];
|
||||||
|
@ -636,6 +654,12 @@ void NativeWindowMac::ShowInactive() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeWindowMac::Hide() {
|
void NativeWindowMac::Hide() {
|
||||||
|
if (is_modal() && parent()) {
|
||||||
|
[window_ orderOut:nil];
|
||||||
|
[parent()->GetNativeWindow() endSheet:window_];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
[window_ orderOut:nil];
|
[window_ orderOut:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -643,6 +667,10 @@ bool NativeWindowMac::IsVisible() {
|
||||||
return [window_ isVisible];
|
return [window_ isVisible];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NativeWindowMac::IsEnabled() {
|
||||||
|
return [window_ attachedSheet] == nil;
|
||||||
|
}
|
||||||
|
|
||||||
void NativeWindowMac::Maximize() {
|
void NativeWindowMac::Maximize() {
|
||||||
if (IsMaximized())
|
if (IsMaximized())
|
||||||
return;
|
return;
|
||||||
|
@ -911,6 +939,21 @@ bool NativeWindowMac::HasModalDialog() {
|
||||||
return [window_ attachedSheet] != nil;
|
return [window_ attachedSheet] != nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NativeWindowMac::SetParentWindow(NativeWindow* parent) {
|
||||||
|
if (is_modal())
|
||||||
|
return;
|
||||||
|
|
||||||
|
NativeWindow::SetParentWindow(parent);
|
||||||
|
|
||||||
|
// Remove current parent window.
|
||||||
|
if ([window_ parentWindow])
|
||||||
|
[[window_ parentWindow] removeChildWindow:window_];
|
||||||
|
|
||||||
|
// Set new current window.
|
||||||
|
if (parent)
|
||||||
|
[parent->GetNativeWindow() addChildWindow:window_ ordered:NSWindowAbove];
|
||||||
|
}
|
||||||
|
|
||||||
gfx::NativeWindow NativeWindowMac::GetNativeWindow() {
|
gfx::NativeWindow NativeWindowMac::GetNativeWindow() {
|
||||||
return window_;
|
return window_;
|
||||||
}
|
}
|
||||||
|
@ -1132,8 +1175,9 @@ void NativeWindowMac::SetCollectionBehavior(bool on, NSUInteger flag) {
|
||||||
// static
|
// static
|
||||||
NativeWindow* NativeWindow::Create(
|
NativeWindow* NativeWindow::Create(
|
||||||
brightray::InspectableWebContents* inspectable_web_contents,
|
brightray::InspectableWebContents* inspectable_web_contents,
|
||||||
const mate::Dictionary& options) {
|
const mate::Dictionary& options,
|
||||||
return new NativeWindowMac(inspectable_web_contents, options);
|
NativeWindow* parent) {
|
||||||
|
return new NativeWindowMac(inspectable_web_contents, options, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace atom
|
} // namespace atom
|
||||||
|
|
|
@ -33,6 +33,9 @@ class NativeWindowObserver {
|
||||||
// Called when the window is gonna closed.
|
// Called when the window is gonna closed.
|
||||||
virtual void WillCloseWindow(bool* prevent_default) {}
|
virtual void WillCloseWindow(bool* prevent_default) {}
|
||||||
|
|
||||||
|
// Called before the native window object is going to be destroyed.
|
||||||
|
virtual void WillDestoryNativeObject() {}
|
||||||
|
|
||||||
// Called when the window is closed.
|
// Called when the window is closed.
|
||||||
virtual void OnWindowClosed() {}
|
virtual void OnWindowClosed() {}
|
||||||
|
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "ui/views/window/client_view.h"
|
#include "ui/views/window/client_view.h"
|
||||||
#include "ui/views/widget/native_widget_private.h"
|
#include "ui/views/widget/native_widget_private.h"
|
||||||
#include "ui/views/widget/widget.h"
|
#include "ui/views/widget/widget.h"
|
||||||
|
#include "ui/wm/core/window_util.h"
|
||||||
#include "ui/wm/core/shadow_types.h"
|
#include "ui/wm/core/shadow_types.h"
|
||||||
|
|
||||||
#if defined(USE_X11)
|
#if defined(USE_X11)
|
||||||
|
@ -36,6 +37,7 @@
|
||||||
#include "atom/browser/ui/views/global_menu_bar_x11.h"
|
#include "atom/browser/ui/views/global_menu_bar_x11.h"
|
||||||
#include "atom/browser/ui/views/frameless_view.h"
|
#include "atom/browser/ui/views/frameless_view.h"
|
||||||
#include "atom/browser/ui/views/native_frame_view.h"
|
#include "atom/browser/ui/views/native_frame_view.h"
|
||||||
|
#include "atom/browser/ui/x/event_disabler.h"
|
||||||
#include "atom/browser/ui/x/window_state_watcher.h"
|
#include "atom/browser/ui/x/window_state_watcher.h"
|
||||||
#include "atom/browser/ui/x/x_window_utils.h"
|
#include "atom/browser/ui/x/x_window_utils.h"
|
||||||
#include "base/strings/string_util.h"
|
#include "base/strings/string_util.h"
|
||||||
|
@ -125,14 +127,16 @@ class NativeWindowClientView : public views::ClientView {
|
||||||
|
|
||||||
NativeWindowViews::NativeWindowViews(
|
NativeWindowViews::NativeWindowViews(
|
||||||
brightray::InspectableWebContents* web_contents,
|
brightray::InspectableWebContents* web_contents,
|
||||||
const mate::Dictionary& options)
|
const mate::Dictionary& options,
|
||||||
: NativeWindow(web_contents, options),
|
NativeWindow* parent)
|
||||||
|
: NativeWindow(web_contents, options, parent),
|
||||||
window_(new views::Widget),
|
window_(new views::Widget),
|
||||||
web_view_(inspectable_web_contents()->GetView()->GetView()),
|
web_view_(inspectable_web_contents()->GetView()->GetView()),
|
||||||
menu_bar_autohide_(false),
|
menu_bar_autohide_(false),
|
||||||
menu_bar_visible_(false),
|
menu_bar_visible_(false),
|
||||||
menu_bar_alt_pressed_(false),
|
menu_bar_alt_pressed_(false),
|
||||||
keyboard_event_handler_(new views::UnhandledKeyboardEventHandler),
|
keyboard_event_handler_(new views::UnhandledKeyboardEventHandler),
|
||||||
|
disable_count_(0),
|
||||||
use_content_size_(false),
|
use_content_size_(false),
|
||||||
movable_(true),
|
movable_(true),
|
||||||
resizable_(true),
|
resizable_(true),
|
||||||
|
@ -186,6 +190,9 @@ NativeWindowViews::NativeWindowViews(
|
||||||
params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
|
params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
|
if (parent)
|
||||||
|
params.parent = parent->GetNativeWindow();
|
||||||
|
|
||||||
params.native_widget =
|
params.native_widget =
|
||||||
new views::DesktopNativeWidgetAura(window_.get());
|
new views::DesktopNativeWidgetAura(window_.get());
|
||||||
atom_desktop_window_tree_host_win_ = new AtomDesktopWindowTreeHostWin(
|
atom_desktop_window_tree_host_win_ = new AtomDesktopWindowTreeHostWin(
|
||||||
|
@ -236,12 +243,23 @@ NativeWindowViews::NativeWindowViews(
|
||||||
state_atom_list.push_back(GetAtom("_NET_WM_STATE_FULLSCREEN"));
|
state_atom_list.push_back(GetAtom("_NET_WM_STATE_FULLSCREEN"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string window_type;
|
||||||
|
options.Get(options::kType, &window_type);
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
SetParentWindow(parent);
|
||||||
|
// Force using dialog type for child window.
|
||||||
|
window_type = "dialog";
|
||||||
|
// Modal window needs the _NET_WM_STATE_MODAL hint.
|
||||||
|
if (is_modal())
|
||||||
|
state_atom_list.push_back(GetAtom("_NET_WM_STATE_MODAL"));
|
||||||
|
}
|
||||||
|
|
||||||
ui::SetAtomArrayProperty(GetAcceleratedWidget(), "_NET_WM_STATE", "ATOM",
|
ui::SetAtomArrayProperty(GetAcceleratedWidget(), "_NET_WM_STATE", "ATOM",
|
||||||
state_atom_list);
|
state_atom_list);
|
||||||
|
|
||||||
// Set the _NET_WM_WINDOW_TYPE.
|
// Set the _NET_WM_WINDOW_TYPE.
|
||||||
std::string window_type;
|
if (!window_type.empty())
|
||||||
if (options.Get(options::kType, &window_type))
|
|
||||||
SetWindowType(GetAcceleratedWidget(), window_type);
|
SetWindowType(GetAcceleratedWidget(), window_type);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -337,6 +355,9 @@ bool NativeWindowViews::IsFocused() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeWindowViews::Show() {
|
void NativeWindowViews::Show() {
|
||||||
|
if (is_modal() && NativeWindow::parent())
|
||||||
|
static_cast<NativeWindowViews*>(NativeWindow::parent())->SetEnabled(false);
|
||||||
|
|
||||||
window_->native_widget_private()->ShowWithWindowState(GetRestoredState());
|
window_->native_widget_private()->ShowWithWindowState(GetRestoredState());
|
||||||
|
|
||||||
NotifyWindowShow();
|
NotifyWindowShow();
|
||||||
|
@ -359,6 +380,9 @@ void NativeWindowViews::ShowInactive() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeWindowViews::Hide() {
|
void NativeWindowViews::Hide() {
|
||||||
|
if (is_modal() && NativeWindow::parent())
|
||||||
|
static_cast<NativeWindowViews*>(NativeWindow::parent())->SetEnabled(true);
|
||||||
|
|
||||||
window_->Hide();
|
window_->Hide();
|
||||||
|
|
||||||
NotifyWindowHide();
|
NotifyWindowHide();
|
||||||
|
@ -373,6 +397,14 @@ bool NativeWindowViews::IsVisible() {
|
||||||
return window_->IsVisible();
|
return window_->IsVisible();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool NativeWindowViews::IsEnabled() {
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
return ::IsWindowEnabled(GetAcceleratedWidget());
|
||||||
|
#elif defined(USE_X11)
|
||||||
|
return !event_disabler_.get();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void NativeWindowViews::Maximize() {
|
void NativeWindowViews::Maximize() {
|
||||||
if (IsVisible())
|
if (IsVisible())
|
||||||
window_->Maximize();
|
window_->Maximize();
|
||||||
|
@ -772,6 +804,32 @@ void NativeWindowViews::SetMenu(ui::MenuModel* menu_model) {
|
||||||
Layout();
|
Layout();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
|
||||||
|
NativeWindow::SetParentWindow(parent);
|
||||||
|
|
||||||
|
#if defined(USE_X11)
|
||||||
|
XDisplay* xdisplay = gfx::GetXDisplay();
|
||||||
|
XSetTransientForHint(
|
||||||
|
xdisplay, GetAcceleratedWidget(),
|
||||||
|
parent? parent->GetAcceleratedWidget() : DefaultRootWindow(xdisplay));
|
||||||
|
#elif defined(OS_WIN) && defined(DEBUG)
|
||||||
|
// Should work, but does not, it seems that the views toolkit doesn't support
|
||||||
|
// reparenting on desktop.
|
||||||
|
if (parent) {
|
||||||
|
::SetParent(GetAcceleratedWidget(), parent->GetAcceleratedWidget());
|
||||||
|
views::Widget::ReparentNativeView(GetNativeWindow(),
|
||||||
|
parent->GetNativeWindow());
|
||||||
|
wm::AddTransientChild(parent->GetNativeWindow(), GetNativeWindow());
|
||||||
|
} else {
|
||||||
|
if (!GetNativeWindow()->parent())
|
||||||
|
return;
|
||||||
|
::SetParent(GetAcceleratedWidget(), NULL);
|
||||||
|
views::Widget::ReparentNativeView(GetNativeWindow(), nullptr);
|
||||||
|
wm::RemoveTransientChild(GetNativeWindow()->parent(), GetNativeWindow());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
gfx::NativeWindow NativeWindowViews::GetNativeWindow() {
|
gfx::NativeWindow NativeWindowViews::GetNativeWindow() {
|
||||||
return window_->GetNativeWindow();
|
return window_->GetNativeWindow();
|
||||||
}
|
}
|
||||||
|
@ -867,6 +925,33 @@ void NativeWindowViews::SetIcon(const gfx::ImageSkia& icon) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void NativeWindowViews::SetEnabled(bool enable) {
|
||||||
|
// Handle multiple calls of SetEnabled correctly.
|
||||||
|
if (enable) {
|
||||||
|
--disable_count_;
|
||||||
|
if (disable_count_ != 0)
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
++disable_count_;
|
||||||
|
if (disable_count_ != 1)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(OS_WIN)
|
||||||
|
::EnableWindow(GetAcceleratedWidget(), enable);
|
||||||
|
#elif defined(USE_X11)
|
||||||
|
views::DesktopWindowTreeHostX11* tree_host =
|
||||||
|
views::DesktopWindowTreeHostX11::GetHostForXID(GetAcceleratedWidget());
|
||||||
|
if (enable) {
|
||||||
|
tree_host->RemoveEventRewriter(event_disabler_.get());
|
||||||
|
event_disabler_.reset();
|
||||||
|
} else {
|
||||||
|
event_disabler_.reset(new EventDisabler);
|
||||||
|
tree_host->AddEventRewriter(event_disabler_.get());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void NativeWindowViews::OnWidgetActivationChanged(
|
void NativeWindowViews::OnWidgetActivationChanged(
|
||||||
views::Widget* widget, bool active) {
|
views::Widget* widget, bool active) {
|
||||||
if (widget != window_.get())
|
if (widget != window_.get())
|
||||||
|
@ -900,6 +985,15 @@ void NativeWindowViews::OnWidgetBoundsChanged(
|
||||||
}
|
}
|
||||||
|
|
||||||
void NativeWindowViews::DeleteDelegate() {
|
void NativeWindowViews::DeleteDelegate() {
|
||||||
|
if (is_modal() && NativeWindow::parent()) {
|
||||||
|
NativeWindowViews* parent =
|
||||||
|
static_cast<NativeWindowViews*>(NativeWindow::parent());
|
||||||
|
// Enable parent window after current window gets closed.
|
||||||
|
parent->SetEnabled(true);
|
||||||
|
// Focus on parent window.
|
||||||
|
parent->Focus(true);
|
||||||
|
}
|
||||||
|
|
||||||
NotifyWindowClosed();
|
NotifyWindowClosed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1110,8 +1204,9 @@ ui::WindowShowState NativeWindowViews::GetRestoredState() {
|
||||||
// static
|
// static
|
||||||
NativeWindow* NativeWindow::Create(
|
NativeWindow* NativeWindow::Create(
|
||||||
brightray::InspectableWebContents* inspectable_web_contents,
|
brightray::InspectableWebContents* inspectable_web_contents,
|
||||||
const mate::Dictionary& options) {
|
const mate::Dictionary& options,
|
||||||
return new NativeWindowViews(inspectable_web_contents, options);
|
NativeWindow* parent) {
|
||||||
|
return new NativeWindowViews(inspectable_web_contents, options, parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace atom
|
} // namespace atom
|
||||||
|
|
|
@ -32,6 +32,8 @@ class WindowStateWatcher;
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
class AtomDesktopWindowTreeHostWin;
|
class AtomDesktopWindowTreeHostWin;
|
||||||
|
#elif defined(USE_X11)
|
||||||
|
class EventDisabler;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
class NativeWindowViews : public NativeWindow,
|
class NativeWindowViews : public NativeWindow,
|
||||||
|
@ -42,7 +44,8 @@ class NativeWindowViews : public NativeWindow,
|
||||||
public views::WidgetObserver {
|
public views::WidgetObserver {
|
||||||
public:
|
public:
|
||||||
NativeWindowViews(brightray::InspectableWebContents* inspectable_web_contents,
|
NativeWindowViews(brightray::InspectableWebContents* inspectable_web_contents,
|
||||||
const mate::Dictionary& options);
|
const mate::Dictionary& options,
|
||||||
|
NativeWindow* parent);
|
||||||
~NativeWindowViews() override;
|
~NativeWindowViews() override;
|
||||||
|
|
||||||
// NativeWindow:
|
// NativeWindow:
|
||||||
|
@ -54,6 +57,7 @@ class NativeWindowViews : public NativeWindow,
|
||||||
void ShowInactive() override;
|
void ShowInactive() override;
|
||||||
void Hide() override;
|
void Hide() override;
|
||||||
bool IsVisible() override;
|
bool IsVisible() override;
|
||||||
|
bool IsEnabled() override;
|
||||||
void Maximize() override;
|
void Maximize() override;
|
||||||
void Unmaximize() override;
|
void Unmaximize() override;
|
||||||
bool IsMaximized() override;
|
bool IsMaximized() override;
|
||||||
|
@ -94,6 +98,7 @@ class NativeWindowViews : public NativeWindow,
|
||||||
void SetIgnoreMouseEvents(bool ignore) override;
|
void SetIgnoreMouseEvents(bool ignore) override;
|
||||||
void SetFocusable(bool focusable) override;
|
void SetFocusable(bool focusable) override;
|
||||||
void SetMenu(ui::MenuModel* menu_model) override;
|
void SetMenu(ui::MenuModel* menu_model) override;
|
||||||
|
void SetParentWindow(NativeWindow* parent) override;
|
||||||
gfx::NativeWindow GetNativeWindow() override;
|
gfx::NativeWindow GetNativeWindow() override;
|
||||||
void SetOverlayIcon(const gfx::Image& overlay,
|
void SetOverlayIcon(const gfx::Image& overlay,
|
||||||
const std::string& description) override;
|
const std::string& description) override;
|
||||||
|
@ -113,6 +118,8 @@ class NativeWindowViews : public NativeWindow,
|
||||||
void SetIcon(const gfx::ImageSkia& icon);
|
void SetIcon(const gfx::ImageSkia& icon);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void SetEnabled(bool enable);
|
||||||
|
|
||||||
views::Widget* widget() const { return window_.get(); }
|
views::Widget* widget() const { return window_.get(); }
|
||||||
|
|
||||||
#if defined(OS_WIN)
|
#if defined(OS_WIN)
|
||||||
|
@ -187,6 +194,9 @@ class NativeWindowViews : public NativeWindow,
|
||||||
// Handles window state events.
|
// Handles window state events.
|
||||||
std::unique_ptr<WindowStateWatcher> window_state_watcher_;
|
std::unique_ptr<WindowStateWatcher> window_state_watcher_;
|
||||||
|
|
||||||
|
// To disable the mouse events.
|
||||||
|
std::unique_ptr<EventDisabler> event_disabler_;
|
||||||
|
|
||||||
// The "resizable" flag on Linux is implemented by setting size constraints,
|
// The "resizable" flag on Linux is implemented by setting size constraints,
|
||||||
// we need to make sure size constraints are restored when window becomes
|
// we need to make sure size constraints are restored when window becomes
|
||||||
// resizable again.
|
// resizable again.
|
||||||
|
@ -220,6 +230,9 @@ class NativeWindowViews : public NativeWindow,
|
||||||
// Map from accelerator to menu item's command id.
|
// Map from accelerator to menu item's command id.
|
||||||
accelerator_util::AcceleratorTable accelerator_table_;
|
accelerator_util::AcceleratorTable accelerator_table_;
|
||||||
|
|
||||||
|
// How many times the Disable has been called.
|
||||||
|
int disable_count_;
|
||||||
|
|
||||||
bool use_content_size_;
|
bool use_content_size_;
|
||||||
bool movable_;
|
bool movable_;
|
||||||
bool resizable_;
|
bool resizable_;
|
||||||
|
|
27
atom/browser/ui/x/event_disabler.cc
Normal file
27
atom/browser/ui/x/event_disabler.cc
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright (c) 2016 GitHub, Inc.
|
||||||
|
// Use of this source code is governed by the MIT license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#include "atom/browser/ui/x/event_disabler.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
EventDisabler::EventDisabler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
EventDisabler::~EventDisabler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ui::EventRewriteStatus EventDisabler::RewriteEvent(
|
||||||
|
const ui::Event& event,
|
||||||
|
std::unique_ptr<ui::Event>* rewritten_event) {
|
||||||
|
return ui::EVENT_REWRITE_DISCARD;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui::EventRewriteStatus EventDisabler::NextDispatchEvent(
|
||||||
|
const ui::Event& last_event,
|
||||||
|
std::unique_ptr<ui::Event>* new_event) {
|
||||||
|
return ui::EVENT_REWRITE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace atom
|
32
atom/browser/ui/x/event_disabler.h
Normal file
32
atom/browser/ui/x/event_disabler.h
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
// Copyright (c) 2016 GitHub, Inc.
|
||||||
|
// Use of this source code is governed by the MIT license that can be
|
||||||
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
#ifndef ATOM_BROWSER_UI_X_EVENT_DISABLER_H_
|
||||||
|
#define ATOM_BROWSER_UI_X_EVENT_DISABLER_H_
|
||||||
|
|
||||||
|
#include "base/macros.h"
|
||||||
|
#include "ui/events/event_rewriter.h"
|
||||||
|
|
||||||
|
namespace atom {
|
||||||
|
|
||||||
|
class EventDisabler : public ui::EventRewriter {
|
||||||
|
public:
|
||||||
|
EventDisabler();
|
||||||
|
~EventDisabler() override;
|
||||||
|
|
||||||
|
// ui::EventRewriter:
|
||||||
|
ui::EventRewriteStatus RewriteEvent(
|
||||||
|
const ui::Event& event,
|
||||||
|
std::unique_ptr<ui::Event>* rewritten_event) override;
|
||||||
|
ui::EventRewriteStatus NextDispatchEvent(
|
||||||
|
const ui::Event& last_event,
|
||||||
|
std::unique_ptr<ui::Event>* new_event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DISALLOW_COPY_AND_ASSIGN(EventDisabler);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace atom
|
||||||
|
|
||||||
|
#endif // ATOM_BROWSER_UI_X_EVENT_DISABLER_H_
|
|
@ -14,10 +14,6 @@
|
||||||
|
|
||||||
namespace atom {
|
namespace atom {
|
||||||
|
|
||||||
namespace internal {
|
|
||||||
|
|
||||||
} // namespace internal
|
|
||||||
|
|
||||||
// Like ES6's WeakMap, but the key is Integer and the value is Weak Pointer.
|
// Like ES6's WeakMap, but the key is Integer and the value is Weak Pointer.
|
||||||
template<typename K>
|
template<typename K>
|
||||||
class KeyWeakMap {
|
class KeyWeakMap {
|
||||||
|
@ -57,7 +53,7 @@ class KeyWeakMap {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns all objects.
|
// Returns all objects.
|
||||||
std::vector<v8::Local<v8::Object>> Values(v8::Isolate* isolate) {
|
std::vector<v8::Local<v8::Object>> Values(v8::Isolate* isolate) const {
|
||||||
std::vector<v8::Local<v8::Object>> keys;
|
std::vector<v8::Local<v8::Object>> keys;
|
||||||
keys.reserve(map_.size());
|
keys.reserve(map_.size());
|
||||||
for (const auto& iter : map_) {
|
for (const auto& iter : map_) {
|
||||||
|
|
|
@ -59,6 +59,39 @@ win.loadURL('https://github.com')
|
||||||
Note that even for apps that use `ready-to-show` event, it is still recommended
|
Note that even for apps that use `ready-to-show` event, it is still recommended
|
||||||
to set `backgroundColor` to make app feel more native.
|
to set `backgroundColor` to make app feel more native.
|
||||||
|
|
||||||
|
## Parent and child windows
|
||||||
|
|
||||||
|
By using `parent` option, you can create child windows:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
let top = new BrowserWindow()
|
||||||
|
let child = new BrowserWindow({parent: top})
|
||||||
|
```
|
||||||
|
|
||||||
|
The `child` window will always show on top of the `top` window.
|
||||||
|
|
||||||
|
### Modal windows
|
||||||
|
|
||||||
|
A modal window is a child window that disables parent window, to create a modal
|
||||||
|
window, you have to set both `parent` and `modal` options:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
let child = new BrowserWindow({parent: top, modal: true, show: false})
|
||||||
|
child.loadURL('https://github.com')
|
||||||
|
child.once('ready-to-show', () => {
|
||||||
|
child.show()
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
### Platform notices
|
||||||
|
|
||||||
|
* On macOS the child windows will keep the relative position to parent window
|
||||||
|
when parent window moves, while on Windows and Linux child windows will not
|
||||||
|
move.
|
||||||
|
* On Windows it is not supported to change parent window dynamically.
|
||||||
|
* On Linux the type of modal windows will be changed to `dialog`.
|
||||||
|
* On Linux many desktop environments do not support hiding a modal window.
|
||||||
|
|
||||||
## Class: BrowserWindow
|
## Class: BrowserWindow
|
||||||
|
|
||||||
`BrowserWindow` is an
|
`BrowserWindow` is an
|
||||||
|
@ -116,6 +149,9 @@ It creates a new `BrowserWindow` with native properties as set by the `options`.
|
||||||
`true`.
|
`true`.
|
||||||
* `frame` Boolean - Specify `false` to create a
|
* `frame` Boolean - Specify `false` to create a
|
||||||
[Frameless Window](frameless-window.md). Default is `true`.
|
[Frameless Window](frameless-window.md). Default is `true`.
|
||||||
|
* `parent` BrowserWindow - Specify parent window. Default is `null`.
|
||||||
|
* `modal` Boolean - Whether this is a modal window. This only works when the
|
||||||
|
window is a child window. Default is `false`.
|
||||||
* `acceptFirstMouse` Boolean - Whether the web view accepts a single
|
* `acceptFirstMouse` Boolean - Whether the web view accepts a single
|
||||||
mouse-down event that simultaneously activates the window. Default is
|
mouse-down event that simultaneously activates the window. Default is
|
||||||
`false`.
|
`false`.
|
||||||
|
@ -532,6 +568,10 @@ Hides the window.
|
||||||
|
|
||||||
Returns a boolean, whether the window is visible to the user.
|
Returns a boolean, whether the window is visible to the user.
|
||||||
|
|
||||||
|
### `win.isModal()`
|
||||||
|
|
||||||
|
Returns whether current window is a modal window.
|
||||||
|
|
||||||
### `win.maximize()`
|
### `win.maximize()`
|
||||||
|
|
||||||
Maximizes the window.
|
Maximizes the window.
|
||||||
|
@ -1017,3 +1057,18 @@ events.
|
||||||
Changes whether the window can be focused.
|
Changes whether the window can be focused.
|
||||||
|
|
||||||
[blink-feature-string]: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
|
[blink-feature-string]: https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
|
||||||
|
|
||||||
|
### `win.setParentWindow(parent)` _Linux_ _macOS_
|
||||||
|
|
||||||
|
* `parent` BrowserWindow
|
||||||
|
|
||||||
|
Sets `parent` as current window's parent window, passing `null` will turn
|
||||||
|
current window into a top-level window.
|
||||||
|
|
||||||
|
### `win.getParentWindow()`
|
||||||
|
|
||||||
|
Returns the parent window.
|
||||||
|
|
||||||
|
### `win.getChildWindows()`
|
||||||
|
|
||||||
|
Returns all child windows.
|
||||||
|
|
|
@ -286,6 +286,8 @@
|
||||||
'atom/browser/ui/win/notify_icon.h',
|
'atom/browser/ui/win/notify_icon.h',
|
||||||
'atom/browser/ui/win/taskbar_host.cc',
|
'atom/browser/ui/win/taskbar_host.cc',
|
||||||
'atom/browser/ui/win/taskbar_host.h',
|
'atom/browser/ui/win/taskbar_host.h',
|
||||||
|
'atom/browser/ui/x/event_disabler.cc',
|
||||||
|
'atom/browser/ui/x/event_disabler.h',
|
||||||
'atom/browser/ui/x/window_state_watcher.cc',
|
'atom/browser/ui/x/window_state_watcher.cc',
|
||||||
'atom/browser/ui/x/window_state_watcher.h',
|
'atom/browser/ui/x/window_state_watcher.h',
|
||||||
'atom/browser/ui/x/x_window_utils.cc',
|
'atom/browser/ui/x/x_window_utils.cc',
|
||||||
|
|
|
@ -117,7 +117,6 @@ BrowserWindow.fromDevToolsWebContents = (webContents) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helpers.
|
// Helpers.
|
||||||
|
|
||||||
Object.assign(BrowserWindow.prototype, {
|
Object.assign(BrowserWindow.prototype, {
|
||||||
loadURL (...args) {
|
loadURL (...args) {
|
||||||
return this.webContents.loadURL.apply(this.webContents, args)
|
return this.webContents.loadURL.apply(this.webContents, args)
|
||||||
|
|
|
@ -836,6 +836,110 @@ describe('browser-window module', function () {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('parent window', function () {
|
||||||
|
let c = null
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
if (c != null) c.destroy()
|
||||||
|
c = new BrowserWindow({show: false, parent: w})
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(function () {
|
||||||
|
if (c != null) c.destroy()
|
||||||
|
c = null
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('parent option', function () {
|
||||||
|
it('sets parent window', function () {
|
||||||
|
assert.equal(c.getParentWindow(), w)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('adds window to child windows of parent', function () {
|
||||||
|
assert.deepEqual(w.getChildWindows(), [c])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('removes from child windows of parent when window is closed', function (done) {
|
||||||
|
c.once('closed', () => {
|
||||||
|
assert.deepEqual(w.getChildWindows(), [])
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
c.close()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('win.setParentWindow(parent)', function () {
|
||||||
|
if (process.platform === 'win32') return
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
if (c != null) c.destroy()
|
||||||
|
c = new BrowserWindow({show: false})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('sets parent window', function () {
|
||||||
|
assert.equal(w.getParentWindow(), null)
|
||||||
|
assert.equal(c.getParentWindow(), null)
|
||||||
|
c.setParentWindow(w)
|
||||||
|
assert.equal(c.getParentWindow(), w)
|
||||||
|
c.setParentWindow(null)
|
||||||
|
assert.equal(c.getParentWindow(), null)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('adds window to child windows of parent', function () {
|
||||||
|
assert.deepEqual(w.getChildWindows(), [])
|
||||||
|
c.setParentWindow(w)
|
||||||
|
assert.deepEqual(w.getChildWindows(), [c])
|
||||||
|
c.setParentWindow(null)
|
||||||
|
assert.deepEqual(w.getChildWindows(), [])
|
||||||
|
})
|
||||||
|
|
||||||
|
it('removes from child windows of parent when window is closed', function (done) {
|
||||||
|
c.once('closed', () => {
|
||||||
|
assert.deepEqual(w.getChildWindows(), [])
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
c.setParentWindow(w)
|
||||||
|
c.close()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('modal option', function () {
|
||||||
|
// The isEnabled API is not reliable on macOS.
|
||||||
|
if (process.platform === 'darwin') return
|
||||||
|
|
||||||
|
beforeEach(function () {
|
||||||
|
if (c != null) c.destroy()
|
||||||
|
c = new BrowserWindow({show: false, parent: w, modal: true})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('disables parent window', function () {
|
||||||
|
assert.equal(w.isEnabled(), true)
|
||||||
|
c.show()
|
||||||
|
assert.equal(w.isEnabled(), false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('enables parent window when closed', function (done) {
|
||||||
|
c.once('closed', () => {
|
||||||
|
assert.equal(w.isEnabled(), true)
|
||||||
|
done()
|
||||||
|
})
|
||||||
|
c.show()
|
||||||
|
c.close()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('disables parent window recursively', function () {
|
||||||
|
let c2 = new BrowserWindow({show: false, parent: w, modal: true})
|
||||||
|
c.show()
|
||||||
|
assert.equal(w.isEnabled(), false)
|
||||||
|
c2.show()
|
||||||
|
assert.equal(w.isEnabled(), false)
|
||||||
|
c.destroy()
|
||||||
|
assert.equal(w.isEnabled(), false)
|
||||||
|
c2.destroy()
|
||||||
|
assert.equal(w.isEnabled(), true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
describe('window.webContents.send(channel, args...)', function () {
|
describe('window.webContents.send(channel, args...)', function () {
|
||||||
it('throws an error when the channel is missing', function () {
|
it('throws an error when the channel is missing', function () {
|
||||||
assert.throws(function () {
|
assert.throws(function () {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue