问题
My app uses NSTask to execute shell scripts, one of those scripts launches an X11 app (specifically meld
).
I would have expected this to work:
#!/bin/bash
source ~/.profile # setup $PATH/etc
meld .
But it fails with:
gtk.icon_theme_get_default().append_search_path(meld.paths.icon_dir())
Traceback (most recent call last):
File "/usr/local/bin/meld", line 132, in <module>
gtk.icon_theme_get_default().append_search_path(meld.paths.icon_dir())
AttributeError: 'NoneType' object has no attribute 'append_search_path'
As a proof of concept I changed the script to this, which works perfectly:
#!/usr/bin/ruby
exec 'osascript -e \'tell app "Terminal" to do script "meld ' + Dir.pwd + '" in front window\''
Does anyone what is causing the problem? Here is my code for executing the shell script:
NSTask *task = [[NSTask alloc] init];
task.launchPath = self.scriptURL.path;
task.standardOutput = [NSPipe pipe];
task.currentDirectoryPath = workingDirectoryURL.path;
[task launch];
回答1:
X11 apps learn the display server's address using the DISPLAY environment variable.
On OS X, the DISPLAY value is randomized for security reasons, so you can't hard-code it, as you noticed. Instead, there is a launchd agent that tells launchd to set DISPLAY when it starts a process.
Somewhere between launchd and meld, the value of DISPLAY is being dropped or overwritten. Your job is to find out where.
- Make sure the launchd agent is running. Run
launchctl list
and look for org.macosforge.xquartz.startx. Sincemeld
is working from Terminal.app this part is probably correct. - Make sure DISPLAY is set in your app. It should be listed in
[NSProcessInfo processInfo].environment
. - Make sure DISPLAY is set in the NSTask you launch. Try running
/usr/bin/env
with an NSTask, and make sure DISPLAY appears in its output. - Make sure DISPLAY is set inside the script you run. Try
echo $DISPLAY
before and after sourcing ~/.profile. (Sometimes the .profile itself overwrites DISPLAY to an incorrect value because that's sometimes the right thing to do on other operating systems.)
EDIT: this is the code I used to copy DISPLAY from my GUI app to the shell script:
NSTask *task = ...
task.environment = [NSProcessInfo processInfo].environment;
[task.launch];
回答2:
Change your script to spew the environment variables and compare "working" to "not-working".
There are subtle differences between how shells are initialized across the different execution models. Almost assuredly, the environment is the source of your issues.
回答3:
Take a look at man launchctl
launchctl submit ... -p /usr/local/bin/meld -- .
to have launchd launch the job; that will set certain environment variables for you that are part of the per-user session.
来源:https://stackoverflow.com/questions/15650151/issue-launching-x11-app-via-nstask