native_window_views.cc 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407
  1. // Copyright (c) 2014 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include "shell/browser/native_window_views.h"
  5. #if defined(OS_WIN)
  6. #include <wrl/client.h>
  7. #endif
  8. #include <memory>
  9. #include <tuple>
  10. #include <utility>
  11. #include <vector>
  12. #include "base/numerics/ranges.h"
  13. #include "base/stl_util.h"
  14. #include "base/strings/utf_string_conversions.h"
  15. #include "content/public/browser/browser_thread.h"
  16. #include "native_mate/dictionary.h"
  17. #include "shell/browser/api/atom_api_web_contents.h"
  18. #include "shell/browser/native_browser_view_views.h"
  19. #include "shell/browser/ui/inspectable_web_contents.h"
  20. #include "shell/browser/ui/inspectable_web_contents_view.h"
  21. #include "shell/browser/ui/views/root_view.h"
  22. #include "shell/browser/web_contents_preferences.h"
  23. #include "shell/browser/web_view_manager.h"
  24. #include "shell/browser/window_list.h"
  25. #include "shell/common/atom_constants.h"
  26. #include "shell/common/native_mate_converters/image_converter.h"
  27. #include "shell/common/options_switches.h"
  28. #include "ui/aura/window_tree_host.h"
  29. #include "ui/base/hit_test.h"
  30. #include "ui/gfx/image/image.h"
  31. #include "ui/gfx/native_widget_types.h"
  32. #include "ui/views/background.h"
  33. #include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
  34. #include "ui/views/controls/webview/webview.h"
  35. #include "ui/views/widget/native_widget_private.h"
  36. #include "ui/views/widget/widget.h"
  37. #include "ui/views/window/client_view.h"
  38. #include "ui/wm/core/shadow_types.h"
  39. #include "ui/wm/core/window_util.h"
  40. #if defined(USE_X11)
  41. #include "base/strings/string_util.h"
  42. #include "chrome/browser/ui/libgtkui/unity_service.h"
  43. #include "shell/browser/browser.h"
  44. #include "shell/browser/ui/views/frameless_view.h"
  45. #include "shell/browser/ui/views/global_menu_bar_x11.h"
  46. #include "shell/browser/ui/views/native_frame_view.h"
  47. #include "shell/browser/ui/x/event_disabler.h"
  48. #include "shell/browser/ui/x/window_state_watcher.h"
  49. #include "shell/browser/ui/x/x_window_utils.h"
  50. #include "ui/base/x/x11_util.h"
  51. #include "ui/gfx/x/x11_types.h"
  52. #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
  53. #include "ui/views/window/native_frame_view.h"
  54. #elif defined(OS_WIN)
  55. #include "shell/browser/ui/views/win_frame_view.h"
  56. #include "shell/browser/ui/win/atom_desktop_native_widget_aura.h"
  57. #include "skia/ext/skia_utils_win.h"
  58. #include "ui/base/win/shell.h"
  59. #include "ui/display/screen.h"
  60. #include "ui/display/win/screen_win.h"
  61. #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
  62. #endif
  63. namespace electron {
  64. namespace {
  65. #if defined(OS_WIN)
  66. const LPCWSTR kUniqueTaskBarClassName = L"Shell_TrayWnd";
  67. void FlipWindowStyle(HWND handle, bool on, DWORD flag) {
  68. DWORD style = ::GetWindowLong(handle, GWL_STYLE);
  69. if (on)
  70. style |= flag;
  71. else
  72. style &= ~flag;
  73. ::SetWindowLong(handle, GWL_STYLE, style);
  74. }
  75. // Similar to the ones in display::win::ScreenWin, but with rounded values
  76. // These help to avoid problems that arise from unresizable windows where the
  77. // original ceil()-ed values can cause calculation errors, since converting
  78. // both ways goes through a ceil() call. Related issue: #15816
  79. gfx::Rect ScreenToDIPRect(HWND hwnd, const gfx::Rect& pixel_bounds) {
  80. float scale_factor = display::win::ScreenWin::GetScaleFactorForHWND(hwnd);
  81. gfx::Rect dip_rect = ScaleToRoundedRect(pixel_bounds, 1.0f / scale_factor);
  82. dip_rect.set_origin(
  83. display::win::ScreenWin::ScreenToDIPRect(hwnd, pixel_bounds).origin());
  84. return dip_rect;
  85. }
  86. gfx::Rect DIPToScreenRect(HWND hwnd, const gfx::Rect& pixel_bounds) {
  87. float scale_factor = display::win::ScreenWin::GetScaleFactorForHWND(hwnd);
  88. gfx::Rect screen_rect = ScaleToRoundedRect(pixel_bounds, scale_factor);
  89. screen_rect.set_origin(
  90. display::win::ScreenWin::DIPToScreenRect(hwnd, pixel_bounds).origin());
  91. return screen_rect;
  92. }
  93. #endif
  94. class NativeWindowClientView : public views::ClientView {
  95. public:
  96. NativeWindowClientView(views::Widget* widget,
  97. views::View* root_view,
  98. NativeWindowViews* window)
  99. : views::ClientView(widget, root_view), window_(window) {}
  100. ~NativeWindowClientView() override = default;
  101. bool CanClose() override {
  102. window_->NotifyWindowCloseButtonClicked();
  103. return false;
  104. }
  105. private:
  106. NativeWindowViews* window_;
  107. DISALLOW_COPY_AND_ASSIGN(NativeWindowClientView);
  108. };
  109. } // namespace
  110. NativeWindowViews::NativeWindowViews(const mate::Dictionary& options,
  111. NativeWindow* parent)
  112. : NativeWindow(options, parent),
  113. root_view_(new RootView(this)),
  114. keyboard_event_handler_(new views::UnhandledKeyboardEventHandler) {
  115. options.Get(options::kTitle, &title_);
  116. bool menu_bar_autohide;
  117. if (options.Get(options::kAutoHideMenuBar, &menu_bar_autohide))
  118. root_view_->SetAutoHideMenuBar(menu_bar_autohide);
  119. #if defined(OS_WIN)
  120. // On Windows we rely on the CanResize() to indicate whether window can be
  121. // resized, and it should be set before window is created.
  122. options.Get(options::kResizable, &resizable_);
  123. options.Get(options::kMinimizable, &minimizable_);
  124. options.Get(options::kMaximizable, &maximizable_);
  125. // Transparent window must not have thick frame.
  126. options.Get("thickFrame", &thick_frame_);
  127. if (transparent())
  128. thick_frame_ = false;
  129. #endif
  130. if (enable_larger_than_screen())
  131. // We need to set a default maximum window size here otherwise Windows
  132. // will not allow us to resize the window larger than scree.
  133. // Setting directly to INT_MAX somehow doesn't work, so we just devide
  134. // by 10, which should still be large enough.
  135. SetContentSizeConstraints(extensions::SizeConstraints(
  136. gfx::Size(), gfx::Size(INT_MAX / 10, INT_MAX / 10)));
  137. int width = 800, height = 600;
  138. options.Get(options::kWidth, &width);
  139. options.Get(options::kHeight, &height);
  140. gfx::Rect bounds(0, 0, width, height);
  141. widget_size_ = bounds.size();
  142. widget()->AddObserver(this);
  143. views::Widget::InitParams params;
  144. params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  145. params.bounds = bounds;
  146. params.delegate = this;
  147. params.type = views::Widget::InitParams::TYPE_WINDOW;
  148. params.remove_standard_frame = !has_frame();
  149. if (transparent())
  150. params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW;
  151. // The given window is most likely not rectangular since it uses
  152. // transparency and has no standard frame, don't show a shadow for it.
  153. if (transparent() && !has_frame())
  154. params.shadow_type = views::Widget::InitParams::SHADOW_TYPE_NONE;
  155. bool focusable;
  156. if (options.Get(options::kFocusable, &focusable) && !focusable)
  157. params.activatable = views::Widget::InitParams::ACTIVATABLE_NO;
  158. #if defined(OS_WIN)
  159. if (parent)
  160. params.parent = parent->GetNativeWindow();
  161. params.native_widget = new AtomDesktopNativeWidgetAura(this);
  162. #elif defined(USE_X11)
  163. std::string name = Browser::Get()->GetName();
  164. // Set WM_WINDOW_ROLE.
  165. params.wm_role_name = "browser-window";
  166. // Set WM_CLASS.
  167. params.wm_class_name = base::ToLowerASCII(name);
  168. params.wm_class_class = name;
  169. #endif
  170. widget()->Init(std::move(params));
  171. bool fullscreen = false;
  172. options.Get(options::kFullscreen, &fullscreen);
  173. std::string window_type;
  174. options.Get(options::kType, &window_type);
  175. #if defined(USE_X11)
  176. // Start monitoring window states.
  177. window_state_watcher_.reset(new WindowStateWatcher(this));
  178. // Set _GTK_THEME_VARIANT to dark if we have "dark-theme" option set.
  179. bool use_dark_theme = false;
  180. if (options.Get(options::kDarkTheme, &use_dark_theme) && use_dark_theme) {
  181. SetGTKDarkThemeEnabled(use_dark_theme);
  182. }
  183. // Before the window is mapped the SetWMSpecState can not work, so we have
  184. // to manually set the _NET_WM_STATE.
  185. std::vector<::Atom> state_atom_list;
  186. bool skip_taskbar = false;
  187. if (options.Get(options::kSkipTaskbar, &skip_taskbar) && skip_taskbar) {
  188. state_atom_list.push_back(GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
  189. }
  190. // Before the window is mapped, there is no SHOW_FULLSCREEN_STATE.
  191. if (fullscreen) {
  192. state_atom_list.push_back(GetAtom("_NET_WM_STATE_FULLSCREEN"));
  193. }
  194. if (parent) {
  195. SetParentWindow(parent);
  196. // Force using dialog type for child window.
  197. window_type = "dialog";
  198. // Modal window needs the _NET_WM_STATE_MODAL hint.
  199. if (is_modal())
  200. state_atom_list.push_back(GetAtom("_NET_WM_STATE_MODAL"));
  201. }
  202. if (!state_atom_list.empty())
  203. ui::SetAtomArrayProperty(GetAcceleratedWidget(), "_NET_WM_STATE", "ATOM",
  204. state_atom_list);
  205. // Set the _NET_WM_WINDOW_TYPE.
  206. if (!window_type.empty())
  207. SetWindowType(GetAcceleratedWidget(), window_type);
  208. #endif
  209. #if defined(OS_WIN)
  210. if (!has_frame()) {
  211. // Set Window style so that we get a minimize and maximize animation when
  212. // frameless.
  213. DWORD frame_style = WS_CAPTION | WS_OVERLAPPED;
  214. if (resizable_)
  215. frame_style |= WS_THICKFRAME;
  216. if (minimizable_)
  217. frame_style |= WS_MINIMIZEBOX;
  218. if (maximizable_)
  219. frame_style |= WS_MAXIMIZEBOX;
  220. // We should not show a frame for transparent window.
  221. if (!thick_frame_)
  222. frame_style &= ~(WS_THICKFRAME | WS_CAPTION);
  223. ::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style);
  224. }
  225. LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
  226. if (window_type == "toolbar")
  227. ex_style |= WS_EX_TOOLWINDOW;
  228. ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
  229. #endif
  230. if (has_frame()) {
  231. // TODO(zcbenz): This was used to force using native frame on Windows 2003,
  232. // we should check whether setting it in InitParams can work.
  233. widget()->set_frame_type(views::Widget::FrameType::kForceNative);
  234. widget()->FrameTypeChanged();
  235. #if defined(OS_WIN)
  236. // thickFrame also works for normal window.
  237. if (!thick_frame_)
  238. FlipWindowStyle(GetAcceleratedWidget(), false, WS_THICKFRAME);
  239. #endif
  240. }
  241. // Default content view.
  242. SetContentView(new views::View());
  243. gfx::Size size = bounds.size();
  244. if (has_frame() &&
  245. options.Get(options::kUseContentSize, &use_content_size_) &&
  246. use_content_size_)
  247. size = ContentBoundsToWindowBounds(gfx::Rect(size)).size();
  248. widget()->CenterWindow(size);
  249. #if defined(OS_WIN)
  250. // Save initial window state.
  251. if (fullscreen)
  252. last_window_state_ = ui::SHOW_STATE_FULLSCREEN;
  253. else
  254. last_window_state_ = ui::SHOW_STATE_NORMAL;
  255. #endif
  256. #if defined(OS_LINUX)
  257. // Listen to move events.
  258. aura::Window* window = GetNativeWindow();
  259. if (window)
  260. window->AddPreTargetHandler(this);
  261. #endif
  262. }
  263. NativeWindowViews::~NativeWindowViews() {
  264. widget()->RemoveObserver(this);
  265. #if defined(OS_WIN)
  266. // Disable mouse forwarding to relinquish resources, should any be held.
  267. SetForwardMouseMessages(false);
  268. #endif
  269. #if defined(OS_LINUX)
  270. aura::Window* window = GetNativeWindow();
  271. if (window)
  272. window->RemovePreTargetHandler(this);
  273. #endif
  274. }
  275. void NativeWindowViews::SetGTKDarkThemeEnabled(bool use_dark_theme) {
  276. #if defined(USE_X11)
  277. XDisplay* xdisplay = gfx::GetXDisplay();
  278. if (use_dark_theme) {
  279. XChangeProperty(xdisplay, GetAcceleratedWidget(),
  280. XInternAtom(xdisplay, "_GTK_THEME_VARIANT", x11::False),
  281. XInternAtom(xdisplay, "UTF8_STRING", x11::False), 8,
  282. PropModeReplace,
  283. reinterpret_cast<const unsigned char*>("dark"), 4);
  284. } else {
  285. XChangeProperty(xdisplay, GetAcceleratedWidget(),
  286. XInternAtom(xdisplay, "_GTK_THEME_VARIANT", x11::False),
  287. XInternAtom(xdisplay, "UTF8_STRING", x11::False), 8,
  288. PropModeReplace,
  289. reinterpret_cast<const unsigned char*>("light"), 5);
  290. }
  291. #endif
  292. }
  293. void NativeWindowViews::SetContentView(views::View* view) {
  294. if (content_view()) {
  295. root_view_->RemoveChildView(content_view());
  296. }
  297. set_content_view(view);
  298. focused_view_ = view;
  299. root_view_->AddChildView(content_view());
  300. root_view_->Layout();
  301. }
  302. void NativeWindowViews::Close() {
  303. if (!IsClosable()) {
  304. WindowList::WindowCloseCancelled(this);
  305. return;
  306. }
  307. widget()->Close();
  308. }
  309. void NativeWindowViews::CloseImmediately() {
  310. widget()->CloseNow();
  311. }
  312. void NativeWindowViews::Focus(bool focus) {
  313. // For hidden window focus() should do nothing.
  314. if (!IsVisible())
  315. return;
  316. if (focus) {
  317. widget()->Activate();
  318. } else {
  319. widget()->Deactivate();
  320. }
  321. }
  322. bool NativeWindowViews::IsFocused() {
  323. return widget()->IsActive();
  324. }
  325. void NativeWindowViews::Show() {
  326. if (is_modal() && NativeWindow::parent() &&
  327. !widget()->native_widget_private()->IsVisible())
  328. static_cast<NativeWindowViews*>(parent())->IncrementChildModals();
  329. widget()->native_widget_private()->Show(GetRestoredState(), gfx::Rect());
  330. // explicitly focus the window
  331. widget()->Activate();
  332. NotifyWindowShow();
  333. #if defined(USE_X11)
  334. if (global_menu_bar_)
  335. global_menu_bar_->OnWindowMapped();
  336. #endif
  337. }
  338. void NativeWindowViews::ShowInactive() {
  339. widget()->ShowInactive();
  340. NotifyWindowShow();
  341. #if defined(USE_X11)
  342. if (global_menu_bar_)
  343. global_menu_bar_->OnWindowMapped();
  344. #endif
  345. }
  346. void NativeWindowViews::Hide() {
  347. if (is_modal() && NativeWindow::parent())
  348. static_cast<NativeWindowViews*>(parent())->DecrementChildModals();
  349. widget()->Hide();
  350. NotifyWindowHide();
  351. #if defined(USE_X11)
  352. if (global_menu_bar_)
  353. global_menu_bar_->OnWindowUnmapped();
  354. #endif
  355. }
  356. bool NativeWindowViews::IsVisible() {
  357. return widget()->IsVisible();
  358. }
  359. bool NativeWindowViews::IsEnabled() {
  360. #if defined(OS_WIN)
  361. return ::IsWindowEnabled(GetAcceleratedWidget());
  362. #elif defined(USE_X11)
  363. return !event_disabler_.get();
  364. #endif
  365. }
  366. void NativeWindowViews::IncrementChildModals() {
  367. num_modal_children_++;
  368. SetEnabledInternal(ShouldBeEnabled());
  369. }
  370. void NativeWindowViews::DecrementChildModals() {
  371. if (num_modal_children_ > 0) {
  372. num_modal_children_--;
  373. }
  374. SetEnabledInternal(ShouldBeEnabled());
  375. }
  376. void NativeWindowViews::SetEnabled(bool enable) {
  377. if (enable != is_enabled_) {
  378. is_enabled_ = enable;
  379. SetEnabledInternal(ShouldBeEnabled());
  380. }
  381. }
  382. bool NativeWindowViews::ShouldBeEnabled() {
  383. return is_enabled_ && (num_modal_children_ == 0);
  384. }
  385. void NativeWindowViews::SetEnabledInternal(bool enable) {
  386. if (enable && IsEnabled()) {
  387. return;
  388. } else if (!enable && !IsEnabled()) {
  389. return;
  390. }
  391. #if defined(OS_WIN)
  392. ::EnableWindow(GetAcceleratedWidget(), enable);
  393. #elif defined(USE_X11)
  394. views::DesktopWindowTreeHostX11* tree_host =
  395. views::DesktopWindowTreeHostX11::GetHostForXID(GetAcceleratedWidget());
  396. if (enable) {
  397. tree_host->RemoveEventRewriter(event_disabler_.get());
  398. event_disabler_.reset();
  399. } else {
  400. event_disabler_.reset(new EventDisabler);
  401. tree_host->AddEventRewriter(event_disabler_.get());
  402. }
  403. #endif
  404. }
  405. #if defined(USE_X11)
  406. void NativeWindowViews::Maximize() {
  407. if (IsVisible())
  408. widget()->Maximize();
  409. else
  410. widget()->native_widget_private()->Show(ui::SHOW_STATE_MAXIMIZED,
  411. gfx::Rect());
  412. }
  413. #endif
  414. void NativeWindowViews::Unmaximize() {
  415. #if defined(OS_WIN)
  416. if (!(::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME)) {
  417. SetBounds(restore_bounds_, false);
  418. return;
  419. }
  420. #endif
  421. widget()->Restore();
  422. }
  423. bool NativeWindowViews::IsMaximized() {
  424. return widget()->IsMaximized();
  425. }
  426. void NativeWindowViews::Minimize() {
  427. if (IsVisible())
  428. widget()->Minimize();
  429. else
  430. widget()->native_widget_private()->Show(ui::SHOW_STATE_MINIMIZED,
  431. gfx::Rect());
  432. }
  433. void NativeWindowViews::Restore() {
  434. widget()->Restore();
  435. }
  436. bool NativeWindowViews::IsMinimized() {
  437. return widget()->IsMinimized();
  438. }
  439. void NativeWindowViews::SetFullScreen(bool fullscreen) {
  440. if (!IsFullScreenable())
  441. return;
  442. #if defined(OS_WIN)
  443. // There is no native fullscreen state on Windows.
  444. bool leaving_fullscreen = IsFullscreen() && !fullscreen;
  445. if (fullscreen) {
  446. last_window_state_ = ui::SHOW_STATE_FULLSCREEN;
  447. NotifyWindowEnterFullScreen();
  448. } else {
  449. last_window_state_ = ui::SHOW_STATE_NORMAL;
  450. NotifyWindowLeaveFullScreen();
  451. }
  452. // For window without WS_THICKFRAME style, we can not call SetFullscreen().
  453. // This path will be used for transparent windows as well.
  454. if (!thick_frame_) {
  455. if (fullscreen) {
  456. restore_bounds_ = GetBounds();
  457. auto display =
  458. display::Screen::GetScreen()->GetDisplayNearestPoint(GetPosition());
  459. SetBounds(display.bounds(), false);
  460. } else {
  461. SetBounds(restore_bounds_, false);
  462. }
  463. return;
  464. }
  465. // We set the new value after notifying, so we can handle the size event
  466. // correctly.
  467. widget()->SetFullscreen(fullscreen);
  468. // If restoring from fullscreen and the window isn't visible, force visible,
  469. // else a non-responsive window shell could be rendered.
  470. // (this situation may arise when app starts with fullscreen: true)
  471. // Note: the following must be after "widget()->SetFullscreen(fullscreen);"
  472. if (leaving_fullscreen && !IsVisible())
  473. FlipWindowStyle(GetAcceleratedWidget(), true, WS_VISIBLE);
  474. #else
  475. if (IsVisible())
  476. widget()->SetFullscreen(fullscreen);
  477. else if (fullscreen)
  478. widget()->native_widget_private()->Show(ui::SHOW_STATE_FULLSCREEN,
  479. gfx::Rect());
  480. // Auto-hide menubar when in fullscreen.
  481. if (fullscreen)
  482. SetMenuBarVisibility(false);
  483. else
  484. SetMenuBarVisibility(!IsMenuBarAutoHide());
  485. #endif
  486. }
  487. bool NativeWindowViews::IsFullscreen() const {
  488. return widget()->IsFullscreen();
  489. }
  490. void NativeWindowViews::SetBounds(const gfx::Rect& bounds, bool animate) {
  491. #if defined(OS_WIN) || defined(USE_X11)
  492. // On Linux and Windows the minimum and maximum size should be updated with
  493. // window size when window is not resizable.
  494. if (!resizable_) {
  495. SetMaximumSize(bounds.size());
  496. SetMinimumSize(bounds.size());
  497. }
  498. #endif
  499. widget()->SetBounds(bounds);
  500. }
  501. gfx::Rect NativeWindowViews::GetBounds() {
  502. #if defined(OS_WIN)
  503. if (IsMinimized())
  504. return widget()->GetRestoredBounds();
  505. #endif
  506. return widget()->GetWindowBoundsInScreen();
  507. }
  508. gfx::Rect NativeWindowViews::GetContentBounds() {
  509. return content_view() ? content_view()->GetBoundsInScreen() : gfx::Rect();
  510. }
  511. gfx::Size NativeWindowViews::GetContentSize() {
  512. #if defined(OS_WIN)
  513. if (IsMinimized())
  514. return NativeWindow::GetContentSize();
  515. #endif
  516. return content_view() ? content_view()->size() : gfx::Size();
  517. }
  518. gfx::Rect NativeWindowViews::GetNormalBounds() {
  519. return widget()->GetRestoredBounds();
  520. }
  521. void NativeWindowViews::SetContentSizeConstraints(
  522. const extensions::SizeConstraints& size_constraints) {
  523. NativeWindow::SetContentSizeConstraints(size_constraints);
  524. #if defined(OS_WIN)
  525. // Changing size constraints would force adding the WS_THICKFRAME style, so
  526. // do nothing if thickFrame is false.
  527. if (!thick_frame_)
  528. return;
  529. #endif
  530. // widget_delegate() is only available after Init() is called, we make use of
  531. // this to determine whether native widget has initialized.
  532. if (widget() && widget()->widget_delegate())
  533. widget()->OnSizeConstraintsChanged();
  534. if (resizable_)
  535. old_size_constraints_ = size_constraints;
  536. }
  537. void NativeWindowViews::SetResizable(bool resizable) {
  538. if (resizable != resizable_) {
  539. // On Linux there is no "resizable" property of a window, we have to set
  540. // both the minimum and maximum size to the window size to achieve it.
  541. if (resizable) {
  542. SetContentSizeConstraints(old_size_constraints_);
  543. SetMaximizable(maximizable_);
  544. } else {
  545. old_size_constraints_ = GetContentSizeConstraints();
  546. resizable_ = false;
  547. gfx::Size content_size = GetContentSize();
  548. SetContentSizeConstraints(
  549. extensions::SizeConstraints(content_size, content_size));
  550. }
  551. }
  552. #if defined(OS_WIN)
  553. if (has_frame() && thick_frame_)
  554. FlipWindowStyle(GetAcceleratedWidget(), resizable, WS_THICKFRAME);
  555. #endif
  556. resizable_ = resizable;
  557. }
  558. void NativeWindowViews::MoveTop() {
  559. // TODO(julien.isorce): fix chromium in order to use existing
  560. // widget()->StackAtTop().
  561. #if defined(OS_WIN)
  562. gfx::Point pos = GetPosition();
  563. gfx::Size size = GetSize();
  564. ::SetWindowPos(GetAcceleratedWidget(), HWND_TOP, pos.x(), pos.y(),
  565. size.width(), size.height(),
  566. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  567. #elif defined(USE_X11)
  568. electron::MoveWindowToForeground(GetAcceleratedWidget());
  569. #endif
  570. }
  571. bool NativeWindowViews::IsResizable() {
  572. #if defined(OS_WIN)
  573. if (has_frame())
  574. return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME;
  575. #endif
  576. return CanResize();
  577. }
  578. void NativeWindowViews::SetMovable(bool movable) {
  579. movable_ = movable;
  580. }
  581. bool NativeWindowViews::IsMovable() {
  582. #if defined(OS_WIN)
  583. return movable_;
  584. #else
  585. return true; // Not implemented on Linux.
  586. #endif
  587. }
  588. void NativeWindowViews::SetMinimizable(bool minimizable) {
  589. #if defined(OS_WIN)
  590. FlipWindowStyle(GetAcceleratedWidget(), minimizable, WS_MINIMIZEBOX);
  591. #endif
  592. minimizable_ = minimizable;
  593. }
  594. bool NativeWindowViews::IsMinimizable() {
  595. #if defined(OS_WIN)
  596. return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_MINIMIZEBOX;
  597. #else
  598. return true; // Not implemented on Linux.
  599. #endif
  600. }
  601. void NativeWindowViews::SetMaximizable(bool maximizable) {
  602. #if defined(OS_WIN)
  603. FlipWindowStyle(GetAcceleratedWidget(), maximizable, WS_MAXIMIZEBOX);
  604. #endif
  605. maximizable_ = maximizable;
  606. }
  607. bool NativeWindowViews::IsMaximizable() {
  608. #if defined(OS_WIN)
  609. return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_MAXIMIZEBOX;
  610. #else
  611. return true; // Not implemented on Linux.
  612. #endif
  613. }
  614. void NativeWindowViews::SetExcludedFromShownWindowsMenu(bool excluded) {}
  615. bool NativeWindowViews::IsExcludedFromShownWindowsMenu() {
  616. // return false on unsupported platforms
  617. return false;
  618. }
  619. void NativeWindowViews::SetFullScreenable(bool fullscreenable) {
  620. fullscreenable_ = fullscreenable;
  621. }
  622. bool NativeWindowViews::IsFullScreenable() {
  623. return fullscreenable_;
  624. }
  625. void NativeWindowViews::SetClosable(bool closable) {
  626. #if defined(OS_WIN)
  627. HMENU menu = GetSystemMenu(GetAcceleratedWidget(), false);
  628. if (closable) {
  629. EnableMenuItem(menu, SC_CLOSE, MF_BYCOMMAND | MF_ENABLED);
  630. } else {
  631. EnableMenuItem(menu, SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  632. }
  633. #endif
  634. }
  635. bool NativeWindowViews::IsClosable() {
  636. #if defined(OS_WIN)
  637. HMENU menu = GetSystemMenu(GetAcceleratedWidget(), false);
  638. MENUITEMINFO info;
  639. memset(&info, 0, sizeof(info));
  640. info.cbSize = sizeof(info);
  641. info.fMask = MIIM_STATE;
  642. if (!GetMenuItemInfo(menu, SC_CLOSE, false, &info)) {
  643. return false;
  644. }
  645. return !(info.fState & MFS_DISABLED);
  646. #elif defined(USE_X11)
  647. return true;
  648. #endif
  649. }
  650. void NativeWindowViews::SetAlwaysOnTop(ui::ZOrderLevel z_order,
  651. const std::string& level,
  652. int relativeLevel,
  653. std::string* error) {
  654. bool level_changed = z_order != widget()->GetZOrderLevel();
  655. widget()->SetZOrderLevel(z_order);
  656. #if defined(OS_WIN)
  657. // Reset the placement flag.
  658. behind_task_bar_ = false;
  659. if (z_order != ui::ZOrderLevel::kNormal) {
  660. // On macOS the window is placed behind the Dock for the following levels.
  661. // Re-use the same names on Windows to make it easier for the user.
  662. static const std::vector<std::string> levels = {
  663. "floating", "torn-off-menu", "modal-panel", "main-menu", "status"};
  664. behind_task_bar_ = base::Contains(levels, level);
  665. }
  666. #endif
  667. MoveBehindTaskBarIfNeeded();
  668. // This must be notified at the very end or IsAlwaysOnTop
  669. // will not yet have been updated to reflect the new status
  670. if (level_changed)
  671. NativeWindow::NotifyWindowAlwaysOnTopChanged();
  672. }
  673. ui::ZOrderLevel NativeWindowViews::GetZOrderLevel() {
  674. return widget()->GetZOrderLevel();
  675. }
  676. void NativeWindowViews::Center() {
  677. widget()->CenterWindow(GetSize());
  678. }
  679. void NativeWindowViews::Invalidate() {
  680. widget()->SchedulePaintInRect(gfx::Rect(GetBounds().size()));
  681. }
  682. void NativeWindowViews::SetTitle(const std::string& title) {
  683. title_ = title;
  684. widget()->UpdateWindowTitle();
  685. }
  686. std::string NativeWindowViews::GetTitle() {
  687. return title_;
  688. }
  689. void NativeWindowViews::FlashFrame(bool flash) {
  690. #if defined(OS_WIN)
  691. // The Chromium's implementation has a bug stopping flash.
  692. if (!flash) {
  693. FLASHWINFO fwi;
  694. fwi.cbSize = sizeof(fwi);
  695. fwi.hwnd = GetAcceleratedWidget();
  696. fwi.dwFlags = FLASHW_STOP;
  697. fwi.uCount = 0;
  698. FlashWindowEx(&fwi);
  699. return;
  700. }
  701. #endif
  702. widget()->FlashFrame(flash);
  703. }
  704. void NativeWindowViews::SetSkipTaskbar(bool skip) {
  705. #if defined(OS_WIN)
  706. Microsoft::WRL::ComPtr<ITaskbarList> taskbar;
  707. if (FAILED(::CoCreateInstance(CLSID_TaskbarList, nullptr,
  708. CLSCTX_INPROC_SERVER,
  709. IID_PPV_ARGS(&taskbar))) ||
  710. FAILED(taskbar->HrInit()))
  711. return;
  712. if (skip) {
  713. taskbar->DeleteTab(GetAcceleratedWidget());
  714. } else {
  715. taskbar->AddTab(GetAcceleratedWidget());
  716. taskbar_host_.RestoreThumbarButtons(GetAcceleratedWidget());
  717. }
  718. #elif defined(USE_X11)
  719. SetWMSpecState(GetAcceleratedWidget(), skip,
  720. GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
  721. #endif
  722. }
  723. void NativeWindowViews::SetSimpleFullScreen(bool simple_fullscreen) {
  724. SetFullScreen(simple_fullscreen);
  725. }
  726. bool NativeWindowViews::IsSimpleFullScreen() {
  727. return IsFullscreen();
  728. }
  729. void NativeWindowViews::SetKiosk(bool kiosk) {
  730. SetFullScreen(kiosk);
  731. }
  732. bool NativeWindowViews::IsKiosk() {
  733. return IsFullscreen();
  734. }
  735. void NativeWindowViews::SetBackgroundColor(SkColor background_color) {
  736. // web views' background color.
  737. root_view_->SetBackground(views::CreateSolidBackground(background_color));
  738. #if defined(OS_WIN)
  739. // Set the background color of native window.
  740. HBRUSH brush = CreateSolidBrush(skia::SkColorToCOLORREF(background_color));
  741. ULONG_PTR previous_brush =
  742. SetClassLongPtr(GetAcceleratedWidget(), GCLP_HBRBACKGROUND,
  743. reinterpret_cast<LONG_PTR>(brush));
  744. if (previous_brush)
  745. DeleteObject((HBRUSH)previous_brush);
  746. InvalidateRect(GetAcceleratedWidget(), NULL, 1);
  747. #endif
  748. }
  749. void NativeWindowViews::SetHasShadow(bool has_shadow) {
  750. wm::SetShadowElevation(GetNativeWindow(),
  751. has_shadow ? wm::kShadowElevationInactiveWindow
  752. : wm::kShadowElevationNone);
  753. }
  754. bool NativeWindowViews::HasShadow() {
  755. return GetNativeWindow()->GetProperty(wm::kShadowElevationKey) !=
  756. wm::kShadowElevationNone;
  757. }
  758. void NativeWindowViews::SetOpacity(const double opacity) {
  759. #if defined(OS_WIN)
  760. const double boundedOpacity = base::ClampToRange(opacity, 0.0, 1.0);
  761. HWND hwnd = GetAcceleratedWidget();
  762. if (!layered_) {
  763. LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
  764. ex_style |= WS_EX_LAYERED;
  765. ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
  766. layered_ = true;
  767. }
  768. ::SetLayeredWindowAttributes(hwnd, 0, boundedOpacity * 255, LWA_ALPHA);
  769. opacity_ = boundedOpacity;
  770. #else
  771. opacity_ = 1.0; // setOpacity unsupported on Linux
  772. #endif
  773. }
  774. double NativeWindowViews::GetOpacity() {
  775. return opacity_;
  776. }
  777. void NativeWindowViews::SetIgnoreMouseEvents(bool ignore, bool forward) {
  778. #if defined(OS_WIN)
  779. LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
  780. if (ignore)
  781. ex_style |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
  782. else
  783. ex_style &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED);
  784. if (layered_)
  785. ex_style |= WS_EX_LAYERED;
  786. ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
  787. // Forwarding is always disabled when not ignoring mouse messages.
  788. if (!ignore) {
  789. SetForwardMouseMessages(false);
  790. } else {
  791. SetForwardMouseMessages(forward);
  792. }
  793. #elif defined(USE_X11)
  794. if (ignore) {
  795. XRectangle r = {0, 0, 1, 1};
  796. XShapeCombineRectangles(gfx::GetXDisplay(), GetAcceleratedWidget(),
  797. ShapeInput, 0, 0, &r, 1, ShapeSet, YXBanded);
  798. } else {
  799. XShapeCombineMask(gfx::GetXDisplay(), GetAcceleratedWidget(), ShapeInput, 0,
  800. 0, x11::None, ShapeSet);
  801. }
  802. #endif
  803. }
  804. void NativeWindowViews::SetContentProtection(bool enable) {
  805. #if defined(OS_WIN)
  806. DWORD affinity = enable ? WDA_MONITOR : WDA_NONE;
  807. ::SetWindowDisplayAffinity(GetAcceleratedWidget(), affinity);
  808. #endif
  809. }
  810. void NativeWindowViews::SetFocusable(bool focusable) {
  811. widget()->widget_delegate()->SetCanActivate(focusable);
  812. #if defined(OS_WIN)
  813. LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
  814. if (focusable)
  815. ex_style &= ~WS_EX_NOACTIVATE;
  816. else
  817. ex_style |= WS_EX_NOACTIVATE;
  818. ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
  819. SetSkipTaskbar(!focusable);
  820. Focus(false);
  821. #endif
  822. }
  823. void NativeWindowViews::SetMenu(AtomMenuModel* menu_model) {
  824. #if defined(USE_X11)
  825. // Remove global menu bar.
  826. if (global_menu_bar_ && menu_model == nullptr) {
  827. global_menu_bar_.reset();
  828. root_view_->UnregisterAcceleratorsWithFocusManager();
  829. return;
  830. }
  831. // Use global application menu bar when possible.
  832. if (ShouldUseGlobalMenuBar()) {
  833. if (!global_menu_bar_)
  834. global_menu_bar_.reset(new GlobalMenuBarX11(this));
  835. if (global_menu_bar_->IsServerStarted()) {
  836. root_view_->RegisterAcceleratorsWithFocusManager(menu_model);
  837. global_menu_bar_->SetMenu(menu_model);
  838. return;
  839. }
  840. }
  841. #endif
  842. // Should reset content size when setting menu.
  843. gfx::Size content_size = GetContentSize();
  844. bool should_reset_size = use_content_size_ && has_frame() &&
  845. !IsMenuBarAutoHide() &&
  846. ((!!menu_model) != root_view_->HasMenu());
  847. root_view_->SetMenu(menu_model);
  848. if (should_reset_size) {
  849. // Enlarge the size constraints for the menu.
  850. int menu_bar_height = root_view_->GetMenuBarHeight();
  851. extensions::SizeConstraints constraints = GetContentSizeConstraints();
  852. if (constraints.HasMinimumSize()) {
  853. gfx::Size min_size = constraints.GetMinimumSize();
  854. min_size.set_height(min_size.height() + menu_bar_height);
  855. constraints.set_minimum_size(min_size);
  856. }
  857. if (constraints.HasMaximumSize()) {
  858. gfx::Size max_size = constraints.GetMaximumSize();
  859. max_size.set_height(max_size.height() + menu_bar_height);
  860. constraints.set_maximum_size(max_size);
  861. }
  862. SetContentSizeConstraints(constraints);
  863. // Resize the window to make sure content size is not changed.
  864. SetContentSize(content_size);
  865. }
  866. }
  867. void NativeWindowViews::AddBrowserView(NativeBrowserView* view) {
  868. if (!content_view())
  869. return;
  870. if (!view) {
  871. return;
  872. }
  873. add_browser_view(view);
  874. content_view()->AddChildView(
  875. view->GetInspectableWebContentsView()->GetView());
  876. }
  877. void NativeWindowViews::RemoveBrowserView(NativeBrowserView* view) {
  878. if (!content_view())
  879. return;
  880. if (!view) {
  881. return;
  882. }
  883. content_view()->RemoveChildView(
  884. view->GetInspectableWebContentsView()->GetView());
  885. remove_browser_view(view);
  886. }
  887. void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
  888. NativeWindow::SetParentWindow(parent);
  889. #if defined(USE_X11)
  890. XDisplay* xdisplay = gfx::GetXDisplay();
  891. XSetTransientForHint(
  892. xdisplay, GetAcceleratedWidget(),
  893. parent ? parent->GetAcceleratedWidget() : DefaultRootWindow(xdisplay));
  894. #elif defined(OS_WIN)
  895. // To set parentship between windows into Windows is better to play with the
  896. // owner instead of the parent, as Windows natively seems to do if a parent
  897. // is specified at window creation time.
  898. // For do this we must NOT use the ::SetParent function, instead we must use
  899. // the ::GetWindowLongPtr or ::SetWindowLongPtr functions with "nIndex" set
  900. // to "GWLP_HWNDPARENT" which actually means the window owner.
  901. HWND hwndParent = parent ? parent->GetAcceleratedWidget() : NULL;
  902. if (hwndParent ==
  903. (HWND)::GetWindowLongPtr(GetAcceleratedWidget(), GWLP_HWNDPARENT))
  904. return;
  905. ::SetWindowLongPtr(GetAcceleratedWidget(), GWLP_HWNDPARENT,
  906. (LONG_PTR)hwndParent);
  907. // Ensures the visibility
  908. if (IsVisible()) {
  909. WINDOWPLACEMENT wp;
  910. wp.length = sizeof(WINDOWPLACEMENT);
  911. ::GetWindowPlacement(GetAcceleratedWidget(), &wp);
  912. ::ShowWindow(GetAcceleratedWidget(), SW_HIDE);
  913. ::ShowWindow(GetAcceleratedWidget(), wp.showCmd);
  914. ::BringWindowToTop(GetAcceleratedWidget());
  915. }
  916. #endif
  917. }
  918. gfx::NativeView NativeWindowViews::GetNativeView() const {
  919. return widget()->GetNativeView();
  920. }
  921. gfx::NativeWindow NativeWindowViews::GetNativeWindow() const {
  922. return widget()->GetNativeWindow();
  923. }
  924. void NativeWindowViews::SetProgressBar(double progress,
  925. NativeWindow::ProgressState state) {
  926. #if defined(OS_WIN)
  927. taskbar_host_.SetProgressBar(GetAcceleratedWidget(), progress, state);
  928. #elif defined(USE_X11)
  929. if (unity::IsRunning()) {
  930. unity::SetProgressFraction(progress);
  931. }
  932. #endif
  933. }
  934. void NativeWindowViews::SetOverlayIcon(const gfx::Image& overlay,
  935. const std::string& description) {
  936. #if defined(OS_WIN)
  937. taskbar_host_.SetOverlayIcon(GetAcceleratedWidget(), overlay, description);
  938. #endif
  939. }
  940. void NativeWindowViews::SetAutoHideMenuBar(bool auto_hide) {
  941. root_view_->SetAutoHideMenuBar(auto_hide);
  942. }
  943. bool NativeWindowViews::IsMenuBarAutoHide() {
  944. return root_view_->IsMenuBarAutoHide();
  945. }
  946. void NativeWindowViews::SetMenuBarVisibility(bool visible) {
  947. root_view_->SetMenuBarVisibility(visible);
  948. }
  949. bool NativeWindowViews::IsMenuBarVisible() {
  950. return root_view_->IsMenuBarVisible();
  951. }
  952. void NativeWindowViews::SetVisibleOnAllWorkspaces(bool visible,
  953. bool visibleOnFullScreen) {
  954. widget()->SetVisibleOnAllWorkspaces(visible);
  955. }
  956. bool NativeWindowViews::IsVisibleOnAllWorkspaces() {
  957. #if defined(USE_X11)
  958. // Use the presence/absence of _NET_WM_STATE_STICKY in _NET_WM_STATE to
  959. // determine whether the current window is visible on all workspaces.
  960. XAtom sticky_atom = GetAtom("_NET_WM_STATE_STICKY");
  961. std::vector<XAtom> wm_states;
  962. ui::GetAtomArrayProperty(GetAcceleratedWidget(), "_NET_WM_STATE", &wm_states);
  963. return std::find(wm_states.begin(), wm_states.end(), sticky_atom) !=
  964. wm_states.end();
  965. #endif
  966. return false;
  967. }
  968. gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() const {
  969. if (GetNativeWindow() && GetNativeWindow()->GetHost())
  970. return GetNativeWindow()->GetHost()->GetAcceleratedWidget();
  971. else
  972. return gfx::kNullAcceleratedWidget;
  973. }
  974. NativeWindowHandle NativeWindowViews::GetNativeWindowHandle() const {
  975. return GetAcceleratedWidget();
  976. }
  977. gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
  978. const gfx::Rect& bounds) const {
  979. if (!has_frame())
  980. return bounds;
  981. gfx::Rect window_bounds(bounds);
  982. #if defined(OS_WIN)
  983. HWND hwnd = GetAcceleratedWidget();
  984. gfx::Rect dpi_bounds = DIPToScreenRect(hwnd, bounds);
  985. window_bounds = ScreenToDIPRect(
  986. hwnd,
  987. widget()->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds));
  988. #endif
  989. if (root_view_->HasMenu() && root_view_->IsMenuBarVisible()) {
  990. int menu_bar_height = root_view_->GetMenuBarHeight();
  991. window_bounds.set_y(window_bounds.y() - menu_bar_height);
  992. window_bounds.set_height(window_bounds.height() + menu_bar_height);
  993. }
  994. return window_bounds;
  995. }
  996. gfx::Rect NativeWindowViews::WindowBoundsToContentBounds(
  997. const gfx::Rect& bounds) const {
  998. if (!has_frame())
  999. return bounds;
  1000. gfx::Rect content_bounds(bounds);
  1001. #if defined(OS_WIN)
  1002. HWND hwnd = GetAcceleratedWidget();
  1003. content_bounds.set_size(DIPToScreenRect(hwnd, content_bounds).size());
  1004. RECT rect;
  1005. SetRectEmpty(&rect);
  1006. DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
  1007. DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
  1008. AdjustWindowRectEx(&rect, style, FALSE, ex_style);
  1009. content_bounds.set_width(content_bounds.width() - (rect.right - rect.left));
  1010. content_bounds.set_height(content_bounds.height() - (rect.bottom - rect.top));
  1011. content_bounds.set_size(ScreenToDIPRect(hwnd, content_bounds).size());
  1012. #endif
  1013. if (root_view_->HasMenu() && root_view_->IsMenuBarVisible()) {
  1014. int menu_bar_height = root_view_->GetMenuBarHeight();
  1015. content_bounds.set_y(content_bounds.y() + menu_bar_height);
  1016. content_bounds.set_height(content_bounds.height() - menu_bar_height);
  1017. }
  1018. return content_bounds;
  1019. }
  1020. void NativeWindowViews::UpdateDraggableRegions(
  1021. std::unique_ptr<SkRegion> region) {
  1022. draggable_region_ = std::move(region);
  1023. }
  1024. #if defined(OS_WIN)
  1025. void NativeWindowViews::SetIcon(HICON window_icon, HICON app_icon) {
  1026. // We are responsible for storing the images.
  1027. window_icon_ = base::win::ScopedHICON(CopyIcon(window_icon));
  1028. app_icon_ = base::win::ScopedHICON(CopyIcon(app_icon));
  1029. HWND hwnd = GetAcceleratedWidget();
  1030. SendMessage(hwnd, WM_SETICON, ICON_SMALL,
  1031. reinterpret_cast<LPARAM>(window_icon_.get()));
  1032. SendMessage(hwnd, WM_SETICON, ICON_BIG,
  1033. reinterpret_cast<LPARAM>(app_icon_.get()));
  1034. }
  1035. #elif defined(USE_X11)
  1036. void NativeWindowViews::SetIcon(const gfx::ImageSkia& icon) {
  1037. auto* tree_host = static_cast<views::DesktopWindowTreeHost*>(
  1038. views::DesktopWindowTreeHostX11::GetHostForXID(GetAcceleratedWidget()));
  1039. tree_host->SetWindowIcons(icon, icon);
  1040. }
  1041. #endif
  1042. void NativeWindowViews::OnWidgetActivationChanged(views::Widget* changed_widget,
  1043. bool active) {
  1044. if (changed_widget != widget())
  1045. return;
  1046. if (active) {
  1047. MoveBehindTaskBarIfNeeded();
  1048. NativeWindow::NotifyWindowFocus();
  1049. } else {
  1050. NativeWindow::NotifyWindowBlur();
  1051. }
  1052. // Hide menu bar when window is blured.
  1053. if (!active && IsMenuBarAutoHide() && IsMenuBarVisible())
  1054. SetMenuBarVisibility(false);
  1055. root_view_->ResetAltState();
  1056. }
  1057. void NativeWindowViews::OnWidgetBoundsChanged(views::Widget* changed_widget,
  1058. const gfx::Rect& bounds) {
  1059. if (changed_widget != widget())
  1060. return;
  1061. // Note: We intentionally use `GetBounds()` instead of `bounds` to properly
  1062. // handle minimized windows on Windows.
  1063. const auto new_bounds = GetBounds();
  1064. if (widget_size_ != new_bounds.size()) {
  1065. int width_delta = new_bounds.width() - widget_size_.width();
  1066. int height_delta = new_bounds.height() - widget_size_.height();
  1067. for (NativeBrowserView* item : browser_views()) {
  1068. NativeBrowserViewViews* native_view =
  1069. static_cast<NativeBrowserViewViews*>(item);
  1070. native_view->SetAutoResizeProportions(widget_size_);
  1071. native_view->AutoResize(new_bounds, width_delta, height_delta);
  1072. }
  1073. NotifyWindowResize();
  1074. widget_size_ = new_bounds.size();
  1075. }
  1076. }
  1077. void NativeWindowViews::OnWidgetDestroying(views::Widget* widget) {
  1078. #if defined(OS_LINUX)
  1079. aura::Window* window = GetNativeWindow();
  1080. if (window)
  1081. window->RemovePreTargetHandler(this);
  1082. #endif
  1083. }
  1084. void NativeWindowViews::DeleteDelegate() {
  1085. if (is_modal() && this->parent()) {
  1086. auto* parent = this->parent();
  1087. // Enable parent window after current window gets closed.
  1088. static_cast<NativeWindowViews*>(parent)->DecrementChildModals();
  1089. // Focus on parent window.
  1090. parent->Focus(true);
  1091. }
  1092. NotifyWindowClosed();
  1093. }
  1094. views::View* NativeWindowViews::GetInitiallyFocusedView() {
  1095. return focused_view_;
  1096. }
  1097. bool NativeWindowViews::CanResize() const {
  1098. return resizable_;
  1099. }
  1100. bool NativeWindowViews::CanMaximize() const {
  1101. return resizable_ && maximizable_;
  1102. }
  1103. bool NativeWindowViews::CanMinimize() const {
  1104. #if defined(OS_WIN)
  1105. return minimizable_;
  1106. #elif defined(USE_X11)
  1107. return true;
  1108. #endif
  1109. }
  1110. base::string16 NativeWindowViews::GetWindowTitle() const {
  1111. return base::UTF8ToUTF16(title_);
  1112. }
  1113. views::View* NativeWindowViews::GetContentsView() {
  1114. return root_view_.get();
  1115. }
  1116. bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
  1117. gfx::NativeView child,
  1118. const gfx::Point& location) {
  1119. // App window should claim mouse events that fall within the draggable region.
  1120. if (draggable_region() &&
  1121. draggable_region()->contains(location.x(), location.y()))
  1122. return false;
  1123. // And the events on border for dragging resizable frameless window.
  1124. if (!has_frame() && CanResize()) {
  1125. FramelessView* frame =
  1126. static_cast<FramelessView*>(widget()->non_client_view()->frame_view());
  1127. return frame->ResizingBorderHitTest(location) == HTNOWHERE;
  1128. }
  1129. return true;
  1130. }
  1131. views::ClientView* NativeWindowViews::CreateClientView(views::Widget* widget) {
  1132. return new NativeWindowClientView(widget, root_view_.get(), this);
  1133. }
  1134. views::NonClientFrameView* NativeWindowViews::CreateNonClientFrameView(
  1135. views::Widget* widget) {
  1136. #if defined(OS_WIN)
  1137. WinFrameView* frame_view = new WinFrameView;
  1138. frame_view->Init(this, widget);
  1139. return frame_view;
  1140. #else
  1141. if (has_frame()) {
  1142. return new NativeFrameView(this, widget);
  1143. } else {
  1144. FramelessView* frame_view = new FramelessView;
  1145. frame_view->Init(this, widget);
  1146. return frame_view;
  1147. }
  1148. #endif
  1149. }
  1150. void NativeWindowViews::OnWidgetMove() {
  1151. NotifyWindowMove();
  1152. }
  1153. void NativeWindowViews::HandleKeyboardEvent(
  1154. content::WebContents*,
  1155. const content::NativeWebKeyboardEvent& event) {
  1156. #if defined(OS_LINUX)
  1157. if (event.windows_key_code == ui::VKEY_BROWSER_BACK)
  1158. NotifyWindowExecuteAppCommand(kBrowserBackward);
  1159. else if (event.windows_key_code == ui::VKEY_BROWSER_FORWARD)
  1160. NotifyWindowExecuteAppCommand(kBrowserForward);
  1161. #endif
  1162. keyboard_event_handler_->HandleKeyboardEvent(event,
  1163. root_view_->GetFocusManager());
  1164. root_view_->HandleKeyEvent(event);
  1165. }
  1166. #if defined(OS_LINUX)
  1167. void NativeWindowViews::OnMouseEvent(ui::MouseEvent* event) {
  1168. if (event->type() != ui::ET_MOUSE_PRESSED)
  1169. return;
  1170. if (event->changed_button_flags() == ui::EF_BACK_MOUSE_BUTTON)
  1171. NotifyWindowExecuteAppCommand(kBrowserBackward);
  1172. else if (event->changed_button_flags() == ui::EF_FORWARD_MOUSE_BUTTON)
  1173. NotifyWindowExecuteAppCommand(kBrowserForward);
  1174. }
  1175. #endif
  1176. ui::WindowShowState NativeWindowViews::GetRestoredState() {
  1177. if (IsMaximized())
  1178. return ui::SHOW_STATE_MAXIMIZED;
  1179. if (IsFullscreen())
  1180. return ui::SHOW_STATE_FULLSCREEN;
  1181. return ui::SHOW_STATE_NORMAL;
  1182. }
  1183. void NativeWindowViews::MoveBehindTaskBarIfNeeded() {
  1184. #if defined(OS_WIN)
  1185. if (behind_task_bar_) {
  1186. const HWND task_bar_hwnd = ::FindWindow(kUniqueTaskBarClassName, nullptr);
  1187. ::SetWindowPos(GetAcceleratedWidget(), task_bar_hwnd, 0, 0, 0, 0,
  1188. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  1189. }
  1190. #endif
  1191. // TODO(julien.isorce): Implement X11 case.
  1192. }
  1193. // static
  1194. NativeWindow* NativeWindow::Create(const mate::Dictionary& options,
  1195. NativeWindow* parent) {
  1196. return new NativeWindowViews(options, parent);
  1197. }
  1198. } // namespace electron