Define DevTools content API
[chromium-blink-merge.git] / base / message_pump_x.cc
blob3b1ed3da1f58dab6517656fe06fc9ed8eb0fe1f8
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"
12 namespace {
14 gboolean XSourcePrepare(GSource* source, gint* timeout_ms) {
15 if (XPending(base::MessagePumpX::GetDefaultXDisplay()))
16 *timeout_ms = 0;
17 else
18 *timeout_ms = -1;
19 return FALSE;
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.)
32 return TRUE;
35 GSourceFuncs XSourceFuncs = {
36 XSourcePrepare,
37 XSourceCheck,
38 XSourceDispatch,
39 NULL
42 // The opcode used for checking events.
43 int xiopcode = -1;
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
49 // is specified.
50 base::MessagePumpDispatcher* g_default_dispatcher = NULL;
52 void InitializeXInput2(void) {
53 Display* display = base::MessagePumpX::GetDefaultXDisplay();
54 if (!display)
55 return;
57 int event, err;
59 if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) {
60 DVLOG(1) << "X Input extension not available.";
61 xiopcode = -1;
62 return;
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;
68 #else
69 int major = 2, minor = 0;
70 #endif
71 if (XIQueryVersion(display, &major, &minor) == BadRequest) {
72 DVLOG(1) << "XInput2 not supported in the server.";
73 xiopcode = -1;
74 return;
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.";
80 xiopcode = -1;
81 return;
83 #endif
86 } // namespace
88 namespace base {
90 MessagePumpX::MessagePumpX() : MessagePumpGlib(),
91 x_source_(NULL) {
92 InitializeXInput2();
93 InitXSource();
96 MessagePumpX::~MessagePumpX() {
97 g_source_destroy(x_source_);
98 g_source_unref(x_source_);
99 XCloseDisplay(g_xdisplay);
100 g_xdisplay = NULL;
103 // static
104 Display* MessagePumpX::GetDefaultXDisplay() {
105 if (!g_xdisplay)
106 g_xdisplay = XOpenDisplay(NULL);
107 return g_xdisplay;
110 // static
111 bool MessagePumpX::HasXInput2() {
112 return xiopcode != -1;
115 // static
116 void MessagePumpX::SetDefaultDispatcher(MessagePumpDispatcher* dispatcher) {
117 DCHECK(!g_default_dispatcher || !dispatcher);
118 g_default_dispatcher = dispatcher;
121 void MessagePumpX::InitXSource() {
122 DCHECK(!x_source_);
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,
136 XEvent* xev) {
137 bool should_quit = false;
139 bool have_cookie = false;
140 if (xev->type == GenericEvent &&
141 XGetEventData(xev->xgeneric.display, &xev->xcookie)) {
142 have_cookie = true;
145 if (WillProcessXEvent(xev) == EVENT_CONTINUE) {
146 MessagePumpDispatcher::DispatchStatus status =
147 dispatcher->Dispatch(xev);
149 if (status == MessagePumpDispatcher::EVENT_QUIT) {
150 should_quit = true;
151 Quit();
152 } else if (status == MessagePumpDispatcher::EVENT_IGNORED) {
153 DVLOG(1) << "Event (" << xev->type << ") not handled.";
155 DidProcessXEvent(xev);
158 if (have_cookie) {
159 XFreeEventData(xev->xgeneric.display, &xev->xcookie);
162 return should_quit;
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)) {
176 XEvent xev;
177 XNextEvent(display, &xev);
178 if (ProcessXEvent(dispatcher, &xev))
179 return true;
182 return g_main_context_iteration(context, block);
185 bool MessagePumpX::WillProcessXEvent(XEvent* xevent) {
186 ObserverListBase<MessagePumpObserver>::Iterator it(observers());
187 MessagePumpObserver* obs;
188 while ((obs = it.GetNext()) != NULL) {
189 if (obs->WillProcessEvent(xevent))
190 return true;
192 return false;
195 void MessagePumpX::DidProcessXEvent(XEvent* xevent) {
196 ObserverListBase<MessagePumpObserver>::Iterator it(observers());
197 MessagePumpObserver* obs;
198 while ((obs = it.GetNext()) != NULL) {
199 obs->DidProcessEvent(xevent);
203 } // namespace base