0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

patch 9.1.0064: No Wayland support

Problem:  No Wayland support
Solution: Add Wayland UI support
          (lilydjwg)

closes: #9639

Signed-off-by: lilydjwg <lilydjwg@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
lilydjwg
2024-01-29 20:54:28 +01:00
committed by Christian Brabandt
parent 94ff09a093
commit 6e0a18f82b
12 changed files with 180 additions and 58 deletions

View File

@@ -1,4 +1,4 @@
*builtin.txt* For Vim version 9.1. Last change: 2024 Jan 25 *builtin.txt* For Vim version 9.1. Last change: 2024 Jan 29
VIM REFERENCE MANUAL by Bram Moolenaar VIM REFERENCE MANUAL by Bram Moolenaar
@@ -4424,14 +4424,16 @@ getwinpos([{timeout}]) *getwinpos()*
getwinposx() The result is a Number, which is the X coordinate in pixels of getwinposx() The result is a Number, which is the X coordinate in pixels of
the left hand side of the GUI Vim window. Also works for an the left hand side of the GUI Vim window. Also works for an
xterm (uses a timeout of 100 msec). xterm (uses a timeout of 100 msec).
The result will be -1 if the information is not available. The result will be -1 if the information is not available
(e.g. on the Wayland backend).
The value can be used with `:winpos`. The value can be used with `:winpos`.
*getwinposy()* *getwinposy()*
getwinposy() The result is a Number, which is the Y coordinate in pixels of getwinposy() The result is a Number, which is the Y coordinate in pixels of
the top of the GUI Vim window. Also works for an xterm (uses the top of the GUI Vim window. Also works for an xterm (uses
a timeout of 100 msec). a timeout of 100 msec).
The result will be -1 if the information is not available. The result will be -1 if the information is not available
(e.g. on the Wayland backend).
The value can be used with `:winpos`. The value can be used with `:winpos`.
getwinvar({winnr}, {varname} [, {def}]) *getwinvar()* getwinvar({winnr}, {varname} [, {def}]) *getwinvar()*

View File

@@ -1589,8 +1589,11 @@ again:
// Only comparing Rows and Columns may be sufficient, but let's stay on // Only comparing Rows and Columns may be sufficient, but let's stay on
// the safe side. // the safe side.
if (gui.num_rows != screen_Rows || gui.num_cols != screen_Columns if (gui.num_rows != screen_Rows || gui.num_cols != screen_Columns
|| gui.num_rows != Rows || gui.num_cols != Columns) || gui.num_rows != Rows || gui.num_cols != Columns || gui.force_redraw)
{
shell_resized(); shell_resized();
gui.force_redraw = 0;
}
#ifdef FEAT_GUI_HAIKU #ifdef FEAT_GUI_HAIKU
vim_unlock_screen(); vim_unlock_screen();

View File

@@ -259,6 +259,7 @@ typedef struct Gui
int scrollbar_height; // Height of horizontal scrollbar int scrollbar_height; // Height of horizontal scrollbar
int left_sbar_x; // Calculated x coord for left scrollbar int left_sbar_x; // Calculated x coord for left scrollbar
int right_sbar_x; // Calculated x coord for right scrollbar int right_sbar_x; // Calculated x coord for right scrollbar
int force_redraw; // Force a redraw even e.g. not resized
#ifdef FEAT_MENU #ifdef FEAT_MENU
# ifndef FEAT_GUI_GTK # ifndef FEAT_GUI_GTK

View File

@@ -793,6 +793,36 @@ draw_event(GtkWidget *widget UNUSED,
return FALSE; return FALSE;
} }
# if GTK_CHECK_VERSION(3,10,0)
static gboolean
scale_factor_event(GtkWidget *widget,
GParamSpec* pspec UNUSED,
gpointer user_data UNUSED)
{
if (gui.surface != NULL)
cairo_surface_destroy(gui.surface);
int w, h;
gtk_window_get_size(GTK_WINDOW(gui.mainwin), &w, &h);
gui.surface = gdk_window_create_similar_surface(
gtk_widget_get_window(widget),
CAIRO_CONTENT_COLOR_ALPHA,
w, h);
int usable_height = h;
if (gtk_socket_id != 0)
usable_height -= (gui.char_height - (gui.char_height/2)); // sic.
gui_gtk_form_freeze(GTK_FORM(gui.formwin));
gui.force_redraw = 1;
gui_resize_shell(w, usable_height);
gui_gtk_form_thaw(GTK_FORM(gui.formwin));
return TRUE;
}
# endif // GTK_CHECK_VERSION(3,10,0)
#else // !GTK_CHECK_VERSION(3,0,0) #else // !GTK_CHECK_VERSION(3,0,0)
static gint static gint
expose_event(GtkWidget *widget UNUSED, expose_event(GtkWidget *widget UNUSED,
@@ -1667,11 +1697,12 @@ selection_get_cb(GtkWidget *widget UNUSED,
int int
gui_mch_early_init_check(int give_message) gui_mch_early_init_check(int give_message)
{ {
char_u *p; char_u *p, *q;
// Guess that when $DISPLAY isn't set the GUI can't start. // Guess that when $DISPLAY isn't set the GUI can't start.
p = mch_getenv((char_u *)"DISPLAY"); p = mch_getenv((char_u *)"DISPLAY");
if (p == NULL || *p == NUL) q = mch_getenv((char_u *)"WAYLAND_DISPLAY");
if ((p == NULL || *p == NUL) && (q == NULL || *q == NUL))
{ {
gui.dying = TRUE; gui.dying = TRUE;
if (give_message) if (give_message)
@@ -1704,6 +1735,9 @@ gui_mch_init_check(void)
#if GTK_CHECK_VERSION(3,10,0) #if GTK_CHECK_VERSION(3,10,0)
// Vim currently assumes that Gtk means X11, so it cannot use native Gtk // Vim currently assumes that Gtk means X11, so it cannot use native Gtk
// support for other backends such as Wayland. // support for other backends such as Wayland.
//
// Use an environment variable to enable unfinished Wayland support.
if (getenv("GVIM_ENABLE_WAYLAND") == NULL)
gdk_set_allowed_backends ("x11"); gdk_set_allowed_backends ("x11");
#endif #endif
@@ -2024,6 +2058,10 @@ scroll_event(GtkWidget *widget,
{ {
int button; int button;
int_u vim_modifiers; int_u vim_modifiers;
#if GTK_CHECK_VERSION(3,4,0)
static double acc_x, acc_y;
static guint32 last_smooth_event_time;
#endif
if (gtk_socket_id != 0 && !gtk_widget_has_focus(widget)) if (gtk_socket_id != 0 && !gtk_widget_has_focus(widget))
gtk_widget_grab_focus(widget); gtk_widget_grab_focus(widget);
@@ -2042,6 +2080,16 @@ scroll_event(GtkWidget *widget,
case GDK_SCROLL_RIGHT: case GDK_SCROLL_RIGHT:
button = MOUSE_6; button = MOUSE_6;
break; break;
#if GTK_CHECK_VERSION(3,4,0)
case GDK_SCROLL_SMOOTH:
if (event->time - last_smooth_event_time > 50)
// reset our accumulations after 50ms of silence
acc_x = acc_y = 0;
acc_x += event->delta_x;
acc_y += event->delta_y;
last_smooth_event_time = event->time;
break;
#endif
default: // This shouldn't happen default: // This shouldn't happen
return FALSE; return FALSE;
} }
@@ -2054,6 +2102,36 @@ scroll_event(GtkWidget *widget,
vim_modifiers = modifiers_gdk2mouse(event->state); vim_modifiers = modifiers_gdk2mouse(event->state);
#if GTK_CHECK_VERSION(3,4,0)
if (event->direction == GDK_SCROLL_SMOOTH)
{
while (acc_x > 1.0)
{ // right
acc_x = MAX(0.0, acc_x - 1.0);
gui_send_mouse_event(MOUSE_6, (int)event->x, (int)event->y,
FALSE, vim_modifiers);
}
while (acc_x < -1.0)
{ // left
acc_x = MIN(0.0, acc_x + 1.0);
gui_send_mouse_event(MOUSE_7, (int)event->x, (int)event->y,
FALSE, vim_modifiers);
}
while (acc_y > 1.0)
{ // down
acc_y = MAX(0.0, acc_y - 1.0);
gui_send_mouse_event(MOUSE_5, (int)event->x, (int)event->y,
FALSE, vim_modifiers);
}
while (acc_y < -1.0)
{ // up
acc_y = MIN(0.0, acc_y + 1.0);
gui_send_mouse_event(MOUSE_4, (int)event->x, (int)event->y,
FALSE, vim_modifiers);
}
}
else
#endif
gui_send_mouse_event(button, (int)event->x, (int)event->y, gui_send_mouse_event(button, (int)event->x, (int)event->y,
FALSE, vim_modifiers); FALSE, vim_modifiers);
@@ -2509,10 +2587,12 @@ setup_save_yourself(void)
// Fall back to old method // Fall back to old method
// first get the existing value // first get the existing value
GdkWindow * const mainwin_win = gtk_widget_get_window(gui.mainwin); Display * dpy = gui_mch_get_display();
if (!dpy)
return;
if (XGetWMProtocols(GDK_WINDOW_XDISPLAY(mainwin_win), GdkWindow * const mainwin_win = gtk_widget_get_window(gui.mainwin);
GDK_WINDOW_XID(mainwin_win), if (XGetWMProtocols(dpy, GDK_WINDOW_XID(mainwin_win),
&existing_atoms, &count)) &existing_atoms, &count))
{ {
Atom *new_atoms; Atom *new_atoms;
@@ -2620,7 +2700,10 @@ mainwin_realize(GtkWidget *widget UNUSED, gpointer data UNUSED)
// When started with "--echo-wid" argument, write window ID on stdout. // When started with "--echo-wid" argument, write window ID on stdout.
if (echo_wid_arg) if (echo_wid_arg)
{ {
if (gui_mch_get_display())
printf("WID: %ld\n", (long)GDK_WINDOW_XID(mainwin_win)); printf("WID: %ld\n", (long)GDK_WINDOW_XID(mainwin_win));
else
printf("WID: 0\n");
fflush(stdout); fflush(stdout);
} }
@@ -2655,6 +2738,8 @@ mainwin_realize(GtkWidget *widget UNUSED, gpointer data UNUSED)
setup_save_yourself(); setup_save_yourself();
#ifdef FEAT_CLIENTSERVER #ifdef FEAT_CLIENTSERVER
if (gui_mch_get_display())
{
if (serverName == NULL && serverDelayedStartName != NULL) if (serverName == NULL && serverDelayedStartName != NULL)
{ {
// This is a :gui command in a plain vim with no previous server // This is a :gui command in a plain vim with no previous server
@@ -2676,6 +2761,7 @@ mainwin_realize(GtkWidget *widget UNUSED, gpointer data UNUSED)
gtk_widget_add_events(gui.mainwin, GDK_PROPERTY_CHANGE_MASK); gtk_widget_add_events(gui.mainwin, GDK_PROPERTY_CHANGE_MASK);
g_signal_connect(G_OBJECT(gui.mainwin), "property-notify-event", g_signal_connect(G_OBJECT(gui.mainwin), "property-notify-event",
G_CALLBACK(property_event), NULL); G_CALLBACK(property_event), NULL);
}
#endif #endif
} }
@@ -3919,6 +4005,9 @@ gui_mch_init(void)
GDK_BUTTON_PRESS_MASK | GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_RELEASE_MASK |
GDK_SCROLL_MASK | GDK_SCROLL_MASK |
#if GTK_CHECK_VERSION(3,4,0)
GDK_SMOOTH_SCROLL_MASK |
#endif
GDK_KEY_PRESS_MASK | GDK_KEY_PRESS_MASK |
GDK_KEY_RELEASE_MASK | GDK_KEY_RELEASE_MASK |
GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_MASK |
@@ -4520,6 +4609,10 @@ gui_mch_open(void)
#endif #endif
g_signal_connect(G_OBJECT(gui.formwin), "configure-event", g_signal_connect(G_OBJECT(gui.formwin), "configure-event",
G_CALLBACK(form_configure_event), NULL); G_CALLBACK(form_configure_event), NULL);
#if GTK_CHECK_VERSION(3,10,0)
g_signal_connect(G_OBJECT(gui.formwin), "notify::scale-factor",
G_CALLBACK(scale_factor_event), NULL);
#endif
#ifdef FEAT_DND #ifdef FEAT_DND
// Set up for receiving DND items. // Set up for receiving DND items.
@@ -4602,10 +4695,14 @@ gui_mch_exit(int rc UNUSED)
*/ */
int int
gui_mch_get_winpos(int *x, int *y) gui_mch_get_winpos(int *x, int *y)
{
if (gui_mch_get_display())
{ {
gtk_window_get_position(GTK_WINDOW(gui.mainwin), x, y); gtk_window_get_position(GTK_WINDOW(gui.mainwin), x, y);
return OK; return OK;
} }
return FAIL;
}
/* /*
* Set the position of the top left corner of the window to the given * Set the position of the top left corner of the window to the given
@@ -6229,9 +6326,10 @@ gui_mch_haskey(char_u *name)
int int
gui_get_x11_windis(Window *win, Display **dis) gui_get_x11_windis(Window *win, Display **dis)
{ {
if (gui.mainwin != NULL && gtk_widget_get_window(gui.mainwin) != NULL) Display * dpy = gui_mch_get_display();
if (dpy)
{ {
*dis = GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin)); *dis = dpy;
*win = GDK_WINDOW_XID(gtk_widget_get_window(gui.mainwin)); *win = GDK_WINDOW_XID(gtk_widget_get_window(gui.mainwin));
return OK; return OK;
} }
@@ -6242,18 +6340,18 @@ gui_get_x11_windis(Window *win, Display **dis)
} }
#endif #endif
#if defined(FEAT_CLIENTSERVER) \
|| (defined(FEAT_X11) && defined(FEAT_CLIPBOARD)) || defined(PROTO)
Display * Display *
gui_mch_get_display(void) gui_mch_get_display(void)
{ {
if (gui.mainwin != NULL && gtk_widget_get_window(gui.mainwin) != NULL) if (gui.mainwin != NULL && gtk_widget_get_window(gui.mainwin) != NULL
#if GTK_CHECK_VERSION(3,0,0)
&& GDK_IS_X11_DISPLAY(gtk_widget_get_display(gui.mainwin))
#endif
)
return GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin)); return GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin));
else else
return NULL; return NULL;
} }
#endif
void void
gui_mch_beep(void) gui_mch_beep(void)
@@ -6915,6 +7013,7 @@ clip_mch_request_selection(Clipboard_T *cbd)
return; return;
} }
if (gui_mch_get_display())
// Final fallback position - use the X CUT_BUFFER0 store // Final fallback position - use the X CUT_BUFFER0 store
yank_cut_buffer0(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin)), yank_cut_buffer0(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin)),
cbd); cbd);
@@ -7083,8 +7182,10 @@ gui_mch_setmouse(int x, int y)
// Sorry for the Xlib call, but we can't avoid it, since there is no // 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 // internal GDK mechanism present to accomplish this. (and for good
// reason...) // reason...)
XWarpPointer(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.drawarea)), Display * dpy = gui_mch_get_display();
(Window)0, GDK_WINDOW_XID(gtk_widget_get_window(gui.drawarea)), if (dpy)
XWarpPointer(dpy, (Window)0,
GDK_WINDOW_XID(gtk_widget_get_window(gui.drawarea)),
0, 0, 0U, 0U, x, y); 0, 0, 0U, 0U, x, y);
} }

View File

@@ -2320,12 +2320,11 @@ mch_settitle(char_u *title, char_u *icon)
#ifdef FEAT_X11 #ifdef FEAT_X11
if (get_x11_windis() == OK) if (get_x11_windis() == OK)
type = 1; type = 1;
#else #endif
#if defined(FEAT_GUI_PHOTON) \ #if defined(FEAT_GUI_PHOTON) \
|| defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU) || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU)
if (gui.in_use) if (gui.in_use)
type = 1; type = 1;
# endif
#endif #endif
/* /*

View File

@@ -160,6 +160,14 @@ func CheckEnv(name)
endif endif
endfunc endfunc
" Command to Check for pure X11 (no Wayland)
command -nargs=0 CheckX11 call CheckX11()
func CheckX11()
if !empty($WAYLAND_DISPLAY) || empty($DISPLAY)
throw 'Skipped: not pure X11 environment'
endif
endfunc
" Command to check that we are using the GUI " Command to check that we are using the GUI
command CheckGui call CheckGui() command CheckGui call CheckGui()
func CheckGui() func CheckGui()

View File

@@ -13,7 +13,7 @@ source shared.vim
func Check_X11_Connection() func Check_X11_Connection()
if has('x11') if has('x11')
CheckEnv DISPLAY CheckX11
try try
call remote_send('xxx', '') call remote_send('xxx', '')
catch catch

View File

@@ -111,6 +111,8 @@ func Test_getfontname_without_arg()
endfunc endfunc
func Test_getwinpos() func Test_getwinpos()
CheckX11
call assert_match('Window position: X \d\+, Y \d\+', execute('winpos')) call assert_match('Window position: X \d\+, Y \d\+', execute('winpos'))
call assert_true(getwinposx() >= 0) call assert_true(getwinposx() >= 0)
call assert_true(getwinposy() >= 0) call assert_true(getwinposy() >= 0)
@@ -897,7 +899,7 @@ func Test_set_term()
endfunc endfunc
func Test_windowid_variable() func Test_windowid_variable()
if g:x11_based_gui || has('win32') if (g:x11_based_gui && empty($WAYLAND_DISPLAY)) || has('win32')
call assert_true(v:windowid > 0) call assert_true(v:windowid > 0)
else else
call assert_equal(0, v:windowid) call assert_equal(0, v:windowid)

View File

@@ -139,8 +139,8 @@ func Test_quotestar()
if has('macunix') if has('macunix')
let skipped = Do_test_quotestar_for_macunix() let skipped = Do_test_quotestar_for_macunix()
elseif has('x11') elseif has('x11')
if empty($DISPLAY) if empty($DISPLAY) || !empty($WAYLAND_DISPLAY)
let skipped = "Test can only run when $DISPLAY is set." let skipped = "Test can only run when $DISPLAY is set and $WAYLAND_DISPLAY is not set."
else else
let skipped = Do_test_quotestar_for_x11() let skipped = Do_test_quotestar_for_x11()
endif endif

View File

@@ -518,9 +518,10 @@ func Test_geometry()
call writefile([&columns, &lines, getwinposx(), getwinposy(), string(getwinpos())], "Xtest_geometry") call writefile([&columns, &lines, getwinposx(), getwinposy(), string(getwinpos())], "Xtest_geometry")
qall qall
[CODE] [CODE]
" Hide menu because gtk insists to make the window wide enough to show it completely
" Some window managers have a bar at the top that pushes windows down, " Some window managers have a bar at the top that pushes windows down,
" need to use at least 130, let's do 150 " need to use at least 130, let's do 150
if RunVim([], after, '-f -g -geometry 31x13+41+150') if RunVim(['set guioptions-=m'], after, '-f -g -geometry 31x13+41+150')
let lines = readfile('Xtest_geometry') let lines = readfile('Xtest_geometry')
" Depending on the GUI library and the windowing system the final size " Depending on the GUI library and the windowing system the final size
" might be a bit different, allow for some tolerance. Tuned based on " might be a bit different, allow for some tolerance. Tuned based on
@@ -529,11 +530,14 @@ func Test_geometry()
" for some reason, the window may contain fewer lines than requested " for some reason, the window may contain fewer lines than requested
" for GTK, so allow some tolerance " for GTK, so allow some tolerance
call assert_inrange(8, 13, str2nr(lines[1])) call assert_inrange(8, 13, str2nr(lines[1]))
" on Wayland there is no way to set or retrieve window positions
if empty($WAYLAND_DISPLAY)
call assert_equal('41', lines[2]) call assert_equal('41', lines[2])
call assert_equal('150', lines[3]) call assert_equal('150', lines[3])
call assert_equal('[41, 150]', lines[4]) call assert_equal('[41, 150]', lines[4])
endif endif
endif endif
endif
call delete('Xtest_geometry') call delete('Xtest_geometry')
endfunc endfunc

View File

@@ -3409,7 +3409,7 @@ def Test_remote_foreground()
CheckFeature clientserver CheckFeature clientserver
# remote_foreground() doesn't fail on MS-Windows # remote_foreground() doesn't fail on MS-Windows
CheckNotMSWindows CheckNotMSWindows
CheckEnv DISPLAY CheckX11
v9.CheckDefAndScriptFailure(['remote_foreground(10)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1']) v9.CheckDefAndScriptFailure(['remote_foreground(10)'], ['E1013: Argument 1: type mismatch, expected string but got number', 'E1174: String required for argument 1'])
assert_fails('remote_foreground("NonExistingServer")', 'E241:') assert_fails('remote_foreground("NonExistingServer")', 'E241:')

View File

@@ -704,6 +704,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
64,
/**/ /**/
63, 63,
/**/ /**/