Skip to content

Instantly share code, notes, and snippets.

@ewerybody
Created April 2, 2026 08:42
Show Gist options
  • Select an option

  • Save ewerybody/dd0ef1b540647bdd2d88466d1133a6bd to your computer and use it in GitHub Desktop.

Select an option

Save ewerybody/dd0ef1b540647bdd2d88466d1133a6bd to your computer and use it in GitHub Desktop.
Open File Browser - InkScape Extension to show current SVG document in Nemo, Explorer, Finder ...
<?xml version="1.0" encoding="UTF-8"?>
<inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">
<name>Open File Browser</name>
<id>org.inkscape.effect.open_filebrowser</id>
<effect>
<object-type>all</object-type>
<effects-menu>
<submenu name="Document"/>
</effects-menu>
</effect>
<script>
<command location="inx" interpreter="python">open_filebrowser.py</command>
</script>
</inkscape-extension>
"""
Open File Browser - Inkscape Effect Extension
Tries opening up system file browser with current SVG document file selected.
"""
import sys
import subprocess
from pathlib import Path
import inkex
class OpenFileBrowser(inkex.EffectExtension):
def effect(self):
document_path = Path(self.document_path())
if not document_path.is_file():
inkex.errormsg(
f"Source file not found: {document_path}\nSave the document first!"
)
return
if sys.platform == "win32":
win_shell_open(document_path)
return
if sys.platform == "darwin":
mac_show_in_finder(document_path)
return
if sys.platform == "linux":
linux_show_in_filemanager(document_path)
def win_shell_open(path: Path):
"""On Windows make use of `SHOpenFolderAndSelectItems` to open existing
Explorer window if any or open a fresh one.
Faster and resource friendly.
"""
import ctypes
if not isinstance(path, str):
path = str(path)
shell32 = ctypes.windll.shell32
ole32 = ctypes.windll.ole32
# CRITICAL: declare types or ctypes truncates 64-bit pointers to 32-bit
shell32.ILCreateFromPathW.restype = ctypes.c_void_p
shell32.ILCreateFromPathW.argtypes = [ctypes.c_wchar_p]
shell32.ILFree.restype = None
shell32.ILFree.argtypes = [ctypes.c_void_p]
shell32.SHOpenFolderAndSelectItems.restype = ctypes.HRESULT
shell32.SHOpenFolderAndSelectItems.argtypes = [
ctypes.c_void_p,
ctypes.c_uint,
ctypes.c_void_p,
ctypes.c_ulong,
]
h_init: int = ole32.CoInitialize(None)
pidl: int | None = None
try:
pidl = shell32.ILCreateFromPathW(str(path))
if not pidl:
raise ctypes.WinError()
h_result: int = shell32.SHOpenFolderAndSelectItems(pidl, 0, None, 0)
if h_result:
raise ctypes.WinError(h_result)
finally:
if pidl:
shell32.ILFree(pidl)
if not h_init:
ole32.CoUninitialize()
def linux_show_in_filemanager(path: Path) -> bool:
"""Try D-Bus FileManager1 first (Nemo, Nautilus, Dolphin...),
fall back to `xdg-open` on parent folder.
"""
uri: str = path.as_uri()
try:
subprocess.run(
[
"dbus-send",
"--session",
"--dest=org.freedesktop.FileManager1",
"--type=method_call",
"/org/freedesktop/FileManager1",
"org.freedesktop.FileManager1.ShowItems",
f"array:string:{uri}",
"string:",
],
check=True,
timeout=3,
)
return True
except (
subprocess.CalledProcessError,
FileNotFoundError,
subprocess.TimeoutExpired,
):
# dbus-send not available, or no FileManager1 service running
subprocess.Popen(['xdg-open', str(path.parent)], start_new_session=True)
return False
def mac_show_in_finder(path: Path) -> None:
script = f'tell application "Finder" to reveal POSIX file "{path}"'
subprocess.Popen(["osascript", "-e", script], start_new_session=True)
if __name__ == '__main__':
OpenFileBrowser().run()
Display the source blob
Display the rendered blob
Raw
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
width="70"
height="60"
viewBox="0 0 70 60"
version="1.1"
id="svg1"
sodipodi:docname="org.inkscape.effect.open_filebrowser.svg"
inkscape:version="1.4.3 (0d15f75, 2025-12-25)"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="false"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
showgrid="false"
inkscape:zoom="11.057742"
inkscape:cx="30.295516"
inkscape:cy="31.561597"
inkscape:current-layer="layer2"
inkscape:window-width="3440"
inkscape:window-height="1406"
inkscape:window-x="-11"
inkscape:window-y="-11"
inkscape:window-maximized="1"
showborder="false"
borderlayer="false"
showguides="true">
<inkscape:grid
id="grid1"
units="px"
originx="0"
originy="0"
spacingx="1"
spacingy="1"
empcolor="#0099e5"
empopacity="0.30196078"
color="#3f84a6"
opacity="0.14901961"
empspacing="5"
dotted="false"
gridanglex="30"
gridanglez="30"
visible="false" />
</sodipodi:namedview>
<defs
id="defs1">
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter6"
x="-0.1468138"
y="-0.71427652"
width="1.2936276"
height="2.428553">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="1.91 8.481"
id="feGaussianBlur6" />
</filter>
</defs>
<g
inkscape:groupmode="layer"
id="layer2"
inkscape:label="main">
<rect
style="fill:#f4e3bf;fill-opacity:1;stroke:none;stroke-width:0.38037;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
id="rect4"
width="36.090714"
height="31.456278"
x="3.232753"
y="21.608473"
ry="4.0049257"
rx="4.1201887"
transform="matrix(1,0,0.15866246,0.98733288,0,0)" />
<rect
style="opacity:0.307229;mix-blend-mode:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.523081;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke;filter:url(#filter6)"
id="rect6"
width="31.223223"
height="28.496527"
x="12.218544"
y="18.505661"
ry="6.7406564"
rx="4.5295973"
transform="matrix(0.90961481,0,-0.02416628,0.57395741,2.3986698,20.190451)" />
<path
style="opacity:1;fill:#7881c0;fill-opacity:1;stroke:#000000;stroke-width:1.51181;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
d="M 63.90762,4.7127562 C 63.340899,15.261952 59.297708,22.495709 51.906931,28.248671 l 8.661087,2.245716 -22.869166,4.548665 8.175721,-19.661298 1.889519,9.010968 C 52.161882,20.512628 57.687099,14.04029 57.849137,4.7564533 Z"
id="path7"
sodipodi:nodetypes="cccccccc" />
<path
id="rect5"
style="fill:#e6c67b;fill-opacity:1;stroke-width:0.377954;stroke-linecap:round;stroke-linejoin:round;paint-order:fill markers stroke"
d="M 50.111801,28.63332 H 38.236693 c -5.010906,0 -0.02611,-3.16629 -5.298208,-3.16629 H 22.42626 c -1.959952,0 -3.862048,1.502904 -4.369691,3.346098 l -5.572562,20.233346 c -0.507641,1.843194 0.745997,3.346097 2.70595,3.346097 h 29.015074 c 1.959951,0 3.908834,-1.492359 4.36969,-3.346097 L 52.817749,31.979418 C 53.278606,30.125679 52.071752,28.63332 50.111801,28.63332 Z"
sodipodi:nodetypes="sccssssssss" />
</g>
</svg>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment