1 // Copyright (c) 2011 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_x.h"
7 #include <X11/extensions/XInput2.h>
9 #include "base/basictypes.h"
10 #include "base/message_loop.h"
14 gboolean
XSourcePrepare(GSource
* source
, gint
* timeout_ms
) {
15 if (XPending(base::MessagePumpX::GetDefaultXDisplay()))
22 gboolean
XSourceCheck(GSource
* source
) {
23 return XPending(base::MessagePumpX::GetDefaultXDisplay());
26 gboolean
XSourceDispatch(GSource
* source
,
27 GSourceFunc unused_func
,
28 gpointer unused_data
) {
29 // TODO(sad): When GTK event proecssing is completely removed, the event
30 // processing and dispatching should be done here (i.e. XNextEvent,
31 // ProcessXEvent etc.)
35 GSourceFuncs XSourceFuncs
= {
42 // The opcode used for checking events.
45 // The message-pump opens a connection to the display and owns it.
46 Display
* g_xdisplay
= NULL
;
48 // The default dispatcher to process native events when no dispatcher
50 base::MessagePumpDispatcher
* g_default_dispatcher
= NULL
;
52 void InitializeXInput2(void) {
53 Display
* display
= base::MessagePumpX::GetDefaultXDisplay();
59 if (!XQueryExtension(display
, "XInputExtension", &xiopcode
, &event
, &err
)) {
60 DVLOG(1) << "X Input extension not available.";
65 #if defined(USE_XI2_MT)
66 // USE_XI2_MT also defines the required XI2 minor minimum version.
67 int major
= 2, minor
= USE_XI2_MT
;
69 int major
= 2, minor
= 0;
71 if (XIQueryVersion(display
, &major
, &minor
) == BadRequest
) {
72 DVLOG(1) << "XInput2 not supported in the server.";
76 #if defined(USE_XI2_MT)
77 if (major
< 2 || (major
== 2 && minor
< USE_XI2_MT
)) {
78 DVLOG(1) << "XI version on server is " << major
<< "." << minor
<< ". "
79 << "But 2." << USE_XI2_MT
<< " is required.";
90 MessagePumpX::MessagePumpX() : MessagePumpGlib(),
96 MessagePumpX::~MessagePumpX() {
97 g_source_destroy(x_source_
);
98 g_source_unref(x_source_
);
99 XCloseDisplay(g_xdisplay
);
104 Display
* MessagePumpX::GetDefaultXDisplay() {
106 g_xdisplay
= XOpenDisplay(NULL
);
111 bool MessagePumpX::HasXInput2() {
112 return xiopcode
!= -1;
116 void MessagePumpX::SetDefaultDispatcher(MessagePumpDispatcher
* dispatcher
) {
117 DCHECK(!g_default_dispatcher
|| !dispatcher
);
118 g_default_dispatcher
= dispatcher
;
121 void MessagePumpX::InitXSource() {
123 GPollFD
* x_poll
= new GPollFD();
124 Display
* display
= GetDefaultXDisplay();
125 DCHECK(display
) << "Unable to get connection to X server";
126 x_poll
->fd
= ConnectionNumber(display
);
127 x_poll
->events
= G_IO_IN
;
129 x_source_
= g_source_new(&XSourceFuncs
, sizeof(GSource
));
130 g_source_add_poll(x_source_
, x_poll
);
131 g_source_set_can_recurse(x_source_
, FALSE
);
132 g_source_attach(x_source_
, g_main_context_default());
135 bool MessagePumpX::ProcessXEvent(MessagePumpDispatcher
* dispatcher
,
137 bool should_quit
= false;
139 bool have_cookie
= false;
140 if (xev
->type
== GenericEvent
&&
141 XGetEventData(xev
->xgeneric
.display
, &xev
->xcookie
)) {
145 if (!WillProcessXEvent(xev
)) {
146 MessagePumpDispatcher::DispatchStatus status
=
147 dispatcher
->Dispatch(xev
);
149 if (status
== MessagePumpDispatcher::EVENT_QUIT
) {
152 } else if (status
== MessagePumpDispatcher::EVENT_IGNORED
) {
153 DVLOG(1) << "Event (" << xev
->type
<< ") not handled.";
155 DidProcessXEvent(xev
);
159 XFreeEventData(xev
->xgeneric
.display
, &xev
->xcookie
);
165 bool MessagePumpX::RunOnce(GMainContext
* context
, bool block
) {
166 Display
* display
= GetDefaultXDisplay();
167 MessagePumpDispatcher
* dispatcher
=
168 GetDispatcher() ? GetDispatcher() : g_default_dispatcher
;
170 if (!display
|| !dispatcher
)
171 return g_main_context_iteration(context
, block
);
173 // In the general case, we want to handle all pending events before running
174 // the tasks. This is what happens in the message_pump_glib case.
175 while (XPending(display
)) {
177 XNextEvent(display
, &xev
);
178 if (ProcessXEvent(dispatcher
, &xev
))
182 return g_main_context_iteration(context
, block
);
185 bool MessagePumpX::WillProcessXEvent(XEvent
* xevent
) {
186 if (!observers().might_have_observers())
188 ObserverListBase
<MessagePumpObserver
>::Iterator
it(observers());
189 MessagePumpObserver
* obs
;
190 while ((obs
= it
.GetNext()) != NULL
) {
191 if (obs
->WillProcessEvent(xevent
))
197 void MessagePumpX::DidProcessXEvent(XEvent
* xevent
) {
198 FOR_EACH_OBSERVER(MessagePumpObserver
, observers(), DidProcessEvent(xevent
));