Merge pull request #862 from atom/window-state-events

Add window states events for BrowserWindow
This commit is contained in:
Cheng Zhao 2014-11-25 15:41:10 +08:00
commit 8278d8b51a
14 changed files with 334 additions and 14 deletions

View file

@ -179,6 +179,8 @@
'atom/browser/ui/win/notify_icon_host.h',
'atom/browser/ui/win/notify_icon.cc',
'atom/browser/ui/win/notify_icon.h',
'atom/browser/ui/x/window_state_watcher.cc',
'atom/browser/ui/x/window_state_watcher.h',
'atom/browser/ui/x/x_window_utils.cc',
'atom/browser/ui/x/x_window_utils.h',
'atom/browser/web_view/web_view_manager.cc',

View file

@ -112,6 +112,30 @@ void Window::OnWindowFocus() {
Emit("focus");
}
void Window::OnWindowMaximize() {
Emit("maximize");
}
void Window::OnWindowUnmaximize() {
Emit("unmaximize");
}
void Window::OnWindowMinimize() {
Emit("minimize");
}
void Window::OnWindowRestore() {
Emit("restore");
}
void Window::OnWindowEnterFullScreen() {
Emit("enter-full-screen");
}
void Window::OnWindowLeaveFullScreen() {
Emit("leave-full-screen");
}
void Window::OnRendererUnresponsive() {
Emit("unresponsive");
}
@ -193,8 +217,8 @@ bool Window::IsMinimized() {
return window_->IsMinimized();
}
void Window::SetFullscreen(bool fullscreen) {
window_->SetFullscreen(fullscreen);
void Window::SetFullScreen(bool fullscreen) {
window_->SetFullScreen(fullscreen);
}
bool Window::IsFullscreen() {
@ -422,7 +446,7 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("minimize", &Window::Minimize)
.SetMethod("restore", &Window::Restore)
.SetMethod("isMinimized", &Window::IsMinimized)
.SetMethod("setFullScreen", &Window::SetFullscreen)
.SetMethod("setFullScreen", &Window::SetFullScreen)
.SetMethod("isFullScreen", &Window::IsFullscreen)
.SetMethod("getSize", &Window::GetSize)
.SetMethod("setSize", &Window::SetSize)

View file

@ -43,7 +43,7 @@ class Window : public mate::EventEmitter,
explicit Window(const mate::Dictionary& options);
virtual ~Window();
// Implementations of NativeWindowObserver:
// NativeWindowObserver:
void OnPageTitleUpdated(bool* prevent_default,
const std::string& title) override;
void WillCreatePopupWindow(const base::string16& frame_name,
@ -54,6 +54,12 @@ class Window : public mate::EventEmitter,
void OnWindowClosed() override;
void OnWindowBlur() override;
void OnWindowFocus() override;
void OnWindowMaximize() override;
void OnWindowUnmaximize() override;
void OnWindowMinimize() override;
void OnWindowRestore() override;
void OnWindowEnterFullScreen() override;
void OnWindowLeaveFullScreen() override;
void OnRendererUnresponsive() override;
void OnRendererResponsive() override;
@ -74,7 +80,7 @@ class Window : public mate::EventEmitter,
void Minimize();
void Restore();
bool IsMinimized();
void SetFullscreen(bool fullscreen);
void SetFullScreen(bool fullscreen);
bool IsFullscreen();
void SetSize(int width, int height);
std::vector<int> GetSize();

View file

@ -204,7 +204,7 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
}
bool fullscreen;
if (options.Get(switches::kFullscreen, &fullscreen) && fullscreen) {
SetFullscreen(true);
SetFullScreen(true);
}
bool skip;
if (options.Get(switches::kSkipTaskbar, &skip) && skip) {
@ -466,6 +466,32 @@ void NativeWindow::NotifyWindowFocus() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowFocus());
}
void NativeWindow::NotifyWindowMaximize() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowMaximize());
}
void NativeWindow::NotifyWindowUnmaximize() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowUnmaximize());
}
void NativeWindow::NotifyWindowMinimize() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowMinimize());
}
void NativeWindow::NotifyWindowRestore() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_, OnWindowRestore());
}
void NativeWindow::NotifyWindowEnterFullScreen() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnWindowEnterFullScreen());
}
void NativeWindow::NotifyWindowLeaveFullScreen() {
FOR_EACH_OBSERVER(NativeWindowObserver, observers_,
OnWindowLeaveFullScreen());
}
bool NativeWindow::ShouldCreateWebContents(
content::WebContents* web_contents,
int route_id,

View file

@ -111,7 +111,7 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
virtual void Minimize() = 0;
virtual void Restore() = 0;
virtual bool IsMinimized() = 0;
virtual void SetFullscreen(bool fullscreen) = 0;
virtual void SetFullScreen(bool fullscreen) = 0;
virtual bool IsFullscreen() = 0;
virtual void SetSize(const gfx::Size& size) = 0;
virtual gfx::Size GetSize() = 0;
@ -192,6 +192,12 @@ class NativeWindow : public brightray::DefaultWebContentsDelegate,
void NotifyWindowClosed();
void NotifyWindowBlur();
void NotifyWindowFocus();
void NotifyWindowMaximize();
void NotifyWindowUnmaximize();
void NotifyWindowMinimize();
void NotifyWindowRestore();
void NotifyWindowEnterFullScreen();
void NotifyWindowLeaveFullScreen();
void AddObserver(NativeWindowObserver* obs) {
observers_.AddObserver(obs);

View file

@ -37,7 +37,7 @@ class NativeWindowMac : public NativeWindow {
virtual void Minimize() OVERRIDE;
virtual void Restore() OVERRIDE;
virtual bool IsMinimized() OVERRIDE;
virtual void SetFullscreen(bool fullscreen) OVERRIDE;
virtual void SetFullScreen(bool fullscreen) OVERRIDE;
virtual bool IsFullscreen() OVERRIDE;
virtual void SetSize(const gfx::Size& size) OVERRIDE;
virtual gfx::Size GetSize() OVERRIDE;

View file

@ -81,11 +81,36 @@ static const CGFloat kAtomWindowCornerRadius = 4.0;
shell_->ClipWebView();
}
- (void)windowDidMiniaturize:(NSNotification*)notification {
shell_->NotifyWindowMinimize();
}
- (void)windowDidDeminiaturize:(NSNotification*)notification {
shell_->NotifyWindowRestore();
}
- (BOOL)windowShouldZoom:(NSWindow*)window toFrame:(NSRect)newFrame {
// Cocoa doen't have concept of maximize/unmaximize, so wee need to emulate
// them by calculating size change when zooming.
if (newFrame.size.width < [window frame].size.width ||
newFrame.size.height < [window frame].size.height)
shell_->NotifyWindowUnmaximize();
else
shell_->NotifyWindowMaximize();
return YES;
}
- (void)windowDidEnterFullScreen:(NSNotification*)notification {
shell_->NotifyWindowEnterFullScreen();
}
- (void)windowDidExitFullScreen:(NSNotification*)notification {
if (!shell_->has_frame()) {
NSWindow* window = shell_->GetNativeWindow();
[[window standardWindowButton:NSWindowFullScreenButton] setHidden:YES];
}
shell_->NotifyWindowLeaveFullScreen();
}
- (void)windowWillClose:(NSNotification*)notification {
@ -375,7 +400,7 @@ bool NativeWindowMac::IsMinimized() {
return [window_ isMiniaturized];
}
void NativeWindowMac::SetFullscreen(bool fullscreen) {
void NativeWindowMac::SetFullScreen(bool fullscreen) {
if (fullscreen == IsFullscreen())
return;
@ -520,10 +545,10 @@ void NativeWindowMac::SetKiosk(bool kiosk) {
NSApplicationPresentationDisableHideApplication;
[NSApp setPresentationOptions:options];
is_kiosk_ = true;
SetFullscreen(true);
SetFullScreen(true);
} else if (!kiosk && is_kiosk_) {
is_kiosk_ = false;
SetFullscreen(false);
SetFullScreen(false);
[NSApp setPresentationOptions:kiosk_options_];
}
}

View file

@ -39,6 +39,14 @@ class NativeWindowObserver {
// Called when window gains focus.
virtual void OnWindowFocus() {}
// Called when window state changed.
virtual void OnWindowMaximize() {}
virtual void OnWindowUnmaximize() {}
virtual void OnWindowMinimize() {}
virtual void OnWindowRestore() {}
virtual void OnWindowEnterFullScreen() {}
virtual void OnWindowLeaveFullScreen() {}
// Called when renderer is hung.
virtual void OnRendererUnresponsive() {}

View file

@ -32,6 +32,7 @@
#include "atom/browser/browser.h"
#include "atom/browser/ui/views/global_menu_bar_x11.h"
#include "atom/browser/ui/views/frameless_view.h"
#include "atom/browser/ui/x/window_state_watcher.h"
#include "atom/browser/ui/x/x_window_utils.h"
#include "base/environment.h"
#include "base/nix/xdg_util.h"
@ -144,6 +145,9 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
menu_bar_autohide_(false),
menu_bar_visible_(false),
menu_bar_alt_pressed_(false),
#if defined(OS_WIN)
is_minimized_(false),
#endif
keyboard_event_handler_(new views::UnhandledKeyboardEventHandler),
use_content_size_(false),
resizable_(true) {
@ -189,6 +193,9 @@ NativeWindowViews::NativeWindowViews(content::WebContents* web_contents,
window_->Init(params);
#if defined(USE_X11)
// Start monitoring window states.
window_state_watcher_.reset(new WindowStateWatcher(this));
// Set _GTK_THEME_VARIANT to dark if we have "dark-theme" option set.
bool use_dark_theme = false;
if (options.Get(switches::kDarkTheme, &use_dark_theme) && use_dark_theme) {
@ -311,8 +318,15 @@ bool NativeWindowViews::IsMinimized() {
return window_->IsMinimized();
}
void NativeWindowViews::SetFullscreen(bool fullscreen) {
void NativeWindowViews::SetFullScreen(bool fullscreen) {
window_->SetFullscreen(fullscreen);
#if defined(OS_WIN)
// There is no native fullscreen state on Windows.
if (fullscreen)
NotifyWindowEnterFullScreen();
else
NotifyWindowLeaveFullScreen();
#endif
}
bool NativeWindowViews::IsFullscreen() {
@ -484,7 +498,7 @@ void NativeWindowViews::SetSkipTaskbar(bool skip) {
}
void NativeWindowViews::SetKiosk(bool kiosk) {
SetFullscreen(kiosk);
SetFullScreen(kiosk);
}
bool NativeWindowViews::IsKiosk() {
@ -716,6 +730,27 @@ views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView(
#endif
}
#if defined(OS_WIN)
bool NativeWindowViews::ExecuteWindowsCommand(int command_id) {
// Windows uses the 4 lower order bits of |command_id| for type-specific
// information so we must exclude this when comparing.
static const int sc_mask = 0xFFF0;
if ((command_id & sc_mask) == SC_MINIMIZE) {
NotifyWindowMinimize();
is_minimized_ = true;
} else if ((command_id & sc_mask) == SC_RESTORE) {
if (is_minimized_)
NotifyWindowRestore();
else
NotifyWindowUnmaximize();
is_minimized_ = false;
} else if ((command_id & sc_mask) == SC_MAXIMIZE) {
NotifyWindowMaximize();
}
return false;
}
#endif
gfx::ImageSkia NativeWindowViews::GetDevToolsWindowIcon() {
return GetWindowAppIcon();
}

View file

@ -22,6 +22,7 @@ namespace atom {
class GlobalMenuBarX11;
class MenuBar;
class WindowStateWatcher;
class NativeWindowViews : public NativeWindow,
public views::WidgetDelegateView,
@ -47,7 +48,7 @@ class NativeWindowViews : public NativeWindow,
void Minimize() override;
void Restore() override;
bool IsMinimized() override;
void SetFullscreen(bool fullscreen) override;
void SetFullScreen(bool fullscreen) override;
bool IsFullscreen() override;
void SetSize(const gfx::Size& size) override;
gfx::Size GetSize() override;
@ -110,6 +111,9 @@ class NativeWindowViews : public NativeWindow,
views::ClientView* CreateClientView(views::Widget* widget) override;
views::NonClientFrameView* CreateNonClientFrameView(
views::Widget* widget) override;
#if defined(OS_WIN)
bool ExecuteWindowsCommand(int command_id) override;
#endif
// brightray::InspectableWebContentsDelegate:
gfx::ImageSkia GetDevToolsWindowIcon() override;
@ -144,6 +148,13 @@ class NativeWindowViews : public NativeWindow,
#if defined(USE_X11)
scoped_ptr<GlobalMenuBarX11> global_menu_bar_;
// Handles window state events.
scoped_ptr<WindowStateWatcher> window_state_watcher_;
#elif defined(OS_WIN)
// Records window was whether restored from minimized state or maximized
// state.
bool is_minimized_;
#endif
// Handles unhandled keyboard messages coming back from the renderer process.

View file

@ -0,0 +1,78 @@
// Copyright (c) 2014 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/window_state_watcher.h"
#include <X11/Xlib.h>
#include "ui/events/platform/platform_event_source.h"
namespace atom {
namespace {
const char* kAtomsToCache[] = {
"_NET_WM_STATE",
NULL,
};
} // namespace
WindowStateWatcher::WindowStateWatcher(NativeWindowViews* window)
: window_(window),
widget_(window->GetAcceleratedWidget()),
atom_cache_(gfx::GetXDisplay(), kAtomsToCache),
was_minimized_(false),
was_maximized_(false) {
ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
}
WindowStateWatcher::~WindowStateWatcher() {
ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this);
}
void WindowStateWatcher::WillProcessEvent(const ui::PlatformEvent& event) {
if (IsWindowStateEvent(event)) {
was_minimized_ = window_->IsMinimized();
was_maximized_ = window_->IsMaximized();
}
}
void WindowStateWatcher::DidProcessEvent(const ui::PlatformEvent& event) {
if (IsWindowStateEvent(event)) {
bool is_minimized = window_->IsMinimized();
bool is_maximized = window_->IsMaximized();
bool is_fullscreen = window_->IsFullscreen();
if (is_minimized != was_minimized_) {
if (is_minimized)
window_->NotifyWindowMinimize();
else
window_->NotifyWindowRestore();
} else if (is_maximized != was_maximized_) {
if (is_maximized)
window_->NotifyWindowMaximize();
else
window_->NotifyWindowUnmaximize();
} else {
// If this is neither a "maximize" or "minimize" event, then we think it
// is a "fullscreen" event.
// The "IsFullscreen()" becomes true immediately before "WillProcessEvent"
// is called, so we can not handle this like "maximize" and "minimize" by
// watching whether they have changed.
if (is_fullscreen)
window_->NotifyWindowEnterFullScreen();
else
window_->NotifyWindowLeaveFullScreen();
}
}
}
bool WindowStateWatcher::IsWindowStateEvent(const ui::PlatformEvent& event) {
::Atom changed_atom = event->xproperty.atom;
return (changed_atom == atom_cache_.GetAtom("_NET_WM_STATE") &&
event->type == PropertyNotify &&
event->xproperty.window == widget_);
}
} // namespace atom

View file

@ -0,0 +1,41 @@
// Copyright (c) 2014 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_WINDOW_STATE_WATCHER_H_
#define ATOM_BROWSER_UI_X_WINDOW_STATE_WATCHER_H_
#include "ui/events/platform/platform_event_observer.h"
#include "atom/browser/native_window_views.h"
#include "ui/gfx/x/x11_atom_cache.h"
namespace atom {
class WindowStateWatcher : public ui::PlatformEventObserver {
public:
explicit WindowStateWatcher(NativeWindowViews* window);
virtual ~WindowStateWatcher();
protected:
// ui::PlatformEventObserver:
void WillProcessEvent(const ui::PlatformEvent& event) override;
void DidProcessEvent(const ui::PlatformEvent& event) override;
private:
bool IsWindowStateEvent(const ui::PlatformEvent& event);
NativeWindowViews* window_;
gfx::AcceleratedWidget widget_;
ui::X11AtomCache atom_cache_;
bool was_minimized_;
bool was_maximized_;
DISALLOW_COPY_AND_ASSIGN(WindowStateWatcher);
};
} // namespace atom
#endif // ATOM_BROWSER_UI_X_WINDOW_STATE_WATCHER_H_

View file

@ -147,6 +147,30 @@ Emitted when window loses focus.
Emitted when window gains focus.
### Event: 'maximize'
Emitted when window is maximized.
### Event: 'unmaximize'
Emitted when window exits from maximized state.
### Event: 'minimize'
Emitted when window is minimized.
### Event: 'restore'
Emitted when window is restored from minimized state.
### Event: 'enter-full-screen'
Emitted when window enters full screen state.
### Event: 'leave-full-screen'
Emitted when window leaves full screen state.
### Event: 'devtools-opened'
Emitted when devtools is opened.

View file

@ -183,3 +183,37 @@ describe 'browser-window module', ->
assert.equal frameName, 'target'
done()
w.loadUrl "file://#{fixtures}/pages/target-name.html"
describe 'maximize event', ->
return if isCI and process.platform is 'linux'
it 'emits when window is maximized', (done) ->
@timeout 10000
w.once 'maximize', -> done()
w.show()
w.maximize()
describe 'unmaximize event', ->
return if isCI and process.platform is 'linux'
it 'emits when window is unmaximized', (done) ->
@timeout 10000
w.once 'unmaximize', -> done()
w.show()
w.maximize()
w.unmaximize()
describe 'minimize event', ->
return if isCI and process.platform is 'linux'
it 'emits when window is minimized', (done) ->
@timeout 10000
w.once 'minimize', -> done()
w.show()
w.minimize()
describe 'restore event', ->
return if isCI and process.platform is 'linux'
it 'emits when window is restored', (done) ->
@timeout 10000
w.once 'restore', -> done()
w.show()
w.minimize()
w.restore()