diff options
author | Bram Moolenaar <Bram@vim.org> | 2016-02-23 17:14:37 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2016-02-23 17:14:37 +0100 |
commit | 9892189d2e7ab94b750f99e6da4cbfc3c8014517 (patch) | |
tree | 18634bacebb9e922feceff40c924cdc48550d7ac /src/gui_gtk_x11.c | |
parent | 6bd364e08461159ad3c153ffba4def5b896486a1 (diff) | |
download | vim-git-9892189d2e7ab94b750f99e6da4cbfc3c8014517.tar.gz |
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.c | 1339 |
1 files changed, 1319 insertions, 20 deletions
diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c index 9f6775fb8..440b401ab 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 } gui_mch_update(); @@ -3023,12 +3555,19 @@ gui_mch_update_tabline(void) 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 @@ gui_mch_update_tabline(void) } 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 @@ gui_mch_update_tabline(void) 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 @@ gui_mch_update_tabline(void) 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 @@ gui_mch_set_curtab(int nr) 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 @@ gui_mch_init(void) #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 @@ gui_mch_init(void) #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_mch_init(void) 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 @@ gui_mch_init(void) 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 @@ gui_mch_init(void) * 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 @@ gui_mch_init(void) 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 @@ gui_mch_init(void) /* 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 @@ gui_mch_init(void) 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 @@ gui_mch_init(void) 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_mch_init(void) */ 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 @@ gui_mch_init(void) */ 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 @@ gui_mch_init(void) */ 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 @@ gui_mch_init(void) 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 @@ gui_mch_forked(void) } #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 @@ gui_mch_forked(void) 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 @@ form_configure_event(GtkWidget *widget UNUSED, * 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 @@ gui_mch_open(void) * 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 @@ gui_mch_open(void) * 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 @@ gui_mch_set_winpos(int x, int y) 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 @@ force_shell_resize_idle(gpointer data) 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 @@ force_shell_resize_idle(gpointer data) 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 @@ gui_mch_set_shellsize(int width, int height, 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 @@ gui_mch_enable_menu(int showit) 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 @@ gui_mch_show_toolbar(int showit) 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 @@ gui_mch_adjust_charheight(void) 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 @@ gui_mch_font_dialog(char_u *oldval) 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 @@ gui_mch_font_dialog(char_u *oldval) } } +#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 @@ gui_mch_font_dialog(char_u *oldval) { 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 @@ gui_mch_get_color(char_u *name) 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 @@ setup_zero_width_cluster(PangoItem *item, PangoGlyphInfo *glyph, 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 @@ draw_glyph_string(int row, int col, int num_cells, int flags, 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 @@ draw_glyph_string(int row, int col, int num_cells, int flags, 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 @@ draw_under(int flags, int row, int col, int cells) /* 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 @@ draw_under(int flags, int row, int col, int cells) 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 @@ draw_under(int flags, int row, int col, int cells) * 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 @@ gui_gtk2_draw_string(int row, int col, char_u *s, int len, int flags) 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 @@ gui_gtk2_draw_string(int row, int col, char_u *s, int len, int flags) 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 @@ gui_gtk2_draw_string(int row, int col, char_u *s, int len, int flags) 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 @@ not_ascii: } /*** 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 @@ not_ascii: 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 @@ gui_mch_haskey(char_u *name) 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 @@ gui_get_x11_windis(Window *win, Display **dis) 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 @@ gui_mch_beep(void) #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 @@ gui_mch_beep(void) 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 @@ gui_mch_flash(int msec) FILL_Y((int)Rows) + gui.border_offset); gdk_gc_destroy(invert_gc); +#endif } /* @@ -5301,6 +6290,10 @@ gui_mch_flash(int msec) 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 @@ gui_mch_invert_rectangle(int r, int c, int nr, int nc) 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_set_foreground(void) 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 @@ gui_mch_draw_hollow_cursor(guicolor_T color) 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 @@ gui_mch_update(void) 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 @@ gui_mch_wait_for_chars(long wtime) * 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 @@ gui_mch_wait_for_chars(long wtime) 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_wait_for_chars(long wtime) 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 @@ gui_mch_flush(void) 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 @@ gui_mch_clear_block(int row1, int col1, int row2, int col2) (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 @@ check_copy_area(void) 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 @@ check_copy_area(void) 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_mch_delete_lines(int row, int num_lines) 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 @@ gui_mch_delete_lines(int row, int num_lines) 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_mch_insert_lines(int row, int num_lines) 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 @@ clip_mch_request_selection(VimClipboard *cbd) } /* 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_grey(vimmenu_T *menu, int grey) 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 @@ gui_mch_menu_hidden(vimmenu_T *menu, int hidden) 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 @@ gui_mch_menu_hidden(vimmenu_T *menu, int hidden) } 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 @@ gui_mch_enable_scrollbar(scrollbar_T *sb, int flag) 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_enable_scrollbar(scrollbar_T *sb, int flag) 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 @@ gui_mch_get_rgb(guicolor_T pixel) 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 @@ gui_mch_setmouse(int x, int y) /* 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 @@ gui_mch_mousehide(int hide) 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 @@ mch_set_mouse_shape(int shape) 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 @@ mch_set_mouse_shape(int shape) # 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 @@ gui_mch_drawsign(int row, int col, int typenr) 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 @@ gui_mch_drawsign(int row, int col, int typenr) 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 @@ gui_mch_drawsign(int row, int col, int typenr) 127, GDK_RGB_DITHER_NORMAL, 0, 0); +# endif /* !GTK_CHECK_VERSION(3,0,0) */ if (need_scale) g_object_unref(sign); } |