michael@0: // Copyright (c) 2008 The Chromium Authors. All rights reserved. michael@0: // Use of this source code is governed by a BSD-style license that can be michael@0: // found in the LICENSE file. michael@0: michael@0: #ifndef BASE_MESSAGE_PUMP_GLIB_H_ michael@0: #define BASE_MESSAGE_PUMP_GLIB_H_ michael@0: michael@0: #include "base/message_pump.h" michael@0: #include "base/observer_list.h" michael@0: #include "base/scoped_ptr.h" michael@0: #include "base/time.h" michael@0: michael@0: typedef union _GdkEvent GdkEvent; michael@0: typedef struct _GMainContext GMainContext; michael@0: typedef struct _GPollFD GPollFD; michael@0: typedef struct _GSource GSource; michael@0: michael@0: namespace base { michael@0: michael@0: // This class implements a MessagePump needed for TYPE_UI MessageLoops on michael@0: // OS_LINUX platforms using GLib. michael@0: class MessagePumpForUI : public MessagePump { michael@0: public: michael@0: // Observer is notified prior to a GdkEvent event being dispatched. As michael@0: // Observers are notified of every change, they have to be FAST! michael@0: class Observer { michael@0: public: michael@0: virtual ~Observer() {} michael@0: michael@0: // This method is called before processing a message. michael@0: virtual void WillProcessEvent(GdkEvent* event) = 0; michael@0: michael@0: // This method is called after processing a message. michael@0: virtual void DidProcessEvent(GdkEvent* event) = 0; michael@0: }; michael@0: michael@0: // Dispatcher is used during a nested invocation of Run to dispatch events. michael@0: // If Run is invoked with a non-NULL Dispatcher, MessageLoop does not michael@0: // dispatch events (or invoke gtk_main_do_event), rather every event is michael@0: // passed to Dispatcher's Dispatch method for dispatch. It is up to the michael@0: // Dispatcher to dispatch, or not, the event. michael@0: // michael@0: // The nested loop is exited by either posting a quit, or returning false michael@0: // from Dispatch. michael@0: class Dispatcher { michael@0: public: michael@0: virtual ~Dispatcher() {} michael@0: // Dispatches the event. If true is returned processing continues as michael@0: // normal. If false is returned, the nested loop exits immediately. michael@0: virtual bool Dispatch(GdkEvent* event) = 0; michael@0: }; michael@0: michael@0: MessagePumpForUI(); michael@0: virtual ~MessagePumpForUI(); michael@0: michael@0: // Like MessagePump::Run, but GdkEvent objects are routed through dispatcher. michael@0: virtual void RunWithDispatcher(Delegate* delegate, Dispatcher* dispatcher); michael@0: michael@0: virtual void Run(Delegate* delegate) { RunWithDispatcher(delegate, NULL); } michael@0: virtual void Quit(); michael@0: virtual void ScheduleWork(); michael@0: virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time); michael@0: michael@0: // Internal methods used for processing the pump callbacks. They are michael@0: // public for simplicity but should not be used directly. HandlePrepare michael@0: // is called during the prepare step of glib, and returns a timeout that michael@0: // will be passed to the poll. HandleCheck is called after the poll michael@0: // has completed, and returns whether or not HandleDispatch should be called. michael@0: // HandleDispatch is called if HandleCheck returned true. michael@0: int HandlePrepare(); michael@0: bool HandleCheck(); michael@0: void HandleDispatch(); michael@0: michael@0: // Adds an Observer, which will start receiving notifications immediately. michael@0: void AddObserver(Observer* observer); michael@0: michael@0: // Removes an Observer. It is safe to call this method while an Observer is michael@0: // receiving a notification callback. michael@0: void RemoveObserver(Observer* observer); michael@0: michael@0: private: michael@0: // We may make recursive calls to Run, so we save state that needs to be michael@0: // separate between them in this structure type. michael@0: struct RunState { michael@0: Delegate* delegate; michael@0: Dispatcher* dispatcher; michael@0: michael@0: // Used to flag that the current Run() invocation should return ASAP. michael@0: bool should_quit; michael@0: michael@0: // Used to count how many Run() invocations are on the stack. michael@0: int run_depth; michael@0: michael@0: // This keeps the state of whether the pump got signaled that there was new michael@0: // work to be done. Since we eat the message on the wake up pipe as soon as michael@0: // we get it, we keep that state here to stay consistent. michael@0: bool has_work; michael@0: }; michael@0: michael@0: // Invoked from EventDispatcher. Notifies all observers we're about to michael@0: // process an event. michael@0: void WillProcessEvent(GdkEvent* event); michael@0: michael@0: // Invoked from EventDispatcher. Notifies all observers we processed an michael@0: // event. michael@0: void DidProcessEvent(GdkEvent* event); michael@0: michael@0: // Callback prior to gdk dispatching an event. michael@0: static void EventDispatcher(GdkEvent* event, void* data); michael@0: michael@0: RunState* state_; michael@0: michael@0: // This is a GLib structure that we can add event sources to. We use the michael@0: // default GLib context, which is the one to which all GTK events are michael@0: // dispatched. michael@0: GMainContext* context_; michael@0: michael@0: // This is the time when we need to do delayed work. michael@0: TimeTicks delayed_work_time_; michael@0: michael@0: // The work source. It is shared by all calls to Run and destroyed when michael@0: // the message pump is destroyed. michael@0: GSource* work_source_; michael@0: michael@0: // We use a wakeup pipe to make sure we'll get out of the glib polling phase michael@0: // when another thread has scheduled us to do some work. There is a glib michael@0: // mechanism g_main_context_wakeup, but this won't guarantee that our event's michael@0: // Dispatch() will be called. michael@0: int wakeup_pipe_read_; michael@0: int wakeup_pipe_write_; michael@0: // Use a scoped_ptr to avoid needing the definition of GPollFD in the header. michael@0: scoped_ptr wakeup_gpollfd_; michael@0: michael@0: // List of observers. michael@0: ObserverList observers_; michael@0: michael@0: DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI); michael@0: }; michael@0: michael@0: } // namespace base michael@0: michael@0: #endif // BASE_MESSAGE_PUMP_GLIB_H_