Skip to content

Commit ef17b7b

Browse files
committed
Replace modal windows with floating child windows
Remove runModalForWindow: from all utility controllers. Each window now uses setLevel:NSFloatingWindowLevel while open and reverts to NSNormalWindowLevel on close, so it floats above the main emulator window without blocking input. The Joystick configuration dialog is a sub-dialog of the (already floating) Preferences window: it uses addChildWindow:ordered:NSWindowAbove so the parent cannot rise above its child by activation alone. Add an Edit menu to MainMenu.xib so Cmd+C/V work in the debugger entry field. Fix Debugger.xib hidesOnDeactivate and block the emulation thread on a semaphore while the debugger is active. debugger_run() in handleWillClose: only fires when debugger_active is still 1 (user-initiated close); on Continue/Step the calling action has already set debugger_mode via deactivate_debugger() and a second debugger_run() would clobber a HALTED set by debugger_step(). Pin the emulation timer to the dedicated emulator thread via performSelector:onThread: in pause/unpause. Without this the timer ended up on whichever thread happened to call unpause (usually the main thread, from deactivate_debugger), and the next debugger break re-entered ui_debugger_activate on the main thread and deadlocked in dispatch_semaphore_wait.
1 parent fc74dec commit ef17b7b

14 files changed

Lines changed: 186 additions & 44 deletions

fusepb/controllers/DebuggerController.m

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ - (void)mainThreadDebuggerDisassemble:(NSNumber *)address;
5858
/* Is the debugger window active (as opposed to the debugger itself)? */
5959
static int debugger_active;
6060

61+
/* Set inside handleWillClose: while it transitively re-enters
62+
deactivate_debugger() via debugger_run(); keeps that nested call from
63+
re-issuing [window close] on a window that is already closing. */
64+
static int debugger_closing;
65+
66+
/* Semaphore that blocks the emulation thread inside ui_debugger_activate()
67+
until the user dismisses the debugger (Continue / close). */
68+
static dispatch_semaphore_t debugger_semaphore;
69+
6170
@implementation DebuggerController
6271

6372
static DebuggerController *singleton = nil;
@@ -102,6 +111,7 @@ - (id)init
102111
[super init];
103112
self = [super initWithWindowNibName:@"Debugger"];
104113
singleton = self;
114+
debugger_semaphore = dispatch_semaphore_create( 0 );
105115

106116
[self performSelectorOnMainThread:@selector(habdleCloseNotification) withObject:nil waitUntilDone:YES];
107117
[self performSelectorOnMainThread:@selector(setWindowFrameAutosaveName:) withObject:@"DebuggerWindow" waitUntilDone:YES];
@@ -131,6 +141,7 @@ - (void)dealloc
131141

132142
- (void)handleWillClose:(NSNotification *)note
133143
{
144+
debugger_closing = 1;
134145
[breakpointsContents release];
135146
breakpointsContents = nil;
136147
[dissasemblyContents release];
@@ -142,7 +153,12 @@ - (void)handleWillClose:(NSNotification *)note
142153
[memoryMapContents release];
143154
memoryMapContents = nil;
144155

145-
debugger_run();
156+
/* Only resume execution when the user dismissed the window directly.
157+
If we arrived via deactivate_debugger(), debugger_active is already
158+
0 and the caller has set debugger_mode; calling debugger_run() now
159+
would overwrite a HALTED set by debugger_step(). */
160+
if( debugger_active ) debugger_run();
161+
debugger_closing = 0;
146162
}
147163

148164
- (void)eventsDoubleAction:(id)sender
@@ -191,13 +207,16 @@ - (void)debugger_activate:(id)sender
191207
{
192208
[[DisplayOpenGLView instance] pause];
193209

210+
[(NSPanel *)[singleton window] setBecomesKeyOnlyIfNeeded:NO];
194211
[singleton showWindow:nil];
212+
[[singleton window] makeFirstResponder:entry];
213+
214+
[[singleton window] setLevel:NSFloatingWindowLevel];
195215

196216
[continueButton setEnabled:YES];
197217
[breakButton setEnabled:NO];
198218
if( !debugger_active ) activate_debugger();
199219

200-
[NSApp runModalForWindow:[self window]];
201220
}
202221

203222
- (void)debugger_deactivate:(int)interruptable
@@ -302,6 +321,13 @@ - (void)debugger_update_breakpoints
302321

303322
- (void)debugger_update:(id)sender
304323
{
324+
NSWindow *window = [singleton window];
325+
NSText *fieldEditor = [window fieldEditor:NO forObject:entry];
326+
NSResponder *currentFR = [window firstResponder];
327+
BOOL entryWasFirstResponder = ( fieldEditor != nil && currentFR == fieldEditor );
328+
NSString *savedText = entryWasFirstResponder ? [[fieldEditor string] copy] : nil;
329+
NSRange savedSelection = entryWasFirstResponder ? [fieldEditor selectedRange] : NSMakeRange( 0, 0 );
330+
305331
char buffer[40];
306332
NSString *format_16_bit, *format_8_bit;
307333
int capabilities;
@@ -519,6 +545,16 @@ - (void)debugger_update:(id)sender
519545
}
520546

521547
[memoryMap reloadData];
548+
549+
if( entryWasFirstResponder ) {
550+
[window makeFirstResponder:entry];
551+
NSText *restoredEditor = [window fieldEditor:NO forObject:entry];
552+
if( restoredEditor ) {
553+
[restoredEditor setString:savedText];
554+
[restoredEditor setSelectedRange:savedSelection];
555+
}
556+
}
557+
[savedText release];
522558
}
523559

524560
- (void)add_event:(event_t *)ptr
@@ -651,7 +687,11 @@ - (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(int)rowIndex
651687
int
652688
ui_debugger_activate( void )
653689
{
654-
[[Emulator instance] debuggerActivate];
690+
[[Emulator instance] performSelectorOnMainThread:@selector(debuggerActivate)
691+
withObject:nil
692+
waitUntilDone:YES];
693+
694+
dispatch_semaphore_wait( debugger_semaphore, DISPATCH_TIME_FOREVER );
655695

656696
return 0;
657697
}
@@ -721,10 +761,14 @@ - (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(int)rowIndex
721761

722762
static int
723763
deactivate_debugger( void )
724-
{
725-
[NSApp stopModal];
764+
{
726765
debugger_active = 0;
766+
[[singleton window] setLevel:NSNormalWindowLevel];
727767
[[DisplayOpenGLView instance] unpause];
768+
dispatch_semaphore_signal( debugger_semaphore );
769+
if( !debugger_closing && [[singleton window] isVisible] ) {
770+
[[singleton window] close];
771+
}
728772
return 0;
729773
}
730774

fusepb/controllers/FuseController.m

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1146,7 +1146,7 @@ - (IBAction)cocoa_break:(id)sender
11461146
if ( gdbserver_debugging_enabled ) {
11471147
return;
11481148
}
1149-
if ( paused ) {
1149+
if ( paused || fuse_emulation_paused ) {
11501150
debugger_mode = DEBUGGER_MODE_HALTED;
11511151
paused = 0;
11521152
[[DebuggerController singleton] debugger_activate:nil];

fusepb/controllers/JoystickConfigurationController.m

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,10 @@ - (IBAction)apply:(id)sender;
154154

155155
- (IBAction)cancel:(id)sender
156156
{
157-
[NSApp stopModal];
157+
NSWindow *parent = [[self window] parentWindow];
158+
if( parent ) {
159+
[parent removeChildWindow:[self window]];
160+
}
158161
[[self window] close];
159162
}
160163

@@ -165,8 +168,23 @@ - (void)showWindow:(id)sender
165168

166169
joyNum = [sender tag];
167170

171+
/* Capture the parent before [super showWindow:] takes key status away. */
172+
NSWindow *parent = [NSApp keyWindow];
173+
168174
[super showWindow:sender];
169175

176+
/* Pin to the parent (Preferences) so this sub-dialog cannot be hidden
177+
behind it when the parent is at NSFloatingWindowLevel. */
178+
NSWindow *currentParent = [[self window] parentWindow];
179+
if( parent != [self window] && currentParent != parent ) {
180+
if( currentParent ) {
181+
[currentParent removeChildWindow:[self window]];
182+
}
183+
if( parent ) {
184+
[parent addChildWindow:[self window] ordered:NSWindowAbove];
185+
}
186+
}
187+
170188
[joyXAxis removeAllItems];
171189
[joyYAxis removeAllItems];
172190

@@ -375,8 +393,6 @@ - (void)showWindow:(id)sender
375393
default:
376394
assert(0);
377395
}
378-
379-
[NSApp runModalForWindow:[self window]];
380396
}
381397

382398
@end

fusepb/controllers/LoadBinaryController.m

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,25 +89,30 @@ - (IBAction)apply:(id)sender
8989

9090
- (IBAction)cancel:(id)sender
9191
{
92-
[NSApp stopModal];
92+
[[self window] setLevel:NSNormalWindowLevel];
9393
[[self window] close];
9494

9595
[[DisplayOpenGLView instance] unpause];
9696
}
9797

9898
- (void)showWindow:(id)sender
9999
{
100+
if( [[self window] isVisible] ) {
101+
[[self window] makeKeyAndOrderFront:sender];
102+
return;
103+
}
104+
100105
[[DisplayOpenGLView instance] pause];
101106

102107
[super showWindow:sender];
103108

109+
[[self window] setLevel:NSFloatingWindowLevel];
110+
104111
[file setStringValue:@""];
105112
[start setStringValue:@""];
106113
[length setStringValue:@""];
107114

108115
[apply setEnabled:NO];
109-
110-
[NSApp runModalForWindow:[self window]];
111116
}
112117

113118
- (IBAction)chooseFile:(id)sender

fusepb/controllers/MemoryBrowserController.m

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,15 +59,18 @@ - (void)showWindow:(id)sender
5959
NSString *address;
6060
NSMutableString *hex, *data;
6161

62+
if( [[self window] isVisible] ) {
63+
[[self window] makeKeyAndOrderFront:sender];
64+
return;
65+
}
66+
6267
notificationObserver =
6368
[nc addObserverForName:@"NSWindowWillCloseNotification"
6469
object:[self window]
6570
queue:mainQueue
6671
usingBlock:^(NSNotification *note) {
6772
[nc removeObserver:notificationObserver];
6873

69-
[NSApp stopModal];
70-
7174
[tableContents removeAllObjects];
7275

7376
[tableContents release];
@@ -76,6 +79,8 @@ - (void)showWindow:(id)sender
7679

7780
[memoryBrowser reloadData];
7881

82+
[[self window] setLevel:NSNormalWindowLevel];
83+
7984
[[DisplayOpenGLView instance] unpause];
8085
}];
8186

@@ -105,9 +110,9 @@ - (void)showWindow:(id)sender
105110

106111
[super showWindow:sender];
107112

113+
[[self window] setLevel:NSFloatingWindowLevel];
114+
108115
[memoryBrowser reloadData];
109-
110-
[NSApp runModalForWindow:[self window]];
111116
}
112117

113118
- (int)numberOfRowsInTableView:(NSTableView *)table

fusepb/controllers/PokeFinderController.m

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -94,22 +94,27 @@ - (void) dealloc
9494

9595
- (void)handleWillClose:(NSNotification *)note
9696
{
97-
[NSApp stopModal];
98-
9997
[tableContents removeAllObjects];
10098
[tableContents release];
10199

102100
tableContents = nil;
103101

104102
[matchList reloadData];
105103

104+
[[self window] setLevel:NSNormalWindowLevel];
105+
106106
[[DisplayOpenGLView instance] unpause];
107107
}
108108

109109
- (void)showWindow:(id)sender
110110
{
111111
NSNotificationCenter *nc;
112112

113+
if( [[self window] isVisible] ) {
114+
[[self window] makeKeyAndOrderFront:sender];
115+
return;
116+
}
117+
113118
nc = [NSNotificationCenter defaultCenter];
114119
[nc addObserver:self
115120
selector:@selector(handleWillClose:)
@@ -120,9 +125,9 @@ - (void)showWindow:(id)sender
120125

121126
[super showWindow:sender];
122127

128+
[[self window] setLevel:NSFloatingWindowLevel];
129+
123130
[self update_pokefinder];
124-
125-
[NSApp runModalForWindow:[self window]];
126131
}
127132

128133
- (IBAction)search:(id)sender

fusepb/controllers/PokeMemoryController.m

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ - (id)init
5151
object:[self window]
5252
queue:mainQueue
5353
usingBlock:^(NSNotification *note) {
54-
[NSApp stopModal];
55-
5654
for( NSMutableDictionary* trainerModel in [trainersController content] ) {
5755
trainer_t* trainer =
5856
(trainer_t*)[[trainerModel valueForKey:@"trainerVal"] pointerValue];
@@ -67,6 +65,8 @@ - (id)init
6765

6866
[trainers reloadData];
6967

68+
[[self window] setLevel:NSNormalWindowLevel];
69+
7070
[[DisplayOpenGLView instance] unpause];
7171
}];
7272

@@ -88,6 +88,11 @@ - (void)dealloc
8888

8989
- (void)showWindow:(id)sender
9090
{
91+
if( [[self window] isVisible] ) {
92+
[[self window] makeKeyAndOrderFront:sender];
93+
return;
94+
}
95+
9196
[[DisplayOpenGLView instance] pause];
9297

9398
if( trainer_list ) {
@@ -96,9 +101,9 @@ - (void)showWindow:(id)sender
96101

97102
[super showWindow:sender];
98103

104+
[[self window] setLevel:NSFloatingWindowLevel];
105+
99106
[trainers reloadData];
100-
101-
[NSApp runModalForWindow:[self window]];
102107
}
103108

104109
- (void)addObjectToPokeList:(NSDictionary*)poke

fusepb/controllers/PreferencesController.m

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ - (void)awakeFromNib
142142

143143
- (void)showWindow:(id)sender
144144
{
145+
if( [[self window] isVisible] ) {
146+
[[self window] makeKeyAndOrderFront:sender];
147+
return;
148+
}
149+
145150
[[DisplayOpenGLView instance] pause];
146151

147152
[machineRomsController setContent:nil];
@@ -157,6 +162,8 @@ - (void)showWindow:(id)sender
157162

158163
[super showWindow:sender];
159164

165+
[[self window] setLevel:NSFloatingWindowLevel];
166+
160167
[self setMassStorageType];
161168
[self setExternalSoundType];
162169

@@ -166,12 +173,6 @@ - (void)showWindow:(id)sender
166173
selector:@selector(handleWillClose:)
167174
name:@"NSWindowWillCloseNotification"
168175
object:[self window]];
169-
170-
[NSApp runModalForWindow:[self window]];
171-
172-
[machineRomsController setContent:nil];
173-
[machineRoms release];
174-
machineRoms = nil;
175176
}
176177

177178
- (void)fixPhantomTypistMode
@@ -200,8 +201,6 @@ - (void)fixPhantomTypistMode
200201

201202
- (void)handleWillClose:(NSNotification *)note
202203
{
203-
[NSApp stopModal];
204-
205204
[[NSNotificationCenter defaultCenter] removeObserver:self];
206205

207206
int old_bilinear = settings_current.bilinear_filter;
@@ -235,6 +234,12 @@ - (void)handleWillClose:(NSNotification *)note
235234
[Emulator endROMScopedAccess:romURLs];
236235
}
237236

237+
[machineRomsController setContent:nil];
238+
[machineRoms release];
239+
machineRoms = nil;
240+
241+
[[self window] setLevel:NSNormalWindowLevel];
242+
238243
[[DisplayOpenGLView instance] unpause];
239244
}
240245

0 commit comments

Comments
 (0)