native_window_views.cc 48 KB

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