// Copyright (c) 2013 GitHub, Inc. // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. #include "atom/browser/api/atom_api_browser_window.h" #include "atom/browser/api/atom_api_browser_view.h" #include "atom/browser/api/atom_api_menu.h" #include "atom/browser/api/atom_api_web_contents.h" #include "atom/browser/browser.h" #include "atom/browser/native_window.h" #include "atom/browser/unresponsive_suppressor.h" #include "atom/browser/web_contents_preferences.h" #include "atom/browser/window_list.h" #include "atom/common/api/api_messages.h" #include "atom/common/color_util.h" #include "atom/common/native_mate_converters/callback.h" #include "atom/common/native_mate_converters/file_path_converter.h" #include "atom/common/native_mate_converters/gfx_converter.h" #include "atom/common/native_mate_converters/gurl_converter.h" #include "atom/common/native_mate_converters/image_converter.h" #include "atom/common/native_mate_converters/string16_converter.h" #include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/options_switches.h" #include "base/command_line.h" #include "base/threading/thread_task_runner_handle.h" #include "content/browser/renderer_host/render_widget_host_impl.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/common/content_switches.h" #include "native_mate/constructor.h" #include "native_mate/dictionary.h" #include "ui/gfx/geometry/rect.h" #include "ui/gl/gpu_switching_manager.h" #if defined(TOOLKIT_VIEWS) #include "atom/browser/native_window_views.h" #endif #if defined(OS_WIN) #include "atom/browser/ui/win/taskbar_host.h" #include "ui/base/win/shell.h" #endif #include "atom/common/node_includes.h" #if defined(OS_WIN) namespace mate { template<> struct Converter { static bool FromV8(v8::Isolate* isolate, v8::Handle val, atom::TaskbarHost::ThumbarButton* out) { mate::Dictionary dict; if (!ConvertFromV8(isolate, val, &dict)) return false; dict.Get("click", &(out->clicked_callback)); dict.Get("tooltip", &(out->tooltip)); dict.Get("flags", &out->flags); return dict.Get("icon", &(out->icon)); } }; } // namespace mate #endif namespace atom { namespace api { namespace { // Converts binary data to Buffer. v8::Local ToBuffer(v8::Isolate* isolate, void* val, int size) { auto buffer = node::Buffer::Copy(isolate, static_cast(val), size); if (buffer.IsEmpty()) return v8::Null(isolate); else return buffer.ToLocalChecked(); } } // namespace BrowserWindow::BrowserWindow(v8::Isolate* isolate, v8::Local wrapper, const mate::Dictionary& options) : weak_factory_(this) { mate::Handle web_contents; // Use options.webPreferences in WebContents. mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate); options.Get(options::kWebPreferences, &web_preferences); // Copy the backgroundColor to webContents. v8::Local value; if (options.Get(options::kBackgroundColor, &value)) web_preferences.Set(options::kBackgroundColor, value); v8::Local transparent; if (options.Get("transparent", &transparent)) web_preferences.Set("transparent", transparent); #if defined(ENABLE_OSR) // Offscreen windows are always created frameless. bool offscreen; if (web_preferences.Get("offscreen", &offscreen) && offscreen) { auto window_options = const_cast(options); window_options.Set(options::kFrame, false); } #endif if (options.Get("webContents", &web_contents) && !web_contents.IsEmpty()) { // Set webPreferences from options if using an existing webContents. // These preferences will be used when the webContent launches new // render processes. auto* existing_preferences = WebContentsPreferences::FromWebContents(web_contents->web_contents()); base::DictionaryValue web_preferences_dict; if (mate::ConvertFromV8(isolate, web_preferences.GetHandle(), &web_preferences_dict)) { existing_preferences->dict()->Clear(); existing_preferences->Merge(web_preferences_dict); } } else { // Creates the WebContents used by BrowserWindow. web_contents = WebContents::Create(isolate, web_preferences); } Init(isolate, wrapper, options, web_contents); } void BrowserWindow::Init(v8::Isolate* isolate, v8::Local wrapper, const mate::Dictionary& options, mate::Handle web_contents) { web_contents_.Reset(isolate, web_contents.ToV8()); api_web_contents_ = web_contents.get(); api_web_contents_->AddObserver(this); Observe(api_web_contents_->web_contents()); // Keep a copy of the options for later use. mate::Dictionary(isolate, web_contents->GetWrapper()).Set( "browserWindowOptions", options); // The parent window. mate::Handle parent; if (options.Get("parent", &parent) && !parent.IsEmpty()) parent_window_.Reset(isolate, parent.ToV8()); // Creates BrowserWindow. window_.reset(NativeWindow::Create( web_contents->managed_web_contents(), options, parent.IsEmpty() ? nullptr : parent->window_.get())); web_contents->SetOwnerWindow(window_.get()); window_->set_is_offscreen_dummy(api_web_contents_->IsOffScreen()); // Tell the content module to initialize renderer widget with transparent // mode. ui::GpuSwitchingManager::SetTransparent(window_->transparent()); #if defined(TOOLKIT_VIEWS) // Sets the window icon. mate::Handle icon; if (options.Get(options::kIcon, &icon) && !icon.IsEmpty()) SetIcon(icon); #endif window_->InitFromOptions(options); window_->AddObserver(this); InitWith(isolate, wrapper); AttachAsUserData(window_.get()); // We can only append this window to parent window's child windows after this // window's JS wrapper gets initialized. if (!parent.IsEmpty()) parent->child_windows_.Set(isolate, ID(), wrapper); auto* host = web_contents->web_contents()->GetRenderViewHost(); if (host) host->GetWidget()->AddInputEventObserver(this); } BrowserWindow::~BrowserWindow() { if (!window_->IsClosed()) window_->CloseImmediately(); api_web_contents_->RemoveObserver(this); // Destroy the native window in next tick because the native code might be // iterating all windows. base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, window_.release()); } void BrowserWindow::OnInputEvent(const blink::WebInputEvent& event) { switch (event.GetType()) { case blink::WebInputEvent::kGestureScrollBegin: case blink::WebInputEvent::kGestureScrollUpdate: case blink::WebInputEvent::kGestureScrollEnd: Emit("scroll-touch-edge"); break; default: break; } } void BrowserWindow::RenderViewHostChanged(content::RenderViewHost* old_host, content::RenderViewHost* new_host) { if (old_host) old_host->GetWidget()->RemoveInputEventObserver(this); if (new_host) new_host->GetWidget()->AddInputEventObserver(this); } void BrowserWindow::RenderViewCreated( content::RenderViewHost* render_view_host) { if (!window_->transparent()) return; content::RenderWidgetHostImpl* impl = content::RenderWidgetHostImpl::FromID( render_view_host->GetProcess()->GetID(), render_view_host->GetRoutingID()); if (impl) impl->SetBackgroundOpaque(false); } void BrowserWindow::DidFirstVisuallyNonEmptyPaint() { if (window_->IsVisible()) return; // When there is a non-empty first paint, resize the RenderWidget to force // Chromium to draw. const auto view = web_contents()->GetRenderWidgetHostView(); view->Show(); view->SetSize(window_->GetContentSize()); // Emit the ReadyToShow event in next tick in case of pending drawing work. base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::Bind([](base::WeakPtr self) { if (self) self->Emit("ready-to-show"); }, GetWeakPtr())); } void BrowserWindow::BeforeUnloadDialogCancelled() { WindowList::WindowCloseCancelled(window_.get()); // Cancel unresponsive event when window close is cancelled. window_unresponsive_closure_.Cancel(); } void BrowserWindow::OnRendererUnresponsive(content::RenderWidgetHost*) { // Schedule the unresponsive shortly later, since we may receive the // responsive event soon. This could happen after the whole application had // blocked for a while. // Also notice that when closing this event would be ignored because we have // explicitly started a close timeout counter. This is on purpose because we // don't want the unresponsive event to be sent too early when user is closing // the window. ScheduleUnresponsiveEvent(50); } bool BrowserWindow::OnMessageReceived(const IPC::Message& message, content::RenderFrameHost* rfh) { bool handled = true; IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(BrowserWindow, message, rfh) IPC_MESSAGE_HANDLER(AtomFrameHostMsg_UpdateDraggableRegions, UpdateDraggableRegions) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; } void BrowserWindow::OnCloseContents() { DCHECK(web_contents()); // Close all child windows before closing current window. v8::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); for (v8::Local value : child_windows_.Values(isolate())) { mate::Handle child; if (mate::ConvertFromV8(isolate(), value, &child) && !child.IsEmpty()) child->window_->CloseImmediately(); } // When the web contents is gone, close the window immediately, but the // memory will not be freed until you call delete. // In this way, it would be safe to manage windows via smart pointers. If you // want to free memory when the window is closed, you can do deleting by // overriding the OnWindowClosed method in the observer. window_->CloseImmediately(); // Do not sent "unresponsive" event after window is closed. window_unresponsive_closure_.Cancel(); } void BrowserWindow::OnRendererResponsive() { window_unresponsive_closure_.Cancel(); Emit("responsive"); } void BrowserWindow::WillCloseWindow(bool* prevent_default) { *prevent_default = Emit("close"); } void BrowserWindow::RequestPreferredWidth(int* width) { *width = web_contents()->GetPreferredSize().width(); } void BrowserWindow::OnCloseButtonClicked(bool* prevent_default) { // When user tries to close the window by clicking the close button, we do // not close the window immediately, instead we try to close the web page // first, and when the web page is closed the window will also be closed. *prevent_default = true; // Assume the window is not responding if it doesn't cancel the close and is // not closed in 5s, in this way we can quickly show the unresponsive // dialog when the window is busy executing some script withouth waiting for // the unresponsive timeout. if (window_unresponsive_closure_.IsCancelled()) ScheduleUnresponsiveEvent(5000); if (!web_contents()) // Already closed by renderer return; if (web_contents()->NeedToFireBeforeUnload()) web_contents()->DispatchBeforeUnload(); else web_contents()->Close(); } void BrowserWindow::OnWindowClosed() { auto* host = web_contents()->GetRenderViewHost(); if (host) host->GetWidget()->RemoveInputEventObserver(this); api_web_contents_->DestroyWebContents(true /* async */); Observe(nullptr); RemoveFromWeakMap(); window_->RemoveObserver(this); // We can not call Destroy here because we need to call Emit first, but we // also do not want any method to be used, so just mark as destroyed here. MarkDestroyed(); Emit("closed"); RemoveFromParentChildWindows(); ResetBrowserView(); // Destroy the native class when window is closed. base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, GetDestroyClosure()); } void BrowserWindow::OnWindowEndSession() { Emit("session-end"); } void BrowserWindow::OnWindowBlur() { web_contents()->StoreFocus(); #if defined(OS_MACOSX) auto* rwhv = web_contents()->GetRenderWidgetHostView(); if (rwhv) rwhv->SetActive(false); #endif Emit("blur"); } void BrowserWindow::OnWindowFocus() { web_contents()->RestoreFocus(); #if defined(OS_MACOSX) auto* rwhv = web_contents()->GetRenderWidgetHostView(); if (rwhv) rwhv->SetActive(true); #else if (!api_web_contents_->IsDevToolsOpened()) web_contents()->Focus(); #endif Emit("focus"); } void BrowserWindow::OnWindowShow() { Emit("show"); } void BrowserWindow::OnWindowHide() { Emit("hide"); } void BrowserWindow::OnWindowMaximize() { Emit("maximize"); } void BrowserWindow::OnWindowUnmaximize() { Emit("unmaximize"); } void BrowserWindow::OnWindowMinimize() { Emit("minimize"); } void BrowserWindow::OnWindowRestore() { Emit("restore"); } void BrowserWindow::OnWindowResize() { #if defined(OS_MACOSX) if (!draggable_regions_.empty()) UpdateDraggableRegions(nullptr, draggable_regions_); #endif Emit("resize"); } void BrowserWindow::OnWindowMove() { Emit("move"); } void BrowserWindow::OnWindowMoved() { Emit("moved"); } void BrowserWindow::OnWindowEnterFullScreen() { Emit("enter-full-screen"); } void BrowserWindow::OnWindowLeaveFullScreen() { Emit("leave-full-screen"); } void BrowserWindow::OnWindowScrollTouchBegin() { Emit("scroll-touch-begin"); } void BrowserWindow::OnWindowScrollTouchEnd() { Emit("scroll-touch-end"); } void BrowserWindow::OnWindowSwipe(const std::string& direction) { Emit("swipe", direction); } void BrowserWindow::OnWindowSheetBegin() { Emit("sheet-begin"); } void BrowserWindow::OnWindowSheetEnd() { Emit("sheet-end"); } void BrowserWindow::OnWindowEnterHtmlFullScreen() { Emit("enter-html-full-screen"); } void BrowserWindow::OnWindowLeaveHtmlFullScreen() { Emit("leave-html-full-screen"); } void BrowserWindow::OnExecuteWindowsCommand(const std::string& command_name) { Emit("app-command", command_name); } void BrowserWindow::OnTouchBarItemResult(const std::string& item_id, const base::DictionaryValue& details) { Emit("-touch-bar-interaction", item_id, details); } void BrowserWindow::OnNewWindowForTab() { Emit("new-window-for-tab"); } #if defined(OS_WIN) void BrowserWindow::OnWindowMessage(UINT message, WPARAM w_param, LPARAM l_param) { if (IsWindowMessageHooked(message)) { messages_callback_map_[message].Run( ToBuffer(isolate(), static_cast(&w_param), sizeof(WPARAM)), ToBuffer(isolate(), static_cast(&l_param), sizeof(LPARAM))); } } #endif // static mate::WrappableBase* BrowserWindow::New(mate::Arguments* args) { if (!Browser::Get()->is_ready()) { args->ThrowError("Cannot create BrowserWindow before app is ready"); return nullptr; } if (args->Length() > 1) { args->ThrowError(); return nullptr; } mate::Dictionary options; if (!(args->Length() == 1 && args->GetNext(&options))) { options = mate::Dictionary::CreateEmpty(args->isolate()); } return new BrowserWindow(args->isolate(), args->GetThis(), options); } void BrowserWindow::Close() { window_->Close(); } void BrowserWindow::Focus() { window_->Focus(true); } void BrowserWindow::Blur() { window_->Focus(false); } bool BrowserWindow::IsFocused() { return window_->IsFocused(); } void BrowserWindow::Show() { window_->Show(); } void BrowserWindow::ShowInactive() { // This method doesn't make sense for modal window.. if (IsModal()) return; window_->ShowInactive(); } void BrowserWindow::Hide() { window_->Hide(); } bool BrowserWindow::IsVisible() { return window_->IsVisible(); } bool BrowserWindow::IsEnabled() { return window_->IsEnabled(); } void BrowserWindow::SetEnabled(bool enable) { window_->SetEnabled(enable); } void BrowserWindow::Maximize() { window_->Maximize(); } void BrowserWindow::Unmaximize() { window_->Unmaximize(); } bool BrowserWindow::IsMaximized() { return window_->IsMaximized(); } void BrowserWindow::Minimize() { window_->Minimize(); } void BrowserWindow::Restore() { window_->Restore(); } bool BrowserWindow::IsMinimized() { return window_->IsMinimized(); } void BrowserWindow::SetFullScreen(bool fullscreen) { window_->SetFullScreen(fullscreen); } bool BrowserWindow::IsFullscreen() { return window_->IsFullscreen(); } void BrowserWindow::SetBounds(const gfx::Rect& bounds, mate::Arguments* args) { bool animate = false; args->GetNext(&animate); window_->SetBounds(bounds, animate); } gfx::Rect BrowserWindow::GetBounds() { return window_->GetBounds(); } void BrowserWindow::SetContentBounds(const gfx::Rect& bounds, mate::Arguments* args) { bool animate = false; args->GetNext(&animate); window_->SetContentBounds(bounds, animate); } gfx::Rect BrowserWindow::GetContentBounds() { return window_->GetContentBounds(); } void BrowserWindow::SetSize(int width, int height, mate::Arguments* args) { bool animate = false; args->GetNext(&animate); window_->SetSize(gfx::Size(width, height), animate); } std::vector BrowserWindow::GetSize() { std::vector result(2); gfx::Size size = window_->GetSize(); result[0] = size.width(); result[1] = size.height(); return result; } void BrowserWindow::SetContentSize(int width, int height, mate::Arguments* args) { bool animate = false; args->GetNext(&animate); window_->SetContentSize(gfx::Size(width, height), animate); } std::vector BrowserWindow::GetContentSize() { std::vector result(2); gfx::Size size = window_->GetContentSize(); result[0] = size.width(); result[1] = size.height(); return result; } void BrowserWindow::SetMinimumSize(int width, int height) { window_->SetMinimumSize(gfx::Size(width, height)); } std::vector BrowserWindow::GetMinimumSize() { std::vector result(2); gfx::Size size = window_->GetMinimumSize(); result[0] = size.width(); result[1] = size.height(); return result; } void BrowserWindow::SetMaximumSize(int width, int height) { window_->SetMaximumSize(gfx::Size(width, height)); } std::vector BrowserWindow::GetMaximumSize() { std::vector result(2); gfx::Size size = window_->GetMaximumSize(); result[0] = size.width(); result[1] = size.height(); return result; } void BrowserWindow::SetSheetOffset(double offsetY, mate::Arguments* args) { double offsetX = 0.0; args->GetNext(&offsetX); window_->SetSheetOffset(offsetX, offsetY); } void BrowserWindow::SetResizable(bool resizable) { window_->SetResizable(resizable); } bool BrowserWindow::IsResizable() { return window_->IsResizable(); } void BrowserWindow::SetMovable(bool movable) { window_->SetMovable(movable); } bool BrowserWindow::IsMovable() { return window_->IsMovable(); } void BrowserWindow::SetMinimizable(bool minimizable) { window_->SetMinimizable(minimizable); } bool BrowserWindow::IsMinimizable() { return window_->IsMinimizable(); } void BrowserWindow::SetMaximizable(bool maximizable) { window_->SetMaximizable(maximizable); } bool BrowserWindow::IsMaximizable() { return window_->IsMaximizable(); } void BrowserWindow::SetFullScreenable(bool fullscreenable) { window_->SetFullScreenable(fullscreenable); } bool BrowserWindow::IsFullScreenable() { return window_->IsFullScreenable(); } void BrowserWindow::SetClosable(bool closable) { window_->SetClosable(closable); } bool BrowserWindow::IsClosable() { return window_->IsClosable(); } void BrowserWindow::SetAlwaysOnTop(bool top, mate::Arguments* args) { std::string level = "floating"; int relativeLevel = 0; std::string error; args->GetNext(&level); args->GetNext(&relativeLevel); window_->SetAlwaysOnTop(top, level, relativeLevel, &error); if (!error.empty()) { args->ThrowError(error); } } bool BrowserWindow::IsAlwaysOnTop() { return window_->IsAlwaysOnTop(); } void BrowserWindow::Center() { window_->Center(); } void BrowserWindow::SetPosition(int x, int y, mate::Arguments* args) { bool animate = false; args->GetNext(&animate); window_->SetPosition(gfx::Point(x, y), animate); } std::vector BrowserWindow::GetPosition() { std::vector result(2); gfx::Point pos = window_->GetPosition(); result[0] = pos.x(); result[1] = pos.y(); return result; } void BrowserWindow::SetTitle(const std::string& title) { window_->SetTitle(title); } std::string BrowserWindow::GetTitle() { return window_->GetTitle(); } void BrowserWindow::FlashFrame(bool flash) { window_->FlashFrame(flash); } void BrowserWindow::SetSkipTaskbar(bool skip) { window_->SetSkipTaskbar(skip); } void BrowserWindow::SetSimpleFullScreen(bool simple_fullscreen) { window_->SetSimpleFullScreen(simple_fullscreen); } bool BrowserWindow::IsSimpleFullScreen() { return window_->IsSimpleFullScreen(); } void BrowserWindow::SetKiosk(bool kiosk) { window_->SetKiosk(kiosk); } bool BrowserWindow::IsKiosk() { return window_->IsKiosk(); } void BrowserWindow::SetBackgroundColor(const std::string& color_name) { SkColor color = ParseHexColor(color_name); window_->SetBackgroundColor(color); auto* view = web_contents()->GetRenderWidgetHostView(); if (view) view->SetBackgroundColor(color); } void BrowserWindow::SetHasShadow(bool has_shadow) { window_->SetHasShadow(has_shadow); } bool BrowserWindow::HasShadow() { return window_->HasShadow(); } void BrowserWindow::SetOpacity(const double opacity) { window_->SetOpacity(opacity); } double BrowserWindow::GetOpacity() { return window_->GetOpacity(); } void BrowserWindow::FocusOnWebView() { web_contents()->GetRenderViewHost()->GetWidget()->Focus(); } void BrowserWindow::BlurWebView() { web_contents()->GetRenderViewHost()->GetWidget()->Blur(); } bool BrowserWindow::IsWebViewFocused() { auto host_view = web_contents()->GetRenderViewHost()->GetWidget()->GetView(); return host_view && host_view->HasFocus(); } void BrowserWindow::SetRepresentedFilename(const std::string& filename) { window_->SetRepresentedFilename(filename); } std::string BrowserWindow::GetRepresentedFilename() { return window_->GetRepresentedFilename(); } void BrowserWindow::SetDocumentEdited(bool edited) { window_->SetDocumentEdited(edited); } bool BrowserWindow::IsDocumentEdited() { return window_->IsDocumentEdited(); } void BrowserWindow::SetIgnoreMouseEvents(bool ignore, mate::Arguments* args) { mate::Dictionary options; bool forward = false; args->GetNext(&options) && options.Get("forward", &forward); return window_->SetIgnoreMouseEvents(ignore, forward); } void BrowserWindow::SetContentProtection(bool enable) { return window_->SetContentProtection(enable); } void BrowserWindow::SetFocusable(bool focusable) { return window_->SetFocusable(focusable); } void BrowserWindow::SetProgressBar(double progress, mate::Arguments* args) { mate::Dictionary options; std::string mode; NativeWindow::ProgressState state = NativeWindow::PROGRESS_NORMAL; args->GetNext(&options) && options.Get("mode", &mode); if (mode == "error") { state = NativeWindow::PROGRESS_ERROR; } else if (mode == "paused") { state = NativeWindow::PROGRESS_PAUSED; } else if (mode == "indeterminate") { state = NativeWindow::PROGRESS_INDETERMINATE; } else if (mode == "none") { state = NativeWindow::PROGRESS_NONE; } window_->SetProgressBar(progress, state); } void BrowserWindow::SetOverlayIcon(const gfx::Image& overlay, const std::string& description) { window_->SetOverlayIcon(overlay, description); } bool BrowserWindow::SetThumbarButtons(mate::Arguments* args) { #if defined(OS_WIN) std::vector buttons; if (!args->GetNext(&buttons)) { args->ThrowError(); return false; } auto window = static_cast(window_.get()); return window->taskbar_host().SetThumbarButtons( window_->GetAcceleratedWidget(), buttons); #else return false; #endif } void BrowserWindow::SetMenu(v8::Isolate* isolate, v8::Local value) { mate::Handle menu; if (value->IsObject() && mate::V8ToString(value->ToObject()->GetConstructorName()) == "Menu" && mate::ConvertFromV8(isolate, value, &menu) && !menu.IsEmpty()) { menu_.Reset(isolate, menu.ToV8()); window_->SetMenu(menu->model()); } else if (value->IsNull()) { menu_.Reset(); window_->SetMenu(nullptr); } else { isolate->ThrowException(v8::Exception::TypeError( mate::StringToV8(isolate, "Invalid Menu"))); } } void BrowserWindow::SetAutoHideMenuBar(bool auto_hide) { window_->SetAutoHideMenuBar(auto_hide); } bool BrowserWindow::IsMenuBarAutoHide() { return window_->IsMenuBarAutoHide(); } void BrowserWindow::SetMenuBarVisibility(bool visible) { window_->SetMenuBarVisibility(visible); } bool BrowserWindow::IsMenuBarVisible() { return window_->IsMenuBarVisible(); } #if defined(OS_WIN) bool BrowserWindow::HookWindowMessage(UINT message, const MessageCallback& callback) { messages_callback_map_[message] = callback; return true; } void BrowserWindow::UnhookWindowMessage(UINT message) { if (!ContainsKey(messages_callback_map_, message)) return; messages_callback_map_.erase(message); } bool BrowserWindow::IsWindowMessageHooked(UINT message) { return ContainsKey(messages_callback_map_, message); } void BrowserWindow::UnhookAllWindowMessages() { messages_callback_map_.clear(); } bool BrowserWindow::SetThumbnailClip(const gfx::Rect& region) { auto window = static_cast(window_.get()); return window->taskbar_host().SetThumbnailClip( window_->GetAcceleratedWidget(), region); } bool BrowserWindow::SetThumbnailToolTip(const std::string& tooltip) { auto window = static_cast(window_.get()); return window->taskbar_host().SetThumbnailToolTip( window_->GetAcceleratedWidget(), tooltip); } void BrowserWindow::SetAppDetails(const mate::Dictionary& options) { base::string16 app_id; base::FilePath app_icon_path; int app_icon_index = 0; base::string16 relaunch_command; base::string16 relaunch_display_name; options.Get("appId", &app_id); options.Get("appIconPath", &app_icon_path); options.Get("appIconIndex", &app_icon_index); options.Get("relaunchCommand", &relaunch_command); options.Get("relaunchDisplayName", &relaunch_display_name); ui::win::SetAppDetailsForWindow( app_id, app_icon_path, app_icon_index, relaunch_command, relaunch_display_name, window_->GetAcceleratedWidget()); } #endif #if defined(TOOLKIT_VIEWS) void BrowserWindow::SetIcon(mate::Handle icon) { #if defined(OS_WIN) static_cast(window_.get())->SetIcon( icon->GetHICON(GetSystemMetrics(SM_CXSMICON)), icon->GetHICON(GetSystemMetrics(SM_CXICON))); #elif defined(USE_X11) static_cast(window_.get())->SetIcon( icon->image().AsImageSkia()); #endif } #endif void BrowserWindow::SetAspectRatio(double aspect_ratio, mate::Arguments* args) { gfx::Size extra_size; args->GetNext(&extra_size); window_->SetAspectRatio(aspect_ratio, extra_size); } void BrowserWindow::PreviewFile(const std::string& path, mate::Arguments* args) { std::string display_name; if (!args->GetNext(&display_name)) display_name = path; window_->PreviewFile(path, display_name); } void BrowserWindow::CloseFilePreview() { window_->CloseFilePreview(); } void BrowserWindow::SetParentWindow(v8::Local value, mate::Arguments* args) { if (IsModal()) { args->ThrowError("Can not be called for modal window"); return; } mate::Handle parent; if (value->IsNull() || value->IsUndefined()) { 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 BrowserWindow::GetParentWindow() const { if (parent_window_.IsEmpty()) return v8::Null(isolate()); else return v8::Local::New(isolate(), parent_window_); } std::vector> BrowserWindow::GetChildWindows() const { return child_windows_.Values(isolate()); } v8::Local BrowserWindow::GetBrowserView() const { if (browser_view_.IsEmpty()) { return v8::Null(isolate()); } return v8::Local::New(isolate(), browser_view_); } void BrowserWindow::SetBrowserView(v8::Local value) { ResetBrowserView(); mate::Handle browser_view; if (value->IsNull() || value->IsUndefined()) { window_->SetBrowserView(nullptr); } else if (mate::ConvertFromV8(isolate(), value, &browser_view)) { window_->SetBrowserView(browser_view->view()); browser_view->web_contents()->SetOwnerWindow(window_.get()); browser_view_.Reset(isolate(), value); #if defined(OS_MACOSX) UpdateDraggableRegions(nullptr, draggable_regions_); #endif } } void BrowserWindow::ResetBrowserView() { if (browser_view_.IsEmpty()) { return; } mate::Handle browser_view; if (mate::ConvertFromV8(isolate(), GetBrowserView(), &browser_view) && !browser_view.IsEmpty()) { browser_view->web_contents()->SetOwnerWindow(nullptr); } browser_view_.Reset(); } bool BrowserWindow::IsModal() const { return window_->is_modal(); } v8::Local BrowserWindow::GetNativeWindowHandle() { gfx::AcceleratedWidget handle = window_->GetAcceleratedWidget(); return ToBuffer( isolate(), static_cast(&handle), sizeof(gfx::AcceleratedWidget)); } void BrowserWindow::SetVisibleOnAllWorkspaces(bool visible) { return window_->SetVisibleOnAllWorkspaces(visible); } bool BrowserWindow::IsVisibleOnAllWorkspaces() { return window_->IsVisibleOnAllWorkspaces(); } void BrowserWindow::SetAutoHideCursor(bool auto_hide) { window_->SetAutoHideCursor(auto_hide); } void BrowserWindow::SelectPreviousTab() { window_->SelectPreviousTab(); } void BrowserWindow::SelectNextTab() { window_->SelectNextTab(); } void BrowserWindow::MergeAllWindows() { window_->MergeAllWindows(); } void BrowserWindow::MoveTabToNewWindow() { window_->MoveTabToNewWindow(); } void BrowserWindow::ToggleTabBar() { window_->ToggleTabBar(); } void BrowserWindow::AddTabbedWindow(NativeWindow* window, mate::Arguments* args) { const bool windowAdded = window_->AddTabbedWindow(window); if (!windowAdded) args->ThrowError("AddTabbedWindow cannot be called by a window on itself."); } void BrowserWindow::SetVibrancy(mate::Arguments* args) { std::string type; args->GetNext(&type); auto* render_view_host = web_contents()->GetRenderViewHost(); if (render_view_host) { auto* impl = content::RenderWidgetHostImpl::FromID( render_view_host->GetProcess()->GetID(), render_view_host->GetRoutingID()); if (impl) impl->SetBackgroundOpaque(type.empty() ? !window_->transparent() : false); } window_->SetVibrancy(type); } void BrowserWindow::SetTouchBar( const std::vector& items) { window_->SetTouchBar(items); } void BrowserWindow::RefreshTouchBarItem(const std::string& item_id) { window_->RefreshTouchBarItem(item_id); } void BrowserWindow::SetEscapeTouchBarItem( const mate::PersistentDictionary& item) { window_->SetEscapeTouchBarItem(item); } int32_t BrowserWindow::ID() const { return weak_map_id(); } v8::Local BrowserWindow::WebContents(v8::Isolate* isolate) { if (web_contents_.IsEmpty()) { return v8::Null(isolate); } return v8::Local::New(isolate, web_contents_); } void BrowserWindow::RemoveFromParentChildWindows() { if (parent_window_.IsEmpty()) return; mate::Handle parent; if (!mate::ConvertFromV8(isolate(), GetParentWindow(), &parent) || parent.IsEmpty()) { return; } parent->child_windows_.Remove(ID()); } // Convert draggable regions in raw format to SkRegion format. std::unique_ptr BrowserWindow::DraggableRegionsToSkRegion( const std::vector& regions) { std::unique_ptr sk_region(new SkRegion); for (const DraggableRegion& region : regions) { sk_region->op( region.bounds.x(), region.bounds.y(), region.bounds.right(), region.bounds.bottom(), region.draggable ? SkRegion::kUnion_Op : SkRegion::kDifference_Op); } return sk_region; } void BrowserWindow::ScheduleUnresponsiveEvent(int ms) { if (!window_unresponsive_closure_.IsCancelled()) return; window_unresponsive_closure_.Reset( base::Bind(&BrowserWindow::NotifyWindowUnresponsive, GetWeakPtr())); base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( FROM_HERE, window_unresponsive_closure_.callback(), base::TimeDelta::FromMilliseconds(ms)); } void BrowserWindow::NotifyWindowUnresponsive() { window_unresponsive_closure_.Cancel(); if (!window_->IsClosed() && window_->IsEnabled() && !IsUnresponsiveEventSuppressed()) { Emit("unresponsive"); } } // static void BrowserWindow::BuildPrototype(v8::Isolate* isolate, v8::Local prototype) { prototype->SetClassName(mate::StringToV8(isolate, "BrowserWindow")); mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) .MakeDestroyable() .SetMethod("close", &BrowserWindow::Close) .SetMethod("focus", &BrowserWindow::Focus) .SetMethod("blur", &BrowserWindow::Blur) .SetMethod("isFocused", &BrowserWindow::IsFocused) .SetMethod("show", &BrowserWindow::Show) .SetMethod("showInactive", &BrowserWindow::ShowInactive) .SetMethod("hide", &BrowserWindow::Hide) .SetMethod("isVisible", &BrowserWindow::IsVisible) .SetMethod("isEnabled", &BrowserWindow::IsEnabled) .SetMethod("setEnabled", & BrowserWindow::SetEnabled) .SetMethod("maximize", &BrowserWindow::Maximize) .SetMethod("unmaximize", &BrowserWindow::Unmaximize) .SetMethod("isMaximized", &BrowserWindow::IsMaximized) .SetMethod("minimize", &BrowserWindow::Minimize) .SetMethod("restore", &BrowserWindow::Restore) .SetMethod("isMinimized", &BrowserWindow::IsMinimized) .SetMethod("setFullScreen", &BrowserWindow::SetFullScreen) .SetMethod("isFullScreen", &BrowserWindow::IsFullscreen) .SetMethod("setAspectRatio", &BrowserWindow::SetAspectRatio) .SetMethod("previewFile", &BrowserWindow::PreviewFile) .SetMethod("closeFilePreview", &BrowserWindow::CloseFilePreview) #if !defined(OS_WIN) .SetMethod("setParentWindow", &BrowserWindow::SetParentWindow) #endif .SetMethod("getParentWindow", &BrowserWindow::GetParentWindow) .SetMethod("getChildWindows", &BrowserWindow::GetChildWindows) .SetMethod("getBrowserView", &BrowserWindow::GetBrowserView) .SetMethod("setBrowserView", &BrowserWindow::SetBrowserView) .SetMethod("isModal", &BrowserWindow::IsModal) .SetMethod("getNativeWindowHandle", &BrowserWindow::GetNativeWindowHandle) .SetMethod("getBounds", &BrowserWindow::GetBounds) .SetMethod("setBounds", &BrowserWindow::SetBounds) .SetMethod("getSize", &BrowserWindow::GetSize) .SetMethod("setSize", &BrowserWindow::SetSize) .SetMethod("getContentBounds", &BrowserWindow::GetContentBounds) .SetMethod("setContentBounds", &BrowserWindow::SetContentBounds) .SetMethod("getContentSize", &BrowserWindow::GetContentSize) .SetMethod("setContentSize", &BrowserWindow::SetContentSize) .SetMethod("setMinimumSize", &BrowserWindow::SetMinimumSize) .SetMethod("getMinimumSize", &BrowserWindow::GetMinimumSize) .SetMethod("setMaximumSize", &BrowserWindow::SetMaximumSize) .SetMethod("getMaximumSize", &BrowserWindow::GetMaximumSize) .SetMethod("setSheetOffset", &BrowserWindow::SetSheetOffset) .SetMethod("setResizable", &BrowserWindow::SetResizable) .SetMethod("isResizable", &BrowserWindow::IsResizable) .SetMethod("setMovable", &BrowserWindow::SetMovable) .SetMethod("isMovable", &BrowserWindow::IsMovable) .SetMethod("setMinimizable", &BrowserWindow::SetMinimizable) .SetMethod("isMinimizable", &BrowserWindow::IsMinimizable) .SetMethod("setMaximizable", &BrowserWindow::SetMaximizable) .SetMethod("isMaximizable", &BrowserWindow::IsMaximizable) .SetMethod("setFullScreenable", &BrowserWindow::SetFullScreenable) .SetMethod("isFullScreenable", &BrowserWindow::IsFullScreenable) .SetMethod("setClosable", &BrowserWindow::SetClosable) .SetMethod("isClosable", &BrowserWindow::IsClosable) .SetMethod("setAlwaysOnTop", &BrowserWindow::SetAlwaysOnTop) .SetMethod("isAlwaysOnTop", &BrowserWindow::IsAlwaysOnTop) .SetMethod("center", &BrowserWindow::Center) .SetMethod("setPosition", &BrowserWindow::SetPosition) .SetMethod("getPosition", &BrowserWindow::GetPosition) .SetMethod("setTitle", &BrowserWindow::SetTitle) .SetMethod("getTitle", &BrowserWindow::GetTitle) .SetMethod("flashFrame", &BrowserWindow::FlashFrame) .SetMethod("setSkipTaskbar", &BrowserWindow::SetSkipTaskbar) .SetMethod("setSimpleFullScreen", &BrowserWindow::SetSimpleFullScreen) .SetMethod("isSimpleFullScreen", &BrowserWindow::IsSimpleFullScreen) .SetMethod("setKiosk", &BrowserWindow::SetKiosk) .SetMethod("isKiosk", &BrowserWindow::IsKiosk) .SetMethod("setBackgroundColor", &BrowserWindow::SetBackgroundColor) .SetMethod("setHasShadow", &BrowserWindow::SetHasShadow) .SetMethod("hasShadow", &BrowserWindow::HasShadow) .SetMethod("setOpacity", &BrowserWindow::SetOpacity) .SetMethod("getOpacity", &BrowserWindow::GetOpacity) .SetMethod("setRepresentedFilename", &BrowserWindow::SetRepresentedFilename) .SetMethod("getRepresentedFilename", &BrowserWindow::GetRepresentedFilename) .SetMethod("setDocumentEdited", &BrowserWindow::SetDocumentEdited) .SetMethod("isDocumentEdited", &BrowserWindow::IsDocumentEdited) .SetMethod("setIgnoreMouseEvents", &BrowserWindow::SetIgnoreMouseEvents) .SetMethod("setContentProtection", &BrowserWindow::SetContentProtection) .SetMethod("setFocusable", &BrowserWindow::SetFocusable) .SetMethod("focusOnWebView", &BrowserWindow::FocusOnWebView) .SetMethod("blurWebView", &BrowserWindow::BlurWebView) .SetMethod("isWebViewFocused", &BrowserWindow::IsWebViewFocused) .SetMethod("setProgressBar", &BrowserWindow::SetProgressBar) .SetMethod("setOverlayIcon", &BrowserWindow::SetOverlayIcon) .SetMethod("setThumbarButtons", &BrowserWindow::SetThumbarButtons) .SetMethod("setMenu", &BrowserWindow::SetMenu) .SetMethod("setAutoHideMenuBar", &BrowserWindow::SetAutoHideMenuBar) .SetMethod("isMenuBarAutoHide", &BrowserWindow::IsMenuBarAutoHide) .SetMethod("setMenuBarVisibility", &BrowserWindow::SetMenuBarVisibility) .SetMethod("isMenuBarVisible", &BrowserWindow::IsMenuBarVisible) .SetMethod("setVisibleOnAllWorkspaces", &BrowserWindow::SetVisibleOnAllWorkspaces) .SetMethod("isVisibleOnAllWorkspaces", &BrowserWindow::IsVisibleOnAllWorkspaces) #if defined(OS_MACOSX) .SetMethod("setAutoHideCursor", &BrowserWindow::SetAutoHideCursor) .SetMethod("mergeAllWindows", &BrowserWindow::MergeAllWindows) .SetMethod("selectPreviousTab", &BrowserWindow::SelectPreviousTab) .SetMethod("selectNextTab", &BrowserWindow::SelectNextTab) .SetMethod("moveTabToNewWindow", &BrowserWindow::MoveTabToNewWindow) .SetMethod("toggleTabBar", &BrowserWindow::ToggleTabBar) .SetMethod("addTabbedWindow", &BrowserWindow::AddTabbedWindow) #endif .SetMethod("setVibrancy", &BrowserWindow::SetVibrancy) .SetMethod("_setTouchBarItems", &BrowserWindow::SetTouchBar) .SetMethod("_refreshTouchBarItem", &BrowserWindow::RefreshTouchBarItem) .SetMethod("_setEscapeTouchBarItem", &BrowserWindow::SetEscapeTouchBarItem) #if defined(OS_WIN) .SetMethod("hookWindowMessage", &BrowserWindow::HookWindowMessage) .SetMethod("isWindowMessageHooked", &BrowserWindow::IsWindowMessageHooked) .SetMethod("unhookWindowMessage", &BrowserWindow::UnhookWindowMessage) .SetMethod("unhookAllWindowMessages", &BrowserWindow::UnhookAllWindowMessages) .SetMethod("setThumbnailClip", &BrowserWindow::SetThumbnailClip) .SetMethod("setThumbnailToolTip", &BrowserWindow::SetThumbnailToolTip) .SetMethod("setAppDetails", &BrowserWindow::SetAppDetails) #endif #if defined(TOOLKIT_VIEWS) .SetMethod("setIcon", &BrowserWindow::SetIcon) #endif .SetProperty("id", &BrowserWindow::ID) .SetProperty("webContents", &BrowserWindow::WebContents); } // static v8::Local BrowserWindow::From(v8::Isolate* isolate, NativeWindow* native_window) { auto existing = TrackableObject::FromWrappedClass(isolate, native_window); if (existing) return existing->GetWrapper(); else return v8::Null(isolate); } } // namespace api } // namespace atom namespace { using atom::api::BrowserWindow; void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { v8::Isolate* isolate = context->GetIsolate(); BrowserWindow::SetConstructor(isolate, base::Bind(&BrowserWindow::New)); mate::Dictionary browser_window( isolate, BrowserWindow::GetConstructor(isolate)->GetFunction()); browser_window.SetMethod( "fromId", &mate::TrackableObject::FromWeakMapID); browser_window.SetMethod( "getAllWindows", &mate::TrackableObject::GetAll); mate::Dictionary dict(isolate, exports); dict.Set("BrowserWindow", browser_window); } } // namespace NODE_BUILTIN_MODULE_CONTEXT_AWARE(atom_browser_window, Initialize)