Index: ui/views/widget/desktop_root_window_host_linux.cc |
diff --git a/ui/views/widget/desktop_root_window_host_linux.cc b/ui/views/widget/desktop_root_window_host_linux.cc |
index c2f28657a357076baaa232a296e31411b0281a71..1d82f018399839c6966c3b72477587a3ec2b1f48 100644 |
--- a/ui/views/widget/desktop_root_window_host_linux.cc |
+++ b/ui/views/widget/desktop_root_window_host_linux.cc |
@@ -4,17 +4,172 @@ |
#include "ui/views/widget/desktop_root_window_host_linux.h" |
+#include <X11/extensions/XInput2.h> |
+#include <X11/Xatom.h> |
+#include <X11/Xutil.h> |
+ |
+#include "base/message_pump_aurax11.h" |
+#include "base/stringprintf.h" |
+#include "ui/aura/client/screen_position_client.h" |
+#include "ui/aura/client/user_action_client.h" |
+#include "ui/aura/desktop/desktop_activation_client.h" |
+#include "ui/aura/desktop/desktop_dispatcher_client.h" |
+#include "ui/aura/focus_manager.h" |
#include "ui/aura/root_window.h" |
+#include "ui/aura/shared/compound_event_filter.h" |
+#include "ui/aura/shared/input_method_event_filter.h" |
+#include "ui/base/touch/touch_factory.h" |
+#include "ui/base/x/x11_util.h" |
+#include "ui/views/widget/desktop_capture_client.h" |
+#include "ui/views/widget/x11_desktop_handler.h" |
+#include "ui/views/widget/x11_window_event_filter.h" |
namespace views { |
+namespace { |
+ |
+// Standard Linux mouse buttons for going back and forward. |
+const int kBackMouseButton = 8; |
+const int kForwardMouseButton = 9; |
+ |
+const char* kAtomsToCache[] = { |
+ "WM_DELETE_WINDOW", |
+ "_NET_WM_PING", |
+ "_NET_WM_PID", |
+ "WM_S0", |
+ NULL |
+}; |
+ |
+} // namespace |
+ |
//////////////////////////////////////////////////////////////////////////////// |
// DesktopRootWindowHostLinux, public: |
-DesktopRootWindowHostLinux::DesktopRootWindowHostLinux() { |
+DesktopRootWindowHostLinux::DesktopRootWindowHostLinux() |
+ : xdisplay_(base::MessagePumpAuraX11::GetDefaultXDisplay()), |
+ xwindow_(0), |
+ x_root_window_(DefaultRootWindow(xdisplay_)), |
+ atom_cache_(xdisplay_, kAtomsToCache), |
+ window_mapped_(false), |
+ focus_when_shown_(false) { |
} |
DesktopRootWindowHostLinux::~DesktopRootWindowHostLinux() { |
+ base::MessagePumpAuraX11::Current()->RemoveDispatcherForWindow(xwindow_); |
+ XDestroyWindow(xdisplay_, xwindow_); |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// DesktopRootWindowHostLinux, private: |
+ |
+void DesktopRootWindowHostLinux::InitX11Window(const gfx::Rect& bounds) { |
+ XSetWindowAttributes swa; |
+ memset(&swa, 0, sizeof(swa)); |
+ swa.background_pixmap = None; |
+ xwindow_ = XCreateWindow( |
+ xdisplay_, x_root_window_, |
+ bounds.x(), bounds.y(), bounds.width(), bounds.height(), |
+ 0, // border width |
+ CopyFromParent, // depth |
+ InputOutput, |
+ CopyFromParent, // visual |
+ CWBackPixmap, |
+ &swa); |
+ base::MessagePumpAuraX11::Current()->AddDispatcherForWindow(this, xwindow_); |
+ |
+ // TODO(erg): Maybe need to set a ViewProp here like in RWHL::RWHL(). |
+ |
+ long event_mask = ButtonPressMask | ButtonReleaseMask | FocusChangeMask | |
+ KeyPressMask | KeyReleaseMask | |
+ EnterWindowMask | LeaveWindowMask | |
+ ExposureMask | VisibilityChangeMask | |
+ StructureNotifyMask | PropertyChangeMask | |
+ PointerMotionMask; |
+ XSelectInput(xdisplay_, xwindow_, event_mask); |
+ XFlush(xdisplay_); |
+ |
+ // TODO(erg): Something about an invisible cursor here? Don't think I need |
+ // it, but this is where it was. |
+ |
+ // TODO(erg): We currently only request window deletion events. We also |
+ // should listen for activation events and anything else that GTK+ listens |
+ // for, and do something useful. |
+ ::Atom protocols[2]; |
+ protocols[0] = atom_cache_.GetAtom("WM_DELETE_WINDOW"); |
+ protocols[1] = atom_cache_.GetAtom("_NET_WM_PING"); |
+ XSetWMProtocols(xdisplay_, xwindow_, protocols, 2); |
+ |
+ // We need a WM_CLIENT_MACHINE and WM_LOCALE_NAME value so we integrate with |
+ // the desktop environment. |
+ XSetWMProperties(xdisplay_, xwindow_, NULL, NULL, NULL, 0, NULL, NULL, NULL); |
+ |
+ // Likewise, the X server needs to know this window's pid so it knows which |
+ // program to kill if the window hangs. |
+ pid_t pid = getpid(); |
+ XChangeProperty(xdisplay_, |
+ xwindow_, |
+ atom_cache_.GetAtom("_NET_WM_PID"), |
+ XA_CARDINAL, |
+ 32, |
+ PropModeReplace, |
+ reinterpret_cast<unsigned char*>(&pid), 1); |
+ |
+ // TODO(erg): Now that we're forked from RootWindowHostLinux, we should be |
+ // doing a much better job about communicating things like the window title |
+ // and icon to the window manager, which should replace this piece of copied |
+ // code. |
+ static int root_window_number = 0; |
+ std::string name = StringPrintf("aura_root_%d", root_window_number++); |
+ XStoreName(xdisplay_, xwindow_, name.c_str()); |
+} |
+ |
+// TODO(erg): This method should basically be everything I need form |
+// RootWindowHostLinux::RootWindowHostLinux(). |
+void DesktopRootWindowHostLinux::InitRootWindow( |
+ const Widget::InitParams& params) { |
+ aura::RootWindow::CreateParams rw_params(params.bounds); |
+ rw_params.host = this; |
+ root_window_.reset(new aura::RootWindow(rw_params)); |
+ root_window_->Init(); |
+ root_window_->AddChild(content_window_); |
+ root_window_host_delegate_ = root_window_.get(); |
+ |
+ capture_client_.reset(new DesktopCaptureClient); |
+ aura::client::SetCaptureClient(root_window_.get(), capture_client_.get()); |
+ |
+ root_window_->set_focus_manager( |
+ X11DesktopHandler::get()->get_focus_manager()); |
+ |
+ aura::DesktopActivationClient* activation_client = |
+ X11DesktopHandler::get()->get_activation_client(); |
+ aura::client::SetActivationClient( |
+ root_window_.get(), activation_client); |
+ |
+ dispatcher_client_.reset(new aura::DesktopDispatcherClient); |
+ aura::client::SetDispatcherClient(root_window_.get(), |
+ dispatcher_client_.get()); |
+ |
+ // No event filter for aura::Env. Create CompoundEvnetFilter per RootWindow. |
+ root_window_event_filter_ = new aura::shared::CompoundEventFilter; |
+ // Pass ownership of the filter to the root_window. |
+ root_window_->SetEventFilter(root_window_event_filter_); |
+ |
+ input_method_filter_.reset(new aura::shared::InputMethodEventFilter()); |
+ input_method_filter_->SetInputMethodPropertyInRootWindow(root_window_.get()); |
+ root_window_event_filter_->AddFilter(input_method_filter_.get()); |
+ |
+ // TODO(erg): Unify this code once the other consumer goes away. |
+ x11_window_event_filter_.reset( |
+ new X11WindowEventFilter(root_window_.get(), activation_client)); |
+ x11_window_event_filter_->SetUseHostWindowBorders(false); |
+ root_window_event_filter_->AddFilter(x11_window_event_filter_.get()); |
+} |
+ |
+bool DesktopRootWindowHostLinux::IsWindowManagerPresent() { |
+ // Per ICCCM 2.8, "Manager Selections", window managers should take ownership |
+ // of WM_Sn selections (where n is a screen number). |
+ return XGetSelectionOwner( |
+ xdisplay_, atom_cache_.GetAtom("WM_S0")) != None; |
} |
//////////////////////////////////////////////////////////////////////////////// |
@@ -22,8 +177,24 @@ DesktopRootWindowHostLinux::~DesktopRootWindowHostLinux() { |
void DesktopRootWindowHostLinux::Init(aura::Window* content_window, |
const Widget::InitParams& params) { |
- // TODO(erg): |
- NOTIMPLEMENTED(); |
+ content_window_ = content_window; |
+ |
+ // TODO(erg): Check whether we *should* be building a RootWindowHost here, or |
+ // whether we should be proxying requests to another DRWHL. |
+ |
+ // TODO(erg): We can finally solve the role problem! Based on params, try to |
+ // determine whether this is a utility window such as a menu. |
+ |
+ InitX11Window(params.bounds); |
+ InitRootWindow(params); |
+ |
+ // TODO(erg): This should be done by a LayoutManager instead of being a |
+ // one-off hack. |
+ content_window_->SetBounds(params.bounds); |
+ |
+ // This needs to be the intersection of: |
+ // - NativeWidgetAura::InitNativeWidget() |
+ // - DesktopNativeWidgetHelperAura::PreInitialize() |
} |
void DesktopRootWindowHostLinux::Close() { |
@@ -32,20 +203,22 @@ void DesktopRootWindowHostLinux::Close() { |
} |
void DesktopRootWindowHostLinux::CloseNow() { |
- // TODO(erg): |
NOTIMPLEMENTED(); |
} |
aura::RootWindowHost* DesktopRootWindowHostLinux::AsRootWindowHost() { |
- // TODO(erg): |
- NOTIMPLEMENTED(); |
- return NULL; |
+ return this; |
} |
void DesktopRootWindowHostLinux::ShowWindowWithState( |
ui::WindowShowState show_state) { |
- // TODO(erg): |
- NOTIMPLEMENTED(); |
+ if (show_state != ui::SHOW_STATE_DEFAULT && |
+ show_state != ui::SHOW_STATE_NORMAL) { |
+ // Only forwarding to Show(). |
+ NOTIMPLEMENTED(); |
+ } |
+ |
+ Show(); |
} |
void DesktopRootWindowHostLinux::ShowMaximizedWithBounds( |
@@ -55,9 +228,7 @@ void DesktopRootWindowHostLinux::ShowMaximizedWithBounds( |
} |
bool DesktopRootWindowHostLinux::IsVisible() const { |
- // TODO(erg): |
- NOTIMPLEMENTED(); |
- return true; |
+ return window_mapped_; |
} |
void DesktopRootWindowHostLinux::SetSize(const gfx::Size& size) { |
@@ -73,8 +244,8 @@ void DesktopRootWindowHostLinux::CenterWindow(const gfx::Size& size) { |
void DesktopRootWindowHostLinux::GetWindowPlacement( |
gfx::Rect* bounds, |
ui::WindowShowState* show_state) const { |
- // TODO(erg): |
- NOTIMPLEMENTED(); |
+ // TODO(erg): |
+ NOTIMPLEMENTED(); |
} |
gfx::Rect DesktopRootWindowHostLinux::GetWindowBoundsInScreen() const { |
@@ -177,6 +348,351 @@ void DesktopRootWindowHostLinux::SetWindowTitle(const string16& title) { |
} |
//////////////////////////////////////////////////////////////////////////////// |
+// DesktopRootWindowHostLinux, aura::RootWindowHost implementation: |
+ |
+aura::RootWindow* DesktopRootWindowHostLinux::GetRootWindow() { |
+ return root_window_.get(); |
+} |
+ |
+gfx::AcceleratedWidget DesktopRootWindowHostLinux::GetAcceleratedWidget() { |
+ return xwindow_; |
+} |
+ |
+void DesktopRootWindowHostLinux::Show() { |
+ if (!window_mapped_) { |
+ // Before we map the window, set size hints. Otherwise, some window managers |
+ // will ignore toplevel XMoveWindow commands. |
+ XSizeHints size_hints; |
+ size_hints.flags = PPosition; |
+ size_hints.x = bounds_.x(); |
+ size_hints.y = bounds_.y(); |
+ XSetWMNormalHints(xdisplay_, xwindow_, &size_hints); |
+ |
+ XMapWindow(xdisplay_, xwindow_); |
+ |
+ // We now block until our window is mapped. Some X11 APIs will crash and |
+ // burn if passed |xwindow_| before the window is mapped, and XMapWindow is |
+ // asynchronous. |
+ base::MessagePumpAuraX11::Current()->BlockUntilWindowMapped(xwindow_); |
+ window_mapped_ = true; |
+ } |
+} |
+ |
+void DesktopRootWindowHostLinux::Hide() { |
+ if (window_mapped_) { |
+ XWithdrawWindow(xdisplay_, xwindow_, 0); |
+ window_mapped_ = false; |
+ } |
+} |
+ |
+void DesktopRootWindowHostLinux::ToggleFullScreen() { |
+} |
+ |
+gfx::Rect DesktopRootWindowHostLinux::GetBounds() const { |
+ return gfx::Rect(100, 100); |
+} |
+ |
+void DesktopRootWindowHostLinux::SetBounds(const gfx::Rect& bounds) { |
+} |
+ |
+gfx::Point DesktopRootWindowHostLinux::GetLocationOnNativeScreen() const { |
+ return gfx::Point(1, 1); |
+} |
+ |
+void DesktopRootWindowHostLinux::SetCapture() { |
+} |
+ |
+void DesktopRootWindowHostLinux::ReleaseCapture() { |
+} |
+ |
+void DesktopRootWindowHostLinux::SetCursor(gfx::NativeCursor cursor) { |
+} |
+ |
+void DesktopRootWindowHostLinux::ShowCursor(bool show) { |
+} |
+ |
+bool DesktopRootWindowHostLinux::QueryMouseLocation( |
+ gfx::Point* location_return) { |
+ return false; |
+} |
+ |
+bool DesktopRootWindowHostLinux::ConfineCursorToRootWindow() { |
+ return false; |
+} |
+ |
+void DesktopRootWindowHostLinux::UnConfineCursor() { |
+} |
+ |
+void DesktopRootWindowHostLinux::MoveCursorTo(const gfx::Point& location) { |
+} |
+ |
+void DesktopRootWindowHostLinux::SetFocusWhenShown(bool focus_when_shown) { |
+ static const char* k_NET_WM_USER_TIME = "_NET_WM_USER_TIME"; |
+ focus_when_shown_ = focus_when_shown; |
+ if (IsWindowManagerPresent() && !focus_when_shown_) { |
+ ui::SetIntProperty(xwindow_, |
+ k_NET_WM_USER_TIME, |
+ k_NET_WM_USER_TIME, |
+ 0); |
+ } |
+} |
+ |
+bool DesktopRootWindowHostLinux::GrabSnapshot( |
+ const gfx::Rect& snapshot_bounds, |
+ std::vector<unsigned char>* png_representation) { |
+ return false; |
+} |
+ |
+void DesktopRootWindowHostLinux::PostNativeEvent( |
+ const base::NativeEvent& native_event) { |
+ DCHECK(xwindow_); |
+ DCHECK(xdisplay_); |
+ XEvent xevent = *native_event; |
+ xevent.xany.display = xdisplay_; |
+ xevent.xany.window = xwindow_; |
+ |
+ switch (xevent.type) { |
+ case EnterNotify: |
+ case LeaveNotify: |
+ case MotionNotify: |
+ case KeyPress: |
+ case KeyRelease: |
+ case ButtonPress: |
+ case ButtonRelease: { |
+ // The fields used below are in the same place for all of events |
+ // above. Using xmotion from XEvent's unions to avoid repeating |
+ // the code. |
+ xevent.xmotion.root = x_root_window_; |
+ xevent.xmotion.time = CurrentTime; |
+ |
+ gfx::Point point(xevent.xmotion.x, xevent.xmotion.y); |
+ root_window_->ConvertPointToNativeScreen(&point); |
+ xevent.xmotion.x_root = point.x(); |
+ xevent.xmotion.y_root = point.y(); |
+ } |
+ default: |
+ break; |
+ } |
+ XSendEvent(xdisplay_, xwindow_, False, 0, &xevent); |
+} |
+ |
+void DesktopRootWindowHostLinux::OnDeviceScaleFactorChanged( |
+ float device_scale_factor) { |
+} |
+ |
+void DesktopRootWindowHostLinux::PrepareForShutdown() { |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// DesktopRootWindowHostLinux, MessageLoop::Dispatcher implementation: |
+ |
+bool DesktopRootWindowHostLinux::Dispatch(const base::NativeEvent& event) { |
+ XEvent* xev = event; |
+ |
+ // May want to factor CheckXEventForConsistency(xev); into a common location |
+ // since it is called here. |
+ switch (xev->type) { |
+ case Expose: |
+ // TODO(erg): Can we only redraw the affected areas? |
+ root_window_host_delegate_->OnHostPaint(); |
+ break; |
+ case KeyPress: { |
+ ui::KeyEvent keydown_event(xev, false); |
+ root_window_host_delegate_->OnHostKeyEvent(&keydown_event); |
+ break; |
+ } |
+ case KeyRelease: { |
+ ui::KeyEvent keyup_event(xev, false); |
+ root_window_host_delegate_->OnHostKeyEvent(&keyup_event); |
+ break; |
+ } |
+ case ButtonPress: { |
+ if (static_cast<int>(xev->xbutton.button) == kBackMouseButton || |
+ static_cast<int>(xev->xbutton.button) == kForwardMouseButton) { |
+ aura::client::UserActionClient* gesture_client = |
+ aura::client::GetUserActionClient(root_window_.get()); |
+ if (gesture_client) { |
+ gesture_client->OnUserAction( |
+ static_cast<int>(xev->xbutton.button) == kBackMouseButton ? |
+ aura::client::UserActionClient::BACK : |
+ aura::client::UserActionClient::FORWARD); |
+ } |
+ break; |
+ } |
+ } // fallthrough |
+ case ButtonRelease: { |
+ ui::MouseEvent mouseev(xev); |
+ root_window_host_delegate_->OnHostMouseEvent(&mouseev); |
+ break; |
+ } |
+ case FocusOut: |
+ if (xev->xfocus.mode != NotifyGrab) |
+ root_window_host_delegate_->OnHostLostCapture(); |
+ break; |
+ case ConfigureNotify: { |
+ DCHECK_EQ(xwindow_, xev->xconfigure.window); |
+ DCHECK_EQ(xwindow_, xev->xconfigure.event); |
+ // It's possible that the X window may be resized by some other means than |
+ // from within aura (e.g. the X window manager can change the size). Make |
+ // sure the root window size is maintained properly. |
+ gfx::Rect bounds(xev->xconfigure.x, xev->xconfigure.y, |
+ xev->xconfigure.width, xev->xconfigure.height); |
+ bool size_changed = bounds_.size() != bounds.size(); |
+ bool origin_changed = bounds_.origin() != bounds.origin(); |
+ bounds_ = bounds; |
+ if (size_changed) |
+ root_window_host_delegate_->OnHostResized(bounds.size()); |
+ if (origin_changed) |
+ root_window_host_delegate_->OnHostMoved(bounds_.origin()); |
+ break; |
+ } |
+ case GenericEvent: { |
+ ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); |
+ if (!factory->ShouldProcessXI2Event(xev)) |
+ break; |
+ |
+ ui::EventType type = ui::EventTypeFromNative(xev); |
+ XEvent last_event; |
+ int num_coalesced = 0; |
+ |
+ switch (type) { |
+ // case ui::ET_TOUCH_MOVED: |
+ // num_coalesced = CoalescePendingMotionEvents(xev, &last_event); |
+ // if (num_coalesced > 0) |
+ // xev = &last_event; |
+ // // fallthrough |
+ // case ui::ET_TOUCH_PRESSED: |
+ // case ui::ET_TOUCH_RELEASED: { |
+ // ui::TouchEvent touchev(xev); |
+ // root_window_host_delegate_->OnHostTouchEvent(&touchev); |
+ // break; |
+ // } |
+ case ui::ET_MOUSE_MOVED: |
+ case ui::ET_MOUSE_DRAGGED: |
+ case ui::ET_MOUSE_PRESSED: |
+ case ui::ET_MOUSE_RELEASED: |
+ case ui::ET_MOUSE_ENTERED: |
+ case ui::ET_MOUSE_EXITED: { |
+ if (type == ui::ET_MOUSE_MOVED || type == ui::ET_MOUSE_DRAGGED) { |
+ // If this is a motion event, we want to coalesce all pending motion |
+ // events that are at the top of the queue. |
+ // num_coalesced = CoalescePendingMotionEvents(xev, &last_event); |
+ // if (num_coalesced > 0) |
+ // xev = &last_event; |
+ } else if (type == ui::ET_MOUSE_PRESSED) { |
+ XIDeviceEvent* xievent = |
+ static_cast<XIDeviceEvent*>(xev->xcookie.data); |
+ int button = xievent->detail; |
+ if (button == kBackMouseButton || button == kForwardMouseButton) { |
+ aura::client::UserActionClient* gesture_client = |
+ aura::client::GetUserActionClient( |
+ root_window_host_delegate_->AsRootWindow()); |
+ if (gesture_client) { |
+ bool reverse_direction = |
+ ui::IsTouchpadEvent(xev) && ui::IsNaturalScrollEnabled(); |
+ gesture_client->OnUserAction( |
+ (button == kBackMouseButton && !reverse_direction) || |
+ (button == kForwardMouseButton && reverse_direction) ? |
+ aura::client::UserActionClient::BACK : |
+ aura::client::UserActionClient::FORWARD); |
+ } |
+ break; |
+ } |
+ } |
+ ui::MouseEvent mouseev(xev); |
+ root_window_host_delegate_->OnHostMouseEvent(&mouseev); |
+ break; |
+ } |
+ case ui::ET_MOUSEWHEEL: { |
+ ui::MouseWheelEvent mouseev(xev); |
+ root_window_host_delegate_->OnHostMouseEvent(&mouseev); |
+ break; |
+ } |
+ case ui::ET_SCROLL_FLING_START: |
+ case ui::ET_SCROLL_FLING_CANCEL: |
+ case ui::ET_SCROLL: { |
+ ui::ScrollEvent scrollev(xev); |
+ root_window_host_delegate_->OnHostScrollEvent(&scrollev); |
+ break; |
+ } |
+ case ui::ET_UNKNOWN: |
+ break; |
+ default: |
+ NOTREACHED(); |
+ } |
+ |
+ // If we coalesced an event we need to free its cookie. |
+ if (num_coalesced > 0) |
+ XFreeEventData(xev->xgeneric.display, &last_event.xcookie); |
+ break; |
+ } |
+ case MapNotify: { |
+ // If there's no window manager running, we need to assign the X input |
+ // focus to our host window. |
+ if (!IsWindowManagerPresent() && focus_when_shown_) |
+ XSetInputFocus(xdisplay_, xwindow_, RevertToNone, CurrentTime); |
+ break; |
+ } |
+ case ClientMessage: { |
+ Atom message_type = static_cast<Atom>(xev->xclient.data.l[0]); |
+ if (message_type == atom_cache_.GetAtom("WM_DELETE_WINDOW")) { |
+ // We have received a close message from the window manager. |
+ root_window_->OnRootWindowHostCloseRequested(); |
+ } else if (message_type == atom_cache_.GetAtom("_NET_WM_PING")) { |
+ XEvent reply_event = *xev; |
+ reply_event.xclient.window = x_root_window_; |
+ |
+ XSendEvent(xdisplay_, |
+ reply_event.xclient.window, |
+ False, |
+ SubstructureRedirectMask | SubstructureNotifyMask, |
+ &reply_event); |
+ } |
+ break; |
+ } |
+ case MappingNotify: { |
+ switch (xev->xmapping.request) { |
+ case MappingModifier: |
+ case MappingKeyboard: |
+ XRefreshKeyboardMapping(&xev->xmapping); |
+ root_window_->OnKeyboardMappingChanged(); |
+ break; |
+ case MappingPointer: |
+ ui::UpdateButtonMap(); |
+ break; |
+ default: |
+ NOTIMPLEMENTED() << " Unknown request: " << xev->xmapping.request; |
+ break; |
+ } |
+ break; |
+ } |
+ case MotionNotify: { |
+ // Discard all but the most recent motion event that targets the same |
+ // window with unchanged state. |
+ XEvent last_event; |
+ while (XPending(xev->xany.display)) { |
+ XEvent next_event; |
+ XPeekEvent(xev->xany.display, &next_event); |
+ if (next_event.type == MotionNotify && |
+ next_event.xmotion.window == xev->xmotion.window && |
+ next_event.xmotion.subwindow == xev->xmotion.subwindow && |
+ next_event.xmotion.state == xev->xmotion.state) { |
+ XNextEvent(xev->xany.display, &last_event); |
+ xev = &last_event; |
+ } else { |
+ break; |
+ } |
+ } |
+ |
+ ui::MouseEvent mouseev(xev); |
+ root_window_host_delegate_->OnHostMouseEvent(&mouseev); |
+ break; |
+ } |
+ } |
+ return true; |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
// DesktopRootWindowHost, public: |
// static |