Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(598)

Side by Side Diff: base/message_pump_aurax11.cc

Issue 16897006: Move message_pump to base/message_loop. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « base/message_pump_aurax11.h ('k') | base/message_pump_default.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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_pump_aurax11.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.h"
14
15 namespace {
16
17 gboolean XSourcePrepare(GSource* source, gint* timeout_ms) {
18 if (XPending(base::MessagePumpAuraX11::GetDefaultXDisplay()))
19 *timeout_ms = 0;
20 else
21 *timeout_ms = -1;
22 return FALSE;
23 }
24
25 gboolean XSourceCheck(GSource* source) {
26 return XPending(base::MessagePumpAuraX11::GetDefaultXDisplay());
27 }
28
29 gboolean XSourceDispatch(GSource* source,
30 GSourceFunc unused_func,
31 gpointer data) {
32 base::MessagePumpAuraX11* pump = static_cast<base::MessagePumpAuraX11*>(data);
33 return pump->DispatchXEvents();
34 }
35
36 GSourceFuncs XSourceFuncs = {
37 XSourcePrepare,
38 XSourceCheck,
39 XSourceDispatch,
40 NULL
41 };
42
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.
48 //
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;
53
54 bool InitializeXInput2Internal() {
55 Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
56 if (!display)
57 return false;
58
59 int event, err;
60
61 int xiopcode;
62 if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) {
63 DVLOG(1) << "X Input extension not available.";
64 return false;
65 }
66 g_xinput_opcode = xiopcode;
67
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;
71 #else
72 int major = 2, minor = 0;
73 #endif
74 if (XIQueryVersion(display, &major, &minor) == BadRequest) {
75 DVLOG(1) << "XInput2 not supported in the server.";
76 return false;
77 }
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.";
82 return false;
83 }
84 #endif
85
86 return true;
87 }
88
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;
94 }
95 return target;
96 }
97
98 bool InitializeXInput2() {
99 static bool xinput2_supported = InitializeXInput2Internal();
100 return xinput2_supported;
101 }
102
103 bool InitializeXkb() {
104 Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay();
105 if (!display)
106 return false;
107
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.";
113 return false;
114 }
115
116 // Ask the server not to send KeyRelease event when the user holds down a key.
117 // crbug.com/138092
118 Bool supported_return;
119 if (!XkbSetDetectableAutoRepeat(display, True, &supported_return)) {
120 DVLOG(1) << "XKB not supported in the server.";
121 return false;
122 }
123
124 return true;
125 }
126
127 } // namespace
128
129 namespace base {
130
131 MessagePumpAuraX11::MessagePumpAuraX11() : 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 // static
143 Display* MessagePumpAuraX11::GetDefaultXDisplay() {
144 if (!g_xdisplay)
145 g_xdisplay = XOpenDisplay(NULL);
146 return g_xdisplay;
147 }
148
149 // static
150 bool MessagePumpAuraX11::HasXInput2() {
151 return InitializeXInput2();
152 }
153
154 // static
155 MessagePumpAuraX11* MessagePumpAuraX11::Current() {
156 MessageLoopForUI* loop = MessageLoopForUI::current();
157 return static_cast<MessagePumpAuraX11*>(loop->pump_ui());
158 }
159
160 void MessagePumpAuraX11::AddDispatcherForWindow(
161 MessagePumpDispatcher* dispatcher,
162 unsigned long xid) {
163 dispatchers_.insert(std::make_pair(xid, dispatcher));
164 }
165
166 void MessagePumpAuraX11::RemoveDispatcherForWindow(unsigned long xid) {
167 dispatchers_.erase(xid);
168 }
169
170 void MessagePumpAuraX11::AddDispatcherForRootWindow(
171 MessagePumpDispatcher* dispatcher) {
172 root_window_dispatchers_.AddObserver(dispatcher);
173 }
174
175 void MessagePumpAuraX11::RemoveDispatcherForRootWindow(
176 MessagePumpDispatcher* dispatcher) {
177 root_window_dispatchers_.RemoveObserver(dispatcher);
178 }
179
180 bool MessagePumpAuraX11::DispatchXEvents() {
181 Display* display = GetDefaultXDisplay();
182 DCHECK(display);
183 MessagePumpDispatcher* dispatcher =
184 GetDispatcher() ? GetDispatcher() : this;
185
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)) {
189 XEvent xev;
190 XNextEvent(display, &xev);
191 if (dispatcher && ProcessXEvent(dispatcher, &xev))
192 return TRUE;
193 }
194 return TRUE;
195 }
196
197 void MessagePumpAuraX11::BlockUntilWindowMapped(unsigned long xid) {
198 XEvent event;
199
200 Display* display = GetDefaultXDisplay();
201 DCHECK(display);
202
203 MessagePumpDispatcher* dispatcher =
204 GetDispatcher() ? GetDispatcher() : this;
205
206 do {
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);
212 }
213
214 MessagePumpAuraX11::~MessagePumpAuraX11() {
215 g_source_destroy(x_source_);
216 g_source_unref(x_source_);
217 XCloseDisplay(g_xdisplay);
218 g_xdisplay = NULL;
219 }
220
221 void MessagePumpAuraX11::InitXSource() {
222 // CHECKs are to help track down crbug.com/113106.
223 CHECK(!x_source_);
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;
230
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());
236 }
237
238 bool MessagePumpAuraX11::ProcessXEvent(MessagePumpDispatcher* dispatcher,
239 XEvent* xev) {
240 bool should_quit = false;
241
242 bool have_cookie = false;
243 if (xev->type == GenericEvent &&
244 XGetEventData(xev->xgeneric.display, &xev->xcookie)) {
245 have_cookie = true;
246 }
247
248 if (!WillProcessXEvent(xev)) {
249 if (!dispatcher->Dispatch(xev)) {
250 should_quit = true;
251 Quit();
252 }
253 DidProcessXEvent(xev);
254 }
255
256 if (have_cookie) {
257 XFreeEventData(xev->xgeneric.display, &xev->xcookie);
258 }
259
260 return should_quit;
261 }
262
263 bool MessagePumpAuraX11::WillProcessXEvent(XEvent* xevent) {
264 if (!observers().might_have_observers())
265 return false;
266 ObserverListBase<MessagePumpObserver>::Iterator it(observers());
267 MessagePumpObserver* obs;
268 while ((obs = it.GetNext()) != NULL) {
269 if (obs->WillProcessEvent(xevent))
270 return true;
271 }
272 return false;
273 }
274
275 void MessagePumpAuraX11::DidProcessXEvent(XEvent* xevent) {
276 FOR_EACH_OBSERVER(MessagePumpObserver, observers(), DidProcessEvent(xevent));
277 }
278
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;
284 }
285
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
289 // dispatchers.
290 if (xev->type == MappingNotify) {
291 for (DispatchersMap::const_iterator it = dispatchers_.begin();
292 it != dispatchers_.end(); ++it) {
293 it->second->Dispatch(xev);
294 }
295 return true;
296 }
297
298 if (FindEventTarget(xev) == x_root_window_) {
299 FOR_EACH_OBSERVER(MessagePumpDispatcher, root_window_dispatchers_,
300 Dispatch(xev));
301 return true;
302 }
303 MessagePumpDispatcher* dispatcher = GetDispatcherForXEvent(xev);
304 return dispatcher ? dispatcher->Dispatch(xev) : true;
305 }
306
307 } // namespace base
OLDNEW
« no previous file with comments | « base/message_pump_aurax11.h ('k') | base/message_pump_default.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698