Skip to content
This repository was archived by the owner on Aug 31, 2021. It is now read-only.

Commit 590458a

Browse files
Merge pull request #7446 from livecodeian/bugfix-22935
[[ Bug 22935 ]] Fix engine instability after opening & closing modal stack
2 parents af5e912 + 581a002 commit 590458a

4 files changed

Lines changed: 60 additions & 17 deletions

File tree

docs/notes/bugfix-22935.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# Fix engine instability after opening & closing a modal stack

engine/src/mac-core.mm

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -667,8 +667,9 @@ void MCPlatformSetSystemProperty(MCPlatformSystemProperty p_property, MCPlatform
667667
bool is_done;
668668
};
669669

670-
static MCModalSession *s_modal_sessions = nil;
671-
static uindex_t s_modal_session_count = 0;
670+
static MCAutoArray<MCModalSession> s_modal_sessions;
671+
static MCAutoArray<MCModalSession> s_modal_sessions_pending_cleanup;
672+
static uindex_t s_modal_session_run_depth = 0;
672673

673674
struct MCCallback
674675
{
@@ -786,7 +787,7 @@ bool MCPlatformWaitForEvent(double p_duration, bool p_blocking)
786787
s_in_blocking_wait = true;
787788

788789
bool t_modal;
789-
t_modal = s_modal_session_count > 0;
790+
t_modal = s_modal_sessions.Size() > 0;
790791

791792
NSAutoreleasePool *t_pool;
792793
t_pool = [[NSAutoreleasePool alloc] init];
@@ -805,8 +806,17 @@ bool MCPlatformWaitForEvent(double p_duration, bool p_blocking)
805806
// Run the modal session, if it has been created yet (it might not if this
806807
// wait was triggered by reacting to an event caused as part of creating
807808
// the modal session, e.g. when losing window focus).
808-
if (s_modal_sessions[s_modal_session_count - 1].session != nil)
809-
[NSApp runModalSession: s_modal_sessions[s_modal_session_count - 1] . session];
809+
// Check the modal run depth to prevent re-entering a modal session that
810+
// is already being run.
811+
if (s_modal_session_run_depth < s_modal_sessions.Size() && s_modal_sessions[s_modal_session_run_depth].session != nil)
812+
{
813+
s_modal_session_run_depth++;
814+
[NSApp runModalSession: s_modal_sessions[s_modal_session_run_depth - 1].session];
815+
s_modal_session_run_depth--;
816+
817+
// clean up modal sessions
818+
MCMacPlatformCleanupModalSessions();
819+
}
810820

811821
t_event = nil;
812822
}
@@ -842,38 +852,59 @@ void MCMacPlatformBeginModalSession(MCMacPlatformWindow *p_window)
842852
// current mouse window.
843853
MCMacPlatformSyncMouseBeforeDragging();
844854

845-
/* UNCHECKED */ MCMemoryResizeArray(s_modal_session_count + 1, s_modal_sessions, s_modal_session_count);
855+
MCModalSession t_session;
846856

847-
s_modal_sessions[s_modal_session_count - 1] . is_done = false;
848-
s_modal_sessions[s_modal_session_count - 1] . window = p_window;
857+
t_session.is_done = false;
858+
t_session.window = p_window;
849859
p_window -> Retain();
850860
// IM-2015-01-30: [[ Bug 14140 ]] lock the window frame to prevent it from being centered on the screen.
851861
p_window->SetFrameLocked(true);
852-
s_modal_sessions[s_modal_session_count - 1] . session = [NSApp beginModalSessionForWindow: (NSWindow *)(p_window -> GetHandle())];
862+
863+
t_session.session = [NSApp beginModalSessionForWindow: (NSWindow *)(p_window -> GetHandle())];
864+
/* UNCHECKED */ s_modal_sessions.Push(t_session);
865+
853866
p_window->SetFrameLocked(false);
854867
}
855868

856869
void MCMacPlatformEndModalSession(MCMacPlatformWindow *p_window)
857870
{
858871
uindex_t t_index;
859-
for(t_index = 0; t_index < s_modal_session_count; t_index++)
872+
for(t_index = 0; t_index < s_modal_sessions.Size(); t_index++)
860873
if (s_modal_sessions[t_index] . window == p_window)
861874
break;
862875

863-
if (t_index == s_modal_session_count)
876+
if (t_index == s_modal_sessions.Size())
864877
return;
865878

866879
s_modal_sessions[t_index] . is_done = true;
867880

868-
for(uindex_t t_final_index = s_modal_session_count; t_final_index > 0; t_final_index--)
881+
/* Pop all modal sessions which are now complete. All those which are
882+
* get pushed onto a list to be destroyed later. */
883+
while (s_modal_sessions.Size() > 0)
869884
{
870-
if (!s_modal_sessions[t_final_index - 1] . is_done)
885+
if (!s_modal_sessions[s_modal_sessions.Size() - 1] . is_done)
871886
return;
872887

873-
[NSApp endModalSession: s_modal_sessions[t_final_index - 1] . session];
874-
[s_modal_sessions[t_final_index - 1] . window -> GetHandle() orderOut: nil];
875-
s_modal_sessions[t_final_index - 1] . window -> Release();
876-
s_modal_session_count -= 1;
888+
MCModalSession t_session;
889+
/* UNCHECKED */ s_modal_sessions.Pop(t_session);
890+
/* UNCHECKED */ s_modal_sessions_pending_cleanup.Push(t_session);
891+
892+
[NSApp endModalSession: t_session.session];
893+
}
894+
}
895+
896+
/* Process all modal sessions which are pending destruction. This
897+
* ensures that windows don't get hidden and destroyed at the wrong
898+
* time (e.g. within a nested modal session!). */
899+
void MCMacPlatformCleanupModalSessions(void)
900+
{
901+
while (s_modal_sessions_pending_cleanup.Size() > 0)
902+
{
903+
MCModalSession t_session;
904+
/* UNCHECKED */ s_modal_sessions_pending_cleanup.Pop(t_session);
905+
906+
[t_session.window->GetHandle() orderOut: nil];
907+
t_session.window->Release();
877908
}
878909
}
879910

engine/src/mac-internal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -582,6 +582,7 @@ void MCMacPlatformScheduleCallback(void (*)(void*), void *);
582582

583583
void MCMacPlatformBeginModalSession(MCMacPlatformWindow *window);
584584
void MCMacPlatformEndModalSession(MCMacPlatformWindow *window);
585+
void MCMacPlatformCleanupModalSessions(void);
585586

586587
void MCMacPlatformHandleMouseCursorChange(MCPlatformWindowRef window);
587588
void MCMacPlatformHandleMousePress(uint32_t p_button, bool p_is_down);

libfoundation/include/foundation-auto.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1094,6 +1094,16 @@ template<typename T> class MCAutoArray
10941094
m_ptr[m_size - 1] = p_value;
10951095
return true;
10961096
}
1097+
1098+
bool Pop(T &r_value)
1099+
{
1100+
if (m_size == 0)
1101+
return false;
1102+
1103+
r_value = m_ptr[m_size - 1];
1104+
Shrink(m_size - 1);
1105+
return true;
1106+
}
10971107

10981108
//////////
10991109

0 commit comments

Comments
 (0)