native_window_views.cc 57 KB

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