]> git.ipfire.org Git - thirdparty/vim.git/commitdiff
patch 9.1.0064: No Wayland support v9.1.0064
authorlilydjwg <lilydjwg@gmail.com>
Mon, 29 Jan 2024 19:54:28 +0000 (20:54 +0100)
committerChristian Brabandt <cb@256bit.org>
Mon, 29 Jan 2024 19:54:28 +0000 (20:54 +0100)
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>
12 files changed:
runtime/doc/builtin.txt
src/gui.c
src/gui.h
src/gui_gtk_x11.c
src/os_unix.c
src/testdir/check.vim
src/testdir/test_clientserver.vim
src/testdir/test_gui.vim
src/testdir/test_quotestar.vim
src/testdir/test_startup.vim
src/testdir/test_vim9_builtin.vim
src/version.c

index 88cf642ca4ec0403bef9133c506dc9def6a67913..5001205ea648e4475b1b63b36873cfc71e85c335 100644 (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
@@ -4424,14 +4424,16 @@ getwinpos([{timeout}])                                  *getwinpos()*
 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
                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`.
 
                                                        *getwinposy()*
 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
                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`.
 
 getwinvar({winnr}, {varname} [, {def}])                                *getwinvar()*
index 223ede2828b321ccaa8b9831e5bfdf39a9e7f9c3..29e462380c959d4c1a091cbbabb4f2246d090ca7 100644 (file)
--- a/src/gui.c
+++ b/src/gui.c
@@ -1589,8 +1589,11 @@ again:
     // Only comparing Rows and Columns may be sufficient, but let's stay on
     // the safe side.
     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();
+       gui.force_redraw = 0;
+    }
 
 #ifdef FEAT_GUI_HAIKU
     vim_unlock_screen();
index 1882000f6b8dd8119239755cef7ae06bee01f432..c677ba1fe47e76e3f2716f72ecf8d86c5c8f2f4e 100644 (file)
--- a/src/gui.h
+++ b/src/gui.h
@@ -259,6 +259,7 @@ typedef struct Gui
     int                scrollbar_height;   // Height of horizontal scrollbar
     int                left_sbar_x;        // Calculated x coord for left 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
 # ifndef FEAT_GUI_GTK
index 4d2a6ae710316f4e2c4a42de9f194c3aa9441fa9..187123739edccda6ef7338ea35bafb6eb15bdce6 100644 (file)
@@ -793,6 +793,36 @@ draw_event(GtkWidget *widget UNUSED,
 
     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)
     static gint
 expose_event(GtkWidget *widget UNUSED,
@@ -1667,11 +1697,12 @@ selection_get_cb(GtkWidget          *widget UNUSED,
     int
 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.
     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;
        if (give_message)
@@ -1704,7 +1735,10 @@ gui_mch_init_check(void)
 #if GTK_CHECK_VERSION(3,10,0)
     // Vim currently assumes that Gtk means X11, so it cannot use native Gtk
     // support for other backends such as Wayland.
-    gdk_set_allowed_backends ("x11");
+    //
+    // Use an environment variable to enable unfinished Wayland support.
+    if (getenv("GVIM_ENABLE_WAYLAND") == NULL)
+       gdk_set_allowed_backends ("x11");
 #endif
 
 #ifdef FEAT_GUI_GNOME
@@ -2024,6 +2058,10 @@ scroll_event(GtkWidget *widget,
 {
     int            button;
     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))
        gtk_widget_grab_focus(widget);
@@ -2042,6 +2080,16 @@ scroll_event(GtkWidget *widget,
        case GDK_SCROLL_RIGHT:
            button = MOUSE_6;
            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
            return FALSE;
     }
@@ -2054,8 +2102,38 @@ scroll_event(GtkWidget *widget,
 
     vim_modifiers = modifiers_gdk2mouse(event->state);
 
-    gui_send_mouse_event(button, (int)event->x, (int)event->y,
-                                                       FALSE, vim_modifiers);
+#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,
+               FALSE, vim_modifiers);
 
     return TRUE;
 }
@@ -2509,10 +2587,12 @@ setup_save_yourself(void)
        // Fall back to old method
 
        // 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),
-                   GDK_WINDOW_XID(mainwin_win),
+       GdkWindow * const mainwin_win = gtk_widget_get_window(gui.mainwin);
+       if (XGetWMProtocols(dpy, GDK_WINDOW_XID(mainwin_win),
                    &existing_atoms, &count))
        {
            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.
     if (echo_wid_arg)
     {
-       printf("WID: %ld\n", (long)GDK_WINDOW_XID(mainwin_win));
+       if (gui_mch_get_display())
+           printf("WID: %ld\n", (long)GDK_WINDOW_XID(mainwin_win));
+       else
+           printf("WID: 0\n");
        fflush(stdout);
     }
 
@@ -2655,27 +2738,30 @@ mainwin_realize(GtkWidget *widget UNUSED, gpointer data UNUSED)
        setup_save_yourself();
 
 #ifdef FEAT_CLIENTSERVER
-    if (serverName == NULL && serverDelayedStartName != NULL)
+    if (gui_mch_get_display())
     {
-       // This is a :gui command in a plain vim with no previous server
-       commWindow = GDK_WINDOW_XID(mainwin_win);
+       if (serverName == NULL && serverDelayedStartName != NULL)
+       {
+           // This is a :gui command in a plain vim with no previous server
+           commWindow = GDK_WINDOW_XID(mainwin_win);
 
-       (void)serverRegisterName(GDK_WINDOW_XDISPLAY(mainwin_win),
-                                serverDelayedStartName);
-    }
-    else
-    {
-       /*
-        * Cannot handle "XLib-only" windows with gtk event routines, we'll
-        * have to change the "server" registration to that of the main window
-        * If we have not registered a name yet, remember the window.
-        */
-       serverChangeRegisteredWindow(GDK_WINDOW_XDISPLAY(mainwin_win),
-                                    GDK_WINDOW_XID(mainwin_win));
+           (void)serverRegisterName(GDK_WINDOW_XDISPLAY(mainwin_win),
+                                   serverDelayedStartName);
+       }
+       else
+       {
+           /*
+           * Cannot handle "XLib-only" windows with gtk event routines, we'll
+           * have to change the "server" registration to that of the main window
+           * If we have not registered a name yet, remember the window.
+           */
+           serverChangeRegisteredWindow(GDK_WINDOW_XDISPLAY(mainwin_win),
+                                       GDK_WINDOW_XID(mainwin_win));
+       }
+       gtk_widget_add_events(gui.mainwin, GDK_PROPERTY_CHANGE_MASK);
+       g_signal_connect(G_OBJECT(gui.mainwin), "property-notify-event",
+                       G_CALLBACK(property_event), NULL);
     }
-    gtk_widget_add_events(gui.mainwin, GDK_PROPERTY_CHANGE_MASK);
-    g_signal_connect(G_OBJECT(gui.mainwin), "property-notify-event",
-                    G_CALLBACK(property_event), NULL);
 #endif
 }
 
@@ -3919,6 +4005,9 @@ gui_mch_init(void)
                          GDK_BUTTON_PRESS_MASK |
                          GDK_BUTTON_RELEASE_MASK |
                          GDK_SCROLL_MASK |
+#if GTK_CHECK_VERSION(3,4,0)
+                         GDK_SMOOTH_SCROLL_MASK |
+#endif
                          GDK_KEY_PRESS_MASK |
                          GDK_KEY_RELEASE_MASK |
                          GDK_POINTER_MOTION_MASK |
@@ -4520,6 +4609,10 @@ gui_mch_open(void)
 #endif
     g_signal_connect(G_OBJECT(gui.formwin), "configure-event",
                                       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
     // Set up for receiving DND items.
@@ -4603,8 +4696,12 @@ gui_mch_exit(int rc UNUSED)
     int
 gui_mch_get_winpos(int *x, int *y)
 {
-    gtk_window_get_position(GTK_WINDOW(gui.mainwin), x, y);
-    return OK;
+    if (gui_mch_get_display())
+    {
+       gtk_window_get_position(GTK_WINDOW(gui.mainwin), x, y);
+       return OK;
+    }
+    return FAIL;
 }
 
 /*
@@ -6229,9 +6326,10 @@ gui_mch_haskey(char_u *name)
     int
 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));
        return OK;
     }
@@ -6242,18 +6340,18 @@ gui_get_x11_windis(Window *win, Display **dis)
 }
 #endif
 
-#if defined(FEAT_CLIENTSERVER) \
-       || (defined(FEAT_X11) && defined(FEAT_CLIPBOARD)) || defined(PROTO)
-
     Display *
 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));
     else
        return NULL;
 }
-#endif
 
     void
 gui_mch_beep(void)
@@ -6915,9 +7013,10 @@ clip_mch_request_selection(Clipboard_T *cbd)
            return;
     }
 
-    // Final fallback position - use the X CUT_BUFFER0 store
-    yank_cut_buffer0(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin)),
-           cbd);
+    if (gui_mch_get_display())
+       // Final fallback position - use the X CUT_BUFFER0 store
+       yank_cut_buffer0(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(gui.mainwin)),
+               cbd);
 }
 
 /*
@@ -7083,9 +7182,11 @@ 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...)
-    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);
+    Display * dpy = gui_mch_get_display();
+    if (dpy)
+       XWarpPointer(dpy, (Window)0,
+               GDK_WINDOW_XID(gtk_widget_get_window(gui.drawarea)),
+               0, 0, 0U, 0U, x, y);
 }
 
 
index af8f00604c677033ae2e6a6175b28e4203046e6a..dae5bbe827e871fbebe433bf80941d36d44961e7 100644 (file)
@@ -2320,12 +2320,11 @@ mch_settitle(char_u *title, char_u *icon)
 #ifdef FEAT_X11
     if (get_x11_windis() == OK)
        type = 1;
-#else
-# if defined(FEAT_GUI_PHOTON) \
+#endif
+#if defined(FEAT_GUI_PHOTON) \
     || defined(FEAT_GUI_GTK) || defined(FEAT_GUI_HAIKU)
     if (gui.in_use)
        type = 1;
-# endif
 #endif
 
     /*
index 82abb646732d4bf20ea6fb0a82979154c887127f..e67d39ad22df6a7e0eecaf59c7dcebe7496e99a3 100644 (file)
@@ -160,6 +160,14 @@ func CheckEnv(name)
   endif
 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 CheckGui call CheckGui()
 func CheckGui()
index 53947f410bae209a37ff4b8e9dd295bae1e25685..8be521b9f71c31c65e5001b32392e4d0aa1d9cbe 100644 (file)
@@ -13,7 +13,7 @@ source shared.vim
 
 func Check_X11_Connection()
   if has('x11')
-    CheckEnv DISPLAY
+    CheckX11
     try
       call remote_send('xxx', '')
     catch
index e13f4c3dc5ef78232e52f2435366c0cd5569762c..dbf1d3b3101561bcd9494996ce290cfdeddfacc3 100644 (file)
@@ -111,6 +111,8 @@ func Test_getfontname_without_arg()
 endfunc
 
 func Test_getwinpos()
+  CheckX11
+
   call assert_match('Window position: X \d\+, Y \d\+', execute('winpos'))
   call assert_true(getwinposx() >= 0)
   call assert_true(getwinposy() >= 0)
@@ -897,7 +899,7 @@ func Test_set_term()
 endfunc
 
 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)
   else
     call assert_equal(0, v:windowid)
index 1d269425473d960508b35dbf83487651345013dc..322ce6260b91103cc695b189d6af26d4264c4af1 100644 (file)
@@ -139,8 +139,8 @@ func Test_quotestar()
   if has('macunix')
     let skipped = Do_test_quotestar_for_macunix()
   elseif has('x11')
-    if empty($DISPLAY)
-      let skipped = "Test can only run when $DISPLAY is set."
+    if empty($DISPLAY) || !empty($WAYLAND_DISPLAY)
+      let skipped = "Test can only run when $DISPLAY is set and $WAYLAND_DISPLAY is not set."
     else
       let skipped = Do_test_quotestar_for_x11()
     endif
index 7bf5a4116211856f1a881a056a1e363a2a118faa..7c703916045e70e11bf08d49d275a93df41a4492 100644 (file)
@@ -518,9 +518,10 @@ func Test_geometry()
       call writefile([&columns, &lines, getwinposx(), getwinposy(), string(getwinpos())], "Xtest_geometry")
       qall
     [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,
     " 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')
       " Depending on the GUI library and the windowing system the final size
       " might be a bit different, allow for some tolerance.  Tuned based on
@@ -529,9 +530,12 @@ func Test_geometry()
       " for some reason, the window may contain fewer lines than requested
       " for GTK, so allow some tolerance
       call assert_inrange(8, 13,  str2nr(lines[1]))
-      call assert_equal('41', lines[2])
-      call assert_equal('150', lines[3])
-      call assert_equal('[41, 150]', lines[4])
+      " 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('150', lines[3])
+        call assert_equal('[41, 150]', lines[4])
+      endif
     endif
   endif
 
index 9af0d0709091d5a2b7ca530fcdcde7383b809057..aa819811cc1590a04886c549d53aa9e4857db8be 100644 (file)
@@ -3409,7 +3409,7 @@ def Test_remote_foreground()
   CheckFeature clientserver
   # remote_foreground() doesn't fail on MS-Windows
   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'])
   assert_fails('remote_foreground("NonExistingServer")', 'E241:')
index 6dd48d1be83d5d3253fe53a254ddd3d851069ea3..cf123b5b2a299b910637b3af141630178aa1a2e0 100644 (file)
@@ -704,6 +704,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    64,
 /**/
     63,
 /**/