--- CV/bin/cv 2003/11/05 02:05:44 1.14 +++ CV/bin/cv 2005/07/17 05:01:30 1.46 @@ -1,22 +1,44 @@ #!/opt/bin/perl +use Cwd (); +use Encode (); + use Gtk2 -init; use Gtk2::Gdk::Keysyms; use Gtk2::CV::ImageWindow; use Gtk2::CV::Schnauzer; +use Gtk2::CV; + +Gtk2::Rc->parse (Gtk2::CV::find_rcfile "gtkrc"); + +use File::Spec; + +require Gtk2::CV::Plugin; +require "$ENV{HOME}/.cvrc" if -r "$ENV{HOME}/.cvrc"; + +my $mainwin; my $viewer; my $schnauzer; +my $info; +my $help; + +my $schnauzer_idx = 0; sub new_schnauzer { - my $w = new Gtk2::Window; - $w->add (my $s = new Gtk2::CV::Schnauzer); + my $s = new Gtk2::CV::Schnauzer; - $s->signal_connect (activate => sub { $viewer->load_image ($_[1]) }); $s->signal_connect_after (key_press_event => \&std_keys); + $s->signal_connect (activate => sub { + my $label = sprintf "%s (%d)", + (File::Spec->splitpath ($_[1]))[2], + -s $_[1]; + $info->set_label ($label); + $viewer->load_image ($_[1]); + }); - $s->set_dir ("."); + Gtk2::CV::Plugin->call (new_schnauzer => $s); $s; } @@ -25,47 +47,99 @@ my $key = $_[1]->keyval; my $state = $_[1]->state; - my $ctrl = grep $_ eq "control-mask", @$state; + my $ctrl = $state * "control-mask"; if ($key == $Gtk2::Gdk::Keysyms{q}) { main_quit Gtk2; } elsif ($ctrl && $key == $Gtk2::Gdk::Keysyms{v}) { - new_schnauzer->get_toplevel->show_all; + my $w = new Gtk2::Window; + + $w->set_title ("CV: Schnauzer"); + $w->add (my $s = new_schnauzer); + $s->set_dir (File::Spec->curdir); + $s->set_geometry_hints; + $w->show_all; + + } elsif ($ctrl && $key == $Gtk2::Gdk::Keysyms{h}) { + unless ($help) { + require Gtk2::PodViewer; + + $help = new Gtk2::Window; + $help->set_title ("CV: Help"); + $help->set_default_size (500, 300); + $help->signal_connect (delete_event => sub { $help->hide; 1 }); + + $help->add (my $sw = new Gtk2::ScrolledWindow); + $sw->add (my $h = new Gtk2::PodViewer); + + #binmode DATA, ":utf8"; + $h->load_string (do { local $/; }); + } + + $help->show_all; } else { - $schnauzer->handle_key ($key, $state); + return 0; } - 1; + 1 } -$viewer = new Gtk2::CV::ImageWindow; -$viewer->signal_connect (key_press_event => \&std_keys); -$viewer->signal_connect (delete_event => sub { main_quit Gtk2 }); +{ + $viewer = new Gtk2::CV::ImageWindow; -$viewer->set_title ("CV"); + $viewer->set_title ("CV: Image"); -$schnauzer = new_schnauzer; + $viewer->signal_connect (key_press_event => sub { + &std_keys + or $schnauzer->signal_emit (key_press_event => $_[1]) + }); + $viewer->signal_connect (delete_event => sub { main_quit Gtk2 }); + + $viewer->signal_connect (button3_press_event => sub { + $mainwin->visible + ? $mainwin->hide + : $mainwin->show_all; + 1; + }); + + Gtk2::CV::Plugin->call (new_imagewindow => $viewer); + + $schnauzer = new_schnauzer; + + $mainwin = new Gtk2::Window; + $mainwin->set_title ("CV"); + $mainwin->add (my $vbox = new Gtk2::VBox); + $mainwin->signal_connect (delete_event => sub { $mainwin->hide; 1; }); + + $vbox->add ($schnauzer); + $vbox->pack_end (my $frame = new Gtk2::Frame, 0, 0, 0); + $frame->add (my $hbox = new Gtk2::HBox 0, 0); + $hbox->pack_start ((new Gtk2::Label "Info: "), 0, 0, 0); + $hbox->pack_end (my $labelwindow = new Gtk2::EventBox, 1, 1, 0); + $labelwindow->add ($info = new Gtk2::Label); + $labelwindow->signal_connect_after (size_request => sub { $_[1]->width (0); 0 }); + $info->set (selectable => 1, xalign => 0, justify => "left"); -my $mainwin = $schnauzer->get_toplevel; - -$viewer->signal_connect (button3_press_event => sub { - $mainwin->visible - ? $mainwin->hide - : $mainwin->show_all; -}); + $schnauzer->set_geometry_hints; +} if (@ARGV) { - $viewer->load_image ($ARGV[0]); - - if (@ARGV > 1) { - $schnauzer->set_paths (\@ARGV); - } + $schnauzer->set_paths ([map Glib::filename_to_unicode $_, @ARGV]); + $schnauzer->show_all; +$viewer->show_all; + $schnauzer->handle_key ($Gtk2::Gdk::Keysyms{space}, []); +} else { + $schnauzer->set_dir (File::Spec->curdir); + $mainwin->show_all; + $viewer->show_all; } $viewer->show_all; main Gtk2; +__DATA__ + =head1 NAME cv - a fast gtk+ image viewer modeled after xv @@ -90,6 +164,7 @@ n reset to normal size m maximize to screensize M maxime to screensize, respecting image aspect + ctrl-m toggle maxpect-always mode u uncrop r set scaling mode to 'nearest' (fastest) s set scaling mode to 'bilinear' (default) @@ -97,6 +172,22 @@ t rotate clockwise 90° T rotate counterclockwise° ctrl-v open a new visual schnauzer window for the current dir + ctrl-s rescan visual schnauzer files for updates/deletes etc. + ctrl-e run an editor ($CV_EDITOR or "gimp") on the current image. + +And when playing movies, these additional keys are active: + + left rewind by 10 seconds + right forward by 10 seconds + down rewind by 60 seconds + up forward by 60 seconds + pg_up rewind by 600 seconds + pg_down forward by 600 seconds + o toggle on-screen display + p pause/unpause + escape stop playing + 9 turn volume down + 0 turn volume up The following keys are redirected to the default visual schnauzer window: @@ -117,11 +208,46 @@ home move to first file end move to last file - ctrl-g generate icons for the selected files ctrl-d delete selected files WITHOUT ASKING AGAIN + ctrl-g generate icons for the selected files + ctrl-u update selected (or all) icons if neccessary + ctrl-a select all files + +=head1 ENVIRONMENT + +=over 4 + +=item CV_EDITOR + +The program that gets executed when the user presses C in the +Schnauzer or image window. The default is C. + +=item CV_PRINT_DESTINATION + +The default (perl-style) destination to use in the print dialog. + +=item CV_TRASHCAN + +When set, must point to a directory where all files that are deleted are +moved to. If unset, files that are deleted are really being deleted. + +=back + +=head1 SECURITY CONSIDERATIONS + +CV uses Pixbuf to load images. Pixbuf is not considered safe for this +purpose, though (from the gtk-2.2 release notes): + +"While efforts have been made to make gdk-pixbuf robust against invalid +images, using gdk-pixbuf to load untrusted data is not recommended, due to +the likelyhood that there are additional problems where an invalid image +could cause gdk-pixbuf to crash or worse." =head1 BUGS/TODO + Pixbuf doesn't honor G_BROKEN_FILENAMES, so accessing files with names + incompatible with utf-8 fails. + rotate on disk print lots of ui issues