shell_surface_base.cc 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840
  1. // Copyright 2015 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/exo/shell_surface_base.h"
  5. #include <algorithm>
  6. #include "ash/constants/ash_constants.h"
  7. #include "ash/constants/ash_features.h"
  8. #include "ash/display/screen_orientation_controller.h"
  9. #include "ash/frame/non_client_frame_view_ash.h"
  10. #include "ash/public/cpp/ash_constants.h"
  11. #include "ash/public/cpp/rounded_corner_utils.h"
  12. #include "ash/public/cpp/shelf_types.h"
  13. #include "ash/public/cpp/shell_window_ids.h"
  14. #include "ash/public/cpp/window_properties.h"
  15. #include "ash/screen_util.h"
  16. #include "ash/shell.h"
  17. #include "ash/wm/desks/desks_controller.h"
  18. #include "ash/wm/desks/desks_util.h"
  19. #include "ash/wm/drag_window_resizer.h"
  20. #include "ash/wm/resize_shadow_controller.h"
  21. #include "ash/wm/screen_pinning_controller.h"
  22. #include "ash/wm/window_resizer.h"
  23. #include "ash/wm/window_state.h"
  24. #include "ash/wm/window_util.h"
  25. #include "base/check.h"
  26. #include "base/debug/stack_trace.h"
  27. #include "base/logging.h"
  28. #include "base/memory/ptr_util.h"
  29. #include "base/strings/string_number_conversions.h"
  30. #include "base/strings/stringprintf.h"
  31. #include "base/strings/utf_string_conversions.h"
  32. #include "base/trace_event/trace_event.h"
  33. #include "base/trace_event/traced_value.h"
  34. #include "build/chromeos_buildflags.h"
  35. #include "cc/trees/layer_tree_frame_sink.h"
  36. #include "chromeos/crosapi/cpp/crosapi_constants.h"
  37. #include "chromeos/ui/base/chromeos_ui_constants.h"
  38. #include "chromeos/ui/base/window_pin_type.h"
  39. #include "chromeos/ui/base/window_properties.h"
  40. #include "chromeos/ui/base/window_state_type.h"
  41. #include "chromeos/ui/frame/caption_buttons/snap_controller.h"
  42. #include "chromeos/ui/frame/multitask_menu/float_controller_base.h"
  43. #include "components/app_restore/app_restore_info.h"
  44. #include "components/app_restore/app_restore_utils.h"
  45. #include "components/app_restore/window_properties.h"
  46. #include "components/exo/custom_window_state_delegate.h"
  47. #include "components/exo/security_delegate.h"
  48. #include "components/exo/shell_surface_util.h"
  49. #include "components/exo/surface.h"
  50. #include "components/exo/window_properties.h"
  51. #include "components/exo/wm_helper.h"
  52. #include "third_party/skia/include/core/SkPath.h"
  53. #include "ui/accessibility/ax_enums.mojom.h"
  54. #include "ui/accessibility/ax_node_data.h"
  55. #include "ui/aura/client/aura_constants.h"
  56. #include "ui/aura/client/capture_client.h"
  57. #include "ui/aura/client/cursor_client.h"
  58. #include "ui/aura/client/focus_client.h"
  59. #include "ui/aura/window.h"
  60. #include "ui/aura/window_observer.h"
  61. #include "ui/aura/window_occlusion_tracker.h"
  62. #include "ui/aura/window_targeter.h"
  63. #include "ui/aura/window_tree_host.h"
  64. #include "ui/base/accelerators/accelerator.h"
  65. #include "ui/base/class_property.h"
  66. #include "ui/base/ui_base_features.h"
  67. #include "ui/compositor/compositor.h"
  68. #include "ui/compositor/layer.h"
  69. #include "ui/compositor_extra/shadow.h"
  70. #include "ui/display/display.h"
  71. #include "ui/display/screen.h"
  72. #include "ui/gfx/geometry/size_conversions.h"
  73. #include "ui/gfx/geometry/vector2d_conversions.h"
  74. #include "ui/views/accessibility/view_accessibility.h"
  75. #include "ui/views/layout/fill_layout.h"
  76. #include "ui/views/widget/widget.h"
  77. #include "ui/wm/core/coordinate_conversion.h"
  78. #include "ui/wm/core/shadow_controller.h"
  79. #include "ui/wm/core/shadow_types.h"
  80. #include "ui/wm/core/window_animations.h"
  81. #include "ui/wm/core/window_util.h"
  82. namespace exo {
  83. namespace {
  84. // The accelerator keys used to close ShellSurfaces.
  85. const struct {
  86. ui::KeyboardCode keycode;
  87. int modifiers;
  88. } kCloseWindowAccelerators[] = {
  89. {ui::VKEY_W, ui::EF_CONTROL_DOWN},
  90. {ui::VKEY_W, ui::EF_SHIFT_DOWN | ui::EF_CONTROL_DOWN},
  91. {ui::VKEY_F4, ui::EF_ALT_DOWN}};
  92. class ShellSurfaceWidget : public views::Widget {
  93. public:
  94. ShellSurfaceWidget() = default;
  95. ShellSurfaceWidget(const ShellSurfaceWidget&) = delete;
  96. ShellSurfaceWidget& operator=(const ShellSurfaceWidget&) = delete;
  97. // Overridden from views::Widget:
  98. void OnKeyEvent(ui::KeyEvent* event) override {
  99. if (GetFocusManager()->GetFocusedView() &&
  100. GetFocusManager()->GetFocusedView()->GetWidget() != this) {
  101. // If the focus is on the overlay widget, dispatch the key event normally.
  102. views::Widget::OnKeyEvent(event);
  103. } else if (GetFocusManager()->ProcessAccelerator(ui::Accelerator(*event))) {
  104. // Otherwise handle only accelerators. Do not call Widget::OnKeyEvent that
  105. // eats focus management keys (like the tab key) as well.
  106. event->SetHandled();
  107. }
  108. }
  109. };
  110. class CustomFrameView : public ash::NonClientFrameViewAsh {
  111. public:
  112. using ShapeRects = std::vector<gfx::Rect>;
  113. CustomFrameView(views::Widget* widget,
  114. ShellSurfaceBase* shell_surface,
  115. bool enabled)
  116. : NonClientFrameViewAsh(widget), shell_surface_(shell_surface) {
  117. SetFrameEnabled(enabled);
  118. if (!enabled)
  119. NonClientFrameViewAsh::SetShouldPaintHeader(false);
  120. }
  121. CustomFrameView(const CustomFrameView&) = delete;
  122. CustomFrameView& operator=(const CustomFrameView&) = delete;
  123. ~CustomFrameView() override = default;
  124. // Overridden from ash::NonClientFrameViewAsh:
  125. void SetShouldPaintHeader(bool paint) override {
  126. if (GetFrameEnabled()) {
  127. NonClientFrameViewAsh::SetShouldPaintHeader(paint);
  128. return;
  129. }
  130. }
  131. // Overridden from views::NonClientFrameView:
  132. gfx::Rect GetBoundsForClientView() const override {
  133. if (GetFrameEnabled())
  134. return ash::NonClientFrameViewAsh::GetBoundsForClientView();
  135. return bounds();
  136. }
  137. gfx::Rect GetWindowBoundsForClientBounds(
  138. const gfx::Rect& client_bounds) const override {
  139. if (GetFrameEnabled()) {
  140. return ash::NonClientFrameViewAsh::GetWindowBoundsForClientBounds(
  141. client_bounds);
  142. }
  143. return client_bounds;
  144. }
  145. int NonClientHitTest(const gfx::Point& point) override {
  146. if (GetFrameEnabled() || shell_surface_->server_side_resize())
  147. return ash::NonClientFrameViewAsh::NonClientHitTest(point);
  148. return GetWidget()->client_view()->NonClientHitTest(point);
  149. }
  150. void GetWindowMask(const gfx::Size& size, SkPath* window_mask) override {
  151. if (GetFrameEnabled())
  152. return ash::NonClientFrameViewAsh::GetWindowMask(size, window_mask);
  153. }
  154. void ResetWindowControls() override {
  155. if (GetFrameEnabled())
  156. return ash::NonClientFrameViewAsh::ResetWindowControls();
  157. }
  158. void UpdateWindowIcon() override {
  159. if (GetFrameEnabled())
  160. return ash::NonClientFrameViewAsh::ResetWindowControls();
  161. }
  162. void UpdateWindowTitle() override {
  163. if (GetFrameEnabled())
  164. return ash::NonClientFrameViewAsh::UpdateWindowTitle();
  165. }
  166. void SizeConstraintsChanged() override {
  167. if (GetFrameEnabled())
  168. return ash::NonClientFrameViewAsh::SizeConstraintsChanged();
  169. }
  170. gfx::Size GetMinimumSize() const override {
  171. gfx::Size minimum_size = shell_surface_->GetMinimumSize();
  172. if (GetFrameEnabled()) {
  173. return ash::NonClientFrameViewAsh::GetWindowBoundsForClientBounds(
  174. gfx::Rect(minimum_size))
  175. .size();
  176. }
  177. return minimum_size;
  178. }
  179. gfx::Size GetMaximumSize() const override {
  180. gfx::Size maximum_size = shell_surface_->GetMaximumSize();
  181. if (GetFrameEnabled() && !maximum_size.IsEmpty()) {
  182. return ash::NonClientFrameViewAsh::GetWindowBoundsForClientBounds(
  183. gfx::Rect(maximum_size))
  184. .size();
  185. }
  186. return maximum_size;
  187. }
  188. private:
  189. ShellSurfaceBase* const shell_surface_;
  190. };
  191. class CustomWindowTargeter : public aura::WindowTargeter {
  192. public:
  193. explicit CustomWindowTargeter(ShellSurfaceBase* shell_surface)
  194. : shell_surface_(shell_surface), widget_(shell_surface->GetWidget()) {}
  195. CustomWindowTargeter(const CustomWindowTargeter&) = delete;
  196. CustomWindowTargeter& operator=(const CustomWindowTargeter&) = delete;
  197. ~CustomWindowTargeter() override = default;
  198. // Overridden from aura::WindowTargeter:
  199. bool EventLocationInsideBounds(aura::Window* window,
  200. const ui::LocatedEvent& event) const override {
  201. gfx::Point local_point =
  202. ConvertEventLocationToWindowCoordinates(window, event);
  203. if (IsInResizeHandle(window, event, local_point))
  204. return true;
  205. Surface* surface = GetShellRootSurface(window);
  206. if (!surface)
  207. return false;
  208. int component =
  209. widget_->non_client_view()
  210. ? widget_->non_client_view()->NonClientHitTest(local_point)
  211. : HTNOWHERE;
  212. if (component != HTNOWHERE && component != HTCLIENT &&
  213. component != HTBORDER) {
  214. return true;
  215. }
  216. aura::Window::ConvertPointToTarget(window, surface->window(), &local_point);
  217. return surface->HitTest(local_point);
  218. }
  219. private:
  220. bool IsInResizeHandle(aura::Window* window,
  221. const ui::LocatedEvent& event,
  222. const gfx::Point& local_point) const {
  223. if (window != widget_->GetNativeWindow() ||
  224. !widget_->widget_delegate()->CanResize()) {
  225. return false;
  226. }
  227. if (!shell_surface_->server_side_resize())
  228. return false;
  229. ui::EventTarget* parent =
  230. static_cast<ui::EventTarget*>(window)->GetParentTarget();
  231. if (parent) {
  232. aura::WindowTargeter* parent_targeter =
  233. static_cast<aura::WindowTargeter*>(parent->GetEventTargeter());
  234. if (parent_targeter) {
  235. gfx::Rect mouse_rect;
  236. gfx::Rect touch_rect;
  237. if (parent_targeter->GetHitTestRects(window, &mouse_rect,
  238. &touch_rect)) {
  239. const gfx::Vector2d offset = -window->bounds().OffsetFromOrigin();
  240. mouse_rect.Offset(offset);
  241. touch_rect.Offset(offset);
  242. if (event.IsTouchEvent() || event.IsGestureEvent()
  243. ? touch_rect.Contains(local_point)
  244. : mouse_rect.Contains(local_point)) {
  245. return true;
  246. }
  247. }
  248. }
  249. }
  250. return false;
  251. }
  252. ShellSurfaceBase* shell_surface_;
  253. views::Widget* const widget_;
  254. };
  255. void CloseAllShellSurfaceTransientChildren(aura::Window* window) {
  256. // Deleting a window may delete other transient children. Remove other shell
  257. // surface bases first so they don't get deleted.
  258. auto list = wm::GetTransientChildren(window);
  259. for (size_t i = 0; i < list.size(); ++i) {
  260. if (GetShellSurfaceBaseForWindow(list[i]))
  261. wm::RemoveTransientChild(window, list[i]);
  262. }
  263. }
  264. int shell_id = 0;
  265. void ShowSnapPreview(aura::Window* window,
  266. chromeos::SnapDirection snap_direction) {
  267. chromeos::SnapController::Get()->ShowSnapPreview(
  268. window, snap_direction,
  269. /*allow_haptic_feedback=*/false);
  270. }
  271. void CommitSnap(aura::Window* window, chromeos::SnapDirection snap_direction) {
  272. chromeos::SnapController::Get()->CommitSnap(window, snap_direction);
  273. }
  274. } // namespace
  275. ////////////////////////////////////////////////////////////////////////////////
  276. // ShellSurfaceBase, public:
  277. ShellSurfaceBase::ShellSurfaceBase(Surface* surface,
  278. const gfx::Point& origin,
  279. bool can_minimize,
  280. int container)
  281. : SurfaceTreeHost(base::StringPrintf("ExoShellSurfaceHost-%d", shell_id)),
  282. origin_(origin),
  283. container_(container),
  284. can_minimize_(can_minimize) {
  285. WMHelper::GetInstance()->AddActivationObserver(this);
  286. surface->AddSurfaceObserver(this);
  287. SetRootSurface(surface);
  288. host_window()->Show();
  289. set_owned_by_client();
  290. SetCanMinimize(can_minimize_);
  291. SetCanMaximize(ash::desks_util::IsDeskContainerId(container_));
  292. SetCanResize(true);
  293. SetShowTitle(false);
  294. }
  295. ShellSurfaceBase::~ShellSurfaceBase() {
  296. // If the surface was TrustedPinned, we have to unpin first as this might have
  297. // locked down some system functions.
  298. if (current_pinned_state_ == chromeos::WindowPinType::kTrustedPinned) {
  299. pending_pinned_state_ = chromeos::WindowPinType::kNone;
  300. UpdatePinned();
  301. }
  302. // Close the overlay in case the window is deleted by the server.
  303. overlay_widget_.reset();
  304. // Remove activation observer before hiding widget to prevent it from
  305. // casuing the configure callback to be called.
  306. WMHelper::GetInstance()->RemoveActivationObserver(this);
  307. // Client is gone by now, so don't call callbacks.
  308. close_callback_.Reset();
  309. pre_close_callback_.Reset();
  310. surface_destroyed_callback_.Reset();
  311. if (widget_) {
  312. widget_->GetNativeWindow()->RemoveObserver(this);
  313. widget_->RemoveObserver(this);
  314. // Remove transient children which are shell surfaces so they are not
  315. // automatically destroyed.
  316. CloseAllShellSurfaceTransientChildren(widget_->GetNativeWindow());
  317. if (widget_->IsVisible())
  318. widget_->Hide();
  319. widget_->CloseNow();
  320. }
  321. if (parent_)
  322. parent_->RemoveObserver(this);
  323. if (root_surface())
  324. root_surface()->RemoveSurfaceObserver(this);
  325. if (has_grab_)
  326. WMHelper::GetInstance()->GetCaptureClient()->RemoveObserver(this);
  327. CHECK(!views::WidgetObserver::IsInObserverList());
  328. }
  329. void ShellSurfaceBase::Activate() {
  330. TRACE_EVENT0("exo", "ShellSurfaceBase::Activate");
  331. if (!widget_ || widget_->IsActive())
  332. return;
  333. widget_->Activate();
  334. }
  335. void ShellSurfaceBase::SetTitle(const std::u16string& title) {
  336. TRACE_EVENT1("exo", "ShellSurfaceBase::SetTitle", "title",
  337. base::UTF16ToUTF8(title));
  338. WidgetDelegate::SetTitle(title);
  339. }
  340. void ShellSurfaceBase::SetIcon(const gfx::ImageSkia& icon) {
  341. TRACE_EVENT0("exo", "ShellSurfaceBase::SetIcon");
  342. WidgetDelegate::SetIcon(icon);
  343. }
  344. void ShellSurfaceBase::SetSystemModal(bool system_modal) {
  345. if (system_modal == system_modal_)
  346. return;
  347. bool non_system_modal_window_was_active =
  348. !system_modal_ && widget_ && widget_->IsActive();
  349. system_modal_ = system_modal;
  350. if (widget_) {
  351. UpdateSystemModal();
  352. // Deactivate to give the focus back to normal windows.
  353. if (!system_modal_ && !non_system_modal_window_was_active_) {
  354. widget_->Deactivate();
  355. }
  356. }
  357. non_system_modal_window_was_active_ = non_system_modal_window_was_active;
  358. }
  359. void ShellSurfaceBase::SetBoundsForShadows(
  360. const absl::optional<gfx::Rect>& shadow_bounds) {
  361. if (shadow_bounds_ != shadow_bounds) {
  362. // Set normal shadow bounds.
  363. shadow_bounds_ = shadow_bounds;
  364. shadow_bounds_changed_ = true;
  365. if (widget_ && shadow_bounds) {
  366. // Set resize shadow bounds and origin.
  367. const gfx::Rect bounds = shadow_bounds.value();
  368. const gfx::Point absolute_origin =
  369. widget_->GetNativeWindow()->bounds().origin();
  370. const gfx::Rect absolute_bounds =
  371. gfx::Rect(absolute_origin.x(), absolute_origin.y(), bounds.width(),
  372. bounds.height());
  373. ash::Shell::Get()
  374. ->resize_shadow_controller()
  375. ->UpdateResizeShadowBoundsOfWindow(widget_->GetNativeWindow(),
  376. absolute_bounds);
  377. }
  378. }
  379. }
  380. void ShellSurfaceBase::UpdateSystemModal() {
  381. DCHECK(widget_);
  382. DCHECK_EQ(container_, ash::kShellWindowId_SystemModalContainer);
  383. widget_->GetNativeWindow()->SetProperty(
  384. aura::client::kModalKey,
  385. system_modal_ ? ui::MODAL_TYPE_SYSTEM : ui::MODAL_TYPE_NONE);
  386. }
  387. void ShellSurfaceBase::SetApplicationId(const char* application_id) {
  388. // Store the value in |application_id_| in case the window does not exist yet.
  389. if (application_id)
  390. application_id_ = std::string(application_id);
  391. else
  392. application_id_.reset();
  393. if (widget_ && widget_->GetNativeWindow()) {
  394. SetShellApplicationId(widget_->GetNativeWindow(), application_id_);
  395. WMHelper::AppPropertyResolver::Params params;
  396. if (application_id_)
  397. params.app_id = *application_id_;
  398. if (startup_id_)
  399. params.startup_id = *startup_id_;
  400. ui::PropertyHandler& property_handler = *widget_->GetNativeWindow();
  401. WMHelper::GetInstance()->PopulateAppProperties(params, property_handler);
  402. }
  403. this->NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged,
  404. /* send_native_event */ false);
  405. }
  406. void ShellSurfaceBase::SetStartupId(const char* startup_id) {
  407. // Store the value in |startup_id_| in case the window does not exist yet.
  408. if (startup_id)
  409. startup_id_ = std::string(startup_id);
  410. else
  411. startup_id_.reset();
  412. if (widget_ && widget_->GetNativeWindow())
  413. SetShellStartupId(widget_->GetNativeWindow(), startup_id_);
  414. }
  415. void ShellSurfaceBase::SetUseImmersiveForFullscreen(bool value) {
  416. // Store the value in case the window doesn't exist yet.
  417. immersive_implied_by_fullscreen_ = value;
  418. if (widget_ && widget_->GetNativeWindow())
  419. SetShellUseImmersiveForFullscreen(widget_->GetNativeWindow(), value);
  420. }
  421. void ShellSurfaceBase::ShowSnapPreviewToPrimary() {
  422. ShowSnapPreview(widget_->GetNativeWindow(),
  423. chromeos::SnapDirection::kPrimary);
  424. }
  425. void ShellSurfaceBase::ShowSnapPreviewToSecondary() {
  426. ShowSnapPreview(widget_->GetNativeWindow(),
  427. chromeos::SnapDirection::kSecondary);
  428. }
  429. void ShellSurfaceBase::HideSnapPreview() {
  430. ShowSnapPreview(widget_->GetNativeWindow(), chromeos::SnapDirection::kNone);
  431. }
  432. void ShellSurfaceBase::SetSnappedToPrimary() {
  433. CommitSnap(widget_->GetNativeWindow(), chromeos::SnapDirection::kPrimary);
  434. }
  435. void ShellSurfaceBase::SetSnappedToSecondary() {
  436. CommitSnap(widget_->GetNativeWindow(), chromeos::SnapDirection::kSecondary);
  437. }
  438. void ShellSurfaceBase::UnsetSnap() {
  439. CommitSnap(widget_->GetNativeWindow(), chromeos::SnapDirection::kNone);
  440. }
  441. void ShellSurfaceBase::SetCanGoBack() {
  442. if (widget_)
  443. widget_->GetNativeWindow()->SetProperty(ash::kMinimizeOnBackKey, false);
  444. }
  445. void ShellSurfaceBase::UnsetCanGoBack() {
  446. if (widget_)
  447. widget_->GetNativeWindow()->SetProperty(ash::kMinimizeOnBackKey, true);
  448. }
  449. void ShellSurfaceBase::SetPip() {
  450. if (!widget_) {
  451. pending_pip_ = true;
  452. return;
  453. }
  454. pending_pip_ = false;
  455. // Set all the necessary window properties and window state.
  456. auto* window = widget_->GetNativeWindow();
  457. window->SetProperty(ash::kWindowPipTypeKey, true);
  458. window->SetProperty(aura::client::kZOrderingKey,
  459. ui::ZOrderLevel::kFloatingWindow);
  460. if (initial_bounds_)
  461. return;
  462. // If no initial bounds is specified, pip windows should start in the bottom
  463. // right corner of the screen so move |window| to the bottom right of the
  464. // work area and let the pip positioner move it within the work area.
  465. auto display = display::Screen::GetScreen()->GetDisplayNearestWindow(window);
  466. gfx::Size window_size = window->bounds().size();
  467. window->SetBoundsInScreen(
  468. gfx::Rect(display.work_area().bottom_right(), window_size), display);
  469. }
  470. void ShellSurfaceBase::UnsetPip() {
  471. if (!widget_) {
  472. pending_pip_ = false;
  473. return;
  474. }
  475. // Set all the necessary window properties and window state.
  476. auto* window = widget_->GetNativeWindow();
  477. window->SetProperty(ash::kWindowPipTypeKey, false);
  478. window->SetProperty(aura::client::kZOrderingKey, ui::ZOrderLevel::kNormal);
  479. }
  480. void ShellSurfaceBase::MoveToDesk(int desk_index) {
  481. if (widget_) {
  482. ash::DesksController::Get()->SendToDeskAtIndex(widget_->GetNativeWindow(),
  483. desk_index);
  484. }
  485. }
  486. void ShellSurfaceBase::SetVisibleOnAllWorkspaces() {
  487. if (widget_)
  488. widget_->SetVisibleOnAllWorkspaces(true);
  489. }
  490. void ShellSurfaceBase::SetInitialWorkspace(const char* initial_workspace) {
  491. if (initial_workspace)
  492. initial_workspace_ = std::string(initial_workspace);
  493. else
  494. initial_workspace_.reset();
  495. }
  496. void ShellSurfaceBase::Pin(bool trusted) {
  497. pending_pinned_state_ = trusted ? chromeos::WindowPinType::kTrustedPinned
  498. : chromeos::WindowPinType::kPinned;
  499. UpdatePinned();
  500. }
  501. void ShellSurfaceBase::Unpin() {
  502. // Only need to do something when we have to set a pinned mode.
  503. if (pending_pinned_state_ == chromeos::WindowPinType::kNone)
  504. return;
  505. // Remove any pending pin states which might not have been applied yet.
  506. pending_pinned_state_ = chromeos::WindowPinType::kNone;
  507. UpdatePinned();
  508. }
  509. void ShellSurfaceBase::UpdatePinned() {
  510. if (!widget_) {
  511. // It is possible to get here before the widget has actually been created.
  512. // The state will be set once the widget gets created.
  513. return;
  514. }
  515. if (current_pinned_state_ != pending_pinned_state_) {
  516. auto* window = widget_->GetNativeWindow();
  517. if (pending_pinned_state_ == chromeos::WindowPinType::kNone) {
  518. ash::WindowState::Get(window)->Restore();
  519. } else {
  520. bool trusted_pinned =
  521. pending_pinned_state_ == chromeos::WindowPinType::kTrustedPinned;
  522. ash::window_util::PinWindow(window,
  523. /*trusted=*/trusted_pinned);
  524. }
  525. current_pinned_state_ = pending_pinned_state_;
  526. }
  527. }
  528. void ShellSurfaceBase::SetChildAxTreeId(ui::AXTreeID child_ax_tree_id) {
  529. GetViewAccessibility().OverrideChildTreeID(child_ax_tree_id);
  530. this->NotifyAccessibilityEvent(ax::mojom::Event::kChildrenChanged, false);
  531. }
  532. void ShellSurfaceBase::SetGeometry(const gfx::Rect& geometry) {
  533. TRACE_EVENT1("exo", "ShellSurfaceBase::SetGeometry", "geometry",
  534. geometry.ToString());
  535. if (geometry.IsEmpty()) {
  536. DLOG(WARNING) << "Surface geometry must be non-empty";
  537. return;
  538. }
  539. pending_geometry_ = geometry;
  540. }
  541. void ShellSurfaceBase::SetWindowBounds(const gfx::Rect& bounds) {
  542. TRACE_EVENT1("exo", "ShellSurfaceBase::SetWindowBounds", "bounds",
  543. bounds.ToString());
  544. if (!widget_) {
  545. initial_bounds_.emplace(bounds);
  546. return;
  547. }
  548. // TODO(crbug.com/1261321): This will not work if the full server side
  549. // decoration is used.
  550. DCHECK(!frame_enabled());
  551. widget_->SetBounds(bounds);
  552. }
  553. void ShellSurfaceBase::SetRestoreInfo(int32_t restore_session_id,
  554. int32_t restore_window_id) {
  555. // TODO(crbug.com/1327490): Rename restore info variables.
  556. // Restore information must be set before widget is created.
  557. DCHECK(!widget_);
  558. restore_session_id_.emplace(restore_session_id);
  559. restore_window_id_.emplace(restore_window_id);
  560. }
  561. void ShellSurfaceBase::SetRestoreInfoWithWindowIdSource(
  562. int32_t restore_session_id,
  563. const std::string& restore_window_id_source) {
  564. restore_session_id_.emplace(restore_session_id);
  565. if (!restore_window_id_source.empty())
  566. restore_window_id_source_.emplace(restore_window_id_source);
  567. }
  568. void ShellSurfaceBase::SetFloat() {
  569. // TODO(crbug.com/1347534): This currently can unset float as well, but its
  570. // necessary until configure request is ready otherwise the window will remain
  571. // floated forever.
  572. chromeos::FloatControllerBase::Get()->ToggleFloat(widget_->GetNativeWindow());
  573. }
  574. void ShellSurfaceBase::UnsetFloat() {
  575. chromeos::FloatControllerBase::Get()->ToggleFloat(widget_->GetNativeWindow());
  576. }
  577. void ShellSurfaceBase::SetDisplay(int64_t display_id) {
  578. TRACE_EVENT1("exo", "ShellSurfaceBase::SetDisplay", "display_id", display_id);
  579. pending_display_id_ = display_id;
  580. }
  581. void ShellSurfaceBase::SetOrigin(const gfx::Point& origin) {
  582. TRACE_EVENT1("exo", "ShellSurfaceBase::SetOrigin", "origin",
  583. origin.ToString());
  584. origin_ = origin;
  585. }
  586. void ShellSurfaceBase::SetActivatable(bool activatable) {
  587. TRACE_EVENT1("exo", "ShellSurfaceBase::SetActivatable", "activatable",
  588. activatable);
  589. activatable_ = activatable;
  590. }
  591. void ShellSurfaceBase::SetContainer(int container) {
  592. TRACE_EVENT1("exo", "ShellSurfaceBase::SetContainer", "container", container);
  593. SetContainerInternal(container);
  594. }
  595. void ShellSurfaceBase::SetMaximumSize(const gfx::Size& size) {
  596. TRACE_EVENT1("exo", "ShellSurfaceBase::SetMaximumSize", "size",
  597. size.ToString());
  598. pending_maximum_size_ = size;
  599. }
  600. void ShellSurfaceBase::SetMinimumSize(const gfx::Size& size) {
  601. TRACE_EVENT1("exo", "ShellSurfaceBase::SetMinimumSize", "size",
  602. size.ToString());
  603. pending_minimum_size_ = size;
  604. }
  605. void ShellSurfaceBase::SetAspectRatio(const gfx::SizeF& aspect_ratio) {
  606. TRACE_EVENT1("exo", "ShellSurfaceBase::SetAspectRatio", "aspect_ratio",
  607. aspect_ratio.ToString());
  608. pending_aspect_ratio_ = aspect_ratio;
  609. }
  610. void ShellSurfaceBase::SetCanMinimize(bool can_minimize) {
  611. TRACE_EVENT1("exo", "ShellSurfaceBase::SetCanMinimize", "can_minimize",
  612. can_minimize);
  613. can_minimize_ = can_minimize;
  614. WidgetDelegate::SetCanMinimize(!parent_ && can_minimize_);
  615. }
  616. void ShellSurfaceBase::SetMenu() {
  617. is_menu_ = true;
  618. }
  619. void ShellSurfaceBase::DisableMovement() {
  620. movement_disabled_ = true;
  621. SetCanResize(false);
  622. if (widget_)
  623. widget_->set_movement_disabled(true);
  624. }
  625. void ShellSurfaceBase::UpdateResizability() {
  626. SetCanResize(CalculateCanResize());
  627. auto max_size = GetMaximumSize();
  628. // Allow maximizeing if the max size is bigger than 32k resolution.
  629. SetCanMaximize(CanResize() && !parent_ &&
  630. ash::desks_util::IsDeskContainerId(container_) &&
  631. (max_size.IsEmpty() ||
  632. (max_size.width() > ash::kAllowMaximizeThreshold &&
  633. max_size.height() > ash::kAllowMaximizeThreshold)));
  634. }
  635. void ShellSurfaceBase::RebindRootSurface(Surface* root_surface,
  636. bool can_minimize,
  637. int container) {
  638. can_minimize_ = can_minimize;
  639. container_ = container;
  640. this->root_surface()->RemoveSurfaceObserver(this);
  641. root_surface->AddSurfaceObserver(this);
  642. SetRootSurface(root_surface);
  643. host_window()->Show();
  644. // Re-apply window properties to the new root surface.
  645. auto* window = widget_ ? widget_->GetNativeWindow() : nullptr;
  646. if (window) {
  647. // Int properties.
  648. for (auto* const key :
  649. {aura::client::kSkipImeProcessing, chromeos::kFrameRestoreLookKey,
  650. ash::kFrameRateThrottleKey}) {
  651. if (base::Contains(window->GetAllPropertyKeys(), key)) {
  652. OnWindowPropertyChanged(window, key,
  653. /*old_value(unused)=*/0);
  654. }
  655. }
  656. // Boolean property.
  657. if (base::Contains(window->GetAllPropertyKeys(),
  658. aura::client::kWindowWorkspaceKey)) {
  659. OnWindowPropertyChanged(window, aura::client::kWindowWorkspaceKey,
  660. /*old_value(unused)=*/0);
  661. }
  662. if (window->HasFocus())
  663. host_window()->Focus();
  664. }
  665. SetCanMinimize(can_minimize_);
  666. SetCanMaximize(ash::desks_util::IsDeskContainerId(container_));
  667. SetCanResize(true);
  668. SetShowTitle(false);
  669. }
  670. std::unique_ptr<base::trace_event::TracedValue>
  671. ShellSurfaceBase::AsTracedValue() const {
  672. std::unique_ptr<base::trace_event::TracedValue> value(
  673. new base::trace_event::TracedValue());
  674. value->SetString("title", base::UTF16ToUTF8(GetWindowTitle()));
  675. if (GetWidget() && GetWidget()->GetNativeWindow()) {
  676. const std::string* application_id =
  677. GetShellApplicationId(GetWidget()->GetNativeWindow());
  678. if (application_id)
  679. value->SetString("application_id", *application_id);
  680. const std::string* startup_id =
  681. GetShellStartupId(GetWidget()->GetNativeWindow());
  682. if (startup_id)
  683. value->SetString("startup_id", *startup_id);
  684. }
  685. return value;
  686. }
  687. void ShellSurfaceBase::AddOverlay(OverlayParams&& overlay_params) {
  688. DCHECK(widget_);
  689. DCHECK(!overlay_widget_);
  690. overlay_overlaps_frame_ = overlay_params.overlaps_frame;
  691. overlay_can_resize_ = std::move(overlay_params.can_resize);
  692. views::Widget::InitParams params(views::Widget::InitParams::TYPE_CONTROL);
  693. params.parent = widget_->GetNativeWindow();
  694. params.ownership = views::Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
  695. if (overlay_params.translucent)
  696. params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
  697. if (overlay_params.focusable)
  698. params.activatable = views::Widget::InitParams::Activatable::kYes;
  699. params.delegate = new views::WidgetDelegate();
  700. params.delegate->SetOwnedByWidget(true);
  701. params.delegate->SetContentsView(std::move(overlay_params.contents_view));
  702. params.name = "Overlay";
  703. overlay_widget_ = std::make_unique<views::Widget>();
  704. overlay_widget_->Init(std::move(params));
  705. overlay_widget_->GetNativeWindow()->SetEventTargeter(
  706. std::make_unique<aura::WindowTargeter>());
  707. overlay_widget_->Show();
  708. // Setup Focus Traversal.
  709. overlay_widget_->SetFocusTraversableParentView(this);
  710. overlay_widget_->SetFocusTraversableParent(
  711. GetWidget()->GetFocusTraversable());
  712. SetFocusTraversesOut(true);
  713. skip_ime_processing_ = GetWidget()->GetNativeWindow()->GetProperty(
  714. aura::client::kSkipImeProcessing);
  715. if (skip_ime_processing_) {
  716. GetWidget()->GetNativeWindow()->SetProperty(
  717. aura::client::kSkipImeProcessing, false);
  718. }
  719. UpdateWidgetBounds();
  720. UpdateResizability();
  721. }
  722. void ShellSurfaceBase::RemoveOverlay() {
  723. overlay_widget_.reset();
  724. SetFocusTraversesOut(false);
  725. if (skip_ime_processing_) {
  726. GetWidget()->GetNativeWindow()->SetProperty(
  727. aura::client::kSkipImeProcessing, true);
  728. }
  729. UpdateResizability();
  730. }
  731. ////////////////////////////////////////////////////////////////////////////////
  732. // SurfaceDelegate overrides:
  733. void ShellSurfaceBase::OnSurfaceCommit() {
  734. // Pause occlusion tracking since we will update a bunch of window properties.
  735. aura::WindowOcclusionTracker::ScopedPause pause_occlusion;
  736. // SetShadowBounds requires synchronizing shadow bounds with the next frame,
  737. // so submit the next frame to a new surface and let the host window use the
  738. // new surface.
  739. if (shadow_bounds_changed_)
  740. host_window()->AllocateLocalSurfaceId();
  741. DCHECK(presentation_callbacks().empty());
  742. root_surface()->CommitSurfaceHierarchy(false);
  743. if (!OnPreWidgetCommit())
  744. return;
  745. CommitWidget();
  746. OnPostWidgetCommit();
  747. SubmitCompositorFrame();
  748. }
  749. bool ShellSurfaceBase::IsInputEnabled(Surface*) const {
  750. return true;
  751. }
  752. void ShellSurfaceBase::OnSetFrame(SurfaceFrameType frame_type) {
  753. if (!IsFrameDecorationSupported(frame_type)) {
  754. DLOG(WARNING)
  755. << "popup does not support frame decoration other than NONE/SHADOW.";
  756. return;
  757. }
  758. bool frame_was_disabled = !frame_enabled();
  759. bool frame_type_changed = frame_type_ != frame_type;
  760. frame_type_ = frame_type;
  761. switch (frame_type) {
  762. case SurfaceFrameType::NONE:
  763. shadow_bounds_.reset();
  764. break;
  765. case SurfaceFrameType::NORMAL:
  766. case SurfaceFrameType::AUTOHIDE:
  767. case SurfaceFrameType::OVERLAY:
  768. case SurfaceFrameType::SHADOW:
  769. // Initialize the shadow if it didn't exist. Do not reset if
  770. // the frame type just switched from another enabled type or
  771. // there is a pending shadow_bounds_ change to avoid overriding
  772. // a shadow bounds which have been changed and not yet committed.
  773. if (frame_type_changed &&
  774. (!shadow_bounds_ || (frame_was_disabled && !shadow_bounds_changed_)))
  775. shadow_bounds_ = gfx::Rect();
  776. break;
  777. }
  778. if (!widget_)
  779. return;
  780. // Override redirect window and popup can request NONE/SHADOW. The shadow
  781. // will be updated in next commit.
  782. if (widget_->non_client_view()) {
  783. CustomFrameView* frame_view =
  784. static_cast<CustomFrameView*>(widget_->non_client_view()->frame_view());
  785. if (frame_view->GetFrameEnabled() == frame_enabled())
  786. return;
  787. frame_view->SetFrameEnabled(frame_enabled());
  788. frame_view->SetShouldPaintHeader(frame_enabled());
  789. }
  790. widget_->GetRootView()->Layout();
  791. // TODO(oshima): We probably should wait applying these if the
  792. // window is animating.
  793. UpdateWidgetBounds();
  794. UpdateSurfaceBounds();
  795. }
  796. void ShellSurfaceBase::OnSetFrameColors(SkColor active_color,
  797. SkColor inactive_color) {
  798. has_frame_colors_ = true;
  799. active_frame_color_ = SkColorSetA(active_color, SK_AlphaOPAQUE);
  800. inactive_frame_color_ = SkColorSetA(inactive_color, SK_AlphaOPAQUE);
  801. if (widget_) {
  802. // Set kTrackDefaultFrameColors to false to prevent clobbering the active
  803. // and inactive frame colors during theme changes.
  804. widget_->GetNativeWindow()->SetProperty(chromeos::kTrackDefaultFrameColors,
  805. false);
  806. widget_->GetNativeWindow()->SetProperty(chromeos::kFrameActiveColorKey,
  807. active_frame_color_);
  808. widget_->GetNativeWindow()->SetProperty(chromeos::kFrameInactiveColorKey,
  809. inactive_frame_color_);
  810. }
  811. }
  812. void ShellSurfaceBase::OnSetStartupId(const char* startup_id) {
  813. SetStartupId(startup_id);
  814. }
  815. void ShellSurfaceBase::OnSetApplicationId(const char* application_id) {
  816. SetApplicationId(application_id);
  817. }
  818. void ShellSurfaceBase::OnActivationRequested() {
  819. if (widget_ && GetSecurityDelegate() &&
  820. GetSecurityDelegate()->CanSelfActivate(widget_->GetNativeWindow())) {
  821. this->Activate();
  822. }
  823. }
  824. void ShellSurfaceBase::OnSetServerStartResize() {
  825. server_side_resize_ = true;
  826. }
  827. ////////////////////////////////////////////////////////////////////////////////
  828. // SurfaceObserver overrides:
  829. void ShellSurfaceBase::OnSurfaceDestroying(Surface* surface) {
  830. DCHECK_EQ(root_surface(), surface);
  831. surface->RemoveSurfaceObserver(this);
  832. SetRootSurface(nullptr);
  833. overlay_widget_.reset();
  834. if (widget_)
  835. SetShellRootSurface(widget_->GetNativeWindow(), nullptr);
  836. // Hide widget before surface is destroyed. This allows hide animations to
  837. // run using the current surface contents.
  838. if (widget_) {
  839. // Remove transient children which are shell surfaces so they are not
  840. // automatically hidden.
  841. CloseAllShellSurfaceTransientChildren(widget_->GetNativeWindow());
  842. widget_->Hide();
  843. }
  844. // Note: In its use in the Wayland server implementation, the surface
  845. // destroyed callback may destroy the ShellSurface instance. This call needs
  846. // to be last so that the instance can be destroyed.
  847. if (!surface_destroyed_callback_.is_null())
  848. std::move(surface_destroyed_callback_).Run();
  849. }
  850. ////////////////////////////////////////////////////////////////////////////////
  851. // views::WidgetDelegate overrides:
  852. bool ShellSurfaceBase::OnCloseRequested(
  853. views::Widget::ClosedReason close_reason) {
  854. if (!pre_close_callback_.is_null())
  855. pre_close_callback_.Run();
  856. // Closing the shell surface is a potentially asynchronous operation, so we
  857. // will defer actually closing the Widget right now, and come back and call
  858. // CloseNow() when the callback completes and the shell surface is destroyed
  859. // (see ~ShellSurfaceBase()).
  860. if (!close_callback_.is_null())
  861. close_callback_.Run();
  862. return false;
  863. }
  864. void ShellSurfaceBase::WindowClosing() {
  865. SetEnabled(false);
  866. if (widget_)
  867. widget_->RemoveObserver(this);
  868. widget_ = nullptr;
  869. }
  870. views::Widget* ShellSurfaceBase::GetWidget() {
  871. return widget_;
  872. }
  873. const views::Widget* ShellSurfaceBase::GetWidget() const {
  874. return widget_;
  875. }
  876. views::View* ShellSurfaceBase::GetContentsView() {
  877. return this;
  878. }
  879. std::unique_ptr<views::NonClientFrameView>
  880. ShellSurfaceBase::CreateNonClientFrameView(views::Widget* widget) {
  881. return CreateNonClientFrameViewInternal(widget);
  882. }
  883. bool ShellSurfaceBase::ShouldSaveWindowPlacement() const {
  884. return !is_popup_ && !movement_disabled_;
  885. }
  886. bool ShellSurfaceBase::WidgetHasHitTestMask() const {
  887. return true;
  888. }
  889. void ShellSurfaceBase::GetWidgetHitTestMask(SkPath* mask) const {
  890. GetHitTestMask(mask);
  891. gfx::Point origin = host_window()->bounds().origin();
  892. SkMatrix matrix;
  893. float scale = GetScale();
  894. matrix.setScaleTranslate(
  895. SkFloatToScalar(1.0f / scale), SkFloatToScalar(1.0f / scale),
  896. SkIntToScalar(origin.x()), SkIntToScalar(origin.y()));
  897. mask->transform(matrix);
  898. }
  899. void ShellSurfaceBase::OnCaptureChanged(aura::Window* lost_capture,
  900. aura::Window* gained_capture) {
  901. if (lost_capture == widget_->GetNativeWindow() && is_popup_) {
  902. WMHelper::GetInstance()->GetCaptureClient()->RemoveObserver(this);
  903. if (gained_capture &&
  904. lost_capture == wm::GetTransientParent(gained_capture)) {
  905. // Don't close if the capture has been transferred to the child popup.
  906. return;
  907. }
  908. aura::Window* parent = wm::GetTransientParent(lost_capture);
  909. if (parent) {
  910. // The capture needs to be transferred to the parent if it had grab.
  911. views::Widget* parent_widget =
  912. views::Widget::GetWidgetForNativeWindow(parent);
  913. ShellSurfaceBase* parent_shell_surface = static_cast<ShellSurfaceBase*>(
  914. parent_widget->widget_delegate()->GetContentsView());
  915. if (parent_shell_surface->has_grab_)
  916. parent_shell_surface->StartCapture();
  917. }
  918. widget_->Close();
  919. }
  920. }
  921. ////////////////////////////////////////////////////////////////////////////////
  922. // views::WidgetObserver overrides:
  923. void ShellSurfaceBase::OnWidgetClosing(views::Widget* widget) {
  924. DCHECK(widget_ == widget);
  925. // To force the widget to close we first disconnect this shell surface from
  926. // its underlying surface, by asserting to it that the surface destroyed
  927. // itself. After that, it is safe to call CloseNow() on the widget.
  928. //
  929. // TODO(crbug.com/1010326): This only closes the aura/exo pieces, but we
  930. // should go one level deeper and destroy the wayland stuff. Some options:
  931. // - Invoke xkill under-the-hood, which will only work for x11 and won't
  932. // work if the container itself is stuck.
  933. // - Close the wl connection to the client (i.e. wlkill) this is
  934. // problematic with X11 as all of xwayland shares the same client.
  935. // - Transitively kill all the wl_resources rooted at this window's
  936. // wl_surface, which is not really supported in wayland.
  937. OnSurfaceDestroying(root_surface());
  938. }
  939. ////////////////////////////////////////////////////////////////////////////////
  940. // views::Views overrides:
  941. gfx::Size ShellSurfaceBase::CalculatePreferredSize() const {
  942. if (!geometry_.IsEmpty())
  943. return geometry_.size();
  944. // The root surface's content bounds should be used instead of the host window
  945. // bounds because the host window bounds are not updated until the widget is
  946. // committed, meaning that if we need to calculate the preferred size before
  947. // then (e.g. in OnPreWidgetCommit()), then we need to use the root surface's
  948. // to ensure that we're using the correct bounds' size.
  949. return root_surface()->surface_hierarchy_content_bounds().size();
  950. }
  951. gfx::Size ShellSurfaceBase::GetMinimumSize() const {
  952. return minimum_size_.IsEmpty() ? gfx::Size(1, 1) : minimum_size_;
  953. }
  954. gfx::Size ShellSurfaceBase::GetMaximumSize() const {
  955. // On ChromeOS, non empty maximum size will make the window
  956. // non maximizable.
  957. return maximum_size_;
  958. }
  959. void ShellSurfaceBase::GetAccessibleNodeData(ui::AXNodeData* node_data) {
  960. node_data->role = ax::mojom::Role::kClient;
  961. if (application_id_) {
  962. node_data->AddStringAttribute(
  963. ax::mojom::StringAttribute::kChildTreeNodeAppId, *application_id_);
  964. }
  965. }
  966. views::FocusTraversable* ShellSurfaceBase::GetFocusTraversable() {
  967. return overlay_widget_.get();
  968. }
  969. ////////////////////////////////////////////////////////////////////////////////
  970. // aura::WindowObserver overrides:
  971. void ShellSurfaceBase::OnWindowDestroying(aura::Window* window) {
  972. if (window == parent_)
  973. SetParentInternal(nullptr);
  974. window->RemoveObserver(this);
  975. if (widget_ && window == widget_->GetNativeWindow() && root_surface())
  976. root_surface()->ThrottleFrameRate(false);
  977. }
  978. void ShellSurfaceBase::OnWindowPropertyChanged(aura::Window* window,
  979. const void* key,
  980. intptr_t old_value) {
  981. if (widget_ && window == widget_->GetNativeWindow()) {
  982. if (key == aura::client::kSkipImeProcessing) {
  983. SetSkipImeProcessingToDescendentSurfaces(
  984. window, window->GetProperty(aura::client::kSkipImeProcessing));
  985. } else if (key == chromeos::kFrameRestoreLookKey) {
  986. root_surface()->SetFrameLocked(
  987. window->GetProperty(chromeos::kFrameRestoreLookKey));
  988. } else if (key == aura::client::kWindowWorkspaceKey) {
  989. root_surface()->OnDeskChanged(GetWindowDeskStateChanged(window));
  990. } else if (key == ash::kFrameRateThrottleKey) {
  991. root_surface()->ThrottleFrameRate(
  992. window->GetProperty(ash::kFrameRateThrottleKey));
  993. }
  994. }
  995. }
  996. void ShellSurfaceBase::OnWindowAddedToRootWindow(aura::Window* window) {
  997. UpdateDisplayOnTree();
  998. }
  999. void ShellSurfaceBase::OnWindowParentChanged(aura::Window* window,
  1000. aura::Window* parent) {
  1001. root_surface()->OnDeskChanged(GetWindowDeskStateChanged(window));
  1002. }
  1003. ////////////////////////////////////////////////////////////////////////////////
  1004. // wm::ActivationChangeObserver overrides:
  1005. void ShellSurfaceBase::OnWindowActivated(ActivationReason reason,
  1006. aura::Window* gained_active,
  1007. aura::Window* lost_active) {
  1008. if (!widget_)
  1009. return;
  1010. if (overlay_widget_ && overlay_widget_->widget_delegate()->CanActivate()) {
  1011. aura::client::FocusClient* client =
  1012. aura::client::GetFocusClient(widget_->GetNativeWindow());
  1013. client->ResetFocusWithinActiveWindow(overlay_widget_->GetNativeWindow());
  1014. }
  1015. if (gained_active == widget_->GetNativeWindow() ||
  1016. lost_active == widget_->GetNativeWindow()) {
  1017. DCHECK(gained_active != widget_->GetNativeWindow() || CanActivate());
  1018. UpdateShadow();
  1019. }
  1020. }
  1021. // Returns true if surface is currently being resized.
  1022. bool ShellSurfaceBase::IsDragged() const {
  1023. if (in_extended_drag_)
  1024. return true;
  1025. if (!widget_)
  1026. return false;
  1027. ash::WindowState* window_state =
  1028. ash::WindowState::Get(widget_->GetNativeWindow());
  1029. return window_state ? window_state->is_dragged() : false;
  1030. }
  1031. ////////////////////////////////////////////////////////////////////////////////
  1032. // ui::AcceleratorTarget overrides:
  1033. bool ShellSurfaceBase::AcceleratorPressed(const ui::Accelerator& accelerator) {
  1034. for (const auto& entry : kCloseWindowAccelerators) {
  1035. if (ui::Accelerator(entry.keycode, entry.modifiers) == accelerator) {
  1036. OnCloseRequested(views::Widget::ClosedReason::kUnspecified);
  1037. return true;
  1038. }
  1039. }
  1040. return views::View::AcceleratorPressed(accelerator);
  1041. }
  1042. ////////////////////////////////////////////////////////////////////////////////
  1043. // ShellSurfaceBase, protected:
  1044. void ShellSurfaceBase::CreateShellSurfaceWidget(
  1045. ui::WindowShowState show_state) {
  1046. DCHECK(GetEnabled());
  1047. DCHECK(!widget_);
  1048. // Sommelier sets the null application id for override redirect windows,
  1049. // which controls its bounds by itself.
  1050. bool emulate_x11_override_redirect =
  1051. !is_popup_ && parent_ && ash::desks_util::IsDeskContainerId(container_) &&
  1052. !application_id_.has_value();
  1053. if (emulate_x11_override_redirect) {
  1054. // override redirect is used for menu, tooltips etc, which should be placed
  1055. // above normal windows, but below lock screen. Specify the container here
  1056. // to avoid using parent_ in params.parent.
  1057. SetContainerInternal(ash::kShellWindowId_ShelfBubbleContainer);
  1058. // X11 override redirect should not be activatable.
  1059. activatable_ = false;
  1060. DisableMovement();
  1061. }
  1062. if (system_modal_)
  1063. SetModalType(ui::MODAL_TYPE_SYSTEM);
  1064. views::Widget::InitParams params;
  1065. params.type = (emulate_x11_override_redirect || is_menu_)
  1066. ? views::Widget::InitParams::TYPE_MENU
  1067. : (is_popup_ ? views::Widget::InitParams::TYPE_POPUP
  1068. : views::Widget::InitParams::TYPE_WINDOW);
  1069. params.ownership = views::Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
  1070. params.delegate = this;
  1071. params.shadow_type = views::Widget::InitParams::ShadowType::kNone;
  1072. params.opacity = views::Widget::InitParams::WindowOpacity::kTranslucent;
  1073. params.show_state = show_state;
  1074. if (initial_z_order_.has_value())
  1075. params.z_order = initial_z_order_.value();
  1076. if (initial_workspace_.has_value()) {
  1077. const std::string kToggleVisibleOnAllWorkspacesValue = "-1";
  1078. if (initial_workspace_ == kToggleVisibleOnAllWorkspacesValue) {
  1079. // If |initial_workspace_| is -1, window is visible on all workspaces.
  1080. params.visible_on_all_workspaces = true;
  1081. } else {
  1082. params.workspace = initial_workspace_.value();
  1083. }
  1084. }
  1085. // Make shell surface a transient child if |parent_| has been set and
  1086. // container_ isn't specified.
  1087. aura::Window* root_window =
  1088. WMHelper::GetInstance()->GetRootWindowForNewWindows();
  1089. if (ash::desks_util::IsDeskContainerId(container_)) {
  1090. DCHECK_EQ(ash::desks_util::GetActiveDeskContainerId(), container_);
  1091. if (parent_)
  1092. params.parent = parent_;
  1093. else
  1094. params.context = root_window;
  1095. } else {
  1096. params.parent = ash::Shell::GetContainer(root_window, container_);
  1097. }
  1098. if (initial_bounds_)
  1099. params.bounds = *initial_bounds_;
  1100. else
  1101. params.bounds = gfx::Rect(origin_, gfx::Size());
  1102. WMHelper::AppPropertyResolver::Params property_resolver_params;
  1103. if (application_id_)
  1104. property_resolver_params.app_id = *application_id_;
  1105. if (startup_id_)
  1106. property_resolver_params.startup_id = *startup_id_;
  1107. property_resolver_params.for_creation = true;
  1108. WMHelper::GetInstance()->PopulateAppProperties(
  1109. property_resolver_params, params.init_properties_container);
  1110. SetShellApplicationId(&params.init_properties_container, application_id_);
  1111. SetShellRootSurface(&params.init_properties_container, root_surface());
  1112. SetShellStartupId(&params.init_properties_container, startup_id_);
  1113. bool activatable = activatable_;
  1114. // ShellSurfaces in system modal container are only activatable if input
  1115. // region is non-empty. See OnCommitSurface() for more details.
  1116. if (container_ == ash::kShellWindowId_SystemModalContainer)
  1117. activatable &= HasHitTestRegion();
  1118. // Transient child needs to have an application id to be activatable.
  1119. if (parent_)
  1120. activatable &= application_id_.has_value();
  1121. params.activatable = activatable
  1122. ? views::Widget::InitParams::Activatable::kYes
  1123. : views::Widget::InitParams::Activatable::kNo;
  1124. if (restore_session_id_) {
  1125. params.init_properties_container.SetProperty(app_restore::kWindowIdKey,
  1126. *restore_session_id_);
  1127. }
  1128. if (restore_window_id_) {
  1129. params.init_properties_container.SetProperty(
  1130. app_restore::kRestoreWindowIdKey, *restore_window_id_);
  1131. }
  1132. if (restore_window_id_source_) {
  1133. params.init_properties_container.SetProperty(
  1134. app_restore::kRestoreWindowIdKey,
  1135. app_restore::FetchRestoreWindowId(*restore_window_id_source_));
  1136. params.init_properties_container.SetProperty(
  1137. app_restore::kAppIdKey, restore_window_id_source_.value());
  1138. }
  1139. #if BUILDFLAG(IS_CHROMEOS_ASH)
  1140. // Restore `params` to those of the saved `restore_window_id_`.
  1141. app_restore::ModifyWidgetParams(params.init_properties_container.GetProperty(
  1142. app_restore::kRestoreWindowIdKey),
  1143. &params);
  1144. #endif
  1145. // If app restore specifies the initial bounds, set `initial_bounds_` to it so
  1146. // that shell surface knows the initial bounds is set.
  1147. if (!params.bounds.IsEmpty() && !initial_bounds_)
  1148. initial_bounds_.emplace(params.bounds);
  1149. OverrideInitParams(&params);
  1150. // Note: NativeWidget owns this widget.
  1151. widget_ = new ShellSurfaceWidget;
  1152. widget_->Init(std::move(params));
  1153. widget_->AddObserver(this);
  1154. // As setting the pinned mode may have come in earlier we apply it now.
  1155. UpdatePinned();
  1156. aura::Window* window = widget_->GetNativeWindow();
  1157. window->SetName(base::StringPrintf("ExoShellSurface-%d", shell_id++));
  1158. window->AddChild(host_window());
  1159. // Works for both mash and non-mash. https://crbug.com/839521
  1160. window->SetEventTargetingPolicy(
  1161. aura::EventTargetingPolicy::kTargetAndDescendants);
  1162. InstallCustomWindowTargeter();
  1163. // Start tracking changes to window bounds and window state.
  1164. window->AddObserver(this);
  1165. ash::WindowState* window_state = ash::WindowState::Get(window);
  1166. // Skip initializing window state when it is menu.
  1167. // TODO(crbug.com/1338597): Remove `window_state` condition when tooltip fix
  1168. // is done. Without the fix, window_state can be null when it is tooltip and
  1169. // the parent window is menu, so add null check of `window_state` here.
  1170. if (!is_menu_ && window_state)
  1171. InitializeWindowState(window_state);
  1172. SetShellUseImmersiveForFullscreen(window, immersive_implied_by_fullscreen_);
  1173. // Fade visibility animations for non-activatable windows.
  1174. if (!CanActivate()) {
  1175. wm::SetWindowVisibilityAnimationType(
  1176. window, wm::WINDOW_VISIBILITY_ANIMATION_TYPE_FADE);
  1177. }
  1178. // Register close window accelerators.
  1179. views::FocusManager* focus_manager = widget_->GetFocusManager();
  1180. for (const auto& entry : kCloseWindowAccelerators) {
  1181. focus_manager->RegisterAccelerator(
  1182. ui::Accelerator(entry.keycode, entry.modifiers),
  1183. ui::AcceleratorManager::kNormalPriority, this);
  1184. }
  1185. // Show widget next time Commit() is called.
  1186. if (show_state != ui::SHOW_STATE_MINIMIZED)
  1187. pending_show_widget_ = true;
  1188. UpdateDisplayOnTree();
  1189. if (frame_type_ != SurfaceFrameType::NONE)
  1190. OnSetFrame(frame_type_);
  1191. if (pending_pip_)
  1192. SetPip();
  1193. root_surface()->OnDeskChanged(GetWindowDeskStateChanged(window));
  1194. WMHelper::GetInstance()->NotifyExoWindowCreated(widget_->GetNativeWindow());
  1195. }
  1196. ShellSurfaceBase::OverlayParams::OverlayParams(
  1197. std::unique_ptr<views::View> overlay)
  1198. : contents_view(std::move(overlay)) {}
  1199. ShellSurfaceBase::OverlayParams::~OverlayParams() = default;
  1200. bool ShellSurfaceBase::IsResizing() const {
  1201. ash::WindowState* window_state =
  1202. ash::WindowState::Get(widget_->GetNativeWindow());
  1203. if (!window_state || !window_state->is_dragged())
  1204. return false;
  1205. return window_state->drag_details() &&
  1206. (window_state->drag_details()->bounds_change &
  1207. ash::WindowResizer::kBoundsChange_Resizes);
  1208. }
  1209. gfx::Rect ShellSurfaceBase::ComputeAdjustedBounds(
  1210. const gfx::Rect& bounds) const {
  1211. return bounds;
  1212. }
  1213. void ShellSurfaceBase::UpdateWidgetBounds() {
  1214. DCHECK(widget_);
  1215. absl::optional<gfx::Rect> bounds = GetWidgetBounds();
  1216. if (!bounds)
  1217. return;
  1218. gfx::Rect adjusted_bounds = ComputeAdjustedBounds(*bounds);
  1219. if (overlay_widget_) {
  1220. gfx::Rect content_bounds(adjusted_bounds.size());
  1221. int height = 0;
  1222. if (!overlay_overlaps_frame_ && frame_enabled()) {
  1223. auto* frame_view = static_cast<const ash::NonClientFrameViewAsh*>(
  1224. widget_->non_client_view()->frame_view());
  1225. height = frame_view->NonClientTopBorderHeight();
  1226. }
  1227. content_bounds.set_height(content_bounds.height() - height);
  1228. content_bounds.set_y(height);
  1229. overlay_widget_->SetBounds(content_bounds);
  1230. }
  1231. aura::Window* window = widget_->GetNativeWindow();
  1232. ash::WindowState* window_state = ash::WindowState::Get(window);
  1233. // Return early if the shell is currently managing the bounds of the widget.
  1234. if (window_state && !window_state->allow_set_bounds_direct()) {
  1235. // 1) When a window is either maximized/fullscreen/pinned.
  1236. if (window_state->IsMaximizedOrFullscreenOrPinned())
  1237. return;
  1238. // 2) When a window is snapped.
  1239. if (window_state->IsSnapped())
  1240. return;
  1241. // 3) When a window is being interactively resized.
  1242. if (IsResizing())
  1243. return;
  1244. // 4) When a window's bounds are being animated.
  1245. if (window->layer()->GetAnimator()->IsAnimatingProperty(
  1246. ui::LayerAnimationElement::BOUNDS))
  1247. return;
  1248. }
  1249. SetWidgetBounds(adjusted_bounds, adjusted_bounds != *bounds);
  1250. }
  1251. void ShellSurfaceBase::UpdateSurfaceBounds() {
  1252. gfx::Point origin = GetClientViewBounds().origin();
  1253. origin += GetSurfaceOrigin().OffsetFromOrigin();
  1254. origin -= ToFlooredVector2d(ScaleVector2d(
  1255. root_surface_origin().OffsetFromOrigin(), 1.f / GetScale()));
  1256. gfx::Rect surface_bounds(origin, host_window()->bounds().size());
  1257. if (host_window()->bounds() == surface_bounds)
  1258. return;
  1259. host_window()->SetBounds(surface_bounds);
  1260. }
  1261. void ShellSurfaceBase::UpdateShadow() {
  1262. if (!widget_ || !root_surface())
  1263. return;
  1264. aura::Window* window = widget_->GetNativeWindow();
  1265. if (!shadow_bounds_) {
  1266. wm::SetShadowElevation(window, wm::kShadowElevationNone);
  1267. } else {
  1268. // Use a small style shadow for popup surface.
  1269. if (frame_type_ == SurfaceFrameType::SHADOW && is_popup_)
  1270. wm::SetShadowElevation(window, wm::kShadowElevationMenuOrTooltip);
  1271. else
  1272. wm::SetShadowElevation(window, wm::kShadowElevationDefault);
  1273. ui::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
  1274. // Maximized/Fullscreen window does not create a shadow.
  1275. if (!shadow)
  1276. return;
  1277. gfx::Rect shadow_bounds = GetShadowBounds();
  1278. gfx::Point origin = GetClientViewBounds().origin();
  1279. if (!window->GetProperty(aura::client::kUseWindowBoundsForShadow)) {
  1280. origin += GetSurfaceOrigin().OffsetFromOrigin();
  1281. origin -= ToFlooredVector2d(ScaleVector2d(
  1282. root_surface_origin().OffsetFromOrigin(), 1.f / GetScale()));
  1283. if (origin.x() != 0 || origin.y() != 0) {
  1284. shadow_bounds.set_origin(origin);
  1285. if (widget_) {
  1286. gfx::Point widget_origin =
  1287. widget_->GetWindowBoundsInScreen().origin();
  1288. origin += ToFlooredVector2d(
  1289. ScaleVector2d(gfx::Vector2d(widget_origin.x(), widget_origin.y()),
  1290. 1.f / GetScale()));
  1291. gfx::Rect bounds = geometry_;
  1292. bounds.set_origin(origin);
  1293. ash::Shell::Get()
  1294. ->resize_shadow_controller()
  1295. ->UpdateResizeShadowBoundsOfWindow(widget_->GetNativeWindow(),
  1296. bounds);
  1297. }
  1298. }
  1299. }
  1300. shadow->SetContentBounds(shadow_bounds);
  1301. // Surfaces that can't be activated are usually menus and tooltips. Use a
  1302. // small style shadow for them.
  1303. if (!CanActivate())
  1304. shadow->SetElevation(wm::kShadowElevationMenuOrTooltip);
  1305. UpdateCornerRadius();
  1306. }
  1307. }
  1308. void ShellSurfaceBase::UpdateCornerRadius() {
  1309. if (!widget_)
  1310. return;
  1311. if (!ash::features::IsPipRoundedCornersEnabled())
  1312. return;
  1313. ash::WindowState* window_state =
  1314. ash::WindowState::Get(widget_->GetNativeWindow());
  1315. // The host window's transform scales by |1/GetScale()| but we do not want the
  1316. // rounded corners scaled that way. So we multiply the radius by |GetScale()|.
  1317. if (window_state) {
  1318. ash::SetCornerRadius(
  1319. window_state->window(), host_window()->layer(),
  1320. window_state->IsPip()
  1321. ? base::ClampRound(GetScale() * chromeos::kPipRoundedCornerRadius)
  1322. : 0);
  1323. }
  1324. }
  1325. void ShellSurfaceBase::UpdateFrameType() {
  1326. // Nothing to do here for now as frame type is updated immediately in
  1327. // OnSetFrame() by default.
  1328. }
  1329. gfx::Rect ShellSurfaceBase::GetVisibleBounds() const {
  1330. // Use |geometry_| if set, otherwise use the visual bounds of the surface.
  1331. if (geometry_.IsEmpty()) {
  1332. gfx::Size size;
  1333. if (root_surface()) {
  1334. float int_part;
  1335. DCHECK(std::modf(root_surface()->content_size().width(), &int_part) ==
  1336. 0.0f &&
  1337. std::modf(root_surface()->content_size().height(), &int_part) ==
  1338. 0.0f);
  1339. size = gfx::ToCeiledSize(root_surface()->content_size());
  1340. if (client_submits_surfaces_in_pixel_coordinates()) {
  1341. float dsf = host_window()->layer()->device_scale_factor();
  1342. size = gfx::ScaleToRoundedSize(size, 1.0f / dsf);
  1343. }
  1344. }
  1345. return gfx::Rect(size);
  1346. }
  1347. const auto* screen = display::Screen::GetScreen();
  1348. display::Display display;
  1349. if (!screen->GetDisplayWithDisplayId(display_id_, &display))
  1350. return geometry_;
  1351. // Convert from display to screen coordinates.
  1352. return geometry_ + display.bounds().OffsetFromOrigin();
  1353. }
  1354. gfx::Rect ShellSurfaceBase::GetClientViewBounds() const {
  1355. return widget_->non_client_view()
  1356. ? widget_->non_client_view()
  1357. ->frame_view()
  1358. ->GetBoundsForClientView()
  1359. : gfx::Rect(widget_->GetWindowBoundsInScreen().size());
  1360. }
  1361. gfx::Rect ShellSurfaceBase::GetWidgetBoundsFromVisibleBounds() const {
  1362. auto visible_bounds = GetVisibleBounds();
  1363. return widget_->non_client_view()
  1364. ? widget_->non_client_view()->GetWindowBoundsForClientBounds(
  1365. visible_bounds)
  1366. : visible_bounds;
  1367. }
  1368. gfx::Rect ShellSurfaceBase::GetShadowBounds() const {
  1369. return shadow_bounds_->IsEmpty()
  1370. ? gfx::Rect(widget_->GetNativeWindow()->bounds().size())
  1371. : gfx::ScaleToEnclosedRect(*shadow_bounds_, 1.f / GetScale());
  1372. }
  1373. void ShellSurfaceBase::InstallCustomWindowTargeter() {
  1374. aura::Window* window = widget_->GetNativeWindow();
  1375. window->SetEventTargeter(std::make_unique<CustomWindowTargeter>(this));
  1376. }
  1377. std::unique_ptr<views::NonClientFrameView>
  1378. ShellSurfaceBase::CreateNonClientFrameViewInternal(views::Widget* widget) {
  1379. aura::Window* window = widget_->GetNativeWindow();
  1380. // ShellSurfaces always use immersive mode.
  1381. window->SetProperty(chromeos::kImmersiveIsActive, true);
  1382. ash::WindowState* window_state = ash::WindowState::Get(window);
  1383. if (!frame_enabled() && window_state && !window_state->HasDelegate()) {
  1384. window_state->SetDelegate(std::make_unique<CustomWindowStateDelegate>());
  1385. }
  1386. auto frame_view =
  1387. std::make_unique<CustomFrameView>(widget, this, frame_enabled());
  1388. if (has_frame_colors_)
  1389. frame_view->SetFrameColors(active_frame_color_, inactive_frame_color_);
  1390. return frame_view;
  1391. }
  1392. bool ShellSurfaceBase::ShouldExitFullscreenFromRestoreOrMaximized() {
  1393. if (widget_ && widget_->GetNativeWindow()) {
  1394. return widget_->GetNativeWindow()->GetProperty(
  1395. kRestoreOrMaximizeExitsFullscreen);
  1396. }
  1397. return false;
  1398. }
  1399. ////////////////////////////////////////////////////////////////////////////////
  1400. // ShellSurfaceBase, private:
  1401. float ShellSurfaceBase::GetScale() const {
  1402. return 1.f;
  1403. }
  1404. void ShellSurfaceBase::StartCapture() {
  1405. widget_->set_auto_release_capture(false);
  1406. WMHelper::GetInstance()->GetCaptureClient()->AddObserver(this);
  1407. // Just capture on the window.
  1408. widget_->SetCapture(nullptr /* view */);
  1409. }
  1410. void ShellSurfaceBase::OnPostWidgetCommit() {
  1411. // |shadow_bounds_changed_| represents whether |shadow_bounds_| has changed
  1412. // since the last commit, but as UpdateShadow() can be called multiple times
  1413. // in a single commit process, we need to ensure that it's not reset halfway
  1414. // in the current commit by resetting it here.
  1415. shadow_bounds_changed_ = false;
  1416. }
  1417. void ShellSurfaceBase::SetContainerInternal(int container) {
  1418. container_ = container;
  1419. WidgetDelegate::SetCanMaximize(
  1420. !parent_ && ash::desks_util::IsDeskContainerId(container_));
  1421. if (widget_)
  1422. widget_->OnSizeConstraintsChanged();
  1423. }
  1424. void ShellSurfaceBase::SetParentInternal(aura::Window* parent) {
  1425. parent_ = parent;
  1426. WidgetDelegate::SetCanMinimize(!parent_ && can_minimize_);
  1427. UpdateResizability();
  1428. if (widget_)
  1429. widget_->OnSizeConstraintsChanged();
  1430. }
  1431. bool ShellSurfaceBase::CalculateCanResize() const {
  1432. if (overlay_widget_ && overlay_can_resize_.has_value())
  1433. return *overlay_can_resize_;
  1434. return !movement_disabled_ && GetCanResizeFromSizeConstraints();
  1435. }
  1436. void ShellSurfaceBase::CommitWidget() {
  1437. // Apply new window geometry.
  1438. geometry_ = pending_geometry_;
  1439. display_id_ = pending_display_id_;
  1440. // Apply new minimum/maximium size.
  1441. bool size_constraint_changed = minimum_size_ != pending_minimum_size_ ||
  1442. maximum_size_ != pending_maximum_size_;
  1443. minimum_size_ = pending_minimum_size_;
  1444. maximum_size_ = pending_maximum_size_;
  1445. UpdateResizability();
  1446. if (!widget_)
  1447. return;
  1448. if (!pending_aspect_ratio_.IsEmpty()) {
  1449. widget_->SetAspectRatio(pending_aspect_ratio_);
  1450. } else if (widget_->GetNativeWindow()) {
  1451. // TODO(yoshiki): Move the logic to clear aspect ratio into view::Widget.
  1452. widget_->GetNativeWindow()->ClearProperty(aura::client::kAspectRatio);
  1453. }
  1454. UpdateWidgetBounds();
  1455. SurfaceTreeHost::UpdateHostWindowBounds();
  1456. UpdateFrameType();
  1457. gfx::Rect bounds = geometry_;
  1458. if (!bounds.IsEmpty() && !widget_->GetNativeWindow()->GetProperty(
  1459. aura::client::kUseWindowBoundsForShadow)) {
  1460. SetBoundsForShadows(absl::make_optional(bounds));
  1461. }
  1462. UpdateShadow();
  1463. // System modal container is used by clients to implement overlay
  1464. // windows using a single ShellSurface instance. If hit-test
  1465. // region is empty, then it is non interactive window and won't be
  1466. // activated.
  1467. if (container_ == ash::kShellWindowId_SystemModalContainer) {
  1468. // Prevent window from being activated when hit test region is empty.
  1469. bool activatable = activatable_ && HasHitTestRegion();
  1470. if (activatable != CanActivate()) {
  1471. SetCanActivate(activatable);
  1472. // Activate or deactivate window if activation state changed.
  1473. if (activatable) {
  1474. // Automatically activate only if the window is modal.
  1475. // Non modal window should be activated by a user action.
  1476. // TODO(oshima): Non modal system window does not have an associated
  1477. // task ID, and as a result, it cannot be activated from client side.
  1478. // Fix this (b/65460424) and remove this if condition.
  1479. if (system_modal_)
  1480. wm::ActivateWindow(widget_->GetNativeWindow());
  1481. } else if (widget_->IsActive()) {
  1482. wm::DeactivateWindow(widget_->GetNativeWindow());
  1483. }
  1484. }
  1485. }
  1486. UpdateSurfaceBounds();
  1487. // Don't show yet if the shell surface doesn't have content or is minimized
  1488. // while waiting for content.
  1489. bool should_show =
  1490. !host_window()->bounds().IsEmpty() && !widget_->IsMinimized();
  1491. // Do not layout the window if the position should not be controlled by window
  1492. // manager. (popup, emulating x11 override direct, or requested not to move)
  1493. if (is_popup_ || movement_disabled_)
  1494. needs_layout_on_show_ = false;
  1495. // Do not center if the initial bounds is set.
  1496. if (initial_bounds_)
  1497. needs_layout_on_show_ = false;
  1498. // Show widget if needed.
  1499. if (pending_show_widget_ && should_show) {
  1500. DCHECK(!widget_->IsClosed());
  1501. DCHECK(!widget_->IsVisible());
  1502. pending_show_widget_ = false;
  1503. auto* window = widget_->GetNativeWindow();
  1504. auto* window_state = ash::WindowState::Get(window);
  1505. // TODO(crbug.com/1261321): correct the initial origin once lacros can
  1506. // communicate it instead of centering.
  1507. if (window_state && window_state->IsMaximizedOrFullscreenOrPinned()) {
  1508. gfx::Size current_content_size = CalculatePreferredSize();
  1509. gfx::Rect restore_bounds = display::Screen::GetScreen()
  1510. ->GetDisplayNearestWindow(window)
  1511. .work_area();
  1512. if (!current_content_size.IsEmpty())
  1513. restore_bounds.ClampToCenteredSize(current_content_size);
  1514. window_state->SetRestoreBoundsInScreen(restore_bounds);
  1515. }
  1516. // TODO(crbug.com/1291592): Hook this up with the WM's window positioning
  1517. // logic.
  1518. if (needs_layout_on_show_) {
  1519. widget_->CenterWindow(GetWidgetBoundsFromVisibleBounds().size());
  1520. needs_layout_on_show_ = false;
  1521. }
  1522. widget_->Show();
  1523. if (has_grab_)
  1524. StartCapture();
  1525. if (container_ == ash::kShellWindowId_SystemModalContainer)
  1526. UpdateSystemModal();
  1527. }
  1528. if (size_constraint_changed)
  1529. widget_->OnSizeConstraintsChanged();
  1530. }
  1531. bool ShellSurfaceBase::IsFrameDecorationSupported(SurfaceFrameType frame_type) {
  1532. if (!is_popup_)
  1533. return true;
  1534. // Popup doesn't support frame types other than NONE/SHADOW.
  1535. return frame_type == SurfaceFrameType::SHADOW ||
  1536. frame_type == SurfaceFrameType::NONE;
  1537. }
  1538. void ShellSurfaceBase::SetOrientationLock(
  1539. chromeos::OrientationType orientation_lock) {
  1540. #if BUILDFLAG(IS_CHROMEOS_ASH)
  1541. TRACE_EVENT1("exo", "ShellSurfaceBase::SetOrientationLock",
  1542. "orientation_lock", static_cast<int>(orientation_lock));
  1543. if (!widget_) {
  1544. initial_orientation_lock_ = orientation_lock;
  1545. return;
  1546. }
  1547. ash::Shell* shell = ash::Shell::Get();
  1548. shell->screen_orientation_controller()->LockOrientationForWindow(
  1549. widget_->GetNativeWindow(), orientation_lock);
  1550. #else
  1551. NOTREACHED();
  1552. #endif // BUILDFLAG(IS_CHROMEOS_ASH)
  1553. }
  1554. void ShellSurfaceBase::SetZOrder(ui::ZOrderLevel z_order) {
  1555. // If there is already a widget, we can immediately set its z order.
  1556. if (widget_) {
  1557. widget_->SetZOrderLevel(z_order);
  1558. return;
  1559. }
  1560. // Otherwise, we want to save `z_order` for when `widget_` is initialized.
  1561. initial_z_order_ = z_order;
  1562. }
  1563. } // namespace exo