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