feat: a desktop entry, installed by an opt-in CMake target
The entry's Exec is the built binary's absolute path, so it always launches what was last built -- and moving the build directory breaks it, which is the price of having no install step. An install() rule would make a second copy that can diverge; a documented cp would need the binary on PATH, which it is not. The target writes the entry and both icons under XDG_DATA_HOME, refreshes the desktop and icon caches when the tools are there, and runs desktop-file-validate as a hard failure -- the shell ignores a malformed entry in silence, so the failure belongs at the moment the entry is asked for. It prints the three paths it wrote, which is the uninstall instructions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
33eee0c8d0
commit
a055325831
3 files changed
+99
No files matched your search
@@ -0,0 +1,61 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
#
|
||||
# The `desktop-entry` target's body. Copies the generated entry and the two app icons into
|
||||
# $XDG_DATA_HOME, validates the entry, refreshes the caches that make the shell notice, and
|
||||
# prints every path it wrote.
|
||||
#
|
||||
# This runs only when the target is named. The project deliberately has no install step -- that
|
||||
# is the stated reason its icons are a GResource -- and a target that does nothing until asked
|
||||
# preserves that while still producing a working entry.
|
||||
#
|
||||
# Expects -DENTRY=, -DICON= and -DSYMBOLIC= on the command line.
|
||||
|
||||
if(DEFINED ENV{XDG_DATA_HOME} AND NOT "$ENV{XDG_DATA_HOME}" STREQUAL "")
|
||||
set(data_home "$ENV{XDG_DATA_HOME}")
|
||||
else()
|
||||
set(data_home "$ENV{HOME}/.local/share")
|
||||
endif()
|
||||
|
||||
set(apps_dir "${data_home}/applications")
|
||||
set(icon_dir "${data_home}/icons/hicolor/scalable/apps")
|
||||
set(sym_dir "${data_home}/icons/hicolor/symbolic/apps")
|
||||
|
||||
# The icons are copied from the source tree rather than extracted from the GResource: the same
|
||||
# two files serve both the in-binary resource and the installed theme, so there is one copy to
|
||||
# edit. `file(COPY)` creates the directories.
|
||||
file(COPY "${ENTRY}" DESTINATION "${apps_dir}")
|
||||
file(COPY "${ICON}" DESTINATION "${icon_dir}")
|
||||
file(COPY "${SYMBOLIC}" DESTINATION "${sym_dir}")
|
||||
|
||||
get_filename_component(entry_name "${ENTRY}" NAME)
|
||||
get_filename_component(icon_name "${ICON}" NAME)
|
||||
get_filename_component(sym_name "${SYMBOLIC}" NAME)
|
||||
|
||||
# Validated here rather than left to the shell, which ignores a malformed entry in silence: the
|
||||
# failure belongs at the moment the entry is asked for.
|
||||
find_program(DESKTOP_FILE_VALIDATE desktop-file-validate)
|
||||
if(DESKTOP_FILE_VALIDATE)
|
||||
execute_process(COMMAND "${DESKTOP_FILE_VALIDATE}" "${apps_dir}/${entry_name}"
|
||||
RESULT_VARIABLE validate_result)
|
||||
if(NOT validate_result EQUAL 0)
|
||||
message(FATAL_ERROR "desktop-file-validate rejected ${apps_dir}/${entry_name}")
|
||||
endif()
|
||||
message(STATUS "desktop-file-validate: ok")
|
||||
else()
|
||||
message(STATUS "desktop-file-validate: not on PATH, entry not validated")
|
||||
endif()
|
||||
|
||||
find_program(UPDATE_DESKTOP_DATABASE update-desktop-database)
|
||||
if(UPDATE_DESKTOP_DATABASE)
|
||||
execute_process(COMMAND "${UPDATE_DESKTOP_DATABASE}" "${apps_dir}")
|
||||
endif()
|
||||
|
||||
find_program(GTK4_UPDATE_ICON_CACHE gtk4-update-icon-cache)
|
||||
if(GTK4_UPDATE_ICON_CACHE)
|
||||
execute_process(COMMAND "${GTK4_UPDATE_ICON_CACHE}" -f -t "${data_home}/icons/hicolor")
|
||||
endif()
|
||||
|
||||
# Printed because there is no uninstall target: undoing this is these three paths.
|
||||
message(STATUS "wrote ${apps_dir}/${entry_name}")
|
||||
message(STATUS "wrote ${icon_dir}/${icon_name}")
|
||||
message(STATUS "wrote ${sym_dir}/${sym_name}")
|
||||
Reference in new issue
Block a user