home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.0 / NeXTSTEP3.0.iso / NextDeveloper / Examples / DistributedObjects / remoteSpot / Thinker.m < prev   
Text File  |  1992-07-24  |  6KB  |  295 lines

  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 <machE'5senderIsInvalid.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 theE'6ntRecord = [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 isE'7sed 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
  295.