/usr/share/perl5/X11/FreeDesktop/DesktopEntry.pm is in libx11-freedesktop-desktopentry-perl 0.04-3.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 | # $Id: DesktopEntry.pm,v 1.9 2005/01/12 17:13:02 jodrell Exp $
# Copyright (c) 2005 Gavin Brown. All rights reserved. This program is
# free software; you can redistribute it and/or modify it under the same
# terms as Perl itself.
package X11::FreeDesktop::DesktopEntry;
use Carp;
use vars qw($VERSION $ROOT_GROUP $DEFAULT_GROUP $DEFAULT_LOCALE @REQUIRED $VERBOSE $SILENT);
use utf8;
use strict;
our $VERSION = '0.04';
our $ROOT_GROUP = '_root';
our $DEFAULT_GROUP = 'Desktop Entry';
our $DEFAULT_LOCALE = 'C';
our @REQUIRED = qw(Encoding Name Type);
our $VERBOSE = 0;
our $SILENT = 0;
=pod
=head1 NAME
X11::FreeDesktop::DesktopEntry - an interface to Freedesktop.org .desktop files.
=head1 SYNOPSIS
use X11::FreeDesktop::DesktopEntry;
my $entry = X11::FreeDesktop::DesktopEntry->new_from_data($data);
print $entry->get_value('Name');
print $entry->Exec;
$entry->set_value('Name', 'Example Program');
print $entry->as_string;
$entry->reset;
=head1 DESCRIPTION
This module provides an object-oriented interface to files that comply with the
Freedesktop.org desktop entry specification. You can query the file for
available values, modify them, and also get locale information as well.
=head1 CONSTRUCTOR
X11::FreeDesktop::DesktopEntry doesn't have the standard C<new()> constructor.
This allows subclasses to implement their own backend-specific constructor
without needing to re-implement the constructor, which can be a pain I<(for an
example subclass that uses L<Gnome2::VFS> as a backend, see the C<PerlPanel::DesktopEntry>
module in the PerlPanel distribution)>.
my $entry = X11::FreeDesktop::DesktopEntry->new_from_data($data);
If there is an error reading or parsing the data, the constructor will
C<carp()> and return an undefined value.
=cut
sub new_from_data {
my ($package, $data) = @_;
my $self = { _raw => $data };
bless($self, $package);
return undef unless ($self->parse);
return $self;
}
sub parse {
my $self = shift;
my @lines = split(/[\r\n]/, $self->{_raw});
my ($current_group, $last_key);
for (my $i = 0 ; $i < scalar(@lines) ; $i++) {
chomp(my $line = $lines[$i]);
if ($line =~ /^[\s\t\r\n]*$/) {
# ignore whitespace:
next;
} elsif ($line =~ /^\s*\#(.+)$/) {
# the spec requires that we be able to preserve comments, so
# we need to note the position that the comment occurred at, relative
# to the current group and last key:
push(@{$self->{comments}->{(defined($current_group) ? $current_group : $ROOT_GROUP)}->{$last_key}}, $1);
} elsif ($line =~ /^\[([^\[]+)\]/) {
# defines a new group:
$current_group = $1;
$self->{data}->{$current_group} = {};
} elsif ($current_group ne '') {
# got a key=value pair:
my ($key, $value) = split(/\s*=\s*/, $line, 2);
$last_key = $key;
my $locale = $DEFAULT_LOCALE;
# check for the Key[postfix] format:
if ($key =~ /\[([^\[]+)\]$/) {
$locale = $1;
$key =~ s/\[$locale\]$//;
}
if (defined($self->{data}->{$current_group}->{$key}->{$locale})) {
carp(sprintf(
'Parse error on %s line %s: value already exists for \'%s\' in \'%s\', skipping later entry',
$self->{uri},
$i+1,
$last_key,
$current_group,
)) if ($VERBOSE == 1);
} else {
$self->{data}->{$current_group}->{$key}->{$locale} = $value;
}
} else {
# an error:
carp(sprintf('Parse error on %s line %s: no group name defined', $self->{uri}, $i+1)) unless ($SILENT == 1);
return undef;
}
}
return 1;
}
=pod
=head1 METHODS
$entry->is_valid($locale);
Returns a true or false valid depending on whether the required keys exist for
the given C<$locale>. A list of the required keys can be found in the
Freedesktop.org specification. If C<$locale> is omitted, it will default to
'C<C>'.
=cut
sub is_valid {
my ($self, $locale) = @_;
$locale = (defined($locale) ? $locale : $DEFAULT_LOCALE);
foreach my $key (@REQUIRED) {
if (!defined($self->get_value($key, $DEFAULT_GROUP, $locale))) {
return undef;
}
}
return 1;
}
=pod
my @groups = $entry->groups;
This returns an array of scalars containing the I<group names> included in the
file. Groups are defined by a line like the following in the file itself:
[Desktop Entry]
A valid desktop entry file will always have one of these, at the top.
=cut
sub groups {
return keys(%{$_[0]->{data}});
}
=pod
$entry->has_group($group);
Returns true or false depending on whether the file has a section with the name
of C<$group>.
=cut
sub has_group {
return defined($_[0]->{data}->{$_[1]});
}
=pod
my @keys = $entry->keys($group, $locale);
Returns an array of the available keys in C<$group> and the C<$locale> locale.
Both these values revert to defaults if they're undefined. When C<$locale> is
defined, the array will be folded in with the keys from 'C<C>', since locales
inherit keys from the default locale. See the C<get_value()> method for
another example of this inheritance.
=cut
sub keys {
my ($self, $group, $locale) = @_;
$group = (defined($group) ? $group : $DEFAULT_GROUP);
my %keys;
foreach my $key (CORE::keys(%{$self->{data}->{$group}})) {
# add the key if $locale is defined and a value exists for that locale, or if $locale isn't defined:
$keys{$key}++ if ((defined($locale) && defined($self->{data}->{$group}->{$key}->{$locale})) || !defined($locale));
}
if ($locale ne $DEFAULT_LOCALE) {
# fold in the keys for the default locale:
foreach my $key ($self->keys($group, $DEFAULT_LOCALE)) {
$keys{$key}++;
}
}
return sort(keys(%keys));
}
=pod
$entry->has_key($key, $group);
Returns true or false depending on whether the file has a key with the name of
C<$key> in the C<$group> section. If C<$group> is omitted, then the default
group (C<'Desktop Entry'>) will be used.
=cut
sub has_key {
return defined($_[0]->{data}->{defined($_[2]) ? $_[2] : $DEFAULT_GROUP}->{$_[1]});
}
=pod
my @locales = $entry->locales($key, $group);
Returns an array of strings naming all the available locales for the given
C<$key>. If C<$key> or C<$group> don't exist in the file, this method will
C<carp()> and return undef. There should always be at least one locale in the
returned array - the default locale, 'C<C>'.
=cut
sub locales {
my ($self, $key, $group) = @_;
$group = (defined($group) ? $group : $DEFAULT_GROUP);
if (!$self->has_group($group)) {
carp(sprintf('get_value(): no \'%s\' group found', $group)) if ($VERBOSE == 1);
return undef;
} elsif (!$self->has_key($key, $group)) {
carp(sprintf('get_value(): no \'%s\' key found in \'%s\'', $key, $group)) if ($VERBOSE == 1);
return undef;
} else {
return CORE::keys(%{$self->{data}->{$group}->{$key}});
}
}
=pod
my $string = $entry->get_value($key, $group, $locale);
Returns the value of the key named by C<$key>. C<$group> is optional, and will
be set to the default if omitted (see above). C<$locale> is also optional, and
defines the locale for the string (defaults to 'C<C>' if omitted). If the
requested key does not exist for a non-default C<$locale> of the form C<xx_YY>,
then the module will search for a value for the C<xx> locale. If nothing is
found, this method will attempt to return the value for the 'C<C>' locale. If
this value does not exist, this method will return undef.
=cut
sub get_value {
my ($self, $key, $group, $locale) = @_;
$group = (defined($group) ? $group : $DEFAULT_GROUP);
$locale = (defined($locale) ? $locale : $DEFAULT_LOCALE);
($locale, undef) = split(/\./, $locale, 2); # in case locale is of the form xx_YY.UTF-8
my $rval;
if (!defined($self->{data}->{$group}->{$key}->{$locale})) {
if ($locale =~ /^[a-z]{2}_[A-Z]{2}$/) {
my ($base, undef) = split(/_/, $locale, 2);
$rval = $self->get_value($key, $group, $base);
} else {
$rval = ($locale eq $DEFAULT_LOCALE ? undef : $self->get_value($key, $group, $DEFAULT_LOCALE));
}
} else {
$rval = $self->{data}->{$group}->{$key}->{$locale};
}
utf8::decode($rval);
return $rval;
}
=pod
$entry->set_value($key, $value, $locale, $group);
This method sets the value of the C<$key> key in the C<$locale> locale and
C<$group> group to be C<$value>. If C<$locale> and C<$group> are omitted, the
defaults are used. C<$value> is always interpreted as a string. This method
always returns true.
=cut
sub set_value {
my ($self, $key, $value, $locale, $group) = @_;
$group = (defined($group) ? $group : $DEFAULT_GROUP);
$locale = (defined($locale) ? $locale : $DEFAULT_LOCALE);
($locale, undef) = split(/\./, $locale, 2); # in case locale is of the form xx_YY.UTF-8
$self->{data}->{$group}->{$key}->{$locale} = $value;
return 1;
}
=pod
my $data = $entry->as_string;
This method returns a scalar containing the full entry in .desktop format. This
data can then be used to write the entry to disk.
=cut
sub as_string {
my $self = shift;
my $data;
if (defined($self->{comments}->{$ROOT_GROUP})) {
foreach my $key (CORE::keys(%{$self->{comments}->{$ROOT_GROUP}})) {
foreach my $comment (@{$self->{comments}->{$ROOT_GROUP}->{$key}}) {
$data .= sprintf("# %s\n", $comment);
}
}
}
foreach my $group (sort($self->groups)) {
$data .= sprintf("[%s]\n", $group);
if (defined($self->{comments}->{$group}) && defined($self->{comments}->{$group}->{''})) {
foreach my $comment (@{$self->{comments}->{$group}->{''}}) {
$data .= sprintf("# %s\n", $comment);
}
}
foreach my $key (sort($self->keys($group))) {
foreach my $locale (sort($self->locales($key, $group))) {
my $name = sprintf('%s%s', $key, ($locale ne $DEFAULT_LOCALE ? sprintf('[%s]', $locale) : ''));
$data .= sprintf("%s=%s\n", $name, $self->get_value($key, $group, $locale));
if (defined($self->{comments}->{$group}) && defined($self->{comments}->{$group}->{$name})) {
foreach my $comment (@{$self->{comments}->{$group}->{$name}}) {
$data .= sprintf("# %s\n", $comment);
}
}
}
}
$data .= "\n";
}
return $data;
}
=pod
$entry->reset;
This method restores the entry to its initial state - it undoes any changes
made to the values stored in the entry.
=cut
sub reset {
my $self = shift;
$self->{data} = {};
return $self->parse;
}
=pod
=head1 CONVENIENCE METHODS
my $name = $entry->Name($locale);
my $generic_name = $entry->GenericName($locale);
my $comment = $entry->Comment($locale);
my $type = $entry->Type($locale);
my $icon = $entry->Icon($locale);
my $exec = $entry->Exec($locale);
my $url = $entry->URL($locale);
my $startup_notify = $entry->StartupNotify($locale);
These methods are shortcuts for the mostly commonly accessed fields from a
desktop entry file. If undefined, $locale reverts to the default.
=cut
sub Name { $_[0]->get_value('Name', $DEFAULT_GROUP, $_[1]) }
sub GenericName { $_[0]->get_value('GenericName', $DEFAULT_GROUP, $_[1]) }
sub Comment { $_[0]->get_value('Comment', $DEFAULT_GROUP, $_[1]) }
sub Type { $_[0]->get_value('Type', $DEFAULT_GROUP, $_[1]) }
sub Icon { $_[0]->get_value('Icon', $DEFAULT_GROUP, $_[1]) }
sub Exec { $_[0]->get_value('Exec', $DEFAULT_GROUP, $_[1]) }
sub URL { $_[0]->get_value('URL', $DEFAULT_GROUP, $_[1]) }
sub StartupNotify { return ($_[0]->get_value('StartupNotify', $DEFAULT_GROUP, $_[1]) eq 'true' ? 1 : undef) }
=pod
=head1 NOTES
Please note that according to the Freedesktop.org spec, key names are case-sensitive.
=head1 SEE ALSO
The Freedesktop.org Desktop Entry Specification at L<http://www.freedesktop.org/Standards/desktop-entry-spec>.
=head1 AUTHOR
Gavin Brown E<lt>gavin.brown@uk.comE<gt>.
=head1 COPYRIGHT
Copyright (c) 2005 Gavin Brown. This program is free software, you can use it and/or modify it under the same terms as Perl itself.
=cut
1;
|