From 6b22a2613856c66ee5a191045fe07cd4f6bf84e9 Mon Sep 17 00:00:00 2001 From: core-code Date: Mon, 4 Jun 2007 19:18:35 +0000 Subject: [PATCH] mac updates git-svn-id: svn://svn.code.sf.net/p/actiongame/code/trunk/ac@1126 e016b1c5-ed68-44aa-a2f7-31cac88cffde --- source/src/console.cpp | 6 +- source/src/cube.h | 4 - source/xcode/ConsoleView.h | 25 + source/xcode/ConsoleView.m | 120 ++ source/xcode/English.lproj/InfoPlist.strings | Bin 618 -> 632 bytes source/xcode/Help.tiff | Bin 0 -> 1716 bytes source/xcode/Keys.gif | Bin 0 -> 2545 bytes source/xcode/Launcher.h | 24 +- source/xcode/Launcher.m | 584 +++++- source/xcode/Main.gif | Bin 0 -> 1629 bytes source/xcode/ReadMe.html | 12 + source/xcode/SDLMain.m | 233 ++- source/xcode/Server.gif | Bin 0 -> 2344 bytes .../actioncube.xcodeproj/julianmayer.pbxuser | 1562 ++++++++++++++--- .../actioncube.xcodeproj/project.pbxproj | 288 +-- source/xcode/launcher-Info.plist | 2 + source/xcode/macutils.mm | 16 + source/xcode/main.m | 8 - 18 files changed, 2312 insertions(+), 572 deletions(-) create mode 100755 source/xcode/ConsoleView.h create mode 100755 source/xcode/ConsoleView.m create mode 100644 source/xcode/Help.tiff create mode 100644 source/xcode/Keys.gif create mode 100644 source/xcode/Main.gif create mode 100644 source/xcode/ReadMe.html create mode 100644 source/xcode/Server.gif create mode 100644 source/xcode/macutils.mm diff --git a/source/src/console.cpp b/source/src/console.cpp index 6cd689fa..20b98814 100644 --- a/source/src/console.cpp +++ b/source/src/console.cpp @@ -180,7 +180,11 @@ void pasteconsole() s_strcat(commandbuf, cb); GlobalUnlock(cb); CloseClipboard(); - #elif !defined(__APPLE__) + #elif defined(__APPLE__) + extern void mac_pasteconsole(char *commandbuf); + + mac_pasteconsole(commandbuf); + #else SDL_SysWMinfo wminfo; SDL_VERSION(&wminfo.version); wminfo.subsystem = SDL_SYSWM_X11; diff --git a/source/src/cube.h b/source/src/cube.h index 6e89afff..bbd5c81a 100644 --- a/source/src/cube.h +++ b/source/src/cube.h @@ -42,11 +42,7 @@ #include #undef __glext_h__ -#ifdef __APPLE__ -#include "OpenGL/glext.h" -#else #include "GL/glext.h" -#endif #include diff --git a/source/xcode/ConsoleView.h b/source/xcode/ConsoleView.h new file mode 100755 index 00000000..89df0b71 --- /dev/null +++ b/source/xcode/ConsoleView.h @@ -0,0 +1,25 @@ +#import + +/* + * A basic console view + */ + +@interface ConsoleView : NSView { +@private + NSMutableArray *array; + NSDictionary *attr; + BOOL endScroll; +} +- (void)scrollToEnd:(BOOL)enable; + +/* + * Append the given line + */ +- (void)appendLine:(NSString*)line; + +/* + * Append multiple lines, skip blank ones + */ +- (void)appendText:(NSString*)text; + +@end diff --git a/source/xcode/ConsoleView.m b/source/xcode/ConsoleView.m new file mode 100755 index 00000000..a8c65c36 --- /dev/null +++ b/source/xcode/ConsoleView.m @@ -0,0 +1,120 @@ +#import "ConsoleView.h" + +#define MAX_LINES 200 +#define LINE_WIDTH 500 +#define LINE_HEIGHT 12 + +/* + * This VScroller sends a scrollToEnd message to the console based on whether you hit page/line down or not + */ +@interface VScroller : NSScroller { +} +@end +@implementation VScroller +- (NSScrollerPart)hitPart { + ConsoleView *view = (ConsoleView *)[(NSScrollView*)[self superview] documentView]; + NSScrollerPart part = [super hitPart]; + [view scrollToEnd:((part == NSScrollerIncrementPage) || (part == NSScrollerIncrementLine))]; + return part; +} +@end + + +@implementation ConsoleView + +- (id)initWithFrame:(NSRect)frame { + self = [super initWithFrame:frame]; + if (self) { + array = [[[NSMutableArray alloc] init] retain]; + + attr = [[NSDictionary dictionaryWithObjectsAndKeys: + [NSFont userFontOfSize:(LINE_HEIGHT-2)], NSFontAttributeName, + [NSColor colorWithCalibratedRed:0.2 green:0.8 blue:0.2 alpha:1.0], NSForegroundColorAttributeName, + nil] retain]; + } + return self; +} + +- (void)awakeFromNib { + [self scrollToEnd:YES]; + + NSScroller *vscroll = [[VScroller alloc] init]; + [vscroll setControlSize:[[[self enclosingScrollView] verticalScroller] controlSize]]; + [[self enclosingScrollView] setVerticalScroller:vscroll]; +} + +- (void)dealloc { + [attr release]; + [array release]; + [super dealloc]; +} + +- (BOOL)isFlipped { + return YES; +} + +- (void)drawRect:(NSRect)rect { + //draw the visible lines only + int startLine = rect.origin.y/LINE_HEIGHT; + int endLine = 1 + (rect.origin.y+rect.size.height)/LINE_HEIGHT; + if(startLine < 0) startLine = 0; + if(endLine > [array count]) endLine = [array count]; + int i; + for(i = startLine; i < endLine; i++) { + NSString *str = [array objectAtIndex:i]; + [str drawAtPoint:NSMakePoint(2, i * LINE_HEIGHT) withAttributes:attr]; + } +} + +- (void)scrollToEnd:(BOOL)enable { + endScroll = enable; +} + +- (void)appendLine:(NSString*)line { + BOOL chop = [array count] > MAX_LINES; + if(chop) { + [array removeObjectAtIndex:0]; // limit the number of lines + } + [array addObject:line]; + int i = [array count]; + [self setFrame:NSMakeRect(0, 0, LINE_WIDTH, i*LINE_HEIGHT)]; // increase the frame size + + NSRect rect = NSMakeRect(0, (i-1)*LINE_HEIGHT, LINE_WIDTH, LINE_HEIGHT); + if(endScroll) { + // Scroll to the line just added + if([self scrollRectToVisible:rect]) return; + } else { + // Lock the scrolling on the first visible line + i = [self visibleRect].origin.y/LINE_HEIGHT; + if(!chop) i++; + if(i < 0) i = 0; + if(i > [array count]) i = [array count]; + NSRect vrect = NSMakeRect(0, (i-1)*LINE_HEIGHT, LINE_WIDTH, LINE_HEIGHT); + if([self scrollRectToVisible:vrect]) return; + } + if(chop) + [self setNeedsDisplay:YES]; + else + [self setNeedsDisplayInRect:rect]; +} + +- (void)appendText:(NSString*)text { + NSArray *lines = [text componentsSeparatedByString:@"\n"]; //@TODO assumes we get given lines rather than fragments... + int i; + for(i = 0; i < [lines count]; i++) { + NSString *line = [lines objectAtIndex:i]; + if([line length] == 0) continue; //skip empty + [self appendLine:line]; + } +} + +- (BOOL)acceptsFirstResponder { + return YES; +} + +- (IBAction)delete:(id)sender { + [array removeAllObjects]; + [self setFrame:NSMakeRect(0,0,0,0)]; +} + +@end diff --git a/source/xcode/English.lproj/InfoPlist.strings b/source/xcode/English.lproj/InfoPlist.strings index 406562073e2fe6a40c64bc1a60d1b53c55d8e618..ad05759bf7742c3aeeec381a6841d70ba4cb888a 100644 GIT binary patch delta 108 zcmaFG@`GhU9d|K9F+(ClDMJoJ$;5VFc_c1_Gf+5*A(cUa!GJ-J!4im#C-#d^W?@tz Tq-?Syqb8&IBl|g~QfI*MJa^ghs$vliIxD`zH QXVhdgn_S7b7EA^L09h;*?EnA( diff --git a/source/xcode/Help.tiff b/source/xcode/Help.tiff new file mode 100644 index 0000000000000000000000000000000000000000..058483139a4cd978174d42cc19784de5978d37ea GIT binary patch literal 1716 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 HAOHY6VKqWB literal 0 HcmV?d00001 diff --git a/source/xcode/Launcher.h b/source/xcode/Launcher.h index ad2b4a93..fedcc289 100644 --- a/source/xcode/Launcher.h +++ b/source/xcode/Launcher.h @@ -1,10 +1,26 @@ #import -@interface MyObject : NSObject -{ - IBOutlet NSPopUpButton *resolutions; - IBOutlet NSButtonCell *fullscreen; +@class ConsoleView; +@interface Launcher : NSObject { + IBOutlet NSWindow *window; + IBOutlet NSView *view1; + IBOutlet NSView *view2; + IBOutlet NSView *view3; + + IBOutlet NSArrayController *maps; + IBOutlet NSArrayController *keys; + IBOutlet NSPopUpButton *resolutions; + IBOutlet NSButton *multiplayer; + IBOutlet ConsoleView *console; +@private + NSMutableDictionary *toolBarItems; + pid_t server; } + - (IBAction)playAction:(id)sender; + +- (IBAction)multiplayerAction:(id)sender; + +- (IBAction)helpAction:(id)sender; @end \ No newline at end of file diff --git a/source/xcode/Launcher.m b/source/xcode/Launcher.m index 6bb66e5c..2b5714d3 100644 --- a/source/xcode/Launcher.m +++ b/source/xcode/Launcher.m @@ -1,109 +1,533 @@ #import "Launcher.h" - -#include +#import "ConsoleView.h" #include +#include /* unlink */ +#include /* forkpty */ + #define kMaxDisplays 16 -NSMutableArray *array; - -static int numberForKey( CFDictionaryRef desc, CFStringRef key ) +// unless you want strings with "(null)" in them :-/ +@interface NSUserDefaults(Extras) +- (NSString*)nonNullStringForKey:(NSString*)key; +@end + +@implementation NSUserDefaults(Extras) +- (NSString*)nonNullStringForKey:(NSString*)key { + NSString *result = [self stringForKey:key]; + return (result?result:@""); +} +@end + + + +@interface Map : NSObject { + NSString *path; +} +@end + +@implementation Map +- (id)initWithPath:(NSString*)aPath +{ + if((self = [super init])) + path = [[aPath stringByDeletingPathExtension] retain]; + return self; +} +- (void)dealloc +{ + [path release]; + [super dealloc]; +} +- (NSString*)path { return path; } +- (NSString*)name { return [path lastPathComponent]; } +- (NSImage*)image { return [[NSImage alloc] initWithContentsOfFile:[path stringByAppendingString:@".jpg"]]; } +- (NSString*)text +{ + NSString *text = [NSString alloc]; + if(![text respondsToSelector:@selector(initWithContentsOfFile:encoding:error:)]) + return [text initWithContentsOfFile:[path stringByAppendingString:@".txt"]]; //deprecated in 10.4 + NSError *error; + return [text initWithContentsOfFile:[path stringByAppendingString:@".txt"] encoding:NSASCIIStringEncoding error:&error]; +} +- (NSString*)tickIfExists:(NSString*)ext +{ + unichar tickCh = 0x2713; + return [[NSFileManager defaultManager] fileExistsAtPath:[path stringByAppendingString:ext]] ? [NSString stringWithCharacters:&tickCh length:1] : @""; +} +- (NSString*)hasImage { return [self tickIfExists:@".jpg"]; } +- (NSString*)hasText { return [self tickIfExists:@".txt"]; } +- (NSString*)hasCfg { return [self tickIfExists:@".cfg"]; } +@end + + + +static int numberForKey(CFDictionaryRef desc, CFStringRef key) { CFNumberRef value; int num = 0; - - if ( (value = CFDictionaryGetValue(desc, key)) == NULL ) + if ((value = CFDictionaryGetValue(desc, key)) == NULL) return 0; CFNumberGetValue(value, kCFNumberIntType, &num); return num; } +@implementation Launcher -static void listModes(CGDirectDisplayID dspy) +- (void)switchViews:(NSToolbarItem *)item +{ + NSView *prefsView; + switch([item tag]) + { + case 1: prefsView = view1; break; + case 2: prefsView = view2; break; + case 3: prefsView = view3; break; + //extend as see fit... + default: return; + } + + //to stop flicker, we make a temp blank view. + NSView *tempView = [[NSView alloc] initWithFrame:[[window contentView] frame]]; + [window setContentView:tempView]; + [tempView release]; + + //mojo to get the right frame for the new window. + NSRect newFrame = [window frame]; + newFrame.size.height = [prefsView frame].size.height + ([window frame].size.height - [[window contentView] frame].size.height); + newFrame.size.width = [prefsView frame].size.width; + newFrame.origin.y += ([[window contentView] frame].size.height - [prefsView frame].size.height); + + //set the frame to newFrame and animate it. + [window setFrame:newFrame display:YES animate:YES]; + //set the main content view to the new view we have picked through the if structure above. + [window setContentView:prefsView]; + [window setContentMinSize:[prefsView bounds].size]; +} + +- (NSToolbarItem*)addToolBarItem:(NSString*)name +{ + int n = [toolBarItems count] + 1; + NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:[NSString stringWithFormat:@"%0d", n]]; + [item setTag:n]; + [item setTarget:self]; + [item setAction:@selector(switchViews:)]; + [toolBarItems setObject:item forKey:[item itemIdentifier]]; + [item setLabel:NSLocalizedString(name, @"")]; + [item setImage:[NSImage imageNamed:name]]; + [item release]; + return item; +} + +- (void)initViews +{ + toolBarItems = [[NSMutableDictionary alloc] init]; + NSToolbarItem *first = [self addToolBarItem:@"Main"]; + [self addToolBarItem:@"Keys"]; + [self addToolBarItem:@"Server"]; + + NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:NSToolbarFlexibleSpaceItemIdentifier]; + [toolBarItems setObject:item forKey:[item itemIdentifier]]; + [item release]; + + [[self addToolBarItem:@"Help"] setAction:@selector(helpAction:)]; + + NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"PreferencePanes"]; + [toolbar setDelegate:self]; + [toolbar setAllowsUserCustomization:NO]; + [toolbar setAutosavesConfiguration:NO]; + [window setToolbar:toolbar]; + [toolbar release]; + if([window respondsToSelector:@selector(setShowsToolbarButton:)]) [window setShowsToolbarButton:NO]; //10.4+ + + //Make it select the first by default + [toolbar setSelectedItemIdentifier:[first itemIdentifier]]; + [self switchViews:first]; +} + +/* + * toolbar delegate methods + */ +- (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag +{ + return [toolBarItems objectForKey:itemIdentifier]; +} + +- (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)theToolbar +{ + return [self toolbarDefaultItemIdentifiers:theToolbar]; +} + +- (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)theToolbar +{ + return [NSArray arrayWithObjects:@"1", @"2", @"3", NSToolbarFlexibleSpaceItemIdentifier, @"5", nil]; +} + +- (NSArray *)toolbarSelectableItemIdentifiers: (NSToolbar *)toolbar { + return [NSArray arrayWithObjects:@"1", @"2", @"3", nil]; +} + + + + + + +- (void)addResolutionsForDisplay:(CGDirectDisplayID)dspy { - CFArrayRef modeList; - CFDictionaryRef mode; CFIndex i, cnt; - - modeList = CGDisplayAvailableModes(dspy); - if ( modeList == NULL ) - { - printf( "Display is invalid\n" ); - return; - } + CFArrayRef modeList = CGDisplayAvailableModes(dspy); + if(modeList == NULL) return; cnt = CFArrayGetCount(modeList); - //printf( "Display 0x%x: %d modes:\n", (unsigned int)dspy, (int)cnt ); - for ( i = 0; i < cnt; ++i ) - { - mode = CFArrayGetValueAtIndex(modeList, i); - [array addObject:[NSString stringWithFormat:@"%i x %i", numberForKey(mode, kCGDisplayWidth), numberForKey(mode, kCGDisplayHeight)]]; - - } + for(i = 0; i < cnt; i++) { + CFDictionaryRef mode = CFArrayGetValueAtIndex(modeList, i); + NSString *title = [NSString stringWithFormat:@"%i x %i", numberForKey(mode, kCGDisplayWidth), numberForKey(mode, kCGDisplayHeight)]; + if(![resolutions itemWithTitle:title]) [resolutions addItemWithTitle:title]; + } } -@implementation MyObject - -- (IBAction)playAction:(id)sender -{ - NSArray *res = [[resolutions titleOfSelectedItem] componentsSeparatedByString:@" x "]; - NSMutableArray *args = [[NSMutableArray alloc] init]; - NSString *cwd = [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"actioncube"]; - - [args addObject:[NSString stringWithFormat:@"-w%@", [res objectAtIndex:0]]]; - [args addObject:[NSString stringWithFormat:@"-h%@", [res objectAtIndex:1]]]; - - if([fullscreen state] == NSOffState) [args addObject:@"-t"]; - - - NSTask *task = [[NSTask alloc] init]; - [task setCurrentDirectoryPath:cwd]; - [task setLaunchPath:[cwd stringByAppendingPathComponent:@"actioncube.app/Contents/MacOS/actioncube"]]; - [task setArguments:args]; - [args release]; - - BOOL okay = YES; - - NS_DURING - [task launch]; - [NSApp terminate:self]; - NS_HANDLER - NSRunAlertPanel(@"Error", @"Can't start Sauerbraten! Please move the directory containing Sauerbraten to a path that doesn't contain weird characters or start Sauerbraten manually.", @"OK", NULL, NULL); - okay = NO; - NS_ENDHANDLER -} - - -- (void)applicationDidFinishLaunching:(NSNotification *)aNotification +- (void)initResolutions { CGDirectDisplayID display[kMaxDisplays]; CGDisplayCount numDisplays; - CGDisplayCount i; - CGDisplayErr err; - - array = [[NSMutableArray alloc] init]; - - err = CGGetActiveDisplayList(kMaxDisplays, - display, - &numDisplays); - if ( err != CGDisplayNoErr ) + [resolutions removeAllItems]; + if(CGGetActiveDisplayList(kMaxDisplays, display, &numDisplays) == CGDisplayNoErr) { - printf("Cannot get displays (%d)\n", err); - exit( 1 ); + CGDisplayCount i; + for (i = 0; i < numDisplays; i++) + [self addResolutionsForDisplay:display[i]]; } + [resolutions selectItemAtIndex: [[NSUserDefaults standardUserDefaults] integerForKey:@"resolution"]]; +} + + + + +/* directory where the executable lives */ +-(NSString *)cwd +{ + return [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"assaultcube"]; +} + +/* build key array from config data */ +-(NSArray *)getKeys:(NSDictionary *)dict +{ + NSMutableArray *arr = [[NSMutableArray alloc] init]; + NSEnumerator *e = [dict keyEnumerator]; + NSString *key; + while ((key = [e nextObject])) + { + NSString *trig; + if([key hasPrefix:@"editbind"]) + trig = [key substringFromIndex:9]; + else if([key hasPrefix:@"bind"]) + trig = [key substringFromIndex:5]; + else + continue; + [arr addObject:[NSDictionary dictionaryWithObjectsAndKeys: //keys used in nib + trig, @"key", + [key hasPrefix:@"editbind"]?@"edit":@"", @"mode", + [dict objectForKey:key], @"action", + nil]]; + } + return arr; +} + + +/* + * extract a dictionary from the config files containing: + * - name, team, gamma strings + * - bind/editbind '.' key strings + */ +-(NSDictionary *)readConfigFiles +{ + NSMutableDictionary *dict = [[NSMutableDictionary alloc] init]; + [dict setObject:@"" forKey:@"name"]; //ensure these entries are never nil + [dict setObject:@"" forKey:@"team"]; - //printf( "%d displays found\n", (int)numDisplays ); - for ( i = 0; i < numDisplays; ++i ) - listModes(display[i]); + NSString *files[] = {@"config.cfg", @"autoexec.cfg"}; + int i; + for(i = 0; i < sizeof(files)/sizeof(NSString*); i++) + { + NSString *file = [[self cwd] stringByAppendingPathComponent:files[i]]; + NSArray *lines = [[NSString stringWithContentsOfFile:file] componentsSeparatedByString:@"\n"]; + + if(i==0 && !lines) // ugh - special case when first run... + { + file = [[self cwd] stringByAppendingPathComponent:@"config/defaults.cfg"]; + lines = [[NSString stringWithContentsOfFile:file] componentsSeparatedByString:@"\n"]; + } + + NSString *line; + NSEnumerator *e = [lines objectEnumerator]; + while(line = [e nextObject]) + { + NSRange r; // more flexible to do this manually rather than via NSScanner... + int j = 0; + while(j < [line length] && [line characterAtIndex:j] <= ' ') j++; //skip white + r.location = j; + while(j < [line length] && [line characterAtIndex:j] > ' ') j++; //until white + r.length = j - r.location; + NSString *type = [line substringWithRange:r]; + + while(j < [line length] && [line characterAtIndex:j] <= ' ') j++; //skip white + if(j < [line length] && [line characterAtIndex:j] == '"') + { + r.location = ++j; + while(j < [line length] && [line characterAtIndex:j] != '"') j++; //until close quote + r.length = (j++) - r.location; + } else { + r.location = j; + while(j < [line length] && [line characterAtIndex:j] > ' ') j++; //until white + r.length = j - r.location; + } + NSString *value = [line substringWithRange:r]; + + while(j < [line length] && [line characterAtIndex:j] <= ' ') j++; //skip white + NSString *remainder = [line substringFromIndex:j]; + + if([type isEqual:@"name"] || [type isEqual:@"team"] || [type isEqual:@"gamma"]) + [dict setObject:value forKey:type]; + else if([type isEqual:@"bind"] || [type isEqual:@"editbind"]) + [dict setObject:remainder forKey:[NSString stringWithFormat:@"%@.%@", type,value]]; + } + } + return dict; +} + +-(void)updateAutoexecFile:(NSDictionary *)updates +{ + NSString *file = [[self cwd] stringByAppendingPathComponent:@"config/autoexec.cfg"]; + //build the data + NSString *result = nil; + NSArray *lines = [[NSString stringWithContentsOfFile:file] componentsSeparatedByString:@"\n"]; + if(lines) + { + NSString *line; + NSEnumerator *e = [lines objectEnumerator]; + while(line = [e nextObject]) + { + NSScanner *scanner = [NSScanner scannerWithString:line]; + NSString *type; + if([scanner scanCharactersFromSet:[NSCharacterSet letterCharacterSet] intoString:&type]) + if([updates objectForKey:type]) continue; //skip things declared in updates + result = (result) ? [NSString stringWithFormat:@"%@\n%@", result, line] : line; + } + } + NSEnumerator *e = [updates keyEnumerator]; + NSString *type; + while(type = [e nextObject]) + { + id value = [updates objectForKey:type]; + if([type isEqual:@"name"] || [type isEqual:@"team"]) value = [NSString stringWithFormat:@"\"%@\"", value]; + NSString *line = [NSString stringWithFormat:@"%@ %@", type, value]; + result = (result) ? [NSString stringWithFormat:@"%@\n%@", result, line] : line; + } + //backup + NSFileManager *fm = [NSFileManager defaultManager]; + NSString *backupfile = nil; + if([fm fileExistsAtPath:file]) + { + backupfile = [file stringByAppendingString:@".bak"]; + if(![fm movePath:file toPath:backupfile handler:nil]) return; //can't create backup + } + //write the new file + if(![fm createFileAtPath:file contents:[result dataUsingEncoding:NSASCIIStringEncoding] attributes:nil]) return; //can't create new file + //remove the backup + if(backupfile) [fm removeFileAtPath:backupfile handler:nil]; +} + +- (void)serverTerminated +{ + if(server==-1) return; + server = -1; + [multiplayer setTitle:@"Start"]; + [console appendText:@"\n \n"]; +} + +- (void)setServerActive:(BOOL)start +{ + if((server==-1) != start) return; - [resolutions removeAllItems]; + if(!start) + { //STOP + + //damn server, terminate isn't good enough for you - die, die, die... + if((server!=-1) && (server!=0)) kill(server, SIGKILL); //@WARNING - you do not want a 0 or -1 to be accidentally sent a kill! + [self serverTerminated]; + } + else + { //START + NSString *cwd = [self cwd]; + NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; + + NSArray *opts = [[defs nonNullStringForKey:@"server_options"] componentsSeparatedByString:@" "]; + + const char *childCwd = [cwd fileSystemRepresentation]; + const char *childPath = [[cwd stringByAppendingPathComponent:@"actioncube.app/Contents/MacOS/actioncube"] fileSystemRepresentation]; + const char **args = (const char**)malloc(sizeof(char*)*([opts count] + 3 + 3)); //3 = {path, -d, NULL}, and +3 again for optional settings... + int i, fdm, argc = 0; + + args[argc++] = childPath; + args[argc++] = "-d"; + + for(i = 0; i < [opts count]; i++) + { + NSString *opt = [opts objectAtIndex:i]; + if([opt length] == 0) continue; //skip empty + args[argc++] = [opt UTF8String]; + } + + NSString *desc = [[NSUserDefaults standardUserDefaults] nonNullStringForKey:@"server_description"]; + if (![desc isEqualToString:@""]) args[argc++] = [[NSString stringWithFormat:@"-n%@", desc] UTF8String]; + + NSString *pass = [[NSUserDefaults standardUserDefaults] nonNullStringForKey:@"server_password"]; + if (![pass isEqualToString:@""]) args[argc++] = [[NSString stringWithFormat:@"-p%@", pass] UTF8String]; + + int clients = [[NSUserDefaults standardUserDefaults] integerForKey:@"server_maxclients"]; + if (clients > 0) args[argc++] = [[NSString stringWithFormat:@"-c%d", clients] UTF8String]; + + args[argc++] = NULL; + + switch ( (server = forkpty(&fdm, NULL, NULL, NULL)) ) // forkpty so we can reliably grab SDL console + { + case -1: + [console appendLine:@"Error - can't launch server"]; + [self serverTerminated]; + break; + case 0: // child + chdir(childCwd); + execv(childPath, (char*const*)args); + fprintf(stderr, "Error - can't launch server\n"); + _exit(0); + default: // parent + free(args); + //fprintf(stderr, "fdm=%d\n", slave_name, fdm); + [multiplayer setTitle:@"Stop"]; + + NSFileHandle *taskOutput = [[NSFileHandle alloc] initWithFileDescriptor:fdm]; + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc addObserver:self selector:@selector(serverDataAvailable:) name:NSFileHandleReadCompletionNotification object:taskOutput]; + [taskOutput readInBackgroundAndNotify]; + break; + } + } +} + +- (void)serverDataAvailable:(NSNotification *)note +{ + NSFileHandle *taskOutput = [note object]; + NSData *data = [[note userInfo] objectForKey:NSFileHandleNotificationDataItem]; - int h; - for (h = 0; h < [array count]; h++) - { - id haha = [resolutions itemWithTitle:[array objectAtIndex:h]]; - if (haha == nil) - [resolutions addItemWithTitle:[array objectAtIndex:h]]; - } + if (data && [data length]) + { + NSString *text = [[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding]; + [console appendText:text]; + [text release]; + [taskOutput readInBackgroundAndNotify]; //wait for more data + } + else + { + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + [nc removeObserver:self name:NSFileHandleReadCompletionNotification object:taskOutput]; + close([taskOutput fileDescriptor]); + [self setServerActive:NO]; + } +} + +- (BOOL)playFile +{ + NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; + + NSArray *res = [[resolutions titleOfSelectedItem] componentsSeparatedByString:@" x "]; + NSMutableArray *args = [[NSMutableArray alloc] init]; + NSString *cwd = [self cwd]; - [resolutions selectItemAtIndex: [[NSUserDefaults standardUserDefaults] integerForKey:@"resolution"]]; + //suppose could use this to update gamma and keys too, but can't be bothered... + [self updateAutoexecFile:[NSDictionary dictionaryWithObjectsAndKeys: + [defs nonNullStringForKey:@"name"], @"name", + [defs nonNullStringForKey:@"team"], @"team", + nil]]; + + [args addObject:[NSString stringWithFormat:@"-w%@", [res objectAtIndex:0]]]; + [args addObject:[NSString stringWithFormat:@"-h%@", [res objectAtIndex:1]]]; + [args addObject:@"-z32"]; + + if([defs integerForKey:@"fullscreen"] == 0) [args addObject:@"-t"]; + [args addObject:[NSString stringWithFormat:@"-a%d", [defs integerForKey:@"fsaa"]]]; + [args addObject:[NSString stringWithFormat:@"-f%d", [defs integerForKey:@"shader"]]]; + + NSString *adv = [defs nonNullStringForKey:@"advancedOptions"]; + if(![adv isEqual:@""]) [args addObjectsFromArray:[adv componentsSeparatedByString:@" "]]; + + NSTask *task = [[NSTask alloc] init]; + [task setCurrentDirectoryPath:cwd]; + [task setLaunchPath:[cwd stringByAppendingPathComponent:@"actioncube.app/Contents/MacOS/actioncube"]]; + [task setArguments:args]; + [task setEnvironment:[NSDictionary dictionaryWithObjectsAndKeys: + @"1", @"SDL_SINGLEDISPLAY", + @"1", @"SDL_ENABLEAPPEVENTS", nil + ]]; // makes Command-H, Command-M and Command-Q work at least when not in fullscreen + [args release]; + + BOOL okay = YES; + + NS_DURING + [task launch]; + if(server==-1) [NSApp terminate:self]; //if there is a server then don't exit! + NS_HANDLER + //NSLog(@"%@", localException); + NSBeginCriticalAlertSheet( + @"Can't start AssaultCube", nil, nil, nil, + window, nil, nil, nil, nil, + @"Please move the directory containing AssaultCube to a path that doesn't contain weird characters or start AssaultCube manually."); + okay = NO; + NS_ENDHANDLER + + return okay; +} + +- (void)awakeFromNib +{ + [self initViews]; + + NSDictionary *dict = [self readConfigFiles]; + [keys addObjects:[self getKeys:dict]]; + NSUserDefaults *defs = [NSUserDefaults standardUserDefaults]; + if([[defs nonNullStringForKey:@"name"] isEqual:@""]) + { + NSString *name = [dict objectForKey:@"name"]; + if([name isEqual:@""] || [name isEqual:@"unnamed"]) name = NSUserName(); + [defs setValue:name forKey:@"name"]; + } + if([[defs nonNullStringForKey:@"team"] isEqual:@""]) [defs setValue:[dict objectForKey:@"team"] forKey:@"team"]; + + [self initResolutions]; + server = -1; + [window setDelegate:self]; // so can catch the window close + [NSApp setDelegate:self]; //so can catch the double-click & dropped files +} + +-(void)windowWillClose:(NSNotification *)notification +{ + [self setServerActive:NO]; + [NSApp terminate:self]; +} + +/* + * Interface actions + */ +- (IBAction)multiplayerAction:(id)sender +{ + [window makeFirstResponder:window]; //ensure fields are exited and committed + [self setServerActive:(server==-1)]; +} + +- (IBAction)playAction:(id)sender +{ + [window makeFirstResponder:window]; //ensure fields are exited and committed + [self playFile]; +} + +- (IBAction)helpAction:(id)sender +{ + NSString *file = [[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByAppendingPathComponent:@"ReadMe.html"]; + [[NSWorkspace sharedWorkspace] openURL:[NSURL fileURLWithPath:file]]; } @end \ No newline at end of file diff --git a/source/xcode/Main.gif b/source/xcode/Main.gif new file mode 100644 index 0000000000000000000000000000000000000000..fb54c3713fa31de73b1e54755718d221289e198f GIT binary patch literal 1629 zcmV-j2BP^#Nk%w1VL$*t0M!5h00030|NrG36!>QpxUQxC@8nZHFq46F`D_#UY7_Zv z6#kP@xNAJlmUMVtP5562_+$?FW)lBv6#r}#`DqmRY8u2=75Z=?`E@DzdouZfJ^G1A z`j1lQgiGLtQTmo%`lx&Sw2b_}oBYSA{nNYt;n0RU6#AWP_FWb9R~GI+6!Ky`^|YpB z9TVv*7wk(n?`c`+G9>0973Cil;|>Sp6Aa`R59JyX@f{TH9Tesr6y+NfK%Iyjr zjF31a5;eBobQ0k3V6oz|Xw+~3)cBv_aQcA$aB*cLglBnN1}1$cAdG-q?o{w<3NuE4ILxskx8w!SG^g+Xb2w)#na6!X{;Ttbb zq)e)G=?Mi7Cd3`m0*8PdKBj8K`c50d4;=hL01P3+1`!}&yr^MAK#dt@nVC}CxI_pH z4zlfD6E>peMjY_~|mX?s6cTDbV2!O@RtD+(7k*R--5*ff0D^FVt;U3c&*!z`#RcRhxYz zU;|vBZw)K6ec+$FE)W7gEWqGG4bi$-x7`rX*bxS7^6I#mtlkg<3ob210t~LTM&9Os zb&f$^5MnU@!3Djh8nnO)@|zex`mg{UYnavzSOuNYp0fl4fE{*BkbgNO4KJ`zPDCTX zAl9)cAddCOBts}+?vwV->UfwBH5)S_d=TAo8^rR;Pq^PrKE~(cH{E_LJ=q|Jqf`Hw01xYCNMlY z*kF@tu&EJ=FhZj-;hvHNfEnn3cPiYUp^_uRF-brI7J$l%mXw1Os!%~YxPj<;NT45D zpan{3fuC@gKOX47a6M$61?azTnZh+Y+8hd?cIkqT18K@k@? zGw1bsii{8tVj85F12tAnjCXY68}ksyIX0<|cP!%_Qegx%;^2!engJG3_Vl7ZF*Y0eJG0P6%ZV*a89I;07K`0P{?s$5~E6 bl{r8`8GGqVE`-toi!7!xm&r^g1OWg$)_T2V literal 0 HcmV?d00001 diff --git a/source/xcode/ReadMe.html b/source/xcode/ReadMe.html new file mode 100644 index 00000000..3cbe4a90 --- /dev/null +++ b/source/xcode/ReadMe.html @@ -0,0 +1,12 @@ + + + +AssaultCube Documentation + + + +

AssaultCube Documentation

+Click here. + diff --git a/source/xcode/SDLMain.m b/source/xcode/SDLMain.m index 28ecce8e..1520dbff 100644 --- a/source/xcode/SDLMain.m +++ b/source/xcode/SDLMain.m @@ -10,24 +10,58 @@ #import /* for MAXPATHLEN */ #import +/* For some reaon, Apple removed setAppleMenu from the headers in 10.4, + but the method still is there and works. To avoid warnings, we declare + it ourselves here. */ +@interface NSApplication(SDL_Missing_Methods) +- (void)setAppleMenu:(NSMenu *)menu; +@end + /* Use this flag to determine whether we use SDLMain.nib or not */ #define SDL_USE_NIB_FILE 0 +/* Use this flag to determine whether we use CPS (docking) or not */ +#define SDL_USE_CPS 1 +#ifdef SDL_USE_CPS +/* Portions of CPS.h */ +typedef struct CPSProcessSerNum +{ + UInt32 lo; + UInt32 hi; +} CPSProcessSerNum; + +extern OSErr CPSGetCurrentProcess( CPSProcessSerNum *psn); +extern OSErr CPSEnableForegroundOperation( CPSProcessSerNum *psn, UInt32 _arg2, UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); +extern OSErr CPSSetFrontProcess( CPSProcessSerNum *psn); + +#endif /* SDL_USE_CPS */ static int gArgc; static char **gArgv; static BOOL gFinderLaunch; +static BOOL gCalledAppMainline = FALSE; + +static NSString *getApplicationName(void) +{ + NSDictionary *dict; + NSString *appName = 0; + + /* Determine the application name */ + dict = (NSDictionary *)CFBundleGetInfoDictionary(CFBundleGetMainBundle()); + if (dict) + appName = [dict objectForKey: @"CFBundleName"]; + + if (![appName length]) + appName = [[NSProcessInfo processInfo] processName]; + + return appName; +} #if SDL_USE_NIB_FILE /* A helper category for NSString */ @interface NSString (ReplaceSubString) - (NSString *)stringByReplacingRange:(NSRange)aRange with:(NSString *)aString; @end -#else -/* An internal Apple class used to setup Apple menus */ -@interface NSAppleMenuController:NSObject {} -- (void)controlMenu:(NSMenu *)aMenu; -@end #endif @interface SDLApplication : NSApplication @@ -42,8 +76,17 @@ static BOOL gFinderLaunch; event.type = SDL_QUIT; SDL_PushEvent(&event); } -@end +// ADDED SO IT DOESN'T BEEP BECAUSE WE ENABLE SDL_ENABLEAPPEVENTS +- (void)sendEvent:(NSEvent *)anEvent +{ + if( NSKeyDown == [anEvent type] || NSKeyUp == [anEvent type] ) { + if( [anEvent modifierFlags] & NSCommandKeyMask ) + [super sendEvent: anEvent]; + } else + [super sendEvent: anEvent]; +} +@end /* The main class of the application, the application's delegate */ @implementation SDLMain @@ -51,25 +94,18 @@ static BOOL gFinderLaunch; /* Set the working directory to the .app's parent directory */ - (void) setupWorkingDirectory:(BOOL)shouldChdir { - char parentdir[MAXPATHLEN]; - char *c; - - strncpy ( parentdir, gArgv[0], sizeof(parentdir) ); - c = (char*) parentdir; - - while (*c != '\0') /* go to end */ - c++; - - while (*c != '/') /* back up to parent */ - c--; - - *c++ = '\0'; /* cut off last part (binary name) */ - if (shouldChdir) { - assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ - assert ( chdir ("../../../") == 0 ); /* chdir to the .app's parent */ - } + char parentdir[MAXPATHLEN]; + CFURLRef url = CFBundleCopyBundleURL(CFBundleGetMainBundle()); + CFURLRef url2 = CFURLCreateCopyDeletingLastPathComponent(0, url); + if (CFURLGetFileSystemRepresentation(url2, true, (UInt8 *)parentdir, MAXPATHLEN)) { + assert ( chdir (parentdir) == 0 ); /* chdir to the binary app's parent */ + } + CFRelease(url); + CFRelease(url2); + } + } #if SDL_USE_NIB_FILE @@ -99,38 +135,56 @@ static BOOL gFinderLaunch; #else -void setupAppleMenu(void) +static void setApplicationMenu(void) { /* warning: this code is very odd */ - NSAppleMenuController *appleMenuController; NSMenu *appleMenu; - NSMenuItem *appleMenuItem; - - appleMenuController = [[NSAppleMenuController alloc] init]; - appleMenu = [[NSMenu alloc] initWithTitle:@""]; - appleMenuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; + NSMenuItem *menuItem; + NSString *title; + NSString *appName; - [appleMenuItem setSubmenu:appleMenu]; + appName = getApplicationName(); + appleMenu = [[NSMenu alloc] initWithTitle:@""]; + + /* Add menu items */ + title = [@"About " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; - /* yes, we do need to add it and then remove it -- - if you don't add it, it doesn't get displayed - if you don't remove it, you have an extra, titleless item in the menubar - when you remove it, it appears to stick around - very, very odd */ - [[NSApp mainMenu] addItem:appleMenuItem]; - [appleMenuController controlMenu:appleMenu]; - [[NSApp mainMenu] removeItem:appleMenuItem]; + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Hide " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(hide:) keyEquivalent:@"h"]; + + menuItem = (NSMenuItem *)[appleMenu addItemWithTitle:@"Hide Others" action:@selector(hideOtherApplications:) keyEquivalent:@"h"]; + [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)]; + + [appleMenu addItemWithTitle:@"Show All" action:@selector(unhideAllApplications:) keyEquivalent:@""]; + + [appleMenu addItem:[NSMenuItem separatorItem]]; + + title = [@"Quit " stringByAppendingString:appName]; + [appleMenu addItemWithTitle:title action:@selector(terminate:) keyEquivalent:@"q"]; + + + /* Put menu into the menubar */ + menuItem = [[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""]; + [menuItem setSubmenu:appleMenu]; + [[NSApp mainMenu] addItem:menuItem]; + + /* Tell the application object that this is now the application menu */ + [NSApp setAppleMenu:appleMenu]; + + /* Finally give up our references to the objects */ [appleMenu release]; - [appleMenuItem release]; + [menuItem release]; } /* Create a window menu */ -void setupWindowMenu(void) +static void setupWindowMenu(void) { - NSMenu *windowMenu; - NSMenuItem *windowMenuItem; - NSMenuItem *menuItem; - + NSMenu *windowMenu; + NSMenuItem *windowMenuItem; + NSMenuItem *menuItem; windowMenu = [[NSMenu alloc] initWithTitle:@"Window"]; @@ -153,7 +207,7 @@ void setupWindowMenu(void) } /* Replacement for NSApplicationMain */ -void CustomApplicationMain (argc, argv) +static void CustomApplicationMain (int argc, char **argv) { NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; SDLMain *sdlMain; @@ -161,11 +215,22 @@ void CustomApplicationMain (argc, argv) /* Ensure the application object is initialised */ [SDLApplication sharedApplication]; +#ifdef SDL_USE_CPS + { + CPSProcessSerNum PSN; + /* Tell the dock about us */ + if (!CPSGetCurrentProcess(&PSN)) + if (!CPSEnableForegroundOperation(&PSN,0x03,0x3C,0x2C,0x1103)) + if (!CPSSetFrontProcess(&PSN)) + [SDLApplication sharedApplication]; + } +#endif /* SDL_USE_CPS */ + /* Set up the menubar */ [NSApp setMainMenu:[[NSMenu alloc] init]]; - setupAppleMenu(); + setApplicationMenu(); setupWindowMenu(); - + /* Create SDLMain and make it the app delegate */ sdlMain = [[SDLMain alloc] init]; [NSApp setDelegate:sdlMain]; @@ -179,6 +244,56 @@ void CustomApplicationMain (argc, argv) #endif + +/* + * Catch document open requests...this lets us notice files when the app + * was launched by double-clicking a document, or when a document was + * dragged/dropped on the app's icon. You need to have a + * CFBundleDocumentsType section in your Info.plist to get this message, + * apparently. + * + * Files are added to gArgv, so to the app, they'll look like command line + * arguments. Previously, apps launched from the finder had nothing but + * an argv[0]. + * + * This message may be received multiple times to open several docs on launch. + * + * This message is ignored once the app's mainline has been called. + */ +- (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filename +{ + const char *temparg; + size_t arglen; + char *arg; + char **newargv; + + if (!gFinderLaunch) /* MacOS is passing command line args. */ + return FALSE; + + if (gCalledAppMainline) /* app has started, ignore this document. */ + return FALSE; + + temparg = [filename UTF8String]; + arglen = SDL_strlen(temparg) + 1; + arg = (char *) SDL_malloc(arglen); + if (arg == NULL) + return FALSE; + + newargv = (char **) realloc(gArgv, sizeof (char *) * (gArgc + 2)); + if (newargv == NULL) + { + SDL_free(arg); + return FALSE; + } + gArgv = newargv; + + SDL_strlcpy(arg, temparg, arglen); + gArgv[gArgc++] = arg; + gArgv[gArgc] = NULL; + return TRUE; +} + + /* Called when the internal event loop has just started running */ - (void) applicationDidFinishLaunching: (NSNotification *) note { @@ -189,10 +304,11 @@ void CustomApplicationMain (argc, argv) #if SDL_USE_NIB_FILE /* Set the main menu to contain the real app name instead of "SDL App" */ - [self fixMenu:[NSApp mainMenu] withAppName:[[NSProcessInfo processInfo] processName]]; + [self fixMenu:[NSApp mainMenu] withAppName:getApplicationName()]; #endif /* Hand off to main application code */ + gCalledAppMainline = TRUE; status = SDL_main (gArgc, gArgv); /* We're done, thank you for playing */ @@ -250,23 +366,22 @@ void CustomApplicationMain (argc, argv) /* Main entry point to executable - should *not* be SDL_main! */ int main (int argc, char **argv) { - /* Copy the arguments into a global variable */ - int i; - /* This is passed if we are launched by double-clicking */ if ( argc >= 2 && strncmp (argv[1], "-psn", 4) == 0 ) { + gArgv = (char **) SDL_malloc(sizeof (char *) * 2); + gArgv[0] = argv[0]; + gArgv[1] = NULL; gArgc = 1; - gFinderLaunch = YES; + gFinderLaunch = YES; } else { + int i; gArgc = argc; - gFinderLaunch = NO; + gArgv = (char **) SDL_malloc(sizeof (char *) * (argc+1)); + for (i = 0; i <= argc; i++) + gArgv[i] = argv[i]; + gFinderLaunch = NO; } - gArgv = (char**) malloc (sizeof(*gArgv) * (gArgc+1)); - assert (gArgv != NULL); - for (i = 0; i < gArgc; i++) - gArgv[i] = argv[i]; - gArgv[i] = NULL; #if SDL_USE_NIB_FILE [SDLApplication poseAsClass:[NSApplication class]]; diff --git a/source/xcode/Server.gif b/source/xcode/Server.gif new file mode 100644 index 0000000000000000000000000000000000000000..60a7b3b0a8c6470ddbd4b3516399cbb36e95c96e GIT binary patch literal 2344 zcmV+@3D@>VNk%w1VL$*t0M!5h00030|Ns3`0OtSzARr-^mzk`rt)!);Yinv^Vqvtj zvy6<3uYV?vXCt7Mfx?I@cUdZ6N+yYKL!F6eYF$XYx38gZC6jzvdumWYJ2H@kbWu-C zu&kzdc5|+LH=dc2tD~8Nf`Qc2(!ajF(ThmWrGWqE)Bf4M&B?}~N)`OVp8c+Y&sG@x zmSpu-4gGE^{DDdMJp!036!9ei$shyrL@VnO1nLO`?*IVQ0s`wH9g>le?(Xj0-QAv^ zp8x;m+3!l3Q7!=q=2@YvI0c-sM z|N6BN_~%Uz4i`Ec;Lr|5C2uGebVxuEfxRRYE`V4@2}K1%C{CPnSRoRKbSFB1fAmSMG%f2z<0VFot4+5Q0HrNN_O;h6RX0AU&|7gIWdb+KJG^dMVrs z7bM`OkU;Z@v=b|W1~u60y&|X%d}#XtL5KoX4#aj?j*kKixOL~&{S`q61>+WM5KeqB zX#z@6IqM*ii-VNJ9PEf+0z`@X74DOmK%&0~54c_6fp!w;_SArbQLs~b7dW$lbGMLC z0!Zb|W{yAp5M)9Rg`lAS0!V70Pyz!Dgiz0d7-8^%1LNfsLVx$gDC2z}if}>?BF(14 zBs0cHf(j*&@PGv#ba3JlQa$4tJrDH9f(I5bzyJ#mP&uWHB-Fs)3okVJz?WY#0A`pC zNT2})r6sY!X)N+Zj|UP$X~CRRKH$NZLH2h+3nah^!vkH4`GAyyHc6rcCZ>r*1ZJ{W zQ37|8z`&eQ5_;!<5|Gfs3M;6v0tpw4DW;TT4%$FM7(jp`5*eVPL5mbc`alDdGT?!& zgR-D$3%qWs!mk_zdFPp)NM{e=IYI(@kSg^Bh*l5KqWoN7 zgD#f;E_g@W9|h-R#wYRsJY*=s4p2Y=2n-Md5IXf~UfQR6|h1s|uk59LkIpw(wAIM znY9?q>8@uT83xqa4(RZp1FZ6k4-^uU0!Rb`cKuIS|I+}YrjP|GFe_jw3xN*EgdL0h zBUp|=fU7K2A=~VL$TkaD2*`j2nPu%=NrnLED4+lc;7|zMI)n`@00lhIMQRtxRJ)$k zPG>zSQzg*U1}x9BtVw_%#IuA?0Cxci;6eyUMgUcO2sLk48x9X|rb8ac5GkGU{Udd6cE6u}E07K;GZ z95@LX0F5Y~lb6421l^~launcher CFBundleIconFile actioncube + CFBundleIdentifier + assaultcube CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType diff --git a/source/xcode/macutils.mm b/source/xcode/macutils.mm new file mode 100644 index 00000000..75a10b0d --- /dev/null +++ b/source/xcode/macutils.mm @@ -0,0 +1,16 @@ +#import + +#define _MAXDEFSTR 260 +inline char *s_strncpy(char *d, const char *s, size_t m) { strncpy(d,s,m); d[m-1] = 0; return d; }; +inline char *s_strcat(char *d, const char *s) { size_t n = strlen(d); return s_strncpy(d+n,s,_MAXDEFSTR-n); }; + +void mac_pasteconsole(char *commandbuf) +{ + NSPasteboard *pasteboard = [NSPasteboard generalPasteboard]; + NSString *type = [pasteboard availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]]; + if (type != nil) { + NSString *contents = [pasteboard stringForType:type]; + if (contents != nil) + s_strcat(commandbuf, [contents lossyCString]); + } +} \ No newline at end of file diff --git a/source/xcode/main.m b/source/xcode/main.m index 6443a6d2..05e5b6c7 100644 --- a/source/xcode/main.m +++ b/source/xcode/main.m @@ -1,11 +1,3 @@ -// -// main.m -// Play Cube -// -// Created by Julian Mayer on 31.08.05. -// Copyright __MyCompanyName__ 2005. All rights reserved. -// - #import int main(int argc, char *argv[])