Skip to content

Commit

Permalink
- Swtiched to Gtk2 for resolving the absolute paths for icons.
Browse files Browse the repository at this point in the history
This solution is more robust, slightly faster and uses less space for cache.
  • Loading branch information
trizen committed Jul 19, 2017
1 parent 827a494 commit 1d16c90
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 138 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ A very fast dynamic file browser that allows quick searching and launching of us

### Dependencies:

* [Gtk2](https://metacpan.org/pod/Gtk2)
* [Data::Dump](https://metacpan.org/pod/Data::Dump)
* [File::MimeInfo](https://metacpan.org/pod/File::MimeInfo)
* [Linux::DesktopFiles>=0.08](https://metacpan.org/pod/Linux::DesktopFiles)

### Set-up:

Expand Down
265 changes: 128 additions & 137 deletions obbrowser
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#!/usr/bin/perl

# Copyright (C) 2012-2016 Daniel "Trizen" Șuteu <echo dHJpemVueEBnbWFpbC5jb20K | base64 -d>.
# Copyright (C) 2012-2017 Daniel "Trizen" Șuteu <echo dHJpemVueEBnbWFpbC5jb20K | base64 -d>.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
Expand All @@ -18,21 +18,22 @@
# Original author: dircha
# See: http://bbs.archbang.org/viewtopic.php?id=1589

# Name: obbrowser
# License: GPLv3
# Date: 29 December 2012
# Latest edit: 04 May 2016
# Website: http://github.com/trizen/obbrowser
# Latest edit: 19 July 2017
# https://github.com/trizen/obbrowser

# ---------------------------------------------------------
# Recursively browse filesystem through openbox3 pipe menus
# ---------------------------------------------------------

#use 5.014;
use 5.014;
#use strict;
#use warnings;

my $pkgname = 'obbrowser';
my $version = 0.06;
my $version = 0.07;

our $CONFIG;

Expand All @@ -42,9 +43,9 @@ my $home_dir =
|| (getpwuid($<))[7]
|| `echo -n ~`;

my $config_dir = "$home_dir/.config/obbrowser";
my $config_file = "$config_dir/config.pl";
my $icons_db_filename = "$config_dir/icons.db";
my $config_dir = "$home_dir/.config/obbrowser";
my $config_file = "$config_dir/config.pl";
my $cache_db = "$config_dir/cache.db";

if (not -d $config_dir) {
require File::Path;
Expand All @@ -70,10 +71,10 @@ usage: $0 [dir]
$config_file
4. After changing the current icon theme, also delete the icon database
4. After changing the current icon theme, also delete the cache database
that is generated by obbrowser:
$icons_db_filename
$cache_db
USAGE
exit;
Expand All @@ -93,30 +94,21 @@ my $config_documentation = <<"EOD";
=for comment
|| ICON SETTINGS
| icon_dirs_first : While searching for icons, look in this directories first,
before looking in the directories of the current icon theme.
Example: [
"\$ENV{HOME}/My icons",
],
| icon_dirs_last : While searching for icons, also look in this icon directories.
Example: [
"/usr/share/icons/Tango",
],
| with_icons : A true value will make the script to use icons for files and directories.
This option may be slow, depending on the configuration of your system.
| mime_ext_only : A true value will make the script to get the mimetype by extension only.
This will improve the performance, as no content will be read from files.
| gtk_rc_filename : Absolute path to the gtkrc file.
This file is used to get the name of the current icon theme.
| icon_size : Preferred size for icons. (default: 16)
| skip_svg_icons : Ignore SVG icons. (default: 0)
| force_svg_icons : Use only SVG icons. (default: 0)
| force_icon_size : Use only icons at the prefered icon size, if possible. (default: 0)
|| MENU
| file_manager : Command to your file manager for opening files and directories.
| browse_label : Label for browse here action.
| browse_label : Label for "Browse here..." action.
| start_path : An absolute path from which to start to browse the filesystem.
| dirs_first : A true value will make the script to order directories before files.
Expand All @@ -125,19 +117,17 @@ my $config_documentation = <<"EOD";
EOD

my %CONFIG = (
'Linux::DesktopFiles' => {
gtk_rc_filename => "$home_dir/.gtkrc-2.0",
icon_dirs_first => undef,
icon_dirs_last => undef,
skip_svg_icons => 0,
},
file_manager => 'pcmanfm',
browse_label => 'Browse here...',
start_path => $home_dir,
dirs_first => 0,
with_icons => 1,
mime_ext_only => 0,
VERSION => $version,
file_manager => 'pcmanfm',
browse_label => 'Browse here...',
start_path => $home_dir,
dirs_first => 0,
with_icons => 1,
mime_ext_only => 0,
icon_size => 16,
force_icon_size => 0,
force_svg_icons => 0,
skip_svg_icons => 0,
VERSION => $version,
);

sub dump_configuration {
Expand All @@ -163,39 +153,8 @@ if ($CONFIG{VERSION} != $version) {
dump_configuration();
}

my $ld_obj;
if ($CONFIG{with_icons}) {

my @keys = qw(
Tie/Hash.pm
Carp.pm
Exporter.pm
warnings.pm
);

@INC{@keys, 'warnings/register.pm', 'strict.pm'} = ();

require Linux::DesktopFiles;

$Linux::DesktopFiles::VERSION >= 0.08
|| die "Update Linux::DesktopFiles to a newer version! (requires >=0.08)\n";

$ld_obj = Linux::DesktopFiles->new(
%{$CONFIG{'Linux::DesktopFiles'}},

strict_icon_dirs => 1,
use_current_theme_icons => 1,
home_dir => $home_dir,

$CONFIG{with_icons}
? (
abs_icon_paths => 1,
icon_db_filename => $icons_db_filename,
)
: (),
);

delete @INC{@keys};
{
@INC{'warnings.pm', 'warnings/register.pm', 'strict.pm'} = ();
}

{
Expand Down Expand Up @@ -232,87 +191,119 @@ sub mk_file_elem {
. q{&quot;</execute></action></item>};
}

{
my $path = @ARGV ? shift() : $CONFIG{start_path};
require GDBM_File;
tie my %cache_db, 'GDBM_File', $cache_db, &GDBM_File::GDBM_WRCREAT, 0640;

my (%alias, %icons, @dirs, @files);
opendir(my $dir_h, $path) or warn "$0: Can't open dir `$path': $!\n";
foreach my $file (readdir $dir_h) {
sub get_icon_path {
my ($name) = @_;

next if chr ord $file eq q{.}; # skip the hidden files
state $gtk = do {
require Gtk2;
'Gtk2'->init;
'Gtk2';
};

if ($CONFIG{with_icons}) {
state $theme = do {
"${gtk}::IconTheme"->get_default;
};

if (-d "$path/$file") {
push @dirs, [$file, $icons{'inode-directory'} ||= $ld_obj->get_icon_path('inode-directory')];
next;
}
state $flags = "${gtk}::IconLookupFlags"->new(
[($CONFIG{force_icon_size} ? 'force-size' : ()),
($CONFIG{skip_svg_icons} ? 'no-svg' : ()),
($CONFIG{force_svg_icons} ? 'force-svg' : ()),
]
);

require File::MimeInfo; # File::MimeInfo::Magic is better, but slower!

my $mime_type = (
(
$CONFIG{mime_ext_only}
? File::MimeInfo::globs($file)
: File::MimeInfo::mimetype("$path/$file")
) // 'unknown'
) =~ tr|/|-|r;

$mime_type = $alias{$mime_type} if exists $alias{$mime_type};

{
my $type = $mime_type;
while (1) {
if ($icons{$type} ||= $ld_obj->get_icon_path($type)) {
$alias{$mime_type} = $type;
$mime_type = $type;
last;
}
elsif ($icons{"gnome-mime-$type"} ||= $ld_obj->get_icon_path("gnome-mime-$type")) {
$alias{$mime_type} = "gnome-mime-$type";
$mime_type = "gnome-mime-$type";
last;
}
$type =~ s{.*\K[[:punct:]]\w++$}{} || last;
}
}
my $icon_info = $theme->lookup_icon($name, $CONFIG{icon_size}, $flags);

defined($icon_info)
? $icon_info->get_filename
: '';
}

if (!$icons{$mime_type}) {
my $type = $mime_type;
while (1) {
$type =~ s{^application-x-\K.*?-}{} || last;
$icons{$type} ||= $ld_obj->get_icon_path($type);
$icons{$type} && do { $alias{$mime_type} = $type; $mime_type = $type; last };
sub check_icon {
$cache_db{$_[0]} //= get_icon_path($_[0]);
}

my $path = @ARGV ? shift() : $CONFIG{start_path};

my (%alias, %icons, @dirs, @files);
opendir(my $dir_h, $path) or warn "$0: Can't open dir `$path': $!\n";
foreach my $file (readdir $dir_h) {

next if chr ord $file eq q{.}; # skip the hidden files

if ($CONFIG{with_icons}) {

if (-d "$path/$file") {
push @dirs, [$file, $icons{'inode-directory'} ||= check_icon('inode-directory')];
next;
}

require File::MimeInfo; # File::MimeInfo::Magic is better, but slower!

my $mime_type = (
(
$CONFIG{mime_ext_only}
? File::MimeInfo::globs($file)
: File::MimeInfo::mimetype("$path/$file")
) // 'unknown'
) =~ tr|/|-|r;

$mime_type = $alias{$mime_type} if exists $alias{$mime_type};

{
my $type = $mime_type;
while (1) {
if ($icons{$type} ||= check_icon($type)) {
$alias{$mime_type} = $type;
$mime_type = $type;
last;
}
elsif ($icons{"gnome-mime-$type"} ||= check_icon("gnome-mime-$type")) {
$alias{$mime_type} = "gnome-mime-$type";
$mime_type = "gnome-mime-$type";
last;
}
$type =~ s{.*\K[[:punct:]]\w++$}{} || last;
}
push @files, [
$file, $icons{$mime_type} ||=
do { $alias{$mime_type} = 'unknown'; $ld_obj->get_icon_path('unknown') }
];
}
else {
push @{-d "$path/$file" ? \@dirs : \@files}, [$file, ''];
}

if (!$icons{$mime_type}) {
my $type = $mime_type;
while (1) {
$type =~ s{^application-x-\K.*?-}{} || last;
$icons{$type} ||= check_icon($type);
$icons{$type} && do { $alias{$mime_type} = $type; $mime_type = $type; last };
}
}
push @files, [
$file, $icons{$mime_type} ||=
do { $alias{$mime_type} = 'unknown'; check_icon('unknown') }
];
}
else {
push @{-d "$path/$file" ? \@dirs : \@files}, [$file, ''];
}
closedir $dir_h;

my $thisDir = xmlEscape($path);
my $qEscapedDir = escapeQuot($thisDir);
my $escapedProgramName = xmlEscape($0);
}
closedir $dir_h;

# "Browse here..." launches this directory
my $generated_menu = qq{<openbox_pipe_menu><item label="$CONFIG{browse_label}"><action name="Execute">}
. qq{<execute>$CONFIG{file_manager} &quot;$qEscapedDir&quot;</execute></action></item><separator/>};
my $thisDir = xmlEscape($path);
my $qEscapedDir = escapeQuot($thisDir);
my $escapedProgramName = xmlEscape($0);

my @calls = ([\&mk_file_elem => \@files], [\&mk_dir_elem => \@dirs]);
# "Browse here..." launches this directory
my $generated_menu = qq{<openbox_pipe_menu><item label="$CONFIG{browse_label}"><action name="Execute">}
. qq{<execute>$CONFIG{file_manager} &quot;$qEscapedDir&quot;</execute></action></item><separator/>};

foreach my $call ($CONFIG{dirs_first} ? reverse(@calls) : @calls) {
$generated_menu .= $call->[0]->($thisDir, $qEscapedDir, xmlEscape($_->[0]), $_->[1], $escapedProgramName)
for sort { lc $a->[0] cmp lc $b->[0] } @{$call->[1]};
}
my @calls = ([\&mk_file_elem => \@files], [\&mk_dir_elem => \@dirs]);

++$|;
print $generated_menu, "</openbox_pipe_menu>";
exit;
foreach my $call ($CONFIG{dirs_first} ? reverse(@calls) : @calls) {
$generated_menu .= $call->[0]->($thisDir, $qEscapedDir, xmlEscape($_->[0]), $_->[1], $escapedProgramName)
for sort { lc $a->[0] cmp lc $b->[0] } @{$call->[1]};
}

local $| = 1;
print $generated_menu, "</openbox_pipe_menu>";
exit;

0 comments on commit 1d16c90

Please sign in to comment.