From d4e0ed060315c1052cd55e18201c9a8ec6a8a5d2 Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Mon, 23 Mar 2015 10:54:14 +0000 Subject: [PATCH] #669: * don't create an OSX dock icon for the sound process: use a nested app, don't exec, don't probe the display * if the sound sink fails to start, tell the server immediately! * only log changes in sound pipeline "duration" with an actual value git-svn-id: https://xpra.org/svn/Xpra/trunk@8822 3bb7dfac-3a0b-4e04-842a-767bc560f471 --- osx/Info.plist | 4 +-- osx/Xpra_NoDock.app/Contents/Info.plist | 39 +++++++++++++++++++++++ osx/make-app.sh | 12 +++++++ src/xpra/client/ui_client_base.py | 3 +- src/xpra/net/subprocess_wrapper.py | 9 ++++-- src/xpra/platform/darwin/paths.py | 42 ++++++++++++++++--------- src/xpra/sound/pulseaudio_util.py | 8 ++--- src/xpra/sound/sound_pipeline.py | 4 ++- src/xpra/sound/wrapper.py | 10 +++++- 9 files changed, 104 insertions(+), 27 deletions(-) create mode 100644 osx/Xpra_NoDock.app/Contents/Info.plist diff --git a/osx/Info.plist b/osx/Info.plist index e924a79f54..e4600429b1 100644 --- a/osx/Info.plist +++ b/osx/Info.plist @@ -11,7 +11,7 @@ CFBundleName Xpra CFBundleGetInfoString - 0.15.0, (c) 2013-2014 http://xpra.org/ + 0.15.0, (c) 2013-2015 http://xpra.org/ CFBundleIconFile xpra.icns CFBundleIdentifier @@ -27,7 +27,7 @@ CFBundleVersion 0.15.0 NSHumanReadableCopyright - Copyright 2012-2014 Antoine Martin antoine@devloop.org.uk, GNU General Public License. + Copyright 2012-2015 Antoine Martin antoine@devloop.org.uk, GNU General Public License. LSMinimumSystemVersion 10.5 LSUIElement diff --git a/osx/Xpra_NoDock.app/Contents/Info.plist b/osx/Xpra_NoDock.app/Contents/Info.plist new file mode 100644 index 0000000000..9a6cfa69f7 --- /dev/null +++ b/osx/Xpra_NoDock.app/Contents/Info.plist @@ -0,0 +1,39 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + Xpra + CFBundleDisplayName + Xpra + CFBundleName + Xpra Without Tray + CFBundleGetInfoString + 0.15.0, (c) 2013-2015 http://xpra.org/ + CFBundleIconFile + xpra.icns + CFBundleIdentifier + xpra_notray + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleShortVersionString + 0.15 + CFBundleSignature + ???? + CFBundleVersion + 0.15 + NSHumanReadableCopyright + Copyright 2012-2014 Antoine Martin antoine@devloop.org.uk, GNU General Public License. + LSMinimumSystemVersion + 10.5 + LSUIElement + 1 + CFBundleDisplayName + Xpra + CFBundleName + Xpra + diff --git a/osx/make-app.sh b/osx/make-app.sh index e997a3c2a7..376c6038cb 100755 --- a/osx/make-app.sh +++ b/osx/make-app.sh @@ -156,6 +156,18 @@ echo "Ship a default xpra.conf" cp ../src/build/xpra.conf ${RSCDIR}/etc/ +echo +echo "*******************************************************************************" +echo "Xpra without a tray..." +for app in Xpra_NoDock.app; do + SUB_APP="${IMAGE_DIR}/Contents/${app}" + rsync -rplvtog ${app} ${IMAGE_DIR}/Contents/ + ln -sf ../../Resources ${SUB_APP}/Contents/Resources + ln -sf ../../MacOS ${SUB_APP}/Contents/MacOS + ln -sf ../../Helpers ${SUB_APP}/Contents/Helpers +done + + echo echo "*******************************************************************************" echo "Hacks" diff --git a/src/xpra/client/ui_client_base.py b/src/xpra/client/ui_client_base.py index d02a6ac7df..c73839438c 100644 --- a/src/xpra/client/ui_client_base.py +++ b/src/xpra/client/ui_client_base.py @@ -1684,8 +1684,9 @@ def start_sound_sink(self, codec): self.sound_sink.start() soundlog("%s sound sink started", codec) return True - except: + except Exception as e: log.error("failed to start sound sink", exc_info=True) + self.sound_sink_error(self.sound_sink, e) return False def new_sound_buffer(self, sound_source, data, metadata): diff --git a/src/xpra/net/subprocess_wrapper.py b/src/xpra/net/subprocess_wrapper.py index 0d6c9af6a5..eae6d7aa84 100644 --- a/src/xpra/net/subprocess_wrapper.py +++ b/src/xpra/net/subprocess_wrapper.py @@ -231,12 +231,15 @@ def make_protocol(self): def exec_subprocess(self): - kwargs = {} - if os.name=="posix": - kwargs["close_fds"] = True + kwargs = self.exec_kwargs() log("exec_subprocess() command=%s, kwargs=%s", self.command, kwargs) return subprocess.Popen(self.command, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=sys.stderr.fileno(), **kwargs) + def exec_kwargs(self): + if os.name=="posix": + return {"close_fds" : True} + return {} + def cleanup(self): self.stop() diff --git a/src/xpra/platform/darwin/paths.py b/src/xpra/platform/darwin/paths.py index d2ed528601..0ba0e4ae6a 100644 --- a/src/xpra/platform/darwin/paths.py +++ b/src/xpra/platform/darwin/paths.py @@ -16,21 +16,30 @@ def debug(*msg): def get_resources_dir(): rsc = None RESOURCES = "/Resources/" - try: - import gtkosx_application #@UnresolvedImport + #FUGLY warning: importing gtkosx_application causes the dock to appear, + #and in some cases we don't want that.. so use the env var XPRA_SKIP_UI as workaround for such cases: + if os.environ.get("XPRA_SKIP_UI", "0")=="0": try: - rsc = gtkosx_application.gtkosx_application_get_resource_path() - debug("get_resources_dir() gtkosx_application_get_resource_path=%s", rsc) - if rsc: - i = rsc.rfind(RESOURCES) - if i<=0: - rsc = None + import gtkosx_application #@UnresolvedImport + try: + rsc = gtkosx_application.gtkosx_application_get_resource_path() + debug("get_resources_dir() gtkosx_application_get_resource_path=%s", rsc) + except: + #maybe we're not running from an app bundle? + pass except: - #maybe we're not running from an app bundle? - pass - except: - print("ERROR: gtkosx_application module is missing - trying to continue anyway") - if not rsc: + #delayed import to prevent cycles: + from xpra.log import Logger + log = Logger("util") + log.error("ERROR: gtkosx_application module is missing - trying to continue anyway") + else: + debug("XPRA_SKIP_UI is set, not importing gtkosx_application") + if rsc is None: + #try using the path to this file to find the resource path: + rsc = __file__ + i = rsc.rfind(RESOURCES) + if i<=0: + #last fallback: try the default app dir from xpra.platform.paths import default_get_app_dir rsc = default_get_app_dir() debug("get_resources_dir() default_get_app_dir()=%s", rsc) @@ -70,5 +79,10 @@ def get_system_conf_dir(): def get_sound_executable(): - helper = os.path.join(get_app_dir(), "MacOS", "Xpra") + #try to use the subapp: + base = get_app_dir() + subapp = os.path.join(base, "Xpra_NoDock.app", "Contents") + if os.path.exists(subapp) and os.path.isdir(subapp): + base = subapp + helper = os.path.join(subapp, "MacOS", "Xpra") return os.environ.get("XPRA_SOUND_EXECUTABLE", helper) diff --git a/src/xpra/sound/pulseaudio_util.py b/src/xpra/sound/pulseaudio_util.py index da584d3b4d..b081bc4db4 100755 --- a/src/xpra/sound/pulseaudio_util.py +++ b/src/xpra/sound/pulseaudio_util.py @@ -62,13 +62,13 @@ def pactl_output(log_errors=True, *pactl_args): return -1, None def get_x11_property(atom_name): - if sys.platform.startswith("win"): + if sys.platform.startswith("darwin") or sys.platform.startswith("win"): return "" try: from gtk import gdk root = gdk.get_default_root_window() - pulse_server_atom = gdk.atom_intern(atom_name) - p = root.property_get(pulse_server_atom) + atom = gdk.atom_intern(atom_name) + p = root.property_get(atom) if p is None: return "" v = p[2] @@ -78,8 +78,6 @@ def get_x11_property(atom_name): return "" def has_pa_x11_property(): - if os.name!="posix": - return False #try root window property (faster) ps = get_x11_property("PULSE_SERVER") return len(ps)>0 diff --git a/src/xpra/sound/sound_pipeline.py b/src/xpra/sound/sound_pipeline.py index 79d3a74f39..792f467cba 100644 --- a/src/xpra/sound/sound_pipeline.py +++ b/src/xpra/sound/sound_pipeline.py @@ -174,7 +174,9 @@ def on_message(self, bus, message): elif t == gst.MESSAGE_DURATION: d = message.parse_duration() try: - log("duration changed: %s", d[1]) + v = d[1] + if v>0: + log("duration changed: %s", v) except: log("duration changed: %s", d) elif t == gst.MESSAGE_LATENCY: diff --git a/src/xpra/sound/wrapper.py b/src/xpra/sound/wrapper.py index 9b2fb5ff38..8ba6e15370 100644 --- a/src/xpra/sound/wrapper.py +++ b/src/xpra/sound/wrapper.py @@ -146,7 +146,15 @@ def __init__(self): #hook some default packet handlers: self.connect("state-changed", self.state_changed) self.connect("info", self.info_update) - + + def exec_kwargs(self): + #override so we can add the skip-ui flag needed for OSX to behave properly + kwargs = subprocess_caller.exec_kwargs(self) + env = os.environ.copy() + env["XPRA_SKIP_UI"] = "1" + kwargs["env"] = env + return kwargs + def state_changed(self, sink, new_state): self.state = new_state