diff options
-rw-r--r-- | runtime/doc/eval.txt | 1 | ||||
-rw-r--r-- | runtime/doc/gui.txt | 11 | ||||
-rw-r--r-- | runtime/doc/gui_x11.txt | 10 | ||||
-rwxr-xr-x | src/auto/configure | 264 | ||||
-rw-r--r-- | src/channel.c | 33 | ||||
-rw-r--r-- | src/config.h.in | 3 | ||||
-rw-r--r-- | src/configure.in | 78 | ||||
-rw-r--r-- | src/eval.c | 4 | ||||
-rw-r--r-- | src/gui.h | 7 | ||||
-rw-r--r-- | src/gui_beval.c | 163 | ||||
-rw-r--r-- | src/gui_beval.h | 6 | ||||
-rw-r--r-- | src/gui_gtk.c | 747 | ||||
-rw-r--r-- | src/gui_gtk_f.c | 390 | ||||
-rw-r--r-- | src/gui_gtk_f.h | 19 | ||||
-rw-r--r-- | src/gui_gtk_x11.c | 1339 | ||||
-rw-r--r-- | src/if_mzsch.c | 16 | ||||
-rw-r--r-- | src/mbyte.c | 23 | ||||
-rw-r--r-- | src/netbeans.c | 44 | ||||
-rw-r--r-- | src/structs.h | 2 | ||||
-rw-r--r-- | src/version.c | 14 |
20 files changed, 3087 insertions, 87 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index 022a5da7a..abc022d39 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -7315,6 +7315,7 @@ gui_athena Compiled with Athena GUI. gui_gnome Compiled with Gnome support (gui_gtk is also defined). gui_gtk Compiled with GTK+ GUI (any version). gui_gtk2 Compiled with GTK+ 2 GUI (gui_gtk is also defined). +gui_gtk3 Compiled with GTK+ 3 GUI (gui_gtk is also defined). gui_mac Compiled with Macintosh GUI. gui_motif Compiled with Motif GUI. gui_photon Compiled with Photon GUI. diff --git a/runtime/doc/gui.txt b/runtime/doc/gui.txt index d77976330..520eba910 100644 --- a/runtime/doc/gui.txt +++ b/runtime/doc/gui.txt @@ -25,7 +25,7 @@ Other GUI documentation: First you must make sure you actually have a version of Vim with the GUI code included. You can check this with the ":version" command, it says "with xxx -GUI", where "xxx" is X11-Motif, X11-Athena, Photon, GTK, GTK2, etc., or +GUI", where "xxx" is X11-Motif, X11-Athena, Photon, GTK2, GTK3, etc., or "MS-Windows 32 bit GUI version". How to start the GUI depends on the system used. Mostly you can run the @@ -514,11 +514,14 @@ a menu entry. Hit <Enter> to execute it. Hit <Esc> if you want to cancel. This does require the |+menu| feature enabled at compile time. *tear-off-menus* -GTK+ and Motif support Tear-off menus. These are sort of sticky menus or +GTK+ 2 and Motif support Tear-off menus. These are sort of sticky menus or pop-up menus that are present all the time. If the resizing does not work correctly, this may be caused by using something like "Vim*geometry" in the defaults. Use "Vim.geometry" instead. +As to GTK+ 3, tear-off menus have been deprecated since GTK+ 3.4. +Accordingly, they are disabled if gvim is linked against GTK+ 3.4 or later. + The Win32 GUI version emulates Motif's tear-off menus. Actually, a Motif user will spot the differences easily, but hopefully they're just as useful. You can also use the |:tearoff| command together with |hidden-menus| to create @@ -650,8 +653,8 @@ When no or zero priority is given, 500 is used. The priority for the PopUp menu is not used. The Help menu will be placed on the far right side of the menu bar on systems -which support this (Motif and GTK+). For GTK+ 2, this is not done anymore -because right-aligning the Help menu is now discouraged UI design. +which support this (Motif and GTK+). For GTK+ 2 and 3, this is not done +anymore because right-aligning the Help menu is now discouraged UI design. You can use a priority higher than 9999, to make it go after the Help menu, but that is non-standard and is discouraged. The highest possible priority is diff --git a/runtime/doc/gui_x11.txt b/runtime/doc/gui_x11.txt index f085e2f2c..605b998af 100644 --- a/runtime/doc/gui_x11.txt +++ b/runtime/doc/gui_x11.txt @@ -369,6 +369,16 @@ Write this in the file ~/.gtkrc and it will be used by GTK+. For GTK+ 2 you might have to use the file ~/.gtkrc-2.0 instead, depending on your distribution. +For GTK+ 3, an effect similar to the above can be obtained by adding the +following snippet of CSS code to $XDG_HOME_DIR/gtk-3.0/gtk.css (usually, +$HOME/.config/gtk-3.0/gtk.css): + > + .tooltip { + background-color: #ffffcc; + color: #000000; + } +< + Using Vim as a GTK+ plugin *gui-gtk-socketid* When the GTK+ version of Vim starts up normally, it creates its own top level diff --git a/src/auto/configure b/src/auto/configure index 69aec67c6..1b3b0c70f 100755 --- a/src/auto/configure +++ b/src/auto/configure @@ -821,6 +821,7 @@ with_x enable_gui enable_gtk2_check enable_gnome_check +enable_gtk3_check enable_motif_check enable_athena_check enable_nextaw_check @@ -1481,9 +1482,10 @@ Optional Features: --enable-hangulinput Include Hangul input support. --enable-xim Include XIM input support. --enable-fontset Include X fontset output support. - --enable-gui=OPTS X11 GUI default=auto OPTS=auto/no/gtk2/gnome2/motif/athena/neXtaw/photon/carbon + --enable-gui=OPTS X11 GUI default=auto OPTS=auto/no/gtk2/gnome2/gtk3/motif/athena/neXtaw/photon/carbon --enable-gtk2-check If auto-select GUI, check for GTK+ 2 default=yes --enable-gnome-check If GTK GUI, check for GNOME default=no + --enable-gtk3-check If auto-select GUI, check for GTK+ 3 default=yes --enable-motif-check If auto-select GUI, check for Motif default=yes --enable-athena-check If auto-select GUI, check for Athena default=yes --enable-nextaw-check If auto-select GUI, check for neXtaw default=yes @@ -4355,7 +4357,7 @@ fi if test "x$CARBON" = "xyes"; then - if test -z "$with_x" -a "X$enable_gui" != Xmotif -a "X$enable_gui" != Xathena -a "X$enable_gui" != Xgtk2; then + if test -z "$with_x" -a "X$enable_gui" != Xmotif -a "X$enable_gui" != Xathena -a "X$enable_gui" != Xgtk2 -a "X$enable_gui" != Xgtk3; then with_x=no fi fi @@ -8606,6 +8608,9 @@ $as_echo "GTK+ 2.x GUI support" >&6; } $as_echo "GNOME 2.x GUI support" >&6; } SKIP_GNOME= SKIP_GTK2=;; + gtk3) { $as_echo "$as_me:${as_lineno-$LINENO}: result: GTK+ 3.x GUI support" >&5 +$as_echo "GTK+ 3.x GUI support" >&6; } + SKIP_GTK3=;; motif) { $as_echo "$as_me:${as_lineno-$LINENO}: result: Motif GUI support" >&5 $as_echo "Motif GUI support" >&6; } SKIP_MOTIF=;; @@ -8657,6 +8662,23 @@ $as_echo "$enable_gnome_check" >&6; } fi fi +if test "x$SKIP_GTK3" != "xYES" -a "$enable_gui_canon" != "gtk3"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for GTK+ 3" >&5 +$as_echo_n "checking whether or not to look for GTK+ 3... " >&6; } + # Check whether --enable-gtk3-check was given. +if test "${enable_gtk3_check+set}" = set; then : + enableval=$enable_gtk3_check; +else + enable_gtk3_check="yes" +fi + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_gtk3_check" >&5 +$as_echo "$enable_gtk3_check" >&6; } + if test "x$enable_gtk3_check" = "xno"; then + SKIP_GTK3=YES + fi +fi + if test "x$SKIP_MOTIF" != "xYES" -a "$enable_gui_canon" != "motif"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether or not to look for Motif" >&5 $as_echo_n "checking whether or not to look for Motif... " >&6; } @@ -8831,13 +8853,13 @@ fi if test "X$GTK_CONFIG" != "Xno" -o "X$PKG_CONFIG" != "Xno"; then { - min_gtk_version=2.2.0 - { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5 -$as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; } no_gtk="" if (test "X$SKIP_GTK2" != "XYES" -a "X$PKG_CONFIG" != "Xno") \ && $PKG_CONFIG --exists gtk+-2.0; then { + min_gtk_version=2.2.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5 +$as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; } GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-2.0` GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-2.0` GTK_LIBS=`$PKG_CONFIG --libs gtk+-2.0` @@ -8848,6 +8870,23 @@ $as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; } gtk_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` } + elif (test "X$SKIP_GTK3" != "XYES" -a "X$PKG_CONFIG" != "Xno") \ + && $PKG_CONFIG --exists gtk+-3.0; then + { + min_gtk_version=2.2.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5 +$as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; } + + GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-3.0` + GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-3.0` + GTK_LIBS=`$PKG_CONFIG --libs gtk+-3.0` + gtk_major_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + gtk_minor_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + gtk_micro_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + } else no_gtk=yes fi @@ -8943,6 +8982,7 @@ $as_echo "no" >&6; } rm -f conf.gtktest if test "x$GTK_CFLAGS" != "x"; then + SKIP_GTK3=YES SKIP_ATHENA=YES SKIP_NEXTAW=YES SKIP_MOTIF=YES @@ -9044,6 +9084,218 @@ $as_echo "not found" >&6; } fi fi + +if test -z "$SKIP_GTK3"; then + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking --disable-gtktest argument" >&5 +$as_echo_n "checking --disable-gtktest argument... " >&6; } + # Check whether --enable-gtktest was given. +if test "${enable_gtktest+set}" = set; then : + enableval=$enable_gtktest; +else + enable_gtktest=yes +fi + + if test "x$enable_gtktest" = "xyes" ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test enabled" >&5 +$as_echo "gtk test enabled" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: gtk test disabled" >&5 +$as_echo "gtk test disabled" >&6; } + fi + + if test "X$PKG_CONFIG" = "X"; then + # Extract the first word of "pkg-config", so it can be a program name with args. +set dummy pkg-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if ${ac_cv_path_PKG_CONFIG+:} false; then : + $as_echo_n "(cached) " >&6 +else + case $PKG_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_PKG_CONFIG" && ac_cv_path_PKG_CONFIG="no" + ;; +esac +fi +PKG_CONFIG=$ac_cv_path_PKG_CONFIG +if test -n "$PKG_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5 +$as_echo "$PKG_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi + + if test "x$PKG_CONFIG" != "xno"; then + + if test "X$GTK_CONFIG" != "Xno" -o "X$PKG_CONFIG" != "Xno"; then + { + no_gtk="" + if (test "X$SKIP_GTK2" != "XYES" -a "X$PKG_CONFIG" != "Xno") \ + && $PKG_CONFIG --exists gtk+-2.0; then + { + min_gtk_version=3.0.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5 +$as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; } + GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-2.0` + GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-2.0` + GTK_LIBS=`$PKG_CONFIG --libs gtk+-2.0` + gtk_major_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + gtk_minor_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + gtk_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + } + elif (test "X$SKIP_GTK3" != "XYES" -a "X$PKG_CONFIG" != "Xno") \ + && $PKG_CONFIG --exists gtk+-3.0; then + { + min_gtk_version=3.0.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5 +$as_echo_n "checking for GTK - version >= $min_gtk_version... " >&6; } + + GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-3.0` + GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-3.0` + GTK_LIBS=`$PKG_CONFIG --libs gtk+-3.0` + gtk_major_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'` + gtk_minor_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'` + gtk_micro_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'` + } + else + no_gtk=yes + fi + + if test "x$enable_gtktest" = "xyes" -a "x$no_gtk" = "x"; then + { + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $GTK_CFLAGS" + LIBS="$LIBS $GTK_LIBS" + + rm -f conf.gtktest + if test "$cross_compiling" = yes; then : + echo $ac_n "cross compiling; assumed OK... $ac_c" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include <gtk/gtk.h> +#include <stdio.h> +#if STDC_HEADERS +# include <stdlib.h> +# include <stddef.h> +#endif + +int +main () +{ +int major, minor, micro; +char *tmp_version; + +system ("touch conf.gtktest"); + +/* HP/UX 9 (%@#!) writes to sscanf strings */ +tmp_version = g_strdup("$min_gtk_version"); +if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string\n", "$min_gtk_version"); + exit(1); + } + +if ((gtk_major_version > major) || + ((gtk_major_version == major) && (gtk_minor_version > minor)) || + ((gtk_major_version == major) && (gtk_minor_version == minor) && + (gtk_micro_version >= micro))) +{ + return 0; +} +return 1; +} + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + no_gtk=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + } + fi + if test "x$no_gtk" = x ; then + if test "x$enable_gtktest" = "xyes"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&5 +$as_echo "yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&6; } + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&5 +$as_echo "found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&6; } + fi + GUI_LIB_LOC="$GTK_LIBDIR" + GTK_LIBNAME="$GTK_LIBS" + GUI_INC_LOC="$GTK_CFLAGS" + else + { + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + GTK_CFLAGS="" + GTK_LIBS="" + : + } + fi + } + else + GTK_CFLAGS="" + GTK_LIBS="" + : + fi + + + rm -f conf.gtktest + + if test "x$GTK_CFLAGS" != "x"; then + SKIP_GTK2=YES + SKIP_GNOME=YES + SKIP_ATHENA=YES + SKIP_NEXTAW=YES + SKIP_MOTIF=YES + GUITYPE=GTK + + $as_echo "#define HAVE_GTK_MULTIHEAD 1" >>confdefs.h + + $as_echo "#define USE_GTK3 1" >>confdefs.h + + fi + fi +fi + if test "x$GUITYPE" = "xGTK"; then { $as_echo "$as_me:${as_lineno-$LINENO}: checking version of Gdk-Pixbuf" >&5 $as_echo_n "checking version of Gdk-Pixbuf... " >&6; } @@ -9546,7 +9798,7 @@ done fi -if test -z "$SKIP_ATHENA" -o -z "$SKIP_NEXTAW" -o -z "$SKIP_MOTIF" -o -z "$SKIP_GTK2"; then +if test -z "$SKIP_ATHENA" -o -z "$SKIP_NEXTAW" -o -z "$SKIP_MOTIF" -o -z "$SKIP_GTK2" -o -z "$SKIP_GTK3"; then cppflags_save=$CPPFLAGS CPPFLAGS="$CPPFLAGS $X_CFLAGS" for ac_header in X11/xpm.h X11/Sunkeysym.h diff --git a/src/channel.c b/src/channel.c index e9068fee5..c59758d85 100644 --- a/src/channel.c +++ b/src/channel.c @@ -361,6 +361,17 @@ messageFromNetbeans(XtPointer clientData, #endif #ifdef FEAT_GUI_GTK +# if GTK_CHECK_VERSION(3,0,0) + static gboolean +messageFromNetbeans(GIOChannel *unused1 UNUSED, + GIOCondition unused2 UNUSED, + gpointer clientData) +{ + channel_read_fd(GPOINTER_TO_INT(clientData)); + return TRUE; /* Return FALSE instead in case the event source is to + * be removed after this function returns. */ +} +# else static void messageFromNetbeans(gpointer clientData, gint unused1 UNUSED, @@ -368,6 +379,7 @@ messageFromNetbeans(gpointer clientData, { channel_read_fd((int)(long)clientData); } +# endif #endif static void @@ -388,12 +400,27 @@ channel_gui_register_one(channel_T *channel, int part) /* Tell gdk we are interested in being called when there * is input on the editor connection socket. */ if (channel->ch_part[part].ch_inputHandler == 0) +# if GTK_CHECK_VERSION(3,0,0) + { + GIOChannel *chnnl = g_io_channel_unix_new( + (gint)channel->ch_part[part].ch_fd); + + channel->ch_part[part].ch_inputHandler = g_io_add_watch( + chnnl, + G_IO_IN|G_IO_HUP|G_IO_ERR|G_IO_PRI, + messageFromNetbeans, + GINT_TO_POINTER(channel->ch_part[part].ch_fd)); + + g_io_channel_unref(chnnl); + } +# else channel->ch_part[part].ch_inputHandler = gdk_input_add( (gint)channel->ch_part[part].ch_fd, (GdkInputCondition) ((int)GDK_INPUT_READ + (int)GDK_INPUT_EXCEPTION), messageFromNetbeans, (gpointer)(long)channel->ch_part[part].ch_fd); +# endif # else # ifdef FEAT_GUI_W32 /* Tell Windows we are interested in receiving message when there @@ -457,7 +484,11 @@ channel_gui_unregister(channel_T *channel) # ifdef FEAT_GUI_GTK if (channel->ch_part[part].ch_inputHandler != 0) { +# if GTK_CHECK_VERSION(3,0,0) + g_source_remove(channel->ch_part[part].ch_inputHandler); +# else gdk_input_remove(channel->ch_part[part].ch_inputHandler); +# endif channel->ch_part[part].ch_inputHandler = 0; } # else @@ -606,7 +637,7 @@ channel_open( fd_set wfds; #if defined(__APPLE__) && __APPLE__ == 1 # define PASS_RFDS - fd_set rfds; + fd_set rfds; FD_ZERO(&rfds); FD_SET(sd, &rfds); diff --git a/src/config.h.in b/src/config.h.in index 8e115f5f1..fd45c7332 100644 --- a/src/config.h.in +++ b/src/config.h.in @@ -460,3 +460,6 @@ /* Define if GResource is used to load icons */ #undef USE_GRESOURCE + +/* Define if GTK+ GUI is to be linked against GTK+ 3 */ +#undef USE_GTK3 diff --git a/src/configure.in b/src/configure.in index 9f19c137b..930278c7d 100644 --- a/src/configure.in +++ b/src/configure.in @@ -213,7 +213,7 @@ if test "`(uname) 2>/dev/null`" = Darwin; then dnl or Motif, Athena or GTK GUI is used. AC_CHECK_HEADER(Carbon/Carbon.h, CARBON=yes) if test "x$CARBON" = "xyes"; then - if test -z "$with_x" -a "X$enable_gui" != Xmotif -a "X$enable_gui" != Xathena -a "X$enable_gui" != Xgtk2; then + if test -z "$with_x" -a "X$enable_gui" != Xmotif -a "X$enable_gui" != Xathena -a "X$enable_gui" != Xgtk2 -a "X$enable_gui" != Xgtk3; then with_x=no fi fi @@ -2198,7 +2198,7 @@ test "x$with_x" = xno -a "x$MACOSX" != "xyes" -a "x$QNX" != "xyes" && enable_gui AC_MSG_CHECKING(--enable-gui argument) AC_ARG_ENABLE(gui, - [ --enable-gui[=OPTS] X11 GUI [default=auto] [OPTS=auto/no/gtk2/gnome2/motif/athena/neXtaw/photon/carbon]], , enable_gui="auto") + [ --enable-gui[=OPTS] X11 GUI [default=auto] [OPTS=auto/no/gtk2/gnome2/gtk3/motif/athena/neXtaw/photon/carbon]], , enable_gui="auto") dnl Canonicalize the --enable-gui= argument so that it can be easily compared. dnl Do not use character classes for portability with old tools. @@ -2256,6 +2256,8 @@ else gnome2) AC_MSG_RESULT(GNOME 2.x GUI support) SKIP_GNOME= SKIP_GTK2=;; + gtk3) AC_MSG_RESULT(GTK+ 3.x GUI support) + SKIP_GTK3=;; motif) AC_MSG_RESULT(Motif GUI support) SKIP_MOTIF=;; athena) AC_MSG_RESULT(Athena GUI support) @@ -2291,6 +2293,17 @@ if test "x$SKIP_GNOME" != "xYES" -a "$enable_gui_canon" != "gnome2"; then fi fi +if test "x$SKIP_GTK3" != "xYES" -a "$enable_gui_canon" != "gtk3"; then + AC_MSG_CHECKING(whether or not to look for GTK+ 3) + AC_ARG_ENABLE(gtk3-check, + [ --enable-gtk3-check If auto-select GUI, check for GTK+ 3 [default=yes]], + , enable_gtk3_check="yes") + AC_MSG_RESULT($enable_gtk3_check) + if test "x$enable_gtk3_check" = "xno"; then + SKIP_GTK3=YES + fi +fi + if test "x$SKIP_MOTIF" != "xYES" -a "$enable_gui_canon" != "motif"; then AC_MSG_CHECKING(whether or not to look for Motif) AC_ARG_ENABLE(motif-check, @@ -2379,12 +2392,12 @@ AC_DEFUN(AM_PATH_GTK, [ if test "X$GTK_CONFIG" != "Xno" -o "X$PKG_CONFIG" != "Xno"; then { - min_gtk_version=ifelse([$1], ,2.2.0,$1) - AC_MSG_CHECKING(for GTK - version >= $min_gtk_version) no_gtk="" if (test "X$SKIP_GTK2" != "XYES" -a "X$PKG_CONFIG" != "Xno") \ && $PKG_CONFIG --exists gtk+-2.0; then { + min_gtk_version=ifelse([$1], ,2.2.0,$1) + AC_MSG_CHECKING(for GTK - version >= $min_gtk_version) dnl We should be using PKG_CHECK_MODULES() instead of this hack. dnl But I guess the dependency on pkgconfig.m4 is not wanted or dnl something like that. @@ -2398,6 +2411,22 @@ AC_DEFUN(AM_PATH_GTK, gtk_micro_version=`$PKG_CONFIG --modversion gtk+-2.0 | \ sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` } + elif (test "X$SKIP_GTK3" != "XYES" -a "X$PKG_CONFIG" != "Xno") \ + && $PKG_CONFIG --exists gtk+-3.0; then + { + min_gtk_version=ifelse([$1], ,3.0.0,$1) + AC_MSG_CHECKING(for GTK - version >= $min_gtk_version) + + GTK_CFLAGS=`$PKG_CONFIG --cflags gtk+-3.0` + GTK_LIBDIR=`$PKG_CONFIG --libs-only-L gtk+-3.0` + GTK_LIBS=`$PKG_CONFIG --libs gtk+-3.0` + gtk_major_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\1/'` + gtk_minor_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\2/'` + gtk_micro_version=`$PKG_CONFIG --modversion gtk+-3.0 | \ + sed 's/\([[0-9]]*\)\.\([[0-9]]*\)\.\([[0-9]]*\)/\3/'` + } else no_gtk=yes fi @@ -2573,6 +2602,7 @@ if test -z "$SKIP_GTK2"; then GTK_LIBNAME="$GTK_LIBS" GUI_INC_LOC="$GTK_CFLAGS"], ) if test "x$GTK_CFLAGS" != "x"; then + SKIP_GTK3=YES SKIP_ATHENA=YES SKIP_NEXTAW=YES SKIP_MOTIF=YES @@ -2601,6 +2631,44 @@ if test -z "$SKIP_GTK2"; then fi fi + +dnl --------------------------------------------------------------------------- +dnl Check for GTK3. +dnl --------------------------------------------------------------------------- +if test -z "$SKIP_GTK3"; then + + AC_MSG_CHECKING(--disable-gtktest argument) + AC_ARG_ENABLE(gtktest, [ --disable-gtktest Do not try to compile and run a test GTK program], + , enable_gtktest=yes) + if test "x$enable_gtktest" = "xyes" ; then + AC_MSG_RESULT(gtk test enabled) + else + AC_MSG_RESULT(gtk test disabled) + fi + + if test "X$PKG_CONFIG" = "X"; then + AC_PATH_PROG(PKG_CONFIG, pkg-config, no) + fi + + if test "x$PKG_CONFIG" != "xno"; then + AM_PATH_GTK(3.0.0, + [GUI_LIB_LOC="$GTK_LIBDIR" + GTK_LIBNAME="$GTK_LIBS" + GUI_INC_LOC="$GTK_CFLAGS"], ) + if test "x$GTK_CFLAGS" != "x"; then + SKIP_GTK2=YES + SKIP_GNOME=YES + SKIP_ATHENA=YES + SKIP_NEXTAW=YES + SKIP_MOTIF=YES + GUITYPE=GTK + AC_SUBST(GTK_LIBNAME) + AC_DEFINE(HAVE_GTK_MULTIHEAD) + AC_DEFINE(USE_GTK3) + fi + fi +fi + dnl Check the version of Gdk-Pixbuf. If the version is 2.31 or later and dnl glib-compile-resources is found in PATH, use GResource. if test "x$GUITYPE" = "xGTK"; then @@ -2823,7 +2891,7 @@ if test "$enable_xsmp" = "yes"; then fi -if test -z "$SKIP_ATHENA" -o -z "$SKIP_NEXTAW" -o -z "$SKIP_MOTIF" -o -z "$SKIP_GTK2"; then +if test -z "$SKIP_ATHENA" -o -z "$SKIP_NEXTAW" -o -z "$SKIP_MOTIF" -o -z "$SKIP_GTK2" -o -z "$SKIP_GTK3"; then dnl Check for X11/xpm.h and X11/Sunkeysym.h with the GUI include path cppflags_save=$CPPFLAGS CPPFLAGS="$CPPFLAGS $X_CFLAGS" diff --git a/src/eval.c b/src/eval.c index 3b1172ecd..147156818 100644 --- a/src/eval.c +++ b/src/eval.c @@ -13671,7 +13671,11 @@ f_has(typval_T *argvars, typval_T *rettv) #endif #ifdef FEAT_GUI_GTK "gui_gtk", +# ifdef USE_GTK3 + "gui_gtk3", +# else "gui_gtk2", +# endif #endif #ifdef FEAT_GUI_GNOME "gui_gnome", @@ -359,7 +359,9 @@ typedef struct Gui #endif #ifdef FEAT_GUI_GTK +# ifndef USE_GTK3 int visibility; /* Is shell partially/fully obscured? */ +# endif GdkCursor *blank_pointer; /* Blank pointer */ /* X Resources */ @@ -381,7 +383,12 @@ typedef struct Gui GdkColor *fgcolor; /* GDK-styled foreground color */ GdkColor *bgcolor; /* GDK-styled background color */ GdkColor *spcolor; /* GDK-styled special color */ +# ifdef USE_GTK3 + cairo_surface_t *surface; /* drawarea surface */ + gboolean by_signal; /* cause of draw operation */ +# else GdkGC *text_gc; /* cached GC for normal text */ +# endif PangoContext *text_context; /* the context used for all text */ PangoFont *ascii_font; /* cached font for ASCII strings */ PangoGlyphString *ascii_glyphs; /* cached code point -> glyph map */ diff --git a/src/gui_beval.c b/src/gui_beval.c index e96e67d3f..258ba8aeb 100644 --- a/src/gui_beval.c +++ b/src/gui_beval.c @@ -122,7 +122,11 @@ general_beval_cb(BalloonEval *beval, int state UNUSED) #if !defined(FEAT_GUI_W32) || defined(PROTO) #ifdef FEAT_GUI_GTK -# include <gdk/gdkkeysyms.h> +# if GTK_CHECK_VERSION(3,0,0) +# include <gdk/gdkkeysyms-compat.h> +# else +# include <gdk/gdkkeysyms.h> +# endif # include <gtk/gtk.h> #else # include <X11/keysym.h> @@ -164,8 +168,16 @@ static gint target_event_cb(GtkWidget *, GdkEvent *, gpointer); static gint mainwin_event_cb(GtkWidget *, GdkEvent *, gpointer); static void pointer_event(BalloonEval *, int, int, unsigned); static void key_event(BalloonEval *, unsigned, int); +# if GTK_CHECK_VERSION(3,0,0) +static gboolean timeout_cb(gpointer); +# else static gint timeout_cb(gpointer); -static gint balloon_expose_event_cb(GtkWidget *, GdkEventExpose *, gpointer); +# endif +# if GTK_CHECK_VERSION(3,0,0) +static gboolean balloon_draw_event_cb (GtkWidget *, cairo_t *, gpointer); +# else +static gint balloon_expose_event_cb (GtkWidget *, GdkEventExpose *, gpointer); +# endif #else static void addEventHandler(Widget, BalloonEval *); static void removeEventHandler(BalloonEval *); @@ -459,10 +471,16 @@ addEventHandler(GtkWidget *target, BalloonEval *beval) * This allows us to catch events independently of the signal handlers * in gui_gtk_x11.c. */ +# if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(target), "event", + G_CALLBACK(target_event_cb), + beval); +# else /* Should use GTK_OBJECT() here, but that causes a lint warning... */ gtk_signal_connect((GtkObject*)(target), "event", GTK_SIGNAL_FUNC(target_event_cb), beval); +# endif /* * Nasty: Key press events go to the main window thus the drawing area * will never see them. This means we have to connect to the main window @@ -471,9 +489,15 @@ addEventHandler(GtkWidget *target, BalloonEval *beval) if (gtk_socket_id == 0 && gui.mainwin != NULL && gtk_widget_is_ancestor(target, gui.mainwin)) { +# if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(gui.mainwin), "event", + G_CALLBACK(mainwin_event_cb), + beval); +# else gtk_signal_connect((GtkObject*)(gui.mainwin), "event", GTK_SIGNAL_FUNC(mainwin_event_cb), beval); +# endif } } @@ -481,17 +505,29 @@ addEventHandler(GtkWidget *target, BalloonEval *beval) removeEventHandler(BalloonEval *beval) { /* LINTED: avoid warning: dubious operation on enum */ +# if GTK_CHECK_VERSION(3,0,0) + g_signal_handlers_disconnect_by_func(G_OBJECT(beval->target), + G_CALLBACK(target_event_cb), + beval); +# else gtk_signal_disconnect_by_func((GtkObject*)(beval->target), GTK_SIGNAL_FUNC(target_event_cb), beval); +# endif if (gtk_socket_id == 0 && gui.mainwin != NULL && gtk_widget_is_ancestor(beval->target, gui.mainwin)) { /* LINTED: avoid warning: dubious operation on enum */ +# if GTK_CHECK_VERSION(3,0,0) + g_signal_handlers_disconnect_by_func(G_OBJECT(gui.mainwin), + G_CALLBACK(mainwin_event_cb), + beval); +# else gtk_signal_disconnect_by_func((GtkObject*)(gui.mainwin), GTK_SIGNAL_FUNC(mainwin_event_cb), beval); +# endif } } @@ -517,7 +553,17 @@ target_event_cb(GtkWidget *widget, GdkEvent *event, gpointer data) * GDK_POINTER_MOTION_HINT_MASK is set, thus we cannot obtain * the coordinates from the GdkEventMotion struct directly. */ +# if GTK_CHECK_VERSION(3,0,0) + { + 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); + GdkDevice * const dev = gdk_device_manager_get_client_pointer(mngr); + gdk_window_get_device_position(win, dev , &x, &y, &state); + } +# else gdk_window_get_pointer(widget->window, &x, &y, &state); +# endif pointer_event(beval, x, y, (unsigned int)state); } else @@ -609,8 +655,13 @@ pointer_event(BalloonEval *beval, int x, int y, unsigned state) } else { +# if GTK_CHECK_VERSION(3,0,0) + beval->timerID = g_timeout_add((guint)p_bdlay, + &timeout_cb, beval); +# else beval->timerID = gtk_timeout_add((guint32)p_bdlay, &timeout_cb, beval); +# endif } } } @@ -647,7 +698,11 @@ key_event(BalloonEval *beval, unsigned keyval, int is_keypress) cancelBalloon(beval); } +# if GTK_CHECK_VERSION(3,0,0) + static gboolean +# else static gint +# endif timeout_cb(gpointer data) { BalloonEval *beval = (BalloonEval *)data; @@ -663,6 +718,37 @@ timeout_cb(gpointer data) return FALSE; /* don't call me again */ } +# if GTK_CHECK_VERSION(3,0,0) + static gboolean +balloon_draw_event_cb(GtkWidget *widget, + cairo_t *cr, + gpointer data UNUSED) +{ + GtkStyleContext *context = NULL; + gint width = -1, height = -1; + + if (widget == NULL) + return TRUE; + + context = gtk_widget_get_style_context(widget); + width = gtk_widget_get_allocated_width(widget); + height = gtk_widget_get_allocated_height(widget); + + gtk_style_context_save(context); + + gtk_style_context_add_class(context, "tooltip"); + gtk_style_context_set_state(context, GTK_STATE_FLAG_NORMAL); + + cairo_save(cr); + gtk_render_frame(context, cr, 0, 0, width, height); + gtk_render_background(context, cr, 0, 0, width, height); + cairo_restore(cr); + + gtk_style_context_restore(context); + + return FALSE; +} +# else static gint balloon_expose_event_cb(GtkWidget *widget, GdkEventExpose *event, @@ -675,6 +761,7 @@ balloon_expose_event_cb(GtkWidget *widget, return FALSE; /* continue emission */ } +# endif /* !GTK_CHECK_VERSION(3,0,0) */ #else /* !FEAT_GUI_GTK */ @@ -957,8 +1044,37 @@ set_printable_label_text(GtkLabel *label, char_u *text) aep = syn_gui_attr2entry(hl_attr(HLF_8)); pixel = (aep != NULL) ? aep->ae_u.gui.fg_color : INVALCOLOR; if (pixel != INVALCOLOR) +# if GTK_CHECK_VERSION(3,0,0) + { + GdkVisual * const visual = gtk_widget_get_visual(gui.drawarea); + + if (visual == NULL) + { + color.red = 0; + color.green = 0; + color.blue = 0; + } + else + { + guint32 r_mask, g_mask, b_mask; + gint r_shift, g_shift, b_shift; + + 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); + + color.red = ((pixel & r_mask) >> r_shift) / 255.0 * 65535; + color.green = ((pixel & g_mask) >> g_shift) / 255.0 * 65535; + color.blue = ((pixel & b_mask) >> b_shift) / 255.0 * 65535; + } + } +# else gdk_colormap_query_color(gtk_widget_get_colormap(gui.drawarea), (unsigned long)pixel, &color); +# endif pdest = buf; p = text; @@ -1059,8 +1175,10 @@ drawBalloon(BalloonEval *beval) screen_w = gdk_screen_width(); screen_h = gdk_screen_height(); # endif +# if !GTK_CHECK_VERSION(3,0,0) gtk_widget_ensure_style(beval->balloonShell); gtk_widget_ensure_style(beval->balloonLabel); +# endif set_printable_label_text(GTK_LABEL(beval->balloonLabel), beval->msg); /* @@ -1081,10 +1199,18 @@ drawBalloon(BalloonEval *beval) MAX(20, screen_w - 20))); /* Calculate the balloon's width and height. */ +# if GTK_CHECK_VERSION(3,0,0) + gtk_widget_get_preferred_size(beval->balloonShell, &requisition, NULL); +# else gtk_widget_size_request(beval->balloonShell, &requisition); +# endif /* Compute position of the balloon area */ +# if GTK_CHECK_VERSION(3,0,0) + gdk_window_get_origin(gtk_widget_get_window(beval->target), &x, &y); +# else gdk_window_get_origin(beval->target->window, &x, &y); +# endif x += beval->x; y += beval->y; @@ -1099,7 +1225,11 @@ drawBalloon(BalloonEval *beval) y = CLAMP(y + y_offset, 0, MAX(0, screen_h - requisition.height)); /* Show the balloon */ +# if GTK_CHECK_VERSION(3,0,0) + gtk_window_move(GTK_WINDOW(beval->balloonShell), x, y); +# else gtk_widget_set_uposition(beval->balloonShell, x, y); +# endif gtk_widget_show(beval->balloonShell); beval->showState = ShS_SHOWING; @@ -1126,7 +1256,11 @@ cancelBalloon(BalloonEval *beval) if (beval->timerID != 0) { +# if GTK_CHECK_VERSION(3,0,0) + g_source_remove(beval->timerID); +# else gtk_timeout_remove(beval->timerID); +# endif beval->timerID = 0; } beval->showState = ShS_NEUTRAL; @@ -1138,17 +1272,42 @@ createBalloonEvalWindow(BalloonEval *beval) beval->balloonShell = gtk_window_new(GTK_WINDOW_POPUP); gtk_widget_set_app_paintable(beval->balloonShell, TRUE); +# if GTK_CHECK_VERSION(3,0,0) + gtk_window_set_resizable(GTK_WINDOW(beval->balloonShell), FALSE); +# else gtk_window_set_policy(GTK_WINDOW(beval->balloonShell), FALSE, FALSE, TRUE); +# endif gtk_widget_set_name(beval->balloonShell, "gtk-tooltips"); +# if GTK_CHECK_VERSION(3,0,0) + gtk_container_set_border_width(GTK_CONTAINER(beval->balloonShell), 4); +# else gtk_container_border_width(GTK_CONTAINER(beval->balloonShell), 4); +# endif +# if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(beval->balloonShell), "draw", + G_CALLBACK(balloon_draw_event_cb), NULL); +# else gtk_signal_connect((GtkObject*)(beval->balloonShell), "expose_event", GTK_SIGNAL_FUNC(balloon_expose_event_cb), NULL); +# endif beval->balloonLabel = gtk_label_new(NULL); gtk_label_set_line_wrap(GTK_LABEL(beval->balloonLabel), FALSE); gtk_label_set_justify(GTK_LABEL(beval->balloonLabel), GTK_JUSTIFY_LEFT); +# if GTK_CHECK_VERSION(3,16,0) + gtk_label_set_xalign(GTK_LABEL(beval->balloonLabel), 0.5); + gtk_label_set_yalign(GTK_LABEL(beval->balloonLabel), 0.5); +# elif GTK_CHECK_VERSION(3,14,0) + GValue align_val = G_VALUE_INIT; + g_value_init(&align_val, G_TYPE_FLOAT); + g_value_set_float(&align_val, 0.5); + g_object_set_property(G_OBJECT(beval->balloonLabel), "xalign", &align_val); + g_object_set_property(G_OBJECT(beval->balloonLabel), "yalign", &align_val); + g_value_unset(&align_val); +# else gtk_misc_set_alignment(GTK_MISC(beval->balloonLabel), 0.5f, 0.5f); +# endif gtk_widget_set_name(beval->balloonLabel, "vim-balloon-label"); gtk_widget_show(beval->balloonLabel); diff --git a/src/gui_beval.h b/src/gui_beval.h index 859c08193..ead0fb172 100644 --- a/src/gui_beval.h +++ b/src/gui_beval.h @@ -11,7 +11,11 @@ #define GUI_BEVAL_H #ifdef FEAT_GUI_GTK -# include <gtk/gtkwidget.h> +# ifdef USE_GTK3 +# include <gtk/gtk.h> +# else +# include <gtk/gtkwidget.h> +# endif #else # if defined(FEAT_GUI_X11) # include <X11/Intrinsic.h> diff --git a/src/gui_gtk.c b/src/gui_gtk.c index 99e4d70df..6decec0df 100644 --- a/src/gui_gtk.c +++ b/src/gui_gtk.c @@ -22,8 +22,17 @@ * * Best supporting actor (He helped somewhat, aesthetically speaking): * Maxime Romano <verbophobe@hotmail.com> + * + * Support for GTK+ 3 was added by: + * + * 2016 Kazunobu Kuriyama <kazunobu.kuriyama@gmail.com> + * + * With the help of Marius Gedminas and the word of Bram Moolenaar, + * "Let's give this some time to mature." */ +#include "vim.h" + #ifdef FEAT_GUI_GTK # include "gui_gtk_f.h" #endif @@ -37,8 +46,6 @@ # undef MAX #endif -#include "vim.h" - #ifdef FEAT_GUI_GNOME /* Gnome redefines _() and N_(). Grrr... */ # ifdef _ @@ -63,7 +70,11 @@ #endif #ifdef FEAT_GUI_GTK -# include <gdk/gdkkeysyms.h> +# if GTK_CHECK_VERSION(3,0,0) +# include <gdk/gdkkeysyms-compat.h> +# else +# include <gdk/gdkkeysyms.h> +# endif # include <gdk/gdk.h> # ifdef WIN3264 # include <gdk/gdkwin32.h> @@ -104,6 +115,70 @@ static void recent_func_log_func( * match toolbar_names[] in menu.c! All stock icons including the "vim-*" * ones can be overridden in your gtkrc file. */ +# if GTK_CHECK_VERSION(3,10,0) +static const char * const menu_themed_names[] = +{ + /* 00 */ "document-new", /* sub. GTK_STOCK_NEW */ + /* 01 */ "document-open", /* sub. GTK_STOCK_OPEN */ + /* 02 */ "document-save", /* sub. GTK_STOCK_SAVE */ + /* 03 */ "edit-undo", /* sub. GTK_STOCK_UNDO */ + /* 04 */ "edit-redo", /* sub. GTK_STOCK_REDO */ + /* 05 */ "edit-cut", /* sub. GTK_STOCK_CUT */ + /* 06 */ "edit-copy", /* sub. GTK_STOCK_COPY */ + /* 07 */ "edit-paste", /* sub. GTK_STOCK_PASTE */ + /* 08 */ "document-print", /* sub. GTK_STOCK_PRINT */ + /* 09 */ "help-browser", /* sub. GTK_STOCK_HELP */ + /* 10 */ "edit-find", /* sub. GTK_STOCK_FIND */ +# if GTK_CHECK_VERSION(3,14,0) + /* Use the file names in gui_gtk_res.xml, cutting off the extension. + * Similar changes follow. */ + /* 11 */ "stock_vim_save_all", + /* 12 */ "stock_vim_session_save", + /* 13 */ "stock_vim_session_new", + /* 14 */ "stock_vim_session_load", +# else + /* 11 */ "vim-save-all", + /* 12 */ "vim-session-save", + /* 13 */ "vim-session-new", + /* 14 */ "vim-session-load", +# endif + /* 15 */ "system-run", /* sub. GTK_STOCK_EXECUTE */ + /* 16 */ "edit-find-replace", /* sub. GTK_STOCK_FIND_AND_REPLACE */ + /* 17 */ "window-close", /* sub. GTK_STOCK_CLOSE, FIXME: fuzzy */ +# if GTK_CHECK_VERSION(3,14,0) + /* 18 */ "stock_vim_window_maximize", + /* 19 */ "stock_vim_window_minimize", + /* 20 */ "stock_vim_window_split", + /* 21 */ "stock_vim_shell", +# else + /* 18 */ "vim-window-maximize", + /* 19 */ "vim-window-minimize", + /* 20 */ "vim-window-split", + /* 21 */ "vim-shell", +# endif + /* 22 */ "go-previous", /* sub. GTK_STOCK_GO_BACK */ + /* 23 */ "go-next", /* sub. GTK_STOCK_GO_FORWARD */ +# if GTK_CHECK_VERSION(3,14,0) + /* 24 */ "stock_vim_find_help", +# else + /* 24 */ "vim-find-help", +# endif + /* 25 */ "gtk-convert", /* sub. GTK_STOCK_CONVERT */ + /* 26 */ "go-jump", /* sub. GTK_STOCK_JUMP_TO */ +# if GTK_CHECK_VERSION(3,14,0) + /* 27 */ "stock_vim_build_tags", + /* 28 */ "stock_vim_window_split_vertical", + /* 29 */ "stock_vim_window_maximize_width", + /* 30 */ "stock_vim_window_minimize_width", +# else + /* 27 */ "vim-build-tags", + /* 28 */ "vim-window-split-vertical", + /* 29 */ "vim-window-maximize-width", + /* 30 */ "vim-window-minimize-width", +# endif + /* 31 */ "application-exit", /* GTK_STOCK_QUIT */ +}; +# else /* !GTK_CHECK_VERSION(3,10,0) */ static const char * const menu_stock_ids[] = { /* 00 */ GTK_STOCK_NEW, @@ -139,8 +214,10 @@ static const char * const menu_stock_ids[] = /* 30 */ "vim-window-minimize-width", /* 31 */ GTK_STOCK_QUIT }; +# endif /* !GTK_CHECK_VERSION(3,10,0) */ -#ifdef USE_GRESOURCE +# ifdef USE_GRESOURCE +# if !GTK_CHECK_VERSION(3,10,0) typedef struct IconNames { const char *icon_name; const char *file_name; @@ -162,9 +239,10 @@ static IconNames stock_vim_icons[] = { { "vim-window-split-vertical", "stock_vim_window_split_vertical.png" }, { NULL, NULL } }; -#endif +# endif +# endif /* USE_G_RESOURCE */ -#ifndef USE_GRESOURCE +# ifndef USE_GRESOURCE static void add_stock_icon(GtkIconFactory *factory, const char *stock_id, @@ -182,7 +260,7 @@ add_stock_icon(GtkIconFactory *factory, gtk_icon_set_unref(icon_set); g_object_unref(pixbuf); } -#endif +# endif static int lookup_menu_iconfile(char_u *iconfile, char_u *dest) @@ -214,6 +292,52 @@ lookup_menu_iconfile(char_u *iconfile, char_u *dest) load_menu_iconfile(char_u *name, GtkIconSize icon_size) { GtkWidget *image = NULL; +# if GTK_CHECK_VERSION(3,10,0) + int pixel_size = -1; + + switch (icon_size) + { + case GTK_ICON_SIZE_MENU: + pixel_size = 16; + break; + case GTK_ICON_SIZE_SMALL_TOOLBAR: + pixel_size = 16; + break; + case GTK_ICON_SIZE_LARGE_TOOLBAR: + pixel_size = 24; + break; + case GTK_ICON_SIZE_BUTTON: + pixel_size = 16; + break; + case GTK_ICON_SIZE_DND: + pixel_size = 32; + break; + case GTK_ICON_SIZE_DIALOG: + pixel_size = 48; + break; + case GTK_ICON_SIZE_INVALID: + /* FALLTHROUGH */ + default: + pixel_size = 0; + break; + } + + if (pixel_size > 0 || pixel_size == -1) + { + GdkPixbuf * const pixbuf + = gdk_pixbuf_new_from_file_at_scale((const char *)name, + pixel_size, pixel_size, TRUE, NULL); + if (pixbuf != NULL) + { + image = gtk_image_new_from_pixbuf(pixbuf); + g_object_unref(pixbuf); + } + } + if (image == NULL) + image = gtk_image_new_from_icon_name("image-missing", icon_size); + + return image; +# else /* !GTK_CHECK_VERSION(3,10,0) */ GtkIconSet *icon_set; GtkIconSource *icon_source; @@ -234,6 +358,7 @@ load_menu_iconfile(char_u *name, GtkIconSize icon_size) gtk_icon_set_unref(icon_set); return image; +# endif /* !GTK_CHECK_VERSION(3,10,0) */ } static GtkWidget * @@ -254,6 +379,17 @@ create_menu_icon(vimmenu_T *menu, GtkIconSize icon_size) /* Still not found? Then use a builtin icon, a blank one as fallback. */ if (image == NULL) { +# if GTK_CHECK_VERSION(3,10,0) + const char *icon_name = NULL; + const int n_names = G_N_ELEMENTS(menu_themed_names); + + if (menu->iconidx >= 0 && menu->iconidx < n_names) + icon_name = menu_themed_names[menu->iconidx]; + if (icon_name == NULL) + icon_name = "image-missing"; + + image = gtk_image_new_from_icon_name(icon_name, icon_size); +# else const char *stock_id; const int n_ids = G_N_ELEMENTS(menu_stock_ids); @@ -263,6 +399,7 @@ create_menu_icon(vimmenu_T *menu, GtkIconSize icon_size) stock_id = GTK_STOCK_MISSING_IMAGE; image = gtk_image_new_from_stock(stock_id, icon_size); +# endif } return image; @@ -288,12 +425,12 @@ toolbar_button_focus_in_event(GtkWidget *widget UNUSED, void gui_gtk_register_stock_icons(void) { -#ifndef USE_GRESOURCE -# include "../pixmaps/stock_icons.h" +# ifndef USE_GRESOURCE +# include "../pixmaps/stock_icons.h" GtkIconFactory *factory; factory = gtk_icon_factory_new(); -# define ADD_ICON(Name, Data) add_stock_icon(factory, Name, Data, (int)sizeof(Data)) +# define ADD_ICON(Name, Data) add_stock_icon(factory, Name, Data, (int)sizeof(Data)) ADD_ICON("vim-build-tags", stock_vim_build_tags); ADD_ICON("vim-find-help", stock_vim_find_help); @@ -309,35 +446,91 @@ gui_gtk_register_stock_icons(void) ADD_ICON("vim-window-split", stock_vim_window_split); ADD_ICON("vim-window-split-vertical", stock_vim_window_split_vertical); -# undef ADD_ICON -#else - GtkIconFactory * const factory = gtk_icon_factory_new(); +# undef ADD_ICON + + gtk_icon_factory_add_default(factory); + g_object_unref(factory); +# else /* defined(USE_GRESOURCE) */ const char * const path_prefix = "/org/vim/gui/icon"; +# if GTK_CHECK_VERSION(3,14,0) + GdkScreen *screen = NULL; + GtkIconTheme *icon_theme = NULL; + + if (GTK_IS_WIDGET(gui.mainwin)) + screen = gtk_widget_get_screen(gui.mainwin); + else + screen = gdk_screen_get_default(); + icon_theme = gtk_icon_theme_get_for_screen(screen); + gtk_icon_theme_add_resource_path(icon_theme, path_prefix); +# elif GTK_CHECK_VERSION(3,0,0) IconNames *names; for (names = stock_vim_icons; names->icon_name != NULL; names++) { - char path[MAXPATHL]; - GdkPixbuf *pixbuf; - - vim_snprintf(path, MAXPATHL, "%s/%s", path_prefix, names->file_name); - pixbuf = gdk_pixbuf_new_from_resource(path, NULL); - if (pixbuf != NULL) - { - GtkIconSet *icon_set = gtk_icon_set_new_from_pixbuf(pixbuf); - gtk_icon_factory_add(factory, names->icon_name, icon_set); - gtk_icon_set_unref(icon_set); - g_object_unref(pixbuf); - } + char path[MAXPATHL]; + + vim_snprintf(path, MAXPATHL, "%s/%s", path_prefix, names->file_name); + GdkPixbuf *pixbuf = NULL; + pixbuf = gdk_pixbuf_new_from_resource(path, NULL); + if (pixbuf != NULL) + { + const gint size = MAX(gdk_pixbuf_get_width(pixbuf), + gdk_pixbuf_get_height(pixbuf)); + if (size > 16) + { + /* An icon theme is supposed to provide fixed-size + * image files for each size, e.g., 16, 22, 24, ... + * Naturally, in contrast to GtkIconSet, GtkIconTheme + * won't prepare size variants for us out of a single + * fixed-size image. + * + * Currently, Vim provides 24x24 images only while the + * icon size on the menu and the toolbar is set to 16x16 + * by default. + * + * Resize them by ourselves until we have our own fully + * fledged icon theme. */ + GdkPixbuf *src = pixbuf; + pixbuf = gdk_pixbuf_scale_simple(src, + 16, 16, + GDK_INTERP_BILINEAR); + if (pixbuf == NULL) + pixbuf = src; + else + g_object_unref(src); + } + gtk_icon_theme_add_builtin_icon(names->icon_name, size, pixbuf); + g_object_unref(pixbuf); + } } -#endif +# else /* !GTK_CHECK_VERSION(3,0.0) */ + GtkIconFactory * const factory = gtk_icon_factory_new(); + IconNames *names; + + for (names = stock_vim_icons; names->icon_name != NULL; names++) + { + char path[MAXPATHL]; + GdkPixbuf *pixbuf; + + vim_snprintf(path, MAXPATHL, "%s/%s", path_prefix, names->file_name); + pixbuf = gdk_pixbuf_new_from_resource(path, NULL); + if (pixbuf != NULL) + { + GtkIconSet *icon_set = gtk_icon_set_new_from_pixbuf(pixbuf); + gtk_icon_factory_add(factory, names->icon_name, icon_set); + gtk_icon_set_unref(icon_set); + g_object_unref(pixbuf); + } + } + gtk_icon_factory_add_default(factory); g_object_unref(factory); +# endif /* !GTK_CHECK_VERSION(3,0,0) */ +# endif /* defined(USE_GRESOURCE) */ } #endif /* FEAT_TOOLBAR */ - #if defined(FEAT_MENU) || defined(PROTO) /* @@ -408,7 +601,12 @@ menu_item_new(vimmenu_T *menu, GtkWidget *parent_widget) * changes to Vim's menu system. Not to mention that all the translations * had to be updated. */ menu->id = gtk_menu_item_new(); +# if GTK_CHECK_VERSION(3,2,0) + box = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 20); + gtk_box_set_homogeneous(GTK_BOX(box), FALSE); +# else box = gtk_hbox_new(FALSE, 20); +# endif use_mnemonic = (p_wak[0] != 'n' || !GTK_IS_MENU_BAR(parent_widget)); text = translate_mnemonic_tag(menu->name, use_mnemonic); @@ -465,10 +663,17 @@ gui_mch_add_menu(vimmenu_T *menu, int idx) gtk_menu_set_accel_group(GTK_MENU(menu->submenu_id), gui.accel_group); gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu->id), menu->submenu_id); +# if !GTK_CHECK_VERSION(3,4,0) menu->tearoff_handle = gtk_tearoff_menu_item_new(); if (vim_strchr(p_go, GO_TEAROFF) != NULL) gtk_widget_show(menu->tearoff_handle); +# if GTK_CHECK_VERSION(3,0,0) + gtk_menu_shell_prepend(GTK_MENU_SHELL(menu->submenu_id), + menu->tearoff_handle); +# else gtk_menu_prepend(GTK_MENU(menu->submenu_id), menu->tearoff_handle); +# endif +# endif } static void @@ -494,7 +699,17 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx) if (menu_is_separator(menu->name)) { +# if GTK_CHECK_VERSION(3,0,0) + GtkToolItem *item = gtk_separator_tool_item_new(); + gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(item), + TRUE); + gtk_tool_item_set_expand(GTK_TOOL_ITEM(item), FALSE); + gtk_widget_show(GTK_WIDGET(item)); + + gtk_toolbar_insert(toolbar, item, idx); +# else gtk_toolbar_insert_space(toolbar, idx); +# endif menu->id = NULL; } else @@ -509,6 +724,24 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx) * a nasty GTK error message, skip the tooltip. */ CONVERT_TO_UTF8_FREE(tooltip); +# if GTK_CHECK_VERSION(3,0,0) + { + GtkWidget *icon; + GtkToolItem *item; + + icon = create_menu_icon(menu, + gtk_toolbar_get_icon_size(toolbar)); + item = gtk_tool_button_new(icon, (const gchar *)text); + gtk_tool_item_set_tooltip_text(item, (const gchar *)tooltip); + g_signal_connect(G_OBJECT(item), "clicked", + G_CALLBACK(&menu_item_activate), menu); + gtk_widget_show_all(GTK_WIDGET(item)); + + gtk_toolbar_insert(toolbar, item, idx); + + menu->id = GTK_WIDGET(item); + } +# else menu->id = gtk_toolbar_insert_item( toolbar, (const char *)text, @@ -518,10 +751,16 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx) G_CALLBACK(&menu_item_activate), menu, idx); +# endif if (gtk_socket_id != 0) +# if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(menu->id), "focus-in-event", + G_CALLBACK(toolbar_button_focus_in_event), NULL); +# else gtk_signal_connect(GTK_OBJECT(menu->id), "focus_in_event", GTK_SIGNAL_FUNC(toolbar_button_focus_in_event), NULL); +# endif CONVERT_TO_UTF8_FREE(text); CONVERT_TO_UTF8_FREE(tooltip); @@ -545,7 +784,12 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx) menu->id = gtk_menu_item_new(); gtk_widget_set_sensitive(menu->id, FALSE); gtk_widget_show(menu->id); +# if GTK_CHECK_VERSION(3,0,0) + gtk_menu_shell_insert(GTK_MENU_SHELL(parent->submenu_id), + menu->id, idx); +# else gtk_menu_insert(GTK_MENU(parent->submenu_id), menu->id, idx); +# endif return; } @@ -553,11 +797,21 @@ gui_mch_add_menu_item(vimmenu_T *menu, int idx) /* Add textual menu item. */ menu_item_new(menu, parent->submenu_id); gtk_widget_show(menu->id); +# if GTK_CHECK_VERSION(3,0,0) + gtk_menu_shell_insert(GTK_MENU_SHELL(parent->submenu_id), + menu->id, idx); +# else gtk_menu_insert(GTK_MENU(parent->submenu_id), menu->id, idx); +# endif if (menu->id != NULL) +# if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(menu->id), "activate", + G_CALLBACK(menu_item_activate), menu); +# else gtk_signal_connect(GTK_OBJECT(menu->id), "activate", GTK_SIGNAL_FUNC(menu_item_activate), menu); +# endif } } #endif /* FEAT_MENU */ @@ -592,6 +846,7 @@ gui_gtk_set_mnemonics(int enable) } } +# if !GTK_CHECK_VERSION(3,4,0) static void recurse_tearoffs(vimmenu_T *menu, int val) { @@ -608,12 +863,21 @@ recurse_tearoffs(vimmenu_T *menu, int val) recurse_tearoffs(menu->children, val); } } +# endif +# if GTK_CHECK_VERSION(3,4,0) + void +gui_mch_toggle_tearoffs(int enable UNUSED) +{ + /* Do nothing */ +} +# else void gui_mch_toggle_tearoffs(int enable) { recurse_tearoffs(root_menu, enable); } +# endif #endif /* FEAT_MENU */ #if defined(FEAT_TOOLBAR) @@ -644,10 +908,15 @@ gui_mch_menu_set_tip(vimmenu_T *menu) char_u *tooltip; tooltip = CONVERT_TO_UTF8(menu->strings[MENU_INDEX_TIP]); - if (tooltip == NULL || utf_valid_string(tooltip, NULL)) + if (tooltip != NULL && utf_valid_string(tooltip, NULL)) +# if GTK_CHECK_VERSION(3,0,0) /* Only set the tooltip when it's valid utf-8. */ - gtk_tooltips_set_tip(GTK_TOOLBAR(gui.toolbar)->tooltips, - menu->id, (const char *)tooltip, NULL); + gtk_widget_set_tooltip_text(menu->id, (const gchar *)tooltip); +# else + /* Only set the tooltip when it's valid utf-8. */ + gtk_tooltips_set_tip(GTK_TOOLBAR(gui.toolbar)->tooltips, + menu->id, (const char *)tooltip, NULL); +# endif CONVERT_TO_UTF8_FREE(tooltip); } } @@ -676,8 +945,20 @@ gui_mch_destroy_menu(vimmenu_T *menu) if (menu->parent != NULL && menu_is_toolbar(menu->parent->name)) { if (menu_is_separator(menu->name)) +# if GTK_CHECK_VERSION(3,0,0) + { + GtkToolItem *item = NULL; + + item = gtk_toolbar_get_nth_item(GTK_TOOLBAR(gui.toolbar), + get_menu_position(menu)); + if (item != NULL) + gtk_container_remove(GTK_CONTAINER(gui.toolbar), + GTK_WIDGET(item)); + } +# else gtk_toolbar_remove_space(GTK_TOOLBAR(gui.toolbar), get_menu_position(menu)); +# endif else if (menu->id != NULL) gtk_widget_destroy(menu->id); } @@ -711,18 +992,42 @@ gui_mch_set_scrollbar_thumb(scrollbar_T *sb, long val, long size, long max) adjustment = gtk_range_get_adjustment(GTK_RANGE(sb->id)); +#if GTK_CHECK_VERSION(3,0,0) + gtk_adjustment_set_lower(adjustment, 0.0); + gtk_adjustment_set_value(adjustment, val); + gtk_adjustment_set_upper(adjustment, max + 1); + gtk_adjustment_set_page_size(adjustment, size); + gtk_adjustment_set_page_increment(adjustment, + size < 3L ? 1L : size - 2L); + gtk_adjustment_set_step_increment(adjustment, 1.0); +#else adjustment->lower = 0.0; adjustment->value = val; adjustment->upper = max + 1; adjustment->page_size = size; adjustment->page_increment = size < 3L ? 1L : size - 2L; adjustment->step_increment = 1.0; +#endif +#if GTK_CHECK_VERSION(3,0,0) + g_signal_handler_block(G_OBJECT(adjustment), + (gulong)sb->handler_id); +#else g_signal_handler_block(GTK_OBJECT(adjustment), (gulong)sb->handler_id); +#endif + +#if !GTK_CHECK_VERSION(3,18,0) gtk_adjustment_changed(adjustment); +#endif + +#if GTK_CHECK_VERSION(3,0,0) + g_signal_handler_unblock(G_OBJECT(adjustment), + (gulong)sb->handler_id); +#else g_signal_handler_unblock(GTK_OBJECT(adjustment), (gulong)sb->handler_id); +#endif } } @@ -750,7 +1055,12 @@ adjustment_value_changed(GtkAdjustment *adjustment, gpointer data) #endif sb = gui_find_scrollbar((long)data); +#if GTK_CHECK_VERSION(3,0,0) + value = gtk_adjustment_get_value(adjustment); +#else value = (long)adjustment->value; +#endif +#if !GTK_CHECK_VERSION(3,0,0) /* * The dragging argument must be right for the scrollbar to work with * closed folds. This isn't documented, hopefully this will keep on @@ -793,7 +1103,7 @@ adjustment_value_changed(GtkAdjustment *adjustment, gpointer data) } } } - +#endif /* !GTK_CHECK_VERSION(3,0,0) */ gui_drag_scrollbar(sb, value, dragging); } @@ -802,23 +1112,42 @@ adjustment_value_changed(GtkAdjustment *adjustment, gpointer data) gui_mch_create_scrollbar(scrollbar_T *sb, int orient) { if (orient == SBAR_HORIZ) +#if GTK_CHECK_VERSION(3,2,0) + sb->id = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, NULL); +#else sb->id = gtk_hscrollbar_new(NULL); +#endif else if (orient == SBAR_VERT) +#if GTK_CHECK_VERSION(3,2,0) + sb->id = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, NULL); +#else sb->id = gtk_vscrollbar_new(NULL); +#endif if (sb->id != NULL) { GtkAdjustment *adjustment; +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_can_focus(sb->id, FALSE); +#else GTK_WIDGET_UNSET_FLAGS(sb->id, GTK_CAN_FOCUS); +#endif gtk_form_put(GTK_FORM(gui.formwin), sb->id, 0, 0); adjustment = gtk_range_get_adjustment(GTK_RANGE(sb->id)); +#if GTK_CHECK_VERSION(3,0,0) + sb->handler_id = g_signal_connect( + G_OBJECT(adjustment), "value-changed", + G_CALLBACK(adjustment_value_changed), + GINT_TO_POINTER(sb->ident)); +#else sb->handler_id = gtk_signal_connect( GTK_OBJECT(adjustment), "value_changed", GTK_SIGNAL_FUNC(adjustment_value_changed), GINT_TO_POINTER(sb->ident)); +#endif gui_mch_update(); } } @@ -932,8 +1261,13 @@ gui_mch_browse(int saving UNUSED, GTK_WINDOW(gui.mainwin), saving ? GTK_FILE_CHOOSER_ACTION_SAVE : GTK_FILE_CHOOSER_ACTION_OPEN, +# if GTK_CHECK_VERSION(3,10,0) + _("_Cancel"), GTK_RESPONSE_CANCEL, + saving ? _("_Save") : _("_Open"), GTK_RESPONSE_ACCEPT, +# else GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, saving ? GTK_STOCK_SAVE : GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, +# endif NULL); gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(fc), (const gchar *)dirbuf); @@ -991,7 +1325,7 @@ gui_mch_browse(int saving UNUSED, } gtk_widget_destroy(GTK_WIDGET(fc)); -#else +#else /* !USE_FILE_CHOOSER */ if (gui.filedlg == NULL) { @@ -1027,7 +1361,7 @@ gui_mch_browse(int saving UNUSED, gtk_widget_show(gui.filedlg); gtk_main(); -#endif +#endif /* !USE_FILE_CHOOSER */ g_log_remove_handler(domain, log_handler); CONVERT_TO_UTF8_FREE(title); @@ -1062,8 +1396,13 @@ gui_mch_browsedir( (const gchar *)title, GTK_WINDOW(gui.mainwin), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, +# if GTK_CHECK_VERSION(3,10,0) + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_OK"), GTK_RESPONSE_ACCEPT, +# else GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, +# endif NULL); CONVERT_TO_UTF8_FREE(title); @@ -1096,10 +1435,10 @@ gui_mch_browsedir( g_free(dirname); return p; -# else +# else /* !defined(GTK_FILE_CHOOSER) */ /* For GTK 2.2 and earlier: fall back to ordinary file selector. */ return gui_mch_browse(0, title, NULL, NULL, initdir, NULL); -# endif +# endif /* !defined(GTK_FILE_CHOOSER) */ } @@ -1266,6 +1605,11 @@ dialog_add_buttons(GtkDialog *dialog, char_u *button_string) /* Check 'v' flag in 'guioptions': vertical button placement. */ if (vim_strchr(p_go, GO_VERTICAL) != NULL) { +# if GTK_CHECK_VERSION(3,0,0) + /* Add GTK+ 3 code if necessary. */ + /* N.B. GTK+ 3 doesn't allow you to access vbox and action_area via + * the C API. */ +# else GtkWidget *vbutton_box; vbutton_box = gtk_vbutton_box_new(); @@ -1274,6 +1618,7 @@ dialog_add_buttons(GtkDialog *dialog, char_u *button_string) vbutton_box, TRUE, FALSE, 0); /* Overrule the "action_area" value, hopefully this works... */ GTK_DIALOG(dialog)->action_area = vbutton_box; +# endif } /* @@ -1308,6 +1653,16 @@ dialog_add_buttons(GtkDialog *dialog, char_u *button_string) */ if (ok != NULL && ync != NULL) /* almost impossible to fail */ { +# if GTK_CHECK_VERSION(3,10,0) + if (button_equal(label, ok[0])) label = _("OK"); + else if (button_equal(label, ync[0])) label = _("Yes"); + else if (button_equal(label, ync[1])) label = _("No"); + else if (button_equal(label, ync[2])) label = _("Cancel"); + else if (button_equal(label, "Ok")) label = _("OK"); + else if (button_equal(label, "Yes")) label = _("Yes"); + else if (button_equal(label, "No")) label = _("No"); + else if (button_equal(label, "Cancel")) label = _("Canccl"); +# else if (button_equal(label, ok[0])) label = GTK_STOCK_OK; else if (button_equal(label, ync[0])) label = GTK_STOCK_YES; else if (button_equal(label, ync[1])) label = GTK_STOCK_NO; @@ -1316,6 +1671,7 @@ dialog_add_buttons(GtkDialog *dialog, char_u *button_string) else if (button_equal(label, "Yes")) label = GTK_STOCK_YES; else if (button_equal(label, "No")) label = GTK_STOCK_NO; else if (button_equal(label, "Cancel")) label = GTK_STOCK_CANCEL; +# endif } label8 = CONVERT_TO_UTF8((char_u *)label); gtk_dialog_add_button(dialog, (const gchar *)label8, idx); @@ -1408,14 +1764,32 @@ gui_mch_dialog(int type, /* type of dialog */ gtk_entry_set_text(GTK_ENTRY(entry), (const char *)text); CONVERT_TO_UTF8_FREE(text); +# if GTK_CHECK_VERSION(3,14,0) + gtk_widget_set_halign(GTK_WIDGET(entry), GTK_ALIGN_CENTER); + gtk_widget_set_valign(GTK_WIDGET(entry), GTK_ALIGN_CENTER); + gtk_widget_set_hexpand(GTK_WIDGET(entry), TRUE); + gtk_widget_set_vexpand(GTK_WIDGET(entry), TRUE); + + alignment = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); +# else alignment = gtk_alignment_new((float)0.5, (float)0.5, (float)1.0, (float)1.0); +# endif gtk_container_add(GTK_CONTAINER(alignment), entry); gtk_container_set_border_width(GTK_CONTAINER(alignment), 5); gtk_widget_show(alignment); +# if GTK_CHECK_VERSION(3,0,0) + { + GtkWidget * const vbox + = gtk_dialog_get_content_area(GTK_DIALOG(dialog)); + gtk_box_pack_start(GTK_BOX(vbox), + alignment, TRUE, FALSE, 0); + } +# else gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), alignment, TRUE, FALSE, 0); +# endif dialoginfo.noalt = FALSE; } else @@ -1473,6 +1847,7 @@ gui_mch_show_popupmenu(vimmenu_T *menu) * Append a submenu for selecting an input method. This is * currently the only way to switch input methods at runtime. */ +# if !GTK_CHECK_VERSION(3,10,0) if (xic != NULL && g_object_get_data(G_OBJECT(menu->submenu_id), "vim-has-im-menu") == NULL) { @@ -1499,6 +1874,7 @@ gui_mch_show_popupmenu(vimmenu_T *menu) g_object_set_data(G_OBJECT(menu->submenu_id), "vim-has-im-menu", GINT_TO_POINTER(TRUE)); } +# endif # endif /* FEAT_XIM */ gtk_menu_popup(GTK_MENU(menu->submenu_id), @@ -1524,7 +1900,11 @@ popup_menu_position_func(GtkMenu *menu UNUSED, gboolean *push_in UNUSED, gpointer user_data UNUSED) { +# if GTK_CHECK_VERSION(3,0,0) + gdk_window_get_origin(gtk_widget_get_window(gui.drawarea), x, y); +# else gdk_window_get_origin(gui.drawarea->window, x, y); +# endif if (popup_mouse_pos) { @@ -1534,7 +1914,12 @@ popup_menu_position_func(GtkMenu *menu UNUSED, *x += mx; *y += my; } +# if GTK_CHECK_VERSION(3,0,0) + else if (curwin != NULL && gui.drawarea != NULL && + gtk_widget_get_window(gui.drawarea) != NULL) +# else else if (curwin != NULL && gui.drawarea != NULL && gui.drawarea->window != NULL) +# endif { /* Find the cursor position in the current window */ *x += FILL_X(W_WINCOL(curwin) + curwin->w_wcol + 1) + 1; @@ -1612,7 +1997,13 @@ find_key_press_event( } static GtkWidget * -create_image_button(const char *stock_id, const char *label) +#if GTK_CHECK_VERSION(3,10,0) +create_image_button(const char *stock_id UNUSED, + const char *label) +#else +create_image_button(const char *stock_id, + const char *label) +#endif { char_u *text; GtkWidget *box; @@ -1621,18 +2012,35 @@ create_image_button(const char *stock_id, const char *label) text = CONVERT_TO_UTF8((char_u *)label); +#if GTK_CHECK_VERSION(3,2,0) + box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 3); + gtk_box_set_homogeneous(GTK_BOX(box), FALSE); +#else box = gtk_hbox_new(FALSE, 3); - gtk_box_pack_start(GTK_BOX(box), - gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_BUTTON), - FALSE, FALSE, 0); +#endif +#if !GTK_CHECK_VERSION(3,10,0) + if (stock_id != NULL) + gtk_box_pack_start(GTK_BOX(box), + gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_BUTTON), + FALSE, FALSE, 0); +#endif gtk_box_pack_start(GTK_BOX(box), gtk_label_new((const char *)text), FALSE, FALSE, 0); CONVERT_TO_UTF8_FREE(text); +#if GTK_CHECK_VERSION(3,14,0) + gtk_widget_set_halign(GTK_WIDGET(box), GTK_ALIGN_CENTER); + gtk_widget_set_valign(GTK_WIDGET(box), GTK_ALIGN_CENTER); + gtk_widget_set_hexpand(GTK_WIDGET(box), TRUE); + gtk_widget_set_vexpand(GTK_WIDGET(box), TRUE); + + alignment = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); +#else alignment = gtk_alignment_new((float)0.5, (float)0.5, (float)0.0, (float)0.0); +#endif gtk_container_add(GTK_CONTAINER(alignment), box); gtk_widget_show_all(alignment); @@ -1695,10 +2103,17 @@ find_replace_dialog_create(char_u *arg, int do_replace) if (entry_text != NULL) { gtk_entry_set_text(GTK_ENTRY(frdp->what), (char *)entry_text); +#if GTK_CHECK_VERSION(3,0,0) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->wword), + (gboolean)wword); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->mcase), + (gboolean)mcase); +#else gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(frdp->wword), (gboolean)wword); gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(frdp->mcase), (gboolean)mcase); +#endif } gtk_window_present(GTK_WINDOW(frdp->dialog)); vim_free(entry_text); @@ -1706,7 +2121,11 @@ find_replace_dialog_create(char_u *arg, int do_replace) } frdp->dialog = gtk_dialog_new(); +#if GTK_CHECK_VERSION(3,0,0) + /* Nothing equivalent to gtk_dialog_set_has_separator() in GTK+ 3. */ +#else gtk_dialog_set_has_separator(GTK_DIALOG(frdp->dialog), FALSE); +#endif gtk_window_set_transient_for(GTK_WINDOW(frdp->dialog), GTK_WINDOW(gui.mainwin)); gtk_window_set_destroy_with_parent(GTK_WINDOW(frdp->dialog), TRUE); @@ -1721,164 +2140,402 @@ find_replace_dialog_create(char_u *arg, int do_replace) CONV(_("VIM - Search..."))); } +#if GTK_CHECK_VERSION(3,2,0) + hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); + gtk_box_set_homogeneous(GTK_BOX(hbox), FALSE); +#else hbox = gtk_hbox_new(FALSE, 0); +#endif gtk_container_set_border_width(GTK_CONTAINER(hbox), 10); +#if GTK_CHECK_VERSION(3,0,0) + { + GtkWidget * const dialog_vbox + = gtk_dialog_get_content_area(GTK_DIALOG(frdp->dialog)); + gtk_container_add(GTK_CONTAINER(dialog_vbox), hbox); + } +#else gtk_container_add(GTK_CONTAINER(GTK_DIALOG(frdp->dialog)->vbox), hbox); +#endif if (do_replace) +#if GTK_CHECK_VERSION(3,4,0) + table = gtk_grid_new(); +#else table = gtk_table_new(1024, 4, FALSE); +#endif else +#if GTK_CHECK_VERSION(3,4,0) + table = gtk_grid_new(); +#else table = gtk_table_new(1024, 3, FALSE); +#endif gtk_box_pack_start(GTK_BOX(hbox), table, TRUE, TRUE, 0); +#if GTK_CHECK_VERSION(3,0,0) + gtk_container_set_border_width(GTK_CONTAINER(table), 4); +#else gtk_container_border_width(GTK_CONTAINER(table), 4); +#endif tmp = gtk_label_new(CONV(_("Find what:"))); +#if GTK_CHECK_VERSION(3,16,0) + gtk_label_set_xalign(GTK_LABEL(tmp), 0.0); + gtk_label_set_yalign(GTK_LABEL(tmp), 0.5); +#elif GTK_CHECK_VERSION(3,14,0) + { + GValue align_val = G_VALUE_INIT; + + g_value_init(&align_val, G_TYPE_FLOAT); + + g_value_set_float(&align_val, 0.0); + g_object_set_property(G_OBJECT(tmp), "xalign", &align_val); + + g_value_set_float(&align_val, 0.5); + g_object_set_property(G_OBJECT(tmp), "yalign", &align_val); + + g_value_unset(&align_val); + } +#else gtk_misc_set_alignment(GTK_MISC(tmp), (gfloat)0.0, (gfloat)0.5); +#endif +#if GTK_CHECK_VERSION(3,4,0) + gtk_grid_attach(GTK_GRID(table), tmp, 0, 0, 2, 1); +#else gtk_table_attach(GTK_TABLE(table), tmp, 0, 1, 0, 1, GTK_FILL, GTK_EXPAND, 2, 2); +#endif frdp->what = gtk_entry_new(); sensitive = (entry_text != NULL && entry_text[0] != NUL); if (entry_text != NULL) gtk_entry_set_text(GTK_ENTRY(frdp->what), (char *)entry_text); +#if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(frdp->what), "changed", + G_CALLBACK(entry_changed_cb), frdp->dialog); + g_signal_connect_after(G_OBJECT(frdp->what), "key-press-event", + G_CALLBACK(find_key_press_event), + (gpointer) frdp); +#else gtk_signal_connect(GTK_OBJECT(frdp->what), "changed", GTK_SIGNAL_FUNC(entry_changed_cb), frdp->dialog); gtk_signal_connect_after(GTK_OBJECT(frdp->what), "key_press_event", GTK_SIGNAL_FUNC(find_key_press_event), (gpointer) frdp); +#endif +#if GTK_CHECK_VERSION(3,4,0) + gtk_grid_attach(GTK_GRID(table), frdp->what, 2, 0, 5, 1); +#else gtk_table_attach(GTK_TABLE(table), frdp->what, 1, 1024, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 2, 2); +#endif if (do_replace) { tmp = gtk_label_new(CONV(_("Replace with:"))); +#if GTK_CHECK_VERSION(3,16,0) + gtk_label_set_xalign(GTK_LABEL(tmp), 0.0); + gtk_label_set_yalign(GTK_LABEL(tmp), 0.5); +#elif GTK_CHECK_VERSION(3,14,0) + { + GValue align_val = G_VALUE_INIT; + + g_value_init(&align_val, G_TYPE_FLOAT); + + g_value_set_float(&align_val, 0.0); + g_object_set_property(G_OBJECT(tmp), "xalign", &align_val); + + g_value_set_float(&align_val, 0.5); + g_object_set_property(G_OBJECT(tmp), "yalign", &align_val); + + g_value_unset(&align_val); + } +#else gtk_misc_set_alignment(GTK_MISC(tmp), (gfloat)0.0, (gfloat)0.5); +#endif +#if GTK_CHECK_VERSION(3,4,0) + gtk_grid_attach(GTK_GRID(table), tmp, 0, 1, 2, 1); +#else gtk_table_attach(GTK_TABLE(table), tmp, 0, 1, 1, 2, GTK_FILL, GTK_EXPAND, 2, 2); +#endif frdp->with = gtk_entry_new(); +#if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(frdp->with), "activate", + G_CALLBACK(find_replace_cb), + GINT_TO_POINTER(FRD_R_FINDNEXT)); + g_signal_connect_after(G_OBJECT(frdp->with), "key-press-event", + G_CALLBACK(find_key_press_event), + (gpointer) frdp); +#else gtk_signal_connect(GTK_OBJECT(frdp->with), "activate", GTK_SIGNAL_FUNC(find_replace_cb), GINT_TO_POINTER(FRD_R_FINDNEXT)); gtk_signal_connect_after(GTK_OBJECT(frdp->with), "key_press_event", GTK_SIGNAL_FUNC(find_key_press_event), (gpointer) frdp); +#endif +#if GTK_CHECK_VERSION(3,4,0) + gtk_grid_attach(GTK_GRID(table), frdp->with, 2, 1, 5, 1); +#else gtk_table_attach(GTK_TABLE(table), frdp->with, 1, 1024, 1, 2, GTK_EXPAND | GTK_FILL, GTK_EXPAND, 2, 2); +#endif /* * Make the entry activation only change the input focus onto the * with item. */ +#if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(frdp->what), "activate", + G_CALLBACK(entry_activate_cb), frdp->with); +#else gtk_signal_connect(GTK_OBJECT(frdp->what), "activate", GTK_SIGNAL_FUNC(entry_activate_cb), frdp->with); +#endif } else { /* * Make the entry activation do the search. */ +#if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(frdp->what), "activate", + G_CALLBACK(find_replace_cb), + GINT_TO_POINTER(FRD_FINDNEXT)); +#else gtk_signal_connect(GTK_OBJECT(frdp->what), "activate", GTK_SIGNAL_FUNC(find_replace_cb), GINT_TO_POINTER(FRD_FINDNEXT)); +#endif } /* whole word only button */ frdp->wword = gtk_check_button_new_with_label(CONV(_("Match whole word only"))); +#if GTK_CHECK_VERSION(3,0,0) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->wword), + (gboolean)wword); +#else gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(frdp->wword), (gboolean)wword); +#endif if (do_replace) +#if GTK_CHECK_VERSION(3,4,0) + gtk_grid_attach(GTK_GRID(table), frdp->wword, 0, 2, 5, 1); +#else gtk_table_attach(GTK_TABLE(table), frdp->wword, 0, 1023, 2, 3, GTK_FILL, GTK_EXPAND, 2, 2); +#endif else +#if GTK_CHECK_VERSION(3,4,0) + gtk_grid_attach(GTK_GRID(table), frdp->wword, 0, 3, 5, 1); +#else gtk_table_attach(GTK_TABLE(table), frdp->wword, 0, 1023, 1, 2, GTK_FILL, GTK_EXPAND, 2, 2); +#endif /* match case button */ frdp->mcase = gtk_check_button_new_with_label(CONV(_("Match case"))); +#if GTK_CHECK_VERSION(3,0,0) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->mcase), + (gboolean)mcase); +#else gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(frdp->mcase), (gboolean)mcase); +#endif if (do_replace) +#if GTK_CHECK_VERSION(3,4,0) + gtk_grid_attach(GTK_GRID(table), frdp->mcase, 0, 3, 5, 1); +#else gtk_table_attach(GTK_TABLE(table), frdp->mcase, 0, 1023, 3, 4, GTK_FILL, GTK_EXPAND, 2, 2); +#endif else +#if GTK_CHECK_VERSION(3,4,0) + gtk_grid_attach(GTK_GRID(table), frdp->mcase, 0, 4, 5, 1); +#else gtk_table_attach(GTK_TABLE(table), frdp->mcase, 0, 1023, 2, 3, GTK_FILL, GTK_EXPAND, 2, 2); +#endif tmp = gtk_frame_new(CONV(_("Direction"))); if (do_replace) +#if GTK_CHECK_VERSION(3,4,0) + gtk_grid_attach(GTK_GRID(table), tmp, 5, 2, 2, 4); +#else gtk_table_attach(GTK_TABLE(table), tmp, 1023, 1024, 2, 4, GTK_FILL, GTK_FILL, 2, 2); +#endif else +#if GTK_CHECK_VERSION(3,4,0) + gtk_grid_attach(GTK_GRID(table), tmp, 5, 2, 1, 3); +#else gtk_table_attach(GTK_TABLE(table), tmp, 1023, 1024, 1, 3, GTK_FILL, GTK_FILL, 2, 2); +#endif +#if GTK_CHECK_VERSION(3,2,0) + vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); + gtk_box_set_homogeneous(GTK_BOX(vbox), FALSE); +#else vbox = gtk_vbox_new(FALSE, 0); +#endif +#if GTK_CHECK_VERSION(3,0,0) + gtk_container_set_border_width(GTK_CONTAINER(vbox), 0); +#else gtk_container_border_width(GTK_CONTAINER(vbox), 0); +#endif gtk_container_add(GTK_CONTAINER(tmp), vbox); /* 'Up' and 'Down' buttons */ frdp->up = gtk_radio_button_new_with_label(NULL, CONV(_("Up"))); gtk_box_pack_start(GTK_BOX(vbox), frdp->up, TRUE, TRUE, 0); +#if GTK_CHECK_VERSION(3,0,0) + frdp->down = gtk_radio_button_new_with_label( + gtk_radio_button_get_group(GTK_RADIO_BUTTON(frdp->up)), + CONV(_("Down"))); +#else frdp->down = gtk_radio_button_new_with_label( gtk_radio_button_group(GTK_RADIO_BUTTON(frdp->up)), CONV(_("Down"))); +#endif +#if GTK_CHECK_VERSION(3,0,0) + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(frdp->down), TRUE); +#else gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(frdp->down), TRUE); +#endif gtk_container_set_border_width(GTK_CONTAINER(vbox), 2); gtk_box_pack_start(GTK_BOX(vbox), frdp->down, TRUE, TRUE, 0); /* vbox to hold the action buttons */ +#if GTK_CHECK_VERSION(3,2,0) + actionarea = gtk_button_box_new(GTK_ORIENTATION_VERTICAL); +#else actionarea = gtk_vbutton_box_new(); +#endif +#if GTK_CHECK_VERSION(3,0,0) + gtk_container_set_border_width(GTK_CONTAINER(actionarea), 2); +#else gtk_container_border_width(GTK_CONTAINER(actionarea), 2); +#endif gtk_box_pack_end(GTK_BOX(hbox), actionarea, FALSE, FALSE, 0); /* 'Find Next' button */ +#if GTK_CHECK_VERSION(3,10,0) + frdp->find = create_image_button(NULL, _("Find Next")); +#else frdp->find = create_image_button(GTK_STOCK_FIND, _("Find Next")); +#endif gtk_widget_set_sensitive(frdp->find, sensitive); +#if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(frdp->find), "clicked", + G_CALLBACK(find_replace_cb), + (do_replace) ? GINT_TO_POINTER(FRD_R_FINDNEXT) + : GINT_TO_POINTER(FRD_FINDNEXT)); +#else gtk_signal_connect(GTK_OBJECT(frdp->find), "clicked", GTK_SIGNAL_FUNC(find_replace_cb), (do_replace) ? GINT_TO_POINTER(FRD_R_FINDNEXT) : GINT_TO_POINTER(FRD_FINDNEXT)); +#endif +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_can_default(frdp->find, TRUE); +#else GTK_WIDGET_SET_FLAGS(frdp->find, GTK_CAN_DEFAULT); +#endif gtk_box_pack_start(GTK_BOX(actionarea), frdp->find, FALSE, FALSE, 0); gtk_widget_grab_default(frdp->find); if (do_replace) { /* 'Replace' button */ +#if GTK_CHECK_VERSION(3,10,0) + frdp->replace = create_image_button(NULL, _("Replace")); +#else frdp->replace = create_image_button(GTK_STOCK_CONVERT, _("Replace")); +#endif gtk_widget_set_sensitive(frdp->replace, sensitive); +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_can_default(frdp->find, TRUE); +#else GTK_WIDGET_SET_FLAGS(frdp->replace, GTK_CAN_DEFAULT); +#endif gtk_box_pack_start(GTK_BOX(actionarea), frdp->replace, FALSE, FALSE, 0); +#if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(frdp->replace), "clicked", + G_CALLBACK(find_replace_cb), + GINT_TO_POINTER(FRD_REPLACE)); +#else gtk_signal_connect(GTK_OBJECT(frdp->replace), "clicked", GTK_SIGNAL_FUNC(find_replace_cb), GINT_TO_POINTER(FRD_REPLACE)); +#endif /* 'Replace All' button */ +#if GTK_CHECK_VERSION(3,10,0) + frdp->all = create_image_button(NULL, _("Replace All")); +#else frdp->all = create_image_button(GTK_STOCK_CONVERT, _("Replace All")); +#endif gtk_widget_set_sensitive(frdp->all, sensitive); +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_can_default(frdp->all, TRUE); +#else GTK_WIDGET_SET_FLAGS(frdp->all, GTK_CAN_DEFAULT); +#endif gtk_box_pack_start(GTK_BOX(actionarea), frdp->all, FALSE, FALSE, 0); +#if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(frdp->all), "clicked", + G_CALLBACK(find_replace_cb), + GINT_TO_POINTER(FRD_REPLACEALL)); +#else gtk_signal_connect(GTK_OBJECT(frdp->all), "clicked", GTK_SIGNAL_FUNC(find_replace_cb), GINT_TO_POINTER(FRD_REPLACEALL)); +#endif } /* 'Cancel' button */ +#if GTK_CHECK_VERSION(3,10,0) + tmp = gtk_button_new_with_mnemonic(_("_Close")); +#else tmp = gtk_button_new_from_stock(GTK_STOCK_CLOSE); +#endif +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_can_default(tmp, TRUE); +#else GTK_WIDGET_SET_FLAGS(tmp, GTK_CAN_DEFAULT); +#endif gtk_box_pack_end(GTK_BOX(actionarea), tmp, FALSE, FALSE, 0); +#if GTK_CHECK_VERSION(3,0,0) + g_signal_connect_swapped(G_OBJECT(tmp), + "clicked", G_CALLBACK(gtk_widget_hide), + G_OBJECT(frdp->dialog)); + g_signal_connect_swapped(G_OBJECT(frdp->dialog), + "delete-event", G_CALLBACK(gtk_widget_hide_on_delete), + G_OBJECT(frdp->dialog)); +#else gtk_signal_connect_object(GTK_OBJECT(tmp), "clicked", GTK_SIGNAL_FUNC(gtk_widget_hide), GTK_OBJECT(frdp->dialog)); gtk_signal_connect_object(GTK_OBJECT(frdp->dialog), "delete_event", GTK_SIGNAL_FUNC(gtk_widget_hide_on_delete), GTK_OBJECT(frdp->dialog)); +#endif +#if GTK_CHECK_VERSION(3,2,0) + tmp = gtk_separator_new(GTK_ORIENTATION_VERTICAL); +#else tmp = gtk_vseparator_new(); +#endif gtk_box_pack_end(GTK_BOX(hbox), tmp, FALSE, FALSE, 10); /* Suppress automatic show of the unused action area */ +#if GTK_CHECK_VERSION(3,0,0) +# if !GTK_CHECK_VERSION(3,12,0) + gtk_widget_hide(gtk_dialog_get_action_area(GTK_DIALOG(frdp->dialog))); +# endif +#else gtk_widget_hide(GTK_DIALOG(frdp->dialog)->action_area); +#endif gtk_widget_show_all(hbox); gtk_widget_show(frdp->dialog); @@ -1928,11 +2585,23 @@ find_replace_cb(GtkWidget *widget UNUSED, gpointer data) } find_text = (char_u *)gtk_entry_get_text(GTK_ENTRY(sfr->what)); +#if GTK_CHECK_VERSION(3,0,0) + direction_down = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sfr->down)); +#else direction_down = GTK_TOGGLE_BUTTON(sfr->down)->active; +#endif +#if GTK_CHECK_VERSION(3,0,0) + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sfr->wword))) +#else if (GTK_TOGGLE_BUTTON(sfr->wword)->active) +#endif flags |= FRD_WHOLE_WORD; +#if GTK_CHECK_VERSION(3,0,0) + if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(sfr->mcase))) +#else if (GTK_TOGGLE_BUTTON(sfr->mcase)->active) +#endif flags |= FRD_MATCH_CASE; repl_text = CONVERT_FROM_UTF8(repl_text); diff --git a/src/gui_gtk_f.c b/src/gui_gtk_f.c index 0eb50652c..838a4ca8f 100644 --- a/src/gui_gtk_f.c +++ b/src/gui_gtk_f.c @@ -19,13 +19,19 @@ * children at arbitrary positions width arbitrary sizes. This finally puts * an end on our resize problems with which we where struggling for such a * long time. + * + * Support for GTK+ 3 was added by: + * + * 2016 Kazunobu Kuriyama <kazunobu.kuriyama@gmail.com> */ #include "vim.h" #include <gtk/gtk.h> /* without this it compiles, but gives errors at runtime! */ #include "gui_gtk_f.h" -#include <gtk/gtksignal.h> +#if !GTK_CHECK_VERSION(3,0,0) +# include <gtk/gtksignal.h> +#endif #ifdef WIN3264 # include <gdk/gdkwin32.h> #else @@ -52,10 +58,23 @@ static void gtk_form_unrealize(GtkWidget *widget); static void gtk_form_map(GtkWidget *widget); static void gtk_form_size_request(GtkWidget *widget, GtkRequisition *requisition); +#if GTK_CHECK_VERSION(3,0,0) +static void gtk_form_get_preferred_width(GtkWidget *widget, + gint *minimal_width, + gint *natural_width); +static void gtk_form_get_preferred_height(GtkWidget *widget, + gint *minimal_height, + gint *natural_height); +#endif static void gtk_form_size_allocate(GtkWidget *widget, GtkAllocation *allocation); +#if GTK_CHECK_VERSION(3,0,0) +static gboolean gtk_form_draw(GtkWidget *widget, + cairo_t *cr); +#else static gint gtk_form_expose(GtkWidget *widget, GdkEventExpose *event); +#endif static void gtk_form_remove(GtkContainer *container, GtkWidget *widget); @@ -73,22 +92,27 @@ static void gtk_form_position_child(GtkForm *form, gboolean force_allocate); static void gtk_form_position_children(GtkForm *form); +#if !GTK_CHECK_VERSION(3,0,0) static GdkFilterReturn gtk_form_filter(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data); static GdkFilterReturn gtk_form_main_filter(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data); - +#endif +#if !GTK_CHECK_VERSION(3,16,0) static void gtk_form_set_static_gravity(GdkWindow *window, gboolean use_static); +#endif static void gtk_form_send_configure(GtkForm *form); static void gtk_form_child_map(GtkWidget *widget, gpointer user_data); static void gtk_form_child_unmap(GtkWidget *widget, gpointer user_data); +#if !GTK_CHECK_VERSION(3,0,0) static GtkWidgetClass *parent_class = NULL; +#endif /* Public interface */ @@ -98,7 +122,11 @@ gtk_form_new(void) { GtkForm *form; +#if GTK_CHECK_VERSION(3,0,0) + form = g_object_new(GTK_TYPE_FORM, NULL); +#else form = gtk_type_new(gtk_form_get_type()); +#endif return GTK_WIDGET(form); } @@ -120,8 +148,12 @@ gtk_form_put(GtkForm *form, child->window = NULL; child->x = x; child->y = y; +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_size_request(child->widget, -1, -1); +#else child->widget->requisition.width = 0; child->widget->requisition.height = 0; +#endif child->mapped = FALSE; form->children = g_list_append(form->children, child); @@ -131,13 +163,24 @@ gtk_form_put(GtkForm *form, * that gtk_widget_set_parent() realizes the widget if it's visible * and its parent is mapped. */ +#if GTK_CHECK_VERSION(3,0,0) + if (gtk_widget_get_realized(GTK_WIDGET(form))) +#else if (GTK_WIDGET_REALIZED(form)) +#endif gtk_form_attach_child_window(form, child); gtk_widget_set_parent(child_widget, GTK_WIDGET(form)); +#if !GTK_CHECK_VERSION(3,0,0) gtk_widget_size_request(child->widget, NULL); +#endif +#if GTK_CHECK_VERSION(3,0,0) + if (gtk_widget_get_realized(GTK_WIDGET(form)) + && !gtk_widget_get_realized(child_widget)) +#else if (GTK_WIDGET_REALIZED(form) && !GTK_WIDGET_REALIZED(child_widget)) +#endif gtk_form_realize_child(form, child); gtk_form_position_child(form, child, TRUE); @@ -193,6 +236,9 @@ gtk_form_thaw(GtkForm *form) /* Basic Object handling procedures */ +#if GTK_CHECK_VERSION(3,0,0) +G_DEFINE_TYPE(GtkForm, gtk_form, GTK_TYPE_CONTAINER) +#else GtkType gtk_form_get_type(void) { @@ -213,6 +259,7 @@ gtk_form_get_type(void) } return form_type; } +#endif /* !GTK_CHECK_VERSION(3,0,0) */ static void gtk_form_class_init(GtkFormClass *klass) @@ -223,14 +270,25 @@ gtk_form_class_init(GtkFormClass *klass) widget_class = (GtkWidgetClass *) klass; container_class = (GtkContainerClass *) klass; +#if !GTK_CHECK_VERSION(3,0,0) parent_class = gtk_type_class(gtk_container_get_type()); +#endif widget_class->realize = gtk_form_realize; widget_class->unrealize = gtk_form_unrealize; widget_class->map = gtk_form_map; +#if GTK_CHECK_VERSION(3,0,0) + widget_class->get_preferred_width = gtk_form_get_preferred_width; + widget_class->get_preferred_height = gtk_form_get_preferred_height; +#else widget_class->size_request = gtk_form_size_request; +#endif widget_class->size_allocate = gtk_form_size_allocate; +#if GTK_CHECK_VERSION(3,0,0) + widget_class->draw = gtk_form_draw; +#else widget_class->expose_event = gtk_form_expose; +#endif container_class->remove = gtk_form_remove; container_class->forall = gtk_form_forall; @@ -239,15 +297,22 @@ gtk_form_class_init(GtkFormClass *klass) static void gtk_form_init(GtkForm *form) { +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_has_window(GTK_WIDGET(form), TRUE); +#endif form->children = NULL; +#if !GTK_CHECK_VERSION(3,0,0) form->width = 1; form->height = 1; +#endif form->bin_window = NULL; +#if !GTK_CHECK_VERSION(3,0,0) form->configure_serial = 0; form->visibility = GDK_VISIBILITY_PARTIAL; +#endif form->freeze_count = 0; } @@ -267,40 +332,92 @@ gtk_form_realize(GtkWidget *widget) g_return_if_fail(GTK_IS_FORM(widget)); form = GTK_FORM(widget); +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_realized(widget, TRUE); +#else GTK_WIDGET_SET_FLAGS(form, GTK_REALIZED); +#endif attributes.window_type = GDK_WINDOW_CHILD; +#if GTK_CHECK_VERSION(3,0,0) + { + GtkAllocation allocation; + gtk_widget_get_allocation(widget, &allocation); + attributes.x = allocation.x; + attributes.y = allocation.y; + attributes.width = allocation.width; + attributes.height = allocation.height; + } +#else attributes.x = widget->allocation.x; attributes.y = widget->allocation.y; attributes.width = widget->allocation.width; attributes.height = widget->allocation.height; +#endif attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual(widget); +#if GTK_CHECK_VERSION(3,0,0) + attributes.event_mask = GDK_EXPOSURE_MASK; +#else attributes.colormap = gtk_widget_get_colormap(widget); attributes.event_mask = GDK_VISIBILITY_NOTIFY_MASK; +#endif +#if GTK_CHECK_VERSION(3,0,0) + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; +#else attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; +#endif +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_window(widget, + gdk_window_new(gtk_widget_get_parent_window(widget), + &attributes, attributes_mask)); + gdk_window_set_user_data(gtk_widget_get_window(widget), widget); +#else widget->window = gdk_window_new(gtk_widget_get_parent_window(widget), &attributes, attributes_mask); gdk_window_set_user_data(widget->window, widget); +#endif attributes.x = 0; attributes.y = 0; attributes.event_mask = gtk_widget_get_events(widget); +#if GTK_CHECK_VERSION(3,0,0) + form->bin_window = gdk_window_new(gtk_widget_get_window(widget), + &attributes, attributes_mask); +#else form->bin_window = gdk_window_new(widget->window, &attributes, attributes_mask); +#endif gdk_window_set_user_data(form->bin_window, widget); +#if !GTK_CHECK_VERSION(3,16,0) gtk_form_set_static_gravity(form->bin_window, TRUE); +#endif +#if GTK_CHECK_VERSION(3,0,0) + { + GtkStyleContext * const sctx = gtk_widget_get_style_context(widget); + + gtk_style_context_add_class(sctx, "gtk-form"); + gtk_style_context_set_state(sctx, GTK_STATE_FLAG_NORMAL); +# if !GTK_CHECK_VERSION(3,18,0) + gtk_style_context_set_background(sctx, gtk_widget_get_window(widget)); + gtk_style_context_set_background(sctx, form->bin_window); +# endif + } +#else widget->style = gtk_style_attach(widget->style, widget->window); gtk_style_set_background(widget->style, widget->window, GTK_STATE_NORMAL); gtk_style_set_background(widget->style, form->bin_window, GTK_STATE_NORMAL); +#endif +#if !GTK_CHECK_VERSION(3,0,0) gdk_window_add_filter(widget->window, gtk_form_main_filter, form); gdk_window_add_filter(form->bin_window, gtk_form_filter, form); +#endif for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next) { @@ -308,7 +425,11 @@ gtk_form_realize(GtkWidget *widget) gtk_form_attach_child_window(form, child); +#if GTK_CHECK_VERSION(3,0,0) + if (gtk_widget_get_visible(child->widget)) +#else if (GTK_WIDGET_VISIBLE(child->widget)) +#endif gtk_form_realize_child(form, child); } } @@ -332,17 +453,30 @@ gtk_form_map(GtkWidget *widget) form = GTK_FORM(widget); +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_mapped(widget, TRUE); +#else GTK_WIDGET_SET_FLAGS(widget, GTK_MAPPED); +#endif +#if GTK_CHECK_VERSION(3,0,0) + gdk_window_show(gtk_widget_get_window(widget)); +#else gdk_window_show(widget->window); +#endif gdk_window_show(form->bin_window); for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next) { GtkFormChild *child = tmp_list->data; +#if GTK_CHECK_VERSION(3,0,0) + if (gtk_widget_get_visible(child->widget) + && !gtk_widget_get_mapped(child->widget)) +#else if (GTK_WIDGET_VISIBLE(child->widget) && !GTK_WIDGET_MAPPED(child->widget)) +#endif gtk_widget_map(child->widget); } } @@ -369,12 +503,21 @@ gtk_form_unrealize(GtkWidget *widget) if (child->window != NULL) { +#if GTK_CHECK_VERSION(3,0,0) + g_signal_handlers_disconnect_by_func(G_OBJECT(child->widget), + G_CALLBACK(gtk_form_child_map), + child); + g_signal_handlers_disconnect_by_func(G_OBJECT(child->widget), + G_CALLBACK(gtk_form_child_unmap), + child); +#else gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget), GTK_SIGNAL_FUNC(gtk_form_child_map), child); gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget), GTK_SIGNAL_FUNC(gtk_form_child_unmap), child); +#endif gdk_window_set_user_data(child->window, NULL); gdk_window_destroy(child->window); @@ -385,20 +528,33 @@ gtk_form_unrealize(GtkWidget *widget) tmp_list = tmp_list->next; } +#if GTK_CHECK_VERSION(3,0,0) + if (GTK_WIDGET_CLASS (gtk_form_parent_class)->unrealize) + (* GTK_WIDGET_CLASS (gtk_form_parent_class)->unrealize) (widget); +#else if (GTK_WIDGET_CLASS (parent_class)->unrealize) (* GTK_WIDGET_CLASS (parent_class)->unrealize) (widget); +#endif } static void gtk_form_size_request(GtkWidget *widget, GtkRequisition *requisition) { +#if !GTK_CHECK_VERSION(3,0,0) GList *tmp_list; GtkForm *form; +#endif g_return_if_fail(GTK_IS_FORM(widget)); +#if !GTK_CHECK_VERSION(3,0,0) form = GTK_FORM(widget); +#endif +#if GTK_CHECK_VERSION(3,0,0) + requisition->width = 1; + requisition->height = 1; +#else requisition->width = form->width; requisition->height = form->height; @@ -410,7 +566,36 @@ gtk_form_size_request(GtkWidget *widget, GtkRequisition *requisition) gtk_widget_size_request(child->widget, NULL); tmp_list = tmp_list->next; } +#endif +} + +#if GTK_CHECK_VERSION(3,0,0) + static void +gtk_form_get_preferred_width(GtkWidget *widget, + gint *minimal_width, + gint *natural_width) +{ + GtkRequisition requisition; + + gtk_form_size_request(widget, &requisition); + + *minimal_width = requisition.width; + *natural_width = requisition.width; +} + + static void +gtk_form_get_preferred_height(GtkWidget *widget, + gint *minimal_height, + gint *natural_height) +{ + GtkRequisition requisition; + + gtk_form_size_request(widget, &requisition); + + *minimal_height = requisition.height; + *natural_height = requisition.height; } +#endif /* GTK_CHECK_VERSION(3,0,0) */ static void gtk_form_size_allocate(GtkWidget *widget, GtkAllocation *allocation) @@ -418,17 +603,34 @@ gtk_form_size_allocate(GtkWidget *widget, GtkAllocation *allocation) GList *tmp_list; GtkForm *form; gboolean need_reposition; +#if GTK_CHECK_VERSION(3,0,0) + GtkAllocation cur_alloc; +#endif g_return_if_fail(GTK_IS_FORM(widget)); +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_get_allocation(widget, &cur_alloc); + + if (cur_alloc.x == allocation->x + && cur_alloc.y == allocation->y + && cur_alloc.width == allocation->width + && cur_alloc.height == allocation->height) +#else if (widget->allocation.x == allocation->x && widget->allocation.y == allocation->y && widget->allocation.width == allocation->width && widget->allocation.height == allocation->height) +#endif return; +#if GTK_CHECK_VERSION(3,0,0) + need_reposition = cur_alloc.width != allocation->width + || cur_alloc.height != allocation->height; +#else need_reposition = widget->allocation.width != allocation->width || widget->allocation.height != allocation->height; +#endif form = GTK_FORM(widget); if (need_reposition) @@ -444,20 +646,81 @@ gtk_form_size_allocate(GtkWidget *widget, GtkAllocation *allocation) } } +#if GTK_CHECK_VERSION(3,0,0) + if (gtk_widget_get_realized(widget)) +#else if (GTK_WIDGET_REALIZED(widget)) +#endif { +#if GTK_CHECK_VERSION(3,0,0) + gdk_window_move_resize(gtk_widget_get_window(widget), + allocation->x, allocation->y, + allocation->width, allocation->height); +#else gdk_window_move_resize(widget->window, allocation->x, allocation->y, allocation->width, allocation->height); +#endif gdk_window_move_resize(GTK_FORM(widget)->bin_window, 0, 0, allocation->width, allocation->height); } +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_allocation(widget, allocation); +#else widget->allocation = *allocation; +#endif if (need_reposition) gtk_form_send_configure(form); } +#if GTK_CHECK_VERSION(3,0,0) + static void +gtk_form_render_background(GtkWidget *widget, cairo_t *cr) +{ + gtk_render_background(gtk_widget_get_style_context(widget), cr, + 0, 0, + gtk_widget_get_allocated_width(widget), + gtk_widget_get_allocated_height(widget)); +} + + static gboolean +gtk_form_draw(GtkWidget *widget, cairo_t *cr) +{ + GList *tmp_list = NULL; + GtkForm *form = NULL; + + g_return_val_if_fail(GTK_IS_FORM(widget), FALSE); + + gtk_form_render_background(widget, cr); + + form = GTK_FORM(widget); + for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next) + { + GtkFormChild * const formchild = tmp_list->data; + + if (!gtk_widget_get_has_window(formchild->widget) && + gtk_cairo_should_draw_window(cr, formchild->window)) + { + /* To get gtk_widget_draw() to work, it is required to call + * gtk_widget_size_allocate() in advance with a well-posed + * allocation for a given child widget in order to set a + * certain private GtkWidget variable, called + * widget->priv->alloc_need, to the proper value; othewise, + * gtk_widget_draw() fails and the relevant scrollbar won't + * appear on the screen. + * + * Calling gtk_form_position_child() like this is one of ways + * to make sure of that. */ + gtk_form_position_child(form, formchild, TRUE); + + gtk_form_render_background(formchild->widget, cr); + } + } + + return GTK_WIDGET_CLASS(gtk_form_parent_class)->draw(widget, cr); +} +#else /* !GTK_CHECK_VERSION(3,0,0) */ static gint gtk_form_expose(GtkWidget *widget, GdkEventExpose *event) { @@ -497,6 +760,7 @@ gtk_form_expose(GtkWidget *widget, GdkEventExpose *event) return FALSE; } +#endif /* !GTK_CHECK_VERSION(3,0,0) */ /* Container method */ @@ -522,12 +786,22 @@ gtk_form_remove(GtkContainer *container, GtkWidget *widget) if (tmp_list) { +#if GTK_CHECK_VERSION(3,0,0) + const gboolean was_visible = gtk_widget_get_visible(widget); +#endif if (child->window) { +#if GTK_CHECK_VERSION(3,0,0) + g_signal_handlers_disconnect_by_func(G_OBJECT(child->widget), + G_CALLBACK(>k_form_child_map), child); + g_signal_handlers_disconnect_by_func(G_OBJECT(child->widget), + G_CALLBACK(>k_form_child_unmap), child); +#else gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget), GTK_SIGNAL_FUNC(>k_form_child_map), child); gtk_signal_disconnect_by_func(GTK_OBJECT(child->widget), GTK_SIGNAL_FUNC(>k_form_child_unmap), child); +#endif /* FIXME: This will cause problems for reparenting NO_WINDOW * widgets out of a GtkForm @@ -536,7 +810,10 @@ gtk_form_remove(GtkContainer *container, GtkWidget *widget) gdk_window_destroy(child->window); } gtk_widget_unparent(widget); - +#if GTK_CHECK_VERSION(3,0,0) + if (was_visible) + gtk_widget_queue_resize(GTK_WIDGET(container)); +#endif form->children = g_list_remove_link(form->children, tmp_list); g_list_free_1(tmp_list); g_free(child); @@ -577,7 +854,11 @@ gtk_form_attach_child_window(GtkForm *form, GtkFormChild *child) if (child->window != NULL) return; /* been there, done that */ +#if GTK_CHECK_VERSION(3,0,0) + if (!gtk_widget_get_has_window(child->widget)) +#else if (GTK_WIDGET_NO_WINDOW(child->widget)) +#endif { GtkWidget *widget; GdkWindowAttr attributes; @@ -588,34 +869,75 @@ gtk_form_attach_child_window(GtkForm *form, GtkFormChild *child) attributes.window_type = GDK_WINDOW_CHILD; attributes.x = child->x; attributes.y = child->y; +#if GTK_CHECK_VERSION(3,0,0) + { + GtkRequisition requisition; + + gtk_widget_get_preferred_size(child->widget, &requisition, NULL); + + attributes.width = requisition.width; + attributes.height = requisition.height; + } +#else attributes.width = child->widget->requisition.width; attributes.height = child->widget->requisition.height; +#endif attributes.wclass = GDK_INPUT_OUTPUT; attributes.visual = gtk_widget_get_visual(widget); +#if !GTK_CHECK_VERSION(3,0,0) attributes.colormap = gtk_widget_get_colormap(widget); +#endif attributes.event_mask = GDK_EXPOSURE_MASK; +#if GTK_CHECK_VERSION(3,0,0) + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL; +#else attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; +#endif child->window = gdk_window_new(form->bin_window, &attributes, attributes_mask); gdk_window_set_user_data(child->window, widget); +#if GTK_CHECK_VERSION(3,0,0) + { + GtkStyleContext * const sctx = gtk_widget_get_style_context(widget); + + gtk_style_context_set_state(sctx, GTK_STATE_FLAG_NORMAL); +# if !GTK_CHECK_VERSION(3,18,0) + gtk_style_context_set_background(sctx, child->window); +# endif + } +#else gtk_style_set_background(widget->style, child->window, GTK_STATE_NORMAL); +#endif gtk_widget_set_parent_window(child->widget, child->window); +#if !GTK_CHECK_VERSION(3,16,0) gtk_form_set_static_gravity(child->window, TRUE); +#endif /* * Install signal handlers to map/unmap child->window * alongside with the actual widget. */ +#if GTK_CHECK_VERSION(3,0,0) + g_signal_connect(G_OBJECT(child->widget), "map", + G_CALLBACK(>k_form_child_map), child); + g_signal_connect(G_OBJECT(child->widget), "unmap", + G_CALLBACK(>k_form_child_unmap), child); +#else gtk_signal_connect(GTK_OBJECT(child->widget), "map", GTK_SIGNAL_FUNC(>k_form_child_map), child); gtk_signal_connect(GTK_OBJECT(child->widget), "unmap", GTK_SIGNAL_FUNC(>k_form_child_unmap), child); +#endif } +#if GTK_CHECK_VERSION(3,0,0) + else if (!gtk_widget_get_realized(child->widget)) +#else else if (!GTK_WIDGET_REALIZED(child->widget)) +#endif { gtk_widget_set_parent_window(child->widget, form->bin_window); } @@ -627,8 +949,14 @@ gtk_form_realize_child(GtkForm *form, GtkFormChild *child) gtk_form_attach_child_window(form, child); gtk_widget_realize(child->widget); +#if !GTK_CHECK_VERSION(3,16,0) if (child->window == NULL) /* might be already set, see above */ +# if GTK_CHECK_VERSION(3,0,0) + gtk_form_set_static_gravity(gtk_widget_get_window(child->widget), TRUE); +# else gtk_form_set_static_gravity(child->widget->window, TRUE); +# endif +#endif } static void @@ -646,9 +974,18 @@ gtk_form_position_child(GtkForm *form, GtkFormChild *child, { if (!child->mapped) { +#if GTK_CHECK_VERSION(3,0,0) + if (gtk_widget_get_mapped(GTK_WIDGET(form)) + && gtk_widget_get_visible(child->widget)) +#else if (GTK_WIDGET_MAPPED(form) && GTK_WIDGET_VISIBLE(child->widget)) +#endif { +#if GTK_CHECK_VERSION(3,0,0) + if (!gtk_widget_get_mapped(child->widget)) +#else if (!GTK_WIDGET_MAPPED(child->widget)) +#endif gtk_widget_map(child->widget); child->mapped = TRUE; @@ -659,15 +996,31 @@ gtk_form_position_child(GtkForm *form, GtkFormChild *child, if (force_allocate) { GtkAllocation allocation; +#if GTK_CHECK_VERSION(3,0,0) + GtkRequisition requisition; + gtk_widget_get_preferred_size(child->widget, &requisition, NULL); +#endif + +#if GTK_CHECK_VERSION(3,0,0) + if (!gtk_widget_get_has_window(child->widget)) +#else if (GTK_WIDGET_NO_WINDOW(child->widget)) +#endif { if (child->window) { +#if GTK_CHECK_VERSION(3,0,0) + gdk_window_move_resize(child->window, + x, y, + requisition.width, + requisition.height); +#else gdk_window_move_resize(child->window, x, y, child->widget->requisition.width, child->widget->requisition.height); +#endif } allocation.x = 0; @@ -679,8 +1032,13 @@ gtk_form_position_child(GtkForm *form, GtkFormChild *child, allocation.y = y; } +#if GTK_CHECK_VERSION(3,0,0) + allocation.width = requisition.width; + allocation.height = requisition.height; +#else allocation.width = child->widget->requisition.width; allocation.height = child->widget->requisition.height; +#endif gtk_widget_size_allocate(child->widget, &allocation); } @@ -691,7 +1049,11 @@ gtk_form_position_child(GtkForm *form, GtkFormChild *child, { child->mapped = FALSE; +#if GTK_CHECK_VERSION(3,0,0) + if (gtk_widget_get_mapped(child->widget)) +#else if (GTK_WIDGET_MAPPED(child->widget)) +#endif gtk_widget_unmap(child->widget); } } @@ -717,6 +1079,7 @@ gtk_form_position_children(GtkForm *form) * them or discards them, depending on whether we are obscured * or not. */ +#if !GTK_CHECK_VERSION(3,0,0) static GdkFilterReturn gtk_form_filter(GdkXEvent *gdk_xevent, GdkEvent *event UNUSED, gpointer data) { @@ -783,7 +1146,9 @@ gtk_form_main_filter(GdkXEvent *gdk_xevent, } return GDK_FILTER_CONTINUE; } +#endif /* !GTK_CHECK_VERSION(3,0,0) */ +#if !GTK_CHECK_VERSION(3,16,0) static void gtk_form_set_static_gravity(GdkWindow *window, gboolean use_static) { @@ -791,13 +1156,18 @@ gtk_form_set_static_gravity(GdkWindow *window, gboolean use_static) * results in an annoying assertion error message. */ gdk_window_set_static_gravities(window, use_static); } +#endif /* !GTK_CHECK_VERSION(3,16,0) */ void gtk_form_move_resize(GtkForm *form, GtkWidget *widget, gint x, gint y, gint w, gint h) { +#if GTK_CHECK_VERSION(3,0,0) + gtk_widget_set_size_request(widget, w, h); +#else widget->requisition.width = w; widget->requisition.height = h; +#endif gtk_form_move(form, widget, x, y); } @@ -811,11 +1181,24 @@ gtk_form_send_configure(GtkForm *form) widget = GTK_WIDGET(form); event.type = GDK_CONFIGURE; +#if GTK_CHECK_VERSION(3,0,0) + event.window = gtk_widget_get_window(widget); + { + GtkAllocation allocation; + + gtk_widget_get_allocation(widget, &allocation); + event.x = allocation.x; + event.y = allocation.y; + event.width = allocation.width; + event.height = allocation.height; + } +#else event.window = widget->window; event.x = widget->allocation.x; event.y = widget->allocation.y; event.width = widget->allocation.width; event.height = widget->allocation.height; +#endif gtk_main_do_event((GdkEvent*)&event); } @@ -841,4 +1224,3 @@ gtk_form_child_unmap(GtkWidget *widget UNUSED, gpointer user_data) child->mapped = FALSE; gdk_window_hide(child->window); } - diff --git a/src/gui_gtk_f.h b/src/gui_gtk_f.h index 73b0024f8..fa0f40aa3 100644 --- a/src/gui_gtk_f.h +++ b/src/gui_gtk_f.h @@ -9,8 +9,12 @@ #ifndef __GTK_FORM_H__ #define __GTK_FORM_H__ +#ifdef USE_GTK3 +#include <gtk/gtk.h> +#else #include <gdk/gdk.h> #include <gtk/gtkcontainer.h> +#endif #ifdef __cplusplus @@ -18,10 +22,17 @@ extern "C" { #endif #define GTK_TYPE_FORM (gtk_form_get_type ()) +#ifdef USE_GTK3 +#define GTK_FORM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GTK_TYPE_FORM, GtkForm)) +#define GTK_FORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GTK_TYPE_FORM, GtkFormClass)) +#define GTK_IS_FORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GTK_TYPE_FORM)) +#define GTK_IS_FORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GTK_TYPE_FORM)) +#else #define GTK_FORM(obj) (GTK_CHECK_CAST ((obj), GTK_TYPE_FORM, GtkForm)) #define GTK_FORM_CLASS(klass) (GTK_CHECK_CLASS_CAST ((klass), GTK_TYPE_FORM, GtkFormClass)) #define GTK_IS_FORM(obj) (GTK_CHECK_TYPE ((obj), GTK_TYPE_FORM)) #define GTK_IS_FORM_CLASS(klass) (GTK_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FORM)) +#endif typedef struct _GtkForm GtkForm; @@ -33,13 +44,17 @@ struct _GtkForm GList *children; +#ifndef USE_GTK3 guint width; guint height; +#endif GdkWindow *bin_window; +#ifndef USE_GTK3 GdkVisibilityState visibility; gulong configure_serial; +#endif gint freeze_count; }; @@ -49,7 +64,11 @@ struct _GtkFormClass GtkContainerClass parent_class; }; +#ifdef USE_GTK3 +GType gtk_form_get_type(void); +#else GtkType gtk_form_get_type(void); +#endif GtkWidget *gtk_form_new(void); 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); } diff --git a/src/if_mzsch.c b/src/if_mzsch.c index 0a3c201f3..4be3c7201 100644 --- a/src/if_mzsch.c +++ b/src/if_mzsch.c @@ -852,7 +852,11 @@ static int mz_threads_allow = 0; static void CALLBACK timer_proc(HWND, UINT, UINT, DWORD); static UINT timer_id = 0; #elif defined(FEAT_GUI_GTK) +# if GTK_CHECK_VERSION(3,0,0) +static gboolean timer_proc(gpointer); +# else static gint timer_proc(gpointer); +# endif static guint timer_id = 0; #elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) static void timer_proc(XtPointer, XtIntervalId *); @@ -892,7 +896,11 @@ static void remove_timer(void); static void CALLBACK timer_proc(HWND hwnd UNUSED, UINT uMsg UNUSED, UINT idEvent UNUSED, DWORD dwTime UNUSED) # elif defined(FEAT_GUI_GTK) +# if GTK_CHECK_VERSION(3,0,0) + static gboolean +# else static gint +# endif timer_proc(gpointer data UNUSED) # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) static void @@ -919,7 +927,11 @@ setup_timer(void) # if defined(FEAT_GUI_W32) timer_id = SetTimer(NULL, 0, p_mzq, timer_proc); # elif defined(FEAT_GUI_GTK) +# if GTK_CHECK_VERSION(3,0,0) + timer_id = g_timeout_add((guint)p_mzq, (GSourceFunc)timer_proc, NULL); +# else timer_id = gtk_timeout_add((guint32)p_mzq, (GtkFunction)timer_proc, NULL); +# endif # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) timer_id = XtAppAddTimeOut(app_context, p_mzq, timer_proc, NULL); # elif defined(FEAT_GUI_MAC) @@ -935,7 +947,11 @@ remove_timer(void) # if defined(FEAT_GUI_W32) KillTimer(NULL, timer_id); # elif defined(FEAT_GUI_GTK) +# if GTK_CHECK_VERSION(3,0,0) + g_source_remove(timer_id); +# else gtk_timeout_remove(timer_id); +# endif # elif defined(FEAT_GUI_MOTIF) || defined(FEAT_GUI_ATHENA) XtRemoveTimeOut(timer_id); # elif defined(FEAT_GUI_MAC) diff --git a/src/mbyte.c b/src/mbyte.c index 16092843b..b44168ded 100644 --- a/src/mbyte.c +++ b/src/mbyte.c @@ -109,7 +109,11 @@ #endif #if defined(FEAT_GUI_GTK) && defined(FEAT_XIM) -# include <gdk/gdkkeysyms.h> +# if GTK_CHECK_VERSION(3,0,0) +# include <gdk/gdkkeysyms-compat.h> +# else +# include <gdk/gdkkeysyms.h> +# endif # ifdef WIN3264 # include <gdk/gdkwin32.h> # else @@ -4941,7 +4945,11 @@ xim_init(void) #endif g_return_if_fail(gui.drawarea != NULL); +#if GTK_CHECK_VERSION(3,0,0) + g_return_if_fail(gtk_widget_get_window(gui.drawarea) != NULL); +#else g_return_if_fail(gui.drawarea->window != NULL); +#endif xic = gtk_im_multicontext_new(); g_object_ref(xic); @@ -4955,7 +4963,11 @@ xim_init(void) g_signal_connect(G_OBJECT(xic), "preedit_end", G_CALLBACK(&im_preedit_end_cb), NULL); +#if GTK_CHECK_VERSION(3,0,0) + gtk_im_context_set_client_window(xic, gtk_widget_get_window(gui.drawarea)); +#else gtk_im_context_set_client_window(xic, gui.drawarea->window); +#endif } void @@ -5054,12 +5066,21 @@ im_synthesize_keypress(unsigned int keyval, unsigned int state) # ifdef HAVE_GTK_MULTIHEAD event = (GdkEventKey *)gdk_event_new(GDK_KEY_PRESS); +# if GTK_CHECK_VERSION(3,0,0) + g_object_ref(gtk_widget_get_window(gui.drawarea)); + /* unreffed by gdk_event_free() */ +# else g_object_ref(gui.drawarea->window); /* unreffed by gdk_event_free() */ +# endif # else event = (GdkEventKey *)g_malloc0((gulong)sizeof(GdkEvent)); event->type = GDK_KEY_PRESS; # endif +# if GTK_CHECK_VERSION(3,0,0) + event->window = gtk_widget_get_window(gui.drawarea); +# else event->window = gui.drawarea->window; +# endif event->send_event = TRUE; event->time = GDK_CURRENT_TIME; event->state = state; diff --git a/src/netbeans.c b/src/netbeans.c index ca0278eee..44a725e1e 100644 --- a/src/netbeans.c +++ b/src/netbeans.c @@ -3055,17 +3055,56 @@ netbeans_draw_multisign_indicator(int row) int i; int y; int x; +#if GTK_CHECK_VERSION(3,0,0) + cairo_t *cr = NULL; +#else GdkDrawable *drawable = gui.drawarea->window; +#endif if (!NETBEANS_OPEN) return; +#if GTK_CHECK_VERSION(3,0,0) + cr = cairo_create(gui.surface); + { + GdkVisual *visual = NULL; + guint32 r_mask, g_mask, b_mask; + gint r_shift, g_shift, b_shift; + + visual = gdk_window_get_visual(gtk_widget_get_window(gui.drawarea)); + if (visual != NULL) + { + 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); + + cairo_set_source_rgb(cr, + ((gui.fgcolor->red & r_mask) >> r_shift) / 255.0, + ((gui.fgcolor->green & g_mask) >> g_shift) / 255.0, + ((gui.fgcolor->blue & b_mask) >> b_shift) / 255.0); + } + } +#endif + x = 0; y = row * gui.char_height + 2; for (i = 0; i < gui.char_height - 3; i++) +#if GTK_CHECK_VERSION(3,0,0) + cairo_rectangle(cr, x+2, y++, 1, 1); +#else gdk_draw_point(drawable, gui.text_gc, x+2, y++); +#endif +#if GTK_CHECK_VERSION(3,0,0) + cairo_rectangle(cr, x+0, y, 1, 1); + cairo_rectangle(cr, x+2, y, 1, 1); + cairo_rectangle(cr, x+4, y++, 1, 1); + cairo_rectangle(cr, x+1, y, 1, 1); + cairo_rectangle(cr, x+2, y, 1, 1); + cairo_rectangle(cr, x+3, y++, 1, 1); + cairo_rectangle(cr, x+2, y, 1, 1); +#else gdk_draw_point(drawable, gui.text_gc, x+0, y); gdk_draw_point(drawable, gui.text_gc, x+2, y); gdk_draw_point(drawable, gui.text_gc, x+4, y++); @@ -3073,6 +3112,11 @@ netbeans_draw_multisign_indicator(int row) gdk_draw_point(drawable, gui.text_gc, x+2, y); gdk_draw_point(drawable, gui.text_gc, x+3, y++); gdk_draw_point(drawable, gui.text_gc, x+2, y); +#endif + +#if GTK_CHECK_VERSION(3,0,0) + cairo_destroy(cr); +#endif } #endif /* FEAT_GUI_GTK */ diff --git a/src/structs.h b/src/structs.h index c47eef31a..95b33c3a0 100644 --- a/src/structs.h +++ b/src/structs.h @@ -2736,7 +2736,9 @@ struct VimMenu #ifdef FEAT_GUI_GTK GtkWidget *id; /* Manage this to enable item */ GtkWidget *submenu_id; /* If this is submenu, add children here */ +# if defined(GTK_CHECK_VERSION) && !GTK_CHECK_VERSION(3,4,0) GtkWidget *tearoff_handle; +# endif GtkWidget *label; /* Used by "set wak=" code. */ #endif #ifdef FEAT_GUI_MOTIF diff --git a/src/version.c b/src/version.c index f3fc7c942..94f7b36e7 100644 --- a/src/version.c +++ b/src/version.c @@ -749,6 +749,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1402, +/**/ 1401, /**/ 1400, @@ -3824,11 +3826,15 @@ list_version(void) MSG_PUTS(_("without GUI.")); #else # ifdef FEAT_GUI_GTK -# ifdef FEAT_GUI_GNOME - MSG_PUTS(_("with GTK2-GNOME GUI.")); +# ifdef USE_GTK3 + MSG_PUTS(_("with GTK3 GUI.")); # else - MSG_PUTS(_("with GTK2 GUI.")); -# endif +# ifdef FEAT_GUI_GNOME + MSG_PUTS(_("with GTK2-GNOME GUI.")); +# else + MSG_PUTS(_("with GTK2 GUI.")); +# endif +# endif # else # ifdef FEAT_GUI_MOTIF MSG_PUTS(_("with X11-Motif GUI.")); |