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>
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"
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
36 // TODO(oshima): Move this to base.
37 class EventWaiter
: public base::MessageLoopForUI::Observer
{
39 typedef bool (*EventWaiterMatcher
)(const base::NativeEvent
& event
);
41 EventWaiter(const base::Closure
& closure
, EventWaiterMatcher 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_
);
59 virtual void DidProcessEvent(const base::NativeEvent
& event
) OVERRIDE
{
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
{
81 UIControlsX11(WindowTreeHost
* host
) : host_(host
) {
84 virtual bool SendKeyPress(gfx::NativeWindow window
,
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
,
101 const base::Closure
& closure
) OVERRIDE
{
102 DCHECK(!command
); // No command key on Aura
104 xevent
.xkey
.type
= KeyPress
;
106 SetKeycodeAndSendThenMask(&xevent
, XK_Control_L
, ControlMask
);
108 SetKeycodeAndSendThenMask(&xevent
, XK_Shift_L
, ShiftMask
);
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
);
120 UnmaskAndSetKeycodeThenSend(&xevent
, Mod1Mask
, XK_Alt_L
);
122 UnmaskAndSetKeycodeThenSend(&xevent
, ShiftMask
, XK_Shift_L
);
124 UnmaskAndSetKeycodeThenSend(&xevent
, ControlMask
, XK_Control_L
);
125 DCHECK(!xevent
.xkey
.state
);
126 RunClosureAfterAllPendingUIEvents(closure
);
130 virtual bool SendMouseMove(long screen_x
, long screen_y
) OVERRIDE
{
131 return SendMouseMoveNotifyWhenDone(screen_x
, screen_y
, base::Closure());
133 virtual bool SendMouseMoveNotifyWhenDone(
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(),
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
);
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
);
166 virtual bool SendMouseEvents(MouseButton type
, int state
) OVERRIDE
{
167 return SendMouseEventsNotifyWhenDone(type
, state
, base::Closure());
169 virtual bool SendMouseEventsNotifyWhenDone(
172 const base::Closure
& closure
) OVERRIDE
{
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(),
182 xbutton
->x
= mouse_loc
.x();
183 xbutton
->y
= mouse_loc
.y();
184 xbutton
->same_screen
= True
;
187 xbutton
->button
= Button1
;
188 xbutton
->state
= Button1Mask
;
191 xbutton
->button
= Button2
;
192 xbutton
->state
= Button2Mask
;
195 xbutton
->button
= Button3
;
196 xbutton
->state
= Button3Mask
;
199 // WindowEventDispatcher will take care of other necessary fields.
201 xevent
.xbutton
.type
= ButtonPress
;
202 host_
->PostNativeEvent(&xevent
);
203 button_down_mask
|= xbutton
->state
;
206 xevent
.xbutton
.type
= ButtonRelease
;
207 host_
->PostNativeEvent(&xevent
);
208 button_down_mask
= (button_down_mask
| xbutton
->state
) ^ xbutton
->state
;
210 RunClosureAfterAllPendingUIEvents(closure
);
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())
220 static XEvent
* marker_event
= NULL
;
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
);
233 void SetKeycodeAndSendThenMask(XEvent
* xevent
,
236 xevent
->xkey
.keycode
=
237 XKeysymToKeycode(gfx::GetXDisplay(), keysym
);
238 host_
->PostNativeEvent(xevent
);
239 xevent
->xkey
.state
|= mask
;
242 void UnmaskAndSetKeycodeThenSend(XEvent
* xevent
,
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
);
258 UIControlsAura
* CreateUIControlsAura(WindowTreeHost
* host
) {
259 return new UIControlsX11(host
);