2 // **********************************************************************
3 // The Cheat - A universal game cheater for Mac OS X
4 // (C) 2003-2005 Chaz McGarvey (BrokenZipper)
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 1, or (at your option)
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 #import "AppController.h"
23 #import "CheatDocument.h"
24 #import "AboutBoxController.h"
25 #import "HelpController.h"
26 #import "PreferenceController.h"
28 @implementation AppController
31 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
32 #pragma mark Initialization
33 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
38 NSMutableDictionary
*defaults
= [NSMutableDictionary dictionary
];
40 TCFirstLaunchPref
= [[NSString stringWithFormat
:@
"TC%@%@Pref", ChazAppName(), ChazAppVersion()] retain
];
41 NSString
*broadcastName
= [NSString stringWithFormat
:@
"%@'s Computer", NSFullUserName()];
43 // register user defaults
44 [defaults setObject
:[NSNumber numberWithBool
:NO
] forKey
:TCFirstLaunchPref
];
45 [defaults setObject
:[NSNumber numberWithBool
:NO
] forKey
:TCWindowsOnTopPref
];
46 [defaults setObject
:[NSNumber numberWithBool
:YES
] forKey
:TCUpdateCheckPref
];
47 [defaults setObject
:[NSNumber numberWithBool
:YES
] forKey
:TCDisplayValuesPref
];
48 [defaults setObject
:[NSNumber numberWithFloat
:1.0] forKey
:TCValueUpdatePref
];
49 [defaults setObject
:[NSNumber numberWithInt
:1000] forKey
:TCHitsDisplayedPref
];
50 [defaults setObject
:[NSNumber numberWithBool
:NO
] forKey
:TCRunServerPref
];
51 [defaults setObject
:broadcastName forKey
:TCBroadcastNamePref
];
52 [defaults setObject
:[NSNumber numberWithInt
:TCDefaultListenPort
] forKey
:TCListenPortPref
];
53 [defaults setObject
:[NSNumber numberWithFloat
:gFadeAnimationDuration
] forKey
:TCFadeAnimationPref
];
54 [defaults setObject
:[NSNumber numberWithBool
:YES
] forKey
:TCAskForSavePref
];
55 [defaults setObject
:[NSNumber numberWithBool
:YES
] forKey
:TCSwitchVariablesPref
];
56 [defaults setObject
:[NSNumber numberWithBool
:YES
] forKey
:TCAutoStartEditingVarsPref
];
59 [[NSUserDefaults standardUserDefaults
] registerDefaults
:defaults
];
62 gFadeAnimationDuration
= [[NSUserDefaults standardUserDefaults
] floatForKey
:TCFadeAnimationPref
];
67 if ( self = [super init
] ) {
68 [self setDelegate
:self];
77 ChazLog( @
"AppController deallocated!!" );
78 [self stopCheatServer
];
82 // http://vgable.com/blog/2008/10/05/restarting-your-cocoa-application/
83 - (void)restartOurselves
85 NSString
*killArg1AndOpenArg2Script
= @
"kill -9 $1 \n open \"$2\"";
86 NSString
*ourPID
= [NSString stringWithFormat
:@
"%d", [[NSProcessInfo processInfo
] processIdentifier
]];
87 NSString
*pathToUs
= [[NSBundle mainBundle
] bundlePath
];
89 NSArray
*shArgs
= [NSArray arrayWithObjects
:@
"-c", killArg1AndOpenArg2Script
, @
"", ourPID
, pathToUs
, nil];
90 NSTask
*restartTask
= [NSTask launchedTaskWithLaunchPath
:@
"/bin/sh" arguments
:shArgs
];
91 [restartTask waitUntilExit
];
92 NSLog(@
"*** ERROR: %@ should have been terminated, but we are still running", pathToUs
);
93 assert(!"We should not be running!");
96 - (BOOL) checkExecutablePermissions
{
97 NSDictionary
*applicationAttributes
= [[NSFileManager defaultManager
] fileAttributesAtPath
:[[NSBundle mainBundle
] executablePath
] traverseLink
: YES
];
99 // We expect 2755 as octal (1517 as decimal, -rwxr-sr-x as extended notation)
100 return ([applicationAttributes filePosixPermissions
] == 1517 && [[applicationAttributes fileGroupOwnerAccountName
] isEqualToString
: @
"procmod"]);
103 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
104 #pragma mark NSApplication Delegate
105 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
107 - (void)applicationDidFinishLaunching
:(NSNotification
*)aNotification
109 [NSApp activateIgnoringOtherApps
:YES
];
111 // check if this is the first launch
112 if ( ![[NSUserDefaults standardUserDefaults
] boolForKey
:TCFirstLaunchPref
] ) {
114 [self showAboutBoxWindow
:self];
115 [[NSUserDefaults standardUserDefaults
] setBool
:YES forKey
:TCFirstLaunchPref
];
118 // if should check for updates on launch
119 if ( [[NSUserDefaults standardUserDefaults
] boolForKey
:TCUpdateCheckPref
] ) {
120 ChazCheckForUpdate( TCUpdateCheckURL
, NO
);
123 // automatically start the cheat server if the pref is set
124 if ( [[NSUserDefaults standardUserDefaults
] boolForKey
:TCRunServerPref
] ) {
125 if ( ![self startCheatServer
] ) {
126 // inform the user that the server won't start
127 NSRunAlertPanel( @
"The Cheat could not start the server.",
128 @
"The cheat server failed to start. Check the server settings and start it manually.",
131 [self showPreferenceWindow
:self];
132 [_preferenceController chooseServer
:self];
138 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
139 #pragma mark Interface Actions
140 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
143 - (IBAction
)newSearchWindow
:(id)sender
145 NSDocumentController
*controller
= [NSDocumentController sharedDocumentController
];
146 CheatDocument
*doc
= [controller makeUntitledDocumentOfType
:@
"Cheat Document"];
148 ChazLog( @
"nil document" );
150 [doc setMode
:TCSearchMode
];
151 [controller addDocument
:doc
];
152 [doc makeWindowControllers
];
156 - (IBAction
)newBlankCheatWindow
:(id)sender
158 NSDocumentController
*controller
= [NSDocumentController sharedDocumentController
];
159 CheatDocument
*doc
= [controller makeUntitledDocumentOfType
:@
"Cheat Document"];
161 ChazLog( @
"nil document" );
163 [doc setMode
:TCCheatMode
];
164 [controller addDocument
:doc
];
165 [doc makeWindowControllers
];
169 - (IBAction
)showAboutBoxWindow
:(id)sender
171 if ( !_aboutBoxController
) {
172 _aboutBoxController
= [[AboutBoxController alloc
] init
];
174 [_aboutBoxController showWindow
:self];
177 - (IBAction
)showPreferenceWindow
:(id)sender
179 if ( !_preferenceController
) {
180 _preferenceController
= [[PreferenceController alloc
] init
];
182 [_preferenceController showWindow
:self];
186 - (IBAction
)launchHelpFile
:(id)sender
188 if ( !_helpController
) {
189 _helpController
= [[HelpController alloc
] init
];
191 [_helpController showWindow
:self];
194 - (IBAction
)launchEmailMenu
:(id)sender
199 - (IBAction
)launchWebsiteMenu
:(id)sender
205 - (IBAction
)checkForUpdate
:(id)sender
207 ChazCheckForUpdate( TCUpdateCheckURL
, YES
);
211 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
212 #pragma mark CheatServer Stuff
213 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
215 - (CheatServer
*)cheatServer
218 _server
= [[CheatServer alloc
] initWithDelegate
:self];
223 - (BOOL)startCheatServer
225 ChazLog( @
"cheat server starting..." );
227 // start the server with saved settings
228 int port
= [[NSUserDefaults standardUserDefaults
] integerForKey
:TCListenPortPref
];
229 NSString
*name
= [[NSUserDefaults standardUserDefaults
] objectForKey
:TCBroadcastNamePref
];
230 if ( [name isEqualToString
:@
""] ) {
234 // stop the cheat server if it's running
235 [self stopCheatServer
];
238 if ( [[self cheatServer
] listenOnPort
:port broadcast
:name
] ) {
239 [[NSNotificationCenter defaultCenter
] postNotificationName
:TCServerStartedNote object
:[self cheatServer
]];
245 - (void)stopCheatServer
249 [[NSNotificationCenter defaultCenter
] postNotificationName
:TCServerStoppedNote object
:[self cheatServer
]];
254 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
255 #pragma mark CheatServerDelegate
256 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
258 - (void)serverDisconnectedUnexpectedly
:(CheatServer
*)theServer
260 ChazLog( @
"server disconnected unexpectedly." );
261 [self stopCheatServer
];
264 - (void)server
:(CheatServer
*)theServer failedToBroadcastName
:(NSString
*)theName
266 NSBeginInformationalAlertSheet( @
"The cheat server can not broadcast.", @
"OK", nil, nil, [_preferenceController window
], nil, NULL
, NULL
, NULL
,
267 @
"The Cheat can't broadcast as \"%@\" because that name is in use by another server. The server will continue running with broadcasting disabled.", theName
);
270 - (void)serverChildrenChanged
:(CheatServer
*)theServer
272 [[NSNotificationCenter defaultCenter
] postNotificationName
:TCServerConnectionsChangedNote object
:theServer
];