added or/and improved closable, minimizable, movable, resizable features for windows on os x and windows

This commit is contained in:
evgenyzinoviev 2016-01-18 23:46:35 +01:00
parent 7842a657d0
commit 2a554cb138
11 changed files with 255 additions and 36 deletions

View file

@ -408,6 +408,30 @@ bool Window::IsResizable() {
return window_->IsResizable(); return window_->IsResizable();
} }
void Window::SetMovable(bool movable) {
window_->SetMovable(movable);
}
bool Window::IsMovable() {
return window_->IsMovable();
}
void Window::SetMinimizable(bool minimizable) {
window_->SetMinimizable(minimizable);
}
bool Window::IsMinimizable() {
return window_->IsMinimizable();
}
void Window::SetClosable(bool closable) {
window_->SetClosable(closable);
}
bool Window::IsClosable() {
return window_->IsClosable();
}
void Window::SetAlwaysOnTop(bool top) { void Window::SetAlwaysOnTop(bool top) {
window_->SetAlwaysOnTop(top); window_->SetAlwaysOnTop(top);
} }
@ -659,6 +683,12 @@ void Window::BuildPrototype(v8::Isolate* isolate,
.SetMethod("getMaximumSize", &Window::GetMaximumSize) .SetMethod("getMaximumSize", &Window::GetMaximumSize)
.SetMethod("setResizable", &Window::SetResizable) .SetMethod("setResizable", &Window::SetResizable)
.SetMethod("isResizable", &Window::IsResizable) .SetMethod("isResizable", &Window::IsResizable)
.SetMethod("setMovable", &Window::SetMovable)
.SetMethod("isMovable", &Window::IsMovable)
.SetMethod("setMinimizable", &Window::SetMinimizable)
.SetMethod("isMinimizable", &Window::IsMinimizable)
.SetMethod("setClosable", &Window::SetClosable)
.SetMethod("isClosable", &Window::IsClosable)
.SetMethod("setAlwaysOnTop", &Window::SetAlwaysOnTop) .SetMethod("setAlwaysOnTop", &Window::SetAlwaysOnTop)
.SetMethod("isAlwaysOnTop", &Window::IsAlwaysOnTop) .SetMethod("isAlwaysOnTop", &Window::IsAlwaysOnTop)
.SetMethod("center", &Window::Center) .SetMethod("center", &Window::Center)

View file

@ -106,6 +106,12 @@ class Window : public mate::TrackableObject<Window>,
std::vector<int> GetMaximumSize(); std::vector<int> GetMaximumSize();
void SetResizable(bool resizable); void SetResizable(bool resizable);
bool IsResizable(); bool IsResizable();
void SetMovable(bool movable);
bool IsMovable();
void SetMinimizable(bool minimizable);
bool IsMinimizable();
void SetClosable(bool closable);
bool IsClosable();
void SetAlwaysOnTop(bool top); void SetAlwaysOnTop(bool top);
bool IsAlwaysOnTop(); bool IsAlwaysOnTop();
void Center(); void Center();

View file

@ -120,6 +120,14 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
if (options.Get(options::kResizable, &resizable)) { if (options.Get(options::kResizable, &resizable)) {
SetResizable(resizable); SetResizable(resizable);
} }
bool minimizable;
if (options.Get(options::kMinimizable, &minimizable)) {
SetMinimizable(minimizable);
}
bool closable;
if (options.Get(options::kClosable, &closable)) {
SetClosable(closable);
}
#endif #endif
bool top; bool top;
if (options.Get(options::kAlwaysOnTop, &top) && top) { if (options.Get(options::kAlwaysOnTop, &top) && top) {

View file

@ -125,6 +125,12 @@ class NativeWindow : public base::SupportsUserData,
virtual gfx::Size GetMaximumSize(); virtual gfx::Size GetMaximumSize();
virtual void SetResizable(bool resizable) = 0; virtual void SetResizable(bool resizable) = 0;
virtual bool IsResizable() = 0; virtual bool IsResizable() = 0;
virtual void SetMovable(bool movable) = 0;
virtual bool IsMovable() = 0;
virtual void SetMinimizable(bool minimizable) = 0;
virtual bool IsMinimizable() = 0;
virtual void SetClosable(bool closable) = 0;
virtual bool IsClosable() = 0;
virtual void SetAlwaysOnTop(bool top) = 0; virtual void SetAlwaysOnTop(bool top) = 0;
virtual bool IsAlwaysOnTop() = 0; virtual bool IsAlwaysOnTop() = 0;
virtual void Center() = 0; virtual void Center() = 0;

View file

@ -48,6 +48,12 @@ class NativeWindowMac : public NativeWindow {
const extensions::SizeConstraints& size_constraints) override; const extensions::SizeConstraints& size_constraints) override;
void SetResizable(bool resizable) override; void SetResizable(bool resizable) override;
bool IsResizable() override; bool IsResizable() override;
void SetMovable(bool movable) override;
bool IsMovable() override;
void SetMinimizable(bool minimizable) override;
bool IsMinimizable() override;
void SetClosable(bool closable) override;
bool IsClosable() override;
void SetAlwaysOnTop(bool top) override; void SetAlwaysOnTop(bool top) override;
bool IsAlwaysOnTop() override; bool IsAlwaysOnTop() override;
void Center() override; void Center() override;
@ -100,6 +106,7 @@ class NativeWindowMac : public NativeWindow {
gfx::Size WindowSizeToContentSize(const gfx::Size& size) override; gfx::Size WindowSizeToContentSize(const gfx::Size& size) override;
void UpdateDraggableRegions( void UpdateDraggableRegions(
const std::vector<DraggableRegion>& regions) override; const std::vector<DraggableRegion>& regions) override;
void FixZoomButton();
void InstallView(); void InstallView();
void UninstallView(); void UninstallView();

View file

@ -369,6 +369,12 @@ NativeWindowMac::NativeWindowMac(
bool resizable = true; bool resizable = true;
options.Get(options::kResizable, &resizable); options.Get(options::kResizable, &resizable);
bool minimizable = true;
options.Get(options::kMinimizable, &minimizable);
bool closable = true;
options.Get(options::kClosable, &closable);
// New title bar styles are available in Yosemite or newer // New title bar styles are available in Yosemite or newer
std::string titleBarStyle; std::string titleBarStyle;
if (base::mac::IsOSYosemiteOrLater()) if (base::mac::IsOSYosemiteOrLater())
@ -385,8 +391,13 @@ NativeWindowMac::NativeWindowMac(
useStandardWindow = false; useStandardWindow = false;
} }
NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask | NSUInteger styleMask = NSTitledWindowMask | NSClosableWindowMask;
NSMiniaturizableWindowMask; if (minimizable) {
styleMask |= NSMiniaturizableWindowMask;
}
if (!closable) {
styleMask &= ~NSClosableWindowMask;
}
if (!useStandardWindow || transparent() || !has_frame()) { if (!useStandardWindow || transparent() || !has_frame()) {
styleMask |= NSTexturedBackgroundWindowMask; styleMask |= NSTexturedBackgroundWindowMask;
} }
@ -487,6 +498,11 @@ NativeWindowMac::NativeWindowMac(
[window_ setCollectionBehavior:collectionBehavior]; [window_ setCollectionBehavior:collectionBehavior];
} }
// Disable zoom button if window is not resizable
if (!resizable) {
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO];
}
NSView* view = inspectable_web_contents()->GetView()->GetNativeView(); NSView* view = inspectable_web_contents()->GetView()->GetNativeView();
[view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
@ -635,8 +651,10 @@ void NativeWindowMac::SetResizable(bool resizable) {
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:YES]; [[window_ standardWindowButton:NSWindowZoomButton] setEnabled:YES];
[window_ setStyleMask:[window_ styleMask] | NSResizableWindowMask]; [window_ setStyleMask:[window_ styleMask] | NSResizableWindowMask];
} else { } else {
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO]; // If we disable the button before changing the styleMask, button is not
// disabled. Looks like a bug in Cocoa (OS X 10.10.5)
[window_ setStyleMask:[window_ styleMask] & (~NSResizableWindowMask)]; [window_ setStyleMask:[window_ styleMask] & (~NSResizableWindowMask)];
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO];
} }
} }
@ -644,10 +662,56 @@ bool NativeWindowMac::IsResizable() {
return [window_ styleMask] & NSResizableWindowMask; return [window_ styleMask] & NSResizableWindowMask;
} }
void NativeWindowMac::SetMovable(bool movable) {
[window_ setMovable:movable];
}
bool NativeWindowMac::IsMovable() {
return [window_ isMovable];
}
void NativeWindowMac::SetMinimizable(bool minimizable) {
if (minimizable) {
[window_ setStyleMask:[window_ styleMask] | NSMiniaturizableWindowMask];
} else {
[window_ setStyleMask:[window_ styleMask] & (~NSMiniaturizableWindowMask)];
}
FixZoomButton();
}
bool NativeWindowMac::IsMinimizable() {
return [window_ styleMask] & NSMiniaturizableWindowMask;
}
void NativeWindowMac::SetClosable(bool closable) {
if (closable) {
[window_ setStyleMask:[window_ styleMask] | NSClosableWindowMask];
} else {
[window_ setStyleMask:[window_ styleMask] & (~NSClosableWindowMask)];
}
FixZoomButton();
}
bool NativeWindowMac::IsClosable() {
return [window_ styleMask] & NSClosableWindowMask;
}
void NativeWindowMac::SetAlwaysOnTop(bool top) { void NativeWindowMac::SetAlwaysOnTop(bool top) {
[window_ setLevel:(top ? NSFloatingWindowLevel : NSNormalWindowLevel)]; [window_ setLevel:(top ? NSFloatingWindowLevel : NSNormalWindowLevel)];
} }
void NativeWindowMac::FixZoomButton() {
// If fullscreen has not been disabled via `fullscreen: false` (i.e. when
// collectionBehavior has NSWindowCollectionBehaviorFullScreenPrimary mask),
// zoom button is reset to it's default (enabled) state when window's
// styleMask has been changed. So if the button was disabled, we have to
// disable it again. I think it's a bug in Cocoa.
if ([window_ collectionBehavior] & NSWindowCollectionBehaviorFullScreenPrimary
&& !([window_ styleMask] & NSResizableWindowMask)) {
[[window_ standardWindowButton:NSWindowZoomButton] setEnabled:NO];
}
}
bool NativeWindowMac::IsAlwaysOnTop() { bool NativeWindowMac::IsAlwaysOnTop() {
return [window_ level] == NSFloatingWindowLevel; return [window_ level] == NSFloatingWindowLevel;
} }

View file

@ -126,7 +126,10 @@ NativeWindowViews::NativeWindowViews(
menu_bar_alt_pressed_(false), menu_bar_alt_pressed_(false),
keyboard_event_handler_(new views::UnhandledKeyboardEventHandler), keyboard_event_handler_(new views::UnhandledKeyboardEventHandler),
use_content_size_(false), use_content_size_(false),
resizable_(true) { resizable_(true),
maximizable_(true),
movable_(true),
minimizable_(true) {
options.Get(options::kTitle, &title_); options.Get(options::kTitle, &title_);
options.Get(options::kAutoHideMenuBar, &menu_bar_autohide_); options.Get(options::kAutoHideMenuBar, &menu_bar_autohide_);
@ -134,6 +137,8 @@ NativeWindowViews::NativeWindowViews(
// On Windows we rely on the CanResize() to indicate whether window can be // On Windows we rely on the CanResize() to indicate whether window can be
// resized, and it should be set before window is created. // resized, and it should be set before window is created.
options.Get(options::kResizable, &resizable_); options.Get(options::kResizable, &resizable_);
options.Get(options::kMovable, &movable_);
options.Get(options::kMinimizable, &minimizable_);
#endif #endif
if (enable_larger_than_screen()) if (enable_larger_than_screen())
@ -182,7 +187,9 @@ NativeWindowViews::NativeWindowViews(
window_->Init(params); window_->Init(params);
bool fullscreen = false; bool fullscreen = false;
options.Get(options::kFullscreen, &fullscreen); if (options.Get(options::kFullscreen, &fullscreen) && !fullscreen) {
maximizable_ = false;
}
#if defined(USE_X11) #if defined(USE_X11)
// Start monitoring window states. // Start monitoring window states.
@ -236,22 +243,27 @@ NativeWindowViews::NativeWindowViews(
last_normal_size_ = gfx::Size(widget_size_); last_normal_size_ = gfx::Size(widget_size_);
if (!has_frame()) { DWORD style = ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE);
// Set Window style so that we get a minimize and maximize animation when style |= WS_THICKFRAME | WS_CAPTION | WS_MINIMIZEBOX;
// frameless. if (!maximizable_) {
DWORD frame_style = WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | style &= (~WS_MAXIMIZEBOX);
WS_CAPTION; } else {
// We should not show a frame for transparent window. style |= WS_MAXIMIZEBOX;
if (transparent())
frame_style &= ~(WS_THICKFRAME | WS_CAPTION);
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style);
} }
if (transparent()) { if (transparent()) {
// Transparent window on Windows has to have WS_EX_COMPOSITED style. DWORD ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
ex_style |= WS_EX_COMPOSITED; ex_style |= WS_EX_COMPOSITED;
::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style); ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
if (!has_frame()) {
// We should not show a frame for transparent window.
style &= ~(WS_THICKFRAME | WS_CAPTION);
}
}
if (!transparent() || !has_frame()) {
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, style);
} }
#endif #endif
@ -427,10 +439,12 @@ void NativeWindowViews::SetResizable(bool resizable) {
// WS_THICKFRAME => Resize handle // WS_THICKFRAME => Resize handle
if (!transparent()) { if (!transparent()) {
DWORD style = ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE); DWORD style = ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE);
if (resizable) if (resizable) {
style |= WS_MAXIMIZEBOX | WS_MINIMIZEBOX | WS_THICKFRAME; style |= WS_THICKFRAME;
else if (maximizable_) style |= WS_MAXIMIZEBOX;
style = (style & ~(WS_MAXIMIZEBOX | WS_THICKFRAME)) | WS_MINIMIZEBOX; } else {
style &= ~(WS_THICKFRAME | WS_MAXIMIZEBOX);
}
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, style); ::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, style);
} }
#elif defined(USE_X11) #elif defined(USE_X11)
@ -456,6 +470,64 @@ bool NativeWindowViews::IsResizable() {
return resizable_; return resizable_;
} }
void NativeWindowViews::SetMovable(bool movable) {
movable_ = movable;
}
bool NativeWindowViews::IsMovable() {
return movable_;
}
void NativeWindowViews::SetMinimizable(bool minimizable) {
#if defined(OS_WIN)
if (!transparent()) {
DWORD style = ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE);
if (minimizable)
style |= WS_MINIMIZEBOX;
else
style &= (~WS_MINIMIZEBOX);
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, style);
}
#endif
minimizable_ = minimizable;
}
bool NativeWindowViews::IsMinimizable() {
#if defined(OS_WIN)
return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_MINIMIZEBOX;
#elif defined(USE_X11)
return true;
#endif
}
void NativeWindowViews::SetClosable(bool closable) {
#if defined(OS_WIN)
HMENU menu = GetSystemMenu(GetAcceleratedWidget(), false);
if (closable) {
EnableMenuItem(menu, SC_CLOSE, MF_BYCOMMAND | MF_ENABLED);
} else {
EnableMenuItem(menu, SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
}
#endif
}
bool NativeWindowViews::IsClosable() {
#if defined(OS_WIN)
HMENU menu = GetSystemMenu(GetAcceleratedWidget(), false);
MENUITEMINFO info;
memset(&info, 0, sizeof(info));
info.cbSize = sizeof(info);
info.fMask = MIIM_STATE;
if (!GetMenuItemInfo(menu, SC_CLOSE, false, &info)) {
return false;
}
return !(info.fState & MFS_DISABLED);
#elif defined(USE_X11)
return true;
#endif
}
void NativeWindowViews::SetAlwaysOnTop(bool top) { void NativeWindowViews::SetAlwaysOnTop(bool top) {
window_->SetAlwaysOnTop(top); window_->SetAlwaysOnTop(top);
} }
@ -717,7 +789,11 @@ bool NativeWindowViews::CanMaximize() const {
} }
bool NativeWindowViews::CanMinimize() const { bool NativeWindowViews::CanMinimize() const {
#ifdef (OS_WIN)
return minimizable_;
#elif defined(USE_X11)
return true; return true;
#endif
} }
base::string16 NativeWindowViews::GetWindowTitle() const { base::string16 NativeWindowViews::GetWindowTitle() const {

View file

@ -68,6 +68,12 @@ class NativeWindowViews : public NativeWindow,
const extensions::SizeConstraints& size_constraints) override; const extensions::SizeConstraints& size_constraints) override;
void SetResizable(bool resizable) override; void SetResizable(bool resizable) override;
bool IsResizable() override; bool IsResizable() override;
void SetMovable(bool movable) override;
bool IsMovable() override;
void SetMinimizable(bool minimizable) override;
bool IsMinimizable() override;
void SetClosable(bool closable) override;
bool IsClosable() override;
void SetAlwaysOnTop(bool top) override; void SetAlwaysOnTop(bool top) override;
bool IsAlwaysOnTop() override; bool IsAlwaysOnTop() override;
void Center() override; void Center() override;
@ -197,6 +203,9 @@ class NativeWindowViews : public NativeWindow,
bool use_content_size_; bool use_content_size_;
bool resizable_; bool resizable_;
bool maximizable_;
bool movable_;
bool minimizable_;
std::string title_; std::string title_;
gfx::Size widget_size_; gfx::Size widget_size_;

View file

@ -89,10 +89,19 @@ bool NativeWindowViews::PreHandleMSG(
if (HIWORD(w_param) == THBN_CLICKED) if (HIWORD(w_param) == THBN_CLICKED)
return taskbar_host_.HandleThumbarButtonEvent(LOWORD(w_param)); return taskbar_host_.HandleThumbarButtonEvent(LOWORD(w_param));
return false; return false;
case WM_SIZE: case WM_SIZE:
// Handle window state change. // Handle window state change.
HandleSizeEvent(w_param, l_param); HandleSizeEvent(w_param, l_param);
return false; return false;
case WM_MOVING: {
if (!movable_) {
::GetWindowRect(GetAcceleratedWidget(), (LPRECT)l_param);
}
return false;
}
default: default:
return false; return false;
} }

View file

@ -8,22 +8,24 @@ namespace atom {
namespace options { namespace options {
const char kTitle[] = "title"; const char kTitle[] = "title";
const char kIcon[] = "icon"; const char kIcon[] = "icon";
const char kFrame[] = "frame"; const char kFrame[] = "frame";
const char kShow[] = "show"; const char kShow[] = "show";
const char kCenter[] = "center"; const char kCenter[] = "center";
const char kX[] = "x"; const char kX[] = "x";
const char kY[] = "y"; const char kY[] = "y";
const char kWidth[] = "width"; const char kWidth[] = "width";
const char kHeight[] = "height"; const char kHeight[] = "height";
const char kMinWidth[] = "minWidth"; const char kMinWidth[] = "minWidth";
const char kMinHeight[] = "minHeight"; const char kMinHeight[] = "minHeight";
const char kMaxWidth[] = "maxWidth"; const char kMaxWidth[] = "maxWidth";
const char kMaxHeight[] = "maxHeight"; const char kMaxHeight[] = "maxHeight";
const char kResizable[] = "resizable"; const char kResizable[] = "resizable";
const char kMovable[] = "movable"; const char kMovable[] = "movable";
const char kFullscreen[] = "fullscreen"; const char kMinimizable[] = "minimizable";
const char kClosable[] = "closable";
const char kFullscreen[] = "fullscreen";
// Whether the window should show in taskbar. // Whether the window should show in taskbar.
const char kSkipTaskbar[] = "skipTaskbar"; const char kSkipTaskbar[] = "skipTaskbar";

View file

@ -24,6 +24,8 @@ extern const char kMaxWidth[];
extern const char kMaxHeight[]; extern const char kMaxHeight[];
extern const char kResizable[]; extern const char kResizable[];
extern const char kMovable[]; extern const char kMovable[];
extern const char kMinimizable[];
extern const char kClosable[];
extern const char kFullscreen[]; extern const char kFullscreen[];
extern const char kSkipTaskbar[]; extern const char kSkipTaskbar[];
extern const char kKiosk[]; extern const char kKiosk[];