summaryrefslogtreecommitdiffstats
path: root/OSX/seticon.pl
blob: a4f8c2c3f7e6aa75563b2c570f5aa3d62541cbc3 (plain) (blame)
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
#!/usr/bin/perl -w
# Copyright © 2015-2016 Dave Odell <dmo2118@gmail.com>
#
# Permission to use, copy, modify, distribute, and sell this software and its
# documentation for any purpose is hereby granted without fee, provided that
# the above copyright notice appear in all copies and that both that
# copyright notice and this permission notice appear in supporting
# documentation.  No representations are made about the suitability of this
# software for any purpose.  It is provided "as is" without express or
# implied warranty.

# This is a replacement for seticon from http://osxutils.sourceforge.net/.

require 5;
use diagnostics;
use strict;
#use IPC::Open2;
use File::Temp;

my $progname = $0; $progname =~ s@.*/@@g;
my ($version) = ('$Revision: 1.7 $' =~ m/\s(\d[.\d]+)\s/s);

my $verbose = 0;

sub set_icon ($$) {
  my ($icon, $target) = @_;
  my $target_res = $target;

  if (-d $target) {
    $target_res = $target_res . "/Icon\r";
  }

  # Rez hates absolute paths, apparently.
  if ($icon =~ m@^/@s) {
    my $cwd = `pwd`;
    chomp $cwd;
    $icon =~ s@^\Q$cwd/@@s;
  }

  # The Rez language is documented in "Building and Managing Programs in MPW,
  # Second Edition". No longer available on Apple's servers, it can now be
  # found at:
  # http://www.powerpc.hu/manila/static/home/Apple/developer/Tool_Chest/Core_Mac_OS_Tools/MPW_etc./Documentation/MPW_Reference/Building_Progs_In_MPW.sit.hqx

  my $pgm = "Read 'icns' (kCustomIconResource) \"$icon\";\n";

  # Rez can read from stdin, but only if it is a file handle, not if it
  # is a pipe (OS X 10.9, Xcode 5; OSX 10.11, Xcode 6).

  my ($rez_fh, $rez_filename) = File::Temp::tempfile(DIR => '.', UNLINK => 1);
  print $rez_fh $pgm;
  close $rez_fh;

  my @cmd = ('Rez',

             '-isysroot', 
             '/Applications/Xcode.app/Contents/Developer/Platforms' .
             '/MacOSX.platform/Developer/SDKs/MacOSX.sdk',

             'CoreServices.r',
             $rez_filename,
             '-o', $target_res);

  print STDERR "$progname: exec: " . join(' ', @cmd) . "\n$pgm\n"
    if ($verbose);

#  my ($in, $out);
#  my $pid = open2 ($out, $in, @cmd);
#  print $in $pgm;
#  close ($in);
#  waitpid ($pid, 0);

  system (@cmd);

  my $exit  = $? >> 8;
  exit ($exit) if $exit;

  # Have to also inform Finder that the icon is there, with the
  # com.apple.FinderInfo xattr (a FolderInfo struct).
  @cmd = ('SetFile', '-a', 'C', $target);
  system (@cmd);
  $exit  = $? >> 8;
  exit ($exit) if $exit;
}

sub error($) {
  my ($err) = @_;
  print STDERR "$progname: $err\n";
  exit 1;
}

sub usage() {
  print "Usage: $progname -d source [file...]\n";
  exit 1;
}

sub main() {
  my ($src, @dst);
  while ($#ARGV >= 0) {
    $_ = shift @ARGV;
    if (m/^--?verbose$/s)      { $verbose++; }
    elsif (m/^-v+$/s)          { $verbose += length($_)-1; }
    elsif (m/^-d$/s)           { $src = shift @ARGV; }
    elsif (m/^-/s)             { usage(); }
    else { push @dst, $_; }
  }
  error ("no source") unless defined($src);
  error ("no files") unless @dst;
  foreach my $f (@dst) {
    set_icon ($src, $f);
  }
}

main();
exit 0;