diff options
146 files changed, 11620 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..0c70587 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,50 @@ +=== No ChangeLog === + + Since this module is using git, we rely on commit messages to provide change + history. Please write commit messages in the format described at + http://live.gnome.org/Git/CommitMessages + + Below is a copy of this format: + +=== begin example commit === +tag: Short explanation of the commit + +Longer explanation explaining exactly what's changed, whether any +external or private interfaces changed, what bugs were fixed (with bug +tracker reference if applicable) and so forth. Be concise but not too brief. +=== end example commit === + + - The commit message is mainly for the other people, so they should be able + to understand it now and six months later. + + - Always add a brief description of the commit to the _first_ line of the + commit and terminate by two newlines (it will work without the second + newline, but that is not nice for the interfaces). + + - First line (the brief description) must only be one sentence and should + start with a capital letter unless it starts with a lowercase symbol or + identifier. Don't use a trailing period either. Don't exceed 72 characters. + + - You can prefix the first line with one tag, to make it easier to know to + which part of the module the commit applies. For example, a commit with + "fish: Make it work with newer fortune" in the gnome-panel module clearly + applies to the fish applet. + + - The main description (the body) is normal prose and should use normal + punctuation and capital letters where appropriate. Normally, for patches + sent to a mailing list, the body is copied from there. This main + description can be empty if the change is self-explanatory (eg: "Add DOAP + file"). + + - When committing code on behalf of others use the --author option, e.g. git + commit -a --author "Joe Coder <joe@coder.org>". + + - When referring to a bug, you can use this form: bgo#12345. Use bgo for + bugzilla.gnome.org, but you can also reference bugs in other bug trackers: + rh means bugzilla.redhat.com, bnc means bugzilla.novell.com, lp means + launchpad.net, etc. Whenever possible, use the full URL of the bug, though. + + - When a commit closes a bug, the commit message should contain a line like: + Closes: http://bugzilla.gnome.org/show_bug.cgi?id=12345 + or simply: + http://bugzilla.gnome.org/show_bug.cgi?id=12345 @@ -0,0 +1,16 @@ +xdg-specs +========= + +This repository contains the XDG specifications. + +To discuss the specifications, you may use the xdg mailing list: + + http://lists.freedesktop.org/mailman/listinfo/xdg + + +How to report issues +==================== + +Issues should be reported to the freedesktop.org bug tracking system: + + https://bugs.freedesktop.org/ (product Specifications) diff --git a/autostart/.cvsignore b/autostart/.cvsignore new file mode 100644 index 0000000..f5518ef --- /dev/null +++ b/autostart/.cvsignore @@ -0,0 +1,14 @@ +config.log +config.status +config.sub +configure +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +config.guess +config.h +config.h.in +install-sh +missing +autostart-spec.html diff --git a/autostart/AUTHORS b/autostart/AUTHORS new file mode 100644 index 0000000..cc42641 --- /dev/null +++ b/autostart/AUTHORS @@ -0,0 +1,5 @@ +John Palmieri <johnp@redhat.com> +Kévin Ottens <ervin@ipsquad.net> +Renato Caldas <seventhguardian_@hotmail.com> +Rodrigo Moya <rodrigo@gnome-db.org> +Waldo Bastian <waldo.bastian@intel.com> diff --git a/autostart/COPYING b/autostart/COPYING new file mode 100644 index 0000000..73e7995 --- /dev/null +++ b/autostart/COPYING @@ -0,0 +1,2 @@ +FIXME - we need a license for specs + diff --git a/autostart/ChangeLog b/autostart/ChangeLog new file mode 100644 index 0000000..b7b5318 --- /dev/null +++ b/autostart/ChangeLog @@ -0,0 +1,4 @@ +2006-02-13 Waldo Bastian <waldo.bastian@intel.com> + + * Import of autostart spec + diff --git a/autostart/INSTALL b/autostart/INSTALL new file mode 100644 index 0000000..56b077d --- /dev/null +++ b/autostart/INSTALL @@ -0,0 +1,236 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free +Software Foundation, Inc. + +This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + +These are generic installation instructions. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. (Caching is +disabled by default to prevent problems with accidental use of stale +cache files.) + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You only need +`configure.ac' if you want to change it or regenerate `configure' using +a newer version of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. If you're + using `csh' on an old version of System V, you might need to type + `sh ./configure' instead to prevent `csh' from trying to execute + `configure' itself. + + Running `configure' takes awhile. While running, it prints some + messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + +Compilers and Options +===================== + +Some systems require unusual options for compilation or linking that the +`configure' script does not know about. Run `./configure --help' for +details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + +You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you must use a version of `make' that +supports the `VPATH' variable, such as GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + If you have to use a `make' that does not support the `VPATH' +variable, you have to compile the package for one architecture at a +time in the source code directory. After you have installed the +package for one architecture, use `make distclean' before reconfiguring +for another architecture. + +Installation Names +================== + +By default, `make install' will install the package's files in +`/usr/local/bin', `/usr/local/man', etc. You can specify an +installation prefix other than `/usr/local' by giving `configure' the +option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +give `configure' the option `--exec-prefix=PREFIX', the package will +use PREFIX as the prefix for installing programs and libraries. +Documentation and other data files will still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + +Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Specifying the System Type +========================== + +There may be some features `configure' cannot figure out automatically, +but needs to determine by the type of machine the package will run on. +Usually, assuming the package is built to be run on the _same_ +architectures, `configure' can figure that out, but if it prints a +message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the `--target=TYPE' option to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + +If you want to set default values for `configure' scripts to share, you +can create a site shell script called `config.site' that gives default +values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + +Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). Here is a another example: + + /bin/bash ./configure CONFIG_SHELL=/bin/bash + +Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent +configuration-related scripts to be executed by `/bin/bash'. + +`configure' Invocation +====================== + +`configure' recognizes the following options to control how it operates. + +`--help' +`-h' + Print a summary of the options to `configure', and exit. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/autostart/Makefile.am b/autostart/Makefile.am new file mode 100644 index 0000000..f13d2c9 --- /dev/null +++ b/autostart/Makefile.am @@ -0,0 +1,16 @@ +HTML_FILES= autostart-spec.html + +XML_FILES= autostart-spec.xml + +EXTRA_DIST= $(HTML_FILES) $(XML_FILES) + +if XML_DOCS_ENABLED +all-local: $(HTML_FILES) +endif + +%.html: %.xml + $(XMLTO) html-nochunks $< + +maintainer-clean-local: + rm -f $(HTML_FILES) + diff --git a/autostart/NEWS b/autostart/NEWS new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/autostart/NEWS diff --git a/autostart/README b/autostart/README new file mode 100644 index 0000000..7700629 --- /dev/null +++ b/autostart/README @@ -0,0 +1,6 @@ +This is the autostart specification. + +It covers +* automatic launching of applications when the user logs in +* automatic launching of applications when a new media is mounted + diff --git a/autostart/autogen.sh b/autostart/autogen.sh new file mode 100755 index 0000000..b1376df --- /dev/null +++ b/autostart/autogen.sh @@ -0,0 +1,3 @@ +#! /bin/sh +autoreconf -v --install || exit 1 +./configure --enable-maintainer-mode "$@" diff --git a/autostart/autostart-spec.xml b/autostart/autostart-spec.xml new file mode 100644 index 0000000..ba5487e --- /dev/null +++ b/autostart/autostart-spec.xml @@ -0,0 +1,273 @@ +<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" + "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ + <!ENTITY version "0.5"> + <!ENTITY dtd-version "0.5"> + ]> + +<article id="index"> + <articleinfo> + <title>Desktop Application Autostart Specification</title> + <releaseinfo>Version &version;</releaseinfo> + <date>13 February 2006</date> + <authorgroup> + <author> + <firstname>John</firstname> + <surname>Palmieri</surname> + <affiliation> + <address> + <email>johnp@redhat.com</email> + </address> + </affiliation> + </author> + <author> + <firstname>Kévin</firstname> + <surname>Ottens</surname> + <affiliation> + <address> + <email>ervin@ipsquad.net</email> + </address> + </affiliation> + </author> + <author> + <firstname>Renato</firstname> + <surname>Caldas</surname> + <affiliation> + <address> + <email>seventhguardian_@hotmail.com</email> + </address> + </affiliation> + </author> + <author> + <firstname>Rodrigo</firstname> + <surname>Moya</surname> + <affiliation> + <address> + <email>rodrigo@gnome-db.org</email> + </address> + </affiliation> + </author> + <author> + <firstname>Waldo</firstname> + <surname>Bastian</surname> + <affiliation> + <address> + <email>bastian@kde.org</email> + </address> + </affiliation> + </author> + </authorgroup> + </articleinfo> + + <sect1 id="introduction"> + <title>Introduction</title> + <para> + This DRAFT document defines a method for automatically starting + applications during the startup of a desktop environment and after + mounting a removable medium. + </para> + <para> + Some of the file locations in this specification are specified based + on the <ulink url="http://standards.freedesktop.org/basedir-spec/"> + "desktop base directory specification"</ulink>. + </para> + <para> + The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL + NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and + "OPTIONAL" in this document are to be interpreted as + described in RFC 2119. + </para> + </sect1> + <sect1 id="startup"> + <title>Autostart Of Applications During Startup</title> + <para> + By placing an application's .desktop file + in one of the Autostart directories the application will be + automatically launched during startup of the user's desktop environment after the user + has logged in. + </para> + <sect2> + <title>Autostart Directories</title> + <para> + The Autostart Directories are $XDG_CONFIG_DIRS/autostart as defined + in accordance with the + <ulink url="http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html#referencing"> + "Referencing this specification"</ulink> section in the + <ulink url="http://standards.freedesktop.org/basedir-spec/"> + "desktop base directory specification"</ulink>. + </para> + <para> + If the same filename is located under multiple Autostart Directories + only the file under the most important directory should be used. + </para> + <informalexample> + <para> + Example: If $XDG_CONFIG_HOME is not set the Autostart Directory + in the user's home directory is ~/.config/autostart/ + </para> + </informalexample> + <informalexample> + <para> + Example: If $XDG_CONFIG_DIRS is not set the system wide Autostart + Directory is /etc/xdg/autostart/ + </para> + </informalexample> + <informalexample> + <para> + Example: If $XDG_CONFIG_HOME and $XDG_CONFIG_DIRS are not set and + the two files /etc/xdg/autostart/foo.desktop and + ~/.config/autostart/foo.desktop exist then only the file + ~/.config/autostart/foo.desktop will be used because + ~/.config/autostart/ is more important than /etc/xdg/autostart/ + </para> + </informalexample> + </sect2> + <sect2> + <title>Application .desktop Files</title> + <para> + An application .desktop file must have the format as defined in + the <ulink url="http://standards.freedesktop.org/desktop-entry-spec/"> + "Desktop Entry Specification"</ulink>. All keys should be + interpreted as defined with the following exceptions in order to + take into account that the .desktop files in an autostart directory + are not shown in a menu. + </para> + <sect3> + <title>Hidden Key</title> + <para> + When the .desktop file has the Hidden key set to true, the .desktop + file MUST be ignored. When multiple .desktop files with the + same name exists in multiple directories then only the Hidden key + in the most important .desktop file must be considered: If it is + set to true all .desktop files with the same name + in the other directories MUST be ignored as well. + </para> + </sect3> + <sect3> + <title>OnlyShowIn and NotShowIn Keys</title> + <para> + The OnlyShownIn entry may contain a list of strings identifying + the desktop environments that MUST autostart this application, + all other desktop environments MUST NOT autostart this application. + </para> + <para> + The NotShownIn entry may contain a list of strings identifying + the desktop environments that MUST NOT autostart this + application, all other desktop environments MUST autostart this + application. + </para> + <para> + Only one of these keys, either OnlyShowIn or NotShowIn, may appear + in a single .desktop file. + </para> + </sect3> + <sect3> + <title>TryExec Key</title> + <para> + A .desktop file with a non-empty TryExec field MUST NOT be + autostarted if the value of the TryExec key does NOT match with + an installed executable program. The value of the TryExec field + may either be an absolute path or the name of an executable + without any path components. If the name of an executable is + specified without any path components then the $PATH environment + is searched to find a matching executable program. + </para> + </sect3> + </sect2> + <sect2> + <title>Implementation Notes</title> + <informalexample> + <para> + If an application autostarts by having a .desktop file installed + in the system wide autostart directory, an individual user can + disable the autotomatic start of this application by placing a + .desktop file of the same name in its personal autostart directory + which contains the key Hidden=true. + </para> + </informalexample> + </sect2> + </sect1> + <sect1 id="mounting"> + <title>Autostart Of Applications After Mount</title> + <para> + When a desktop environment mounts a new medium, the medium may contain + an Autostart file that can suggest to start an application or + an Autoopen file that can suggest to open a specific file located + on the medium. + </para> + <sect2> + <title>Autostart Files</title> + <para> + When a new medium is mounted the root directory of the medium should + be checked for the following Autostart files in order of precendence: + .autorun, autorun, autorun.sh + Only the first file that is present should be considered. + </para> + <para> + The desktop environment MAY ignore Autostart files altogether + based on policy set by the user, system administrator or vendor. + </para> + <para> + The desktop environment MUST prompt the user for confirmation before + automatically starting an application. + </para> + <para> + When an Autostart file has been detected and the user has confirmed + its execution the autostart file MUST be executed with the + current working directory (CWD) set to the root directory of the + medium. + </para> + </sect2> + <sect2> + <title>Autoopen Files</title> + <para> + When a new medium is mounted and a) the medium does not contain an + Autostart file or b) a policy to ignore Autostart files is in effect + then the root directory of the medium should be checked for the + following Autoopen files in order of precedence: + .autoopen, autoopen . + Only the first file that is present should be considered. + </para> + <para> + The desktop environment MAY ignore Autoopen files altogether + based on policy set by the user, system administrator or vendor. + </para> + <para> + An Autoopen file MUST contain a single relative path that points to + a non-executable file contained on the medium. + If the file contains a newline or carriage return character then the + newline or carriage return character itself and all characters that + follow MUST be ignored. + </para> + <para> + The relative path MUST NOT contain path components that refer to a + parent directory (../) + </para> + <para> + The relative path MUST NOT point to an executable file. + </para> + <para> + The desktop environment MUST verify that the relative path points to + a file that is actually located on the medium, taking into account any + symbolic or other links and MUST ignore any relative path that + points to a file location outside the medium itself. + </para> + <para> + If the relative path points to an executable file then the desktop + environment MUST NOT execute the file. + </para> + <para> + The desktop environment MUST prompt the user for confirmation before + opening the file. + </para> + <para> + When an Autoopen file has been detected and the user has confirmed + that the file indicated in the Autoopen file should be opened then + the file indicated in the Autoopen file MUST be opened in the + application normally preferred by the user for files of its kind + UNLESS the user instructed otherwise. + </para> + </sect2> + </sect1> + +</article> + diff --git a/autostart/configure.in b/autostart/configure.in new file mode 100644 index 0000000..7df76ac --- /dev/null +++ b/autostart/configure.in @@ -0,0 +1,61 @@ +dnl -*- mode: m4 -*- +AC_PREREQ(2.52) + +AC_INIT(autostart-spec.xml) + +AM_INIT_AUTOMAKE(autostart-spec, 0.5) + +# Honor aclocal flags +ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS" + + ## must come before we use the $USE_MAINTAINER_MODE variable later +AM_MAINTAINER_MODE + +AC_ARG_ENABLE(xml-docs, [ --enable-xml-docs build XML into HTML (requires xmlto)],enable_xml_docs=$enableval,enable_xml_docs=auto) + +### XML tools + +AC_PATH_PROG(XMLTO, xmlto, no) + +AC_MSG_CHECKING([whether to build XML documentation]) + +if test x$XMLTO = xno ; then + have_xmlto=no +else + have_xmlto=yes +fi + +if test x$enable_xml_docs = xauto ; then + if test x$have_xmlto = xno ; then + enable_xml_docs=no + else + enable_xml_docs=yes + fi +fi + +if test x$enable_xml_docs = xyes; then + if test x$have_xmlto = xno; then + AC_MSG_ERROR([Building XML docs explicitly required, but xmlto not found]) + fi +fi + +AM_CONDITIONAL(XML_DOCS_ENABLED, test x$enable_xml_docs = xyes) +AC_MSG_RESULT(yes) + +AC_OUTPUT([ +Makefile +]) + +dnl ========================================================================== +echo " + Autostart specification $VERSION + ============== + + prefix: ${prefix} + source code location: ${srcdir} + xmlto: ${XMLTO}" + +echo " + Maintainer mode: ${USE_MAINTAINER_MODE} + Building XML docs: ${enable_xml_docs} +" diff --git a/basedir/.gitignore b/basedir/.gitignore new file mode 100644 index 0000000..126e056 --- /dev/null +++ b/basedir/.gitignore @@ -0,0 +1 @@ +basedir-spec.html diff --git a/basedir/Makefile b/basedir/Makefile new file mode 100644 index 0000000..35a73df --- /dev/null +++ b/basedir/Makefile @@ -0,0 +1,7 @@ +all: basedir-spec.html + +%.html: %.xml + xmlto html-nochunks $< + +clean: + rm -f basedir-spec.html diff --git a/basedir/basedir-spec.xml b/basedir/basedir-spec.xml new file mode 100644 index 0000000..03a982b --- /dev/null +++ b/basedir/basedir-spec.xml @@ -0,0 +1,298 @@ +<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" + "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ + ]> +<article id="index"> + <articleinfo> + <title>XDG Base Directory Specification</title> + <releaseinfo>Version 0.7</releaseinfo> + <date>24th November 2010</date> + <authorgroup> + <author> + <firstname>Waldo</firstname> + <surname>Bastian</surname> + <affiliation> + <address> + <email>bastian@kde.org</email> + </address> + </affiliation> + </author> + <author> + <firstname>Ryan</firstname> + <surname>Lortie</surname> + <affiliation> + <address> + <email>desrt@desrt.ca</email> + </address> + </affiliation> + </author> + <author> + <firstname>Lennart</firstname> + <surname>Poettering</surname> + <affiliation> + <address> + <email>lennart@poettering.net</email> + </address> + </affiliation> + </author> + </authorgroup> + </articleinfo> + + <sect1 id="introduction"> + <title>Introduction</title> + <para> + Various specifications specify files and file formats. This + specification defines where these files should be looked for by + defining one or more base directories relative to which files + should be located. + </para> + </sect1> + + <sect1 id="basics"> + <title>Basics</title> + <para> + The XDG Base Directory Specification is based on the following concepts: + <itemizedlist> + <listitem> + <para> + There is a single base directory relative to which user-specific + data files should be written. This directory is defined by the + environment variable <literal>$XDG_DATA_HOME</literal>. + </para> + </listitem> + <listitem> + <para> + There is a single base directory relative to which user-specific + configuration files should be written. This directory is defined by the + environment variable <literal>$XDG_CONFIG_HOME</literal>. + </para> + </listitem> + <listitem> + <para> + There is a set of preference ordered base directories relative to + which data files should be searched. This set of directories is defined + by the environment variable <literal>$XDG_DATA_DIRS</literal>. + </para> + </listitem> + <listitem> + <para> + There is a set of preference ordered base directories relative to + which configuration files should be searched. + This set of directories is defined + by the environment variable <literal>$XDG_CONFIG_DIRS</literal>. + </para> + </listitem> + <listitem> + <para> + There is a single base directory relative to which user-specific + non-essential (cached) data should be written. + This directory is defined by the + environment variable <literal>$XDG_CACHE_HOME</literal>. + </para> + </listitem> + <listitem> + <para> + There is a single base directory relative to which + user-specific runtime files and other file objects should + be placed. This directory is defined by the environment + variable <literal>$XDG_RUNTIME_DIR</literal>. + </para> + </listitem> + </itemizedlist> + </para> + + <para>All paths set in these environment variables must be + absolute. If an implementation encounters a relative path in any + of these variables it should consider the path invalid and ignore + it.</para> + </sect1> + + + <sect1 id="variables"> + <title>Environment variables</title> + <para> + <literal>$XDG_DATA_HOME</literal> defines the base directory relative to + which user specific data files should be stored. If + <literal>$XDG_DATA_HOME</literal> is either not set or empty, a default equal to + <literal>$HOME</literal>/.local/share should be used. + </para> + <para> + <literal>$XDG_CONFIG_HOME</literal> defines the base directory relative to + which user specific configuration files should be stored. If + <literal>$XDG_CONFIG_HOME</literal> is either not set or empty, a default equal to + <literal>$HOME</literal>/.config should be used. + </para> + <para> + <literal>$XDG_DATA_DIRS</literal> defines the preference-ordered set of + base directories to search for data files in addition to the + <literal>$XDG_DATA_HOME</literal> base directory. + The directories in <literal>$XDG_DATA_DIRS</literal> should be seperated + with a colon ':'. + </para> + <para> + If <literal>$XDG_DATA_DIRS</literal> is either not set or empty, a value equal to + /usr/local/share/:/usr/share/ should be used. + </para> + <para> + <literal>$XDG_CONFIG_DIRS</literal> defines the preference-ordered set of + base directories to search for configuration files in addition to the + <literal>$XDG_CONFIG_HOME</literal> base directory. + The directories in <literal>$XDG_CONFIG_DIRS</literal> should be seperated + with a colon ':'. + </para> + <para> + If <literal>$XDG_CONFIG_DIRS</literal> is either not set or empty, a value equal to + /etc/xdg should be used. + </para> + <para> + The order of base directories denotes their importance; the first + directory listed is the most important. When the same information is + defined in multiple places the information defined relative to the more + important base directory takes precedent. The base directory defined + by <literal>$XDG_DATA_HOME</literal> is considered more important than + any of the base directories defined by <literal>$XDG_DATA_DIRS</literal>. + The base directory defined + by <literal>$XDG_CONFIG_HOME</literal> is considered more important than + any of the base directories defined by <literal>$XDG_CONFIG_DIRS</literal>. + </para> + <para> + <literal>$XDG_CACHE_HOME</literal> defines the base directory relative to + which user specific non-essential data files should be stored. If + <literal>$XDG_CACHE_HOME</literal> is either not set or empty, a default equal to + <literal>$HOME</literal>/.cache should be used. + </para> + + <para> + <literal>$XDG_RUNTIME_DIR</literal> defines the base directory + relative to which user-specific non-essential runtime files and + other file objects (such as sockets, named pipes, ...) should be + stored. The directory MUST be owned by the user, and he MUST be + the only one having read and write access to it. Its Unix access + mode MUST be 0700. + </para> + <para> + The lifetime of the directory MUST be bound to the user being + logged in. It MUST be created when the user first logs in and if + the user fully logs out the directory MUST be removed. If the + user logs in more than once he should get pointed to the same + directory, and it is mandatory that the directory continues to + exist from his first login to his last logout on the system, and + not removed in between. Files in the directory MUST not survive + reboot or a full logout/login cycle. + </para> + <para> + The directory MUST be on a local file system and not shared with + any other system. The directory MUST by fully-featured by the + standards of the operating system. More specifically, on + Unix-like operating systems AF_UNIX sockets, symbolic links, + hard links, proper permissions, file locking, sparse files, + memory mapping, file change notifications, a reliable hard link + count must be supported, and no restrictions on the file name + character set should be imposed. Files in this directory MAY be + subjected to periodic clean-up. To ensure that your files are + not removed, they should have their access time timestamp + modified at least once every 6 hours of monotonic time or the + 'sticky' bit should be set on the file. + </para> + <para> + If <literal>$XDG_RUNTIME_DIR</literal> is not set applications + should fall back to a replacement directory with similar + capabilities and print a warning message. Applications should + use this directory for communication and synchronization + purposes and should not place larger files in it, since it might + reside in runtime memory and cannot necessarily be swapped out + to disk. + </para> + </sect1> + + <sect1 id="referencing"> + <title>Referencing this specification</title> + <para> + Other specifications may reference this specification by specifying the + location of a data file as + <literal>$XDG_DATA_DIRS</literal>/subdir/filename. This implies that: + <itemizedlist> + <listitem> + <para> + Such file should be installed to <literal>$datadir</literal>/subdir/filename + with <literal>$datadir</literal> defaulting to /usr/share. + </para> + </listitem> + <listitem> + <para> + A user specific version of the data file may be created in + <literal>$XDG_DATA_HOME</literal>/subdir/filename, taking into + account the default value for <literal>$XDG_DATA_HOME</literal> if + <literal>$XDG_DATA_HOME</literal> is not set. + </para> + </listitem> + <listitem> + <para> + Lookups of the data file should search for ./subdir/filename relative to + all base directories specified by <literal>$XDG_DATA_HOME</literal> and + <literal>$XDG_DATA_DIRS</literal> . If an environment + variable is either not set or empty, its default value as defined by this specification + should be used instead. + </para> + </listitem> + </itemizedlist> + </para> + <para> + Specifications may reference this specification by specifying the + location of a configuration file as + <literal>$XDG_CONFIG_DIRS</literal>/subdir/filename. This implies that: + <itemizedlist> + <listitem> + <para> + Default configuration files should be installed to <literal>$sysconfdir</literal>/xdg/subdir/filename + with <literal>$sysconfdir</literal> defaulting to /etc. + </para> + </listitem> + <listitem> + <para> + A user specific version of the configuration file may be created in + <literal>$XDG_CONFIG_HOME</literal>/subdir/filename, taking into + account the default value for <literal>$XDG_CONFIG_HOME</literal> if + <literal>$XDG_CONFIG_HOME</literal> is not set. + </para> + </listitem> + <listitem> + <para> + Lookups of the configuration file should search for ./subdir/filename relative to + all base directories indicated by <literal>$XDG_CONFIG_HOME</literal> and + <literal>$XDG_CONFIG_DIRS</literal> . If an environment + variable is either not set or empty, its default value as defined by this specification + should be used instead. + </para> + </listitem> + </itemizedlist> + </para> + <para> + If, when attempting to write a file, the destination + directory is non-existant an attempt should be made to create it + with permission <literal>0700</literal>. If the destination directory + exists already the permissions should not be changed. + The application should be prepared to handle the case where the file + could not be written, either because the directory was non-existant + and could not be created, or for any other reason. In such case it + may chose to present an error message to the user. + </para> + <para> + When attempting to read a file, if for any reason a file in a certain + directory is unaccessible, e.g. because the directory is non-existant, + the file is non-existant or the user is not authorized to open the file, + then the processing of the file in that directory should be skipped. + If due to this a required file could not be found at all, the + application may chose to present an error message to the user. + </para> + <para> + A specification that refers to <literal>$XDG_DATA_DIRS</literal> or + <literal>$XDG_CONFIG_DIRS</literal> should define what the behaviour + must be when a file is located under multiple base directories. + It could, for example, define that only the file under the most + important base directory should be used or, as another example, + it could define rules for merging the information from the different + files. + </para> + </sect1> + +</article> diff --git a/desktop-entry/.cvsignore b/desktop-entry/.cvsignore new file mode 100644 index 0000000..e2bf8b5 --- /dev/null +++ b/desktop-entry/.cvsignore @@ -0,0 +1,2 @@ +*.ps +*.html diff --git a/desktop-entry/ChangeLog b/desktop-entry/ChangeLog new file mode 100644 index 0000000..7113101 --- /dev/null +++ b/desktop-entry/ChangeLog @@ -0,0 +1,182 @@ +2008-09-12 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: reword sentence about characters allowed in + key names to avoid some ambiguity. + Patch by Simon McVittie <simon.mcvittie@collabora.co.uk> + +2008-03-04 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: bump version to 1.1-draft, so we can publish + it. See http://bugs.freedesktop.org/show_bug.cgi?id=14097 + +2007-09-10 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: fix Icon key in example: it was using the + .png extension for an icon name. Which is wrong :-) + +2007-07-27 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: don't say that the files are encoded as + lines of 8-bit characters, which is wrong for UTF-8. Use something a + bit better proposed by Matthias Clasen <mclasen@redhat.com> + Bug #11417. + +2007-05-30 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: s/DESKTOP_LAUNCH_ID/DESKTOP_STARTUP_ID/ + Thanks to Dan Winship <danw@gnome.org> for catching this. + Bug #11081. + +2007-04-28 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: scanf behavior is locale-dependent, and the + numeric type shouldn't be. Specify that the value is a floating point + number as recognized by scanf in the C locale. + Thanks to Dan Winship <danw@gnome.org> for catching this. + http://lists.freedesktop.org/archives/xdg/2007-April/009732.html + +2007-04-28 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: clarify description for the TryExec key. + http://lists.freedesktop.org/archives/xdg/2007-March/009556.html + +2007-04-28 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: change "the $PATH" to "the $PATH environment + variable". + http://lists.freedesktop.org/archives/xdg/2007-March/009552.html + +2007-04-28 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: improve the description of the Comment key. + http://lists.freedesktop.org/archives/xdg/2007-March/009440.html + +2007-04-28 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: a desktop file of type Application should + always have an Exec key. Same for Link Type and URL key. + http://lists.freedesktop.org/archives/xdg/2007-March/009437.html + +2007-04-28 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: desktop files of type Directory have a + .directory extension right now (at least in GNOME), but according to + the spec, this is wrong. The patch fixes this. Also, it removes a + small part of text explaining the name of a desktop file describing a + directory. + http://lists.freedesktop.org/archives/xdg/2007-March/009437.html + +2007-04-28 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml:clarify a bit the text about keys that only + makes sense in a specific context. Also, state that the keys should + not be used outside of this context. For example, the URL key should + not be present if the type is not Link. + http://lists.freedesktop.org/archives/xdg/2007-March/009437.html + +2007-04-28 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: small typo + http://lists.freedesktop.org/archives/xdg/2007-March/009437.html + +2007-04-28 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: this changes the type of the version from + numeric to string. It's needed if we consider the possibility that + there are some desktop entry files out there using 0.9.x as a value + for this key. The change doesn't break anything. + http://lists.freedesktop.org/archives/xdg/2007-March/009437.html + +2007-04-28 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: UnmountIcon is a localestring key. + http://lists.freedesktop.org/archives/xdg/2007-March/009437.html + +2007-04-28 Vincent Untz <vuntz@gnome.org> + + * desktop-entry-spec.xml: clarify that lists should always end with a + semicolon, even if there's only one value. + http://lists.freedesktop.org/archives/xdg/2007-March/009437.html + +2007-02-06 Waldo Bastian <waldo.bastian@intel.com> + * Clearify that %U may result in either local paths or file: URLs + * Deprecate %d, %n, %D and %N. They aren't usable on Gnome and + you can do the same with dirname and basename in a script. + * Clearify that %f, %u, %F or %U should only be used once. + * Clearify that these codes should be ignored if there is no file + to open. + * Forbid the use of field codes in quoted arguments. + * Clearify that %F and %U should only be used as a stand alone argument. + * Bumped version to 1.0 + +2006-10-30 Waldo Bastian <waldo.bastian@intel.com> + * Remove equal sign from reserved characters in Exec args + * Add backslash to list of reserved characters in Exec args + +2006-10-04 Waldo Bastian <waldo.bastian@intel.com> + * Deprecate %v, it is FSDevice specific + +2006-08-30 Waldo Bastian <waldo.bastian@intel.com> + * list FSDevice type as KDE specific + * refer to Icon Theme Specification + +2006-08-22 Waldo Bastian <waldo.bastian@intel.com> + * clarification of Exec key + * correction of StartupWMClass, clarify StartupNotify (Lubos Lunak) + * deprecate SortOrder and FilePattern key (Vincent Untz) + * remove section on "MIME Type caching" from spec (Vincent Untz) + * groups and keys must be unique (Vincent Untz) + See http://lists.freedesktop.org/archives/xdg/2006-August/008446.html + +2006-05-28 Vincent Untz <vuntz@gnome.org> + * cleanup of text and some reorg for clearity + * move all of the legacy-mixed encoding stuff to the appendix + * deprecate the Swallow* keys + * improve definition of group headers + * reorder the list of standard keys so they are sorted by type + See http://lists.freedesktop.org/archives/xdg/2006-May/008131.html + +Tue Jul 13 18:04:11 2004 Jonathan Blandford <jrb@gnome.org> + + * desktop-entry-spec.xml: Update the MIME description to make it + more relevent. + +2004-04-19 Mark McLoughlin <mark@skynet.ie> + + Pointed out by Ville Skyttä <ville.skytta@iki.fi> + + * desktop-entry-spec.xml: fix minor typo. + +2004-04-18 Mark McLoughlin <mark@skynet.ie> + + Patch from Ville Skyttä <ville.skytta@iki.fi> + + * desktop-entry-spec.xml: editorial changes, fixes for + typos and general cleanups. + +Mon Jul 7 18:26:14 2003 Owen Taylor <otaylor@redhat.com> + + * destop-entry-spec.sgml: Merge changes by Havoc + Pennington that had been made in web module: + + 2002/04/20: add changes posted to xdg-list a while back + +Sat Aug 24 17:00:48 2002 Owen Taylor <otaylor@redhat.com> + + * desktop-entry-spec.sgml: In legacy-mixed table, fix duplicate + pt entry, language code for Armenian. Make explicit that + language-country locale tags can match a single language in + the table. (Pablo Saratxaga) + +Tue Mar 13 12:37:03 2001 Owen Taylor <otaylor@redhat.com> + + * 0.9.3 + + * Reworked the description of encoding handling for + Legacy-Mixed for clarity and added a bit more details + on how encoding-matching should be done. + +Thu Mar 8 17:42:05 2001 Owen Taylor <otaylor@redhat.com> + + * Import into CVS. + diff --git a/desktop-entry/desktop-entry-spec.xml b/desktop-entry/desktop-entry-spec.xml new file mode 100644 index 0000000..34bc154 --- /dev/null +++ b/desktop-entry/desktop-entry-spec.xml @@ -0,0 +1,1232 @@ +<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" + "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ + ]> +<article id="index"> + <articleinfo> + <title>Desktop Entry Specification</title> + <releaseinfo>Version 1.1-draft</releaseinfo> + <date>4 Mar 2008</date> + <authorgroup> + <author> + <firstname>Preston</firstname> + <surname>Brown</surname> + <affiliation> + <address> + <email>pbrown@kde.org</email> + </address> + </affiliation> + </author> + <author> + <firstname>Jonathan</firstname> + <surname>Blandford</surname> + <affiliation> + <address> + <email>jrb@redhat.com</email> + </address> + </affiliation> + </author> + <author> + <firstname>Owen</firstname> + <surname>Taylor</surname> + <affiliation> + <address> + <email>otaylor@gtk.org</email> + </address> + </affiliation> + </author> + <author> + <firstname>Vincent</firstname> + <surname>Untz</surname> + <affiliation> + <address> + <email>vuntz@gnome.org</email> + </address> + </affiliation> + </author> + <author> + <firstname>Waldo</firstname> + <surname>Bastian</surname> + <affiliation> + <address> + <email>waldo.bastian@intel.com</email> + </address> + </affiliation> + </author> + </authorgroup> + </articleinfo> + + <sect1 id="introduction"> + <title>Introduction</title> + <para> + Both the KDE and GNOME desktop environments have adopted a similar + format for "desktop entries", or configuration files describing how a + particular program is to be launched, how it appears in menus, etc. + It is to the larger community's benefit that a unified standard be + agreed upon by all parties such that interoperation between the two + environments, and indeed any additional environments that implement + the specification, becomes simpler. + </para> + </sect1> + <sect1 id="basic-format"> + <title>Basic format of the file</title> + <para> + Desktop entry files should have the <filename>.desktop</filename> + extension, except for files of <varname>Type</varname> + <constant>Directory</constant> which should have the + <filename>.directory</filename> extension. Determining file type on basis + of extension makes determining the file type very easy and quick. + When no file extension is present, the desktop system should + fall back to recognition via "magic detection". + </para> + <para> + Desktop entry files are encoded in UTF-8. A file is interpreted as a + series of lines that are separated by linefeed characters. Case is + significant everywhere in the file. + </para> + <para> + Compliant implementations MUST not remove any fields from the file, + even if they don't support them. Such fields must be maintained in a + list somewhere, and if the file is "rewritten", they will be included. + This ensures that any desktop-specific extensions will be preserved + even if another system accesses and changes the file. + </para> + <sect2 id="comments"> + <title>Comments</title> + <para> + Lines beginning with a <literal>#</literal> and blank lines are + considered comments and will be ignored, however they should be + preserved across reads and writes of the desktop entry file. + </para> + <para> + Comment lines are uninterpreted and may contain any character + (except for LF). However, using UTF-8 for comment lines that + contain characters not in ASCII is encouraged. + </para> + </sect2> + <sect2 id="group-header"> + <title>Group headers</title> + <para> + A group header with name <literal>groupname</literal> is a line in the + format: + </para> + <programlisting>[groupname]</programlisting> + <para> + Group names may contain all ASCII characters except for + <literal>[</literal> and <literal>]</literal> and control characters. + </para> + <para> + Multiple groups may not have the same name. + </para> + <para> + All <literal>{key,value}</literal> pairs following a group header until + a new group header belong to the group. + </para> + <para> + The basic format of the desktop entry file requires that there be + a group header named <literal>Desktop Entry</literal>. There may + be other groups present in the file, but this is the most + important group which explicitly needs to be supported. This + group should also be used as the "magic key" for automatic MIME + type detection. There should be nothing preceding this group in + the desktop entry file but possibly one or more comments. + </para> + </sect2> + <sect2 id="entries"> + <title>Entries</title> + <para> + Entries in the file are <literal>{key,value}</literal> pairs in the + format: + </para> + <programlisting>Key=Value</programlisting> + <para> + Space before and after the equals sign should be ignored; the + <literal>=</literal> sign is the actual delimiter. + </para> + <para> + Only the characters <literal>A-Za-z0-9-</literal> may be used in + key names. + </para> + <para> + As the case is significant, the keys <varname>Name</varname> and + <varname>NAME</varname> are not equivalent. + </para> + <para> + Multiple keys in the same group may not have the same name. Keys in + different groups may have the same name. + </para> + </sect2> + </sect1> + <sect1 id="value-types"> + <title>Possible value types</title> + <para> + The value types recognized are <literal>string</literal>, + <literal>localestring</literal>, + <literal>boolean</literal>, and + <literal>numeric</literal>. + </para> + <itemizedlist> + <listitem> + <para> + Values of type <literal>string</literal> may contain all ASCII + characters except for control characters. + </para> + </listitem> + <listitem> + <para> + Values of type <literal>localestring</literal> are user displayable, + and are encoded in UTF-8. + </para> + </listitem> + <listitem> + <para> + Values of type <literal>boolean</literal> must either be the string + <literal>true</literal> or <literal>false</literal>. + </para> + </listitem> + <listitem> + <para> + Values of type <literal>numeric</literal> must be a valid floating + point number as recognized by the <literal>%f</literal> specifier for + <function>scanf</function> in the <literal>C</literal> locale. + </para> + </listitem> + </itemizedlist> + <para> + The escape sequences <literal>\s</literal>, <literal>\n</literal>, + <literal>\t</literal>, <literal>\r</literal>, and + <literal>\\</literal> are supported for values of type + <literal>string</literal> and <literal>localestring</literal>, meaning + ASCII space, newline, tab, carriage return, and backslash, respectively. + </para> + <para> + Some keys can have multiple values. In such a case, the value of the key + is specified as a plural: for example, <literal>string(s)</literal>. The + multiple values should be separated by a semicolon, and the value of the + key should have a semicolon as trailing character. Semicolons in these + values need to be escaped using <literal>\;</literal>. + </para> + </sect1> + <sect1 id="localized-keys"> + <title>Localized values for keys</title> + <para> + Keys with type <literal>localestring</literal> may be postfixed by + [<replaceable>LOCALE</replaceable>], + where <replaceable>LOCALE</replaceable> is the locale type of the + entry. <replaceable>LOCALE</replaceable> must be of the form + <literal><replaceable>lang</replaceable>_<replaceable>COUNTRY</replaceable>.<replaceable>ENCODING</replaceable>@<replaceable>MODIFIER</replaceable></literal>, + where + <literal>_<replaceable>COUNTRY</replaceable></literal>, + <literal>.<replaceable>ENCODING</replaceable></literal>, + and <literal>@<replaceable>MODIFIER</replaceable></literal> + may be omitted. If a postfixed key occurs, the same + key must be also present without the postfix. + </para> + <para> + When reading in the desktop entry file, the value of the key is + selected by matching the current POSIX locale for the + <varname>LC_MESSAGES</varname> category against the + <replaceable>LOCALE</replaceable> postfixes of all occurrences + of the key, with the + <literal>.<replaceable>ENCODING</replaceable></literal> part + stripped. + </para> + <para> + The matching is done as follows. If + <varname>LC_MESSAGES</varname> is of the form + <literal><replaceable>lang</replaceable>_<replaceable>COUNTRY</replaceable>.<replaceable>ENCODING</replaceable>@<replaceable>MODIFIER</replaceable></literal>, + then it will match a key of the form + <literal><replaceable>lang</replaceable>_<replaceable>COUNTRY</replaceable>@<replaceable>MODIFIER</replaceable></literal>. + If such a key does not exist, it will attempt to match + <literal><replaceable>lang</replaceable>_<replaceable>COUNTRY</replaceable></literal> + followed by + <literal><replaceable>lang</replaceable>@<replaceable>MODIFIER</replaceable></literal>. + Then, a match against <replaceable>lang</replaceable> by itself + will be attempted. Finally, if no matching key is found the + required key without a locale specified is used. The encoding + from the <varname>LC_MESSAGES</varname> value is ignored + when matching. + </para> + <para> + If <varname>LC_MESSAGES</varname> does not have a <replaceable>MODIFIER</replaceable> + field, then no key with a modifier will be matched. Similarly, if + <varname>LC_MESSAGES</varname> does not have a <replaceable>COUNTRY</replaceable> + field, then no key with a country specified will be matched. If + <varname>LC_MESSAGES</varname> just has a <replaceable>lang</replaceable> field, then + it will do a straight match to a key with a similar value. The + following table lists possible matches of various <varname>LC_MESSAGES</varname> values in + the order in which they are matched. Note that the + <replaceable>ENCODING</replaceable> field isn't shown. + </para> + <table> + <title>Locale Matching</title> + <tgroup cols="2"> +<thead> + <row> + <entry><varname>LC_MESSAGES</varname> value</entry> + <entry>Possible keys in order of matching</entry> + </row> +</thead> +<tbody> + <row> + <entry><literal><replaceable>lang</replaceable>_<replaceable>COUNTRY</replaceable>@<replaceable>MODIFIER</replaceable></literal></entry> + <entry> + <literal><replaceable>lang</replaceable>_<replaceable>COUNTRY</replaceable>@<replaceable>MODIFIER</replaceable></literal>, + <literal><replaceable>lang</replaceable>_<replaceable>COUNTRY</replaceable></literal>, + <literal><replaceable>lang</replaceable>@<replaceable>MODIFIER</replaceable></literal>, + <literal><replaceable>lang</replaceable></literal>, + default value + </entry> + </row> + <row> + <entry><literal><replaceable>lang</replaceable>_<replaceable>COUNTRY</replaceable></literal></entry> + <entry> + <literal><replaceable>lang</replaceable>_<replaceable>COUNTRY</replaceable></literal>, + <replaceable>lang</replaceable>, + default value + </entry> + </row> + <row> + <entry><literal><replaceable>lang</replaceable>@<replaceable>MODIFIER</replaceable></literal></entry> + <entry> + <literal><replaceable>lang</replaceable>@<replaceable>MODIFIER</replaceable></literal>, + <replaceable>lang</replaceable>, + default value + </entry> + </row> + <row> + <entry><replaceable>lang</replaceable></entry> + <entry> + <replaceable>lang</replaceable>, + default value + </entry> + </row> +</tbody> + </tgroup> + </table> + + <para> + For example, if the current value of the <varname>LC_MESSAGES</varname> category + is <literal>sr_YU@Latn</literal> and the desktop file includes: + </para> + <programlisting> + Name=Foo + Name[sr_YU]=... + Name[sr@Latn]=... + Name[sr]=...</programlisting> + <para> + then the value of the <varname>Name</varname> keyed by <literal>sr_YU</literal> is used. + </para> + </sect1> + <sect1 id="recognized-keys"> + <title>Recognized desktop entry keys</title> + <para> + Keys are either OPTIONAL or REQUIRED. If a key is OPTIONAL it may or + may not be present in the file. However, if it isn't, the + implementation of the standard should not blow up, it must provide + some sane defaults. + </para> + <para> + Some keys only make sense in the context when another particular key + is also present and set to a specific value. Those keys should not be + used if the particular key is not present or not set to the specific + value. For example, the <varname>Terminal</varname> key can only be used + when the value of the <varname>Type</varname> key is + <constant>Application</constant>. + </para> + <para> + If a REQUIRED key is only valid in the context of another key set to a + specific value, then it has to be present only if the other key is set to + the specific value. For example, the <varname>URL</varname> key has to be + present when and only when when the value of the <varname>Type</varname> + key is <constant>Link</constant>. + </para> + <para> + Some example keys: <varname>Name[C]</varname>, <varname>Comment[it]</varname>. + </para> + <table> + <title>Standard Keys</title> + <tgroup cols="5"> + <thead> + <row> + <entry>Key</entry> + <entry>Description</entry> + <entry>Value Type</entry> + <entry>REQ?</entry> + <entry>Type</entry> + </row> + </thead> + <tbody> + <row> + <entry id="key-type"><varname>Type</varname></entry> + <entry> + This specification defines 3 types of desktop entries: + <constant>Application</constant> (type 1), + <constant>Link</constant> (type 2) + and <constant>Directory</constant> (type 3). + To allow the addition of new types in the future, + implementations should ignore desktop entries with an + unknown type. + </entry> + <entry>string</entry> + <entry>YES</entry> + </row> + <row> + <entry id="key-version"><varname>Version</varname></entry> + <entry> + Version of the Desktop Entry Specification that the + desktop entry conforms with. Entries that confirm with this + version of the specification should use <literal>1.0</literal>. + Note that the version field is not required to be present. + </entry> + <entry>string</entry> + <entry>NO</entry> + <entry>1-3</entry> + </row> + <row> + <entry id="key-name"><varname>Name</varname></entry> + <entry> + Specific name of the application, for example "Mozilla". + </entry> + <entry>localestring</entry> + <entry>YES</entry> + <entry>1-3</entry> + </row> + <row> + <entry id="key-genericname"><varname>GenericName</varname></entry> + <entry> + Generic name of the application, for example "Web Browser". + </entry> + <entry>localestring</entry> + <entry>NO</entry> + <entry>1-3</entry> + </row> + <row> + <entry id="key-nodisplay"><varname>NoDisplay</varname></entry> + <entry> + <varname>NoDisplay</varname> means "this application exists, but don't display it in the menus". + This can be useful to e.g. associate this application with MIME types, so that + it gets launched from a file manager (or other apps), without having a menu + entry for it (there are tons of good reasons for this, including e.g. the + <literal>netscape -remote</literal>, or <literal>kfmclient openURL</literal> kind of stuff). + </entry> + <entry>boolean</entry> + <entry>NO</entry> + <entry>1-3</entry> + </row> + <row> + <entry id="key-comment"><varname>Comment</varname></entry> + <entry> + Tooltip for the entry, for example "View sites on the + Internet". The value should not be redundant with the values of + <varname>Name</varname> and <varname>GenericName</varname>. + </entry> + <entry>localestring</entry> + <entry>NO</entry> + <entry>1-3</entry> + </row> + <row> + <entry id="key-icon"><varname>Icon</varname></entry> + <entry> + Icon to display in file manager, menus, etc. If the + name is an absolute path, the given file will be + used. If the name is not an absolute path, the algorithm described + in the <ulink + url="http://freedesktop.org/wiki/Standards/icon-theme-spec">Icon + Theme Specification</ulink> will be used to locate the icon. + </entry> + <entry>localestring</entry> + <entry>NO</entry> + <entry>1-3</entry> + </row> + <row> + <entry id="key-hidden"><varname>Hidden</varname></entry> + <entry> + <varname>Hidden</varname> should have been called <varname>Deleted</varname>. + It means the user deleted (at his level) + something that was present (at an upper level, e.g. in the system dirs). It's + strictly equivalent to the <filename>.desktop</filename> file not existing at all, as far as that user is + concerned. This can also be used to "uninstall" existing files (e.g. due to a renaming) + - by letting <literal>make install</literal> install a file with <literal>Hidden=true</literal> in it. + </entry> + <entry>boolean</entry> + <entry>NO</entry> + <entry>1-3</entry> + </row> + <row> + <entry id="key-onlyshowin"><varname>OnlyShowIn</varname>, <varname>NotShowIn</varname></entry> + <entry> + A list of strings identifying the environments that should + display/not display a given desktop entry. Only one of + these keys, either <varname>OnlyShowIn</varname> or + <varname>NotShowIn</varname>, may appear in a group (for + possible values see the <ulink + url="http://www.freedesktop.org/Standards/menu-spec">Desktop + Menu Specification</ulink>). + </entry> + <entry>string(s)</entry> + <entry>NO</entry> + <entry>1-3</entry> + </row> + <row> + <entry id="key-tryexec"><varname>TryExec</varname></entry> + <entry> + Path to an executable file on disk used to determine if the program + is actually installed. If the path is not an absolute path, the file + is looked up in the $PATH environment variable. If the file is not + present or if it is not executable, the entry may be ignored (not be + used in menus, for example). + </entry> + <entry>string</entry> + <entry>NO</entry> + <entry>1</entry> + </row> + <row> + <entry id="key-exec"><varname>Exec</varname></entry> + <entry> + Program to execute, possibly with arguments. + </entry> + <entry>string</entry> + <entry>YES</entry> + <entry>1</entry> + </row> + <row> + <entry id="key-path"><varname>Path</varname></entry> + <entry> + If entry is of type <constant>Application</constant>, the working directory to run the program in. + </entry> + <entry>string</entry> + <entry>NO</entry> + <entry>1</entry> + </row> + <row> + <entry id="key-terminal"><varname>Terminal</varname></entry> + <entry> + Whether the program runs in a terminal window. + </entry> + <entry>boolean</entry> + <entry>NO</entry> + <entry>1</entry> + </row> + <row> + <entry id="key-mimetype"><varname>MimeType</varname></entry> + <entry> + The MIME type(s) supported by this application. + </entry> + <entry>string(s)</entry> + <entry>NO</entry> + <entry>1</entry> + </row> + <row> + <entry id="key-categories"><varname>Categories</varname></entry> + <entry> + Categories in which the entry should be shown in a menu (for + possible values see the <ulink + url="http://www.freedesktop.org/Standards/menu-spec">Desktop + Menu Specification</ulink>). + </entry> + <entry>string(s)</entry> + <entry>NO</entry> + <entry>1</entry> + </row> + <row> + <entry id="key-startupnotify"><varname>StartupNotify</varname></entry> + <entry> + If true, it is KNOWN that the application will send a "remove" + message when started with the DESKTOP_STARTUP_ID environment variable set. + If false, it is KNOWN that the application does not work + with startup notification at all (does not shown any window, breaks + even when using StartupWMClass, etc.). + If absent, a reasonable handling is up to implementations (assuming false, + using StartupWMClass, etc.). (See the <ulink url="http://www.freedesktop.org/Standards/startup-notification-spec">Startup Notification Protocol Specification</ulink> for more details). + </entry> + <entry>boolean</entry> + <entry>NO</entry> + <entry>1</entry> + </row> + <row> + <entry id="key-startupwmclass"><varname>StartupWMClass</varname></entry> + <entry> + If specified, it is known that the application will map at least one + window with the given string as its WM class or WM name hint (see the <ulink url="http://www.freedesktop.org/Standards/startup-notification-spec">Startup Notification Protocol Specification</ulink> for more details). + </entry> + <entry>string</entry> + <entry>NO</entry> + <entry>1</entry> + </row> + <row> + <entry id="key-url"><varname>URL</varname></entry> + <entry> + If entry is Link type, the URL to access. + </entry> + <entry>string</entry> + <entry>YES</entry> + <entry>2</entry> + </row> + </tbody> + </tgroup> + </table> + </sect1> + <sect1 id="exec-variables"> + <title>The <varname>Exec</varname> key</title> + <para> + The <varname>Exec</varname> key must contain a command line. + A command line consists of an executable program optionally followed + by one or more arguments. + The executable program can either be specified with its full path or + with the name of the executable only. If no full path is provided the + executable is looked up in the $PATH environment variable used by the + desktop environment. + The name or path of the executable program may not contain the equal + sign ("="). Arguments are separated by a space. + </para> + <para> + Arguments may be quoted in whole. If an argument contains a reserved + character the argument must be quoted. The rules for quoting of + arguments is also applicable to the executable name or path of the + executable program as provided. + </para> + <para> + Quoting must be done by enclosing the argument between double quotes + and escaping the double quote character, backtick character ("`"), + dollar sign ("$") and backslash character ("\") by preceding it with an + additional backslash character. Implementations must undo quoting before + expanding field codes and before passing the argument to the executable + program. Reserved characters are space (" "), tab, newline, double + quote, single quote ("'"), backslash character ("\"), + greater-than sign (">"), less-than sign ("<"), + tilde ("~"), vertical bar ("|"), ampersand ("&"), semicolon (";"), + dollar sign ("$"), asterisk ("*"), question mark ("?"), hash mark ("#"), + parenthesis ("(") and (")") and backtick character ("`"). + </para> + <para> + Note that the general escape rule for values of type string states that + the backslash character can be escaped as ("\\") as well and that this + escape rule is applied before the quoting rule. As such, to + unambiguously represent a literal backslash character in a quoted + argument in a desktop entry file requires the use of four successive + backslash characters ("\\\\"). Likewise, a literal dollar sign in a + quoted argument in a desktop entry file is unambiguously represented + with ("\\$"). + </para> + <para> + A number of special field codes have been defined which will be + expanded by the file manager or program launcher when encountered + in the command line. + Field codes consist of the percentage character ("%") followed by + an alpha character. Literal percentage characters must be escaped + as <literal>%%</literal>. + Deprecated field codes should be removed from the command line and + ignored. + Field codes are expanded only once, the string that is used to + replace the field code should not be checked for field codes itself. + </para> + <para> + Command lines that contain a field code that is not listed in this + specification are invalid and must not be processed, in particular + implementations may not introduce support for field codes not listed + in this specification. Extensions, if any, should be introduced by + means of a new key. + </para> + <para> + Implementations must take care not to expand field codes into multiple + arguments unless explicitly instructed by this specification. + This means that name fields, filenames and other replacements that + can contain spaces must be passed as a single argument + to the executable program after expansion. + </para> + <para> + Although the <varname>Exec</varname> key is defined to have a value + of the type string, which is limited to ASCII characters, field code + expansion may introduce non-ASCII characters in arguments. + Implementations must take care that all characters in arguments + passed to the executable program are properly encoded according to + the applicable locale setting. + </para> + <para> + Recognized field codes are as follows: + </para> + <informaltable> + <tgroup cols="2"> + <thead> + <row> + <entry>Code</entry> + <entry>Description</entry> + </row> + </thead> + <tbody> + <row> + <entry><literal>%f</literal></entry> + <entry> + A single file name, even if multiple files are selected. The system + reading the desktop entry should recognize that the program in + question cannot handle multiple file arguments, and it should + should probably spawn and execute multiple copies of a program + for each selected file if the program is not able to handle + additional file arguments. If files are not on the local file system + (i.e. are on HTTP or FTP locations), the files will be copied to the local + file system and <literal>%f</literal> will be expanded to point at the temporary + file. Used for programs that do not understand the URL syntax. + </entry> + </row> + <row> + <entry><literal>%F</literal></entry> + <entry> + A list of files. Use for apps that can open several local + files at once. + Each file is passed as a separate argument to + the executable program. + </entry> + </row> + <row> + <entry><literal>%u</literal></entry> + <entry> + A single URL. Local files may either be passed as + file: URLs or as file path. + </entry> + </row> + <row> + <entry><literal>%U</literal></entry> + <entry> + A list of URLs. + Each URL is passed as a separate argument to + the executable program. Local files may either be passed as + file: URLs or as file path. + </entry> + </row> + <row> + <entry><literal>%d</literal></entry> + <entry> + Deprecated. + </entry> + </row> + <row> + <entry><literal>%D</literal></entry> + <entry> + Deprecated. + </entry> + </row> + <row> + <entry><literal>%n</literal></entry> + <entry> + Deprecated. + </entry> + </row> + <row> + <entry><literal>%N</literal></entry> + <entry> + Deprecated. + </entry> + </row> + <row> + <entry><literal>%i</literal></entry> + <entry> + The <varname>Icon</varname> key of the desktop entry + expanded as two arguments, first + <literal>--icon</literal> and then the value of the + <varname>Icon</varname> key. Should not expand to any + arguments if the <varname>Icon</varname> key is empty + or missing. + </entry> + </row> + <row> + <entry><literal>%c</literal></entry> + <entry> + The translated name of the application as listed in + the appropriate <varname>Name</varname> key in the + desktop entry. + </entry> + </row> + <row> + <entry><literal>%k</literal></entry> + <entry> + The location of the desktop file as either a URI (if for + example gotten from the vfolder system) or a local + filename or empty if no location is known. + </entry> + </row> + <row> + <entry><literal>%v</literal></entry> + <entry> + Deprecated. + </entry> + </row> + <row> + <entry><literal>%m</literal></entry> + <entry> + Deprecated. + </entry> + </row> + </tbody> + </tgroup> + </informaltable> + <para> + A command line may contain at most one %f, %u, %F or %U field code. + If the application should not open any + file the %f, %u, %F and %U field codes must be removed from the + command line and ignored. + </para> + <para> + Field codes must not be used inside a quoted argument, the result of + field code expansion inside a quoted argument is undefined. The %F and + %U field codes may only be used as an argument on their own. + </para> + </sect1> + <sect1 id="mime-types"> + <title>Registering MIME Types</title> + <para> + The <varname>MimeType</varname> key is used to indicate the MIME + Types that an application knows how to handle. It is expected that + for some applications this list could become long. An application + is expected to be able to reasonably open files of these types + using the command listed in the <varname>Exec</varname> key. + </para> + <para> + There should be no priority for MIME Types in this field, or any + form of priority in the desktop file. Priority for applications + is handled external to the <filename>.desktop</filename> files. + </para> +<!-- + <sect2 id="mime-caching"> + <title>Caching MIME Types</title> + <para> + To make parsing of all the desktop files less costly, a + <command>update-desktop-database</command> program is provided + that will generate a cache file. The concept is identical to + that of the 'update-mime-database' program in that it lets + applications avoid reading in (potentially) hundreds of files. + It will need to be run after every desktop file is installed. + One cache file is created for every directory in + $XDG_DATA_DIRS/applications/, and will create a file called + $XDG_DATA_DIRS/applications/mimeinfo.cache. + </para> + <para> + The format of the cache is similar to that of the desktop file, + and is just a list mapping mime-types to desktop files. Here's + a quick example of what it would look like: + </para> + <programlisting>application/x-foo=foo.desktop;bar.desktop; +application/x-bar=bar.desktop;</programlisting> + <para> + Each MIME Type is listed only once per cache file, and the + desktop-id is expected to exist in that particular directory. + That is to say, if the cache file is located at + <filename>/usr/share/applications/mimeinfo.cache</filename>, + bar.desktop refers to the file + <filename>/usr/share/applications/bar.desktop</filename>. + </para> + </sect2> + <sect2 id="mime-priority"> + <title>Priority of MIME Types and desktop files</title> + <para> + There is also a preference list to determine preferred + application of a given MIME Type. It defines the 'default' + application to handle a given MIME Type. It has the same format + as the cache list. + </para> + <programlisting>mime/type=desktop-id.desktop;</programlisting> + <para> + If a mime type is listed multiple times (either in the same + file, or in another file further down the search path), the + latter mention wins. If a listed file doesn't exist, or is + precluded through the <varname>OnlyShowIn</varname> or + <varname>NotShowIn</varname> keys, they should be ignored. + This means that applications will have to keep a history of the + preferred applications that they run into, so that if the top + desktop file for a given MIME Type isn't available, the second + one can be tested, etc. + </para> + <para> + It is also worth noting who this mechanism is defined for. It + is primarily intended for use by distributors/sysadmins to + provide a sane set of defaults for their users. Additionally, + users themselves can use this mechanism to override the user + defaults. We intentionally don't provide a way for application + authors themselves to list themselves as the default for a given + type, as we felt that that cannot work. + </para> + </sect2> +--> + </sect1> + <sect1 id="extending"> + <title>Extending the format</title> + <para> + If the standard is to be amended with a new <literal>{key,value}</literal> pair which + should be applicable to all supporting parties, a group discussion + will take place. This is the preferred method for introducing + changes. If one particular party wishes to add a field for personal + use, they should prefix the key with the string <varname>X-<replaceable>PRODUCT</replaceable></varname>, + e.g. <varname>X-NewDesktop-Foo</varname>, following the precedent set by other IETF and RFC + standards. + </para> + <para> + Alternatively, fields can be placed in their own group, where they may + then have arbitrary key names. If this is the case, the group should + follow the scheme outlined above, + i.e. <literal>[X-<replaceable>PRODUCT</replaceable> + <replaceable>GROUPNAME</replaceable>]</literal> or + something similar. These steps will avoid namespace clashes between + different yet similar environments. + </para> + </sect1> + <appendix id="example"> + <title>Example Desktop Entry File</title> + <programlisting> +[Desktop Entry] +Version=1.0 +Type=Application +Name=Foo Viewer +Comment=The best viewer for Foo objects available! +TryExec=fooview +Exec=fooview %F +Icon=fooview +MimeType=image/x-foo; +X-KDE-Library=libfooview +X-KDE-FactoryName=fooviewfactory +X-KDE-ServiceType=FooService</programlisting> + </appendix> + <appendix id="kde-items"> + <title>Currently reserved for use within KDE</title> + <para> + For historical reasons KDE is using some KDE-specific extensions + that are currently not prefixed by a <literal>X-KDE-</literal> prefix. + </para> + <itemizedlist> + <listitem> + <para> + KDE specific keys: <varname>ServiceTypes</varname>, + <varname>DocPath</varname>, <varname>Keywords</varname>, + <varname>InitialPreference</varname> + </para> + </listitem> + <listitem> + <para> + KDE specific types: <constant>ServiceType</constant>, + <constant>Service</constant> and <constant>FSDevice</constant> + </para> + </listitem> + </itemizedlist> + <para> + KDE uses the following additional keys for desktop entries of the + <constant>FSDevice</constant> type. + </para> + <table> + <title>FSDevice Specific Keys</title> + <tgroup cols="3"> + <thead> + <row> + <entry>Key</entry> + <entry>Description</entry> + <entry>Value Type</entry> + </row> + </thead> + <tbody> + <row> + <entry id="key-dev"><varname>Dev</varname></entry> + <entry> + The device to mount. + </entry> + <entry>string</entry> + </row> + <row> + <entry id="key-fstype"><varname>FSType</varname></entry> + <entry> + The type of file system to try to mount. + </entry> + <entry>string</entry> + </row> + <row> + <entry id="key-mountpoint"><varname>MountPoint</varname></entry> + <entry> + The mount point of the device in question. + </entry> + <entry>string</entry> + </row> + <row> + <entry id="key-readonly"><varname>ReadOnly</varname></entry> + <entry> + Specifies whether or not the device is read only. + </entry> + <entry>boolean</entry> + </row> + <row> + <entry id="key-unmounticon"><varname>UnmountIcon</varname></entry> + <entry> + Icon to display when device is not mounted. Mounted devices display icon from the <varname>Icon</varname> key. + </entry> + <entry>localestring</entry> + </row> + </tbody> + </tgroup> + </table> + </appendix> + <appendix id="deprecated-items"> + <title>Deprecated Items</title> + <para> + As this standard is quite old there are some deprecated items that + may or may not be used by several implementations. + </para> + <itemizedlist> + <listitem> + <para> + <literal>Type=MimeType</literal> is deprecated as there is a + new standard for this now, see the <ulink + url="http://www.freedesktop.org/Standards/shared-mime-info-spec">Shared + MIME-info Database specification</ulink> for more + information. In consequence the Keys + <varname>Patterns</varname> (various file name extensions + associated with the MIME type) and + <varname>DefaultApp</varname> (the default application + associated with this MIME type) are also deprecated. + </para> + </listitem> + <listitem> + <para> + Using <filename>.kdelnk</filename> instead of + <filename>.desktop</filename> as the file extension is + deprecated. + </para> + </listitem> + <listitem> + <para> + Using <literal>[KDE Desktop Entry]</literal> instead of + <literal>[Desktop Entry]</literal> as header is deprecated. + </para> + </listitem> + <listitem> + <para> + The <literal>Encoding</literal> key is deprecated. It was used to + specify whether keys of type <literal>localestring</literal> were + encoded in UTF-8 or in the specified locale. Possible values are + <literal>UTF-8</literal> and <literal>Legacy-Mixed</literal>. See + <xref linkend="legacy-mixed"/> for more details. + </para> + </listitem> + <listitem> + <para> + Deprecated <varname>Exec</varname> field codes: + <literal>%m</literal> (the mini-icon associated with the + desktop entry, this should be expanded as two arguments, + <literal>--miniicon</literal> and the content of the + <varname>MiniIcon</varname> key, it can also be ignored by + expanding it to no arguments), %v (the device as listed + in the <varname>Dev</varname> key in the desktop file), + %d (the directory of a file), %D (the directories of + files), %n (the base name of a file) and %N (the base names + of files). + </para> + </listitem> + <listitem> + <para> + Deprecated keys: <varname>MiniIcon</varname> (small icon for + menus, etc.), <varname>TerminalOptions</varname> (if the + program runs in a terminal, any options that should be + passed to the terminal emulator before actually executing + the program), <varname>Protocols</varname>, + <varname>Extensions</varname>, + <varname>BinaryPattern</varname>, + <varname>MapNotify</varname>. + </para> + </listitem> + <listitem> + <para> + The <literal>SwallowTitle</literal> and + <literal>SwallowExec</literal> keys are deprecated. + The <literal>SwallowTitle</literal> key is of type + <literal>localestring</literal> and specifies the title of the window + if is swallowed onto the panel. The <literal>SwallowExec</literal> + key is of type <literal>string</literal> and specifies the + program to exec if swallowed app is clicked. + </para> + </listitem> + <listitem> + <para> + The <literal>SortOrder</literal> key is deprecated. It is of type + <literal>string(s)</literal> and may be used to specify the order in + which to display files. The <ulink + url="http://www.freedesktop.org/Standards/menu-spec">Desktop + Menu Specification</ulink> defines another mechanism for defining the + order of menu items. + </para> + </listitem> + <listitem> + <para> + The <literal>FilePattern</literal> key is deprecated. + The value is a list of regular + expressions to match against for a file manager to determine if this + entry's icon should be displayed. Usually simply the name of the main + executable and friends. + </para> + </listitem> + <listitem> + <para> + Historically some booleans have been represented by the numeric + entries <constant>0</constant> or <constant>1</constant>. With + this version of the standard they are now to be represented as a + boolean string. However, if an implementation is reading a pre-1.0 + desktop entry, it should interpret <constant>0</constant> and + <constant>1</constant> as <constant>false</constant> and + <constant>true</constant>, respectively. + </para> + </listitem> + <listitem> + <para> + Historically lists have been comma separated. This is inconsistent with other lists which are separated by a semicolon. When reading a pre-1.0 desktop entry, comma separated lists should continue to be supported. + </para> + </listitem> + </itemizedlist> + </appendix> + <appendix id="legacy-mixed"> + <title>The <constant>Legacy-Mixed</constant> Encoding (Deprecated)</title> + <para> + The <constant>Legacy-Mixed</constant> encoding corresponds to the + traditional encoding of desktop files in older versions of the GNOME and + KDE desktop files. In this encoding, the encoding of each + <literal>localestring</literal> key is determined by the locale tag for + that key, if any, instead of being UTF-8. For keys without a locale tag, + the value must contain only ASCII characters. + </para> + <para> + If the file specifies an unsupported encoding, the implementation + should either ignore the file, or, if the user has requested a direct + operation on the file (such as opening it for editing), display an + appropriate error indication to the user. + </para> + <para> + In the absence of an <varname>Encoding</varname> key, the implementation may choose + to autodetect the encoding of the file by using such factors + as: + </para> + <itemizedlist> + <listitem> + <para> + The location of the file on the file system + </para> + </listitem> + <listitem> + <para> + Whether the contents of the file are valid UTF-8 + </para> + </listitem> + </itemizedlist> + <para> + If the implementation does not perform such auto-detection, it should + treat a file without an <varname>Encoding</varname> key in the same way as a file with an + unsupported <varname>Encoding</varname> key. + </para> + <para> + If the locale tag includes an <literal>.<replaceable>ENCODING</replaceable></literal> part, then that determines + the encoding for the line. Otherwise, the encoding is determined + by the language, or + <literal><replaceable>lang</replaceable>_<replaceable>COUNTRY</replaceable></literal> + pair from the locale tag, according to the following table. + </para> + <informaltable> + <tgroup cols="2"> + <thead> + <row> + <entry>Encoding</entry> + <entry>Aliases</entry> + <entry>Tags</entry> + </row> + </thead> + <tbody> + <row> + <entry>ARMSCII-8 (*)</entry><entry></entry><entry>hy</entry> + </row><row> + <entry>BIG5</entry><entry></entry><entry>zh_TW</entry> + </row><row> + <entry>CP1251</entry><entry></entry><entry>be bg</entry> + </row><row> + <entry>EUC-CN</entry><entry>GB2312</entry><entry>zh_CN</entry> + </row><row> + <entry>EUC-JP</entry><entry></entry><entry>ja</entry> + </row><row> + <entry>EUC-KR</entry><entry></entry><entry>ko</entry> + </row><row> + <entry>GEORGIAN-ACADEMY (*)</entry><entry></entry><entry></entry> + </row><row> + <entry>GEORGIAN-PS (*)</entry><entry></entry><entry>ka</entry> + </row><row> + <entry>ISO-8859-1</entry><entry></entry><entry>br ca da de en es eu fi fr gl it nl no pt sv wa</entry> + </row><row> + <entry>ISO-8859-2</entry><entry></entry><entry>cs hr hu pl ro sk sl sq sr</entry> + </row><row> + <entry>ISO-8859-3 </entry><entry></entry><entry>eo</entry> + </row><row> + <entry>ISO-8859-5</entry><entry></entry><entry>mk sp</entry> + </row><row> + <entry>ISO-8859-7</entry><entry></entry><entry>el</entry> + </row><row> + <entry>ISO-8859-9</entry><entry></entry><entry>tr</entry> + </row><row> + <entry>ISO-8859-13</entry><entry></entry><entry>lt lv mi</entry> + </row><row> + <entry>ISO-8859-14</entry><entry></entry><entry>cy ga</entry> + </row><row> + <entry>ISO-8859-15</entry><entry></entry><entry>et</entry> + </row><row> + <entry>KOI8-R</entry><entry></entry><entry>ru</entry> + </row><row> + <entry>KOI8-U</entry><entry></entry><entry>uk</entry> + </row><row> + <entry>TCVN-5712 (*)</entry><entry>TCVN</entry><entry>vi</entry> + </row><row> + <entry>TIS-620</entry><entry></entry><entry>th</entry> + </row><row> + <entry>VISCII</entry><entry></entry><entry></entry> + </row> + </tbody> + </tgroup> + </informaltable> + <variablelist> + <varlistentry> + <term>Encoding</term> + <listitem> + <para> + The name given here is listed here is typically the + canonical name for the encoding in the GNU C Library's + <function>iconv</function> facility. Encodings marked with (*) are not + currently supported by the GNU C Library; for this reason, + implementations may choose to ignore lines in desktop + files that resolve to this encoding. Desktop files with + these encodings are currently rare or non-existent. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>Aliases</term> + <listitem> + <para> + Other names for the encoding found in existing desktop + files. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>Tags</term> + <listitem> + <para> + Language tags for which this is the default encoding. + </para> + </listitem> + </varlistentry> + </variablelist> + <para> + This table above covers all tags and encodings that are known to + be currently in use. Implementors may choose to support + encodings not in the above set. For tags without defaults listed + in the above table, desktop file creators must specify the + <literal>.<replaceable>ENCODING</replaceable></literal> part of the locale tag. + </para> + <para> + Matching the <literal>.<replaceable>ENCODING</replaceable></literal> part of the locale tag against a locale + name or alias should be done by stripping all punctuation + characters from both the tag and the name or alias, converting + both name and alias to lowercase, and comparing the result. + This is necessary because, for example, <literal>Big5</literal> is frequently + found instead of <literal>BIG5</literal> and <literal>georgianacademy</literal> instead of + <literal>GEORGIAN-ACADEMY</literal>. Desktop files creators should, however, use + the name as it appears in the "Encoding" column above. + </para> + </appendix> +</article> diff --git a/help-system/help-system-spec.xml b/help-system/help-system-spec.xml new file mode 100644 index 0000000..ffe1a5d --- /dev/null +++ b/help-system/help-system-spec.xml @@ -0,0 +1,195 @@ +<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" +"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ +]> +<article id="index"> + <title>Help System Specification</title> + + <articleinfo> + <title>Help System Specification</title> + <date>2010-04-30</date> + <authorgroup> + <author> + <firstname>Shaun</firstname> + <surname>McCance</surname> + <affiliation> + <address> + <email>shaunm@gnome.org</email> + </address> + </affiliation> + </author> + </authorgroup> + </articleinfo> + + <section id="overview"> + <title>Overview</title> + <para>This specification provides a common directory layout and URI + scheme for locally installed help documents. Documents installed and + referenced using this system will have better interoperability between + different desktop environments and help applications.</para> + </section> + + <section id="layout"> + <title>Directory Layout</title> + + <para>A document is a collection of files, possibly from multiple + directories in a path. Documents may be in any format, or even in + multiple formats; see <xref linkend="formats"/> for details. A + document has a <emphasis>document identifier</emphasis> that + identifies it uniquely and specifies where it can be found on + the file system. A document identifier consists of one or more + characters from the following: digits (U+0030-U+0039), letters + (U+0041-U+005A and U+0061-U+007A), hyphen (U+002D), underscore + (U+005F), period (U+002E), and percent (U+0025).</para> + + <para>Document identifiers are not explicitly namespaced. To + avoid conflicts, document identifiers should start with the name + of the application or package that provides the document. In many + cases, the name of the application or package alone may be used. + Otherwise, the document identifier should start with the name + of the package or application followed by a hyphen.</para> + + <para>Documents are installed under the <filename>help</filename> + subdirectory in <envar>$XDG_DATA_HOME</envar> or in the + <envar>$XDG_DATA_DIRS</envar> path. See the + <ulink url="http://standards.freedesktop.org/basedir-spec/latest/">XDG + Base Directory Specification</ulink> for details on <envar>$XDG_DATA_HOME</envar> + and <envar>$XDG_DATA_DIRS</envar>. Each <filename>help</filename> + directory in the path contains subdirectories for languages. Each + language subdirectory contains subdirectories for documents, where + the name of each subdirectory matches the document identifier of + a document.</para> + + <para>The <emphasis>document path</emphasis> for a given document + is the list of directories of the following form:</para> + + <programlisting><replaceable>datadir</replaceable>/help/<replaceable>lang</replaceable>/<replaceable>document</replaceable></programlisting> + + <variablelist> + <varlistentry> + <term><filename><replaceable>datadir</replaceable></filename></term> + <listitem><para>Either <envar>$XDG_DATA_HOME</envar> or a directory in + the <envar>$XDG_DATA_DIRS</envar> path.</para></listitem> + </varlistentry> + <varlistentry> + <term><filename><replaceable>lang</replaceable></filename></term> + <listitem><para>The language code of a language in the user's + list of preferred languages.</para></listitem> + </varlistentry> + <varlistentry> + <term><filename><replaceable>document</replaceable></filename></term> + <listitem><para>The document identifier of the document.</para></listitem> + </varlistentry> + </variablelist> + + <para>The document path is ordered first according to the position of + <filename><replaceable>datadir</replaceable></filename> in the path, then + by the position of <filename><replaceable>lang</replaceable></filename> + in the user's preferred list of languages. So, for example, if the + user's preferred language list is <systemitem>pt_BT:pt:C</systemitem>, + then <filename>~/.local/share/help/pt/beanstalk</filename> would take + precedence over <filename>/usr/share/help/pt_BR/beanstalk</filename>.</para> + </section> + + <section id="uri-scheme"> + <title>URI Scheme</title> + + <para>Documents are referenced using the <systemitem>help:</systemitem> + URI scheme. The <systemitem>help:</systemitem> URI scheme has the + following form:</para> + + <programlisting>help:<replaceable>document</replaceable>/<replaceable>page</replaceable>?<replaceable>options</replaceable>#<replaceable>anchor</replaceable></programlisting> + + <variablelist> + <varlistentry> + <term><replaceable>document</replaceable></term> + <listitem><para>The document identifier.</para></listitem> + </varlistentry> + <varlistentry> + <term><replaceable>page</replaceable></term> + <listitem><para>An identifier for a page within the document. Documents + often consist of multiple logical pages, which may not be reflected in + the actual files on the system. The page identifier is optional. If it + is not present, the preceding <systemitem>/</systemitem> character + should be omitted.</para></listitem> + </varlistentry> + <varlistentry> + <term><replaceable>options</replaceable></term> + <listitem><para>Additional options that can influence how applications + present a document. Options are optional. If they are not present, the + preceding <systemitem>?</systemitem> character should be omitted. If + they are present, they must conform to the + <systemitem>application/x-www-form-urlencoded</systemitem> MIME type. + Options may be used, for example, to override language settings or to + provide keys for conditional processing. This specification makes no + specific recommendations for the options.</para></listitem> + </varlistentry> + <varlistentry> + <term><replaceable>anchor</replaceable></term> + <listitem><para>An anchor point within a page. Applications should + scroll to an appropriate point whenever possible. The anchor is + optional. If it is not present, the preceding <systemitem>#</systemitem> + character should be omitted.</para></listitem> + </varlistentry> + </variablelist> + + <para>Page identifiers and anchors may contain any character that is + valid in a document identifier. Some document types may have further + restrictions on page identifiers or anchors.</para> + </section> + + <section id="formats"> + <title>Help Formats</title> + + <para>Documents may be installed in any format. Not all help applications + may recognize and handle the same types of documents. Whenever possible, + help applications should support HTML. Documents may be installed in + multiple formats. Help applications choose which format to use when + multiple formats are present.</para> + + <para>For any format, a help application must map the information found + in the <systemitem>help:</systemitem> URI scheme to the information in + that format. This specification contains recommendations for finding + and handling documents in DocBook, Mallard, HTML, and XHTML.</para> + + <section id="docbook"> + <title>DocBook</title> + <para>DocBook documents have a file named <filename>index.docbook</filename> + in the document path. Any files referenced from the DocBook file, including + XML fragments included through XInclude, should be looked up according to + the document path.</para> + <para>When a help application displays a DocBook document, it will often + display it in multiple pages or chunks, rather than as a single long page. + The page identifier specifies which chunk to display. Not all applications + will split a DocBook document into chunks in the same way, so the page + identifier may not map exactly to the <sgmltag>id</sgmltag> attribute + of an element that is chunked. In this case, the applicaiton displays + the nearest enclosing chunk and treats the page identifier as an anchor + if no anchor was explicitly provided.</para> + </section> + + <section id="mallard"> + <title>Mallard</title> + <para>Mallard documents have a file named <filename>index.page</filename> + in the document path. Other page files may be different directories in + the document path. Any files referenced in any page file, including XML + fragments included through XInclude, should be looked up according to + the document path.</para> + <para>The page identifier specifies the id of a Mallard page file. The + anchor specifies the id of a section within a Mallard page file.</para> + </section> + + <section id="html"> + <title>HTML and XHTML</title> + <para>HTML documents have a file named <filename>index.html</filename> + in the document path. XHTML documents have a file named <filename>index.xhtml</filename> + in the document path. Other HTML or XHTML files in the document may + be in different directories in the document path. Any files referenced + in any HTML or XHTML page, including XML fragments included through + XInclude in XHTML, should be looked up according to the document path.</para> + <para>The page identifier specifies the base file name, without the + <filename>.html</filename> or <filename>.xhtml</filename> extension, + of an HTML or XHTML file in the document. The anchor specifies a named + anchor within the HTML or XHTML file.</para> + </section> + </section> +</article> diff --git a/menu/.cvsignore b/menu/.cvsignore new file mode 100644 index 0000000..f90eaaf --- /dev/null +++ b/menu/.cvsignore @@ -0,0 +1,11 @@ +config.log +config.status +config.sub +configure +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +config.guess +config.h +config.h.in diff --git a/menu/AUTHORS b/menu/AUTHORS new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/menu/AUTHORS diff --git a/menu/COPYING b/menu/COPYING new file mode 100644 index 0000000..73e7995 --- /dev/null +++ b/menu/COPYING @@ -0,0 +1,2 @@ +FIXME - we need a license for specs + diff --git a/menu/ChangeLog b/menu/ChangeLog new file mode 100644 index 0000000..025e9e1 --- /dev/null +++ b/menu/ChangeLog @@ -0,0 +1,143 @@ +2009-01-10 Vincent Untz <vuntz@gnome.org> + + * menu-spec.xml: bump version to 1.1-draft + +2009-01-10 Vincent Untz <vuntz@gnome.org> + + * menu-spec.xml: add LXDE as registered desktop environment for + OnlyShowIn. + See http://lists.freedesktop.org/archives/xdg/2008-December/010103.html + +2007-08-18 Vincent Untz <vuntz@gnome.org> + + * menu-spec.xml: accept X-Foo for environments in + OnlyShowIn/NotShowIn. + Fix bug #11564. + +2007-07-27 Vincent Untz <vuntz@gnome.org> + + * menu-spec.xml: change sysconfdir/desktop/menus/ to sysconfdir/menus/ + in one place. + Fix bug #8289. + +2007-02-06 Waldo Bastian <waldo.bastian@intel.com> + * Added scondary menu categories + * Bumped version to 1.0 + +2007-01-18 Waldo Bastian <waldo.bastian@intel.com> + + * Added support for LSB's tet testing framework + + * Renamed test to more meaningful names: + 1 -> Category + 2 -> OnlyUnallocated + 3 -> Deleted + 4 -> Move + 5 -> All + 6 -> Filename + 7 -> And + 8 -> Or + 9 -> Exclude + a -> DesktopFileID + b -> menu-multiple-matching + c -> Directory + d -> submenu-collision + e -> LegacyDir-relative + f -> Move-collapsing + g -> AppDir-relative + h -> DirectoryDir-relative + i -> DefaultMergeDirs + j -> MergeDir-relative + k -> MergeFile-relative + l -> MergeFile2 + m -> NoDisplay + n -> NoDisplay2 + o -> boolean-logic + p -> MergeFile3 + q -> MergeFile-parent + r -> MergeFile-path + s -> desktop-name-collision + t -> Move-ordering + u -> MergeFile-recursive + v -> NotOnlyUnallocated-default + w -> LegacyDir-Move + x -> Move-submenu + y -> Merge-combined + + * Added the following new tests: + AppDir + DirectoryDir + MergeDir-absolute + MergeFile-absolute + official-categories + +2006-03-28 Waldo Bastian <waldo.bastian@intel.com> + + * menu-spec.xml: Added example for installing sub-menu. + +2006-03-21 Waldo Bastian <waldo.bastian@intel.com> + + * menu-spec.xml: Recommend to use /usr/share for datadir + +2005-03-30 Waldo Bastian <bastian@kde.org> + + * menu-spec.xml: Change semantics and remove restrictions on <Move> + element to facilitate menu editing. + +2005-03-23 Waldo Bastian <bastian@kde.org> + + * menu-spec.xml: Clearify DTD conformance and version compatibility + +2005-03-22 Waldo Bastian <bastian@kde.org> + + * menu-spec.xml, menu.dtd: Added type attribute to <MergeFile> + element to facilitate menu-editing. + +2005-02-24 Waldo Bastian <bastian@kde.org> + + * menu-spec.xml: Fixed links to www.freedesktop.org + +2004-12-13 Mark McLoughlin <mark@skynet.ie> + + * menu-spec.xml: elaboration from Waldo. + +2004-12-08 Mark McLoughlin <mark@skynet.ie> + + * menu-spec.xml: make <OnlyUnallocated/> be for entries + which don't match any <Include> rule rather than entries + which don't appear in any menu. + +2004-09-03 Mark McLoughlin <mark@skynet.ie> + + * menu-spec.xml: minor typo - "This specification adds two + new fields to desktop entries" - s/two/three/ + +2004-05-07 Mark McLoughlin <mark@skynet.ie> + + * menu-spec.xml: fix typo in <Menuname> description. Its + inline_header rather than inline_title according to the DTD. + +2004-04-18 Mark McLoughlin <mark@skynet.ie> + + Patch from Ville Skyttä <ville.skytta@iki.fi> + + * menu-spec.xml: editorial changes and typo fixes. + +2003-12-12 Waldo Bastian <bastian@kde.org> + * menu-spec.xml: Correct example in "Legacy Menu Hierarchies" + +2003-11-09 Heinrich Wendel <h_wendel@cojobo.net> + * menu-spec.xml: patch for categories based on Suse 9.0 + * menu-spec.xml: Grahpics -> Graphics + * menu-spec.xml: DTD fix + * menu.dtd: added dtd + * testsuite: fixed errors highlighted by havoc + +2003-10-23 Havoc Pennington <hp@redhat.com> + + * menu-spec.xml: clarify how <Move> elements are resolved + +2003-10-21 Havoc Pennington <hp@redhat.com> + + * create autotools setup + diff --git a/menu/Makefile.am b/menu/Makefile.am new file mode 100644 index 0000000..92448da --- /dev/null +++ b/menu/Makefile.am @@ -0,0 +1,16 @@ +HTML_FILES= menu-spec.html + +XML_FILES= menu-spec.xml + +EXTRA_DIST= $(HTML_FILES) $(XML_FILES) + +if XML_DOCS_ENABLED +all-local: $(HTML_FILES) +endif + +%.html: %.xml + $(XMLTO) html-nochunks $< + +maintainer-clean-local: + rm -f $(HTML_FILES) + diff --git a/menu/NEWS b/menu/NEWS new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/menu/NEWS diff --git a/menu/README b/menu/README new file mode 100644 index 0000000..0edf632 --- /dev/null +++ b/menu/README @@ -0,0 +1 @@ +This is the specification and test suite for the menu system. diff --git a/menu/autogen.sh b/menu/autogen.sh new file mode 100755 index 0000000..b1376df --- /dev/null +++ b/menu/autogen.sh @@ -0,0 +1,3 @@ +#! /bin/sh +autoreconf -v --install || exit 1 +./configure --enable-maintainer-mode "$@" diff --git a/menu/configure.in b/menu/configure.in new file mode 100644 index 0000000..7a5a76c --- /dev/null +++ b/menu/configure.in @@ -0,0 +1,61 @@ +dnl -*- mode: m4 -*- +AC_PREREQ(2.52) + +AC_INIT(menu-spec.xml) + +AM_INIT_AUTOMAKE(desktop-menu-spec, 0.7) + +# Honor aclocal flags +ACLOCAL="$ACLOCAL $ACLOCAL_FLAGS" + + ## must come before we use the $USE_MAINTAINER_MODE variable later +AM_MAINTAINER_MODE + +AC_ARG_ENABLE(xml-docs, [ --enable-xml-docs build XML into HTML (requires xmlto)],enable_xml_docs=$enableval,enable_xml_docs=auto) + +### XML tools + +AC_PATH_PROG(XMLTO, xmlto, no) + +AC_MSG_CHECKING([whether to build XML documentation]) + +if test x$XMLTO = xno ; then + have_xmlto=no +else + have_xmlto=yes +fi + +if test x$enable_xml_docs = xauto ; then + if test x$have_xmlto = xno ; then + enable_xml_docs=no + else + enable_xml_docs=yes + fi +fi + +if test x$enable_xml_docs = xyes; then + if test x$have_xmlto = xno; then + AC_MSG_ERROR([Building XML docs explicitly required, but xmlto not found]) + fi +fi + +AM_CONDITIONAL(XML_DOCS_ENABLED, test x$enable_xml_docs = xyes) +AC_MSG_RESULT(yes) + +AC_OUTPUT([ +Makefile +]) + +dnl ========================================================================== +echo " + Menu specification $VERSION + ============== + + prefix: ${prefix} + source code location: ${srcdir} + xmlto: ${XMLTO}" + +echo " + Maintainer mode: ${USE_MAINTAINER_MODE} + Building XML docs: ${enable_xml_docs} +" diff --git a/menu/menu-spec.xml b/menu/menu-spec.xml new file mode 100644 index 0000000..28c0097 --- /dev/null +++ b/menu/menu-spec.xml @@ -0,0 +1,2383 @@ +<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" + "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ + <!ENTITY version "1.1-draft"> + <!ENTITY dtd-version "1.0"> + ]> + +<article id="index"> + <articleinfo> + <title>Desktop Menu Specification</title> + <releaseinfo>Version &version;</releaseinfo> + <date>31 March 2011</date> + <authorgroup> + <author> + <firstname>Waldo</firstname> + <surname>Bastian</surname> + <affiliation> + <address> + <email>waldo.bastian@intel.com</email> + </address> + </affiliation> + </author> + <author> + <firstname>Francois</firstname> + <surname>Gouget</surname> + <affiliation> + <address> + <email>fgouget@codeweavers.com</email> + </address> + </affiliation> + </author> + <author> + <firstname>Alex</firstname> + <surname>Graveley</surname> + <affiliation> + <address> + <email>alex@ximian.com</email> + </address> + </affiliation> + </author> + <author> + <firstname>George</firstname> + <surname>Lebl</surname> + <affiliation> + <address> + <email>jirka@5z.com</email> + </address> + </affiliation> + </author> + <author> + <firstname>Havoc</firstname> + <surname>Pennington</surname> + <affiliation> + <address> + <email>hp@pobox.com</email> + </address> + </affiliation> + </author> + <author> + <firstname>Heinrich</firstname> + <surname>Wendel</surname> + <affiliation> + <address> + <email>h_wendel@cojobo.net</email> + </address> + </affiliation> + </author> + </authorgroup> + </articleinfo> + + <sect1 id="introduction"> + <title>Introduction</title> + <para> + This document defines how to construct a user-visible hierarchy of + applications, typically displayed as a menu. It allows third-party + software to add menu items that work for all desktops, and allows system + administrators to edit menus in a way that affects all desktops. + </para> + <para> + The basic scheme is very simple. Information about each application (menu + item) is stored in a desktop entry (see <ulink + url="http://www.freedesktop.org/Standards/desktop-entry-spec">Desktop + Entry Standard</ulink>). Then an XML configuration file defines the + hierarchical arrangement (layout) of menu items, and which menu items are + actually displayed. + </para> + <para> + Things are complicated somewhat by the need to support legacy desktop + entry hierarchies, and the need to allow third parties to extend the menu + layout. Both of these issues are addressed by the idea of + <firstterm>merging</firstterm> two menu layouts. + </para> + <para> + In addition to a strict definition of the contents of each menu this + specification also foresees in a number of layout / presentation hints. + This part of the specification is optional, implementations may chose to + ignore these hints. + </para> + </sect1> + <sect1 id="paths"> + <title>File locations</title> + <para> + Files involved in this specification are located according to the <ulink + url="http://www.freedesktop.org/Standards/basedir-spec">"desktop + base directory specification"</ulink>. + </para> + <para> + Here are the files defined by this specification: + <variablelist> + <varlistentry> + +<term><varname>$XDG_CONFIG_DIRS</varname>/menus/<varname>${XDG_MENU_PREFIX}</varname>applications.menu</term> + <listitem> + <para> + This file contains the XML definition of the main application + menu layout. The first file found in the search path should be + used; other files are ignored. This implies that if the user + has their own <varname>${XDG_MENU_PREFIX}</varname>applications.menu, + it replaces the system wide one. + (Though the user's menu may explicitly merge the system wide + one.) + </para> + <para> + Systems that offer multiple desktop environments and that want + to use distinct menu layouts in the different environments can + use differently prefixed .menu files. In this case the + <varname>$XDG_MENU_PREFIX</varname> environment variable must + be set by the system to reflect the .menu file that is being + used. + </para> + <para> + For example if a system contains both the GNOME and the KDE + desktop environments it can decide to use + gnome-applications.menu as the menu layout in GNOME sessions + and kde-applications.menu as the menu layout in KDE sessions. + To correctly reflect this, it should set the + <varname>$XDG_MENU_PREFIX</varname> environment variable to + "gnome-" respectively "kde-". + </para> + <para> + Implementations may chose to use .menu files with other names + for tasks or menus other than the main application menu. Such + usage is not covered by this specification. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>$XDG_CONFIG_DIRS</varname>/menus/applications-merged/</term> + <listitem> + <para> + The default merge directories included in the + <DefaultMergeDirs> element. By convention, third parties + may add new <Menu> files in this location to create their + own sub-menus. + </para> + <para> + Note that a system that uses either gnome-applications.menu or + kde-applications.menu depending on the desktop environment in + use must still use applications-merged as the default merge + directory in both cases. + </para> + <para> + Implementations may chose to use .menu files with names other + than application.menu for tasks or menus other than the main + application menu. In that case the first part of the name of + the default merge directory is derived from the name of the + .menu file. + </para> + <para> + For example in a system that uses a preferences.menu file to + describe an additional menu, the default merge directories + included in the <DefaultMergeDirs> element in the + preferences.menu file would become + <varname>$XDG_CONFIG_DIRS</varname>/menus/preferences-merged/ + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>$XDG_DATA_DIRS</varname>/applications/</term> + <listitem> + <para> + This directory contains a .desktop file for each possible menu + item. Each directory in the <varname>$XDG_DATA_DIRS</varname> + search path should be used (i.e. desktop entries are collected + from all of them, not just the first one that exists). When two + desktop entries have the same name, the one appearing earlier in + the path is used. + </para> + <para> + The <DefaultAppDirs> element in a menu file indicates that + this default list of desktop entry locations should be scanned at + that point. If a menu file does not contain + <DefaultAppDirs>, then these locations are not scanned. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><varname>$XDG_DATA_DIRS</varname>/desktop-directories/</term> + <listitem> + <para> + This directory contains directory entries which may be associated + with folders in the menu layout. Each directory + in the search path should be used. Only files ending in + .directory are used; other files are ignored. + </para> + <para> + The <DefaultDirectoryDirs> element in a menu file indicates that + this default list of directory entry locations should be scanned at + that point. If a menu file does not contain + <DefaultDirectoryDirs>, then these locations are not scanned. + </para> + </listitem> + </varlistentry> + </variablelist> + </para> + </sect1> + <sect1 id="desktop-entry-extensions"> + <title>Extensions to the desktop entry format</title> + <para> + This specification adds three new fields to <ulink + url="http://www.freedesktop.org/Standards/desktop-entry-spec">desktop + entries</ulink>: <varname>Categories</varname>, + <varname>OnlyShowIn</varname> and <varname>NotShowIn</varname>. + </para> + <para> + The <varname>Categories</varname> field is a list of strings used to + classify menu items. For example, applications in the + <literal>AudioVideo</literal> category might end up in the + "Sound & Video" submenu. <xref linkend="category-registry"/> + enumerates the standard categories. Categories not in this document + must be prefixed by the string "X-" indicating that they are extensions. + Categories are case-sensitive. + </para> + <para> + Desktop entries should list all categories that clearly apply. They should + not list categories that only vaguely or possibly apply, because the user + will end up seeing the same desktop entry in a half-dozen places. But + it's typical that several categories will apply to a given desktop entry. + </para> + <para> + The <varname>OnlyShowIn</varname> field is a list of strings identifying + the environments that should display a given menu item. If an + <varname>OnlyShowIn</varname> field is present, a given environment should + only display the menu item if the string identifying that environment is + present. The strings are case-sensitive. <xref + linkend="onlyshowin-registry"/> enumerates the strings to use for + some common environments. + </para> + <para> + The <varname>NotShowIn</varname> field is a list of strings identifying + the environments that should not display a given menu item. If an + <varname>NotShowIn</varname> field is present, a given environment should + only display the menu item if the string identifying that environment is + not present. The strings are case-sensitive. <xref + linkend="onlyshowin-registry"/> enumerates the strings to use for + some common environments. + </para> + <para> + Environments not in this document must be prefixed by the string "X-" + indicating that they are extensions. Environments are case-sensitive. + </para> + <sect2 id="desktop-entry-extensions-examples"> + <title>Examples of using <varname>Categories</varname> and <varname>OnlyShowIn</varname></title> + <para> + A desktop entry for a Qt-based image viewer might contain + this <varname>Categories</varname> line: + <informalexample> + <programlisting> + Categories=Qt;Graphics;RasterGraphics;Viewer; + </programlisting> + </informalexample> + </para> + <para> + A desktop entry for Octave, a command-line mathematics program (which + would also have the field <literal>Terminal=true</literal>), might have: + <informalexample> + <programlisting> + Categories=ConsoleOnly;Math; + </programlisting> + </informalexample> + </para> + <para> + A desktop entry for a GNOME-specific calculator program + that should only appear in GNOME might have: + <informalexample> + <programlisting> + Categories=GNOME;Utility; + OnlyShowIn=GNOME; + </programlisting> + </informalexample> + Note that the <varname>OnlyShowIn</varname> field is a + <emphasis>list</emphasis> and thus ends in a semicolon. + </para> + </sect2> + </sect1> + <sect1 id="menu-file-format"> + <title>Format of menu files</title> + <para> + Menu files must be well-formed XML files and end in the extension + ".menu". They should also conform to the menu file DTD which implies + that implementation-specific extensions to the file format are not + allowed. Implementations may stop processing if they encounter a menu + file which does not comply with the associated DTD. Note that the + associated DTD may differ in version from the one defined in this document. + </para> + <para> + When an implementation updates an existing menu file it may need to + update the identifier to a newer version of the DTD. Implementations + should never update the identifier of an existing menu file to an + older version. In order to remain compatible with newer versions, + implementations should ignore and preserve any XML elements, + attributes and attribute values that it does not know how to handle. + </para> + <sect2 id="menu-file-doctype"> + <title>Document Type Declaration</title> + <para> + Menu files for this version of the specification must use the following + namespace, public and system identifiers: + <variablelist> + <varlistentry> + <term>Namespace</term> + <listitem> + <para> + <literal>http://www.freedesktop.org/standards/menu</literal> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>Public Identifier for &version;</term> + <listitem> + <para> + <literal>PUBLIC "-//freedesktop//DTD Menu &dtd-version;//EN"</literal> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>System Identifier for &version;</term> + <listitem> + <para> +<literal>http://www.freedesktop.org/standards/menu-spec/menu-&dtd-version;.dtd</literal> + </para> + </listitem> + </varlistentry> + </variablelist> + + Here is a sample document type declaration: + <informalexample> + <programlisting> + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu &dtd-version;//EN" + "http://www.freedesktop.org/standards/menu-spec/menu-&dtd-version;.dtd"> + </programlisting> + </informalexample> + + All menu files MUST include the document type declaration, so that + implementations can adapt to different versions of this specification + (and so implementations can validate the menu file against + the DTD). + </para> + </sect2> + <sect2 id="menu-file-elements"> + <title>Elements</title> + <para> + <variablelist> + <varlistentry> + <term><Menu></term> + <listitem> + <para> + The root element is <Menu>. Each <Menu> element may + contain any number of nested <Menu> elements, indicating submenus. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><AppDir></term> + <listitem> + <para> + This element may only appear below <Menu>. The + content of this element is a directory name. Desktop entries + in this directory are scanned and added to the pool of entries + which can be included in this <Menu> and its submenus. + Only files ending in ".desktop" should be used, other files are + ignored. + </para> + <para> + Desktop entries in the pool of available entries are identified + by their <firstterm>desktop-file id</firstterm> (see <xref + linkend="term-desktop-file-id"/>). + The desktop-file id of a desktop entry is equal to its filename, + with any path components removed. + So given a <AppDir> + <filename>/foo/bar</filename> and desktop entry + <filename>/foo/bar/Hello.desktop</filename> the desktop + entry would get a desktop-file id of <filename>Hello.desktop</filename> + </para> + <para> + If the directory contains sub-directories then these sub-directories + should be (recursively) scanned as well. The name of the subdirectory + should be added as prefix to the desktop-file id together with a dash character ("-") + So given a <AppDir> + <filename>/foo/bar</filename> and desktop entry + <filename>/foo/bar/booz/Hello.desktop</filename> the desktop + entry would get a desktop-file id of <filename>booz-Hello.desktop</filename> + A desktop entry <filename>/foo/bar/bo/oz/Hello.desktop</filename> would result + in a desktop-file id of <filename>bo-oz-Hello.desktop</filename> + </para> + <para> + <AppDir> elements appearing later in the menu file have + priority in case of collisions between desktop-file ids. + </para> + <para> + If the filename given as an <AppDir> is not an absolute + path, it should be located relative to the location of the menu + file being parsed. + </para> + <para> + Duplicate <AppDir> elements (that specify the same + directory) should be ignored, but the <emphasis>last</emphasis> + duplicate in the file should be used when establishing the order + in which to scan the directories. This is important when merging + (see <xref linkend="merge-algorithm"/>). The order of + <AppDir> elements with respect to <Include> and + <Exclude> elements is not relevant, also to facilitate + merging. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><DefaultAppDirs></term> + <listitem> + <para> + This element may only appear below <Menu>. The element has + no content. The element should be treated as if it were a list + of <AppDir> elements containing the default app dir + locations + (<replaceable>datadir</replaceable>/applications/ etc.). When expanding + <DefaultAppDirs> to a list of <AppDir>, the default + locations that are earlier in the search path go later in the + <Menu> so that they have priority. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><DirectoryDir></term> + <listitem> + <para> + This element may only appear below <Menu>. The content of + this element is a directory name. Each directory listed in a + <DirectoryDir> element will be searched for directory + entries to be used when resolving the <Directory> element + for this menu and its submenus. + If the filename given as a <DirectoryDir> is not an absolute path, + it should be located relative to the location + of the menu file being parsed. + </para> + <para> + Directory entries in the pool of available entries are identified + by their <firstterm>relative path</firstterm> (see <xref + linkend="term-relative-path"/>). + </para> + <para> + If two directory entries have duplicate relative paths, the one from + the last (furthest down) element in the menu file must be used. + Only files ending in the extension ".directory" should be + loaded, other files should be ignored. + </para> + <para> + Duplicate <DirectoryDir> elements (that specify the same + directory) are handled as with duplicate <AppDir> + elements (the last duplicate is used). + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><DefaultDirectoryDirs></term> + <listitem> + <para> + This element may only appear below <Menu>. The element has + no content. The element should be treated as if it were a list + of <DirectoryDir> elements containing the default desktop dir + locations + (<replaceable>datadir</replaceable>/desktop-directories/ etc.). The default + locations that are earlier in the search path go later in the + <Menu> so that they have priority. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Name></term> + <listitem> + <para> + Each <Menu> element must have a single <Name> + element. The content of the <Name> element is a name to + be used when referring to the given menu. Each submenu of a + given <Menu> must have a unique name. <Menu> + elements can thus be referenced by a menu path, for example + "Applications/Graphics." The <Name> field must not contain + the slash character ("/"); implementations should discard + any name containing a slash. See also <xref linkend="term-menu-path"/>. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Directory></term> + <listitem> + <para> + Each <Menu> element has any number of <Directory> + elements. The content of the <Directory> element + is the relative path of a directory entry containing meta information + about the <Menu>, such as its icon and localized name. + If no <Directory> is specified for a <Menu>, + its <Name> field should be used as the user-visible + name of the menu. + </para> + <para> + Duplicate <Directory> elements are allowed in order + to simplify menu merging, and allow user menus to override + system menus. The last <Directory> element to appear + in the menu file "wins" and other elements are ignored, + unless the last element points to a nonexistent directory + entry, in which case the previous element should be tried instead, + and so on. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><OnlyUnallocated> and <NotOnlyUnallocated></term> + <listitem> + <para> + Each <Menu> may contain any number of + <OnlyUnallocated> and <NotOnlyUnallocated> + elements. Only the last such element to appear is relevant, as + it determines whether the <Menu> can contain any desktop + entries, or only those desktop entries that do not match other + menus. If neither <OnlyUnallocated> nor + <NotOnlyUnallocated> elements are present, the default + is <NotOnlyUnallocated>. + </para> + <para> + To handle <OnlyUnallocated>, the menu file must be + analyzed in two conceptual passes. The first pass processes + <Menu> elements that can match any desktop entry. During + this pass, each desktop entry is marked as allocated according + to whether it was matched by an <Include> rule in some + <Menu>. The second pass processes only <Menu> + elements that are restricted to unallocated desktop entries. + During the second pass, queries may only match desktop entries + that were not marked as allocated during the first pass. + See <xref linkend="query-algorithm"/>. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Deleted> and <NotDeleted></term> + <listitem> + <para> + Each <Menu> may contain any number of <Deleted> and + <NotDeleted> elements. Only the last such element to + appear is relevant, as it determines whether the <Menu> + has been deleted. If neither <Deleted> nor + <NotDeleted> elements are present, the default is + <NotDeleted>. The purpose of this element is to support + menu editing. If a menu contains a <Deleted> element + not followed by a <NotDeleted> element, that menu + should be ignored. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Include></term> + <listitem> + <para> + An <Include> element is a set of rules attempting to match + some of the known desktop entries. The <Include> element + contains a list of any number of matching rules. Matching rules + are specified using the elements <And>, <Or>, + <Not>, <All>, <Filename>, and + <Category>. Each rule in a list of rules has a logical OR + relationship, that is, desktop entries which match any rule + are included in the menu. + </para> + <para> + <Include> elements must appear immediately under + <Menu> elements. The desktop entries they match are + included in the menu. <Include> and <Exclude> + elements for a given <Menu> are processed in order, + with queries earlier in the file handled first. This has + implications for merging, see <xref linkend="merge-algorithm"/>. + See <xref linkend="query-algorithm"/> for full details on + how to process <Include> and <Exclude> elements. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Exclude></term> + <listitem> + <para> + Any number of <Exclude> elements may appear below a + <Menu> element. The content of an <Exclude> element + is a list of matching rules, just as with an + <Include>. However, the desktop entries matched are + removed from the list of desktop entries included so far. (Thus + an <Exclude> element that appears before any + <Include> elements will have no effect, for example, as no + desktop entries have been included yet.) + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Filename></term> + <listitem> + <para> + The <Filename> element is the most basic matching rule. + It matches a desktop entry if the desktop entry has the given + desktop-file id. See <xref linkend="term-desktop-file-id"/>. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Category></term> + <listitem> + <para> + The <Category> element is another basic matching + predicate. It matches a desktop entry if the desktop entry has + the given category in its <varname>Categories</varname> field. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><All></term> + <listitem> + <para> + The <All> element is a matching rule that matches + all desktop entries. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><And></term> + <listitem> + <para> + The <And> element contains a list of matching rules. + If each of the matching rules inside the <And> + element match a desktop entry, then the entire + <And> rule matches the desktop entry. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Or></term> + <listitem> + <para> + The <Or> element contains a list of matching rules. + If any of the matching rules inside the <Or> + element match a desktop entry, then the entire + <Or> rule matches the desktop entry. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Not></term> + <listitem> + <para> + The <Not> element contains a list of matching rules. If + any of the matching rules inside the <Not> element matches + a desktop entry, then the entire <Not> rule does + <emphasis>not</emphasis> match the desktop entry. That is, + matching rules below <Not> have a logical OR relationship. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><MergeFile [type="path"|"parent"] ></term> + <listitem> + <para> + Any number of <MergeFile> elements may be listed below a + <Menu> element, giving the name of another menu file to + be merged into this one. <xref linkend="merge-algorithm"/> + specifies how merging is done. The root <Menu> of the + merged file will be merged into the immediate parent of the + <MergeFile> element. The <Name> element of the + root <Menu> of the merged file are ignored. + </para> + <para> + If the type attribute is missing or set to "path" then the + contents of the <MergeFile> element indicates the + file to be merged. If this is not an absolute path then the + file to be merged should be located relative to the location + of the menu file that contains this <MergeFile> element. + </para> + <para> + Duplicate <MergeFile> elements (that specify the same + file) are handled as with duplicate <AppDir> + elements (the last duplicate is used). + </para> + <para> + If the type attribute is set to "parent" and the file that + contains this <MergeFile> element is located under one + of the paths specified by <varname>$XDG_CONFIG_DIRS</varname>, + the contents of the element should be ignored and the remaining + paths specified by <varname>$XDG_CONFIG_DIRS</varname> are + searched for a file with the same relative filename. The first + file encountered should be merged. There should be no + merging at all if no matching file is found. + </para> + <para> + Compatibility note: The filename specified inside the <MergeFile> + element should be ignored if the type attribute is set to "parent", + it should however be expected that implementations based on + previous versions of this specification will ignore the + type attribute and that such implementations will use the + filename inside the <MergeFile> element instead. + </para> + <para> + Example 1: If <varname>$XDG_CONFIG_HOME</varname> is "~/.config/" and + <varname>$XDG_CONFIG_DIRS</varname> is "/opt/gnome/:/etc/xdg/" + and the file ~/.config/menus/applications.menu contains + <MergeFile type="parent">/opt/kde3/etc/xdg/menus/applications.menu</MergeFile> + then the file /opt/gnome/menus/applications.menu + should be merged if it exists. If that file does not exists + then the file /etc/xdg/menus/applications.menu + should be merged instead. + </para> + <para> + Example 2: If <varname>$XDG_CONFIG_HOME</varname> is "~/.config/" and + <varname>$XDG_CONFIG_DIRS</varname> is "/opt/gnome/:/etc/xdg/" + and the file /opt/gnome/menus/applications.menu contains + <MergeFile type="parent">/opt/kde3/etc/xdg/menus/applications.menu</MergeFile> + then the file /etc/xdg/menus/applications.menu should be merged + if it exists. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><MergeDir></term> + <listitem> + <para> + Any number of <MergeDir> elements may be listed below a + <Menu> element. A <MergeDir> contains the name of a + directory. Each file in the given directory which ends in the + ".menu" extension should be merged in the same way that a + <MergeFile> would be. If the filename given as a + <MergeDir> is not an absolute path, it should be located + relative to the location of the menu file being parsed. + The files inside the merged directory are not merged in any + specified order. + </para> + <para> + Duplicate <MergeDir> elements (that specify the same + directory) are handled as with duplicate <AppDir> + elements (the last duplicate is used). + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><DefaultMergeDirs></term> + <listitem> + <para> + This element may only appear below <Menu>. The element has + no content. The element should be treated as if it were a list + of <MergeDir> elements containing the default merge + directory locations. When expanding <DefaultMergeDirs> to a + list of <MergeDir>, the default locations that are earlier + in the search path go later in the <Menu> so that they + have priority. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><LegacyDir></term> + <listitem> + <para> + This element may only appear below <Menu>. The text + content of this element is a directory name. Each directory + listed in a <LegacyDir> element will be an old-style + legacy hierarchy of desktop entries, see <xref + linkend="legacy-hierarchies"/> for how to load such a + hierarchy. Implementations must not load legacy hierarchies that + are not explicitly specified in the menu file (because for + example the menu file may not be the main menu). If the + filename given as a <LegacyDir> is not an absolute path, + it should be located relative to the location of the menu file + being parsed. + </para> + <para> + Duplicate <LegacyDir> elements (that specify the same + directory) are handled as with duplicate <AppDir> + elements (the last duplicate is used). + </para> + <para> + The <LegacyDir> element may have one attribute, + <literal>prefix</literal>. Normally, given a <LegacyDir> + <filename>/foo/bar</filename> and desktop entry + <filename>/foo/bar/baz/Hello.desktop</filename> the desktop + entry would get a desktop-file id of <filename>Hello.desktop</filename>. + Given a prefix of <literal>boo-</literal>, it would instead be + assigned the desktop-file id <filename>boo-Hello.desktop</filename>. + The prefix should not contain path separator ('/') characters. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><KDELegacyDirs></term> + <listitem> + <para> + This element may only appear below <Menu>. The element has + no content. The element should be treated as if it were a list + of <LegacyDir> elements containing the traditional desktop + file locations supported by KDE with a hard coded prefix of "kde-". + When expanding <KDELegacyDirs> to a list of <LegacyDir>, the + locations that are earlier in the search path go later in the + <Menu> so that they have priority. + The search path can be obtained by running <filename>kde-config --path apps</filename> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Move></term> + <listitem> + <para> + This element may only appear below <Menu>. The + <Move> element contains pairs of <Old>/<New> + elements indicating how to rename a descendant of the current + <Menu>. If the destination path already exists, the moved + menu is merged with the destination menu (see <xref + linkend="merge-algorithm"/> for details). + </para> + <para> + <Move> is used primarily to fix up legacy directories. + For example, say you are merging a <LegacyDir> with folder + names that don't match the current hierarchy; the legacy folder + names can be moved to the new names, where they will be merged + with the new folders. + </para> + <para> + <Move> is also useful for implementing menu + editing, see <xref linkend="menu-editing"/>. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Old></term> + <listitem> + <para> + This element may only appear below <Move>, and + must be followed by a <New> element. The content of both + <Old> and <New> should be a menu path + (slash-separated concatenation of <Name> fields, see + <xref linkend="term-menu-path"/>). + Paths are interpreted relative to the menu containing + the <Move> element. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><New></term> + <listitem> + <para> + This element may only appear below <Move>, and must + be preceded by an <Old> element. The <New> element + specifies the new path for the preceding <Old> element. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Layout></term> + <listitem> + <para> + The <Layout> element is an optional part of this specification. + Implementations that do not support the <Layout> element should + preserve any <Layout> elements and their contents as far as + possible. + Each <Menu> may optionally contain a <Layout> element. + If multiple elements appear then only the last such element is relevant. + The purpose of this element is to offer suggestions for the presentation + of the menu. + If a menu does not contain a <Layout> element or if it contains + an empty <Layout> element then the default layout should be used. + The <Layout> element may contain <Filename>, <Menuname>, + <Separator> and <Merge> elements. The <Layout> element + defines a suggested layout for the menu starting from top to bottom. + References to desktop entries that are not contained in this + menu as defined by the <Include> and <Exclude> elements should + be ignored. References to sub-menus that are not directly contained in this + menu as defined by the <Menu> elements should be ignored. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><DefaultLayout [show_empty="false"] [inline="false"] [inline_limit="4"] [inline_header="true"] [inline_alias="false"]></term> + <listitem> + <para> + The <DefaultLayout> element is an optional part of this specification. + Implementations that do not support the <DefaultLayout> element should + preserve any <DefaultLayout> elements and their contents as far as + possible. + Each <Menu> may optionally contain a <DefaultLayout> element + which defines the default-layout for the current menu and all its sub-menus. + If a menu has a <DefaultLayout> element then this will override + any default-layout specified by a parent menu. + The default-layout defines the suggested layout if a <Menu> element + does either not have <Layout> element or if it has an empty <Layout> element. + For explanations of the various attributes see the <Menuname> element. + If no default-layout has been specified then the layout as specified by the following + elements should be assumed: + <DefaultLayout show_empty="false" inline="false" inline_limit="4" inline_header="true" inline_alias="false"><Merge type="menus"/><Merge type="files"/></DefaultLayout> + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Menuname [show_empty="..."] [inline="..."] [inline_limit="..."] [inline_header="..."] [inline_alias="..."]></term> + <listitem> + <para> + This element may only appear as a child of a <Layout> or <DefaultLayout> + menu. Its contents references an immediate sub-menu of the current menu as defined + with the <Menu> element, as such it should never contain a slash. + If no such sub-menu exists the element should be ignored. + This element may have various attributes, the default values are taken from the DefaultLayout key. + The show_empty attribute defines whether a menu that contains no desktop + entries and no sub-menus should be shown at all. The show_empty attribute + can be "true" or "false". + It may have an inline attribute that can be either "true" or "false". + If the inline attribute is "true" the menu that is referenced may be copied into the + current menu at the current point instead of being inserted as sub-menu of the current menu. + The optional inline_limit attribute defines the maximum number of entries that can be inlined. + If the sub-menu has more entries than inline_limit, the sub-menu will not be inlined. + If the inline_limit is 0 (zero) there is no limit. + The optional inline_header attribute defines whether an inlined menu should be preceded with + a header entry listing the caption of the sub-menu. + The inline_header attribute can be either "true" or "false". + The optional inline_alias attribute defines whether a single inlined entry should adopt the + caption of the inlined menu. In such case no additional header entry will be added regardless + of the value of the inline_header attribute. + The inline_alias attribute can be either "true" or "false". + Example: if a menu has a sub-menu titled "WordProcessor" with a single entry "OpenOffice 4.2", + and both inline="true" and inline_alias="true" are specified then this would result in the + "OpenOffice 4.2" entry being inlined in the current menu but the "OpenOffice 4.2" caption + of the entry would be replaced with "WordProcessor". + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Separator></term> + <listitem> + <para> + This element may only appear as a child of a <Layout> or <DefaultLayout> + menu. It indicates a suggestion to draw a visual separator at this point in the menu. + <Separator> elements at the start of a menu, at the end of a menu or that directly + follow other <Separator> elements may be ignored. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term><Merge type="menus"|"files"|"all"/></term> + <listitem> + <para> + This element may only appear as a child of a <Layout> or <DefaultLayout> + menu. It indicates the point where desktop entries and sub-menus that are not explicitly + mentioned within the <Layout> or <DefaultLayout> element are to be inserted. + It has a type attribute that indicates which elements should be inserted: + type="menus" + means that all sub-menus that are not explicitly mentioned should be inserted in + alphabetical order of their visual caption at this point. + type="files" + means that all desktop entries + contained in this menu that are not explicitly mentioned should be inserted in + alphabetical order of their visual caption at this point. + type="all" means that a mix of all sub-menus + and all desktop entries that are not explicitly mentioned should be inserted in + alphabetical order of their visual caption at this point. + Each <Layout> or <DefaultLayout> element shall have exactly one <Merge type="all"> + element or it shall have exactly one <Merge type="files"> and exactly one + <Merge type="menus"> element. An exception is made for a completely empty <Layout> + element which may be used to indicate that the default-layout should be used instead. + </para> + </listitem> + </varlistentry> + </variablelist> + </para> + </sect2> + </sect1> + + <sect1 id="merge-algorithm"> + <title>Merging</title> + <para> + Sometimes two menu layouts need to be merged. This is done when folding in + legacy menu hierarchies (see <xref linkend="legacy-hierarchies"/>) and also + for files specified in <MergeFile> elements. A common case is that + per-user menu files might merge the system menu file. Merging is also used + to avoid cut-and-paste, for example to include a common submenu in + multiple menu files. + </para> + <para> + Merging involves a base <Menu> and a merged <Menu>. The base + is the "target" menu and the merged <Menu> is being added to it. The + result of the merge is termed the "combined menu." + </para> + <para> + As a preparatory step, the goal is to resolve all files into + XML elements. To do so, traverse the entire menu tree. For each + <MergeFile>, <MergeDir>, or <LegacyDir> element, replace + the <MergeFile>, <MergeDir>, or <LegacyDir> element with + the child elements of the root <Menu> of the file(s) being + merged. As a special exception, remove the <Name> element from the + root element of each file being merged. To generate a + <Menu> based on a <LegacyDir>, see + <xref linkend="legacy-hierarchies"/>. + </para> + <para> + Continue processing until no <MergeFile>, <MergeDir>, or + <LegacyDir> elements remain, taking care to avoid infinite loops + caused by files that reference one another. + </para> + <para> + Once all files have been loaded into a single tree, scan the tree + recursively performing these steps to remove duplicates: + <orderedlist> + <listitem> + <para> + Consolidate child menus. Each group of child <Menu>s with the same + name must be consolidated into a single child menu with that name. + Concatenate the child elements of all menus with the same name, in + the order that they appear, and insert those elements as the + children of the <emphasis>last</emphasis> menu with that name. + Delete all the newly empty <Menu> elements, keeping the + last one. + </para> + </listitem> + <listitem> + <para> + Expand <DefaultAppDirs> and <DefaultDirectoryDirs> + elements to <AppDir> and <DirectoryDir> elements. + Consolidate duplicate <AppDir>, <DirectoryDir>, + and <Directory> elements by keeping the last one. + For <Directory> elements that refer to distinct directory + entries, all of them should be kept - if the last one points + to a nonexistent file, the one before that can be used instead, + and so forth. + </para> + </listitem> + <listitem> + <para> + Recurse into each child <Menu>, performing this list of + steps for each child in order. + </para> + </listitem> + </orderedlist> + </para> + <para> + After recursing once to remove duplicates, recurse a second time to + resolve <Move> elements for each menu starting with any child + menu before handling the more top level menus. + So the deepest menus have their <Move> operations performed first. + Within each <Menu>, execute <Move> operations in the order + that they appear. If the destination path does not exist, simply relocate + the origin <Menu> element, and change its <Name> field to + match the destination path. If the origin path does not exist, do + nothing. If both paths exist, take the origin <Menu> element, + delete its <Name> element, and prepend its remaining child elements + to the destination <Menu> element. + </para> + <para> + If any <Move> operations affect a menu, then re-run the + steps to resolve duplicates in case any duplicates have been + created. + </para> + <para> + Finally, for each <Menu> containing a <Deleted> element which + is not followed by a <NotDeleted> element, remove that menu and all + its child menus. + </para> + + <para> + Merged menu elements are kept in order because <Include> and + <Exclude> elements later in the file override <Include> and + <Exclude> elements earlier in the file. This means that if the user's + menu file merges the system menu file, the user can always override what + the system menu specifies by placing elements after the <MergeFile> + that incorporates the system file. + </para> + <para> + To prevent that a desktop entry from one party inadvertently cancels out + the desktop entry from another party because both happen to get the same + desktop-file id it is recommended that providers of desktop-files ensure that + all desktop-file ids start with a vendor prefix. A vendor prefix + consists of [a-zA-Z] and is terminated with a dash ("-"). Open Source + projects and commercial parties are encouraged to use a word or phrase, + preferably their name, as prefix for which they hold a trademark. Open Source + applications can also ask to make use of the vendor prefix of another open + source project (such as GNOME or KDE) they consider themselves affiliated + with, at the discretion of these projects. + </para> + <para> + For example, to ensure that GNOME applications start with a vendor prefix of "gnome-", + it could either add "gnome-" to all the desktop files it installs in + <filename><replaceable>datadir</replaceable>/applications/</filename> or it could + install desktop files in a <filename><replaceable>datadir</replaceable>/applications/gnome</filename> + subdirectory. When including legacy menu hierarchies the <literal>prefix</literal> argument + of the <LegacyDir> element can be used to specify a prefix. + </para> + </sect1> + + <sect1 id="query-algorithm"> + <title>Generating the menus</title> + <para> + After merging the menus, the result should be a single menu layout + description. For each <Menu>, we have a list of directories where + desktop entries can be found, a list of directories where directory + entries can be found, and a series of <Include> and <Exclude> + directives. + </para> + <para> + For each <Menu> element, build a pool of desktop entries by + collecting entries found in each <AppDir> for the menu element. If + two entries have the same desktop-file id, the entry for the earlier (closer + to the top of the file) <AppDir> must be discarded. Next, add to the + pool the entries for any <AppDir>s specified by ancestor + <Menu> elements. If a parent menu has a duplicate entry (same + desktop-file id), the entry for the child menu has priority. + </para> + <para> + Next, walk through all <Include> and <Exclude> statements. + For each <Include>, match the rules against the pool of all desktop + entries. For each desktop entry that matches one of the rules, + add it to the menu to be displayed and mark it as having been allocated. + For each <Exclude>, match the rules against the currently-included + desktop entries. For each desktop entry that matches, remove it again + from the menu. Note that an entry that is included in a menu but excluded + again by a later <Exclude> is still considered allocated (for the + purposes of <OnlyUnallocated>) even though that entry no longer + appears in the menu. + </para> + <para> + Two passes are necessary, once for regular menus where any entry may + be matched, and once for <OnlyUnallocated> menus where only entries + which have not been marked as allocated may be matched. + </para> + <para> + The result is a tree of desktop entries, of course. + </para> + </sect1> + + <sect1 id="legacy-hierarchies"> + <title>Legacy Menu Hierarchies</title> + <para> + Traditionally, menus were defined as a filesystem hierarchy, with each + filesystem directory corresponding to a submenu. Implementations of this + specification must be able to load these old-style hierarchies + as specified in this section. + </para> + <para> + The general approach is: the legacy hierarchy is converted into a + <Menu>, and then this menu layout is merged with the menu that + specified <LegacyDir>. + </para> + <para> + Desktop entries in the legacy hierarchy should be added to the pool of + desktop entries as if the <LegacyDir> were an + <AppDir>. Directory entries in the legacy hierarchy should be added + to the pool of directory entries as if the <LegacyDir> were a + <DirectoryDir>. This can be trivially implemented by adding + appropriate <AppDir> and <DirectoryDir> statements to the root + legacy <Menu>. There is one slight complexity, namely the + "prefix" attribute of <LegacyDir>. + </para> + <para> + The menu layout corresponds conceptually to the following, though actually + generating the XML is not necessary: + <itemizedlist> + <listitem> + <para> + For each directory in the legacy hierarchy, a + <Menu> is created with the same <Name> + as the directory on disk. + </para> + </listitem> + <listitem> + <para> + This menu then contains an <Include> element that includes + each desktop entry in the directory. That is, it should have a + + <Filename><replaceable>Foo/Bar/foo.desktop</replaceable></Filename> + for each desktop entry in the directory. + </para> + <para> + As a special exception, if a desktop entry in a directory contains + a <varname>Categories</varname> field, that desktop entry should + <emphasis>not</emphasis> be included in the legacy menu. + That is, no <Include> element should be generated for + the entry. This allows a desktop entry to be installed + in a legacy location but still work optimally with the + menu system specified in this document. + </para> + </listitem> + <listitem> + <para> + If the legacy directory contains a ".directory" file, then + a <Directory> element should be generated that points to said + ".directory" file. + </para> + </listitem> + <listitem> + <para> + Legacy desktop entries should not be assigned any + <varname>Categories</varname> fields if they didn't have them + already, except that all legacy entries should have the + "Legacy" category added to allow menu files to treat them + specially. (If the same directory is given as both + a <LegacyDir> and an <AppDir>, its desktop + entries should be labeled "Legacy" only if the <LegacyDir> + appears later in the file than the <AppDir>.) + </para> + </listitem> + </itemizedlist> + </para> + <para> + For example, say we have the following legacy directory hierarchy: + <informalexample> + <programlisting> + /usr/share/applnk + /usr/share/applnk/.directory + /usr/share/applnk/bar.desktop + /usr/share/applnk/System + /usr/share/applnk/System/.directory + /usr/share/applnk/System/foo.desktop + </programlisting> + </informalexample> + Conceptually that is converted to the following <Menu>: + <informalexample> + <programlisting> + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu &dtd-version;//EN" + "http://www.freedesktop.org/standards/menu-spec/menu-&dtd-version;.dtd"> + + <Menu> + <Name>Applications</Name> + <AppDir>/usr/share/applnk</AppDir> + <DirectoryDir>/usr/share/applnk</DirectoryDir> + <Directory>.directory</Directory> + <Include> + <Filename>bar.desktop</Filename> + </Include> + <Menu> + <Name>System</Name> + <AppDir>/usr/share/applnk/System</AppDir> + <DirectoryDir>/usr/share/applnk/System</DirectoryDir> + <Directory>.directory</Directory> + <Include> + <Filename>foo.desktop</Filename> + </Include> + </Menu> + </Menu> + </programlisting> + </informalexample> + This <Menu> is then merged as if it were in a file + and loaded with <MergeFile>. + </para> + </sect1> + + <sect1 id="example"> + <title>Example Menu File</title> + <para> + <informalexample> + <programlisting> + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu &dtd-version;//EN" + "http://www.freedesktop.org/standards/menu-spec/menu-&dtd-version;.dtd"> + + <Menu> + <Name>Applications</Name> + <Directory>Applications.directory</Directory> + + <-- Search the default locations --> + <DefaultAppDirs/> + <DefaultDirectoryDirs/> + + <-- Merge third-party submenus --> + <MergeDir>applications-merged</MergeDir> + + <-- Merge legacy hierarchy --> + <LegacyDir>/usr/share/applnk</LegacyDir> + + <-- Define default layout --> + <DefaultLayout> + <Merge type="menus"/> + <Merge type="files"/> + <Separator/> + <Menuname>More</Menuname> + </DefaultLayout> + + <-- some random moves, maybe to clean up legacy dirs, + maybe from menu editing --> + <Move> + <Old>Foo</Old> + <New>Bar</New> + <Old>Foo2</Old> + <New>Bar2</New> + </Move> + + <-- A preferences submenu, kept in a separate file + so it can also be used standalone --> + <Menu> + <Name>Preferences</Name> + <Directory>Preferences.directory</Directory> + <MergeFile>preferences.menu</MergeFile> + </Menu> + + <-- An Office submenu, specified inline --> + <Menu> + <Name>Office</Name> + <Directory>Office.directory</Directory> + <Include> + <Category>Office</Category> + </Include> + <Exclude> + <Filename>foo.desktop</Filename> + </Exclude> + </Menu> + + </Menu> + </programlisting> + </informalexample> + </para> + </sect1> + + <appendix id="category-registry"> + <title>Registered Categories</title> + <para> + This section contains a number of well known categories and + suggestions on how to use them. The list of Main Categories consist + of those categories that every conforming desktop environment MUST + support. By including one of these categories in an application's + desktop entry file the application will be ensured that it will + show up in a section of the application menu dedicated to this + category. The list of Additional Categories provides categories + that can be used to provide more fine grained information about + the application. Additional Categories should always be used in + combination with one of the Main Categories. + </para> + <para> + The table below lists all Main Categories. + Note that category names are case-sensitive. + <informaltable> + <tgroup cols="3"> + <thead> + <row> + <entry>Main Category</entry> + <entry>Description</entry> + <entry>Notes</entry> + </row> + </thead> + <tbody> + <row> + <entry>AudioVideo</entry> + <entry>Application for presenting, creating, or processing multimedia (audio/video)</entry> + </row><row> + <entry>Audio</entry> + <entry>An audio application</entry> + <entry>Desktop entry must include AudioVideo as well</entry> + </row><row> + <entry>Video</entry> + <entry>A video application</entry> + <entry>Desktop entry must include AudioVideo as well</entry> + </row><row> + <entry>Development</entry> + <entry>An application for development</entry> + </row><row> + <entry>Education</entry> + <entry>Educational software</entry> + </row><row> + <entry>Game</entry> + <entry>A game</entry> + </row><row> + <entry>Graphics</entry> + <entry>Application for viewing, creating, or processing graphics</entry> + </row><row> + <entry>Network</entry> + <entry>Network application such as a web browser</entry> + </row><row> + <entry>Office</entry> + <entry>An office type application</entry> + </row><row> + <entry>Settings</entry> + <entry>Settings applications</entry> + <entry>Entries may appear in a separate menu or as part of a + "Control Center"</entry> + </row><row> + <entry>System</entry> + <entry>System application, "System Tools" such as say a log viewer or network monitor</entry> + </row><row> + <entry>Utility</entry> + <entry>Small utility application, "Accessories"</entry> + </row> + </tbody> + </tgroup> + </informaltable> + </para> + <para> + The table below describes Additional Categories. The Related + Categories column lists one or more categories that are suggested + to be used in conjunction with the Additional Category. Note that at + least one Main Category must be included in the desktop entry's list + of categories. If multiple Main Categories are included in a single + desktop entry file, the entry may appear more than once in the menu. + If the Related Categories column is blank, the + Additional Category can be used with any Main Category. + <informaltable> + <tgroup cols="3"> + <thead> + <row> + <entry>Additional Category</entry> + <entry>Description</entry> + <entry>Related Categories</entry> + </row> + </thead> + <tbody> + <row> + <entry>Building</entry> + <entry>A tool to build applications</entry> + <entry>Development</entry> + + </row><row> + <entry>Debugger</entry> + <entry>A tool to debug applications</entry> + <entry>Development</entry> + + </row><row> + <entry>IDE</entry> + <entry>IDE application</entry> + <entry>Development</entry> + + </row><row> + <entry>GUIDesigner</entry> + <entry>A GUI designer application</entry> + <entry>Development</entry> + + </row><row> + <entry>Profiling</entry> + <entry>A profiling tool</entry> + <entry>Development</entry> + + </row><row> + <entry>RevisionControl</entry> + <entry>Applications like cvs or subversion</entry> + <entry>Development</entry> + + </row><row> + <entry>Translation</entry> + <entry>A translation tool</entry> + <entry>Development</entry> + + </row><row> + <entry>Calendar</entry> + <entry>Calendar application</entry> + <entry>Office</entry> + + </row><row> + <entry>ContactManagement</entry> + <entry>E.g. an address book</entry> + <entry>Office</entry> + + </row><row> + <entry>Database</entry> + <entry>Application to manage a database</entry> + <entry>Office or Development or AudioVideo</entry> + + </row><row> + <entry>Dictionary</entry> + <entry>A dictionary</entry> + <entry>Office;TextTools</entry> + + </row><row> + <entry>Chart</entry> + <entry>Chart application</entry> + <entry>Office</entry> + + </row><row> + <entry>Email</entry> + <entry>Email application</entry> + <entry>Office;Network</entry> + + </row><row> + <entry>Finance</entry> + <entry>Application to manage your finance</entry> + <entry>Office</entry> + + </row><row> + <entry>FlowChart</entry> + <entry>A flowchart application</entry> + <entry>Office</entry> + + </row><row> + <entry>PDA</entry> + <entry>Tool to manage your PDA</entry> + <entry>Office</entry> + + </row><row> + <entry>ProjectManagement</entry> + <entry>Project management application</entry> + <entry>Office;Development</entry> + + </row><row> + <entry>Presentation</entry> + <entry>Presentation software</entry> + <entry>Office</entry> + + </row><row> + <entry>Spreadsheet</entry> + <entry>A spreadsheet</entry> + <entry>Office</entry> + + </row><row> + <entry>WordProcessor</entry> + <entry>A word processor</entry> + <entry>Office</entry> + + </row><row> + <entry>2DGraphics</entry> + <entry>2D based graphical application</entry> + <entry>Graphics</entry> + + </row><row> + <entry>VectorGraphics</entry> + <entry>Application for viewing, creating, or processing vector graphics</entry> + <entry>Graphics;2DGraphics</entry> + + </row><row> + <entry>RasterGraphics</entry> + <entry>Application for viewing, creating, or processing raster (bitmap) graphics</entry> + <entry>Graphics;2DGraphics</entry> + + </row><row> + <entry>3DGraphics</entry> + <entry>Application for viewing, creating, or processing 3-D graphics</entry> + <entry>Graphics</entry> + + </row><row> + <entry>Scanning</entry> + <entry>Tool to scan a file/text</entry> + <entry>Graphics</entry> + + </row><row> + <entry>OCR</entry> + <entry>Optical character recognition application</entry> + <entry>Graphics;Scanning</entry> + + </row><row> + <entry>Photography</entry> + <entry>Camera tools, etc.</entry> + <entry>Graphics or Office</entry> + + </row><row> + <entry>Publishing</entry> + <entry>Desktop Publishing applications and Color Management tools</entry> + <entry>Graphics or Office</entry> + + </row><row> + <entry>Viewer</entry> + <entry>Tool to view e.g. a graphic or pdf file</entry> + <entry>Graphics or Office</entry> + + </row><row> + <entry>TextTools</entry> + <entry>A text tool utiliy</entry> + <entry>Utility</entry> + + </row><row> + <entry>DesktopSettings</entry> + <entry>Configuration tool for the GUI</entry> + <entry>Settings</entry> + + </row><row> + <entry>HardwareSettings</entry> + <entry>A tool to manage hardware components, like sound cards, video cards or printers</entry> + <entry>Settings</entry> + + </row><row> + <entry>Printing</entry> + <entry>A tool to manage printers</entry> + <entry>HardwareSettings;Settings</entry> + + </row><row> + <entry>PackageManager</entry> + <entry>A package manager application</entry> + <entry>Settings</entry> + + </row><row> + <entry>Dialup</entry> + <entry>A dial-up program</entry> + <entry>Network</entry> + + </row><row> + <entry>InstantMessaging</entry> + <entry>An instant messaging client</entry> + <entry>Network</entry> + + </row><row> + <entry>Chat</entry> + <entry>A chat client</entry> + <entry>Network</entry> + + </row><row> + <entry>IRCClient</entry> + <entry>An IRC client</entry> + <entry>Network</entry> + + </row><row> + <entry>FileTransfer</entry> + <entry>Tools like FTP or P2P programs</entry> + <entry>Network</entry> + + </row><row> + <entry>HamRadio</entry> + <entry>HAM radio software</entry> + <entry>Network or Audio</entry> + + </row><row> + <entry>News</entry> + <entry>A news reader or a news ticker</entry> + <entry>Network</entry> + + </row><row> + <entry>P2P</entry> + <entry>A P2P program</entry> + <entry>Network</entry> + + </row><row> + <entry>RemoteAccess</entry> + <entry>A tool to remotely manage your PC</entry> + <entry>Network</entry> + + </row><row> + <entry>Telephony</entry> + <entry>Telephony via PC</entry> + <entry>Network</entry> + + </row><row> + <entry>TelephonyTools</entry> + <entry>Telephony tools, to dial a number, manage PBX, ...</entry> + <entry>Utility</entry> + + </row><row> + <entry>VideoConference</entry> + <entry>Video Conference software</entry> + <entry>Network</entry> + + </row><row> + <entry>WebBrowser</entry> + <entry>A web browser</entry> + <entry>Network</entry> + + </row><row> + <entry>WebDevelopment</entry> + <entry>A tool for web developers</entry> + <entry>Network or Development</entry> + + </row><row> + <entry>Midi</entry> + <entry>An app related to MIDI</entry> + <entry>AudioVideo;Audio</entry> + + </row><row> + <entry>Mixer</entry> + <entry>Just a mixer</entry> + <entry>AudioVideo;Audio</entry> + + </row><row> + <entry>Sequencer</entry> + <entry>A sequencer</entry> + <entry>AudioVideo;Audio</entry> + + </row><row> + <entry>Tuner</entry> + <entry>A tuner</entry> + <entry>AudioVideo;Audio</entry> + + </row><row> + <entry>TV</entry> + <entry>A TV application</entry> + <entry>AudioVideo;Video</entry> + + </row><row> + <entry>AudioVideoEditing</entry> + <entry>Application to edit audio/video files</entry> + <entry>Audio or Video or AudioVideo</entry> + + </row><row> + <entry>Player</entry> + <entry>Application to play audio/video files</entry> + <entry>Audio or Video or AudioVideo</entry> + + </row><row> + <entry>Recorder</entry> + <entry>Application to record audio/video files</entry> + <entry>Audio or Video or AudioVideo</entry> + + </row><row> + <entry>DiscBurning</entry> + <entry>Application to burn a disc</entry> + <entry>AudioVideo</entry> + + </row><row> + <entry>ActionGame</entry> + <entry>An action game</entry> + <entry>Game</entry> + + </row><row> + <entry>AdventureGame</entry> + <entry>Adventure style game</entry> + <entry>Game</entry> + + </row><row> + <entry>ArcadeGame</entry> + <entry>Arcade style game</entry> + <entry>Game</entry> + + </row><row> + <entry>BoardGame</entry> + <entry>A board game</entry> + <entry>Game</entry> + + </row><row> + <entry>BlocksGame</entry> + <entry>Falling blocks game</entry> + <entry>Game</entry> + + </row><row> + <entry>CardGame</entry> + <entry>A card game</entry> + <entry>Game</entry> + + </row><row> + <entry>KidsGame</entry> + <entry>A game for kids</entry> + <entry>Game</entry> + + </row><row> + <entry>LogicGame</entry> + <entry>Logic games like puzzles, etc</entry> + <entry>Game</entry> + + </row><row> + <entry>RolePlaying</entry> + <entry>A role playing game</entry> + <entry>Game</entry> + + </row><row> + <entry>Simulation</entry> + <entry>A simulation game</entry> + <entry>Game</entry> + + </row><row> + <entry>SportsGame</entry> + <entry>A sports game</entry> + <entry>Game</entry> + + </row><row> + <entry>StrategyGame</entry> + <entry>A strategy game</entry> + <entry>Game</entry> + + </row><row> + <entry>Art</entry> + <entry>Software to teach arts</entry> + <entry>Education</entry> + + </row><row> + <entry>Construction</entry> + <entry></entry> + <entry>Education</entry> + + </row><row> + <entry>Music</entry> + <entry>Musical software</entry> + <entry>AudioVideo;Education</entry> + + </row><row> + <entry>Languages</entry> + <entry>Software to learn foreign languages</entry> + <entry>Education</entry> + + </row><row> + <entry>Science</entry> + <entry>Scientific software</entry> + <entry>Education</entry> + + </row><row> + <entry>ArtificialIntelligence</entry> + <entry>Artificial Intelligence software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>Astronomy</entry> + <entry>Astronomy software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>Biology</entry> + <entry>Biology software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>Chemistry</entry> + <entry>Chemistry software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>ComputerScience</entry> + <entry>ComputerSience software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>DataVisualization</entry> + <entry>Data visualization software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>Economy</entry> + <entry>Economy software</entry> + <entry>Education</entry> + + </row><row> + <entry>Electricity</entry> + <entry>Electricity software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>Geography</entry> + <entry>Geography software</entry> + <entry>Education</entry> + + </row><row> + <entry>Geology</entry> + <entry>Geology software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>Geoscience</entry> + <entry>Geoscience software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>History</entry> + <entry>History software</entry> + <entry>Education</entry> + + </row><row> + <entry>ImageProcessing</entry> + <entry>Image Processing software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>Literature</entry> + <entry>Literature software</entry> + <entry>Education</entry> + + </row><row> + <entry>Math</entry> + <entry>Math software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>NumericalAnalysis</entry> + <entry>Numerical analysis software</entry> + <entry>Education;Science;Math</entry> + + </row><row> + <entry>MedicalSoftware</entry> + <entry>Medical software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>Physics</entry> + <entry>Physics software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>Robotics</entry> + <entry>Robotics software</entry> + <entry>Education;Science</entry> + + </row><row> + <entry>Sports</entry> + <entry>Sports software</entry> + <entry>Education</entry> + + </row><row> + <entry>ParallelComputing</entry> + <entry>Parallel computing software</entry> + <entry>Education;Science;ComputerScience</entry> + + </row><row> + <entry>Amusement</entry> + <entry>A simple amusement</entry> + <entry></entry> + + + </row><row> + <entry>Archiving</entry> + <entry>A tool to archive/backup data</entry> + <entry>Utility</entry> + + </row><row> + <entry>Compression</entry> + <entry>A tool to manage compressed data/archives</entry> + <entry>Utility;Archiving</entry> + + </row><row> + <entry>Electronics</entry> + <entry>Electronics software, e.g. a circuit designer</entry> + <entry></entry> + + </row><row> + <entry>Emulator</entry> + <entry>Emulator of another platform, such as a DOS emulator</entry> + <entry>System or Game</entry> + + </row><row> + <entry>Engineering</entry> + <entry>Engineering software, e.g. CAD programs</entry> + <entry></entry> + + </row><row> + <entry>FileTools</entry> + <entry>A file tool utility</entry> + <entry>Utility or System</entry> + + </row><row> + <entry>FileManager</entry> + <entry>A file manager</entry> + <entry>System;FileTools</entry> + + </row><row> + <entry>TerminalEmulator</entry> + <entry>A terminal emulator application</entry> + <entry>System</entry> + + </row><row> + <entry>Filesystem</entry> + <entry>A file system tool</entry> + <entry>System</entry> + + </row><row> + <entry>Monitor</entry> + <entry>Monitor application/applet that monitors some resource or activity</entry> + <entry>System</entry> + + </row><row> + <entry>Security</entry> + <entry>A security tool</entry> + <entry>Settings or System</entry> + + </row><row> + <entry>Accessibility</entry> + <entry>Accessibility</entry> + <entry>Settings or Utility</entry> + + </row><row> + <entry>Calculator</entry> + <entry>A calculator</entry> + <entry>Utility</entry> + + </row><row> + <entry>Clock</entry> + <entry>A clock application/applet</entry> + <entry>Utility</entry> + + </row><row> + <entry>TextEditor</entry> + <entry>A text editor</entry> + <entry>Utility</entry> + + </row><row> + <entry>Documentation</entry> + <entry>Help or documentation</entry> + <entry></entry> + + </row><row> + <entry>Adult</entry> + <entry>Application handles adult or explicit material</entry> + <entry></entry> + + </row><row> + <entry>Core</entry> + <entry>Important application, core to the desktop such as a file manager or a help browser</entry> + <entry></entry> + + </row><row> + <entry>KDE</entry> + <entry>Application based on KDE libraries</entry> + <entry>QT</entry> + + </row><row> + <entry>GNOME</entry> + <entry>Application based on GNOME libraries</entry> + <entry>GTK</entry> + + </row><row> + <entry>GTK</entry> + <entry>Application based on GTK+ libraries</entry> + <entry></entry> + + </row><row> + <entry>Qt</entry> + <entry>Application based on Qt libraries</entry> + <entry></entry> + + </row><row> + <entry>Motif</entry> + <entry>Application based on Motif libraries</entry> + <entry></entry> + + </row><row> + <entry>Java</entry> + <entry>Application based on Java GUI libraries, such as AWT or Swing</entry> + <entry></entry> + + </row><row> + <entry>ConsoleOnly</entry> + <entry>Application that only works inside a terminal (text-based or command line application)</entry> + <entry></entry> + + </row> + </tbody> + </tgroup> + </informaltable> + + </para> + <para> + The table below describes Reserved Categories. + Reserved Categories have a specific desktop specific meaning + that has not been standardized (yet). Desktop entry files that use + a reserved category MUST also include an appropriate OnlyShowIn= entry + to restrict themselves to those environments that properly support the + reserved category as used. + <informaltable> + <tgroup cols="2"> + <thead> + <row> + <entry>Reserved Category</entry> + <entry>Description</entry> + </row> + </thead> + <tbody> + <row> + <entry>Screensaver</entry> + <entry>A screen saver (launching this desktop entry should activate the screen saver)</entry> + </row><row> + <entry>TrayIcon</entry> + <entry>An application that is primarily an icon for the "system tray" or "notification area" (apps that open a normal window and just happen to have a tray icon as well should not list this category)</entry> + </row><row> + <entry>Applet</entry> + <entry>An applet that will run inside a panel or another such application, likely desktop specific</entry> + </row><row> + <entry>Shell</entry> + <entry>A shell (an actual specific shell such as + <filename>bash</filename> or <filename>tcsh</filename>, not a TerminalEmulator)</entry> + </row> + </tbody> + </tgroup> + </informaltable> + + </para> + </appendix> + <appendix id="onlyshowin-registry"> + <title>Registered OnlyShowIn Environments</title> + <para> + Remember, these are case-sensitive. "KDE" not "kde" should be + used. + <informaltable> + <tgroup cols="2"> + <thead> + <row> + <entry>OnlyShowIn Value</entry> + <entry>Environment</entry> + </row> + </thead> + <tbody> + <row> + <entry>GNOME</entry><entry>GNOME Desktop</entry> + </row><row> + <entry>KDE</entry><entry>KDE Desktop</entry> + </row><row> + <entry>LXDE</entry><entry>LXDE Desktop</entry> + </row><row> + <entry>ROX</entry><entry>ROX Desktop</entry> + </row><row> + <entry>Unity</entry><entry>Unity Shell</entry> + </row><row> + <entry>XFCE</entry><entry>XFCE Desktop</entry> + </row><row> + <entry>Old</entry><entry>Legacy menu systems</entry> + </row> + </tbody> + </tgroup> + </informaltable> + </para> + </appendix> + <appendix id="third-party-howto"> + <title>Integrating your application in the menus</title> + <sect1 id="adding-items"> + <title>Adding menu items</title> + <para> + The following steps describe how a third party application can add + menu items to the menu system: + <itemizedlist> + <listitem> + <para> + Install desktop entries to + <replaceable>datadir</replaceable>/applications/ for each menu + item. Please namespace the filename, as in "vendor-foo.desktop", or + use a subdirectory of + <replaceable>datadir</replaceable>/applications/ so you have + "vendor/foo.desktop." Please be sure all desktop entries are valid + (see the <ulink + url="http://www.freedesktop.org/software/desktop-file-utils/"> + desktop-file-utils</ulink> package for a validation utility). + </para> + </listitem> + <listitem> + <para> + Install an XML menu file to <replaceable>sysconfdir</replaceable>/menus/applications-merged/ to add any submenus, if your desktop entries aren't already + included in some common categories. + </para> + </listitem> + <listitem> + <para> + Install any directory entries needed for your submenus to <replaceable>datadir</replaceable>/desktop-directories/, taking care to namespace and validate + the directory entries. + </para> + </listitem> + </itemizedlist> + </para> + </sect1> + <sect1 id="locations"> + <title>Install Locations</title> + <para> + If an application is intended to be installed by root on a system wide + basis then /usr/share is recommended to be used as value for + <replaceable>datadir</replaceable> and /etc/xdg is recommended to be + used as value for <replaceable>sysconfdir</replaceable>. + In case the /usr/share hierarchy is not writable it is recommended to + use /usr/local/share as value for <replaceable>datadir</replaceable> + instead. + </para> + <para> + If an application is intended to be installed by an unprivileged user + for exclusive use by that user only then + <varname>$XDG_DATA_HOME</varname> should be used as value + for <replaceable>datadir</replaceable> and + <varname>$XDG_CONFIG_HOME</varname> should be used as value + for <replaceable>sysconfdir</replaceable>. + If <varname>$XDG_DATA_HOME</varname> is not set, the default value of + $HOME/.local/share should be used for it. + If <varname>$XDG_CONFIG_HOME</varname> is not set, the default value of + $HOME/.config should be used for it. + </para> + </sect1> + <sect1 id="menu-add-example"> + <title>Example</title> + <para> + The company ShinyThings Inc. has developed an application named + <emphasis>WebMirror 1.0</emphasis> and would like to add its own + submenu to the system menus consisting of a <emphasis>WebMirror</emphasis> + menu item and a <emphasis>WebMirror Admin Tool</emphasis> + menu item. The company will use "shinythings" as its vendor id. + For the purpose of this example all menu items will be available + in two languages, English and Dutch. + The language code for Dutch is <emphasis>nl</emphasis>. + </para> + <para> + First the company needs to create two .desktop files that describe + the two menu items: + <informalexample> + <programlisting> + <replaceable>datadir</replaceable>/applications/shinythings-webmirror.desktop: + + [Desktop Entry] + Encoding=UTF-8 + Type=Application + + Exec=webmirror + Icon=webmirror + + Name=WebMirror + Name[nl]=WebSpiegel + </programlisting> + </informalexample> + and + <informalexample> + <programlisting> + <replaceable>datadir</replaceable>/applications/shinythings-webmirror-admin.desktop: + + [Desktop Entry] + Encoding=UTF-8 + Type=Application + + Exec=webmirror-admintool + Icon=webmirror-admintool + + Name=WebMirror Admin Tool + Name[nl]=WebSpiegel Administratie Tool + </programlisting> + </informalexample> + A .directory file needs to be installed to provide a title and icon + for the sub-menu itself: + <informalexample> + <programlisting> + <replaceable>datadir</replaceable>/desktop-directories/shinythings-webmirror.directory: + + [Desktop Entry] + Encoding=UTF-8 + + Icon=webmirror + + Name=WebMirror + Name[nl]=WebSpiegel + </programlisting> + </informalexample> + And finally, a .menu file needs to be provided that links it all + togther: + <informalexample> + <programlisting> + <replaceable>sysconfdir</replaceable>/menus/application-merged/shinythings-webmirror.menu: + + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu &dtd-version;//EN" + "http://www.freedesktop.org/standards/menu-spec/menu-&dtd-version;.dtd"> + <Menu> + <Name>Applications</Name> + <Menu> + <Name>WebMirror</Name> + <Directory>shinythings-webmirror.directory</Directory> + <Include> + <Filename>shinythings-webmirror.desktop</Filename> + <Filename>shinythings-webmirror-admin.desktop</Filename> + </Include> + </Menu> + </programlisting> + </informalexample> + + </para> + </sect1> + <sect1 id="compatibility"> + <title>Backward Compatibility</title> + <para> + For a limited time, installing a directory hierarchy to + the old GNOME/KDE specific locations such as /usr/share/applnk and + /usr/share/gnome/apps will continue to work as way to add your + application to the menu system as well. There are two ways to support + both the old and new menu systems at the same time: + <itemizedlist> + <listitem> + <para> + If you add a <varname>Categories</varname> line to the desktop + entries in the legacy hierarchy, implementations of this + specification will ignore their location in the legacy hierarchy, + and arrange them according to <varname>Categories</varname> instead. + This allows you to install a single desktop file that works in all + cases, though on the down side it's in a legacy location. + </para> + </listitem> + <listitem> + <para> + If you add the line <literal>OnlyShowIn=Old;</literal> to a desktop + entry, then old legacy implementations that ignore + <varname>OnlyShowIn</varname> will still show the desktop entry, but + implementations of this specification will not. Thus you can + add an "<literal>OnlyShowIn=Old;</literal>" entry to the legacy + hierarchy, and a new-style desktop entry to + <replaceable>datadir</replaceable>/applications/, and still get + only one entry in the menus. + </para> + </listitem> + </itemizedlist> + </para> + </sect1> + </appendix> + <appendix id="implementation-notes"> + <title>Implementation notes</title> + <sect1 id="menu-editing"> + <title>Menu editing</title> + <para> + To implement menu editing, the intent is that a per-user file is + created. The per-user file should specify a <MergeFile> with the + system wide file, so that system changes are inherited. When the user + deletes a menu item, you add + <literal><Exclude><Filename>foo.desktop</Filename></Exclude></literal>. If + the user adds a menu item, you use + <literal><Include><Filename>foo.desktop</Filename></Include></literal>. + </para> + <para> + If the user moves a folder you can use <Move> elements + to represent the move. <Move> elements used for menu-editing + should always be added to the most top-level menu to ensure that moves + are performed in the order in which they are specified; moves specified + in child menus are always performed before moves specified in a more + top level menu regardless of their location in the menu file. + </para> + <para> + To delete a folder, simply append the <Deleted> element. + </para> + <para> + When adding a new folder or moving an existing folder, menu editing + implementations are advised not to re-use the menu path of a previously + deleted folder. + </para> + <para> + Menu editors probably need to do some kind of consolidation/compression + to avoid an XML tree that grows infinitely over time. + </para> + </sect1> + </appendix> + <glossary><title>Glossary</title> + <para> + This glossary defines some of the terms used in this specification. + </para> + + <glossentry id="term-desktop-entry"><glossterm>Desktop entry</glossterm> + <glossdef> + <para> + A desktop entry is a file with a name ending in the ".desktop" + extension which conforms to the <ulink + url="http://www.freedesktop.org/Standards/desktop-entry-spec">desktop + entry specification</ulink> with <literal>Type=Application</literal>. + It describes a menu item, including a name, an icon, and what to do when the item is selected. + Desktop entries are also known as ".desktop files." + </para> + </glossdef> + </glossentry> + + <glossentry id="term-desktop-file-id"><glossterm>Desktop-File Id</glossterm> + <glossdef> + <para> + The id to identify a desktop entry with. + For example, if <filename>/usr/share/applications</filename> is + specified as an <AppDir>, and <filename>/opt/ude</filename> + as <LegacyDir prefix="foo-"> + then + <filename>/usr/share/applications/foo/bar.desktop</filename>, + <filename>/usr/share/applications/foo-bar.desktop</filename> + and + <filename>/opt/ude/Settings/bar.desktop</filename> all have + the same desktop-file id <literal>foo-bar.desktop</literal> + </para> + </glossdef> + </glossentry> + + <glossentry id="term-directory-entry"><glossterm>Directory entry</glossterm> + <glossdef> + <para> + A directory entry is a file with a name ending in the ".directory" + extension which conforms to the <ulink + url="http://www.freedesktop.org/Standards/desktop-entry-spec">desktop + entry specification</ulink> with <literal>Type=Directory</literal>. + It provides a localized name and an icon for a submenu. + Directory entries are also known as ".directory files." + </para> + </glossdef> + </glossentry> + + <glossentry id="term-menu-path"><glossterm>Menu path</glossterm> + <glossdef> + <para> + A "menu path" is the path to a particular menu. Menu paths are + always "relative" so never start with a slash character. + The path to a menu is simply the <Name> of each parent + of the menu, followed by the <Name> of the menu itself. + For example, "Foo/Bar/Baz" is a valid menu path. + </para> + </glossdef> + </glossentry> + + <glossentry id="term-relative-path"><glossterm>Relative path</glossterm> + <glossdef> + <para> + The canonical path to a directory entry, relative to the + <DirectoryDir> containing the + entry. For example, if <filename>/usr/share/desktop-directories</filename> is + specified as an <DirectoryDir>, the relative path to + <filename>/usr/share/desktop-directories/foo/bar.directory</filename> is + <filename>foo/bar.directory</filename>. + </para> + </glossdef> + </glossentry> + </glossary> +</article> + diff --git a/menu/menu.dtd b/menu/menu.dtd new file mode 100644 index 0000000..1bca3ed --- /dev/null +++ b/menu/menu.dtd @@ -0,0 +1,84 @@ +<!-- For explanations see http://www.freedesktop.org/standards/menu-spec --> +<!ELEMENT Menu ( + Name, ( + Directory + | DefaultAppDirs + | AppDir + | DefaultDirectoryDirs + | DirectoryDir + | LegacyDir + | KDELegacyDirs + | MergeFile + | DefaultMergeDirs + | MergeDir + | OnlyUnallocated + | NotOnlyUnallocated + | Deleted + | NotDeleted + | Include + | Exclude + | Move + | Menu + | Layout + | DefaultLayout + )* +)> + +<!ELEMENT Name (#PCDATA)> + +<!ELEMENT Directory (#PCDATA)> + +<!ELEMENT DefaultAppDirs EMPTY> +<!ELEMENT AppDir (#PCDATA)> + +<!ELEMENT DefaultDirectoryDirs EMPTY> +<!ELEMENT DirectoryDir (#PCDATA)> + +<!ELEMENT LegacyDir (#PCDATA)> +<!ATTLIST LegacyDir prefix CDATA #IMPLIED> +<!ELEMENT KDELegacyDirs EMPTY> + +<!ELEMENT MergeFile (#PCDATA)> +<!ATTLIST MergeFile type (path|parent) #IMPLIED> + +<!ELEMENT DefaultMergeDirs EMPTY> +<!ELEMENT MergeDir (#PCDATA)> + +<!ELEMENT OnlyUnallocated EMPTY> +<!ELEMENT NotOnlyUnallocated EMPTY> + +<!ELEMENT Deleted EMPTY> +<!ELEMENT NotDeleted EMPTY> + +<!ELEMENT Exclude ((Category|Filename|And|Or|Not|All)*)> +<!ELEMENT Include ((Category|Filename|And|Or|Not|All)*)> + +<!ELEMENT And ((Category|Filename|And|Or|Not|All)*)> +<!ELEMENT Or ((Category|Filename|And|Or|Not|All)*)> +<!ELEMENT Not ((Category|Filename|And|Or|Not|All)*)> +<!ELEMENT Filename (#PCDATA)> +<!ELEMENT Category (#PCDATA)> +<!ELEMENT All EMPTY> + +<!ELEMENT Move ((Old,New)*)> +<!ELEMENT Old (#PCDATA)> +<!ELEMENT New (#PCDATA)> + +<!ELEMENT Layout ((Filename|Menuname|Separator|Merge)*)> +<!ELEMENT DefaultLayout ((Filename|Menuname|Separator|Merge)*)> +<!ATTLIST DefaultLayout show_empty (true|false) #IMPLIED> +<!ATTLIST DefaultLayout inline (true|false) #IMPLIED> +<!ATTLIST DefaultLayout inline_limit CDATA #IMPLIED> +<!ATTLIST DefaultLayout inline_header (true|false) #IMPLIED> +<!ATTLIST DefaultLayout inline_alias (true|false) #IMPLIED> + +<!ELEMENT Menuname (#PCDATA)> +<!ATTLIST Menuname inline (true|false) #IMPLIED> +<!ATTLIST Menuname inline_limit CDATA #IMPLIED> +<!ATTLIST Menuname inline_header (true|false) #IMPLIED> +<!ATTLIST Menuname inline_alias (true|false) #IMPLIED> + +<!ELEMENT Separator EMPTY> + +<!ELEMENT Merge EMPTY> +<!ATTLIST Merge type (menus|files|all) #REQUIRED> diff --git a/menu/tests/ChangeLog b/menu/tests/ChangeLog new file mode 100644 index 0000000..ac55e4f --- /dev/null +++ b/menu/tests/ChangeLog @@ -0,0 +1,70 @@ +2005-04-25 Mark McLoughlin <mark@skynet.ie> + + * tests/u: add test for recursive inclusion of .menu files. + Also know as the "get really hosed and eat all the RAM + you can find" test. + +2005-04-20 Waldo Bastian <bastian@kde.org> + + * tests/s/result, + tests/s/test: Test that .desktop files under $HOME correctly + override .desktop files at system level + + * tests/t/result, + tests/t/test: Test order in which <Move> elements are processed + +2005-02-18 Mark McLoughlin <mark@skynet.ie> + + Make it a bit more difficult in order to catch: + http://bugzilla.gnome.org/show_bug.cgi?id=167758 + Thanks to Chris Lahey for the test case. + + * tests/o/test: put freecell.desktop in a subdirectory. + +2005-02-18 Mark McLoughlin <mark@skynet.ie> + + * tests/o/result, + tests/o/test: test that + <And><Category>foo</Category><Not><Category>foo</Category></Not></And> + doesn't match anything. + + * README: add bit about how to test the GNOME impl. + +2005-02-18 Mark McLoughlin <mark@skynet.ie> + + Problem pointed out by Waldo. + + * menutest: don't try and run the "CVS" test :) + + * tests/m/result, + tests/n/result: items in a hidden or deleted menu + should be considered allocated. + +2004-12-08 Mark McLoughlin <mark@skynet.ie> + + * tests/2/result, + tests/2/test: test the new <OnlyUnallocated> behaviour. + +2004-08-29 Mark McLoughlin <mark@skynet.ie> + + * tests/m: test for NoDisplay=true behavious in .desktop and + .directory files. + + * data/hidden.desktop, + data/hidden.directory: add. + + * data/apps.directory: add Type=Directory. + + * menutest: actually generate a test result if one doesn't + exist - makes it easier to write new tests. + +2003-10-23 Havoc Pennington <hp@redhat.com> + + * tests/f/test: remove <OnlyUnallocated/> from inside <Include> + statement, not allowed. + +2003-10-16 Havoc Pennington <hp@redhat.com> + + * menutest: cat log file on failure; print list of failed tests + when we're done + diff --git a/menu/tests/README b/menu/tests/README new file mode 100644 index 0000000..b003dc0 --- /dev/null +++ b/menu/tests/README @@ -0,0 +1,44 @@ +This directory contains regression tests for the menu-spec. + +To run these tests your menu-spec implementation should be +able to generate a menu in the following text format: + +<Full Menu Name><tab><Desktop File Id><tab><Full Path to Desktop File> + +Example: + +Editors/ kde-kwrite.desktop /home/bastian/.local/share/applications/kde-kwrite.desktop +Editors/ kde-kate.desktop /home/bastian/.local/share/applications/kde-kate.desktop +Editors/ kde-KEdit.desktop /home/bastian/.local/share/applications/kde-KEdit.desktop +Development/ kde-gideon.desktop /opt/kde3/share/applnk/Development/gideon.desktop +Development/ kde-kbabel.desktop /opt/kde3/share/applnk/Development/kbabel.desktop +Development/ kde-quanta.desktop /opt/kde3/share/applnk/Development/quanta.desktop +/ kde-Kfind.desktop /opt/kde3/share/applnk/Kfind.desktop +/ kde-Home.desktop /opt/kde3/share/applnk/Home.desktop +/ kde-Help.desktop /opt/kde3/share/applnk/Help.desktop + + + +The environment variable $MENUTEST should point to a command that is +able to generate the menu in the above format. + +To test KDE one can use: + MENUTEST="kbuildsycoca --menutest" + +With GNOME, you can use: + MENUTEST=gnome-menu-spec-test + +The menutest script should be used to run the tests. The following commands can +be used: + + MENUTEST="foo -bar" ./menutest + +to run all tests + + MENUTEST="foo -bar" TESTS="Deleted Directory" ./menutest + +to run the tests named "Deleted" and "Directory" only + +All tests contain of a test setup script named "test" and a file describing +the expected menu named "result". + diff --git a/menu/tests/TODO b/menu/tests/TODO new file mode 100644 index 0000000..6e178bf --- /dev/null +++ b/menu/tests/TODO @@ -0,0 +1,5 @@ +I hope you understand what i mean ;) + +desktop-file-id stuff & overwrite stuff absolute path + +onlyshowin - notshowin diff --git a/menu/tests/data/Help.desktop b/menu/tests/data/Help.desktop new file mode 100644 index 0000000..dc867cd --- /dev/null +++ b/menu/tests/data/Help.desktop @@ -0,0 +1,68 @@ +[Desktop Entry] +Encoding=UTF-8 +Exec=khelpcenter +Icon=khelpcenter +DocPath=khelpcenter/index.html +Type=Application +Terminal=0 + +Name=Help +Name[af]=Hulp +Name[az]=Yardım +Name[be]=Дапамога +Name[bg]=Помощ +Name[br]=Skoazell +Name[bs]=Pomoć +Name[ca]=Ajuda +Name[cs]=Nápověda +Name[cy]=Cymorth +Name[da]=Hjælp +Name[de]=Hilfe +Name[el]=Βοήθεια +Name[eo]=Helpo +Name[es]=Ayuda +Name[et]=Abiinfo +Name[eu]=Laguntza +Name[fa]=راهنما +Name[fi]=Ohje +Name[fr]=Aide +Name[gl]=Axuda +Name[he]=עזרה +Name[hr]=Pomoć +Name[hu]=Segítség +Name[id]=Keterangan bantu +Name[is]=Hjálp +Name[it]=Aiuto +Name[ja]=ヘルプ +Name[ko]=도움말 +Name[lo]=ລະບົບຊ່ວຍເຫືລອ +Name[lt]=Pagalba +Name[lv]=Palīdzība +Name[mn]=Тусламж +Name[mt]=Għajnuna +Name[nb]=Hjelp +Name[nn]=Hjelp +Name[nso]=Thuso +Name[oc]=Ajuda +Name[pl]=Pomoc +Name[pt]=Ajuda +Name[pt_BR]=Ajuda +Name[ro]=Ajutor +Name[ru]=Справка +Name[sk]=Pomocník +Name[sl]=Pomoč +Name[sr]=Pomoć +Name[ss]=Sita +Name[sv]=Hjälp +Name[ta]=¯¾Å¢ +Name[th]=ระบบช่วยเหลือ +Name[tr]=Yardım +Name[uk]=Довідка +Name[ven]=Thuso +Name[vi]=Trợ giúp +Name[wa]=Aidance +Name[xh]=Uncedo +Name[zh_CN]=帮助 +Name[zh_TW]=求助 +Name[zu]=Usizo + diff --git a/menu/tests/data/Home.desktop b/menu/tests/data/Home.desktop new file mode 100644 index 0000000..2bf8178 --- /dev/null +++ b/menu/tests/data/Home.desktop @@ -0,0 +1,127 @@ +[Desktop Entry] +Encoding=UTF-8 +Type=Application +Exec=kfmclient openProfile filemanagement +Icon=folder_home +Terminal=0 + +Name=Home +Name[af]=Huis +Name[az]=Başlanğıc +Name[be]=Хатні +Name[bg]=Домашна директория +Name[br]=Er-gêr +Name[bs]=Početak +Name[ca]=Inici +Name[cs]=Můj adresář +Name[cy]=Cartref +Name[da]=Hjem +Name[de]=Persönliches Verzeichnis +Name[el]=Σπίτι +Name[eo]=Hejmo +Name[es]=Personal +Name[et]=Kodukataloog +Name[eu]=Etxea +Name[fa]=خانه +Name[fi]=Koti +Name[fr]=Dossier personnel +Name[gl]=Persoal +Name[he]=בית +Name[hr]=Početak +Name[hu]=Saját könyvtár +Name[id]=Rumah +Name[is]=Heimasvæðið þitt +Name[ja]=ホーム +Name[ko]=홈 +Name[lo]=ພື້ນທີ່ສ່ວນຕົວ +Name[lt]=Pradžia +Name[lv]=Mājas +Name[mn]=Хувийн лавлах +Name[mt]=Direttorju Personali +Name[nb]=Hjem +Name[nl]=Persoonlijke map +Name[nn]=Heim +Name[nso]=Gae +Name[oc]=Inici +Name[pl]=Katalog domowy +Name[pt]=Casa +Name[ro]=Acasă +Name[ru]=Домой +Name[sk]=Domov +Name[sl]=Domov +Name[sr]=Кориснички директоријум +Name[ss]=Ekhaya +Name[sv]=Hem +Name[ta]=¦¾¡¼ì¸õ +Name[th]=พื้นที่ส่วนตัว +Name[tr]=Başlangıç +Name[uk]=Домівка +Name[ven]=Haya +Name[wa]=Måjhon +Name[xh]=Ikhaya +Name[xx]=xxHomexx +Name[zh_CN]=起点 +Name[zh_TW]=家目錄 +Name[zu]=Ikhaya + +GenericName=Personal Files +GenericName[af]=Persoonlike Lêers +GenericName[az]=Şəxsi Fayllar +GenericName[be]=Пэрсанальныя файлы +GenericName[bg]=Лични файлове +GenericName[br]=Restroù deoc'h +GenericName[bs]=Osobne datoteke +GenericName[ca]=Fitxers personals +GenericName[cs]=Osobní soubory +GenericName[cy]=Ffeiliau Personol +GenericName[da]=Personlige filer +GenericName[de]=Eigene Dateien +GenericName[el]=Προσωπικά Αρχεία +GenericName[eo]=Personaj dosieroj +GenericName[es]=Archivos personales +GenericName[et]=Isiklikud failid +GenericName[eu]=Fitxategi Pertsonalak +GenericName[fa]=پروندههای شخصی +GenericName[fi]=Omat tiedostot +GenericName[fr]=Fichiers personnels +GenericName[gl]=Ficheiros Persoais +GenericName[he]=קבצים אישיים +GenericName[hr]=Osobne datoteke +GenericName[hu]=személyes fájlok +GenericName[id]=File Pribadi +GenericName[is]=Skrárnar þÃnar +GenericName[it]=File personali +GenericName[ja]=個人のファイル +GenericName[ko]=혼자만 쓰는 파일 +GenericName[lo]=ທີ່ເກັບແຟ້ມແລະເອກະສານສວ່ນຕົວຫລືອື່ນຯ +GenericName[lt]=Asmeninės Bylos +GenericName[lv]=Personālie Faili +GenericName[mn]=Өөрийн файлууд +GenericName[mt]=Fajls Personali +GenericName[nb]=Personlige filer +GenericName[nl]=persoonlijke bestanden +GenericName[nn]=Personlege filer +GenericName[nso]=Difaele tsa Botho +GenericName[oc]=FiquièRs personals +GenericName[pl]=Pliki osobiste +GenericName[pt]=Ficheiros Pessoais +GenericName[pt_BR]=Arquivos Pessoais +GenericName[ro]=Fişiere personale +GenericName[ru]=Личные файлы +GenericName[sk]=Osobné súbory +GenericName[sl]=Osebne datoteke +GenericName[sr]=Овај директоријум садржи ваше личне фајлове +GenericName[sv]=Personliga filer +GenericName[ta]=¦º¡ó¾ì §¸¡ôÒì¸û +GenericName[th]=ที่เก็บแฟ้มและเอกสารส่วนตัว หรืออื่น ๆ +GenericName[tr]=Kişisel Dosyalar +GenericName[uk]=Особисті файли +GenericName[ven]=Dzifaela dza vhune +GenericName[vi]=File cá nhân +GenericName[wa]=Fitchîs da vosse +GenericName[xh]=Iifayile Zobuqu +GenericName[xx]=xxPersonal Filesxx +GenericName[zh_CN]=个人文件 +GenericName[zh_TW]=個人檔案 +GenericName[zu]=Amafayela Omuntu siqu + diff --git a/menu/tests/data/KEdit.desktop b/menu/tests/data/KEdit.desktop new file mode 100644 index 0000000..4274a2b --- /dev/null +++ b/menu/tests/data/KEdit.desktop @@ -0,0 +1,34 @@ +[Desktop Entry] +Encoding=UTF-8 +BinaryPattern=kedit; +MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++; +GenericName=Simple Text Editor +GenericName[ca]=Editor de text +GenericName[cs]=Jednoduchý textový editor +GenericName[da]=Simpel teksteditor +GenericName[es]=Editor de texto sencillo +GenericName[fr]=Éditeur de texte élémentaire +GenericName[pt_BR]=Editor de Texto Simples +GenericName[sv]=Enkel texteditor +GenericName[wa]=Simpe aspougneu di tecse +Exec=kedit -caption "%c" %i %m %u +Icon=kedit +TerminalOptions= +Path= +DocPath=kedit/index.html +Type=Application +Terminal=0 +Name=KEdit +Name[af]=Kredigeer +Name[eo]=Redaktilo +Name[hr]=Uređivač +Name[lv]=KRediģēt +Name[pl]=Edytor +Name[sv]=Kedit +Name[th]=แก้ไขข้อความ +Name[ven]=U sengulusa ha K +Name[xh]=Abahleli Be K +Name[zh_TW]=KDE 編輯器 +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;TextEditor diff --git a/menu/tests/data/Kfind.desktop b/menu/tests/data/Kfind.desktop new file mode 100644 index 0000000..8984f18 --- /dev/null +++ b/menu/tests/data/Kfind.desktop @@ -0,0 +1,66 @@ +[Desktop Entry] +Encoding=UTF-8 +Exec=kfind %f +Icon=kfind +DocPath=kfind/index.html +TerminalOptions= +Path= +Type=Application +Terminal=0 +Name=Find Files +Name[af]=Soek Lêers +Name[be]=Шукаць файлы +Name[bg]=Търсене на файлове +Name[br]=Klask restroù +Name[bs]=Pronađi datoteke +Name[ca]=Cerca fitxers +Name[cs]=Najít soubory +Name[cy]=Canfod Ffeiliau +Name[da]=Find filer +Name[de]=Dateien suchen +Name[el]=Εύρεση αρχείων +Name[eo]=Trovu dosierojn +Name[es]=KFind +Name[et]=Failide otsimine +Name[eu]=Fitxategiak Bilatu +Name[fa]=یافتن پروندهها +Name[fi]=Etsi tiedostoja +Name[fr]=Recherche de fichiers +Name[gl]=Buscar Ficheiros +Name[he]=חפש קבצים +Name[hr]=Nađi datoteke +Name[hu]=Fájlkeresés +Name[id]=Cari Berkas +Name[it]=Trova file +Name[ja]=ファイルを検索 +Name[ko]=파일 찾기 +Name[lo]=ຄົ້ນຫາແຟ້ມ +Name[lt]=Rasti bylas +Name[lv]=Meklēt Failus +Name[mn]=Файл хайх +Name[mt]=Sib Fajls +Name[nb]=Finn filer +Name[nl]=Bestanden zoeken +Name[nn]=Finn filer +Name[nso]=Hwetsa Difaele +Name[oc]=Cerca fiquièrs +Name[pl]=Znajdź pliki +Name[pt]=Procurar Ficheiros +Name[pt_BR]=Encontrar arquivos +Name[ro]=Caută fişiere +Name[ru]=Поиск файлов +Name[sk]=Hľadať súbory +Name[sl]=Poišči datoteke +Name[sr]=Pretraga fajlova +Name[sv]=Hitta filer +Name[ta]=§¸¡ôÒì ¸ñÎÀ¢Ê +Name[th]=ค้นหาแฟ้ม +Name[tr]=Dosyalarda Bul +Name[uk]=Знайти файли +Name[ven]=Todani faela +Name[vi]=Tìm file +Name[xh]=Fumana Iifayile +Name[zh_CN]=查找文件 +Name[zh_TW]=尋找檔案 +Name[zu]=Thola Amafayela +X-KDE-StartupNotify=true diff --git a/menu/tests/data/apps.directory b/menu/tests/data/apps.directory new file mode 100644 index 0000000..d54b4bd --- /dev/null +++ b/menu/tests/data/apps.directory @@ -0,0 +1,66 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Apps +Name[af]=Programme +Name[ar]=تطبيقات +Name[az]=Proqram Tə'minatları +Name[be]=Дастасаваньні +Name[bg]=Приложения +Name[br]=Arloadoù +Name[bs]=Aplikacije +Name[ca]=Aplicacions +Name[cs]=Aplikace +Name[da]=Øvrige programmer +Name[de]=Programme +Name[el]=Εφαρμογές +Name[eo]=Aplikaĵoj +Name[es]=Aplicaciones +Name[et]=Rakendused +Name[eu]=Aplikazioak +Name[fa]=برنامههای کاربردی +Name[fi]=Sovellukset +Name[fo]=Nýtsluskipanir +Name[gl]=Aplicacións +Name[he]=יישומים +Name[hr]=Programi +Name[hu]=Alkalmazások +Name[id]=Aplikasi +Name[is]=Forrit +Name[it]=Applicazioni +Name[ja]=アプリケーション +Name[ko]=응용 프로그램 +Name[lo]=ອັບພລິກເຄເຊິນ +Name[lt]=Programos +Name[lv]=Aplikācijas +Name[mk]=Апликации +Name[mt]=Applikazzjonijiet +Name[nb]=Programmer +Name[nl]=Programma's +Name[nn]=Program +Name[nso]=Ditshomiso +Name[oc]=Aplicacions +Name[pl]=Aplikacje +Name[pt]=Aplicações +Name[pt_BR]=Aplicativos +Name[ro]=Aplicaţii +Name[ru]=Приложения +Name[se]=Prográmmat +Name[sk]=Aplikácie +Name[sl]=Uporabniški programi +Name[sr]=Aplikacije +Name[ss]=Ticelo +Name[sv]=Program +Name[ta]=ÀÂýÀ¡Î¸û +Name[th]=แอพพลิเคชัน +Name[tr]=Uygulamalar +Name[uk]=Програми +Name[ven]=Apulikhesheni +Name[vi]=Chương trình +Name[wa]=Programes +Name[xh]=Izicelo +Name[zh_CN]=应用程序 +Name[zh_TW]=應用程式 +Name[zu]=Abayaleli +Type=Directory +Icon=package_applications + diff --git a/menu/tests/data/freecell.desktop b/menu/tests/data/freecell.desktop new file mode 100644 index 0000000..da6d251 --- /dev/null +++ b/menu/tests/data/freecell.desktop @@ -0,0 +1,83 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=FreeCell +Name[be]=Вольная ячэя +Name[bg]=Свободна Клетка +Name[bn]=ফ্রীসেল +Name[ca]=FreeCell +Name[cs]=FreeCell +Name[da]=Napoleon +Name[de]=FreeCell +Name[el]=FreeCell +Name[es]=FreeCell +Name[et]=Freecell +Name[fi]=Vapaakenttä +Name[fr]=Freecell +Name[ga]=FreeCell +Name[gl]=FreeCell +Name[he]=פריסל +Name[hu]=FreeCell +Name[it]=FreeCell +Name[ja]=フリーセル +Name[ko]=프리셀 +Name[lt]=FreeCell +Name[lv]=FreeCell +Name[mn]=Фриселл +Name[ms]=FreeCell +Name[nl]=FreeCell +Name[no]=Freecell +Name[pl]=FreeCell +Name[pt]=Freecell +Name[pt_BR]=FreeCell +Name[ru]=Фриселл +Name[sk]=FreeCell +Name[sl]=FreeCell +Name[sv]=Napoleon på S:t Helena +Name[tr]=İskambil falı +Name[uk]=Вільна комірка +Name[vi]=FreeCell +Name[wa]=Freecell +Name[zh_CN]=空当接龙 +Name[zh_TW]=Freecell +Comment=FreeCell game +Comment[be]=Гульня ў Вольную ячэю +Comment[bg]=игра Свободна Клетка +Comment[bn]=ফ্রীসেল খেলা +Comment[ca]=Joc del FreeCell +Comment[cs]=Hra FreeCell +Comment[da]=Kortspillet Napoleon +Comment[de]=FreeCell-Spiel +Comment[el]=Το παιχνίδι FreeCell +Comment[es]=Juego FreeCell +Comment[et]=Kaardimäng FreeCell +Comment[fi]=Vapaakenttä-peli +Comment[fr]=Jeu de cartes Freecell +Comment[he]=משחק פריסל +Comment[hu]=FreeCell játék +Comment[it]=FreeCell +Comment[ja]=フリーセルの GNOME 版 +Comment[lv]=FreeCell spēle +Comment[mn]=GNOME Фриселл тоглоом +Comment[ms]=Permainan FreeCell +Comment[nl]=FreeCell Spel +Comment[no]=Spillet FreeCell +Comment[pl]=Gra FreeCell +Comment[pt]=Jogo FreeCell +Comment[pt_BR]=Jogo de FreeCell +Comment[ru]=Пасьянс "Ячейка" +Comment[sk]=Hra FreeCell +Comment[sl]=Igra Freecell +Comment[sv]=Spelet Napoleon på S:t Helena +Comment[tr]=İskambil falı oyunu +Comment[uk]=Гра "Вільна комірка" +Comment[vi]=Trò chơi FreeCell +Comment[zh_TW]=Freecell 紙牌接龍遊戲 +Exec=freecell +Icon=gnome-cardgame.png +Terminal=false +Type=Application +Categories=GNOME;Application;Game;CardGame; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-games +X-GNOME-Bugzilla-Component=freecell +StartupNotify=true diff --git a/menu/tests/data/gataxx.desktop b/menu/tests/data/gataxx.desktop new file mode 100644 index 0000000..10dfec6 --- /dev/null +++ b/menu/tests/data/gataxx.desktop @@ -0,0 +1,81 @@ +[Desktop Entry] +Encoding=UTF-8 +Icon=gataxx.png +Name=Gataxx +Name[am]=Gataxx +Name[be]=Gataxx +Name[bg]=Гатаксс +Name[bn]=জীঅ্যাটাক্স +Name[ca]=Gataxx +Name[cs]=Gataxx +Name[da]=Ataxx +Name[de]=Gataxx +Name[el]=Gataxx +Name[es]=Gataxx +Name[et]=Gataxx +Name[fi]=Gataxx +Name[fr]=Gataxx +Name[he]=Gataxx +Name[hu]=Gataxx +Name[it]=Gataxx +Name[ja]=Gataxx +Name[ko]=Gataxx +Name[lv]=Gataxx +Name[mn]=Gataxx +Name[ms]=Gataxx +Name[nl]=Gataxx +Name[no]=Gataxx +Name[pl]=Gataxx +Name[pt]=Gataxx +Name[pt_BR]=Gataxx +Name[ru]=Gataxx +Name[sk]=Gataxx +Name[sl]=Gataxx +Name[sv]=Gataxx +Name[tr]=Gataxx +Name[uk]=Атаки +Name[vi]=Gataxx +Name[wa]=Gataxx +Name[zh_CN]=Gataxx +Name[zh_TW]=Gataxx +Comment=Ataxx game +Comment[be]=Гульня Ataxx +Comment[bg]=Игра атаксс +Comment[bn]=অ্যাটাক্স খেলা +Comment[ca]=Joc del Ataxx +Comment[cs]=Hra Ataxx +Comment[da]=Spillet Ataxx +Comment[de]=Ataxx-Spiel +Comment[el]=Παιχνίδι Ataxx +Comment[es]=Un juego tipo Ataxx. +Comment[et]=Mäng nimega ataxx +Comment[fi]=Ataxx-peli +Comment[fr]=Jeu Ataxx +Comment[he]=משחק Ataxx +Comment[hu]=Ataxx játék +Comment[it]=Gioco Ataxx +Comment[ja]=Ataxx ゲーム +Comment[lv]=Ataxx spēle +Comment[mn]=Ataxx тоглоом. +Comment[ms]=Permainan Ataxx +Comment[nl]=Ataxx +Comment[no]=Ataxx-spill +Comment[pl]=Gra Ataxx +Comment[pt]=Jogo Ataxx +Comment[pt_BR]=Jogo Ataxx +Comment[ru]=Игра ataxx +Comment[sk]=Hra Ataxx +Comment[sl]=Igra Ataxx +Comment[sv]=Spelet Ataxx +Comment[tr]=Ataxx oyunu +Comment[uk]=Гра "Атаки" +Comment[vi]=Trò chơi Ataxx. +Comment[zh_TW]=Ataxx 遊戲 +Exec=gataxx +Terminal=false +Type=Application +Categories=GNOME;Application;Game;BoardGame; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-games +X-GNOME-Bugzilla-Component=gataxx +StartupNotify=true diff --git a/menu/tests/data/gideon-legacy.desktop b/menu/tests/data/gideon-legacy.desktop new file mode 100644 index 0000000..4595087 --- /dev/null +++ b/menu/tests/data/gideon-legacy.desktop @@ -0,0 +1,12 @@ +[KDE Desktop Entry] +Encoding=UTF-8 +BinaryPattern=kdevelop; +Type=Application +Exec=gideon %u +MimeType=application/x-kdevelop; +Icon=gideon +DocPath=kdevelop/index.html +Terminal=0 +Name=KDevelop 3.0 +Comment=IDE for C++/Qt/KDE +X-DCOP-ServiceType=Multi diff --git a/menu/tests/data/gideon.desktop b/menu/tests/data/gideon.desktop new file mode 100644 index 0000000..1e11dc1 --- /dev/null +++ b/menu/tests/data/gideon.desktop @@ -0,0 +1,13 @@ +[Desktop Entry] +Encoding=UTF-8 +BinaryPattern=kdevelop; +Type=Application +Exec=gideon %u +MimeType=application/x-kdevelop; +Icon=gideon +DocPath=kdevelop/index.html +Terminal=0 +Name=KDevelop 3.0 +Comment=IDE for C++/Qt/KDE +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;Development diff --git a/menu/tests/data/glines-2.desktop b/menu/tests/data/glines-2.desktop new file mode 100644 index 0000000..266747d --- /dev/null +++ b/menu/tests/data/glines-2.desktop @@ -0,0 +1,83 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Glines +Name[be]=Glines +Name[bg]=ГЛинии +Name[bn]=জীলাইন্স +Name[ca]=Glines +Name[cs]=Glines +Name[da]=Linjer +Name[de]=Glines +Name[el]=Glines +Name[es]=Glines +Name[et]=Glines +Name[eu]=Glines +Name[fi]=Glines +Name[fr]=Glines +Name[he]=Glines +Name[hu]=Glines +Name[it]=Glines +Name[ja]=Glines +Name[ko]=Glines +Name[lt]=Glines +Name[lv]=Glines +Name[mn]=Glines +Name[ms]=Glines +Name[nl]=GLines +Name[no]=Glines +Name[pl]=Glines +Name[pt]=GLinhas +Name[pt_BR]=Glines +Name[ro]=Glines +Name[ru]=Glines +Name[sk]=GČiary +Name[sl]=Glines +Name[sv]=Glinjer +Name[tr]=Sıradaki toplar +Name[uk]=Ряди +Name[vi]=Glines +Name[wa]=GRoyes +Name[zh_CN]=Glines +Name[zh_TW]=Glines +Comment=Color lines game +Comment[be]=Гульня "Каляровыя лініі" +Comment[bg]=Игра Цветни линии +Comment[bn]=কালার লাইন্স খেলা +Comment[ca]=Joc de línies de color +Comment[cs]=Hra Barevné linie +Comment[da]=Farvede linjer-spil +Comment[de]=Farblinienspiel +Comment[el]=Παιχνίδι γραμμών χρώματος +Comment[es]=Juego del tipo líneas de colores. +Comment[fi]=Väriviivapeli +Comment[fr]=Jeu de lignes colorées +Comment[he]=משחק שורות צבעוניות +Comment[hu]=Color lines játék +Comment[it]=Gioco Color Lines +Comment[ja]=カラーラインのゲーム +Comment[lv]=Krāsu līniju spēle +Comment[mn]=Өнгөт бөмбөлөг тоглоом +Comment[ms]=Permainan garisan warna +Comment[nl]=Kleurlijnen +Comment[no]=Spill med fargelinjer +Comment[pl]=Gra w kolorowe linie +Comment[pt]=Jogo das linhas coloridas +Comment[pt_BR]=Jogo de linhas coloridas +Comment[ru]=Игра "Цветные линии" +Comment[sk]=Hra Farebné čiary +Comment[sl]=Igra barvnih črt +Comment[sv]=Färglinjespel +Comment[tr]=Color lines oyunu +Comment[uk]=Гра "Кольорові ряди" +Comment[vi]=Trò chơi ColorLines +Comment[zh_TW]=Color lines 遊戲 +Exec=glines +Icon=glines.png +Terminal=false +Type=Application +Categories=GNOME;Application;Game;PuzzleGame; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-games +X-GNOME-Bugzilla-Component=glines +StartupNotify=true +NoDisplay=true diff --git a/menu/tests/data/glines.desktop b/menu/tests/data/glines.desktop new file mode 100644 index 0000000..5e5b465 --- /dev/null +++ b/menu/tests/data/glines.desktop @@ -0,0 +1,82 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Glines +Name[be]=Glines +Name[bg]=ГЛинии +Name[bn]=জীলাইন্স +Name[ca]=Glines +Name[cs]=Glines +Name[da]=Linjer +Name[de]=Glines +Name[el]=Glines +Name[es]=Glines +Name[et]=Glines +Name[eu]=Glines +Name[fi]=Glines +Name[fr]=Glines +Name[he]=Glines +Name[hu]=Glines +Name[it]=Glines +Name[ja]=Glines +Name[ko]=Glines +Name[lt]=Glines +Name[lv]=Glines +Name[mn]=Glines +Name[ms]=Glines +Name[nl]=GLines +Name[no]=Glines +Name[pl]=Glines +Name[pt]=GLinhas +Name[pt_BR]=Glines +Name[ro]=Glines +Name[ru]=Glines +Name[sk]=GČiary +Name[sl]=Glines +Name[sv]=Glinjer +Name[tr]=Sıradaki toplar +Name[uk]=Ряди +Name[vi]=Glines +Name[wa]=GRoyes +Name[zh_CN]=Glines +Name[zh_TW]=Glines +Comment=Color lines game +Comment[be]=Гульня "Каляровыя лініі" +Comment[bg]=Игра Цветни линии +Comment[bn]=কালার লাইন্স খেলা +Comment[ca]=Joc de línies de color +Comment[cs]=Hra Barevné linie +Comment[da]=Farvede linjer-spil +Comment[de]=Farblinienspiel +Comment[el]=Παιχνίδι γραμμών χρώματος +Comment[es]=Juego del tipo líneas de colores. +Comment[fi]=Väriviivapeli +Comment[fr]=Jeu de lignes colorées +Comment[he]=משחק שורות צבעוניות +Comment[hu]=Color lines játék +Comment[it]=Gioco Color Lines +Comment[ja]=カラーラインのゲーム +Comment[lv]=Krāsu līniju spēle +Comment[mn]=Өнгөт бөмбөлөг тоглоом +Comment[ms]=Permainan garisan warna +Comment[nl]=Kleurlijnen +Comment[no]=Spill med fargelinjer +Comment[pl]=Gra w kolorowe linie +Comment[pt]=Jogo das linhas coloridas +Comment[pt_BR]=Jogo de linhas coloridas +Comment[ru]=Игра "Цветные линии" +Comment[sk]=Hra Farebné čiary +Comment[sl]=Igra barvnih črt +Comment[sv]=Färglinjespel +Comment[tr]=Color lines oyunu +Comment[uk]=Гра "Кольорові ряди" +Comment[vi]=Trò chơi ColorLines +Comment[zh_TW]=Color lines 遊戲 +Exec=glines +Icon=glines.png +Terminal=false +Type=Application +Categories=GNOME;Application;Game;PuzzleGame; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-games +X-GNOME-Bugzilla-Component=glines +StartupNotify=true diff --git a/menu/tests/data/hidden.desktop b/menu/tests/data/hidden.desktop new file mode 100644 index 0000000..dbbbff9 --- /dev/null +++ b/menu/tests/data/hidden.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Hidden +Comment=You shouldn't see this +Exec=hidden +Type=Application +Categories=GNOME;Application;TextEditor; +NoDisplay=true diff --git a/menu/tests/data/hidden.directory b/menu/tests/data/hidden.directory new file mode 100644 index 0000000..5f1e776 --- /dev/null +++ b/menu/tests/data/hidden.directory @@ -0,0 +1,5 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Hidden +Type=Directory +NoDisplay=true diff --git a/menu/tests/data/kate.desktop b/menu/tests/data/kate.desktop new file mode 100644 index 0000000..3ca1c5d --- /dev/null +++ b/menu/tests/data/kate.desktop @@ -0,0 +1,30 @@ +[Desktop Entry] +Encoding=UTF-8 +GenericName=Advanced Text Editor +GenericName[cy]=Golygydd Testun Uwch +GenericName[da]= Avanceret teksteditor +GenericName[el]=Προχωρημένος διορθωτής κειμένου +GenericName[es]=Editor de texto avanzado +GenericName[fa]=ویرایشگر متن پیشرفته +GenericName[hu]=szövegszerkesztő +GenericName[pt_BR]=Editor de Texto Avançado +GenericName[sr]=Napredni editor teksta +GenericName[sv]=Avancerad texteditor +BinaryPattern= +Name=Kate +Name[ar]=كيت +Name[bg]=Редактор Kate +Name[eo]=Kodredaktilo +Name[fa]=کِیت +Name[ko]=카테 +Name[ru]=Редактор Kate +MimeType=text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;text/rdf; +Exec=kate %u +TerminalOptions= +Icon=kate +Path= +DocPath=kate/index.html +Type=Application +Terminal=0 +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;TextEditor diff --git a/menu/tests/data/kbabel.desktop b/menu/tests/data/kbabel.desktop new file mode 100644 index 0000000..2892cb8 --- /dev/null +++ b/menu/tests/data/kbabel.desktop @@ -0,0 +1,69 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=KBabel +Name[af]=Kbabel +Name[ar]=المترجم +Name[eo]=Babelo-tradukilo +Name[ko]=K바벨 +Name[pt_BR]=Editor de POTFiles +Name[sv]=Kbabel +Name[xx]=xxKBabelxx +Exec=kbabel %i %m -caption "%c" %U +Icon=kbabel +MiniIcon=kbabel +Type=Application +DocPath=kbabel/index.html +MimeType=application/x-gettext; +GenericName=Translation Tool +GenericName[af]=Vertaling Program +GenericName[ar]=أداة الترجمة +GenericName[bg]=Инструменти за Превод +GenericName[bs]=Alat za prevođenje +GenericName[ca]=Eina de traducció +GenericName[cs]=Překladatelský nástroj +GenericName[cy]=Erfyn Cyfieithu +GenericName[da]=Oversættelsesværktøj +GenericName[de]=Übersetzungsprogramm +GenericName[el]=Εργαλείο μετάφρασης +GenericName[eo]=Tradukilo por Qt-programoj +GenericName[es]=Herramienta de traducción +GenericName[et]=Tõlkimise rakendus +GenericName[eu]=Itzulpenerako Tresnak +GenericName[fi]=Käännöstyökalu +GenericName[fo]=Umsetingaramboð +GenericName[fr]=Outil de traduction +GenericName[he]=כלי תרגום +GenericName[hr]=Uslužni program za prevođenje +GenericName[hu]=segédprogram fordítóknak +GenericName[it]=Strumento per le traduzioni +GenericName[ja]=翻訳ツール +GenericName[lt]=Vertimo įrankis +GenericName[lv]=Tulkošanas Rīks +GenericName[mt]=Għodda tat-traduzzjoni +GenericName[nb]=Oversettingsverktøy +GenericName[nl]=vertaalprogramma +GenericName[nn]=Omsetjingsverktøy +GenericName[nso]=Sebereka sa Thlathollo +GenericName[pl]=Narzędzie dla tłumaczy +GenericName[pt]=Ferramenta de Tradução +GenericName[pt_BR]=Ferramenta de Tradução +GenericName[ro]=Utilitar de traducere +GenericName[ru]=Утилита локализации приложений +GenericName[sk]=Prekladací nástroj +GenericName[sl]=Orodje za prevajanje +GenericName[sv]=Översättningsverktyg +GenericName[ta]=¦Á¡Æ¢¦ÀÂ÷ôÒì ¸ÕÅ¢ +GenericName[th]=เครื่องมือแปลภาษา +GenericName[tr]=Çeviri Aracı +GenericName[uk]=Засіб для перекладів +GenericName[ven]=Zwishumiswa zwau Dologa +GenericName[vi]=Công cụ dịch +GenericName[xh]=Isixhobo Soguqulelo lomsebenzi kolunye ulwimi +GenericName[xx]=xxTranslation Toolxx +GenericName[zh_CN]=翻译工具 +GenericName[zh_TW]=翻譯工具 +GenericName[zu]=Ithuluzi Lokuguqulela +Terminal=0 +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Unique +Categories=Qt;KDE;Development diff --git a/menu/tests/data/kedit-legacy.desktop b/menu/tests/data/kedit-legacy.desktop new file mode 100644 index 0000000..fa9700e --- /dev/null +++ b/menu/tests/data/kedit-legacy.desktop @@ -0,0 +1,33 @@ +[Desktop Entry] +Encoding=UTF-8 +BinaryPattern=kedit; +MimeType=text/english;text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++; +GenericName=Simple Text Editor +GenericName[ca]=Editor de text +GenericName[cs]=Jednoduchý textový editor +GenericName[da]=Simpel teksteditor +GenericName[es]=Editor de texto sencillo +GenericName[fr]=Éditeur de texte élémentaire +GenericName[pt_BR]=Editor de Texto Simples +GenericName[sv]=Enkel texteditor +GenericName[wa]=Simpe aspougneu di tecse +Exec=kedit -caption "%c" %i %m %u +Icon=kedit +TerminalOptions= +Path= +DocPath=kedit/index.html +Type=Application +Terminal=0 +Name=KEdit +Name[af]=Kredigeer +Name[eo]=Redaktilo +Name[hr]=Uređivač +Name[lv]=KRediģēt +Name[pl]=Edytor +Name[sv]=Kedit +Name[th]=แก้ไขข้อความ +Name[ven]=U sengulusa ha K +Name[xh]=Abahleli Be K +Name[zh_TW]=KDE 編輯器 +X-KDE-StartupNotify=true +X-DCOP-ServiceType=Multi diff --git a/menu/tests/data/kwrite.desktop b/menu/tests/data/kwrite.desktop new file mode 100644 index 0000000..9804fa6 --- /dev/null +++ b/menu/tests/data/kwrite.desktop @@ -0,0 +1,84 @@ +[Desktop Entry] +Encoding=UTF-8 +GenericName=Text Editor +GenericName[af]=Teks Redigeerder +GenericName[ar]=محرر نصوص +GenericName[be]=Тэкставы рэдактар +GenericName[bg]=Текстов Редактор +GenericName[bs]=Tekst editor +GenericName[ca]=Editor de text +GenericName[cs]=Textový editor +GenericName[cy]=Golygydd Testun +GenericName[da]= Teksteditor +GenericName[de]=Texteditor +GenericName[el]=Διορθωτής Κειμένου +GenericName[eo]=Tekstredaktilo +GenericName[es]=Editor de texto +GenericName[et]=Tekstiredaktor +GenericName[eu]=Testu Editorea +GenericName[fa]=ویرایشگر متن +GenericName[fi]=Tekstieditori +GenericName[fo]=Tekstritil +GenericName[fr]=Éditeur de texte +GenericName[he]=עורך טקסט +GenericName[hr]=Uređivač teksta +GenericName[hu]=szövegszerkesztő +GenericName[is]=Textaritill +GenericName[it]=Editor di testi +GenericName[ja]=テキストエディタ +GenericName[ko]=글월 편집기 +GenericName[lo]=ເຄື່ອງມືແກ້ໄຂຂໍ້ຄວາມ +GenericName[lt]=Teksto redaktorius +GenericName[lv]=Teksta Redaktors +GenericName[mn]=Текст боловсруулагч +GenericName[mt]=Editur tat-test +GenericName[nb]=Skriveprogram +GenericName[nl]=teksteditor +GenericName[nn]=Skriveprogram +GenericName[nso]=Mofetosi wa Sengwalwana +GenericName[pl]=Edytor tekstowy +GenericName[pt]=Editor de Texto +GenericName[pt_BR]=Editor de Texto +GenericName[ro]=Editor de text +GenericName[ru]=Текстовый редактор +GenericName[sk]=Textový editor +GenericName[sl]=Urejevalnik besedil +GenericName[sr]=Editor teksta +GenericName[ss]=Sihleli sembhalo +GenericName[sv]=Texteditor +GenericName[ta]=¯¨Ã ¦¾¡ÌôÀ¡Ç÷ +GenericName[th]=เครื่องมือแก้ไขข้อความ +GenericName[tr]=Metin Düzenleyici +GenericName[uk]=Редактор текстів +GenericName[ven]=Musengulusi wa Manwalwa +GenericName[vi]=Trình soạn văn bản +GenericName[wa]=Aspougneu di tecse +GenericName[xh]=Umhleli Wombhalo +GenericName[zh_CN]=文本编辑器 +GenericName[zh_TW]=文字編輯器 +GenericName[zu]=Umlungisi wombhalo +BinaryPattern= +Name=KWrite +Name[af]=Kskryf +Name[ar]=كاتب كيدي +Name[eo]=Simpla kodredaktilo +Name[fa]=نوشتار K +Name[fo]=KSkriva +Name[lo]=Kwrite +Name[lv]=KRakstīt +Name[nso]=KNgwala +Name[ru]=Редактор KWrite +Name[sv]=Kwrite +Name[ven]=Nwala ha K +MimeType=text/plain;text/x-makefile;text/x-c++hdr;text/x-c++src;text/x-chdr;text/x-csrc;text/x-java;text/x-moc;text/x-pascal;text/x-tcl;text/x-tex;application/x-shellscript;text/x-c;text/x-c++;text/x-diff;text/rdf; +Exec=kwrite %u +X-KDE-StartupNotify=true +TerminalOptions= +Icon=kwrite +Path= +DocPath=kwrite/index.html +Type=Application +Terminal=0 +InitialPreference=8 +X-DCOP-ServiceType=Multi +Categories=Qt;KDE;TextEditor diff --git a/menu/tests/data/mahjongg-2.desktop b/menu/tests/data/mahjongg-2.desktop new file mode 100644 index 0000000..95cfe27 --- /dev/null +++ b/menu/tests/data/mahjongg-2.desktop @@ -0,0 +1,86 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Mahjongg +Name[am]=ማህጆንግ +Name[be]=Маджонг +Name[bg]=Махджонг +Name[bn]=মাহজং +Name[ca]=Mahjongg +Name[cs]=Mahjongg +Name[da]=Mahjongg +Name[de]=Mahjongg +Name[el]=Mahjongg +Name[es]=Mahjongg +Name[et]=Mahjongg +Name[fa]=ماهجونگ +Name[fi]=Mahjongg +Name[fr]=Mahjongg +Name[gl]=Mahjongg +Name[he]=Mahjongg +Name[hu]=Mahjongg +Name[it]=Mahjongg +Name[ja]=GNOME 上海 +Name[ko]=그놈 마작 +Name[lt]=Mahjongg +Name[lv]=Mahjongg +Name[mn]=Маджонг +Name[ms]=Mahjongg +Name[nl]=Mahjongg +Name[no]=Mahjongg +Name[pl]=Mahjongg +Name[pt]=Mahjongg +Name[pt_BR]=Mahjongg +Name[ru]=Маджонг +Name[sk]=Mahjongg +Name[sl]=Mahjongg +Name[sv]=Mah Jong +Name[tr]=Mahjongg +Name[uk]=Магджонґ +Name[vi]=Mahjongg +Name[wa]=Mahjongg +Name[zh_CN]=堆麻将 +Name[zh_TW]=上海麻將 +Comment=Mahjongg game +Comment[am]=የማህጆንግ ጨዋታ +Comment[be]=Гульня Маджонг +Comment[bg]=Игра на Махджонг +Comment[bn]=মাহজং খেলা +Comment[ca]=Joc del Mahjongg +Comment[cs]=Hra Mahjongg +Comment[da]=Mahjonggspil +Comment[de]=Mahjongg-Spiel +Comment[el]=Παιχνίδι Mahjongg +Comment[es]=Juego Mahjongg +Comment[et]=Mäng nimega mahjongg +Comment[fa]=بازی ماهجونگ +Comment[fi]=Mahjongg-peli +Comment[fr]=Jeu de Mahjongg +Comment[he]=משחק Mahjongg +Comment[hu]=Mahjongg játék +Comment[it]=Gioco Mahjongg +Comment[ja]=麻雀ゲーム +Comment[lv]=Mahjongg spēle +Comment[mn]=Mahjongg тоглоом +Comment[ms]=Permainan Mahjongg +Comment[nl]=Mahjongg +Comment[no]=Mahjongg-spill +Comment[pl]=Gra Mahjongg +Comment[pt]=Jogo Mahjongg +Comment[pt_BR]=Jogo Mahjongg +Comment[ru]=Игра Маджонг +Comment[sk]=Hra Mahjongg +Comment[sl]=Igra Mahjongg +Comment[sv]=Mah Jong-spel +Comment[tr]=Mahjongg oyunu +Comment[uk]=Гра "Магджонґ" +Comment[vi]=Trò chơi Mahjongg +Comment[zh_TW]=上海麻將遊戲 +Exec=mahjongg +Icon=gnome-mahjongg.png +Terminal=false +Type=Application +Categories=GNOME;Application;Development; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-games +X-GNOME-Bugzilla-Component=mahjongg +StartupNotify=true diff --git a/menu/tests/data/mahjongg.desktop b/menu/tests/data/mahjongg.desktop new file mode 100644 index 0000000..0d5f5de --- /dev/null +++ b/menu/tests/data/mahjongg.desktop @@ -0,0 +1,86 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Mahjongg +Name[am]=ማህጆንግ +Name[be]=Маджонг +Name[bg]=Махджонг +Name[bn]=মাহজং +Name[ca]=Mahjongg +Name[cs]=Mahjongg +Name[da]=Mahjongg +Name[de]=Mahjongg +Name[el]=Mahjongg +Name[es]=Mahjongg +Name[et]=Mahjongg +Name[fa]=ماهجونگ +Name[fi]=Mahjongg +Name[fr]=Mahjongg +Name[gl]=Mahjongg +Name[he]=Mahjongg +Name[hu]=Mahjongg +Name[it]=Mahjongg +Name[ja]=GNOME 上海 +Name[ko]=그놈 마작 +Name[lt]=Mahjongg +Name[lv]=Mahjongg +Name[mn]=Маджонг +Name[ms]=Mahjongg +Name[nl]=Mahjongg +Name[no]=Mahjongg +Name[pl]=Mahjongg +Name[pt]=Mahjongg +Name[pt_BR]=Mahjongg +Name[ru]=Маджонг +Name[sk]=Mahjongg +Name[sl]=Mahjongg +Name[sv]=Mah Jong +Name[tr]=Mahjongg +Name[uk]=Магджонґ +Name[vi]=Mahjongg +Name[wa]=Mahjongg +Name[zh_CN]=堆麻将 +Name[zh_TW]=上海麻將 +Comment=Mahjongg game +Comment[am]=የማህጆንግ ጨዋታ +Comment[be]=Гульня Маджонг +Comment[bg]=Игра на Махджонг +Comment[bn]=মাহজং খেলা +Comment[ca]=Joc del Mahjongg +Comment[cs]=Hra Mahjongg +Comment[da]=Mahjonggspil +Comment[de]=Mahjongg-Spiel +Comment[el]=Παιχνίδι Mahjongg +Comment[es]=Juego Mahjongg +Comment[et]=Mäng nimega mahjongg +Comment[fa]=بازی ماهجونگ +Comment[fi]=Mahjongg-peli +Comment[fr]=Jeu de Mahjongg +Comment[he]=משחק Mahjongg +Comment[hu]=Mahjongg játék +Comment[it]=Gioco Mahjongg +Comment[ja]=麻雀ゲーム +Comment[lv]=Mahjongg spēle +Comment[mn]=Mahjongg тоглоом +Comment[ms]=Permainan Mahjongg +Comment[nl]=Mahjongg +Comment[no]=Mahjongg-spill +Comment[pl]=Gra Mahjongg +Comment[pt]=Jogo Mahjongg +Comment[pt_BR]=Jogo Mahjongg +Comment[ru]=Игра Маджонг +Comment[sk]=Hra Mahjongg +Comment[sl]=Igra Mahjongg +Comment[sv]=Mah Jong-spel +Comment[tr]=Mahjongg oyunu +Comment[uk]=Гра "Магджонґ" +Comment[vi]=Trò chơi Mahjongg +Comment[zh_TW]=上海麻將遊戲 +Exec=mahjongg +Icon=gnome-mahjongg.png +Terminal=false +Type=Application +Categories=GNOME;Application;Game;BoardGame; +X-GNOME-Bugzilla-Bugzilla=GNOME +X-GNOME-Bugzilla-Product=gnome-games +X-GNOME-Bugzilla-Component=mahjongg +StartupNotify=true diff --git a/menu/tests/data/quanta.desktop b/menu/tests/data/quanta.desktop new file mode 100644 index 0000000..4b23aef --- /dev/null +++ b/menu/tests/data/quanta.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=Quanta Plus +Exec=quanta +Icon=quanta +Type=Application +MimeType=text/html +DocPath=quanta/index.html +Comment=Web Development Environment +Categories=Qt;KDE;Development diff --git a/menu/tests/expand b/menu/tests/expand new file mode 100755 index 0000000..5dbaac8 --- /dev/null +++ b/menu/tests/expand @@ -0,0 +1,12 @@ +#!/usr/bin/perl + +# This script performs expansion of environment variables of the form ${HOME} + +while(<>) +{ + while (($a) = ($_ =~ /[^\$]*\$\{([^\}]*)\}.*/)) + { + s/([^\$]*)(\$\{$a\})(.*)/$1$ENV{$a}$3/; + } + printf $_; +}
\ No newline at end of file diff --git a/menu/tests/menutest b/menu/tests/menutest new file mode 100755 index 0000000..9d37246 --- /dev/null +++ b/menu/tests/menutest @@ -0,0 +1,200 @@ +#!/bin/bash +# these vars are usable *only* for debugging purposes; they're not allowed as part of the spec, thus don't use them. +# set MENU_FAKE_PREFIX to a non empty val to force testing for if things would succeed if XDG_MENU_PREFIX were +# implemented +# set MENU_FAKE_APPLICATIONS to force a work around for applications-merged postfixing. +# +function installData() +{ + local DIR="$1" + shift + mkdir -p "${DIR}" + for file in $*; do + cp "data/${file}" "${DIR}" + WIPE[$WIPE_IDX]="${DIR}/${file}" + WIPE_IDX=$(( $WIPE_IDX + 1 )) + done +} + +function installDataAs() +{ + local DIR="$1" + mkdir -p "${DIR}" + cp "data/$2" "${DIR}/$3" + WIPE[${WIPE_IDX}]="${DIR}/${3}" + WIPE_IDX=$(( $WIPE_IDX + 1 )) +} + +setup_local_xdg_vars() { + export XDG_CONFIG_HOME="${MENUTESTDIR}/xdg_config_home" + export XDG_DATA_HOME="${MENUTESTDIR}/xdg_data_home" + export XDG_CONFIG_DIR="${MENUTESTDIR}/xdg_config_dir" + export XDG_CONFIG_DIRS="$XDG_CONFIG_DIR:${XDG_CONFIG_DIRS}2" + export XDG_DATA_DIR="${MENUTESTDIR}/xdg_data_dir" + export XDG_DATA_DIRS="$XDG_DATA_DIR:${XDG_DATA_DIR}2" + export XDG_CACHE_HOME="${MENUTESTDIR}/xdg_cache_home" +} + +setup_xdg_system_data_vars() +{ + export XDG_CACHE_HOME="${XDG_DATA_HOME:-${HOME}/.cache}" + export XDG_DATA_HOME="${XDG_DATA_HOME:-${HOME}/.local/share}" + export XDG_CONFIG_DIR="${XDG_CONFIG_DIR:-/etc/xdg}" + if [ -z "${XDG_DATA_DIRS}" ]; then + export XDG_DATA_DIRS="/usr/local/share:/usr/share" + fi + export XDG_DATA_DIRS="${XDG_DATA_DIRS}:${MENUTESTDIR}/xdg_cache_dir" + export XDG_DATA_DIR="${XDG_DATA_DIRS//*:}" + if [ -z "${XDG_CONFIG_DIRS}" ]; then + export XDG_CONFIG_DIRS="/etc/xdg" + fi + export XDG_CONFIG_DIR="${XDG_CONFIG_DIRS/:*}" +} + +run_test() { + if [ -z "$1" ]; then + echo "requires name of test directory to run" + exit 1 + fi + local TEST="$1" + rm -rf "${MENUTESTDIR}" 2> /dev/null + mkdir "${MENUTESTDIR}" + RESULT="${TEST}/result" + + ( + unset WIPE WIPE_IDX + declare -a WIPE + declare -i WIPE_IDX=0 + unset MODE + + . ${TEST}/test + echo ">>> Running test ${TEST}, purpose $TEST_PURPOSE" + + if [ "${MODE:-local}" == "local" ]; then + setup_local_xdg_vars + elif [ "${MODE}" == "system_data" ]; then + setup_xdg_system_data_vars + else + echo "!!! unknown MODE from $TEST, bailing" + exit -1 + fi + + test_code + + declare -i IDX=0 + while [ $WIPE_IDX -gt $IDX ]; do + echo "${WIPE[$IDX]}" >> "${MENUTESTDIR}/wipe" + IDX=$(( $IDX + 1 )) + done + + DEBUG_OVERRIDES='' + [ -n "$MENU_FAKE_PREFIX" ] && DEBUG_OVERRIDES=.menu + [ -n "$MENU_FAKE_APPLICATIONS" ] && DEBUG_OVERIDES="${DEBUG_OVERRIDES} -merged" + + for x in dir home; do + for y in ${DEBUG_OVERRIDES}; do + if [ -e "${MENUTESTDIR}/xdg_config_${x}/menus/applications${y}" ]; then + ln -s applications${y} "${MENUTESTDIR}/xdg_config_${x}/menus/kde-applications${y}" + ln -s applications${y} "${MENUTESTDIR}/xdg_config_${x}/menus/gnome-applications${y}" + fi + done + unset y + done + unset x DEBUG_OVERRIDES + + $MENUTEST > ${MENUTESTDIR}/run-result 2> ${MENUTESTDIR}/log + + if [ -e "${RESULT}" ]; then + ./expand "${RESULT}" > "${MENUTESTDIR}/required-result" + fi + + if [ "$(type -t interpret_results)" == "function" ]; then + interpret_results + else + default_interpret_results + fi + ret=$? + if [ -e "${MENUTESTDIR}/wipe" ]; then + cat "${MENUTESTDIR}/wipe" | while read l; do + [ -z "$l" ] && continue + rm "$l" + done + fi + return $ret + ) +} + +default_interpret_results() { + if [ ! -e "${RESULT}" ]; then + echo "!!! Result file (${RESULT}) for ${TEST} missing" + echo '>>> Failed' + return 1 + elif diff -q "${MENUTESTDIR}/run-result" "${MENUTESTDIR}/required-result" > /dev/null; then + echo '>>> OK' + return 0 + fi + sort "${MENUTESTDIR}/run-result" > "${MENUTESTDIR}/run-result.sorted" + sort "${MENUTESTDIR}/required-result" > "${MENUTESTDIR}/required-result.sorted" + if diff -u "${MENUTESTDIR}/run-result.sorted" "${MENUTESTDIR}/required-result.sorted" > "${MENUTESTDIR}/result.diff"; then + echo '>>> OK (different order)' + return 0 + fi + grep "${MENUTESTDIR}" "${MENUTESTDIR}/run-result" > "${MENUTESTDIR}/run-result.filtered" 2> /dev/null + if diff -q "${MENUTESTDIR}/run-result.filtered" "${MENUTESTDIR}/required-result" > /dev/null; then + echo '>>> OK (additional system items)' + return 0 + fi + grep "${MENUTESTDIR}" "${MENUTESTDIR}/run-result.sorted" > "${MENUTESTDIR}/required-result.filtered" 2> /dev/null + if diff -u "${MENUTESTDIR}/run-result.filtered" "${MENUTESTDIR}/required-result.sorted" > "${MENUTESTDIR}/result.diff"; then + echo '>>> OK (different order, additional system items)' + return 0 + fi + echo '>>> Failed' + cat "${MENUTESTDIR}/result.diff" + cat "${MENUTESTDIR}/log" + return 1 +} + +if [ -z "${TESTS}" ]; then + export TESTS=`ls tests/*/test | sed -e 's:^\(\./\)\?tests/\+::' -e 's:/\+test$::'` +fi + +if [ -z "$TET_RUN" ]; then + + if [ "x${MENUTEST}" == "x" ]; then + echo 'To run the test set $MENUTEST to your menu-spec implementation.' + exit 1 + fi + + if [ "x${MENUTESTDIR}" == "x" ]; then + MENUTESTDIR=/tmp/menutestdir + echo Using ${MENUTESTDIR} as test directory, override with \$MENUTESTDIR. + else + echo Using ${MENUTESTDIR} as test directory. + fi + + export MENUTESTDIR + export USER=${USER:-test} + + + FAILED= + SUCCEEDED= + + for TESTCASE in ${TESTS}; do + if [ "${TESTCASE}" == "CVS" ]; then + continue + fi + echo + if ! run_test "tests/${TESTCASE}" ${MODE}; then + FAILED="${FAILED} ${TESTCASE}" + else + SUCCEEDED="${SUCCEEDED} ${TESTCASE}" + fi + done + + echo "OK tests: ${SUCCEEDED}" + [ -n "${FAILED}" ] && echo "Failed tests: ${FAILED}" + echo "$(echo ${SUCCEEDED} | wc -w) tests passed, $(echo ${FAILED} | wc -w) tests failed" + [ -z "${FAILED}" ] && exit 0 + exit 1 +fi diff --git a/menu/tests/tests/All/result b/menu/tests/tests/All/result new file mode 100644 index 0000000..fc75a82 --- /dev/null +++ b/menu/tests/tests/All/result @@ -0,0 +1,4 @@ +Applications/ freecell.desktop ${XDG_DATA_DIR}/applications/freecell.desktop +Applications/ gataxx.desktop ${XDG_DATA_DIR}/applications/gataxx.desktop +Applications/ glines.desktop ${XDG_DATA_DIR}/applications/glines.desktop +Applications/ mahjongg.desktop ${XDG_DATA_DIR}/applications/mahjongg.desktop diff --git a/menu/tests/tests/All/test b/menu/tests/tests/All/test new file mode 100644 index 0000000..e97bddc --- /dev/null +++ b/menu/tests/tests/All/test @@ -0,0 +1,26 @@ +TEST_PURPOSE="<All> Keyword" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + + <Menu> + <Name>Applications</Name> + <Include> + <All/> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications gataxx.desktop mahjongg.desktop freecell.desktop glines.desktop +} diff --git a/menu/tests/tests/And/result b/menu/tests/tests/And/result new file mode 100644 index 0000000..dc159fa --- /dev/null +++ b/menu/tests/tests/And/result @@ -0,0 +1 @@ +Applications/ freecell.desktop ${XDG_DATA_DIR}/applications/freecell.desktop diff --git a/menu/tests/tests/And/test b/menu/tests/tests/And/test new file mode 100644 index 0000000..31571db --- /dev/null +++ b/menu/tests/tests/And/test @@ -0,0 +1,29 @@ +TEST_PURPOSE="<And> Keyword" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + + <Menu> + <Name>Applications</Name> + <Include> + <And> + <Filename>freecell.desktop</Filename> + <Category>Game</Category> + </And> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications gataxx.desktop mahjongg.desktop freecell.desktop glines.desktop +} diff --git a/menu/tests/tests/AppDir-relative/result b/menu/tests/tests/AppDir-relative/result new file mode 100644 index 0000000..9e1d622 --- /dev/null +++ b/menu/tests/tests/AppDir-relative/result @@ -0,0 +1,3 @@ +Applications/ KEdit.desktop ${XDG_CONFIG_DIR}/menus/apps/KEdit.desktop +Applications/ kate.desktop ${XDG_CONFIG_DIR}/menus/apps/kate.desktop +Applications/ kwrite.desktop ${XDG_CONFIG_DIR}/menus/apps/kwrite.desktop diff --git a/menu/tests/tests/AppDir-relative/test b/menu/tests/tests/AppDir-relative/test new file mode 100644 index 0000000..75bd201 --- /dev/null +++ b/menu/tests/tests/AppDir-relative/test @@ -0,0 +1,27 @@ +TEST_PURPOSE="<AppDir> relative path tag ..." + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <AppDir>apps</AppDir> + + <Menu> + <Name>Applications</Name> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData "${XDG_CONFIG_DIR}/menus/apps" kwrite.desktop KEdit.desktop quanta.desktop kate.desktop kbabel.desktop + installDataAs "${XDG_CONFIG_DIR}/menus/apps" kwrite.desktop should_be_ignored.notdesktop +} diff --git a/menu/tests/tests/AppDir/test b/menu/tests/tests/AppDir/test new file mode 100644 index 0000000..8faff91 --- /dev/null +++ b/menu/tests/tests/AppDir/test @@ -0,0 +1,4 @@ +. tests/AppDir-relative/test +export PATH_EXPANSION='${XDG_CONFIG_DIR}/menus/' +TEST_PURPOSE="<AppDir> absolute path" + diff --git a/menu/tests/tests/Category/result b/menu/tests/tests/Category/result new file mode 100644 index 0000000..73b00c9 --- /dev/null +++ b/menu/tests/tests/Category/result @@ -0,0 +1,3 @@ +Editors/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Editors/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Editors/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop diff --git a/menu/tests/tests/Category/test b/menu/tests/tests/Category/test new file mode 100644 index 0000000..3ee0777 --- /dev/null +++ b/menu/tests/tests/Category/test @@ -0,0 +1,29 @@ +TEST_PURPOSE="<Category> tag" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + + <Menu> + <Name>Editors</Name> + <Include> + <Category>TextEditor</Category> + <!-- note it's lowercase, this is intentional to verify + it's a case sensitive implementation --> + <Category>application</Category> + </Include> + </Menu> +</Menu> +EOF + +# Install .desktop files, freecell is daft but intentional to verify category support is case sensitive +installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop kate.desktop freecell.desktop +} diff --git a/menu/tests/tests/DefaultMergeDirs/result b/menu/tests/tests/DefaultMergeDirs/result new file mode 100644 index 0000000..9e17189 --- /dev/null +++ b/menu/tests/tests/DefaultMergeDirs/result @@ -0,0 +1,5 @@ +Applications/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Applications/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Applications/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop +Development/ kbabel.desktop ${XDG_DATA_DIR}/applications/kbabel.desktop +Development/ quanta.desktop ${XDG_DATA_DIR}/applications/quanta.desktop diff --git a/menu/tests/tests/DefaultMergeDirs/test b/menu/tests/tests/DefaultMergeDirs/test new file mode 100644 index 0000000..3b570f2 --- /dev/null +++ b/menu/tests/tests/DefaultMergeDirs/test @@ -0,0 +1,43 @@ +TEST_PURPOSE="<DefaultMergeDirs> tag ..." + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <DefaultAppDirs/> + <DefaultMergeDirs/> + + <Menu> + <Name>Applications</Name> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> +</Menu> +EOF + + mkdir ${XDG_CONFIG_DIR}/menus/applications-merged/ + ./expand > ${XDG_CONFIG_DIR}/menus/applications-merged/test.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <Menu> + <Name>Development</Name> + <Include> + <Category>Development</Category> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop quanta.desktop kate.desktop kbabel.desktop +} diff --git a/menu/tests/tests/Deleted/result b/menu/tests/tests/Deleted/result new file mode 100644 index 0000000..c121419 --- /dev/null +++ b/menu/tests/tests/Deleted/result @@ -0,0 +1,2 @@ +BoardGames/ gataxx.desktop ${XDG_DATA_DIR}/applications/gataxx.desktop +BoardGames/ mahjongg.desktop ${XDG_DATA_DIR}/applications/mahjongg.desktop diff --git a/menu/tests/tests/Deleted/test b/menu/tests/tests/Deleted/test new file mode 100644 index 0000000..db7a413 --- /dev/null +++ b/menu/tests/tests/Deleted/test @@ -0,0 +1,35 @@ +TEST_PURPOSE="<Deleted> tag" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + + <Menu> + <Name>BoardGames</Name> + <Include> + <Category>BoardGame</Category> + </Include> + </Menu> + <Menu> + <Name>Games</Name> + <Include> + <Category>Game</Category> + </Include> + <Deleted/> + <NotDeleted/> + <Deleted/> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications gataxx.desktop mahjongg.desktop freecell.desktop glines.desktop +} diff --git a/menu/tests/tests/DesktopFileID/result b/menu/tests/tests/DesktopFileID/result new file mode 100644 index 0000000..9629384 --- /dev/null +++ b/menu/tests/tests/DesktopFileID/result @@ -0,0 +1,4 @@ +Applications/ company-games-freecell.desktop ${XDG_DATA_DIR}/applications/company/games/freecell.desktop +Applications/ company-games-gataxx.desktop ${XDG_DATA_DIR}/applications/company/games/gataxx.desktop +Applications/ company-games-glines.desktop ${XDG_DATA_DIR}/applications/company/games/glines.desktop +Applications/ company-games-mahjongg.desktop ${XDG_DATA_DIR}/applications/company/games/mahjongg.desktop diff --git a/menu/tests/tests/DesktopFileID/test b/menu/tests/tests/DesktopFileID/test new file mode 100644 index 0000000..ae2c679 --- /dev/null +++ b/menu/tests/tests/DesktopFileID/test @@ -0,0 +1,26 @@ +TEST_PURPOSE="DesktopFileIDs in submenus" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + + <Menu> + <Name>Applications</Name> + <Include> + <Category>Game</Category> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications/company/games gataxx.desktop mahjongg.desktop freecell.desktop glines.desktop +} diff --git a/menu/tests/tests/Directory/result b/menu/tests/tests/Directory/result new file mode 100644 index 0000000..2cd1d1f --- /dev/null +++ b/menu/tests/tests/Directory/result @@ -0,0 +1,3 @@ +Apps/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Apps/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Apps/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop diff --git a/menu/tests/tests/Directory/test b/menu/tests/tests/Directory/test new file mode 100644 index 0000000..fe7e126 --- /dev/null +++ b/menu/tests/tests/Directory/test @@ -0,0 +1,29 @@ +TEST_PURPOSE="<Directory> tag ..." + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + <DefaultDirectoryDirs/> + + <Menu> + <Name>Applications</Name> + <Directory>apps.directory</Directory> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop quanta.desktop kate.desktop kbabel.desktop + installData ${XDG_DATA_DIR}/desktop-directories apps.directory +} diff --git a/menu/tests/tests/DirectoryDir-relative/result b/menu/tests/tests/DirectoryDir-relative/result new file mode 100644 index 0000000..2cd1d1f --- /dev/null +++ b/menu/tests/tests/DirectoryDir-relative/result @@ -0,0 +1,3 @@ +Apps/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Apps/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Apps/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop diff --git a/menu/tests/tests/DirectoryDir-relative/test b/menu/tests/tests/DirectoryDir-relative/test new file mode 100644 index 0000000..4a5e039 --- /dev/null +++ b/menu/tests/tests/DirectoryDir-relative/test @@ -0,0 +1,28 @@ +TEST_PURPOSE="relative <DirectoryDir> tag ..." + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + <DirectoryDir>${PATH_EXPANSION}desktop-directories</DirectoryDir> + + <Menu> + <Name>Applications</Name> + <Directory>apps.directory</Directory> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> +</Menu> +EOF + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop quanta.desktop kate.desktop kbabel.desktop + installData ${XDG_CONFIG_DIR}/menus/desktop-directories apps.directory +} diff --git a/menu/tests/tests/DirectoryDir/test b/menu/tests/tests/DirectoryDir/test new file mode 100644 index 0000000..dc8bb3b --- /dev/null +++ b/menu/tests/tests/DirectoryDir/test @@ -0,0 +1,4 @@ +. tests/DirectoryDir-relative/test +export PATH_EXPANSION='${XDG_CONFIG_DIR}/menus/' +TEST_PURPOSE="<DirectoryDir> absolute path" + diff --git a/menu/tests/tests/Exclude/result b/menu/tests/tests/Exclude/result new file mode 100644 index 0000000..dfbb122 --- /dev/null +++ b/menu/tests/tests/Exclude/result @@ -0,0 +1,3 @@ +Applications/ freecell.desktop ${XDG_DATA_DIR}/applications/freecell.desktop +Applications/ gataxx.desktop ${XDG_DATA_DIR}/applications/gataxx.desktop +Applications/ mahjongg.desktop ${XDG_DATA_DIR}/applications/mahjongg.desktop diff --git a/menu/tests/tests/Exclude/test b/menu/tests/tests/Exclude/test new file mode 100644 index 0000000..728ec99 --- /dev/null +++ b/menu/tests/tests/Exclude/test @@ -0,0 +1,32 @@ +TEST_PURPOSE="<Exclude> Keyword" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + + <Menu> + <Name>Applications</Name> + <Include> + <Or> + <Filename>freecell.desktop</Filename> + <Category>Game</Category> + </Or> + </Include> + <Exclude> + <Filename>glines.desktop</Filename> + </Exclude> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications gataxx.desktop mahjongg.desktop freecell.desktop glines.desktop +} diff --git a/menu/tests/tests/Filename/result b/menu/tests/tests/Filename/result new file mode 100644 index 0000000..dc159fa --- /dev/null +++ b/menu/tests/tests/Filename/result @@ -0,0 +1 @@ +Applications/ freecell.desktop ${XDG_DATA_DIR}/applications/freecell.desktop diff --git a/menu/tests/tests/Filename/test b/menu/tests/tests/Filename/test new file mode 100644 index 0000000..b9d021d --- /dev/null +++ b/menu/tests/tests/Filename/test @@ -0,0 +1,26 @@ +TEST_PURPOSE="<Filename> tag" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + + <Menu> + <Name>Applications</Name> + <Include> + <Filename>freecell.desktop</Filename> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications gataxx.desktop mahjongg.desktop freecell.desktop glines.desktop +} diff --git a/menu/tests/tests/LegacyDir-Move/result b/menu/tests/tests/LegacyDir-Move/result new file mode 100644 index 0000000..9a2b9db --- /dev/null +++ b/menu/tests/tests/LegacyDir-Move/result @@ -0,0 +1,2 @@ +Editors/ gideon-legacy.desktop ${LEGACY_DIR}/Development/gideon-legacy.desktop +/ Home.desktop ${LEGACY_DIR}/Home.desktop diff --git a/menu/tests/tests/LegacyDir-Move/test b/menu/tests/tests/LegacyDir-Move/test new file mode 100644 index 0000000..7e6e85e --- /dev/null +++ b/menu/tests/tests/LegacyDir-Move/test @@ -0,0 +1,39 @@ +TEST_PURPOSE="move entries from <LegacyDir>" + +test_code() { + LEGACY_DIR=${MENUTESTDIR}/legacy_applnk + export LEGACY_DIR + + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <LegacyDir>${LEGACY_DIR}</LegacyDir> + <DefaultAppDirs/> + <DefaultDirectoryDirs/> + + <Menu> + <Name>Development</Name> + <Exclude> + <Filename>gideon-legacy.desktop</Filename> + </Exclude> + </Menu> + <Menu> + <Name>Editors</Name> + <Include> + <Filename>gideon-legacy.desktop</Filename> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + + installData ${LEGACY_DIR} Home.desktop + installData ${LEGACY_DIR}/Development gideon-legacy.desktop +} diff --git a/menu/tests/tests/LegacyDir-relative/result b/menu/tests/tests/LegacyDir-relative/result new file mode 100644 index 0000000..0c2af9b --- /dev/null +++ b/menu/tests/tests/LegacyDir-relative/result @@ -0,0 +1,9 @@ +Development/ gideon-legacy.desktop ${LEGACY_DIR}/Development/gideon-legacy.desktop +Development/ kbabel.desktop ${LEGACY_DIR}/Development/kbabel.desktop +Development/ quanta.desktop ${LEGACY_DIR}/Development/quanta.desktop +Editors/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Editors/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Editors/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop +/ Help.desktop ${LEGACY_DIR}/Help.desktop +/ Home.desktop ${LEGACY_DIR}/Home.desktop +/ Kfind.desktop ${LEGACY_DIR}/Kfind.desktop diff --git a/menu/tests/tests/LegacyDir-relative/test b/menu/tests/tests/LegacyDir-relative/test new file mode 100644 index 0000000..5082590 --- /dev/null +++ b/menu/tests/tests/LegacyDir-relative/test @@ -0,0 +1,42 @@ +TEST_PURPOSE="Simple <LegacyDir> test" + +test_code() { + LEGACY_DIR=${MENUTESTDIR}/legacy_applnk + export LEGACY_DIR + + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <LegacyDir>${LEGACY_DIR}</LegacyDir> + <DefaultAppDirs/> + <DefaultDirectoryDirs/> + + <Menu> + <Name>Editors</Name> + <Directory>kde-editors.directory</Directory> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> + <Menu> + <Name>Development</Name> + <Directory>kde-development.directory</Directory> + <Include> + <Category>Development</Category> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop kate.desktop + installData ${LEGACY_DIR}/Development gideon-legacy.desktop kbabel.desktop quanta.desktop + installData ${LEGACY_DIR} Kfind.desktop Home.desktop Help.desktop +} + diff --git a/menu/tests/tests/Merge-combined/result b/menu/tests/tests/Merge-combined/result new file mode 100644 index 0000000..999bd1e --- /dev/null +++ b/menu/tests/tests/Merge-combined/result @@ -0,0 +1 @@ +Editors/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop diff --git a/menu/tests/tests/Merge-combined/test b/menu/tests/tests/Merge-combined/test new file mode 100644 index 0000000..07cfab3 --- /dev/null +++ b/menu/tests/tests/Merge-combined/test @@ -0,0 +1,46 @@ +TEST_PURPOSE="Merge Two Menus and a Legacy Menu" + +test_code() { + LEGACY_DIR=${MENUTESTDIR}/legacy_applnk + export LEGACY_DIR + + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + <DefaultDirectoryDirs/> + <LegacyDir>${LEGACY_DIR}</LegacyDir> + + <Menu> + <Name>Development</Name> + <Include> + <Filename>kate.desktop</Filename> + </Include> + </Menu> + <Menu> + <Name>Development</Name> + <Include> + <Filename>KEdit.desktop</Filename> + </Include> + <Deleted/> + </Menu> + <Menu> + <Name>Editors</Name> + <Include> + <Filename>kwrite.desktop</Filename> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + + installData ${LEGACY_DIR}/Development gideon-legacy.desktop + installData ${XDG_DATA_DIR}/applications kate.desktop kwrite.desktop KEdit.desktop +} diff --git a/menu/tests/tests/MergeDir-absolute/test b/menu/tests/tests/MergeDir-absolute/test new file mode 100644 index 0000000..db6c895 --- /dev/null +++ b/menu/tests/tests/MergeDir-absolute/test @@ -0,0 +1,3 @@ +. tests/MergeDir-relative/test +export PATH_EXPANSION='${XDG_CONFIG_DIR}/menus/' +export TEST_PURPOSE="<MergeDir> absolute path test" diff --git a/menu/tests/tests/MergeDir-relative/result b/menu/tests/tests/MergeDir-relative/result new file mode 100644 index 0000000..9e17189 --- /dev/null +++ b/menu/tests/tests/MergeDir-relative/result @@ -0,0 +1,5 @@ +Applications/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Applications/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Applications/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop +Development/ kbabel.desktop ${XDG_DATA_DIR}/applications/kbabel.desktop +Development/ quanta.desktop ${XDG_DATA_DIR}/applications/quanta.desktop diff --git a/menu/tests/tests/MergeDir-relative/test b/menu/tests/tests/MergeDir-relative/test new file mode 100644 index 0000000..ba96b1a --- /dev/null +++ b/menu/tests/tests/MergeDir-relative/test @@ -0,0 +1,61 @@ +TEST_PURPOSE="<MergeDir> relative path ..." + +test_code() { + # Generate applications.menu + mkdir -p "${XDG_CONFIG_DIR}/menus" + ./expand > "${XDG_CONFIG_DIR}/menus/applications.menu" <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <DefaultAppDirs/> + <MergeDir>${PATH_EXPANSION}applications-merged</MergeDir> + + <Menu> + <Name>Applications</Name> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> +</Menu> +EOF + + mkdir "${XDG_CONFIG_DIR}/menus/applications-merged/" + ./expand > "${XDG_CONFIG_DIR}/menus/applications-merged/test.menu" <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <Menu> + <Name>Development</Name> + <Include> + <Category>Development</Category> + </Include> + </Menu> +</Menu> +EOF + + # intentional crap entry to verify it does _not_ get picked up + ./expand > "${XDG_CONFIG_DIR}/menus/applications-merged/dar.notmenu" <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <Menu> + <Name>testing</Name> + <Include> + <All/> + </Include> + </Menu> +</Menu> +EOF + + + # Install .desktop files + installData "${XDG_DATA_DIR}/applications" kwrite.desktop KEdit.desktop quanta.desktop kate.desktop kbabel.desktop +} diff --git a/menu/tests/tests/MergeFile-absolute/test b/menu/tests/tests/MergeFile-absolute/test new file mode 100644 index 0000000..24cf669 --- /dev/null +++ b/menu/tests/tests/MergeFile-absolute/test @@ -0,0 +1,3 @@ +. tests/MergeFile-relative/test +export PATH_EXPANSION='${XDG_CONFIG_DIR}/menus/' +export TEST_PURPOSE="<MergeFile> absolute path" diff --git a/menu/tests/tests/MergeFile-parent/result b/menu/tests/tests/MergeFile-parent/result new file mode 100644 index 0000000..9e17189 --- /dev/null +++ b/menu/tests/tests/MergeFile-parent/result @@ -0,0 +1,5 @@ +Applications/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Applications/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Applications/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop +Development/ kbabel.desktop ${XDG_DATA_DIR}/applications/kbabel.desktop +Development/ quanta.desktop ${XDG_DATA_DIR}/applications/quanta.desktop diff --git a/menu/tests/tests/MergeFile-parent/test b/menu/tests/tests/MergeFile-parent/test new file mode 100644 index 0000000..00ed006 --- /dev/null +++ b/menu/tests/tests/MergeFile-parent/test @@ -0,0 +1,61 @@ +TEST_PURPOSE="<MergeFile> tag ..." + +test_code() { + # Tests the type attribute in <MergeFile> + + # Generate applications.menu + mkdir -p ${XDG_CONFIG_HOME}/menus + ./expand > ${XDG_CONFIG_HOME}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <DefaultAppDirs/> + <MergeFile type="parent">${XDG_CONFIG_DIR}/menus/test.menu</MergeFile> + + <Menu> + <Name>Applications</Name> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> +</Menu> +EOF + + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/test.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <Menu> + <Name>Games</Name> + <Include> + <Category>Game</Category> + </Include> + </Menu> +</Menu> +EOF + + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <Menu> + <Name>Development</Name> + <Include> + <Category>Development</Category> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop quanta.desktop kate.desktop kbabel.desktop freecell.desktop glines.desktop +} diff --git a/menu/tests/tests/MergeFile-path/result b/menu/tests/tests/MergeFile-path/result new file mode 100644 index 0000000..fbe635e --- /dev/null +++ b/menu/tests/tests/MergeFile-path/result @@ -0,0 +1,5 @@ +Applications/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Applications/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Applications/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop +Games/ freecell.desktop ${XDG_DATA_DIR}/applications/freecell.desktop +Games/ glines.desktop ${XDG_DATA_DIR}/applications/glines.desktop diff --git a/menu/tests/tests/MergeFile-path/test b/menu/tests/tests/MergeFile-path/test new file mode 100644 index 0000000..97daa5c --- /dev/null +++ b/menu/tests/tests/MergeFile-path/test @@ -0,0 +1,61 @@ +TEST_PURPOSE="<MergeFile> tag ..." + +test_code() { + # Tests the type attribute in <MergeFile> + + # Generate applications.menu + mkdir -p ${XDG_CONFIG_HOME}/menus + ./expand > ${XDG_CONFIG_HOME}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <DefaultAppDirs/> + <MergeFile type="path">${XDG_CONFIG_DIR}/menus/test.menu</MergeFile> + + <Menu> + <Name>Applications</Name> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> +</Menu> +EOF + + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/test.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <Menu> + <Name>Games</Name> + <Include> + <Category>Game</Category> + </Include> + </Menu> +</Menu> +EOF + + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <Menu> + <Name>Development</Name> + <Include> + <Category>Development</Category> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop quanta.desktop kate.desktop kbabel.desktop freecell.desktop glines.desktop +} diff --git a/menu/tests/tests/MergeFile-recursive/result b/menu/tests/tests/MergeFile-recursive/result new file mode 100644 index 0000000..9e17189 --- /dev/null +++ b/menu/tests/tests/MergeFile-recursive/result @@ -0,0 +1,5 @@ +Applications/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Applications/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Applications/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop +Development/ kbabel.desktop ${XDG_DATA_DIR}/applications/kbabel.desktop +Development/ quanta.desktop ${XDG_DATA_DIR}/applications/quanta.desktop diff --git a/menu/tests/tests/MergeFile-recursive/test b/menu/tests/tests/MergeFile-recursive/test new file mode 100644 index 0000000..4dbab21 --- /dev/null +++ b/menu/tests/tests/MergeFile-recursive/test @@ -0,0 +1,58 @@ +TEST_PURPOSE="test elaborate recursive look in <MergeFile>s" + +test_code(){ + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <DefaultAppDirs/> + <MergeFile>applications-merged/test.menu</MergeFile> + + <Menu> + <Name>Applications</Name> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> +</Menu> +EOF + + + mkdir ${XDG_CONFIG_DIR}/menus/applications-merged/ + ./expand > ${XDG_CONFIG_DIR}/menus/applications-merged/test.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <MergeFile>extra/test.menu</MergeFile> +</Menu> +EOF + + mkdir ${XDG_CONFIG_DIR}/menus/applications-merged/extra/ + ./expand > ${XDG_CONFIG_DIR}/menus/applications-merged/extra/test.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <Menu> + <Name>Development</Name> + <Include> + <Category>Development</Category> + </Include> + </Menu> + + <MergeFile>../test.menu</MergeFile> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop quanta.desktop kate.desktop kbabel.desktop +} diff --git a/menu/tests/tests/MergeFile-relative/result b/menu/tests/tests/MergeFile-relative/result new file mode 100644 index 0000000..9e17189 --- /dev/null +++ b/menu/tests/tests/MergeFile-relative/result @@ -0,0 +1,5 @@ +Applications/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Applications/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Applications/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop +Development/ kbabel.desktop ${XDG_DATA_DIR}/applications/kbabel.desktop +Development/ quanta.desktop ${XDG_DATA_DIR}/applications/quanta.desktop diff --git a/menu/tests/tests/MergeFile-relative/test b/menu/tests/tests/MergeFile-relative/test new file mode 100644 index 0000000..c3478db --- /dev/null +++ b/menu/tests/tests/MergeFile-relative/test @@ -0,0 +1,44 @@ +TEST_PURPOSE="<MergeFile> tag relative path" + +test_code(){ + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <DefaultAppDirs/> + <MergeFile>${PATH_EXPANSION}applications-merged/test.menu</MergeFile> + + <Menu> + <Name>Applications</Name> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> +</Menu> +EOF + + mkdir ${XDG_CONFIG_DIR}/menus/applications-merged/ + ./expand > ${XDG_CONFIG_DIR}/menus/applications-merged/test.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> +<!-- test --> + +<Menu> + <Name>KDE</Name> + + <Menu> + <Name>Development</Name> + <Include> + <Category>Development</Category> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop quanta.desktop kate.desktop kbabel.desktop +} diff --git a/menu/tests/tests/MergeFile2/result b/menu/tests/tests/MergeFile2/result new file mode 100644 index 0000000..9e17189 --- /dev/null +++ b/menu/tests/tests/MergeFile2/result @@ -0,0 +1,5 @@ +Applications/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Applications/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Applications/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop +Development/ kbabel.desktop ${XDG_DATA_DIR}/applications/kbabel.desktop +Development/ quanta.desktop ${XDG_DATA_DIR}/applications/quanta.desktop diff --git a/menu/tests/tests/MergeFile2/test b/menu/tests/tests/MergeFile2/test new file mode 100644 index 0000000..e5b1591 --- /dev/null +++ b/menu/tests/tests/MergeFile2/test @@ -0,0 +1,57 @@ +TEST_PURPOSE="<MergeFile> tag ..." + +test_code() { + # Tests the use of relative paths in <MergeFile> + + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <DefaultAppDirs/> + <MergeFile>applications-merged/test.menu</MergeFile> + + <Menu> + <Name>Applications</Name> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> +</Menu> +EOF + + mkdir ${XDG_CONFIG_DIR}/menus/applications-merged/ + ./expand > ${XDG_CONFIG_DIR}/menus/applications-merged/test.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <MergeFile>extra/test.menu</MergeFile> +</Menu> +EOF + + mkdir ${XDG_CONFIG_DIR}/menus/applications-merged/extra/ + ./expand > ${XDG_CONFIG_DIR}/menus/applications-merged/extra/test.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <Menu> + <Name>Development</Name> + <Include> + <Category>Development</Category> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop quanta.desktop kate.desktop kbabel.desktop +} diff --git a/menu/tests/tests/MergeFile3/result b/menu/tests/tests/MergeFile3/result new file mode 100644 index 0000000..9e17189 --- /dev/null +++ b/menu/tests/tests/MergeFile3/result @@ -0,0 +1,5 @@ +Applications/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Applications/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Applications/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop +Development/ kbabel.desktop ${XDG_DATA_DIR}/applications/kbabel.desktop +Development/ quanta.desktop ${XDG_DATA_DIR}/applications/quanta.desktop diff --git a/menu/tests/tests/MergeFile3/test b/menu/tests/tests/MergeFile3/test new file mode 100644 index 0000000..8781888 --- /dev/null +++ b/menu/tests/tests/MergeFile3/test @@ -0,0 +1,56 @@ +TEST_PURPOSE="<MergeFile> tag ..." + +test_code() { + # Tests the use of relative paths in <MergeFile> + + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <DefaultAppDirs/> + <MergeFile>test.menu</MergeFile> + + <Menu> + <Name>Applications</Name> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> +</Menu> +EOF + + ./expand > ${XDG_CONFIG_DIR}/menus/test.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <MergeFile>extra/test.menu</MergeFile> +</Menu> +EOF + + mkdir ${XDG_CONFIG_DIR}/menus/extra/ + ./expand > ${XDG_CONFIG_DIR}/menus/extra/test.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <Menu> + <Name>Development</Name> + <Include> + <Category>Development</Category> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop quanta.desktop kate.desktop kbabel.desktop +} diff --git a/menu/tests/tests/Move-collapsing/result b/menu/tests/tests/Move-collapsing/result new file mode 100644 index 0000000..10ccec6 --- /dev/null +++ b/menu/tests/tests/Move-collapsing/result @@ -0,0 +1,4 @@ +Games/BoardGame/ gataxx.desktop ${XDG_DATA_DIR}/applications/gataxx.desktop +Games/BoardGame/ mahjongg.desktop ${XDG_DATA_DIR}/applications/mahjongg.desktop +Games/ freecell.desktop ${XDG_DATA_DIR}/applications/freecell.desktop +Games/ glines.desktop ${XDG_DATA_DIR}/applications/glines.desktop diff --git a/menu/tests/tests/Move-collapsing/test b/menu/tests/tests/Move-collapsing/test new file mode 100644 index 0000000..b842b0a --- /dev/null +++ b/menu/tests/tests/Move-collapsing/test @@ -0,0 +1,40 @@ +TEST_PURPOSE="complicated <Move> operation" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + <Move> + <Old>Games1</Old> + <New>Games</New> + </Move> + + <Menu> + <Name>Games1</Name> + <Menu> + <Name>BoardGame</Name> + <Include> + <Category>BoardGame</Category> + </Include> + </Menu> + </Menu> + <Menu> + <Name>Games</Name> + <Include> + <Category>Game</Category> + </Include> + <OnlyUnallocated/> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications gataxx.desktop mahjongg.desktop freecell.desktop glines.desktop +} diff --git a/menu/tests/tests/Move-ordering/result b/menu/tests/tests/Move-ordering/result new file mode 100644 index 0000000..b941f58 --- /dev/null +++ b/menu/tests/tests/Move-ordering/result @@ -0,0 +1,3 @@ +Development/ gideon.desktop ${XDG_DATA_DIR}/applications/gideon.desktop +Games-Correct/ freecell.desktop ${XDG_DATA_DIR}/applications/freecell.desktop +Games-Correct/ glines.desktop ${XDG_DATA_DIR}/applications/glines.desktop diff --git a/menu/tests/tests/Move-ordering/test b/menu/tests/tests/Move-ordering/test new file mode 100644 index 0000000..f8883b9 --- /dev/null +++ b/menu/tests/tests/Move-ordering/test @@ -0,0 +1,49 @@ +TEST_PURPOSE="Order of <Move> operations ..." + +test_code() { + # Tests the type attribute in <MergeFile> + + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <DefaultAppDirs/> + <Menu> + <Name>Development</Name> + <Menu> + <Name>Games</Name> + <Include> + <Category>Game</Category> + </Include> + </Menu> + <Include> + <Category>Development</Category> + </Include> + </Menu> + <Move> + <Old>Development/Games-New</Old> + <New>Games-Correct</New> + </Move> + <Move> + <Old>Development/Games</Old> + <New>Games-Wrong</New> + </Move> + <Menu> + <Name>Development</Name> + <Move> + <Old>Games</Old> + <New>Games-New</New> + </Move> + </Menu> +</Menu> +EOF + + # Move operations in sub-menus should be performed first + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications freecell.desktop glines.desktop gideon.desktop +} diff --git a/menu/tests/tests/Move-submenu/result b/menu/tests/tests/Move-submenu/result new file mode 100644 index 0000000..f1c44ef --- /dev/null +++ b/menu/tests/tests/Move-submenu/result @@ -0,0 +1 @@ +A/B/Development/ gideon-legacy.desktop ${XDG_DATA_DIR}/applications/gideon-legacy.desktop diff --git a/menu/tests/tests/Move-submenu/test b/menu/tests/tests/Move-submenu/test new file mode 100644 index 0000000..2751983 --- /dev/null +++ b/menu/tests/tests/Move-submenu/test @@ -0,0 +1,32 @@ +TEST_PURPOSE="Move into a new Submenu" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + <DefaultDirectoryDirs/> + + <Menu> + <Name>Development</Name> + <Include> + <Filename>gideon-legacy.desktop</Filename> + </Include> + </Menu> + <Move> + <Old>Development</Old> + <New>A/B/Development</New> + </Move> +</Menu> +EOF + + # Install .desktop files + + installData ${XDG_DATA_DIR}/applications gideon-legacy.desktop +} diff --git a/menu/tests/tests/Move/result b/menu/tests/tests/Move/result new file mode 100644 index 0000000..d9a802d --- /dev/null +++ b/menu/tests/tests/Move/result @@ -0,0 +1,2 @@ +Games/ gataxx.desktop ${XDG_DATA_DIR}/applications/gataxx.desktop +Games/ mahjongg.desktop ${XDG_DATA_DIR}/applications/mahjongg.desktop diff --git a/menu/tests/tests/Move/test b/menu/tests/tests/Move/test new file mode 100644 index 0000000..9f2d162 --- /dev/null +++ b/menu/tests/tests/Move/test @@ -0,0 +1,34 @@ +TEST_PURPOSE="simple <Move> operation" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + <Move> + <Old>Foo</Old> + <New>Bar</New> + <Old>BoardGames</Old> + <New>Apps</New> + <Old>BoardGames</Old> + <New>Games</New> + </Move> + + <Menu> + <Name>BoardGames</Name> + <Include> + <Category>BoardGame</Category> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications gataxx.desktop mahjongg.desktop freecell.desktop glines.desktop +} diff --git a/menu/tests/tests/NoDisplay/result b/menu/tests/tests/NoDisplay/result new file mode 100644 index 0000000..7ed7169 --- /dev/null +++ b/menu/tests/tests/NoDisplay/result @@ -0,0 +1 @@ +Other/ freecell.desktop ${XDG_DATA_DIR}/applications/freecell.desktop diff --git a/menu/tests/tests/NoDisplay/test b/menu/tests/tests/NoDisplay/test new file mode 100644 index 0000000..48e94ea --- /dev/null +++ b/menu/tests/tests/NoDisplay/test @@ -0,0 +1,37 @@ +TEST_PURPOSE="NoDisplay desktop entry values" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <DefaultAppDirs/> + <DefaultDirectoryDirs/> + + <Menu> + <Name>Shouldn't see this</Name> + <Directory>hidden.directory</Directory> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> + + <Menu> + <Name>Other</Name> + <OnlyUnallocated/> + <Include> + <All/> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop kate.desktop freecell.desktop hidden.desktop + installData ${XDG_DATA_DIR}/desktop-directories hidden.directory +} diff --git a/menu/tests/tests/NoDisplay2/result b/menu/tests/tests/NoDisplay2/result new file mode 100644 index 0000000..7ed7169 --- /dev/null +++ b/menu/tests/tests/NoDisplay2/result @@ -0,0 +1 @@ +Other/ freecell.desktop ${XDG_DATA_DIR}/applications/freecell.desktop diff --git a/menu/tests/tests/NoDisplay2/test b/menu/tests/tests/NoDisplay2/test new file mode 100644 index 0000000..62ba5a7 --- /dev/null +++ b/menu/tests/tests/NoDisplay2/test @@ -0,0 +1,38 @@ +TEST_PURPOSE="Allocation of desktop entry values from deleted menus" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus +./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <DefaultAppDirs/> + <DefaultDirectoryDirs/> + + <Menu> + <Name>Shouldn't see this</Name> + <Directory>apps.directory</Directory> + <Include> + <Category>TextEditor</Category> + </Include> + <Deleted/> + </Menu> + + <Menu> + <Name>Other</Name> + <OnlyUnallocated/> + <Include> + <All/> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop kate.desktop freecell.desktop hidden.desktop + installData ${XDG_DATA_DIR}/desktop-directories apps.directory +} diff --git a/menu/tests/tests/NotOnlyUnallocated-default/result b/menu/tests/tests/NotOnlyUnallocated-default/result new file mode 100644 index 0000000..0c398b7 --- /dev/null +++ b/menu/tests/tests/NotOnlyUnallocated-default/result @@ -0,0 +1,2 @@ +Applications/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop +Editors/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop diff --git a/menu/tests/tests/NotOnlyUnallocated-default/test b/menu/tests/tests/NotOnlyUnallocated-default/test new file mode 100644 index 0000000..2f4956e --- /dev/null +++ b/menu/tests/tests/NotOnlyUnallocated-default/test @@ -0,0 +1,33 @@ +TEST_PURPOSE="Another <OnlyUnallocated> test" + +test_code() { + # Tests <OnlyUnallocated> + + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <DefaultAppDirs/> + + <Menu> + <Name>Applications</Name> + <Include> + <Filename>kwrite.desktop</Filename> + </Include> + </Menu> + <Menu> + <Name>Editors</Name> + <Include> + <Filename>kwrite.desktop</Filename> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop +} diff --git a/menu/tests/tests/OnlyUnallocated/result b/menu/tests/tests/OnlyUnallocated/result new file mode 100644 index 0000000..8be4bc7 --- /dev/null +++ b/menu/tests/tests/OnlyUnallocated/result @@ -0,0 +1,3 @@ +BoardGames/ gataxx.desktop ${XDG_DATA_DIR}/applications/gataxx.desktop +BoardGames/ mahjongg.desktop ${XDG_DATA_DIR}/applications/mahjongg.desktop +Games/ freecell.desktop ${XDG_DATA_DIR}/applications/freecell.desktop diff --git a/menu/tests/tests/OnlyUnallocated/test b/menu/tests/tests/OnlyUnallocated/test new file mode 100644 index 0000000..efda0ff --- /dev/null +++ b/menu/tests/tests/OnlyUnallocated/test @@ -0,0 +1,44 @@ +TEST_PURPOSE="<OnlyAllocated> tag" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + + <Menu> + <Name>BoardGames</Name> + <Include> + <And> + <Category>Game</Category> + <Not> + <Category>CardGame</Category> + </Not> + </And> + </Include> + <Exclude> + <Category>PuzzleGame</Category> + </Exclude> + </Menu> + <Menu> + <Name>Games</Name> + <Include> + <Category>Game</Category> + </Include> + <OnlyUnallocated/> + <NotOnlyUnallocated/> + <OnlyUnallocated/> + </Menu> +</Menu> +EOF + + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications gataxx.desktop mahjongg.desktop freecell.desktop glines.desktop +} diff --git a/menu/tests/tests/Or/result b/menu/tests/tests/Or/result new file mode 100644 index 0000000..fc75a82 --- /dev/null +++ b/menu/tests/tests/Or/result @@ -0,0 +1,4 @@ +Applications/ freecell.desktop ${XDG_DATA_DIR}/applications/freecell.desktop +Applications/ gataxx.desktop ${XDG_DATA_DIR}/applications/gataxx.desktop +Applications/ glines.desktop ${XDG_DATA_DIR}/applications/glines.desktop +Applications/ mahjongg.desktop ${XDG_DATA_DIR}/applications/mahjongg.desktop diff --git a/menu/tests/tests/Or/test b/menu/tests/tests/Or/test new file mode 100644 index 0000000..cd10cfd --- /dev/null +++ b/menu/tests/tests/Or/test @@ -0,0 +1,29 @@ +TEST_PURPOSE="<Or> Keyword" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + + <Menu> + <Name>Applications</Name> + <Include> + <Or> + <Filename>freecell.desktop</Filename> + <Category>Game</Category> + </Or> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications gataxx.desktop mahjongg.desktop freecell.desktop glines.desktop +} diff --git a/menu/tests/tests/boolean-logic/result b/menu/tests/tests/boolean-logic/result new file mode 100644 index 0000000..ea47f01 --- /dev/null +++ b/menu/tests/tests/boolean-logic/result @@ -0,0 +1,3 @@ +Apps/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Apps/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop +Apps/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop diff --git a/menu/tests/tests/boolean-logic/test b/menu/tests/tests/boolean-logic/test new file mode 100644 index 0000000..dc045c4 --- /dev/null +++ b/menu/tests/tests/boolean-logic/test @@ -0,0 +1,36 @@ +TEST_PURPOSE="<And><Category>foo</Category><Not><Category>foo</Category></Not></And> shouldn't match anything" + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + + <DefaultAppDirs/> + <DefaultDirectoryDirs/> + + <Menu> + <Name>Applications</Name> + <Directory>apps.directory</Directory> + <Include> + <Or> + <Category>TextEditor</Category> + <And> + <Category>Game</Category> + <Not><Category>Game</Category></Not> + </And> + </Or> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop kate.desktop + installData ${XDG_DATA_DIR}/applications/test freecell.desktop + installData ${XDG_DATA_DIR}/desktop-directories apps.directory +} diff --git a/menu/tests/tests/desktop-name-collision/result b/menu/tests/tests/desktop-name-collision/result new file mode 100644 index 0000000..e1e9221 --- /dev/null +++ b/menu/tests/tests/desktop-name-collision/result @@ -0,0 +1,3 @@ +Development/ kde-gideon.desktop ${XDG_DATA_HOME}/applications/kde-gideon.desktop +Development/ mahjongg.desktop ${XDG_DATA_HOME}/applications/mahjongg.desktop +Games/ freecell.desktop ${XDG_DATA_HOME}/applications/freecell.desktop diff --git a/menu/tests/tests/desktop-name-collision/test b/menu/tests/tests/desktop-name-collision/test new file mode 100644 index 0000000..46b5ded --- /dev/null +++ b/menu/tests/tests/desktop-name-collision/test @@ -0,0 +1,53 @@ +TEST_PURPOSE=".desktop files with same name ..." + +test_code() { + # Tests the type attribute in <MergeFile> + + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <DefaultAppDirs/> + <Menu> + <Name>Games</Name> + <Include> + <Category>Game</Category> + </Include> + </Menu> + <Menu> + <Name>Development</Name> + <Include> + <Category>Development</Category> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications freecell.desktop glines.desktop mahjongg.desktop + + # freecell.desktop is installed twice, only the version under ${XDG_DATA_HOME}/applications + # should show up in the menu + # freecell.desktop in ${XDG_DATA_DIR}/applications should be ignored. + installData ${XDG_DATA_HOME}/applications freecell.desktop + + # ${XDG_DATA_HOME}/applications/glines.desktop has NoDisplay=true + # glines.desktop should not be shown + # glines.desktop in ${XDG_DATA_DIR}/applications should be ignored. + installDataAs ${XDG_DATA_HOME}/applications glines-2.desktop glines.desktop + + # ${XDG_DATA_HOME}/applications/mahjongg.desktop has Categories=Development + # mahjongg.desktop should be shown under the Development menu + # mahjongg.desktop in ${XDG_DATA_DIR}/applications should be ignored. + installDataAs ${XDG_DATA_HOME}/applications mahjongg-2.desktop mahjongg.desktop + + # kde/gideon.desktop and kde-gideon.desktop are equivalent + # only the version under ${XDG_DATA_HOME}/applications should show up in the menu + # gideon.desktop in ${XDG_DATA_DIR}/applications/kde should be ignored. + installDataAs ${XDG_DATA_DIR}/applications/kde gideon.desktop + installDataAs ${XDG_DATA_HOME}/applications gideon.desktop kde-gideon.desktop +} diff --git a/menu/tests/tests/menu-multiple-matching/result b/menu/tests/tests/menu-multiple-matching/result new file mode 100644 index 0000000..986c873 --- /dev/null +++ b/menu/tests/tests/menu-multiple-matching/result @@ -0,0 +1,5 @@ +Applications/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Applications/ gataxx.desktop ${XDG_DATA_DIR}/applications/gataxx.desktop +Applications/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Applications/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop +Applications/ quanta.desktop ${XDG_DATA_DIR}/applications/quanta.desktop diff --git a/menu/tests/tests/menu-multiple-matching/test b/menu/tests/tests/menu-multiple-matching/test new file mode 100644 index 0000000..d8914ab --- /dev/null +++ b/menu/tests/tests/menu-multiple-matching/test @@ -0,0 +1,36 @@ +TEST_PURPOSE="complicated rule ..." + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + + <Menu> + <Name>Applications</Name> + <Include> + <And> + <Category>Game</Category> + <Category>BoardGame</Category> + </And> + <Or> + <Category>TextEditor</Category> + <Filename>quanta.desktop</Filename> + </Or> + </Include> + <Exclude> + <Filename>mahjongg.desktop</Filename> + </Exclude> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications gataxx.desktop mahjongg.desktop freecell.desktop glines.desktop kwrite.desktop KEdit.desktop quanta.desktop kate.desktop kbabel.desktop +} diff --git a/menu/tests/tests/official-categories/categories.list b/menu/tests/tests/official-categories/categories.list new file mode 100644 index 0000000..6e2198d --- /dev/null +++ b/menu/tests/tests/official-categories/categories.list @@ -0,0 +1,10 @@ +AudioVideo +Development +Education +Game +Graphics +Network +Office +Settings +System +Utility diff --git a/menu/tests/tests/official-categories/test b/menu/tests/tests/official-categories/test new file mode 100644 index 0000000..09621cd --- /dev/null +++ b/menu/tests/tests/official-categories/test @@ -0,0 +1,73 @@ +TEST_PURPOSE="verify all required categories are supported" + +base_loc="tests/official-categories" + +test_code() +{ + local category + for category in $(< "${base_loc}/categories.list"); do + CATEGORY="${category}" ./expand "${base_loc}/unique-entry.desktop" > "data/${category}.desktop" + installData "${XDG_DATA_DIR}/applications" "${category}.desktop" + rm "data/${category}.desktop" + done +} + +query() +{ + echo "$@" + ret='' + while [ -z "$ret" ]; do + echo -n "y/n? :" + read ret + if ! [ "$ret" == "y" -o "$ret" == "n" ]; then + echo "invalid response; must be 'y' or 'n'" + ret='' + fi + done + [ "$ret" == "y" ] && return 0 + return 1 +} + +interpret_results() +{ + # inefficient, but works. + local missed='' + local correct='' + for category in $(< "${base_loc}/categories.list"); do + if grep "/${category}\.desktop" "${MENUTESTDIR}/run-result" > /dev/null; then + correct="${correct} ${category}" + else + missed="${missed} ${category}" + fi + done + if [ -z "${missed}" ]; then + echo ">>> OK" + return 0 + fi + if [ "$(echo $missed)" != "Settings" ]; then + # failures. + cat "${MENUTESTDIR}/run-result" + echo "missed categories $missed" + echo "matched ${correct}" + echo ">>> Failed (missed $(echo $missed | wc -w) out of $(wc -l "${base_loc}/categories.list")" + return 1 + fi + echo ">>> Settings failed; checking interactively" + local ret + if [ "$(id -u)" != "0" ]; then + echo ">>> Cannot go interactive due to test being ran as non-root; re-run as root" + return 1; + elif ! which xdg-desktop-menu &> /dev/null; then + echo ">>> xdg-desktop-menu is not available; cannot do interactive test" + return 1; + fi + xdg-desktop-menu install --mode system --novendor "${XDG_DATA_DIR}/applications/Settings.desktop" + ( + query "Please check for a 'menu-spec-testing' in any gnome/kde system settings panel" + ) + ret=$? + xdg-desktop-menu uninstall --mode system "${XDG_DATA_DIR}/applications/Settings.desktop" + return $(($ret)) +} + +MODE=system_data diff --git a/menu/tests/tests/official-categories/unique-entry.desktop b/menu/tests/tests/official-categories/unique-entry.desktop new file mode 100644 index 0000000..6ee3b88 --- /dev/null +++ b/menu/tests/tests/official-categories/unique-entry.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Encoding=UTF-8 +Name=menu-spec-testing +Exec=true +Icon=quanta +Type=Application +MimeType=text/html +Comment=menu-spec testing +Categories=${CATEGORY}; diff --git a/menu/tests/tests/submenu-collision/result b/menu/tests/tests/submenu-collision/result new file mode 100644 index 0000000..6aa47d7 --- /dev/null +++ b/menu/tests/tests/submenu-collision/result @@ -0,0 +1,5 @@ +Applications/ KEdit.desktop ${XDG_DATA_DIR}/applications/KEdit.desktop +Applications/ kate.desktop ${XDG_DATA_DIR}/applications/kate.desktop +Applications/ kbabel.desktop ${XDG_DATA_DIR}/applications/kbabel.desktop +Applications/ kwrite.desktop ${XDG_DATA_DIR}/applications/kwrite.desktop +Applications/ quanta.desktop ${XDG_DATA_DIR}/applications/quanta.desktop diff --git a/menu/tests/tests/submenu-collision/test b/menu/tests/tests/submenu-collision/test new file mode 100644 index 0000000..7d29896 --- /dev/null +++ b/menu/tests/tests/submenu-collision/test @@ -0,0 +1,32 @@ +TEST_PURPOSE="two submenus with the same name ..." + +test_code() { + # Generate applications.menu + mkdir -p ${XDG_CONFIG_DIR}/menus + ./expand > ${XDG_CONFIG_DIR}/menus/applications.menu <<EOF + <!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/1.0/menu.dtd"> + +<Menu> + <Name>KDE</Name> + <!-- Search the default locations --> + <DefaultAppDirs/> + + <Menu> + <Name>Applications</Name> + <Include> + <Category>TextEditor</Category> + </Include> + </Menu> + <Menu> + <Name>Applications</Name> + <Include> + <Category>Development</Category> + </Include> + </Menu> +</Menu> +EOF + + # Install .desktop files + installData ${XDG_DATA_DIR}/applications kwrite.desktop KEdit.desktop quanta.desktop kate.desktop kbabel.desktop +} diff --git a/menu/tests/tet_menutest b/menu/tests/tet_menutest new file mode 100755 index 0000000..1aae67e --- /dev/null +++ b/menu/tests/tet_menutest @@ -0,0 +1,39 @@ +#!/bin/bash +TET_RUN="asdf" +export MENUTESTDIR="${MENUTESTDIR:-/tmp/menutest}" +. menutest +# hack, figure out the var to use here + +tpstart() { + tet_infoline "$*" + FAIL=N +} + +tet_startup='' +tet_cleanup='' +declare -i count=1 +iclist='' +echo $TESTS +for TESTCASE in ${TESTS}; do + [ ! -e "tests/${TESTCASE}/test" ] && continue; + # this basically curries the arg to run_test. + eval "tp${count}() { + . tests/${TESTCASE}/test + tpstart \"$(. tests/${TESTCASE}/test; echo ${TEST_PURPOSE-none stated})\"; + if ! run_test tests/\"$TESTCASE\"; then + tet_result FAIL; + else + tet_result PASS; + fi + set +x + }"; + iclist="${iclist} ic${count}" + eval "ic${count}=tp${count}" + # force subshelling, so that it doesn't pull a die on us + ((count+=1)) +done +tet_iclist=iclist +. /opt/lsb-tet3-lite/lib/posix_sh/tcm.sh +tet_outputline 100 "xdg menu test" +tet_tcm_main $tet_iclist + diff --git a/menu/tet_scen b/menu/tet_scen new file mode 100644 index 0000000..4fe544e --- /dev/null +++ b/menu/tet_scen @@ -0,0 +1,5 @@ +all + "Starting menu tests" + /tests/tet_menutest + "finished menu tests" + diff --git a/menu/tetexec.cfg b/menu/tetexec.cfg new file mode 100644 index 0000000..ea150c9 --- /dev/null +++ b/menu/tetexec.cfg @@ -0,0 +1 @@ +TET_PASS_TC_NAME=True diff --git a/secret-service/.gitignore b/secret-service/.gitignore new file mode 100644 index 0000000..551e415 --- /dev/null +++ b/secret-service/.gitignore @@ -0,0 +1,3 @@ + +/html/*.html +reference.xml diff --git a/secret-service/Makefile b/secret-service/Makefile new file mode 100644 index 0000000..00efeb9 --- /dev/null +++ b/secret-service/Makefile @@ -0,0 +1,17 @@ + +SPEC = org.freedesktop.Secrets.xml + +all: html/index.html + +html/index.html: reference.xml docbook-params.xsl specification.xml + xmlto --skip-validation -o html/ -x docbook-params.xsl xhtml specification.xml + +reference.xml: tools/spec-to-docbook.xsl $(SPEC) + xsltproc tools/spec-to-docbook.xsl $(SPEC) > $@ + +clean: + rm -f reference.xml + rm -f html/*.html + +upload: all + rsync -Hvax html/./ specs.freedesktop.org:/srv/specifications.freedesktop.org/www/secret-service/./ diff --git a/secret-service/README b/secret-service/README new file mode 100644 index 0000000..72a9997 --- /dev/null +++ b/secret-service/README @@ -0,0 +1,20 @@ +Generating the specification consists of separate steps: + +1. Use an xslt processor to create a DocBook XML document from the Telepathy + Introspection document using the provided stylesheet: + +$ xsltproc tools/spec-to-docbook.xsl \ + org.freedesktop.Secrets.xml >reference.xml + +2. Convert specification.xml and reference.xml to a suitable output format + (specification.xml includes reference.xml), eg html: + +$ xmlto --skip-validation -o html -p params-html.xsl xhtml specification.xml + +If you choose a different directory for html generation, be sure to copy +html/style.css to that location. + +Then open the resulting html/index.html in your favourite browser. + + +Michael Leupold <lemma@confuego.org> diff --git a/secret-service/docbook-params.xsl b/secret-service/docbook-params.xsl new file mode 100644 index 0000000..5d8591a --- /dev/null +++ b/secret-service/docbook-params.xsl @@ -0,0 +1,39 @@ +<?xml version="1.0"?> +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + +<!-- + Parameters for DocBook transformation. + + Copyright (C) 2009 Michael Leupold <lemma@confuego.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +--> + + <xsl:import href="http://docbook.sourceforge.net/release/xsl/current/xhtml/chunk.xsl"/> + + <xsl:param name="toc.max.depth">3</xsl:param> + <xsl:param name="generate.section.toc.level">0</xsl:param> + <xsl:param name="generate.toc"> + book toc + part nop + chapter toc + </xsl:param> + <xsl:param name="html.stylesheet">style.css</xsl:param> + <xsl:param name="funcsynopsis.style">ansi</xsl:param> + <xsl:param name="funcsynopsis.decoration">1</xsl:param> + <xsl:param name="refentry.generate.name">0</xsl:param> + <xsl:param name="refentry.generate.title">1</xsl:param> + +</xsl:stylesheet> diff --git a/secret-service/html/style.css b/secret-service/html/style.css new file mode 100644 index 0000000..f8a03b0 --- /dev/null +++ b/secret-service/html/style.css @@ -0,0 +1,127 @@ +/* reference.css, a stylesheet for reference documentation + * generated by the DocBook XSL Stylesheets */ +/* $Id: reference.css 8234 2009-02-09 12:10:48Z xmldoc $ */ + +div.legalnotice { + font-size: 80%; +} + +div.note, div.tip, div.warning { + margin-left: 5%; + margin-right: 10%; + padding: 5px; +} + +div.note, div.tip { + border-left: solid #d5dee3 20px; + border-right: solid #d5dee3 20px; +} + +div.note, div.tip { + border-left: solid palegreen 20px; + border-right: solid palegreen 20px; +} + +div.warning { + border-left: solid yellow 20px; + border-right: solid yellow 20px; +} + +div.note p, div.tip p, div.warning p { + margin-top: 0px; + margin-bottom: 4px; +} + +div.note h3, div.tip h3, div.warning h3 { + margin-top: 0; +} + +div.informalexample { + background-color: #d5dee3; + border-top-width: 2px; + border-top-style: double; + border-top-color: #d3d3d3; + border-bottom-width: 2px; + border-bottom-style: double; + border-bottom-color: #d3d3d3; + padding: 4px; + margin: 0em; + margin-left: 2em; +} + +pre.programlisting, pre.synopsis { + whitespace: pre; + font-family: monospace; + background-color: #d5dee3; + border-top-width: 1px; + border-top-style: single; + border-top-color: #d3d3d3; + border-bottom-width: 1px; + border-bottom-style: single; + border-bottom-color: #d3d3d3; + padding: 4px; + margin: 0em; + margin-top: 6px; + margin-bottom: 6px; +} + +div.informalexample pre { + whitespace: pre; + font-family: monospace; + border-top-width: 0px; + border-bottom-width: 0px; + padding: 0px; +} + +/* Parameter and PI titles */ + div.refnamediv h2 { + font-size: 2em; +} + +div.funcsynopsis, code.fieldsynopsis, +div.refsect2 div.refsynopsisdiv { + padding: 0.5em; + background-color: #F4F4F4; + border: 1px solid gray; + display: block; + width: 80%; +} + +div.refsynopsisdiv code.fieldsynopsis { + padding: 0; + border: 0; +} + +code.fieldsynopsis span.modifier { + min-width: 8em; + display: inline-block; +} + +code.fieldsynopsis span.type { + min-width: 11em; + display: inline-block; +} + +code.fieldsynopsis span.varname { + min-width: 11em; + display: inline-block; + font-size: 1.1em; + font-weight: bold; +} + +div.funcprototype-spacer { + max-height: 0.5em; +} + +table.funcprototype-table * td { + font-size: 0.9em; +} + +table.funcprototype-table * td code.funcdef { + font-size: 1.1em; +} + +b.fsfunc { + display: inline-block; + min-width: 11em; +}
\ No newline at end of file diff --git a/secret-service/org.freedesktop.Secrets.xml b/secret-service/org.freedesktop.Secrets.xml new file mode 100644 index 0000000..b6fba64 --- /dev/null +++ b/secret-service/org.freedesktop.Secrets.xml @@ -0,0 +1,490 @@ +<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> + +<!-- + * This is the well known dbus service name for controlling the + * entire daemon. The service manages collections of secrets. These + * are analogous to the gnome-keyring 'keyrings'. +--> +<tp:spec xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0"> + <tp:title>Secret Service API Specification</tp:title> + <tp:version>0.1</tp:version> + <tp:copyright> + Copyright (C) 2009 Stef Walter <stef@memberwebs.com> + </tp:copyright> + <tp:copyright> + Copyright (C) 2009 Michael Leupold <lemma@confuego.org> + </tp:copyright> + + <!-- + * ====================================================================================== + * ERROR CODES + * + --> + + <tp:errors namespace="org.freedesktop.Secret.Error"> + <tp:docstring>Errors returned by the Secret Service API.</tp:docstring> + <tp:error name="IsLocked"> + <tp:docstring>The object must be unlocked before this action can be carried out.</tp:docstring> + </tp:error> + <tp:error name="NoSession"> + <tp:docstring>The session does not exist.</tp:docstring> + </tp:error> + <tp:error name="NoSuchObject"> + <tp:docstring>No such item or collection exists.</tp:docstring> + </tp:error> + </tp:errors> + + <!-- + * ====================================================================================== + * SECRET STRUCT + * Signature: (oayays) + * + --> + + <tp:struct name="Secret"> + <tp:docstring>The Secret type holds a (possibly encoded) secret.</tp:docstring> + <tp:member type="o" name="session"> + <tp:docstring>The session that was used to encode the secret.</tp:docstring> + </tp:member> + <tp:member type="ay" name="parameters"> + <tp:docstring>Algorithm dependent parameters for secret value encoding.</tp:docstring> + </tp:member> + <tp:member type="ay" name="value"> + <tp:docstring>Possibly encoded secret value</tp:docstring> + </tp:member> + <tp:member type="s" name="content_type"> + <tp:docstring>The content type of the secret. For example: 'text/plain; charset=utf8'</tp:docstring> + </tp:member> + </tp:struct> + + <tp:mapping name="ObjectPath_Secret_Map"> + <tp:docstring>A mapping from object-paths to Secret structs</tp:docstring> + <tp:member type="o" name="Key"> + <tp:docstring>D-Bus object-path</tp:docstring> + </tp:member> + <tp:member type="(oayays)" name="Value" tp:type="Secret"> + <tp:docstring>A secret</tp:docstring> + </tp:member> + </tp:mapping> + + <!-- + * ====================================================================================== + * SERVICE INTERFACE + * + --> + + <node name="/org/freedesktop/Secrets"> + + <interface name="org.freedesktop.Secret.Service"> + + <tp:docstring> + The Secret Service manages all the sessions and collections. + </tp:docstring> + + <property name="Collections" type="ao" access="read"> + <tp:docstring>The object paths of all collections (ie: keyrings)</tp:docstring> + </property> + + <method name="OpenSession"> + <tp:docstring>Open a unique session for the caller application.</tp:docstring> + <arg name="algorithm" type="s" direction="in"> + <tp:docstring>The algorithm the caller wishes to use.</tp:docstring> + </arg> + <arg name="input" type="v" direction="in"> + <tp:docstring>Input arguments for the algorithm.</tp:docstring> + </arg> + <arg name="output" type="v" direction="out"> + <tp:docstring>Output of the session algorithm negotiation.</tp:docstring> + </arg> + <arg name="result" type="o" direction="out"> + <tp:docstring>The object path of the session, if session was created.</tp:docstring> + </arg> + </method> + + <method name="CreateCollection"> + <tp:docstring>Create a new collection with the specified properties.</tp:docstring> + <arg name="properties" type="a{sv}" direction="in"> + <tp:docstring xmlns:docbook="http://docbook.org/ns/docbook"> + <para> + Properties for the new collection. This allows setting the new collection's + properties upon its creation. All READWRITE properties are useable. Specify + the property names in full interface.Property form. + <example> + <title>Example for properties</title> + <programlisting> +<![CDATA[ +properties = { "org.freedesktop.Secret.Collection.Label": "MyCollection" } +]]> + </programlisting> + </example> + </para> + </tp:docstring> + </arg> + <arg name="alias" type="s" direction="in"> + <tp:docstring xmlns:docbook="http://docbook.org/ns/docbook"> + <para> + If creating this connection for a well known alias then a string like + <literal>default</literal>. If an collection with this well-known alias already + exists, then that collection will be returned instead of creating a new + collection. Any readwrite properties provided to this function will be set on + the collection. + </para> + <para> + Set this to an empty string if the new collection should not be associated with a + well known alias. + </para> + </tp:docstring> + </arg> + <arg name="collection" type="o" direction="out"> + <tp:docstring>The new collection object, or '/' if prompting is necessary.</tp:docstring> + </arg> + <arg name="prompt" type="o" direction="out"> + <tp:docstring>A prompt object if prompting is necessary, or '/' if no prompt was needed.</tp:docstring> + </arg> + </method> + + <method name="SearchItems"> + <tp:docstring>Find items in any collection.</tp:docstring> + <arg name="attributes" type="a{ss}" direction="in"> + <tp:docstring>Find secrets in any collection.</tp:docstring> + </arg> + <arg name="unlocked" type="ao" direction="out"> + <tp:docstring>Items found.</tp:docstring> + </arg> + <arg name="locked" type="ao" direction="out"> + <tp:docstring>Items found that require authentication.</tp:docstring> + </arg> + </method> + + <method name="Unlock"> + <tp:docstring>Unlock the specified objects.</tp:docstring> + <arg name="objects" type="ao" direction="in"> + <tp:docstring>Objects to unlock.</tp:docstring> + </arg> + <arg name="unlocked" type="ao" direction="out"> + <tp:docstring>Objects that were unlocked without a prompt.</tp:docstring> + </arg> + <arg name="prompt" type="o" direction="out"> + <tp:docstring>A prompt object which can be used to unlock the remaining objects, or the special value '/' when no prompt is necessary.</tp:docstring> + </arg> + </method> + + <method name="Lock"> + <tp:docstring>Lock the items.</tp:docstring> + <arg name="objects" type="ao" direction="in"> + <tp:docstring>Objects to lock.</tp:docstring> + </arg> + <arg name="locked" type="ao" direction="out"> + <tp:docstring>Objects that were locked without a prompt.</tp:docstring> + </arg> + <arg name="Prompt" type="o" direction="out"> + <tp:docstring>A prompt to lock the objects, or the special value '/' when no prompt is necessary.</tp:docstring> + </arg> + </method> + + <method name="GetSecrets"> + <tp:docstring>Retrieve multiple secrets from different items.</tp:docstring> + <arg name="items" type="ao" direction="in"> + <tp:docstring>Items to get secrets for.</tp:docstring> + </arg> + <arg name="session" type="o" direction="in"> + <tp:docstring>The session to use to encode the secrets.</tp:docstring> + </arg> + <arg name="secrets" type="a{o(oayays)}" direction="out" tp:type="ObjectPath_Secret_Map"> + <tp:docstring>Secrets for the items.</tp:docstring> + </arg> + </method> + + <method name="ReadAlias"> + <tp:docstring>Get the collection with the given alias.</tp:docstring> + <arg name="name" type='s' direction='in'> + <tp:docstring>An alias, such as 'default'.</tp:docstring> + </arg> + <arg name="collection" type='o' direction='out'> + <tp:docstring>The collection or the the path '/' if no such collection exists.</tp:docstring> + </arg> + </method> + + <method name="SetAlias"> + <tp:docstring>Setup a collection alias.</tp:docstring> + <arg name="name" type='s' direction='in'> + <tp:docstring>An alias, such as 'default'.</tp:docstring> + </arg> + <arg name="collection" type='o' direction='in'> + <tp:docstring> + The collection to make the alias point to. To remove an alias use the special value '/'. + </tp:docstring> + </arg> + </method> + + <signal name="CollectionCreated"> + <tp:docstring>A collection was created.</tp:docstring> + <arg name="collection" type="o"> + <tp:docstring>Collection that was created</tp:docstring> + </arg> + </signal> + + <signal name="CollectionDeleted"> + <tp:docstring>A collection was deleted.</tp:docstring> + <arg name="collection" type="o"> + <tp:docstring>Collection that was deleted.</tp:docstring> + </arg> + </signal> + + <signal name="CollectionChanged"> + <tp:docstring>A collection was changed.</tp:docstring> + <arg name="collection" type="o"> + <tp:docstring>Collection that was changed.</tp:docstring> + </arg> + </signal> + + </interface> + + </node> + + <!-- + * ====================================================================================== + * COLLECTION INTERFACE + * + --> + + <node name="/org/freedesktop/Secrets/collection/xxxx"> + + <interface name="org.freedesktop.Secret.Collection"> + + <tp:docstring>A collection of items containing secrets.</tp:docstring> + + <property name="Items" type="ao" access="read"> + <tp:docstring>Items in this collection.</tp:docstring> + </property> + + <property name="Label" type="s" access="readwrite"> + <tp:docstring>The displayable label of this collection.</tp:docstring> + </property> + + <property name="Locked" type="b" access="read"> + <tp:docstring> + Whether the collection is locked and must be authenticated by the client application. + </tp:docstring> + </property> + + <property name="Created" type="t" access="read"> + <tp:docstring>The unix time when the collection was created.</tp:docstring> + </property> + + <property name="Modified" type="t" access="read"> + <tp:docstring>The unix time when the collection was last modified.</tp:docstring> + </property> + + <method name="Delete"> + <tp:docstring>Delete this collection.</tp:docstring> + <arg name="prompt" type="o" direction="out"> + <tp:docstring>A prompt to delete the collection, or the special value '/' when no prompt is necessary.</tp:docstring> + </arg> + </method> + + <method name="SearchItems"> + <tp:docstring>Search for items in this collection matching the lookup attributes.</tp:docstring> + <arg name="attributes" type="a{ss}" direction="in"> + <tp:docstring>Attributes to match.</tp:docstring> + </arg> + <arg name="results" type="ao" direction="out"> + <tp:docstring>Items that matched the attributes.</tp:docstring> + </arg> + </method> + + <method name="CreateItem"> + <tp:docstring>Create an item with the given attributes, secret and label. If replace is set, then it replaces an item already present with the same values for the attributes.</tp:docstring> + <arg name="properties" type="a{sv}" direction="in"> + <tp:docstring>The properties for the new item.</tp:docstring> + <tp:docstring xmlns:docbook="http://docbook.org/ns/docbook"> + <para> + Properties for the new item. This allows setting the new item's + properties upon its creation. All READWRITE properties are useable. + Specify the property names in full interface.Property form. + <example> + <title>Example for properties</title> + <programlisting> +<![CDATA[ +properties = { + "org.freedesktop.Secret.Item.Label": "MyItem", + "org.freedesktop.Secret.Item.Attributes": { + "Attribute1": "Value1", + "Attribute2": "Value2" + } + } +]]> + </programlisting> + </example> + <note> + <para> + Please note that there is a distinction between the terms + <emphasis>Property</emphasis>, which refers to a D-Bus properties + of an object, and <emphasis>Attribute</emphasis>, which refers to one + of a secret item's string-valued attributes. + </para> + </note> + </para> + </tp:docstring> + </arg> + <arg name="secret" type="(oayays)" tp:type="Secret" direction="in"> + <tp:docstring>The secret to store in the item, encoded with the included session.</tp:docstring> + </arg> + <arg name="replace" type="b" direction="in"> + <tp:docstring>Whether to replace an item with the same attributes or not.</tp:docstring> + </arg> + <arg name="item" type="o" direction="out"> + <tp:docstring>The item created, or the special value '/' if a prompt is necessary.</tp:docstring> + </arg> + <arg name="prompt" type="o" direction="out"> + <tp:docstring>A prompt object, or the special value '/' if no prompt is necessary.</tp:docstring> + </arg> + </method> + + <signal name="ItemCreated"> + <tp:docstring>A new item in this collection was created.</tp:docstring> + <arg name="item" type="o"> + <tp:docstring>The item that was created.</tp:docstring> + </arg> + </signal> + + <signal name="ItemDeleted"> + <tp:docstring>An item in this collection was deleted.</tp:docstring> + + <arg name="item" type="o"> + <tp:docstring>The item that was deleted.</tp:docstring> + </arg> + </signal> + + <signal name="ItemChanged"> + <tp:docstring>An item in this collection changed.</tp:docstring> + + <arg name="item" type="o"> + <tp:docstring>The item that was changed.</tp:docstring> + </arg> + </signal> + + </interface> + + </node> + + <!-- + * ====================================================================================== + * ITEM INTERFACE + * + --> + + <node name="/org/freedesktop/Secret/collection/xxxx/iiii"> + + <interface name="org.freedesktop.Secret.Item"> + + <tp:docstring>An item contains a secret, lookup attributes and has a label.</tp:docstring> + + <property name="Locked" type="b" access="read"> + <tp:docstring>Whether the item is locked and requires authentication, or not.</tp:docstring> + </property> + + <property name="Attributes" type="a{ss}" access="readwrite"> + <tp:docstring>The lookup attributes for this item.</tp:docstring> + </property> + + <property name="Label" type="s" access="readwrite"> + <tp:docstring>The displayable label for this item.</tp:docstring> + </property> + + <property name="Created" type="t" access="read"> + <tp:docstring>The unix time when the item was created.</tp:docstring> + </property> + + <property name="Modified" type="t" access="read"> + <tp:docstring>The unix time when the item was last modified.</tp:docstring> + </property> + + <method name="Delete"> + <tp:docstring>Delete this item.</tp:docstring> + <arg name="Prompt" type="o" direction="out"> + <tp:docstring>A prompt object, or the special value '/' if no prompt is necessary.</tp:docstring> + </arg> + </method> + + <method name="GetSecret"> + <tp:docstring>Retrieve the secret for this item.</tp:docstring> + <arg name="session" type="o" direction="in"> + <tp:docstring>The session to use to encode the secret.</tp:docstring> + </arg> + <arg name="secret" type="(oayays)" tp:type="Secret" direction="out"> + <tp:docstring>The secret retrieved.</tp:docstring> + </arg> + </method> + + <method name="SetSecret"> + <tp:docstring>Set the secret for this item.</tp:docstring> + <arg name="secret" type="(oayays)" tp:type="Secret" direction="in"> + <tp:docstring>The secret to set, encoded for the included session.</tp:docstring> + </arg> + </method> + + </interface> + + </node> + + <!-- + * ====================================================================================== + * SESSION INTERFACE + * + --> + + <node name="/org/freedesktop/Secret/session/ssss"> + + <interface name="org.freedesktop.Secret.Session"> + + <tp:docstring>A session tracks state between the service and a client application.</tp:docstring> + + <method name="Close"> + <tp:docstring>Close this session.</tp:docstring> + </method> + + </interface> + + </node> + + <!-- + * ====================================================================================== + * PROMPT INTERFACE + * + --> + + <node name="/org/freedesktop/Secret/prompts/pppp"> + + <interface name="org.freedesktop.Secret.Prompt"> + <tp:docstring>A prompt necessary to complete an operation.</tp:docstring> + + <method name="Prompt"> + <tp:docstring>Perform the prompt.</tp:docstring> + <arg name="window-id" type="s" direction="in"> + <tp:docstring>Platform specific window handle to use for + showing the prompt.</tp:docstring> + </arg> + </method> + + <method name="Dismiss"> + <tp:docstring>Dismiss the prompt.</tp:docstring> + </method> + + <signal name="Completed"> + <tp:docstring>The prompt and operation completed.</tp:docstring> + <arg name="dismissed" type="b"> + <tp:docstring>Whether the prompt and operation were dismissed or not.</tp:docstring> + </arg> + <arg name="result" type="v"> + <tp:docstring>The possibly empty, operation specific, + result.</tp:docstring> + </arg> + </signal> + + </interface> + + </node> + +</tp:spec> diff --git a/secret-service/specification.xml b/secret-service/specification.xml new file mode 100644 index 0000000..507eb78 --- /dev/null +++ b/secret-service/specification.xml @@ -0,0 +1,580 @@ +<?xml version="1.0"?> +<book xml:id="index" xmlns="http://docbook.org/ns/docbook" version="5.0"> + <bookinfo> + <title>Secret Service API Draft</title> + <releaseinfo> + Secret Service 0.2 DRAFT + </releaseinfo> + + <authorgroup> + <author> + <firstname>Stef</firstname> + <surname>Walter</surname> + <affiliation> + <jobtitle>GNOME Keyring Developer</jobtitle> + <address> + <email>stefw@collabora.co.uk</email> + </address> + </affiliation> + </author> + <author> + <firstname>Michael</firstname> + <surname>Leupold</surname> + <affiliation> + <jobtitle>KWallet Developer</jobtitle> + <address> + <email>lemma@confuego.org</email> + </address> + </affiliation> + </author> + </authorgroup> + + <copyright> + <year>2008-2011</year> + <holder>The Secret Service API Authors</holder> + </copyright> + + </bookinfo> + + <part xml:id="description"> + <title>API Documentation</title> + <chapter> + <title>Introduction</title> + + <para>The Secret Service API allows client applications to store secrets securely in a + service running in the user's login session. </para> + + <para>The secrets are usually stored in an encrypted manner by the service. The + service may need to be unlocked by the user before the secrets become available + for retrieval by client applications.</para> + + <para>The Secret Service stores a secret along with a set of lookup attributes. + The attributes can be used to look up and retrieve a secret at a later date. The + lookup attributes are not treated as secret material, and the service may choose + not to encrypt attributes when storing them to disk.</para> + + <para>This API was desigened by GNOME and KDE developers with the goal of having + a common way to store secrets. Its predecessors are the desktop-specific APIs + used by GNOME Keyring and KWallet.</para> + </chapter> + + <chapter> + <title>Secrets</title> + + <para>A secret is something an application wishes to store securely. A good example + is a password that an application needs to save and use at a later date.</para> + + <para>Within this API a secret value is treated as an array of bytes. It is + recommended that a secret consist of user-readable text, although this API has + no such requirement.</para> + + <para>Applications wishing to store multiple values as part of a single secret, may + choose to use a textual format to combine these values into one. For example, multiple + values may be combined using the 'desktop' key file format, or XML.</para> + + <para>Secrets may be <link linkend='transfer-secrets'>encrypted when transferred</link> + to or from the client application.</para> + + <para>The <link linkend='type-Secret'><classname>Secret</classname> structure</link> encapsulates + a secret value along with its transfer encryption parameters.</para> + </chapter> + + <chapter> + <title>Collection and Items</title> + + <para>Each secret is stored together with + <link linkend='lookup-attributes'>lookup attributes</link> and a label. These together + form an <link linkend='org.freedesktop.Secret.Item'>item</link>.</para> + + <para>A group of items together form a + <link linkend='org.freedesktop.Secret.Collection'>collection</link>. + A collection is similar in concept to the terms 'keyring' or 'wallet'.</para> + + <para>Collections and items are represented as DBus objects, and each has its own + object path. Under normal circumstances, the object path of a collection or item + should not change for its lifetime.</para> + + <para>It is strongly recommended that client applications use + <link linkend='lookup-attributes'>lookup attributes</link> to find items rather than + recording the object path of a stored item. This allows maximum interoperability.</para> + + <para>An item or a collection may be initially in a locked state. When in a locked + state the item or collection may not be modified in any way, and the secret may not + be read. Client applications that require access to the secret of a locked item, or + desire to modify a locked item, must <link linkend='unlocking'>unlock it</link> before use.</para> + + <para>The service must prevent modification of locked collections or items. On + such an invalid access the + <link linkend='org.freedesktop.Secret.Error.IsLocked'><errorname>IsLocked</errorname></link> + error should be raised.</para> + + <para>Client applications without special requirements should store in the default + collection. The default collection is always accessible through a + <link linkend='object-paths'>specific object path</link>.</para> + + <para>A new item can be created with the + <link linkend='org.freedesktop.Secret.Collection.CreateItem'> + <function>CreateItem()</function></link> + method on the Collection interface. When creating an item, the properties of the new + item are specified. The service may ignore or change these properties when creating + the item.</para> + + <para>When creating an item, the service may need to prompt the user for additional + information. In this case, a <link linkend='prompts'>prompt object</link> is returned. It + must be <link linkend='org.freedesktop.Secret.Prompt.Prompt'>acted upon</link> in order for + the collection to be created. In this case, the + <link linkend='org.freedesktop.Secret.Prompt.Completed'>result of the prompt</link> + will contain the object path of the new item.</para> + + <para>An item can be deleted by calling the + <link linkend='org.freedesktop.Secret.Item.Delete'><function>Delete()</function></link> + method on the Item interface.</para> + + <para>When deleting an item, the service may need to prompt the user for additional + information. In this case, a <link linkend='prompts'>prompt object</link> is returned. It + must be <link linkend='org.freedesktop.Secret.Prompt.Prompt'>acted upon</link> in order for + the item to be deleted.</para> + + <para>Client applications with special needs can create a new collection by calling the + <link linkend='org.freedesktop.Secret.Service.CreateCollection'> + <function>CreateCollection()</function></link> + method on the Service interface. When creating a collection, the properties of the new + collection are specified. The service may ignore or change these properties when creating + the collection.</para> + + <para>When creating a collection, the service may need to prompt the user for additional + information. In this case, a <link linkend='prompts'>prompt object</link> is returned. It + must be <link linkend='org.freedesktop.Secret.Prompt.Prompt'>acted upon</link> in order for + the collection to be created. In this case, the + <link linkend='org.freedesktop.Secret.Prompt.Completed'>result of the prompt</link> + will contain the object path of the new collection.</para> + + <para>A collection can be deleted by calling the + <link linkend='org.freedesktop.Secret.Collection.Delete'><function>Delete()</function></link> + method on the Collection interface.</para> + + <para>When deleting a collection, the service may need to prompt the user for additional + information. In this case, a <link linkend='prompts'>prompt object</link> is returned. It + must be <link linkend='org.freedesktop.Secret.Prompt.Prompt'>acted upon</link> in order for + the collection to be deleted.</para> + </chapter> + + <chapter xml:id="aliases"> + <title>Aliases</title> + + <para>Collections may be accessed via well known aliases. For example an alias + called <literal>default</literal> tells applications which is the default + collection to store secrets.</para> + + <para>The aliased collections will be available at a + <link linkend='object-paths'>well-known DBus object path</link>.</para> + + <para>If an application needs to create a collection with a given alias, this can + be done in a race free fashion by specifying the alias parameter of the + <link linkend='org.freedesktop.Secret.Service.CreateCollection'>CreateCollection()</link> + method on the service interface. If a collection with that alias already exists, + then it will be returned instead of creating a new one.</para> + + <para>For applications like password managers it can be useful to allow the user to + configure which collection is associated with which well known alias. To alias or + unalias a collection use the + <link linkend='org.freedesktop.Secret.Service.SetAlias'>SetAlias()</link> method on the + service interface. Use the + <link linkend='org.freedesktop.Secret.Service.ReadAlias'>ReadAlias()</link> method on the + service interface to discover which collection is associated with a given alias.</para> + </chapter> + + <chapter xml:id="lookup-attributes"> + <title>Lookup Attributes</title> + + <para>Attributes can and should be stored with a secret to facilitate lookup + of the secret at a later date.</para> + + <para>An attribute constists of a name, and a value. Both parts are simple + strings.</para> + + <para>The service may have additional requirements as to what can be present + in an attribute name. It is recommended that attribute names are human + readable, and kept simple for the sake of simplicity.</para> + + <para>During a lookup, attribute names and values are matched via case-sensitive + string equality.</para> + + <para>It's important to remember that attributes are not part of the secret. + Services implementing this API will probably store attributes in an unencrypted + manner in order to support simple and effecient lookups.</para> + + <para>In order to search for items, use the + <link linkend='org.freedesktop.Secret.Service.SearchItems'><function>SearchItems()</function></link> + method of the Service interface. The matched items will be returned in two sets. The + <parameter class='function'>unlocked</parameter> return value will contain the object paths + of all the items that are not locked. The <parameter class='function'>locked</parameter> return + value will contain object paths of items that are locked, which can be + <link linkend='unlocking'>unlocked if desired</link>.</para> + + <para>The + <link linkend='org.freedesktop.Secret.Collection.SearchItems'><function>SearchItems()</function></link> + method of the Collection interface is similar, except for it only searches a single collection.</para> + + </chapter> + + <chapter xml:id="sessions"> + <title>Sessions</title> + + <para>A session is established between a client application and a service. A session + is used to <link linkend='transfer-secrets'>transfer secrets</link> between the client + application and the service.</para> + + <para>A session is established by calling the service's + <link linkend='org.freedesktop.Secret.Service.OpenSession'> + <function>OpenSession()</function></link> + method. Once established, a session is bound to calling application's connection to + the DBus session bus.</para> + + <para>A session is closed when the client application disconnects from the DBus + session bus. Alternatively the client application can call the + <link linkend='org.freedesktop.Secret.Session.Close'><function>Close()</function></link> + method on the session interface. Once a session is closed all session specific + negotiations will be dropped by the service.</para> + + <para>More than one session may opened by a client application, although this is + not normally necessary.</para> + </chapter> + + <chapter xml:id='transfer-secrets'> + <title>Transfer of Secrets</title> + + <para>To access or store secrets, use the + <link linkend='org.freedesktop.Secret.Item.GetSecret'><function>GetSecret()</function></link>, + <link linkend='org.freedesktop.Secret.Item.SetSecret'><function>SetSecret()</function></link> + methods on the item interface, or the + <link linkend='org.freedesktop.Secret.Service.GetSecrets'><function>GetSecrets()</function></link>, + method on the service interface.</para> + + <para>You must specify a session when retrieving or storing a secret. The session + controls how the secret is encoded during transfer. Since this is a D-Bus API, the + data in all method calls and other accesses in this API will go through multiple + processes, and may be cached arbitrarilyby the OS or elsewhere.</para> + + <para>The Secrets API has provision to encrypt secrets while in transit between + the service and the client application. The encryption is not envisioned to withstand + man in the middle attacks, or other active attacks. It is envisioned to minimize + storage of plain text secrets in memory and prevent storage plain text storage of + secrets in a swap file or other caching mechanism.</para> + + <para>Many client applications may choose not to make use of the provisions to + encrypt secrets in transit. In fact for applications unable to prevent their own + memory from being paged to disk (eg: Java, C# or Python apps), transfering + encrypted secrets would be an excersize of questionable value.</para> + + <section> + <title>Negotiation of Algorithms</title> + + <para>In order to encrypt secrets in transit, the service and the client + application must agree on an algorithm, and some algorithm specific + parameters (eg: a key).</para> + + <para>When the client application opens a <link linkend='sessions'>session</link> + with the service, it calls the + <link linkend='org.freedesktop.Secret.Service.OpenSession'><function> + OpenSession()</function></link> method on the service. The algorithms argument to the + <function>OpenSession()</function> method specifies a set of algorithms to be used + together for key agreement and encryption. The other arguments are algorithm + specific.</para> + + <para>If a service does not support a specific set of algorithms, a + <errorname>org.freedesktop.DBus.Error.NotSupported</errorname> + error is returned, and the client is free to try another set of algorithms. + The <emphasis>plain</emphasis> algorithm is almost always supported.</para> + + <para>An algorithm may require that the <function>OpenSession()</function> method is + called multiple times in succession to be complete. Each iteration transfers + algorithm specific data back forth between the service and the client. The object path + '/' is returned from <function>OpenSession()</function> when session negotiation is + incomplete.</para> + + <para>None of the algorithms documented in this initial version of the specification + require multiple calls to <function>OpenSession()</function>.</para> + + <para>When <function>OpenSession()</function> completes, it returns the session object + path along with a valid session object path.</para> + + <para>Once an session algorithm has been negotiated, it is used for all transfer a + secrets whenever that session is specified along with the + <link linkend='type-Secret'><classname>secret</classname></link>.</para> + </section> + + <section> + <title>Algorithm: plain</title> + + <segmentedlist> + <?dbhtml list-presentation="list"?> + <segtitle>Session algorithm</segtitle> + <segtitle><link linkend='org.freedesktop.Secret.Service.OpenSession'> + Session input</link></segtitle> + <segtitle><link linkend='org.freedesktop.Secret.Service.OpenSession'> + Session output</link></segtitle> + <segtitle><link linkend='type-Secret'> + <classname>Secret</classname> parameter</link></segtitle> + <seglistitem> + <!-- TODO: literal? --> + <seg><emphasis>plain</emphasis></seg> + <seg>empty string</seg> + <seg>empty string</seg> + <seg>empty string</seg> + </seglistitem> + </segmentedlist> + + <para>The plain algorithm does no encryption whatsoever.</para> + + <para>It is strongly recommended that a service implementing this API support + the <emphasis>plain</emphasis> algorithm.</para> + </section> + + <section> + <title>Algorithm: dh-ietf1024-sha256-aes128-cbc-pkcs7</title> + + <segmentedlist> + <?dbhtml list-presentation="list"?> + <segtitle>Session algorithm</segtitle> + <segtitle><link linkend='org.freedesktop.Secret.Service.OpenSession'> + Session input</link></segtitle> + <segtitle><link linkend='org.freedesktop.Secret.Service.OpenSession'> + Session output</link></segtitle> + <segtitle><link linkend='type-Secret'> + <classname>Secret</classname> parameter</link></segtitle> + <seglistitem> + <!-- TODO: literal? --> + <seg><emphasis>dh-ietf1024-sha256-aes128-cbc-pkcs7</emphasis></seg> + <seg>Client DH pub key as an array of bytes</seg> + <seg>Service DH pub key as an array of bytes</seg> + <seg>16 byte AES initialization vector</seg> + </seglistitem> + </segmentedlist> + + <para>DH key agreement <citation>rfc2631</citation> is used to create a secret key + using 1024 bit parameters of the standard IETF 'Second Oakley Group' + <citation>rfc2409</citation>. The secret key is then digested into a 128-bit key + appropriate for AES. This is done using HKDF <citation>rfc5869</citation> with NULL + salt and empty info, using the SHA-2 256 hash algorithm + <citation>fips-180-3.2008</citation>. The secrets are encrypted using AES + <citation>fips-197.2001</citation> in cipher block chaining mode with pkcs7 style + padding <citation>rfc2315</citation>.</para> + + <para>The public keys are transferred as an array of bytes representing an + unsigned integer of arbitrary size, most-significant byte first (e.g., the + integer 32768 is represented as the 2-byte string 0x80 0x00)</para> + </section> + + </chapter> + + <chapter xml:id='unlocking'> + <title>Locking and Unlocking</title> + + <para>Some items and/or collections may be marked as locked by the service. + The secrets of locked items cannot be accessed. Additionally, locked items or collections + cannot be modified by the client application.</para> + + <para>It's up to the service whether to unlock items individually, or collections as a + whole. The client application should act as if it must unlock each item individually.</para> + + <para>A service may upon unlocking a collection, unlock all items in that collection. If + a service is not able to unlock an item individually, it should treat a request to unlock + an item as a request to unlock the connection that the item is in.</para> + + <para>A service may choose to unlock items or collections just for a single client + application. Alternatively the service may choose to allow any client application to access + items or collections unlocked by a another client application.</para> + + <para>A client application should always be ready to unlock the items for the secrets + it needs, or objects it must modify. It must not assume that an item is already unlocked + for whatever reason.</para> + + <para>A service may lock previously unlocked items for any reason at any time. Usually this + is done in response to user actions, timeouts, or external actions (such as the computer + sleeping). The inherent race conditions present due to this are unavoidable, and must be + handled gracefully.</para> + + <para>In order to unlock an item or collection the service's + <link linkend='org.freedesktop.Secret.Service.Unlock'> + <function>Unlock()</function></link> + method is called with one or more DBus object paths of items or collections. The + <function>Unlock()</function> will return the DBus object paths of objects it could + immediately unlock without prompting.</para> + + <para>The <function>Unlock()</function> method may also return a + <link linkend='org.freedesktop.Secret.Prompt.Prompt'>prompt object</link>. If a prompt + object is returned, it must be <link linkend='prompts'>acted upon</link> in order to complete + the unlocking of the remaining objects. The + <link linkend='org.freedesktop.Secret.Prompt.Completed'>result of the prompt</link> + will contain the object paths that were successfully unlocked by the prompt.</para> + + <para>In order to lock an item or collection the service's + <link linkend='org.freedesktop.Secret.Service.Unlock'> + <function>Lock()</function></link> + method is called with one or more DBus object paths of items or collections. The + <function>Lock()</function> will return the DBus object paths of objects it could + immediately lock without prompting.</para> + + <para>The <function>Lock()</function> method may also return a + <link linkend='org.freedesktop.Secret.Prompt.Prompt'>prompt object</link>. If a prompt + object is returned, it must be <link linkend='prompts'>acted upon</link> in order to complete + the locking of the remaining objects. The + <link linkend='org.freedesktop.Secret.Prompt.Completed'>result of the prompt</link> + will contain the object paths that were successfully locked by the prompt.</para> + </chapter> + + <chapter xml:id='prompts'> + <title>Prompts and Prompting</title> + + <para>In order to complete various operations, such as unlocking a collection, the + service may need to prompt the user for additional information, such as a master password.</para> + + <para>The prompts are displayed by the service on behalf of the client application.</para> + + <para>Operations that require a prompt to complete will return a prompt object. The client + application must then call the + <link linkend='org.freedesktop.Secret.Prompt.Prompt'><function>Prompt()</function></link> + method of the prompt object to display the prompt. Client applications can use the + <parameter class='function'>window-id</parameter> + argument to display the prompt attached to their application window.</para> + + <para>Once the user provides the additional required information to the prompt, the service + completes the operation that required the prompt. Then it emits the the + <link linkend='org.freedesktop.Secret.Prompt.Completed'><function>Completed</function></link> + signal of the prompt object. The <parameter class='function'>result</parameter> argument of + the signal contains operation an operation specific result.</para> + + <para>Either the user or the client application can dismiss a prompt. In this case the + operation that required the additional information is cancelled. The client application + can dismiss a prompt by calling the + <link linkend='org.freedesktop.Secret.Prompt.Dismiss'><function>Dismiss()</function></link> + method of the prompt object. The <function>Completed</function> signal will be emitted + with its <parameter class='function'>dismissed</parameter> argument set to + <constant>TRUE</constant>.</para> + + <para>Once the <function>Completed</function> signal is emitted on a prompt object, it + is no longer valid. Prompt objects are specific to the client application's connection + to the DBus bus. Once an application disconnects, all its prompts are no longer valid.</para> + + <para>There is an inherent race between the <function>Dismiss()</function> method and the + <function>Completed</function> signal. An application calling <function>Dismiss()</function> + must be prepared to handle the fact that the <function>Completed</function> has already been + emitted (although perhaps not received by the client). In addition the client must be prepared + to handle the fact that the prompt object is no longer valid.</para> + </chapter> + + <chapter> + <title>What's not included in the API</title> + + <para>A service may implement additional DBus interfaces for further capabilities not + included in this specification. Password management applications or other narrowly + focused tools should make use of these when necessary.</para> + + <para>This specification does not mandate the use of master passwords to lock a + collection of secrets. The service may choose to implement any method for locking + secrets.</para> + + <para>This specification does not mandate any form of access control. The service may + choose to allow certain applications to access a keyring, and others.</para> + + <para>[TODO: complete]</para> + </chapter> + + <chapter> + <title>Notes for Service Implementors</title> + + <para>[TODO: complete]</para> + </chapter> + + </part> + + <part xml:id="ref-dbus-api"> + <title>D-Bus API Reference</title> + + <chapter xml:id='object-paths'> + <title>Object Paths</title> + + <para>The various DBus object paths used with the Secret Service API are designed to be human + readable but not displayed to the user. The object path of an item or collection should + not change for its lifetime, under normal circumstances.</para> + + <programlisting>/org/freedesktop/secrets</programlisting> + <para>The object path for the service.</para> + + <programlisting>/org/freedesktop/secrets/collection/<emphasis>xxxx</emphasis></programlisting> + <para>The object path for a collection, where <emphasis>xxxx</emphasis> represents a + possibly encoded or truncated version of the initial label of the collection.</para> + + <programlisting>/org/freedesktop/secrets/collection/<emphasis>xxxx</emphasis>/<emphasis>iiii</emphasis></programlisting> + <para>The object path for an item, where <emphasis>xxxx</emphasis> is the collection (above) + and <emphasis>iiii</emphasis> is an auto-generated item specific identifier.</para> + + <programlisting>/org/freedesktop/secrets/session/<emphasis>ssss</emphasis></programlisting> + <para>The object path for a session, where <emphasis>ssss</emphasis> is an auto-generated + session specific identifier.</para> + + <programlisting>/org/freedesktop/secrets/aliases/default</programlisting> + <para>The default collection for client applications to store secrets is available under + this object path in addition to its real object path (above). Other aliases may also be + present.</para> + </chapter> + + <xi:include href="reference.xml" xpointer="interfaces" xmlns:xi="http://www.w3.org/2001/XInclude"> + <xi:fallback/> + </xi:include> + <xi:include href="reference.xml" xpointer="types" xmlns:xi="http://www.w3.org/2001/XInclude"> + <xi:fallback/> + </xi:include> + <xi:include href="reference.xml" xpointer="errors" xmlns:xi="http://www.w3.org/2001/XInclude"> + <xi:fallback/> + </xi:include> + + </part> + + <xi:include href="xml/annotation-glossary.xml" xmlns:xi="http://www.w3.org/2001/XInclude"> + <xi:fallback/> + </xi:include> + + <bibliography> + <title>References</title> + + <bibliomixed> + <abbrev>rfc2315</abbrev> + IETF <ulink url="http://www.ietf.org/rfc/rfc2315.txt">RFC 2315</ulink>: + PKCS #7: Cryptographic Message Syntax Version 1.5 + </bibliomixed> + + <bibliomixed> + <abbrev>rfc2409</abbrev> + IETF <ulink url="http://www.ietf.org/rfc/rfc2409.txt">RFC 2409</ulink>: + The Internet Key Exchange (IKE) + </bibliomixed> + + <bibliomixed> + <abbrev>rfc2631</abbrev> + IETF <ulink url="http://www.ietf.org/rfc/rfc2631.txt">RFC 2631</ulink>: + Diffie-Hellman Key Agreement Method + </bibliomixed> + + <bibliomixed> + <abbrev>rfc5869</abbrev> + IETF <ulink url="http://www.ietf.org/rfc/rfc5869.txt">RFC 5869</ulink>: + HMAC-based Extract-and-Expand Key Derivation Function (HKDF) + </bibliomixed> + + <bibliomixed> + <abbrev>fips-180-3.2008</abbrev> + NIST <ulink url="http://csrc.nist.gov/publications/fips/fips180-3/fips180-3_final.pdf">FIPS PUB 180-3</ulink>: + Secure Hash Standard (SHS), October 2008 + </bibliomixed> + + <bibliomixed> + <abbrev>fips-197.2001</abbrev> + NIST <ulink url="http://csrc.nist.gov/publications/fips/fips197/fips-197.pdf">FIPS PUB 197</ulink>: + Advanced Encryption Standard (AES), November 2001 + </bibliomixed> + + </bibliography> + +</book> diff --git a/secret-service/tools/resolve-type.xsl b/secret-service/tools/resolve-type.xsl new file mode 100644 index 0000000..a37f2af --- /dev/null +++ b/secret-service/tools/resolve-type.xsl @@ -0,0 +1,122 @@ +<?xml version="1.0"?> +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + xmlns:html="http://www.w3.org/1999/xhtml" + exclude-result-prefixes="tp html"> + +<!-- + Helper templates for Telepathy D-Bus Introspection conversion. + + Copyright (C) 2009 Michael Leupold <lemma@confuego.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +--> + + <!-- Resolve the type a node has. This will first look at tp:type and + - if not found - use the type attribute --> + <xsl:template name="ResolveType"> + <xsl:param name="node"/> + <xsl:variable name="unstripped"> + <xsl:choose> + <xsl:when test="$node//@tp:type"> + <xsl:call-template name="TpType"> + <xsl:with-param name="type" select="$node//@tp:type"/> + </xsl:call-template> + </xsl:when> + <xsl:when test="$node//@type"> + <xsl:call-template name="DBusType"> + <xsl:with-param name="type" select="$node//@type"/> + </xsl:call-template> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + Node doesn't contain a type. + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:value-of select="translate(translate($unstripped, ' ', ''), '
', '')"/> + </xsl:template> + + <!-- Map a D-Bus type to its EggDBus counterpart --> + <xsl:template name="DBusType"> + <xsl:param name="type"/> + <xsl:choose> + <xsl:when test="$type='o'">ObjectPath</xsl:when> + <xsl:when test="$type='s'">String</xsl:when> + <xsl:when test="$type='y'">Byte</xsl:when> + <xsl:when test="$type='b'">Boolean</xsl:when> + <xsl:when test="$type='n'">Int16</xsl:when> + <xsl:when test="$type='q'">UInt16</xsl:when> + <xsl:when test="$type='i'">Int32</xsl:when> + <xsl:when test="$type='u'">UInt32</xsl:when> + <xsl:when test="$type='x'">Int64</xsl:when> + <xsl:when test="$type='t'">UInt64</xsl:when> + <xsl:when test="$type='d'">Double</xsl:when> + <xsl:when test="$type='g'">Signature</xsl:when> + <xsl:when test="$type='v'">Variant</xsl:when> + <xsl:when test="starts-with($type, 'a{')"> + Dict< + <xsl:call-template name="DBusType"> + <xsl:with-param name="type" select="substring($type, 3, 1)"/> + </xsl:call-template> + , + <xsl:call-template name="DBusType"> + <xsl:with-param name="type" select="substring($type, 4, 1)"/> + </xsl:call-template> + > + </xsl:when> + <xsl:when test="starts-with($type, 'a')"> + Array< + <xsl:call-template name="DBusType"> + <xsl:with-param name="type" select="substring($type, 2)"/> + </xsl:call-template> + > + </xsl:when> + <!-- TODO: doesn't implement dict-entries and structs --> + <xsl:otherwise> + <xsl:message terminate="yes"> + Unknown DBus Type <xsl:value-of select="$type"/> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- Resolve tp:type attributes by searching for matching tp:struct + and tp:mapping elements --> + <xsl:template name="TpType"> + <xsl:param name="type"/> + <xsl:choose> + <xsl:when test="/tp:spec/tp:struct[@name=$type]"> + <xsl:value-of select="$type"/> + </xsl:when> + <xsl:when test="/tp:spec/tp:mapping[@name=$type]"> + Dict< + <xsl:call-template name="ResolveType"> + <xsl:with-param name="node" select="/tp:spec/tp:mapping[@name=$type]/tp:member[@name='Key']"/> + </xsl:call-template>, + <xsl:call-template name="ResolveType"> + <xsl:with-param name="node" select="/tp:spec/tp:mapping[@name=$type]/tp:member[@name='Value']"/> + </xsl:call-template> + > + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + Unspecified type <xsl:value-of select="$type"/>. + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:template> +</xsl:stylesheet> diff --git a/secret-service/tools/spec-to-docbook.xsl b/secret-service/tools/spec-to-docbook.xsl new file mode 100644 index 0000000..a6b18a3 --- /dev/null +++ b/secret-service/tools/spec-to-docbook.xsl @@ -0,0 +1,1242 @@ +<?xml version="1.0"?> + +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + xmlns:html="http://www.w3.org/1999/xhtml" + xmlns:xlink="http://www.w3.org/1999/xlink" + xmlns:docbook="http://docbook.org/ns/docbook" + exclude-result-prefixes="tp html"> + +<!-- + Telepathy D-Bus Introspection to Docbook XML translator. + Based on Telepathy's doc-generator.xsl. + + Copyright (C) 2006-2008 Collabora Limited + Copyright (C) 2009 Michael Leupold <lemma@confuego.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +--> + + <xsl:output method="xml" indent="yes" encoding="ascii" + omit-xml-declaration="no"/> + + <xsl:include href="resolve-type.xsl"/> + + <xsl:param name="allow-undefined-interfaces" select="false()"/> + + <xsl:template match="docbook:* | html:* | @*"> + <xsl:copy> + <xsl:apply-templates/> + </xsl:copy> + </xsl:template> + + <xsl:template name="direction"> + <xsl:param name="indirection"/> + <xsl:choose> + <xsl:when test="$indirection = 'in'">IN</xsl:when> + <xsl:otherwise>OUT</xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template match="tp:type"> + <xsl:call-template name="tp-type"> + <xsl:with-param name="tp-type" select="string(.)"/> + </xsl:call-template> + </xsl:template> + + <!-- tp:dbus-ref: reference a D-Bus interface, signal, method or property --> + <xsl:template match="tp:dbus-ref"> + <xsl:variable name="name"> + <xsl:choose> + <xsl:when test="@namespace"> + <xsl:value-of select="@namespace"/> + <xsl:text>.</xsl:text> + </xsl:when> + </xsl:choose> + <xsl:value-of select="string(.)"/> + </xsl:variable> + + <xsl:choose> + <xsl:when test="//interface[@name=$name] + or //interface/method[concat(../@name, '.', @name)=$name] + or //interface/signal[concat(../@name, '.', @name)=$name] + or //interface/property[concat(../@name, '.', @name)=$name] + or //interface[@name=concat($name, '.DRAFT')] + or //interface/method[ + concat(../@name, '.', @name)=concat($name, '.DRAFT')] + or //interface/signal[ + concat(../@name, '.', @name)=concat($name, '.DRAFT')] + or //interface/property[ + concat(../@name, '.', @name)=concat($name, '.DRAFT')] + "> + <link linkend="{$name}"> + <literal><xsl:value-of select="$name"/></literal> + </link> + </xsl:when> + + <xsl:when test="$allow-undefined-interfaces"> + <!-- TODO: Convert to docbook --> + <span xmlns="http://www.w3.org/1999/xhtml" title="defined elsewhere"> + <xsl:value-of select="string(.)"/> + </span> + </xsl:when> + + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: cannot find D-Bus interface, method, </xsl:text> + <xsl:text>signal or property called '</xsl:text> + <xsl:value-of select="$name"/> + <xsl:text>' </xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- tp:member-ref: reference a property of the current interface --> + <xsl:template match="tp:member-ref"> + <xsl:variable name="prefix" select="concat(ancestor::interface/@name, + '.')"/> + <xsl:variable name="name" select="string(.)"/> + + <xsl:if test="not(ancestor::interface)"> + <xsl:message terminate="yes"> + <xsl:text>ERR: Cannot use tp:member-ref when not in an</xsl:text> + <xsl:text> <interface> </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:choose> + <xsl:when test="ancestor::interface/signal[@name=$name]"/> + <xsl:when test="ancestor::interface/method[@name=$name]"/> + <xsl:when test="ancestor::interface/property[@name=$name]"/> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: interface </xsl:text> + <xsl:value-of select="ancestor::interface/@name"/> + <xsl:text> has no signal/method/property called </xsl:text> + <xsl:value-of select="$name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + + <link linkend="{$prefix}{$name}"> + <literal><xsl:value-of select="concat($prefix, $name)"/></literal> + </link> + </xsl:template> + + <xsl:template match="*" mode="identity"> + <xsl:copy> + <xsl:apply-templates mode="identity"/> + </xsl:copy> + </xsl:template> + + <xsl:template match="tp:docstring"> + <para> + <xsl:copy-of select="child::node()"/> + </para> + </xsl:template> + + <xsl:template match="tp:docstring" mode="nopara"> + <xsl:copy-of select="child::node()"/> + </xsl:template> + + <xsl:template match="tp:added"> + <para> + Added in version <xsl:value-of select="@version"/>. + <xsl:apply-templates select="node()"/> + </para> + </xsl:template> + + <xsl:template match="tp:changed"> + <xsl:choose> + <xsl:when test="node()"> + <para> + Changed in version <xsl:value-of select="@version"/>: + <xsl:apply-templates select="node()"/></para> + </xsl:when> + <xsl:otherwise> + <para>Changed in version + <xsl:value-of select="@version"/></para> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template match="tp:deprecated"> + <para> + Deprecated since version <xsl:value-of select="@version"/>. + <xsl:apply-templates select="node()"/> + </para> + </xsl:template> + + <xsl:template match="tp:rationale"> + <!-- TODO: special? --> + <para> + <xsl:apply-templates select="node()"/> + </para> + </xsl:template> + + <xsl:template match="tp:errors"> + <title>Errors</title> + <xsl:apply-templates/> + </xsl:template> + + <xsl:template name="generic-types"> + <chapter> + <xsl:attribute name="xml:id">types</xsl:attribute> + <title>Types</title> + <xsl:call-template name="do-types"/> + </chapter> + </xsl:template> + + <xsl:template name="do-types"> + <xsl:if test="tp:simple-type"> + <section> + <title>Simple types</title> + <xsl:apply-templates select="tp:simple-type"/> + </section> + </xsl:if> + + <xsl:if test="tp:enum"> + <section> + <title>Enumerated types</title> + <xsl:apply-templates select="tp:enum"/> + </section> + </xsl:if> + + <xsl:if test="tp:flags"> + <section> + <title>Sets of flags</title> + <xsl:apply-templates select="tp:flags"/> + </section> + </xsl:if> + + <xsl:if test="tp:struct"> + <section> + <title>Struct types</title> + <xsl:apply-templates select="tp:struct"/> + </section> + </xsl:if> + + <xsl:if test="tp:mapping"> + <section> + <title>Map types</title> + <xsl:apply-templates select="tp:mapping"/> + </section> + </xsl:if> + + <xsl:if test="tp:external-type"> + <section> + <title>Types defined elsewhere</title> + <glosslist> + <xsl:apply-templates select="tp:external-type"/> + </glosslist> + </section> + </xsl:if> + </xsl:template> + + <xsl:template match="tp:error"> + <simplesect> + <title> + <xsl:attribute name="xml:id"> + <xsl:value-of select="concat(../@namespace, '.', translate(@name, ' ', ''))"/> + </xsl:attribute> + <literal><xsl:value-of select="concat(../@namespace, '.', translate(@name, ' ', ''))"/></literal> + </title> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </simplesect> + </xsl:template> + + <xsl:template match="/tp:spec/tp:copyright"> + <!-- TODO: use <copyright> --> + <legalnotice> + <para><xsl:apply-templates mode="text"/></para> + </legalnotice> + </xsl:template> + <xsl:template match="/tp:spec/tp:license"> + <!-- TODO: right tag? --> + <legalnotice> + <para> + <xsl:apply-templates/> + </para> + </legalnotice> + </xsl:template> + + <xsl:template match="tp:copyright"/> + <xsl:template match="tp:license"/> + + <xsl:template match="interface"> + + <refentry> + <xsl:attribute name="xml:id"> + <xsl:value-of select="@name"/> + </xsl:attribute> + <refmeta> + <refentrytitle><literal><xsl:value-of select="@name"/></literal></refentrytitle> + </refmeta> + + <refnamediv> + <refdescriptor><xsl:value-of select="@name"/></refdescriptor> + <refname><xsl:value-of select="@name"/></refname> + <refpurpose><xsl:apply-templates select="tp:docstring" mode="nopara"/></refpurpose> + </refnamediv> + + <xsl:if test="tp:added"> + <refsection> + <xsl:apply-templates select="tp:added"/> + </refsection> + </xsl:if> + <xsl:if test="tp:changed"> + <refsection> + <xsl:apply-templates select="tp:changed"/> + </refsection> + </xsl:if> + <xsl:if test="tp:deprecated"> + <refsection> + <xsl:apply-templates select="tp:deprecated"/> + </refsection> + </xsl:if> + + <xsl:if test="@tp:causes-havoc"> + <refsection> + <warning> + <para> + This interface is <xsl:value-of select="@tp:causes-havoc"/> + and is likely to cause havoc to your API/ABI if bindings are generated. + Don't include it in libraries that care about compatibility. + </para> + </warning> + </refsection> + </xsl:if> + + <xsl:if test="tp:requires"> + <refsection> + <tip> + <para>Implementations of this interface must also implement:</para> + <itemizedlist> + <xsl:for-each select="tp:requires"> + <listitem> + <para> + <link linkend="{@interface}"> + <literal><xsl:value-of select="@interface"/></literal> + </link> + </para> + </listitem> + </xsl:for-each> + </itemizedlist> + </tip> + </refsection> + </xsl:if> + + <refsynopsisdiv> + <xsl:if test="method"> + <refsect2> + <title>Methods</title> + <funcsynopsis> + <xsl:apply-templates select="method" mode="funcsynopsislinked"/> + </funcsynopsis> + </refsect2> + </xsl:if> + <xsl:if test="signal"> + <refsect2> + <title>Signals</title> + <funcsynopsis> + <xsl:apply-templates select="signal" mode="funcsynopsislinked"/> + </funcsynopsis> + </refsect2> + </xsl:if> + <xsl:if test="property"> + <refsect2> + <title>Properties</title> + <refsynopsisdiv> + <title> </title> + <xsl:apply-templates select="property" mode="fieldsynopsislinked"/> + </refsynopsisdiv> + </refsect2> + </xsl:if> + </refsynopsisdiv> + + <xsl:if test="method"> + <refsection> + <title>Methods</title> + <xsl:apply-templates select="method" mode="detail"/> + </refsection> + </xsl:if> + + <xsl:if test="signal"> + <refsection> + <title>Signals</title> + <xsl:apply-templates select="signal" mode="detail"/> + </refsection> + </xsl:if> + + <xsl:if test="tp:property"> + <refsection> + <title>Telepathy Properties</title> + <para> + Accessed using the + <link linkend="org.freedesktop.Telepathy.Properties"> + <literal>org.freedesktop.Telepathy.Properties</literal> + </link> + </para> + <glosslist> + <xsl:apply-templates select="tp:property" mode="detail"/> + </glosslist> + </refsection> + </xsl:if> + + <xsl:if test="property"> + <refsection> + <title>D-Bus Properties</title> + <para> + Accessed using the org.freedesktop.DBus.Properties interface. + </para> + <xsl:apply-templates select="property" mode="detail"/> + </refsection> + </xsl:if> + + <xsl:call-template name="do-types"/> + + </refentry> + + </xsl:template> + + <xsl:template match="tp:flags"> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a tp:flags type </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @type on tp:flags type</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <section> + <xsl:attribute name="xml:id"> + <xsl:value-of select="@name"/> + </xsl:attribute> + <title><literal><xsl:value-of select="@name"/></literal></title> + <xsl:apply-templates select="tp:docstring" /> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + <glosslist> + <xsl:variable name="value-prefix"> + <xsl:choose> + <xsl:when test="@value-prefix"> + <xsl:value-of select="@value-prefix"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:for-each select="tp:flag"> + <glossentry> + <glossterm> + <xsl:value-of select="concat($value-prefix, '_', @suffix)"/> = <xsl:value-of select="@value"/> + </glossterm> + <glossdef> + <xsl:choose> + <xsl:when test="tp:docstring"> + <xsl:apply-templates select="tp:docstring" /> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </xsl:when> + <xsl:otherwise> + (Undocumented) + </xsl:otherwise> + </xsl:choose> + </glossdef> + </glossentry> + </xsl:for-each> + </glosslist> + </section> + </xsl:template> + + <xsl:template match="tp:enum"> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a tp:enum type </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @type on tp:enum type</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <section> + <xsl:attribute name="xml:id"> + <xsl:value-of select="concat('type-', @name)"/> + </xsl:attribute> + <title><literal><xsl:value-of select="@name"/></literal></title> + <xsl:apply-templates select="tp:docstring" /> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + <glosslist> + <xsl:variable name="value-prefix"> + <xsl:choose> + <xsl:when test="@value-prefix"> + <xsl:value-of select="@value-prefix"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:for-each select="tp:enumvalue"> + <glossentry> + <glossterm> + <xsl:value-of select="concat($value-prefix, '_', @suffix)"/> = <xsl:value-of select="@value"/> + </glossterm> + <glossdef> + <xsl:choose> + <xsl:when test="tp:docstring"> + <xsl:apply-templates select="tp:docstring" /> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </xsl:when> + <xsl:otherwise> + (Undocumented) + </xsl:otherwise> + </xsl:choose> + </glossdef> + </glossentry> + </xsl:for-each> + </glosslist> + </section> + </xsl:template> + + <xsl:template match="property" mode="fieldsynopsis"> + + <fieldsynopsis> + <xsl:attribute name="xml:id"> + <xsl:value-of select="concat(../@name, '.', @name)"/> + </xsl:attribute> + <modifier> + <xsl:choose> + <xsl:when test="@access = 'read'"> + <xsl:text>READ</xsl:text> + </xsl:when> + <xsl:when test="@access = 'write'"> + <xsl:text>WRITE</xsl:text> + </xsl:when> + <xsl:when test="@access = 'readwrite'"> + <xsl:text>READWRITE</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: unknown or missing value for </xsl:text> + <xsl:text>@access on property </xsl:text> + <xsl:value-of select="concat(../@name, '.', @name)"/> + <xsl:text>: '</xsl:text> + <xsl:value-of select="@access"/> + <xsl:text>' </xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </modifier> + <type> + <xsl:call-template name="ResolveType"> + <xsl:with-param name="node" select="."/> + </xsl:call-template> + </type> + <varname> + <xsl:value-of select="@name"/> + </varname> + </fieldsynopsis> + + </xsl:template> + + <xsl:template match="property" mode="fieldsynopsislinked"> + + <fieldsynopsis> + <modifier> + <xsl:choose> + <xsl:when test="@access = 'read'"> + <xsl:text>READ</xsl:text> + </xsl:when> + <xsl:when test="@access = 'write'"> + <xsl:text>WRITE</xsl:text> + </xsl:when> + <xsl:when test="@access = 'readwrite'"> + <xsl:text>READWRITE</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: unknown or missing value for </xsl:text> + <xsl:text>@access on property </xsl:text> + <xsl:value-of select="concat(../@name, '.', @name)"/> + <xsl:text>: '</xsl:text> + <xsl:value-of select="@access"/> + <xsl:text>' </xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </modifier> + <type> + <xsl:call-template name="ResolveType"> + <xsl:with-param name="node" select="."/> + </xsl:call-template> + </type> + <varname> + <xsl:attribute name="xlink:href"> + <xsl:value-of select="concat('#', ../@name, '.', @name)"/> + </xsl:attribute> + <xsl:value-of select="@name"/> + </varname> + </fieldsynopsis> + + </xsl:template> + + <xsl:template match="property" mode="detail"> + + <xsl:if test="not(parent::interface)"> + <xsl:message terminate="yes"> + <xsl:text>ERR: property </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> does not have an interface as parent </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a property of </xsl:text> + <xsl:value-of select="../@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @type on property </xsl:text> + <xsl:value-of select="concat(../@name, '.', @name)"/> + <xsl:text>: '</xsl:text> + <xsl:value-of select="@access"/> + <xsl:text>' </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:apply-templates select="." mode="fieldsynopsis"/> + + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </xsl:template> + + <xsl:template match="tp:property" mode="detail"> + <glossentry> + <glossterm> + <xsl:if test="@name"> + <xsl:value-of select="@name"/> − + </xsl:if> + <xsl:value-of select="@type"/> + </glossterm> + <glossdef> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </glossdef> + </glossentry> + </xsl:template> + + <xsl:template match="tp:mapping"> + <section> + <xsl:attribute name="xml:id"> + <xsl:value-of select="concat('type-', @name)"/> + </xsl:attribute> + <title> + <literal><xsl:value-of select="@name"/></literal> + </title> + <xsl:apply-templates select="tp:docstring"/> + <xsl:if test="string(@array-name) != ''"> + <para> + In bindings that need a separate name, arrays of + <xsl:value-of select="@name"/> should be called + <xsl:value-of select="@array-name"/>. + </para> + </xsl:if> + <section> + <title>Members</title> + <glosslist> + <xsl:apply-templates select="tp:member" mode="description"/> + </glosslist> + </section> + </section> + </xsl:template> + + <xsl:template match="tp:docstring" mode="in-index"/> + + <xsl:template match="tp:simple-type | tp:enum | tp:flags | tp:external-type" + mode="in-index"> + − <xsl:value-of select="@type"/> + </xsl:template> + + <xsl:template match="tp:simple-type"> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a tp:simple-type </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @type on tp:simple-type</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <section> + <xsl:attribute name="xml:id"> + <xsl:value-of select="concat('type-', @name)"/> + </xsl:attribute> + <title> + <literal><xsl:value-of select="@name"/> − <xsl:value-of select="@type"/></literal> + </title> + <para> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </para> + </section> + </xsl:template> + + <xsl:template match="tp:external-type"> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a tp:external-type </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @type on tp:external-type</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <glossentry> + <glossterm> + <xsl:attribute name="xml:id"> + <xsl:value-of select="concat('type-', @name)"/> + </xsl:attribute> + <xsl:value-of select="@name"/> − <xsl:value-of select="@type"/> + </glossterm> + <glossdef>Defined by: <xsl:value-of select="@from"/></glossdef> + </glossentry> + </xsl:template> + + <xsl:template match="tp:struct" mode="in-index"> + − ( <xsl:for-each select="tp:member"> + <xsl:value-of select="@type"/> + <xsl:if test="position() != last()">, </xsl:if> + </xsl:for-each> ) + </xsl:template> + + <xsl:template match="tp:mapping" mode="in-index"> + − a{ <xsl:for-each select="tp:member"> + <xsl:value-of select="@type"/> + <xsl:if test="position() != last()"> → </xsl:if> + </xsl:for-each> } + </xsl:template> + + <xsl:template match="tp:struct"> + <section> + <xsl:attribute name="xml:id"> + <xsl:value-of select="concat('type-', @name)"/> + </xsl:attribute> + <title> + <literal> + <xsl:value-of select="@name"/> + </literal> + </title> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + <xsl:choose> + <xsl:when test="string(@array-name) != ''"> + <para>In bindings that need a separate name, arrays of + <xsl:value-of select="@name"/> should be called + <xsl:value-of select="@array-name"/>.</para> + </xsl:when> + <xsl:otherwise> + <para>Arrays of <xsl:value-of select="@name"/> don't generally + make sense.</para> + </xsl:otherwise> + </xsl:choose> + <classsynopsis> + <ooclass> + <modifier>struct</modifier> + <classname><xsl:value-of select="@name"/></classname> + </ooclass> + <xsl:apply-templates select="tp:member" mode="fieldsynopsis"/> + </classsynopsis> + <glosslist> + <xsl:apply-templates select="tp:member" mode="description"/> + </glosslist> + </section> + </xsl:template> + + <xsl:template match="arg" mode="paramdef"> + <paramdef> + <xsl:call-template name="direction"> + <xsl:with-param name="indirection" select="@direction"/> + </xsl:call-template> + <xsl:text> </xsl:text> + <type> + <xsl:call-template name="ResolveType"> + <xsl:with-param name="node" select="."/> + </xsl:call-template> + </type> + <xsl:text> </xsl:text> + <parameter><xsl:value-of select="@name"/></parameter> + </paramdef> + </xsl:template> + + <xsl:template match="arg" mode="paramtable"> + <glossentry> + <glossterm><literal><xsl:value-of select="@name"/></literal></glossterm> + <glossdef> + <para><xsl:apply-templates select="tp:docstring" mode="nopara"/></para> + </glossdef> + </glossentry> + </xsl:template> + + <xsl:template match="method|signal" mode="funcsynopsis"> + <funcsynopsis> + <funcprototype> + <funcdef> + <function> + <xsl:value-of select="@name"/> + </function> + </funcdef> + <xsl:choose> + <xsl:when test="arg"> + <xsl:apply-templates select="arg" mode="paramdef"/> + </xsl:when> + <xsl:otherwise> + <void/> + </xsl:otherwise> + </xsl:choose> + </funcprototype> + </funcsynopsis> + </xsl:template> + + <xsl:template match="method|signal" mode="funcsynopsislinked"> + <funcprototype> + <funcdef> + <function linkend="{concat(parent::interface//@name, '.', @name)}"> + <xsl:value-of select="@name"/> + </function> + </funcdef> + <xsl:choose> + <xsl:when test="arg"> + <xsl:apply-templates select="arg" mode="paramdef"/> + </xsl:when> + <xsl:otherwise> + <void/> + </xsl:otherwise> + </xsl:choose> + </funcprototype> + </xsl:template> + + <xsl:template match="method" mode="detail"> + + <xsl:if test="not(parent::interface)"> + <xsl:message terminate="yes"> + <xsl:text>ERR: method </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> does not have an interface as parent </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a method of </xsl:text> + <xsl:value-of select="../@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:for-each select="arg"> + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: an arg of method </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has no type</xsl:text> + </xsl:message> + </xsl:if> + <xsl:choose> + <xsl:when test="@direction='in'"> + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: an 'in' arg of method </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has no name</xsl:text> + </xsl:message> + </xsl:if> + </xsl:when> + <xsl:when test="@direction='out'"> + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="no"> + <xsl:text>INFO: an 'out' arg of method </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has no name</xsl:text> + </xsl:message> + </xsl:if> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: an arg of method </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has direction neither 'in' nor 'out'</xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + + <refsection> + <xsl:attribute name="xml:id"> + <xsl:value-of select="concat(../@name, concat('.', @name))"/> + </xsl:attribute> + <title> + <literal><xsl:value-of select="concat(../@name, concat('.', @name))"/></literal> + </title> + <xsl:apply-templates select="." mode="funcsynopsis"/> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + + <xsl:if test="arg"> + <glosslist> + <xsl:apply-templates select="arg" mode="paramtable"/> + </glosslist> + </xsl:if> + + <xsl:if test="tp:possible-errors"> + <formalpara> + <title>Possible errors</title> + <para> + <glosslist> + <xsl:apply-templates select="tp:possible-errors/tp:error"/> + </glosslist> + </para> + </formalpara> + </xsl:if> + </refsection> + </xsl:template> + + <xsl:template name="tp-type"> + <xsl:param name="tp-type"/> + <xsl:param name="type"/> + + <xsl:variable name="single-type"> + <xsl:choose> + <xsl:when test="contains($tp-type, '[]')"> + <xsl:value-of select="substring-before($tp-type, '[]')"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$tp-type"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="type-of-tp-type"> + <xsl:if test="contains($tp-type, '[]')"> + <!-- one 'a', plus one for each [ after the [], and delete all ] --> + <xsl:value-of select="concat('a', + translate(substring-after($tp-type, '[]'), '[]', 'a'))"/> + </xsl:if> + + <xsl:choose> + <xsl:when test="//tp:simple-type[@name=$single-type]"> + <xsl:value-of select="string(//tp:simple-type[@name=$single-type]/@type)"/> + </xsl:when> + <xsl:when test="//tp:struct[@name=$single-type]"> + <xsl:text>(</xsl:text> + <xsl:for-each select="//tp:struct[@name=$single-type]/tp:member"> + <xsl:value-of select="@type"/> + </xsl:for-each> + <xsl:text>)</xsl:text> + </xsl:when> + <xsl:when test="//tp:enum[@name=$single-type]"> + <xsl:value-of select="string(//tp:enum[@name=$single-type]/@type)"/> + </xsl:when> + <xsl:when test="//tp:flags[@name=$single-type]"> + <xsl:value-of select="string(//tp:flags[@name=$single-type]/@type)"/> + </xsl:when> + <xsl:when test="//tp:mapping[@name=$single-type]"> + <xsl:text>a{</xsl:text> + <xsl:for-each select="//tp:mapping[@name=$single-type]/tp:member"> + <xsl:value-of select="@type"/> + </xsl:for-each> + <xsl:text>}</xsl:text> + </xsl:when> + <xsl:when test="//tp:external-type[@name=$single-type]"> + <xsl:value-of select="string(//tp:external-type[@name=$single-type]/@type)"/> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: Unable to find type '</xsl:text> + <xsl:value-of select="$tp-type"/> + <xsl:text>' </xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:if test="string($type) != '' and + string($type-of-tp-type) != string($type)"> + <xsl:message terminate="yes"> + <xsl:text>ERR: tp:type '</xsl:text> + <xsl:value-of select="$tp-type"/> + <xsl:text>' has D-Bus type '</xsl:text> + <xsl:value-of select="$type-of-tp-type"/> + <xsl:text>' but has been used with type='</xsl:text> + <xsl:value-of select="$type"/> + <xsl:text>' </xsl:text> + </xsl:message> + </xsl:if> + + <link linkend="type-{$single-type}"> + <literal><xsl:value-of select="concat('type-', $single-type)"/></literal> + </link> + + </xsl:template> + + <xsl:template name="parenthesized-tp-type"> + <xsl:if test="@tp:type"> + <xsl:text> (</xsl:text> + <xsl:call-template name="tp-type"> + <xsl:with-param name="tp-type" select="@tp:type"/> + <xsl:with-param name="type" select="@type"/> + </xsl:call-template> + <xsl:text>)</xsl:text> + </xsl:if> + </xsl:template> + + <xsl:template match="tp:member" mode="fieldsynopsis"> + <xsl:variable name="type"> + <xsl:call-template name="ResolveType"> + <xsl:with-param name="node" select="."/> + </xsl:call-template> + </xsl:variable> + <fieldsynopsis> + <type><xsl:value-of select="normalize-space($type)"/></type> + <varname><xsl:value-of select="@name"/></varname> + </fieldsynopsis> + </xsl:template> + + <xsl:template match="tp:member" mode="description"> + <glossentry> + <glossterm> + <varname><xsl:value-of select="@name"/></varname> + </glossterm> + <glossdef> + <xsl:choose> + <xsl:when test="tp:docstring"> + <xsl:apply-templates select="tp:docstring" /> + </xsl:when> + <xsl:otherwise> + <!-- emphasize --> + (undocumented) + </xsl:otherwise> + </xsl:choose> + </glossdef> + </glossentry> + </xsl:template> + + <xsl:template match="tp:possible-errors/tp:error"> + <glossentry> + <glossterm> + <xsl:value-of select="@name"/> + </glossterm> + <glossdef> + <xsl:variable name="name" select="@name"/> + <xsl:choose> + <xsl:when test="tp:docstring"> + <xsl:apply-templates select="tp:docstring"/> + </xsl:when> + <xsl:when test="//tp:errors/tp:error[concat(../@namespace, '.', translate(@name, ' ', ''))=$name]/tp:docstring"> + <xsl:apply-templates select="//tp:errors/tp:error[concat(../@namespace, '.', translate(@name, ' ', ''))=$name]/tp:docstring"/> <!-- TODO: emphasize -->(generic description) + </xsl:when> + <xsl:otherwise> + (Undocumented.) + </xsl:otherwise> + </xsl:choose> + </glossdef> + </glossentry> + </xsl:template> + + <xsl:template match="signal" mode="detail"> + + <xsl:if test="not(parent::interface)"> + <xsl:message terminate="yes"> + <xsl:text>ERR: signal </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> does not have an interface as parent </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a signal of </xsl:text> + <xsl:value-of select="../@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:for-each select="arg"> + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: an arg of signal </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has no type</xsl:text> + </xsl:message> + </xsl:if> + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: an arg of signal </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has no name</xsl:text> + </xsl:message> + </xsl:if> + <xsl:choose> + <xsl:when test="not(@direction)"/> + <xsl:when test="@direction='in'"/> + <!-- This doesn't work with the DTD (see comment in DTD) + <xsl:when test="@direction='in'"> + <xsl:message terminate="no"> + <xsl:text>INFO: an arg of signal </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has unnecessary direction 'in'</xsl:text> + </xsl:message> + </xsl:when> + --> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: an arg of signal </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has direction other than 'in'</xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + + <refsection> + <xsl:attribute name="xml:id"> + <xsl:value-of select="concat(../@name, concat('.', @name))"/> + </xsl:attribute> + <title> + <literal><xsl:value-of select="concat(../@name, concat('.', @name))"/></literal> + </title> + <xsl:apply-templates select="." mode="funcsynopsis"/> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + + <xsl:if test="arg"> + <glosslist> + <xsl:apply-templates select="arg" mode="paramtable"/> + </glosslist> + </xsl:if> + </refsection> + </xsl:template> + + <xsl:template match="/tp:spec"> + <book xmlns="http://docbook.org/ns/docbook" version="5.0"> + <bookinfo> + <title><xsl:value-of select="tp:title"/></title> + <xsl:apply-templates select="tp:copyright"/> + <xsl:apply-templates select="tp:license"/> + <xsl:if test="tp:docstring"> + <abstract> + <xsl:apply-templates select="tp:docstring"/> + </abstract> + </xsl:if> + <!-- TODO: Version + <xsl:if test="tp:version"> + <xsl:text> version </xsl:text> + <xsl:value-of select="tp:version"/> + </xsl:if> --> + </bookinfo> + <chapter> + <xsl:attribute name="xml:id">interfaces</xsl:attribute> + <title>Interfaces</title> + <xsl:apply-templates select="//node"/> + </chapter> + <xsl:call-template name="generic-types"/> + <xsl:if test="tp:errors"> + <chapter> + <xsl:attribute name="xml:id">errors</xsl:attribute> + <xsl:apply-templates select="tp:errors"/> + </chapter> + </xsl:if> + </book> + </xsl:template> + + <xsl:template match="node"> + <xsl:apply-templates /> + </xsl:template> + + <xsl:template match="text()"> + <xsl:if test="normalize-space(.) != ''"> + <xsl:message terminate="yes"> + <xsl:text>Stray text: {{{</xsl:text> + <xsl:value-of select="." /> + <xsl:text>}}} </xsl:text> + </xsl:message> + </xsl:if> + </xsl:template> + + <xsl:template match="*"> + <xsl:message terminate="yes"> + <xsl:text>Unrecognised element: {</xsl:text> + <xsl:value-of select="namespace-uri(.)" /> + <xsl:text>}</xsl:text> + <xsl:value-of select="local-name(.)" /> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:template> +</xsl:stylesheet> + +<!-- vim:set sw=2 sts=2 et: --> diff --git a/secret-service/tools/spec-to-introspect.xsl b/secret-service/tools/spec-to-introspect.xsl new file mode 100644 index 0000000..ca8b4b6 --- /dev/null +++ b/secret-service/tools/spec-to-introspect.xsl @@ -0,0 +1,147 @@ +<?xml version="1.0"?> +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + exclude-result-prefixes="tp"> + +<!-- + Telepathy D-Bus Introspection to EggDBus Introspection format translator. + + Copyright 2009 Michael Leupold <lemma@confuego.org> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +--> + +<!-- + TODO: + - Enable conversion of dictionary element types (eg. "{ss}") and + struct types (eg. "(sayay)") + - unhandled: tp:simple-type, tp:enum, tp:flags, tp:external-type + - tp:docstring may contain XHTML which this template doesn't handle +--> + + <xsl:include href="resolve-type.xsl"/> + + <!-- main template --> + <xsl:template match="tp:spec"> + <node> + <xsl:apply-templates select="tp:errors"/> + <xsl:apply-templates select="tp:struct"/> + <!-- TODO: <xsl:apply-templates select="tp:mapping"/> --> + <xsl:apply-templates select="node/interface"/> + </node> + </xsl:template> + + <!-- handle most of the D-Bus introspection elements --> + <xsl:template match="interface|annotation|method|signal"> + <xsl:copy> + <xsl:for-each select="@*"> + <xsl:if test="not(starts-with(name(), 'tp:'))"> + <xsl:copy/> + </xsl:if> + </xsl:for-each> + <xsl:apply-templates/> + </xsl:copy> + </xsl:template> + + <!-- handle the arg and property D-Bus introspection elements. + They get special handling because they may contain a tp:type + attribute --> + <xsl:template match="arg|property"> + <xsl:copy> + <xsl:for-each select="@*"> + <xsl:choose> + <xsl:when test="not(starts-with(name(), 'tp:'))"> + <xsl:copy/> + </xsl:when> + <xsl:when test="name() = 'tp:type'"> + <xsl:variable name="type"> + <xsl:call-template name="TpType"> + <xsl:with-param name="type" select="."/> + </xsl:call-template> + </xsl:variable> + <annotation name="org.gtk.EggDBus.Type"> + <xsl:attribute name="value"> + <xsl:value-of select="translate(translate($type, ' ', ''), '
', '')"/> + </xsl:attribute> + </annotation> + </xsl:when> + <xsl:otherwise/> + </xsl:choose> + </xsl:for-each> + <xsl:apply-templates/> + </xsl:copy> + </xsl:template> + + <!-- tp:docstring to org.gtk.EggDBus.DocString --> + <xsl:template match="tp:docstring"> + <annotation name="org.gtk.EggDBus.DocString"> + <xsl:attribute name="value"> + <xsl:value-of select="normalize-space(text())"/> + </xsl:attribute> + </annotation> + </xsl:template> + + <!-- tp:errors to org.gtk.EggDBus.DeclareErrorDomain --> + <xsl:template match="tp:errors"> + <annotation value="Error" name="org.gtk.EggDBus.DeclareErrorDomain"> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:error"/> + </annotation> + </xsl:template> + + <!-- tp:error to org.gtk.EggDBus.ErrorDomain.Member --> + <xsl:template match="tp:error"> + <annotation name="org.gtk.EggDBus.ErrorDomain.Member"> + <xsl:attribute name="value"> + <xsl:value-of select="concat(../@namespace, '.', @name)"/> + </xsl:attribute> + <xsl:apply-templates select="tp:docstring"/> + </annotation> + </xsl:template> + + <!-- tp:struct to org.gtk.EggDBus.DeclareStruct --> + <xsl:template match="tp:struct"> + <annotation name="org.gtk.EggDBus.DeclareStruct"> + <xsl:attribute name="value"> + <xsl:value-of select="@name"/> + </xsl:attribute> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:member"/> + </annotation> + </xsl:template> + + <!-- tp:member to org.gtk.EggDBus.Struct.Member --> + <xsl:template match="tp:member"> + <xsl:variable name="type"> + <xsl:call-template name="ResolveType"> + <xsl:with-param name="node" select="."/> + </xsl:call-template> + </xsl:variable> + <annotation name="org.gtk.EggDBus.Struct.Member"> + <xsl:attribute name="value"> + <xsl:value-of select="concat(normalize-space($type), ':', @name)"/> + </xsl:attribute> + <xsl:apply-templates select="tp:docstring"/> + </annotation> + </xsl:template> + + <xsl:template match="text()"/> + + <xsl:output method="xml" indent="yes" encoding="UTF-8" + omit-xml-declaration="no" + doctype-system="http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd" + doctype-public="-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"/> + +</xsl:stylesheet> diff --git a/systemtray/ChangeLog b/systemtray/ChangeLog new file mode 100644 index 0000000..9487095 --- /dev/null +++ b/systemtray/ChangeLog @@ -0,0 +1,10 @@ +2009-01-10 Vincent Untz <vuntz@gnome.org> + + * systemtray-spec.xml: add _NET_SYSTEM_TRAY_VISUAL and a description of + visual and background pixmap handling.. + See http://lists.freedesktop.org/archives/xdg/2009-January/010122.html + +2004-11-30 Mark McLoughlin <mark@skynet.ie> + + * systemtray-spec.xml: add _NET_SYSTEM_TRAY_ORIENTATION. + diff --git a/systemtray/systemtray-spec.xml b/systemtray/systemtray-spec.xml new file mode 100644 index 0000000..669f3d0 --- /dev/null +++ b/systemtray/systemtray-spec.xml @@ -0,0 +1,444 @@ +<?xml version="1.0"?> +<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" +"http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ +]> +<article id="index"> + <articleinfo> + <title>System Tray Protocol Specification</title> + <releaseinfo>Version 0.3</releaseinfo> + <date>10 January 2009</date> + <authorgroup> + <author> + <firstname>Havoc</firstname> + <surname>Pennington</surname> + <affiliation> + <address> + <email>hp@redhat.com</email> + </address> + </affiliation> + </author> + </authorgroup> + </articleinfo> + + <sect1 id="overview"> + <title>Overview</title> + <para> + The "system tray" is an application running on a given X screen + that can display small icons provided by running + applications. Windows XP calls this feature the "notification area." + <footnote><para>According to the MSDN documentation for the + <literal>Shell_NotifyIcon()</literal> function, + "The taskbar notification area is sometimes erroneously called + the 'tray.'" So presumably "notification area" is the official + term on Windows. Parts of the docs also call it the "status + area."</para></footnote> Inspired by KDE, this specification + uses the term "system tray." + </para> + <para> + From a UI standpoint, the system tray is normally used for + transient icons that indicate some special state, while + full-blown "applets" are used for permanent dock/panel + features. For example, a system tray icon might appear to tell + the user that they have new mail, or have an incoming instant + message, or something along those lines. + </para> + <para> + The basic idea is that creating an icon in the notification + area is less annoying than popping up a dialog. However it's + also harder to notice, so Windows XP adds a feature allowing + tray icons to pop up small message balloons. (Users can disable + these via a hidden registry setting.) This specification + also supports the balloon feature. + </para> + </sect1> + + <sect1 id="definitions"> + <title>Definitions</title> + <variablelist> + <varlistentry> + <term>System tray</term> + <listitem> + <para> + The system tray is an X client which owns a special + manager selection on a given screen and provides + container windows. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>Selection owner window</term> + <listitem> + <para> + The selection owner window is the window belonging to the + System Tray that owns the manager selection (as in + <literal>XGetSelectionOwner()</literal>/<literal>XSetSelectionOwner()</literal>. + Note that this probably is not the same window that's used + to contain the system tray icons. + </para> + </listitem> + </varlistentry> + <varlistentry> + <term>Tray icon</term> + <listitem> + <para> + The tray icon is a window to be embedded in the + system tray. + </para> + </listitem> + </varlistentry> + </variablelist> + </sect1> + + <sect1 id="locating"> + <title>Locating the system tray</title> + <para> + On startup, the system tray must acquire a manager selection + called <literal>_NET_SYSTEM_TRAY_Sn</literal>, replacing + <literal>n</literal> with the screen number the tray wants to + use. The conventions for manager selections are defined in the + ICCCM. + </para> + <para> + Because the selection owner window should be destroyed when the + manager selection is lost, normally the selection owner window + will not be the same as any of the user-visible windows provided + by the system tray. + </para> + <para> + A system tray that fails to get the selection or loses the + selection should assume that another system tray is running, + and let the selection owner handle tray icons. + </para> + <para> + An application wishing to provide an icon to the system tray + should first locate the system tray by requesting the owner + window of the manager selection. If the manager selection has no + owner, clients may use the method described in the ICCCM + (watching for a <literal>MANAGER</literal> client message) to be + notified when a system tray appears. + </para> + </sect1> + + <sect1 id="messages"> + <title>Opcode messages</title> + <para> + Tray icons can send "opcodes" to + the system tray. These are X client messages, sent with + <literal>NoEventMask</literal>, a + <literal>message_type</literal> of + <literal>_NET_SYSTEM_TRAY_OPCODE</literal>, and format 32. + The first data field in the message is a timestamp (the stamp + of the current event, if available, otherwise CurrentTime). + The second data field is an integer indicating the op code + of the message: + <programlisting> +#define SYSTEM_TRAY_REQUEST_DOCK 0 +#define SYSTEM_TRAY_BEGIN_MESSAGE 1 +#define SYSTEM_TRAY_CANCEL_MESSAGE 2 + </programlisting> + The content remaining three data fields depends on the type of + message being sent. If they are unused by a particular + message, they should always be set to 0. + </para> + <para> + Here is an example of how to send a client message: + <programlisting><!-- +-->#include <X11/Xlib.h> + +void send_message( + Display* dpy, /* display */ + Window w, /* sender (tray icon window) */ + long message, /* message opcode */ + long data1 /* message data 1 */ + long data2 /* message data 2 */ + long data3 /* message data 3 */ +){ + XEvent ev; + + memset(&ev, 0, sizeof(ev)); + ev.xclient.type = ClientMessage; + ev.xclient.window = w; + ev.xclient.message_type = XInternAtom (dpy, "_NET_SYSTEM_TRAY_OPCODE", False ); + ev.xclient.format = 32; + ev.xclient.data.l[0] = x_time; + ev.xclient.data.l[1] = message; + ev.xclient.data.l[2] = data1; + ev.xclient.data.l[3] = data2; + ev.xclient.data.l[4] = data3; + + trap_errors(); + XSendEvent(dpy, w, False, NoEventMask, &ev); + XSync(dpy, False); + if (untrap_errors()) { + /* Handle failure */ + } +}<!-- + --></programlisting> + + </para> + + </sect1> + + <sect1 id="docking"> + <title>Docking a tray icon</title> + <para> + A tray icon must support the "client" or "plug" side of the + XEMBED specification. XEMBED is a protocol for cross-toolkit + widget embedding. + </para> + <para> + To begin the docking process, the tray icon application sends + a client message event to the manager selection owner window, + as described in <xref linkend="messages"/>. This event + should contain the <literal>SYSTEM_TRAY_REQUEST_DOCK</literal> + opcode, <literal>xclient.data.l[2]</literal> should contain + the X window ID of the tray icon to be docked. + </para> + <para> + At this point the "embedding life cycle" explained in the XEMBED + specification begins. The XEMBED specification explains how the + embedding application will interact with the embedded tray + icon, and how the embedder/embedded relationship may be ended. + </para> + <para> + Tray icons may be assigned any size by the system tray, and + should do their best to cope with any size effectively. + </para> + </sect1> + + <sect1 id="visuals"> + <title>Visual and background pixmap handling</title> + <para> + If the _NET_SYSTEM_TRAY_VISUAL property (see below) is present, + tray icon windows should be created using that visual. If the + property is not present, then tray icon windows should be + created using the default visual of the screen. + </para> + <para> + Historically, to allow the appearance of icons with transparent + backgrounds on servers that did not support visuals with an + alpha channel or the Composite extension, a convention was + adopted where a background pixmap was set on the XEMBED embedder + window, aligned properly to match the contents of the embedder + window's parent, the tray icon window was set to have a + background of ParentRelative, and drawing of the icon done on + top of this background. + </para> + <para> + Setting the background of a window to ParentRelative when the + depth of the window does not match the depth of the window's + parent, or reparenting a window with a ParentRelative + background into a parent with a non-matching depth produces a + BadMatch error, so the embedder window must be created to match + the visual of the tray icon window, even if the tray icon window + does not have the visual provided in _NET_SYSTEM_TRAY_VISUAL. If + convenient, the tray manager may set an appropriate background + pixmap on the embedder window to provide the appearance of + transparency. However, the preferred method of transparency is + to use a visual with an alpha channel in _NET_SYSTEM_TRAY_VISUAL. + </para> + </sect1> + + <sect1 id="hints"> + <title>Tray icon hints</title> + <para> + Tray icons should set the following hints to help the system + tray provide a nice user interface. The name and icon hints + are used if the system tray needs to refer to a tray icon; + for example, the system tray may present a list of tray + icons and let the user reorder them or change their properties. + </para> + + <sect2><title>_NET_WM_NAME</title> + <programlisting><![CDATA[ +_NET_WM_NAME, UTF8_STRING +]]></programlisting> + <para> + This hint should be set as it would be for a normal toplevel + window, as defined in the Extended Window Manager Hints + Specification (EWMH). The hint MUST be in UTF-8 encoding. It + provides a human-readable, localized name for the tray icon. + </para> + </sect2> + + <sect2><title>WM_CLASS</title> + <programlisting><![CDATA[ +WM_CLASS, STRING +]]></programlisting> + <para> + This hint should be set as it would be for a normal toplevel + window, as defined in the ICCCM. The system tray can use it + to distinguish different kinds of tray icon. This is useful + for example if the system tray wants to save and restore the + positions of the icons in the tray. + </para> + </sect2> + + <sect2> + <title>_NET_WM_ICON</title> + <programlisting><![CDATA[ +_NET_WM_ICON CARDINAL[][2+n]/32 +]]></programlisting> + <para> + This hint should be set as it would be for a normal toplevel + window, as defined in the Extended Window Manager Hints + Specification (EWMH). See that specification for the format + of the icon data. + </para> + </sect2> + + </sect1> + + <sect1 id="manager-hints"> + <title>Tray manager hints</title> + <para> +The tray manager should set the following hints on the selection +owner window. + </para> + + <sect2> + <title>_NET_SYSTEM_TRAY_ORIENTATION</title> + <programlisting><![CDATA[ +_NET_SYSTEM_TRAY_ORIENTATION orientation CARDINAL/32 +]]> + #define _NET_SYSTEM_TRAY_ORIENTATION_HORZ 0 + #define _NET_SYSTEM_TRAY_ORIENTATION_VERT 1 + </programlisting> + + <para> +The property should be set by the tray manager to indicate the current +orientation of the tray. Tray icons may use this hint in order to +maintain the icon's aspect ratio and also as an indication of how the +icon contents should be laid out. + </para> + + </sect2> + + <sect2> + <title>_NET_SYSTEM_TRAY_VISUAL</title> + <programlisting><![CDATA[ +_NET_SYSTEM_TRAY_VISUAL visual_id VISUALID/32 +]]> + </programlisting> + + <para> +The property should be set by the tray manager to indicate the preferred +visual for icon windows. To avoid ambiguity about the colormap to use +this visual must either be the default visual for the screen or it +must be a TrueColor visual. If this property is set to a visual with +an alpha channel, the tray manager must use the Composite extension to +composite the icon against the background using PictOpOver. + </para> + + </sect2> + </sect1> + + <sect1 id="balloon"> + <title>Balloon messages</title> + <para> + Tray icons may ask the system tray to display a balloon message + to the user. The system tray coordinates balloon messages + to ensure that they have a consistent look-and-feel, and to + avoid displaying multiple balloon messages at once. + </para> + <para> + A balloon message is a short text message to be displayed to + the user. The message may have a timeout; if so, the message + will be taken down after the timeout expires. Messages are + displayed in a queue, as only one can appear at a time; + if a message has a timeout, the timer begins when the message + is first displayed. Users may be allowed to close messages at + any time, and may be allowed to disable all message display. + </para> + <para> + System trays may display balloon messages in any way they + see fit; for example, instead of popping up a balloon, they + could choose to put a special indicator around icons with + pending messages, and display the message on mouseover. + </para> + <para> + Balloon messages are sent from the tray icon to the system tray + selection owner window as a series of client messages. The first + client message is an opcode message, and contains the usual timestamp, + and the op code <literal>SYSTEM_TRAY_BEGIN_MESSAGE</literal>. + <literal>xclient.data.l[2]</literal> contains the timeout in + thousandths of a second or zero for infinite timeout, + <literal>xclient.data.l[3]</literal> contains the length + of the message string in bytes, not including any nul bytes, and + <literal>xclient.data.l[4]</literal> contains an ID number + for the message. This ID number should never be reused by + the same tray icon. (The simplest way to generate the ID number + is to increment it with each message sent.) + </para> + <para> + Following the <literal>SYSTEM_TRAY_BEGIN_MESSAGE</literal> + op code, the tray icon should send a series of client messages + with a <literal>message_type</literal> of + <literal>_NET_SYSTEM_TRAY_MESSAGE_DATA</literal>. These client + messages must have their <literal>window</literal> field set + to the window ID of the tray icon, and have a + <literal>format</literal> of 8. + </para> + <para> + Each <literal>_NET_SYSTEM_TRAY_MESSAGE_DATA</literal> message + contains 20 bytes of the message string, up to the length given + in the <literal>SYSTEM_TRAY_BEGIN_MESSAGE</literal> opcode. + If the message string is zero-length, then no messages need be + sent beyond the <literal>SYSTEM_TRAY_BEGIN_MESSAGE</literal>. + A terminating nul byte should never be sent. + </para> + <para> + System trays may receive portions of messages from several + tray icons at once, so are required to reassemble the messages + based on the window ID of the tray icon. + </para> + <para> + The tray icon may wish to cancel a previously-sent balloon + message. To do so, it sends a + <literal>SYSTEM_TRAY_CANCEL_MESSAGE</literal> opcode with + <literal>data.l[2]</literal> set to the ID number of the message + to cancel. + </para> + </sect1> + + <appendix id="changes"> + <title>Change history</title> + <formalpara> + <title>Version 0.3, 10 January 2009, Owen Taylor</title> + <para> + <itemizedlist> + <listitem> + <para> + Added the _NET_SYSTEM_TRAY_VISUAL hint and a + description of visual and background pixmap handling. + </para> + </listitem> + </itemizedlist> + </para> + </formalpara> + <formalpara> + <title>Version 0.2, 23 November 2004, Mark McLoughlin</title> + <para> + <itemizedlist> + <listitem> + <para> + Added the _NET_SYSTEM_TRAY_ORIENTATION hint. + </para> + </listitem> + </itemizedlist> + </para> + </formalpara> + <formalpara> + <title>Version 0.1, 20 April 2002, Havoc Pennington</title> + <para> + <itemizedlist> + <listitem> + <para> + Created initial draft. + </para> + </listitem> + </itemizedlist> + </para> + </formalpara> + </appendix> +</article> |