unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Whether a struct window *w is a live/valid window.
@ 2019-03-20 20:14 Keith David Bershatsky
  2019-03-22 15:01 ` Alan Third
  0 siblings, 1 reply; 5+ messages in thread
From: Keith David Bershatsky @ 2019-03-20 20:14 UTC (permalink / raw)
  To: Emacs Devel

I am working on feature requests #22873 (multiple fake cursors) and crosshairs #17684 (crosshairs that track the cursor position).

In trying to resolve an issue where removal of vertical scroll bars erased fake cursors that were laid during update_window, I added a check to see whether the window still exists.  Emacs crashed while running under gdb with the following backtrace:

(gdb) bt
#0  terminate_due_to_signal (sig=6, backtrace_limit=2147483647) at emacs.c:359
#1  0x00000001001ee93a in die (
    msg=0x100337658 "((((struct vectorlike_header *) ((void *) (gl_intptr_t) (((window).i) - (Lisp_Vectorlike)))) ->size) & (PSEUDOVECTOR_FLAG | PVEC_TYPE_MASK)) == (PSEUDOVECTOR_FLAG | (PVEC_WINDOW << PSEUDOVECTOR_AREA_B"..., 
    file=0x10036c3e8 <__func__.21885+38033> "nsterm.m", line=5325)
    at alloc.c:7214
#2  0x00000001002d8d49 in ns_judge_scroll_bars (f=0x118b5f040) at nsterm.m:5325
#3  0x0000000100071a86 in redisplay_internal (from_where=3) at xdisp.c:19142
#4  * * *

Here is what I did to create the problem:

.  nsterm.h defines the structure for the EmacsScroller and one of the components is:  struct window *window

.  I set up a simple function in nsterm.m that returns WINDOW from the above-described structure:

    - (struct window *)mc_get_window
    {
      return window;
    }

.  I added a reference in nsterm.h to the new function, at the same location under EmacsScroller where other similar functions are referenced (e.g., initFrame, setFrame, setPosition, etc.).

    - (struct window *)mc_get_window;

.  In ns_judge_scroll_bars in nsterm.m, I added a check to see whether the window was still live/valid:

    for (i = [subviews count]-1; i >= 0; --i)
    {
      view = [subviews objectAtIndex: i];
      if (![view isKindOfClass: [EmacsScroller class]]) continue;
      Lisp_Object window;
      struct window *w = [view mc_get_window];
      if (w != NULL)
        XSETWINDOW (window, w);
      if (w != NULL
          && !WINDOW_LIVE_P (window))
        {
          ...
        }
        ...
    }

.  Emacs is crashing sometimes at the location of XSETWINDOW (window, w) in the above-described check.


Q:  What is the proper way to check whether the WINDOW component in EmacsScroller coincides with a live/valid window?



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Whether a struct window *w is a live/valid window.
  2019-03-20 20:14 Keith David Bershatsky
@ 2019-03-22 15:01 ` Alan Third
  0 siblings, 0 replies; 5+ messages in thread
From: Alan Third @ 2019-03-22 15:01 UTC (permalink / raw)
  To: Keith David Bershatsky; +Cc: Emacs Devel

On Wed, Mar 20, 2019 at 01:14:13PM -0700, Keith David Bershatsky wrote:
> I am working on feature requests #22873 (multiple fake cursors) and
> crosshairs #17684 (crosshairs that track the cursor position).
> 
> In trying to resolve an issue where removal of vertical scroll bars
> erased fake cursors that were laid during update_window

Sorry if this has already been covered, but after the scrollbar is
removed the toolkit should mark the area under the toolkit as needing
redrawn. That will then cause [EmacsView drawRect:], and subsequently
expose_frame, to be called on that rectangle. Why aren’t the cursors
being redrawn at that time?

Is everything else ‘under’ the scrollbars being drawn correctly?
-- 
Alan Third



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Whether a struct window *w is a live/valid window.
@ 2019-03-23  6:30 Keith David Bershatsky
  2019-03-23 10:49 ` Alan Third
  0 siblings, 1 reply; 5+ messages in thread
From: Keith David Bershatsky @ 2019-03-23  6:30 UTC (permalink / raw)
  To: Alan Third; +Cc: emacs-devel

Thank you, Allen, for reading and responding to this particular thread.

I could be wrong, but it appears to me that removal of the vertical scroll bars does not remove the glyphs that are underneath.  As such, the glyphs that are underneath are not redrawn.  However, removal of the vertical scroll bar has the side effect of removing the fake cursors.  My workaround has been to remove the scroll bars graciously so as not to cause removal of the fake cursors.  That way, the fake cursors do not need to be redrawn.  On the NS port, I use removeFromSuperviewWithoutNeedingDisplay.  On the w32 port, I use SendMessage (hwnd, WM_SETREDRAW, false, 0) before destroying a window (DestroyWindow); and, I set the bRepaint argument of MoveWindow to false when the window just needs to be moved.

In the current draft of multiple fake cursors, they are laid immediately following the calls to draw_glyphs.

FACT PATTERNS:  Two (2) adjacent windows (left/right) within a single frame.  Either the user deletes the left window; or, the user deletes the right window.  When the user deletes the left window, its scroll bar (center of screen) is no longer associated with a live/valid window.  When a user deletes the right window, the scroll bar (center of screen) remains associated with the left window but needs to be moved.

When either the left or right window is deleted, update_window redraws all of the screen lines and effectively erases the scroll bar (center of screen).  In a related thread, Eli Z. was kind enough to provide an outline of the relevant events:

  . `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.

When I stepped through the code, I observed that removal of the scroll bars is delayed on the NS and W32 platforms.  update_window runs _before_ scroll bars are actually removed.  Scroll bar removal occurs during read_char at approximately the location of read_decoded_event_from_main_queue.

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

The w32 port uses a Lisp_Object for the WINDOW component of the scroll bar structure.  Calling WINDOW_LIVE_P seems to be working well on that platform.

The NS port uses `struct window *window`, and Emacs occasionally crashes when I have attempted to use XSETWINDOW (as described in the initial post of this thread).  My workaround is to tentatively use:

   if (w != NULL
       && NILP (w->contents))

instead of trying to create a Lisp_Object with XSETWINDOW so that I can then use WINDOW_LIVE_P.

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

> Date: [03-22-2019 08:01:48] <22 Mar 2019 15:01:48 +0000>
> From: Alan Third <alan@idiocy.org>
> To: Keith David Bershatsky <esq@lawlist.com>
> Cc: Emacs Devel <emacs-devel@gnu.org>
> Subject: Re: Whether a struct window *w is a live/valid window.
> 
> On Wed, Mar 20, 2019 at 01:14:13PM -0700, Keith David Bershatsky wrote:
> > I am working on feature requests #22873 (multiple fake cursors) and
> > crosshairs #17684 (crosshairs that track the cursor position).
> >
> > In trying to resolve an issue where removal of vertical scroll bars
> > erased fake cursors that were laid during update_window
> 
> Sorry if this has already been covered, but after the scrollbar is
> removed the toolkit should mark the area under the toolkit as needing
> redrawn. That will then cause [EmacsView drawRect:], and subsequently
> expose_frame, to be called on that rectangle. Why aren't the cursors
> being redrawn at that time?
> 
> Is everything else ‘under' the scrollbars being drawn correctly?
> --
> Alan Third



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Whether a struct window *w is a live/valid window.
  2019-03-23  6:30 Keith David Bershatsky
@ 2019-03-23 10:49 ` Alan Third
  0 siblings, 0 replies; 5+ messages in thread
From: Alan Third @ 2019-03-23 10:49 UTC (permalink / raw)
  To: Keith David Bershatsky; +Cc: emacs-devel

On Fri, Mar 22, 2019 at 11:30:26PM -0700, Keith David Bershatsky wrote:
> 
> When I stepped through the code, I observed that removal of the
> scroll bars is delayed on the NS and W32 platforms. update_window
> runs _before_ scroll bars are actually removed. Scroll bar removal
> occurs during read_char at approximately the location of
> read_decoded_event_from_main_queue.

OK, I think you have a slight misunderstanding of what ‘removing the
scrollbars’ does, on NS at lease.

When a scrollbar is removed it doesn’t ‘undraw’ the scrollbar from the
screen, it marks the area it was as needing to be redrawn, and that is
done from scratch. So the fact that the glyphs don’t appear to be
deleted means that they are *redrawn*. The multiple cursors appear to
be deleted, so that means that they are *not* redrawn.

The redrawing doesn’t happen synchronously either. It occurs when we
call [NSApp run], which is generally done when we’re handling input.

If you look in nsterm.m you’ll see a call in ns_read_socket and
ns_select. That’s where the screen will be redrawn.

You could try redrawing the cursors in [EmacsView drawRect:], but it
has no concept of Emacs windows, so you would have to step through
them and make sure you only updated the windows in the current frame,
and that they’re live.

It would be better if they were redrawn in expose_window, perhaps.

One thing to bear in mind is that drawRect: sets up clipping areas so
you can’t draw outside areas that have been marked for update. So the
usual drawing routine goes like

redisplay:
  mark area as dirty (setNeedsDisplayInRect:)
  
check for input:
  run the NS event loop ([NSApp run])
    drawRect:
      expose_frame
        expose_window
          do actual drawing somewhere in here

> The NS port uses `struct window *window`, and Emacs occasionally
> crashes when I have attempted to use XSETWINDOW (as described in the
> initial post of this thread). My workaround is to tentatively use:
> 
>    if (w != NULL && NILP (w->contents))

That looks reasonable to me.
-- 
Alan Third



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Whether a struct window *w is a live/valid window.
@ 2019-03-23 17:03 Keith David Bershatsky
  0 siblings, 0 replies; 5+ messages in thread
From: Keith David Bershatsky @ 2019-03-23 17:03 UTC (permalink / raw)
  To: Alan Third; +Cc: emacs-devel

Thank you, Alan, for confirming that a reasonable approach to checking whether the window is alive/valid is to use:

    if (w != NULL && NILP (w->contents))

The drawing method for glyphs that I am familiar with is as follows:

draw_glyphs

  FRAME_RIF (f)->draw_glyph_string (s);

    font->driver->draw

Those series of events do not occur when the vertical scroll bar is removed.  The scroll bar removal is processed in the span of just one (1) gdb step; i.e., "s".

ns_read_socket ... [NSAPP run];

The calls to "draw_glyphs ... font->driver->draw" have already occurred and the window has already been properly updated (with fake cursors) *before* "ns_read_socket ... [NSAPP run]" is processed.  Does "ns_read_socket ... [NSAPP run]" have a sort of "selective photographic memory" of the glyphs, but not the fake cursors that were created with NSRectFill?

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



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2019-03-23 17:03 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2019-03-23 17:03 Whether a struct window *w is a live/valid window Keith David Bershatsky
  -- strict thread matches above, loose matches on Subject: below --
2019-03-23  6:30 Keith David Bershatsky
2019-03-23 10:49 ` Alan Third
2019-03-20 20:14 Keith David Bershatsky
2019-03-22 15:01 ` Alan Third

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).