Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!network!ucsd!hub!orange!dz
From: dz@orange.ucsb.edu (Daniel James Zerkle)
Newsgroups: comp.sys.next
Subject: communication between programs with Speaker and Listener
Keywords: speaker listener ipc port kernel preview
Message-ID: <2220@hub.UUCP>
Date: 17 Aug 89 16:41:26 GMT
Sender: news@hub.UUCP
Reply-To: dz@cornu.ucsb.edu (Daniel James Zerkle)
Distribution: usa
Organization: University of California, Santa Barbara
Lines: 121

You know the way that Digital Librarian can communicate with WriteNow
to display certain documents?  Ever notice that the print panel does
the same thing with Preview in many applications?  I am trying to do
something similar, but I am having no luck at all.  I want to be able
to send a message to Preview to display certain PostScript documents.
I have not gotten this to work, so if anything I say is clearly wrong,
let me know, as I may have some misconceptions.  Anyway, this is what I
understand so far:

The standard way to do inter-process communication  on a NeXT is with
the Speaker and Listener objects.  An application that wants to be able
to receive messages from other programs to do such useful procedures as
display or print files has a listener object that gets the messages and
passes them off to some sort of delegate, which takes care of the
actual work.  Preview should have one of these objects.  If a program
wants to *send* messages to other programs, it has a Speaker object for
each such program with which it wants to communicate.  You message the
Speaker when you want something interesting to happen at the other end.

As I'm not familiar with the special features of Mach over UNIX, this
part is where I'm a bit fuzzy.  The Listener listens and the Speaker
speaks over something called a "port".  When a Listener object is
started up, it creates the port and registers it with the Mach kernel.
A program with a speaker object can find that port somehow by looking
it up with the kernel.  Once it is found, there is an object method to
set that port as the one used.

Anyway, this is the code given as a typical use of the Speaker object
(this is in the documentation for Speaker):

/*****************************/
SpeakerId = [Speaker new];

port = NXPortFromName("someapp",NULL);
	// get port for "someapp" 
if (port != PORT_NULL)  
	[SpeakerId setSendPort:port]; 
	ec = [SpeakerId openFile:"/usr/foo" ok:&returnOk];
	// any method 
	if (ec == 0) 
		// fiddle with return results, like returnOk above 


[SpeakerId free]
	// when we quit
/*****************************/

This is the code I made that is utterly failing to work:

/*****************************/
- doDisplay:sender
{
    printf("Displayer is messaged...\n");
    [inputForm selectTextAt:0];
    
    SpeakerId = [Speaker new];
    port = NXPortFromName("/NextDeveloper/Demos/Preview",NULL);
    strcpy(dfile, [inputForm stringValueAt:0]);
    printf("File name is %s.\n",dfile);
    if (port != PORT_NULL)
      {
      printf("messaging the speaker\n");
      [SpeakerId openFile:dfile ok:&returnOk];
      }
    [SpeakerId free];
    return self;
}
/*****************************/

This bit of code is obviously just to test things out.  I'll clean up
later.  The assorted printf's (I don't grok gdb yet) show that the
openFile method does not get called (the file name and all else seem
correct).  Thusly, port must in fact == PORT_NULL (whatever that is).
The problem is, therefore, in the NXPortFromName() call.  Unfortunately,
I could find no online documentation anywhere for this call.  The best
I could do was the following line from /usr/include/appkit/Listener.h:

extern port_t NXPortFromName(const char *portName, const char *hostName);

Seeing "hostName", I tried changing the NULL to both "." and "pab" (our NeXT
is christened "pab", and it isn't my fault).  That had no effect whatsoever.

These are some good questions to answer:

1. How do I get the proper port identification, when all I know is the
   name of the program I want to use? Will this work if I don't even have
   the full pathname?  Should I use just the name and not the full path?

2a.Applications such as Digital Librarian and WriteNow (not to mention
   the Workspace Manager) will start up an application they need if it is
   not already started.  Is this automatic, or do I need to do it myself
   upon receipt of some error saying that there is no port registered
   under the desired application's name?

2b.How do I get this error message?  How do I know that the receiving
   program is ready (it may take awhile to start up)?

3. Who takes care of these sorts of things?  Should I be talking to the
   Workspace Manager, or directly to the kernel?  Is there more than one
   option?  If so, what is better under which circumstances?

4. Will the documentation be any better under 1.0?  It was rather a cheap
   shot to bring up NXPortFromName() and not have it documented anywhere.

5. Just what exactly do ports do?  How do they do it?  Chapter 15 of the
   technical manual talks about them but it is rather hard to follow.

6. Is there anything else I should know?

Obviously, the most useful thing for me right now would be a little piece
of Obj-C that would tell Preview what to do when I need it.  If you can
answer a couple of these questions, I'll probably be able to figure out
the code for myself.  (Just wish I had the source....)

Many thanks (in advance, of course).  May your family be blessed for
generations to come if you actually figure this out.

| Dan Zerkle home:(805) 968-4683 morning:961-2434 afternoon:687-0110  |
| dz@cornu.ucsb.edu dz%cornu@ucsbuxa.bitnet ...ucbvax!hub!cornu!dz    |
| Snailmail: 6681 Berkshire Terrace #5, Isla Vista, CA  93117         |
| Disclaimer: If it's wrong or stupid, pretend I didn't do it.        |