From 8169a79f11f25dad52133133c4d54d857c942d73 Mon Sep 17 00:00:00 2001
From: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
Date: Fri, 31 May 2013 10:49:33 +0200
Subject: [PATCH] Integrate the event loop with QApplication.

---
 example/main.cpp           |   5 +-
 lib/blinqapplication.cpp   | 233 +++++++++++++++++++++++++++++++++++++
 lib/blinqapplication.h     |  12 ++
 lib/blinqpage.cpp          | 229 +-----------------------------------
 lib/blinqpage.h            |   2 +-
 lib/lib.pro                |   2 +
 lib/web_contents_view_qt.h |   1 +
 7 files changed, 255 insertions(+), 229 deletions(-)
 create mode 100644 lib/blinqapplication.cpp
 create mode 100644 lib/blinqapplication.h

diff --git a/example/main.cpp b/example/main.cpp
index bae44ab1c..1b2c658c4 100644
--- a/example/main.cpp
+++ b/example/main.cpp
@@ -1,14 +1,15 @@
 #include <QtGui>
 #include <QtWidgets>
 
+#include <blinqapplication.h>
 #include <blinqpage.h>
 
 int main(int argc, char **argv)
 {
     printf("main called\n");
-    QApplication app(argc, argv);
+    BlinqApplication app(argc, argv);
 
-    BlinqPage page(argc, argv);
+    BlinqPage page;
 //    page.window()->show();
 
     return app.exec();
diff --git a/lib/blinqapplication.cpp b/lib/blinqapplication.cpp
new file mode 100644
index 000000000..2fb42e186
--- /dev/null
+++ b/lib/blinqapplication.cpp
@@ -0,0 +1,233 @@
+#include "blinqapplication.h"
+
+#include <math.h>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/message_loop.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "base/threading/thread_restrictions.h"
+#include "content/public/app/content_main_delegate.h"
+#include "content/public/app/content_main_runner.h"
+#include "content/public/browser/browser_main_runner.h"
+#include "content/public/common/content_paths.h"
+#include "content/public/common/main_function_params.h"
+#include "content/shell/shell_browser_context.h"
+#include "content/shell/shell_content_browser_client.h"
+#include "webkit/common/user_agent/user_agent_util.h"
+
+#include "web_contents_view_qt.h"
+
+namespace {
+
+static inline base::FilePath::StringType qStringToStringType(const QString &str)
+{
+#if defined(OS_POSIX)
+    return str.toStdString();
+#elif defined(OS_WIN)
+    return str.toStdWString();
+#endif
+}
+
+static QByteArray blinqProcessPath() {
+    static bool initialized = false;
+#ifdef BLINQ_PROCESS_PATH
+    static QByteArray processPath(BLINQ_PROCESS_PATH);
+#else
+    static QByteArray processPath;
+#endif
+    if (initialized)
+        return processPath;
+    // Allow overriding at runtime for the time being.
+    const QByteArray fromEnv = qgetenv("BLINQ_PROCESS_PATH");
+    if (!fromEnv.isEmpty())
+        processPath = fromEnv;
+    if (processPath.isEmpty())
+        qFatal("BLINQ_PROCESS_PATH environment variable not set or empty.");
+    initialized = true;
+    return processPath;
+}
+
+static void initializeBlinkPaths()
+{
+    static bool initialized = false;
+    if (initialized)
+        return;
+
+    PathService::Override(content::CHILD_PROCESS_EXE, base::FilePath(qStringToStringType(QString(blinqProcessPath()))));
+}
+
+// Return a timeout suitable for the glib loop, -1 to block forever,
+// 0 to return right away, or a timeout in milliseconds from now.
+int GetTimeIntervalMilliseconds(const base::TimeTicks& from) {
+  if (from.is_null())
+    return -1;
+
+  // Be careful here.  TimeDelta has a precision of microseconds, but we want a
+  // value in milliseconds.  If there are 5.5ms left, should the delay be 5 or
+  // 6?  It should be 6 to avoid executing delayed work too early.
+  int delay = static_cast<int>(
+      ceil((from - base::TimeTicks::Now()).InMillisecondsF()));
+
+  // If this value is negative, then we need to run delayed work soon.
+  return delay < 0 ? 0 : delay;
+}
+
+class MessagePump : public QObject,
+                    public base::MessagePump
+{
+public:
+    MessagePump()
+        : m_delegate(0)
+    {
+    }
+
+    virtual void Run(Delegate *delegate)
+    {
+        // It would be possible to do like the Android message loop and use
+        // Start(Delegate*) instead of Run to avoid blocking, but we still
+        // need to grab the command line arguments, so keep it simple for now
+        // by forcing the use of BlinqApplication.
+        m_delegate = delegate;
+        QApplication::exec();
+        m_delegate = 0;
+    }
+
+    virtual void Quit()
+    {
+        QCoreApplication::instance()->quit();
+    }
+
+    virtual void ScheduleWork()
+    {
+        QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+    }
+
+    virtual void ScheduleDelayedWork(const base::TimeTicks &delayed_work_time)
+    {
+        startTimer(GetTimeIntervalMilliseconds(delayed_work_time));
+    }
+
+protected:
+    virtual void customEvent(QEvent *ev)
+    {
+        if (handleScheduledWork())
+            QCoreApplication::postEvent(this, new QEvent(QEvent::User));
+    }
+
+    virtual void timerEvent(QTimerEvent *ev)
+    {
+        killTimer(ev->timerId());
+
+        base::TimeTicks next_delayed_work_time;
+        m_delegate->DoDelayedWork(&next_delayed_work_time);
+
+        if (!next_delayed_work_time.is_null())
+            startTimer(GetTimeIntervalMilliseconds(next_delayed_work_time));
+    }
+
+private:
+    bool handleScheduledWork() {
+        bool more_work_is_plausible = m_delegate->DoWork();
+
+        base::TimeTicks delayed_work_time;
+        more_work_is_plausible |= m_delegate->DoDelayedWork(&delayed_work_time);
+
+        if (more_work_is_plausible)
+            return true;
+
+        more_work_is_plausible |= m_delegate->DoIdleWork();
+        if (!more_work_is_plausible && !delayed_work_time.is_null())
+            startTimer(GetTimeIntervalMilliseconds(delayed_work_time));
+
+        return more_work_is_plausible;
+    }
+
+    Delegate *m_delegate;
+};
+
+base::MessagePump* messagePumpFactory()
+{
+    return new MessagePump;
+}
+
+class ContentBrowserClientQt : public content::ShellContentBrowserClient
+{
+public:
+    virtual content::WebContentsViewPort* OverrideCreateWebContentsView(content::WebContents* web_contents, content::RenderViewHostDelegateView** render_view_host_delegate_view)
+    {
+      fprintf(stderr, "OverrideCreateWebContentsView\n");
+        WebContentsViewQt* rv = new WebContentsViewQt(web_contents);
+        *render_view_host_delegate_view = rv;
+        return rv;
+    }
+};
+
+class ContentMainDelegateQt : public content::ContentMainDelegate
+{
+public:
+    content::ContentBrowserClient* CreateContentBrowserClient()
+    {
+        m_browserClient.reset(new ContentBrowserClientQt);
+        return m_browserClient.get();
+    }
+
+private:
+    scoped_ptr<ContentBrowserClientQt> m_browserClient;
+};
+
+}
+
+BlinqApplication::BlinqApplication(int &argc, char **argv)
+    : QApplication(argc, argv)
+{
+    {
+        int myArgc = argc + 3;
+        const char **myArgv = new const char *[myArgc];
+
+        for (int i = 0; i < argc; ++i)
+            myArgv[i] = argv[i];
+        QByteArray subProcessPathOption("--browser-subprocess-path=");
+        subProcessPathOption.append(blinqProcessPath());
+        myArgv[argc] = subProcessPathOption.constData();
+        myArgv[argc + 1] = "--no-sandbox";
+
+        std::string ua = webkit_glue::BuildUserAgentFromProduct("Qrome/0.1");
+
+        QByteArray userAgentParameter("--user-agent=");
+        userAgentParameter.append(QString::fromStdString(ua).toUtf8());
+        myArgv[argc + 2] = userAgentParameter.constData();
+
+        CommandLine::Init(myArgc, myArgv);
+
+        delete [] myArgv;
+    }
+
+    base::MessageLoop::InitMessagePumpForUIFactory(::messagePumpFactory);
+
+    static content::ContentMainRunner *runner = 0;
+    if (!runner) {
+        runner = content::ContentMainRunner::Create();
+        runner->Initialize(0, 0, new ContentMainDelegateQt);
+    }
+
+    initializeBlinkPaths();
+
+    static content::BrowserMainRunner *browserRunner = 0;
+    if (!browserRunner) {
+        //CommandLine::Init(0, 0);
+
+        browserRunner = content::BrowserMainRunner::Create();
+
+        browserRunner->Initialize(content::MainFunctionParams(*CommandLine::ForCurrentProcess()));
+    }
+
+    base::ThreadRestrictions::SetIOAllowed(true);
+}
+
+int BlinqApplication::exec()
+{
+    base::RunLoop runLoop;
+    runLoop.Run();
+}
diff --git a/lib/blinqapplication.h b/lib/blinqapplication.h
new file mode 100644
index 000000000..7b8c83770
--- /dev/null
+++ b/lib/blinqapplication.h
@@ -0,0 +1,12 @@
+#ifndef BLINQAPPLICATION_H
+#define BLINQAPPLICATION_H
+
+#include <QApplication>
+
+class Q_DECL_EXPORT BlinqApplication : public QApplication {
+public:
+    BlinqApplication(int &argc, char **argv);
+	static int exec();
+};
+
+#endif
\ No newline at end of file
diff --git a/lib/blinqpage.cpp b/lib/blinqpage.cpp
index a178566be..8a68ea79f 100644
--- a/lib/blinqpage.cpp
+++ b/lib/blinqpage.cpp
@@ -9,39 +9,25 @@
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/notification_service.h"
 #include "content/public/browser/web_contents_view.h"
-#include "content/public/browser/browser_main_runner.h"
-#include "content/public/app/content_main_runner.h"
-#include "content/public/app/content_main_delegate.h"
-#include "content/public/common/content_paths.h"
-#include "content/public/common/main_function_params.h"
 #include "net/url_request/url_request_context_getter.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/path_service.h"
-#include "base/files/file_path.h"
 #include "base/event_types.h"
-#include "base/command_line.h"
 #include "ui/gfx/insets.h"
-#include "base/message_loop.h"
 #include "ui/gfx/screen.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/rect_conversions.h"
 #include "ui/surface/transport_dib.h"
-#include "base/threading/thread_restrictions.h"
 #include "content/common/view_messages.h"
-#include "content/shell/shell_browser_context.h"
-#include "content/shell/app/shell_main_delegate.h"
-#include "content/shell/shell_content_browser_client.h"
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_view_host_impl.h"
 #include "content/browser/renderer_host/backing_store.h"
-#include "webkit/common/user_agent/user_agent_util.h"
+#include "content/shell/shell_browser_context.h"
+#include "content/shell/shell_content_browser_client.h"
 #include "skia/ext/platform_canvas.h"
 
 #include "backing_store_qt.h"
-#include "raster_window.h"
 #include "render_widget_host_view_qt.h"
-#include "web_contents_view_qt.h"
 
 #include <QByteArray>
 #include <QWindow>
@@ -71,68 +57,6 @@ private:
     Context *context;
 };
 
-class ContentBrowserClientQt : public content::ShellContentBrowserClient
-{
-public:
-    virtual content::WebContentsViewPort* OverrideCreateWebContentsView(content::WebContents* web_contents, content::RenderViewHostDelegateView** render_view_host_delegate_view)
-    {
-      fprintf(stderr, "OverrideCreateWebContentsView\n");
-        WebContentsViewQt* rv = new WebContentsViewQt(web_contents);
-        *render_view_host_delegate_view = rv;
-        return rv;
-    }
-};
-
-class ContentMainDelegateQt : public content::ContentMainDelegate
-{
-public:
-    content::ContentBrowserClient* CreateContentBrowserClient()
-    {
-        m_browserClient.reset(new ContentBrowserClientQt);
-        return m_browserClient.get();
-    }
-
-private:
-    scoped_ptr<ContentBrowserClientQt> m_browserClient;
-};
-
-static inline base::FilePath::StringType qStringToStringType(const QString &str)
-{
-#if defined(OS_POSIX)
-    return str.toStdString();
-#elif defined(OS_WIN)
-    return str.toStdWString();
-#endif
-}
-
-static QByteArray blinqProcessPath() {
-    static bool initialized = false;
-#ifdef BLINQ_PROCESS_PATH
-    static QByteArray processPath(BLINQ_PROCESS_PATH);
-#else
-    static QByteArray processPath;
-#endif
-    if (initialized)
-        return processPath;
-    // Allow overriding at runtime for the time being.
-    const QByteArray fromEnv = qgetenv("BLINQ_PROCESS_PATH");
-    if (!fromEnv.isEmpty())
-        processPath = fromEnv;
-    if (processPath.isEmpty())
-        qFatal("BLINQ_PROCESS_PATH environment variable not set or empty.");
-    initialized = true;
-    return processPath;
-}
-
-static void initializeBlinkPaths()
-{
-    static bool initialized = false;
-    if (initialized)
-        return;
-
-    PathService::Override(content::CHILD_PROCESS_EXE, base::FilePath(qStringToStringType(QString(blinqProcessPath()))));
-}
-
 class Context : public content::BrowserContext
 {
 public:
@@ -201,108 +125,6 @@ public:
     }
 };
 
-// Return a timeout suitable for the glib loop, -1 to block forever,
-// 0 to return right away, or a timeout in milliseconds from now.
-int GetTimeIntervalMilliseconds(const base::TimeTicks& from) {
-  if (from.is_null())
-    return -1;
-
-  // Be careful here.  TimeDelta has a precision of microseconds, but we want a
-  // value in milliseconds.  If there are 5.5ms left, should the delay be 5 or
-  // 6?  It should be 6 to avoid executing delayed work too early.
-  int delay = static_cast<int>(
-      ceil((from - base::TimeTicks::Now()).InMillisecondsF()));
-
-  // If this value is negative, then we need to run delayed work soon.
-  return delay < 0 ? 0 : delay;
-}
-
-#if 0
-class MessagePump : public QObject,
-                    public base::MessagePump
-{
-public:
-    struct DelayedWorkEvent : public QEvent
-    {
-    public:
-        DelayedWorkEvent(int msecs)
-            : QEvent(static_cast<QEvent::Type>(QEvent::User + 1))
-            , m_secs(msecs)
-        {}
-
-        int m_secs;
-    };
-
-    MessagePump()
-        : m_delegate(0)
-    {
-    }
-
-    virtual void Run(Delegate *delegate)
-    {
-        m_delegate = delegate;
-        printf("RUN\n");
-    }
-
-    virtual void Quit()
-    {
-        printf("QUIT?!\n");
-    }
-
-    virtual void ScheduleWork()
-    {
-        QCoreApplication::postEvent(this, new QEvent(QEvent::User));
-        printf("ScheduleWork\n");
-    }
-
-    virtual void ScheduleDelayedWork(const base::TimeTicks &delayed_work_time)
-    {
-        printf("Schedule Delayed Work %d\n", GetTimeIntervalMilliseconds(delayed_work_time));
-//        QCoreApplication::postEvent(this, new DelayedWorkEvent(GetTimeIntervalMilliseconds(delayed_work_time)));
-        QCoreApplication::postEvent(this, new QEvent(QEvent::User));
-    }
-
-protected:
-    virtual void customEvent(QEvent *ev)
-    {
-        if (ev->type() == QEvent::User + 1) {
-            startTimer(static_cast<DelayedWorkEvent*>(ev)->m_secs);
-            return;
-        }
-        printf("customEvent\n");
-        if (!m_delegate)
-            return;
-        if (m_delegate->DoWork())
-            return;
-        m_delegate->DoIdleWork();
-    }
-
-    virtual void timerEvent(QTimerEvent *ev)
-    {
-        printf("timerEvent\n");
-        killTimer(ev->timerId());
-        if (!m_delegate)
-            return;
-        base::TimeTicks next_delayed_work_time;
-        if (!m_delegate->DoDelayedWork(&next_delayed_work_time))
-            m_delegate->DoIdleWork();
-
-        if (!next_delayed_work_time.is_null()) {
-            QCoreApplication::postEvent(this, new QEvent(QEvent::User));
-//            startTimer(GetTimeIntervalMilliseconds(next_delayed_work_time));
-        }
-    }
-
-private:
-    Delegate *m_delegate;
-};
-
-base::MessagePump* messagePumpFactory()
-{
-    return new MessagePump;
-}
-#endif
-
 }
 
 class BlinqPagePrivate
@@ -312,51 +134,8 @@ public:
     scoped_ptr<content::WebContents> contents;
 };
 
-BlinqPage::BlinqPage(int argc, char **argv)
+BlinqPage::BlinqPage()
 {
-    {
-        int myArgc = argc + 3;
-        const char **myArgv = new const char *[myArgc];
-
-        for (int i = 0; i < argc; ++i)
-            myArgv[i] = argv[i];
-        QByteArray subProcessPathOption("--browser-subprocess-path=");
-        subProcessPathOption.append(blinqProcessPath());
-        myArgv[argc] = subProcessPathOption.constData();
-        myArgv[argc + 1] = "--no-sandbox";
-
-        std::string ua = webkit_glue::BuildUserAgentFromProduct("Qrome/0.1");
-
-        QByteArray userAgentParameter("--user-agent=");
-        userAgentParameter.append(QString::fromStdString(ua).toUtf8());
-        myArgv[argc + 2] = userAgentParameter.constData();
-
-        CommandLine::Init(myArgc, myArgv);
-
-        delete [] myArgv;
-
-//        base::MessageLoop::InitMessagePumpForUIFactory(::messagePumpFactory);
-    }
-
-    static content::ContentMainRunner *runner = 0;
-    if (!runner) {
-        runner = content::ContentMainRunner::Create();
-        runner->Initialize(0, 0, new ContentMainDelegateQt);
-    }
-
-    initializeBlinkPaths();
-
-    static content::BrowserMainRunner *browserRunner = 0;
-    if (!browserRunner) {
-        //CommandLine::Init(0, 0);
-
-        browserRunner = content::BrowserMainRunner::Create();
-
-        browserRunner->Initialize(content::MainFunctionParams(*CommandLine::ForCurrentProcess()));
-    }
-
-    base::ThreadRestrictions::SetIOAllowed(true);
-
     d.reset(new BlinqPagePrivate);
 
     d->context.reset(static_cast<content::ShellContentBrowserClient*>(content::GetContentClient()->browser())->browser_context());
@@ -367,8 +146,6 @@ BlinqPage::BlinqPage(int argc, char **argv)
 //                                         content::Referrer(),
 //                                         content::PAGE_TRANSITION_TYPED,
 //                                         std::string());
-
-    MessageLoopForUI::current()->Run();
 }
 
 BlinqPage::~BlinqPage()
diff --git a/lib/blinqpage.h b/lib/blinqpage.h
index 6c3933b83..c07619d8c 100644
--- a/lib/blinqpage.h
+++ b/lib/blinqpage.h
@@ -11,7 +11,7 @@ class BlinqPagePrivate;
 class Q_DECL_EXPORT BlinqPage
 {
 public:
-    BlinqPage(int argc, char **argv);
+    BlinqPage();
     ~BlinqPage();
 
     QWindow *window();
diff --git a/lib/lib.pro b/lib/lib.pro
index 59c557792..cb766577e 100644
--- a/lib/lib.pro
+++ b/lib/lib.pro
@@ -20,6 +20,7 @@ QT += gui-private widgets
 
 SOURCES = \
         backing_store_qt.cpp \
+        blinqapplication.cpp \
         blinqpage.cpp \
         raster_window.cpp \
         render_widget_host_view_qt.cpp \
@@ -29,6 +30,7 @@ SOURCES = \
 
 HEADERS = \
         backing_store_qt.h \
+        blinqapplication.h \
         blinqpage.h \
         raster_window.h \
         render_widget_host_view_qt.h \
diff --git a/lib/web_contents_view_qt.h b/lib/web_contents_view_qt.h
index 068df4e7d..c5d38a0ef 100644
--- a/lib/web_contents_view_qt.h
+++ b/lib/web_contents_view_qt.h
@@ -7,6 +7,7 @@
 #include "content/port/browser/render_view_host_delegate_view.h"
 #include "content/port/browser/web_contents_view_port.h"
 #include "render_widget_host_view_qt.h"
+#include "raster_window.h"
 
 class WebContentsViewQt
     : public content::WebContentsViewPort
-- 
GitLab