It's not legal to call -layoutSubtreeIfNeeded (Issue #23153)

398 views
Skip to first unread message

lszl84

unread,
Jan 18, 2023, 3:46:36 PM1/18/23
to wx-...@googlegroups.com, Subscribed

Description

Simple app logs the following message:

2023-01-18 21:43:25.481064+0100 main[63108:3984011] It's not legal to call -layoutSubtreeIfNeeded on a view which is already being laid out.  If you are implementing the view's -layout method, you can call -[super layout] instead. Break on void _NSDetectedLayoutRecursion(void) to debug.  This will be logged only once.  This may break in the future.

The code is very basic:

#include <wx/wx.h>

class MyApp : public wxApp
{
public:
    virtual bool OnInit();
};

class MyFrame : public wxFrame
{
public:
    MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size);
};

bool MyApp::OnInit()
{
    MyFrame *frame = new MyFrame("Hello World", wxDefaultPosition, wxDefaultSize);
    frame->Show(true);
    return true;
}

wxIMPLEMENT_APP(MyApp);

MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size)
    : wxFrame(NULL, wxID_ANY, title, pos, size)
{

}

Platform and version information

  • wxWidgets version you use: master (3.3.0), also reproduces on 3.1.6
  • wxWidgets port you use: wxOSX
  • OS and its version: Monterey 12.6.2


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/23153@github.com>

VZ

unread,
Jan 18, 2023, 5:48:06 PM1/18/23
to wx-...@googlegroups.com, Subscribed

Thanks for reporting this, it's probably a new warning in 12.6 (or some intermediate version, at least I can't reproduce this on my 12.0).

Could you please do what it says, i.e. break on _NSDetectedLayoutRecursion and look at the backtrace when it's called? This might allow us to fix it even without reproducing it. Otherwise I'll try to remember to look at it when I upgrade my macOS installation...


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/23153/1396196767@github.com>

lszl84

unread,
Jan 18, 2023, 7:46:04 PM1/18/23
to wx-...@googlegroups.com, Subscribed

I've mentioned that it reproduces even for an empty app, which is not true. Well, it did reproduce for me, but I think it's some crazy caching issue (more on that later if you're interested).

The fact is, it ALWAYS reproduces when showing a wxFontDialog. Here's the trace:

Console is in 'commands' mode, prefix expressions with '?'.
Launching: /Users/lukasz/Documents/Development/wx_scratchpad/build/subprojects/Build/wx_scratchpad_core/main.app/Contents/MacOS/main
Launched process 91476
bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x00007ff814d11c52 AppKit`_NSDetectedLayoutRecursion
    frame #1: 0x00007ff8144fa57d AppKit`-[NSWindow(NSConstraintBasedLayout) _layoutViewTree] + 148
    frame #2: 0x00007ff8144f6f18 AppKit`-[NSWindow _oldPlaceWindow:fromServer:] + 648
    frame #3: 0x00007ff8144f53ce AppKit`-[NSWindow _setFrameCommon:display:fromServer:] + 1278
    frame #4: 0x00007ff8145bd3b5 AppKit`-[NSThemeFrame _growWindowReshapeContentAndToolbarView:withOldToolbarFrameSize:animate:] + 1896
    frame #5: 0x00007ff8145bcb12 AppKit`-[NSThemeFrame _reshapeContentAndToolbarView:withOldToolbarFrameSize:resizeWindow:animate:] + 612
    frame #6: 0x00007ff8145a935e AppKit`-[NSThemeFrame _toolbarFrameSizeChanged:oldSize:] + 73
    frame #7: 0x00007ff8145a92ba AppKit`-[NSWindow _toolbarFrameSizeChanged:oldSize:] + 93
    frame #8: 0x00007ff81459d762 AppKit`-[NSToolbarView _layoutDirtyItemViewersAndTileToolbar] + 473
    frame #9: 0x00007ff8145c3971 AppKit`-[NSToolbarView layout] + 63
    frame #10: 0x00007ff8144fba94 AppKit`_NSViewLayout + 564
    frame #11: 0x00007ff8144fb573 AppKit`-[NSView _layoutSubtreeWithOldSize:] + 361
    frame #12: 0x00007ff8144fb6c1 AppKit`-[NSView _layoutSubtreeWithOldSize:] + 695
    frame #13: 0x00007ff8144fb6c1 AppKit`-[NSView _layoutSubtreeWithOldSize:] + 695
    frame #14: 0x00007ff8144fb6c1 AppKit`-[NSView _layoutSubtreeWithOldSize:] + 695
    frame #15: 0x00007ff8144faa85 AppKit`-[NSView _layoutSubtreeIfNeededAndAllowTemporaryEngine:] + 1041
    frame #16: 0x00007ff8144fa57d AppKit`-[NSWindow(NSConstraintBasedLayout) _layoutViewTree] + 148
    frame #17: 0x00007ff814570e8d AppKit`-[NSWindow(NSConstraintBasedLayout) layoutIfNeeded] + 251
    frame #18: 0x00007ff8145df992 AppKit`-[NSWindow _setUpFirstResponderBeforeBecomingVisible] + 63
    frame #19: 0x00007ff8145dee6f AppKit`-[NSWindow _doWindowWillBeVisibleAsSheet:] + 153
    frame #20: 0x00007ff8145dd495 AppKit`-[NSWindow _reallyDoOrderWindowAboveOrBelow:relativeTo:findKey:forCounter:force:isModal:] + 1240
    frame #21: 0x00007ff8145dcc64 AppKit`-[NSWindow _reallyDoOrderWindow:relativeTo:findKey:forCounter:force:isModal:] + 135
    frame #22: 0x00007ff8145dbc7c AppKit`-[NSWindow _doOrderWindow:relativeTo:findKey:forCounter:force:isModal:] + 289
    frame #23: 0x00007ff8145dbaf9 AppKit`-[NSWindow orderWindow:relativeTo:] + 152
    frame #24: 0x00007ff8145effa0 AppKit`-[NSPersistentUIRestorer orderRestoredWindows] + 2584
    frame #25: 0x00007ff8145e5e63 AppKit`-[NSPersistentUIRestorer finishedRestoringWindowsWithZOrder:completionHandler:] + 1348
    frame #26: 0x00007ff814fa84a6 AppKit`__102-[NSPersistentUIRestorer restoreStateFromRecords:usingDelegate:requireSecureCoding:completionHandler:]_block_invoke_3 + 171
    frame #27: 0x00007ff8145e58bb AppKit`__99-[NSApplication(NSPersistentUIRestorationSupport) _restoreWindowWithRestoration:completionHandler:]_block_invoke + 365
    frame #28: 0x00007ff814fa92d2 AppKit`___NSMainRunLoopPerformBlockInModes_block_invoke + 25
    frame #29: 0x00007ff811a6cd11 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    frame #30: 0x00007ff811a6cbbc CoreFoundation`__CFRunLoopDoBlocks + 445
    frame #31: 0x00007ff811a6b86a CoreFoundation`__CFRunLoopRun + 878
    frame #32: 0x00007ff811a6ae3c CoreFoundation`CFRunLoopRunSpecific + 562
    frame #33: 0x00007ff81a71a5e6 HIToolbox`RunCurrentEventLoopInMode + 292
    frame #34: 0x00007ff81a71a213 HIToolbox`ReceiveNextEventCommon + 283
    frame #35: 0x00007ff81a71a0e5 HIToolbox`_BlockUntilNextEventMatchingListInModeWithFilter + 70
    frame #36: 0x00007ff8144a4fad AppKit`_DPSNextEvent + 927
    frame #37: 0x00007ff8144a366a AppKit`-[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1394
    frame #38: 0x00007ff814495d19 AppKit`-[NSApplication run] + 586
    frame #39: 0x00000001001809c3 main`wxApp::CallOnInit(this=0x0000000101a08150) at utils.mm:394:9
    frame #40: 0x00000001002fa355 main`wxEntry(argc=0x000000010057c348, argv=0x0000000101a07d20) at init.cpp:488:25
    frame #41: 0x00000001002fa566 main`wxEntry(argc=0x00007ff7bfeff2e8, argv=0x00007ff7bfeff428) at init.cpp:516:12
    frame #42: 0x000000010000a103 main`main(argc=1, argv=0x00007ff7bfeff428) at main.cpp:23:1
    frame #43: 0x0000000100bd952e dyld`start + 462

Now for the weird stuff. I'm using my CMake template that downloads and compiles wxWidgets as an ExternalProject (https://github.com/lszl84/wx_cmake_template). I add basic code to display the font dialog:

MyFrame::MyFrame(const wxString &title, const wxPoint &pos, const wxSize &size)
    : wxFrame(NULL, wxID_ANY, title, pos, size)
{
    auto button = new wxButton(this, wxID_ANY, "Click me");
    button->Bind(wxEVT_BUTTON, [this](wxCommandEvent &event)
                 {
                     wxFontDialog dialog(this);

                     dialog.ShowModal();
                 });
}

I run the app, show the dialog and get the warning. Now the weird part is this: I delete the code in MyFrame constructor, run the app again. I get the correct empty window, BUT the font dialog is still shown!

If I change my CFBundleIdentifier, the font dialog does not show up, so maybe it's some OS caching issue? I don't know but it does make you question your sanity when you run an empty app and see a hanging Font Dialog there (see video).

https://user-images.githubusercontent.com/42072702/213329027-10f5c313-b52d-44f7-860e-7c3d0b8d5b5f.mov


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/23153/1396296227@github.com>

VZ

unread,
Jan 19, 2023, 6:21:32 AM1/19/23
to wx-...@googlegroups.com, Subscribed

Sorry, this seems to be really difficult to believe. I suspect you're not rebuilding your application properly or not using the right binary. The only other non-magical explanation I can see is that macOS automatically preserves the windows that were open the last time the application ran, but I don't think it can do it without any opt-in on the application part.

Also, the stack is pretty baffling: this is called before the font dialog is created (it's called even before OnInit() is called), so I don't understand what layout can it complain about.

So, again, please double check that you are running the code you think you run.

BTW, videos don't play for me (in Firefox).


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/23153/1396822578@github.com>

lszl84

unread,
Jan 19, 2023, 7:15:55 AM1/19/23
to wx-...@googlegroups.com, Subscribed

I agree, it is difficult to believe. As I said, I began to question my sanity.

But please do check out this video (this dropbox link should play in Firefox): https://www.dropbox.com/s/6c68uod1tgwaeiu/insane_font_dialog.mov?dl=0 and let me know what you think...


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/23153/1396887517@github.com>

lszl84

unread,
Jan 19, 2023, 7:37:11 AM1/19/23
to wx-...@googlegroups.com, Subscribed

Also, it turns out the trace from above post was when the font dialog automatically showed up. You can see calls to NSPersistentUIRestorer so the theory that Mac OS tries to automatically restore dialogs based on the bundle ID may be correct.

Now the correct trace for the layout problem when showing the font dialog is this:

Console is in 'commands' mode, prefix expressions with '?'.
Launching: /Users/lukasz/Documents/Development/wx_scratchpad/build/subprojects/Build/wx_scratchpad_core/main.app/Contents/MacOS/main

Launched process 13860
bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x00007ff814d11c52 AppKit`_NSDetectedLayoutRecursion
    frame #1: 0x00007ff8144fa57d AppKit`-[NSWindow(NSConstraintBasedLayout) _layoutViewTree] + 148
    frame #2: 0x00007ff8144f6f18 AppKit`-[NSWindow _oldPlaceWindow:fromServer:] + 648
    frame #3: 0x00007ff8144f53ce AppKit`-[NSWindow _setFrameCommon:display:fromServer:] + 1278
    frame #4: 0x00007ff8145bd3b5 AppKit`-[NSThemeFrame _growWindowReshapeContentAndToolbarView:withOldToolbarFrameSize:animate:] + 1896
    frame #5: 0x00007ff8145bcb12 AppKit`-[NSThemeFrame _reshapeContentAndToolbarView:withOldToolbarFrameSize:resizeWindow:animate:] + 612
    frame #6: 0x00007ff8145a935e AppKit`-[NSThemeFrame _toolbarFrameSizeChanged:oldSize:] + 73
    frame #7: 0x00007ff8145a92ba AppKit`-[NSWindow _toolbarFrameSizeChanged:oldSize:] + 93
    frame #8: 0x00007ff81459d762 AppKit`-[NSToolbarView _layoutDirtyItemViewersAndTileToolbar] + 473
    frame #9: 0x00007ff8145c3971 AppKit`-[NSToolbarView layout] + 63
    frame #10: 0x00007ff8144fba94 AppKit`_NSViewLayout + 564
    frame #11: 0x00007ff8144fb573 AppKit`-[NSView _layoutSubtreeWithOldSize:] + 361
    frame #12: 0x00007ff8144fb6c1 AppKit`-[NSView _layoutSubtreeWithOldSize:] + 695
    frame #13: 0x00007ff8144fb6c1 AppKit`-[NSView _layoutSubtreeWithOldSize:] + 695
    frame #14: 0x00007ff8144fb6c1 AppKit`-[NSView _layoutSubtreeWithOldSize:] + 695
    frame #15: 0x00007ff8144faa85 AppKit`-[NSView _layoutSubtreeIfNeededAndAllowTemporaryEngine:] + 1041
    frame #16: 0x00007ff8144fa57d AppKit`-[NSWindow(NSConstraintBasedLayout) _layoutViewTree] + 148
    frame #17: 0x00007ff814570e8d AppKit`-[NSWindow(NSConstraintBasedLayout) layoutIfNeeded] + 251
    frame #18: 0x00007ff8145df992 AppKit`-[NSWindow _setUpFirstResponderBeforeBecomingVisible] + 63
    frame #19: 0x00007ff8145dee6f AppKit`-[NSWindow _doWindowWillBeVisibleAsSheet:] + 153
    frame #20: 0x00007ff8145dd495 AppKit`-[NSWindow _reallyDoOrderWindowAboveOrBelow:relativeTo:findKey:forCounter:force:isModal:] + 1240
    frame #21: 0x00007ff8145dcc64 AppKit`-[NSWindow _reallyDoOrderWindow:relativeTo:findKey:forCounter:force:isModal:] + 135
    frame #22: 0x00007ff814d3405f AppKit`__71-[NSWindow _doOrderWindow:relativeTo:findKey:forCounter:force:isModal:]_block_invoke.2772 + 79
    frame #23: 0x00007ff8144f3c37 AppKit`NSPerformVisuallyAtomicChange + 132
    frame #24: 0x00007ff8145dbeec AppKit`-[NSWindow _doOrderWindow:relativeTo:findKey:forCounter:force:isModal:] + 913
    frame #25: 0x00007ff8147559f4 AppKit`-[NSApplication _orderFrontModalWindow:relativeToWindow:] + 653
    frame #26: 0x00007ff814755543 AppKit`-[NSApplication _commonBeginModalSessionForWindow:relativeToWindow:modalDelegate:didEndSelector:contextInfo:] + 1359
    frame #27: 0x00007ff814754fed AppKit`-[NSApplication beginModalSessionForWindow:] + 37
    frame #28: 0x00007ff814754f52 AppKit`__35-[NSApplication runModalForWindow:]_block_invoke_2 + 39
    frame #29: 0x00007ff814754f18 AppKit`__35-[NSApplication runModalForWindow:]_block_invoke + 78
    frame #30: 0x00007ff8147547be AppKit`_NSTryRunModal + 100
    frame #31: 0x00007ff8147546a5 AppKit`-[NSApplication runModalForWindow:] + 128
    frame #32: 0x000000010024e2ad main`RunMixedFontDialog(dialog=0x00007ff7bfefd710) at fontdlgosx.mm:265:5
    frame #33: 0x00000001002527b5 main`wxFontDialog::ShowModal(this=0x00007ff7bfefd710) at fontdlg.cpp:87:18
    frame #34: 0x000000010000c989 main`MyFrame::MyFrame(this=(0x000000010680a000), event=0x00007ff7bfefde60)::$_0::operator()(wxCommandEvent&) const at main.cpp:34:28
    frame #35: 0x000000010000c845 main`wxEventFunctorFunctor<wxEventTypeTag<wxCommandEvent>, MyFrame::MyFrame(wxString const&, wxPoint const&, wxSize const&)::$_0>::operator(this=0x0000000103831010, (null)=0x0000000103831040, event=0x00007ff7bfefde60)(wxEvtHandler*, wxEvent&) at event.h:547:9
    frame #36: 0x000000010031662b main`wxAppConsoleBase::CallEventHandler(this=0x000000010171cea0, handler=0x0000000103831040, functor=0x0000000103831010, event=0x00007ff7bfefde60) const at appbase.cpp:641:9
    frame #37: 0x0000000100432470 main`wxEvtHandler::ProcessEventIfMatchesId(entry=0x0000000103831370, handler=0x0000000103831040, event=0x00007ff7bfefde60) at event.cpp:1393:23
    frame #38: 0x00000001004345ad main`wxEvtHandler::SearchDynamicEventTable(this=0x0000000103831040, event=0x00007ff7bfefde60) at event.cpp:1853:18
    frame #39: 0x00000001004343aa main`wxEvtHandler::TryHereOnly(this=0x0000000103831040, event=0x00007ff7bfefde60) at event.cpp:1576:29
    frame #40: 0x000000010043416f main`wxEvtHandler::TryBeforeAndHere(this=0x0000000103831040, event=0x00007ff7bfefde60) at event.h:3988:36
    frame #41: 0x00000001004341a1 main`wxEvtHandler::ProcessEventLocally(this=0x0000000103831040, event=0x00007ff7bfefde60) at event.cpp:1513:12
    frame #42: 0x000000010043405e main`wxEvtHandler::ProcessEvent(this=0x0000000103831040, event=0x00007ff7bfefde60) at event.cpp:1486:10
    frame #43: 0x0000000100434771 main`wxEvtHandler::SafelyProcessEvent(this=0x0000000103831040, event=0x00007ff7bfefde60) at event.cpp:1602:16
    frame #44: 0x0000000100163645 main`wxWindowBase::HandleWindowEvent(this=0x0000000103831040, event=0x00007ff7bfefde60) const at wincmn.cpp:1539:31
    frame #45: 0x000000010025900d main`wxControl::ProcessCommand(this=0x0000000103831040, event=0x00007ff7bfefde60) at control.cpp:70:12
    frame #46: 0x000000010021f919 main`wxButton::OSXHandleClicked(this=0x0000000103831040, (null)=0) at button_osx.cpp:135:5
    frame #47: 0x00000001002fecfd main`wxWidgetCocoaImpl::controlAction(this=0x0000000103835a20, (null)=0x0000000103831e40, (null)=0x00000001005a698a, (null)=0x0000000103831e40) at window.mm:2422:17
    frame #48: 0x00000001002fa45a main`wxOSX_controlAction(self=0x0000000103831e40, _cmd="controlAction:", sender=0x0000000103831e40) at window.mm:1261:11
    frame #49: 0x00007ff8146a90ce AppKit`-[NSApplication(NSResponder) sendAction:to:from:] + 288
    frame #50: 0x00007ff8146a8f74 AppKit`-[NSControl sendAction:to:] + 86
    frame #51: 0x00007ff8146a8ea6 AppKit`__26-[NSCell _sendActionFrom:]_block_invoke + 131
    frame #52: 0x00007ff8146a8daf AppKit`-[NSCell _sendActionFrom:] + 171
    frame #53: 0x00007ff8146a8cf7 AppKit`-[NSButtonCell _sendActionFrom:] + 96
    frame #54: 0x00007ff8146a5b6f AppKit`NSControlTrackMouse + 1813
    frame #55: 0x00007ff8146a5436 AppKit`-[NSCell trackMouse:inRect:ofView:untilMouseUp:] + 121
    frame #56: 0x00007ff8146a5306 AppKit`-[NSButtonCell trackMouse:inRect:ofView:untilMouseUp:] + 679
    frame #57: 0x00007ff8146a46d6 AppKit`-[NSControl mouseDown:] + 678
    frame #58: 0x00000001002fb100 main`wxWidgetCocoaImpl::mouseEvent(this=0x0000000103835a20, event=0x00000001015492f0, slf=0x0000000103831e40, _cmd=0x00007ff82be3dcf9) at window.mm:1486:13
    frame #59: 0x00000001002f9708 main`wxOSX_mouseEvent(self=0x0000000103831e40, _cmd="mouseDown:", event=0x00000001015492f0) at window.mm:1060:15
    frame #60: 0x00007ff8146a2bc1 AppKit`-[NSWindow(NSEventRouting) _handleMouseDownEvent:isDelayedEvent:] + 4859
    frame #61: 0x00007ff814616d7e AppKit`-[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 2582
    frame #62: 0x00007ff81461614e AppKit`-[NSWindow(NSEventRouting) sendEvent:] + 352
    frame #63: 0x00000001002da332 main`-[wxNSWindow sendEvent:](self=0x0000000101520440, _cmd="sendEvent:", event=0x00000001015492f0) at nonownedwnd.mm:177:9
    frame #64: 0x00007ff814614524 AppKit`-[NSApplication(NSEvent) sendEvent:] + 352
    frame #65: 0x00000001001db0a1 main`-[wxNSApplication sendEvent:](self=0x0000000101608630, _cmd="sendEvent:", anEvent=0x00000001015492f0) at utils.mm:359:9
    frame #66: 0x00007ff8148cd18b AppKit`-[NSApplication _handleEvent:] + 65
    frame #67: 0x00007ff814495d3e AppKit`-[NSApplication run] + 623
    frame #68: 0x00000001002c8316 main`wxGUIEventLoop::OSXDoRun(this=0x0000000103d11e70) at evtloop.mm:301:13
    frame #69: 0x00000001004440a4 main`wxCFEventLoop::DoRun(this=0x0000000103d11e70) at evtloop_cf.cpp:326:13
    frame #70: 0x0000000100360151 main`wxEventLoopBase::Run(this=0x0000000103d11e70) at evtloopcmn.cpp:87:12
    frame #71: 0x00000001003154ca main`wxAppConsoleBase::MainLoop(this=0x000000010171cea0) at appbase.cpp:347:37
    frame #72: 0x0000000100315009 main`wxAppConsoleBase::OnRun(this=0x000000010171cea0) at appbase.cpp:269:12
    frame #73: 0x00000001000168e8 main`wxAppBase::OnRun(this=0x000000010171cea0) at appcmn.cpp:334:26
    frame #74: 0x0000000100255476 main`wxApp::OnRun(this=0x000000010171cea0) at app.cpp:356:23
    frame #75: 0x00000001003a267d main`wxEntry(argc=0x000000010065f7cc, argv=0x000000010171ca70) at init.cpp:490:26
    frame #76: 0x00000001003a2826 main`wxEntry(argc=0x00007ff7bfeff2e8, argv=0x00007ff7bfeff428) at init.cpp:500:12
    frame #77: 0x0000000100009bd3 main`main(argc=1, argv=0x00007ff7bfeff428) at main.cpp:25:1
    frame #78: 0x0000000100f9152e dyld`start + 462

You can see the last wx call is RunMixedFontDialog which seems to make sense.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <wxWidgets/wxWidgets/issues/23153/1396912370@github.com>

Reply all
Reply to author
Forward
0 new messages