Adding fake cursors when resizing a window.

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Adding fake cursors when resizing a window.

Keith David Bershatsky
I am working on optimization of feature requests #22873 (multiple fake cursors) and #17684 (crosshairs that track the cursor position, and a visible fill column indicator).

The current design erases fake cursor before draw_glyphs is called, and then adds back the fake cursors with updated coordinates subsequent thereto.

Fact Pattern:  Two-window left/right split with vertical scroll bars on each window.  The user deletes the right window and the left window increases in size to fill the entire frame.  update_window is called and all of the fake get erased at the outset using the window's current_matrix before scrolling_window is called.  Then, draw_glyphs does its thing on the relevant lines and fake cursors are laid on each relevant line subsequent thereto.

From what I can tell, it appears that draw_glyphs is able to write glyphs _underneath_ the vertical scroll bar in the center of the screen (that is about to be removed).  However, drawing a rectangle (to create a fake cursor) from nsterm.m cannot write a fake cursor _underneath_ the vertical scroll bar in the center of the screen (that is about to be removed).  When the vertical scroll bar is removed from the center of the screen, the area where the fake cursor could not be drawn is readily apparent.

One of my thoughts on dealing with this issue is to remove the vertical scroll bar (splitting the 2 windows) before update_window runs.

Q:  Is my guess about what is happening correct?  And, when is the best/earliest point in time to draw the fake cursors in the area where the vertical scroll bar will be removed?

SCREENSHOT -- BEFORE:  https://www.lawlist.com/images/before_03_06_2019.png

SCREENSHOT -- AFTER:  https://www.lawlist.com/images/after_03_06_2019.png

Reply | Threaded
Open this post in threaded view
|

Re: Adding fake cursors when resizing a window.

martin rudalics
 > One of my thoughts on dealing with this issue is to remove the
 > vertical scroll bar (splitting the 2 windows) before update_window
 > runs.

 From my experience, the scroll bar drawing code is allergic to such
changes.  Please be sure to test it with all toolkit and non-toolkit
combinations if you intend to change it.

Thanks, martin

Reply | Threaded
Open this post in threaded view
|

Re: Adding fake cursors when resizing a window.

Eli Zaretskii
In reply to this post by Keith David Bershatsky
> Date: Wed, 06 Mar 2019 19:42:16 -0800
> From: Keith David Bershatsky <[hidden email]>
>
> Fact Pattern:  Two-window left/right split with vertical scroll bars on each window.  The user deletes the right window and the left window increases in size to fill the entire frame.  update_window is called and all of the fake get erased at the outset using the window's current_matrix before scrolling_window is called.  Then, draw_glyphs does its thing on the relevant lines and fake cursors are laid on each relevant line subsequent thereto.
>
> From what I can tell, it appears that draw_glyphs is able to write glyphs _underneath_ the vertical scroll bar in the center of the screen (that is about to be removed).  However, drawing a rectangle (to create a fake cursor) from nsterm.m cannot write a fake cursor _underneath_ the vertical scroll bar in the center of the screen (that is about to be removed).  When the vertical scroll bar is removed from the center of the screen, the area where the fake cursor could not be drawn is readily apparent.

I'm confused by your description of the sequence of events.  Is this
what happens on NS, or are you saying you see this on X and w32 as
well?  I'm less familiar with the redisplay sequence on NS (and it
also recently tends to change frequently), but on X and w32 your
description is either inaccurate or misses something, because the
sequence AFAIK is like this:

  . redisplay_internal calls the condemn_scroll_bars_hook, which marks
    all scroll bars as candidates for deletion
  . then redisplay_internal calls redisplay_windows, which walks the
    window-tree and examines each window, whereby each window that is
    still alive in the window-tree "redeems" its scroll bars by
    marking them not to be deleted
  . then redisplay_internal calls judge_scroll_bars_hook, which
    removes all the scroll bars that were not "redeemed"
  . and only after that redisplay_internal calls update_frame, which
    calls update_window for each live window, and that ends up calling
    draw_glyphs to deliver the updated contents to the glass.

So I don't understand why you see draw_glyphs draw "underneath" the
scroll bar, since by the time draw_glyphs is called, the scroll bar in
the middle of the frame was supposed to be deleted already.

> One of my thoughts on dealing with this issue is to remove the vertical scroll bar (splitting the 2 windows) before update_window runs.

AFAIK, we already do that, at least on X and on w32.

Reply | Threaded
Open this post in threaded view
|

Re: Adding fake cursors when resizing a window.

Keith David Bershatsky
In reply to this post by Keith David Bershatsky
Thank you, Eli and Martin, for reviewing and responding to this particular thread.

I am able to observe the behavior described on Emacs for w32 and NS, but _not_ running on X11 with the current build settings.

I have set up stderr messages in all locations where draw_glyphs is called and have concluded that draw_glyphs is _not_ responsible for erasing the fake cursors along the vertical strip that forms the scroll bar in the middle of the screen (which gets removed when the right window is deleted, and the left window increases to fill the entire frame).  In addition to the stderr messages, I can visually see that the gap left in the area of fake cursors is the same width as the vertical scroll bar, and the gap does not align exactly with two characters.  In other words, if draw_glyphs were somehow responsible for erasing the fake cursors in the area affected, then the fake cursors would be removed at the same X-axis and exact pixel width of each new character that gets drawn on the glass.

I do not know why draw_glyphs is able to redraw the row without any problems, but drawing fake cursors along that region of the vertical scroll bar fails.  On the w32 platform, the fake cursors at issue (BAR/HBAR_CURSOR) are drawn with w32_fill_area.  On the NS platform, the fake cursors (BAR/HBAR_CURSOR) are drawn with NSRectFill.

It probably would not be too difficult to create a minimal working example that draws/erases a horizontal line (the width of the window) every command loop to help demonstrate the issue, if that would be helpful ....

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

> Date: [03-07-2019 07:12:57] <07 Mar 2019 17:12:57 +0200>
> From: Eli Zaretskii <[hidden email]>
> To: Keith David Bershatsky <[hidden email]>
> CC: [hidden email]
> Subject: Re: Adding fake cursors when resizing a window.
>
> > Date: Wed, 06 Mar 2019 19:42:16 -0800
> > From: Keith David Bershatsky <[hidden email]>
> >
> > Fact Pattern:  Two-window left/right split with vertical scroll bars on each window.  The user deletes the right window and the left window increases in size to fill the entire frame.  update_window is called and all of the fake get erased at the outset using the window's current_matrix before scrolling_window is called.  Then, draw_glyphs does its thing on the relevant lines and fake cursors are laid on each relevant line subsequent thereto.
> >
> > From what I can tell, it appears that draw_glyphs is able to write glyphs _underneath_ the vertical scroll bar in the center of the screen (that is about to be removed).  However, drawing a rectangle (to create a fake cursor) from nsterm.m cannot write a fake cursor _underneath_ the vertical scroll bar in the center of the screen (that is about to be removed).  When the vertical scroll bar is removed from the center of the screen, the area where the fake cursor could not be drawn is readily apparent.
>
> I'm confused by your description of the sequence of events.  Is this
> what happens on NS, or are you saying you see this on X and w32 as
> well?  I'm less familiar with the redisplay sequence on NS (and it
> also recently tends to change frequently), but on X and w32 your
> description is either inaccurate or misses something, because the
> sequence AFAIK is like this:
>
>   . redisplay_internal calls the condemn_scroll_bars_hook, which marks
>     all scroll bars as candidates for deletion
>   . then redisplay_internal calls redisplay_windows, which walks the
>     window-tree and examines each window, whereby each window that is
>     still alive in the window-tree "redeems" its scroll bars by
>     marking them not to be deleted
>   . then redisplay_internal calls judge_scroll_bars_hook, which
>     removes all the scroll bars that were not "redeemed"
>   . and only after that redisplay_internal calls update_frame, which
>     calls update_window for each live window, and that ends up calling
>     draw_glyphs to deliver the updated contents to the glass.
>
> So I don't understand why you see draw_glyphs draw "underneath" the
> scroll bar, since by the time draw_glyphs is called, the scroll bar in
> the middle of the frame was supposed to be deleted already.
>
> > One of my thoughts on dealing with this issue is to remove the vertical scroll bar (splitting the 2 windows) before update_window runs.
>
> AFAIK, we already do that, at least on X and on w32.

Reply | Threaded
Open this post in threaded view
|

Re: Adding fake cursors when resizing a window.

Eli Zaretskii
> Date:  Thu, 07 Mar 2019 17:39:20 -0800
> From:  Keith David Bershatsky <[hidden email]>
> Cc:  [hidden email],Martin Rudalics <[hidden email]>
>
> I am able to observe the behavior described on Emacs for w32 and NS, but _not_ running on X11 with the current build settings.
>
> I have set up stderr messages in all locations where draw_glyphs is called and have concluded that draw_glyphs is _not_ responsible for erasing the fake cursors along the vertical strip that forms the scroll bar in the middle of the screen (which gets removed when the right window is deleted, and the left window increases to fill the entire frame).  In addition to the stderr messages, I can visually see that the gap left in the area of fake cursors is the same width as the vertical scroll bar, and the gap does not align exactly with two characters.  In other words, if draw_glyphs were somehow responsible for erasing the fake cursors in the area affected, then the fake cursors would be removed at the same X-axis and exact pixel width of each new character that gets drawn on the glass.

Step through the code starting at the point where you redraw the fake
cursors, and see what happens.  Maybe some later operation erases
them, or something.

Reply | Threaded
Open this post in threaded view
|

Re: Adding fake cursors when resizing a window.

Keith David Bershatsky
In reply to this post by Keith David Bershatsky
I have been working on stepping through the code and have observed the following series of events:

-  When there is a two-window left/right split and the user calls delete-window on the right window, update_window runs a couple of times.

-  draw_glyphs does its job on all relevant screen lines.

-  Fake cursors are placed on all relevant screen lines immediately following the calls to draw_glyphs.

-  Although the call to remove/add scroll bars happens earlier in time, it is not actually processed by Emacs until the tail end of read_char, at approximately read_decoded_event_from_main_queue.  Here is a screenshot of gdb at the point where this happens:

http://www.lawlist.com/images/after_03_10_2019.png

-  Although the scroll bar in the center is no longer visible because it was overwritten during update_window, Emacs tries to remove the center scroll bar anyway and that is what erases the fake cursors along the vertical strip in the center of the screen.

-  At about the exact same time that the scroll bar in the center of the screen gets erased, the right scroll bar on the far right of the window is added.

I do not know if the scroll bar in the center will always be completely overwritten by update_window in this circumstance.  If it will always be completely overwritten in this situation, then one idea would be to figure out how to suppress formally removing the scroll bar in the center.

And the other idea, which Martin cautioned against, is to figure out how to remove the center scroll bar at the outset of update_window (instead of letting Emacs delay the execution until after all is said and done).

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

> Date: [03-07-2019 23:55:48] <08 Mar 2019 09:55:48 +0200>
> From: Eli Zaretskii <[hidden email]>
> To: Keith David Bershatsky <[hidden email]>
> CC: [hidden email],[hidden email]
> Subject: Re: Adding fake cursors when resizing a window.
>
> * * *
>
> Step through the code starting at the point where you redraw the fake
> cursors, and see what happens.  Maybe some later operation erases
> them, or something.

Reply | Threaded
Open this post in threaded view
|

Re: Adding fake cursors when resizing a window.

Eli Zaretskii
> Date:  Sun, 10 Mar 2019 11:04:03 -0700
> From:  Keith David Bershatsky <[hidden email]>
> Cc:  [hidden email],Martin Rudalics <[hidden email]>
>
> -  Although the scroll bar in the center is no longer visible because it was overwritten during update_window, Emacs tries to remove the center scroll bar anyway and that is what erases the fake cursors along the vertical strip in the center of the screen.
>
> -  At about the exact same time that the scroll bar in the center of the screen gets erased, the right scroll bar on the far right of the window is added.

Isn't this because the window-system removes the scroll bars?

Reply | Threaded
Open this post in threaded view
|

Re: Adding fake cursors when resizing a window.

Keith David Bershatsky
In reply to this post by Keith David Bershatsky
Thank you, Eli, for helping me to understand that the issue arises because the scroll-bars are added/removed by calling window-system functions that are platform specific.

As to w32term.c, I tentatively resolved the issue in w32_set_vertical_scroll_bar by preventing MoveWindow from repainting the old/new scroll bar when enlarging the main window.  However, I only tested a 2-window left/right split.  I see that the current version of w32term.c uses SetWindowPos instead of MoveWindow.  I have not yet done any testing with altering the last argument to SetWindowPos (i.e., uFlags) to see if it is possible to prevent painting the old scroll bar when enlarging the main window.  [Draft patch proof concept attached.]

As to nsterm.m, I tentatively resolved the issue in ns_set_vertical_scroll_bar by destroying the scroll bar and preventing repaint with an Apple function called removeFromSuperviewWithoutNeedingDisplay, and then creating a new scroll bar.  [Draft patch proof concept attached.]

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

> Date: [03-10-2019 11:27:10] <10 Mar 2019 20:27:10 +0200>
> From: Eli Zaretskii <[hidden email]>
> To: Keith David Bershatsky <[hidden email]>
> CC: [hidden email],[hidden email]
> Subject: Re: Adding fake cursors when resizing a window.
>
> > Date:  Sun, 10 Mar 2019 11:04:03 -0700
> > From:  Keith David Bershatsky <[hidden email]>
> > Cc:  [hidden email],Martin Rudalics <[hidden email]>
> >
> > -  Although the scroll bar in the center is no longer visible because it was overwritten during update_window, Emacs tries to remove the center scroll bar anyway and that is what erases the fake cursors along the vertical strip in the center of the screen.
> >
> > -  At about the exact same time that the scroll bar in the center of the screen gets erased, the right scroll bar on the far right of the window is added.
>
> Isn't this because the window-system removes the scroll bars?


2019_03_13__21_16_50_327.diff (7K) Download Attachment