Apps/Gedit/FixingTextCutOffBug

See:

100% reproducible with certain files.

Generating a file to reproduce the bug (here 100 lines, might need to be adapted for your screen size):

$ seq 1 100 > text-cut-off

Open the file from the terminal, with gedit window already maximized.

Some printf-debugging is possible (gdb might not be appropriate because of switching windows between gedit and the terminal, which triggers different events in the gedit app).

See the wip/text-cut-off git branches in gedit for some tests.

Workarounds

Workaround 1

g_object_set (gtk_settings_get_default (),
              "gtk-enable-animations", FALSE,
              NULL);

Workaround 2

Unrelated to workaround 1 (so it's an OR, not an AND).

After loading a file, do not scroll to the cursor.

Hints for finding the location of the bug

Most probably related to the combination of: animations, and scrolling the GtkTextView (see the two workarounds above).

In gtkadjustment.c? If gtk_adjustment_enable_animation() (internal function) does nothing, the bug doesn't occur.

A small digression with a new mini Adjustment class (ideas such as: respect class invariants at all times, and store the original value before being clamped):

First conclusion

It's related to GtkAdjustment. Either its implementation, or its use by GtkTextView.

In gtktextview.c, after s/gtk_adjustment_animate_to_value/gtk_adjustment_set_value/, the bug doesn't occur anymore.

Locate the bug more precisely

I think it's that (Update: yes it's that):

On the last call to gtk_text_view_size_allocate() (while the text is still cut off), the adjustments are animating, but some adjustment values need to change (at least the page_size needs to be updated to its final value).

Because gtk_text_view_size_allocate() calls text_window_size_allocate(), which can change the SCREEN_HEIGHT(). And SCREEN_HEIGHT() is used as the vadjustment page-size.

Suggestion (?): take into account gtk_adjustment_is_animating() inside gtk_text_view_set_vadjustment_values() (and for the horizontal one too).

See comments in https://bugzilla.gnome.org/show_bug.cgi?id=733406

What happens in gedit

Example:

GtkTextView vadjustment: value=0.0 lower=0.0 upper=2000.0 page_size=969.0

Then gtk_text_view_size_allocate() is called one more time,
but the vadjustment is animating, so the page_size is not updated correctly.
The vadjustment value can go to (upper - page_size = 1031.0) max, so the text is cut off.

After unmaximize/maximize the gedit window, we get the right page_size:

GtkTextView vadjustment: value=0.0 lower=0.0 upper=2000.0 page_size=917.0

upper - page_size = 1083.0, so value can go further and show the bottom of the text.

Even without animation, there is a problem to restore the cursor position to the last line(s) (even though the text is not cut off and can be scrolled down manually):

We request to scroll to the last line.

GtkTextView vadjustment: value=1031.0 lower=0.0 upper=2000.0 page_size=969.0

value has been clamped.

Then we get the additional call to gtk_text_view_size_allocate(),
and because animations are disabled here, the vadjustment is updated.

But the value of 1031.0 is not updated, while page_size is:

GtkTextView vadjustment: value=1031.0 lower=0.0 upper=2000.0 page_size=917.0

To show the last line, it should instead be:

[scrolling manually here]

GtkTextView vadjustment: value=1083.0 lower=0.0 upper=2000.0 page_size=917.0

Simple fix in gedit

We ask to scroll to the cursor too early. By changing the idle_scroll to a timeout (250ms seems fine), everything works. But it's a hack.

Edit: actually no, doesn't work with larger files, even though the timeout is dispatched (so gtk_text_view_scroll_to_mark() is called after 250ms but it doesn't scroll to the position, weird). Need more debugging...

Edit 2: wait idle -> wait timeout of 250ms -> finally scroll: that works in all cases that I've tested :-) (but it's even more hacky). It's because the idle takes longer than 250ms with larger files: if we launch both the timeout and the idle at the same time, we first get the timeout and then the idle (while with smaller files it's the reverse).

Why there is an extra call to gtk_text_view_size_allocate()

We get the extra call to gtk_text_view_size_allocate() via gtk_container_idle_sizer() on the GeditWindow. gtk_container_idle_sizer() is called during GdkFrameClock::layout, which is thus called after the idle_scroll (idle_scroll from gedit-tab.c).

Better solution: we can expect that gtk_text_view_scroll_to_mark() works in all situations. Maybe with an implementation that connects to the GdkFrameClock (?).

gtk_text_view_flush_scroll() is maybe called too early

With this code inserted at the beginning of gtk_text_view_flush_scroll():

  if (text_view->priv->layout == NULL ||
      !gtk_text_layout_is_valid (text_view->priv->layout))
    g_warning ("%s() layout not valid", G_STRFUNC);

we get several warnings.

gtk_text_view_scroll_to_mark() directly calls gtk_text_view_flush_scroll() if the layout is valid. (If not, gtk_text_view_flush_scroll() is called later on).

Apps/Gedit/Attic/FixingTextCutOffBug (last edited 2023-12-09 05:24:34 by SébastienWilmet)