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

Commit 95edb2f

Browse files
committed
[[ Bug 22935 ]] Defer closure of modal window until after modal session ends
This patch fixes an issue where closing a modal window would immediately trigger a window event resulting in 'resumeStack' being sent to the window behind. If a script called 'wait' while handling that message then it would lead to an attempt to run the modal session that had just been ended, causing an error.
1 parent c1c5213 commit 95edb2f

File tree

3 files changed

+51
-16
lines changed

3 files changed

+51
-16
lines changed

engine/src/mac-core.mm

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -667,8 +667,8 @@ 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;
672672
static uindex_t s_modal_session_run_depth = 0;
673673

674674
struct MCCallback
@@ -787,7 +787,7 @@ bool MCPlatformWaitForEvent(double p_duration, bool p_blocking)
787787
s_in_blocking_wait = true;
788788

789789
bool t_modal;
790-
t_modal = s_modal_session_count > 0;
790+
t_modal = s_modal_sessions.Size() > 0;
791791

792792
NSAutoreleasePool *t_pool;
793793
t_pool = [[NSAutoreleasePool alloc] init];
@@ -802,11 +802,14 @@ bool MCPlatformWaitForEvent(double p_duration, bool p_blocking)
802802
// the modal session, e.g. when losing window focus).
803803
// Check the modal run depth to prevent re-entering a modal session that
804804
// is already being run.
805-
if (s_modal_session_run_depth < s_modal_session_count && s_modal_sessions[s_modal_session_run_depth].session != nil)
805+
if (s_modal_session_run_depth < s_modal_sessions.Size() && s_modal_sessions[s_modal_session_run_depth].session != nil)
806806
{
807807
s_modal_session_run_depth++;
808808
[NSApp runModalSession: s_modal_sessions[s_modal_session_run_depth - 1].session];
809809
s_modal_session_run_depth--;
810+
811+
// clean up modal sessions
812+
MCMacPlatformCleanupModalSessions();
810813
}
811814

812815
t_event = nil;
@@ -873,38 +876,59 @@ void MCMacPlatformBeginModalSession(MCMacPlatformWindow *p_window)
873876
// current mouse window.
874877
MCMacPlatformSyncMouseBeforeDragging();
875878

876-
/* UNCHECKED */ MCMemoryResizeArray(s_modal_session_count + 1, s_modal_sessions, s_modal_session_count);
879+
MCModalSession t_session;
877880

878-
s_modal_sessions[s_modal_session_count - 1] . is_done = false;
879-
s_modal_sessions[s_modal_session_count - 1] . window = p_window;
881+
t_session.is_done = false;
882+
t_session.window = p_window;
880883
p_window -> Retain();
881884
// IM-2015-01-30: [[ Bug 14140 ]] lock the window frame to prevent it from being centered on the screen.
882885
p_window->SetFrameLocked(true);
883-
s_modal_sessions[s_modal_session_count - 1] . session = [NSApp beginModalSessionForWindow: (NSWindow *)(p_window -> GetHandle())];
886+
887+
t_session.session = [NSApp beginModalSessionForWindow: (NSWindow *)(p_window -> GetHandle())];
888+
/* UNCHECKED */ s_modal_sessions.Push(t_session);
889+
884890
p_window->SetFrameLocked(false);
885891
}
886892

887893
void MCMacPlatformEndModalSession(MCMacPlatformWindow *p_window)
888894
{
889895
uindex_t t_index;
890-
for(t_index = 0; t_index < s_modal_session_count; t_index++)
896+
for(t_index = 0; t_index < s_modal_sessions.Size(); t_index++)
891897
if (s_modal_sessions[t_index] . window == p_window)
892898
break;
893899

894-
if (t_index == s_modal_session_count)
900+
if (t_index == s_modal_sessions.Size())
895901
return;
896902

897903
s_modal_sessions[t_index] . is_done = true;
898904

899-
for(uindex_t t_final_index = s_modal_session_count; t_final_index > 0; t_final_index--)
905+
/* Pop all modal sessions which are now complete. All those which are
906+
* get pushed onto a list to be destroyed later. */
907+
while (s_modal_sessions.Size() > 0)
900908
{
901-
if (!s_modal_sessions[t_final_index - 1] . is_done)
909+
if (!s_modal_sessions[s_modal_sessions.Size() - 1] . is_done)
902910
return;
903911

904-
[NSApp endModalSession: s_modal_sessions[t_final_index - 1] . session];
905-
[s_modal_sessions[t_final_index - 1] . window -> GetHandle() orderOut: nil];
906-
s_modal_sessions[t_final_index - 1] . window -> Release();
907-
s_modal_session_count -= 1;
912+
MCModalSession t_session;
913+
/* UNCHECKED */ s_modal_sessions.Pop(t_session);
914+
/* UNCHECKED */ s_modal_sessions_pending_cleanup.Push(t_session);
915+
916+
[NSApp endModalSession: t_session.session];
917+
}
918+
}
919+
920+
/* Process all modal sessions which are pending destruction. This
921+
* ensures that windows don't get hidden and destroyed at the wrong
922+
* time (e.g. within a nested modal session!). */
923+
void MCMacPlatformCleanupModalSessions(void)
924+
{
925+
while (s_modal_sessions_pending_cleanup.Size() > 0)
926+
{
927+
MCModalSession t_session;
928+
/* UNCHECKED */ s_modal_sessions_pending_cleanup.Pop(t_session);
929+
930+
[t_session.window->GetHandle() orderOut: nil];
931+
t_session.window->Release();
908932
}
909933
}
910934

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)