- add sources.
[platform/framework/web/crosswalk.git] / src / base / message_loop / message_pump_x11.cc
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.
4
5 #include "base/message_loop/message_pump_x11.h"
6
7 #include <glib.h>
8 #include <X11/X.h>
9 #include <X11/extensions/XInput2.h>
10 #include <X11/XKBlib.h>
11
12 #include "base/basictypes.h"
13 #include "base/message_loop/message_loop.h"
14
15 namespace base {
16
17 namespace {
18
19 gboolean XSourcePrepare(GSource* source, gint* timeout_ms) {
20   if (XPending(MessagePumpX11::GetDefaultXDisplay()))
21     *timeout_ms = 0;
22   else
23     *timeout_ms = -1;
24   return FALSE;
25 }
26
27 gboolean XSourceCheck(GSource* source) {
28   return XPending(MessagePumpX11::GetDefaultXDisplay());
29 }
30
31 gboolean XSourceDispatch(GSource* source,
32                          GSourceFunc unused_func,
33                          gpointer data) {
34   MessagePumpX11* pump = static_cast<MessagePumpX11*>(data);
35   return pump->DispatchXEvents();
36 }
37
38 GSourceFuncs XSourceFuncs = {
39   XSourcePrepare,
40   XSourceCheck,
41   XSourceDispatch,
42   NULL
43 };
44
45 // The connection is essentially a global that's accessed through a static
46 // method and destroyed whenever ~MessagePumpX11() is called. We do this
47 // for historical reasons so user code can call
48 // MessagePumpForUI::GetDefaultXDisplay() where MessagePumpForUI is a typedef
49 // to whatever type in the current build.
50 //
51 // TODO(erg): This can be changed to something more sane like
52 // MessagePumpX11::Current()->display() once MessagePumpGtk goes away.
53 Display* g_xdisplay = NULL;
54 int g_xinput_opcode = -1;
55
56 bool InitializeXInput2Internal() {
57   Display* display = MessagePumpX11::GetDefaultXDisplay();
58   if (!display)
59     return false;
60
61   int event, err;
62
63   int xiopcode;
64   if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) {
65     DVLOG(1) << "X Input extension not available.";
66     return false;
67   }
68   g_xinput_opcode = xiopcode;
69
70 #if defined(USE_XI2_MT)
71   // USE_XI2_MT also defines the required XI2 minor minimum version.
72   int major = 2, minor = USE_XI2_MT;
73 #else
74   int major = 2, minor = 0;
75 #endif
76   if (XIQueryVersion(display, &major, &minor) == BadRequest) {
77     DVLOG(1) << "XInput2 not supported in the server.";
78     return false;
79   }
80 #if defined(USE_XI2_MT)
81   if (major < 2 || (major == 2 && minor < USE_XI2_MT)) {
82     DVLOG(1) << "XI version on server is " << major << "." << minor << ". "
83             << "But 2." << USE_XI2_MT << " is required.";
84     return false;
85   }
86 #endif
87
88   return true;
89 }
90
91 Window FindEventTarget(const NativeEvent& xev) {
92   Window target = xev->xany.window;
93   if (xev->type == GenericEvent &&
94       static_cast<XIEvent*>(xev->xcookie.data)->extension == g_xinput_opcode) {
95     target = static_cast<XIDeviceEvent*>(xev->xcookie.data)->event;
96   }
97   return target;
98 }
99
100 bool InitializeXInput2() {
101   static bool xinput2_supported = InitializeXInput2Internal();
102   return xinput2_supported;
103 }
104
105 bool InitializeXkb() {
106   Display* display = MessagePumpX11::GetDefaultXDisplay();
107   if (!display)
108     return false;
109
110   int opcode, event, error;
111   int major = XkbMajorVersion;
112   int minor = XkbMinorVersion;
113   if (!XkbQueryExtension(display, &opcode, &event, &error, &major, &minor)) {
114     DVLOG(1) << "Xkb extension not available.";
115     return false;
116   }
117
118   // Ask the server not to send KeyRelease event when the user holds down a key.
119   // crbug.com/138092
120   Bool supported_return;
121   if (!XkbSetDetectableAutoRepeat(display, True, &supported_return)) {
122     DVLOG(1) << "XKB not supported in the server.";
123     return false;
124   }
125
126   return true;
127 }
128
129 }  // namespace
130
131 MessagePumpX11::MessagePumpX11() : MessagePumpGlib(),
132     x_source_(NULL) {
133   InitializeXInput2();
134   InitializeXkb();
135   InitXSource();
136
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);
140 }
141
142 MessagePumpX11::~MessagePumpX11() {
143   g_source_destroy(x_source_);
144   g_source_unref(x_source_);
145   XCloseDisplay(g_xdisplay);
146   g_xdisplay = NULL;
147 }
148
149 // static
150 Display* MessagePumpX11::GetDefaultXDisplay() {
151   if (!g_xdisplay)
152     g_xdisplay = XOpenDisplay(NULL);
153   return g_xdisplay;
154 }
155
156 // static
157 bool MessagePumpX11::HasXInput2() {
158   return InitializeXInput2();
159 }
160
161 #if defined(TOOLKIT_GTK)
162 // static
163 MessagePumpX11* MessagePumpX11::Current() {
164   MessageLoop* loop = MessageLoop::current();
165   return static_cast<MessagePumpX11*>(loop->pump_gpu());
166 }
167 #else
168 // static
169 MessagePumpX11* MessagePumpX11::Current() {
170   MessageLoopForUI* loop = MessageLoopForUI::current();
171   return static_cast<MessagePumpX11*>(loop->pump_ui());
172 }
173 #endif
174
175 void MessagePumpX11::AddDispatcherForWindow(
176     MessagePumpDispatcher* dispatcher,
177     unsigned long xid) {
178   dispatchers_.insert(std::make_pair(xid, dispatcher));
179 }
180
181 void MessagePumpX11::RemoveDispatcherForWindow(unsigned long xid) {
182   dispatchers_.erase(xid);
183 }
184
185 void MessagePumpX11::AddDispatcherForRootWindow(
186     MessagePumpDispatcher* dispatcher) {
187   root_window_dispatchers_.AddObserver(dispatcher);
188 }
189
190 void MessagePumpX11::RemoveDispatcherForRootWindow(
191     MessagePumpDispatcher* dispatcher) {
192   root_window_dispatchers_.RemoveObserver(dispatcher);
193 }
194
195 void MessagePumpX11::AddObserver(MessagePumpObserver* observer) {
196   observers_.AddObserver(observer);
197 }
198
199 void MessagePumpX11::RemoveObserver(MessagePumpObserver* observer) {
200   observers_.RemoveObserver(observer);
201 }
202
203 bool MessagePumpX11::DispatchXEvents() {
204   Display* display = GetDefaultXDisplay();
205   DCHECK(display);
206   MessagePumpDispatcher* dispatcher =
207       GetDispatcher() ? GetDispatcher() : this;
208
209   // In the general case, we want to handle all pending events before running
210   // the tasks. This is what happens in the message_pump_glib case.
211   while (XPending(display)) {
212     XEvent xev;
213     XNextEvent(display, &xev);
214     if (dispatcher && ProcessXEvent(dispatcher, &xev))
215       return TRUE;
216   }
217   return TRUE;
218 }
219
220 void MessagePumpX11::BlockUntilWindowMapped(unsigned long xid) {
221   XEvent event;
222
223   Display* display = GetDefaultXDisplay();
224   DCHECK(display);
225
226   MessagePumpDispatcher* dispatcher =
227       GetDispatcher() ? GetDispatcher() : this;
228
229   do {
230     // Block until there's a message of |event_mask| type on |w|. Then remove
231     // it from the queue and stuff it in |event|.
232     XWindowEvent(display, xid, StructureNotifyMask, &event);
233     ProcessXEvent(dispatcher, &event);
234   } while (event.type != MapNotify);
235 }
236
237 void MessagePumpX11::InitXSource() {
238   // CHECKs are to help track down crbug.com/113106.
239   CHECK(!x_source_);
240   Display* display = GetDefaultXDisplay();
241   CHECK(display) << "Unable to get connection to X server";
242   x_poll_.reset(new GPollFD());
243   CHECK(x_poll_.get());
244   x_poll_->fd = ConnectionNumber(display);
245   x_poll_->events = G_IO_IN;
246
247   x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource));
248   g_source_add_poll(x_source_, x_poll_.get());
249   g_source_set_can_recurse(x_source_, TRUE);
250   g_source_set_callback(x_source_, NULL, this, NULL);
251   g_source_attach(x_source_, g_main_context_default());
252 }
253
254 bool MessagePumpX11::ProcessXEvent(MessagePumpDispatcher* dispatcher,
255                                        XEvent* xev) {
256   bool should_quit = false;
257
258   bool have_cookie = false;
259   if (xev->type == GenericEvent &&
260       XGetEventData(xev->xgeneric.display, &xev->xcookie)) {
261     have_cookie = true;
262   }
263
264   if (!WillProcessXEvent(xev)) {
265     if (!dispatcher->Dispatch(xev)) {
266       should_quit = true;
267       Quit();
268     }
269     DidProcessXEvent(xev);
270   }
271
272   if (have_cookie) {
273     XFreeEventData(xev->xgeneric.display, &xev->xcookie);
274   }
275
276   return should_quit;
277 }
278
279 bool MessagePumpX11::WillProcessXEvent(XEvent* xevent) {
280   if (!observers().might_have_observers())
281     return false;
282   ObserverListBase<MessagePumpObserver>::Iterator it(observers());
283   MessagePumpObserver* obs;
284   while ((obs = it.GetNext()) != NULL) {
285     if (obs->WillProcessEvent(xevent))
286       return true;
287   }
288   return false;
289 }
290
291 void MessagePumpX11::DidProcessXEvent(XEvent* xevent) {
292   FOR_EACH_OBSERVER(MessagePumpObserver, observers(), DidProcessEvent(xevent));
293 }
294
295 MessagePumpDispatcher* MessagePumpX11::GetDispatcherForXEvent(
296     const NativeEvent& xev) const {
297   ::Window x_window = FindEventTarget(xev);
298   DispatchersMap::const_iterator it = dispatchers_.find(x_window);
299   return it != dispatchers_.end() ? it->second : NULL;
300 }
301
302 bool MessagePumpX11::Dispatch(const NativeEvent& xev) {
303   // MappingNotify events (meaning that the keyboard or pointer buttons have
304   // been remapped) aren't associated with a window; send them to all
305   // dispatchers.
306   if (xev->type == MappingNotify) {
307     for (DispatchersMap::const_iterator it = dispatchers_.begin();
308          it != dispatchers_.end(); ++it) {
309       it->second->Dispatch(xev);
310     }
311     return true;
312   }
313
314   if (FindEventTarget(xev) == x_root_window_) {
315     FOR_EACH_OBSERVER(MessagePumpDispatcher, root_window_dispatchers_,
316                       Dispatch(xev));
317     return true;
318   }
319   MessagePumpDispatcher* dispatcher = GetDispatcherForXEvent(xev);
320   return dispatcher ? dispatcher->Dispatch(xev) : true;
321 }
322
323 }  // namespace base