| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/message_pump_x.h" | 5 #include "base/message_pump_aurax11.h" |
| 6 | 6 |
| 7 #include <X11/extensions/XInput2.h> | 7 #include <X11/extensions/XInput2.h> |
| 8 | 8 |
| 9 #include <map> |
| 10 |
| 9 #include "base/basictypes.h" | 11 #include "base/basictypes.h" |
| 12 #include "base/lazy_instance.h" |
| 10 #include "base/message_loop.h" | 13 #include "base/message_loop.h" |
| 11 | 14 |
| 12 namespace { | 15 namespace { |
| 13 | 16 |
| 14 gboolean XSourcePrepare(GSource* source, gint* timeout_ms) { | 17 gboolean XSourcePrepare(GSource* source, gint* timeout_ms) { |
| 15 if (XPending(base::MessagePumpX::GetDefaultXDisplay())) | 18 if (XPending(base::MessagePumpAuraX11::GetDefaultXDisplay())) |
| 16 *timeout_ms = 0; | 19 *timeout_ms = 0; |
| 17 else | 20 else |
| 18 *timeout_ms = -1; | 21 *timeout_ms = -1; |
| 19 return FALSE; | 22 return FALSE; |
| 20 } | 23 } |
| 21 | 24 |
| 22 gboolean XSourceCheck(GSource* source) { | 25 gboolean XSourceCheck(GSource* source) { |
| 23 return XPending(base::MessagePumpX::GetDefaultXDisplay()); | 26 return XPending(base::MessagePumpAuraX11::GetDefaultXDisplay()); |
| 24 } | 27 } |
| 25 | 28 |
| 26 gboolean XSourceDispatch(GSource* source, | 29 gboolean XSourceDispatch(GSource* source, |
| 27 GSourceFunc unused_func, | 30 GSourceFunc unused_func, |
| 28 gpointer data) { | 31 gpointer data) { |
| 29 base::MessagePumpX* pump = static_cast<base::MessagePumpX*>(data); | 32 base::MessagePumpAuraX11* pump = static_cast<base::MessagePumpAuraX11*>(data); |
| 30 return pump->DispatchXEvents(); | 33 return pump->DispatchXEvents(); |
| 31 } | 34 } |
| 32 | 35 |
| 33 GSourceFuncs XSourceFuncs = { | 36 GSourceFuncs XSourceFuncs = { |
| 34 XSourcePrepare, | 37 XSourcePrepare, |
| 35 XSourceCheck, | 38 XSourceCheck, |
| 36 XSourceDispatch, | 39 XSourceDispatch, |
| 37 NULL | 40 NULL |
| 38 }; | 41 }; |
| 39 | 42 |
| 40 // The message-pump opens a connection to the display and owns it. | 43 // The message-pump opens a connection to the display and owns it. |
| 41 Display* g_xdisplay = NULL; | 44 Display* g_xdisplay = NULL; |
| 42 | 45 |
| 43 // The default dispatcher to process native events when no dispatcher | 46 // The default dispatcher to process native events when no dispatcher |
| 44 // is specified. | 47 // is specified. |
| 45 base::MessagePumpDispatcher* g_default_dispatcher = NULL; | 48 base::MessagePumpDispatcher* g_default_dispatcher = NULL; |
| 46 | 49 |
| 50 // A cache of Atoms tied to the lifetime of |g_xdisplay|. Cleared when |
| 51 // |g_xdisplay| is destroyed. |
| 52 typedef std::map<base::atom::Name, ::Atom> AtomMap; |
| 53 base::LazyInstance<AtomMap> g_cached_atoms = LAZY_INSTANCE_INITIALIZER; |
| 54 |
| 55 // A list of atoms that we'll intern on host creation to save roundtrips to the |
| 56 // X11 server. Must be kept in sync with base::atom::Name |
| 57 struct AtomInfo { |
| 58 base::atom::Name id; |
| 59 const char* name; |
| 60 } const kAtomList[] = { |
| 61 { base::atom::WM_DELETE_WINDOW, "WM_DELETE_WINDOW" }, |
| 62 { base::atom::_NET_WM_MOVERESIZE, "_NET_WM_MOVERESIZE" }, |
| 63 { base::atom::_NET_WM_PING, "_NET_WM_PING" }, |
| 64 { base::atom::_NET_WM_PID, "_NET_WM_PID" }, |
| 65 { base::atom::WM_S0, "WM_S0" }, |
| 66 { base::atom::_MOTIF_WM_HINTS, "_MOTIF_WM_HINTS" } |
| 67 }; |
| 68 |
| 69 // Our lists need to stay in sync here. |
| 70 COMPILE_ASSERT(arraysize(kAtomList) == base::atom::ATOM_COUNT, |
| 71 atom_lists_are_same_size); |
| 72 |
| 47 bool InitializeXInput2Internal() { | 73 bool InitializeXInput2Internal() { |
| 48 Display* display = base::MessagePumpX::GetDefaultXDisplay(); | 74 Display* display = base::MessagePumpAuraX11::GetDefaultXDisplay(); |
| 49 if (!display) | 75 if (!display) |
| 50 return false; | 76 return false; |
| 51 | 77 |
| 52 int event, err; | 78 int event, err; |
| 53 | 79 |
| 54 int xiopcode; | 80 int xiopcode; |
| 55 if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) { | 81 if (!XQueryExtension(display, "XInputExtension", &xiopcode, &event, &err)) { |
| 56 DVLOG(1) << "X Input extension not available."; | 82 DVLOG(1) << "X Input extension not available."; |
| 57 return false; | 83 return false; |
| 58 } | 84 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 80 | 106 |
| 81 bool InitializeXInput2() { | 107 bool InitializeXInput2() { |
| 82 static bool xinput2_supported = InitializeXInput2Internal(); | 108 static bool xinput2_supported = InitializeXInput2Internal(); |
| 83 return xinput2_supported; | 109 return xinput2_supported; |
| 84 } | 110 } |
| 85 | 111 |
| 86 } // namespace | 112 } // namespace |
| 87 | 113 |
| 88 namespace base { | 114 namespace base { |
| 89 | 115 |
| 90 MessagePumpX::MessagePumpX() : MessagePumpGlib(), | 116 MessagePumpAuraX11::MessagePumpAuraX11() : MessagePumpGlib(), |
| 91 x_source_(NULL) { | 117 x_source_(NULL) { |
| 92 InitializeXInput2(); | 118 InitializeXInput2(); |
| 93 InitXSource(); | 119 InitXSource(); |
| 94 } | 120 } |
| 95 | 121 |
| 96 // static | 122 // static |
| 97 Display* MessagePumpX::GetDefaultXDisplay() { | 123 Display* MessagePumpAuraX11::GetDefaultXDisplay() { |
| 98 if (!g_xdisplay) | 124 if (!g_xdisplay) |
| 99 g_xdisplay = XOpenDisplay(NULL); | 125 g_xdisplay = XOpenDisplay(NULL); |
| 100 return g_xdisplay; | 126 return g_xdisplay; |
| 101 } | 127 } |
| 102 | 128 |
| 103 // static | 129 // static |
| 104 bool MessagePumpX::HasXInput2() { | 130 ::Atom MessagePumpAuraX11::GetAtom(atom::Name name) { |
| 131 AtomMap& cached_atom_map = g_cached_atoms.Get(); |
| 132 if (cached_atom_map.empty()) { |
| 133 // First time we're trying to use a cached atom. Intern all our atom data. |
| 134 const char* all_names[atom::ATOM_COUNT]; |
| 135 ::Atom cached_atoms[atom::ATOM_COUNT]; |
| 136 |
| 137 for (int i = 0; i < atom::ATOM_COUNT; ++i) |
| 138 all_names[i] = kAtomList[i].name; |
| 139 |
| 140 // Grab all the atoms we need now to minimize roundtrips to the X11 server. |
| 141 XInternAtoms(base::MessagePumpAuraX11::GetDefaultXDisplay(), |
| 142 const_cast<char**>(all_names), atom::ATOM_COUNT, False, |
| 143 cached_atoms); |
| 144 |
| 145 for (int i = 0; i < atom::ATOM_COUNT; ++i) |
| 146 cached_atom_map.insert(std::make_pair(kAtomList[i].id, cached_atoms[i])); |
| 147 } |
| 148 |
| 149 AtomMap::const_iterator it = cached_atom_map.find(name); |
| 150 DCHECK(it != cached_atom_map.end()); |
| 151 return it->second; |
| 152 } |
| 153 |
| 154 // static |
| 155 bool MessagePumpAuraX11::HasXInput2() { |
| 105 return InitializeXInput2(); | 156 return InitializeXInput2(); |
| 106 } | 157 } |
| 107 | 158 |
| 108 // static | 159 // static |
| 109 void MessagePumpX::SetDefaultDispatcher(MessagePumpDispatcher* dispatcher) { | 160 void MessagePumpAuraX11::SetDefaultDispatcher( |
| 161 MessagePumpDispatcher* dispatcher) { |
| 110 DCHECK(!g_default_dispatcher || !dispatcher); | 162 DCHECK(!g_default_dispatcher || !dispatcher); |
| 111 g_default_dispatcher = dispatcher; | 163 g_default_dispatcher = dispatcher; |
| 112 } | 164 } |
| 113 | 165 |
| 114 gboolean MessagePumpX::DispatchXEvents() { | 166 gboolean MessagePumpAuraX11::DispatchXEvents() { |
| 115 Display* display = GetDefaultXDisplay(); | 167 Display* display = GetDefaultXDisplay(); |
| 116 DCHECK(display); | 168 DCHECK(display); |
| 117 MessagePumpDispatcher* dispatcher = | 169 MessagePumpDispatcher* dispatcher = |
| 118 GetDispatcher() ? GetDispatcher() : g_default_dispatcher; | 170 GetDispatcher() ? GetDispatcher() : g_default_dispatcher; |
| 119 | 171 |
| 120 // In the general case, we want to handle all pending events before running | 172 // In the general case, we want to handle all pending events before running |
| 121 // the tasks. This is what happens in the message_pump_glib case. | 173 // the tasks. This is what happens in the message_pump_glib case. |
| 122 while (XPending(display)) { | 174 while (XPending(display)) { |
| 123 XEvent xev; | 175 XEvent xev; |
| 124 XNextEvent(display, &xev); | 176 XNextEvent(display, &xev); |
| 125 if (dispatcher && ProcessXEvent(dispatcher, &xev)) | 177 if (dispatcher && ProcessXEvent(dispatcher, &xev)) |
| 126 return TRUE; | 178 return TRUE; |
| 127 } | 179 } |
| 128 return TRUE; | 180 return TRUE; |
| 129 } | 181 } |
| 130 | 182 |
| 131 MessagePumpX::~MessagePumpX() { | 183 MessagePumpAuraX11::~MessagePumpAuraX11() { |
| 132 g_source_destroy(x_source_); | 184 g_source_destroy(x_source_); |
| 133 g_source_unref(x_source_); | 185 g_source_unref(x_source_); |
| 134 XCloseDisplay(g_xdisplay); | 186 XCloseDisplay(g_xdisplay); |
| 135 g_xdisplay = NULL; | 187 g_xdisplay = NULL; |
| 188 g_cached_atoms.Get().clear(); |
| 136 } | 189 } |
| 137 | 190 |
| 138 void MessagePumpX::InitXSource() { | 191 void MessagePumpAuraX11::InitXSource() { |
| 139 // CHECKs are to help track down crbug.com/113106. | 192 // CHECKs are to help track down crbug.com/113106. |
| 140 CHECK(!x_source_); | 193 CHECK(!x_source_); |
| 141 Display* display = GetDefaultXDisplay(); | 194 Display* display = GetDefaultXDisplay(); |
| 142 CHECK(display) << "Unable to get connection to X server"; | 195 CHECK(display) << "Unable to get connection to X server"; |
| 143 x_poll_.reset(new GPollFD()); | 196 x_poll_.reset(new GPollFD()); |
| 144 CHECK(x_poll_.get()); | 197 CHECK(x_poll_.get()); |
| 145 x_poll_->fd = ConnectionNumber(display); | 198 x_poll_->fd = ConnectionNumber(display); |
| 146 x_poll_->events = G_IO_IN; | 199 x_poll_->events = G_IO_IN; |
| 147 | 200 |
| 148 x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource)); | 201 x_source_ = g_source_new(&XSourceFuncs, sizeof(GSource)); |
| 149 g_source_add_poll(x_source_, x_poll_.get()); | 202 g_source_add_poll(x_source_, x_poll_.get()); |
| 150 g_source_set_can_recurse(x_source_, TRUE); | 203 g_source_set_can_recurse(x_source_, TRUE); |
| 151 g_source_set_callback(x_source_, NULL, this, NULL); | 204 g_source_set_callback(x_source_, NULL, this, NULL); |
| 152 g_source_attach(x_source_, g_main_context_default()); | 205 g_source_attach(x_source_, g_main_context_default()); |
| 153 } | 206 } |
| 154 | 207 |
| 155 bool MessagePumpX::ProcessXEvent(MessagePumpDispatcher* dispatcher, | 208 bool MessagePumpAuraX11::ProcessXEvent(MessagePumpDispatcher* dispatcher, |
| 156 XEvent* xev) { | 209 XEvent* xev) { |
| 157 bool should_quit = false; | 210 bool should_quit = false; |
| 158 | 211 |
| 159 bool have_cookie = false; | 212 bool have_cookie = false; |
| 160 if (xev->type == GenericEvent && | 213 if (xev->type == GenericEvent && |
| 161 XGetEventData(xev->xgeneric.display, &xev->xcookie)) { | 214 XGetEventData(xev->xgeneric.display, &xev->xcookie)) { |
| 162 have_cookie = true; | 215 have_cookie = true; |
| 163 } | 216 } |
| 164 | 217 |
| 165 if (!WillProcessXEvent(xev)) { | 218 if (!WillProcessXEvent(xev)) { |
| 166 if (!dispatcher->Dispatch(xev)) { | 219 if (!dispatcher->Dispatch(xev)) { |
| 167 should_quit = true; | 220 should_quit = true; |
| 168 Quit(); | 221 Quit(); |
| 169 } | 222 } |
| 170 DidProcessXEvent(xev); | 223 DidProcessXEvent(xev); |
| 171 } | 224 } |
| 172 | 225 |
| 173 if (have_cookie) { | 226 if (have_cookie) { |
| 174 XFreeEventData(xev->xgeneric.display, &xev->xcookie); | 227 XFreeEventData(xev->xgeneric.display, &xev->xcookie); |
| 175 } | 228 } |
| 176 | 229 |
| 177 return should_quit; | 230 return should_quit; |
| 178 } | 231 } |
| 179 | 232 |
| 180 bool MessagePumpX::WillProcessXEvent(XEvent* xevent) { | 233 bool MessagePumpAuraX11::WillProcessXEvent(XEvent* xevent) { |
| 181 if (!observers().might_have_observers()) | 234 if (!observers().might_have_observers()) |
| 182 return false; | 235 return false; |
| 183 ObserverListBase<MessagePumpObserver>::Iterator it(observers()); | 236 ObserverListBase<MessagePumpObserver>::Iterator it(observers()); |
| 184 MessagePumpObserver* obs; | 237 MessagePumpObserver* obs; |
| 185 while ((obs = it.GetNext()) != NULL) { | 238 while ((obs = it.GetNext()) != NULL) { |
| 186 if (obs->WillProcessEvent(xevent)) | 239 if (obs->WillProcessEvent(xevent)) |
| 187 return true; | 240 return true; |
| 188 } | 241 } |
| 189 return false; | 242 return false; |
| 190 } | 243 } |
| 191 | 244 |
| 192 void MessagePumpX::DidProcessXEvent(XEvent* xevent) { | 245 void MessagePumpAuraX11::DidProcessXEvent(XEvent* xevent) { |
| 193 FOR_EACH_OBSERVER(MessagePumpObserver, observers(), DidProcessEvent(xevent)); | 246 FOR_EACH_OBSERVER(MessagePumpObserver, observers(), DidProcessEvent(xevent)); |
| 194 } | 247 } |
| 195 | 248 |
| 196 } // namespace base | 249 } // namespace base |
| OLD | NEW |