Don't switch browser locale on secondary user login
[chromium-blink-merge.git] / base / message_loop / message_pump_x11.cc
blobdd8b965e69568b3710211e045ec834e4db86e70f
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_loop/message_pump_x11.h"
7 #include <glib.h>
8 #include <X11/X.h>
9 #include <X11/extensions/XInput2.h>
10 #include <X11/XKBlib.h>
12 #include "base/basictypes.h"
13 #include "base/message_loop/message_loop.h"
15 namespace base {
17 namespace {
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;
27 gboolean XSourceCheck(GSource* source) {
28 return XPending(MessagePumpX11::GetDefaultXDisplay());
31 gboolean XSourceDispatch(GSource* source,
32 GSourceFunc unused_func,
33 gpointer data) {
34 MessagePumpX11* pump = static_cast<MessagePumpX11*>(data);
35 return pump->DispatchXEvents();
38 GSourceFuncs XSourceFuncs = {
39 XSourcePrepare,
40 XSourceCheck,
41 XSourceDispatch,
42 NULL
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.
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;
56 bool InitializeXInput2Internal() {
57 Display* display = MessagePumpX11::GetDefaultXDisplay();
58 if (!display)
59 return false;
61 int event, err;
63 int xiopcode;
64 if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) {
65 DVLOG(1) << "X Input extension not available.";
66 return false;
68 g_xinput_opcode = xiopcode;
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;
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;
86 #endif
88 return true;
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;
97 return target;
100 bool InitializeXInput2() {
101 static bool xinput2_supported = InitializeXInput2Internal();
102 return xinput2_supported;
105 bool InitializeXkb() {
106 Display* display = MessagePumpX11::GetDefaultXDisplay();
107 if (!display)
108 return false;
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;
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;
126 return true;
129 } // namespace
131 MessagePumpX11::MessagePumpX11() : MessagePumpGlib(),
132 x_source_(NULL) {
133 InitializeXInput2();
134 InitializeXkb();
135 InitXSource();
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);
142 MessagePumpX11::~MessagePumpX11() {
143 g_source_destroy(x_source_);
144 g_source_unref(x_source_);
145 XCloseDisplay(g_xdisplay);
146 g_xdisplay = NULL;
149 // static
150 Display* MessagePumpX11::GetDefaultXDisplay() {
151 if (!g_xdisplay)
152 g_xdisplay = XOpenDisplay(NULL);
153 return g_xdisplay;
156 // static
157 bool MessagePumpX11::HasXInput2() {
158 return InitializeXInput2();
161 #if defined(TOOLKIT_GTK)
162 // static
163 MessagePumpX11* MessagePumpX11::Current() {
164 MessageLoop* loop = MessageLoop::current();
165 return static_cast<MessagePumpX11*>(loop->pump_gpu());
167 #else
168 // static
169 MessagePumpX11* MessagePumpX11::Current() {
170 MessageLoopForUI* loop = MessageLoopForUI::current();
171 return static_cast<MessagePumpX11*>(loop->pump_ui());
173 #endif
175 void MessagePumpX11::AddDispatcherForWindow(
176 MessagePumpDispatcher* dispatcher,
177 unsigned long xid) {
178 dispatchers_.insert(std::make_pair(xid, dispatcher));
181 void MessagePumpX11::RemoveDispatcherForWindow(unsigned long xid) {
182 dispatchers_.erase(xid);
185 void MessagePumpX11::AddDispatcherForRootWindow(
186 MessagePumpDispatcher* dispatcher) {
187 root_window_dispatchers_.AddObserver(dispatcher);
190 void MessagePumpX11::RemoveDispatcherForRootWindow(
191 MessagePumpDispatcher* dispatcher) {
192 root_window_dispatchers_.RemoveObserver(dispatcher);
195 void MessagePumpX11::AddObserver(MessagePumpObserver* observer) {
196 observers_.AddObserver(observer);
199 void MessagePumpX11::RemoveObserver(MessagePumpObserver* observer) {
200 observers_.RemoveObserver(observer);
203 bool MessagePumpX11::DispatchXEvents() {
204 Display* display = GetDefaultXDisplay();
205 DCHECK(display);
206 MessagePumpDispatcher* dispatcher =
207 GetDispatcher() ? GetDispatcher() : this;
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;
217 return TRUE;
220 void MessagePumpX11::BlockUntilWindowMapped(unsigned long xid) {
221 XEvent event;
223 Display* display = GetDefaultXDisplay();
224 DCHECK(display);
226 MessagePumpDispatcher* dispatcher =
227 GetDispatcher() ? GetDispatcher() : this;
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);
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;
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());
254 bool MessagePumpX11::ProcessXEvent(MessagePumpDispatcher* dispatcher,
255 XEvent* xev) {
256 bool should_quit = false;
258 bool have_cookie = false;
259 if (xev->type == GenericEvent &&
260 XGetEventData(xev->xgeneric.display, &xev->xcookie)) {
261 have_cookie = true;
264 if (!WillProcessXEvent(xev)) {
265 if (!dispatcher->Dispatch(xev)) {
266 should_quit = true;
267 Quit();
269 DidProcessXEvent(xev);
272 if (have_cookie) {
273 XFreeEventData(xev->xgeneric.display, &xev->xcookie);
276 return should_quit;
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;
288 return false;
291 void MessagePumpX11::DidProcessXEvent(XEvent* xevent) {
292 FOR_EACH_OBSERVER(MessagePumpObserver, observers(), DidProcessEvent(xevent));
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;
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);
311 return true;
314 if (FindEventTarget(xev) == x_root_window_) {
315 FOR_EACH_OBSERVER(MessagePumpDispatcher, root_window_dispatchers_,
316 Dispatch(xev));
317 return true;
319 MessagePumpDispatcher* dispatcher = GetDispatcherForXEvent(xev);
320 return dispatcher ? dispatcher->Dispatch(xev) : true;
323 } // namespace base