Add ability for NetLogLogger to gather data from more than just NetLog
[chromium-blink-merge.git] / ui / views / widget / desktop_aura / desktop_window_tree_host_x11.cc
blob9ea44a849eacf7d924ce96cc0f29c928ecf15dad
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/x/x11_util.h"
27 #include "ui/events/devices/x11/device_data_manager_x11.h"
28 #include "ui/events/devices/x11/device_list_cache_x11.h"
29 #include "ui/events/devices/x11/touch_factory_x11.h"
30 #include "ui/events/event_utils.h"
31 #include "ui/events/platform/platform_event_source.h"
32 #include "ui/events/platform/x11/x11_event_source.h"
33 #include "ui/gfx/display.h"
34 #include "ui/gfx/geometry/insets.h"
35 #include "ui/gfx/geometry/size_conversions.h"
36 #include "ui/gfx/image/image_skia.h"
37 #include "ui/gfx/image/image_skia_rep.h"
38 #include "ui/gfx/path.h"
39 #include "ui/gfx/path_x11.h"
40 #include "ui/gfx/screen.h"
41 #include "ui/native_theme/native_theme.h"
42 #include "ui/views/corewm/tooltip_aura.h"
43 #include "ui/views/ime/input_method.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 } // namespace
133 ////////////////////////////////////////////////////////////////////////////////
134 // DesktopWindowTreeHostX11, public:
136 DesktopWindowTreeHostX11::DesktopWindowTreeHostX11(
137 internal::NativeWidgetDelegate* native_widget_delegate,
138 DesktopNativeWidgetAura* desktop_native_widget_aura)
139 : xdisplay_(gfx::GetXDisplay()),
140 xwindow_(0),
141 x_root_window_(DefaultRootWindow(xdisplay_)),
142 atom_cache_(xdisplay_, kAtomsToCache),
143 window_mapped_(false),
144 is_fullscreen_(false),
145 is_always_on_top_(false),
146 use_native_frame_(false),
147 should_maximize_after_map_(false),
148 use_argb_visual_(false),
149 drag_drop_client_(NULL),
150 native_widget_delegate_(native_widget_delegate),
151 desktop_native_widget_aura_(desktop_native_widget_aura),
152 content_window_(NULL),
153 window_parent_(NULL),
154 window_shape_(NULL),
155 custom_window_shape_(false),
156 urgency_hint_set_(false),
157 close_widget_factory_(this) {
160 DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() {
161 window()->ClearProperty(kHostForRootWindow);
162 aura::client::SetWindowMoveClient(window(), NULL);
163 desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
164 if (window_shape_)
165 XDestroyRegion(window_shape_);
166 DestroyDispatcher();
169 // static
170 aura::Window* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid) {
171 aura::WindowTreeHost* host =
172 aura::WindowTreeHost::GetForAcceleratedWidget(xid);
173 return host ? host->window()->GetProperty(kViewsWindowForRootWindow) : NULL;
176 // static
177 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::GetHostForXID(XID xid) {
178 aura::WindowTreeHost* host =
179 aura::WindowTreeHost::GetForAcceleratedWidget(xid);
180 return host ? host->window()->GetProperty(kHostForRootWindow) : NULL;
183 // static
184 std::vector<aura::Window*> DesktopWindowTreeHostX11::GetAllOpenWindows() {
185 std::vector<aura::Window*> windows(open_windows().size());
186 std::transform(open_windows().begin(),
187 open_windows().end(),
188 windows.begin(),
189 GetContentWindowForXID);
190 return windows;
193 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowBounds() const {
194 return bounds_in_pixels_;
197 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowOuterBounds() const {
198 gfx::Rect outer_bounds(bounds_in_pixels_);
199 outer_bounds.Inset(-native_window_frame_borders_in_pixels_);
200 return outer_bounds;
203 ::Region DesktopWindowTreeHostX11::GetWindowShape() const {
204 return window_shape_;
207 void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged(
208 bool active) {
209 if (active) {
210 FlashFrame(false);
211 OnHostActivated();
212 open_windows().remove(xwindow_);
213 open_windows().insert(open_windows().begin(), xwindow_);
214 } else {
215 ReleaseCapture();
218 desktop_native_widget_aura_->HandleActivationChanged(active);
220 native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
223 void DesktopWindowTreeHostX11::AddObserver(
224 views::DesktopWindowTreeHostObserverX11* observer) {
225 observer_list_.AddObserver(observer);
228 void DesktopWindowTreeHostX11::RemoveObserver(
229 views::DesktopWindowTreeHostObserverX11* observer) {
230 observer_list_.RemoveObserver(observer);
233 void DesktopWindowTreeHostX11::SwapNonClientEventHandler(
234 scoped_ptr<ui::EventHandler> handler) {
235 wm::CompoundEventFilter* compound_event_filter =
236 desktop_native_widget_aura_->root_window_event_filter();
237 if (x11_non_client_event_filter_)
238 compound_event_filter->RemoveHandler(x11_non_client_event_filter_.get());
239 compound_event_filter->AddHandler(handler.get());
240 x11_non_client_event_filter_ = handler.Pass();
243 void DesktopWindowTreeHostX11::CleanUpWindowList() {
244 delete open_windows_;
245 open_windows_ = NULL;
248 ////////////////////////////////////////////////////////////////////////////////
249 // DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation:
251 void DesktopWindowTreeHostX11::Init(aura::Window* content_window,
252 const Widget::InitParams& params) {
253 content_window_ = content_window;
255 // TODO(erg): Check whether we *should* be building a WindowTreeHost here, or
256 // whether we should be proxying requests to another DRWHL.
258 // In some situations, views tries to make a zero sized window, and that
259 // makes us crash. Make sure we have valid sizes.
260 Widget::InitParams sanitized_params = params;
261 if (sanitized_params.bounds.width() == 0)
262 sanitized_params.bounds.set_width(100);
263 if (sanitized_params.bounds.height() == 0)
264 sanitized_params.bounds.set_height(100);
266 InitX11Window(sanitized_params);
269 void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
270 const Widget::InitParams& params) {
271 window()->SetProperty(kViewsWindowForRootWindow, content_window_);
272 window()->SetProperty(kHostForRootWindow, this);
274 // Ensure that the X11DesktopHandler exists so that it dispatches activation
275 // messages to us.
276 X11DesktopHandler::get();
278 // TODO(erg): Unify this code once the other consumer goes away.
279 SwapNonClientEventHandler(
280 scoped_ptr<ui::EventHandler>(new X11WindowEventFilter(this)).Pass());
281 SetUseNativeFrame(params.type == Widget::InitParams::TYPE_WINDOW &&
282 !params.remove_standard_frame);
284 x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
285 aura::client::SetWindowMoveClient(window(), x11_window_move_client_.get());
287 SetWindowTransparency();
289 native_widget_delegate_->OnNativeWidgetCreated(true);
292 scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostX11::CreateTooltip() {
293 return make_scoped_ptr(new corewm::TooltipAura);
296 scoped_ptr<aura::client::DragDropClient>
297 DesktopWindowTreeHostX11::CreateDragDropClient(
298 DesktopNativeCursorManager* cursor_manager) {
299 drag_drop_client_ = new DesktopDragDropClientAuraX11(
300 window(), cursor_manager, xdisplay_, xwindow_);
301 drag_drop_client_->Init();
302 return make_scoped_ptr(drag_drop_client_);
305 void DesktopWindowTreeHostX11::Close() {
306 // TODO(erg): Might need to do additional hiding tasks here.
307 delayed_resize_task_.Cancel();
309 if (!close_widget_factory_.HasWeakPtrs()) {
310 // And we delay the close so that if we are called from an ATL callback,
311 // we don't destroy the window before the callback returned (as the caller
312 // may delete ourselves on destroy and the ATL callback would still
313 // dereference us when the callback returns).
314 base::MessageLoop::current()->PostTask(
315 FROM_HERE,
316 base::Bind(&DesktopWindowTreeHostX11::CloseNow,
317 close_widget_factory_.GetWeakPtr()));
321 void DesktopWindowTreeHostX11::CloseNow() {
322 if (xwindow_ == None)
323 return;
325 ReleaseCapture();
326 native_widget_delegate_->OnNativeWidgetDestroying();
328 // If we have children, close them. Use a copy for iteration because they'll
329 // remove themselves.
330 std::set<DesktopWindowTreeHostX11*> window_children_copy = window_children_;
331 for (std::set<DesktopWindowTreeHostX11*>::iterator it =
332 window_children_copy.begin(); it != window_children_copy.end();
333 ++it) {
334 (*it)->CloseNow();
336 DCHECK(window_children_.empty());
338 // If we have a parent, remove ourselves from its children list.
339 if (window_parent_) {
340 window_parent_->window_children_.erase(this);
341 window_parent_ = NULL;
344 // Remove the event listeners we've installed. We need to remove these
345 // because otherwise we get assert during ~WindowEventDispatcher().
346 desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
347 x11_non_client_event_filter_.get());
348 x11_non_client_event_filter_.reset();
350 // Destroy the compositor before destroying the |xwindow_| since shutdown
351 // may try to swap, and the swap without a window causes an X error, which
352 // causes a crash with in-process renderer.
353 DestroyCompositor();
355 open_windows().remove(xwindow_);
356 // Actually free our native resources.
357 if (ui::PlatformEventSource::GetInstance())
358 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
359 XDestroyWindow(xdisplay_, xwindow_);
360 xwindow_ = None;
362 desktop_native_widget_aura_->OnHostClosed();
365 aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() {
366 return this;
369 void DesktopWindowTreeHostX11::ShowWindowWithState(
370 ui::WindowShowState show_state) {
371 if (!window_mapped_)
372 MapWindow(show_state);
374 if (show_state == ui::SHOW_STATE_NORMAL ||
375 show_state == ui::SHOW_STATE_MAXIMIZED) {
376 Activate();
379 native_widget_delegate_->AsWidget()->SetInitialFocus(show_state);
382 void DesktopWindowTreeHostX11::ShowMaximizedWithBounds(
383 const gfx::Rect& restored_bounds) {
384 ShowWindowWithState(ui::SHOW_STATE_MAXIMIZED);
385 // Enforce |restored_bounds_in_pixels_| since calling Maximize() could have
386 // reset it.
387 restored_bounds_in_pixels_ = ToPixelRect(restored_bounds);
390 bool DesktopWindowTreeHostX11::IsVisible() const {
391 return window_mapped_;
394 void DesktopWindowTreeHostX11::SetSize(const gfx::Size& requested_size) {
395 gfx::Size size_in_pixels = ToPixelRect(gfx::Rect(requested_size)).size();
396 size_in_pixels = AdjustSize(size_in_pixels);
397 bool size_changed = bounds_in_pixels_.size() != size_in_pixels;
398 XResizeWindow(xdisplay_, xwindow_, size_in_pixels.width(),
399 size_in_pixels.height());
400 bounds_in_pixels_.set_size(size_in_pixels);
401 if (size_changed) {
402 OnHostResized(size_in_pixels);
403 ResetWindowRegion();
407 void DesktopWindowTreeHostX11::StackAtTop() {
408 XRaiseWindow(xdisplay_, xwindow_);
411 void DesktopWindowTreeHostX11::CenterWindow(const gfx::Size& size) {
412 gfx::Size size_in_pixels = ToPixelRect(gfx::Rect(size)).size();
413 gfx::Rect parent_bounds_in_pixels = GetWorkAreaBoundsInPixels();
415 // If |window_|'s transient parent bounds are big enough to contain |size|,
416 // use them instead.
417 if (wm::GetTransientParent(content_window_)) {
418 gfx::Rect transient_parent_rect =
419 wm::GetTransientParent(content_window_)->GetBoundsInScreen();
420 if (transient_parent_rect.height() >= size.height() &&
421 transient_parent_rect.width() >= size.width()) {
422 parent_bounds_in_pixels = ToPixelRect(transient_parent_rect);
426 gfx::Rect window_bounds_in_pixels(
427 parent_bounds_in_pixels.x() +
428 (parent_bounds_in_pixels.width() - size_in_pixels.width()) / 2,
429 parent_bounds_in_pixels.y() +
430 (parent_bounds_in_pixels.height() - size_in_pixels.height()) / 2,
431 size_in_pixels.width(), size_in_pixels.height());
432 // Don't size the window bigger than the parent, otherwise the user may not be
433 // able to close or move it.
434 window_bounds_in_pixels.AdjustToFit(parent_bounds_in_pixels);
436 SetBounds(window_bounds_in_pixels);
439 void DesktopWindowTreeHostX11::GetWindowPlacement(
440 gfx::Rect* bounds,
441 ui::WindowShowState* show_state) const {
442 *bounds = GetRestoredBounds();
444 if (IsFullscreen()) {
445 *show_state = ui::SHOW_STATE_FULLSCREEN;
446 } else if (IsMinimized()) {
447 *show_state = ui::SHOW_STATE_MINIMIZED;
448 } else if (IsMaximized()) {
449 *show_state = ui::SHOW_STATE_MAXIMIZED;
450 } else if (!IsActive()) {
451 *show_state = ui::SHOW_STATE_INACTIVE;
452 } else {
453 *show_state = ui::SHOW_STATE_NORMAL;
457 gfx::Rect DesktopWindowTreeHostX11::GetWindowBoundsInScreen() const {
458 return ToDIPRect(bounds_in_pixels_);
461 gfx::Rect DesktopWindowTreeHostX11::GetClientAreaBoundsInScreen() const {
462 // TODO(erg): The NativeWidgetAura version returns |bounds_in_pixels_|,
463 // claiming it's needed for View::ConvertPointToScreen() to work correctly.
464 // DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() just asks windows
465 // what it thinks the client rect is.
467 // Attempts to calculate the rect by asking the NonClientFrameView what it
468 // thought its GetBoundsForClientView() were broke combobox drop down
469 // placement.
470 return GetWindowBoundsInScreen();
473 gfx::Rect DesktopWindowTreeHostX11::GetRestoredBounds() const {
474 // We can't reliably track the restored bounds of a window, but we can get
475 // the 90% case down. When *chrome* is the process that requests maximizing
476 // or restoring bounds, we can record the current bounds before we request
477 // maximization, and clear it when we detect a state change.
478 if (!restored_bounds_in_pixels_.IsEmpty())
479 return ToDIPRect(restored_bounds_in_pixels_);
481 return GetWindowBoundsInScreen();
484 gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInScreen() const {
485 return ToDIPRect(GetWorkAreaBoundsInPixels());
488 void DesktopWindowTreeHostX11::SetShape(gfx::NativeRegion native_region) {
489 if (window_shape_)
490 XDestroyRegion(window_shape_);
491 custom_window_shape_ = false;
492 window_shape_ = NULL;
494 if (native_region) {
495 gfx::Transform transform = GetRootTransform();
496 if (!transform.IsIdentity() && !native_region->isEmpty()) {
497 SkPath path_in_dip;
498 if (native_region->getBoundaryPath(&path_in_dip)) {
499 SkPath path_in_pixels;
500 path_in_dip.transform(transform.matrix(), &path_in_pixels);
501 window_shape_ = gfx::CreateRegionFromSkPath(path_in_pixels);
502 } else {
503 window_shape_ = XCreateRegion();
505 } else {
506 window_shape_ = gfx::CreateRegionFromSkRegion(*native_region);
509 custom_window_shape_ = true;
510 delete native_region;
512 ResetWindowRegion();
515 void DesktopWindowTreeHostX11::Activate() {
516 if (!window_mapped_)
517 return;
519 X11DesktopHandler::get()->ActivateWindow(xwindow_);
522 void DesktopWindowTreeHostX11::Deactivate() {
523 if (!IsActive())
524 return;
526 ReleaseCapture();
527 X11DesktopHandler::get()->DeactivateWindow(xwindow_);
530 bool DesktopWindowTreeHostX11::IsActive() const {
531 return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
534 void DesktopWindowTreeHostX11::Maximize() {
535 if (HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN")) {
536 // Unfullscreen the window if it is fullscreen.
537 SetWMSpecState(false,
538 atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
539 None);
541 // Resize the window so that it does not have the same size as a monitor.
542 // (Otherwise, some window managers immediately put the window back in
543 // fullscreen mode).
544 gfx::Rect adjusted_bounds_in_pixels(bounds_in_pixels_.origin(),
545 AdjustSize(bounds_in_pixels_.size()));
546 if (adjusted_bounds_in_pixels != bounds_in_pixels_)
547 SetBounds(adjusted_bounds_in_pixels);
550 // Some WMs do not respect maximization hints on unmapped windows, so we
551 // save this one for later too.
552 should_maximize_after_map_ = !window_mapped_;
554 // When we are in the process of requesting to maximize a window, we can
555 // accurately keep track of our restored bounds instead of relying on the
556 // heuristics that are in the PropertyNotify and ConfigureNotify handlers.
557 restored_bounds_in_pixels_ = bounds_in_pixels_;
559 SetWMSpecState(true,
560 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
561 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
562 if (IsMinimized())
563 ShowWindowWithState(ui::SHOW_STATE_NORMAL);
566 void DesktopWindowTreeHostX11::Minimize() {
567 ReleaseCapture();
568 XIconifyWindow(xdisplay_, xwindow_, 0);
571 void DesktopWindowTreeHostX11::Restore() {
572 should_maximize_after_map_ = false;
573 SetWMSpecState(false,
574 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
575 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
576 if (IsMinimized())
577 ShowWindowWithState(ui::SHOW_STATE_NORMAL);
580 bool DesktopWindowTreeHostX11::IsMaximized() const {
581 return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") &&
582 HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
585 bool DesktopWindowTreeHostX11::IsMinimized() const {
586 return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
589 bool DesktopWindowTreeHostX11::HasCapture() const {
590 return g_current_capture == this;
593 void DesktopWindowTreeHostX11::SetAlwaysOnTop(bool always_on_top) {
594 is_always_on_top_ = always_on_top;
595 SetWMSpecState(always_on_top,
596 atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
597 None);
600 bool DesktopWindowTreeHostX11::IsAlwaysOnTop() const {
601 return is_always_on_top_;
604 void DesktopWindowTreeHostX11::SetVisibleOnAllWorkspaces(bool always_visible) {
605 SetWMSpecState(always_visible,
606 atom_cache_.GetAtom("_NET_WM_STATE_STICKY"),
607 None);
609 int new_desktop = 0;
610 if (always_visible) {
611 new_desktop = kAllDesktops;
612 } else {
613 if (!ui::GetCurrentDesktop(&new_desktop))
614 return;
617 XEvent xevent;
618 memset (&xevent, 0, sizeof (xevent));
619 xevent.type = ClientMessage;
620 xevent.xclient.window = xwindow_;
621 xevent.xclient.message_type = atom_cache_.GetAtom("_NET_WM_DESKTOP");
622 xevent.xclient.format = 32;
623 xevent.xclient.data.l[0] = new_desktop;
624 xevent.xclient.data.l[1] = 0;
625 xevent.xclient.data.l[2] = 0;
626 xevent.xclient.data.l[3] = 0;
627 xevent.xclient.data.l[4] = 0;
628 XSendEvent(xdisplay_, x_root_window_, False,
629 SubstructureRedirectMask | SubstructureNotifyMask,
630 &xevent);
633 bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) {
634 if (window_title_ == title)
635 return false;
636 window_title_ = title;
637 std::string utf8str = base::UTF16ToUTF8(title);
638 XChangeProperty(xdisplay_,
639 xwindow_,
640 atom_cache_.GetAtom("_NET_WM_NAME"),
641 atom_cache_.GetAtom("UTF8_STRING"),
643 PropModeReplace,
644 reinterpret_cast<const unsigned char*>(utf8str.c_str()),
645 utf8str.size());
646 XTextProperty xtp;
647 char *c_utf8_str = const_cast<char *>(utf8str.c_str());
648 if (Xutf8TextListToTextProperty(xdisplay_, &c_utf8_str, 1,
649 XUTF8StringStyle, &xtp) == Success) {
650 XSetWMName(xdisplay_, xwindow_, &xtp);
651 XFree(xtp.value);
653 return true;
656 void DesktopWindowTreeHostX11::ClearNativeFocus() {
657 // This method is weird and misnamed. Instead of clearing the native focus,
658 // it sets the focus to our |content_window_|, which will trigger a cascade
659 // of focus changes into views.
660 if (content_window_ && aura::client::GetFocusClient(content_window_) &&
661 content_window_->Contains(
662 aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) {
663 aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
667 Widget::MoveLoopResult DesktopWindowTreeHostX11::RunMoveLoop(
668 const gfx::Vector2d& drag_offset,
669 Widget::MoveLoopSource source,
670 Widget::MoveLoopEscapeBehavior escape_behavior) {
671 aura::client::WindowMoveSource window_move_source =
672 source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
673 aura::client::WINDOW_MOVE_SOURCE_MOUSE :
674 aura::client::WINDOW_MOVE_SOURCE_TOUCH;
675 if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
676 window_move_source) == aura::client::MOVE_SUCCESSFUL)
677 return Widget::MOVE_LOOP_SUCCESSFUL;
679 return Widget::MOVE_LOOP_CANCELED;
682 void DesktopWindowTreeHostX11::EndMoveLoop() {
683 x11_window_move_client_->EndMoveLoop();
686 void DesktopWindowTreeHostX11::SetVisibilityChangedAnimationsEnabled(
687 bool value) {
688 // Much like the previous NativeWidgetGtk, we don't have anything to do here.
691 bool DesktopWindowTreeHostX11::ShouldUseNativeFrame() const {
692 return use_native_frame_;
695 bool DesktopWindowTreeHostX11::ShouldWindowContentsBeTransparent() const {
696 return false;
699 void DesktopWindowTreeHostX11::FrameTypeChanged() {
700 Widget::FrameType new_type =
701 native_widget_delegate_->AsWidget()->frame_type();
702 if (new_type == Widget::FRAME_TYPE_DEFAULT) {
703 // The default is determined by Widget::InitParams::remove_standard_frame
704 // and does not change.
705 return;
708 SetUseNativeFrame(new_type == Widget::FRAME_TYPE_FORCE_NATIVE);
709 // Replace the frame and layout the contents. Even though we don't have a
710 // swapable glass frame like on Windows, we still replace the frame because
711 // the button assets don't update otherwise.
712 native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame();
715 void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen) {
716 if (is_fullscreen_ == fullscreen)
717 return;
718 is_fullscreen_ = fullscreen;
719 if (is_fullscreen_)
720 delayed_resize_task_.Cancel();
722 // Work around a bug where if we try to unfullscreen, metacity immediately
723 // fullscreens us again. This is a little flickery and not necessary if
724 // there's a gnome-panel, but it's not easy to detect whether there's a
725 // panel or not.
726 bool unmaximize_and_remaximize = !fullscreen && IsMaximized() &&
727 ui::GuessWindowManager() == ui::WM_METACITY;
729 if (unmaximize_and_remaximize)
730 Restore();
731 SetWMSpecState(fullscreen,
732 atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
733 None);
734 if (unmaximize_and_remaximize)
735 Maximize();
737 // Try to guess the size we will have after the switch to/from fullscreen:
738 // - (may) avoid transient states
739 // - works around Flash content which expects to have the size updated
740 // synchronously.
741 // See https://crbug.com/361408
742 if (fullscreen) {
743 restored_bounds_in_pixels_ = bounds_in_pixels_;
744 const gfx::Display display =
745 gfx::Screen::GetScreenFor(NULL)->GetDisplayNearestWindow(window());
746 bounds_in_pixels_ = ToPixelRect(display.bounds());
747 } else {
748 bounds_in_pixels_ = restored_bounds_in_pixels_;
750 OnHostMoved(bounds_in_pixels_.origin());
751 OnHostResized(bounds_in_pixels_.size());
753 if (HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN") == fullscreen) {
754 Relayout();
755 ResetWindowRegion();
757 // Else: the widget will be relaid out either when the window bounds change or
758 // when |xwindow_|'s fullscreen state changes.
761 bool DesktopWindowTreeHostX11::IsFullscreen() const {
762 return is_fullscreen_;
765 void DesktopWindowTreeHostX11::SetOpacity(unsigned char opacity) {
766 // X server opacity is in terms of 32 bit unsigned int space, and counts from
767 // the opposite direction.
768 // XChangeProperty() expects "cardinality" to be long.
769 unsigned long cardinality = opacity * 0x1010101;
771 if (cardinality == 0xffffffff) {
772 XDeleteProperty(xdisplay_, xwindow_,
773 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
774 } else {
775 XChangeProperty(xdisplay_, xwindow_,
776 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
777 XA_CARDINAL, 32,
778 PropModeReplace,
779 reinterpret_cast<unsigned char*>(&cardinality), 1);
783 void DesktopWindowTreeHostX11::SetWindowIcons(
784 const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
785 // TODO(erg): The way we handle icons across different versions of chrome
786 // could be substantially improved. The Windows version does its own thing
787 // and only sometimes comes down this code path. The icon stuff in
788 // ChromeViewsDelegate is hard coded to use HICONs. Likewise, we're hard
789 // coded to be given two images instead of an arbitrary collection of images
790 // so that we can pass to the WM.
792 // All of this could be made much, much better.
793 std::vector<unsigned long> data;
795 if (window_icon.HasRepresentation(1.0f))
796 SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data);
798 if (app_icon.HasRepresentation(1.0f))
799 SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data);
801 if (data.empty())
802 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_ICON"));
803 else
804 ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data);
807 void DesktopWindowTreeHostX11::InitModalType(ui::ModalType modal_type) {
808 switch (modal_type) {
809 case ui::MODAL_TYPE_NONE:
810 break;
811 default:
812 // TODO(erg): Figure out under what situations |modal_type| isn't
813 // none. The comment in desktop_native_widget_aura.cc suggests that this
814 // is rare.
815 NOTIMPLEMENTED();
819 void DesktopWindowTreeHostX11::FlashFrame(bool flash_frame) {
820 if (urgency_hint_set_ == flash_frame)
821 return;
823 gfx::XScopedPtr<XWMHints> hints(XGetWMHints(xdisplay_, xwindow_));
824 if (!hints) {
825 // The window hasn't had its hints set yet.
826 hints.reset(XAllocWMHints());
829 if (flash_frame)
830 hints->flags |= XUrgencyHint;
831 else
832 hints->flags &= ~XUrgencyHint;
834 XSetWMHints(xdisplay_, xwindow_, hints.get());
836 urgency_hint_set_ = flash_frame;
839 void DesktopWindowTreeHostX11::OnRootViewLayout() {
840 UpdateMinAndMaxSize();
843 void DesktopWindowTreeHostX11::OnNativeWidgetFocus() {
844 native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
847 void DesktopWindowTreeHostX11::OnNativeWidgetBlur() {
848 if (xwindow_)
849 native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
852 bool DesktopWindowTreeHostX11::IsAnimatingClosed() const {
853 return false;
856 bool DesktopWindowTreeHostX11::IsTranslucentWindowOpacitySupported() const {
857 return false;
860 void DesktopWindowTreeHostX11::SizeConstraintsChanged() {
861 UpdateMinAndMaxSize();
864 ////////////////////////////////////////////////////////////////////////////////
865 // DesktopWindowTreeHostX11, aura::WindowTreeHost implementation:
867 gfx::Transform DesktopWindowTreeHostX11::GetRootTransform() const {
868 gfx::Display display = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay();
869 if (window_mapped_) {
870 aura::Window* win = const_cast<aura::Window*>(window());
871 display = gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(win);
874 float scale = display.device_scale_factor();
875 gfx::Transform transform;
876 transform.Scale(scale, scale);
877 return transform;
880 ui::EventSource* DesktopWindowTreeHostX11::GetEventSource() {
881 return this;
884 gfx::AcceleratedWidget DesktopWindowTreeHostX11::GetAcceleratedWidget() {
885 return xwindow_;
888 void DesktopWindowTreeHostX11::Show() {
889 ShowWindowWithState(ui::SHOW_STATE_NORMAL);
890 native_widget_delegate_->OnNativeWidgetVisibilityChanged(true);
893 void DesktopWindowTreeHostX11::Hide() {
894 if (window_mapped_) {
895 XWithdrawWindow(xdisplay_, xwindow_, 0);
896 window_mapped_ = false;
898 native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
901 gfx::Rect DesktopWindowTreeHostX11::GetBounds() const {
902 return bounds_in_pixels_;
905 void DesktopWindowTreeHostX11::SetBounds(
906 const gfx::Rect& requested_bounds_in_pixel) {
907 gfx::Rect bounds_in_pixels(requested_bounds_in_pixel.origin(),
908 AdjustSize(requested_bounds_in_pixel.size()));
909 bool origin_changed = bounds_in_pixels_.origin() != bounds_in_pixels.origin();
910 bool size_changed = bounds_in_pixels_.size() != bounds_in_pixels.size();
911 XWindowChanges changes = {0};
912 unsigned value_mask = 0;
914 if (size_changed) {
915 if (bounds_in_pixels.width() < min_size_in_pixels_.width() ||
916 bounds_in_pixels.height() < min_size_in_pixels_.height() ||
917 (!max_size_in_pixels_.IsEmpty() &&
918 (bounds_in_pixels.width() > max_size_in_pixels_.width() ||
919 bounds_in_pixels.height() > max_size_in_pixels_.height()))) {
920 // Update the minimum and maximum sizes in case they have changed.
921 UpdateMinAndMaxSize();
923 gfx::Size size_in_pixels = bounds_in_pixels.size();
924 size_in_pixels.SetToMin(max_size_in_pixels_);
925 size_in_pixels.SetToMax(min_size_in_pixels_);
926 bounds_in_pixels.set_size(size_in_pixels);
929 changes.width = bounds_in_pixels.width();
930 changes.height = bounds_in_pixels.height();
931 value_mask |= CWHeight | CWWidth;
934 if (origin_changed) {
935 changes.x = bounds_in_pixels.x();
936 changes.y = bounds_in_pixels.y();
937 value_mask |= CWX | CWY;
939 if (value_mask)
940 XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
942 // Assume that the resize will go through as requested, which should be the
943 // case if we're running without a window manager. If there's a window
944 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
945 // (possibly synthetic) ConfigureNotify about the actual size and correct
946 // |bounds_in_pixels_| later.
947 bounds_in_pixels_ = bounds_in_pixels;
949 if (origin_changed)
950 native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
951 if (size_changed) {
952 OnHostResized(bounds_in_pixels.size());
953 ResetWindowRegion();
957 gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const {
958 return bounds_in_pixels_.origin();
961 void DesktopWindowTreeHostX11::SetCapture() {
962 if (HasCapture())
963 return;
965 // Grabbing the mouse is asynchronous. However, we synchronously start
966 // forwarding all mouse events received by Chrome to the
967 // aura::WindowEventDispatcher which has capture. This makes capture
968 // synchronous for all intents and purposes if either:
969 // - |g_current_capture|'s X window has capture.
970 // OR
971 // - The topmost window underneath the mouse is managed by Chrome.
972 DesktopWindowTreeHostX11* old_capturer = g_current_capture;
974 // Update |g_current_capture| prior to calling OnHostLostWindowCapture() to
975 // avoid releasing pointer grab.
976 g_current_capture = this;
977 if (old_capturer)
978 old_capturer->OnHostLostWindowCapture();
980 GrabPointer(xwindow_, true, None);
983 void DesktopWindowTreeHostX11::ReleaseCapture() {
984 if (g_current_capture == this) {
985 // Release mouse grab asynchronously. A window managed by Chrome is likely
986 // the topmost window underneath the mouse so the capture release being
987 // asynchronous is likely inconsequential.
988 g_current_capture = NULL;
989 UngrabPointer();
991 OnHostLostWindowCapture();
995 void DesktopWindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) {
996 XDefineCursor(xdisplay_, xwindow_, cursor.platform());
999 void DesktopWindowTreeHostX11::MoveCursorToNative(const gfx::Point& location) {
1000 XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
1001 bounds_in_pixels_.x() + location.x(),
1002 bounds_in_pixels_.y() + location.y());
1005 void DesktopWindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
1006 // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
1007 // the same tap-to-click disabling here that chromeos does.
1010 ////////////////////////////////////////////////////////////////////////////////
1011 // DesktopWindowTreeHostX11, ui::EventSource implementation:
1013 ui::EventProcessor* DesktopWindowTreeHostX11::GetEventProcessor() {
1014 return dispatcher();
1017 ////////////////////////////////////////////////////////////////////////////////
1018 // DesktopWindowTreeHostX11, private:
1020 void DesktopWindowTreeHostX11::InitX11Window(
1021 const Widget::InitParams& params) {
1022 unsigned long attribute_mask = CWBackPixmap;
1023 XSetWindowAttributes swa;
1024 memset(&swa, 0, sizeof(swa));
1025 swa.background_pixmap = None;
1027 ::Atom window_type;
1028 switch (params.type) {
1029 case Widget::InitParams::TYPE_MENU:
1030 swa.override_redirect = True;
1031 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
1032 break;
1033 case Widget::InitParams::TYPE_TOOLTIP:
1034 swa.override_redirect = True;
1035 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
1036 break;
1037 case Widget::InitParams::TYPE_POPUP:
1038 swa.override_redirect = True;
1039 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION");
1040 break;
1041 case Widget::InitParams::TYPE_DRAG:
1042 swa.override_redirect = True;
1043 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_DND");
1044 break;
1045 default:
1046 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
1047 break;
1049 if (swa.override_redirect)
1050 attribute_mask |= CWOverrideRedirect;
1052 // Detect whether we're running inside a compositing manager. If so, try to
1053 // use the ARGB visual. Otherwise, just use our parent's visual.
1054 Visual* visual = CopyFromParent;
1055 int depth = CopyFromParent;
1056 if (base::CommandLine::ForCurrentProcess()->HasSwitch(
1057 switches::kEnableTransparentVisuals) &&
1058 XGetSelectionOwner(xdisplay_, atom_cache_.GetAtom("_NET_WM_CM_S0")) !=
1059 None) {
1060 Visual* rgba_visual = GetARGBVisual();
1061 if (rgba_visual) {
1062 visual = rgba_visual;
1063 depth = 32;
1065 attribute_mask |= CWColormap;
1066 swa.colormap = XCreateColormap(xdisplay_, x_root_window_, visual,
1067 AllocNone);
1069 // x.org will BadMatch if we don't set a border when the depth isn't the
1070 // same as the parent depth.
1071 attribute_mask |= CWBorderPixel;
1072 swa.border_pixel = 0;
1074 use_argb_visual_ = true;
1078 bounds_in_pixels_ = ToPixelRect(params.bounds);
1079 bounds_in_pixels_.set_size(AdjustSize(bounds_in_pixels_.size()));
1080 xwindow_ = XCreateWindow(xdisplay_, x_root_window_, bounds_in_pixels_.x(),
1081 bounds_in_pixels_.y(), bounds_in_pixels_.width(),
1082 bounds_in_pixels_.height(),
1083 0, // border width
1084 depth, InputOutput, visual, attribute_mask, &swa);
1085 if (ui::PlatformEventSource::GetInstance())
1086 ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
1087 open_windows().push_back(xwindow_);
1089 // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
1091 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
1092 KeyPressMask | KeyReleaseMask |
1093 EnterWindowMask | LeaveWindowMask |
1094 ExposureMask | VisibilityChangeMask |
1095 StructureNotifyMask | PropertyChangeMask |
1096 PointerMotionMask;
1097 XSelectInput(xdisplay_, xwindow_, event_mask);
1098 XFlush(xdisplay_);
1100 if (ui::IsXInput2Available())
1101 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
1103 // TODO(erg): We currently only request window deletion events. We also
1104 // should listen for activation events and anything else that GTK+ listens
1105 // for, and do something useful.
1106 ::Atom protocols[2];
1107 protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
1108 protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
1109 XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
1111 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
1112 // the desktop environment.
1113 XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
1115 // Likewise, the X server needs to know this window's pid so it knows which
1116 // program to kill if the window hangs.
1117 // XChangeProperty() expects "pid" to be long.
1118 static_assert(sizeof(long) >= sizeof(pid_t),
1119 "pid_t should not be larger than long");
1120 long pid = getpid();
1121 XChangeProperty(xdisplay_,
1122 xwindow_,
1123 atom_cache_.GetAtom("_NET_WM_PID"),
1124 XA_CARDINAL,
1126 PropModeReplace,
1127 reinterpret_cast<unsigned char*>(&pid), 1);
1129 XChangeProperty(xdisplay_,
1130 xwindow_,
1131 atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
1132 XA_ATOM,
1134 PropModeReplace,
1135 reinterpret_cast<unsigned char*>(&window_type), 1);
1137 // List of window state properties (_NET_WM_STATE) to set, if any.
1138 std::vector< ::Atom> state_atom_list;
1140 // Remove popup windows from taskbar unless overridden.
1141 if ((params.type == Widget::InitParams::TYPE_POPUP ||
1142 params.type == Widget::InitParams::TYPE_BUBBLE) &&
1143 !params.force_show_in_taskbar) {
1144 state_atom_list.push_back(
1145 atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
1148 // If the window should stay on top of other windows, add the
1149 // _NET_WM_STATE_ABOVE property.
1150 is_always_on_top_ = params.keep_on_top;
1151 if (is_always_on_top_)
1152 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
1154 if (params.visible_on_all_workspaces) {
1155 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_STICKY"));
1156 ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllDesktops);
1159 // Setting _NET_WM_STATE by sending a message to the root_window (with
1160 // SetWMSpecState) has no effect here since the window has not yet been
1161 // mapped. So we manually change the state.
1162 if (!state_atom_list.empty()) {
1163 ui::SetAtomArrayProperty(xwindow_,
1164 "_NET_WM_STATE",
1165 "ATOM",
1166 state_atom_list);
1169 if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
1170 ui::SetWindowClassHint(
1171 xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
1174 const char* wm_role_name = NULL;
1175 // If the widget isn't overriding the role, provide a default value for popup
1176 // and bubble types.
1177 if (!params.wm_role_name.empty()) {
1178 wm_role_name = params.wm_role_name.c_str();
1179 } else {
1180 switch (params.type) {
1181 case Widget::InitParams::TYPE_POPUP:
1182 wm_role_name = kX11WindowRolePopup;
1183 break;
1184 case Widget::InitParams::TYPE_BUBBLE:
1185 wm_role_name = kX11WindowRoleBubble;
1186 break;
1187 default:
1188 break;
1191 if (wm_role_name)
1192 ui::SetWindowRole(xdisplay_, xwindow_, std::string(wm_role_name));
1194 if (params.remove_standard_frame) {
1195 // Setting _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED tells gnome-shell to not force
1196 // fullscreen on the window when it matches the desktop size.
1197 ui::SetHideTitlebarWhenMaximizedProperty(xwindow_,
1198 ui::HIDE_TITLEBAR_WHEN_MAXIMIZED);
1201 // If we have a parent, record the parent/child relationship. We use this
1202 // data during destruction to make sure that when we try to close a parent
1203 // window, we also destroy all child windows.
1204 if (params.parent && params.parent->GetHost()) {
1205 XID parent_xid =
1206 params.parent->GetHost()->GetAcceleratedWidget();
1207 window_parent_ = GetHostForXID(parent_xid);
1208 DCHECK(window_parent_);
1209 window_parent_->window_children_.insert(this);
1212 // If we have a delegate which is providing a default window icon, use that
1213 // icon.
1214 gfx::ImageSkia* window_icon = ViewsDelegate::views_delegate ?
1215 ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL;
1216 if (window_icon) {
1217 SetWindowIcons(gfx::ImageSkia(), *window_icon);
1219 CreateCompositor(GetAcceleratedWidget());
1222 gfx::Size DesktopWindowTreeHostX11::AdjustSize(
1223 const gfx::Size& requested_size_in_pixels) {
1224 std::vector<gfx::Display> displays =
1225 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE)->GetAllDisplays();
1226 // Compare against all monitor sizes. The window manager can move the window
1227 // to whichever monitor it wants.
1228 for (size_t i = 0; i < displays.size(); ++i) {
1229 if (requested_size_in_pixels == displays[i].GetSizeInPixel()) {
1230 return gfx::Size(requested_size_in_pixels.width() - 1,
1231 requested_size_in_pixels.height() - 1);
1235 // Do not request a 0x0 window size. It causes an XError.
1236 gfx::Size size_in_pixels = requested_size_in_pixels;
1237 size_in_pixels.SetToMax(gfx::Size(1, 1));
1238 return size_in_pixels;
1241 void DesktopWindowTreeHostX11::OnWMStateUpdated() {
1242 std::vector< ::Atom> atom_list;
1243 // Ignore the return value of ui::GetAtomArrayProperty(). Fluxbox removes the
1244 // _NET_WM_STATE property when no _NET_WM_STATE atoms are set.
1245 ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list);
1247 bool was_minimized = IsMinimized();
1249 window_properties_.clear();
1250 std::copy(atom_list.begin(), atom_list.end(),
1251 inserter(window_properties_, window_properties_.begin()));
1253 // Propagate the window minimization information to the content window, so
1254 // the render side can update its visibility properly. OnWMStateUpdated() is
1255 // called by PropertyNofify event from DispatchEvent() when the browser is
1256 // minimized or shown from minimized state. On Windows, this is realized by
1257 // calling OnHostResized() with an empty size. In particular,
1258 // HWNDMessageHandler::GetClientAreaBounds() returns an empty size when the
1259 // window is minimized. On Linux, returning empty size in GetBounds() or
1260 // SetBounds() does not work.
1261 // We also propagate the minimization to the compositor, to makes sure that we
1262 // don't draw any 'blank' frames that could be noticed in applications such as
1263 // window manager previews, which show content even when a window is
1264 // minimized.
1265 bool is_minimized = IsMinimized();
1266 if (is_minimized != was_minimized) {
1267 if (is_minimized) {
1268 compositor()->SetVisible(false);
1269 content_window_->Hide();
1270 } else {
1271 content_window_->Show();
1272 compositor()->SetVisible(true);
1276 if (restored_bounds_in_pixels_.IsEmpty()) {
1277 DCHECK(!IsFullscreen());
1278 if (IsMaximized()) {
1279 // The request that we become maximized originated from a different
1280 // process. |bounds_in_pixels_| already contains our maximized bounds. Do
1281 // a best effort attempt to get restored bounds by setting it to our
1282 // previously set bounds (and if we get this wrong, we aren't any worse
1283 // off since we'd otherwise be returning our maximized bounds).
1284 restored_bounds_in_pixels_ = previous_bounds_in_pixels_;
1286 } else if (!IsMaximized() && !IsFullscreen()) {
1287 // If we have restored bounds, but WM_STATE no longer claims to be
1288 // maximized or fullscreen, we should clear our restored bounds.
1289 restored_bounds_in_pixels_ = gfx::Rect();
1292 // Ignore requests by the window manager to enter or exit fullscreen (e.g. as
1293 // a result of pressing a window manager accelerator key). Chrome does not
1294 // handle window manager initiated fullscreen. In particular, Chrome needs to
1295 // do preprocessing before the x window's fullscreen state is toggled.
1297 is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE");
1299 // Now that we have different window properties, we may need to relayout the
1300 // window. (The windows code doesn't need this because their window change is
1301 // synchronous.)
1302 Relayout();
1303 ResetWindowRegion();
1306 void DesktopWindowTreeHostX11::OnFrameExtentsUpdated() {
1307 std::vector<int> insets;
1308 if (ui::GetIntArrayProperty(xwindow_, "_NET_FRAME_EXTENTS", &insets) &&
1309 insets.size() == 4) {
1310 // |insets| are returned in the order: [left, right, top, bottom].
1311 native_window_frame_borders_in_pixels_ =
1312 gfx::Insets(insets[2], insets[0], insets[3], insets[1]);
1313 } else {
1314 native_window_frame_borders_in_pixels_ = gfx::Insets();
1318 void DesktopWindowTreeHostX11::UpdateMinAndMaxSize() {
1319 if (!window_mapped_)
1320 return;
1322 gfx::Size minimum_in_pixels =
1323 ToPixelRect(gfx::Rect(native_widget_delegate_->GetMinimumSize())).size();
1324 gfx::Size maximum_in_pixels =
1325 ToPixelRect(gfx::Rect(native_widget_delegate_->GetMaximumSize())).size();
1326 if (min_size_in_pixels_ == minimum_in_pixels &&
1327 max_size_in_pixels_ == maximum_in_pixels)
1328 return;
1330 min_size_in_pixels_ = minimum_in_pixels;
1331 max_size_in_pixels_ = maximum_in_pixels;
1333 XSizeHints hints;
1334 long supplied_return;
1335 XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return);
1337 if (minimum_in_pixels.IsEmpty()) {
1338 hints.flags &= ~PMinSize;
1339 } else {
1340 hints.flags |= PMinSize;
1341 hints.min_width = min_size_in_pixels_.width();
1342 hints.min_height = min_size_in_pixels_.height();
1345 if (maximum_in_pixels.IsEmpty()) {
1346 hints.flags &= ~PMaxSize;
1347 } else {
1348 hints.flags |= PMaxSize;
1349 hints.max_width = max_size_in_pixels_.width();
1350 hints.max_height = max_size_in_pixels_.height();
1353 XSetWMNormalHints(xdisplay_, xwindow_, &hints);
1356 void DesktopWindowTreeHostX11::UpdateWMUserTime(
1357 const ui::PlatformEvent& event) {
1358 if (!IsActive())
1359 return;
1361 ui::EventType type = ui::EventTypeFromNative(event);
1362 if (type == ui::ET_MOUSE_PRESSED ||
1363 type == ui::ET_KEY_PRESSED ||
1364 type == ui::ET_TOUCH_PRESSED) {
1365 unsigned long wm_user_time_ms = static_cast<unsigned long>(
1366 ui::EventTimeFromNative(event).InMilliseconds());
1367 XChangeProperty(xdisplay_,
1368 xwindow_,
1369 atom_cache_.GetAtom("_NET_WM_USER_TIME"),
1370 XA_CARDINAL,
1372 PropModeReplace,
1373 reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
1375 X11DesktopHandler::get()->set_wm_user_time_ms(wm_user_time_ms);
1379 void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled,
1380 ::Atom state1,
1381 ::Atom state2) {
1382 XEvent xclient;
1383 memset(&xclient, 0, sizeof(xclient));
1384 xclient.type = ClientMessage;
1385 xclient.xclient.window = xwindow_;
1386 xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
1387 xclient.xclient.format = 32;
1388 xclient.xclient.data.l[0] =
1389 enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
1390 xclient.xclient.data.l[1] = state1;
1391 xclient.xclient.data.l[2] = state2;
1392 xclient.xclient.data.l[3] = 1;
1393 xclient.xclient.data.l[4] = 0;
1395 XSendEvent(xdisplay_, x_root_window_, False,
1396 SubstructureRedirectMask | SubstructureNotifyMask,
1397 &xclient);
1400 bool DesktopWindowTreeHostX11::HasWMSpecProperty(const char* property) const {
1401 return window_properties_.find(atom_cache_.GetAtom(property)) !=
1402 window_properties_.end();
1405 void DesktopWindowTreeHostX11::SetUseNativeFrame(bool use_native_frame) {
1406 use_native_frame_ = use_native_frame;
1407 ui::SetUseOSWindowFrame(xwindow_, use_native_frame);
1408 ResetWindowRegion();
1411 void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
1412 // In Windows, the native events sent to chrome are separated into client
1413 // and non-client versions of events, which we record on our LocatedEvent
1414 // structures. On X11, we emulate the concept of non-client. Before we pass
1415 // this event to the cross platform event handling framework, we need to
1416 // make sure it is appropriately marked as non-client if it's in the non
1417 // client area, or otherwise, we can get into a state where the a window is
1418 // set as the |mouse_pressed_handler_| in window_event_dispatcher.cc
1419 // despite the mouse button being released.
1421 // We can't do this later in the dispatch process because we share that
1422 // with ash, and ash gets confused about event IS_NON_CLIENT-ness on
1423 // events, since ash doesn't expect this bit to be set, because it's never
1424 // been set before. (This works on ash on Windows because none of the mouse
1425 // events on the ash desktop are clicking in what Windows considers to be a
1426 // non client area.) Likewise, we won't want to do the following in any
1427 // WindowTreeHost that hosts ash.
1428 if (content_window_ && content_window_->delegate()) {
1429 int flags = event->flags();
1430 int hit_test_code =
1431 content_window_->delegate()->GetNonClientComponent(event->location());
1432 if (hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE)
1433 flags |= ui::EF_IS_NON_CLIENT;
1434 event->set_flags(flags);
1437 // While we unset the urgency hint when we gain focus, we also must remove it
1438 // on mouse clicks because we can call FlashFrame() on an active window.
1439 if (event->IsAnyButton() || event->IsMouseWheelEvent())
1440 FlashFrame(false);
1442 if (!g_current_capture || g_current_capture == this) {
1443 SendEventToProcessor(event);
1444 } else {
1445 // Another DesktopWindowTreeHostX11 has installed itself as
1446 // capture. Translate the event's location and dispatch to the other.
1447 ConvertEventToDifferentHost(event, g_current_capture);
1448 g_current_capture->SendEventToProcessor(event);
1452 void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) {
1453 if (g_current_capture && g_current_capture != this &&
1454 event->type() == ui::ET_TOUCH_PRESSED) {
1455 ConvertEventToDifferentHost(event, g_current_capture);
1456 g_current_capture->SendEventToProcessor(event);
1457 } else {
1458 SendEventToProcessor(event);
1462 void DesktopWindowTreeHostX11::ConvertEventToDifferentHost(
1463 ui::LocatedEvent* located_event,
1464 DesktopWindowTreeHostX11* host) {
1465 DCHECK_NE(this, host);
1466 const gfx::Display display_src =
1467 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(window());
1468 const gfx::Display display_dest =
1469 gfx::Screen::GetNativeScreen()->GetDisplayNearestWindow(host->window());
1470 DCHECK_EQ(display_src.device_scale_factor(),
1471 display_dest.device_scale_factor());
1472 gfx::Vector2d offset = GetLocationOnNativeScreen() -
1473 host->GetLocationOnNativeScreen();
1474 gfx::Point location_in_pixel_in_host = located_event->location() + offset;
1475 located_event->set_location(location_in_pixel_in_host);
1478 void DesktopWindowTreeHostX11::ResetWindowRegion() {
1479 // If a custom window shape was supplied then apply it.
1480 if (custom_window_shape_) {
1481 XShapeCombineRegion(
1482 xdisplay_, xwindow_, ShapeBounding, 0, 0, window_shape_, false);
1483 return;
1486 if (window_shape_)
1487 XDestroyRegion(window_shape_);
1488 window_shape_ = NULL;
1490 if (!IsMaximized() && !IsFullscreen()) {
1491 gfx::Path window_mask;
1492 views::Widget* widget = native_widget_delegate_->AsWidget();
1493 if (widget->non_client_view()) {
1494 // Some frame views define a custom (non-rectangular) window mask. If
1495 // so, use it to define the window shape. If not, fall through.
1496 widget->non_client_view()->GetWindowMask(bounds_in_pixels_.size(),
1497 &window_mask);
1498 if (window_mask.countPoints() > 0) {
1499 window_shape_ = gfx::CreateRegionFromSkPath(window_mask);
1500 XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding,
1501 0, 0, window_shape_, false);
1502 return;
1507 // If we didn't set the shape for any reason, reset the shaping information.
1508 // How this is done depends on the border style, due to quirks and bugs in
1509 // various window managers.
1510 if (ShouldUseNativeFrame()) {
1511 // If the window has system borders, the mask must be set to null (not a
1512 // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will
1513 // not put borders on a window with a custom shape.
1514 XShapeCombineMask(xdisplay_, xwindow_, ShapeBounding, 0, 0, None, ShapeSet);
1515 } else {
1516 // Conversely, if the window does not have system borders, the mask must be
1517 // manually set to a rectangle that covers the whole window (not null). This
1518 // is due to a bug in KWin <= 4.11.5 (KDE bug #330573) where setting a null
1519 // shape causes the hint to disable system borders to be ignored (resulting
1520 // in a double border).
1521 XRectangle r = {0,
1523 static_cast<unsigned short>(bounds_in_pixels_.width()),
1524 static_cast<unsigned short>(bounds_in_pixels_.height())};
1525 XShapeCombineRectangles(
1526 xdisplay_, xwindow_, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded);
1530 void DesktopWindowTreeHostX11::SerializeImageRepresentation(
1531 const gfx::ImageSkiaRep& rep,
1532 std::vector<unsigned long>* data) {
1533 int width = rep.GetWidth();
1534 data->push_back(width);
1536 int height = rep.GetHeight();
1537 data->push_back(height);
1539 const SkBitmap& bitmap = rep.sk_bitmap();
1540 SkAutoLockPixels locker(bitmap);
1542 for (int y = 0; y < height; ++y)
1543 for (int x = 0; x < width; ++x)
1544 data->push_back(bitmap.getColor(x, y));
1547 Visual* DesktopWindowTreeHostX11::GetARGBVisual() {
1548 XVisualInfo visual_template;
1549 visual_template.screen = 0;
1551 int visuals_len;
1552 gfx::XScopedPtr<XVisualInfo[]> visual_list(XGetVisualInfo(
1553 xdisplay_, VisualScreenMask, &visual_template, &visuals_len));
1554 for (int i = 0; i < visuals_len; ++i) {
1555 // Why support only 8888 ARGB? Because it's all that GTK+ supports. In
1556 // gdkvisual-x11.cc, they look for this specific visual and use it for all
1557 // their alpha channel using needs.
1559 // TODO(erg): While the following does find a valid visual, some GL drivers
1560 // don't believe that this has an alpha channel. According to marcheu@,
1561 // this should work on open source driver though. (It doesn't work with
1562 // NVidia's binaries currently.) http://crbug.com/369209
1563 const XVisualInfo& info = visual_list[i];
1564 if (info.depth == 32 && info.visual->red_mask == 0xff0000 &&
1565 info.visual->green_mask == 0x00ff00 &&
1566 info.visual->blue_mask == 0x0000ff) {
1567 return info.visual;
1571 return nullptr;
1574 std::list<XID>& DesktopWindowTreeHostX11::open_windows() {
1575 if (!open_windows_)
1576 open_windows_ = new std::list<XID>();
1577 return *open_windows_;
1580 void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) {
1581 if (show_state != ui::SHOW_STATE_DEFAULT &&
1582 show_state != ui::SHOW_STATE_NORMAL &&
1583 show_state != ui::SHOW_STATE_INACTIVE &&
1584 show_state != ui::SHOW_STATE_MAXIMIZED) {
1585 // It will behave like SHOW_STATE_NORMAL.
1586 NOTIMPLEMENTED();
1589 // Before we map the window, set size hints. Otherwise, some window managers
1590 // will ignore toplevel XMoveWindow commands.
1591 XSizeHints size_hints;
1592 size_hints.flags = PPosition;
1593 size_hints.x = bounds_in_pixels_.x();
1594 size_hints.y = bounds_in_pixels_.y();
1595 XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
1597 // If SHOW_STATE_INACTIVE, tell the window manager not to focus the window
1598 // when mapping. This is done by setting the _NET_WM_USER_TIME to 0. See e.g.
1599 // http://standards.freedesktop.org/wm-spec/latest/ar01s05.html
1600 unsigned long wm_user_time_ms = (show_state == ui::SHOW_STATE_INACTIVE) ?
1601 0 : X11DesktopHandler::get()->wm_user_time_ms();
1602 if (show_state == ui::SHOW_STATE_INACTIVE || wm_user_time_ms != 0) {
1603 XChangeProperty(xdisplay_,
1604 xwindow_,
1605 atom_cache_.GetAtom("_NET_WM_USER_TIME"),
1606 XA_CARDINAL,
1608 PropModeReplace,
1609 reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
1613 XMapWindow(xdisplay_, xwindow_);
1615 // We now block until our window is mapped. Some X11 APIs will crash and
1616 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
1617 // asynchronous.
1618 if (ui::X11EventSource::GetInstance())
1619 ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_);
1620 window_mapped_ = true;
1622 // Some WMs only respect maximize hints after the window has been mapped.
1623 // Check whether we need to re-do a maximization.
1624 if (should_maximize_after_map_) {
1625 Maximize();
1626 should_maximize_after_map_ = false;
1630 void DesktopWindowTreeHostX11::SetWindowTransparency() {
1631 compositor()->SetHostHasTransparentBackground(use_argb_visual_);
1632 window()->SetTransparent(use_argb_visual_);
1633 content_window_->SetTransparent(use_argb_visual_);
1636 void DesktopWindowTreeHostX11::Relayout() {
1637 Widget* widget = native_widget_delegate_->AsWidget();
1638 NonClientView* non_client_view = widget->non_client_view();
1639 // non_client_view may be NULL, especially during creation.
1640 if (non_client_view) {
1641 non_client_view->client_view()->InvalidateLayout();
1642 non_client_view->InvalidateLayout();
1644 widget->GetRootView()->Layout();
1647 ////////////////////////////////////////////////////////////////////////////////
1648 // DesktopWindowTreeHostX11, ui::PlatformEventDispatcher implementation:
1650 bool DesktopWindowTreeHostX11::CanDispatchEvent(
1651 const ui::PlatformEvent& event) {
1652 return event->xany.window == xwindow_ ||
1653 (event->type == GenericEvent &&
1654 static_cast<XIDeviceEvent*>(event->xcookie.data)->event == xwindow_);
1657 uint32_t DesktopWindowTreeHostX11::DispatchEvent(
1658 const ui::PlatformEvent& event) {
1659 XEvent* xev = event;
1661 TRACE_EVENT1("views", "DesktopWindowTreeHostX11::Dispatch",
1662 "event->type", event->type);
1664 UpdateWMUserTime(event);
1666 // May want to factor CheckXEventForConsistency(xev); into a common location
1667 // since it is called here.
1668 switch (xev->type) {
1669 case EnterNotify:
1670 case LeaveNotify: {
1671 // Ignore EventNotify and LeaveNotify events from children of |xwindow_|.
1672 // NativeViewGLSurfaceGLX adds a child to |xwindow_|.
1673 // TODO(pkotwicz|tdanderson): Figure out whether the suppression is
1674 // necessary. crbug.com/385716
1675 if (xev->xcrossing.detail == NotifyInferior)
1676 break;
1678 ui::MouseEvent mouse_event(xev);
1679 DispatchMouseEvent(&mouse_event);
1680 break;
1682 case Expose: {
1683 gfx::Rect damage_rect_in_pixels(xev->xexpose.x, xev->xexpose.y,
1684 xev->xexpose.width, xev->xexpose.height);
1685 compositor()->ScheduleRedrawRect(damage_rect_in_pixels);
1686 break;
1688 case KeyPress: {
1689 ui::KeyEvent keydown_event(xev);
1690 SendEventToProcessor(&keydown_event);
1691 break;
1693 case KeyRelease: {
1694 // There is no way to deactivate a window in X11 so ignore input if
1695 // window is supposed to be 'inactive'. See comments in
1696 // X11DesktopHandler::DeactivateWindow() for more details.
1697 if (!IsActive() && !HasCapture())
1698 break;
1700 ui::KeyEvent key_event(xev);
1701 SendEventToProcessor(&key_event);
1702 break;
1704 case ButtonPress:
1705 case ButtonRelease: {
1706 ui::EventType event_type = ui::EventTypeFromNative(xev);
1707 switch (event_type) {
1708 case ui::ET_MOUSEWHEEL: {
1709 ui::MouseWheelEvent mouseev(xev);
1710 DispatchMouseEvent(&mouseev);
1711 break;
1713 case ui::ET_MOUSE_PRESSED:
1714 case ui::ET_MOUSE_RELEASED: {
1715 ui::MouseEvent mouseev(xev);
1716 DispatchMouseEvent(&mouseev);
1717 break;
1719 case ui::ET_UNKNOWN:
1720 // No event is created for X11-release events for mouse-wheel buttons.
1721 break;
1722 default:
1723 NOTREACHED() << event_type;
1725 break;
1727 case FocusOut:
1728 if (xev->xfocus.mode != NotifyGrab) {
1729 ReleaseCapture();
1730 OnHostLostWindowCapture();
1731 X11DesktopHandler::get()->ProcessXEvent(xev);
1732 } else {
1733 dispatcher()->OnHostLostMouseGrab();
1735 break;
1736 case FocusIn:
1737 X11DesktopHandler::get()->ProcessXEvent(xev);
1738 break;
1739 case ConfigureNotify: {
1740 DCHECK_EQ(xwindow_, xev->xconfigure.window);
1741 DCHECK_EQ(xwindow_, xev->xconfigure.event);
1742 // It's possible that the X window may be resized by some other means than
1743 // from within aura (e.g. the X window manager can change the size). Make
1744 // sure the root window size is maintained properly.
1745 int translated_x_in_pixels = xev->xconfigure.x;
1746 int translated_y_in_pixels = xev->xconfigure.y;
1747 if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
1748 Window unused;
1749 XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_, 0, 0,
1750 &translated_x_in_pixels, &translated_y_in_pixels,
1751 &unused);
1753 gfx::Rect bounds_in_pixels(translated_x_in_pixels, translated_y_in_pixels,
1754 xev->xconfigure.width, xev->xconfigure.height);
1755 bool size_changed = bounds_in_pixels_.size() != bounds_in_pixels.size();
1756 bool origin_changed =
1757 bounds_in_pixels_.origin() != bounds_in_pixels.origin();
1758 previous_bounds_in_pixels_ = bounds_in_pixels_;
1759 bounds_in_pixels_ = bounds_in_pixels;
1761 if (origin_changed)
1762 OnHostMoved(bounds_in_pixels_.origin());
1764 if (size_changed) {
1765 delayed_resize_task_.Reset(base::Bind(
1766 &DesktopWindowTreeHostX11::DelayedResize,
1767 close_widget_factory_.GetWeakPtr(), bounds_in_pixels.size()));
1768 base::MessageLoop::current()->PostTask(
1769 FROM_HERE, delayed_resize_task_.callback());
1771 break;
1773 case GenericEvent: {
1774 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
1775 if (!factory->ShouldProcessXI2Event(xev))
1776 break;
1778 ui::EventType type = ui::EventTypeFromNative(xev);
1779 XEvent last_event;
1780 int num_coalesced = 0;
1782 switch (type) {
1783 case ui::ET_TOUCH_MOVED:
1784 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1785 if (num_coalesced > 0)
1786 xev = &last_event;
1787 // fallthrough
1788 case ui::ET_TOUCH_PRESSED:
1789 case ui::ET_TOUCH_RELEASED: {
1790 ui::TouchEvent touchev(xev);
1791 DispatchTouchEvent(&touchev);
1792 break;
1794 case ui::ET_MOUSE_MOVED:
1795 case ui::ET_MOUSE_DRAGGED:
1796 case ui::ET_MOUSE_PRESSED:
1797 case ui::ET_MOUSE_RELEASED:
1798 case ui::ET_MOUSE_ENTERED:
1799 case ui::ET_MOUSE_EXITED: {
1800 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
1801 // If this is a motion event, we want to coalesce all pending motion
1802 // events that are at the top of the queue.
1803 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1804 if (num_coalesced > 0)
1805 xev = &last_event;
1807 ui::MouseEvent mouseev(xev);
1808 DispatchMouseEvent(&mouseev);
1809 break;
1811 case ui::ET_MOUSEWHEEL: {
1812 ui::MouseWheelEvent mouseev(xev);
1813 DispatchMouseEvent(&mouseev);
1814 break;
1816 case ui::ET_SCROLL_FLING_START:
1817 case ui::ET_SCROLL_FLING_CANCEL:
1818 case ui::ET_SCROLL: {
1819 ui::ScrollEvent scrollev(xev);
1820 SendEventToProcessor(&scrollev);
1821 break;
1823 case ui::ET_KEY_PRESSED:
1824 case ui::ET_KEY_RELEASED: {
1825 ui::KeyEvent key_event(xev);
1826 SendEventToProcessor(&key_event);
1827 break;
1829 case ui::ET_UNKNOWN:
1830 break;
1831 default:
1832 NOTREACHED();
1835 // If we coalesced an event we need to free its cookie.
1836 if (num_coalesced > 0)
1837 XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
1838 break;
1840 case MapNotify: {
1841 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1842 observer_list_,
1843 OnWindowMapped(xwindow_));
1844 break;
1846 case UnmapNotify: {
1847 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1848 observer_list_,
1849 OnWindowUnmapped(xwindow_));
1850 break;
1852 case ClientMessage: {
1853 Atom message_type = xev->xclient.message_type;
1854 if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
1855 Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
1856 if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
1857 // We have received a close message from the window manager.
1858 OnHostCloseRequested();
1859 } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
1860 XEvent reply_event = *xev;
1861 reply_event.xclient.window = x_root_window_;
1863 XSendEvent(xdisplay_,
1864 reply_event.xclient.window,
1865 False,
1866 SubstructureRedirectMask | SubstructureNotifyMask,
1867 &reply_event);
1869 } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
1870 drag_drop_client_->OnXdndEnter(xev->xclient);
1871 } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
1872 drag_drop_client_->OnXdndLeave(xev->xclient);
1873 } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
1874 drag_drop_client_->OnXdndPosition(xev->xclient);
1875 } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
1876 drag_drop_client_->OnXdndStatus(xev->xclient);
1877 } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
1878 drag_drop_client_->OnXdndFinished(xev->xclient);
1879 } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
1880 drag_drop_client_->OnXdndDrop(xev->xclient);
1882 break;
1884 case MappingNotify: {
1885 switch (xev->xmapping.request) {
1886 case MappingModifier:
1887 case MappingKeyboard:
1888 XRefreshKeyboardMapping(&xev->xmapping);
1889 break;
1890 case MappingPointer:
1891 ui::DeviceDataManagerX11::GetInstance()->UpdateButtonMap();
1892 break;
1893 default:
1894 NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
1895 break;
1897 break;
1899 case MotionNotify: {
1900 // Discard all but the most recent motion event that targets the same
1901 // window with unchanged state.
1902 XEvent last_event;
1903 while (XPending(xev->xany.display)) {
1904 XEvent next_event;
1905 XPeekEvent(xev->xany.display, &next_event);
1906 if (next_event.type == MotionNotify &&
1907 next_event.xmotion.window == xev->xmotion.window &&
1908 next_event.xmotion.subwindow == xev->xmotion.subwindow &&
1909 next_event.xmotion.state == xev->xmotion.state) {
1910 XNextEvent(xev->xany.display, &last_event);
1911 xev = &last_event;
1912 } else {
1913 break;
1917 ui::MouseEvent mouseev(xev);
1918 DispatchMouseEvent(&mouseev);
1919 break;
1921 case PropertyNotify: {
1922 ::Atom changed_atom = xev->xproperty.atom;
1923 if (changed_atom == atom_cache_.GetAtom("_NET_WM_STATE"))
1924 OnWMStateUpdated();
1925 else if (changed_atom == atom_cache_.GetAtom("_NET_FRAME_EXTENTS"))
1926 OnFrameExtentsUpdated();
1927 break;
1929 case SelectionNotify: {
1930 drag_drop_client_->OnSelectionNotify(xev->xselection);
1931 break;
1934 return ui::POST_DISPATCH_STOP_PROPAGATION;
1937 void DesktopWindowTreeHostX11::DelayedResize(const gfx::Size& size_in_pixels) {
1938 OnHostResized(size_in_pixels);
1939 ResetWindowRegion();
1940 delayed_resize_task_.Cancel();
1943 gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInPixels() const {
1944 std::vector<int> value;
1945 if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
1946 value.size() >= 4) {
1947 return gfx::Rect(value[0], value[1], value[2], value[3]);
1950 // Fetch the geometry of the root window.
1951 Window root;
1952 int x, y;
1953 unsigned int width, height;
1954 unsigned int border_width, depth;
1955 if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y, &width, &height,
1956 &border_width, &depth)) {
1957 NOTIMPLEMENTED();
1958 return gfx::Rect(0, 0, 10, 10);
1961 return gfx::Rect(x, y, width, height);
1964 gfx::Rect DesktopWindowTreeHostX11::ToDIPRect(
1965 const gfx::Rect& rect_in_pixels) const {
1966 gfx::RectF rect_in_dip = rect_in_pixels;
1967 GetRootTransform().TransformRectReverse(&rect_in_dip);
1968 return gfx::ToEnclosingRect(rect_in_dip);
1971 gfx::Rect DesktopWindowTreeHostX11::ToPixelRect(
1972 const gfx::Rect& rect_in_dip) const {
1973 gfx::RectF rect_in_pixels = rect_in_dip;
1974 GetRootTransform().TransformRect(&rect_in_pixels);
1975 return gfx::ToEnclosingRect(rect_in_pixels);
1978 ////////////////////////////////////////////////////////////////////////////////
1979 // DesktopWindowTreeHost, public:
1981 // static
1982 DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
1983 internal::NativeWidgetDelegate* native_widget_delegate,
1984 DesktopNativeWidgetAura* desktop_native_widget_aura) {
1985 return new DesktopWindowTreeHostX11(native_widget_delegate,
1986 desktop_native_widget_aura);
1989 // static
1990 ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) {
1991 const views::LinuxUI* linux_ui = views::LinuxUI::instance();
1992 if (linux_ui) {
1993 ui::NativeTheme* native_theme = linux_ui->GetNativeTheme(window);
1994 if (native_theme)
1995 return native_theme;
1998 return ui::NativeTheme::instance();
2001 } // namespace views