diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 07:39:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-13 07:39:41 +0000 |
commit | 00c068502d170f9f9b59c4a68aa12e8835859f6c (patch) | |
tree | 2047fc01b8c70326d9b87b47a575e7e5f2141b62 /src/gui_gtk_x11.c | |
parent | Adding upstream version 2:9.1.0016. (diff) | |
download | vim-00c068502d170f9f9b59c4a68aa12e8835859f6c.tar.xz vim-00c068502d170f9f9b59c4a68aa12e8835859f6c.zip |
Adding upstream version 2:9.1.0199.upstream/2%9.1.0199
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/gui_gtk_x11.c')
-rw-r--r-- | src/gui_gtk_x11.c | 336 |
1 files changed, 245 insertions, 91 deletions
diff --git a/src/gui_gtk_x11.c b/src/gui_gtk_x11.c index 87838b9..d4a8b93 100644 --- a/src/gui_gtk_x11.c +++ b/src/gui_gtk_x11.c @@ -116,6 +116,7 @@ enum TARGET_TEXT, TARGET_TEXT_URI_LIST, TARGET_TEXT_PLAIN, + TARGET_TEXT_PLAIN_UTF8, TARGET_VIM, TARGET_VIMENC }; @@ -132,7 +133,9 @@ static const GtkTargetEntry selection_targets[] = {"UTF8_STRING", 0, TARGET_UTF8_STRING}, {"COMPOUND_TEXT", 0, TARGET_COMPOUND_TEXT}, {"TEXT", 0, TARGET_TEXT}, - {"STRING", 0, TARGET_STRING} + {"STRING", 0, TARGET_STRING}, + {"text/plain;charset=utf-8", 0, TARGET_TEXT_PLAIN_UTF8}, + {"text/plain", 0, TARGET_TEXT_PLAIN} }; #define N_SELECTION_TARGETS ARRAY_LENGTH(selection_targets) @@ -790,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, @@ -1119,11 +1152,14 @@ modifiers_gdk2vim(guint state) if (state & GDK_MOD1_MASK) modifiers |= MOD_MASK_ALT; #if GTK_CHECK_VERSION(2,10,0) - if (state & GDK_SUPER_MASK) + if (state & GDK_META_MASK) modifiers |= MOD_MASK_META; -#endif + if (state & GDK_SUPER_MASK) + modifiers |= MOD_MASK_CMD; +#else if (state & GDK_MOD4_MASK) - modifiers |= MOD_MASK_META; + modifiers |= MOD_MASK_CMD; +#endif return modifiers; } @@ -1528,6 +1564,8 @@ selection_get_cb(GtkWidget *widget UNUSED, && info != (guint)TARGET_VIMENC && info != (guint)TARGET_VIM && info != (guint)TARGET_COMPOUND_TEXT + && info != (guint)TARGET_TEXT_PLAIN + && info != (guint)TARGET_TEXT_PLAIN_UTF8 && info != (guint)TARGET_TEXT) return; @@ -1659,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) @@ -1696,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 @@ -2007,15 +2049,26 @@ button_press_event(GtkWidget *widget, } /* - * GTK+ 2 abstracts scrolling via the GdkEventScroll. + * GTK+ abstracts scrolling via the GdkEventScroll. */ static gboolean scroll_event(GtkWidget *widget, GdkEventScroll *event, gpointer data UNUSED) { - int button; + int button = 0; // silence gcc int_u vim_modifiers; +#if GTK_CHECK_VERSION(3,4,0) + static double acc_x, acc_y; +#if !GTK_CHECK_VERSION(3,22,0) + static guint32 last_smooth_event_time; +#endif +#define DT_X11 1 +#define DT_WAYLAND 2 + static int display_type; + if (!display_type) + display_type = gui_mch_get_display() ? DT_X11 : DT_WAYLAND; +#endif if (gtk_socket_id != 0 && !gtk_widget_has_focus(widget)) gtk_widget_grab_focus(widget); @@ -2034,6 +2087,29 @@ 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->is_stop) + { + acc_x = acc_y = 0; + // this event tells us to stop, without an actual moving + return FALSE; + } +#if GTK_CHECK_VERSION(3,22,0) + if (gdk_device_get_axes(event->device) & GDK_AXIS_FLAG_WHEEL) + // this is from a wheel (as oppose to a touchpad / trackpoint) +#else + if (event->time - last_smooth_event_time > 50) + // reset our accumulations after 50ms of silence +#endif + acc_x = acc_y = 0; + acc_x += event->delta_x; + acc_y += event->delta_y; +#if !GTK_CHECK_VERSION(3,22,0) + last_smooth_event_time = event->time; +#endif + break; +#endif default: // This shouldn't happen return FALSE; } @@ -2046,8 +2122,42 @@ 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) + // on x11, despite not requested, when we copy into primary clipboard, + // we'll get smooth events. Unsmooth ones will also come along. + if (event->direction == GDK_SCROLL_SMOOTH && display_type == DT_WAYLAND) + { + 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 +#undef DT_X11 +#undef DT_WAYLAND +#endif + gui_send_mouse_event(button, (int)event->x, (int)event->y, + FALSE, vim_modifiers); return TRUE; } @@ -2501,10 +2611,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; @@ -2612,7 +2724,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); } @@ -2647,27 +2762,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 } @@ -3533,30 +3651,28 @@ gui_mch_set_curtab(int nr) * Add selection targets for PRIMARY and CLIPBOARD selections. */ void -gui_gtk_set_selection_targets(void) +gui_gtk_set_selection_targets(GdkAtom selection) { int i, j = 0; - int n_targets = N_SELECTION_TARGETS; - GtkTargetEntry targets[N_SELECTION_TARGETS]; + static int n_targets = N_SELECTION_TARGETS; + static GtkTargetEntry targets[N_SELECTION_TARGETS]; - for (i = 0; i < (int)N_SELECTION_TARGETS; ++i) + if (targets[0].target == NULL) { - // OpenOffice tries to use TARGET_HTML and fails when we don't - // return something, instead of trying another target. Therefore only - // offer TARGET_HTML when it works. - if (!clip_html && selection_targets[i].info == TARGET_HTML) - n_targets--; - else - targets[j++] = selection_targets[i]; + for (i = 0; i < (int)N_SELECTION_TARGETS; ++i) + { + // OpenOffice tries to use TARGET_HTML and fails when we don't + // return something, instead of trying another target. Therefore only + // offer TARGET_HTML when it works. + if (!clip_html && selection_targets[i].info == TARGET_HTML) + n_targets--; + else + targets[j++] = selection_targets[i]; + } } - gtk_selection_clear_targets(gui.drawarea, (GdkAtom)GDK_SELECTION_PRIMARY); - gtk_selection_clear_targets(gui.drawarea, (GdkAtom)clip_plus.gtk_sel_atom); - gtk_selection_add_targets(gui.drawarea, - (GdkAtom)GDK_SELECTION_PRIMARY, - targets, n_targets); - gtk_selection_add_targets(gui.drawarea, - (GdkAtom)clip_plus.gtk_sel_atom, + gtk_selection_clear_targets(gui.drawarea, selection); + gtk_selection_add_targets(gui.drawarea, selection, targets, n_targets); } @@ -3906,17 +4022,37 @@ gui_mch_init(void) #endif // Determine which events we will filter. - gtk_widget_set_events(gui.drawarea, - GDK_EXPOSURE_MASK | - GDK_ENTER_NOTIFY_MASK | - GDK_LEAVE_NOTIFY_MASK | - GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_SCROLL_MASK | - GDK_KEY_PRESS_MASK | - GDK_KEY_RELEASE_MASK | - GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK); + gint event_mask = + GDK_EXPOSURE_MASK | + GDK_ENTER_NOTIFY_MASK | + GDK_LEAVE_NOTIFY_MASK | + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_KEY_PRESS_MASK | + GDK_KEY_RELEASE_MASK | + GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK; +#if GTK_CHECK_VERSION(3,4,0) + if (GDK_IS_X11_DISPLAY(gdk_display_get_default())) + { + // for X11, if we were using smooth scroll events, we + // would get an scroll without deltas on the very first user scroll* and + // get both "unsmooth" scroll and smooth scroll events after + // copying into the primary selection + // + // *: https://bugzilla.gnome.org/show_bug.cgi?id=675959 + event_mask |= GDK_SCROLL_MASK; + } + else + { + // for Wayland, touchpads don't generate "unsmooth" scroll events. Both + // touchpads and wheels generate smooth scroll events expectedly. + event_mask |= GDK_SMOOTH_SCROLL_MASK; + } +#else + event_mask |= GDK_SCROLL_MASK; +#endif + gtk_widget_set_events(gui.drawarea, event_mask); gtk_widget_show(gui.drawarea); gui_gtk_form_put(GTK_FORM(gui.formwin), gui.drawarea, 0, 0); @@ -4032,20 +4168,7 @@ gui_mch_init(void) 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); - - /* - * Add selection handler functions. - */ - 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); - - gui_gtk_set_selection_targets(); - - g_signal_connect(G_OBJECT(gui.drawarea), "selection-get", - G_CALLBACK(selection_get_cb), NULL); + G_CALLBACK(scroll_event), NULL); // Pretend we don't have input focus, we will get an event if we do. gui.in_focus = FALSE; @@ -4527,6 +4650,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. @@ -4579,6 +4706,17 @@ gui_mch_open(void) #endif } + /* + * Add selection handler functions. + */ + 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); + + g_signal_connect(G_OBJECT(gui.drawarea), "selection-get", + G_CALLBACK(selection_get_cb), NULL); + return OK; } @@ -4599,8 +4737,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; } /* @@ -6225,9 +6367,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; } @@ -6238,18 +6381,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) @@ -6911,9 +7054,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); } /* @@ -6935,10 +7079,18 @@ clip_mch_lose_selection(Clipboard_T *cbd UNUSED) int clip_mch_own_selection(Clipboard_T *cbd) { + // If we're blocking autocmds, we are filling the register to offer the + // selection (inside selection-get) + if (is_autocmd_blocked()) + return OK; + int success; success = gtk_selection_owner_set(gui.drawarea, cbd->gtk_sel_atom, gui.event_time); + // don't update on every visual selection change + if (!(cbd->owned && VIsual_active)) + gui_gtk_set_selection_targets(cbd->gtk_sel_atom); gui_mch_update(); return (success) ? OK : FAIL; } @@ -7071,9 +7223,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); } |