MacViews: Get c/b/ui/views/tabs to build on Mac
[chromium-blink-merge.git] / ui / views / widget / desktop_aura / desktop_window_tree_host_x11.cc
bloba6f120943f57de515556c227b84f04f8f253b208
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/debug/trace_event.h"
16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.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/event_utils.h"
28 #include "ui/events/platform/platform_event_source.h"
29 #include "ui/events/platform/x11/x11_event_source.h"
30 #include "ui/events/x/device_data_manager_x11.h"
31 #include "ui/events/x/device_list_cache_x.h"
32 #include "ui/events/x/touch_factory_x11.h"
33 #include "ui/gfx/display.h"
34 #include "ui/gfx/image/image_skia.h"
35 #include "ui/gfx/image/image_skia_rep.h"
36 #include "ui/gfx/insets.h"
37 #include "ui/gfx/path.h"
38 #include "ui/gfx/path_x11.h"
39 #include "ui/gfx/screen.h"
40 #include "ui/native_theme/native_theme.h"
41 #include "ui/views/corewm/tooltip_aura.h"
42 #include "ui/views/ime/input_method.h"
43 #include "ui/views/linux_ui/linux_ui.h"
44 #include "ui/views/views_delegate.h"
45 #include "ui/views/views_switches.h"
46 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
47 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
48 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
49 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_observer_x11.h"
50 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
51 #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
52 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
53 #include "ui/wm/core/compound_event_filter.h"
54 #include "ui/wm/core/window_util.h"
56 namespace views {
58 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::g_current_capture =
59 NULL;
60 std::list<XID>* DesktopWindowTreeHostX11::open_windows_ = NULL;
62 DEFINE_WINDOW_PROPERTY_KEY(
63 aura::Window*, kViewsWindowForRootWindow, NULL);
65 DEFINE_WINDOW_PROPERTY_KEY(
66 DesktopWindowTreeHostX11*, kHostForRootWindow, NULL);
68 namespace {
70 // Constants that are part of EWMH.
71 const int k_NET_WM_STATE_ADD = 1;
72 const int k_NET_WM_STATE_REMOVE = 0;
74 // Special value of the _NET_WM_DESKTOP property which indicates that the window
75 // should appear on all desktops.
76 const int kAllDesktops = 0xFFFFFFFF;
78 const char* kAtomsToCache[] = {
79 "UTF8_STRING",
80 "WM_DELETE_WINDOW",
81 "WM_PROTOCOLS",
82 "_NET_FRAME_EXTENTS",
83 "_NET_WM_CM_S0",
84 "_NET_WM_DESKTOP",
85 "_NET_WM_ICON",
86 "_NET_WM_NAME",
87 "_NET_WM_PID",
88 "_NET_WM_PING",
89 "_NET_WM_STATE",
90 "_NET_WM_STATE_ABOVE",
91 "_NET_WM_STATE_FULLSCREEN",
92 "_NET_WM_STATE_HIDDEN",
93 "_NET_WM_STATE_MAXIMIZED_HORZ",
94 "_NET_WM_STATE_MAXIMIZED_VERT",
95 "_NET_WM_STATE_SKIP_TASKBAR",
96 "_NET_WM_STATE_STICKY",
97 "_NET_WM_USER_TIME",
98 "_NET_WM_WINDOW_OPACITY",
99 "_NET_WM_WINDOW_TYPE",
100 "_NET_WM_WINDOW_TYPE_DND",
101 "_NET_WM_WINDOW_TYPE_MENU",
102 "_NET_WM_WINDOW_TYPE_NORMAL",
103 "_NET_WM_WINDOW_TYPE_NOTIFICATION",
104 "_NET_WM_WINDOW_TYPE_TOOLTIP",
105 "XdndActionAsk",
106 "XdndActionCopy"
107 "XdndActionLink",
108 "XdndActionList",
109 "XdndActionMove",
110 "XdndActionPrivate",
111 "XdndAware",
112 "XdndDrop",
113 "XdndEnter",
114 "XdndFinished",
115 "XdndLeave",
116 "XdndPosition",
117 "XdndProxy", // Proxy windows?
118 "XdndSelection",
119 "XdndStatus",
120 "XdndTypeList",
121 NULL
124 } // namespace
126 ////////////////////////////////////////////////////////////////////////////////
127 // DesktopWindowTreeHostX11, public:
129 DesktopWindowTreeHostX11::DesktopWindowTreeHostX11(
130 internal::NativeWidgetDelegate* native_widget_delegate,
131 DesktopNativeWidgetAura* desktop_native_widget_aura)
132 : xdisplay_(gfx::GetXDisplay()),
133 xwindow_(0),
134 x_root_window_(DefaultRootWindow(xdisplay_)),
135 atom_cache_(xdisplay_, kAtomsToCache),
136 window_mapped_(false),
137 is_fullscreen_(false),
138 is_always_on_top_(false),
139 use_native_frame_(false),
140 should_maximize_after_map_(false),
141 use_argb_visual_(false),
142 drag_drop_client_(NULL),
143 native_widget_delegate_(native_widget_delegate),
144 desktop_native_widget_aura_(desktop_native_widget_aura),
145 content_window_(NULL),
146 window_parent_(NULL),
147 window_shape_(NULL),
148 custom_window_shape_(false),
149 urgency_hint_set_(false),
150 close_widget_factory_(this) {
153 DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() {
154 window()->ClearProperty(kHostForRootWindow);
155 aura::client::SetWindowMoveClient(window(), NULL);
156 desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
157 if (window_shape_)
158 XDestroyRegion(window_shape_);
159 DestroyDispatcher();
162 // static
163 aura::Window* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid) {
164 aura::WindowTreeHost* host =
165 aura::WindowTreeHost::GetForAcceleratedWidget(xid);
166 return host ? host->window()->GetProperty(kViewsWindowForRootWindow) : NULL;
169 // static
170 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::GetHostForXID(XID xid) {
171 aura::WindowTreeHost* host =
172 aura::WindowTreeHost::GetForAcceleratedWidget(xid);
173 return host ? host->window()->GetProperty(kHostForRootWindow) : NULL;
176 // static
177 std::vector<aura::Window*> DesktopWindowTreeHostX11::GetAllOpenWindows() {
178 std::vector<aura::Window*> windows(open_windows().size());
179 std::transform(open_windows().begin(),
180 open_windows().end(),
181 windows.begin(),
182 GetContentWindowForXID);
183 return windows;
186 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowBounds() const {
187 return bounds_;
190 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowOuterBounds() const {
191 gfx::Rect outer_bounds(bounds_);
192 outer_bounds.Inset(-native_window_frame_borders_);
193 return outer_bounds;
196 ::Region DesktopWindowTreeHostX11::GetWindowShape() const {
197 return window_shape_;
200 void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged(
201 bool active) {
202 if (active) {
203 FlashFrame(false);
204 OnHostActivated();
205 open_windows().remove(xwindow_);
206 open_windows().insert(open_windows().begin(), xwindow_);
207 } else {
208 ReleaseCapture();
211 desktop_native_widget_aura_->HandleActivationChanged(active);
213 native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
216 void DesktopWindowTreeHostX11::AddObserver(
217 views::DesktopWindowTreeHostObserverX11* observer) {
218 observer_list_.AddObserver(observer);
221 void DesktopWindowTreeHostX11::RemoveObserver(
222 views::DesktopWindowTreeHostObserverX11* observer) {
223 observer_list_.RemoveObserver(observer);
226 void DesktopWindowTreeHostX11::SwapNonClientEventHandler(
227 scoped_ptr<ui::EventHandler> handler) {
228 wm::CompoundEventFilter* compound_event_filter =
229 desktop_native_widget_aura_->root_window_event_filter();
230 if (x11_non_client_event_filter_)
231 compound_event_filter->RemoveHandler(x11_non_client_event_filter_.get());
232 compound_event_filter->AddHandler(handler.get());
233 x11_non_client_event_filter_ = handler.Pass();
236 void DesktopWindowTreeHostX11::CleanUpWindowList() {
237 delete open_windows_;
238 open_windows_ = NULL;
241 ////////////////////////////////////////////////////////////////////////////////
242 // DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation:
244 void DesktopWindowTreeHostX11::Init(aura::Window* content_window,
245 const Widget::InitParams& params) {
246 content_window_ = content_window;
248 // TODO(erg): Check whether we *should* be building a WindowTreeHost here, or
249 // whether we should be proxying requests to another DRWHL.
251 // In some situations, views tries to make a zero sized window, and that
252 // makes us crash. Make sure we have valid sizes.
253 Widget::InitParams sanitized_params = params;
254 if (sanitized_params.bounds.width() == 0)
255 sanitized_params.bounds.set_width(100);
256 if (sanitized_params.bounds.height() == 0)
257 sanitized_params.bounds.set_height(100);
259 InitX11Window(sanitized_params);
262 void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
263 const Widget::InitParams& params) {
264 window()->SetProperty(kViewsWindowForRootWindow, content_window_);
265 window()->SetProperty(kHostForRootWindow, this);
267 // Ensure that the X11DesktopHandler exists so that it dispatches activation
268 // messages to us.
269 X11DesktopHandler::get();
271 // TODO(erg): Unify this code once the other consumer goes away.
272 SwapNonClientEventHandler(
273 scoped_ptr<ui::EventHandler>(new X11WindowEventFilter(this)).Pass());
274 SetUseNativeFrame(params.type == Widget::InitParams::TYPE_WINDOW &&
275 !params.remove_standard_frame);
277 x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
278 aura::client::SetWindowMoveClient(window(), x11_window_move_client_.get());
280 SetWindowTransparency();
282 native_widget_delegate_->OnNativeWidgetCreated(true);
285 scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostX11::CreateTooltip() {
286 return scoped_ptr<corewm::Tooltip>(
287 new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE));
290 scoped_ptr<aura::client::DragDropClient>
291 DesktopWindowTreeHostX11::CreateDragDropClient(
292 DesktopNativeCursorManager* cursor_manager) {
293 drag_drop_client_ = new DesktopDragDropClientAuraX11(
294 window(), cursor_manager, xdisplay_, xwindow_);
295 drag_drop_client_->Init();
296 return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
299 void DesktopWindowTreeHostX11::Close() {
300 // TODO(erg): Might need to do additional hiding tasks here.
301 delayed_resize_task_.Cancel();
303 if (!close_widget_factory_.HasWeakPtrs()) {
304 // And we delay the close so that if we are called from an ATL callback,
305 // we don't destroy the window before the callback returned (as the caller
306 // may delete ourselves on destroy and the ATL callback would still
307 // dereference us when the callback returns).
308 base::MessageLoop::current()->PostTask(
309 FROM_HERE,
310 base::Bind(&DesktopWindowTreeHostX11::CloseNow,
311 close_widget_factory_.GetWeakPtr()));
315 void DesktopWindowTreeHostX11::CloseNow() {
316 if (xwindow_ == None)
317 return;
319 ReleaseCapture();
320 native_widget_delegate_->OnNativeWidgetDestroying();
322 // If we have children, close them. Use a copy for iteration because they'll
323 // remove themselves.
324 std::set<DesktopWindowTreeHostX11*> window_children_copy = window_children_;
325 for (std::set<DesktopWindowTreeHostX11*>::iterator it =
326 window_children_copy.begin(); it != window_children_copy.end();
327 ++it) {
328 (*it)->CloseNow();
330 DCHECK(window_children_.empty());
332 // If we have a parent, remove ourselves from its children list.
333 if (window_parent_) {
334 window_parent_->window_children_.erase(this);
335 window_parent_ = NULL;
338 // Remove the event listeners we've installed. We need to remove these
339 // because otherwise we get assert during ~WindowEventDispatcher().
340 desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
341 x11_non_client_event_filter_.get());
342 x11_non_client_event_filter_.reset();
344 // Destroy the compositor before destroying the |xwindow_| since shutdown
345 // may try to swap, and the swap without a window causes an X error, which
346 // causes a crash with in-process renderer.
347 DestroyCompositor();
349 open_windows().remove(xwindow_);
350 // Actually free our native resources.
351 if (ui::PlatformEventSource::GetInstance())
352 ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
353 XDestroyWindow(xdisplay_, xwindow_);
354 xwindow_ = None;
356 desktop_native_widget_aura_->OnHostClosed();
359 aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() {
360 return this;
363 void DesktopWindowTreeHostX11::ShowWindowWithState(
364 ui::WindowShowState show_state) {
365 if (!window_mapped_)
366 MapWindow(show_state);
368 if (show_state == ui::SHOW_STATE_NORMAL ||
369 show_state == ui::SHOW_STATE_MAXIMIZED) {
370 Activate();
373 native_widget_delegate_->AsWidget()->SetInitialFocus(show_state);
376 void DesktopWindowTreeHostX11::ShowMaximizedWithBounds(
377 const gfx::Rect& restored_bounds) {
378 ShowWindowWithState(ui::SHOW_STATE_MAXIMIZED);
379 // Enforce |restored_bounds_| since calling Maximize() could have reset it.
380 restored_bounds_ = restored_bounds;
383 bool DesktopWindowTreeHostX11::IsVisible() const {
384 return window_mapped_;
387 void DesktopWindowTreeHostX11::SetSize(const gfx::Size& requested_size) {
388 gfx::Size size = AdjustSize(requested_size);
389 bool size_changed = bounds_.size() != size;
390 XResizeWindow(xdisplay_, xwindow_, size.width(), size.height());
391 bounds_.set_size(size);
392 if (size_changed) {
393 OnHostResized(size);
394 ResetWindowRegion();
398 void DesktopWindowTreeHostX11::StackAtTop() {
399 XRaiseWindow(xdisplay_, xwindow_);
402 void DesktopWindowTreeHostX11::CenterWindow(const gfx::Size& size) {
403 gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
405 // If |window_|'s transient parent bounds are big enough to contain |size|,
406 // use them instead.
407 if (wm::GetTransientParent(content_window_)) {
408 gfx::Rect transient_parent_rect =
409 wm::GetTransientParent(content_window_)->GetBoundsInScreen();
410 if (transient_parent_rect.height() >= size.height() &&
411 transient_parent_rect.width() >= size.width()) {
412 parent_bounds = transient_parent_rect;
416 gfx::Rect window_bounds(
417 parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
418 parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
419 size.width(),
420 size.height());
421 // Don't size the window bigger than the parent, otherwise the user may not be
422 // able to close or move it.
423 window_bounds.AdjustToFit(parent_bounds);
425 SetBounds(window_bounds);
428 void DesktopWindowTreeHostX11::GetWindowPlacement(
429 gfx::Rect* bounds,
430 ui::WindowShowState* show_state) const {
431 *bounds = GetRestoredBounds();
433 if (IsFullscreen()) {
434 *show_state = ui::SHOW_STATE_FULLSCREEN;
435 } else if (IsMinimized()) {
436 *show_state = ui::SHOW_STATE_MINIMIZED;
437 } else if (IsMaximized()) {
438 *show_state = ui::SHOW_STATE_MAXIMIZED;
439 } else if (!IsActive()) {
440 *show_state = ui::SHOW_STATE_INACTIVE;
441 } else {
442 *show_state = ui::SHOW_STATE_NORMAL;
446 gfx::Rect DesktopWindowTreeHostX11::GetWindowBoundsInScreen() const {
447 return bounds_;
450 gfx::Rect DesktopWindowTreeHostX11::GetClientAreaBoundsInScreen() const {
451 // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its
452 // needed for View::ConvertPointToScreen() to work
453 // correctly. DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() just
454 // asks windows what it thinks the client rect is.
456 // Attempts to calculate the rect by asking the NonClientFrameView what it
457 // thought its GetBoundsForClientView() were broke combobox drop down
458 // placement.
459 return bounds_;
462 gfx::Rect DesktopWindowTreeHostX11::GetRestoredBounds() const {
463 // We can't reliably track the restored bounds of a window, but we can get
464 // the 90% case down. When *chrome* is the process that requests maximizing
465 // or restoring bounds, we can record the current bounds before we request
466 // maximization, and clear it when we detect a state change.
467 if (!restored_bounds_.IsEmpty())
468 return restored_bounds_;
470 return GetWindowBoundsInScreen();
473 gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInScreen() const {
474 std::vector<int> value;
475 if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
476 value.size() >= 4) {
477 return gfx::Rect(value[0], value[1], value[2], value[3]);
480 // Fetch the geometry of the root window.
481 Window root;
482 int x, y;
483 unsigned int width, height;
484 unsigned int border_width, depth;
485 if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y,
486 &width, &height, &border_width, &depth)) {
487 NOTIMPLEMENTED();
488 return gfx::Rect(0, 0, 10, 10);
491 return gfx::Rect(x, y, width, height);
494 void DesktopWindowTreeHostX11::SetShape(gfx::NativeRegion native_region) {
495 if (window_shape_)
496 XDestroyRegion(window_shape_);
497 custom_window_shape_ = false;
498 window_shape_ = NULL;
500 if (native_region) {
501 custom_window_shape_ = true;
502 window_shape_ = gfx::CreateRegionFromSkRegion(*native_region);
503 delete native_region;
505 ResetWindowRegion();
508 void DesktopWindowTreeHostX11::Activate() {
509 if (!window_mapped_)
510 return;
512 X11DesktopHandler::get()->ActivateWindow(xwindow_);
515 void DesktopWindowTreeHostX11::Deactivate() {
516 if (!IsActive())
517 return;
519 ReleaseCapture();
520 X11DesktopHandler::get()->DeactivateWindow(xwindow_);
523 bool DesktopWindowTreeHostX11::IsActive() const {
524 return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
527 void DesktopWindowTreeHostX11::Maximize() {
528 if (HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN")) {
529 // Unfullscreen the window if it is fullscreen.
530 SetWMSpecState(false,
531 atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
532 None);
534 // Resize the window so that it does not have the same size as a monitor.
535 // (Otherwise, some window managers immediately put the window back in
536 // fullscreen mode).
537 gfx::Rect adjusted_bounds(bounds_.origin(), AdjustSize(bounds_.size()));
538 if (adjusted_bounds != bounds_)
539 SetBounds(adjusted_bounds);
542 // Some WMs do not respect maximization hints on unmapped windows, so we
543 // save this one for later too.
544 should_maximize_after_map_ = !window_mapped_;
546 // When we are in the process of requesting to maximize a window, we can
547 // accurately keep track of our restored bounds instead of relying on the
548 // heuristics that are in the PropertyNotify and ConfigureNotify handlers.
549 restored_bounds_ = bounds_;
551 SetWMSpecState(true,
552 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
553 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
554 if (IsMinimized())
555 ShowWindowWithState(ui::SHOW_STATE_NORMAL);
558 void DesktopWindowTreeHostX11::Minimize() {
559 ReleaseCapture();
560 XIconifyWindow(xdisplay_, xwindow_, 0);
563 void DesktopWindowTreeHostX11::Restore() {
564 should_maximize_after_map_ = false;
565 SetWMSpecState(false,
566 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
567 atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
568 if (IsMinimized())
569 ShowWindowWithState(ui::SHOW_STATE_NORMAL);
572 bool DesktopWindowTreeHostX11::IsMaximized() const {
573 return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") &&
574 HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
577 bool DesktopWindowTreeHostX11::IsMinimized() const {
578 return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
581 bool DesktopWindowTreeHostX11::HasCapture() const {
582 return g_current_capture == this;
585 void DesktopWindowTreeHostX11::SetAlwaysOnTop(bool always_on_top) {
586 is_always_on_top_ = always_on_top;
587 SetWMSpecState(always_on_top,
588 atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
589 None);
592 bool DesktopWindowTreeHostX11::IsAlwaysOnTop() const {
593 return is_always_on_top_;
596 void DesktopWindowTreeHostX11::SetVisibleOnAllWorkspaces(bool always_visible) {
597 SetWMSpecState(always_visible,
598 atom_cache_.GetAtom("_NET_WM_STATE_STICKY"),
599 None);
601 int new_desktop = 0;
602 if (always_visible) {
603 new_desktop = kAllDesktops;
604 } else {
605 if (!ui::GetCurrentDesktop(&new_desktop))
606 return;
609 XEvent xevent;
610 memset (&xevent, 0, sizeof (xevent));
611 xevent.type = ClientMessage;
612 xevent.xclient.window = xwindow_;
613 xevent.xclient.message_type = atom_cache_.GetAtom("_NET_WM_DESKTOP");
614 xevent.xclient.format = 32;
615 xevent.xclient.data.l[0] = new_desktop;
616 xevent.xclient.data.l[1] = 0;
617 xevent.xclient.data.l[2] = 0;
618 xevent.xclient.data.l[3] = 0;
619 xevent.xclient.data.l[4] = 0;
620 XSendEvent(xdisplay_, x_root_window_, False,
621 SubstructureRedirectMask | SubstructureNotifyMask,
622 &xevent);
625 bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) {
626 if (window_title_ == title)
627 return false;
628 window_title_ = title;
629 std::string utf8str = base::UTF16ToUTF8(title);
630 XChangeProperty(xdisplay_,
631 xwindow_,
632 atom_cache_.GetAtom("_NET_WM_NAME"),
633 atom_cache_.GetAtom("UTF8_STRING"),
635 PropModeReplace,
636 reinterpret_cast<const unsigned char*>(utf8str.c_str()),
637 utf8str.size());
638 XTextProperty xtp;
639 char *c_utf8_str = const_cast<char *>(utf8str.c_str());
640 if (Xutf8TextListToTextProperty(xdisplay_, &c_utf8_str, 1,
641 XUTF8StringStyle, &xtp) == Success) {
642 XSetWMName(xdisplay_, xwindow_, &xtp);
643 XFree(xtp.value);
645 return true;
648 void DesktopWindowTreeHostX11::ClearNativeFocus() {
649 // This method is weird and misnamed. Instead of clearing the native focus,
650 // it sets the focus to our |content_window_|, which will trigger a cascade
651 // of focus changes into views.
652 if (content_window_ && aura::client::GetFocusClient(content_window_) &&
653 content_window_->Contains(
654 aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) {
655 aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
659 Widget::MoveLoopResult DesktopWindowTreeHostX11::RunMoveLoop(
660 const gfx::Vector2d& drag_offset,
661 Widget::MoveLoopSource source,
662 Widget::MoveLoopEscapeBehavior escape_behavior) {
663 aura::client::WindowMoveSource window_move_source =
664 source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
665 aura::client::WINDOW_MOVE_SOURCE_MOUSE :
666 aura::client::WINDOW_MOVE_SOURCE_TOUCH;
667 if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
668 window_move_source) == aura::client::MOVE_SUCCESSFUL)
669 return Widget::MOVE_LOOP_SUCCESSFUL;
671 return Widget::MOVE_LOOP_CANCELED;
674 void DesktopWindowTreeHostX11::EndMoveLoop() {
675 x11_window_move_client_->EndMoveLoop();
678 void DesktopWindowTreeHostX11::SetVisibilityChangedAnimationsEnabled(
679 bool value) {
680 // Much like the previous NativeWidgetGtk, we don't have anything to do here.
683 bool DesktopWindowTreeHostX11::ShouldUseNativeFrame() const {
684 return use_native_frame_;
687 bool DesktopWindowTreeHostX11::ShouldWindowContentsBeTransparent() const {
688 return false;
691 void DesktopWindowTreeHostX11::FrameTypeChanged() {
692 Widget::FrameType new_type =
693 native_widget_delegate_->AsWidget()->frame_type();
694 if (new_type == Widget::FRAME_TYPE_DEFAULT) {
695 // The default is determined by Widget::InitParams::remove_standard_frame
696 // and does not change.
697 return;
700 SetUseNativeFrame(new_type == Widget::FRAME_TYPE_FORCE_NATIVE);
701 // Replace the frame and layout the contents. Even though we don't have a
702 // swapable glass frame like on Windows, we still replace the frame because
703 // the button assets don't update otherwise.
704 native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame();
707 void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen) {
708 if (is_fullscreen_ == fullscreen)
709 return;
710 is_fullscreen_ = fullscreen;
711 if (is_fullscreen_)
712 delayed_resize_task_.Cancel();
714 // Work around a bug where if we try to unfullscreen, metacity immediately
715 // fullscreens us again. This is a little flickery and not necessary if
716 // there's a gnome-panel, but it's not easy to detect whether there's a
717 // panel or not.
718 bool unmaximize_and_remaximize = !fullscreen && IsMaximized() &&
719 ui::GuessWindowManager() == ui::WM_METACITY;
721 if (unmaximize_and_remaximize)
722 Restore();
723 SetWMSpecState(fullscreen,
724 atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
725 None);
726 if (unmaximize_and_remaximize)
727 Maximize();
729 // Try to guess the size we will have after the switch to/from fullscreen:
730 // - (may) avoid transient states
731 // - works around Flash content which expects to have the size updated
732 // synchronously.
733 // See https://crbug.com/361408
734 if (fullscreen) {
735 restored_bounds_ = bounds_;
736 const gfx::Display display =
737 gfx::Screen::GetScreenFor(NULL)->GetDisplayNearestWindow(window());
738 bounds_ = display.bounds();
739 } else {
740 bounds_ = restored_bounds_;
742 OnHostMoved(bounds_.origin());
743 OnHostResized(bounds_.size());
745 if (HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN") == fullscreen) {
746 Relayout();
747 ResetWindowRegion();
749 // Else: the widget will be relaid out either when the window bounds change or
750 // when |xwindow_|'s fullscreen state changes.
753 bool DesktopWindowTreeHostX11::IsFullscreen() const {
754 return is_fullscreen_;
757 void DesktopWindowTreeHostX11::SetOpacity(unsigned char opacity) {
758 // X server opacity is in terms of 32 bit unsigned int space, and counts from
759 // the opposite direction.
760 // XChangeProperty() expects "cardinality" to be long.
761 unsigned long cardinality = opacity * 0x1010101;
763 if (cardinality == 0xffffffff) {
764 XDeleteProperty(xdisplay_, xwindow_,
765 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
766 } else {
767 XChangeProperty(xdisplay_, xwindow_,
768 atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
769 XA_CARDINAL, 32,
770 PropModeReplace,
771 reinterpret_cast<unsigned char*>(&cardinality), 1);
775 void DesktopWindowTreeHostX11::SetWindowIcons(
776 const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
777 // TODO(erg): The way we handle icons across different versions of chrome
778 // could be substantially improved. The Windows version does its own thing
779 // and only sometimes comes down this code path. The icon stuff in
780 // ChromeViewsDelegate is hard coded to use HICONs. Likewise, we're hard
781 // coded to be given two images instead of an arbitrary collection of images
782 // so that we can pass to the WM.
784 // All of this could be made much, much better.
785 std::vector<unsigned long> data;
787 if (window_icon.HasRepresentation(1.0f))
788 SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data);
790 if (app_icon.HasRepresentation(1.0f))
791 SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data);
793 if (data.empty())
794 XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_ICON"));
795 else
796 ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data);
799 void DesktopWindowTreeHostX11::InitModalType(ui::ModalType modal_type) {
800 switch (modal_type) {
801 case ui::MODAL_TYPE_NONE:
802 break;
803 default:
804 // TODO(erg): Figure out under what situations |modal_type| isn't
805 // none. The comment in desktop_native_widget_aura.cc suggests that this
806 // is rare.
807 NOTIMPLEMENTED();
811 void DesktopWindowTreeHostX11::FlashFrame(bool flash_frame) {
812 if (urgency_hint_set_ == flash_frame)
813 return;
815 XWMHints* hints = XGetWMHints(xdisplay_, xwindow_);
816 if (!hints) {
817 // The window hasn't had its hints set yet.
818 hints = XAllocWMHints();
821 if (flash_frame)
822 hints->flags |= XUrgencyHint;
823 else
824 hints->flags &= ~XUrgencyHint;
826 XSetWMHints(xdisplay_, xwindow_, hints);
827 XFree(hints);
829 urgency_hint_set_ = flash_frame;
832 void DesktopWindowTreeHostX11::OnRootViewLayout() {
833 UpdateMinAndMaxSize();
836 void DesktopWindowTreeHostX11::OnNativeWidgetFocus() {
837 native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
840 void DesktopWindowTreeHostX11::OnNativeWidgetBlur() {
841 if (xwindow_)
842 native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
845 bool DesktopWindowTreeHostX11::IsAnimatingClosed() const {
846 return false;
849 bool DesktopWindowTreeHostX11::IsTranslucentWindowOpacitySupported() const {
850 return false;
853 void DesktopWindowTreeHostX11::SizeConstraintsChanged() {
854 UpdateMinAndMaxSize();
857 ////////////////////////////////////////////////////////////////////////////////
858 // DesktopWindowTreeHostX11, aura::WindowTreeHost implementation:
860 ui::EventSource* DesktopWindowTreeHostX11::GetEventSource() {
861 return this;
864 gfx::AcceleratedWidget DesktopWindowTreeHostX11::GetAcceleratedWidget() {
865 return xwindow_;
868 void DesktopWindowTreeHostX11::Show() {
869 ShowWindowWithState(ui::SHOW_STATE_NORMAL);
870 native_widget_delegate_->OnNativeWidgetVisibilityChanged(true);
873 void DesktopWindowTreeHostX11::Hide() {
874 if (window_mapped_) {
875 XWithdrawWindow(xdisplay_, xwindow_, 0);
876 window_mapped_ = false;
878 native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
881 gfx::Rect DesktopWindowTreeHostX11::GetBounds() const {
882 return bounds_;
885 void DesktopWindowTreeHostX11::SetBounds(const gfx::Rect& requested_bounds) {
886 gfx::Rect bounds(requested_bounds.origin(),
887 AdjustSize(requested_bounds.size()));
888 bool origin_changed = bounds_.origin() != bounds.origin();
889 bool size_changed = bounds_.size() != bounds.size();
890 XWindowChanges changes = {0};
891 unsigned value_mask = 0;
893 if (size_changed) {
894 if (bounds.width() < min_size_.width() ||
895 bounds.height() < min_size_.height() ||
896 (!max_size_.IsEmpty() &&
897 (bounds.width() > max_size_.width() ||
898 bounds.height() > max_size_.height()))) {
899 // Update the minimum and maximum sizes in case they have changed.
900 UpdateMinAndMaxSize();
902 gfx::Size size = bounds.size();
903 size.SetToMin(max_size_);
904 size.SetToMax(min_size_);
905 bounds.set_size(size);
908 changes.width = bounds.width();
909 changes.height = bounds.height();
910 value_mask |= CWHeight | CWWidth;
913 if (origin_changed) {
914 changes.x = bounds.x();
915 changes.y = bounds.y();
916 value_mask |= CWX | CWY;
918 if (value_mask)
919 XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
921 // Assume that the resize will go through as requested, which should be the
922 // case if we're running without a window manager. If there's a window
923 // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
924 // (possibly synthetic) ConfigureNotify about the actual size and correct
925 // |bounds_| later.
926 bounds_ = bounds;
928 if (origin_changed)
929 native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
930 if (size_changed) {
931 OnHostResized(bounds.size());
932 ResetWindowRegion();
936 gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const {
937 return bounds_.origin();
940 void DesktopWindowTreeHostX11::SetCapture() {
941 if (HasCapture())
942 return;
944 // Grabbing the mouse is asynchronous. However, we synchronously start
945 // forwarding all mouse events received by Chrome to the
946 // aura::WindowEventDispatcher which has capture. This makes capture
947 // synchronous for all intents and purposes if either:
948 // - |g_current_capture|'s X window has capture.
949 // OR
950 // - The topmost window underneath the mouse is managed by Chrome.
951 DesktopWindowTreeHostX11* old_capturer = g_current_capture;
952 g_current_capture = this;
953 if (old_capturer)
954 old_capturer->OnHostLostWindowCapture();
956 unsigned int event_mask = PointerMotionMask | ButtonReleaseMask |
957 ButtonPressMask;
958 XGrabPointer(xdisplay_, xwindow_, True, event_mask, GrabModeAsync,
959 GrabModeAsync, None, None, CurrentTime);
962 void DesktopWindowTreeHostX11::ReleaseCapture() {
963 if (g_current_capture == this) {
964 // Release mouse grab asynchronously. A window managed by Chrome is likely
965 // the topmost window underneath the mouse so the capture release being
966 // asynchronous is likely inconsequential.
967 g_current_capture = NULL;
968 XUngrabPointer(xdisplay_, CurrentTime);
970 OnHostLostWindowCapture();
974 void DesktopWindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) {
975 XDefineCursor(xdisplay_, xwindow_, cursor.platform());
978 void DesktopWindowTreeHostX11::MoveCursorToNative(const gfx::Point& location) {
979 XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
980 bounds_.x() + location.x(), bounds_.y() + location.y());
983 void DesktopWindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
984 // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
985 // the same tap-to-click disabling here that chromeos does.
988 void DesktopWindowTreeHostX11::PostNativeEvent(
989 const base::NativeEvent& native_event) {
990 DCHECK(xwindow_);
991 DCHECK(xdisplay_);
992 XEvent xevent = *native_event;
993 xevent.xany.display = xdisplay_;
994 xevent.xany.window = xwindow_;
996 switch (xevent.type) {
997 case EnterNotify:
998 case LeaveNotify:
999 case MotionNotify:
1000 case KeyPress:
1001 case KeyRelease:
1002 case ButtonPress:
1003 case ButtonRelease: {
1004 // The fields used below are in the same place for all of events
1005 // above. Using xmotion from XEvent's unions to avoid repeating
1006 // the code.
1007 xevent.xmotion.root = x_root_window_;
1008 xevent.xmotion.time = CurrentTime;
1010 gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
1011 ConvertPointToNativeScreen(&point);
1012 xevent.xmotion.x_root = point.x();
1013 xevent.xmotion.y_root = point.y();
1015 default:
1016 break;
1018 XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
1021 ////////////////////////////////////////////////////////////////////////////////
1022 // DesktopWindowTreeHostX11, ui::EventSource implementation:
1024 ui::EventProcessor* DesktopWindowTreeHostX11::GetEventProcessor() {
1025 return dispatcher();
1028 ////////////////////////////////////////////////////////////////////////////////
1029 // DesktopWindowTreeHostX11, private:
1031 void DesktopWindowTreeHostX11::InitX11Window(
1032 const Widget::InitParams& params) {
1033 unsigned long attribute_mask = CWBackPixmap;
1034 XSetWindowAttributes swa;
1035 memset(&swa, 0, sizeof(swa));
1036 swa.background_pixmap = None;
1038 ::Atom window_type;
1039 switch (params.type) {
1040 case Widget::InitParams::TYPE_MENU:
1041 swa.override_redirect = True;
1042 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
1043 break;
1044 case Widget::InitParams::TYPE_TOOLTIP:
1045 swa.override_redirect = True;
1046 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
1047 break;
1048 case Widget::InitParams::TYPE_POPUP:
1049 swa.override_redirect = True;
1050 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION");
1051 break;
1052 case Widget::InitParams::TYPE_DRAG:
1053 swa.override_redirect = True;
1054 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_DND");
1055 break;
1056 default:
1057 window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
1058 break;
1060 if (swa.override_redirect)
1061 attribute_mask |= CWOverrideRedirect;
1063 // Detect whether we're running inside a compositing manager. If so, try to
1064 // use the ARGB visual. Otherwise, just use our parent's visual.
1065 Visual* visual = CopyFromParent;
1066 int depth = CopyFromParent;
1067 if (CommandLine::ForCurrentProcess()->HasSwitch(
1068 switches::kEnableTransparentVisuals) &&
1069 XGetSelectionOwner(xdisplay_,
1070 atom_cache_.GetAtom("_NET_WM_CM_S0")) != None) {
1071 Visual* rgba_visual = GetARGBVisual();
1072 if (rgba_visual) {
1073 visual = rgba_visual;
1074 depth = 32;
1076 attribute_mask |= CWColormap;
1077 swa.colormap = XCreateColormap(xdisplay_, x_root_window_, visual,
1078 AllocNone);
1080 // x.org will BadMatch if we don't set a border when the depth isn't the
1081 // same as the parent depth.
1082 attribute_mask |= CWBorderPixel;
1083 swa.border_pixel = 0;
1085 use_argb_visual_ = true;
1089 bounds_ = gfx::Rect(params.bounds.origin(),
1090 AdjustSize(params.bounds.size()));
1091 xwindow_ = XCreateWindow(
1092 xdisplay_, x_root_window_,
1093 bounds_.x(), bounds_.y(),
1094 bounds_.width(), bounds_.height(),
1095 0, // border width
1096 depth,
1097 InputOutput,
1098 visual,
1099 attribute_mask,
1100 &swa);
1101 if (ui::PlatformEventSource::GetInstance())
1102 ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
1103 open_windows().push_back(xwindow_);
1105 // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
1107 long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
1108 KeyPressMask | KeyReleaseMask |
1109 EnterWindowMask | LeaveWindowMask |
1110 ExposureMask | VisibilityChangeMask |
1111 StructureNotifyMask | PropertyChangeMask |
1112 PointerMotionMask;
1113 XSelectInput(xdisplay_, xwindow_, event_mask);
1114 XFlush(xdisplay_);
1116 if (ui::IsXInput2Available())
1117 ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
1119 // TODO(erg): We currently only request window deletion events. We also
1120 // should listen for activation events and anything else that GTK+ listens
1121 // for, and do something useful.
1122 ::Atom protocols[2];
1123 protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
1124 protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
1125 XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
1127 // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
1128 // the desktop environment.
1129 XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
1131 // Likewise, the X server needs to know this window's pid so it knows which
1132 // program to kill if the window hangs.
1133 // XChangeProperty() expects "pid" to be long.
1134 COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
1135 long pid = getpid();
1136 XChangeProperty(xdisplay_,
1137 xwindow_,
1138 atom_cache_.GetAtom("_NET_WM_PID"),
1139 XA_CARDINAL,
1141 PropModeReplace,
1142 reinterpret_cast<unsigned char*>(&pid), 1);
1144 XChangeProperty(xdisplay_,
1145 xwindow_,
1146 atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
1147 XA_ATOM,
1149 PropModeReplace,
1150 reinterpret_cast<unsigned char*>(&window_type), 1);
1152 // List of window state properties (_NET_WM_STATE) to set, if any.
1153 std::vector< ::Atom> state_atom_list;
1155 // Remove popup windows from taskbar unless overridden.
1156 if ((params.type == Widget::InitParams::TYPE_POPUP ||
1157 params.type == Widget::InitParams::TYPE_BUBBLE) &&
1158 !params.force_show_in_taskbar) {
1159 state_atom_list.push_back(
1160 atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
1163 // If the window should stay on top of other windows, add the
1164 // _NET_WM_STATE_ABOVE property.
1165 is_always_on_top_ = params.keep_on_top;
1166 if (is_always_on_top_)
1167 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
1169 if (params.visible_on_all_workspaces) {
1170 state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_STICKY"));
1171 ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllDesktops);
1174 // Setting _NET_WM_STATE by sending a message to the root_window (with
1175 // SetWMSpecState) has no effect here since the window has not yet been
1176 // mapped. So we manually change the state.
1177 if (!state_atom_list.empty()) {
1178 ui::SetAtomArrayProperty(xwindow_,
1179 "_NET_WM_STATE",
1180 "ATOM",
1181 state_atom_list);
1184 if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
1185 ui::SetWindowClassHint(
1186 xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
1188 if (!params.wm_role_name.empty() ||
1189 params.type == Widget::InitParams::TYPE_POPUP) {
1190 const char kX11WindowRolePopup[] = "popup";
1191 ui::SetWindowRole(xdisplay_, xwindow_, params.wm_role_name.empty() ?
1192 std::string(kX11WindowRolePopup) : params.wm_role_name);
1195 if (params.remove_standard_frame) {
1196 // Setting _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED tells gnome-shell to not force
1197 // fullscreen on the window when it matches the desktop size.
1198 ui::SetHideTitlebarWhenMaximizedProperty(xwindow_,
1199 ui::HIDE_TITLEBAR_WHEN_MAXIMIZED);
1202 // If we have a parent, record the parent/child relationship. We use this
1203 // data during destruction to make sure that when we try to close a parent
1204 // window, we also destroy all child windows.
1205 if (params.parent && params.parent->GetHost()) {
1206 XID parent_xid =
1207 params.parent->GetHost()->GetAcceleratedWidget();
1208 window_parent_ = GetHostForXID(parent_xid);
1209 DCHECK(window_parent_);
1210 window_parent_->window_children_.insert(this);
1213 // If we have a delegate which is providing a default window icon, use that
1214 // icon.
1215 gfx::ImageSkia* window_icon = ViewsDelegate::views_delegate ?
1216 ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL;
1217 if (window_icon) {
1218 SetWindowIcons(gfx::ImageSkia(), *window_icon);
1220 CreateCompositor(GetAcceleratedWidget());
1223 gfx::Size DesktopWindowTreeHostX11::AdjustSize(
1224 const gfx::Size& requested_size) {
1225 std::vector<gfx::Display> displays =
1226 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE)->GetAllDisplays();
1227 // Compare against all monitor sizes. The window manager can move the window
1228 // to whichever monitor it wants.
1229 for (size_t i = 0; i < displays.size(); ++i) {
1230 if (requested_size == displays[i].size()) {
1231 return gfx::Size(requested_size.width() - 1,
1232 requested_size.height() - 1);
1236 // Do not request a 0x0 window size. It causes an XError.
1237 gfx::Size size = requested_size;
1238 size.SetToMax(gfx::Size(1,1));
1239 return size;
1242 void DesktopWindowTreeHostX11::OnWMStateUpdated() {
1243 std::vector< ::Atom> atom_list;
1244 if (!ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list))
1245 return;
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_.IsEmpty()) {
1277 DCHECK(!IsFullscreen());
1278 if (IsMaximized()) {
1279 // The request that we become maximized originated from a different
1280 // process. |bounds_| already contains our maximized bounds. Do a best
1281 // effort attempt to get restored bounds by setting it to our previously
1282 // set bounds (and if we get this wrong, we aren't any worse off since
1283 // we'd otherwise be returning our maximized bounds).
1284 restored_bounds_ = previous_bounds_;
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_ = 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_ = gfx::Insets(
1312 insets[2],
1313 insets[0],
1314 insets[3],
1315 insets[1]);
1316 } else {
1317 native_window_frame_borders_ = gfx::Insets();
1321 void DesktopWindowTreeHostX11::UpdateMinAndMaxSize() {
1322 if (!window_mapped_)
1323 return;
1325 gfx::Size minimum = native_widget_delegate_->GetMinimumSize();
1326 gfx::Size maximum = native_widget_delegate_->GetMaximumSize();
1327 if (min_size_ == minimum && max_size_ == maximum)
1328 return;
1330 min_size_ = minimum;
1331 max_size_ = maximum;
1333 XSizeHints hints;
1334 long supplied_return;
1335 XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return);
1337 if (minimum.IsEmpty()) {
1338 hints.flags &= ~PMinSize;
1339 } else {
1340 hints.flags |= PMinSize;
1341 hints.min_width = min_size_.width();
1342 hints.min_height = min_size_.height();
1345 if (maximum.IsEmpty()) {
1346 hints.flags &= ~PMaxSize;
1347 } else {
1348 hints.flags |= PMaxSize;
1349 hints.max_width = max_size_.width();
1350 hints.max_height = max_size_.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 event->ConvertLocationToTarget(window(), g_current_capture->window());
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 event->ConvertLocationToTarget(window(), g_current_capture->window());
1456 g_current_capture->SendEventToProcessor(event);
1457 } else {
1458 SendEventToProcessor(event);
1462 void DesktopWindowTreeHostX11::ResetWindowRegion() {
1463 // If a custom window shape was supplied then apply it.
1464 if (custom_window_shape_) {
1465 XShapeCombineRegion(
1466 xdisplay_, xwindow_, ShapeBounding, 0, 0, window_shape_, false);
1467 return;
1470 if (window_shape_)
1471 XDestroyRegion(window_shape_);
1472 window_shape_ = NULL;
1474 if (!IsMaximized() && !IsFullscreen()) {
1475 gfx::Path window_mask;
1476 views::Widget* widget = native_widget_delegate_->AsWidget();
1477 if (widget->non_client_view()) {
1478 // Some frame views define a custom (non-rectangular) window mask. If
1479 // so, use it to define the window shape. If not, fall through.
1480 widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask);
1481 if (window_mask.countPoints() > 0) {
1482 window_shape_ = gfx::CreateRegionFromSkPath(window_mask);
1483 XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding,
1484 0, 0, window_shape_, false);
1485 return;
1490 // If we didn't set the shape for any reason, reset the shaping information.
1491 // How this is done depends on the border style, due to quirks and bugs in
1492 // various window managers.
1493 if (ShouldUseNativeFrame()) {
1494 // If the window has system borders, the mask must be set to null (not a
1495 // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will
1496 // not put borders on a window with a custom shape.
1497 XShapeCombineMask(xdisplay_, xwindow_, ShapeBounding, 0, 0, None, ShapeSet);
1498 } else {
1499 // Conversely, if the window does not have system borders, the mask must be
1500 // manually set to a rectangle that covers the whole window (not null). This
1501 // is due to a bug in KWin <= 4.11.5 (KDE bug #330573) where setting a null
1502 // shape causes the hint to disable system borders to be ignored (resulting
1503 // in a double border).
1504 XRectangle r = {0, 0, static_cast<unsigned short>(bounds_.width()),
1505 static_cast<unsigned short>(bounds_.height())};
1506 XShapeCombineRectangles(
1507 xdisplay_, xwindow_, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded);
1511 void DesktopWindowTreeHostX11::SerializeImageRepresentation(
1512 const gfx::ImageSkiaRep& rep,
1513 std::vector<unsigned long>* data) {
1514 int width = rep.GetWidth();
1515 data->push_back(width);
1517 int height = rep.GetHeight();
1518 data->push_back(height);
1520 const SkBitmap& bitmap = rep.sk_bitmap();
1521 SkAutoLockPixels locker(bitmap);
1523 for (int y = 0; y < height; ++y)
1524 for (int x = 0; x < width; ++x)
1525 data->push_back(bitmap.getColor(x, y));
1528 Visual* DesktopWindowTreeHostX11::GetARGBVisual() {
1529 XVisualInfo visual_template;
1530 visual_template.screen = 0;
1531 Visual* to_return = NULL;
1533 int visuals_len;
1534 XVisualInfo* visual_list = XGetVisualInfo(xdisplay_,
1535 VisualScreenMask,
1536 &visual_template, &visuals_len);
1537 for (int i = 0; i < visuals_len; ++i) {
1538 // Why support only 8888 ARGB? Because it's all that GTK+ supports. In
1539 // gdkvisual-x11.cc, they look for this specific visual and use it for all
1540 // their alpha channel using needs.
1542 // TODO(erg): While the following does find a valid visual, some GL drivers
1543 // don't believe that this has an alpha channel. According to marcheu@,
1544 // this should work on open source driver though. (It doesn't work with
1545 // NVidia's binaries currently.) http://crbug.com/369209
1546 if (visual_list[i].depth == 32 &&
1547 visual_list[i].visual->red_mask == 0xff0000 &&
1548 visual_list[i].visual->green_mask == 0x00ff00 &&
1549 visual_list[i].visual->blue_mask == 0x0000ff) {
1550 to_return = visual_list[i].visual;
1551 break;
1555 if (visual_list)
1556 XFree(visual_list);
1558 return to_return;
1561 std::list<XID>& DesktopWindowTreeHostX11::open_windows() {
1562 if (!open_windows_)
1563 open_windows_ = new std::list<XID>();
1564 return *open_windows_;
1567 void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) {
1568 if (show_state != ui::SHOW_STATE_DEFAULT &&
1569 show_state != ui::SHOW_STATE_NORMAL &&
1570 show_state != ui::SHOW_STATE_INACTIVE &&
1571 show_state != ui::SHOW_STATE_MAXIMIZED) {
1572 // It will behave like SHOW_STATE_NORMAL.
1573 NOTIMPLEMENTED();
1576 // Before we map the window, set size hints. Otherwise, some window managers
1577 // will ignore toplevel XMoveWindow commands.
1578 XSizeHints size_hints;
1579 size_hints.flags = PPosition;
1580 size_hints.x = bounds_.x();
1581 size_hints.y = bounds_.y();
1582 XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
1584 // If SHOW_STATE_INACTIVE, tell the window manager not to focus the window
1585 // when mapping. This is done by setting the _NET_WM_USER_TIME to 0. See e.g.
1586 // http://standards.freedesktop.org/wm-spec/latest/ar01s05.html
1587 unsigned long wm_user_time_ms = (show_state == ui::SHOW_STATE_INACTIVE) ?
1588 0 : X11DesktopHandler::get()->wm_user_time_ms();
1589 if (show_state == ui::SHOW_STATE_INACTIVE || wm_user_time_ms != 0) {
1590 XChangeProperty(xdisplay_,
1591 xwindow_,
1592 atom_cache_.GetAtom("_NET_WM_USER_TIME"),
1593 XA_CARDINAL,
1595 PropModeReplace,
1596 reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
1600 XMapWindow(xdisplay_, xwindow_);
1602 // We now block until our window is mapped. Some X11 APIs will crash and
1603 // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
1604 // asynchronous.
1605 if (ui::X11EventSource::GetInstance())
1606 ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_);
1607 window_mapped_ = true;
1609 // Some WMs only respect maximize hints after the window has been mapped.
1610 // Check whether we need to re-do a maximization.
1611 if (should_maximize_after_map_) {
1612 Maximize();
1613 should_maximize_after_map_ = false;
1617 void DesktopWindowTreeHostX11::SetWindowTransparency() {
1618 compositor()->SetHostHasTransparentBackground(use_argb_visual_);
1619 window()->SetTransparent(use_argb_visual_);
1620 content_window_->SetTransparent(use_argb_visual_);
1623 void DesktopWindowTreeHostX11::Relayout() {
1624 Widget* widget = native_widget_delegate_->AsWidget();
1625 NonClientView* non_client_view = widget->non_client_view();
1626 // non_client_view may be NULL, especially during creation.
1627 if (non_client_view) {
1628 non_client_view->client_view()->InvalidateLayout();
1629 non_client_view->InvalidateLayout();
1631 widget->GetRootView()->Layout();
1634 ////////////////////////////////////////////////////////////////////////////////
1635 // DesktopWindowTreeHostX11, ui::PlatformEventDispatcher implementation:
1637 bool DesktopWindowTreeHostX11::CanDispatchEvent(
1638 const ui::PlatformEvent& event) {
1639 return event->xany.window == xwindow_ ||
1640 (event->type == GenericEvent &&
1641 static_cast<XIDeviceEvent*>(event->xcookie.data)->event == xwindow_);
1644 uint32_t DesktopWindowTreeHostX11::DispatchEvent(
1645 const ui::PlatformEvent& event) {
1646 XEvent* xev = event;
1648 TRACE_EVENT1("views", "DesktopWindowTreeHostX11::Dispatch",
1649 "event->type", event->type);
1651 UpdateWMUserTime(event);
1653 // May want to factor CheckXEventForConsistency(xev); into a common location
1654 // since it is called here.
1655 switch (xev->type) {
1656 case EnterNotify:
1657 case LeaveNotify: {
1658 // Ignore EventNotify and LeaveNotify events from children of |xwindow_|.
1659 // NativeViewGLSurfaceGLX adds a child to |xwindow_|.
1660 // TODO(pkotwicz|tdanderson): Figure out whether the suppression is
1661 // necessary. crbug.com/385716
1662 if (xev->xcrossing.detail == NotifyInferior)
1663 break;
1665 ui::MouseEvent mouse_event(xev);
1666 DispatchMouseEvent(&mouse_event);
1667 break;
1669 case Expose: {
1670 gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
1671 xev->xexpose.width, xev->xexpose.height);
1672 compositor()->ScheduleRedrawRect(damage_rect);
1673 break;
1675 case KeyPress: {
1676 ui::KeyEvent keydown_event(xev);
1677 SendEventToProcessor(&keydown_event);
1678 break;
1680 case KeyRelease: {
1681 // There is no way to deactivate a window in X11 so ignore input if
1682 // window is supposed to be 'inactive'. See comments in
1683 // X11DesktopHandler::DeactivateWindow() for more details.
1684 if (!IsActive() && !HasCapture())
1685 break;
1687 ui::KeyEvent key_event(xev);
1688 SendEventToProcessor(&key_event);
1689 break;
1691 case ButtonPress:
1692 case ButtonRelease: {
1693 ui::EventType event_type = ui::EventTypeFromNative(xev);
1694 switch (event_type) {
1695 case ui::ET_MOUSEWHEEL: {
1696 ui::MouseWheelEvent mouseev(xev);
1697 DispatchMouseEvent(&mouseev);
1698 break;
1700 case ui::ET_MOUSE_PRESSED:
1701 case ui::ET_MOUSE_RELEASED: {
1702 ui::MouseEvent mouseev(xev);
1703 DispatchMouseEvent(&mouseev);
1704 break;
1706 case ui::ET_UNKNOWN:
1707 // No event is created for X11-release events for mouse-wheel buttons.
1708 break;
1709 default:
1710 NOTREACHED() << event_type;
1712 break;
1714 case FocusOut:
1715 if (xev->xfocus.mode != NotifyGrab) {
1716 ReleaseCapture();
1717 OnHostLostWindowCapture();
1718 X11DesktopHandler::get()->ProcessXEvent(xev);
1719 } else {
1720 dispatcher()->OnHostLostMouseGrab();
1722 break;
1723 case FocusIn:
1724 X11DesktopHandler::get()->ProcessXEvent(xev);
1725 break;
1726 case ConfigureNotify: {
1727 DCHECK_EQ(xwindow_, xev->xconfigure.window);
1728 DCHECK_EQ(xwindow_, xev->xconfigure.event);
1729 // It's possible that the X window may be resized by some other means than
1730 // from within aura (e.g. the X window manager can change the size). Make
1731 // sure the root window size is maintained properly.
1732 int translated_x = xev->xconfigure.x;
1733 int translated_y = xev->xconfigure.y;
1734 if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
1735 Window unused;
1736 XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_,
1737 0, 0, &translated_x, &translated_y, &unused);
1739 gfx::Rect bounds(translated_x, translated_y,
1740 xev->xconfigure.width, xev->xconfigure.height);
1741 bool size_changed = bounds_.size() != bounds.size();
1742 bool origin_changed = bounds_.origin() != bounds.origin();
1743 previous_bounds_ = bounds_;
1744 bounds_ = bounds;
1746 if (origin_changed)
1747 OnHostMoved(bounds_.origin());
1749 if (size_changed) {
1750 delayed_resize_task_.Reset(base::Bind(
1751 &DesktopWindowTreeHostX11::DelayedResize,
1752 close_widget_factory_.GetWeakPtr(),
1753 bounds.size()));
1754 base::MessageLoop::current()->PostTask(
1755 FROM_HERE, delayed_resize_task_.callback());
1757 break;
1759 case GenericEvent: {
1760 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
1761 if (!factory->ShouldProcessXI2Event(xev))
1762 break;
1764 ui::EventType type = ui::EventTypeFromNative(xev);
1765 XEvent last_event;
1766 int num_coalesced = 0;
1768 switch (type) {
1769 case ui::ET_TOUCH_MOVED:
1770 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1771 if (num_coalesced > 0)
1772 xev = &last_event;
1773 // fallthrough
1774 case ui::ET_TOUCH_PRESSED:
1775 case ui::ET_TOUCH_RELEASED: {
1776 ui::TouchEvent touchev(xev);
1777 DispatchTouchEvent(&touchev);
1778 break;
1780 case ui::ET_MOUSE_MOVED:
1781 case ui::ET_MOUSE_DRAGGED:
1782 case ui::ET_MOUSE_PRESSED:
1783 case ui::ET_MOUSE_RELEASED:
1784 case ui::ET_MOUSE_ENTERED:
1785 case ui::ET_MOUSE_EXITED: {
1786 if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
1787 // If this is a motion event, we want to coalesce all pending motion
1788 // events that are at the top of the queue.
1789 num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1790 if (num_coalesced > 0)
1791 xev = &last_event;
1793 ui::MouseEvent mouseev(xev);
1794 DispatchMouseEvent(&mouseev);
1795 break;
1797 case ui::ET_MOUSEWHEEL: {
1798 ui::MouseWheelEvent mouseev(xev);
1799 DispatchMouseEvent(&mouseev);
1800 break;
1802 case ui::ET_SCROLL_FLING_START:
1803 case ui::ET_SCROLL_FLING_CANCEL:
1804 case ui::ET_SCROLL: {
1805 ui::ScrollEvent scrollev(xev);
1806 SendEventToProcessor(&scrollev);
1807 break;
1809 case ui::ET_KEY_PRESSED:
1810 case ui::ET_KEY_RELEASED: {
1811 ui::KeyEvent key_event(xev);
1812 SendEventToProcessor(&key_event);
1813 break;
1815 case ui::ET_UNKNOWN:
1816 break;
1817 default:
1818 NOTREACHED();
1821 // If we coalesced an event we need to free its cookie.
1822 if (num_coalesced > 0)
1823 XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
1824 break;
1826 case MapNotify: {
1827 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1828 observer_list_,
1829 OnWindowMapped(xwindow_));
1830 break;
1832 case UnmapNotify: {
1833 FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1834 observer_list_,
1835 OnWindowUnmapped(xwindow_));
1836 break;
1838 case ClientMessage: {
1839 Atom message_type = xev->xclient.message_type;
1840 if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
1841 Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
1842 if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
1843 // We have received a close message from the window manager.
1844 OnHostCloseRequested();
1845 } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
1846 XEvent reply_event = *xev;
1847 reply_event.xclient.window = x_root_window_;
1849 XSendEvent(xdisplay_,
1850 reply_event.xclient.window,
1851 False,
1852 SubstructureRedirectMask | SubstructureNotifyMask,
1853 &reply_event);
1855 } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
1856 drag_drop_client_->OnXdndEnter(xev->xclient);
1857 } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
1858 drag_drop_client_->OnXdndLeave(xev->xclient);
1859 } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
1860 drag_drop_client_->OnXdndPosition(xev->xclient);
1861 } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
1862 drag_drop_client_->OnXdndStatus(xev->xclient);
1863 } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
1864 drag_drop_client_->OnXdndFinished(xev->xclient);
1865 } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
1866 drag_drop_client_->OnXdndDrop(xev->xclient);
1868 break;
1870 case MappingNotify: {
1871 switch (xev->xmapping.request) {
1872 case MappingModifier:
1873 case MappingKeyboard:
1874 XRefreshKeyboardMapping(&xev->xmapping);
1875 break;
1876 case MappingPointer:
1877 ui::DeviceDataManagerX11::GetInstance()->UpdateButtonMap();
1878 break;
1879 default:
1880 NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
1881 break;
1883 break;
1885 case MotionNotify: {
1886 // Discard all but the most recent motion event that targets the same
1887 // window with unchanged state.
1888 XEvent last_event;
1889 while (XPending(xev->xany.display)) {
1890 XEvent next_event;
1891 XPeekEvent(xev->xany.display, &next_event);
1892 if (next_event.type == MotionNotify &&
1893 next_event.xmotion.window == xev->xmotion.window &&
1894 next_event.xmotion.subwindow == xev->xmotion.subwindow &&
1895 next_event.xmotion.state == xev->xmotion.state) {
1896 XNextEvent(xev->xany.display, &last_event);
1897 xev = &last_event;
1898 } else {
1899 break;
1903 ui::MouseEvent mouseev(xev);
1904 DispatchMouseEvent(&mouseev);
1905 break;
1907 case PropertyNotify: {
1908 ::Atom changed_atom = xev->xproperty.atom;
1909 if (changed_atom == atom_cache_.GetAtom("_NET_WM_STATE"))
1910 OnWMStateUpdated();
1911 else if (changed_atom == atom_cache_.GetAtom("_NET_FRAME_EXTENTS"))
1912 OnFrameExtentsUpdated();
1913 break;
1915 case SelectionNotify: {
1916 drag_drop_client_->OnSelectionNotify(xev->xselection);
1917 break;
1920 return ui::POST_DISPATCH_STOP_PROPAGATION;
1923 void DesktopWindowTreeHostX11::DelayedResize(const gfx::Size& size) {
1924 OnHostResized(size);
1925 ResetWindowRegion();
1926 delayed_resize_task_.Cancel();
1929 ////////////////////////////////////////////////////////////////////////////////
1930 // DesktopWindowTreeHost, public:
1932 // static
1933 DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
1934 internal::NativeWidgetDelegate* native_widget_delegate,
1935 DesktopNativeWidgetAura* desktop_native_widget_aura) {
1936 return new DesktopWindowTreeHostX11(native_widget_delegate,
1937 desktop_native_widget_aura);
1940 // static
1941 ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) {
1942 const views::LinuxUI* linux_ui = views::LinuxUI::instance();
1943 if (linux_ui) {
1944 ui::NativeTheme* native_theme = linux_ui->GetNativeTheme(window);
1945 if (native_theme)
1946 return native_theme;
1949 return ui::NativeTheme::instance();
1952 } // namespace views