I improved my testing setup a bit from what I used in this comment. Now you can see when argdebug
gets called multiple times.
$HOME/bin/argdebug
#!/bin/sh
echo >&2 'argdebug'
for x in "$@"; do
echo >&2 " '$x'"
done
$HOME/.local/share/applications/test-protocol.desktop
#!/usr/bin/env xdg-open
[Desktop Entry]
Name=Test Protocol
Exec=argdebug "%u"
Icon=emacs-icon
Type=Application
Terminal=false
MimeType=x-scheme-handler/test-protocol;
NoDisplay=true
Don't forget to sudo update-desktop-database
! (as well as anything specific to your DE, such as kbuildsyscocoa5
in my case)
On most systems, xdg-open
itself does extremely little work. It tries to detect your desktop environment, and then typically delegates to whatever tools your DE provides.
$HOME/bin/xdg-open-ExpHP is a modified copy of xdg-open
that lets us select the desktop environment it uses at runtime.
--- /usr/bin/xdg-open 2017-05-30 17:23:44.243430717 -0400
+++ /home/lampam/xdg-open-ExpHP 2017-08-20 12:08:53.409952763 -0400
@@ -974,6 +974,10 @@
;;
esac
+if [ x"$OVERRIDE_DE" != x"" ]; then
+ DE=$OVERRIDE_DE
+fi
+
case "$DE" in
kde)
open_kde "$url"
Let's review the facts:
- On my system,
xdg-open
callskde-open5
.kde-open5
is called with two colons...- ...but then
kde-open5
callsargdebug
with only one colon... - ...and adding a third slash after the first colon somehow prevents this from happening.
- @nerikj reports that
xdg-open
callsgio open
on his system.- once again,
gio open
is called with two colons... - ...but then
gio open
callsemacs-capture
with only one colon... - ...and adding a third slash after the first colon somehow prevents this from happening.
- once again,
What we see here are two different toolkits exhibiting the exact same behavior. So either:
- Possibility A: The way these programs treat URLs is actually the correct way.
- I wouldn't know and I'm too lazy to RTFP right now, but, uh... that would seem really really weird??
- Possibility B: The behavior is in some library that both desktop environments depend on.
To help rule out possibility A, I will try forcing xdg-open
to use its fallback logic.
First, for a point of comparison, let's repeat my experiments from here.
Here's what I normally see using xdg-open.
$ xdg-open-gio "test-protocol://lol://a/b/c"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-protocol"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-protocol"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-protocol"
kf5.kio.core: "preferred service for x-scheme-handler/test-protocol" "test-protocol"
argdebug
'test-protocol://lol//a/b/c
You can see that argdebug
is called without the second colon. However, it isn't xdg-open
's fault, because if you look at the trace output, you see that the colon is still there in the call to kde-open5
:
$ bash -x $(which xdg-open-ExpHP) "test-protocol://lol://a/b/c" 2>&1 | tail -n12
+ case "${KDE_SESSION_VERSION}" in
+ kde-open5 test-protocol://lol://a/b/c
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-protocol"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-protocol"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-protocol"
kf5.kio.core: "preferred service for x-scheme-handler/test-protocol" "test-protocol"
argdebug
'test-protocol://lol//a/b/c'
+ '[' 0 -eq 0 ']'
+ exit_success
+ '[' 0 -gt 0 ']'
+ exit 0
Ok, so far so good; this is consistent with what I saw before.
Here comes the new stuff.
When xdg-open
cannot detect your DE, it falls back to open_generic
, which is its own built-in fallback logic for parsing URLs and .desktop files. We can force it to use this logic by setting DE to 'generic':
$ OVERRIDE_DE=generic xdg-open-ExpHP "test-protocol://lol://L/a/b/c"
argdebug
'"%u"'
'test-protocol://lol://L/a/b/c'
-oof. That's odd. So, this output tells us two things:
- The fallback logic in
xdg-open
does NOT eat the colon!!! (so we see thatxdg-open
IS capable of calling the program correctly, with enough prodding!) - For some reason, we're seeing that
open_generic
calls our program with two arguments.- For some reason, the
"%u"
is still there!
- For some reason, the
Looking closely at the search_desktop_file
function in xdg-open
, we see logic for performing the substitutions:
set -- $(get_key "${file}" "Exec" | last_word)
# We need to replace any occurrence of "%f", "%F" and
# the like by the target file. We examine each
# argument and append the modified argument to the
# end then shift.
local args=$#
local replaced=0
while [ $args -gt 0 ]; do
case $1 in
%[c])
replaced=1
arg="${localised_name}"
shift
set -- "$@" "$arg"
;;
%[fFuU])
replaced=1
arg="$target"
shift
set -- "$@" "$arg"
;;
%[i])
replaced=1
shift
set -- "$@" "--icon" "$icon"
;;
*)
arg="$1"
shift
set -- "$@" "$arg"
;;
esac
args=$(( $args - 1 ))
done
[ $replaced -eq 1 ] || set -- "$@" "$target"
Ah. It is failing to substitute "%u"
because it is looking specifically for %u
(without quotes). It ends up hitting the set
in the last statement, which basically says, "if you didn't find anything to replace, just add the filename to the end of the arguments in Exec."
...okey dokey then. I see two possible fixes for this. I wonder, will either of them also fix it for kde-open5
?
~/.local/share/applications/test-b-protocol.desktop (%u without quotes in Exec)
#!/usr/bin/env xdg-open
[Desktop Entry]
Name=Test Protocol
Exec=argdebug %u
Icon=emacs-icon
Type=Application
Terminal=false
MimeType=x-scheme-handler/test-b-protocol;
NoDisplay=true
~/.local/share/applications/test-c-protocol.desktop (no %u pattern in Exec)
#!/usr/bin/env xdg-open
[Desktop Entry]
Name=Test Protocol
Exec=argdebug
Icon=emacs-icon
Type=Application
Terminal=false
MimeType=x-scheme-handler/test-c-protocol;
NoDisplay=true
As expected, both of these configurations work perfectly with open_generic
:
$ OVERRIDE_DE=generic xdg-open-ExpHP "test-b-protocol://lol://L/a/b/c"
argdebug
'test-b-protocol://lol://L/a/b/c'
$ OVERRIDE_DE=generic xdg-open-ExpHP "test-c-protocol://lol://L/a/b/c"
argdebug
'test-c-protocol://lol://L/a/b/c'
But neither work correctly with kde-open5
.
$ xdg-open-ExpHP "test-b-protocol://lol://L/a/b/c"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-b-protocol"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-b-protocol"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-b-protocol"
kf5.kio.core: "preferred service for x-scheme-handler/test-b-protocol" "test-b-protocol"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-b-protocol"
argdebug
'test-b-protocol://lol//L/a/b/c'
$ xdg-open-ExpHP "test-c-protocol://lol://L/a/b/c"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-c-protocol"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-c-protocol"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-c-protocol"
kf5.kio.core: "preferred service for x-scheme-handler/test-c-protocol" "test-c-protocol"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-c-protocol"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-c-protocol"
kf5.kio.core: Refilling KProtocolInfoFactory cache in the hope to find "test-c-protocol"
kf5.kio.core: "preferred service for x-scheme-handler/test-c-protocol" "test-c-protocol"
argdebug
''
We see here that, for KDE, %u
works like "%u"
, and it does not add the raw URL if you omit the %u. (instead it does the moronic act of calling argdebug
with a single empty argument (as opposed to no arguments like any sane program would do). My money is on this being a default-initialized std::string
:P)
- xdg-open itself never deletes the second colon, not even when you let it do all of the work itself. (
open_generic
)- if you force it to do all of the work itself, then
Exec=_emacs-client %u
(no quotes!) orExec=_emacs-client
will produce the correct behavior. - alas, these still won't work for KDE
- if you force it to do all of the work itself, then
gio open
andkde-open5
share the exact same colon-eating bug!- They probably use the same library for something... but what?
- There is no solace. Only pain and misfortune.
xdg-open
andkde-open5
disagree about how to handle a double-quoted"%u"
, or the omission of%u
.- Either the
.desktop
format is horribly underspecified, or all of its implementations just suck.