electron/shell/browser/native_window_views.cc

1482 lines
44 KiB
C++
Raw Normal View History

// 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 "shell/browser/native_window_views.h"
2017-09-12 15:56:49 +00:00
#if defined(OS_WIN)
#include <wrl/client.h>
2017-09-12 15:56:49 +00:00
#endif
#include <memory>
#include <tuple>
#include <utility>
#include <vector>
2015-02-11 01:14:26 +00:00
#include "base/numerics/ranges.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/desktop_media_id.h"
#include "shell/browser/api/electron_api_web_contents.h"
#include "shell/browser/native_browser_view_views.h"
#include "shell/browser/ui/inspectable_web_contents.h"
#include "shell/browser/ui/inspectable_web_contents_view.h"
#include "shell/browser/ui/views/root_view.h"
#include "shell/browser/web_contents_preferences.h"
#include "shell/browser/web_view_manager.h"
#include "shell/browser/window_list.h"
#include "shell/common/electron_constants.h"
#include "shell/common/gin_converters/image_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "shell/common/options_switches.h"
2014-07-21 14:03:58 +00:00
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
2015-02-07 01:00:26 +00:00
#include "ui/gfx/image/image.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/background.h"
#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
#include "ui/views/controls/webview/webview.h"
2014-12-16 01:28:51 +00:00
#include "ui/views/widget/native_widget_private.h"
#include "ui/views/widget/widget.h"
2016-08-26 22:30:02 +00:00
#include "ui/views/window/client_view.h"
2014-12-24 00:55:57 +00:00
#include "ui/wm/core/shadow_types.h"
2016-08-26 22:30:02 +00:00
#include "ui/wm/core/window_util.h"
#if defined(USE_X11)
2014-11-24 07:27:36 +00:00
#include "base/strings/string_util.h"
#include "shell/browser/browser.h"
#include "shell/browser/linux/unity_service.h"
#include "shell/browser/ui/views/frameless_view.h"
#include "shell/browser/ui/views/global_menu_bar_x11.h"
#include "shell/browser/ui/views/native_frame_view.h"
#include "shell/browser/ui/x/event_disabler.h"
#include "shell/browser/ui/x/window_state_watcher.h"
#include "shell/browser/ui/x/x_window_utils.h"
#include "ui/base/x/x11_util.h"
#include "ui/gfx/x/x11_types.h"
2016-05-20 13:22:15 +00:00
#include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
2014-07-24 10:06:27 +00:00
#include "ui/views/window/native_frame_view.h"
#elif defined(OS_WIN)
#include "shell/browser/ui/views/win_frame_view.h"
#include "shell/browser/ui/win/electron_desktop_native_widget_aura.h"
#include "skia/ext/skia_utils_win.h"
#include "ui/base/win/shell.h"
2016-07-21 17:20:43 +00:00
#include "ui/display/screen.h"
2016-08-26 22:30:02 +00:00
#include "ui/display/win/screen_win.h"
#include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
#endif
namespace electron {
namespace {
2016-01-23 10:23:18 +00:00
#if defined(OS_WIN)
const LPCWSTR kUniqueTaskBarClassName = L"Shell_TrayWnd";
2016-01-23 10:23:18 +00:00
void FlipWindowStyle(HWND handle, bool on, DWORD flag) {
DWORD style = ::GetWindowLong(handle, GWL_STYLE);
if (on)
style |= flag;
else
style &= ~flag;
::SetWindowLong(handle, GWL_STYLE, style);
}
// Similar to the ones in display::win::ScreenWin, but with rounded values
// These help to avoid problems that arise from unresizable windows where the
// original ceil()-ed values can cause calculation errors, since converting
// both ways goes through a ceil() call. Related issue: #15816
gfx::Rect ScreenToDIPRect(HWND hwnd, const gfx::Rect& pixel_bounds) {
float scale_factor = display::win::ScreenWin::GetScaleFactorForHWND(hwnd);
gfx::Rect dip_rect = ScaleToRoundedRect(pixel_bounds, 1.0f / scale_factor);
dip_rect.set_origin(
display::win::ScreenWin::ScreenToDIPRect(hwnd, pixel_bounds).origin());
return dip_rect;
}
gfx::Rect DIPToScreenRect(HWND hwnd, const gfx::Rect& pixel_bounds) {
float scale_factor = display::win::ScreenWin::GetScaleFactorForHWND(hwnd);
gfx::Rect screen_rect = ScaleToRoundedRect(pixel_bounds, scale_factor);
screen_rect.set_origin(
display::win::ScreenWin::DIPToScreenRect(hwnd, pixel_bounds).origin());
return screen_rect;
}
2016-01-23 10:23:18 +00:00
#endif
class NativeWindowClientView : public views::ClientView {
public:
NativeWindowClientView(views::Widget* widget,
views::View* root_view,
NativeWindowViews* window)
: views::ClientView(widget, root_view), window_(window) {}
~NativeWindowClientView() override = default;
2015-01-10 01:24:36 +00:00
bool CanClose() override {
window_->NotifyWindowCloseButtonClicked();
return false;
}
private:
NativeWindowViews* window_;
DISALLOW_COPY_AND_ASSIGN(NativeWindowClientView);
};
} // namespace
NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
2018-04-08 11:20:43 +00:00
NativeWindow* parent)
: NativeWindow(options, parent),
root_view_(new RootView(this)),
keyboard_event_handler_(new views::UnhandledKeyboardEventHandler) {
options.Get(options::kTitle, &title_);
bool menu_bar_autohide;
if (options.Get(options::kAutoHideMenuBar, &menu_bar_autohide))
root_view_->SetAutoHideMenuBar(menu_bar_autohide);
2014-08-26 05:37:37 +00:00
#if defined(OS_WIN)
// On Windows we rely on the CanResize() to indicate whether window can be
// resized, and it should be set before window is created.
options.Get(options::kResizable, &resizable_);
options.Get(options::kMinimizable, &minimizable_);
2016-01-22 21:24:33 +00:00
options.Get(options::kMaximizable, &maximizable_);
2016-07-09 12:49:15 +00:00
// Transparent window must not have thick frame.
options.Get("thickFrame", &thick_frame_);
if (transparent())
thick_frame_ = false;
2014-08-26 05:37:37 +00:00
#endif
if (enable_larger_than_screen())
// We need to set a default maximum window size here otherwise Windows
// will not allow us to resize the window larger than scree.
// Setting directly to INT_MAX somehow doesn't work, so we just devide
// by 10, which should still be large enough.
SetContentSizeConstraints(extensions::SizeConstraints(
gfx::Size(), gfx::Size(INT_MAX / 10, INT_MAX / 10)));
int width = 800, height = 600;
options.Get(options::kWidth, &width);
options.Get(options::kHeight, &height);
gfx::Rect bounds(0, 0, width, height);
2015-05-20 08:37:13 +00:00
widget_size_ = bounds.size();
widget()->AddObserver(this);
2014-07-08 04:55:33 +00:00
views::Widget::InitParams params;
params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
params.bounds = bounds;
params.delegate = this;
params.type = views::Widget::InitParams::TYPE_WINDOW;
params.remove_standard_frame = !has_frame();
2014-07-07 09:22:22 +00:00
if (transparent())
params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
2014-12-24 00:55:57 +00:00
2016-01-23 10:55:12 +00:00
// The given window is most likely not rectangular since it uses
// transparency and has no standard frame, don't show a shadow for it.
if (transparent() && !has_frame())
params.shadow_type = views::Widget::InitParams::ShadowType::kNone;
2016-01-23 10:55:12 +00:00
bool focusable;
if (options.Get(options::kFocusable, &focusable) && !focusable)
params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
#if defined(OS_WIN)
if (parent)
params.parent = parent->GetNativeWindow();
params.native_widget = new ElectronDesktopNativeWidgetAura(this);
2015-08-06 02:15:27 +00:00
#elif defined(USE_X11)
2014-11-24 07:27:36 +00:00
std::string name = Browser::Get()->GetName();
// Set WM_WINDOW_ROLE.
2014-11-24 07:27:36 +00:00
params.wm_role_name = "browser-window";
// Set WM_CLASS.
2015-12-07 11:56:23 +00:00
params.wm_class_name = base::ToLowerASCII(name);
2014-11-24 07:27:36 +00:00
params.wm_class_class = name;
2014-07-21 14:03:58 +00:00
#endif
2014-07-07 09:22:22 +00:00
widget()->Init(std::move(params));
bool fullscreen = false;
options.Get(options::kFullscreen, &fullscreen);
std::string window_type;
options.Get(options::kType, &window_type);
#if defined(USE_X11)
2014-11-25 03:46:30 +00:00
// Start monitoring window states.
window_state_watcher_ = std::make_unique<WindowStateWatcher>(this);
2014-11-25 03:46:30 +00:00
// Set _GTK_THEME_VARIANT to dark if we have "dark-theme" option set.
bool use_dark_theme = false;
if (options.Get(options::kDarkTheme, &use_dark_theme) && use_dark_theme) {
SetGTKDarkThemeEnabled(use_dark_theme);
}
// Before the window is mapped the SetWMSpecState can not work, so we have
// to manually set the _NET_WM_STATE.
std::vector<::Atom> state_atom_list;
bool skip_taskbar = false;
if (options.Get(options::kSkipTaskbar, &skip_taskbar) && skip_taskbar) {
state_atom_list.push_back(GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
}
// Before the window is mapped, there is no SHOW_FULLSCREEN_STATE.
if (fullscreen) {
state_atom_list.push_back(GetAtom("_NET_WM_STATE_FULLSCREEN"));
}
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"));
}
if (!state_atom_list.empty())
ui::SetAtomArrayProperty(GetAcceleratedWidget(), "_NET_WM_STATE", "ATOM",
state_atom_list);
// Set the _NET_WM_WINDOW_TYPE.
if (!window_type.empty())
SetWindowType(GetAcceleratedWidget(), window_type);
#endif
2014-11-07 18:34:52 +00:00
#if defined(OS_WIN)
2016-01-23 10:23:18 +00:00
if (!has_frame()) {
// Set Window style so that we get a minimize and maximize animation when
// frameless.
DWORD frame_style = WS_CAPTION | WS_OVERLAPPED;
2016-01-23 10:23:18 +00:00
if (resizable_)
frame_style |= WS_THICKFRAME;
if (minimizable_)
frame_style |= WS_MINIMIZEBOX;
if (maximizable_)
frame_style |= WS_MAXIMIZEBOX;
// We should not show a frame for transparent window.
2016-07-09 12:49:15 +00:00
if (!thick_frame_)
2016-01-23 10:23:18 +00:00
frame_style &= ~(WS_THICKFRAME | WS_CAPTION);
::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style);
}
2014-12-24 00:55:57 +00:00
LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
if (window_type == "toolbar")
ex_style |= WS_EX_TOOLWINDOW;
::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
2014-11-07 18:34:52 +00:00
#endif
if (has_frame()) {
// TODO(zcbenz): This was used to force using native frame on Windows 2003,
// we should check whether setting it in InitParams can work.
widget()->set_frame_type(views::Widget::FrameType::kForceNative);
widget()->FrameTypeChanged();
2017-08-21 08:42:45 +00:00
#if defined(OS_WIN)
// thickFrame also works for normal window.
if (!thick_frame_)
FlipWindowStyle(GetAcceleratedWidget(), false, WS_THICKFRAME);
2017-08-21 08:42:45 +00:00
#endif
}
// Default content view.
SetContentView(new views::View());
gfx::Size size = bounds.size();
if (has_frame() &&
options.Get(options::kUseContentSize, &use_content_size_) &&
use_content_size_)
size = ContentBoundsToWindowBounds(gfx::Rect(size)).size();
widget()->CenterWindow(size);
2016-07-09 14:10:36 +00:00
#if defined(OS_WIN)
// Save initial window state.
if (fullscreen)
last_window_state_ = ui::SHOW_STATE_FULLSCREEN;
else
last_window_state_ = ui::SHOW_STATE_NORMAL;
#endif
#if defined(OS_LINUX)
// Listen to move events.
aura::Window* window = GetNativeWindow();
if (window)
window->AddPreTargetHandler(this);
#endif
}
NativeWindowViews::~NativeWindowViews() {
widget()->RemoveObserver(this);
#if defined(OS_WIN)
// Disable mouse forwarding to relinquish resources, should any be held.
SetForwardMouseMessages(false);
#endif
#if defined(OS_LINUX)
aura::Window* window = GetNativeWindow();
if (window)
window->RemovePreTargetHandler(this);
#endif
}
void NativeWindowViews::SetGTKDarkThemeEnabled(bool use_dark_theme) {
#if defined(USE_X11)
XDisplay* xdisplay = gfx::GetXDisplay();
if (use_dark_theme) {
XChangeProperty(xdisplay, GetAcceleratedWidget(),
XInternAtom(xdisplay, "_GTK_THEME_VARIANT", x11::False),
XInternAtom(xdisplay, "UTF8_STRING", x11::False), 8,
PropModeReplace,
reinterpret_cast<const unsigned char*>("dark"), 4);
} else {
XChangeProperty(xdisplay, GetAcceleratedWidget(),
XInternAtom(xdisplay, "_GTK_THEME_VARIANT", x11::False),
XInternAtom(xdisplay, "UTF8_STRING", x11::False), 8,
PropModeReplace,
reinterpret_cast<const unsigned char*>("light"), 5);
}
#endif
}
void NativeWindowViews::SetContentView(views::View* view) {
if (content_view()) {
root_view_->RemoveChildView(content_view());
2018-04-08 11:20:43 +00:00
}
set_content_view(view);
focused_view_ = view;
root_view_->AddChildView(content_view());
root_view_->Layout();
2018-04-08 11:20:43 +00:00
}
void NativeWindowViews::Close() {
if (!IsClosable()) {
WindowList::WindowCloseCancelled(this);
return;
}
widget()->Close();
}
void NativeWindowViews::CloseImmediately() {
widget()->CloseNow();
}
void NativeWindowViews::Focus(bool focus) {
// For hidden window focus() should do nothing.
if (!IsVisible())
return;
if (focus) {
widget()->Activate();
} else {
widget()->Deactivate();
}
}
bool NativeWindowViews::IsFocused() {
return widget()->IsActive();
}
void NativeWindowViews::Show() {
if (is_modal() && NativeWindow::parent() &&
!widget()->native_widget_private()->IsVisible())
static_cast<NativeWindowViews*>(parent())->IncrementChildModals();
widget()->native_widget_private()->Show(GetRestoredState(), gfx::Rect());
// explicitly focus the window
widget()->Activate();
NotifyWindowShow();
#if defined(USE_X11)
if (global_menu_bar_)
global_menu_bar_->OnWindowMapped();
#endif
2014-10-17 14:51:20 +00:00
}
void NativeWindowViews::ShowInactive() {
widget()->ShowInactive();
NotifyWindowShow();
#if defined(USE_X11)
if (global_menu_bar_)
global_menu_bar_->OnWindowMapped();
#endif
}
void NativeWindowViews::Hide() {
if (is_modal() && NativeWindow::parent())
static_cast<NativeWindowViews*>(parent())->DecrementChildModals();
widget()->Hide();
NotifyWindowHide();
#if defined(USE_X11)
if (global_menu_bar_)
global_menu_bar_->OnWindowUnmapped();
#endif
}
bool NativeWindowViews::IsVisible() {
return widget()->IsVisible();
}
bool NativeWindowViews::IsEnabled() {
#if defined(OS_WIN)
return ::IsWindowEnabled(GetAcceleratedWidget());
#elif defined(USE_X11)
return !event_disabler_.get();
#endif
}
void NativeWindowViews::IncrementChildModals() {
num_modal_children_++;
SetEnabledInternal(ShouldBeEnabled());
}
void NativeWindowViews::DecrementChildModals() {
if (num_modal_children_ > 0) {
num_modal_children_--;
}
SetEnabledInternal(ShouldBeEnabled());
}
2018-04-08 11:20:43 +00:00
void NativeWindowViews::SetEnabled(bool enable) {
if (enable != is_enabled_) {
is_enabled_ = enable;
SetEnabledInternal(ShouldBeEnabled());
}
}
bool NativeWindowViews::ShouldBeEnabled() {
return is_enabled_ && (num_modal_children_ == 0);
}
void NativeWindowViews::SetEnabledInternal(bool enable) {
if (enable && IsEnabled()) {
return;
} else if (!enable && !IsEnabled()) {
return;
2018-04-08 11:20:43 +00:00
}
#if defined(OS_WIN)
::EnableWindow(GetAcceleratedWidget(), enable);
#elif defined(USE_X11)
views::DesktopWindowTreeHostLinux* tree_host =
views::DesktopWindowTreeHostLinux::GetHostForWidget(
GetAcceleratedWidget());
2018-04-08 11:20:43 +00:00
if (enable) {
tree_host->RemoveEventRewriter(event_disabler_.get());
event_disabler_.reset();
} else {
event_disabler_ = std::make_unique<EventDisabler>();
2018-04-08 11:20:43 +00:00
tree_host->AddEventRewriter(event_disabler_.get());
}
#endif
}
#if defined(USE_X11)
void NativeWindowViews::Maximize() {
if (IsVisible())
widget()->Maximize();
else
widget()->native_widget_private()->Show(ui::SHOW_STATE_MAXIMIZED,
gfx::Rect());
}
#endif
void NativeWindowViews::Unmaximize() {
2016-07-09 14:04:42 +00:00
#if defined(OS_WIN)
2016-12-15 06:01:03 +00:00
if (!(::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME)) {
2016-07-09 14:16:57 +00:00
SetBounds(restore_bounds_, false);
2016-07-09 14:04:42 +00:00
return;
}
#endif
widget()->Restore();
}
bool NativeWindowViews::IsMaximized() {
return widget()->IsMaximized();
}
void NativeWindowViews::Minimize() {
if (IsVisible())
widget()->Minimize();
else
widget()->native_widget_private()->Show(ui::SHOW_STATE_MINIMIZED,
gfx::Rect());
}
void NativeWindowViews::Restore() {
widget()->Restore();
}
2014-07-26 05:58:26 +00:00
bool NativeWindowViews::IsMinimized() {
return widget()->IsMinimized();
2014-07-26 05:58:26 +00:00
}
2014-11-25 06:34:14 +00:00
void NativeWindowViews::SetFullScreen(bool fullscreen) {
if (!IsFullScreenable())
return;
2014-11-25 06:28:34 +00:00
#if defined(OS_WIN)
// There is no native fullscreen state on Windows.
2017-06-14 00:47:15 +00:00
bool leaving_fullscreen = IsFullscreen() && !fullscreen;
if (fullscreen) {
last_window_state_ = ui::SHOW_STATE_FULLSCREEN;
NotifyWindowEnterFullScreen();
} else {
last_window_state_ = ui::SHOW_STATE_NORMAL;
2014-11-25 06:28:34 +00:00
NotifyWindowLeaveFullScreen();
}
2017-01-18 22:40:42 +00:00
// For window without WS_THICKFRAME style, we can not call SetFullscreen().
// This path will be used for transparent windows as well.
if (!thick_frame_) {
if (fullscreen) {
restore_bounds_ = GetBounds();
auto display =
display::Screen::GetScreen()->GetDisplayNearestPoint(GetPosition());
SetBounds(display.bounds(), false);
} else {
SetBounds(restore_bounds_, false);
}
return;
}
// We set the new value after notifying, so we can handle the size event
// correctly.
widget()->SetFullscreen(fullscreen);
// If restoring from fullscreen and the window isn't visible, force visible,
// else a non-responsive window shell could be rendered.
// (this situation may arise when app starts with fullscreen: true)
// Note: the following must be after "widget()->SetFullscreen(fullscreen);"
2017-06-14 00:55:55 +00:00
if (leaving_fullscreen && !IsVisible())
2017-06-14 00:47:15 +00:00
FlipWindowStyle(GetAcceleratedWidget(), true, WS_VISIBLE);
#else
if (IsVisible())
widget()->SetFullscreen(fullscreen);
else if (fullscreen)
widget()->native_widget_private()->Show(ui::SHOW_STATE_FULLSCREEN,
gfx::Rect());
2016-07-11 04:10:19 +00:00
// Auto-hide menubar when in fullscreen.
if (fullscreen)
SetMenuBarVisibility(false);
else
SetMenuBarVisibility(!IsMenuBarAutoHide());
2014-11-25 06:28:34 +00:00
#endif
}
2015-04-21 13:35:36 +00:00
bool NativeWindowViews::IsFullscreen() const {
return widget()->IsFullscreen();
}
void NativeWindowViews::SetBounds(const gfx::Rect& bounds, bool animate) {
#if defined(OS_WIN) || defined(USE_X11)
// On Linux and Windows the minimum and maximum size should be updated with
// window size when window is not resizable.
if (!resizable_) {
SetMaximumSize(bounds.size());
SetMinimumSize(bounds.size());
}
#endif
widget()->SetBounds(bounds);
}
gfx::Rect NativeWindowViews::GetBounds() {
#if defined(OS_WIN)
if (IsMinimized())
return widget()->GetRestoredBounds();
#endif
return widget()->GetWindowBoundsInScreen();
}
2016-07-29 01:19:17 +00:00
gfx::Rect NativeWindowViews::GetContentBounds() {
return content_view() ? content_view()->GetBoundsInScreen() : gfx::Rect();
2016-07-29 01:19:17 +00:00
}
gfx::Size NativeWindowViews::GetContentSize() {
#if defined(OS_WIN)
if (IsMinimized())
return NativeWindow::GetContentSize();
#endif
return content_view() ? content_view()->size() : gfx::Size();
}
gfx::Rect NativeWindowViews::GetNormalBounds() {
return widget()->GetRestoredBounds();
}
void NativeWindowViews::SetContentSizeConstraints(
const extensions::SizeConstraints& size_constraints) {
NativeWindow::SetContentSizeConstraints(size_constraints);
2017-08-21 08:42:45 +00:00
#if defined(OS_WIN)
// Changing size constraints would force adding the WS_THICKFRAME style, so
// do nothing if thickFrame is false.
2017-08-21 08:42:45 +00:00
if (!thick_frame_)
return;
#endif
// widget_delegate() is only available after Init() is called, we make use of
// this to determine whether native widget has initialized.
if (widget() && widget()->widget_delegate())
widget()->OnSizeConstraintsChanged();
if (resizable_)
old_size_constraints_ = size_constraints;
}
void NativeWindowViews::SetResizable(bool resizable) {
2014-08-26 05:37:37 +00:00
if (resizable != resizable_) {
// On Linux there is no "resizable" property of a window, we have to set
// both the minimum and maximum size to the window size to achieve it.
if (resizable) {
SetContentSizeConstraints(old_size_constraints_);
SetMaximizable(maximizable_);
2014-08-26 05:37:37 +00:00
} else {
old_size_constraints_ = GetContentSizeConstraints();
resizable_ = false;
gfx::Size content_size = GetContentSize();
SetContentSizeConstraints(
extensions::SizeConstraints(content_size, content_size));
2014-08-26 05:37:37 +00:00
}
}
#if defined(OS_WIN)
if (has_frame() && thick_frame_)
FlipWindowStyle(GetAcceleratedWidget(), resizable, WS_THICKFRAME);
#endif
2014-08-26 05:37:37 +00:00
resizable_ = resizable;
}
bool NativeWindowViews::MoveAbove(const std::string& sourceId) {
const content::DesktopMediaID id = content::DesktopMediaID::Parse(sourceId);
if (id.type != content::DesktopMediaID::TYPE_WINDOW)
return false;
#if defined(OS_WIN)
const HWND otherWindow = reinterpret_cast<HWND>(id.id);
if (!::IsWindow(otherWindow))
return false;
gfx::Point pos = GetPosition();
gfx::Size size = GetSize();
::SetWindowPos(GetAcceleratedWidget(), otherWindow, pos.x(), pos.y(),
size.width(), size.height(),
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
#elif defined(USE_X11)
if (!IsWindowValid(id.id))
return false;
electron::MoveWindowAbove(GetAcceleratedWidget(), id.id);
#endif
return true;
}
void NativeWindowViews::MoveTop() {
// TODO(julien.isorce): fix chromium in order to use existing
// widget()->StackAtTop().
#if defined(OS_WIN)
gfx::Point pos = GetPosition();
gfx::Size size = GetSize();
2018-04-18 01:55:30 +00:00
::SetWindowPos(GetAcceleratedWidget(), HWND_TOP, pos.x(), pos.y(),
size.width(), size.height(),
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
#elif defined(USE_X11)
electron::MoveWindowToForeground(GetAcceleratedWidget());
#endif
}
bool NativeWindowViews::IsResizable() {
2016-01-23 12:03:56 +00:00
#if defined(OS_WIN)
2016-11-15 05:23:59 +00:00
if (has_frame())
2016-07-09 12:49:15 +00:00
return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME;
2016-01-23 12:03:56 +00:00
#endif
2018-04-25 07:25:55 +00:00
return CanResize();
}
void NativeWindowViews::SetAspectRatio(double aspect_ratio,
const gfx::Size& extra_size) {
NativeWindow::SetAspectRatio(aspect_ratio, extra_size);
#if defined(OS_LINUX)
gfx::SizeF aspect(aspect_ratio, 1.0);
// Scale up because SetAspectRatio() truncates aspect value to int
aspect.Scale(100);
widget()->SetAspectRatio(aspect);
#endif
}
void NativeWindowViews::SetMovable(bool movable) {
movable_ = movable;
}
bool NativeWindowViews::IsMovable() {
2016-01-19 15:43:52 +00:00
#if defined(OS_WIN)
return movable_;
2016-01-23 10:23:18 +00:00
#else
return true; // Not implemented on Linux.
2016-01-19 15:43:52 +00:00
#endif
}
void NativeWindowViews::SetMinimizable(bool minimizable) {
#if defined(OS_WIN)
2016-01-23 10:23:18 +00:00
FlipWindowStyle(GetAcceleratedWidget(), minimizable, WS_MINIMIZEBOX);
#endif
minimizable_ = minimizable;
}
bool NativeWindowViews::IsMinimizable() {
#if defined(OS_WIN)
2016-01-23 11:35:30 +00:00
return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_MINIMIZEBOX;
2016-01-23 10:23:18 +00:00
#else
2016-01-23 11:35:30 +00:00
return true; // Not implemented on Linux.
#endif
}
2016-01-22 21:24:33 +00:00
void NativeWindowViews::SetMaximizable(bool maximizable) {
#if defined(OS_WIN)
2016-01-23 10:23:18 +00:00
FlipWindowStyle(GetAcceleratedWidget(), maximizable, WS_MAXIMIZEBOX);
2016-01-22 21:24:33 +00:00
#endif
2016-01-23 10:23:18 +00:00
maximizable_ = maximizable;
2016-01-22 21:24:33 +00:00
}
bool NativeWindowViews::IsMaximizable() {
#if defined(OS_WIN)
2016-01-23 11:35:30 +00:00
return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_MAXIMIZEBOX;
2016-01-23 10:23:18 +00:00
#else
2016-01-23 11:35:30 +00:00
return true; // Not implemented on Linux.
2016-01-22 21:24:33 +00:00
#endif
}
void NativeWindowViews::SetExcludedFromShownWindowsMenu(bool excluded) {}
bool NativeWindowViews::IsExcludedFromShownWindowsMenu() {
// return false on unsupported platforms
return false;
}
void NativeWindowViews::SetFullScreenable(bool fullscreenable) {
fullscreenable_ = fullscreenable;
2016-01-22 21:24:33 +00:00
}
2016-01-23 07:47:37 +00:00
bool NativeWindowViews::IsFullScreenable() {
return fullscreenable_;
2016-01-22 21:24:33 +00:00
}
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(ui::ZOrderLevel z_order,
2018-04-18 01:55:30 +00:00
const std::string& level,
int relativeLevel) {
bool level_changed = z_order != widget()->GetZOrderLevel();
widget()->SetZOrderLevel(z_order);
#if defined(OS_WIN)
// Reset the placement flag.
behind_task_bar_ = false;
if (z_order != ui::ZOrderLevel::kNormal) {
// On macOS the window is placed behind the Dock for the following levels.
// Re-use the same names on Windows to make it easier for the user.
static const std::vector<std::string> levels = {
"floating", "torn-off-menu", "modal-panel", "main-menu", "status"};
behind_task_bar_ = base::Contains(levels, level);
}
#endif
MoveBehindTaskBarIfNeeded();
// This must be notified at the very end or IsAlwaysOnTop
// will not yet have been updated to reflect the new status
if (level_changed)
NativeWindow::NotifyWindowAlwaysOnTopChanged();
}
ui::ZOrderLevel NativeWindowViews::GetZOrderLevel() {
return widget()->GetZOrderLevel();
}
void NativeWindowViews::Center() {
widget()->CenterWindow(GetSize());
}
void NativeWindowViews::Invalidate() {
widget()->SchedulePaintInRect(gfx::Rect(GetBounds().size()));
}
void NativeWindowViews::SetTitle(const std::string& title) {
title_ = title;
widget()->UpdateWindowTitle();
}
std::string NativeWindowViews::GetTitle() {
return title_;
}
void NativeWindowViews::FlashFrame(bool flash) {
#if defined(OS_WIN)
// The Chromium's implementation has a bug stopping flash.
if (!flash) {
FLASHWINFO fwi;
fwi.cbSize = sizeof(fwi);
fwi.hwnd = GetAcceleratedWidget();
fwi.dwFlags = FLASHW_STOP;
fwi.uCount = 0;
FlashWindowEx(&fwi);
return;
}
#endif
widget()->FlashFrame(flash);
}
void NativeWindowViews::SetSkipTaskbar(bool skip) {
2014-07-07 09:22:22 +00:00
#if defined(OS_WIN)
Microsoft::WRL::ComPtr<ITaskbarList> taskbar;
if (FAILED(::CoCreateInstance(CLSID_TaskbarList, nullptr,
CLSCTX_INPROC_SERVER,
IID_PPV_ARGS(&taskbar))) ||
2014-07-21 14:03:58 +00:00
FAILED(taskbar->HrInit()))
return;
if (skip) {
2014-07-21 14:03:58 +00:00
taskbar->DeleteTab(GetAcceleratedWidget());
} else {
2014-07-21 14:03:58 +00:00
taskbar->AddTab(GetAcceleratedWidget());
taskbar_host_.RestoreThumbarButtons(GetAcceleratedWidget());
}
#elif defined(USE_X11)
SetWMSpecState(GetAcceleratedWidget(), skip,
GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
2014-07-07 09:22:22 +00:00
#endif
}
void NativeWindowViews::SetSimpleFullScreen(bool simple_fullscreen) {
SetFullScreen(simple_fullscreen);
}
bool NativeWindowViews::IsSimpleFullScreen() {
return IsFullscreen();
}
void NativeWindowViews::SetKiosk(bool kiosk) {
2014-11-25 06:34:14 +00:00
SetFullScreen(kiosk);
}
bool NativeWindowViews::IsKiosk() {
return IsFullscreen();
}
SkColor NativeWindowViews::GetBackgroundColor() {
return root_view_->background()->get_color();
}
void NativeWindowViews::SetBackgroundColor(SkColor background_color) {
2015-10-23 03:35:33 +00:00
// web views' background color.
root_view_->SetBackground(views::CreateSolidBackground(background_color));
2015-10-23 03:35:33 +00:00
#if defined(OS_WIN)
// Set the background color of native window.
HBRUSH brush = CreateSolidBrush(skia::SkColorToCOLORREF(background_color));
2018-04-18 01:55:30 +00:00
ULONG_PTR previous_brush =
SetClassLongPtr(GetAcceleratedWidget(), GCLP_HBRBACKGROUND,
reinterpret_cast<LONG_PTR>(brush));
2015-10-23 03:35:33 +00:00
if (previous_brush)
DeleteObject((HBRUSH)previous_brush);
InvalidateRect(GetAcceleratedWidget(), NULL, 1);
2015-10-23 03:35:33 +00:00
#endif
}
2016-01-23 10:55:12 +00:00
void NativeWindowViews::SetHasShadow(bool has_shadow) {
wm::SetShadowElevation(GetNativeWindow(),
has_shadow ? wm::kShadowElevationInactiveWindow
: wm::kShadowElevationNone);
2016-01-23 10:55:12 +00:00
}
bool NativeWindowViews::HasShadow() {
2018-04-18 01:55:30 +00:00
return GetNativeWindow()->GetProperty(wm::kShadowElevationKey) !=
wm::kShadowElevationNone;
2016-01-23 10:55:12 +00:00
}
2017-09-29 02:26:02 +00:00
void NativeWindowViews::SetOpacity(const double opacity) {
#if defined(OS_WIN)
const double boundedOpacity = base::ClampToRange(opacity, 0.0, 1.0);
2017-10-02 00:52:27 +00:00
HWND hwnd = GetAcceleratedWidget();
2017-09-29 02:26:02 +00:00
if (!layered_) {
2017-10-02 00:52:27 +00:00
LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
2017-09-29 02:26:02 +00:00
ex_style |= WS_EX_LAYERED;
2017-10-02 00:52:27 +00:00
::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
2017-09-29 02:26:02 +00:00
layered_ = true;
}
::SetLayeredWindowAttributes(hwnd, 0, boundedOpacity * 255, LWA_ALPHA);
opacity_ = boundedOpacity;
#else
opacity_ = 1.0; // setOpacity unsupported on Linux
2017-09-29 02:26:02 +00:00
#endif
}
double NativeWindowViews::GetOpacity() {
return opacity_;
2017-09-29 02:26:02 +00:00
}
void NativeWindowViews::SetIgnoreMouseEvents(bool ignore, bool forward) {
#if defined(OS_WIN)
LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
if (ignore)
ex_style |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
else
ex_style &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED);
2017-09-29 02:26:02 +00:00
if (layered_)
ex_style |= WS_EX_LAYERED;
::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
// Forwarding is always disabled when not ignoring mouse messages.
if (!ignore) {
SetForwardMouseMessages(false);
} else {
SetForwardMouseMessages(forward);
}
#elif defined(USE_X11)
if (ignore) {
XRectangle r = {0, 0, 1, 1};
XShapeCombineRectangles(gfx::GetXDisplay(), GetAcceleratedWidget(),
ShapeInput, 0, 0, &r, 1, ShapeSet, YXBanded);
} else {
2018-04-18 01:55:30 +00:00
XShapeCombineMask(gfx::GetXDisplay(), GetAcceleratedWidget(), ShapeInput, 0,
0, x11::None, ShapeSet);
}
#endif
}
void NativeWindowViews::SetContentProtection(bool enable) {
#if defined(OS_WIN)
DWORD affinity = enable ? WDA_MONITOR : WDA_NONE;
::SetWindowDisplayAffinity(GetAcceleratedWidget(), affinity);
#endif
}
2016-06-13 08:10:28 +00:00
void NativeWindowViews::SetFocusable(bool focusable) {
widget()->widget_delegate()->SetCanActivate(focusable);
#if defined(OS_WIN)
LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
2016-06-13 08:10:28 +00:00
if (focusable)
ex_style &= ~WS_EX_NOACTIVATE;
else
ex_style |= WS_EX_NOACTIVATE;
::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
SetSkipTaskbar(!focusable);
Focus(false);
#endif
}
void NativeWindowViews::SetMenu(ElectronMenuModel* menu_model) {
2015-06-04 08:10:19 +00:00
#if defined(USE_X11)
// Remove global menu bar.
if (global_menu_bar_ && menu_model == nullptr) {
2015-06-04 08:10:19 +00:00
global_menu_bar_.reset();
root_view_->UnregisterAcceleratorsWithFocusManager();
return;
}
2014-07-16 14:10:10 +00:00
// Use global application menu bar when possible.
if (ShouldUseGlobalMenuBar()) {
if (!global_menu_bar_)
global_menu_bar_ = std::make_unique<GlobalMenuBarX11>(this);
if (global_menu_bar_->IsServerStarted()) {
root_view_->RegisterAcceleratorsWithFocusManager(menu_model);
global_menu_bar_->SetMenu(menu_model);
return;
}
2014-07-16 14:10:10 +00:00
}
#endif
2014-07-16 14:10:10 +00:00
// Should reset content size when setting menu.
gfx::Size content_size = GetContentSize();
bool should_reset_size = use_content_size_ && has_frame() &&
!IsMenuBarAutoHide() &&
((!!menu_model) != root_view_->HasMenu());
root_view_->SetMenu(menu_model);
if (should_reset_size) {
// Enlarge the size constraints for the menu.
int menu_bar_height = root_view_->GetMenuBarHeight();
extensions::SizeConstraints constraints = GetContentSizeConstraints();
if (constraints.HasMinimumSize()) {
gfx::Size min_size = constraints.GetMinimumSize();
min_size.set_height(min_size.height() + menu_bar_height);
constraints.set_minimum_size(min_size);
}
if (constraints.HasMaximumSize()) {
gfx::Size max_size = constraints.GetMaximumSize();
max_size.set_height(max_size.height() + menu_bar_height);
constraints.set_maximum_size(max_size);
}
SetContentSizeConstraints(constraints);
2014-07-17 06:23:28 +00:00
// Resize the window to make sure content size is not changed.
SetContentSize(content_size);
}
2014-07-04 08:54:10 +00:00
}
void NativeWindowViews::AddBrowserView(NativeBrowserView* view) {
if (!content_view())
2018-04-08 11:20:43 +00:00
return;
if (!view) {
return;
Implement initial, experimental BrowserView API Right now, `<webview>` is the only way to embed additional content in a `BrowserWindow`. Unfortunately `<webview>` suffers from a [number of problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20). To make matters worse, many of these are upstream Chromium bugs instead of Electron-specific bugs. For us at [Figma](https://www.figma.com), the main issue is very slow performance. Despite the upstream improvements to `<webview>` through the OOPIF work, it is probable that there will continue to be `<webview>`-specific bugs in the future. Therefore, this introduces a `<webview>` alternative to called `BrowserView`, which... - is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will likely also be bugs in `BrowserWindow` web contents) - is instantiated in the main process like `BrowserWindow` (and unlike `<webview>`, which lives in the DOM of a `BrowserWindow` web contents) - needs to be added to a `BrowserWindow` to display something on the screen This implements the most basic API. The API is expected to evolve and change in the near future and has consequently been marked as experimental. Please do not use this API in production unless you are prepared to deal with breaking changes. In the future, we will want to change the API to support multiple `BrowserView`s per window. We will also want to consider z-ordering auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
}
add_browser_view(view);
content_view()->AddChildView(
view->GetInspectableWebContentsView()->GetView());
}
void NativeWindowViews::RemoveBrowserView(NativeBrowserView* view) {
if (!content_view())
return;
if (!view) {
Implement initial, experimental BrowserView API Right now, `<webview>` is the only way to embed additional content in a `BrowserWindow`. Unfortunately `<webview>` suffers from a [number of problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20). To make matters worse, many of these are upstream Chromium bugs instead of Electron-specific bugs. For us at [Figma](https://www.figma.com), the main issue is very slow performance. Despite the upstream improvements to `<webview>` through the OOPIF work, it is probable that there will continue to be `<webview>`-specific bugs in the future. Therefore, this introduces a `<webview>` alternative to called `BrowserView`, which... - is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will likely also be bugs in `BrowserWindow` web contents) - is instantiated in the main process like `BrowserWindow` (and unlike `<webview>`, which lives in the DOM of a `BrowserWindow` web contents) - needs to be added to a `BrowserWindow` to display something on the screen This implements the most basic API. The API is expected to evolve and change in the near future and has consequently been marked as experimental. Please do not use this API in production unless you are prepared to deal with breaking changes. In the future, we will want to change the API to support multiple `BrowserView`s per window. We will also want to consider z-ordering auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
return;
}
content_view()->RemoveChildView(
view->GetInspectableWebContentsView()->GetView());
remove_browser_view(view);
Implement initial, experimental BrowserView API Right now, `<webview>` is the only way to embed additional content in a `BrowserWindow`. Unfortunately `<webview>` suffers from a [number of problems](https://github.com/electron/electron/issues?utf8=%E2%9C%93&q=is%3Aissue%20is%3Aopen%20label%3Awebview%20). To make matters worse, many of these are upstream Chromium bugs instead of Electron-specific bugs. For us at [Figma](https://www.figma.com), the main issue is very slow performance. Despite the upstream improvements to `<webview>` through the OOPIF work, it is probable that there will continue to be `<webview>`-specific bugs in the future. Therefore, this introduces a `<webview>` alternative to called `BrowserView`, which... - is a thin wrapper around `api::WebContents` (so bugs in `BrowserView` will likely also be bugs in `BrowserWindow` web contents) - is instantiated in the main process like `BrowserWindow` (and unlike `<webview>`, which lives in the DOM of a `BrowserWindow` web contents) - needs to be added to a `BrowserWindow` to display something on the screen This implements the most basic API. The API is expected to evolve and change in the near future and has consequently been marked as experimental. Please do not use this API in production unless you are prepared to deal with breaking changes. In the future, we will want to change the API to support multiple `BrowserView`s per window. We will also want to consider z-ordering auto-resizing, and possibly even nested views.
2017-04-11 17:47:30 +00:00
}
void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
NativeWindow::SetParentWindow(parent);
#if defined(USE_X11)
XDisplay* xdisplay = gfx::GetXDisplay();
XSetTransientForHint(
xdisplay, GetAcceleratedWidget(),
2018-04-18 01:55:30 +00:00
parent ? parent->GetAcceleratedWidget() : DefaultRootWindow(xdisplay));
#elif defined(OS_WIN)
// To set parentship between windows into Windows is better to play with the
// owner instead of the parent, as Windows natively seems to do if a parent
// is specified at window creation time.
// For do this we must NOT use the ::SetParent function, instead we must use
// the ::GetWindowLongPtr or ::SetWindowLongPtr functions with "nIndex" set
// to "GWLP_HWNDPARENT" which actually means the window owner.
HWND hwndParent = parent ? parent->GetAcceleratedWidget() : NULL;
if (hwndParent ==
(HWND)::GetWindowLongPtr(GetAcceleratedWidget(), GWLP_HWNDPARENT))
return;
::SetWindowLongPtr(GetAcceleratedWidget(), GWLP_HWNDPARENT,
(LONG_PTR)hwndParent);
// Ensures the visibility
if (IsVisible()) {
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
::GetWindowPlacement(GetAcceleratedWidget(), &wp);
::ShowWindow(GetAcceleratedWidget(), SW_HIDE);
::ShowWindow(GetAcceleratedWidget(), wp.showCmd);
::BringWindowToTop(GetAcceleratedWidget());
}
#endif
}
2017-05-21 18:57:19 +00:00
gfx::NativeView NativeWindowViews::GetNativeView() const {
return widget()->GetNativeView();
}
2017-05-21 18:57:19 +00:00
gfx::NativeWindow NativeWindowViews::GetNativeWindow() const {
return widget()->GetNativeWindow();
}
2018-04-18 01:55:30 +00:00
void NativeWindowViews::SetProgressBar(double progress,
NativeWindow::ProgressState state) {
2014-09-17 01:42:47 +00:00
#if defined(OS_WIN)
taskbar_host_.SetProgressBar(GetAcceleratedWidget(), progress, state);
2014-09-18 11:12:24 +00:00
#elif defined(USE_X11)
if (unity::IsRunning()) {
unity::SetProgressFraction(progress);
}
2014-09-17 01:42:47 +00:00
#endif
}
2015-02-11 01:14:26 +00:00
void NativeWindowViews::SetOverlayIcon(const gfx::Image& overlay,
const std::string& description) {
#if defined(OS_WIN)
2015-08-06 05:07:00 +00:00
taskbar_host_.SetOverlayIcon(GetAcceleratedWidget(), overlay, description);
#endif
}
2014-11-12 12:32:14 +00:00
void NativeWindowViews::SetAutoHideMenuBar(bool auto_hide) {
root_view_->SetAutoHideMenuBar(auto_hide);
2014-11-12 12:32:14 +00:00
}
bool NativeWindowViews::IsMenuBarAutoHide() {
return root_view_->IsMenuBarAutoHide();
2014-11-12 12:32:14 +00:00
}
void NativeWindowViews::SetMenuBarVisibility(bool visible) {
root_view_->SetMenuBarVisibility(visible);
2014-11-12 12:32:14 +00:00
}
bool NativeWindowViews::IsMenuBarVisible() {
return root_view_->IsMenuBarVisible();
2014-11-12 12:32:14 +00:00
}
void NativeWindowViews::SetVisibleOnAllWorkspaces(bool visible) {
widget()->SetVisibleOnAllWorkspaces(visible);
}
bool NativeWindowViews::IsVisibleOnAllWorkspaces() {
2015-03-27 11:41:07 +00:00
#if defined(USE_X11)
// Use the presence/absence of _NET_WM_STATE_STICKY in _NET_WM_STATE to
// determine whether the current window is visible on all workspaces.
2015-03-29 13:35:40 +00:00
XAtom sticky_atom = GetAtom("_NET_WM_STATE_STICKY");
std::vector<XAtom> wm_states;
ui::GetAtomArrayProperty(GetAcceleratedWidget(), "_NET_WM_STATE", &wm_states);
2018-04-18 01:55:30 +00:00
return std::find(wm_states.begin(), wm_states.end(), sticky_atom) !=
wm_states.end();
2015-03-27 11:41:07 +00:00
#endif
return false;
}
content::DesktopMediaID NativeWindowViews::GetDesktopMediaID() const {
const gfx::AcceleratedWidget accelerated_widget = GetAcceleratedWidget();
content::DesktopMediaID::Id window_handle = content::DesktopMediaID::kNullId;
content::DesktopMediaID::Id aura_id = content::DesktopMediaID::kNullId;
#if defined(OS_WIN)
window_handle =
reinterpret_cast<content::DesktopMediaID::Id>(accelerated_widget);
#elif defined(USE_X11)
window_handle = accelerated_widget;
#endif
aura::WindowTreeHost* const host =
aura::WindowTreeHost::GetForAcceleratedWidget(accelerated_widget);
aura::Window* const aura_window = host ? host->window() : nullptr;
if (aura_window) {
aura_id = content::DesktopMediaID::RegisterNativeWindow(
content::DesktopMediaID::TYPE_WINDOW, aura_window)
.window_id;
}
// No constructor to pass the aura_id. Make sure to not use the other
// constructor that has a third parameter, it is for yet another purpose.
content::DesktopMediaID result = content::DesktopMediaID(
content::DesktopMediaID::TYPE_WINDOW, window_handle);
// Confusing but this is how content::DesktopMediaID is designed. The id
// property is the window handle whereas the window_id property is an id
// given by a map containing all aura instances.
result.window_id = aura_id;
return result;
}
2017-05-21 18:57:19 +00:00
gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() const {
if (GetNativeWindow() && GetNativeWindow()->GetHost())
return GetNativeWindow()->GetHost()->GetAcceleratedWidget();
else
return gfx::kNullAcceleratedWidget;
2014-07-21 14:03:58 +00:00
}
NativeWindowHandle NativeWindowViews::GetNativeWindowHandle() const {
return GetAcceleratedWidget();
}
gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
const gfx::Rect& bounds) const {
if (!has_frame())
return bounds;
gfx::Rect window_bounds(bounds);
#if defined(OS_WIN)
if (widget()->non_client_view()) {
HWND hwnd = GetAcceleratedWidget();
gfx::Rect dpi_bounds = DIPToScreenRect(hwnd, bounds);
window_bounds = ScreenToDIPRect(
hwnd, widget()->non_client_view()->GetWindowBoundsForClientBounds(
dpi_bounds));
}
#endif
if (root_view_->HasMenu() && root_view_->IsMenuBarVisible()) {
int menu_bar_height = root_view_->GetMenuBarHeight();
window_bounds.set_y(window_bounds.y() - menu_bar_height);
window_bounds.set_height(window_bounds.height() + menu_bar_height);
}
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(DIPToScreenRect(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(ScreenToDIPRect(hwnd, content_bounds).size());
#endif
if (root_view_->HasMenu() && root_view_->IsMenuBarVisible()) {
int menu_bar_height = root_view_->GetMenuBarHeight();
content_bounds.set_y(content_bounds.y() + menu_bar_height);
content_bounds.set_height(content_bounds.height() - menu_bar_height);
}
return content_bounds;
}
void NativeWindowViews::UpdateDraggableRegions(
std::unique_ptr<SkRegion> region) {
draggable_region_ = std::move(region);
}
2016-05-20 13:28:07 +00:00
#if defined(OS_WIN)
2016-05-31 08:47:45 +00:00
void NativeWindowViews::SetIcon(HICON window_icon, HICON app_icon) {
// We are responsible for storing the images.
window_icon_ = base::win::ScopedHICON(CopyIcon(window_icon));
app_icon_ = base::win::ScopedHICON(CopyIcon(app_icon));
2016-05-20 13:28:07 +00:00
HWND hwnd = GetAcceleratedWidget();
SendMessage(hwnd, WM_SETICON, ICON_SMALL,
2016-05-31 08:47:45 +00:00
reinterpret_cast<LPARAM>(window_icon_.get()));
2016-05-20 13:28:07 +00:00
SendMessage(hwnd, WM_SETICON, ICON_BIG,
2016-05-31 08:47:45 +00:00
reinterpret_cast<LPARAM>(app_icon_.get()));
2016-05-20 13:28:07 +00:00
}
#elif defined(USE_X11)
2016-05-20 13:22:15 +00:00
void NativeWindowViews::SetIcon(const gfx::ImageSkia& icon) {
auto* tree_host = views::DesktopWindowTreeHostLinux::GetHostForWidget(
GetAcceleratedWidget());
2018-04-25 07:16:31 +00:00
tree_host->SetWindowIcons(icon, icon);
2016-05-20 13:22:15 +00:00
}
2016-05-20 13:28:07 +00:00
#endif
2016-05-20 13:22:15 +00:00
void NativeWindowViews::OnWidgetActivationChanged(views::Widget* changed_widget,
2018-04-18 01:55:30 +00:00
bool active) {
if (changed_widget != widget())
2014-07-08 04:55:33 +00:00
return;
if (active) {
MoveBehindTaskBarIfNeeded();
NativeWindow::NotifyWindowFocus();
} else {
NativeWindow::NotifyWindowBlur();
}
2014-08-07 06:48:02 +00:00
// Hide menu bar when window is blured.
if (!active && IsMenuBarAutoHide() && IsMenuBarVisible())
SetMenuBarVisibility(false);
root_view_->ResetAltState();
2014-07-08 04:55:33 +00:00
}
void NativeWindowViews::OnWidgetBoundsChanged(views::Widget* changed_widget,
2018-04-18 01:55:30 +00:00
const gfx::Rect& bounds) {
if (changed_widget != widget())
2015-05-09 15:55:10 +00:00
return;
// Note: We intentionally use `GetBounds()` instead of `bounds` to properly
// handle minimized windows on Windows.
const auto new_bounds = GetBounds();
if (widget_size_ != new_bounds.size()) {
int width_delta = new_bounds.width() - widget_size_.width();
int height_delta = new_bounds.height() - widget_size_.height();
for (NativeBrowserView* item : browser_views()) {
NativeBrowserViewViews* native_view =
static_cast<NativeBrowserViewViews*>(item);
native_view->SetAutoResizeProportions(widget_size_);
native_view->AutoResize(new_bounds, width_delta, height_delta);
}
2015-05-09 15:55:10 +00:00
NotifyWindowResize();
widget_size_ = new_bounds.size();
2015-05-09 15:55:10 +00:00
}
}
void NativeWindowViews::OnWidgetDestroying(views::Widget* widget) {
#if defined(OS_LINUX)
aura::Window* window = GetNativeWindow();
if (window)
window->RemovePreTargetHandler(this);
#endif
}
void NativeWindowViews::DeleteDelegate() {
if (is_modal() && this->parent()) {
auto* parent = this->parent();
// Enable parent window after current window gets closed.
static_cast<NativeWindowViews*>(parent)->DecrementChildModals();
// Focus on parent window.
parent->Focus(true);
}
NotifyWindowClosed();
}
views::View* NativeWindowViews::GetInitiallyFocusedView() {
return focused_view_;
}
bool NativeWindowViews::CanResize() const {
return resizable_;
}
bool NativeWindowViews::CanMaximize() const {
2016-01-23 10:23:18 +00:00
return resizable_ && maximizable_;
}
bool NativeWindowViews::CanMinimize() const {
2016-01-19 15:57:14 +00:00
#if defined(OS_WIN)
return minimizable_;
#elif defined(USE_X11)
return true;
#endif
}
base::string16 NativeWindowViews::GetWindowTitle() const {
return base::UTF8ToUTF16(title_);
}
views::View* NativeWindowViews::GetContentsView() {
return root_view_.get();
}
bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
gfx::NativeView child,
const gfx::Point& location) {
// App window should claim mouse events that fall within the draggable region.
if (draggable_region() &&
draggable_region()->contains(location.x(), location.y()))
return false;
// And the events on border for dragging resizable frameless window.
if (!has_frame() && CanResize()) {
2018-04-18 01:55:30 +00:00
FramelessView* frame =
static_cast<FramelessView*>(widget()->non_client_view()->frame_view());
return frame->ResizingBorderHitTest(location) == HTNOWHERE;
}
return true;
}
views::ClientView* NativeWindowViews::CreateClientView(views::Widget* widget) {
return new NativeWindowClientView(widget, root_view_.get(), this);
}
2014-07-04 04:32:03 +00:00
views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView(
views::Widget* widget) {
2014-07-24 10:06:27 +00:00
#if defined(OS_WIN)
2014-11-12 06:33:30 +00:00
WinFrameView* frame_view = new WinFrameView;
frame_view->Init(this, widget);
return frame_view;
#else
if (has_frame()) {
2015-07-24 08:04:54 +00:00
return new NativeFrameView(this, widget);
2014-07-24 10:06:27 +00:00
} else {
2014-11-12 06:33:30 +00:00
FramelessView* frame_view = new FramelessView;
2014-07-24 10:06:27 +00:00
frame_view->Init(this, widget);
return frame_view;
}
#endif
2014-07-04 04:32:03 +00:00
}
void NativeWindowViews::OnWidgetMove() {
NotifyWindowMove();
}
2014-07-04 08:54:10 +00:00
void NativeWindowViews::HandleKeyboardEvent(
content::WebContents*,
const content::NativeWebKeyboardEvent& event) {
#if defined(OS_LINUX)
if (event.windows_key_code == ui::VKEY_BROWSER_BACK)
NotifyWindowExecuteAppCommand(kBrowserBackward);
else if (event.windows_key_code == ui::VKEY_BROWSER_FORWARD)
NotifyWindowExecuteAppCommand(kBrowserForward);
#endif
keyboard_event_handler_->HandleKeyboardEvent(event,
root_view_->GetFocusManager());
root_view_->HandleKeyEvent(event);
2014-07-04 08:54:10 +00:00
}
#if defined(OS_LINUX)
void NativeWindowViews::OnMouseEvent(ui::MouseEvent* event) {
if (event->type() != ui::ET_MOUSE_PRESSED)
return;
if (event->changed_button_flags() == ui::EF_BACK_MOUSE_BUTTON)
NotifyWindowExecuteAppCommand(kBrowserBackward);
else if (event->changed_button_flags() == ui::EF_FORWARD_MOUSE_BUTTON)
NotifyWindowExecuteAppCommand(kBrowserForward);
}
#endif
ui::WindowShowState NativeWindowViews::GetRestoredState() {
if (IsMaximized())
return ui::SHOW_STATE_MAXIMIZED;
if (IsFullscreen())
return ui::SHOW_STATE_FULLSCREEN;
return ui::SHOW_STATE_NORMAL;
}
void NativeWindowViews::MoveBehindTaskBarIfNeeded() {
#if defined(OS_WIN)
if (behind_task_bar_) {
const HWND task_bar_hwnd = ::FindWindow(kUniqueTaskBarClassName, nullptr);
::SetWindowPos(GetAcceleratedWidget(), task_bar_hwnd, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
}
#endif
// TODO(julien.isorce): Implement X11 case.
}
// static
NativeWindow* NativeWindow::Create(const gin_helper::Dictionary& options,
2018-04-08 11:20:43 +00:00
NativeWindow* parent) {
return new NativeWindowViews(options, parent);
}
} // namespace electron