1
2#import <Cocoa/Cocoa.h>
3
4#include "compat.h"
5#include "baselayer.h"
6#include "build.h"
7#include "editor.h"
8#include "osxbits.h"
9
10#ifndef MAC_OS_X_VERSION_10_5
11# define NSImageScaleNone NSScaleNone
12#endif
13
14#ifndef MAC_OS_X_VERSION_10_12
15# define NSEventModifierFlagOption NSAlternateKeyMask
16# define NSEventModifierFlagCommand NSCommandKeyMask
17# define NSEventMaskAny NSAnyEventMask
18# define NSWindowStyleMaskTitled NSTitledWindowMask
19# define NSWindowStyleMaskClosable NSClosableWindowMask
20# define NSWindowStyleMaskMiniaturizable NSMiniaturizableWindowMask
21# define NSWindowStyleMaskResizable NSResizableWindowMask
22# define NSAlertStyleInformational NSInformationalAlertStyle
23# define NSControlSizeSmall NSSmallControlSize
24#endif
25
26#ifndef MAC_OS_X_VERSION_10_14
27# define NSButtonTypeSwitch NSSwitchButton
28# define NSBezelStyleRounded NSRoundedBezelStyle
29# define NSControlStateValueOn NSOnState
30# define NSControlStateValueOff NSOffState
31#endif
32
33static inline NSRect NSRectChangeXY(NSRect const rect, CGFloat const x, CGFloat const y)
34{
35    return NSMakeRect(x, y, rect.size.width, rect.size.height);
36}
37static inline NSRect NSSizeAddXY(NSSize const size, CGFloat const x, CGFloat const y)
38{
39    return NSMakeRect(x, y, size.width, size.height);
40}
41static inline CGFloat NSRightEdge(NSRect rect)
42{
43    return rect.origin.x + rect.size.width;
44}
45static inline CGFloat NSTopEdge(NSRect rect)
46{
47    return rect.origin.y + rect.size.height;
48}
49
50static inline void setFontToSmall(id control)
51{
52    [control setFont:[NSFont fontWithDescriptor:[[control font] fontDescriptor] size:[NSFont smallSystemFontSize]]];
53}
54
55static inline void setControlToSmall(id control)
56{
57    [control setControlSize:NSControlSizeSmall];
58}
59
60static inline NSTextField * makeLabel(NSString * labelText)
61{
62    NSTextField *textField = [[NSTextField alloc] init];
63    setFontToSmall(textField);
64    setControlToSmall([textField cell]);
65    [textField setStringValue:labelText];
66    [textField setBezeled:NO];
67    [textField setDrawsBackground:NO];
68    [textField setEditable:NO];
69    [textField setSelectable:NO];
70    [textField sizeToFit];
71    return textField;
72}
73
74static inline NSButton * makeCheckbox(NSString * labelText)
75{
76    NSButton *checkbox = [[NSButton alloc] init];
77    setFontToSmall(checkbox);
78    setControlToSmall([checkbox cell]);
79    [checkbox setTitle:labelText];
80    [checkbox setButtonType:NSButtonTypeSwitch];
81    [checkbox sizeToFit];
82    return checkbox;
83}
84
85static inline NSPopUpButton * makeComboBox(void)
86{
87    NSPopUpButton *comboBox = [[NSPopUpButton alloc] init];
88    [comboBox setPullsDown:NO];
89    setFontToSmall(comboBox);
90    setControlToSmall([comboBox cell]);
91    [comboBox setBezelStyle:NSBezelStyleRounded];
92    [comboBox setPreferredEdge:NSMaxYEdge];
93    [[comboBox cell] setArrowPosition:NSPopUpArrowAtCenter];
94    [comboBox sizeToFit];
95    return comboBox;
96}
97
98/* setAppleMenu disappeared from the headers in 10.4 */
99@interface NSApplication(NSAppleMenu)
100- (void)setAppleMenu:(NSMenu *)menu;
101@end
102
103static inline NSString * GetApplicationName(void)
104{
105    NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"];
106    if (!appName)
107        appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"];
108    if (![appName length])
109        appName = [[NSProcessInfo processInfo] processName];
110
111    return appName;
112}
113
114static inline void CreateApplicationMenus(void)
115{
116    NSString *appName;
117    NSString *title;
118    NSMenu *rootMenu;
119    NSMenu *serviceMenu;
120    NSMenuItem *menuItem;
121
122    NSMenu *mainMenu = [[NSMenu alloc] init];
123
124    /* Create the application menu */
125    appName = GetApplicationName();
126    rootMenu = [[NSMenu alloc] init];
127
128    /* Put menu into the menubar */
129    menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""];
130    [menuItem setSubmenu:rootMenu];
131    [mainMenu addItem:menuItem];
132    [menuItem release];
133
134    /* Add menu items */
135    title = [@"About " stringByAppendingString:appName];
136    [rootMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""];
137
138    [rootMenu addItem:[NSMenuItem separatorItem]];
139
140    serviceMenu = [[NSMenu alloc] init];
141    menuItem = (NSMenuItem *)[rootMenu addItemWithTitle:@"Services" action:nil keyEquivalent:@""];
142    [menuItem setSubmenu:serviceMenu];
143
144    [nsapp setServicesMenu:serviceMenu];
145    [serviceMenu release];
146
147    [rootMenu addItem:[NSMenuItem separatorItem]];
148
149    title = [@"Hide " stringByAppendingString:appName];
150    [rootMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"];
151
152    menuItem = (NSMenuItem *)[rootMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"];
153    [menuItem setKeyEquivalentModifierMask:(NSEventModifierFlagOption|NSEventModifierFlagCommand)];
154
155    [rootMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""];
156
157    [rootMenu addItem:[NSMenuItem separatorItem]];
158
159    title = [@"Quit " stringByAppendingString:appName];
160    [rootMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"];
161
162    /* Create the main menu bar */
163    [nsapp setMainMenu:mainMenu];
164    [mainMenu release];  /* we're done with it, let NSApp own it. */
165
166    /* Tell the application object that this is now the application menu */
167    [nsapp setAppleMenu:rootMenu];
168    [rootMenu release];
169}
170
171static int retval = -1;
172
173static struct {
174    int fullscreen;
175    int xdim2d, ydim2d;
176    int xdim3d, ydim3d, bpp3d;
177    int forcesetup;
178} settings;
179
180@interface StartupWindow : NSWindow <NSWindowDelegate>
181{
182    NSMutableArray *modeslist2d;
183    NSMutableArray *modeslist3d;
184
185    NSButton *alwaysShowButton;
186    NSButton *fullscreenButton;
187    NSTextView *messagesView;
188    NSTabView *tabView;
189    NSTabViewItem *tabViewItemSetup;
190    NSTabViewItem *tabViewItemMessageLog;
191    NSPopUpButton *videoMode2DPUButton;
192    NSPopUpButton *videoMode3DPUButton;
193
194    NSButton *cancelButton;
195    NSButton *startButton;
196}
197
198- (StartupWindow *)init;
199
200- (void)dealloc;
201- (void)populateVideoModes:(BOOL)firstTime;
202
203- (void)fullscreenClicked:(id)sender;
204
205- (void)cancel:(id)sender;
206- (void)start:(id)sender;
207
208- (void)setupRunMode;
209- (void)setupMessagesMode;
210
211- (void)putsMessage:(NSString *)str;
212
213@end
214
215@implementation StartupWindow : NSWindow
216
217- (StartupWindow *)init
218{
219    NSUInteger const style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable;
220    NSRect const windowFrame = NSMakeRect(0, 0, 480, 280);
221    self = [super initWithContentRect:windowFrame styleMask:style backing:NSBackingStoreBuffered defer:NO];
222
223    if (self)
224    {
225        // window properties
226        [self setDelegate:self];
227        [self setReleasedWhenClosed:NO];
228#if defined MAC_OS_X_VERSION_10_3 && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_3
229        [self setContentMinSize:[[self contentView] frame].size];
230#else
231        [self setMinSize:[NSWindow frameRectForContentRect:[[self contentView] frame] styleMask:[self styleMask]].size];
232#endif
233
234
235        // image on the left
236        NSRect const imageFrame = NSMakeRect(0, 0, 100, 280);
237        NSImageView * imageView = [[NSImageView alloc] initWithFrame:imageFrame];
238        [imageView setImageScaling:NSImageScaleNone];
239        [imageView setImage:[NSImage imageNamed:@"build"]];
240        [[self contentView] addSubview:imageView];
241        [imageView setAutoresizingMask:NSViewMaxXMargin | NSViewHeightSizable];
242
243
244        // buttons
245        CGFloat const buttonWidth = 80;
246        CGFloat const buttonHeight = 32;
247
248        NSRect const startButtonFrame = NSMakeRect(windowFrame.size.width - buttonWidth, 0, buttonWidth, buttonHeight);
249        startButton = [[NSButton alloc] initWithFrame:startButtonFrame];
250        [[self contentView] addSubview:startButton];
251        [startButton setTitle:@"Start"];
252        [startButton setTarget:self];
253        [startButton setAction:@selector(start:)];
254        [startButton setBezelStyle:NSBezelStyleRounded];
255        [startButton setKeyEquivalent:@"\r"];
256        [startButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
257
258        NSRect const cancelButtonFrame = NSMakeRect(startButtonFrame.origin.x - buttonWidth, 0, buttonWidth, buttonHeight);
259        cancelButton = [[NSButton alloc] initWithFrame:cancelButtonFrame];
260        [[self contentView] addSubview:cancelButton];
261        [cancelButton setTitle:@"Cancel"];
262        [cancelButton setTarget:self];
263        [cancelButton setAction:@selector(cancel:)];
264        [cancelButton setBezelStyle:NSBezelStyleRounded];
265        [cancelButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
266
267
268        // tab frame
269        NSRect const tabViewFrame = NSMakeRect(imageFrame.size.width, buttonHeight, windowFrame.size.width - imageFrame.size.width, windowFrame.size.height - buttonHeight - 5);
270        tabView = [[NSTabView alloc] initWithFrame:tabViewFrame];
271        [[self contentView] addSubview:tabView];
272        setFontToSmall(tabView);
273        setControlToSmall(tabView);
274        [tabView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
275
276
277        // setup tab
278
279        tabViewItemSetup = [[NSTabViewItem alloc] init];
280        [tabView addTabViewItem:tabViewItemSetup];
281        [tabViewItemSetup setLabel:@"Setup"];
282        NSRect const tabViewItemSetupFrame = [[tabViewItemSetup view] frame];
283
284
285        // always show checkbox
286        alwaysShowButton = makeCheckbox(@"Always show this window at startup");
287        [[tabViewItemSetup view] addSubview:alwaysShowButton];
288        NSSize const alwaysShowButtonSize = [alwaysShowButton frame].size;
289        NSRect const alwaysShowButtonFrame = NSSizeAddXY(alwaysShowButtonSize, tabViewItemSetupFrame.size.width - alwaysShowButtonSize.width, 0);
290        [alwaysShowButton setFrame:alwaysShowButtonFrame];
291        [alwaysShowButton setAutoresizingMask:NSViewMinXMargin | NSViewMaxYMargin];
292
293
294        // video mode selectors and labels
295        NSTextField * label2DVideoMode = makeLabel(@"2D Video mode:");
296        [[tabViewItemSetup view] addSubview:label2DVideoMode];
297        NSSize const label2DVideoModeSize = [label2DVideoMode frame].size;
298        [label2DVideoMode setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
299
300        NSTextField * label3DVideoMode = makeLabel(@"3D Video mode:");
301        [[tabViewItemSetup view] addSubview:label3DVideoMode];
302        NSSize const label3DVideoModeSize = [label3DVideoMode frame].size;
303        [label3DVideoMode setAutoresizingMask:NSViewMaxXMargin | NSViewMinYMargin];
304
305        fullscreenButton = makeCheckbox(@"Fullscreen");
306        [[tabViewItemSetup view] addSubview:fullscreenButton];
307        NSSize const fullscreenButtonSize = [fullscreenButton frame].size;
308        [fullscreenButton setAction:@selector(fullscreenClicked:)];
309        [fullscreenButton setAutoresizingMask:NSViewMinXMargin | NSViewMinYMargin];
310
311        CGFloat const labelsVideoModeRightEdge = max(label2DVideoModeSize.width, label3DVideoModeSize.width);
312
313        videoMode2DPUButton = makeComboBox();
314        [[tabViewItemSetup view] addSubview:videoMode2DPUButton];
315        NSSize const videoMode2DPUButtonSize = [videoMode2DPUButton frame].size;
316        CGFloat const videoMode2DButtonX = labelsVideoModeRightEdge;
317        NSRect const videoMode2DPUButtonFrame = NSMakeRect(videoMode2DButtonX, tabViewItemSetupFrame.size.height - videoMode2DPUButtonSize.height, tabViewItemSetupFrame.size.width - videoMode2DButtonX - fullscreenButtonSize.width, videoMode2DPUButtonSize.height);
318        [videoMode2DPUButton setFrame:videoMode2DPUButtonFrame];
319        [videoMode2DPUButton setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
320
321        videoMode3DPUButton = makeComboBox();
322        [[tabViewItemSetup view] addSubview:videoMode3DPUButton];
323        NSSize const videoMode3DPUButtonSize = [videoMode3DPUButton frame].size;
324        CGFloat const videoMode3DButtonX = labelsVideoModeRightEdge;
325        NSRect const videoMode3DPUButtonFrame = NSMakeRect(videoMode3DButtonX, videoMode2DPUButtonFrame.origin.y - videoMode3DPUButtonSize.height, tabViewItemSetupFrame.size.width - videoMode3DButtonX - fullscreenButtonSize.width, videoMode3DPUButtonSize.height);
326        [videoMode3DPUButton setFrame:videoMode3DPUButtonFrame];
327        [videoMode3DPUButton setAutoresizingMask:NSViewWidthSizable | NSViewMinYMargin];
328
329        NSRect const label2DVideoModeFrame = NSSizeAddXY(label2DVideoModeSize, 0, videoMode2DPUButtonFrame.origin.y + rintf((videoMode2DPUButtonSize.height - label2DVideoModeSize.height) * 0.5f) + 1);
330        [label2DVideoMode setFrame:label2DVideoModeFrame];
331
332        NSRect const label3DVideoModeFrame = NSSizeAddXY(label3DVideoModeSize, 0, videoMode3DPUButtonFrame.origin.y + rintf((videoMode3DPUButtonSize.height - label3DVideoModeSize.height) * 0.5f) + 1);
333        [label3DVideoMode setFrame:label3DVideoModeFrame];
334
335        NSRect const fullscreenButtonFrame = NSSizeAddXY(fullscreenButtonSize, tabViewItemSetupFrame.size.width - fullscreenButtonSize.width, videoMode3DPUButtonFrame.origin.y + rintf((videoMode3DPUButtonSize.height - fullscreenButtonSize.height) * 0.5f) + 1);
336        [fullscreenButton setFrame:fullscreenButtonFrame];
337
338
339        // message log tab
340
341        tabViewItemMessageLog = [[NSTabViewItem alloc] init];
342        [tabView addTabViewItem:tabViewItemMessageLog];
343        [tabViewItemMessageLog setLabel:@"Message Log"];
344        NSRect const tabViewItemMessageLogFrame = [[tabViewItemMessageLog view] frame];
345
346
347        // message log
348        NSScrollView * messagesScrollView = [[NSScrollView alloc] initWithFrame:NSRectChangeXY(tabViewItemMessageLogFrame, 0, 0)];
349        [[tabViewItemMessageLog view] addSubview:messagesScrollView];
350        [messagesScrollView setBorderType:NSBezelBorder];
351        [messagesScrollView setHasVerticalScroller:YES];
352        [messagesScrollView setHasHorizontalScroller:NO];
353        setControlToSmall([[messagesScrollView verticalScroller] cell]);
354        NSSize const messagesScrollViewContentSize = [messagesScrollView contentSize];
355        [messagesScrollView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable];
356
357        messagesView = [[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, messagesScrollViewContentSize.width, messagesScrollViewContentSize.height)];
358        [messagesScrollView setDocumentView:messagesView];
359        [messagesView setEditable:NO];
360        [messagesView setRichText:NO];
361        setFontToSmall(messagesView);
362        [messagesView setMinSize:NSMakeSize(0.0, messagesScrollViewContentSize.height)];
363        [messagesView setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
364        [messagesView setVerticallyResizable:YES];
365        [messagesView setHorizontallyResizable:NO];
366        [messagesView setAutoresizingMask:NSViewWidthSizable];
367
368        [[messagesView textContainer] setContainerSize:NSMakeSize(messagesScrollViewContentSize.width, FLT_MAX)];
369        [[messagesView textContainer] setWidthTracksTextView:YES];
370    }
371
372    return self;
373}
374
375- (BOOL)canBecomeKeyWindow
376{
377    return YES;
378}
379
380- (BOOL)canBecomeMainWindow
381{
382    return YES;
383}
384
385- (BOOL) windowShouldClose:(id)sender
386{
387    UNREFERENCED_PARAMETER(sender);
388
389    retval = 0;
390
391    return YES;
392}
393
394- (void)dealloc
395{
396    [modeslist3d release];
397    [super dealloc];
398}
399
400- (void)populateVideoModes:(BOOL)firstTime
401{
402    int i, mode3d, fullscreen = ([fullscreenButton state] == NSControlStateValueOn);
403    int mode2d, idx2d = -1;
404    int idx3d = -1;
405    int xdim2d = 0, ydim2d = 0;
406    int const bpp2d = 8;
407    int xdim = 0, ydim = 0, bpp = 0;
408
409    if (firstTime) {
410        xdim2d = settings.xdim2d;
411        ydim2d = settings.ydim2d;
412        xdim = settings.xdim3d;
413        ydim = settings.ydim3d;
414        bpp  = settings.bpp3d;
415    } else {
416        mode2d = [[modeslist2d objectAtIndex:[videoMode2DPUButton indexOfSelectedItem]] intValue];
417        if (mode2d >= 0) {
418            xdim2d = validmode[mode2d].xdim;
419            ydim2d = validmode[mode2d].ydim;
420        }
421
422        mode3d = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue];
423        if (mode3d >= 0) {
424            xdim = validmode[mode3d].xdim;
425            ydim = validmode[mode3d].ydim;
426            bpp = validmode[mode3d].bpp;
427        }
428    }
429
430
431    mode2d = videoCheckMode(&xdim2d, &ydim2d, bpp2d, fullscreen, 1);
432
433    [modeslist2d release];
434    [videoMode2DPUButton removeAllItems];
435
436    modeslist2d = [[NSMutableArray alloc] init];
437
438    for (i = 0; i < validmodecnt; i++) {
439        if (fullscreen == validmode[i].fs) {
440            if (i == mode2d) idx2d = [modeslist2d count];
441            [modeslist2d addObject:[NSNumber numberWithInt:i]];
442            [videoMode2DPUButton addItemWithTitle:[NSString stringWithFormat:@"%d %C %d",
443                                                   validmode[i].xdim, 0xd7, validmode[i].ydim]];
444        }
445    }
446
447    if (idx2d >= 0) [videoMode2DPUButton selectItemAtIndex:idx2d];
448
449
450    mode3d = videoCheckMode(&xdim, &ydim, bpp, fullscreen, 1);
451    if (mode3d < 0) {
452        int i, cd[] = { 32, 24, 16, 15, 8, 0 };
453        for (i=0; cd[i]; ) { if (cd[i] >= bpp) i++; else break; }
454        for ( ; cd[i]; i++) {
455            mode3d = videoCheckMode(&xdim, &ydim, cd[i], fullscreen, 1);
456            if (mode3d < 0) continue;
457            break;
458        }
459    }
460
461    [modeslist3d release];
462    [videoMode3DPUButton removeAllItems];
463
464    modeslist3d = [[NSMutableArray alloc] init];
465
466    for (i = 0; i < validmodecnt; i++) {
467        if (fullscreen == validmode[i].fs) {
468            if (i == mode3d) idx3d = [modeslist3d count];
469            [modeslist3d addObject:[NSNumber numberWithInt:i]];
470            [videoMode3DPUButton addItemWithTitle:[NSString stringWithFormat:@"%d %C %d %d-bpp",
471                                                   validmode[i].xdim, 0xd7, validmode[i].ydim, validmode[i].bpp]];
472        }
473    }
474
475    if (idx3d >= 0) [videoMode3DPUButton selectItemAtIndex:idx3d];
476}
477
478- (void)fullscreenClicked:(id)sender
479{
480    UNREFERENCED_PARAMETER(sender);
481
482    [self populateVideoModes:NO];
483}
484
485- (void)cancel:(id)sender
486{
487    UNREFERENCED_PARAMETER(sender);
488
489    retval = 0;
490}
491
492- (void)start:(id)sender
493{
494    UNREFERENCED_PARAMETER(sender);
495
496    int mode2d = [[modeslist2d objectAtIndex:[videoMode2DPUButton indexOfSelectedItem]] intValue];
497    if (mode2d >= 0) {
498        settings.xdim2d = validmode[mode2d].xdim;
499        settings.ydim2d = validmode[mode2d].ydim;
500        settings.fullscreen = validmode[mode2d].fs;
501    }
502
503    int mode = [[modeslist3d objectAtIndex:[videoMode3DPUButton indexOfSelectedItem]] intValue];
504    if (mode >= 0) {
505        settings.xdim3d = validmode[mode].xdim;
506        settings.ydim3d = validmode[mode].ydim;
507        settings.bpp3d = validmode[mode].bpp;
508        settings.fullscreen = validmode[mode].fs;
509    }
510
511    settings.forcesetup = [alwaysShowButton state] == NSControlStateValueOn;
512
513    retval = 1;
514}
515
516- (void)setupRunMode
517{
518    videoGetModes();
519
520    [fullscreenButton setState: (settings.fullscreen ? NSControlStateValueOn : NSControlStateValueOff)];
521    [alwaysShowButton setState: (settings.forcesetup ? NSControlStateValueOn : NSControlStateValueOff)];
522    [self populateVideoModes:YES];
523
524    // enable all the controls on the Configuration page
525    NSEnumerator *enumerator = [[[tabViewItemSetup view] subviews] objectEnumerator];
526    NSControl *control;
527    while ((control = [enumerator nextObject]))
528    {
529        if ([control respondsToSelector:@selector(setEnabled:)])
530            [control setEnabled:true];
531    }
532
533    [cancelButton setEnabled:true];
534    [startButton setEnabled:true];
535
536    [tabView selectTabViewItem:tabViewItemSetup];
537    [NSCursor unhide]; // Why should I need to do this?
538}
539
540- (void)setupMessagesMode
541{
542    [tabView selectTabViewItem:tabViewItemMessageLog];
543
544    // disable all the controls on the Configuration page except "always show", so the
545    // user can enable it if they want to while waiting for something else to happen
546    NSEnumerator *enumerator = [[[tabViewItemSetup view] subviews] objectEnumerator];
547    NSControl *control;
548    while ((control = [enumerator nextObject]))
549    {
550        if (control != alwaysShowButton && [control respondsToSelector:@selector(setEnabled:)])
551            [control setEnabled:false];
552    }
553
554    [cancelButton setEnabled:false];
555    [startButton setEnabled:false];
556}
557
558- (void)putsMessage:(NSString *)str
559{
560    NSRange end;
561    NSTextStorage *text = [messagesView textStorage];
562    BOOL shouldAutoScroll;
563
564    shouldAutoScroll = ((int)NSMaxY([messagesView bounds]) == (int)NSMaxY([messagesView visibleRect]));
565
566    end.location = [text length];
567    end.length = 0;
568
569    [text beginEditing];
570    [messagesView replaceCharactersInRange:end withString:str];
571    [text endEditing];
572
573    if (shouldAutoScroll) {
574        end.location = [text length];
575        end.length = 0;
576        [messagesView scrollRangeToVisible:end];
577    }
578}
579
580@end
581
582static StartupWindow *startwin = nil;
583
584int startwin_open(void)
585{
586    if (startwin != nil) return 1;
587
588    startwin = [[StartupWindow alloc] init];
589    if (startwin == nil) return -1;
590
591    [startwin setupMessagesMode];
592
593    [startwin center];
594    [startwin makeKeyAndOrderFront:nil];
595
596    CreateApplicationMenus();
597
598    return 0;
599}
600
601int startwin_close(void)
602{
603    if (startwin == nil) return 1;
604
605    [startwin close];
606    [startwin release];
607    startwin = nil;
608
609    return 0;
610}
611
612int startwin_puts(const char *s)
613{
614    NSString *ns;
615
616    if (!s) return -1;
617    if (startwin == nil) return 1;
618
619    ns = [NSString stringWithUTF8String:s];
620    [startwin putsMessage:ns];
621    [ns release];
622
623    return 0;
624}
625
626int startwin_settitle(const char *s)
627{
628    NSString *ns;
629
630    if (!s) return -1;
631    if (startwin == nil) return 1;
632
633    ns = [NSString stringWithUTF8String:s];
634    [startwin setTitle:ns];
635    [ns release];
636
637    return 0;
638}
639
640int startwin_idle(void *v)
641{
642    UNREFERENCED_PARAMETER(v);
643
644    if (startwin)
645    {
646        NSEvent *event;
647        do
648        {
649            event = [nsapp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate date] inMode:NSDefaultRunLoopMode dequeue:YES];
650            [nsapp sendEvent:event];
651        }
652        while (event != nil);
653
654        [startwin displayIfNeeded];
655        [nsapp updateWindows];
656    }
657
658    return 0;
659}
660
661
662int startwin_run(void)
663{
664    if (startwin == nil) return 0;
665
666    settings.fullscreen = fullscreen;
667    settings.xdim2d = xdim2d;
668    settings.ydim2d = ydim2d;
669    settings.xdim3d = xdimgame;
670    settings.ydim3d = ydimgame;
671    settings.bpp3d = bppgame;
672    settings.forcesetup = forcesetup;
673
674    [startwin setupRunMode];
675
676    do
677    {
678        NSEvent *event = [nsapp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantFuture] inMode:NSDefaultRunLoopMode dequeue:YES];
679        [nsapp sendEvent:event];
680        [nsapp updateWindows];
681    }
682    while (retval == -1);
683
684    [startwin setupMessagesMode];
685    [nsapp updateWindows];
686
687    if (retval) {
688        fullscreen = settings.fullscreen;
689        xdim2d = settings.xdim2d;
690        ydim2d = settings.ydim2d;
691        xdimgame = settings.xdim3d;
692        ydimgame = settings.ydim3d;
693        bppgame = settings.bpp3d;
694        forcesetup = settings.forcesetup;
695    }
696
697    return retval;
698}
699