|
|
1.1 root 1:
2: /* Thinker.m, the brains in the color server app */
3:
4: #import "Thinker.h"
5: #import "SpotView.h"
6: #import "ClientRecord.h"
7: #import "FullCopyList.h"
8: #import <libc.h>
9: #import <appkit/Panel.h>
10: #import <machkit/NXNetNameServer.h>
11: #import <machkit/senderIsInvalid.h>
12: #import <mach/mach.h>
13: #import <mach/mach_error.h>
14: #import <objc/hashtable.h>
15: #import <servers/netname.h>
16:
17: #define REGISTERED_NAME "samsColorServer"
18: #define streq !strcmp
19:
20: @implementation Thinker
21:
22: //////////////////////////////////////////////////////
23: // Shared server and client code
24: //////////////////////////////////////////////////////
25: - appDidInit:sender
26: {
27: float r,g,b;
28: NXColor theColor;
29:
30: spotList = [[FullCopyList alloc] init];
31:
32: // return a proxy for the server
33: // this looks for a color server on any host. In the real world,
34: // you would probably specify a host.
35: // this returns a local proxy to the remote "root" object
36:
37: server = [NXConnection connectToName:REGISTERED_NAME onHost:"*"];
38:
39: if (server)
40: {
41: // Become a client, already a server running
42: isServer = NO;
43: myConnection = [server connectionForProxy];
44: [myConnection registerForInvalidationNotification:self];
45: [server setProtocolForProxy:@protocol(spotServerMethods)];
46: [win setTitle:"Spot Client"];
47: }
48:
49: else
50:
51: {
52: // Become the spot server, since no server is running
53: // There is a window of vulnerability here; if 2 apps
54: // launch nearly simultaneously, both will not find servers,
55: // one will become the real server but the other will also
56: // think it's the server (but will never get clients).
57: // I should deal with this...
58:
59: isServer = YES;
60:
61: myConnection = [NXConnection registerRoot:self withName:REGISTERED_NAME];
62:
63: // printf("server: root connection is 0x%x\n", myConnection);
64:
65: [win setTitle:"Spot Server"];
66: clientList = [[List alloc] init];
67:
68: server = self; //so this can act as its own pseudo client...
69: }
70:
71: [myConnection runFromAppKit];
72:
73: [mySpotView lateInit];
74:
75: [server addClient:self r:&r g:&g b:&b];
76: theColor = NXConvertRGBToColor(r,g,b);
77: [[win setBackgroundColor:theColor] display];
78:
79: return self;
80: }
81:
82: - appWillTerminate:sender
83: {
84: if (isServer)
85: {
86: int i, n = [clientList count];
87:
88: for (i = 0; i < n; i++)
89: {
90: id theClient = [[clientList objectAt:i] client];
91: if (theClient != self) [theClient serverTerminated];
92: }
93: }
94: else
95: {
96: [server clientTerminated:self];
97: }
98: return self;
99: }
100:
101: - server
102: { return server;
103: }
104:
105: - (BOOL)isServer
106: { return isServer;
107: }
108:
109: // this is sent by a connection
110: - senderIsInvalid:sender
111: {
112: if (isServer)
113: {
114: int i, n = [clientList count];
115:
116: for (i = 0; i < n; i++)
117: {
118: id theClientRecord = [clientList objectAt:i];
119: if ([theClientRecord connection] == sender)
120: {
121: [self nukeClient: theClientRecord];
122: break;
123: }
124: }
125: }
126: else
127: {
128: [self serverTerminated];
129: }
130:
131: // now free the connection since it's no longer useful
132: // this also frees the proxies that the connection maintained
133: [sender free];
134:
135: return nil;
136: }
137:
138: //////////////////////////////////////////////////////
139: // Server code
140: //////////////////////////////////////////////////////
141:
142: // the server needs to keep a local database of clients so it can
143: // message them all and associate port deaths to dead clients
144:
145: - (void) addClient:remoteClient
146: r:(out float *)r
147: g:(out float *)g
148: b:(out float *)b
149: {
150: id connToClient, aSpot, client;
151:
152: if (remoteClient != self)
153: {
154: [remoteClient setProtocolForProxy:@protocol(spotClientMethods)];
155:
156: connToClient = [remoteClient connectionForProxy];
157: [connToClient registerForInvalidationNotification:self];
158: }
159: else connToClient = nil;
160:
161: aSpot = [[[Spot alloc] init] addReference];
162: client = [[ClientRecord alloc]
163: initClient:remoteClient connection:connToClient spot:aSpot];
164:
165:
166:
167: // the client list is used internally by the server, while the
168: // spot list contains some duplicate information, but must
169: // be exported.
170:
171: [clientList addObject:client];
172: [spotList addObject:aSpot];
173:
174: NXConvertColorToRGB([aSpot color], r, g, b);
175:
176: [self sendSpotListToClients];
177:
178: return;
179: }
180:
181: // only called in server by server
182: - nukeClient: theClientRecord
183: {
184: id theSpot = [theClientRecord spot];
185: [clientList removeObject:theClientRecord];
186: [spotList removeObject:theSpot];
187: [theSpot invalidate];
188: [NXApp delayedFree:theSpot]; // so we don't kill in modal loop
189: [theClientRecord free];
190: [self sendSpotListToClients];
191: return self;
192: }
193:
194: - (void) clientTerminated:(in id)sender
195: {
196: int i, n = [clientList count];
197: id theClient;
198:
199: for (i = 0; i < n; i++)
200: {
201: id theClientRecord = [clientList objectAt:i];
202: theClient = [theClientRecord client];
203:
204: if (theClient == sender)
205: {
206: [self nukeClient: theClientRecord];
207: return;
208: }
209: }
210:
211: return;
212: }
213:
214: - (oneway void) sendSpotListToClients
215: {
216: int i, n = [clientList count];
217: id theClient;
218:
219: for (i = 0; i < n; i++)
220: {
221: theClient = [[clientList objectAt:i] client];
222:
223: if (theClient != self)
224: {
225: [theClient useSpotList:spotList];
226: }
227: else [mySpotView display];
228: }
229:
230: return;
231: }
232:
233: // the point is passed in view coordinates; it is interpreted in the
234: // server's view's coordinate system. It returns a spot object if
235: // possible, which creates a proxy to that object on the client side
236:
237: - getSpotForPoint:(NXPoint) pnt spotLocation:(out NXPoint *)loc
238: {
239: int n = [spotList count];
240: int i;
241:
242: for (i = n-1; i >= 0; i--)
243: {
244: id aSpot = [spotList objectAt:i];
245: NXPoint spnt = [aSpot location];
246: if (pnt.x > spnt.x && pnt.x < spnt.x + 30 &&
247: pnt.y > spnt.y && pnt.y < spnt.y + 30)
248: {
249: if ([aSpot doLock])
250: {
251: *loc = spnt;
252: return aSpot;
253: }
254: return nil;
255: }
256: }
257: return nil;
258: }
259:
260: - (oneway void) spotDidChange
261: {
262: [server sendSpotListToClients];
263: return;
264: }
265:
266: //////////////////////////////////////////////////////
267: // Client code
268: //////////////////////////////////////////////////////
269:
270: // return the clients own copy of the spotList
271: - spotList
272: {
273: return spotList;
274: }
275:
276: // don't ever send this message to the server!
277: - (oneway void) useSpotList: (bycopy in id) newSpotList
278: {
279: [spotList freeObjects];
280: [spotList free];
281: spotList = newSpotList;
282: [mySpotView display];
283: return;
284: }
285:
286: // the dying server calls this to nuke the clients
287: - (oneway void) serverTerminated
288: {
289: NXRunAlertPanel (NULL, "Server terminated. Helpless client now "
290: "terminating as well.", "Oot!", NULL, NULL);
291: [NXApp terminate:self];
292: }
293:
294: @end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.