From http://www.jwz.org/xscreensaver/xscreensaver-5.23.tar.gz
[xscreensaver] / driver / xscreensaver-getimage-desktop
index f7d9e7650aa371aaf5bd049dfa95f330099246ac..2a6d345180eb53833ef7333f0e00196f1bdc7c65 100755 (executable)
@@ -1,5 +1,5 @@
 #!/usr/bin/perl -w
-# Copyright © 2003 Jamie Zawinski <jwz@jwz.org>.
+# Copyright © 2003-2013 Jamie Zawinski <jwz@jwz.org>.
 #
 # Permission to use, copy, modify, distribute, and sell this software and its
 # documentation for any purpose is hereby granted without fee, provided that
@@ -9,42 +9,40 @@
 # software for any purpose.  It is provided "as is" without express or 
 # implied warranty.
 #
-# This program attempts to grab an image of the desktop, and then load
-# it on to the root window using the "xscreensaver-getimage-file"
-# program.  Various frame-grabbing programs are known, and the first
-# one found is used.
 #
-# NOTE:  This script is only used on MacOS X / XDarwin systems, because
-#        on those systems, it's necessary to use the "screencapture"
-#        program to get an image of the desktop -- the usual X11
-#        mechanism for grabbing the screen doesn't work on OSX.
+# This script is invoked by "xscreensaver-getimage" on X11 MacOS systems
+# to grab an image of the desktop, and then load it on to the given X11
+# Drawable using the "xscreensaver-getimage-file" program.
 #
-# The various xscreensaver hacks that manipulate images ("slidescreen",
-# "jigsaw", etc.) get the image to manipulate by running the
-# "xscreensaver-getimage" program.
+# This script is only used in an *X11* build on MacOS systems.
 #
-# "xscreensaver-getimage" will invoke this program, depending on the
-# value of the "grabDesktopImages" setting in the ~/.xscreensaver file
-# (or in /usr/lib/X11/app-defaults/XScreenSaver).
+# When running on non-Mac X11 systems, utils/grabscreen.c is used.
+#
+# However, when running under X11 on MacOS, that usual X11-based
+# screen-grabbing mechanism doesn't work, so we need to invoke the
+# "/usr/bin/screencapture" program to do it instead.  (This script).
+#
+# However again, for the MacOS-native (Cocoa) build of the screen savers,
+# "utils/grabclient.c" instead links against "OSX/osxgrabscreen.m", which
+# grabs screen images directly without invoking a sub-process to do it.
 #
 # Created: 20-Oct-2003.
 
+
 require 5;
-use diagnostics;
+#use diagnostics;      # Fails on some MacOS 10.5 systems
 use strict;
 
 my $progname = $0; $progname =~ s@.*/@@g;
-my $version = q{ $Revision: 1.1 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/;
+my $version = q{ $Revision: 1.6 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/;
 
 my @grabber   = ("screencapture", "-x");
 my @converter = ("pdf2jpeg");
 
 my $verbose = 0;
-my $use_stdout_p = 0;
-my $return_filename_p = 0;
 
 
-sub error {
+sub error($) {
   ($_) = @_;
   print STDERR "$progname: $_\n";
   exit 1;
@@ -52,7 +50,7 @@ sub error {
 
 # returns the full path of the named program, or undef.
 #
-sub which {
+sub which($) {
   my ($prog) = @_;
   foreach (split (/:/, $ENV{PATH})) {
     if (-x "$_/$prog") {
@@ -62,7 +60,7 @@ sub which {
   return undef;
 }
 
-sub check_path {
+sub check_path() {
   my $ok = 1;
   foreach ($grabber[0], $converter[0]) {
     if (! which ($_)) {
@@ -74,21 +72,21 @@ sub check_path {
 }
 
 
-sub grab_image {
+sub grab_image() {
 
   check_path();
 
   my $tmpdir = $ENV{TMPDIR};
   $tmpdir = "/tmp" unless $tmpdir;
 
-  my $tmpfile = "$tmpdir/xssgrab.$$.pdf";
+  my $tmpfile = sprintf ("%s/xssgrab.%08x.pdf", $tmpdir, rand(0xffffffff));
   my @cmd     = (@grabber, $tmpfile);
 
   unlink $tmpfile;
 
   print STDERR "$progname: executing \"" . join(' ', @cmd) . "\"\n"
     if ($verbose);
-  system (@cmd);
+  system (join(' ', @cmd) . ' 2>/dev/null');
 
   my @st = stat($tmpfile);
   my $size = (@st ? $st[7] : 0);
@@ -101,22 +99,44 @@ sub grab_image {
     }
   }
 
-  # Convert the PDF to a JPEG
+  # On MacOS 10.3, "screencapture -x" always wrote a PDF.
+  # On 10.4.2, it writes a PNG by default, and the output format can be
+  # changed with the new "-t" argument.
+  #
+  # So, for maximal compatibility, we run it without "-t", but look at
+  # the first few bytes to see if it's a PDF, and if it is, convert it
+  # to a JPEG first.  Otherwise, we assume that whatever screencapture
+  # wrote is a file format that xscreensaver-getimage-file can already
+  # cope with (though it will have the extension ".pdf", regardless of
+  # what is actually in the file).
+  #
+  my $pdf_p = 0;
   {
-    my $jpgfile = $tmpfile;
-    $jpgfile =~ s/\.[^.]+$//;
-    $jpgfile .= ".jpg";
-
-    @cmd = (@converter, $tmpfile, $jpgfile);
-    push @cmd, "--verbose" if ($verbose);
-
-    print STDERR "$progname: executing \"" . join(' ', @cmd) . "\"\n"
-      if ($verbose);
-    system (@cmd);
-    unlink $tmpfile;
-    $tmpfile = $jpgfile;
+    open (my $in, '<:raw', $tmpfile) || error ("$tmpfile: $!");
+    my $buf = '';
+    read ($in, $buf, 10);
+    close $in;
+    $pdf_p = ($buf =~ m/^%PDF-/s);
   }
 
+  # If it's a PDF, convert it to a JPEG.
+  #
+  if ($pdf_p)
+    {
+      my $jpgfile = $tmpfile;
+      $jpgfile =~ s/\.[^.]+$//;
+      $jpgfile .= ".jpg";
+
+      @cmd = (@converter, $tmpfile, $jpgfile);
+      push @cmd, "--verbose" if ($verbose);
+
+      print STDERR "$progname: executing \"" . join(' ', @cmd) . "\"\n"
+        if ($verbose);
+      system (@cmd);
+      unlink $tmpfile;
+      $tmpfile = $jpgfile;
+    }
+
   @st = stat($tmpfile);
   $size = (@st ? $st[7] : 0);
   if ($size <= 2048) {
@@ -128,55 +148,25 @@ sub grab_image {
     }
   }
 
-  if ($return_filename_p) {
-    print STDERR "$progname: wrote \"$tmpfile\"\n" if ($verbose);
-    print STDOUT "$tmpfile\n";
-
-  } elsif ($use_stdout_p) {
-    local *IN;
-    my $ppm = "";
-    my $reader = "djpeg $tmpfile";
-    $reader .= " 2>/dev/null" if ($verbose <= 1);
-    $reader .= " |";
-
-    open(IN, $reader) || error "reading $tmpfile: $!";
-    print STDERR "$progname: reading $tmpfile\n" if ($verbose > 1);
-    while (<IN>) { $ppm .= $_; }
-    close IN;
-    unlink $tmpfile;
-    print STDOUT $ppm;
-
-  } else {
-
-    @cmd = ("xscreensaver-getimage-file");
-    push @cmd, "--verbose" if ($verbose);
-    push @cmd, $tmpfile;
-
-    print STDERR "$progname: executing \"" . join(' ', @cmd) . "\"\n"
-      if ($verbose);
-    system (@cmd);
-
-    unlink $tmpfile;
-  }
+  print STDERR "$progname: wrote \"$tmpfile\"\n" if ($verbose);
+  print STDOUT "$tmpfile\n";
 }
 
 
-sub usage {
-  print STDERR "usage: $progname [--verbose] [--name | --stdout]\n";
+sub usage() {
+  print STDERR "usage: $progname [--verbose]\n";
   exit 1;
 }
 
-sub main {
+sub main() {
   while ($_ = $ARGV[0]) {
     shift @ARGV;
-    if ($_ eq "--verbose") { $verbose++; }
-    elsif (m/^-v+$/) { $verbose += length($_)-1; }
-    elsif (m/^--?stdout$/) { $use_stdout_p = 1; }
-    elsif (m/^--?name$/)   { $return_filename_p = 1; }
-    elsif (m/^-./) { usage; }
-    else { usage; }
+    if    (m/^--?verbose$/s) { $verbose++; }
+    elsif (m/^-v+$/s)        { $verbose += length($_)-1; }
+    elsif (m/^--?name$/s)    { }   # ignored, for compatibility
+    elsif (m/^-./)           { usage; }
+    else                     { usage; }
   }
-
   grab_image();
 }