native_window_views.cc 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866
  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. // FIXME(ckerr) this incorrect #include order is a temporary
  5. // fix to unblock the roll. Will fix in an upgrade followup.
  6. #include "ui/base/ozone_buildflags.h"
  7. #if BUILDFLAG(IS_OZONE_X11)
  8. #include "ui/base/x/x11_util.h"
  9. #endif
  10. #include "shell/browser/native_window_views.h"
  11. #if BUILDFLAG(IS_WIN)
  12. #include <dwmapi.h>
  13. #include <wrl/client.h>
  14. #endif
  15. #include <memory>
  16. #include <utility>
  17. #include <vector>
  18. #include "base/containers/contains.h"
  19. #include "base/memory/raw_ref.h"
  20. #include "base/numerics/ranges.h"
  21. #include "base/strings/utf_string_conversions.h"
  22. #include "content/public/browser/desktop_media_id.h"
  23. #include "content/public/common/color_parser.h"
  24. #include "shell/browser/api/electron_api_web_contents.h"
  25. #include "shell/browser/ui/inspectable_web_contents_view.h"
  26. #include "shell/browser/ui/views/root_view.h"
  27. #include "shell/browser/web_contents_preferences.h"
  28. #include "shell/browser/web_view_manager.h"
  29. #include "shell/browser/window_list.h"
  30. #include "shell/common/electron_constants.h"
  31. #include "shell/common/gin_converters/image_converter.h"
  32. #include "shell/common/gin_helper/dictionary.h"
  33. #include "shell/common/options_switches.h"
  34. #include "ui/aura/window_tree_host.h"
  35. #include "ui/base/hit_test.h"
  36. #include "ui/display/screen.h"
  37. #include "ui/gfx/image/image.h"
  38. #include "ui/gfx/native_widget_types.h"
  39. #include "ui/ozone/public/ozone_platform.h"
  40. #include "ui/views/background.h"
  41. #include "ui/views/controls/webview/webview.h"
  42. #include "ui/views/widget/native_widget_private.h"
  43. #include "ui/views/widget/widget.h"
  44. #include "ui/views/window/client_view.h"
  45. #include "ui/wm/core/shadow_types.h"
  46. #include "ui/wm/core/window_util.h"
  47. #if BUILDFLAG(IS_LINUX)
  48. #include "base/strings/string_util.h"
  49. #include "shell/browser/browser.h"
  50. #include "shell/browser/linux/unity_service.h"
  51. #include "shell/browser/ui/electron_desktop_window_tree_host_linux.h"
  52. #include "shell/browser/ui/views/client_frame_view_linux.h"
  53. #include "shell/browser/ui/views/native_frame_view.h"
  54. #include "shell/browser/ui/views/opaque_frame_view.h"
  55. #include "shell/common/platform_util.h"
  56. #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
  57. #include "ui/views/window/native_frame_view.h"
  58. #if BUILDFLAG(IS_OZONE_X11)
  59. #include "shell/browser/ui/views/global_menu_bar_x11.h"
  60. #include "shell/browser/ui/x/event_disabler.h"
  61. #include "shell/browser/ui/x/x_window_utils.h"
  62. #include "ui/gfx/x/atom_cache.h"
  63. #include "ui/gfx/x/connection.h"
  64. #include "ui/gfx/x/shape.h"
  65. #include "ui/gfx/x/xproto.h"
  66. #endif
  67. #elif BUILDFLAG(IS_WIN)
  68. #include "base/win/win_util.h"
  69. #include "base/win/windows_version.h"
  70. #include "shell/browser/ui/views/win_frame_view.h"
  71. #include "shell/browser/ui/win/electron_desktop_native_widget_aura.h"
  72. #include "skia/ext/skia_utils_win.h"
  73. #include "ui/display/win/screen_win.h"
  74. #include "ui/gfx/color_utils.h"
  75. #include "ui/gfx/win/hwnd_util.h"
  76. #include "ui/gfx/win/msg_util.h"
  77. #endif
  78. namespace electron {
  79. #if BUILDFLAG(IS_WIN)
  80. DWM_SYSTEMBACKDROP_TYPE GetBackdropFromString(const std::string& material) {
  81. if (material == "none") {
  82. return DWMSBT_NONE;
  83. } else if (material == "acrylic") {
  84. return DWMSBT_TRANSIENTWINDOW;
  85. } else if (material == "mica") {
  86. return DWMSBT_MAINWINDOW;
  87. } else if (material == "tabbed") {
  88. return DWMSBT_TABBEDWINDOW;
  89. }
  90. return DWMSBT_AUTO;
  91. }
  92. // Similar to the ones in display::win::ScreenWin, but with rounded values
  93. // These help to avoid problems that arise from unresizable windows where the
  94. // original ceil()-ed values can cause calculation errors, since converting
  95. // both ways goes through a ceil() call. Related issue: #15816
  96. gfx::Rect ScreenToDIPRect(HWND hwnd, const gfx::Rect& pixel_bounds) {
  97. float scale_factor = display::win::ScreenWin::GetScaleFactorForHWND(hwnd);
  98. gfx::Rect dip_rect = ScaleToRoundedRect(pixel_bounds, 1.0f / scale_factor);
  99. dip_rect.set_origin(
  100. display::win::ScreenWin::ScreenToDIPRect(hwnd, pixel_bounds).origin());
  101. return dip_rect;
  102. }
  103. #endif
  104. namespace {
  105. #if BUILDFLAG(IS_WIN)
  106. const LPCWSTR kUniqueTaskBarClassName = L"Shell_TrayWnd";
  107. void FlipWindowStyle(HWND handle, bool on, DWORD flag) {
  108. DWORD style = ::GetWindowLong(handle, GWL_STYLE);
  109. if (on)
  110. style |= flag;
  111. else
  112. style &= ~flag;
  113. ::SetWindowLong(handle, GWL_STYLE, style);
  114. // Window's frame styles are cached so we need to call SetWindowPos
  115. // with the SWP_FRAMECHANGED flag to update cache properly.
  116. ::SetWindowPos(handle, 0, 0, 0, 0, 0, // ignored
  117. SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
  118. SWP_NOACTIVATE | SWP_NOOWNERZORDER);
  119. }
  120. gfx::Rect DIPToScreenRect(HWND hwnd, const gfx::Rect& pixel_bounds) {
  121. float scale_factor = display::win::ScreenWin::GetScaleFactorForHWND(hwnd);
  122. gfx::Rect screen_rect = ScaleToRoundedRect(pixel_bounds, scale_factor);
  123. screen_rect.set_origin(
  124. display::win::ScreenWin::DIPToScreenRect(hwnd, pixel_bounds).origin());
  125. return screen_rect;
  126. }
  127. // Chromium uses a buggy implementation that converts content rect to window
  128. // rect when calculating min/max size, we should use the same implementation
  129. // when passing min/max size so we can get correct results.
  130. gfx::Size WindowSizeToContentSizeBuggy(HWND hwnd, const gfx::Size& size) {
  131. // Calculate the size of window frame, using same code with the
  132. // HWNDMessageHandler::OnGetMinMaxInfo method.
  133. // The pitfall is, when window is minimized the calculated window frame size
  134. // will be different from other states.
  135. RECT client_rect, rect;
  136. GetClientRect(hwnd, &client_rect);
  137. GetWindowRect(hwnd, &rect);
  138. CR_DEFLATE_RECT(&rect, &client_rect);
  139. // Convert DIP size to pixel size, do calculation and then return DIP size.
  140. gfx::Rect screen_rect = DIPToScreenRect(hwnd, gfx::Rect(size));
  141. gfx::Size screen_client_size(screen_rect.width() - (rect.right - rect.left),
  142. screen_rect.height() - (rect.bottom - rect.top));
  143. return ScreenToDIPRect(hwnd, gfx::Rect(screen_client_size)).size();
  144. }
  145. #endif
  146. [[maybe_unused]] bool IsX11() {
  147. return ui::OzonePlatform::GetInstance()
  148. ->GetPlatformProperties()
  149. .electron_can_call_x11;
  150. }
  151. class NativeWindowClientView : public views::ClientView {
  152. public:
  153. NativeWindowClientView(views::Widget* widget,
  154. views::View* root_view,
  155. NativeWindowViews* window)
  156. : views::ClientView{widget, root_view},
  157. window_{raw_ref<NativeWindowViews>::from_ptr(window)} {}
  158. ~NativeWindowClientView() override = default;
  159. // disable copy
  160. NativeWindowClientView(const NativeWindowClientView&) = delete;
  161. NativeWindowClientView& operator=(const NativeWindowClientView&) = delete;
  162. // views::ClientView
  163. views::CloseRequestResult OnWindowCloseRequested() override {
  164. window_->NotifyWindowCloseButtonClicked();
  165. return views::CloseRequestResult::kCannotClose;
  166. }
  167. private:
  168. const raw_ref<NativeWindowViews> window_;
  169. };
  170. } // namespace
  171. NativeWindowViews::NativeWindowViews(const gin_helper::Dictionary& options,
  172. NativeWindow* parent)
  173. : NativeWindow(options, parent) {
  174. options.Get(options::kTitle, &title_);
  175. bool menu_bar_autohide;
  176. if (options.Get(options::kAutoHideMenuBar, &menu_bar_autohide))
  177. root_view_.SetAutoHideMenuBar(menu_bar_autohide);
  178. #if BUILDFLAG(IS_WIN)
  179. // On Windows we rely on the CanResize() to indicate whether window can be
  180. // resized, and it should be set before window is created.
  181. options.Get(options::kResizable, &resizable_);
  182. options.Get(options::kMinimizable, &minimizable_);
  183. options.Get(options::kMaximizable, &maximizable_);
  184. // Transparent window must not have thick frame.
  185. options.Get("thickFrame", &thick_frame_);
  186. if (transparent())
  187. thick_frame_ = false;
  188. overlay_button_color_ = color_utils::GetSysSkColor(COLOR_BTNFACE);
  189. overlay_symbol_color_ = color_utils::GetSysSkColor(COLOR_BTNTEXT);
  190. #endif
  191. v8::Local<v8::Value> titlebar_overlay;
  192. if (options.Get(options::ktitleBarOverlay, &titlebar_overlay) &&
  193. titlebar_overlay->IsObject()) {
  194. auto titlebar_overlay_obj =
  195. gin_helper::Dictionary::CreateEmpty(options.isolate());
  196. options.Get(options::ktitleBarOverlay, &titlebar_overlay_obj);
  197. std::string overlay_color_string;
  198. if (titlebar_overlay_obj.Get(options::kOverlayButtonColor,
  199. &overlay_color_string)) {
  200. bool success = content::ParseCssColorString(overlay_color_string,
  201. &overlay_button_color_);
  202. DCHECK(success);
  203. }
  204. std::string overlay_symbol_color_string;
  205. if (titlebar_overlay_obj.Get(options::kOverlaySymbolColor,
  206. &overlay_symbol_color_string)) {
  207. bool success = content::ParseCssColorString(overlay_symbol_color_string,
  208. &overlay_symbol_color_);
  209. DCHECK(success);
  210. }
  211. }
  212. // |hidden| is the only non-default titleBarStyle valid on Windows and Linux.
  213. if (title_bar_style_ == TitleBarStyle::kHidden)
  214. set_has_frame(false);
  215. #if BUILDFLAG(IS_WIN)
  216. // If the taskbar is re-created after we start up, we have to rebuild all of
  217. // our buttons.
  218. taskbar_created_message_ = RegisterWindowMessage(TEXT("TaskbarCreated"));
  219. #endif
  220. if (enable_larger_than_screen())
  221. // We need to set a default maximum window size here otherwise Windows
  222. // will not allow us to resize the window larger than scree.
  223. // Setting directly to INT_MAX somehow doesn't work, so we just divide
  224. // by 10, which should still be large enough.
  225. SetContentSizeConstraints(extensions::SizeConstraints(
  226. gfx::Size(), gfx::Size(INT_MAX / 10, INT_MAX / 10)));
  227. int width = 800, height = 600;
  228. options.Get(options::kWidth, &width);
  229. options.Get(options::kHeight, &height);
  230. gfx::Rect bounds(0, 0, width, height);
  231. widget_size_ = bounds.size();
  232. widget()->AddObserver(this);
  233. using InitParams = views::Widget::InitParams;
  234. auto params = InitParams{InitParams::WIDGET_OWNS_NATIVE_WIDGET,
  235. InitParams::TYPE_WINDOW};
  236. params.bounds = bounds;
  237. params.delegate = this;
  238. params.remove_standard_frame = !has_frame() || has_client_frame();
  239. // If a client frame, we need to draw our own shadows.
  240. if (IsTranslucent() || has_client_frame())
  241. params.opacity = InitParams::WindowOpacity::kTranslucent;
  242. // The given window is most likely not rectangular since it is translucent and
  243. // has no standard frame, don't show a shadow for it.
  244. if (IsTranslucent() && !has_frame())
  245. params.shadow_type = InitParams::ShadowType::kNone;
  246. bool focusable;
  247. if (options.Get(options::kFocusable, &focusable) && !focusable)
  248. params.activatable = InitParams::Activatable::kNo;
  249. #if BUILDFLAG(IS_WIN)
  250. if (parent)
  251. params.parent = parent->GetNativeWindow();
  252. params.native_widget = new ElectronDesktopNativeWidgetAura(this);
  253. #elif BUILDFLAG(IS_LINUX)
  254. std::string name = Browser::Get()->GetName();
  255. // Set WM_WINDOW_ROLE.
  256. params.wm_role_name = "browser-window";
  257. // Set WM_CLASS.
  258. params.wm_class_name = base::ToLowerASCII(name);
  259. params.wm_class_class = name;
  260. // Set Wayland application ID.
  261. params.wayland_app_id = platform_util::GetXdgAppId();
  262. auto* native_widget = new views::DesktopNativeWidgetAura(widget());
  263. params.native_widget = native_widget;
  264. params.desktop_window_tree_host =
  265. new ElectronDesktopWindowTreeHostLinux(this, native_widget);
  266. #endif
  267. widget()->Init(std::move(params));
  268. widget()->SetNativeWindowProperty(kElectronNativeWindowKey.c_str(), this);
  269. SetCanResize(resizable_);
  270. bool fullscreen = false;
  271. options.Get(options::kFullscreen, &fullscreen);
  272. std::string window_type;
  273. options.Get(options::kType, &window_type);
  274. #if BUILDFLAG(IS_LINUX)
  275. // Set _GTK_THEME_VARIANT to dark if we have "dark-theme" option set.
  276. bool use_dark_theme = false;
  277. if (options.Get(options::kDarkTheme, &use_dark_theme) && use_dark_theme) {
  278. SetGTKDarkThemeEnabled(use_dark_theme);
  279. }
  280. if (parent)
  281. SetParentWindow(parent);
  282. if (IsX11()) {
  283. // Before the window is mapped the SetWMSpecState can not work, so we have
  284. // to manually set the _NET_WM_STATE.
  285. std::vector<x11::Atom> state_atom_list;
  286. // Before the window is mapped, there is no SHOW_FULLSCREEN_STATE.
  287. if (fullscreen) {
  288. state_atom_list.push_back(x11::GetAtom("_NET_WM_STATE_FULLSCREEN"));
  289. }
  290. if (parent) {
  291. // Force using dialog type for child window.
  292. window_type = "dialog";
  293. // Modal window needs the _NET_WM_STATE_MODAL hint.
  294. if (is_modal())
  295. state_atom_list.push_back(x11::GetAtom("_NET_WM_STATE_MODAL"));
  296. }
  297. if (!state_atom_list.empty()) {
  298. auto* connection = x11::Connection::Get();
  299. connection->SetArrayProperty(
  300. static_cast<x11::Window>(GetAcceleratedWidget()),
  301. x11::GetAtom("_NET_WM_STATE"), x11::Atom::ATOM, state_atom_list);
  302. }
  303. // Set the _NET_WM_WINDOW_TYPE.
  304. if (!window_type.empty())
  305. SetWindowType(static_cast<x11::Window>(GetAcceleratedWidget()),
  306. window_type);
  307. }
  308. #endif
  309. #if BUILDFLAG(IS_WIN)
  310. if (!has_frame()) {
  311. // Set Window style so that we get a minimize and maximize animation when
  312. // frameless.
  313. DWORD frame_style = WS_CAPTION | WS_OVERLAPPED;
  314. if (resizable_)
  315. frame_style |= WS_THICKFRAME;
  316. if (minimizable_)
  317. frame_style |= WS_MINIMIZEBOX;
  318. if (maximizable_)
  319. frame_style |= WS_MAXIMIZEBOX;
  320. // We should not show a frame for transparent window.
  321. if (!thick_frame_)
  322. frame_style &= ~(WS_THICKFRAME | WS_CAPTION);
  323. ::SetWindowLong(GetAcceleratedWidget(), GWL_STYLE, frame_style);
  324. bool rounded_corner = true;
  325. options.Get(options::kRoundedCorners, &rounded_corner);
  326. if (!rounded_corner)
  327. SetRoundedCorners(false);
  328. }
  329. LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
  330. if (window_type == "toolbar")
  331. ex_style |= WS_EX_TOOLWINDOW;
  332. ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
  333. #endif
  334. if (has_frame() && !has_client_frame()) {
  335. // TODO(zcbenz): This was used to force using native frame on Windows 2003,
  336. // we should check whether setting it in InitParams can work.
  337. widget()->set_frame_type(views::Widget::FrameType::kForceNative);
  338. widget()->FrameTypeChanged();
  339. #if BUILDFLAG(IS_WIN)
  340. // thickFrame also works for normal window.
  341. if (!thick_frame_)
  342. FlipWindowStyle(GetAcceleratedWidget(), false, WS_THICKFRAME);
  343. #endif
  344. }
  345. // Default content view.
  346. SetContentView(new views::View());
  347. gfx::Size size = bounds.size();
  348. if (has_frame() &&
  349. options.Get(options::kUseContentSize, &use_content_size_) &&
  350. use_content_size_)
  351. size = ContentBoundsToWindowBounds(gfx::Rect(size)).size();
  352. widget()->CenterWindow(size);
  353. #if BUILDFLAG(IS_WIN)
  354. // Save initial window state.
  355. if (fullscreen)
  356. last_window_state_ = ui::mojom::WindowShowState::kFullscreen;
  357. else
  358. last_window_state_ = ui::mojom::WindowShowState::kNormal;
  359. #endif
  360. // Listen to mouse events.
  361. aura::Window* window = GetNativeWindow();
  362. if (window)
  363. window->AddPreTargetHandler(this);
  364. #if BUILDFLAG(IS_LINUX)
  365. // On linux after the widget is initialized we might have to force set the
  366. // bounds if the bounds are smaller than the current display
  367. SetBounds(gfx::Rect(GetPosition(), bounds.size()), false);
  368. #endif
  369. SetOwnedByWidget(false);
  370. RegisterDeleteDelegateCallback(base::BindOnce(
  371. [](NativeWindowViews* window) {
  372. if (window->is_modal() && window->parent()) {
  373. auto* parent = window->parent();
  374. // Enable parent window after current window gets closed.
  375. static_cast<NativeWindowViews*>(parent)->DecrementChildModals();
  376. // Focus on parent window.
  377. parent->Focus(true);
  378. }
  379. window->NotifyWindowClosed();
  380. },
  381. this));
  382. }
  383. NativeWindowViews::~NativeWindowViews() {
  384. widget()->RemoveObserver(this);
  385. #if BUILDFLAG(IS_WIN)
  386. // Disable mouse forwarding to relinquish resources, should any be held.
  387. SetForwardMouseMessages(false);
  388. #endif
  389. aura::Window* window = GetNativeWindow();
  390. if (window)
  391. window->RemovePreTargetHandler(this);
  392. }
  393. void NativeWindowViews::SetGTKDarkThemeEnabled(bool use_dark_theme) {
  394. #if BUILDFLAG(IS_LINUX)
  395. if (IsX11()) {
  396. const std::string color = use_dark_theme ? "dark" : "light";
  397. auto* connection = x11::Connection::Get();
  398. connection->SetStringProperty(
  399. static_cast<x11::Window>(GetAcceleratedWidget()),
  400. x11::GetAtom("_GTK_THEME_VARIANT"), x11::GetAtom("UTF8_STRING"), color);
  401. }
  402. #endif
  403. }
  404. void NativeWindowViews::SetContentView(views::View* view) {
  405. if (content_view()) {
  406. root_view_.GetMainView()->RemoveChildView(content_view());
  407. }
  408. set_content_view(view);
  409. focused_view_ = view;
  410. root_view_.GetMainView()->AddChildView(content_view());
  411. root_view_.GetMainView()->DeprecatedLayoutImmediately();
  412. }
  413. void NativeWindowViews::Close() {
  414. if (!IsClosable()) {
  415. WindowList::WindowCloseCancelled(this);
  416. return;
  417. }
  418. widget()->Close();
  419. }
  420. void NativeWindowViews::CloseImmediately() {
  421. widget()->CloseNow();
  422. }
  423. void NativeWindowViews::Focus(bool focus) {
  424. // For hidden window focus() should do nothing.
  425. if (!IsVisible())
  426. return;
  427. if (focus) {
  428. widget()->Activate();
  429. } else {
  430. widget()->Deactivate();
  431. }
  432. }
  433. bool NativeWindowViews::IsFocused() const {
  434. return widget()->IsActive();
  435. }
  436. void NativeWindowViews::Show() {
  437. if (is_modal() && NativeWindow::parent() &&
  438. !widget()->native_widget_private()->IsVisible())
  439. static_cast<NativeWindowViews*>(parent())->IncrementChildModals();
  440. widget()->native_widget_private()->Show(GetRestoredState(), gfx::Rect());
  441. // explicitly focus the window
  442. widget()->Activate();
  443. NotifyWindowShow();
  444. #if BUILDFLAG(IS_LINUX)
  445. if (global_menu_bar_)
  446. global_menu_bar_->OnWindowMapped();
  447. // On X11, setting Z order before showing the window doesn't take effect,
  448. // so we have to call it again.
  449. if (IsX11())
  450. widget()->SetZOrderLevel(widget()->GetZOrderLevel());
  451. #endif
  452. }
  453. void NativeWindowViews::ShowInactive() {
  454. widget()->ShowInactive();
  455. NotifyWindowShow();
  456. #if BUILDFLAG(IS_LINUX)
  457. if (global_menu_bar_)
  458. global_menu_bar_->OnWindowMapped();
  459. // On X11, setting Z order before showing the window doesn't take effect,
  460. // so we have to call it again.
  461. if (IsX11())
  462. widget()->SetZOrderLevel(widget()->GetZOrderLevel());
  463. #endif
  464. }
  465. void NativeWindowViews::Hide() {
  466. if (is_modal() && NativeWindow::parent())
  467. static_cast<NativeWindowViews*>(parent())->DecrementChildModals();
  468. widget()->Hide();
  469. NotifyWindowHide();
  470. #if BUILDFLAG(IS_LINUX)
  471. if (global_menu_bar_)
  472. global_menu_bar_->OnWindowUnmapped();
  473. #endif
  474. #if BUILDFLAG(IS_WIN)
  475. // When the window is removed from the taskbar via win.hide(),
  476. // the thumbnail buttons need to be set up again.
  477. // Ensure that when the window is hidden,
  478. // the taskbar host is notified that it should re-add them.
  479. taskbar_host_.SetThumbarButtonsAdded(false);
  480. #endif
  481. }
  482. bool NativeWindowViews::IsVisible() const {
  483. #if BUILDFLAG(IS_WIN)
  484. // widget()->IsVisible() calls ::IsWindowVisible, which returns non-zero if a
  485. // window or any of its parent windows are visible. We want to only check the
  486. // current window.
  487. bool visible =
  488. ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_VISIBLE;
  489. // WS_VISIBLE is true even if a window is minimized - explicitly check that.
  490. return visible && !IsMinimized();
  491. #else
  492. return widget()->IsVisible();
  493. #endif
  494. }
  495. bool NativeWindowViews::IsEnabled() const {
  496. #if BUILDFLAG(IS_WIN)
  497. return ::IsWindowEnabled(GetAcceleratedWidget());
  498. #elif BUILDFLAG(IS_LINUX)
  499. if (IsX11())
  500. return !event_disabler_.get();
  501. NOTIMPLEMENTED();
  502. return true;
  503. #endif
  504. }
  505. void NativeWindowViews::IncrementChildModals() {
  506. num_modal_children_++;
  507. SetEnabledInternal(ShouldBeEnabled());
  508. }
  509. void NativeWindowViews::DecrementChildModals() {
  510. if (num_modal_children_ > 0) {
  511. num_modal_children_--;
  512. }
  513. SetEnabledInternal(ShouldBeEnabled());
  514. }
  515. void NativeWindowViews::SetEnabled(bool enable) {
  516. if (enable != is_enabled_) {
  517. is_enabled_ = enable;
  518. SetEnabledInternal(ShouldBeEnabled());
  519. }
  520. }
  521. bool NativeWindowViews::ShouldBeEnabled() const {
  522. return is_enabled_ && (num_modal_children_ == 0);
  523. }
  524. void NativeWindowViews::SetEnabledInternal(bool enable) {
  525. if (enable && IsEnabled()) {
  526. return;
  527. } else if (!enable && !IsEnabled()) {
  528. return;
  529. }
  530. #if BUILDFLAG(IS_WIN)
  531. ::EnableWindow(GetAcceleratedWidget(), enable);
  532. #else
  533. if (IsX11()) {
  534. views::DesktopWindowTreeHostPlatform* tree_host =
  535. views::DesktopWindowTreeHostLinux::GetHostForWidget(
  536. GetAcceleratedWidget());
  537. if (enable) {
  538. tree_host->RemoveEventRewriter(event_disabler_.get());
  539. event_disabler_.reset();
  540. } else {
  541. event_disabler_ = std::make_unique<EventDisabler>();
  542. tree_host->AddEventRewriter(event_disabler_.get());
  543. }
  544. }
  545. #endif
  546. }
  547. void NativeWindowViews::Maximize() {
  548. #if BUILDFLAG(IS_WIN)
  549. if (IsTranslucent()) {
  550. // If a window is translucent but not transparent on Windows,
  551. // that means it must have a backgroundMaterial set.
  552. if (!transparent())
  553. SetRoundedCorners(false);
  554. restore_bounds_ = GetBounds();
  555. auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(
  556. GetNativeWindow());
  557. SetBounds(display.work_area(), false);
  558. NotifyWindowMaximize();
  559. return;
  560. }
  561. #endif
  562. if (IsVisible()) {
  563. widget()->Maximize();
  564. } else {
  565. widget()->native_widget_private()->Show(
  566. ui::mojom::WindowShowState::kMaximized, gfx::Rect());
  567. NotifyWindowShow();
  568. }
  569. }
  570. void NativeWindowViews::Unmaximize() {
  571. if (!IsMaximized())
  572. return;
  573. #if BUILDFLAG(IS_WIN)
  574. if (IsTranslucent()) {
  575. SetBounds(restore_bounds_, false);
  576. NotifyWindowUnmaximize();
  577. if (transparent()) {
  578. UpdateThickFrame();
  579. } else {
  580. SetRoundedCorners(true);
  581. }
  582. return;
  583. }
  584. #endif
  585. widget()->Restore();
  586. #if BUILDFLAG(IS_WIN)
  587. UpdateThickFrame();
  588. #endif
  589. }
  590. bool NativeWindowViews::IsMaximized() const {
  591. if (widget()->IsMaximized())
  592. return true;
  593. #if BUILDFLAG(IS_WIN)
  594. if (IsTranslucent() && !IsMinimized()) {
  595. // If the window is the same dimensions and placement as the
  596. // display, we consider it maximized.
  597. auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(
  598. GetNativeWindow());
  599. return GetBounds() == display.work_area();
  600. }
  601. #endif
  602. return false;
  603. }
  604. void NativeWindowViews::Minimize() {
  605. if (IsVisible())
  606. widget()->Minimize();
  607. else
  608. widget()->native_widget_private()->Show(
  609. ui::mojom::WindowShowState::kMinimized, gfx::Rect());
  610. }
  611. void NativeWindowViews::Restore() {
  612. #if BUILDFLAG(IS_WIN)
  613. if (IsMaximized() && IsTranslucent()) {
  614. SetBounds(restore_bounds_, false);
  615. NotifyWindowRestore();
  616. if (transparent()) {
  617. UpdateThickFrame();
  618. } else {
  619. SetRoundedCorners(true);
  620. }
  621. return;
  622. }
  623. #endif
  624. widget()->Restore();
  625. #if BUILDFLAG(IS_WIN)
  626. UpdateThickFrame();
  627. #endif
  628. }
  629. bool NativeWindowViews::IsMinimized() const {
  630. return widget()->IsMinimized();
  631. }
  632. void NativeWindowViews::SetFullScreen(bool fullscreen) {
  633. if (!IsFullScreenable())
  634. return;
  635. #if BUILDFLAG(IS_WIN)
  636. // There is no native fullscreen state on Windows.
  637. bool leaving_fullscreen = IsFullscreen() && !fullscreen;
  638. if (fullscreen) {
  639. last_window_state_ = ui::mojom::WindowShowState::kFullscreen;
  640. NotifyWindowEnterFullScreen();
  641. } else {
  642. last_window_state_ = ui::mojom::WindowShowState::kNormal;
  643. NotifyWindowLeaveFullScreen();
  644. }
  645. // For window without WS_THICKFRAME style, we can not call SetFullscreen().
  646. // This path will be used for transparent windows as well.
  647. if (!thick_frame_) {
  648. if (fullscreen) {
  649. restore_bounds_ = GetBounds();
  650. auto display =
  651. display::Screen::GetScreen()->GetDisplayNearestPoint(GetPosition());
  652. SetBounds(display.bounds(), false);
  653. } else {
  654. SetBounds(restore_bounds_, false);
  655. }
  656. return;
  657. }
  658. // We set the new value after notifying, so we can handle the size event
  659. // correctly.
  660. widget()->SetFullscreen(fullscreen);
  661. // If restoring from fullscreen and the window isn't visible, force visible,
  662. // else a non-responsive window shell could be rendered.
  663. // (this situation may arise when app starts with fullscreen: true)
  664. // Note: the following must be after "widget()->SetFullscreen(fullscreen);"
  665. if (leaving_fullscreen && !IsVisible())
  666. FlipWindowStyle(GetAcceleratedWidget(), true, WS_VISIBLE);
  667. // Auto-hide menubar when in fullscreen.
  668. if (fullscreen) {
  669. menu_bar_visible_before_fullscreen_ = IsMenuBarVisible();
  670. SetMenuBarVisibility(false);
  671. } else {
  672. // No fullscreen -> fullscreen video -> un-fullscreen video results
  673. // in `NativeWindowViews::SetFullScreen(false)` being called twice.
  674. // `menu_bar_visible_before_fullscreen_` is always false on the
  675. // second call which results in `SetMenuBarVisibility(false)` no
  676. // matter what. We check `leaving_fullscreen` to avoid this.
  677. if (!leaving_fullscreen)
  678. return;
  679. SetMenuBarVisibility(!IsMenuBarAutoHide() &&
  680. menu_bar_visible_before_fullscreen_);
  681. menu_bar_visible_before_fullscreen_ = false;
  682. }
  683. #else
  684. if (IsVisible())
  685. widget()->SetFullscreen(fullscreen);
  686. else if (fullscreen)
  687. widget()->native_widget_private()->Show(
  688. ui::mojom::WindowShowState::kFullscreen, gfx::Rect());
  689. // Auto-hide menubar when in fullscreen.
  690. if (fullscreen) {
  691. menu_bar_visible_before_fullscreen_ = IsMenuBarVisible();
  692. SetMenuBarVisibility(false);
  693. } else {
  694. SetMenuBarVisibility(!IsMenuBarAutoHide() &&
  695. menu_bar_visible_before_fullscreen_);
  696. menu_bar_visible_before_fullscreen_ = false;
  697. }
  698. #endif
  699. }
  700. bool NativeWindowViews::IsFullscreen() const {
  701. return widget()->IsFullscreen();
  702. }
  703. void NativeWindowViews::SetBounds(const gfx::Rect& bounds, bool animate) {
  704. #if BUILDFLAG(IS_WIN)
  705. if (is_moving_ || is_resizing_) {
  706. pending_bounds_change_ = bounds;
  707. }
  708. #endif
  709. #if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_LINUX)
  710. // On Linux and Windows the minimum and maximum size should be updated with
  711. // window size when window is not resizable.
  712. if (!resizable_) {
  713. SetMaximumSize(bounds.size());
  714. SetMinimumSize(bounds.size());
  715. }
  716. #endif
  717. widget()->SetBounds(bounds);
  718. }
  719. gfx::Rect NativeWindowViews::GetBounds() const {
  720. #if BUILDFLAG(IS_WIN)
  721. if (IsMinimized())
  722. return widget()->GetRestoredBounds();
  723. #endif
  724. return widget()->GetWindowBoundsInScreen();
  725. }
  726. gfx::Rect NativeWindowViews::GetContentBounds() const {
  727. return content_view() ? content_view()->GetBoundsInScreen() : gfx::Rect();
  728. }
  729. gfx::Size NativeWindowViews::GetContentSize() const {
  730. #if BUILDFLAG(IS_WIN)
  731. if (IsMinimized())
  732. return NativeWindow::GetContentSize();
  733. #endif
  734. return content_view() ? content_view()->size() : gfx::Size();
  735. }
  736. gfx::Rect NativeWindowViews::GetNormalBounds() const {
  737. #if BUILDFLAG(IS_WIN)
  738. if (IsMaximized() && IsTranslucent())
  739. return restore_bounds_;
  740. #endif
  741. return widget()->GetRestoredBounds();
  742. }
  743. void NativeWindowViews::SetContentSizeConstraints(
  744. const extensions::SizeConstraints& size_constraints) {
  745. NativeWindow::SetContentSizeConstraints(size_constraints);
  746. #if BUILDFLAG(IS_WIN)
  747. // Changing size constraints would force adding the WS_THICKFRAME style, so
  748. // do nothing if thickFrame is false.
  749. if (!thick_frame_)
  750. return;
  751. #endif
  752. // widget_delegate() is only available after Init() is called, we make use
  753. // of this to determine whether native widget has initialized.
  754. if (widget() && widget()->widget_delegate())
  755. widget()->OnSizeConstraintsChanged();
  756. if (resizable_)
  757. old_size_constraints_ = size_constraints;
  758. }
  759. #if BUILDFLAG(IS_WIN)
  760. // This override does almost the same with its parent, except that it uses
  761. // the WindowSizeToContentSizeBuggy method to convert window size to content
  762. // size. See the comment of the method for the reason behind this.
  763. extensions::SizeConstraints NativeWindowViews::GetContentSizeConstraints()
  764. const {
  765. if (content_size_constraints_)
  766. return *content_size_constraints_;
  767. if (!size_constraints_)
  768. return extensions::SizeConstraints();
  769. extensions::SizeConstraints constraints;
  770. if (size_constraints_->HasMaximumSize()) {
  771. constraints.set_maximum_size(WindowSizeToContentSizeBuggy(
  772. GetAcceleratedWidget(), size_constraints_->GetMaximumSize()));
  773. }
  774. if (size_constraints_->HasMinimumSize()) {
  775. constraints.set_minimum_size(WindowSizeToContentSizeBuggy(
  776. GetAcceleratedWidget(), size_constraints_->GetMinimumSize()));
  777. }
  778. return constraints;
  779. }
  780. #endif
  781. void NativeWindowViews::SetResizable(bool resizable) {
  782. if (resizable != resizable_) {
  783. // On Linux there is no "resizable" property of a window, we have to set
  784. // both the minimum and maximum size to the window size to achieve it.
  785. if (resizable) {
  786. SetContentSizeConstraints(old_size_constraints_);
  787. SetMaximizable(maximizable_);
  788. } else {
  789. old_size_constraints_ = GetContentSizeConstraints();
  790. resizable_ = false;
  791. gfx::Size content_size = GetContentSize();
  792. SetContentSizeConstraints(
  793. extensions::SizeConstraints(content_size, content_size));
  794. }
  795. }
  796. resizable_ = resizable;
  797. SetCanResize(resizable_);
  798. #if BUILDFLAG(IS_WIN)
  799. UpdateThickFrame();
  800. #endif
  801. }
  802. bool NativeWindowViews::MoveAbove(const std::string& sourceId) {
  803. const content::DesktopMediaID id = content::DesktopMediaID::Parse(sourceId);
  804. if (id.type != content::DesktopMediaID::TYPE_WINDOW)
  805. return false;
  806. #if BUILDFLAG(IS_WIN)
  807. const HWND otherWindow = reinterpret_cast<HWND>(id.id);
  808. if (!::IsWindow(otherWindow))
  809. return false;
  810. ::SetWindowPos(GetAcceleratedWidget(), GetWindow(otherWindow, GW_HWNDPREV), 0,
  811. 0, 0, 0,
  812. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  813. #else
  814. if (IsX11()) {
  815. if (!IsWindowValid(static_cast<x11::Window>(id.id)))
  816. return false;
  817. electron::MoveWindowAbove(static_cast<x11::Window>(GetAcceleratedWidget()),
  818. static_cast<x11::Window>(id.id));
  819. }
  820. #endif
  821. return true;
  822. }
  823. void NativeWindowViews::MoveTop() {
  824. // TODO(julien.isorce): fix chromium in order to use existing
  825. // widget()->StackAtTop().
  826. #if BUILDFLAG(IS_WIN)
  827. gfx::Point pos = GetPosition();
  828. gfx::Size size = GetSize();
  829. ::SetWindowPos(GetAcceleratedWidget(), HWND_TOP, pos.x(), pos.y(),
  830. size.width(), size.height(),
  831. SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
  832. #else
  833. if (IsX11())
  834. electron::MoveWindowToForeground(
  835. static_cast<x11::Window>(GetAcceleratedWidget()));
  836. #endif
  837. }
  838. bool NativeWindowViews::IsResizable() const {
  839. #if BUILDFLAG(IS_WIN)
  840. if (has_frame())
  841. return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME;
  842. #endif
  843. return resizable_;
  844. }
  845. void NativeWindowViews::SetAspectRatio(double aspect_ratio,
  846. const gfx::Size& extra_size) {
  847. NativeWindow::SetAspectRatio(aspect_ratio, extra_size);
  848. gfx::SizeF aspect(aspect_ratio, 1.0);
  849. // Scale up because SetAspectRatio() truncates aspect value to int
  850. aspect.Scale(100);
  851. widget()->SetAspectRatio(aspect);
  852. }
  853. void NativeWindowViews::SetMovable(bool movable) {
  854. movable_ = movable;
  855. }
  856. bool NativeWindowViews::IsMovable() const {
  857. #if BUILDFLAG(IS_WIN)
  858. return movable_;
  859. #else
  860. return true; // Not implemented on Linux.
  861. #endif
  862. }
  863. void NativeWindowViews::SetMinimizable(bool minimizable) {
  864. #if BUILDFLAG(IS_WIN)
  865. FlipWindowStyle(GetAcceleratedWidget(), minimizable, WS_MINIMIZEBOX);
  866. if (IsWindowControlsOverlayEnabled()) {
  867. auto* frame_view =
  868. static_cast<WinFrameView*>(widget()->non_client_view()->frame_view());
  869. frame_view->caption_button_container()->UpdateButtons();
  870. }
  871. #endif
  872. minimizable_ = minimizable;
  873. }
  874. bool NativeWindowViews::IsMinimizable() const {
  875. #if BUILDFLAG(IS_WIN)
  876. return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_MINIMIZEBOX;
  877. #else
  878. return true; // Not implemented on Linux.
  879. #endif
  880. }
  881. void NativeWindowViews::SetMaximizable(bool maximizable) {
  882. #if BUILDFLAG(IS_WIN)
  883. FlipWindowStyle(GetAcceleratedWidget(), maximizable, WS_MAXIMIZEBOX);
  884. if (IsWindowControlsOverlayEnabled()) {
  885. auto* frame_view =
  886. static_cast<WinFrameView*>(widget()->non_client_view()->frame_view());
  887. frame_view->caption_button_container()->UpdateButtons();
  888. }
  889. #endif
  890. maximizable_ = maximizable;
  891. }
  892. bool NativeWindowViews::IsMaximizable() const {
  893. #if BUILDFLAG(IS_WIN)
  894. return ::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_MAXIMIZEBOX;
  895. #else
  896. return true; // Not implemented on Linux.
  897. #endif
  898. }
  899. bool NativeWindowViews::IsExcludedFromShownWindowsMenu() const {
  900. // return false on unsupported platforms
  901. return false;
  902. }
  903. void NativeWindowViews::SetFullScreenable(bool fullscreenable) {
  904. fullscreenable_ = fullscreenable;
  905. }
  906. bool NativeWindowViews::IsFullScreenable() const {
  907. return fullscreenable_;
  908. }
  909. void NativeWindowViews::SetClosable(bool closable) {
  910. #if BUILDFLAG(IS_WIN)
  911. HMENU menu = GetSystemMenu(GetAcceleratedWidget(), false);
  912. if (closable) {
  913. EnableMenuItem(menu, SC_CLOSE, MF_BYCOMMAND | MF_ENABLED);
  914. } else {
  915. EnableMenuItem(menu, SC_CLOSE, MF_BYCOMMAND | MF_DISABLED | MF_GRAYED);
  916. }
  917. if (IsWindowControlsOverlayEnabled()) {
  918. auto* frame_view =
  919. static_cast<WinFrameView*>(widget()->non_client_view()->frame_view());
  920. frame_view->caption_button_container()->UpdateButtons();
  921. }
  922. #endif
  923. }
  924. bool NativeWindowViews::IsClosable() const {
  925. #if BUILDFLAG(IS_WIN)
  926. HMENU menu = GetSystemMenu(GetAcceleratedWidget(), false);
  927. MENUITEMINFO info;
  928. memset(&info, 0, sizeof(info));
  929. info.cbSize = sizeof(info);
  930. info.fMask = MIIM_STATE;
  931. if (!GetMenuItemInfo(menu, SC_CLOSE, false, &info)) {
  932. return false;
  933. }
  934. return !(info.fState & MFS_DISABLED);
  935. #elif BUILDFLAG(IS_LINUX)
  936. return true;
  937. #endif
  938. }
  939. void NativeWindowViews::SetAlwaysOnTop(ui::ZOrderLevel z_order,
  940. const std::string& level,
  941. int relativeLevel) {
  942. bool level_changed = z_order != widget()->GetZOrderLevel();
  943. widget()->SetZOrderLevel(z_order);
  944. #if BUILDFLAG(IS_WIN)
  945. // Reset the placement flag.
  946. behind_task_bar_ = false;
  947. if (z_order != ui::ZOrderLevel::kNormal) {
  948. // On macOS the window is placed behind the Dock for the following levels.
  949. // Re-use the same names on Windows to make it easier for the user.
  950. static const std::vector<std::string> levels = {
  951. "floating", "torn-off-menu", "modal-panel", "main-menu", "status"};
  952. behind_task_bar_ = base::Contains(levels, level);
  953. }
  954. #endif
  955. MoveBehindTaskBarIfNeeded();
  956. // This must be notified at the very end or IsAlwaysOnTop
  957. // will not yet have been updated to reflect the new status
  958. if (level_changed)
  959. NativeWindow::NotifyWindowAlwaysOnTopChanged();
  960. }
  961. ui::ZOrderLevel NativeWindowViews::GetZOrderLevel() const {
  962. return widget()->GetZOrderLevel();
  963. }
  964. // We previous called widget()->CenterWindow() here, but in
  965. // Chromium CL 4916277 behavior was changed to center relative to the
  966. // parent window if there is one. We want to keep the old behavior
  967. // for now to avoid breaking API contract, but should consider the long
  968. // term plan for this aligning with upstream.
  969. void NativeWindowViews::Center() {
  970. #if BUILDFLAG(IS_LINUX)
  971. auto display =
  972. display::Screen::GetScreen()->GetDisplayNearestWindow(GetNativeWindow());
  973. gfx::Rect window_bounds_in_screen = display.work_area();
  974. window_bounds_in_screen.ClampToCenteredSize(GetSize());
  975. widget()->SetBounds(window_bounds_in_screen);
  976. #else
  977. HWND hwnd = GetAcceleratedWidget();
  978. gfx::Size size = display::win::ScreenWin::DIPToScreenSize(hwnd, GetSize());
  979. gfx::CenterAndSizeWindow(nullptr, hwnd, size);
  980. #endif
  981. }
  982. void NativeWindowViews::Invalidate() {
  983. widget()->SchedulePaintInRect(gfx::Rect(GetBounds().size()));
  984. }
  985. void NativeWindowViews::SetTitle(const std::string& title) {
  986. title_ = title;
  987. widget()->UpdateWindowTitle();
  988. }
  989. std::string NativeWindowViews::GetTitle() const {
  990. return title_;
  991. }
  992. void NativeWindowViews::FlashFrame(bool flash) {
  993. #if BUILDFLAG(IS_WIN)
  994. // The Chromium's implementation has a bug stopping flash.
  995. if (!flash) {
  996. FLASHWINFO fwi;
  997. fwi.cbSize = sizeof(fwi);
  998. fwi.hwnd = GetAcceleratedWidget();
  999. fwi.dwFlags = FLASHW_STOP;
  1000. fwi.uCount = 0;
  1001. FlashWindowEx(&fwi);
  1002. return;
  1003. }
  1004. #endif
  1005. widget()->FlashFrame(flash);
  1006. }
  1007. void NativeWindowViews::SetSkipTaskbar(bool skip) {
  1008. #if BUILDFLAG(IS_WIN)
  1009. Microsoft::WRL::ComPtr<ITaskbarList> taskbar;
  1010. if (FAILED(::CoCreateInstance(CLSID_TaskbarList, nullptr,
  1011. CLSCTX_INPROC_SERVER,
  1012. IID_PPV_ARGS(&taskbar))) ||
  1013. FAILED(taskbar->HrInit()))
  1014. return;
  1015. if (skip) {
  1016. taskbar->DeleteTab(GetAcceleratedWidget());
  1017. } else {
  1018. taskbar->AddTab(GetAcceleratedWidget());
  1019. taskbar_host_.RestoreThumbarButtons(GetAcceleratedWidget());
  1020. }
  1021. #endif
  1022. }
  1023. void NativeWindowViews::SetSimpleFullScreen(bool simple_fullscreen) {
  1024. SetFullScreen(simple_fullscreen);
  1025. }
  1026. bool NativeWindowViews::IsSimpleFullScreen() const {
  1027. return IsFullscreen();
  1028. }
  1029. void NativeWindowViews::SetKiosk(bool kiosk) {
  1030. SetFullScreen(kiosk);
  1031. }
  1032. bool NativeWindowViews::IsKiosk() const {
  1033. return IsFullscreen();
  1034. }
  1035. bool NativeWindowViews::IsTabletMode() const {
  1036. #if BUILDFLAG(IS_WIN)
  1037. // TODO: Prefer the async version base::win::IsDeviceInTabletMode
  1038. // which requires making the public api async.
  1039. return base::win::IsWindows10TabletMode(GetAcceleratedWidget());
  1040. #else
  1041. return false;
  1042. #endif
  1043. }
  1044. SkColor NativeWindowViews::GetBackgroundColor() const {
  1045. auto* background = root_view_.background();
  1046. if (!background)
  1047. return SK_ColorTRANSPARENT;
  1048. return background->color().ConvertToSkColor(root_view_.GetColorProvider());
  1049. }
  1050. void NativeWindowViews::SetBackgroundColor(SkColor background_color) {
  1051. // web views' background color.
  1052. root_view_.SetBackground(views::CreateSolidBackground(background_color));
  1053. #if BUILDFLAG(IS_WIN)
  1054. // Set the background color of native window.
  1055. HBRUSH brush = CreateSolidBrush(skia::SkColorToCOLORREF(background_color));
  1056. ULONG_PTR previous_brush =
  1057. SetClassLongPtr(GetAcceleratedWidget(), GCLP_HBRBACKGROUND,
  1058. reinterpret_cast<LONG_PTR>(brush));
  1059. if (previous_brush)
  1060. DeleteObject((HBRUSH)previous_brush);
  1061. InvalidateRect(GetAcceleratedWidget(), nullptr, 1);
  1062. #endif
  1063. }
  1064. void NativeWindowViews::SetHasShadow(bool has_shadow) {
  1065. wm::SetShadowElevation(GetNativeWindow(),
  1066. has_shadow ? wm::kShadowElevationInactiveWindow
  1067. : wm::kShadowElevationNone);
  1068. }
  1069. bool NativeWindowViews::HasShadow() const {
  1070. return GetNativeWindow()->GetProperty(wm::kShadowElevationKey) !=
  1071. wm::kShadowElevationNone;
  1072. }
  1073. void NativeWindowViews::SetOpacity(const double opacity) {
  1074. #if BUILDFLAG(IS_WIN)
  1075. const double boundedOpacity = std::clamp(opacity, 0.0, 1.0);
  1076. HWND hwnd = GetAcceleratedWidget();
  1077. if (!layered_) {
  1078. LONG ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
  1079. ex_style |= WS_EX_LAYERED;
  1080. ::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
  1081. layered_ = true;
  1082. }
  1083. ::SetLayeredWindowAttributes(hwnd, 0, boundedOpacity * 255, LWA_ALPHA);
  1084. opacity_ = boundedOpacity;
  1085. #else
  1086. opacity_ = 1.0; // setOpacity unsupported on Linux
  1087. #endif
  1088. }
  1089. double NativeWindowViews::GetOpacity() const {
  1090. return opacity_;
  1091. }
  1092. void NativeWindowViews::SetIgnoreMouseEvents(bool ignore, bool forward) {
  1093. #if BUILDFLAG(IS_WIN)
  1094. LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
  1095. if (ignore)
  1096. ex_style |= (WS_EX_TRANSPARENT | WS_EX_LAYERED);
  1097. else
  1098. ex_style &= ~(WS_EX_TRANSPARENT | WS_EX_LAYERED);
  1099. if (layered_)
  1100. ex_style |= WS_EX_LAYERED;
  1101. ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
  1102. // Forwarding is always disabled when not ignoring mouse messages.
  1103. if (!ignore) {
  1104. SetForwardMouseMessages(false);
  1105. } else {
  1106. SetForwardMouseMessages(forward);
  1107. }
  1108. #else
  1109. if (IsX11()) {
  1110. auto* connection = x11::Connection::Get();
  1111. if (ignore) {
  1112. x11::Rectangle r{0, 0, 1, 1};
  1113. connection->shape().Rectangles({
  1114. .operation = x11::Shape::So::Set,
  1115. .destination_kind = x11::Shape::Sk::Input,
  1116. .ordering = x11::ClipOrdering::YXBanded,
  1117. .destination_window =
  1118. static_cast<x11::Window>(GetAcceleratedWidget()),
  1119. .rectangles = {r},
  1120. });
  1121. } else {
  1122. connection->shape().Mask({
  1123. .operation = x11::Shape::So::Set,
  1124. .destination_kind = x11::Shape::Sk::Input,
  1125. .destination_window =
  1126. static_cast<x11::Window>(GetAcceleratedWidget()),
  1127. .source_bitmap = x11::Pixmap::None,
  1128. });
  1129. }
  1130. }
  1131. #endif
  1132. }
  1133. void NativeWindowViews::SetContentProtection(bool enable) {
  1134. #if BUILDFLAG(IS_WIN)
  1135. widget()->native_widget_private()->SetAllowScreenshots(!enable);
  1136. #endif
  1137. }
  1138. bool NativeWindowViews::IsContentProtected() const {
  1139. #if BUILDFLAG(IS_WIN)
  1140. return !widget()->native_widget_private()->AreScreenshotsAllowed();
  1141. #else // Not implemented on Linux
  1142. return false;
  1143. #endif
  1144. }
  1145. void NativeWindowViews::SetFocusable(bool focusable) {
  1146. widget()->widget_delegate()->SetCanActivate(focusable);
  1147. #if BUILDFLAG(IS_WIN)
  1148. LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
  1149. if (focusable)
  1150. ex_style &= ~WS_EX_NOACTIVATE;
  1151. else
  1152. ex_style |= WS_EX_NOACTIVATE;
  1153. ::SetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE, ex_style);
  1154. SetSkipTaskbar(!focusable);
  1155. Focus(false);
  1156. #endif
  1157. }
  1158. bool NativeWindowViews::IsFocusable() const {
  1159. bool can_activate = widget()->widget_delegate()->CanActivate();
  1160. #if BUILDFLAG(IS_WIN)
  1161. LONG ex_style = ::GetWindowLong(GetAcceleratedWidget(), GWL_EXSTYLE);
  1162. bool no_activate = ex_style & WS_EX_NOACTIVATE;
  1163. return !no_activate && can_activate;
  1164. #else
  1165. return can_activate;
  1166. #endif
  1167. }
  1168. void NativeWindowViews::SetMenu(ElectronMenuModel* menu_model) {
  1169. #if BUILDFLAG(IS_LINUX)
  1170. // Remove global menu bar.
  1171. if (global_menu_bar_ && menu_model == nullptr) {
  1172. global_menu_bar_.reset();
  1173. root_view_.UnregisterAcceleratorsWithFocusManager();
  1174. return;
  1175. }
  1176. // Use global application menu bar when possible.
  1177. bool can_use_global_menus = ui::OzonePlatform::GetInstance()
  1178. ->GetPlatformProperties()
  1179. .supports_global_application_menus;
  1180. if (can_use_global_menus && ShouldUseGlobalMenuBar()) {
  1181. if (!global_menu_bar_)
  1182. global_menu_bar_ = std::make_unique<GlobalMenuBarX11>(this);
  1183. if (global_menu_bar_->IsServerStarted()) {
  1184. root_view_.RegisterAcceleratorsWithFocusManager(menu_model);
  1185. global_menu_bar_->SetMenu(menu_model);
  1186. return;
  1187. }
  1188. }
  1189. #endif
  1190. // Should reset content size when setting menu.
  1191. gfx::Size content_size = GetContentSize();
  1192. bool should_reset_size = use_content_size_ && has_frame() &&
  1193. !IsMenuBarAutoHide() &&
  1194. ((!!menu_model) != root_view_.HasMenu());
  1195. root_view_.SetMenu(menu_model);
  1196. if (should_reset_size) {
  1197. // Enlarge the size constraints for the menu.
  1198. int menu_bar_height = root_view_.GetMenuBarHeight();
  1199. extensions::SizeConstraints constraints = GetContentSizeConstraints();
  1200. if (constraints.HasMinimumSize()) {
  1201. gfx::Size min_size = constraints.GetMinimumSize();
  1202. min_size.set_height(min_size.height() + menu_bar_height);
  1203. constraints.set_minimum_size(min_size);
  1204. }
  1205. if (constraints.HasMaximumSize()) {
  1206. gfx::Size max_size = constraints.GetMaximumSize();
  1207. max_size.set_height(max_size.height() + menu_bar_height);
  1208. constraints.set_maximum_size(max_size);
  1209. }
  1210. SetContentSizeConstraints(constraints);
  1211. // Resize the window to make sure content size is not changed.
  1212. SetContentSize(content_size);
  1213. }
  1214. }
  1215. void NativeWindowViews::SetParentWindow(NativeWindow* parent) {
  1216. NativeWindow::SetParentWindow(parent);
  1217. #if BUILDFLAG(IS_LINUX)
  1218. if (IsX11()) {
  1219. auto* connection = x11::Connection::Get();
  1220. connection->SetProperty(
  1221. static_cast<x11::Window>(GetAcceleratedWidget()),
  1222. x11::Atom::WM_TRANSIENT_FOR, x11::Atom::WINDOW,
  1223. parent ? static_cast<x11::Window>(parent->GetAcceleratedWidget())
  1224. : ui::GetX11RootWindow());
  1225. }
  1226. #elif BUILDFLAG(IS_WIN)
  1227. // To set parentship between windows into Windows is better to play with the
  1228. // owner instead of the parent, as Windows natively seems to do if a parent
  1229. // is specified at window creation time.
  1230. // For do this we must NOT use the ::SetParent function, instead we must use
  1231. // the ::GetWindowLongPtr or ::SetWindowLongPtr functions with "nIndex" set
  1232. // to "GWLP_HWNDPARENT" which actually means the window owner.
  1233. HWND hwndParent = parent ? parent->GetAcceleratedWidget() : nullptr;
  1234. if (hwndParent ==
  1235. (HWND)::GetWindowLongPtr(GetAcceleratedWidget(), GWLP_HWNDPARENT))
  1236. return;
  1237. ::SetWindowLongPtr(GetAcceleratedWidget(), GWLP_HWNDPARENT,
  1238. (LONG_PTR)hwndParent);
  1239. // Ensures the visibility
  1240. if (IsVisible()) {
  1241. WINDOWPLACEMENT wp;
  1242. wp.length = sizeof(WINDOWPLACEMENT);
  1243. ::GetWindowPlacement(GetAcceleratedWidget(), &wp);
  1244. ::ShowWindow(GetAcceleratedWidget(), SW_HIDE);
  1245. ::ShowWindow(GetAcceleratedWidget(), wp.showCmd);
  1246. ::BringWindowToTop(GetAcceleratedWidget());
  1247. }
  1248. #endif
  1249. }
  1250. gfx::NativeView NativeWindowViews::GetNativeView() const {
  1251. return widget()->GetNativeView();
  1252. }
  1253. gfx::NativeWindow NativeWindowViews::GetNativeWindow() const {
  1254. return widget()->GetNativeWindow();
  1255. }
  1256. void NativeWindowViews::SetProgressBar(double progress,
  1257. NativeWindow::ProgressState state) {
  1258. #if BUILDFLAG(IS_WIN)
  1259. taskbar_host_.SetProgressBar(GetAcceleratedWidget(), progress, state);
  1260. #elif BUILDFLAG(IS_LINUX)
  1261. if (unity::IsRunning()) {
  1262. unity::SetProgressFraction(progress);
  1263. }
  1264. #endif
  1265. }
  1266. void NativeWindowViews::SetOverlayIcon(const gfx::Image& overlay,
  1267. const std::string& description) {
  1268. #if BUILDFLAG(IS_WIN)
  1269. SkBitmap overlay_bitmap = overlay.AsBitmap();
  1270. taskbar_host_.SetOverlayIcon(GetAcceleratedWidget(), overlay_bitmap,
  1271. description);
  1272. #endif
  1273. }
  1274. void NativeWindowViews::SetAutoHideMenuBar(bool auto_hide) {
  1275. root_view_.SetAutoHideMenuBar(auto_hide);
  1276. }
  1277. bool NativeWindowViews::IsMenuBarAutoHide() const {
  1278. return root_view_.is_menu_bar_auto_hide();
  1279. }
  1280. void NativeWindowViews::SetMenuBarVisibility(bool visible) {
  1281. root_view_.SetMenuBarVisibility(visible);
  1282. }
  1283. bool NativeWindowViews::IsMenuBarVisible() const {
  1284. return root_view_.is_menu_bar_visible();
  1285. }
  1286. void NativeWindowViews::SetBackgroundMaterial(const std::string& material) {
  1287. NativeWindow::SetBackgroundMaterial(material);
  1288. #if BUILDFLAG(IS_WIN)
  1289. // DWMWA_USE_HOSTBACKDROPBRUSH is only supported on Windows 11 22H2 and up.
  1290. if (base::win::GetVersion() < base::win::Version::WIN11_22H2)
  1291. return;
  1292. DWM_SYSTEMBACKDROP_TYPE backdrop_type = GetBackdropFromString(material);
  1293. HRESULT result =
  1294. DwmSetWindowAttribute(GetAcceleratedWidget(), DWMWA_SYSTEMBACKDROP_TYPE,
  1295. &backdrop_type, sizeof(backdrop_type));
  1296. if (FAILED(result))
  1297. LOG(WARNING) << "Failed to set background material to " << material;
  1298. // For frameless windows with a background material set, we also need to
  1299. // remove the caption color so it doesn't render a caption bar (since the
  1300. // window is frameless)
  1301. COLORREF caption_color = DWMWA_COLOR_DEFAULT;
  1302. if (backdrop_type != DWMSBT_NONE && backdrop_type != DWMSBT_AUTO &&
  1303. !has_frame()) {
  1304. caption_color = DWMWA_COLOR_NONE;
  1305. }
  1306. result = DwmSetWindowAttribute(GetAcceleratedWidget(), DWMWA_CAPTION_COLOR,
  1307. &caption_color, sizeof(caption_color));
  1308. if (FAILED(result))
  1309. LOG(WARNING) << "Failed to set caption color to transparent";
  1310. #endif
  1311. }
  1312. void NativeWindowViews::SetVisibleOnAllWorkspaces(
  1313. bool visible,
  1314. bool visibleOnFullScreen,
  1315. bool skipTransformProcessType) {
  1316. widget()->SetVisibleOnAllWorkspaces(visible);
  1317. }
  1318. bool NativeWindowViews::IsVisibleOnAllWorkspaces() const {
  1319. #if BUILDFLAG(IS_LINUX)
  1320. if (IsX11()) {
  1321. // Use the presence/absence of _NET_WM_STATE_STICKY in _NET_WM_STATE to
  1322. // determine whether the current window is visible on all workspaces.
  1323. x11::Atom sticky_atom = x11::GetAtom("_NET_WM_STATE_STICKY");
  1324. std::vector<x11::Atom> wm_states;
  1325. auto* connection = x11::Connection::Get();
  1326. connection->GetArrayProperty(
  1327. static_cast<x11::Window>(GetAcceleratedWidget()),
  1328. x11::GetAtom("_NET_WM_STATE"), &wm_states);
  1329. return base::Contains(wm_states, sticky_atom);
  1330. }
  1331. #endif
  1332. return false;
  1333. }
  1334. content::DesktopMediaID NativeWindowViews::GetDesktopMediaID() const {
  1335. const gfx::AcceleratedWidget accelerated_widget = GetAcceleratedWidget();
  1336. content::DesktopMediaID::Id window_handle = content::DesktopMediaID::kNullId;
  1337. content::DesktopMediaID::Id aura_id = content::DesktopMediaID::kNullId;
  1338. #if BUILDFLAG(IS_WIN)
  1339. window_handle =
  1340. reinterpret_cast<content::DesktopMediaID::Id>(accelerated_widget);
  1341. #elif BUILDFLAG(IS_LINUX)
  1342. window_handle = static_cast<uint32_t>(accelerated_widget);
  1343. #endif
  1344. aura::WindowTreeHost* const host =
  1345. aura::WindowTreeHost::GetForAcceleratedWidget(accelerated_widget);
  1346. aura::Window* const aura_window = host ? host->window() : nullptr;
  1347. if (aura_window) {
  1348. aura_id = content::DesktopMediaID::RegisterNativeWindow(
  1349. content::DesktopMediaID::TYPE_WINDOW, aura_window)
  1350. .window_id;
  1351. }
  1352. // No constructor to pass the aura_id. Make sure to not use the other
  1353. // constructor that has a third parameter, it is for yet another purpose.
  1354. content::DesktopMediaID result = content::DesktopMediaID(
  1355. content::DesktopMediaID::TYPE_WINDOW, window_handle);
  1356. // Confusing but this is how content::DesktopMediaID is designed. The id
  1357. // property is the window handle whereas the window_id property is an id
  1358. // given by a map containing all aura instances.
  1359. result.window_id = aura_id;
  1360. return result;
  1361. }
  1362. gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() const {
  1363. if (GetNativeWindow() && GetNativeWindow()->GetHost())
  1364. return GetNativeWindow()->GetHost()->GetAcceleratedWidget();
  1365. else
  1366. return gfx::kNullAcceleratedWidget;
  1367. }
  1368. NativeWindowHandle NativeWindowViews::GetNativeWindowHandle() const {
  1369. return GetAcceleratedWidget();
  1370. }
  1371. gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
  1372. const gfx::Rect& bounds) const {
  1373. if (!has_frame())
  1374. return bounds;
  1375. gfx::Rect window_bounds(bounds);
  1376. #if BUILDFLAG(IS_WIN)
  1377. if (widget()->non_client_view()) {
  1378. HWND hwnd = GetAcceleratedWidget();
  1379. gfx::Rect dpi_bounds = DIPToScreenRect(hwnd, bounds);
  1380. window_bounds = ScreenToDIPRect(
  1381. hwnd, widget()->non_client_view()->GetWindowBoundsForClientBounds(
  1382. dpi_bounds));
  1383. }
  1384. #endif
  1385. if (root_view_.HasMenu() && root_view_.is_menu_bar_visible()) {
  1386. int menu_bar_height = root_view_.GetMenuBarHeight();
  1387. window_bounds.set_y(window_bounds.y() - menu_bar_height);
  1388. window_bounds.set_height(window_bounds.height() + menu_bar_height);
  1389. }
  1390. return window_bounds;
  1391. }
  1392. gfx::Rect NativeWindowViews::WindowBoundsToContentBounds(
  1393. const gfx::Rect& bounds) const {
  1394. if (!has_frame())
  1395. return bounds;
  1396. gfx::Rect content_bounds(bounds);
  1397. #if BUILDFLAG(IS_WIN)
  1398. HWND hwnd = GetAcceleratedWidget();
  1399. content_bounds.set_size(DIPToScreenRect(hwnd, content_bounds).size());
  1400. RECT rect;
  1401. SetRectEmpty(&rect);
  1402. DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
  1403. DWORD ex_style = ::GetWindowLong(hwnd, GWL_EXSTYLE);
  1404. AdjustWindowRectEx(&rect, style, FALSE, ex_style);
  1405. content_bounds.set_width(content_bounds.width() - (rect.right - rect.left));
  1406. content_bounds.set_height(content_bounds.height() - (rect.bottom - rect.top));
  1407. content_bounds.set_size(ScreenToDIPRect(hwnd, content_bounds).size());
  1408. #endif
  1409. if (root_view_.HasMenu() && root_view_.is_menu_bar_visible()) {
  1410. int menu_bar_height = root_view_.GetMenuBarHeight();
  1411. content_bounds.set_y(content_bounds.y() + menu_bar_height);
  1412. content_bounds.set_height(content_bounds.height() - menu_bar_height);
  1413. }
  1414. return content_bounds;
  1415. }
  1416. #if BUILDFLAG(IS_WIN)
  1417. void NativeWindowViews::SetIcon(HICON window_icon, HICON app_icon) {
  1418. // We are responsible for storing the images.
  1419. window_icon_ = base::win::ScopedGDIObject<HICON>(CopyIcon(window_icon));
  1420. app_icon_ = base::win::ScopedGDIObject<HICON>(CopyIcon(app_icon));
  1421. HWND hwnd = GetAcceleratedWidget();
  1422. SendMessage(hwnd, WM_SETICON, ICON_SMALL,
  1423. reinterpret_cast<LPARAM>(window_icon_.get()));
  1424. SendMessage(hwnd, WM_SETICON, ICON_BIG,
  1425. reinterpret_cast<LPARAM>(app_icon_.get()));
  1426. }
  1427. #elif BUILDFLAG(IS_LINUX)
  1428. void NativeWindowViews::SetIcon(const gfx::ImageSkia& icon) {
  1429. auto* tree_host = views::DesktopWindowTreeHostLinux::GetHostForWidget(
  1430. GetAcceleratedWidget());
  1431. tree_host->SetWindowIcons(icon, {});
  1432. }
  1433. #endif
  1434. #if BUILDFLAG(IS_WIN)
  1435. void NativeWindowViews::UpdateThickFrame() {
  1436. if (!thick_frame_)
  1437. return;
  1438. if (IsMaximized() && !transparent()) {
  1439. // For maximized window add thick frame always, otherwise it will be
  1440. // removed in HWNDMessageHandler::SizeConstraintsChanged() which will
  1441. // result in maximized window bounds change.
  1442. FlipWindowStyle(GetAcceleratedWidget(), true, WS_THICKFRAME);
  1443. } else if (has_frame()) {
  1444. FlipWindowStyle(GetAcceleratedWidget(), resizable_, WS_THICKFRAME);
  1445. }
  1446. }
  1447. #endif
  1448. void NativeWindowViews::OnWidgetActivationChanged(views::Widget* changed_widget,
  1449. bool active) {
  1450. if (changed_widget != widget())
  1451. return;
  1452. if (active) {
  1453. MoveBehindTaskBarIfNeeded();
  1454. NativeWindow::NotifyWindowFocus();
  1455. } else {
  1456. NativeWindow::NotifyWindowBlur();
  1457. }
  1458. // Hide menu bar when window is blurred.
  1459. if (!active && IsMenuBarAutoHide() && IsMenuBarVisible())
  1460. SetMenuBarVisibility(false);
  1461. root_view_.ResetAltState();
  1462. }
  1463. void NativeWindowViews::OnWidgetBoundsChanged(views::Widget* changed_widget,
  1464. const gfx::Rect& bounds) {
  1465. if (changed_widget != widget())
  1466. return;
  1467. #if BUILDFLAG(IS_WIN)
  1468. // OnWidgetBoundsChanged is emitted both when a window is moved and when a
  1469. // window is resized. If the window is moving, then
  1470. // WidgetObserver::OnWidgetBoundsChanged is being called from
  1471. // Widget::OnNativeWidgetMove() and not Widget::OnNativeWidgetSizeChanged.
  1472. // |GetWindowBoundsInScreen| has a ~1 pixel margin
  1473. // of error because it converts from floats to integers between
  1474. // calculations, so if we check existing bounds directly against the new
  1475. // bounds without accounting for that we'll have constant false positives
  1476. // when the window is moving but the user hasn't changed its size at all.
  1477. auto isWithinOnePixel = [](gfx::Size old_size, gfx::Size new_size) -> bool {
  1478. return base::IsApproximatelyEqual(old_size.width(), new_size.width(), 1) &&
  1479. base::IsApproximatelyEqual(old_size.height(), new_size.height(), 1);
  1480. };
  1481. if (is_moving_ && isWithinOnePixel(widget_size_, bounds.size()))
  1482. return;
  1483. #endif
  1484. // We use |GetBounds| to account for minimized windows on Windows.
  1485. const auto new_bounds = GetBounds();
  1486. if (widget_size_ != new_bounds.size()) {
  1487. NotifyWindowResize();
  1488. widget_size_ = new_bounds.size();
  1489. }
  1490. }
  1491. void NativeWindowViews::OnWidgetDestroying(views::Widget* widget) {
  1492. aura::Window* window = GetNativeWindow();
  1493. if (window)
  1494. window->RemovePreTargetHandler(this);
  1495. }
  1496. void NativeWindowViews::OnWidgetDestroyed(views::Widget* changed_widget) {
  1497. widget_destroyed_ = true;
  1498. }
  1499. views::View* NativeWindowViews::GetInitiallyFocusedView() {
  1500. return focused_view_;
  1501. }
  1502. bool NativeWindowViews::CanMaximize() const {
  1503. return resizable_ && maximizable_;
  1504. }
  1505. bool NativeWindowViews::CanMinimize() const {
  1506. #if BUILDFLAG(IS_WIN)
  1507. return minimizable_;
  1508. #elif BUILDFLAG(IS_LINUX)
  1509. return true;
  1510. #endif
  1511. }
  1512. std::u16string NativeWindowViews::GetWindowTitle() const {
  1513. return base::UTF8ToUTF16(title_);
  1514. }
  1515. views::View* NativeWindowViews::GetContentsView() {
  1516. return root_view_.GetMainView();
  1517. }
  1518. bool NativeWindowViews::ShouldDescendIntoChildForEventHandling(
  1519. gfx::NativeView child,
  1520. const gfx::Point& location) {
  1521. return NonClientHitTest(location) == HTNOWHERE;
  1522. }
  1523. views::ClientView* NativeWindowViews::CreateClientView(views::Widget* widget) {
  1524. return new NativeWindowClientView{widget, &root_view_, this};
  1525. }
  1526. std::unique_ptr<views::NonClientFrameView>
  1527. NativeWindowViews::CreateNonClientFrameView(views::Widget* widget) {
  1528. #if BUILDFLAG(IS_WIN)
  1529. auto frame_view = std::make_unique<WinFrameView>();
  1530. frame_view->Init(this, widget);
  1531. return frame_view;
  1532. #else
  1533. if (has_frame() && !has_client_frame()) {
  1534. return std::make_unique<NativeFrameView>(this, widget);
  1535. } else {
  1536. if (has_frame() && has_client_frame()) {
  1537. auto frame_view = std::make_unique<ClientFrameViewLinux>();
  1538. frame_view->Init(this, widget);
  1539. return frame_view;
  1540. } else {
  1541. auto frame_view = std::make_unique<OpaqueFrameView>();
  1542. frame_view->Init(this, widget);
  1543. return frame_view;
  1544. }
  1545. }
  1546. #endif
  1547. }
  1548. void NativeWindowViews::OnWidgetMove() {
  1549. NotifyWindowMove();
  1550. }
  1551. void NativeWindowViews::HandleKeyboardEvent(
  1552. content::WebContents*,
  1553. const input::NativeWebKeyboardEvent& event) {
  1554. if (widget_destroyed_)
  1555. return;
  1556. #if BUILDFLAG(IS_LINUX)
  1557. if (event.windows_key_code == ui::VKEY_BROWSER_BACK)
  1558. NotifyWindowExecuteAppCommand(kBrowserBackward);
  1559. else if (event.windows_key_code == ui::VKEY_BROWSER_FORWARD)
  1560. NotifyWindowExecuteAppCommand(kBrowserForward);
  1561. #endif
  1562. keyboard_event_handler_.HandleKeyboardEvent(event,
  1563. root_view_.GetFocusManager());
  1564. root_view_.HandleKeyEvent(event);
  1565. }
  1566. void NativeWindowViews::OnMouseEvent(ui::MouseEvent* event) {
  1567. if (event->type() != ui::EventType::kMousePressed)
  1568. return;
  1569. // Alt+Click should not toggle menu bar.
  1570. root_view_.ResetAltState();
  1571. #if BUILDFLAG(IS_LINUX)
  1572. if (event->changed_button_flags() == ui::EF_BACK_MOUSE_BUTTON)
  1573. NotifyWindowExecuteAppCommand(kBrowserBackward);
  1574. else if (event->changed_button_flags() == ui::EF_FORWARD_MOUSE_BUTTON)
  1575. NotifyWindowExecuteAppCommand(kBrowserForward);
  1576. #endif
  1577. }
  1578. ui::mojom::WindowShowState NativeWindowViews::GetRestoredState() {
  1579. if (IsMaximized()) {
  1580. #if BUILDFLAG(IS_WIN)
  1581. // Restore maximized state for windows that are not translucent.
  1582. if (!IsTranslucent()) {
  1583. return ui::mojom::WindowShowState::kMaximized;
  1584. }
  1585. #else
  1586. return ui::mojom::WindowShowState::kMinimized;
  1587. #endif
  1588. }
  1589. if (IsFullscreen())
  1590. return ui::mojom::WindowShowState::kFullscreen;
  1591. return ui::mojom::WindowShowState::kNormal;
  1592. }
  1593. void NativeWindowViews::MoveBehindTaskBarIfNeeded() {
  1594. #if BUILDFLAG(IS_WIN)
  1595. if (behind_task_bar_) {
  1596. const HWND task_bar_hwnd = ::FindWindow(kUniqueTaskBarClassName, nullptr);
  1597. ::SetWindowPos(GetAcceleratedWidget(), task_bar_hwnd, 0, 0, 0, 0,
  1598. SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
  1599. }
  1600. #endif
  1601. // TODO(julien.isorce): Implement X11 case.
  1602. }
  1603. // static
  1604. std::unique_ptr<NativeWindow> NativeWindow::Create(
  1605. const gin_helper::Dictionary& options,
  1606. NativeWindow* parent) {
  1607. return std::make_unique<NativeWindowViews>(options, parent);
  1608. }
  1609. } // namespace electron