Subject: Re: bug#77988: 31.0.50; No more images after fullscreen and load-theme

From: Eli Zaretskii <[email-masked]>
Date: Tue, 20 May 2025 14:57:21 +0300

> From: Elijah Gabe Pérez <[email-masked]>
> Cc: [email-masked],  [email-masked],  [email-masked]
> Date: Mon, 19 May 2025 14:06:56 -0600
> 
> I've followed all the steps, It doesn't seem that there are any
> differences:
> 
> M-: (find-file "etc/images/gnus/gnus.svg")
> M-: (set-frame-parameter nil 'fullscreen 'fullboth)
> C-l
> 
> (gdb) p Vframe_list
> $1 = {
>   i = 0x7ffff185e2c3
> }
> (gdb) xcar
> $2 = {
>   i = 0xbd3a7d
> }
> (gdb) xframe
> $3 = (struct frame *) 0xbd3a78
> "gnus.svg - GNU Emacs at fedora"
> (gdb) p $3->image_cache
> $4 = (struct image_cache *) 0xc20740
> (gdb) c
> Continuing.
> 
> (After the svg was displayed incorrectly):
> M-: (load-theme 'modus-operandi)
> C-l
> 
> Thread 1 "emacs" hit Breakpoint 3, Frecenter (arg=..., redisplay=...) at window.c:6976
> 6976	  struct window *w = XWINDOW (selected_window);
> (gdb) p $3->image_cache
> $5 = (struct image_cache *) 0xc20740

OK, so the image cache stays put.  But what about its contents?  To
see this, we first need to know the cache slot where this image is
stored.  Here's how:

After visiting the image, type C-l and define one additional
breakpoint:

  (gdb) break set_cursor_from_row
  (gdb) c

When you continue, this new breakpoint will break almost immediately.
In most cases, the first time it breaks is in the wrong window.
Here4's how to verify that:

  Thread 1 hit Breakpoint 3, set_cursor_from_row (w=0x90d35e8, row=0x10056c18,
      matrix=0x909fa88, delta=0, delta_bytes=0, dy=0, dvpos=0) at xdisp.c:18363
  18363     struct glyph *glyph = row->glyphs[TEXT_AREA];
  (gdb) p w->contents
  $1 = XIL(0xa00000000907a4f0)
  (gdb) xbuffer
  $2 = (struct buffer *) 0x907a4f0
  0x9048bf0 " *Echo Area 1*"

The command "xbuffer" (and other commands I use below) are defined in
src/.gdbinit.  So if GDB says it doesn't know about that command, tell
it to read .gdbinit:

  (gdb) source /path/to/emacs/src/.gdbinit

and then repeat the command, which should now work.

As you see above, the first time the breakpoint breaks, Emacs is
redisplaying the echo-area, which is not what we want.  So continue
the program until the next time the breakpoint breaks:

  (gdb) c
  Continuing.

  Thread 1 hit Breakpoint 3, set_cursor_from_row (w=0x90d3408, row=0x100c2b50,
      matrix=0x1005cf80, delta=0, delta_bytes=0, dy=0, dvpos=0) at xdisp.c:18363
  18363     struct glyph *glyph = row->glyphs[TEXT_AREA];
  (gdb) p w->contents
  $3 = XIL(0xa0000000090c3d20)
  (gdb) xbuffer
  $4 = (struct buffer *) 0x90c3d20
  0x90491ec "gnus.svg"

And now we are in the correct window.  So:

  (gdb) n
  18364     struct glyph *end = glyph + row->used[TEXT_AREA];
  (gdb) pgrow
  TEXT: 2 glyphs
    0    0: IMAGE[25] slice=0,0,260,264 pos=1 w=260 a+d=132+132 MB
    1  260: CHAR[ ] pos=0 blev=0,btyp=B w=8 a+d=132+132 MB

This tells us that the first (and only) "display element" in the
(only) screen line of the window is an image, and "[25]" says that the
image's cache slot is 25.  (In your case, the slot number might be
different.)  Now:

  (gdb) p Vframe_list
  $7 = XIL(0xc000000009150100)
  (gdb) xcar
  $8 = 0xa0000000090d31e8
  (gdb) xframe
  $9 = (struct frame *) 0x90d31e8
  "gnus.svg - GNU Emacs at ELIZ-PC"
  (gdb) p $9->image_cache
  $10 = (struct image_cache *) 0x90b8cf8
  (gdb) p *$9->image_cache
  $11 = {
    buckets = 0x1005bfa0,
    images = 0x90ae788,
    size = 50,
    used = 26,
    refcount = 1,
    scaling_col_width = 10
  }
  (gdb) p *$9->image_cache->images[25]
  $12 = {
    timestamp = {
      tv_sec = 1747466321,
      tv_nsec = 665317000
    },
    pixmap = 0x840517f3,
    mask = 0x0,
    xform = {
      eM11 = 1,
      eM12 = 0,
      eM21 = 0,
      eM22 = 1,
      eDx = 0,
      eDy = 0
    },
    smoothing = true,
    colors = 0x0,
    ncolors = 0,
    background = 4294967295,
    face_foreground = 33554432,
    face_background = 50331647,
    face_font_size = 13,
    face_font_family = 0x100ea860 "Courier New",
    face_font_height = 16,
    face_font_width = 8,
    background_transparent = 0,
    background_valid = 1,
    background_transparent_valid = 0,
    width = 260,
    height = 264,
    scale = 1,
    corners = {0, 0, -1, 0},
    ascent = 50,
    spec = XIL(0xc0000000090fb4e0),
    dependencies = XIL(0xc0000000090fb030),
    relief = 0,
    hmargin = 0,
    vmargin = 0,
    type = 0xd750c0 <image_types>,
    load_failed_p = false,
    lisp_data = XIL(0),
    hash = 15697133349389086448,
    id = 25,
    next = 0x0,
    prev = 0x0
  }

Do this before and after the corruption, and let's see if the cached
image changes.  Notes:

  . the breakpoint in set_cursor_from_row gets hit very frequently, so
    disable it after you use it the first time (the command is
    "disable N" where N is the number of the breakpoint), then do
    whatever it takes to have the image display incorrectly, then
    enable the breakpoint ("enable N") after C-l
  . the cache slot of the image might change after it gets corrupted,
    so don't assume it's the same slot number, but instead look at
    what the "pgrow" command shows, and use that.

Thanks.