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
56namespace views {
57
58DesktopWindowTreeHostX11* DesktopWindowTreeHostX11::g_current_capture =
59    NULL;
60std::list<XID>* DesktopWindowTreeHostX11::open_windows_ = NULL;
61
62DEFINE_WINDOW_PROPERTY_KEY(
63    aura::Window*, kViewsWindowForRootWindow, NULL);
64
65DEFINE_WINDOW_PROPERTY_KEY(
66    DesktopWindowTreeHostX11*, kHostForRootWindow, NULL);
67
68namespace {
69
70// Constants that are part of EWMH.
71const int k_NET_WM_STATE_ADD = 1;
72const 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.
76const int kAllDesktops = 0xFFFFFFFF;
77
78const 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
129DesktopWindowTreeHostX11::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
153DesktopWindowTreeHostX11::~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
163aura::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
170DesktopWindowTreeHostX11* 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
177std::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
186gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowBounds() const {
187  return bounds_;
188}
189
190gfx::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
200void 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
216void DesktopWindowTreeHostX11::AddObserver(
217    views::DesktopWindowTreeHostObserverX11* observer) {
218  observer_list_.AddObserver(observer);
219}
220
221void DesktopWindowTreeHostX11::RemoveObserver(
222    views::DesktopWindowTreeHostObserverX11* observer) {
223  observer_list_.RemoveObserver(observer);
224}
225
226void 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
236void DesktopWindowTreeHostX11::CleanUpWindowList() {
237  delete open_windows_;
238  open_windows_ = NULL;
239}
240
241////////////////////////////////////////////////////////////////////////////////
242// DesktopWindowTreeHostX11, DesktopWindowTreeHost implementation:
243
244void 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
262void 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
285scoped_ptr<corewm::Tooltip> DesktopWindowTreeHostX11::CreateTooltip() {
286  return scoped_ptr<corewm::Tooltip>(
287      new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE));
288}
289
290scoped_ptr<aura::client::DragDropClient>
291DesktopWindowTreeHostX11::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
299void 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
315void 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
359aura::WindowTreeHost* DesktopWindowTreeHostX11::AsWindowTreeHost() {
360  return this;
361}
362
363void 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
376void 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
383bool DesktopWindowTreeHostX11::IsVisible() const {
384  return window_mapped_;
385}
386
387void 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
398void DesktopWindowTreeHostX11::StackAtTop() {
399  XRaiseWindow(xdisplay_, xwindow_);
400}
401
402void 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
428void 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
446gfx::Rect DesktopWindowTreeHostX11::GetWindowBoundsInScreen() const {
447  return bounds_;
448}
449
450gfx::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
462gfx::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
473gfx::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
494void 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
508void DesktopWindowTreeHostX11::Activate() {
509  if (!window_mapped_)
510    return;
511
512  X11DesktopHandler::get()->ActivateWindow(xwindow_);
513}
514
515void DesktopWindowTreeHostX11::Deactivate() {
516  if (!IsActive())
517    return;
518
519  ReleaseCapture();
520  X11DesktopHandler::get()->DeactivateWindow(xwindow_);
521}
522
523bool DesktopWindowTreeHostX11::IsActive() const {
524  return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
525}
526
527void 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
558void DesktopWindowTreeHostX11::Minimize() {
559  ReleaseCapture();
560  XIconifyWindow(xdisplay_, xwindow_, 0);
561}
562
563void 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
572bool DesktopWindowTreeHostX11::IsMaximized() const {
573  return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") &&
574          HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
575}
576
577bool DesktopWindowTreeHostX11::IsMinimized() const {
578  return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
579}
580
581bool DesktopWindowTreeHostX11::HasCapture() const {
582  return g_current_capture == this;
583}
584
585void 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
592bool DesktopWindowTreeHostX11::IsAlwaysOnTop() const {
593  return is_always_on_top_;
594}
595
596void 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
625bool 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
648void 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
659Widget::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
674void DesktopWindowTreeHostX11::EndMoveLoop() {
675  x11_window_move_client_->EndMoveLoop();
676}
677
678void DesktopWindowTreeHostX11::SetVisibilityChangedAnimationsEnabled(
679    bool value) {
680  // Much like the previous NativeWidgetGtk, we don't have anything to do here.
681}
682
683bool DesktopWindowTreeHostX11::ShouldUseNativeFrame() const {
684  return use_native_frame_;
685}
686
687bool DesktopWindowTreeHostX11::ShouldWindowContentsBeTransparent() const {
688  return false;
689}
690
691void 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
707void 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
753bool DesktopWindowTreeHostX11::IsFullscreen() const {
754  return is_fullscreen_;
755}
756
757void 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
775void 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
799void 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
811void 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
832void DesktopWindowTreeHostX11::OnRootViewLayout() {
833  UpdateMinAndMaxSize();
834}
835
836void DesktopWindowTreeHostX11::OnNativeWidgetFocus() {
837  native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
838}
839
840void DesktopWindowTreeHostX11::OnNativeWidgetBlur() {
841  if (xwindow_)
842    native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
843}
844
845bool DesktopWindowTreeHostX11::IsAnimatingClosed() const {
846  return false;
847}
848
849bool DesktopWindowTreeHostX11::IsTranslucentWindowOpacitySupported() const {
850  return false;
851}
852
853void DesktopWindowTreeHostX11::SizeConstraintsChanged() {
854  UpdateMinAndMaxSize();
855}
856
857////////////////////////////////////////////////////////////////////////////////
858// DesktopWindowTreeHostX11, aura::WindowTreeHost implementation:
859
860ui::EventSource* DesktopWindowTreeHostX11::GetEventSource() {
861  return this;
862}
863
864gfx::AcceleratedWidget DesktopWindowTreeHostX11::GetAcceleratedWidget() {
865  return xwindow_;
866}
867
868void DesktopWindowTreeHostX11::Show() {
869  ShowWindowWithState(ui::SHOW_STATE_NORMAL);
870  native_widget_delegate_->OnNativeWidgetVisibilityChanged(true);
871}
872
873void DesktopWindowTreeHostX11::Hide() {
874  if (window_mapped_) {
875    XWithdrawWindow(xdisplay_, xwindow_, 0);
876    window_mapped_ = false;
877  }
878  native_widget_delegate_->OnNativeWidgetVisibilityChanged(false);
879}
880
881gfx::Rect DesktopWindowTreeHostX11::GetBounds() const {
882  return bounds_;
883}
884
885void 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
935gfx::Point DesktopWindowTreeHostX11::GetLocationOnNativeScreen() const {
936  return bounds_.origin();
937}
938
939void 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
961void 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
973void DesktopWindowTreeHostX11::SetCursorNative(gfx::NativeCursor cursor) {
974  XDefineCursor(xdisplay_, xwindow_, cursor.platform());
975}
976
977void 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
982void 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
987void 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
1023ui::EventProcessor* DesktopWindowTreeHostX11::GetEventProcessor() {
1024  return dispatcher();
1025}
1026
1027////////////////////////////////////////////////////////////////////////////////
1028// DesktopWindowTreeHostX11, private:
1029
1030void 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 = getpid();
1135  XChangeProperty(xdisplay_,
1136                  xwindow_,
1137                  atom_cache_.GetAtom("_NET_WM_PID"),
1138                  XA_CARDINAL,
1139                  32,
1140                  PropModeReplace,
1141                  reinterpret_cast<unsigned char*>(&pid), 1);
1142
1143  XChangeProperty(xdisplay_,
1144                  xwindow_,
1145                  atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
1146                  XA_ATOM,
1147                  32,
1148                  PropModeReplace,
1149                  reinterpret_cast<unsigned char*>(&window_type), 1);
1150
1151  // List of window state properties (_NET_WM_STATE) to set, if any.
1152  std::vector< ::Atom> state_atom_list;
1153
1154  // Remove popup windows from taskbar unless overridden.
1155  if ((params.type == Widget::InitParams::TYPE_POPUP ||
1156       params.type == Widget::InitParams::TYPE_BUBBLE) &&
1157      !params.force_show_in_taskbar) {
1158    state_atom_list.push_back(
1159        atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
1160  }
1161
1162  // If the window should stay on top of other windows, add the
1163  // _NET_WM_STATE_ABOVE property.
1164  is_always_on_top_ = params.keep_on_top;
1165  if (is_always_on_top_)
1166    state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
1167
1168  if (params.visible_on_all_workspaces) {
1169    state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_STICKY"));
1170    ui::SetIntProperty(xwindow_, "_NET_WM_DESKTOP", "CARDINAL", kAllDesktops);
1171  }
1172
1173  // Setting _NET_WM_STATE by sending a message to the root_window (with
1174  // SetWMSpecState) has no effect here since the window has not yet been
1175  // mapped. So we manually change the state.
1176  if (!state_atom_list.empty()) {
1177    ui::SetAtomArrayProperty(xwindow_,
1178                             "_NET_WM_STATE",
1179                             "ATOM",
1180                             state_atom_list);
1181  }
1182
1183  if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
1184    ui::SetWindowClassHint(
1185        xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
1186  }
1187  if (!params.wm_role_name.empty() ||
1188      params.type == Widget::InitParams::TYPE_POPUP) {
1189    const char kX11WindowRolePopup[] = "popup";
1190    ui::SetWindowRole(xdisplay_, xwindow_, params.wm_role_name.empty() ?
1191                      std::string(kX11WindowRolePopup) : params.wm_role_name);
1192  }
1193
1194  if (params.remove_standard_frame) {
1195    // Setting _GTK_HIDE_TITLEBAR_WHEN_MAXIMIZED tells gnome-shell to not force
1196    // fullscreen on the window when it matches the desktop size.
1197    ui::SetHideTitlebarWhenMaximizedProperty(xwindow_,
1198                                             ui::HIDE_TITLEBAR_WHEN_MAXIMIZED);
1199  }
1200
1201  // If we have a parent, record the parent/child relationship. We use this
1202  // data during destruction to make sure that when we try to close a parent
1203  // window, we also destroy all child windows.
1204  if (params.parent && params.parent->GetHost()) {
1205    XID parent_xid =
1206        params.parent->GetHost()->GetAcceleratedWidget();
1207    window_parent_ = GetHostForXID(parent_xid);
1208    DCHECK(window_parent_);
1209    window_parent_->window_children_.insert(this);
1210  }
1211
1212  // If we have a delegate which is providing a default window icon, use that
1213  // icon.
1214  gfx::ImageSkia* window_icon = ViewsDelegate::views_delegate ?
1215      ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL;
1216  if (window_icon) {
1217    SetWindowIcons(gfx::ImageSkia(), *window_icon);
1218  }
1219  CreateCompositor(GetAcceleratedWidget());
1220}
1221
1222gfx::Size DesktopWindowTreeHostX11::AdjustSize(
1223    const gfx::Size& requested_size) {
1224  std::vector<gfx::Display> displays =
1225      gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE)->GetAllDisplays();
1226  // Compare against all monitor sizes. The window manager can move the window
1227  // to whichever monitor it wants.
1228  for (size_t i = 0; i < displays.size(); ++i) {
1229    if (requested_size == displays[i].size()) {
1230      return gfx::Size(requested_size.width() - 1,
1231                       requested_size.height() - 1);
1232    }
1233  }
1234  return requested_size;
1235}
1236
1237void DesktopWindowTreeHostX11::OnWMStateUpdated() {
1238  std::vector< ::Atom> atom_list;
1239  if (!ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list))
1240    return;
1241
1242  bool was_minimized = IsMinimized();
1243
1244  window_properties_.clear();
1245  std::copy(atom_list.begin(), atom_list.end(),
1246            inserter(window_properties_, window_properties_.begin()));
1247
1248  // Propagate the window minimization information to the content window, so
1249  // the render side can update its visibility properly. OnWMStateUpdated() is
1250  // called by PropertyNofify event from DispatchEvent() when the browser is
1251  // minimized or shown from minimized state. On Windows, this is realized by
1252  // calling OnHostResized() with an empty size. In particular,
1253  // HWNDMessageHandler::GetClientAreaBounds() returns an empty size when the
1254  // window is minimized. On Linux, returning empty size in GetBounds() or
1255  // SetBounds() does not work.
1256  // We also propagate the minimization to the compositor, to makes sure that we
1257  // don't draw any 'blank' frames that could be noticed in applications such as
1258  // window manager previews, which show content even when a window is
1259  // minimized.
1260  bool is_minimized = IsMinimized();
1261  if (is_minimized != was_minimized) {
1262    if (is_minimized) {
1263      compositor()->SetVisible(false);
1264      content_window_->Hide();
1265    } else {
1266      content_window_->Show();
1267      compositor()->SetVisible(true);
1268    }
1269  }
1270
1271  if (restored_bounds_.IsEmpty()) {
1272    DCHECK(!IsFullscreen());
1273    if (IsMaximized()) {
1274      // The request that we become maximized originated from a different
1275      // process. |bounds_| already contains our maximized bounds. Do a best
1276      // effort attempt to get restored bounds by setting it to our previously
1277      // set bounds (and if we get this wrong, we aren't any worse off since
1278      // we'd otherwise be returning our maximized bounds).
1279      restored_bounds_ = previous_bounds_;
1280    }
1281  } else if (!IsMaximized() && !IsFullscreen()) {
1282    // If we have restored bounds, but WM_STATE no longer claims to be
1283    // maximized or fullscreen, we should clear our restored bounds.
1284    restored_bounds_ = gfx::Rect();
1285  }
1286
1287  // Ignore requests by the window manager to enter or exit fullscreen (e.g. as
1288  // a result of pressing a window manager accelerator key). Chrome does not
1289  // handle window manager initiated fullscreen. In particular, Chrome needs to
1290  // do preprocessing before the x window's fullscreen state is toggled.
1291
1292  is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE");
1293
1294  // Now that we have different window properties, we may need to relayout the
1295  // window. (The windows code doesn't need this because their window change is
1296  // synchronous.)
1297  Relayout();
1298  ResetWindowRegion();
1299}
1300
1301void DesktopWindowTreeHostX11::OnFrameExtentsUpdated() {
1302  std::vector<int> insets;
1303  if (ui::GetIntArrayProperty(xwindow_, "_NET_FRAME_EXTENTS", &insets) &&
1304      insets.size() == 4) {
1305    // |insets| are returned in the order: [left, right, top, bottom].
1306    native_window_frame_borders_ = gfx::Insets(
1307        insets[2],
1308        insets[0],
1309        insets[3],
1310        insets[1]);
1311  } else {
1312    native_window_frame_borders_ = gfx::Insets();
1313  }
1314}
1315
1316void DesktopWindowTreeHostX11::UpdateMinAndMaxSize() {
1317  if (!window_mapped_)
1318    return;
1319
1320  gfx::Size minimum = native_widget_delegate_->GetMinimumSize();
1321  gfx::Size maximum = native_widget_delegate_->GetMaximumSize();
1322  if (min_size_ == minimum && max_size_ == maximum)
1323    return;
1324
1325  min_size_ = minimum;
1326  max_size_ = maximum;
1327
1328  XSizeHints hints;
1329  long supplied_return;
1330  XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return);
1331
1332  if (minimum.IsEmpty()) {
1333    hints.flags &= ~PMinSize;
1334  } else {
1335    hints.flags |= PMinSize;
1336    hints.min_width = min_size_.width();
1337    hints.min_height = min_size_.height();
1338  }
1339
1340  if (maximum.IsEmpty()) {
1341    hints.flags &= ~PMaxSize;
1342  } else {
1343    hints.flags |= PMaxSize;
1344    hints.max_width = max_size_.width();
1345    hints.max_height = max_size_.height();
1346  }
1347
1348  XSetWMNormalHints(xdisplay_, xwindow_, &hints);
1349}
1350
1351void DesktopWindowTreeHostX11::UpdateWMUserTime(
1352    const ui::PlatformEvent& event) {
1353  if (!IsActive())
1354    return;
1355
1356  ui::EventType type = ui::EventTypeFromNative(event);
1357  if (type == ui::ET_MOUSE_PRESSED ||
1358      type == ui::ET_KEY_PRESSED ||
1359      type == ui::ET_TOUCH_PRESSED) {
1360    unsigned long wm_user_time_ms = static_cast<unsigned long>(
1361        ui::EventTimeFromNative(event).InMilliseconds());
1362    XChangeProperty(xdisplay_,
1363                    xwindow_,
1364                    atom_cache_.GetAtom("_NET_WM_USER_TIME"),
1365                    XA_CARDINAL,
1366                    32,
1367                    PropModeReplace,
1368                    reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
1369                    1);
1370    X11DesktopHandler::get()->set_wm_user_time_ms(wm_user_time_ms);
1371  }
1372}
1373
1374void DesktopWindowTreeHostX11::SetWMSpecState(bool enabled,
1375                                                ::Atom state1,
1376                                                ::Atom state2) {
1377  XEvent xclient;
1378  memset(&xclient, 0, sizeof(xclient));
1379  xclient.type = ClientMessage;
1380  xclient.xclient.window = xwindow_;
1381  xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
1382  xclient.xclient.format = 32;
1383  xclient.xclient.data.l[0] =
1384      enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
1385  xclient.xclient.data.l[1] = state1;
1386  xclient.xclient.data.l[2] = state2;
1387  xclient.xclient.data.l[3] = 1;
1388  xclient.xclient.data.l[4] = 0;
1389
1390  XSendEvent(xdisplay_, x_root_window_, False,
1391             SubstructureRedirectMask | SubstructureNotifyMask,
1392             &xclient);
1393}
1394
1395bool DesktopWindowTreeHostX11::HasWMSpecProperty(const char* property) const {
1396  return window_properties_.find(atom_cache_.GetAtom(property)) !=
1397      window_properties_.end();
1398}
1399
1400void DesktopWindowTreeHostX11::SetUseNativeFrame(bool use_native_frame) {
1401  use_native_frame_ = use_native_frame;
1402  ui::SetUseOSWindowFrame(xwindow_, use_native_frame);
1403  ResetWindowRegion();
1404}
1405
1406void DesktopWindowTreeHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
1407  // In Windows, the native events sent to chrome are separated into client
1408  // and non-client versions of events, which we record on our LocatedEvent
1409  // structures. On X11, we emulate the concept of non-client. Before we pass
1410  // this event to the cross platform event handling framework, we need to
1411  // make sure it is appropriately marked as non-client if it's in the non
1412  // client area, or otherwise, we can get into a state where the a window is
1413  // set as the |mouse_pressed_handler_| in window_event_dispatcher.cc
1414  // despite the mouse button being released.
1415  //
1416  // We can't do this later in the dispatch process because we share that
1417  // with ash, and ash gets confused about event IS_NON_CLIENT-ness on
1418  // events, since ash doesn't expect this bit to be set, because it's never
1419  // been set before. (This works on ash on Windows because none of the mouse
1420  // events on the ash desktop are clicking in what Windows considers to be a
1421  // non client area.) Likewise, we won't want to do the following in any
1422  // WindowTreeHost that hosts ash.
1423  if (content_window_ && content_window_->delegate()) {
1424    int flags = event->flags();
1425    int hit_test_code =
1426        content_window_->delegate()->GetNonClientComponent(event->location());
1427    if (hit_test_code != HTCLIENT && hit_test_code != HTNOWHERE)
1428      flags |= ui::EF_IS_NON_CLIENT;
1429    event->set_flags(flags);
1430  }
1431
1432  // While we unset the urgency hint when we gain focus, we also must remove it
1433  // on mouse clicks because we can call FlashFrame() on an active window.
1434  if (event->IsAnyButton() || event->IsMouseWheelEvent())
1435    FlashFrame(false);
1436
1437  if (!g_current_capture || g_current_capture == this) {
1438    SendEventToProcessor(event);
1439  } else {
1440    // Another DesktopWindowTreeHostX11 has installed itself as
1441    // capture. Translate the event's location and dispatch to the other.
1442    event->ConvertLocationToTarget(window(), g_current_capture->window());
1443    g_current_capture->SendEventToProcessor(event);
1444  }
1445}
1446
1447void DesktopWindowTreeHostX11::DispatchTouchEvent(ui::TouchEvent* event) {
1448  if (g_current_capture && g_current_capture != this &&
1449      event->type() == ui::ET_TOUCH_PRESSED) {
1450    event->ConvertLocationToTarget(window(), g_current_capture->window());
1451    g_current_capture->SendEventToProcessor(event);
1452  } else {
1453    SendEventToProcessor(event);
1454  }
1455}
1456
1457void DesktopWindowTreeHostX11::ResetWindowRegion() {
1458  // If a custom window shape was supplied then apply it.
1459  if (custom_window_shape_) {
1460    XShapeCombineRegion(
1461        xdisplay_, xwindow_, ShapeBounding, 0, 0, window_shape_, false);
1462    return;
1463  }
1464
1465  if (window_shape_)
1466    XDestroyRegion(window_shape_);
1467  window_shape_ = NULL;
1468
1469  if (!IsMaximized() && !IsFullscreen()) {
1470    gfx::Path window_mask;
1471    views::Widget* widget = native_widget_delegate_->AsWidget();
1472    if (widget->non_client_view()) {
1473      // Some frame views define a custom (non-rectangular) window mask. If
1474      // so, use it to define the window shape. If not, fall through.
1475      widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask);
1476      if (window_mask.countPoints() > 0) {
1477        window_shape_ = gfx::CreateRegionFromSkPath(window_mask);
1478        XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding,
1479                            0, 0, window_shape_, false);
1480        return;
1481      }
1482    }
1483  }
1484
1485  // If we didn't set the shape for any reason, reset the shaping information.
1486  // How this is done depends on the border style, due to quirks and bugs in
1487  // various window managers.
1488  if (ShouldUseNativeFrame()) {
1489    // If the window has system borders, the mask must be set to null (not a
1490    // rectangle), because several window managers (eg, KDE, XFCE, XMonad) will
1491    // not put borders on a window with a custom shape.
1492    XShapeCombineMask(xdisplay_, xwindow_, ShapeBounding, 0, 0, None, ShapeSet);
1493  } else {
1494    // Conversely, if the window does not have system borders, the mask must be
1495    // manually set to a rectangle that covers the whole window (not null). This
1496    // is due to a bug in KWin <= 4.11.5 (KDE bug #330573) where setting a null
1497    // shape causes the hint to disable system borders to be ignored (resulting
1498    // in a double border).
1499    XRectangle r = {0, 0, static_cast<unsigned short>(bounds_.width()),
1500                    static_cast<unsigned short>(bounds_.height())};
1501    XShapeCombineRectangles(
1502        xdisplay_, xwindow_, ShapeBounding, 0, 0, &r, 1, ShapeSet, YXBanded);
1503  }
1504}
1505
1506void DesktopWindowTreeHostX11::SerializeImageRepresentation(
1507    const gfx::ImageSkiaRep& rep,
1508    std::vector<unsigned long>* data) {
1509  int width = rep.GetWidth();
1510  data->push_back(width);
1511
1512  int height = rep.GetHeight();
1513  data->push_back(height);
1514
1515  const SkBitmap& bitmap = rep.sk_bitmap();
1516  SkAutoLockPixels locker(bitmap);
1517
1518  for (int y = 0; y < height; ++y)
1519    for (int x = 0; x < width; ++x)
1520      data->push_back(bitmap.getColor(x, y));
1521}
1522
1523Visual* DesktopWindowTreeHostX11::GetARGBVisual() {
1524  XVisualInfo visual_template;
1525  visual_template.screen = 0;
1526  Visual* to_return = NULL;
1527
1528  int visuals_len;
1529  XVisualInfo* visual_list = XGetVisualInfo(xdisplay_,
1530                                            VisualScreenMask,
1531                                            &visual_template, &visuals_len);
1532  for (int i = 0; i < visuals_len; ++i) {
1533    // Why support only 8888 ARGB? Because it's all that GTK+ supports. In
1534    // gdkvisual-x11.cc, they look for this specific visual and use it for all
1535    // their alpha channel using needs.
1536    //
1537    // TODO(erg): While the following does find a valid visual, some GL drivers
1538    // don't believe that this has an alpha channel. According to marcheu@,
1539    // this should work on open source driver though. (It doesn't work with
1540    // NVidia's binaries currently.) http://crbug.com/369209
1541    if (visual_list[i].depth == 32 &&
1542        visual_list[i].visual->red_mask == 0xff0000 &&
1543        visual_list[i].visual->green_mask == 0x00ff00 &&
1544        visual_list[i].visual->blue_mask == 0x0000ff) {
1545      to_return = visual_list[i].visual;
1546      break;
1547    }
1548  }
1549
1550  if (visual_list)
1551    XFree(visual_list);
1552
1553  return to_return;
1554}
1555
1556std::list<XID>& DesktopWindowTreeHostX11::open_windows() {
1557  if (!open_windows_)
1558    open_windows_ = new std::list<XID>();
1559  return *open_windows_;
1560}
1561
1562void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) {
1563  if (show_state != ui::SHOW_STATE_DEFAULT &&
1564      show_state != ui::SHOW_STATE_NORMAL &&
1565      show_state != ui::SHOW_STATE_INACTIVE &&
1566      show_state != ui::SHOW_STATE_MAXIMIZED) {
1567    // It will behave like SHOW_STATE_NORMAL.
1568    NOTIMPLEMENTED();
1569  }
1570
1571  // Before we map the window, set size hints. Otherwise, some window managers
1572  // will ignore toplevel XMoveWindow commands.
1573  XSizeHints size_hints;
1574  size_hints.flags = PPosition;
1575  size_hints.x = bounds_.x();
1576  size_hints.y = bounds_.y();
1577  XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
1578
1579  // If SHOW_STATE_INACTIVE, tell the window manager not to focus the window
1580  // when mapping. This is done by setting the _NET_WM_USER_TIME to 0. See e.g.
1581  // http://standards.freedesktop.org/wm-spec/latest/ar01s05.html
1582  unsigned long wm_user_time_ms = (show_state == ui::SHOW_STATE_INACTIVE) ?
1583      0 : X11DesktopHandler::get()->wm_user_time_ms();
1584  if (show_state == ui::SHOW_STATE_INACTIVE || wm_user_time_ms != 0) {
1585    XChangeProperty(xdisplay_,
1586                    xwindow_,
1587                    atom_cache_.GetAtom("_NET_WM_USER_TIME"),
1588                    XA_CARDINAL,
1589                    32,
1590                    PropModeReplace,
1591                    reinterpret_cast<const unsigned char *>(&wm_user_time_ms),
1592                    1);
1593  }
1594
1595  XMapWindow(xdisplay_, xwindow_);
1596
1597  // We now block until our window is mapped. Some X11 APIs will crash and
1598  // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
1599  // asynchronous.
1600  if (ui::X11EventSource::GetInstance())
1601    ui::X11EventSource::GetInstance()->BlockUntilWindowMapped(xwindow_);
1602  window_mapped_ = true;
1603
1604  // Some WMs only respect maximize hints after the window has been mapped.
1605  // Check whether we need to re-do a maximization.
1606  if (should_maximize_after_map_) {
1607    Maximize();
1608    should_maximize_after_map_ = false;
1609  }
1610}
1611
1612void DesktopWindowTreeHostX11::SetWindowTransparency() {
1613  compositor()->SetHostHasTransparentBackground(use_argb_visual_);
1614  window()->SetTransparent(use_argb_visual_);
1615  content_window_->SetTransparent(use_argb_visual_);
1616}
1617
1618void DesktopWindowTreeHostX11::Relayout() {
1619  Widget* widget = native_widget_delegate_->AsWidget();
1620  NonClientView* non_client_view = widget->non_client_view();
1621  // non_client_view may be NULL, especially during creation.
1622  if (non_client_view) {
1623    non_client_view->client_view()->InvalidateLayout();
1624    non_client_view->InvalidateLayout();
1625  }
1626  widget->GetRootView()->Layout();
1627}
1628
1629////////////////////////////////////////////////////////////////////////////////
1630// DesktopWindowTreeHostX11, ui::PlatformEventDispatcher implementation:
1631
1632bool DesktopWindowTreeHostX11::CanDispatchEvent(
1633    const ui::PlatformEvent& event) {
1634  return event->xany.window == xwindow_ ||
1635         (event->type == GenericEvent &&
1636          static_cast<XIDeviceEvent*>(event->xcookie.data)->event == xwindow_);
1637}
1638
1639uint32_t DesktopWindowTreeHostX11::DispatchEvent(
1640    const ui::PlatformEvent& event) {
1641  XEvent* xev = event;
1642
1643  TRACE_EVENT1("views", "DesktopWindowTreeHostX11::Dispatch",
1644               "event->type", event->type);
1645
1646  UpdateWMUserTime(event);
1647
1648  // May want to factor CheckXEventForConsistency(xev); into a common location
1649  // since it is called here.
1650  switch (xev->type) {
1651    case EnterNotify:
1652    case LeaveNotify: {
1653      // Ignore EventNotify and LeaveNotify events from children of |xwindow_|.
1654      // NativeViewGLSurfaceGLX adds a child to |xwindow_|.
1655      // TODO(pkotwicz|tdanderson): Figure out whether the suppression is
1656      // necessary. crbug.com/385716
1657      if (xev->xcrossing.detail == NotifyInferior)
1658        break;
1659
1660      ui::MouseEvent mouse_event(xev);
1661      DispatchMouseEvent(&mouse_event);
1662      break;
1663    }
1664    case Expose: {
1665      gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
1666                            xev->xexpose.width, xev->xexpose.height);
1667      compositor()->ScheduleRedrawRect(damage_rect);
1668      break;
1669    }
1670    case KeyPress: {
1671      ui::KeyEvent keydown_event(xev);
1672      SendEventToProcessor(&keydown_event);
1673      break;
1674    }
1675    case KeyRelease: {
1676      // There is no way to deactivate a window in X11 so ignore input if
1677      // window is supposed to be 'inactive'. See comments in
1678      // X11DesktopHandler::DeactivateWindow() for more details.
1679      if (!IsActive() && !HasCapture())
1680        break;
1681
1682      ui::KeyEvent key_event(xev);
1683      SendEventToProcessor(&key_event);
1684      break;
1685    }
1686    case ButtonPress:
1687    case ButtonRelease: {
1688      ui::EventType event_type = ui::EventTypeFromNative(xev);
1689      switch (event_type) {
1690        case ui::ET_MOUSEWHEEL: {
1691          ui::MouseWheelEvent mouseev(xev);
1692          DispatchMouseEvent(&mouseev);
1693          break;
1694        }
1695        case ui::ET_MOUSE_PRESSED:
1696        case ui::ET_MOUSE_RELEASED: {
1697          ui::MouseEvent mouseev(xev);
1698          DispatchMouseEvent(&mouseev);
1699          break;
1700        }
1701        case ui::ET_UNKNOWN:
1702          // No event is created for X11-release events for mouse-wheel buttons.
1703          break;
1704        default:
1705          NOTREACHED() << event_type;
1706      }
1707      break;
1708    }
1709    case FocusOut:
1710      if (xev->xfocus.mode != NotifyGrab) {
1711        ReleaseCapture();
1712        OnHostLostWindowCapture();
1713        X11DesktopHandler::get()->ProcessXEvent(xev);
1714      } else {
1715        dispatcher()->OnHostLostMouseGrab();
1716      }
1717      break;
1718    case FocusIn:
1719      X11DesktopHandler::get()->ProcessXEvent(xev);
1720      break;
1721    case ConfigureNotify: {
1722      DCHECK_EQ(xwindow_, xev->xconfigure.window);
1723      DCHECK_EQ(xwindow_, xev->xconfigure.event);
1724      // It's possible that the X window may be resized by some other means than
1725      // from within aura (e.g. the X window manager can change the size). Make
1726      // sure the root window size is maintained properly.
1727      int translated_x = xev->xconfigure.x;
1728      int translated_y = xev->xconfigure.y;
1729      if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
1730        Window unused;
1731        XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_,
1732            0, 0, &translated_x, &translated_y, &unused);
1733      }
1734      gfx::Rect bounds(translated_x, translated_y,
1735                       xev->xconfigure.width, xev->xconfigure.height);
1736      bool size_changed = bounds_.size() != bounds.size();
1737      bool origin_changed = bounds_.origin() != bounds.origin();
1738      previous_bounds_ = bounds_;
1739      bounds_ = bounds;
1740
1741      if (origin_changed)
1742        OnHostMoved(bounds_.origin());
1743
1744      if (size_changed) {
1745        delayed_resize_task_.Reset(base::Bind(
1746            &DesktopWindowTreeHostX11::DelayedResize,
1747            close_widget_factory_.GetWeakPtr(),
1748            bounds.size()));
1749        base::MessageLoop::current()->PostTask(
1750            FROM_HERE, delayed_resize_task_.callback());
1751      }
1752      break;
1753    }
1754    case GenericEvent: {
1755      ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
1756      if (!factory->ShouldProcessXI2Event(xev))
1757        break;
1758
1759      ui::EventType type = ui::EventTypeFromNative(xev);
1760      XEvent last_event;
1761      int num_coalesced = 0;
1762
1763      switch (type) {
1764        case ui::ET_TOUCH_MOVED:
1765          num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1766          if (num_coalesced > 0)
1767            xev = &last_event;
1768          // fallthrough
1769        case ui::ET_TOUCH_PRESSED:
1770        case ui::ET_TOUCH_RELEASED: {
1771          ui::TouchEvent touchev(xev);
1772          DispatchTouchEvent(&touchev);
1773          break;
1774        }
1775        case ui::ET_MOUSE_MOVED:
1776        case ui::ET_MOUSE_DRAGGED:
1777        case ui::ET_MOUSE_PRESSED:
1778        case ui::ET_MOUSE_RELEASED:
1779        case ui::ET_MOUSE_ENTERED:
1780        case ui::ET_MOUSE_EXITED: {
1781          if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
1782            // If this is a motion event, we want to coalesce all pending motion
1783            // events that are at the top of the queue.
1784            num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
1785            if (num_coalesced > 0)
1786              xev = &last_event;
1787          }
1788          ui::MouseEvent mouseev(xev);
1789          DispatchMouseEvent(&mouseev);
1790          break;
1791        }
1792        case ui::ET_MOUSEWHEEL: {
1793          ui::MouseWheelEvent mouseev(xev);
1794          DispatchMouseEvent(&mouseev);
1795          break;
1796        }
1797        case ui::ET_SCROLL_FLING_START:
1798        case ui::ET_SCROLL_FLING_CANCEL:
1799        case ui::ET_SCROLL: {
1800          ui::ScrollEvent scrollev(xev);
1801          SendEventToProcessor(&scrollev);
1802          break;
1803        }
1804        case ui::ET_KEY_PRESSED:
1805        case ui::ET_KEY_RELEASED: {
1806          ui::KeyEvent key_event(xev);
1807          SendEventToProcessor(&key_event);
1808          break;
1809        }
1810        case ui::ET_UNKNOWN:
1811          break;
1812        default:
1813          NOTREACHED();
1814      }
1815
1816      // If we coalesced an event we need to free its cookie.
1817      if (num_coalesced > 0)
1818        XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
1819      break;
1820    }
1821    case MapNotify: {
1822      FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1823                        observer_list_,
1824                        OnWindowMapped(xwindow_));
1825      break;
1826    }
1827    case UnmapNotify: {
1828      FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11,
1829                        observer_list_,
1830                        OnWindowUnmapped(xwindow_));
1831      break;
1832    }
1833    case ClientMessage: {
1834      Atom message_type = xev->xclient.message_type;
1835      if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
1836        Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
1837        if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
1838          // We have received a close message from the window manager.
1839          OnHostCloseRequested();
1840        } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
1841          XEvent reply_event = *xev;
1842          reply_event.xclient.window = x_root_window_;
1843
1844          XSendEvent(xdisplay_,
1845                     reply_event.xclient.window,
1846                     False,
1847                     SubstructureRedirectMask | SubstructureNotifyMask,
1848                     &reply_event);
1849        }
1850      } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
1851        drag_drop_client_->OnXdndEnter(xev->xclient);
1852      } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
1853        drag_drop_client_->OnXdndLeave(xev->xclient);
1854      } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
1855        drag_drop_client_->OnXdndPosition(xev->xclient);
1856      } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
1857        drag_drop_client_->OnXdndStatus(xev->xclient);
1858      } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
1859        drag_drop_client_->OnXdndFinished(xev->xclient);
1860      } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
1861        drag_drop_client_->OnXdndDrop(xev->xclient);
1862      }
1863      break;
1864    }
1865    case MappingNotify: {
1866      switch (xev->xmapping.request) {
1867        case MappingModifier:
1868        case MappingKeyboard:
1869          XRefreshKeyboardMapping(&xev->xmapping);
1870          break;
1871        case MappingPointer:
1872          ui::DeviceDataManagerX11::GetInstance()->UpdateButtonMap();
1873          break;
1874        default:
1875          NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
1876          break;
1877      }
1878      break;
1879    }
1880    case MotionNotify: {
1881      // Discard all but the most recent motion event that targets the same
1882      // window with unchanged state.
1883      XEvent last_event;
1884      while (XPending(xev->xany.display)) {
1885        XEvent next_event;
1886        XPeekEvent(xev->xany.display, &next_event);
1887        if (next_event.type == MotionNotify &&
1888            next_event.xmotion.window == xev->xmotion.window &&
1889            next_event.xmotion.subwindow == xev->xmotion.subwindow &&
1890            next_event.xmotion.state == xev->xmotion.state) {
1891          XNextEvent(xev->xany.display, &last_event);
1892          xev = &last_event;
1893        } else {
1894          break;
1895        }
1896      }
1897
1898      ui::MouseEvent mouseev(xev);
1899      DispatchMouseEvent(&mouseev);
1900      break;
1901    }
1902    case PropertyNotify: {
1903      ::Atom changed_atom = xev->xproperty.atom;
1904      if (changed_atom == atom_cache_.GetAtom("_NET_WM_STATE"))
1905        OnWMStateUpdated();
1906      else if (changed_atom == atom_cache_.GetAtom("_NET_FRAME_EXTENTS"))
1907        OnFrameExtentsUpdated();
1908      break;
1909    }
1910    case SelectionNotify: {
1911      drag_drop_client_->OnSelectionNotify(xev->xselection);
1912      break;
1913    }
1914  }
1915  return ui::POST_DISPATCH_STOP_PROPAGATION;
1916}
1917
1918void DesktopWindowTreeHostX11::DelayedResize(const gfx::Size& size) {
1919  OnHostResized(size);
1920  ResetWindowRegion();
1921  delayed_resize_task_.Cancel();
1922}
1923
1924////////////////////////////////////////////////////////////////////////////////
1925// DesktopWindowTreeHost, public:
1926
1927// static
1928DesktopWindowTreeHost* DesktopWindowTreeHost::Create(
1929    internal::NativeWidgetDelegate* native_widget_delegate,
1930    DesktopNativeWidgetAura* desktop_native_widget_aura) {
1931  return new DesktopWindowTreeHostX11(native_widget_delegate,
1932                                      desktop_native_widget_aura);
1933}
1934
1935// static
1936ui::NativeTheme* DesktopWindowTreeHost::GetNativeTheme(aura::Window* window) {
1937  const views::LinuxUI* linux_ui = views::LinuxUI::instance();
1938  if (linux_ui) {
1939    ui::NativeTheme* native_theme = linux_ui->GetNativeTheme(window);
1940    if (native_theme)
1941      return native_theme;
1942  }
1943
1944  return ui::NativeTheme::instance();
1945}
1946
1947}  // namespace views
1948