diff --git a/config/rules.mk b/config/rules.mk index 3ccdb4fda15f..f55be1c66ff8 100644 --- a/config/rules.mk +++ b/config/rules.mk @@ -1408,6 +1408,10 @@ host_%.$(OBJ_SUFFIX): %.mm $(GLOBAL_DEPS) moc_%.cpp: %.h $(GLOBAL_DEPS) $(MOC) $< $(OUTOPTION)$@ +moc_%.cc: %.cc $(GLOBAL_DEPS) + $(REPORT_BUILD) + $(ELOG) $(MOC) $(_VPATH_SRCS:.cc=.h) $(OUTOPTION)$@ + ifdef ASFILES # The AS_DASH_C_FLAG is needed cause not all assemblers (Solaris) accept # a '-c' flag. diff --git a/ipc/chromium/Makefile.in b/ipc/chromium/Makefile.in index 0be39c2d001c..37504af53f54 100644 --- a/ipc/chromium/Makefile.in +++ b/ipc/chromium/Makefile.in @@ -246,11 +246,27 @@ CPPSRCS += \ file_util_linux.cc \ file_version_info_linux.cc \ idle_timer_none.cc \ - message_pump_glib.cc \ process_util_linux.cc \ time_posix.cc \ $(NULL) +ifdef MOZ_ENABLE_GTK2 +CPPSRCS += \ + message_pump_glib.cc \ + $(NULL) +endif + +ifdef MOZ_ENABLE_QT +MOCSRCS = \ + moc_message_pump_qt.cc \ + $(NULL) + +CPPSRCS += \ + $(MOCSRCS) \ + message_pump_qt.cc \ + $(NULL) +endif + endif # } OS_LINUX # libevent diff --git a/ipc/chromium/src/base/message_loop.cc b/ipc/chromium/src/base/message_loop.cc index ec8217657000..6b4c16b09ae9 100644 --- a/ipc/chromium/src/base/message_loop.cc +++ b/ipc/chromium/src/base/message_loop.cc @@ -20,8 +20,13 @@ #include "base/message_pump_libevent.h" #endif #if defined(OS_LINUX) +#ifdef MOZ_WIDGET_GTK2 #include "base/message_pump_glib.h" #endif +#ifdef MOZ_WIDGET_QT +#include "base/message_pump_qt.h" +#endif +#endif #ifdef CHROMIUM_MOZILLA_BUILD #include "MessagePump.h" diff --git a/ipc/chromium/src/base/message_pump_qt.cc b/ipc/chromium/src/base/message_pump_qt.cc new file mode 100644 index 000000000000..dc993cf4f30b --- /dev/null +++ b/ipc/chromium/src/base/message_pump_qt.cc @@ -0,0 +1,142 @@ +// 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_qt.h" + +#include +#include +#include + +#include +#include + +#include "base/eintr_wrapper.h" +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "base/platform_thread.h" + +namespace { +// Cached QEvent user type, registered for our event system +static int sPokeEvent; +} // namespace + +namespace base { + +MessagePumpForUI::MessagePumpForUI() + : qt_pump(*this) +{ +} + +MessagePumpForUI::~MessagePumpForUI() { +} + +MessagePumpQt::MessagePumpQt(MessagePumpForUI &aPump) + : pump(aPump) +{ + // Register our custom event type, to use in qApp event loop +#if (QT_VERSION >= QT_VERSION_CHECK(4, 4, 0)) + sPokeEvent = QEvent::registerEventType(); +#else + sPokeEvent = QEvent::User+5000; +#endif +} + +MessagePumpQt::~MessagePumpQt() +{ +} + +bool +MessagePumpQt::event(QEvent *e) +{ + if (e->type() == sPokeEvent) { + pump.HandleDispatch(); + return true; + } + return false; +} + +void MessagePumpForUI::Run(Delegate* delegate) { + RunState state; + state.delegate = delegate; + state.should_quit = false; + state.run_depth = state_ ? state_->run_depth + 1 : 1; + // We really only do a single task for each iteration of the loop. If we + // have done something, assume there is likely something more to do. This + // will mean that we don't block on the message pump until there was nothing + // more to do. We also set this to true to make sure not to block on the + // first iteration of the loop, so RunAllPending() works correctly. + state.more_work_is_plausible = true; + + RunState* previous_state = state_; + state_ = &state; + + // We run our own loop instead of using g_main_loop_quit in one of the + // callbacks. This is so we only quit our own loops, and we don't quit + // nested loops run by others. TODO(deanm): Is this what we want? + + while (!state_->should_quit) { + QAbstractEventDispatcher *dispatcher = QAbstractEventDispatcher::instance(qApp->thread()); + if (!dispatcher) + return; + dispatcher->processEvents(QEventLoop::AllEvents | QEventLoop::WaitForMoreEvents); + } + + state_ = previous_state; +} + +void MessagePumpForUI::HandleDispatch() { + // We should only ever have a single message on the wakeup pipe, since we + // are only signaled when the queue went from empty to non-empty. The qApp + // poll will tell us whether there was data, so this read shouldn't block. + if (state_->should_quit) + return; + + state_->more_work_is_plausible = false; + + if (state_->delegate->DoWork()) + state_->more_work_is_plausible = true; + + if (state_->should_quit) + return; + + if (state_->delegate->DoDelayedWork(&delayed_work_time_)) + state_->more_work_is_plausible = true; + if (state_->should_quit) + return; + + // Don't do idle work if we think there are more important things + // that we could be doing. + if (state_->more_work_is_plausible) + return; + + if (state_->delegate->DoIdleWork()) + state_->more_work_is_plausible = true; + if (state_->should_quit) + return; +} + +void MessagePumpForUI::Quit() { + if (state_) { + state_->should_quit = true; + } else { + NOTREACHED() << "Quit called outside Run!"; + } +} + +void MessagePumpForUI::ScheduleWork() { + // This can be called on any thread, so we don't want to touch any state + // variables as we would then need locks all over. This ensures that if + // we are sleeping in a poll that we will wake up. + QCoreApplication::postEvent(&qt_pump, + new QEvent((QEvent::Type) sPokeEvent)); +} + +void MessagePumpForUI::ScheduleDelayedWork(const Time& delayed_work_time) { + // We need to wake up the loop in case the poll timeout needs to be + // adjusted. This will cause us to try to do work, but that's ok. + delayed_work_time_ = delayed_work_time; + ScheduleWork(); +} + +} // namespace base diff --git a/ipc/chromium/src/base/message_pump_qt.h b/ipc/chromium/src/base/message_pump_qt.h new file mode 100644 index 000000000000..79b4d9ae31ad --- /dev/null +++ b/ipc/chromium/src/base/message_pump_qt.h @@ -0,0 +1,80 @@ +// 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_QT_H_ +#define BASE_MESSAGE_PUMP_QT_H_ + +#include + +#include "base/message_pump.h" +#include "base/time.h" + +namespace base { + +class MessagePumpForUI; + +class MessagePumpQt : public QObject { + Q_OBJECT + + public: + MessagePumpQt(MessagePumpForUI &pump); + ~MessagePumpQt(); + + virtual bool event (QEvent *e); + + private: + base::MessagePumpForUI &pump; +}; + +// This class implements a MessagePump needed for TYPE_UI MessageLoops on +// OS_LINUX platforms using QApplication event loop +class MessagePumpForUI : public MessagePump { + + public: + MessagePumpForUI(); + ~MessagePumpForUI(); + + virtual void Run(Delegate* delegate); + virtual void Quit(); + virtual void ScheduleWork(); + virtual void ScheduleDelayedWork(const Time& delayed_work_time); + + // Internal methods used for processing the pump callbacks. They are + // public for simplicity but should not be used directly. + // HandleDispatch is called after the poll has completed. + void HandleDispatch(); + + private: + // We may make recursive calls to Run, so we save state that needs to be + // separate between them in this structure type. + struct RunState { + Delegate* delegate; + + // Used to flag that the current Run() invocation should return ASAP. + bool should_quit; + + // Used to count how many Run() invocations are on the stack. + int run_depth; + + // Used internally for controlling whether we want a message pump + // iteration to be blocking or not. + bool more_work_is_plausible; + }; + + RunState* state_; + + // This is the time when we need to do delayed work. + Time delayed_work_time_; + + // MessagePump implementation for Qt based on the GLib implement. + // On Qt we use a QObject base class and the + // default qApp in order to process events through QEventLoop. + MessagePumpQt qt_pump; + + DISALLOW_COPY_AND_ASSIGN(MessagePumpForUI); +}; + +} // namespace base + +#endif // BASE_MESSAGE_PUMP_QT_H_