In Mac OS X Lion CARemoteLayerServer and CARemoteLayerClient were added to QuartzCore. I've been trying to investigate if they'd be suitable for splitting a graphical application between multiple processes, but without success.
I can use them successfully within a single process, with some code along the lines of this:
- (void)buildLayerSingleProcess
{
CARemoteLayerServer *server = [CARemoteLayerServer sharedServer];
self.client = [[CARemoteLayerClient alloc] initWithServerPort: server.serverPort];
uint32_t clientID = self.client.clientId;
CALayer *layer1 = [CALayer layer];
layer1.bounds = CGRectMake(0.0, 0.0, 100.0, 100.0);
CGColorRef color = CGColorCreateGenericRGB(0.4, 0.2, 0.3, 1.0);
[layer1 setBackgroundColor: color];
CFRelease(color);
[layer1 setOpacity: 0.75];
[layer1 setBorderWidth: 5.0f];
layer1.position = CGPointMake([[self.window contentView] frame].size.width / 2.0, [[self.window contentView] frame ].size.height / 2.0);
self.client.layer = layer2;
CALayer *servedLayer = [CALayer layerWithRemoteClientId: self.client.clientId];
[[[self.window contentView] layer] addSublayer: servedLayer];
}
Which is nice, but I'd like to try and do something similar between processes. The fact that server.serverPort is of type mach_port_t implies that it'd be suitable for use between processes.
However, when I split that code up to run in two processes (either two individual apps, or a main process and an XPC service), when I try to initialise the CARemoteLayerClient with the mach_port_t from the server in the other process I get:
unable to register with server: 0x10000003
It may well be they're not suited for between random processes, but the use of mach_port_t kinda implies that.
Has anyone else had any success using these classes between processes?
Yes, it's possible. Here is an example: https://github.com/krevis/RemoteLayerDemo
Run the app, press the "Get Remote Layer" button, and the service will be started and will give the app a green remote layer. (Oddly, it takes several seconds to appear -- no idea why.)
After that, the "Change Color" button sends a message to the service asking it to change the layer's color, which takes effect immediately, and even animates. The "Remove Remote Layer" button removes the layer; the service will then get terminated if you let it idle for a few seconds.
The hard part is passing the Mach port of the CARemoteLayerServer
between processes. The mach_port_t
that you see in your process is just a number; it only has meaning within your process. (Same idea as a pointer: pointers are just numbers, but you can't pass a pointer from one process to another, and expect them to point to the same thing.)
You'd think XPC could send Mach ports, but it can't. It would make this a lot easier!
Instead, you have to use Mach API to send the underlying Mach port around. In the demo, I'm using bootstrap_register
in the app and and bootstrap_look_up
in the service, using an agreed-upon name. This is not secure, because any other app in the same bootstrap context could find the port, but it's good enough for a demo. In reality you'd want to dive down to some uglier Mach calls.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With