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