bdf0d19a4a01df05ac4f3fa7b87355a0ffb33b9e
[platform/framework/web/crosswalk.git] / src / ui / views / widget / desktop_aura / desktop_window_tree_host_x11.cc
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.
4
5 #include "ui/views/widget/desktop_aura/desktop_window_tree_host_x11.h"
6
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>
12
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.h"
31 #include "ui/events/x/device_list_cache_x.h"
32 #include "ui/events/x/touch_factory_x11.h"
33 #include "ui/gfx/image/image_skia.h"
34 #include "ui/gfx/image/image_skia_rep.h"
35 #include "ui/gfx/insets.h"
36 #include "ui/gfx/path.h"
37 #include "ui/gfx/path_x11.h"
38 #include "ui/gfx/screen.h"
39 #include "ui/native_theme/native_theme.h"
40 #include "ui/views/corewm/tooltip_aura.h"
41 #include "ui/views/ime/input_method.h"
42 #include "ui/views/linux_ui/linux_ui.h"
43 #include "ui/views/views_delegate.h"
44 #include "ui/views/views_switches.h"
45 #include "ui/views/widget/desktop_aura/desktop_dispatcher_client.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_scoped_capture.h"
53 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
54 #include "ui/wm/core/compound_event_filter.h"
55 #include "ui/wm/core/window_util.h"
56
57 namespace views {
58
59 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::g_current_capture =
60     NULL;
61 std::list<XID>* DesktopWindowTreeHostX11::open_windows_ = NULL;
62
63 DEFINE_WINDOW_PROPERTY_KEY(
64     aura::Window*, kViewsWindowForRootWindow, NULL);
65
66 DEFINE_WINDOW_PROPERTY_KEY(
67     DesktopWindowTreeHostX11*, kHostForRootWindow, NULL);
68
69 namespace {
70
71 // Constants that are part of EWMH.
72 const int k_NET_WM_STATE_ADD = 1;
73 const int k_NET_WM_STATE_REMOVE = 0;
74
75 // Special value of the _NET_WM_DESKTOP property which indicates that the window
76 // should appear on all desktops.
77 const int kAllDesktops = 0xFFFFFFFF;
78
79 const char* kAtomsToCache[] = {
80   "UTF8_STRING",
81   "WM_DELETE_WINDOW",
82   "WM_PROTOCOLS",
83   "_NET_FRAME_EXTENTS",
84   "_NET_WM_CM_S0",
85   "_NET_WM_DESKTOP",
86   "_NET_WM_ICON",
87   "_NET_WM_NAME",
88   "_NET_WM_PID",
89   "_NET_WM_PING",
90   "_NET_WM_STATE",
91   "_NET_WM_STATE_ABOVE",
92   "_NET_WM_STATE_FULLSCREEN",
93   "_NET_WM_STATE_HIDDEN",
94   "_NET_WM_STATE_MAXIMIZED_HORZ",
95   "_NET_WM_STATE_MAXIMIZED_VERT",
96   "_NET_WM_STATE_SKIP_TASKBAR",
97   "_NET_WM_STATE_STICKY",
98   "_NET_WM_USER_TIME",
99   "_NET_WM_WINDOW_OPACITY",
100   "_NET_WM_WINDOW_TYPE",
101   "_NET_WM_WINDOW_TYPE_DND",
102   "_NET_WM_WINDOW_TYPE_MENU",
103   "_NET_WM_WINDOW_TYPE_NORMAL",
104   "_NET_WM_WINDOW_TYPE_NOTIFICATION",
105   "_NET_WM_WINDOW_TYPE_TOOLTIP",
106   "XdndActionAsk",
107   "XdndActionCopy"
108   "XdndActionLink",
109   "XdndActionList",
110   "XdndActionMove",
111   "XdndActionPrivate",
112   "XdndAware",
113   "XdndDrop",
114   "XdndEnter",
115   "XdndFinished",
116   "XdndLeave",
117   "XdndPosition",
118   "XdndProxy",  // Proxy windows?
119   "XdndSelection",
120   "XdndStatus",
121   "XdndTypeList",
122   NULL
123 };
124
125 }  // namespace
126
127 ////////////////////////////////////////////////////////////////////////////////
128 // DesktopWindowTreeHostX11, public:
129
130 DesktopWindowTreeHostX11::DesktopWindowTreeHostX11(
131     internal::NativeWidgetDelegate* native_widget_delegate,
132     DesktopNativeWidgetAura* desktop_native_widget_aura)
133     : close_widget_factory_(this),
134       xdisplay_(gfx::GetXDisplay()),
135       xwindow_(0),
136       x_root_window_(DefaultRootWindow(xdisplay_)),
137       atom_cache_(xdisplay_, kAtomsToCache),
138       window_mapped_(false),
139       is_fullscreen_(false),
140       is_always_on_top_(false),
141       use_native_frame_(false),
142       use_argb_visual_(false),
143       drag_drop_client_(NULL),
144       current_cursor_(ui::kCursorNull),
145       native_widget_delegate_(native_widget_delegate),
146       desktop_native_widget_aura_(desktop_native_widget_aura),
147       content_window_(NULL),
148       window_parent_(NULL),
149       window_shape_(NULL),
150       custom_window_shape_(false),
151       urgency_hint_set_(false) {
152 }
153
154 DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() {
155   window()->ClearProperty(kHostForRootWindow);
156   aura::client::SetWindowMoveClient(window(), NULL);
157   desktop_native_widget_aura_->OnDesktopWindowTreeHostDestroyed(this);
158   if (window_shape_)
159     XDestroyRegion(window_shape_);
160   DestroyDispatcher();
161 }
162
163 // static
164 aura::Window* DesktopWindowTreeHostX11::GetContentWindowForXID(XID xid) {
165   aura::WindowTreeHost* host =
166       aura::WindowTreeHost::GetForAcceleratedWidget(xid);
167   return host ? host->window()->GetProperty(kViewsWindowForRootWindow) : NULL;
168 }
169
170 // static
171 DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::GetHostForXID(XID xid) {
172   aura::WindowTreeHost* host =
173       aura::WindowTreeHost::GetForAcceleratedWidget(xid);
174   return host ? host->window()->GetProperty(kHostForRootWindow) : NULL;
175 }
176
177 // static
178 std::vector<aura::Window*> DesktopWindowTreeHostX11::GetAllOpenWindows() {
179   std::vector<aura::Window*> windows(open_windows().size());
180   std::transform(open_windows().begin(),
181                  open_windows().end(),
182                  windows.begin(),
183                  GetContentWindowForXID);
184   return windows;
185 }
186
187 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowBounds() const {
188   return bounds_;
189 }
190
191 gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowOuterBounds() const {
192   gfx::Rect outer_bounds(bounds_);
193   outer_bounds.Inset(-native_window_frame_borders_);
194   return outer_bounds;
195 }
196
197 ::Region DesktopWindowTreeHostX11::GetWindowShape() const {
198   return window_shape_;
199 }
200
201 void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged(
202     bool active) {
203   if (active) {
204     FlashFrame(false);
205     OnHostActivated();
206     open_windows().remove(xwindow_);
207     open_windows().insert(open_windows().begin(), xwindow_);
208   }
209
210   desktop_native_widget_aura_->HandleActivationChanged(active);
211
212   native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
213 }
214
215 void DesktopWindowTreeHostX11::AddObserver(
216     views::DesktopWindowTreeHostObserverX11* observer) {
217   observer_list_.AddObserver(observer);
218 }
219
220 void DesktopWindowTreeHostX11::RemoveObserver(
221     views::DesktopWindowTreeHostObserverX11* observer) {
222   observer_list_.RemoveObserver(observer);
223 }
224
225 void DesktopWindowTreeHostX11::SwapNonClientEventHandler(
226     scoped_ptr<ui::EventHandler> handler) {
227   wm::CompoundEventFilter* compound_event_filter =
228       desktop_native_widget_aura_->root_window_event_filter();
229   if (x11_non_client_event_filter_)
230     compound_event_filter->RemoveHandler(x11_non_client_event_filter_.get());
231   compound_event_filter->AddHandler(handler.get());
232   x11_non_client_event_filter_ = handler.Pass();
233 }
234
235 void DesktopWindowTreeHostX11::CleanUpWindowList() {
236   delete open_windows_;
237   open_windows_ = NULL;
238 }
239
240 ////////////////////////////////////////////////////////////////////////////////
241 // DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation:
242
243 void DesktopWindowTreeHostX11::Init(aura::Window* content_window,
244                                     const Widget::InitParams& params) {
245   content_window_ = content_window;
246
247   // TODO(erg): Check whether we *should* be building a WindowTreeHost here, or
248   // whether we should be proxying requests to another DRWHL.
249
250   // In some situations, views tries to make a zero sized window, and that
251   // makes us crash. Make sure we have valid sizes.
252   Widget::InitParams sanitized_params = params;
253   if (sanitized_params.bounds.width() == 0)
254     sanitized_params.bounds.set_width(100);
255   if (sanitized_params.bounds.height() == 0)
256     sanitized_params.bounds.set_height(100);
257
258   InitX11Window(sanitized_params);
259 }
260
261 void DesktopWindowTreeHostX11::OnNativeWidgetCreated(
262     const Widget::InitParams& params) {
263   window()->SetProperty(kViewsWindowForRootWindow, content_window_);
264   window()->SetProperty(kHostForRootWindow, this);
265
266   // Ensure that the X11DesktopHandler exists so that it dispatches activation
267   // messages to us.
268   X11DesktopHandler::get();
269
270   // TODO(erg): Unify this code once the other consumer goes away.
271   SwapNonClientEventHandler(
272       scoped_ptr<ui::EventHandler>(new X11WindowEventFilter(this)).Pass());
273   SetUseNativeFrame(params.type == Widget::InitParams::TYPE_WINDOW &&
274                     !params.remove_standard_frame);
275
276   x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
277   aura::client::SetWindowMoveClient(window(), x11_window_move_client_.get());
278
279   SetWindowTransparency();
280
281   native_widget_delegate_->OnNativeWidgetCreated(true);
282 }
283
284 scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostX11::CreateTooltip() {
285   return scoped_ptr<corewm::Tooltip>(
286       new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE));
287 }
288
289 scoped_ptr<aura::client::DragDropClient>
290 DesktopWindowTreeHostX11::CreateDragDropClient(
291     DesktopNativeCursorManager* cursor_manager) {
292   drag_drop_client_ = new DesktopDragDropClientAuraX11(
293       window(), cursor_manager, xdisplay_, xwindow_);
294   return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
295 }
296
297 void DesktopWindowTreeHostX11::Close() {
298   // TODO(erg): Might need to do additional hiding tasks here.
299
300   if (!close_widget_factory_.HasWeakPtrs()) {
301     // And we delay the close so that if we are called from an ATL callback,
302     // we don't destroy the window before the callback returned (as the caller
303     // may delete ourselves on destroy and the ATL callback would still
304     // dereference us when the callback returns).
305     base::MessageLoop::current()->PostTask(
306         FROM_HERE,
307         base::Bind(&DesktopWindowTreeHostX11::CloseNow,
308                    close_widget_factory_.GetWeakPtr()));
309   }
310 }
311
312 void DesktopWindowTreeHostX11::CloseNow() {
313   if (xwindow_ == None)
314     return;
315
316   x11_capture_.reset();
317   native_widget_delegate_->OnNativeWidgetDestroying();
318
319   // If we have children, close them. Use a copy for iteration because they'll
320   // remove themselves.
321   std::set<DesktopWindowTreeHostX11*> window_children_copy = window_children_;
322   for (std::set<DesktopWindowTreeHostX11*>::iterator it =
323            window_children_copy.begin(); it != window_children_copy.end();
324        ++it) {
325     (*it)->CloseNow();
326   }
327   DCHECK(window_children_.empty());
328
329   // If we have a parent, remove ourselves from its children list.
330   if (window_parent_) {
331     window_parent_->window_children_.erase(this);
332     window_parent_ = NULL;
333   }
334
335   // Remove the event listeners we've installed. We need to remove these
336   // because otherwise we get assert during ~WindowEventDispatcher().
337   desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
338       x11_non_client_event_filter_.get());
339   x11_non_client_event_filter_.reset();
340
341   // Destroy the compositor before destroying the |xwindow_| since shutdown
342   // may try to swap, and the swap without a window causes an X error, which
343   // causes a crash with in-process renderer.
344   DestroyCompositor();
345
346   open_windows().remove(xwindow_);
347   // Actually free our native resources.
348   if (ui::PlatformEventSource::GetInstance())
349     ui::PlatformEventSource::GetInstance()->RemovePlatformEventDispatcher(this);
350   XDestroyWindow(xdisplay_, xwindow_);
351   xwindow_ = None;
352
353   desktop_native_widget_aura_->OnHostClosed();
354 }
355
356 aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() {
357   return this;
358 }
359
360 void DesktopWindowTreeHostX11::ShowWindowWithState(
361     ui::WindowShowState show_state) {
362   if (!window_mapped_)
363     MapWindow(show_state);
364
365   if (show_state == ui::SHOW_STATE_NORMAL ||
366       show_state == ui::SHOW_STATE_MAXIMIZED) {
367     // Note: XFCE ignores a maximize hint given before mapping the window.
368     if (show_state == ui::SHOW_STATE_MAXIMIZED)
369       Maximize();
370     Activate();
371   }
372
373   native_widget_delegate_->AsWidget()->SetInitialFocus(show_state);
374 }
375
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;
381 }
382
383 bool DesktopWindowTreeHostX11::IsVisible() const {
384   return window_mapped_;
385 }
386
387 void DesktopWindowTreeHostX11::SetSize(const gfx::Size& size) {
388   bool size_changed = bounds_.size() != size;
389   XResizeWindow(xdisplay_, xwindow_, size.width(), size.height());
390   bounds_.set_size(size);
391   if (size_changed) {
392     OnHostResized(size);
393     ResetWindowRegion();
394   }
395 }
396
397 void DesktopWindowTreeHostX11::StackAtTop() {
398   XRaiseWindow(xdisplay_, xwindow_);
399 }
400
401 void DesktopWindowTreeHostX11::CenterWindow(const gfx::Size& size) {
402   gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
403
404   // If |window_|'s transient parent bounds are big enough to contain |size|,
405   // use them instead.
406   if (wm::GetTransientParent(content_window_)) {
407     gfx::Rect transient_parent_rect =
408         wm::GetTransientParent(content_window_)->GetBoundsInScreen();
409     if (transient_parent_rect.height() >= size.height() &&
410         transient_parent_rect.width() >= size.width()) {
411       parent_bounds = transient_parent_rect;
412     }
413   }
414
415   gfx::Rect window_bounds(
416       parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
417       parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
418       size.width(),
419       size.height());
420   // Don't size the window bigger than the parent, otherwise the user may not be
421   // able to close or move it.
422   window_bounds.AdjustToFit(parent_bounds);
423
424   SetBounds(window_bounds);
425 }
426
427 void DesktopWindowTreeHostX11::GetWindowPlacement(
428     gfx::Rect* bounds,
429     ui::WindowShowState* show_state) const {
430   *bounds = GetRestoredBounds();
431
432   if (IsFullscreen()) {
433     *show_state = ui::SHOW_STATE_FULLSCREEN;
434   } else if (IsMinimized()) {
435     *show_state = ui::SHOW_STATE_MINIMIZED;
436   } else if (IsMaximized()) {
437     *show_state = ui::SHOW_STATE_MAXIMIZED;
438   } else if (!IsActive()) {
439     *show_state = ui::SHOW_STATE_INACTIVE;
440   } else {
441     *show_state = ui::SHOW_STATE_NORMAL;
442   }
443 }
444
445 gfx::Rect DesktopWindowTreeHostX11::GetWindowBoundsInScreen() const {
446   return bounds_;
447 }
448
449 gfx::Rect DesktopWindowTreeHostX11::GetClientAreaBoundsInScreen() const {
450   // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its
451   // needed for View::ConvertPointToScreen() to work
452   // correctly. DesktopWindowTreeHostWin::GetClientAreaBoundsInScreen() just
453   // asks windows what it thinks the client rect is.
454   //
455   // Attempts to calculate the rect by asking the NonClientFrameView what it
456   // thought its GetBoundsForClientView() were broke combobox drop down
457   // placement.
458   return bounds_;
459 }
460
461 gfx::Rect DesktopWindowTreeHostX11::GetRestoredBounds() const {
462   // We can't reliably track the restored bounds of a window, but we can get
463   // the 90% case down. When *chrome* is the process that requests maximizing
464   // or restoring bounds, we can record the current bounds before we request
465   // maximization, and clear it when we detect a state change.
466   if (!restored_bounds_.IsEmpty())
467     return restored_bounds_;
468
469   return GetWindowBoundsInScreen();
470 }
471
472 gfx::Rect DesktopWindowTreeHostX11::GetWorkAreaBoundsInScreen() const {
473   std::vector<int> value;
474   if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
475       value.size() >= 4) {
476     return gfx::Rect(value[0], value[1], value[2], value[3]);
477   }
478
479   // Fetch the geometry of the root window.
480   Window root;
481   int x, y;
482   unsigned int width, height;
483   unsigned int border_width, depth;
484   if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y,
485                     &width, &height, &border_width, &depth)) {
486     NOTIMPLEMENTED();
487     return gfx::Rect(0, 0, 10, 10);
488   }
489
490   return gfx::Rect(x, y, width, height);
491 }
492
493 void DesktopWindowTreeHostX11::SetShape(gfx::NativeRegion native_region) {
494   if (window_shape_)
495     XDestroyRegion(window_shape_);
496   custom_window_shape_ = true;
497   window_shape_ = gfx::CreateRegionFromSkRegion(*native_region);
498   ResetWindowRegion();
499   delete native_region;
500 }
501
502 void DesktopWindowTreeHostX11::Activate() {
503   if (!window_mapped_)
504     return;
505
506   X11DesktopHandler::get()->ActivateWindow(xwindow_);
507 }
508
509 void DesktopWindowTreeHostX11::Deactivate() {
510   if (!IsActive())
511     return;
512
513   x11_capture_.reset();
514   XLowerWindow(xdisplay_, xwindow_);
515 }
516
517 bool DesktopWindowTreeHostX11::IsActive() const {
518   return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
519 }
520
521 void DesktopWindowTreeHostX11::Maximize() {
522   // When we are in the process of requesting to maximize a window, we can
523   // accurately keep track of our restored bounds instead of relying on the
524   // heuristics that are in the PropertyNotify and ConfigureNotify handlers.
525   restored_bounds_ = bounds_;
526
527   SetWMSpecState(true,
528                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
529                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
530   if (IsMinimized())
531     ShowWindowWithState(ui::SHOW_STATE_NORMAL);
532 }
533
534 void DesktopWindowTreeHostX11::Minimize() {
535   x11_capture_.reset();
536   XIconifyWindow(xdisplay_, xwindow_, 0);
537 }
538
539 void DesktopWindowTreeHostX11::Restore() {
540   SetWMSpecState(false,
541                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
542                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
543   if (IsMinimized())
544     ShowWindowWithState(ui::SHOW_STATE_NORMAL);
545 }
546
547 bool DesktopWindowTreeHostX11::IsMaximized() const {
548   return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") &&
549           HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
550 }
551
552 bool DesktopWindowTreeHostX11::IsMinimized() const {
553   return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
554 }
555
556 bool DesktopWindowTreeHostX11::HasCapture() const {
557   return g_current_capture == this;
558 }
559
560 void DesktopWindowTreeHostX11::SetAlwaysOnTop(bool always_on_top) {
561   is_always_on_top_ = always_on_top;
562   SetWMSpecState(always_on_top,
563                  atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
564                  None);
565 }
566
567 bool DesktopWindowTreeHostX11::IsAlwaysOnTop() const {
568   return is_always_on_top_;
569 }
570
571 void DesktopWindowTreeHostX11::SetVisibleOnAllWorkspaces(bool always_visible) {
572   SetWMSpecState(always_visible,
573                  atom_cache_.GetAtom("_NET_WM_STATE_STICKY"),
574                  None);
575
576   int new_desktop = 0;
577   if (always_visible) {
578     new_desktop = kAllDesktops;
579   } else {
580     if (!ui::GetCurrentDesktop(&new_desktop))
581       return;
582   }
583
584   XEvent xevent;
585   memset (&xevent, 0, sizeof (xevent));
586   xevent.type = ClientMessage;
587   xevent.xclient.window = xwindow_;
588   xevent.xclient.message_type = atom_cache_.GetAtom("_NET_WM_DESKTOP");
589   xevent.xclient.format = 32;
590   xevent.xclient.data.l[0] = new_desktop;
591   xevent.xclient.data.l[1] = 0;
592   xevent.xclient.data.l[2] = 0;
593   xevent.xclient.data.l[3] = 0;
594   xevent.xclient.data.l[4] = 0;
595   XSendEvent(xdisplay_, x_root_window_, False,
596              SubstructureRedirectMask | SubstructureNotifyMask,
597              &xevent);
598 }
599
600 bool DesktopWindowTreeHostX11::SetWindowTitle(const base::string16& title) {
601   if (window_title_ == title)
602     return false;
603   window_title_ = title;
604   std::string utf8str = base::UTF16ToUTF8(title);
605   XChangeProperty(xdisplay_,
606                   xwindow_,
607                   atom_cache_.GetAtom("_NET_WM_NAME"),
608                   atom_cache_.GetAtom("UTF8_STRING"),
609                   8,
610                   PropModeReplace,
611                   reinterpret_cast<const unsigned char*>(utf8str.c_str()),
612                   utf8str.size());
613   // TODO(erg): This is technically wrong. So XStoreName and friends expect
614   // this in Host Portable Character Encoding instead of UTF-8, which I believe
615   // is Compound Text. This shouldn't matter 90% of the time since this is the
616   // fallback to the UTF8 property above.
617   XStoreName(xdisplay_, xwindow_, utf8str.c_str());
618   return true;
619 }
620
621 void DesktopWindowTreeHostX11::ClearNativeFocus() {
622   // This method is weird and misnamed. Instead of clearing the native focus,
623   // it sets the focus to our |content_window_|, which will trigger a cascade
624   // of focus changes into views.
625   if (content_window_ && aura::client::GetFocusClient(content_window_) &&
626       content_window_->Contains(
627           aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) {
628     aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
629   }
630 }
631
632 Widget::MoveLoopResult DesktopWindowTreeHostX11::RunMoveLoop(
633     const gfx::Vector2d& drag_offset,
634     Widget::MoveLoopSource source,
635     Widget::MoveLoopEscapeBehavior escape_behavior) {
636   aura::client::WindowMoveSource window_move_source =
637       source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
638       aura::client::WINDOW_MOVE_SOURCE_MOUSE :
639       aura::client::WINDOW_MOVE_SOURCE_TOUCH;
640   if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
641       window_move_source) == aura::client::MOVE_SUCCESSFUL)
642     return Widget::MOVE_LOOP_SUCCESSFUL;
643
644   return Widget::MOVE_LOOP_CANCELED;
645 }
646
647 void DesktopWindowTreeHostX11::EndMoveLoop() {
648   x11_window_move_client_->EndMoveLoop();
649 }
650
651 void DesktopWindowTreeHostX11::SetVisibilityChangedAnimationsEnabled(
652     bool value) {
653   // Much like the previous NativeWidgetGtk, we don't have anything to do here.
654 }
655
656 bool DesktopWindowTreeHostX11::ShouldUseNativeFrame() const {
657   return use_native_frame_;
658 }
659
660 bool DesktopWindowTreeHostX11::ShouldWindowContentsBeTransparent() const {
661   return false;
662 }
663
664 void DesktopWindowTreeHostX11::FrameTypeChanged() {
665   Widget::FrameType new_type =
666       native_widget_delegate_->AsWidget()->frame_type();
667   if (new_type == Widget::FRAME_TYPE_DEFAULT) {
668     // The default is determined by Widget::InitParams::remove_standard_frame
669     // and does not change.
670     return;
671   }
672
673   SetUseNativeFrame(new_type == Widget::FRAME_TYPE_FORCE_NATIVE);
674   // Replace the frame and layout the contents. Even though we don't have a
675   // swapable glass frame like on Windows, we still replace the frame because
676   // the button assets don't update otherwise.
677   native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame();
678 }
679
680 void DesktopWindowTreeHostX11::SetFullscreen(bool fullscreen) {
681   if (is_fullscreen_ == fullscreen)
682     return;
683   is_fullscreen_ = fullscreen;
684   SetWMSpecState(fullscreen,
685                  atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
686                  None);
687   // Try to guess the size we will have after the switch to/from fullscreen:
688   // - (may) avoid transient states
689   // - works around Flash content which expects to have the size updated
690   //   synchronously.
691   // See https://crbug.com/361408
692   if (fullscreen) {
693     restored_bounds_ = bounds_;
694     const gfx::Display display =
695         gfx::Screen::GetScreenFor(NULL)->GetDisplayNearestWindow(window());
696     bounds_ = display.bounds();
697   } else {
698     bounds_ = restored_bounds_;
699   }
700   OnHostMoved(bounds_.origin());
701   OnHostResized(bounds_.size());
702
703   if (HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN") == fullscreen) {
704     Relayout();
705     ResetWindowRegion();
706   }
707   // Else: the widget will be relaid out either when the window bounds change or
708   // when |xwindow_|'s fullscreen state changes.
709 }
710
711 bool DesktopWindowTreeHostX11::IsFullscreen() const {
712   return is_fullscreen_;
713 }
714
715 void DesktopWindowTreeHostX11::SetOpacity(unsigned char opacity) {
716   // X server opacity is in terms of 32 bit unsigned int space, and counts from
717   // the opposite direction.
718   // XChangeProperty() expects "cardinality" to be long.
719   unsigned long cardinality = opacity * 0x1010101;
720
721   if (cardinality == 0xffffffff) {
722     XDeleteProperty(xdisplay_, xwindow_,
723                     atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
724   } else {
725     XChangeProperty(xdisplay_, xwindow_,
726                     atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
727                     XA_CARDINAL, 32,
728                     PropModeReplace,
729                     reinterpret_cast<unsigned char*>(&cardinality), 1);
730   }
731 }
732
733 void DesktopWindowTreeHostX11::SetWindowIcons(
734     const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
735   // TODO(erg): The way we handle icons across different versions of chrome
736   // could be substantially improved. The Windows version does its own thing
737   // and only sometimes comes down this code path. The icon stuff in
738   // ChromeViewsDelegate is hard coded to use HICONs. Likewise, we're hard
739   // coded to be given two images instead of an arbitrary collection of images
740   // so that we can pass to the WM.
741   //
742   // All of this could be made much, much better.
743   std::vector<unsigned long> data;
744
745   if (window_icon.HasRepresentation(1.0f))
746     SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data);
747
748   if (app_icon.HasRepresentation(1.0f))
749     SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data);
750
751   if (data.empty())
752     XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_ICON"));
753   else
754     ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data);
755 }
756
757 void DesktopWindowTreeHostX11::InitModalType(ui::ModalType modal_type) {
758   switch (modal_type) {
759     case ui::MODAL_TYPE_NONE:
760       break;
761     default:
762       // TODO(erg): Figure out under what situations |modal_type| isn't
763       // none. The comment in desktop_native_widget_aura.cc suggests that this
764       // is rare.
765       NOTIMPLEMENTED();
766   }
767 }
768
769 void DesktopWindowTreeHostX11::FlashFrame(bool flash_frame) {
770   if (urgency_hint_set_ == flash_frame)
771     return;
772
773   XWMHints* hints = XGetWMHints(xdisplay_, xwindow_);
774   if (!hints) {
775     // The window hasn't had its hints set yet.
776     hints = XAllocWMHints();
777   }
778
779   if (flash_frame)
780     hints->flags |= XUrgencyHint;
781   else
782     hints->flags &= ~XUrgencyHint;
783
784   XSetWMHints(xdisplay_, xwindow_, hints);
785   XFree(hints);
786
787   urgency_hint_set_ = flash_frame;
788 }
789
790 void DesktopWindowTreeHostX11::OnRootViewLayout() const {
791   if (!window_mapped_)
792     return;
793
794   XSizeHints hints;
795   long supplied_return;
796   XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return);
797
798   gfx::Size minimum = native_widget_delegate_->GetMinimumSize();
799   if (minimum.IsEmpty()) {
800     hints.flags &= ~PMinSize;
801   } else {
802     hints.flags |= PMinSize;
803     hints.min_width = minimum.width();
804     hints.min_height = minimum.height();
805   }
806
807   gfx::Size maximum = native_widget_delegate_->GetMaximumSize();
808   if (maximum.IsEmpty()) {
809     hints.flags &= ~PMaxSize;
810   } else {
811     hints.flags |= PMaxSize;
812     hints.max_width = maximum.width();
813     hints.max_height = maximum.height();
814   }
815
816   XSetWMNormalHints(xdisplay_, xwindow_, &hints);
817 }
818
819 void DesktopWindowTreeHostX11::OnNativeWidgetFocus() {
820   native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
821 }
822
823 void DesktopWindowTreeHostX11::OnNativeWidgetBlur() {
824   if (xwindow_) {
825     x11_capture_.reset();
826     native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
827   }
828 }
829
830 bool DesktopWindowTreeHostX11::IsAnimatingClosed() const {
831   return false;
832 }
833
834 ////////////////////////////////////////////////////////////////////////////////
835 // DesktopWindowTreeHostX11, aura::WindowTreeHost implementation:
836
837 ui::EventSource* DesktopWindowTreeHostX11::GetEventSource() {
838   return this;
839 }
840
841 gfx::AcceleratedWidget DesktopWindowTreeHostX11::GetAcceleratedWidget() {
842   return xwindow_;
843 }
844
845 void DesktopWindowTreeHostX11::Show() {
846   ShowWindowWithState(ui::SHOW_STATE_NORMAL);
847   native_widget_delegate_->OnNativeWidgetVisibilityChanged(true);
848 }
849
850 void DesktopWindowTreeHostX11::Hide() {
851   if (window_mapped_) {
852     XWithdrawWindow(xdisplay_, xwindow_, 0);
853     window_mapped_ = false;
854   }
855   native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
856 }
857
858 gfx::Rect DesktopWindowTreeHostX11::GetBounds() const {
859   return bounds_;
860 }
861
862 void DesktopWindowTreeHostX11::SetBounds(const gfx::Rect& bounds) {
863   bool origin_changed = bounds_.origin() != bounds.origin();
864   bool size_changed = bounds_.size() != bounds.size();
865   XWindowChanges changes = {0};
866   unsigned value_mask = 0;
867
868   if (size_changed) {
869     // X11 will send an XError at our process if have a 0 sized window.
870     DCHECK_GT(bounds.width(), 0);
871     DCHECK_GT(bounds.height(), 0);
872
873     changes.width = bounds.width();
874     changes.height = bounds.height();
875     value_mask |= CWHeight | CWWidth;
876   }
877
878   if (origin_changed) {
879     changes.x = bounds.x();
880     changes.y = bounds.y();
881     value_mask |= CWX | CWY;
882   }
883   if (value_mask)
884     XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
885
886   // Assume that the resize will go through as requested, which should be the
887   // case if we're running without a window manager.  If there's a window
888   // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
889   // (possibly synthetic) ConfigureNotify about the actual size and correct
890   // |bounds_| later.
891   bounds_ = bounds;
892
893   if (origin_changed)
894     native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
895   if (size_changed) {
896     OnHostResized(bounds.size());
897     ResetWindowRegion();
898   }
899 }
900
901 gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const {
902   return bounds_.origin();
903 }
904
905 void DesktopWindowTreeHostX11::SetCapture() {
906   // This is vaguely based on the old NativeWidgetGtk implementation.
907   //
908   // X11's XPointerGrab() shouldn't be used for everything; it doesn't map
909   // cleanly to Windows' SetCapture(). GTK only provides a separate concept of
910   // a grab that wasn't the X11 pointer grab, but was instead a manual
911   // redirection of the event. (You need to drop into GDK if you want to
912   // perform a raw X11 grab).
913
914   if (g_current_capture)
915     g_current_capture->OnCaptureReleased();
916
917   g_current_capture = this;
918   x11_capture_.reset(new X11ScopedCapture(xwindow_));
919 }
920
921 void DesktopWindowTreeHostX11::ReleaseCapture() {
922   if (g_current_capture == this)
923     g_current_capture->OnCaptureReleased();
924 }
925
926 void DesktopWindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) {
927   XDefineCursor(xdisplay_, xwindow_, cursor.platform());
928 }
929
930 void DesktopWindowTreeHostX11::MoveCursorToNative(const gfx::Point& location) {
931   XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
932                bounds_.x() + location.x(), bounds_.y() + location.y());
933 }
934
935 void DesktopWindowTreeHostX11::OnCursorVisibilityChangedNative(bool show) {
936   // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
937   // the same tap-to-click disabling here that chromeos does.
938 }
939
940 void DesktopWindowTreeHostX11::PostNativeEvent(
941     const base::NativeEvent& native_event) {
942   DCHECK(xwindow_);
943   DCHECK(xdisplay_);
944   XEvent xevent = *native_event;
945   xevent.xany.display = xdisplay_;
946   xevent.xany.window = xwindow_;
947
948   switch (xevent.type) {
949     case EnterNotify:
950     case LeaveNotify:
951     case MotionNotify:
952     case KeyPress:
953     case KeyRelease:
954     case ButtonPress:
955     case ButtonRelease: {
956       // The fields used below are in the same place for all of events
957       // above. Using xmotion from XEvent's unions to avoid repeating
958       // the code.
959       xevent.xmotion.root = x_root_window_;
960       xevent.xmotion.time = CurrentTime;
961
962       gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
963       ConvertPointToNativeScreen(&point);
964       xevent.xmotion.x_root = point.x();
965       xevent.xmotion.y_root = point.y();
966     }
967     default:
968       break;
969   }
970   XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
971 }
972
973 void DesktopWindowTreeHostX11::OnDeviceScaleFactorChanged(
974     float device_scale_factor) {
975 }
976
977 ////////////////////////////////////////////////////////////////////////////////
978 // DesktopWindowTreeHostX11, ui::EventSource implementation:
979
980 ui::EventProcessor* DesktopWindowTreeHostX11::GetEventProcessor() {
981   return dispatcher();
982 }
983
984 ////////////////////////////////////////////////////////////////////////////////
985 // DesktopWindowTreeHostX11, private:
986
987 void DesktopWindowTreeHostX11::InitX11Window(
988     const Widget::InitParams& params) {
989   unsigned long attribute_mask = CWBackPixmap;
990   XSetWindowAttributes swa;
991   memset(&swa, 0, sizeof(swa));
992   swa.background_pixmap = None;
993
994   ::Atom window_type;
995   switch (params.type) {
996     case Widget::InitParams::TYPE_MENU:
997       swa.override_redirect = True;
998       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
999       break;
1000     case Widget::InitParams::TYPE_TOOLTIP:
1001       swa.override_redirect = True;
1002       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
1003       break;
1004     case Widget::InitParams::TYPE_POPUP:
1005       swa.override_redirect = True;
1006       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION");
1007       break;
1008     case Widget::InitParams::TYPE_DRAG:
1009       swa.override_redirect = True;
1010       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_DND");
1011       break;
1012     default:
1013       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
1014       break;
1015   }
1016   if (swa.override_redirect)
1017     attribute_mask |= CWOverrideRedirect;
1018
1019   // Detect whether we're running inside a compositing manager. If so, try to
1020   // use the ARGB visual. Otherwise, just use our parent's visual.
1021   Visual* visual = CopyFromParent;
1022   int depth = CopyFromParent;
1023   if (CommandLine::ForCurrentProcess()->HasSwitch(
1024           switches::kEnableTransparentVisuals) &&
1025       XGetSelectionOwner(xdisplay_,
1026                          atom_cache_.GetAtom("_NET_WM_CM_S0")) != None) {
1027     Visual* rgba_visual = GetARGBVisual();
1028     if (rgba_visual) {
1029       visual = rgba_visual;
1030       depth = 32;
1031
1032       attribute_mask |= CWColormap;
1033       swa.colormap = XCreateColormap(xdisplay_, x_root_window_, visual,
1034                                      AllocNone);
1035
1036       // x.org will BadMatch if we don't set a border when the depth isn't the
1037       // same as the parent depth.
1038       attribute_mask |= CWBorderPixel;
1039       swa.border_pixel = 0;
1040
1041       use_argb_visual_ = true;
1042     }
1043   }
1044
1045   bounds_ = params.bounds;
1046   xwindow_ = XCreateWindow(
1047       xdisplay_, x_root_window_,
1048       bounds_.x(), bounds_.y(),
1049       bounds_.width(), bounds_.height(),
1050       0,               // border width
1051       depth,
1052       InputOutput,
1053       visual,
1054       attribute_mask,
1055       &swa);
1056   if (ui::PlatformEventSource::GetInstance())
1057     ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
1058   open_windows().push_back(xwindow_);
1059
1060   // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
1061
1062   long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
1063                     KeyPressMask | KeyReleaseMask |
1064                     EnterWindowMask | LeaveWindowMask |
1065                     ExposureMask | VisibilityChangeMask |
1066                     StructureNotifyMask | PropertyChangeMask |
1067                     PointerMotionMask;
1068   XSelectInput(xdisplay_, xwindow_, event_mask);
1069   XFlush(xdisplay_);
1070
1071   if (ui::IsXInput2Available())
1072     ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
1073
1074   // TODO(erg): We currently only request window deletion events. We also
1075   // should listen for activation events and anything else that GTK+ listens
1076   // for, and do something useful.
1077   ::Atom protocols[2];
1078   protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
1079   protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
1080   XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
1081
1082   // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
1083   // the desktop environment.
1084   XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
1085
1086   // Likewise, the X server needs to know this window's pid so it knows which
1087   // program to kill if the window hangs.
1088   // XChangeProperty() expects "pid" to be long.
1089   COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
1090   long pid = params.net_wm_pid;
1091   if (!pid)
1092     pid = getpid();
1093   XChangeProperty(xdisplay_,
1094                   xwindow_,
1095                   atom_cache_.GetAtom("_NET_WM_PID"),
1096                   XA_CARDINAL,
1097                   32,
1098                   PropModeReplace,
1099                   reinterpret_cast<unsigned char*>(&pid), 1);
1100
1101   XChangeProperty(xdisplay_,
1102                   xwindow_,
1103                   atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
1104                   XA_ATOM,
1105                   32,
1106                   PropModeReplace,
1107                   reinterpret_cast<unsigned char*>(&window_type), 1);
1108
1109   // List of window state properties (_NET_WM_STATE) to set, if any.
1110   std::vector< ::Atom> state_atom_list;
1111
1112   // Remove popup windows from taskbar unless overridden.
1113   if ((params.type == Widget::InitParams::TYPE_POPUP ||
1114        params.type == Widget::InitParams::TYPE_BUBBLE) &&
1115       !params.force_show_in_taskbar) {
1116     state_atom_list.push_back(
1117         atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
1118   }
1119
1120   // If the window should stay on top of other windows, add the
1121   // _NET_WM_STATE_ABOVE property.
1122   is_always_on_top_ = params.keep_on_top;
1123   if (is_always_on_top_)
1124     state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
1125
1126   if (params.visible_on_all_workspaces) {
1127     state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_STICKY"));
1128     ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllDesktops);
1129   }
1130
1131   // Setting _NET_WM_STATE by sending a message to the root_window (with
1132   // SetWMSpecState) has no effect here since the window has not yet been
1133   // mapped. So we manually change the state.
1134   if (!state_atom_list.empty()) {
1135     ui::SetAtomArrayProperty(xwindow_,
1136                              "_NET_WM_STATE",
1137                              "ATOM",
1138                              state_atom_list);
1139   }
1140
1141   if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
1142     ui::SetWindowClassHint(
1143         xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
1144   }
1145   if (!params.wm_role_name.empty() ||
1146       params.type == Widget::InitParams::TYPE_POPUP) {
1147     const char kX11WindowRolePopup[] = "popup";
1148     ui::SetWindowRole(xdisplay_, xwindow_, params.wm_role_name.empty() ?
1149                       std::string(kX11WindowRolePopup) : params.wm_role_name);
1150   }
1151
1152   if (params.remove_standard_frame) {
1153     // Setting _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED tells gnome-shell to not force
1154     // fullscreen on the window when it matches the desktop size.
1155     ui::SetHideTitlebarWhenMaximizedProperty(xwindow_,
1156                                              ui::HIDE_TITLEBAR_WHEN_MAXIMIZED);
1157   }
1158
1159   // If we have a parent, record the parent/child relationship. We use this
1160   // data during destruction to make sure that when we try to close a parent
1161   // window, we also destroy all child windows.
1162   if (params.parent && params.parent->GetHost()) {
1163     XID parent_xid =
1164         params.parent->GetHost()->GetAcceleratedWidget();
1165     window_parent_ = GetHostForXID(parent_xid);
1166     DCHECK(window_parent_);
1167     window_parent_->window_children_.insert(this);
1168   }
1169
1170   // If we have a delegate which is providing a default window icon, use that
1171   // icon.
1172   gfx::ImageSkia* window_icon = ViewsDelegate::views_delegate ?
1173       ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL;
1174   if (window_icon) {
1175     SetWindowIcons(gfx::ImageSkia(), *window_icon);
1176   }
1177   CreateCompositor(GetAcceleratedWidget());
1178 }
1179
1180 void DesktopWindowTreeHostX11::OnWMStateUpdated() {
1181   std::vector< ::Atom> atom_list;
1182   if (!ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list))
1183     return;
1184
1185   bool was_minimized = IsMinimized();
1186
1187   window_properties_.clear();
1188   std::copy(atom_list.begin(), atom_list.end(),
1189             inserter(window_properties_, window_properties_.begin()));
1190
1191   // Propagate the window minimization information to the content window, so
1192   // the render side can update its visibility properly. OnWMStateUpdated() is
1193   // called by PropertyNofify event from DispatchEvent() when the browser is
1194   // minimized or shown from minimized state. On Windows, this is realized by
1195   // calling OnHostResized() with an empty size. In particular,
1196   // HWNDMessageHandler::GetClientAreaBounds() returns an empty size when the
1197   // window is minimized. On Linux, returning empty size in GetBounds() or
1198   // SetBounds() does not work.
1199   bool is_minimized = IsMinimized();
1200   if (is_minimized != was_minimized) {
1201     if (is_minimized)
1202       content_window_->Hide();
1203     else
1204       content_window_->Show();
1205   }
1206
1207   if (restored_bounds_.IsEmpty()) {
1208     DCHECK(!IsFullscreen());
1209     if (IsMaximized()) {
1210       // The request that we become maximized originated from a different
1211       // process. |bounds_| already contains our maximized bounds. Do a best
1212       // effort attempt to get restored bounds by setting it to our previously
1213       // set bounds (and if we get this wrong, we aren't any worse off since
1214       // we'd otherwise be returning our maximized bounds).
1215       restored_bounds_ = previous_bounds_;
1216     }
1217   } else if (!IsMaximized() && !IsFullscreen()) {
1218     // If we have restored bounds, but WM_STATE no longer claims to be
1219     // maximized or fullscreen, we should clear our restored bounds.
1220     restored_bounds_ = gfx::Rect();
1221   }
1222
1223   // Ignore requests by the window manager to enter or exit fullscreen (e.g. as
1224   // a result of pressing a window manager accelerator key). Chrome does not
1225   // handle window manager initiated fullscreen. In particular, Chrome needs to
1226   // do preprocessing before the x window's fullscreen state is toggled.
1227
1228   is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE");
1229
1230   // Now that we have different window properties, we may need to relayout the
1231   // window. (The windows code doesn't need this because their window change is
1232   // synchronous.)
1233   Relayout();
1234   ResetWindowRegion();
1235 }
1236
1237 void DesktopWindowTreeHostX11::OnFrameExtentsUpdated() {
1238   std::vector<int> insets;
1239   if (ui::GetIntArrayProperty(xwindow_, "_NET_FRAME_EXTENTS", &insets) &&
1240       insets.size() == 4) {
1241     // |insets| are returned in the order: [left, right, top, bottom].
1242     native_window_frame_borders_ = gfx::Insets(
1243         insets[2],
1244         insets[0],
1245         insets[3],
1246         insets[1]);
1247   } else {
1248     native_window_frame_borders_ = gfx::Insets();
1249   }
1250 }
1251
1252 void DesktopWindowTreeHostX11::UpdateWMUserTime(
1253     const ui::PlatformEvent& event) {
1254   if (!IsActive())
1255     return;
1256
1257   ui::EventType type = ui::EventTypeFromNative(event);
1258   if (type == ui::ET_MOUSE_PRESSED ||
1259       type == ui::ET_KEY_PRESSED ||
1260       type == ui::ET_TOUCH_PRESSED) {
1261     unsigned long wm_user_time_ms = static_cast<unsigned long>(
1262         ui::EventTimeFromNative(event).InMilliseconds());
1263     XChangeProperty(xdisplay_,
1264                     xwindow_,
1265                     atom_cache_.GetAtom("_NET_WM_USER_TIME"),
1266                     XA_CARDINAL,
1267                     32,
1268                     PropModeReplace,
1269                     reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
1270                     1);
1271     X11DesktopHandler::get()->set_wm_user_time_ms(wm_user_time_ms);
1272   }
1273 }
1274
1275 void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled,
1276                                                 ::Atom state1,
1277                                                 ::Atom state2) {
1278   XEvent xclient;
1279   memset(&xclient, 0, sizeof(xclient));
1280   xclient.type = ClientMessage;
1281   xclient.xclient.window = xwindow_;
1282   xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
1283   xclient.xclient.format = 32;
1284   xclient.xclient.data.l[0] =
1285       enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
1286   xclient.xclient.data.l[1] = state1;
1287   xclient.xclient.data.l[2] = state2;
1288   xclient.xclient.data.l[3] = 1;
1289   xclient.xclient.data.l[4] = 0;
1290
1291   XSendEvent(xdisplay_, x_root_window_, False,
1292              SubstructureRedirectMask | SubstructureNotifyMask,
1293              &xclient);
1294 }
1295
1296 bool DesktopWindowTreeHostX11::HasWMSpecProperty(const char* property) const {
1297   return window_properties_.find(atom_cache_.GetAtom(property)) !=
1298       window_properties_.end();
1299 }
1300
1301 void DesktopWindowTreeHostX11::SetUseNativeFrame(bool use_native_frame) {
1302   use_native_frame_ = use_native_frame;
1303   ui::SetUseOSWindowFrame(xwindow_, use_native_frame);
1304   ResetWindowRegion();
1305 }
1306
1307 void DesktopWindowTreeHostX11::OnCaptureReleased() {
1308   x11_capture_.reset();
1309   g_current_capture = NULL;
1310   OnHostLostWindowCapture();
1311   native_widget_delegate_->OnMouseCaptureLost();
1312 }
1313
1314 void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
1315   // In Windows, the native events sent to chrome are separated into client
1316   // and non-client versions of events, which we record on our LocatedEvent
1317   // structures. On X11, we emulate the concept of non-client. Before we pass
1318   // this event to the cross platform event handling framework, we need to
1319   // make sure it is appropriately marked as non-client if it's in the non
1320   // client area, or otherwise, we can get into a state where the a window is
1321   // set as the |mouse_pressed_handler_| in window_event_dispatcher.cc
1322   // despite the mouse button being released.
1323   //
1324   // We can't do this later in the dispatch process because we share that
1325   // with ash, and ash gets confused about event IS_NON_CLIENT-ness on
1326   // events, since ash doesn't expect this bit to be set, because it's never
1327   // been set before. (This works on ash on Windows because none of the mouse
1328   // events on the ash desktop are clicking in what Windows considers to be a
1329   // non client area.) Likewise, we won't want to do the following in any
1330   // WindowTreeHost that hosts ash.
1331   if (content_window_ && content_window_->delegate()) {
1332     int flags = event->flags();
1333     int hit_test_code =
1334         content_window_->delegate()->GetNonClientComponent(event->location());
1335     if (hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE)
1336       flags |= ui::EF_IS_NON_CLIENT;
1337     event->set_flags(flags);
1338   }
1339
1340   // While we unset the urgency hint when we gain focus, we also must remove it
1341   // on mouse clicks because we can call FlashFrame() on an active window.
1342   if (event->IsAnyButton() || event->IsMouseWheelEvent())
1343     FlashFrame(false);
1344
1345   if (!g_current_capture || g_current_capture == this) {
1346     SendEventToProcessor(event);
1347   } else {
1348     // Another DesktopWindowTreeHostX11 has installed itself as
1349     // capture. Translate the event's location and dispatch to the other.
1350     event->ConvertLocationToTarget(window(), g_current_capture->window());
1351     g_current_capture->SendEventToProcessor(event);
1352   }
1353 }
1354
1355 void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) {
1356   if (g_current_capture && g_current_capture != this &&
1357       event->type() == ui::ET_TOUCH_PRESSED) {
1358     event->ConvertLocationToTarget(window(), g_current_capture->window());
1359     g_current_capture->SendEventToProcessor(event);
1360   } else {
1361     SendEventToProcessor(event);
1362   }
1363 }
1364
1365 void DesktopWindowTreeHostX11::ResetWindowRegion() {
1366   // If a custom window shape was supplied then apply it.
1367   if (custom_window_shape_) {
1368     XShapeCombineRegion(
1369         xdisplay_, xwindow_, ShapeBounding, 0, 0, window_shape_, false);
1370     return;
1371   }
1372
1373   if (window_shape_)
1374     XDestroyRegion(window_shape_);
1375   window_shape_ = NULL;
1376
1377   if (!IsMaximized() && !IsFullscreen()) {
1378     gfx::Path window_mask;
1379     views::Widget* widget = native_widget_delegate_->AsWidget();
1380     if (widget->non_client_view()) {
1381       // Some frame views define a custom (non-rectangular) window mask. If
1382       // so, use it to define the window shape. If not, fall through.
1383       widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask);
1384       if (window_mask.countPoints() > 0) {
1385         window_shape_ = gfx::CreateRegionFromSkPath(window_mask);
1386         XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding,
1387                             0, 0, window_shape_, false);
1388         return;
1389       }
1390     }
1391   }
1392
1393   // If we didn't set the shape for any reason, reset the shaping information.
1394   // How this is done depends on the border style, due to quirks and bugs in
1395   // various window managers.
1396   if (ShouldUseNativeFrame()) {
1397     // If the window has system borders, the mask must be set to null (not a
1398     // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will
1399     // not put borders on a window with a custom shape.
1400     XShapeCombineMask(xdisplay_, xwindow_, ShapeBounding, 0, 0, None, ShapeSet);
1401   } else {
1402     // Conversely, if the window does not have system borders, the mask must be
1403     // manually set to a rectangle that covers the whole window (not null). This
1404     // is due to a bug in KWin <= 4.11.5 (KDE bug #330573) where setting a null
1405     // shape causes the hint to disable system borders to be ignored (resulting
1406     // in a double border).
1407     XRectangle r = {0, 0, static_cast<unsigned short>(bounds_.width()),
1408                     static_cast<unsigned short>(bounds_.height())};
1409     XShapeCombineRectangles(
1410         xdisplay_, xwindow_, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded);
1411   }
1412 }
1413
1414 void DesktopWindowTreeHostX11::SerializeImageRepresentation(
1415     const gfx::ImageSkiaRep& rep,
1416     std::vector<unsigned long>* data) {
1417   int width = rep.GetWidth();
1418   data->push_back(width);
1419
1420   int height = rep.GetHeight();
1421   data->push_back(height);
1422
1423   const SkBitmap& bitmap = rep.sk_bitmap();
1424   SkAutoLockPixels locker(bitmap);
1425
1426   for (int y = 0; y < height; ++y)
1427     for (int x = 0; x < width; ++x)
1428       data->push_back(bitmap.getColor(x, y));
1429 }
1430
1431 Visual* DesktopWindowTreeHostX11::GetARGBVisual() {
1432   XVisualInfo visual_template;
1433   visual_template.screen = 0;
1434   Visual* to_return = NULL;
1435
1436   int visuals_len;
1437   XVisualInfo* visual_list = XGetVisualInfo(xdisplay_,
1438                                             VisualScreenMask,
1439                                             &visual_template, &visuals_len);
1440   for (int i = 0; i < visuals_len; ++i) {
1441     // Why support only 8888 ARGB? Because it's all that GTK+ supports. In
1442     // gdkvisual-x11.cc, they look for this specific visual and use it for all
1443     // their alpha channel using needs.
1444     //
1445     // TODO(erg): While the following does find a valid visual, some GL drivers
1446     // don't believe that this has an alpha channel. According to marcheu@,
1447     // this should work on open source driver though. (It doesn't work with
1448     // NVidia's binaries currently.) http://crbug.com/369209
1449     if (visual_list[i].depth == 32 &&
1450         visual_list[i].visual->red_mask == 0xff0000 &&
1451         visual_list[i].visual->green_mask == 0x00ff00 &&
1452         visual_list[i].visual->blue_mask == 0x0000ff) {
1453       to_return = visual_list[i].visual;
1454       break;
1455     }
1456   }
1457
1458   if (visual_list)
1459     XFree(visual_list);
1460
1461   return to_return;
1462 }
1463
1464 std::list<XID>& DesktopWindowTreeHostX11::open_windows() {
1465   if (!open_windows_)
1466     open_windows_ = new std::list<XID>();
1467   return *open_windows_;
1468 }
1469
1470 void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) {
1471   if (show_state != ui::SHOW_STATE_DEFAULT &&
1472       show_state != ui::SHOW_STATE_NORMAL &&
1473       show_state != ui::SHOW_STATE_INACTIVE) {
1474     // It will behave like SHOW_STATE_NORMAL.
1475     NOTIMPLEMENTED();
1476   }
1477
1478   // Before we map the window, set size hints. Otherwise, some window managers
1479   // will ignore toplevel XMoveWindow commands.
1480   XSizeHints size_hints;
1481   size_hints.flags = PPosition;
1482   size_hints.x = bounds_.x();
1483   size_hints.y = bounds_.y();
1484   XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
1485
1486   // If SHOW_STATE_INACTIVE, tell the window manager not to focus the window
1487   // when mapping. This is done by setting the _NET_WM_USER_TIME to 0. See e.g.
1488   // http://standards.freedesktop.org/wm-spec/latest/ar01s05.html
1489   unsigned long wm_user_time_ms = (show_state == ui::SHOW_STATE_INACTIVE) ?
1490       0 : X11DesktopHandler::get()->wm_user_time_ms();
1491   if (show_state == ui::SHOW_STATE_INACTIVE || wm_user_time_ms != 0) {
1492     XChangeProperty(xdisplay_,
1493                     xwindow_,
1494                     atom_cache_.GetAtom("_NET_WM_USER_TIME"),
1495                     XA_CARDINAL,
1496                     32,
1497                     PropModeReplace,
1498                     reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
1499                     1);
1500   }
1501
1502   XMapWindow(xdisplay_, xwindow_);
1503
1504   // We now block until our window is mapped. Some X11 APIs will crash and
1505   // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
1506   // asynchronous.
1507   if (ui::X11EventSource::GetInstance())
1508     ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_);
1509   window_mapped_ = true;
1510 }
1511
1512 void DesktopWindowTreeHostX11::SetWindowTransparency() {
1513   compositor()->SetHostHasTransparentBackground(use_argb_visual_);
1514   window()->SetTransparent(use_argb_visual_);
1515   content_window_->SetTransparent(use_argb_visual_);
1516 }
1517
1518 void DesktopWindowTreeHostX11::Relayout() {
1519   Widget* widget = native_widget_delegate_->AsWidget();
1520   NonClientView* non_client_view = widget->non_client_view();
1521   // non_client_view may be NULL, especially during creation.
1522   if (non_client_view) {
1523     non_client_view->client_view()->InvalidateLayout();
1524     non_client_view->InvalidateLayout();
1525   }
1526   widget->GetRootView()->Layout();
1527 }
1528
1529 ////////////////////////////////////////////////////////////////////////////////
1530 // DesktopWindowTreeHostX11, ui::PlatformEventDispatcher implementation:
1531
1532 bool DesktopWindowTreeHostX11::CanDispatchEvent(
1533     const ui::PlatformEvent& event) {
1534   return event->xany.window == xwindow_ ||
1535          (event->type == GenericEvent &&
1536           static_cast<XIDeviceEvent*>(event->xcookie.data)->event == xwindow_);
1537 }
1538
1539 uint32_t DesktopWindowTreeHostX11::DispatchEvent(
1540     const ui::PlatformEvent& event) {
1541   XEvent* xev = event;
1542
1543   TRACE_EVENT1("views", "DesktopWindowTreeHostX11::Dispatch",
1544                "event->type", event->type);
1545
1546   UpdateWMUserTime(event);
1547
1548   // May want to factor CheckXEventForConsistency(xev); into a common location
1549   // since it is called here.
1550   switch (xev->type) {
1551     case EnterNotify:
1552     case LeaveNotify: {
1553       // Ignore EventNotify and LeaveNotify events from children of |xwindow_|.
1554       // NativeViewGLSurfaceGLX adds a child to |xwindow_|.
1555       // TODO(pkotwicz|tdanderson): Figure out whether the suppression is
1556       // necessary. crbug.com/385716
1557       if (xev->xcrossing.detail == NotifyInferior)
1558         break;
1559
1560       ui::MouseEvent mouse_event(xev);
1561       DispatchMouseEvent(&mouse_event);
1562       break;
1563     }
1564     case Expose: {
1565       gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
1566                             xev->xexpose.width, xev->xexpose.height);
1567       compositor()->ScheduleRedrawRect(damage_rect);
1568       break;
1569     }
1570     case KeyPress: {
1571       ui::KeyEvent keydown_event(xev, false);
1572       SendEventToProcessor(&keydown_event);
1573       break;
1574     }
1575     case KeyRelease: {
1576       ui::KeyEvent keyup_event(xev, false);
1577       SendEventToProcessor(&keyup_event);
1578       break;
1579     }
1580     case ButtonPress:
1581     case ButtonRelease: {
1582       ui::EventType event_type = ui::EventTypeFromNative(xev);
1583       switch (event_type) {
1584         case ui::ET_MOUSEWHEEL: {
1585           ui::MouseWheelEvent mouseev(xev);
1586           DispatchMouseEvent(&mouseev);
1587           break;
1588         }
1589         case ui::ET_MOUSE_PRESSED:
1590         case ui::ET_MOUSE_RELEASED: {
1591           ui::MouseEvent mouseev(xev);
1592           DispatchMouseEvent(&mouseev);
1593           break;
1594         }
1595         case ui::ET_UNKNOWN:
1596           // No event is created for X11-release events for mouse-wheel buttons.
1597           break;
1598         default:
1599           NOTREACHED() << event_type;
1600       }
1601       break;
1602     }
1603     case FocusOut:
1604       if (xev->xfocus.mode != NotifyGrab) {
1605         ReleaseCapture();
1606         OnHostLostWindowCapture();
1607         X11DesktopHandler::get()->ProcessXEvent(xev);
1608       } else {
1609         dispatcher()->OnHostLostMouseGrab();
1610       }
1611       break;
1612     case FocusIn:
1613       X11DesktopHandler::get()->ProcessXEvent(xev);
1614       break;
1615     case ConfigureNotify: {
1616       DCHECK_EQ(xwindow_, xev->xconfigure.window);
1617       DCHECK_EQ(xwindow_, xev->xconfigure.event);
1618       // It's possible that the X window may be resized by some other means than
1619       // from within aura (e.g. the X window manager can change the size). Make
1620       // sure the root window size is maintained properly.
1621       int translated_x = xev->xconfigure.x;
1622       int translated_y = xev->xconfigure.y;
1623       if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
1624         Window unused;
1625         XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_,
1626             0, 0, &translated_x, &translated_y, &unused);
1627       }
1628       gfx::Rect bounds(translated_x, translated_y,
1629                        xev->xconfigure.width, xev->xconfigure.height);
1630       bool size_changed = bounds_.size() != bounds.size();
1631       bool origin_changed = bounds_.origin() != bounds.origin();
1632       previous_bounds_ = bounds_;
1633       bounds_ = bounds;
1634       if (size_changed)
1635         OnHostResized(bounds.size());
1636       if (origin_changed)
1637         OnHostMoved(bounds_.origin());
1638       if (size_changed)
1639         ResetWindowRegion();
1640       break;
1641     }
1642     case GenericEvent: {
1643       ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
1644       if (!factory->ShouldProcessXI2Event(xev))
1645         break;
1646
1647       ui::EventType type = ui::EventTypeFromNative(xev);
1648       XEvent last_event;
1649       int num_coalesced = 0;
1650
1651       switch (type) {
1652         case ui::ET_TOUCH_MOVED:
1653           num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1654           if (num_coalesced > 0)
1655             xev = &last_event;
1656           // fallthrough
1657         case ui::ET_TOUCH_PRESSED:
1658         case ui::ET_TOUCH_RELEASED: {
1659           ui::TouchEvent touchev(xev);
1660           DispatchTouchEvent(&touchev);
1661           break;
1662         }
1663         case ui::ET_MOUSE_MOVED:
1664         case ui::ET_MOUSE_DRAGGED:
1665         case ui::ET_MOUSE_PRESSED:
1666         case ui::ET_MOUSE_RELEASED:
1667         case ui::ET_MOUSE_ENTERED:
1668         case ui::ET_MOUSE_EXITED: {
1669           if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
1670             // If this is a motion event, we want to coalesce all pending motion
1671             // events that are at the top of the queue.
1672             num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1673             if (num_coalesced > 0)
1674               xev = &last_event;
1675           }
1676           ui::MouseEvent mouseev(xev);
1677           DispatchMouseEvent(&mouseev);
1678           break;
1679         }
1680         case ui::ET_MOUSEWHEEL: {
1681           ui::MouseWheelEvent mouseev(xev);
1682           DispatchMouseEvent(&mouseev);
1683           break;
1684         }
1685         case ui::ET_SCROLL_FLING_START:
1686         case ui::ET_SCROLL_FLING_CANCEL:
1687         case ui::ET_SCROLL: {
1688           ui::ScrollEvent scrollev(xev);
1689           SendEventToProcessor(&scrollev);
1690           break;
1691         }
1692         case ui::ET_UNKNOWN:
1693           break;
1694         default:
1695           NOTREACHED();
1696       }
1697
1698       // If we coalesced an event we need to free its cookie.
1699       if (num_coalesced > 0)
1700         XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
1701       break;
1702     }
1703     case MapNotify: {
1704       FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1705                         observer_list_,
1706                         OnWindowMapped(xwindow_));
1707       break;
1708     }
1709     case UnmapNotify: {
1710       FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1711                         observer_list_,
1712                         OnWindowUnmapped(xwindow_));
1713       break;
1714     }
1715     case ClientMessage: {
1716       Atom message_type = xev->xclient.message_type;
1717       if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
1718         Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
1719         if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
1720           // We have received a close message from the window manager.
1721           OnHostCloseRequested();
1722         } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
1723           XEvent reply_event = *xev;
1724           reply_event.xclient.window = x_root_window_;
1725
1726           XSendEvent(xdisplay_,
1727                      reply_event.xclient.window,
1728                      False,
1729                      SubstructureRedirectMask | SubstructureNotifyMask,
1730                      &reply_event);
1731         }
1732       } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
1733         drag_drop_client_->OnXdndEnter(xev->xclient);
1734       } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
1735         drag_drop_client_->OnXdndLeave(xev->xclient);
1736       } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
1737         drag_drop_client_->OnXdndPosition(xev->xclient);
1738       } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
1739         drag_drop_client_->OnXdndStatus(xev->xclient);
1740       } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
1741         drag_drop_client_->OnXdndFinished(xev->xclient);
1742       } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
1743         drag_drop_client_->OnXdndDrop(xev->xclient);
1744       }
1745       break;
1746     }
1747     case MappingNotify: {
1748       switch (xev->xmapping.request) {
1749         case MappingModifier:
1750         case MappingKeyboard:
1751           XRefreshKeyboardMapping(&xev->xmapping);
1752           break;
1753         case MappingPointer:
1754           ui::DeviceDataManager::GetInstance()->UpdateButtonMap();
1755           break;
1756         default:
1757           NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
1758           break;
1759       }
1760       break;
1761     }
1762     case MotionNotify: {
1763       // Discard all but the most recent motion event that targets the same
1764       // window with unchanged state.
1765       XEvent last_event;
1766       while (XPending(xev->xany.display)) {
1767         XEvent next_event;
1768         XPeekEvent(xev->xany.display, &next_event);
1769         if (next_event.type == MotionNotify &&
1770             next_event.xmotion.window == xev->xmotion.window &&
1771             next_event.xmotion.subwindow == xev->xmotion.subwindow &&
1772             next_event.xmotion.state == xev->xmotion.state) {
1773           XNextEvent(xev->xany.display, &last_event);
1774           xev = &last_event;
1775         } else {
1776           break;
1777         }
1778       }
1779
1780       ui::MouseEvent mouseev(xev);
1781       DispatchMouseEvent(&mouseev);
1782       break;
1783     }
1784     case PropertyNotify: {
1785       ::Atom changed_atom = xev->xproperty.atom;
1786       if (changed_atom == atom_cache_.GetAtom("_NET_WM_STATE"))
1787         OnWMStateUpdated();
1788       else if (changed_atom == atom_cache_.GetAtom("_NET_FRAME_EXTENTS"))
1789         OnFrameExtentsUpdated();
1790       break;
1791     }
1792     case SelectionNotify: {
1793       drag_drop_client_->OnSelectionNotify(xev->xselection);
1794       break;
1795     }
1796   }
1797   return ui::POST_DISPATCH_STOP_PROPAGATION;
1798 }
1799
1800 ////////////////////////////////////////////////////////////////////////////////
1801 // DesktopWindowTreeHost, public:
1802
1803 // static
1804 DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
1805     internal::NativeWidgetDelegate* native_widget_delegate,
1806     DesktopNativeWidgetAura* desktop_native_widget_aura) {
1807   return new DesktopWindowTreeHostX11(native_widget_delegate,
1808                                       desktop_native_widget_aura);
1809 }
1810
1811 // static
1812 ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) {
1813   const views::LinuxUI* linux_ui = views::LinuxUI::instance();
1814   if (linux_ui) {
1815     ui::NativeTheme* native_theme = linux_ui->GetNativeTheme(window);
1816     if (native_theme)
1817       return native_theme;
1818   }
1819
1820   return ui::NativeTheme::instance();
1821 }
1822
1823 }  // namespace views