patch 9.2.0501: GTK4: there is no GTK4 UI available

Problem:  GTK4: there is no GTK4 UI available
Solution: Implement GTK4 UI (Yasuhiro Matsumoto).

To enable, use the --enable-gui=gtk4 configure switch. Configure
currently favors GTK3 over GTK4 if no explicit --enable-gui switch has
been given and both libraries are present

closes: #19815

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Yasuhiro Matsumoto <mattn.jp@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
Yasuhiro Matsumoto
2026-05-19 18:13:27 +00:00
committed by Christian Brabandt
parent d004cc4f89
commit da5ebe71cb
25 changed files with 5655 additions and 41 deletions
@@ -88,6 +88,7 @@ runs:
sudo cp ci/pinned-pkgs /etc/apt/preferences.d/pinned-pkgs
echo '::endgroup::'
# TODO: switch to GTK4 GUI
- name: Install packages
shell: bash
run: |
+4
View File
@@ -498,6 +498,9 @@ SRC_UNIX = \
src/gui_gtk_f.c \
src/gui_gtk_f.h \
src/gui_gtk_x11.c \
src/gui_gtk4.c \
src/gui_gtk4_f.c \
src/gui_gtk4_f.h \
src/gui_gtk_res.xml \
src/gui_motif.c \
src/gui_xmdlg.c \
@@ -527,6 +530,7 @@ SRC_UNIX = \
src/proto/gui_gtk.pro \
src/proto/gui_gtk_x11.pro \
src/proto/gui_gtk_gresources.pro \
src/proto/gui_gtk4.pro \
src/proto/gui_motif.pro \
src/proto/gui_xmdlg.pro \
src/proto/gui_x11.pro \
+5 -1
View File
@@ -65,7 +65,11 @@ To build Vim on Ubuntu from scratch on a clean system using git:
% sudo apt install libwayland-dev
% make reconfig
Add GUI support:
Add GUI (GTK3) support:
% sudo apt install libgtk-3-dev
% make reconfig
Add GUI (GTK4) support:
% sudo apt install libgtk-3-dev
% make reconfig
+27 -2
View File
@@ -1232,6 +1232,23 @@ GTK_MAN_TARGETS = yes
GTK_TESTTARGET = gui
GTK_BUNDLE =
### GTK4 GUI
GTK4_SRC = gui.c gui_gtk4.c gui_gtk4_f.c \
$(GRESOURCE_SRC)
GTK4_OBJ = objects/gui.o objects/gui_gtk4.o \
objects/gui_gtk4_f.o \
$(GRESOURCE_OBJ)
GTK4_DEFS = -DFEAT_GUI_GTK $(NARROW_PROTO)
GTK4_IPATH = $(GUI_INC_LOC)
GTK4_LIBS_DIR = $(GUI_LIB_LOC)
GTK4_LIBS1 =
GTK4_LIBS2 = $(GTK_LIBNAME)
GTK4_INSTALL = install_normal install_gui_extra
GTK4_TARGETS = installglinks
GTK4_MAN_TARGETS = yes
GTK4_TESTTARGET = gui
GTK4_BUNDLE =
### Motif GUI
MOTIF_SRC = gui.c gui_motif.c gui_x11.c gui_beval.c \
gui_xmdlg.c gui_xmebw.c
@@ -1289,8 +1306,8 @@ HAIKUGUI_TESTTARGET = gui
HAIKUGUI_BUNDLE =
# All GUI files
ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_motif.c gui_xmdlg.c gui_xmebw.c gui_gtk_x11.c gui_x11.c gui_haiku.cc
ALL_GUI_PRO = proto/gui.pro proto/gui_gtk.pro proto/gui_motif.pro proto/gui_xmdlg.pro proto/gui_gtk_x11.pro proto/gui_x11.pro proto/gui_w32.pro proto/gui_photon.pro
ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_gtk4.c gui_gtk4_f.c gui_motif.c gui_xmdlg.c gui_xmebw.c gui_gtk_x11.c gui_x11.c gui_haiku.cc
ALL_GUI_PRO = proto/gui.pro proto/gui_gtk.pro proto/gui_gtk4.pro proto/gui_motif.pro proto/gui_xmdlg.pro proto/gui_gtk_x11.pro proto/gui_x11.pro proto/gui_w32.pro proto/gui_photon.pro
# }}}
@@ -3364,6 +3381,13 @@ objects/gui_gtk_gresources.o: auto/gui_gtk_gresources.c
objects/gui_gtk_x11.o: gui_gtk_x11.c
$(CCC) -o $@ gui_gtk_x11.c
objects/gui_gtk4.o: gui_gtk4.c
$(CCC) -o $@ gui_gtk4.c
objects/gui_gtk4_f.o: gui_gtk4_f.c
$(CCC) -o $@ gui_gtk4_f.c
objects/gui_haiku.o: gui_haiku.cc
$(CCC) -o $@ gui_haiku.cc
@@ -4797,6 +4821,7 @@ proto/winclip.pro: winclip.c
proto/window.pro: window.c
proto/gui.pro: gui.c
proto/gui_gtk.pro: gui_gtk.c
proto/gui_gtk4.pro: gui_gtk4.c
proto/gui_motif.pro: gui_motif.c
proto/gui_xmdlg.pro: gui_xmdlg.c
proto/gui_gtk_x11.pro: gui_gtk_x11.c
+226 -5
View File
@@ -862,6 +862,7 @@ with_x
enable_gui
enable_gtk2_check
enable_gnome_check
enable_gtk4_check
enable_gtk3_check
enable_motif_check
enable_gtktest
@@ -1538,9 +1539,10 @@ Optional Features:
--disable-farsi Deprecated.
--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/gtk3/motif/haiku/photon/carbon
--enable-gui=OPTS X11 GUI. default=auto OPTS=auto/no/gtk2/gnome2/gtk3/gtk4/motif/haiku/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-gtk4-check If auto-select GUI, check for GTK 4 default=yes
--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
--disable-gtktest Do not try to compile and run a test GTK program
@@ -10486,6 +10488,7 @@ enable_gui_canon=`echo "_$enable_gui" | \
SKIP_GTK2=YES
SKIP_GTK3=YES
SKIP_GTK4=YES
SKIP_GNOME=YES
SKIP_MOTIF=YES
SKIP_PHOTON=YES
@@ -10516,7 +10519,7 @@ printf "%s\n" "no GUI support" >&6; }
SKIP_PHOTON=YES ;;
yes|""|auto) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: automatic GUI support" >&5
printf "%s\n" "automatic GUI support" >&6; }
gui_auto=yes ;;
gui_auto=yes ;;
photon) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Photon GUI support" >&5
printf "%s\n" "Photon GUI support" >&6; } ;;
*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Sorry, $enable_gui GUI is not supported" >&5
@@ -10530,7 +10533,7 @@ elif test "x$MACOS_X" = "xyes" -a "x$with_x" = "xno" ; then
printf "%s\n" "no GUI support" >&6; } ;;
yes|"") { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes - automatic GUI support" >&5
printf "%s\n" "yes - automatic GUI support" >&6; }
gui_auto=yes ;;
gui_auto=yes ;;
auto) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: auto - disable GUI support for Mac OS" >&5
printf "%s\n" "auto - disable GUI support for Mac OS" >&6; } ;;
*) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Sorry, $enable_gui GUI is not supported" >&5
@@ -10546,6 +10549,7 @@ printf "%s\n" "yes/auto - automatic GUI support" >&6; }
gui_auto=yes
SKIP_GTK2=
SKIP_GTK3=
SKIP_GTK4=
SKIP_GNOME=
SKIP_MOTIF=;;
gtk2) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: GTK+ 2.x GUI support" >&5
@@ -10558,6 +10562,9 @@ printf "%s\n" "GNOME 2.x GUI support" >&6; }
gtk3) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: GTK+ 3.x GUI support" >&5
printf "%s\n" "GTK+ 3.x GUI support" >&6; }
SKIP_GTK3=;;
gtk4) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: GTK 4.x GUI support" >&5
printf "%s\n" "GTK 4.x GUI support" >&6; }
SKIP_GTK4=;;
motif) { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: Motif GUI support" >&5
printf "%s\n" "Motif GUI support" >&6; }
SKIP_MOTIF=;;
@@ -10607,6 +10614,25 @@ printf "%s\n" "$enable_gnome_check" >&6; }
fi
fi
if test "x$SKIP_GTK4" != "xYES" -a "$enable_gui_canon" != "gtk4"; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether or not to look for GTK 4" >&5
printf %s "checking whether or not to look for GTK 4... " >&6; }
# Check whether --enable-gtk4-check was given.
if test ${enable_gtk4_check+y}
then :
enableval=$enable_gtk4_check;
else case e in #(
e) enable_gtk4_check="yes" ;;
esac
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $enable_gtk4_check" >&5
printf "%s\n" "$enable_gtk4_check" >&6; }
if test "x$enable_gtk4_check" = "xno"; then
SKIP_GTK4=YES
fi
fi
if test "x$SKIP_GTK3" != "xYES" -a "$enable_gui_canon" != "gtk3"; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether or not to look for GTK+ 3" >&5
printf %s "checking whether or not to look for GTK+ 3... " >&6; }
@@ -10681,6 +10707,8 @@ printf "%s\n" "gtk test disabled" >&6; }
gtk_pkg_name="gtk+-2.0" ;; #(
3.*) :
gtk_pkg_name="gtk+-3.0" ;; #(
4.*) :
gtk_pkg_name="gtk4" ;; #(
*) :
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
@@ -10697,7 +10725,7 @@ then :
printf "%s\n" "found" >&6; }
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5
printf %s "checking for GTK - version >= $min_gtk_version... " >&6; }
GTK_CPPFLAGS=`$PKG_CONFIG --cflags-only-I $gtk_pkg_name`
GTK_CPPFLAGS=`$PKG_CONFIG --cflags-only-I $gtk_pkg_name`
GTK_CFLAGS=`$PKG_CONFIG --cflags-only-other $gtk_pkg_name`
GTK_LIBDIR=`$PKG_CONFIG --libs-only-L $gtk_pkg_name`
GTK_LIBS=`$PKG_CONFIG --libs $gtk_pkg_name`
@@ -10821,6 +10849,7 @@ fi
if test -n "$GTK_CPPFLAGS"; then
SKIP_GTK2=YES
SKIP_GTK4=YES
SKIP_GNOME=YES
SKIP_MOTIF=YES
GUITYPE=GTK
@@ -10831,6 +10860,196 @@ fi
fi
fi
if test -z "$SKIP_GTK4"; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking --disable-gtktest argument" >&5
printf %s "checking --disable-gtktest argument... " >&6; }
# Check whether --enable-gtktest was given.
if test ${enable_gtktest+y}
then :
enableval=$enable_gtktest;
else case e in #(
e) enable_gtktest=yes ;;
esac
fi
if test "x$enable_gtktest" = "xyes" ; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: gtk test enabled" >&5
printf "%s\n" "gtk test enabled" >&6; }
else
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: gtk test disabled" >&5
printf "%s\n" "gtk test disabled" >&6; }
fi
if test "x$PKG_CONFIG" != "xno"; then
min_gtk_version="4.0.0"
if test "$PKG_CONFIG" != "no"; then
case $min_gtk_version in #(
2.*) :
gtk_pkg_name="gtk+-2.0" ;; #(
3.*) :
gtk_pkg_name="gtk+-3.0" ;; #(
4.*) :
gtk_pkg_name="gtk4" ;; #(
*) :
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
as_fn_error $? "The configure script does not know which pkg-config name to use for GTK $min_gtk_version\"
See 'config.log' for more details" "$LINENO" 5; } ;;
esac
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for pkg-config $gtk_pkg_name" >&5
printf %s "checking for pkg-config $gtk_pkg_name... " >&6; }
if "$PKG_CONFIG" --exists "$gtk_pkg_name"
then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: found" >&5
printf "%s\n" "found" >&6; }
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5
printf %s "checking for GTK - version >= $min_gtk_version... " >&6; }
GTK_CPPFLAGS=`$PKG_CONFIG --cflags-only-I $gtk_pkg_name`
GTK_CFLAGS=`$PKG_CONFIG --cflags-only-other $gtk_pkg_name`
GTK_LIBDIR=`$PKG_CONFIG --libs-only-L $gtk_pkg_name`
GTK_LIBS=`$PKG_CONFIG --libs $gtk_pkg_name`
gtk_major_version=`$PKG_CONFIG --modversion $gtk_pkg_name | \
sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\1/'`
gtk_minor_version=`$PKG_CONFIG --modversion $gtk_pkg_name | \
sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\2/'`
gtk_micro_version=`$PKG_CONFIG --modversion $gtk_pkg_name | \
sed 's/\([0-9]*\)\.\([0-9]*\)\.\([0-9]*\)/\3/'`
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&5
printf "%s\n" "yes; found version $gtk_major_version.$gtk_minor_version.$gtk_micro_version" >&6; }
else case e in #(
e)
GTK_CPPFLAGS=""
GTK_CFLAGS=""
GTK_LIBDIR=""
GTK_LIBS=""
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no; consider installing your distro GTK -dev package" >&5
printf "%s\n" "no; consider installing your distro GTK -dev package" >&6; }
if test "$fail_if_missing" = "yes" -a "$gui_auto" != "yes"; then
as_fn_error $? "pkg-config could not find $gtk_pkg_name" "$LINENO" 5
fi
;;
esac
fi
fi
gtktest_success="yes"
if test "$enable_gtktest" = "yes"; then
{
ac_save_CPPFLAGS="$CPPFLAGS"
ac_save_CFLAGS="$CFLAGS"
ac_save_LIBS="$LIBS"
CPPFLAGS="$CPPFLAGS $GTK_CPPFLAGS"
CFLAGS="$CFLAGS $GTK_CFLAGS"
LIBS="$LIBS $GTK_LIBS"
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking ability to compile GTK test program" >&5
printf %s "checking ability to compile GTK test program... " >&6; }
if test "$cross_compiling" = yes
then :
echo $ac_n "cross compiling; assumed OK... $ac_c"
else case e in #(
e) 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 ex_major = $gtk_major_version;
int ex_minor = $gtk_minor_version;
int ex_micro = $gtk_micro_version;
#if $gtk_major_version == 2
guint ob_major = gtk_major_version;
guint ob_minor = gtk_minor_version;
guint ob_micro = gtk_micro_version;
#else
guint ob_major = gtk_get_major_version();
guint ob_minor = gtk_get_minor_version();
guint ob_micro = gtk_get_micro_version();
#endif
if ((ob_major > ex_major) ||
((ob_major == ex_major)
&& (ob_minor > ex_minor)) ||
((ob_major == ex_major)
&& (ob_minor == ex_minor)
&& (ob_micro >= ex_micro)))
return 0;
else
return 1;
}
_ACEOF
if ac_fn_c_try_run "$LINENO"
then :
gtktest_success="yes"; { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
else case e in #(
e) gtktest_success="no"; { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; } ;;
esac
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext ;;
esac
fi
CPPFLAGS="$ac_save_CPPFLAGS"
CFLAGS="$ac_save_CFLAGS"
LIBS="$ac_save_LIBS"
}
fi
if test "$gtktest_success" = "yes"; then
GUI_LIB_LOC="$GTK_LIBDIR"
GTK_LIBNAME="$GTK_LIBS"
GUI_INC_LOC="$GTK_CPPFLAGS"
else
GTK_CPPFLAGS=""
GTK_CFLAGS=""
GTK_LIBDIR=""
GTK_LIBS=""
if test "$fail_if_missing" = "yes" -a "$gui_auto" != "yes"; then
as_fn_error $? "Failed to compile GTK test program." "$LINENO" 5
fi
fi
if test -n "$GTK_CPPFLAGS"; then
SKIP_GTK3=YES
SKIP_GTK2=YES
SKIP_GNOME=YES
SKIP_MOTIF=YES
GUITYPE=GTK4
printf "%s\n" "#define USE_GTK4 1" >>confdefs.h
X_LIBS=
X_PRE_LIBS=
X_EXTRA_LIBS=
X_LIB=
if test "$enable_xim" = "auto"; then
enable_xim="yes"
fi
fi
fi
fi
if test -z "$SKIP_GTK2"; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking --disable-gtktest argument" >&5
printf %s "checking --disable-gtktest argument... " >&6; }
@@ -10861,6 +11080,8 @@ printf "%s\n" "gtk test disabled" >&6; }
gtk_pkg_name="gtk+-2.0" ;; #(
3.*) :
gtk_pkg_name="gtk+-3.0" ;; #(
4.*) :
gtk_pkg_name="gtk4" ;; #(
*) :
{ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: error: in '$ac_pwd':" >&5
printf "%s\n" "$as_me: error: in '$ac_pwd':" >&2;}
@@ -10877,7 +11098,7 @@ then :
printf "%s\n" "found" >&6; }
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GTK - version >= $min_gtk_version" >&5
printf %s "checking for GTK - version >= $min_gtk_version... " >&6; }
GTK_CPPFLAGS=`$PKG_CONFIG --cflags-only-I $gtk_pkg_name`
GTK_CPPFLAGS=`$PKG_CONFIG --cflags-only-I $gtk_pkg_name`
GTK_CFLAGS=`$PKG_CONFIG --cflags-only-other $gtk_pkg_name`
GTK_LIBDIR=`$PKG_CONFIG --libs-only-L $gtk_pkg_name`
GTK_LIBS=`$PKG_CONFIG --libs $gtk_pkg_name`
+1 -1
View File
@@ -11,7 +11,7 @@
#define BEVAL__H
#ifdef FEAT_GUI_GTK
# ifdef USE_GTK3
# if defined(USE_GTK3) || defined(USE_GTK4)
# include <gtk/gtk.h>
# else
# include <gtk/gtkwidget.h>
+3 -2
View File
@@ -1891,7 +1891,8 @@ clip_x11_set_selection(Clipboard_T *cbd UNUSED)
# endif
# if defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
# if (defined(FEAT_XCLIPBOARD) || defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)) \
&& !defined(USE_GTK4)
/*
* Get the contents of the X CUT_BUFFER0 and put it in "cbd".
*/
@@ -3298,7 +3299,7 @@ did_set_clipboard(optset_T *args UNUSED)
vim_regfree(clip_exclude_prog);
clip_exclude_prog = new_exclude_prog;
# endif
# ifdef FEAT_GUI_GTK
# if defined(FEAT_GUI_GTK) && !defined(USE_GTK4)
if (gui.in_use)
{
gui_gtk_set_selection_targets((GdkAtom)GDK_SELECTION_PRIMARY);
+3
View File
@@ -496,6 +496,9 @@
/* Define if GTK+ GUI is to be linked against GTK+ 3 */
#undef USE_GTK3
/* Define if GTK GUI is to be linked against GTK 4 */
#undef USE_GTK4
/* Define if we have isinf() */
#undef HAVE_ISINF
+65 -7
View File
@@ -2613,7 +2613,7 @@ test "x$with_x" = xno -a "x$HAIKU" != "xyes" -a "x$MACOS_X" != "xyes" -a "x$QNX"
AC_MSG_CHECKING(--enable-gui argument)
AC_ARG_ENABLE(gui,
[ --enable-gui[=OPTS] X11 GUI. [default=auto] [OPTS=auto/no/gtk2/gnome2/gtk3/motif/haiku/photon/carbon]], , enable_gui="auto")
[ --enable-gui[=OPTS] X11 GUI. [default=auto] [OPTS=auto/no/gtk2/gnome2/gtk3/gtk4/motif/haiku/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.
@@ -2623,6 +2623,7 @@ enable_gui_canon=`echo "_$enable_gui" | \
dnl Skip everything by default.
SKIP_GTK2=YES
SKIP_GTK3=YES
SKIP_GTK4=YES
SKIP_GNOME=YES
SKIP_MOTIF=YES
SKIP_PHOTON=YES
@@ -2646,7 +2647,7 @@ elif test "x$QNX" = "xyes" -a "x$with_x" = "xno" ; then
no) AC_MSG_RESULT(no GUI support)
SKIP_PHOTON=YES ;;
yes|""|auto) AC_MSG_RESULT(automatic GUI support)
gui_auto=yes ;;
gui_auto=yes ;;
photon) AC_MSG_RESULT(Photon GUI support) ;;
*) AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported])
SKIP_PHOTON=YES ;;
@@ -2656,7 +2657,7 @@ elif test "x$MACOS_X" = "xyes" -a "x$with_x" = "xno" ; then
case "$enable_gui_canon" in
no) AC_MSG_RESULT(no GUI support) ;;
yes|"") AC_MSG_RESULT(yes - automatic GUI support)
gui_auto=yes ;;
gui_auto=yes ;;
auto) AC_MSG_RESULT(auto - disable GUI support for Mac OS) ;;
*) AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported]) ;;
esac
@@ -2668,6 +2669,7 @@ else
gui_auto=yes
SKIP_GTK2=
SKIP_GTK3=
SKIP_GTK4=
SKIP_GNOME=
SKIP_MOTIF=;;
gtk2) AC_MSG_RESULT(GTK+ 2.x GUI support)
@@ -2677,6 +2679,8 @@ else
SKIP_GTK2=;;
gtk3) AC_MSG_RESULT(GTK+ 3.x GUI support)
SKIP_GTK3=;;
gtk4) AC_MSG_RESULT(GTK 4.x GUI support)
SKIP_GTK4=;;
motif) AC_MSG_RESULT(Motif GUI support)
SKIP_MOTIF=;;
*) AC_MSG_RESULT([Sorry, $enable_gui GUI is not supported]) ;;
@@ -2708,6 +2712,17 @@ if test "x$SKIP_GNOME" != "xYES" -a "$enable_gui_canon" != "gnome2"; then
fi
fi
if test "x$SKIP_GTK4" != "xYES" -a "$enable_gui_canon" != "gtk4"; then
AC_MSG_CHECKING(whether or not to look for GTK 4)
AC_ARG_ENABLE(gtk4-check,
[ --enable-gtk4-check If auto-select GUI, check for GTK 4 [default=yes]],
, enable_gtk4_check="yes")
AC_MSG_RESULT($enable_gtk4_check)
if test "x$enable_gtk4_check" = "xno"; then
SKIP_GTK4=YES
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,
@@ -2747,6 +2762,7 @@ AC_DEFUN(AM_PATH_GTK,
AS_CASE([$min_gtk_version],
[2.*], [gtk_pkg_name="gtk+-2.0"],
[3.*], [gtk_pkg_name="gtk+-3.0"],
[4.*], [gtk_pkg_name="gtk4"],
[AC_MSG_FAILURE([The configure script does not know which pkg-config name to use for GTK $min_gtk_version"])])
AC_MSG_CHECKING([for pkg-config $gtk_pkg_name])
@@ -2754,9 +2770,9 @@ AC_DEFUN(AM_PATH_GTK,
[
AC_MSG_RESULT(found)
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.
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.
GTK_CPPFLAGS=`$PKG_CONFIG --cflags-only-I $gtk_pkg_name`
GTK_CFLAGS=`$PKG_CONFIG --cflags-only-other $gtk_pkg_name`
GTK_LIBDIR=`$PKG_CONFIG --libs-only-L $gtk_pkg_name`
@@ -2935,7 +2951,7 @@ AC_DEFUN([GNOME_INIT],[
])
dnl ---------------------------------------------------------------------------
dnl Check for GTK3. If it succeeds, skip the check for GTK2.
dnl Check for GTK3. If it succeeds, skip the check for GTK2/GTK4
dnl ---------------------------------------------------------------------------
if test -z "$SKIP_GTK3"; then
AC_MSG_CHECKING(--disable-gtktest argument)
@@ -2954,6 +2970,7 @@ if test -z "$SKIP_GTK3"; then
GUI_INC_LOC="$GTK_CPPFLAGS"])
if test -n "$GTK_CPPFLAGS"; then
SKIP_GTK2=YES
SKIP_GTK4=YES
SKIP_GNOME=YES
SKIP_MOTIF=YES
GUITYPE=GTK
@@ -2963,6 +2980,47 @@ if test -z "$SKIP_GTK3"; then
fi
fi
dnl ---------------------------------------------------------------------------
dnl Check for GTK4. If it succeeds, skip the check for GTK3/GTK2.
dnl ---------------------------------------------------------------------------
if test -z "$SKIP_GTK4"; 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" != "xno"; then
AM_PATH_GTK(4.0.0,
[GUI_LIB_LOC="$GTK_LIBDIR"
GTK_LIBNAME="$GTK_LIBS"
GUI_INC_LOC="$GTK_CPPFLAGS"])
if test -n "$GTK_CPPFLAGS"; then
SKIP_GTK3=YES
SKIP_GTK2=YES
SKIP_GNOME=YES
SKIP_MOTIF=YES
GUITYPE=GTK4
AC_SUBST(GTK_LIBNAME)
AC_DEFINE(USE_GTK4)
dnl GTK4 does not use any X11 APIs directly.
dnl GTK4 itself links against X11 for its backend, so the
dnl dynamic linker resolves X11 symbols via GTK4's dependency.
X_LIBS=
X_PRE_LIBS=
X_EXTRA_LIBS=
X_LIB=
dnl automatically enable XIM for GTK4
if test "$enable_xim" = "auto"; then
enable_xim="yes"
fi
fi
fi
fi
dnl ---------------------------------------------------------------------------
dnl Check for GTK2. If it fails, then continue on for Motif as before...
dnl ---------------------------------------------------------------------------
+7
View File
@@ -7133,6 +7133,13 @@ f_has(typval_T *argvars, typval_T *rettv)
1
#else
0
#endif
},
{"gui_gtk4",
#if defined(FEAT_GUI_GTK) && defined(USE_GTK4)
1
#else
0
#endif
},
{"gui_gnome",
+13 -3
View File
@@ -296,6 +296,14 @@
# define FEAT_POSTSCRIPT
#endif
/*
* +gtk_print Native GTK print dialog for :hardcopy (GTK4).
* Uses GtkPrintOperation + Pango/Cairo instead of PostScript.
*/
#if defined(FEAT_PRINTER) && defined(FEAT_GUI_GTK) && defined(USE_GTK4)
# define FEAT_GUI_GTK_PRINT
#endif
/*
* +diff Displaying diffs in a nice way.
* Can be enabled in autoconf already.
@@ -505,7 +513,8 @@
/*
* GUI dark theme variant
*/
#if (defined(FEAT_GUI_GTK) && defined(USE_GTK3)) || defined(FEAT_GUI_MSWIN)
#if (defined(FEAT_GUI_GTK) && (defined(USE_GTK3) || defined(USE_GTK4))) \
|| defined(FEAT_GUI_MSWIN)
# define FEAT_GUI_DARKTHEME
#endif
@@ -805,7 +814,7 @@
* +X11 Unix only. Include code for xterm title saving and X
* clipboard. Only works if HAVE_X11 is also defined.
*/
#if defined(FEAT_NORMAL) || defined(FEAT_GUI_MOTIF)
#if (defined(FEAT_NORMAL) || defined(FEAT_GUI_MOTIF)) && !defined(USE_GTK4)
# define WANT_X11
#endif
@@ -910,7 +919,8 @@
#if defined(FEAT_NORMAL) \
&& (defined(UNIX) || defined(VMS)) \
&& defined(WANT_X11) && defined(HAVE_X11)
&& defined(WANT_X11) && defined(HAVE_X11) \
&& !defined(USE_GTK4)
# define FEAT_XCLIPBOARD
# ifndef FEAT_CLIPBOARD
# define FEAT_CLIPBOARD
+1 -1
View File
@@ -2018,7 +2018,7 @@ vgetc(void)
continue;
}
#endif
#if defined(FEAT_GUI) && defined(FEAT_GUI_GTK) && defined(FEAT_MENU)
#if defined(FEAT_GUI) && defined(FEAT_GUI_GTK) && !defined(USE_GTK4) && defined(FEAT_MENU)
// GTK: <F10> normally selects the menu, but it's passed until
// here to allow mapping it. Intercept and invoke the GTK
// behavior if it's not mapped.
+6
View File
@@ -1709,6 +1709,12 @@ gui_set_shellsize(
#if defined(MSWIN) || defined(FEAT_GUI_GTK)
// If not setting to a user specified size and maximized, calculate the
// number of characters that fit in the maximized window.
// FIXME: gui_mch_newfont() is called here even when the font hasn't
// changed at all. For example, ":set guioptions=k" triggers this path
// via gui_init_which_components() -> gui_set_shellsize(FALSE, ...).
// The intent is to keep the window size and recalculate Rows/Columns,
// which has nothing to do with fonts. This should be a separate
// function with a more descriptive name.
if (!mustset && (vim_strchr(p_go, GO_KEEPWINSIZE) != NULL
|| gui_mch_maximized()))
{
+17 -5
View File
@@ -15,7 +15,17 @@
# ifdef VMS
# include "gui_gtk_vms.h"
# endif
# include <X11/Intrinsic.h>
# ifdef USE_GTK4
// Types used in proto files but not available without X11 headers
typedef void *Widget;
typedef void *XtAppContext;
typedef void Display;
typedef unsigned long Window;
typedef unsigned long Atom;
typedef GdkEvent GdkEventKey; // GTK4: GdkEventKey merged into GdkEvent
# else
# include <X11/Intrinsic.h>
# endif
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wstrict-prototypes"
# include <gtk/gtk.h>
@@ -344,7 +354,7 @@ typedef struct Gui
#endif
#ifdef FEAT_GUI_GTK
# ifndef USE_GTK3
# if !defined(USE_GTK3) && !defined(USE_GTK4)
int visibility; // Is shell partially/fully obscured?
# endif
GdkCursor *blank_pointer; // Blank pointer
@@ -365,7 +375,7 @@ typedef struct Gui
GtkWidget *menubar_h; // menubar handle
GtkWidget *toolbar_h; // toolbar handle
# endif
# ifdef USE_GTK3
# if defined(USE_GTK3) || defined(USE_GTK4)
GdkRGBA *fgcolor; // GDK-styled foreground color
GdkRGBA *bgcolor; // GDK-styled background color
GdkRGBA *spcolor; // GDK-styled special color
@@ -374,7 +384,7 @@ typedef struct Gui
GdkColor *bgcolor; // GDK-styled background color
GdkColor *spcolor; // GDK-styled special color
# endif
# ifdef USE_GTK3
# if defined(USE_GTK3) || defined(USE_GTK4)
cairo_surface_t *surface; // drawarea surface
# else
GdkGC *text_gc; // cached GC for normal text
@@ -386,7 +396,9 @@ typedef struct Gui
GtkWidget *tabline; // tab pages line handle
# endif
# ifndef USE_GTK4
GtkAccelGroup *accel_group;
# endif
GtkWidget *filedlg; // file selection dialog
char_u *browse_fname; // file name from filedlg
@@ -553,7 +565,7 @@ typedef enum
* For Solaris Studio, that is not the case. An explicit type cast is needed
* to suppress warnings on that particular conversion.
*/
# if defined(__SUNPRO_C) && defined(USE_GTK3)
# if defined(__SUNPRO_C) && (defined(USE_GTK3) || defined(USE_GTK4))
# define FUNC2GENERIC(func) (void *)(func)
# else
# define FUNC2GENERIC(func) G_CALLBACK(func)
+17 -1
View File
@@ -16,7 +16,9 @@
#if !defined(FEAT_GUI_MSWIN)
# ifdef FEAT_GUI_GTK
# if GTK_CHECK_VERSION(3,0,0)
# ifdef USE_GTK4
# include <gdk/gdkkeysyms.h>
# elif GTK_CHECK_VERSION(3,0,0)
# include <gdk/gdkkeysyms-compat.h>
# else
# include <gdk/gdkkeysyms.h>
@@ -390,7 +392,11 @@ pointer_event(BalloonEval *beval, int x, int y, unsigned state)
beval->x = x;
beval->y = y;
# ifdef USE_GTK4
if (state & (int)GDK_ALT_MASK)
# else
if (state & (int)GDK_MOD1_MASK)
# endif
{
/*
* Alt is pressed -- enter super-evaluate-mode,
@@ -416,14 +422,24 @@ key_event(BalloonEval *beval, unsigned keyval, int is_keypress)
{
switch (keyval)
{
# ifdef USE_GTK4
case GDK_KEY_Shift_L:
case GDK_KEY_Shift_R:
# else
case GDK_Shift_L:
case GDK_Shift_R:
# endif
beval->showState = ShS_UPDATE_PENDING;
(*beval->msgCB)(beval, (is_keypress)
? (int)GDK_SHIFT_MASK : 0);
break;
# ifdef USE_GTK4
case GDK_KEY_Control_L:
case GDK_KEY_Control_R:
# else
case GDK_Control_L:
case GDK_Control_R:
# endif
beval->showState = ShS_UPDATE_PENDING;
(*beval->msgCB)(beval, (is_keypress)
? (int)GDK_CONTROL_MASK : 0);
+4638
View File
File diff suppressed because it is too large Load Diff
+324
View File
@@ -0,0 +1,324 @@
/* vi:set ts=8 sts=4 sw=4 noet:
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
* See README.txt for an overview of the Vim source code.
*
* GTK4 GtkForm widget - a simple container for absolute child positioning.
* This is a clean rewrite of gui_gtk_f.c for GTK4.
*
* In GTK4, widgets no longer have their own GdkWindows (now GdkSurface),
* GtkContainer is removed, and child positioning uses GskTransform via
* gtk_widget_allocate(). This makes the form widget much simpler.
*/
#include "vim.h"
#include <gtk/gtk.h>
#include "gui_gtk4_f.h"
typedef struct _GtkFormChild GtkFormChild;
struct _GtkFormChild
{
GtkWidget *widget;
gint x;
gint y;
};
// Forward declarations
static void gui_gtk_form_class_init(GtkFormClass *klass);
static void gui_gtk_form_init(GtkForm *form);
static void form_measure(GtkWidget *widget, GtkOrientation orientation,
int for_size, int *minimum, int *natural,
int *minimum_baseline, int *natural_baseline);
static void form_size_allocate(GtkWidget *widget, int width, int height,
int baseline);
static void form_snapshot(GtkWidget *widget, GtkSnapshot *snapshot);
static void form_dispose(GObject *object);
static void form_position_child(GtkForm *form, GtkFormChild *child,
gboolean force_allocate);
G_DEFINE_TYPE(GtkForm, gui_gtk_form, GTK_TYPE_WIDGET)
// Public interface
GtkWidget *
gui_gtk_form_new(void)
{
return GTK_WIDGET(g_object_new(GTK_TYPE_FORM, NULL));
}
void
gui_gtk_form_put(
GtkForm *form,
GtkWidget *child_widget,
gint x,
gint y)
{
GtkFormChild *child;
g_return_if_fail(GTK_IS_FORM(form));
child = g_new(GtkFormChild, 1);
if (child == NULL)
return;
child->widget = child_widget;
child->x = x;
child->y = y;
gtk_widget_set_size_request(child->widget, -1, -1);
form->children = g_list_append(form->children, child);
gtk_widget_set_parent(child_widget, GTK_WIDGET(form));
form_position_child(form, child, TRUE);
}
void
gui_gtk_form_move(
GtkForm *form,
GtkWidget *child_widget,
gint x,
gint y)
{
GList *tmp_list;
g_return_if_fail(GTK_IS_FORM(form));
for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
{
GtkFormChild *child = tmp_list->data;
if (child->widget == child_widget)
{
child->x = x;
child->y = y;
form_position_child(form, child, TRUE);
return;
}
}
}
void
gui_gtk_form_move_resize(
GtkForm *form,
GtkWidget *widget,
gint x,
gint y,
gint w,
gint h)
{
gtk_widget_set_size_request(widget, w, h);
gui_gtk_form_move(form, widget, x, y);
}
void
gui_gtk_form_remove(GtkForm *form, GtkWidget *child_widget)
{
GList *tmp_list;
g_return_if_fail(GTK_IS_FORM(form));
for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
{
GtkFormChild *child = tmp_list->data;
if (child->widget == child_widget)
{
form->children = g_list_remove_link(form->children, tmp_list);
g_list_free_1(tmp_list);
gtk_widget_unparent(child_widget);
g_free(child);
return;
}
}
}
void
gui_gtk_form_freeze(GtkForm *form)
{
g_return_if_fail(GTK_IS_FORM(form));
++form->freeze_count;
}
void
gui_gtk_form_thaw(GtkForm *form)
{
g_return_if_fail(GTK_IS_FORM(form));
if (!form->freeze_count)
return;
if (!(--form->freeze_count))
{
GList *tmp_list;
for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
form_position_child(form, tmp_list->data, FALSE);
gtk_widget_queue_draw(GTK_WIDGET(form));
}
}
// GObject/GtkWidget class implementation
static void
gui_gtk_form_class_init(GtkFormClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
gobject_class->dispose = form_dispose;
widget_class->measure = form_measure;
widget_class->size_allocate = form_size_allocate;
widget_class->snapshot = form_snapshot;
}
static void
gui_gtk_form_init(GtkForm *form)
{
form->children = NULL;
form->freeze_count = 0;
}
static void
form_measure(
GtkWidget *widget UNUSED,
GtkOrientation orientation UNUSED,
int for_size UNUSED,
int *minimum,
int *natural,
int *minimum_baseline,
int *natural_baseline)
{
*minimum = 1;
*natural = 1;
*minimum_baseline = -1;
*natural_baseline = -1;
}
static guint form_resize_idle_id = 0;
static int form_last_width = 0;
static int form_last_height = 0;
static gboolean
form_resize_idle_cb(gpointer data UNUSED)
{
int w, h;
form_resize_idle_id = 0;
// Use drawarea's actual allocation, not formwin's
if (gui.drawarea == NULL)
return FALSE;
w = gtk_widget_get_width(gui.drawarea);
h = gtk_widget_get_height(gui.drawarea);
if (w > 1 && h > 1)
gui_resize_shell(w, h);
return FALSE;
}
static void
form_size_allocate(GtkWidget *widget, int width, int height,
int baseline UNUSED)
{
GtkForm *form;
GList *tmp_list;
g_return_if_fail(GTK_IS_FORM(widget));
form = GTK_FORM(widget);
for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
form_position_child(form, tmp_list->data, TRUE);
// Notify Vim about size change via idle callback
if (width != form_last_width || height != form_last_height)
{
form_last_width = width;
form_last_height = height;
if (form_resize_idle_id == 0)
form_resize_idle_id = g_idle_add(form_resize_idle_cb, NULL);
}
}
static void
form_snapshot(GtkWidget *widget, GtkSnapshot *snapshot)
{
GtkForm *form;
GList *tmp_list;
g_return_if_fail(GTK_IS_FORM(widget));
form = GTK_FORM(widget);
for (tmp_list = form->children; tmp_list; tmp_list = tmp_list->next)
{
GtkFormChild *child = tmp_list->data;
if (child->widget != NULL
&& GTK_IS_WIDGET(child->widget)
&& gtk_widget_get_parent(child->widget) == widget)
gtk_widget_snapshot_child(widget, child->widget, snapshot);
}
}
static void
form_dispose(GObject *object)
{
GtkForm *form = GTK_FORM(object);
GList *tmp_list;
tmp_list = form->children;
while (tmp_list)
{
GtkFormChild *child = tmp_list->data;
tmp_list = tmp_list->next;
gtk_widget_unparent(child->widget);
g_free(child);
}
g_list_free(form->children);
form->children = NULL;
G_OBJECT_CLASS(gui_gtk_form_parent_class)->dispose(object);
}
// Child positioning using GskTransform
static void
form_position_child(
GtkForm *form UNUSED,
GtkFormChild *child,
gboolean force_allocate)
{
if (!force_allocate)
return;
if (child->widget == NULL || !GTK_IS_WIDGET(child->widget))
return;
{
GtkRequisition requisition;
GskTransform *transform;
int w, h;
gtk_widget_get_preferred_size(child->widget, &requisition, NULL);
w = requisition.width;
h = requisition.height;
// If widget has no size request (e.g. drawarea), use parent size
if (w <= 0)
w = gtk_widget_get_width(GTK_WIDGET(form));
if (h <= 0)
h = gtk_widget_get_height(GTK_WIDGET(form));
if (w <= 0) w = 1;
if (h <= 0) h = 1;
transform = gsk_transform_translate(NULL,
&GRAPHENE_POINT_INIT((float)child->x, (float)child->y));
gtk_widget_allocate(child->widget, w, h, -1, transform);
}
}
+59
View File
@@ -0,0 +1,59 @@
/* vi:set ts=8 sts=4 sw=4 noet:
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
*
* GTK4 GtkForm widget - a simple container for absolute positioning.
*/
#ifndef GUI_GTK4_FORM_H
#define GUI_GTK4_FORM_H
#include <gtk/gtk.h>
#ifdef __cplusplus
extern "C" {
#endif
#define GTK_TYPE_FORM (gui_gtk_form_get_type())
#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))
typedef struct _GtkForm GtkForm;
typedef struct _GtkFormClass GtkFormClass;
struct _GtkForm
{
GtkWidget widget;
GList *children;
gint freeze_count;
};
struct _GtkFormClass
{
GtkWidgetClass parent_class;
};
GType gui_gtk_form_get_type(void);
GtkWidget *gui_gtk_form_new(void);
void gui_gtk_form_put(GtkForm *form, GtkWidget *widget, gint x, gint y);
void gui_gtk_form_move(GtkForm *form, GtkWidget *widget, gint x, gint y);
void gui_gtk_form_move_resize(GtkForm *form, GtkWidget *widget,
gint x, gint y, gint w, gint h);
void gui_gtk_form_remove(GtkForm *form, GtkWidget *widget);
void gui_gtk_form_freeze(GtkForm *form);
void gui_gtk_form_thaw(GtkForm *form);
#ifdef __cplusplus
}
#endif
#endif // GUI_GTK4_FORM_H
+94 -8
View File
@@ -18,15 +18,19 @@
#endif
#if defined(FEAT_GUI_GTK) && defined(FEAT_XIM)
# if GTK_CHECK_VERSION(3,0,0)
# ifdef USE_GTK4
# include <gdk/gdkkeysyms.h>
# elif GTK_CHECK_VERSION(3,0,0)
# include <gdk/gdkkeysyms-compat.h>
# else
# include <gdk/gdkkeysyms.h>
# endif
# ifdef MSWIN
# include <gdk/gdkwin32.h>
# else
# include <gdk/gdkx.h>
# if !defined(USE_GTK4)
# ifdef MSWIN
# include <gdk/gdkwin32.h>
# else
# include <gdk/gdkx.h>
# endif
# endif
#endif
@@ -185,7 +189,11 @@ static int im_preedit_cursor = 0; // cursor offset in characters
static int im_preedit_trailing = 0; // number of characters after cursor
static unsigned long im_commit_handler_id = 0;
# ifdef USE_GTK4
static unsigned int im_activatekey_keyval = GDK_KEY_VoidSymbol;
# else
static unsigned int im_activatekey_keyval = GDK_VoidSymbol;
# endif
static unsigned int im_activatekey_state = 0;
static GtkWidget *preedit_window = NULL;
@@ -272,6 +280,19 @@ im_preedit_window_set_position(void)
if (preedit_window == NULL)
return;
# ifdef USE_GTK4
// GTK4: positioning popup windows is limited.
// Use a simpler approach - just place near the cursor.
x = FILL_X(gui.col);
y = FILL_Y(gui.row) + gui.char_height;
width = 0;
height = 0;
screen_x = 0;
screen_y = 0;
screen_width = 0;
screen_height = 0;
// GTK4 doesn't have gtk_window_move; preedit is shown in-place.
# else
gui_gtk_get_screen_geom_of_win(gui.drawarea, 0, 0,
&screen_x, &screen_y, &screen_width, &screen_height);
gdk_window_get_origin(gtk_widget_get_window(gui.drawarea), &x, &y);
@@ -283,6 +304,7 @@ im_preedit_window_set_position(void)
if (y + height > screen_y + screen_height)
y = screen_y + screen_height - height;
gtk_window_move(GTK_WINDOW(preedit_window), x, y);
# endif
}
static void
@@ -305,18 +327,28 @@ im_preedit_window_open(void)
if (preedit_window == NULL)
{
# ifdef USE_GTK4
preedit_window = gtk_window_new();
# else
preedit_window = gtk_window_new(GTK_WINDOW_POPUP);
# endif
gtk_window_set_transient_for(GTK_WINDOW(preedit_window),
GTK_WINDOW(gui.mainwin));
preedit_label = gtk_label_new("");
gtk_widget_set_name(preedit_label, "vim-gui-preedit-area");
# ifdef USE_GTK4
gtk_window_set_child(GTK_WINDOW(preedit_window), preedit_label);
# else
gtk_container_add(GTK_CONTAINER(preedit_window), preedit_label);
# endif
}
# if GTK_CHECK_VERSION(3,16,0)
{
# ifndef USE_GTK4
GtkStyleContext * const context
= gtk_widget_get_style_context(preedit_label);
# endif
GtkCssProvider * const provider = gtk_css_provider_new();
gchar *css = NULL;
const char * const fontname
@@ -329,10 +361,15 @@ im_preedit_window_open(void)
{
// fontsize was given in points. Convert it into that in pixels
// to use with CSS.
# ifdef USE_GTK4
// GTK4: assume 96 DPI as default
fontsize = 96 * fontsize / 72;
# else
GdkScreen * const screen
= gdk_window_get_screen(gtk_widget_get_window(gui.mainwin));
const gdouble dpi = gdk_screen_get_resolution(screen);
fontsize = dpi * fontsize / 72;
# endif
}
if (fontsize > 0)
fontsize_propval = g_strdup_printf("%dpx", fontsize);
@@ -355,9 +392,16 @@ im_preedit_window_open(void)
(gui.back_pixel >> 8) & 0xff,
gui.back_pixel & 0xff);
# ifdef USE_GTK4
gtk_css_provider_load_from_string(provider, css);
gtk_style_context_add_provider_for_display(
gdk_display_get_default(),
GTK_STYLE_PROVIDER(provider), G_MAXUINT);
# else
gtk_css_provider_load_from_data(provider, css, -1, NULL);
gtk_style_context_add_provider(context,
GTK_STYLE_PROVIDER(provider), G_MAXUINT);
# endif
g_free(css);
g_free(fontsize_propval);
@@ -396,9 +440,13 @@ im_preedit_window_open(void)
layout = gtk_label_get_layout(GTK_LABEL(preedit_label));
pango_layout_get_pixel_size(layout, &w, &h);
h = MAX(h, gui.char_height);
# ifdef USE_GTK4
gtk_window_set_default_size(GTK_WINDOW(preedit_window), w, h);
gtk_widget_set_visible(preedit_window, TRUE);
# else
gtk_window_resize(GTK_WINDOW(preedit_window), w, h);
gtk_widget_show_all(preedit_window);
# endif
im_preedit_window_set_position();
}
@@ -411,7 +459,11 @@ im_preedit_window_open(void)
im_preedit_window_close(void)
{
if (preedit_window != NULL)
# ifdef USE_GTK4
gtk_widget_set_visible(preedit_window, FALSE);
# else
gtk_widget_hide(preedit_window);
# endif
}
static void
@@ -874,7 +926,9 @@ xim_init(void)
# endif
g_return_if_fail(gui.drawarea != NULL);
# ifndef USE_GTK4
g_return_if_fail(gtk_widget_get_window(gui.drawarea) != NULL);
# endif
xic = gtk_im_multicontext_new();
g_object_ref(xic);
@@ -888,7 +942,11 @@ xim_init(void)
g_signal_connect(G_OBJECT(xic), "preedit_end",
G_CALLBACK(&im_preedit_end_cb), NULL);
# ifdef USE_GTK4
gtk_im_context_set_client_widget(xic, gui.drawarea);
# else
gtk_im_context_set_client_window(xic, gtk_widget_get_window(gui.drawarea));
# endif
}
void
@@ -911,6 +969,7 @@ im_shutdown(void)
xim_has_preediting = FALSE;
}
# ifndef USE_GTK4
/*
* Convert the string argument to keyval and state for GdkEventKey.
* If str is valid return TRUE, otherwise FALSE.
@@ -980,7 +1039,9 @@ im_xim_isvalid_imactivate(void)
&im_activatekey_keyval,
&im_activatekey_state);
}
# endif // !USE_GTK4
# ifndef USE_GTK4
static void
im_synthesize_keypress(unsigned int keyval, unsigned int state)
{
@@ -1008,6 +1069,7 @@ im_synthesize_keypress(unsigned int keyval, unsigned int state)
gdk_event_free((GdkEvent *)event);
}
# endif // !USE_GTK4
void
xim_reset(void)
@@ -1027,6 +1089,11 @@ xim_reset(void)
{
xim_set_focus(gui.in_focus);
# ifdef USE_GTK4
im_shutdown();
xim_init();
xim_set_focus(gui.in_focus);
# else
if (im_activatekey_keyval != GDK_VoidSymbol)
{
if (im_is_active)
@@ -1043,6 +1110,7 @@ xim_reset(void)
xim_init();
xim_set_focus(gui.in_focus);
}
# endif
}
}
@@ -1051,12 +1119,13 @@ xim_reset(void)
xim_has_preediting = FALSE;
}
# ifndef USE_GTK4
int
xim_queue_key_press_event(GdkEventKey *event, int down)
{
# ifdef FEAT_GUI_GTK
# ifdef FEAT_GUI_GTK
if (event->state & GDK_SUPER_MASK) return FALSE;
# endif
# endif
if (down)
{
// Workaround GTK2 XIM 'feature' that always converts keypad keys to
@@ -1185,6 +1254,23 @@ xim_queue_key_press_event(GdkEventKey *event, int down)
return FALSE;
}
# else // USE_GTK4
// GTK4: imactivatekey is not supported because GTK4's GtkIMContext
// does not allow synthesizing key events for IM activation.
int
im_xim_isvalid_imactivate(void)
{
// Empty string is always valid (means no activation key).
// Any other value is not supported in GTK4.
return p_imak[0] == NUL;
}
int
xim_queue_key_press_event(GdkEvent *event UNUSED, int down UNUSED)
{
return FALSE;
}
# endif // !USE_GTK4
int
im_get_status(void)
+10
View File
@@ -560,6 +560,16 @@ ex_hardcopy(exarg_T *eap)
CLEAR_FIELD(settings);
settings.has_color = TRUE;
#ifdef FEAT_GUI_GTK_PRINT
// Use the native GTK print dialog only for interactive printing;
// ":hardcopy >file" must fall through to the PostScript writer.
if (gui.in_use && *eap->arg != '>')
{
gui_gtk4_hardcopy(eap);
return;
}
#endif
#ifdef FEAT_POSTSCRIPT
if (*eap->arg == '>')
{
+12 -1
View File
@@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Vim\n"
"Report-Msgid-Bugs-To: vim-dev@vim.org\n"
"POT-Creation-Date: 2026-05-17 19:50+0000\n"
"POT-Creation-Date: 2026-05-19 18:20+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@@ -921,9 +921,11 @@ msgstr ""
msgid "VIM - Search..."
msgstr ""
#. "Find what:" label + entry
msgid "Find what:"
msgstr ""
#. "Replace with:" label + entry
msgid "Replace with:"
msgstr ""
@@ -957,6 +959,12 @@ msgstr ""
msgid "_Close"
msgstr ""
msgid "Direction:"
msgstr ""
msgid "Close"
msgstr ""
msgid "Vim: Received \"die\" request from session manager\n"
msgstr ""
@@ -3454,6 +3462,9 @@ msgstr ""
msgid "without GUI."
msgstr ""
msgid "with GTK4 GUI."
msgstr ""
msgid "with GTK3 GUI."
msgstr ""
+6 -2
View File
@@ -302,8 +302,12 @@ extern char_u *vimpty_getenv(const char_u *string); // in misc2.c
# include "gui_w32.pro"
# endif
# ifdef FEAT_GUI_GTK
# include "gui_gtk.pro"
# include "gui_gtk_x11.pro"
# ifdef USE_GTK4
# include "gui_gtk4.pro"
# else
# include "gui_gtk.pro"
# include "gui_gtk_x11.pro"
# endif
# endif
# ifdef FEAT_GUI_MOTIF
# include "gui_motif.pro"
+110
View File
@@ -0,0 +1,110 @@
/* gui_gtk4.c */
void gui_mch_prepare(int *argc, char **argv);
void gui_mch_free_all(void);
int gui_mch_is_blinking(void);
int gui_mch_is_blink_off(void);
void gui_mch_set_blinking(long waittime, long on, long off);
void gui_mch_stop_blink(int may_call_gui_update_cursor);
void gui_mch_start_blink(void);
int gui_mch_early_init_check(int give_message);
int gui_mch_init_check(void);
int gui_mch_init(void);
void gui_mch_new_colors(void);
int gui_mch_open(void);
void gui_mch_exit(int rc);
int gui_mch_get_winpos(int *x, int *y);
void gui_mch_set_winpos(int x, int y);
int gui_mch_maximized(void);
void gui_mch_unmaximize(void);
void gui_mch_newfont(void);
void gui_mch_settitle(char_u *title, char_u *icon);
void gui_mch_set_shellsize(int width, int height, int min_width, int min_height, int base_width, int base_height, int direction);
void gui_mch_get_screen_dimensions(int *screen_w, int *screen_h);
void gui_mch_enable_menu(int showit);
void gui_mch_show_toolbar(int showit);
void gui_mch_set_dark_theme(int dark);
int gui_mch_adjust_charheight(void);
char_u *gui_mch_font_dialog(char_u *oldval);
int gui_mch_init_font(char_u *font_name, int fontset);
GuiFont gui_mch_get_font(char_u *name, int report_error);
char_u *gui_mch_get_fontname(GuiFont font, char_u *name);
void gui_mch_free_font(GuiFont font);
void gui_mch_expand_font(optexpand_T *args, void *param, int (*add_match)(char_u *val));
guicolor_T gui_mch_get_color(char_u *name);
guicolor_T gui_mch_get_rgb_color(int r, int g, int b);
void gui_mch_set_fg_color(guicolor_T color);
void gui_mch_set_bg_color(guicolor_T color);
void gui_mch_set_sp_color(guicolor_T color);
guicolor_T gui_mch_get_rgb(guicolor_T pixel);
void gui_mch_clear_block(int row1, int col1, int row2, int col2);
void gui_mch_clear_all(void);
void gui_mch_delete_lines(int row, int num_lines);
void gui_mch_insert_lines(int row, int num_lines);
void gui_mch_draw_hollow_cursor(guicolor_T color);
void gui_mch_draw_part_cursor(int w, int h, guicolor_T color);
void gui_mch_flash(int msec);
void gui_mch_invert_rectangle(int r, int c, int nr, int nc);
void gui_mch_update(void);
int gui_mch_wait_for_chars(long wtime);
void gui_mch_flush(void);
void gui_mch_beep(void);
void *gui_mch_get_display(void);
void gui_mch_iconify(void);
void gui_mch_set_foreground(void);
void gui_mch_getmouse(int *x, int *y);
void gui_mch_setmouse(int x, int y);
void gui_mch_mousehide(int hide);
int gui_mch_haskey(char_u *name);
void gui_mch_forked(void);
void gui_mch_enable_scrollbar(scrollbar_T *sb, int flag);
void gui_mch_menu_grey(vimmenu_T *menu, int grey);
void gui_mch_menu_hidden(vimmenu_T *menu, int hidden);
void gui_mch_draw_menubar(void);
void gui_mch_show_tabline(int showit);
int gui_mch_showing_tabline(void);
void gui_mch_update_tabline(void);
void gui_mch_set_curtab(int nr);
void gui_mch_drawsign(int row, int col, int typenr);
void *gui_mch_register_sign(char_u *signfile);
void gui_mch_destroy_sign(void *sign);
int gui_gtk_draw_string_ext(int row, int col, char_u *s, int len, int flags, int force_pango);
int gui_gtk_draw_string(int row, int col, char_u *s, int len, int flags);
int gui_get_x11_windis(Window *win, Display **dis);
void gui_gtk_init_socket_server(void);
void gui_gtk_uninit_socket_server(void);
void gui_gtk_set_mnemonics(int enable);
void gui_make_popup(char_u *path_name, int mouse_pos);
int get_menu_tool_width(void);
int get_menu_tool_height(void);
void clip_mch_request_selection(Clipboard_T *cbd);
void clip_mch_set_selection(Clipboard_T *cbd);
int clip_mch_own_selection(Clipboard_T *cbd);
void clip_mch_lose_selection(Clipboard_T *cbd);
void gui_mch_post_balloon(BalloonEval *beval, char_u *mesg);
BalloonEval *gui_mch_create_beval_area(void *target, char_u *mesg, void (*mesgCB)(BalloonEval *, int), void *clientData);
void gui_mch_enable_beval_area(BalloonEval *beval);
void gui_mch_disable_beval_area(BalloonEval *beval);
guint gtk_main_level(void);
void gtk_main_quit(void);
void mch_set_mouse_shape(int shape);
void gui_mch_add_menu(vimmenu_T *menu, int idx);
void gui_mch_add_menu_item(vimmenu_T *menu, int idx);
void gui_mch_toggle_tearoffs(int enable);
void gui_mch_menu_set_tip(vimmenu_T *menu);
void gui_mch_destroy_menu(vimmenu_T *menu);
void gui_mch_show_popupmenu(vimmenu_T *menu);
void gui_mch_set_scrollbar_thumb(scrollbar_T *sb, long val, long size, long max);
void gui_mch_set_scrollbar_pos(scrollbar_T *sb, int x, int y, int w, int h);
int gui_mch_get_scrollbar_xpadding(void);
int gui_mch_get_scrollbar_ypadding(void);
void gui_mch_create_scrollbar(scrollbar_T *sb, int orient);
void gui_mch_destroy_scrollbar(scrollbar_T *sb);
void gui_mch_set_text_area_pos(int x, int y, int w, int h);
char_u *gui_mch_browse(int saving, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter);
char_u *gui_mch_browsedir(char_u *title, char_u *initdir);
int gui_mch_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton, char_u *textfield, int ex_cmd);
void gui_mch_find_dialog(exarg_T *eap);
void gui_mch_replace_dialog(exarg_T *eap);
void ex_helpfind(exarg_T *eap);
void gui_gtk4_hardcopy(exarg_T *eap);
/* vim: set ft=c : */
+5 -1
View File
@@ -729,6 +729,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
501,
/**/
500,
/**/
@@ -2077,7 +2079,9 @@ list_version(void)
#if !defined(FEAT_GUI)
msg_puts(_("without GUI."));
#elif defined(FEAT_GUI_GTK)
# if defined(USE_GTK3)
# if defined(USE_GTK4)
msg_puts(_("with GTK4 GUI."));
# elif defined(USE_GTK3)
msg_puts(_("with GTK3 GUI."));
# elif defined(FEAT_GUI_GNOME)
msg_puts(_("with GTK2-GNOME GUI."));
+1 -1
View File
@@ -2365,7 +2365,7 @@ typedef struct
Atom sel_atom; // PRIMARY/CLIPBOARD selection ID
# endif
# ifdef FEAT_GUI_GTK
# if defined(FEAT_GUI_GTK) && !defined(USE_GTK4)
GdkAtom gtk_sel_atom; // PRIMARY/CLIPBOARD selection ID
# endif