Subject: bug#76691: `display-monitor-attributes-list` not working properly on macOS

From: Robert Pluim <[email-masked]>
Date: Wed, 05 Mar 2025 14:44:41 +0100

>>>>> On Wed, 5 Mar 2025 06:38:05 -0500, Ship Mints <[email-masked]> said:

    Ship> On Wed, Mar 5, 2025 at 4:04 AM Robert Pluim <[email-masked]> wrote:
    >> >>>>> On Tue, 4 Mar 2025 11:06:29 -0500, Ship Mints <[email-masked]>
    >> said:
    >> 
    Ship> On Tue, Mar 4, 2025 at 10:59 AM Ship Mints <[email-masked]>
    >> wrote:
    >> >> On Tue, Mar 4, 2025 at 10:34 AM Robert Pluim <[email-masked]>
    >> wrote:
    >> >>
    >> >>> It gives me reasonable looking names here:
    >> >>>
    >> >>> (((name . "PL3467WQ") (geometry 0 0 3440 1440) (workarea 0 25 3440
    >> >>> 1415) (mm-size 801 329) (frames #<frame *scratch* 0x131887028>)
    >> >>> (source . "NS")) ((name . "Built-in Display") (geometry 459 1440
    >> 2048
    >> >>> 1332) (workarea 459 1440 2048 1287) (mm-size 290 189) (frames)
    >> (source
    >> >>> . "NS")))
    >> >>>
    >> >>
    >> >> Robert,
    >> >>
    >> >> When you run (x-display-list), what do you get? Just your host name,
    >> >> right? And if you unplug and replug your monitors and rerun?
    >> >>
    >> 
    >> I get just my host name.
    >> 
    Ship> And also (display-monitor-attributes-list) just to make sure it
    >> works with
    Ship> comings and goings of displays.
    >> 
    >> I unplugged and replugged my external monitor, and Emacs crashed in
    >> `read_char', which is a different crash from the one I saw earlier,
    >> which was in `Fx_create_frame'. Iʼve got the lldb session if it helps.
    >> 

    Ship> The way make-frame-on-monitor is implemented is nothing special.  Just find
    Ship> the coordinates of the "workspace" occupied by the named monitor and use
    Ship> those as the basis for the new frame.  The bt from yesterday's perhaps
    Ship> indicates some kind of guard might be needed for frame coordinates that
    Ship> might be out of bounds, perhaps?  Do you think the frame on the second
    Ship> monitor was larger than the screen?  I admit to not having played much with
    Ship> trying to make oversized frames but it happens to me occasionally if only
    Ship> over left and right by a column or row or two, not more.

The default frame size is smaller than both monitors. I guess itʼs
possible something decided to place it off screen.

    Ship> I'm curious what the read_char bt looks like.  You saw the patch, it's
    Ship> pretty much a nothing.  I updated it yesterday to use xstrdup instead of
    Ship> the two-step.  I doubt that's anything.  But here's the updated patch, just
    Ship> in case.

It might be an existing emacs issue, rather than anything to do with
your patch (if youʼre feeling inspired, rewriting the socket handling
on macOS to use the normal event loop rather than the hackery with a
separate thread to run select might improve the port a lot. Or it might
make no difference)

Anyway, Iʼm suspicious about the fact that `ns_read_socket' appears in
this backtrace twice.

* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
  * frame #0: 0x00000001854e3720 libsystem_kernel.dylib`__pthread_kill + 8
    frame #1: 0x000000018551bf70 libsystem_pthread.dylib`pthread_kill + 288
    frame #2: 0x0000000185428908 libsystem_c.dylib`abort + 128
    frame #3: 0x0000000185331e38 libsystem_malloc.dylib`malloc_vreport + 896
    frame #4: 0x000000018535a458 libsystem_malloc.dylib`malloc_zone_error + 100
    frame #5: 0x0000000185349774 libsystem_malloc.dylib`nanov2_guard_corruption_detected + 44
    frame #6: 0x0000000185349734 libsystem_malloc.dylib`nanov2_allocate_outlined + 460
    frame #7: 0x0000000185348468 libsystem_malloc.dylib`nanov2_calloc_type + 568
    frame #8: 0x000000018b69c610 CoreGraphics`CGGStackCreateWithGState + 40
    frame #9: 0x000000018b71b0b0 CoreGraphics`CGDisplayListDrawInContextDelegate + 596
    frame #10: 0x0000000189590ee4 AppKit`___lldb_unnamed_symbol169773 + 884
    frame #11: 0x0000000189609008 AppKit`___lldb_unnamed_symbol172077 + 100
    frame #12: 0x000000018e165fbc QuartzCore`CABackingStoreUpdate_ + 284
    frame #13: 0x000000018e1bc2d8 QuartzCore`invocation function for block in CA::Layer::display_() + 120
    frame #14: 0x000000018e16503c QuartzCore`-[CALayer _display] + 1636
    frame #15: 0x0000000189608e94 AppKit`___lldb_unnamed_symbol172075 + 1372
    frame #16: 0x00000001896096b0 AppKit`___lldb_unnamed_symbol172087 + 28
    frame #17: 0x00000001894fc49c AppKit`___lldb_unnamed_symbol166799 + 148
    frame #18: 0x0000000189608f88 AppKit`___lldb_unnamed_symbol172076 + 128
    frame #19: 0x000000018e1641b8 QuartzCore`CA::Layer::display_if_needed(CA::Transaction*) + 784
    frame #20: 0x000000018e2f30e4 QuartzCore`CA::Context::commit_transaction(CA::Transaction*, double, double*) + 528
    frame #21: 0x000000018e146780 QuartzCore`CA::Transaction::commit() + 648
    frame #22: 0x000000018929da9c AppKit`__62+[CATransaction(NSCATransaction) NS_setFlushesWithDisplayLink]_block_invoke + 272
    frame #23: 0x0000000189ca88f4 AppKit`___NSRunLoopObserverCreateWithHandler_block_invoke + 64
    frame #24: 0x0000000185603be8 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36
    frame #25: 0x0000000185603ad4 CoreFoundation`__CFRunLoopDoObservers + 552
    frame #26: 0x0000000185603104 CoreFoundation`__CFRunLoopRun + 788
    frame #27: 0x0000000185602734 CoreFoundation`CFRunLoopRunSpecific + 588
    frame #28: 0x0000000190b71530 HIToolbox`RunCurrentEventLoopInMode + 292
    frame #29: 0x0000000190b7717c HIToolbox`ReceiveNextEventCommon + 216
    frame #30: 0x0000000190b77508 HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 76
    frame #31: 0x000000018917a848 AppKit`_DPSNextEvent + 660
    frame #32: 0x0000000189ae0c24 AppKit`-[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 688
    frame #33: 0x000000018916d874 AppKit`-[NSApplication run] + 480
    frame #34: 0x00000001001fbf44 emacs`-[EmacsApp run](self=0x0000000129722680, _cmd=<unavailable>) at nsterm.m:5938:7 [opt]
    frame #35: 0x000000010020efb0 emacs`ns_read_socket_1(terminal=<unavailable>, hold_quit=<unavailable>, no_release=<unavailable>) at nsterm.m:4812:11 [opt]
    frame #36: 0x00000001000dc838 emacs`gobble_input at keyboard.c:7919:17 [opt]
    frame #37: 0x00000001000d8d80 emacs`swallow_events [inlined] get_input_pending(flags=1) at keyboard.c:7875:7 [opt]
    frame #38: 0x00000001000d8d0c emacs`swallow_events(do_display=true) at keyboard.c:4602:3 [opt]
    frame #39: 0x0000000100007d38 emacs`sit_for(timeout=(EMACS_INT) $4 = 30, reading=true, display_option=1) at dispnew.c:6284:3 [opt]
    frame #40: 0x00000001000d5ba0 emacs`read_char(commandflag=<unavailable>, map=<unavailable>, prev_event=<unavailable>, used_mouse_menu=<unavailable>, end_time=<unavailable>) at keyboard.c:2923:11 [opt]
    frame #41: 0x00000001000d2ab0 emacs`read_key_sequence(keybuf=<unavailable>, prompt=(struct Lisp_Symbol *) $22 = 0x00000001008eefe0, dont_downcase_last=false, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=<unavailable>, disable_text_conversion_p=<unavailable>) at keyboard.c:10743:12 [opt]
    frame #42: 0x00000001000d0ee4 emacs`command_loop_1 at keyboard.c:1429:15 [opt]
    frame #14: 0x000000018e16503c QuartzCore`-[CALayer _display] + 1636
    frame #15: 0x0000000189608e94 AppKit`___lldb_unnamed_symbol172075 + 1372
    frame #16: 0x00000001896096b0 AppKit`___lldb_unnamed_symbol172087 + 28
    frame #17: 0x00000001894fc49c AppKit`___lldb_unnamed_symbol166799 + 148
    frame #18: 0x0000000189608f88 AppKit`___lldb_unnamed_symbol172076 + 128
    frame #19: 0x000000018e1641b8 QuartzCore`CA::Layer::display_if_needed(CA::Transaction*) + 784
    frame #20: 0x000000018e2f30e4 QuartzCore`CA::Context::commit_transaction(CA::Transaction*, double, double*) + 528
    frame #21: 0x000000018e146780 QuartzCore`CA::Transaction::commit() + 648
    frame #22: 0x000000018929da9c AppKit`__62+[CATransaction(NSCATransaction) NS_setFlushesWithDisplayLink]_block_invoke + 272
    frame #23: 0x0000000189ca88f4 AppKit`___NSRunLoopObserverCreateWithHandler_block_invoke + 64
    frame #24: 0x0000000185603be8 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36
    frame #25: 0x0000000185603ad4 CoreFoundation`__CFRunLoopDoObservers + 552
    frame #26: 0x0000000185603104 CoreFoundation`__CFRunLoopRun + 788
    frame #27: 0x0000000185602734 CoreFoundation`CFRunLoopRunSpecific + 588
    frame #28: 0x0000000190b71530 HIToolbox`RunCurrentEventLoopInMode + 292
    frame #29: 0x0000000190b7717c HIToolbox`ReceiveNextEventCommon + 216
    frame #30: 0x0000000190b77508 HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 76
    frame #31: 0x000000018917a848 AppKit`_DPSNextEvent + 660
    frame #32: 0x0000000189ae0c24 AppKit`-[NSApplication(NSEventRouting) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 688
    frame #33: 0x000000018916d874 AppKit`-[NSApplication run] + 480
    frame #34: 0x00000001001fbf44 emacs`-[EmacsApp run](self=0x0000000129722680, _cmd=<unavailable>) at nsterm.m:5938:7 [opt]
    frame #35: 0x000000010020efb0 emacs`ns_read_socket_1(terminal=<unavailable>, hold_quit=<unavailable>, no_release=<unavailable>) at nsterm.m:4812:11 [opt]
    frame #36: 0x00000001000dc838 emacs`gobble_input at keyboard.c:7919:17 [opt]
    frame #37: 0x00000001000d8d80 emacs`swallow_events [inlined] get_input_pending(flags=1) at keyboard.c:7875:7 [opt]
    frame #38: 0x00000001000d8d0c emacs`swallow_events(do_display=true) at keyboard.c:4602:3 [opt]
    frame #39: 0x0000000100007d38 emacs`sit_for(timeout=(EMACS_INT) $4 = 30, reading=true, display_option=1) at dispnew.c:6284:3 [opt]
    frame #40: 0x00000001000d5ba0 emacs`read_char(commandflag=<unavailable>, map=<unavailable>, prev_event=<unavailable>, used_mouse_menu=<unavailable>, end_time=<unavailable>) at keyboard.c:2923:11 [opt]
    frame #41: 0x00000001000d2ab0 emacs`read_key_sequence(keybuf=<unavailable>, prompt=(struct Lisp_Symbol *) $22 = 0x00000001008eefe0, dont_downcase_last=false, can_return_switch_frame=true, fix_current_buffer=true, prevent_redisplay=<unavailable>, disable_text_conversion_p=<unavailable>) at keyboard.c:10743:12 [opt]
    frame #42: 0x00000001000d0ee4 emacs`command_loop_1 at keyboard.c:1429:15 [opt]
    frame #43: 0x000000010015b994 emacs`internal_condition_case(bfun=(emacs`command_loop_1 at keyboard.c:1324), handlers=<unavailable>, hfun=(emacs`cmd_error at keyboard.c:970)) at eval.c:1613:25 [opt]
    frame #44: 0x00000001000d0b78 emacs`command_loop_2(handlers=(struct Lisp_Symbol *) $43 = 0x00000001008ef070) at keyboard.c:1168:11 [opt]
    frame #45: 0x000000010015b030 emacs`internal_catch(tag=(struct Lisp_Symbol *) $64 = 0x00000001008f63f0, func=(emacs`command_loop_2 at keyboard.c:1164), arg=(struct Lisp_Symbol *) $85 = 0x00000001008ef070) at eval.c:1292:25 [opt]
    frame #46: 0x00000001000d03a8 emacs`command_loop at keyboard.c:1138:13 [opt]
    frame #47: 0x00000001000d0270 emacs`recursive_edit_1 at keyboard.c:754:9 [opt]
    frame #48: 0x00000001001068c0 emacs`Fread_from_minibuffer [inlined] read_minibuf(map=<unavailable>, initial=<unavailable>, prompt=(struct Lisp_String *) $94 = 0x00000001297199a0, expflag=<unavailable>, histvar=<unavailable>, histpos=(EMACS_INT) $100 = 0, defalt=<unavailable>, allow_props=<unavailable>, inherit_input_method=<unavailable>) at minibuf.c:905:3 [opt]
    frame #49: 0x0000000100105bf0 emacs`Fread_from_minibuffer(prompt=<unavailable>, initial_contents=<unavailable>, keymap=(struct Lisp_Cons *) $106 = 0x0000000102fe8910, read=<unavailable>, hist=<unavailable>, default_value=<unavailable>, inherit_input_method=(struct Lisp_Symbol *) $124 = 0x00000001008eefe0) at minibuf.c:1394:9 [opt]
    frame #50: 0x00000001001a54f8 emacs`exec_byte_code(fun=<unavailable>, args_template=<unavailable>, nargs=<unavailable>, args=<unavailable>) at bytecode.c:812:14 [opt]
    frame #51: 0x000000010015e9f0 emacs`funcall_lambda(fun=<unavailable>, nargs=<unavailable>, arg_vector=<unavailable>) at eval.c:3252:9 [opt] [artificial]
    frame #52: 0x000000010015e298 emacs`funcall_general(fun=<unavailable>, numargs=<unavailable>, args=<unavailable>) at lisp.h:0:43 [opt] [artificial]
    frame #53: 0x0000000100159260 emacs`Ffuncall(nargs=9, args=(struct Lisp_Symbol *) $133 = 0x00000002706ed540) at eval.c:3093:21 [opt]
    frame #54: 0x0000000100106f94 emacs`Fcompleting_read(prompt=(struct Lisp_String *) $139 = 0x00000001297199a0, collection=(struct Lisp_Vector *) $145 = 0x000000010285dd38, predicate=(struct Lisp_Vector *) $151 = 0x000000012a1d5748, require_match=(struct Lisp_Symbol *) $169 = 0x00000001008ef010, initial_input=(struct Lisp_Symbol *) $190 = 0x00000001008eefe0, hist=(struct Lisp_Symbol *) $211 = 0x000000010285c5c8, def=(struct Lisp_Symbol *) $232 = 0x00000001008eefe0, inherit_input_method=(struct Lisp_Symbol *) $253 = 0x00000001008eefe0) at minibuf.c:2049:10 [opt]
    frame #55: 0x00000001001a54f8 emacs`exec_byte_code(fun=<unavailable>, args_template=<unavailable>, nargs=<unavailable>, args=<unavailable>) at bytecode.c:812:14 [opt]
    frame #56: 0x00000001001a4ad4 emacs`Fbyte_code(bytestr=<unavailable>, vector=(struct Lisp_Vector *) $262 = 0x000000010285c3d8, maxdepth=(EMACS_INT) $268 = 3) at bytecode.c:329:10 [opt]
    frame #57: 0x00000001001588c0 emacs`eval_sub(form=(struct Lisp_Cons *) $274 = 0x000000010285c3a8) at eval.c:2604:15 [opt]
    frame #58: 0x000000010015ce4c emacs`Feval(form=<unavailable>, lexical=<unavailable>) at eval.c:2462:28 [opt]
    frame #59: 0x0000000100155f48 emacs`Fcall_interactively(function=<unavailable>, record_flag=(struct Lisp_Symbol *) $292 = 0x00000001008eefe0, keys=(struct Lisp_Vector *) $301 = 0x000000012a2505c0) at callint.c:325:15 [opt]
    frame #60: 0x00000001001a54f8 emacs`exec_byte_code(fun=<unavailable>, args_template=<unavailable>, nargs=<unavailable>, args=<unavailable>) at bytecode.c:812:14 [opt]
    frame #61: 0x000000010015e9f0 emacs`funcall_lambda(fun=<unavailable>, nargs=<unavailable>, arg_vector=<unavailable>) at eval.c:3252:9 [opt] [artificial]
    frame #62: 0x000000010015e298 emacs`funcall_general(fun=<unavailable>, numargs=<unavailable>, args=<unavailable>) at lisp.h:0:43 [opt] [artificial]
    frame #63: 0x0000000100159260 emacs`Ffuncall(nargs=2, args=(struct Lisp_Symbol *) $319 = 0x00000002706edbc0) at eval.c:3093:21 [opt]
    frame #64: 0x00000001000d10e4 emacs`command_loop_1 at keyboard.c:1550:13 [opt]
    frame #65: 0x000000010015b994 emacs`internal_condition_case(bfun=(emacs`command_loop_1 at keyboard.c:1324), handlers=<unavailable>, hfun=(emacs`cmd_error at keyboard.c:970)) at eval.c:1613:25 [opt]
    frame #66: 0x00000001000d0b78 emacs`command_loop_2(handlers=(struct Lisp_Symbol *) $340 = 0x00000001008ef070) at keyboard.c:1168:11 [opt]
    frame #67: 0x000000010015b030 emacs`internal_catch(tag=<unavailable>, func=(emacs`command_loop_2 at keyboard.c:1164), arg=(struct Lisp_Symbol *) $361 = 0x00000001008ef070) at eval.c:1292:25 [opt]
    frame #68: 0x000000010023ee7c emacs`command_loop.cold.1 at keyboard.c:1146:2 [opt]
    frame #69: 0x00000001000d03c0 emacs`command_loop at keyboard.c:1145:2 [opt]
    frame #70: 0x00000001000d0270 emacs`recursive_edit_1 at keyboard.c:754:9 [opt]
    frame #71: 0x00000001000d0550 emacs`Frecursive_edit at keyboard.c:837:3 [opt]
    frame #72: 0x00000001000cf300 emacs`main(argc=<unavailable>, argv=0x000000016fdff2c8) at emacs.c:2646:3 [opt]
    frame #73: 0x000000018519c274 dyld`start + 2840
(lldb)

Robert
--