ui_controls_factory_aurax11.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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.
4
5#include <X11/keysym.h>
6#include <X11/Xlib.h>
7
8// X macro fail.
9#if defined(RootWindow)
10#undef RootWindow
11#endif
12
13#include "base/logging.h"
14#include "base/message_pump_aurax11.h"
15#include "ui/aura/client/screen_position_client.h"
16#include "ui/aura/env.h"
17#include "ui/aura/root_window.h"
18#include "ui/aura/test/ui_controls_factory_aura.h"
19#include "ui/base/keycodes/keyboard_code_conversion_x.h"
20#include "ui/base/test/ui_controls_aura.h"
21#include "ui/compositor/dip_util.h"
22
23namespace aura {
24namespace test {
25namespace {
26
27using ui_controls::DOWN;
28using ui_controls::LEFT;
29using ui_controls::MIDDLE;
30using ui_controls::MouseButton;
31using ui_controls::RIGHT;
32using ui_controls::UIControlsAura;
33using ui_controls::UP;
34
35// Mask of the buttons currently down.
36unsigned button_down_mask = 0;
37
38// Event waiter executes the specified closure|when a matching event
39// is found.
40// TODO(oshima): Move this to base.
41class EventWaiter : public base::MessageLoopForUI::Observer {
42 public:
43  typedef bool (*EventWaiterMatcher)(const base::NativeEvent& event);
44
45  EventWaiter(const base::Closure& closure, EventWaiterMatcher matcher)
46      : closure_(closure),
47        matcher_(matcher) {
48    base::MessageLoopForUI::current()->AddObserver(this);
49  }
50
51  virtual ~EventWaiter() {
52    base::MessageLoopForUI::current()->RemoveObserver(this);
53  }
54
55  // MessageLoop::Observer implementation:
56  virtual base::EventStatus WillProcessEvent(
57      const base::NativeEvent& event) OVERRIDE {
58    if ((*matcher_)(event)) {
59      base::MessageLoop::current()->PostTask(FROM_HERE, closure_);
60      delete this;
61    }
62    return base::EVENT_CONTINUE;
63  }
64
65  virtual void DidProcessEvent(const base::NativeEvent& event) OVERRIDE {
66  }
67
68 private:
69  base::Closure closure_;
70  EventWaiterMatcher matcher_;
71  DISALLOW_COPY_AND_ASSIGN(EventWaiter);
72};
73
74// Returns atom that indidates that the XEvent is marker event.
75Atom MarkerEventAtom() {
76  return XInternAtom(base::MessagePumpAuraX11::GetDefaultXDisplay(),
77                     "marker_event",
78                     False);
79}
80
81// Returns true when the event is a marker event.
82bool Matcher(const base::NativeEvent& event) {
83  return event->xany.type == ClientMessage &&
84      event->xclient.message_type == MarkerEventAtom();
85}
86
87class UIControlsX11 : public UIControlsAura {
88 public:
89  UIControlsX11(aura::RootWindow* root_window) : root_window_(root_window) {
90  }
91
92  virtual bool SendKeyPress(gfx::NativeWindow window,
93                            ui::KeyboardCode key,
94                            bool control,
95                            bool shift,
96                            bool alt,
97                            bool command) OVERRIDE {
98    DCHECK(!command);  // No command key on Aura
99    return SendKeyPressNotifyWhenDone(
100        window, key, control, shift, alt, command, base::Closure());
101  }
102  virtual bool SendKeyPressNotifyWhenDone(
103      gfx::NativeWindow window,
104      ui::KeyboardCode key,
105      bool control,
106      bool shift,
107      bool alt,
108      bool command,
109      const base::Closure& closure) OVERRIDE {
110    DCHECK(!command);  // No command key on Aura
111    XEvent xevent = {0};
112    xevent.xkey.type = KeyPress;
113    if (control)
114      SetKeycodeAndSendThenMask(&xevent, XK_Control_L, ControlMask);
115    if (shift)
116      SetKeycodeAndSendThenMask(&xevent, XK_Shift_L, ShiftMask);
117    if (alt)
118      SetKeycodeAndSendThenMask(&xevent, XK_Alt_L, Mod1Mask);
119    xevent.xkey.keycode =
120        XKeysymToKeycode(base::MessagePumpAuraX11::GetDefaultXDisplay(),
121                         ui::XKeysymForWindowsKeyCode(key, shift));
122    root_window_->PostNativeEvent(&xevent);
123
124    // Send key release events.
125    xevent.xkey.type = KeyRelease;
126    root_window_->PostNativeEvent(&xevent);
127    if (alt)
128      UnmaskAndSetKeycodeThenSend(&xevent, Mod1Mask, XK_Alt_L);
129    if (shift)
130      UnmaskAndSetKeycodeThenSend(&xevent, ShiftMask, XK_Shift_L);
131    if (control)
132      UnmaskAndSetKeycodeThenSend(&xevent, ControlMask, XK_Control_L);
133    DCHECK(!xevent.xkey.state);
134    RunClosureAfterAllPendingUIEvents(closure);
135    return true;
136  }
137
138  // Simulate a mouse move. (x,y) are absolute screen coordinates.
139  virtual bool SendMouseMove(long x, long y) OVERRIDE {
140    return SendMouseMoveNotifyWhenDone(x, y, base::Closure());
141  }
142  virtual bool SendMouseMoveNotifyWhenDone(
143      long x,
144      long y,
145      const base::Closure& closure) OVERRIDE {
146    XEvent xevent = {0};
147    XMotionEvent* xmotion = &xevent.xmotion;
148    xmotion->type = MotionNotify;
149    gfx::Point point = ui::ConvertPointToPixel(
150        root_window_->layer(),
151        gfx::Point(static_cast<int>(x), static_cast<int>(y)));
152    xmotion->x = point.x();
153    xmotion->y = point.y();
154    xmotion->state = button_down_mask;
155    xmotion->same_screen = True;
156    // RootWindow will take care of other necessary fields.
157    root_window_->PostNativeEvent(&xevent);
158    RunClosureAfterAllPendingUIEvents(closure);
159    return true;
160  }
161  virtual bool SendMouseEvents(MouseButton type, int state) OVERRIDE {
162    return SendMouseEventsNotifyWhenDone(type, state, base::Closure());
163  }
164  virtual bool SendMouseEventsNotifyWhenDone(
165      MouseButton type,
166      int state,
167      const base::Closure& closure) OVERRIDE {
168    XEvent xevent = {0};
169    XButtonEvent* xbutton = &xevent.xbutton;
170    gfx::Point mouse_loc = aura::Env::GetInstance()->last_mouse_location();
171    aura::client::ScreenPositionClient* screen_position_client =
172          aura::client::GetScreenPositionClient(root_window_);
173    if (screen_position_client)
174      screen_position_client->ConvertPointFromScreen(root_window_, &mouse_loc);
175    xbutton->x = mouse_loc.x();
176    xbutton->y = mouse_loc.y();
177    xbutton->same_screen = True;
178    switch (type) {
179      case LEFT:
180        xbutton->button = Button1;
181        xbutton->state = Button1Mask;
182        break;
183      case MIDDLE:
184        xbutton->button = Button2;
185        xbutton->state = Button2Mask;
186        break;
187      case RIGHT:
188        xbutton->button = Button3;
189        xbutton->state = Button3Mask;
190        break;
191    }
192    // RootWindow will take care of other necessary fields.
193    if (state & DOWN) {
194      xevent.xbutton.type = ButtonPress;
195      root_window_->PostNativeEvent(&xevent);
196      button_down_mask |= xbutton->state;
197    }
198    if (state & UP) {
199      xevent.xbutton.type = ButtonRelease;
200      root_window_->PostNativeEvent(&xevent);
201      button_down_mask = (button_down_mask | xbutton->state) ^ xbutton->state;
202    }
203    RunClosureAfterAllPendingUIEvents(closure);
204    return true;
205  }
206  virtual bool SendMouseClick(MouseButton type) OVERRIDE {
207    return SendMouseEvents(type, UP | DOWN);
208  }
209  virtual void RunClosureAfterAllPendingUIEvents(
210      const base::Closure& closure) OVERRIDE {
211    if (closure.is_null())
212      return;
213    static XEvent* marker_event = NULL;
214    if (!marker_event) {
215      marker_event = new XEvent();
216      marker_event->xclient.type = ClientMessage;
217      marker_event->xclient.display = NULL;
218      marker_event->xclient.window = None;
219      marker_event->xclient.format = 8;
220    }
221    marker_event->xclient.message_type = MarkerEventAtom();
222    root_window_->PostNativeEvent(marker_event);
223    new EventWaiter(closure, &Matcher);
224  }
225 private:
226  void SetKeycodeAndSendThenMask(XEvent* xevent,
227                                 KeySym keysym,
228                                 unsigned int mask) {
229    xevent->xkey.keycode =
230        XKeysymToKeycode(base::MessagePumpAuraX11::GetDefaultXDisplay(),
231                         keysym);
232    root_window_->PostNativeEvent(xevent);
233    xevent->xkey.state |= mask;
234  }
235
236  void UnmaskAndSetKeycodeThenSend(XEvent* xevent,
237                                   unsigned int mask,
238                                   KeySym keysym) {
239    xevent->xkey.state ^= mask;
240    xevent->xkey.keycode =
241        XKeysymToKeycode(base::MessagePumpAuraX11::GetDefaultXDisplay(),
242                         keysym);
243    root_window_->PostNativeEvent(xevent);
244  }
245
246  aura::RootWindow* root_window_;
247
248  DISALLOW_COPY_AND_ASSIGN(UIControlsX11);
249};
250
251}  // namespace
252
253UIControlsAura* CreateUIControlsAura(aura::RootWindow* root_window) {
254  return new UIControlsX11(root_window);
255}
256
257}  // namespace test
258}  // namespace aura
259