diff options
Diffstat (limited to 'base')
-rw-r--r-- | base/base.gypi | 7 | ||||
-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, 209 insertions, 14 deletions
diff --git a/base/base.gypi b/base/base.gypi index b9fad5e..d0fa20b 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"', { @@ -447,6 +448,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', @@ -604,10 +607,12 @@ 'symbolize', '../build/util/build_util.gyp:lastchange', '../build/linux/system.gyp:gtk', + '../build/linux/system.gyp:x11', 'xdg_mime', ], 'export_dependent_settings': [ '../build/linux/system.gyp:gtk', + '../build/linux/system.gyp:x11', ], },], [ 'OS == "freebsd" or OS == "openbsd"', { @@ -708,10 +713,12 @@ '../build/util/build_util.gyp:lastchange', '../build/linux/system.gyp:gtk', '../build/linux/system.gyp:nss', + '../build/linux/system.gyp:x11', 'xdg_mime', ], 'export_dependent_settings': [ '../build/linux/system.gyp:gtk', + '../build/linux/system.gyp:x11', ], },], ['OS == "linux"', { 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 |