Home | History | Annotate | Download | only in desktop_aura
      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 = 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 
   1222 gfx::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 
   1237 void 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 
   1301 void 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 
   1316 void 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 
   1351 void 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 
   1374 void 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 
   1395 bool DesktopWindowTreeHostX11::HasWMSpecProperty(const char* property) const {
   1396   return window_properties_.find(atom_cache_.GetAtom(property)) !=
   1397       window_properties_.end();
   1398 }
   1399 
   1400 void DesktopWindowTreeHostX11::SetUseNativeFrame(bool use_native_frame) {
   1401   use_native_frame_ = use_native_frame;
   1402   ui::SetUseOSWindowFrame(xwindow_, use_native_frame);
   1403   ResetWindowRegion();
   1404 }
   1405 
   1406 void 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 
   1447 void 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 
   1457 void 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 
   1506 void 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 
   1523 Visual* 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 
   1556 std::list<XID>& DesktopWindowTreeHostX11::open_windows() {
   1557   if (!open_windows_)
   1558     open_windows_ = new std::list<XID>();
   1559   return *open_windows_;
   1560 }
   1561 
   1562 void 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 
   1612 void DesktopWindowTreeHostX11::SetWindowTransparency() {
   1613   compositor()->SetHostHasTransparentBackground(use_argb_visual_);
   1614   window()->SetTransparent(use_argb_visual_);
   1615   content_window_->SetTransparent(use_argb_visual_);
   1616 }
   1617 
   1618 void 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 
   1632 bool 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 
   1639 uint32_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 
   1918 void 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
   1928 DesktopWindowTreeHost* 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
   1936 ui::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