ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/BasiliskII/src/MacOSX/Controller.mm
Revision: 1.15
Committed: 2008-01-01T09:40:32Z (16 years, 11 months ago) by gbeauche
Branch: MAIN
CVS Tags: HEAD
Changes since 1.14: +2 -2 lines
Log Message:
Happy New Year!

File Contents

# Content
1 /*
2 * Controller.m - Simple application window management.
3 *
4 * $Id: Controller.mm,v 1.14 2006/03/10 08:16:56 nigel Exp $
5 *
6 * Basilisk II (C) 1997-2008 Christian Bauer
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #import "Controller.h"
24 #import "Emulator.h"
25
26 #import "sysdeps.h" // Types used in Basilisk C++ code
27
28 #import <main.h>
29 #import <prefs.h>
30
31 #define DEBUG 0
32 #import <debug.h>
33
34 #import "misc_macosx.h"
35 #import "video_macosx.h"
36
37 @implementation Controller
38
39 //
40 // Standard NSApplication methods that we override
41 //
42
43 - (id) init
44 {
45 #ifdef ENABLE_MULTIPLE
46 emulators = [NSMutableArray new];
47 #endif
48 return [super init];
49 }
50
51 - (void) dealloc
52 {
53 #ifdef ENABLE_MULTIPLE
54 [emulators dealloc];
55 #endif
56 [super dealloc];
57 }
58
59 - (void) awakeFromNib
60 {
61 #ifdef ENABLE_MULTIPLE
62 [self NewEmulator: self]; // So the user gets something on screen
63 #endif
64 [[NSApplication sharedApplication]
65 setDelegate: self]; // Enable applicationShouldTerminate
66 }
67
68 - (void) sendEvent: (NSEvent *)event;
69 {
70 // We can either process the event ourselves,
71 // or pass it to our superclass for the other UI objects to process
72 bool passToSuper = false;
73
74 if ( [self isAnyEmulatorDisplayingSheets] ||
75 [[thePrefsEditor window] isVisible] || ! [self isAnyEmulatorRunning] )
76 passToSuper = true;
77
78 if ( [[theEmulator screen] isFullScreen] )
79 passToSuper = false;
80
81 if ( passToSuper )
82 [super sendEvent: event]; // NSApplication default
83 else
84 {
85 NSEventType type = [event type];
86
87 if ( type == NSKeyUp || type == NSKeyDown || type == NSFlagsChanged )
88 [self dispatchKeyEvent: event
89 type: type];
90 else
91 [self dispatchEvent: event
92 type: type];
93 }
94 }
95
96 // NSApplication methods which are invoked through delegation
97
98 - (BOOL) applicationShouldTerminateAfterLastWindowClosed: (NSApplication *)app
99 { return YES; }
100
101 - (NSApplicationTerminateReply) applicationShouldTerminate: (NSApplication *)app
102 {
103 short count;
104 char *stillRunningMessage;
105
106 if ( [thePrefsEditor hasEdited] )
107 if ( ChoiceAlert("Preferences have been edited",
108 "Save changes", "Quit") )
109 SavePrefs();
110
111 // if ( edited )
112 // {
113 // NSString *title = [NSString stringWithCString: getString(STR_WARNING_ALERT_TITLE)],
114 // *msg = @"Preferences have been edited",
115 // *def = @"Save changes",
116 // *alt = @"Quit Application",
117 // *other = @"Continue";
118 //
119 // switch ( NSRunAlertPanel(title, msg, def, alt, other, nil) )
120 // {
121 // case NSAlertDefault: savePrefs();
122 // case NSAlertAlternate: return NSTerminateNow;
123 // case NSAlertOther: return NSTerminateCancel;
124 // }
125 // }
126
127
128 if ( [[thePrefsEditor window] isVisible] )
129 [[thePrefsEditor window] performClose: self];
130
131
132 count = [self emulatorCreatedCount];
133
134 if ( count > 0 )
135 {
136 if ( count > 1 )
137 stillRunningMessage = "Emulators are still running\nExiting Basilisk may lose data";
138 else
139 stillRunningMessage = "Emulator is still running\nExiting Basilisk may lose data";
140 if ( ! ChoiceAlert(stillRunningMessage, "Exit", "Continue") )
141 return NSTerminateCancel; // NSTerminateLater?
142 }
143
144 return NSTerminateNow;
145 }
146
147
148 // Event dispatching, called by sendEvent
149
150 - (void) dispatchKeyEvent: (NSEvent *)event
151 type: (NSEventType)type
152 {
153 EmulatorView *view;
154
155 #ifdef ENABLE_MULTIPLE
156 // We need to work out what window's Emulator should receive these messages
157
158
159 int tmp;
160
161 for ( tmp = 0; tmp < [emulators count], ++tmp )
162 {
163 theEmulator = [emulators objectAtIndex: tmp];
164 view = [theEmulator screen];
165
166 if ( [ theEmulator isRunning ] &&
167 ( [[theEmulator window] isKeyWindow] || [view isFullScreen] ) )
168 break;
169 }
170
171 if ( tmp < [emulators count] ) // i.e. if we exited the for loop
172 #else
173 view = [theEmulator screen];
174
175 if ( [theEmulator isRunning] &&
176 ( [[theEmulator window] isKeyWindow] || [view isFullScreen] ) )
177 #endif
178 {
179 D(NSLog(@"Got a key event - %d\n", [event keyCode]));
180 switch ( type )
181 {
182 case NSKeyUp:
183 [view keyUp: event];
184 break;
185 case NSKeyDown:
186 D(NSLog(@"%s - NSKeyDown - %@", __PRETTY_FUNCTION__, event));
187 [view keyDown: event];
188 break;
189 case NSFlagsChanged:
190 [view flagsChanged: event];
191 break;
192 default:
193 NSLog(@"%s - Sent a non-key event (logic error)",
194 __PRETTY_FUNCTION__);
195 [super sendEvent: event];
196 }
197 }
198 else // No Basilisk window is key (maybe a panel or pane).
199 [super sendEvent: event]; // Call NSApplication default
200
201 }
202
203 - (void) dispatchEvent: (NSEvent *)event
204 type: (NSEventType)type
205 {
206 EmulatorView *view;
207 BOOL fullScreen;
208
209 #ifdef ENABLE_MULTIPLE
210 // We need to work out what window's Emulator should receive these messages
211
212
213 int tmp;
214
215 for ( tmp = 0; tmp < [emulators count], ++tmp )
216 {
217 theEmulator = [emulators objectAtIndex: tmp];
218 view = [theEmulator screen];
219 fullScreen = [view isFullScreen];
220
221 if ( [theEmulator isRunning] &&
222 ( fullScreen || [[theEmulator window] isMainWindow] ) )
223 break;
224 }
225
226 if ( tmp < [emulators count] ) // i.e. if we exited the for loop
227 #else
228 view = [theEmulator screen];
229 fullScreen = [view isFullScreen];
230
231 if ( [theEmulator isRunning] &&
232 ( fullScreen || [[theEmulator window] isMainWindow] ) )
233 #endif
234 {
235 if ( fullScreen || [view mouseInView: event] )
236 {
237 switch ( type )
238 {
239 case NSLeftMouseDown:
240 [view mouseDown: event];
241 break;
242 case NSLeftMouseUp:
243 [view mouseUp: event];
244 break;
245 case NSLeftMouseDragged:
246 case NSMouseMoved:
247 if ( fullScreen )
248 [view fullscreenMouseMove];
249 else
250 [view processMouseMove: event];
251 break;
252 default:
253 [super sendEvent: event]; // NSApplication default
254 }
255 return;
256 }
257 }
258
259 // Either the pointer is not in the Emulator's screen, no Basilisk window is running,
260 // or no Basilisk window is main (e.g. there might be a panel or pane up).
261 //
262 // We should just be calling NSApp's default sendEvent, but then for some reason
263 // mouseMoved events are still passed to our EmulatorView, so we filter them out.
264
265 if ( type != NSMouseMoved )
266 [super sendEvent: event];
267 }
268
269
270 // Methods to display documentation:
271
272 - (IBAction) HelpHowTo: (id)sender
273 {
274 NSString *path = [[NSBundle mainBundle] pathForResource: @"HowTo"
275 ofType: @"html"];
276
277 if ( ! path )
278 InfoSheet(@"Cannot find HowTo.html", [theEmulator window]);
279 else
280 if ( ! [[NSWorkspace sharedWorkspace] openFile: path] )
281 InfoSheet(@"Cannot open HowTo.html with default app", [theEmulator window]);
282 }
283
284 - (IBAction) HelpToDo: (id)sender
285 {
286 NSString *path = [[NSBundle mainBundle] pathForResource: @"ToDo"
287 ofType: @"html"];
288
289 if ( ! path )
290 InfoSheet(@"Cannot find ToDo.html", [theEmulator window]);
291 else
292 if ( ! [[NSWorkspace sharedWorkspace] openFile: path
293 withApplication: @"TextEdit"] )
294 InfoSheet(@"Cannot open ToDo.html with TextEdit", [theEmulator window]);
295 }
296
297 - (IBAction) HelpVersions: (id)sender
298 {
299 NSString *path = [[NSBundle mainBundle] pathForResource: @"Versions"
300 ofType: @"html"];
301
302 if ( ! path )
303 InfoSheet(@"Cannot find Versions.html", [theEmulator window]);
304 else
305 if ( ! [[NSWorkspace sharedWorkspace] openFile: path
306 withApplication: @"TextEdit"] )
307 InfoSheet(@"Cannot open Versions.html with TextEdit",
308 [theEmulator window]);
309 }
310
311
312 // Menu items which for managing more than one window
313
314 #ifdef ENABLE_MULTIPLE
315
316 - (IBAction) NewEmulator: (id)sender
317 {
318 NSString *title;
319
320 if ( ! [NSBundle loadNibNamed:@"Win512x342" owner:self] )
321 {
322 NSLog(@"%s - LoadNibNamed@Win512x342 failed", __PRETTY_FUNCTION__);
323 return;
324 }
325
326 if ( theEmulator == nil)
327 {
328 NSLog(@"%s - Newly created emulator's NIB stuff not fully linked?", __PRETTY_FUNCTION__);
329 return;
330 }
331
332 [emulators addObject: theEmulator];
333 title = [NSString localizedStringWithFormat:@"BasiliskII Emulator %d", [emulators count]];
334 [theEmulator -> win setTitle: title];
335 }
336
337 - (IBAction) PauseAll: (id)sender
338 {
339 [emulators makeObjectsPerformSelector:@selector(Suspend:)
340 withObject:self];
341 }
342
343 - (IBAction) RunAll: (id)sender
344 {
345 [emulators makeObjectsPerformSelector:@selector(Resume:)
346 withObject:self];
347 }
348
349 - (IBAction) TerminateAll: (id)sender
350 {
351 [emulators makeObjectsPerformSelector:@selector(Terminate:)
352 withObject:self];
353 }
354
355 #endif
356
357 - (BOOL) isAnyEmulatorDisplayingSheets
358 {
359 #ifdef ENABLE_MULTIPLE
360 int tmp;
361
362 for ( tmp = 0; tmp < [emulators count], ++tmp )
363 if ( [[[emulators objectAtIndex: tmp] window] attachedSheet] )
364 break;
365
366 if ( tmp < [emulators count] ) // i.e. if we exited the for loop
367 #else
368 if ( [[theEmulator window] attachedSheet] )
369 #endif
370 return TRUE;
371
372 return FALSE;
373 }
374
375 - (BOOL) isAnyEmulatorRunning
376 {
377 #ifdef ENABLE_MULTIPLE
378 int tmp;
379
380 for ( tmp = 0; tmp < [emulators count], ++tmp )
381 if ( [[emulators objectAtIndex: tmp] isRunning] )
382 break;
383
384 if ( tmp < [emulators count] ) // i.e. if we exited the for loop
385 #else
386 if ( [theEmulator isRunning] )
387 #endif
388 return TRUE;
389
390 return FALSE;
391 }
392
393 - (short) emulatorCreatedCount
394 {
395 short count = 0;
396 #ifdef ENABLE_MULTIPLE
397 int tmp;
398
399 for ( tmp = 0; tmp < [emulators count], ++tmp )
400 if ( [[emulators objectAtIndex: tmp] uaeCreated] )
401 ++count;
402 #else
403 if ( [theEmulator uaeCreated] )
404 ++count;
405 #endif
406
407 return count;
408 }
409
410 @end