| OLD | NEW | 
 | (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 |  | 
| OLD | NEW |