summaryrefslogtreecommitdiffstats
path: root/src/gui_gtk_x11.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-02-23 17:14:37 +0100
committerBram Moolenaar <Bram@vim.org>2016-02-23 17:14:37 +0100
commit9892189d2e7ab94b750f99e6da4cbfc3c8014517 (patch)
tree18634bacebb9e922feceff40c924cdc48550d7ac /src/gui_gtk_x11.c
parent6bd364e08461159ad3c153ffba4def5b896486a1 (diff)
patch 7.4.1402v7.4.1402
Problem: GTK 3 is not supported. Solution: Add GTK 3 support. (Kazunobu Kuriyama)
Diffstat (limited to 'src/gui_gtk_x11.c')
-rw-r--r--src/gui_gtk_x11.c1339
1 files changed, 1319 insertions, 20 deletions
diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c
index 9f6775fb8c..440b401ab1 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 @@ extern void bonobo_dock_item_set_behavior(BonoboDockItem *dock_item, BonoboDockI
# 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 @@ gui_mch_free_all(void)
}
#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 @@ visibility_event(GtkWidget *widget UNUSED,
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 @@ expose_event(GtkWidget *widget UNUSED,
return FALSE;
}
+#endif /* !GTK_CHECK_VERSION(3,0,0) */
#ifdef FEAT_CLIENTSERVER
/*
@@ -643,7 +736,11 @@ property_event(GtkWidget *widget,
{
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 @@ property_event(GtkWidget *widget,
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_ontime = 400;
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 @@ gui_mch_stop_blink(void)
{
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 @@ gui_mch_stop_blink(void)
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 @@ gui_mch_start_blink(void)
{
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 @@ enter_notify_event(GtkWidget *widget UNUSED,
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 @@ key_press_event(GtkWidget *widget UNUSED,
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 @@ key_press_event(GtkWidget *widget UNUSED,
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 @@ key_release_event(GtkWidget *widget UNUSED,
* 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 @@ selection_received_cb(GtkWidget *widget UNUSED,
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 @@ selection_received_cb(GtkWidget *widget UNUSED,
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 @@ selection_get_cb(GtkWidget *widget UNUSED,
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 @@ selection_get_cb(GtkWidget *widget UNUSED,
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 @@ selection_get_cb(GtkWidget *widget UNUSED,
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 @@ static int mouse_timed_out = TRUE;
/*
* 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 @@ mouse_click_timer_cb(gpointer data)
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 @@ process_motion_notify(int x, int y, GdkModifierType state)
/*
* 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 @@ process_motion_notify(int x, int y, GdkModifierType state)
/* 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 @@ process_motion_notify(int x, int y, GdkModifierType state)
/* 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 @@ motion_notify_event(GtkWidget *widget,
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 @@ button_press_event(GtkWidget *widget,
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 @@ button_press_event(GtkWidget *widget,
/* 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 @@ scroll_event(GtkWidget *widget,
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 @@ button_release_event(GtkWidget *widget UNUSED,
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 @@ drag_handle_uri_list(GdkDragContext *context,
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 @@ drag_handle_text(GdkDragContext *context,
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 @@ drag_data_received_cb(GtkWidget *widget,
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 @@ drag_data_received_cb(GtkWidget *widget,
/* 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 @@ setup_save_yourself(void)
Atom *existing_atoms = NULL;
int count = 0;
-#ifdef USE_XSMP
+# ifdef USE_XSMP
if (xsmp_icefd != -1)
{
/*
@@ -2264,16 +2575,25 @@ setup_save_yourself(void)
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 @@ setup_save_yourself(void)
{
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 @@ global_event_filter(GdkXEvent *xev,
* 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 @@ mainwin_realize(GtkWidget *widget UNUSED, gpointer data UNUSED)
#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 @@ mainwin_realize(GtkWidget *widget UNUSED, gpointer data UNUSED)
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 @@ mainwin_realize(GtkWidget *widget UNUSED, gpointer data UNUSED)
* 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 @@ mainwin_realize(GtkWidget *widget UNUSED, gpointer data UNUSED)
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 @@ mainwin_screen_changed_cb(GtkWidget *widget,
* 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 @@ mainwin_screen_changed_cb(GtkWidget *widget,
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 @@ drawarea_unrealize_cb(GtkWidget *widget UNUSED, gpointer data UNUSED)
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 @@ drawarea_style_set_cb(GtkWidget *widget UNUSED,
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 @@ get_item_dimensions(GtkWidget *widget, GtkOrientation orientation)
{
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 @@ get_item_dimensions(GtkWidget *widget, GtkOrientation orientation)
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 @@ icon_size_changed_foreach(GtkWidget *widget, gpointer user_data)
{
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 @@ icon_size_changed_foreach(GtkWidget *widget, gpointer user_data)
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 @@ set_toolbar_style(GtkToolbar *toolbar)
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 @@ set_toolbar_style(GtkToolbar *toolbar)
#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 @@ add_tabline_menu_item(GtkWidget *menu, char_u *text, int resp)
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 @@ on_tabline_menu(GtkWidget *widget, GdkEvent *event)
)
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 @@ on_tabline_menu(GtkWidget *widget, GdkEvent *event)
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 @@ gui_mch_show_tabline(int showit)
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
}