description: restore support for building against gtk2
author: Michael Gilbert <mgilbert@debian.org>
origin: chromium 69 authors

--- a/build/config/linux/atk/BUILD.gn
+++ b/build/config/linux/atk/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/features.gni")
+import("//build/config/linux/gtk/gtk.gni")
 import("//build/config/linux/pkg_config.gni")
 import("//build/config/ui.gni")
 
@@ -17,20 +18,18 @@ if (use_atk) {
 }
 
 pkg_config("atk_base") {
-  packages = [
-    "atk",
-    "atk-bridge-2.0",
-  ]
+  packages = [ "atk" ]
   atk_lib_dir = exec_script(pkg_config_script,
                             pkg_config_args + [
                                   "--libdir",
                                   "atk",
                                 ],
                             "string")
-  defines = [
-    "ATK_LIB_DIR=\"$atk_lib_dir\"",
-    "USE_ATK_BRIDGE",
-  ]
+  defines = [ "ATK_LIB_DIR=\"$atk_lib_dir\"" ]
+  if (gtk_version == 3) {
+    packages += [ "atk-bridge-2.0" ]
+    defines += [ "USE_ATK_BRIDGE" ]
+  }
 }
 
 # gn orders flags on a target before flags from configs. The default config
--- a/ui/accessibility/BUILD.gn
+++ b/ui/accessibility/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/config/linux/pkg_config.gni")
+import("//build/config/linux/gtk/gtk.gni")
 import("//build/config/features.gni")
 import("//build/config/ui.gni")
 import("//mojo/public/tools/bindings/mojom.gni")
@@ -126,13 +127,19 @@ component("accessibility") {
     sources += [
       "platform/atk_util_auralinux.cc",
       "platform/atk_util_auralinux.h",
-      "platform/atk_util_auralinux_gtk.cc",
       "platform/ax_platform_atk_hyperlink.cc",
       "platform/ax_platform_atk_hyperlink.h",
       "platform/ax_platform_node_auralinux.cc",
       "platform/ax_platform_node_auralinux.h",
     ]
 
+    if (gtk_version == 2 ) {
+      sources += [ "platform/atk_util_auralinux_gtk2.cc" ]
+    }
+    if (gtk_version == 3) {
+      sources += [ "platform/atk_util_auralinux_gtk.cc" ]
+    }
+
     configs += [ "//build/config/linux/atk" ]
 
     if (use_glib) {
--- a/build/config/linux/gtk/BUILD.gn
+++ b/build/config/linux/gtk/BUILD.gn
@@ -7,18 +7,10 @@ import("//build/config/linux/pkg_config.
 
 assert(is_linux, "This file should only be referenced on Linux")
 
-# GN doesn't check visibility for configs so we give this an obviously internal
-# name to discourage random targets from accidentally depending on this and
-# bypassing the GTK target's visibility.
-pkg_config("gtk_internal_config") {
-  # Gtk requires gmodule, but it does not list it as a dependency in some
-  # misconfigured systems.
-  packages = [
-    "gmodule-2.0",
-    "gtk+-${gtk_version}.0",
-    "gthread-2.0",
-  ]
-}
+# The target in this file will automatically reference GTK2 or GTK3 depending
+# on the state of the build flag. Some builds reference both 2 and 3, and some
+# builds reference neither, so both need to be available but in different
+# directories so pkg-config is only run when necessary.
 
 # Basically no parts of Chrome should depend on GTK. To prevent accidents, the
 # parts that explicitly need GTK are whitelisted on this target.
@@ -35,10 +27,13 @@ group("gtk") {
     "//remoting/host:remoting_me2me_host_static",
     "//remoting/test:it2me_standalone_host_main",
     "//webrtc/examples:peerconnection_client",
-    "//chrome/browser/ui/libgtkui:*",
   ]
 
-  public_configs = [ ":gtk_internal_config" ]
+  if (gtk_version == 2) {
+    public_deps = [
+      "//build/config/linux/gtk2",
+    ]
+  }
 }
 
 # Depend on "gtkprint" to get this.
--- a/build/config/linux/gtk/gtk.gni
+++ b/build/config/linux/gtk/gtk.gni
@@ -7,4 +7,4 @@ declare_args() {
   gtk_version = 3
 }
 
-assert(gtk_version >= 3 && gtk_version <= 4)
+assert(gtk_version >= 2 && gtk_version <= 4)
--- /dev/null
+++ b/build/config/linux/gtk2/BUILD.gn
@@ -0,0 +1,33 @@
+# Copyright 2015 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.
+
+import("//build/config/linux/pkg_config.gni")
+
+assert(is_linux, "This file should only be referenced on Linux")
+
+# Depend on //build/config/linux/gtk2 to use GTKv2. Depend on
+# //build/config/linux/gtk to get GTK 2 or 3 depending on the build flags.
+#
+# GN doesn't check visibility for configs so we give this an obviously internal
+# name to discourage random targets from accidentally depending on this and
+# bypassing the GTK target's visibility.
+pkg_config("gtk2_internal_config") {
+  # Gtk requires gmodule, but it does not list it as a dependency in some
+  # misconfigured systems.
+  packages = [
+    "gmodule-2.0",
+    "gtk+-2.0",
+    "gthread-2.0",
+  ]
+}
+
+# Basically no parts of Chrome should depend on GTK. To prevent accidents, the
+# parts that explicitly need GTK2 are whitelisted on this target.
+group("gtk2") {
+  visibility = [
+    "//build/config/linux/gtk",
+    "//chrome/browser/ui/libgtkui:*",
+  ]
+  public_configs = [ ":gtk2_internal_config" ]
+}
--- a/chrome/browser/ui/libgtkui/BUILD.gn
+++ b/chrome/browser/ui/libgtkui/BUILD.gn
@@ -8,122 +8,154 @@ import("//build/config/features.gni")
 import("//build/config/linux/gtk/gtk.gni")
 import("//printing/buildflags/buildflags.gni")
 
-component("libgtkui") {
-  sources = [
-    "app_indicator_icon.cc",
-    "app_indicator_icon.h",
-    "app_indicator_icon_menu.cc",
-    "app_indicator_icon_menu.h",
-    "chrome_gtk_menu_subclasses.cc",
-    "chrome_gtk_menu_subclasses.h",
-    "gtk_background_painter.cc",
-    "gtk_background_painter.h",
-    "gtk_event_loop.cc",
-    "gtk_event_loop.h",
-    "gtk_key_bindings_handler.cc",
-    "gtk_key_bindings_handler.h",
-    "gtk_signal.h",
-    "gtk_ui.cc",
-    "gtk_ui.h",
-    "gtk_util.cc",
-    "gtk_util.h",
-    "libgtkui_export.h",
-    "menu_util.cc",
-    "menu_util.h",
-    "native_theme_gtk.cc",
-    "native_theme_gtk.h",
-    "nav_button_provider_gtk.cc",
-    "nav_button_provider_gtk.h",
-    "print_dialog_gtk.cc",
-    "print_dialog_gtk.h",
-    "printing_gtk_util.cc",
-    "printing_gtk_util.h",
-    "select_file_dialog_impl.cc",
-    "select_file_dialog_impl.h",
-    "select_file_dialog_impl_gtk.cc",
-    "select_file_dialog_impl_gtk.h",
-    "select_file_dialog_impl_kde.cc",
-    "settings_provider.h",
-    "settings_provider_gtk.cc",
-    "settings_provider_gtk.h",
-    "skia_utils_gtk.cc",
-    "skia_utils_gtk.h",
-    "unity_service.cc",
-    "unity_service.h",
-    "x11_input_method_context_impl_gtk.cc",
-    "x11_input_method_context_impl_gtk.h",
-  ]
-
-  if (gtk_version <= 3) {
-    sources += [
-      "gtk_status_icon.cc",
-      "gtk_status_icon.h",
+# Automatically depends on the GTK version associated with the current build
+# flags.
+group("libgtkui") {
+  if (gtk_version == 3) {
+    public_deps = [
+      ":libgtk3ui",
+    ]
+  } else {
+    public_deps = [
+      ":libgtk2ui",
     ]
   }
+}
 
-  configs += [
-    "//build/config/linux/pangocairo",
-    "//build/config/linux:x11",
-  ]
-
-  if (use_gio) {
-    sources += [
-      "settings_provider_gsettings.cc",
-      "settings_provider_gsettings.h",
+template("libgtkui") {
+  component(target_name) {
+    sources = invoker.sources + [
+                "app_indicator_icon.cc",
+                "app_indicator_icon.h",
+                "app_indicator_icon_menu.cc",
+                "app_indicator_icon_menu.h",
+                "chrome_gtk_menu_subclasses.cc",
+                "chrome_gtk_menu_subclasses.h",
+                "gtk_event_loop.cc",
+                "gtk_event_loop.h",
+                "gtk_key_bindings_handler.cc",
+                "gtk_key_bindings_handler.h",
+                "gtk_signal.h",
+                "gtk_status_icon.cc",
+                "gtk_status_icon.h",
+                "gtk_ui.cc",
+                "gtk_ui.h",
+                "gtk_util.cc",
+                "gtk_util.h",
+                "libgtkui_export.h",
+                "menu_util.cc",
+                "menu_util.h",
+                "settings_provider.h",
+                "print_dialog_gtk.cc",
+                "print_dialog_gtk.h",
+                "printing_gtk_util.cc",
+                "printing_gtk_util.h",
+                "select_file_dialog_impl.cc",
+                "select_file_dialog_impl.h",
+                "select_file_dialog_impl_gtk.cc",
+                "select_file_dialog_impl_gtk.h",
+                "select_file_dialog_impl_kde.cc",
+                "skia_utils_gtk.cc",
+                "skia_utils_gtk.h",
+                "unity_service.cc",
+                "unity_service.h",
+                "x11_input_method_context_impl_gtk.cc",
+                "x11_input_method_context_impl_gtk.h",
+              ]
+
+    configs += [
+      "//build/config/linux/pangocairo",
+      "//build/config/linux:x11",
     ]
-    configs += [ "//build/linux:gio_config" ]
-  }
 
-  if (use_cups) {
-    configs += [ "//printing:cups" ]
+    if (use_gio) {
+      sources += [
+        "settings_provider_gsettings.cc",
+        "settings_provider_gsettings.h",
+      ]
+      configs += [ "//build/linux:gio_config" ]
+    }
+
+    if (use_cups) {
+      configs += [ "//printing:cups" ]
+    }
+
+    defines = [ "LIBGTKUI_IMPLEMENTATION" ]
+
+    deps = invoker.deps + [
+             "//chrome/browser/ui/views",
+             "//chrome/common:constants",
+             "//base",
+             "//base:i18n",
+             "//base/third_party/dynamic_annotations",
+             "//cc/paint",
+             "//chrome/common:buildflags",
+             "//chrome:extra_resources",
+             "//chrome:resources",
+             "//chrome:strings",
+             "//chrome/app:command_ids",
+             "//chrome/app/theme:theme_resources",
+             "//components/prefs",
+             "//components/resources",
+             "//content/public/browser",
+             "//printing",
+             "//skia",
+
+             # GTK pulls pangoft2, which requires HarfBuzz symbols. When linking
+             # our own HarfBuzz avoid mixing symbols from system HarfBuzz and
+             # our own through the indirect dependency to harfbuzz-ng here.
+             "//third_party:freetype_harfbuzz",
+             "//ui/aura",
+             "//ui/base",
+             "//ui/base/ime",
+             "//ui/display",
+             "//ui/events",
+             "//ui/events:dom_keyboard_layout",
+             "//ui/events:dom_keycode_converter",
+             "//ui/events:events_base",
+             "//ui/events/platform/x11",
+             "//ui/gfx",
+             "//ui/gfx/geometry",
+             "//ui/gfx/x",
+             "//ui/native_theme",
+             "//ui/resources",
+             "//ui/shell_dialogs",
+             "//ui/strings",
+             "//ui/views",
+           ]
+    public_deps = [
+      "//chrome/browser:theme_properties",
+    ]
   }
+}
 
-  defines = [ "LIBGTKUI_IMPLEMENTATION" ]
-
-  deps = [
-    "//base",
-    "//base:i18n",
-    "//base/third_party/dynamic_annotations",
-    "//build/config/linux/gtk",
-    "//build/config/linux/gtk:gtkprint",
-    "//cc/paint",
-    "//chrome:extra_resources",
-    "//chrome:resources",
-    "//chrome:strings",
-    "//chrome/app:command_ids",
-    "//chrome/app/theme:theme_resources",
-    "//chrome/browser/ui/views",
-    "//chrome/common:buildflags",
-    "//chrome/common:constants",
-    "//components/prefs",
-    "//components/resources",
-    "//content/public/browser",
-    "//printing",
-    "//skia",
-
-    # GTK pulls pangoft2, which requires HarfBuzz symbols. When linking
-    # our own HarfBuzz avoid mixing symbols from system HarfBuzz and
-    # our own through the indirect dependency to harfbuzz-ng here.
-    "//third_party:freetype_harfbuzz",
-    "//ui/aura",
-    "//ui/base",
-    "//ui/base/ime",
-    "//ui/display",
-    "//ui/events",
-    "//ui/events:dom_keyboard_layout",
-    "//ui/events:dom_keycode_converter",
-    "//ui/events:events_base",
-    "//ui/events/platform/x11",
-    "//ui/gfx",
-    "//ui/gfx/geometry",
-    "//ui/gfx/x",
-    "//ui/native_theme",
-    "//ui/resources",
-    "//ui/shell_dialogs",
-    "//ui/strings",
-    "//ui/views",
-  ]
-  public_deps = [
-    "//chrome/browser:theme_properties",
-  ]
+if (gtk_version == 3) {
+  libgtkui("libgtk3ui") {
+    sources = [
+      "gtk_background_painter.cc",
+      "gtk_background_painter.h",
+      "native_theme_gtk.cc",
+      "native_theme_gtk.h",
+      "nav_button_provider_gtk.cc",
+      "nav_button_provider_gtk.h",
+      "settings_provider_gtk.cc",
+      "settings_provider_gtk.h",
+    ]
+    deps = [
+      "//build/config/linux/gtk:gtkprint",
+    ]
+  }
+} else {
+  libgtkui("libgtk2ui") {
+    sources = [
+      "gtk2/chrome_gtk_frame.cc",
+      "gtk2/chrome_gtk_frame.h",
+      "gtk2/native_theme_gtk2.cc",
+      "gtk2/native_theme_gtk2.h",
+    ]
+    deps = [
+      "//build/config/linux/gtk2",
+      "//build/config/linux/gtk:gtkprint",
+    ]
+  }
 }
--- a/chrome/browser/ui/libgtkui/app_indicator_icon.cc
+++ b/chrome/browser/ui/libgtkui/app_indicator_icon.cc
@@ -91,15 +91,27 @@ void EnsureMethodsLoaded() {
 
   void* indicator_lib = nullptr;
 
-  if (!indicator_lib) {
-    indicator_lib =
-        dlopen("libappindicator" STRINGIZE(GTK_MAJOR_VERSION) ".so", RTLD_LAZY);
-  }
-
-  if (!indicator_lib) {
-    indicator_lib = dlopen(
-        "libappindicator" STRINGIZE(GTK_MAJOR_VERSION) ".so.1", RTLD_LAZY);
-  }
+  // These include guards might be unnecessary, but let's keep them as a
+  // precaution since using gtk2 and gtk3 symbols in the same process is
+  // explicitly unsupported.
+#if GTK_MAJOR_VERSION == 2
+  if (!indicator_lib)
+    indicator_lib = dlopen("libappindicator.so", RTLD_LAZY);
+
+  if (!indicator_lib)
+    indicator_lib = dlopen("libappindicator.so.1", RTLD_LAZY);
+
+  if (!indicator_lib)
+    indicator_lib = dlopen("libappindicator.so.0", RTLD_LAZY);
+#endif
+
+#if GTK_MAJOR_VERSION == 3
+  if (!indicator_lib)
+    indicator_lib = dlopen("libappindicator3.so", RTLD_LAZY);
+
+  if (!indicator_lib)
+    indicator_lib = dlopen("libappindicator3.so.1", RTLD_LAZY);
+#endif
 
   if (!indicator_lib)
     return;
--- a/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.cc
+++ b/chrome/browser/ui/libgtkui/gtk_key_bindings_handler.cc
@@ -77,7 +77,11 @@ bool GtkKeyBindingsHandler::MatchEvent(
   // will be emitted.
 
   gtk_bindings_activate_event(
+#if GDK_MAJOR_VERSION >= 3
       G_OBJECT(handler_),
+#else
+      GTK_OBJECT(handler_),
+#endif
       &gdk_event);
 
   bool matched = !edit_commands_.empty();
--- a/chrome/browser/ui/libgtkui/gtk_status_icon.cc
+++ b/chrome/browser/ui/libgtkui/gtk_status_icon.cc
@@ -21,11 +21,13 @@ GtkStatusIcon::GtkStatusIcon(const gfx::
                              const base::string16& tool_tip) {
   GdkPixbuf* pixbuf = GdkPixbufFromSkBitmap(*image.bitmap());
   {
+#if GTK_MAJOR_VERSION == 3
     // GTK has a bug that leaks 384 bytes when creating a GtkStatusIcon.  It
     // will not be fixed since the status icon was deprecated in version 3.14.
     // Luckily, Chromium doesn't need to create a status icon very often, if at
     // all.
     ANNOTATE_SCOPED_MEMORY_LEAK;
+#endif
     gtk_status_icon_ = gtk_status_icon_new_from_pixbuf(pixbuf);
   }
   g_object_unref(pixbuf);
--- a/chrome/browser/ui/libgtkui/gtk_ui.cc
+++ b/chrome/browser/ui/libgtkui/gtk_ui.cc
@@ -75,6 +75,15 @@
 #include "ui/views/linux_ui/window_button_order_observer.h"
 #include "ui/views/resources/grit/views_resources.h"
 
+#if GTK_MAJOR_VERSION == 2
+#include "chrome/browser/ui/libgtkui/gtk2/chrome_gtk_frame.h"
+#include "chrome/browser/ui/libgtkui/gtk2/native_theme_gtk2.h"
+#elif GTK_MAJOR_VERSION == 3
+#include "chrome/browser/ui/libgtkui/native_theme_gtk.h"
+#include "chrome/browser/ui/libgtkui/nav_button_provider_gtk.h"
+#include "chrome/browser/ui/libgtkui/settings_provider_gtk.h"
+#endif
+
 #if defined(USE_GIO)
 #include "chrome/browser/ui/libgtkui/settings_provider_gsettings.h"
 #endif
@@ -134,6 +143,49 @@ class GtkButtonImageSource : public gfx:
         width, height, width * 4);
     cairo_t* cr = cairo_create(surface);
 
+#if GTK_MAJOR_VERSION == 2
+    // Create a temporary GTK button to snapshot
+    GtkWidget* window = gtk_offscreen_window_new();
+    GtkWidget* button = gtk_toggle_button_new();
+
+    if (state_ == ui::NativeTheme::kPressed)
+      gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(button), true);
+    else if (state_ == ui::NativeTheme::kDisabled)
+      gtk_widget_set_sensitive(button, false);
+
+    gtk_widget_set_size_request(button, width, height);
+    gtk_container_add(GTK_CONTAINER(window), button);
+
+    if (is_blue_)
+      TurnButtonBlue(button);
+
+    gtk_widget_show_all(window);
+
+    if (focus_)
+      GTK_WIDGET_SET_FLAGS(button, GTK_HAS_FOCUS);
+
+    int w, h;
+    GdkPixmap* pixmap;
+
+    {
+      // http://crbug.com/346740
+      ANNOTATE_SCOPED_MEMORY_LEAK;
+      pixmap = gtk_widget_get_snapshot(button, nullptr);
+    }
+
+    gdk_drawable_get_size(GDK_DRAWABLE(pixmap), &w, &h);
+    GdkColormap* colormap = gdk_drawable_get_colormap(pixmap);
+    GdkPixbuf* pixbuf = gdk_pixbuf_get_from_drawable(
+        nullptr, GDK_DRAWABLE(pixmap), colormap, 0, 0, 0, 0, w, h);
+
+    gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
+    cairo_paint(cr);
+
+    g_object_unref(pixbuf);
+    g_object_unref(pixmap);
+
+    gtk_widget_destroy(window);
+#else
     ScopedStyleContext context = GetStyleContextFromCss(
         is_blue_ ? "GtkButton#button.default.suggested-action"
                  : "GtkButton#button");
@@ -181,6 +233,7 @@ class GtkButtonImageSource : public gfx:
       gtk_render_focus(context, cr, focus_rect.x(), focus_rect.y(),
                        focus_rect.width(), focus_rect.height());
     }
+#endif
 
     cairo_destroy(cr);
     cairo_surface_destroy(surface);
@@ -245,15 +298,19 @@ int indicators_count;
 // The unknown content type.
 const char* kUnknownContentType = "application/octet-stream";
 
+#if GTK_MAJOR_VERSION > 2
 using GdkSetAllowedBackendsFn = void (*)(const gchar*);
 // Place this function pointer in read-only memory after being resolved to
 // prevent it being tampered with. See https://crbug.com/771365 for details.
 PROTECTED_MEMORY_SECTION base::ProtectedMemory<GdkSetAllowedBackendsFn>
     g_gdk_set_allowed_backends;
+#endif
 
 std::unique_ptr<SettingsProvider> CreateSettingsProvider(GtkUi* gtk_ui) {
+#if GTK_MAJOR_VERSION == 3
   if (GtkVersionCheck(3, 14))
     return std::make_unique<SettingsProviderGtk>(gtk_ui);
+#endif
 #if defined(USE_GIO)
   return std::make_unique<SettingsProviderGSettings>(gtk_ui);
 #else
@@ -311,8 +368,10 @@ gfx::FontRenderParams GetGtkFontRenderPa
 }
 
 views::LinuxUI::NonClientWindowFrameAction GetDefaultMiddleClickAction() {
+#if GTK_MAJOR_VERSION == 3
   if (GtkVersionCheck(3, 14))
     return views::LinuxUI::WINDOW_FRAME_ACTION_NONE;
+#endif
   std::unique_ptr<base::Environment> env(base::Environment::Create());
   switch (base::nix::GetDesktopEnvironment(env.get())) {
     case base::nix::DESKTOP_ENVIRONMENT_KDE4:
@@ -327,6 +386,7 @@ views::LinuxUI::NonClientWindowFrameActi
   }
 }
 
+#if GTK_MAJOR_VERSION > 2
 // COLOR_TOOLBAR_TOP_SEPARATOR represents the border between tabs and the
 // frame, as well as the border between tabs and the toolbar.  For this
 // reason, it is difficult to calculate the One True Color that works well on
@@ -377,6 +437,7 @@ SkColor GetToolbarTopSeparatorColor(SkCo
   border.l = l;
   return HSLToSkColor(border, a * 0xff);
 }
+#endif
 
 }  // namespace
 
@@ -387,6 +448,7 @@ GtkUi::GtkUi() {
       GetDefaultMiddleClickAction();
   window_frame_actions_[WINDOW_FRAME_ACTION_SOURCE_RIGHT_CLICK] =
       views::LinuxUI::WINDOW_FRAME_ACTION_MENU;
+#if GTK_MAJOR_VERSION > 2
   // Force Gtk to use Xwayland if it would have used wayland.  libgtkui assumes
   // the use of X11 (eg. X11InputMethodContextImplGtk) and will crash under
   // other backends.
@@ -399,13 +461,23 @@ GtkUi::GtkUi() {
     DCHECK(*g_gdk_set_allowed_backends);
   if (*g_gdk_set_allowed_backends)
     base::UnsanitizedCfiCall(g_gdk_set_allowed_backends)("x11");
+#endif
+#if GTK_MAJOR_VERSION >= 3
   // Avoid GTK initializing atk-bridge, and let AuraLinux implementation
   // do it once it is ready.
   std::unique_ptr<base::Environment> env(base::Environment::Create());
   env->SetVar("NO_AT_BRIDGE", "1");
+#endif
   GtkInitFromCommandLine(*base::CommandLine::ForCurrentProcess());
+#if GTK_MAJOR_VERSION == 2
+  native_theme_ = NativeThemeGtk2::instance();
+  fake_window_ = chrome_gtk_frame_new();
+#elif GTK_MAJOR_VERSION == 3
   native_theme_ = NativeThemeGtk::instance();
   fake_window_ = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+#else
+#error "Unsupported GTK version"
+#endif
   gtk_widget_realize(fake_window_);
 }
 
@@ -804,8 +876,10 @@ bool GtkUi::PreferDarkTheme() const {
 
 #if BUILDFLAG(ENABLE_NATIVE_WINDOW_NAV_BUTTONS)
 std::unique_ptr<views::NavButtonProvider> GtkUi::CreateNavButtonProvider() {
+#if GTK_MAJOR_VERSION == 3
   if (GtkVersionCheck(3, 14))
     return std::make_unique<libgtkui::NavButtonProviderGtk>();
+#endif
   return nullptr;
 }
 #endif
@@ -897,6 +971,66 @@ void GtkUi::LoadGtkValues() {
   UpdateDeviceScaleFactor();
   UpdateCursorTheme();
 
+#if GTK_MAJOR_VERSION == 2
+  const color_utils::HSL kDefaultFrameShift = {-1, -1, 0.4};
+  SkColor frame_color =
+      native_theme_->GetSystemColor(ui::NativeTheme::kColorId_WindowBackground);
+  frame_color = color_utils::HSLShift(frame_color, kDefaultFrameShift);
+  GetChromeStyleColor("frame-color", &frame_color);
+  colors_[ThemeProperties::COLOR_FRAME] = frame_color;
+
+  GtkStyle* style = gtk_rc_get_style(fake_window_);
+  SkColor temp_color = color_utils::HSLShift(
+      GdkColorToSkColor(style->bg[GTK_STATE_INSENSITIVE]), kDefaultFrameShift);
+  GetChromeStyleColor("inactive-frame-color", &temp_color);
+  colors_[ThemeProperties::COLOR_FRAME_INACTIVE] = temp_color;
+
+  temp_color = color_utils::HSLShift(frame_color, kDefaultTintFrameIncognito);
+  GetChromeStyleColor("incognito-frame-color", &temp_color);
+  colors_[ThemeProperties::COLOR_FRAME_INCOGNITO] = temp_color;
+
+  temp_color =
+      color_utils::HSLShift(frame_color, kDefaultTintFrameIncognitoInactive);
+  GetChromeStyleColor("incognito-inactive-frame-color", &temp_color);
+  colors_[ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE] = temp_color;
+
+  SkColor tab_color =
+      native_theme_->GetSystemColor(ui::NativeTheme::kColorId_DialogBackground);
+  SkColor label_color = native_theme_->GetSystemColor(
+      ui::NativeTheme::kColorId_LabelEnabledColor);
+
+  colors_[ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON] =
+      color_utils::DeriveDefaultIconColor(label_color);
+
+  colors_[ThemeProperties::COLOR_TAB_TEXT] = label_color;
+  colors_[ThemeProperties::COLOR_BOOKMARK_TEXT] = label_color;
+  colors_[ThemeProperties::COLOR_BACKGROUND_TAB_TEXT] =
+      color_utils::BlendTowardOppositeLuma(label_color, 50);
+
+  inactive_selection_bg_color_ = native_theme_->GetSystemColor(
+      ui::NativeTheme::kColorId_TextfieldReadOnlyBackground);
+  inactive_selection_fg_color_ = native_theme_->GetSystemColor(
+      ui::NativeTheme::kColorId_TextfieldReadOnlyColor);
+
+  // We pick the text and background colors for the NTP out of the
+  // colors for a GtkEntry. We do this because GtkEntries background
+  // color is never the same as |tab_color|, is usually a white,
+  // and when it isn't a white, provides sufficient contrast to
+  // |tab_color|. Try this out with Darklooks, HighContrastInverse
+  // or ThinIce.
+  colors_[ThemeProperties::COLOR_NTP_BACKGROUND] =
+      native_theme_->GetSystemColor(
+          ui::NativeTheme::kColorId_TextfieldDefaultBackground);
+  colors_[ThemeProperties::COLOR_NTP_TEXT] = native_theme_->GetSystemColor(
+      ui::NativeTheme::kColorId_TextfieldDefaultColor);
+  // The NTP header is the color that surrounds the current active
+  // thumbnail on the NTP, and acts as the border of the "Recent
+  // Links" box. It would be awesome if they were separated so we
+  // could use GetBorderColor() for the border around the "Recent
+  // Links" section, but matching the frame color is more important.
+  colors_[ThemeProperties::COLOR_NTP_HEADER] =
+      colors_[ThemeProperties::COLOR_FRAME];
+#else
   SkColor tab_color = GetBgColor("");
   SkColor tab_text_color = GetFgColor("GtkLabel");
 
@@ -1062,6 +1196,7 @@ void GtkUi::LoadGtkValues() {
           toolbar_top_separator_inactive;
     }
   }
+#endif
 
   colors_[ThemeProperties::COLOR_TOOLBAR] = tab_color;
   colors_[ThemeProperties::COLOR_CONTROL_BACKGROUND] = tab_color;
@@ -1151,6 +1286,20 @@ void GtkUi::UpdateDefaultFont() {
   g_object_unref(fake_label);
 }
 
+bool GtkUi::GetChromeStyleColor(const char* style_property,
+                                SkColor* ret_color) const {
+#if GTK_MAJOR_VERSION == 2
+  GdkColor* style_color = nullptr;
+  gtk_widget_style_get(fake_window_, style_property, &style_color, nullptr);
+  if (style_color) {
+    *ret_color = GdkColorToSkColor(*style_color);
+    gdk_color_free(style_color);
+    return true;
+  }
+#endif
+  return false;
+}
+
 void GtkUi::ResetStyle() {
   LoadGtkValues();
   native_theme_->NotifyObservers();
@@ -1160,12 +1309,19 @@ float GtkUi::GetRawDeviceScaleFactor() {
   if (display::Display::HasForceDeviceScaleFactor())
     return display::Display::GetForcedDeviceScaleFactor();
 
+#if GTK_MAJOR_VERSION == 2
+  GtkSettings* gtk_settings = gtk_settings_get_default();
+  gint gtk_dpi = -1;
+  g_object_get(gtk_settings, "gtk-xft-dpi", &gtk_dpi, nullptr);
+  const float scale_factor = gtk_dpi / (1024 * kDefaultDPI);
+#else
   GdkScreen* screen = gdk_screen_get_default();
   gint scale = gtk_widget_get_scale_factor(fake_window_);
   DCHECK_GT(scale, 0);
   gdouble resolution = gdk_screen_get_resolution(screen);
   const float scale_factor =
       resolution <= 0 ? scale : resolution * scale / kDefaultDPI;
+#endif
 
   // Blacklist scaling factors <120% (crbug.com/484400) and round
   // to 1 decimal to prevent rendering problems (crbug.com/485183).
--- a/chrome/browser/ui/libgtkui/gtk_ui.h
+++ b/chrome/browser/ui/libgtkui/gtk_ui.h
@@ -145,6 +145,10 @@ class GtkUi : public views::LinuxUI {
   // Updates |default_font_*|.
   void UpdateDefaultFont();
 
+  // Gets a ChromeGtkFrame theme color; returns true on success.
+  bool GetChromeStyleColor(const char* sytle_property,
+                           SkColor* ret_color) const;
+
   float GetRawDeviceScaleFactor();
 
   ui::NativeTheme* native_theme_;
--- a/chrome/browser/ui/libgtkui/gtk_util.cc
+++ b/chrome/browser/ui/libgtkui/gtk_util.cc
@@ -169,8 +169,12 @@ int EventFlagsFromGdkState(guint state)
 }
 
 void TurnButtonBlue(GtkWidget* button) {
+#if GTK_MAJOR_VERSION == 2
+  gtk_widget_set_can_default(button, true);
+#else
   gtk_style_context_add_class(gtk_widget_get_style_context(button),
                               "suggested-action");
+#endif
 }
 
 void SetGtkTransientForAura(GtkWidget* dialog, aura::Window* parent) {
@@ -215,6 +219,7 @@ void ParseButtonLayout(const std::string
   }
 }
 
+#if GTK_MAJOR_VERSION > 2
 namespace {
 
 float GetDeviceScaleFactor() {
@@ -622,5 +627,6 @@ SkColor GetSeparatorColor(const std::str
   gtk_render_frame(context, surface.cairo(), 0, 0, w, h);
   return surface.GetAveragePixelValue(false);
 }
+#endif
 
 }  // namespace libgtkui
--- a/chrome/browser/ui/libgtkui/gtk_util.h
+++ b/chrome/browser/ui/libgtkui/gtk_util.h
@@ -83,6 +83,7 @@ void ParseButtonLayout(const std::string
                        std::vector<views::FrameButton>* leading_buttons,
                        std::vector<views::FrameButton>* trailing_buttons);
 
+#if GTK_MAJOR_VERSION > 2
 void* GetGdkSharedLibrary();
 void* GetGtkSharedLibrary();
 
@@ -199,6 +200,7 @@ SkColor GetSelectionBgColor(const std::s
 
 // Get the color of the GtkSeparator specified by |css_selector|.
 SkColor GetSeparatorColor(const std::string& css_selector);
+#endif
 
 }  // namespace libgtkui
 
--- a/chrome/browser/ui/libgtkui/print_dialog_gtk.cc
+++ b/chrome/browser/ui/libgtkui/print_dialog_gtk.cc
@@ -286,8 +286,14 @@ void PrintDialogGtk::UpdateSettings(prin
           gtk_page_setup_set_paper_size(page_setup_, custom_size);
           gtk_paper_size_free(custom_size);
         }
+#if GTK_CHECK_VERSION(2, 28, 0)
         g_list_free_full(gtk_paper_sizes,
                          reinterpret_cast<GDestroyNotify>(gtk_paper_size_free));
+#else
+        g_list_foreach(gtk_paper_sizes,
+                       reinterpret_cast<GFunc>(gtk_paper_size_free), nullptr);
+        g_list_free(gtk_paper_sizes);
+#endif
       }
     } else {
       VLOG(1) << "Using default paper size";
@@ -475,7 +481,11 @@ void PrintDialogGtk::OnResponse(GtkWidge
 
 static void OnJobCompletedThunk(GtkPrintJob* print_job,
                                 gpointer user_data,
+#if GTK_MAJOR_VERSION == 2
+                                GError* error
+#else
                                 const GError* error
+#endif
                                 ) {
   static_cast<PrintDialogGtk*>(user_data)->OnJobCompleted(print_job, error);
 }
--- a/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc
+++ b/chrome/browser/ui/libgtkui/x11_input_method_context_impl_gtk.cc
@@ -86,7 +86,12 @@ bool X11InputMethodContextImplGtk::Dispa
   gint win_y = 0;
   gdk_window_get_origin(event->key.window, &win_x, &win_y);
 
+#if GTK_MAJOR_VERSION == 2
+  gint factor = 1;
+#else
   gint factor = gdk_window_get_scale_factor(event->key.window);
+#endif
+
   gint caret_x = last_caret_bounds_.x() / factor;
   gint caret_y = last_caret_bounds_.y() / factor;
   gint caret_w = last_caret_bounds_.width() / factor;
@@ -218,11 +223,19 @@ GdkEvent* X11InputMethodContextImplGtk::
   g_free(keyvals);
   keyvals = nullptr;
 // Get a GdkWindow.
+#if GTK_CHECK_VERSION(2, 24, 0)
   GdkWindow* window = gdk_x11_window_lookup_for_display(display, xkey.window);
+#else
+  GdkWindow* window = gdk_window_lookup_for_display(display, xkey.window);
+#endif
   if (window)
     g_object_ref(window);
   else
+#if GTK_CHECK_VERSION(2, 24, 0)
     window = gdk_x11_window_foreign_new_for_display(display, xkey.window);
+#else
+    window = gdk_window_foreign_new_for_display(display, xkey.window);
+#endif
   if (!window) {
     LOG(ERROR) << "Cannot get a GdkWindow for a key event.";
     return nullptr;
--- /dev/null
+++ b/chrome/browser/ui/libgtkui/gtk2/chrome_gtk_frame.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2012 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 "chrome/browser/ui/libgtkui/gtk2/chrome_gtk_frame.h"
+
+G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
+G_BEGIN_DECLS
+
+// MetaFrames declaration
+G_DEFINE_TYPE(MetaFrames, meta_frames, GTK_TYPE_WINDOW)
+
+static void meta_frames_class_init(MetaFramesClass* frames_class) {
+  // Noop since we don't declare anything.
+}
+
+static void meta_frames_init(MetaFrames* button) {
+}
+
+
+// ChromeGtkFrame declaration
+G_DEFINE_TYPE(ChromeGtkFrame, chrome_gtk_frame, meta_frames_get_type())
+
+static void chrome_gtk_frame_class_init(ChromeGtkFrameClass* frame_class) {
+  GtkWidgetClass* widget_class = reinterpret_cast<GtkWidgetClass*>(frame_class);
+
+  // Frame tints:
+  gtk_widget_class_install_style_property(
+      widget_class,
+      g_param_spec_boxed(
+          "frame-color",
+          "Frame Color",
+          "The color that the chrome frame will be. (If unspecified, "
+            " Chrome will take ChromeGtkFrame::bg[SELECTED] and slightly darken"
+            " it.)",
+          GDK_TYPE_COLOR,
+          G_PARAM_READABLE));
+  gtk_widget_class_install_style_property(
+      widget_class,
+      g_param_spec_boxed(
+          "inactive-frame-color",
+          "Inactive Frame Color",
+          "The color that the inactive chrome frame will be. (If"
+            " unspecified, Chrome will take ChromeGtkFrame::bg[INSENSITIVE]"
+            " and slightly darken it.)",
+          GDK_TYPE_COLOR,
+          G_PARAM_READABLE));
+  gtk_widget_class_install_style_property(
+      widget_class,
+      g_param_spec_boxed(
+          "incognito-frame-color",
+          "Incognito Frame Color",
+          "The color that the incognito frame will be. (If unspecified,"
+            " Chrome will take the frame color and tint it by Chrome's default"
+            " incognito tint.)",
+          GDK_TYPE_COLOR,
+          G_PARAM_READABLE));
+  gtk_widget_class_install_style_property(
+      widget_class,
+      g_param_spec_boxed(
+          "incognito-inactive-frame-color",
+          "Incognito Inactive Frame Color",
+          "The color that the inactive incognito frame will be. (If"
+            " unspecified, Chrome will take the frame color and tint it by"
+            " Chrome's default incognito tint.)",
+          GDK_TYPE_COLOR,
+          G_PARAM_READABLE));
+
+  // Frame gradient control:
+  gtk_widget_class_install_style_property(
+      widget_class,
+      g_param_spec_int(
+          "frame-gradient-size",
+          "Chrome Frame Gradient Size",
+          "The size of the gradient on top of the frame image. Specify 0 to"
+            " make the frame a solid color.",
+          0,      // 0 disables the gradient
+          128,    // The frame image is only up to 128 pixels tall.
+          16,     // By default, gradients are 16 pixels high.
+          G_PARAM_READABLE));
+  gtk_widget_class_install_style_property(
+      widget_class,
+      g_param_spec_boxed(
+          "frame-gradient-color",
+          "Frame Gradient Color",
+          "The top color of the chrome frame gradient. (If unspecified,"
+            " chrome will create a lighter tint of frame-color",
+          GDK_TYPE_COLOR,
+          G_PARAM_READABLE));
+  gtk_widget_class_install_style_property(
+      widget_class,
+      g_param_spec_boxed(
+          "inactive-frame-gradient-color",
+          "Inactive Frame Gradient Color",
+          "The top color of the inactive chrome frame gradient. (If"
+            " unspecified, chrome will create a lighter tint of frame-color",
+          GDK_TYPE_COLOR,
+          G_PARAM_READABLE));
+  gtk_widget_class_install_style_property(
+      widget_class,
+      g_param_spec_boxed(
+          "incognito-frame-gradient-color",
+          "Incognito Frame Gradient Color",
+          "The top color of the incognito chrome frame gradient. (If"
+            " unspecified, chrome will create a lighter tint of frame-color",
+          GDK_TYPE_COLOR,
+          G_PARAM_READABLE));
+  gtk_widget_class_install_style_property(
+      widget_class,
+      g_param_spec_boxed(
+          "incognito-inactive-frame-gradient-color",
+          "Incognito Inactive Frame Gradient Color",
+          "The top color of the incognito inactive chrome frame gradient. (If"
+            " unspecified, chrome will create a lighter tint of frame-color",
+          GDK_TYPE_COLOR,
+          G_PARAM_READABLE));
+
+  // Scrollbar color properties:
+  gtk_widget_class_install_style_property(
+      widget_class,
+      g_param_spec_boxed(
+          "scrollbar-slider-prelight-color",
+          "Scrollbar Slider Prelight Color",
+          "The color applied to the mouse is above the tab",
+          GDK_TYPE_COLOR,
+          G_PARAM_READABLE));
+  gtk_widget_class_install_style_property(
+      widget_class,
+      g_param_spec_boxed(
+          "scrollbar-slider-normal-color",
+          "Scrollbar Slider Normal Color",
+          "The color applied to the slider normally",
+          GDK_TYPE_COLOR,
+          G_PARAM_READABLE));
+  gtk_widget_class_install_style_property(
+      widget_class,
+      g_param_spec_boxed(
+          "scrollbar-trough-color",
+          "Scrollbar Trough Color",
+          "The background color of the slider track",
+          GDK_TYPE_COLOR,
+          G_PARAM_READABLE));
+}
+
+static void chrome_gtk_frame_init(ChromeGtkFrame* frame) {
+}
+
+GtkWidget* chrome_gtk_frame_new(void) {
+  return GTK_WIDGET(g_object_new(chrome_gtk_frame_get_type(), "type",
+                                 GTK_WINDOW_TOPLEVEL, nullptr));
+}
+
+G_END_DECLS
--- /dev/null
+++ b/chrome/browser/ui/libgtkui/gtk2/chrome_gtk_frame.h
@@ -0,0 +1,54 @@
+// Copyright (c) 2012 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 CHROME_BROWSER_UI_LIBGTKUI_CHROME_GTK_FRAME_H_
+#define CHROME_BROWSER_UI_LIBGTKUI_CHROME_GTK_FRAME_H_
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+// This file declares two subclasses of GtkWindow for easier gtk+ theme
+// integration.
+//
+// The first is "MetaFrames," which is (was?) the name of a gobject class in
+// the metacity window manager. To actually get at those values, we need to
+// have an object whose gobject class name string matches the definitions in
+// the gtkrc file. MetaFrames derives from GtkWindow.
+//
+// Metaframes can not be instantiated. It has no constructor; instantiate
+// ChromeGtkFrame instead.
+typedef struct _MetaFrames       MetaFrames;
+typedef struct _MetaFramesClass  MetaFramesClass;
+
+struct _MetaFrames {
+  GtkWindow window;
+};
+
+struct _MetaFramesClass {
+  GtkWindowClass parent_class;
+};
+
+
+// The second is ChromeGtkFrame, which defines a number of optional style
+// properties so theme authors can control how chromium appears in gtk-theme
+// mode.  It derives from MetaFrames in chrome so older themes that declare a
+// MetaFrames theme will still work. New themes should target this class.
+typedef struct _ChromeGtkFrame       ChromeGtkFrame;
+typedef struct _ChromeGtkFrameClass  ChromeGtkFrameClass;
+
+struct _ChromeGtkFrame {
+  MetaFrames frames;
+};
+
+struct _ChromeGtkFrameClass {
+  MetaFramesClass frames_class;
+};
+
+// Creates a GtkWindow object the the class name "ChromeGtkFrame".
+GtkWidget* chrome_gtk_frame_new();
+
+G_END_DECLS
+
+#endif  // CHROME_BROWSER_UI_LIBGTKUI_CHROME_GTK_FRAME_H_
--- /dev/null
+++ b/chrome/browser/ui/libgtkui/gtk2/native_theme_gtk2.cc
@@ -0,0 +1,474 @@
+// Copyright (c) 2013 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 "chrome/browser/ui/libgtkui/gtk2/native_theme_gtk2.h"
+
+#include <gtk/gtk.h>
+
+#include "chrome/browser/ui/libgtkui/gtk2/chrome_gtk_frame.h"
+#include "chrome/browser/ui/libgtkui/chrome_gtk_menu_subclasses.h"
+#include "chrome/browser/ui/libgtkui/gtk_ui.h"
+#include "chrome/browser/ui/libgtkui/gtk_util.h"
+#include "chrome/browser/ui/libgtkui/skia_utils_gtk.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include "ui/gfx/color_palette.h"
+#include "ui/gfx/color_utils.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/path.h"
+#include "ui/gfx/skia_util.h"
+#include "ui/native_theme/common_theme.h"
+#include "ui/native_theme/native_theme_aura.h"
+#include "ui/native_theme/native_theme_dark_aura.h"
+
+namespace libgtkui {
+
+namespace {
+
+enum WidgetState {
+  NORMAL = 0,
+  ACTIVE = 1,
+  PRELIGHT = 2,
+  SELECTED = 3,
+  INSENSITIVE = 4,
+};
+
+// Same order as enum WidgetState above
+const GtkStateType stateMap[] = {
+    GTK_STATE_NORMAL,   GTK_STATE_ACTIVE,      GTK_STATE_PRELIGHT,
+    GTK_STATE_SELECTED, GTK_STATE_INSENSITIVE,
+};
+
+SkColor GetFgColor(GtkWidget* widget, WidgetState state) {
+  return GdkColorToSkColor(gtk_rc_get_style(widget)->fg[stateMap[state]]);
+}
+SkColor GetBgColor(GtkWidget* widget, WidgetState state) {
+  return GdkColorToSkColor(gtk_rc_get_style(widget)->bg[stateMap[state]]);
+}
+
+SkColor GetTextColor(GtkWidget* widget, WidgetState state) {
+  return GdkColorToSkColor(gtk_rc_get_style(widget)->text[stateMap[state]]);
+}
+SkColor GetTextAAColor(GtkWidget* widget, WidgetState state) {
+  return GdkColorToSkColor(gtk_rc_get_style(widget)->text_aa[stateMap[state]]);
+}
+SkColor GetBaseColor(GtkWidget* widget, WidgetState state) {
+  return GdkColorToSkColor(gtk_rc_get_style(widget)->base[stateMap[state]]);
+}
+
+}  // namespace
+
+// static
+NativeThemeGtk2* NativeThemeGtk2::instance() {
+  CR_DEFINE_STATIC_LOCAL(NativeThemeGtk2, s_native_theme, ());
+  return &s_native_theme;
+}
+
+// Constructors automatically called
+NativeThemeGtk2::NativeThemeGtk2() {}
+// This doesn't actually get called
+NativeThemeGtk2::~NativeThemeGtk2() {}
+
+void NativeThemeGtk2::PaintMenuPopupBackground(
+    cc::PaintCanvas* canvas,
+    const gfx::Size& size,
+    const MenuBackgroundExtraParams& menu_background) const {
+  if (menu_background.corner_radius > 0) {
+    cc::PaintFlags flags;
+    flags.setStyle(cc::PaintFlags::kFill_Style);
+    flags.setAntiAlias(true);
+    flags.setColor(GetSystemColor(kColorId_MenuBackgroundColor));
+
+    gfx::Path path;
+    SkRect rect = SkRect::MakeWH(SkIntToScalar(size.width()),
+                                 SkIntToScalar(size.height()));
+    SkScalar radius = SkIntToScalar(menu_background.corner_radius);
+    SkScalar radii[8] = {radius, radius, radius, radius,
+                         radius, radius, radius, radius};
+    path.addRoundRect(rect, radii);
+
+    canvas->drawPath(path, flags);
+  } else {
+    canvas->drawColor(GetSystemColor(kColorId_MenuBackgroundColor),
+                      SkBlendMode::kSrc);
+  }
+}
+
+void NativeThemeGtk2::PaintMenuItemBackground(
+    cc::PaintCanvas* canvas,
+    State state,
+    const gfx::Rect& rect,
+    const MenuItemExtraParams& menu_item) const {
+  SkColor color;
+  cc::PaintFlags flags;
+  switch (state) {
+    case NativeTheme::kNormal:
+    case NativeTheme::kDisabled:
+      color = GetSystemColor(NativeTheme::kColorId_MenuBackgroundColor);
+      flags.setColor(color);
+      break;
+    case NativeTheme::kHovered:
+      color =
+          GetSystemColor(NativeTheme::kColorId_FocusedMenuItemBackgroundColor);
+      flags.setColor(color);
+      break;
+    default:
+      NOTREACHED() << "Invalid state " << state;
+      break;
+  }
+  if (menu_item.corner_radius > 0) {
+    const SkScalar radius = SkIntToScalar(menu_item.corner_radius);
+    canvas->drawRoundRect(gfx::RectToSkRect(rect), radius, radius, flags);
+    return;
+  }
+  canvas->drawRect(gfx::RectToSkRect(rect), flags);
+}
+
+SkColor NativeThemeGtk2::GetSystemColor(ColorId color_id) const {
+  const SkColor kPositiveTextColor = SkColorSetRGB(0x0b, 0x80, 0x43);
+  const SkColor kNegativeTextColor = SkColorSetRGB(0xc5, 0x39, 0x29);
+
+  switch (color_id) {
+    // Windows
+    case kColorId_WindowBackground:
+      return GetBgColor(GetWindow(), SELECTED);
+
+    // Dialogs
+    case kColorId_DialogBackground:
+    case kColorId_BubbleBackground:
+      return GetBgColor(GetWindow(), NORMAL);
+
+    // FocusableBorder
+    case kColorId_FocusedBorderColor:
+      return GetBgColor(GetEntry(), SELECTED);
+    case kColorId_UnfocusedBorderColor:
+      return GetTextAAColor(GetEntry(), NORMAL);
+
+    // MenuItem
+    case kColorId_SelectedMenuItemForegroundColor:
+      return GetTextColor(GetMenuItem(), SELECTED);
+    case kColorId_FocusedMenuItemBackgroundColor:
+      return GetBgColor(GetMenuItem(), SELECTED);
+
+    case kColorId_EnabledMenuItemForegroundColor:
+      return GetTextColor(GetMenuItem(), NORMAL);
+    case kColorId_MenuItemMinorTextColor:
+    case kColorId_DisabledMenuItemForegroundColor:
+      return GetTextColor(GetMenuItem(), INSENSITIVE);
+    case kColorId_MenuBorderColor:
+    case kColorId_MenuSeparatorColor:
+      return GetTextColor(GetMenuItem(), INSENSITIVE);
+    case kColorId_MenuBackgroundColor:
+      return GetBgColor(GetMenu(), NORMAL);
+    case kColorId_TouchableMenuItemLabelColor:
+    case kColorId_ActionableSubmenuVerticalSeparatorColor:
+      return kInvalidColorIdColor;
+
+    // Label
+    case kColorId_LabelEnabledColor:
+      return GetTextColor(GetEntry(), NORMAL);
+    case kColorId_LabelDisabledColor:
+      return GetTextColor(GetLabel(), INSENSITIVE);
+    case kColorId_LabelTextSelectionColor:
+      return GetTextColor(GetLabel(), SELECTED);
+    case kColorId_LabelTextSelectionBackgroundFocused:
+      return GetBaseColor(GetLabel(), SELECTED);
+
+    // Link
+    case kColorId_LinkDisabled:
+      return SkColorSetA(GetSystemColor(kColorId_LinkEnabled), 0xBB);
+    case kColorId_LinkEnabled: {
+      SkColor link_color = SK_ColorTRANSPARENT;
+      GdkColor* style_color = nullptr;
+      gtk_widget_style_get(GetWindow(), "link-color", &style_color, nullptr);
+      if (style_color) {
+        link_color = GdkColorToSkColor(*style_color);
+        gdk_color_free(style_color);
+      }
+      if (link_color != SK_ColorTRANSPARENT)
+        return link_color;
+      // Default color comes from gtklinkbutton.c.
+      return SkColorSetRGB(0x00, 0x00, 0xEE);
+    }
+    case kColorId_LinkPressed:
+      return SK_ColorRED;
+
+    // Separator
+    case kColorId_SeparatorColor:
+      return GetFgColor(GetSeparator(), INSENSITIVE);
+
+    // Button
+    case kColorId_ButtonEnabledColor:
+      return GetTextColor(GetButton(), NORMAL);
+    case kColorId_BlueButtonEnabledColor:
+      return GetTextColor(GetBlueButton(), NORMAL);
+    case kColorId_ButtonDisabledColor:
+      return GetTextColor(GetButton(), INSENSITIVE);
+    case kColorId_BlueButtonDisabledColor:
+      return GetTextColor(GetBlueButton(), INSENSITIVE);
+    case kColorId_ButtonHoverColor:
+      return GetTextColor(GetButton(), PRELIGHT);
+    case kColorId_BlueButtonHoverColor:
+      return GetTextColor(GetBlueButton(), PRELIGHT);
+    case kColorId_BlueButtonPressedColor:
+      return GetTextColor(GetBlueButton(), ACTIVE);
+    case kColorId_BlueButtonShadowColor:
+      return SK_ColorTRANSPARENT;
+    case kColorId_ProminentButtonColor:
+      return GetSystemColor(kColorId_LinkEnabled);
+    case kColorId_TextOnProminentButtonColor:
+      return GetTextColor(GetLabel(), SELECTED);
+    case kColorId_ButtonPressedShade:
+      return SK_ColorTRANSPARENT;
+
+    // TabbedPane
+    case ui::NativeTheme::kColorId_TabTitleColorActive:
+      return GetTextColor(GetEntry(), NORMAL);
+    case ui::NativeTheme::kColorId_TabTitleColorInactive:
+      return GetTextColor(GetLabel(), INSENSITIVE);
+    case ui::NativeTheme::kColorId_TabBottomBorder:
+      return GetTextColor(GetEntry(), NORMAL);
+
+    // Textfield
+    case kColorId_TextfieldDefaultColor:
+      return GetTextColor(GetEntry(), NORMAL);
+    case kColorId_TextfieldDefaultBackground:
+      return GetBaseColor(GetEntry(), NORMAL);
+
+    case kColorId_TextfieldReadOnlyColor:
+      return GetTextColor(GetEntry(), ACTIVE);
+    case kColorId_TextfieldReadOnlyBackground:
+      return GetBaseColor(GetEntry(), ACTIVE);
+    case kColorId_TextfieldSelectionColor:
+      return GetTextColor(GetEntry(), SELECTED);
+    case kColorId_TextfieldSelectionBackgroundFocused:
+      return GetBaseColor(GetEntry(), SELECTED);
+
+    // Tooltips
+    case kColorId_TooltipBackground:
+      return GetBgColor(GetTooltip(), NORMAL);
+    case kColorId_TooltipText:
+      return GetFgColor(GetTooltip(), NORMAL);
+
+    // Trees and Tables (implemented on GTK using the same class)
+    case kColorId_TableBackground:
+    case kColorId_TreeBackground:
+      return GetBgColor(GetTree(), NORMAL);
+    case kColorId_TableText:
+    case kColorId_TreeText:
+      return GetTextColor(GetTree(), NORMAL);
+    case kColorId_TableSelectedText:
+    case kColorId_TableSelectedTextUnfocused:
+    case kColorId_TreeSelectedText:
+    case kColorId_TreeSelectedTextUnfocused:
+      return GetTextColor(GetTree(), SELECTED);
+    case kColorId_TableSelectionBackgroundFocused:
+    case kColorId_TableSelectionBackgroundUnfocused:
+    case kColorId_TreeSelectionBackgroundFocused:
+    case kColorId_TreeSelectionBackgroundUnfocused:
+      return GetBgColor(GetTree(), SELECTED);
+    case kColorId_TableGroupingIndicatorColor:
+      return GetTextAAColor(GetTree(), NORMAL);
+
+    // Table Headers
+    case kColorId_TableHeaderText:
+      return GetTextColor(GetTree(), NORMAL);
+    case kColorId_TableHeaderBackground:
+      return GetBgColor(GetTree(), NORMAL);
+    case kColorId_TableHeaderSeparator:
+      return GetFgColor(GetSeparator(), INSENSITIVE);
+
+    // Results Table
+    case kColorId_ResultsTableNormalBackground:
+      return GetSystemColor(kColorId_TextfieldDefaultBackground);
+    case kColorId_ResultsTableHoveredBackground:
+      return color_utils::AlphaBlend(
+          GetSystemColor(kColorId_TextfieldDefaultBackground),
+          GetSystemColor(kColorId_TextfieldSelectionBackgroundFocused), 0x80);
+    case kColorId_ResultsTableSelectedBackground:
+      return GetSystemColor(kColorId_TextfieldSelectionBackgroundFocused);
+    case kColorId_ResultsTableNormalText:
+    case kColorId_ResultsTableHoveredText:
+      return GetSystemColor(kColorId_TextfieldDefaultColor);
+    case kColorId_ResultsTableSelectedText:
+      return GetSystemColor(kColorId_TextfieldSelectionColor);
+    case kColorId_ResultsTableNormalDimmedText:
+    case kColorId_ResultsTableHoveredDimmedText:
+      return color_utils::AlphaBlend(
+          GetSystemColor(kColorId_TextfieldDefaultColor),
+          GetSystemColor(kColorId_TextfieldDefaultBackground), 0x80);
+    case kColorId_ResultsTableSelectedDimmedText:
+      return color_utils::AlphaBlend(
+          GetSystemColor(kColorId_TextfieldSelectionColor),
+          GetSystemColor(kColorId_TextfieldDefaultBackground), 0x80);
+    case kColorId_ResultsTableNormalUrl:
+    case kColorId_ResultsTableHoveredUrl:
+      return NormalURLColor(GetSystemColor(kColorId_TextfieldDefaultColor));
+
+    case kColorId_ResultsTableSelectedUrl:
+      return SelectedURLColor(
+          GetSystemColor(kColorId_TextfieldSelectionColor),
+          GetSystemColor(kColorId_TextfieldSelectionBackgroundFocused));
+
+    case kColorId_ResultsTablePositiveText: {
+      return color_utils::GetReadableColor(kPositiveTextColor,
+                                           GetBaseColor(GetEntry(), NORMAL));
+    }
+    case kColorId_ResultsTablePositiveHoveredText: {
+      return color_utils::GetReadableColor(kPositiveTextColor,
+                                           GetBaseColor(GetEntry(), PRELIGHT));
+    }
+    case kColorId_ResultsTablePositiveSelectedText: {
+      return color_utils::GetReadableColor(kPositiveTextColor,
+                                           GetBaseColor(GetEntry(), SELECTED));
+    }
+    case kColorId_ResultsTableNegativeText: {
+      return color_utils::GetReadableColor(kNegativeTextColor,
+                                           GetBaseColor(GetEntry(), NORMAL));
+    }
+    case kColorId_ResultsTableNegativeHoveredText: {
+      return color_utils::GetReadableColor(kNegativeTextColor,
+                                           GetBaseColor(GetEntry(), PRELIGHT));
+    }
+    case kColorId_ResultsTableNegativeSelectedText: {
+      return color_utils::GetReadableColor(kNegativeTextColor,
+                                           GetBaseColor(GetEntry(), SELECTED));
+    }
+
+    // Throbber
+    case kColorId_ThrobberSpinningColor:
+    case kColorId_ThrobberLightColor:
+      return GetSystemColor(kColorId_TextfieldSelectionBackgroundFocused);
+
+    case kColorId_ThrobberWaitingColor:
+      return color_utils::AlphaBlend(
+          GetSystemColor(kColorId_TextfieldSelectionBackgroundFocused),
+          GetBgColor(GetWindow(), NORMAL), 0x80);
+
+    // Alert icons
+    // Just fall back to the same colors as Aura.
+    case kColorId_AlertSeverityLow:
+    case kColorId_AlertSeverityMedium:
+    case kColorId_AlertSeverityHigh: {
+      ui::NativeTheme* fallback_theme =
+          color_utils::IsDark(GetTextColor(GetEntry(), NORMAL))
+              ? ui::NativeTheme::GetInstanceForNativeUi()
+              : ui::NativeThemeDarkAura::instance();
+      return fallback_theme->GetSystemColor(color_id);
+    }
+
+    case kColorId_NumColors:
+      NOTREACHED();
+      break;
+  }
+
+  return kInvalidColorIdColor;
+}
+
+GtkWidget* NativeThemeGtk2::GetWindow() const {
+  static GtkWidget* fake_window = nullptr;
+
+  if (!fake_window) {
+    fake_window = chrome_gtk_frame_new();
+    gtk_widget_realize(fake_window);
+  }
+
+  return fake_window;
+}
+
+GtkWidget* NativeThemeGtk2::GetEntry() const {
+  static GtkWidget* fake_entry = nullptr;
+
+  if (!fake_entry) {
+    fake_entry = gtk_entry_new();
+
+    // The fake entry needs to be in the window so it can be realized so we can
+    // use the computed parts of the style.
+    gtk_container_add(GTK_CONTAINER(GetWindow()), fake_entry);
+    gtk_widget_realize(fake_entry);
+  }
+
+  return fake_entry;
+}
+
+GtkWidget* NativeThemeGtk2::GetLabel() const {
+  static GtkWidget* fake_label = nullptr;
+
+  if (!fake_label)
+    fake_label = gtk_label_new("");
+
+  return fake_label;
+}
+
+GtkWidget* NativeThemeGtk2::GetButton() const {
+  static GtkWidget* fake_button = nullptr;
+
+  if (!fake_button)
+    fake_button = gtk_button_new();
+
+  return fake_button;
+}
+
+GtkWidget* NativeThemeGtk2::GetBlueButton() const {
+  static GtkWidget* fake_bluebutton = nullptr;
+
+  if (!fake_bluebutton) {
+    fake_bluebutton = gtk_button_new();
+    TurnButtonBlue(fake_bluebutton);
+  }
+
+  return fake_bluebutton;
+}
+
+GtkWidget* NativeThemeGtk2::GetTree() const {
+  static GtkWidget* fake_tree = nullptr;
+
+  if (!fake_tree)
+    fake_tree = gtk_tree_view_new();
+
+  return fake_tree;
+}
+
+GtkWidget* NativeThemeGtk2::GetTooltip() const {
+  static GtkWidget* fake_tooltip = nullptr;
+
+  if (!fake_tooltip) {
+    fake_tooltip = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_widget_set_name(fake_tooltip, "gtk-tooltip");
+    gtk_widget_realize(fake_tooltip);
+  }
+
+  return fake_tooltip;
+}
+
+GtkWidget* NativeThemeGtk2::GetMenu() const {
+  static GtkWidget* fake_menu = nullptr;
+
+  if (!fake_menu)
+    fake_menu = gtk_custom_menu_new();
+
+  return fake_menu;
+}
+
+GtkWidget* NativeThemeGtk2::GetMenuItem() const {
+  static GtkWidget* fake_menu_item = nullptr;
+
+  if (!fake_menu_item) {
+    fake_menu_item = gtk_custom_menu_item_new();
+    gtk_menu_shell_append(GTK_MENU_SHELL(GetMenu()), fake_menu_item);
+  }
+
+  return fake_menu_item;
+}
+
+GtkWidget* NativeThemeGtk2::GetSeparator() const {
+  static GtkWidget* fake_separator = nullptr;
+
+  if (!fake_separator)
+    fake_separator = gtk_hseparator_new();
+
+  return fake_separator;
+}
+
+}  // namespace libgtkui
--- /dev/null
+++ b/chrome/browser/ui/libgtkui/gtk2/native_theme_gtk2.h
@@ -0,0 +1,55 @@
+// Copyright (c) 2013 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 CHROME_BROWSER_UI_LIBGTKUI_NATIVE_THEME_GTK2_H_
+#define CHROME_BROWSER_UI_LIBGTKUI_NATIVE_THEME_GTK2_H_
+
+#include "base/macros.h"
+#include "ui/native_theme/native_theme_base.h"
+
+typedef struct _GtkWidget GtkWidget;
+
+namespace libgtkui {
+
+// A version of NativeTheme that uses GTK2 supplied colours instead of the
+// default aura colours. Analogue to NativeThemeWin, except that can't be
+// compiled into the main chrome binary like the Windows code can.
+class NativeThemeGtk2 : public ui::NativeThemeBase {
+ public:
+  static NativeThemeGtk2* instance();
+
+  // Overridden from ui::NativeThemeBase:
+  SkColor GetSystemColor(ColorId color_id) const override;
+  void PaintMenuPopupBackground(
+      cc::PaintCanvas* canvas,
+      const gfx::Size& size,
+      const MenuBackgroundExtraParams& menu_background) const override;
+  void PaintMenuItemBackground(
+      cc::PaintCanvas* canvas,
+      State state,
+      const gfx::Rect& rect,
+      const MenuItemExtraParams& menu_item) const override;
+
+ private:
+  NativeThemeGtk2();
+  ~NativeThemeGtk2() override;
+
+  // Returns various widgets for theming use.
+  GtkWidget* GetWindow() const;
+  GtkWidget* GetEntry() const;
+  GtkWidget* GetLabel() const;
+  GtkWidget* GetButton() const;
+  GtkWidget* GetBlueButton() const;
+  GtkWidget* GetTree() const;
+  GtkWidget* GetTooltip() const;
+  GtkWidget* GetMenu() const;
+  GtkWidget* GetMenuItem() const;
+  GtkWidget* GetSeparator() const;
+
+  DISALLOW_COPY_AND_ASSIGN(NativeThemeGtk2);
+};
+
+}  // namespace libgtkui
+
+#endif  // CHROME_BROWSER_UI_LIBGTKUI_NATIVE_THEME_GTK2_H_
--- /dev/null
+++ b/ui/accessibility/platform/atk_util_auralinux_gtk2.cc
@@ -0,0 +1,84 @@
+// Copyright 2017 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 <glib-2.0/gmodule.h>
+
+#include "base/bind.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/logging.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/task/post_task.h"
+#include "ui/accessibility/platform/atk_util_auralinux.h"
+
+typedef void (*GnomeAccessibilityModuleInitFunc)();
+
+const char kAtkBridgeModule[] = "atk-bridge";
+const char kAtkBridgePath[] = "gtk-2.0/modules/libatk-bridge.so";
+const char kAtkBridgeSymbolName[] = "gnome_accessibility_module_init";
+const char kGtkModules[] = "GTK_MODULES";
+
+namespace ui {
+
+// Returns a function pointer to be invoked on the main thread to init
+// the gnome accessibility module if it's enabled (nullptr otherwise).
+GnomeAccessibilityModuleInitFunc GetAccessibilityModuleInitFunc() {
+  base::AssertBlockingAllowed();
+
+  // Try to load libatk-bridge.so.
+  base::FilePath atk_bridge_path(ATK_LIB_DIR);
+  atk_bridge_path = atk_bridge_path.Append(kAtkBridgePath);
+  GModule* bridge = g_module_open(atk_bridge_path.value().c_str(),
+                                  static_cast<GModuleFlags>(0));
+  if (!bridge) {
+    VLOG(1) << "Unable to open module " << atk_bridge_path.value();
+    return nullptr;
+  }
+
+  GnomeAccessibilityModuleInitFunc init_func = nullptr;
+
+  if (!g_module_symbol(bridge, kAtkBridgeSymbolName, (gpointer*)&init_func)) {
+    VLOG(1) << "Unable to get symbol pointer from " << atk_bridge_path.value();
+    return nullptr;
+  }
+
+  DCHECK(init_func);
+  return init_func;
+}
+
+void FinishAccessibilityInitOnMainThread(
+    GnomeAccessibilityModuleInitFunc init_func) {
+  if (!init_func) {
+    VLOG(1) << "Will not enable ATK accessibility support.";
+    return;
+  }
+
+  init_func();
+}
+
+bool AtkUtilAuraLinux::PlatformShouldEnableAccessibility() {
+  std::unique_ptr<base::Environment> env(base::Environment::Create());
+  std::string gtk_modules;
+  if (!env->GetVar(kGtkModules, &gtk_modules))
+    return false;
+
+  for (const std::string& module :
+       base::SplitString(gtk_modules, ":", base::TRIM_WHITESPACE,
+                         base::SPLIT_WANT_NONEMPTY)) {
+    if (module == kAtkBridgeModule)
+      return true;
+  }
+  return false;
+}
+
+void AtkUtilAuraLinux::PlatformInitializeAsync() {
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE,
+      {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::Bind(&GetAccessibilityModuleInitFunc),
+      base::Bind(&FinishAccessibilityInitOnMainThread));
+}
+
+}  // namespace ui
