To: vim_dev@googlegroups.com Subject: Patch 8.2.4776 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.4776 Problem: GTK: 'lines' and 'columns' may change during startup. Solution: Ignore stale GTK resize events. (Ernie Rael, closes #10179) Files: src/gui_gtk_x11.c *** ../vim-8.2.4775/src/gui_gtk_x11.c 2022-04-15 13:53:30.052708679 +0100 --- src/gui_gtk_x11.c 2022-04-17 18:24:50.852088820 +0100 *************** *** 397,402 **** --- 397,526 ---- #endif /* + * Keep a short term resize history so that stale gtk responses can be + * discarded. + * When a gtk_window_resize() request is sent to gtk, the width/height of + * the request is saved. Recent stale requests are kept around in a list. + * See https://github.com/vim/vim/issues/10123 + */ + #if 0 // Change to 1 to enable ch_log() calls for debugging. + # ifdef FEAT_JOB_CHANNEL + # define ENABLE_RESIZE_HISTORY_LOG + # endif + #endif + + /* + * History item of a resize request. + * Width and height are of gui.mainwin. + */ + typedef struct resize_history { + int used; // If true, can't match for discard. Only matches once. + int width; + int height; + #ifdef ENABLE_RESIZE_HISTORY_LOG + int seq; // for ch_log messages + #endif + struct resize_history *next; + } resize_hist_T; + + // never NULL during execution + static resize_hist_T *latest_resize_hist; + // list of stale resize requests + static resize_hist_T *old_resize_hists; + + /* + * Used when calling gtk_window_resize(). + * Create a resize request history item, put previous request on stale list. + * Width/height are the size of the request for the gui.mainwin. + */ + static void + alloc_resize_hist(int width, int height) + { + // alloc a new resize hist, save current in list of old history + resize_hist_T *prev_hist = latest_resize_hist; + resize_hist_T *new_hist = ALLOC_CLEAR_ONE(resize_hist_T); + + new_hist->width = width; + new_hist->height = height; + latest_resize_hist = new_hist; + + // previous hist item becomes head of list + prev_hist->next = old_resize_hists; + old_resize_hists = prev_hist; + + #ifdef ENABLE_RESIZE_HISTORY_LOG + new_hist->seq = prev_hist->seq + 1; + ch_log(NULL, "gui_gtk: New resize seq %d (%d, %d) [%d, %d]", + new_hist->seq, width, height, (int)Columns, (int)Rows); + #endif + } + + /* + * Free everything on the stale resize history list. + * This list is empty when there are no outstanding resize requests. + */ + static void + clear_resize_hists() + { + #ifdef ENABLE_RESIZE_HISTORY_LOG + int i = 0; + #endif + + if (latest_resize_hist) + latest_resize_hist->used = TRUE; + while (old_resize_hists != NULL) + { + resize_hist_T *next_hist = old_resize_hists->next; + + vim_free(old_resize_hists); + old_resize_hists = next_hist; + #ifdef ENABLE_RESIZE_HISTORY_LOG + i++; + #endif + } + #ifdef ENABLE_RESIZE_HISTORY_LOG + ch_log(NULL, "gui_gtk: free %d hists", i); + #endif + } + + // true if hist item is unused and matches w,h + #define MATCH_WIDTH_HEIGHT(hist, w, h) \ + (!hist->used && hist->width == w && hist->height == h) + + /* + * Search the resize hist list. + * Return true if the specified width,height match an item in the list that + * has never matched before. Mark the matching item as used so it will + * not match again. + */ + static int + match_stale_width_height(int width, int height) + { + resize_hist_T *hist = old_resize_hists; + + for (hist = old_resize_hists; hist != NULL; hist = hist->next) + if (MATCH_WIDTH_HEIGHT(hist, width, height)) + { + #ifdef ENABLE_RESIZE_HISTORY_LOG + ch_log(NULL, "gui_gtk: discard seq %d, cur seq %d", + hist->seq, latest_resize_hist->seq); + #endif + hist->used = TRUE; + return TRUE; + } + return FALSE; + } + + #if defined(EXITFREE) + static void + free_all_resize_hist() + { + clear_resize_hists(); + vim_free(latest_resize_hist); + } + #endif + + /* * GTK doesn't set the GDK_BUTTON1_MASK state when dragging a touch. Add this * state when dragging. */ *************** *** 593,598 **** --- 717,723 ---- #if defined(USE_GNOME_SESSION) vim_free(abs_restart_command); #endif + free_all_resize_hist(); } #endif *************** *** 709,715 **** xev.xproperty.window = commWindow; xev.xproperty.state = PropertyNewValue; serverEventProc(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(widget)), ! &xev, 0); } return FALSE; } --- 834,840 ---- xev.xproperty.window = commWindow; xev.xproperty.state = PropertyNewValue; serverEventProc(GDK_WINDOW_XDISPLAY(gtk_widget_get_window(widget)), ! &xev, 0); } return FALSE; } *************** *** 720,727 **** */ static void gtk_settings_xft_dpi_changed_cb(GtkSettings *gtk_settings UNUSED, ! GParamSpec *pspec UNUSED, ! gpointer data UNUSED) { // Create a new PangoContext for this screen, and initialize it // with the current font if necessary. --- 845,852 ---- */ static void gtk_settings_xft_dpi_changed_cb(GtkSettings *gtk_settings UNUSED, ! GParamSpec *pspec UNUSED, ! gpointer data UNUSED) { // Create a new PangoContext for this screen, and initialize it // with the current font if necessary. *************** *** 4006,4012 **** GdkEventConfigure *event, gpointer data UNUSED) { ! int usable_height = event->height; #if GTK_CHECK_VERSION(3,22,2) && !GTK_CHECK_VERSION(3,22,4) // As of 3.22.2, GdkWindows have started distributing configure events to --- 4131,4166 ---- GdkEventConfigure *event, gpointer data UNUSED) { ! int usable_height = event->height; ! // Resize requests are made for gui.mainwin, ! // get it's dimensions for searching if this event ! // is a response to a vim request. ! GdkWindow *win = gtk_widget_get_window(gui.mainwin); ! int w = gdk_window_get_width(win); ! int h = gdk_window_get_height(win); ! ! #ifdef ENABLE_RESIZE_HISTORY_LOG ! ch_log(NULL, "gui_gtk: form_configure_event: (%d, %d) [%d, %d]", ! w, h, (int)Columns, (int)Rows); ! #endif ! ! // Look through history of recent vim resize reqeusts. ! // If this event matches: ! // - "latest resize hist" We're caught up; ! // clear the history and process this event. ! // If history is, old to new, 100, 99, 100, 99. If this event is ! // 99 for the stale, it is matched against the current. History ! // is cleared, we my bounce, but no worse than before. ! // - "older/stale hist" If match an unused event in history, ! // then discard this event, and mark the matching event as used. ! // - "no match" Figure it's a user resize event, clear history. ! // NOTE: clear history is default, then all incoming events are processed ! ! if (!MATCH_WIDTH_HEIGHT(latest_resize_hist, w, h) ! && match_stale_width_height(w, h)) ! // discard stale event ! return TRUE; ! clear_resize_hists(); #if GTK_CHECK_VERSION(3,22,2) && !GTK_CHECK_VERSION(3,22,4) // As of 3.22.2, GdkWindows have started distributing configure events to *************** *** 4329,4343 **** * manager upon us and should not interfere with what VIM is requesting * upon startup. */ g_signal_connect(G_OBJECT(gui.formwin), "configure-event", ! G_CALLBACK(form_configure_event), NULL); #ifdef FEAT_DND // Set up for receiving DND items. gui_gtk_set_dnd_targets(); g_signal_connect(G_OBJECT(gui.drawarea), "drag-data-received", ! G_CALLBACK(drag_data_received_cb), NULL); #endif // With GTK+ 2, we need to iconify the window before calling show() --- 4483,4498 ---- * manager upon us and should not interfere with what VIM is requesting * upon startup. */ + latest_resize_hist = ALLOC_CLEAR_ONE(resize_hist_T); g_signal_connect(G_OBJECT(gui.formwin), "configure-event", ! G_CALLBACK(form_configure_event), NULL); #ifdef FEAT_DND // Set up for receiving DND items. gui_gtk_set_dnd_targets(); g_signal_connect(G_OBJECT(gui.drawarea), "drag-data-received", ! G_CALLBACK(drag_data_received_cb), NULL); #endif // With GTK+ 2, we need to iconify the window before calling show() *************** *** 4516,4521 **** --- 4671,4677 ---- width += get_menu_tool_width(); height += get_menu_tool_height(); + alloc_resize_hist(width, height); // track the resize request if (gtk_socket_id == 0) gtk_window_resize(GTK_WINDOW(gui.mainwin), width, height); else *** ../vim-8.2.4775/src/version.c 2022-04-17 17:34:37.660960579 +0100 --- src/version.c 2022-04-17 18:14:28.856281284 +0100 *************** *** 748,749 **** --- 748,751 ---- { /* Add new patch number below this line */ + /**/ + 4776, /**/ -- The Feynman problem solving Algorithm: 1) Write down the problem 2) Think real hard 3) Write down the answer /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///