diff options
author | rjkroege@google.com <rjkroege@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-21 19:35:50 +0000 |
---|---|---|
committer | rjkroege@google.com <rjkroege@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-21 19:35:50 +0000 |
commit | 4b170c5fbe7fcf69487424d580ce4dbeb7035a01 (patch) | |
tree | 350b297be642f4e0b50a5b1fe05f9c6007f4336e /base | |
parent | 923b561488b3b5fd733c703c287c720d3c3f3088 (diff) | |
download | chromium_src-4b170c5fbe7fcf69487424d580ce4dbeb7035a01.zip chromium_src-4b170c5fbe7fcf69487424d580ce4dbeb7035a01.tar.gz chromium_src-4b170c5fbe7fcf69487424d580ce4dbeb7035a01.tar.bz2 |
Add a message pump for touchui=1
The message pump reads events directly from X. For most events, it passes them
on to GDK for normal processing. It consumes some events (e.g. keypress events)
to demonstrate how it's intended to work. This, of course, makes chrome mostly
unusable since you can only use the mouse to do things. But this is a small
first step towards capturing events through MPX (e.g. touch etc.) and processing
them as chrome pleases.
glib message pump: Slightly change architecture
This changeset breaks down the glib message pump a little so that it can be
easily subclassed. The next set of commits will introduce a subclass that still
uses GTK and GDK widgets, but reads events directly from X instead of through
GTK/GDK.
Review URL: http://codereview.chromium.org/3748002
Patch from Sadrul Chowdhury <sadrul@chromium.org>.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@63397 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/base.gypi | 3 | ||||
-rw-r--r-- | base/message_loop.cc | 10 | ||||
-rw-r--r-- | base/message_pump_glib.cc | 30 | ||||
-rw-r--r-- | base/message_pump_glib.h | 9 | ||||
-rw-r--r-- | base/message_pump_glib_x.cc | 104 | ||||
-rw-r--r-- | base/message_pump_glib_x.h | 63 |
6 files changed, 205 insertions, 14 deletions
diff --git a/base/base.gypi b/base/base.gypi index 7280eb8..019f9ae 100644 --- a/base/base.gypi +++ b/base/base.gypi @@ -333,6 +333,7 @@ 'sources!': [ 'atomicops_internals_x86_gcc.cc', 'message_pump_glib.cc', + 'message_pump_glib_x.cc', ], }], [ 'OS != "linux"', { @@ -441,6 +442,8 @@ 'md5.h', 'message_pump_glib.cc', 'message_pump_glib.h', + 'message_pump_glib_x.cc', + 'message_pump_glib_x.h', 'message_pump_libevent.cc', 'message_pump_libevent.h', 'message_pump_mac.h', diff --git a/base/message_loop.cc b/base/message_loop.cc index 8f6c997b..f335ca1 100644 --- a/base/message_loop.cc +++ b/base/message_loop.cc @@ -23,6 +23,9 @@ #if defined(OS_POSIX) && !defined(OS_MACOSX) #include "base/message_pump_glib.h" #endif +#if defined(TOUCH_UI) +#include "base/message_pump_glib_x.h" +#endif using base::Time; using base::TimeDelta; @@ -134,6 +137,9 @@ MessageLoop::MessageLoop(Type type) #elif defined(OS_MACOSX) #define MESSAGE_PUMP_UI base::MessagePumpMac::Create() #define MESSAGE_PUMP_IO new base::MessagePumpLibevent() +#elif defined(TOUCH_UI) +#define MESSAGE_PUMP_UI new base::MessagePumpGlibX() +#define MESSAGE_PUMP_IO new base::MessagePumpLibevent() #elif defined(OS_POSIX) // POSIX but not MACOSX. #define MESSAGE_PUMP_UI new base::MessagePumpForUI() #define MESSAGE_PUMP_IO new base::MessagePumpLibevent() @@ -533,9 +539,9 @@ bool MessageLoop::DoWork() { return false; } -bool MessageLoop::DoDelayedWork(Time* next_delayed_work_time) { +bool MessageLoop::DoDelayedWork(base::Time* next_delayed_work_time) { if (!nestable_tasks_allowed_ || delayed_work_queue_.empty()) { - *next_delayed_work_time = Time(); + *next_delayed_work_time = base::Time(); return false; } diff --git a/base/message_pump_glib.cc b/base/message_pump_glib.cc index e85a712..ad6d177 100644 --- a/base/message_pump_glib.cc +++ b/base/message_pump_glib.cc @@ -207,8 +207,7 @@ void MessagePumpForUI::RunWithDispatcher(Delegate* delegate, // Don't block if we think we have more work to do. bool block = !more_work_is_plausible; - // g_main_context_iteration returns true if events have been dispatched. - more_work_is_plausible = g_main_context_iteration(context_, block); + more_work_is_plausible = RunOnce(context_, block); if (state_->should_quit) break; @@ -232,6 +231,11 @@ void MessagePumpForUI::RunWithDispatcher(Delegate* delegate, state_ = previous_state; } +bool MessagePumpForUI::RunOnce(GMainContext* context, bool block) { + // g_main_context_iteration returns true if events have been dispatched. + return g_main_context_iteration(context, block); +} + // Return the timeout we want passed to poll. int MessagePumpForUI::HandlePrepare() { // We know we have work, but we haven't called HandleDispatch yet. Don't let @@ -332,19 +336,21 @@ void MessagePumpForUI::ScheduleDelayedWork(const Time& delayed_work_time) { ScheduleWork(); } -// static -void MessagePumpForUI::EventDispatcher(GdkEvent* event, gpointer data) { - MessagePumpForUI* message_pump = reinterpret_cast<MessagePumpForUI*>(data); - - message_pump->WillProcessEvent(event); - if (message_pump->state_ && // state_ may be null during tests. - message_pump->state_->dispatcher) { - if (!message_pump->state_->dispatcher->Dispatch(event)) - message_pump->state_->should_quit = true; +void MessagePumpForUI::DispatchEvents(GdkEvent* event) { + WillProcessEvent(event); + if (state_ && state_->dispatcher) { // state_ may be null during tests. + if (!state_->dispatcher->Dispatch(event)) + state_->should_quit = true; } else { gtk_main_do_event(event); } - message_pump->DidProcessEvent(event); + DidProcessEvent(event); +} + +// static +void MessagePumpForUI::EventDispatcher(GdkEvent* event, gpointer data) { + MessagePumpForUI* message_pump = reinterpret_cast<MessagePumpForUI*>(data); + message_pump->DispatchEvents(event); } } // namespace base diff --git a/base/message_pump_glib.h b/base/message_pump_glib.h index f6d022a..31d37c0 100644 --- a/base/message_pump_glib.h +++ b/base/message_pump_glib.h @@ -57,6 +57,11 @@ class MessagePumpForUI : public MessagePump { // Like MessagePump::Run, but GdkEvent objects are routed through dispatcher. virtual void RunWithDispatcher(Delegate* delegate, Dispatcher* dispatcher); + // Run a single iteration of the mainloop. A return value of true indicates + // that an event was handled. |block| indicates if it should wait if no event + // is ready for processing. + virtual bool RunOnce(GMainContext* context, bool block); + virtual void Run(Delegate* delegate) { RunWithDispatcher(delegate, NULL); } virtual void Quit(); virtual void ScheduleWork(); @@ -79,6 +84,10 @@ class MessagePumpForUI : public MessagePump { // receiving a notification callback. void RemoveObserver(Observer* observer); + // Dispatch an available GdkEvent. Essentially this allows a subclass to do + // some task before/after calling the default handler (EventDispatcher). + virtual void DispatchEvents(GdkEvent* event); + private: // We may make recursive calls to Run, so we save state that needs to be // separate between them in this structure type. diff --git a/base/message_pump_glib_x.cc b/base/message_pump_glib_x.cc new file mode 100644 index 0000000..f77f61d --- /dev/null +++ b/base/message_pump_glib_x.cc @@ -0,0 +1,104 @@ +// Copyright (c) 2010 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_glib_x.h" + +#include <gdk/gdkx.h> +#include <X11/Xlib.h> + +namespace { + +gboolean PlaceholderDispatch(GSource* source, + GSourceFunc cb, + gpointer data) { + return TRUE; +} + +} // namespace + +namespace base { + +MessagePumpGlibX::MessagePumpGlibX() : base::MessagePumpForUI(), + gdksource_(NULL), + dispatching_event_(false), + capture_x_events_(0), + capture_gdk_events_(0) { + gdk_event_handler_set(&EventDispatcherX, this, NULL); + + InitializeEventsToCapture(); +} + +MessagePumpGlibX::~MessagePumpGlibX() { +} + +bool MessagePumpGlibX::RunOnce(GMainContext* context, bool block) { + GdkDisplay* gdisp = gdk_display_get_default(); + Display* display = GDK_DISPLAY_XDISPLAY(gdisp); + if (XPending(display)) { + XEvent xev; + XPeekEvent(display, &xev); + if (capture_x_events_[xev.type]) { + XNextEvent(display, &xev); + + DLOG(INFO) << "nom noming event"; + + // TODO(sad): Create a GdkEvent from |xev| and pass it on to + // EventDispatcherX. The ultimate goal is to create a views::Event from + // |xev| and send it to a rootview. When done, the preceding DLOG will be + // removed. + } else { + // TODO(sad): A couple of extra events can still sneak in during this + 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; +} + +void MessagePumpGlibX::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; +} + +void MessagePumpGlibX::EventDispatcherX(GdkEvent* event, gpointer data) { + MessagePumpGlibX* pump_x = reinterpret_cast<MessagePumpGlibX*>(data); + + if (!pump_x->gdksource_) { + pump_x->gdksource_ = g_main_current_source(); + } else if (!pump_x->IsDispatchingEvent()) { + if (event->type != GDK_NOTHING && + pump_x->capture_gdk_events_[event->type]) { + // TODO(sad): An X event is caught by the GDK handler. Put it back in the + // X queue so that we catch it in the next iteration. When done, the + // following DLOG statement will be removed. + DLOG(INFO) << "GDK ruined it!!"; + } + } + + pump_x->DispatchEvents(event); +} + +} // namespace base diff --git a/base/message_pump_glib_x.h b/base/message_pump_glib_x.h new file mode 100644 index 0000000..2f50731 --- /dev/null +++ b/base/message_pump_glib_x.h @@ -0,0 +1,63 @@ +// Copyright (c) 2010 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. + +#ifndef BASE_MESSAGE_PUMP_GLIB_X_H +#define BASE_MESSAGE_PUMP_GLIB_X_H + +#include "base/message_pump.h" +#include "base/message_pump_glib.h" + +#include <bitset> + +#include <glib.h> +#include <gtk/gtk.h> +#include <X11/X.h> + +namespace base { + +class MessagePumpGlibX : public MessagePumpForUI { + public: + MessagePumpGlibX(); + virtual ~MessagePumpGlibX(); + + // MessagePumpForUI implementation. + virtual bool RunOnce(GMainContext* context, bool block); + + // Indicates whether a GDK event was injected by chrome (when |true|) or if it + // was captured and being processed by GDK (when |false|). + bool IsDispatchingEvent(void) { return dispatching_event_; } + + private: + static void EventDispatcherX(GdkEvent* event, gpointer data); + + // Update the lookup table and flag the events that should be captured and + // processed so that GDK doesn't get to them. + void InitializeEventsToCapture(void); + + // The event source for GDK events. + GSource* gdksource_; + + // Indicates whether a GDK event was injected by chrome (when |true|) or if it + // was captured and being processed by GDK (when |false|). + bool dispatching_event_; + +#if ! GTK_CHECK_VERSION(2,18,0) +// GDK_EVENT_LAST was introduced in GTK+ 2.18.0. For earlier versions, we pick a +// large enough value (the value of GDK_EVENT_LAST in 2.18.0) so that it works +// for all versions. +#define GDK_EVENT_LAST 37 +#endif + + // We do not want to process all the events ourselves. So we use a lookup + // table to quickly check if a particular event should be handled by us or if + // it should be passed on to the default GDK handler. + std::bitset<LASTEvent> capture_x_events_; + std::bitset<GDK_EVENT_LAST> capture_gdk_events_; + + DISALLOW_COPY_AND_ASSIGN(MessagePumpGlibX); +}; + +} // namespace base + +#endif // BASE_MESSAGE_PUMP_GLIB_X_H |