1 // Copyright 2019 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 
5 #include "ui/ozone/platform/wayland/host/wayland_window_manager.h"
6 
7 #include "ui/ozone/platform/wayland/host/wayland_window.h"
8 
9 namespace ui {
10 
11 WaylandWindowManager::WaylandWindowManager() = default;
12 
13 WaylandWindowManager::~WaylandWindowManager() = default;
14 
AddObserver(WaylandWindowObserver * observer)15 void WaylandWindowManager::AddObserver(WaylandWindowObserver* observer) {
16   observers_.AddObserver(observer);
17 }
18 
RemoveObserver(WaylandWindowObserver * observer)19 void WaylandWindowManager::RemoveObserver(WaylandWindowObserver* observer) {
20   observers_.RemoveObserver(observer);
21 }
22 
NotifyWindowConfigured(WaylandWindow * window)23 void WaylandWindowManager::NotifyWindowConfigured(WaylandWindow* window) {
24   for (WaylandWindowObserver& observer : observers_)
25     observer.OnWindowConfigured(window);
26 }
27 
GrabLocatedEvents(WaylandWindow * window)28 void WaylandWindowManager::GrabLocatedEvents(WaylandWindow* window) {
29   DCHECK_NE(located_events_grabber_, window);
30 
31   // Wayland doesn't allow to grab the mouse. However, we start forwarding all
32   // mouse events received by WaylandWindow to the aura::WindowEventDispatcher
33   // which has capture.
34   auto* old_grabber = located_events_grabber_;
35   located_events_grabber_ = window;
36   if (old_grabber)
37     old_grabber->OnWindowLostCapture();
38 }
39 
UngrabLocatedEvents(WaylandWindow * window)40 void WaylandWindowManager::UngrabLocatedEvents(WaylandWindow* window) {
41   DCHECK_EQ(located_events_grabber_, window);
42   auto* old_grabber = located_events_grabber_;
43   located_events_grabber_ = nullptr;
44   old_grabber->OnWindowLostCapture();
45 }
46 
GetWindow(gfx::AcceleratedWidget widget) const47 WaylandWindow* WaylandWindowManager::GetWindow(
48     gfx::AcceleratedWidget widget) const {
49   auto it = window_map_.find(widget);
50   return it == window_map_.end() ? nullptr : it->second;
51 }
52 
GetWindowWithLargestBounds() const53 WaylandWindow* WaylandWindowManager::GetWindowWithLargestBounds() const {
54   WaylandWindow* window_with_largest_bounds = nullptr;
55   for (auto entry : window_map_) {
56     if (!window_with_largest_bounds) {
57       window_with_largest_bounds = entry.second;
58       continue;
59     }
60     WaylandWindow* window = entry.second;
61     if (window_with_largest_bounds->GetBounds() < window->GetBounds())
62       window_with_largest_bounds = window;
63   }
64   return window_with_largest_bounds;
65 }
66 
GetCurrentFocusedWindow() const67 WaylandWindow* WaylandWindowManager::GetCurrentFocusedWindow() const {
68   for (auto entry : window_map_) {
69     WaylandWindow* window = entry.second;
70     if (window->has_pointer_focus() || window->has_touch_focus())
71       return window;
72   }
73   return nullptr;
74 }
75 
GetCurrentKeyboardFocusedWindow() const76 WaylandWindow* WaylandWindowManager::GetCurrentKeyboardFocusedWindow() const {
77   for (auto entry : window_map_) {
78     WaylandWindow* window = entry.second;
79     if (window->has_keyboard_focus())
80       return window;
81   }
82   return nullptr;
83 }
84 
FindParentForNewWindow(gfx::AcceleratedWidget parent_widget) const85 WaylandWindow* WaylandWindowManager::FindParentForNewWindow(
86     gfx::AcceleratedWidget parent_widget) const {
87   auto* parent_window = GetWindow(parent_widget);
88 
89   // If propagated parent has already had a child, it means that |this| is a
90   // submenu of a 3-dot menu. In aura, the parent of a 3-dot menu and its
91   // submenu is the main native widget, which is the main window. In contrast,
92   // Wayland requires a menu window to be a parent of a submenu window. Thus,
93   // check if the suggested parent has a child. If yes, take its child as a
94   // parent of |this|.
95   // Another case is a notification window or a drop down window, which does not
96   // have a parent in aura. In this case, take the current focused window as a
97   // parent.
98   if (!parent_window)
99     parent_window = GetCurrentFocusedWindow();
100 
101   // If there is no current focused window, figure out the current active window
102   // set by the Wayland server. Only one window at a time can be set as active.
103   if (!parent_window) {
104     auto windows = GetAllWindows();
105     for (auto* window : windows) {
106       if (window->IsActive()) {
107         parent_window = window;
108         break;
109       }
110     }
111   }
112 
113   return parent_window ? parent_window->GetTopMostChildWindow() : nullptr;
114 }
115 
GetWindowsOnOutput(uint32_t output_id)116 std::vector<WaylandWindow*> WaylandWindowManager::GetWindowsOnOutput(
117     uint32_t output_id) {
118   std::vector<WaylandWindow*> result;
119   for (auto entry : window_map_) {
120     if (entry.second->entered_outputs_ids().count(output_id) > 0)
121       result.push_back(entry.second);
122   }
123   return result;
124 }
125 
AddWindow(gfx::AcceleratedWidget widget,WaylandWindow * window)126 void WaylandWindowManager::AddWindow(gfx::AcceleratedWidget widget,
127                                      WaylandWindow* window) {
128   window_map_[widget] = window;
129 
130   for (WaylandWindowObserver& observer : observers_)
131     observer.OnWindowAdded(window);
132 }
133 
RemoveWindow(gfx::AcceleratedWidget widget)134 void WaylandWindowManager::RemoveWindow(gfx::AcceleratedWidget widget) {
135   auto* window = window_map_[widget];
136   DCHECK(window);
137 
138   window_map_.erase(widget);
139 
140   for (WaylandWindowObserver& observer : observers_)
141     observer.OnWindowRemoved(window);
142 }
143 
AddSubsurface(gfx::AcceleratedWidget widget,WaylandSubsurface * subsurface)144 void WaylandWindowManager::AddSubsurface(gfx::AcceleratedWidget widget,
145                                          WaylandSubsurface* subsurface) {
146   auto* window = window_map_[widget];
147   DCHECK(window);
148 
149   for (WaylandWindowObserver& observer : observers_)
150     observer.OnSubsurfaceAdded(window, subsurface);
151 }
152 
RemoveSubsurface(gfx::AcceleratedWidget widget,WaylandSubsurface * subsurface)153 void WaylandWindowManager::RemoveSubsurface(gfx::AcceleratedWidget widget,
154                                             WaylandSubsurface* subsurface) {
155   auto* window = window_map_[widget];
156   DCHECK(window);
157 
158   for (WaylandWindowObserver& observer : observers_)
159     observer.OnSubsurfaceRemoved(window, subsurface);
160 }
161 
AllocateAcceleratedWidget()162 gfx::AcceleratedWidget WaylandWindowManager::AllocateAcceleratedWidget() {
163   return ++last_accelerated_widget_;
164 }
165 
GetAllWindows() const166 std::vector<WaylandWindow*> WaylandWindowManager::GetAllWindows() const {
167   std::vector<WaylandWindow*> result;
168   for (auto entry : window_map_)
169     result.push_back(entry.second);
170   return result;
171 }
172 
173 }  // namespace ui
174