xdg-desktop-menu 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420
  1. #!/bin/sh
  2. #---------------------------------------------
  3. # xdg-desktop-menu
  4. #
  5. # Utility script to install menu items on a Linux desktop.
  6. # Refer to the usage() function below for usage.
  7. #
  8. # Copyright 2009-2010, Fathi Boudra <fabo@freedesktop.org>
  9. # Copyright 2009-2010, Rex Dieter <rdieter@fedoraproject.org>
  10. # Copyright 2006, Kevin Krammer <kevin.krammer@gmx.at>
  11. # Copyright 2006, Jeremy White <jwhite@codeweavers.com>
  12. #
  13. # LICENSE:
  14. #
  15. # Permission is hereby granted, free of charge, to any person obtaining a
  16. # copy of this software and associated documentation files (the "Software"),
  17. # to deal in the Software without restriction, including without limitation
  18. # the rights to use, copy, modify, merge, publish, distribute, sublicense,
  19. # and/or sell copies of the Software, and to permit persons to whom the
  20. # Software is furnished to do so, subject to the following conditions:
  21. #
  22. # The above copyright notice and this permission notice shall be included
  23. # in all copies or substantial portions of the Software.
  24. #
  25. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  26. # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  27. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  28. # THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  29. # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  30. # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  31. # OTHER DEALINGS IN THE SOFTWARE.
  32. #
  33. #---------------------------------------------
  34. manualpage()
  35. {
  36. cat << _MANUALPAGE
  37. Name
  38. xdg-desktop-menu -- command line tool for (un)installing
  39. desktop menu items
  40. Synopsis
  41. xdg-desktop-menu install [--noupdate] [--novendor] [--mode
  42. mode] directory-file(s) desktop-file(s)
  43. xdg-desktop-menu uninstall [--noupdate] [--mode mode]
  44. directory-file(s) desktop-file(s)
  45. xdg-desktop-menu forceupdate [--mode mode]
  46. xdg-desktop-menu { --help | --manual | --version }
  47. Description
  48. The xdg-desktop-menu program can be used to install new menu
  49. entries to the desktop's application menu.
  50. The application menu works according to the XDG Desktop Menu
  51. Specification at
  52. http://www.freedesktop.org/wiki/Specifications/menu-spec
  53. Commands
  54. install
  55. Install one or more applications in a submenu of the
  56. desktop menu system.
  57. desktop-file: A desktop file represents a single menu
  58. entry in the menu. Desktop files are defined by the
  59. freedesktop.org Desktop Entry Specification. The most
  60. important aspects of *.desktop files are summarized
  61. below.
  62. Menu entries can be added to the menu system in two
  63. different ways. They can either be added to a predefined
  64. submenu in the menu system based on one or more category
  65. keywords, or they can be added to a new submenu.
  66. To add a menu entry to a predefined submenu the desktop
  67. file that represents the menu entry must have a
  68. Categories= entry that lists one or more keywords. The
  69. menu item will be included in an appropriate submenu
  70. based on the included keywords.
  71. To add menu items to a new submenu the desktop-files
  72. must be preceded by a directory-file that describes the
  73. submenu. If multiple desktop-files are specified, all
  74. entries will be added to the same menu. If entries are
  75. installed to a menu that has been created with a
  76. previous call to xdg-desktop-menu the entries will be
  77. installed in addition to any already existing entries.
  78. directory-file: The *.directory file indicated by
  79. directory-file represents a submenu. The directory file
  80. provides the name and icon for a submenu. The name of
  81. the directory file is used to identify the submenu.
  82. If multiple directory files are provided each file will
  83. represent a submenu within the menu that precedes it,
  84. creating a nested menu hierarchy (sub-sub-menus). The
  85. menu entries themselves will be added to the last
  86. submenu.
  87. Directory files follow the syntax defined by the
  88. freedesktop.org Desktop Entry Specification.
  89. uninstall
  90. Remove applications or submenus from the desktop menu
  91. system previously installed with xdg-desktop-menu
  92. install.
  93. A submenu and the associated directory file is only
  94. removed when the submenu no longer contains any menu
  95. entries.
  96. forceupdate
  97. Force an update of the menu system.
  98. This command is only useful if the last call to
  99. xdg-desktop-menu included the --noupdate option.
  100. Options
  101. --noupdate
  102. Postpone updating the menu system. If multiple updates
  103. to the menu system are made in sequence this flag can be
  104. used to indicate that additional changes will follow and
  105. that it is not necessary to update the menu system right
  106. away.
  107. --novendor
  108. Normally, xdg-desktop-menu checks to ensure that any
  109. *.directory and *.desktop files to be installed has a
  110. vendor prefix. This option can be used to disable that
  111. check.
  112. A vendor prefix consists of alpha characters ([a-zA-Z])
  113. and is terminated with a dash ("-"). Companies and
  114. organizations are encouraged to use a word or phrase,
  115. preferably the organizations name, for which they hold a
  116. trademark as their vendor prefix. The purpose of the
  117. vendor prefix is to prevent name conflicts.
  118. --mode mode
  119. mode can be user or system. In user mode the file is
  120. (un)installed for the current user only. In system mode
  121. the file is (un)installed for all users on the system.
  122. Usually only root is allowed to install in system mode.
  123. The default is to use system mode when called by root
  124. and to use user mode when called by a non-root user.
  125. --help
  126. Show command synopsis.
  127. --manual
  128. Show this manual page.
  129. --version
  130. Show the xdg-utils version information.
  131. Desktop Files
  132. An application item in the application menu is represented by a
  133. *.desktop file. A *.desktop file consists of a [Desktop Entry]
  134. header followed by several Key=Value lines.
  135. A *.desktop file can provide a name and description for an
  136. application in several different languages. This is done by
  137. adding a language code as used by LC_MESSAGES in square
  138. brackets behind the Key. This way one can specify different
  139. values for the same Key depending on the currently selected
  140. language.
  141. The following keys are often used:
  142. Type=Application
  143. This is a mandatory field that indicates that the
  144. *.desktop file describes an application launcher.
  145. Name=Application Name
  146. The name of the application. For example Mozilla
  147. GenericName=Generic Name
  148. A generic description of the application. For example
  149. Web Browser
  150. Comment=Comment
  151. Optional field to specify a tooltip for the application.
  152. For example Visit websites on the Internet
  153. Icon=Icon File
  154. The icon to use for the application. This can either be
  155. an absolute path to an image file or an icon-name. If an
  156. icon-name is provided an image lookup by name is done in
  157. the user's current icon theme. The xdg-icon-resource
  158. command can be used to install image files into icon
  159. themes. The advantage of using an icon-name instead of
  160. an absolute path is that with an icon-name the
  161. application icon can be provided in several different
  162. sizes as well as in several differently themed styles.
  163. Exec=Command Line
  164. The command line to start the application. If the
  165. application can open files the %f placeholder should be
  166. specified. When a file is dropped on the application
  167. launcher the %f is replaced with the file path of the
  168. dropped file. If multiple files can be specified on the
  169. command line the %F placeholder should be used instead
  170. of %f. If the application is able to open URLs in
  171. addition to local files then %u or %U can be used
  172. instead of %f or %F.
  173. Categories=Categories
  174. A list of categories separated by semi-colons. A
  175. category is a keyword that describes and classifies the
  176. application. By default applications are organized in
  177. the application menu based on category. When menu
  178. entries are explicitly assigned to a new submenu it is
  179. not necessary to list any categories.
  180. When using categories it is recommended to include one
  181. of the following categories: AudioVideo, Development,
  182. Education, Game, Graphics, Network, Office, Settings,
  183. System, Utility.
  184. See Appendix A of the XDG Desktop Menu Specification for
  185. information about additional categories:
  186. http://standards.freedesktop.org/menu-spec/menu-spec-1.0
  187. .html#category-registry
  188. MimeType=Mimetypes
  189. A list of mimetypes separated by semi-colons. This field
  190. is used to indicate which file types the application is
  191. able to open.
  192. For a complete overview of the *.desktop file format please
  193. visit
  194. http://www.freedesktop.org/wiki/Specifications/desktop-entry-sp
  195. ec
  196. Directory Files
  197. The appearance of submenu in the application menu is provided
  198. by a *.directory file. In particular it provides the title of
  199. the submenu and a possible icon. A *.directory file consists of
  200. a [Desktop Entry] header followed by several Key=Value lines.
  201. A *.directory file can provide a title (name) for the submenu
  202. in several different languages. This is done by adding a
  203. language code as used by LC_MESSAGES in square brackets behind
  204. the Key. This way one can specify different values for the same
  205. Key depending on the currently selected language.
  206. The following keys are relevant for submenus:
  207. Type=Directory
  208. This is a mandatory field that indicates that the
  209. *.directory file describes a submenu.
  210. Name=Menu Name
  211. The title of submenu. For example Mozilla
  212. Comment=Comment
  213. Optional field to specify a tooltip for the submenu.
  214. Icon=Icon File
  215. The icon to use for the submenu. This can either be an
  216. absolute path to an image file or an icon-name. If an
  217. icon-name is provided an image lookup by name is done in
  218. the user's current icon theme. The xdg-icon-resource
  219. command can be used to install image files into icon
  220. themes. The advantage of using an icon-name instead of
  221. an absolute path is that with an icon-name the submenu
  222. icon can be provided in several different sizes as well
  223. as in several differently themed styles.
  224. Environment Variables
  225. xdg-desktop-menu honours the following environment variables:
  226. XDG_UTILS_DEBUG_LEVEL
  227. Setting this environment variable to a non-zero
  228. numerical value makes xdg-desktop-menu do more verbose
  229. reporting on stderr. Setting a higher value increases
  230. the verbosity.
  231. XDG_UTILS_INSTALL_MODE
  232. This environment variable can be used by the user or
  233. administrator to override the installation mode. Valid
  234. values are user and system.
  235. Exit Codes
  236. An exit code of 0 indicates success while a non-zero exit code
  237. indicates failure. The following failure codes can be returned:
  238. 1
  239. Error in command line syntax.
  240. 2
  241. One of the files passed on the command line did not
  242. exist.
  243. 3
  244. A required tool could not be found.
  245. 4
  246. The action failed.
  247. 5
  248. No permission to read one of the files passed on the
  249. command line.
  250. See Also
  251. xdg-desktop-icon(1), xdg-icon-resource(1), xdg-mime(1), Desktop
  252. entry specification, Desktop menu specification
  253. Examples
  254. The company ShinyThings Inc. has developed an application named
  255. "WebMirror" and would like to add it to the application menu.
  256. The company will use "shinythings" as its vendor id. In order
  257. to add the application to the menu there needs to be a .desktop
  258. file with a suitable Categories entry:
  259. shinythings-webmirror.desktop:
  260. [Desktop Entry]
  261. Encoding=UTF-8
  262. Type=Application
  263. Exec=webmirror
  264. Icon=webmirror
  265. Name=WebMirror
  266. Name[nl]=WebSpiegel
  267. Categories=Network;WebDevelopment;
  268. Now the xdg-desktop-menu tool can be used to add the
  269. shinythings-webmirror.desktop file to the desktop application
  270. menu:
  271. xdg-desktop-menu install ./shinythings-webmirror.desktop
  272. Note that for the purpose of this example the menu items are
  273. available in two languages, English and Dutch. The language
  274. code for Dutch is nl.
  275. In the next example the company ShinyThings Inc. will add its
  276. own submenu to the desktop application menu consisting of a
  277. "WebMirror" menu item and a "WebMirror Admin Tool" menu item.
  278. First the company needs to create two .desktop files that
  279. describe the two menu items. Since the items are to be added to
  280. a new submenu it is not necessary to include a Categories=
  281. line:
  282. shinythings-webmirror.desktop:
  283. [Desktop Entry]
  284. Encoding=UTF-8
  285. Type=Application
  286. Exec=webmirror
  287. Icon=shinythings-webmirror
  288. Name=WebMirror
  289. Name[nl]=WebSpiegel
  290. shinythings-webmirror-admin.desktop:
  291. [Desktop Entry]
  292. Encoding=UTF-8
  293. Type=Application
  294. Exec=webmirror-admintool
  295. Icon=shinythings-webmirror-admintool
  296. Name=WebMirror Admin Tool
  297. Name[nl]=WebSpiegel Administratie Tool
  298. In addition a .directory file needs to be created to provide a
  299. title and icon for the sub-menu itself:
  300. shinythings-webmirror.directory:
  301. [Desktop Entry]
  302. Encoding=UTF-8
  303. Icon=shinythings-webmirror-menu
  304. Name=WebMirror
  305. Name[nl]=WebSpiegel
  306. These file can now be installed with:
  307. xdg-desktop-menu install ./shinythings-webmirror.directory \
  308. ./shinythings-webmirror.desktop ./shinythings-webmirror-admin.desk
  309. top
  310. The menu entries could also be installed one by one:
  311. xdg-desktop-menu install --noupdate ./shinythings-webmirror.directory \
  312. ./shinythings-webmirror.desktop
  313. xdg-desktop-menu install --noupdate ./shinythings-webmirror.directory \
  314. ./shinythings-webmirror-admin.desktop
  315. xdg-desktop-menu forceupdate
  316. Although the result is the same it is slightly more efficient
  317. to install all files at the same time.
  318. The *.desktop and *.directory files reference icons with the
  319. names webmirror, webmirror-admin and webmirror-menu which
  320. should also be installed. In this example the icons are
  321. installed in two different sizes, once with a size of 22x22
  322. pixels and once with a size of 64x64 pixels:
  323. xdg-icon-resource install --size 22 ./wmicon-22.png shinythings-webmirro
  324. r
  325. xdg-icon-resource install --size 22 ./wmicon-menu-22.png shinythings-web
  326. mirror-menu
  327. xdg-icon-resource install --size 22 ./wmicon-admin-22.png shinythings-we
  328. bmirror-admin
  329. xdg-icon-resource install --size 64 ./wmicon-64.png shinythings-webmirro
  330. r
  331. xdg-icon-resource install --size 64 ./wmicon-menu-64.png shinythings-web
  332. mirror-menu
  333. xdg-icon-resource install --size 64 ./wmicon-admin-64.png shinythings-we
  334. bmirror-admin
  335. _MANUALPAGE
  336. }
  337. usage()
  338. {
  339. cat << _USAGE
  340. xdg-desktop-menu -- command line tool for (un)installing
  341. desktop menu items
  342. Synopsis
  343. xdg-desktop-menu install [--noupdate] [--novendor] [--mode
  344. mode] directory-file(s) desktop-file(s)
  345. xdg-desktop-menu uninstall [--noupdate] [--mode mode]
  346. directory-file(s) desktop-file(s)
  347. xdg-desktop-menu forceupdate [--mode mode]
  348. xdg-desktop-menu { --help | --manual | --version }
  349. _USAGE
  350. }
  351. #@xdg-utils-common@
  352. #----------------------------------------------------------------------------
  353. # Common utility functions included in all XDG wrapper scripts
  354. #----------------------------------------------------------------------------
  355. DEBUG()
  356. {
  357. [ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && return 0;
  358. [ ${XDG_UTILS_DEBUG_LEVEL} -lt $1 ] && return 0;
  359. shift
  360. echo "$@" >&2
  361. }
  362. # This handles backslashes but not quote marks.
  363. first_word()
  364. {
  365. read first rest
  366. echo "$first"
  367. }
  368. #-------------------------------------------------------------
  369. # map a binary to a .desktop file
  370. binary_to_desktop_file()
  371. {
  372. search="${XDG_DATA_HOME:-$HOME/.local/share}:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
  373. binary="`which "$1"`"
  374. binary="`readlink -f "$binary"`"
  375. base="`basename "$binary"`"
  376. IFS=:
  377. for dir in $search; do
  378. unset IFS
  379. [ "$dir" ] || continue
  380. [ -d "$dir/applications" ] || [ -d "$dir/applnk" ] || continue
  381. for file in "$dir"/applications/*.desktop "$dir"/applications/*/*.desktop "$dir"/applnk/*.desktop "$dir"/applnk/*/*.desktop; do
  382. [ -r "$file" ] || continue
  383. # Check to make sure it's worth the processing.
  384. grep -q "^Exec.*$base" "$file" || continue
  385. # Make sure it's a visible desktop file (e.g. not "preferred-web-browser.desktop").
  386. grep -Eq "^(NoDisplay|Hidden)=true" "$file" && continue
  387. command="`grep -E "^Exec(\[[^]=]*])?=" "$file" | cut -d= -f 2- | first_word`"
  388. command="`which "$command"`"
  389. if [ x"`readlink -f "$command"`" = x"$binary" ]; then
  390. # Fix any double slashes that got added path composition
  391. echo "$file" | sed -e 's,//*,/,g'
  392. return
  393. fi
  394. done
  395. done
  396. }
  397. #-------------------------------------------------------------
  398. # map a .desktop file to a binary
  399. desktop_file_to_binary()
  400. {
  401. search="${XDG_DATA_HOME:-$HOME/.local/share}:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
  402. desktop="`basename "$1"`"
  403. IFS=:
  404. for dir in $search; do
  405. unset IFS
  406. [ "$dir" ] && [ -d "$dir/applications" ] || [ -d "$dir/applnk" ] || continue
  407. # Check if desktop file contains -
  408. if [ "${desktop#*-}" != "$desktop" ]; then
  409. vendor=${desktop%-*}
  410. app=${desktop#*-}
  411. if [ -r $dir/applications/$vendor/$app ]; then
  412. file_path=$dir/applications/$vendor/$app
  413. elif [ -r $dir/applnk/$vendor/$app ]; then
  414. file_path=$dir/applnk/$vendor/$app
  415. fi
  416. fi
  417. if test -z "$file_path" ; then
  418. for indir in "$dir"/applications/ "$dir"/applications/*/ "$dir"/applnk/ "$dir"/applnk/*/; do
  419. file="$indir/$desktop"
  420. if [ -r "$file" ]; then
  421. file_path=$file
  422. break
  423. fi
  424. done
  425. fi
  426. if [ -r "$file_path" ]; then
  427. # Remove any arguments (%F, %f, %U, %u, etc.).
  428. command="`grep -E "^Exec(\[[^]=]*])?=" "$file_path" | cut -d= -f 2- | first_word`"
  429. command="`which "$command"`"
  430. readlink -f "$command"
  431. return
  432. fi
  433. done
  434. }
  435. #-------------------------------------------------------------
  436. # Exit script on successfully completing the desired operation
  437. exit_success()
  438. {
  439. if [ $# -gt 0 ]; then
  440. echo "$@"
  441. echo
  442. fi
  443. exit 0
  444. }
  445. #-----------------------------------------
  446. # Exit script on malformed arguments, not enough arguments
  447. # or missing required option.
  448. # prints usage information
  449. exit_failure_syntax()
  450. {
  451. if [ $# -gt 0 ]; then
  452. echo "xdg-desktop-menu: $@" >&2
  453. echo "Try 'xdg-desktop-menu --help' for more information." >&2
  454. else
  455. usage
  456. echo "Use 'man xdg-desktop-menu' or 'xdg-desktop-menu --manual' for additional info."
  457. fi
  458. exit 1
  459. }
  460. #-------------------------------------------------------------
  461. # Exit script on missing file specified on command line
  462. exit_failure_file_missing()
  463. {
  464. if [ $# -gt 0 ]; then
  465. echo "xdg-desktop-menu: $@" >&2
  466. fi
  467. exit 2
  468. }
  469. #-------------------------------------------------------------
  470. # Exit script on failure to locate necessary tool applications
  471. exit_failure_operation_impossible()
  472. {
  473. if [ $# -gt 0 ]; then
  474. echo "xdg-desktop-menu: $@" >&2
  475. fi
  476. exit 3
  477. }
  478. #-------------------------------------------------------------
  479. # Exit script on failure returned by a tool application
  480. exit_failure_operation_failed()
  481. {
  482. if [ $# -gt 0 ]; then
  483. echo "xdg-desktop-menu: $@" >&2
  484. fi
  485. exit 4
  486. }
  487. #------------------------------------------------------------
  488. # Exit script on insufficient permission to read a specified file
  489. exit_failure_file_permission_read()
  490. {
  491. if [ $# -gt 0 ]; then
  492. echo "xdg-desktop-menu: $@" >&2
  493. fi
  494. exit 5
  495. }
  496. #------------------------------------------------------------
  497. # Exit script on insufficient permission to write a specified file
  498. exit_failure_file_permission_write()
  499. {
  500. if [ $# -gt 0 ]; then
  501. echo "xdg-desktop-menu: $@" >&2
  502. fi
  503. exit 6
  504. }
  505. check_input_file()
  506. {
  507. if [ ! -e "$1" ]; then
  508. exit_failure_file_missing "file '$1' does not exist"
  509. fi
  510. if [ ! -r "$1" ]; then
  511. exit_failure_file_permission_read "no permission to read file '$1'"
  512. fi
  513. }
  514. check_vendor_prefix()
  515. {
  516. file_label="$2"
  517. [ -n "$file_label" ] || file_label="filename"
  518. file=`basename "$1"`
  519. case "$file" in
  520. [[:alpha:]]*-*)
  521. return
  522. ;;
  523. esac
  524. echo "xdg-desktop-menu: $file_label '$file' does not have a proper vendor prefix" >&2
  525. echo 'A vendor prefix consists of alpha characters ([a-zA-Z]) and is terminated' >&2
  526. echo 'with a dash ("-"). An example '"$file_label"' is '"'example-$file'" >&2
  527. echo "Use --novendor to override or 'xdg-desktop-menu --manual' for additional info." >&2
  528. exit 1
  529. }
  530. check_output_file()
  531. {
  532. # if the file exists, check if it is writeable
  533. # if it does not exists, check if we are allowed to write on the directory
  534. if [ -e "$1" ]; then
  535. if [ ! -w "$1" ]; then
  536. exit_failure_file_permission_write "no permission to write to file '$1'"
  537. fi
  538. else
  539. DIR=`dirname "$1"`
  540. if [ ! -w "$DIR" ] || [ ! -x "$DIR" ]; then
  541. exit_failure_file_permission_write "no permission to create file '$1'"
  542. fi
  543. fi
  544. }
  545. #----------------------------------------
  546. # Checks for shared commands, e.g. --help
  547. check_common_commands()
  548. {
  549. while [ $# -gt 0 ] ; do
  550. parm="$1"
  551. shift
  552. case "$parm" in
  553. --help)
  554. usage
  555. echo "Use 'man xdg-desktop-menu' or 'xdg-desktop-menu --manual' for additional info."
  556. exit_success
  557. ;;
  558. --manual)
  559. manualpage
  560. exit_success
  561. ;;
  562. --version)
  563. echo "xdg-desktop-menu 1.1.3"
  564. exit_success
  565. ;;
  566. esac
  567. done
  568. }
  569. check_common_commands "$@"
  570. [ -z "${XDG_UTILS_DEBUG_LEVEL}" ] && unset XDG_UTILS_DEBUG_LEVEL;
  571. if [ ${XDG_UTILS_DEBUG_LEVEL-0} -lt 1 ]; then
  572. # Be silent
  573. xdg_redirect_output=" > /dev/null 2> /dev/null"
  574. else
  575. # All output to stderr
  576. xdg_redirect_output=" >&2"
  577. fi
  578. #--------------------------------------
  579. # Checks for known desktop environments
  580. # set variable DE to the desktop environments name, lowercase
  581. detectDE()
  582. {
  583. # see https://bugs.freedesktop.org/show_bug.cgi?id=34164
  584. unset GREP_OPTIONS
  585. if [ -n "${XDG_CURRENT_DESKTOP}" ]; then
  586. case "${XDG_CURRENT_DESKTOP}" in
  587. # only recently added to menu-spec, pre-spec X- still in use
  588. Cinnamon|X-Cinnamon)
  589. DE=cinnamon;
  590. ;;
  591. ENLIGHTENMENT)
  592. DE=enlightenment;
  593. ;;
  594. # GNOME, GNOME-Classic:GNOME, or GNOME-Flashback:GNOME
  595. GNOME*)
  596. DE=gnome;
  597. ;;
  598. KDE)
  599. DE=kde;
  600. ;;
  601. # Deepin Desktop Environments
  602. DEEPIN|Deepin|deepin)
  603. DE=dde;
  604. ;;
  605. LXDE)
  606. DE=lxde;
  607. ;;
  608. LXQt)
  609. DE=lxqt;
  610. ;;
  611. MATE)
  612. DE=mate;
  613. ;;
  614. XFCE)
  615. DE=xfce
  616. ;;
  617. X-Generic)
  618. DE=generic
  619. ;;
  620. esac
  621. fi
  622. if [ x"$DE" = x"" ]; then
  623. # classic fallbacks
  624. if [ x"$KDE_FULL_SESSION" != x"" ]; then DE=kde;
  625. elif [ x"$GNOME_DESKTOP_SESSION_ID" != x"" ]; then DE=gnome;
  626. elif [ x"$MATE_DESKTOP_SESSION_ID" != x"" ]; then DE=mate;
  627. elif `dbus-send --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:org.gnome.SessionManager > /dev/null 2>&1` ; then DE=gnome;
  628. elif xprop -root _DT_SAVE_MODE 2> /dev/null | grep ' = \"xfce4\"$' >/dev/null 2>&1; then DE=xfce;
  629. elif xprop -root 2> /dev/null | grep -i '^xfce_desktop_window' >/dev/null 2>&1; then DE=xfce
  630. elif echo $DESKTOP | grep -q '^Enlightenment'; then DE=enlightenment;
  631. elif [ x"$LXQT_SESSION_CONFIG" != x"" ]; then DE=lxqt;
  632. fi
  633. fi
  634. if [ x"$DE" = x"" ]; then
  635. # fallback to checking $DESKTOP_SESSION
  636. case "$DESKTOP_SESSION" in
  637. gnome)
  638. DE=gnome;
  639. ;;
  640. LXDE|Lubuntu)
  641. DE=lxde;
  642. ;;
  643. MATE)
  644. DE=mate;
  645. ;;
  646. xfce|xfce4|'Xfce Session')
  647. DE=xfce;
  648. ;;
  649. esac
  650. fi
  651. if [ x"$DE" = x"" ]; then
  652. # fallback to uname output for other platforms
  653. case "$(uname 2>/dev/null)" in
  654. CYGWIN*)
  655. DE=cygwin;
  656. ;;
  657. Darwin)
  658. DE=darwin;
  659. ;;
  660. esac
  661. fi
  662. if [ x"$DE" = x"gnome" ]; then
  663. # gnome-default-applications-properties is only available in GNOME 2.x
  664. # but not in GNOME 3.x
  665. which gnome-default-applications-properties > /dev/null 2>&1 || DE="gnome3"
  666. fi
  667. if [ -f "$XDG_RUNTIME_DIR/flatpak-info" ]; then
  668. DE="flatpak"
  669. fi
  670. }
  671. #----------------------------------------------------------------------------
  672. # kfmclient exec/openURL can give bogus exit value in KDE <= 3.5.4
  673. # It also always returns 1 in KDE 3.4 and earlier
  674. # Simply return 0 in such case
  675. kfmclient_fix_exit_code()
  676. {
  677. version=`LC_ALL=C.UTF-8 kde-config --version 2>/dev/null | grep '^KDE'`
  678. major=`echo $version | sed 's/KDE.*: \([0-9]\).*/\1/'`
  679. minor=`echo $version | sed 's/KDE.*: [0-9]*\.\([0-9]\).*/\1/'`
  680. release=`echo $version | sed 's/KDE.*: [0-9]*\.[0-9]*\.\([0-9]\).*/\1/'`
  681. test "$major" -gt 3 && return $1
  682. test "$minor" -gt 5 && return $1
  683. test "$release" -gt 4 && return $1
  684. return 0
  685. }
  686. #----------------------------------------------------------------------------
  687. # Returns true if there is a graphical display attached.
  688. has_display()
  689. {
  690. if [ -n "$DISPLAY" ] || [ -n "$WAYLAND_DISPLAY" ]; then
  691. return 0
  692. else
  693. return 1
  694. fi
  695. }
  696. update_desktop_database()
  697. {
  698. # echo Update desktop database: $mode
  699. if [ "$mode" = "system" ] ; then
  700. for x in `echo $PATH | sed 's/:/ /g'` /opt/gnome/bin; do
  701. if [ -x $x/update-desktop-database ] ; then
  702. DEBUG 1 "Running $x/update-desktop-database"
  703. eval '$x/update-desktop-database'$xdg_redirect_output
  704. return
  705. fi
  706. done
  707. fi
  708. }
  709. # Make application $1/$2 the default for all the mimetypes it support,
  710. # iff such mimetype didn't had a default application already.
  711. # $1 Install dir for desktop file
  712. # $2 base name of desktop file
  713. make_lazy_default()
  714. {
  715. local mimetypes
  716. local xdg_user_dir
  717. local xdg_default_dirs
  718. DEBUG 1 "make_lazy_default $1/$2"
  719. mimetypes=`awk '
  720. {
  721. if (match($0,/MimeType=/)) {
  722. split(substr($0,RSTART+9),mimetypes,";")
  723. for (n in mimetypes)
  724. {
  725. if (mimetypes[n])
  726. print mimetypes[n]
  727. }
  728. }
  729. }' "$1/$2" 2> /dev/null`
  730. for MIME in $mimetypes ; do
  731. xdg_default_dirs="$XDG_DATA_DIRS"
  732. [ -n "$xdg_default_dirs" ] || xdg_default_dirs=/usr/local/share/:/usr/share/
  733. if [ x"$mode" = x"user" ] ; then
  734. xdg_user_dir="$XDG_DATA_HOME"
  735. [ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.local/share"
  736. xdg_default_dirs="$xdg_user_dir:$xdg_default_dirs"
  737. fi
  738. local default_app
  739. for x in `echo "$xdg_default_dirs" | sed 's/:/ /g'`; do
  740. DEBUG 2 "Checking $x/applications/defaults.list"
  741. default_app=`grep "$MIME=" $x/applications/defaults.list 2> /dev/null | cut -d '=' -f 2`
  742. if [ -n "$default_app" ] ; then
  743. DEBUG 2 "Found default apps for $MIME: $default_app"
  744. default_app="$default_app;"
  745. break;
  746. fi
  747. done
  748. DEBUG 2 "Current default apps for $MIME: $default_app"
  749. if echo "$default_app" | grep "$2" > /dev/null 2> /dev/null; then
  750. # App already listed as default
  751. continue;
  752. fi
  753. default_file="$(readlink -f "$1/defaults.list")"
  754. DEBUG 1 "Updating $default_file"
  755. grep -v "$MIME=" $default_file > ${default_file}.new 2> /dev/null
  756. if ! grep "[Default Applications]" ${default_file}.new > /dev/null; then
  757. echo "[Default Applications]" >> ${default_file}.new
  758. fi
  759. echo $MIME="$default_app$2" >> ${default_file}.new
  760. mv ${default_file}.new $default_file
  761. done
  762. }
  763. update_submenu()
  764. {
  765. DEBUG 1 "update_submenu $1"
  766. menu_file="$1"
  767. xdg_dir_name=menus
  768. xdg_user_dir="$XDG_CONFIG_HOME"
  769. [ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.config"
  770. xdg_user_dir="$xdg_user_dir/$xdg_dir_name"
  771. xdg_system_dirs="$XDG_CONFIG_DIRS"
  772. [ -n "$xdg_system_dirs" ] || xdg_system_dirs=/etc/xdg
  773. xdg_global_dir=
  774. for x in `echo $xdg_system_dirs | sed 's/:/ /g'` ; do
  775. if [ -w $x/$xdg_dir_name ] ; then
  776. xdg_global_dir="$x/$xdg_dir_name"
  777. break
  778. fi
  779. done
  780. xdg_user_dir="$xdg_user_dir/applications-merged"
  781. xdg_global_dir="$xdg_global_dir/applications-merged"
  782. DEBUG 3 "Install locations for *.menu file:"
  783. DEBUG 3 "xdg_user_dir: $xdg_user_dir"
  784. DEBUG 3 "xdg_global_dir: $xdg_global_dir"
  785. DEBUG 3 "kde_user_dir: $kde_user_dir"
  786. DEBUG 3 "kde_global_dir: $kde_global_dir"
  787. if [ x"$mode" = x"user" ] ; then
  788. xdg_dir="$xdg_user_dir"
  789. kde_dir="$kde_user_dir"
  790. my_umask=077
  791. my_chmod=0600
  792. else
  793. xdg_dir="$xdg_global_dir"
  794. kde_dir="$kde_global_dir"
  795. my_umask=022
  796. my_chmod=0644
  797. if [ -z "${xdg_dir}${kde_dir}" ] ; then
  798. exit_failure_operation_impossible "No writable system menu directory found."
  799. fi
  800. fi
  801. if [ -z "$menu_file" ] ; then
  802. # Work around for SUSE/gnome 2.12 to pick up new ~/.local/share/applications
  803. save_umask=`umask`
  804. umask $my_umask
  805. mkdir -p $xdg_dir
  806. touch $xdg_dir/xdg-desktop-menu-dummy.menu
  807. umask $save_umask
  808. return
  809. fi
  810. if [ $action = "install" ] && [ -f "/etc/mandrake-release" ] ; then
  811. # Work around for Mandriva 2006
  812. mandrake_xdg_dir=`echo "$xdg_dir" | sed -e 's^/applications-merged^/applications-mdk-merged^'`
  813. if [ ! -e "$mandrake_xdg_dir" ] ; then
  814. DEBUG 1 "Mandriva Workaround: Link '$xdg_dir' to '$mandrake_xdg_dir'"
  815. mkdir -p `dirname "$mandrake_xdg_dir"`
  816. eval 'ln -s "applications-merged" "$mandrake_xdg_dir"'$xdg_redirect_output
  817. fi
  818. fi
  819. if [ $action = "install" -a x"$mode" = x"user" ] && [ -d "/etc/xdg/menus/kde-applications-merged" ] ; then
  820. # Work around for Fedora Core 5 + patched KDE
  821. kde_xdg_dir=`echo "$xdg_dir" | sed -e 's^/applications-merged^/kde-applications-merged^'`
  822. if [ ! -e "$kde_xdg_dir" ] ; then
  823. DEBUG 1 "Fedora Workaround: Link '$xdg_dir' to '$kde_xdg_dir'"
  824. mkdir -p `dirname "$kde_xdg_dir"`
  825. eval 'ln -s "applications-merged" "$kde_xdg_dir"'$xdg_redirect_output
  826. fi
  827. fi
  828. if [ $action = "install" -a x"$mode" = x"system" ] && [ -d "/etc/xdg/menus/kde-applications-merged" ] && [ ! -d "/etc/xdg/menus/applications-merged" ] ; then
  829. # Work around for Kubuntu 6.06
  830. kde_xdg_dir=`echo "$xdg_dir" | sed -e 's^/applications-merged^/kde-applications-merged^'`
  831. DEBUG 1 "Kubuntu Workaround: Link '$xdg_dir' to 'kde-applications-merged'"
  832. eval 'ln -s "kde-applications-merged" "$xdg_dir"'$xdg_redirect_output
  833. fi
  834. orig_menu_file=$xdg_dir/$menu_file
  835. DEBUG 1 "Updating $orig_menu_file ($action)"
  836. test "${TMPDIR+set}" = set || TMPDIR=/tmp
  837. tmpfile=`mktemp $TMPDIR/tmp.XXXXXXXXXX`
  838. orig_desktop_files=
  839. if [ -r "$orig_menu_file" ] ; then
  840. awk '
  841. # List all files within <Filename> tags
  842. BEGIN {
  843. RS="<"
  844. }
  845. /^Filename/ {
  846. if (match($0,/>/)) {
  847. print substr($0,RSTART+1)
  848. }
  849. }' $orig_menu_file > $tmpfile
  850. fi
  851. orig_desktop_files=`cat $tmpfile`
  852. new_desktop_files=
  853. if [ $action = "install" ] ; then
  854. for desktop_file in $desktop_files; do
  855. basefile=`basename "$desktop_file"`
  856. if ! grep '^'$basefile'$' $tmpfile > /dev/null 2> /dev/null ; then
  857. # Append
  858. echo "$basefile" >> $tmpfile
  859. fi
  860. done
  861. new_desktop_files=`cat $tmpfile`
  862. fi
  863. if [ $action = "uninstall" ] ; then
  864. echo > $tmpfile
  865. for desktop_file in $desktop_files; do
  866. echo "$desktop_file" >> $tmpfile
  867. done
  868. # Files to uninstall are listed in $tmpfile
  869. # Existing files are in $orig_desktop_files
  870. if [ ! -z "$orig_desktop_files" ]; then
  871. for desktop_file in $orig_desktop_files; do
  872. if ! grep '^'$desktop_file'$' $tmpfile > /dev/null 2> /dev/null; then
  873. # Keep this file, it's not in the uninstall list
  874. new_desktop_files="$new_desktop_files $desktop_file"
  875. fi
  876. done
  877. fi
  878. fi
  879. rm -f "$tmpfile"
  880. DEBUG 3 "Files to list in $menu_file: $new_desktop_files"
  881. if [ -n "$new_desktop_files" ] ; then
  882. # Install/update
  883. test "${TMPDIR+set}" = set || TMPDIR=/tmp
  884. tmpfile=`mktemp $TMPDIR/tmp.XXXXXXXXXX`
  885. (
  886. echo '<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN"'
  887. echo ' "http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd">'
  888. echo '<!-- Do not edit manually - generated and managed by xdg-desktop-menu -->'
  889. echo '<Menu>'
  890. echo ' <Name>Applications</Name>'
  891. for desktop_file in $directory_files; do
  892. basefile=`basename "$desktop_file"`
  893. basefilename=`echo "$basefile"|cut -d '.' -f 1`
  894. echo "<Menu>"
  895. echo " <Name>$basefilename</Name>"
  896. echo " <Directory>$basefile</Directory>"
  897. done
  898. echo " <Include>"
  899. for desktop_file in $new_desktop_files; do
  900. echo " <Filename>$desktop_file</Filename>"
  901. done
  902. echo " </Include>"
  903. for desktop_file in $directory_files; do
  904. echo "</Menu>"
  905. done
  906. echo '</Menu>'
  907. ) > $tmpfile
  908. chmod $my_chmod $tmpfile
  909. save_umask=`umask`
  910. umask $my_umask
  911. mkdir -p $xdg_dir
  912. eval 'cp $tmpfile $xdg_dir/$menu_file'$xdg_redirect_output
  913. umask $save_umask
  914. rm -f "$tmpfile"
  915. else
  916. # Uninstall
  917. rm -f $xdg_dir/$menu_file
  918. fi
  919. # Uninstall .directory files only if no longer referenced
  920. if [ $action = "uninstall" ] ; then
  921. test "${TMPDIR+set}" = set || TMPDIR=/tmp
  922. tmpfile=`mktemp $TMPDIR/tmp.XXXXXXXXXX`
  923. for menu_file in $xdg_dir/*; do
  924. if grep 'generated and managed by xdg-desktop-menu' "$menu_file" > /dev/null 2> /dev/null; then
  925. awk '
  926. # List all files within <Directory> tags
  927. BEGIN {
  928. RS="<"
  929. }
  930. /^Directory/ {
  931. if (match($0,/>/)) {
  932. print substr($0,RSTART+1)
  933. }
  934. }' "$menu_file" >> $tmpfile
  935. fi
  936. done
  937. orig_directory_files="$directory_files"
  938. directory_files=
  939. for desktop_file in $orig_directory_files; do
  940. if ! grep '^'$desktop_file'$' $tmpfile > /dev/null 2> /dev/null; then
  941. # No longer in use, safe to delete
  942. directory_files="$directory_files $desktop_file"
  943. fi
  944. done
  945. rm -f "$tmpfile"
  946. fi
  947. }
  948. [ x"$1" != x"" ] || exit_failure_syntax
  949. mode=
  950. action=
  951. update=yes
  952. desktop_files=
  953. directory_files=
  954. case $1 in
  955. install)
  956. action=install
  957. ;;
  958. uninstall)
  959. action=uninstall
  960. ;;
  961. forceupdate)
  962. action=forceupdate
  963. ;;
  964. *)
  965. exit_failure_syntax "unknown command '$1'"
  966. ;;
  967. esac
  968. shift
  969. vendor=true
  970. while [ $# -gt 0 ] ; do
  971. parm="$1"
  972. shift
  973. case "$parm" in
  974. --noupdate)
  975. update=no
  976. ;;
  977. --mode)
  978. if [ -z "$1" ] ; then
  979. exit_failure_syntax "mode argument missing for --mode"
  980. fi
  981. case "$1" in
  982. user)
  983. mode="user"
  984. ;;
  985. system)
  986. mode="system"
  987. ;;
  988. *)
  989. exit_failure_syntax "unknown mode '$1'"
  990. ;;
  991. esac
  992. shift
  993. ;;
  994. --novendor)
  995. vendor=false
  996. ;;
  997. -*)
  998. exit_failure_syntax "unexpected option '$parm'"
  999. ;;
  1000. *)
  1001. if [ "$action" = "install" ] ; then
  1002. check_input_file "$parm"
  1003. fi
  1004. case "$parm" in
  1005. *.directory)
  1006. if [ -n "$desktop_files" ] ; then
  1007. exit_failure_syntax "'$parm' must precede any *.desktop file"
  1008. fi
  1009. directory_files="$directory_files $parm"
  1010. ;;
  1011. *.desktop)
  1012. desktop_files="$desktop_files $parm"
  1013. ;;
  1014. *)
  1015. exit_failure_syntax "file to $action must be a *.directory or *.desktop file"
  1016. ;;
  1017. esac
  1018. ;;
  1019. esac
  1020. done
  1021. # Shouldn't happen
  1022. if [ -z "$action" ] ; then
  1023. exit_failure_syntax "command argument missing"
  1024. fi
  1025. if [ -n "$XDG_UTILS_INSTALL_MODE" ] ; then
  1026. if [ "$XDG_UTILS_INSTALL_MODE" = "system" ] ; then
  1027. mode="system"
  1028. elif [ "$XDG_UTILS_INSTALL_MODE" = "user" ] ; then
  1029. mode="user"
  1030. fi
  1031. fi
  1032. if [ -z "$mode" ] ; then
  1033. if [ `whoami` = "root" ] ; then
  1034. mode="system"
  1035. else
  1036. mode="user"
  1037. fi
  1038. fi
  1039. if [ x"$action" = x"forceupdate" ] ; then
  1040. update_desktop_database
  1041. exit_success
  1042. fi
  1043. if [ -z "$desktop_files" ] ; then
  1044. exit_failure_syntax "desktop-file argument missing"
  1045. fi
  1046. menu_name=
  1047. for desktop_file in $directory_files; do
  1048. if [ "$vendor" = "true" -a "$action" = "install" ] ; then
  1049. check_vendor_prefix "$desktop_file"
  1050. fi
  1051. basefilename=`basename "$desktop_file" | cut -d '.' -f 1`
  1052. if [ -z "$menu_name" ] ; then
  1053. menu_name="$basefilename"
  1054. else
  1055. menu_name="$menu_name-$basefilename"
  1056. fi
  1057. done
  1058. if [ -n "$menu_name" ] ; then
  1059. if [ x"$mode" = x"user" ] ; then
  1060. update_submenu "user-$menu_name.menu"
  1061. else
  1062. update_submenu "$menu_name.menu"
  1063. fi
  1064. else
  1065. # Work around for SUSE/gnome 2.12 to pick up new ~/.local/share/applications
  1066. if [ x"$mode" = x"user" ] ; then
  1067. update_submenu
  1068. fi
  1069. fi
  1070. # Install *.directory files
  1071. xdg_dir_name=desktop-directories
  1072. xdg_user_dir="$XDG_DATA_HOME"
  1073. [ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.local/share"
  1074. xdg_user_dir="$xdg_user_dir/$xdg_dir_name"
  1075. xdg_system_dirs="$XDG_DATA_DIRS"
  1076. [ -n "$xdg_system_dirs" ] || xdg_system_dirs=/usr/local/share/:/usr/share/
  1077. xdg_global_dir=
  1078. for x in `echo $xdg_system_dirs | sed 's/:/ /g'` ; do
  1079. if [ -w $x/$xdg_dir_name ] ; then
  1080. xdg_global_dir="$x/$xdg_dir_name"
  1081. break
  1082. fi
  1083. done
  1084. DEBUG 3 "Install locations for *.directory files:"
  1085. DEBUG 3 "xdg_user_dir: $xdg_user_dir"
  1086. DEBUG 3 "xdg_global_dir: $xdg_global_dir"
  1087. DEBUG 3 "kde_user_dir: $kde_user_dir"
  1088. DEBUG 3 "kde_global_dir: $kde_global_dir"
  1089. if [ x"$mode" = x"user" ] ; then
  1090. xdg_dir="$xdg_user_dir"
  1091. kde_dir="$kde_user_dir"
  1092. my_umask=077
  1093. else
  1094. xdg_dir="$xdg_global_dir"
  1095. kde_dir="$kde_global_dir"
  1096. my_umask=022
  1097. if [ -z "${xdg_dir}${kde_dir}" ] ; then
  1098. exit_failure_operation_impossible "No writable system menu directory found."
  1099. fi
  1100. fi
  1101. for desktop_file in $directory_files; do
  1102. basefile=`basename "$desktop_file"`
  1103. DEBUG 1 "$action $desktop_file in $xdg_dir $kde_dir"
  1104. case $action in
  1105. install)
  1106. save_umask=`umask`
  1107. umask $my_umask
  1108. for x in $xdg_dir $kde_dir ; do
  1109. mkdir -p $x
  1110. eval 'cp $desktop_file $x/$basefile'$xdg_redirect_output
  1111. done
  1112. umask $save_umask
  1113. ;;
  1114. uninstall)
  1115. for x in $xdg_dir $kde_dir ; do
  1116. rm -f $x/$basefile
  1117. done
  1118. ;;
  1119. esac
  1120. done
  1121. # Install *.desktop files
  1122. xdg_dir_name=applications
  1123. xdg_user_dir="$XDG_DATA_HOME"
  1124. [ -n "$xdg_user_dir" ] || xdg_user_dir="$HOME/.local/share"
  1125. xdg_user_dir="$xdg_user_dir/$xdg_dir_name"
  1126. xdg_system_dirs="$XDG_DATA_DIRS"
  1127. [ -n "$xdg_system_dirs" ] || xdg_system_dirs=/usr/local/share/:/usr/share/
  1128. xdg_global_dir=
  1129. for x in `echo $xdg_system_dirs | sed 's/:/ /g'` ; do
  1130. if [ -w $x/$xdg_dir_name ] ; then
  1131. xdg_global_dir="$x/$xdg_dir_name"
  1132. break
  1133. fi
  1134. done
  1135. kde_user_dir=`kde${KDE_SESSION_VERSION}-config --path apps 2> /dev/null | cut -d ':' -f 1`
  1136. kde_global_dir=`kde${KDE_SESSION_VERSION}-config --path apps 2> /dev/null | cut -d ':' -f 2`
  1137. [ -w $kde_global_dir ] || kde_global_dir=
  1138. DEBUG 3 "Install locations for *.desktop files:"
  1139. DEBUG 3 "xdg_user_dir: $xdg_user_dir"
  1140. DEBUG 3 "xdg_global_dir: $xdg_global_dir"
  1141. DEBUG 3 "kde_user_dir: $kde_user_dir"
  1142. DEBUG 3 "kde_global_dir: $kde_global_dir"
  1143. if [ x"$mode" = x"user" ] ; then
  1144. xdg_dir="$xdg_user_dir"
  1145. kde_dir="$kde_user_dir"
  1146. my_umask=077
  1147. else
  1148. xdg_dir="$xdg_global_dir"
  1149. kde_dir="$kde_global_dir"
  1150. my_umask=022
  1151. if [ -z "${xdg_dir}${kde_dir}" ] ; then
  1152. exit_failure_operation_impossible "No writable system menu directory found."
  1153. fi
  1154. fi
  1155. for desktop_file in $desktop_files; do
  1156. if [ "$vendor" = "true" -a "$action" = "install" ] ; then
  1157. check_vendor_prefix "$desktop_file"
  1158. fi
  1159. basefile=`basename "$desktop_file"`
  1160. DEBUG 1 "$action $desktop_file in $xdg_dir $kde_dir"
  1161. case $action in
  1162. install)
  1163. save_umask=`umask`
  1164. umask $my_umask
  1165. for x in $xdg_dir $kde_dir ; do
  1166. mkdir -p $x
  1167. eval 'cp $desktop_file $x/$basefile'$xdg_redirect_output
  1168. done
  1169. if [ -f $kde_dir/$basefile ] ; then
  1170. echo "OnlyShowIn=Old;" >> $kde_dir/$basefile
  1171. fi
  1172. make_lazy_default "$xdg_dir" "$basefile"
  1173. umask $save_umask
  1174. ;;
  1175. uninstall)
  1176. for x in $xdg_dir $kde_dir ; do
  1177. rm -f $x/$basefile
  1178. done
  1179. ;;
  1180. esac
  1181. done
  1182. if [ x"$update" = x"yes" ] ; then
  1183. update_desktop_database
  1184. fi
  1185. exit_success