|
|
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.