aura: Stop converting Rect to RectF implicitly.
[chromium-blink-merge.git] / ui / views / widget / desktop_aura / desktop_window_tree_host_x11.cc
blob94a1cc2c8bce20bbdc56a50ca37debbb241b9249
1 // Copyright (c) 2012 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.
5 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
7 #include <X11/extensions/shape.h>
8 #include <X11/extensions/XInput2.h>
9 #include <X11/Xatom.h>
10 #include <X11/Xregion.h>
11 #include <X11/Xutil.h>
13 #include "base/basictypes.h"
14 #include "base/command_line.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/strings/utf_string_conversions.h"
17 #include "base/trace_event/trace_event.h"
18 #include "third_party/skia/include/core/SkPath.h"
19 #include "ui/aura/client/cursor_client.h"
20 #include "ui/aura/client/focus_client.h"
21 #include "ui/aura/window.h"
22 #include "ui/aura/window_event_dispatcher.h"
23 #include "ui/aura/window_property.h"
24 #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
25 #include "ui/base/hit_test.h"
26 #include "ui/base/ime/input_method.h"
27 #include "ui/base/x/x11_util.h"
28 #include "ui/events/devices/x11/device_data_manager_x11.h"
29 #include "ui/events/devices/x11/device_list_cache_x11.h"
30 #include "ui/events/devices/x11/touch_factory_x11.h"
31 #include "ui/events/event_utils.h"
32 #include "ui/events/platform/platform_event_source.h"
33 #include "ui/events/platform/x11/x11_event_source.h"
34 #include "ui/gfx/display.h"
35 #include "ui/gfx/geometry/insets.h"
36 #include "ui/gfx/geometry/size_conversions.h"
37 #include "ui/gfx/image/image_skia.h"
38 #include "ui/gfx/image/image_skia_rep.h"
39 #include "ui/gfx/path.h"
40 #include "ui/gfx/path_x11.h"
41 #include "ui/gfx/screen.h"
42 #include "ui/native_theme/native_theme.h"
43 #include "ui/views/corewm/tooltip_aura.h"
44 #include "ui/views/linux_ui/linux_ui.h"
45 #include "ui/views/views_delegate.h"
46 #include "ui/views/views_switches.h"
47 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
48 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
49 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
50 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h"
51 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
52 #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
53 #include "ui/views/widget/desktop_aura/x11_pointer_grab.h"
54 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
55 #include "ui/wm/core/compound_event_filter.h"
56 #include "ui/wm/core/window_util.h"
58 DECLARE_WINDOW_PROPERTY_TYPE(views::DesktopWindowTreeHostX11*);
60 namespace views {
62 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::g_current_capture =
63 NULL;
64 std::list<XID>* DesktopWindowTreeHostX11::open_windows_ = NULL;
66 DEFINE_WINDOW_PROPERTY_KEY(
67 aura::Window*, kViewsWindowForRootWindow, NULL);
69 DEFINE_WINDOW_PROPERTY_KEY(
70 DesktopWindowTreeHostX11*, kHostForRootWindow, NULL);
72 namespace {
74 // Constants that are part of EWMH.
75 const int k_NET_WM_STATE_ADD = 1;
76 const int k_NET_WM_STATE_REMOVE = 0;
78 // Special value of the _NET_WM_DESKTOP property which indicates that the window
79 // should appear on all desktops.
80 const int kAllDesktops = 0xFFFFFFFF;
82 const char* kAtomsToCache[] = {
83 "UTF8_STRING",
84 "WM_DELETE_WINDOW",
85 "WM_PROTOCOLS",
86 "_NET_FRAME_EXTENTS",
87 "_NET_WM_CM_S0",
88 "_NET_WM_DESKTOP",
89 "_NET_WM_ICON",
90 "_NET_WM_NAME",
91 "_NET_WM_PID",
92 "_NET_WM_PING",
93 "_NET_WM_STATE",
94 "_NET_WM_STATE_ABOVE",
95 "_NET_WM_STATE_FULLSCREEN",
96 "_NET_WM_STATE_HIDDEN",
97 "_NET_WM_STATE_MAXIMIZED_HORZ",
98 "_NET_WM_STATE_MAXIMIZED_VERT",
99 "_NET_WM_STATE_SKIP_TASKBAR",
100 "_NET_WM_STATE_STICKY",
101 "_NET_WM_USER_TIME",
102 "_NET_WM_WINDOW_OPACITY",
103 "_NET_WM_WINDOW_TYPE",
104 "_NET_WM_WINDOW_TYPE_DND",
105 "_NET_WM_WINDOW_TYPE_MENU",
106 "_NET_WM_WINDOW_TYPE_NORMAL",
107 "_NET_WM_WINDOW_TYPE_NOTIFICATION",
108 "_NET_WM_WINDOW_TYPE_TOOLTIP",
109 "XdndActionAsk",
110 "XdndActionCopy"
111 "XdndActionLink",
112 "XdndActionList",
113 "XdndActionMove",
114 "XdndActionPrivate",
115 "XdndAware",
116 "XdndDrop",
117 "XdndEnter",
118 "XdndFinished",
119 "XdndLeave",
120 "XdndPosition",
121 "XdndProxy", // Proxy windows?
122 "XdndSelection",
123 "XdndStatus",
124 "XdndTypeList",
125 NULL
128 const char kX11WindowRolePopup[] = "popup";
129 const char kX11WindowRoleBubble[] = "bubble";
131 // Returns the whole path from |window| to the root.
132 std::vector<::Window> GetParentsList(XDisplay* xdisplay, ::Window window) {
133 ::Window parent_win, root_win;
134 Window* child_windows;
135 unsigned int num_child_windows;
136 std::vector<::Window> result;
138 while (window) {
139 result.push_back(window);
140 if (!XQueryTree(xdisplay, window,
141 &root_win, &parent_win, &child_windows, &num_child_windows))
142 break;
143 if (child_windows)
144 XFree(child_windows);
145 window = parent_win;
147 return result;
150 } // namespace
152 ////////////////////////////////////////////////////////////////////////////////
153 // DesktopWindowTreeHostX11, public:
155 DesktopWindowTreeHostX11::DesktopWindowTreeHostX11(
156 internal::NativeWidgetDelegate* native_widget_delegate,
157 DesktopNativeWidgetAura* desktop_native_widget_aura)
158 : xdisplay_(gfx::GetXDisplay()),
159 xwindow_(0),
160 x_root_window_(DefaultRootWindow(xdisplay_)),
161 atom_cache_(xdisplay_, kAtomsToCache),
162 window_mapped_(false),
163 is_fullscreen_(false),
164 is_always_on_top_(false),
165 use_native_frame_(false),
166 should_maximize_after_map_(false),
167 use_argb_visual_(false),
168 drag_drop_client_(NULL),
169 native_widget_delegate_(native_widget_delegate),
170 desktop_native_widget_aura_(desktop_native_widget_aura),
171 content_window_(NULL),
172 window_parent_(NULL),
173 custom_window_shape_(false),
174 urgency_hint_set_(false),
175 close_widget_factory_(this) {
178 DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() {
179 window()->ClearProperty(kHostForRootWindow);
180 aura::client::SetWindowMoveClient(window(), NULL);
181 desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
182 DestroyDispatcher();
185 // static
186 aura::Window* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid) {
187 aura::WindowTreeHost* host =
188 aura::WindowTreeHost::GetForAcceleratedWidget(xid);
189 return host ? host->window()->GetProperty(kViewsWindowForRootWindow) : NULL;
192 // static
193 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::GetHostForXID(XID xid) {
194 aura::WindowTreeHost* host =
195 aura::WindowTreeHost::GetForAcceleratedWidget(xid);
196 return host ? host->window()->GetProperty(kHostForRootWindow) : NULL;
199 // static
200 std::vector<aura::Window*> DesktopWindowTreeHostX11::GetAllOpenWindows() {
201 std::vector<aura::Window*> windows(open_windows().size());
202 std::transform(open_windows().begin(),
203 open_windows().end(),
204 windows.begin(),
205 GetContentWindowForXID);
206 return windows;
209 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowBounds() const {
210 return bounds_in_pixels_;
213 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowOuterBounds() const {
214 gfx::Rect outer_bounds(bounds_in_pixels_);
215 outer_bounds.Inset(-native_window_frame_borders_in_pixels_);
216 return outer_bounds;
219 ::Region DesktopWindowTreeHostX11::GetWindowShape() const {
220 return window_shape_.get();
223 void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged(
224 bool active) {
225 if (active) {
226 FlashFrame(false);
227 OnHostActivated();
228 open_windows().remove(xwindow_);
229 open_windows().insert(open_windows().begin(), xwindow_);
230 } else {
231 ReleaseCapture();
234 desktop_native_widget_aura_->HandleActivationChanged(active);
236 native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
239 void DesktopWindowTreeHostX11::AddObserver(
240 views::DesktopWindowTreeHostObserverX11* observer) {
241 observer_list_.AddObserver(observer);
244 void DesktopWindowTreeHostX11::RemoveObserver(
245 views::DesktopWindowTreeHostObserverX11* observer) {
246 observer_list_.RemoveObserver(observer);
249 void DesktopWindowTreeHostX11::SwapNonClientEventHandler(
250 scoped_ptr<ui::EventHandler> handler) {
251 wm::CompoundEventFilter* compound_event_filter =
252 desktop_native_widget_aura_->root_window_event_filter();
253 if (x11_non_client_event_filter_)
254 compound_event_filter->RemoveHandler(x11_non_client_event_filter_.get());
255 compound_event_filter->AddHandler(handler.get());
256 x11_non_client_event_filter_ = handler.Pass();
259 void DesktopWindowTreeHostX11::CleanUpWindowList(
260 void (*func)(aura::Window* window)) {
261 if (!open_windows_)
262 return;
263 while (!open_windows_->empty()) {
264 XID xid = open_windows_->front();
265 func(GetContentWindowForXID(xid));
266 if (!open_windows_->empty() && open_windows_->front() == xid)
267 open_windows_->erase(open_windows_->begin());
270 delete open_windows_;
271 open_windows_ = NULL;
274 ////////////////////////////////////////////////////////////////////////////////
275 // DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation:
277 void DesktopWindowTreeHostX11::Init(aura::Window* content_window,
278 const Widget::InitParams& params) {
279 content_window_ = content_window;
281 // TODO(erg): Check whether we *should* be building a WindowTreeHost here, or
282 // whether we should be proxying requests to another DRWHL.
284 // In some situations, views tries to make a zero sized window, and that
285 // makes us crash. Make sure we have valid sizes.
286 Widget::InitParams sanitized_params = params;
287 if (sanitized_params.bounds.width() == 0)
288 sanitized_params.bounds.set_width(100);
289 if (sanitized_params.bounds.height() == 0)
290 sanitized_params.bounds.set_height(100);
292 InitX11Window(sanitized_params);
295 void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
296 const Widget::InitParams& params) {
297 window()->SetProperty(kViewsWindowForRootWindow, content_window_);
298 window()->SetProperty(kHostForRootWindow, this);
300 // Ensure that the X11DesktopHandler exists so that it dispatches activation
301 // messages to us.
302 X11DesktopHandler::get();
304 // TODO(erg): Unify this code once the other consumer goes away.
305 SwapNonClientEventHandler(
306 scoped_ptr<ui::EventHandler>(new X11WindowEventFilter(this)).Pass());
307 SetUseNativeFrame(params.type == Widget::InitParams::TYPE_WINDOW &&
308 !params.remove_standard_frame);
310 x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
311 aura::client::SetWindowMoveClient(window(), x11_window_move_client_.get());
313 SetWindowTransparency();
315 native_widget_delegate_->OnNativeWidgetCreated(true);
318 scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostX11::CreateTooltip() {
319 return make_scoped_ptr(new corewm::TooltipAura);
322 scoped_ptr<aura::client::DragDropClient>
323 DesktopWindowTreeHostX11::CreateDragDropClient(
324 DesktopNativeCursorManager* cursor_manager) {
325 drag_drop_client_ = new DesktopDragDropClientAuraX11(
326 window(), cursor_manager, xdisplay_, xwindow_);
327 drag_drop_client_->Init();
328 return make_scoped_ptr(drag_drop_client_);
331 void DesktopWindowTreeHostX11::Close() {
332 // TODO(erg): Might need to do additional hiding tasks here.
333 delayed_resize_task_.Cancel();
335 if (!close_widget_factory_.HasWeakPtrs()) {
336 // And we delay the close so that if we are called from an ATL callback,
337 // we don't destroy the window before the callback returned (as the caller
338 // may delete ourselves on destroy and the ATL callback would still
339 // dereference us when the callback returns).
340 base::MessageLoop::current()->PostTask(
341 FROM_HERE,
342 base::Bind(&DesktopWindowTreeHostX11::CloseNow,
343 close_widget_factory_.GetWeakPtr()));
347 void DesktopWindowTreeHostX11::CloseNow() {
348 if (xwindow_ == None)
349 return;
351 ReleaseCapture();
352 native_widget_delegate_->OnNativeWidgetDestroying();
354 // If we have children, close them. Use a copy for iteration because they'll
355 // remove themselves.
356 std::set<DesktopWindowTreeHostX11*> window_children_copy = window_children_;
357 for (std::set<DesktopWindowTreeHostX11*>::iterator it =
358 window_children_copy.begin(); it != window_children_copy.end();
359 ++it) {
360 (*it)->CloseNow();
362 DCHECK(window_children_.empty());
364 // If we have a parent, remove ourselves from its children list.
365 if (window_parent_) {
366 window_parent_->window_children_.erase(this);
367 window_parent_ = NULL;
370 // Remove the event listeners we've installed. We need to remove these
371 // because otherwise we get assert during ~WindowEventDispatcher().
372 desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
373 x11_non_client_event_filter_.get());
374 x11_non_client_event_filter_.reset();
376 // Destroy the compositor before destroying the |xwindow_| since shutdown
377 // may try to swap, and the swap without a window causes an X error, which
378 // causes a crash with in-process renderer.
379 DestroyCompositor();
381 open_windows().remove(xwindow_);
382 // Actually free our native resources.
383 if (ui::PlatformEventSource::GetInstance())
384 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
385 XDestroyWindow(xdisplay_, xwindow_);
386 xwindow_ = None;
388 desktop_native_widget_aura_->OnHostClosed();
391 aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() {
392 return this;
395 void DesktopWindowTreeHostX11::ShowWindowWithState(
396 ui::WindowShowState show_state) {
397 if (compositor())
398 compositor()->SetVisible(true);
399 if (!window_mapped_)
400 MapWindow(show_state);
402 switch (show_state) {
403 case ui::SHOW_STATE_NORMAL:
404 Activate();
405 break;
406 case ui::SHOW_STATE_MAXIMIZED:
407 Maximize();
408 break;
409 case ui::SHOW_STATE_MINIMIZED:
410 Minimize();
411 break;
412 case ui::SHOW_STATE_FULLSCREEN:
413 SetFullscreen(true);
414 break;
415 default:
416 break;
419 native_widget_delegate_->AsWidget()->SetInitialFocus(show_state);
422 void DesktopWindowTreeHostX11::ShowMaximizedWithBounds(
423 const gfx::Rect& restored_bounds) {
424 ShowWindowWithState(ui::SHOW_STATE_MAXIMIZED);
425 // Enforce |restored_bounds_in_pixels_| since calling Maximize() could have
426 // reset it.
427 restored_bounds_in_pixels_ = ToPixelRect(restored_bounds);
430 bool DesktopWindowTreeHostX11::IsVisible() const {
431 return window_mapped_;
434 void DesktopWindowTreeHostX11::SetSize(const gfx::Size& requested_size) {
435 gfx::Size size_in_pixels = ToPixelRect(gfx::Rect(requested_size)).size();
436 size_in_pixels = AdjustSize(size_in_pixels);
437 bool size_changed = bounds_in_pixels_.size() != size_in_pixels;
438 XResizeWindow(xdisplay_, xwindow_, size_in_pixels.width(),
439 size_in_pixels.height());
440 bounds_in_pixels_.set_size(size_in_pixels);
441 if (size_changed) {
442 OnHostResized(size_in_pixels);
443 ResetWindowRegion();
447 void DesktopWindowTreeHostX11::StackAbove(aura::Window* window) {
448 if (window && window->GetRootWindow()) {
449 ::Window window_below = window->GetHost()->GetAcceleratedWidget();
450 // Find all parent windows up to the root.
451 std::vector<::Window> window_below_parents =
452 GetParentsList(xdisplay_, window_below);
453 std::vector<::Window> window_above_parents =
454 GetParentsList(xdisplay_, xwindow_);
456 // Find their common ancestor.
457 auto it_below_window = window_below_parents.rbegin();
458 auto it_above_window = window_above_parents.rbegin();
459 for (; it_below_window != window_below_parents.rend() &&
460 it_above_window != window_above_parents.rend() &&
461 *it_below_window == *it_above_window;
462 ++it_below_window, ++it_above_window) {
465 if (it_below_window != window_below_parents.rend() &&
466 it_above_window != window_above_parents.rend()) {
467 // First stack |xwindow_| below so Z-order of |window| stays the same.
468 ::Window windows[] = {*it_below_window, *it_above_window};
469 if (XRestackWindows(xdisplay_, windows, 2) == 0) {
470 // Now stack them properly.
471 std::swap(windows[0], windows[1]);
472 XRestackWindows(xdisplay_, windows, 2);
478 void DesktopWindowTreeHostX11::StackAtTop() {
479 XRaiseWindow(xdisplay_, xwindow_);
482 void DesktopWindowTreeHostX11::CenterWindow(const gfx::Size& size) {
483 gfx::Size size_in_pixels = ToPixelRect(gfx::Rect(size)).size();
484 gfx::Rect parent_bounds_in_pixels = GetWorkAreaBoundsInPixels();
486 // If |window_|'s transient parent bounds are big enough to contain |size|,
487 // use them instead.
488 if (wm::GetTransientParent(content_window_)) {
489 gfx::Rect transient_parent_rect =
490 wm::GetTransientParent(content_window_)->GetBoundsInScreen();
491 if (transient_parent_rect.height() >= size.height() &&
492 transient_parent_rect.width() >= size.width()) {
493 parent_bounds_in_pixels = ToPixelRect(transient_parent_rect);
497 gfx::Rect window_bounds_in_pixels(
498 parent_bounds_in_pixels.x() +
499 (parent_bounds_in_pixels.width() - size_in_pixels.width()) / 2,
500 parent_bounds_in_pixels.y() +
501 (parent_bounds_in_pixels.height() - size_in_pixels.height()) / 2,
502 size_in_pixels.width(), size_in_pixels.height());
503 // Don't size the window bigger than the parent, otherwise the user may not be
504 // able to close or move it.
505 window_bounds_in_pixels.AdjustToFit(parent_bounds_in_pixels);
507 SetBounds(window_bounds_in_pixels);
510 void DesktopWindowTreeHostX11::GetWindowPlacement(
511 gfx::Rect* bounds,
512 ui::WindowShowState* show_state) const {
513 *bounds = GetRestoredBounds();
515 if (IsFullscreen()) {
516 *show_state = ui::SHOW_STATE_FULLSCREEN;
517 } else if (IsMinimized()) {
518 *show_state = ui::SHOW_STATE_MINIMIZED;
519 } else if (IsMaximized()) {
520 *show_state = ui::SHOW_STATE_MAXIMIZED;
521 } else if (!IsActive()) {
522 *show_state = ui::SHOW_STATE_INACTIVE;
523 } else {
524 *show_state = ui::SHOW_STATE_NORMAL;
528 gfx::Rect DesktopWindowTreeHostX11::GetWindowBoundsInScreen() const {
529 return ToDIPRect(bounds_in_pixels_);
532 gfx::Rect DesktopWindowTreeHostX11::GetClientAreaBoundsInScreen() const {
533 // TODO(erg): The NativeWidgetAura version returns |bounds_in_pixels_|,
534 // claiming it's needed for View::ConvertPointToScreen() to work correctly.
535 // DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() just asks windows
536 // what it thinks the client rect is.
538 // Attempts to calculate the rect by asking the NonClientFrameView what it
539 // thought its GetBoundsForClientView() were broke combobox drop down
540 // placement.
541 return GetWindowBoundsInScreen();
544 gfx::Rect DesktopWindowTreeHostX11::GetRestoredBounds() const {
545 // We can't reliably track the restored bounds of a window, but we can get
546 // the 90% case down. When *chrome* is the process that requests maximizing
547 // or restoring bounds, we can record the current bounds before we request
548 // maximization, and clear it when we detect a state change.
549 if (!restored_bounds_in_pixels_.IsEmpty())
550 return ToDIPRect(restored_bounds_in_pixels_);
552 return GetWindowBoundsInScreen();
555 gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInScreen() const {
556 return ToDIPRect(GetWorkAreaBoundsInPixels());
559 void DesktopWindowTreeHostX11::SetShape(SkRegion* native_region) {
560 custom_window_shape_ = false;
561 window_shape_.reset();
563 if (native_region) {
564 gfx::Transform transform = GetRootTransform();
565 if (!transform.IsIdentity() && !native_region->isEmpty()) {
566 SkPath path_in_dip;
567 if (native_region->getBoundaryPath(&path_in_dip)) {
568 SkPath path_in_pixels;
569 path_in_dip.transform(transform.matrix(), &path_in_pixels);
570 window_shape_.reset(gfx::CreateRegionFromSkPath(path_in_pixels));
571 } else {
572 window_shape_.reset(XCreateRegion());
574 } else {
575 window_shape_.reset(gfx::CreateRegionFromSkRegion(*native_region));
578 custom_window_shape_ = true;
579 delete native_region;
581 ResetWindowRegion();
584 void DesktopWindowTreeHostX11::Activate() {
585 if (!window_mapped_)
586 return;
588 X11DesktopHandler::get()->ActivateWindow(xwindow_);
591 void DesktopWindowTreeHostX11::Deactivate() {
592 if (!IsActive())
593 return;
595 ReleaseCapture();
596 X11DesktopHandler::get()->DeactivateWindow(xwindow_);
599 bool DesktopWindowTreeHostX11::IsActive() const {
600 return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
603 void DesktopWindowTreeHostX11::Maximize() {
604 if (HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN")) {
605 // Unfullscreen the window if it is fullscreen.
606 SetWMSpecState(false,
607 atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
608 None);
610 // Resize the window so that it does not have the same size as a monitor.
611 // (Otherwise, some window managers immediately put the window back in
612 // fullscreen mode).
613 gfx::Rect adjusted_bounds_in_pixels(bounds_in_pixels_.origin(),
614 AdjustSize(bounds_in_pixels_.size()));
615 if (adjusted_bounds_in_pixels != bounds_in_pixels_)
616 SetBounds(adjusted_bounds_in_pixels);
619 // Some WMs do not respect maximization hints on unmapped windows, so we
620 // save this one for later too.
621 should_maximize_after_map_ = !window_mapped_;
623 // When we are in the process of requesting to maximize a window, we can
624 // accurately keep track of our restored bounds instead of relying on the
625 // heuristics that are in the PropertyNotify and ConfigureNotify handlers.
626 restored_bounds_in_pixels_ = bounds_in_pixels_;
628 SetWMSpecState(true,
629 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
630 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
631 if (IsMinimized())
632 ShowWindowWithState(ui::SHOW_STATE_NORMAL);
635 void DesktopWindowTreeHostX11::Minimize() {
636 ReleaseCapture();
637 XIconifyWindow(xdisplay_, xwindow_, 0);
640 void DesktopWindowTreeHostX11::Restore() {
641 should_maximize_after_map_ = false;
642 SetWMSpecState(false,
643 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
644 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
645 if (IsMinimized())
646 ShowWindowWithState(ui::SHOW_STATE_NORMAL);
649 bool DesktopWindowTreeHostX11::IsMaximized() const {
650 return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") &&
651 HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
654 bool DesktopWindowTreeHostX11::IsMinimized() const {
655 return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
658 bool DesktopWindowTreeHostX11::HasCapture() const {
659 return g_current_capture == this;
662 void DesktopWindowTreeHostX11::SetAlwaysOnTop(bool always_on_top) {
663 is_always_on_top_ = always_on_top;
664 SetWMSpecState(always_on_top,
665 atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
666 None);
669 bool DesktopWindowTreeHostX11::IsAlwaysOnTop() const {
670 return is_always_on_top_;
673 void DesktopWindowTreeHostX11::SetVisibleOnAllWorkspaces(bool always_visible) {
674 SetWMSpecState(always_visible,
675 atom_cache_.GetAtom("_NET_WM_STATE_STICKY"),
676 None);
678 int new_desktop = 0;
679 if (always_visible) {
680 new_desktop = kAllDesktops;
681 } else {
682 if (!ui::GetCurrentDesktop(&new_desktop))
683 return;
686 XEvent xevent;
687 memset (&xevent, 0, sizeof (xevent));
688 xevent.type = ClientMessage;
689 xevent.xclient.window = xwindow_;
690 xevent.xclient.message_type = atom_cache_.GetAtom("_NET_WM_DESKTOP");
691 xevent.xclient.format = 32;
692 xevent.xclient.data.l[0] = new_desktop;
693 xevent.xclient.data.l[1] = 0;
694 xevent.xclient.data.l[2] = 0;
695 xevent.xclient.data.l[3] = 0;
696 xevent.xclient.data.l[4] = 0;
697 XSendEvent(xdisplay_, x_root_window_, False,
698 SubstructureRedirectMask | SubstructureNotifyMask,
699 &xevent);
702 bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) {
703 if (window_title_ == title)
704 return false;
705 window_title_ = title;
706 std::string utf8str = base::UTF16ToUTF8(title);
707 XChangeProperty(xdisplay_,
708 xwindow_,
709 atom_cache_.GetAtom("_NET_WM_NAME"),
710 atom_cache_.GetAtom("UTF8_STRING"),
712 PropModeReplace,
713 reinterpret_cast<const unsigned char*>(utf8str.c_str()),
714 utf8str.size());
715 XTextProperty xtp;
716 char *c_utf8_str = const_cast<char *>(utf8str.c_str());
717 if (Xutf8TextListToTextProperty(xdisplay_, &c_utf8_str, 1,
718 XUTF8StringStyle, &xtp) == Success) {
719 XSetWMName(xdisplay_, xwindow_, &xtp);
720 XFree(xtp.value);
722 return true;
725 void DesktopWindowTreeHostX11::ClearNativeFocus() {
726 // This method is weird and misnamed. Instead of clearing the native focus,
727 // it sets the focus to our |content_window_|, which will trigger a cascade
728 // of focus changes into views.
729 if (content_window_ && aura::client::GetFocusClient(content_window_) &&
730 content_window_->Contains(
731 aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) {
732 aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
736 Widget::MoveLoopResult DesktopWindowTreeHostX11::RunMoveLoop(
737 const gfx::Vector2d& drag_offset,
738 Widget::MoveLoopSource source,
739 Widget::MoveLoopEscapeBehavior escape_behavior) {
740 aura::client::WindowMoveSource window_move_source =
741 source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
742 aura::client::WINDOW_MOVE_SOURCE_MOUSE :
743 aura::client::WINDOW_MOVE_SOURCE_TOUCH;
744 if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
745 window_move_source) == aura::client::MOVE_SUCCESSFUL)
746 return Widget::MOVE_LOOP_SUCCESSFUL;
748 return Widget::MOVE_LOOP_CANCELED;
751 void DesktopWindowTreeHostX11::EndMoveLoop() {
752 x11_window_move_client_->EndMoveLoop();
755 void DesktopWindowTreeHostX11::SetVisibilityChangedAnimationsEnabled(
756 bool value) {
757 // Much like the previous NativeWidgetGtk, we don't have anything to do here.
760 bool DesktopWindowTreeHostX11::ShouldUseNativeFrame() const {
761 return use_native_frame_;
764 bool DesktopWindowTreeHostX11::ShouldWindowContentsBeTransparent() const {
765 return false;
768 void DesktopWindowTreeHostX11::FrameTypeChanged() {
769 Widget::FrameType new_type =
770 native_widget_delegate_->AsWidget()->frame_type();
771 if (new_type == Widget::FRAME_TYPE_DEFAULT) {
772 // The default is determined by Widget::InitParams::remove_standard_frame
773 // and does not change.
774 return;
777 SetUseNativeFrame(new_type == Widget::FRAME_TYPE_FORCE_NATIVE);
778 // Replace the frame and layout the contents. Even though we don't have a
779 // swapable glass frame like on Windows, we still replace the frame because
780 // the button assets don't update otherwise.
781 native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame();
784 void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen) {
785 if (is_fullscreen_ == fullscreen)
786 return;
787 is_fullscreen_ = fullscreen;
788 if (is_fullscreen_)
789 delayed_resize_task_.Cancel();
791 // Work around a bug where if we try to unfullscreen, metacity immediately
792 // fullscreens us again. This is a little flickery and not necessary if
793 // there's a gnome-panel, but it's not easy to detect whether there's a
794 // panel or not.
795 bool unmaximize_and_remaximize = !fullscreen && IsMaximized() &&
796 ui::GuessWindowManager() == ui::WM_METACITY;
798 if (unmaximize_and_remaximize)
799 Restore();
800 SetWMSpecState(fullscreen,
801 atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
802 None);
803 if (unmaximize_and_remaximize)
804 Maximize();
806 // Try to guess the size we will have after the switch to/from fullscreen:
807 // - (may) avoid transient states
808 // - works around Flash content which expects to have the size updated
809 // synchronously.
810 // See https://crbug.com/361408
811 if (fullscreen) {
812 restored_bounds_in_pixels_ = bounds_in_pixels_;
813 const gfx::Display display =
814 gfx::Screen::GetScreenFor(NULL)->GetDisplayNearestWindow(window());
815 bounds_in_pixels_ = ToPixelRect(display.bounds());
816 } else {
817 bounds_in_pixels_ = restored_bounds_in_pixels_;
819 OnHostMoved(bounds_in_pixels_.origin());
820 OnHostResized(bounds_in_pixels_.size());
822 if (HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN") == fullscreen) {
823 Relayout();
824 ResetWindowRegion();
826 // Else: the widget will be relaid out either when the window bounds change or
827 // when |xwindow_|'s fullscreen state changes.
830 bool DesktopWindowTreeHostX11::IsFullscreen() const {
831 return is_fullscreen_;
834 void DesktopWindowTreeHostX11::SetOpacity(unsigned char opacity) {
835 // X server opacity is in terms of 32 bit unsigned int space, and counts from
836 // the opposite direction.
837 // XChangeProperty() expects "cardinality" to be long.
838 unsigned long cardinality = opacity * 0x1010101;
840 if (cardinality == 0xffffffff) {
841 XDeleteProperty(xdisplay_, xwindow_,
842 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
843 } else {
844 XChangeProperty(xdisplay_, xwindow_,
845 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
846 XA_CARDINAL, 32,
847 PropModeReplace,
848 reinterpret_cast<unsigned char*>(&cardinality), 1);
852 void DesktopWindowTreeHostX11::SetWindowIcons(
853 const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
854 // TODO(erg): The way we handle icons across different versions of chrome
855 // could be substantially improved. The Windows version does its own thing
856 // and only sometimes comes down this code path. The icon stuff in
857 // ChromeViewsDelegate is hard coded to use HICONs. Likewise, we're hard
858 // coded to be given two images instead of an arbitrary collection of images
859 // so that we can pass to the WM.
861 // All of this could be made much, much better.
862 std::vector<unsigned long> data;
864 if (window_icon.HasRepresentation(1.0f))
865 SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data);
867 if (app_icon.HasRepresentation(1.0f))
868 SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data);
870 if (!data.empty())
871 ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data);
874 void DesktopWindowTreeHostX11::InitModalType(ui::ModalType modal_type) {
875 switch (modal_type) {
876 case ui::MODAL_TYPE_NONE:
877 break;
878 default:
879 // TODO(erg): Figure out under what situations |modal_type| isn't
880 // none. The comment in desktop_native_widget_aura.cc suggests that this
881 // is rare.
882 NOTIMPLEMENTED();
886 void DesktopWindowTreeHostX11::FlashFrame(bool flash_frame) {
887 if (urgency_hint_set_ == flash_frame)
888 return;
890 gfx::XScopedPtr<XWMHints> hints(XGetWMHints(xdisplay_, xwindow_));
891 if (!hints) {
892 // The window hasn't had its hints set yet.
893 hints.reset(XAllocWMHints());
896 if (flash_frame)
897 hints->flags |= XUrgencyHint;
898 else
899 hints->flags &= ~XUrgencyHint;
901 XSetWMHints(xdisplay_, xwindow_, hints.get());
903 urgency_hint_set_ = flash_frame;
906 void DesktopWindowTreeHostX11::OnRootViewLayout() {
907 UpdateMinAndMaxSize();
910 void DesktopWindowTreeHostX11::OnNativeWidgetFocus() {
913 void DesktopWindowTreeHostX11::OnNativeWidgetBlur() {
916 bool DesktopWindowTreeHostX11::IsAnimatingClosed() const {
917 return false;
920 bool DesktopWindowTreeHostX11::IsTranslucentWindowOpacitySupported() const {
921 return false;
924 void DesktopWindowTreeHostX11::SizeConstraintsChanged() {
925 UpdateMinAndMaxSize();
928 ////////////////////////////////////////////////////////////////////////////////
929 // DesktopWindowTreeHostX11, aura::WindowTreeHost implementation:
931 gfx::Transform DesktopWindowTreeHostX11::GetRootTransform() const {
932 gfx::Display display = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
933 if (window_mapped_) {
934 aura::Window* win = const_cast<aura::Window*>(window());
935 display = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(win);
938 float scale = display.device_scale_factor();
939 gfx::Transform transform;
940 transform.Scale(scale, scale);
941 return transform;
944 ui::EventSource* DesktopWindowTreeHostX11::GetEventSource() {
945 return this;
948 gfx::AcceleratedWidget DesktopWindowTreeHostX11::GetAcceleratedWidget() {
949 return xwindow_;
952 void DesktopWindowTreeHostX11::ShowImpl() {
953 ShowWindowWithState(ui::SHOW_STATE_NORMAL);
954 native_widget_delegate_->OnNativeWidgetVisibilityChanged(true);
957 void DesktopWindowTreeHostX11::HideImpl() {
958 if (window_mapped_) {
959 XWithdrawWindow(xdisplay_, xwindow_, 0);
960 window_mapped_ = false;
962 native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
965 gfx::Rect DesktopWindowTreeHostX11::GetBounds() const {
966 return bounds_in_pixels_;
969 void DesktopWindowTreeHostX11::SetBounds(
970 const gfx::Rect& requested_bounds_in_pixel) {
971 gfx::Rect bounds_in_pixels(requested_bounds_in_pixel.origin(),
972 AdjustSize(requested_bounds_in_pixel.size()));
973 bool origin_changed = bounds_in_pixels_.origin() != bounds_in_pixels.origin();
974 bool size_changed = bounds_in_pixels_.size() != bounds_in_pixels.size();
975 XWindowChanges changes = {0};
976 unsigned value_mask = 0;
978 if (size_changed) {
979 if (bounds_in_pixels.width() < min_size_in_pixels_.width() ||
980 bounds_in_pixels.height() < min_size_in_pixels_.height() ||
981 (!max_size_in_pixels_.IsEmpty() &&
982 (bounds_in_pixels.width() > max_size_in_pixels_.width() ||
983 bounds_in_pixels.height() > max_size_in_pixels_.height()))) {
984 // Update the minimum and maximum sizes in case they have changed.
985 UpdateMinAndMaxSize();
987 gfx::Size size_in_pixels = bounds_in_pixels.size();
988 size_in_pixels.SetToMin(max_size_in_pixels_);
989 size_in_pixels.SetToMax(min_size_in_pixels_);
990 bounds_in_pixels.set_size(size_in_pixels);
993 changes.width = bounds_in_pixels.width();
994 changes.height = bounds_in_pixels.height();
995 value_mask |= CWHeight | CWWidth;
998 if (origin_changed) {
999 changes.x = bounds_in_pixels.x();
1000 changes.y = bounds_in_pixels.y();
1001 value_mask |= CWX | CWY;
1003 if (value_mask)
1004 XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
1006 // Assume that the resize will go through as requested, which should be the
1007 // case if we're running without a window manager. If there's a window
1008 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
1009 // (possibly synthetic) ConfigureNotify about the actual size and correct
1010 // |bounds_in_pixels_| later.
1011 bounds_in_pixels_ = bounds_in_pixels;
1013 if (origin_changed)
1014 native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
1015 if (size_changed) {
1016 OnHostResized(bounds_in_pixels.size());
1017 ResetWindowRegion();
1021 gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const {
1022 return bounds_in_pixels_.origin();
1025 void DesktopWindowTreeHostX11::SetCapture() {
1026 if (HasCapture())
1027 return;
1029 // Grabbing the mouse is asynchronous. However, we synchronously start
1030 // forwarding all mouse events received by Chrome to the
1031 // aura::WindowEventDispatcher which has capture. This makes capture
1032 // synchronous for all intents and purposes if either:
1033 // - |g_current_capture|'s X window has capture.
1034 // OR
1035 // - The topmost window underneath the mouse is managed by Chrome.
1036 DesktopWindowTreeHostX11* old_capturer = g_current_capture;
1038 // Update |g_current_capture| prior to calling OnHostLostWindowCapture() to
1039 // avoid releasing pointer grab.
1040 g_current_capture = this;
1041 if (old_capturer)
1042 old_capturer->OnHostLostWindowCapture();
1044 GrabPointer(xwindow_, true, None);
1047 void DesktopWindowTreeHostX11::ReleaseCapture() {
1048 if (g_current_capture == this) {
1049 // Release mouse grab asynchronously. A window managed by Chrome is likely
1050 // the topmost window underneath the mouse so the capture release being
1051 // asynchronous is likely inconsequential.
1052 g_current_capture = NULL;
1053 UngrabPointer();
1055 OnHostLostWindowCapture();
1059 void DesktopWindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) {
1060 XDefineCursor(xdisplay_, xwindow_, cursor.platform());
1063 void DesktopWindowTreeHostX11::MoveCursorToNative(const gfx::Point& location) {
1064 XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
1065 bounds_in_pixels_.x() + location.x(),
1066 bounds_in_pixels_.y() + location.y());
1069 void DesktopWindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
1070 // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
1071 // the same tap-to-click disabling here that chromeos does.
1074 ////////////////////////////////////////////////////////////////////////////////
1075 // DesktopWindowTreeHostX11, private:
1077 void DesktopWindowTreeHostX11::InitX11Window(
1078 const Widget::InitParams& params) {
1079 unsigned long attribute_mask = CWBackPixmap;
1080 XSetWindowAttributes swa;
1081 memset(&swa, 0, sizeof(swa));
1082 swa.background_pixmap = None;
1084 ::Atom window_type;
1085 switch (params.type) {
1086 case Widget::InitParams::TYPE_MENU:
1087 swa.override_redirect = True;
1088 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
1089 break;
1090 case Widget::InitParams::TYPE_TOOLTIP:
1091 swa.override_redirect = True;
1092 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
1093 break;
1094 case Widget::InitParams::TYPE_POPUP:
1095 swa.override_redirect = True;
1096 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION");
1097 break;
1098 case Widget::InitParams::TYPE_DRAG:
1099 swa.override_redirect = True;
1100 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_DND");
1101 break;
1102 default:
1103 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
1104 break;
1106 if (swa.override_redirect)
1107 attribute_mask |= CWOverrideRedirect;
1109 // Detect whether we're running inside a compositing manager. If so, try to
1110 // use the ARGB visual. Otherwise, just use our parent's visual.
1111 Visual* visual = CopyFromParent;
1112 int depth = CopyFromParent;
1113 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1114 switches::kEnableTransparentVisuals) &&
1115 XGetSelectionOwner(xdisplay_, atom_cache_.GetAtom("_NET_WM_CM_S0")) !=
1116 None) {
1117 Visual* rgba_visual = GetARGBVisual();
1118 if (rgba_visual) {
1119 visual = rgba_visual;
1120 depth = 32;
1122 attribute_mask |= CWColormap;
1123 swa.colormap = XCreateColormap(xdisplay_, x_root_window_, visual,
1124 AllocNone);
1126 // x.org will BadMatch if we don't set a border when the depth isn't the
1127 // same as the parent depth.
1128 attribute_mask |= CWBorderPixel;
1129 swa.border_pixel = 0;
1131 use_argb_visual_ = true;
1135 bounds_in_pixels_ = ToPixelRect(params.bounds);
1136 bounds_in_pixels_.set_size(AdjustSize(bounds_in_pixels_.size()));
1137 xwindow_ = XCreateWindow(xdisplay_, x_root_window_, bounds_in_pixels_.x(),
1138 bounds_in_pixels_.y(), bounds_in_pixels_.width(),
1139 bounds_in_pixels_.height(),
1140 0, // border width
1141 depth, InputOutput, visual, attribute_mask, &swa);
1142 if (ui::PlatformEventSource::GetInstance())
1143 ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
1144 open_windows().push_back(xwindow_);
1146 // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
1148 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
1149 KeyPressMask | KeyReleaseMask |
1150 EnterWindowMask | LeaveWindowMask |
1151 ExposureMask | VisibilityChangeMask |
1152 StructureNotifyMask | PropertyChangeMask |
1153 PointerMotionMask;
1154 XSelectInput(xdisplay_, xwindow_, event_mask);
1155 XFlush(xdisplay_);
1157 if (ui::IsXInput2Available())
1158 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
1160 // TODO(erg): We currently only request window deletion events. We also
1161 // should listen for activation events and anything else that GTK+ listens
1162 // for, and do something useful.
1163 ::Atom protocols[2];
1164 protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
1165 protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
1166 XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
1168 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
1169 // the desktop environment.
1170 XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
1172 // Likewise, the X server needs to know this window's pid so it knows which
1173 // program to kill if the window hangs.
1174 // XChangeProperty() expects "pid" to be long.
1175 static_assert(sizeof(long) >= sizeof(pid_t),
1176 "pid_t should not be larger than long");
1177 long pid = getpid();
1178 XChangeProperty(xdisplay_,
1179 xwindow_,
1180 atom_cache_.GetAtom("_NET_WM_PID"),
1181 XA_CARDINAL,
1183 PropModeReplace,
1184 reinterpret_cast<unsigned char*>(&pid), 1);
1186 XChangeProperty(xdisplay_,
1187 xwindow_,
1188 atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
1189 XA_ATOM,
1191 PropModeReplace,
1192 reinterpret_cast<unsigned char*>(&window_type), 1);
1194 // List of window state properties (_NET_WM_STATE) to set, if any.
1195 std::vector< ::Atom> state_atom_list;
1197 // Remove popup windows from taskbar unless overridden.
1198 if ((params.type == Widget::InitParams::TYPE_POPUP ||
1199 params.type == Widget::InitParams::TYPE_BUBBLE) &&
1200 !params.force_show_in_taskbar) {
1201 state_atom_list.push_back(
1202 atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
1205 // If the window should stay on top of other windows, add the
1206 // _NET_WM_STATE_ABOVE property.
1207 is_always_on_top_ = params.keep_on_top;
1208 if (is_always_on_top_)
1209 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
1211 if (params.visible_on_all_workspaces) {
1212 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_STICKY"));
1213 ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllDesktops);
1216 // Setting _NET_WM_STATE by sending a message to the root_window (with
1217 // SetWMSpecState) has no effect here since the window has not yet been
1218 // mapped. So we manually change the state.
1219 if (!state_atom_list.empty()) {
1220 ui::SetAtomArrayProperty(xwindow_,
1221 "_NET_WM_STATE",
1222 "ATOM",
1223 state_atom_list);
1226 if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
1227 ui::SetWindowClassHint(
1228 xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
1231 const char* wm_role_name = NULL;
1232 // If the widget isn't overriding the role, provide a default value for popup
1233 // and bubble types.
1234 if (!params.wm_role_name.empty()) {
1235 wm_role_name = params.wm_role_name.c_str();
1236 } else {
1237 switch (params.type) {
1238 case Widget::InitParams::TYPE_POPUP:
1239 wm_role_name = kX11WindowRolePopup;
1240 break;
1241 case Widget::InitParams::TYPE_BUBBLE:
1242 wm_role_name = kX11WindowRoleBubble;
1243 break;
1244 default:
1245 break;
1248 if (wm_role_name)
1249 ui::SetWindowRole(xdisplay_, xwindow_, std::string(wm_role_name));
1251 if (params.remove_standard_frame) {
1252 // Setting _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED tells gnome-shell to not force
1253 // fullscreen on the window when it matches the desktop size.
1254 ui::SetHideTitlebarWhenMaximizedProperty(xwindow_,
1255 ui::HIDE_TITLEBAR_WHEN_MAXIMIZED);
1258 // If we have a parent, record the parent/child relationship. We use this
1259 // data during destruction to make sure that when we try to close a parent
1260 // window, we also destroy all child windows.
1261 if (params.parent && params.parent->GetHost()) {
1262 XID parent_xid =
1263 params.parent->GetHost()->GetAcceleratedWidget();
1264 window_parent_ = GetHostForXID(parent_xid);
1265 DCHECK(window_parent_);
1266 window_parent_->window_children_.insert(this);
1269 // If we have a delegate which is providing a default window icon, use that
1270 // icon.
1271 gfx::ImageSkia* window_icon =
1272 ViewsDelegate::GetInstance()
1273 ? ViewsDelegate::GetInstance()->GetDefaultWindowIcon()
1274 : NULL;
1275 if (window_icon) {
1276 SetWindowIcons(gfx::ImageSkia(), *window_icon);
1278 CreateCompositor();
1279 OnAcceleratedWidgetAvailable();
1282 gfx::Size DesktopWindowTreeHostX11::AdjustSize(
1283 const gfx::Size& requested_size_in_pixels) {
1284 std::vector<gfx::Display> displays =
1285 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE)->GetAllDisplays();
1286 // Compare against all monitor sizes. The window manager can move the window
1287 // to whichever monitor it wants.
1288 for (size_t i = 0; i < displays.size(); ++i) {
1289 if (requested_size_in_pixels == displays[i].GetSizeInPixel()) {
1290 return gfx::Size(requested_size_in_pixels.width() - 1,
1291 requested_size_in_pixels.height() - 1);
1295 // Do not request a 0x0 window size. It causes an XError.
1296 gfx::Size size_in_pixels = requested_size_in_pixels;
1297 size_in_pixels.SetToMax(gfx::Size(1, 1));
1298 return size_in_pixels;
1301 void DesktopWindowTreeHostX11::OnWMStateUpdated() {
1302 std::vector< ::Atom> atom_list;
1303 // Ignore the return value of ui::GetAtomArrayProperty(). Fluxbox removes the
1304 // _NET_WM_STATE property when no _NET_WM_STATE atoms are set.
1305 ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list);
1307 bool was_minimized = IsMinimized();
1309 window_properties_.clear();
1310 std::copy(atom_list.begin(), atom_list.end(),
1311 inserter(window_properties_, window_properties_.begin()));
1313 // Propagate the window minimization information to the content window, so
1314 // the render side can update its visibility properly. OnWMStateUpdated() is
1315 // called by PropertyNofify event from DispatchEvent() when the browser is
1316 // minimized or shown from minimized state. On Windows, this is realized by
1317 // calling OnHostResized() with an empty size. In particular,
1318 // HWNDMessageHandler::GetClientAreaBounds() returns an empty size when the
1319 // window is minimized. On Linux, returning empty size in GetBounds() or
1320 // SetBounds() does not work.
1321 // We also propagate the minimization to the compositor, to makes sure that we
1322 // don't draw any 'blank' frames that could be noticed in applications such as
1323 // window manager previews, which show content even when a window is
1324 // minimized.
1325 bool is_minimized = IsMinimized();
1326 if (is_minimized != was_minimized) {
1327 if (is_minimized) {
1328 compositor()->SetVisible(false);
1329 content_window_->Hide();
1330 } else {
1331 content_window_->Show();
1332 compositor()->SetVisible(true);
1336 if (restored_bounds_in_pixels_.IsEmpty()) {
1337 DCHECK(!IsFullscreen());
1338 if (IsMaximized()) {
1339 // The request that we become maximized originated from a different
1340 // process. |bounds_in_pixels_| already contains our maximized bounds. Do
1341 // a best effort attempt to get restored bounds by setting it to our
1342 // previously set bounds (and if we get this wrong, we aren't any worse
1343 // off since we'd otherwise be returning our maximized bounds).
1344 restored_bounds_in_pixels_ = previous_bounds_in_pixels_;
1346 } else if (!IsMaximized() && !IsFullscreen()) {
1347 // If we have restored bounds, but WM_STATE no longer claims to be
1348 // maximized or fullscreen, we should clear our restored bounds.
1349 restored_bounds_in_pixels_ = gfx::Rect();
1352 // Ignore requests by the window manager to enter or exit fullscreen (e.g. as
1353 // a result of pressing a window manager accelerator key). Chrome does not
1354 // handle window manager initiated fullscreen. In particular, Chrome needs to
1355 // do preprocessing before the x window's fullscreen state is toggled.
1357 is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE");
1359 // Now that we have different window properties, we may need to relayout the
1360 // window. (The windows code doesn't need this because their window change is
1361 // synchronous.)
1362 Relayout();
1363 ResetWindowRegion();
1366 void DesktopWindowTreeHostX11::OnFrameExtentsUpdated() {
1367 std::vector<int> insets;
1368 if (ui::GetIntArrayProperty(xwindow_, "_NET_FRAME_EXTENTS", &insets) &&
1369 insets.size() == 4) {
1370 // |insets| are returned in the order: [left, right, top, bottom].
1371 native_window_frame_borders_in_pixels_ =
1372 gfx::Insets(insets[2], insets[0], insets[3], insets[1]);
1373 } else {
1374 native_window_frame_borders_in_pixels_ = gfx::Insets();
1378 void DesktopWindowTreeHostX11::UpdateMinAndMaxSize() {
1379 if (!window_mapped_)
1380 return;
1382 gfx::Size minimum_in_pixels =
1383 ToPixelRect(gfx::Rect(native_widget_delegate_->GetMinimumSize())).size();
1384 gfx::Size maximum_in_pixels =
1385 ToPixelRect(gfx::Rect(native_widget_delegate_->GetMaximumSize())).size();
1386 if (min_size_in_pixels_ == minimum_in_pixels &&
1387 max_size_in_pixels_ == maximum_in_pixels)
1388 return;
1390 min_size_in_pixels_ = minimum_in_pixels;
1391 max_size_in_pixels_ = maximum_in_pixels;
1393 XSizeHints hints;
1394 long supplied_return;
1395 XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return);
1397 if (minimum_in_pixels.IsEmpty()) {
1398 hints.flags &= ~PMinSize;
1399 } else {
1400 hints.flags |= PMinSize;
1401 hints.min_width = min_size_in_pixels_.width();
1402 hints.min_height = min_size_in_pixels_.height();
1405 if (maximum_in_pixels.IsEmpty()) {
1406 hints.flags &= ~PMaxSize;
1407 } else {
1408 hints.flags |= PMaxSize;
1409 hints.max_width = max_size_in_pixels_.width();
1410 hints.max_height = max_size_in_pixels_.height();
1413 XSetWMNormalHints(xdisplay_, xwindow_, &hints);
1416 void DesktopWindowTreeHostX11::UpdateWMUserTime(
1417 const ui::PlatformEvent& event) {
1418 if (!IsActive())
1419 return;
1421 ui::EventType type = ui::EventTypeFromNative(event);
1422 if (type == ui::ET_MOUSE_PRESSED ||
1423 type == ui::ET_KEY_PRESSED ||
1424 type == ui::ET_TOUCH_PRESSED) {
1425 unsigned long wm_user_time_ms = static_cast<unsigned long>(
1426 ui::EventTimeFromNative(event).InMilliseconds());
1427 XChangeProperty(xdisplay_,
1428 xwindow_,
1429 atom_cache_.GetAtom("_NET_WM_USER_TIME"),
1430 XA_CARDINAL,
1432 PropModeReplace,
1433 reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
1435 X11DesktopHandler::get()->set_wm_user_time_ms(wm_user_time_ms);
1439 void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled,
1440 ::Atom state1,
1441 ::Atom state2) {
1442 XEvent xclient;
1443 memset(&xclient, 0, sizeof(xclient));
1444 xclient.type = ClientMessage;
1445 xclient.xclient.window = xwindow_;
1446 xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
1447 xclient.xclient.format = 32;
1448 xclient.xclient.data.l[0] =
1449 enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
1450 xclient.xclient.data.l[1] = state1;
1451 xclient.xclient.data.l[2] = state2;
1452 xclient.xclient.data.l[3] = 1;
1453 xclient.xclient.data.l[4] = 0;
1455 XSendEvent(xdisplay_, x_root_window_, False,
1456 SubstructureRedirectMask | SubstructureNotifyMask,
1457 &xclient);
1460 bool DesktopWindowTreeHostX11::HasWMSpecProperty(const char* property) const {
1461 return window_properties_.find(atom_cache_.GetAtom(property)) !=
1462 window_properties_.end();
1465 void DesktopWindowTreeHostX11::SetUseNativeFrame(bool use_native_frame) {
1466 use_native_frame_ = use_native_frame;
1467 ui::SetUseOSWindowFrame(xwindow_, use_native_frame);
1468 ResetWindowRegion();
1471 void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
1472 // In Windows, the native events sent to chrome are separated into client
1473 // and non-client versions of events, which we record on our LocatedEvent
1474 // structures. On X11, we emulate the concept of non-client. Before we pass
1475 // this event to the cross platform event handling framework, we need to
1476 // make sure it is appropriately marked as non-client if it's in the non
1477 // client area, or otherwise, we can get into a state where the a window is
1478 // set as the |mouse_pressed_handler_| in window_event_dispatcher.cc
1479 // despite the mouse button being released.
1481 // We can't do this later in the dispatch process because we share that
1482 // with ash, and ash gets confused about event IS_NON_CLIENT-ness on
1483 // events, since ash doesn't expect this bit to be set, because it's never
1484 // been set before. (This works on ash on Windows because none of the mouse
1485 // events on the ash desktop are clicking in what Windows considers to be a
1486 // non client area.) Likewise, we won't want to do the following in any
1487 // WindowTreeHost that hosts ash.
1488 if (content_window_ && content_window_->delegate()) {
1489 int flags = event->flags();
1490 int hit_test_code =
1491 content_window_->delegate()->GetNonClientComponent(event->location());
1492 if (hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE)
1493 flags |= ui::EF_IS_NON_CLIENT;
1494 event->set_flags(flags);
1497 // While we unset the urgency hint when we gain focus, we also must remove it
1498 // on mouse clicks because we can call FlashFrame() on an active window.
1499 if (event->IsAnyButton() || event->IsMouseWheelEvent())
1500 FlashFrame(false);
1502 if (!g_current_capture || g_current_capture == this) {
1503 SendEventToProcessor(event);
1504 } else {
1505 // Another DesktopWindowTreeHostX11 has installed itself as
1506 // capture. Translate the event's location and dispatch to the other.
1507 ConvertEventToDifferentHost(event, g_current_capture);
1508 g_current_capture->SendEventToProcessor(event);
1512 void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) {
1513 if (g_current_capture && g_current_capture != this &&
1514 event->type() == ui::ET_TOUCH_PRESSED) {
1515 ConvertEventToDifferentHost(event, g_current_capture);
1516 g_current_capture->SendEventToProcessor(event);
1517 } else {
1518 SendEventToProcessor(event);
1522 void DesktopWindowTreeHostX11::DispatchKeyEvent(ui::KeyEvent* event) {
1523 GetInputMethod()->DispatchKeyEvent(event);
1526 void DesktopWindowTreeHostX11::ConvertEventToDifferentHost(
1527 ui::LocatedEvent* located_event,
1528 DesktopWindowTreeHostX11* host) {
1529 DCHECK_NE(this, host);
1530 const gfx::Display display_src =
1531 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(window());
1532 const gfx::Display display_dest =
1533 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(host->window());
1534 DCHECK_EQ(display_src.device_scale_factor(),
1535 display_dest.device_scale_factor());
1536 gfx::Vector2d offset = GetLocationOnNativeScreen() -
1537 host->GetLocationOnNativeScreen();
1538 gfx::Point location_in_pixel_in_host = located_event->location() + offset;
1539 located_event->set_location(location_in_pixel_in_host);
1542 void DesktopWindowTreeHostX11::ResetWindowRegion() {
1543 // If a custom window shape was supplied then apply it.
1544 if (custom_window_shape_) {
1545 XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding, 0, 0,
1546 window_shape_.get(), false);
1547 return;
1550 window_shape_.reset();
1552 if (!IsMaximized() && !IsFullscreen()) {
1553 gfx::Path window_mask;
1554 views::Widget* widget = native_widget_delegate_->AsWidget();
1555 if (widget->non_client_view()) {
1556 // Some frame views define a custom (non-rectangular) window mask. If
1557 // so, use it to define the window shape. If not, fall through.
1558 widget->non_client_view()->GetWindowMask(bounds_in_pixels_.size(),
1559 &window_mask);
1560 if (window_mask.countPoints() > 0) {
1561 window_shape_.reset(gfx::CreateRegionFromSkPath(window_mask));
1562 XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding, 0, 0,
1563 window_shape_.get(), false);
1564 return;
1569 // If we didn't set the shape for any reason, reset the shaping information.
1570 // How this is done depends on the border style, due to quirks and bugs in
1571 // various window managers.
1572 if (ShouldUseNativeFrame()) {
1573 // If the window has system borders, the mask must be set to null (not a
1574 // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will
1575 // not put borders on a window with a custom shape.
1576 XShapeCombineMask(xdisplay_, xwindow_, ShapeBounding, 0, 0, None, ShapeSet);
1577 } else {
1578 // Conversely, if the window does not have system borders, the mask must be
1579 // manually set to a rectangle that covers the whole window (not null). This
1580 // is due to a bug in KWin <= 4.11.5 (KDE bug #330573) where setting a null
1581 // shape causes the hint to disable system borders to be ignored (resulting
1582 // in a double border).
1583 XRectangle r = {0,
1585 static_cast<unsigned short>(bounds_in_pixels_.width()),
1586 static_cast<unsigned short>(bounds_in_pixels_.height())};
1587 XShapeCombineRectangles(
1588 xdisplay_, xwindow_, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded);
1592 void DesktopWindowTreeHostX11::SerializeImageRepresentation(
1593 const gfx::ImageSkiaRep& rep,
1594 std::vector<unsigned long>* data) {
1595 int width = rep.GetWidth();
1596 data->push_back(width);
1598 int height = rep.GetHeight();
1599 data->push_back(height);
1601 const SkBitmap& bitmap = rep.sk_bitmap();
1602 SkAutoLockPixels locker(bitmap);
1604 for (int y = 0; y < height; ++y)
1605 for (int x = 0; x < width; ++x)
1606 data->push_back(bitmap.getColor(x, y));
1609 Visual* DesktopWindowTreeHostX11::GetARGBVisual() {
1610 XVisualInfo visual_template;
1611 visual_template.screen = 0;
1613 int visuals_len;
1614 gfx::XScopedPtr<XVisualInfo[]> visual_list(XGetVisualInfo(
1615 xdisplay_, VisualScreenMask, &visual_template, &visuals_len));
1616 for (int i = 0; i < visuals_len; ++i) {
1617 // Why support only 8888 ARGB? Because it's all that GTK+ supports. In
1618 // gdkvisual-x11.cc, they look for this specific visual and use it for all
1619 // their alpha channel using needs.
1621 // TODO(erg): While the following does find a valid visual, some GL drivers
1622 // don't believe that this has an alpha channel. According to marcheu@,
1623 // this should work on open source driver though. (It doesn't work with
1624 // NVidia's binaries currently.) http://crbug.com/369209
1625 const XVisualInfo& info = visual_list[i];
1626 if (info.depth == 32 && info.visual->red_mask == 0xff0000 &&
1627 info.visual->green_mask == 0x00ff00 &&
1628 info.visual->blue_mask == 0x0000ff) {
1629 return info.visual;
1633 return nullptr;
1636 std::list<XID>& DesktopWindowTreeHostX11::open_windows() {
1637 if (!open_windows_)
1638 open_windows_ = new std::list<XID>();
1639 return *open_windows_;
1642 void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) {
1643 if (show_state != ui::SHOW_STATE_DEFAULT &&
1644 show_state != ui::SHOW_STATE_NORMAL &&
1645 show_state != ui::SHOW_STATE_INACTIVE &&
1646 show_state != ui::SHOW_STATE_MAXIMIZED) {
1647 // It will behave like SHOW_STATE_NORMAL.
1648 NOTIMPLEMENTED();
1651 // Before we map the window, set size hints. Otherwise, some window managers
1652 // will ignore toplevel XMoveWindow commands.
1653 XSizeHints size_hints;
1654 size_hints.flags = PPosition;
1655 size_hints.x = bounds_in_pixels_.x();
1656 size_hints.y = bounds_in_pixels_.y();
1657 XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
1659 // If SHOW_STATE_INACTIVE, tell the window manager not to focus the window
1660 // when mapping. This is done by setting the _NET_WM_USER_TIME to 0. See e.g.
1661 // http://standards.freedesktop.org/wm-spec/latest/ar01s05.html
1662 unsigned long wm_user_time_ms = (show_state == ui::SHOW_STATE_INACTIVE) ?
1663 0 : X11DesktopHandler::get()->wm_user_time_ms();
1664 if (show_state == ui::SHOW_STATE_INACTIVE || wm_user_time_ms != 0) {
1665 XChangeProperty(xdisplay_,
1666 xwindow_,
1667 atom_cache_.GetAtom("_NET_WM_USER_TIME"),
1668 XA_CARDINAL,
1670 PropModeReplace,
1671 reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
1675 XMapWindow(xdisplay_, xwindow_);
1677 // We now block until our window is mapped. Some X11 APIs will crash and
1678 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
1679 // asynchronous.
1680 if (ui::X11EventSource::GetInstance())
1681 ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_);
1682 window_mapped_ = true;
1684 UpdateMinAndMaxSize();
1686 // Some WMs only respect maximize hints after the window has been mapped.
1687 // Check whether we need to re-do a maximization.
1688 if (should_maximize_after_map_) {
1689 Maximize();
1690 should_maximize_after_map_ = false;
1694 void DesktopWindowTreeHostX11::SetWindowTransparency() {
1695 compositor()->SetHostHasTransparentBackground(use_argb_visual_);
1696 window()->SetTransparent(use_argb_visual_);
1697 content_window_->SetTransparent(use_argb_visual_);
1700 void DesktopWindowTreeHostX11::Relayout() {
1701 Widget* widget = native_widget_delegate_->AsWidget();
1702 NonClientView* non_client_view = widget->non_client_view();
1703 // non_client_view may be NULL, especially during creation.
1704 if (non_client_view) {
1705 non_client_view->client_view()->InvalidateLayout();
1706 non_client_view->InvalidateLayout();
1708 widget->GetRootView()->Layout();
1711 ////////////////////////////////////////////////////////////////////////////////
1712 // DesktopWindowTreeHostX11, ui::PlatformEventDispatcher implementation:
1714 bool DesktopWindowTreeHostX11::CanDispatchEvent(
1715 const ui::PlatformEvent& event) {
1716 return event->xany.window == xwindow_ ||
1717 (event->type == GenericEvent &&
1718 static_cast<XIDeviceEvent*>(event->xcookie.data)->event == xwindow_);
1721 uint32_t DesktopWindowTreeHostX11::DispatchEvent(
1722 const ui::PlatformEvent& event) {
1723 XEvent* xev = event;
1725 TRACE_EVENT1("views", "DesktopWindowTreeHostX11::Dispatch",
1726 "event->type", event->type);
1728 UpdateWMUserTime(event);
1730 // May want to factor CheckXEventForConsistency(xev); into a common location
1731 // since it is called here.
1732 switch (xev->type) {
1733 case EnterNotify:
1734 case LeaveNotify: {
1735 // Ignore EventNotify and LeaveNotify events from children of |xwindow_|.
1736 // NativeViewGLSurfaceGLX adds a child to |xwindow_|.
1737 // TODO(pkotwicz|tdanderson): Figure out whether the suppression is
1738 // necessary. crbug.com/385716
1739 if (xev->xcrossing.detail == NotifyInferior)
1740 break;
1742 ui::MouseEvent mouse_event(xev);
1743 DispatchMouseEvent(&mouse_event);
1744 break;
1746 case Expose: {
1747 gfx::Rect damage_rect_in_pixels(xev->xexpose.x, xev->xexpose.y,
1748 xev->xexpose.width, xev->xexpose.height);
1749 compositor()->ScheduleRedrawRect(damage_rect_in_pixels);
1750 break;
1752 case KeyPress: {
1753 ui::KeyEvent keydown_event(xev);
1754 DispatchKeyEvent(&keydown_event);
1755 break;
1757 case KeyRelease: {
1758 // There is no way to deactivate a window in X11 so ignore input if
1759 // window is supposed to be 'inactive'. See comments in
1760 // X11DesktopHandler::DeactivateWindow() for more details.
1761 if (!IsActive() && !HasCapture())
1762 break;
1764 ui::KeyEvent key_event(xev);
1765 DispatchKeyEvent(&key_event);
1766 break;
1768 case ButtonPress:
1769 case ButtonRelease: {
1770 ui::EventType event_type = ui::EventTypeFromNative(xev);
1771 switch (event_type) {
1772 case ui::ET_MOUSEWHEEL: {
1773 ui::MouseWheelEvent mouseev(xev);
1774 DispatchMouseEvent(&mouseev);
1775 break;
1777 case ui::ET_MOUSE_PRESSED:
1778 case ui::ET_MOUSE_RELEASED: {
1779 ui::MouseEvent mouseev(xev);
1780 DispatchMouseEvent(&mouseev);
1781 break;
1783 case ui::ET_UNKNOWN:
1784 // No event is created for X11-release events for mouse-wheel buttons.
1785 break;
1786 default:
1787 NOTREACHED() << event_type;
1789 break;
1791 case FocusOut:
1792 if (xev->xfocus.mode != NotifyGrab) {
1793 ReleaseCapture();
1794 OnHostLostWindowCapture();
1795 X11DesktopHandler::get()->ProcessXEvent(xev);
1796 } else {
1797 dispatcher()->OnHostLostMouseGrab();
1799 break;
1800 case FocusIn:
1801 X11DesktopHandler::get()->ProcessXEvent(xev);
1802 break;
1803 case ConfigureNotify: {
1804 DCHECK_EQ(xwindow_, xev->xconfigure.window);
1805 DCHECK_EQ(xwindow_, xev->xconfigure.event);
1806 // It's possible that the X window may be resized by some other means than
1807 // from within aura (e.g. the X window manager can change the size). Make
1808 // sure the root window size is maintained properly.
1809 int translated_x_in_pixels = xev->xconfigure.x;
1810 int translated_y_in_pixels = xev->xconfigure.y;
1811 if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
1812 Window unused;
1813 XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_, 0, 0,
1814 &translated_x_in_pixels, &translated_y_in_pixels,
1815 &unused);
1817 gfx::Rect bounds_in_pixels(translated_x_in_pixels, translated_y_in_pixels,
1818 xev->xconfigure.width, xev->xconfigure.height);
1819 bool size_changed = bounds_in_pixels_.size() != bounds_in_pixels.size();
1820 bool origin_changed =
1821 bounds_in_pixels_.origin() != bounds_in_pixels.origin();
1822 previous_bounds_in_pixels_ = bounds_in_pixels_;
1823 bounds_in_pixels_ = bounds_in_pixels;
1825 if (origin_changed)
1826 OnHostMoved(bounds_in_pixels_.origin());
1828 if (size_changed) {
1829 delayed_resize_task_.Reset(base::Bind(
1830 &DesktopWindowTreeHostX11::DelayedResize,
1831 close_widget_factory_.GetWeakPtr(), bounds_in_pixels.size()));
1832 base::MessageLoop::current()->PostTask(
1833 FROM_HERE, delayed_resize_task_.callback());
1835 break;
1837 case GenericEvent: {
1838 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
1839 if (!factory->ShouldProcessXI2Event(xev))
1840 break;
1842 ui::EventType type = ui::EventTypeFromNative(xev);
1843 XEvent last_event;
1844 int num_coalesced = 0;
1846 switch (type) {
1847 case ui::ET_TOUCH_MOVED:
1848 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1849 if (num_coalesced > 0)
1850 xev = &last_event;
1851 // fallthrough
1852 case ui::ET_TOUCH_PRESSED:
1853 case ui::ET_TOUCH_RELEASED: {
1854 ui::TouchEvent touchev(xev);
1855 DispatchTouchEvent(&touchev);
1856 break;
1858 case ui::ET_MOUSE_MOVED:
1859 case ui::ET_MOUSE_DRAGGED:
1860 case ui::ET_MOUSE_PRESSED:
1861 case ui::ET_MOUSE_RELEASED:
1862 case ui::ET_MOUSE_ENTERED:
1863 case ui::ET_MOUSE_EXITED: {
1864 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
1865 // If this is a motion event, we want to coalesce all pending motion
1866 // events that are at the top of the queue.
1867 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1868 if (num_coalesced > 0)
1869 xev = &last_event;
1871 ui::MouseEvent mouseev(xev);
1872 DispatchMouseEvent(&mouseev);
1873 break;
1875 case ui::ET_MOUSEWHEEL: {
1876 ui::MouseWheelEvent mouseev(xev);
1877 DispatchMouseEvent(&mouseev);
1878 break;
1880 case ui::ET_SCROLL_FLING_START:
1881 case ui::ET_SCROLL_FLING_CANCEL:
1882 case ui::ET_SCROLL: {
1883 ui::ScrollEvent scrollev(xev);
1884 SendEventToProcessor(&scrollev);
1885 break;
1887 case ui::ET_KEY_PRESSED:
1888 case ui::ET_KEY_RELEASED: {
1889 ui::KeyEvent key_event(xev);
1890 DispatchKeyEvent(&key_event);
1891 break;
1893 case ui::ET_UNKNOWN:
1894 break;
1895 default:
1896 NOTREACHED();
1899 // If we coalesced an event we need to free its cookie.
1900 if (num_coalesced > 0)
1901 XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
1902 break;
1904 case MapNotify: {
1905 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1906 observer_list_,
1907 OnWindowMapped(xwindow_));
1908 break;
1910 case UnmapNotify: {
1911 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1912 observer_list_,
1913 OnWindowUnmapped(xwindow_));
1914 break;
1916 case ClientMessage: {
1917 Atom message_type = xev->xclient.message_type;
1918 if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
1919 Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
1920 if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
1921 // We have received a close message from the window manager.
1922 OnHostCloseRequested();
1923 } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
1924 XEvent reply_event = *xev;
1925 reply_event.xclient.window = x_root_window_;
1927 XSendEvent(xdisplay_,
1928 reply_event.xclient.window,
1929 False,
1930 SubstructureRedirectMask | SubstructureNotifyMask,
1931 &reply_event);
1933 } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
1934 drag_drop_client_->OnXdndEnter(xev->xclient);
1935 } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
1936 drag_drop_client_->OnXdndLeave(xev->xclient);
1937 } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
1938 drag_drop_client_->OnXdndPosition(xev->xclient);
1939 } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
1940 drag_drop_client_->OnXdndStatus(xev->xclient);
1941 } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
1942 drag_drop_client_->OnXdndFinished(xev->xclient);
1943 } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
1944 drag_drop_client_->OnXdndDrop(xev->xclient);
1946 break;
1948 case MappingNotify: {
1949 switch (xev->xmapping.request) {
1950 case MappingModifier:
1951 case MappingKeyboard:
1952 XRefreshKeyboardMapping(&xev->xmapping);
1953 break;
1954 case MappingPointer:
1955 ui::DeviceDataManagerX11::GetInstance()->UpdateButtonMap();
1956 break;
1957 default:
1958 NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
1959 break;
1961 break;
1963 case MotionNotify: {
1964 // Discard all but the most recent motion event that targets the same
1965 // window with unchanged state.
1966 XEvent last_event;
1967 while (XPending(xev->xany.display)) {
1968 XEvent next_event;
1969 XPeekEvent(xev->xany.display, &next_event);
1970 if (next_event.type == MotionNotify &&
1971 next_event.xmotion.window == xev->xmotion.window &&
1972 next_event.xmotion.subwindow == xev->xmotion.subwindow &&
1973 next_event.xmotion.state == xev->xmotion.state) {
1974 XNextEvent(xev->xany.display, &last_event);
1975 xev = &last_event;
1976 } else {
1977 break;
1981 ui::MouseEvent mouseev(xev);
1982 DispatchMouseEvent(&mouseev);
1983 break;
1985 case PropertyNotify: {
1986 ::Atom changed_atom = xev->xproperty.atom;
1987 if (changed_atom == atom_cache_.GetAtom("_NET_WM_STATE"))
1988 OnWMStateUpdated();
1989 else if (changed_atom == atom_cache_.GetAtom("_NET_FRAME_EXTENTS"))
1990 OnFrameExtentsUpdated();
1991 break;
1993 case SelectionNotify: {
1994 drag_drop_client_->OnSelectionNotify(xev->xselection);
1995 break;
1998 return ui::POST_DISPATCH_STOP_PROPAGATION;
2001 void DesktopWindowTreeHostX11::DelayedResize(const gfx::Size& size_in_pixels) {
2002 OnHostResized(size_in_pixels);
2003 ResetWindowRegion();
2004 delayed_resize_task_.Cancel();
2007 gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInPixels() const {
2008 std::vector<int> value;
2009 if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
2010 value.size() >= 4) {
2011 return gfx::Rect(value[0], value[1], value[2], value[3]);
2014 // Fetch the geometry of the root window.
2015 Window root;
2016 int x, y;
2017 unsigned int width, height;
2018 unsigned int border_width, depth;
2019 if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y, &width, &height,
2020 &border_width, &depth)) {
2021 NOTIMPLEMENTED();
2022 return gfx::Rect(0, 0, 10, 10);
2025 return gfx::Rect(x, y, width, height);
2028 gfx::Rect DesktopWindowTreeHostX11::ToDIPRect(
2029 const gfx::Rect& rect_in_pixels) const {
2030 gfx::RectF rect_in_dip = gfx::RectF(rect_in_pixels);
2031 GetRootTransform().TransformRectReverse(&rect_in_dip);
2032 return gfx::ToEnclosingRect(rect_in_dip);
2035 gfx::Rect DesktopWindowTreeHostX11::ToPixelRect(
2036 const gfx::Rect& rect_in_dip) const {
2037 gfx::RectF rect_in_pixels = gfx::RectF(rect_in_dip);
2038 GetRootTransform().TransformRect(&rect_in_pixels);
2039 return gfx::ToEnclosingRect(rect_in_pixels);
2042 ////////////////////////////////////////////////////////////////////////////////
2043 // DesktopWindowTreeHost, public:
2045 // static
2046 DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
2047 internal::NativeWidgetDelegate* native_widget_delegate,
2048 DesktopNativeWidgetAura* desktop_native_widget_aura) {
2049 return new DesktopWindowTreeHostX11(native_widget_delegate,
2050 desktop_native_widget_aura);
2053 // static
2054 ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) {
2055 const views::LinuxUI* linux_ui = views::LinuxUI::instance();
2056 if (linux_ui) {
2057 ui::NativeTheme* native_theme = linux_ui->GetNativeTheme(window);
2058 if (native_theme)
2059 return native_theme;
2062 return ui::NativeTheme::instance();
2065 } // namespace views