diff src/gui_gtk.c @ 8218:3456e2ebebd4 v7.4.1402

commit https://github.com/vim/vim/commit/9892189d2e7ab94b750f99e6da4cbfc3c8014517 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Feb 23 17:14:37 2016 +0100 patch 7.4.1402 Problem: GTK 3 is not supported. Solution: Add GTK 3 support. (Kazunobu Kuriyama)
author Christian Brabandt <cb@256bit.org>
date Tue, 23 Feb 2016 17:15:05 +0100
parents 81794242a275
children 738c2929d6ad
line wrap: on
line diff
--- a/src/gui_gtk.c
+++ b/src/gui_gtk.c
@@ -22,8 +22,17 @@
  *
  * Best supporting actor (He helped somewhat, aesthetically speaking):
  * Maxime Romano <verbophobe@hotmail.com>
+ *
+ * Support for GTK+ 3 was added by:
+ *
+ * 2016  Kazunobu Kuriyama  <kazunobu.kuriyama@gmail.com>
+ *
+ * With the help of Marius Gedminas and the word of Bram Moolenaar,
+ * "Let's give this some time to mature."
  */
 
+#include "vim.h"
+
 #ifdef FEAT_GUI_GTK
 # include "gui_gtk_f.h"
 #endif
@@ -37,8 +46,6 @@
 # undef MAX
 #endif
 
-#include "vim.h"
-
 #ifdef FEAT_GUI_GNOME
 /* Gnome redefines _() and N_().  Grrr... */
 # ifdef _
@@ -63,7 +70,11 @@
 #endif
 
 #ifdef FEAT_GUI_GTK
-# include <gdk/gdkkeysyms.h>
+# if GTK_CHECK_VERSION(3,0,0)
+#  include <gdk/gdkkeysyms-compat.h>
+# else
+#  include <gdk/gdkkeysyms.h>
+# endif
 # include <gdk/gdk.h>
 # ifdef WIN3264
 #  include <gdk/gdkwin32.h>
@@ -104,6 +115,70 @@ static void recent_func_log_func(
  * match toolbar_names[] in menu.c!  All stock icons including the "vim-*"
  * ones can be overridden in your gtkrc file.
  */
+# if GTK_CHECK_VERSION(3,10,0)
+static const char * const menu_themed_names[] =
+{
+    /* 00 */ "document-new",		/* sub. GTK_STOCK_NEW */
+    /* 01 */ "document-open",		/* sub. GTK_STOCK_OPEN */
+    /* 02 */ "document-save",		/* sub. GTK_STOCK_SAVE */
+    /* 03 */ "edit-undo",		/* sub. GTK_STOCK_UNDO */
+    /* 04 */ "edit-redo",		/* sub. GTK_STOCK_REDO */
+    /* 05 */ "edit-cut",		/* sub. GTK_STOCK_CUT */
+    /* 06 */ "edit-copy",		/* sub. GTK_STOCK_COPY */
+    /* 07 */ "edit-paste",		/* sub. GTK_STOCK_PASTE */
+    /* 08 */ "document-print",		/* sub. GTK_STOCK_PRINT */
+    /* 09 */ "help-browser",		/* sub. GTK_STOCK_HELP */
+    /* 10 */ "edit-find",		/* sub. GTK_STOCK_FIND */
+#  if GTK_CHECK_VERSION(3,14,0)
+    /* Use the file names in gui_gtk_res.xml, cutting off the extension.
+     * Similar changes follow. */
+    /* 11 */ "stock_vim_save_all",
+    /* 12 */ "stock_vim_session_save",
+    /* 13 */ "stock_vim_session_new",
+    /* 14 */ "stock_vim_session_load",
+#  else
+    /* 11 */ "vim-save-all",
+    /* 12 */ "vim-session-save",
+    /* 13 */ "vim-session-new",
+    /* 14 */ "vim-session-load",
+#  endif
+    /* 15 */ "system-run",		/* sub. GTK_STOCK_EXECUTE */
+    /* 16 */ "edit-find-replace",	/* sub. GTK_STOCK_FIND_AND_REPLACE */
+    /* 17 */ "window-close",		/* sub. GTK_STOCK_CLOSE, FIXME: fuzzy */
+#  if GTK_CHECK_VERSION(3,14,0)
+    /* 18 */ "stock_vim_window_maximize",
+    /* 19 */ "stock_vim_window_minimize",
+    /* 20 */ "stock_vim_window_split",
+    /* 21 */ "stock_vim_shell",
+#  else
+    /* 18 */ "vim-window-maximize",
+    /* 19 */ "vim-window-minimize",
+    /* 20 */ "vim-window-split",
+    /* 21 */ "vim-shell",
+#  endif
+    /* 22 */ "go-previous",		/* sub. GTK_STOCK_GO_BACK */
+    /* 23 */ "go-next",			/* sub. GTK_STOCK_GO_FORWARD */
+#  if GTK_CHECK_VERSION(3,14,0)
+    /* 24 */ "stock_vim_find_help",
+#  else
+    /* 24 */ "vim-find-help",
+#  endif
+    /* 25 */ "gtk-convert",		/* sub. GTK_STOCK_CONVERT */
+    /* 26 */ "go-jump",			/* sub. GTK_STOCK_JUMP_TO */
+#  if GTK_CHECK_VERSION(3,14,0)
+    /* 27 */ "stock_vim_build_tags",
+    /* 28 */ "stock_vim_window_split_vertical",
+    /* 29 */ "stock_vim_window_maximize_width",
+    /* 30 */ "stock_vim_window_minimize_width",
+#  else
+    /* 27 */ "vim-build-tags",
+    /* 28 */ "vim-window-split-vertical",
+    /* 29 */ "vim-window-maximize-width",
+    /* 30 */ "vim-window-minimize-width",
+#  endif
+    /* 31 */ "application-exit",	/* GTK_STOCK_QUIT */
+};
+# else /* !GTK_CHECK_VERSION(3,10,0) */
 static const char * const menu_stock_ids[] =
 {
     /* 00 */ GTK_STOCK_NEW,
@@ -139,8 +214,10 @@ static const char * const menu_stock_ids
     /* 30 */ "vim-window-minimize-width",
     /* 31 */ GTK_STOCK_QUIT
 };
+# endif /* !GTK_CHECK_VERSION(3,10,0) */
 
-#ifdef USE_GRESOURCE
+# ifdef USE_GRESOURCE
+#  if !GTK_CHECK_VERSION(3,10,0)
 typedef struct IconNames {
     const char *icon_name;
     const char *file_name;
@@ -162,9 +239,10 @@ static IconNames stock_vim_icons[] = {
     { "vim-window-split-vertical", "stock_vim_window_split_vertical.png" },
     { NULL, NULL }
 };
-#endif
+#  endif
+# endif /* USE_G_RESOURCE */
 
-#ifndef USE_GRESOURCE
+# ifndef USE_GRESOURCE
     static void
 add_stock_icon(GtkIconFactory	*factory,
 	       const char	*stock_id,
@@ -182,7 +260,7 @@ add_stock_icon(GtkIconFactory	*factory,
     gtk_icon_set_unref(icon_set);
     g_object_unref(pixbuf);
 }
-#endif
+# endif
 
     static int
 lookup_menu_iconfile(char_u *iconfile, char_u *dest)
@@ -214,6 +292,52 @@ lookup_menu_iconfile(char_u *iconfile, c
 load_menu_iconfile(char_u *name, GtkIconSize icon_size)
 {
     GtkWidget	    *image = NULL;
+# if GTK_CHECK_VERSION(3,10,0)
+    int		     pixel_size = -1;
+
+    switch (icon_size)
+    {
+	case GTK_ICON_SIZE_MENU:
+	    pixel_size = 16;
+	    break;
+	case GTK_ICON_SIZE_SMALL_TOOLBAR:
+	    pixel_size = 16;
+	    break;
+	case GTK_ICON_SIZE_LARGE_TOOLBAR:
+	    pixel_size = 24;
+	    break;
+	case GTK_ICON_SIZE_BUTTON:
+	    pixel_size = 16;
+	    break;
+	case GTK_ICON_SIZE_DND:
+	    pixel_size = 32;
+	    break;
+	case GTK_ICON_SIZE_DIALOG:
+	    pixel_size = 48;
+	    break;
+	case GTK_ICON_SIZE_INVALID:
+	    /* FALLTHROUGH */
+	default:
+	    pixel_size = 0;
+	    break;
+    }
+
+    if (pixel_size > 0 || pixel_size == -1)
+    {
+	GdkPixbuf * const pixbuf
+	    = gdk_pixbuf_new_from_file_at_scale((const char *)name,
+		pixel_size, pixel_size, TRUE, NULL);
+	if (pixbuf != NULL)
+	{
+	    image = gtk_image_new_from_pixbuf(pixbuf);
+	    g_object_unref(pixbuf);
+	}
+    }
+    if (image == NULL)
+	image = gtk_image_new_from_icon_name("image-missing", icon_size);
+
+    return image;
+# else /* !GTK_CHECK_VERSION(3,10,0) */
     GtkIconSet	    *icon_set;
     GtkIconSource   *icon_source;
 
@@ -234,6 +358,7 @@ load_menu_iconfile(char_u *name, GtkIcon
     gtk_icon_set_unref(icon_set);
 
     return image;
+# endif /* !GTK_CHECK_VERSION(3,10,0) */
 }
 
     static GtkWidget *
@@ -254,6 +379,17 @@ create_menu_icon(vimmenu_T *menu, GtkIco
     /* Still not found?  Then use a builtin icon, a blank one as fallback. */
     if (image == NULL)
     {
+# if GTK_CHECK_VERSION(3,10,0)
+	const char *icon_name = NULL;
+	const int   n_names = G_N_ELEMENTS(menu_themed_names);
+
+	if (menu->iconidx >= 0 && menu->iconidx < n_names)
+	    icon_name = menu_themed_names[menu->iconidx];
+	if (icon_name == NULL)
+	    icon_name = "image-missing";
+
+	image = gtk_image_new_from_icon_name(icon_name, icon_size);
+# else
 	const char  *stock_id;
 	const int   n_ids = G_N_ELEMENTS(menu_stock_ids);
 
@@ -263,6 +399,7 @@ create_menu_icon(vimmenu_T *menu, GtkIco
 	    stock_id = GTK_STOCK_MISSING_IMAGE;
 
 	image = gtk_image_new_from_stock(stock_id, icon_size);
+# endif
     }
 
     return image;
@@ -288,12 +425,12 @@ toolbar_button_focus_in_event(GtkWidget 
     void
 gui_gtk_register_stock_icons(void)
 {
-#ifndef USE_GRESOURCE
-# include "../pixmaps/stock_icons.h"
+# ifndef USE_GRESOURCE
+#  include "../pixmaps/stock_icons.h"
     GtkIconFactory *factory;
 
     factory = gtk_icon_factory_new();
-# define ADD_ICON(Name, Data) add_stock_icon(factory, Name, Data, (int)sizeof(Data))
+#  define ADD_ICON(Name, Data) add_stock_icon(factory, Name, Data, (int)sizeof(Data))
 
     ADD_ICON("vim-build-tags",		  stock_vim_build_tags);
     ADD_ICON("vim-find-help",		  stock_vim_find_help);
@@ -309,35 +446,91 @@ gui_gtk_register_stock_icons(void)
     ADD_ICON("vim-window-split",	  stock_vim_window_split);
     ADD_ICON("vim-window-split-vertical", stock_vim_window_split_vertical);
 
-# undef ADD_ICON
-#else
-    GtkIconFactory * const factory = gtk_icon_factory_new();
+#  undef ADD_ICON
+
+    gtk_icon_factory_add_default(factory);
+    g_object_unref(factory);
+# else /* defined(USE_GRESOURCE) */
     const char * const path_prefix = "/org/vim/gui/icon";
+#  if GTK_CHECK_VERSION(3,14,0)
+    GdkScreen    *screen = NULL;
+    GtkIconTheme *icon_theme = NULL;
+
+    if (GTK_IS_WIDGET(gui.mainwin))
+	screen = gtk_widget_get_screen(gui.mainwin);
+    else
+	screen = gdk_screen_get_default();
+    icon_theme = gtk_icon_theme_get_for_screen(screen);
+    gtk_icon_theme_add_resource_path(icon_theme, path_prefix);
+#  elif GTK_CHECK_VERSION(3,0,0)
     IconNames *names;
 
     for (names = stock_vim_icons; names->icon_name != NULL; names++)
     {
-        char path[MAXPATHL];
-        GdkPixbuf *pixbuf;
+	char path[MAXPATHL];
 
-        vim_snprintf(path, MAXPATHL, "%s/%s", path_prefix, names->file_name);
-        pixbuf = gdk_pixbuf_new_from_resource(path, NULL);
-        if (pixbuf != NULL)
-        {
-            GtkIconSet *icon_set = gtk_icon_set_new_from_pixbuf(pixbuf);
-            gtk_icon_factory_add(factory, names->icon_name, icon_set);
-            gtk_icon_set_unref(icon_set);
-            g_object_unref(pixbuf);
-        }
+	vim_snprintf(path, MAXPATHL, "%s/%s", path_prefix, names->file_name);
+	GdkPixbuf *pixbuf = NULL;
+	pixbuf = gdk_pixbuf_new_from_resource(path, NULL);
+	if (pixbuf != NULL)
+	{
+	    const gint size = MAX(gdk_pixbuf_get_width(pixbuf),
+				  gdk_pixbuf_get_height(pixbuf));
+	    if (size > 16)
+	    {
+		/* An icon theme is supposed to provide fixed-size
+		 * image files for each size, e.g., 16, 22, 24, ...
+		 * Naturally, in contrast to GtkIconSet, GtkIconTheme
+		 * won't prepare size variants for us out of a single
+		 * fixed-size image.
+		 *
+		 * Currently, Vim provides 24x24 images only while the
+		 * icon size on the menu and the toolbar is set to 16x16
+		 * by default.
+		 *
+		 * Resize them by ourselves until we have our own fully
+		 * fledged icon theme. */
+		GdkPixbuf *src = pixbuf;
+		pixbuf = gdk_pixbuf_scale_simple(src,
+						 16, 16,
+						 GDK_INTERP_BILINEAR);
+		if (pixbuf == NULL)
+		    pixbuf = src;
+		else
+		    g_object_unref(src);
+	    }
+	    gtk_icon_theme_add_builtin_icon(names->icon_name, size, pixbuf);
+	    g_object_unref(pixbuf);
+	}
     }
-#endif
+#  else /* !GTK_CHECK_VERSION(3,0.0) */
+    GtkIconFactory * const factory = gtk_icon_factory_new();
+    IconNames *names;
+
+    for (names = stock_vim_icons; names->icon_name != NULL; names++)
+    {
+	char path[MAXPATHL];
+	GdkPixbuf *pixbuf;
+
+	vim_snprintf(path, MAXPATHL, "%s/%s", path_prefix, names->file_name);
+	pixbuf = gdk_pixbuf_new_from_resource(path, NULL);
+	if (pixbuf != NULL)
+	{
+	    GtkIconSet *icon_set = gtk_icon_set_new_from_pixbuf(pixbuf);
+	    gtk_icon_factory_add(factory, names->icon_name, icon_set);
+	    gtk_icon_set_unref(icon_set);
+	    g_object_unref(pixbuf);
+	}
+    }
+
     gtk_icon_factory_add_default(factory);
     g_object_unref(factory);
+#  endif /* !GTK_CHECK_VERSION(3,0,0) */
+# endif /* defined(USE_GRESOURCE) */
 }
 
 #endif /* FEAT_TOOLBAR */
 
-
 #if defined(FEAT_MENU) || defined(PROTO)
 
 /*
@@ -408,7 +601,12 @@ menu_item_new(vimmenu_T *menu, GtkWidget
      * changes to Vim's menu system.  Not to mention that all the translations
      * had to be updated. */
     menu->id = gtk_menu_item_new();
+# if GTK_CHECK_VERSION(3,2,0)
+    box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 20);
+    gtk_box_set_homogeneous(GTK_BOX(box), FALSE);
+# else
     box = gtk_hbox_new(FALSE, 20);
+# endif
 
     use_mnemonic = (p_wak[0] != 'n' || !GTK_IS_MENU_BAR(parent_widget));
     text = translate_mnemonic_tag(menu->name, use_mnemonic);
@@ -465,10 +663,17 @@ gui_mch_add_menu(vimmenu_T *menu, int id
     gtk_menu_set_accel_group(GTK_MENU(menu->submenu_id), gui.accel_group);
     gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu->id), menu->submenu_id);
 
+# if !GTK_CHECK_VERSION(3,4,0)
     menu->tearoff_handle = gtk_tearoff_menu_item_new();
     if (vim_strchr(p_go, GO_TEAROFF) != NULL)
 	gtk_widget_show(menu->tearoff_handle);
+#  if GTK_CHECK_VERSION(3,0,0)
+    gtk_menu_shell_prepend(GTK_MENU_SHELL(menu->submenu_id),
+	    menu->tearoff_handle);
+#  else
     gtk_menu_prepend(GTK_MENU(menu->submenu_id), menu->tearoff_handle);
+#  endif
+# endif
 }
 
     static void
@@ -494,7 +699,17 @@ gui_mch_add_menu_item(vimmenu_T *menu, i
 
 	if (menu_is_separator(menu->name))
 	{
+#  if GTK_CHECK_VERSION(3,0,0)
+	    GtkToolItem *item = gtk_separator_tool_item_new();
+	    gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(item),
+		    TRUE);
+	    gtk_tool_item_set_expand(GTK_TOOL_ITEM(item), FALSE);
+	    gtk_widget_show(GTK_WIDGET(item));
+
+	    gtk_toolbar_insert(toolbar, item, idx);
+#  else
 	    gtk_toolbar_insert_space(toolbar, idx);
+#  endif
 	    menu->id = NULL;
 	}
 	else
@@ -509,6 +724,24 @@ gui_mch_add_menu_item(vimmenu_T *menu, i
 		 * a nasty GTK error message, skip the tooltip. */
 		CONVERT_TO_UTF8_FREE(tooltip);
 
+#  if GTK_CHECK_VERSION(3,0,0)
+	    {
+		GtkWidget *icon;
+		GtkToolItem *item;
+
+		icon = create_menu_icon(menu,
+			gtk_toolbar_get_icon_size(toolbar));
+		item = gtk_tool_button_new(icon, (const gchar *)text);
+		gtk_tool_item_set_tooltip_text(item, (const gchar *)tooltip);
+		g_signal_connect(G_OBJECT(item), "clicked",
+			G_CALLBACK(&menu_item_activate), menu);
+		gtk_widget_show_all(GTK_WIDGET(item));
+
+		gtk_toolbar_insert(toolbar, item, idx);
+
+		menu->id = GTK_WIDGET(item);
+	    }
+#  else
 	    menu->id = gtk_toolbar_insert_item(
 		    toolbar,
 		    (const char *)text,
@@ -518,10 +751,16 @@ gui_mch_add_menu_item(vimmenu_T *menu, i
 		    G_CALLBACK(&menu_item_activate),
 		    menu,
 		    idx);
+#  endif
 
 	    if (gtk_socket_id != 0)
+#  if GTK_CHECK_VERSION(3,0,0)
+		g_signal_connect(G_OBJECT(menu->id), "focus-in-event",
+			G_CALLBACK(toolbar_button_focus_in_event), NULL);
+#  else
 		gtk_signal_connect(GTK_OBJECT(menu->id), "focus_in_event",
 			GTK_SIGNAL_FUNC(toolbar_button_focus_in_event), NULL);
+#  endif
 
 	    CONVERT_TO_UTF8_FREE(text);
 	    CONVERT_TO_UTF8_FREE(tooltip);
@@ -545,7 +784,12 @@ gui_mch_add_menu_item(vimmenu_T *menu, i
 	    menu->id = gtk_menu_item_new();
 	    gtk_widget_set_sensitive(menu->id, FALSE);
 	    gtk_widget_show(menu->id);
+# if GTK_CHECK_VERSION(3,0,0)
+	    gtk_menu_shell_insert(GTK_MENU_SHELL(parent->submenu_id),
+		    menu->id, idx);
+# else
 	    gtk_menu_insert(GTK_MENU(parent->submenu_id), menu->id, idx);
+# endif
 
 	    return;
 	}
@@ -553,11 +797,21 @@ gui_mch_add_menu_item(vimmenu_T *menu, i
 	/* Add textual menu item. */
 	menu_item_new(menu, parent->submenu_id);
 	gtk_widget_show(menu->id);
+# if GTK_CHECK_VERSION(3,0,0)
+	gtk_menu_shell_insert(GTK_MENU_SHELL(parent->submenu_id),
+		menu->id, idx);
+# else
 	gtk_menu_insert(GTK_MENU(parent->submenu_id), menu->id, idx);
+# endif
 
 	if (menu->id != NULL)
+# if GTK_CHECK_VERSION(3,0,0)
+	    g_signal_connect(G_OBJECT(menu->id), "activate",
+			     G_CALLBACK(menu_item_activate), menu);
+# else
 	    gtk_signal_connect(GTK_OBJECT(menu->id), "activate",
 			       GTK_SIGNAL_FUNC(menu_item_activate), menu);
+# endif
     }
 }
 #endif /* FEAT_MENU */
@@ -592,6 +846,7 @@ gui_gtk_set_mnemonics(int enable)
     }
 }
 
+# if !GTK_CHECK_VERSION(3,4,0)
     static void
 recurse_tearoffs(vimmenu_T *menu, int val)
 {
@@ -608,12 +863,21 @@ recurse_tearoffs(vimmenu_T *menu, int va
 	recurse_tearoffs(menu->children, val);
     }
 }
+# endif
 
+# if GTK_CHECK_VERSION(3,4,0)
+    void
+gui_mch_toggle_tearoffs(int enable UNUSED)
+{
+    /* Do nothing */
+}
+# else
     void
 gui_mch_toggle_tearoffs(int enable)
 {
     recurse_tearoffs(root_menu, enable);
 }
+# endif
 #endif /* FEAT_MENU */
 
 #if defined(FEAT_TOOLBAR)
@@ -644,10 +908,15 @@ gui_mch_menu_set_tip(vimmenu_T *menu)
 	char_u *tooltip;
 
 	tooltip = CONVERT_TO_UTF8(menu->strings[MENU_INDEX_TIP]);
-	if (tooltip == NULL || utf_valid_string(tooltip, NULL))
+	if (tooltip != NULL && utf_valid_string(tooltip, NULL))
+# if GTK_CHECK_VERSION(3,0,0)
 	    /* Only set the tooltip when it's valid utf-8. */
-	gtk_tooltips_set_tip(GTK_TOOLBAR(gui.toolbar)->tooltips,
-			     menu->id, (const char *)tooltip, NULL);
+	    gtk_widget_set_tooltip_text(menu->id, (const gchar *)tooltip);
+# else
+	    /* Only set the tooltip when it's valid utf-8. */
+	    gtk_tooltips_set_tip(GTK_TOOLBAR(gui.toolbar)->tooltips,
+				 menu->id, (const char *)tooltip, NULL);
+# endif
 	CONVERT_TO_UTF8_FREE(tooltip);
     }
 }
@@ -676,8 +945,20 @@ gui_mch_destroy_menu(vimmenu_T *menu)
     if (menu->parent != NULL && menu_is_toolbar(menu->parent->name))
     {
 	if (menu_is_separator(menu->name))
+#  if GTK_CHECK_VERSION(3,0,0)
+	{
+	    GtkToolItem *item = NULL;
+
+	    item = gtk_toolbar_get_nth_item(GTK_TOOLBAR(gui.toolbar),
+					    get_menu_position(menu));
+	    if (item != NULL)
+		gtk_container_remove(GTK_CONTAINER(gui.toolbar),
+				     GTK_WIDGET(item));
+	}
+#  else
 	    gtk_toolbar_remove_space(GTK_TOOLBAR(gui.toolbar),
 				     get_menu_position(menu));
+#  endif
 	else if (menu->id != NULL)
 	    gtk_widget_destroy(menu->id);
     }
@@ -711,18 +992,42 @@ gui_mch_set_scrollbar_thumb(scrollbar_T 
 
 	adjustment = gtk_range_get_adjustment(GTK_RANGE(sb->id));
 
+#if GTK_CHECK_VERSION(3,0,0)
+	gtk_adjustment_set_lower(adjustment, 0.0);
+	gtk_adjustment_set_value(adjustment, val);
+	gtk_adjustment_set_upper(adjustment, max + 1);
+	gtk_adjustment_set_page_size(adjustment, size);
+	gtk_adjustment_set_page_increment(adjustment,
+					  size < 3L ? 1L : size - 2L);
+	gtk_adjustment_set_step_increment(adjustment, 1.0);
+#else
 	adjustment->lower = 0.0;
 	adjustment->value = val;
 	adjustment->upper = max + 1;
 	adjustment->page_size = size;
 	adjustment->page_increment = size < 3L ? 1L : size - 2L;
 	adjustment->step_increment = 1.0;
+#endif
 
+#if GTK_CHECK_VERSION(3,0,0)
+	g_signal_handler_block(G_OBJECT(adjustment),
+						      (gulong)sb->handler_id);
+#else
 	g_signal_handler_block(GTK_OBJECT(adjustment),
 						      (gulong)sb->handler_id);
+#endif
+
+#if !GTK_CHECK_VERSION(3,18,0)
 	gtk_adjustment_changed(adjustment);
+#endif
+
+#if GTK_CHECK_VERSION(3,0,0)
+	g_signal_handler_unblock(G_OBJECT(adjustment),
+						      (gulong)sb->handler_id);
+#else
 	g_signal_handler_unblock(GTK_OBJECT(adjustment),
 						      (gulong)sb->handler_id);
+#endif
     }
 }
 
@@ -750,7 +1055,12 @@ adjustment_value_changed(GtkAdjustment *
 #endif
 
     sb = gui_find_scrollbar((long)data);
+#if GTK_CHECK_VERSION(3,0,0)
+    value = gtk_adjustment_get_value(adjustment);
+#else
     value = (long)adjustment->value;
+#endif
+#if !GTK_CHECK_VERSION(3,0,0)
     /*
      * The dragging argument must be right for the scrollbar to work with
      * closed folds.  This isn't documented, hopefully this will keep on
@@ -793,7 +1103,7 @@ adjustment_value_changed(GtkAdjustment *
 	    }
 	}
     }
-
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
     gui_drag_scrollbar(sb, value, dragging);
 }
 
@@ -802,23 +1112,42 @@ adjustment_value_changed(GtkAdjustment *
 gui_mch_create_scrollbar(scrollbar_T *sb, int orient)
 {
     if (orient == SBAR_HORIZ)
+#if GTK_CHECK_VERSION(3,2,0)
+	sb->id = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, NULL);
+#else
 	sb->id = gtk_hscrollbar_new(NULL);
+#endif
     else if (orient == SBAR_VERT)
+#if GTK_CHECK_VERSION(3,2,0)
+	sb->id = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, NULL);
+#else
 	sb->id = gtk_vscrollbar_new(NULL);
+#endif
 
     if (sb->id != NULL)
     {
 	GtkAdjustment *adjustment;
 
+#if GTK_CHECK_VERSION(3,0,0)
+	gtk_widget_set_can_focus(sb->id, FALSE);
+#else
 	GTK_WIDGET_UNSET_FLAGS(sb->id, GTK_CAN_FOCUS);
+#endif
 	gtk_form_put(GTK_FORM(gui.formwin), sb->id, 0, 0);
 
 	adjustment = gtk_range_get_adjustment(GTK_RANGE(sb->id));
 
+#if GTK_CHECK_VERSION(3,0,0)
+	sb->handler_id = g_signal_connect(
+			     G_OBJECT(adjustment), "value-changed",
+			     G_CALLBACK(adjustment_value_changed),
+			     GINT_TO_POINTER(sb->ident));
+#else
 	sb->handler_id = gtk_signal_connect(
 			     GTK_OBJECT(adjustment), "value_changed",
 			     GTK_SIGNAL_FUNC(adjustment_value_changed),
 			     GINT_TO_POINTER(sb->ident));
+#endif
 	gui_mch_update();
     }
 }
@@ -932,8 +1261,13 @@ gui_mch_browse(int saving UNUSED,
 	    GTK_WINDOW(gui.mainwin),
 	    saving ? GTK_FILE_CHOOSER_ACTION_SAVE
 					   : GTK_FILE_CHOOSER_ACTION_OPEN,
+# if GTK_CHECK_VERSION(3,10,0)
+	    _("_Cancel"), GTK_RESPONSE_CANCEL,
+	    saving ? _("_Save") : _("_Open"), GTK_RESPONSE_ACCEPT,
+# else
 	    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 	    saving ? GTK_STOCK_SAVE : GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+# endif
 	    NULL);
     gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fc),
 						       (const gchar *)dirbuf);
@@ -991,7 +1325,7 @@ gui_mch_browse(int saving UNUSED,
     }
     gtk_widget_destroy(GTK_WIDGET(fc));
 
-#else
+#else /* !USE_FILE_CHOOSER */
 
     if (gui.filedlg == NULL)
     {
@@ -1027,7 +1361,7 @@ gui_mch_browse(int saving UNUSED,
 
     gtk_widget_show(gui.filedlg);
     gtk_main();
-#endif
+#endif /* !USE_FILE_CHOOSER */
     g_log_remove_handler(domain, log_handler);
 
     CONVERT_TO_UTF8_FREE(title);
@@ -1062,8 +1396,13 @@ gui_mch_browsedir(
 	    (const gchar *)title,
 	    GTK_WINDOW(gui.mainwin),
 	    GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+#  if GTK_CHECK_VERSION(3,10,0)
+	    _("_Cancel"), GTK_RESPONSE_CANCEL,
+	    _("_OK"), GTK_RESPONSE_ACCEPT,
+#  else
 	    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
 	    GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+#  endif
 	    NULL);
 
     CONVERT_TO_UTF8_FREE(title);
@@ -1096,10 +1435,10 @@ gui_mch_browsedir(
     g_free(dirname);
     return p;
 
-# else
+# else /* !defined(GTK_FILE_CHOOSER) */
     /* For GTK 2.2 and earlier: fall back to ordinary file selector. */
     return gui_mch_browse(0, title, NULL, NULL, initdir, NULL);
-# endif
+# endif /* !defined(GTK_FILE_CHOOSER) */
 }
 
 
@@ -1266,6 +1605,11 @@ dialog_add_buttons(GtkDialog *dialog, ch
     /* Check 'v' flag in 'guioptions': vertical button placement. */
     if (vim_strchr(p_go, GO_VERTICAL) != NULL)
     {
+# if GTK_CHECK_VERSION(3,0,0)
+	/* Add GTK+ 3 code if necessary. */
+	/* N.B. GTK+ 3 doesn't allow you to access vbox and action_area via
+	 * the C API. */
+# else
 	GtkWidget	*vbutton_box;
 
 	vbutton_box = gtk_vbutton_box_new();
@@ -1274,6 +1618,7 @@ dialog_add_buttons(GtkDialog *dialog, ch
 						 vbutton_box, TRUE, FALSE, 0);
 	/* Overrule the "action_area" value, hopefully this works... */
 	GTK_DIALOG(dialog)->action_area = vbutton_box;
+# endif
     }
 
     /*
@@ -1308,6 +1653,16 @@ dialog_add_buttons(GtkDialog *dialog, ch
 	 */
 	if (ok != NULL && ync != NULL) /* almost impossible to fail */
 	{
+# if GTK_CHECK_VERSION(3,10,0)
+	    if	    (button_equal(label, ok[0]))    label = _("OK");
+	    else if (button_equal(label, ync[0]))   label = _("Yes");
+	    else if (button_equal(label, ync[1]))   label = _("No");
+	    else if (button_equal(label, ync[2]))   label = _("Cancel");
+	    else if (button_equal(label, "Ok"))     label = _("OK");
+	    else if (button_equal(label, "Yes"))    label = _("Yes");
+	    else if (button_equal(label, "No"))     label = _("No");
+	    else if (button_equal(label, "Cancel")) label = _("Canccl");
+# else
 	    if	    (button_equal(label, ok[0]))    label = GTK_STOCK_OK;
 	    else if (button_equal(label, ync[0]))   label = GTK_STOCK_YES;
 	    else if (button_equal(label, ync[1]))   label = GTK_STOCK_NO;
@@ -1316,6 +1671,7 @@ dialog_add_buttons(GtkDialog *dialog, ch
 	    else if (button_equal(label, "Yes"))    label = GTK_STOCK_YES;
 	    else if (button_equal(label, "No"))     label = GTK_STOCK_NO;
 	    else if (button_equal(label, "Cancel")) label = GTK_STOCK_CANCEL;
+# endif
 	}
 	label8 = CONVERT_TO_UTF8((char_u *)label);
 	gtk_dialog_add_button(dialog, (const gchar *)label8, idx);
@@ -1408,14 +1764,32 @@ gui_mch_dialog(int	type,	    /* type of 
 	gtk_entry_set_text(GTK_ENTRY(entry), (const char *)text);
 	CONVERT_TO_UTF8_FREE(text);
 
+# if GTK_CHECK_VERSION(3,14,0)
+	gtk_widget_set_halign(GTK_WIDGET(entry), GTK_ALIGN_CENTER);
+	gtk_widget_set_valign(GTK_WIDGET(entry), GTK_ALIGN_CENTER);
+	gtk_widget_set_hexpand(GTK_WIDGET(entry), TRUE);
+	gtk_widget_set_vexpand(GTK_WIDGET(entry), TRUE);
+
+	alignment = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+# else
 	alignment = gtk_alignment_new((float)0.5, (float)0.5,
 						      (float)1.0, (float)1.0);
+# endif
 	gtk_container_add(GTK_CONTAINER(alignment), entry);
 	gtk_container_set_border_width(GTK_CONTAINER(alignment), 5);
 	gtk_widget_show(alignment);
 
+# if GTK_CHECK_VERSION(3,0,0)
+	{
+	    GtkWidget * const vbox
+		= gtk_dialog_get_content_area(GTK_DIALOG(dialog));
+	    gtk_box_pack_start(GTK_BOX(vbox),
+		    alignment, TRUE, FALSE, 0);
+	}
+# else
 	gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox),
 			   alignment, TRUE, FALSE, 0);
+# endif
 	dialoginfo.noalt = FALSE;
     }
     else
@@ -1473,6 +1847,7 @@ gui_mch_show_popupmenu(vimmenu_T *menu)
      * Append a submenu for selecting an input method.	This is
      * currently the only way to switch input methods at runtime.
      */
+#  if !GTK_CHECK_VERSION(3,10,0)
     if (xic != NULL && g_object_get_data(G_OBJECT(menu->submenu_id),
 					 "vim-has-im-menu") == NULL)
     {
@@ -1499,6 +1874,7 @@ gui_mch_show_popupmenu(vimmenu_T *menu)
 	g_object_set_data(G_OBJECT(menu->submenu_id),
 			  "vim-has-im-menu", GINT_TO_POINTER(TRUE));
     }
+#  endif
 # endif /* FEAT_XIM */
 
     gtk_menu_popup(GTK_MENU(menu->submenu_id),
@@ -1524,7 +1900,11 @@ popup_menu_position_func(GtkMenu *menu U
 			 gboolean *push_in UNUSED,
 			 gpointer user_data UNUSED)
 {
+# if GTK_CHECK_VERSION(3,0,0)
+    gdk_window_get_origin(gtk_widget_get_window(gui.drawarea), x, y);
+# else
     gdk_window_get_origin(gui.drawarea->window, x, y);
+# endif
 
     if (popup_mouse_pos)
     {
@@ -1534,7 +1914,12 @@ popup_menu_position_func(GtkMenu *menu U
 	*x += mx;
 	*y += my;
     }
+# if GTK_CHECK_VERSION(3,0,0)
+    else if (curwin != NULL && gui.drawarea != NULL &&
+	     gtk_widget_get_window(gui.drawarea) != NULL)
+# else
     else if (curwin != NULL && gui.drawarea != NULL && gui.drawarea->window != NULL)
+# endif
     {
 	/* Find the cursor position in the current window */
 	*x += FILL_X(W_WINCOL(curwin) + curwin->w_wcol + 1) + 1;
@@ -1612,7 +1997,13 @@ find_key_press_event(
 }
 
     static GtkWidget *
-create_image_button(const char *stock_id, const char *label)
+#if GTK_CHECK_VERSION(3,10,0)
+create_image_button(const char *stock_id UNUSED,
+		    const char *label)
+#else
+create_image_button(const char *stock_id,
+		    const char *label)
+#endif
 {
     char_u	*text;
     GtkWidget	*box;
@@ -1621,18 +2012,35 @@ create_image_button(const char *stock_id
 
     text = CONVERT_TO_UTF8((char_u *)label);
 
+#if GTK_CHECK_VERSION(3,2,0)
+    box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 3);
+    gtk_box_set_homogeneous(GTK_BOX(box), FALSE);
+#else
     box = gtk_hbox_new(FALSE, 3);
-    gtk_box_pack_start(GTK_BOX(box),
-		       gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_BUTTON),
-		       FALSE, FALSE, 0);
+#endif
+#if !GTK_CHECK_VERSION(3,10,0)
+    if (stock_id != NULL)
+	gtk_box_pack_start(GTK_BOX(box),
+			   gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_BUTTON),
+			   FALSE, FALSE, 0);
+#endif
     gtk_box_pack_start(GTK_BOX(box),
 		       gtk_label_new((const char *)text),
 		       FALSE, FALSE, 0);
 
     CONVERT_TO_UTF8_FREE(text);
 
+#if GTK_CHECK_VERSION(3,14,0)
+    gtk_widget_set_halign(GTK_WIDGET(box), GTK_ALIGN_CENTER);
+    gtk_widget_set_valign(GTK_WIDGET(box), GTK_ALIGN_CENTER);
+    gtk_widget_set_hexpand(GTK_WIDGET(box), TRUE);
+    gtk_widget_set_vexpand(GTK_WIDGET(box), TRUE);
+
+    alignment = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+#else
     alignment = gtk_alignment_new((float)0.5, (float)0.5,
 						      (float)0.0, (float)0.0);
+#endif
     gtk_container_add(GTK_CONTAINER(alignment), box);
     gtk_widget_show_all(alignment);
 
@@ -1695,10 +2103,17 @@ find_replace_dialog_create(char_u *arg, 
 	if (entry_text != NULL)
 	{
 	    gtk_entry_set_text(GTK_ENTRY(frdp->what), (char *)entry_text);
+#if GTK_CHECK_VERSION(3,0,0)
+	    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->wword),
+							     (gboolean)wword);
+	    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->mcase),
+							     (gboolean)mcase);
+#else
 	    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(frdp->wword),
 							     (gboolean)wword);
 	    gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(frdp->mcase),
 							     (gboolean)mcase);
+#endif
 	}
 	gtk_window_present(GTK_WINDOW(frdp->dialog));
 	vim_free(entry_text);
@@ -1706,7 +2121,11 @@ find_replace_dialog_create(char_u *arg, 
     }
 
     frdp->dialog = gtk_dialog_new();
+#if GTK_CHECK_VERSION(3,0,0)
+    /* Nothing equivalent to gtk_dialog_set_has_separator() in GTK+ 3. */
+#else
     gtk_dialog_set_has_separator(GTK_DIALOG(frdp->dialog), FALSE);
+#endif
     gtk_window_set_transient_for(GTK_WINDOW(frdp->dialog), GTK_WINDOW(gui.mainwin));
     gtk_window_set_destroy_with_parent(GTK_WINDOW(frdp->dialog), TRUE);
 
@@ -1721,164 +2140,402 @@ find_replace_dialog_create(char_u *arg, 
 			     CONV(_("VIM - Search...")));
     }
 
+#if GTK_CHECK_VERSION(3,2,0)
+    hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0);
+    gtk_box_set_homogeneous(GTK_BOX(hbox), FALSE);
+#else
     hbox = gtk_hbox_new(FALSE, 0);
+#endif
     gtk_container_set_border_width(GTK_CONTAINER(hbox), 10);
+#if GTK_CHECK_VERSION(3,0,0)
+    {
+	GtkWidget * const dialog_vbox
+	    = gtk_dialog_get_content_area(GTK_DIALOG(frdp->dialog));
+	gtk_container_add(GTK_CONTAINER(dialog_vbox), hbox);
+    }
+#else
     gtk_container_add(GTK_CONTAINER(GTK_DIALOG(frdp->dialog)->vbox), hbox);
+#endif
 
     if (do_replace)
+#if GTK_CHECK_VERSION(3,4,0)
+	table = gtk_grid_new();
+#else
 	table = gtk_table_new(1024, 4, FALSE);
+#endif
     else
+#if GTK_CHECK_VERSION(3,4,0)
+	table = gtk_grid_new();
+#else
 	table = gtk_table_new(1024, 3, FALSE);
+#endif
     gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, TRUE, 0);
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_container_set_border_width(GTK_CONTAINER(table), 4);
+#else
     gtk_container_border_width(GTK_CONTAINER(table), 4);
+#endif
 
     tmp = gtk_label_new(CONV(_("Find what:")));
+#if GTK_CHECK_VERSION(3,16,0)
+    gtk_label_set_xalign(GTK_LABEL(tmp), 0.0);
+    gtk_label_set_yalign(GTK_LABEL(tmp), 0.5);
+#elif GTK_CHECK_VERSION(3,14,0)
+    {
+	GValue align_val = G_VALUE_INIT;
+
+	g_value_init(&align_val, G_TYPE_FLOAT);
+
+	g_value_set_float(&align_val, 0.0);
+	g_object_set_property(G_OBJECT(tmp), "xalign", &align_val);
+
+	g_value_set_float(&align_val, 0.5);
+	g_object_set_property(G_OBJECT(tmp), "yalign", &align_val);
+
+	g_value_unset(&align_val);
+    }
+#else
     gtk_misc_set_alignment(GTK_MISC(tmp), (gfloat)0.0, (gfloat)0.5);
+#endif
+#if GTK_CHECK_VERSION(3,4,0)
+    gtk_grid_attach(GTK_GRID(table), tmp, 0, 0, 2, 1);
+#else
     gtk_table_attach(GTK_TABLE(table), tmp, 0, 1, 0, 1,
 		     GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
     frdp->what = gtk_entry_new();
     sensitive = (entry_text != NULL && entry_text[0] != NUL);
     if (entry_text != NULL)
 	gtk_entry_set_text(GTK_ENTRY(frdp->what), (char *)entry_text);
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(frdp->what), "changed",
+		     G_CALLBACK(entry_changed_cb), frdp->dialog);
+    g_signal_connect_after(G_OBJECT(frdp->what), "key-press-event",
+			   G_CALLBACK(find_key_press_event),
+			   (gpointer) frdp);
+#else
     gtk_signal_connect(GTK_OBJECT(frdp->what), "changed",
 		       GTK_SIGNAL_FUNC(entry_changed_cb), frdp->dialog);
     gtk_signal_connect_after(GTK_OBJECT(frdp->what), "key_press_event",
 				 GTK_SIGNAL_FUNC(find_key_press_event),
 				 (gpointer) frdp);
+#endif
+#if GTK_CHECK_VERSION(3,4,0)
+    gtk_grid_attach(GTK_GRID(table), frdp->what, 2, 0, 5, 1);
+#else
     gtk_table_attach(GTK_TABLE(table), frdp->what, 1, 1024, 0, 1,
 		     GTK_EXPAND | GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
 
     if (do_replace)
     {
 	tmp = gtk_label_new(CONV(_("Replace with:")));
+#if GTK_CHECK_VERSION(3,16,0)
+	gtk_label_set_xalign(GTK_LABEL(tmp), 0.0);
+	gtk_label_set_yalign(GTK_LABEL(tmp), 0.5);
+#elif GTK_CHECK_VERSION(3,14,0)
+	{
+	    GValue align_val = G_VALUE_INIT;
+
+	    g_value_init(&align_val, G_TYPE_FLOAT);
+
+	    g_value_set_float(&align_val, 0.0);
+	    g_object_set_property(G_OBJECT(tmp), "xalign", &align_val);
+
+	    g_value_set_float(&align_val, 0.5);
+	    g_object_set_property(G_OBJECT(tmp), "yalign", &align_val);
+
+	    g_value_unset(&align_val);
+	}
+#else
 	gtk_misc_set_alignment(GTK_MISC(tmp), (gfloat)0.0, (gfloat)0.5);
+#endif
+#if GTK_CHECK_VERSION(3,4,0)
+	gtk_grid_attach(GTK_GRID(table), tmp, 0, 1, 2, 1);
+#else
 	gtk_table_attach(GTK_TABLE(table), tmp, 0, 1, 1, 2,
 			 GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
 	frdp->with = gtk_entry_new();
+#if GTK_CHECK_VERSION(3,0,0)
+	g_signal_connect(G_OBJECT(frdp->with), "activate",
+			 G_CALLBACK(find_replace_cb),
+			 GINT_TO_POINTER(FRD_R_FINDNEXT));
+	g_signal_connect_after(G_OBJECT(frdp->with), "key-press-event",
+			       G_CALLBACK(find_key_press_event),
+			       (gpointer) frdp);
+#else
 	gtk_signal_connect(GTK_OBJECT(frdp->with), "activate",
 			   GTK_SIGNAL_FUNC(find_replace_cb),
 			   GINT_TO_POINTER(FRD_R_FINDNEXT));
 	gtk_signal_connect_after(GTK_OBJECT(frdp->with), "key_press_event",
 				 GTK_SIGNAL_FUNC(find_key_press_event),
 				 (gpointer) frdp);
+#endif
+#if GTK_CHECK_VERSION(3,4,0)
+	gtk_grid_attach(GTK_GRID(table), frdp->with, 2, 1, 5, 1);
+#else
 	gtk_table_attach(GTK_TABLE(table), frdp->with, 1, 1024, 1, 2,
 			 GTK_EXPAND | GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
 
 	/*
 	 * Make the entry activation only change the input focus onto the
 	 * with item.
 	 */
+#if GTK_CHECK_VERSION(3,0,0)
+	g_signal_connect(G_OBJECT(frdp->what), "activate",
+			 G_CALLBACK(entry_activate_cb), frdp->with);
+#else
 	gtk_signal_connect(GTK_OBJECT(frdp->what), "activate",
 			   GTK_SIGNAL_FUNC(entry_activate_cb), frdp->with);
+#endif
     }
     else
     {
 	/*
 	 * Make the entry activation do the search.
 	 */
+#if GTK_CHECK_VERSION(3,0,0)
+	g_signal_connect(G_OBJECT(frdp->what), "activate",
+			 G_CALLBACK(find_replace_cb),
+			 GINT_TO_POINTER(FRD_FINDNEXT));
+#else
 	gtk_signal_connect(GTK_OBJECT(frdp->what), "activate",
 			   GTK_SIGNAL_FUNC(find_replace_cb),
 			   GINT_TO_POINTER(FRD_FINDNEXT));
+#endif
     }
 
     /* whole word only button */
     frdp->wword = gtk_check_button_new_with_label(CONV(_("Match whole word only")));
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->wword),
+							(gboolean)wword);
+#else
     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(frdp->wword),
 							(gboolean)wword);
+#endif
     if (do_replace)
+#if GTK_CHECK_VERSION(3,4,0)
+	gtk_grid_attach(GTK_GRID(table), frdp->wword, 0, 2, 5, 1);
+#else
 	gtk_table_attach(GTK_TABLE(table), frdp->wword, 0, 1023, 2, 3,
 			 GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
     else
+#if GTK_CHECK_VERSION(3,4,0)
+	gtk_grid_attach(GTK_GRID(table), frdp->wword, 0, 3, 5, 1);
+#else
 	gtk_table_attach(GTK_TABLE(table), frdp->wword, 0, 1023, 1, 2,
 			 GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
 
     /* match case button */
     frdp->mcase = gtk_check_button_new_with_label(CONV(_("Match case")));
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->mcase),
+							     (gboolean)mcase);
+#else
     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(frdp->mcase),
 							     (gboolean)mcase);
+#endif
     if (do_replace)
+#if GTK_CHECK_VERSION(3,4,0)
+	gtk_grid_attach(GTK_GRID(table), frdp->mcase, 0, 3, 5, 1);
+#else
 	gtk_table_attach(GTK_TABLE(table), frdp->mcase, 0, 1023, 3, 4,
 			 GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
     else
+#if GTK_CHECK_VERSION(3,4,0)
+	gtk_grid_attach(GTK_GRID(table), frdp->mcase, 0, 4, 5, 1);
+#else
 	gtk_table_attach(GTK_TABLE(table), frdp->mcase, 0, 1023, 2, 3,
 			 GTK_FILL, GTK_EXPAND, 2, 2);
+#endif
 
     tmp = gtk_frame_new(CONV(_("Direction")));
     if (do_replace)
+#if GTK_CHECK_VERSION(3,4,0)
+	gtk_grid_attach(GTK_GRID(table), tmp, 5, 2, 2, 4);
+#else
 	gtk_table_attach(GTK_TABLE(table), tmp, 1023, 1024, 2, 4,
 			 GTK_FILL, GTK_FILL, 2, 2);
+#endif
     else
+#if GTK_CHECK_VERSION(3,4,0)
+	gtk_grid_attach(GTK_GRID(table), tmp, 5, 2, 1, 3);
+#else
 	gtk_table_attach(GTK_TABLE(table), tmp, 1023, 1024, 1, 3,
 			 GTK_FILL, GTK_FILL, 2, 2);
+#endif
+#if GTK_CHECK_VERSION(3,2,0)
+    vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+    gtk_box_set_homogeneous(GTK_BOX(vbox), FALSE);
+#else
     vbox = gtk_vbox_new(FALSE, 0);
+#endif
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_container_set_border_width(GTK_CONTAINER(vbox), 0);
+#else
     gtk_container_border_width(GTK_CONTAINER(vbox), 0);
+#endif
     gtk_container_add(GTK_CONTAINER(tmp), vbox);
 
     /* 'Up' and 'Down' buttons */
     frdp->up = gtk_radio_button_new_with_label(NULL, CONV(_("Up")));
     gtk_box_pack_start(GTK_BOX(vbox), frdp->up, TRUE, TRUE, 0);
+#if GTK_CHECK_VERSION(3,0,0)
+    frdp->down = gtk_radio_button_new_with_label(
+			gtk_radio_button_get_group(GTK_RADIO_BUTTON(frdp->up)),
+			CONV(_("Down")));
+#else
     frdp->down = gtk_radio_button_new_with_label(
 			gtk_radio_button_group(GTK_RADIO_BUTTON(frdp->up)),
 			CONV(_("Down")));
+#endif
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->down), TRUE);
+#else
     gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(frdp->down), TRUE);
+#endif
     gtk_container_set_border_width(GTK_CONTAINER(vbox), 2);
     gtk_box_pack_start(GTK_BOX(vbox), frdp->down, TRUE, TRUE, 0);
 
     /* vbox to hold the action buttons */
+#if GTK_CHECK_VERSION(3,2,0)
+    actionarea = gtk_button_box_new(GTK_ORIENTATION_VERTICAL);
+#else
     actionarea = gtk_vbutton_box_new();
+#endif
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_container_set_border_width(GTK_CONTAINER(actionarea), 2);
+#else
     gtk_container_border_width(GTK_CONTAINER(actionarea), 2);
+#endif
     gtk_box_pack_end(GTK_BOX(hbox), actionarea, FALSE, FALSE, 0);
 
     /* 'Find Next' button */
+#if GTK_CHECK_VERSION(3,10,0)
+    frdp->find = create_image_button(NULL, _("Find Next"));
+#else
     frdp->find = create_image_button(GTK_STOCK_FIND, _("Find Next"));
+#endif
     gtk_widget_set_sensitive(frdp->find, sensitive);
 
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(frdp->find), "clicked",
+		     G_CALLBACK(find_replace_cb),
+		     (do_replace) ? GINT_TO_POINTER(FRD_R_FINDNEXT)
+				  : GINT_TO_POINTER(FRD_FINDNEXT));
+#else
     gtk_signal_connect(GTK_OBJECT(frdp->find), "clicked",
 		       GTK_SIGNAL_FUNC(find_replace_cb),
 		       (do_replace) ? GINT_TO_POINTER(FRD_R_FINDNEXT)
 				    : GINT_TO_POINTER(FRD_FINDNEXT));
+#endif
 
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_widget_set_can_default(frdp->find, TRUE);
+#else
     GTK_WIDGET_SET_FLAGS(frdp->find, GTK_CAN_DEFAULT);
+#endif
     gtk_box_pack_start(GTK_BOX(actionarea), frdp->find, FALSE, FALSE, 0);
     gtk_widget_grab_default(frdp->find);
 
     if (do_replace)
     {
 	/* 'Replace' button */
+#if GTK_CHECK_VERSION(3,10,0)
+	frdp->replace = create_image_button(NULL, _("Replace"));
+#else
 	frdp->replace = create_image_button(GTK_STOCK_CONVERT, _("Replace"));
+#endif
 	gtk_widget_set_sensitive(frdp->replace, sensitive);
+#if GTK_CHECK_VERSION(3,0,0)
+	gtk_widget_set_can_default(frdp->find, TRUE);
+#else
 	GTK_WIDGET_SET_FLAGS(frdp->replace, GTK_CAN_DEFAULT);
+#endif
 	gtk_box_pack_start(GTK_BOX(actionarea), frdp->replace, FALSE, FALSE, 0);
+#if GTK_CHECK_VERSION(3,0,0)
+	g_signal_connect(G_OBJECT(frdp->replace), "clicked",
+			 G_CALLBACK(find_replace_cb),
+			 GINT_TO_POINTER(FRD_REPLACE));
+#else
 	gtk_signal_connect(GTK_OBJECT(frdp->replace), "clicked",
 			   GTK_SIGNAL_FUNC(find_replace_cb),
 			   GINT_TO_POINTER(FRD_REPLACE));
+#endif
 
 	/* 'Replace All' button */
+#if GTK_CHECK_VERSION(3,10,0)
+	frdp->all = create_image_button(NULL, _("Replace All"));
+#else
 	frdp->all = create_image_button(GTK_STOCK_CONVERT, _("Replace All"));
+#endif
 	gtk_widget_set_sensitive(frdp->all, sensitive);
+#if GTK_CHECK_VERSION(3,0,0)
+	gtk_widget_set_can_default(frdp->all, TRUE);
+#else
 	GTK_WIDGET_SET_FLAGS(frdp->all, GTK_CAN_DEFAULT);
+#endif
 	gtk_box_pack_start(GTK_BOX(actionarea), frdp->all, FALSE, FALSE, 0);
+#if GTK_CHECK_VERSION(3,0,0)
+	g_signal_connect(G_OBJECT(frdp->all), "clicked",
+			 G_CALLBACK(find_replace_cb),
+			 GINT_TO_POINTER(FRD_REPLACEALL));
+#else
 	gtk_signal_connect(GTK_OBJECT(frdp->all), "clicked",
 			   GTK_SIGNAL_FUNC(find_replace_cb),
 			   GINT_TO_POINTER(FRD_REPLACEALL));
+#endif
     }
 
     /* 'Cancel' button */
+#if GTK_CHECK_VERSION(3,10,0)
+    tmp = gtk_button_new_with_mnemonic(_("_Close"));
+#else
     tmp = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+#endif
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_widget_set_can_default(tmp, TRUE);
+#else
     GTK_WIDGET_SET_FLAGS(tmp, GTK_CAN_DEFAULT);
+#endif
     gtk_box_pack_end(GTK_BOX(actionarea), tmp, FALSE, FALSE, 0);
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect_swapped(G_OBJECT(tmp),
+			     "clicked", G_CALLBACK(gtk_widget_hide),
+			     G_OBJECT(frdp->dialog));
+    g_signal_connect_swapped(G_OBJECT(frdp->dialog),
+			     "delete-event", G_CALLBACK(gtk_widget_hide_on_delete),
+			     G_OBJECT(frdp->dialog));
+#else
     gtk_signal_connect_object(GTK_OBJECT(tmp),
 			      "clicked", GTK_SIGNAL_FUNC(gtk_widget_hide),
 			      GTK_OBJECT(frdp->dialog));
     gtk_signal_connect_object(GTK_OBJECT(frdp->dialog),
 			      "delete_event", GTK_SIGNAL_FUNC(gtk_widget_hide_on_delete),
 			      GTK_OBJECT(frdp->dialog));
+#endif
 
+#if GTK_CHECK_VERSION(3,2,0)
+    tmp = gtk_separator_new(GTK_ORIENTATION_VERTICAL);
+#else
     tmp = gtk_vseparator_new();
+#endif
     gtk_box_pack_end(GTK_BOX(hbox), tmp, FALSE, FALSE, 10);
 
     /* Suppress automatic show of the unused action area */
+#if GTK_CHECK_VERSION(3,0,0)
+# if !GTK_CHECK_VERSION(3,12,0)
+    gtk_widget_hide(gtk_dialog_get_action_area(GTK_DIALOG(frdp->dialog)));
+# endif
+#else
     gtk_widget_hide(GTK_DIALOG(frdp->dialog)->action_area);
+#endif
     gtk_widget_show_all(hbox);
     gtk_widget_show(frdp->dialog);
 
@@ -1928,11 +2585,23 @@ find_replace_cb(GtkWidget *widget UNUSED
     }
 
     find_text = (char_u *)gtk_entry_get_text(GTK_ENTRY(sfr->what));
+#if GTK_CHECK_VERSION(3,0,0)
+    direction_down = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sfr->down));
+#else
     direction_down = GTK_TOGGLE_BUTTON(sfr->down)->active;
+#endif
 
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sfr->wword)))
+#else
     if (GTK_TOGGLE_BUTTON(sfr->wword)->active)
+#endif
 	flags |= FRD_WHOLE_WORD;
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sfr->mcase)))
+#else
     if (GTK_TOGGLE_BUTTON(sfr->mcase)->active)
+#endif
 	flags |= FRD_MATCH_CASE;
 
     repl_text = CONVERT_FROM_UTF8(repl_text);