patch 7.4.1402
Problem:    GTK 3 is not supported.
Solution:   Add GTK 3 support. (Kazunobu Kuriyama)
diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c
index 9f6775f..440b401 100644
--- a/src/gui_gtk_x11.c
+++ b/src/gui_gtk_x11.c
@@ -19,6 +19,10 @@
  *
  * (C) 2002,2003  Jason Hildebrand  <jason@peaceworks.ca>
  *		  Daniel Elstner  <daniel.elstner@gmx.net>
+ *
+ * Support for GTK+ 3 was added by:
+ *
+ * 2016  Kazunobu Kuriyama  <kazunobu.kuriyama@gmail.com>
  */
 
 #include "vim.h"
@@ -75,14 +79,18 @@
 # define GdkEventConfigure int
 # define GdkEventClient int
 #else
-# include <gdk/gdkkeysyms.h>
+# if GTK_CHECK_VERSION(3,0,0)
+#  include <gdk/gdkkeysyms-compat.h>
+#  include <gtk/gtkx.h>
+# else
+#  include <gdk/gdkkeysyms.h>
+# endif
 # include <gdk/gdk.h>
 # ifdef WIN3264
 #  include <gdk/gdkwin32.h>
 # else
 #  include <gdk/gdkx.h>
 # endif
-
 # include <gtk/gtk.h>
 # include "gui_gtk_f.h"
 #endif
@@ -580,6 +588,7 @@
 }
 #endif
 
+#if !GTK_CHECK_VERSION(3,0,0)
 /*
  * This should be maybe completely removed.
  * Doesn't seem possible, since check_copy_area() relies on
@@ -601,10 +610,93 @@
 			     gui.visibility != GDK_VISIBILITY_UNOBSCURED);
     return FALSE;
 }
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
 
 /*
  * Redraw the corresponding portions of the screen.
  */
+#if GTK_CHECK_VERSION(3,0,0)
+static gboolean is_key_pressed = FALSE;
+
+static gboolean gui_gtk_is_blink_on(void);
+static gboolean gui_gtk_is_no_blink(void);
+static void gui_gtk_window_clear(GdkWindow *win);
+
+    static void
+gui_gtk3_redraw(int x, int y, int width, int height)
+{
+    gui_redraw_block(Y_2_ROW(y), X_2_COL(x),
+	    Y_2_ROW(y + height - 1), X_2_COL(x + width - 1),
+	    GUI_MON_NOCLEAR);
+}
+
+    static void
+gui_gtk3_update_cursor(cairo_t *cr)
+{
+    if (gui.row == gui.cursor_row)
+    {
+	gui.by_signal = TRUE;
+	gui_update_cursor(TRUE, TRUE);
+	gui.by_signal = FALSE;
+	cairo_paint(cr);
+    }
+}
+
+    static gboolean
+gui_gtk3_should_draw_cursor(void)
+{
+    unsigned int cond = 0;
+    cond |= gui_gtk_is_blink_on();
+    cond |= is_key_pressed;
+    cond |= gui.in_focus == FALSE;
+    cond |= gui_gtk_is_no_blink();
+    return  cond;
+}
+
+    static gboolean
+draw_event(GtkWidget *widget,
+	   cairo_t   *cr,
+	   gpointer   user_data UNUSED)
+{
+    /* Skip this when the GUI isn't set up yet, will redraw later. */
+    if (gui.starting)
+	return FALSE;
+
+    out_flush();		/* make sure all output has been processed */
+				/* for GTK+ 3, may induce other draw events. */
+
+    cairo_set_source_surface(cr, gui.surface, 0, 0);
+
+    /* Draw the window without the cursor. */
+    gui.by_signal = TRUE;
+    {
+	cairo_rectangle_list_t *list = NULL;
+
+	gui_gtk_window_clear(gtk_widget_get_window(widget));
+
+	list = cairo_copy_clip_rectangle_list(cr);
+	if (list->status != CAIRO_STATUS_CLIP_NOT_REPRESENTABLE)
+	{
+	    int i;
+	    for (i = 0; i < list->num_rectangles; i++)
+	    {
+		const cairo_rectangle_t rect = list->rectangles[i];
+		gui_gtk3_redraw(rect.x, rect.y, rect.width, rect.height);
+	    }
+	}
+	cairo_rectangle_list_destroy(list);
+
+	cairo_paint(cr);
+    }
+    gui.by_signal = FALSE;
+
+    /* Add the cursor to the window if necessary.*/
+    if (gui_gtk3_should_draw_cursor())
+	gui_gtk3_update_cursor(cr);
+
+    return FALSE;
+}
+#else /* !GTK_CHECK_VERSION(3,0,0) */
     static gint
 expose_event(GtkWidget *widget UNUSED,
 	     GdkEventExpose *event,
@@ -631,6 +723,7 @@
 
     return FALSE;
 }
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
 
 #ifdef FEAT_CLIENTSERVER
 /*
@@ -643,7 +736,11 @@
 {
     if (event->type == GDK_PROPERTY_NOTIFY
 	    && event->state == (int)GDK_PROPERTY_NEW_VALUE
+# if GTK_CHECK_VERSION(3,0,0)
+	    && GDK_WINDOW_XID(event->window) == commWindow
+# else
 	    && GDK_WINDOW_XWINDOW(event->window) == commWindow
+# endif
 	    && GET_X_ATOM(event->atom) == commProperty)
     {
 	XEvent xev;
@@ -653,11 +750,16 @@
 	xev.xproperty.atom = commProperty;
 	xev.xproperty.window = commWindow;
 	xev.xproperty.state = PropertyNewValue;
+# if GTK_CHECK_VERSION(3,0,0)
+	serverEventProc(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(widget)),
+		&xev, 0);
+# else
 	serverEventProc(GDK_WINDOW_XDISPLAY(widget->window), &xev, 0);
+# endif
     }
     return FALSE;
 }
-#endif
+#endif /* defined(FEAT_CLIENTSERVER) */
 
 
 /****************************************************************************
@@ -682,6 +784,20 @@
 static long_u blink_offtime = 250;
 static guint blink_timer = 0;
 
+#if GTK_CHECK_VERSION(3,0,0)
+    static gboolean
+gui_gtk_is_blink_on(void)
+{
+    return blink_state == BLINK_ON;
+}
+
+    static gboolean
+gui_gtk_is_no_blink(void)
+{
+    return blink_waittime == 0 || blink_ontime == 0 || blink_offtime == 0;
+}
+#endif
+
     void
 gui_mch_set_blinking(long waittime, long on, long off)
 {
@@ -698,7 +814,11 @@
 {
     if (blink_timer)
     {
+#if GTK_CHECK_VERSION(3,0,0)
+	g_source_remove(blink_timer);
+#else
 	gtk_timeout_remove(blink_timer);
+#endif
 	blink_timer = 0;
     }
     if (blink_state == BLINK_OFF)
@@ -706,22 +826,36 @@
     blink_state = BLINK_NONE;
 }
 
+#if GTK_CHECK_VERSION(3,0,0)
+    static gboolean
+#else
     static gint
+#endif
 blink_cb(gpointer data UNUSED)
 {
     if (blink_state == BLINK_ON)
     {
 	gui_undraw_cursor();
 	blink_state = BLINK_OFF;
+#if GTK_CHECK_VERSION(3,0,0)
+	blink_timer = g_timeout_add((guint)blink_offtime,
+				   (GSourceFunc) blink_cb, NULL);
+#else
 	blink_timer = gtk_timeout_add((guint32)blink_offtime,
 				   (GtkFunction) blink_cb, NULL);
+#endif
     }
     else
     {
 	gui_update_cursor(TRUE, FALSE);
 	blink_state = BLINK_ON;
+#if GTK_CHECK_VERSION(3,0,0)
+	blink_timer = g_timeout_add((guint)blink_ontime,
+				   (GSourceFunc) blink_cb, NULL);
+#else
 	blink_timer = gtk_timeout_add((guint32)blink_ontime,
 				   (GtkFunction) blink_cb, NULL);
+#endif
     }
 
     return FALSE;		/* don't happen again */
@@ -736,14 +870,23 @@
 {
     if (blink_timer)
     {
+#if GTK_CHECK_VERSION(3,0,0)
+	g_source_remove(blink_timer);
+#else
 	gtk_timeout_remove(blink_timer);
+#endif
 	blink_timer = 0;
     }
     /* Only switch blinking on if none of the times is zero */
     if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
     {
+#if GTK_CHECK_VERSION(3,0,0)
+	blink_timer = g_timeout_add((guint)blink_waittime,
+				   (GSourceFunc) blink_cb, NULL);
+#else
 	blink_timer = gtk_timeout_add((guint32)blink_waittime,
 				   (GtkFunction) blink_cb, NULL);
+#endif
 	blink_state = BLINK_ON;
 	gui_update_cursor(TRUE, FALSE);
     }
@@ -758,7 +901,11 @@
 	gui_mch_start_blink();
 
     /* make sure keyboard input goes there */
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_socket_id == 0 || !gtk_widget_has_focus(gui.drawarea))
+#else
     if (gtk_socket_id == 0 || !GTK_WIDGET_HAS_FOCUS(gui.drawarea))
+#endif
 	gtk_widget_grab_focus(gui.drawarea);
 
     return FALSE;
@@ -938,6 +1085,11 @@
     guint	state;
     char_u	*s, *d;
 
+#if GTK_CHECK_VERSION(3,0,0)
+    is_key_pressed = TRUE;
+    gui_mch_stop_blink();
+#endif
+
     gui.event_time = event->time;
     key_sym = event->keyval;
     state = event->state;
@@ -1127,12 +1279,17 @@
     return TRUE;
 }
 
-#if defined(FEAT_XIM)
+#if defined(FEAT_XIM) || GTK_CHECK_VERSION(3,0,0)
     static gboolean
 key_release_event(GtkWidget *widget UNUSED,
 		  GdkEventKey *event,
 		  gpointer data UNUSED)
 {
+# if GTK_CHECK_VERSION(3,0,0)
+    is_key_pressed = FALSE;
+    gui_mch_start_blink();
+# endif
+# if defined(FEAT_XIM)
     gui.event_time = event->time;
     /*
      * GTK+ 2 input methods may do fancy stuff on key release events too.
@@ -1140,6 +1297,9 @@
      * by holding down CTRL-SHIFT and typing hexadecimal digits.
      */
     return xim_queue_key_press_event(event, FALSE);
+# else
+    return TRUE;
+# endif
 }
 #endif
 
@@ -1179,13 +1339,22 @@
     int		    len;
     int		    motion_type = MAUTO;
 
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_selection_data_get_selection(data) == clip_plus.gtk_sel_atom)
+#else
     if (data->selection == clip_plus.gtk_sel_atom)
+#endif
 	cbd = &clip_plus;
     else
 	cbd = &clip_star;
 
+#if GTK_CHECK_VERSION(3,0,0)
+    text = (char_u *)gtk_selection_data_get_data(data);
+    len = gtk_selection_data_get_length(data);
+#else
     text = (char_u *)data->data;
     len  = data->length;
+#endif
 
     if (text == NULL || len <= 0)
     {
@@ -1195,13 +1364,20 @@
 	return;
     }
 
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_selection_data_get_data_type(data) == vim_atom)
+#else
     if (data->type == vim_atom)
+#endif
     {
 	motion_type = *text++;
 	--len;
     }
-
+#if GTK_CHECK_VERSION(3,0,0)
+    else if (gtk_selection_data_get_data_type(data) == vimenc_atom)
+#else
     else if (data->type == vimenc_atom)
+#endif
     {
 	char_u		*enc;
 	vimconv_T	conv;
@@ -1292,7 +1468,12 @@
     GdkAtom	    type;
     VimClipboard    *cbd;
 
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_selection_data_get_selection(selection_data)
+	    == clip_plus.gtk_sel_atom)
+#else
     if (selection_data->selection == clip_plus.gtk_sel_atom)
+#endif
 	cbd = &clip_plus;
     else
 	cbd = &clip_star;
@@ -1361,8 +1542,12 @@
 	    string = tmpbuf;
 	    length += 2;
 
+#if !GTK_CHECK_VERSION(3,0,0)
+	    /* Looks redandunt even for GTK2 because these values are
+	     * overwritten by gtk_selection_data_set() that follows. */
 	    selection_data->type = selection_data->target;
 	    selection_data->format = 16;	/* 16 bits per char */
+#endif
 	    gtk_selection_data_set(selection_data, html_atom, 16,
 							      string, length);
 	    vim_free(string);
@@ -1411,9 +1596,12 @@
 
     if (string != NULL)
     {
+#if !GTK_CHECK_VERSION(3,0,0)
+	/* Looks redandunt even for GTK2 because these values are
+	 * overwritten by gtk_selection_data_set() that follows. */
 	selection_data->type = selection_data->target;
 	selection_data->format = 8;	/* 8 bits per char */
-
+#endif
 	gtk_selection_data_set(selection_data, type, 8, string, length);
 	vim_free(string);
     }
@@ -1493,7 +1681,11 @@
 /*
  * Timer used to recognize multiple clicks of the mouse button
  */
+#if GTK_CHECK_VERSION(3,0,0)
+    static gboolean
+#else
     static gint
+#endif
 mouse_click_timer_cb(gpointer data)
 {
     /* we don't use this information currently */
@@ -1505,13 +1697,20 @@
 
 static guint motion_repeat_timer  = 0;
 static int   motion_repeat_offset = FALSE;
+#ifdef GTK_DEST_DEFAULT_ALL
+static gboolean  motion_repeat_timer_cb(gpointer);
+#else
 static gint  motion_repeat_timer_cb(gpointer);
+#endif
 
     static void
 process_motion_notify(int x, int y, GdkModifierType state)
 {
     int	    button;
     int_u   vim_modifiers;
+#if GTK_CHECK_VERSION(3,0,0)
+    GtkAllocation allocation;
+#endif
 
     button = (state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK |
 		       GDK_BUTTON3_MASK | GDK_BUTTON4_MASK |
@@ -1538,9 +1737,17 @@
     /*
      * Auto repeat timer handling.
      */
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_widget_get_allocation(gui.drawarea, &allocation);
+
+    if (x < 0 || y < 0
+	    || x >= allocation.width
+	    || y >= allocation.height)
+#else
     if (x < 0 || y < 0
 	    || x >= gui.drawarea->allocation.width
 	    || y >= gui.drawarea->allocation.height)
+#endif
     {
 
 	int dx;
@@ -1551,8 +1758,13 @@
 	/* Calculate the maximal distance of the cursor from the drawing area.
 	 * (offshoot can't become negative here!).
 	 */
+#if GTK_CHECK_VERSION(3,0,0)
+	dx = x < 0 ? -x : x - allocation.width;
+	dy = y < 0 ? -y : y - allocation.height;
+#else
 	dx = x < 0 ? -x : x - gui.drawarea->allocation.width;
 	dy = y < 0 ? -y : y - gui.drawarea->allocation.height;
+#endif
 
 	offshoot = dx > dy ? dx : dy;
 
@@ -1577,22 +1789,66 @@
 
 	/* shoot again */
 	if (!motion_repeat_timer)
+#if GTK_CHECK_VERSION(3,0,0)
+	    motion_repeat_timer = g_timeout_add((guint)delay,
+						motion_repeat_timer_cb, NULL);
+#else
 	    motion_repeat_timer = gtk_timeout_add((guint32)delay,
 						motion_repeat_timer_cb, NULL);
+#endif
     }
 }
 
+#if GTK_CHECK_VERSION(3,0,0)
+    static GdkDevice *
+gui_gtk_get_pointer_device(GtkWidget *widget)
+{
+    GdkWindow * const win = gtk_widget_get_window(widget);
+    GdkDisplay * const dpy = gdk_window_get_display(win);
+    GdkDeviceManager * const mngr = gdk_display_get_device_manager(dpy);
+    return gdk_device_manager_get_client_pointer(mngr);
+}
+
+    static GdkWindow *
+gui_gtk_get_pointer(GtkWidget       *widget,
+		    gint	    *x,
+		    gint	    *y,
+		    GdkModifierType *state)
+{
+    GdkWindow * const win = gtk_widget_get_window(widget);
+    GdkDevice * const dev = gui_gtk_get_pointer_device(widget);
+    return gdk_window_get_device_position(win, dev , x, y, state);
+}
+
+    static GdkWindow *
+gui_gtk_window_at_position(GtkWidget *widget,
+			   gint      *x,
+			   gint      *y)
+{
+    GdkDevice * const dev = gui_gtk_get_pointer_device(widget);
+    return gdk_device_get_window_at_position(dev, x, y);
+}
+#endif
+
 /*
  * Timer used to recognize multiple clicks of the mouse button.
  */
+#if GTK_CHECK_VERSION(3,0,0)
+    static gboolean
+#else
     static gint
+#endif
 motion_repeat_timer_cb(gpointer data UNUSED)
 {
     int		    x;
     int		    y;
     GdkModifierType state;
 
+#if GTK_CHECK_VERSION(3,0,0)
+    gui_gtk_get_pointer(gui.drawarea, &x, &y, &state);
+#else
     gdk_window_get_pointer(gui.drawarea->window, &x, &y, &state);
+#endif
 
     if (!(state & (GDK_BUTTON1_MASK | GDK_BUTTON2_MASK |
 		   GDK_BUTTON3_MASK | GDK_BUTTON4_MASK |
@@ -1637,7 +1893,11 @@
 	int		y;
 	GdkModifierType	state;
 
+#if GTK_CHECK_VERSION(3,0,0)
+	gui_gtk_get_pointer(widget, &x, &y, &state);
+#else
 	gdk_window_get_pointer(widget->window, &x, &y, &state);
+#endif
 	process_motion_notify(x, y, state);
     }
     else
@@ -1668,7 +1928,11 @@
     gui.event_time = event->time;
 
     /* Make sure we have focus now we've been selected */
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_socket_id != 0 && !gtk_widget_has_focus(widget))
+#else
     if (gtk_socket_id != 0 && !GTK_WIDGET_HAS_FOCUS(widget))
+#endif
 	gtk_widget_grab_focus(widget);
 
     /*
@@ -1684,14 +1948,23 @@
     /* Handle multiple clicks */
     if (!mouse_timed_out && mouse_click_timer)
     {
+#if GTK_CHECK_VERSION(3,0,0)
+	g_source_remove(mouse_click_timer);
+#else
 	gtk_timeout_remove(mouse_click_timer);
+#endif
 	mouse_click_timer = 0;
 	repeated_click = TRUE;
     }
 
     mouse_timed_out = FALSE;
+#if GTK_CHECK_VERSION(3,0,0)
+    mouse_click_timer = g_timeout_add((guint)p_mouset,
+				  mouse_click_timer_cb, &mouse_timed_out);
+#else
     mouse_click_timer = gtk_timeout_add((guint32)p_mouset,
 				  mouse_click_timer_cb, &mouse_timed_out);
+#endif
 
     switch (event->button)
     {
@@ -1730,7 +2003,11 @@
     int	    button;
     int_u   vim_modifiers;
 
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_socket_id != 0 && !gtk_widget_has_focus(widget))
+#else
     if (gtk_socket_id != 0 && !GTK_WIDGET_HAS_FOCUS(widget))
+#endif
 	gtk_widget_grab_focus(widget);
 
     switch (event->direction)
@@ -1781,7 +2058,11 @@
        area .*/
     if (motion_repeat_timer)
     {
+#if GTK_CHECK_VERSION(3,0,0)
+	g_source_remove(motion_repeat_timer);
+#else
 	gtk_timeout_remove(motion_repeat_timer);
+#endif
 	motion_repeat_timer = 0;
     }
 
@@ -1896,7 +2177,13 @@
     char_u  **fnames;
     int	    nfiles = 0;
 
+# if GTK_CHECK_VERSION(3,0,0)
+    fnames = parse_uri_list(&nfiles,
+	    (char_u *)gtk_selection_data_get_data(data),
+	    gtk_selection_data_get_length(data));
+# else
     fnames = parse_uri_list(&nfiles, data->data, data->length);
+# endif
 
     if (fnames != NULL && nfiles > 0)
     {
@@ -1923,10 +2210,19 @@
     int	    len;
     char_u  *tmpbuf = NULL;
 
+# if GTK_CHECK_VERSION(3,0,0)
+    text = (char_u *)gtk_selection_data_get_data(data);
+    len = gtk_selection_data_get_length(data);
+# else
     text = data->data;
     len  = data->length;
+# endif
 
+# if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_selection_data_get_data_type(data) == utf8_string_atom)
+# else
     if (data->type == utf8_string_atom)
+# endif
     {
 	if (input_conv.vc_type != CONV_NONE)
 	    tmpbuf = string_convert(&input_conv, text, &len);
@@ -1962,10 +2258,21 @@
     GdkModifierType state;
 
     /* Guard against trash */
+# if GTK_CHECK_VERSION(3,0,0)
+    const guchar * const data_data = gtk_selection_data_get_data(data);
+    const gint data_length = gtk_selection_data_get_length(data);
+    const gint data_format = gtk_selection_data_get_format(data);
+
+    if (data_data == NULL
+	    || data_length <= 0
+	    || data_format != 8
+	    || data_data[data_length] != '\0')
+# else
     if (data->data == NULL
 	    || data->length <= 0
 	    || data->format != 8
 	    || data->data[data->length] != '\0')
+# endif
     {
 	gtk_drag_finish(context, FALSE, FALSE, time_);
 	return;
@@ -1973,7 +2280,11 @@
 
     /* Get the current modifier state for proper distinguishment between
      * different operations later. */
+#if GTK_CHECK_VERSION(3,0,0)
+    gui_gtk_get_pointer(widget, NULL, NULL, &state);
+# else
     gdk_window_get_pointer(widget->window, NULL, NULL, &state);
+# endif
 
     /* Not sure about the role of "text/plain" here... */
     if (info == (guint)TARGET_TEXT_URI_LIST)
@@ -2253,7 +2564,7 @@
     Atom    *existing_atoms = NULL;
     int	    count = 0;
 
-#ifdef USE_XSMP
+# ifdef USE_XSMP
     if (xsmp_icefd != -1)
     {
 	/*
@@ -2264,16 +2575,25 @@
 
 	g_io_add_watch(g_io, G_IO_IN | G_IO_ERR | G_IO_HUP,
 				  local_xsmp_handle_requests, (gpointer)g_io);
+	g_io_channel_unref(g_io);
     }
     else
-#endif
+# endif
     {
 	/* Fall back to old method */
 
 	/* first get the existing value */
+# if GTK_CHECK_VERSION(3,0,0)
+	GdkWindow * const mainwin_win = gtk_widget_get_window(gui.mainwin);
+
+	if (XGetWMProtocols(GDK_WINDOW_XDISPLAY(mainwin_win),
+		    GDK_WINDOW_XID(mainwin_win),
+		    &existing_atoms, &count))
+# else
 	if (XGetWMProtocols(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
 		    GDK_WINDOW_XWINDOW(gui.mainwin->window),
 		    &existing_atoms, &count))
+# endif
 	{
 	    Atom	*new_atoms;
 	    Atom	save_yourself_xatom;
@@ -2295,8 +2615,13 @@
 		{
 		    memcpy(new_atoms, existing_atoms, count * sizeof(Atom));
 		    new_atoms[count] = save_yourself_xatom;
+# if GTK_CHECK_VERSION(3,0,0)
+		    XSetWMProtocols(GDK_WINDOW_XDISPLAY(mainwin_win),
+			    GDK_WINDOW_XID(mainwin_win),
+# else
 		    XSetWMProtocols(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
 			    GDK_WINDOW_XWINDOW(gui.mainwin->window),
+# endif
 			    new_atoms, count + 1);
 		    vim_free(new_atoms);
 		}
@@ -2341,8 +2666,13 @@
 	 * know we are done saving ourselves.  We don't want to be
 	 * restarted, thus set argv to NULL.
 	 */
+# if GTK_CHECK_VERSION(3,0,0)
+	XSetCommand(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin)),
+		    GDK_WINDOW_XID(gtk_widget_get_window(gui.mainwin)),
+# else
 	XSetCommand(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
 		    GDK_WINDOW_XWINDOW(gui.mainwin->window),
+# endif
 		    NULL, 0);
 	return GDK_FILTER_REMOVE;
     }
@@ -2376,10 +2706,18 @@
 #undef magick
 # undef static
 
+#if GTK_CHECK_VERSION(3,0,0)
+    GdkWindow * const mainwin_win = gtk_widget_get_window(gui.mainwin);
+#endif
+
     /* When started with "--echo-wid" argument, write window ID on stdout. */
     if (echo_wid_arg)
     {
+#if GTK_CHECK_VERSION(3,0,0)
+	printf("WID: %ld\n", (long)GDK_WINDOW_XID(mainwin_win));
+#else
 	printf("WID: %ld\n", (long)GDK_WINDOW_XWINDOW(gui.mainwin->window));
+#endif
 	fflush(stdout);
     }
 
@@ -2416,10 +2754,17 @@
     if (serverName == NULL && serverDelayedStartName != NULL)
     {
 	/* This is a :gui command in a plain vim with no previous server */
+# if GTK_CHECK_VERSION(3,0,0)
+	commWindow = GDK_WINDOW_XID(mainwin_win);
+
+	(void)serverRegisterName(GDK_WINDOW_XDISPLAY(mainwin_win),
+				 serverDelayedStartName);
+# else
 	commWindow = GDK_WINDOW_XWINDOW(gui.mainwin->window);
 
 	(void)serverRegisterName(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
 				 serverDelayedStartName);
+# endif
     }
     else
     {
@@ -2428,12 +2773,22 @@
 	 * have to change the "server" registration to that of the main window
 	 * If we have not registered a name yet, remember the window
 	 */
+# if GTK_CHECK_VERSION(3,0,0)
+	serverChangeRegisteredWindow(GDK_WINDOW_XDISPLAY(mainwin_win),
+				     GDK_WINDOW_XID(mainwin_win));
+# else
 	serverChangeRegisteredWindow(GDK_WINDOW_XDISPLAY(gui.mainwin->window),
 				     GDK_WINDOW_XWINDOW(gui.mainwin->window));
+# endif
     }
     gtk_widget_add_events(gui.mainwin, GDK_PROPERTY_CHANGE_MASK);
+# if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(gui.mainwin), "property-notify-event",
+		     G_CALLBACK(property_event), NULL);
+# else
     gtk_signal_connect(GTK_OBJECT(gui.mainwin), "property_notify_event",
 		       GTK_SIGNAL_FUNC(property_event), NULL);
+# endif
 #endif
 }
 
@@ -2441,21 +2796,60 @@
 create_blank_pointer(void)
 {
     GdkWindow	*root_window = NULL;
+#if GTK_CHECK_VERSION(3,0,0)
+    GdkPixbuf   *blank_mask;
+#else
     GdkPixmap	*blank_mask;
+#endif
     GdkCursor	*cursor;
     GdkColor	color = { 0, 0, 0, 0 };
+#if !GTK_CHECK_VERSION(3,0,0)
     char	blank_data[] = { 0x0 };
+#endif
 
 #ifdef HAVE_GTK_MULTIHEAD
+# if GTK_CHECK_VERSION(3,12,0)
+    {
+	GdkWindow * const win = gtk_widget_get_window(gui.mainwin);
+	GdkScreen * const scrn = gdk_window_get_screen(win);
+	root_window = gdk_screen_get_root_window(scrn);
+    }
+# else
     root_window = gtk_widget_get_root_window(gui.mainwin);
+# endif
 #endif
 
     /* Create a pseudo blank pointer, which is in fact one pixel by one pixel
      * in size. */
+#if GTK_CHECK_VERSION(3,0,0)
+    {
+	cairo_surface_t *surf;
+	cairo_t		*cr;
+
+	surf = cairo_image_surface_create(CAIRO_FORMAT_A1, 1, 1);
+	cr = cairo_create(surf);
+
+	cairo_set_source_rgb(cr,
+			     color.red / 65535.0,
+			     color.green / 65535.0,
+			     color.blue / 65535.0);
+	cairo_rectangle(cr, 0, 0, 1, 1);
+	cairo_fill(cr);
+	cairo_destroy(cr);
+
+	blank_mask = gdk_pixbuf_get_from_surface(surf, 0, 0, 1, 1);
+	cairo_surface_destroy(surf);
+
+	cursor = gdk_cursor_new_from_pixbuf(gdk_window_get_display(root_window),
+					    blank_mask, 0, 0);
+	g_object_unref(blank_mask);
+    }
+#else
     blank_mask = gdk_bitmap_create_from_data(root_window, blank_data, 1, 1);
     cursor = gdk_cursor_new_from_pixmap(blank_mask, blank_mask,
 					&color, &color, 0, 0);
     gdk_bitmap_unref(blank_mask);
+#endif
 
     return cursor;
 }
@@ -2473,12 +2867,22 @@
      * Recreate the invisible mouse cursor.
      */
     if (gui.blank_pointer != NULL)
+# if GTK_CHECK_VERSION(3,0,0)
+	g_object_unref(G_OBJECT(gui.blank_pointer));
+# else
 	gdk_cursor_unref(gui.blank_pointer);
+# endif
 
     gui.blank_pointer = create_blank_pointer();
 
+# if GTK_CHECK_VERSION(3,0,0)
+    if (gui.pointer_hidden && gtk_widget_get_window(gui.drawarea) != NULL)
+	gdk_window_set_cursor(gtk_widget_get_window(gui.drawarea),
+		gui.blank_pointer);
+# else
     if (gui.pointer_hidden && gui.drawarea->window != NULL)
 	gdk_window_set_cursor(gui.drawarea->window, gui.blank_pointer);
+# endif
 
     /*
      * Create a new PangoContext for this screen, and initialize it
@@ -2509,28 +2913,54 @@
 drawarea_realize_cb(GtkWidget *widget, gpointer data UNUSED)
 {
     GtkWidget *sbar;
+#if GTK_CHECK_VERSION(3,0,0)
+    GtkAllocation allocation;
+#endif
 
 #ifdef FEAT_XIM
     xim_init();
 #endif
     gui_mch_new_colors();
+#if GTK_CHECK_VERSION(3,0,0)
+    gui.surface = gdk_window_create_similar_surface(
+	    gtk_widget_get_window(widget),
+	    CAIRO_CONTENT_COLOR_ALPHA,
+	    gtk_widget_get_allocated_width(widget),
+	    gtk_widget_get_allocated_height(widget));
+#else
     gui.text_gc = gdk_gc_new(gui.drawarea->window);
+#endif
 
     gui.blank_pointer = create_blank_pointer();
     if (gui.pointer_hidden)
+#if GTK_CHECK_VERSION(3,0,0)
+	gdk_window_set_cursor(gtk_widget_get_window(widget), gui.blank_pointer);
+#else
 	gdk_window_set_cursor(widget->window, gui.blank_pointer);
+#endif
 
     /* get the actual size of the scrollbars, if they are realized */
     sbar = firstwin->w_scrollbars[SBAR_LEFT].id;
     if (!sbar || (!gui.which_scrollbars[SBAR_LEFT]
 				    && firstwin->w_scrollbars[SBAR_RIGHT].id))
 	sbar = firstwin->w_scrollbars[SBAR_RIGHT].id;
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_widget_get_allocation(sbar, &allocation);
+    if (sbar && gtk_widget_get_realized(sbar) && allocation.width)
+	gui.scrollbar_width = allocation.width;
+#else
     if (sbar && GTK_WIDGET_REALIZED(sbar) && sbar->allocation.width)
 	gui.scrollbar_width = sbar->allocation.width;
+#endif
 
     sbar = gui.bottom_sbar.id;
+#if GTK_CHECK_VERSION(3,0,0)
+    if (sbar && gtk_widget_get_realized(sbar) && allocation.height)
+	gui.scrollbar_height = allocation.height;
+#else
     if (sbar && GTK_WIDGET_REALIZED(sbar) && sbar->allocation.height)
 	gui.scrollbar_height = sbar->allocation.height;
+#endif
 }
 
 /*
@@ -2558,10 +2988,22 @@
     g_object_unref(gui.text_context);
     gui.text_context = NULL;
 
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gui.surface != NULL)
+    {
+	cairo_surface_destroy(gui.surface);
+	gui.surface = NULL;
+    }
+#else
     g_object_unref(gui.text_gc);
     gui.text_gc = NULL;
+#endif
 
+#if GTK_CHECK_VERSION(3,0,0)
+    g_object_unref(G_OBJECT(gui.blank_pointer));
+#else
     gdk_cursor_unref(gui.blank_pointer);
+#endif
     gui.blank_pointer = NULL;
 }
 
@@ -2573,6 +3015,38 @@
     gui_mch_new_colors();
 }
 
+#if GTK_CHECK_VERSION(3,0,0)
+    static gboolean
+drawarea_configure_event_cb(GtkWidget	      *widget,
+			    GdkEventConfigure *event,
+			    gpointer	       data UNUSED)
+{
+    static int cur_width = 0;
+    static int cur_height = 0;
+
+    g_return_val_if_fail(event
+	    && event->width >= 1 && event->height >= 1, TRUE);
+
+    if (event->width == cur_width && event->height == cur_height)
+	return TRUE;
+
+    cur_width = event->width;
+    cur_height = event->height;
+
+    if (gui.surface != NULL)
+	cairo_surface_destroy(gui.surface);
+
+    gui.surface = gdk_window_create_similar_surface(
+	    gtk_widget_get_window(widget),
+	    CAIRO_CONTENT_COLOR_ALPHA,
+	    event->width, event->height);
+
+    gtk_widget_queue_draw(widget);
+
+    return TRUE;
+}
+#endif
+
 /*
  * Callback routine for the "delete_event" signal on the toplevel window.
  * Tries to vim gracefully, or refuses to exit with changed buffers.
@@ -2592,7 +3066,7 @@
 {
     GtkOrientation item_orientation = GTK_ORIENTATION_HORIZONTAL;
 
-#ifdef FEAT_GUI_GNOME
+# ifdef FEAT_GUI_GNOME
     if (using_gnome && widget != NULL)
     {
 	GtkWidget *parent;
@@ -2611,16 +3085,34 @@
 	    item_orientation = bonobo_dock_item_get_orientation(dockitem);
 	}
     }
-#endif
+# endif
+# if GTK_CHECK_VERSION(3,0,0)
+    if (widget != NULL
+	    && item_orientation == orientation
+	    && gtk_widget_get_realized(widget)
+	    && gtk_widget_get_visible(widget))
+# else
     if (widget != NULL
 	    && item_orientation == orientation
 	    && GTK_WIDGET_REALIZED(widget)
 	    && GTK_WIDGET_VISIBLE(widget))
+# endif
     {
+# if GTK_CHECK_VERSION(3,0,0)
+	GtkAllocation allocation;
+
+	gtk_widget_get_allocation(widget, &allocation);
+
+	if (orientation == GTK_ORIENTATION_HORIZONTAL)
+	    return allocation.height;
+	else
+	    return allocation.width;
+# else
 	if (orientation == GTK_ORIENTATION_HORIZONTAL)
 	    return widget->allocation.height;
 	else
 	    return widget->allocation.width;
+# endif
     }
     return 0;
 }
@@ -2774,6 +3266,17 @@
     {
 	GtkImage *image = (GtkImage *)widget;
 
+# if GTK_CHECK_VERSION(3,10,0)
+	if (gtk_image_get_storage_type(image) == GTK_IMAGE_ICON_NAME)
+	{
+	    const GtkIconSize icon_size = GPOINTER_TO_INT(user_data);
+	    const gchar *icon_name;
+
+	    gtk_image_get_icon_name(image, &icon_name, NULL);
+
+	    gtk_image_set_from_icon_name(image, icon_name, icon_size);
+	}
+# else
 	/* User-defined icons are stored in a GtkIconSet */
 	if (gtk_image_get_storage_type(image) == GTK_IMAGE_ICON_SET)
 	{
@@ -2787,6 +3290,7 @@
 	    gtk_image_set_from_icon_set(image, icon_set, icon_size);
 	    gtk_icon_set_unref(icon_set);
 	}
+# endif
     }
     else if (GTK_IS_CONTAINER(widget))
     {
@@ -2815,7 +3319,9 @@
 	style = GTK_TOOLBAR_ICONS;
 
     gtk_toolbar_set_style(toolbar, style);
+# if !GTK_CHECK_VERSION(3,0,0)
     gtk_toolbar_set_tooltips(toolbar, (toolbar_flags & TOOLBAR_TOOLTIPS) != 0);
+# endif
 
     switch (tbis_flags)
     {
@@ -2847,7 +3353,9 @@
 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
 static int ignore_tabline_evt = FALSE;
 static GtkWidget *tabline_menu;
+# if !GTK_CHECK_VERSION(3,0,0)
 static GtkTooltips *tabline_tooltip;
+# endif
 static int clicked_page;	    /* page clicked in tab line */
 
 /*
@@ -2872,9 +3380,15 @@
     CONVERT_TO_UTF8_FREE(utf_text);
 
     gtk_container_add(GTK_CONTAINER(menu), item);
+# if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(item), "activate",
+	    G_CALLBACK(tabline_menu_handler),
+	    GINT_TO_POINTER(resp));
+# else
     gtk_signal_connect(GTK_OBJECT(item), "activate",
 	    GTK_SIGNAL_FUNC(tabline_menu_handler),
 	    (gpointer)(long)resp);
+# endif
 }
 
 /*
@@ -2916,10 +3430,20 @@
 	   )
 	    return TRUE;
 
+# if GTK_CHECK_VERSION(3,0,0)
+	tabwin = gui_gtk_window_at_position(gui.mainwin, &x, &y);
+# else
 	tabwin = gdk_window_at_pointer(&x, &y);
+# endif
+
 	gdk_window_get_user_data(tabwin, (gpointer)&tabwidget);
+# if GTK_CHECK_VERSION(3,0,0)
+	clicked_page = GPOINTER_TO_INT(g_object_get_data(G_OBJECT(tabwidget),
+							 "tab_num"));
+# else
 	clicked_page = (int)(long)gtk_object_get_user_data(
 						       GTK_OBJECT(tabwidget));
+# endif
 
 	/* If the event was generated for 3rd button popup the menu. */
 	if (bevent->button == 3)
@@ -2950,7 +3474,11 @@
     static void
 on_select_tab(
 	GtkNotebook	*notebook UNUSED,
+# if GTK_CHECK_VERSION(3,0,0)
+	gpointer	*page UNUSED,
+# else
 	GtkNotebookPage *page UNUSED,
+# endif
 	gint		idx,
 	gpointer	data UNUSED)
 {
@@ -2975,7 +3503,11 @@
 	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gui.tabline), showit);
 	update_window_manager_hints(0, 0);
 	if (showit)
+# if GTK_CHECK_VERSION(3,0,0)
+	    gtk_widget_set_can_focus(GTK_WIDGET(gui.tabline), FALSE);
+# else
 	    GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(gui.tabline), GTK_CAN_FOCUS);
+# endif
     }
 
     gui_mch_update();
@@ -3023,12 +3555,19 @@
 	if (page == NULL)
 	{
 	    /* Add notebook page */
+# if GTK_CHECK_VERSION(3,2,0)
+	    page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+	    gtk_box_set_homogeneous(GTK_BOX(page), FALSE);
+# else
 	    page = gtk_vbox_new(FALSE, 0);
+# endif
 	    gtk_widget_show(page);
 	    event_box = gtk_event_box_new();
 	    gtk_widget_show(event_box);
 	    label = gtk_label_new("-Empty-");
+# if !GTK_CHECK_VERSION(3,14,0)
 	    gtk_misc_set_padding(GTK_MISC(label), 2, 2);
+# endif
 	    gtk_container_add(GTK_CONTAINER(event_box), label);
 	    gtk_widget_show(label);
 	    gtk_notebook_insert_page(GTK_NOTEBOOK(gui.tabline),
@@ -3038,9 +3577,18 @@
 	}
 
 	event_box = gtk_notebook_get_tab_label(GTK_NOTEBOOK(gui.tabline), page);
+# if GTK_CHECK_VERSION(3,0,0)
+	g_object_set_data(G_OBJECT(event_box), "tab_num",
+						     GINT_TO_POINTER(tab_num));
+# else
 	gtk_object_set_user_data(GTK_OBJECT(event_box),
 						     (gpointer)(long)tab_num);
+# endif
+# if GTK_CHECK_VERSION(3,0,0)
+	label = gtk_bin_get_child(GTK_BIN(event_box));
+# else
 	label = GTK_BIN(event_box)->child;
+# endif
 	get_tabline_label(tp, FALSE);
 	labeltext = CONVERT_TO_UTF8(NameBuff);
 	gtk_label_set_text(GTK_LABEL(label), (const char *)labeltext);
@@ -3048,8 +3596,12 @@
 
 	get_tabline_label(tp, TRUE);
 	labeltext = CONVERT_TO_UTF8(NameBuff);
+# if GTK_CHECK_VERSION(3,0,0)
+	gtk_widget_set_tooltip_text(event_box, (const gchar *)labeltext);
+# else
 	gtk_tooltips_set_tip(GTK_TOOLTIPS(tabline_tooltip), event_box,
 			     (const char *)labeltext, NULL);
+# endif
 	CONVERT_TO_UTF8_FREE(labeltext);
     }
 
@@ -3057,8 +3609,13 @@
     while (gtk_notebook_get_nth_page(GTK_NOTEBOOK(gui.tabline), nr) != NULL)
 	gtk_notebook_remove_page(GTK_NOTEBOOK(gui.tabline), nr);
 
+# if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_notebook_get_current_page(GTK_NOTEBOOK(gui.tabline)) != curtabidx)
+	gtk_notebook_set_current_page(GTK_NOTEBOOK(gui.tabline), curtabidx);
+# else
     if (gtk_notebook_current_page(GTK_NOTEBOOK(gui.tabline)) != curtabidx)
 	gtk_notebook_set_page(GTK_NOTEBOOK(gui.tabline), curtabidx);
+# endif
 
     /* Make sure everything is in place before drawing text. */
     gui_mch_update();
@@ -3076,8 +3633,13 @@
 	return;
 
     ignore_tabline_evt = TRUE;
+# if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_notebook_get_current_page(GTK_NOTEBOOK(gui.tabline)) != nr - 1)
+	gtk_notebook_set_current_page(GTK_NOTEBOOK(gui.tabline), nr - 1);
+# else
     if (gtk_notebook_current_page(GTK_NOTEBOOK(gui.tabline)) != nr - 1)
 	gtk_notebook_set_page(GTK_NOTEBOOK(gui.tabline), nr - 1);
+# endif
     ignore_tabline_evt = FALSE;
 }
 
@@ -3187,8 +3749,10 @@
 #endif
     /* FIXME: Need to install the classic icons and a gtkrc.classic file.
      * The hard part is deciding install locations and the Makefile magic. */
-#if 0
+#if !GTK_CHECK_VERSION(3,0,0)
+# if 0
     gtk_rc_parse("gtkrc");
+# endif
 #endif
 
     /* Initialize values */
@@ -3221,7 +3785,11 @@
 #else
 	plug = gtk_plug_new(gtk_socket_id);
 #endif
+#if GTK_CHECK_VERSION(3,0,0)
+	if (plug != NULL && gtk_plug_get_socket_window(GTK_PLUG(plug)) != NULL)
+#else
 	if (plug != NULL && GTK_PLUG(plug)->socket_window != NULL)
+#endif
 	{
 	    gui.mainwin = plug;
 	}
@@ -3256,14 +3824,26 @@
     gui.text_context = gtk_widget_create_pango_context(gui.mainwin);
     pango_context_set_base_dir(gui.text_context, PANGO_DIRECTION_LTR);
 
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_container_set_border_width(GTK_CONTAINER(gui.mainwin), 0);
+#else
     gtk_container_border_width(GTK_CONTAINER(gui.mainwin), 0);
+#endif
     gtk_widget_add_events(gui.mainwin, GDK_VISIBILITY_NOTIFY_MASK);
 
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(gui.mainwin), "delete-event",
+		     G_CALLBACK(&delete_event_cb), NULL);
+
+    g_signal_connect(G_OBJECT(gui.mainwin), "realize",
+		     G_CALLBACK(&mainwin_realize), NULL);
+#else
     gtk_signal_connect(GTK_OBJECT(gui.mainwin), "delete_event",
 		       GTK_SIGNAL_FUNC(&delete_event_cb), NULL);
 
     gtk_signal_connect(GTK_OBJECT(gui.mainwin), "realize",
 		       GTK_SIGNAL_FUNC(&mainwin_realize), NULL);
+#endif
 #ifdef HAVE_GTK_MULTIHEAD
     g_signal_connect(G_OBJECT(gui.mainwin), "screen_changed",
 		     G_CALLBACK(&mainwin_screen_changed_cb), NULL);
@@ -3272,7 +3852,12 @@
     gtk_window_add_accel_group(GTK_WINDOW(gui.mainwin), gui.accel_group);
 
     /* A vertical box holds the menubar, toolbar and main text window. */
+#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
 
 #ifdef FEAT_GUI_GNOME
     if (using_gnome)
@@ -3335,11 +3920,17 @@
      * Create the toolbar and handle
      */
     /* some aesthetics on the toolbar */
+# ifdef USE_GTK3
+    /* TODO: Add GTK+ 3 code here using GtkCssProvider if neccessary. */
+    /* N.B.  Since the default value of GtkToolbar::button-relief is
+     * GTK_RELIEF_NONE, there's no need to specify that, probably. */
+# else
     gtk_rc_parse_string(
 	    "style \"vim-toolbar-style\" {\n"
 	    "  GtkToolbar::button_relief = GTK_RELIEF_NONE\n"
 	    "}\n"
 	    "widget \"*.vim-toolbar\" style \"vim-toolbar-style\"\n");
+# endif
     gui.toolbar = gtk_toolbar_new();
     gtk_widget_set_name(gui.toolbar, "vim-toolbar");
     set_toolbar_style(GTK_TOOLBAR(gui.toolbar));
@@ -3381,42 +3972,77 @@
     gtk_notebook_set_show_border(GTK_NOTEBOOK(gui.tabline), FALSE);
     gtk_notebook_set_show_tabs(GTK_NOTEBOOK(gui.tabline), FALSE);
     gtk_notebook_set_scrollable(GTK_NOTEBOOK(gui.tabline), TRUE);
+# if !GTK_CHECK_VERSION(3,0,0)
     gtk_notebook_set_tab_border(GTK_NOTEBOOK(gui.tabline), FALSE);
+# endif
 
+# if !GTK_CHECK_VERSION(3,0,0)
     tabline_tooltip = gtk_tooltips_new();
     gtk_tooltips_enable(GTK_TOOLTIPS(tabline_tooltip));
+# endif
 
     {
 	GtkWidget *page, *label, *event_box;
 
 	/* Add the first tab. */
+# if GTK_CHECK_VERSION(3,2,0)
+	page = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
+	gtk_box_set_homogeneous(GTK_BOX(page), FALSE);
+# else
 	page = gtk_vbox_new(FALSE, 0);
+# endif
 	gtk_widget_show(page);
 	gtk_container_add(GTK_CONTAINER(gui.tabline), page);
 	label = gtk_label_new("-Empty-");
 	gtk_widget_show(label);
 	event_box = gtk_event_box_new();
 	gtk_widget_show(event_box);
+# if GTK_CHECK_VERSION(3,0,0)
+	g_object_set_data(G_OBJECT(event_box), "tab_num", GINT_TO_POINTER(1L));
+# else
 	gtk_object_set_user_data(GTK_OBJECT(event_box), (gpointer)1L);
+# endif
+# if !GTK_CHECK_VERSION(3,14,0)
 	gtk_misc_set_padding(GTK_MISC(label), 2, 2);
+# endif
 	gtk_container_add(GTK_CONTAINER(event_box), label);
 	gtk_notebook_set_tab_label(GTK_NOTEBOOK(gui.tabline), page, event_box);
     }
 
+# if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(gui.tabline), "switch-page",
+		     G_CALLBACK(on_select_tab), NULL);
+# else
     gtk_signal_connect(GTK_OBJECT(gui.tabline), "switch_page",
 		       GTK_SIGNAL_FUNC(on_select_tab), NULL);
+# endif
 
     /* Create a popup menu for the tab line and connect it. */
     tabline_menu = create_tabline_menu();
+# if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect_swapped(G_OBJECT(gui.tabline), "button-press-event",
+	    G_CALLBACK(on_tabline_menu), G_OBJECT(tabline_menu));
+# else
     gtk_signal_connect_object(GTK_OBJECT(gui.tabline), "button_press_event",
 	    GTK_SIGNAL_FUNC(on_tabline_menu), GTK_OBJECT(tabline_menu));
-#endif
+# endif
+#endif /* FEAT_GUI_TABLINE */
 
     gui.formwin = gtk_form_new();
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_container_set_border_width(GTK_CONTAINER(gui.formwin), 0);
+#else
     gtk_container_border_width(GTK_CONTAINER(gui.formwin), 0);
+#endif
+#if !GTK_CHECK_VERSION(3,0,0)
     gtk_widget_set_events(gui.formwin, GDK_EXPOSURE_MASK);
+#endif
 
     gui.drawarea = gtk_drawing_area_new();
+#if GTK_CHECK_VERSION(3,0,0)
+    gui.surface = NULL;
+    gui.by_signal = FALSE;
+#endif
 
     /* Determine which events we will filter. */
     gtk_widget_set_events(gui.drawarea,
@@ -3438,18 +4064,35 @@
 
     /* For GtkSockets, key-presses must go to the focus widget (drawarea)
      * and not the window. */
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect((gtk_socket_id == 0) ? G_OBJECT(gui.mainwin)
+					  : G_OBJECT(gui.drawarea),
+		       "key-press-event",
+		       G_CALLBACK(key_press_event), NULL);
+#else
     gtk_signal_connect((gtk_socket_id == 0) ? GTK_OBJECT(gui.mainwin)
 					    : GTK_OBJECT(gui.drawarea),
 		       "key_press_event",
 		       GTK_SIGNAL_FUNC(key_press_event), NULL);
-#if defined(FEAT_XIM)
+#endif
+#if defined(FEAT_XIM) || GTK_CHECK_VERSION(3,0,0)
     /* Also forward key release events for the benefit of GTK+ 2 input
      * modules.  Try CTRL-SHIFT-xdigits to enter a Unicode code point. */
     g_signal_connect((gtk_socket_id == 0) ? G_OBJECT(gui.mainwin)
 					  : G_OBJECT(gui.drawarea),
-		     "key_release_event",
+		     "key-release-event",
 		     G_CALLBACK(&key_release_event), NULL);
 #endif
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(gui.drawarea), "realize",
+		     G_CALLBACK(drawarea_realize_cb), NULL);
+    g_signal_connect(G_OBJECT(gui.drawarea), "unrealize",
+		     G_CALLBACK(drawarea_unrealize_cb), NULL);
+    g_signal_connect(G_OBJECT(gui.drawarea), "configure-event",
+	    G_CALLBACK(drawarea_configure_event_cb), NULL);
+    g_signal_connect_after(G_OBJECT(gui.drawarea), "style-set",
+			   G_CALLBACK(&drawarea_style_set_cb), NULL);
+#else
     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "realize",
 		       GTK_SIGNAL_FUNC(drawarea_realize_cb), NULL);
     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "unrealize",
@@ -3457,8 +4100,11 @@
 
     gtk_signal_connect_after(GTK_OBJECT(gui.drawarea), "style_set",
 			     GTK_SIGNAL_FUNC(&drawarea_style_set_cb), NULL);
+#endif
 
+#if !GTK_CHECK_VERSION(3,0,0)
     gui.visibility = GDK_VISIBILITY_UNOBSCURED;
+#endif
 
 #if !(defined(FEAT_GUI_GNOME) && defined(FEAT_SESSION))
     wm_protocols_atom = gdk_atom_intern("WM_PROTOCOLS", FALSE);
@@ -3467,7 +4113,11 @@
 
     if (gtk_socket_id != 0)
 	/* make sure keyboard input can go to the drawarea */
+#if GTK_CHECK_VERSION(3,0,0)
+	gtk_widget_set_can_focus(gui.drawarea, TRUE);
+#else
 	GTK_WIDGET_SET_FLAGS(gui.drawarea, GTK_CAN_FOCUS);
+#endif
 
     /*
      * Set clipboard specific atoms
@@ -3482,10 +4132,15 @@
      */
     gui.border_offset = gui.border_width;
 
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(gui.drawarea), "draw",
+		     G_CALLBACK(draw_event), NULL);
+#else
     gtk_signal_connect(GTK_OBJECT(gui.mainwin), "visibility_notify_event",
 		       GTK_SIGNAL_FUNC(visibility_event), NULL);
     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "expose_event",
 		       GTK_SIGNAL_FUNC(expose_event), NULL);
+#endif
 
     /*
      * Only install these enter/leave callbacks when 'p' in 'guioptions'.
@@ -3493,10 +4148,17 @@
      */
     if (vim_strchr(p_go, GO_POINTER) != NULL)
     {
+#if GTK_CHECK_VERSION(3,0,0)
+	g_signal_connect(G_OBJECT(gui.drawarea), "leave-notify-event",
+			 G_CALLBACK(leave_notify_event), NULL);
+	g_signal_connect(G_OBJECT(gui.drawarea), "enter-notify-event",
+			 G_CALLBACK(enter_notify_event), NULL);
+#else
 	gtk_signal_connect(GTK_OBJECT(gui.drawarea), "leave_notify_event",
 			   GTK_SIGNAL_FUNC(leave_notify_event), NULL);
 	gtk_signal_connect(GTK_OBJECT(gui.drawarea), "enter_notify_event",
 			   GTK_SIGNAL_FUNC(enter_notify_event), NULL);
+#endif
     }
 
     /* Real windows can get focus ... GtkPlug, being a mere container can't,
@@ -3505,25 +4167,56 @@
      */
     if (gtk_socket_id == 0)
     {
+#if GTK_CHECK_VERSION(3,0,0)
+	g_signal_connect(G_OBJECT(gui.mainwin), "focus-out-event",
+			 G_CALLBACK(focus_out_event), NULL);
+	g_signal_connect(G_OBJECT(gui.mainwin), "focus-in-event",
+			 G_CALLBACK(focus_in_event), NULL);
+#else
 	gtk_signal_connect(GTK_OBJECT(gui.mainwin), "focus_out_event",
 			       GTK_SIGNAL_FUNC(focus_out_event), NULL);
 	gtk_signal_connect(GTK_OBJECT(gui.mainwin), "focus_in_event",
 			       GTK_SIGNAL_FUNC(focus_in_event), NULL);
+#endif
     }
     else
     {
+#if GTK_CHECK_VERSION(3,0,0)
+	g_signal_connect(G_OBJECT(gui.drawarea), "focus-out-event",
+			 G_CALLBACK(focus_out_event), NULL);
+	g_signal_connect(G_OBJECT(gui.drawarea), "focus-in-event",
+			 G_CALLBACK(focus_in_event), NULL);
+#else
 	gtk_signal_connect(GTK_OBJECT(gui.drawarea), "focus_out_event",
 			       GTK_SIGNAL_FUNC(focus_out_event), NULL);
 	gtk_signal_connect(GTK_OBJECT(gui.drawarea), "focus_in_event",
 			       GTK_SIGNAL_FUNC(focus_in_event), NULL);
+#endif
 #ifdef FEAT_GUI_TABLINE
+# if GTK_CHECK_VERSION(3,0,0)
+	g_signal_connect(G_OBJECT(gui.tabline), "focus-out-event",
+			 G_CALLBACK(focus_out_event), NULL);
+	g_signal_connect(G_OBJECT(gui.tabline), "focus-in-event",
+			 G_CALLBACK(focus_in_event), NULL);
+# else
 	gtk_signal_connect(GTK_OBJECT(gui.tabline), "focus_out_event",
 			       GTK_SIGNAL_FUNC(focus_out_event), NULL);
 	gtk_signal_connect(GTK_OBJECT(gui.tabline), "focus_in_event",
 			       GTK_SIGNAL_FUNC(focus_in_event), NULL);
+# endif
 #endif /* FEAT_GUI_TABLINE */
     }
 
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(gui.drawarea), "motion-notify-event",
+		     G_CALLBACK(motion_notify_event), NULL);
+    g_signal_connect(G_OBJECT(gui.drawarea), "button-press-event",
+		     G_CALLBACK(button_press_event), NULL);
+    g_signal_connect(G_OBJECT(gui.drawarea), "button-release-event",
+		     G_CALLBACK(button_release_event), NULL);
+    g_signal_connect(G_OBJECT(gui.drawarea), "scroll-event",
+		     G_CALLBACK(&scroll_event), NULL);
+#else
     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "motion_notify_event",
 		       GTK_SIGNAL_FUNC(motion_notify_event), NULL);
     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "button_press_event",
@@ -3532,19 +4225,32 @@
 		       GTK_SIGNAL_FUNC(button_release_event), NULL);
     g_signal_connect(G_OBJECT(gui.drawarea), "scroll_event",
 		     G_CALLBACK(&scroll_event), NULL);
+#endif
 
     /*
      * Add selection handler functions.
      */
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(gui.drawarea), "selection-clear-event",
+		     G_CALLBACK(selection_clear_event), NULL);
+    g_signal_connect(G_OBJECT(gui.drawarea), "selection-received",
+		     G_CALLBACK(selection_received_cb), NULL);
+#else
     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "selection_clear_event",
 		       GTK_SIGNAL_FUNC(selection_clear_event), NULL);
     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "selection_received",
 		       GTK_SIGNAL_FUNC(selection_received_cb), NULL);
+#endif
 
     gui_gtk_set_selection_targets();
 
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(gui.drawarea), "selection-get",
+		     G_CALLBACK(selection_get_cb), NULL);
+#else
     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "selection_get",
 		       GTK_SIGNAL_FUNC(selection_get_cb), NULL);
+#endif
 
     /* Pretend we don't have input focus, we will get an event if we do. */
     gui.in_focus = FALSE;
@@ -3572,6 +4278,67 @@
 }
 #endif /* FEAT_GUI_GNOME && FEAT_SESSION */
 
+#if GTK_CHECK_VERSION(3,0,0)
+    static void
+gui_gtk_get_rgb_from_pixel(guint32 pixel, GdkRGBA *result)
+{
+    GdkVisual * const visual = gtk_widget_get_visual(gui.drawarea);
+    guint32 r_mask, g_mask, b_mask;
+    gint r_shift, g_shift, b_shift;
+
+    if (visual == NULL)
+    {
+	result->red = 0.0;
+	result->green = 0.0;
+	result->blue = 0.0;
+	result->alpha = 0.0;
+	return;
+    }
+
+    gdk_visual_get_red_pixel_details(visual, &r_mask, &r_shift, NULL);
+    gdk_visual_get_green_pixel_details(visual, &g_mask, &g_shift, NULL);
+    gdk_visual_get_blue_pixel_details(visual, &b_mask, &b_shift, NULL);
+
+    result->red = ((pixel & r_mask) >> r_shift) / 255.0;
+    result->green = ((pixel & g_mask) >> g_shift) / 255.0;
+    result->blue = ((pixel & b_mask) >> b_shift) / 255.0;
+    result->alpha = 1.0;
+}
+
+/* Convert a GdRGBA into a pixel value using drawarea's visual */
+    static guint32
+gui_gtk_get_pixel_from_rgb(const GdkRGBA *rgba)
+{
+    GdkVisual * const visual = gtk_widget_get_visual(gui.drawarea);
+    guint32 r_mask, g_mask, b_mask;
+    gint r_shift, g_shift, b_shift;
+    guint32 r, g, b;
+
+    if (visual == NULL)
+	return 0;
+
+    gdk_visual_get_red_pixel_details(visual, &r_mask, &r_shift, NULL);
+    gdk_visual_get_green_pixel_details(visual, &g_mask, &g_shift, NULL);
+    gdk_visual_get_blue_pixel_details(visual, &b_mask, &b_shift, NULL);
+
+    r = rgba->red * 65535;
+    g = rgba->green * 65535;
+    b = rgba->blue * 65535;
+
+    return ((r << r_shift) & r_mask) |
+	   ((g << g_shift) & g_mask) |
+	   ((b << b_shift) & b_mask);
+}
+
+    static void
+set_cairo_source_rgb_from_pixel(cairo_t *cr, guint32 pixel)
+{
+    GdkRGBA result;
+    gui_gtk_get_rgb_from_pixel(pixel, &result);
+    cairo_set_source_rgb(cr, result.red, result.green, result.blue);
+}
+#endif /* GTK_CHECK_VERSION(3,0,0) */
+
 /*
  * Called when the foreground or background color has been changed.
  * This used to change the graphics contexts directly but we are
@@ -3580,12 +4347,39 @@
     void
 gui_mch_new_colors(void)
 {
+#if GTK_CHECK_VERSION(3,0,0)
+    GdkWindow * const da_win = gtk_widget_get_window(gui.drawarea);
+
+    if (gui.drawarea != NULL && gtk_widget_get_window(gui.drawarea) != NULL)
+#else
     if (gui.drawarea != NULL && gui.drawarea->window != NULL)
+#endif
     {
+#if GTK_CHECK_VERSION(3,4,0)
+	GdkRGBA color;
+
+	gui_gtk_get_rgb_from_pixel(gui.back_pixel, &color);
+	{
+	    cairo_pattern_t * const pat = cairo_pattern_create_rgba(
+		    color.red, color.green, color.blue, color.alpha);
+	    if (pat != NULL)
+	    {
+		gdk_window_set_background_pattern(da_win, pat);
+		cairo_pattern_destroy(pat);
+	    }
+	    else
+		gdk_window_set_background_rgba(da_win, &color);
+	}
+#else /* !GTK_CHECK_VERSION(3,4,0) */
 	GdkColor color = { 0, 0, 0, 0 };
 
 	color.pixel = gui.back_pixel;
+# if GTK_CHECK_VERSION(3,0,0)
+	gdk_window_set_background(da_win, &color);
+# else
 	gdk_window_set_background(gui.drawarea->window, &color);
+# endif
+#endif /* !GTK_CHECK_VERSION(3,4,0) */
     }
 }
 
@@ -3618,8 +4412,13 @@
  * We can't do much more here than to trying to preserve what had been done,
  * since the window is already inevitably going away.
  */
+#if GTK_CHECK_VERSION(3,0,0)
+    static void
+mainwin_destroy_cb(GObject *object UNUSED, gpointer data UNUSED)
+#else
     static void
 mainwin_destroy_cb(GtkObject *object UNUSED, gpointer data UNUSED)
+#endif
 {
     /* Don't write messages to the GUI anymore */
     full_screen = FALSE;
@@ -3799,8 +4598,13 @@
      * changed them). */
     highlight_gui_started();	/* re-init colors and fonts */
 
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(gui.mainwin), "destroy",
+		     G_CALLBACK(mainwin_destroy_cb), NULL);
+#else
     gtk_signal_connect(GTK_OBJECT(gui.mainwin), "destroy",
 		       GTK_SIGNAL_FUNC(mainwin_destroy_cb), NULL);
+#endif
 
 #ifdef FEAT_HANGULIN
     hangul_keyboard_set();
@@ -3816,15 +4620,25 @@
      * manager upon us and should not interfere with what VIM is requesting
      * upon startup.
      */
+#if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(gui.formwin), "configure-event",
+		     G_CALLBACK(form_configure_event), NULL);
+#else
     gtk_signal_connect(GTK_OBJECT(gui.formwin), "configure_event",
 		       GTK_SIGNAL_FUNC(form_configure_event), NULL);
+#endif
 
 #ifdef FEAT_DND
     /* Set up for receiving DND items. */
     gui_gtk_set_dnd_targets();
 
+# if GTK_CHECK_VERSION(3,0,0)
+    g_signal_connect(G_OBJECT(gui.drawarea), "drag-data-received",
+		     G_CALLBACK(drag_data_received_cb), NULL);
+# else
     gtk_signal_connect(GTK_OBJECT(gui.drawarea), "drag_data_received",
 		       GTK_SIGNAL_FUNC(drag_data_received_cb), NULL);
+# endif
 #endif
 
 	/* With GTK+ 2, we need to iconify the window before calling show()
@@ -3901,7 +4715,8 @@
     gtk_window_move(GTK_WINDOW(gui.mainwin), x, y);
 }
 
-#if 0
+#if !GTK_CHECK_VERSION(3,0,0)
+# if 0
 static int resize_idle_installed = FALSE;
 /*
  * Idle handler to force resize.  Used by gui_mch_set_shellsize() to ensure
@@ -3937,7 +4752,8 @@
     resize_idle_installed = FALSE;
     return FALSE; /* don't call me again */
 }
-#endif
+# endif
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
 
 /*
  * Return TRUE if the main window is maximized.
@@ -3945,9 +4761,15 @@
     int
 gui_mch_maximized(void)
 {
+#if GTK_CHECK_VERSION(3,0,0)
+    return (gui.mainwin != NULL && gtk_widget_get_window(gui.mainwin) != NULL
+	    && (gdk_window_get_state(gtk_widget_get_window(gui.mainwin))
+					       & GDK_WINDOW_STATE_MAXIMIZED));
+#else
     return (gui.mainwin != NULL && gui.mainwin->window != NULL
 	    && (gdk_window_get_state(gui.mainwin->window)
 					       & GDK_WINDOW_STATE_MAXIMIZED));
+#endif
 }
 
 /*
@@ -4002,14 +4824,16 @@
     else
 	update_window_manager_hints(width, height);
 
-# if 0
+# if !GTK_CHECK_VERSION(3,0,0)
+#  if 0
     if (!resize_idle_installed)
     {
 	g_idle_add_full(GDK_PRIORITY_EVENTS + 10,
 			&force_shell_resize_idle, NULL, NULL);
 	resize_idle_installed = TRUE;
     }
-# endif
+#  endif
+# endif /* !GTK_CHECK_VERSION(3,0,0) */
     /*
      * Wait until all events are processed to prevent a crash because the
      * real size of the drawing area doesn't reflect Vim's internal ideas.
@@ -4084,7 +4908,11 @@
 	widget = gui.menubar;
 
     /* Do not disable the menu while starting up, otherwise F10 doesn't work. */
+# if GTK_CHECK_VERSION(3,0,0)
+    if (!showit != !gtk_widget_get_visible(widget) && !gui.starting)
+# else
     if (!showit != !GTK_WIDGET_VISIBLE(widget) && !gui.starting)
+# endif
     {
 	if (showit)
 	    gtk_widget_show(widget);
@@ -4115,7 +4943,11 @@
     if (showit)
 	set_toolbar_style(GTK_TOOLBAR(gui.toolbar));
 
+# if GTK_CHECK_VERSION(3,0,0)
+    if (!showit != !gtk_widget_get_visible(widget))
+# else
     if (!showit != !GTK_WIDGET_VISIBLE(widget))
+# endif
     {
 	if (showit)
 	    gtk_widget_show(widget);
@@ -4200,6 +5032,17 @@
     return OK;
 }
 
+#if GTK_CHECK_VERSION(3,0,0)
+/* Callback function used in gui_mch_font_dialog() */
+    static gboolean
+font_filter(const PangoFontFamily *family,
+	    const PangoFontFace   *face UNUSED,
+	    gpointer		   data UNUSED)
+{
+    return pango_font_family_is_monospace((PangoFontFamily *)family);
+}
+#endif
+
 /*
  * Put up a font dialog and return the selected font name in allocated memory.
  * "oldval" is the previous value.  Return NULL when cancelled.
@@ -4217,7 +5060,13 @@
     char_u	*fontname = NULL;
     char_u	*oldname;
 
+#if GTK_CHECK_VERSION(3,2,0)
+    dialog = gtk_font_chooser_dialog_new(NULL, NULL);
+    gtk_font_chooser_set_filter_func(GTK_FONT_CHOOSER(dialog), font_filter,
+	    NULL, NULL);
+#else
     dialog = gtk_font_selection_dialog_new(NULL);
+#endif
 
     gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(gui.mainwin));
     gtk_window_set_destroy_with_parent(GTK_WINDOW(dialog), TRUE);
@@ -4244,15 +5093,25 @@
 	    }
 	}
 
+#if GTK_CHECK_VERSION(3,2,0)
+	gtk_font_chooser_set_font(
+		GTK_FONT_CHOOSER(dialog), (const gchar *)oldname);
+#else
 	gtk_font_selection_dialog_set_font_name(
 		GTK_FONT_SELECTION_DIALOG(dialog), (const char *)oldname);
+#endif
 
 	if (oldname != oldval)
 	    vim_free(oldname);
     }
     else
+#if GTK_CHECK_VERSION(3,2,0)
+	gtk_font_chooser_set_font(
+		GTK_FONT_CHOOSER(dialog), DEFAULT_FONT);
+#else
 	gtk_font_selection_dialog_set_font_name(
 		GTK_FONT_SELECTION_DIALOG(dialog), DEFAULT_FONT);
+#endif
 
     response = gtk_dialog_run(GTK_DIALOG(dialog));
 
@@ -4260,8 +5119,12 @@
     {
 	char *name;
 
+#if GTK_CHECK_VERSION(3,2,0)
+	name = gtk_font_chooser_get_font(GTK_FONT_CHOOSER(dialog));
+#else
 	name = gtk_font_selection_dialog_get_font_name(
 			    GTK_FONT_SELECTION_DIALOG(dialog));
+#endif
 	if (name != NULL)
 	{
 	    char_u  *p;
@@ -4636,17 +5499,29 @@
 
     while (name != NULL)
     {
+#if GTK_CHECK_VERSION(3,0,0)
+	GdkRGBA     color;
+#else
 	GdkColor    color;
+#endif
 	int	    parsed;
 	int	    i;
 
+#if GTK_CHECK_VERSION(3,0,0)
+	parsed = gdk_rgba_parse(&color, (const gchar *)name);
+#else
 	parsed = gdk_color_parse((const char *)name, &color);
+#endif
 
 	if (parsed)
 	{
+#if GTK_CHECK_VERSION(3,0,0)
+	    return (guicolor_T)gui_gtk_get_pixel_from_rgb(&color);
+#else
 	    gdk_colormap_alloc_color(gtk_widget_get_colormap(gui.drawarea),
 				     &color, FALSE, TRUE);
 	    return (guicolor_T)color.pixel;
+#endif
 	}
 	/* add a few builtin names and try again */
 	for (i = 0; ; ++i)
@@ -4838,12 +5713,26 @@
 	glyph->geometry.x_offset = -width + MAX(0, width - ink_rect.width) / 2;
 }
 
+#if GTK_CHECK_VERSION(3,0,0)
+    static void
+draw_glyph_string(int row, int col, int num_cells, int flags,
+		  PangoFont *font, PangoGlyphString *glyphs,
+		  cairo_t *cr)
+#else
     static void
 draw_glyph_string(int row, int col, int num_cells, int flags,
 		  PangoFont *font, PangoGlyphString *glyphs)
+#endif
 {
     if (!(flags & DRAW_TRANSP))
     {
+#if GTK_CHECK_VERSION(3,0,0)
+	set_cairo_source_rgb_from_pixel(cr, gui.bgcolor->pixel);
+	cairo_rectangle(cr,
+			FILL_X(col), FILL_Y(row),
+			num_cells * gui.char_width, gui.char_height);
+	cairo_fill(cr);
+#else
 	gdk_gc_set_foreground(gui.text_gc, gui.bgcolor);
 
 	gdk_draw_rectangle(gui.drawarea->window,
@@ -4853,8 +5742,14 @@
 			   FILL_Y(row),
 			   num_cells * gui.char_width,
 			   gui.char_height);
+#endif
     }
 
+#if GTK_CHECK_VERSION(3,0,0)
+    set_cairo_source_rgb_from_pixel(cr, gui.fgcolor->pixel);
+    cairo_move_to(cr, TEXT_X(col), TEXT_Y(row));
+    pango_cairo_show_glyph_string(cr, font, glyphs);
+#else
     gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
 
     gdk_draw_glyphs(gui.drawarea->window,
@@ -4863,22 +5758,36 @@
 		    TEXT_X(col),
 		    TEXT_Y(row),
 		    glyphs);
+#endif
 
     /* redraw the contents with an offset of 1 to emulate bold */
     if ((flags & DRAW_BOLD) && !gui.font_can_bold)
+#if GTK_CHECK_VERSION(3,0,0)
+    {
+	set_cairo_source_rgb_from_pixel(cr, gui.fgcolor->pixel);
+	cairo_move_to(cr, TEXT_X(col) + 1, TEXT_Y(row));
+	pango_cairo_show_glyph_string(cr, font, glyphs);
+    }
+#else
 	gdk_draw_glyphs(gui.drawarea->window,
 			gui.text_gc,
 			font,
 			TEXT_X(col) + 1,
 			TEXT_Y(row),
 			glyphs);
+#endif
 }
 
 /*
  * Draw underline and undercurl at the bottom of the character cell.
  */
+#if GTK_CHECK_VERSION(3,0,0)
+    static void
+draw_under(int flags, int row, int col, int cells, cairo_t *cr)
+#else
     static void
 draw_under(int flags, int row, int col, int cells)
+#endif
 {
     int			i;
     int			offset;
@@ -4888,6 +5797,17 @@
     /* Undercurl: draw curl at the bottom of the character cell. */
     if (flags & DRAW_UNDERC)
     {
+#if GTK_CHECK_VERSION(3,0,0)
+	cairo_set_line_width(cr, 1.0);
+	cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
+	set_cairo_source_rgb_from_pixel(cr, gui.spcolor->pixel);
+	for (i = FILL_X(col); i < FILL_X(col + cells); ++i)
+	{
+	    offset = val[i % 8];
+	    cairo_line_to(cr, i, y - offset + 0.5);
+	}
+	cairo_stroke(cr);
+#else
 	gdk_gc_set_foreground(gui.text_gc, gui.spcolor);
 	for (i = FILL_X(col); i < FILL_X(col + cells); ++i)
 	{
@@ -4895,6 +5815,7 @@
 	    gdk_draw_point(gui.drawarea->window, gui.text_gc, i, y - offset);
 	}
 	gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
+#endif
     }
 
     /* Underline: draw a line at the bottom of the character cell. */
@@ -4904,9 +5825,20 @@
 	 * Otherwise put the line just below the character. */
 	if (p_linespace > 1)
 	    y -= p_linespace - 1;
+#if GTK_CHECK_VERSION(3,0,0)
+	{
+	    cairo_set_line_width(cr, 1.0);
+	    cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
+	    set_cairo_source_rgb_from_pixel(cr, gui.fgcolor->pixel);
+	    cairo_move_to(cr, FILL_X(col), y + 0.5);
+	    cairo_line_to(cr, FILL_X(col + cells), y + 0.5);
+	    cairo_stroke(cr);
+	}
+#else
 	gdk_draw_line(gui.drawarea->window, gui.text_gc,
 		      FILL_X(col), y,
 		      FILL_X(col + cells) - 1, y);
+#endif
     }
 }
 
@@ -4922,8 +5854,15 @@
     int			convlen;
     char_u		*sp, *bp;
     int			plen;
+#if GTK_CHECK_VERSION(3,0,0)
+    cairo_t		*cr;
+#endif
 
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gui.text_context == NULL || gtk_widget_get_window(gui.drawarea) == NULL)
+#else
     if (gui.text_context == NULL || gui.drawarea->window == NULL)
+#endif
 	return len;
 
     if (output_conv.vc_type != CONV_NONE)
@@ -4976,8 +5915,14 @@
     area.width	= gui.num_cols * gui.char_width;
     area.height = gui.char_height;
 
+#if GTK_CHECK_VERSION(3,0,0)
+    cr = cairo_create(gui.surface);
+    cairo_rectangle(cr, area.x, area.y, area.width, area.height);
+    cairo_clip(cr);
+#else
     gdk_gc_set_clip_origin(gui.text_gc, 0, 0);
     gdk_gc_set_clip_rectangle(gui.text_gc, &area);
+#endif
 
     glyphs = pango_glyph_string_new();
 
@@ -5004,7 +5949,11 @@
 	    glyphs->log_clusters[i] = i;
 	}
 
+#if GTK_CHECK_VERSION(3,0,0)
+	draw_glyph_string(row, col, len, flags, gui.ascii_font, glyphs, cr);
+#else
 	draw_glyph_string(row, col, len, flags, gui.ascii_font, glyphs);
+#endif
 
 	column_offset = len;
     }
@@ -5162,8 +6111,14 @@
 	    }
 
 	    /*** Aaaaand action! ***/
+#if GTK_CHECK_VERSION(3,0,0)
+	    draw_glyph_string(row, col + column_offset, item_cells,
+			      flags, item->analysis.font, glyphs,
+			      cr);
+#else
 	    draw_glyph_string(row, col + column_offset, item_cells,
 			      flags, item->analysis.font, glyphs);
+#endif
 
 	    pango_item_free(item);
 
@@ -5175,12 +6130,23 @@
 
 skipitall:
     /* Draw underline and undercurl. */
+#if GTK_CHECK_VERSION(3,0,0)
+    draw_under(flags, row, col, column_offset, cr);
+#else
     draw_under(flags, row, col, column_offset);
+#endif
 
     pango_glyph_string_free(glyphs);
     vim_free(conv_buf);
 
+#if GTK_CHECK_VERSION(3,0,0)
+    cairo_destroy(cr);
+    if (!gui.by_signal)
+	gdk_window_invalidate_rect(gtk_widget_get_window(gui.drawarea),
+		&area, FALSE);
+#else
     gdk_gc_set_clip_rectangle(gui.text_gc, NULL);
+#endif
 
     return column_offset;
 }
@@ -5207,10 +6173,19 @@
     int
 gui_get_x11_windis(Window *win, Display **dis)
 {
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gui.mainwin != NULL && gtk_widget_get_window(gui.mainwin) != NULL)
+#else
     if (gui.mainwin != NULL && gui.mainwin->window != NULL)
+#endif
     {
+#if GTK_CHECK_VERSION(3,0,0)
+	*dis = GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin));
+	*win = GDK_WINDOW_XID(gtk_widget_get_window(gui.mainwin));
+#else
 	*dis = GDK_WINDOW_XDISPLAY(gui.mainwin->window);
 	*win = GDK_WINDOW_XWINDOW(gui.mainwin->window);
+#endif
 	return OK;
     }
 
@@ -5226,8 +6201,13 @@
     Display *
 gui_mch_get_display(void)
 {
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gui.mainwin != NULL && gtk_widget_get_window(gui.mainwin) != NULL)
+	return GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin));
+#else
     if (gui.mainwin != NULL && gui.mainwin->window != NULL)
 	return GDK_WINDOW_XDISPLAY(gui.mainwin->window);
+#endif
     else
 	return NULL;
 }
@@ -5239,7 +6219,11 @@
 #ifdef HAVE_GTK_MULTIHEAD
     GdkDisplay *display;
 
+# if GTK_CHECK_VERSION(3,0,0)
+    if (gui.mainwin != NULL && gtk_widget_get_realized(gui.mainwin))
+# else
     if (gui.mainwin != NULL && GTK_WIDGET_REALIZED(gui.mainwin))
+# endif
 	display = gtk_widget_get_display(gui.mainwin);
     else
 	display = gdk_display_get_default();
@@ -5254,6 +6238,10 @@
     void
 gui_mch_flash(int msec)
 {
+#if GTK_CHECK_VERSION(3,0,0)
+    /* TODO Replace GdkGC with Cairo */
+    (void)msec;
+#else
     GdkGCValues	values;
     GdkGC	*invert_gc;
 
@@ -5293,6 +6281,7 @@
 		       FILL_Y((int)Rows) + gui.border_offset);
 
     gdk_gc_destroy(invert_gc);
+#endif
 }
 
 /*
@@ -5301,6 +6290,10 @@
     void
 gui_mch_invert_rectangle(int r, int c, int nr, int nc)
 {
+#if GTK_CHECK_VERSION(3,0,0)
+    /* TODO Replace GdkGC with Cairo */
+    (void)r; (void)c; (void)nr; (void)nc;
+#else
     GdkGCValues values;
     GdkGC *invert_gc;
 
@@ -5322,6 +6315,7 @@
 		       FILL_X(c), FILL_Y(r),
 		       (nc) * gui.char_width, (nr) * gui.char_height);
     gdk_gc_destroy(invert_gc);
+#endif
 }
 
 /*
@@ -5351,19 +6345,44 @@
 gui_mch_draw_hollow_cursor(guicolor_T color)
 {
     int		i = 1;
+#if GTK_CHECK_VERSION(3,0,0)
+    cairo_t    *cr;
+#endif
 
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_widget_get_window(gui.drawarea) == NULL)
+#else
     if (gui.drawarea->window == NULL)
+#endif
 	return;
 
+#if GTK_CHECK_VERSION(3,0,0)
+    cr = cairo_create(gui.surface);
+#endif
+
     gui_mch_set_fg_color(color);
 
+#if GTK_CHECK_VERSION(3,0,0)
+    set_cairo_source_rgb_from_pixel(cr, gui.fgcolor->pixel);
+#else
     gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
+#endif
     if (mb_lefthalve(gui.row, gui.col))
 	i = 2;
+#if GTK_CHECK_VERSION(3,0,0)
+    cairo_set_line_width(cr, 1.0);
+    cairo_set_line_cap(cr, CAIRO_LINE_CAP_BUTT);
+    cairo_rectangle(cr,
+	    FILL_X(gui.col) + 0.5, FILL_Y(gui.row) + 0.5,
+	    i * gui.char_width - 1, gui.char_height - 1);
+    cairo_stroke(cr);
+    cairo_destroy(cr);
+#else
     gdk_draw_rectangle(gui.drawarea->window, gui.text_gc,
 	    FALSE,
 	    FILL_X(gui.col), FILL_Y(gui.row),
 	    i * gui.char_width - 1, gui.char_height - 1);
+#endif
 }
 
 /*
@@ -5373,21 +6392,43 @@
     void
 gui_mch_draw_part_cursor(int w, int h, guicolor_T color)
 {
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_widget_get_window(gui.drawarea) == NULL)
+#else
     if (gui.drawarea->window == NULL)
+#endif
 	return;
 
     gui_mch_set_fg_color(color);
 
+#if GTK_CHECK_VERSION(3,0,0)
+    {
+	cairo_t *cr;
+
+	cr = cairo_create(gui.surface);
+	set_cairo_source_rgb_from_pixel(cr, gui.fgcolor->pixel);
+	cairo_rectangle(cr,
+# ifdef FEAT_RIGHTLEFT
+	    /* vertical line should be on the right of current point */
+	    CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
+# endif
+	    FILL_X(gui.col), FILL_Y(gui.row) + gui.char_height - h,
+	    w, h);
+	cairo_fill(cr);
+	cairo_destroy(cr);
+    }
+#else /* !GTK_CHECK_VERSION(3,0,0) */
     gdk_gc_set_foreground(gui.text_gc, gui.fgcolor);
     gdk_draw_rectangle(gui.drawarea->window, gui.text_gc,
 	    TRUE,
-#ifdef FEAT_RIGHTLEFT
+# ifdef FEAT_RIGHTLEFT
 	    /* vertical line should be on the right of current point */
 	    CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
-#endif
+# endif
 	    FILL_X(gui.col),
 	    FILL_Y(gui.row) + gui.char_height - h,
 	    w, h);
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
 }
 
 
@@ -5404,7 +6445,11 @@
 	g_main_context_iteration(NULL, TRUE);
 }
 
+#if GTK_CHECK_VERSION(3,0,0)
+    static gboolean
+#else
     static gint
+#endif
 input_timer_cb(gpointer data)
 {
     int *timed_out = (int *) data;
@@ -5473,7 +6518,11 @@
      * time */
 
     if (wtime > 0)
+#if GTK_CHECK_VERSION(3,0,0)
+	timer = g_timeout_add((guint)wtime, input_timer_cb, &timed_out);
+#else
 	timer = gtk_timeout_add((guint32)wtime, input_timer_cb, &timed_out);
+#endif
     else
 	timer = 0;
 
@@ -5507,7 +6556,11 @@
 	if (input_available())
 	{
 	    if (timer != 0 && !timed_out)
+#if GTK_CHECK_VERSION(3,0,0)
+		g_source_remove(timer);
+#else
 		gtk_timeout_remove(timer);
+#endif
 	    return OK;
 	}
     } while (wtime < 0 || !timed_out);
@@ -5531,15 +6584,24 @@
 gui_mch_flush(void)
 {
 #ifdef HAVE_GTK_MULTIHEAD
+# if GTK_CHECK_VERSION(3,0,0)
+    if (gui.mainwin != NULL && gtk_widget_get_realized(gui.mainwin))
+# else
     if (gui.mainwin != NULL && GTK_WIDGET_REALIZED(gui.mainwin))
+# endif
 	gdk_display_sync(gtk_widget_get_display(gui.mainwin));
 #else
     gdk_flush(); /* historical misnomer: calls XSync(), not XFlush() */
 #endif
     /* This happens to actually do what gui_mch_flush() is supposed to do,
      * according to the comment above. */
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gui.drawarea != NULL && gtk_widget_get_window(gui.drawarea) != NULL)
+	gdk_window_process_updates(gtk_widget_get_window(gui.drawarea), FALSE);
+#else
     if (gui.drawarea != NULL && gui.drawarea->window != NULL)
 	gdk_window_process_updates(gui.drawarea->window, FALSE);
+#endif
 }
 
 /*
@@ -5549,13 +6611,42 @@
     void
 gui_mch_clear_block(int row1, int col1, int row2, int col2)
 {
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_widget_get_window(gui.drawarea) == NULL)
+	return;
+#else
     GdkColor color;
 
     if (gui.drawarea->window == NULL)
 	return;
 
     color.pixel = gui.back_pixel;
+#endif
 
+#if GTK_CHECK_VERSION(3,0,0)
+    {
+	/* Add one pixel to the far right column in case a double-stroked
+	 * bold glyph may sit there. */
+	const GdkRectangle rect = {
+	    FILL_X(col1), FILL_Y(row1),
+	    (col2 - col1 + 1) * gui.char_width + (col2 == Columns - 1),
+	    (row2 - row1 + 1) * gui.char_height
+	};
+	GdkWindow * const win = gtk_widget_get_window(gui.drawarea);
+	cairo_t * const cr = cairo_create(gui.surface);
+	cairo_pattern_t * const pat = gdk_window_get_background_pattern(win);
+	if (pat != NULL)
+	    cairo_set_source(cr, pat);
+	else
+	    set_cairo_source_rgb_from_pixel(cr, gui.back_pixel);
+	gdk_cairo_rectangle(cr, &rect);
+	cairo_fill(cr);
+	cairo_destroy(cr);
+
+	if (!gui.by_signal)
+	    gdk_window_invalidate_rect(win, &rect, FALSE);
+    }
+#else /* !GTK_CHECK_VERSION(3,0,0) */
     gdk_gc_set_foreground(gui.text_gc, &color);
 
     /* Clear one extra pixel at the far right, for when bold characters have
@@ -5565,15 +6656,44 @@
 		       (col2 - col1 + 1) * gui.char_width
 						      + (col2 == Columns - 1),
 		       (row2 - row1 + 1) * gui.char_height);
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
 }
 
+#if GTK_CHECK_VERSION(3,0,0)
+    static void
+gui_gtk_window_clear(GdkWindow *win)
+{
+    const GdkRectangle rect = {
+	0, 0, gdk_window_get_width(win), gdk_window_get_height(win)
+    };
+    cairo_t * const cr = cairo_create(gui.surface);
+    cairo_pattern_t * const pat = gdk_window_get_background_pattern(win);
+    if (pat != NULL)
+	cairo_set_source(cr, pat);
+    else
+	set_cairo_source_rgb_from_pixel(cr, gui.back_pixel);
+    gdk_cairo_rectangle(cr, &rect);
+    cairo_fill(cr);
+    cairo_destroy(cr);
+
+    if (!gui.by_signal)
+	gdk_window_invalidate_rect(win, &rect, FALSE);
+}
+#endif
+
     void
 gui_mch_clear_all(void)
 {
+#if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_widget_get_window(gui.drawarea) != NULL)
+	gui_gtk_window_clear(gtk_widget_get_window(gui.drawarea));
+#else
     if (gui.drawarea->window != NULL)
 	gdk_window_clear(gui.drawarea->window);
+#endif
 }
 
+#if !GTK_CHECK_VERSION(3,0,0)
 /*
  * Redraw any text revealed by scrolling up/down.
  */
@@ -5610,6 +6730,27 @@
 
     gui_can_update_cursor();
 }
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
+
+#if GTK_CHECK_VERSION(3,0,0)
+    static void
+gui_gtk_surface_copy_rect(int dest_x, int dest_y,
+			  int src_x,  int src_y,
+			  int width,  int height)
+{
+    cairo_t * const cr = cairo_create(gui.surface);
+
+    cairo_rectangle(cr, dest_x, dest_y, width, height);
+    cairo_clip(cr);
+    cairo_push_group(cr);
+    cairo_set_source_surface(cr, gui.surface, dest_x - src_x, dest_y - src_y);
+    cairo_paint(cr);
+    cairo_pop_group_to_source(cr);
+    cairo_paint(cr);
+
+    cairo_destroy(cr);
+}
+#endif
 
 /*
  * Delete the given number of lines from the given row, scrolling up any
@@ -5618,6 +6759,26 @@
     void
 gui_mch_delete_lines(int row, int num_lines)
 {
+#if GTK_CHECK_VERSION(3,0,0)
+    const int ncols = gui.scroll_region_right - gui.scroll_region_left + 1;
+    const int nrows = gui.scroll_region_bot - row + 1;
+    const int src_nrows = nrows - num_lines;
+
+    gui_gtk_surface_copy_rect(
+	    FILL_X(gui.scroll_region_left), FILL_Y(row),
+	    FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines),
+	    gui.char_width * ncols + 1,     gui.char_height * src_nrows);
+    gui_clear_block(
+	    gui.scroll_region_bot - num_lines + 1, gui.scroll_region_left,
+	    gui.scroll_region_bot,		   gui.scroll_region_right);
+    gui_gtk3_redraw(
+	    FILL_X(gui.scroll_region_left), FILL_Y(row),
+	    gui.char_width * ncols + 1,     gui.char_height * nrows);
+    if (!gui.by_signal)
+	gtk_widget_queue_draw_area(gui.drawarea,
+		FILL_X(gui.scroll_region_left), FILL_Y(row),
+		gui.char_width * ncols + 1,	gui.char_height * nrows);
+#else
     if (gui.visibility == GDK_VISIBILITY_FULLY_OBSCURED)
 	return;			/* Can't see the window */
 
@@ -5638,6 +6799,7 @@
 						       gui.scroll_region_left,
 		    gui.scroll_region_bot, gui.scroll_region_right);
     check_copy_area();
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
 }
 
 /*
@@ -5647,6 +6809,26 @@
     void
 gui_mch_insert_lines(int row, int num_lines)
 {
+#if GTK_CHECK_VERSION(3,0,0)
+    const int ncols = gui.scroll_region_right - gui.scroll_region_left + 1;
+    const int nrows = gui.scroll_region_bot - row + 1;
+    const int src_nrows = nrows - num_lines;
+
+    gui_gtk_surface_copy_rect(
+	    FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines),
+	    FILL_X(gui.scroll_region_left), FILL_Y(row),
+	    gui.char_width * ncols + 1,     gui.char_height * src_nrows);
+    gui_mch_clear_block(
+	    row,		 gui.scroll_region_left,
+	    row + num_lines - 1, gui.scroll_region_right);
+    gui_gtk3_redraw(
+	    FILL_X(gui.scroll_region_left), FILL_Y(row),
+	    gui.char_width * ncols + 1,     gui.char_height * nrows);
+    if (!gui.by_signal)
+	gtk_widget_queue_draw_area(gui.drawarea,
+		FILL_X(gui.scroll_region_left), FILL_Y(row),
+		gui.char_width * ncols + 1,	gui.char_height * nrows);
+#else
     if (gui.visibility == GDK_VISIBILITY_FULLY_OBSCURED)
 	return;			/* Can't see the window */
 
@@ -5665,6 +6847,7 @@
     gui_clear_block(row, gui.scroll_region_left,
 				row + num_lines - 1, gui.scroll_region_right);
     check_copy_area();
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
 }
 
 /*
@@ -5700,7 +6883,12 @@
     }
 
     /* Final fallback position - use the X CUT_BUFFER0 store */
+#if GTK_CHECK_VERSION(3,0,0)
+    yank_cut_buffer0(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin)),
+	    cbd);
+#else
     yank_cut_buffer0(GDK_WINDOW_XDISPLAY(gui.mainwin->window), cbd);
+#endif
 }
 
 /*
@@ -5758,7 +6946,11 @@
 
     gui_mch_menu_hidden(menu, FALSE);
     /* Be clever about bitfields versus true booleans here! */
+# if GTK_CHECK_VERSION(3,0,0)
+    if (!gtk_widget_get_sensitive(menu->id) == !grey)
+# else
     if (!GTK_WIDGET_SENSITIVE(menu->id) == !grey)
+# endif
     {
 	gtk_widget_set_sensitive(menu->id, !grey);
 	gui_mch_update();
@@ -5776,7 +6968,11 @@
 
     if (hidden)
     {
+# if GTK_CHECK_VERSION(3,0,0)
+	if (gtk_widget_get_visible(menu->id))
+# else
 	if (GTK_WIDGET_VISIBLE(menu->id))
+# endif
 	{
 	    gtk_widget_hide(menu->id);
 	    gui_mch_update();
@@ -5784,7 +6980,11 @@
     }
     else
     {
+# if GTK_CHECK_VERSION(3,0,0)
+	if (!gtk_widget_get_visible(menu->id))
+# else
 	if (!GTK_WIDGET_VISIBLE(menu->id))
+# endif
 	{
 	    gtk_widget_show(menu->id);
 	    gui_mch_update();
@@ -5812,10 +7012,14 @@
     if (sb->id == NULL)
 	return;
 
+#if GTK_CHECK_VERSION(3,0,0)
+    gtk_widget_set_visible(sb->id, flag);
+#else
     if (flag)
 	gtk_widget_show(sb->id);
     else
 	gtk_widget_hide(sb->id);
+#endif
 
     update_window_manager_hints(0, 0);
 }
@@ -5828,8 +7032,18 @@
 gui_mch_get_rgb(guicolor_T pixel)
 {
     GdkColor color;
+#if GTK_CHECK_VERSION(3,0,0)
+    GdkRGBA rgba;
+
+    gui_gtk_get_rgb_from_pixel(pixel, &rgba);
+
+    color.red = rgba.red * 65535;
+    color.green = rgba.green * 65535;
+    color.blue = rgba.blue * 65535;
+#else
     gdk_colormap_query_color(gtk_widget_get_colormap(gui.drawarea),
 			     (unsigned long)pixel, &color);
+#endif
 
     return (((unsigned)color.red   & 0xff00) << 8)
 	 |  ((unsigned)color.green & 0xff00)
@@ -5842,7 +7056,11 @@
     void
 gui_mch_getmouse(int *x, int *y)
 {
+#if GTK_CHECK_VERSION(3,0,0)
+    gui_gtk_get_pointer(gui.drawarea, x, y, NULL);
+#else
     gdk_window_get_pointer(gui.drawarea->window, x, y, NULL);
+#endif
 }
 
     void
@@ -5851,9 +7069,15 @@
     /* Sorry for the Xlib call, but we can't avoid it, since there is no
      * internal GDK mechanism present to accomplish this.  (and for good
      * reason...) */
+#if GTK_CHECK_VERSION(3,0,0)
+    XWarpPointer(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.drawarea)),
+		 (Window)0, GDK_WINDOW_XID(gtk_widget_get_window(gui.drawarea)),
+		 0, 0, 0U, 0U, x, y);
+#else
     XWarpPointer(GDK_WINDOW_XDISPLAY(gui.drawarea->window),
 		 (Window)0, GDK_WINDOW_XWINDOW(gui.drawarea->window),
 		 0, 0, 0U, 0U, x, y);
+#endif
 }
 
 
@@ -5874,10 +7098,19 @@
     if (gui.pointer_hidden != hide)
     {
 	gui.pointer_hidden = hide;
+#if GTK_CHECK_VERSION(3,0,0)
+	if (gtk_widget_get_window(gui.drawarea) && gui.blank_pointer != NULL)
+#else
 	if (gui.drawarea->window && gui.blank_pointer != NULL)
+#endif
 	{
 	    if (hide)
+#if GTK_CHECK_VERSION(3,0,0)
+		gdk_window_set_cursor(gtk_widget_get_window(gui.drawarea),
+			gui.blank_pointer);
+#else
 		gdk_window_set_cursor(gui.drawarea->window, gui.blank_pointer);
+#endif
 	    else
 #ifdef FEAT_MOUSESHAPE
 		mch_set_mouse_shape(last_shape);
@@ -5919,11 +7152,20 @@
     int		   id;
     GdkCursor	   *c;
 
+# if GTK_CHECK_VERSION(3,0,0)
+    if (gtk_widget_get_window(gui.drawarea) == NULL)
+# else
     if (gui.drawarea->window == NULL)
+# endif
 	return;
 
     if (shape == MSHAPE_HIDE || gui.pointer_hidden)
+# if GTK_CHECK_VERSION(3,0,0)
+	gdk_window_set_cursor(gtk_widget_get_window(gui.drawarea),
+		gui.blank_pointer);
+# else
 	gdk_window_set_cursor(gui.drawarea->window, gui.blank_pointer);
+# endif
     else
     {
 	if (shape >= MSHAPE_NUMBERED)
@@ -5944,8 +7186,16 @@
 # else
 	c = gdk_cursor_new((GdkCursorType)id);
 # endif
+# if GTK_CHECK_VERSION(3,0,0)
+	gdk_window_set_cursor(gtk_widget_get_window(gui.drawarea), c);
+# else
 	gdk_window_set_cursor(gui.drawarea->window, c);
+# endif
+# if GTK_CHECK_VERSION(3,0,0)
+	g_object_unref(G_OBJECT(c));
+# else
 	gdk_cursor_destroy(c); /* Unref, actually.  Bloody GTK+ 1. */
+# endif
     }
     if (shape != MSHAPE_HIDE)
 	last_shape = shape;
@@ -5972,7 +7222,12 @@
 
     sign = (GdkPixbuf *)sign_get_image(typenr);
 
+# if GTK_CHECK_VERSION(3,0,0)
+    if (sign != NULL && gui.drawarea != NULL
+	    && gtk_widget_get_window(gui.drawarea) != NULL)
+# else
     if (sign != NULL && gui.drawarea != NULL && gui.drawarea->window != NULL)
+# endif
     {
 	int width;
 	int height;
@@ -6036,6 +7291,49 @@
 	xoffset = (width  - SIGN_WIDTH)  / 2;
 	yoffset = (height - SIGN_HEIGHT) / 2;
 
+# if GTK_CHECK_VERSION(3,0,0)
+	{
+	    cairo_t	    *cr;
+	    cairo_surface_t *bg_surf;
+	    cairo_t	    *bg_cr;
+	    cairo_surface_t *sign_surf;
+	    cairo_t	    *sign_cr;
+
+	    cr = cairo_create(gui.surface);
+
+	    bg_surf = cairo_surface_create_similar(gui.surface,
+		    cairo_surface_get_content(gui.surface),
+		    SIGN_WIDTH, SIGN_HEIGHT);
+	    bg_cr = cairo_create(bg_surf);
+	    set_cairo_source_rgb_from_pixel(bg_cr, gui.bgcolor->pixel);
+	    cairo_paint(bg_cr);
+
+	    sign_surf = cairo_surface_create_similar(gui.surface,
+		    cairo_surface_get_content(gui.surface),
+		    SIGN_WIDTH, SIGN_HEIGHT);
+	    sign_cr = cairo_create(sign_surf);
+	    gdk_cairo_set_source_pixbuf(sign_cr, sign, -xoffset, -yoffset);
+	    cairo_paint(sign_cr);
+
+	    cairo_set_operator(sign_cr, CAIRO_OPERATOR_DEST_OVER);
+	    cairo_set_source_surface(sign_cr, bg_surf, 0, 0);
+	    cairo_paint(sign_cr);
+
+	    cairo_set_source_surface(cr, sign_surf, FILL_X(col), FILL_Y(row));
+	    cairo_paint(cr);
+
+	    cairo_destroy(sign_cr);
+	    cairo_surface_destroy(sign_surf);
+	    cairo_destroy(bg_cr);
+	    cairo_surface_destroy(bg_surf);
+	    cairo_destroy(cr);
+
+	    if (!gui.by_signal)
+		gtk_widget_queue_draw_area(gui.drawarea,
+			FILL_X(col), FILL_Y(col), width, height);
+
+	}
+# else /* !GTK_CHECK_VERSION(3,0,0) */
 	gdk_gc_set_foreground(gui.text_gc, gui.bgcolor);
 
 	gdk_draw_rectangle(gui.drawarea->window,
@@ -6058,6 +7356,7 @@
 					    127,
 					    GDK_RGB_DITHER_NORMAL,
 					    0, 0);
+# endif /* !GTK_CHECK_VERSION(3,0,0) */
 	if (need_scale)
 	    g_object_unref(sign);
     }