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 root_window_dispatchers_
.AddObserver(dispatcher
);
175 void MessagePumpAuraX11::RemoveDispatcherForRootWindow(
176 MessagePumpDispatcher
* dispatcher
) {
177 root_window_dispatchers_
.RemoveObserver(dispatcher
);
180 bool MessagePumpAuraX11::DispatchXEvents() {
181 Display
* display
= GetDefaultXDisplay();
183 MessagePumpDispatcher
* dispatcher
=
184 GetDispatcher() ? GetDispatcher() : this;
186 // In the general case, we want to handle all pending events before running
187 // the tasks. This is what happens in the message_pump_glib case.
188 while (XPending(display
)) {
190 XNextEvent(display
, &xev
);
191 if (dispatcher
&& ProcessXEvent(dispatcher
, &xev
))
197 void MessagePumpAuraX11::BlockUntilWindowMapped(unsigned long xid
) {
200 Display
* display
= GetDefaultXDisplay();
203 MessagePumpDispatcher
* dispatcher
=
204 GetDispatcher() ? GetDispatcher() : this;
207 // Block until there's a message of |event_mask| type on |w|. Then remove
208 // it from the queue and stuff it in |event|.
209 XWindowEvent(display
, xid
, StructureNotifyMask
, &event
);
210 ProcessXEvent(dispatcher
, &event
);
211 } while (event
.type
!= MapNotify
);
214 MessagePumpAuraX11::~MessagePumpAuraX11() {
215 g_source_destroy(x_source_
);
216 g_source_unref(x_source_
);
217 XCloseDisplay(g_xdisplay
);
221 void MessagePumpAuraX11::InitXSource() {
222 // CHECKs are to help track down crbug.com/113106.
224 Display
* display
= GetDefaultXDisplay();
225 CHECK(display
) << "Unable to get connection to X server";
226 x_poll_
.reset(new GPollFD());
227 CHECK(x_poll_
.get());
228 x_poll_
->fd
= ConnectionNumber(display
);
229 x_poll_
->events
= G_IO_IN
;
231 x_source_
= g_source_new(&XSourceFuncs
, sizeof(GSource
));
232 g_source_add_poll(x_source_
, x_poll_
.get());
233 g_source_set_can_recurse(x_source_
, TRUE
);
234 g_source_set_callback(x_source_
, NULL
, this, NULL
);
235 g_source_attach(x_source_
, g_main_context_default());
238 bool MessagePumpAuraX11::ProcessXEvent(MessagePumpDispatcher
* dispatcher
,
240 bool should_quit
= false;
242 bool have_cookie
= false;
243 if (xev
->type
== GenericEvent
&&
244 XGetEventData(xev
->xgeneric
.display
, &xev
->xcookie
)) {
248 if (!WillProcessXEvent(xev
)) {
249 if (!dispatcher
->Dispatch(xev
)) {
253 DidProcessXEvent(xev
);
257 XFreeEventData(xev
->xgeneric
.display
, &xev
->xcookie
);
263 bool MessagePumpAuraX11::WillProcessXEvent(XEvent
* xevent
) {
264 if (!observers().might_have_observers())
266 ObserverListBase
<MessagePumpObserver
>::Iterator
it(observers());
267 MessagePumpObserver
* obs
;
268 while ((obs
= it
.GetNext()) != NULL
) {
269 if (obs
->WillProcessEvent(xevent
))
275 void MessagePumpAuraX11::DidProcessXEvent(XEvent
* xevent
) {
276 FOR_EACH_OBSERVER(MessagePumpObserver
, observers(), DidProcessEvent(xevent
));
279 MessagePumpDispatcher
* MessagePumpAuraX11::GetDispatcherForXEvent(
280 const base::NativeEvent
& xev
) const {
281 ::Window x_window
= FindEventTarget(xev
);
282 DispatchersMap::const_iterator it
= dispatchers_
.find(x_window
);
283 return it
!= dispatchers_
.end() ? it
->second
: NULL
;
286 bool MessagePumpAuraX11::Dispatch(const base::NativeEvent
& xev
) {
287 // MappingNotify events (meaning that the keyboard or pointer buttons have
288 // been remapped) aren't associated with a window; send them to all
290 if (xev
->type
== MappingNotify
) {
291 for (DispatchersMap::const_iterator it
= dispatchers_
.begin();
292 it
!= dispatchers_
.end(); ++it
) {
293 it
->second
->Dispatch(xev
);
298 if (FindEventTarget(xev
) == x_root_window_
) {
299 FOR_EACH_OBSERVER(MessagePumpDispatcher
, root_window_dispatchers_
,
303 MessagePumpDispatcher
* dispatcher
= GetDispatcherForXEvent(xev
);
304 return dispatcher
? dispatcher
->Dispatch(xev
) : true;