Home | History | Annotate | Download | only in 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/aura/root_window_host_x11.h"
      6 
      7 #include <strings.h>
      8 #include <X11/cursorfont.h>
      9 #include <X11/extensions/Xfixes.h>
     10 #include <X11/extensions/XInput2.h>
     11 #include <X11/extensions/Xrandr.h>
     12 #include <X11/Xatom.h>
     13 #include <X11/Xcursor/Xcursor.h>
     14 #include <X11/Xlib.h>
     15 
     16 #include <algorithm>
     17 #include <limits>
     18 #include <string>
     19 
     20 #include "base/basictypes.h"
     21 #include "base/command_line.h"
     22 #include "base/debug/trace_event.h"
     23 #include "base/message_loop/message_loop.h"
     24 #include "base/message_loop/message_pump_x11.h"
     25 #include "base/stl_util.h"
     26 #include "base/strings/string_number_conversions.h"
     27 #include "base/strings/string_util.h"
     28 #include "base/strings/stringprintf.h"
     29 #include "base/sys_info.h"
     30 #include "ui/aura/client/cursor_client.h"
     31 #include "ui/aura/client/screen_position_client.h"
     32 #include "ui/aura/client/user_action_client.h"
     33 #include "ui/aura/env.h"
     34 #include "ui/aura/root_window.h"
     35 #include "ui/base/cursor/cursor.h"
     36 #include "ui/base/ui_base_switches.h"
     37 #include "ui/base/view_prop.h"
     38 #include "ui/base/x/x11_util.h"
     39 #include "ui/compositor/dip_util.h"
     40 #include "ui/compositor/layer.h"
     41 #include "ui/events/event.h"
     42 #include "ui/events/event_utils.h"
     43 #include "ui/events/keycodes/keyboard_codes.h"
     44 #include "ui/events/x/device_data_manager.h"
     45 #include "ui/events/x/device_list_cache_x.h"
     46 #include "ui/events/x/touch_factory_x11.h"
     47 #include "ui/gfx/screen.h"
     48 
     49 using std::max;
     50 using std::min;
     51 
     52 namespace aura {
     53 
     54 namespace {
     55 
     56 // Standard Linux mouse buttons for going back and forward.
     57 const int kBackMouseButton = 8;
     58 const int kForwardMouseButton = 9;
     59 
     60 const char* kAtomsToCache[] = {
     61   "WM_DELETE_WINDOW",
     62   "_NET_WM_PING",
     63   "_NET_WM_PID",
     64   "WM_S0",
     65 #if defined(OS_CHROMEOS)
     66   "Tap Paused",  // Defined in the gestures library.
     67 #endif
     68   NULL
     69 };
     70 
     71 ::Window FindEventTarget(const base::NativeEvent& xev) {
     72   ::Window target = xev->xany.window;
     73   if (xev->type == GenericEvent)
     74     target = static_cast<XIDeviceEvent*>(xev->xcookie.data)->event;
     75   return target;
     76 }
     77 
     78 #if defined(USE_XI2_MT)
     79 bool IsSideBezelsEnabled() {
     80   static bool side_bezels_enabled =
     81       CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
     82           switches::kTouchSideBezels) != "0";
     83   return side_bezels_enabled;
     84 }
     85 #endif
     86 
     87 void SelectXInput2EventsForRootWindow(XDisplay* display, ::Window root_window) {
     88   CHECK(ui::IsXInput2Available());
     89   unsigned char mask[XIMaskLen(XI_LASTEVENT)] = {};
     90   memset(mask, 0, sizeof(mask));
     91 
     92   XISetMask(mask, XI_HierarchyChanged);
     93   XISetMask(mask, XI_KeyPress);
     94   XISetMask(mask, XI_KeyRelease);
     95 
     96   XIEventMask evmask;
     97   evmask.deviceid = XIAllDevices;
     98   evmask.mask_len = sizeof(mask);
     99   evmask.mask = mask;
    100   XISelectEvents(display, root_window, &evmask, 1);
    101 
    102 #if defined(OS_CHROMEOS)
    103   if (base::SysInfo::IsRunningOnChromeOS()) {
    104     // It is necessary to listen for touch events on the root window for proper
    105     // touch event calibration on Chrome OS, but this is not currently necessary
    106     // on the desktop. This seems to fail in some cases (e.g. when logging
    107     // in incognito). So select for non-touch events first, and then select for
    108     // touch-events (but keep the other events in the mask, i.e. do not memset
    109     // |mask| back to 0).
    110     // TODO(sad): Figure out why this happens. http://crbug.com/153976
    111     XISetMask(mask, XI_TouchBegin);
    112     XISetMask(mask, XI_TouchUpdate);
    113     XISetMask(mask, XI_TouchEnd);
    114     XISelectEvents(display, root_window, &evmask, 1);
    115   }
    116 #endif
    117 }
    118 
    119 bool default_override_redirect = false;
    120 
    121 }  // namespace
    122 
    123 namespace internal {
    124 
    125 // Accomplishes 2 tasks concerning touch event calibration:
    126 // 1. Being a message-pump observer,
    127 //    routes all the touch events to the X root window,
    128 //    where they can be calibrated later.
    129 // 2. Has the Calibrate method that does the actual bezel calibration,
    130 //    when invoked from X root window's event dispatcher.
    131 class TouchEventCalibrate : public base::MessagePumpObserver {
    132  public:
    133   TouchEventCalibrate()
    134     : left_(0),
    135       right_(0),
    136       top_(0),
    137       bottom_(0) {
    138     base::MessageLoopForUI::current()->AddObserver(this);
    139 #if defined(USE_XI2_MT)
    140     std::vector<std::string> parts;
    141     if (Tokenize(CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
    142         switches::kTouchCalibration), ",", &parts) >= 4) {
    143       if (!base::StringToInt(parts[0], &left_))
    144         DLOG(ERROR) << "Incorrect left border calibration value passed.";
    145       if (!base::StringToInt(parts[1], &right_))
    146         DLOG(ERROR) << "Incorrect right border calibration value passed.";
    147       if (!base::StringToInt(parts[2], &top_))
    148         DLOG(ERROR) << "Incorrect top border calibration value passed.";
    149       if (!base::StringToInt(parts[3], &bottom_))
    150         DLOG(ERROR) << "Incorrect bottom border calibration value passed.";
    151     }
    152 #endif  // defined(USE_XI2_MT)
    153   }
    154 
    155   virtual ~TouchEventCalibrate() {
    156     base::MessageLoopForUI::current()->RemoveObserver(this);
    157   }
    158 
    159 #if defined(USE_XI2_MT)
    160   bool IsEventOnSideBezels(
    161       const base::NativeEvent& xev,
    162       const gfx::Rect& bounds) {
    163     if (!left_ && !right_)
    164       return false;
    165 
    166     gfx::Point location = ui::EventLocationFromNative(xev);
    167     int x = location.x();
    168     return x < left_ || x > bounds.width() - right_;
    169   }
    170 #endif  // defined(USE_XI2_MT)
    171 
    172   // Modify the location of the |event|,
    173   // expanding it from |bounds| to (|bounds| + bezels).
    174   // Required when touchscreen is bigger than screen (i.e. has bezels),
    175   // because we receive events in touchscreen coordinates,
    176   // which need to be expanded when converting to screen coordinates,
    177   // so that location on bezels will be outside of screen area.
    178   void Calibrate(ui::TouchEvent* event, const gfx::Rect& bounds) {
    179 #if defined(USE_XI2_MT)
    180     int x = event->x();
    181     int y = event->y();
    182 
    183     if (!left_ && !right_ && !top_ && !bottom_)
    184       return;
    185 
    186     const int resolution_x = bounds.width();
    187     const int resolution_y = bounds.height();
    188     // The "grace area" (10% in this case) is to make it easier for the user to
    189     // navigate to the corner.
    190     const double kGraceAreaFraction = 0.1;
    191     if (left_ || right_) {
    192       // Offset the x position to the real
    193       x -= left_;
    194       // Check if we are in the grace area of the left side.
    195       // Note: We might not want to do this when the gesture is locked?
    196       if (x < 0 && x > -left_ * kGraceAreaFraction)
    197         x = 0;
    198       // Check if we are in the grace area of the right side.
    199       // Note: We might not want to do this when the gesture is locked?
    200       if (x > resolution_x - left_ &&
    201           x < resolution_x - left_ + right_ * kGraceAreaFraction)
    202         x = resolution_x - left_;
    203       // Scale the screen area back to the full resolution of the screen.
    204       x = (x * resolution_x) / (resolution_x - (right_ + left_));
    205     }
    206     if (top_ || bottom_) {
    207       // When there is a top bezel we add our border,
    208       y -= top_;
    209 
    210       // Check if we are in the grace area of the top side.
    211       // Note: We might not want to do this when the gesture is locked?
    212       if (y < 0 && y > -top_ * kGraceAreaFraction)
    213         y = 0;
    214 
    215       // Check if we are in the grace area of the bottom side.
    216       // Note: We might not want to do this when the gesture is locked?
    217       if (y > resolution_y - top_ &&
    218           y < resolution_y - top_ + bottom_ * kGraceAreaFraction)
    219         y = resolution_y - top_;
    220       // Scale the screen area back to the full resolution of the screen.
    221       y = (y * resolution_y) / (resolution_y - (bottom_ + top_));
    222     }
    223 
    224     // Set the modified coordinate back to the event.
    225     if (event->root_location() == event->location()) {
    226       // Usually those will be equal,
    227       // if not, I am not sure what the correct value should be.
    228       event->set_root_location(gfx::Point(x, y));
    229     }
    230     event->set_location(gfx::Point(x, y));
    231 #endif  // defined(USE_XI2_MT)
    232   }
    233 
    234  private:
    235   // Overridden from base::MessagePumpObserver:
    236   virtual base::EventStatus WillProcessEvent(
    237       const base::NativeEvent& event) OVERRIDE {
    238 #if defined(USE_XI2_MT)
    239     if (event->type == GenericEvent &&
    240         (event->xgeneric.evtype == XI_TouchBegin ||
    241          event->xgeneric.evtype == XI_TouchUpdate ||
    242          event->xgeneric.evtype == XI_TouchEnd)) {
    243       XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event->xcookie.data);
    244       xievent->event = xievent->root;
    245       xievent->event_x = xievent->root_x;
    246       xievent->event_y = xievent->root_y;
    247     }
    248 #endif  // defined(USE_XI2_MT)
    249     return base::EVENT_CONTINUE;
    250   }
    251 
    252   virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
    253   }
    254 
    255   // The difference in screen's native resolution pixels between
    256   // the border of the touchscreen and the border of the screen,
    257   // aka bezel sizes.
    258   int left_;
    259   int right_;
    260   int top_;
    261   int bottom_;
    262 
    263   DISALLOW_COPY_AND_ASSIGN(TouchEventCalibrate);
    264 };
    265 
    266 }  // namespace internal
    267 
    268 ////////////////////////////////////////////////////////////////////////////////
    269 // RootWindowHostX11::MouseMoveFilter filters out the move events that
    270 // jump back and forth between two points. This happens when sub pixel mouse
    271 // move is enabled and mouse move events could be jumping between two neighbor
    272 // pixels, e.g. move(0,0), move(1,0), move(0,0), move(1,0) and on and on.
    273 // The filtering is done by keeping track of the last two event locations and
    274 // provides a Filter method to find out whether a mouse event is in a different
    275 // location and should be processed.
    276 
    277 class RootWindowHostX11::MouseMoveFilter {
    278  public:
    279   MouseMoveFilter() : insert_index_(0) {
    280     for (size_t i = 0; i < kMaxEvents; ++i) {
    281       const int int_max = std::numeric_limits<int>::max();
    282       recent_locations_[i] = gfx::Point(int_max, int_max);
    283     }
    284   }
    285   ~MouseMoveFilter() {}
    286 
    287   // Returns true if |event| is known and should be ignored.
    288   bool Filter(const base::NativeEvent& event) {
    289     const gfx::Point& location = ui::EventLocationFromNative(event);
    290     for (size_t i = 0; i < kMaxEvents; ++i) {
    291       if (location == recent_locations_[i])
    292         return true;
    293     }
    294 
    295     recent_locations_[insert_index_] = location;
    296     insert_index_ = (insert_index_ + 1) % kMaxEvents;
    297     return false;
    298   }
    299 
    300  private:
    301   static const size_t kMaxEvents = 2;
    302 
    303   gfx::Point recent_locations_[kMaxEvents];
    304   size_t insert_index_;
    305 
    306   DISALLOW_COPY_AND_ASSIGN(MouseMoveFilter);
    307 };
    308 
    309 ////////////////////////////////////////////////////////////////////////////////
    310 // RootWindowHostX11
    311 
    312 RootWindowHostX11::RootWindowHostX11(const gfx::Rect& bounds)
    313     : xdisplay_(gfx::GetXDisplay()),
    314       xwindow_(0),
    315       x_root_window_(DefaultRootWindow(xdisplay_)),
    316       current_cursor_(ui::kCursorNull),
    317       window_mapped_(false),
    318       bounds_(bounds),
    319       is_internal_display_(false),
    320       touch_calibrate_(new internal::TouchEventCalibrate),
    321       mouse_move_filter_(new MouseMoveFilter),
    322       atom_cache_(xdisplay_, kAtomsToCache),
    323       bezel_tracking_ids_(0) {
    324   XSetWindowAttributes swa;
    325   memset(&swa, 0, sizeof(swa));
    326   swa.background_pixmap = None;
    327   swa.override_redirect = default_override_redirect;
    328   xwindow_ = XCreateWindow(
    329       xdisplay_, x_root_window_,
    330       bounds.x(), bounds.y(), bounds.width(), bounds.height(),
    331       0,               // border width
    332       CopyFromParent,  // depth
    333       InputOutput,
    334       CopyFromParent,  // visual
    335       CWBackPixmap | CWOverrideRedirect,
    336       &swa);
    337   base::MessagePumpX11::Current()->AddDispatcherForWindow(this, xwindow_);
    338   base::MessagePumpX11::Current()->AddDispatcherForRootWindow(this);
    339 
    340   long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask |
    341                     KeyPressMask | KeyReleaseMask |
    342                     EnterWindowMask | LeaveWindowMask |
    343                     ExposureMask | VisibilityChangeMask |
    344                     StructureNotifyMask | PropertyChangeMask |
    345                     PointerMotionMask;
    346   XSelectInput(xdisplay_, xwindow_, event_mask);
    347   XFlush(xdisplay_);
    348 
    349   if (ui::IsXInput2Available()) {
    350     ui::TouchFactory::GetInstance()->SetupXI2ForXWindow(xwindow_);
    351     SelectXInput2EventsForRootWindow(xdisplay_, x_root_window_);
    352   }
    353 
    354   // TODO(erg): We currently only request window deletion events. We also
    355   // should listen for activation events and anything else that GTK+ listens
    356   // for, and do something useful.
    357   ::Atom protocols[2];
    358   protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW");
    359   protocols[1] = atom_cache_.GetAtom("_NET_WM_PING");
    360   XSetWMProtocols(xdisplay_, xwindow_, protocols, 2);
    361 
    362   // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with
    363   // the desktop environment.
    364   XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL);
    365 
    366   // Likewise, the X server needs to know this window's pid so it knows which
    367   // program to kill if the window hangs.
    368   // XChangeProperty() expects "pid" to be long.
    369   COMPILE_ASSERT(sizeof(long) >= sizeof(pid_t), pid_t_bigger_than_long);
    370   long pid = getpid();
    371   XChangeProperty(xdisplay_,
    372                   xwindow_,
    373                   atom_cache_.GetAtom("_NET_WM_PID"),
    374                   XA_CARDINAL,
    375                   32,
    376                   PropModeReplace,
    377                   reinterpret_cast<unsigned char*>(&pid), 1);
    378 
    379   XRRSelectInput(xdisplay_, x_root_window_,
    380                  RRScreenChangeNotifyMask | RROutputChangeNotifyMask);
    381   Env::GetInstance()->AddObserver(this);
    382 }
    383 
    384 RootWindowHostX11::~RootWindowHostX11() {
    385   Env::GetInstance()->RemoveObserver(this);
    386   base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this);
    387   base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_);
    388 
    389   UnConfineCursor();
    390 
    391   XDestroyWindow(xdisplay_, xwindow_);
    392 }
    393 
    394 bool RootWindowHostX11::Dispatch(const base::NativeEvent& event) {
    395   XEvent* xev = event;
    396 
    397   if (FindEventTarget(event) == x_root_window_)
    398     return DispatchEventForRootWindow(event);
    399 
    400   switch (xev->type) {
    401     case EnterNotify: {
    402       aura::Window* root_window = GetRootWindow()->window();
    403       client::CursorClient* cursor_client =
    404           client::GetCursorClient(root_window);
    405       if (cursor_client) {
    406         const gfx::Display display = gfx::Screen::GetScreenFor(root_window)->
    407             GetDisplayNearestWindow(root_window);
    408         cursor_client->SetDisplay(display);
    409       }
    410       ui::MouseEvent mouse_event(xev);
    411       // EnterNotify creates ET_MOUSE_MOVE. Mark as synthesized as this is not
    412       // real mouse move event.
    413       mouse_event.set_flags(mouse_event.flags() | ui::EF_IS_SYNTHESIZED);
    414       TranslateAndDispatchMouseEvent(&mouse_event);
    415       break;
    416     }
    417     case LeaveNotify: {
    418       ui::MouseEvent mouse_event(xev);
    419       TranslateAndDispatchMouseEvent(&mouse_event);
    420       break;
    421     }
    422     case Expose: {
    423       gfx::Rect damage_rect(xev->xexpose.x, xev->xexpose.y,
    424                             xev->xexpose.width, xev->xexpose.height);
    425       delegate_->AsRootWindow()->ScheduleRedrawRect(damage_rect);
    426       break;
    427     }
    428     case KeyPress: {
    429       ui::KeyEvent keydown_event(xev, false);
    430       delegate_->OnHostKeyEvent(&keydown_event);
    431       break;
    432     }
    433     case KeyRelease: {
    434       ui::KeyEvent keyup_event(xev, false);
    435       delegate_->OnHostKeyEvent(&keyup_event);
    436       break;
    437     }
    438     case ButtonPress: {
    439       if (static_cast<int>(xev->xbutton.button) == kBackMouseButton ||
    440           static_cast<int>(xev->xbutton.button) == kForwardMouseButton) {
    441         client::UserActionClient* gesture_client =
    442             client::GetUserActionClient(delegate_->AsRootWindow()->window());
    443         if (gesture_client) {
    444           gesture_client->OnUserAction(
    445               static_cast<int>(xev->xbutton.button) == kBackMouseButton ?
    446               client::UserActionClient::BACK :
    447               client::UserActionClient::FORWARD);
    448         }
    449         break;
    450       }
    451     }  // fallthrough
    452     case ButtonRelease: {
    453       switch (ui::EventTypeFromNative(xev)) {
    454         case ui::ET_MOUSEWHEEL: {
    455           ui::MouseWheelEvent mouseev(xev);
    456           TranslateAndDispatchMouseEvent(&mouseev);
    457           break;
    458         }
    459         case ui::ET_MOUSE_PRESSED:
    460         case ui::ET_MOUSE_RELEASED: {
    461           ui::MouseEvent mouseev(xev);
    462           TranslateAndDispatchMouseEvent(&mouseev);
    463           break;
    464         }
    465         case ui::ET_UNKNOWN:
    466           // No event is created for X11-release events for mouse-wheel buttons.
    467           break;
    468         default:
    469           NOTREACHED();
    470       }
    471       break;
    472     }
    473     case FocusOut:
    474       if (xev->xfocus.mode != NotifyGrab)
    475         delegate_->OnHostLostWindowCapture();
    476       break;
    477     case ConfigureNotify: {
    478       DCHECK_EQ(xwindow_, xev->xconfigure.event);
    479       DCHECK_EQ(xwindow_, xev->xconfigure.window);
    480       // It's possible that the X window may be resized by some other means
    481       // than from within aura (e.g. the X window manager can change the
    482       // size). Make sure the root window size is maintained properly.
    483       gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y,
    484           xev->xconfigure.width, xev->xconfigure.height);
    485       bool size_changed = bounds_.size() != bounds.size();
    486       bool origin_changed = bounds_.origin() != bounds.origin();
    487       bounds_ = bounds;
    488       UpdateIsInternalDisplay();
    489       // Always update barrier and mouse location because |bounds_| might
    490       // have already been updated in |SetBounds|.
    491       if (pointer_barriers_) {
    492         UnConfineCursor();
    493         ConfineCursorToRootWindow();
    494       }
    495       if (size_changed)
    496         delegate_->OnHostResized(bounds.size());
    497       if (origin_changed)
    498         delegate_->OnHostMoved(bounds_.origin());
    499       break;
    500     }
    501     case GenericEvent:
    502       DispatchXI2Event(event);
    503       break;
    504     case ClientMessage: {
    505       Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]);
    506       if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) {
    507         // We have received a close message from the window manager.
    508         delegate_->AsRootWindow()->OnRootWindowHostCloseRequested();
    509       } else if (message_type == atom_cache_.GetAtom("_NET_WM_PING")) {
    510         XEvent reply_event = *xev;
    511         reply_event.xclient.window = x_root_window_;
    512 
    513         XSendEvent(xdisplay_,
    514                    reply_event.xclient.window,
    515                    False,
    516                    SubstructureRedirectMask | SubstructureNotifyMask,
    517                    &reply_event);
    518       }
    519       break;
    520     }
    521     case MappingNotify: {
    522       switch (xev->xmapping.request) {
    523         case MappingModifier:
    524         case MappingKeyboard:
    525           XRefreshKeyboardMapping(&xev->xmapping);
    526           delegate_->AsRootWindow()->OnKeyboardMappingChanged();
    527           break;
    528         case MappingPointer:
    529           ui::DeviceDataManager::GetInstance()->UpdateButtonMap();
    530           break;
    531         default:
    532           NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request;
    533           break;
    534       }
    535       break;
    536     }
    537     case MotionNotify: {
    538       // Discard all but the most recent motion event that targets the same
    539       // window with unchanged state.
    540       XEvent last_event;
    541       while (XPending(xev->xany.display)) {
    542         XEvent next_event;
    543         XPeekEvent(xev->xany.display, &next_event);
    544         if (next_event.type == MotionNotify &&
    545             next_event.xmotion.window == xev->xmotion.window &&
    546             next_event.xmotion.subwindow == xev->xmotion.subwindow &&
    547             next_event.xmotion.state == xev->xmotion.state) {
    548           XNextEvent(xev->xany.display, &last_event);
    549           xev = &last_event;
    550         } else {
    551           break;
    552         }
    553       }
    554 
    555       ui::MouseEvent mouseev(xev);
    556       TranslateAndDispatchMouseEvent(&mouseev);
    557       break;
    558     }
    559   }
    560   return true;
    561 }
    562 
    563 RootWindow* RootWindowHostX11::GetRootWindow() {
    564   return delegate_->AsRootWindow();
    565 }
    566 
    567 gfx::AcceleratedWidget RootWindowHostX11::GetAcceleratedWidget() {
    568   return xwindow_;
    569 }
    570 
    571 void RootWindowHostX11::Show() {
    572   if (!window_mapped_) {
    573     // Before we map the window, set size hints. Otherwise, some window managers
    574     // will ignore toplevel XMoveWindow commands.
    575     XSizeHints size_hints;
    576     size_hints.flags = PPosition | PWinGravity;
    577     size_hints.x = bounds_.x();
    578     size_hints.y = bounds_.y();
    579     // Set StaticGravity so that the window position is not affected by the
    580     // frame width when running with window manager.
    581     size_hints.win_gravity = StaticGravity;
    582     XSetWMNormalHints(xdisplay_, xwindow_, &size_hints);
    583 
    584     XMapWindow(xdisplay_, xwindow_);
    585 
    586     // We now block until our window is mapped. Some X11 APIs will crash and
    587     // burn if passed |xwindow_| before the window is mapped, and XMapWindow is
    588     // asynchronous.
    589     base::MessagePumpX11::Current()->BlockUntilWindowMapped(xwindow_);
    590     window_mapped_ = true;
    591   }
    592 }
    593 
    594 void RootWindowHostX11::Hide() {
    595   if (window_mapped_) {
    596     XWithdrawWindow(xdisplay_, xwindow_, 0);
    597     window_mapped_ = false;
    598   }
    599 }
    600 
    601 void RootWindowHostX11::ToggleFullScreen() {
    602   NOTIMPLEMENTED();
    603 }
    604 
    605 gfx::Rect RootWindowHostX11::GetBounds() const {
    606   return bounds_;
    607 }
    608 
    609 void RootWindowHostX11::SetBounds(const gfx::Rect& bounds) {
    610   // Even if the host window's size doesn't change, aura's root window
    611   // size, which is in DIP, changes when the scale changes.
    612   float current_scale = delegate_->GetDeviceScaleFactor();
    613   float new_scale = gfx::Screen::GetScreenFor(
    614       delegate_->AsRootWindow()->window())->GetDisplayNearestWindow(
    615           delegate_->AsRootWindow()->window()).device_scale_factor();
    616   bool origin_changed = bounds_.origin() != bounds.origin();
    617   bool size_changed = bounds_.size() != bounds.size();
    618   XWindowChanges changes = {0};
    619   unsigned value_mask = 0;
    620 
    621   if (size_changed) {
    622     changes.width = bounds.width();
    623     changes.height = bounds.height();
    624     value_mask = CWHeight | CWWidth;
    625   }
    626 
    627   if (origin_changed) {
    628     changes.x = bounds.x();
    629     changes.y = bounds.y();
    630     value_mask |= CWX | CWY;
    631   }
    632   if (value_mask)
    633     XConfigureWindow(xdisplay_, xwindow_, value_mask, &changes);
    634 
    635   // Assume that the resize will go through as requested, which should be the
    636   // case if we're running without a window manager.  If there's a window
    637   // manager, it can modify or ignore the request, but (per ICCCM) we'll get a
    638   // (possibly synthetic) ConfigureNotify about the actual size and correct
    639   // |bounds_| later.
    640   bounds_ = bounds;
    641   UpdateIsInternalDisplay();
    642   if (origin_changed)
    643     delegate_->OnHostMoved(bounds.origin());
    644   if (size_changed || current_scale != new_scale) {
    645     delegate_->OnHostResized(bounds.size());
    646   } else {
    647     delegate_->AsRootWindow()->window()->SchedulePaintInRect(
    648         delegate_->AsRootWindow()->window()->bounds());
    649   }
    650 }
    651 
    652 gfx::Insets RootWindowHostX11::GetInsets() const {
    653   return insets_;
    654 }
    655 
    656 void RootWindowHostX11::SetInsets(const gfx::Insets& insets) {
    657   insets_ = insets;
    658   if (pointer_barriers_) {
    659     UnConfineCursor();
    660     ConfineCursorToRootWindow();
    661   }
    662 }
    663 
    664 gfx::Point RootWindowHostX11::GetLocationOnNativeScreen() const {
    665   return bounds_.origin();
    666 }
    667 
    668 void RootWindowHostX11::SetCapture() {
    669   // TODO(oshima): Grab x input.
    670 }
    671 
    672 void RootWindowHostX11::ReleaseCapture() {
    673   // TODO(oshima): Release x input.
    674 }
    675 
    676 void RootWindowHostX11::SetCursor(gfx::NativeCursor cursor) {
    677   if (cursor == current_cursor_)
    678     return;
    679   current_cursor_ = cursor;
    680   SetCursorInternal(cursor);
    681 }
    682 
    683 bool RootWindowHostX11::QueryMouseLocation(gfx::Point* location_return) {
    684   client::CursorClient* cursor_client =
    685       client::GetCursorClient(GetRootWindow()->window());
    686   if (cursor_client && !cursor_client->IsMouseEventsEnabled()) {
    687     *location_return = gfx::Point(0, 0);
    688     return false;
    689   }
    690 
    691   ::Window root_return, child_return;
    692   int root_x_return, root_y_return, win_x_return, win_y_return;
    693   unsigned int mask_return;
    694   XQueryPointer(xdisplay_,
    695                 xwindow_,
    696                 &root_return,
    697                 &child_return,
    698                 &root_x_return, &root_y_return,
    699                 &win_x_return, &win_y_return,
    700                 &mask_return);
    701   *location_return = gfx::Point(max(0, min(bounds_.width(), win_x_return)),
    702                                 max(0, min(bounds_.height(), win_y_return)));
    703   return (win_x_return >= 0 && win_x_return < bounds_.width() &&
    704           win_y_return >= 0 && win_y_return < bounds_.height());
    705 }
    706 
    707 bool RootWindowHostX11::ConfineCursorToRootWindow() {
    708 #if XFIXES_MAJOR >= 5
    709   DCHECK(!pointer_barriers_.get());
    710   if (pointer_barriers_)
    711     return false;
    712   pointer_barriers_.reset(new XID[4]);
    713   gfx::Rect bounds(bounds_);
    714   bounds.Inset(insets_);
    715   // Horizontal, top barriers.
    716   pointer_barriers_[0] = XFixesCreatePointerBarrier(
    717       xdisplay_, x_root_window_,
    718       bounds.x(), bounds.y(), bounds.right(), bounds.y(),
    719       BarrierPositiveY,
    720       0, XIAllDevices);
    721   // Horizontal, bottom barriers.
    722   pointer_barriers_[1] = XFixesCreatePointerBarrier(
    723       xdisplay_, x_root_window_,
    724       bounds.x(), bounds.bottom(), bounds.right(),  bounds.bottom(),
    725       BarrierNegativeY,
    726       0, XIAllDevices);
    727   // Vertical, left  barriers.
    728   pointer_barriers_[2] = XFixesCreatePointerBarrier(
    729       xdisplay_, x_root_window_,
    730       bounds.x(), bounds.y(), bounds.x(), bounds.bottom(),
    731       BarrierPositiveX,
    732       0, XIAllDevices);
    733   // Vertical, right barriers.
    734   pointer_barriers_[3] = XFixesCreatePointerBarrier(
    735       xdisplay_, x_root_window_,
    736       bounds.right(), bounds.y(), bounds.right(), bounds.bottom(),
    737       BarrierNegativeX,
    738       0, XIAllDevices);
    739 #endif
    740   return true;
    741 }
    742 
    743 void RootWindowHostX11::UnConfineCursor() {
    744 #if XFIXES_MAJOR >= 5
    745   if (pointer_barriers_) {
    746     XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[0]);
    747     XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[1]);
    748     XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[2]);
    749     XFixesDestroyPointerBarrier(xdisplay_, pointer_barriers_[3]);
    750     pointer_barriers_.reset();
    751   }
    752 #endif
    753 }
    754 
    755 void RootWindowHostX11::OnCursorVisibilityChanged(bool show) {
    756   SetCrOSTapPaused(!show);
    757 }
    758 
    759 void RootWindowHostX11::MoveCursorTo(const gfx::Point& location) {
    760   XWarpPointer(xdisplay_, None, x_root_window_, 0, 0, 0, 0,
    761                bounds_.x() + location.x(),
    762                bounds_.y() + location.y());
    763 }
    764 
    765 void RootWindowHostX11::PostNativeEvent(
    766     const base::NativeEvent& native_event) {
    767   DCHECK(xwindow_);
    768   DCHECK(xdisplay_);
    769   XEvent xevent = *native_event;
    770   xevent.xany.display = xdisplay_;
    771   xevent.xany.window = xwindow_;
    772 
    773   switch (xevent.type) {
    774     case EnterNotify:
    775     case LeaveNotify:
    776     case MotionNotify:
    777     case KeyPress:
    778     case KeyRelease:
    779     case ButtonPress:
    780     case ButtonRelease: {
    781       // The fields used below are in the same place for all of events
    782       // above. Using xmotion from XEvent's unions to avoid repeating
    783       // the code.
    784       xevent.xmotion.root = x_root_window_;
    785       xevent.xmotion.time = CurrentTime;
    786 
    787       gfx::Point point(xevent.xmotion.x, xevent.xmotion.y);
    788       delegate_->AsRootWindow()->host()->ConvertPointToNativeScreen(&point);
    789       xevent.xmotion.x_root = point.x();
    790       xevent.xmotion.y_root = point.y();
    791     }
    792     default:
    793       break;
    794   }
    795   XSendEvent(xdisplay_, xwindow_, False, 0, &xevent);
    796 }
    797 
    798 void RootWindowHostX11::OnDeviceScaleFactorChanged(
    799     float device_scale_factor) {
    800 }
    801 
    802 void RootWindowHostX11::PrepareForShutdown() {
    803   base::MessagePumpX11::Current()->RemoveDispatcherForWindow(xwindow_);
    804 }
    805 
    806 void RootWindowHostX11::OnWindowInitialized(Window* window) {
    807 }
    808 
    809 void RootWindowHostX11::OnRootWindowInitialized(RootWindow* root_window) {
    810   // UpdateIsInternalDisplay relies on:
    811   // 1. delegate_ pointing to RootWindow - available after SetDelegate.
    812   // 2. RootWindow's kDisplayIdKey property set - available by the time
    813   //    RootWindow::Init is called.
    814   //    (set in DisplayManager::CreateRootWindowForDisplay)
    815   // Ready when NotifyRootWindowInitialized is called from RootWindow::Init.
    816   if (!delegate_ || root_window != GetRootWindow())
    817     return;
    818   UpdateIsInternalDisplay();
    819 
    820   // We have to enable Tap-to-click by default because the cursor is set to
    821   // visible in Shell::InitRootWindowController.
    822   SetCrOSTapPaused(false);
    823 }
    824 
    825 ui::EventProcessor* RootWindowHostX11::GetEventProcessor() {
    826   return delegate_->GetEventProcessor();
    827 }
    828 
    829 bool RootWindowHostX11::DispatchEventForRootWindow(
    830     const base::NativeEvent& event) {
    831   switch (event->type) {
    832     case GenericEvent:
    833       DispatchXI2Event(event);
    834       break;
    835   }
    836 
    837   return true;
    838 }
    839 
    840 void RootWindowHostX11::DispatchXI2Event(const base::NativeEvent& event) {
    841   ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
    842   XEvent* xev = event;
    843   if (!factory->ShouldProcessXI2Event(xev))
    844     return;
    845 
    846   TRACE_EVENT1("input", "RootWindowHostX11::DispatchXI2Event",
    847                "event_latency_us",
    848                (ui::EventTimeForNow() - ui::EventTimeFromNative(event)).
    849                  InMicroseconds());
    850 
    851   ui::EventType type = ui::EventTypeFromNative(xev);
    852   XEvent last_event;
    853   int num_coalesced = 0;
    854 
    855   switch (type) {
    856     case ui::ET_TOUCH_MOVED:
    857     case ui::ET_TOUCH_PRESSED:
    858     case ui::ET_TOUCH_CANCELLED:
    859     case ui::ET_TOUCH_RELEASED: {
    860 #if defined(OS_CHROMEOS)
    861       // Bail out early before generating a ui::TouchEvent if this event
    862       // is not within the range of this RootWindow. Converting an xevent
    863       // to ui::TouchEvent might change the state of the global touch tracking
    864       // state, e.g. touch release event can remove the touch id from the
    865       // record, and doing this multiple time when there are multiple
    866       // RootWindow will cause problem. So only generate the ui::TouchEvent
    867       // when we are sure it belongs to this RootWindow.
    868       if (base::SysInfo::IsRunningOnChromeOS() &&
    869           !bounds_.Contains(ui::EventLocationFromNative(xev)))
    870         break;
    871 #endif  // defined(OS_CHROMEOS)
    872       ui::TouchEvent touchev(xev);
    873 #if defined(USE_XI2_MT)
    874       // Ignore touch events with touch press happening on the side bezel.
    875       if (!IsSideBezelsEnabled()) {
    876         uint32 tracking_id = (1 << touchev.touch_id());
    877         if (type == ui::ET_TOUCH_PRESSED &&
    878             touch_calibrate_->IsEventOnSideBezels(xev, bounds_))
    879           bezel_tracking_ids_ |= tracking_id;
    880         if (bezel_tracking_ids_ & tracking_id) {
    881           if (type == ui::ET_TOUCH_CANCELLED || type == ui::ET_TOUCH_RELEASED)
    882             bezel_tracking_ids_ =
    883                 (bezel_tracking_ids_ | tracking_id) ^ tracking_id;
    884           return;
    885         }
    886       }
    887 #endif  // defined(USE_XI2_MT)
    888 #if defined(OS_CHROMEOS)
    889       if (base::SysInfo::IsRunningOnChromeOS()) {
    890         // X maps the touch-surface to the size of the X root-window.
    891         // In multi-monitor setup, Coordinate Transformation Matrix
    892         // repositions the touch-surface onto part of X root-window
    893         // containing aura root-window corresponding to the touchscreen.
    894         // However, if aura root-window has non-zero origin,
    895         // we need to relocate the event into aura root-window coordinates.
    896         touchev.Relocate(bounds_.origin());
    897 #if defined(USE_XI2_MT)
    898         if (is_internal_display_)
    899           touch_calibrate_->Calibrate(&touchev, bounds_);
    900 #endif  // defined(USE_XI2_MT)
    901       }
    902 #endif  // defined(OS_CHROMEOS)
    903       delegate_->OnHostTouchEvent(&touchev);
    904       break;
    905     }
    906     case ui::ET_MOUSE_MOVED:
    907     case ui::ET_MOUSE_DRAGGED:
    908     case ui::ET_MOUSE_PRESSED:
    909     case ui::ET_MOUSE_RELEASED:
    910     case ui::ET_MOUSE_ENTERED:
    911     case ui::ET_MOUSE_EXITED: {
    912       if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) {
    913         // If this is a motion event, we want to coalesce all pending motion
    914         // events that are at the top of the queue.
    915         num_coalesced = ui::CoalescePendingMotionEvents(xev, &last_event);
    916         if (num_coalesced > 0)
    917           xev = &last_event;
    918 
    919         if (mouse_move_filter_ && mouse_move_filter_->Filter(xev))
    920           break;
    921       } else if (type == ui::ET_MOUSE_PRESSED ||
    922                  type == ui::ET_MOUSE_RELEASED) {
    923         XIDeviceEvent* xievent =
    924             static_cast<XIDeviceEvent*>(xev->xcookie.data);
    925         int button = xievent->detail;
    926         if (button == kBackMouseButton || button == kForwardMouseButton) {
    927           if (type == ui::ET_MOUSE_RELEASED)
    928             break;
    929           client::UserActionClient* gesture_client =
    930               client::GetUserActionClient(delegate_->AsRootWindow()->window());
    931           if (gesture_client) {
    932             bool reverse_direction =
    933                 ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled();
    934             gesture_client->OnUserAction(
    935                 (button == kBackMouseButton && !reverse_direction) ||
    936                 (button == kForwardMouseButton && reverse_direction) ?
    937                 client::UserActionClient::BACK :
    938                 client::UserActionClient::FORWARD);
    939           }
    940           break;
    941         }
    942       }
    943       ui::MouseEvent mouseev(xev);
    944       TranslateAndDispatchMouseEvent(&mouseev);
    945       break;
    946     }
    947     case ui::ET_MOUSEWHEEL: {
    948       ui::MouseWheelEvent mouseev(xev);
    949       TranslateAndDispatchMouseEvent(&mouseev);
    950       break;
    951     }
    952     case ui::ET_SCROLL_FLING_START:
    953     case ui::ET_SCROLL_FLING_CANCEL:
    954     case ui::ET_SCROLL: {
    955       ui::ScrollEvent scrollev(xev);
    956       delegate_->OnHostScrollEvent(&scrollev);
    957       break;
    958     }
    959     case ui::ET_UMA_DATA:
    960       break;
    961     case ui::ET_UNKNOWN:
    962       break;
    963     default:
    964       NOTREACHED();
    965   }
    966 
    967   // If we coalesced an event we need to free its cookie.
    968   if (num_coalesced > 0)
    969     XFreeEventData(xev->xgeneric.display, &last_event.xcookie);
    970 }
    971 
    972 bool RootWindowHostX11::IsWindowManagerPresent() {
    973   // Per ICCCM 2.8, "Manager Selections", window managers should take ownership
    974   // of WM_Sn selections (where n is a screen number).
    975   return XGetSelectionOwner(
    976       xdisplay_, atom_cache_.GetAtom("WM_S0")) != None;
    977 }
    978 
    979 void RootWindowHostX11::SetCursorInternal(gfx::NativeCursor cursor) {
    980   XDefineCursor(xdisplay_, xwindow_, cursor.platform());
    981 }
    982 
    983 void RootWindowHostX11::TranslateAndDispatchMouseEvent(
    984     ui::MouseEvent* event) {
    985   Window* root_window = GetRootWindow()->window();
    986   client::ScreenPositionClient* screen_position_client =
    987       client::GetScreenPositionClient(root_window);
    988   gfx::Rect local(bounds_.size());
    989 
    990   if (screen_position_client && !local.Contains(event->location())) {
    991     gfx::Point location(event->location());
    992     // In order to get the correct point in screen coordinates
    993     // during passive grab, we first need to find on which host window
    994     // the mouse is on, and find out the screen coordinates on that
    995     // host window, then convert it back to this host window's coordinate.
    996     screen_position_client->ConvertHostPointToScreen(root_window, &location);
    997     screen_position_client->ConvertPointFromScreen(root_window, &location);
    998     root_window->GetDispatcher()->ConvertPointToHost(&location);
    999     event->set_location(location);
   1000     event->set_root_location(location);
   1001   }
   1002   delegate_->OnHostMouseEvent(event);
   1003 }
   1004 
   1005 void RootWindowHostX11::UpdateIsInternalDisplay() {
   1006   Window* root_window = GetRootWindow()->window();
   1007   gfx::Screen* screen = gfx::Screen::GetScreenFor(root_window);
   1008   gfx::Display display = screen->GetDisplayNearestWindow(root_window);
   1009   is_internal_display_ = display.IsInternal();
   1010 }
   1011 
   1012 void RootWindowHostX11::SetCrOSTapPaused(bool state) {
   1013 #if defined(OS_CHROMEOS)
   1014   if (!ui::IsXInput2Available())
   1015     return;
   1016   // Temporarily pause tap-to-click when the cursor is hidden.
   1017   Atom prop = atom_cache_.GetAtom("Tap Paused");
   1018   unsigned char value = state;
   1019   XIDeviceList dev_list =
   1020       ui::DeviceListCacheX::GetInstance()->GetXI2DeviceList(xdisplay_);
   1021 
   1022   // Only slave pointer devices could possibly have tap-paused property.
   1023   for (int i = 0; i < dev_list.count; i++) {
   1024     if (dev_list[i].use == XISlavePointer) {
   1025       Atom old_type;
   1026       int old_format;
   1027       unsigned long old_nvalues, bytes;
   1028       unsigned char* data;
   1029       int result = XIGetProperty(xdisplay_, dev_list[i].deviceid, prop, 0, 0,
   1030                                  False, AnyPropertyType, &old_type, &old_format,
   1031                                  &old_nvalues, &bytes, &data);
   1032       if (result != Success)
   1033         continue;
   1034       XFree(data);
   1035       XIChangeProperty(xdisplay_, dev_list[i].deviceid, prop, XA_INTEGER, 8,
   1036                        PropModeReplace, &value, 1);
   1037     }
   1038   }
   1039 #endif
   1040 }
   1041 
   1042 // static
   1043 RootWindowHost* RootWindowHost::Create(const gfx::Rect& bounds) {
   1044   return new RootWindowHostX11(bounds);
   1045 }
   1046 
   1047 // static
   1048 gfx::Size RootWindowHost::GetNativeScreenSize() {
   1049   ::XDisplay* xdisplay = gfx::GetXDisplay();
   1050   return gfx::Size(DisplayWidth(xdisplay, 0), DisplayHeight(xdisplay, 0));
   1051 }
   1052 
   1053 namespace test {
   1054 
   1055 void SetUseOverrideRedirectWindowByDefault(bool override_redirect) {
   1056   default_override_redirect = override_redirect;
   1057 }
   1058 
   1059 }  // namespace test
   1060 }  // namespace aura
   1061