diff options
author | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-24 20:10:25 +0000 |
---|---|---|
committer | sadrul@chromium.org <sadrul@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-06-24 20:10:25 +0000 |
commit | 2047ef4d68229d47cba8bf7f2e0465ab31f8b3ce (patch) | |
tree | 86af296c2de9e5ac31c9ed79e21d9d0e4ccda8c4 /base/message_pump_x.cc | |
parent | 86e1db9d9de1ce72ba045bd3755e7a077a1f7fd8 (diff) | |
download | chromium_src-2047ef4d68229d47cba8bf7f2e0465ab31f8b3ce.zip chromium_src-2047ef4d68229d47cba8bf7f2e0465ab31f8b3ce.tar.gz chromium_src-2047ef4d68229d47cba8bf7f2e0465ab31f8b3ce.tar.bz2 |
Refactor the glib message-pump, and use it as the base for a gtk message pump and an X message pump.
The changes:
* Rename MessagePumpGlibX to MessagePumpX.
* Rename MessagePumpForUI to MessagePumpGlib.
* Move some stuff out of MessagePumpGlib, and into MessagePumpGtk and MessagePumpX.
* Rename MessagePumpForUI::Observer to MessageObserver, moved the platform-specific implementations into MessagePumpGtk and MessagePumpX. Ditto for MessagePumpForUI::Dispatcher.
MessagePumpX is independent of MessagePumpGtk. At the moment, MessagePumpX does process some GDK event, but once we have a complete native_widget_x, we can take out the GDK processing and things should continue to work.
BUG=none
TEST=existing message-pump tests.
Review URL: http://codereview.chromium.org/7250001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@90418 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base/message_pump_x.cc')
-rw-r--r-- | base/message_pump_x.cc | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/base/message_pump_x.cc b/base/message_pump_x.cc new file mode 100644 index 0000000..a50e182 --- /dev/null +++ b/base/message_pump_x.cc @@ -0,0 +1,232 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/message_pump_x.h" + +#include <gdk/gdkx.h> +#if defined(HAVE_XINPUT2) +#include <X11/extensions/XInput2.h> +#else +#include <X11/Xlib.h> +#endif + +#include "base/basictypes.h" + +namespace { + +gboolean PlaceholderDispatch(GSource* source, + GSourceFunc cb, + gpointer data) { + return TRUE; +} + +} // namespace + +namespace base { + +MessagePumpX::MessagePumpX() : MessagePumpGlib(), +#if defined(HAVE_XINPUT2) + xiopcode_(-1), +#endif + gdksource_(NULL), + dispatching_event_(false), + capture_x_events_(0), + capture_gdk_events_(0) { + gdk_window_add_filter(NULL, &GdkEventFilter, this); + gdk_event_handler_set(&EventDispatcherX, this, NULL); + +#if defined(HAVE_XINPUT2) + InitializeXInput2(); +#endif + InitializeEventsToCapture(); +} + +MessagePumpX::~MessagePumpX() { + gdk_window_remove_filter(NULL, &GdkEventFilter, this); + gdk_event_handler_set(reinterpret_cast<GdkEventFunc>(gtk_main_do_event), + this, NULL); +} + +bool MessagePumpX::ShouldCaptureXEvent(XEvent* xev) { + return capture_x_events_[xev->type] +#if defined(HAVE_XINPUT2) + && (xev->type != GenericEvent || xev->xcookie.extension == xiopcode_) +#endif + ; +} + + +bool MessagePumpX::ProcessXEvent(XEvent* xev) { + bool should_quit = false; + +#if defined(HAVE_XINPUT2) + bool have_cookie = false; + if (xev->type == GenericEvent && + XGetEventData(xev->xgeneric.display, &xev->xcookie)) { + have_cookie = true; + } +#endif + + if (WillProcessXEvent(xev) == MessagePumpObserver::EVENT_CONTINUE) { + MessagePumpDispatcher::DispatchStatus status = + GetDispatcher()->Dispatch(xev); + + if (status == MessagePumpDispatcher::EVENT_QUIT) { + should_quit = true; + Quit(); + } else if (status == MessagePumpDispatcher::EVENT_IGNORED) { + VLOG(1) << "Event (" << xev->type << ") not handled."; + } + } + +#if defined(HAVE_XINPUT2) + if (have_cookie) { + XFreeEventData(xev->xgeneric.display, &xev->xcookie); + } +#endif + + return should_quit; +} + +bool MessagePumpX::RunOnce(GMainContext* context, bool block) { + GdkDisplay* gdisp = gdk_display_get_default(); + if (!gdisp || !GetDispatcher()) + return g_main_context_iteration(context, block); + + Display* display = GDK_DISPLAY_XDISPLAY(gdisp); + + if (XPending(display)) { + XEvent xev; + XPeekEvent(display, &xev); + + if (ShouldCaptureXEvent(&xev)) { + XNextEvent(display, &xev); + if (ProcessXEvent(&xev)) + return true; + } else { + // TODO(sad): A couple of extra events can still sneak in during this. + // Those should be sent back to the X queue from the dispatcher + // EventDispatcherX. + if (gdksource_) + gdksource_->source_funcs->dispatch = gdkdispatcher_; + g_main_context_iteration(context, FALSE); + } + } + + bool retvalue; + if (gdksource_) { + // Replace the dispatch callback of the GDK event source temporarily so that + // it doesn't read events from X. + gboolean (*cb)(GSource*, GSourceFunc, void*) = + gdksource_->source_funcs->dispatch; + gdksource_->source_funcs->dispatch = PlaceholderDispatch; + + dispatching_event_ = true; + retvalue = g_main_context_iteration(context, block); + dispatching_event_ = false; + + gdksource_->source_funcs->dispatch = cb; + } else { + retvalue = g_main_context_iteration(context, block); + } + + return retvalue; +} + +GdkFilterReturn MessagePumpX::GdkEventFilter(GdkXEvent* gxevent, + GdkEvent* gevent, + gpointer data) { + MessagePumpX* pump = static_cast<MessagePumpX*>(data); + XEvent* xev = static_cast<XEvent*>(gxevent); + + if (pump->ShouldCaptureXEvent(xev) && pump->GetDispatcher()) { + pump->ProcessXEvent(xev); + return GDK_FILTER_REMOVE; + } + + return GDK_FILTER_CONTINUE; +} + +bool MessagePumpX::WillProcessXEvent(XEvent* xevent) { + ObserverListBase<MessagePumpObserver>::Iterator it(observers()); + MessagePumpObserver* obs; + while ((obs = it.GetNext()) != NULL) { + if (obs->WillProcessXEvent(xevent)) + return true; + } + return false; +} + +void MessagePumpX::EventDispatcherX(GdkEvent* event, gpointer data) { + MessagePumpX* pump_x = reinterpret_cast<MessagePumpX*>(data); + + if (!pump_x->gdksource_) { + pump_x->gdksource_ = g_main_current_source(); + if (pump_x->gdksource_) + pump_x->gdkdispatcher_ = pump_x->gdksource_->source_funcs->dispatch; + } else if (!pump_x->IsDispatchingEvent()) { + if (event->type != GDK_NOTHING && + pump_x->capture_gdk_events_[event->type]) { + NOTREACHED() << "GDK received an event it shouldn't have"; + } + } + + gtk_main_do_event(event); +} + +void MessagePumpX::InitializeEventsToCapture(void) { + // TODO(sad): Decide which events we want to capture and update the tables + // accordingly. + capture_x_events_[KeyPress] = true; + capture_gdk_events_[GDK_KEY_PRESS] = true; + + capture_x_events_[KeyRelease] = true; + capture_gdk_events_[GDK_KEY_RELEASE] = true; + + capture_x_events_[ButtonPress] = true; + capture_gdk_events_[GDK_BUTTON_PRESS] = true; + + capture_x_events_[ButtonRelease] = true; + capture_gdk_events_[GDK_BUTTON_RELEASE] = true; + + capture_x_events_[MotionNotify] = true; + capture_gdk_events_[GDK_MOTION_NOTIFY] = true; + +#if defined(HAVE_XINPUT2) + capture_x_events_[GenericEvent] = true; +#endif +} + +#if defined(HAVE_XINPUT2) +void MessagePumpX::InitializeXInput2(void) { + GdkDisplay* display = gdk_display_get_default(); + if (!display) + return; + + Display* xdisplay = GDK_DISPLAY_XDISPLAY(display); + int event, err; + + if (!XQueryExtension(xdisplay, "XInputExtension", &xiopcode_, &event, &err)) { + VLOG(1) << "X Input extension not available."; + xiopcode_ = -1; + return; + } + + int major = 2, minor = 0; + if (XIQueryVersion(xdisplay, &major, &minor) == BadRequest) { + VLOG(1) << "XInput2 not supported in the server."; + xiopcode_ = -1; + return; + } +} +#endif // HAVE_XINPUT2 + +MessagePumpObserver::EventStatus + MessagePumpObserver::WillProcessXEvent(XEvent* xev) { + return EVENT_CONTINUE; +} + +COMPILE_ASSERT(XLASTEvent >= LASTEvent, XLASTEvent_too_small); + +} // namespace base |