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