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_root_window_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/debug/trace_event.h"
     15 #include "base/message_loop/message_pump_x11.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/client/user_action_client.h"
     22 #include "ui/aura/root_window.h"
     23 #include "ui/aura/window.h"
     24 #include "ui/aura/window_property.h"
     25 #include "ui/base/dragdrop/os_exchange_data_provider_aurax11.h"
     26 #include "ui/base/x/x11_util.h"
     27 #include "ui/events/event_utils.h"
     28 #include "ui/events/x/device_data_manager.h"
     29 #include "ui/events/x/device_list_cache_x.h"
     30 #include "ui/events/x/touch_factory_x11.h"
     31 #include "ui/gfx/image/image_skia.h"
     32 #include "ui/gfx/image/image_skia_rep.h"
     33 #include "ui/gfx/insets.h"
     34 #include "ui/gfx/path.h"
     35 #include "ui/gfx/path_x11.h"
     36 #include "ui/native_theme/native_theme.h"
     37 #include "ui/views/corewm/compound_event_filter.h"
     38 #include "ui/views/corewm/corewm_switches.h"
     39 #include "ui/views/corewm/tooltip_aura.h"
     40 #include "ui/views/ime/input_method.h"
     41 #include "ui/views/linux_ui/linux_ui.h"
     42 #include "ui/views/views_delegate.h"
     43 #include "ui/views/widget/desktop_aura/desktop_dispatcher_client.h"
     44 #include "ui/views/widget/desktop_aura/desktop_drag_drop_client_aurax11.h"
     45 #include "ui/views/widget/desktop_aura/desktop_native_cursor_manager.h"
     46 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
     47 #include "ui/views/widget/desktop_aura/desktop_root_window_host_observer_x11.h"
     48 #include "ui/views/widget/desktop_aura/x11_desktop_handler.h"
     49 #include "ui/views/widget/desktop_aura/x11_desktop_window_move_client.h"
     50 #include "ui/views/widget/desktop_aura/x11_window_event_filter.h"
     51 
     52 namespace views {
     53 
     54 DesktopRootWindowHostX11* DesktopRootWindowHostX11::g_current_capture =
     55     NULL;
     56 std::list<XID>* DesktopRootWindowHostX11::open_windows_ = NULL;
     57 
     58 DEFINE_WINDOW_PROPERTY_KEY(
     59     aura::Window*, kViewsWindowForRootWindow, NULL);
     60 
     61 DEFINE_WINDOW_PROPERTY_KEY(
     62     DesktopRootWindowHostX11*, kHostForRootWindow, NULL);
     63 
     64 namespace {
     65 
     66 // Standard Linux mouse buttons for going back and forward.
     67 const int kBackMouseButton = 8;
     68 const int kForwardMouseButton = 9;
     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 const char* kAtomsToCache[] = {
     75   "UTF8_STRING",
     76   "WM_DELETE_WINDOW",
     77   "WM_PROTOCOLS",
     78   "WM_S0",
     79   "_NET_WM_ICON",
     80   "_NET_WM_NAME",
     81   "_NET_WM_PID",
     82   "_NET_WM_PING",
     83   "_NET_WM_STATE",
     84   "_NET_WM_STATE_ABOVE",
     85   "_NET_WM_STATE_FULLSCREEN",
     86   "_NET_WM_STATE_HIDDEN",
     87   "_NET_WM_STATE_MAXIMIZED_HORZ",
     88   "_NET_WM_STATE_MAXIMIZED_VERT",
     89   "_NET_WM_STATE_SKIP_TASKBAR",
     90   "_NET_WM_WINDOW_OPACITY",
     91   "_NET_WM_WINDOW_TYPE",
     92   "_NET_WM_WINDOW_TYPE_DND",
     93   "_NET_WM_WINDOW_TYPE_MENU",
     94   "_NET_WM_WINDOW_TYPE_NORMAL",
     95   "_NET_WM_WINDOW_TYPE_NOTIFICATION",
     96   "_NET_WM_WINDOW_TYPE_TOOLTIP",
     97   "XdndActionAsk",
     98   "XdndActionCopy"
     99   "XdndActionLink",
    100   "XdndActionList",
    101   "XdndActionMove",
    102   "XdndActionPrivate",
    103   "XdndAware",
    104   "XdndDrop",
    105   "XdndEnter",
    106   "XdndFinished",
    107   "XdndLeave",
    108   "XdndPosition",
    109   "XdndProxy",  // Proxy windows?
    110   "XdndSelection",
    111   "XdndStatus",
    112   "XdndTypeList",
    113   NULL
    114 };
    115 
    116 }  // namespace
    117 
    118 ////////////////////////////////////////////////////////////////////////////////
    119 // DesktopRootWindowHostX11, public:
    120 
    121 DesktopRootWindowHostX11::DesktopRootWindowHostX11(
    122     internal::NativeWidgetDelegate* native_widget_delegate,
    123     DesktopNativeWidgetAura* desktop_native_widget_aura)
    124     : close_widget_factory_(this),
    125       xdisplay_(gfx::GetXDisplay()),
    126       xwindow_(0),
    127       x_root_window_(DefaultRootWindow(xdisplay_)),
    128       atom_cache_(xdisplay_, kAtomsToCache),
    129       window_mapped_(false),
    130       is_fullscreen_(false),
    131       is_always_on_top_(false),
    132       root_window_(NULL),
    133       drag_drop_client_(NULL),
    134       current_cursor_(ui::kCursorNull),
    135       native_widget_delegate_(native_widget_delegate),
    136       desktop_native_widget_aura_(desktop_native_widget_aura),
    137       content_window_(NULL),
    138       window_parent_(NULL),
    139       custom_window_shape_(NULL) {
    140 }
    141 
    142 DesktopRootWindowHostX11::~DesktopRootWindowHostX11() {
    143   root_window_->window()->ClearProperty(kHostForRootWindow);
    144   aura::client::SetWindowMoveClient(root_window_->window(), NULL);
    145   desktop_native_widget_aura_->OnDesktopRootWindowHostDestroyed(root_window_);
    146   if (custom_window_shape_)
    147     XDestroyRegion(custom_window_shape_);
    148 }
    149 
    150 // static
    151 aura::Window* DesktopRootWindowHostX11::GetContentWindowForXID(XID xid) {
    152   aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
    153   return root ? root->window()->GetProperty(kViewsWindowForRootWindow) : NULL;
    154 }
    155 
    156 // static
    157 DesktopRootWindowHostX11* DesktopRootWindowHostX11::GetHostForXID(XID xid) {
    158   aura::RootWindow* root = aura::RootWindow::GetForAcceleratedWidget(xid);
    159   return root ? root->window()->GetProperty(kHostForRootWindow) : NULL;
    160 }
    161 
    162 // static
    163 std::vector<aura::Window*> DesktopRootWindowHostX11::GetAllOpenWindows() {
    164   std::vector<aura::Window*> windows(open_windows().size());
    165   std::transform(open_windows().begin(),
    166                  open_windows().end(),
    167                  windows.begin(),
    168                  GetContentWindowForXID);
    169   return windows;
    170 }
    171 
    172 gfx::Rect DesktopRootWindowHostX11::GetX11RootWindowBounds() const {
    173   return bounds_;
    174 }
    175 
    176 void DesktopRootWindowHostX11::HandleNativeWidgetActivationChanged(
    177     bool active) {
    178   if (active) {
    179     delegate_->OnHostActivated();
    180     open_windows().remove(xwindow_);
    181     open_windows().insert(open_windows().begin(), xwindow_);
    182   }
    183 
    184   desktop_native_widget_aura_->HandleActivationChanged(active);
    185 
    186   native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint();
    187 }
    188 
    189 void DesktopRootWindowHostX11::AddObserver(
    190     views::DesktopRootWindowHostObserverX11* observer) {
    191   observer_list_.AddObserver(observer);
    192 }
    193 
    194 void DesktopRootWindowHostX11::RemoveObserver(
    195     views::DesktopRootWindowHostObserverX11* observer) {
    196   observer_list_.RemoveObserver(observer);
    197 }
    198 
    199 void DesktopRootWindowHostX11::CleanUpWindowList() {
    200   delete open_windows_;
    201   open_windows_ = NULL;
    202 }
    203 
    204 ////////////////////////////////////////////////////////////////////////////////
    205 // DesktopRootWindowHostX11, DesktopRootWindowHost implementation:
    206 
    207 void DesktopRootWindowHostX11::Init(
    208     aura::Window* content_window,
    209     const Widget::InitParams& params,
    210     aura::RootWindow::CreateParams* rw_create_params) {
    211   content_window_ = content_window;
    212 
    213   // TODO(erg): Check whether we *should* be building a RootWindowHost here, or
    214   // whether we should be proxying requests to another DRWHL.
    215 
    216   // In some situations, views tries to make a zero sized window, and that
    217   // makes us crash. Make sure we have valid sizes.
    218   Widget::InitParams sanitized_params = params;
    219   if (sanitized_params.bounds.width() == 0)
    220     sanitized_params.bounds.set_width(100);
    221   if (sanitized_params.bounds.height() == 0)
    222     sanitized_params.bounds.set_height(100);
    223 
    224   InitX11Window(sanitized_params);
    225 
    226   rw_create_params->initial_bounds = bounds_;
    227   rw_create_params->host = this;
    228 }
    229 
    230 void DesktopRootWindowHostX11::OnRootWindowCreated(
    231     aura::RootWindow* root,
    232     const Widget::InitParams& params) {
    233   root_window_ = root;
    234 
    235   root_window_->window()->SetProperty(kViewsWindowForRootWindow,
    236                                       content_window_);
    237   root_window_->window()->SetProperty(kHostForRootWindow, this);
    238   delegate_ = root_window_;
    239 
    240   // If we're given a parent, we need to mark ourselves as transient to another
    241   // window. Otherwise activation gets screwy.
    242   gfx::NativeView parent = params.parent;
    243   if (!params.child && params.parent)
    244     parent->AddTransientChild(content_window_);
    245 
    246   // Ensure that the X11DesktopHandler exists so that it dispatches activation
    247   // messages to us.
    248   X11DesktopHandler::get();
    249 
    250   // TODO(erg): Unify this code once the other consumer goes away.
    251   x11_window_event_filter_.reset(new X11WindowEventFilter(root_window_, this));
    252   x11_window_event_filter_->SetUseHostWindowBorders(false);
    253   desktop_native_widget_aura_->root_window_event_filter()->AddHandler(
    254       x11_window_event_filter_.get());
    255 
    256   x11_window_move_client_.reset(new X11DesktopWindowMoveClient);
    257   aura::client::SetWindowMoveClient(root_window_->window(),
    258                                     x11_window_move_client_.get());
    259 
    260   native_widget_delegate_->OnNativeWidgetCreated(true);
    261 }
    262 
    263 scoped_ptr<corewm::Tooltip> DesktopRootWindowHostX11::CreateTooltip() {
    264   return scoped_ptr<corewm::Tooltip>(
    265       new corewm::TooltipAura(gfx::SCREEN_TYPE_NATIVE));
    266 }
    267 
    268 scoped_ptr<aura::client::DragDropClient>
    269 DesktopRootWindowHostX11::CreateDragDropClient(
    270     DesktopNativeCursorManager* cursor_manager) {
    271   drag_drop_client_ = new DesktopDragDropClientAuraX11(
    272       root_window_->window(), cursor_manager, xdisplay_, xwindow_);
    273   return scoped_ptr<aura::client::DragDropClient>(drag_drop_client_).Pass();
    274 }
    275 
    276 void DesktopRootWindowHostX11::Close() {
    277   // TODO(erg): Might need to do additional hiding tasks here.
    278 
    279   if (!close_widget_factory_.HasWeakPtrs()) {
    280     // And we delay the close so that if we are called from an ATL callback,
    281     // we don't destroy the window before the callback returned (as the caller
    282     // may delete ourselves on destroy and the ATL callback would still
    283     // dereference us when the callback returns).
    284     base::MessageLoop::current()->PostTask(
    285         FROM_HERE,
    286         base::Bind(&DesktopRootWindowHostX11::CloseNow,
    287                    close_widget_factory_.GetWeakPtr()));
    288   }
    289 }
    290 
    291 void DesktopRootWindowHostX11::CloseNow() {
    292   if (xwindow_ == None)
    293     return;
    294 
    295   native_widget_delegate_->OnNativeWidgetDestroying();
    296 
    297   // If we have children, close them. Use a copy for iteration because they'll
    298   // remove themselves.
    299   std::set<DesktopRootWindowHostX11*> window_children_copy = window_children_;
    300   for (std::set<DesktopRootWindowHostX11*>::iterator it =
    301            window_children_copy.begin(); it != window_children_copy.end();
    302        ++it) {
    303     (*it)->CloseNow();
    304   }
    305   DCHECK(window_children_.empty());
    306 
    307   // If we have a parent, remove ourselves from its children list.
    308   if (window_parent_) {
    309     window_parent_->window_children_.erase(this);
    310     window_parent_ = NULL;
    311   }
    312 
    313   // Remove the event listeners we've installed. We need to remove these
    314   // because otherwise we get assert during ~RootWindow().
    315   desktop_native_widget_aura_->root_window_event_filter()->RemoveHandler(
    316       x11_window_event_filter_.get());
    317 
    318   open_windows().remove(xwindow_);
    319   // Actually free our native resources.
    320   base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_);
    321   XDestroyWindow(xdisplay_, xwindow_);
    322   xwindow_ = None;
    323 
    324   desktop_native_widget_aura_->OnHostClosed();
    325 }
    326 
    327 aura::RootWindowHost* DesktopRootWindowHostX11::AsRootWindowHost() {
    328   return this;
    329 }
    330 
    331 void DesktopRootWindowHostX11::ShowWindowWithState(
    332     ui::WindowShowState show_state) {
    333   if (show_state != ui::SHOW_STATE_DEFAULT &&
    334       show_state != ui::SHOW_STATE_NORMAL) {
    335     // Only forwarding to Show().
    336     NOTIMPLEMENTED();
    337   }
    338 
    339   Show();
    340 }
    341 
    342 void DesktopRootWindowHostX11::ShowMaximizedWithBounds(
    343     const gfx::Rect& restored_bounds) {
    344   restored_bounds_ = restored_bounds;
    345   Maximize();
    346   Show();
    347 }
    348 
    349 bool DesktopRootWindowHostX11::IsVisible() const {
    350   return window_mapped_;
    351 }
    352 
    353 void DesktopRootWindowHostX11::SetSize(const gfx::Size& size) {
    354   // TODO(erg):
    355   NOTIMPLEMENTED();
    356 }
    357 
    358 void DesktopRootWindowHostX11::StackAtTop() {
    359   XRaiseWindow(xdisplay_, xwindow_);
    360 }
    361 
    362 void DesktopRootWindowHostX11::CenterWindow(const gfx::Size& size) {
    363   gfx::Rect parent_bounds = GetWorkAreaBoundsInScreen();
    364 
    365   // If |window_|'s transient parent bounds are big enough to contain |size|,
    366   // use them instead.
    367   if (content_window_->transient_parent()) {
    368     gfx::Rect transient_parent_rect =
    369         content_window_->transient_parent()->GetBoundsInScreen();
    370     if (transient_parent_rect.height() >= size.height() &&
    371         transient_parent_rect.width() >= size.width()) {
    372       parent_bounds = transient_parent_rect;
    373     }
    374   }
    375 
    376   gfx::Rect window_bounds(
    377       parent_bounds.x() + (parent_bounds.width() - size.width()) / 2,
    378       parent_bounds.y() + (parent_bounds.height() - size.height()) / 2,
    379       size.width(),
    380       size.height());
    381   // Don't size the window bigger than the parent, otherwise the user may not be
    382   // able to close or move it.
    383   window_bounds.AdjustToFit(parent_bounds);
    384 
    385   SetBounds(window_bounds);
    386 }
    387 
    388 void DesktopRootWindowHostX11::GetWindowPlacement(
    389     gfx::Rect* bounds,
    390     ui::WindowShowState* show_state) const {
    391   *bounds = bounds_;
    392 
    393   if (IsFullscreen()) {
    394     *show_state = ui::SHOW_STATE_FULLSCREEN;
    395   } else if (IsMinimized()) {
    396     *show_state = ui::SHOW_STATE_MINIMIZED;
    397   } else if (IsMaximized()) {
    398     *show_state = ui::SHOW_STATE_MAXIMIZED;
    399   } else if (!IsActive()) {
    400     *show_state = ui::SHOW_STATE_INACTIVE;
    401   } else {
    402     *show_state = ui::SHOW_STATE_NORMAL;
    403   }
    404 }
    405 
    406 gfx::Rect DesktopRootWindowHostX11::GetWindowBoundsInScreen() const {
    407   return bounds_;
    408 }
    409 
    410 gfx::Rect DesktopRootWindowHostX11::GetClientAreaBoundsInScreen() const {
    411   // TODO(erg): The NativeWidgetAura version returns |bounds_|, claiming its
    412   // needed for View::ConvertPointToScreen() to work
    413   // correctly. DesktopRootWindowHostWin::GetClientAreaBoundsInScreen() just
    414   // asks windows what it thinks the client rect is.
    415   //
    416   // Attempts to calculate the rect by asking the NonClientFrameView what it
    417   // thought its GetBoundsForClientView() were broke combobox drop down
    418   // placement.
    419   return bounds_;
    420 }
    421 
    422 gfx::Rect DesktopRootWindowHostX11::GetRestoredBounds() const {
    423   // We can't reliably track the restored bounds of a window, but we can get
    424   // the 90% case down. When *chrome* is the process that requests maximizing
    425   // or restoring bounds, we can record the current bounds before we request
    426   // maximization, and clear it when we detect a state change.
    427   if (!restored_bounds_.IsEmpty())
    428     return restored_bounds_;
    429 
    430   return GetWindowBoundsInScreen();
    431 }
    432 
    433 gfx::Rect DesktopRootWindowHostX11::GetWorkAreaBoundsInScreen() const {
    434   std::vector<int> value;
    435   if (ui::GetIntArrayProperty(x_root_window_, "_NET_WORKAREA", &value) &&
    436       value.size() >= 4) {
    437     return gfx::Rect(value[0], value[1], value[2], value[3]);
    438   }
    439 
    440   // Fetch the geometry of the root window.
    441   Window root;
    442   int x, y;
    443   unsigned int width, height;
    444   unsigned int border_width, depth;
    445   if (!XGetGeometry(xdisplay_, x_root_window_, &root, &x, &y,
    446                     &width, &height, &border_width, &depth)) {
    447     NOTIMPLEMENTED();
    448     return gfx::Rect(0, 0, 10, 10);
    449   }
    450 
    451   return gfx::Rect(x, y, width, height);
    452 }
    453 
    454 void DesktopRootWindowHostX11::SetShape(gfx::NativeRegion native_region) {
    455   if (custom_window_shape_)
    456     XDestroyRegion(custom_window_shape_);
    457   custom_window_shape_ = gfx::CreateRegionFromSkRegion(*native_region);
    458   ResetWindowRegion();
    459   delete native_region;
    460 }
    461 
    462 void DesktopRootWindowHostX11::Activate() {
    463   X11DesktopHandler::get()->ActivateWindow(xwindow_);
    464   native_widget_delegate_->AsWidget()->SetInitialFocus();
    465 }
    466 
    467 void DesktopRootWindowHostX11::Deactivate() {
    468   // Deactivating a window means activating nothing.
    469   X11DesktopHandler::get()->ActivateWindow(None);
    470 }
    471 
    472 bool DesktopRootWindowHostX11::IsActive() const {
    473   return X11DesktopHandler::get()->IsActiveWindow(xwindow_);
    474 }
    475 
    476 void DesktopRootWindowHostX11::Maximize() {
    477   // When we're the process requesting the maximizing, we can accurately keep
    478   // track of our restored bounds instead of relying on the heuristics that are
    479   // in the PropertyNotify and ConfigureNotify handlers.
    480   restored_bounds_ = bounds_;
    481 
    482   SetWMSpecState(true,
    483                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
    484                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
    485 }
    486 
    487 void DesktopRootWindowHostX11::Minimize() {
    488   XIconifyWindow(xdisplay_, xwindow_, 0);
    489 }
    490 
    491 void DesktopRootWindowHostX11::Restore() {
    492   SetWMSpecState(false,
    493                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_VERT"),
    494                  atom_cache_.GetAtom("_NET_WM_STATE_MAXIMIZED_HORZ"));
    495 }
    496 
    497 bool DesktopRootWindowHostX11::IsMaximized() const {
    498   return (HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_VERT") &&
    499           HasWMSpecProperty("_NET_WM_STATE_MAXIMIZED_HORZ"));
    500 }
    501 
    502 bool DesktopRootWindowHostX11::IsMinimized() const {
    503   return HasWMSpecProperty("_NET_WM_STATE_HIDDEN");
    504 }
    505 
    506 
    507 bool DesktopRootWindowHostX11::HasCapture() const {
    508   return g_current_capture == this;
    509 }
    510 
    511 void DesktopRootWindowHostX11::SetAlwaysOnTop(bool always_on_top) {
    512   is_always_on_top_ = always_on_top;
    513   SetWMSpecState(always_on_top,
    514                  atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"),
    515                  None);
    516 }
    517 
    518 bool DesktopRootWindowHostX11::IsAlwaysOnTop() const {
    519   return is_always_on_top_;
    520 }
    521 
    522 bool DesktopRootWindowHostX11::SetWindowTitle(const string16& title) {
    523   if (window_title_ == title)
    524     return false;
    525   window_title_ = title;
    526   std::string utf8str = UTF16ToUTF8(title);
    527   XChangeProperty(xdisplay_,
    528                   xwindow_,
    529                   atom_cache_.GetAtom("_NET_WM_NAME"),
    530                   atom_cache_.GetAtom("UTF8_STRING"),
    531                   8,
    532                   PropModeReplace,
    533                   reinterpret_cast<const unsigned char*>(utf8str.c_str()),
    534                   utf8str.size());
    535   // TODO(erg): This is technically wrong. So XStoreName and friends expect
    536   // this in Host Portable Character Encoding instead of UTF-8, which I believe
    537   // is Compound Text. This shouldn't matter 90% of the time since this is the
    538   // fallback to the UTF8 property above.
    539   XStoreName(xdisplay_, xwindow_, utf8str.c_str());
    540   return true;
    541 }
    542 
    543 void DesktopRootWindowHostX11::ClearNativeFocus() {
    544   // This method is weird and misnamed. Instead of clearing the native focus,
    545   // it sets the focus to our |content_window_|, which will trigger a cascade
    546   // of focus changes into views.
    547   if (content_window_ && aura::client::GetFocusClient(content_window_) &&
    548       content_window_->Contains(
    549           aura::client::GetFocusClient(content_window_)->GetFocusedWindow())) {
    550     aura::client::GetFocusClient(content_window_)->FocusWindow(content_window_);
    551   }
    552 }
    553 
    554 Widget::MoveLoopResult DesktopRootWindowHostX11::RunMoveLoop(
    555     const gfx::Vector2d& drag_offset,
    556     Widget::MoveLoopSource source,
    557     Widget::MoveLoopEscapeBehavior escape_behavior) {
    558   aura::client::WindowMoveSource window_move_source =
    559       source == Widget::MOVE_LOOP_SOURCE_MOUSE ?
    560       aura::client::WINDOW_MOVE_SOURCE_MOUSE :
    561       aura::client::WINDOW_MOVE_SOURCE_TOUCH;
    562   if (x11_window_move_client_->RunMoveLoop(content_window_, drag_offset,
    563       window_move_source) == aura::client::MOVE_SUCCESSFUL)
    564     return Widget::MOVE_LOOP_SUCCESSFUL;
    565 
    566   return Widget::MOVE_LOOP_CANCELED;
    567 }
    568 
    569 void DesktopRootWindowHostX11::EndMoveLoop() {
    570   x11_window_move_client_->EndMoveLoop();
    571 }
    572 
    573 void DesktopRootWindowHostX11::SetVisibilityChangedAnimationsEnabled(
    574     bool value) {
    575   // Much like the previous NativeWidgetGtk, we don't have anything to do here.
    576 }
    577 
    578 bool DesktopRootWindowHostX11::ShouldUseNativeFrame() {
    579   return false;
    580 }
    581 
    582 void DesktopRootWindowHostX11::FrameTypeChanged() {
    583   // Replace the frame and layout the contents. Even though we don't have a
    584   // swapable glass frame like on Windows, we still replace the frame because
    585   // the button assets don't update otherwise.
    586   native_widget_delegate_->AsWidget()->non_client_view()->UpdateFrame();
    587 }
    588 
    589 NonClientFrameView* DesktopRootWindowHostX11::CreateNonClientFrameView() {
    590   return NULL;
    591 }
    592 
    593 void DesktopRootWindowHostX11::SetFullscreen(bool fullscreen) {
    594   is_fullscreen_ = fullscreen;
    595   SetWMSpecState(fullscreen,
    596                  atom_cache_.GetAtom("_NET_WM_STATE_FULLSCREEN"),
    597                  None);
    598 }
    599 
    600 bool DesktopRootWindowHostX11::IsFullscreen() const {
    601   return is_fullscreen_;
    602 }
    603 
    604 void DesktopRootWindowHostX11::SetOpacity(unsigned char opacity) {
    605   // X server opacity is in terms of 32 bit unsigned int space, and counts from
    606   // the opposite direction.
    607   // XChangeProperty() expects "cardinality" to be long.
    608   unsigned long cardinality = opacity * 0x1010101;
    609 
    610   if (cardinality == 0xffffffff) {
    611     XDeleteProperty(xdisplay_, xwindow_,
    612                     atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"));
    613   } else {
    614     XChangeProperty(xdisplay_, xwindow_,
    615                     atom_cache_.GetAtom("_NET_WM_WINDOW_OPACITY"),
    616                     XA_CARDINAL, 32,
    617                     PropModeReplace,
    618                     reinterpret_cast<unsigned char*>(&cardinality), 1);
    619   }
    620 }
    621 
    622 void DesktopRootWindowHostX11::SetWindowIcons(
    623     const gfx::ImageSkia& window_icon, const gfx::ImageSkia& app_icon) {
    624   // TODO(erg): The way we handle icons across different versions of chrome
    625   // could be substantially improved. The Windows version does its own thing
    626   // and only sometimes comes down this code path. The icon stuff in
    627   // ChromeViewsDelegate is hard coded to use HICONs. Likewise, we're hard
    628   // coded to be given two images instead of an arbitrary collection of images
    629   // so that we can pass to the WM.
    630   //
    631   // All of this could be made much, much better.
    632   std::vector<unsigned long> data;
    633 
    634   if (window_icon.HasRepresentation(1.0f))
    635     SerializeImageRepresentation(window_icon.GetRepresentation(1.0f), &data);
    636 
    637   if (app_icon.HasRepresentation(1.0f))
    638     SerializeImageRepresentation(app_icon.GetRepresentation(1.0f), &data);
    639 
    640   if (data.empty())
    641     XDeleteProperty(xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_ICON"));
    642   else
    643     ui::SetAtomArrayProperty(xwindow_, "_NET_WM_ICON", "CARDINAL", data);
    644 }
    645 
    646 void DesktopRootWindowHostX11::InitModalType(ui::ModalType modal_type) {
    647   switch (modal_type) {
    648     case ui::MODAL_TYPE_NONE:
    649       break;
    650     default:
    651       // TODO(erg): Figure out under what situations |modal_type| isn't
    652       // none. The comment in desktop_native_widget_aura.cc suggests that this
    653       // is rare.
    654       NOTIMPLEMENTED();
    655   }
    656 }
    657 
    658 void DesktopRootWindowHostX11::FlashFrame(bool flash_frame) {
    659   // TODO(erg):
    660   NOTIMPLEMENTED();
    661 }
    662 
    663 void DesktopRootWindowHostX11::OnRootViewLayout() const {
    664   if (!window_mapped_)
    665     return;
    666 
    667   XSizeHints hints;
    668   long supplied_return;
    669   XGetWMNormalHints(xdisplay_, xwindow_, &hints, &supplied_return);
    670 
    671   gfx::Size minimum = native_widget_delegate_->GetMinimumSize();
    672   if (minimum.IsEmpty()) {
    673     hints.flags &= ~PMinSize;
    674   } else {
    675     hints.flags |= PMinSize;
    676     hints.min_width = minimum.width();
    677     hints.min_height = minimum.height();
    678   }
    679 
    680   gfx::Size maximum = native_widget_delegate_->GetMaximumSize();
    681   if (maximum.IsEmpty()) {
    682     hints.flags &= ~PMaxSize;
    683   } else {
    684     hints.flags |= PMaxSize;
    685     hints.max_width = maximum.width();
    686     hints.max_height = maximum.height();
    687   }
    688 
    689   XSetWMNormalHints(xdisplay_, xwindow_, &hints);
    690 }
    691 
    692 void DesktopRootWindowHostX11::OnNativeWidgetFocus() {
    693   native_widget_delegate_->AsWidget()->GetInputMethod()->OnFocus();
    694 }
    695 
    696 void DesktopRootWindowHostX11::OnNativeWidgetBlur() {
    697   if (xwindow_)
    698     native_widget_delegate_->AsWidget()->GetInputMethod()->OnBlur();
    699 }
    700 
    701 bool DesktopRootWindowHostX11::IsAnimatingClosed() const {
    702   return false;
    703 }
    704 
    705 ////////////////////////////////////////////////////////////////////////////////
    706 // DesktopRootWindowHostX11, aura::RootWindowHost implementation:
    707 
    708 aura::RootWindow* DesktopRootWindowHostX11::GetRootWindow() {
    709   return root_window_;
    710 }
    711 
    712 gfx::AcceleratedWidget DesktopRootWindowHostX11::GetAcceleratedWidget() {
    713   return xwindow_;
    714 }
    715 
    716 void DesktopRootWindowHostX11::Show() {
    717   if (!window_mapped_) {
    718     // Before we map the window, set size hints. Otherwise, some window managers
    719     // will ignore toplevel XMoveWindow commands.
    720     XSizeHints size_hints;
    721     size_hints.flags = PPosition;
    722     size_hints.x = bounds_.x();
    723     size_hints.y = bounds_.y();
    724     XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
    725 
    726     XMapWindow(xdisplay_, xwindow_);
    727 
    728     // We now block until our window is mapped. Some X11 APIs will crash and
    729     // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
    730     // asynchronous.
    731     base::MessagePumpX11::Current()->BlockUntilWindowMapped(xwindow_);
    732     window_mapped_ = true;
    733   }
    734 
    735   native_widget_delegate_->AsWidget()->SetInitialFocus();
    736 }
    737 
    738 void DesktopRootWindowHostX11::Hide() {
    739   if (window_mapped_) {
    740     XWithdrawWindow(xdisplay_, xwindow_, 0);
    741     window_mapped_ = false;
    742   }
    743 }
    744 
    745 void DesktopRootWindowHostX11::ToggleFullScreen() {
    746   NOTIMPLEMENTED();
    747 }
    748 
    749 gfx::Rect DesktopRootWindowHostX11::GetBounds() const {
    750   return bounds_;
    751 }
    752 
    753 void DesktopRootWindowHostX11::SetBounds(const gfx::Rect& bounds) {
    754   bool origin_changed = bounds_.origin() != bounds.origin();
    755   bool size_changed = bounds_.size() != bounds.size();
    756   XWindowChanges changes = {0};
    757   unsigned value_mask = 0;
    758 
    759   if (size_changed) {
    760     // X11 will send an XError at our process if have a 0 sized window.
    761     DCHECK_GT(bounds.width(), 0);
    762     DCHECK_GT(bounds.height(), 0);
    763 
    764     changes.width = bounds.width();
    765     changes.height = bounds.height();
    766     value_mask |= CWHeight | CWWidth;
    767   }
    768 
    769   if (origin_changed) {
    770     changes.x = bounds.x();
    771     changes.y = bounds.y();
    772     value_mask |= CWX | CWY;
    773   }
    774   if (value_mask)
    775     XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
    776 
    777   // Assume that the resize will go through as requested, which should be the
    778   // case if we're running without a window manager.  If there's a window
    779   // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
    780   // (possibly synthetic) ConfigureNotify about the actual size and correct
    781   // |bounds_| later.
    782   bounds_ = bounds;
    783 
    784   if (origin_changed)
    785     native_widget_delegate_->AsWidget()->OnNativeWidgetMove();
    786   if (size_changed)
    787     delegate_->OnHostResized(bounds.size());
    788   else
    789     delegate_->OnHostPaint(gfx::Rect(bounds.size()));
    790 }
    791 
    792 gfx::Insets DesktopRootWindowHostX11::GetInsets() const {
    793   return gfx::Insets();
    794 }
    795 
    796 void DesktopRootWindowHostX11::SetInsets(const gfx::Insets& insets) {
    797 }
    798 
    799 gfx::Point DesktopRootWindowHostX11::GetLocationOnNativeScreen() const {
    800   return bounds_.origin();
    801 }
    802 
    803 void DesktopRootWindowHostX11::SetCapture() {
    804   // This is vaguely based on the old NativeWidgetGtk implementation.
    805   //
    806   // X11's XPointerGrab() shouldn't be used for everything; it doesn't map
    807   // cleanly to Windows' SetCapture(). GTK only provides a separate concept of
    808   // a grab that wasn't the X11 pointer grab, but was instead a manual
    809   // redirection of the event. (You need to drop into GDK if you want to
    810   // perform a raw X11 grab).
    811 
    812   if (g_current_capture)
    813     g_current_capture->OnCaptureReleased();
    814 
    815   g_current_capture = this;
    816 
    817   // TODO(erg): In addition to the above, NativeWidgetGtk performs a full X
    818   // pointer grab when our NativeWidget is of type Menu. However, things work
    819   // without it. Clicking inside a chrome window causes a release capture, and
    820   // clicking outside causes an activation change. Since previous attempts at
    821   // using XPointerGrab() to implement this have locked my X server, I'm going
    822   // to skip this for now.
    823 }
    824 
    825 void DesktopRootWindowHostX11::ReleaseCapture() {
    826   if (g_current_capture)
    827     g_current_capture->OnCaptureReleased();
    828 }
    829 
    830 void DesktopRootWindowHostX11::SetCursor(gfx::NativeCursor cursor) {
    831   XDefineCursor(xdisplay_, xwindow_, cursor.platform());
    832 }
    833 
    834 bool DesktopRootWindowHostX11::QueryMouseLocation(
    835     gfx::Point* location_return) {
    836   aura::client::CursorClient* cursor_client =
    837       aura::client::GetCursorClient(GetRootWindow()->window());
    838   if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
    839     *location_return = gfx::Point(0, 0);
    840     return false;
    841   }
    842 
    843   ::Window root_return, child_return;
    844   int root_x_return, root_y_return, win_x_return, win_y_return;
    845   unsigned int mask_return;
    846   XQueryPointer(xdisplay_,
    847                 xwindow_,
    848                 &root_return,
    849                 &child_return,
    850                 &root_x_return, &root_y_return,
    851                 &win_x_return, &win_y_return,
    852                 &mask_return);
    853   *location_return = gfx::Point(
    854       std::max(0, std::min(bounds_.width(), win_x_return)),
    855       std::max(0, std::min(bounds_.height(), win_y_return)));
    856   return (win_x_return >= 0 && win_x_return < bounds_.width() &&
    857           win_y_return >= 0 && win_y_return < bounds_.height());
    858 }
    859 
    860 bool DesktopRootWindowHostX11::ConfineCursorToRootWindow() {
    861   NOTIMPLEMENTED();
    862   return false;
    863 }
    864 
    865 void DesktopRootWindowHostX11::UnConfineCursor() {
    866   NOTIMPLEMENTED();
    867 }
    868 
    869 void DesktopRootWindowHostX11::OnCursorVisibilityChanged(bool show) {
    870   // TODO(erg): Conditional on us enabling touch on desktop linux builds, do
    871   // the same tap-to-click disabling here that chromeos does.
    872 }
    873 
    874 void DesktopRootWindowHostX11::MoveCursorTo(const gfx::Point& location) {
    875   XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
    876                bounds_.x() + location.x(), bounds_.y() + location.y());
    877 }
    878 
    879 void DesktopRootWindowHostX11::PostNativeEvent(
    880     const base::NativeEvent& native_event) {
    881   DCHECK(xwindow_);
    882   DCHECK(xdisplay_);
    883   XEvent xevent = *native_event;
    884   xevent.xany.display = xdisplay_;
    885   xevent.xany.window = xwindow_;
    886 
    887   switch (xevent.type) {
    888     case EnterNotify:
    889     case LeaveNotify:
    890     case MotionNotify:
    891     case KeyPress:
    892     case KeyRelease:
    893     case ButtonPress:
    894     case ButtonRelease: {
    895       // The fields used below are in the same place for all of events
    896       // above. Using xmotion from XEvent's unions to avoid repeating
    897       // the code.
    898       xevent.xmotion.root = x_root_window_;
    899       xevent.xmotion.time = CurrentTime;
    900 
    901       gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
    902       ConvertPointToNativeScreen(&point);
    903       xevent.xmotion.x_root = point.x();
    904       xevent.xmotion.y_root = point.y();
    905     }
    906     default:
    907       break;
    908   }
    909   XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
    910 }
    911 
    912 void DesktopRootWindowHostX11::OnDeviceScaleFactorChanged(
    913     float device_scale_factor) {
    914 }
    915 
    916 void DesktopRootWindowHostX11::PrepareForShutdown() {
    917 }
    918 
    919 ////////////////////////////////////////////////////////////////////////////////
    920 // DesktopRootWindowHostX11, private:
    921 
    922 void DesktopRootWindowHostX11::InitX11Window(
    923     const Widget::InitParams& params) {
    924   unsigned long attribute_mask = CWBackPixmap;
    925   XSetWindowAttributes swa;
    926   memset(&swa, 0, sizeof(swa));
    927   swa.background_pixmap = None;
    928 
    929   ::Atom window_type;
    930   switch (params.type) {
    931     case Widget::InitParams::TYPE_MENU:
    932       swa.override_redirect = True;
    933       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_MENU");
    934       break;
    935     case Widget::InitParams::TYPE_TOOLTIP:
    936       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_TOOLTIP");
    937       break;
    938     case Widget::InitParams::TYPE_POPUP:
    939       swa.override_redirect = True;
    940       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NOTIFICATION");
    941       break;
    942     case Widget::InitParams::TYPE_DRAG:
    943       swa.override_redirect = True;
    944       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_DND");
    945       break;
    946     default:
    947       window_type = atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE_NORMAL");
    948       break;
    949   }
    950   if (swa.override_redirect)
    951     attribute_mask |= CWOverrideRedirect;
    952 
    953   bounds_ = params.bounds;
    954   xwindow_ = XCreateWindow(
    955       xdisplay_, x_root_window_,
    956       bounds_.x(), bounds_.y(),
    957       bounds_.width(), bounds_.height(),
    958       0,               // border width
    959       CopyFromParent,  // depth
    960       InputOutput,
    961       CopyFromParent,  // visual
    962       attribute_mask,
    963       &swa);
    964   base::MessagePumpX11::Current()->AddDispatcherForWindow(this, xwindow_);
    965   open_windows().push_back(xwindow_);
    966 
    967   // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL().
    968 
    969   long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
    970                     KeyPressMask | KeyReleaseMask |
    971                     EnterWindowMask | LeaveWindowMask |
    972                     ExposureMask | VisibilityChangeMask |
    973                     StructureNotifyMask | PropertyChangeMask |
    974                     PointerMotionMask;
    975   XSelectInput(xdisplay_, xwindow_, event_mask);
    976   XFlush(xdisplay_);
    977 
    978   if (ui::IsXInput2Available())
    979     ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
    980 
    981   // TODO(erg): We currently only request window deletion events. We also
    982   // should listen for activation events and anything else that GTK+ listens
    983   // for, and do something useful.
    984   ::Atom protocols[2];
    985   protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
    986   protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
    987   XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
    988 
    989   // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
    990   // the desktop environment.
    991   XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
    992 
    993   // Likewise, the X server needs to know this window's pid so it knows which
    994   // program to kill if the window hangs.
    995   // XChangeProperty() expects "pid" to be long.
    996   COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
    997   long pid = getpid();
    998   XChangeProperty(xdisplay_,
    999                   xwindow_,
   1000                   atom_cache_.GetAtom("_NET_WM_PID"),
   1001                   XA_CARDINAL,
   1002                   32,
   1003                   PropModeReplace,
   1004                   reinterpret_cast<unsigned char*>(&pid), 1);
   1005 
   1006   XChangeProperty(xdisplay_,
   1007                   xwindow_,
   1008                   atom_cache_.GetAtom("_NET_WM_WINDOW_TYPE"),
   1009                   XA_ATOM,
   1010                   32,
   1011                   PropModeReplace,
   1012                   reinterpret_cast<unsigned char*>(&window_type), 1);
   1013 
   1014   // List of window state properties (_NET_WM_STATE) to set, if any.
   1015   std::vector< ::Atom> state_atom_list;
   1016 
   1017   // Remove popup windows from taskbar.
   1018   if (params.type == Widget::InitParams::TYPE_POPUP ||
   1019       params.type == Widget::InitParams::TYPE_BUBBLE) {
   1020     state_atom_list.push_back(
   1021         atom_cache_.GetAtom("_NET_WM_STATE_SKIP_TASKBAR"));
   1022   }
   1023 
   1024   // If the window should stay on top of other windows, add the
   1025   // _NET_WM_STATE_ABOVE property.
   1026   is_always_on_top_ = params.keep_on_top;
   1027   if (is_always_on_top_)
   1028     state_atom_list.push_back(atom_cache_.GetAtom("_NET_WM_STATE_ABOVE"));
   1029 
   1030   // Setting _NET_WM_STATE by sending a message to the root_window (with
   1031   // SetWMSpecState) has no effect here since the window has not yet been
   1032   // mapped. So we manually change the state.
   1033   if (!state_atom_list.empty()) {
   1034     ui::SetAtomArrayProperty(xwindow_,
   1035                              "_NET_WM_STATE",
   1036                              "ATOM",
   1037                              state_atom_list);
   1038   }
   1039 
   1040   if (!params.wm_class_name.empty() || !params.wm_class_class.empty()) {
   1041     ui::SetWindowClassHint(
   1042         xdisplay_, xwindow_, params.wm_class_name, params.wm_class_class);
   1043   }
   1044   if (!params.wm_role_name.empty() ||
   1045       params.type == Widget::InitParams::TYPE_POPUP) {
   1046     const char kX11WindowRolePopup[] = "popup";
   1047     ui::SetWindowRole(xdisplay_, xwindow_, params.wm_role_name.empty() ?
   1048                       std::string(kX11WindowRolePopup) : params.wm_role_name);
   1049   }
   1050 
   1051   // If we have a parent, record the parent/child relationship. We use this
   1052   // data during destruction to make sure that when we try to close a parent
   1053   // window, we also destroy all child windows.
   1054   if (params.parent && params.parent->GetDispatcher()) {
   1055     XID parent_xid =
   1056         params.parent->GetDispatcher()->host()->GetAcceleratedWidget();
   1057     window_parent_ = GetHostForXID(parent_xid);
   1058     DCHECK(window_parent_);
   1059     window_parent_->window_children_.insert(this);
   1060   }
   1061 
   1062   // If we have a delegate which is providing a default window icon, use that
   1063   // icon.
   1064   gfx::ImageSkia* window_icon = ViewsDelegate::views_delegate ?
   1065       ViewsDelegate::views_delegate->GetDefaultWindowIcon() : NULL;
   1066   if (window_icon) {
   1067     SetWindowIcons(gfx::ImageSkia(), *window_icon);
   1068   }
   1069 }
   1070 
   1071 bool DesktopRootWindowHostX11::IsWindowManagerPresent() {
   1072   // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
   1073   // of WM_Sn selections (where n is a screen number).
   1074   return XGetSelectionOwner(
   1075       xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
   1076 }
   1077 
   1078 void DesktopRootWindowHostX11::SetWMSpecState(bool enabled,
   1079                                                 ::Atom state1,
   1080                                                 ::Atom state2) {
   1081   XEvent xclient;
   1082   memset(&xclient, 0, sizeof(xclient));
   1083   xclient.type = ClientMessage;
   1084   xclient.xclient.window = xwindow_;
   1085   xclient.xclient.message_type = atom_cache_.GetAtom("_NET_WM_STATE");
   1086   xclient.xclient.format = 32;
   1087   xclient.xclient.data.l[0] =
   1088       enabled ? k_NET_WM_STATE_ADD : k_NET_WM_STATE_REMOVE;
   1089   xclient.xclient.data.l[1] = state1;
   1090   xclient.xclient.data.l[2] = state2;
   1091   xclient.xclient.data.l[3] = 1;
   1092   xclient.xclient.data.l[4] = 0;
   1093 
   1094   XSendEvent(xdisplay_, x_root_window_, False,
   1095              SubstructureRedirectMask | SubstructureNotifyMask,
   1096              &xclient);
   1097 }
   1098 
   1099 bool DesktopRootWindowHostX11::HasWMSpecProperty(const char* property) const {
   1100   return window_properties_.find(atom_cache_.GetAtom(property)) !=
   1101       window_properties_.end();
   1102 }
   1103 
   1104 void DesktopRootWindowHostX11::OnCaptureReleased() {
   1105   g_current_capture = NULL;
   1106   delegate_->OnHostLostWindowCapture();
   1107   native_widget_delegate_->OnMouseCaptureLost();
   1108 }
   1109 
   1110 void DesktopRootWindowHostX11::DispatchMouseEvent(ui::MouseEvent* event) {
   1111   if (!g_current_capture || g_current_capture == this) {
   1112     delegate_->OnHostMouseEvent(event);
   1113   } else {
   1114     // Another DesktopRootWindowHostX11 has installed itself as
   1115     // capture. Translate the event's location and dispatch to the other.
   1116     event->ConvertLocationToTarget(root_window_->window(),
   1117                                    g_current_capture->root_window_->window());
   1118     g_current_capture->delegate_->OnHostMouseEvent(event);
   1119   }
   1120 }
   1121 
   1122 void DesktopRootWindowHostX11::DispatchTouchEvent(ui::TouchEvent* event) {
   1123   if (g_current_capture && g_current_capture != this &&
   1124       event->type() == ui::ET_TOUCH_PRESSED) {
   1125     event->ConvertLocationToTarget(root_window_->window(),
   1126                                    g_current_capture->root_window_->window());
   1127     g_current_capture->delegate_->OnHostTouchEvent(event);
   1128   } else {
   1129     delegate_->OnHostTouchEvent(event);
   1130   }
   1131 }
   1132 
   1133 void DesktopRootWindowHostX11::ResetWindowRegion() {
   1134   // If a custom window shape was supplied then apply it.
   1135   if (custom_window_shape_) {
   1136     XShapeCombineRegion(
   1137         xdisplay_, xwindow_, ShapeBounding, 0, 0, custom_window_shape_, false);
   1138     return;
   1139   }
   1140 
   1141   if (!IsMaximized()) {
   1142     gfx::Path window_mask;
   1143     views::Widget* widget = native_widget_delegate_->AsWidget();
   1144     if (widget->non_client_view()) {
   1145       // Some frame views define a custom (non-rectangular) window mask. If
   1146       // so, use it to define the window shape. If not, fall through.
   1147       widget->non_client_view()->GetWindowMask(bounds_.size(), &window_mask);
   1148       if (window_mask.countPoints() > 0) {
   1149         Region region = gfx::CreateRegionFromSkPath(window_mask);
   1150         XShapeCombineRegion(xdisplay_, xwindow_, ShapeBounding,
   1151                             0, 0, region, false);
   1152         XDestroyRegion(region);
   1153         return;
   1154       }
   1155     }
   1156   }
   1157 
   1158   // If we didn't set the shape for any reason, reset the shaping information
   1159   // by ShapeSet-ing with our bounds rect.
   1160   XRectangle r = { 0, 0, static_cast<unsigned short>(bounds_.width()),
   1161                    static_cast<unsigned short>(bounds_.height()) };
   1162   XShapeCombineRectangles(xdisplay_, xwindow_, ShapeBounding,
   1163                           0, 0, &r, 1, ShapeSet, YXBanded);
   1164 }
   1165 
   1166 void DesktopRootWindowHostX11::SerializeImageRepresentation(
   1167     const gfx::ImageSkiaRep& rep,
   1168     std::vector<unsigned long>* data) {
   1169   int width = rep.GetWidth();
   1170   data->push_back(width);
   1171 
   1172   int height = rep.GetHeight();
   1173   data->push_back(height);
   1174 
   1175   const SkBitmap& bitmap = rep.sk_bitmap();
   1176   SkAutoLockPixels locker(bitmap);
   1177 
   1178   for (int y = 0; y < height; ++y)
   1179     for (int x = 0; x < width; ++x)
   1180       data->push_back(bitmap.getColor(x, y));
   1181 }
   1182 
   1183 std::list<XID>& DesktopRootWindowHostX11::open_windows() {
   1184   if (!open_windows_)
   1185     open_windows_ = new std::list<XID>();
   1186   return *open_windows_;
   1187 }
   1188 
   1189 ////////////////////////////////////////////////////////////////////////////////
   1190 // DesktopRootWindowHostX11, MessageLoop::Dispatcher implementation:
   1191 
   1192 bool DesktopRootWindowHostX11::Dispatch(const base::NativeEvent& event) {
   1193   XEvent* xev = event;
   1194 
   1195   TRACE_EVENT1("views", "DesktopRootWindowHostX11::Dispatch",
   1196                "event->type", event->type);
   1197 
   1198   // May want to factor CheckXEventForConsistency(xev); into a common location
   1199   // since it is called here.
   1200   switch (xev->type) {
   1201     case EnterNotify:
   1202     case LeaveNotify: {
   1203       if (!g_current_capture)
   1204         X11DesktopHandler::get()->ProcessXEvent(xev);
   1205       ui::MouseEvent mouse_event(xev);
   1206       DispatchMouseEvent(&mouse_event);
   1207       break;
   1208     }
   1209     case Expose: {
   1210       gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
   1211                             xev->xexpose.width, xev->xexpose.height);
   1212       delegate_->OnHostPaint(damage_rect);
   1213       break;
   1214     }
   1215     case KeyPress: {
   1216       ui::KeyEvent keydown_event(xev, false);
   1217       delegate_->OnHostKeyEvent(&keydown_event);
   1218       break;
   1219     }
   1220     case KeyRelease: {
   1221       ui::KeyEvent keyup_event(xev, false);
   1222       delegate_->OnHostKeyEvent(&keyup_event);
   1223       break;
   1224     }
   1225     case ButtonPress: {
   1226       if (static_cast<int>(xev->xbutton.button) == kBackMouseButton ||
   1227           static_cast<int>(xev->xbutton.button) == kForwardMouseButton) {
   1228         aura::client::UserActionClient* gesture_client =
   1229             aura::client::GetUserActionClient(root_window_->window());
   1230         if (gesture_client) {
   1231           gesture_client->OnUserAction(
   1232               static_cast<int>(xev->xbutton.button) == kBackMouseButton ?
   1233               aura::client::UserActionClient::BACK :
   1234               aura::client::UserActionClient::FORWARD);
   1235         }
   1236         break;
   1237       }
   1238     }  // fallthrough
   1239     case ButtonRelease: {
   1240       ui::EventType event_type = ui::EventTypeFromNative(xev);
   1241       switch (event_type) {
   1242         case ui::ET_MOUSEWHEEL: {
   1243           ui::MouseWheelEvent mouseev(xev);
   1244           DispatchMouseEvent(&mouseev);
   1245           break;
   1246         }
   1247         case ui::ET_MOUSE_PRESSED:
   1248         case ui::ET_MOUSE_RELEASED: {
   1249           ui::MouseEvent mouseev(xev);
   1250           DispatchMouseEvent(&mouseev);
   1251           break;
   1252         }
   1253         case ui::ET_UNKNOWN:
   1254           // No event is created for X11-release events for mouse-wheel buttons.
   1255           break;
   1256         default:
   1257           NOTREACHED() << event_type;
   1258       }
   1259       break;
   1260     }
   1261     case FocusOut:
   1262       if (xev->xfocus.mode != NotifyGrab) {
   1263         ReleaseCapture();
   1264         delegate_->OnHostLostWindowCapture();
   1265       } else {
   1266         delegate_->OnHostLostMouseGrab();
   1267       }
   1268       break;
   1269     case ConfigureNotify: {
   1270       DCHECK_EQ(xwindow_, xev->xconfigure.window);
   1271       DCHECK_EQ(xwindow_, xev->xconfigure.event);
   1272       // It's possible that the X window may be resized by some other means than
   1273       // from within aura (e.g. the X window manager can change the size). Make
   1274       // sure the root window size is maintained properly.
   1275       int translated_x = xev->xconfigure.x;
   1276       int translated_y = xev->xconfigure.y;
   1277       if (!xev->xconfigure.send_event && !xev->xconfigure.override_redirect) {
   1278         Window unused;
   1279         XTranslateCoordinates(xdisplay_, xwindow_, x_root_window_,
   1280             0, 0, &translated_x, &translated_y, &unused);
   1281       }
   1282       gfx::Rect bounds(translated_x, translated_y,
   1283                        xev->xconfigure.width, xev->xconfigure.height);
   1284       bool size_changed = bounds_.size() != bounds.size();
   1285       bool origin_changed = bounds_.origin() != bounds.origin();
   1286       previous_bounds_ = bounds_;
   1287       bounds_ = bounds;
   1288       if (size_changed)
   1289         delegate_->OnHostResized(bounds.size());
   1290       if (origin_changed)
   1291         delegate_->OnHostMoved(bounds_.origin());
   1292       ResetWindowRegion();
   1293       break;
   1294     }
   1295     case GenericEvent: {
   1296       ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
   1297       if (!factory->ShouldProcessXI2Event(xev))
   1298         break;
   1299 
   1300       ui::EventType type = ui::EventTypeFromNative(xev);
   1301       XEvent last_event;
   1302       int num_coalesced = 0;
   1303 
   1304       switch (type) {
   1305         case ui::ET_TOUCH_MOVED:
   1306           num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
   1307           if (num_coalesced > 0)
   1308             xev = &last_event;
   1309           // fallthrough
   1310         case ui::ET_TOUCH_PRESSED:
   1311         case ui::ET_TOUCH_RELEASED: {
   1312           ui::TouchEvent touchev(xev);
   1313           DispatchTouchEvent(&touchev);
   1314           break;
   1315         }
   1316         case ui::ET_MOUSE_MOVED:
   1317         case ui::ET_MOUSE_DRAGGED:
   1318         case ui::ET_MOUSE_PRESSED:
   1319         case ui::ET_MOUSE_RELEASED:
   1320         case ui::ET_MOUSE_ENTERED:
   1321         case ui::ET_MOUSE_EXITED: {
   1322           if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
   1323             // If this is a motion event, we want to coalesce all pending motion
   1324             // events that are at the top of the queue.
   1325             num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
   1326             if (num_coalesced > 0)
   1327               xev = &last_event;
   1328           } else if (type == ui::ET_MOUSE_PRESSED) {
   1329             XIDeviceEvent* xievent =
   1330                 static_cast<XIDeviceEvent*>(xev->xcookie.data);
   1331             int button = xievent->detail;
   1332             if (button == kBackMouseButton || button == kForwardMouseButton) {
   1333               aura::client::UserActionClient* gesture_client =
   1334                   aura::client::GetUserActionClient(
   1335                       delegate_->AsRootWindow()->window());
   1336               if (gesture_client) {
   1337                 bool reverse_direction =
   1338                     ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled();
   1339                 gesture_client->OnUserAction(
   1340                     (button == kBackMouseButton && !reverse_direction) ||
   1341                     (button == kForwardMouseButton && reverse_direction) ?
   1342                     aura::client::UserActionClient::BACK :
   1343                     aura::client::UserActionClient::FORWARD);
   1344               }
   1345               break;
   1346             }
   1347           } else if (type == ui::ET_MOUSE_RELEASED) {
   1348             XIDeviceEvent* xievent =
   1349                 static_cast<XIDeviceEvent*>(xev->xcookie.data);
   1350             int button = xievent->detail;
   1351             if (button == kBackMouseButton || button == kForwardMouseButton) {
   1352               // We've already passed the back/forward mouse down to the user
   1353               // action client; we want to swallow the corresponding release.
   1354               break;
   1355             }
   1356           }
   1357           ui::MouseEvent mouseev(xev);
   1358           DispatchMouseEvent(&mouseev);
   1359           break;
   1360         }
   1361         case ui::ET_MOUSEWHEEL: {
   1362           ui::MouseWheelEvent mouseev(xev);
   1363           DispatchMouseEvent(&mouseev);
   1364           break;
   1365         }
   1366         case ui::ET_SCROLL_FLING_START:
   1367         case ui::ET_SCROLL_FLING_CANCEL:
   1368         case ui::ET_SCROLL: {
   1369           ui::ScrollEvent scrollev(xev);
   1370           delegate_->OnHostScrollEvent(&scrollev);
   1371           break;
   1372         }
   1373         case ui::ET_UNKNOWN:
   1374           break;
   1375         default:
   1376           NOTREACHED();
   1377       }
   1378 
   1379       // If we coalesced an event we need to free its cookie.
   1380       if (num_coalesced > 0)
   1381         XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
   1382       break;
   1383     }
   1384     case MapNotify: {
   1385       FOR_EACH_OBSERVER(DesktopRootWindowHostObserverX11,
   1386                         observer_list_,
   1387                         OnWindowMapped(xwindow_));
   1388       break;
   1389     }
   1390     case UnmapNotify: {
   1391       FOR_EACH_OBSERVER(DesktopRootWindowHostObserverX11,
   1392                         observer_list_,
   1393                         OnWindowUnmapped(xwindow_));
   1394       break;
   1395     }
   1396     case ClientMessage: {
   1397       Atom message_type = xev->xclient.message_type;
   1398       if (message_type == atom_cache_.GetAtom("WM_PROTOCOLS")) {
   1399         Atom protocol = static_cast<Atom>(xev->xclient.data.l[0]);
   1400         if (protocol == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
   1401           // We have received a close message from the window manager.
   1402           root_window_->OnRootWindowHostCloseRequested();
   1403         } else if (protocol == atom_cache_.GetAtom("_NET_WM_PING")) {
   1404           XEvent reply_event = *xev;
   1405           reply_event.xclient.window = x_root_window_;
   1406 
   1407           XSendEvent(xdisplay_,
   1408                      reply_event.xclient.window,
   1409                      False,
   1410                      SubstructureRedirectMask | SubstructureNotifyMask,
   1411                      &reply_event);
   1412         }
   1413       } else if (message_type == atom_cache_.GetAtom("XdndEnter")) {
   1414         drag_drop_client_->OnXdndEnter(xev->xclient);
   1415       } else if (message_type == atom_cache_.GetAtom("XdndLeave")) {
   1416         drag_drop_client_->OnXdndLeave(xev->xclient);
   1417       } else if (message_type == atom_cache_.GetAtom("XdndPosition")) {
   1418         drag_drop_client_->OnXdndPosition(xev->xclient);
   1419       } else if (message_type == atom_cache_.GetAtom("XdndStatus")) {
   1420         drag_drop_client_->OnXdndStatus(xev->xclient);
   1421       } else if (message_type == atom_cache_.GetAtom("XdndFinished")) {
   1422         drag_drop_client_->OnXdndFinished(xev->xclient);
   1423       } else if (message_type == atom_cache_.GetAtom("XdndDrop")) {
   1424         drag_drop_client_->OnXdndDrop(xev->xclient);
   1425       }
   1426       break;
   1427     }
   1428     case MappingNotify: {
   1429       switch (xev->xmapping.request) {
   1430         case MappingModifier:
   1431         case MappingKeyboard:
   1432           XRefreshKeyboardMapping(&xev->xmapping);
   1433           root_window_->OnKeyboardMappingChanged();
   1434           break;
   1435         case MappingPointer:
   1436           ui::DeviceDataManager::GetInstance()->UpdateButtonMap();
   1437           break;
   1438         default:
   1439           NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
   1440           break;
   1441       }
   1442       break;
   1443     }
   1444     case MotionNotify: {
   1445       // Discard all but the most recent motion event that targets the same
   1446       // window with unchanged state.
   1447       XEvent last_event;
   1448       while (XPending(xev->xany.display)) {
   1449         XEvent next_event;
   1450         XPeekEvent(xev->xany.display, &next_event);
   1451         if (next_event.type == MotionNotify &&
   1452             next_event.xmotion.window == xev->xmotion.window &&
   1453             next_event.xmotion.subwindow == xev->xmotion.subwindow &&
   1454             next_event.xmotion.state == xev->xmotion.state) {
   1455           XNextEvent(xev->xany.display, &last_event);
   1456           xev = &last_event;
   1457         } else {
   1458           break;
   1459         }
   1460       }
   1461 
   1462       ui::MouseEvent mouseev(xev);
   1463       DispatchMouseEvent(&mouseev);
   1464       break;
   1465     }
   1466     case PropertyNotify: {
   1467       // Get our new window property state if the WM has told us its changed.
   1468       ::Atom state = atom_cache_.GetAtom("_NET_WM_STATE");
   1469 
   1470       std::vector< ::Atom> atom_list;
   1471       if (xev->xproperty.atom == state &&
   1472           ui::GetAtomArrayProperty(xwindow_, "_NET_WM_STATE", &atom_list)) {
   1473         window_properties_.clear();
   1474         std::copy(atom_list.begin(), atom_list.end(),
   1475                   inserter(window_properties_, window_properties_.begin()));
   1476 
   1477         if (!restored_bounds_.IsEmpty() && !IsMaximized()) {
   1478           // If we have restored bounds, but WM_STATE no longer claims to be
   1479           // maximized, we should clear our restored bounds.
   1480           restored_bounds_ = gfx::Rect();
   1481         } else if (IsMaximized() && restored_bounds_.IsEmpty()) {
   1482           // The request that we become maximized originated from a different
   1483           // process. |bounds_| already contains our maximized bounds. Do a
   1484           // best effort attempt to get restored bounds by setting it to our
   1485           // previously set bounds (and if we get this wrong, we aren't any
   1486           // worse off since we'd otherwise be returning our maximized bounds).
   1487           restored_bounds_ = previous_bounds_;
   1488         }
   1489 
   1490         is_fullscreen_ = HasWMSpecProperty("_NET_WM_STATE_FULLSCREEN");
   1491         is_always_on_top_ = HasWMSpecProperty("_NET_WM_STATE_ABOVE");
   1492 
   1493         // Now that we have different window properties, we may need to
   1494         // relayout the window. (The windows code doesn't need this because
   1495         // their window change is synchronous.)
   1496         //
   1497         // TODO(erg): While this does work, there's a quick flash showing the
   1498         // tabstrip/toolbar/etc. when going into fullscreen mode before hiding
   1499         // those parts of the UI because we receive the sizing event from the
   1500         // window manager before we receive the event that changes the
   1501         // fullscreen state. Unsure what to do about that.
   1502         Widget* widget = native_widget_delegate_->AsWidget();
   1503         NonClientView* non_client_view = widget->non_client_view();
   1504         // non_client_view may be NULL, especially during creation.
   1505         if (non_client_view) {
   1506           non_client_view->client_view()->InvalidateLayout();
   1507           non_client_view->InvalidateLayout();
   1508         }
   1509         widget->GetRootView()->Layout();
   1510       }
   1511       break;
   1512     }
   1513     case SelectionNotify: {
   1514       drag_drop_client_->OnSelectionNotify(xev->xselection);
   1515       break;
   1516     }
   1517   }
   1518   return true;
   1519 }
   1520 
   1521 ////////////////////////////////////////////////////////////////////////////////
   1522 // DesktopRootWindowHost, public:
   1523 
   1524 // static
   1525 DesktopRootWindowHost* DesktopRootWindowHost::Create(
   1526     internal::NativeWidgetDelegate* native_widget_delegate,
   1527     DesktopNativeWidgetAura* desktop_native_widget_aura) {
   1528   return new DesktopRootWindowHostX11(native_widget_delegate,
   1529                                       desktop_native_widget_aura);
   1530 }
   1531 
   1532 // static
   1533 ui::NativeTheme* DesktopRootWindowHost::GetNativeTheme(aura::Window* window) {
   1534   const views::LinuxUI* linux_ui = views::LinuxUI::instance();
   1535   if (linux_ui) {
   1536     ui::NativeTheme* native_theme = linux_ui->GetNativeTheme();
   1537     if (native_theme)
   1538       return native_theme;
   1539   }
   1540 
   1541   return ui::NativeTheme::instance();
   1542 }
   1543 
   1544 }  // namespace views
   1545