base: Do not allow MessagePumpObservers to consume events.
[chromium-blink-merge.git] / ui / aura / test / ui_controls_factory_aurax11.cc
blobda8dff469d4df67309986c24c6358a32ac85a562
1 // Copyright 2013 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.
5 #include <X11/keysym.h>
6 #include <X11/Xlib.h>
8 #include "base/logging.h"
9 #include "ui/aura/client/screen_position_client.h"
10 #include "ui/aura/env.h"
11 #include "ui/aura/test/ui_controls_factory_aura.h"
12 #include "ui/aura/window.h"
13 #include "ui/aura/window_tree_host.h"
14 #include "ui/base/test/ui_controls_aura.h"
15 #include "ui/base/x/x11_util.h"
16 #include "ui/compositor/dip_util.h"
17 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
19 namespace aura {
20 namespace test {
21 namespace {
23 using ui_controls::DOWN;
24 using ui_controls::LEFT;
25 using ui_controls::MIDDLE;
26 using ui_controls::MouseButton;
27 using ui_controls::RIGHT;
28 using ui_controls::UIControlsAura;
29 using ui_controls::UP;
31 // Mask of the buttons currently down.
32 unsigned button_down_mask = 0;
34 // Event waiter executes the specified closure|when a matching event
35 // is found.
36 // TODO(oshima): Move this to base.
37 class EventWaiter : public base::MessageLoopForUI::Observer {
38 public:
39 typedef bool (*EventWaiterMatcher)(const base::NativeEvent& event);
41 EventWaiter(const base::Closure& closure, EventWaiterMatcher matcher)
42 : closure_(closure),
43 matcher_(matcher) {
44 base::MessageLoopForUI::current()->AddObserver(this);
47 virtual ~EventWaiter() {
48 base::MessageLoopForUI::current()->RemoveObserver(this);
51 // MessageLoop::Observer implementation:
52 virtual void WillProcessEvent(const base::NativeEvent& event) OVERRIDE {
53 if ((*matcher_)(event)) {
54 base::MessageLoop::current()->PostTask(FROM_HERE, closure_);
55 delete this;
59 virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
62 private:
63 base::Closure closure_;
64 EventWaiterMatcher matcher_;
65 DISALLOW_COPY_AND_ASSIGN(EventWaiter);
68 // Returns atom that indidates that the XEvent is marker event.
69 Atom MarkerEventAtom() {
70 return XInternAtom(gfx::GetXDisplay(), "marker_event", False);
73 // Returns true when the event is a marker event.
74 bool Matcher(const base::NativeEvent& event) {
75 return event->xany.type == ClientMessage &&
76 event->xclient.message_type == MarkerEventAtom();
79 class UIControlsX11 : public UIControlsAura {
80 public:
81 UIControlsX11(WindowTreeHost* host) : host_(host) {
84 virtual bool SendKeyPress(gfx::NativeWindow window,
85 ui::KeyboardCode key,
86 bool control,
87 bool shift,
88 bool alt,
89 bool command) OVERRIDE {
90 DCHECK(!command); // No command key on Aura
91 return SendKeyPressNotifyWhenDone(
92 window, key, control, shift, alt, command, base::Closure());
94 virtual bool SendKeyPressNotifyWhenDone(
95 gfx::NativeWindow window,
96 ui::KeyboardCode key,
97 bool control,
98 bool shift,
99 bool alt,
100 bool command,
101 const base::Closure& closure) OVERRIDE {
102 DCHECK(!command); // No command key on Aura
103 XEvent xevent = {0};
104 xevent.xkey.type = KeyPress;
105 if (control)
106 SetKeycodeAndSendThenMask(&xevent, XK_Control_L, ControlMask);
107 if (shift)
108 SetKeycodeAndSendThenMask(&xevent, XK_Shift_L, ShiftMask);
109 if (alt)
110 SetKeycodeAndSendThenMask(&xevent, XK_Alt_L, Mod1Mask);
111 xevent.xkey.keycode =
112 XKeysymToKeycode(gfx::GetXDisplay(),
113 ui::XKeysymForWindowsKeyCode(key, shift));
114 host_->PostNativeEvent(&xevent);
116 // Send key release events.
117 xevent.xkey.type = KeyRelease;
118 host_->PostNativeEvent(&xevent);
119 if (alt)
120 UnmaskAndSetKeycodeThenSend(&xevent, Mod1Mask, XK_Alt_L);
121 if (shift)
122 UnmaskAndSetKeycodeThenSend(&xevent, ShiftMask, XK_Shift_L);
123 if (control)
124 UnmaskAndSetKeycodeThenSend(&xevent, ControlMask, XK_Control_L);
125 DCHECK(!xevent.xkey.state);
126 RunClosureAfterAllPendingUIEvents(closure);
127 return true;
130 virtual bool SendMouseMove(long screen_x, long screen_y) OVERRIDE {
131 return SendMouseMoveNotifyWhenDone(screen_x, screen_y, base::Closure());
133 virtual bool SendMouseMoveNotifyWhenDone(
134 long screen_x,
135 long screen_y,
136 const base::Closure& closure) OVERRIDE {
137 gfx::Point root_location(screen_x, screen_y);
138 aura::client::ScreenPositionClient* screen_position_client =
139 aura::client::GetScreenPositionClient(host_->window());
140 if (screen_position_client) {
141 screen_position_client->ConvertPointFromScreen(host_->window(),
142 &root_location);
144 gfx::Point root_current_location;
145 host_->QueryMouseLocation(&root_current_location);
146 host_->ConvertPointFromHost(&root_current_location);
148 if (root_location != root_current_location && button_down_mask == 0) {
149 // Move the cursor because EnterNotify/LeaveNotify are generated with the
150 // current mouse position as a result of XGrabPointer()
151 host_->window()->MoveCursorTo(root_location);
152 } else {
153 XEvent xevent = {0};
154 XMotionEvent* xmotion = &xevent.xmotion;
155 xmotion->type = MotionNotify;
156 xmotion->x = root_location.x();
157 xmotion->y = root_location.y();
158 xmotion->state = button_down_mask;
159 xmotion->same_screen = True;
160 // WindowTreeHost will take care of other necessary fields.
161 host_->PostNativeEvent(&xevent);
163 RunClosureAfterAllPendingUIEvents(closure);
164 return true;
166 virtual bool SendMouseEvents(MouseButton type, int state) OVERRIDE {
167 return SendMouseEventsNotifyWhenDone(type, state, base::Closure());
169 virtual bool SendMouseEventsNotifyWhenDone(
170 MouseButton type,
171 int state,
172 const base::Closure& closure) OVERRIDE {
173 XEvent xevent = {0};
174 XButtonEvent* xbutton = &xevent.xbutton;
175 gfx::Point mouse_loc = aura::Env::GetInstance()->last_mouse_location();
176 aura::client::ScreenPositionClient* screen_position_client =
177 aura::client::GetScreenPositionClient(host_->window());
178 if (screen_position_client) {
179 screen_position_client->ConvertPointFromScreen(host_->window(),
180 &mouse_loc);
182 xbutton->x = mouse_loc.x();
183 xbutton->y = mouse_loc.y();
184 xbutton->same_screen = True;
185 switch (type) {
186 case LEFT:
187 xbutton->button = Button1;
188 xbutton->state = Button1Mask;
189 break;
190 case MIDDLE:
191 xbutton->button = Button2;
192 xbutton->state = Button2Mask;
193 break;
194 case RIGHT:
195 xbutton->button = Button3;
196 xbutton->state = Button3Mask;
197 break;
199 // WindowEventDispatcher will take care of other necessary fields.
200 if (state & DOWN) {
201 xevent.xbutton.type = ButtonPress;
202 host_->PostNativeEvent(&xevent);
203 button_down_mask |= xbutton->state;
205 if (state & UP) {
206 xevent.xbutton.type = ButtonRelease;
207 host_->PostNativeEvent(&xevent);
208 button_down_mask = (button_down_mask | xbutton->state) ^ xbutton->state;
210 RunClosureAfterAllPendingUIEvents(closure);
211 return true;
213 virtual bool SendMouseClick(MouseButton type) OVERRIDE {
214 return SendMouseEvents(type, UP | DOWN);
216 virtual void RunClosureAfterAllPendingUIEvents(
217 const base::Closure& closure) OVERRIDE {
218 if (closure.is_null())
219 return;
220 static XEvent* marker_event = NULL;
221 if (!marker_event) {
222 marker_event = new XEvent();
223 marker_event->xclient.type = ClientMessage;
224 marker_event->xclient.display = NULL;
225 marker_event->xclient.window = None;
226 marker_event->xclient.format = 8;
228 marker_event->xclient.message_type = MarkerEventAtom();
229 host_->PostNativeEvent(marker_event);
230 new EventWaiter(closure, &Matcher);
232 private:
233 void SetKeycodeAndSendThenMask(XEvent* xevent,
234 KeySym keysym,
235 unsigned int mask) {
236 xevent->xkey.keycode =
237 XKeysymToKeycode(gfx::GetXDisplay(), keysym);
238 host_->PostNativeEvent(xevent);
239 xevent->xkey.state |= mask;
242 void UnmaskAndSetKeycodeThenSend(XEvent* xevent,
243 unsigned int mask,
244 KeySym keysym) {
245 xevent->xkey.state ^= mask;
246 xevent->xkey.keycode =
247 XKeysymToKeycode(gfx::GetXDisplay(), keysym);
248 host_->PostNativeEvent(xevent);
251 WindowTreeHost* host_;
253 DISALLOW_COPY_AND_ASSIGN(UIControlsX11);
256 } // namespace
258 UIControlsAura* CreateUIControlsAura(WindowTreeHost* host) {
259 return new UIControlsX11(host);
262 } // namespace test
263 } // namespace aura