Package: emacs;
Reported by: Aaron Jensen <aaronjensen <at> gmail.com>
Date: Thu, 4 Oct 2018 13:07:02 UTC
Severity: minor
Tags: fixed
Merged with 31904, 33891, 34127, 34710, 36302
Found in versions 26.1.90, 26.1.91, 26.2.90, 27.0.50
Fixed in version 28.1
Done: Alan Third <alan <at> idiocy.org>
Bug is archived. No further changes may be made.
View this message in rfc822 format
From: Alan Third <alan <at> idiocy.org> To: Eli Zaretskii <eliz <at> gnu.org> Cc: boris <at> d12frosted.io, 32932 <at> debbugs.gnu.org, aaronjensen <at> gmail.com Subject: bug#32932: 27.0.50; render bugs on macOS Mojave Date: Sun, 4 Nov 2018 13:24:04 +0000
On Sat, Nov 03, 2018 at 11:03:27PM +0200, Eli Zaretskii wrote: > > Or perhaps expose_frame actually thinks it should be blank at that > > moment, but for some reason we’ve not marked the whole window or > > whatever as dirty? > > > > So we’re to display an image but it’s not loaded yet, so redisplay > > blanks the window for the time being, but we fail to mark it dirty or > > garbaged. Expose_frame comes along and draws the bit we’ve previously > > asked it to draw. Finally the image loads and redisplay marks the > > whole window as dirty leading to everything catching up at the next > > expose_frame. > > I'm puzzled by this description, and actually by the whole larger > picture. You see, I originally thought you had a problem of > flickering caused by redrawing the cursor, which was said to trigger > redrawing of the entire screen line where the cursor was, instead of > redrawing just the character under the cursor. Is that still the > problem we are discussing? If so, how does visiting the image file > come into play, and where is cursor positioned in this scenario? Apologies, Aaron’s repeatable test case involves a dired buffer of images and hitting return on one of the images. There’s a pause while it loads, during which the line with the cursor on it sometimes blanks. Then the image loads. I think what’s probably happening is that when the image begins to load the emacs window containing the dired buffer is marked as garbaged as it’s going to be replaced by the buffer containing the image, however because there’s a reasonably long gap between the user requesting the opening of the image, and the image actually loading redisplay and expose_frame have time to run. Because the window is marked as garbaged expose_window doesn’t do anything. This would be fine except we seem to have a rogue clear_area somewhere. NSTrace doesn’t show it running, and they happen too often for me to reasonably use a breakpoint to find it. Here’s some output from NSTrace: nsterm.m : 4441: [53008] ns_select nsterm.m : 5391: [53009] | [EmacsApp run] nsterm.m : 5458: [53010] | | [EmacsApp sendEvent:] nsterm.m : 5459: [53011] | | +--- Type: 10 Here we have the user hitting return in the image file in dired. nsterm.m : 6076: [53012] | | | [EmacsView keyDown:] nsterm.m : 4195: [53013] | | | | ns_send_appdefined(-1) nsterm.m : 5458: [53014] | | [EmacsApp sendEvent:] nsterm.m : 5459: [53015] | | +--- Type: 15 nsterm.m : 5429: [53016] | | | [EmacsApp stop:] nsterm.m : 4359: [53017] | ns_read_socket nsterm.m : 4359: [53018] | ns_read_socket nsterm.m : 4195: [53019] | | ns_send_appdefined(-1) nsterm.m : 5391: [53020] | | [EmacsApp run] nsterm.m : 5458: [53021] | | | [EmacsApp sendEvent:] nsterm.m : 5459: [53022] | | | +--- Type: 15 nsterm.m : 5429: [53023] | | | | [EmacsApp stop:] nsterm.m : 4359: [53024] | ns_read_socket nsterm.m : 4195: [53025] | | ns_send_appdefined(-1) nsterm.m : 5391: [53026] | | [EmacsApp run] nsterm.m : 5458: [53027] | | | [EmacsApp sendEvent:] nsterm.m : 5459: [53028] | | | +--- Type: 15 nsterm.m : 5429: [53029] | | | | [EmacsApp stop:] nsterm.m : 4359: [53030] ns_read_socket nsterm.m : 4195: [53031] | ns_send_appdefined(-1) nsterm.m : 5391: [53032] | [EmacsApp run] nsterm.m : 5458: [53033] | | [EmacsApp sendEvent:] nsterm.m : 5459: [53034] | | +--- Type: 15 nsterm.m : 5429: [53035] | | | [EmacsApp stop:] I believe this is now Emacs trying to modify the cursor. The cursor is at pixel position (381, 268). nsterm.m : 2299: [53036] ns_lisp_to_color nsterm.m : 2177: [53037] | ns_get_color(LightGoldenrod3, **) nsterm.m : 4035: [53038] ns_draw_glyph_string nsterm.m : 1191: [53039] | ns_clip_to_rect ns_clip_to_rect nsterm.m : 1195: [53040] | +--- r: (X:10 Y:268)/(W:560 H:14) nsterm.m : 1214: [53041] | +--- New dirty rect: (X:10 Y:268)/(W:560 H:14) nsterm.m : 3048: [53042] ns_draw_window_cursor nsterm.m : 3048: [53043] ns_draw_window_cursor nsterm.m : 3048: [53044] ns_draw_window_cursor nsterm.m : 1191: [53045] | ns_clip_to_rect ns_clip_to_rect nsterm.m : 1195: [53046] | +--- r: (X:381 Y:268)/(W:7 H:14) nsterm.m : 1214: [53047] | +--- New dirty rect: (X:381 Y:268)/(W:7 H:14) nsterm.m : 3048: [53048] ns_draw_window_cursor nsimage.m : 61: [53049] ns_image_for_XPM I think these are functions called by redisplay_internal. I believe they’re updating the modeline and/or the minibuffer. nsterm.m : 1060: [53050] ns_update_begin nsterm.m : 1015: [53051] | ns_update_auto_hide_menu_bar nsterm.m : 7772: [53052] | [EmacsView isFullscreen] ->> 0 nsterm.m : 1109: [53053] ns_update_window_begin nsterm.m : 4035: [53054] ns_draw_glyph_string nsterm.m : 1191: [53055] | ns_clip_to_rect ns_clip_to_rect nsterm.m : 1195: [53056] | +--- r: (X:10 Y:492)/(W:560 H:14) nsterm.m : 1214: [53057] | +--- New dirty rect: (X:10 Y:492)/(W:560 H:14) nsterm.m : 2682: [53058] ns_clear_frame_area nsterm.m : 1191: [53059] | ns_clip_to_rect ns_clip_to_rect nsterm.m : 1195: [53060] | +--- r: (X:416 Y:492)/(W:154 H:14) nsterm.m : 1214: [53061] | +--- New dirty rect: (X:416 Y:492)/(W:154 H:14) nsterm.m : 1139: [53062] ns_update_window_end nsterm.m : 3048: [53063] | ns_draw_window_cursor nsterm.m : 1176: [53064] ns_update_end nsterm.m : 2532: [53065] ns_frame_up_to_date nsterm.m : 4359: [53066] ns_read_socket nsterm.m : 4195: [53067] | ns_send_appdefined(-1) nsterm.m : 5391: [53068] | [EmacsApp run] Now drawRect is called. It currently steps through each of the unique dirty rectangles calling expose_frame. nsterm.m : 8100: [53069] | | [EmacsView drawRect:(X:10 Y:268)/(W:560 H:238)] modeline/minibuffer: nsterm.m : 8117: [53070] | | +--- Exposing rect: (X:10 Y:492)/(W:560 H:14) nsterm.m : 3048: [53071] | | | ns_draw_window_cursor nsterm.m : 4035: [53072] | | | ns_draw_glyph_string nsterm.m : 1191: [53073] | | | | ns_clip_to_rect ns_clip_to_rect nsterm.m : 1195: [53074] | | | | +--- r: (X:10 Y:492)/(W:560 H:14) nsterm.m : 3624: [53075] | | | | ns_maybe_dumpglyphs_background nsterm.m : 1229: [53076] | | | | ns_reset_clipping nsterm.m : 2922: [53077] | | | ns_draw_fringe_bitmap nsterm.m : 2924: [53078] | | | +--- which:0 cursor:0 overlay:0 width:0 height:0 period:0 nsterm.m : 1191: [53079] | | | | ns_clip_to_rect ns_clip_to_rect nsterm.m : 1195: [53080] | | | | +--- r: (X:2 Y:492)/(W:8 H:14) nsterm.m : 2961: [53081] | | | +--- clearRect: (X:2 Y:492)/(W:8 H:14) nsterm.m : 1229: [53082] | | | | ns_reset_clipping nsterm.m : 2922: [53083] | | | ns_draw_fringe_bitmap nsterm.m : 2924: [53084] | | | +--- which:0 cursor:0 overlay:0 width:0 height:0 period:0 nsterm.m : 1191: [53085] | | | | ns_clip_to_rect ns_clip_to_rect nsterm.m : 1195: [53086] | | | | +--- r: (X:570 Y:492)/(W:8 H:14) nsterm.m : 2961: [53087] | | | +--- clearRect: (X:570 Y:492)/(W:8 H:14) nsterm.m : 1229: [53088] | | | | ns_reset_clipping nsterm.m : 3048: [53089] | | | ns_draw_window_cursor Here it finally reaches the rectangle that contains the cursor. It appears to do nothing. Not even clear the area. nsterm.m : 8117: [53090] | | +--- Exposing rect: (X:10 Y:268)/(W:560 H:14) nsterm.m : 5458: [53091] | | [EmacsApp sendEvent:] nsterm.m : 5459: [53092] | | +--- Type: 11 I’ve tried to work out if drawRect is ‘helpfully’ clearing the dirty rectangles for us, but I don’t think it is. Perhaps this approach is just doomed to suffer from issues like these. -- Alan Third
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.