diff --git cef_paths2.gypi cef_paths2.gypi
index 3c71213..227952e 100644
--- cef_paths2.gypi
+++ cef_paths2.gypi
@@ -368,6 +368,8 @@
       'tests/cefclient/browser/dialog_handler_gtk.cc',
       'tests/cefclient/browser/dialog_handler_gtk.h',
       'tests/cefclient/browser/main_context_impl_posix.cc',
+      'tests/cefclient/browser/main_message_loop_multithreaded_gtk.cc',
+      'tests/cefclient/browser/main_message_loop_multithreaded_gtk.h',
       'tests/cefclient/browser/print_handler_gtk.cc',
       'tests/cefclient/browser/print_handler_gtk.h',
       'tests/cefclient/browser/resource_util_linux.cc',
diff --git include/internal/cef_types.h include/internal/cef_types.h
index 5bac44a..384a733 100644
--- include/internal/cef_types.h
+++ include/internal/cef_types.h
@@ -181,7 +181,7 @@ typedef struct _cef_settings_t {
   // Set to true (1) to have the browser process message loop run in a separate
   // thread. If false (0) than the CefDoMessageLoopWork() function must be
   // called from your application message loop. This option is only supported on
-  // Windows.
+  // Windows and Linux.
   ///
   int multi_threaded_message_loop;
 
diff --git libcef/browser/browser_host_impl.cc libcef/browser/browser_host_impl.cc
index 2bad458..d290ba7 100644
--- libcef/browser/browser_host_impl.cc
+++ libcef/browser/browser_host_impl.cc
@@ -205,6 +205,7 @@ bool CefBrowserHost::CreateBrowser(
     const CefString& url,
     const CefBrowserSettings& settings,
     CefRefPtr<CefRequestContext> request_context) {
+  printf("CefBrowserHost::CreateBrowser\n");
   // Verify that the context is in a valid state.
   if (!CONTEXT_STATE_VALID()) {
     NOTREACHED() << "context not valid";
@@ -235,7 +236,7 @@ bool CefBrowserHost::CreateBrowser(
   CreateBrowserHelper* helper = new CreateBrowserHelper(
       windowInfo, client, url, settings, request_context);
   CEF_POST_TASK(CEF_UIT, base::BindOnce(CreateBrowserWithHelper, helper));
-
+  printf("CefBrowserHost::CreateBrowser end\n");
   return true;
 }
 
@@ -246,6 +247,7 @@ CefRefPtr<CefBrowser> CefBrowserHost::CreateBrowserSync(
     const CefString& url,
     const CefBrowserSettings& settings,
     CefRefPtr<CefRequestContext> request_context) {
+  printf("CefBrowserHost::CreateBrowserSync\n");
   // Verify that the context is in a valid state.
   if (!CONTEXT_STATE_VALID()) {
     NOTREACHED() << "context not valid";
@@ -285,6 +287,7 @@ CefRefPtr<CefBrowser> CefBrowserHost::CreateBrowserSync(
 
   CefRefPtr<CefBrowserHostImpl> browser =
       CefBrowserHostImpl::Create(create_params);
+  printf("CefBrowserHost::CreateBrowserSync end\n");
   return browser.get();
 }
 
@@ -402,6 +405,7 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::CreateInternal(
     std::unique_ptr<CefBrowserPlatformDelegate> platform_delegate,
     CefRefPtr<CefExtension> extension) {
   CEF_REQUIRE_UIT();
+  printf("CefBrowserHostImpl::CreateInternal\n");
   DCHECK(web_contents);
   DCHECK(browser_info);
   DCHECK(request_context);
@@ -438,6 +442,7 @@ CefRefPtr<CefBrowserHostImpl> CefBrowserHostImpl::CreateInternal(
 
   // 1. Notify the browser's LifeSpanHandler. This must always be the first
   // notification for the browser.
+  printf("OnAfterCreated\n");
   if (client.get()) {
     CefRefPtr<CefLifeSpanHandler> handler = client->GetLifeSpanHandler();
     if (handler.get())
diff --git libcef/browser/context.cc libcef/browser/context.cc
index 633ca17..c53ea6e 100644
--- libcef/browser/context.cc
+++ libcef/browser/context.cc
@@ -343,7 +343,7 @@ bool CefContext::Initialize(const CefMainArgs& args,
   init_thread_id_ = base::PlatformThread::CurrentId();
   settings_ = settings;
 
-#if !defined(OS_WIN)
+#if !(defined(OS_WIN) || defined(OS_LINUX))
   if (settings.multi_threaded_message_loop) {
     NOTIMPLEMENTED() << "multi_threaded_message_loop is not supported.";
     return false;
diff --git libcef/browser/native/browser_platform_delegate_native_linux.cc libcef/browser/native/browser_platform_delegate_native_linux.cc
index a20f5d3..0559ff4 100644
--- libcef/browser/native/browser_platform_delegate_native_linux.cc
+++ libcef/browser/native/browser_platform_delegate_native_linux.cc
@@ -57,6 +57,7 @@ void CefBrowserPlatformDelegateNativeLinux::BrowserDestroyed(
 }
 
 bool CefBrowserPlatformDelegateNativeLinux::CreateHostWindow() {
+  printf("CefBrowserPlatformDelegateNativeLinux::CreateHostWindow\n");
   DCHECK(!window_x11_);
   DCHECK(!window_widget_);
 
@@ -77,17 +78,17 @@ bool CefBrowserPlatformDelegateNativeLinux::CreateHostWindow() {
 
   // Add a reference that will be released in BrowserDestroyed().
   browser_->AddRef();
-
+  printf("A\n");
   CefWindowDelegateView* delegate_view =
       new CefWindowDelegateView(GetBackgroundColor());
   delegate_view->Init(window_info_.window, browser_->web_contents(),
                       gfx::Rect(gfx::Point(), rect.size()));
-
+  printf("B\n");
   window_widget_ = delegate_view->GetWidget();
   window_widget_->Show();
-
+  printf("C\n");
   window_x11_->Show();
-
+  printf("D\n");
   // As an additional requirement on Linux, we must set the colors for the
   // render widgets in webkit.
   content::RendererPreferences* prefs =
@@ -114,7 +115,7 @@ bool CefBrowserPlatformDelegateNativeLinux::CreateHostWindow() {
   prefs->subpixel_rendering = params.subpixel_rendering;
 
   browser_->web_contents()->GetRenderViewHost()->SyncRendererPrefs();
-
+  printf("E\n");
   return true;
 }
 
diff --git libcef/browser/native/window_x11.cc libcef/browser/native/window_x11.cc
index 5429fd4..817e7b6 100644
--- libcef/browser/native/window_x11.cc
+++ libcef/browser/native/window_x11.cc
@@ -90,6 +90,7 @@ CefWindowX11::CefWindowX11(CefRefPtr<CefBrowserHostImpl> browser,
       bounds_(bounds),
       focus_pending_(false),
       weak_ptr_factory_(this) {
+  printf("CefWindowX11\n");
   if (parent_xwindow_ == x11::None)
     parent_xwindow_ = DefaultRootWindow(xdisplay_);
 
@@ -104,6 +105,7 @@ CefWindowX11::CefWindowX11(CefRefPtr<CefBrowserHostImpl> browser,
                            InputOutput,
                            CopyFromParent,  // visual
                            CWBackPixmap | CWOverrideRedirect, &swa);
+  CHECK(xwindow_);
 
   if (ui::PlatformEventSource::GetInstance())
     ui::PlatformEventSource::GetInstance()->AddPlatformEventDispatcher(this);
@@ -152,6 +154,7 @@ void CefWindowX11::Close() {
 }
 
 void CefWindowX11::Show() {
+  printf("CefWindowX11::Show()\n");
   if (xwindow_ == x11::None)
     return;
 
@@ -211,6 +214,7 @@ void CefWindowX11::Hide() {
 }
 
 void CefWindowX11::Focus() {
+  printf("CefWindowX11::Focus\n");
   if (xwindow_ == x11::None || !window_mapped_)
     return;
 
@@ -275,6 +279,7 @@ bool CefWindowX11::CanDispatchEvent(const ui::PlatformEvent& event) {
 }
 
 uint32_t CefWindowX11::DispatchEvent(const ui::PlatformEvent& event) {
+  printf("CefWindowX11::DispatchEvent\n");
   XEvent* xev = event;
   switch (xev->type) {
     case ConfigureNotify: {
diff --git tests/cefclient/browser/browser_window_osr_gtk.cc tests/cefclient/browser/browser_window_osr_gtk.cc
index 0d4a784..619644a 100644
--- tests/cefclient/browser/browser_window_osr_gtk.cc
+++ tests/cefclient/browser/browser_window_osr_gtk.cc
@@ -1215,7 +1215,7 @@ void BrowserWindowOsrGtk::OnCursorChange(
 
   // Retrieve the X11 display shared with Chromium.
   ::Display* xdisplay = cef_get_xdisplay();
-  DCHECK(xdisplay);
+  CHECK(xdisplay != 0);
 
   // Retrieve the X11 window handle for the GTK widget.
   ::Window xwindow = GDK_WINDOW_XID(gtk_widget_get_window(glarea_));
diff --git tests/cefclient/browser/browser_window_std_gtk.cc tests/cefclient/browser/browser_window_std_gtk.cc
index 8256c35..f5a9d93 100644
--- tests/cefclient/browser/browser_window_std_gtk.cc
+++ tests/cefclient/browser/browser_window_std_gtk.cc
@@ -29,6 +29,7 @@ namespace {
 
 void SetXWindowVisible(::Window xwindow, bool visible) {
   ::Display* xdisplay = cef_get_xdisplay();
+  CHECK(xdisplay != 0);
 
   // Retrieve the atoms required by the below XChangeProperty call.
   const char* kAtoms[] = {"_NET_WM_STATE", "ATOM", "_NET_WM_STATE_HIDDEN"};
@@ -67,6 +68,7 @@ void SetXWindowBounds(::Window xwindow,
                       size_t width,
                       size_t height) {
   ::Display* xdisplay = cef_get_xdisplay();
+  CHECK(xdisplay != 0);
   XWindowChanges changes = {0};
   changes.x = x;
   changes.y = y;
@@ -88,6 +90,7 @@ void BrowserWindowStdGtk::CreateBrowser(
     const CefRect& rect,
     const CefBrowserSettings& settings,
     CefRefPtr<CefRequestContext> request_context) {
+  printf("CreateBrowser\n");
   REQUIRE_MAIN_THREAD();
 
   CefWindowInfo window_info;
@@ -119,6 +122,7 @@ void BrowserWindowStdGtk::ShowPopup(ClientWindowHandle parent_handle,
   if (browser_) {
     ::Window parent_xwindow = GetXWindowForWidget(parent_handle);
     ::Display* xdisplay = cef_get_xdisplay();
+    CHECK(xdisplay != 0);
     ::Window xwindow = browser_->GetHost()->GetWindowHandle();
     DCHECK(xwindow);
 
diff --git tests/cefclient/browser/main_context_impl.cc tests/cefclient/browser/main_context_impl.cc
index 5ccedae..8154ba5 100644
--- tests/cefclient/browser/main_context_impl.cc
+++ tests/cefclient/browser/main_context_impl.cc
@@ -135,7 +135,7 @@ bool MainContextImpl::UseWindowlessRendering() {
 }
 
 void MainContextImpl::PopulateSettings(CefSettings* settings) {
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_LINUX)
   settings->multi_threaded_message_loop =
       command_line_->HasSwitch(switches::kMultiThreadedMessageLoop);
 #endif
diff --git tests/cefclient/browser/main_message_loop_multithreaded_gtk.cc tests/cefclient/browser/main_message_loop_multithreaded_gtk.cc
new file mode 100644
index 0000000..d214afe
--- /dev/null
+++ tests/cefclient/browser/main_message_loop_multithreaded_gtk.cc
@@ -0,0 +1,128 @@
+// Copyright (c) 2018 The Chromium Embedded Framework 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 "tests/cefclient/browser/main_message_loop_multithreaded_gtk.h"
+
+#include <X11/Xlib.h>
+#include <gtk/gtkmain.h>
+
+#include "include/base/cef_bind.h"
+#include "include/base/cef_logging.h"
+#include "include/wrapper/cef_closure_task.h"
+
+namespace client {
+
+namespace {
+
+// Same as g_idle_add() but specifying the GMainContext.
+guint idle_add(GMainContext* main_context,
+               GSourceFunc function,
+               gpointer data) {
+  GSource* source = g_idle_source_new();
+  g_source_set_callback(source, function, data, nullptr);
+  guint id = g_source_attach(source, main_context);
+  g_source_unref(source);
+  return id;
+}
+
+// Same as g_timeout_add() but specifying the GMainContext.
+guint timeout_add(GMainContext* main_context,
+                  guint interval,
+                  GSourceFunc function,
+                  gpointer data) {
+  GSource* source = g_timeout_source_new(interval);
+  g_source_set_callback(source, function, data, nullptr);
+  guint id = g_source_attach(source, main_context);
+  g_source_unref(source);
+  return id;
+}
+
+}  // namespace
+
+MainMessageLoopMultithreadedGtk::MainMessageLoopMultithreadedGtk()
+    : thread_id_(base::PlatformThread::CurrentId()) {
+  // Initialize Xlib support for concurrent threads. This function must be the
+  // first Xlib function a multi-threaded program calls, and it must complete
+  // before any other Xlib call is made.
+  CHECK(XInitThreads() != 0);
+
+  // Initialize GDK thread support.
+  gdk_threads_init();
+  gdk_threads_enter();
+}
+
+MainMessageLoopMultithreadedGtk::~MainMessageLoopMultithreadedGtk() {
+  DCHECK(RunsTasksOnCurrentThread());
+  DCHECK(queued_tasks_.empty());
+}
+
+int MainMessageLoopMultithreadedGtk::Run() {
+  DCHECK(RunsTasksOnCurrentThread());
+
+  // Chromium uses the default GLib context so we create our own context.
+  main_context_ = g_main_context_new();
+  main_loop_ = g_main_loop_new(main_context_, TRUE);
+
+  // Check the queue when GTK is idle, or at least every 100ms.
+  // TODO(cef): It might be more efficient to use input functions
+  // (gdk_input_add) and trigger by writing to an fd.
+  idle_add(main_context_, MainMessageLoopMultithreadedGtk::TriggerRunTasks,
+           this);
+  timeout_add(main_context_, 100,
+              MainMessageLoopMultithreadedGtk::TriggerRunTasks, this);
+
+  // Block until g_main_loop_quit().
+  g_main_loop_run(main_loop_);
+
+  // Release GLib resources.
+  g_main_loop_unref(main_loop_);
+  main_loop_ = nullptr;
+  g_main_context_unref(main_context_);
+  main_context_ = nullptr;
+
+  gdk_threads_leave();
+
+  return 0;
+}
+
+void MainMessageLoopMultithreadedGtk::Quit() {
+  PostTask(CefCreateClosureTask(base::Bind(
+      &MainMessageLoopMultithreadedGtk::DoQuit, base::Unretained(this))));
+}
+
+void MainMessageLoopMultithreadedGtk::PostTask(CefRefPtr<CefTask> task) {
+  base::AutoLock lock_scope(lock_);
+
+  // Queue the task.
+  queued_tasks_.push(task);
+}
+
+bool MainMessageLoopMultithreadedGtk::RunsTasksOnCurrentThread() const {
+  return (thread_id_ == base::PlatformThread::CurrentId());
+}
+
+// static
+int MainMessageLoopMultithreadedGtk::TriggerRunTasks(void* self) {
+  static_cast<MainMessageLoopMultithreadedGtk*>(self)->RunTasks();
+  return G_SOURCE_CONTINUE;
+}
+
+void MainMessageLoopMultithreadedGtk::RunTasks() {
+  DCHECK(RunsTasksOnCurrentThread());
+  base::AutoLock lock_scope(lock_);
+
+  // Execute all queued tasks.
+  while (!queued_tasks_.empty()) {
+    CefRefPtr<CefTask> task = queued_tasks_.front();
+    queued_tasks_.pop();
+    task->Execute();
+  }
+}
+
+void MainMessageLoopMultithreadedGtk::DoQuit() {
+  DCHECK(RunsTasksOnCurrentThread());
+  g_main_loop_quit(main_loop_);
+}
+
+}  // namespace client
diff --git tests/cefclient/browser/main_message_loop_multithreaded_gtk.h tests/cefclient/browser/main_message_loop_multithreaded_gtk.h
new file mode 100644
index 0000000..69cddda
--- /dev/null
+++ tests/cefclient/browser/main_message_loop_multithreaded_gtk.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2018 The Chromium Embedded Framework 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 CEF_TESTS_CEFCLIENT_BROWSER_MAIN_MESSAGE_LOOP_MULTITHREADED_GTK_H_
+#define CEF_TESTS_CEFCLIENT_BROWSER_MAIN_MESSAGE_LOOP_MULTITHREADED_GTK_H_
+#pragma once
+
+#include <queue>
+
+#include <gdk/gdk.h>
+
+#include "include/base/cef_lock.h"
+#include "include/base/cef_platform_thread.h"
+#include "tests/shared/browser/main_message_loop.h"
+
+namespace client {
+
+// Represents the main message loop in the browser process when using multi-
+// threaded message loop mode on Windows. In this mode there is no Chromium
+// message loop running on the main application thread. Instead, this
+// implementation utilizes a hidden message window for running tasks.
+class MainMessageLoopMultithreadedGtk : public MainMessageLoop {
+ public:
+  MainMessageLoopMultithreadedGtk();
+  ~MainMessageLoopMultithreadedGtk();
+
+  // MainMessageLoop methods.
+  int Run() OVERRIDE;
+  void Quit() OVERRIDE;
+  void PostTask(CefRefPtr<CefTask> task) OVERRIDE;
+  bool RunsTasksOnCurrentThread() const OVERRIDE;
+
+ private:
+  static int TriggerRunTasks(void* self);
+  void RunTasks();
+  void DoQuit();
+
+  base::PlatformThreadId thread_id_;
+
+  GMainContext* main_context_;
+  GMainLoop* main_loop_;
+
+  base::Lock lock_;
+
+  // Must be protected by |lock_|.
+  std::queue<CefRefPtr<CefTask>> queued_tasks_;
+
+  DISALLOW_COPY_AND_ASSIGN(MainMessageLoopMultithreadedGtk);
+};
+
+}  // namespace client
+
+#endif  // CEF_TESTS_CEFCLIENT_BROWSER_MAIN_MESSAGE_LOOP_MULTITHREADED_GTK_H_
diff --git tests/cefclient/browser/root_window_gtk.cc tests/cefclient/browser/root_window_gtk.cc
index 480dd09..598e11f 100644
--- tests/cefclient/browser/root_window_gtk.cc
+++ tests/cefclient/browser/root_window_gtk.cc
@@ -243,6 +243,7 @@ void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings,
                                      bool initially_hidden) {
   REQUIRE_MAIN_THREAD();
   DCHECK(!window_);
+  printf("CreateRootWindow\n");
 
   // TODO(port): If no x,y position is specified the window will always appear
   // in the upper-left corner. Maybe there's a better default place to put it?
@@ -259,6 +260,7 @@ void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings,
   }
 
   window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+  CHECK(window_);
   gtk_window_set_default_size(GTK_WINDOW(window_), width, height);
   g_signal_connect(G_OBJECT(window_), "focus-in-event",
                    G_CALLBACK(&RootWindowGtk::WindowFocusIn), this);
@@ -359,6 +361,7 @@ void RootWindowGtk::CreateRootWindow(const CefBrowserSettings& settings,
 
 void RootWindowGtk::OnBrowserCreated(CefRefPtr<CefBrowser> browser) {
   REQUIRE_MAIN_THREAD();
+  printf("OnBrowserCreated\n");
 
   // For popup browsers create the root window once the browser has been
   // created.
@@ -463,6 +466,8 @@ void RootWindowGtk::NotifyDestroyedIfDone() {
 gboolean RootWindowGtk::WindowFocusIn(GtkWidget* widget,
                                       GdkEventFocus* event,
                                       RootWindowGtk* self) {
+  printf("WindowFocusIn\n");
+  REQUIRE_MAIN_THREAD();
   if (event->in && self->browser_window_.get()) {
     self->browser_window_->SetFocus(true);
     self->delegate_->OnRootWindowActivated(self);
@@ -477,6 +482,8 @@ gboolean RootWindowGtk::WindowFocusIn(GtkWidget* widget,
 gboolean RootWindowGtk::WindowState(GtkWidget* widget,
                                     GdkEventWindowState* event,
                                     RootWindowGtk* self) {
+  printf("WindowState\n");
+  REQUIRE_MAIN_THREAD();
   // Called when the root window is iconified or restored. Hide the browser
   // window when the root window is iconified to reduce resource usage.
   if ((event->changed_mask & GDK_WINDOW_STATE_ICONIFIED) &&
@@ -494,6 +501,8 @@ gboolean RootWindowGtk::WindowState(GtkWidget* widget,
 gboolean RootWindowGtk::WindowConfigure(GtkWindow* window,
                                         GdkEvent* event,
                                         RootWindowGtk* self) {
+  printf("WindowConfigure\n");
+  REQUIRE_MAIN_THREAD();
   // Called when size, position or stack order changes.
   CefRefPtr<CefBrowser> browser = self->GetBrowser();
   if (browser.get()) {
@@ -543,6 +552,9 @@ gboolean RootWindowGtk::WindowDelete(GtkWidget* widget,
 void RootWindowGtk::VboxSizeAllocated(GtkWidget* widget,
                                       GtkAllocation* allocation,
                                       RootWindowGtk* self) {
+  printf("VboxSizeAllocated\n");
+  REQUIRE_MAIN_THREAD();
+
   // Offset browser positioning by any controls that will appear in the client
   // area.
   const int ux_height = self->toolbar_height_ + self->menubar_height_;
@@ -561,6 +573,8 @@ void RootWindowGtk::VboxSizeAllocated(GtkWidget* widget,
 void RootWindowGtk::MenubarSizeAllocated(GtkWidget* widget,
                                          GtkAllocation* allocation,
                                          RootWindowGtk* self) {
+  printf("MenubarSizeAllocated\n");
+  REQUIRE_MAIN_THREAD();
   self->menubar_height_ = allocation->height;
 }
 
diff --git tests/cefclient/browser/root_window_manager.cc tests/cefclient/browser/root_window_manager.cc
index 4258333..8444fe5 100644
--- tests/cefclient/browser/root_window_manager.cc
+++ tests/cefclient/browser/root_window_manager.cc
@@ -159,6 +159,11 @@ scoped_refptr<RootWindow> RootWindowManager::CreateRootWindowAsPopup(
     CefBrowserSettings& settings) {
   CEF_REQUIRE_UI_THREAD();
 
+  if (!temp_window_) {
+    // TempWindow must be created on the UI thread.
+    temp_window_.reset(new TempWindow());
+  }
+
   MainContext::Get()->PopulateBrowserSettings(&settings);
 
   scoped_refptr<RootWindow> root_window =
@@ -390,8 +395,9 @@ void RootWindowManager::OnRootWindowDestroyed(RootWindow* root_window) {
   }
 
   if (terminate_when_all_windows_closed_ && root_windows_.empty()) {
-    // Quit the main message loop after all windows have closed.
-    MainMessageLoop::Get()->Quit();
+    // All windows have closed. Clean up on the UI thread.
+    CefPostTask(TID_UI, base::Bind(&RootWindowManager::CleanupOnUIThread,
+                                   base::Unretained(this)));
   }
 }
 
@@ -440,4 +446,16 @@ void RootWindowManager::CreateExtensionWindow(
   }
 }
 
+void RootWindowManager::CleanupOnUIThread() {
+  CEF_REQUIRE_UI_THREAD();
+
+  if (temp_window_) {
+    // TempWindow must be destroyed on the UI thread.
+    temp_window_.reset(nullptr);
+  }
+
+  // Quit the main message loop.
+  MainMessageLoop::Get()->Quit();
+}
+
 }  // namespace client
diff --git tests/cefclient/browser/root_window_manager.h tests/cefclient/browser/root_window_manager.h
index 23e6075..f98f41e 100644
--- tests/cefclient/browser/root_window_manager.h
+++ tests/cefclient/browser/root_window_manager.h
@@ -106,6 +106,8 @@ class RootWindowManager : public RootWindow::Delegate {
                              const base::Closure& close_callback,
                              bool with_osr) OVERRIDE;
 
+  void CleanupOnUIThread();
+
   const bool terminate_when_all_windows_closed_;
   bool request_context_per_browser_;
   bool request_context_shared_cache_;
@@ -124,7 +126,7 @@ class RootWindowManager : public RootWindow::Delegate {
   CefRefPtr<CefBrowser> active_browser_;
 
   // Singleton window used as the temporary parent for popup browsers.
-  TempWindow temp_window_;
+  scoped_ptr<TempWindow> temp_window_;
 
   CefRefPtr<CefRequestContext> shared_request_context_;
 
diff --git tests/cefclient/browser/temp_window_mac.h tests/cefclient/browser/temp_window_mac.h
index a4b968a..0bec1e0 100644
--- tests/cefclient/browser/temp_window_mac.h
+++ tests/cefclient/browser/temp_window_mac.h
@@ -11,7 +11,7 @@
 namespace client {
 
 // Represents a singleton hidden window that acts as a temporary parent for
-// popup browsers.
+// popup browsers. Only accessed on the UI thread.
 class TempWindowMac {
  public:
   // Returns the singleton window handle.
@@ -20,6 +20,8 @@ class TempWindowMac {
  private:
   // A single instance will be created/owned by RootWindowManager.
   friend class RootWindowManager;
+  // Allow deletion via scoped_ptr only.
+  friend struct base::DefaultDeleter<TempWindowMac>;
 
   TempWindowMac();
   ~TempWindowMac();
diff --git tests/cefclient/browser/temp_window_win.h tests/cefclient/browser/temp_window_win.h
index 6498a45..b5f312e 100644
--- tests/cefclient/browser/temp_window_win.h
+++ tests/cefclient/browser/temp_window_win.h
@@ -11,7 +11,7 @@
 namespace client {
 
 // Represents a singleton hidden window that acts as a temporary parent for
-// popup browsers.
+// popup browsers. Only accessed on the UI thread.
 class TempWindowWin {
  public:
   // Returns the singleton window handle.
@@ -20,6 +20,8 @@ class TempWindowWin {
  private:
   // A single instance will be created/owned by RootWindowManager.
   friend class RootWindowManager;
+  // Allow deletion via scoped_ptr only.
+  friend struct base::DefaultDeleter<TempWindowWin>;
 
   TempWindowWin();
   ~TempWindowWin();
diff --git tests/cefclient/browser/temp_window_x11.cc tests/cefclient/browser/temp_window_x11.cc
index ca9dad7..051cdfd 100644
--- tests/cefclient/browser/temp_window_x11.cc
+++ tests/cefclient/browser/temp_window_x11.cc
@@ -16,6 +16,7 @@ namespace {
 // Create the temp window.
 ::Window CreateTempWindow() {
   ::Display* xdisplay = cef_get_xdisplay();
+  CHECK(xdisplay != 0);
   ::Window parent_xwindow = DefaultRootWindow(xdisplay);
 
   XSetWindowAttributes swa;
@@ -33,6 +34,7 @@ namespace {
 // Close the temp window.
 void CloseTempWindow(::Window xwindow) {
   ::Display* xdisplay = cef_get_xdisplay();
+  CHECK(xdisplay != 0);
   XDestroyWindow(xdisplay, xwindow);
 }
 
diff --git tests/cefclient/browser/temp_window_x11.h tests/cefclient/browser/temp_window_x11.h
index 4d98698..08e452e 100644
--- tests/cefclient/browser/temp_window_x11.h
+++ tests/cefclient/browser/temp_window_x11.h
@@ -11,7 +11,7 @@
 namespace client {
 
 // Represents a singleton hidden window that acts as a temporary parent for
-// popup browsers.
+// popup browsers. Only accessed on the UI thread.
 class TempWindowX11 {
  public:
   // Returns the singleton window handle.
@@ -20,6 +20,8 @@ class TempWindowX11 {
  private:
   // A single instance will be created/owned by RootWindowManager.
   friend class RootWindowManager;
+  // Allow deletion via scoped_ptr only.
+  friend struct base::DefaultDeleter<TempWindowX11>;
 
   TempWindowX11();
   ~TempWindowX11();
diff --git tests/cefclient/cefclient_gtk.cc tests/cefclient/cefclient_gtk.cc
index 57938ae..3b8bf3e 100644
--- tests/cefclient/cefclient_gtk.cc
+++ tests/cefclient/cefclient_gtk.cc
@@ -19,6 +19,7 @@
 #include "include/cef_command_line.h"
 #include "include/wrapper/cef_helpers.h"
 #include "tests/cefclient/browser/main_context_impl.h"
+#include "tests/cefclient/browser/main_message_loop_multithreaded_gtk.h"
 #include "tests/cefclient/browser/test_runner.h"
 #include "tests/shared/browser/client_app_browser.h"
 #include "tests/shared/browser/main_message_loop_external_pump.h"
@@ -92,7 +93,9 @@ int RunMain(int argc, char* argv[]) {
 
   // Create the main message loop object.
   scoped_ptr<MainMessageLoop> message_loop;
-  if (settings.external_message_pump)
+  if (settings.multi_threaded_message_loop)
+    message_loop.reset(new MainMessageLoopMultithreadedGtk);
+  else if (settings.external_message_pump)
     message_loop = MainMessageLoopExternalPump::Create();
   else
     message_loop.reset(new MainMessageLoopStd);
diff --git tests/ceftests/test_suite.cc tests/ceftests/test_suite.cc
index 95b6400..9914301 100644
--- tests/ceftests/test_suite.cc
+++ tests/ceftests/test_suite.cc
@@ -119,7 +119,7 @@ int CefTestSuite::Run() {
 }
 
 void CefTestSuite::GetSettings(CefSettings& settings) const {
-#if defined(OS_WIN)
+#if (defined(OS_WIN) || defined(OS_LINUX))
   settings.multi_threaded_message_loop =
       command_line_->HasSwitch(client::switches::kMultiThreadedMessageLoop);
 #endif
