| Index: ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc | 
| diff --git a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc | 
| index aeadc78f2fe40a9863c39daa451852a86f78cf9f..127440275591315aeabf0222c06fc93d5b45d0ec 100644 | 
| --- a/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc | 
| +++ b/ui/views/widget/desktop_aura/desktop_window_tree_host_x11.cc | 
| @@ -91,6 +91,7 @@ const char* kAtomsToCache[] = { | 
| "UTF8_STRING", | 
| "WM_DELETE_WINDOW", | 
| "WM_PROTOCOLS", | 
| +  "_NET_ACTIVE_WINDOW", | 
| "_NET_FRAME_EXTENTS", | 
| "_NET_WM_CM_S0", | 
| "_NET_WM_DESKTOP", | 
| @@ -155,6 +156,24 @@ std::vector<::Window> GetParentsList(XDisplay* xdisplay, ::Window window) { | 
| return result; | 
| } | 
|  | 
| +int XI2ModeToXMode(int xi2_mode) { | 
| +  switch (xi2_mode) { | 
| +    case XINotifyNormal: | 
| +      return NotifyNormal; | 
| +    case XINotifyGrab: | 
| +    case XINotifyPassiveGrab: | 
| +      return NotifyGrab; | 
| +    case XINotifyUngrab: | 
| +    case XINotifyPassiveUngrab: | 
| +      return NotifyUngrab; | 
| +    case XINotifyWhileGrabbed: | 
| +      return NotifyWhileGrabbed; | 
| +    default: | 
| +      NOTREACHED(); | 
| +      return NotifyNormal; | 
| +  } | 
| +} | 
| + | 
| }  // namespace | 
|  | 
| //////////////////////////////////////////////////////////////////////////////// | 
| @@ -181,9 +200,12 @@ DesktopWindowTreeHostX11::DesktopWindowTreeHostX11( | 
| window_parent_(NULL), | 
| custom_window_shape_(false), | 
| urgency_hint_set_(false), | 
| +      has_pointer_grab_(false), | 
| activatable_(true), | 
| -      close_widget_factory_(this) { | 
| -} | 
| +      has_pointer_(false), | 
| +      has_window_focus_(false), | 
| +      has_pointer_focus_(false), | 
| +      close_widget_factory_(this) {} | 
|  | 
| DesktopWindowTreeHostX11::~DesktopWindowTreeHostX11() { | 
| window()->ClearProperty(kHostForRootWindow); | 
| @@ -230,20 +252,147 @@ gfx::Rect DesktopWindowTreeHostX11::GetX11RootWindowOuterBounds() const { | 
| return window_shape_.get(); | 
| } | 
|  | 
| -void DesktopWindowTreeHostX11::HandleNativeWidgetActivationChanged( | 
| -    bool active) { | 
| -  if (active) { | 
| +void DesktopWindowTreeHostX11::BeforeActivationStateChanged() { | 
| +  was_active_ = IsActive(); | 
| +  had_pointer_ = has_pointer_; | 
| +  had_pointer_grab_ = has_pointer_grab_; | 
| +  had_window_focus_ = has_window_focus_; | 
| +} | 
| + | 
| +void DesktopWindowTreeHostX11::AfterActivationStateChanged() { | 
| +  if (had_pointer_grab_ && !has_pointer_grab_) | 
| +    dispatcher()->OnHostLostMouseGrab(); | 
| + | 
| +  bool had_pointer_capture = had_pointer_ || had_pointer_grab_; | 
| +  bool has_pointer_capture = has_pointer_ || has_pointer_grab_; | 
| +  if (had_pointer_capture && !has_pointer_capture) | 
| +    OnHostLostWindowCapture(); | 
| + | 
| +  if (!was_active_ && IsActive()) { | 
| FlashFrame(false); | 
| OnHostActivated(); | 
| +    // TODO(thomasanderson): Remove this window shuffling and use XWindowCache | 
| +    // instead. | 
| open_windows().remove(xwindow_); | 
| open_windows().insert(open_windows().begin(), xwindow_); | 
| -  } else { | 
| -    ReleaseCapture(); | 
| } | 
|  | 
| -  desktop_native_widget_aura_->HandleActivationChanged(active); | 
| +  if (was_active_ != IsActive()) { | 
| +    desktop_native_widget_aura_->HandleActivationChanged(IsActive()); | 
| +    native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint(); | 
| +  } | 
| +} | 
| + | 
| +void DesktopWindowTreeHostX11::OnCrossingEvent(bool enter, | 
| +                                               bool focus_in_window_or_ancestor, | 
| +                                               int mode, | 
| +                                               int detail) { | 
| +  // NotifyInferior on a crossing event means the pointer moved into or out of a | 
| +  // child window, but the pointer is still within |xwindow_|. | 
| +  if (detail == NotifyInferior) | 
| +    return; | 
|  | 
| -  native_widget_delegate_->AsWidget()->GetRootView()->SchedulePaint(); | 
| +  BeforeActivationStateChanged(); | 
| + | 
| +  if (mode == NotifyGrab) | 
| +    has_pointer_grab_ = enter; | 
| +  else if (mode == NotifyUngrab) | 
| +    has_pointer_grab_ = false; | 
| + | 
| +  has_pointer_ = enter; | 
| +  if (focus_in_window_or_ancestor && !has_window_focus_) { | 
| +    // If we reach this point, we know the focus is in an ancestor or the | 
| +    // pointer root.  The definition of |has_pointer_focus_| is (An ancestor | 
| +    // window or the PointerRoot is focused) && |has_pointer_|.  Therefore, we | 
| +    // can just use |has_pointer_| in the assignment.  The transitions for when | 
| +    // the focus changes are handled in OnFocusEvent(). | 
| +    has_pointer_focus_ = has_pointer_; | 
| +  } | 
| + | 
| +  AfterActivationStateChanged(); | 
| +} | 
| + | 
| +void DesktopWindowTreeHostX11::OnFocusEvent(bool focus_in, | 
| +                                            int mode, | 
| +                                            int detail) { | 
| +  // NotifyInferior on a focus event means the focus moved into or out of a | 
| +  // child window, but the focus is still within |xwindow_|. | 
| +  if (detail == NotifyInferior) | 
| +    return; | 
| + | 
| +  bool notify_grab = mode == NotifyGrab || mode == NotifyUngrab; | 
| + | 
| +  BeforeActivationStateChanged(); | 
| + | 
| +  // For every focus change, the X server sends normal focus events which are | 
| +  // useful for tracking |has_window_focus_|, but supplements these events with | 
| +  // NotifyPointer events which are only useful for tracking pointer focus. | 
| + | 
| +  // For |has_pointer_focus_| and |has_window_focus_|, we continue tracking | 
| +  // state during a grab, but ignore grab/ungrab events themselves. | 
| +  if (!notify_grab && detail != NotifyPointer) | 
| +    has_window_focus_ = focus_in; | 
| + | 
| +  if (!notify_grab && has_pointer_) { | 
| +    switch (detail) { | 
| +      case NotifyAncestor: | 
| +      case NotifyVirtual: | 
| +        // If we reach this point, we know |has_pointer_| was true before and | 
| +        // after this event.  Since the definition of |has_pointer_focus_| is | 
| +        // (An ancestor window or the PointerRoot is focused) && |has_pointer_|, | 
| +        // we only need to worry about transitions on the first conjunct. | 
| +        // Therefore, |has_pointer_focus_| will become true when: | 
| +        // 1. Focus moves from |xwindow_| to an ancestor | 
| +        //    (FocusOut with NotifyAncestor) | 
| +        // 2. Focus moves from a decendant of |xwindow_| to an ancestor | 
| +        //    (FocusOut with NotifyVirtual) | 
| +        // |has_pointer_focus_| will become false when: | 
| +        // 1. Focus moves from an ancestor to |xwindow_| | 
| +        //    (FocusIn with NotifyAncestor) | 
| +        // 2. Focus moves from an ancestor to a child of |xwindow_| | 
| +        //    (FocusIn with NotifyVirtual) | 
| +        has_pointer_focus_ = !focus_in; | 
| +        break; | 
| +      case NotifyPointer: | 
| +        // The remaining cases for |has_pointer_focus_| becoming true are: | 
| +        // 3. Focus moves from |xwindow_| to the PointerRoot | 
| +        // 4. Focus moves from a decendant of |xwindow_| to the PointerRoot | 
| +        // 5. Focus moves from None to the PointerRoot | 
| +        // 6. Focus moves from Other to the PointerRoot | 
| +        // 7. Focus moves from None to an ancestor of |xwindow_| | 
| +        // 8. Focus moves from Other to an ancestor fo |xwindow_| | 
| +        // In each case, we will get a FocusIn with a detail of NotifyPointer. | 
| +        // The remaining cases for |has_pointer_focus_| becoming false are: | 
| +        // 3. Focus moves from the PointerRoot to |xwindow_| | 
| +        // 4. Focus moves from the PointerRoot to a decendant of |xwindow| | 
| +        // 5. Focus moves from the PointerRoot to None | 
| +        // 6. Focus moves from an ancestor of |xwindow_| to None | 
| +        // 7. Focus moves from the PointerRoot to Other | 
| +        // 8. Focus moves from an ancestor of |xwindow_| to Other | 
| +        // In each case, we will get a FocusOut with a detail of NotifyPointer. | 
| +        has_pointer_focus_ = focus_in; | 
| +        break; | 
| +      case NotifyNonlinear: | 
| +      case NotifyNonlinearVirtual: | 
| +        // We get Nonlinear(Virtual) events when | 
| +        // 1. Focus moves from Other to |xwindow_| | 
| +        //    (FocusIn with NotifyNonlinear) | 
| +        // 2. Focus moves from Other to a decendant of |xwindow_| | 
| +        //    (FocusIn with NotifyNonlinearVirtual) | 
| +        // 3. Focus moves from |xwindow_| to Other | 
| +        //    (FocusOut with NotifyNonlinear) | 
| +        // 4. Focus moves from a decendant of |xwindow_| to Other | 
| +        //    (FocusOut with NotifyNonlinearVirtual) | 
| +        // |has_pointer_focus_| should be false before and after this event. | 
| +        has_pointer_focus_ = false; | 
| +      default: | 
| +        break; | 
| +    } | 
| +  } | 
| + | 
| +  ignore_keyboard_input_ = false; | 
| + | 
| +  AfterActivationStateChanged(); | 
| } | 
|  | 
| void DesktopWindowTreeHostX11::AddObserver( | 
| @@ -308,8 +457,8 @@ void DesktopWindowTreeHostX11::OnNativeWidgetCreated( | 
| window()->SetProperty(kViewsWindowForRootWindow, content_window_); | 
| window()->SetProperty(kHostForRootWindow, this); | 
|  | 
| -  // Ensure that the X11DesktopHandler exists so that it dispatches activation | 
| -  // messages to us. | 
| +  // Ensure that the X11DesktopHandler exists so that it tracks create/destroy | 
| +  // notify events. | 
| X11DesktopHandler::get(); | 
|  | 
| // TODO(erg): Unify this code once the other consumer goes away. | 
| @@ -406,7 +555,7 @@ void DesktopWindowTreeHostX11::ShowWindowWithState( | 
| ui::WindowShowState show_state) { | 
| if (compositor()) | 
| compositor()->SetVisible(true); | 
| -  if (!window_mapped_) | 
| +  if (!IsVisible()) | 
| MapWindow(show_state); | 
|  | 
| switch (show_state) { | 
| @@ -426,8 +575,7 @@ void DesktopWindowTreeHostX11::ShowWindowWithState( | 
| // Makes the window activated by default if the state is not INACTIVE or | 
| // MINIMIZED. | 
| if (show_state != ui::SHOW_STATE_INACTIVE && | 
| -      show_state != ui::SHOW_STATE_MINIMIZED && | 
| -      activatable_) { | 
| +      show_state != ui::SHOW_STATE_MINIMIZED) { | 
| Activate(); | 
| } | 
|  | 
| @@ -443,7 +591,7 @@ void DesktopWindowTreeHostX11::ShowMaximizedWithBounds( | 
| } | 
|  | 
| bool DesktopWindowTreeHostX11::IsVisible() const { | 
| -  return window_mapped_; | 
| +  return window_mapped_ && !wait_for_unmap_; | 
| } | 
|  | 
| void DesktopWindowTreeHostX11::SetSize(const gfx::Size& requested_size) { | 
| @@ -614,22 +762,81 @@ void DesktopWindowTreeHostX11::SetShape( | 
| } | 
|  | 
| void DesktopWindowTreeHostX11::Activate() { | 
| -  if (!window_mapped_) | 
| +  if (!IsVisible() || !activatable_) | 
| return; | 
|  | 
| -  X11DesktopHandler::get()->ActivateWindow(xwindow_); | 
| +  BeforeActivationStateChanged(); | 
| + | 
| +  ignore_keyboard_input_ = false; | 
| + | 
| +  // wmii says that it supports _NET_ACTIVE_WINDOW but does not. | 
| +  // https://code.google.com/p/wmii/issues/detail?id=266 | 
| +  static bool wm_supports_active_window = | 
| +      ui::GuessWindowManager() != ui::WM_WMII && | 
| +      ui::WmSupportsHint(atom_cache_.GetAtom("_NET_ACTIVE_WINDOW")); | 
| + | 
| +  Time timestamp = ui::X11EventSource::GetInstance()->GetTimestamp(); | 
| + | 
| +  if (wm_supports_active_window) { | 
| +    XEvent xclient; | 
| +    memset(&xclient, 0, sizeof(xclient)); | 
| +    xclient.type = ClientMessage; | 
| +    xclient.xclient.window = xwindow_; | 
| +    xclient.xclient.message_type = atom_cache_.GetAtom("_NET_ACTIVE_WINDOW"); | 
| +    xclient.xclient.format = 32; | 
| +    xclient.xclient.data.l[0] = 1;  // Specified we are an app. | 
| +    xclient.xclient.data.l[1] = timestamp; | 
| +    // TODO(thomasanderson): if another chrome window is active, specify that in | 
| +    // data.l[2].  The EWMH spec claims this may make the WM more likely to | 
| +    // service our _NET_ACTIVE_WINDOW request. | 
| +    xclient.xclient.data.l[2] = None; | 
| +    xclient.xclient.data.l[3] = 0; | 
| +    xclient.xclient.data.l[4] = 0; | 
| + | 
| +    XSendEvent(xdisplay_, x_root_window_, False, | 
| +               SubstructureRedirectMask | SubstructureNotifyMask, &xclient); | 
| +  } else { | 
| +    XRaiseWindow(xdisplay_, xwindow_); | 
| +    // Directly ask the X server to give focus to the window. Note that the call | 
| +    // will raise an X error if the window is not mapped. | 
| +    XSetInputFocus(xdisplay_, xwindow_, RevertToParent, timestamp); | 
| +    // At this point, we know we will receive focus, and some tests depend on a | 
| +    // window being IsActive() immediately after an Activate(), so just set this | 
| +    // state now. | 
| +    has_pointer_focus_ = false; | 
| +    has_window_focus_ = true; | 
| +  } | 
| +  AfterActivationStateChanged(); | 
| } | 
|  | 
| void DesktopWindowTreeHostX11::Deactivate() { | 
| -  if (!IsActive()) | 
| -    return; | 
| +  BeforeActivationStateChanged(); | 
| + | 
| +  // Ignore future input events. | 
| +  ignore_keyboard_input_ = true; | 
|  | 
| ReleaseCapture(); | 
| -  X11DesktopHandler::get()->DeactivateWindow(xwindow_); | 
| +  XLowerWindow(xdisplay_, xwindow_); | 
| + | 
| +  AfterActivationStateChanged(); | 
| } | 
|  | 
| bool DesktopWindowTreeHostX11::IsActive() const { | 
| -  return X11DesktopHandler::get()->IsActiveWindow(xwindow_); | 
| +  // Focus and stacking order are independent in X11.  Since we cannot guarantee | 
| +  // a window is topmost iff it has focus, just use the focus state to determine | 
| +  // if a window is active.  Note that Activate() and Deactivate() change the | 
| +  // stacking order in addition to changing the focus state. | 
| +  bool is_active = | 
| +      (has_window_focus_ || has_pointer_focus_) && !ignore_keyboard_input_; | 
| + | 
| +  // is_active => window_mapped_ | 
| +  // !window_mapped_ => !is_active | 
| +  DCHECK(!is_active || window_mapped_); | 
| + | 
| +  // |has_window_focus_| and |has_pointer_focus_| are mutually exclusive. | 
| +  DCHECK(!has_window_focus_ || !has_pointer_focus_); | 
| + | 
| +  return is_active; | 
| } | 
|  | 
| void DesktopWindowTreeHostX11::Maximize() { | 
| @@ -650,7 +857,7 @@ void DesktopWindowTreeHostX11::Maximize() { | 
|  | 
| // Some WMs do not respect maximization hints on unmapped windows, so we | 
| // save this one for later too. | 
| -  should_maximize_after_map_ = !window_mapped_; | 
| +  should_maximize_after_map_ = !IsVisible(); | 
|  | 
| // When we are in the process of requesting to maximize a window, we can | 
| // accurately keep track of our restored bounds instead of relying on the | 
| @@ -971,7 +1178,7 @@ void DesktopWindowTreeHostX11::SizeConstraintsChanged() { | 
|  | 
| gfx::Transform DesktopWindowTreeHostX11::GetRootTransform() const { | 
| display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay(); | 
| -  if (window_mapped_) { | 
| +  if (IsVisible()) { | 
| aura::Window* win = const_cast<aura::Window*>(window()); | 
| display = display::Screen::GetScreen()->GetDisplayNearestWindow(win); | 
| } | 
| @@ -996,9 +1203,8 @@ void DesktopWindowTreeHostX11::ShowImpl() { | 
| } | 
|  | 
| void DesktopWindowTreeHostX11::HideImpl() { | 
| -  if (window_mapped_) { | 
| +  if (IsVisible()) { | 
| XWithdrawWindow(xdisplay_, xwindow_, 0); | 
| -    window_mapped_ = false; | 
| wait_for_unmap_ = true; | 
| } | 
| native_widget_delegate_->OnNativeWidgetVisibilityChanged(false); | 
| @@ -1086,7 +1292,9 @@ void DesktopWindowTreeHostX11::SetCapture() { | 
| if (old_capturer) | 
| old_capturer->OnHostLostWindowCapture(); | 
|  | 
| -  GrabPointer(xwindow_, true, None); | 
| +  // If the pointer is already in |xwindow_|, we will not get a crossing event | 
| +  // with a mode of NotifyGrab, so we must record the grab state manually. | 
| +  has_pointer_grab_ |= !GrabPointer(xwindow_, true, None); | 
| } | 
|  | 
| void DesktopWindowTreeHostX11::ReleaseCapture() { | 
| @@ -1096,6 +1304,7 @@ void DesktopWindowTreeHostX11::ReleaseCapture() { | 
| // asynchronous is likely inconsequential. | 
| g_current_capture = NULL; | 
| UngrabPointer(); | 
| +    has_pointer_grab_ = false; | 
|  | 
| OnHostLostWindowCapture(); | 
| } | 
| @@ -1424,7 +1633,7 @@ void DesktopWindowTreeHostX11::OnFrameExtentsUpdated() { | 
| } | 
|  | 
| void DesktopWindowTreeHostX11::UpdateMinAndMaxSize() { | 
| -  if (!window_mapped_) | 
| +  if (!IsVisible()) | 
| return; | 
|  | 
| gfx::Size minimum_in_pixels = | 
| @@ -1480,7 +1689,6 @@ void DesktopWindowTreeHostX11::UpdateWMUserTime( | 
| PropModeReplace, | 
| reinterpret_cast<const unsigned char *>(&wm_user_time_ms), | 
| 1); | 
| -    X11DesktopHandler::get()->set_wm_user_time_ms(wm_user_time_ms); | 
| } | 
| } | 
|  | 
| @@ -1681,17 +1889,16 @@ void DesktopWindowTreeHostX11::MapWindow(ui::WindowShowState show_state) { | 
| // If SHOW_STATE_INACTIVE, tell the window manager not to focus the window | 
| // when mapping. This is done by setting the _NET_WM_USER_TIME to 0. See e.g. | 
| // http://standards.freedesktop.org/wm-spec/latest/ar01s05.html | 
| -  unsigned long wm_user_time_ms = (show_state == ui::SHOW_STATE_INACTIVE) ? | 
| -      0 : X11DesktopHandler::get()->wm_user_time_ms(); | 
| +  ignore_keyboard_input_ = show_state == ui::SHOW_STATE_INACTIVE; | 
| +  unsigned long wm_user_time_ms = | 
| +      ignore_keyboard_input_ | 
| +          ? 0 | 
| +          : ui::X11EventSource::GetInstance()->GetTimestamp(); | 
| if (show_state == ui::SHOW_STATE_INACTIVE || wm_user_time_ms != 0) { | 
| -    XChangeProperty(xdisplay_, | 
| -                    xwindow_, | 
| -                    atom_cache_.GetAtom("_NET_WM_USER_TIME"), | 
| -                    XA_CARDINAL, | 
| -                    32, | 
| -                    PropModeReplace, | 
| -                    reinterpret_cast<const unsigned char *>(&wm_user_time_ms), | 
| -                    1); | 
| +    XChangeProperty( | 
| +        xdisplay_, xwindow_, atom_cache_.GetAtom("_NET_WM_USER_TIME"), | 
| +        XA_CARDINAL, 32, PropModeReplace, | 
| +        reinterpret_cast<const unsigned char*>(&wm_user_time_ms), 1); | 
| } | 
|  | 
| ui::X11EventSource* event_source = ui::X11EventSource::GetInstance(); | 
| @@ -1753,15 +1960,15 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( | 
| switch (xev->type) { | 
| case EnterNotify: | 
| case LeaveNotify: { | 
| +      OnCrossingEvent(xev->type == EnterNotify, xev->xcrossing.focus, | 
| +                      xev->xcrossing.mode, xev->xcrossing.detail); | 
| + | 
| // Ignore EventNotify and LeaveNotify events from children of |xwindow_|. | 
| // NativeViewGLSurfaceGLX adds a child to |xwindow_|. | 
| -      // TODO(pkotwicz|tdanderson): Figure out whether the suppression is | 
| -      // necessary. crbug.com/385716 | 
| -      if (xev->xcrossing.detail == NotifyInferior) | 
| -        break; | 
| - | 
| -      ui::MouseEvent mouse_event(xev); | 
| -      DispatchMouseEvent(&mouse_event); | 
| +      if (xev->xcrossing.detail != NotifyInferior) { | 
| +        ui::MouseEvent mouse_event(xev); | 
| +        DispatchMouseEvent(&mouse_event); | 
| +      } | 
| break; | 
| } | 
| case Expose: { | 
| @@ -1777,8 +1984,7 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( | 
| } | 
| case KeyRelease: { | 
| // There is no way to deactivate a window in X11 so ignore input if | 
| -      // window is supposed to be 'inactive'. See comments in | 
| -      // X11DesktopHandler::DeactivateWindow() for more details. | 
| +      // window is supposed to be 'inactive'. | 
| if (!IsActive() && !HasCapture()) | 
| break; | 
|  | 
| @@ -1809,17 +2015,10 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( | 
| } | 
| break; | 
| } | 
| -    case FocusOut: | 
| -      if (xev->xfocus.mode != NotifyGrab) { | 
| -        ReleaseCapture(); | 
| -        OnHostLostWindowCapture(); | 
| -        X11DesktopHandler::get()->ProcessXEvent(xev); | 
| -      } else { | 
| -        dispatcher()->OnHostLostMouseGrab(); | 
| -      } | 
| -      break; | 
| case FocusIn: | 
| -      X11DesktopHandler::get()->ProcessXEvent(xev); | 
| +    case FocusOut: | 
| +      OnFocusEvent(xev->type == FocusIn, event->xfocus.mode, | 
| +                   event->xfocus.detail); | 
| break; | 
| case ConfigureNotify: { | 
| DCHECK_EQ(xwindow_, xev->xconfigure.window); | 
| @@ -1860,6 +2059,23 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( | 
| if (!factory->ShouldProcessXI2Event(xev)) | 
| break; | 
|  | 
| +      XIEnterEvent* enter_event = static_cast<XIEnterEvent*>(xev->xcookie.data); | 
| +      switch (static_cast<XIEvent*>(xev->xcookie.data)->evtype) { | 
| +        case XI_Enter: | 
| +        case XI_Leave: | 
| +          OnCrossingEvent(enter_event->evtype == XI_Enter, enter_event->focus, | 
| +                          XI2ModeToXMode(enter_event->mode), | 
| +                          enter_event->detail); | 
| +          break; | 
| +        case XI_FocusIn: | 
| +        case XI_FocusOut: | 
| +          OnFocusEvent(enter_event->evtype == XI_FocusIn, | 
| +                       XI2ModeToXMode(enter_event->mode), enter_event->detail); | 
| +          break; | 
| +        default: | 
| +          break; | 
| +      } | 
| + | 
| ui::EventType type = ui::EventTypeFromNative(xev); | 
| XEvent last_event; | 
| int num_coalesced = 0; | 
| @@ -1941,7 +2157,12 @@ uint32_t DesktopWindowTreeHostX11::DispatchEvent( | 
| break; | 
| } | 
| case UnmapNotify: { | 
| +      window_mapped_ = false; | 
| wait_for_unmap_ = false; | 
| +      has_pointer_ = false; | 
| +      has_pointer_grab_ = false; | 
| +      has_pointer_focus_ = false; | 
| +      has_window_focus_ = false; | 
| FOR_EACH_OBSERVER(DesktopWindowTreeHostObserverX11, | 
| observer_list_, | 
| OnWindowUnmapped(xwindow_)); | 
|  |