1 // Copyright (c) 2012 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 "base/message_pump_aurax11.h"
9 #include <X11/extensions/XInput2.h>
10 #include <X11/XKBlib.h>
12 #include "base/basictypes.h"
13 #include "base/message_loop.h"
17 gboolean
XSourcePrepare(GSource
* source
, gint
* timeout_ms
) {
18 if (XPending(base::MessagePumpAuraX11::GetDefaultXDisplay()))
25 gboolean
XSourceCheck(GSource
* source
) {
26 return XPending(base::MessagePumpAuraX11::GetDefaultXDisplay());
29 gboolean
XSourceDispatch(GSource
* source
,
30 GSourceFunc unused_func
,
32 base::MessagePumpAuraX11
* pump
= static_cast<base::MessagePumpAuraX11
*>(data
);
33 return pump
->DispatchXEvents();
36 GSourceFuncs XSourceFuncs
= {
43 // The connection is essentially a global that's accessed through a static
44 // method and destroyed whenever ~MessagePumpAuraX11() is called. We do this
45 // for historical reasons so user code can call
46 // MessagePumpForUI::GetDefaultXDisplay() where MessagePumpForUI is a typedef
47 // to whatever type in the current build.
49 // TODO(erg): This can be changed to something more sane like
50 // MessagePumpAuraX11::Current()->display() once MessagePumpGtk goes away.
51 Display
* g_xdisplay
= NULL
;
52 int g_xinput_opcode
= -1;
54 bool InitializeXInput2Internal() {
55 Display
* display
= base::MessagePumpAuraX11::GetDefaultXDisplay();
62 if (!XQueryExtension(display
, "XInputExtension", &xiopcode
, &event
, &err
)) {
63 DVLOG(1) << "X Input extension not available.";
66 g_xinput_opcode
= xiopcode
;
68 #if defined(USE_XI2_MT)
69 // USE_XI2_MT also defines the required XI2 minor minimum version.
70 int major
= 2, minor
= USE_XI2_MT
;
72 int major
= 2, minor
= 0;
74 if (XIQueryVersion(display
, &major
, &minor
) == BadRequest
) {
75 DVLOG(1) << "XInput2 not supported in the server.";
78 #if defined(USE_XI2_MT)
79 if (major
< 2 || (major
== 2 && minor
< USE_XI2_MT
)) {
80 DVLOG(1) << "XI version on server is " << major
<< "." << minor
<< ". "
81 << "But 2." << USE_XI2_MT
<< " is required.";
89 Window
FindEventTarget(const base::NativeEvent
& xev
) {
90 Window target
= xev
->xany
.window
;
91 if (xev
->type
== GenericEvent
&&
92 static_cast<XIEvent
*>(xev
->xcookie
.data
)->extension
== g_xinput_opcode
) {
93 target
= static_cast<XIDeviceEvent
*>(xev
->xcookie
.data
)->event
;
98 bool InitializeXInput2() {
99 static bool xinput2_supported
= InitializeXInput2Internal();
100 return xinput2_supported
;
103 bool InitializeXkb() {
104 Display
* display
= base::MessagePumpAuraX11::GetDefaultXDisplay();
108 int opcode
, event
, error
;
109 int major
= XkbMajorVersion
;
110 int minor
= XkbMinorVersion
;
111 if (!XkbQueryExtension(display
, &opcode
, &event
, &error
, &major
, &minor
)) {
112 DVLOG(1) << "Xkb extension not available.";
116 // Ask the server not to send KeyRelease event when the user holds down a key.
118 Bool supported_return
;
119 if (!XkbSetDetectableAutoRepeat(display
, True
, &supported_return
)) {
120 DVLOG(1) << "XKB not supported in the server.";
131 MessagePumpAuraX11::MessagePumpAuraX11() : MessagePumpGlib(),
137 // Can't put this in the initializer list because g_xdisplay may not exist
138 // until after InitXSource().
139 x_root_window_
= DefaultRootWindow(g_xdisplay
);
143 Display
* MessagePumpAuraX11::GetDefaultXDisplay() {
145 g_xdisplay
= XOpenDisplay(NULL
);
150 bool MessagePumpAuraX11::HasXInput2() {
151 return InitializeXInput2();
155 MessagePumpAuraX11
* MessagePumpAuraX11::Current() {
156 MessageLoopForUI
* loop
= MessageLoopForUI::current();
157 return static_cast<MessagePumpAuraX11
*>(loop
->pump_ui());
160 void MessagePumpAuraX11::AddDispatcherForWindow(
161 MessagePumpDispatcher
* dispatcher
,
163 dispatchers_
.insert(std::make_pair(xid
, dispatcher
));
166 void MessagePumpAuraX11::RemoveDispatcherForWindow(unsigned long xid
) {
167 dispatchers_
.erase(xid
);
170 void MessagePumpAuraX11::AddDispatcherForRootWindow(
171 MessagePumpDispatcher
* dispatcher
) {
172 DCHECK(std::find(root_window_dispatchers_
.begin(),
173 root_window_dispatchers_
.end(),
175 root_window_dispatchers_
.end());
176 root_window_dispatchers_
.push_back(dispatcher
);
179 void MessagePumpAuraX11::RemoveDispatcherForRootWindow(
180 MessagePumpDispatcher
* dispatcher
) {
181 root_window_dispatchers_
.erase(
182 std::remove(root_window_dispatchers_
.begin(),
183 root_window_dispatchers_
.end(),
187 bool MessagePumpAuraX11::DispatchXEvents() {
188 Display
* display
= GetDefaultXDisplay();
190 MessagePumpDispatcher
* dispatcher
=
191 GetDispatcher() ? GetDispatcher() : this;
193 // In the general case, we want to handle all pending events before running
194 // the tasks. This is what happens in the message_pump_glib case.
195 while (XPending(display
)) {
197 XNextEvent(display
, &xev
);
198 if (dispatcher
&& ProcessXEvent(dispatcher
, &xev
))
204 void MessagePumpAuraX11::BlockUntilWindowMapped(unsigned long xid
) {
207 Display
* display
= GetDefaultXDisplay();
210 MessagePumpDispatcher
* dispatcher
=
211 GetDispatcher() ? GetDispatcher() : this;
214 // Block until there's a message of |event_mask| type on |w|. Then remove
215 // it from the queue and stuff it in |event|.
216 XWindowEvent(display
, xid
, StructureNotifyMask
, &event
);
217 ProcessXEvent(dispatcher
, &event
);
218 } while (event
.type
!= MapNotify
);
221 MessagePumpAuraX11::~MessagePumpAuraX11() {
222 g_source_destroy(x_source_
);
223 g_source_unref(x_source_
);
224 XCloseDisplay(g_xdisplay
);
228 void MessagePumpAuraX11::InitXSource() {
229 // CHECKs are to help track down crbug.com/113106.
231 Display
* display
= GetDefaultXDisplay();
232 CHECK(display
) << "Unable to get connection to X server";
233 x_poll_
.reset(new GPollFD());
234 CHECK(x_poll_
.get());
235 x_poll_
->fd
= ConnectionNumber(display
);
236 x_poll_
->events
= G_IO_IN
;
238 x_source_
= g_source_new(&XSourceFuncs
, sizeof(GSource
));
239 g_source_add_poll(x_source_
, x_poll_
.get());
240 g_source_set_can_recurse(x_source_
, TRUE
);
241 g_source_set_callback(x_source_
, NULL
, this, NULL
);
242 g_source_attach(x_source_
, g_main_context_default());
245 bool MessagePumpAuraX11::ProcessXEvent(MessagePumpDispatcher
* dispatcher
,
247 bool should_quit
= false;
249 bool have_cookie
= false;
250 if (xev
->type
== GenericEvent
&&
251 XGetEventData(xev
->xgeneric
.display
, &xev
->xcookie
)) {
255 if (!WillProcessXEvent(xev
)) {
256 if (!dispatcher
->Dispatch(xev
)) {
260 DidProcessXEvent(xev
);
264 XFreeEventData(xev
->xgeneric
.display
, &xev
->xcookie
);
270 bool MessagePumpAuraX11::WillProcessXEvent(XEvent
* xevent
) {
271 if (!observers().might_have_observers())
273 ObserverListBase
<MessagePumpObserver
>::Iterator
it(observers());
274 MessagePumpObserver
* obs
;
275 while ((obs
= it
.GetNext()) != NULL
) {
276 if (obs
->WillProcessEvent(xevent
))
282 void MessagePumpAuraX11::DidProcessXEvent(XEvent
* xevent
) {
283 FOR_EACH_OBSERVER(MessagePumpObserver
, observers(), DidProcessEvent(xevent
));
286 MessagePumpDispatcher
* MessagePumpAuraX11::GetDispatcherForXEvent(
287 const base::NativeEvent
& xev
) const {
288 ::Window x_window
= FindEventTarget(xev
);
289 DispatchersMap::const_iterator it
= dispatchers_
.find(x_window
);
290 return it
!= dispatchers_
.end() ? it
->second
: NULL
;
293 bool MessagePumpAuraX11::Dispatch(const base::NativeEvent
& xev
) {
294 // MappingNotify events (meaning that the keyboard or pointer buttons have
295 // been remapped) aren't associated with a window; send them to all
297 if (xev
->type
== MappingNotify
) {
298 for (DispatchersMap::const_iterator it
= dispatchers_
.begin();
299 it
!= dispatchers_
.end(); ++it
) {
300 it
->second
->Dispatch(xev
);
305 if (FindEventTarget(xev
) == x_root_window_
) {
306 for (Dispatchers::const_iterator it
= root_window_dispatchers_
.begin();
307 it
!= root_window_dispatchers_
.end();
309 (*it
)->Dispatch(xev
);
313 MessagePumpDispatcher
* dispatcher
= GetDispatcherForXEvent(xev
);
314 return dispatcher
? dispatcher
->Dispatch(xev
) : true;