home *** CD-ROM | disk | FTP | other *** search
-
- /* Thinker.m, the brains in the color server app */
-
- #import "Thinker.h"
- #import "SpotView.h"
- #import "ClientRecord.h"
- #import "FullCopyList.h"
- #import <libc.h>
- #import <appkit/Panel.h>
- #import <machkit/NXNetNameServer.h>
- #import <machE'5senderIsInvalid.h>
- #import <mach/mach.h>
- #import <mach/mach_error.h>
- #import <objc/hashtable.h>
- #import <servers/netname.h>
-
- #define REGISTERED_NAME "samsColorServer"
- #define streq !strcmp
-
- @implementation Thinker
-
- //////////////////////////////////////////////////////
- // Shared server and client code
- //////////////////////////////////////////////////////
- - appDidInit:sender
- {
- float r,g,b;
- NXColor theColor;
-
- spotList = [[FullCopyList alloc] init];
-
- // return a proxy for the server
- // this looks for a color server on any host. In the real world,
- // you would probably specify a host.
- // this returns a local proxy to the remote "root" object
-
- server = [NXConnection connectToName:REGISTERED_NAME onHost:"*"];
-
- if (server)
- {
- // Become a client, already a server running
- isServer = NO;
- myConnection = [server connectionForProxy];
- [myConnection registerForInvalidationNotification:self];
- [server setProtocolForProxy:@protocol(spotServerMethods)];
- [win setTitle:"Spot Client"];
- }
-
- else
-
- {
- // Become the spot server, since no server is running
- // There is a window of vulnerability here; if 2 apps
- // launch nearly simultaneously, both will not find servers,
- // one will become the real server but the other will also
- // think it's the server (but will never get clients).
- // I should deal with this...
-
- isServer = YES;
-
- myConnection = [NXConnection registerRoot:self withName:REGISTERED_NAME];
-
- // printf("server: root connection is 0x%x\n", myConnection);
-
- [win setTitle:"Spot Server"];
- clientList = [[List alloc] init];
-
- server = self; //so this can act as its own pseudo client...
- }
-
- [myConnection runFromAppKit];
-
- [mySpotView lateInit];
-
- [server addClient:self r:&r g:&g b:&b];
- theColor = NXConvertRGBToColor(r,g,b);
- [[win setBackgroundColor:theColor] display];
-
- return self;
- }
-
- - appWillTerminate:sender
- {
- if (isServer)
- {
- int i, n = [clientList count];
-
- for (i = 0; i < n; i++)
- {
- id theClient = [[clientList objectAt:i] client];
- if (theClient != self) [theClient serverTerminated];
- }
- }
- else
- {
- [server clientTerminated:self];
- }
- return self;
- }
-
- - server
- { return server;
- }
-
- - (BOOL)isServer
- { return isServer;
- }
-
- // this is sent by a connection
- - senderIsInvalid:sender
- {
- if (isServer)
- {
- int i, n = [clientList count];
-
- for (i = 0; i < n; i++)
- {
- id theE'6ntRecord = [clientList objectAt:i];
- if ([theClientRecord connection] == sender)
- {
- [self nukeClient: theClientRecord];
- break;
- }
- }
- }
- else
- {
- [self serverTerminated];
- }
-
- // now free the connection since it's no longer useful
- // this also frees the proxies that the connection maintained
- [sender free];
-
- return nil;
- }
-
- //////////////////////////////////////////////////////
- // Server code
- //////////////////////////////////////////////////////
-
- // the server needs to keep a local database of clients so it can
- // message them all and associate port deaths to dead clients
-
- - (void) addClient:remoteClient
- r:(out float *)r
- g:(out float *)g
- b:(out float *)b
- {
- id connToClient, aSpot, client;
-
- if (remoteClient != self)
- {
- [remoteClient setProtocolForProxy:@protocol(spotClientMethods)];
-
- connToClient = [remoteClient connectionForProxy];
- [connToClient registerForInvalidationNotification:self];
- }
- else connToClient = nil;
-
- aSpot = [[[Spot alloc] init] addReference];
- client = [[ClientRecord alloc]
- initClient:remoteClient connection:connToClient spot:aSpot];
-
-
-
- // the client list is used internally by the server, while the
- // spot list contains some duplicate information, but must
- // be exported.
-
- [clientList addObject:client];
- [spotList addObject:aSpot];
-
- NXConvertColorToRGB([aSpot color], r, g, b);
-
- [self sendSpotListToClients];
-
- return;
- }
-
- // only called in server by server
- - nukeClient: theClientRecord
- {
- id theSpot = [theClientRecord spot];
- [clientList removeObject:theClientRecord];
- [spotList removeObject:theSpot];
- [theSpot invalidate];
- [NXApp delayedFree:theSpot]; // so we don't kill in modal loop
- [theClientRecord free];
- [self sendSpotListToClients];
- return self;
- }
-
- - (void) clientTerminated:(in id)sender
- {
- int i, n = [clientList count];
- id theClient;
-
- for (i = 0; i < n; i++)
- {
- id theClientRecord = [clientList objectAt:i];
- theClient = [theClientRecord client];
-
- if (theClient == sender)
- {
- [self nukeClient: theClientRecord];
- return;
- }
- }
-
- return;
- }
-
- - (oneway void) sendSpotListToClients
- {
- int i, n = [clientList count];
- id theClient;
-
- for (i = 0; i < n; i++)
- {
- theClient = [[clientList objectAt:i] client];
-
- if (theClient != self)
- {
- [theClient useSpotList:spotList];
- }
- else [mySpotView display];
- }
-
- return;
- }
-
- // the point isE'7sed in view coordinates; it is interpreted in the
- // server's view's coordinate system. It returns a spot object if
- // possible, which creates a proxy to that object on the client side
-
- - getSpotForPoint:(NXPoint) pnt spotLocation:(out NXPoint *)loc
- {
- int n = [spotList count];
- int i;
-
- for (i = n-1; i >= 0; i--)
- {
- id aSpot = [spotList objectAt:i];
- NXPoint spnt = [aSpot location];
- if (pnt.x > spnt.x && pnt.x < spnt.x + 30 &&
- pnt.y > spnt.y && pnt.y < spnt.y + 30)
- {
- if ([aSpot doLock])
- {
- *loc = spnt;
- return aSpot;
- }
- return nil;
- }
- }
- return nil;
- }
-
- - (oneway void) spotDidChange
- {
- [server sendSpotListToClients];
- return;
- }
-
- //////////////////////////////////////////////////////
- // Client code
- //////////////////////////////////////////////////////
-
- // return the clients own copy of the spotList
- - spotList
- {
- return spotList;
- }
-
- // don't ever send this message to the server!
- - (oneway void) useSpotList: (bycopy in id) newSpotList
- {
- [spotList freeObjects];
- [spotList free];
- spotList = newSpotList;
- [mySpotView display];
- return;
- }
-
- // the dying server calls this to nuke the clients
- - (oneway void) serverTerminated
- {
- NXRunAlertPanel (NULL, "Server terminated. Helpless client now "
- "terminating as well.", "Oot!", NULL, NULL);
- [NXApp terminate:self];
- }
-
- @end
-