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 if ( lastStatus
!= STATUS_CHANGING_CONTINUOUSLY
)
307 [serverPopup setEnabled
:NO
];
308 [self updatePauseButton
];
309 [pauseButton setEnabled
:NO
];
310 [processPopup setEnabled
:NO
];
311 [typePopup setEnabled
:NO
];
312 [sizePopup setEnabled
:NO
];
313 [searchTextField setEnabled
:NO
];
314 [searchRadioMatrix setEnabled
:NO
];
315 [searchButton setEnabled
:NO
];
316 [clearSearchButton setEnabled
:NO
];
317 [statusBar startAnimation
:self];
318 [addressTable setEnabled
:NO
];
319 [changeButton setEnabled
:NO
];
321 [[serverMenu itemAtIndex
:0] setTitle
:@
"Disconnect"];
325 - (void)setStatusChangingLater
328 status
= STATUS_CHANGING_LATER
;
330 [serverPopup setEnabled
:NO
];
331 [self updatePauseButton
];
332 [pauseButton setEnabled
:NO
];
333 [processPopup setEnabled
:NO
];
334 [typePopup setEnabled
:NO
];
335 [sizePopup setEnabled
:NO
];
336 [searchTextField setEnabled
:NO
];
337 [searchRadioMatrix setEnabled
:NO
];
338 [searchButton setEnabled
:NO
];
339 [clearSearchButton setEnabled
:NO
];
340 [self setStatusText
:@
"Changing LaterÉ" duration
:0];
341 [statusBar startAnimation
:self];
342 [addressTable setEnabled
:NO
];
343 [changeButton setTitle
:@
"Cancel Change"];
344 [changeButton setEnabled
:YES
];
346 [[serverMenu itemAtIndex
:0] setTitle
:@
"Disconnect"];
349 - (void)setStatusChangingContinuously
352 status
= STATUS_CHANGING_CONTINUOUSLY
;
354 [serverPopup setEnabled
:NO
];
355 [self updatePauseButton
];
356 [pauseButton setEnabled
:YES
];
357 [processPopup setEnabled
:NO
];
358 [typePopup setEnabled
:NO
];
359 [sizePopup setEnabled
:NO
];
360 [searchTextField setEnabled
:NO
];
361 [searchRadioMatrix setEnabled
:NO
];
362 [searchButton setEnabled
:NO
];
363 [clearSearchButton setEnabled
:NO
];
364 [self setStatusText
:@
"Repeating ChangeÉ" duration
:0];
365 [statusBar startAnimation
:self];
366 [addressTable setEnabled
:NO
];
367 [changeButton setTitle
:@
"Stop Change"];
368 [changeButton setEnabled
:YES
];
370 [[serverMenu itemAtIndex
:0] setTitle
:@
"Disconnect"];
373 - (void)setStatusUndoing
376 status
= STATUS_UNDOING
;
378 [serverPopup setEnabled
:NO
];
379 [self updatePauseButton
];
380 [pauseButton setEnabled
:NO
];
381 [processPopup setEnabled
:NO
];
382 [typePopup setEnabled
:NO
];
383 [sizePopup setEnabled
:NO
];
384 [searchTextField setEnabled
:NO
];
385 [searchRadioMatrix setEnabled
:NO
];
386 [searchButton setEnabled
:NO
];
387 [clearSearchButton setEnabled
:NO
];
388 [self setStatusText
:@
"UndoingÉ" duration
:0];
389 [statusBar startAnimation
:self];
390 [addressTable setEnabled
:NO
];
391 [changeButton setTitle
:@
"ChangeÉ"];
392 [changeButton setEnabled
:NO
];
394 [[serverMenu itemAtIndex
:0] setTitle
:@
"Disconnect"];
397 - (void)setStatusRedoing
400 status
= STATUS_REDOING
;
402 [serverPopup setEnabled
:NO
];
403 [self updatePauseButton
];
404 [pauseButton setEnabled
:NO
];
405 [processPopup setEnabled
:NO
];
406 [typePopup setEnabled
:NO
];
407 [sizePopup setEnabled
:NO
];
408 [searchTextField setEnabled
:NO
];
409 [searchRadioMatrix setEnabled
:NO
];
410 [searchButton setEnabled
:NO
];
411 [clearSearchButton setEnabled
:NO
];
412 [self setStatusText
:@
"RedoingÉ" duration
:0];
413 [statusBar startAnimation
:self];
414 [addressTable setEnabled
:NO
];
415 [changeButton setTitle
:@
"ChangeÉ"];
416 [changeButton setEnabled
:NO
];
418 [[serverMenu itemAtIndex
:0] setTitle
:@
"Disconnect"];
421 - (void)setStatusToLast
423 switch ( lastStatus
)
425 case STATUS_DISCONNECTED
:
426 [self setStatusDisconnected
];
429 case STATUS_CONNECTED
:
430 [self setStatusConnected
];
433 case STATUS_CHEATING
:
434 [self setStatusCheating
];
437 case STATUS_SEARCHING
:
438 [self setStatusSearching
];
441 case STATUS_CHANGING
:
442 [self setStatusChanging
];
445 case STATUS_CHANGING_LATER
:
446 [self setStatusChangingLater
];
449 case STATUS_CHANGING_CONTINUOUSLY
:
450 [self setStatusChangingContinuously
];
454 [self setStatusUndoing
];
458 [self setStatusRedoing
];
463 - (void)setStatusText
:(NSString
*)msg duration
:(NSTimeInterval
)seconds
465 [self setStatusText
:msg duration
:seconds color
:[NSColor blackColor
]];
468 - (void)setStatusText
:(NSString
*)msg duration
:(NSTimeInterval
)seconds color
:(NSColor
*)color
470 if ( statusTextTimer
)
472 [statusTextTimer invalidate
];
473 [statusTextTimer release
], statusTextTimer
= nil;
477 [savedStatusText release
];
478 [savedStatusColor release
];
479 savedStatusText
= [[statusText stringValue
] retain
];
480 savedStatusColor
= [[statusText textColor
] retain
];
483 [statusText setTextColor
:color
];
484 [statusText setStringValue
:msg
];
486 if ( seconds
!= 0.0 )
488 statusTextTimer
= [[NSTimer scheduledTimerWithTimeInterval
:seconds target
:self selector
:@selector(statusTextTimer
:) userInfo
:nil repeats
:NO
] retain
];
492 - (void)statusTextTimer
:(NSTimer
*)timer
494 [statusText setTextColor
:savedStatusColor
];
495 [statusText setStringValue
:savedStatusText
];
497 [savedStatusColor release
], savedStatusColor
= nil;
498 [savedStatusText release
], savedStatusText
= nil;
499 [statusTextTimer invalidate
];
500 [statusTextTimer release
], statusTextTimer
= nil;
504 - (void)connectToLocal
506 NSString
*localName
= @
"Local"; //[NSString stringWithFormat:@"%@ (local)", TCGlobalBroadcastName];
508 // depending on how the listener is listening, we need to use different means to connect to local
509 if ( TCGlobalListening
)
511 if ( TCGlobalAllowRemote
)
513 struct sockaddr_in addr
;
515 addr.sin_family
= AF_INET
;
516 addr.sin_port
= htonl( TCGlobalListenPort
);
517 addr.sin_addr.s_addr
= INADDR_ANY
;
519 [self connectToServer
:[NSData dataWithBytes
:&addr length
:sizeof(addr
)] name
:localName
];
523 struct sockaddr_un addr
;
525 addr.sun_family
= AF_UNIX
;
526 strncpy( addr.sun_path
, TCDefaultListenPath
, 103 );
528 [self connectToServer
:[NSData dataWithBytes
:&addr length
:sizeof(addr
)] name
:localName
];
533 - (void)connectToServer
:(NSData
*)addr name
:(NSString
*)name
541 waitingToConnect
= YES
;
542 connectionAddress
= [addr retain
];
543 connectionName
= [name retain
];
547 connection
= [[CheatClient clientWithDelegate
:self server
:addr name
:name
] retain
];
548 connectionAddress
= [addr retain
];
549 connectionName
= [name retain
];
552 [self setStatusConnected
];
559 [connection release
], connection
= nil;
564 [connectionAddress release
], connectionAddress
= nil;
565 [connectionName release
], connectionName
= nil;
567 [processMenu removeAllItems
];
569 [serverPopup selectItemAtIndex
:0];
570 [self setStatusDisconnected
];
575 - (void)sendProcessListRequest
578 int length
= sizeof(header
);
580 header.checksum
= RandomChecksum();
584 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
586 NSLog( @
"sendProcessListRequest failed on socket %i", sockfd
);
590 - (void)sendClearSearch
593 int length
= sizeof(header
);
595 header.checksum
= RandomChecksum();
599 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
601 NSLog( @
"sendClearSearch failed on socket %i", sockfd
);
605 - (void)sendSearch
:(char const *)data size
:(int)size
608 int length
= sizeof(header
) + size
;
609 int lengthAfter
= length
;
613 header.checksum
= RandomChecksum();
617 if ( (buffer
= (char *)malloc( length
)) == NULL
)
619 NSLog( @
"sendSearch:size: failed" );
624 COPY_TO_BUFFER( ptr
, &header
, sizeof(header
) );
625 COPY_TO_BUFFER( ptr
, data
, size
);
627 if ( SendBuffer( sockfd
, buffer
, &lengthAfter
) == -1 || lengthAfter
!= length
)
629 NSLog( @
"sendSearch:size: failed" );
635 - (void)sendChange
:(char const *)data size
:(int)size
638 int length
= sizeof(header
) + size
;
639 int lengthAfter
= length
;
643 header.checksum
= RandomChecksum();
647 if ( (buffer
= (char *)malloc( length
)) == NULL
)
649 NSLog( @
"sendChange:size: failed" );
654 COPY_TO_BUFFER( ptr
, &header
, sizeof(header
) );
655 COPY_TO_BUFFER( ptr
, data
, size
);
657 if ( SendBuffer( sockfd
, buffer
, &lengthAfter
) == -1 || lengthAfter
!= length
)
659 NSLog( @
"sendChange:size: failed" );
665 - (void)sendPauseTarget
;
668 int length
= sizeof(header
);
670 header.checksum
= RandomChecksum();
671 header.function
= 10;
674 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
676 NSLog( @
"sendPauseTarget failed" );
680 - (void)sendVariableValueRequest
685 - (void)sendUndoRequest
688 int length
= sizeof(header
);
690 header.checksum
= RandomChecksum();
691 header.function
= 14;
694 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
696 NSLog( @
"sendUndoRequest failed" );
700 - (void)sendRedoRequest
703 int length
= sizeof(header
);
705 header.checksum
= RandomChecksum();
706 header.function
= 16;
709 if ( SendBuffer( sockfd
, (char *)(&header
), &length
) == -1 || length
!= sizeof(header
) )
711 NSLog( @
"sendRedoRequest failed" );
715 - (void)sendSetTargetPID
:(int)pid
718 int length
= sizeof(header
) + sizeof(u_int32_t
);
719 int lengthAfter
= length
;
721 u_int32_t tarPID
= (u_int32_t
)pid
;
725 header.checksum
= RandomChecksum();
726 header.function
= 18;
727 header.size
= sizeof(u_int32_t
);
729 if ( (buffer
= (char *)malloc( length
)) == NULL
)
731 NSLog( @
"sendSetTargetPID: failed" );
736 COPY_TO_BUFFER( ptr
, &header
, sizeof(header
) );
737 COPY_TO_BUFFER( ptr
, &tarPID
, sizeof(tarPID
) );
739 if ( SendBuffer( sockfd
, buffer
, &lengthAfter
) == -1 || lengthAfter
!= length
)
741 NSLog( @
"sendSetTargetPID: failed" );
748 - (void)receivedProcessList
:(NSData
*)data
751 u_int32_t processCount
= 0;
753 char *ptr
= (char *)[data bytes
];
756 COPY_FROM_BUFFER( &processCount
, ptr
, sizeof(processCount
) );
758 max
= (int)processCount
;
760 for ( i
= 0; i
< max
; i
++ )
765 COPY_FROM_BUFFER( &pid
, ptr
, sizeof(pid
) );
766 name
= [NSString stringWithCString
:ptr
], ptr
+= [name length
] + 1;
768 item
= [[NSMenuItem alloc
] initWithTitle
:name action
:@selector(processMenuItem
:) keyEquivalent
:@
""];
769 [item setTag
:(int)pid
];
771 [processMenu addItem
:[item autorelease
]];
775 - (void)receivedSearchFinished
777 if ( searchResultsAmount
== 1 )
779 TCPlaySound( @
"Submarine" );
781 else if ( searchResultsAmount
== 0 )
783 TCPlaySound( @
"Basso" );
786 [self setStatusToLast
];
787 //[self setStatusText:@"Search Finished" duration:1.5];
788 [cheatWindow makeFirstResponder
:searchTextField
];
791 - (void)receivedVariableList
:(NSData
*)data
793 char *ptr
= (char *)[data bytes
];
795 [self destroyResults
];
797 COPY_FROM_BUFFER( &searchResultsAmount
, ptr
, sizeof(searchResultsAmount
) );
799 if ( searchResultsAmount
> 0 )
801 int memSize
= TCAddressSize
*searchResultsAmount
;
803 if ( (searchResults
= (TCaddress
*)malloc( memSize
)) == NULL
)
805 NSLog( @
"receivedVariableList failed: malloc failed" );
806 searchResultsAmount
= 0;
810 COPY_FROM_BUFFER( searchResults
, ptr
, memSize
);
813 [addressTable reloadData
];
816 - (void)receivedChangeFinished
818 [self setStatusToLast
];
820 if ( status
== STATUS_CHANGING_CONTINUOUSLY
)
822 [self setStatusText
:@
"Change Occured" duration
:1.5];
826 TCPlaySound( @
"Tink" );
830 - (void)receivedError
:(NSData
*)data
835 char *ptr
= (char *)[data bytes
];
837 COPY_FROM_BUFFER( &fatal
, ptr
, sizeof(fatal
) );
839 msg
= [NSString stringWithCString
:ptr
];
842 [self handleErrorMessage
:msg fatal
:fatal
];
845 - (void)receivedUndoFinished
847 [self setStatusToLast
];
850 - (void)receivedRedoFinished
852 [self setStatusToLast
];
855 - (void)receivedUndoRedoStatus
:(NSData
*)data
857 char *ptr
= (char *)[data bytes
];
859 COPY_FROM_BUFFER( &undoCount
, ptr
, sizeof(undoCount
) );
860 COPY_FROM_BUFFER( &redoCount
, ptr
, sizeof(redoCount
) );
862 NSLog( @
"UNDO: %i, REDO: %i", undoCount
, redoCount
);
865 - (void)receivedAppLaunched
:(NSData
*)data
869 char *ptr
= (char *)[data bytes
];
874 COPY_FROM_BUFFER( &pid
, ptr
, sizeof(pid
) );
875 name
= [NSString stringWithCString
:ptr
], ptr
+= [name length
] + 1;
877 item
= [[NSMenuItem alloc
] initWithTitle
:name action
:@selector(processMenuItem
:) keyEquivalent
:@
""];
878 [item setTag
:(int)pid
];
880 [processMenu addItem
:[item autorelease
]];
883 - (void)receivedAppQuit
:(NSData
*)data
887 char *ptr
= (char *)[data bytes
];
889 COPY_FROM_BUFFER( &pid
, ptr
, sizeof(pid
) );
891 [processMenu removeItemWithTag
:pid
];
894 - (void)receivedTargetQuit
897 [self sendClearSearch
];
899 // tell the server that the first app is now the target.
900 targetPID
= [[processMenu itemAtIndex
:0] tag
];
901 [self sendSetTargetPID
:targetPID
];
904 [self handleErrorMessage
:@
"The application that was being cheated has quit." fatal
:NO
];
906 [self setStatusConnected
];
909 - (void)receivedPauseFinished
:(NSData
*)data
911 char *ptr
= (char *)[data bytes
];
913 COPY_FROM_BUFFER( &targetPaused
, ptr
, sizeof(targetPaused
) );
917 [self setStatusText
:@
"Target Paused" duration
:1.5];
921 [self setStatusText
:@
"Target Resumed" duration
:1.5];
924 [self updatePauseButton
];
928 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
929 %%%%%%%%%%%%%%%%%%%%%% Searching & Changing
930 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
935 TCtype type
= [[typePopup selectedItem
] tag
];
936 TCsize size
= [[sizePopup selectedItem
] tag
];
939 int dataSize
= sizeof(type
) + sizeof(size
);
941 data
= (char *)malloc( dataSize
);
944 // copy the size and type of the variable.
945 COPY_TO_BUFFER( ptr
, &type
, sizeof(type
) );
946 COPY_TO_BUFFER( ptr
, &size
, sizeof(size
) );
948 // switch to cheating mode if this is the first search.
949 if ( status
== STATUS_CONNECTED
)
951 [self setStatusCheating
];
954 // copy the value to search for.
963 NSString
*string
= [searchTextField stringValue
];
964 int stringLength
= [string length
] + 1;
966 data
= (char *)realloc( data
, dataSize
+ stringLength
);
967 ptr
= data
+ dataSize
;
968 dataSize
+= stringLength
;
970 COPY_TO_BUFFER( ptr
, [string cString
], stringLength
);
983 int8_t value
= [searchTextField intValue
];
985 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
986 ptr
= data
+ dataSize
;
987 dataSize
+= sizeof(value
);
989 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
995 int16_t value
= [searchTextField intValue
];
997 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
998 ptr
= data
+ dataSize
;
999 dataSize
+= sizeof(value
);
1001 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1007 int32_t value
= [searchTextField intValue
];
1009 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1010 ptr
= data
+ dataSize
;
1011 dataSize
+= sizeof(value
);
1013 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1026 float value
= [searchTextField floatValue
];
1028 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1029 ptr
= data
+ dataSize
;
1030 dataSize
+= sizeof(value
);
1032 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1038 double value
= [searchTextField doubleValue
];
1040 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1041 ptr
= data
+ dataSize
;
1042 dataSize
+= sizeof(value
);
1044 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1053 u_int32_t value
= 0;//[searchTextField intValue];
1055 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1056 ptr
= data
+ dataSize
;
1057 dataSize
+= sizeof(value
);
1059 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1064 [self sendSearch
:data size
:dataSize
];
1067 [self setStatusSearching
];
1072 TCtype type
= [[typePopup selectedItem
] tag
];
1073 TCsize size
= [[sizePopup selectedItem
] tag
];
1075 NSArray
*selectedAddresses
= [[addressTable selectedRowEnumerator
] allObjects
];
1076 int i
, addressCount
= [selectedAddresses count
];
1079 int dataSize
= sizeof(type
) + sizeof(size
) + sizeof(addressCount
) + TCAddressSize
*addressCount
;
1081 data
= (char *)malloc( dataSize
);
1084 // copy the size and type of the variable.
1085 COPY_TO_BUFFER( ptr
, &type
, sizeof(type
) );
1086 COPY_TO_BUFFER( ptr
, &size
, sizeof(size
) );
1088 // copy the amount and the list of addresses to change.
1089 COPY_TO_BUFFER( ptr
, &addressCount
, sizeof(addressCount
) );
1090 for ( i
= 0; i
< addressCount
; i
++ )
1092 COPY_TO_BUFFER( ptr
, &((TCaddress
*)searchResults
)[ [[selectedAddresses objectAtIndex
:i
] intValue
] ], sizeof(TCaddress
) );
1095 // copy the new value.
1104 NSString
*string
= [changeTextField stringValue
];
1105 int stringLength
= [string length
] + 1;
1107 data
= (char *)realloc( data
, dataSize
+ stringLength
);
1108 ptr
= data
+ dataSize
;
1109 dataSize
+= stringLength
;
1111 COPY_TO_BUFFER( ptr
, [string cString
], stringLength
);
1124 int8_t value
= [changeTextField intValue
];
1126 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1127 ptr
= data
+ dataSize
;
1128 dataSize
+= sizeof(value
);
1130 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1136 int16_t value
= [changeTextField intValue
];
1138 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1139 ptr
= data
+ dataSize
;
1140 dataSize
+= sizeof(value
);
1142 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1148 int32_t value
= [changeTextField intValue
];
1150 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1151 ptr
= data
+ dataSize
;
1152 dataSize
+= sizeof(value
);
1154 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1167 float value
= [changeTextField floatValue
];
1169 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1170 ptr
= data
+ dataSize
;
1171 dataSize
+= sizeof(value
);
1173 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1179 double value
= [changeTextField doubleValue
];
1181 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1182 ptr
= data
+ dataSize
;
1183 dataSize
+= sizeof(value
);
1185 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1194 u_int32_t value
= 0;//[searchTextField intValue];
1196 data
= (char *)realloc( data
, dataSize
+ sizeof(value
) );
1197 ptr
= data
+ dataSize
;
1198 dataSize
+= sizeof(value
);
1200 COPY_TO_BUFFER( ptr
, &value
, sizeof(value
) );
1205 [self sendChange
:data size
:dataSize
];
1208 [self setStatusChanging
];
1212 - (void)changeSheet
:(NSWindow
*)sheet returned
:(int)returned context
:(void *)context
1214 if ( returned
== 1 )
1216 if ( [recurringChangeButton state
] == NSOnState
)
1218 float seconds
= [changeSecondsCombo floatValue
];
1220 [self setStatusChangingContinuously
];
1224 changeTimer
= [[NSTimer scheduledTimerWithTimeInterval
:seconds target
:self selector
:@selector(changeTimer
:) userInfo
:nil repeats
:YES
] retain
];
1234 - (void)changeTimer
:(NSTimer
*)timer
1240 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1241 %%%%%%%%%%%%%%%%%%%%%% Cheat Window Interface
1242 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1245 - (IBAction
)typePopup
:(id)sender
1247 switch ( [typePopup indexOfSelectedItem
] )
1250 [sizePopup setMenu
:stringSizeMenu
];
1255 [sizePopup setMenu
:integerSizeMenu
];
1259 [sizePopup setMenu
:decimalSizeMenu
];
1263 [self updateSearchBoxes
];
1264 [self updateSearchButton
];
1268 - (IBAction
)searchButton
:(id)sender
1273 - (IBAction
)clearSearchButton
:(id)sender
1277 [self setStatusConnected
];
1278 [self setStatusText
:@
"Search Cleared" duration
:1.5];
1280 [self sendClearSearch
];
1284 - (IBAction
)changeButton
:(id)sender
1286 [changeTimer invalidate
];
1287 [changeTimer release
], changeTimer
= nil;
1289 if ( status
== STATUS_CHANGING_CONTINUOUSLY
)
1291 [self setStatusCheating
];
1293 else if ( status
== STATUS_CHEATING
)
1295 [NSApp beginSheet
:changeSheet modalForWindow
:cheatWindow modalDelegate
:self didEndSelector
:@selector(changeSheet
:returned
:context
:) contextInfo
:NULL
];
1296 //[NSApp runModalForWindow:changeSheet];
1297 //[NSApp endSheet:changeSheet];
1298 //[changeSheet orderOut:self];
1303 - (IBAction
)serverMenuItem
:(id)sender
1305 NSData
*data
= [[[serverList objectAtIndex
:[sender tag
]] addresses
] objectAtIndex
:0];
1306 /* struct sockaddr_in addr;
1308 [data getBytes:&addr];*/
1310 [self connectToServer
:data name
:[serverPopup titleOfSelectedItem
]];
1313 - (IBAction
)serverMenuDisconnect
:(id)sender
1318 - (IBAction
)serverMenuLocal
:(id)sender
1320 [self connectToLocal
];
1323 - (IBAction
)processMenuItem
:(id)sender
1325 targetPID
= [sender tag
];
1327 [self sendSetTargetPID
:targetPID
];
1329 [self setStatusText
:[NSString stringWithFormat
:@
"PID: %i", targetPID
] duration
:0];
1333 - (IBAction
)pauseButton
:(id)sender
1335 [self sendPauseTarget
];
1339 - (void)undoMenu
:(id)sender
1341 if ( undoCount
== 1 )
1343 [self clearSearchButton
:self];
1347 [self sendUndoRequest
];
1349 [self setStatusUndoing
];
1353 - (void)redoMenu
:(id)sender
1355 [self sendRedoRequest
];
1357 [self setStatusRedoing
];
1360 - (BOOL)respondsToSelector
:(SEL)aSelector
1362 if ( aSelector
== @selector(undoMenu
:) )
1364 if ( status
== STATUS_CHEATING
&& undoCount
> 0 )
1374 if ( aSelector
== @selector(redoMenu
:) )
1376 if ( status
== STATUS_CHEATING
&& redoCount
> 0 )
1386 return [super respondsToSelector
:aSelector
];
1390 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1391 %%%%%%%%%%%%%%%%%%%%%% Change Sheet Interface
1392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1395 - (IBAction
)cancelButton
:(id)sender
1397 [changeSheet orderOut
:sender
];
1398 [NSApp endSheet
:changeSheet returnCode
:0];
1399 //[NSApp stopModal];
1402 - (IBAction
)okButton
:(id)sender
1404 [changeSheet orderOut
:sender
];
1405 [NSApp endSheet
:changeSheet returnCode
:1];
1406 //[NSApp stopModal];
1410 - (IBAction
)recurringChangeButton
:(id)sender
1412 if ( [recurringChangeButton state
] == NSOnState
)
1414 [changeSecondsCombo setEnabled
:YES
];
1418 [changeSecondsCombo setEnabled
:NO
];
1423 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1424 %%%%%%%%%%%%%%%%%%%%%% Cleaning Up
1425 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1435 [changeTimer invalidate
];
1436 [changeTimer release
], changeTimer
= nil;
1438 [self destroyResults
];
1439 [addressTable reloadData
];
1442 - (void)destroyResults
1444 if ( searchResultsAmount
> 0 )
1446 free( searchResults
);
1448 searchResultsAmount
= 0;
1455 [[NSNotificationCenter defaultCenter
] removeObserver
:self];
1461 [serverList release
];
1462 [addressList release
];
1464 // clean up status timer stuff
1465 [savedStatusColor release
];
1466 [savedStatusText release
];
1467 [statusTextTimer invalidate
];
1468 [statusTextTimer release
];
1470 [changeTimer invalidate
];
1471 [changeTimer release
];
1473 [self destroyResults
];
1479 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1480 %%%%%%%%%%%%%%%%%%%%%% TCListener Notifications
1481 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1484 - (void)listenerStarted
:(NSNotification
*)note
1486 if ( !everConnected
)
1488 [self connectToLocal
];
1492 - (void)listenerStopped
:(NSNotification
*)note
1498 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1499 %%%%%%%%%%%%%%%%%%%%%% TCWindowsOnTopChanged Notification
1500 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1503 - (void)windowsOnTopChanged
:(NSNotification
*)note
1505 if ( TCGlobalWindowsOnTop
)
1507 [cheatWindow setLevel
:NSPopUpMenuWindowLevel
];
1511 [cheatWindow setLevel
:NSNormalWindowLevel
];
1516 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1517 %%%%%%%%%%%%%%%%%%%%%% TCWindowsOnTopChanged Notification
1518 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1521 - (void)handleErrorMessage
:(NSString
*)msg fatal
:(BOOL)fatal
1523 // close the change sheet if it's open.
1524 if ( [cheatWindow attachedSheet
] )
1526 [changeSheet orderOut
:self];
1527 [NSApp endSheet
:changeSheet returnCode
:0];
1531 NSBeginAlertSheet( fatal? @
"Fatal Error":@
"Error", @
"OK", nil, nil, cheatWindow
, nil, nil, nil, 0, msg
);
1535 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1536 %%%%%%%%%%%%%%%%%%%%%% ClientDelegate
1537 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1540 - (void)clientConnectedWithSocket
:(int)sock name
:(NSString
*)name
1542 // the client is reporting that a connection has been made.
1545 [self sendProcessListRequest
];
1547 [serverPopup selectItemWithTitle
:name
];
1549 [self setStatusConnected
];
1552 - (void)clientDisconnected
1554 // if there is a pending connection, connect now.
1555 if ( waitingToConnect
)
1557 waitingToConnect
= NO
;
1558 connection
= [[CheatClient clientWithDelegate
:self server
:connectionAddress name
:connectionName
] retain
];
1560 // if our connection variable is still valid, we were disconnected unexpectedly.
1561 else if ( connection
)
1564 NSBeginAlertSheet( @
"Network Failure", @
"OK", nil, nil, cheatWindow
, nil, nil, nil, 0, @
"The server has disconnected you." );
1568 - (void)clientError
:(NSString
*)error message
:(NSString
*)message
1570 NSBeginAlertSheet( error
, @
"OK", nil, nil, cheatWindow
, nil, nil, nil, 0, message
);
1574 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1575 %%%%%%%%%%%%%%%%%%%%%% NSToolbar Delegate
1576 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1579 *** A toolbar is no longer used, but the code still remains for possible future use. ***
1581 - (NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSString *)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
1583 NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdentifier];
1585 if ( [itemIdentifier isEqualToString:@"Disconnect"] )
1587 disconnectButton = item;
1589 [item setLabel:@"Disconnect"];
1590 [item setPaletteLabel:[item label]];
1591 [item setImage:[NSImage imageNamed:@"disconnect"]];
1592 [item setTarget:self];
1593 [item setToolTip:@"Click here to pause or unpause the program being cheated."];
1595 else if ( [itemIdentifier isEqualToString:@"ServerPopup"] )
1597 NSRect fRect = [typePopup frame];
1598 NSSize fSize = NSMakeSize( FLT_MAX, fRect.size.height );
1599 NSMenuItem *menu = [[NSMenuItem alloc] initWithTitle:@"Server" action:@selector(serverPopup:) keyEquivalent:@""];
1601 [menu setSubmenu:[serverPopup menu]];
1603 [item setLabel:@"Server"];
1604 [item setPaletteLabel:[item label]];
1605 [item setView:serverPopup];
1606 [item setMinSize:fRect.size];
1607 [item setMaxSize:fSize];
1608 [item setMenuFormRepresentation:[menu autorelease]];
1615 - (NSArray *)toolbarAllowedItemIdentifiers:(NSToolbar*)toolbar
1617 return [NSArray arrayWithObjects:NSToolbarSeparatorItemIdentifier,
1618 NSToolbarSpaceItemIdentifier,
1619 NSToolbarFlexibleSpaceItemIdentifier,
1620 NSToolbarCustomizeToolbarItemIdentifier,
1621 @"Disconnect", @"ServerPopup", nil];
1624 - (NSArray *)toolbarDefaultItemIdentifiers:(NSToolbar*)toolbar
1626 return [NSArray arrayWithObjects:@"Disconnect", @"ServerPopup", nil];
1630 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1631 %%%%%%%%%%%%%%%%%%%%%% NSTableView Data Source/Delegate
1632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1635 - (void)controlTextDidChange
:(NSNotification
*)aNotification
1637 [self updateSearchButton
];
1641 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1642 %%%%%%%%%%%%%%%%%%%%%% NSTableView Data Source/Delegate
1643 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1646 - (int)numberOfRowsInTableView
:(NSTableView
*)table
1648 return (searchResultsAmount
<= TCMaxSearchResults
) ? searchResultsAmount
: TCMaxSearchResults
;
1651 - (id)tableView
:(NSTableView
*)table objectValueForTableColumn
:(NSTableColumn
*)column row
:(int)row
1653 return [NSString stringWithFormat
:@
"%0.8X", ((TCaddress
*)searchResults
)[row
]];
1656 - (void)tableView
:(NSTableView
*) setObjectValue
:(id)object forTableColumn
:(NSTableColumn
*)column row
:(int)row
1661 - (void)tableViewSelectionDidChange
:(NSNotification
*)note
1663 if ( [addressTable selectedRow
] != -1 )
1665 addressSelected
= YES
;
1669 addressSelected
= NO
;
1672 [self updateChangeButton
];
1676 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1677 %%%%%%%%%%%%%%%%%%%%%% NSNetServiceBrowser Delegate
1678 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
1681 - (void)netServiceBrowser
:(NSNetServiceBrowser
*)browser didFindService
:(NSNetService
*)service moreComing
:(BOOL)more
1683 // a server has broadcast; not much use until it's resolved.
1684 [service setDelegate
:self];
1688 - (void)netServiceBrowser
:(NSNetServiceBrowser
*)browser didRemoveService
:(NSNetService
*)service moreComing
:(BOOL)more
1690 [serverMenu removeAllItemsWithTitle
:[service name
]];
1692 // if this is the last broadcast server, take away the divider.
1693 if ( [serverMenu numberOfItems
] == 3 )
1695 [serverMenu removeItemAtIndex
:2];
1699 - (void)netServiceDidResolveAddress
:(NSNetService
*)service
1701 NSString
*name
= [service name
];
1702 int tag
= [serverList count
];
1705 if ( [serverMenu itemWithTitle
:name
] == nil )
1707 item
= [[NSMenuItem alloc
] initWithTitle
:[service name
] action
:@selector(serverMenuItem
:) keyEquivalent
:@
""];
1711 // if this is the first server, add a divider.
1712 if ( [serverMenu numberOfItems
] <= 2 )
1714 [serverMenu addItem
:[NSMenuItem separatorItem
]];
1717 [serverList addObject
:service
];
1718 [serverMenu addItem
:[item autorelease
]];
1720 // select the item if we are already connected to the server.
1721 // this could happen if the server rebroadcast as a different name.
1722 if ( connection
&& [[[service addresses
] objectAtIndex
:0] isEqualToData
:connectionAddress
] )
1724 [serverPopup selectItemWithTitle
:[service name
]];
1733 // Internal Functions
1734 void TCPlaySound( NSString
*name
)
1736 if ( TCGlobalPlaySounds
)
1738 [[NSSound soundNamed
:name
] play
];