2 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6 // Created: Sun Sep 07 2003
8 // Copyright: 2003 Chaz McGarvey. All rights reserved.
9 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
11 #import "MyDocument.h"
13 #import "CheatClient.h"
17 void TCPlaySound( NSString
*name
);
20 @implementation MyDocument
24 if ( self = [super init
] )
26 NSNotificationCenter
*nc
= [NSNotificationCenter defaultCenter
];
30 serverList
= [[NSMutableArray alloc
] init
];
31 addressList
= [[NSMutableArray alloc
] init
];
33 // set up the network browser
34 browser
= [[NSNetServiceBrowser alloc
] init
];
35 [browser setDelegate
:self];
36 [browser searchForServicesOfType
:@
"_cheat._tcp." inDomain
:@
"local."];
38 // notifications to receive
39 [nc addObserver
:self selector
:@selector(listenerStarted
:) name
:@
"TCListenerStarted" object
:nil];
40 [nc addObserver
:self selector
:@selector(listenerStopped
:) name
:@
"TCListenerStopped" object
:nil];
41 [nc addObserver
:self selector
:@selector(windowsOnTopChanged
:) name
:@
"TCWindowsOnTopChanged" object
:nil];
43 [self connectToLocal
];
49 - (NSString
*)windowNibName
54 - (NSString
*)displayName
56 return [NSString stringWithFormat
:@
"The Cheat %i", TCGlobalDocumentCount
++];
59 - (void)windowControllerDidLoadNib
:(NSWindowController
*)controller
61 [super windowControllerDidLoadNib
:controller
];
63 [self initialInterfaceSetup
];
69 // closing the window will automatically disconnect the client from the server,
70 // but if the application is quitting, the client may not get a chance to exit.
71 // this _should_ be OK.
74 // clean up status timer stuff.
75 // we do this here because we don't want the timer to fire after the window is gone
76 // since we need to use the window in that method.
77 [savedStatusColor release
], savedStatusColor
= nil;
78 [savedStatusText release
], savedStatusText
= nil;
79 [statusTextTimer invalidate
];
80 [statusTextTimer release
], statusTextTimer
= nil;
86 - (void)initialInterfaceSetup
88 NSString
*localName
= @
"Local"; //[NSString stringWithFormat:@"%@ (local)", TCGlobalBroadcastName];
90 // misc window settings
91 [cheatWindow useOptimizedDrawing
:YES
];
92 [cheatWindow setFrameAutosaveName
:@
"TCCheatWindow"];
95 if ( TCGlobalWindowsOnTop
)
97 [cheatWindow setLevel
:NSPopUpMenuWindowLevel
];
100 // set up the server menu default items
101 [serverMenu removeAllItems
];
102 [serverMenu addItemWithTitle
:@
"Not Connected" action
:@selector(serverMenuDisconnect
:) keyEquivalent
:@
""];
103 [serverMenu addItemWithTitle
:localName action
:@selector(serverMenuLocal
:) keyEquivalent
:@
""];
104 [processMenu removeAllItems
];
106 // give tags to the menu items.
107 [[typeMenu itemWithTitle
:@
"Integer"] setTag
:TYPE_INTEGER
];
108 [[typeMenu itemWithTitle
:@
"String"] setTag
:TYPE_STRING
];
109 [[typeMenu itemWithTitle
:@
"Decimal"] setTag
:TYPE_DECIMAL
];
110 [[typeMenu itemWithTitle
:@
"Unknown Value"] setTag
:TYPE_UNKNOWN
];
111 [[stringSizeMenu itemWithTitle
:@
"8-bit"] setTag
:SIZE_8_BIT
];
112 [[integerSizeMenu itemWithTitle
:@
"char"] setTag
:SIZE_8_BIT
];
113 [[integerSizeMenu itemWithTitle
:@
"short"] setTag
:SIZE_16_BIT
];
114 [[integerSizeMenu itemWithTitle
:@
"long"] setTag
:SIZE_32_BIT
];
115 [[decimalSizeMenu itemWithTitle
:@
"float"] setTag
:SIZE_32_BIT
];
116 [[decimalSizeMenu itemWithTitle
:@
"double"] setTag
:SIZE_64_BIT
];
119 [statusText setStringValue
:@
""];
120 [self setStatusDisconnected
];
122 // change sheet initial interface.
123 [changeSecondsCombo setEnabled
:NO
];
126 - (void)updateSearchButton
128 TCtype type
= [typePopup indexOfSelectedItem
];
130 if ( type
!= TYPE_UNKNOWN
)
132 if ( [[searchTextField stringValue
] isEqualToString
:@
""] )
134 [searchButton setEnabled
:NO
];
138 [searchButton setEnabled
:YES
];
143 [searchButton setEnabled
:YES
];
147 - (void)updatePauseButton
151 [pauseButton setTitle
:@
"Pause Target"];
155 [pauseButton setTitle
:@
"Resume Target"];
159 - (void)updateSearchBoxes
161 TCtype type
= [typePopup indexOfSelectedItem
];
163 if ( type
!= TYPE_UNKNOWN
)
165 [searchTextField setEnabled
:YES
];
166 [searchRadioMatrix setEnabled
:NO
];
170 [searchTextField setEnabled
:NO
];
171 [searchRadioMatrix setEnabled
:YES
];
175 - (void)updateChangeButton
177 if ( addressSelected
)
179 [changeButton setEnabled
:YES
];
183 [changeButton setEnabled
:NO
];
188 - (void)setStatusDisconnected
191 status
= STATUS_DISCONNECTED
;
193 [serverPopup setEnabled
:YES
];
194 [pauseButton setTitle
:@
"Pause Target"];
195 [pauseButton setEnabled
:NO
];
196 [processPopup setEnabled
:NO
];
197 [typePopup setEnabled
:NO
];
198 [sizePopup setEnabled
:NO
];
199 [searchTextField setEnabled
:NO
];
200 [searchRadioMatrix setEnabled
:NO
];
201 [searchButton setEnabled
:NO
];
202 [clearSearchButton setEnabled
:NO
];
203 [self setStatusText
:@
"Not Connected" duration
:0];
204 [statusBar stopAnimation
:self];
205 [addressTable setEnabled
:NO
];
206 [changeButton setTitle
:@
"ChangeĆ"];
207 [changeButton setEnabled
:NO
];
209 [[serverMenu itemAtIndex
:0] setTitle
:@
"Not Connected"];
212 - (void)setStatusConnected
215 status
= STATUS_CONNECTED
;
217 [serverPopup setEnabled
:YES
];
218 [self updatePauseButton
];
219 [pauseButton setEnabled
:YES
];
220 [processPopup setEnabled
:YES
];
221 [typePopup setEnabled
:YES
];
222 [sizePopup setEnabled
:YES
];
223 [self updateSearchBoxes
];
224 [self updateSearchButton
];
225 [clearSearchButton setEnabled
:NO
];
226 [self setStatusText
:@
"Connected" duration
:0];
227 [statusBar stopAnimation
:self];
228 [addressTable setEnabled
:NO
];
229 [changeButton setTitle
:@
"ChangeĆ"];
230 [changeButton setEnabled
:NO
];
232 [[serverMenu itemAtIndex
:0] setTitle
:@
"Disconnect"];
235 - (void)setStatusCheating
238 status
= STATUS_CHEATING
;
240 [serverPopup setEnabled
:YES
];
241 [self updatePauseButton
];
242 [pauseButton setEnabled
:YES
];
243 [processPopup setEnabled
:NO
];
244 [typePopup setEnabled
:NO
];
245 [sizePopup setEnabled
:NO
];
246 [self updateSearchBoxes
];
247 [self updateSearchButton
];
248 [clearSearchButton setEnabled
:YES
];
249 if ( searchResultsAmount
< TCMaxSearchResults
)
251 if ( searchResultsAmount
== 1 )
253 [self setStatusText
:[NSString stringWithFormat
:@
"Results: %i", searchResultsAmount
] duration
:0 color
:[NSColor colorWithCalibratedRed
:0.0f green
:0.5f blue
:0.0f alpha
:1.0f
]];
255 else if ( searchResultsAmount
== 0 )
257 [self setStatusText
:[NSString stringWithFormat
:@
"Results: %i", searchResultsAmount
] duration
:0 color
:[NSColor colorWithCalibratedRed
:0.5f green
:0.0f blue
:0.0f alpha
:1.0f
]];
261 [self setStatusText
:[NSString stringWithFormat
:@
"Results: %i", searchResultsAmount
] duration
:0];
266 [self setStatusText
:[NSString stringWithFormat
:@
"Results: >%i", TCMaxSearchResults
] duration
:0];
268 [statusBar stopAnimation
:self];
269 [addressTable setEnabled
:YES
];
270 [changeButton setTitle
:@
"ChangeĆ"];
271 [self updateChangeButton
];
273 [[serverMenu itemAtIndex
:0] setTitle
:@
"Disconnect"];
276 - (void)setStatusSearching
279 status
= STATUS_SEARCHING
;
281 [serverPopup setEnabled
:NO
];
282 [self updatePauseButton
];
283 [pauseButton setEnabled
:NO
];
284 [processPopup setEnabled
:NO
];
285 [typePopup setEnabled
:NO
];
286 [sizePopup setEnabled
:NO
];
287 [searchTextField setEnabled
:NO
];
288 [searchRadioMatrix setEnabled
:NO
];
289 [searchButton setEnabled
:NO
];
290 [clearSearchButton setEnabled
:NO
];
291 [self setStatusText
:@
"SearchingĆ" duration
:0];
292 [statusBar startAnimation
:self];
293 [addressTable setEnabled
:NO
];
294 [changeButton setTitle
:@
"ChangeĆ"];
295 [changeButton setEnabled
:NO
];
297 [[serverMenu itemAtIndex
:0] setTitle
:@
"Disconnect"];
300 - (void)setStatusChanging
303 status
= STATUS_CHANGING
;
305 [serverPopup setEnabled
:NO
];
306 [self updatePauseButton
];
307 [pauseButton setEnabled
:NO
];
308 [processPopup setEnabled
:NO
];
309 [typePopup setEnabled
:NO
];
310 [sizePopup setEnabled
:NO
];
311 [searchTextField setEnabled
:NO
];
312 [searchRadioMatrix setEnabled
:NO
];
313 [searchButton setEnabled
:NO
];
314 [clearSearchButton setEnabled
:NO
];
315 [self setStatusText
:@
"ChangingĆ" duration
:0];
316 [statusBar startAnimation
:self];
317 [addressTable setEnabled
:NO
];
318 [changeButton setEnabled
:NO
];
320 [[serverMenu itemAtIndex
:0] setTitle
:@
"Disconnect"];
323 - (void)setStatusChangingLater
326 status
= STATUS_CHANGING_LATER
;
328 [serverPopup setEnabled
:NO
];
329 [self updatePauseButton
];
330 [pauseButton setEnabled
:NO
];
331 [processPopup setEnabled
:NO
];
332 [typePopup setEnabled
:NO
];
333 [sizePopup setEnabled
:NO
];
334 [searchTextField setEnabled
:NO
];
335 [searchRadioMatrix setEnabled
:NO
];
336 [searchButton setEnabled
:NO
];
337 [clearSearchButton setEnabled
:NO
];
338 [self setStatusText
:@
"Changing LaterĆ" duration
:0];
339 [statusBar startAnimation
:self];
340 [addressTable setEnabled
:NO
];
341 [changeButton setTitle
:@
"Cancel Change"];
342 [changeButton setEnabled
:YES
];
344 [[serverMenu itemAtIndex
:0] setTitle
:@
"Disconnect"];
347 - (void)setStatusChangingContinuously
350 status
= STATUS_CHANGING_CONTINUOUSLY
;
352 [serverPopup setEnabled
:NO
];
353 [self updatePauseButton
];
354 [pauseButton setEnabled
:YES
];
355 [processPopup setEnabled
:NO
];
356 [typePopup setEnabled
:NO
];
357 [sizePopup setEnabled
:NO
];
358 [searchTextField setEnabled
:NO
];
359 [searchRadioMatrix setEnabled
:NO
];
360 [searchButton setEnabled
:NO
];
361 [clearSearchButton setEnabled
:NO
];
362 [self setStatusText
:@
"Repeated Change" duration
:0];
363 [statusBar startAnimation
:self];
364 [addressTable setEnabled
:NO
];
365 [changeButton setTitle
:@
"Stop Change"];
366 [changeButton setEnabled
:YES
];
368 [[serverMenu itemAtIndex
:0] setTitle
:@
"Disconnect"];
371 - (void)setStatusUndoing
374 status
= STATUS_UNDOING
;
376 [serverPopup setEnabled
:NO
];
377 [self updatePauseButton
];
378 [pauseButton setEnabled
:NO
];
379 [processPopup setEnabled
:NO
];
380 [typePopup setEnabled
:NO
];
381 [sizePopup setEnabled
:NO
];
382 [searchTextField setEnabled
:NO
];
383 [searchRadioMatrix setEnabled
:NO
];
384 [searchButton setEnabled
:NO
];
385 [clearSearchButton setEnabled
:NO
];
386 [self setStatusText
:@
"UndoingĆ" duration
:0];
387 [statusBar startAnimation
:self];
388 [addressTable setEnabled
:NO
];
389 [changeButton setTitle
:@
"ChangeĆ"];
390 [changeButton setEnabled
:NO
];
392 [[serverMenu itemAtIndex
:0] setTitle
:@
"Disconnect"];
395 - (void)setStatusRedoing
398 status
= STATUS_REDOING
;
400 [serverPopup setEnabled
:NO
];
401 [self updatePauseButton
];
402 [pauseButton setEnabled
:NO
];
403 [processPopup setEnabled
:NO
];
404 [typePopup setEnabled
:NO
];
405 [sizePopup setEnabled
:NO
];
406 [searchTextField setEnabled
:NO
];
407 [searchRadioMatrix setEnabled
:NO
];
408 [searchButton setEnabled
:NO
];
409 [clearSearchButton setEnabled
:NO
];
410 [self setStatusText
:@
"RedoingĆ" duration
:0];
411 [statusBar startAnimation
:self];
412 [addressTable setEnabled
:NO
];
413 [changeButton setTitle
:@
"ChangeĆ"];
414 [changeButton setEnabled
:NO
];
416 [[serverMenu itemAtIndex
:0] setTitle
:@
"Disconnect"];
419 - (void)setStatusToLast
421 switch ( lastStatus
)
423 case STATUS_DISCONNECTED
:
424 [self setStatusDisconnected
];
427 case STATUS_CONNECTED
:
428 [self setStatusConnected
];
431 case STATUS_CHEATING
:
432 [self setStatusCheating
];
435 case STATUS_SEARCHING
:
436 [self setStatusSearching
];
439 case STATUS_CHANGING
:
440 [self setStatusChanging
];
443 case STATUS_CHANGING_LATER
:
444 [self setStatusChangingLater
];
447 case STATUS_CHANGING_CONTINUOUSLY
:
448 [self setStatusChangingContinuously
];
452 [self setStatusUndoing
];
456 [self setStatusRedoing
];
461 - (void)setStatusText
:(NSString
*)msg duration
:(NSTimeInterval
)seconds
463 [self setStatusText
:msg duration
:seconds color
:[NSColor blackColor
]];
466 - (void)setStatusText
:(NSString
*)msg duration
:(NSTimeInterval
)seconds color
:(NSColor
*)color
470 [statusText setTextColor
:color
];
471 [statusText setStringValue
:msg
];
475 if ( statusTextTimer
)
477 [statusTextTimer invalidate
];
478 [statusTextTimer release
];
482 [savedStatusText release
];
483 [savedStatusColor release
];
484 savedStatusText
= [[statusText stringValue
] retain
];
485 savedStatusColor
= [[statusText textColor
] retain
];
488 [statusText setTextColor
:color
];
489 [statusText setStringValue
:msg
];
490 statusTextTimer
= [[NSTimer scheduledTimerWithTimeInterval
:seconds target
:self selector
:@selector(statusTextTimer
:) userInfo
:nil repeats
:NO
] retain
];
495 - (void)statusTextTimer
:(NSTimer
*)timer
497 [statusText setTextColor
:savedStatusColor
];
498 [statusText setStringValue
:savedStatusText
];
500 [savedStatusColor release
], savedStatusColor
= nil;
501 [savedStatusText release
], savedStatusText
= nil;
502 [statusTextTimer invalidate
];
503 [statusTextTimer release
], statusTextTimer
= nil;
507 - (void)connectToLocal
509 NSString
*localName
= @
"Local"; //[NSString stringWithFormat:@"%@ (local)", TCGlobalBroadcastName];
511 // depending on how the listener is listening, we need to use different means to connect to local
512 if ( TCGlobalListening
)
514 if ( TCGlobalAllowRemote
)
516 struct sockaddr_in addr
;
518 addr.sin_family
= AF_INET
;
519 addr.sin_port
= htonl( TCGlobalListenPort
);
520 addr.sin_addr.s_addr
= INADDR_ANY
;
522 [self connectToServer
:[NSData dataWithBytes
:&addr length
:sizeof(addr
)] name
:localName
];
526 struct sockaddr_un addr
;
528 addr.sun_family
= AF_UNIX
;
529 strncpy( addr.sun_path
, TCDefaultListenPath
, 103 );
531 [self connectToServer
:[NSData dataWithBytes
:&addr length
:sizeof(addr
)] name
:localName
];
536 - (void)connectToServer
:(NSData
*)addr name
:(NSString
*)name
544 waitingToConnect
= YES
;
545 connectionAddress
= [addr retain
];
546 connectionName
= [name retain
];
550 connection
= [[CheatClient clientWithDelegate
:self server
:addr name
:name
] retain
];
551 connectionAddress
= [addr retain
];
552 connectionName
= [name retain
];
555 [self setStatusConnected
];
562 [connection release
], connection
= nil;
567 [connectionAddress release
], connectionAddress
= nil;
568 [connectionName release
], connectionName
= nil;
570 [processMenu removeAllItems
];
572 [serverPopup selectItemAtIndex
:0];
573 [self setStatusDisconnected
];
578 - (void)sendProcessListRequest
581 int length
= sizeof(header
);
583 header.checksum
= RandomChecksum();
587 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
589 NSLog( @
"sendProcessListRequest failed on socket %i", sockfd
);
593 - (void)sendClearSearch
596 int length
= sizeof(header
);
598 header.checksum
= RandomChecksum();
602 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
604 NSLog( @
"sendClearSearch failed on socket %i", sockfd
);
608 - (void)sendSearch
:(char const *)data size
:(int)size
611 int length
= sizeof(header
) + size
;
612 int lengthAfter
= length
;
616 header.checksum
= RandomChecksum();
620 if ( (buffer
= (char *)malloc( length
)) == NULL
)
622 NSLog( @
"sendSearch:size: failed" );
627 COPY_TO_BUFFER( ptr
, &header
, sizeof(header
) );
628 COPY_TO_BUFFER( ptr
, data
, size
);
630 if ( SendBuffer( sockfd
, buffer
, &lengthAfter
) == -1 || lengthAfter
!= length
)
632 NSLog( @
"sendSearch:size: failed" );
638 - (void)sendChange
:(char const *)data size
:(int)size
641 int length
= sizeof(header
) + size
;
642 int lengthAfter
= length
;
646 header.checksum
= RandomChecksum();
650 if ( (buffer
= (char *)malloc( length
)) == NULL
)
652 NSLog( @
"sendChange:size: failed" );
657 COPY_TO_BUFFER( ptr
, &header
, sizeof(header
) );
658 COPY_TO_BUFFER( ptr
, data
, size
);
660 if ( SendBuffer( sockfd
, buffer
, &lengthAfter
) == -1 || lengthAfter
!= length
)
662 NSLog( @
"sendChange:size: failed" );
668 - (void)sendPauseTarget
;
671 int length
= sizeof(header
);
673 header.checksum
= RandomChecksum();
674 header.function
= 10;
677 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
679 NSLog( @
"sendPauseTarget failed" );
683 - (void)sendVariableValueRequest
688 - (void)sendUndoRequest
691 int length
= sizeof(header
);
693 header.checksum
= RandomChecksum();
694 header.function
= 14;
697 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
699 NSLog( @
"sendUndoRequest failed" );
703 - (void)sendRedoRequest
706 int length
= sizeof(header
);
708 header.checksum
= RandomChecksum();
709 header.function
= 16;
712 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
714 NSLog( @
"sendRedoRequest failed" );
718 - (void)sendSetTargetPID
:(int)pid
721 int length
= sizeof(header
) + sizeof(u_int32_t
);
722 int lengthAfter
= length
;
724 u_int32_t tarPID
= (u_int32_t
)pid
;
728 header.checksum
= RandomChecksum();
729 header.function
= 18;
730 header.size
= sizeof(u_int32_t
);
732 if ( (buffer
= (char *)malloc( length
)) == NULL
)
734 NSLog( @
"sendSetTargetPID: failed" );
739 COPY_TO_BUFFER( ptr
, &header
, sizeof(header
) );
740 COPY_TO_BUFFER( ptr
, &tarPID
, sizeof(tarPID
) );
742 if ( SendBuffer( sockfd
, buffer
, &lengthAfter
) == -1 || lengthAfter
!= length
)
744 NSLog( @
"sendSetTargetPID: failed" );
751 - (void)receivedProcessList
:(NSData
*)data
754 u_int32_t processCount
= 0;
756 char *ptr
= (char *)[data bytes
];
759 COPY_FROM_BUFFER( &processCount
, ptr
, sizeof(processCount
) );
761 max
= (int)processCount
;
763 for ( i
= 0; i
< max
; i
++ )
768 COPY_FROM_BUFFER( &pid
, ptr
, sizeof(pid
) );
769 name
= [NSString stringWithCString
:ptr
], ptr
+= [name length
] + 1;
771 item
= [[NSMenuItem alloc
] initWithTitle
:name action
:@selector(processMenuItem
:) keyEquivalent
:@
""];
772 [item setTag
:(int)pid
];
774 [processMenu addItem
:[item autorelease
]];
778 - (void)receivedSearchFinished
780 if ( searchResultsAmount
== 1 )
782 TCPlaySound( @
"Submarine" );
784 else if ( searchResultsAmount
== 0 )
786 TCPlaySound( @
"Basso" );
789 [self setStatusToLast
];
790 [self setStatusText
:@
"Search Finished" duration
:1.5];
791 [cheatWindow makeFirstResponder
:searchTextField
];
794 - (void)receivedVariableList
:(NSData
*)data
796 char *ptr
= (char *)[data bytes
];
798 [self destroyResults
];
800 COPY_FROM_BUFFER( &searchResultsAmount
, ptr
, sizeof(searchResultsAmount
) );
802 if ( searchResultsAmount
> 0 )
804 int memSize
= TCAddressSize
*searchResultsAmount
;
806 if ( (searchResults
= (TCaddress
*)malloc( memSize
)) == NULL
)
808 NSLog( @
"receivedVariableList failed: malloc failed" );
809 searchResultsAmount
= 0;
813 COPY_FROM_BUFFER( searchResults
, ptr
, memSize
);
816 [addressTable reloadData
];
819 - (void)receivedChangeFinished
821 TCPlaySound( @
"Tink" );
823 [self setStatusToLast
];
824 [self setStatusText
:@
"Change Finished" duration
:1.5];
827 - (void)receivedError
:(NSData
*)data
832 char *ptr
= (char *)[data bytes
];
834 COPY_FROM_BUFFER( &fatal
, ptr
, sizeof(fatal
) );
836 msg
= [NSString stringWithCString
:ptr
];
839 [self handleErrorMessage
:msg fatal
:fatal
];
842 - (void)receivedUndoFinished
844 [self setStatusToLast
];
847 - (void)receivedRedoFinished
849 [self setStatusToLast
];
852 - (void)receivedUndoRedoStatus
:(NSData
*)data
854 char *ptr
= (char *)[data bytes
];
856 COPY_FROM_BUFFER( &undoCount
, ptr
, sizeof(undoCount
) );
857 COPY_FROM_BUFFER( &redoCount
, ptr
, sizeof(redoCount
) );
859 NSLog( @
"UNDO: %i, REDO: %i", undoCount
, redoCount
);
862 - (void)receivedAppLaunched
:(NSData
*)data
866 char *ptr
= (char *)[data bytes
];
871 COPY_FROM_BUFFER( &pid
, ptr
, sizeof(pid
) );
872 name
= [NSString stringWithCString
:ptr
], ptr
+= [name length
] + 1;
874 item
= [[NSMenuItem alloc
] initWithTitle
:name action
:@selector(processMenuItem
:) keyEquivalent
:@
""];
875 [item setTag
:(int)pid
];
877 [processMenu addItem
:[item autorelease
]];
880 - (void)receivedAppQuit
:(NSData
*)data
884 char *ptr
= (char *)[data bytes
];
886 COPY_FROM_BUFFER( &pid
, ptr
, sizeof(pid
) );
888 [processMenu removeItemWithTag
:pid
];
891 - (void)receivedTargetQuit
894 [self sendClearSearch
];
896 // tell the server that the first app is now the target.
897 targetPID
= [[processMenu itemAtIndex
:0] tag
];
898 [self sendSetTargetPID
:targetPID
];
901 [self handleErrorMessage
:@
"The application that was being cheated has quit." fatal
:NO
];
903 [self setStatusConnected
];
906 - (void)receivedPauseFinished
:(NSData
*)data
908 char *ptr
= (char *)[data bytes
];
910 COPY_FROM_BUFFER( &targetPaused
, ptr
, sizeof(targetPaused
) );
914 [self setStatusText
:@
"Target Paused" duration
:1.5];
918 [self setStatusText
:@
"Target Resumed" duration
:1.5];
921 [self updatePauseButton
];
925 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
926 %%%%%%%%%%%%%%%%%%%%%% Searching & Changing
927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
932 TCtype type
= [[typePopup selectedItem
] tag
];
933 TCsize size
= [[sizePopup selectedItem
] tag
];
936 int dataSize
= sizeof(type
) + sizeof(size
);
938 data
= (char *)malloc( dataSize
);
941 // copy the size and type of the variable.
942 COPY_TO_BUFFER( ptr
, &type
, sizeof(type
) );
943 COPY_TO_BUFFER( ptr
, &size
, sizeof(size
) );
945 // switch to cheating mode if this is the first search.
946 if ( status
== STATUS_CONNECTED
)
948 [self setStatusCheating
];
951 // copy the value to search for.
960 NSString
*string
= [searchTextField stringValue
];
961 int stringLength
= [string length
] + 1;
963 data
= (char *)realloc( data
, dataSize
+ stringLength
);
964 ptr
= data
+ dataSize
;
965 dataSize
+= stringLength
;
967 COPY_TO_BUFFER( ptr
, [string cString
], stringLength
);
980 int8_t value
= [searchTextField intValue
];
982 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
983 ptr
= data
+ dataSize
;
984 dataSize
+= sizeof(value
);
986 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
992 int16_t value
= [searchTextField intValue
];
994 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
995 ptr
= data
+ dataSize
;
996 dataSize
+= sizeof(value
);
998 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1004 int32_t value
= [searchTextField intValue
];
1006 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1007 ptr
= data
+ dataSize
;
1008 dataSize
+= sizeof(value
);
1010 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1023 float value
= [searchTextField floatValue
];
1025 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1026 ptr
= data
+ dataSize
;
1027 dataSize
+= sizeof(value
);
1029 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1035 double value
= [searchTextField doubleValue
];
1037 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1038 ptr
= data
+ dataSize
;
1039 dataSize
+= sizeof(value
);
1041 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1050 u_int32_t value
= 0;//[searchTextField intValue];
1052 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1053 ptr
= data
+ dataSize
;
1054 dataSize
+= sizeof(value
);
1056 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1061 [self sendSearch
:data size
:dataSize
];
1064 [self setStatusSearching
];
1069 TCtype type
= [[typePopup selectedItem
] tag
];
1070 TCsize size
= [[sizePopup selectedItem
] tag
];
1072 NSArray
*selectedAddresses
= [[addressTable selectedRowEnumerator
] allObjects
];
1073 int i
, addressCount
= [selectedAddresses count
];
1076 int dataSize
= sizeof(type
) + sizeof(size
) + sizeof(addressCount
) + TCAddressSize
*addressCount
;
1078 data
= (char *)malloc( dataSize
);
1081 // copy the size and type of the variable.
1082 COPY_TO_BUFFER( ptr
, &type
, sizeof(type
) );
1083 COPY_TO_BUFFER( ptr
, &size
, sizeof(size
) );
1085 // copy the amount and the list of addresses to change.
1086 COPY_TO_BUFFER( ptr
, &addressCount
, sizeof(addressCount
) );
1087 for ( i
= 0; i
< addressCount
; i
++ )
1089 COPY_TO_BUFFER( ptr
, &((TCaddress
*)searchResults
)[ [[selectedAddresses objectAtIndex
:i
] intValue
] ], sizeof(TCaddress
) );
1092 // copy the new value.
1101 NSString
*string
= [changeTextField stringValue
];
1102 int stringLength
= [string length
] + 1;
1104 data
= (char *)realloc( data
, dataSize
+ stringLength
);
1105 ptr
= data
+ dataSize
;
1106 dataSize
+= stringLength
;
1108 COPY_TO_BUFFER( ptr
, [string cString
], stringLength
);
1121 int8_t value
= [changeTextField intValue
];
1123 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1124 ptr
= data
+ dataSize
;
1125 dataSize
+= sizeof(value
);
1127 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1133 int16_t value
= [changeTextField intValue
];
1135 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1136 ptr
= data
+ dataSize
;
1137 dataSize
+= sizeof(value
);
1139 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1145 int32_t value
= [changeTextField intValue
];
1147 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1148 ptr
= data
+ dataSize
;
1149 dataSize
+= sizeof(value
);
1151 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1164 float value
= [changeTextField floatValue
];
1166 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1167 ptr
= data
+ dataSize
;
1168 dataSize
+= sizeof(value
);
1170 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1176 double value
= [changeTextField doubleValue
];
1178 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1179 ptr
= data
+ dataSize
;
1180 dataSize
+= sizeof(value
);
1182 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1191 u_int32_t value
= 0;//[searchTextField intValue];
1193 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1194 ptr
= data
+ dataSize
;
1195 dataSize
+= sizeof(value
);
1197 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1202 [self sendChange
:data size
:dataSize
];
1205 [self setStatusChanging
];
1209 - (void)changeSheet
:(NSWindow
*)sheet returned
:(int)returned context
:(void *)context
1211 if ( returned
== 1 )
1213 if ( [recurringChangeButton state
] == NSOnState
)
1215 float seconds
= [changeSecondsCombo floatValue
];
1217 [self setStatusChangingContinuously
];
1221 changeTimer
= [[NSTimer scheduledTimerWithTimeInterval
:seconds target
:self selector
:@selector(changeTimer
:) userInfo
:nil repeats
:YES
] retain
];
1231 - (void)changeTimer
:(NSTimer
*)timer
1237 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1238 %%%%%%%%%%%%%%%%%%%%%% Cheat Window Interface
1239 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1242 - (IBAction
)typePopup
:(id)sender
1244 switch ( [typePopup indexOfSelectedItem
] )
1247 [sizePopup setMenu
:stringSizeMenu
];
1252 [sizePopup setMenu
:integerSizeMenu
];
1256 [sizePopup setMenu
:decimalSizeMenu
];
1260 [self updateSearchBoxes
];
1261 [self updateSearchButton
];
1265 - (IBAction
)searchButton
:(id)sender
1270 - (IBAction
)clearSearchButton
:(id)sender
1274 [self setStatusConnected
];
1275 [self setStatusText
:@
"Search Cleared" duration
:1.5];
1277 [self sendClearSearch
];
1281 - (IBAction
)changeButton
:(id)sender
1283 [changeTimer invalidate
];
1284 [changeTimer release
], changeTimer
= nil;
1286 if ( status
== STATUS_CHANGING_CONTINUOUSLY
)
1288 [self setStatusCheating
];
1290 else if ( status
= STATUS_CHEATING
)
1292 [NSApp beginSheet
:changeSheet modalForWindow
:cheatWindow modalDelegate
:self didEndSelector
:@selector(changeSheet
:returned
:context
:) contextInfo
:NULL
];
1293 //[NSApp runModalForWindow:changeSheet];
1294 //[NSApp endSheet:changeSheet];
1295 //[changeSheet orderOut:self];
1300 - (IBAction
)serverMenuItem
:(id)sender
1302 NSData
*data
= [[[serverList objectAtIndex
:[sender tag
]] addresses
] objectAtIndex
:0];
1303 /* struct sockaddr_in addr;
1305 [data getBytes:&addr];*/
1307 [self connectToServer
:data name
:[serverPopup titleOfSelectedItem
]];
1310 - (IBAction
)serverMenuDisconnect
:(id)sender
1315 - (IBAction
)serverMenuLocal
:(id)sender
1317 [self connectToLocal
];
1320 - (IBAction
)processMenuItem
:(id)sender
1322 targetPID
= [sender tag
];
1324 [self sendSetTargetPID
:targetPID
];
1326 [self setStatusText
:[NSString stringWithFormat
:@
"PID: %i", targetPID
] duration
:0];
1330 - (IBAction
)pauseButton
:(id)sender
1332 [self sendPauseTarget
];
1336 - (void)undoMenu
:(id)sender
1338 if ( undoCount
== 1 )
1340 [self clearSearchButton
:self];
1344 [self sendUndoRequest
];
1346 [self setStatusUndoing
];
1350 - (void)redoMenu
:(id)sender
1352 [self sendRedoRequest
];
1354 [self setStatusRedoing
];
1357 - (BOOL)respondsToSelector
:(SEL)aSelector
1359 if ( aSelector
== @selector(undoMenu
:) )
1361 if ( status
== STATUS_CHEATING
&& undoCount
> 0 )
1371 if ( aSelector
== @selector(redoMenu
:) )
1373 if ( status
== STATUS_CHEATING
&& redoCount
> 0 )
1383 return [super respondsToSelector
:aSelector
];
1387 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1388 %%%%%%%%%%%%%%%%%%%%%% Change Sheet Interface
1389 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1392 - (IBAction
)cancelButton
:(id)sender
1394 [changeSheet orderOut
:sender
];
1395 [NSApp endSheet
:changeSheet returnCode
:0];
1396 //[NSApp stopModal];
1399 - (IBAction
)okButton
:(id)sender
1401 [changeSheet orderOut
:sender
];
1402 [NSApp endSheet
:changeSheet returnCode
:1];
1403 //[NSApp stopModal];
1407 - (IBAction
)recurringChangeButton
:(id)sender
1409 if ( [recurringChangeButton state
] == NSOnState
)
1411 [changeSecondsCombo setEnabled
:YES
];
1415 [changeSecondsCombo setEnabled
:NO
];
1420 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1421 %%%%%%%%%%%%%%%%%%%%%% Cleaning Up
1422 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1432 [changeTimer invalidate
];
1433 [changeTimer release
], changeTimer
= nil;
1435 [self destroyResults
];
1436 [addressTable reloadData
];
1439 - (void)destroyResults
1441 if ( searchResultsAmount
> 0 )
1443 free( searchResults
);
1445 searchResultsAmount
= 0;
1452 [[NSNotificationCenter defaultCenter
] removeObserver
:self];
1458 [serverList release
];
1459 [addressList release
];
1461 // clean up status timer stuff
1462 [savedStatusColor release
];
1463 [savedStatusText release
];
1464 [statusTextTimer invalidate
];
1465 [statusTextTimer release
];
1467 [changeTimer invalidate
];
1468 [changeTimer release
];
1470 [self destroyResults
];
1476 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1477 %%%%%%%%%%%%%%%%%%%%%% TCListener Notifications
1478 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1481 - (void)listenerStarted
:(NSNotification
*)note
1483 if ( !everConnected
)
1485 [self connectToLocal
];
1489 - (void)listenerStopped
:(NSNotification
*)note
1495 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1496 %%%%%%%%%%%%%%%%%%%%%% TCWindowsOnTopChanged Notification
1497 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1500 - (void)windowsOnTopChanged
:(NSNotification
*)note
1502 if ( TCGlobalWindowsOnTop
)
1504 [cheatWindow setLevel
:NSPopUpMenuWindowLevel
];
1508 [cheatWindow setLevel
:NSNormalWindowLevel
];
1513 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1514 %%%%%%%%%%%%%%%%%%%%%% TCWindowsOnTopChanged Notification
1515 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1518 - (void)handleErrorMessage
:(NSString
*)msg fatal
:(BOOL)fatal
1520 // close the change sheet if it's open.
1521 if ( [cheatWindow attachedSheet
] )
1523 [changeSheet orderOut
:self];
1524 [NSApp endSheet
:changeSheet returnCode
:0];
1528 NSBeginAlertSheet( fatal? @
"Fatal Error":@
"Error", @
"OK", nil, nil, cheatWindow
, nil, nil, nil, 0, msg
);
1532 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1533 %%%%%%%%%%%%%%%%%%%%%% ClientDelegate
1534 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1537 - (void)clientConnectedWithSocket
:(int)sock name
:(NSString
*)name
1539 // the client is reporting that a connection has been made.
1542 [self sendProcessListRequest
];
1544 [serverPopup selectItemWithTitle
:name
];
1546 [self setStatusConnected
];
1549 - (void)clientDisconnected
1551 // if there is a pending connection, connect now.
1552 if ( waitingToConnect
)
1554 waitingToConnect
= NO
;
1555 connection
= [[CheatClient clientWithDelegate
:self server
:connectionAddress name
:connectionName
] retain
];
1557 // if our connection variable is still valid, we were disconnected unexpectedly.
1558 else if ( connection
)
1561 NSBeginAlertSheet( @
"Network Failure", @
"OK", nil, nil, cheatWindow
, nil, nil, nil, 0, @
"The server has disconnected you." );
1565 - (void)clientError
:(NSString
*)error message
:(NSString
*)message
1567 NSBeginAlertSheet( error
, @
"OK", nil, nil, cheatWindow
, nil, nil, nil, 0, message
);
1571 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1572 %%%%%%%%%%%%%%%%%%%%%% NSToolbar Delegate
1573 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1576 *** A toolbar is no longer used, but the code still remains for possible future use. ***
1578 - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
1580 NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
1582 if ( [itemIdentifier isEqualToString:@"Disconnect"] )
1584 disconnectButton = item;
1586 [item setLabel:@"Disconnect"];
1587 [item setPaletteLabel:[item label]];
1588 [item setImage:[NSImage imageNamed:@"disconnect"]];
1589 [item setTarget:self];
1590 [item setToolTip:@"Click here to pause or unpause the program being cheated."];
1592 else if ( [itemIdentifier isEqualToString:@"ServerPopup"] )
1594 NSRect fRect = [typePopup frame];
1595 NSSize fSize = NSMakeSize( FLT_MAX, fRect.size.height );
1596 NSMenuItem *menu = [[NSMenuItem alloc] initWithTitle:@"Server" action:@selector(serverPopup:) keyEquivalent:@""];
1598 [menu setSubmenu:[serverPopup menu]];
1600 [item setLabel:@"Server"];
1601 [item setPaletteLabel:[item label]];
1602 [item setView:serverPopup];
1603 [item setMinSize:fRect.size];
1604 [item setMaxSize:fSize];
1605 [item setMenuFormRepresentation:[menu autorelease]];
1612 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
1614 return [NSArray arrayWithObjects:NSToolbarSeparatorItemIdentifier,
1615 NSToolbarSpaceItemIdentifier,
1616 NSToolbarFlexibleSpaceItemIdentifier,
1617 NSToolbarCustomizeToolbarItemIdentifier,
1618 @"Disconnect", @"ServerPopup", nil];
1621 - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
1623 return [NSArray arrayWithObjects:@"Disconnect", @"ServerPopup", nil];
1627 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1628 %%%%%%%%%%%%%%%%%%%%%% NSTableView Data Source/Delegate
1629 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1632 - (void)controlTextDidChange
:(NSNotification
*)aNotification
1634 [self updateSearchButton
];
1638 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1639 %%%%%%%%%%%%%%%%%%%%%% NSTableView Data Source/Delegate
1640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1643 - (int)numberOfRowsInTableView
:(NSTableView
*)table
1645 return (searchResultsAmount
<= TCMaxSearchResults
) ? searchResultsAmount
: TCMaxSearchResults
;
1648 - (id)tableView
:(NSTableView
*)table objectValueForTableColumn
:(NSTableColumn
*)column row
:(int)row
1650 return [NSString stringWithFormat
:@
"%0.8X", ((TCaddress
*)searchResults
)[row
]];
1653 - (void)tableView
:(NSTableView
*) setObjectValue
:(id)object forTableColumn
:(NSTableColumn
*)column row
:(int)row
1658 - (void)tableViewSelectionDidChange
:(NSNotification
*)note
1660 if ( [addressTable selectedRow
] != -1 )
1662 addressSelected
= YES
;
1666 addressSelected
= NO
;
1669 [self updateChangeButton
];
1673 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1674 %%%%%%%%%%%%%%%%%%%%%% NSNetServiceBrowser Delegate
1675 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1678 - (void)netServiceBrowser
:(NSNetServiceBrowser
*)browser didFindService
:(NSNetService
*)service moreComing
:(BOOL)more
1680 // a server has broadcast; not much use until it's resolved.
1681 [service setDelegate
:self];
1685 - (void)netServiceBrowser
:(NSNetServiceBrowser
*)browser didRemoveService
:(NSNetService
*)service moreComing
:(BOOL)more
1687 [serverMenu removeAllItemsWithTitle
:[service name
]];
1689 // if this is the last broadcast server, take away the divider.
1690 if ( [serverMenu numberOfItems
] == 3 )
1692 [serverMenu removeItemAtIndex
:2];
1696 - (void)netServiceDidResolveAddress
:(NSNetService
*)service
1698 NSString
*name
= [service name
];
1699 int tag
= [serverList count
];
1702 if ( [serverMenu itemWithTitle
:name
] == nil )
1704 item
= [[NSMenuItem alloc
] initWithTitle
:[service name
] action
:@selector(serverMenuItem
:) keyEquivalent
:@
""];
1708 // if this is the first server, add a divider.
1709 if ( [serverMenu numberOfItems
] <= 2 )
1711 [serverMenu addItem
:[NSMenuItem separatorItem
]];
1714 [serverList addObject
:service
];
1715 [serverMenu addItem
:[item autorelease
]];
1717 // select the item if we are already connected to the server.
1718 // this could happen if the server rebroadcast as a different name.
1719 if ( connection
&& [[[service addresses
] objectAtIndex
:0] isEqualToData
:connectionAddress
] )
1721 [serverPopup selectItemWithTitle
:[service name
]];
1730 // Internal Functions
1731 void TCPlaySound( NSString
*name
)
1733 if ( TCGlobalPlaySounds
)
1735 [[NSSound soundNamed
:name
] play
];