native_window_views.cc 45 KB

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